@fusion.dev/helix-headless 0.182.2 → 0.184.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/types/vue.d.ts CHANGED
@@ -40,6 +40,7 @@ import type {
40
40
  HelixHeadlessChat,
41
41
  HelixHeadlessCheckboxGroup,
42
42
  HelixHeadlessCheckbox,
43
+ registerHighlighter,
43
44
  HelixHeadlessCodeBlock,
44
45
  HelixHeadlessCode,
45
46
  HelixHeadlessColorInput,
@@ -3432,7 +3433,11 @@ whole of it, which Shiki writes, are taken off, so the lines sit level
3432
3433
  with the gutter's numbers and the block keeps one tab stop. The code stays
3433
3434
  in the slot, so the copy button copies it as written and a reader without
3434
3435
  the script still has it. Not called on a server, which has no code to
3435
- read, nor for a diff. */
3436
+ read, nor for a diff.
3437
+
3438
+ Absent, the block draws with the highlighter `registerHighlighter` gave
3439
+ every block, where an entry such as `@fusion.dev/helix-sandbox/code-block`
3440
+ registered one, and plain otherwise. */
3436
3441
  highlight?: (HelixHeadlessCodeBlock["highlight"]) | undefined;
3437
3442
  };
3438
3443
 
@@ -11042,7 +11047,11 @@ Cleared as the menu closes and as a submenu opens or closes, so each page
11042
11047
  starts with every row showing. */
11043
11048
  filter?: (HelixHeadlessMenu["filter"]) | undefined;
11044
11049
  /** Whether the menu shows a field above its rows that narrows them as the
11045
- reader types, with focus staying in the field. */
11050
+ reader types, with focus staying in the field, once
11051
+ `@fusion.dev/helix/menu/filter` (or `@fusion.dev/helix-headless/menu/filter`)
11052
+ is imported. Without that import it does nothing, so a menu that never
11053
+ filters carries none of the filter's code, and a development build says
11054
+ which import is missing. */
11046
11055
  filterable?: (HelixHeadlessMenu["filterable"]) | undefined;
11047
11056
  /** The filter field's name and placeholder. */
11048
11057
  "filter-label"?: (HelixHeadlessMenu["filterLabel"]) | undefined;
@@ -16294,6 +16303,12 @@ number, and both are carried as one comma-separated value, which is what a
16294
16303
  form submits. `TimePicker` carries the longer note on the interaction and
16295
16304
  on why a wheel cannot do either. */
16296
16305
  mode?: (HelixHeadlessTimeInput["mode"]) | undefined;
16306
+ /** The words on the list's button that chooses the current time, drawn with
16307
+ `show-now`. */
16308
+ "now-label"?: (HelixHeadlessTimeInput["nowLabel"]) | undefined;
16309
+ /** The words on the list's button that chooses the current time, drawn with
16310
+ `show-now`. */
16311
+ nowLabel?: (HelixHeadlessTimeInput["nowLabel"]) | undefined;
16297
16312
  /** Placeholder text shown before a time is entered. */
16298
16313
  placeholder?: (HelixHeadlessTimeInput["placeholder"]) | undefined;
16299
16314
  /** The message shown when a range holds more than two times.
@@ -16334,6 +16349,14 @@ removes rather than as "Remove" said once per time. */
16334
16349
  may give them, the field writes them, and the list's `step` counts seconds.
16335
16350
  See Time Picker's `seconds`. */
16336
16351
  seconds?: (HelixHeadlessTimeInput["seconds"]) | undefined;
16352
+ /** Draws a button under the times in the list that chooses the current time,
16353
+ moved to the nearest time on offer. See Time Picker's `show-now`. Its words
16354
+ are `now-label`. */
16355
+ "show-now"?: (HelixHeadlessTimeInput["showNow"]) | undefined;
16356
+ /** Draws a button under the times in the list that chooses the current time,
16357
+ moved to the nearest time on offer. See Time Picker's `show-now`. Its words
16358
+ are `now-label`. */
16359
+ showNow?: (HelixHeadlessTimeInput["showNow"]) | undefined;
16337
16360
  /** How far apart the offered times are, in minutes, or in seconds with
16338
16361
  `seconds`. */
16339
16362
  step?: (HelixHeadlessTimeInput["step"]) | undefined;
@@ -18957,6 +18980,13 @@ are rendered at a time.
18957
18980
  An `aria-label` or `aria-labelledby` on the host names the list too, and
18958
18981
  wins over this. */
18959
18982
  label?: (HelixHeadlessVirtualList["label"]) | undefined;
18983
+ /** How items of more than one column are laid out. `grid`, the default, puts
18984
+ them in lines of equal columns. `waterfall` puts each item, in the order
18985
+ of the set, under the column that ends highest, as a wall of photos of
18986
+ different heights is: `columns`, or `min-column-width`, says how many
18987
+ columns. Rows of a waterfall are measured, and Up and Down move along a
18988
+ column. */
18989
+ layout?: (HelixHeadlessVirtualList["layout"]) | undefined;
18960
18990
  /** Marks the list as busy fetching more items, and draws a row after the last
18961
18991
  item that says so.
18962
18992
 
@@ -18989,14 +19019,15 @@ follows the box as it resizes, which `columns` then does not decide. */
18989
19019
  /** Which way the list runs. `horizontal` lays the items out along a line
18990
19020
  and scrolls it sideways: Left and Right move between items, the other
18991
19021
  way round on a right-to-left page, and `estimate` is an item's width. A
18992
- grid always runs down. */
19022
+ grid and a waterfall always run down. */
18993
19023
  orientation?: (HelixHeadlessVirtualList["orientation"]) | undefined;
18994
19024
  /** Lets a reader move items, once `@fusion.dev/helix/virtual-list/reorder`
18995
19025
  (or `@fusion.dev/helix-headless/virtual-list/reorder`) is imported: Alt
18996
19026
  with an arrow moves the row the keys are on, and a pointer drags a row.
18997
19027
  The list moves no item itself: you move your `items` on `helix-reorder`.
18998
19028
  Without that import it does nothing, so a list that never moves items
18999
- carries none of the code. A list of one column, without sections. */
19029
+ carries none of the code. A list of one column, without sections or a
19030
+ waterfall. */
19000
19031
  reorderable?: (HelixHeadlessVirtualList["reorderable"]) | undefined;
19001
19032
  /** The field of each item that names its section, as a key or a path of
19002
19033
  keys. Set, the items are drawn in sections: a header, then the items, in
@@ -19436,7 +19467,7 @@ export interface WcToolkitVueGlobalComponents {
19436
19467
  HelixHeadlessCheckboxVueProps,
19437
19468
  HelixHeadlessCheckboxVueEvents
19438
19469
  >;
19439
- /** Renders a '<pre><code>' pair: 'pre' keeps the whitespace, and 'code' marks it as code. Long lines scroll inside the block and do not wrap, because a line break can be significant in code. A copy button is on by default. Set 'no-copy' to remove it. The button copies the slotted text, so there is no second copy of the code to keep in sync. For a fragment of code inside a sentence, use 'Code'. Set 'line-numbers' to number the lines in a gutter beside the code, hidden from the accessibility tree and left out of a copy. Set 'mark-lines' to mark lines a reader should look at, such as '2, 4-6': the block draws a band behind each run, placed where the lines are laid out, so it follows a highlighter's markup and lines that wrap. 'added-lines' and 'removed-lines' mark lines the same way as inserted and deleted, as Expressive Code's 'ins' and 'del' do, in code that is not a diff. The bands are drawn and hidden from screen readers, so say in the text around the block what a marked line means. Set 'wrap' to wrap long lines rather than scroll them; a gutter then numbers each line where it starts. Set 'wrappable' for a button in the header that turns 'wrap' on and off, pressed while the lines wrap. The header holds the name, the 'actions' slot, and the copy button. Slot a control into 'actions', such as a button that sets 'wrap' or one that opens the code in an editor, and the block draws a header for it even with no name. 'copy-icon' and 'copied-icon' replace the copy button's two icons. Set 'highlight' to a function that turns the code into highlighted markup, such as one wrapping Shiki or Prism, and the block draws what it returns; it is handed the block's 'language', so one function serves every block. The code stays in the slot, so the copy button and the page's own text are the code as written. Set 'expandable' on a block whose height is capped, such as by '--code-block-max-block-size', and a button under it shows every line and then fewer again, as a docs site's long example does. The button is drawn only while the cap hides something, says whether the block is expanded with 'aria-expanded', names the block it opens with 'aria-controls', and the block carries ':state(expanded)' while it is. Set 'diff' to show a change. Put a unified diff, the output of 'git diff' or 'diff -u', in the same slot, and the block draws the lines it added and removed. The block never computes a diff itself. Line numbers come from the hunk headers and are hidden from the accessibility tree. Changed lines are '<ins>' and '<del>' with the '+' and '-' kept as text, so the change does not depend on color. Where a removed line is paired with the added line that replaced it, the words each does not share with the other are the 'changed' part, so the eye goes to what changed within the line. Each file in the patch is its own block under its own name, and its copy button copies the new version of the file. 'variant="split"' shows the old version beside the new, each removal opposite its replacement. 'context-lines' folds each long run of unchanged lines, keeping that many beside each change, behind a button that shows them and hides them again, as a code host draws a diff written with more context than a reader needs. **A block that scrolls is a tab stop.** While its lines run past its width or its cap, the scroller is a region named for the block, such as "Code, app.ts", that Tab reaches, so a keyboard scrolls it with the arrow keys in every browser. Chromium and Firefox make a scrolling box focusable on their own, and Safari does not. A block that fits is no stop at all. **The code the block draws is marked untranslated**, 'translate="no"' on its '<pre>', so a page translator leaves highlighted lines and a diff as written. Code in the slot takes its translation mode from the element, which writes nothing onto itself, so set 'translate="no"' on the element to keep a translator off plain code too. On the server, the slot renders as ordinary code, so a diff first appears as the patch text in a '<pre>'. The client makes the same first render, which keeps hydration clean, and draws the diff once it can read the content. Diff mode is experimental. The rest of the family is stable. **Several blocks are files**, one shown at a time under a row of tabs, as Sandbox shows its source panes. Put Code Blocks in the default slot of a Code Block, and each is a file named on its tab by its 'label' or, without one, its 'language'. 'file' holds the name of the file shown. The tabs are a tab list: the arrow keys move to a tab and show its file, the two swapping on a right-to-left page, and Home and End go to the first and the last. Choosing one sends 'helix-before-change' with the file's name, which you can cancel, and 'change' once 'file' holds it. The files not shown carry 'hidden', and the one shown draws no name of its own, its tab naming it. One block draws no tabs. A server cannot see the blocks inside, so the client draws the tabs once it upgrades. */
19470
+ /** Renders a '<pre><code>' pair: 'pre' keeps the whitespace, and 'code' marks it as code. Long lines scroll inside the block and do not wrap, because a line break can be significant in code. A copy button is on by default. Set 'no-copy' to remove it. The button copies the slotted text, so there is no second copy of the code to keep in sync. For a fragment of code inside a sentence, use 'Code'. Set 'line-numbers' to number the lines in a gutter beside the code, hidden from the accessibility tree and left out of a copy. Set 'mark-lines' to mark lines a reader should look at, such as '2, 4-6': the block draws a band behind each run, placed where the lines are laid out, so it follows a highlighter's markup and lines that wrap. 'added-lines' and 'removed-lines' mark lines the same way as inserted and deleted, as Expressive Code's 'ins' and 'del' do, in code that is not a diff. The bands are drawn and hidden from screen readers, so say in the text around the block what a marked line means. Set 'wrap' to wrap long lines rather than scroll them; a gutter then numbers each line where it starts. Set 'wrappable' for a button in the header that turns 'wrap' on and off, pressed while the lines wrap. The header holds the name, the 'actions' slot, and the copy button. Slot a control into 'actions', such as a button that sets 'wrap' or one that opens the code in an editor, and the block draws a header for it even with no name. 'copy-icon' and 'copied-icon' replace the copy button's two icons. Set 'highlight' to a function that turns the code into highlighted markup, such as one wrapping Shiki or Prism, and the block draws what it returns; it is handed the block's 'language', so one function serves every block. The code stays in the slot, so the copy button and the page's own text are the code as written. **Code Block ships no grammar**, so plain code costs you no parser. To color code without a highlighter of your own, import one more entry beside the block's. It colors every block by its 'language' ('css', 'html', 'js', 'jsx', 'sh', 'ts', or 'tsx') with the Lezer grammars of the sandbox's editor, in the editor's colors: '''js import '@fusion.dev/helix/code-block' import '@fusion.dev/helix-sandbox/code-block' ''' That entry calls 'registerHighlighter', which you can also call yourself to give every block one highlighter of your own. Set 'expandable' on a block whose height is capped, such as by '--code-block-max-block-size', and a button under it shows every line and then fewer again, as a docs site's long example does. The button is drawn only while the cap hides something, says whether the block is expanded with 'aria-expanded', names the block it opens with 'aria-controls', and the block carries ':state(expanded)' while it is. Set 'diff' to show a change. Put a unified diff, the output of 'git diff' or 'diff -u', in the same slot, and the block draws the lines it added and removed. The block never computes a diff itself. Line numbers come from the hunk headers and are hidden from the accessibility tree. Changed lines are '<ins>' and '<del>' with the '+' and '-' kept as text, so the change does not depend on color. Where a removed line is paired with the added line that replaced it, the words each does not share with the other are the 'changed' part, so the eye goes to what changed within the line. Each file in the patch is its own block under its own name, and its copy button copies the new version of the file. 'variant="split"' shows the old version beside the new, each removal opposite its replacement. 'context-lines' folds each long run of unchanged lines, keeping that many beside each change, behind a button that shows them and hides them again, as a code host draws a diff written with more context than a reader needs. **A block that scrolls is a tab stop.** While its lines run past its width or its cap, the scroller is a region named for the block, such as "Code, app.ts", that Tab reaches, so a keyboard scrolls it with the arrow keys in every browser. Chromium and Firefox make a scrolling box focusable on their own, and Safari does not. A block that fits is no stop at all. **The code the block draws is marked untranslated**, 'translate="no"' on its '<pre>', so a page translator leaves highlighted lines and a diff as written. Code in the slot takes its translation mode from the element, which writes nothing onto itself, so set 'translate="no"' on the element to keep a translator off plain code too. On the server, the slot renders as ordinary code, so a diff first appears as the patch text in a '<pre>'. The client makes the same first render, which keeps hydration clean, and draws the diff once it can read the content. Diff mode is experimental. The rest of the family is stable. **Several blocks are files**, one shown at a time under a row of tabs, as Sandbox shows its source panes. Put Code Blocks in the default slot of a Code Block, and each is a file named on its tab by its 'label' or, without one, its 'language'. 'file' holds the name of the file shown. The tabs are a tab list: the arrow keys move to a tab and show its file, the two swapping on a right-to-left page, and Home and End go to the first and the last. Choosing one sends 'helix-before-change' with the file's name, which you can cancel, and 'change' once 'file' holds it. The files not shown carry 'hidden', and the one shown draws no name of its own, its tab naming it. One block draws no tabs. A server cannot see the blocks inside, so the client draws the tabs once it upgrades. */
19440
19471
  "helix-headless-code-block": DefineCustomElement<
19441
19472
  HelixHeadlessCodeBlock,
19442
19473
  HelixHeadlessCodeBlockVueProps,
@@ -19760,7 +19791,7 @@ export interface WcToolkitVueGlobalComponents {
19760
19791
  HelixHeadlessMenuItemVueProps,
19761
19792
  HelixHeadlessMenuItemVueEvents
19762
19793
  >;
19763
- /** 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. Focus follows a mouse resting on a row in either mode, and a drilled page is a 'menu' named by the row that opened it. **'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 (Space on a choice row changes it and leaves the menu open), 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) }'. **The choices in one place.** 'checkedValues' holds the values of the rows that are checked, anywhere in the menu, and setting it checks exactly those rows, as React Aria's 'selectedKeys' does. 'change' is sent on the menu when a reader's choice changes it. 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. **A filter field.** With 'filterable', the menu opens with focus in a field above its rows, and typing narrows the rows of the page the keys move in, as React Aria's 'Autocomplete' around a 'Menu' does. A row is kept where its words hold the filter, in any case, or where 'filterMatch' says so. Each page starts unfiltered, and the filter is cleared as the menu closes. Where typing keeps no row, the menu shows 'no-results-text'. Focus stays in the field: Up and Down Arrow move the highlight through the rows that are left, Enter chooses the highlighted row, Right Arrow opens its submenu, Left Arrow on a submenu goes back, and Escape clears the filter and then closes the menu. A screen reader hears how many rows the filter keeps ('results-label'). Home, End and the other keys move the caret and type. The field names the highlighted row with 'aria-activedescendant', and the rows are a 'menu' after the field. Cancel 'helix-filter' to keep every row showing and narrow the rows yourself, such as by replacing them with rows from a server. */
19794
+ /** 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. Focus follows a mouse resting on a row in either mode, and a drilled page is a 'menu' named by the row that opened it. **'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 (Space on a choice row changes it and leaves the menu open), 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) }'. **The choices in one place.** 'checkedValues' holds the values of the rows that are checked, anywhere in the menu, and setting it checks exactly those rows, as React Aria's 'selectedKeys' does. 'change' is sent on the menu when a reader's choice changes it. 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. **A filter field** is a separate import, '@fusion.dev/helix/menu/filter', so a menu that never filters carries none of its code: '''js import '@fusion.dev/helix/menu' import '@fusion.dev/helix/menu/filter' ''' With it imported and 'filterable' set, the menu opens with focus in a field above its rows, and typing narrows the rows of the page the keys move in, as React Aria's 'Autocomplete' around a 'Menu' does. A row is kept where its words hold the filter, in any case, or where 'filterMatch' says so. Each page starts unfiltered, and the filter is cleared as the menu closes. Where typing keeps no row, the menu shows 'no-results-text'. Focus stays in the field: Up and Down Arrow move the highlight through the rows that are left, Enter chooses the highlighted row, Right Arrow opens its submenu, Left Arrow on a submenu goes back, and Escape clears the filter and then closes the menu. A screen reader hears how many rows the filter keeps ('results-label'). Home, End and the other keys move the caret and type. The field names the highlighted row with 'aria-activedescendant', and the rows are a 'menu' after the field. Cancel 'helix-filter' to keep every row showing and narrow the rows yourself, such as by replacing them with rows from a server. */
19764
19795
  "helix-headless-menu": DefineCustomElement<
19765
19796
  HelixHeadlessMenu,
19766
19797
  HelixHeadlessMenuVueProps,
@@ -20180,7 +20211,7 @@ export interface WcToolkitVueGlobalComponents {
20180
20211
  HelixHeadlessVideoVueProps,
20181
20212
  HelixHeadlessVideoVueEvents
20182
20213
  >;
20183
- /** The items arrive as data, in one of two ways: - 'items' takes an array. A framework sets it as a property, and React hydration keeps it. - 'for' names a '<script type="application/json">' that holds an array, which a server sends as markup. Each item is drawn into a row in one of two ways: - 'renderItem' is a function from an item and its index to the row's content: a Lit template, a string, or a DOM node. - A '<template>' child defines one row. 'data-field="name"' fills an element with the item's 'name' as text, and 'data-field-href="url"' writes the item's 'url' into 'href', the same for any attribute. A field may be a path of keys, such as 'author.name'. Rows are your markup in the light DOM, so your stylesheet styles them. **A grid.** 'columns' lays the items out that many to a line, as a grid of equal columns, and windows the set a line at a time, as React Aria's grid layout does. Each item draws one element, a cell of the grid, and 'estimate' is the height of a line. 'min-column-width' lays out as many columns as fit the box instead, as React Aria's grid layout does with its smallest item size, and follows the box as it resizes. 'gap' spaces the rows, and the columns of a grid, by a number of pixels the list counts in each row's place. **Across.** 'orientation="horizontal"' lays the items out along a line and scrolls it sideways, as a strip of cards does, windowed the same way: 'estimate' is then an item's width, and the box needs an inline size. **Sections.** 'section-field' names the field of each item that says which section it is in, and the list draws a header before each section's items, as React Aria's list box sections do. Each section is an element with the 'group' role, named by its header, which is its first child and carries 'data-header', so your stylesheet styles it, such as with 'position: sticky'. A section starts wherever the field changes, so give the items in order. The window counts the headers with the items, and a section the window starts inside is drawn with its header. 'renderSection' draws a header of your own. **Keyboard.** The list is one tab stop. | Key | What it does | |---|---| | Down, Up | Moves to the next or the previous item, or in a grid to the item in the same column on the next or the previous line. | | Right, Left | In a grid, moves to the next or the previous item along the line, the other way round on a right-to-left page. In a list that runs across, moves to the next or the previous item the same way, and Down and Up are left to the row. | | Home, End | Moves to the first or the last item. | | Page Down, Page Up | Moves by the number of items, or of lines in a grid, on screen. | | A letter or a word | Moves to the next item whose text starts with what you typed. | | Escape | Lets go of every chosen item, in a list with 'selection-mode'. | | Alt with Up or Down | In a 'reorderable' list, moves the item a place. Alt with Home or End moves it to either end. | | Tab | Moves into the focused row's own links and buttons, then out of the list. | An item that is not drawn is scrolled into view and focused, so a keyboard reaches the whole set. The row a reader last focused keeps the tab stop and stays drawn when it scrolls away, so Tab and Shift+Tab come back to it, as React Aria's collections do. In a list nobody has focused yet, the stop moves to the first row on screen. Typing matches each item's 'text-field', which is the first 'data-field' of the row template by default, or the item itself when it is a string or a number. Each row says its place in the whole set with 'aria-posinset' and 'aria-setsize', so a screen reader says "4,000 of 10,000". The row holding focus stays drawn when it scrolls out. **Selecting.** 'selection-mode' makes the list a list box a reader chooses from: 'single' selects one item and 'multiple' any number. Space or a press selects an item, Shift with Space, an arrow, Home, End or a press takes in the items from the last one chosen, and Control or Command with A selects them all, in 'multiple'. Escape lets go of every chosen item, and keeps the key from the dialog or menu around the list while there was something to let go of. 'value' holds the chosen items' keys, separated by commas, in the order of the set: 'key-field' names each item's key, and a string or a number item is its own key. A change asks with 'helix-before-change' and tells with 'change'. Each row is an 'option' marked 'aria-selected', so a row's own links and buttons are not reached there: keep those to a list without 'selection-mode'. 'selection-behavior="replace"' selects the item pressed alone, as a file list does, and the arrow keys carry the selection with them. Control or Command with a press or with Space adds or takes out one item, and with an arrow moves without selecting. **Disabled items.** 'disabled-keys' names items by their keys, separated by commas. Their rows carry 'aria-disabled', the keys and typing pass over them, and a press, Space, or Control with A does not select them. **Rows a stylesheet can tell apart.** A chosen row carries 'data-selected', a disabled one 'data-disabled', as React Aria's rows do, and the row the keys are on, which holds the tab stop, 'data-active', whether or not the list has focus. **Loading more.** 'helix-range-change' fires as the items on screen change, and 'range' holds them. 'helix-load-more' fires once a reader is within one screen of the end, once for each length of the set: add to 'items' and it can fire again. While you fetch, set 'loading': the list is busy, and a row after the last item says "Loading more" ('loading-label', or your own content in the 'loading' slot). 'scrollToIndex' takes a reader to an item. **Moving items** is a separate import, '@fusion.dev/helix/virtual-list/reorder', as React Aria's drag and drop is. With it imported, 'reorderable' lets a reader move items in a list of one column without sections: - Alt with Up or Down moves the item the keys are on a place, and Alt with Home or End to either end, as the APG's rearrangeable listbox does. - A pointer drags a whole row. A press that does not travel is still a press. The list scrolls near an edge, and an item far down a long set is reached by dragging to the edge. - A drop sends 'helix-before-reorder', which you can refuse, and then 'helix-reorder', whose 'keys' hold every item's key in the new order. **You move the items**: set 'items' to them in that order. The keys stay on the item that moved. - Each move is said in a region screen readers announce. The row being dragged carries 'data-dragging', and the row a drop would land beside 'data-drop-before' or 'data-drop-after'. **An empty list.** Set 'empty-label', or put your own content in the 'empty' slot, for a row shown when there are no items and none are loading, such as "No messages yet" and a link to write one. Without either, an empty list shows nothing, since a list whose items have not arrived yet has not said it has none. The list takes the 'empty' state while it has read its items and holds none, and the 'loading' state while 'loading' is set, so your stylesheet can change the box around it for either. A list with no name is reported once in a development build. Name it with 'label' or 'aria-label'. **Row height.** Rows are placed by 'estimate' until they are drawn. Then the list reads the drawn rows' height once and places every row by it, so a wrong estimate still reaches the last item. Set 'measured' for rows of different heights. Once the list draws rows of different heights, such as rows that wrap on a narrow screen, it places each row by its own height whether 'measured' is set or not. The list follows its source. A new 'items' array, an edit to the script's text, or a script replaced under the same id draws the new rows. A row that stays in view keeps its element as the list scrolls. The viewport scrolls on this tier. It carries 'data-scroller', and 'core' ships '[data-scroller] { overflow: auto }' into every shadow root, so 'scrollTop' works with no stylesheet. You still need to set a block size. */
20214
+ /** The items arrive as data, in one of two ways: - 'items' takes an array. A framework sets it as a property, and React hydration keeps it. - 'for' names a '<script type="application/json">' that holds an array, which a server sends as markup. Each item is drawn into a row in one of two ways: - 'renderItem' is a function from an item and its index to the row's content: a Lit template, a string, or a DOM node. - A '<template>' child defines one row. 'data-field="name"' fills an element with the item's 'name' as text, and 'data-field-href="url"' writes the item's 'url' into 'href', the same for any attribute. A field may be a path of keys, such as 'author.name'. Rows are your markup in the light DOM, so your stylesheet styles them. **A grid.** 'columns' lays the items out that many to a line, as a grid of equal columns, and windows the set a line at a time, as React Aria's grid layout does. Each item draws one element, a cell of the grid, and 'estimate' is the height of a line. 'min-column-width' lays out as many columns as fit the box instead, as React Aria's grid layout does with its smallest item size, and follows the box as it resizes. 'gap' spaces the rows, and the columns of a grid, by a number of pixels the list counts in each row's place. A grid without 'selection-mode' is a grid to a reader, as the APG's grid and React Aria's grid list are: the box is a 'grid' with 'aria-rowcount' and 'aria-colcount', each line drawn is a 'row' with 'aria-rowindex', and each item a 'gridcell' with 'aria-colindex'. Each line is a slot of the list's own, so your rows stay its children: give an item one element. With 'selection-mode' it stays a list box of options, as React Aria's list box in a grid layout does. **A waterfall.** 'layout="waterfall"' puts each item, in the order of the set, under the column that ends highest so far, the leftmost of a tie, as a wall of photos of different heights is, and as React Aria's waterfall layout and TanStack Virtual's lanes do. 'columns', or 'min-column-width', says how many columns. Every item is measured, at the width of its column, and placed at its column and its height, so items of any height leave no holes. The list draws the items that reach into the box, and the item holding focus. A reader hears a list, or a list box, in the order of the set, which is also the order Tab and a screen reader's own keys take. In a waterfall, Down and Up move along the column to the next or the previous item in it, Right and Left move to the next or the previous column, to the item there that sits beside this one the most, or the nearest above where none does, and Page Down and Page Up move a box down or up the column. Home and End go to the first and the last item of the set, and Shift with a key takes in the items between in the order of the set. **Across.** 'orientation="horizontal"' lays the items out along a line and scrolls it sideways, as a strip of cards does, windowed the same way: 'estimate' is then an item's width, and the box needs an inline size. **Sections.** 'section-field' names the field of each item that says which section it is in, and the list draws a header before each section's items, as React Aria's list box sections do. Each section is an element with the 'group' role, named by its header, which is its first child and carries 'data-header', so your stylesheet styles it, such as with 'position: sticky'. A section starts wherever the field changes, so give the items in order. The window counts the headers with the items, and a section the window starts inside is drawn with its header. 'renderSection' draws a header of your own. **Keyboard.** The list is one tab stop. | Key | What it does | |---|---| | Down, Up | Moves to the next or the previous item, or in a grid to the item in the same column on the next or the previous line, or in a waterfall to the next or the previous item down the same column. | | Right, Left | In a grid, moves to the next or the previous item along the line, the other way round on a right-to-left page. In a waterfall, moves to the item beside in the next or the previous column. In a list that runs across, moves to the next or the previous item the same way, and Down and Up are left to the row. | | Home, End | Moves to the first or the last item. In a grid without 'selection-mode', to the first or the last item of the line. | | Control or Command with Home or End | In a grid without 'selection-mode', moves to the first or the last item. | | Page Down, Page Up | Moves by the number of items, or of lines in a grid, on screen, or in a waterfall a box down or up the column. | | A letter or a word | Moves to the next item whose text starts with what you typed. | | Escape | Lets go of every chosen item, in a list with 'selection-mode'. | | Alt with Up or Down | In a 'reorderable' list, moves the item a place. Alt with Home or End moves it to either end. | | Tab | Moves into the focused row's own links and buttons, then out of the list. | An item that is not drawn is scrolled into view and focused, so a keyboard reaches the whole set. The row a reader last focused keeps the tab stop and stays drawn when it scrolls away, so Tab and Shift+Tab come back to it, as React Aria's collections do. In a list nobody has focused yet, the stop moves to the first row on screen. Typing matches each item's 'text-field', which is the first 'data-field' of the row template by default, or the item itself when it is a string or a number. Each row says its place in the whole set with 'aria-posinset' and 'aria-setsize', so a screen reader says "4,000 of 10,000", and each cell of a grid its line and its column. The row holding focus stays drawn when it scrolls out. **Selecting.** 'selection-mode' makes the list a list box a reader chooses from: 'single' selects one item and 'multiple' any number. Space or a press selects an item, Shift with Space, an arrow, Home, End or a press takes in the items from the last one chosen, and Control or Command with A selects them all, in 'multiple'. Escape lets go of every chosen item, and keeps the key from the dialog or menu around the list while there was something to let go of. 'value' holds the chosen items' keys, separated by commas, in the order of the set: 'key-field' names each item's key, and a string or a number item is its own key. A change asks with 'helix-before-change' and tells with 'change'. Each row is an 'option' marked 'aria-selected', so a row's own links and buttons are not reached there: keep those to a list without 'selection-mode'. 'selection-behavior="replace"' selects the item pressed alone, as a file list does, and the arrow keys carry the selection with them. Control or Command with a press or with Space adds or takes out one item, and with an arrow moves without selecting. **Disabled items.** 'disabled-keys' names items by their keys, separated by commas. Their rows carry 'aria-disabled', the keys and typing pass over them, and a press, Space, or Control with A does not select them. **Rows a stylesheet can tell apart.** A chosen row carries 'data-selected', a disabled one 'data-disabled', as React Aria's rows do, and the row the keys are on, which holds the tab stop, 'data-active', whether or not the list has focus. **Loading more.** 'helix-range-change' fires as the items on screen change, and 'range' holds them. 'helix-load-more' fires once a reader is within one screen of the end, once for each length of the set: add to 'items' and it can fire again. While you fetch, set 'loading': the list is busy, and a row after the last item says "Loading more" ('loading-label', or your own content in the 'loading' slot). 'scrollToIndex' takes a reader to an item. **Moving items** is a separate import, '@fusion.dev/helix/virtual-list/reorder', as React Aria's drag and drop is. With it imported, 'reorderable' lets a reader move items in a list of one column without sections: - Alt with Up or Down moves the item the keys are on a place, and Alt with Home or End to either end, as the APG's rearrangeable listbox does. - A pointer drags a whole row. A press that does not travel is still a press. The list scrolls near an edge, and an item far down a long set is reached by dragging to the edge. - A drop sends 'helix-before-reorder', which you can refuse, and then 'helix-reorder', whose 'keys' hold every item's key in the new order. **You move the items**: set 'items' to them in that order. The keys stay on the item that moved. - Each move is said in a region screen readers announce. The row being dragged carries 'data-dragging', and the row a drop would land beside 'data-drop-before' or 'data-drop-after'. **An empty list.** Set 'empty-label', or put your own content in the 'empty' slot, for a row shown when there are no items and none are loading, such as "No messages yet" and a link to write one. Without either, an empty list shows nothing, since a list whose items have not arrived yet has not said it has none. The list takes the 'empty' state while it has read its items and holds none, and the 'loading' state while 'loading' is set, so your stylesheet can change the box around it for either. A list with no name is reported once in a development build. Name it with 'label' or 'aria-label'. **Row height.** Rows are placed by 'estimate' until they are drawn. Then the list reads the drawn rows' height once and places every row by it, so a wrong estimate still reaches the last item. Set 'measured' for rows of different heights. Once the list draws rows of different heights, such as rows that wrap on a narrow screen, it places each row by its own height whether 'measured' is set or not. The list follows its source. A new 'items' array, an edit to the script's text, or a script replaced under the same id draws the new rows. A row that stays in view keeps its element as the list scrolls. The viewport scrolls on this tier. It carries 'data-scroller', and 'core' ships '[data-scroller] { overflow: auto }' into every shadow root, so 'scrollTop' works with no stylesheet. You still need to set a block size. */
20184
20215
  "helix-headless-virtual-list": DefineCustomElement<
20185
20216
  HelixHeadlessVirtualList,
20186
20217
  HelixHeadlessVirtualListVueProps,
package/types/words.d.ts CHANGED
@@ -3284,6 +3284,13 @@ declare module '@fusion.dev/helix-core' {
3284
3284
  * English: `{kind, select, date {Enter a whole date.} other {Enter a whole time.}}`
3285
3285
  */
3286
3286
  incompleteMessage: Message
3287
+ /**
3288
+ * The words on the list's button that chooses the current time, drawn with
3289
+ * `show-now`.
3290
+ *
3291
+ * English: `Now`
3292
+ */
3293
+ nowLabel: Message
3287
3294
  /**
3288
3295
  * Placeholder text shown before a time is entered.
3289
3296
  *