@fusion.dev/helix-docs 0.104.0 → 0.105.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 +222 -0
- package/content/metrics.mdx +294 -297
- 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 +3337 -2680
- package/package.json +3 -3
package/content/routing.mdx
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Make components navigate with real anchors, and use your framework's router with them.
|
|
3
3
|
section: Essentials
|
|
4
4
|
title: Routing and navigation
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Routing and navigation
|
|
8
8
|
|
|
9
|
-
Some components navigate
|
|
10
|
-
|
|
11
|
-
inside a shadow root
|
|
9
|
+
Some components navigate, such as a tree used as a sidebar, a button that opens
|
|
10
|
+
another page, or a tab that is a page. Each of these should be a link. A
|
|
11
|
+
framework router does not handle a link inside a shadow root the way it handles
|
|
12
|
+
its own links.
|
|
12
13
|
|
|
13
14
|
## A component that navigates renders its own anchor
|
|
14
15
|
|
|
15
|
-
`Tree.Item` and `Button` both take an `href
|
|
16
|
-
|
|
16
|
+
`Tree.Item` and `Button` both take an `href`. With an `href`, the element you
|
|
17
|
+
press *is* an `<a>`:
|
|
17
18
|
|
|
18
19
|
```html
|
|
19
20
|
<helix-tree-item
|
|
@@ -24,31 +25,31 @@ you press *is* an `<a>`:
|
|
|
24
25
|
</helix-tree-item>
|
|
25
26
|
```
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
amount of JavaScript reproduces:
|
|
28
|
+
A real anchor gives you behavior that JavaScript cannot reproduce:
|
|
29
29
|
|
|
30
|
-
-
|
|
31
|
-
- Enter works, because a focused anchor
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
30
|
+
- The whole row is the target, including the space around the words.
|
|
31
|
+
- Enter works, because Enter activates a focused anchor.
|
|
32
|
+
- Middle-click and Command-click open a new tab.
|
|
33
|
+
- The destination appears in the status bar on hover.
|
|
34
|
+
- Right-click offers Copy Link Address.
|
|
35
|
+
- A crawler follows it.
|
|
36
36
|
|
|
37
|
-
A `<Link>` inside each row
|
|
38
|
-
57px of a 240px row, so
|
|
39
|
-
nothing at all
|
|
37
|
+
A `<Link>` inside each row gives you none of these. In our docs sidebar, the
|
|
38
|
+
anchor was 57px of a 240px row, so about three quarters of every row did nothing. Enter
|
|
39
|
+
did nothing at all, because the tree reported a selection and no anchor
|
|
40
|
+
received it.
|
|
40
41
|
|
|
41
42
|
## `href` and a framework's `<Link>`
|
|
42
43
|
|
|
43
44
|
You cannot give a component's internal anchor to `next/link`. `<Link>` renders
|
|
44
|
-
*its own* `<a>` and attaches its own handlers to it
|
|
45
|
-
|
|
45
|
+
*its own* `<a>` and attaches its own handlers to it. An element that renders an
|
|
46
|
+
anchor inside a shadow root cannot receive those handlers.
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
Choose one: an `href` on the component, or a `<Link>`.
|
|
48
49
|
|
|
49
|
-
##
|
|
50
|
+
## Do not wrap a component in a `<Link>`
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
Wrapping a component in a `<Link>` only partly works:
|
|
52
53
|
|
|
53
54
|
```tsx
|
|
54
55
|
{/* Don't. */}
|
|
@@ -58,23 +59,25 @@ It looks like it should work, and it half does:
|
|
|
58
59
|
```
|
|
59
60
|
|
|
60
61
|
The tree still finds its items, because it collects them with a descendant
|
|
61
|
-
query
|
|
62
|
+
query. The wrapper causes three problems:
|
|
62
63
|
|
|
63
|
-
- **Two focus stops per row.** The anchor
|
|
64
|
-
inside it. A tree
|
|
65
|
-
does not control.
|
|
66
|
-
- **A `treeitem` nested inside a `link`.** Anything
|
|
67
|
-
both, in that order, for one
|
|
68
|
-
- **
|
|
69
|
-
|
|
70
|
-
and browsers rearrange
|
|
64
|
+
- **Two focus stops per row.** The anchor can take focus, and so can the
|
|
65
|
+
treeitem inside it. A tree has a single roving tab stop, and the anchor adds a
|
|
66
|
+
second one that the tree does not control.
|
|
67
|
+
- **A `treeitem` nested inside a `link`.** Anything that reads the semantics
|
|
68
|
+
finds both roles, in that order, for one item.
|
|
69
|
+
- **Invalid markup for a branch.** A branch contains its children, so wrapping a
|
|
70
|
+
branch puts every descendant anchor inside an ancestor anchor. Nested anchors
|
|
71
|
+
are invalid, and browsers rearrange them.
|
|
71
72
|
|
|
72
73
|
## Some roles cannot contain a link
|
|
73
74
|
|
|
74
|
-
`treeitem` and `tab` are the two
|
|
75
|
-
|
|
75
|
+
In Helix, `treeitem` and `tab` are the two roles that cannot contain a link. You
|
|
76
|
+
cannot nest an anchor in either role. A tree keeps the anchor and changes its
|
|
77
|
+
markup.
|
|
76
78
|
|
|
77
|
-
For a tree, the role moves *onto* the anchor and the group becomes
|
|
79
|
+
For a tree, the role moves *onto* the anchor, and the group becomes the
|
|
80
|
+
anchor's sibling:
|
|
78
81
|
|
|
79
82
|
```html
|
|
80
83
|
<!-- What Tree.Item renders when it has an href -->
|
|
@@ -95,20 +98,20 @@ For a tree, the role moves *onto* the anchor and the group becomes its sibling:
|
|
|
95
98
|
</div>
|
|
96
99
|
```
|
|
97
100
|
|
|
98
|
-
|
|
99
|
-
the
|
|
100
|
-
nothing moves
|
|
101
|
-
|
|
101
|
+
This markup is the navigation form of the tree pattern. For that reason, `href`
|
|
102
|
+
changes the structure of the markup as well as adding an attribute. Without an
|
|
103
|
+
`href`, nothing moves. The wrapper stays the `treeitem` and contains its group,
|
|
104
|
+
the same way an `<li>` contains a `<ul>`.
|
|
102
105
|
|
|
103
|
-
Tabs have no equivalent published pattern. Web Awesome
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
Tabs have no equivalent published pattern. Web Awesome has the same problem. Its
|
|
107
|
+
answer is to drop the anchor and navigate in JavaScript. That works, and you
|
|
108
|
+
lose every item in the list above.
|
|
106
109
|
|
|
107
|
-
##
|
|
110
|
+
## Use client-side routing with real anchors
|
|
108
111
|
|
|
109
|
-
|
|
110
|
-
rendered itself.
|
|
111
|
-
|
|
112
|
+
A real anchor causes a full page load, because a framework intercepts only the
|
|
113
|
+
anchors it rendered itself. To use the framework's router, add it on top of the
|
|
114
|
+
anchors:
|
|
112
115
|
|
|
113
116
|
```tsx
|
|
114
117
|
'use client'
|
|
@@ -135,14 +138,14 @@ const navigate = (event) => {
|
|
|
135
138
|
return <nav onClick={navigate} onPointerOver={warm}>{/* … */}</nav>
|
|
136
139
|
```
|
|
137
140
|
|
|
138
|
-
One listener on the container
|
|
139
|
-
rows
|
|
141
|
+
One listener on the container handles every row. You do not need to add
|
|
142
|
+
listeners again as rows are added and removed.
|
|
140
143
|
|
|
141
|
-
### Prefetch
|
|
144
|
+
### Prefetch when the pointer or focus reaches a link
|
|
142
145
|
|
|
143
|
-
`<Link>` prefetches when a link enters the viewport.
|
|
144
|
-
that is seventy requests for one navigation.
|
|
145
|
-
`focus`
|
|
146
|
+
`<Link>` prefetches when a link enters the viewport. In a sidebar of seventy
|
|
147
|
+
links, that is seventy requests for one navigation. Prefetch on `pointerover`
|
|
148
|
+
and `focus` to make one request. People point at a row well before they press
|
|
146
149
|
it:
|
|
147
150
|
|
|
148
151
|
```tsx
|
|
@@ -156,10 +159,10 @@ const warm = (event) => {
|
|
|
156
159
|
}
|
|
157
160
|
```
|
|
158
161
|
|
|
159
|
-
|
|
160
|
-
is
|
|
162
|
+
Next prefetches only in production, so this code has no effect in development.
|
|
163
|
+
That is expected.
|
|
161
164
|
|
|
162
|
-
##
|
|
165
|
+
## Components that take an `href`
|
|
163
166
|
|
|
164
167
|
| Component | Notes |
|
|
165
168
|
|---|---|
|
|
@@ -167,42 +170,46 @@ is not broken.
|
|
|
167
170
|
| `Tree.Item` | Changes the ARIA shape, as above. A linked branch navigates from its row and opens from its chevron. |
|
|
168
171
|
| `Menu.Item` | The row becomes the anchor and carries `menuitem`. Takes `target`, `rel` and `download`. |
|
|
169
172
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
the row
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
it.
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
not cross shadow boundaries
|
|
189
|
-
form.
|
|
190
|
-
inside a *sibling* shadow root reads
|
|
191
|
-
|
|
192
|
-
host is the only element the
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
173
|
+
Other components that should navigate do not take an `href` yet. To make one
|
|
174
|
+
navigate, slot a link into it. `Tree.Item` follows a slotted anchor when you
|
|
175
|
+
press anywhere in the row or use the keyboard, so a tree item can navigate
|
|
176
|
+
without an `href`.
|
|
177
|
+
|
|
178
|
+
## `Option` cannot take an `href`
|
|
179
|
+
|
|
180
|
+
A command palette is a common place to want links in a list, because its
|
|
181
|
+
entries are often half commands and half destinations. It is the one place
|
|
182
|
+
where Helix cannot offer an `href`.
|
|
183
|
+
|
|
184
|
+
A listbox cannot move focus to its options. A combobox keeps focus in its text
|
|
185
|
+
field while the arrow keys move through the list, so it has to use
|
|
186
|
+
`aria-activedescendant`. Focus stays in the field, and an attribute marks the
|
|
187
|
+
current option. A menu works the other way, which makes `Menu.Item` simple.
|
|
188
|
+
Focus moves to the row, so the row can be an anchor with `menuitem` on it.
|
|
189
|
+
|
|
190
|
+
The `aria-activedescendant` reference reaches the option's host and nothing
|
|
191
|
+
inside it. IDREFs do not cross shadow boundaries, so `Listbox` uses the
|
|
192
|
+
element-reference form. We measured this in Chromium. Assigning
|
|
193
|
+
`ariaActiveDescendantElement` an element inside a *sibling* shadow root reads
|
|
194
|
+
back `null`. Assigning the option's host reads back the host. So
|
|
195
|
+
`role="option"` stays on the host, because the host is the only element the
|
|
196
|
+
listbox can point at.
|
|
197
|
+
|
|
198
|
+
A `role="option"` with an anchor inside it is also broken. In the same browser,
|
|
199
|
+
the accessibility tree for `<div role="option"><a href>Open
|
|
200
|
+
settings</a></div>` inside a listbox shows an option with *no accessible name*,
|
|
201
|
+
with the link as its child. A sibling option with plain text has the correct
|
|
202
|
+
name. Moving the role onto the anchor works for `treeitem` and `menuitem`, and
|
|
203
|
+
it cannot work here.
|
|
204
|
+
|
|
205
|
+
No arrangement of the markup meets both of these constraints.
|
|
206
|
+
|
|
207
|
+
**In a command palette, navigate from the `helix-select` event.** Listen for
|
|
208
|
+
`helix-select` on `helix-command` and call your router. A palette entry is a
|
|
209
|
+
command, and "go to Settings" is a command that navigates. Command palettes in
|
|
210
|
+
other applications work the same way. You lose the gestures that only a real
|
|
211
|
+
anchor has:
|
|
212
|
+
|
|
213
|
+
- middle-click
|
|
214
|
+
- a modified click
|
|
215
|
+
- the destination in the status bar
|
package/content/sandbox.mdx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: The
|
|
2
|
+
description: The editable examples on each component page, and what you need to build an editor of your own.
|
|
3
3
|
section: Tooling
|
|
4
4
|
title: Sandbox
|
|
5
5
|
---
|
|
@@ -8,39 +8,38 @@ title: Sandbox
|
|
|
8
8
|
|
|
9
9
|
[Open the sandbox](/helix/sandbox).
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
preview redraws
|
|
11
|
+
You can edit every example on a component's page. When you change the markup,
|
|
12
|
+
the preview redraws. When you change the stylesheet beside it, the preview
|
|
13
|
+
restyles.
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
To build a playground of your own, you would use the same elements. The
|
|
16
|
+
isolation described below makes it safe to run markup that someone else wrote.
|
|
16
17
|
|
|
17
|
-
##
|
|
18
|
+
## How the preview is isolated
|
|
18
19
|
|
|
19
|
-
The preview runs in a sandboxed iframe with an opaque origin
|
|
20
|
-
|
|
21
|
-
route.
|
|
20
|
+
The preview runs in a sandboxed iframe with an opaque origin. The script that
|
|
21
|
+
drives it is a static classic script, served as a file. No route renders it.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
could. Measured.
|
|
23
|
+
Markup you type into the sandbox runs in the frame. An `<img onerror>` in it
|
|
24
|
+
cannot read the cookies or `localStorage` of the page around it, or the editor's
|
|
25
|
+
contents. Before we isolated the frame, it could. We measured both.
|
|
27
26
|
|
|
28
|
-
The classic script is
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
The classic script is required for the isolation to work. From an opaque origin,
|
|
28
|
+
a module import or a `fetch` back to the site's origin is cross-origin, and it
|
|
29
|
+
fails without CORS headers. A classic `<script src>` is not CORS-checked. It is
|
|
30
|
+
the only way to load the component library into a document that the page cannot
|
|
31
|
+
reach into and that cannot reach back out.
|
|
33
32
|
|
|
34
|
-
##
|
|
33
|
+
## How the source panes and the preview communicate
|
|
35
34
|
|
|
36
|
-
A source pane dispatches `helix-before-edit`, which bubbles
|
|
37
|
-
the value to
|
|
38
|
-
|
|
35
|
+
A source pane dispatches `helix-before-edit`, which bubbles. The sandbox passes
|
|
36
|
+
the value to the preview slotted into it. The source pane and the preview do not
|
|
37
|
+
reference each other, so you can replace either one or use it alone.
|
|
39
38
|
|
|
40
|
-
The event
|
|
41
|
-
|
|
42
|
-
markup and `css`
|
|
43
|
-
|
|
39
|
+
The event includes the pane's `name`, so one sandbox can hold several panes
|
|
40
|
+
without tracking which element sent each event. A pane named `html` sets the
|
|
41
|
+
preview's markup, and a pane named `css` sets its stylesheet. The sandbox
|
|
42
|
+
ignores a pane with any other name, so that pane only displays its contents.
|
|
44
43
|
|
|
45
44
|
```html
|
|
46
45
|
<helix-sandbox>
|
|
@@ -56,21 +55,22 @@ something rather than driving it, and is ignored.
|
|
|
56
55
|
</helix-sandbox>
|
|
57
56
|
```
|
|
58
57
|
|
|
59
|
-
##
|
|
58
|
+
## Console output from the example
|
|
60
59
|
|
|
61
|
-
Logs from the example
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
nothing else.
|
|
60
|
+
Logs from the example appear in the console panel. Logs from the page around it
|
|
61
|
+
do not. We patch the console inside the frame on purpose, so the panel shows
|
|
62
|
+
what the example logs and nothing else.
|
|
65
63
|
|
|
66
64
|
## The package is private
|
|
67
65
|
|
|
68
|
-
`@fusion.dev/helix-sandbox`
|
|
69
|
-
repository, and it is Helix tooling
|
|
70
|
-
assume the frame, the frame assumes the build, and the build assumes this
|
|
71
|
-
repository's layout.
|
|
66
|
+
`@fusion.dev/helix-sandbox` is not published. It is the editor and spec runner
|
|
67
|
+
for this repository, and it is Helix tooling. It depends on the repository:
|
|
72
68
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
69
|
+
- The elements depend on the frame.
|
|
70
|
+
- The frame depends on the build.
|
|
71
|
+
- The build depends on this repository's layout.
|
|
72
|
+
|
|
73
|
+
To add editable examples to your own documentation today, you would build the
|
|
74
|
+
editor yourself, from the manifest and the `.examples` files. This is a gap we
|
|
75
|
+
have not filled, and we have no policy against filling it. Tell us if you need
|
|
76
|
+
it.
|