@fusion.dev/helix-headless 0.179.0 → 0.180.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 (40) hide show
  1. package/custom-elements.json +160 -50
  2. package/dist/chat/composer/chat-composer.d.ts +2 -1
  3. package/dist/chat/composer/chat-composer.js +1 -1
  4. package/dist/combobox/root/combobox-root.d.ts +12 -0
  5. package/dist/combobox/root/combobox-root.js +3 -2
  6. package/dist/command/root/command-root.d.ts +12 -0
  7. package/dist/command/root/command-root.js +3 -2
  8. package/dist/data-table/root/data-table-root.d.ts +13 -1
  9. package/dist/data-table/root/data-table-root.js +18 -15
  10. package/dist/date-input/root/date-input-root.d.ts +7 -0
  11. package/dist/date-input/root/date-input-root.js +12 -0
  12. package/dist/date-picker/root/date-picker-root.d.ts +7 -1
  13. package/dist/date-picker/root/date-picker-root.js +12 -0
  14. package/dist/drilldown/root/drilldown-root.js +9 -0
  15. package/dist/filter-input/root/filter-input-root.d.ts +13 -0
  16. package/dist/filter-input/root/filter-input-root.js +2 -1
  17. package/dist/listbox/root/listbox-root.d.ts +16 -2
  18. package/dist/listbox/root/listbox-root.js +8 -4
  19. package/dist/meter/root/meter-root.js +1 -2
  20. package/dist/notifications/notification/notification.js +14 -1
  21. package/dist/option/among.d.ts +23 -0
  22. package/dist/option/among.js +2 -0
  23. package/dist/option/root/option-root.d.ts +1 -17
  24. package/dist/option/root/option-root.js +1 -4
  25. package/dist/scatter-chart/root/scatter-chart-root.d.ts +5 -4
  26. package/dist/scatter-chart/root/scatter-chart-root.js +1 -0
  27. package/dist/select/root/select-root.d.ts +13 -2
  28. package/dist/select/root/select-root.js +3 -3
  29. package/dist/table/column/table-column.d.ts +1 -10
  30. package/dist/table/column/table-column.js +1 -2
  31. package/dist/table/edge.d.ts +10 -0
  32. package/dist/table/edge.js +2 -0
  33. package/dist/tabs/root/tabs-root.d.ts +1 -0
  34. package/dist/tabs/root/tabs-root.js +13 -0
  35. package/dist/tooltip/root/tooltip-root.js +1 -0
  36. package/lint.json +1 -1
  37. package/package.json +5 -5
  38. package/types/jsx.d.ts +210 -16
  39. package/types/vue.d.ts +25 -11
  40. package/types/words.d.ts +14 -0
@@ -23202,7 +23202,7 @@
23202
23202
  "declarations": [
23203
23203
  {
23204
23204
  "kind": "class",
23205
- "description": "The composer is a separate element so you can replace it. If you need\nattachments, slash commands, or a model picker, replace the composer and keep\nthe transcript.\n\nBy default, Enter sends and Shift+Enter starts a new line, the convention in\nmessaging apps. Document editors mostly use the opposite, so `submit-on`\ntakes `enter` or `button`. Use `button` for a long-form composer.\n\nThe composer clears only when no listener cancels the send, so the text is\nkept when you cancel a send that failed.\n\n**In a form, the draft is the composer's value**, submitted under `name`. A\nform reset puts back the `value` the markup declared, and a `<fieldset\ndisabled>` turns the composer off. Sending is still `helix-send`, and it\ndoes not submit the form.\n\n**`required`, `minlength` and `maxlength` are checked by the browser**, as\non a `<textarea>`, and the message is the browser's. `maxlength` stops the\nfield taking more. A draft that fails them does not send, and the composer\ntakes `:state(invalid)` and `aria-invalid` once the reader has tried to send\nit, the form was submitted, or the reader edited the field and left it.\nSending an empty required composer counts as trying. Tabbing past an empty\ncomposer marks nothing.\n\n**`feedback` is a message of your own about the draft**, such as one your\nserver sent back. While it is set, the composer is invalid at once, does\nnot send or submit, shows the message under the field, and a screen reader\nhears it as it appears. Clear it to let the draft go.\n\n**`typing` says whether the user is writing**, and `helix-typing` is sent\neach time it changes: when they start, and when they send or stop for\n`typing-timeout` milliseconds. Pass it on to show \"is typing\" to the other\nside.",
23205
+ "description": "The composer is a separate element so you can replace it. If you need\nattachments, slash commands, or a model picker, replace the composer and keep\nthe transcript.\n\nBy default, Enter sends and Shift+Enter starts a new line, the convention in\nmessaging apps. Document editors mostly use the opposite, so `submit-on`\ntakes `enter` or `button`. Use `button` for a long-form composer.\n\nThe composer clears only when no listener cancels the send, so the text is\nkept when you cancel a send that failed.\n\n**In a form, the draft is the composer's value**, submitted under `name`,\nand an empty draft submits an empty entry, as a native textarea does. A\nform reset puts back the `value` the markup declared, and a `<fieldset\ndisabled>` turns the composer off. Sending is still `helix-send`, and it\ndoes not submit the form.\n\n**`required`, `minlength` and `maxlength` are checked by the browser**, as\non a `<textarea>`, and the message is the browser's. `maxlength` stops the\nfield taking more. A draft that fails them does not send, and the composer\ntakes `:state(invalid)` and `aria-invalid` once the reader has tried to send\nit, the form was submitted, or the reader edited the field and left it.\nSending an empty required composer counts as trying. Tabbing past an empty\ncomposer marks nothing.\n\n**`feedback` is a message of your own about the draft**, such as one your\nserver sent back. While it is set, the composer is invalid at once, does\nnot send or submit, shows the message under the field, and a screen reader\nhears it as it appears. Clear it to let the draft go.\n\n**`typing` says whether the user is writing**, and `helix-typing` is sent\neach time it changes: when they start, and when they send or stop for\n`typing-timeout` milliseconds. Pass it on to show \"is typing\" to the other\nside.",
23206
23206
  "name": "HelixHeadlessChatComposer",
23207
23207
  "cssParts": [
23208
23208
  {
@@ -39646,7 +39646,7 @@
39646
39646
  "declarations": [
39647
39647
  {
39648
39648
  "kind": "class",
39649
- "description": "The list is a `Listbox`, which handles filtering, the empty state, the\nhighlight, `aria-activedescendant`, and scrolling an option into view. This\nelement handles the field, the panel, and the communication between them.\n\nThe typed text and the value are separate. The text is a filter: it narrows\nthe list and is then discarded. The value is the option you choose, and the\nfield then shows that option's text. The filter clears on close, so a\nreopened combobox starts from the whole list.\n\nFocus stays in the text field. The arrow keys move through the list with the\nlistbox's public `navigate` method. As typing narrows the list, a screen\nreader hears how many options are left, such as \"3 results\". Emptying the\nfield and leaving it clears a single choice.\n\n**Keyboard.**\n\n| Key | What it does |\n|---|---|\n| Down, Up | On a closed field, opens the list on the chosen option, or the first or the last. In the open list, moves the highlight, round from the last option to the first. |\n| Alt with Down, Alt with Up | Opens the list without moving the highlight, and closes it, choosing nothing. |\n| Page Down, Page Up | In the open list, moves the highlight by as many options as the list shows at once. |\n| Enter | Chooses the highlighted option. With nothing left in the list, creates what was typed with `creatable`, or takes it with `allows-custom-value`. On a closed field, submits the form. |\n| Escape | Closes the list and puts the chosen words back. On a closed field, a second Escape clears a single choice. |\n| Tab | Closes the list and moves on. |\n| Backspace | With `multiple`, on an empty field, removes the last tag. |\n| Left | With `multiple`, with the caret at the start of the text, moves to the last tag's remove button. Right on a right-to-left page. |\n| Left, Right on a tag | Move between the tags, and past the last back to the text. |\n| Delete, Backspace on a tag | Removes the tag. |\n| Space, Home, End, letters | Edit the text. |\n\n**ARIA.** The input is the `combobox`, named by the label, with\n`aria-expanded`, `aria-controls` naming the list, `aria-autocomplete`\n(`both` with `suggest`, `list` otherwise) and `aria-activedescendant` on\nthe highlighted option. The list is the listbox `Listbox` describes.\n\nOn Apple devices, where VoiceOver does not read the option the field points\nto, the field says it in a live region as the highlight moves, says how many\noptions there are as the list opens, and says a choice once it is made, as\nReact Aria's combobox does there.\n\nSet `autocomplete` to let a browser's autofill choose an option.\n\nWith `multiple`, each chosen option is a tag in the field with its own remove\ncontrol. The text is the field's one tab stop, and the arrow keys reach the\ntags from it. The panel stays open and the filter clears after each choice, so the\nnext choice starts from the whole list.\n\nWith `creatable`, the combobox offers a create row and fires `helix-create`.\nIt does not add the option. The options are your light DOM, and your\nframework would re-render over an element the combobox inserted, so add the\noption in your event handler.",
39649
+ "description": "The list is a `Listbox`, which handles filtering, the empty state, the\nhighlight, `aria-activedescendant`, and scrolling an option into view. This\nelement handles the field, the panel, and the communication between them.\n\nThe typed text and the value are separate. The text is a filter: it narrows\nthe list and is then discarded. The value is the option you choose, and the\nfield then shows that option's text. The filter clears on close, so a\nreopened combobox starts from the whole list.\n\nFocus stays in the text field. The arrow keys move through the list with the\nlistbox's public `navigate` method. As typing narrows the list, a screen\nreader hears how many options are left, such as \"3 results\". Emptying the\nfield and leaving it clears a single choice.\n\n**Keyboard.**\n\n| Key | What it does |\n|---|---|\n| Down, Up | On a closed field, opens the list on the chosen option, or the first or the last. In the open list, moves the highlight, round from the last option to the first. |\n| Alt with Down, Alt with Up | Opens the list without moving the highlight, and closes it, choosing nothing. |\n| Page Down, Page Up | In the open list, moves the highlight by as many options as the list shows at once. |\n| Enter | Chooses the highlighted option. With nothing left in the list, creates what was typed with `creatable`, or takes it with `allows-custom-value`. On a closed field, submits the form. |\n| Escape | Closes the list and puts the chosen words back. On a closed field, a second Escape clears a single choice. |\n| Tab | Closes the list and moves on. |\n| Backspace | With `multiple`, on an empty field, removes the last tag. |\n| Left | With `multiple`, with the caret at the start of the text, moves to the last tag's remove button. Right on a right-to-left page. |\n| Left, Right on a tag | Move between the tags, and past the last back to the text. |\n| Delete, Backspace on a tag | Removes the tag. |\n| Space, Home, End, letters | Edit the text. |\n\n**ARIA.** The input is the `combobox`, named by the label, with\n`aria-expanded`, `aria-controls` naming the list, `aria-autocomplete`\n(`both` with `suggest`, `list` otherwise) and `aria-activedescendant` on\nthe highlighted option. The list is the listbox `Listbox` describes.\n\nOn Apple devices, where VoiceOver does not read the option the field points\nto, the field says it in a live region as the highlight moves, says how many\noptions there are as the list opens, and says a choice once it is made, as\nReact Aria's combobox does there.\n\nSet `autocomplete` to let a browser's autofill choose an option.\n\nWith `multiple`, each chosen option is a tag in the field with its own remove\ncontrol. The text is the field's one tab stop, and the arrow keys reach the\ntags from it. The panel stays open and the filter clears after each choice, so the\nnext choice starts from the whole list.\n\nWith `creatable`, the combobox offers a create row and fires `helix-create`.\nIt does not add the option. The options are your light DOM, and your\nframework would re-render over an element the combobox inserted, so add the\noption in your event handler.\n\n**The options are an import of their own.** An option is the Option family's,\nwhich the combobox does not register, so a page that writes one imports it\nbeside the combobox:\n\n```js\nimport '@fusion.dev/helix/combobox'\nimport '@fusion.dev/helix/option'\n```\n\nIn development, a combobox holding an option nobody registered says so once\nthe page has loaded, with the line to add.",
39650
39650
  "name": "HelixHeadlessCombobox",
39651
39651
  "cssParts": [
39652
39652
  {
@@ -43111,7 +43111,7 @@
43111
43111
  "declarations": [
43112
43112
  {
43113
43113
  "kind": "class",
43114
- "description": "The list is a `Listbox`, which handles filtering, the empty state, the match\nhighlight, `aria-activedescendant`, scrolling an option into view, and moving\nbetween options with the keyboard. The palette adds a dialog and a hotkey\nthat opens it.\n\nThe palette keeps no value. It is not a form control and submits nothing.\nChoosing an option dispatches `helix-select` once. To remember the last\ncommand, store it yourself. An option with `href` is a link to a page, which\nthe browser follows once the palette has closed.\n\nThe hotkey listener is on the document, so the hotkey works from anywhere on\nthe page, including inside another control's text field, whether or not the\npalette is open. `mod` means Command on a Mac and Control elsewhere, so you\nwrite one binding.\n\nWith `inline`, the palette is drawn in the page with no dialog, as a search\nover a list that is always shown.\n\n**Pages.** A command can open a page of commands of its own, as a palette\noffers \"Change theme\" and then the themes. Give the option `opens` with a\nname, and slot the page's commands as `page:` and that name:\n\n```html\n<helix-command>\n <helix-option value=\"theme\" opens=\"theme\">Change theme</helix-option>\n <helix-option value=\"dark\" slot=\"page:theme\">Dark</helix-option>\n <helix-option value=\"light\" slot=\"page:theme\">Light</helix-option>\n</helix-command>\n```\n\nChoosing the opener says `helix-select` with its value, and canceling it\nkeeps the page that is shown. The list then shows the page, named by the\nopener's words, and a screen reader hears those words. Backspace in an empty\nfilter goes back, and a screen reader hears the name of the page it goes\nback to. `page` says which page is shown.\n\nThe filter is cleared when the palette closes, so each opening starts from\nthe full list. Combobox and Select do the same. As typing narrows the list, a\nscreen reader hears how many commands are left, such as \"3 commands\".\n\n**Keyboard.** Focus goes to the filter field as the palette opens, with no\ncommand highlighted, as in React Aria's Autocomplete, so Enter runs nothing\nuntil you type or press Down. Typing highlights the first command left, and\nthe highlight moves through the commands while you type.\n\n| Key | What it does |\n|---|---|\n| `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. |\n| Down, Up | Moves the highlight to the next or the previous command, round from the last to the first. |\n| Page Down, Page Up | Moves the highlight by as many commands as the list shows at once. |\n| Home, End | Move the caret in the filter field. With `home-end=\"list\"`, move the highlight to the first or the last command. |\n| Left, Right | Move the caret in the filter field. |\n| 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. |\n| Command or Control with Enter | Takes the highlighted command's `alternate` destination, where it has one. |\n| Backspace | In an empty filter on a page, goes back to the page before. |\n| Escape | Clears the filter. With the filter empty, closes the palette and puts focus back where it was. |\n| Tab | Stays in the palette, which is modal. With `inline`, moves on through the page. |\n\n**ARIA.** The palette is a modal `dialog` named by `label`, or with\n`inline` no dialog at all. Inside it the filter field is a text field with\n`aria-autocomplete=\"list\"`, `aria-controls` on the list, and\n`aria-activedescendant` on the highlighted command, as the field of React\nAria's `Autocomplete` is. The commands are a `listbox` of `option`s. How many commands typing left, the empty text and\nthe loading text are said in a polite live region.",
43114
+ "description": "The list is a `Listbox`, which handles filtering, the empty state, the match\nhighlight, `aria-activedescendant`, scrolling an option into view, and moving\nbetween options with the keyboard. The palette adds a dialog and a hotkey\nthat opens it.\n\nThe palette keeps no value. It is not a form control and submits nothing.\nChoosing an option dispatches `helix-select` once. To remember the last\ncommand, store it yourself. An option with `href` is a link to a page, which\nthe browser follows once the palette has closed.\n\nThe hotkey listener is on the document, so the hotkey works from anywhere on\nthe page, including inside another control's text field, whether or not the\npalette is open. `mod` means Command on a Mac and Control elsewhere, so you\nwrite one binding.\n\nWith `inline`, the palette is drawn in the page with no dialog, as a search\nover a list that is always shown.\n\n**Pages.** A command can open a page of commands of its own, as a palette\noffers \"Change theme\" and then the themes. Give the option `opens` with a\nname, and slot the page's commands as `page:` and that name:\n\n```html\n<helix-command>\n <helix-option value=\"theme\" opens=\"theme\">Change theme</helix-option>\n <helix-option value=\"dark\" slot=\"page:theme\">Dark</helix-option>\n <helix-option value=\"light\" slot=\"page:theme\">Light</helix-option>\n</helix-command>\n```\n\nChoosing the opener says `helix-select` with its value, and canceling it\nkeeps the page that is shown. The list then shows the page, named by the\nopener's words, and a screen reader hears those words. Backspace in an empty\nfilter goes back, and a screen reader hears the name of the page it goes\nback to. `page` says which page is shown.\n\nThe filter is cleared when the palette closes, so each opening starts from\nthe full list. Combobox and Select do the same. As typing narrows the list, a\nscreen reader hears how many commands are left, such as \"3 commands\".\n\n**Keyboard.** Focus goes to the filter field as the palette opens, with no\ncommand highlighted, as in React Aria's Autocomplete, so Enter runs nothing\nuntil you type or press Down. Typing highlights the first command left, and\nthe highlight moves through the commands while you type.\n\n| Key | What it does |\n|---|---|\n| `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. |\n| Down, Up | Moves the highlight to the next or the previous command, round from the last to the first. |\n| Page Down, Page Up | Moves the highlight by as many commands as the list shows at once. |\n| Home, End | Move the caret in the filter field. With `home-end=\"list\"`, move the highlight to the first or the last command. |\n| Left, Right | Move the caret in the filter field. |\n| 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. |\n| Command or Control with Enter | Takes the highlighted command's `alternate` destination, where it has one. |\n| Backspace | In an empty filter on a page, goes back to the page before. |\n| Escape | Clears the filter. With the filter empty, closes the palette and puts focus back where it was. |\n| Tab | Stays in the palette, which is modal. With `inline`, moves on through the page. |\n\n**ARIA.** The palette is a modal `dialog` named by `label`, or with\n`inline` no dialog at all. Inside it the filter field is a text field with\n`aria-autocomplete=\"list\"`, `aria-controls` on the list, and\n`aria-activedescendant` on the highlighted command, as the field of React\nAria's `Autocomplete` is. The commands are a `listbox` of `option`s. How many commands typing left, the empty text and\nthe loading text are said in a polite live region.\n\n**The commands are an import of their own.** A command is an option, the\nOption family's, which the palette does not register, so a page that writes\none imports it beside the palette:\n\n```js\nimport '@fusion.dev/helix/command'\nimport '@fusion.dev/helix/option'\n```\n\nIn development, a palette holding an option nobody registered says so once\nthe page has loaded, with the line to add.",
43115
43115
  "name": "HelixHeadlessCommand",
43116
43116
  "cssParts": [
43117
43117
  {
@@ -46431,7 +46431,7 @@
46431
46431
  "declarations": [
46432
46432
  {
46433
46433
  "kind": "class",
46434
- "description": "Declare the columns as `TableColumn` children and pass the rows as an array.\nThe schema stays readable in the HTML, and the rows can be windowed, which\nten thousand row elements cannot be.\n\n```html\n<helix-headless-data-table .rows=${rows} sort=\"name:asc\" page-size=\"20\">\n <helix-headless-table-column field=\"name\" sortable>Name</helix-headless-table-column>\n <helix-headless-table-column field=\"size\" text-align=\"end\" sortable .cell=${bytes}>Size</helix-headless-table-column>\n</helix-headless-data-table>\n```\n\nFor a short table written out by hand, use `Table`, which takes rows as\nmarkup.\n\nSort and filter apply to the whole set, including the rows on other pages.\n\n**Write the first page as rows, so the served HTML carries the values.** The\ntable reads each cell from its column, and a server does not pass the column\nchildren to this element, so on its own it serves the headings and no values.\nWrite the first page under the columns as `TableRow` and `TableCell`\nelements, in the table's sort and page size and formatted as its columns draw\nthem. The table shows your rows until `rows` holds a row, then draws its own\nin their place and leaves yours in the page, unshown. A development build\nwarns when the two differ. In React, map the first page of the same array in\nthe same server component.\n\n`selectable` adds a column of checkboxes, keyed on `row-key`:\n\n- A row is selected by its key, so the selection survives a sort, a filter,\n and a page change.\n- `selected` holds the chosen keys, comma separated, the same shape `Listbox`\n uses for a multiple choice. As with `sort`, writing it applies the\n selection, and `default-selected` holds what the markup declared.\n- The checkbox in the heading selects every row in the result, across pages,\n and shows a dash while only some are chosen.\n- Shift with a press on a checkbox selects every row between it and the row\n last chosen.\n- `selection-behavior=\"replace\"` makes a press or a move select the row\n alone, as a file list does. Control or Command with a press adds or takes\n out one row, and Shift with a press selects every row from the one last\n chosen.\n\nTo act on a single row, such as opening it, put a link or a button in a cell.\n\n**Keyboard.** The grid is one tab stop, and the arrow keys move between its\ncells, the headings included.\n\n| Key | What it does |\n|---|---|\n| Right, Left | Moves one cell along the row. Left moves on, on a right-to-left page. |\n| Down, Up | Moves one row, the heading row and the `load-more` row included. |\n| Home, End | Moves to the first or the last cell of the row. |\n| Control with Home or End | Moves to the first or the last cell of the grid. |\n| Page Down, Page Up | Moves by the rows that fit in view. |\n| Enter, F2 | Moves into the cell's controls. Escape moves back to the cell, and Tab moves between the controls of one cell. |\n| Enter, Space on a sortable heading | Sorts by the column. |\n| Enter, Space on the `load-more` row | Sends `helix-load-more`. |\n| Space on a row | Selects the row, in a `selectable` table. Under `selection-behavior=\"replace\"`, selects it alone, and Control or Command with Space adds or takes out the row. |\n| Down, Up, Page Down, Page Up under `selection-behavior=\"replace\"` | Selects the row it moves to alone. Control or Command with the key moves without selecting. |\n| Shift with Down or Up | Selects the rows it moves across, in a `selectable` table. |\n| Shift with Space | Selects every row from the one last chosen, in a `selectable` table. |\n| Control or Command with A | Selects every row, in a `selectable` table. |\n| Right on a row header in a tree grid | Opens a closed row, and moves one cell along an open one. |\n| Left on a row header in a tree grid | Closes an open row, and moves to the parent of a closed one. |\n| A letter or a word | Moves to the next row whose row header starts with what you typed. |\n\n`selected` and `expanded` hold their keys in the order of the rows, as do\n`helix-select`, `helix-selected` and `helix-expand`.\n\nEach row is named by its row header, the column marked `row-header`, or the\nfirst column with a `field` where none is. A screen reader says it as a reader\nmoves between rows.\n\n**Rows that hold rows.** `child-field` names the field that holds a row's\nchild rows, and the grid becomes a tree grid. The row header column draws a\nmark that a press opens and closes a row by, and `expanded` holds the keys of the open\nrows, which `row-key` names. Right on a closed row's header opens it, Left on\nan open one closes it, and Left on a child moves to its parent. A sort orders\nthe rows under each parent, and a search shows the rows that lead to each\nmatch, open.\n\n`load-more` adds a row after the last one with a button that sends\n`helix-load-more`. A `windowed` table also sends it by itself once a reader\nscrolls within one screen of the end, once for each number of rows. Add the\nnext rows to `rows`, and set `loading` while they are on their way.\n\nWhen a fetch fails, set `error-text`, such as \"The files did not load\", and\nput a button that tries again in the `error` slot. The line shows after the\nrows in place of the empty and loading lines, the live region says it, and\nthe table takes the `error` state. Clear it once you try again.\n\nThe controls inside the cells leave the tab order, so Tab moves past the\nwhole grid. A windowed table keeps the row holding focus drawn while the\nrest scroll away.\n\nPeople can resize and reorder the columns. `resizable` on a column puts a\nseparator on its edge. `reorderable` on the table puts a grip on each heading\nthat has a `field`, moved by dragging or with the arrow keys. The new order\nis written to `order` as a list of fields. Your markup is not rewritten: the\ntable assigns the headings to its header in that order.\n\n**`reorderable-rows` lets people move rows.** A column of grips leads each\nrow, named by `move-row-label`. Drag a grip to move its row, and the table\nscrolls near an edge. Or press Space or Enter on a grip, or click it, to pick\nup its row, move it with Down and Up, Home and End, and press Space or Enter\nagain to drop it. A click on another row drops it there, and Escape puts it\nback. The table says each step in its `live` region. A drop sends\n`helix-before-reorder`, which you can refuse, and then `helix-reorder` with\n`kind` set to `row`, whose `keys` hold every key of `rows` in the new order.\n**You move the rows**: set `rows` to the new order, and the table draws it.\nSet `row-key`, so a row is known by its key once it has moved. The grips do\nnothing while a `sort` is set, since the sort decides the order, and a tree\ngrid draws none.\n\n`csv()` returns the result as text: every row that passes the filter, in the\norder and the columns on screen. Saving the file is up to you.\n\n`DataTable` has no `columns` attribute. Each `TableColumn` is part of the\nschema, so you size a column with its own `width`. `Table` has `columns`\nbecause its cells are markup you write and it can have no columns at all.\nWritten on `DataTable`, `columns` has no effect, so watch for it when you\nmove a table from `Table` to `DataTable`.",
46434
+ "description": "Declare the columns as `TableColumn` children and pass the rows as an array.\nThe schema stays readable in the HTML, and the rows can be windowed, which\nten thousand row elements cannot be.\n\n```html\n<helix-headless-data-table .rows=${rows} sort=\"name:asc\" page-size=\"20\">\n <helix-headless-table-column field=\"name\" sortable>Name</helix-headless-table-column>\n <helix-headless-table-column field=\"size\" text-align=\"end\" sortable .cell=${bytes}>Size</helix-headless-table-column>\n</helix-headless-data-table>\n```\n\nFor a short table written out by hand, use `Table`, which takes rows as\nmarkup.\n\nSort and filter apply to the whole set, including the rows on other pages.\n\n**Write the first page as rows, so the served HTML carries the values.** The\ntable reads each cell from its column, and a server does not pass the column\nchildren to this element, so on its own it serves the headings and no values.\nWrite the first page under the columns as `TableRow` and `TableCell`\nelements, in the table's sort and page size and formatted as its columns draw\nthem. The table shows your rows until `rows` holds a row, then draws its own\nin their place and leaves yours in the page, unshown. A development build\nwarns when the two differ. In React, map the first page of the same array in\nthe same server component.\n\n`selectable` adds a column of checkboxes, keyed on `row-key`:\n\n- A row is selected by its key, so the selection survives a sort, a filter,\n and a page change.\n- `selected` holds the chosen keys, comma separated, the same shape `Listbox`\n uses for a multiple choice. As with `sort`, writing it applies the\n selection, and `default-selected` holds what the markup declared.\n- The checkbox in the heading selects every row in the result, across pages,\n and shows a dash while only some are chosen.\n- Shift with a press on a checkbox selects every row between it and the row\n last chosen.\n- `selection-behavior=\"replace\"` makes a press or a move select the row\n alone, as a file list does. Control or Command with a press adds or takes\n out one row, and Shift with a press selects every row from the one last\n chosen.\n\nTo act on a single row, such as opening it, put a link or a button in a cell.\n\n**Keyboard.** The grid is one tab stop, and the arrow keys move between its\ncells, the headings included.\n\n| Key | What it does |\n|---|---|\n| Right, Left | Moves one cell along the row. Left moves on, on a right-to-left page. |\n| Down, Up | Moves one row, the heading row and the `load-more` row included. |\n| Home, End | Moves to the first or the last cell of the row. |\n| Control with Home or End | Moves to the first or the last cell of the grid. |\n| Page Down, Page Up | Moves by the rows that fit in view. |\n| Enter, F2 | Moves into the cell's controls. Escape moves back to the cell, and Tab moves between the controls of one cell. |\n| Enter, Space on a sortable heading | Sorts by the column. |\n| Enter, Space on the `load-more` row | Sends `helix-load-more`. |\n| Space on a row | Selects the row, in a `selectable` table. Under `selection-behavior=\"replace\"`, selects it alone, and Control or Command with Space adds or takes out the row. |\n| Down, Up, Page Down, Page Up under `selection-behavior=\"replace\"` | Selects the row it moves to alone. Control or Command with the key moves without selecting. |\n| Shift with Down or Up | Selects the rows it moves across, in a `selectable` table. |\n| Shift with Space | Selects every row from the one last chosen, in a `selectable` table. |\n| Control or Command with A | Selects every row, in a `selectable` table. |\n| Right on a row header in a tree grid | Opens a closed row, and moves one cell along an open one. |\n| Left on a row header in a tree grid | Closes an open row, and moves to the parent of a closed one. |\n| A letter or a word | Moves to the next row whose row header starts with what you typed. |\n\n`selected` and `expanded` hold their keys in the order of the rows, as do\n`helix-select`, `helix-selected` and `helix-expand`.\n\nEach row is named by its row header, the column marked `row-header`, or the\nfirst column with a `field` where none is. A screen reader says it as a reader\nmoves between rows.\n\n**Rows that hold rows.** `child-field` names the field that holds a row's\nchild rows, and the grid becomes a tree grid. The row header column draws a\nmark that a press opens and closes a row by, and `expanded` holds the keys of the open\nrows, which `row-key` names. Right on a closed row's header opens it, Left on\nan open one closes it, and Left on a child moves to its parent. A sort orders\nthe rows under each parent, and a search shows the rows that lead to each\nmatch, open.\n\n`load-more` adds a row after the last one with a button that sends\n`helix-load-more`. A `windowed` table also sends it by itself once a reader\nscrolls within one screen of the end, once for each number of rows. Add the\nnext rows to `rows`, and set `loading` while they are on their way.\n\nWhen a fetch fails, set `error-text`, such as \"The files did not load\", and\nput a button that tries again in the `error` slot. The line shows after the\nrows in place of the empty and loading lines, the live region says it, and\nthe table takes the `error` state. Clear it once you try again.\n\nThe controls inside the cells leave the tab order, so Tab moves past the\nwhole grid. A windowed table keeps the row holding focus drawn while the\nrest scroll away.\n\nPeople can resize and reorder the columns. `resizable` on a column puts a\nseparator on its edge. `reorderable` on the table puts a grip on each heading\nthat has a `field`, moved by dragging or with the arrow keys. The new order\nis written to `order` as a list of fields. Your markup is not rewritten: the\ntable assigns the headings to its header in that order.\n\n**`reorderable-rows` lets people move rows.** A column of grips leads each\nrow, named by `move-row-label`. Drag a grip to move its row, and the table\nscrolls near an edge. Or press Space or Enter on a grip, or click it, to pick\nup its row, move it with Down and Up, Home and End, and press Space or Enter\nagain to drop it. A click on another row drops it there, and Escape puts it\nback. The table says each step in its `live` region. A drop sends\n`helix-before-reorder`, which you can refuse, and then `helix-reorder` with\n`kind` set to `row`, whose `keys` hold every key of `rows` in the new order.\n**You move the rows**: set `rows` to the new order, and the table draws it.\nSet `row-key`, so a row is known by its key once it has moved. The grips do\nnothing while a `sort` is set, since the sort decides the order, and a tree\ngrid draws none.\n\n`csv()` returns the result as text: every row that passes the filter, in the\norder and the columns on screen. Saving the file is up to you.\n\n`DataTable` has no `columns` attribute. Each `TableColumn` is part of the\nschema, so you size a column with its own `width`. `Table` has `columns`\nbecause its cells are markup you write and it can have no columns at all.\nWritten on `DataTable`, `columns` has no effect, so watch for it when you\nmove a table from `Table` to `DataTable`.\n\n**The columns are an import of their own.** A column is the Table family's\n`TableColumn`, which the data table does not register, so a page that writes\none imports the Table entry beside the data table:\n\n```js\nimport '@fusion.dev/helix/data-table'\nimport '@fusion.dev/helix/table'\n```\n\nIn development, a data table holding a column nobody registered says so once\nthe page has loaded, with the line to add.",
46435
46435
  "name": "HelixHeadlessDataTable",
46436
46436
  "cssProperties": [
46437
46437
  {
@@ -50530,7 +50530,7 @@
50530
50530
  "declarations": [
50531
50531
  {
50532
50532
  "kind": "class",
50533
- "description": "The calendar is `DatePicker`, which handles months, ranges, disabled days,\nthe first day of the week, and the grid's keyboard behavior. The date input\nadds the field, the overlay, and the connection between them.\n\nYou can type a date as well as pick one. The native `<input type=\"date\">`\ngives a picker and locale formatting but allows almost no styling, so the\nfield is a text field. Typing sends `input` on each keystroke and `change`\nwhen you leave the field, as a text field does. A date picked from the\ncalendar sends both. The field reads ISO, `2026-08-04`, and a date written\nin the order, the digits, and the month names of `locale`, `8/4/2026` or\n`Aug 4, 2026` in `en-US` and `4.8.2026` in `de-DE`, which becomes the value\nas you leave the field.\n\nThe trigger and ArrowDown open the calendar with focus on the selected day,\nTab moves between the calendar's controls without leaving it, and Escape\ncloses it and returns focus to the field. A press into the field opens the\ncalendar too. Tab into the field opens nothing, and Tab out of the field\ncloses the calendar. The text field is a `combobox` with\n`aria-haspopup=\"dialog\"`, `aria-expanded`, and `aria-controls`, as in the\nAPG date picker combobox, since Down opens the calendar from it.\n\nWith `segmented`, the field is a row of segments in place of the text: a\nmonth, a day and a year in the order the locale writes them, each set with\ndigits or the arrow keys. Alt+Down opens the calendar from a segment. A\n`range` is two rows with a dash between them, the start and the end, as\nReact Aria's DateRangePicker draws them, and `multiple` keeps the text.\n\nText that is not a date gives the form an empty value, as a native date\nfield does, and `value` keeps the text so it can be corrected.\n\n**Keyboard.** The field is one tab stop, or each segment is with\n`segmented`, and the trigger is one more.\n\n| Key | What it does |\n|---|---|\n| Down | In the text field, opens the calendar with focus on the chosen day. |\n| Alt with Down | Opens the calendar, from the text field or a segment. |\n| Enter | In the text field, takes the typed date and submits the form, as a native field does. |\n| Escape | Closes the calendar and puts focus back in the field. |\n| Tab | In the open calendar, moves between its controls. Out of the field, closes it. |\n| Up, Down on a segment | Steps the segment by one, round from its last value to its first. |\n| Page Up, Page Down on a segment | Steps by a page: a week of days, two months, or five years. |\n| Home, End on a segment | Goes to the segment's first or last value. |\n| Digits on a segment | Fill it, and move to the next once it can take no more. |\n| Backspace, Delete on a segment | Take off its last digit, or move to the segment before where it is empty. |\n| Left, Right on a segment | Move to the previous or the next segment, along the line of text. |\n\nIn the calendar, the keys are `DatePicker`'s: the arrows move by a day or a\nweek, Page Up and Page Down by a month, with Shift by a year, and Home and\nEnd to the start and the end of the week.",
50533
+ "description": "The calendar is `DatePicker`, which handles months, ranges, disabled days,\nthe first day of the week, and the grid's keyboard behavior. The date input\nadds the field, the overlay, and the connection between them.\n\nYou can type a date as well as pick one. The native `<input type=\"date\">`\ngives a picker and locale formatting but allows almost no styling, so the\nfield is a text field. Typing sends `input` on each keystroke and `change`\nwhen you leave the field, as a text field does. A date picked from the\ncalendar sends both. The field reads ISO, `2026-08-04`, and a date written\nin the order, the digits, and the month names of `locale`, `8/4/2026` or\n`Aug 4, 2026` in `en-US` and `4.8.2026` in `de-DE`, which becomes the value\nas you leave the field.\n\nThe trigger and ArrowDown open the calendar with focus on the selected day,\nTab moves between the calendar's controls without leaving it, and Escape\ncloses it and returns focus to the field. A press into the field opens the\ncalendar too. Tab into the field opens nothing, and Tab out of the field\ncloses the calendar. The text field is a `combobox` with\n`aria-haspopup=\"dialog\"`, `aria-expanded`, and `aria-controls`, as in the\nAPG date picker combobox, since Down opens the calendar from it.\n\nWith `segmented`, the field is a row of segments in place of the text: a\nmonth, a day and a year in the order the locale writes them, each set with\ndigits or the arrow keys. Alt+Down opens the calendar from a segment. A\n`range` is two rows with a dash between them, the start and the end, as\nReact Aria's DateRangePicker draws them, and `multiple` keeps the text.\nA range whose end is before its start reports `rangeUnderflow`, as Date\nPicker does, with `range-order-message`.\n\nText that is not a date gives the form an empty value, as a native date\nfield does, and `value` keeps the text so it can be corrected.\n\n**Keyboard.** The field is one tab stop, or each segment is with\n`segmented`, and the trigger is one more.\n\n| Key | What it does |\n|---|---|\n| Down | In the text field, opens the calendar with focus on the chosen day. |\n| Alt with Down | Opens the calendar, from the text field or a segment. |\n| Enter | In the text field, takes the typed date and submits the form, as a native field does. |\n| Escape | Closes the calendar and puts focus back in the field. |\n| Tab | In the open calendar, moves between its controls. Out of the field, closes it. |\n| Up, Down on a segment | Steps the segment by one, round from its last value to its first. |\n| Page Up, Page Down on a segment | Steps by a page: a week of days, two months, or five years. |\n| Home, End on a segment | Goes to the segment's first or last value. |\n| Digits on a segment | Fill it, and move to the next once it can take no more. |\n| Backspace, Delete on a segment | Take off its last digit, or move to the segment before where it is empty. |\n| Left, Right on a segment | Move to the previous or the next segment, along the line of text. |\n\nIn the calendar, the keys are `DatePicker`'s: the arrows move by a day or a\nweek, Page Up and Page Down by a month, with Shift by a year, and Home and\nEnd to the start and the end of the week.",
50534
50534
  "name": "HelixHeadlessDateInput",
50535
50535
  "cssParts": [
50536
50536
  {
@@ -51172,6 +51172,19 @@
51172
51172
  "words": true
51173
51173
  }
51174
51174
  },
51175
+ {
51176
+ "kind": "field",
51177
+ "name": "rangeOrderMessage",
51178
+ "type": {
51179
+ "text": "string"
51180
+ },
51181
+ "default": "'Choose an end on or after {start}.'",
51182
+ "description": "The message shown when a range ends before it starts. `{start}` is\nreplaced with the start, written the way the field writes dates.",
51183
+ "attribute": "range-order-message",
51184
+ "helix": {
51185
+ "words": true
51186
+ }
51187
+ },
51175
51188
  {
51176
51189
  "kind": "field",
51177
51190
  "name": "rangeOverflowMessage",
@@ -54559,6 +54572,15 @@
54559
54572
  "description": "The message shown when a range holds more than two dates.\n\n**Every sentence a control raises in the browser's bubble is a property**,\nso a form in another language speaks it. Unset is the sentence registered\nfor the page's language, then the English.",
54560
54573
  "fieldName": "rangeLengthMessage"
54561
54574
  },
54575
+ {
54576
+ "name": "range-order-message",
54577
+ "type": {
54578
+ "text": "string"
54579
+ },
54580
+ "default": "'Choose an end on or after {start}.'",
54581
+ "description": "The message shown when a range ends before it starts. `{start}` is\nreplaced with the start, written the way the field writes dates.",
54582
+ "fieldName": "rangeOrderMessage"
54583
+ },
54562
54584
  {
54563
54585
  "name": "range-overflow-message",
54564
54586
  "type": {
@@ -55108,7 +55130,7 @@
55108
55130
  "declarations": [
55109
55131
  {
55110
55132
  "kind": "class",
55111
- "description": "A grid of days that follows the APG date grid pattern:\n\n- The grid is one tab stop. Only the focused cell is in the tab sequence.\n- Arrow keys move by day and by week.\n- `PageUp` and `PageDown` move by month.\n- `Home` and `End` move to the start and end of the week.\n\n**Dates are `YYYY-MM-DD` strings, and every calculation is in UTC**, because\na local-time `Date` shifts across a time zone or daylight-saving boundary.\n\n**The months are the ones `calendar` counts**: the Gregorian months for the\nlocale's own calendar where its months are the Gregorian months, as `th-TH`\nwrites 2569 for 2026, and `gregory` where they are not, as for `fa-IR`\nwith no `calendar`. Name a calendar with months of its own, such as\n`persian`, and every view counts its days, months, and years from `Intl`.\n\n`month` sets which month the grid shows, separately from `value`, so paging\nselects nothing and you can control the view. When unset, it follows the\nfirst selected date, then the current month.\n\n`mode` sets how many dates are held. Unset holds one, `range` holds two and\nmarks the dates between them, and `multiple` toggles each date. All three\nread and write the same comma-separated `value`. With a `mode`, the grid\ncarries `aria-multiselectable`. While a range holds one end, the grid draws\nthe range to the day under the pointer or the focus, marking those cells\n`data-range-preview`.\n\nThe chosen date, range, or count of dates is the grid's description, in a\nregion screen readers announce when it changes, as React Aria's calendars\ndo. `selection-label` words it.\n\n`max-view` makes the heading a button that steps back to the months of the\nyear, and with `year` to a page of years, as Zag's date picker does. The\narrows, Home, End and the page keys move there, Enter or a press chooses, and\nEscape goes back to the days.\n\n`isDateUnavailable` and `dayContent` are properties for a script: a rule\nthat bars dates, and what each day shows in place of its number.\n\nThe month heading is a live region, so a screen reader hears the new month\nwhen Previous or Next is pressed. Neither moves past `min` or `max`, and the\nkeys stop at them too. A value outside the bounds, on a barred day, or off\n`step` reports `rangeUnderflow`, `rangeOverflow`, `badInput` or\n`stepMismatch`, so a form does not submit it.",
55133
+ "description": "A grid of days that follows the APG date grid pattern:\n\n- The grid is one tab stop. Only the focused cell is in the tab sequence.\n- Arrow keys move by day and by week.\n- `PageUp` and `PageDown` move by month.\n- `Home` and `End` move to the start and end of the week.\n\n**Dates are `YYYY-MM-DD` strings, and every calculation is in UTC**, because\na local-time `Date` shifts across a time zone or daylight-saving boundary.\n\n**The months are the ones `calendar` counts**: the Gregorian months for the\nlocale's own calendar where its months are the Gregorian months, as `th-TH`\nwrites 2569 for 2026, and `gregory` where they are not, as for `fa-IR`\nwith no `calendar`. Name a calendar with months of its own, such as\n`persian`, and every view counts its days, months, and years from `Intl`.\n\n`month` sets which month the grid shows, separately from `value`, so paging\nselects nothing and you can control the view. When unset, it follows the\nfirst selected date, then the current month.\n\n`mode` sets how many dates are held. Unset holds one, `range` holds two and\nmarks the dates between them, and `multiple` toggles each date. All three\nread and write the same comma-separated `value`. With a `mode`, the grid\ncarries `aria-multiselectable`. While a range holds one end, the grid draws\nthe range to the day under the pointer or the focus, marking those cells\n`data-range-preview`.\n\nThe chosen date, range, or count of dates is the grid's description, in a\nregion screen readers announce when it changes, as React Aria's calendars\ndo. `selection-label` words it.\n\n`max-view` makes the heading a button that steps back to the months of the\nyear, and with `year` to a page of years, as Zag's date picker does. The\narrows, Home, End and the page keys move there, Enter or a press chooses, and\nEscape goes back to the days.\n\n`isDateUnavailable` and `dayContent` are properties for a script: a rule\nthat bars dates, and what each day shows in place of its number.\n\nThe month heading is a live region, so a screen reader hears the new month\nwhen Previous or Next is pressed. Neither moves past `min` or `max`, and the\nkeys stop at them too. A value outside the bounds, on a barred day, or off\n`step` reports `rangeUnderflow`, `rangeOverflow`, `badInput` or\n`stepMismatch`, so a form does not submit it. A range set from a script\nwhose end is before its start reports `rangeUnderflow` as well.",
55112
55134
  "name": "HelixHeadlessDatePicker",
55113
55135
  "cssProperties": [
55114
55136
  {
@@ -55546,6 +55568,19 @@
55546
55568
  "words": true
55547
55569
  }
55548
55570
  },
55571
+ {
55572
+ "kind": "field",
55573
+ "name": "rangeOrderMessage",
55574
+ "type": {
55575
+ "text": "string"
55576
+ },
55577
+ "default": "'Choose an end on or after {start}.'",
55578
+ "description": "The validation message for a range that ends before it starts. `{start}`\nis replaced with the start, written as a date in `locale`.",
55579
+ "attribute": "range-order-message",
55580
+ "helix": {
55581
+ "words": true
55582
+ }
55583
+ },
55549
55584
  {
55550
55585
  "kind": "field",
55551
55586
  "name": "rangeOverflowMessage",
@@ -57717,6 +57752,15 @@
57717
57752
  "description": "Accessible name for the control that moves back a page, in the years.",
57718
57753
  "fieldName": "previousYearsLabel"
57719
57754
  },
57755
+ {
57756
+ "name": "range-order-message",
57757
+ "type": {
57758
+ "text": "string"
57759
+ },
57760
+ "default": "'Choose an end on or after {start}.'",
57761
+ "description": "The validation message for a range that ends before it starts. `{start}`\nis replaced with the start, written as a date in `locale`.",
57762
+ "fieldName": "rangeOrderMessage"
57763
+ },
57720
57764
  {
57721
57765
  "name": "range-overflow-message",
57722
57766
  "type": {
@@ -70927,7 +70971,7 @@
70927
70971
  "declarations": [
70928
70972
  {
70929
70973
  "kind": "class",
70930
- "description": "Tokens are your own elements, slotted in. A filter can be a facet with a\nprefix, a saved query, or a range, and these belong to your model, so the\nelement does not render tokens from a list of strings. Removing a token is a\nrequest the element fires, and you apply it. Combobox works the other way:\nits tokens show a selection it owns, drawn from the options it was given.\n\n`value` is the typed text. Every keystroke fires `input` with the text on the\nelement, so a table can narrow as the user types. Backspace in an empty field\nfires `helix-dismiss` on the last token, the same event its remove control\nfires, so one handler covers the pointer and the keyboard.\n\n**What a form receives.** The text under `name`, and then one more entry\nunder `name` for each token, in the order the tokens stand:\n\n| Token | Entry |\n|---|---|\n| Any element with a `value` attribute | The value as written: `saved:mine` |\n| `FilterChip` with `name` and values | `status:open,pending` |\n| The same, with `operator=\"none\"` (what a typed `-status:` makes) | `-status:open,pending` |\n| The same, with any other `operator` except `any` | `created[after]:2024` |\n| A token with neither | Nothing |\n\nThe values are the chip's text outside its `field` and `operator` slots,\nwith the spaces around each comma removed. A server splits an entry at its\nfirst colon, reads a leading `-` as the negation, and reads a word in\nbrackets before the colon as the comparison.\n\n**Keyboard.** Focus stays in the text, which is the field's one tab stop. The\ntext names the highlighted suggestion as its `aria-activedescendant`, and the\narrow keys reach the tokens.\n\n| Key | What it does |\n|---|---|\n| Enter | Presses the highlighted suggestion. With none highlighted, reads the typed filters into chips, or submits the form when there are none. |\n| Down, Up | Moves the highlight through the suggestions, wrapping, and opens the panel. |\n| Home, End | Highlights the first or the last suggestion while the panel is open. |\n| Escape | Closes the panel and stops there, so a dialog around the field stays open. With the panel closed, empties the text. In an empty field, does nothing, so the page hears it. |\n| Backspace | In an empty field, asks the last token to go. |\n| Left | With the caret at the start of the text, moves to the last token's remove button. Right on a right-to-left page. |\n| Left, Right on a token | Move between the tokens, and past the last back to the text. |\n| Delete, Backspace on a token | Asks the token to go. |\n\n**Typed filters.** The field parses only the fields you declare. Write\n`FilterField` elements, usually inside the `FilterMenu` slotted into `start`,\nso the picker and the text share one set. On Enter, the field reads the text\nagainst them, and a paste is read the same way as soon as it lands.\n`disposition:refunded,settled` and `-disposition:refunded` fire\n`helix-facet` exactly as ticking those values in the picker would, and the\nparsed text is removed. Everything else stays, so `refund tuesday\ndisposition:settled` is a filter and a search at once. Helix defines the\npunctuation and you define every word. `grammar.ts` has the full rule, so\nread it before you rely on it. A field with no `FilterField` in it parses\nnothing.\n\nA field whose values cannot be listed, such as `assignee:ada`, goes directly\ninside this element, outside the menu. It is not assigned to a slot, so\nnothing draws it and the menu has no page for it, and the grammar still reads\nit.\n\n**The picker has an entry of its own.** `FilterMenu` draws its pages with\n`Menu`, which a field without a picker does not need, so this family's entry\nleaves it out. A page that writes a `FilterMenu` imports both entries:\n\n```js\nimport '@fusion.dev/helix/filter-input'\nimport '@fusion.dev/helix/filter-input/menu'\n```\n\nA picker written without the second is reported once the page has loaded,\nwith the entry to add.\n\n**Suggestions.** Slot options into `suggestions` and the field shows them,\nmoves through them with the arrow keys, and presses one on Enter. The option\nfires its own `helix-select`, and you decide what choosing it means. Keys\nbefore a colon and values after it use the same panel with different\ncontents. `filter-suggestions` narrows the panel to the options whose words\nhold the term at the caret, after its colon, ignoring case and accents, and\nhides the rest. `readFilterText` is exported so you can narrow it yourself\nagainst partly typed text. While the panel is open, a reader hears how many\nsuggestions it offers. The panel opens when it has options and closes when it has\nnone, and a choice does not close it, so after picking a key you see its\nvalues next. Use `selectionStart` and `setSelectionRange` to write a\ncompletion back and put the caret after it, or the next parse reads the wrong\nterm.\n\n**Suggestions from a source.** Set `source` to a function, and the field asks\nit for suggestions as the text changes and draws them as options in the\npanel. It is given the term at the caret, the field the term is a value of,\nthe whole text, and an `AbortSignal`, and returns the suggestions or a\npromise of them. `filter-delay` waits for typing to rest before asking, and\na later keystroke aborts a request still out. While a promise is pending, the\npanel shows `loading-text` and a screen reader hears it, then the count.\nChoosing a suggestion writes its value over the term at the caret, and a\nfinished `field:value` is read into a chip as Enter would. Cancel its\n`helix-select` to write it yourself.\n\n```js\nfilter.source = async ({ field, term, signal }) => {\n const response = await fetch(`/values?field=${field}&q=${term}`, { signal })\n return response.json()\n}\n```\n\n**State.** Three things have three different owners:\n\n- `value` is the text. The user types, the element applies it, and `input`\n reports it. Setting `value` seeds or corrects the text, and the next\n keystroke overwrites it, even in React. To control the value, cancel\n `helix-before-change` and write the value you want, as with every field in\n this library. `default-value` seeds the field.\n- `open` is the suggestions panel. Cancel `helix-before-open` or\n `helix-before-close` to control it, and use `default-open` to seed it.\n- Tokens are your elements in a slot and hold no state. A token goes when you\n remove it from your markup after `helix-dismiss`. A `FilterChip` naming a\n declared field works differently, because the picker holds what is ticked\n and removing the chip alone would leave its value ticked in the hidden\n menu. Its dismissal is treated as the field being filtered by nothing, so\n it fires `helix-facet` like every other change, and the chip goes when the\n filter goes. Set `chips` and the field adds, updates, and removes those\n chips itself, from every `helix-facet` you do not cancel.",
70974
+ "description": "Tokens are your own elements, slotted in. A filter can be a facet with a\nprefix, a saved query, or a range, and these belong to your model, so the\nelement does not render tokens from a list of strings. Removing a token is a\nrequest the element fires, and you apply it. Combobox works the other way:\nits tokens show a selection it owns, drawn from the options it was given.\n\n`value` is the typed text. Every keystroke fires `input` with the text on the\nelement, so a table can narrow as the user types. Backspace in an empty field\nfires `helix-dismiss` on the last token, the same event its remove control\nfires, so one handler covers the pointer and the keyboard.\n\n**What a form receives.** The text under `name`, and then one more entry\nunder `name` for each token, in the order the tokens stand:\n\n| Token | Entry |\n|---|---|\n| Any element with a `value` attribute | The value as written: `saved:mine` |\n| `FilterChip` with `name` and values | `status:open,pending` |\n| The same, with `operator=\"none\"` (what a typed `-status:` makes) | `-status:open,pending` |\n| The same, with any other `operator` except `any` | `created[after]:2024` |\n| A token with neither | Nothing |\n\nThe values are the chip's text outside its `field` and `operator` slots,\nwith the spaces around each comma removed. A server splits an entry at its\nfirst colon, reads a leading `-` as the negation, and reads a word in\nbrackets before the colon as the comparison.\n\n**Keyboard.** Focus stays in the text, which is the field's one tab stop. The\ntext names the highlighted suggestion as its `aria-activedescendant`, and the\narrow keys reach the tokens.\n\n| Key | What it does |\n|---|---|\n| Enter | Presses the highlighted suggestion. With none highlighted, reads the typed filters into chips, or submits the form when there are none. |\n| Down, Up | Moves the highlight through the suggestions, wrapping, and opens the panel. |\n| Home, End | Highlights the first or the last suggestion while the panel is open. |\n| Escape | Closes the panel and stops there, so a dialog around the field stays open. With the panel closed, empties the text. In an empty field, does nothing, so the page hears it. |\n| Backspace | In an empty field, asks the last token to go. |\n| Left | With the caret at the start of the text, moves to the last token's remove button. Right on a right-to-left page. |\n| Left, Right on a token | Move between the tokens, and past the last back to the text. |\n| Delete, Backspace on a token | Asks the token to go. |\n\n**Typed filters.** The field parses only the fields you declare. Write\n`FilterField` elements, usually inside the `FilterMenu` slotted into `start`,\nso the picker and the text share one set. On Enter, the field reads the text\nagainst them, and a paste is read the same way as soon as it lands.\n`disposition:refunded,settled` and `-disposition:refunded` fire\n`helix-facet` exactly as ticking those values in the picker would, and the\nparsed text is removed. Everything else stays, so `refund tuesday\ndisposition:settled` is a filter and a search at once. Helix defines the\npunctuation and you define every word. `grammar.ts` has the full rule, so\nread it before you rely on it. A field with no `FilterField` in it parses\nnothing.\n\nA field whose values cannot be listed, such as `assignee:ada`, goes directly\ninside this element, outside the menu. It is not assigned to a slot, so\nnothing draws it and the menu has no page for it, and the grammar still reads\nit.\n\n**The picker has an entry of its own.** `FilterMenu` draws its pages with\n`Menu`, which a field without a picker does not need, so this family's entry\nleaves it out. A page that writes a `FilterMenu` imports both entries:\n\n```js\nimport '@fusion.dev/helix/filter-input'\nimport '@fusion.dev/helix/filter-input/menu'\n```\n\nA picker written without the second is reported once the page has loaded,\nwith the entry to add.\n\n**Suggestions.** Slot options into `suggestions` and the field shows them,\nmoves through them with the arrow keys, and presses one on Enter. The option\nfires its own `helix-select`, and you decide what choosing it means. Keys\nbefore a colon and values after it use the same panel with different\ncontents. `filter-suggestions` narrows the panel to the options whose words\nhold the term at the caret, after its colon, ignoring case and accents, and\nhides the rest. `readFilterText` is exported so you can narrow it yourself\nagainst partly typed text. While the panel is open, a reader hears how many\nsuggestions it offers. The panel opens when it has options and closes when it has\nnone, and a choice does not close it, so after picking a key you see its\nvalues next. Use `selectionStart` and `setSelectionRange` to write a\ncompletion back and put the caret after it, or the next parse reads the wrong\nterm.\n\n**Suggestions from a source.** Set `source` to a function, and the field asks\nit for suggestions as the text changes and draws them as options in the\npanel. It is given the term at the caret, the field the term is a value of,\nthe whole text, and an `AbortSignal`, and returns the suggestions or a\npromise of them. `filter-delay` waits for typing to rest before asking, and\na later keystroke aborts a request still out. While a promise is pending, the\npanel shows `loading-text` and a screen reader hears it, then the count.\nChoosing a suggestion writes its value over the term at the caret, and a\nfinished `field:value` is read into a chip as Enter would. Cancel its\n`helix-select` to write it yourself.\n\n```js\nfilter.source = async ({ field, term, signal }) => {\n const response = await fetch(`/values?field=${field}&q=${term}`, { signal })\n return response.json()\n}\n```\n\n**State.** Three things have three different owners:\n\n- `value` is the text. The user types, the element applies it, and `input`\n reports it. Setting `value` seeds or corrects the text, and the next\n keystroke overwrites it, even in React. To control the value, cancel\n `helix-before-change` and write the value you want, as with every field in\n this library. `default-value` seeds the field.\n- `open` is the suggestions panel. Cancel `helix-before-open` or\n `helix-before-close` to control it, and use `default-open` to seed it.\n- Tokens are your elements in a slot and hold no state. A token goes when you\n remove it from your markup after `helix-dismiss`. A `FilterChip` naming a\n declared field works differently, because the picker holds what is ticked\n and removing the chip alone would leave its value ticked in the hidden\n menu. Its dismissal is treated as the field being filtered by nothing, so\n it fires `helix-facet` like every other change, and the chip goes when the\n filter goes. Set `chips` and the field adds, updates, and removes those\n chips itself, from every `helix-facet` you do not cancel.\n\n**The suggestions you write are an import of their own.** A suggestion is an\noption, the Option family's, which the field does not register, so a page\nthat slots one imports it beside the field:\n\n```js\nimport '@fusion.dev/helix/filter-input'\nimport '@fusion.dev/helix/option'\n```\n\nIn development, a field holding an option nobody registered says so once the\npage has loaded, with the line to add. The options `source` gives are drawn\nas this Option too, and need the same import.",
70931
70975
  "name": "HelixHeadlessFilterInput",
70932
70976
  "cssParts": [
70933
70977
  {
@@ -96454,7 +96498,7 @@
96454
96498
  "declarations": [
96455
96499
  {
96456
96500
  "kind": "class",
96457
- "description": "The listbox is the control, and options are its items. A Select is a listbox\nwith a trigger in front of it, a Combobox is a listbox with a text input, and\na command palette is a listbox in a dialog. They differ only in what opens\nthe list and what filters it.\n\nWith `multiple` set, `value` is a comma-separated string, like\n`Checkbox.Group`'s, because `MixinControllerValue` holds a string. The form\nreceives one entry per selected option, as a native `<select multiple>` sends\nit, so your server does not split on commas. An option's value may hold a\ncomma: a run of the string that is an option's value is read as that one\nvalue, and the form sends it as one entry.\n\nSelected and active are separate. The selected option is the value. The\nactive option is where the keyboard is: the arrow keys move it, and\n`aria-activedescendant` points to it while focus stays on the list.\n\n**Keyboard.** The list is one tab stop, or its filter field is where there\nis one. In a single-choice list the highlight is the choice unless `manual`\nis set; then Enter, Space or a click chooses.\n\n| Key | What it does |\n|---|---|\n| 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. |\n| Right, Left | With `layout=\"grid\"`, moves to the next or the previous option, mirrored right to left. In a filter field, moves the caret. |\n| Home, End | Moves to the first or the last option. In a filter field, moves the caret. |\n| Page Down, Page Up | Moves by as many options as the list shows at once. |\n| A letter or a word | Moves to the next option whose words start with what you typed. In a filter field, types it. |\n| Enter | Chooses the highlighted option, or follows it where it is a link. |\n| Space | Chooses the highlighted option, or with `multiple` toggles it. In a filter field, types a space. |\n| 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. |\n| Shift with Space | With `multiple`, adds every option from the one last chosen to the highlighted one. In a filter field, types a space. |\n| Shift with Home or End | With `multiple`, adds every option from the highlight to that end. In a filter field, hold Control as well. |\n| Control or Command with A | With `multiple`, chooses every option, or none where all are chosen. In a filter field, selects the text. |\n| Escape | In a filter field, clears the filter. |\n| 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. |\n\n**ARIA.** The `items` part is the `listbox`, named by the label and\ndescribed by the hint and the message, with `aria-multiselectable` under\n`multiple`, `aria-required`, `aria-invalid`, and `aria-busy` while loading.\nEach option is an `option` with `aria-selected`. The list, or its filter\nfield, points `aria-activedescendant` at the highlighted option; the field\nis `aria-autocomplete=\"list\"` and controls the list.\n\nAn option with `href` is a link: Enter or a press follows it and selects\nnothing, and moving onto it with the arrows does not follow it.\n\nAs a filter narrows the list, a screen reader hears how many options are\nleft, such as \"3 results\", from `result-label` and `results-label`. A filter\nthat leaves none says `empty-text`.\n\n**Moving options** is a separate import, `@fusion.dev/helix/listbox/reorder`,\nso a list that never moves options carries none of its code. With it\nimported, `reorderable` lets a reader move options:\n\n- Alt with Up or Down moves the highlighted option a place, and Alt with\n Home or End moves it to either end, as the APG's rearrangeable listbox\n does. The highlight stays on it.\n- A pointer drags an option, with a drop indicator, and the list scrolls near\n an edge. A press that does not travel still chooses the option.\n- A drop sends `helix-before-reorder`, which you can refuse, and then\n `helix-reorder`, whose `keys` hold every value in the new order. **You\n move the options**, or set `items` in the new order: the list moves no\n element of yours.\n- The list says each move in its `live` region. The words are the\n `moved-label`, `canceled-label`, `dropped-label`, and `picked-up-label`\n attributes, which the import reads.\n- An option in a group moves within its group. Options do not move while a\n filter narrows the list, under `layout=\"grid\"`, or while the list is\n disabled.",
96501
+ "description": "The listbox is the control, and options are its items. A Select is a listbox\nwith a trigger in front of it, a Combobox is a listbox with a text input, and\na command palette is a listbox in a dialog. They differ only in what opens\nthe list and what filters it.\n\nWith `multiple` set, `value` is a comma-separated string, like\n`Checkbox.Group`'s, because `MixinControllerValue` holds a string. The form\nreceives one entry per selected option, as a native `<select multiple>` sends\nit, so your server does not split on commas. An option's value may hold a\ncomma: a run of the string that is an option's value is read as that one\nvalue, and the form sends it as one entry.\n\nSelected and active are separate. The selected option is the value. The\nactive option is where the keyboard is: the arrow keys move it, and\n`aria-activedescendant` points to it while focus stays on the list.\n\n**Keyboard.** The list is one tab stop, or its filter field is where there\nis one. In a single-choice list the highlight is the choice unless `manual`\nis set; then Enter, Space or a click chooses.\n\n| Key | What it does |\n|---|---|\n| 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. |\n| Right, Left | With `layout=\"grid\"`, moves to the next or the previous option, mirrored right to left. In a filter field, moves the caret. |\n| Home, End | Moves to the first or the last option. In a filter field, moves the caret. |\n| Page Down, Page Up | Moves by as many options as the list shows at once. |\n| A letter or a word | Moves to the next option whose words start with what you typed. In a filter field, types it. |\n| Enter | Chooses the highlighted option, or follows it where it is a link. |\n| Space | Chooses the highlighted option, or with `multiple` toggles it. In a filter field, types a space. |\n| 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. |\n| Shift with Space | With `multiple`, adds every option from the one last chosen to the highlighted one. In a filter field, types a space. |\n| Shift with Home or End | With `multiple`, adds every option from the highlight to that end. In a filter field, hold Control as well. |\n| Control or Command with A | With `multiple`, chooses every option, or none where all are chosen. In a filter field, selects the text. |\n| Escape | In a filter field, clears the filter. |\n| 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. |\n\n**ARIA.** The `items` part is the `listbox`, named by the label and\ndescribed by the hint and the message, with `aria-multiselectable` under\n`multiple`, `aria-required`, `aria-invalid`, and `aria-busy` while loading.\nEach option is an `option` with `aria-selected`. The list, or its filter\nfield, points `aria-activedescendant` at the highlighted option; the field\nis `aria-autocomplete=\"list\"` and controls the list.\n\nAn option with `href` is a link: Enter or a press follows it and selects\nnothing, and moving onto it with the arrows does not follow it.\n\nAs a filter narrows the list, a screen reader hears how many options are\nleft, such as \"3 results\", from `result-label` and `results-label`. A filter\nthat leaves none says `empty-text`.\n\n**Moving options** is a separate import, `@fusion.dev/helix/listbox/reorder`,\nso a list that never moves options carries none of its code. With it\nimported, `reorderable` lets a reader move options:\n\n- Alt with Up or Down moves the highlighted option a place, and Alt with\n Home or End moves it to either end, as the APG's rearrangeable listbox\n does. The highlight stays on it.\n- A pointer drags an option, with a drop indicator, and the list scrolls near\n an edge. A press that does not travel still chooses the option.\n- A drop sends `helix-before-reorder`, which you can refuse, and then\n `helix-reorder`, whose `keys` hold every value in the new order. **You\n move the options**, or set `items` in the new order: the list moves no\n element of yours.\n- The list says each move in its `live` region. The words are the\n `moved-label`, `canceled-label`, `dropped-label`, and `picked-up-label`\n attributes, which the import reads.\n- An option in a group moves within its group. Options do not move while a\n filter narrows the list, under `layout=\"grid\"`, or while the list is\n disabled.\n\n**The options are an import of their own.** An option you write is the Option\nfamily's, which the list does not register, so a page that writes one imports\nit beside the list:\n\n```js\nimport '@fusion.dev/helix/listbox'\nimport '@fusion.dev/helix/option'\n```\n\nIn development, a list holding an option nobody registered says so once the\npage has loaded, with the line to add. The options `items` draws are this\nOption too, and need the same import.",
96458
96502
  "name": "HelixHeadlessListbox",
96459
96503
  "cssParts": [
96460
96504
  {
@@ -96671,7 +96715,7 @@
96671
96715
  "text": "readonly DataOptionItem[] | undefined"
96672
96716
  },
96673
96717
  "default": "undefined",
96674
- "description": "The options as data, for a list too long to draw whole: each a value,\nwhich is also its words, or a record with a `value`, a `label` and\n`disabled`. Set, the list draws only the options in sight, and the ones\nyou write as children are not read.\n\n**Every option is still reachable.** The keyboard, the typeahead, the\nfilter and the value work over the whole set, and the option the keyboard\nis on is drawn wherever it is, so a screen reader is told about it. Each\ndrawn option says its place in the set (`aria-posinset`, `aria-setsize`).\nReact Aria virtualizes a `ListBox` with its `Virtualizer`; this is core's\n`VirtualizeController`.\n\n**The list needs a height to scroll in**: the styled tier's\n`--listbox-max-block-size`, or a `max-block-size` on `::part(items)` in the\nheadless tier. Import the Option family as well, whose elements are drawn.\nA server sends the list empty, and the options are drawn once it hydrates."
96718
+ "description": "The options as data, for a list too long to draw whole: each a value,\nwhich is also its words, or a record with a `value`, a `label` and\n`disabled`. Set, the list draws only the options in sight, and the ones\nyou write as children are not read.\n\n**Every option is still reachable.** The keyboard, the typeahead, the\nfilter and the value work over the whole set, and the option the keyboard\nis on is drawn wherever it is, so a screen reader is told about it. Each\ndrawn option says its place in the set (`aria-posinset`, `aria-setsize`).\nReact Aria virtualizes a `ListBox` with its `Virtualizer`; this is core's\n`VirtualizeController`.\n\n**The list needs a height to scroll in**: the styled tier's\n`--listbox-max-block-size`, or a `max-block-size` on `::part(items)` in the\nheadless tier. The options drawn are this tier's Option, which the page\nimports, as it imports the options it writes.\nA server sends the list empty, and the options are drawn once it hydrates."
96675
96719
  },
96676
96720
  {
96677
96721
  "kind": "field",
@@ -123539,6 +123583,66 @@
123539
123583
  }
123540
123584
  ]
123541
123585
  },
123586
+ {
123587
+ "kind": "javascript-module",
123588
+ "path": "src/option/among.ts",
123589
+ "declarations": [
123590
+ {
123591
+ "kind": "function",
123592
+ "name": "isOption",
123593
+ "return": {
123594
+ "type": {
123595
+ "text": "element is HelixHeadlessOption"
123596
+ }
123597
+ },
123598
+ "parameters": [
123599
+ {
123600
+ "name": "element",
123601
+ "type": {
123602
+ "text": "Element"
123603
+ }
123604
+ }
123605
+ ],
123606
+ "description": "Whether an element is an option, by its shape.\n\n**Not by `instanceof`.** A tag is defined once, by whichever copy of this\nclass registered it first, and a second copy in the same document tests\nagainst a class no element on the page has: every option failed it, and a\nselect said \"Choose\" over its value. Two copies are a consumer with a\nduplicated dependency, or the browser specs, where each family's bundle\ncarries its own and they share one page. An option nobody registered has no\nsuch shape, and is no option until its entry is imported."
123607
+ },
123608
+ {
123609
+ "kind": "function",
123610
+ "name": "optionsAmong",
123611
+ "return": {
123612
+ "type": {
123613
+ "text": "HelixHeadlessOption[]"
123614
+ }
123615
+ },
123616
+ "parameters": [
123617
+ {
123618
+ "name": "elements",
123619
+ "type": {
123620
+ "text": "readonly Element[]"
123621
+ }
123622
+ }
123623
+ ],
123624
+ "description": "The options among some elements, reaching one level into a group.\n\nWhat a control holding options reads its words from, off its own children\nrather than off the listbox they are slotted into: the slot exists only once a\nrender has made it, so the listbox has none on a first render, and on a page a\nserver rendered the `slotchange` that would correct it fires before anything\nlistens."
123625
+ }
123626
+ ],
123627
+ "exports": [
123628
+ {
123629
+ "kind": "js",
123630
+ "name": "isOption",
123631
+ "declaration": {
123632
+ "name": "isOption",
123633
+ "module": "src/option/among.ts"
123634
+ }
123635
+ },
123636
+ {
123637
+ "kind": "js",
123638
+ "name": "optionsAmong",
123639
+ "declaration": {
123640
+ "name": "optionsAmong",
123641
+ "module": "src/option/among.ts"
123642
+ }
123643
+ }
123644
+ ]
123645
+ },
123542
123646
  {
123543
123647
  "kind": "javascript-module",
123544
123648
  "path": "src/option/group/option-group.ts",
@@ -124042,24 +124146,6 @@
124042
124146
  "kind": "javascript-module",
124043
124147
  "path": "src/option/root/option-root.ts",
124044
124148
  "declarations": [
124045
- {
124046
- "kind": "function",
124047
- "name": "optionsAmong",
124048
- "return": {
124049
- "type": {
124050
- "text": "HelixHeadlessOption[]"
124051
- }
124052
- },
124053
- "parameters": [
124054
- {
124055
- "name": "elements",
124056
- "type": {
124057
- "text": "readonly Element[]"
124058
- }
124059
- }
124060
- ],
124061
- "description": "The options among some elements, reaching one level into a group.\n\nWhat a control holding options reads its words from, off its own children\nrather than off the listbox they are slotted into: the slot exists only once a\nrender has made it, so the listbox has none on a first render, and on a page a\nserver rendered the `slotchange` that would correct it fires before anything\nlistens.\n\n**An option by its shape, not by `instanceof`.** A tag is defined once, by\nwhichever copy of this class registered it first, and a second copy in the\nsame document tests against a class no element on the page has: every option\nfailed it, and a select said \"Choose\" over its value. Two copies are a\nconsumer with a duplicated dependency, or the browser specs, where each\nfamily's bundle carries its own and they share one page."
124062
- },
124063
124149
  {
124064
124150
  "kind": "class",
124065
124151
  "description": "Options are their own family, separate from Select, because an option belongs\nto a listbox and several controls contain one. `role=\"option\"` requires an\nowning `role=\"listbox\"`. A Select is a listbox with a trigger, a Combobox is\na listbox with a text input, and a command palette is a listbox in a dialog.\n`Radio` is a part of its group, because a radio has only one kind of owner.\n\nSelection works the way it does for a radio. Choosing an option dispatches an\nevent, the listbox decides whether the choice stands, and the listbox sets\n`selected`.\n\nFiltering belongs to the owner, which hides an option with `hidden`. What\ncounts as a match differs between a select and a command palette.\n\nAn option with `href` is a link: choosing it follows the link and selects\nnothing, as an entry in a command palette that goes to a page does.\n\nThe option's name is its label alone, as React Aria's `slot=\"label\"` makes\nit: what is in `start` and `end`, an avatar's initials or a shortcut, is\ndrawn and not read as part of the name. The description is read as the\noption's description. A name you give with `aria-label` or\n`aria-labelledby` wins over both.",
@@ -124870,12 +124956,20 @@
124870
124956
  }
124871
124957
  ],
124872
124958
  "exports": [
124959
+ {
124960
+ "kind": "js",
124961
+ "name": "isOption",
124962
+ "declaration": {
124963
+ "name": "isOption",
124964
+ "module": "../among.js"
124965
+ }
124966
+ },
124873
124967
  {
124874
124968
  "kind": "js",
124875
124969
  "name": "optionsAmong",
124876
124970
  "declaration": {
124877
124971
  "name": "optionsAmong",
124878
- "module": "src/option/root/option-root.ts"
124972
+ "module": "../among.js"
124879
124973
  }
124880
124974
  },
124881
124975
  {
@@ -140112,7 +140206,7 @@
140112
140206
  "declarations": [
140113
140207
  {
140114
140208
  "kind": "class",
140115
- "description": "A scatter chart shows how two measures relate. The table's first numeric\ncolumn is measured across, every other numeric column is measured up, and\neach row is one point. A table of countries with an income column and a life\nexpectancy column draws one point for each country. Each additional numeric\ncolumn is another series, in its own color.\n\nBoth axes are labeled, because both positions are values. The ticks sit at\nround numbers, and the range extends to them.\n\n`trend` draws each series' line of best fit, by least squares, across the\nplot in the series' color.\n\n**`size-by` names a third measure, drawn as each point's size**, as a bubble\nchart does: `size-by=\"Population\"` takes that column out of the series and\ngives each point an area in proportion to its row's number there. The\ntooltip and the table still say the number.\n\nThe summary gives each series' correlation coefficient and its number of\npoints. The table has every number, and the drawing is hidden from screen\nreaders.\n\n**The plot is read by key.** It takes focus, named by `label` or the caption.\nThe left and right arrows move from point to point, left to right across\nthe plot, Home and End go to the first and the last, and the up and down\narrows move among the series of a row. The tooltip sits on that point, the\n`live` part says the row in words, and Escape puts the tooltip away.\n\nEach point is a `<span>` placed by percentage over the drawing, as\n`LineChart` places its end points, so points stay round when the drawing\nstretches.\n\nThe plot runs left to right in every text direction, as a number line does.\nThe plot, its axes, and the axis names sit in a `plane` part with\n`dir=\"ltr\"`. The axis names carry `dir=\"auto\"`, so a name in Arabic or Hebrew\nreads in its own direction. The summary and the tooltip bubble follow the\npage's direction.\n\n**A tap shows the reading under it**, and keeps it until a tap lands\nelsewhere. `helix-reading-change` says each move of the reading, by pointer,\ntap or key, and `helix-reading-press` says a reading was clicked, tapped, or\npressed with Enter or Space, for a page that opens what a reading stands for.\n\n**`data` takes the readings as data** where the page has no table to point\n`for` at, in a table's shape: the column headings, then one row per reading\nwith its label first. A table is still the better source where the page can\nshow one, since it reads before any script runs.\n\n**A chart with nothing to draw says so.** A table with no readings shows\n`empty-text`, \"No readings\", in the plot, and `loading` shows `loading-text`\nthere until readings arrive. The `empty` and `loading` slots take markup in\ntheir place, such as a link to add the first reading.\n\n**Keyboard.** The plot is one tab stop.\n\n| Key | What it does |\n|---|---|\n| Tab | Moves focus to the plot and shows the first reading. |\n| Right, Left | Moves to the next or the previous point, left to right across the plot. On a right-to-left page, Left moves to the next. |\n| Down, Up | Moves among the series of the point. With one series, moves to the next or the previous point. |\n| Home, End | Moves to the first or the last point. |\n| Page Down, Page Up | Moves a tenth of the points on or back. |\n| Enter, Space | Presses the point shown, which sends `helix-reading-press`. |\n| Escape | Puts the point and its tooltip away. |",
140209
+ "description": "A scatter chart shows how two measures relate. The table's first numeric\ncolumn is measured across, every other numeric column is measured up, and\neach row is one point. A table of countries with an income column and a life\nexpectancy column draws one point for each country. Each additional numeric\ncolumn is another series, in its own color.\n\nBoth axes are labeled, because both positions are values. The ticks sit at\nround numbers, and the range extends to them.\n\n`trend` draws each series' line of best fit, by least squares, across the\nplot in the series' color.\n\n**`size-by` names a third measure, drawn as each point's size**, as a bubble\nchart does: `size-by=\"Population\"` takes that column out of the series and\ngives each point an area in proportion to its row's number there. The\ntooltip and the table still say the number.\n\nThe summary gives each series' correlation coefficient and its number of\npoints. The table has every number, and the drawing is hidden from screen\nreaders.\n\n**The plot is read by key.** It takes focus, named by `label` or the caption.\nThe left and right arrows move from point to point, left to right across\nthe plot, Home and End go to the first and the last, and the up and down\narrows move among the series of a row. The tooltip sits on that point, the\n`live` part says the row in words, and Escape puts the tooltip away.\n\nEach point is a `<span>` placed by percentage over the drawing, as\n`LineChart` places its end points, so points stay round when the drawing\nstretches.\n\nThe plot runs left to right in every text direction, as a number line does.\nThe plot, its axes, and the axis names sit in a `plane` part with\n`dir=\"ltr\"`, and the arrow keys follow the drawing: Right moves to the next\npoint on a right-to-left page too. The axis names carry `dir=\"auto\"`, so a\nname in Arabic or Hebrew reads in its own direction. The summary and the\ntooltip bubble follow the page's direction.\n\n**A tap shows the reading under it**, and keeps it until a tap lands\nelsewhere. `helix-reading-change` says each move of the reading, by pointer,\ntap or key, and `helix-reading-press` says a reading was clicked, tapped, or\npressed with Enter or Space, for a page that opens what a reading stands for.\n\n**`data` takes the readings as data** where the page has no table to point\n`for` at, in a table's shape: the column headings, then one row per reading\nwith its label first. A table is still the better source where the page can\nshow one, since it reads before any script runs.\n\n**A chart with nothing to draw says so.** A table with no readings shows\n`empty-text`, \"No readings\", in the plot, and `loading` shows `loading-text`\nthere until readings arrive. The `empty` and `loading` slots take markup in\ntheir place, such as a link to add the first reading.\n\n**Keyboard.** The plot is one tab stop.\n\n| Key | What it does |\n|---|---|\n| Tab | Moves focus to the plot and shows the first reading. |\n| Right, Left | Moves to the next or the previous point, left to right across the plot, on a right-to-left page too. |\n| Down, Up | Moves among the series of the point. With one series, moves to the next or the previous point. |\n| Home, End | Moves to the first or the last point. |\n| Page Down, Page Up | Moves a tenth of the points on or back. |\n| Enter, Space | Presses the point shown, which sends `helix-reading-press`. |\n| Escape | Puts the point and its tooltip away. |",
140116
140210
  "name": "HelixHeadlessScatterChart",
140117
140211
  "cssProperties": [
140118
140212
  {
@@ -142877,7 +142971,7 @@
142877
142971
  "declarations": [
142878
142972
  {
142879
142973
  "kind": "class",
142880
- "description": "A trigger that opens a `Listbox`. The list is the same element you can use on\nits own, with the same keyboard behavior, filtering, and multi-select rules.\nSelect adds a trigger that shows what is chosen, a floating surface, and a\nplace for focus to return to when the list closes.\n\nYour options stay in your light DOM and are slotted through into the listbox,\nso the listbox looks through slots to find them. Write them as `Option`,\ngroup them in `Option.Group`, and divide them with `Option.Separator`.\nImporting Select registers all three in the same tier. For a list too long to draw\nwhole, set `items` instead: the list draws only the options in sight, as\nListbox's `items` does, and the trigger, its keys and the form read the\nwhole set.\n\n`Select` owns the value, passes it down to the listbox, and takes changes\nback, so the value lives in one place. With `multiple`, the value is the\nchosen values joined with commas, and the form receives one entry for each.\nAn option's value may hold a comma, and it is read as one value.\n\nSet `valueContent` to draw the trigger's content from the chosen options,\nand several chosen options are written as a list in the reader's language.\n\n**Keyboard.** On the closed trigger:\n\n| Key | What it does |\n|---|---|\n| Down, Enter, Space | Opens the list on the chosen option, or the first. |\n| Up | Opens the list on the chosen option, or the last. |\n| Home, End | Opens the list on the first or the last option. |\n| Left, Right | Chooses the option before or after the chosen one without opening, as React Aria's Select does. On a right-to-left page Left chooses the one after. |\n| 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. |\n\nIn the open list, which is a `Listbox`:\n\n| Key | What it does |\n|---|---|\n| Down, Up, Home, End, Page Down, Page Up | Moves the highlight. |\n| A letter or a word | Moves the highlight to the next option whose words start with what you typed. |\n| Enter, Space | Chooses the highlighted option and closes the list. With `multiple`, toggles it and leaves the list open. |\n| Escape | Closes the list and puts focus back on the trigger. |\n| Tab | Closes the list and moves on. |\n\nA choice made on the closed trigger is said aloud on Apple devices, where\nVoiceOver does not read the trigger's new name.\n\n**ARIA.** The trigger is a `button` with `aria-haspopup=\"listbox\"` and\n`aria-expanded`, named by the label and then the chosen words, as a native\n`<select>` is. The list is the listbox `Listbox` describes, named by the\nlabel, or by `list-label` where there is none.\n\nSet `autocomplete` to let a browser's autofill choose, as a native `<select>`\nwith the same attribute would.",
142974
+ "description": "A trigger that opens a `Listbox`. The list is the same element you can use on\nits own, with the same keyboard behavior, filtering, and multi-select rules.\nSelect adds a trigger that shows what is chosen, a floating surface, and a\nplace for focus to return to when the list closes.\n\nYour options stay in your light DOM and are slotted through into the listbox,\nso the listbox looks through slots to find them. Write them as `Option`,\ngroup them in `Option.Group`, and divide them with `Option.Separator`.\nImporting Select registers all three in the same tier. For a list too long to draw\nwhole, set `items` instead: the list draws only the options in sight, as\nListbox's `items` does, and the trigger, its keys and the form read the\nwhole set.\n\n`Select` owns the value, passes it down to the listbox, and takes changes\nback, so the value lives in one place. With `multiple`, the value is the\nchosen values joined with commas, and the form receives one entry for each.\nAn option's value may hold a comma, and it is read as one value.\n\nSet `valueContent` to draw the trigger's content from the chosen options,\nand several chosen options are written as a list in the reader's language.\n\n**Keyboard.** On the closed trigger:\n\n| Key | What it does |\n|---|---|\n| Down, Enter, Space | Opens the list on the chosen option, or the first. |\n| Up | Opens the list on the chosen option, or the last. |\n| Home, End | Opens the list on the first or the last option. |\n| Left, Right | Chooses the option before or after the chosen one without opening, as React Aria's Select does. On a right-to-left page Left chooses the one after. |\n| 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. |\n\nIn the open list, which is a `Listbox`:\n\n| Key | What it does |\n|---|---|\n| Down, Up, Home, End, Page Down, Page Up | Moves the highlight. |\n| A letter or a word | Moves the highlight to the next option whose words start with what you typed. |\n| Enter, Space | Chooses the highlighted option and closes the list. With `multiple`, toggles it and leaves the list open. |\n| Escape | Closes the list and puts focus back on the trigger. |\n| Tab | Closes the list and moves on. |\n\nA choice made on the closed trigger is said aloud on Apple devices, where\nVoiceOver does not read the trigger's new name.\n\n**ARIA.** The trigger is a `button` with `aria-haspopup=\"listbox\"` and\n`aria-expanded`, named by the label and then the chosen words, as a native\n`<select>` is. The list is the listbox `Listbox` describes, named by the\nlabel, or by `list-label` where there is none.\n\nSet `autocomplete` to let a browser's autofill choose, as a native `<select>`\nwith the same attribute would.\n\n**The options are an import of their own.** An option is the Option family's,\nwhich the select does not register, so a page that writes one imports it\nbeside the select:\n\n```js\nimport '@fusion.dev/helix/select'\nimport '@fusion.dev/helix/option'\n```\n\nIn development, a select holding an option nobody registered says so once the\npage has loaded, with the line to add.",
142881
142975
  "name": "HelixHeadlessSelect",
142882
142976
  "cssProperties": [
142883
142977
  {
@@ -159053,24 +159147,6 @@
159053
159147
  "kind": "javascript-module",
159054
159148
  "path": "src/table/column/table-column.ts",
159055
159149
  "declarations": [
159056
- {
159057
- "kind": "function",
159058
- "name": "edgeOf",
159059
- "return": {
159060
- "type": {
159061
- "text": "string | undefined"
159062
- }
159063
- },
159064
- "parameters": [
159065
- {
159066
- "name": "align",
159067
- "type": {
159068
- "text": "string | undefined"
159069
- }
159070
- }
159071
- ],
159072
- "description": "The edge a column names, where it names one of the three.\n\n**`text-align` is a string anybody can write**, the union on the property being a\ncompile-time claim and nothing else, and both tables put the value straight\ninto CSS: `Table` into a rule in each row's shadow root, `DataTable` into the\ncell it draws. One guard, here with the property, rather than one in each\ntable and only one of them written."
159073
- },
159074
159150
  {
159075
159151
  "kind": "class",
159076
159152
  "description": "Each column provides both its heading and its grid track. Adding a column\nadds a track, and removing one removes it. `Table`'s `columns` is applied one\ntrack at a time to the columns declared under it:\n\n- A heading name in the list affects only its own column's width.\n- A list longer or shorter than the columns is trimmed or shared.\n- A column's own `width` overrides the track in its place.\n\nThis protects the table from a track list that contains the headings by\nmistake, which is invalid CSS that the grid ignores silently, drawing the\nwhole table as one column.\n\nEvery per-column setting goes on the column, so `DataTable` needs no column\nconfiguration object:\n\n- `field` names the key the cell reads.\n- `sortable` lets people sort by the column.\n- `text-align` sets which edge the values line up against.\n- `cell` takes a function for anything `field` alone cannot express.\n\nThe same element works in both `Table` and `DataTable`. It is identified by a\nflag, so the two roots share nothing else.\n\nThe column generates no box of its own, the same as a row. The heading is a\ngrid item of the table, so it lines up with the cells below it.\n\n`hidden` takes the column out of the grid, both its heading and its track, so\nthe other columns keep their widths and every row keeps its cells under their\nheadings. `hidden=\"until-found\"` keeps the track and leaves the heading\ndrawn, as it does on every Helix element. `DataTable` leaves out the cells\nunder a hidden column. In a `Table` the cells are markup you wrote, so hide\nthem with the column: a row with more cells than the table has tracks wraps\nonto the next line.\n\nA heading that does something holds a control. In a `Table` a column\nheader is not focusable, so a sortable heading contains a `<button>`, which\nis the pattern for a sortable table and the only way to reach the sort by\nkeyboard. In a `DataTable` the heading is a cell of the grid, reached with\nthe arrow keys, and its controls with Enter or F2. A resizable column has a\n`separator` on its end edge, moved by dragging or with the arrow keys. In a\ntable with reorderable columns, each column has a grip that the table moves.",
@@ -159923,7 +159999,7 @@
159923
159999
  "name": "edgeOf",
159924
160000
  "declaration": {
159925
160001
  "name": "edgeOf",
159926
- "module": "src/table/column/table-column.ts"
160002
+ "module": "../edge.js"
159927
160003
  }
159928
160004
  },
159929
160005
  {
@@ -159944,6 +160020,40 @@
159944
160020
  }
159945
160021
  ]
159946
160022
  },
160023
+ {
160024
+ "kind": "javascript-module",
160025
+ "path": "src/table/edge.ts",
160026
+ "declarations": [
160027
+ {
160028
+ "kind": "function",
160029
+ "name": "edgeOf",
160030
+ "return": {
160031
+ "type": {
160032
+ "text": "string | undefined"
160033
+ }
160034
+ },
160035
+ "parameters": [
160036
+ {
160037
+ "name": "align",
160038
+ "type": {
160039
+ "text": "string | undefined"
160040
+ }
160041
+ }
160042
+ ],
160043
+ "description": "The edge a column names, where it names one of the three.\n\n**`text-align` is a string anybody can write**, the union on the property being a\ncompile-time claim and nothing else, and both tables put the value straight\ninto CSS: `Table` into a rule in each row's shadow root, `DataTable` into the\ncell it draws. One guard, here with the property, rather than one in each\ntable and only one of them written."
160044
+ }
160045
+ ],
160046
+ "exports": [
160047
+ {
160048
+ "kind": "js",
160049
+ "name": "edgeOf",
160050
+ "declaration": {
160051
+ "name": "edgeOf",
160052
+ "module": "src/table/edge.ts"
160053
+ }
160054
+ }
160055
+ ]
160056
+ },
159947
160057
  {
159948
160058
  "kind": "javascript-module",
159949
160059
  "path": "src/table/grid-controller.ts",
@@ -199724,6 +199834,6 @@
199724
199834
  ],
199725
199835
  "helix": {
199726
199836
  "package": "@fusion.dev/helix-headless",
199727
- "version": "0.179.0"
199837
+ "version": "0.180.0"
199728
199838
  }
199729
199839
  }
@@ -15,7 +15,8 @@ import { type PropertyValues, type TemplateResult } from 'lit';
15
15
  * The composer clears only when no listener cancels the send, so the text is
16
16
  * kept when you cancel a send that failed.
17
17
  *
18
- * **In a form, the draft is the composer's value**, submitted under `name`. A
18
+ * **In a form, the draft is the composer's value**, submitted under `name`,
19
+ * and an empty draft submits an empty entry, as a native textarea does. A
19
20
  * form reset puts back the `value` the markup declared, and a `<fieldset
20
21
  * disabled>` turns the composer off. Sending is still `helix-send`, and it
21
22
  * does not submit the form.
@@ -124,7 +124,7 @@ let HelixHeadlessChatComposer = class HelixHeadlessChatComposer extends HelixFor
124
124
  super.updated(changed);
125
125
  this.markEmpty();
126
126
  if (changed.has('value')) {
127
- this.internals.setFormValue(this.value === '' ? null : this.value, this.value);
127
+ this.internals.setFormValue(this.value, this.value);
128
128
  }
129
129
  const field = this.partNamed('field');
130
130
  if (field?.validity) {
@@ -59,6 +59,18 @@ declare const HelixHeadlessCombobox_base: (new (...args: any[]) => import("@fusi
59
59
  * framework would re-render over an element the combobox inserted, so add the
60
60
  * option in your event handler.
61
61
  *
62
+ * **The options are an import of their own.** An option is the Option family's,
63
+ * which the combobox does not register, so a page that writes one imports it
64
+ * beside the combobox:
65
+ *
66
+ * ```js
67
+ * import '@fusion.dev/helix/combobox'
68
+ * import '@fusion.dev/helix/option'
69
+ * ```
70
+ *
71
+ * In development, a combobox holding an option nobody registered says so once
72
+ * the page has loaded, with the line to add.
73
+ *
62
74
  * @since 0.1.0
63
75
  * @status stable
64
76
  * @category forms
@@ -4,13 +4,13 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { AriaForwardController, afterLinkFollowed, chosenValues, countLabel, customElement, DelayController, drawAutofill, drawStatus, formatWords, HelixCreateEvent, HelixFilterEvent, HelixFormElement, handedLocale, MixinControllerOpen, MixinControllerValue, MixinField, MixinTokens, onApple, PopoverController, reportValues, StatusController, submitImplicitly, UpgradeController, words, wordsLocale, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, afterLinkFollowed, auditChildren, chosenValues, countLabel, customElement, DelayController, drawAutofill, drawStatus, formatWords, HelixCreateEvent, HelixFilterEvent, HelixFormElement, handedLocale, MixinControllerOpen, MixinControllerValue, MixinField, MixinTokens, onApple, PopoverController, reportValues, StatusController, submitImplicitly, UpgradeController, words, wordsLocale, } from '@fusion.dev/helix-core';
8
8
  import { caretDown } from '@fusion.dev/helix-icons';
9
9
  import { nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
11
11
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
12
12
  import { html } from 'lit/static-html.js';
13
- import { optionsAmong } from '../../option/root/option-root.js';
13
+ import { optionsAmong } from '../../option/among.js';
14
14
  import { HelixHeadlessTag } from '../../tag/root/tag-root.js';
15
15
  import '../../listbox/index.js';
16
16
  import '../../tag/root/index.js';
@@ -507,6 +507,7 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
507
507
  }
508
508
  connectedCallback() {
509
509
  super.connectedCallback();
510
+ auditChildren(this, 'option', 'option', 'it suggests nothing');
510
511
  this.addEventListener('helix-select', this.handleLinkFollowed);
511
512
  this.watcher = new MutationObserver(() => this.requestUpdate());
512
513
  this.watcher.observe(this, {
@@ -72,6 +72,18 @@ declare const HelixHeadlessCommand_base: (new (...args: any[]) => import("@fusio
72
72
  * Aria's `Autocomplete` is. The commands are a `listbox` of `option`s. How many commands typing left, the empty text and
73
73
  * the loading text are said in a polite live region.
74
74
  *
75
+ * **The commands are an import of their own.** A command is an option, the
76
+ * Option family's, which the palette does not register, so a page that writes
77
+ * one imports it beside the palette:
78
+ *
79
+ * ```js
80
+ * import '@fusion.dev/helix/command'
81
+ * import '@fusion.dev/helix/option'
82
+ * ```
83
+ *
84
+ * In development, a palette holding an option nobody registered says so once
85
+ * the page has loaded, with the line to add.
86
+ *
75
87
  * @since 0.1.0
76
88
  * @status stable
77
89
  * @category navigation