@fusion.dev/helix-docs 0.142.1 → 0.143.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.
@@ -18,10 +18,11 @@ accessible only when you also handle your parts.
18
18
  Every component implements the keyboard pattern for its role. You do not write
19
19
  any of it:
20
20
 
21
- - Arrow keys move within `Tabs`, `Listbox`, and `Menu`.
21
+ - Arrow keys move within `Tabs`, `Listbox`, `Menu`, `Select`, `Combobox`, and
22
+ the days of a date picker.
22
23
  - `Escape` closes an overlay.
23
24
  - `Home` and `End` go to the first and last item.
24
- - Typing jumps to a matching item.
25
+ - In `Listbox`, `Select`, `Menu`, and `Tree`, typing jumps to a matching item.
25
26
 
26
27
  ### Focus
27
28
 
@@ -106,11 +107,24 @@ and is read where it sits. Neither component is a variant of the other.
106
107
 
107
108
  `aria-labelledby` and `aria-describedby` inside a shadow root cannot point to an
108
109
  id in your document. The browser drops the reference silently and reports no
109
- error. For this reason, every control renders its own label, and connecting two
110
- components by id does not work. See [Forms and validation](./forms).
111
-
112
- A `<label for>` in your markup cannot reach into a shadow root either, so it
113
- does not name a Helix control. Use the control's own `label`.
110
+ error. For this reason, every control renders its own label. See
111
+ [Forms and validation](./forms).
112
+
113
+ **What you write on the host reaches the control inside it.** The form controls,
114
+ `Button`, and `IconButton` carry these down to the element a screen reader is on:
115
+
116
+ - `aria-labelledby` and `aria-describedby`, as element references, so the ids
117
+ you name in your document resolve.
118
+ - A `<label for>` that points at the host, or a `<label>` around it, when the
119
+ control has no `label` of its own.
120
+ - `aria-expanded`, `aria-haspopup`, `aria-controls`, `aria-invalid`, and
121
+ `aria-pressed`.
122
+ - `aria-label` on `Button`, `IconButton`, and `Switch`. A field renders its
123
+ `aria-label` as a hidden label.
124
+
125
+ A `<label>` around a control also reads the words inside the control, such as
126
+ the names of its buttons. Use `<label for>` or the control's own `label` to name
127
+ it with your words alone.
114
128
 
115
129
  When a relationship has to cross the boundary, the components use
116
130
  `ElementInternals` and element-reference properties. They are the only mechanism
@@ -39,8 +39,8 @@ customElements.define('acme-combobox', AcmeCombobox)
39
39
  ```
40
40
 
41
41
  That one line sets the prefix. The styled tier sets its prefix the same way, with
42
- `static override tier = 'helix-'` and nothing else. The static appears 116 times
43
- in the headless manifest, so you can find it there.
42
+ `static override tier = 'helix-'` and nothing else. Every element in the
43
+ headless manifest carries the static, so you can find it there.
44
44
 
45
45
  ## Register every component a component renders
46
46
 
@@ -108,24 +108,26 @@ Use `visibility` so the page does not reflow when the definitions arrive.
108
108
 
109
109
  ### Typings for your tags
110
110
 
111
- `@fusion.dev/helix-cem` is the generator we use for our own typings. It reads
112
- your package and writes `jsx.d.ts`, `vue.d.ts`, and `svelte.d.ts` for your tags,
113
- with every member your subclasses inherit from ours. Add a `cem.config.ts`
114
- beside your `package.json`:
111
+ Your typings come from a manifest of your package. `helix manifest build`, in
112
+ `@fusion.dev/helix-cli`, writes one that includes every member your subclasses
113
+ inherit from ours. Name each Helix package you extend and where its manifest is:
115
114
 
116
- ```ts
117
- import type { HelixCemOptions } from '@fusion.dev/helix-cem'
118
-
119
- export default {
120
- frameworkTypes: true,
121
- packageName: 'acme-system',
122
- tier: 'styled',
123
- } satisfies HelixCemOptions
115
+ ```sh
116
+ helix manifest build . --tier styled \
117
+ --dependency @fusion.dev/helix=node_modules/@fusion.dev/helix/custom-elements.json \
118
+ --dependency @fusion.dev/helix-headless=node_modules/@fusion.dev/helix-headless/custom-elements.json \
119
+ --dependency @fusion.dev/helix-core=node_modules/@fusion.dev/helix-core/custom-elements.json \
120
+ > custom-elements.json
124
121
  ```
125
122
 
126
- Then run `bun --bun helix-cem`. It finds the classes you extend through your
127
- `dependencies`. The typings for `acme-combobox` then include the hundred or so
128
- members it inherits, as well as the two you wrote.
123
+ Then run a typings generator over it. Our own typings start from
124
+ `@wc-toolkit/jsx-types` and `@wc-toolkit/vuejs-types`. The typings for
125
+ `acme-combobox` then include the hundred or so members it inherits, as well as
126
+ the two you wrote.
127
+
128
+ `@fusion.dev/helix-cem`, the step that runs those generators for our packages
129
+ and corrects what they write, is not published. It is build tooling for this
130
+ repository.
129
131
 
130
132
  ### The tag map
131
133
 
@@ -84,6 +84,32 @@ table should not be seen, hide it visually, and the data is still there:
84
84
  The table's caption becomes the chart's accessible name unless you set `label`.
85
85
  The caption usually has the right words already.
86
86
 
87
+ Each chart writes a short summary for screen readers, which starts with that
88
+ name. The drawing is hidden from screen readers, and the summary gives the one
89
+ reading a chart is usually read for:
90
+
91
+ - `Bar Chart`: each series' highest reading.
92
+ - `Line Chart`: each series' latest reading.
93
+ - `Area Chart`: the latest total and each part's share of it.
94
+ - `Donut Chart`: each slice's share of the whole.
95
+ - `Scatter Chart`: each series' number of points and how strongly the two
96
+ measures relate.
97
+
98
+ `Heatmap` is an image with that name. `Sparkline` takes a `label` of its own.
99
+
100
+ ## Tables that change
101
+
102
+ A chart follows its table. It redraws when you edit a cell, add a row, or
103
+ replace the table with a new one under the same id. It also draws a table that
104
+ arrives after the chart does, such as one a framework renders once its data
105
+ loads.
106
+
107
+ A blank cell, or one that does not hold a number, is a gap in its series. The
108
+ row keeps its place on the axis, a line breaks at the gap, a bar chart draws no
109
+ bar there, and a heatmap draws the cell with no tone. The readings after the gap
110
+ stay under their own labels, and the tooltip for that row still shows the
111
+ row's cells.
112
+
87
113
  ## Series colors
88
114
 
89
115
  Helix has twenty-four series color tokens, in order, from
package/content/color.mdx CHANGED
@@ -6,8 +6,8 @@ title: Color
6
6
 
7
7
  # Color
8
8
 
9
- Seventy-four of the library's 185 tokens are colors, and they make up most of a
10
- theme. Each color token is named for its role. No token is named for how it
9
+ Colors are the largest group of the library's tokens, and they make up most of
10
+ a theme. Each color token is named for its role. No token is named for how it
11
11
  looks, because a name like `--brand-blue-500` becomes wrong as soon as you change
12
12
  the theme.
13
13
 
@@ -66,11 +66,18 @@ for a slot of the same name. Helix never renders both.
66
66
 
67
67
  ```html
68
68
  <!-- The property -->
69
- <helix-tooltip content="Save"></helix-tooltip>
69
+ <helix-tooltip
70
+ content="Save"
71
+ for="save"
72
+ id="save-tip"
73
+ ></helix-tooltip>
70
74
 
71
75
  <!-- The slot, which replaces it -->
72
- <helix-tooltip>
73
- <strong>Save</strong>, or press <helix-kbd>⌘S</helix-kbd>
76
+ <helix-tooltip
77
+ for="save"
78
+ id="save-tip"
79
+ >
80
+ <span slot="content"><strong>Save</strong>, or press <helix-kbd>⌘S</helix-kbd></span>
74
81
  </helix-tooltip>
75
82
  ```
76
83
 
@@ -84,8 +91,9 @@ examples put the closing tag on the same line as the opening tag.
84
91
 
85
92
  ## Set a button's width with the layout
86
93
 
87
- A button has no `width` or `fill` property, for the same reason it has no `size`
88
- property. How wide a control is depends on the region it is in.
94
+ A button has no `fill` property and no `size` property. How wide a control is
95
+ depends on the region it is in. `width="full"` fills the row a button sits in,
96
+ and the layout decides everything else.
89
97
 
90
98
  A button already stretches in a column flex or a grid, because a stretch-aligned
91
99
  parent stretches its children:
@@ -163,8 +171,8 @@ and then a second attribute to hide it is the same as having no visible label.
163
171
 
164
172
  `Option`, `Listbox`, and `Select` are three families so that the keyboard
165
173
  handling, the filtering, the multi-select rules, and the active-item tracking
166
- are written once. `Select` renders a `Listbox` internally. A future combobox
167
- will too, and so would a command palette.
174
+ are written once. `Select` renders a `Listbox` internally, and so does `Combobox`. A command
175
+ palette would too.
168
176
 
169
177
  For the same reason, we wrote `DrilldownController`. Since it was first written,
170
178
  `Menu` had held a page stack and derived its rows, and none of that code
@@ -105,6 +105,10 @@ against a dispatch, so every event you can listen for is documented.
105
105
  | `helix-before-change` | A value is about to change, cancelable |
106
106
  | `helix-before-toggle` | A checked state is about to flip, cancelable |
107
107
  | `helix-before-open`, `helix-before-close` | An open state is about to change, cancelable |
108
+ | `helix-before-activate`, `helix-activate` | A set is about to make a different child current, cancelable, and then did |
109
+ | `helix-before-pin`, `helix-pin` | A chat transcript is about to be pinned to the bottom or let go of it, cancelable, and then was |
110
+ | `helix-before-resize`, `helix-resized` | A splitter's divider is about to settle, cancelable, and then did |
111
+ | `helix-before-collapse`, `helix-collapse` | A splitter's pane is about to shut or reopen, cancelable, and then did |
108
112
  | `helix-select` | An item was chosen from a set |
109
113
  | `helix-dismiss` | A user asked for something to close |
110
114
  | `helix-next`, `helix-previous` | Movement through a sequence |
@@ -121,12 +125,36 @@ Every stateful component also sends native events once the change is applied:
121
125
 
122
126
  - `input` and `change` on a value control
123
127
  - `toggle` on anything that opens, carrying `newState` and `oldState` as
124
- `<details>` does
128
+ `<details>` does. It is a `ToggleEvent` in browsers that have one, and it is
129
+ sent whether the change came from a reader or from assigning `open`
125
130
  - `close` on a dialog
126
131
  - `load` and `error` on an image
127
132
 
128
133
  Each component's page lists the events it dispatches, with the class and the
129
- detail.
134
+ detail. The table above lists the common ones.
135
+
136
+ ## Requests under a plain name
137
+
138
+ A few events with no `before` in their name are also cancelable requests. Each
139
+ is sent before the change, and you refuse the change with `preventDefault()`:
140
+
141
+ - `helix-navigate` on Pagination, Data Table, and Date Picker
142
+ - `helix-sort`, `helix-filter`, `helix-select`, and `helix-reorder` on Data Table
143
+ - `helix-select` on Carousel
144
+
145
+ Each of these requests had its name before the library had a word for the
146
+ notification, so the notification has its own name. It is sent after the
147
+ change, is not cancelable, and carries the new state:
148
+
149
+ - `helix-activate` after the page moves on Pagination and Data Table, and after
150
+ the slide moves on Carousel
151
+ - `helix-sorted`, `helix-filtered`, `helix-selected`, and `helix-reordered` on
152
+ Data Table
153
+ - `input` and `change` together on Pagination Size, as a native `<select>`
154
+ sends them
155
+
156
+ A request that is refused sends no notification. Date Picker's `helix-navigate`
157
+ moves the month on show, and the month sends no notification.
130
158
 
131
159
  ## Events in a framework
132
160
 
package/content/forms.mdx CHANGED
@@ -101,23 +101,62 @@ participants:
101
101
  ></helix-input>
102
102
  ```
103
103
 
104
- Submitting an empty form is blocked, and the browser points to the control.
105
- `checkValidity()`, `reportValidity()`, and `:invalid` work as they do for native
106
- controls.
104
+ Submitting an empty form is blocked, and the browser moves focus to the control
105
+ and shows its message there. Each control has the validity API of a native
106
+ control:
107
107
 
108
- `feedback` replaces the browser's message. When `feedback` is empty, the
109
- browser shows its own message, which is localized and familiar. When you set it,
110
- the control shows the message in the words your product uses:
108
+ - `checkValidity()` and `reportValidity()`
109
+ - `setCustomValidity(message)`
110
+ - `validity`, `validationMessage`, and `willValidate`
111
+
112
+ `:invalid` matches the control as it matches a native one.
113
+
114
+ `value-missing-message` replaces the browser's message for a required control
115
+ that is empty. When it is not set, the browser shows its own message, which is
116
+ localized and familiar:
111
117
 
112
118
  ```html
113
119
  <helix-input
114
- feedback="We need this to send your receipt."
115
120
  label="Email"
116
121
  name="email"
117
122
  required
123
+ value-missing-message="We need this to send your receipt."
124
+ ></helix-input>
125
+ ```
126
+
127
+ **`feedback` says what is wrong, and the form does not submit while it is
128
+ set.** Use it for a verdict the browser cannot reach, such as one your server
129
+ returned. The control shows the message under itself and is invalid until you
130
+ clear `feedback`:
131
+
132
+ ```html
133
+ <helix-input
134
+ feedback="That name is taken."
135
+ label="Username"
136
+ name="username"
118
137
  ></helix-input>
119
138
  ```
120
139
 
140
+ `setCustomValidity()` blocks the form in the same way, and the control shows
141
+ its message once the reader has edited the field.
142
+
143
+ ## Focus and Enter
144
+
145
+ `focus()` on a control moves focus to the element a reader would reach with
146
+ Tab, and pressing a `<label>` that names the control does the same. In a group,
147
+ that is the chosen radio, or the first one when nothing is chosen.
148
+
149
+ Pressing Enter in a single-line field submits its form, as Enter in a native
150
+ text field does. These fields do it:
151
+
152
+ - `Input`, `NumberInput`, and `PinInput`
153
+ - `DateInput`, `TimeInput`, and `ColorInput`
154
+ - `Combobox`, while its list is closed
155
+
156
+ The form's first submit button is pressed, and a `helix-button type="submit"`
157
+ counts as one, for a native field too. A form with no submit button is
158
+ submitted when it has only one text field.
159
+
121
160
  `Radio.Group` and `Toggle.Group` take part in the form for their members. Each
122
161
  group owns the `name`, the `value`, and the validity. A single radio is an
123
162
  answer, and the group is the control it answers. `Checkbox.Group` works the
@@ -31,7 +31,7 @@ Add the frame, with an element inside it for the renderer to draw in:
31
31
  Give the frame its notes and links, make the renderer, and connect the two:
32
32
 
33
33
  ```js
34
- import '@fusion.dev/helix'
34
+ import '@fusion.dev/helix/graph'
35
35
  import { connectGraph } from '@fusion.dev/helix-graph'
36
36
  import { sigmaDriver } from '@fusion.dev/helix-graph/sigma'
37
37
  import Graph from 'graphology'
@@ -186,7 +186,10 @@ is a button that shows or hides the group's notes, in the drawing and in the
186
186
  list:
187
187
 
188
188
  ```html
189
- <helix-graph label="Company notes" legend>
189
+ <helix-graph
190
+ label="Company notes"
191
+ legend
192
+ >
190
193
  <div></div>
191
194
  </helix-graph>
192
195
  ```
@@ -234,7 +237,10 @@ and the frame brings it into view with its neighbors. Start with one selected
234
237
  with `default-active`:
235
238
 
236
239
  ```html
237
- <helix-graph default-active="roadmap" label="Research notes">
240
+ <helix-graph
241
+ default-active="roadmap"
242
+ label="Research notes"
243
+ >
238
244
  <div></div>
239
245
  </helix-graph>
240
246
  ```
@@ -246,7 +252,11 @@ Set `depth` to show only the notes within that many links of the selected one,
246
252
  for a graph too large to read at once:
247
253
 
248
254
  ```html
249
- <helix-graph default-active="roadmap" depth="2" label="Research notes">
255
+ <helix-graph
256
+ default-active="roadmap"
257
+ depth="2"
258
+ label="Research notes"
259
+ >
250
260
  <div></div>
251
261
  </helix-graph>
252
262
  ```
@@ -319,7 +329,10 @@ finger moves it. A graph embedded in a page takes the wheel from a reader who
319
329
  is scrolling past it. Set `gestures` on the frame to share them:
320
330
 
321
331
  ```html
322
- <helix-graph gestures="cooperative" label="Research notes">
332
+ <helix-graph
333
+ gestures="cooperative"
334
+ label="Research notes"
335
+ >
323
336
  <div></div>
324
337
  </helix-graph>
325
338
  ```
@@ -340,7 +353,11 @@ drawing takes all of it, as at the top of a page. A Notes button among the
340
353
  controls opens them over the drawing:
341
354
 
342
355
  ```html
343
- <helix-graph gestures="cooperative" label="Research notes" no-panel>
356
+ <helix-graph
357
+ gestures="cooperative"
358
+ label="Research notes"
359
+ no-panel
360
+ >
344
361
  <div></div>
345
362
  </helix-graph>
346
363
  ```
@@ -409,7 +426,8 @@ leaves removing it to your framework.
409
426
  minus keys zoom it. Set `controls="pan zoom fullscreen"` to add buttons that
410
427
  move it.
411
428
  - The list is a listbox, named by `notes-label`. Arrow keys, Home, End, Page
412
- Up, and Page Down move through it, and Enter or Space selects a note.
429
+ Up, and Page Down move through it, typing a letter moves to the next note
430
+ whose name starts with it, and Enter or Space selects a note.
413
431
  - In the search field, Down moves into the list, and Escape empties the search.
414
432
  With `no-panel`, Escape on an empty search closes the list.
415
433
  - Screen readers read the selected note first, then how each other note links
@@ -44,15 +44,15 @@ Each file has its own export. If you bring your own reset or your own ramp,
44
44
  import the two files you want and skip `helix.css`.
45
45
 
46
46
  - **`primitives.css`** holds the raw ramp that the semantic layer is derived
47
- from. The seven `--helix-seed-*` properties are read here. Your own code
48
- should not name a primitive, and leaving the file out does not enforce that.
49
- `tokens.css` refers to a primitive 297 times, so without `primitives.css`
50
- every semantic token resolves to nothing. We measured a page without it:
47
+ from. The `--helix-seed-*` properties are read here. Your own code should
48
+ not name a primitive, and leaving the file out does not enforce that.
49
+ `tokens.css` refers to the primitives throughout, so without
50
+ `primitives.css` every semantic token resolves to nothing. We measured a page without it:
51
51
  `--helix-color-background` computes to `rgba(0, 0, 0, 0)`, and so does every
52
52
  other color. [Theming](theming.mdx) also depends on this file, because without
53
53
  it, setting `--helix-seed-brand` changes nothing.
54
- - **`tokens.css`** declares the semantic layer: 185 custom properties in 15
55
- categories, plus `color-scheme: light dark` on `:root`. The files below read
54
+ - **`tokens.css`** declares the semantic layer, the custom properties grouped
55
+ by category, plus `color-scheme: light dark` on `:root`. The files below read
56
56
  from it, and it reads from `primitives.css`.
57
57
  - **`base.css`** holds the element reset, the type scale on bare `h1` through
58
58
  `h6`, and the recipes for markup that Helix does not render. It reads tokens.
@@ -67,25 +67,23 @@ components. The order then stays visible in one place.
67
67
 
68
68
  ## Register the elements
69
69
 
70
- ```ts
71
- import '@fusion.dev/helix'
72
- ```
73
-
74
- This import has a side effect: it calls `customElements.define` once for every
75
- element. You can run it more than once. A second `define` for the same tag
76
- throws an error and stops the rest of the module, so the helper behind the
77
- import checks the registry first.
78
-
79
- To register only some elements, import them from subpaths:
70
+ Import each family you use from its subpath:
80
71
 
81
72
  ```ts
82
73
  import '@fusion.dev/helix/button'
83
74
  import '@fusion.dev/helix/dialog'
84
75
  ```
85
76
 
86
- Import from subpaths when you use a few components. The package has side
87
- effects by design, so a bundler keeps everything you import. The whole-package
88
- import registers every element, and a subpath registers only its family.
77
+ Each import has a side effect: it calls `customElements.define` for the
78
+ elements of that family, and for the families they render. You can run it more
79
+ than once. A second `define` for the same tag throws an error and stops the rest
80
+ of the module, so the helper behind the import checks the registry first.
81
+
82
+ The package has side effects by design, so a bundler keeps everything you
83
+ import. `import '@fusion.dev/helix'` registers every element in the library,
84
+ which is the whole library in your bundle. Use it for a prototype, and use
85
+ subpaths in an app. [Metrics](./metrics) lists the size of each family and of
86
+ the whole package.
89
87
 
90
88
  ## Check the installation
91
89
 
@@ -33,12 +33,12 @@ reason.
33
33
  bun add @fusion.dev/helix @fusion.dev/helix-styles
34
34
  ```
35
35
 
36
- Add two imports at your app root, in this order. Then you can use the elements
37
- anywhere:
36
+ Import the stylesheet at your app root, then each family you use. Then you can
37
+ use those elements anywhere:
38
38
 
39
39
  ```ts
40
40
  import '@fusion.dev/helix-styles/helix.css'
41
- import '@fusion.dev/helix'
41
+ import '@fusion.dev/helix/accordion'
42
42
  ```
43
43
 
44
44
  ```html
@@ -92,8 +92,8 @@ Six families format numbers or dates and take a `locale`:
92
92
 
93
93
  | | |
94
94
  |---|---|
95
- | `Date Input`, `Date Picker` | Date formats and first day of week |
96
- | `Time Input`, `Time Picker` | 12 or 24 hour, and separators |
95
+ | `Date Input`, `Date Picker` | Date formats, and the first day of the week where `first-day-of-week` is not set |
96
+ | `Time Input`, `Time Picker` | 12 or 24 hour, separators, and the AM and PM on the wheels |
97
97
  | `Pagination` | Grouped thousands in page numbers |
98
98
  | `File Input` | File sizes |
99
99
 
@@ -108,6 +108,15 @@ If you do not set `locale`, these controls use the browser's locale, which is
108
108
  usually correct. Set `locale` when your users choose your application's
109
109
  language separately from the language of their operating system.
110
110
 
111
+ The first day of the week comes from `Intl.Locale`'s week information, which
112
+ Firefox does not provide. There, and where you set no `locale`, the week starts
113
+ on Sunday. Set `first-day-of-week` to choose the day yourself.
114
+
115
+ `locale` formats dates, times, and numbers. It does not translate the words a
116
+ control speaks, such as "Previous month" on a calendar or "Hour" on a time
117
+ wheel. Set those through their properties, such as `previous-label` and
118
+ `next-label` on Date Picker and Date Input, and `hour-label` on Time Picker.
119
+
111
120
  Formatting uses `Intl`, so Helix bundles no locale data, and you have nothing to
112
121
  keep up to date.
113
122
 
@@ -137,8 +146,13 @@ it reports:
137
146
  - `bad-input-message`
138
147
  - `range-underflow-message`
139
148
  - `range-overflow-message`
149
+ - `step-mismatch-message`
140
150
  - `too-short-message`
141
151
 
152
+ Date Picker, Date Input, Time Picker, and Time Input also take
153
+ `unavailable-message`, for a date or time that `disable-dates`, `disable-days`,
154
+ or `disable-times` rules out.
155
+
142
156
  A message appears in the browser's own validation bubble and on the line under
143
157
  the field. `feedback` does not reach the bubble. If you do not set a message, a
144
158
  text field shows the browser's own message, which is already in your user's
package/content/maps.mdx CHANGED
@@ -36,7 +36,7 @@ Add the map frame, an element for MapLibre to draw in, and your places:
36
36
  Create the map with a style from your theme, then connect it to the frame:
37
37
 
38
38
  ```js
39
- import '@fusion.dev/helix'
39
+ import '@fusion.dev/helix/map'
40
40
  import 'maplibre-gl/dist/maplibre-gl.css'
41
41
  import { colorsReady, connectMap } from '@fusion.dev/helix-map'
42
42
  import { followTheme, mapLibreDriver, mapLibreStyle } from '@fusion.dev/helix-map/maplibre'
@@ -161,7 +161,11 @@ is the map's. Give the container a position, such as `position: relative`:
161
161
 
162
162
  ```html
163
163
  <section class="hero">
164
- <helix-map fill credit-placement="bottom-end" label="Downtown Austin">
164
+ <helix-map
165
+ credit-placement="bottom-end"
166
+ fill
167
+ label="Downtown Austin"
168
+ >
165
169
  <div id="map"></div>
166
170
  </helix-map>
167
171
  <div class="hero-words">
@@ -235,7 +239,10 @@ A map embedded in a page, such as a hero, takes the wheel from a reader who is
235
239
  scrolling past it. Set `gestures` on the frame to share them:
236
240
 
237
241
  ```html
238
- <helix-map gestures="cooperative" label="Downtown Austin">
242
+ <helix-map
243
+ gestures="cooperative"
244
+ label="Downtown Austin"
245
+ >
239
246
  <div id="map"></div>
240
247
  </helix-map>
241
248
  ```
@@ -487,7 +494,10 @@ is a map type, which the frame's `map-type` attribute chooses:
487
494
  - `satellite`: the imagery alone, without the roads and names.
488
495
 
489
496
  With `layers` in the frame's `controls`, the layers menu opens with a card for
490
- each map type, showing a picture of the map in it. Set `max-zoom` to the deepest
497
+ each map type, showing a picture of the map in it. Choosing a card sends
498
+ `helix-before-change` with the type's name, `standard`, `hybrid`, or
499
+ `satellite`, and `change` once `map-type` holds it. Cancel the first to keep the
500
+ current type, or listen for the second to store the choice. Set `max-zoom` to the deepest
491
501
  zoom your provider has tiles for, and the map enlarges those tiles when a user
492
502
  zooms in further.
493
503
 
@@ -560,6 +570,10 @@ tile is lit while its layer is shown. Pressing a tile sets its layer's `hidden`
560
570
  attribute, and `connectMap` does not draw a hidden layer. Write `hidden` on a
561
571
  layer to start it turned off.
562
572
 
573
+ Before it sets `hidden`, a tile sends `helix-before-toggle` from the layer, with
574
+ `checked` true when the layer is to be shown. Store the choice from it, or
575
+ cancel it to keep the layer as it is.
576
+
563
577
  Give layers the same `group` to show them as one tile, such as a route and the
564
578
  dotted legs at its ends. The tile takes the name of the first layer in the
565
579
  group, and shows or hides every layer in it. Keep labels short, such as