@fusion.dev/helix-headless 0.156.0 → 0.158.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.
Files changed (47) hide show
  1. package/custom-elements.json +1085 -66
  2. package/dist/command/root/command-root.d.ts +19 -5
  3. package/dist/command/root/command-root.js +14 -4
  4. package/dist/data-table/root/data-table-root.js +5 -2
  5. package/dist/drilldown/item/drilldown-item.d.ts +49 -1
  6. package/dist/drilldown/item/drilldown-item.js +77 -17
  7. package/dist/drilldown/root/drilldown-root.d.ts +45 -5
  8. package/dist/drilldown/root/drilldown-root.js +51 -5
  9. package/dist/element-events.generated.js +1 -1
  10. package/dist/filter-input/menu/filter-menu.d.ts +1 -0
  11. package/dist/filter-input/menu/filter-menu.js +4 -4
  12. package/dist/list/item/list-item.d.ts +15 -1
  13. package/dist/list/item/list-item.js +20 -1
  14. package/dist/list/root/list-root.d.ts +29 -1
  15. package/dist/list/root/list-root.js +44 -10
  16. package/dist/listbox/root/listbox-root.d.ts +19 -2
  17. package/dist/listbox/root/listbox-root.js +16 -8
  18. package/dist/map/root/map-root.d.ts +4 -0
  19. package/dist/map/root/map-root.js +1 -1
  20. package/dist/megamenu/root/megamenu-root.d.ts +50 -13
  21. package/dist/megamenu/root/megamenu-root.js +44 -6
  22. package/dist/menu/item/menu-item.d.ts +24 -1
  23. package/dist/menu/item/menu-item.js +42 -2
  24. package/dist/menu/root/menu-root.d.ts +126 -11
  25. package/dist/menu/root/menu-root.js +336 -26
  26. package/dist/notifications/root/notifications-root.d.ts +20 -0
  27. package/dist/notifications/root/notifications-root.js +32 -1
  28. package/dist/number-input/root/number-input-root.d.ts +7 -4
  29. package/dist/number-input/root/number-input-root.js +3 -3
  30. package/dist/progress/root/progress-root.js +1 -1
  31. package/dist/select/root/select-root.d.ts +8 -1
  32. package/dist/select/root/select-root.js +8 -5
  33. package/dist/skeleton/root/skeleton-root.d.ts +2 -1
  34. package/dist/skeleton/root/skeleton-root.js +1 -1
  35. package/dist/toast/item/toast-item.d.ts +26 -0
  36. package/dist/toast/item/toast-item.js +55 -3
  37. package/dist/toast/root/toast-root.d.ts +32 -0
  38. package/dist/toast/root/toast-root.js +47 -2
  39. package/dist/video/root/video-root.d.ts +1 -0
  40. package/dist/video/root/video-root.js +9 -9
  41. package/dist/video-playlist/menu/video-playlist-menu.d.ts +1 -0
  42. package/dist/video-playlist/menu/video-playlist-menu.js +1 -1
  43. package/lint.json +1 -1
  44. package/package.json +5 -5
  45. package/types/jsx.d.ts +653 -74
  46. package/types/vue.d.ts +133 -16
  47. package/types/words.d.ts +14 -0
package/types/vue.d.ts CHANGED
@@ -4391,6 +4391,13 @@ hydration, or diffed by a framework, it comes back holding whatever the
4391
4391
  last reader did rather than what the author wrote. `:state(open)` carries
4392
4392
  the resolved state for stylesheets, which is what the mirror is for. */
4393
4393
  open?: (HelixHeadlessCommand["open"]) | undefined;
4394
+ /** Whether a command is kept by the filter: a function given the command's
4395
+ words and the filter, trimmed, that returns `true` to keep it showing, as
4396
+ React Aria's `Autocomplete` takes `filter`. See Listbox's `filterMatch`.
4397
+
4398
+ Absent, a command is kept where its words hold the filter, in any case. A
4399
+ property only, there being no way to write a function in markup. */
4400
+ filterMatch?: (HelixHeadlessCommand["filterMatch"]) | undefined;
4394
4401
  /** The commands as data, for a palette too long to draw whole: each a value,
4395
4402
  which is also its words, or a record with a `value`, a `label` and
4396
4403
  `disabled`. Handed to the list, which draws only the commands in sight and
@@ -6302,6 +6309,16 @@ export type HelixHeadlessDrilldownItemHelixSelectElementEvent =
6302
6309
  export type HelixHeadlessDrilldownItemVueProps = {
6303
6310
  /** Whether the row can be reached at all. */
6304
6311
  disabled?: (HelixHeadlessDrilldownItem["disabled"]) | undefined;
6312
+ /** Whether the link downloads the file when the row is chosen. Only
6313
+ meaningful beside an `href`, and only for a file served from this origin. */
6314
+ download?: (HelixHeadlessDrilldownItem["download"]) | undefined;
6315
+ /** The URL the row links to. Setting it renders the row as a link, unless the
6316
+ row opens a page or is disabled. */
6317
+ href?: (HelixHeadlessDrilldownItem["href"]) | undefined;
6318
+ /** The link's `rel`. Set it whenever you set `target="_blank"`. */
6319
+ rel?: (HelixHeadlessDrilldownItem["rel"]) | undefined;
6320
+ /** Where the link opens, for rows that should open outside the current page. */
6321
+ target?: (HelixHeadlessDrilldownItem["target"]) | undefined;
6305
6322
  /** Identifies the row to your event listeners. */
6306
6323
  value?: (HelixHeadlessDrilldownItem["value"]) | undefined;
6307
6324
  /** Whether this row holds the region's tab stop. Set by the drill-down.
@@ -6328,6 +6345,9 @@ export type HelixHeadlessDrilldownElementEvent<E = Event> = TypedEvent<
6328
6345
  HelixHeadlessDrilldown,
6329
6346
  E
6330
6347
  >;
6348
+ /** `helix-navigate` event type */
6349
+ export type HelixHeadlessDrilldownHelixNavigateElementEvent =
6350
+ HelixHeadlessDrilldownElementEvent<HelixNavigateEvent>;
6331
6351
  /** `helix-select` event type */
6332
6352
  export type HelixHeadlessDrilldownHelixSelectElementEvent =
6333
6353
  HelixHeadlessDrilldownElementEvent<HelixSelectEvent>;
@@ -6343,6 +6363,14 @@ and wins over this. */
6343
6363
  "back-label"?: (HelixHeadlessDrilldown["backLabel"]) | undefined;
6344
6364
  /** The text of the back button. */
6345
6365
  backLabel?: (HelixHeadlessDrilldown["backLabel"]) | undefined;
6366
+ /** Whether the drilldown is a site's navigation: a `navigation` landmark
6367
+ named by `label`, whose pages are lists of links. Without it, each page is
6368
+ a `menu`. */
6369
+ navigation?: (HelixHeadlessDrilldown["navigation"]) | undefined;
6370
+ /** The page showing, as the `value` of the row that opens it. Empty is the
6371
+ top page. Setting it shows that page, and a value no row with a page has
6372
+ shows the top page. */
6373
+ page?: (HelixHeadlessDrilldown["page"]) | undefined;
6346
6374
  /** The text shown and announced when there are no rows and none are loading. */
6347
6375
  "empty-text"?: (HelixHeadlessDrilldown["emptyText"]) | undefined;
6348
6376
  /** The text shown and announced when there are no rows and none are loading. */
@@ -6360,6 +6388,8 @@ say that without the component knowing what a row looks like. */
6360
6388
  };
6361
6389
 
6362
6390
  export type HelixHeadlessDrilldownVueEvents = {
6391
+ /** Fired before a reader moves into a page or back out of one. `detail.value` is the `value` of the row whose page is about to show, empty for the top page. Cancelable: cancel it to stay on the page showing. */
6392
+ "helix-navigate": HelixHeadlessDrilldownHelixNavigateElementEvent;
6363
6393
  /** Fired when a row with no page is chosen. Cancelable: canceling it stops the change and leaves the decision to you. */
6364
6394
  "helix-select": HelixHeadlessDrilldownHelixSelectElementEvent;
6365
6395
  };
@@ -8871,7 +8901,9 @@ Not reflected, as a state never is. `row-current` is the part a
8871
8901
  stylesheet draws it from. */
8872
8902
  current?: (HelixHeadlessListItem["current"]) | undefined;
8873
8903
  /** Takes the row out of reach in a list with `selection-mode`: the arrow keys
8874
- pass over it and it cannot be selected or acted on. */
8904
+ pass over it and it cannot be selected or acted on. In a list with
8905
+ `disabled-behavior="selection"`, it cannot be selected and is reached and
8906
+ acted on as any row is. */
8875
8907
  disabled?: (HelixHeadlessListItem["disabled"]) | undefined;
8876
8908
  /** The URL the row links to. Leave it empty for a row that is not a link.
8877
8909
 
@@ -8907,6 +8939,10 @@ being moved, or the one the drop indicator is beside. Unset otherwise. */
8907
8939
  Written by the list from its own `value`, and unset where nothing can be
8908
8940
  selected, which keeps `aria-selected` off a list that does not select. */
8909
8941
  selected?: (HelixHeadlessListItem["selected"]) | undefined;
8942
+ /** Whether `disabled` takes the row out of selection alone, written by a list
8943
+ with `disabled-behavior="selection"`. No attribute: it is coordination
8944
+ between elements, as `focusable` is. */
8945
+ selectionOnly?: (HelixHeadlessListItem["selectionOnly"]) | undefined;
8910
8946
  };
8911
8947
 
8912
8948
  export type HelixHeadlessListItemVueEvents = {
@@ -8942,6 +8978,20 @@ refused, in a `reorderable` list. */
8942
8978
  /** What screen readers hear when a held row is put back, or a move is
8943
8979
  refused, in a `reorderable` list. */
8944
8980
  canceledLabel?: (HelixHeadlessList["canceledLabel"]) | undefined;
8981
+ /** What `disabled` takes from a row, in a list that selects: `all`, which
8982
+ passes over the row, or `selection`, which keeps the row out of the
8983
+ selection and lets the keys reach it and Enter or a press act on it, as
8984
+ React Aria's GridList takes `disabledBehavior`.
8985
+
8986
+ Absent is `all`. */
8987
+ "disabled-behavior"?: (HelixHeadlessList["disabledBehavior"]) | undefined;
8988
+ /** What `disabled` takes from a row, in a list that selects: `all`, which
8989
+ passes over the row, or `selection`, which keeps the row out of the
8990
+ selection and lets the keys reach it and Enter or a press act on it, as
8991
+ React Aria's GridList takes `disabledBehavior`.
8992
+
8993
+ Absent is `all`. */
8994
+ disabledBehavior?: (HelixHeadlessList["disabledBehavior"]) | undefined;
8945
8995
  /** What screen readers hear when a row is dropped, in a `reorderable` list. */
8946
8996
  "dropped-label"?: (HelixHeadlessList["droppedLabel"]) | undefined;
8947
8997
  /** What screen readers hear when a row is dropped, in a `reorderable` list. */
@@ -9325,6 +9375,14 @@ imperatively later, and nothing is hydrating by then.
9325
9375
 
9326
9376
  Here rather than on each control. */
9327
9377
  name?: (HelixHeadlessListbox["name"]) | undefined;
9378
+ /** Whether an option is kept by the filter: a function given the option's
9379
+ words and the filter, trimmed, that returns `true` to keep it showing, as
9380
+ React Aria's `Autocomplete` takes `filter`. For matching that ignores
9381
+ accents, matches the start of each word, or matches out of order.
9382
+
9383
+ Absent, an option is kept where its words hold the filter, in any case. A
9384
+ property only, there being no way to write a function in markup. */
9385
+ filterMatch?: (HelixHeadlessListbox["filterMatch"]) | undefined;
9328
9386
  /** The options as data, for a list too long to draw whole: each a value,
9329
9387
  which is also its words, or a record with a `value`, a `label` and
9330
9388
  `disabled`. Set, the list draws only the options in sight, and the ones
@@ -10194,8 +10252,24 @@ narrow exception the server specs describe covers a mirror that can only
10194
10252
  become true long after hydration, and a viewport measured before the first
10195
10253
  paint is the opposite case. See `MixinControllerOpen` on `open`. */
10196
10254
  bandBelow?: (HelixHeadlessMegamenu["bandBelow"]) | undefined;
10255
+ /** How long a pointer leaving the trigger and the panel waits before the panel
10256
+ closes, in milliseconds. The pointer needs the time to cross from the
10257
+ trigger to the panel. */
10258
+ "close-delay"?: (HelixHeadlessMegamenu["closeDelay"] | `${number}`) | undefined;
10259
+ /** How long a pointer leaving the trigger and the panel waits before the panel
10260
+ closes, in milliseconds. The pointer needs the time to cross from the
10261
+ trigger to the panel. */
10262
+ closeDelay?: (HelixHeadlessMegamenu["closeDelay"]) | undefined;
10197
10263
  /** The section's name, used for the default trigger and the panel. */
10198
10264
  label?: (HelixHeadlessMegamenu["label"]) | undefined;
10265
+ /** How long a pointer rests on the trigger before the panel opens, in
10266
+ milliseconds, under `open-on="hover"`. A pointer crossing the bar on its
10267
+ way somewhere else opens nothing. */
10268
+ "open-delay"?: (HelixHeadlessMegamenu["openDelay"] | `${number}`) | undefined;
10269
+ /** How long a pointer rests on the trigger before the panel opens, in
10270
+ milliseconds, under `open-on="hover"`. A pointer crossing the bar on its
10271
+ way somewhere else opens nothing. */
10272
+ openDelay?: (HelixHeadlessMegamenu["openDelay"]) | undefined;
10199
10273
  /** Whether hovering over the trigger opens the panel (`hover`), or only a press
10200
10274
  does (`click`).
10201
10275
 
@@ -10212,6 +10286,10 @@ the trigger, and it is the default because that is what a navigation bar
10212
10286
  does. `click` is for a trigger that does something else as well, or a panel
10213
10287
  heavy enough that opening it on the way past is rude. */
10214
10288
  openOn?: (HelixHeadlessMegamenu["openOn"]) | undefined;
10289
+ /** The side of the trigger a card panel opens on, when there is room. It
10290
+ moves if that side does not fit. A band ignores it, since a band spans the
10291
+ page under its bar. */
10292
+ placement?: (HelixHeadlessMegamenu["placement"]) | undefined;
10215
10293
  /** Whether the panel is a card under the trigger or a band across the page.
10216
10294
 
10217
10295
  The resting one is the card, hanging off the trigger and as wide as it
@@ -10379,12 +10457,29 @@ Empty by default, which names the surface by its trigger, so a menu opened
10379
10457
  from "Actions" is announced as "Actions". An `aria-label` or
10380
10458
  `aria-labelledby` on the host names it too, and wins over both. */
10381
10459
  label?: (HelixHeadlessMenu["label"]) | undefined;
10460
+ /** The description a trigger gives under `open-on="long-press"`, saying how
10461
+ to open the menu. Translate it with the rest of your interface. */
10462
+ "long-press-label"?: (HelixHeadlessMenu["longPressLabel"]) | undefined;
10463
+ /** The description a trigger gives under `open-on="long-press"`, saying how
10464
+ to open the menu. Translate it with the rest of your interface. */
10465
+ longPressLabel?: (HelixHeadlessMenu["longPressLabel"]) | undefined;
10382
10466
  /** Space between the trigger and the surface, in pixels. */
10383
10467
  offset?: (HelixHeadlessMenu["offset"]) | undefined;
10468
+ /** What opens the menu from its trigger. `long-press` leaves a press to the
10469
+ trigger's own action and opens the menu on a press held for half a second,
10470
+ or on Alt+Down or Alt+Up. */
10471
+ "open-on"?: (HelixHeadlessMenu["openOn"]) | undefined;
10472
+ /** What opens the menu from its trigger. `long-press` leaves a press to the
10473
+ trigger's own action and opens the menu on a press held for half a second,
10474
+ or on Alt+Down or Alt+Up. */
10475
+ openOn?: (HelixHeadlessMenu["openOn"]) | undefined;
10384
10476
  /** The side the menu opens on, when there is room.
10385
10477
 
10386
10478
  It moves if that side does not fit. */
10387
10479
  placement?: (HelixHeadlessMenu["placement"]) | undefined;
10480
+ /** How a submenu opens. `drill` shows it in place of the page showing, with
10481
+ a way back. `flyout` opens it in a panel of its own beside its row. */
10482
+ submenus?: (HelixHeadlessMenu["submenus"]) | undefined;
10388
10483
  /** The text shown and announced when there are no rows and none are loading. */
10389
10484
  "empty-text"?: (HelixHeadlessMenu["emptyText"]) | undefined;
10390
10485
  /** The text shown and announced when there are no rows and none are loading. */
@@ -10792,6 +10887,12 @@ export type HelixHeadlessNotificationsHelixReadElementEvent =
10792
10887
  HelixHeadlessNotificationsElementEvent<HelixReadEvent>;
10793
10888
 
10794
10889
  export type HelixHeadlessNotificationsVueProps = {
10890
+ /** What the feed says when unread notifications arrive, with `{count}` the
10891
+ number of them. Empty it to say nothing. */
10892
+ "arrived-label"?: (HelixHeadlessNotifications["arrivedLabel"]) | undefined;
10893
+ /** What the feed says when unread notifications arrive, with `{count}` the
10894
+ number of them. Empty it to say nothing. */
10895
+ arrivedLabel?: (HelixHeadlessNotifications["arrivedLabel"]) | undefined;
10795
10896
  /** The region's name where `label` is empty. */
10796
10897
  "fallback-label"?: (HelixHeadlessNotifications["fallbackLabel"]) | undefined;
10797
10898
  /** The region's name where `label` is empty. */
@@ -11128,8 +11229,11 @@ imperatively later, and nothing is hydrating by then.
11128
11229
 
11129
11230
  Here rather than on each control. */
11130
11231
  name?: (HelixHeadlessNumberInput["name"]) | undefined;
11131
- /** The value as a number, or `NaN` while the control is empty.
11232
+ /** The value as a number, or `NaN` while the control is empty or does not
11233
+ hold a number.
11132
11234
 
11235
+ Read in the locale and the format, as the form reads it, so `1,5` typed
11236
+ in a locale with a decimal comma is 1.5 here while the form holds 1.5.
11133
11237
  `NaN` and not zero, which is the trap the platform already avoids: `Number('')`
11134
11238
  is zero, so an empty control would report a number it does not hold and a
11135
11239
  form would submit it. */
@@ -13249,7 +13353,8 @@ export type HelixHeadlessSkeletonVueProps = {
13249
13353
  /** What is loading, read out as the placeholder's name, such as "Loading
13250
13354
  profile".
13251
13355
 
13252
- Absent hides the placeholder from screen readers. */
13356
+ Absent hides the placeholder from screen readers. Around content, the name
13357
+ is read while `loading` is set, and the loaded content is read as it is. */
13253
13358
  label?: (HelixHeadlessSkeleton["label"]) | undefined;
13254
13359
  /** Whether the content inside is still loading, which keeps it inert and
13255
13360
  draws the placeholder over it.
@@ -16077,6 +16182,10 @@ A word property: register it for a locale under the host's key. A family
16077
16182
  that names the control otherwise, such as Tag's `Remove {label}`,
16078
16183
  declares its own English with `@words` above the override. */
16079
16184
  dismissLabel?: (HelixHeadlessToastItem["dismissLabel"]) | undefined;
16185
+ /** Whether the region holds the message back, because more messages are
16186
+ showing than its `max-visible`. The region sets it. A waiting message is
16187
+ hidden, its timer has not started, and it is said once it shows. */
16188
+ waiting?: (HelixHeadlessToastItem["waiting"]) | undefined;
16080
16189
  };
16081
16190
 
16082
16191
  export type HelixHeadlessToastItemVueEvents = {
@@ -16102,6 +16211,14 @@ Empty turns it off. */
16102
16211
  /** Accessible name for the region, with `{hotkey}` filled in. Translate it with
16103
16212
  the rest of your interface. */
16104
16213
  label?: (HelixHeadlessToast["label"]) | undefined;
16214
+ /** How many messages show at once. The messages after that many wait, hidden
16215
+ and with their timers stopped, until a message before them goes. Unset,
16216
+ every message shows. */
16217
+ "max-visible"?: (HelixHeadlessToast["maxVisible"] | `${number}`) | undefined;
16218
+ /** How many messages show at once. The messages after that many wait, hidden
16219
+ and with their timers stopped, until a message before them goes. Unset,
16220
+ every message shows. */
16221
+ maxVisible?: (HelixHeadlessToast["maxVisible"]) | undefined;
16105
16222
  /** Which corner or edge the stack sits at.
16106
16223
 
16107
16224
  Named here rather than on each message, because where a page puts its
@@ -18213,7 +18330,7 @@ export interface WcToolkitVueGlobalComponents {
18213
18330
  HelixHeadlessComboboxVueProps,
18214
18331
  HelixHeadlessComboboxVueEvents
18215
18332
  >;
18216
- /** The list is a 'Listbox', which handles filtering, the empty state, the match highlight, 'aria-activedescendant', scrolling an option into view, and moving between options with the keyboard. The palette adds a dialog and a hotkey that opens it. The palette keeps no value. It is not a form control and submits nothing. Choosing an option dispatches 'helix-select' once. To remember the last command, store it yourself. An option with 'href' is a link to a page, which the browser follows once the palette has closed. The hotkey listener is on the document, so the hotkey works from anywhere on the page, including inside another control's text field, whether or not the palette is open. 'mod' means Command on a Mac and Control elsewhere, so you write one binding. With 'inline', the palette is drawn in the page with no dialog, as a search over a list that is always shown. **Pages.** A command can open a page of commands of its own, as a palette offers "Change theme" and then the themes. Give the option 'opens' with a name, and slot the page's commands as 'page:' and that name: '''html <helix-command> <helix-option value="theme" opens="theme">Change theme</helix-option> <helix-option value="dark" slot="page:theme">Dark</helix-option> <helix-option value="light" slot="page:theme">Light</helix-option> </helix-command> ''' Choosing the opener says 'helix-select' with its value, and canceling it keeps the page that is shown. The list then shows the page, named by the opener's words, and Backspace in an empty filter goes back. 'page' says which page is shown. The filter is cleared when the palette closes, so each opening starts from the full list. Combobox and Select do the same. As typing narrows the list, a screen reader hears how many commands are left, such as "3 commands". **Keyboard.** Focus goes to the filter field as the palette opens, and the highlight moves through the commands while you type. | Key | What it does | |---|---| | 'hotkey', Command or Control with K by default | Opens the palette from anywhere on the page, or closes it. With 'inline', puts focus in its filter field. | | Down, Up | Moves the highlight to the next or the previous command, round from the last to the first. | | Page Down, Page Up | Moves the highlight by as many commands as the list shows at once. | | Home, End, Left, Right | Move the caret in the filter field. | | Enter | Runs the highlighted command, or follows it where it is a link, and closes the palette. On a command with 'opens', shows its page. | | Command or Control with Enter | Takes the highlighted command's 'alternate' destination, where it has one. | | Backspace | In an empty filter on a page, goes back to the page before. | | Escape | Clears the filter. With the filter empty, closes the palette and puts focus back where it was. | | Tab | Stays in the palette, which is modal. With 'inline', moves on through the page. | **ARIA.** The palette is a modal 'dialog' named by 'label', or with 'inline' no dialog at all. Inside it the filter field is a 'combobox' with 'aria-activedescendant' on the highlighted command, and the commands are a 'listbox' of 'option's. How many commands typing left, the empty text and the loading text are said in a polite live region. */
18333
+ /** The list is a 'Listbox', which handles filtering, the empty state, the match highlight, 'aria-activedescendant', scrolling an option into view, and moving between options with the keyboard. The palette adds a dialog and a hotkey that opens it. The palette keeps no value. It is not a form control and submits nothing. Choosing an option dispatches 'helix-select' once. To remember the last command, store it yourself. An option with 'href' is a link to a page, which the browser follows once the palette has closed. The hotkey listener is on the document, so the hotkey works from anywhere on the page, including inside another control's text field, whether or not the palette is open. 'mod' means Command on a Mac and Control elsewhere, so you write one binding. With 'inline', the palette is drawn in the page with no dialog, as a search over a list that is always shown. **Pages.** A command can open a page of commands of its own, as a palette offers "Change theme" and then the themes. Give the option 'opens' with a name, and slot the page's commands as 'page:' and that name: '''html <helix-command> <helix-option value="theme" opens="theme">Change theme</helix-option> <helix-option value="dark" slot="page:theme">Dark</helix-option> <helix-option value="light" slot="page:theme">Light</helix-option> </helix-command> ''' Choosing the opener says 'helix-select' with its value, and canceling it keeps the page that is shown. The list then shows the page, named by the opener's words, and a screen reader hears those words. Backspace in an empty filter goes back, and a screen reader hears the name of the page it goes back to. 'page' says which page is shown. The filter is cleared when the palette closes, so each opening starts from the full list. Combobox and Select do the same. As typing narrows the list, a screen reader hears how many commands are left, such as "3 commands". **Keyboard.** Focus goes to the filter field as the palette opens, and the highlight moves through the commands while you type. | Key | What it does | |---|---| | 'hotkey', Command or Control with K by default | Opens the palette from anywhere on the page, or closes it. With 'inline', puts focus in its filter field. | | Down, Up | Moves the highlight to the next or the previous command, round from the last to the first. | | Page Down, Page Up | Moves the highlight by as many commands as the list shows at once. | | Home, End, Left, Right | Move the caret in the filter field. | | Enter | Runs the highlighted command, or follows it where it is a link, and closes the palette. On a command with 'opens', shows its page. | | Command or Control with Enter | Takes the highlighted command's 'alternate' destination, where it has one. | | Backspace | In an empty filter on a page, goes back to the page before. | | Escape | Clears the filter. With the filter empty, closes the palette and puts focus back where it was. | | Tab | Stays in the palette, which is modal. With 'inline', moves on through the page. | **ARIA.** The palette is a modal 'dialog' named by 'label', or with 'inline' no dialog at all. Inside it the filter field is a text field with 'aria-autocomplete="list"', 'aria-controls' on the list, and 'aria-activedescendant' on the highlighted command, as the field of React Aria's 'Autocomplete' is. The commands are a 'listbox' of 'option's. How many commands typing left, the empty text and the loading text are said in a polite live region. */
18217
18334
  "helix-headless-command": DefineCustomElement<
18218
18335
  HelixHeadlessCommand,
18219
18336
  HelixHeadlessCommandVueProps,
@@ -18279,13 +18396,13 @@ export interface WcToolkitVueGlobalComponents {
18279
18396
  HelixHeadlessDrawerVueProps,
18280
18397
  HelixHeadlessDrawerVueEvents
18281
18398
  >;
18282
- /** A row that opens a page contains that page: the page's rows are this row's own children, assigned to the 'page' slot. There are no ids to wire, and moving a row moves its page with it. What the item renders depends on the stack: - On the page that is showing, it renders its row. - When its own page is showing, it renders only that page's rows. Its row belongs to the page above. - When a page further down its own is showing, it renders its page's slot alone, so the rows below reach the page. - Otherwise it renders nothing. The rows stay in the light DOM untouched, so there is no state to keep. Choosing a row dispatches an event, and the stack decides whether that drills in or runs a command. A row that opens a page shows a caret after its text and sets 'aria-haspopup', the same way 'Menu' marks a row with a submenu. The server render leaves both out, because the server cannot see the children. The row is named by its label alone. Words in 'description', a line under the label, and in 'end' describe it instead, through 'aria-describedby', as 'Menu.Item' does: a reader hears "Theme", then "Dark". */
18399
+ /** A row that opens a page contains that page: the page's rows are this row's own children, assigned to the 'page' slot. There are no ids to wire, and moving a row moves its page with it. What the item renders depends on the stack: - On the page that is showing, it renders its row. - When its own page is showing, it renders only that page's rows. Its row belongs to the page above. - When a page further down its own is showing, it renders its page's slot alone, so the rows below reach the page. - Otherwise it renders nothing. The rows stay in the light DOM untouched, so there is no state to keep. Choosing a row dispatches an event, and the stack decides whether that drills in or runs a command. A row that opens a page shows a caret after its text and sets 'aria-haspopup', the same way 'Menu' marks a row with a submenu. The server render leaves both out, because the server cannot see the children. **A row with an 'href' is a link.** The row itself renders as an '<a>' carrying 'menuitem', as 'Menu.Item' does, so a middle click, a modified click and the status bar keep working. Enter follows it, and Space does too. Choosing it fires 'helix-select' first: cancel the event and the link is not followed, so a router can take the navigation. A row that opens a page, or a disabled row, renders no link. A development build warns when a row has no words to be named by, such as a row holding only an icon with no label. The row is named by its label alone. Words in 'description', a line under the label, and in 'end' describe it instead, through 'aria-describedby', as 'Menu.Item' does: a reader hears "Theme", then "Dark". */
18283
18400
  "helix-headless-drilldown-item": DefineCustomElement<
18284
18401
  HelixHeadlessDrilldownItem,
18285
18402
  HelixHeadlessDrilldownItemVueProps,
18286
18403
  HelixHeadlessDrilldownItemVueEvents
18287
18404
  >;
18288
- /** One panel whose content changes as you move between pages. Use it where there is no room for a second column, such as on a phone, or on a touch screen with no hover to open one. It is a region that stays where you put it, such as inside a drawer, a sidebar, or a settings panel. A 'Menu' opens from a trigger and closes when you are done. 'Menu' can drill into pages too, through the same controller. Rows are places to go and commands to run. Nothing here is form-associated and nothing is submitted. To choose a value, use a 'Listbox'. A row that opens a page contains that page, so the stack holds one reference and reads the rest from the DOM. The behavior lives in 'DrilldownController', which 'Menu' shares. After each move the host carries 'data-direction', 'forward' into a page or 'back' out of one, and records ':state(forward)' or ':state(back)', so a stylesheet can slide the new page in from the side the reader is going. Both are written again on every move, so an animation keyed on them runs for each page, two moves the same way included. The styled tier slides the page and swaps it at once under 'prefers-reduced-motion'. Keys, on a row: Up and Down Arrow move between the rows, Home and End go to the first and the last, and a typed letter moves to the next row whose name starts with it. Enter, Space, or Right Arrow opens a row's page, and Left Arrow or Escape goes back, the two arrows swapping on a right-to-left page. The rows of the page showing are a 'menu', named by 'label' on the top page and by the page's title below it. The back button and the title sit above the menu. Disabled rows stay reachable with the arrow keys, and typing a letter moves to the next row whose name starts with it. */
18405
+ /** One panel whose content changes as you move between pages. Use it where there is no room for a second column, such as on a phone, or on a touch screen with no hover to open one. It is a region that stays where you put it, such as inside a drawer, a sidebar, or a settings panel. A 'Menu' opens from a trigger and closes when you are done. 'Menu' can drill into pages too, through the same controller. Rows are places to go and commands to run. Nothing here is form-associated and nothing is submitted. To choose a value, use a 'Listbox'. A row that opens a page contains that page, so the stack holds one reference and reads the rest from the DOM. The behavior lives in 'DrilldownController', which 'Menu' shares. **'page' is the page showing**, as the 'value' of the row that opens it, and empty on the top page. Set it to show a page, such as one a link to a settings screen names. A reader's move updates it, and 'helix-navigate' comes first, so you can refuse the move or take it yourself. After each move the host carries 'data-direction', 'forward' into a page or 'back' out of one, and records ':state(forward)' or ':state(back)', so a stylesheet can slide the new page in from the side the reader is going. Both are written again on every move, so an animation keyed on them runs for each page, two moves the same way included. The styled tier slides the page and swaps it at once under 'prefers-reduced-motion'. **Keyboard.** The drilldown is one tab stop, on the row last focused. | Key | What it does | |---|---| | Down Arrow, Up Arrow | Moves to the next or the previous row. | | Home, End | Moves to the first or the last row. | | A letter | Moves to the next row whose name starts with it. | | Enter, Space | Chooses the row: opens its page, follows its link, or sends 'helix-select'. | | Right Arrow | Opens the row's page. Left Arrow on a right-to-left page. | | Left Arrow, Escape | Goes back one page, with focus on the row that opened it. Right Arrow on a right-to-left page. | The rows of the page showing are a 'menu', named by 'label' on the top page and by the page's title below it. **'navigation' makes it a site's navigation.** The host is a 'navigation' landmark named by 'label', each page is a list, and each row is a list item holding a link or a button, as the APG's disclosure navigation is built, so a reader meets places to go in place of a menu of commands. The keys stay the same. The back button and the title sit above the menu. Disabled rows stay reachable with the arrow keys, and typing a letter moves to the next row whose name starts with it. */
18289
18406
  "helix-headless-drilldown": DefineCustomElement<
18290
18407
  HelixHeadlessDrilldown,
18291
18408
  HelixHeadlessDrilldownVueProps,
@@ -18411,13 +18528,13 @@ export interface WcToolkitVueGlobalComponents {
18411
18528
  HelixHeadlessListItemVueProps,
18412
18529
  HelixHeadlessListItemVueEvents
18413
18530
  >;
18414
- /** Sets 'role="list"' on the host, so a screen reader counts the rows and announces each one's position, such as "1 of 7". **'selection-mode' makes the list interactive**, in the way of a grid list: a grid of rows that is one tab stop. 'single' selects one row at a time and 'multiple' any number, and 'value' holds the selected rows' values, separated by commas. A change asks with 'helix-before-change' and tells with 'change'. 'none' selects nothing, so a press acts on the row. A 'disabled' row is passed over. Each row is named by its label and described by its description, so the words of the controls in 'end' are not read as part of its name. 'selection-behavior' says what a press does to the rows already selected. 'toggle', the default, adds or takes out the row. 'replace' selects the row alone, as a file list does, and the arrow keys carry the selection with them. Control or Command with a press then adds or takes out one row. | Key | What it does | |---|---| | Down, Up | Moves to the next or the previous row. Under 'replace', selects it. | | Home, End | Moves to the first or the last row. Under 'replace', selects it. | | Page Down, Page Up | Moves a box's height of rows, so the row at one edge lands at the other. Under 'replace', selects the row it lands on. | | A letter or a word | Moves to the next row whose words start with what you typed. | | Left, Right | Moves between the row and the controls in its 'end' slot. | | Space | Selects the row, or lets it go. | | Shift with Down, Up, Home, End, Page Down, Page Up or Space | Selects every row from the last one pressed, in 'multiple'. | | Control or Command with Down, Up, Home, End, Page Down or Page Up | Moves without selecting, under 'replace'. | | Control or Command with A | Selects every row, in 'multiple'. | | Escape | Lets go of every selected row, asking first, and keeps the key from the dialog or menu around the list. With nothing selected, the key goes on to them. | | Enter | Acts on the row: follows its link, or sends 'helix-action' from it. | A press with Shift selects every row from the last one pressed, and a press with Control or Command adds or takes out one row under 'replace'. **Leave 'selection-mode' unset for a list a reader reads**, and set it for one a reader chooses from or acts on. The rows of an interactive list are grid rows, which hold controls as a list box option cannot. Give a control in 'end' 'tabindex="-1"' to leave it to the arrow keys and out of the tab order. **'reorderable' lets you move rows.** Each row gets a grip after its 'end' slot, named by 'move-label'. Drag a grip to move its row, and the list scrolls near an edge. Or press a grip with Space, Enter, or a click to pick up its row, move it with the arrow keys, and press the grip again to drop it. A click on another row drops it there, and Escape puts it back. The list says each step in its 'live' region. A drop sends 'helix-before-reorder', which you can refuse, and then 'helix-reorder', whose 'keys' hold every row's value in the new order. **You move the rows**: the list moves no element of yours, so your framework keeps the order it rendered. | Key, on a held row's grip | What it does | |---|---| | Down, Up | Moves the row one place. | | Home, End | Moves the row to the top or the bottom. | | Space, Enter | Drops the row. | | Escape | Puts the row back where it was. | 'start' and 'reversed' number an ordered list as '<ol>' does. The list writes where the numbers start and which way they run as '--list-first' and '--list-step' on its slot, which the styled tier counts from. Reversed with no 'start' counts down from the number of rows, which a server cannot know, so served markup counts from one until the list runs. **An empty list.** Set 'empty-label', or put your own content in the 'empty' slot, for a row shown while the list has no rows and none are loading, such as "No files yet" and a link to add one. Without either, an empty list shows nothing. The list takes the 'empty' state while it has no rows, whatever it shows. **Loading more.** 'load-more' sends 'helix-load-more' once the end of the list comes within a screen of view, in the box that scrolls it or the page, once for each number of rows: add rows and it can send it again. While you fetch, set 'loading': the list is busy, and a row after the last says "Loading more" ('loading-label', or your own content in the 'loading' slot). The list asks for nothing while 'loading' is set. An interactive list with no name is reported once in a development build, since a screen reader announces it as a grid and nothing more. Name it with 'label' or 'aria-label'. */
18531
+ /** Sets 'role="list"' on the host, so a screen reader counts the rows and announces each one's position, such as "1 of 7". **'selection-mode' makes the list interactive**, in the way of a grid list: a grid of rows that is one tab stop. 'single' selects one row at a time and 'multiple' any number, and 'value' holds the selected rows' values, separated by commas. A change asks with 'helix-before-change' and tells with 'change'. 'none' selects nothing, so a press acts on the row. A 'disabled' row is passed over. With 'disabled-behavior="selection"', a 'disabled' row cannot be selected, and is reached and acted on as any row is, as React Aria's GridList has it. Each row is named by its label and described by its description, so the words of the controls in 'end' are not read as part of its name. 'selection-behavior' says what a press does to the rows already selected. 'toggle', the default, adds or takes out the row. 'replace' selects the row alone, as a file list does, and the arrow keys carry the selection with them. Control or Command with a press then adds or takes out one row. | Key | What it does | |---|---| | Down, Up | Moves to the next or the previous row. Under 'replace', selects it. | | Home, End | Moves to the first or the last row. Under 'replace', selects it. | | Page Down, Page Up | Moves a box's height of rows, so the row at one edge lands at the other. Under 'replace', selects the row it lands on. | | A letter or a word | Moves to the next row whose words start with what you typed. | | Left, Right | Moves between the row and the controls in its 'end' slot. | | Space | Selects the row, or lets it go. | | Shift with Down, Up, Home, End, Page Down, Page Up or Space | Selects every row from the last one pressed, in 'multiple'. | | Control or Command with Down, Up, Home, End, Page Down or Page Up | Moves without selecting, under 'replace'. | | Control or Command with A | Selects every row, in 'multiple'. | | Escape | Lets go of every selected row, asking first, and keeps the key from the dialog or menu around the list. With nothing selected, the key goes on to them. | | Enter | Acts on the row: follows its link, or sends 'helix-action' from it. | A press with Shift selects every row from the last one pressed, and a press with Control or Command adds or takes out one row under 'replace'. **Leave 'selection-mode' unset for a list a reader reads**, and set it for one a reader chooses from or acts on. The rows of an interactive list are grid rows, which hold controls as a list box option cannot. Give a control in 'end' 'tabindex="-1"' to leave it to the arrow keys and out of the tab order. **'reorderable' lets you move rows.** Each row gets a grip after its 'end' slot, named by 'move-label'. Drag a grip to move its row, and the list scrolls near an edge. Or press a grip with Space, Enter, or a click to pick up its row, move it with the arrow keys, and press the grip again to drop it. A click on another row drops it there, and Escape puts it back. The list says each step in its 'live' region. A drop sends 'helix-before-reorder', which you can refuse, and then 'helix-reorder', whose 'keys' hold every row's value in the new order. **You move the rows**: the list moves no element of yours, so your framework keeps the order it rendered. | Key, on a held row's grip | What it does | |---|---| | Down, Up | Moves the row one place. | | Home, End | Moves the row to the top or the bottom. | | Space, Enter | Drops the row. | | Escape | Puts the row back where it was. | 'start' and 'reversed' number an ordered list as '<ol>' does. The list writes where the numbers start and which way they run as '--list-first' and '--list-step' on its slot, which the styled tier counts from. Reversed with no 'start' counts down from the number of rows, which a server cannot know, so served markup counts from one until the list runs. **An empty list.** Set 'empty-label', or put your own content in the 'empty' slot, for a row shown while the list has no rows and none are loading, such as "No files yet" and a link to add one. Without either, an empty list shows nothing. The list takes the 'empty' state while it has no rows, whatever it shows. **Loading more.** 'load-more' sends 'helix-load-more' once the end of the list comes within a screen of view, in the box that scrolls it or the page, once for each number of rows: add rows and it can send it again. While you fetch, set 'loading': the list is busy, and a row after the last says "Loading more" ('loading-label', or your own content in the 'loading' slot). The list asks for nothing while 'loading' is set. An interactive list with no name is reported once in a development build, since a screen reader announces it as a grid and nothing more. Name it with 'label' or 'aria-label'. */
18415
18532
  "helix-headless-list": DefineCustomElement<
18416
18533
  HelixHeadlessList,
18417
18534
  HelixHeadlessListVueProps,
18418
18535
  HelixHeadlessListVueEvents
18419
18536
  >;
18420
- /** The listbox is the control, and options are its items. A Select is a listbox with a trigger in front of it, a Combobox is a listbox with a text input, and a command palette is a listbox in a dialog. They differ only in what opens the list and what filters it. With 'multiple' set, 'value' is a comma-separated string, like 'Checkbox.Group''s, because 'MixinControllerValue' holds a string. The form receives one entry per selected option, as a native '<select multiple>' sends it, so your server does not split on commas. Selected and active are separate. The selected option is the value. The active option is where the keyboard is: the arrow keys move it, and 'aria-activedescendant' points to it while focus stays on the list. **Keyboard.** The list is one tab stop, or its filter field is where there is one. In a single-choice list the highlight is the choice unless 'manual' is set; then Enter, Space or a click chooses. | Key | What it does | |---|---| | Down, Up | Moves the highlight to the next or the previous option, round from the last to the first. With 'layout="grid"', to the option below or above, stopping at the edge. | | Right, Left | With 'layout="grid"', moves to the next or the previous option, mirrored right to left. In a filter field, moves the caret. | | Home, End | Moves to the first or the last option. In a filter field, moves the caret. | | Page Down, Page Up | Moves by as many options as the list shows at once. | | A letter or a word | Moves to the next option whose words start with what you typed. In a filter field, types it. | | Enter | Chooses the highlighted option, or follows it where it is a link. | | Space | Chooses the highlighted option, or with 'multiple' toggles it. In a filter field, types a space. | | Shift with Down or Up | With 'multiple', adds the option the highlight moves to. In a filter field, moves the highlight and leaves the value. | | Shift with Space | With 'multiple', adds every option from the one last chosen to the highlighted one. In a filter field, types a space. | | Shift with Home or End | With 'multiple', adds every option from the highlight to that end. In a filter field, hold Control as well. | | Control or Command with A | With 'multiple', chooses every option, or none where all are chosen. In a filter field, selects the text. | | Escape | In a filter field, clears the filter. | | Alt with Up or Down | In a 'reorderable' list, moves the highlighted option a place. Alt with Home or End moves it to either end. | **ARIA.** The 'items' part is the 'listbox', named by the label and described by the hint and the message, with 'aria-multiselectable' under 'multiple', 'aria-required', 'aria-invalid', and 'aria-busy' while loading. Each option is an 'option' with 'aria-selected'. The list, or its filter field, points 'aria-activedescendant' at the highlighted option; the field is 'aria-autocomplete="list"' and controls the list. An option with 'href' is a link: Enter or a press follows it and selects nothing, and moving onto it with the arrows does not follow it. As a filter narrows the list, a screen reader hears how many options are left, such as "3 results", from 'result-label' and 'results-label'. A filter that leaves none says 'empty-text'. **Moving options** is a separate import, '@fusion.dev/helix/listbox/reorder', so a list that never moves options carries none of its code. With it imported, 'reorderable' lets a reader move options: - Alt with Up or Down moves the highlighted option a place, and Alt with Home or End moves it to either end, as the APG's rearrangeable listbox does. The highlight stays on it. - A pointer drags an option, with a drop indicator, and the list scrolls near an edge. A press that does not travel still chooses the option. - A drop sends 'helix-before-reorder', which you can refuse, and then 'helix-reorder', whose 'keys' hold every value in the new order. **You move the options**, or set 'items' in the new order: the list moves no element of yours. - The list says each move in its 'live' region. The words are the 'moved-label', 'canceled-label', 'dropped-label', and 'picked-up-label' attributes, which the import reads. - An option in a group moves within its group. Options do not move while a filter narrows the list, under 'layout="grid"', or while the list is disabled. */
18537
+ /** The listbox is the control, and options are its items. A Select is a listbox with a trigger in front of it, a Combobox is a listbox with a text input, and a command palette is a listbox in a dialog. They differ only in what opens the list and what filters it. With 'multiple' set, 'value' is a comma-separated string, like 'Checkbox.Group''s, because 'MixinControllerValue' holds a string. The form receives one entry per selected option, as a native '<select multiple>' sends it, so your server does not split on commas. An option's value may hold a comma: a run of the string that is an option's value is read as that one value, and the form sends it as one entry. Selected and active are separate. The selected option is the value. The active option is where the keyboard is: the arrow keys move it, and 'aria-activedescendant' points to it while focus stays on the list. **Keyboard.** The list is one tab stop, or its filter field is where there is one. In a single-choice list the highlight is the choice unless 'manual' is set; then Enter, Space or a click chooses. | Key | What it does | |---|---| | Down, Up | Moves the highlight to the next or the previous option, round from the last to the first. With 'layout="grid"', to the option below or above, stopping at the edge. | | Right, Left | With 'layout="grid"', moves to the next or the previous option, mirrored right to left. In a filter field, moves the caret. | | Home, End | Moves to the first or the last option. In a filter field, moves the caret. | | Page Down, Page Up | Moves by as many options as the list shows at once. | | A letter or a word | Moves to the next option whose words start with what you typed. In a filter field, types it. | | Enter | Chooses the highlighted option, or follows it where it is a link. | | Space | Chooses the highlighted option, or with 'multiple' toggles it. In a filter field, types a space. | | Shift with Down or Up | With 'multiple', adds the option the highlight moves to. In a filter field, moves the highlight and leaves the value. | | Shift with Space | With 'multiple', adds every option from the one last chosen to the highlighted one. In a filter field, types a space. | | Shift with Home or End | With 'multiple', adds every option from the highlight to that end. In a filter field, hold Control as well. | | Control or Command with A | With 'multiple', chooses every option, or none where all are chosen. In a filter field, selects the text. | | Escape | In a filter field, clears the filter. | | Alt with Up or Down | In a 'reorderable' list, moves the highlighted option a place. Alt with Home or End moves it to either end. | **ARIA.** The 'items' part is the 'listbox', named by the label and described by the hint and the message, with 'aria-multiselectable' under 'multiple', 'aria-required', 'aria-invalid', and 'aria-busy' while loading. Each option is an 'option' with 'aria-selected'. The list, or its filter field, points 'aria-activedescendant' at the highlighted option; the field is 'aria-autocomplete="list"' and controls the list. An option with 'href' is a link: Enter or a press follows it and selects nothing, and moving onto it with the arrows does not follow it. As a filter narrows the list, a screen reader hears how many options are left, such as "3 results", from 'result-label' and 'results-label'. A filter that leaves none says 'empty-text'. **Moving options** is a separate import, '@fusion.dev/helix/listbox/reorder', so a list that never moves options carries none of its code. With it imported, 'reorderable' lets a reader move options: - Alt with Up or Down moves the highlighted option a place, and Alt with Home or End moves it to either end, as the APG's rearrangeable listbox does. The highlight stays on it. - A pointer drags an option, with a drop indicator, and the list scrolls near an edge. A press that does not travel still chooses the option. - A drop sends 'helix-before-reorder', which you can refuse, and then 'helix-reorder', whose 'keys' hold every value in the new order. **You move the options**, or set 'items' in the new order: the list moves no element of yours. - The list says each move in its 'live' region. The words are the 'moved-label', 'canceled-label', 'dropped-label', and 'picked-up-label' attributes, which the import reads. - An option in a group moves within its group. Options do not move while a filter narrows the list, under 'layout="grid"', or while the list is disabled. */
18421
18538
  "helix-headless-listbox": DefineCustomElement<
18422
18539
  HelixHeadlessListbox,
18423
18540
  HelixHeadlessListboxVueProps,
@@ -18495,19 +18612,19 @@ export interface WcToolkitVueGlobalComponents {
18495
18612
  HelixHeadlessMapTerrainVueProps,
18496
18613
  HelixHeadlessMapTerrainVueEvents
18497
18614
  >;
18498
- /** A disclosure: a button that shows and hides a region of your own links. It does not use 'role="menu"' or 'menuitem', which are for application commands. Those roles take over the arrow keys, announce "menu" to someone looking for navigation, and put every link inside a role that is not a link. As a disclosure, middle clicks, modified clicks, and the status bar keep working. Use 'Menu' for a row of commands. It renders no links. A router renders its own anchors and cannot render them inside this shadow root, so the panel is a slot for the lists and headings you write. It opens on hover by default, and a press always opens it too. 'open-on' sets which. Hover is the default because in a navigation bar people expect to move along the row and see each section. When one panel opens in place of another, each says which way the reader moved, as Radix's 'data-motion' does. Moving toward the end of the bar, the one opening is ':state(from-end)' and the one closing is ':state(to-start)'; moving back, they are ':state(from-start)' and ':state(to-end)'. A stylesheet slides them on that. Start and end follow the reading direction, so on a right-to-left page the end is on the left. A panel that opens or closes on its own carries none of the four. A press on another megamenu's trigger hands over the same way as hovering it. While a panel is open its surface carries its own size, as '--megamenu-surface-inline-size' and '--megamenu-surface-block-size', and a panel that took over from another also carries that one's size, as '--megamenu-from-inline-size' and '--megamenu-from-block-size'. Radix's navigation menu publishes the same pair from its shared viewport, so a stylesheet can grow or shrink one panel into the next. The panel's default slot is the 'columns' part and draws no box, so a sheet can give the columns one of their own. While a panel is open, an 'indicator' slot is rendered beside its trigger, as Radix's indicator marks the open one: slot a mark of your own, such as a bar or an arrow pointing at the panel, and it shows only while the panel is open. The styled tier rests it on the trigger's bottom edge. Left and Right Arrow move between the triggers of the megamenus beside this one, and Home and End go to the first and the last, as Radix's navigation menu does. In a 'Navigation', which holds them in a slot, the arrows are the navigation's, and move between its destinations under its 'arrows'. Down Arrow on the trigger of an open panel moves focus to the panel's first link, Escape closes the panel and returns focus to its trigger, and Tab moves through the panel's links and closes it on the way out. The trigger says 'aria-expanded', and the panel is a group named by 'label'. */
18615
+ /** A disclosure: a button that shows and hides a region of your own links. It does not use 'role="menu"' or 'menuitem', which are for application commands. Those roles take over the arrow keys, announce "menu" to someone looking for navigation, and put every link inside a role that is not a link. As a disclosure, middle clicks, modified clicks, and the status bar keep working. Use 'Menu' for a row of commands. It renders no links. A router renders its own anchors and cannot render them inside this shadow root, so the panel is a slot for the lists and headings you write. It opens on hover by default, and a press always opens it too. 'open-on' sets which. Hover is the default because in a navigation bar people expect to move along the row and see each section. A pointer resting on the trigger opens the panel after 'open-delay', and leaving closes it after 'close-delay'. Moving from one open panel's trigger to another's opens the next at once, as Radix's 'skipDelayDuration' does. When one panel opens in place of another, each says which way the reader moved, as Radix's 'data-motion' does. Moving toward the end of the bar, the one opening is ':state(from-end)' and the one closing is ':state(to-start)'; moving back, they are ':state(from-start)' and ':state(to-end)'. A stylesheet slides them on that. Start and end follow the reading direction, so on a right-to-left page the end is on the left. A panel that opens or closes on its own carries none of the four. A press on another megamenu's trigger hands over the same way as hovering it. While a panel is open its surface carries its own size, as '--megamenu-surface-inline-size' and '--megamenu-surface-block-size', and a panel that took over from another also carries that one's size, as '--megamenu-from-inline-size' and '--megamenu-from-block-size'. Radix's navigation menu publishes the same pair from its shared viewport, so a stylesheet can grow or shrink one panel into the next. While a link in the panel carries 'aria-current="page"', the host has ':state(current)', so the trigger of the section holding the page you are on can say so, as Radix's navigation menu marks its active link. The panel's default slot is the 'columns' part and draws no box, so a sheet can give the columns one of their own. While a panel is open, an 'indicator' slot is rendered beside its trigger, as Radix's indicator marks the open one: slot a mark of your own, such as a bar or an arrow pointing at the panel, and it shows only while the panel is open. The styled tier rests it on the trigger's bottom edge. Left and Right Arrow move between the triggers of the megamenus beside this one, and Home and End go to the first and the last, as Radix's navigation menu does. In a 'Navigation', which holds them in a slot, the arrows are the navigation's, and move between its destinations under its 'arrows'. Down Arrow on the trigger of an open panel moves focus to the panel's first link, Escape closes the panel and returns focus to its trigger, and Tab moves through the panel's links and closes it on the way out. The trigger says 'aria-expanded', and the panel is a group named by 'label'. A Helix trigger, such as 'helix-button', is told whether the panel is open inside its own shadow root. On a plain element, such as a '<button>', the megamenu writes 'aria-expanded', from a frame after its own first render, so a server's markup is never changed while a framework hydrates it. It never writes it where you wrote 'aria-expanded' yourself. */
18499
18616
  "helix-headless-megamenu": DefineCustomElement<
18500
18617
  HelixHeadlessMegamenu,
18501
18618
  HelixHeadlessMegamenuVueProps,
18502
18619
  HelixHeadlessMegamenuVueEvents
18503
18620
  >;
18504
- /** One element covers three kinds of row, and what you give it decides which: - Content in the 'submenu' slot makes the row open a submenu page. - 'checked' makes the row a choice. - With neither, the row is a command. The role follows the kind. A row with 'checked' is 'menuitemcheckbox' with 'aria-checked', and 'exclusive' makes it 'menuitemradio', for a set where only one can be on. A row that opens a page keeps 'menuitem' and sets 'aria-haspopup'. Choosing a choice row checks or unchecks it before 'helix-select' is sent, so a listener reads the new 'checked'. An 'exclusive' row turns on and turns off the 'exclusive' rows next to it. Cancel 'helix-before-toggle' to keep a row as it is and set 'checked' yourself. The menu sets whether the row's page is showing as a property, never as an attribute. An attribute written onto your element after it upgrades causes a hydration mismatch. 'shortcut' shows a row's keyboard shortcut after its label, drawn by 'Kbd' in the platform's glyphs, and gives the row 'aria-keyshortcuts'. It binds nothing: the shortcut is the page's to bind. Other trailing words, such as a count, go in the 'end' slot. The row is named by its label alone. Words in 'description', a line under the label, and in 'end' describe it instead, through 'aria-describedby', as React Aria's menu item does with its description: a reader hears "Copy", then "Copies the selection". The check mark and the caret are the fallbacks of the 'check' and 'chevron' slots, so a mark of your own replaces either by being slotted. Neither is read as part of the row's name. */
18621
+ /** One element covers three kinds of row, and what you give it decides which: - Content in the 'submenu' slot makes the row open a submenu page. - 'checked' makes the row a choice. - With neither, the row is a command. The role follows the kind. A row with 'checked' is 'menuitemcheckbox' with 'aria-checked', and 'exclusive' makes it 'menuitemradio', for a set where only one can be on. A row that opens a page keeps 'menuitem' and sets 'aria-haspopup'. Choosing a choice row checks or unchecks it before 'helix-select' is sent, so a listener reads the new 'checked'. An 'exclusive' row turns on and turns off the 'exclusive' rows next to it. Cancel 'helix-before-toggle' to keep a row as it is and set 'checked' yourself. The menu sets whether the row's page is showing as a property, never as an attribute. An attribute written onto your element after it upgrades causes a hydration mismatch. 'shortcut' shows a row's keyboard shortcut after its label, drawn by 'Kbd' in the platform's glyphs, and gives the row 'aria-keyshortcuts'. It binds nothing: the shortcut is the page's to bind. Other trailing words, such as a count, go in the 'end' slot. The row is named by its label alone. Words in 'description', a line under the label, and in 'end' describe it instead, through 'aria-describedby', as React Aria's menu item does with its description: a reader hears "Copy", then "Copies the selection". A development build warns when a row has no words to be named by, such as a row holding only an icon with no label. The check mark and the caret are the fallbacks of the 'check' and 'chevron' slots, so a mark of your own replaces either by being slotted. Neither is read as part of the row's name. */
18505
18622
  "helix-headless-menu-item": DefineCustomElement<
18506
18623
  HelixHeadlessMenuItem,
18507
18624
  HelixHeadlessMenuItemVueProps,
18508
18625
  HelixHeadlessMenuItemVueEvents
18509
18626
  >;
18510
- /** The trigger is slotted and stays your own element, as with the tooltip. The menu renders its surface in the top layer with the popover API, so an ancestor with 'overflow: hidden' does not clip it and it needs no 'z-index'. Slot a 'helix-button' or 'helix-icon-button' as the trigger, and the menu tells it that it opens a menu and whether the menu is open. A plain '<button>' can only be told by writing attributes onto your markup, which the menu does not do, so give it 'aria-haspopup="menu"' and set its 'aria-expanded' from the 'toggle' event. Submenus drill down. A submenu replaces the panel's content, and a back row returns to the previous page. One panel avoids the diagonal pointer path that side-by-side panels need, stays inside a narrow window, and works on touch screens, which have no hover. The root holds which page is open, because only one page shows at a time. It sets this on items as a property, never as an attribute. An attribute written onto your element after it upgrades causes a hydration mismatch. Group rows under a heading with 'Menu.Section', which is a 'group' named by its heading. Between runs of rows, a '<helix-divider>' is a separator a screen reader announces. Keys: Enter, Space or Down Arrow on the trigger opens the menu on its first row, and Up Arrow on its last. In the menu, Up and Down Arrow move between rows, Home and End go to the first and the last, a typed letter moves to the next row whose name starts with it, Enter and Space choose, Right Arrow opens a row's submenu and Left Arrow goes back, the two swapping on a right-to-left page, and Escape closes the menu and returns focus to the trigger. Tab closes it and moves on. While it is open, the surface carries the trigger's width as '--floating-anchor-inline-size' and the room left below it as '--floating-available-block-size', as Radix's dropdown menu publishes its trigger's width, for a menu as wide as its trigger: 'helix-menu::part(surface) { min-inline-size: var(--floating-anchor-inline-size) }'. With 'context', the trigger is an area and the menu is its context menu: a right-click, a long press, Shift+F10 or the menu key over the area opens it at the pointer, or at the area's corner from the keyboard, as Radix's context menu does. A press on the area does not open it, and closing it returns focus to where it was. */
18627
+ /** The trigger is slotted and stays your own element, as with the tooltip. The menu renders its surface in the top layer with the popover API, so an ancestor with 'overflow: hidden' does not clip it and it needs no 'z-index'. Slot a 'helix-button' or 'helix-icon-button' as the trigger, and the menu tells it that it opens a menu and whether the menu is open, inside its own shadow root. On a plain element, such as a '<button>', the menu writes 'aria-haspopup="menu"' and 'aria-expanded', from a frame after its own first render, so a server's markup is never changed while a framework hydrates it. It never writes 'aria-expanded' where you wrote it yourself. Submenus drill down by default. A submenu replaces the panel's content, and a back row returns to the previous page. One panel stays inside a narrow window, and works on touch screens, which have no hover. **'submenus="flyout"' opens each submenu in a panel of its own beside its row**, as React Aria's 'SubmenuTrigger' and Radix's 'Sub' do. Resting the pointer on the row opens it, and a pointer crossing toward the open panel over the rows between keeps it open, as Radix's grace area does. Right Arrow opens a row's submenu on its first row, and Left Arrow or Escape closes it and returns focus to the row, the two arrows swapping on a right-to-left page. The row says 'aria-expanded', and the panel is a 'menu' named by the row. The root holds which page is open, because only one page shows at a time. It sets this on items as a property, never as an attribute. An attribute written onto your element after it upgrades causes a hydration mismatch. Group rows under a heading with 'Menu.Section', which is a 'group' named by its heading. Between runs of rows, a '<helix-divider>' is a separator a screen reader announces. Keys: Enter, Space or Down Arrow on the trigger opens the menu on its first row, and Up Arrow on its last. In the menu, Up and Down Arrow move between rows, Home and End go to the first and the last, a typed letter moves to the next row whose name starts with it, Enter and Space choose, Right Arrow opens a row's submenu and Left Arrow goes back, the two swapping on a right-to-left page. Left Arrow on the top page does nothing. Escape closes the menu and returns focus to the trigger. Tab closes it and moves on. While it is open, the surface carries the trigger's width as '--floating-anchor-inline-size' and the room left below it as '--floating-available-block-size', as Radix's dropdown menu publishes its trigger's width, for a menu as wide as its trigger: 'helix-menu::part(surface) { min-inline-size: var(--floating-anchor-inline-size) }'. With 'context', the trigger is an area and the menu is its context menu: a right-click, a long press, Shift+F10 or the menu key over the area opens it at the pointer, or at the area's corner from the keyboard, as Radix's context menu does. A press on the area does not open it, and closing it returns focus to where it was. A touch or a pen held still on the area opens it too, on every browser, since iOS sends no 'contextmenu' for one. **A trigger with its own action.** With 'open-on="long-press"', a press on the trigger is the trigger's own, and a press held for half a second opens the menu, as React Aria's 'trigger="longPress"' does. Alt+Down or Alt+Up opens it from the keyboard, and the trigger is described by 'long-press-label', which says so. */
18511
18628
  "helix-headless-menu": DefineCustomElement<
18512
18629
  HelixHeadlessMenu,
18513
18630
  HelixHeadlessMenuVueProps,
@@ -18543,13 +18660,13 @@ export interface WcToolkitVueGlobalComponents {
18543
18660
  HelixHeadlessNotificationVueProps,
18544
18661
  HelixHeadlessNotificationVueEvents
18545
18662
  >;
18546
- /** Notifications are slotted children. Each one is your own markup, with an avatar, a link, or a button in it. Feeds usually hold tens of items, so writing them out lets an item hold anything. The list does not virtualize. Windowing needs the list to own the data, and here you own it, so N notifications are N elements. For a feed of thousands, use a data table with a custom cell. Read state is reported to you. Marking read goes from the root to the item and from the item to you, so a canceled 'helix-read' changes nothing, and if you own 'read', nothing changes until you set it. 'unread' is derived from the items and written to an attribute, so a stylesheet and a badge can both use it without counting. **The feed is one 'Tab' stop for its rows.** Each row takes focus itself and is read by its label. 'ArrowDown' and 'ArrowUp' move to the next and the previous row, 'Home' and 'End' to the first and the last, and 'PageDown' and 'PageUp' move a row on or back from anywhere inside one, as in the APG feed pattern. The controls inside a row stay in the 'Tab' order. Set 'total' when the feed holds one page of a longer list, and each row says its place in the whole of it. **Keyboard.** | Key | What it does | |---|---| | Down, Up | On a row, moves to the next or the previous row. | | Home, End | On a row, moves to the first or the last row. | | Page Down, Page Up | From anywhere in a row, moves to the next or the previous row. | | Control+End | From anywhere in the feed, moves to the first control after it on the page. | | Control+Home | From anywhere in the feed, moves to the nearest control before it on the page. | | Tab | Moves through the controls in a row, and on out of the feed. | **'load-more' adds a button after the list** that sends 'helix-load-more', for a feed that holds one page of a longer list. Append the next page, set 'loading' while it is on its way, and take 'load-more' off once there is nothing more. While the feed is loading the button stays, so focus stays on it, and it is 'aria-disabled' and sends nothing. **'load-error' says a page could not be fetched**, such as "Could not load notifications": it shows under the rows there are, in the 'error' part, in place of the empty and loading lines, and a screen reader hears it. Clear it when you ask again. */
18663
+ /** Notifications are slotted children. Each one is your own markup, with an avatar, a link, or a button in it. Feeds usually hold tens of items, so writing them out lets an item hold anything. The list does not virtualize. Windowing needs the list to own the data, and here you own it, so N notifications are N elements. For a feed of thousands, use a data table with a custom cell. Read state is reported to you. Marking read goes from the root to the item and from the item to you, so a canceled 'helix-read' changes nothing, and if you own 'read', nothing changes until you set it. 'unread' is derived from the items and written to an attribute, so a stylesheet and a badge can both use it without counting. **The feed is one 'Tab' stop for its rows.** Each row takes focus itself and is read by its label. 'ArrowDown' and 'ArrowUp' move to the next and the previous row, 'Home' and 'End' to the first and the last, and 'PageDown' and 'PageUp' move a row on or back from anywhere inside one, as in the APG feed pattern. The controls inside a row stay in the 'Tab' order. Set 'total' when the feed holds one page of a longer list, and each row says its place in the whole of it. **Keyboard.** | Key | What it does | |---|---| | Down, Up | On a row, moves to the next or the previous row. | | Home, End | On a row, moves to the first or the last row. | | Page Down, Page Up | From anywhere in a row, moves to the next or the previous row. | | Control+End | From anywhere in the feed, moves to the first control after it on the page. | | Control+Home | From anywhere in the feed, moves to the nearest control before it on the page. | | Tab | Moves through the controls in a row, and on out of the feed. | **A notification that arrives says so.** Unread rows added above the rows there were are counted in the live region, "1 new notification", in 'arrived-label'. Rows that arrive while 'loading' is set say nothing, so set it while a page is on its way. **'load-more' adds a button after the list** that sends 'helix-load-more', for a feed that holds one page of a longer list. Append the next page, set 'loading' while it is on its way, and take 'load-more' off once there is nothing more. While the feed is loading the button stays, so focus stays on it, and it is 'aria-disabled' and sends nothing. **'load-error' says a page could not be fetched**, such as "Could not load notifications": it shows under the rows there are, in the 'error' part, in place of the empty and loading lines, and a screen reader hears it. Clear it when you ask again. */
18547
18664
  "helix-headless-notifications": DefineCustomElement<
18548
18665
  HelixHeadlessNotifications,
18549
18666
  HelixHeadlessNotificationsVueProps,
18550
18667
  HelixHeadlessNotificationsVueEvents
18551
18668
  >;
18552
- /** A separate family from 'Input''s 'type="number"'. It renders two buttons, binds four keys 'Input' does not, and handles clamping and stepping. The field is 'type="text"' with 'inputmode="decimal"'. Tested in a real browser, 'type="number"' fails in three ways: - Typing '12e' gives a '.value' of '""', so the element cannot see what you typed. A 'type="text"' field keeps '"12e"'. - The mouse wheel over a focused field changes the value, for example from 5 to 4, when you only meant to scroll the page. - 'selectionStart' is 'null', so the caret cannot be managed. 'inputmode="decimal"' keeps the numeric keypad on phones. 'format-options' shows the number with 'Intl.NumberFormat' in 'locale', as a currency, a percent or a unit, while the field is not being edited. Focus shows the number itself, and a typed '$1,200' or '25%' is read back with the same options. The value stays the plain number: '1200', or '0.25' for 25%. The locale's group separators are read in every field, so '1,234' is a number in 'en-US'. The field and its two buttons sit in a 'role="group"', and the field carries 'role-label', "number field" in English, as its 'aria-roledescription', as React Aria's NumberField does. On iOS and iPadOS the field is a plain text field, with no 'role="spinbutton"', which VoiceOver reads as a slider you cannot type in, and no role description, so VoiceOver says the field is required. React Aria's NumberField does the same. Validity follows the platform's rules: 'min', 'max', and 'step' are checked and reported through the host's own 'setValidity', under the platform's flag names. Stepping is separate from typing, so a number is not corrected while you type it. While you type, the form holds the number the text reads as, so a field showing '$2,500.50' gives the form 2500.5, and text that is not a number gives it nothing, as a native number field does. Holding a stepper button down steps once, then again after 400 milliseconds, then every 60 milliseconds until you let go, as React Aria's NumberField does. **Keyboard.** The field is one tab stop, and the stepper buttons are not in the tab order. | Key | What it does | |---|---| | Up, Down | Steps the value up or down by 'step'. | | Page Up, Page Down | Steps by 'large-step' steps, ten by default. | | Home, End | Goes to 'min' or 'max', where there is one. Without one, moves the caret. | | Enter | Commits the typed number and submits the form, as a native field does. | The field has 'role="spinbutton"' with 'aria-valuenow', 'aria-valuemin', 'aria-valuemax', and the formatted text in 'aria-valuetext'. */
18669
+ /** A separate family from 'Input''s 'type="number"'. It renders two buttons, binds four keys 'Input' does not, and handles clamping and stepping. The field is 'type="text"' with 'inputmode="decimal"'. Tested in a real browser, 'type="number"' fails in three ways: - Typing '12e' gives a '.value' of '""', so the element cannot see what you typed. A 'type="text"' field keeps '"12e"'. - The mouse wheel over a focused field changes the value, for example from 5 to 4, when you only meant to scroll the page. - 'selectionStart' is 'null', so the caret cannot be managed. 'inputmode="decimal"' keeps the numeric keypad on phones. 'format-options' shows the number with 'Intl.NumberFormat' in 'locale', as a currency, a percent or a unit, while the field is not being edited. Focus shows the number itself, and a typed '$1,200' or '25%' is read back with the same options. The value stays the plain number: '1200', or '0.25' for 25%. The locale's group separators are read in every field, so '1,234' is a number in 'en-US'. The field and its two buttons sit in a 'role="group"' named by the label, and the field carries 'role-label', "number field" in English, as its 'aria-roledescription', as React Aria's NumberField does. On iOS and iPadOS the field is a plain text field, with no 'role="spinbutton"', which VoiceOver reads as a slider you cannot type in, and no role description, so VoiceOver says the field is required. React Aria's NumberField does the same. Validity follows the platform's rules: 'min', 'max', and 'step' are checked and reported through the host's own 'setValidity', under the platform's flag names. Stepping is separate from typing, so a number is not corrected while you type it. While you type, the form holds the number the text reads as, so a field showing '$2,500.50' gives the form 2500.5, and text that is not a number gives it nothing, as a native number field does. Holding a stepper button down steps once, then again after 400 milliseconds, then every 60 milliseconds until you let go, as React Aria's NumberField does. **Keyboard.** The field is one tab stop, and the stepper buttons are not in the tab order. | Key | What it does | |---|---| | Up, Down | Steps the value up or down by 'step'. | | Page Up, Page Down | Steps by 'large-step' steps, ten by default. | | Home, End | Goes to 'min' or 'max', where there is one. Without one, moves the caret. | | Enter | Commits the typed number and submits the form, as a native field does. | The field has 'role="spinbutton"' with 'aria-valuenow', 'aria-valuemin', 'aria-valuemax', and the formatted text in 'aria-valuetext'. */
18553
18670
  "helix-headless-number-input": DefineCustomElement<
18554
18671
  HelixHeadlessNumberInput,
18555
18672
  HelixHeadlessNumberInputVueProps,
@@ -18663,7 +18780,7 @@ export interface WcToolkitVueGlobalComponents {
18663
18780
  HelixHeadlessScrollAreaVueProps,
18664
18781
  HelixHeadlessScrollAreaVueEvents
18665
18782
  >;
18666
- /** A trigger that opens a 'Listbox'. The list is the same element you can use on its own, with the same keyboard behavior, filtering, and multi-select rules. Select adds a trigger that shows what is chosen, a floating surface, and a place for focus to return to when the list closes. Your options stay in your light DOM and are slotted through into the listbox, so the listbox looks through slots to find them. For a list too long to draw whole, set 'items' instead: the list draws only the options in sight, as Listbox's 'items' does, and the trigger, its keys and the form read the whole set. 'Select' owns the value, passes it down to the listbox, and takes changes back, so the value lives in one place. Set 'valueContent' to draw the trigger's content from the chosen options, and several chosen options are written as a list in the reader's language. **Keyboard.** On the closed trigger: | Key | What it does | |---|---| | Down, Enter, Space | Opens the list on the chosen option, or the first. | | Up | Opens the list on the chosen option, or the last. | | Home, End | Opens the list on the first or the last option. | | Left, Right | Chooses the option before or after the chosen one without opening, as React Aria's Select does, in either direction of text. | | A letter or a word | Chooses the option whose words start with what you typed, as a native '<select>' does. With 'multiple', opens the list on it. | In the open list, which is a 'Listbox': | Key | What it does | |---|---| | Down, Up, Home, End, Page Down, Page Up | Moves the highlight. | | A letter or a word | Moves the highlight to the next option whose words start with what you typed. | | Enter, Space | Chooses the highlighted option and closes the list. With 'multiple', toggles it and leaves the list open. | | Escape | Closes the list and puts focus back on the trigger. | | Tab | Closes the list and moves on. | A choice made on the closed trigger is said aloud on Apple devices, where VoiceOver does not read the trigger's new name. **ARIA.** The trigger is a 'button' with 'aria-haspopup="listbox"' and 'aria-expanded', named by the label and then the chosen words, as a native '<select>' is. The list is the listbox 'Listbox' describes, named by the label, or by 'list-label' where there is none. Set 'autocomplete' to let a browser's autofill choose, as a native '<select>' with the same attribute would. */
18783
+ /** A trigger that opens a 'Listbox'. The list is the same element you can use on its own, with the same keyboard behavior, filtering, and multi-select rules. Select adds a trigger that shows what is chosen, a floating surface, and a place for focus to return to when the list closes. Your options stay in your light DOM and are slotted through into the listbox, so the listbox looks through slots to find them. For a list too long to draw whole, set 'items' instead: the list draws only the options in sight, as Listbox's 'items' does, and the trigger, its keys and the form read the whole set. 'Select' owns the value, passes it down to the listbox, and takes changes back, so the value lives in one place. With 'multiple', the value is the chosen values joined with commas, and the form receives one entry for each. An option's value may hold a comma, and it is read as one value. Set 'valueContent' to draw the trigger's content from the chosen options, and several chosen options are written as a list in the reader's language. **Keyboard.** On the closed trigger: | Key | What it does | |---|---| | Down, Enter, Space | Opens the list on the chosen option, or the first. | | Up | Opens the list on the chosen option, or the last. | | Home, End | Opens the list on the first or the last option. | | Left, Right | Chooses the option before or after the chosen one without opening, as React Aria's Select does, in either direction of text. | | A letter or a word | Chooses the option whose words start with what you typed, as a native '<select>' does. With 'multiple', opens the list on it. | In the open list, which is a 'Listbox': | Key | What it does | |---|---| | Down, Up, Home, End, Page Down, Page Up | Moves the highlight. | | A letter or a word | Moves the highlight to the next option whose words start with what you typed. | | Enter, Space | Chooses the highlighted option and closes the list. With 'multiple', toggles it and leaves the list open. | | Escape | Closes the list and puts focus back on the trigger. | | Tab | Closes the list and moves on. | A choice made on the closed trigger is said aloud on Apple devices, where VoiceOver does not read the trigger's new name. **ARIA.** The trigger is a 'button' with 'aria-haspopup="listbox"' and 'aria-expanded', named by the label and then the chosen words, as a native '<select>' is. The list is the listbox 'Listbox' describes, named by the label, or by 'list-label' where there is none. Set 'autocomplete' to let a browser's autofill choose, as a native '<select>' with the same attribute would. */
18667
18784
  "helix-headless-select": DefineCustomElement<
18668
18785
  HelixHeadlessSelect,
18669
18786
  HelixHeadlessSelectVueProps,
@@ -18837,13 +18954,13 @@ export interface WcToolkitVueGlobalComponents {
18837
18954
  HelixHeadlessTimelineVueProps,
18838
18955
  HelixHeadlessTimelineVueEvents
18839
18956
  >;
18840
- /** Each message is an element because it has a timeout, a tone, a dismiss control, and a lifetime that pauses. **Each item runs its own timer.** A timer held by the region would restart with each new message, and the last of three messages would stay for nine seconds. It pauses while the pointer or focus is on the message, and while the page is hidden, so a message is not spent in a background tab. **Each message is an 'alertdialog' named by its words**, which is how a reader who moves into the stack hears which message they are on. Give it a 'heading' and a 'description', and the heading names it and the description describes it, for a message with a title and a line of detail. The region says each message once as it arrives, a 'danger' one assertively, so a message is never a live region of its own. A touch or a pen swipes a message toward the end of the line, and past halfway, or quickly, dismisses it through the same 'helix-dismiss' as its control. While it moves, the distance is on the 'item' part as '--toast-swipe-x'. **Messages are inverted by default.** The item flips 'color-scheme', so a new message stands out from the page without using a color that carries meaning. */
18957
+ /** Each message is an element because it has a timeout, a tone, a dismiss control, and a lifetime that pauses. **Each item runs its own timer.** A timer held by the region would restart with each new message, and the last of three messages would stay for nine seconds. It pauses while the pointer or focus is on the message, and while the page is hidden, so a message is not spent in a background tab. **Each message is an 'alertdialog' named by its words**, which is how a reader who moves into the stack hears which message they are on. Give it a 'heading' and a 'description', and the heading names it and the description describes it, for a message with a title and a line of detail. The region says each message once as it arrives, a 'danger' one assertively, so a message is never a live region of its own. A touch or a pen swipes a message toward the end of the line, and past halfway, or quickly, dismisses it through the same 'helix-dismiss' as its control. While it moves, the distance is on the 'item' part as '--toast-swipe-x'. **Escape dismisses the message holding focus**, through the same 'helix-dismiss', and focus moves to the next message. **Messages are inverted by default.** The item flips 'color-scheme', so a new message stands out from the page without using a color that carries meaning. */
18841
18958
  "helix-headless-toast-item": DefineCustomElement<
18842
18959
  HelixHeadlessToastItem,
18843
18960
  HelixHeadlessToastItemVueProps,
18844
18961
  HelixHeadlessToastItemVueEvents
18845
18962
  >;
18846
- /** The region and its items are one family because a live region must be in the document before a message is added to it. Assistive technology often does not announce a region that arrives already holding its message. 'Radio.Group' is part of its family for the same reason. **The region is a landmark named by 'label', and it says each message once as it arrives**: a 'danger' message assertively, and every other one politely. It says the word for the tone, the heading, the description and the text, and not the actions, through two live regions of its own, the 'live' parts, which it empties again a moment later. The stack itself is not a live region, so a message is never said twice, and changing the words of a message already showing says nothing. Each message is an 'alertdialog' named by its words, so a reader who moves into the stack hears which message they are on. **'hotkey' takes focus to the stack and back**, F8 unless you set it, and 'label' says which key: '{hotkey}' in it is filled in, so the default name is "Notifications (F8)". Pressed while focus is in the stack, it gives focus back to where it was. **The region never creates or removes items.** You render items and remove them. An item requests closing with a cancelable 'helix-dismiss' event. A dismissed item hides itself and stays in the DOM, so your framework's state and the DOM stay in sync. It hides on its own unless you set 'open', which makes the state yours. **'add()' shows a message from script**, for a page with no framework state to render them from: it appends a message of the region's own tier and removes it once it has been dismissed and has finished leaving. Messages you render yourself stay yours, and the region never removes them. A touch or a pen swipes a message away toward the end of the line. **The stack is in the top layer.** The 'region' part is a 'popover="manual"' shown while a message is showing, and shown again above a modal dialog that opened after it. Position the 'region' part, which is the box in the top layer. While a modal 'Dialog', 'Drawer' or 'Lightbox' is open, the browser makes everything outside it inert, the stack included, so a message stays visible and its actions cannot be pressed. Where the browser has 'ariaNotify', a message that arrives then is announced through it. For a message with an action, render a second region inside the dialog. When a message with focus inside it is dismissed, focus moves to the next message, then the one before it, then back to where it was before it entered the stack. */
18963
+ /** The region and its items are one family because a live region must be in the document before a message is added to it. Assistive technology often does not announce a region that arrives already holding its message. 'Radio.Group' is part of its family for the same reason. **The region is a landmark named by 'label', and it says each message once as it arrives**: a 'danger' message assertively, and every other one politely. It says the word for the tone, the heading, the description and the text, and not the actions, through two live regions of its own, the 'live' parts, which it empties again a moment later. The stack itself is not a live region, so a message is never said twice, and changing the words of a message already showing says nothing. Each message is an 'alertdialog' named by its words, so a reader who moves into the stack hears which message they are on. **'hotkey' takes focus to the stack and back**, F8 unless you set it, and 'label' says which key: '{hotkey}' in it is filled in, so the default name is "Notifications (F8)". Pressed while focus is in the stack, it gives focus back to where it was. **The region never creates or removes items.** You render items and remove them. An item requests closing with a cancelable 'helix-dismiss' event. A dismissed item hides itself and stays in the DOM, so your framework's state and the DOM stay in sync. It hides on its own unless you set 'open', which makes the state yours. **'add()' shows a message from script**, for a page with no framework state to render them from: it appends a message of the region's own tier and removes it once it has been dismissed and has finished leaving. Messages you render yourself stay yours, and the region never removes them. A touch or a pen swipes a message away toward the end of the line. **The stack is in the top layer.** The 'region' part is a 'popover="manual"' shown while a message is showing, and shown again above a modal dialog that opened after it. Position the 'region' part, which is the box in the top layer. While a modal 'Dialog', 'Drawer' or 'Lightbox' is open, the browser makes everything outside it inert, the stack included, so a message stays visible and its actions cannot be pressed. Where the browser has 'ariaNotify', a message that arrives then is announced through it. For a message with an action, render a second region inside the dialog. When a message with focus inside it is dismissed, focus moves to the next message, then the one before it, then back to where it was before it entered the stack. **'max-visible' limits how many messages show at once**, as Zag's 'max' does. The messages after that many, in document order, wait: each is hidden, its timer has not started, and the region says it once it shows, when a message before it goes. A waiting message has ':state(waiting)'. **Keyboard.** | Key | What it does | |---|---| | F8, or your 'hotkey' | Moves focus to the first control in the stack, and back to where it was when pressed in the stack. | | Tab, Shift+Tab | Moves between the controls of the messages. | | Escape | Dismisses the message holding focus. Focus moves to the next message, then the one before it, then back to where it was. | */
18847
18964
  "helix-headless-toast": DefineCustomElement<
18848
18965
  HelixHeadlessToast,
18849
18966
  HelixHeadlessToastVueProps,
package/types/words.d.ts CHANGED
@@ -2228,6 +2228,13 @@ declare module '@fusion.dev/helix-core' {
2228
2228
  * English: `Loading`
2229
2229
  */
2230
2230
  loadingText: Message
2231
+ /**
2232
+ * The description a trigger gives under `open-on="long-press"`, saying how
2233
+ * to open the menu. Translate it with the rest of your interface.
2234
+ *
2235
+ * English: `Long press or press Alt+Down to show the menu`
2236
+ */
2237
+ longPressLabel: Message
2231
2238
  }
2232
2239
  'helix-meter': {
2233
2240
  /**
@@ -2275,6 +2282,13 @@ declare module '@fusion.dev/helix-core' {
2275
2282
  unreadLabel: Message
2276
2283
  }
2277
2284
  'helix-notifications': {
2285
+ /**
2286
+ * What the feed says when unread notifications arrive, with `{count}` the
2287
+ * number of them. Empty it to say nothing.
2288
+ *
2289
+ * English: `{count, plural, one {# new notification} other {# new notifications}}`
2290
+ */
2291
+ arrivedLabel: Message
2278
2292
  /**
2279
2293
  * The text shown and announced when there are no rows and none are loading.
2280
2294
  *