@fusion.dev/helix-docs 0.104.1 → 0.106.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/accessibility.mdx +92 -71
- package/content/angular.mdx +26 -24
- package/content/browser-support.mdx +61 -58
- package/content/building-on-the-headless-tier.mdx +100 -74
- package/content/charting.mdx +98 -79
- package/content/coding-agents.mdx +87 -69
- package/content/color-modes.mdx +40 -37
- package/content/color.mdx +67 -54
- package/content/composition.mdx +85 -83
- package/content/elevation-and-material.mdx +32 -29
- package/content/events.mdx +77 -65
- package/content/forms.mdx +69 -58
- package/content/iconography.mdx +75 -71
- package/content/installation.mdx +77 -68
- package/content/intent-reference.mdx +59 -54
- package/content/introduction.mdx +25 -23
- package/content/localization.mdx +122 -82
- package/content/maps.mdx +431 -0
- package/content/metrics.mdx +296 -299
- package/content/motion.mdx +44 -36
- package/content/other-frameworks.mdx +33 -31
- package/content/overlays.mdx +72 -54
- package/content/overriding-a-component.mdx +85 -74
- package/content/react.mdx +72 -64
- package/content/recipes.mdx +64 -47
- package/content/routing.mdx +100 -93
- package/content/sandbox.mdx +39 -39
- package/content/server-rendering.mdx +95 -84
- package/content/shape-and-borders.mdx +44 -37
- package/content/size-and-density.mdx +51 -46
- package/content/space-and-size.mdx +41 -34
- package/content/state-and-control.mdx +63 -51
- package/content/surfaces-and-separation.mdx +55 -53
- package/content/svelte.mdx +20 -19
- package/content/theme-builder.mdx +42 -31
- package/content/theming.mdx +58 -51
- package/content/tiers.mdx +69 -61
- package/content/tokens.mdx +72 -53
- package/content/typography.mdx +47 -47
- package/content/using-helix-with-an-agent.mdx +147 -115
- package/content/using-the-elements.mdx +55 -50
- package/content/versioning.mdx +42 -35
- package/content/visual-axes.mdx +168 -146
- package/content/vue.mdx +24 -24
- package/content/without-a-bundler.mdx +40 -23
- package/dist/pages.generated.js +49 -43
- package/dist/sources.generated.js +3548 -2682
- package/package.json +3 -3
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: How a property you set becomes a starting value, and how to cancel or take over a change.
|
|
3
3
|
section: Essentials
|
|
4
4
|
title: State and control
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# State and control
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
`
|
|
11
|
-
|
|
9
|
+
A property you set is a starting value, and you can assign it again later to
|
|
10
|
+
correct it. Set `value`, `open`, `checked`, or `active` on a Helix element. The
|
|
11
|
+
element starts there and then manages its own state, as `<input value="Ada">`
|
|
12
|
+
does.
|
|
12
13
|
|
|
13
14
|
```html
|
|
14
15
|
<helix-input
|
|
@@ -17,20 +18,20 @@ managing itself, exactly as `<input value="Ada">` does.
|
|
|
17
18
|
></helix-input>
|
|
18
19
|
```
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
When you type in the input, the value changes. When you assign a new value
|
|
22
|
+
later, the value changes to what you assigned. The control has no modes, and you
|
|
23
|
+
do not need to connect anything before it responds.
|
|
23
24
|
|
|
24
|
-
*
|
|
25
|
-
of
|
|
26
|
-
until
|
|
27
|
-
withholding a state update
|
|
28
|
-
|
|
25
|
+
*Until August 26, 2026, this page said the opposite. Setting a property claimed
|
|
26
|
+
ownership of the state, so the element announced its changes and applied none
|
|
27
|
+
of them until you set the new value. That mode is removed. If you canceled
|
|
28
|
+
changes by withholding a state update, rewrite that code to call
|
|
29
|
+
`preventDefault()`. Nothing else has to change.*
|
|
29
30
|
|
|
30
|
-
##
|
|
31
|
+
## Cancel or take over a change
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
You take control one change at a time. Each change sends a cancelable event
|
|
34
|
+
before it is applied:
|
|
34
35
|
|
|
35
36
|
```ts
|
|
36
37
|
input.addEventListener('helix-before-change', (event) => {
|
|
@@ -40,8 +41,8 @@ input.addEventListener('helix-before-change', (event) => {
|
|
|
40
41
|
})
|
|
41
42
|
```
|
|
42
43
|
|
|
43
|
-
`preventDefault()`
|
|
44
|
-
|
|
44
|
+
`preventDefault()` cancels that one change, and nothing moves. To manage the
|
|
45
|
+
state yourself, cancel the change and assign your own value:
|
|
45
46
|
|
|
46
47
|
```tsx
|
|
47
48
|
<helix-input
|
|
@@ -54,22 +55,27 @@ outright, refuse and assign your own:
|
|
|
54
55
|
/>
|
|
55
56
|
```
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
a form submit, on a link click, on `beforeinput`. Nothing is declared in advance
|
|
59
|
-
and nothing is inferred from which properties you happened to set.
|
|
58
|
+
The platform uses the same pattern. You call `preventDefault()` to cancel:
|
|
60
59
|
|
|
61
|
-
|
|
60
|
+
- a form submit
|
|
61
|
+
- a link click
|
|
62
|
+
- a `beforeinput` event
|
|
63
|
+
|
|
64
|
+
You do not declare anything in advance, and Helix does not infer anything from
|
|
65
|
+
which properties you set.
|
|
66
|
+
|
|
67
|
+
The imperative method reports the same result:
|
|
62
68
|
|
|
63
69
|
```ts
|
|
64
70
|
const applied = item.requestOpen(true)
|
|
65
71
|
```
|
|
66
72
|
|
|
67
|
-
`false` means something
|
|
73
|
+
`false` means something canceled the change.
|
|
68
74
|
|
|
69
|
-
##
|
|
75
|
+
## Follow the state with the change event
|
|
70
76
|
|
|
71
|
-
Most
|
|
72
|
-
element apply:
|
|
77
|
+
Most of the time you do not need to cancel anything. Listen for the change
|
|
78
|
+
event and let the element apply the change:
|
|
73
79
|
|
|
74
80
|
```tsx
|
|
75
81
|
<helix-input label="Name" onChange={(event) => setName(event.currentTarget.value)} />
|
|
@@ -82,11 +88,11 @@ element apply:
|
|
|
82
88
|
></helix-input>
|
|
83
89
|
```
|
|
84
90
|
|
|
85
|
-
The native event carries no detail
|
|
86
|
-
|
|
87
|
-
|
|
91
|
+
The native event carries no detail. The element has already applied the change
|
|
92
|
+
when the event fires, so the value is on the target, where handlers expect to
|
|
93
|
+
find it.
|
|
88
94
|
|
|
89
|
-
## `default
|
|
95
|
+
## `default-value` sets the value a reset returns to
|
|
90
96
|
|
|
91
97
|
```html
|
|
92
98
|
<helix-input
|
|
@@ -95,38 +101,44 @@ where every handler ever written expects to find it.
|
|
|
95
101
|
></helix-input>
|
|
96
102
|
```
|
|
97
103
|
|
|
98
|
-
`default-value` is
|
|
99
|
-
The pair
|
|
100
|
-
attribute* to `defaultValue
|
|
101
|
-
|
|
104
|
+
`default-value` is the value a reset returns to. `value` is the control's
|
|
105
|
+
current value. The pair comes from the platform. A native input reflects its
|
|
106
|
+
`value` *content attribute* to `defaultValue`, and it keeps a dirty flag. Once a
|
|
107
|
+
user has typed, the flag stops the attribute from changing the value.
|
|
102
108
|
|
|
103
|
-
## State is a custom state
|
|
109
|
+
## State is published as a custom state
|
|
104
110
|
|
|
105
111
|
```css
|
|
106
112
|
helix-accordion-item:state(open) { … }
|
|
107
113
|
```
|
|
108
114
|
|
|
109
|
-
`open` is not reflected, and neither is `value`. A
|
|
110
|
-
attribute
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
`value` would carry
|
|
114
|
-
`.value` and `input[value]`.
|
|
115
|
+
`open` is not reflected to an attribute, and neither is `value`. A value written
|
|
116
|
+
back as an attribute would put whatever the last user typed into the markup. A
|
|
117
|
+
serialized element would then hold the user's text, and you could not tell it
|
|
118
|
+
apart from the starting value you wrote. `helix-input` takes `type="password"`.
|
|
119
|
+
A reflected `value` would carry the password past every session-replay masker
|
|
120
|
+
that masks `.value` and `input[value]`.
|
|
121
|
+
|
|
122
|
+
Helix publishes the resolved boolean as a custom state, and the attribute keeps
|
|
123
|
+
the value you wrote. There are four custom states:
|
|
124
|
+
|
|
125
|
+
- `:state(open)`
|
|
126
|
+
- `:state(checked)`
|
|
127
|
+
- `:state(invalid)`
|
|
128
|
+
- `:state(read)`
|
|
115
129
|
|
|
116
|
-
|
|
117
|
-
stays what you wrote. `:state(open)`, `:state(checked)`, `:state(invalid)` and
|
|
118
|
-
`:state(read)` are the four, and they work from your own stylesheet exactly as
|
|
119
|
-
an attribute selector did:
|
|
130
|
+
They work in your own stylesheet as an attribute selector did:
|
|
120
131
|
|
|
121
132
|
```css
|
|
122
133
|
helix-checkbox:state(checked)::part(control) { … }
|
|
123
134
|
helix-input:state(invalid)::part(field) { … }
|
|
124
135
|
```
|
|
125
136
|
|
|
126
|
-
|
|
127
|
-
in the DOM, and the element writes it on its first
|
|
128
|
-
|
|
129
|
-
never produced. React reports that as a
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
the old names,
|
|
137
|
+
Until August 27, 2026, these states were the `data-open` and `data-checked`
|
|
138
|
+
attributes. An attribute is in the DOM, and the element writes it on its first
|
|
139
|
+
update. A framework that renders your markup on the server and then hydrates it
|
|
140
|
+
finds attributes that its own render never produced. React reports that as a
|
|
141
|
+
hydration mismatch and does not fix it. A custom state is not in the DOM. It
|
|
142
|
+
reaches your stylesheet and leaves the markup alone, so the server render and
|
|
143
|
+
the client render always match. If you selected on the old names, replace each
|
|
144
|
+
one with its custom state.
|
|
@@ -1,99 +1,101 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: The four ways a surface is
|
|
2
|
+
description: The four ways to separate a surface from what is behind it, and the tokens that choose between them.
|
|
3
3
|
section: Foundations
|
|
4
4
|
title: Surfaces and separation
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Surfaces and separation
|
|
8
8
|
|
|
9
|
-
**
|
|
10
|
-
a fill, an edge, a lift,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
**Separate each surface from what is behind it with exactly one of four
|
|
10
|
+
things.** The four are a fill, an edge, a lift, and space. A design language
|
|
11
|
+
leads with one of them. Helix uses an edge for surfaces on the page and a lift
|
|
12
|
+
for surfaces above it. A card has a hairline border and no shadow. A menu has a
|
|
13
|
+
shadow and no hairline border. The surface ladder below sets the ground color
|
|
14
|
+
for each place a surface can sit.
|
|
14
15
|
|
|
15
|
-
## The four
|
|
16
|
+
## The four ways to separate a surface
|
|
16
17
|
|
|
17
18
|
| | |
|
|
18
19
|
|---|---|
|
|
19
|
-
| **Fill** | A
|
|
20
|
+
| **Fill** | A ground color different from what is behind it |
|
|
20
21
|
| **Edge** | A border |
|
|
21
22
|
| **Lift** | A shadow |
|
|
22
|
-
| **Space** | Nothing at all
|
|
23
|
+
| **Space** | Nothing at all. The gap separates it |
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
When a design system uses two or three of these without a plan, a card can end
|
|
26
|
+
up with a border, a shadow, and a tint, each added by someone solving the same
|
|
27
|
+
problem again.
|
|
27
28
|
|
|
28
|
-
Helix
|
|
29
|
+
Helix sets the choice with two pairs of policy tokens:
|
|
29
30
|
|
|
30
31
|
[//]: # (tokens:separation-policy)
|
|
31
32
|
|
|
32
33
|
| Token | Value | For |
|
|
33
34
|
| --- | --- | --- |
|
|
34
|
-
| `--helix-border-surface` | `var(--helix-border-thin)` | The
|
|
35
|
-
| `--helix-shadow-surface` | `var(--helix-shadow-none)` | The
|
|
36
|
-
| `--helix-border-floating` | `0` | The
|
|
37
|
-
| `--helix-shadow-floating` | `var(--helix-shadow-lg)` | The
|
|
35
|
+
| `--helix-border-surface` | `var(--helix-border-thin)` | The border of a surface in the page flow. Set it to zero to separate surfaces with shadows. |
|
|
36
|
+
| `--helix-shadow-surface` | `var(--helix-shadow-none)` | The shadow of a surface in the page flow. Set it to none to separate surfaces with borders. |
|
|
37
|
+
| `--helix-border-floating` | `0` | The border of a surface that floats over content. |
|
|
38
|
+
| `--helix-shadow-floating` | `var(--helix-shadow-lg)` | The shadow of a surface that floats over content. |
|
|
38
39
|
|
|
39
40
|
[//]: # (/tokens)
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
To make every component shadow-first, set the border pair to zero and give the
|
|
43
|
+
shadow pair a value. Reverse them to go border-first. Every Helix surface reads
|
|
44
|
+
both pairs, and this is checked. A surface that reads only one pair is easy to
|
|
45
|
+
miss. If it reads the shadow token and sets `border: none` directly, a theme can
|
|
46
|
+
change it in one direction and not in the other.
|
|
46
47
|
|
|
47
|
-
## The ladder
|
|
48
|
+
## The surface ladder
|
|
48
49
|
|
|
49
|
-
A surface's ground
|
|
50
|
+
A surface's ground color token names where the surface sits:
|
|
50
51
|
|
|
51
52
|
[//]: # (tokens:surface-ladder)
|
|
52
53
|
|
|
53
54
|
| Token | Sample | For |
|
|
54
55
|
| --- | --- | --- |
|
|
55
|
-
| `--helix-color-background` | <span data-token-swatch style={{ background: 'var(--helix-color-background)' }} /> | The page.
|
|
56
|
-
| `--helix-color-surface` | <span data-token-swatch style={{ background: 'var(--helix-color-surface)' }} /> | A
|
|
57
|
-
| `--helix-color-surface-raised` | <span data-token-swatch style={{ background: 'var(--helix-color-surface-raised)' }} /> |
|
|
58
|
-
| `--helix-color-surface-overlay` | <span data-token-swatch style={{ background: 'var(--helix-color-surface-overlay)' }} /> |
|
|
59
|
-
| `--helix-color-surface-sunken` | <span data-token-swatch style={{ background: 'var(--helix-color-surface-sunken)' }} /> | A
|
|
56
|
+
| `--helix-color-background` | <span data-token-swatch style={{ background: 'var(--helix-color-background)' }} /> | The page background. Every other surface sits on it. |
|
|
57
|
+
| `--helix-color-surface` | <span data-token-swatch style={{ background: 'var(--helix-color-surface)' }} /> | A surface on the page, such as a card or a panel. The separation policy sets it apart with a fill, a border, or a shadow. |
|
|
58
|
+
| `--helix-color-surface-raised` | <span data-token-swatch style={{ background: 'var(--helix-color-surface-raised)' }} /> | A raised surface on the page, such as a selected tab or a hovered row. Its fill is one step down the ramp. |
|
|
59
|
+
| `--helix-color-surface-overlay` | <span data-token-swatch style={{ background: 'var(--helix-color-surface-overlay)' }} /> | A surface over the page, such as a menu, a popover, or a dialog. Its shadow sets it apart. |
|
|
60
|
+
| `--helix-color-surface-sunken` | <span data-token-swatch style={{ background: 'var(--helix-color-surface-sunken)' }} /> | A recessed surface that holds a value, such as an input, a track, or a groove. Its fill sets it apart. |
|
|
60
61
|
|
|
61
62
|
[//]: # (/tokens)
|
|
62
63
|
|
|
63
|
-
**`raised` goes down the ramp
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
**`raised` goes one step down the ramp.** A selected tab's pill, a hovered row,
|
|
65
|
+
and an option under the pointer all have the page on every side. Only their
|
|
66
|
+
fill separates them, and on a white page a fill has to be a step darker to be
|
|
67
|
+
seen. `overlay` works the other way. Its shadow and what it covers separate it,
|
|
68
|
+
so on a white page it is white.
|
|
68
69
|
|
|
69
|
-
##
|
|
70
|
+
## Using the page color inside a component
|
|
70
71
|
|
|
71
|
-
**`--helix-color-background` is the page
|
|
72
|
+
**`--helix-color-background` is the page color. Do not use it inside a
|
|
73
|
+
component.**
|
|
72
74
|
|
|
73
75
|
```css
|
|
74
76
|
/* Wrong. Claims the component is sitting on the page. */
|
|
75
77
|
.marker { background: var(--helix-color-background); }
|
|
76
78
|
```
|
|
77
79
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
component is put on the page and no other ground. `Timeline`'s marker made it,
|
|
81
|
-
painting itself the page color to knock the rail out behind it, and came out
|
|
82
|
-
darker than any surface that was not the page: on a card it showed as a black
|
|
83
|
-
disc. The sparkline's ring terminus made the same mistake and looked identical.
|
|
80
|
+
Using the page color inside a component assumes the component sits on the page.
|
|
81
|
+
That is right only when the component is placed directly on the page.
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
`Timeline`'s marker had this mistake. It was painted the page color to hide the
|
|
84
|
+
rail behind it, so it came out darker than any surface other than the page. On a
|
|
85
|
+
card, it showed as a black disc. The sparkline's ring terminus had the same
|
|
86
|
+
mistake and looked the same.
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
Both looked correct for months, because components are usually built on the
|
|
89
|
+
page. The mistake shows on a card, a drawer, a toast, a panel, or a photograph,
|
|
90
|
+
and components are not built on any of those.
|
|
91
|
+
|
|
92
|
+
Put the color behind a hook that defaults to the page color. When the component
|
|
93
|
+
sits on another surface, the hook can be set to match. Helix requires this of
|
|
94
|
+
its own components, and the same applies to anything you build with it.
|
|
93
95
|
|
|
94
96
|
## Contrast
|
|
95
97
|
|
|
96
|
-
The theme engine measures
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
The theme engine measures each ink against the ground it is actually painted
|
|
99
|
+
on. The ladder records which pairs occur. For example, `foreground` on
|
|
100
|
+
`surface-overlay` is a real pair, and `foreground-on-accent` on `surface` is
|
|
101
|
+
not. See [Color](./color).
|
package/content/svelte.mdx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: The Svelte typings, and how Svelte passes props and binds events.
|
|
3
3
|
parent: installation
|
|
4
4
|
section: Getting started
|
|
5
5
|
title: Svelte
|
|
@@ -11,35 +11,36 @@ title: Svelte
|
|
|
11
11
|
import '@fusion.dev/helix/svelte'
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
is typed in a component
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
Add this types-only import once. It augments `SvelteHTMLElements`, so every
|
|
15
|
+
Helix tag is typed in a component. The import re-exports the JSX types. Svelte
|
|
16
|
+
binds a handler as `onhelix-before-change={…}`, which is the shape those types
|
|
17
|
+
already describe. With one shared copy of the types, the Svelte and JSX typings
|
|
18
|
+
cannot disagree.
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Pass props and bind events
|
|
21
21
|
|
|
22
22
|
```svelte
|
|
23
23
|
<helix-input label="Name" onchange={(event) => (name = event.target.value)} value={name} />
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
Svelte sets a property when the element has one and an attribute otherwise
|
|
27
|
-
binds `on*` with `addEventListener`.
|
|
28
|
-
|
|
29
|
-
because Svelte was already right about custom elements.
|
|
26
|
+
Svelte sets a property when the element has one, and an attribute otherwise. It
|
|
27
|
+
binds `on*` with `addEventListener`. Svelte shows no unknown-element warning,
|
|
28
|
+
and you do not need a compiler flag.
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
Svelte passes objects and arrays as properties on its own:
|
|
32
31
|
|
|
33
32
|
```svelte
|
|
34
33
|
<helix-tabs items={tabs} />
|
|
35
34
|
```
|
|
36
35
|
|
|
37
|
-
##
|
|
36
|
+
## Read values and refuse changes
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
convention a custom element can opt into. Read the value off the event.
|
|
38
|
+
These two rules apply in every framework.
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
`bind:` does not work on a Helix control, because custom elements have no
|
|
41
|
+
two-way binding convention to opt into. Read the value from the event.
|
|
42
|
+
|
|
43
|
+
A declared `value`, `open`, `checked`, or `active` is a seed. The element starts
|
|
44
|
+
with that value and then applies its own changes. To refuse a change, cancel the
|
|
45
|
+
matching `helix-before-*` event. Skipping a state update does not refuse it. See
|
|
46
|
+
[State and control](./state-and-control).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Enter your theme inputs and see every token Helix computes from them.
|
|
3
3
|
section: Tooling
|
|
4
4
|
title: Theme builder
|
|
5
5
|
---
|
|
@@ -8,37 +8,47 @@ title: Theme builder
|
|
|
8
8
|
|
|
9
9
|
[Open the theme builder](/helix/theme).
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
When you move a slider, every component in the preview updates. Helix computes
|
|
12
|
+
a theme from a few inputs, and the theme builder shows you the result.
|
|
13
13
|
|
|
14
|
-
## What
|
|
14
|
+
## What the theme builder shows
|
|
15
15
|
|
|
16
|
-
You
|
|
17
|
-
chroma ceiling, a radius, a density, a contrast target, a motion character. It
|
|
18
|
-
runs the real derivation, not an approximation of it, and shows you the complete
|
|
19
|
-
token set plus the library rendered in it.
|
|
16
|
+
You enter the same inputs that `derive()` takes:
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
- a brand color
|
|
19
|
+
- a chroma ceiling
|
|
20
|
+
- a radius
|
|
21
|
+
- a density
|
|
22
|
+
- a contrast target
|
|
23
|
+
- a motion character
|
|
24
|
+
|
|
25
|
+
The theme builder runs the full derivation. It shows you every token, and the
|
|
26
|
+
components drawn with them.
|
|
27
|
+
|
|
28
|
+
It shows light and dark at the same time. `[data-color-mode]` works on any
|
|
29
|
+
element, so the two previews are two subtrees of one document. See
|
|
30
|
+
[Color modes](./color-modes).
|
|
23
31
|
|
|
24
32
|
## The contrast column
|
|
25
33
|
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
The contrast column lists every color pair Helix computed. Each pair shows its
|
|
35
|
+
ratio, measured against the background it is painted on. A pair has one of
|
|
36
|
+
three states:
|
|
28
37
|
|
|
29
38
|
- **Met.** The pair reaches the target.
|
|
30
|
-
- **Unverifiable.** The
|
|
31
|
-
measure against.
|
|
32
|
-
|
|
33
|
-
- **Pinned.** You
|
|
34
|
-
|
|
39
|
+
- **Unverifiable.** The background is translucent, so there is no known color
|
|
40
|
+
to measure against. The pair neither passes nor fails. This is the cost of a
|
|
41
|
+
translucent material, and the theme builder reports it.
|
|
42
|
+
- **Pinned.** You set the color yourself. The engine did not compute it, so its
|
|
43
|
+
contrast is not guaranteed.
|
|
35
44
|
|
|
36
|
-
A
|
|
37
|
-
|
|
45
|
+
A column of `unverifiable` pairs means your theme makes a trade. The column lets
|
|
46
|
+
you see that you made it.
|
|
38
47
|
|
|
39
|
-
## What
|
|
48
|
+
## What the theme builder exports
|
|
40
49
|
|
|
41
|
-
The token block
|
|
50
|
+
The theme builder gives you the token block as CSS, to paste into your own
|
|
51
|
+
stylesheet:
|
|
42
52
|
|
|
43
53
|
```css
|
|
44
54
|
:root {
|
|
@@ -47,20 +57,21 @@ The token block, as CSS, to paste into your own stylesheet:
|
|
|
47
57
|
}
|
|
48
58
|
```
|
|
49
59
|
|
|
50
|
-
|
|
60
|
+
It also gives you the intent object, to keep in your repository and derive the
|
|
61
|
+
theme from again:
|
|
51
62
|
|
|
52
63
|
```ts
|
|
53
64
|
export const theme = { brand: '#2563eb', chroma: { ceiling: 0.1 }, radius: 2 }
|
|
54
65
|
```
|
|
55
66
|
|
|
56
|
-
**Keep the intent
|
|
57
|
-
the solver improves
|
|
58
|
-
|
|
59
|
-
it.
|
|
67
|
+
**Keep the intent object in your repository.** The tokens are the output of a
|
|
68
|
+
solver, and the solver improves. A theme stored as its inputs gets each
|
|
69
|
+
improvement. A theme stored as token values stays at the version that produced
|
|
70
|
+
it. Use the tokens only in a system that cannot run the engine.
|
|
60
71
|
|
|
61
|
-
##
|
|
72
|
+
## Limits of the theme builder
|
|
62
73
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
result
|
|
74
|
+
The theme builder shows numbers and swatches. It does not show components in
|
|
75
|
+
your product. The contrast results are a grid with three states, and a terminal
|
|
76
|
+
or a table shows that grid more clearly than a picture. The components beside
|
|
77
|
+
it are for checking the result. They are not a design tool.
|