diff --git a/.changeset/yellow-glasses-tie.md b/.changeset/yellow-glasses-tie.md
new file mode 100644
index 0000000..2cdcdfa
--- /dev/null
+++ b/.changeset/yellow-glasses-tie.md
@@ -0,0 +1,8 @@
+---
+"@hebilicious/cssforge": minor
+---
+
+# Conditions and variables access
+
+Add the posibility to add conditions for colors modules. This is a breaking change for the
+configuration format.
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index bd74917..7015975 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -34,3 +34,16 @@ jobs:
- name: Publish dry run
run: deno publish --dry-run
+
+ test:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: denoland/setup-deno@v2
+ with:
+ deno-version: v2.x
+
+ - name: Run tests
+ run: deno test -A
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..7960d10
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,44 @@
+# Css Forge Library
+
+This is a library for generating CSS variables from design tokens. This library uses Deno
+and TypeScript.
+
+## Creating new features and modules
+
+Make sure to follow the established conventions for modules in `src/modules`. Make sure to
+add tests following the pattern in the `tests` folder.
+
+## Dependencies
+
+Ask permissions before adding new dependencies. Always prefer using features from the
+standard library or writing code from first principles.
+
+## Updating the README.md
+
+To update the README, use the `deno task readme:update` command. There is a special syntax
+in the README that generates the codeblocks. For a comment like this:
+
+
+
+
+
+It will generate a codeblock below. Therefore, these comments are the source of truth and
+should never be deleted. But they should be updated if the source code changes.
diff --git a/README.md b/README.md
index 07e3e35..afa37b0 100644
--- a/README.md
+++ b/README.md
@@ -39,21 +39,27 @@ For programmatic usage, you can install CSS Forge as a dependency:
# Using npm
npx jsr add @hebilicious/cssforge
-# Using Deno
-deno install jsr:@hebilicious/cssforge
+# Using pnpm (10.9 +)
+pnpm i jsr:@hebilicious/cssforge
```
-For CLI usage, you can also run CSS Forge directly from JSR or install it globally:
+Then to run CSS forge, add the following script to your `package.json` or `deno.json` :
-```bash
-# Run directly from jsr with npx
-npx jsr run @hebilicious/cssforge/cli
+```json
+{
+ "scripts": {
+ "cssforge": "node node_modules/@hebilicious/cssforge/src/cli"
+ }
+}
+```
-# Run directly from jsr with deno
-deno run -A jsr:@hebilicious/cssforge/cli
+then run :
-# Or install globally
-deno install -A -n cssforge jsr:@hebilicious/cssforge/cli
+```bash
+#npm
+npm run cssforge
+#pnpm
+pnpm run cssforge
```
## Quick Start
@@ -96,13 +102,19 @@ export default defineConfig({
palette: {
value: {
coral: {
- 100: { hex: "#FF7F50" },
+ value: {
+ 100: { hex: "#FF7F50" },
+ },
},
mint: {
- 100: { hex: "#4ADE80" },
+ value: {
+ 100: { hex: "#4ADE80" },
+ },
},
indigo: {
- 100: { hex: "#4F46E5" },
+ value: {
+ 100: { hex: "#4F46E5" },
+ },
},
},
},
@@ -112,7 +124,7 @@ export default defineConfig({
2. Run CSS Forge with the CLI :
-If you're using a package.json, you can add the follwing into your scripts :
+If you're using a package.json, add the follwing to your scripts :
```json
{
@@ -163,13 +175,16 @@ For example, you can import as a layer :
}
```
+> !IMPORTANT Do not manually edit the generated CSS file, edit the configuration file
+> instead and regenerate.
+
4. Use the generated css in your JS/TS :
```typescript
import { cssForge } from "./.cssforge/output.ts";
// Use like this anywhere :
-//`cssForge.colors.palette.value.basic.white` is fully typed { key: --myKey, value: white, variable: --key: white }
+//`cssForge.colors.palette.basic.white` is fully typed { key: --myKey, value: white, variable: --key: white }
export { cssForge };
```
@@ -187,12 +202,23 @@ export default defineConfig({
palette: {
value: {
simple: {
- white: "oklch(100% 0 0)",
- black: "#000",
- green: { rgb: [0, 255, 0] },
- blue: { hsl: [240, 100, 50] },
- violet: { oklch: "oklch(0.7 0.2 270)" },
- red: { hex: "#FF0000" },
+ value: {
+ white: "oklch(100% 0 0)",
+ black: "#000",
+ green: { rgb: [0, 255, 0] },
+ blue: { hsl: [240, 100, 50] },
+ violet: { oklch: "oklch(0.7 0.2 270)" },
+ red: { hex: "#FF0000" },
+ },
+ },
+ another: {
+ value: {
+ yellow: { hex: "#FFFF00" },
+ cyan: { hex: "#00FFFF" },
+ },
+ settings: {
+ condition: ".Another",
+ },
},
},
},
@@ -203,8 +229,8 @@ export default defineConfig({
primary: {
value: "linear-gradient(to right, var(--c1), var(--c2))",
variables: {
- "c1": "palette.value.simple.white",
- "c2": "palette.value.simple.green",
+ "c1": "palette.simple.white",
+ "c2": "palette.simple.green",
},
},
},
@@ -212,19 +238,36 @@ export default defineConfig({
},
},
theme: {
- value: {
- light: {
+ light: {
+ value: {
+ background: {
+ value: {
+ primary: "var(--1)",
+ secondary: "var(--2)",
+ },
+ variables: {
+ 1: "palette.simple.white",
+ 2: "gradients.white-green.primary",
+ },
+ },
+ },
+ },
+ dark: {
+ value: {
background: {
value: {
primary: "var(--1)",
secondary: "var(--2)",
},
variables: {
- 1: "palette.value.simple.white",
- 2: "gradients.value.white-green", //Reference the color name directly.
+ 1: "palette.another.yellow",
+ 2: "palette.another.cyan",
},
},
},
+ settings: {
+ condition: "@media (prefers-color-scheme: dark)",
+ },
},
},
},
@@ -237,12 +280,23 @@ export default defineConfig({
palette: {
value: {
simple: {
- white: "oklch(100% 0 0)",
- black: "#000",
- green: { rgb: [0, 255, 0] },
- blue: { hsl: [240, 100, 50] },
- violet: { oklch: "oklch(0.7 0.2 270)" },
- red: { hex: "#FF0000" },
+ value: {
+ white: "oklch(100% 0 0)",
+ black: "#000",
+ green: { rgb: [0, 255, 0] },
+ blue: { hsl: [240, 100, 50] },
+ violet: { oklch: "oklch(0.7 0.2 270)" },
+ red: { hex: "#FF0000" },
+ },
+ },
+ another: {
+ value: {
+ yellow: { hex: "#FFFF00" },
+ cyan: { hex: "#00FFFF" },
+ },
+ settings: {
+ condition: ".Another",
+ },
},
},
},
@@ -253,8 +307,8 @@ export default defineConfig({
primary: {
value: "linear-gradient(to right, var(--c1), var(--c2))",
variables: {
- "c1": "palette.value.simple.white",
- "c2": "palette.value.simple.green",
+ "c1": "palette.simple.white",
+ "c2": "palette.simple.green",
},
},
},
@@ -262,19 +316,36 @@ export default defineConfig({
},
},
theme: {
- value: {
- light: {
+ light: {
+ value: {
+ background: {
+ value: {
+ primary: "var(--1)",
+ secondary: "var(--2)",
+ },
+ variables: {
+ 1: "palette.simple.white",
+ 2: "gradients.white-green", //Reference the color name directly.
+ },
+ },
+ },
+ },
+ dark: {
+ value: {
background: {
value: {
primary: "var(--1)",
secondary: "var(--2)",
},
variables: {
- 1: "palette.value.simple.white",
- 2: "gradients.value.white-green", //Reference the color name directly.
+ 1: "palette.another.yellow",
+ 2: "palette.another.cyan",
},
},
},
+ settings: {
+ condition: "@media (prefers-color-scheme: dark)",
+ },
},
},
},
@@ -288,20 +359,33 @@ This will generate the following CSS :
:root {
/*____ Colors ____*/
/* Palette */
+ /* simple */
--palette-simple-white: oklch(100% 0 0);
--palette-simple-black: oklch(0% 0 0);
--palette-simple-green: oklch(86.644% 0.29483 142.49535);
--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 */
+ --palette-another-yellow: oklch(96.798% 0.21101 109.76924);
+ --palette-another-cyan: oklch(90.54% 0.15455 194.76896);
+ }
/* Gradients */
--gradients-white-green-primary: linear-gradient(
to right,
var(--palette-simple-white),
var(--palette-simple-green)
);
+ /* Themes */
/* Theme: light */
/* background */
+ @media (prefers-color-scheme: dark) {
+ /* Theme: dark */
+ /* background */
+ --theme-dark-background-primary: var(--palette-another-yellow);
+ --theme-dark-background-secondary: var(--palette-another-cyan);
+ }
}
```
@@ -508,22 +592,6 @@ This will generate the following CSS :
-#### Referencing Fluid Spacing
-
-To reference fluid spacing, use the `@` symbol and the label of the scale; ie:
-`spacing_fluid-base@xs`. Do not include the prefix in the reference. The labels follow the
-following convention :
-
-- 3xs
-- 2xs
-- xs
-- s
-- m
-- l
-- xl
-- 2xl
-- 3xl
-
### Typography
Define your typography, with fluid typescales powered by
@@ -689,22 +757,6 @@ This will generate the following CSS :
-#### Referencing Fluid Typography
-
-To reference fluid typography, use the `@` symbol and the label of the scale; ie:
-`typography_fluid.comicsans@a`. Do not include the prefix in the reference. The labels
-follow the following convention :
-
-- 3xs
-- 2xs
-- xs
-- s
-- m
-- l
-- xl
-- 2xl
-- 3xl
-
### Primitives
More flexible than other types, primitives allow you to define any type of token by
@@ -751,8 +803,8 @@ export default defineConfig({
},
variables: {
"base": "typography_fluid.arial@m",
- "2": "spacing.custom.size.value.2",
- "3": "spacing.custom.size.value.3",
+ "2": "spacing.custom.size.2",
+ "3": "spacing.custom.size.3",
},
},
},
@@ -803,8 +855,8 @@ export default defineConfig({
},
variables: {
"base": "typography_fluid.arial@m",
- "2": "spacing.custom.size.value.2",
- "3": "spacing.custom.size.value.3",
+ "2": "spacing.custom.size.2",
+ "3": "spacing.custom.size.3",
},
},
},
@@ -843,17 +895,77 @@ This will generate the following CSS :
+## Referencing Variables
+
+### Basic Referencing
+
+To reference any variable, use the `.` notation to navigate through the schema without
+using `.value`.
+
+For example, if an object has the following structure :
+
+```typescript
+{
+ spacing: {
+ custom: {
+ size: {
+ value: {
+ 1: "0.25rem",
+ },
+ },
+ },
+ },
+}
+```
+
+The reference would be : `spacing.custom.size.1`, not `spacing.custom.size.value.1`.
+
+#### Referencing Fluid Spacing
+
+To reference fluid spacing, use the `@` symbol and the label of the scale; ie:
+`spacing_fluid-base@xs`. Do not include the prefix in the reference. The labels follow the
+following convention :
+
+- 3xs
+- 2xs
+- xs
+- s
+- m
+- l
+- xl
+- 2xl
+- 3xl
+
+### Referencing Fluid Typography
+
+To reference fluid typography, use the `@` symbol and the label of the scale; ie:
+`typography_fluid.comicsans@a`. Do not include the prefix in the reference. The labels
+follow the following convention :
+
+- 3xs
+- 2xs
+- xs
+- s
+- m
+- l
+- xl
+- 2xl
+- 3xl
+
## CLI Usage
+Assuming you have added the script to your `package.json`, you can run CSS Forge like this
+:
+
```bash
# Basic usage
-cssforge
+npm run cssforge
# Watch mode
-cssforge --watch
+npm run cssforge -- --watch
# Custom paths and output
-cssforge --config ./foo/bar/custom-path.ts --css ./dist/design-tokens.css --ts ./dist/design-tokens.ts --json ./dist/design-tokens.json --mode all
+npm run cssforge --config ./foo/bar/custom-path.ts --css ./dist/design-tokens.css --ts ./dist/design-tokens.ts --json ./dist/design-tokens.json --mode all
```
## Programmatic Usage
@@ -867,10 +979,20 @@ import { generateCSS } from "jsr:@hebilicious/cssforge";
const css = generateCSS(config);
```
+## Agentic usage
+
+CSSForge is intentionally designed to be extremely simple and integrate well with various
+agents, such as Github Copilot, Gemini, Claude Code ... While there's no documentation
+yet, you can add the README file to the agent context directly.
+
+For most agents, this syntax works
+`@https://raw.githubusercontent.com/Hebilicious/cssforge/refs/heads/main/README.md`.
+
## Best Practices
- **Version Control**: Commit your generated CSS files
- **CSS Layers**: Use `@layer` to manage specificity
+- **Config First**: Always edit the config file, never edit the generated files
## Examples
diff --git a/deno.json b/deno.json
index 9d0c951..8e686d8 100644
--- a/deno.json
+++ b/deno.json
@@ -15,6 +15,7 @@
"chokidar": "npm:chokidar@4.0.3",
"@std/collections": "jsr:@std/collections@^1.1.3",
"@std/assert": "jsr:@std/assert@^1.0.14",
+ "@std/testing": "jsr:@std/testing@^1.0.14",
"colorjs.io": "npm:colorjs.io@0.5.2",
"utopia-core": "npm:utopia-core@1.6.0",
"mdbox": "npm:mdbox@0.1.1"
@@ -28,6 +29,7 @@
"tasks": {
"cli": "deno run -A ./src/cli.ts",
"example:cli": "deno run -A ./src/cli.ts --prefix ./example/basic --mode css",
- "readme:update": "deno run -A ./scripts/update-readme.ts"
+ "readme:update": "deno run -A ./scripts/update-readme.ts",
+ "update:snapshot": "deno test -A -- --update"
}
}
diff --git a/deno.lock b/deno.lock
index 1b29ffc..b741530 100644
--- a/deno.lock
+++ b/deno.lock
@@ -2,14 +2,21 @@
"version": "5",
"specifiers": {
"jsr:@std/assert@*": "1.0.9",
- "jsr:@std/assert@^1.0.14": "1.0.14",
+ "jsr:@std/assert@^1.0.14": "1.0.15",
+ "jsr:@std/assert@^1.0.15": "1.0.15",
+ "jsr:@std/async@^1.0.15": "1.0.15",
"jsr:@std/collections@^1.1.3": "1.1.3",
+ "jsr:@std/data-structures@^1.0.9": "1.0.9",
"jsr:@std/fs@1": "1.0.19",
- "jsr:@std/internal@^1.0.10": "1.0.10",
+ "jsr:@std/fs@^1.0.19": "1.0.19",
+ "jsr:@std/internal@^1.0.10": "1.0.12",
+ "jsr:@std/internal@^1.0.12": "1.0.12",
"jsr:@std/internal@^1.0.5": "1.0.5",
"jsr:@std/internal@^1.0.9": "1.0.10",
"jsr:@std/path@1": "1.1.2",
"jsr:@std/path@^1.1.1": "1.1.2",
+ "jsr:@std/path@^1.1.2": "1.1.2",
+ "jsr:@std/testing@^1.0.14": "1.0.16",
"npm:@changesets/cli@*": "2.29.6",
"npm:@types/node@*": "24.2.0",
"npm:chokidar@4.0.3": "4.0.3",
@@ -31,9 +38,21 @@
"jsr:@std/internal@^1.0.10"
]
},
+ "@std/assert@1.0.15": {
+ "integrity": "d64018e951dbdfab9777335ecdb000c0b4e3df036984083be219ce5941e4703b",
+ "dependencies": [
+ "jsr:@std/internal@^1.0.12"
+ ]
+ },
+ "@std/async@1.0.15": {
+ "integrity": "55d1d9d04f99403fe5730ab16bdcc3c47f658a6bf054cafb38a50f046238116e"
+ },
"@std/collections@1.1.3": {
"integrity": "bf8b0818886df6a32b64c7d3b037a425111f28278d69fd0995aeb62777c986b0"
},
+ "@std/data-structures@1.0.9": {
+ "integrity": "033d6e17e64bf1f84a614e647c1b015fa2576ae3312305821e1a4cb20674bb4d"
+ },
"@std/fs@1.0.19": {
"integrity": "051968c2b1eae4d2ea9f79a08a3845740ef6af10356aff43d3e2ef11ed09fb06",
"dependencies": [
@@ -47,6 +66,9 @@
"@std/internal@1.0.10": {
"integrity": "e3be62ce42cab0e177c27698e5d9800122f67b766a0bea6ca4867886cbde8cf7"
},
+ "@std/internal@1.0.12": {
+ "integrity": "972a634fd5bc34b242024402972cd5143eac68d8dffaca5eaa4dba30ce17b027"
+ },
"@std/path@1.0.8": {
"integrity": "548fa456bb6a04d3c1a1e7477986b6cffbce95102d0bb447c67c4ee70e0364be"
},
@@ -55,6 +77,17 @@
"dependencies": [
"jsr:@std/internal@^1.0.10"
]
+ },
+ "@std/testing@1.0.16": {
+ "integrity": "a917ffdeb5924c9be436dc78bc32e511760e14d3a96e49c607fc5ecca86d0092",
+ "dependencies": [
+ "jsr:@std/assert@^1.0.15",
+ "jsr:@std/async",
+ "jsr:@std/data-structures",
+ "jsr:@std/fs@^1.0.19",
+ "jsr:@std/internal@^1.0.12",
+ "jsr:@std/path@^1.1.2"
+ ]
}
},
"npm": {
@@ -669,6 +702,7 @@
"dependencies": [
"jsr:@std/assert@^1.0.14",
"jsr:@std/collections@^1.1.3",
+ "jsr:@std/testing@^1.0.14",
"npm:chokidar@4.0.3",
"npm:citty@0.1.6",
"npm:colorjs.io@0.5.2",
diff --git a/example/basic/.cssforge/output.css b/example/basic/.cssforge/output.css
index 25fe6df..17f0d1f 100644
--- a/example/basic/.cssforge/output.css
+++ b/example/basic/.cssforge/output.css
@@ -2,9 +2,29 @@
:root {
/*____ Colors ____*/
/* Palette */
+ /* coral */
--palette-coral-100: oklch(73.511% 0.16799 40.24666);
+ /* mint */
--palette-mint-100: oklch(80.035% 0.18206 151.71104);
+ /* indigo */
--palette-indigo-100: oklch(51.057% 0.23005 276.96564);
+ @media (prefers-color-scheme: dark) {
+ /* coral_dark */
+ --palette-coral_dark-100: oklch(69.622% 0.19552 32.32143);
+ }
+ @media (prefers-color-scheme: dark) {
+ /* mint_dark */
+ --palette-mint_dark-100: oklch(72.275% 0.19201 149.57934);
+ }
+ @media (prefers-color-scheme: dark) {
+ /* indigo_dark */
+ --palette-indigo_dark-100: oklch(45.678% 0.21458 277.0229);
+ }
+ /* Themes */
+ /* Theme: main */
+ /* background */
+ --theme-main-background-primary: var(--palette-coral-100);
+ --theme-main-background-secondary: var(--palette-mint-100);
/*____ Spacing ____*/
--spacing_fluid-base-3xs: clamp(0.0625rem, -0.0417rem + 0.5208vw, 0.375rem);
--spacing_fluid-base-2xs: clamp(0.125rem, -0.0833rem + 1.0417vw, 0.75rem);
@@ -15,18 +35,26 @@
--spacing_fluid-base-xl: clamp(0.75rem, -0.5rem + 6.25vw, 4.5rem);
--spacing_fluid-base-2xl: clamp(1rem, -0.6667rem + 8.3333vw, 6rem);
--spacing_fluid-base-3xl: clamp(1.5rem, -1rem + 12.5vw, 9rem);
+ --spacing_fluid-base-3xs-2xs: clamp(0.0625rem, -0.1667rem + 1.1458vw, 0.75rem);
+ --spacing_fluid-base-2xs-xs: clamp(0.125rem, -0.2083rem + 1.6667vw, 1.125rem);
+ --spacing_fluid-base-xs-s: clamp(0.1875rem, -0.25rem + 2.1875vw, 1.5rem);
+ --spacing_fluid-base-s-m: clamp(0.25rem, -0.4167rem + 3.3333vw, 2.25rem);
+ --spacing_fluid-base-m-l: clamp(0.375rem, -0.5rem + 4.375vw, 3rem);
+ --spacing_fluid-base-l-xl: clamp(0.5rem, -0.8333rem + 6.6667vw, 4.5rem);
+ --spacing_fluid-base-xl-2xl: clamp(0.75rem, -1rem + 8.75vw, 6rem);
+ --spacing_fluid-base-2xl-3xl: clamp(1rem, -1.6667rem + 13.3333vw, 9rem);
--spacing-size-1: 0.25rem;
--spacing-size-2: 0.5rem;
--spacing-size-3: 0.75rem;
--spacing-size-4: 1rem;
/*____ Typography ____*/
- --typography_fluid-font-4xl: clamp(2.6703rem, 2.5608rem + 0.5474vw, 3.0518rem);
- --typography_fluid-font-3xl: clamp(2.1362rem, 2.0486rem + 0.4379vw, 2.4414rem);
- --typography_fluid-font-2xl: clamp(1.709rem, 1.6389rem + 0.3503vw, 1.9531rem);
- --typography_fluid-font-xl: clamp(1.3672rem, 1.3111rem + 0.2803vw, 1.5625rem);
- --typography_fluid-font-lg: clamp(1.0938rem, 1.0489rem + 0.2242vw, 1.25rem);
- --typography_fluid-font-base: clamp(0.875rem, 0.8391rem + 0.1794vw, 1rem);
- --typography_fluid-font-sm: clamp(0.7rem, 0.6713rem + 0.1435vw, 0.8rem);
- --typography_fluid-font-xs: clamp(0.56rem, 0.537rem + 0.1148vw, 0.64rem);
- --typography_fluid-font-2xs: clamp(0.448rem, 0.4296rem + 0.0918vw, 0.512rem);
+ --typography_fluid-base-4xl: clamp(2.6703rem, 2.5608rem + 0.5474vw, 3.0518rem);
+ --typography_fluid-base-3xl: clamp(2.1362rem, 2.0486rem + 0.4379vw, 2.4414rem);
+ --typography_fluid-base-2xl: clamp(1.709rem, 1.6389rem + 0.3503vw, 1.9531rem);
+ --typography_fluid-base-xl: clamp(1.3672rem, 1.3111rem + 0.2803vw, 1.5625rem);
+ --typography_fluid-base-l: clamp(1.0938rem, 1.0489rem + 0.2242vw, 1.25rem);
+ --typography_fluid-base-m: clamp(0.875rem, 0.8391rem + 0.1794vw, 1rem);
+ --typography_fluid-base-s: clamp(0.7rem, 0.6713rem + 0.1435vw, 0.8rem);
+ --typography_fluid-base-xs: clamp(0.56rem, 0.537rem + 0.1148vw, 0.64rem);
+ --typography_fluid-base-2xs: clamp(0.448rem, 0.4296rem + 0.0918vw, 0.512rem);
}
diff --git a/example/basic/cssforge.config.ts b/example/basic/cssforge.config.ts
index f46b7b3..323e5a8 100644
--- a/example/basic/cssforge.config.ts
+++ b/example/basic/cssforge.config.ts
@@ -27,8 +27,8 @@ export default defineConfig(
},
},
typography: {
- font: {
- fluid: {
+ fluid: {
+ base: {
value: {
minWidth: 320,
minFontSize: 14,
@@ -46,13 +46,60 @@ export default defineConfig(
palette: {
value: {
coral: {
- 100: { hex: "#FF7F50" },
+ value: {
+ 100: { hex: "#FF7F50" },
+ },
},
mint: {
- 100: { hex: "#4ADE80" },
+ value: {
+ 100: { hex: "#4ADE80" },
+ },
},
indigo: {
- 100: { hex: "#4F46E5" },
+ value: {
+ 100: { hex: "#4F46E5" },
+ },
+ },
+ // dark-mode overrides wrapped in a condition
+ coral_dark: {
+ value: {
+ 100: { hex: "#FF6347" },
+ },
+ settings: {
+ condition: "@media (prefers-color-scheme: dark)",
+ },
+ },
+ mint_dark: {
+ value: {
+ 100: { hex: "#22C55E" },
+ },
+ settings: {
+ condition: "@media (prefers-color-scheme: dark)",
+ },
+ },
+ indigo_dark: {
+ value: {
+ 100: { hex: "#4338CA" },
+ },
+ settings: {
+ condition: "@media (prefers-color-scheme: dark)",
+ },
+ },
+ },
+ },
+ theme: {
+ main: {
+ value: {
+ background: {
+ value: {
+ primary: "var(--coral)",
+ secondary: "var(--mint)",
+ },
+ variables: {
+ coral: "palette.coral.100",
+ mint: "palette.mint.100",
+ },
+ },
},
},
},
diff --git a/src/config.ts b/src/config.ts
index f0d43a7..2fa2432 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -79,8 +79,6 @@ export interface CSSForgeConfig {
);
* ```
*/
-export function defineConfig>(
- config: C,
-): C {
+export function defineConfig>(config: C): C {
return config as C;
}
diff --git a/src/lib.ts b/src/lib.ts
index bc8e1e5..f3a3208 100644
--- a/src/lib.ts
+++ b/src/lib.ts
@@ -71,7 +71,11 @@ function resolveVariable(
if (!colors) throw new Error("The colors object must be passed.");
const result = colors.resolveMap.get(varPath);
if (!result) {
- throw new Error(`The color path ${varPath} could not be resolved.`);
+ throw new Error(
+ `The color path ${varPath} could not be resolved. Map contains ${
+ Array.from(colors.resolveMap.keys()).map((key) => `\n${key}`)
+ }`,
+ );
}
return result.key;
}
diff --git a/src/modules/colors.ts b/src/modules/colors.ts
index c5dd85b..a9a0567 100644
--- a/src/modules/colors.ts
+++ b/src/modules/colors.ts
@@ -29,11 +29,40 @@ interface ColorVariants {
[key: string]: ColorValueOrString;
}
+export interface WithCondition {
+ /**
+ * CSS condition to wrap variables in (e.g., ".MyClass", "@media (prefers-color-scheme: dark)")
+ */
+ condition?: string;
+}
+/**
+ * Settings for palette colors, including optional conditions like media queries.
+ */
+export interface PaletteColorSettings extends WithCondition {}
+
+/**
+ * Settings for gradients, including optional conditions like media queries.
+ */
+export interface GradientSettings extends WithCondition {}
+
+/**
+ * Settings for themes, including optional conditions like media queries.
+ */
+export interface ThemeSettings extends WithCondition {}
+
+/**
+ * A single palette color configuration with its values and optional settings.
+ */
+export interface PaletteColorConfig {
+ value: ColorVariants;
+ settings?: PaletteColorSettings;
+}
+
/**
* A palette of colors, organized by name and variants.
*/
export interface ColorPalette {
- [key: string]: ColorVariants;
+ [key: string]: PaletteColorConfig;
}
interface GradientDefinition {
@@ -51,7 +80,7 @@ interface GradientValue {
*/
export interface Gradient {
value: GradientValue;
- settings?: unknown;
+ settings?: GradientSettings;
}
/**
@@ -65,12 +94,21 @@ interface ColorInThemeValues {
[key: string]: string;
}
-interface ColorTheme {
- [key: string]: {
- value: ColorInThemeValues;
- variables?: Variables;
- settings?: unknown;
+interface ColorInTheme {
+ value: ColorInThemeValues;
+ variables?: Variables;
+ settings?: unknown;
+}
+
+export interface ThemeConfig {
+ value: {
+ [colorName: string]: ColorInTheme;
};
+ settings?: ThemeSettings;
+}
+
+export interface ColorTheme {
+ [themeName: string]: ThemeConfig;
}
/**
@@ -95,10 +133,7 @@ export interface ColorConfig {
* A collection of themes.
*/
theme?: {
- value: {
- [key: string]: ColorTheme;
- };
- settings?: unknown;
+ [themeName: string]: ThemeConfig;
};
}
@@ -182,35 +217,78 @@ export function processColors(colors: ColorConfig): Output {
const resolveMap: ResolveMap = new Map();
cssOutput.push(`/* Palette */`);
const moduleKey = "palette";
- for (const [colorName, variants] of Object.entries(colors.palette.value)) {
+
+ function conditionalBuilder(
+ settings: WithCondition | undefined,
+ initialComment: string,
+ ) {
+ const comments: string[] = [];
+ const vars: string[] = [];
+
+ if (settings?.condition) {
+ comments.push(initialComment);
+ } else {
+ cssOutput.push(initialComment);
+ }
+
+ return {
+ addComment(c: string) {
+ if (settings?.condition) comments.push(c);
+ else cssOutput.push(c);
+ },
+ pushVariable(v: string) {
+ if (settings?.condition) vars.push(v);
+ else cssOutput.push(v);
+ },
+ finalize() {
+ if (settings?.condition && vars.length > 0) {
+ cssOutput.push(`${settings.condition} {`);
+ cssOutput.push(...comments.map((c) => ` ${c}`));
+ cssOutput.push(...vars.map((v) => ` ${v}`));
+ cssOutput.push(`}`);
+ }
+ },
+ };
+ }
+
+ for (const [colorName, colorConfig] of Object.entries(colors.palette.value)) {
validateName(colorName);
- for (const [variantId, colorValue] of Object.entries(variants)) {
- try {
+
+ try {
+ const handler = conditionalBuilder(
+ colorConfig.settings,
+ `/* ${colorName} */`,
+ );
+
+ for (const [variantId, colorValue] of Object.entries(colorConfig.value)) {
validateName(variantId);
const key = `--${moduleKey}-${colorName}-${variantId}`;
const value = colorValueToOklch(colorValue);
const variable = `${key}: ${value};`;
- cssOutput.push(variable);
+ handler.pushVariable(variable);
+
resolveMap.set(
- `${moduleKey}.value.${colorName}.${variantId}`,
+ `${moduleKey}.${colorName}.${variantId}`,
{ key, value, variable },
);
- } catch (error) {
- console.error(
- `Error processing color ${colorName}-${variantId}:`,
- error,
- );
}
+
+ handler.finalize();
+ } catch (error) {
+ console.error(`Error processing color ${colorName}:`, error);
}
}
if (colors.gradients) {
- cssOutput.push(`/* Gradients */`);
+ cssOutput.push(`/* Gradients */`);
const moduleKey = "gradients";
const palette = { css: cssOutput.join("\n"), resolveMap };
+
for (const [gradientName, gradient] of Object.entries(colors.gradients.value)) {
validateName(gradientName);
+ const handler = conditionalBuilder(gradient.settings, `/* ${gradientName} */`);
+
for (
const [variantName, { value, variables }] of Object.entries(
gradient.value,
@@ -227,8 +305,10 @@ export function processColors(colors: ColorConfig): Output {
const key = `--${moduleKey}-${gradientName}-${variantName}`;
const variable = `${key}: ${gradientValue};`;
- cssOutput.push(variable);
- resolveMap.set(`${moduleKey}.value.${gradientName}.${variantName}`, {
+
+ handler.pushVariable(variable);
+
+ resolveMap.set(`${moduleKey}.${gradientName}.${variantName}`, {
variable,
key,
value: gradientValue,
@@ -241,49 +321,56 @@ export function processColors(colors: ColorConfig): Output {
throw error;
}
}
+
+ handler.finalize();
}
}
if (colors.theme) {
+ cssOutput.push(`/* Themes */`);
const moduleKey = "theme";
- for (const [themeName, theme] of Object.entries(colors.theme.value)) {
+ const palette = { css: cssOutput.join("\n"), resolveMap };
+
+ for (const [themeName, themeConfig] of Object.entries(colors.theme)) {
validateName(themeName);
- cssOutput.push(`/* Theme: ${themeName} */`);
- const palette = { css: cssOutput.join("\n"), resolveMap };
- for (
- const [colorName, { value: colorInThemeValues, variables }] of Object
- .entries(theme)
- ) {
- validateName(colorName);
- cssOutput.push(`/* ${colorName} */`);
- try {
+ const handler = conditionalBuilder(
+ themeConfig.settings,
+ `/* Theme: ${themeName} */`,
+ );
+
+ try {
+ for (const [colorName, colorInTheme] of Object.entries(themeConfig.value)) {
+ validateName(colorName);
+ const colorComment = `/* ${colorName} */`;
+ handler.addComment(colorComment);
+
const resolvedMap = getResolvedVariablesMap({
- variables,
+ variables: colorInTheme.variables,
colors: palette,
});
- for (
- const [variantName, variantValue] of Object.entries(
- colorInThemeValues,
- )
- ) {
+ for (const [variantName, variantValue] of Object.entries(colorInTheme.value)) {
validateName(variantName);
- const resolvedValue = resolveValue({ map: resolvedMap, value: variantValue });
+ const resolvedValue = resolveValue({
+ map: resolvedMap,
+ value: variantValue as string,
+ });
const key = `--${moduleKey}-${themeName}-${colorName}-${variantName}`;
const variable = `${key}: ${resolvedValue};`;
- cssOutput.push(`${key}: ${resolvedValue};`);
+
+ handler.pushVariable(variable);
+
resolveMap.set(
- `${moduleKey}.value.${themeName}.${colorName}.${variantName}`,
+ `${moduleKey}.${themeName}.${colorName}.${variantName}`,
{ key, value: resolvedValue, variable },
);
}
- } catch (error) {
- console.error(
- `Error processing color ${themeName}-${colorName}:`,
- error,
- );
}
+
+ handler.finalize();
+ } catch (error) {
+ console.error(`Error processing theme ${themeName}:`, error);
}
}
}
diff --git a/src/modules/primitive.ts b/src/modules/primitive.ts
index 47ee552..20c766a 100644
--- a/src/modules/primitive.ts
+++ b/src/modules/primitive.ts
@@ -125,7 +125,7 @@ export function processPrimitives(
const variable = `${key}: ${resolvedValue};`;
cssOutput.push(variable);
resolveMap.set(
- `${moduleKey}.${primitiveName}.value.${variantName}.${propName}`,
+ `${moduleKey}.${primitiveName}.${variantName}.${propName}`,
{
key,
value: resolvedValue,
diff --git a/src/modules/spacing.ts b/src/modules/spacing.ts
index 95466b6..3bbf018 100644
--- a/src/modules/spacing.ts
+++ b/src/modules/spacing.ts
@@ -115,7 +115,7 @@ export function processSpacing(spacing: SpacingConfig): Output {
const varName = `--${moduleKey}-${scaleName}-${scaleKey}`;
const variable = `${varName}: ${convertedValue};`;
cssOutput.push(variable);
- resolveMap.set(`${moduleKey}.custom.${scaleName}.value.${scaleKey}`, {
+ resolveMap.set(`${moduleKey}.custom.${scaleName}.${scaleKey}`, {
variable,
key: varName,
value: convertedValue,
diff --git a/src/modules/typography.ts b/src/modules/typography.ts
index ad2c475..a5a4da3 100644
--- a/src/modules/typography.ts
+++ b/src/modules/typography.ts
@@ -110,7 +110,7 @@ export function processTypography(config: TypographyConfig): Output {
const key = `--${moduleKey}-weight-${weightName}-${token}`;
const variable = `${key}: ${weightValue};`;
cssOutput.push(variable);
- resolveMap.set(`${moduleKey}.weight.${weightName}.value.${token}`, {
+ resolveMap.set(`${moduleKey}.weight.${weightName}.${token}`, {
variable,
key,
value: weightValue,
diff --git a/tests/__snapshots__/colors.test.ts.snap b/tests/__snapshots__/colors.test.ts.snap
new file mode 100644
index 0000000..b800da7
--- /dev/null
+++ b/tests/__snapshots__/colors.test.ts.snap
@@ -0,0 +1,376 @@
+export const snapshot = {};
+
+snapshot[`processColors - converts hex to oklch 1`] = `
+"/* Palette */
+/* coral */
+--palette-coral-100: oklch(73.511% 0.16799 40.24666);
+--palette-coral-200: oklch(69.622% 0.19552 32.32143);"
+`;
+
+snapshot[`processColors - converts hex to oklch 2`] = `
+[
+ [
+ "palette.coral.100",
+ {
+ key: "--palette-coral-100",
+ value: "oklch(73.511% 0.16799 40.24666)",
+ variable: "--palette-coral-100: oklch(73.511% 0.16799 40.24666);",
+ },
+ ],
+ [
+ "palette.coral.200",
+ {
+ key: "--palette-coral-200",
+ value: "oklch(69.622% 0.19552 32.32143)",
+ variable: "--palette-coral-200: oklch(69.622% 0.19552 32.32143);",
+ },
+ ],
+]
+`;
+
+snapshot[`processColors - handles different color formats 1`] = `
+"/* Palette */
+/* brand */
+--palette-brand-200: oklch(86.644% 0.29483 142.49535);
+--palette-brand-300: oklch(45.201% 0.31321 264.05202);
+--palette-brand-400: oklch(70% 0.2 270);
+--palette-brand-default: oklch(62.796% 0.25768 29.23388);"
+`;
+
+snapshot[`processColors - handles different color formats 2`] = `
+[
+ [
+ "palette.brand.200",
+ {
+ key: "--palette-brand-200",
+ value: "oklch(86.644% 0.29483 142.49535)",
+ variable: "--palette-brand-200: oklch(86.644% 0.29483 142.49535);",
+ },
+ ],
+ [
+ "palette.brand.300",
+ {
+ key: "--palette-brand-300",
+ value: "oklch(45.201% 0.31321 264.05202)",
+ variable: "--palette-brand-300: oklch(45.201% 0.31321 264.05202);",
+ },
+ ],
+ [
+ "palette.brand.400",
+ {
+ key: "--palette-brand-400",
+ value: "oklch(70% 0.2 270)",
+ variable: "--palette-brand-400: oklch(70% 0.2 270);",
+ },
+ ],
+ [
+ "palette.brand.default",
+ {
+ key: "--palette-brand-default",
+ value: "oklch(62.796% 0.25768 29.23388)",
+ variable: "--palette-brand-default: oklch(62.796% 0.25768 29.23388);",
+ },
+ ],
+]
+`;
+
+snapshot[`processColors - handles string values 1`] = `
+"/* Palette */
+/* simple */
+--palette-simple-white: oklch(100% 0 0);
+--palette-simple-black: oklch(0% 0 0);"
+`;
+
+snapshot[`processColors - handles string values 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);",
+ },
+ ],
+]
+`;
+
+snapshot[`processColors - handles themes 1`] = `
+"/* Palette */
+/* simple */
+--palette-simple-white: oklch(100% 0 0);
+--palette-simple-black: oklch(0% 0 0);
+/* Themes */
+/* Theme: light */
+/* background */
+--theme-light-background-primary: var(--palette-simple-white);
+--theme-light-background-secondary: var(--palette-simple-black);"
+`;
+
+snapshot[`processColors - handles themes 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: "--theme-light-background-primary",
+ value: "var(--palette-simple-white)",
+ variable: "--theme-light-background-primary: var(--palette-simple-white);",
+ },
+ ],
+ [
+ "theme.light.background.secondary",
+ {
+ key: "--theme-light-background-secondary",
+ value: "var(--palette-simple-black)",
+ variable: "--theme-light-background-secondary: var(--palette-simple-black);",
+ },
+ ],
+]
+`;
+
+snapshot[`processColors - handles transparency 1`] = `
+"/* Palette */
+/* alpha */
+--palette-alpha-softGray1: oklch(14.48% 0 0 / 12%);
+--palette-alpha-softGray2: oklch(14.48% 0 0 / 24%);"
+`;
+
+snapshot[`processColors - handles transparency 2`] = `
+[
+ [
+ "palette.alpha.softGray1",
+ {
+ key: "--palette-alpha-softGray1",
+ value: "oklch(14.48% 0 0 / 12%)",
+ variable: "--palette-alpha-softGray1: oklch(14.48% 0 0 / 12%);",
+ },
+ ],
+ [
+ "palette.alpha.softGray2",
+ {
+ key: "--palette-alpha-softGray2",
+ value: "oklch(14.48% 0 0 / 24%)",
+ variable: "--palette-alpha-softGray2: oklch(14.48% 0 0 / 24%);",
+ },
+ ],
+]
+`;
+
+snapshot[`processColors - generates gradient with color variables 1`] = `
+"/* Palette */
+/* coral */
+--palette-coral-50: oklch(73.58% 0.16378 34.33822);
+--palette-coral-90: oklch(73.341% 0.17338 44.64289);
+--palette-coral-100: oklch(69.622% 0.19552 32.32143);
+/* indigo */
+--palette-indigo-100: oklch(51.057% 0.23005 276.96564);
+/* Gradients */
+/* orangeGradient */
+--gradients-orangeGradient-primary: linear-gradient(261.78deg, var(--palette-coral-50) 33.1%, var(--palette-coral-90) 56.3%, var(--palette-coral-100) 65.78%, var(--palette-indigo-100) 84.23%);"
+`;
+
+snapshot[`processColors - generates gradient with color variables 2`] = `
+[
+ [
+ "palette.coral.50",
+ {
+ key: "--palette-coral-50",
+ value: "oklch(73.58% 0.16378 34.33822)",
+ variable: "--palette-coral-50: oklch(73.58% 0.16378 34.33822);",
+ },
+ ],
+ [
+ "palette.coral.90",
+ {
+ key: "--palette-coral-90",
+ value: "oklch(73.341% 0.17338 44.64289)",
+ variable: "--palette-coral-90: oklch(73.341% 0.17338 44.64289);",
+ },
+ ],
+ [
+ "palette.coral.100",
+ {
+ key: "--palette-coral-100",
+ value: "oklch(69.622% 0.19552 32.32143)",
+ variable: "--palette-coral-100: oklch(69.622% 0.19552 32.32143);",
+ },
+ ],
+ [
+ "palette.indigo.100",
+ {
+ key: "--palette-indigo-100",
+ value: "oklch(51.057% 0.23005 276.96564)",
+ variable: "--palette-indigo-100: oklch(51.057% 0.23005 276.96564);",
+ },
+ ],
+ [
+ "gradients.orangeGradient.primary",
+ {
+ key: "--gradients-orangeGradient-primary",
+ value: "linear-gradient(261.78deg, var(--palette-coral-50) 33.1%, var(--palette-coral-90) 56.3%, var(--palette-coral-100) 65.78%, var(--palette-indigo-100) 84.23%)",
+ variable: "--gradients-orangeGradient-primary: linear-gradient(261.78deg, var(--palette-coral-50) 33.1%, var(--palette-coral-90) 56.3%, var(--palette-coral-100) 65.78%, var(--palette-indigo-100) 84.23%);",
+ },
+ ],
+]
+`;
+
+snapshot[`processColors - handles themes referencing gradients 1`] = `
+"/* Palette */
+/* coral */
+--palette-coral-50: oklch(73.58% 0.16378 34.33822);
+/* Gradients */
+/* orangeGradient */
+--gradients-orangeGradient-primary: linear-gradient(to right, var(--palette-coral-50), var(--palette-coral-50));
+/* Themes */
+/* Theme: light */
+/* background */
+--theme-light-background-primary: var(--gradients-orangeGradient-primary);"
+`;
+
+snapshot[`processColors - handles themes referencing gradients 2`] = `
+[
+ [
+ "palette.coral.50",
+ {
+ key: "--palette-coral-50",
+ value: "oklch(73.58% 0.16378 34.33822)",
+ variable: "--palette-coral-50: oklch(73.58% 0.16378 34.33822);",
+ },
+ ],
+ [
+ "gradients.orangeGradient.primary",
+ {
+ key: "--gradients-orangeGradient-primary",
+ value: "linear-gradient(to right, var(--palette-coral-50), var(--palette-coral-50))",
+ variable: "--gradients-orangeGradient-primary: linear-gradient(to right, var(--palette-coral-50), var(--palette-coral-50));",
+ },
+ ],
+ [
+ "theme.light.background.primary",
+ {
+ key: "--theme-light-background-primary",
+ value: "var(--gradients-orangeGradient-primary)",
+ variable: "--theme-light-background-primary: var(--gradients-orangeGradient-primary);",
+ },
+ ],
+]
+`;
+
+snapshot[`processColors - handles gradients with conditions 1`] = `
+"/* Palette */
+/* coral */
+--palette-coral-50: oklch(73.58% 0.16378 34.33822);
+/* Gradients */
+@media (prefers-color-scheme: dark) {
+ /* orangeGradient */
+ --gradients-orangeGradient-primary: linear-gradient(to right, var(--palette-coral-50), var(--palette-coral-50));
+}"
+`;
+
+snapshot[`processColors - handles gradients with conditions 2`] = `
+[
+ [
+ "palette.coral.50",
+ {
+ key: "--palette-coral-50",
+ value: "oklch(73.58% 0.16378 34.33822)",
+ variable: "--palette-coral-50: oklch(73.58% 0.16378 34.33822);",
+ },
+ ],
+ [
+ "gradients.orangeGradient.primary",
+ {
+ key: "--gradients-orangeGradient-primary",
+ value: "linear-gradient(to right, var(--palette-coral-50), var(--palette-coral-50))",
+ variable: "--gradients-orangeGradient-primary: linear-gradient(to right, var(--palette-coral-50), var(--palette-coral-50));",
+ },
+ ],
+]
+`;
+
+snapshot[`processColors - handles palette colors with conditions 1`] = `
+"/* Palette */
+/* background */
+--palette-background-light: oklch(100% 0 0);
+@media (prefers-color-scheme: dark) {
+ /* backgroundDark */
+ --palette-backgroundDark-dark: oklch(0% 0 0);
+}"
+`;
+
+snapshot[`processColors - handles palette colors with conditions 2`] = `
+[
+ [
+ "palette.background.light",
+ {
+ key: "--palette-background-light",
+ value: "oklch(100% 0 0)",
+ variable: "--palette-background-light: oklch(100% 0 0);",
+ },
+ ],
+ [
+ "palette.backgroundDark.dark",
+ {
+ key: "--palette-backgroundDark-dark",
+ value: "oklch(0% 0 0)",
+ variable: "--palette-backgroundDark-dark: oklch(0% 0 0);",
+ },
+ ],
+]
+`;
+
+snapshot[`processColors - handles themes with class condition 1`] = `
+"/* Palette */
+/* base */
+--palette-base-primary: oklch(73.511% 0.16799 40.24666);
+/* Themes */
+.dark-theme {
+ /* Theme: dark */
+ /* background */
+ --theme-dark-background-primary: var(--palette-base-primary);
+}"
+`;
+
+snapshot[`processColors - handles themes with class condition 2`] = `
+[
+ [
+ "palette.base.primary",
+ {
+ key: "--palette-base-primary",
+ value: "oklch(73.511% 0.16799 40.24666)",
+ variable: "--palette-base-primary: oklch(73.511% 0.16799 40.24666);",
+ },
+ ],
+ [
+ "theme.dark.background.primary",
+ {
+ key: "--theme-dark-background-primary",
+ value: "var(--palette-base-primary)",
+ variable: "--theme-dark-background-primary: var(--palette-base-primary);",
+ },
+ ],
+]
+`;
diff --git a/tests/__snapshots__/primitive.test.ts.snap b/tests/__snapshots__/primitive.test.ts.snap
new file mode 100644
index 0000000..9b7d113
--- /dev/null
+++ b/tests/__snapshots__/primitive.test.ts.snap
@@ -0,0 +1,172 @@
+export const snapshot = {};
+
+snapshot[`processPrimitives - processes button with variables 1`] = `
+"/* button */
+--button-small-width: 120px;
+--button-small-height: 40px;
+--button-small-fontSize: var(--typography_fluid-arial-foo-m);
+--button-small-radius: 8px;
+--button-small-padding: var(--spacing-size-2) var(--spacing-size-3);"
+`;
+
+snapshot[`processPrimitives - processes button with variables 2`] = `
+[
+ [
+ "primitives.button.small.width",
+ {
+ key: "--button-small-width",
+ value: "120px",
+ variable: "--button-small-width: 120px;",
+ },
+ ],
+ [
+ "primitives.button.small.height",
+ {
+ key: "--button-small-height",
+ value: "40px",
+ variable: "--button-small-height: 40px;",
+ },
+ ],
+ [
+ "primitives.button.small.fontSize",
+ {
+ key: "--button-small-fontSize",
+ value: "var(--typography_fluid-arial-foo-m)",
+ variable: "--button-small-fontSize: var(--typography_fluid-arial-foo-m);",
+ },
+ ],
+ [
+ "primitives.button.small.radius",
+ {
+ key: "--button-small-radius",
+ value: "8px",
+ variable: "--button-small-radius: 8px;",
+ },
+ ],
+ [
+ "primitives.button.small.padding",
+ {
+ key: "--button-small-padding",
+ value: "var(--spacing-size-2) var(--spacing-size-3)",
+ variable: "--button-small-padding: var(--spacing-size-2) var(--spacing-size-3);",
+ },
+ ],
+]
+`;
+
+snapshot[`processPrimitives - processes buttons with settings 1`] = `
+"/* button */
+--button-small-width: 120px;
+--button-small-height: 40px;
+--button-small-radius: 8px;
+--button-big-width: 15rem;
+--button-big-height: 5rem;
+--button-big-radius: 1rem;"
+`;
+
+snapshot[`processPrimitives - processes buttons with settings 2`] = `
+[
+ [
+ "primitives.button.small.width",
+ {
+ key: "--button-small-width",
+ value: "120px",
+ variable: "--button-small-width: 120px;",
+ },
+ ],
+ [
+ "primitives.button.small.height",
+ {
+ key: "--button-small-height",
+ value: "40px",
+ variable: "--button-small-height: 40px;",
+ },
+ ],
+ [
+ "primitives.button.small.radius",
+ {
+ key: "--button-small-radius",
+ value: "8px",
+ variable: "--button-small-radius: 8px;",
+ },
+ ],
+ [
+ "primitives.button.big.width",
+ {
+ key: "--button-big-width",
+ value: "15rem",
+ variable: "--button-big-width: 15rem;",
+ },
+ ],
+ [
+ "primitives.button.big.height",
+ {
+ key: "--button-big-height",
+ value: "5rem",
+ variable: "--button-big-height: 5rem;",
+ },
+ ],
+ [
+ "primitives.button.big.radius",
+ {
+ key: "--button-big-radius",
+ value: "1rem",
+ variable: "--button-big-radius: 1rem;",
+ },
+ ],
+]
+`;
+
+snapshot[`processPrimitives - references colors, gradients, and themes 1`] = `
+"/* card */
+--card-default-background-color: var(--theme-light-background-primary);
+--card-default-background-image: var(--gradients-orangeGradient-primary);
+--card-default-border-color: var(--palette-coral-50);"
+`;
+
+snapshot[`processPrimitives - references colors, gradients, and themes 2`] = `
+[
+ [
+ "primitives.card.default.background-color",
+ {
+ key: "--card-default-background-color",
+ value: "var(--theme-light-background-primary)",
+ variable: "--card-default-background-color: var(--theme-light-background-primary);",
+ },
+ ],
+ [
+ "primitives.card.default.background-image",
+ {
+ key: "--card-default-background-image",
+ value: "var(--gradients-orangeGradient-primary)",
+ variable: "--card-default-background-image: var(--gradients-orangeGradient-primary);",
+ },
+ ],
+ [
+ "primitives.card.default.border-color",
+ {
+ key: "--card-default-border-color",
+ value: "var(--palette-coral-50)",
+ variable: "--card-default-border-color: var(--palette-coral-50);",
+ },
+ ],
+]
+`;
+
+snapshot[`processPrimitives - uses fluid spacing references 1`] = `
+"/* box */
+--box-default-padding: var(--spacing_fluid-gap-gs-s) var(--spacing_fluid-gap-gs-m);"
+`;
+
+snapshot[`processPrimitives - uses fluid spacing references 2`] = `
+[
+ [
+ "primitives.box.default.padding",
+ {
+ key: "--box-default-padding",
+ value: "var(--spacing_fluid-gap-gs-s) var(--spacing_fluid-gap-gs-m)",
+ variable: "--box-default-padding: var(--spacing_fluid-gap-gs-s) var(--spacing_fluid-gap-gs-m);",
+ },
+ ],
+]
+`;
diff --git a/tests/__snapshots__/spacing.test.ts.snap b/tests/__snapshots__/spacing.test.ts.snap
new file mode 100644
index 0000000..5426fd0
--- /dev/null
+++ b/tests/__snapshots__/spacing.test.ts.snap
@@ -0,0 +1,293 @@
+export const snapshot = {};
+
+snapshot[`processSpacing - generates correct spacing scale 1`] = `
+"--spacing-size-1: 0.25rem;
+--spacing-size-2: 0.5rem;
+--spacing-size-3: 0.75rem;
+--spacing-size-s: 1rem;"
+`;
+
+snapshot[`processSpacing - generates correct spacing scale 2`] = `
+[
+ [
+ "spacing.custom.size.1",
+ {
+ key: "--spacing-size-1",
+ value: "0.25rem",
+ variable: "--spacing-size-1: 0.25rem;",
+ },
+ ],
+ [
+ "spacing.custom.size.2",
+ {
+ key: "--spacing-size-2",
+ value: "0.5rem",
+ variable: "--spacing-size-2: 0.5rem;",
+ },
+ ],
+ [
+ "spacing.custom.size.3",
+ {
+ key: "--spacing-size-3",
+ value: "0.75rem",
+ variable: "--spacing-size-3: 0.75rem;",
+ },
+ ],
+ [
+ "spacing.custom.size.s",
+ {
+ key: "--spacing-size-s",
+ value: "1rem",
+ variable: "--spacing-size-s: 1rem;",
+ },
+ ],
+]
+`;
+
+snapshot[`processSpacing - handles settings 1`] = `
+"--spacing-size-1: 1rem;
+--spacing-size-2: 0.5rem;
+--spacing-scale-md: 8px;
+--spacing-scale-lg: 0.75rem;"
+`;
+
+snapshot[`processSpacing - handles settings 2`] = `
+[
+ [
+ "spacing.custom.size.1",
+ {
+ key: "--spacing-size-1",
+ value: "1rem",
+ variable: "--spacing-size-1: 1rem;",
+ },
+ ],
+ [
+ "spacing.custom.size.2",
+ {
+ key: "--spacing-size-2",
+ value: "0.5rem",
+ variable: "--spacing-size-2: 0.5rem;",
+ },
+ ],
+ [
+ "spacing.custom.scale.md",
+ {
+ key: "--spacing-scale-md",
+ value: "8px",
+ variable: "--spacing-scale-md: 8px;",
+ },
+ ],
+ [
+ "spacing.custom.scale.lg",
+ {
+ key: "--spacing-scale-lg",
+ value: "0.75rem",
+ variable: "--spacing-scale-lg: 0.75rem;",
+ },
+ ],
+]
+`;
+
+snapshot[`processSpacing - generates fluid spacing (prefix) 1`] = `
+"--spacing_fluid-base-foo-xs: clamp(0rem, 0rem + 0vw, 0rem);
+--spacing_fluid-base-foo-s: clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem);
+--spacing_fluid-base-foo-m: clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem);
+--spacing_fluid-base-foo-l: clamp(0.5rem, -0.3333rem + 4.1667vw, 3rem);
+--spacing_fluid-base-foo-xs-l: clamp(0rem, -1rem + 5vw, 3rem);
+--spacing_fluid-base-foo-xs-s: clamp(0rem, -0.5rem + 2.5vw, 1.5rem);
+--spacing_fluid-base-foo-s-m: clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem);
+--spacing_fluid-base-foo-m-l: clamp(0.25rem, -0.6667rem + 4.5833vw, 3rem);"
+`;
+
+snapshot[`processSpacing - generates fluid spacing (prefix) 2`] = `
+[
+ [
+ "spacing_fluid.base@xs",
+ {
+ key: "--spacing_fluid-base-foo-xs",
+ value: "clamp(0rem, 0rem + 0vw, 0rem)",
+ variable: "--spacing_fluid-base-foo-xs: clamp(0rem, 0rem + 0vw, 0rem);",
+ },
+ ],
+ [
+ "spacing_fluid.base@s",
+ {
+ key: "--spacing_fluid-base-foo-s",
+ value: "clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem)",
+ variable: "--spacing_fluid-base-foo-s: clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem);",
+ },
+ ],
+ [
+ "spacing_fluid.base@m",
+ {
+ key: "--spacing_fluid-base-foo-m",
+ value: "clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem)",
+ variable: "--spacing_fluid-base-foo-m: clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem);",
+ },
+ ],
+ [
+ "spacing_fluid.base@l",
+ {
+ key: "--spacing_fluid-base-foo-l",
+ value: "clamp(0.5rem, -0.3333rem + 4.1667vw, 3rem)",
+ variable: "--spacing_fluid-base-foo-l: clamp(0.5rem, -0.3333rem + 4.1667vw, 3rem);",
+ },
+ ],
+ [
+ "spacing_fluid.base@xs-l",
+ {
+ key: "--spacing_fluid-base-foo-xs-l",
+ value: "clamp(0rem, -1rem + 5vw, 3rem)",
+ variable: "--spacing_fluid-base-foo-xs-l: clamp(0rem, -1rem + 5vw, 3rem);",
+ },
+ ],
+ [
+ "spacing_fluid.base@xs-s",
+ {
+ key: "--spacing_fluid-base-foo-xs-s",
+ value: "clamp(0rem, -0.5rem + 2.5vw, 1.5rem)",
+ variable: "--spacing_fluid-base-foo-xs-s: clamp(0rem, -0.5rem + 2.5vw, 1.5rem);",
+ },
+ ],
+ [
+ "spacing_fluid.base@s-m",
+ {
+ key: "--spacing_fluid-base-foo-s-m",
+ value: "clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem)",
+ variable: "--spacing_fluid-base-foo-s-m: clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem);",
+ },
+ ],
+ [
+ "spacing_fluid.base@m-l",
+ {
+ key: "--spacing_fluid-base-foo-m-l",
+ value: "clamp(0.25rem, -0.6667rem + 4.5833vw, 3rem)",
+ variable: "--spacing_fluid-base-foo-m-l: clamp(0.25rem, -0.6667rem + 4.5833vw, 3rem);",
+ },
+ ],
+]
+`;
+
+snapshot[`processSpacing - fluid without prefix falls back to scale name 1`] = `
+"--spacing_fluid-rhythm-xs: clamp(0rem, 0rem + 0vw, 0rem);
+--spacing_fluid-rhythm-s: clamp(0.125rem, -0.25rem + 1.875vw, 1.25rem);
+--spacing_fluid-rhythm-m: clamp(0.125rem, -0.25rem + 1.875vw, 1.25rem);
+--spacing_fluid-rhythm-xs-s: clamp(0rem, -0.4167rem + 2.0833vw, 1.25rem);
+--spacing_fluid-rhythm-s-m: clamp(0.125rem, -0.25rem + 1.875vw, 1.25rem);"
+`;
+
+snapshot[`processSpacing - fluid without prefix falls back to scale name 2`] = `
+[
+ [
+ "spacing_fluid.rhythm@xs",
+ {
+ key: "--spacing_fluid-rhythm-xs",
+ value: "clamp(0rem, 0rem + 0vw, 0rem)",
+ variable: "--spacing_fluid-rhythm-xs: clamp(0rem, 0rem + 0vw, 0rem);",
+ },
+ ],
+ [
+ "spacing_fluid.rhythm@s",
+ {
+ key: "--spacing_fluid-rhythm-s",
+ value: "clamp(0.125rem, -0.25rem + 1.875vw, 1.25rem)",
+ variable: "--spacing_fluid-rhythm-s: clamp(0.125rem, -0.25rem + 1.875vw, 1.25rem);",
+ },
+ ],
+ [
+ "spacing_fluid.rhythm@m",
+ {
+ key: "--spacing_fluid-rhythm-m",
+ value: "clamp(0.125rem, -0.25rem + 1.875vw, 1.25rem)",
+ variable: "--spacing_fluid-rhythm-m: clamp(0.125rem, -0.25rem + 1.875vw, 1.25rem);",
+ },
+ ],
+ [
+ "spacing_fluid.rhythm@xs-s",
+ {
+ key: "--spacing_fluid-rhythm-xs-s",
+ value: "clamp(0rem, -0.4167rem + 2.0833vw, 1.25rem)",
+ variable: "--spacing_fluid-rhythm-xs-s: clamp(0rem, -0.4167rem + 2.0833vw, 1.25rem);",
+ },
+ ],
+ [
+ "spacing_fluid.rhythm@s-m",
+ {
+ key: "--spacing_fluid-rhythm-s-m",
+ value: "clamp(0.125rem, -0.25rem + 1.875vw, 1.25rem)",
+ variable: "--spacing_fluid-rhythm-s-m: clamp(0.125rem, -0.25rem + 1.875vw, 1.25rem);",
+ },
+ ],
+]
+`;
+
+snapshot[`processSpacing - combines fluid and custom spacing 1`] = `
+"--spacing_fluid-base-flux-xs: clamp(0rem, 0rem + 0vw, 0rem);
+--spacing_fluid-base-flux-s: clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem);
+--spacing_fluid-base-flux-m: clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem);
+--spacing_fluid-base-flux-xs-s: clamp(0rem, -0.5rem + 2.5vw, 1.5rem);
+--spacing_fluid-base-flux-s-m: clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem);
+--spacing-gap-1: 4px;
+--spacing-gap-2: 8px;"
+`;
+
+snapshot[`processSpacing - combines fluid and custom spacing 2`] = `
+[
+ [
+ "spacing_fluid.base@xs",
+ {
+ key: "--spacing_fluid-base-flux-xs",
+ value: "clamp(0rem, 0rem + 0vw, 0rem)",
+ variable: "--spacing_fluid-base-flux-xs: clamp(0rem, 0rem + 0vw, 0rem);",
+ },
+ ],
+ [
+ "spacing_fluid.base@s",
+ {
+ key: "--spacing_fluid-base-flux-s",
+ value: "clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem)",
+ variable: "--spacing_fluid-base-flux-s: clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem);",
+ },
+ ],
+ [
+ "spacing_fluid.base@m",
+ {
+ key: "--spacing_fluid-base-flux-m",
+ value: "clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem)",
+ variable: "--spacing_fluid-base-flux-m: clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem);",
+ },
+ ],
+ [
+ "spacing_fluid.base@xs-s",
+ {
+ key: "--spacing_fluid-base-flux-xs-s",
+ value: "clamp(0rem, -0.5rem + 2.5vw, 1.5rem)",
+ variable: "--spacing_fluid-base-flux-xs-s: clamp(0rem, -0.5rem + 2.5vw, 1.5rem);",
+ },
+ ],
+ [
+ "spacing_fluid.base@s-m",
+ {
+ key: "--spacing_fluid-base-flux-s-m",
+ value: "clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem)",
+ variable: "--spacing_fluid-base-flux-s-m: clamp(0.25rem, -0.1667rem + 2.0833vw, 1.5rem);",
+ },
+ ],
+ [
+ "spacing.custom.gap.1",
+ {
+ key: "--spacing-gap-1",
+ value: "4px",
+ variable: "--spacing-gap-1: 4px;",
+ },
+ ],
+ [
+ "spacing.custom.gap.2",
+ {
+ key: "--spacing-gap-2",
+ value: "8px",
+ variable: "--spacing-gap-2: 8px;",
+ },
+ ],
+]
+`;
diff --git a/tests/__snapshots__/typography.test.ts.snap b/tests/__snapshots__/typography.test.ts.snap
new file mode 100644
index 0000000..0ce6ae6
--- /dev/null
+++ b/tests/__snapshots__/typography.test.ts.snap
@@ -0,0 +1,268 @@
+export const snapshot = {};
+
+snapshot[`processTypography - generates correct CSS variables 1`] = `
+"--typography_fluid-arial-4xl: clamp(2.6703rem, 2.5608rem + 0.5474vw, 3.0518rem);
+--typography_fluid-arial-3xl: clamp(2.1362rem, 2.0486rem + 0.4379vw, 2.4414rem);
+--typography_fluid-arial-2xl: clamp(1.709rem, 1.6389rem + 0.3503vw, 1.9531rem);
+--typography_fluid-arial-xl: clamp(1.3672rem, 1.3111rem + 0.2803vw, 1.5625rem);
+--typography_fluid-arial-l: clamp(1.0938rem, 1.0489rem + 0.2242vw, 1.25rem);
+--typography_fluid-arial-m: clamp(0.875rem, 0.8391rem + 0.1794vw, 1rem);
+--typography_fluid-arial-s: clamp(0.7rem, 0.6713rem + 0.1435vw, 0.8rem);
+--typography_fluid-arial-xs: clamp(0.56rem, 0.537rem + 0.1148vw, 0.64rem);
+--typography_fluid-arial-2xs: clamp(0.448rem, 0.4296rem + 0.0918vw, 0.512rem);"
+`;
+
+snapshot[`processTypography - generates correct CSS variables 2`] = `
+[
+ [
+ "typography_fluid.arial@4xl",
+ {
+ key: "--typography_fluid-arial-4xl",
+ value: "clamp(2.6703rem, 2.5608rem + 0.5474vw, 3.0518rem)",
+ variable: "--typography_fluid-arial-4xl: clamp(2.6703rem, 2.5608rem + 0.5474vw, 3.0518rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@3xl",
+ {
+ key: "--typography_fluid-arial-3xl",
+ value: "clamp(2.1362rem, 2.0486rem + 0.4379vw, 2.4414rem)",
+ variable: "--typography_fluid-arial-3xl: clamp(2.1362rem, 2.0486rem + 0.4379vw, 2.4414rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@2xl",
+ {
+ key: "--typography_fluid-arial-2xl",
+ value: "clamp(1.709rem, 1.6389rem + 0.3503vw, 1.9531rem)",
+ variable: "--typography_fluid-arial-2xl: clamp(1.709rem, 1.6389rem + 0.3503vw, 1.9531rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@xl",
+ {
+ key: "--typography_fluid-arial-xl",
+ value: "clamp(1.3672rem, 1.3111rem + 0.2803vw, 1.5625rem)",
+ variable: "--typography_fluid-arial-xl: clamp(1.3672rem, 1.3111rem + 0.2803vw, 1.5625rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@l",
+ {
+ key: "--typography_fluid-arial-l",
+ value: "clamp(1.0938rem, 1.0489rem + 0.2242vw, 1.25rem)",
+ variable: "--typography_fluid-arial-l: clamp(1.0938rem, 1.0489rem + 0.2242vw, 1.25rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@m",
+ {
+ key: "--typography_fluid-arial-m",
+ value: "clamp(0.875rem, 0.8391rem + 0.1794vw, 1rem)",
+ variable: "--typography_fluid-arial-m: clamp(0.875rem, 0.8391rem + 0.1794vw, 1rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@s",
+ {
+ key: "--typography_fluid-arial-s",
+ value: "clamp(0.7rem, 0.6713rem + 0.1435vw, 0.8rem)",
+ variable: "--typography_fluid-arial-s: clamp(0.7rem, 0.6713rem + 0.1435vw, 0.8rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@xs",
+ {
+ key: "--typography_fluid-arial-xs",
+ value: "clamp(0.56rem, 0.537rem + 0.1148vw, 0.64rem)",
+ variable: "--typography_fluid-arial-xs: clamp(0.56rem, 0.537rem + 0.1148vw, 0.64rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@2xs",
+ {
+ key: "--typography_fluid-arial-2xs",
+ value: "clamp(0.448rem, 0.4296rem + 0.0918vw, 0.512rem)",
+ variable: "--typography_fluid-arial-2xs: clamp(0.448rem, 0.4296rem + 0.0918vw, 0.512rem);",
+ },
+ ],
+]
+`;
+
+snapshot[`typography - can handle custom labels and prefixes 1`] = `
+"--typography_fluid-arial-text-h1: clamp(4.1723rem, 4.0013rem + 0.8553vw, 4.7684rem);
+--typography_fluid-arial-text-h2: clamp(3.3379rem, 3.201rem + 0.6843vw, 3.8147rem);
+--typography_fluid-arial-text-h3: clamp(2.6703rem, 2.5608rem + 0.5474vw, 3.0518rem);
+--typography_fluid-arial-text-h4: clamp(2.1362rem, 2.0486rem + 0.4379vw, 2.4414rem);
+--typography_fluid-arial-text-xxl: clamp(1.709rem, 1.6389rem + 0.3503vw, 1.9531rem);
+--typography_fluid-arial-text-xl: clamp(1.3672rem, 1.3111rem + 0.2803vw, 1.5625rem);
+--typography_fluid-arial-text-l: clamp(1.0938rem, 1.0489rem + 0.2242vw, 1.25rem);
+--typography_fluid-arial-text-m: clamp(0.875rem, 0.8391rem + 0.1794vw, 1rem);
+--typography_fluid-arial-text-s: clamp(0.7rem, 0.6713rem + 0.1435vw, 0.8rem);
+--typography_fluid-arial-text-xs: clamp(0.56rem, 0.537rem + 0.1148vw, 0.64rem);"
+`;
+
+snapshot[`typography - can handle custom labels and prefixes 2`] = `
+[
+ [
+ "typography_fluid.arial@h1",
+ {
+ key: "--typography_fluid-arial-text-h1",
+ value: "clamp(4.1723rem, 4.0013rem + 0.8553vw, 4.7684rem)",
+ variable: "--typography_fluid-arial-text-h1: clamp(4.1723rem, 4.0013rem + 0.8553vw, 4.7684rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@h2",
+ {
+ key: "--typography_fluid-arial-text-h2",
+ value: "clamp(3.3379rem, 3.201rem + 0.6843vw, 3.8147rem)",
+ variable: "--typography_fluid-arial-text-h2: clamp(3.3379rem, 3.201rem + 0.6843vw, 3.8147rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@h3",
+ {
+ key: "--typography_fluid-arial-text-h3",
+ value: "clamp(2.6703rem, 2.5608rem + 0.5474vw, 3.0518rem)",
+ variable: "--typography_fluid-arial-text-h3: clamp(2.6703rem, 2.5608rem + 0.5474vw, 3.0518rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@h4",
+ {
+ key: "--typography_fluid-arial-text-h4",
+ value: "clamp(2.1362rem, 2.0486rem + 0.4379vw, 2.4414rem)",
+ variable: "--typography_fluid-arial-text-h4: clamp(2.1362rem, 2.0486rem + 0.4379vw, 2.4414rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@xxl",
+ {
+ key: "--typography_fluid-arial-text-xxl",
+ value: "clamp(1.709rem, 1.6389rem + 0.3503vw, 1.9531rem)",
+ variable: "--typography_fluid-arial-text-xxl: clamp(1.709rem, 1.6389rem + 0.3503vw, 1.9531rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@xl",
+ {
+ key: "--typography_fluid-arial-text-xl",
+ value: "clamp(1.3672rem, 1.3111rem + 0.2803vw, 1.5625rem)",
+ variable: "--typography_fluid-arial-text-xl: clamp(1.3672rem, 1.3111rem + 0.2803vw, 1.5625rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@l",
+ {
+ key: "--typography_fluid-arial-text-l",
+ value: "clamp(1.0938rem, 1.0489rem + 0.2242vw, 1.25rem)",
+ variable: "--typography_fluid-arial-text-l: clamp(1.0938rem, 1.0489rem + 0.2242vw, 1.25rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@m",
+ {
+ key: "--typography_fluid-arial-text-m",
+ value: "clamp(0.875rem, 0.8391rem + 0.1794vw, 1rem)",
+ variable: "--typography_fluid-arial-text-m: clamp(0.875rem, 0.8391rem + 0.1794vw, 1rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@s",
+ {
+ key: "--typography_fluid-arial-text-s",
+ value: "clamp(0.7rem, 0.6713rem + 0.1435vw, 0.8rem)",
+ variable: "--typography_fluid-arial-text-s: clamp(0.7rem, 0.6713rem + 0.1435vw, 0.8rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@xs",
+ {
+ key: "--typography_fluid-arial-text-xs",
+ value: "clamp(0.56rem, 0.537rem + 0.1148vw, 0.64rem)",
+ variable: "--typography_fluid-arial-text-xs: clamp(0.56rem, 0.537rem + 0.1148vw, 0.64rem);",
+ },
+ ],
+]
+`;
+
+snapshot[`processTypography - can process weights 1`] = `
+"--typography_fluid-arial-2xl: clamp(1.709rem, 1.6389rem + 0.3503vw, 1.9531rem);
+--typography_fluid-arial-xl: clamp(1.3672rem, 1.3111rem + 0.2803vw, 1.5625rem);
+--typography_fluid-arial-l: clamp(1.0938rem, 1.0489rem + 0.2242vw, 1.25rem);
+--typography_fluid-arial-m: clamp(0.875rem, 0.8391rem + 0.1794vw, 1rem);
+--typography_fluid-arial-s: clamp(0.7rem, 0.6713rem + 0.1435vw, 0.8rem);
+--typography_fluid-arial-xs: clamp(0.56rem, 0.537rem + 0.1148vw, 0.64rem);
+--typography_fluid-arial-2xs: clamp(0.448rem, 0.4296rem + 0.0918vw, 0.512rem);
+--typography-weight-arial-regular: 500;"
+`;
+
+snapshot[`processTypography - can process weights 2`] = `
+[
+ [
+ "typography_fluid.arial@2xl",
+ {
+ key: "--typography_fluid-arial-2xl",
+ value: "clamp(1.709rem, 1.6389rem + 0.3503vw, 1.9531rem)",
+ variable: "--typography_fluid-arial-2xl: clamp(1.709rem, 1.6389rem + 0.3503vw, 1.9531rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@xl",
+ {
+ key: "--typography_fluid-arial-xl",
+ value: "clamp(1.3672rem, 1.3111rem + 0.2803vw, 1.5625rem)",
+ variable: "--typography_fluid-arial-xl: clamp(1.3672rem, 1.3111rem + 0.2803vw, 1.5625rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@l",
+ {
+ key: "--typography_fluid-arial-l",
+ value: "clamp(1.0938rem, 1.0489rem + 0.2242vw, 1.25rem)",
+ variable: "--typography_fluid-arial-l: clamp(1.0938rem, 1.0489rem + 0.2242vw, 1.25rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@m",
+ {
+ key: "--typography_fluid-arial-m",
+ value: "clamp(0.875rem, 0.8391rem + 0.1794vw, 1rem)",
+ variable: "--typography_fluid-arial-m: clamp(0.875rem, 0.8391rem + 0.1794vw, 1rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@s",
+ {
+ key: "--typography_fluid-arial-s",
+ value: "clamp(0.7rem, 0.6713rem + 0.1435vw, 0.8rem)",
+ variable: "--typography_fluid-arial-s: clamp(0.7rem, 0.6713rem + 0.1435vw, 0.8rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@xs",
+ {
+ key: "--typography_fluid-arial-xs",
+ value: "clamp(0.56rem, 0.537rem + 0.1148vw, 0.64rem)",
+ variable: "--typography_fluid-arial-xs: clamp(0.56rem, 0.537rem + 0.1148vw, 0.64rem);",
+ },
+ ],
+ [
+ "typography_fluid.arial@2xs",
+ {
+ key: "--typography_fluid-arial-2xs",
+ value: "clamp(0.448rem, 0.4296rem + 0.0918vw, 0.512rem)",
+ variable: "--typography_fluid-arial-2xs: clamp(0.448rem, 0.4296rem + 0.0918vw, 0.512rem);",
+ },
+ ],
+ [
+ "typography.weight.arial.regular",
+ {
+ key: "--typography-weight-arial-regular",
+ value: "500",
+ variable: "--typography-weight-arial-regular: 500;",
+ },
+ ],
+]
+`;
diff --git a/tests/colors.test.ts b/tests/colors.test.ts
index 14688a7..266964a 100644
--- a/tests/colors.test.ts
+++ b/tests/colors.test.ts
@@ -1,15 +1,18 @@
-import { assertEquals } from "@std/assert";
+import { assert, assertEquals } from "@std/assert";
+import { assertSnapshot } from "@std/testing/snapshot";
import { defineConfig, processColors } from "../src/mod.ts";
import { getLines } from "./helpers.ts";
-Deno.test("processColors - converts hex to oklch", () => {
+Deno.test("processColors - converts hex to oklch", async (t) => {
const config = defineConfig({
colors: {
palette: {
value: {
coral: {
- 100: { hex: "#FF7F50" },
- 200: { hex: "#FF6347" },
+ value: {
+ 100: { hex: "#FF7F50" },
+ 200: { hex: "#FF6347" },
+ },
},
},
},
@@ -19,30 +22,34 @@ Deno.test("processColors - converts hex to oklch", () => {
const { css, resolveMap } = processColors(config.colors);
const lines = getLines(css);
assertEquals(
- lines[1].trim(),
+ lines[2].trim(),
"--palette-coral-100: oklch(73.511% 0.16799 40.24666);",
);
assertEquals(
- lines[2].trim(),
+ lines[3].trim(),
"--palette-coral-200: oklch(69.622% 0.19552 32.32143);",
);
assertEquals(Array.from(resolveMap.keys()), [
- "palette.value.coral.100",
- "palette.value.coral.200",
+ "palette.coral.100",
+ "palette.coral.200",
]);
+ await assertSnapshot(t, css);
+ await assertSnapshot(t, Array.from(resolveMap.entries()));
});
-Deno.test("processColors - handles different color formats", () => {
+Deno.test("processColors - handles different color formats", async (t) => {
const config = defineConfig(
{
colors: {
palette: {
value: {
brand: {
- default: { hex: "#FF0000" },
- 200: { rgb: [0, 255, 0] },
- 300: { hsl: [240, 100, 50] },
- 400: { oklch: "oklch(0.7 0.2 270)" },
+ value: {
+ default: { hex: "#FF0000" },
+ 200: { rgb: [0, 255, 0] },
+ 300: { hsl: [240, 100, 50] },
+ 400: { oklch: "oklch(0.7 0.2 270)" },
+ },
},
},
},
@@ -53,35 +60,39 @@ Deno.test("processColors - handles different color formats", () => {
const lines = getLines(css);
assertEquals(
- lines[1].trim(),
+ lines[2].trim(),
"--palette-brand-200: oklch(86.644% 0.29483 142.49535);",
);
assertEquals(
- lines[2].trim(),
+ lines[3].trim(),
"--palette-brand-300: oklch(45.201% 0.31321 264.05202);",
);
- assertEquals(lines[3].trim(), "--palette-brand-400: oklch(70% 0.2 270);");
+ assertEquals(lines[4].trim(), "--palette-brand-400: oklch(70% 0.2 270);");
assertEquals(
- lines[4].trim(),
+ lines[5].trim(),
"--palette-brand-default: oklch(62.796% 0.25768 29.23388);",
);
assertEquals(Array.from(resolveMap.keys()), [
- "palette.value.brand.200",
- "palette.value.brand.300",
- "palette.value.brand.400",
- "palette.value.brand.default",
+ "palette.brand.200",
+ "palette.brand.300",
+ "palette.brand.400",
+ "palette.brand.default",
]);
+ await assertSnapshot(t, css);
+ await assertSnapshot(t, Array.from(resolveMap.entries()));
});
-Deno.test("processColors - handles string values", () => {
+Deno.test("processColors - handles string values", async (t) => {
const config = defineConfig({
colors: {
palette: {
value: {
simple: {
- white: "oklch(100% 0 0)",
- black: "#000",
+ value: {
+ white: "oklch(100% 0 0)",
+ black: "#000",
+ },
},
},
},
@@ -90,41 +101,45 @@ Deno.test("processColors - handles string values", () => {
const { css, resolveMap } = processColors(config.colors);
const lines = getLines(css);
assertEquals(
- lines[1].trim(),
+ lines[2].trim(),
"--palette-simple-white: oklch(100% 0 0);",
);
assertEquals(
- lines[2].trim(),
+ lines[3].trim(),
"--palette-simple-black: oklch(0% 0 0);",
);
assertEquals(Array.from(resolveMap.keys()), [
- "palette.value.simple.white",
- "palette.value.simple.black",
+ "palette.simple.white",
+ "palette.simple.black",
]);
+ await assertSnapshot(t, css);
+ await assertSnapshot(t, Array.from(resolveMap.entries()));
});
-Deno.test("processColors - handles themes", () => {
+Deno.test("processColors - handles themes", async (t) => {
const config = defineConfig({
colors: {
palette: {
value: {
simple: {
- white: "oklch(100% 0 0)",
- black: { hex: "#000" },
+ value: {
+ white: "oklch(100% 0 0)",
+ black: { hex: "#000" },
+ },
},
},
},
theme: {
- value: {
- light: {
+ light: {
+ value: {
background: {
value: {
primary: "var(--1)",
secondary: "var(--2)",
},
variables: {
- 1: "palette.value.simple.white",
- 2: "palette.value.simple.black",
+ 1: "palette.simple.white",
+ 2: "palette.simple.black",
},
},
},
@@ -135,29 +150,33 @@ Deno.test("processColors - handles themes", () => {
const { css, resolveMap } = processColors(config.colors);
const lines = getLines(css);
assertEquals(
- lines[5].trim(),
+ lines[7].trim(),
"--theme-light-background-primary: var(--palette-simple-white);",
);
assertEquals(
- lines[6].trim(),
+ lines[8].trim(),
"--theme-light-background-secondary: var(--palette-simple-black);",
);
assertEquals(Array.from(resolveMap.keys()), [
- "palette.value.simple.white",
- "palette.value.simple.black",
- "theme.value.light.background.primary",
- "theme.value.light.background.secondary",
+ "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()));
});
-Deno.test("processColors - handles transparency", () => {
+Deno.test("processColors - handles transparency", async (t) => {
const config = defineConfig({
colors: {
palette: {
value: {
alpha: {
- softGray1: "oklch(14.48% 0 0 / 12%)",
- softGray2: "oklch(14.48% 0 0 / 24%)",
+ value: {
+ softGray1: "oklch(14.48% 0 0 / 12%)",
+ softGray2: "oklch(14.48% 0 0 / 24%)",
+ },
},
},
},
@@ -166,31 +185,37 @@ Deno.test("processColors - handles transparency", () => {
const { css, resolveMap } = processColors(config.colors);
const lines = getLines(css);
assertEquals(
- lines[1],
+ lines[2].trim(),
"--palette-alpha-softGray1: oklch(14.48% 0 0 / 12%);",
);
assertEquals(
- lines[2],
+ lines[3].trim(),
"--palette-alpha-softGray2: oklch(14.48% 0 0 / 24%);",
);
assertEquals(Array.from(resolveMap.keys()), [
- "palette.value.alpha.softGray1",
- "palette.value.alpha.softGray2",
+ "palette.alpha.softGray1",
+ "palette.alpha.softGray2",
]);
+ await assertSnapshot(t, css);
+ await assertSnapshot(t, Array.from(resolveMap.entries()));
});
-Deno.test("processColors - generates gradient with color variables", () => {
+Deno.test("processColors - generates gradient with color variables", async (t) => {
const config = defineConfig({
colors: {
palette: {
value: {
coral: {
- "50": { hex: "#FF7E60" },
- "90": { hex: "#FF7F40" },
- "100": { hex: "#FF6347" },
+ value: {
+ "50": { hex: "#FF7E60" },
+ "90": { hex: "#FF7F40" },
+ "100": { hex: "#FF6347" },
+ },
},
indigo: {
- "100": { hex: "#4F46E5" },
+ value: {
+ "100": { hex: "#4F46E5" },
+ },
},
},
},
@@ -202,10 +227,10 @@ Deno.test("processColors - generates gradient with color variables", () => {
value:
"linear-gradient(261.78deg, var(--1) 33.1%, var(--2) 56.3%, var(--3) 65.78%, var(--4) 84.23%)",
variables: {
- "1": "palette.value.coral.50",
- "2": "palette.value.coral.90",
- "3": "palette.value.coral.100",
- "4": "palette.value.indigo.100",
+ "1": "palette.coral.50",
+ "2": "palette.coral.90",
+ "3": "palette.coral.100",
+ "4": "palette.indigo.100",
},
},
},
@@ -223,21 +248,25 @@ Deno.test("processColors - generates gradient with color variables", () => {
assertEquals(lines.at(-1), expected);
assertEquals(Array.from(result.resolveMap.keys()), [
- "palette.value.coral.50",
- "palette.value.coral.90",
- "palette.value.coral.100",
- "palette.value.indigo.100",
- "gradients.value.orangeGradient.primary",
+ "palette.coral.50",
+ "palette.coral.90",
+ "palette.coral.100",
+ "palette.indigo.100",
+ "gradients.orangeGradient.primary",
]);
+ await assertSnapshot(t, result.css);
+ await assertSnapshot(t, Array.from(result.resolveMap.entries()));
});
-Deno.test("processColors - handles themes referencing gradients", () => {
+Deno.test("processColors - handles themes referencing gradients", async (t) => {
const config = defineConfig({
colors: {
palette: {
value: {
coral: {
- "50": { hex: "#FF7E60" },
+ value: {
+ "50": { hex: "#FF7E60" },
+ },
},
},
},
@@ -248,8 +277,8 @@ Deno.test("processColors - handles themes referencing gradients", () => {
primary: {
value: "linear-gradient(to right, var(--c1), var(--c2))",
variables: {
- "c1": "palette.value.coral.50",
- "c2": "palette.value.coral.50",
+ "c1": "palette.coral.50",
+ "c2": "palette.coral.50",
},
},
},
@@ -257,14 +286,14 @@ Deno.test("processColors - handles themes referencing gradients", () => {
},
},
theme: {
- value: {
- light: {
+ light: {
+ value: {
background: {
value: {
primary: "var(--grad)",
},
variables: {
- "grad": "gradients.value.orangeGradient.primary",
+ "grad": "gradients.orangeGradient.primary",
},
},
},
@@ -281,8 +310,184 @@ Deno.test("processColors - handles themes referencing gradients", () => {
"--theme-light-background-primary: var(--gradients-orangeGradient-primary);",
);
assertEquals(Array.from(resolveMap.keys()), [
- "palette.value.coral.50",
- "gradients.value.orangeGradient.primary",
- "theme.value.light.background.primary",
+ "palette.coral.50",
+ "gradients.orangeGradient.primary",
+ "theme.light.background.primary",
+ ]);
+ await assertSnapshot(t, css);
+ await assertSnapshot(t, Array.from(resolveMap.entries()));
+});
+
+Deno.test("processColors - handles gradients with conditions", async (t) => {
+ const config = defineConfig({
+ colors: {
+ palette: {
+ value: {
+ coral: {
+ value: {
+ "50": { hex: "#FF7E60" },
+ },
+ },
+ },
+ },
+ gradients: {
+ value: {
+ orangeGradient: {
+ value: {
+ primary: {
+ value: "linear-gradient(to right, var(--c1), var(--c2))",
+ variables: {
+ "c1": "palette.coral.50",
+ "c2": "palette.coral.50",
+ },
+ },
+ },
+ settings: {
+ condition: "@media (prefers-color-scheme: dark)",
+ },
+ },
+ },
+ },
+ },
+ });
+
+ const { css, resolveMap } = processColors(config.colors);
+ const lines = getLines(css);
+
+ const mediaQueryIndex = lines.findIndex((line) =>
+ line.includes("@media (prefers-color-scheme: dark)")
+ );
+
+ assertEquals(lines[mediaQueryIndex], "@media (prefers-color-scheme: dark) {");
+
+ const varIndex = lines.findIndex((line, idx) =>
+ idx > mediaQueryIndex && line.includes("--gradients-orangeGradient-primary:")
+ );
+
+ assert(
+ varIndex > mediaQueryIndex,
+ "Gradient variable should be inside the media query block",
+ );
+
+ assertEquals(
+ lines[varIndex].trim(),
+ "--gradients-orangeGradient-primary: linear-gradient(to right, var(--palette-coral-50), var(--palette-coral-50));",
+ );
+
+ assertEquals(Array.from(resolveMap.keys()), [
+ "palette.coral.50",
+ "gradients.orangeGradient.primary",
+ ]);
+ await assertSnapshot(t, css);
+ await assertSnapshot(t, Array.from(resolveMap.entries()));
+});
+
+Deno.test("processColors - handles palette colors with conditions", async (t) => {
+ const config = defineConfig({
+ colors: {
+ palette: {
+ value: {
+ background: {
+ value: {
+ light: "oklch(100% 0 0)",
+ },
+ },
+ backgroundDark: {
+ value: {
+ dark: { hex: "#000" },
+ },
+ settings: {
+ condition: "@media (prefers-color-scheme: dark)",
+ },
+ },
+ },
+ },
+ },
+ });
+ const { css, resolveMap } = processColors(config.colors);
+ const lines = getLines(css);
+
+ assertEquals(
+ lines[2].trim(),
+ "--palette-background-light: oklch(100% 0 0);",
+ );
+
+ const mediaQueryIndex = lines.findIndex((line) =>
+ line.includes("@media (prefers-color-scheme: dark)")
+ );
+
+ assertEquals(lines[mediaQueryIndex], "@media (prefers-color-scheme: dark) {");
+
+ const darkVarIndex = lines.findIndex((line) =>
+ line.includes("--palette-backgroundDark-dark:")
+ );
+
+ assertEquals(
+ lines[darkVarIndex].trim(),
+ "--palette-backgroundDark-dark: oklch(0% 0 0);",
+ );
+
+ const closingBraceIndex = lines.findIndex((line, idx) =>
+ idx > mediaQueryIndex && line === "}"
+ );
+ assert(
+ closingBraceIndex > darkVarIndex,
+ "Closing brace should exist after variables",
+ );
+
+ assertEquals(Array.from(resolveMap.keys()), [
+ "palette.background.light",
+ "palette.backgroundDark.dark",
+ ]);
+ await assertSnapshot(t, css);
+ await assertSnapshot(t, Array.from(resolveMap.entries()));
+});
+
+Deno.test("processColors - handles themes with class condition", async (t) => {
+ const config = defineConfig({
+ colors: {
+ palette: {
+ value: {
+ base: {
+ value: {
+ primary: { hex: "#FF7F50" },
+ },
+ },
+ },
+ },
+ theme: {
+ dark: {
+ value: {
+ background: {
+ value: {
+ primary: "var(--1)",
+ },
+ variables: {
+ "1": "palette.base.primary",
+ },
+ },
+ },
+ settings: {
+ condition: ".dark-theme",
+ },
+ },
+ },
+ },
+ });
+
+ const { css, resolveMap } = processColors(config.colors);
+ const lines = getLines(css);
+
+ const classIndex = lines.findIndex((l) => l.includes(".dark-theme"));
+ assertEquals(lines[classIndex], ".dark-theme {");
+
+ const varIndex = lines.findIndex((l) => l.includes("--theme-dark-background-primary:"));
+ assert(varIndex > classIndex, "theme variable should be inside the class block");
+
+ assertEquals(Array.from(resolveMap.keys()), [
+ "palette.base.primary",
+ "theme.dark.background.primary",
]);
+ await assertSnapshot(t, css);
+ await assertSnapshot(t, Array.from(resolveMap.entries()));
});
diff --git a/tests/primitive.test.ts b/tests/primitive.test.ts
index c52388a..519c77f 100644
--- a/tests/primitive.test.ts
+++ b/tests/primitive.test.ts
@@ -1,8 +1,9 @@
import { assertEquals } from "@std/assert";
+import { assertSnapshot } from "@std/testing/snapshot";
import { processPrimitives } from "../src/modules/primitive.ts";
import { defineConfig } from "../src/mod.ts";
-Deno.test("processPrimitives - processes button with variables", () => {
+Deno.test("processPrimitives - processes button with variables", async (t) => {
const config = defineConfig({
typography: {
fluid: {
@@ -44,8 +45,8 @@ Deno.test("processPrimitives - processes button with variables", () => {
},
variables: {
"base": "typography_fluid.arial@m",
- "2": "spacing.custom.size.value.2",
- "3": "spacing.custom.size.value.3",
+ "2": "spacing.custom.size.2",
+ "3": "spacing.custom.size.3",
},
settings: { pxToRem: false },
},
@@ -65,9 +66,11 @@ Deno.test("processPrimitives - processes button with variables", () => {
].join("\n");
assertEquals(result.css, expected);
+ await assertSnapshot(t, result.css);
+ await assertSnapshot(t, Array.from(result.resolveMap.entries()));
});
-Deno.test("processPrimitives - processes buttons with settings", () => {
+Deno.test("processPrimitives - processes buttons with settings", async (t) => {
const config = defineConfig({
primitives: {
button: {
@@ -105,15 +108,19 @@ Deno.test("processPrimitives - processes buttons with settings", () => {
].join("\n");
assertEquals(result.css, expected);
+ await assertSnapshot(t, result.css);
+ await assertSnapshot(t, Array.from(result.resolveMap.entries()));
});
-Deno.test("processPrimitives - references colors, gradients, and themes", () => {
+Deno.test("processPrimitives - references colors, gradients, and themes", async (t) => {
const config = defineConfig({
colors: {
palette: {
value: {
coral: {
- "50": { hex: "#FF7E60" },
+ value: {
+ "50": { hex: "#FF7E60" },
+ },
},
},
},
@@ -124,8 +131,8 @@ Deno.test("processPrimitives - references colors, gradients, and themes", () =>
primary: {
value: "linear-gradient(to right, var(--c1), var(--c2))",
variables: {
- "c1": "palette.value.coral.50",
- "c2": "palette.value.coral.50",
+ "c1": "palette.coral.50",
+ "c2": "palette.coral.50",
},
},
},
@@ -133,14 +140,14 @@ Deno.test("processPrimitives - references colors, gradients, and themes", () =>
},
},
theme: {
- value: {
- light: {
+ light: {
+ value: {
background: {
value: {
primary: "var(--grad)",
},
variables: {
- "grad": "gradients.value.orangeGradient.primary",
+ "grad": "gradients.orangeGradient.primary",
},
},
},
@@ -157,9 +164,9 @@ Deno.test("processPrimitives - references colors, gradients, and themes", () =>
"border-color": "var(--border)",
},
variables: {
- "bg": "theme.value.light.background.primary",
- "grad": "gradients.value.orangeGradient.primary",
- "border": "palette.value.coral.50",
+ "bg": "theme.light.background.primary",
+ "grad": "gradients.orangeGradient.primary",
+ "border": "palette.coral.50",
},
},
},
@@ -176,9 +183,11 @@ Deno.test("processPrimitives - references colors, gradients, and themes", () =>
].join("\n");
assertEquals(result.css, expected);
+ await assertSnapshot(t, result.css);
+ await assertSnapshot(t, Array.from(result.resolveMap.entries()));
});
-Deno.test("processPrimitives - uses fluid spacing references", () => {
+Deno.test("processPrimitives - uses fluid spacing references", async (t) => {
const config = defineConfig({
spacing: {
fluid: {
@@ -218,4 +227,6 @@ Deno.test("processPrimitives - uses fluid spacing references", () => {
"--box-default-padding: var(--spacing_fluid-gap-gs-s) var(--spacing_fluid-gap-gs-m);",
].join("\n");
assertEquals(primitives.css, expected);
+ await assertSnapshot(t, primitives.css);
+ await assertSnapshot(t, Array.from(primitives.resolveMap.entries()));
});
diff --git a/tests/spacing.test.ts b/tests/spacing.test.ts
index ccad980..2156e92 100644
--- a/tests/spacing.test.ts
+++ b/tests/spacing.test.ts
@@ -1,8 +1,9 @@
import { assertEquals } from "@std/assert";
+import { assertSnapshot } from "@std/testing/snapshot";
import { processSpacing } from "../src/modules/spacing.ts";
import { defineConfig } from "../src/config.ts";
-Deno.test("processSpacing - generates correct spacing scale", () => {
+Deno.test("processSpacing - generates correct spacing scale", async (t) => {
const config = defineConfig({
spacing: {
custom: {
@@ -23,15 +24,17 @@ Deno.test("processSpacing - generates correct spacing scale", () => {
assertEquals(result.css, expected);
assertEquals(Array.from(result.resolveMap.keys()), [
- "spacing.custom.size.value.1",
- "spacing.custom.size.value.2",
- "spacing.custom.size.value.3",
- "spacing.custom.size.value.s",
+ "spacing.custom.size.1",
+ "spacing.custom.size.2",
+ "spacing.custom.size.3",
+ "spacing.custom.size.s",
]);
+ await assertSnapshot(t, result.css);
+ await assertSnapshot(t, Array.from(result.resolveMap.entries()));
});
// Test with string keys
-Deno.test("processSpacing - handles settings", () => {
+Deno.test("processSpacing - handles settings", async (t) => {
const config = defineConfig({
spacing: {
custom: {
@@ -58,14 +61,16 @@ Deno.test("processSpacing - handles settings", () => {
assertEquals(result.css, expected);
assertEquals(Array.from(result.resolveMap.keys()), [
- "spacing.custom.size.value.1",
- "spacing.custom.size.value.2",
- "spacing.custom.scale.value.md",
- "spacing.custom.scale.value.lg",
+ "spacing.custom.size.1",
+ "spacing.custom.size.2",
+ "spacing.custom.scale.md",
+ "spacing.custom.scale.lg",
]);
+ await assertSnapshot(t, result.css);
+ await assertSnapshot(t, Array.from(result.resolveMap.entries()));
});
-Deno.test("processSpacing - generates fluid spacing (prefix)", () => {
+Deno.test("processSpacing - generates fluid spacing (prefix)", async (t) => {
const config = defineConfig({
spacing: {
fluid: {
@@ -108,9 +113,11 @@ Deno.test("processSpacing - generates fluid spacing (prefix)", () => {
"spacing_fluid.base@s-m",
"spacing_fluid.base@m-l",
]);
+ await assertSnapshot(t, css);
+ await assertSnapshot(t, Array.from(resolveMap.entries()));
});
-Deno.test("processSpacing - fluid without prefix falls back to scale name", () => {
+Deno.test("processSpacing - fluid without prefix falls back to scale name", async (t) => {
const config = defineConfig({
spacing: {
fluid: {
@@ -144,9 +151,11 @@ Deno.test("processSpacing - fluid without prefix falls back to scale name", () =
"spacing_fluid.rhythm@xs-s",
"spacing_fluid.rhythm@s-m",
]);
+ await assertSnapshot(t, css);
+ await assertSnapshot(t, Array.from(resolveMap.entries()));
});
-Deno.test("processSpacing - combines fluid and custom spacing", () => {
+Deno.test("processSpacing - combines fluid and custom spacing", async (t) => {
const config = defineConfig({
spacing: {
fluid: {
@@ -187,7 +196,9 @@ Deno.test("processSpacing - combines fluid and custom spacing", () => {
"spacing_fluid.base@m",
"spacing_fluid.base@xs-s",
"spacing_fluid.base@s-m",
- "spacing.custom.gap.value.1",
- "spacing.custom.gap.value.2",
+ "spacing.custom.gap.1",
+ "spacing.custom.gap.2",
]);
+ await assertSnapshot(t, css);
+ await assertSnapshot(t, Array.from(resolveMap.entries()));
});
diff --git a/tests/typography.test.ts b/tests/typography.test.ts
index 04a19b0..01b2d78 100644
--- a/tests/typography.test.ts
+++ b/tests/typography.test.ts
@@ -1,8 +1,9 @@
import { assertEquals } from "@std/assert";
+import { assertSnapshot } from "@std/testing/snapshot";
import { defineConfig, processTypography } from "../src/mod.ts";
import { getLines } from "./helpers.ts";
-Deno.test("processTypography - generates correct CSS variables", () => {
+Deno.test("processTypography - generates correct CSS variables", async (t) => {
const config = defineConfig({
typography: {
fluid: {
@@ -56,9 +57,11 @@ Deno.test("processTypography - generates correct CSS variables", () => {
);
assertEquals(hasSize, true, `Missing size ${size}`);
});
+ await assertSnapshot(t, result.css);
+ await assertSnapshot(t, Array.from(result.resolveMap.entries()));
});
-Deno.test("typography - can handle custom labels and prefixes", () => {
+Deno.test("typography - can handle custom labels and prefixes", async (t) => {
const config = defineConfig({
typography: {
fluid: {
@@ -128,9 +131,11 @@ Deno.test("typography - can handle custom labels and prefixes", () => {
);
assertEquals(hasSize, true, `Missing size ${size}`);
});
+ await assertSnapshot(t, result.css);
+ await assertSnapshot(t, Array.from(result.resolveMap.entries()));
});
-Deno.test("processTypography - can process weights", () => {
+Deno.test("processTypography - can process weights", async (t) => {
const positiveSteps = 3;
const negativeSteps = 3;
const config = defineConfig({
@@ -169,7 +174,7 @@ Deno.test("processTypography - can process weights", () => {
"typography_fluid.arial@s",
"typography_fluid.arial@xs",
"typography_fluid.arial@2xs",
- "typography.weight.arial.value.regular",
+ "typography.weight.arial.regular",
],
);
// Test that we have the weight variable
@@ -177,4 +182,6 @@ Deno.test("processTypography - can process weights", () => {
line.includes("--typography-weight-arial-regular:")
);
assertEquals(xlLine, "--typography-weight-arial-regular: 500;");
+ await assertSnapshot(t, result.css);
+ await assertSnapshot(t, Array.from(result.resolveMap.entries()));
});