From 2d0046b6dd6e2b9723023b9806b53f4b175d00e0 Mon Sep 17 00:00:00 2001 From: Rob Gordon Date: Sun, 28 Mar 2021 18:49:36 -0400 Subject: [PATCH] fix(box): hover --- docs/components/DocsLayout.module.scss | 1 + docs/components/DocsLayout.tsx | 8 +- docs/components/slang/config.ts | 9 +- docs/components/slang/index.tsx | 4 +- docs/components/slang/slang.css | 284 ++++++++++++++++++++-- docs/components/theme.tsx | 13 +- docs/pages/_app.tsx | 12 +- docs/pages/box.tsx | 18 +- docs/pages/{.index.tsx => test-index.tsx} | 36 ++- docs/pages/type.tsx | 6 +- slang/src/Box/Box.tsx | 7 +- slang/src/Box/props.ts | 22 ++ slang/src/Type/Type.tsx | 5 +- slang/src/createComponentCss.ts | 96 ++++++++ slang/src/createResponsiveCss.ts | 53 ---- slang/src/makeCSS.ts | 4 +- slang/src/utils.ts | 48 +++- 17 files changed, 494 insertions(+), 132 deletions(-) rename docs/pages/{.index.tsx => test-index.tsx} (64%) create mode 100644 slang/src/createComponentCss.ts delete mode 100644 slang/src/createResponsiveCss.ts diff --git a/docs/components/DocsLayout.module.scss b/docs/components/DocsLayout.module.scss index 1724de0..6f3d0a1 100644 --- a/docs/components/DocsLayout.module.scss +++ b/docs/components/DocsLayout.module.scss @@ -6,6 +6,7 @@ .NavLink { background-color: var(--palette-white-3); + transition: background-color 300ms cubic-bezier(0.23, 1, 0.32, 1); &[aria-current="page"] { background-color: var(--palette-white-2); } diff --git a/docs/components/DocsLayout.tsx b/docs/components/DocsLayout.tsx index e2a52a0..8afff7f 100644 --- a/docs/components/DocsLayout.tsx +++ b/docs/components/DocsLayout.tsx @@ -5,7 +5,7 @@ import styles from "./DocsLayout.module.scss"; import { useRouter } from "next/router"; const links = [ - { href: "/", text: "Home" }, + { href: "/test-index", text: "Home" }, { href: "/getting-started", text: "Getting Started" }, { href: "/box", text: "Box" }, { href: "/type", text: "Type" }, @@ -17,7 +17,8 @@ export default function DocsLayout({ children }: { children: ReactNode }) { - + {children} @@ -67,6 +68,7 @@ function SidebarLink({ pl={4} pr={8} {...(active ? { "aria-current": "page" } : {})} + hover={{ background: "palette-white-2" }} > {text} diff --git a/docs/components/slang/config.ts b/docs/components/slang/config.ts index 9d8d8c6..f579a6e 100644 --- a/docs/components/slang/config.ts +++ b/docs/components/slang/config.ts @@ -4,16 +4,17 @@ const config: Partial = { baseFontFamily: "Neue Montreal", baseFontSizePx: 20, baseFontSizeMobilePx: 16, - baseFontLineHeight: 1.5, + baseFontLineHeight: 1.4, baseFontLineHeightMobile: 1.5, baseContainerSizePx: 700, - baseSpacingPx: 22.4, + baseSpacingPx: 30, + spacerPx: 4, baseSpacingScale: 1.1, errorCorrectionTopPx: -1.32, errorCorrectionTopScale: 1.5, errorCorrectionBottomPx: 1.67, errorCorrectionBottomScale: 1.486, - typeScaleBase: 1.25, + typeScaleBase: 1.4, typeScaleBaseMobile: 1.16, inverseTypeScaleLineHeight: 0.96, inverseTypeScaleLineHeightMobile: 0.969, @@ -23,7 +24,7 @@ const config: Partial = { fluidMaxScreenSizePx: 1200, palette: { white: ["#ffffff", "#f3f2f2", "#dadada", "#e7ebec"], - black: ["#000000"], + black: ["#000000", "#121212", "#333333"], }, colors: { background: "var(--palette-white-1)", diff --git a/docs/components/slang/index.tsx b/docs/components/slang/index.tsx index d3e3932..3028788 100644 --- a/docs/components/slang/index.tsx +++ b/docs/components/slang/index.tsx @@ -16,7 +16,9 @@ type Colors = | "palette-white-1" | "palette-white-2" | "palette-white-3" - | "palette-black-0"; + | "palette-black-0" + | "palette-black-1" + | "palette-black-2"; export type BoxProps = PropsWithAs>; export type TypeProps = PropsWithAs>; const Box = forwardRefWithAs(BoxComponent); diff --git a/docs/components/slang/slang.css b/docs/components/slang/slang.css index de7a030..db0fcee 100644 --- a/docs/components/slang/slang.css +++ b/docs/components/slang/slang.css @@ -500,12 +500,12 @@ body { --base-font-size:20; --base-font-size-mobile-px:16px; --base-font-size-mobile:16; - --base-font-line-height:1.5; + --base-font-line-height:1.4; --base-font-line-height-mobile:1.5; --spacer-px:4px; --spacer:4; - --base-spacing-px:22.4px; - --base-spacing:22.4; + --base-spacing-px:30px; + --base-spacing:30; --base-container-size-px:700px; --base-container-size:700; --base-spacing-scale:1.1; @@ -515,7 +515,7 @@ body { --error-correction-bottom-px:1.67px; --error-correction-bottom:1.67; --error-correction-bottom-scale:1.486; - --type-scale-base:1.25; + --type-scale-base:1.4; --type-scale-base-mobile:1.16; --inverse-type-scale-line-height:0.96; --inverse-type-scale-line-height-mobile:0.969; @@ -526,18 +526,18 @@ body { --fluid-min-screen-size:375; --fluid-max-screen-size-px:1200px; --fluid-max-screen-size:1200; - --multiplier--3:0.512; - --multiplier--2:0.64; - --multiplier--1:0.8; + --multiplier--3:0.36443148688046656; + --multiplier--2:0.5102040816326531; + --multiplier--1:0.7142857142857143; --multiplier-0:1; - --multiplier-1:1.25; - --multiplier-2:1.5625; - --multiplier-3:1.953125; - --multiplier-4:2.44140625; - --multiplier-5:3.0517578125; - --multiplier-6:3.814697265625; - --multiplier-7:4.76837158203125; - --multiplier-8:5.9604644775390625; + --multiplier-1:1.4; + --multiplier-2:1.9599999999999997; + --multiplier-3:2.7439999999999993; + --multiplier-4:3.841599999999999; + --multiplier-5:5.378239999999998; + --multiplier-6:7.529535999999997; + --multiplier-7:10.541350399999995; + --multiplier-8:14.757890559999993; --mobile-multiplier--3:0.6406576735413507; --mobile-multiplier--2:0.7431629013079668; --mobile-multiplier--1:0.8620689655172414; @@ -603,6 +603,8 @@ body { --palette-white-2:#dadada; --palette-white-3:#e7ebec; --palette-black-0:#000000; + --palette-black-1:#121212; + --palette-black-2:#333333; --color-background:var(--palette-white-1); --color-foreground:var(--palette-black-0); } @@ -610,54 +612,117 @@ body { .slang-box.flow { grid-auto-flow: var(--flow); } +.slang-box.flow_hover:hover { +grid-auto-flow: var(--flow_hover); +} .slang-box.content { place-content: var(--content); } +.slang-box.content_hover:hover { +place-content: var(--content_hover); +} .slang-box.items { place-items: var(--items); } +.slang-box.items_hover:hover { +place-items: var(--items_hover); +} .slang-box.self { place-self: var(--self); } +.slang-box.self_hover:hover { +place-self: var(--self_hover); +} .slang-box.p { padding: calc(var(--spacer-px) * var(--p)); } +.slang-box.p_hover:hover { +padding: calc(var(--spacer-px) * var(--p_hover)); +} .slang-box.py { padding-top: calc(var(--spacer-px) * var(--py)); padding-bottom: calc(var(--spacer-px) * var(--py)); } +.slang-box.py_hover:hover { +padding-top: calc(var(--spacer-px) * var(--py_hover)); padding-bottom: calc(var(--spacer-px) * var(--py_hover)); +} .slang-box.px { padding-left: calc(var(--spacer-px) * var(--px)); padding-right: calc(var(--spacer-px) * var(--px)); } +.slang-box.px_hover:hover { +padding-left: calc(var(--spacer-px) * var(--px_hover)); padding-right: calc(var(--spacer-px) * var(--px_hover)); +} .slang-box.pt { padding-top: calc(var(--spacer-px) * var(--pt)); } +.slang-box.pt_hover:hover { +padding-top: calc(var(--spacer-px) * var(--pt_hover)); +} .slang-box.pr { padding-right: calc(var(--spacer-px) * var(--pr)); } +.slang-box.pr_hover:hover { +padding-right: calc(var(--spacer-px) * var(--pr_hover)); +} .slang-box.pb { padding-bottom: calc(var(--spacer-px) * var(--pb)); } +.slang-box.pb_hover:hover { +padding-bottom: calc(var(--spacer-px) * var(--pb_hover)); +} .slang-box.pl { padding-left: calc(var(--spacer-px) * var(--pl)); } +.slang-box.pl_hover:hover { +padding-left: calc(var(--spacer-px) * var(--pl_hover)); +} .slang-box.gap { gap: calc(var(--spacer-px) * var(--gap)); } +.slang-box.gap_hover:hover { +gap: calc(var(--spacer-px) * var(--gap_hover)); +} +.slang-box.columnGap { +column-gap: calc(var(--spacer-px) * var(--columnGap)); +} +.slang-box.columnGap_hover:hover { +column-gap: calc(var(--spacer-px) * var(--columnGap_hover)); +} +.slang-box.rowGap { +row-gap: calc(var(--spacer-px) * var(--rowGap)); +} +.slang-box.rowGap_hover:hover { +row-gap: calc(var(--spacer-px) * var(--rowGap_hover)); +} .slang-box.template { grid-template: var(--template); } +.slang-box.template_hover:hover { +grid-template: var(--template_hover); +} .slang-box.display { display: var(--display); } +.slang-box.display_hover:hover { +display: var(--display_hover); +} .slang-box.overflow { overflow: var(--overflow); } +.slang-box.overflow_hover:hover { +overflow: var(--overflow_hover); +} .slang-box.h { height: var(--h); } +.slang-box.h_hover:hover { +height: var(--h_hover); +} .slang-box.root { min-height: var(--root); } +.slang-box.root_hover:hover { +min-height: var(--root_hover); +} @supports (-webkit-touch-callout: none) { .slang-box.root-safari { min-height: var(--root-safari); @@ -666,155 +731,344 @@ min-height: var(--root-safari); .slang-box.background { background-color: var(--background); } +.slang-box.background_hover:hover { +background-color: var(--background_hover); +} +.slang-box.color { +color: var(--color); +} +.slang-box.color_hover:hover { +color: var(--color_hover); +} .slang-box.contain { max-width: var(--contain); } +.slang-box.contain_hover:hover { +max-width: var(--contain_hover); +} .slang-box.rad { border-radius: calc(var(--smallest-border-radius-px) * var(--rad)); } +.slang-box.rad_hover:hover { +border-radius: calc(var(--smallest-border-radius-px) * var(--rad_hover)); +} @media(min-width: 768px) { .slang-box.flow-tablet { grid-auto-flow: var(--flow-tablet); } +.slang-box.flow-tablet_hover:hover { +grid-auto-flow: var(--flow-tablet_hover); +} .slang-box.content-tablet { place-content: var(--content-tablet); } +.slang-box.content-tablet_hover:hover { +place-content: var(--content-tablet_hover); +} .slang-box.items-tablet { place-items: var(--items-tablet); } +.slang-box.items-tablet_hover:hover { +place-items: var(--items-tablet_hover); +} .slang-box.self-tablet { place-self: var(--self-tablet); } +.slang-box.self-tablet_hover:hover { +place-self: var(--self-tablet_hover); +} .slang-box.p-tablet { padding: calc(var(--spacer-px) * var(--p-tablet)); } +.slang-box.p-tablet_hover:hover { +padding: calc(var(--spacer-px) * var(--p-tablet_hover)); +} .slang-box.py-tablet { padding-top: calc(var(--spacer-px) * var(--py-tablet)); padding-bottom: calc(var(--spacer-px) * var(--py-tablet)); } +.slang-box.py-tablet_hover:hover { +padding-top: calc(var(--spacer-px) * var(--py-tablet_hover)); padding-bottom: calc(var(--spacer-px) * var(--py-tablet_hover)); +} .slang-box.px-tablet { padding-left: calc(var(--spacer-px) * var(--px-tablet)); padding-right: calc(var(--spacer-px) * var(--px-tablet)); } +.slang-box.px-tablet_hover:hover { +padding-left: calc(var(--spacer-px) * var(--px-tablet_hover)); padding-right: calc(var(--spacer-px) * var(--px-tablet_hover)); +} .slang-box.pt-tablet { padding-top: calc(var(--spacer-px) * var(--pt-tablet)); } +.slang-box.pt-tablet_hover:hover { +padding-top: calc(var(--spacer-px) * var(--pt-tablet_hover)); +} .slang-box.pr-tablet { padding-right: calc(var(--spacer-px) * var(--pr-tablet)); } +.slang-box.pr-tablet_hover:hover { +padding-right: calc(var(--spacer-px) * var(--pr-tablet_hover)); +} .slang-box.pb-tablet { padding-bottom: calc(var(--spacer-px) * var(--pb-tablet)); } +.slang-box.pb-tablet_hover:hover { +padding-bottom: calc(var(--spacer-px) * var(--pb-tablet_hover)); +} .slang-box.pl-tablet { padding-left: calc(var(--spacer-px) * var(--pl-tablet)); } +.slang-box.pl-tablet_hover:hover { +padding-left: calc(var(--spacer-px) * var(--pl-tablet_hover)); +} .slang-box.gap-tablet { gap: calc(var(--spacer-px) * var(--gap-tablet)); } +.slang-box.gap-tablet_hover:hover { +gap: calc(var(--spacer-px) * var(--gap-tablet_hover)); +} +.slang-box.columnGap-tablet { +column-gap: calc(var(--spacer-px) * var(--columnGap-tablet)); +} +.slang-box.columnGap-tablet_hover:hover { +column-gap: calc(var(--spacer-px) * var(--columnGap-tablet_hover)); +} +.slang-box.rowGap-tablet { +row-gap: calc(var(--spacer-px) * var(--rowGap-tablet)); +} +.slang-box.rowGap-tablet_hover:hover { +row-gap: calc(var(--spacer-px) * var(--rowGap-tablet_hover)); +} .slang-box.template-tablet { grid-template: var(--template-tablet); } +.slang-box.template-tablet_hover:hover { +grid-template: var(--template-tablet_hover); +} .slang-box.display-tablet { display: var(--display-tablet); } +.slang-box.display-tablet_hover:hover { +display: var(--display-tablet_hover); +} .slang-box.overflow-tablet { overflow: var(--overflow-tablet); } +.slang-box.overflow-tablet_hover:hover { +overflow: var(--overflow-tablet_hover); +} .slang-box.h-tablet { height: var(--h-tablet); } +.slang-box.h-tablet_hover:hover { +height: var(--h-tablet_hover); +} .slang-box.root-tablet { min-height: var(--root-tablet); } +.slang-box.root-tablet_hover:hover { +min-height: var(--root-tablet_hover); +} .slang-box.background-tablet { background-color: var(--background-tablet); } +.slang-box.background-tablet_hover:hover { +background-color: var(--background-tablet_hover); +} +.slang-box.color-tablet { +color: var(--color-tablet); +} +.slang-box.color-tablet_hover:hover { +color: var(--color-tablet_hover); +} .slang-box.contain-tablet { max-width: var(--contain-tablet); } +.slang-box.contain-tablet_hover:hover { +max-width: var(--contain-tablet_hover); +} .slang-box.rad-tablet { border-radius: calc(var(--smallest-border-radius-px) * var(--rad-tablet)); } +.slang-box.rad-tablet_hover:hover { +border-radius: calc(var(--smallest-border-radius-px) * var(--rad-tablet_hover)); +} } @media(min-width: 1024px) { .slang-box.flow-desktop { grid-auto-flow: var(--flow-desktop); } +.slang-box.flow-desktop_hover:hover { +grid-auto-flow: var(--flow-desktop_hover); +} .slang-box.content-desktop { place-content: var(--content-desktop); } +.slang-box.content-desktop_hover:hover { +place-content: var(--content-desktop_hover); +} .slang-box.items-desktop { place-items: var(--items-desktop); } +.slang-box.items-desktop_hover:hover { +place-items: var(--items-desktop_hover); +} .slang-box.self-desktop { place-self: var(--self-desktop); } +.slang-box.self-desktop_hover:hover { +place-self: var(--self-desktop_hover); +} .slang-box.p-desktop { padding: calc(var(--spacer-px) * var(--p-desktop)); } +.slang-box.p-desktop_hover:hover { +padding: calc(var(--spacer-px) * var(--p-desktop_hover)); +} .slang-box.py-desktop { padding-top: calc(var(--spacer-px) * var(--py-desktop)); padding-bottom: calc(var(--spacer-px) * var(--py-desktop)); } +.slang-box.py-desktop_hover:hover { +padding-top: calc(var(--spacer-px) * var(--py-desktop_hover)); padding-bottom: calc(var(--spacer-px) * var(--py-desktop_hover)); +} .slang-box.px-desktop { padding-left: calc(var(--spacer-px) * var(--px-desktop)); padding-right: calc(var(--spacer-px) * var(--px-desktop)); } +.slang-box.px-desktop_hover:hover { +padding-left: calc(var(--spacer-px) * var(--px-desktop_hover)); padding-right: calc(var(--spacer-px) * var(--px-desktop_hover)); +} .slang-box.pt-desktop { padding-top: calc(var(--spacer-px) * var(--pt-desktop)); } +.slang-box.pt-desktop_hover:hover { +padding-top: calc(var(--spacer-px) * var(--pt-desktop_hover)); +} .slang-box.pr-desktop { padding-right: calc(var(--spacer-px) * var(--pr-desktop)); } +.slang-box.pr-desktop_hover:hover { +padding-right: calc(var(--spacer-px) * var(--pr-desktop_hover)); +} .slang-box.pb-desktop { padding-bottom: calc(var(--spacer-px) * var(--pb-desktop)); } +.slang-box.pb-desktop_hover:hover { +padding-bottom: calc(var(--spacer-px) * var(--pb-desktop_hover)); +} .slang-box.pl-desktop { padding-left: calc(var(--spacer-px) * var(--pl-desktop)); } +.slang-box.pl-desktop_hover:hover { +padding-left: calc(var(--spacer-px) * var(--pl-desktop_hover)); +} .slang-box.gap-desktop { gap: calc(var(--spacer-px) * var(--gap-desktop)); } +.slang-box.gap-desktop_hover:hover { +gap: calc(var(--spacer-px) * var(--gap-desktop_hover)); +} +.slang-box.columnGap-desktop { +column-gap: calc(var(--spacer-px) * var(--columnGap-desktop)); +} +.slang-box.columnGap-desktop_hover:hover { +column-gap: calc(var(--spacer-px) * var(--columnGap-desktop_hover)); +} +.slang-box.rowGap-desktop { +row-gap: calc(var(--spacer-px) * var(--rowGap-desktop)); +} +.slang-box.rowGap-desktop_hover:hover { +row-gap: calc(var(--spacer-px) * var(--rowGap-desktop_hover)); +} .slang-box.template-desktop { grid-template: var(--template-desktop); } +.slang-box.template-desktop_hover:hover { +grid-template: var(--template-desktop_hover); +} .slang-box.display-desktop { display: var(--display-desktop); } +.slang-box.display-desktop_hover:hover { +display: var(--display-desktop_hover); +} .slang-box.overflow-desktop { overflow: var(--overflow-desktop); } +.slang-box.overflow-desktop_hover:hover { +overflow: var(--overflow-desktop_hover); +} .slang-box.h-desktop { height: var(--h-desktop); } +.slang-box.h-desktop_hover:hover { +height: var(--h-desktop_hover); +} .slang-box.root-desktop { min-height: var(--root-desktop); } +.slang-box.root-desktop_hover:hover { +min-height: var(--root-desktop_hover); +} .slang-box.background-desktop { background-color: var(--background-desktop); } +.slang-box.background-desktop_hover:hover { +background-color: var(--background-desktop_hover); +} +.slang-box.color-desktop { +color: var(--color-desktop); +} +.slang-box.color-desktop_hover:hover { +color: var(--color-desktop_hover); +} .slang-box.contain-desktop { max-width: var(--contain-desktop); } +.slang-box.contain-desktop_hover:hover { +max-width: var(--contain-desktop_hover); +} .slang-box.rad-desktop { border-radius: calc(var(--smallest-border-radius-px) * var(--rad-desktop)); } +.slang-box.rad-desktop_hover:hover { +border-radius: calc(var(--smallest-border-radius-px) * var(--rad-desktop_hover)); +} } .slang-type.weight { font-weight: var(--weight); } +.slang-type.weight_hover:hover { +font-weight: var(--weight_hover); +} .slang-type.color { color: var(--color); } +.slang-type.color_hover:hover { +color: var(--color_hover); +} @media(min-width: 768px) { .slang-type.weight-tablet { font-weight: var(--weight-tablet); } +.slang-type.weight-tablet_hover:hover { +font-weight: var(--weight-tablet_hover); +} .slang-type.color-tablet { color: var(--color-tablet); } +.slang-type.color-tablet_hover:hover { +color: var(--color-tablet_hover); +} } @media(min-width: 1024px) { .slang-type.weight-desktop { font-weight: var(--weight-desktop); } +.slang-type.weight-desktop_hover:hover { +font-weight: var(--weight-desktop_hover); +} .slang-type.color-desktop { color: var(--color-desktop); } +.slang-type.color-desktop_hover:hover { +color: var(--color-desktop_hover); +} } \ No newline at end of file diff --git a/docs/components/theme.tsx b/docs/components/theme.tsx index 9971902..9cd079b 100644 --- a/docs/components/theme.tsx +++ b/docs/components/theme.tsx @@ -3,16 +3,17 @@ import { Box, BoxProps, Type, TypeProps } from "slang"; import styles from "./theme.module.scss"; const sharedCodeStyle: Partial = { - rad: 1, - background: "palette-white-3", + rad: 2, + background: "palette-black-1", + color: "palette-white-1", }; export function Code(props: BoxProps) { return ( @@ -33,7 +34,7 @@ export function InlineCode(props: BoxProps) { } export function Section(props: BoxProps) { - return ; + return ; } export function Page(props: BoxProps) { @@ -41,9 +42,9 @@ export function Page(props: BoxProps) { } export function Title(props: TypeProps) { - return ; + return ; } export function Subtitle(props: TypeProps) { - return ; + return ; } diff --git a/docs/pages/_app.tsx b/docs/pages/_app.tsx index dd6ca4a..56b09c8 100644 --- a/docs/pages/_app.tsx +++ b/docs/pages/_app.tsx @@ -2,8 +2,11 @@ import "../styles/globals.css"; import "../components/slang/slang.css"; import DocsLayout from "../components/DocsLayout"; import Head from "next/head"; +import { useRouter } from "next/router"; function MyApp({ Component, pageProps }) { + const { pathname } = useRouter(); + const withLayout = !(pathname === "/"); return ( <> @@ -14,10 +17,13 @@ function MyApp({ Component, pageProps }) { src="https://plausible.io/js/plausible.js" /> - - {/* + {withLayout ? ( + + + + ) : ( - */} + )} ); } diff --git a/docs/pages/box.tsx b/docs/pages/box.tsx index 85a198e..19f8090 100644 --- a/docs/pages/box.tsx +++ b/docs/pages/box.tsx @@ -1,4 +1,11 @@ -import { Code, InlineCode, Page, Section } from "components/theme"; +import { + Code, + InlineCode, + Page, + Section, + Subtitle, + Title, +} from "components/theme"; import React from "react"; import { Type, Box } from "slang"; @@ -6,9 +13,7 @@ export default function BoxPage() { return (
- - Box - + Box The box is the swiss-army-knife of layout in Slang. Because it does so much, I thought instead of organizing this page around what the box @@ -18,9 +23,7 @@ export default function BoxPage() {
- - The Right Height - + The Right Height It can be difficult to get your app to be the right height. As best we can tell, it's beneficial for every site to be at least the @@ -51,6 +54,7 @@ export default function BoxPage() { content (blogs), and h for SPA's.
+ Test
); } diff --git a/docs/pages/.index.tsx b/docs/pages/test-index.tsx similarity index 64% rename from docs/pages/.index.tsx rename to docs/pages/test-index.tsx index 22f50cb..a28b57f 100644 --- a/docs/pages/.index.tsx +++ b/docs/pages/test-index.tsx @@ -1,22 +1,23 @@ -import { Code, InlineCode, Page, Section, Title } from "../components/theme"; -import { Type, Box } from "slang"; +import { + InlineCode, + Page, + Section, + Subtitle, + Title, +} from "../components/theme"; +import { Type } from "slang"; import React from "react"; -import Link from "next/link"; export default function Home() { return (
Slang - - Welcome! This the documentation for the open source UI component - library called Slang. It's not quite ready to use but it will be soon. - - Stay tuned, there's more to come! 🍿 -
-
- - Why? + Open-source UI framework for rapid development. + + Slang is a component library with a small set of swiss-army-knife-like + components coupled with a CSS generation pipeline. Slang is mainly + built with DX in mind. The idea driving Slang is that we can do a large part of what's needed @@ -26,9 +27,7 @@ export default function Home() { In additon to that, Slang is:
- - ✅   CSS First - + ✅   CSS First The internet has a had a zero-runtime approach to styling since 1996. @@ -41,9 +40,7 @@ export default function Home() {
- - ✅   Continuous By Design - + ✅   Continuous By Design Although there are plenty of reasons we still need media queries, there is a lot to be gained by making our designs more fluid at the @@ -52,9 +49,6 @@ export default function Home() { better use of screen-space over a broader range of devices.
- - Cool Button! -
); } diff --git a/docs/pages/type.tsx b/docs/pages/type.tsx index 8419157..3f9908c 100644 --- a/docs/pages/type.tsx +++ b/docs/pages/type.tsx @@ -1,12 +1,10 @@ -import { Section } from "components/theme"; +import { Section, Title } from "components/theme"; import { Type } from "slang"; export default function TypePage() { return (
- - Type - + Type This is the type page.
); diff --git a/slang/src/Box/Box.tsx b/slang/src/Box/Box.tsx index b55680d..203fda4 100644 --- a/slang/src/Box/Box.tsx +++ b/slang/src/Box/Box.tsx @@ -1,9 +1,10 @@ import React, { Ref } from "react"; import { - ResponsifyComponentProps, + Responsify, PropsWithAs, produceComponentClassesPropsGetter, separateComponentProps, + Hoverify, } from "../utils"; import "./Box.css"; import { boxConfig, propKeys, ResponsiveProps } from "./props"; @@ -11,9 +12,9 @@ import { boxConfig, propKeys, ResponsiveProps } from "./props"; export type BaseBoxProps< Breakpoint extends string = "tablet" | "desktop", Colors extends string = "foreground" | "background" -> = ResponsifyComponentProps, Breakpoint>; +> = Responsify>, Breakpoint>; -const componentKeys = [...propKeys, "at"]; +const componentKeys = [...propKeys, "at", "hover"]; const getCssClasses = produceComponentClassesPropsGetter< BaseBoxProps, diff --git a/slang/src/Box/props.ts b/slang/src/Box/props.ts index d933b0e..8aaf1e7 100644 --- a/slang/src/Box/props.ts +++ b/slang/src/Box/props.ts @@ -38,6 +38,8 @@ export interface ResponsiveProps< items?: string; self?: string; gap?: number; + columnGap?: number; + rowGap?: number; flow?: "column" | "row"; display?: boolean | string; @@ -66,6 +68,7 @@ export interface ResponsiveProps< // Colors background?: Colors; + color?: Colors; } // Must include all Keys!! @@ -90,6 +93,9 @@ export const propKeys = [ "root", "rad", "background", + "color", + "columnGap", + "rowGap", ]; export const boxConfig: ComponentConfig[] = [ @@ -146,6 +152,16 @@ export const boxConfig: ComponentConfig[] = [ defaultValue: "0", cssFromVariable: (v) => `gap: calc(var(--spacer-px) * ${v});`, }, + { + key: "columnGap", + defaultValue: "0", + cssFromVariable: (v) => `column-gap: calc(var(--spacer-px) * ${v});`, + }, + { + key: "rowGap", + defaultValue: "0", + cssFromVariable: (v) => `row-gap: calc(var(--spacer-px) * ${v});`, + }, { key: "template", defaultValue: "none / none", @@ -207,6 +223,12 @@ export const boxConfig: ComponentConfig[] = [ cssFromVariable: (v) => `background-color: ${v};`, propValueToCssValue: (s) => s && `var(--${s})`, }, + { + key: "color", + defaultValue: "var(--color)", + cssFromVariable: (v) => `color: ${v};`, + propValueToCssValue: (s) => s && `var(--${s})`, + }, { key: "contain", defaultValue: "var(--base-container-size-px)", diff --git a/slang/src/Type/Type.tsx b/slang/src/Type/Type.tsx index 14e3dfa..cfbebbf 100644 --- a/slang/src/Type/Type.tsx +++ b/slang/src/Type/Type.tsx @@ -1,9 +1,10 @@ import React, { Ref } from "react"; import "./Type.scss"; import { + Hoverify, produceComponentClassesPropsGetter, PropsWithAs, - ResponsifyComponentProps, + Responsify, separateComponentProps, } from "../utils"; import { typeConfig, ResponsiveProps, propKeys } from "./props"; @@ -11,7 +12,7 @@ import { typeConfig, ResponsiveProps, propKeys } from "./props"; export interface BaseTypeProps< Breakpoint extends string = "tablet" | "desktop", Colors extends string = "foreground" | "background" -> extends ResponsifyComponentProps, Breakpoint> { +> extends Responsify>, Breakpoint> { size?: number; } diff --git a/slang/src/createComponentCss.ts b/slang/src/createComponentCss.ts new file mode 100644 index 0000000..f08f06d --- /dev/null +++ b/slang/src/createComponentCss.ts @@ -0,0 +1,96 @@ +import { SlangConfig, defaultConfig, componentClassesConfig } from "./config"; +import { SAFARI_PATCH_KEY } from "./constants"; + +export function createComponentCss(userConfig?: Partial): string { + let cssLines: string[] = [""]; + const config = { ...defaultConfig, ...userConfig }; + + // Loop over each component's responsive property list + for (const [className, configList] of Object.entries( + componentClassesConfig, + )) { + // Loop over each property + for (const prop of configList) { + cssLines = cssLines.concat( + `.${className}.${prop.key.toString()} {`, + prop.cssFromVariable(`var(--${prop.key.toString()})`), + `}`, + ); + + // add hover + cssLines = cssLines.concat( + `.${className}.${prop.key.toString()}_hover:hover {`, + prop.cssFromVariable(`var(--${prop.key.toString()}_hover)`), + `}`, + ); + + // Check for safari patch and do the same + if ("iosSafariPatch" in prop) { + cssLines = cssLines.concat( + "@supports (-webkit-touch-callout: none) {", + `.${className}.${prop.key.toString()}-${SAFARI_PATCH_KEY} {`, + prop.cssFromVariable( + `var(--${prop.key.toString()}-${SAFARI_PATCH_KEY})`, + ), + "}", + "}", + ); + } + } + + // Loop over each breakpoint + for (const [breakpoint, size] of Object.entries(config.breakpoints)) { + cssLines = cssLines.concat([ + `@media(min-width: ${size}px) {`, + ...configList.reduce( + (acc, p) => + acc.concat([ + `.${className}.${p.key.toString()}-${breakpoint} {`, + p.cssFromVariable(`var(--${p.key.toString()}-${breakpoint})`), + `}`, + // hover + `.${className}.${p.key.toString()}-${breakpoint}_hover:hover {`, + p.cssFromVariable( + `var(--${p.key.toString()}-${breakpoint}_hover)`, + ), + `}`, + ]), + [], + ), + `}`, + ]); + } + } + + return cssLines.join("\n"); +} + +/* +- root class, classes to apply (replacing properties) +- for each class: + - + + +what is the real point of scoping these classes under a given main class? +to ensure that they perform their supposed duty. but really maybe it's more of a many-to-many dependency graph +that ensure that a specific class performs its duty. +for instance if you add gap then it will automatically add display grid or flex or whatever is needed + +the logic is like + +for any given class-property module, it either accomplishes what it sets out to accomplish OR +there is one or more smallest sets which are also needed to accomplish the function of the class-property-module CPM +so it automatically applies the other class + +i guess the question is when do we finally apply those styles to a component? +if the CPM is functionally self-contained. can it truly be used on any element? +do we use the CSS types to know if an element can truly perform the task of the type :\ + +there's a class + and it does two things: + - its a function of (one or more css properties) => the css to accomplish it + - and a function that maps from (what you pass to a component) => to what value gets set on the css property value + + + +*/ diff --git a/slang/src/createResponsiveCss.ts b/slang/src/createResponsiveCss.ts deleted file mode 100644 index e8adcaf..0000000 --- a/slang/src/createResponsiveCss.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { SlangConfig, defaultConfig, componentClassesConfig } from "./config"; -import { SAFARI_PATCH_KEY } from "./constants"; - -export function createResponsiveCss(userConfig?: Partial): string { - let cssLines: string[] = [""]; - const config = { ...defaultConfig, ...userConfig }; - - // Loop over each component's responsive property list - for (const [className, configList] of Object.entries( - componentClassesConfig, - )) { - // Loop over each property - for (const prop of configList) { - cssLines = cssLines.concat( - `.${className}.${prop.key.toString()} {`, - prop.cssFromVariable(`var(--${prop.key.toString()})`), - `}`, - ); - - // Check for safari patch and do the same - if ("iosSafariPatch" in prop) { - cssLines = cssLines.concat( - "@supports (-webkit-touch-callout: none) {", - `.${className}.${prop.key.toString()}-${SAFARI_PATCH_KEY} {`, - prop.cssFromVariable( - `var(--${prop.key.toString()}-${SAFARI_PATCH_KEY})`, - ), - "}", - "}", - ); - } - } - - // Loop over each breakpoint - for (const [breakpoint, size] of Object.entries(config.breakpoints)) { - cssLines = cssLines.concat([ - `@media(min-width: ${size}px) {`, - ...configList.reduce( - (acc, p) => - acc.concat([ - `.${className}.${p.key.toString()}-${breakpoint} {`, - p.cssFromVariable(`var(--${p.key.toString()}-${breakpoint})`), - `}`, - ]), - [], - ), - `}`, - ]); - } - } - - return cssLines.join("\n"); -} diff --git a/slang/src/makeCSS.ts b/slang/src/makeCSS.ts index 40e4338..29a9797 100644 --- a/slang/src/makeCSS.ts +++ b/slang/src/makeCSS.ts @@ -1,11 +1,11 @@ -import { createResponsiveCss } from "./createResponsiveCss"; +import { createComponentCss } from "./createComponentCss"; import { defaultConfig, SlangConfig } from "./config"; export function makeCSS(config?: Partial) { const cssProperties = createProperties(config); const derivedProperties = createDerivedProperties(config); const colorProperties = createColorProperties(config); - const responsiveCss = createResponsiveCss(config); + const responsiveCss = createComponentCss(config); return [":root {"] .concat( Object.entries({ diff --git a/slang/src/utils.ts b/slang/src/utils.ts index 5e6289b..414f777 100644 --- a/slang/src/utils.ts +++ b/slang/src/utils.ts @@ -26,11 +26,11 @@ export function forwardRefWithAs( >; } -type ResponsiveComponentProperty = { +type ResponsiveComponentProperty = { /** * CSS Custom Property Name */ - key: keyof X; + key: keyof ResponsiveProperties; /** * Initial value, if prop is passed to component @@ -50,7 +50,7 @@ type ResponsiveComponentProperty = { * Custom logic in converting what the user passes * into the component, into the value that will be assed to the custom property */ - propValueToCssValue?: (x: keyof X) => string | undefined; + propValueToCssValue?: (x: keyof ResponsiveProperties) => string | undefined; /** * Declares that a patch needs to be made to make ios safari behavior consistent @@ -62,7 +62,7 @@ type ResponsiveComponentProperty = { */ iosSafariPatch?: { cssFromVariable: (customProperty: string) => string; - propValueToCssValue?: (x: keyof X) => string | undefined; + propValueToCssValue?: (x: keyof ResponsiveProperties) => string | undefined; }; }; @@ -70,10 +70,17 @@ export type ComponentConfig = { [T in keyof X]-?: ResponsiveComponentProperty; }[keyof X]; -export type ResponsifyComponentProps = { +export type Hoverify = { + hover?: Partial; +} & CProps; + +export type Responsify = { at?: Partial>; } & CProps; +// A prop accepts an object with pseudo states as well... +export type AllowPseudo = T | { default?: T; hover?: T }; + /** * Returns a function, which takes the component's props * and returns the components classes and css custom properties @@ -83,7 +90,7 @@ export type ResponsifyComponentProps = { * `const [cssProperties, dynamicClasses] = getComponentClassesProps(props);` */ export function produceComponentClassesPropsGetter( - toReduce: any[], + configArray: any[], ) { /* function getComponentClassesProps(node: PropsWithAs, "div">): [React.CSSProperties, string[]] @@ -95,7 +102,7 @@ export function produceComponentClassesPropsGetter( return function getComponentClassesProps( node: ComponentProps, ): [CSSProperties, string[]] { - const [props, classes] = toReduce.reduce<[CSSProperties, string[]]>( + const [props, classes] = configArray.reduce<[CSSProperties, string[]]>( (acc, prop) => { const [properties, classes] = getIndividualChildCssProp< ComponentProps, @@ -129,23 +136,46 @@ function getIndividualChildCssProp< node, iosSafariPatch, }: ComponentConfig & { - node: ResponsifyComponentProps; + node: Responsify, Breakpoint>; }): [Record, string[]] { // Setup const classes: string[] = []; const properties = {} as Record; let last = defaultValue; + // hover classes/properties need to be added at root & breakpoint sizes + function handleHover( + cProps: Partial>, + key: string | number | symbol, + breakpoint?: string, + ) { + // add return hover classes/properties or nothing + if ("hover" in cProps) { + const value = propValueToCssValue(cProps.hover?.[key]); + if (value) { + const thisKey = [key, breakpoint].filter(Boolean).join("-"); + // add the class + classes.push(`${thisKey}_hover`); + // which activates the property value + properties[`--${thisKey}_hover`] = value; + } + } + } + // Setup default // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const v = propValueToCssValue(node?.[key]); if (v) { last = v; + // add the class classes.push(key.toString()); + // which activates the property value properties[`--${key}`] = last; } + handleHover(node, key); + if (iosSafariPatch && iosSafariPatch.propValueToCssValue) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -174,6 +204,8 @@ function getIndividualChildCssProp< last = value; } properties[`--${key}-${breakpoint}`] = v; + + handleHover(node.at[breakpoint], key, breakpoint); } } return [properties, classes];