@fusion.dev/helix-headless 0.170.0 → 0.171.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +610 -93
- package/dist/chat/composer/chat-composer.d.ts +2 -1
- package/dist/chat/composer/chat-composer.js +7 -1
- package/dist/chat/root/chat-root.d.ts +36 -6
- package/dist/chat/root/chat-root.js +53 -5
- package/dist/code-block/root/code-block-root.d.ts +20 -2
- package/dist/code-block/root/code-block-root.js +29 -8
- package/dist/color-picker/root/color-picker-root.d.ts +50 -7
- package/dist/color-picker/root/color-picker-root.js +62 -1
- package/dist/combobox/root/combobox-root.d.ts +16 -6
- package/dist/combobox/root/combobox-root.js +9 -2
- package/dist/command/root/command-root.d.ts +16 -1
- package/dist/command/root/command-root.js +8 -0
- package/dist/filter-input/chip/filter-chip.d.ts +13 -3
- package/dist/filter-input/chip/filter-chip.js +5 -0
- package/dist/filter-input/menu/filter-menu.js +0 -1
- package/dist/filter-input/root/filter-input-root.d.ts +71 -4
- package/dist/filter-input/root/filter-input-root.js +87 -2
- package/dist/format-date/root/format-date-root.d.ts +3 -1
- package/dist/input/root/input-root.d.ts +6 -0
- package/dist/input/root/input-root.js +13 -0
- package/dist/listbox/root/listbox-root.d.ts +6 -0
- package/dist/listbox/root/listbox-root.js +6 -1
- package/dist/number-input/root/number-input-root.d.ts +16 -6
- package/dist/number-input/root/number-input-root.js +15 -4
- package/dist/select/root/select-root.js +2 -0
- package/dist/steps/root/steps-root.d.ts +32 -8
- package/dist/steps/root/steps-root.js +70 -9
- package/dist/steps/step/step.d.ts +9 -1
- package/dist/steps/step/step.js +5 -0
- package/dist/video-playlist/root/video-playlist-root.d.ts +19 -1
- package/dist/video-playlist/root/video-playlist-root.js +14 -3
- package/dist/virtual-list/root/virtual-list-root.d.ts +8 -0
- package/dist/virtual-list/root/virtual-list-root.js +7 -2
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +490 -116
- package/types/vue.d.ts +108 -25
- package/types/words.d.ts +12 -2
package/types/vue.d.ts
CHANGED
|
@@ -3200,6 +3200,12 @@ export type HelixHeadlessCodeBlockHelixToggleElementEvent =
|
|
|
3200
3200
|
HelixHeadlessCodeBlockElementEvent<HelixToggleEvent>;
|
|
3201
3201
|
|
|
3202
3202
|
export type HelixHeadlessCodeBlockVueProps = {
|
|
3203
|
+
/** The lines to mark as inserted, as numbers and ranges counted from 1, such
|
|
3204
|
+
as `3-4`. Drawn as `mark-lines` is, in the added color. Not for a diff. */
|
|
3205
|
+
"added-lines"?: (HelixHeadlessCodeBlock["addedLines"]) | undefined;
|
|
3206
|
+
/** The lines to mark as inserted, as numbers and ranges counted from 1, such
|
|
3207
|
+
as `3-4`. Drawn as `mark-lines` is, in the added color. Not for a diff. */
|
|
3208
|
+
addedLines?: (HelixHeadlessCodeBlock["addedLines"]) | undefined;
|
|
3203
3209
|
/** The name of a block that scrolls, which is a tab stop while it does.
|
|
3204
3210
|
|
|
3205
3211
|
Where the block has a name, the scroller says it too, such as "Code,
|
|
@@ -3358,6 +3364,12 @@ A false boolean reflects as the attribute's absence, so this costs no
|
|
|
3358
3364
|
reflected property taking no default is satisfied by the default being
|
|
3359
3365
|
`false`. */
|
|
3360
3366
|
noCopy?: (HelixHeadlessCodeBlock["noCopy"]) | undefined;
|
|
3367
|
+
/** The lines to mark as deleted, as numbers and ranges counted from 1. Drawn
|
|
3368
|
+
as `mark-lines` is, in the removed color. Not for a diff. */
|
|
3369
|
+
"removed-lines"?: (HelixHeadlessCodeBlock["removedLines"]) | undefined;
|
|
3370
|
+
/** The lines to mark as deleted, as numbers and ranges counted from 1. Drawn
|
|
3371
|
+
as `mark-lines` is, in the removed color. Not for a diff. */
|
|
3372
|
+
removedLines?: (HelixHeadlessCodeBlock["removedLines"]) | undefined;
|
|
3361
3373
|
/** The words of a button that shows a folded run of unchanged lines, in a
|
|
3362
3374
|
diff with `context-lines`. `{count}` is how many. */
|
|
3363
3375
|
"show-unchanged-label"?: (HelixHeadlessCodeBlock["showUnchangedLabel"]) | undefined;
|
|
@@ -3956,10 +3968,11 @@ would give one control two of each. What is left is the validity call and
|
|
|
3956
3968
|
the anchor the browser points its bubble at.
|
|
3957
3969
|
|
|
3958
3970
|
**Text that is not a color is bad input**, so a form does not submit
|
|
3959
|
-
`#00` from a half-typed value. The picker
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3971
|
+
`#00` from a half-typed value. The picker marks it, and says
|
|
3972
|
+
`badInputMessage` under itself, once the reader leaves the value field or
|
|
3973
|
+
presses Enter, and a missing color once the reader has committed one or a
|
|
3974
|
+
form has refused the picker. Color Input shows its own message against the
|
|
3975
|
+
field the reader typed into. */
|
|
3963
3976
|
required?: (HelixHeadlessColorPicker["required"]) | undefined;
|
|
3964
3977
|
/** What the square's horizontal ramp is called. */
|
|
3965
3978
|
"saturation-label"?: (HelixHeadlessColorPicker["saturationLabel"]) | undefined;
|
|
@@ -4227,12 +4240,13 @@ language. */
|
|
|
4227
4240
|
locale?: (HelixHeadlessCombobox["locale"]) | undefined;
|
|
4228
4241
|
/** Whether more than one option can be chosen.
|
|
4229
4242
|
|
|
4230
|
-
The list already does the work: `value`
|
|
4231
|
-
toggles rather than replaces, and the arrows move without
|
|
4232
|
-
this adds is the tags, and keeping the panel open between
|
|
4243
|
+
The list already does the work: `value` is the chosen values joined with
|
|
4244
|
+
commas, a press toggles rather than replaces, and the arrows move without
|
|
4245
|
+
choosing. What this adds is the tags, and keeping the panel open between
|
|
4246
|
+
picks.
|
|
4233
4247
|
|
|
4234
|
-
|
|
4235
|
-
|
|
4248
|
+
An option's value may hold a comma, and it is read as one value, as
|
|
4249
|
+
`Select` and `Listbox` read it. So may an answer the reader created.
|
|
4236
4250
|
|
|
4237
4251
|
**The list is told, and the field is not.** `aria-multiselectable` belongs
|
|
4238
4252
|
to `listbox`, `grid`, `tree` and `tablist`, and `combobox` dropped it in
|
|
@@ -4507,6 +4521,18 @@ so a palette filtered on a server sends one `helix-filter` for a word.
|
|
|
4507
4521
|
so a palette filtered on a server sends one `helix-filter` for a word.
|
|
4508
4522
|
`0` filters on every keystroke. See Listbox's `filter-delay`. */
|
|
4509
4523
|
filterDelay?: (HelixHeadlessCommand["filterDelay"]) | undefined;
|
|
4524
|
+
/** Where Home and End go from the filter field.
|
|
4525
|
+
|
|
4526
|
+
Absent, they move the caret, as APG's combobox has them. `list` moves the
|
|
4527
|
+
highlight to the first or the last command, as React Aria's Autocomplete
|
|
4528
|
+
does, and Shift with either still selects the text. */
|
|
4529
|
+
"home-end"?: (HelixHeadlessCommand["homeEnd"]) | undefined;
|
|
4530
|
+
/** Where Home and End go from the filter field.
|
|
4531
|
+
|
|
4532
|
+
Absent, they move the caret, as APG's combobox has them. `list` moves the
|
|
4533
|
+
highlight to the first or the last command, as React Aria's Autocomplete
|
|
4534
|
+
does, and Shift with either still selects the text. */
|
|
4535
|
+
homeEnd?: (HelixHeadlessCommand["homeEnd"]) | undefined;
|
|
4510
4536
|
/** The key that opens the palette, written as `mod+k`, `shift+p`, or `k`,
|
|
4511
4537
|
in Kbd's chord spelling: `mod` is Command or Control, `ctrl`, `cmd`,
|
|
4512
4538
|
`alt` and `shift` the keys they name.
|
|
@@ -4524,6 +4550,10 @@ and `open`, `toggle` and the dialog's parts do nothing. */
|
|
|
4524
4550
|
inline?: (HelixHeadlessCommand["inline"]) | undefined;
|
|
4525
4551
|
/** Accessible name for the overlay, which has no visible heading. */
|
|
4526
4552
|
label?: (HelixHeadlessCommand["label"]) | undefined;
|
|
4553
|
+
/** How the commands are laid out, as Listbox's `layout`: `grid` draws them in
|
|
4554
|
+
rows and columns, for a palette of icons or emoji, and the arrow keys
|
|
4555
|
+
follow the rows and the columns. Absent is one command under another. */
|
|
4556
|
+
layout?: (HelixHeadlessCommand["layout"]) | undefined;
|
|
4527
4557
|
/** What the list says when its commands could not be loaded, such as after a
|
|
4528
4558
|
request to a server fails. Empty, null or no attribute is no error, so
|
|
4529
4559
|
removing the attribute clears it. Passed to the list, which shows it
|
|
@@ -6968,6 +6998,13 @@ makes an unusual filter look unusual. */
|
|
|
6968
6998
|
operatorLabel?: (HelixHeadlessFilterChip["operatorLabel"]) | undefined;
|
|
6969
6999
|
/** Whether the element shows a control that dismisses it. */
|
|
6970
7000
|
dismissible?: (HelixHeadlessFilterChip["dismissible"]) | undefined;
|
|
7001
|
+
/** Whether the remove button is a tab stop of its own.
|
|
7002
|
+
|
|
7003
|
+
`FilterInput` writes `false` on the chips in its `tags` slot: the field's
|
|
7004
|
+
text is its one tab stop, and the arrow keys move from the text to the
|
|
7005
|
+
chips, as in a `multiple` Combobox. No attribute: it is coordination
|
|
7006
|
+
between elements, as `Tag.dismissTabStop` is. */
|
|
7007
|
+
dismissTabStop?: (HelixHeadlessFilterChip["dismissTabStop"]) | undefined;
|
|
6971
7008
|
};
|
|
6972
7009
|
|
|
6973
7010
|
export type HelixHeadlessFilterChipVueEvents = {
|
|
@@ -7092,6 +7129,18 @@ export type HelixHeadlessFilterInputToggleElementEvent =
|
|
|
7092
7129
|
HelixHeadlessFilterInputElementEvent<ToggleEvent>;
|
|
7093
7130
|
|
|
7094
7131
|
export type HelixHeadlessFilterInputVueProps = {
|
|
7132
|
+
/** Whether the field keeps a `FilterChip` for each filter in its `tags` slot,
|
|
7133
|
+
from the `helix-facet` events it hears.
|
|
7134
|
+
|
|
7135
|
+
Off, you build the chips, which is what you do when your own model holds
|
|
7136
|
+
the filters. On, a filter typed, picked, or changed adds or updates the
|
|
7137
|
+
chip for its field, one with no values takes it away (unless its
|
|
7138
|
+
comparison takes none, such as "is empty"), and removing the chip clears
|
|
7139
|
+
the filter. A `helix-facet` you cancel changes no chip.
|
|
7140
|
+
|
|
7141
|
+
The chips are elements the field adds to its own children, so leave this
|
|
7142
|
+
off where a framework renders those children and would remove them. */
|
|
7143
|
+
chips?: (HelixHeadlessFilterInput["chips"]) | undefined;
|
|
7095
7144
|
/** Shows a button that empties the field.
|
|
7096
7145
|
|
|
7097
7146
|
The text only. The tokens are the consumer's markup and this element is not
|
|
@@ -7113,6 +7162,29 @@ what you slot and you narrow it. */
|
|
|
7113
7162
|
being typed, as React Aria's Autocomplete filters. Off, the panel shows
|
|
7114
7163
|
what you slot and you narrow it. */
|
|
7115
7164
|
filterSuggestions?: (HelixHeadlessFilterInput["filterSuggestions"]) | undefined;
|
|
7165
|
+
/** Whether the suggestions are still loading, such as while a request for the
|
|
7166
|
+
values of a typed key is out.
|
|
7167
|
+
|
|
7168
|
+
The panel opens on `loading-text`, or the `loading` slot, while the field
|
|
7169
|
+
has focus, and a screen reader hears it. Slot the options and clear this
|
|
7170
|
+
when they arrive. */
|
|
7171
|
+
loading?: (HelixHeadlessFilterInput["loading"]) | undefined;
|
|
7172
|
+
/** Text the panel shows while the suggestions load. */
|
|
7173
|
+
"loading-text"?: (HelixHeadlessFilterInput["loadingText"]) | undefined;
|
|
7174
|
+
/** Text the panel shows while the suggestions load. */
|
|
7175
|
+
loadingText?: (HelixHeadlessFilterInput["loadingText"]) | undefined;
|
|
7176
|
+
/** Text the panel shows when `filter-suggestions` hides every suggestion, such
|
|
7177
|
+
as "No matching filters".
|
|
7178
|
+
|
|
7179
|
+
Empty, or no `no-results` slot, and the panel closes instead, as it does
|
|
7180
|
+
when it has nothing to offer. */
|
|
7181
|
+
"no-results-text"?: (HelixHeadlessFilterInput["noResultsText"]) | undefined;
|
|
7182
|
+
/** Text the panel shows when `filter-suggestions` hides every suggestion, such
|
|
7183
|
+
as "No matching filters".
|
|
7184
|
+
|
|
7185
|
+
Empty, or no `no-results` slot, and the panel closes instead, as it does
|
|
7186
|
+
when it has nothing to offer. */
|
|
7187
|
+
noResultsText?: (HelixHeadlessFilterInput["noResultsText"]) | undefined;
|
|
7116
7188
|
/** The text shown while the field is empty.
|
|
7117
7189
|
|
|
7118
7190
|
Not a label: it goes when typing starts. */
|
|
@@ -11364,9 +11436,13 @@ speaks it: `feedback` replaces the message under the field and does not
|
|
|
11364
11436
|
reach the bubble. Unset is the sentence registered for the page's
|
|
11365
11437
|
language, then the English. */
|
|
11366
11438
|
badInputMessage?: (HelixHeadlessNumberInput["badInputMessage"]) | undefined;
|
|
11367
|
-
/** The name of the step down button, read by screen readers.
|
|
11439
|
+
/** The name of the step down button, read by screen readers. The field's
|
|
11440
|
+
label follows it, so a reader hears "Decrease Quantity", as React Aria
|
|
11441
|
+
names its steppers. */
|
|
11368
11442
|
"decrement-label"?: (HelixHeadlessNumberInput["decrementLabel"]) | undefined;
|
|
11369
|
-
/** The name of the step down button, read by screen readers.
|
|
11443
|
+
/** The name of the step down button, read by screen readers. The field's
|
|
11444
|
+
label follows it, so a reader hears "Decrease Quantity", as React Aria
|
|
11445
|
+
names its steppers. */
|
|
11370
11446
|
decrementLabel?: (HelixHeadlessNumberInput["decrementLabel"]) | undefined;
|
|
11371
11447
|
/** `Intl.NumberFormat` options the number is shown with while the field is
|
|
11372
11448
|
not being edited: a currency, a percent, a unit, or a number of decimals.
|
|
@@ -11384,9 +11460,13 @@ Written as JSON in the attribute.
|
|
|
11384
11460
|
<helix-number-input format-options='{"style":"currency","currency":"EUR"}'></helix-number-input>
|
|
11385
11461
|
``` */
|
|
11386
11462
|
formatOptions?: (HelixHeadlessNumberInput["formatOptions"]) | undefined;
|
|
11387
|
-
/** The name of the step up button, read by screen readers.
|
|
11463
|
+
/** The name of the step up button, read by screen readers. The field's
|
|
11464
|
+
label follows it, so a reader hears "Increase Quantity", as React Aria
|
|
11465
|
+
names its steppers. */
|
|
11388
11466
|
"increment-label"?: (HelixHeadlessNumberInput["incrementLabel"]) | undefined;
|
|
11389
|
-
/** The name of the step up button, read by screen readers.
|
|
11467
|
+
/** The name of the step up button, read by screen readers. The field's
|
|
11468
|
+
label follows it, so a reader hears "Increase Quantity", as React Aria
|
|
11469
|
+
names its steppers. */
|
|
11390
11470
|
incrementLabel?: (HelixHeadlessNumberInput["incrementLabel"]) | undefined;
|
|
11391
11471
|
/** How many steps `PageUp` and `PageDown` move.
|
|
11392
11472
|
|
|
@@ -14545,7 +14625,8 @@ export type HelixHeadlessStepsHelixSelectElementEvent =
|
|
|
14545
14625
|
|
|
14546
14626
|
export type HelixHeadlessStepsVueProps = {
|
|
14547
14627
|
/** Whether the arrow keys move focus between the stages' names, along the
|
|
14548
|
-
way the steps run. Off by default, so the
|
|
14628
|
+
way the steps run, and the names are one tab stop. Off by default, so the
|
|
14629
|
+
arrows keep scrolling the page. */
|
|
14549
14630
|
arrows?: (HelixHeadlessSteps["arrows"]) | undefined;
|
|
14550
14631
|
/** What marks a stage `complete`.
|
|
14551
14632
|
|
|
@@ -14662,7 +14743,9 @@ with the page. */
|
|
|
14662
14743
|
/** Whether a reader may pass the stage without finishing it, in a sequence
|
|
14663
14744
|
with `linear`. Ark UI's skippable step. */
|
|
14664
14745
|
optional?: (HelixHeadlessStep["optional"]) | undefined;
|
|
14665
|
-
/** The value the step sends in `helix-select
|
|
14746
|
+
/** The value the step sends in `helix-select`, and what names the step in its
|
|
14747
|
+
sequence's `active`. Without one, the sequence names the step by its place,
|
|
14748
|
+
counted from 1. */
|
|
14666
14749
|
value?: (HelixHeadlessStep["value"]) | undefined;
|
|
14667
14750
|
};
|
|
14668
14751
|
|
|
@@ -18984,7 +19067,7 @@ export interface WcToolkitVueGlobalComponents {
|
|
|
18984
19067
|
HelixHeadlessCarouselVueProps,
|
|
18985
19068
|
HelixHeadlessCarouselVueEvents
|
|
18986
19069
|
>;
|
|
18987
|
-
/** The composer is a separate element so you can replace it. If you need attachments, slash commands, or a model picker, replace the composer and keep the transcript. By default, Enter sends and Shift+Enter starts a new line, the convention in messaging apps. Document editors mostly use the opposite, so 'submit-on' takes 'enter' or 'button'. Use 'button' for a long-form composer. The composer clears only when no listener cancels the send, so the text is kept when you cancel a send that failed. **In a form, the draft is the composer's value**, submitted under 'name'. A form reset puts back the 'value' the markup declared, and a '<fieldset disabled>' turns the composer off. Sending is still 'helix-send', and it does not submit the form. **'required', 'minlength' and 'maxlength' are checked by the browser**, as on a '<textarea>', and the message is the browser's. 'maxlength' stops the field taking more. A draft that fails them does not send, and the composer takes ':state(invalid)' and 'aria-invalid' once the reader has tried to send it, the form was submitted, or the reader edited the field and left it. Tabbing past an empty composer marks nothing. **'typing' says whether the user is writing**, and 'helix-typing' is sent each time it changes: when they start, and when they send or stop for 'typing-timeout' milliseconds. Pass it on to show "is typing" to the other side. */
|
|
19070
|
+
/** The composer is a separate element so you can replace it. If you need attachments, slash commands, or a model picker, replace the composer and keep the transcript. By default, Enter sends and Shift+Enter starts a new line, the convention in messaging apps. Document editors mostly use the opposite, so 'submit-on' takes 'enter' or 'button'. Use 'button' for a long-form composer. The composer clears only when no listener cancels the send, so the text is kept when you cancel a send that failed. **In a form, the draft is the composer's value**, submitted under 'name'. A form reset puts back the 'value' the markup declared, and a '<fieldset disabled>' turns the composer off. Sending is still 'helix-send', and it does not submit the form. **'required', 'minlength' and 'maxlength' are checked by the browser**, as on a '<textarea>', and the message is the browser's. 'maxlength' stops the field taking more. A draft that fails them does not send, and the composer takes ':state(invalid)' and 'aria-invalid' once the reader has tried to send it, the form was submitted, or the reader edited the field and left it. Sending an empty required composer counts as trying. Tabbing past an empty composer marks nothing. **'typing' says whether the user is writing**, and 'helix-typing' is sent each time it changes: when they start, and when they send or stop for 'typing-timeout' milliseconds. Pass it on to show "is typing" to the other side. */
|
|
18988
19071
|
"helix-headless-chat-composer": DefineCustomElement<
|
|
18989
19072
|
HelixHeadlessChatComposer,
|
|
18990
19073
|
HelixHeadlessChatComposerVueProps,
|
|
@@ -18996,7 +19079,7 @@ export interface WcToolkitVueGlobalComponents {
|
|
|
18996
19079
|
HelixHeadlessChatMessageVueProps,
|
|
18997
19080
|
HelixHeadlessChatMessageVueEvents
|
|
18998
19081
|
>;
|
|
18999
|
-
/** Chat has no positioning, no backdrop, and no trigger, so you can put it in any container, such as a page, a sidebar, a modal, or a floating panel. The transcript stays pinned to the bottom, including while a streamed answer grows, until the user scrolls more than 'threshold' away from it. With 'history' set to 'more', reaching the top fires 'helix-history'. Set 'loading' while you fetch, then prepend the older turns. The turn the user was reading stays in place on screen. The log is 'aria-live="off"'. A separate status region announces each new turn once, when it has finished arriving. It skips the user's own turns unless they failed to send, turns loaded as history, and the turns already there when the transcript opened. A turn is said with its author first, such as "Ada: It ships today" ('arrival-label'), where its author can be named. Pass the turns as children or as 'turns' data. Do not use both. Children render from the server and suit most conversations. 'turns' draws a long transcript one window at a time, so the log needs a block size of its own. **A conversation is built from three elements.** The chat holds the transcript, a 'Chat.Message' stands for each turn, and a 'Chat.Composer' sits in the 'composer' slot. When the user sends, 'helix-send' reaches the chat: add their turn with 'author="me"' and 'state="sending"', then set 'state' to 'sent' or 'failed' when your server answers. Add the reply as a turn with 'state="streaming"', write its text as it arrives, and set 'state' to 'sent' when it is complete. While the user types, the composer sends 'helix-typing', which you can pass on to the other side. When the other side types, set 'typing' to their name: the status band draws three dots and "Ada is typing" ('typing-label'), which a screen reader hears, and clearing it takes them away. Anything slotted into 'status' is drawn first. **Keyboard.** The transcript moves between turns the way a feed does. Each turn says its place, such as "3 of 40", windowed or not. | Key | What it does | |---|---| | Page Down, Page Up | On a turn or inside one, moves focus to the next or the previous turn. On the transcript itself, moves focus to the turn at the top of the view. | | Control with End | Moves focus to the composer. | | Control with Home | Moves focus to the first control above the transcript, or to the transcript. | While you are scrolled away from the newest turn, the 'resume' region shows a button that takes you back, named by 'resume-label', "Jump to latest". Slot your own control into 'resume' to replace it. A screen reader names each turn by its author and its time, such as "You, 2 minutes ago". Set 'me-label' and 'message-label' to say it in your language, and give each turn by 'them' an 'author-label'. A turn with neither an author label nor a time is named by 'turn-label', "Message". A turn from 'turns' is drawn in the chat's shadow root, so style it through the forwarded 'message-*' parts. A turn by 'me' also gets each part with '-mine' added, and the turn's state adds 'message-meta-failed', 'message-content-sending', and 'message-content-streaming'. To style each participant differently, give 'author-styles' the declarations for each author, such as '{"ada": "--chat-message-background-color: …"}': the message drawn for each of their turns takes them as its 'style', so the message's custom properties change for that author alone. Turns passed as children are styled by their 'author', such as 'helix-chat-message[author="ada"]'. */
|
|
19082
|
+
/** Chat has no positioning, no backdrop, and no trigger, so you can put it in any container, such as a page, a sidebar, a modal, or a floating panel. The transcript stays pinned to the bottom, including while a streamed answer grows, until the user scrolls more than 'threshold' away from it. With 'history' set to 'more', reaching the top fires 'helix-history'. Set 'loading' while you fetch, then prepend the older turns. The turn the user was reading stays in place on screen. The log is 'aria-live="off"'. A separate status region announces each new turn once, when it has finished arriving. It skips the user's own turns unless they failed to send, turns loaded as history, and the turns already there when the transcript opened. A turn is said with its author first, such as "Ada: It ships today" ('arrival-label'), where its author can be named. Pass the turns as children or as 'turns' data. Do not use both: a chat given both draws every turn from 'turns' and then the children, and says so once in the console. Children render from the server and suit most conversations. 'turns' draws a long transcript one window at a time, so the log needs a block size of its own. **A conversation is built from three elements.** The chat holds the transcript, a 'Chat.Message' stands for each turn, and a 'Chat.Composer' sits in the 'composer' slot. When the user sends, 'helix-send' reaches the chat: add their turn with 'author="me"' and 'state="sending"', then set 'state' to 'sent' or 'failed' when your server answers. Add the reply as a turn with 'state="streaming"', write its text as it arrives, and set 'state' to 'sent' when it is complete. While the user types, the composer sends 'helix-typing', which you can pass on to the other side. When the other side types, set 'typing' to their name: the status band draws three dots and "Ada is typing" ('typing-label'), which a screen reader hears, and clearing it takes them away. Anything slotted into 'status' is drawn first. **Keyboard.** The transcript moves between turns the way a feed does. Each turn says its place, such as "3 of 40", windowed or not. The transcript is a tab stop while it holds a turn, and the turn a reader moved to is one too. Moving to an older turn unpins a transcript that scrolls and scrolls the turn into view, and moving to the newest pins it again. | Key | What it does | |---|---| | Page Down, Page Up | On a turn or inside one, moves focus to the next or the previous turn. On the transcript itself, moves focus to the turn at the top of the view. | | Control with End | Moves focus to the composer. | | Control with Home | Moves focus to the first control above the transcript, or to the transcript. | While you are scrolled away from the newest turn, the 'resume' region shows a button that takes you back, named by 'resume-label', "Jump to latest". Slot your own control into 'resume' to replace it. A screen reader names each turn by its author and its time, such as "You, 2 minutes ago". Set 'me-label' and 'message-label' to say it in your language, and give each turn by 'them' an 'author-label'. A turn with neither an author label nor a time is named by 'turn-label', "Message". A turn from 'turns' is drawn in the chat's shadow root, so style it through the forwarded 'message-*' parts. A turn by 'me' also gets each part with '-mine' added, and the turn's state adds 'message-meta-failed', 'message-content-sending', and 'message-content-streaming'. To style each participant differently, give 'author-styles' the declarations for each author, such as '{"ada": "--chat-message-background-color: …"}': the message drawn for each of their turns takes them as its 'style', so the message's custom properties change for that author alone. Turns passed as children are styled by their 'author', such as 'helix-chat-message[author="ada"]'. */
|
|
19000
19083
|
"helix-headless-chat": DefineCustomElement<
|
|
19001
19084
|
HelixHeadlessChat,
|
|
19002
19085
|
HelixHeadlessChatVueProps,
|
|
@@ -19014,7 +19097,7 @@ export interface WcToolkitVueGlobalComponents {
|
|
|
19014
19097
|
HelixHeadlessCheckboxVueProps,
|
|
19015
19098
|
HelixHeadlessCheckboxVueEvents
|
|
19016
19099
|
>;
|
|
19017
|
-
/** Renders a '<pre><code>' pair: 'pre' keeps the whitespace, and 'code' marks it as code. Long lines scroll inside the block and do not wrap, because a line break can be significant in code. A copy button is on by default. Set 'no-copy' to remove it. The button copies the slotted text, so there is no second copy of the code to keep in sync. For a fragment of code inside a sentence, use 'Code'. Set 'line-numbers' to number the lines in a gutter beside the code, hidden from the accessibility tree and left out of a copy. Set 'mark-lines' to mark lines a reader should look at, such as '2, 4-6': the block draws a band behind each run, placed where the lines are laid out, so it follows a highlighter's markup and lines that wrap. Set 'wrap' to wrap long lines rather than scroll them; a gutter then numbers each line where it starts. Set 'wrappable' for a button in the header that turns 'wrap' on and off, pressed while the lines wrap. The header holds the name, the 'actions' slot, and the copy button. Slot a control into 'actions', such as a button that sets 'wrap' or one that opens the code in an editor, and the block draws a header for it even with no name. 'copy-icon' and 'copied-icon' replace the copy button's two icons. Set 'highlight' to a function that turns the code into highlighted markup, such as one wrapping Shiki or Prism, and the block draws what it returns; it is handed the block's 'language', so one function serves every block. The code stays in the slot, so the copy button and the page's own text are the code as written. Set 'expandable' on a block whose height is capped, such as by '--code-block-max-block-size', and a button under it shows every line and then fewer again, as a docs site's long example does. The button is drawn only while the cap hides something, says whether the block is expanded with 'aria-expanded', names the block it opens with 'aria-controls', and the block carries ':state(expanded)' while it is. Set 'diff' to show a change. Put a unified diff, the output of 'git diff' or 'diff -u', in the same slot, and the block draws the lines it added and removed. The block never computes a diff itself. Line numbers come from the hunk headers and are hidden from the accessibility tree. Changed lines are '<ins>' and '<del>' with the '+' and '-' kept as text, so the change does not depend on color. Where a removed line is paired with the added line that replaced it, the words each does not share with the other are the 'changed' part, so the eye goes to what changed within the line. Each file in the patch is its own block under its own name, and its copy button copies the new version of the file. 'variant="split"' shows the old version beside the new, each removal opposite its replacement. 'context-lines' folds each long run of unchanged lines, keeping that many beside each change, behind a button that shows them and hides them again, as a code host draws a diff written with more context than a reader needs. **A block that scrolls is a tab stop.** While its lines run past its width or its cap, the scroller is a region named for the block, such as "Code, app.ts", that Tab reaches, so a keyboard scrolls it with the arrow keys in every browser. Chromium and Firefox make a scrolling box focusable on their own, and Safari does not. A block that fits is no stop at all. **The code the block draws is marked untranslated**, 'translate="no"' on its '<pre>', so a page translator leaves highlighted lines and a diff as written. Code in the slot takes its translation mode from the element, which writes nothing onto itself, so set 'translate="no"' on the element to keep a translator off plain code too. On the server, the slot renders as ordinary code, so a diff first appears as the patch text in a '<pre>'. The client makes the same first render, which keeps hydration clean, and draws the diff once it can read the content. Diff mode is experimental. The rest of the family is stable. **Several blocks are files**, one shown at a time under a row of tabs, as Sandbox shows its source panes. Put Code Blocks in the default slot of a Code Block, and each is a file named on its tab by its 'label' or, without one, its 'language'. 'file' holds the name of the file shown. The tabs are a tab list: the arrow keys move to a tab and show its file, the two swapping on a right-to-left page, and Home and End go to the first and the last. Choosing one sends 'helix-before-change' with the file's name, which you can cancel, and 'change' once 'file' holds it. The files not shown carry 'hidden', and the one shown draws no name of its own, its tab naming it. One block draws no tabs. A server cannot see the blocks inside, so the client draws the tabs once it upgrades. */
|
|
19100
|
+
/** Renders a '<pre><code>' pair: 'pre' keeps the whitespace, and 'code' marks it as code. Long lines scroll inside the block and do not wrap, because a line break can be significant in code. A copy button is on by default. Set 'no-copy' to remove it. The button copies the slotted text, so there is no second copy of the code to keep in sync. For a fragment of code inside a sentence, use 'Code'. Set 'line-numbers' to number the lines in a gutter beside the code, hidden from the accessibility tree and left out of a copy. Set 'mark-lines' to mark lines a reader should look at, such as '2, 4-6': the block draws a band behind each run, placed where the lines are laid out, so it follows a highlighter's markup and lines that wrap. 'added-lines' and 'removed-lines' mark lines the same way as inserted and deleted, as Expressive Code's 'ins' and 'del' do, in code that is not a diff. The bands are drawn and hidden from screen readers, so say in the text around the block what a marked line means. Set 'wrap' to wrap long lines rather than scroll them; a gutter then numbers each line where it starts. Set 'wrappable' for a button in the header that turns 'wrap' on and off, pressed while the lines wrap. The header holds the name, the 'actions' slot, and the copy button. Slot a control into 'actions', such as a button that sets 'wrap' or one that opens the code in an editor, and the block draws a header for it even with no name. 'copy-icon' and 'copied-icon' replace the copy button's two icons. Set 'highlight' to a function that turns the code into highlighted markup, such as one wrapping Shiki or Prism, and the block draws what it returns; it is handed the block's 'language', so one function serves every block. The code stays in the slot, so the copy button and the page's own text are the code as written. Set 'expandable' on a block whose height is capped, such as by '--code-block-max-block-size', and a button under it shows every line and then fewer again, as a docs site's long example does. The button is drawn only while the cap hides something, says whether the block is expanded with 'aria-expanded', names the block it opens with 'aria-controls', and the block carries ':state(expanded)' while it is. Set 'diff' to show a change. Put a unified diff, the output of 'git diff' or 'diff -u', in the same slot, and the block draws the lines it added and removed. The block never computes a diff itself. Line numbers come from the hunk headers and are hidden from the accessibility tree. Changed lines are '<ins>' and '<del>' with the '+' and '-' kept as text, so the change does not depend on color. Where a removed line is paired with the added line that replaced it, the words each does not share with the other are the 'changed' part, so the eye goes to what changed within the line. Each file in the patch is its own block under its own name, and its copy button copies the new version of the file. 'variant="split"' shows the old version beside the new, each removal opposite its replacement. 'context-lines' folds each long run of unchanged lines, keeping that many beside each change, behind a button that shows them and hides them again, as a code host draws a diff written with more context than a reader needs. **A block that scrolls is a tab stop.** While its lines run past its width or its cap, the scroller is a region named for the block, such as "Code, app.ts", that Tab reaches, so a keyboard scrolls it with the arrow keys in every browser. Chromium and Firefox make a scrolling box focusable on their own, and Safari does not. A block that fits is no stop at all. **The code the block draws is marked untranslated**, 'translate="no"' on its '<pre>', so a page translator leaves highlighted lines and a diff as written. Code in the slot takes its translation mode from the element, which writes nothing onto itself, so set 'translate="no"' on the element to keep a translator off plain code too. On the server, the slot renders as ordinary code, so a diff first appears as the patch text in a '<pre>'. The client makes the same first render, which keeps hydration clean, and draws the diff once it can read the content. Diff mode is experimental. The rest of the family is stable. **Several blocks are files**, one shown at a time under a row of tabs, as Sandbox shows its source panes. Put Code Blocks in the default slot of a Code Block, and each is a file named on its tab by its 'label' or, without one, its 'language'. 'file' holds the name of the file shown. The tabs are a tab list: the arrow keys move to a tab and show its file, the two swapping on a right-to-left page, and Home and End go to the first and the last. Choosing one sends 'helix-before-change' with the file's name, which you can cancel, and 'change' once 'file' holds it. The files not shown carry 'hidden', and the one shown draws no name of its own, its tab naming it. One block draws no tabs. A server cannot see the blocks inside, so the client draws the tabs once it upgrades. */
|
|
19018
19101
|
"helix-headless-code-block": DefineCustomElement<
|
|
19019
19102
|
HelixHeadlessCodeBlock,
|
|
19020
19103
|
HelixHeadlessCodeBlockVueProps,
|
|
@@ -19044,7 +19127,7 @@ export interface WcToolkitVueGlobalComponents {
|
|
|
19044
19127
|
HelixHeadlessComboboxVueProps,
|
|
19045
19128
|
HelixHeadlessComboboxVueEvents
|
|
19046
19129
|
>;
|
|
19047
|
-
/** The list is a 'Listbox', which handles filtering, the empty state, the match highlight, 'aria-activedescendant', scrolling an option into view, and moving between options with the keyboard. The palette adds a dialog and a hotkey that opens it. The palette keeps no value. It is not a form control and submits nothing. Choosing an option dispatches 'helix-select' once. To remember the last command, store it yourself. An option with 'href' is a link to a page, which the browser follows once the palette has closed. The hotkey listener is on the document, so the hotkey works from anywhere on the page, including inside another control's text field, whether or not the palette is open. 'mod' means Command on a Mac and Control elsewhere, so you write one binding. With 'inline', the palette is drawn in the page with no dialog, as a search over a list that is always shown. **Pages.** A command can open a page of commands of its own, as a palette offers "Change theme" and then the themes. Give the option 'opens' with a name, and slot the page's commands as 'page:' and that name: '''html <helix-command> <helix-option value="theme" opens="theme">Change theme</helix-option> <helix-option value="dark" slot="page:theme">Dark</helix-option> <helix-option value="light" slot="page:theme">Light</helix-option> </helix-command> ''' Choosing the opener says 'helix-select' with its value, and canceling it keeps the page that is shown. The list then shows the page, named by the opener's words, and a screen reader hears those words. Backspace in an empty filter goes back, and a screen reader hears the name of the page it goes back to. 'page' says which page is shown. The filter is cleared when the palette closes, so each opening starts from the full list. Combobox and Select do the same. As typing narrows the list, a screen reader hears how many commands are left, such as "3 commands". **Keyboard.** Focus goes to the filter field as the palette opens, and the highlight moves through the commands while you type. | Key | What it does | |---|---| | 'hotkey', Command or Control with K by default | Opens the palette from anywhere on the page, or closes it. With 'inline', puts focus in its filter field. | | Down, Up | Moves the highlight to the next or the previous command, round from the last to the first. | | Page Down, Page Up | Moves the highlight by as many commands as the list shows at once. | | Home, End, Left, Right | Move the caret in the filter field. | | Enter | Runs the highlighted command, or follows it where it is a link, and closes the palette. On a command with 'opens', shows its page. | | Command or Control with Enter | Takes the highlighted command's 'alternate' destination, where it has one. | | Backspace | In an empty filter on a page, goes back to the page before. | | Escape | Clears the filter. With the filter empty, closes the palette and puts focus back where it was. | | Tab | Stays in the palette, which is modal. With 'inline', moves on through the page. | **ARIA.** The palette is a modal 'dialog' named by 'label', or with 'inline' no dialog at all. Inside it the filter field is a text field with 'aria-autocomplete="list"', 'aria-controls' on the list, and 'aria-activedescendant' on the highlighted command, as the field of React Aria's 'Autocomplete' is. The commands are a 'listbox' of 'option's. How many commands typing left, the empty text and the loading text are said in a polite live region. */
|
|
19130
|
+
/** The list is a 'Listbox', which handles filtering, the empty state, the match highlight, 'aria-activedescendant', scrolling an option into view, and moving between options with the keyboard. The palette adds a dialog and a hotkey that opens it. The palette keeps no value. It is not a form control and submits nothing. Choosing an option dispatches 'helix-select' once. To remember the last command, store it yourself. An option with 'href' is a link to a page, which the browser follows once the palette has closed. The hotkey listener is on the document, so the hotkey works from anywhere on the page, including inside another control's text field, whether or not the palette is open. 'mod' means Command on a Mac and Control elsewhere, so you write one binding. With 'inline', the palette is drawn in the page with no dialog, as a search over a list that is always shown. **Pages.** A command can open a page of commands of its own, as a palette offers "Change theme" and then the themes. Give the option 'opens' with a name, and slot the page's commands as 'page:' and that name: '''html <helix-command> <helix-option value="theme" opens="theme">Change theme</helix-option> <helix-option value="dark" slot="page:theme">Dark</helix-option> <helix-option value="light" slot="page:theme">Light</helix-option> </helix-command> ''' Choosing the opener says 'helix-select' with its value, and canceling it keeps the page that is shown. The list then shows the page, named by the opener's words, and a screen reader hears those words. Backspace in an empty filter goes back, and a screen reader hears the name of the page it goes back to. 'page' says which page is shown. The filter is cleared when the palette closes, so each opening starts from the full list. Combobox and Select do the same. As typing narrows the list, a screen reader hears how many commands are left, such as "3 commands". **Keyboard.** Focus goes to the filter field as the palette opens, and the highlight moves through the commands while you type. | Key | What it does | |---|---| | 'hotkey', Command or Control with K by default | Opens the palette from anywhere on the page, or closes it. With 'inline', puts focus in its filter field. | | Down, Up | Moves the highlight to the next or the previous command, round from the last to the first. | | Page Down, Page Up | Moves the highlight by as many commands as the list shows at once. | | Home, End | Move the caret in the filter field. With 'home-end="list"', move the highlight to the first or the last command. | | Left, Right | Move the caret in the filter field. | | Enter | Runs the highlighted command, or follows it where it is a link, and closes the palette. On a command with 'opens', shows its page. | | Command or Control with Enter | Takes the highlighted command's 'alternate' destination, where it has one. | | Backspace | In an empty filter on a page, goes back to the page before. | | Escape | Clears the filter. With the filter empty, closes the palette and puts focus back where it was. | | Tab | Stays in the palette, which is modal. With 'inline', moves on through the page. | **ARIA.** The palette is a modal 'dialog' named by 'label', or with 'inline' no dialog at all. Inside it the filter field is a text field with 'aria-autocomplete="list"', 'aria-controls' on the list, and 'aria-activedescendant' on the highlighted command, as the field of React Aria's 'Autocomplete' is. The commands are a 'listbox' of 'option's. How many commands typing left, the empty text and the loading text are said in a polite live region. */
|
|
19048
19131
|
"helix-headless-command": DefineCustomElement<
|
|
19049
19132
|
HelixHeadlessCommand,
|
|
19050
19133
|
HelixHeadlessCommandVueProps,
|
|
@@ -19134,7 +19217,7 @@ export interface WcToolkitVueGlobalComponents {
|
|
|
19134
19217
|
HelixHeadlessFileInputVueProps,
|
|
19135
19218
|
HelixHeadlessFileInputVueEvents
|
|
19136
19219
|
>;
|
|
19137
|
-
/** Shows one filter declared by a 'FilterField': the field, the operator, and the values, with a control to remove the filter. The operator is shown only when it is not the field's default: ''' Disposition refunded, chargeback default operator, hidden Disposition is not refunded chosen operator, shown Created after 1 Aug a scalar field has no default ''' Omit 'operator-label' for the field's default operator and pass it for every other operator. The code that builds the chip has the field, and the field defines its default. The chip shows a filter and does not apply it. Dismissing fires 'helix-dismiss' as a request, as on 'Tag' and 'Announcement'. The chip is your element in your list, so you remove it, which keeps your model and the document in step. Call 'preventDefault()' on 'helix-dismiss' to cancel the dismissal, which is also how you take control of the interaction for one press. 'requestChange' documents the pattern. **Keyboard.** The remove button is a tab stop of its own, and Enter or Space on it asks to remove the filter. In a 'FilterInput', Backspace in the empty field asks to remove the last chip, the arrow keys move between the field and the chips, and Delete or Backspace on a chip asks to remove it. The remove button is named 'dismiss-label' followed by the chip's words, such as "Remove filter Status is not open", so a row of chips says which filter each button removes. Write '{label}' in 'dismiss-label' to put the words elsewhere. To let the user change the operator, slot a menu trigger into 'operator'. With the text fallback, the operator is a label. The chip does not interpret operators: their meaning belongs to your domain, as 'FilterOperator' explains. */
|
|
19220
|
+
/** Shows one filter declared by a 'FilterField': the field, the operator, and the values, with a control to remove the filter. The operator is shown only when it is not the field's default: ''' Disposition refunded, chargeback default operator, hidden Disposition is not refunded chosen operator, shown Created after 1 Aug a scalar field has no default ''' Omit 'operator-label' for the field's default operator and pass it for every other operator. The code that builds the chip has the field, and the field defines its default. The chip shows a filter and does not apply it. Dismissing fires 'helix-dismiss' as a request, as on 'Tag' and 'Announcement'. The chip is your element in your list, so you remove it, which keeps your model and the document in step. Call 'preventDefault()' on 'helix-dismiss' to cancel the dismissal, which is also how you take control of the interaction for one press. 'requestChange' documents the pattern. **Keyboard.** The remove button is a tab stop of its own, and Enter or Space on it asks to remove the filter. In a 'FilterInput', the field's text is the one tab stop: Backspace in the empty field asks to remove the last chip, the arrow keys move between the field and the chips, and Delete or Backspace on a chip asks to remove it. The remove button is named 'dismiss-label' followed by the chip's words, such as "Remove filter Status is not open", so a row of chips says which filter each button removes. Write '{label}' in 'dismiss-label' to put the words elsewhere. To let the user change the operator, slot a menu trigger into 'operator'. With the text fallback, the operator is a label. The chip does not interpret operators: their meaning belongs to your domain, as 'FilterOperator' explains. */
|
|
19138
19221
|
"helix-headless-filter-chip": DefineCustomElement<
|
|
19139
19222
|
HelixHeadlessFilterChip,
|
|
19140
19223
|
HelixHeadlessFilterChipVueProps,
|
|
@@ -19158,13 +19241,13 @@ export interface WcToolkitVueGlobalComponents {
|
|
|
19158
19241
|
HelixHeadlessFilterOperatorVueProps,
|
|
19159
19242
|
HelixHeadlessFilterOperatorVueEvents
|
|
19160
19243
|
>;
|
|
19161
|
-
/** Tokens are your own elements, slotted in. A filter can be a facet with a prefix, a saved query, or a range, and these belong to your model, so the element does not render tokens from a list of strings. Removing a token is a request the element fires, and you apply it. Combobox works the other way: its tokens show a selection it owns, drawn from the options it was given. 'value' is the typed text. Every keystroke fires 'input' with the text on the element, so a table can narrow as the user types. Backspace in an empty field fires 'helix-dismiss' on the last token, the same event its remove control fires, so one handler covers the pointer and the keyboard. **What a form receives.** The text under 'name', and then one more entry under 'name' for each token, in the order the tokens stand: | Token | Entry | |---|---| | Any element with a 'value' attribute | The value as written: 'saved:mine' | | 'FilterChip' with 'name' and values | 'status:open,pending' | | The same, with 'operator="none"' (what a typed '-status:' makes) | '-status:open,pending' | | The same, with any other 'operator' except 'any' | 'created[after]:2024' | | A token with neither | Nothing | The values are the chip's text outside its 'field' and 'operator' slots, with the spaces around each comma removed. A server splits an entry at its first colon, reads a leading '-' as the negation, and reads a word in brackets before the colon as the comparison. **Keyboard.** Focus stays in the text. The text names the highlighted suggestion as its 'aria-activedescendant'. | Key | What it does | |---|---| | Enter | Presses the highlighted suggestion. With none highlighted, reads the typed filters into chips, or submits the form when there are none. | | Down, Up | Moves the highlight through the suggestions, wrapping, and opens the panel. | | Home, End | Highlights the first or the last suggestion while the panel is open. | | Escape | Closes the panel and stops there, so a dialog around the field stays open. | | Backspace | In an empty field, asks the last token to go. | | 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. | | Left, Right on a token | Move between the tokens, and past the last back to the text. | | Delete, Backspace on a token | Asks the token to go. | **Typed filters.** The field parses only the fields you declare. Write 'FilterField' elements, usually inside the 'FilterMenu' slotted into 'start', so the picker and the text share one set. On Enter, the field reads the text against them. 'disposition:refunded,settled' and '-disposition:refunded' fire 'helix-facet' exactly as ticking those values in the picker would, and the parsed text is removed. Everything else stays, so 'refund tuesday disposition:settled' is a filter and a search at once. Helix defines the punctuation and you define every word. 'grammar.ts' has the full rule, so read it before you rely on it. A field with no 'FilterField' in it parses nothing. A field whose values cannot be listed, such as 'assignee:ada', goes directly inside this element, outside the menu. It is not assigned to a slot, so nothing draws it and the menu has no page for it, and the grammar still reads it. **Suggestions.** Slot options into 'suggestions' and the field shows them, moves through them with the arrow keys, and presses one on Enter. The option fires its own 'helix-select', and you decide what choosing it means. Keys before a colon and values after it use the same panel with different contents. 'filter-suggestions' narrows the panel to the options whose words hold the term at the caret, after its colon, ignoring case and accents, and hides the rest. 'readFilterText' is exported so you can narrow it yourself against partly typed text. While the panel is open, a reader hears how many suggestions it offers. The panel opens when it has options and closes when it has none, and a choice does not close it, so after picking a key you see its values next. Use 'selectionStart' and 'setSelectionRange' to write a completion back and put the caret after it, or the next parse reads the wrong term. **State.** Three things have three different owners: - 'value' is the text. The user types, the element applies it, and 'input' reports it. Setting 'value' seeds or corrects the text, and the next keystroke overwrites it, even in React. To control the value, cancel 'helix-before-change' and write the value you want, as with every field in this library. 'default-value' seeds the field. - 'open' is the suggestions panel. Cancel 'helix-before-open' or 'helix-before-close' to control it, and use 'default-open' to seed it. - Tokens are your elements in a slot and hold no state. A token goes when you remove it from your markup after 'helix-dismiss'. A 'FilterChip' naming a declared field works differently, because the picker holds what is ticked and removing the chip alone would leave its value ticked in the hidden menu. Its dismissal is treated as the field being filtered by nothing, so it fires 'helix-facet' like every other change, and the chip goes when the filter goes. */
|
|
19244
|
+
/** Tokens are your own elements, slotted in. A filter can be a facet with a prefix, a saved query, or a range, and these belong to your model, so the element does not render tokens from a list of strings. Removing a token is a request the element fires, and you apply it. Combobox works the other way: its tokens show a selection it owns, drawn from the options it was given. 'value' is the typed text. Every keystroke fires 'input' with the text on the element, so a table can narrow as the user types. Backspace in an empty field fires 'helix-dismiss' on the last token, the same event its remove control fires, so one handler covers the pointer and the keyboard. **What a form receives.** The text under 'name', and then one more entry under 'name' for each token, in the order the tokens stand: | Token | Entry | |---|---| | Any element with a 'value' attribute | The value as written: 'saved:mine' | | 'FilterChip' with 'name' and values | 'status:open,pending' | | The same, with 'operator="none"' (what a typed '-status:' makes) | '-status:open,pending' | | The same, with any other 'operator' except 'any' | 'created[after]:2024' | | A token with neither | Nothing | The values are the chip's text outside its 'field' and 'operator' slots, with the spaces around each comma removed. A server splits an entry at its first colon, reads a leading '-' as the negation, and reads a word in brackets before the colon as the comparison. **Keyboard.** Focus stays in the text, which is the field's one tab stop. The text names the highlighted suggestion as its 'aria-activedescendant', and the arrow keys reach the tokens. | Key | What it does | |---|---| | Enter | Presses the highlighted suggestion. With none highlighted, reads the typed filters into chips, or submits the form when there are none. | | Down, Up | Moves the highlight through the suggestions, wrapping, and opens the panel. | | Home, End | Highlights the first or the last suggestion while the panel is open. | | Escape | Closes the panel and stops there, so a dialog around the field stays open. | | Backspace | In an empty field, asks the last token to go. | | 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. | | Left, Right on a token | Move between the tokens, and past the last back to the text. | | Delete, Backspace on a token | Asks the token to go. | **Typed filters.** The field parses only the fields you declare. Write 'FilterField' elements, usually inside the 'FilterMenu' slotted into 'start', so the picker and the text share one set. On Enter, the field reads the text against them. 'disposition:refunded,settled' and '-disposition:refunded' fire 'helix-facet' exactly as ticking those values in the picker would, and the parsed text is removed. Everything else stays, so 'refund tuesday disposition:settled' is a filter and a search at once. Helix defines the punctuation and you define every word. 'grammar.ts' has the full rule, so read it before you rely on it. A field with no 'FilterField' in it parses nothing. A field whose values cannot be listed, such as 'assignee:ada', goes directly inside this element, outside the menu. It is not assigned to a slot, so nothing draws it and the menu has no page for it, and the grammar still reads it. **Suggestions.** Slot options into 'suggestions' and the field shows them, moves through them with the arrow keys, and presses one on Enter. The option fires its own 'helix-select', and you decide what choosing it means. Keys before a colon and values after it use the same panel with different contents. 'filter-suggestions' narrows the panel to the options whose words hold the term at the caret, after its colon, ignoring case and accents, and hides the rest. 'readFilterText' is exported so you can narrow it yourself against partly typed text. While the panel is open, a reader hears how many suggestions it offers. The panel opens when it has options and closes when it has none, and a choice does not close it, so after picking a key you see its values next. Use 'selectionStart' and 'setSelectionRange' to write a completion back and put the caret after it, or the next parse reads the wrong term. **State.** Three things have three different owners: - 'value' is the text. The user types, the element applies it, and 'input' reports it. Setting 'value' seeds or corrects the text, and the next keystroke overwrites it, even in React. To control the value, cancel 'helix-before-change' and write the value you want, as with every field in this library. 'default-value' seeds the field. - 'open' is the suggestions panel. Cancel 'helix-before-open' or 'helix-before-close' to control it, and use 'default-open' to seed it. - Tokens are your elements in a slot and hold no state. A token goes when you remove it from your markup after 'helix-dismiss'. A 'FilterChip' naming a declared field works differently, because the picker holds what is ticked and removing the chip alone would leave its value ticked in the hidden menu. Its dismissal is treated as the field being filtered by nothing, so it fires 'helix-facet' like every other change, and the chip goes when the filter goes. Set 'chips' and the field adds, updates, and removes those chips itself, from every 'helix-facet' you do not cancel. */
|
|
19162
19245
|
"helix-headless-filter-input": DefineCustomElement<
|
|
19163
19246
|
HelixHeadlessFilterInput,
|
|
19164
19247
|
HelixHeadlessFilterInputVueProps,
|
|
19165
19248
|
HelixHeadlessFilterInputVueEvents
|
|
19166
19249
|
>;
|
|
19167
|
-
/** Formats a date with 'Intl' where it is shown, so you do not write the same 'Intl' call and options in your own code. **'elapsed' shows compact relative time for a feed**, such as "42m", "3h", or "1d". After six days it shows a date. In en-US, 'Intl.NumberFormat' narrow renders both 'minute' and 'month' as 'm', so a compact "3m" could mean three minutes or three months. 'elapsedTime' in 'helix/core' does the measurement. **'relative' shows the same reading in words**, such as "3 hours ago" at 'long', "3 hr. ago" at 'short' and "3h ago" at 'narrow', the styles 'sl-relative-time' offers. 'numeric="always"' says "1 day ago" where the default says "yesterday". **'date-style' and 'time-style' take each locale's own pattern**, such as "Tuesday, August 4, 2026" at 'full', and stand in for the separate fields, which 'Intl' refuses beside them. 'hour-cycle' sets a twelve or twenty-four hour clock either way. **The text refreshes on one timer shared by the page.** Each element schedules an update for when its current reading expires, and an element showing a date schedules none, so a long feed left open costs almost nothing. 'frozen' draws the reading once and leaves it. **'fields' draws each field of a date as a part of its own**, such as 'day', 'month' and 'year', so a stylesheet can set the year in a lighter ink or the weekday in capitals with '::part()'. The text between the fields is the locale's own and has no part. An 'elapsed' or 'relative' reading is one phrase, with no parts inside it. **The output is always '<time datetime>'**, so copy and paste and scripts parsing the page get the exact instant, whatever the visible text says. A screen reader reads the text, so an 'elapsed' reading is named in full, such as "3 hours ago", and carries the whole date as its title. **A date with no time, such as '2026-08-04', is that day everywhere.** It is formatted in UTC unless 'time-zone' says otherwise, as Date Input and Date Picker format their dates, so a reader west of UTC sees August 4 and not August 3. **A date is written in a calendar Date Picker draws**: the locale's own where its months are the Gregorian months, as 'th-TH' writes 2569 for 2026, and 'gregory' where they are not, as for 'fa-IR'. 'calendar' picks any of them, 'persian' and 'hebrew' included. */
|
|
19250
|
+
/** Formats a date with 'Intl' where it is shown, so you do not write the same 'Intl' call and options in your own code. **'elapsed' shows compact relative time for a feed**, such as "42m", "3h", or "1d". After six days it shows a date. In en-US, 'Intl.NumberFormat' narrow renders both 'minute' and 'month' as 'm', so a compact "3m" could mean three minutes or three months. 'elapsedTime' in 'helix/core' does the measurement. **'relative' shows the same reading in words**, such as "3 hours ago" at 'long', "3 hr. ago" at 'short' and "3h ago" at 'narrow', the styles 'sl-relative-time' offers. 'numeric="always"' says "1 day ago" where the default says "yesterday". Both readings round the count, as 'sl-relative-time' does: 100 seconds ago is "2 minutes ago", and 59.6 minutes is "1 hour". **'date-style' and 'time-style' take each locale's own pattern**, such as "Tuesday, August 4, 2026" at 'full', and stand in for the separate fields, which 'Intl' refuses beside them. 'hour-cycle' sets a twelve or twenty-four hour clock either way. **The text refreshes on one timer shared by the page.** Each element schedules an update for when its current reading expires, and an element showing a date schedules none, so a long feed left open costs almost nothing. 'frozen' draws the reading once and leaves it. **'fields' draws each field of a date as a part of its own**, such as 'day', 'month' and 'year', so a stylesheet can set the year in a lighter ink or the weekday in capitals with '::part()'. The text between the fields is the locale's own and has no part. An 'elapsed' or 'relative' reading is one phrase, with no parts inside it. **The output is always '<time datetime>'**, so copy and paste and scripts parsing the page get the exact instant, whatever the visible text says. A screen reader reads the text, so an 'elapsed' reading is named in full, such as "3 hours ago", and carries the whole date as its title. **A date with no time, such as '2026-08-04', is that day everywhere.** It is formatted in UTC unless 'time-zone' says otherwise, as Date Input and Date Picker format their dates, so a reader west of UTC sees August 4 and not August 3. **A date is written in a calendar Date Picker draws**: the locale's own where its months are the Gregorian months, as 'th-TH' writes 2569 for 2026, and 'gregory' where they are not, as for 'fa-IR'. 'calendar' picks any of them, 'persian' and 'hebrew' included. */
|
|
19168
19251
|
"helix-headless-format-date": DefineCustomElement<
|
|
19169
19252
|
HelixHeadlessFormatDate,
|
|
19170
19253
|
HelixHeadlessFormatDateVueProps,
|
|
@@ -19560,7 +19643,7 @@ export interface WcToolkitVueGlobalComponents {
|
|
|
19560
19643
|
HelixHeadlessStatVueProps,
|
|
19561
19644
|
HelixHeadlessStatVueEvents
|
|
19562
19645
|
>;
|
|
19563
|
-
/** 'active' sets where the user is, and 'complete' stays on each step. Returning to stage one of three leaves stages one and two finished, so the root sets 'current' on the steps and never changes 'complete'. 'active' is optional. Without it, each step keeps its own 'current', so the sequence is correct in the server's markup, where the root cannot count its slotted children. 'linear' keeps a reader from passing a stage they have not finished, as Ark UI's linear steps do: a stage ahead is out of reach, and its button disabled, until every stage before it is 'complete' or 'optional'. Going back is always allowed. 'next()' and 'previous()' move one stage either way, under the same rules, for your own buttons. 'reset()' goes back to the first stage and clears every stage's 'complete', as Ark UI's 'resetStep' does. 'completion="passed"' marks a stage 'complete' once a reader moves past it, as Ark UI counts a stage before the current one as completed. Going back leaves it complete. In a 'linear' sequence the next stage is then in reach from the current one, and 'validate' decides whether the reader may go. To check a stage before a reader moves on from it, set 'validate' to a function that answers whether the stage is valid, as Ark UI's 'isStepValid' does. Moving forward asks it about the stage the reader is on, and where it answers 'false' the reader stays and the stage is ':state(invalid)' until it answers 'true'. An 'optional' stage is not asked. 'helix-before-activate' is still sent for every move, for a check of your own. 'progress' is how far through the sequence is, from 0 to 100: the share of its stages that are 'complete'. The 'progress' part carries it as a 'progressbar' and as '--steps-progress', and is hidden until a stylesheet gives it a 'display', so a bar of your own costs nothing until you draw it. A screen reader hears it as 'progress-label' says, "33% complete" unless set, as Ark UI's steps write it. The sequence is ':state(complete)' once every stage is. The sequence is a list named by 'label', and each step a list item. The current stage's button says 'aria-current="step"', and a finished stage's button is described by its 'complete-label'. **Keyboard.** Each stage's name is a button and its own tab stop, and Enter or Space goes to the stage. Set 'arrows' and the
|
|
19646
|
+
/** 'active' sets where the user is, and 'complete' stays on each step. Returning to stage one of three leaves stages one and two finished, so the root sets 'current' on the steps and never changes 'complete'. 'active' is optional. Without it, each step keeps its own 'current', so the sequence is correct in the server's markup, where the root cannot count its slotted children. 'active' names a step by its 'value'. A step with no 'value' is named by its place, counted from 1, so a sequence written without values moves as one written with them, and 'helix-activate' says '1', '2' and so on. Give every step a value or none, because a value of '2' and the second place are one name. 'linear' keeps a reader from passing a stage they have not finished, as Ark UI's linear steps do: a stage ahead is out of reach, and its button disabled, until every stage before it is 'complete' or 'optional'. Going back is always allowed. 'next()' and 'previous()' move one stage either way, under the same rules, for your own buttons. 'reset()' goes back to the first stage and clears every stage's 'complete', as Ark UI's 'resetStep' does. A button anywhere on the page calls them with no script, as Ark UI's previous and next triggers do: give it 'commandfor' with the sequence's 'id', and 'command="--previous"', '"--next"' or '"--reset"'. 'completion="passed"' marks a stage 'complete' once a reader moves past it, as Ark UI counts a stage before the current one as completed. Going back leaves it complete. In a 'linear' sequence the next stage is then in reach from the current one, and 'validate' decides whether the reader may go. To check a stage before a reader moves on from it, set 'validate' to a function that answers whether the stage is valid, as Ark UI's 'isStepValid' does. Moving forward asks it about the stage the reader is on, and where it answers 'false' the reader stays and the stage is ':state(invalid)' until it answers 'true'. An 'optional' stage is not asked. 'helix-before-activate' is still sent for every move, for a check of your own. 'progress' is how far through the sequence is, from 0 to 100: the share of its stages that are 'complete'. The 'progress' part carries it as a 'progressbar' and as '--steps-progress', and is hidden until a stylesheet gives it a 'display', so a bar of your own costs nothing until you draw it. A screen reader hears it as 'progress-label' says, "33% complete" unless set, as Ark UI's steps write it. The sequence is ':state(complete)' once every stage is. The sequence is a list named by 'label', and each step a list item. The current stage's button says 'aria-current="step"', and a finished stage's button is described by its 'complete-label'. **Keyboard.** Each stage's name is a button and its own tab stop, and Enter or Space goes to the stage. Set 'arrows' and the names are one tab stop, the current stage's, and the arrow keys move focus between them: Left and Right along a row, Up and Down a column, Home and End to the first and the last. The stop follows focus, so Tab leaves the sequence and Shift+Tab comes back to the name the reader left. The arrows pass over a disabled stage and one a linear sequence holds out of reach, and they move focus without going to the stage. */
|
|
19564
19647
|
"helix-headless-steps": DefineCustomElement<
|
|
19565
19648
|
HelixHeadlessSteps,
|
|
19566
19649
|
HelixHeadlessStepsVueProps,
|
|
@@ -19746,7 +19829,7 @@ export interface WcToolkitVueGlobalComponents {
|
|
|
19746
19829
|
HelixHeadlessVideoPlaylistMenuVueProps,
|
|
19747
19830
|
HelixHeadlessVideoPlaylistMenuVueEvents
|
|
19748
19831
|
>;
|
|
19749
|
-
/** **You slot the player**, so it keeps your appearance, extra controls, captions, and poster treatment. 'Sandbox' takes its preview and 'Menu' its trigger the same way. **Entries are markup.** React skips properties it would set imperatively during hydration, so an array property on a custom element is missing on the first paint of a server-rendered page. 'using-the-elements.mdx' has the measurement. Markup also makes each entry a real button with its name inside. **The playlist does not play media.** It sets 'src' on the player and tracks which entry is current. The current entry moves when: - an entry is pressed, - the player dispatches 'helix-next' or 'helix-previous', or - the player reaches the end. On 'ended' the playlist advances and the next clip starts playing, because the user already pressed play once. 'no-advance' turns that off, and the playlist stays on the entry that ended. 'repeat' decides what happens at the end: 'one' plays the same entry again, and 'all' goes from the last entry back to the first. Without it, the playlist stops on the last entry and sends 'helix-end'. 'shuffle' plays the entries in a random order, starting from the one that is current, and 'previous' retraces that order. **'helix-before-activate' says why the playlist is moving**, in 'detail.cause': 'press' for an entry or a menu choice, 'next' and 'previous' for the player's controls and the methods, 'ended' at the end of a clip, and 'removed' when the current entry leaves the playlist. Cancel an 'ended' move to show your own "Up next" countdown, then call 'next()'. **Removing the current entry moves the playlist on**, to the entry after it, or to the one before it when it was the last. A clip that was playing keeps playing in the entry that takes its place. **The player is named by the current entry**, and the device's own media controls show the entry as the title. A player you gave a 'label' keeps your name, and only the title follows the entry. **Keyboard.** The entries take one stop in the tab order: the entry you last focused, or the current entry before you have focused one. Enter or Space plays it. The arrow keys move focus to the entry before or after, and Home and End to the first and the last, passing over disabled entries. The current entry carries 'aria-current'. While focus is on the player, the player's own keys work, and 'Video' lists them, and Shift with N or P plays the next or the previous entry. The player's previous and next controls move through the entries in the same order the playlist does. **Moving entries.** 'reorderable' lets a reader change the order of the queue: - Alt with Up or Down moves the focused entry a place, and Alt with Home or End moves it to either end, as the APG's rearrangeable listbox does. Focus stays on it. - A pointer drags an entry, with a drop indicator, and the page scrolls near an edge. A press that does not travel still plays the entry. - A drop sends 'helix-before-reorder', which you can refuse, and then 'helix-reorder', whose 'keys' hold every entry's 'value' in the new order. **You move the entries**: the playlist moves no element of yours, and the next entry is the one after the current entry in the order you leave. - Each move is said in the live region, in words you can change: 'moved-label', 'dropped-label', 'canceled-label', and 'picked-up-label'. **What a screen reader hears.** A list named by 'label', with a button for each entry. When the playlist moves to another entry, by a press, by the player's controls, or at the end of a clip, a live region says 'playing-label', "Now playing" and the entry's name. */
|
|
19832
|
+
/** **You slot the player**, so it keeps your appearance, extra controls, captions, and poster treatment. 'Sandbox' takes its preview and 'Menu' its trigger the same way. **The player is a 'Video' or a plain '<video>'.** Either takes 'src' and 'poster' from the entry, is named by it, plays on, and answers Shift with N or P while focused. A plain '<video>' has no previous and next controls that send 'helix-previous' or 'helix-next', so its moves are the entries, the menu, and your own buttons calling 'previous()' and 'next()'. **Entries are markup.** React skips properties it would set imperatively during hydration, so an array property on a custom element is missing on the first paint of a server-rendered page. 'using-the-elements.mdx' has the measurement. Markup also makes each entry a real button with its name inside. **The playlist does not play media.** It sets 'src' on the player and tracks which entry is current. The current entry moves when: - an entry is pressed, - the player dispatches 'helix-next' or 'helix-previous', or - the player reaches the end. On 'ended' the playlist advances and the next clip starts playing, because the user already pressed play once. 'no-advance' turns that off, and the playlist stays on the entry that ended. 'repeat' decides what happens at the end: 'one' plays the same entry again, and 'all' goes from the last entry back to the first. Without it, the playlist stops on the last entry and sends 'helix-end'. 'shuffle' plays the entries in a random order, starting from the one that is current, and 'previous' retraces that order. **'helix-before-activate' says why the playlist is moving**, in 'detail.cause': 'press' for an entry or a menu choice, 'next' and 'previous' for the player's controls and the methods, 'ended' at the end of a clip, and 'removed' when the current entry leaves the playlist. Cancel an 'ended' move to show your own "Up next" countdown, then call 'next()'. **Removing the current entry moves the playlist on**, to the entry after it, or to the one before it when it was the last. A clip that was playing keeps playing in the entry that takes its place. **The player is named by the current entry**, and the device's own media controls show the entry as the title. A player you gave a 'label' keeps your name, and only the title follows the entry. A plain '<video>' is named through 'aria-label', unless you wrote one. **Keyboard.** The entries take one stop in the tab order: the entry you last focused, or the current entry before you have focused one. Enter or Space plays it. The arrow keys move focus to the entry before or after, and Home and End to the first and the last, passing over disabled entries. The current entry carries 'aria-current'. While focus is on the player, the player's own keys work, and 'Video' lists them, and Shift with N or P plays the next or the previous entry. The player's previous and next controls move through the entries in the same order the playlist does. **Moving entries.** 'reorderable' lets a reader change the order of the queue: - Alt with Up or Down moves the focused entry a place, and Alt with Home or End moves it to either end, as the APG's rearrangeable listbox does. Focus stays on it. - A pointer drags an entry, with a drop indicator, and the page scrolls near an edge. A press that does not travel still plays the entry. - A drop sends 'helix-before-reorder', which you can refuse, and then 'helix-reorder', whose 'keys' hold every entry's 'value' in the new order. **You move the entries**: the playlist moves no element of yours, and the next entry is the one after the current entry in the order you leave. - Each move is said in the live region, in words you can change: 'moved-label', 'dropped-label', 'canceled-label', and 'picked-up-label'. **What a screen reader hears.** A list named by 'label', with a button for each entry. When the playlist moves to another entry, by a press, by the player's controls, or at the end of a clip, a live region says 'playing-label', "Now playing" and the entry's name. */
|
|
19750
19833
|
"helix-headless-video-playlist": DefineCustomElement<
|
|
19751
19834
|
HelixHeadlessVideoPlaylist,
|
|
19752
19835
|
HelixHeadlessVideoPlaylistVueProps,
|
|
@@ -19758,7 +19841,7 @@ export interface WcToolkitVueGlobalComponents {
|
|
|
19758
19841
|
HelixHeadlessVideoVueProps,
|
|
19759
19842
|
HelixHeadlessVideoVueEvents
|
|
19760
19843
|
>;
|
|
19761
|
-
/** The items arrive as data, in one of two ways: - 'items' takes an array. A framework sets it as a property, and React hydration keeps it. - 'for' names a '<script type="application/json">' that holds an array, which a server sends as markup. Each item is drawn into a row in one of two ways: - 'renderItem' is a function from an item and its index to the row's content: a Lit template, a string, or a DOM node. - A '<template>' child defines one row. 'data-field="name"' fills an element with the item's 'name' as text, and 'data-field-href="url"' writes the item's 'url' into 'href', the same for any attribute. A field may be a path of keys, such as 'author.name'. Rows are your markup in the light DOM, so your stylesheet styles them. **A grid.** 'columns' lays the items out that many to a line, as a grid of equal columns, and windows the set a line at a time, as React Aria's grid layout does. Each item draws one element, a cell of the grid, and 'estimate' is the height of a line. 'min-column-width' lays out as many columns as fit the box instead, as React Aria's grid layout does with its smallest item size, and follows the box as it resizes. 'gap' spaces the rows, and the columns of a grid, by a number of pixels the list counts in each row's place. **Across.** 'orientation="horizontal"' lays the items out along a line and scrolls it sideways, as a strip of cards does, windowed the same way: 'estimate' is then an item's width, and the box needs an inline size. **Sections.** 'section-field' names the field of each item that says which section it is in, and the list draws a header before each section's items, as React Aria's list box sections do. Each section is an element with the 'group' role, named by its header, which is its first child and carries 'data-header', so your stylesheet styles it, such as with 'position: sticky'. A section starts wherever the field changes, so give the items in order. The window counts the headers with the items, and a section the window starts inside is drawn with its header. 'renderSection' draws a header of your own. **Keyboard.** The list is one tab stop. | Key | What it does | |---|---| | Down, Up | Moves to the next or the previous item, or in a grid to the item in the same column on the next or the previous line. | | Right, Left | In a grid, moves to the next or the previous item along the line, the other way round on a right-to-left page. In a list that runs across, moves to the next or the previous item the same way, and Down and Up are left to the row. | | Home, End | Moves to the first or the last item. | | Page Down, Page Up | Moves by the number of items, or of lines in a grid, on screen. | | A letter or a word | Moves to the next item whose text starts with what you typed. | | Escape | Lets go of every chosen item, in a list with 'selection-mode'. | | Tab | Moves into the focused row's own links and buttons, then out of the list. | An item that is not drawn is scrolled into view and focused, so a keyboard reaches the whole set. When the row holding the tab stop scrolls away, the stop moves to the first row on screen. Typing matches each item's 'text-field', which is the first 'data-field' of the row template by default, or the item itself when it is a string or a number. Each row says its place in the whole set with 'aria-posinset' and 'aria-setsize', so a screen reader says "4,000 of 10,000". The row holding focus stays drawn when it scrolls out. **Selecting.** 'selection-mode' makes the list a list box a reader chooses from: 'single' selects one item and 'multiple' any number. Space or a press selects an item, Shift with Space, an arrow, Home, End or a press takes in the items from the last one chosen, and Control or Command with A selects them all, in 'multiple'. Escape lets go of every chosen item, and keeps the key from the dialog or menu around the list while there was something to let go of. 'value' holds the chosen items' keys, separated by commas, in the order of the set: 'key-field' names each item's key, and a string or a number item is its own key. A change asks with 'helix-before-change' and tells with 'change'. Each row is an 'option' marked 'aria-selected', so a row's own links and buttons are not reached there: keep those to a list without 'selection-mode'. 'selection-behavior="replace"' selects the item pressed alone, as a file list does, and the arrow keys carry the selection with them. Control or Command with a press or with Space adds or takes out one item, and with an arrow moves without selecting. **Disabled items.** 'disabled-keys' names items by their keys, separated by commas. Their rows carry 'aria-disabled', the keys and typing pass over them, and a press, Space, or Control with A does not select them. **Loading more.** 'helix-range-change' fires as the items on screen change, and 'range' holds them. 'helix-load-more' fires once a reader is within one screen of the end, once for each length of the set: add to 'items' and it can fire again. While you fetch, set 'loading': the list is busy, and a row after the last item says "Loading more" ('loading-label', or your own content in the 'loading' slot). 'scrollToIndex' takes a reader to an item. **An empty list.** Set 'empty-label', or put your own content in the 'empty' slot, for a row shown when there are no items and none are loading, such as "No messages yet" and a link to write one. Without either, an empty list shows nothing, since a list whose items have not arrived yet has not said it has none. The list takes the 'empty' state while it has read its items and holds none, and the 'loading' state while 'loading' is set, so your stylesheet can change the box around it for either. A list with no name is reported once in a development build. Name it with 'label' or 'aria-label'. **Row height.** Rows are placed by 'estimate' until they are drawn. Then the list reads the drawn rows' height once and places every row by it, so a wrong estimate still reaches the last item. Set 'measured' for rows of different heights. Once the list draws rows of different heights, such as rows that wrap on a narrow screen, it places each row by its own height whether 'measured' is set or not. The list follows its source. A new 'items' array, an edit to the script's text, or a script replaced under the same id draws the new rows. A row that stays in view keeps its element as the list scrolls. The viewport scrolls on this tier. It carries 'data-scroller', and 'core' ships '[data-scroller] { overflow: auto }' into every shadow root, so 'scrollTop' works with no stylesheet. You still need to set a block size. */
|
|
19844
|
+
/** The items arrive as data, in one of two ways: - 'items' takes an array. A framework sets it as a property, and React hydration keeps it. - 'for' names a '<script type="application/json">' that holds an array, which a server sends as markup. Each item is drawn into a row in one of two ways: - 'renderItem' is a function from an item and its index to the row's content: a Lit template, a string, or a DOM node. - A '<template>' child defines one row. 'data-field="name"' fills an element with the item's 'name' as text, and 'data-field-href="url"' writes the item's 'url' into 'href', the same for any attribute. A field may be a path of keys, such as 'author.name'. Rows are your markup in the light DOM, so your stylesheet styles them. **A grid.** 'columns' lays the items out that many to a line, as a grid of equal columns, and windows the set a line at a time, as React Aria's grid layout does. Each item draws one element, a cell of the grid, and 'estimate' is the height of a line. 'min-column-width' lays out as many columns as fit the box instead, as React Aria's grid layout does with its smallest item size, and follows the box as it resizes. 'gap' spaces the rows, and the columns of a grid, by a number of pixels the list counts in each row's place. **Across.** 'orientation="horizontal"' lays the items out along a line and scrolls it sideways, as a strip of cards does, windowed the same way: 'estimate' is then an item's width, and the box needs an inline size. **Sections.** 'section-field' names the field of each item that says which section it is in, and the list draws a header before each section's items, as React Aria's list box sections do. Each section is an element with the 'group' role, named by its header, which is its first child and carries 'data-header', so your stylesheet styles it, such as with 'position: sticky'. A section starts wherever the field changes, so give the items in order. The window counts the headers with the items, and a section the window starts inside is drawn with its header. 'renderSection' draws a header of your own. **Keyboard.** The list is one tab stop. | Key | What it does | |---|---| | Down, Up | Moves to the next or the previous item, or in a grid to the item in the same column on the next or the previous line. | | Right, Left | In a grid, moves to the next or the previous item along the line, the other way round on a right-to-left page. In a list that runs across, moves to the next or the previous item the same way, and Down and Up are left to the row. | | Home, End | Moves to the first or the last item. | | Page Down, Page Up | Moves by the number of items, or of lines in a grid, on screen. | | A letter or a word | Moves to the next item whose text starts with what you typed. | | Escape | Lets go of every chosen item, in a list with 'selection-mode'. | | Tab | Moves into the focused row's own links and buttons, then out of the list. | An item that is not drawn is scrolled into view and focused, so a keyboard reaches the whole set. When the row holding the tab stop scrolls away, the stop moves to the first row on screen. Typing matches each item's 'text-field', which is the first 'data-field' of the row template by default, or the item itself when it is a string or a number. Each row says its place in the whole set with 'aria-posinset' and 'aria-setsize', so a screen reader says "4,000 of 10,000". The row holding focus stays drawn when it scrolls out. **Selecting.** 'selection-mode' makes the list a list box a reader chooses from: 'single' selects one item and 'multiple' any number. Space or a press selects an item, Shift with Space, an arrow, Home, End or a press takes in the items from the last one chosen, and Control or Command with A selects them all, in 'multiple'. Escape lets go of every chosen item, and keeps the key from the dialog or menu around the list while there was something to let go of. 'value' holds the chosen items' keys, separated by commas, in the order of the set: 'key-field' names each item's key, and a string or a number item is its own key. A change asks with 'helix-before-change' and tells with 'change'. Each row is an 'option' marked 'aria-selected', so a row's own links and buttons are not reached there: keep those to a list without 'selection-mode'. 'selection-behavior="replace"' selects the item pressed alone, as a file list does, and the arrow keys carry the selection with them. Control or Command with a press or with Space adds or takes out one item, and with an arrow moves without selecting. **Disabled items.** 'disabled-keys' names items by their keys, separated by commas. Their rows carry 'aria-disabled', the keys and typing pass over them, and a press, Space, or Control with A does not select them. **Rows a stylesheet can tell apart.** A chosen row carries 'data-selected', a disabled one 'data-disabled', as React Aria's rows do, and the row the keys are on, which holds the tab stop, 'data-active', whether or not the list has focus. **Loading more.** 'helix-range-change' fires as the items on screen change, and 'range' holds them. 'helix-load-more' fires once a reader is within one screen of the end, once for each length of the set: add to 'items' and it can fire again. While you fetch, set 'loading': the list is busy, and a row after the last item says "Loading more" ('loading-label', or your own content in the 'loading' slot). 'scrollToIndex' takes a reader to an item. **An empty list.** Set 'empty-label', or put your own content in the 'empty' slot, for a row shown when there are no items and none are loading, such as "No messages yet" and a link to write one. Without either, an empty list shows nothing, since a list whose items have not arrived yet has not said it has none. The list takes the 'empty' state while it has read its items and holds none, and the 'loading' state while 'loading' is set, so your stylesheet can change the box around it for either. A list with no name is reported once in a development build. Name it with 'label' or 'aria-label'. **Row height.** Rows are placed by 'estimate' until they are drawn. Then the list reads the drawn rows' height once and places every row by it, so a wrong estimate still reaches the last item. Set 'measured' for rows of different heights. Once the list draws rows of different heights, such as rows that wrap on a narrow screen, it places each row by its own height whether 'measured' is set or not. The list follows its source. A new 'items' array, an edit to the script's text, or a script replaced under the same id draws the new rows. A row that stays in view keeps its element as the list scrolls. The viewport scrolls on this tier. It carries 'data-scroller', and 'core' ships '[data-scroller] { overflow: auto }' into every shadow root, so 'scrollTop' works with no stylesheet. You still need to set a block size. */
|
|
19762
19845
|
"helix-headless-virtual-list": DefineCustomElement<
|
|
19763
19846
|
HelixHeadlessVirtualList,
|
|
19764
19847
|
HelixHeadlessVirtualListVueProps,
|
package/types/words.d.ts
CHANGED
|
@@ -1544,6 +1544,12 @@ declare module '@fusion.dev/helix-core' {
|
|
|
1544
1544
|
* English: `Show all`
|
|
1545
1545
|
*/
|
|
1546
1546
|
expandLabel: Message
|
|
1547
|
+
/**
|
|
1548
|
+
* Text the panel shows while the suggestions load.
|
|
1549
|
+
*
|
|
1550
|
+
* English: `Loading`
|
|
1551
|
+
*/
|
|
1552
|
+
loadingText: Message
|
|
1547
1553
|
/**
|
|
1548
1554
|
* The count of the tokens past `max-tags`, as it is shown, with `{count}`
|
|
1549
1555
|
* for the number, written in the element's locale.
|
|
@@ -2457,13 +2463,17 @@ declare module '@fusion.dev/helix-core' {
|
|
|
2457
2463
|
*/
|
|
2458
2464
|
badInputMessage: Message
|
|
2459
2465
|
/**
|
|
2460
|
-
* The name of the step down button, read by screen readers.
|
|
2466
|
+
* The name of the step down button, read by screen readers. The field's
|
|
2467
|
+
* label follows it, so a reader hears "Decrease Quantity", as React Aria
|
|
2468
|
+
* names its steppers.
|
|
2461
2469
|
*
|
|
2462
2470
|
* English: `Decrease`
|
|
2463
2471
|
*/
|
|
2464
2472
|
decrementLabel: Message
|
|
2465
2473
|
/**
|
|
2466
|
-
* The name of the step up button, read by screen readers.
|
|
2474
|
+
* The name of the step up button, read by screen readers. The field's
|
|
2475
|
+
* label follows it, so a reader hears "Increase Quantity", as React Aria
|
|
2476
|
+
* names its steppers.
|
|
2467
2477
|
*
|
|
2468
2478
|
* English: `Increase`
|
|
2469
2479
|
*/
|