@fusion.dev/helix-docs 0.111.1 → 0.112.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/content/intent-reference.mdx +5 -2
- package/content/metrics.mdx +2 -2
- package/content/theming.mdx +49 -10
- package/dist/sources.generated.js +56 -14
- package/package.json +10 -4
|
@@ -10,11 +10,14 @@ title: Intent reference
|
|
|
10
10
|
every field `ThemeIntent` accepts and what changes when you set it.
|
|
11
11
|
|
|
12
12
|
```ts
|
|
13
|
-
import {
|
|
13
|
+
import { initTheme } from '@fusion.dev/helix-theme'
|
|
14
14
|
|
|
15
|
-
const
|
|
15
|
+
const engine = await initTheme('/theme.wasm')
|
|
16
|
+
const theme = engine.derive({ brand: '#2563eb' })
|
|
16
17
|
```
|
|
17
18
|
|
|
19
|
+
[Deriving a theme](./theming) shows how Node loads the engine.
|
|
20
|
+
|
|
18
21
|
**`brand` is the only required input.** Every other field has a default,
|
|
19
22
|
computed from `brand` or from the Helix design language. A theme that sets only
|
|
20
23
|
`brand` is a valid theme.
|
package/content/metrics.mdx
CHANGED
|
@@ -60,7 +60,7 @@ either barrel. The per-component tables show what your page pays.
|
|
|
60
60
|
| `@fusion.dev/helix-core` | 177,056 | 56,663 | 48,189 | The element base class, mixins, decorators, and floating positioning. |
|
|
61
61
|
| `@fusion.dev/helix-headless` | 726,171 | 188,118 | 146,385 | Every headless family. The barrel entry includes all of them. |
|
|
62
62
|
| `@fusion.dev/helix-icons` | 55,565 | 17,727 | 14,864 | The whole glyph set. |
|
|
63
|
-
| `@fusion.dev/helix-theme` | 3,
|
|
63
|
+
| `@fusion.dev/helix-theme` | 3,626 | 1,597 | 1,384 | The derivation engine. Most sites run it at build time, and a theme switcher runs it in the browser. |
|
|
64
64
|
| `@fusion.dev/helix` | 1,257,753 | 294,483 | 216,072 | Every styled family. |
|
|
65
65
|
| `lit` | 15,394 | 6,118 | 5,460 | Lit itself, listed so you can subtract it from every row above. |
|
|
66
66
|
|
|
@@ -402,7 +402,7 @@ stripped column shows the bytes we removed.
|
|
|
402
402
|
| `@fusion.dev/helix-headless` | 13,168,854 | 504 | 1,051,088 | `@fusion.dev/helix-core`, `@fusion.dev/helix-icons`, `uqr` |
|
|
403
403
|
| `@fusion.dev/helix-icons` | 150,162 | 21 | 50,346 | `svgo` |
|
|
404
404
|
| `@fusion.dev/helix-styles` | 102,108 | 6 | 0 | none |
|
|
405
|
-
| `@fusion.dev/helix-theme` |
|
|
405
|
+
| `@fusion.dev/helix-theme` | 500,416 | 8 | 5,191 | none |
|
|
406
406
|
| `@fusion.dev/helix` | 14,295,674 | 870 | 371,115 | `@fusion.dev/helix-core`, `@fusion.dev/helix-headless`, `@fusion.dev/helix-styles` |
|
|
407
407
|
|
|
408
408
|
## Not measured yet
|
package/content/theming.mdx
CHANGED
|
@@ -45,22 +45,35 @@ exact for the default seed and approximate for any other.
|
|
|
45
45
|
target, measures every pair, and returns the theme with any violations:
|
|
46
46
|
|
|
47
47
|
```ts
|
|
48
|
-
import {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
import { readFile } from 'node:fs/promises'
|
|
49
|
+
import { initTheme } from '@fusion.dev/helix-theme'
|
|
50
|
+
|
|
51
|
+
const engine = await initTheme(
|
|
52
|
+
await readFile(new URL(import.meta.resolve('@fusion.dev/helix-theme/wasm/fusion_helix_theme_bg.wasm'))),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
const theme = engine.derive(
|
|
56
|
+
{
|
|
57
|
+
brand: '#0b3d91',
|
|
58
|
+
contrastTarget: 4.5, // 4.5 is WCAG AA, 7 is AAA
|
|
59
|
+
scheme: 'light',
|
|
60
|
+
},
|
|
61
|
+
[':root'],
|
|
62
|
+
)
|
|
55
63
|
|
|
56
64
|
if (theme.violations.length > 0) {
|
|
57
65
|
throw new Error(theme.violations.join('\n'))
|
|
58
66
|
}
|
|
59
67
|
|
|
60
|
-
console.log(
|
|
68
|
+
console.log(theme.css[':root'])
|
|
61
69
|
```
|
|
62
70
|
|
|
63
|
-
The
|
|
71
|
+
The engine is WebAssembly, so `initTheme` loads it once and you wait for it.
|
|
72
|
+
Node passes the module's bytes, as above. A browser passes the URL you serve
|
|
73
|
+
`fusion_helix_theme_bg.wasm` from, such as `initTheme('/theme.wasm')`.
|
|
74
|
+
`derive` renders the CSS under each selector you name.
|
|
75
|
+
|
|
76
|
+
The CSS includes the seeds as well as the tokens. The stylesheet
|
|
64
77
|
computes the values the engine does not, from the same seeds the engine used:
|
|
65
78
|
|
|
66
79
|
- The twenty-four series colors for charts
|
|
@@ -71,6 +84,32 @@ This keeps both ways of theming in agreement on the same page.
|
|
|
71
84
|
|
|
72
85
|
Use tuned to try a color. Use verified for the theme you ship.
|
|
73
86
|
|
|
87
|
+
## Derive both modes
|
|
88
|
+
|
|
89
|
+
A site with light and dark mode needs both themes. `deriveModes` derives your
|
|
90
|
+
intent in each mode and renders one block, with each color as a
|
|
91
|
+
`light-dark()` pair, the way the shipped stylesheet writes its tokens:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
import { initTheme } from '@fusion.dev/helix-theme'
|
|
95
|
+
|
|
96
|
+
const engine = await initTheme('/theme.wasm')
|
|
97
|
+
const { css, dark, light } = engine.deriveModes({ brand: '#0b3d91' }, [':root'])
|
|
98
|
+
|
|
99
|
+
for (const theme of [light, dark]) {
|
|
100
|
+
if (theme.violations.length > 0) {
|
|
101
|
+
throw new Error(theme.violations.join('\n'))
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
console.log(css[':root'])
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`color-scheme` picks the half, so the block follows the operating system and
|
|
109
|
+
`[data-color-mode]` on any element, as described in [Color modes](./color-modes).
|
|
110
|
+
A value that is not a color and still changes with the mode, such as the edge
|
|
111
|
+
of a floating surface, is set by rules after the block, one for each mode.
|
|
112
|
+
|
|
74
113
|
## Why Helix uses OKLCH
|
|
75
114
|
|
|
76
115
|
Equal numeric steps in sRGB do not look like equal steps. That makes scales and
|
|
@@ -106,7 +145,7 @@ engine solves each foreground color against the hardest surface it appears on.
|
|
|
106
145
|
Each derived token includes the result of its contrast check:
|
|
107
146
|
|
|
108
147
|
```ts
|
|
109
|
-
const theme =
|
|
148
|
+
const theme = engine.derive({ brand })
|
|
110
149
|
|
|
111
150
|
for (const token of theme.tokens) {
|
|
112
151
|
console.log(token.name, token.hex, token.contrast, token.chromaReduced)
|
|
@@ -1905,11 +1905,14 @@ title: Intent reference
|
|
|
1905
1905
|
every field \`ThemeIntent\` accepts and what changes when you set it.
|
|
1906
1906
|
|
|
1907
1907
|
\`\`\`ts
|
|
1908
|
-
import {
|
|
1908
|
+
import { initTheme } from '@fusion.dev/helix-theme'
|
|
1909
1909
|
|
|
1910
|
-
const
|
|
1910
|
+
const engine = await initTheme('/theme.wasm')
|
|
1911
|
+
const theme = engine.derive({ brand: '#2563eb' })
|
|
1911
1912
|
\`\`\`
|
|
1912
1913
|
|
|
1914
|
+
[Deriving a theme](./theming) shows how Node loads the engine.
|
|
1915
|
+
|
|
1913
1916
|
**\`brand\` is the only required input.** Every other field has a default,
|
|
1914
1917
|
computed from \`brand\` or from the Helix design language. A theme that sets only
|
|
1915
1918
|
\`brand\` is a valid theme.
|
|
@@ -2830,7 +2833,7 @@ either barrel. The per-component tables show what your page pays.
|
|
|
2830
2833
|
| \`@fusion.dev/helix-core\` | 177,056 | 56,663 | 48,189 | The element base class, mixins, decorators, and floating positioning. |
|
|
2831
2834
|
| \`@fusion.dev/helix-headless\` | 726,171 | 188,118 | 146,385 | Every headless family. The barrel entry includes all of them. |
|
|
2832
2835
|
| \`@fusion.dev/helix-icons\` | 55,565 | 17,727 | 14,864 | The whole glyph set. |
|
|
2833
|
-
| \`@fusion.dev/helix-theme\` | 3,
|
|
2836
|
+
| \`@fusion.dev/helix-theme\` | 3,626 | 1,597 | 1,384 | The derivation engine. Most sites run it at build time, and a theme switcher runs it in the browser. |
|
|
2834
2837
|
| \`@fusion.dev/helix\` | 1,257,753 | 294,483 | 216,072 | Every styled family. |
|
|
2835
2838
|
| \`lit\` | 15,394 | 6,118 | 5,460 | Lit itself, listed so you can subtract it from every row above. |
|
|
2836
2839
|
|
|
@@ -3172,7 +3175,7 @@ stripped column shows the bytes we removed.
|
|
|
3172
3175
|
| \`@fusion.dev/helix-headless\` | 13,168,854 | 504 | 1,051,088 | \`@fusion.dev/helix-core\`, \`@fusion.dev/helix-icons\`, \`uqr\` |
|
|
3173
3176
|
| \`@fusion.dev/helix-icons\` | 150,162 | 21 | 50,346 | \`svgo\` |
|
|
3174
3177
|
| \`@fusion.dev/helix-styles\` | 102,108 | 6 | 0 | none |
|
|
3175
|
-
| \`@fusion.dev/helix-theme\` |
|
|
3178
|
+
| \`@fusion.dev/helix-theme\` | 500,416 | 8 | 5,191 | none |
|
|
3176
3179
|
| \`@fusion.dev/helix\` | 14,295,674 | 870 | 371,115 | \`@fusion.dev/helix-core\`, \`@fusion.dev/helix-headless\`, \`@fusion.dev/helix-styles\` |
|
|
3177
3180
|
|
|
3178
3181
|
## Not measured yet
|
|
@@ -5173,22 +5176,35 @@ exact for the default seed and approximate for any other.
|
|
|
5173
5176
|
target, measures every pair, and returns the theme with any violations:
|
|
5174
5177
|
|
|
5175
5178
|
\`\`\`ts
|
|
5176
|
-
import {
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5179
|
+
import { readFile } from 'node:fs/promises'
|
|
5180
|
+
import { initTheme } from '@fusion.dev/helix-theme'
|
|
5181
|
+
|
|
5182
|
+
const engine = await initTheme(
|
|
5183
|
+
await readFile(new URL(import.meta.resolve('@fusion.dev/helix-theme/wasm/fusion_helix_theme_bg.wasm'))),
|
|
5184
|
+
)
|
|
5185
|
+
|
|
5186
|
+
const theme = engine.derive(
|
|
5187
|
+
{
|
|
5188
|
+
brand: '#0b3d91',
|
|
5189
|
+
contrastTarget: 4.5, // 4.5 is WCAG AA, 7 is AAA
|
|
5190
|
+
scheme: 'light',
|
|
5191
|
+
},
|
|
5192
|
+
[':root'],
|
|
5193
|
+
)
|
|
5183
5194
|
|
|
5184
5195
|
if (theme.violations.length > 0) {
|
|
5185
5196
|
throw new Error(theme.violations.join('\\n'))
|
|
5186
5197
|
}
|
|
5187
5198
|
|
|
5188
|
-
console.log(
|
|
5199
|
+
console.log(theme.css[':root'])
|
|
5189
5200
|
\`\`\`
|
|
5190
5201
|
|
|
5191
|
-
The
|
|
5202
|
+
The engine is WebAssembly, so \`initTheme\` loads it once and you wait for it.
|
|
5203
|
+
Node passes the module's bytes, as above. A browser passes the URL you serve
|
|
5204
|
+
\`fusion_helix_theme_bg.wasm\` from, such as \`initTheme('/theme.wasm')\`.
|
|
5205
|
+
\`derive\` renders the CSS under each selector you name.
|
|
5206
|
+
|
|
5207
|
+
The CSS includes the seeds as well as the tokens. The stylesheet
|
|
5192
5208
|
computes the values the engine does not, from the same seeds the engine used:
|
|
5193
5209
|
|
|
5194
5210
|
- The twenty-four series colors for charts
|
|
@@ -5199,6 +5215,32 @@ This keeps both ways of theming in agreement on the same page.
|
|
|
5199
5215
|
|
|
5200
5216
|
Use tuned to try a color. Use verified for the theme you ship.
|
|
5201
5217
|
|
|
5218
|
+
## Derive both modes
|
|
5219
|
+
|
|
5220
|
+
A site with light and dark mode needs both themes. \`deriveModes\` derives your
|
|
5221
|
+
intent in each mode and renders one block, with each color as a
|
|
5222
|
+
\`light-dark()\` pair, the way the shipped stylesheet writes its tokens:
|
|
5223
|
+
|
|
5224
|
+
\`\`\`ts
|
|
5225
|
+
import { initTheme } from '@fusion.dev/helix-theme'
|
|
5226
|
+
|
|
5227
|
+
const engine = await initTheme('/theme.wasm')
|
|
5228
|
+
const { css, dark, light } = engine.deriveModes({ brand: '#0b3d91' }, [':root'])
|
|
5229
|
+
|
|
5230
|
+
for (const theme of [light, dark]) {
|
|
5231
|
+
if (theme.violations.length > 0) {
|
|
5232
|
+
throw new Error(theme.violations.join('\\n'))
|
|
5233
|
+
}
|
|
5234
|
+
}
|
|
5235
|
+
|
|
5236
|
+
console.log(css[':root'])
|
|
5237
|
+
\`\`\`
|
|
5238
|
+
|
|
5239
|
+
\`color-scheme\` picks the half, so the block follows the operating system and
|
|
5240
|
+
\`[data-color-mode]\` on any element, as described in [Color modes](./color-modes).
|
|
5241
|
+
A value that is not a color and still changes with the mode, such as the edge
|
|
5242
|
+
of a floating surface, is set by rules after the block, one for each mode.
|
|
5243
|
+
|
|
5202
5244
|
## Why Helix uses OKLCH
|
|
5203
5245
|
|
|
5204
5246
|
Equal numeric steps in sRGB do not look like equal steps. That makes scales and
|
|
@@ -5234,7 +5276,7 @@ engine solves each foreground color against the hardest surface it appears on.
|
|
|
5234
5276
|
Each derived token includes the result of its contrast check:
|
|
5235
5277
|
|
|
5236
5278
|
\`\`\`ts
|
|
5237
|
-
const theme =
|
|
5279
|
+
const theme = engine.derive({ brand })
|
|
5238
5280
|
|
|
5239
5281
|
for (const token of theme.tokens) {
|
|
5240
5282
|
console.log(token.name, token.hex, token.contrast, token.chromaReduced)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fusion.dev/helix-docs",
|
|
3
3
|
"description": "Versioned documentation content and registry for Helix.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.112.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ross Sheppard <ross.sheppard@fusion.dev>",
|
|
7
7
|
"repository": {
|
|
@@ -32,12 +32,18 @@
|
|
|
32
32
|
"peers": "bun scripts/build-peers.mjs",
|
|
33
33
|
"test": "bun test src",
|
|
34
34
|
"timings": "bun scripts/build-timings.mjs",
|
|
35
|
-
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
35
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && bun scripts/check-snippets.mjs"
|
|
36
36
|
},
|
|
37
37
|
"bugs": "https://github.com/project-fusion/fusion/issues",
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@fusion.dev/helix
|
|
40
|
-
"@fusion.dev/helix-
|
|
39
|
+
"@fusion.dev/helix": "0.112.0",
|
|
40
|
+
"@fusion.dev/helix-cem": "0.112.0",
|
|
41
|
+
"@fusion.dev/helix-headless": "0.112.0",
|
|
42
|
+
"@fusion.dev/helix-icons": "0.112.0",
|
|
43
|
+
"@fusion.dev/helix-map": "0.112.0",
|
|
44
|
+
"@fusion.dev/helix-styles": "0.112.0",
|
|
45
|
+
"@fusion.dev/helix-testing": "0.112.0",
|
|
46
|
+
"@fusion.dev/helix-theme": "0.112.0",
|
|
41
47
|
"@fusion.dev/scripts": "0.0.0-dev",
|
|
42
48
|
"lit": "^3.2.1",
|
|
43
49
|
"playwright": "^1.62.1"
|