diff --git a/.changeset/bold-towns-exist.md b/.changeset/bold-towns-exist.md new file mode 100644 index 0000000..7ea18a8 --- /dev/null +++ b/.changeset/bold-towns-exist.md @@ -0,0 +1,13 @@ +--- +"@hebilicious/cssforge": minor +--- + +# Introduce variantNameOnly feature for themes. + +When working with themes, you can choose to only include the variant name in the CSS +variable name by setting `variantNameOnly: true` in the color definition settings. This is +usually used in combination with `condition` to conditionnally apply themes. + +- Default: `--theme-${themeName}-${colorName}-${variantName}` +- VariantOnly Name: `--${variantName}` +- Path : `theme.${themeName}.${colorName}.${variantName}` diff --git a/CHANGELOG.md b/CHANGELOG.md index a22202d..faa1840 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,8 @@ - 41bff15: # Conditions and variables access - Add the posibility to add conditions for colors modules. This is a breaking change for the - configuration format. + Add the posibility to add conditions for colors modules. This is a breaking change for + the configuration format. ## 0.2.1 diff --git a/README.md b/README.md index afa37b0..ade741b 100644 --- a/README.md +++ b/README.md @@ -247,7 +247,10 @@ export default defineConfig({ }, variables: { 1: "palette.simple.white", - 2: "gradients.white-green.primary", + 2: "gradients.white-green.primary", //Reference the color name directly. + }, + settings: { + variantNameOnly: true, }, }, }, @@ -263,12 +266,35 @@ export default defineConfig({ 1: "palette.another.yellow", 2: "palette.another.cyan", }, + settings: { + variantNameOnly: true, + }, }, }, settings: { condition: "@media (prefers-color-scheme: dark)", }, }, + pink: { + value: { + background: { + value: { + primary: "var(--1)", + secondary: "var(--2)", + }, + variables: { + 1: "palette.simple.red", + 2: "palette.simple.violet", + }, + settings: { + variantNameOnly: true, + }, + }, + }, + settings: { + condition: ".ThemePink", + }, + }, }, }, }); @@ -325,7 +351,10 @@ export default defineConfig({ }, variables: { 1: "palette.simple.white", - 2: "gradients.white-green", //Reference the color name directly. + 2: "gradients.white-green.primary", //Reference the color name directly. + }, + settings: { + variantNameOnly: true, }, }, }, @@ -341,12 +370,35 @@ export default defineConfig({ 1: "palette.another.yellow", 2: "palette.another.cyan", }, + settings: { + variantNameOnly: true, + }, }, }, settings: { condition: "@media (prefers-color-scheme: dark)", }, }, + pink: { + value: { + background: { + value: { + primary: "var(--1)", + secondary: "var(--2)", + }, + variables: { + 1: "palette.simple.red", + 2: "palette.simple.violet", + }, + settings: { + variantNameOnly: true, + }, + }, + }, + settings: { + condition: ".ThemePink", + }, + }, }, }, }); @@ -366,31 +418,56 @@ This will generate the following CSS : --palette-simple-blue: oklch(45.201% 0.31321 264.05202); --palette-simple-violet: oklch(70% 0.2 270); --palette-simple-red: oklch(62.796% 0.25768 29.23388); + /* another */ .Another { - /* another */ --palette-another-yellow: oklch(96.798% 0.21101 109.76924); --palette-another-cyan: oklch(90.54% 0.15455 194.76896); } - /* Gradients */ + /* Gradients */ + /* white-green */ --gradients-white-green-primary: linear-gradient( to right, var(--palette-simple-white), var(--palette-simple-green) ); - /* Themes */ + /* Themes */ /* Theme: light */ /* background */ + --primary: var(--palette-simple-white); + --secondary: var(--gradients-white-green-primary); + /* Theme: dark */ @media (prefers-color-scheme: dark) { - /* Theme: dark */ /* background */ - --theme-dark-background-primary: var(--palette-another-yellow); - --theme-dark-background-secondary: var(--palette-another-cyan); + --primary: var(--palette-another-yellow); + --secondary: var(--palette-another-cyan); + } + /* Theme: pink */ + .ThemePink { + /* background */ + --primary: var(--palette-simple-red); + --secondary: var(--palette-simple-violet); } } ``` +#### Condition + +You can conditionnally apply colors, gradients or themes by setting the `condition` +property to a selector or media query. Your variables will be wrapped within the +condition. + +#### Theme: Variant Name Only + +When working with themes, you can choose to only include the variant name in the CSS +variable name by setting `variantNameOnly: true` in the color definition settings. This is +usually used in combination with `condition` to conditionnally apply themes. + +- Default: `--theme-${themeName}-${colorName}-${variantName}` +- VariantOnly Name: `--${variantName}` +- Path : `theme.${themeName}.${colorName}.${variantName}` + ### Spacing Define custom spacing scale, that can be referenced for other types, such as primitives. diff --git a/src/modules/colors.ts b/src/modules/colors.ts index a9a0567..a3b5100 100644 --- a/src/modules/colors.ts +++ b/src/modules/colors.ts @@ -97,7 +97,13 @@ interface ColorInThemeValues { interface ColorInTheme { value: ColorInThemeValues; variables?: Variables; - settings?: unknown; + settings?: { + /** + * Only include the variant name in the CSS variable name. + * --theme-light-colors-primaryBackground => --primaryBackground + */ + variantNameOnly?: boolean; + }; } export interface ThemeConfig { @@ -222,18 +228,19 @@ export function processColors(colors: ColorConfig): Output { settings: WithCondition | undefined, initialComment: string, ) { - const comments: string[] = []; + const leadingComments: string[] = []; + const innerComments: string[] = []; const vars: string[] = []; if (settings?.condition) { - comments.push(initialComment); + leadingComments.push(initialComment); } else { cssOutput.push(initialComment); } return { addComment(c: string) { - if (settings?.condition) comments.push(c); + if (settings?.condition) innerComments.push(c); else cssOutput.push(c); }, pushVariable(v: string) { @@ -242,8 +249,9 @@ export function processColors(colors: ColorConfig): Output { }, finalize() { if (settings?.condition && vars.length > 0) { + cssOutput.push(...leadingComments); cssOutput.push(`${settings.condition} {`); - cssOutput.push(...comments.map((c) => ` ${c}`)); + cssOutput.push(...innerComments.map((c) => ` ${c}`)); cssOutput.push(...vars.map((v) => ` ${v}`)); cssOutput.push(`}`); } @@ -349,14 +357,18 @@ export function processColors(colors: ColorConfig): Output { colors: palette, }); + const variantNameOnly = colorInTheme.settings?.variantNameOnly ?? false; for (const [variantName, variantValue] of Object.entries(colorInTheme.value)) { validateName(variantName); const resolvedValue = resolveValue({ map: resolvedMap, - value: variantValue as string, + value: variantValue, }); - const key = `--${moduleKey}-${themeName}-${colorName}-${variantName}`; + const key = variantNameOnly + ? `--${variantName}` + : `--${moduleKey}-${themeName}-${colorName}-${variantName}`; + const variable = `${key}: ${resolvedValue};`; handler.pushVariable(variable); diff --git a/tests/__snapshots__/colors.test.ts.snap b/tests/__snapshots__/colors.test.ts.snap index b800da7..3c2fdaa 100644 --- a/tests/__snapshots__/colors.test.ts.snap +++ b/tests/__snapshots__/colors.test.ts.snap @@ -284,8 +284,8 @@ snapshot[`processColors - handles gradients with conditions 1`] = ` /* coral */ --palette-coral-50: oklch(73.58% 0.16378 34.33822); /* Gradients */ +/* orangeGradient */ @media (prefers-color-scheme: dark) { - /* orangeGradient */ --gradients-orangeGradient-primary: linear-gradient(to right, var(--palette-coral-50), var(--palette-coral-50)); }" `; @@ -315,8 +315,8 @@ snapshot[`processColors - handles palette colors with conditions 1`] = ` "/* Palette */ /* background */ --palette-background-light: oklch(100% 0 0); +/* backgroundDark */ @media (prefers-color-scheme: dark) { - /* backgroundDark */ --palette-backgroundDark-dark: oklch(0% 0 0); }" `; @@ -347,8 +347,8 @@ snapshot[`processColors - handles themes with class condition 1`] = ` /* base */ --palette-base-primary: oklch(73.511% 0.16799 40.24666); /* Themes */ +/* Theme: dark */ .dark-theme { - /* Theme: dark */ /* background */ --theme-dark-background-primary: var(--palette-base-primary); }" @@ -374,3 +374,52 @@ snapshot[`processColors - handles themes with class condition 2`] = ` ], ] `; + +snapshot[`processColors - handles theme variantNameOnly 1`] = ` +"/* Palette */ +/* simple */ +--palette-simple-white: oklch(100% 0 0); +--palette-simple-black: oklch(0% 0 0); +/* Themes */ +/* Theme: light */ +/* background */ +--primary: var(--palette-simple-white); +--secondary: var(--palette-simple-black);" +`; + +snapshot[`processColors - handles theme variantNameOnly 2`] = ` +[ + [ + "palette.simple.white", + { + key: "--palette-simple-white", + value: "oklch(100% 0 0)", + variable: "--palette-simple-white: oklch(100% 0 0);", + }, + ], + [ + "palette.simple.black", + { + key: "--palette-simple-black", + value: "oklch(0% 0 0)", + variable: "--palette-simple-black: oklch(0% 0 0);", + }, + ], + [ + "theme.light.background.primary", + { + key: "--primary", + value: "var(--palette-simple-white)", + variable: "--primary: var(--palette-simple-white);", + }, + ], + [ + "theme.light.background.secondary", + { + key: "--secondary", + value: "var(--palette-simple-black)", + variable: "--secondary: var(--palette-simple-black);", + }, + ], +] +`; diff --git a/tests/colors.test.ts b/tests/colors.test.ts index 266964a..108d88a 100644 --- a/tests/colors.test.ts +++ b/tests/colors.test.ts @@ -491,3 +491,58 @@ Deno.test("processColors - handles themes with class condition", async (t) => { await assertSnapshot(t, css); await assertSnapshot(t, Array.from(resolveMap.entries())); }); + +Deno.test("processColors - handles theme variantNameOnly", async (t) => { + const config = defineConfig({ + colors: { + palette: { + value: { + simple: { + value: { + white: "oklch(100% 0 0)", + black: { hex: "#000" }, + }, + }, + }, + }, + theme: { + light: { + value: { + background: { + value: { + primary: "var(--1)", + secondary: "var(--2)", + }, + variables: { + 1: "palette.simple.white", + 2: "palette.simple.black", + }, + settings: { + variantNameOnly: true, + }, + }, + }, + }, + }, + }, + }); + + const { css, resolveMap } = processColors(config.colors); + const lines = getLines(css); + + const primaryLine = lines.find((l) => l.includes("--primary:")); + const secondaryLine = lines.find((l) => l.includes("--secondary:")); + + assertEquals(primaryLine?.trim(), "--primary: var(--palette-simple-white);"); + assertEquals(secondaryLine?.trim(), "--secondary: var(--palette-simple-black);"); + + assertEquals(Array.from(resolveMap.keys()), [ + "palette.simple.white", + "palette.simple.black", + "theme.light.background.primary", + "theme.light.background.secondary", + ]); + + await assertSnapshot(t, css); + await assertSnapshot(t, Array.from(resolveMap.entries())); +});