@fusion.dev/helix-headless 0.155.0 → 0.157.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 +2695 -137
- package/dist/canvas/node/canvas-node.js +1 -1
- package/dist/canvas/root/canvas-root.d.ts +17 -2
- package/dist/canvas/root/canvas-root.js +23 -6
- package/dist/chat/composer/chat-composer.js +1 -1
- package/dist/chat/root/chat-root.d.ts +14 -1
- package/dist/chat/root/chat-root.js +14 -4
- package/dist/combobox/root/combobox-root.d.ts +10 -0
- package/dist/combobox/root/combobox-root.js +18 -3
- package/dist/command/root/command-root.d.ts +116 -1
- package/dist/command/root/command-root.js +124 -15
- package/dist/data-table/root/data-table-root.d.ts +25 -0
- package/dist/data-table/root/data-table-root.js +13 -3
- package/dist/date-input/root/date-input-root.d.ts +32 -1
- package/dist/date-input/root/date-input-root.js +7 -1
- package/dist/drilldown/item/drilldown-item.d.ts +49 -1
- package/dist/drilldown/item/drilldown-item.js +77 -17
- package/dist/drilldown/root/drilldown-root.d.ts +45 -5
- package/dist/drilldown/root/drilldown-root.js +51 -5
- package/dist/element-events.generated.js +2 -1
- package/dist/filter-input/menu/filter-menu.d.ts +1 -0
- package/dist/filter-input/menu/filter-menu.js +4 -4
- package/dist/graph/root/graph-root.d.ts +13 -0
- package/dist/graph/root/graph-root.js +16 -0
- package/dist/list/root/list-root.d.ts +74 -1
- package/dist/list/root/list-root.js +92 -4
- package/dist/list/selection.js +3 -3
- package/dist/map/root/map-root.d.ts +6 -0
- package/dist/map/root/map-root.js +8 -1
- package/dist/megamenu/root/megamenu-root.d.ts +50 -13
- package/dist/megamenu/root/megamenu-root.js +44 -6
- package/dist/menu/item/menu-item.d.ts +24 -1
- package/dist/menu/item/menu-item.js +42 -2
- package/dist/menu/root/menu-root.d.ts +120 -9
- package/dist/menu/root/menu-root.js +329 -26
- package/dist/notifications/root/notifications-root.d.ts +20 -0
- package/dist/notifications/root/notifications-root.js +32 -1
- package/dist/number-input/root/number-input-root.d.ts +63 -6
- package/dist/number-input/root/number-input-root.js +96 -11
- package/dist/object-inspector/root/object-inspector-root.d.ts +36 -1
- package/dist/object-inspector/root/object-inspector-root.js +26 -2
- package/dist/option/root/option-root.d.ts +32 -0
- package/dist/option/root/option-root.js +44 -5
- package/dist/outline/root/outline-root.d.ts +6 -2
- package/dist/outline/root/outline-root.js +7 -3
- package/dist/table/root/table-root.d.ts +20 -0
- package/dist/table/root/table-root.js +13 -3
- package/dist/time-input/root/time-input-root.d.ts +32 -1
- package/dist/time-input/root/time-input-root.js +9 -2
- package/dist/time-picker/root/time-picker-root.d.ts +63 -1
- package/dist/time-picker/root/time-picker-root.js +58 -7
- package/dist/timeline/item/timeline-item.d.ts +25 -0
- package/dist/timeline/item/timeline-item.js +27 -2
- package/dist/toast/item/toast-item.d.ts +26 -0
- package/dist/toast/item/toast-item.js +55 -3
- package/dist/toast/root/toast-root.d.ts +32 -0
- package/dist/toast/root/toast-root.js +47 -2
- package/dist/video/root/keys.d.ts +6 -2
- package/dist/video/root/keys.js +18 -1
- package/dist/video/root/video-root.d.ts +61 -1
- package/dist/video/root/video-root.js +79 -11
- package/dist/video-playlist/item/video-playlist-item.d.ts +15 -1
- package/dist/video-playlist/item/video-playlist-item.js +7 -0
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +1 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +1 -1
- package/dist/video-playlist/root/video-playlist-root.d.ts +43 -4
- package/dist/video-playlist/root/video-playlist-root.js +69 -2
- package/dist/virtual-list/root/virtual-list-root.d.ts +8 -0
- package/dist/virtual-list/root/virtual-list-root.js +3 -0
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +3346 -266
- package/types/vue.d.ts +910 -66
- package/types/words.d.ts +124 -0
|
@@ -96,6 +96,11 @@ declare const HelixHeadlessTable_base: (new (...args: any[]) => import("@fusion.
|
|
|
96
96
|
* | A letter or a word | Moves to the next row whose first cell starts with what you typed. |
|
|
97
97
|
* | Tab | Leaves the table. |
|
|
98
98
|
*
|
|
99
|
+
* When the rows did not load, set `error-text`, such as "The orders did not
|
|
100
|
+
* load", and put a button that tries again in the `error` slot. The line shows
|
|
101
|
+
* after the rows in place of the empty and loading lines, the live region says
|
|
102
|
+
* it, and the table takes the `error` state. Clear it once you try again.
|
|
103
|
+
*
|
|
99
104
|
* The CSS custom properties listed for this component are written by it and
|
|
100
105
|
* read by the stylesheet that draws it. Do not set them. Each holds a number
|
|
101
106
|
* the component computes and CSS cannot, so the stylesheet can draw the table
|
|
@@ -109,6 +114,7 @@ declare const HelixHeadlessTable_base: (new (...args: any[]) => import("@fusion.
|
|
|
109
114
|
*
|
|
110
115
|
* @slot - The table's rows.
|
|
111
116
|
* @slot empty - Content shown when there are no rows and none are loading, such as a picture and a link. Falls back to `empty-text`, which the live region still says.
|
|
117
|
+
* @slot error - Content shown while `error-text` is set, such as a button that tries again. Falls back to `error-text`, which the live region still says.
|
|
112
118
|
* @slot heading - Words that name the table, shown above it, such as a heading.
|
|
113
119
|
* @slot loading - Content shown while the rows load, such as a spinner. Falls back to `loading-text`, which the live region still says.
|
|
114
120
|
*
|
|
@@ -132,6 +138,7 @@ declare const HelixHeadlessTable_base: (new (...args: any[]) => import("@fusion.
|
|
|
132
138
|
* @csspart checkbox-mark-indeterminate - Added to `checkbox-mark` while only some rows are selected.
|
|
133
139
|
* @csspart drag-preview - A copy of the row a pointer drags by its grip, which follows the pointer in the top layer until the row is let go, in a `reorderable` table. Hidden from assistive technology.
|
|
134
140
|
* @csspart empty - The text shown when there are no rows.
|
|
141
|
+
* @csspart error - The line shown after the rows while `error-text` is set, in place of the empty and loading text.
|
|
135
142
|
* @csspart grid-end - An empty box after the rows, in a `grid` table. Tab focuses it on its way out of the table, so the key leaves from the end.
|
|
136
143
|
* @csspart grid-start - An empty box before the rows, in a `grid` table. Shift with Tab focuses it on its way out of the table.
|
|
137
144
|
* @csspart grip-head - The heading over the row grips, in a `reorderable` table.
|
|
@@ -142,6 +149,9 @@ declare const HelixHeadlessTable_base: (new (...args: any[]) => import("@fusion.
|
|
|
142
149
|
* @csspart table - The grid.
|
|
143
150
|
*
|
|
144
151
|
* @cssproperty --table-template - The column track list the table works out from its columns. The component writes it inline on the element that reads it, so setting it has no effect. Set `columns` to change the tracks.
|
|
152
|
+
*
|
|
153
|
+
* @cssstate empty - While there are no rows and none are loading.
|
|
154
|
+
* @cssstate error - While `error-text` is set.
|
|
145
155
|
*/
|
|
146
156
|
export declare class HelixHeadlessTable extends HelixHeadlessTable_base {
|
|
147
157
|
/**
|
|
@@ -214,6 +224,16 @@ export declare class HelixHeadlessTable extends HelixHeadlessTable_base {
|
|
|
214
224
|
descendingLabel: string;
|
|
215
225
|
/** What screen readers hear when a held row is dropped, in a `reorderable` table. */
|
|
216
226
|
droppedLabel: string;
|
|
227
|
+
/**
|
|
228
|
+
* The text shown and announced when the rows could not load. Set it when a
|
|
229
|
+
* fetch fails, and clear it once you try again. Empty, the default, shows
|
|
230
|
+
* nothing.
|
|
231
|
+
*
|
|
232
|
+
* While it is set, a line after the rows shows it, or your own content in the
|
|
233
|
+
* `error` slot, in place of the empty and loading lines, and the live region
|
|
234
|
+
* says it.
|
|
235
|
+
*/
|
|
236
|
+
errorText: string;
|
|
217
237
|
/**
|
|
218
238
|
* The table's name where neither `label` nor an `aria-label` or
|
|
219
239
|
* `aria-labelledby` on the host gives it one.
|
|
@@ -44,7 +44,7 @@ const SAMPLE = 200;
|
|
|
44
44
|
const textOf = (element) => (element?.textContent ?? '').replace(/\s+/g, ' ').trim();
|
|
45
45
|
const lengthOf = (element) => textOf(element).length;
|
|
46
46
|
const numberOf = (value) => Number(value.replaceAll(',', ''));
|
|
47
|
-
const STATUS = new Set(['empty', 'loading']);
|
|
47
|
+
const STATUS = new Set(['empty', 'error', 'loading']);
|
|
48
48
|
const NAMED = new Set([...STATUS, 'heading']);
|
|
49
49
|
let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixElement) {
|
|
50
50
|
constructor() {
|
|
@@ -57,6 +57,7 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
|
|
|
57
57
|
this.defaultSort = '';
|
|
58
58
|
this.descendingLabel = 'descending';
|
|
59
59
|
this.droppedLabel = 'Dropped';
|
|
60
|
+
this.errorText = '';
|
|
60
61
|
this.fallbackLabel = 'Table';
|
|
61
62
|
this.grid = false;
|
|
62
63
|
this.label = '';
|
|
@@ -496,6 +497,8 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
|
|
|
496
497
|
}
|
|
497
498
|
updated(changed) {
|
|
498
499
|
super.updated(changed);
|
|
500
|
+
this.toggleState('error', this.errorText !== '');
|
|
501
|
+
this.toggleState('empty', !this.loading && !this.hasRows);
|
|
499
502
|
this.assign();
|
|
500
503
|
this.alignCells();
|
|
501
504
|
this.markSorted();
|
|
@@ -561,8 +564,12 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
|
|
|
561
564
|
this.handleSlotChange();
|
|
562
565
|
}}
|
|
563
566
|
></slot>
|
|
564
|
-
${this.
|
|
565
|
-
|
|
567
|
+
${this.errorText === ''
|
|
568
|
+
? this.renderStatus(this.hasRows, grid ? 'gridcell' : 'cell')
|
|
569
|
+
: html `<p part="error" role="row"><span role=${grid ? 'gridcell' : 'cell'}><slot name="error">${this.errorText}</slot></span></p>`}
|
|
570
|
+
</div>${end}${this.errorText === ''
|
|
571
|
+
? this.renderLive(this.hasRows)
|
|
572
|
+
: html `<span part="live" role="status">${this.errorText}</span>`}${this.reorder.drawDragPreview()}`;
|
|
566
573
|
}
|
|
567
574
|
};
|
|
568
575
|
__decorate([
|
|
@@ -590,6 +597,9 @@ __decorate([
|
|
|
590
597
|
words,
|
|
591
598
|
property({ attribute: 'dropped-label' })
|
|
592
599
|
], HelixHeadlessTable.prototype, "droppedLabel", void 0);
|
|
600
|
+
__decorate([
|
|
601
|
+
property({ attribute: 'error-text' })
|
|
602
|
+
], HelixHeadlessTable.prototype, "errorText", void 0);
|
|
593
603
|
__decorate([
|
|
594
604
|
words,
|
|
595
605
|
property({ attribute: 'fallback-label' })
|
|
@@ -34,17 +34,41 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
|
|
|
34
34
|
* hour, a minute, and AM or PM where the clock has them, each set with digits
|
|
35
35
|
* or the arrow keys. Alt+Down opens the list from a segment.
|
|
36
36
|
*
|
|
37
|
+
* Text that is not a time gives the form an empty value, as a native time
|
|
38
|
+
* field does, and `value` keeps the text so it can be corrected.
|
|
39
|
+
*
|
|
40
|
+
* **Keyboard.** The field is one tab stop, or each segment is with
|
|
41
|
+
* `segmented`, and the trigger is one more.
|
|
42
|
+
*
|
|
43
|
+
* | Key | What it does |
|
|
44
|
+
* |---|---|
|
|
45
|
+
* | Down | In the text field, opens the list on the chosen time. |
|
|
46
|
+
* | Alt with Down | Opens the list, from the text field or a segment. |
|
|
47
|
+
* | Enter | In the text field, takes the typed time and submits the form, as a native field does. In the list, chooses the highlighted time. |
|
|
48
|
+
* | Escape | Closes the list and puts focus back in the field. |
|
|
49
|
+
* | Up, Down on a segment | Steps the segment by one, round from its last value to its first. |
|
|
50
|
+
* | Page Up, Page Down on a segment | Steps by a page: two hours, or fifteen minutes or seconds. |
|
|
51
|
+
* | Home, End on a segment | Goes to the segment's first or last value. |
|
|
52
|
+
* | Digits on a segment | Fill it, and move to the next once it can take no more. |
|
|
53
|
+
* | A letter on the half of the day | Picks the half whose name starts with it, such as A for AM. |
|
|
54
|
+
* | Backspace, Delete on a segment | Empty the segment. |
|
|
55
|
+
* | Left, Right on a segment | Move to the previous or the next segment, along the line of text. |
|
|
56
|
+
*
|
|
57
|
+
* In the list, the keys are `TimePicker`'s.
|
|
58
|
+
*
|
|
37
59
|
* @since 0.1.0
|
|
38
60
|
* @status stable
|
|
39
61
|
* @category forms
|
|
40
62
|
* @aliases TimeField, InputTime
|
|
41
63
|
* @documentation https://fusion.dev/helix/components/time-input
|
|
42
64
|
*
|
|
65
|
+
* @slot end - Content after the time, before the trigger, such as a clear button.
|
|
43
66
|
* @slot feedback - The message that says what is wrong with the value.
|
|
44
67
|
* @slot hint - Help under the field.
|
|
45
68
|
* @slot label - The label, for content richer than the `label` text.
|
|
46
69
|
* @slot panel-footer - Content in the panel under the times, such as a note or an action.
|
|
47
70
|
* @slot panel-header - Content in the panel above the times, such as a heading or a shortcut.
|
|
71
|
+
* @slot start - Content before the time, such as an icon.
|
|
48
72
|
* @slot trigger - The icon on the field that shows a list opens.
|
|
49
73
|
*
|
|
50
74
|
* @event {Event} change - Fired after the value changes.
|
|
@@ -76,6 +100,8 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
|
|
|
76
100
|
* @csspart picker-column-search-field - The filter field.
|
|
77
101
|
* @csspart picker-columns - The row of columns, in `wheels`.
|
|
78
102
|
* @csspart picker-feedback - The picker's own message, under the times, while the picker's `feedback` is set.
|
|
103
|
+
* @csspart picker-hint - The picker's hint, which Time Input never sets: help under the field is the field's own `hint`.
|
|
104
|
+
* @csspart picker-label - The picker's visible label, which Time Input never draws: the field's `label` names it.
|
|
79
105
|
* @csspart picker-list - The listbox holding the times, in `list`.
|
|
80
106
|
* @csspart picker-list-empty - The text shown when the filter hides every option.
|
|
81
107
|
* @csspart picker-list-error - The list's `error` part, which the list never sets: its times do not load.
|
|
@@ -283,7 +309,12 @@ export declare class HelixHeadlessTimeInput extends HelixHeadlessTimeInput_base
|
|
|
283
309
|
* what says the reader is done.
|
|
284
310
|
*/
|
|
285
311
|
private readonly handleWheelEnter;
|
|
286
|
-
/**
|
|
312
|
+
/**
|
|
313
|
+
* Each time, where `mode` holds several, sent one entry each.
|
|
314
|
+
*
|
|
315
|
+
* One time that is text and no time, such as `2:45 P`, is sent as an empty
|
|
316
|
+
* entry, as a native time field sends a time it cannot read.
|
|
317
|
+
*/
|
|
287
318
|
protected get answers(): readonly string[] | undefined;
|
|
288
319
|
/** What is wrong with the times, which the text input cannot say. */
|
|
289
320
|
protected validate(): string | readonly [keyof ValidityStateFlags, string];
|
|
@@ -146,7 +146,11 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
146
146
|
return held.length > 0 && held.every((one) => this.isTime(one)) ? held.join(',') : '';
|
|
147
147
|
}
|
|
148
148
|
get answers() {
|
|
149
|
-
|
|
149
|
+
if (this.mode !== undefined) {
|
|
150
|
+
return this.held;
|
|
151
|
+
}
|
|
152
|
+
const text = this.value.trim();
|
|
153
|
+
return text === '' || this.isTime(text) ? undefined : [''];
|
|
150
154
|
}
|
|
151
155
|
validate() {
|
|
152
156
|
const held = this.held;
|
|
@@ -197,7 +201,8 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
197
201
|
column-filter-mark: picker-column-filter-mark, column-hint: picker-column-hint,
|
|
198
202
|
column-items: picker-column-items, column-label: picker-column-label,
|
|
199
203
|
column-live: picker-column-live, column-loading: picker-column-loading, column-search: picker-column-search,
|
|
200
|
-
column-search-field: picker-column-search-field, columns: picker-columns, feedback: picker-feedback,
|
|
204
|
+
column-search-field: picker-column-search-field, columns: picker-columns, feedback: picker-feedback, hint: picker-hint,
|
|
205
|
+
label: picker-label, list: picker-list,
|
|
201
206
|
list-empty: picker-list-empty, list-error: picker-list-error, list-feedback: picker-list-feedback,
|
|
202
207
|
list-filter-icon: picker-list-filter-icon, list-filter-mark: picker-list-filter-mark,
|
|
203
208
|
list-hint: picker-list-hint, list-items: picker-list-items, list-label: picker-list-label,
|
|
@@ -269,10 +274,12 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
269
274
|
render() {
|
|
270
275
|
return html `${this.renderLabel()}
|
|
271
276
|
<div part="field" @keydown=${this.handleKeydown}>
|
|
277
|
+
<slot name="start"></slot>
|
|
272
278
|
${this.mode === 'multiple'
|
|
273
279
|
? this.renderTokenRow(this.shownTimes.map((at) => this.renderTag(at)), this.restCount)
|
|
274
280
|
: nothing}
|
|
275
281
|
${this.segmentsShown ? this.renderSegments() : this.renderControl()}
|
|
282
|
+
<slot name="end"></slot>
|
|
276
283
|
<button
|
|
277
284
|
part="trigger"
|
|
278
285
|
type="button"
|
|
@@ -35,12 +35,37 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
|
|
|
35
35
|
* its choice in markup for the same reason. The list and the wheels both do
|
|
36
36
|
* this, because each wheel is also a listbox.
|
|
37
37
|
*
|
|
38
|
+
* **Keyboard.** The list is one tab stop, and each wheel is one.
|
|
39
|
+
*
|
|
40
|
+
* | Key | What it does |
|
|
41
|
+
* |---|---|
|
|
42
|
+
* | Down, Up | Moves to the next or the previous time, or in a wheel to the next or the previous hour, minute, second, or half of the day. |
|
|
43
|
+
* | Home, End | Moves to the first or the last time, or the first or the last in a wheel. |
|
|
44
|
+
* | Page Down, Page Up | Moves by as many times as the list shows at once. |
|
|
45
|
+
* | Digits | Moves to the next time that starts with what you typed, such as `9` for 9:00. |
|
|
46
|
+
* | Enter, Space | Chooses the highlighted time. Moving chooses too, except under `manual` or with a `mode`. With a `mode`, Space adds or removes the time. |
|
|
47
|
+
* | Right, Left | In the wheels, moves to the next or the previous wheel, mirrored right to left. |
|
|
48
|
+
* | Tab | Moves to the next wheel, then out of the picker. |
|
|
49
|
+
*
|
|
50
|
+
* **ARIA.** The list is a `listbox` named by `label`, a slotted label, the
|
|
51
|
+
* host's `aria-label` or its `aria-labelledby`. A development build warns
|
|
52
|
+
* where all four are empty. The list is described by the hint, or by the
|
|
53
|
+
* message in `feedback` in its place, and carries `aria-multiselectable` with
|
|
54
|
+
* a `mode` and `aria-invalid` while `feedback` says what is wrong. The wheels
|
|
55
|
+
* are a `group` with that name, holding one `listbox` per wheel, named "Hour",
|
|
56
|
+
* "Minute", "Second" and "AM/PM" in the page's language, and each described
|
|
57
|
+
* the same way.
|
|
58
|
+
*
|
|
38
59
|
* @since 0.1.0
|
|
39
60
|
* @status stable
|
|
40
61
|
* @category forms
|
|
41
62
|
* @aliases Time, TimeList
|
|
42
63
|
* @documentation https://fusion.dev/helix/components/time-picker
|
|
43
64
|
*
|
|
65
|
+
* @slot empty - What the list shows when no time falls between `min` and `max`, for content richer than `empty-text`.
|
|
66
|
+
* @slot hint - Help under the times, for content richer than the `hint` text.
|
|
67
|
+
* @slot label - A visible label above the times, which names the list, for content richer than the `label` text.
|
|
68
|
+
*
|
|
44
69
|
* @event {Event} change - Fired after the value changes.
|
|
45
70
|
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before the time changes, and cancelable. Canceling it keeps the current time.
|
|
46
71
|
* @event {Event} input - Fired after the value changes.
|
|
@@ -60,6 +85,8 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
|
|
|
60
85
|
* @csspart column-search-field - The filter field.
|
|
61
86
|
* @csspart columns - The row of columns, in `wheels`.
|
|
62
87
|
* @csspart feedback - The message under the times, while `feedback` is set.
|
|
88
|
+
* @csspart hint - Help under the times, shown while there is no message in `feedback`.
|
|
89
|
+
* @csspart label - The visible label above the times, drawn while a label is slotted.
|
|
63
90
|
* @csspart list - The listbox holding the times, in `list`.
|
|
64
91
|
* @csspart list-empty - The text shown when the filter hides every option.
|
|
65
92
|
* @csspart list-error - The list's `error` part, which Time Picker never sets: its times do not load.
|
|
@@ -115,6 +142,19 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
|
|
|
115
142
|
* reached honestly rather than by handing over an empty range.
|
|
116
143
|
*/
|
|
117
144
|
disableTimes: string;
|
|
145
|
+
/**
|
|
146
|
+
* What the list says when no time falls between `min` and `max`.
|
|
147
|
+
*
|
|
148
|
+
* The fallback of the `empty` slot.
|
|
149
|
+
*/
|
|
150
|
+
emptyText: string;
|
|
151
|
+
/**
|
|
152
|
+
* Help under the times, such as the hours a shop is open, read by screen
|
|
153
|
+
* readers as the list's description. A message in `feedback` replaces it.
|
|
154
|
+
*
|
|
155
|
+
* The fallback of the `hint` slot.
|
|
156
|
+
*/
|
|
157
|
+
hint: string;
|
|
118
158
|
/**
|
|
119
159
|
* The clock the times are written on: `h12` for twelve hours with a
|
|
120
160
|
* meridiem, `h23` for twenty-four.
|
|
@@ -134,7 +174,8 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
|
|
|
134
174
|
/**
|
|
135
175
|
* Accessible name for the list, which has no visible one of its own.
|
|
136
176
|
*
|
|
137
|
-
* An `aria-label` or `aria-labelledby` on the host names the list instead
|
|
177
|
+
* An `aria-label` or `aria-labelledby` on the host names the list instead,
|
|
178
|
+
* and so does a label slotted into `label`, which is also drawn above it.
|
|
138
179
|
*/
|
|
139
180
|
label: string;
|
|
140
181
|
/**
|
|
@@ -473,6 +514,26 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
|
|
|
473
514
|
* aria-label="Slot">` was a listbox named "Time".
|
|
474
515
|
*/
|
|
475
516
|
private get listName();
|
|
517
|
+
/** Whether a hint is slotted, which draws the `hint` part around it. */
|
|
518
|
+
private hintSlotted;
|
|
519
|
+
/** Whether the hint shows: there is one, and no message stands in its place. */
|
|
520
|
+
private get hinted();
|
|
521
|
+
/** The ids that describe each list: the hint, or the message in its place. */
|
|
522
|
+
private get describedBy();
|
|
523
|
+
/**
|
|
524
|
+
* The hint under the times, or a bare slot while there is none to show,
|
|
525
|
+
* hidden while a message stands in its place, so a slotted hint goes too.
|
|
526
|
+
*/
|
|
527
|
+
private renderHint;
|
|
528
|
+
/** Whether a label is slotted, which draws the `label` part around it. */
|
|
529
|
+
private labelSlotted;
|
|
530
|
+
/** Reads the `label` slot, and the list's name again with it. */
|
|
531
|
+
private readonly handleLabelSlot;
|
|
532
|
+
/**
|
|
533
|
+
* The slotted label, in the `label` part, above the times. A bare slot while
|
|
534
|
+
* nothing is slotted, which draws no box.
|
|
535
|
+
*/
|
|
536
|
+
private renderSlottedLabel;
|
|
476
537
|
/**
|
|
477
538
|
* Hears the host's `aria-label` and `aria-labelledby` change, which no
|
|
478
539
|
* property reports. Made on connection, there being no `MutationObserver` on
|
|
@@ -482,6 +543,7 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
|
|
|
482
543
|
connectedCallback(): void;
|
|
483
544
|
disconnectedCallback(): void;
|
|
484
545
|
protected willUpdate(changed: PropertyValues): void;
|
|
546
|
+
protected firstUpdated(changed: PropertyValues): void;
|
|
485
547
|
protected updated(changed: PropertyValues): void;
|
|
486
548
|
/**
|
|
487
549
|
* Moves focus to the list, or to the first wheel.
|
|
@@ -4,9 +4,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { clockLocale, commaList, customElement, dayPeriod, formatWords, HelixFormElement, hostWords, inlineStep, isTwelveHour, MixinControllerValue, MixinPickerFeedback, nearestTime, offeredTimes, reportValues, secondsAsValue, timeBarred, timeFault, valueAsSeconds, wheelParts, wholeHour, words, wordsLocale, writeClock, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { auditName, clockLocale, commaList, customElement, dayPeriod, formatWords, HelixFormElement, hostWords, inlineStep, isTwelveHour, MixinControllerValue, MixinPickerFeedback, nearestTime, offeredTimes, reportValues, secondsAsValue, slotFilled, slottedWords, timeBarred, timeFault, valueAsSeconds, wheelParts, wholeHour, words, wordsLocale, writeClock, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { nothing } from 'lit';
|
|
9
|
-
import { property } from 'lit/decorators.js';
|
|
9
|
+
import { property, state } from 'lit/decorators.js';
|
|
10
10
|
import { html } from 'lit/static-html.js';
|
|
11
11
|
import { wheelName } from '../wheel-name.js';
|
|
12
12
|
import '../../listbox/index.js';
|
|
@@ -16,6 +16,8 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
16
16
|
super(...arguments);
|
|
17
17
|
this.badInputMessage = '{mode, select, single {Enter a time as {shape}.} other {Enter times as {shape}, separated by commas.}}';
|
|
18
18
|
this.disableTimes = '';
|
|
19
|
+
this.emptyText = 'No times to choose from';
|
|
20
|
+
this.hint = '';
|
|
19
21
|
this.label = 'Time';
|
|
20
22
|
this.locale = '';
|
|
21
23
|
this.manual = false;
|
|
@@ -83,6 +85,12 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
83
85
|
this.unavailableMessage = 'Choose a time that is available.';
|
|
84
86
|
this.valueMissingMessage = 'Choose a time.';
|
|
85
87
|
this.listRevealed = false;
|
|
88
|
+
this.hintSlotted = false;
|
|
89
|
+
this.labelSlotted = false;
|
|
90
|
+
this.handleLabelSlot = (event) => {
|
|
91
|
+
this.labelSlotted = slotFilled(event.target);
|
|
92
|
+
this.requestUpdate();
|
|
93
|
+
};
|
|
86
94
|
this.naming = undefined;
|
|
87
95
|
this.handleColumnsKeydown = (event) => {
|
|
88
96
|
const step = inlineStep(this, event.key);
|
|
@@ -247,7 +255,27 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
247
255
|
this.reveal();
|
|
248
256
|
}
|
|
249
257
|
get listName() {
|
|
250
|
-
|
|
258
|
+
const slotted = this.labelSlotted ? slottedWords(this, ['label']) : '';
|
|
259
|
+
return hostWords(this, slotted || this.label);
|
|
260
|
+
}
|
|
261
|
+
get hinted() {
|
|
262
|
+
return (this.hint !== '' || this.hintSlotted) && this.feedback === '';
|
|
263
|
+
}
|
|
264
|
+
get describedBy() {
|
|
265
|
+
return this.feedback !== '' ? 'feedback' : this.hinted ? 'hint' : nothing;
|
|
266
|
+
}
|
|
267
|
+
renderHint() {
|
|
268
|
+
const read = (event) => {
|
|
269
|
+
this.hintSlotted = slotFilled(event.target);
|
|
270
|
+
};
|
|
271
|
+
return this.hinted
|
|
272
|
+
? html `<p part="hint" id="hint"><slot name="hint" @slotchange=${read}>${this.hint}</slot></p>`
|
|
273
|
+
: html `<slot name="hint" ?hidden=${this.feedback !== ''} @slotchange=${read}></slot>`;
|
|
274
|
+
}
|
|
275
|
+
renderSlottedLabel() {
|
|
276
|
+
return this.labelSlotted
|
|
277
|
+
? html `<div part="label"><slot name="label" @slotchange=${this.handleLabelSlot}></slot></div>`
|
|
278
|
+
: html `<slot name="label" @slotchange=${this.handleLabelSlot}></slot>`;
|
|
251
279
|
}
|
|
252
280
|
connectedCallback() {
|
|
253
281
|
super.connectedCallback();
|
|
@@ -264,6 +292,14 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
264
292
|
this.report();
|
|
265
293
|
this.toggleState('blank', this.value === '');
|
|
266
294
|
}
|
|
295
|
+
firstUpdated(changed) {
|
|
296
|
+
super.firstUpdated(changed);
|
|
297
|
+
auditName(this, () => null, 'Give it a `label`, a label in the `label` slot, or an `aria-label` that says what the time is for.', () => this.listName !== '');
|
|
298
|
+
const list = this.partNamed('list');
|
|
299
|
+
if (list) {
|
|
300
|
+
auditName(list, () => null, '', () => true);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
267
303
|
updated(changed) {
|
|
268
304
|
super.updated(changed);
|
|
269
305
|
this.reportRequired();
|
|
@@ -284,7 +320,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
284
320
|
return html `<${this.tag('listbox')}
|
|
285
321
|
part="column"
|
|
286
322
|
data-column=${part}
|
|
287
|
-
aria-describedby=${this.
|
|
323
|
+
aria-describedby=${this.describedBy}
|
|
288
324
|
aria-invalid=${this.marked ? 'true' : nothing}
|
|
289
325
|
exportparts="empty: column-empty, error: column-error, feedback: column-feedback, filter-icon: column-filter-icon,
|
|
290
326
|
filter-mark: column-filter-mark, hint: column-hint, items: column-items, label: column-label,
|
|
@@ -336,7 +372,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
336
372
|
renderList() {
|
|
337
373
|
return html `<${this.tag('listbox')}
|
|
338
374
|
part="list"
|
|
339
|
-
aria-describedby=${this.
|
|
375
|
+
aria-describedby=${this.describedBy}
|
|
340
376
|
aria-invalid=${this.marked ? 'true' : nothing}
|
|
341
377
|
exportparts="empty: list-empty, error: list-error, feedback: list-feedback, filter-icon: list-filter-icon,
|
|
342
378
|
filter-mark: list-filter-mark, hint: list-hint, items: list-items, label: list-label,
|
|
@@ -344,6 +380,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
344
380
|
aria-label=${this.listName}
|
|
345
381
|
data-unset=${this.value === '' ? '' : nothing}
|
|
346
382
|
?disabled=${this.isDisabled}
|
|
383
|
+
empty-text=${this.emptyText}
|
|
347
384
|
?manual=${this.manual}
|
|
348
385
|
?multiple=${this.mode !== undefined}
|
|
349
386
|
.value=${this.value}
|
|
@@ -365,13 +402,14 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
365
402
|
>${writeClock(at, this.clock, this.seconds)}</${this.tag('option')}
|
|
366
403
|
>`;
|
|
367
404
|
})}
|
|
405
|
+
<slot name="empty" slot="empty">${this.emptyText}</slot>
|
|
368
406
|
</${this.tag('listbox')}>`;
|
|
369
407
|
}
|
|
370
408
|
render() {
|
|
371
409
|
if (this.variant === 'wheels' && this.mode === undefined) {
|
|
372
|
-
return html `${this.renderSpinner()}${this.renderPickerFeedback()}`;
|
|
410
|
+
return html `${this.renderSlottedLabel()}${this.renderSpinner()}${this.renderHint()}${this.renderPickerFeedback()}`;
|
|
373
411
|
}
|
|
374
|
-
return html `${this.renderList()}${this.renderPickerFeedback()}`;
|
|
412
|
+
return html `${this.renderSlottedLabel()}${this.renderList()}${this.renderHint()}${this.renderPickerFeedback()}`;
|
|
375
413
|
}
|
|
376
414
|
get valueAsDate() {
|
|
377
415
|
const at = valueAsSeconds(this.value);
|
|
@@ -397,6 +435,13 @@ __decorate([
|
|
|
397
435
|
__decorate([
|
|
398
436
|
property({ attribute: 'disable-times' })
|
|
399
437
|
], HelixHeadlessTimePicker.prototype, "disableTimes", void 0);
|
|
438
|
+
__decorate([
|
|
439
|
+
words,
|
|
440
|
+
property({ attribute: 'empty-text' })
|
|
441
|
+
], HelixHeadlessTimePicker.prototype, "emptyText", void 0);
|
|
442
|
+
__decorate([
|
|
443
|
+
property()
|
|
444
|
+
], HelixHeadlessTimePicker.prototype, "hint", void 0);
|
|
400
445
|
__decorate([
|
|
401
446
|
property({ attribute: 'hour-cycle' })
|
|
402
447
|
], HelixHeadlessTimePicker.prototype, "hourCycle", void 0);
|
|
@@ -466,6 +511,12 @@ __decorate([
|
|
|
466
511
|
__decorate([
|
|
467
512
|
property({ reflect: true })
|
|
468
513
|
], HelixHeadlessTimePicker.prototype, "variant", void 0);
|
|
514
|
+
__decorate([
|
|
515
|
+
state()
|
|
516
|
+
], HelixHeadlessTimePicker.prototype, "hintSlotted", void 0);
|
|
517
|
+
__decorate([
|
|
518
|
+
state()
|
|
519
|
+
], HelixHeadlessTimePicker.prototype, "labelSlotted", void 0);
|
|
469
520
|
HelixHeadlessTimePicker = __decorate([
|
|
470
521
|
customElement('helix-headless-time-picker')
|
|
471
522
|
], HelixHeadlessTimePicker);
|
|
@@ -8,6 +8,12 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
8
8
|
* machine-readable value such as "2026-08-19" travels with a label such as
|
|
9
9
|
* "yesterday". Without `datetime`, the label is a `<span>`.
|
|
10
10
|
*
|
|
11
|
+
* **`relative` writes the time for you** as how long ago it was, such as "3
|
|
12
|
+
* hours ago", from `datetime`, where the `time` slot is empty. The words move
|
|
13
|
+
* on as they go stale, "3 hours ago" becoming "4 hours ago", with one wakeup
|
|
14
|
+
* shared by every reading on the page, as `FormatDate` keeps its own. They are
|
|
15
|
+
* in the language of the page, or of the nearest `lang`.
|
|
16
|
+
*
|
|
11
17
|
* Each entry draws the connector line that arrives at it and hides it when it
|
|
12
18
|
* is the first entry, using `:host(:first-child)`. This needs no index, no
|
|
13
19
|
* counting parent, and no script. `Steps` and `Breadcrumbs` work the same way.
|
|
@@ -44,6 +50,25 @@ export declare class HelixHeadlessTimelineItem extends HelixElement {
|
|
|
44
50
|
* know what instant it names.
|
|
45
51
|
*/
|
|
46
52
|
datetime: string;
|
|
53
|
+
/**
|
|
54
|
+
* Writes the time as how long ago it was, or how long until it, from
|
|
55
|
+
* `datetime`, where the `time` slot is empty: `long` ("3 hours ago"),
|
|
56
|
+
* `short` ("3 hr. ago") or `narrow` ("3h ago"). Set with no value, it is
|
|
57
|
+
* `long`. The words move on as they go stale.
|
|
58
|
+
*/
|
|
59
|
+
relative?: 'long' | 'narrow' | 'short';
|
|
60
|
+
/** The time the reading is drawn against, moved on when the words go stale. */
|
|
61
|
+
private readonly clock;
|
|
62
|
+
/**
|
|
63
|
+
* What the `time` slot shows where nothing is slotted: the reading under
|
|
64
|
+
* `relative`, read against the clock before each render, and nothing
|
|
65
|
+
* otherwise.
|
|
66
|
+
*/
|
|
67
|
+
private reading;
|
|
68
|
+
/** The instant `datetime` names, where `relative` asks for a reading of it. */
|
|
69
|
+
private get moment();
|
|
70
|
+
/** What the reading says at `now`, and when it stops being true. */
|
|
71
|
+
private readingAt;
|
|
47
72
|
/**
|
|
48
73
|
* The kind of event. It sets the color of the mark and nothing else.
|
|
49
74
|
*/
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, HelixElement, hostAria, RelativeClockController, relativeTime, wordsLocale, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { circle, record } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { html } from 'lit';
|
|
10
10
|
import { property } from 'lit/decorators.js';
|
|
@@ -13,9 +13,31 @@ let HelixHeadlessTimelineItem = class HelixHeadlessTimelineItem extends HelixEle
|
|
|
13
13
|
constructor() {
|
|
14
14
|
super(...arguments);
|
|
15
15
|
this.datetime = '';
|
|
16
|
+
this.clock = new RelativeClockController(this, {
|
|
17
|
+
expires: (now) => {
|
|
18
|
+
const moment = this.moment;
|
|
19
|
+
return moment ? this.readingAt(moment, now).next : undefined;
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
this.reading = '';
|
|
23
|
+
}
|
|
24
|
+
get moment() {
|
|
25
|
+
if (this.relative === undefined || this.datetime === '') {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const parsed = new Date(this.datetime);
|
|
29
|
+
return Number.isNaN(parsed.getTime()) ? undefined : parsed;
|
|
30
|
+
}
|
|
31
|
+
readingAt(moment, now) {
|
|
32
|
+
return relativeTime(wordsLocale(this), { style: this.relative || 'long' })(moment, now);
|
|
16
33
|
}
|
|
17
34
|
willUpdate(changed) {
|
|
18
35
|
super.willUpdate(changed);
|
|
36
|
+
if (['datetime', 'relative'].some((key) => changed.has(key))) {
|
|
37
|
+
this.clock.tick();
|
|
38
|
+
}
|
|
39
|
+
const moment = this.moment;
|
|
40
|
+
this.reading = moment ? this.readingAt(moment, new Date(this.clock.now)).text : '';
|
|
19
41
|
hostAria(this.internals, { role: 'listitem' });
|
|
20
42
|
}
|
|
21
43
|
renderMarker() {
|
|
@@ -29,7 +51,7 @@ let HelixHeadlessTimelineItem = class HelixHeadlessTimelineItem extends HelixEle
|
|
|
29
51
|
>`;
|
|
30
52
|
}
|
|
31
53
|
render() {
|
|
32
|
-
const when = html `<slot name="time"
|
|
54
|
+
const when = html `<slot name="time">${this.reading}</slot>`;
|
|
33
55
|
return html `<div part="rail">
|
|
34
56
|
${this.renderMarker()}
|
|
35
57
|
</div>
|
|
@@ -46,6 +68,9 @@ let HelixHeadlessTimelineItem = class HelixHeadlessTimelineItem extends HelixEle
|
|
|
46
68
|
__decorate([
|
|
47
69
|
property()
|
|
48
70
|
], HelixHeadlessTimelineItem.prototype, "datetime", void 0);
|
|
71
|
+
__decorate([
|
|
72
|
+
property()
|
|
73
|
+
], HelixHeadlessTimelineItem.prototype, "relative", void 0);
|
|
49
74
|
__decorate([
|
|
50
75
|
property({ reflect: true })
|
|
51
76
|
], HelixHeadlessTimelineItem.prototype, "tone", void 0);
|
|
@@ -25,6 +25,9 @@ declare const HelixHeadlessToastItem_base: (new (...args: any[]) => import("@fus
|
|
|
25
25
|
* control. While it moves, the distance is on the `item` part as
|
|
26
26
|
* `--toast-swipe-x`.
|
|
27
27
|
*
|
|
28
|
+
* **Escape dismisses the message holding focus**, through the same
|
|
29
|
+
* `helix-dismiss`, and focus moves to the next message.
|
|
30
|
+
*
|
|
28
31
|
* **Messages are inverted by default.** The item flips `color-scheme`, so a new
|
|
29
32
|
* message stands out from the page without using a color that carries meaning.
|
|
30
33
|
*
|
|
@@ -57,6 +60,10 @@ declare const HelixHeadlessToastItem_base: (new (...args: any[]) => import("@fus
|
|
|
57
60
|
*
|
|
58
61
|
* @cssproperty --toast-duration - How long this message stays, in milliseconds, for a progress hint.
|
|
59
62
|
* @cssproperty --toast-swipe-x - How far a swipe has moved the message across, in pixels, toward the right.
|
|
63
|
+
*
|
|
64
|
+
* @cssstate closed - The message has been dismissed and is hidden, or leaving.
|
|
65
|
+
* @cssstate paused - The dismiss timer is paused, while a pointer or focus is on the message, or while the page is hidden.
|
|
66
|
+
* @cssstate waiting - The region holds the message back, past its `max-visible`, until a message before it goes.
|
|
60
67
|
*/
|
|
61
68
|
export declare class HelixHeadlessToastItem extends HelixHeadlessToastItem_base {
|
|
62
69
|
/**
|
|
@@ -110,6 +117,18 @@ export declare class HelixHeadlessToastItem extends HelixHeadlessToastItem_base
|
|
|
110
117
|
* A subset of the tone axis: a toast reports a status and never a brand role.
|
|
111
118
|
*/
|
|
112
119
|
tone?: 'danger' | 'info' | 'success' | 'warning';
|
|
120
|
+
/**
|
|
121
|
+
* Whether the region holds the message back, because more messages are
|
|
122
|
+
* showing than its `max-visible`. The region sets it. A waiting message is
|
|
123
|
+
* hidden, its timer has not started, and it is said once it shows.
|
|
124
|
+
*/
|
|
125
|
+
waiting: boolean;
|
|
126
|
+
/** Whether the dismiss timer has started, which it does once the message first shows. */
|
|
127
|
+
private started;
|
|
128
|
+
/** Whether the timer is held for `waiting`, so the hold is let go once. */
|
|
129
|
+
private holding;
|
|
130
|
+
/** Starts the timer when the message first shows, and holds it while it waits again. */
|
|
131
|
+
private wait;
|
|
113
132
|
/** Whether it is showing, whoever said so, and `undefined` until somebody has. */
|
|
114
133
|
private openState;
|
|
115
134
|
/**
|
|
@@ -128,6 +147,13 @@ export declare class HelixHeadlessToastItem extends HelixHeadlessToastItem_base
|
|
|
128
147
|
private readonly handlePause;
|
|
129
148
|
private readonly handleResume;
|
|
130
149
|
connectedCallback(): void;
|
|
150
|
+
disconnectedCallback(): void;
|
|
151
|
+
/**
|
|
152
|
+
* Escape dismisses the message holding focus, as Radix's toast does. Taken
|
|
153
|
+
* only when the dismissal goes ahead, so a refused one leaves the key to
|
|
154
|
+
* the page.
|
|
155
|
+
*/
|
|
156
|
+
private readonly handleKeydown;
|
|
131
157
|
protected willUpdate(changed: PropertyValues): void;
|
|
132
158
|
protected updated(changed: PropertyValues): void;
|
|
133
159
|
/** The elements assigned to one of the message's named slots. */
|