@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
package/content/theming.mdx
CHANGED
|
@@ -1,28 +1,26 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Compute a complete token set from your brand color and a few other inputs.
|
|
3
3
|
section: Theming
|
|
4
4
|
title: Deriving a theme
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Theming
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Helix computes your color tokens from a few inputs, such as your brand color.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
When a design system ships two hundred fixed color values, you theme it by
|
|
12
|
+
changing them one at a time. A change to one value can break the contrast of a
|
|
13
|
+
component elsewhere, and nothing tells you.
|
|
14
14
|
|
|
15
|
-
`@fusion.dev/helix-theme` computes a complete token set from a
|
|
16
|
-
inputs, and every
|
|
17
|
-
construction** rather than by audit.
|
|
15
|
+
`@fusion.dev/helix-theme` computes a complete token set from a few intent
|
|
16
|
+
inputs, and every text and background pair meets its contrast target.
|
|
18
17
|
|
|
19
18
|
## Two ways to theme
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
names.
|
|
20
|
+
Helix has two ways to theme, and they give different guarantees.
|
|
23
21
|
|
|
24
|
-
**Tuned**
|
|
25
|
-
|
|
22
|
+
**Tuned** uses CSS only. Set a seed and the stylesheet recomputes the colors,
|
|
23
|
+
with nothing to install or run:
|
|
26
24
|
|
|
27
25
|
```css
|
|
28
26
|
:root {
|
|
@@ -32,19 +30,19 @@ has to be installed or run:
|
|
|
32
30
|
}
|
|
33
31
|
```
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
A `var()` inside a custom property is substituted
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
Set seeds at `:root` or on an element with `[data-helix-theme]`. A seed on any
|
|
34
|
+
other element has no effect. A `var()` inside a custom property is substituted
|
|
35
|
+
on the element where the property is *declared*, so the ramp has already
|
|
36
|
+
resolved at the root. The stylesheet declares the ramp again on each
|
|
37
|
+
`[data-helix-theme]` element, so the ramp there reads the seeds you set on it.
|
|
40
38
|
|
|
41
|
-
|
|
42
|
-
`oklch(from …)` can step and rotate,
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
Tuned does not guarantee contrast. CSS has no contrast function.
|
|
40
|
+
`oklch(from …)` can step and rotate a color, but it cannot search for the
|
|
41
|
+
lightness that meets a target. The contrast figures built into the ramp are
|
|
42
|
+
exact for the default seed and approximate for any other.
|
|
45
43
|
|
|
46
|
-
**Verified**
|
|
47
|
-
|
|
44
|
+
**Verified** uses the theme engine. It searches for each color that meets its
|
|
45
|
+
target, measures every pair, and returns the theme with any violations:
|
|
48
46
|
|
|
49
47
|
```ts
|
|
50
48
|
import { deriveTheme, toCss } from '@fusion.dev/helix-theme'
|
|
@@ -62,42 +60,50 @@ if (theme.violations.length > 0) {
|
|
|
62
60
|
console.log(toCss(theme))
|
|
63
61
|
```
|
|
64
62
|
|
|
65
|
-
The
|
|
66
|
-
engine does not
|
|
67
|
-
spacing scale and the corner radii, re-derive from the same values the solver
|
|
68
|
-
used. That is what stops the two paths disagreeing on the same page.
|
|
63
|
+
The CSS from `toCss` includes the seeds as well as the tokens. The stylesheet
|
|
64
|
+
computes the values the engine does not, from the same seeds the engine used:
|
|
69
65
|
|
|
70
|
-
|
|
66
|
+
- The twenty-four series colors for charts
|
|
67
|
+
- The spacing scale
|
|
68
|
+
- The corner radii
|
|
71
69
|
|
|
72
|
-
|
|
70
|
+
This keeps both ways of theming in agreement on the same page.
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
scale generation and contrast math unreliable. OKLCH is what makes derivation
|
|
76
|
-
possible at all. Colors are authored in it and converted at the edge.
|
|
72
|
+
Use tuned to try a color. Use verified for the theme you ship.
|
|
77
73
|
|
|
78
|
-
|
|
79
|
-
target. That is what preserves brand identity while guaranteeing contrast.
|
|
74
|
+
## Why Helix uses OKLCH
|
|
80
75
|
|
|
81
|
-
|
|
76
|
+
Equal numeric steps in sRGB do not look like equal steps. That makes scales and
|
|
77
|
+
contrast math in sRGB unreliable. Helix computes themes in OKLCH for this
|
|
78
|
+
reason. Colors are written in OKLCH and converted to other formats on output.
|
|
82
79
|
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
The engine keeps your brand color's hue and chroma and changes only its
|
|
81
|
+
lightness to meet the target. Your brand color stays recognizable, and its
|
|
82
|
+
contrast is guaranteed.
|
|
85
83
|
|
|
86
|
-
|
|
87
|
-
carrying brand tint falls outside the sRGB gamut and gets truncated on the way
|
|
88
|
-
to hex, breaking both the intended hue and the contrast just solved for. Every
|
|
89
|
-
color is gamut-fitted before it is solved against, and a token reports
|
|
90
|
-
`chromaReduced` when fitting changed it rather than clipping silently.
|
|
84
|
+
## Errors the engine prevents
|
|
91
85
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
than `background`, so light text loses contrast inside every card while the
|
|
95
|
-
page itself passes. Foregrounds are solved against the hardest surface they
|
|
96
|
-
land on, not just the page background.
|
|
86
|
+
The engine prevents two errors. Each one produces a palette that passes review
|
|
87
|
+
and fails in production. Regression tests cover both.
|
|
97
88
|
|
|
98
|
-
|
|
89
|
+
### Colors outside the sRGB gamut
|
|
99
90
|
|
|
100
|
-
|
|
91
|
+
A near-white surface with a brand tint can fall outside the sRGB gamut.
|
|
92
|
+
Converting it to hex then clips it, which changes its hue and breaks the
|
|
93
|
+
contrast the engine solved for. The engine fits every color into the gamut
|
|
94
|
+
before it solves against that color. When fitting changes a token, the token
|
|
95
|
+
reports `chromaReduced`.
|
|
96
|
+
|
|
97
|
+
### Text on more than one surface
|
|
98
|
+
|
|
99
|
+
Text appears on `surface` as often as on `background`, for example in cards,
|
|
100
|
+
dialogs, and menus. In a dark theme, `surface` is *lighter* than `background`.
|
|
101
|
+
Light text that passes on the page can lose contrast inside every card. The
|
|
102
|
+
engine solves each foreground color against the hardest surface it appears on.
|
|
103
|
+
|
|
104
|
+
## Inspect a theme
|
|
105
|
+
|
|
106
|
+
Each derived token includes the result of its contrast check:
|
|
101
107
|
|
|
102
108
|
```ts
|
|
103
109
|
const theme = deriveTheme({ brand })
|
|
@@ -107,5 +113,6 @@ for (const token of theme.tokens) {
|
|
|
107
113
|
}
|
|
108
114
|
```
|
|
109
115
|
|
|
110
|
-
`violations` is empty when the theme passes.
|
|
111
|
-
target at the requested chroma is reported
|
|
116
|
+
`violations` is empty when the theme passes. A color that cannot reach its
|
|
117
|
+
target at the requested chroma is reported in `violations`, so you can fix it
|
|
118
|
+
before you ship.
|
package/content/tiers.mdx
CHANGED
|
@@ -7,39 +7,47 @@ title: Tiers
|
|
|
7
7
|
|
|
8
8
|
# Tiers
|
|
9
9
|
|
|
10
|
-
Helix
|
|
11
|
-
|
|
10
|
+
Helix is four packages stacked on each other. Each package has one job, and each
|
|
11
|
+
depends only on the packages below it.
|
|
12
12
|
|
|
13
13
|
| Package | Owns | Depends on |
|
|
14
14
|
| --- | --- | --- |
|
|
15
15
|
| `@fusion.dev/helix-styles` | Tokens and the base layer. Pure CSS | nothing |
|
|
16
16
|
| `@fusion.dev/helix-core` | Element base class, mixins, decorators | Lit |
|
|
17
17
|
| `@fusion.dev/helix-headless` | Structure, accessibility, state, form participation | `core` |
|
|
18
|
-
| `@fusion.dev/helix` | Presentation: tokens, parts, and the visual axes | `headless`, `
|
|
18
|
+
| `@fusion.dev/helix` | Presentation: tokens, parts, and the visual axes | `headless`, `styles` |
|
|
19
19
|
|
|
20
|
-
`@fusion.dev/helix-theme` and `@fusion.dev/helix-icons` ship beside the stack
|
|
21
|
-
|
|
22
|
-
React package.** The framework typings are generated into `@fusion.dev/helix`, and
|
|
23
|
-
the bridge that repairs React's hydration of custom events is in
|
|
24
|
-
`@fusion.dev/helix-core`. See [React](./react).
|
|
20
|
+
`@fusion.dev/helix-theme` and `@fusion.dev/helix-icons` ship beside the stack.
|
|
21
|
+
Neither is a tier, and you do not need either one to render a component.
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
There is no React package. We generate the framework typings into
|
|
24
|
+
`@fusion.dev/helix`, and the bridge that repairs React's hydration of custom
|
|
25
|
+
events is in `@fusion.dev/helix-core`. See [React](./react).
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
## Why the tiers are separate packages
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
consumable. Consume it and bring your own
|
|
32
|
-
styling entirely; nothing about how Helix looks comes with it. If styling leaks
|
|
33
|
-
downward, the four are one package in four files.
|
|
29
|
+
**`headless` must never depend on `styles`.**
|
|
34
30
|
|
|
35
|
-
|
|
31
|
+
This rule lets you use the headless tier on its own. You install it and write
|
|
32
|
+
all of the styling yourself. Nothing about how Helix looks comes with it. If
|
|
33
|
+
styling moved down into the headless tier, the four packages would be one
|
|
34
|
+
package split across four files.
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
wiring, slots, events, internal state, form participation. It ships no CSS, no
|
|
39
|
-
token references, and none of the visual axes.
|
|
36
|
+
## What each tier contains
|
|
40
37
|
|
|
41
|
-
The
|
|
42
|
-
|
|
38
|
+
The headless tier owns what a component is and does:
|
|
39
|
+
|
|
40
|
+
- markup structure
|
|
41
|
+
- ARIA wiring
|
|
42
|
+
- slots
|
|
43
|
+
- events
|
|
44
|
+
- internal state
|
|
45
|
+
- form participation
|
|
46
|
+
|
|
47
|
+
It ships no CSS, no token references, and none of the visual axes.
|
|
48
|
+
|
|
49
|
+
The styled tier extends the headless tier and adds only presentation. Token
|
|
50
|
+
references live in the styled tier.
|
|
43
51
|
|
|
44
52
|
```ts
|
|
45
53
|
// headless/src/accordion/item/accordion-item.ts
|
|
@@ -77,10 +85,11 @@ export class HelixAccordion extends HelixHeadlessAccordion {
|
|
|
77
85
|
}
|
|
78
86
|
```
|
|
79
87
|
|
|
80
|
-
##
|
|
88
|
+
## Style a component from your stylesheet
|
|
81
89
|
|
|
82
|
-
|
|
83
|
-
element carries a `part`,
|
|
90
|
+
Elements inside the shadow DOM carry no class names for you to select. Each
|
|
91
|
+
structural element carries a `part`, and parts are the public API for overriding
|
|
92
|
+
styles:
|
|
84
93
|
|
|
85
94
|
```css
|
|
86
95
|
helix-accordion-item::part(trigger) {
|
|
@@ -88,9 +97,9 @@ helix-accordion-item::part(trigger) {
|
|
|
88
97
|
}
|
|
89
98
|
```
|
|
90
99
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
100
|
+
To change one value, set the component's own custom property. It defaults to a
|
|
101
|
+
system token. Setting it restyles that one component and leaves `--helix-*` and
|
|
102
|
+
every other component unchanged:
|
|
94
103
|
|
|
95
104
|
```css
|
|
96
105
|
helix-accordion {
|
|
@@ -98,16 +107,16 @@ helix-accordion {
|
|
|
98
107
|
}
|
|
99
108
|
```
|
|
100
109
|
|
|
101
|
-
##
|
|
110
|
+
## Hide elements until they upgrade
|
|
102
111
|
|
|
103
|
-
A custom element is an inline, unstyled box until its definition loads
|
|
104
|
-
light-DOM children render immediately in document order.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
112
|
+
A custom element is an inline, unstyled box until its definition loads. Its
|
|
113
|
+
light-DOM children render immediately, in document order. A card first appears
|
|
114
|
+
as unstyled text and then changes into a card. The delay is short. It is most
|
|
115
|
+
visible on a server-rendered page, where the markup arrives long before the
|
|
116
|
+
JavaScript.
|
|
108
117
|
|
|
109
|
-
`@fusion.dev/helix`
|
|
110
|
-
|
|
118
|
+
`@fusion.dev/helix` includes `elements.css`, which hides each of its tags until
|
|
119
|
+
the tag's definition loads:
|
|
111
120
|
|
|
112
121
|
```css
|
|
113
122
|
helix-card:not(:defined) {
|
|
@@ -115,22 +124,22 @@ helix-card:not(:defined) {
|
|
|
115
124
|
}
|
|
116
125
|
```
|
|
117
126
|
|
|
118
|
-
**The base tier ships no such file
|
|
119
|
-
|
|
127
|
+
**The base tier ships no such file on purpose.** There are three reasons, and
|
|
128
|
+
the third one affects you most.
|
|
120
129
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
130
|
+
First, hiding an element is a design choice. Below the styled tier, we ship only
|
|
131
|
+
the rules a component cannot work without. For example, `overflow` creates a
|
|
132
|
+
scrollport, and `[hidden]` is the platform's own semantics. Hiding an element
|
|
133
|
+
that has not upgraded is a choice between two imperfect first frames. The
|
|
134
|
+
content is in the markup either way, so a crawler reads it in both cases.
|
|
126
135
|
|
|
127
|
-
|
|
128
|
-
because
|
|
129
|
-
live in your stylesheet,
|
|
136
|
+
Second, the rule belongs to the document. A component cannot apply it from
|
|
137
|
+
inside, because there is no shadow root before the upgrade. The rule has to
|
|
138
|
+
live in your stylesheet, so the choice is yours.
|
|
130
139
|
|
|
131
|
-
|
|
132
|
-
base elements you use,
|
|
133
|
-
|
|
140
|
+
Third, one file for every tag would not fit your project. You import only the
|
|
141
|
+
base elements you use, so a generated list would include tags you never ship.
|
|
142
|
+
Write the rule for the elements you have:
|
|
134
143
|
|
|
135
144
|
```css
|
|
136
145
|
helix-base-accordion:not(:defined),
|
|
@@ -139,21 +148,20 @@ helix-base-dialog:not(:defined) {
|
|
|
139
148
|
}
|
|
140
149
|
```
|
|
141
150
|
|
|
142
|
-
`visibility`
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
151
|
+
Use `visibility` so the element keeps its place in the layout and the page does
|
|
152
|
+
not reflow when it upgrades. `display: none` collapses the box, and the content
|
|
153
|
+
jumps in when the definition arrives. That replaces a flash of unstyled text
|
|
154
|
+
with a shift of everything below it.
|
|
146
155
|
|
|
147
|
-
You may want
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
made for you.
|
|
156
|
+
You may want to hide nothing. If your first paint matters more than the final
|
|
157
|
+
layout, or your page has to be readable with JavaScript turned off, let the
|
|
158
|
+
unstyled markup show. Because of that choice, we do not write the file for you.
|
|
151
159
|
|
|
152
160
|
## Mixins and tooling
|
|
153
161
|
|
|
154
|
-
`open` and `defaultOpen` come from `MixinControllerOpen` in
|
|
155
|
-
The manifest analyzer cannot follow a mixin into
|
|
156
|
-
|
|
157
|
-
itself with `@event`, `@property`, or similar.
|
|
158
|
-
|
|
159
|
-
the manifest.
|
|
162
|
+
`open` and `defaultOpen` come from `MixinControllerOpen` in
|
|
163
|
+
`@fusion.dev/helix-core`. The manifest analyzer cannot follow a mixin into
|
|
164
|
+
another package. Document any API that a component gets from a mixin on the
|
|
165
|
+
component itself, with `@event`, `@property`, or a similar tag. Mixin API
|
|
166
|
+
without that documentation is missing from IDE tooltips, from the React wrapper
|
|
167
|
+
generator, and from the manifest that agents read.
|
package/content/tokens.mdx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: The two layers, the surface
|
|
2
|
+
description: The two token layers, the surface tokens, and the rules the build enforces.
|
|
3
3
|
pinned: true
|
|
4
4
|
section: Theming
|
|
5
5
|
title: Tokens
|
|
@@ -7,45 +7,59 @@ title: Tokens
|
|
|
7
7
|
|
|
8
8
|
# Tokens
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Helix has two layers of tokens. You use the second layer, the semantic tokens.
|
|
11
11
|
|
|
12
12
|
| Layer | Shape | Who may use it |
|
|
13
13
|
|---|---|---|
|
|
14
14
|
| Primitive | `--_helix-neutral-500` | `@fusion.dev/helix-styles` only |
|
|
15
|
-
| Semantic | `--helix-color-primary` |
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
15
|
+
| Semantic | `--helix-color-primary` | Any code, including yours |
|
|
16
|
+
|
|
17
|
+
Each semantic token is named for its purpose. The name does not describe its
|
|
18
|
+
value. Every token belongs to exactly one of fifteen categories:
|
|
19
|
+
|
|
20
|
+
- `color`
|
|
21
|
+
- `space`
|
|
22
|
+
- `radii`
|
|
23
|
+
- `font`
|
|
24
|
+
- `text`
|
|
25
|
+
- `weight`
|
|
26
|
+
- `leading`
|
|
27
|
+
- `tracking`
|
|
28
|
+
- `border`
|
|
29
|
+
- `shadow`
|
|
30
|
+
- `material`
|
|
31
|
+
- `duration`
|
|
32
|
+
- `easing`
|
|
33
|
+
- `size`
|
|
34
|
+
- `layer`
|
|
35
|
+
|
|
36
|
+
The leading underscore marks a token as private. We may rename or re-space any
|
|
37
|
+
`--_helix-` token without notice. Code that uses a primitive token can break
|
|
38
|
+
when you update Helix, so use the semantic tokens.
|
|
39
|
+
|
|
40
|
+
## Surface tokens
|
|
41
|
+
|
|
42
|
+
A surface's depth is its distance from the page, in whichever direction has
|
|
43
|
+
room. The page is white in light mode and black in dark mode. In light mode
|
|
44
|
+
nothing is lighter than white, so a raised surface is *darker* than the page.
|
|
31
45
|
|
|
32
46
|
- **`background`**: the page.
|
|
33
|
-
- **`surface`**: a plane on the page
|
|
34
|
-
- **`surface-raised`**: something lifted
|
|
35
|
-
selected tab's pill, a hovered row, an option under the pointer.
|
|
36
|
-
|
|
37
|
-
step darker.
|
|
38
|
-
- **`surface-overlay`**: something *over* the page
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
- **`surface-sunken`**: a well
|
|
42
|
-
groove.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
- **`surface`**: a plane on the page, such as a card or a panel you own.
|
|
48
|
+
- **`surface-raised`**: something lifted that still *lies on* the page, such as
|
|
49
|
+
a selected tab's pill, a hovered row, or an option under the pointer. The page
|
|
50
|
+
surrounds it on all sides, so its fill sets it apart. On a white page, that
|
|
51
|
+
fill is one step darker.
|
|
52
|
+
- **`surface-overlay`**: something *over* the page, such as a menu, a popover, a
|
|
53
|
+
dialog, or the thumb of a switch or a segmented control. Its shadow and the
|
|
54
|
+
content it covers set it apart, so on a white page it is white.
|
|
55
|
+
- **`surface-sunken`**: a well that holds a value, such as an input's fill, a
|
|
56
|
+
track, or a groove.
|
|
57
|
+
|
|
58
|
+
**Use `raised` and `overlay` for different jobs.** They are the same color in
|
|
59
|
+
dark mode, so one token can seem to do both jobs. In light mode they need
|
|
60
|
+
opposite fills. A hovered row must be darker than a white page, and a thumb must
|
|
61
|
+
be lighter than the groove it sits in. If a surface looks almost right in dark
|
|
62
|
+
mode and wrong in light mode, it usually uses the wrong one of these two tokens.
|
|
49
63
|
|
|
50
64
|
## Per-component hooks
|
|
51
65
|
|
|
@@ -55,34 +69,39 @@ helix-card {
|
|
|
55
69
|
}
|
|
56
70
|
```
|
|
57
71
|
|
|
58
|
-
`--card-padding` is
|
|
59
|
-
|
|
60
|
-
|
|
72
|
+
`--card-padding` is a hook that the card component exposes. Hooks are separate
|
|
73
|
+
from the Helix tokens. Each component documents its own hooks, and each hook
|
|
74
|
+
defaults to a semantic token. Use a hook to adjust one component. Use the
|
|
75
|
+
semantic tokens to change every component.
|
|
61
76
|
|
|
62
|
-
## What
|
|
77
|
+
## What fails the build
|
|
63
78
|
|
|
64
|
-
|
|
79
|
+
The build fails on four kinds of error:
|
|
65
80
|
|
|
66
|
-
1.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
81
|
+
1. A raw value where a token exists, such as `#e5e5e5` where a neutral token
|
|
82
|
+
fits.
|
|
83
|
+
2. A primitive token used outside `@fusion.dev/helix-styles`.
|
|
84
|
+
3. A reference to a token that does not exist.
|
|
85
|
+
4. A component hook that nothing reads, or a primitive token that nothing
|
|
86
|
+
resolves to.
|
|
70
87
|
|
|
71
|
-
The third
|
|
72
|
-
|
|
73
|
-
|
|
88
|
+
The third check would be worth running on its own. When a token is renamed, a
|
|
89
|
+
reference to the old name resolves to nothing. The property falls back to a
|
|
90
|
+
browser default without a warning. The code looks correct, and the component
|
|
91
|
+
loses its styles.
|
|
74
92
|
|
|
75
|
-
##
|
|
93
|
+
## Color modes
|
|
76
94
|
|
|
77
|
-
|
|
95
|
+
Each token declares its light and dark values in one declaration:
|
|
78
96
|
|
|
79
97
|
```css
|
|
80
98
|
--helix-color-surface: light-dark(var(--_helix-neutral-50), var(--_helix-neutral-900));
|
|
81
99
|
```
|
|
82
100
|
|
|
83
|
-
|
|
84
|
-
mode
|
|
85
|
-
`data-color-mode="light"` or `"dark"` on any element to
|
|
86
|
-
`color-scheme` inherits, so
|
|
101
|
+
The `color-scheme` property alone decides which value applies. You set the
|
|
102
|
+
color mode with one attribute, and no token is declared twice. Set
|
|
103
|
+
`data-color-mode="light"` or `"dark"` on any element to set the mode for that
|
|
104
|
+
element and everything inside it. `color-scheme` inherits, so one attribute
|
|
105
|
+
shows a light preview inside a dark page.
|
|
87
106
|
|
|
88
|
-
|
|
107
|
+
Without the attribute, the mode follows the operating system.
|