@fusion.dev/helix-headless 0.146.0 → 0.148.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 +9287 -1084
- package/dist/accordion/item/accordion-item.d.ts +43 -21
- package/dist/accordion/item/accordion-item.js +37 -11
- package/dist/accordion/root/accordion-root.d.ts +8 -2
- package/dist/accordion/root/accordion-root.js +6 -8
- package/dist/announcement/root/announcement-root.d.ts +66 -6
- package/dist/announcement/root/announcement-root.js +144 -13
- package/dist/area-chart/root/area-chart-root.d.ts +18 -1
- package/dist/area-chart/root/area-chart-root.js +14 -7
- package/dist/avatar/root/avatar-root.d.ts +31 -1
- package/dist/avatar/root/avatar-root.js +11 -1
- package/dist/badge/count.d.ts +14 -0
- package/dist/badge/count.js +20 -0
- package/dist/badge/root/badge-root.d.ts +57 -6
- package/dist/badge/root/badge-root.js +77 -8
- package/dist/bar-chart/root/bar-chart-root.js +11 -20
- package/dist/bar-chart/stack.d.ts +10 -0
- package/dist/bar-chart/stack.js +8 -0
- package/dist/blockquote/root/blockquote-root.d.ts +66 -8
- package/dist/blockquote/root/blockquote-root.js +85 -8
- package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +14 -0
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +12 -2
- package/dist/breadcrumbs/root/breadcrumbs-root.js +2 -2
- package/dist/button/root/button-root.d.ts +24 -38
- package/dist/button/root/button-root.js +6 -37
- package/dist/button/submitter.d.ts +27 -0
- package/dist/button/submitter.js +25 -0
- package/dist/button-group/arrows.d.ts +14 -0
- package/dist/button-group/arrows.js +10 -0
- package/dist/button-group/root/button-group-root.d.ts +141 -3
- package/dist/button-group/root/button-group-root.js +142 -2
- package/dist/canvas/edge-pan.d.ts +61 -0
- package/dist/canvas/edge-pan.js +63 -0
- package/dist/canvas/node/canvas-node.d.ts +12 -2
- package/dist/canvas/node/canvas-node.js +6 -2
- package/dist/canvas/root/canvas-document.d.ts +10 -0
- package/dist/canvas/root/canvas-document.js +1 -0
- package/dist/canvas/root/canvas-root.d.ts +107 -5
- package/dist/canvas/root/canvas-root.js +140 -36
- package/dist/canvas/snap.d.ts +42 -0
- package/dist/canvas/snap.js +32 -0
- package/dist/card/root/card-root.d.ts +12 -1
- package/dist/card/root/card-root.js +11 -4
- package/dist/carousel/root/carousel-root.d.ts +4 -3
- package/dist/carousel/root/carousel-root.js +2 -6
- package/dist/chat/root/chat-root.d.ts +28 -4
- package/dist/chat/root/chat-root.js +12 -7
- package/dist/checkbox/root/checkbox-root.js +5 -7
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +13 -0
- package/dist/checkbox-group/root/checkbox-group-root.js +16 -7
- package/dist/checkbox-group/select-all.d.ts +9 -4
- package/dist/checkbox-group/select-all.js +1 -1
- package/dist/code-block/root/code-block-root.d.ts +41 -18
- package/dist/code-block/root/code-block-root.js +21 -6
- package/dist/color-input/root/color-input-root.d.ts +11 -0
- package/dist/color-input/root/color-input-root.js +12 -5
- package/dist/color-picker/channels.js +1 -2
- package/dist/color-picker/root/color-picker-root.d.ts +32 -24
- package/dist/color-picker/root/color-picker-root.js +99 -55
- package/dist/color-picker/wheel.d.ts +28 -0
- package/dist/color-picker/wheel.js +15 -0
- package/dist/combobox/root/combobox-root.d.ts +83 -11
- package/dist/combobox/root/combobox-root.js +81 -18
- package/dist/command/root/command-root.d.ts +7 -4
- package/dist/command/root/command-root.js +2 -19
- package/dist/copy-button/root/copy-button-root.d.ts +16 -1
- package/dist/copy-button/root/copy-button-root.js +7 -2
- package/dist/data-table/keys.d.ts +0 -18
- package/dist/data-table/keys.js +1 -11
- package/dist/data-table/root/data-table-root.js +29 -50
- package/dist/date-input/root/date-input-root.d.ts +8 -1
- package/dist/date-input/root/date-input-root.js +8 -5
- package/dist/date-picker/root/date-picker-root.d.ts +14 -9
- package/dist/date-picker/root/date-picker-root.js +21 -16
- package/dist/description-list/item/description-list-item.d.ts +22 -4
- package/dist/description-list/item/description-list-item.js +14 -4
- package/dist/divider/root/divider-root.d.ts +45 -16
- package/dist/divider/root/divider-root.js +28 -4
- package/dist/donut-chart/root/donut-chart-root.js +13 -6
- package/dist/donut-chart/slice-label.d.ts +35 -0
- package/dist/donut-chart/slice-label.js +11 -0
- package/dist/drawer/root/drawer-root.d.ts +4 -2
- package/dist/drawer/root/drawer-root.js +15 -3
- package/dist/drilldown/item/drilldown-item.d.ts +21 -1
- package/dist/drilldown/item/drilldown-item.js +38 -4
- package/dist/drilldown/root/drilldown-root.js +3 -2
- package/dist/element-events.generated.js +5 -1
- package/dist/empty/root/empty-root.d.ts +46 -2
- package/dist/empty/root/empty-root.js +50 -5
- package/dist/file-input/root/file-input-root.d.ts +34 -6
- package/dist/file-input/root/file-input-root.js +55 -21
- package/dist/file-input/status.d.ts +24 -0
- package/dist/file-input/status.js +11 -0
- package/dist/filter-input/chip/filter-chip.d.ts +23 -0
- package/dist/filter-input/chip/filter-chip.js +10 -2
- package/dist/filter-input/root/filter-input-root.d.ts +8 -0
- package/dist/filter-input/root/filter-input-root.js +17 -27
- package/dist/format-date/fields.d.ts +20 -0
- package/dist/format-date/fields.js +14 -0
- package/dist/format-date/options.d.ts +5 -5
- package/dist/format-date/options.js +10 -39
- package/dist/format-date/root/format-date-root.d.ts +53 -4
- package/dist/format-date/root/format-date-root.js +38 -50
- package/dist/graph/root/graph-root.d.ts +23 -5
- package/dist/graph/root/graph-root.js +17 -20
- package/dist/heatmap/root/buckets.d.ts +21 -0
- package/dist/heatmap/root/buckets.js +34 -0
- package/dist/heatmap/root/heatmap-root.d.ts +76 -3
- package/dist/heatmap/root/heatmap-root.js +105 -20
- package/dist/icon/index.d.ts +1 -1
- package/dist/icon/index.js +1 -1
- package/dist/icon/registry.d.ts +26 -1
- package/dist/icon/registry.js +12 -1
- package/dist/icon/root/icon-root.d.ts +13 -0
- package/dist/icon/root/icon-root.js +23 -2
- package/dist/icon/root/index.d.ts +1 -1
- package/dist/icon/root/index.js +1 -1
- package/dist/image/root/image-root.d.ts +20 -0
- package/dist/image/root/image-root.js +6 -1
- package/dist/input/root/input-root.d.ts +23 -2
- package/dist/input/root/input-root.js +12 -8
- package/dist/kbd/root/kbd-root.d.ts +20 -3
- package/dist/kbd/root/kbd-root.js +23 -50
- package/dist/legend/hidden-series.d.ts +10 -2
- package/dist/legend/hidden-series.js +5 -2
- package/dist/legend/root/legend-root.d.ts +25 -7
- package/dist/legend/root/legend-root.js +25 -26
- package/dist/lightbox/root/lightbox-root.d.ts +50 -5
- package/dist/lightbox/root/lightbox-root.js +76 -8
- package/dist/lightbox/zoom.d.ts +2 -0
- package/dist/lightbox/zoom.js +5 -3
- package/dist/line-chart/root/line-chart-root.d.ts +16 -0
- package/dist/line-chart/root/line-chart-root.js +10 -2
- package/dist/list/root/list-root.d.ts +10 -2
- package/dist/list/root/list-root.js +31 -24
- package/dist/list/selection.d.ts +17 -0
- package/dist/list/selection.js +16 -0
- package/dist/listbox/root/listbox-root.d.ts +125 -26
- package/dist/listbox/root/listbox-root.js +156 -166
- package/dist/map/marker/map-marker.d.ts +2 -1
- package/dist/map/root/map-root.d.ts +40 -2
- package/dist/map/root/map-root.js +64 -23
- package/dist/megamenu/hand-over.d.ts +75 -0
- package/dist/megamenu/hand-over.js +67 -0
- package/dist/megamenu/root/megamenu-root.d.ts +38 -14
- package/dist/megamenu/root/megamenu-root.js +29 -50
- package/dist/menu/item/menu-item.js +4 -4
- package/dist/menu/root/menu-root.d.ts +5 -2
- package/dist/meter/root/meter-root.d.ts +42 -0
- package/dist/meter/root/meter-root.js +33 -7
- package/dist/navigation/root/navigation-root.js +5 -8
- package/dist/notifications/group/notification-group.d.ts +8 -1
- package/dist/notifications/group/notification-group.js +12 -6
- package/dist/notifications/notification/notification.d.ts +12 -1
- package/dist/notifications/notification/notification.js +3 -1
- package/dist/notifications/root/notifications-root.d.ts +48 -3
- package/dist/notifications/root/notifications-root.js +36 -6
- package/dist/number-input/grain.d.ts +28 -0
- package/dist/number-input/grain.js +14 -0
- package/dist/number-input/root/number-input-root.d.ts +17 -1
- package/dist/number-input/root/number-input-root.js +29 -18
- package/dist/object-inspector/root/object-inspector-root.d.ts +17 -6
- package/dist/object-inspector/root/object-inspector-root.js +31 -20
- package/dist/option/index.d.ts +1 -0
- package/dist/option/index.js +1 -0
- package/dist/option/separator/option-separator.d.ts +30 -0
- package/dist/option/separator/option-separator.js +21 -0
- package/dist/outline/root/outline-root.d.ts +12 -0
- package/dist/outline/root/outline-root.js +5 -19
- package/dist/pagination/size/pagination-size.d.ts +6 -0
- package/dist/pagination/size/pagination-size.js +5 -3
- package/dist/pin-input/code.d.ts +51 -1
- package/dist/pin-input/code.js +37 -0
- package/dist/pin-input/root/pin-input-root.d.ts +98 -121
- package/dist/pin-input/root/pin-input-root.js +151 -156
- package/dist/popover/hide-outside.js +2 -9
- package/dist/popover/root/popover-root.d.ts +7 -1
- package/dist/popover/root/popover-root.js +9 -1
- package/dist/progress/root/progress-root.d.ts +27 -0
- package/dist/progress/root/progress-root.js +25 -7
- package/dist/qr-code/export.d.ts +19 -0
- package/dist/qr-code/export.js +14 -0
- package/dist/qr-code/name.d.ts +11 -0
- package/dist/qr-code/name.js +7 -0
- package/dist/qr-code/root/qr-code-root.d.ts +31 -9
- package/dist/qr-code/root/qr-code-root.js +29 -17
- package/dist/radio/group/radio-group.d.ts +15 -0
- package/dist/radio/root/radio-root.js +2 -2
- package/dist/rating/root/rating-root.d.ts +22 -9
- package/dist/rating/root/rating-root.js +15 -39
- package/dist/scatter-chart/measures.d.ts +22 -0
- package/dist/scatter-chart/measures.js +11 -0
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +26 -0
- package/dist/scatter-chart/root/scatter-chart-root.js +21 -7
- package/dist/scroll-area/scrollbar.d.ts +0 -8
- package/dist/scroll-area/scrollbar.js +1 -1
- package/dist/select/align.d.ts +47 -0
- package/dist/select/align.js +7 -0
- package/dist/select/root/select-root.d.ts +115 -11
- package/dist/select/root/select-root.js +104 -20
- package/dist/slider/root/slider-root.d.ts +18 -1
- package/dist/slider/root/slider-root.js +22 -0
- package/dist/sparkline/readings.d.ts +30 -12
- package/dist/sparkline/readings.js +32 -15
- package/dist/sparkline/root/sparkline-root.d.ts +46 -3
- package/dist/sparkline/root/sparkline-root.js +60 -21
- package/dist/speed-dial/group/speed-dial-group.d.ts +48 -0
- package/dist/speed-dial/group/speed-dial-group.js +43 -0
- package/dist/speed-dial/index.d.ts +1 -0
- package/dist/speed-dial/index.js +1 -0
- package/dist/speed-dial/item/speed-dial-item.d.ts +27 -2
- package/dist/speed-dial/item/speed-dial-item.js +43 -5
- package/dist/speed-dial/long-press.d.ts +50 -0
- package/dist/speed-dial/long-press.js +48 -0
- package/dist/speed-dial/root/speed-dial-root.d.ts +86 -1
- package/dist/speed-dial/root/speed-dial-root.js +123 -6
- package/dist/splitter/root/splitter-root.d.ts +9 -2
- package/dist/splitter/root/splitter-root.js +18 -3
- package/dist/steps/root/steps-root.d.ts +8 -1
- package/dist/steps/root/steps-root.js +6 -1
- package/dist/steps/step/step.d.ts +1 -0
- package/dist/steps/step/step.js +1 -1
- package/dist/table/cell/table-cell.d.ts +8 -1
- package/dist/table/cell/table-cell.js +6 -2
- package/dist/table/column/table-column.d.ts +6 -0
- package/dist/table/column/table-column.js +5 -1
- package/dist/table/grid-controller.d.ts +117 -0
- package/dist/table/grid-controller.js +293 -0
- package/dist/table/root/table-root.d.ts +47 -3
- package/dist/table/root/table-root.js +93 -29
- package/dist/table/row/table-row.d.ts +36 -0
- package/dist/table/row/table-row.js +52 -2
- package/dist/tabs/root/tabs-root.d.ts +5 -3
- package/dist/tag/group/tag-group.d.ts +16 -4
- package/dist/tag/group/tag-group.js +23 -20
- package/dist/textarea/root/textarea-root.d.ts +14 -2
- package/dist/textarea/root/textarea-root.js +6 -7
- package/dist/time-input/root/time-input-root.d.ts +5 -1
- package/dist/time-input/root/time-input-root.js +10 -7
- package/dist/time-picker/root/time-picker-root.d.ts +12 -14
- package/dist/time-picker/root/time-picker-root.js +18 -23
- package/dist/toast/item/toast-item.d.ts +9 -6
- package/dist/toast/item/toast-item.js +1 -1
- package/dist/toast/root/toast-root.d.ts +40 -4
- package/dist/toast/root/toast-root.js +68 -16
- package/dist/toast/words.d.ts +12 -0
- package/dist/toast/words.js +25 -0
- package/dist/toggle/group/toggle-group.d.ts +29 -5
- package/dist/toggle/group/toggle-group.js +26 -43
- package/dist/toggle/root/toggle-root.js +2 -4
- package/dist/toolbar/root/toolbar-root.d.ts +52 -5
- package/dist/toolbar/root/toolbar-root.js +88 -13
- package/dist/tooltip/root/tooltip-root.d.ts +7 -1
- package/dist/tooltip/root/tooltip-root.js +10 -2
- package/dist/tour/root/tour-root.d.ts +15 -0
- package/dist/tour/root/tour-root.js +20 -1
- package/dist/tour/stop/tour-stop.d.ts +3 -0
- package/dist/tour/stop/tour-stop.js +3 -3
- package/dist/tree/root/tree-root.js +2 -2
- package/dist/trend/figure.d.ts +16 -0
- package/dist/trend/figure.js +8 -0
- package/dist/trend/root/trend-root.d.ts +41 -2
- package/dist/trend/root/trend-root.js +29 -3
- package/dist/video/root/extra-controls.d.ts +12 -0
- package/dist/video/root/extra-controls.js +6 -2
- package/dist/video/root/video-root.d.ts +16 -1
- package/dist/video/root/video-root.js +15 -1
- package/dist/video-playlist/root/video-playlist-root.d.ts +11 -1
- package/dist/video-playlist/root/video-playlist-root.js +3 -0
- package/dist/virtual-list/fill.d.ts +11 -0
- package/dist/virtual-list/fill.js +9 -0
- package/dist/virtual-list/keys.d.ts +16 -7
- package/dist/virtual-list/keys.js +17 -6
- package/dist/virtual-list/plan.d.ts +17 -1
- package/dist/virtual-list/plan.js +13 -2
- package/dist/virtual-list/root/virtual-list-root.d.ts +25 -3
- package/dist/virtual-list/root/virtual-list-root.js +53 -41
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +4934 -954
- package/types/svelte.d.ts +2 -0
- package/types/vue.d.ts +946 -253
- package/dist/color-picker/swatches.d.ts +0 -12
- package/dist/color-picker/swatches.js +0 -26
- package/dist/rating/steps.d.ts +0 -7
- package/dist/rating/steps.js +0 -9
- package/dist/tooltip/focus-target.d.ts +0 -6
- package/dist/tooltip/focus-target.js +0 -9
|
@@ -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 { AriaForwardController, customElement, drawIcon, HelixClearEvent, HelixFormElement, holdCaret, isRtl, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, applyOwnRule, customElement, drawIcon, HelixClearEvent, HelixFormElement, holdCaret, isRtl, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { x } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { html, nothing } from 'lit';
|
|
10
10
|
import { property } from 'lit/decorators.js';
|
|
@@ -126,11 +126,7 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
|
|
|
126
126
|
return;
|
|
127
127
|
}
|
|
128
128
|
this.copyValidity(control);
|
|
129
|
-
|
|
130
|
-
const message = Array.isArray(own) ? own.join(' ') : typeof own === 'string' ? own : '';
|
|
131
|
-
if (message !== '') {
|
|
132
|
-
this.internals.setValidity({ customError: true }, message, control);
|
|
133
|
-
}
|
|
129
|
+
applyOwnRule(this.internals, control, this.validate, this.value);
|
|
134
130
|
this.refreshFeedback();
|
|
135
131
|
}
|
|
136
132
|
connectedCallback() {
|
|
@@ -175,6 +171,9 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
|
|
|
175
171
|
this.sync();
|
|
176
172
|
this.grow();
|
|
177
173
|
}
|
|
174
|
+
renderClearIcon() {
|
|
175
|
+
return html `<slot name="clear-icon">${drawIcon(x)}</slot>`;
|
|
176
|
+
}
|
|
178
177
|
render() {
|
|
179
178
|
return html `${this.renderLabel()}
|
|
180
179
|
<div part="field">
|
|
@@ -207,7 +206,7 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
|
|
|
207
206
|
aria-label=${this.clearLabel}
|
|
208
207
|
@click=${this.handleClear}
|
|
209
208
|
>
|
|
210
|
-
${
|
|
209
|
+
${this.renderClearIcon()}
|
|
211
210
|
</button>`
|
|
212
211
|
: nothing}
|
|
213
212
|
</div>
|
|
@@ -74,6 +74,7 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
|
|
|
74
74
|
* @csspart picker-column-search - The region that holds the filter field.
|
|
75
75
|
* @csspart picker-column-search-field - The filter field.
|
|
76
76
|
* @csspart picker-columns - The row of columns, in `wheels`.
|
|
77
|
+
* @csspart picker-feedback - The picker's own message, under the times, while the picker's `feedback` is set.
|
|
77
78
|
* @csspart picker-list - The listbox holding the times, in `list`.
|
|
78
79
|
* @csspart picker-list-empty - The text shown when the filter hides every option.
|
|
79
80
|
* @csspart picker-list-error - The list's `error` part, which the list never sets: its times do not load.
|
|
@@ -142,9 +143,12 @@ export declare class HelixHeadlessTimeInput extends HelixHeadlessTimeInput_base
|
|
|
142
143
|
/**
|
|
143
144
|
* Language tag the times are written in.
|
|
144
145
|
*
|
|
145
|
-
* Absent
|
|
146
|
+
* Absent is the page's: the `lang` of the nearest element with one, as
|
|
147
|
+
* Shoelace and Web Awesome read it, then the runtime's own.
|
|
146
148
|
*/
|
|
147
149
|
locale: string;
|
|
150
|
+
/** The locale the words are written in: `locale`, or the page's `lang`. */
|
|
151
|
+
private get language();
|
|
148
152
|
/**
|
|
149
153
|
* Latest time that can be chosen, as `HH:mm`.
|
|
150
154
|
*/
|
|
@@ -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 { AriaForwardController, valueAsTime as asTime, clockLocale, customElement, fillTemplate, timeAsValue as fromTime, HelixFormElement, isClockValue, MixinControllerOpen, MixinControllerValue, MixinField, MixinPickerEditing, MixinPickerField, MixinSegmentedField, MixinTokens, timeFault, writeClock, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, valueAsTime as asTime, clockLocale, customElement, fillTemplate, timeAsValue as fromTime, HelixFormElement, isClockValue, localeOf, MixinControllerOpen, MixinControllerValue, MixinField, MixinPickerEditing, MixinPickerField, MixinSegmentedField, MixinTokens, timeFault, writeClock, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { clock } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -88,6 +88,9 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
88
88
|
}
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
|
+
get language() {
|
|
92
|
+
return localeOf(this, this.locale);
|
|
93
|
+
}
|
|
91
94
|
get held() {
|
|
92
95
|
return this.value
|
|
93
96
|
.replace(/\s+[–-]\s+/g, ',')
|
|
@@ -102,7 +105,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
102
105
|
return 'time';
|
|
103
106
|
}
|
|
104
107
|
get segmentLocale() {
|
|
105
|
-
return this.
|
|
108
|
+
return this.language;
|
|
106
109
|
}
|
|
107
110
|
get segmentOptions() {
|
|
108
111
|
return { hourCycle: this.hourCycle, seconds: this.seconds };
|
|
@@ -113,7 +116,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
113
116
|
written(at) {
|
|
114
117
|
return this.timeStyle === 'iso' || !this.isTime(at)
|
|
115
118
|
? at
|
|
116
|
-
: writeClock(at, clockLocale(this.
|
|
119
|
+
: writeClock(at, clockLocale(this.language, this.hourCycle), this.seconds);
|
|
117
120
|
}
|
|
118
121
|
get display() {
|
|
119
122
|
if (this.mode === 'multiple') {
|
|
@@ -155,7 +158,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
155
158
|
return [
|
|
156
159
|
'rangeUnderflow',
|
|
157
160
|
fillTemplate(this.rangeUnderflowMessage || 'Choose a time at or after {min}.', {
|
|
158
|
-
min: writeClock(this.min, clockLocale(this.
|
|
161
|
+
min: writeClock(this.min, clockLocale(this.language, this.hourCycle), this.seconds),
|
|
159
162
|
}),
|
|
160
163
|
];
|
|
161
164
|
}
|
|
@@ -163,7 +166,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
163
166
|
return [
|
|
164
167
|
'rangeOverflow',
|
|
165
168
|
fillTemplate(this.rangeOverflowMessage || 'Choose a time at or before {max}.', {
|
|
166
|
-
max: writeClock(this.max, clockLocale(this.
|
|
169
|
+
max: writeClock(this.max, clockLocale(this.language, this.hourCycle), this.seconds),
|
|
167
170
|
}),
|
|
168
171
|
];
|
|
169
172
|
}
|
|
@@ -189,7 +192,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
189
192
|
column-filter-mark: picker-column-filter-mark, column-hint: picker-column-hint,
|
|
190
193
|
column-items: picker-column-items, column-label: picker-column-label,
|
|
191
194
|
column-live: picker-column-live, column-loading: picker-column-loading, column-search: picker-column-search,
|
|
192
|
-
column-search-field: picker-column-search-field, columns: picker-columns, list: picker-list,
|
|
195
|
+
column-search-field: picker-column-search-field, columns: picker-columns, feedback: picker-feedback, list: picker-list,
|
|
193
196
|
list-empty: picker-list-empty, list-error: picker-list-error, list-feedback: picker-list-feedback,
|
|
194
197
|
list-filter-icon: picker-list-filter-icon, list-filter-mark: picker-list-filter-mark,
|
|
195
198
|
list-hint: picker-list-hint, list-items: picker-list-items, list-label: picker-list-label,
|
|
@@ -206,7 +209,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
206
209
|
manual
|
|
207
210
|
label=${this.label || 'Time'}
|
|
208
211
|
hour-cycle=${this.hourCycle ?? nothing}
|
|
209
|
-
locale=${this.
|
|
212
|
+
locale=${this.language || nothing}
|
|
210
213
|
max=${this.max}
|
|
211
214
|
min=${this.min}
|
|
212
215
|
?seconds=${this.seconds}
|
|
@@ -2,7 +2,7 @@ import { HelixFormElement, type HourCycle } from '@fusion.dev/helix-core';
|
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
import '../../listbox/index.js';
|
|
4
4
|
import '../../option/index.js';
|
|
5
|
-
declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & typeof HelixFormElement;
|
|
5
|
+
declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinPickerFeedbackInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & typeof HelixFormElement;
|
|
6
6
|
/**
|
|
7
7
|
* @summary A control for choosing a time from a list or from wheels.
|
|
8
8
|
*
|
|
@@ -59,6 +59,7 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
|
|
|
59
59
|
* @csspart column-search - The region that holds the filter field.
|
|
60
60
|
* @csspart column-search-field - The filter field.
|
|
61
61
|
* @csspart columns - The row of columns, in `wheels`.
|
|
62
|
+
* @csspart feedback - The message under the times, while `feedback` is set.
|
|
62
63
|
* @csspart list - The listbox holding the times, in `list`.
|
|
63
64
|
* @csspart list-empty - The text shown when the filter hides every option.
|
|
64
65
|
* @csspart list-error - The list's `error` part, which Time Picker never sets: its times do not load.
|
|
@@ -80,6 +81,9 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
|
|
|
80
81
|
* @csspart option-item-selected - The row of a chosen time: the one time, or either end of a range.
|
|
81
82
|
* @csspart option-label - The time's label.
|
|
82
83
|
* @csspart option-text - The label and the caption, as one column.
|
|
84
|
+
*
|
|
85
|
+
* @cssstate blank - While no time is chosen.
|
|
86
|
+
* @cssstate invalid - While `invalid` is set or `feedback` says what is wrong.
|
|
83
87
|
*/
|
|
84
88
|
export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_base {
|
|
85
89
|
/**
|
|
@@ -119,16 +123,6 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
|
|
|
119
123
|
* English, "Stunde" in German.
|
|
120
124
|
*/
|
|
121
125
|
hourLabel?: string;
|
|
122
|
-
/**
|
|
123
|
-
* Whether the current selection fails validation.
|
|
124
|
-
*
|
|
125
|
-
* A flag rather than a message, the same split Date Picker draws. A flat
|
|
126
|
-
* picker has no room of its own for a sentence: the field that wraps one owns
|
|
127
|
-
* the label, the hint and the feedback, and a second message inside the panel
|
|
128
|
-
* would be the same error said twice. What is left for the picker is the one
|
|
129
|
-
* thing the field cannot draw from outside, the mark on the answer itself.
|
|
130
|
-
*/
|
|
131
|
-
invalid: boolean;
|
|
132
126
|
/**
|
|
133
127
|
* Accessible name for the list, which has no visible one of its own.
|
|
134
128
|
*
|
|
@@ -136,11 +130,14 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
|
|
|
136
130
|
*/
|
|
137
131
|
label: string;
|
|
138
132
|
/**
|
|
139
|
-
* Language tag the times are written in.
|
|
133
|
+
* Language tag the times and the wheels' names are written in.
|
|
140
134
|
*
|
|
141
|
-
* Absent
|
|
135
|
+
* Absent is the page's: the `lang` of the nearest element with one, as
|
|
136
|
+
* Shoelace and Web Awesome read it, then the runtime's own.
|
|
142
137
|
*/
|
|
143
138
|
locale: string;
|
|
139
|
+
/** The locale the words are written in: `locale`, or the page's `lang`. */
|
|
140
|
+
private get language();
|
|
144
141
|
/**
|
|
145
142
|
* Stops the arrow keys in the list from choosing each time they move to.
|
|
146
143
|
* Enter, Space or a click chooses.
|
|
@@ -460,7 +457,8 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
|
|
|
460
457
|
private listRevealed;
|
|
461
458
|
/**
|
|
462
459
|
* The list's name: the host's `aria-labelledby` read out, then its
|
|
463
|
-
* `aria-label`, then `label
|
|
460
|
+
* `aria-label`, then `label`, through core's `hostWords`, which Select reads
|
|
461
|
+
* its list's name through too.
|
|
464
462
|
*
|
|
465
463
|
* Read out as words, because the list is inside two shadow roots and an id on
|
|
466
464
|
* the page reaches neither. Measured before this: `<helix-time-picker
|
|
@@ -4,18 +4,17 @@ 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,
|
|
7
|
+
import { clockLocale, commaList, customElement, dayPeriod, fillTemplate, HelixFormElement, hostWords, inlineStep, isTwelveHour, localeOf, MixinControllerValue, MixinPickerFeedback, nearestTime, offeredTimes, reportValues, secondsAsValue, timeBarred, timeFault, valueAsSeconds, wheelParts, wholeHour, writeClock, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { nothing } from 'lit';
|
|
9
9
|
import { property } 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';
|
|
13
13
|
import '../../option/index.js';
|
|
14
|
-
let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControllerValue(HelixFormElement) {
|
|
14
|
+
let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerFeedback(MixinControllerValue(HelixFormElement)) {
|
|
15
15
|
constructor() {
|
|
16
16
|
super(...arguments);
|
|
17
17
|
this.disableTimes = '';
|
|
18
|
-
this.invalid = false;
|
|
19
18
|
this.label = 'Time';
|
|
20
19
|
this.locale = '';
|
|
21
20
|
this.manual = false;
|
|
@@ -94,11 +93,14 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
94
93
|
next.focus();
|
|
95
94
|
};
|
|
96
95
|
}
|
|
96
|
+
get language() {
|
|
97
|
+
return localeOf(this, this.locale);
|
|
98
|
+
}
|
|
97
99
|
get times() {
|
|
98
100
|
return offeredTimes(this.min, this.max, this.step, this.seconds);
|
|
99
101
|
}
|
|
100
102
|
get clock() {
|
|
101
|
-
return clockLocale(this.
|
|
103
|
+
return clockLocale(this.language, this.hourCycle);
|
|
102
104
|
}
|
|
103
105
|
valueFor(at) {
|
|
104
106
|
return secondsAsValue(at, this.seconds);
|
|
@@ -239,13 +241,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
239
241
|
this.reveal();
|
|
240
242
|
}
|
|
241
243
|
get listName() {
|
|
242
|
-
|
|
243
|
-
.split(/\s+/)
|
|
244
|
-
.filter(Boolean)
|
|
245
|
-
.map((id) => elementById(this, id)?.textContent?.trim() ?? '')
|
|
246
|
-
.filter(Boolean)
|
|
247
|
-
.join(' ');
|
|
248
|
-
return named || this.getAttribute('aria-label') || this.label;
|
|
244
|
+
return hostWords(this, this.label);
|
|
249
245
|
}
|
|
250
246
|
connectedCallback() {
|
|
251
247
|
super.connectedCallback();
|
|
@@ -259,8 +255,8 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
259
255
|
}
|
|
260
256
|
willUpdate(changed) {
|
|
261
257
|
super.willUpdate(changed);
|
|
262
|
-
this.internals.ariaInvalid = this.invalid ? 'true' : null;
|
|
263
258
|
this.report();
|
|
259
|
+
this.toggleState('blank', this.value === '');
|
|
264
260
|
}
|
|
265
261
|
updated(changed) {
|
|
266
262
|
super.updated(changed);
|
|
@@ -282,7 +278,8 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
282
278
|
return html `<${this.tag('listbox')}
|
|
283
279
|
part="column"
|
|
284
280
|
data-column=${part}
|
|
285
|
-
aria-
|
|
281
|
+
aria-describedby=${this.feedback === '' ? nothing : 'feedback'}
|
|
282
|
+
aria-invalid=${this.marked ? 'true' : nothing}
|
|
286
283
|
exportparts="empty: column-empty, error: column-error, feedback: column-feedback, filter-icon: column-filter-icon,
|
|
287
284
|
filter-mark: column-filter-mark, hint: column-hint, items: column-items, label: column-label,
|
|
288
285
|
live: column-live, loading: column-loading, search: column-search, search-field: column-search-field"
|
|
@@ -320,20 +317,21 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
320
317
|
data-unset=${this.value === '' ? '' : nothing}
|
|
321
318
|
@keydown=${this.handleColumnsKeydown}
|
|
322
319
|
>
|
|
323
|
-
${this.renderColumn('hour', this.hourLabel ?? wheelName('hour', this.
|
|
324
|
-
${this.renderColumn('minute', this.minuteLabel ?? wheelName('minute', this.
|
|
320
|
+
${this.renderColumn('hour', this.hourLabel ?? wheelName('hour', this.language), hours.map(String), (one) => (twelve ? one : one.padStart(2, '0')), String(shown), (one) => this.wholeHourBarred(Number(one), twelve ? meridiem : undefined))}
|
|
321
|
+
${this.renderColumn('minute', this.minuteLabel ?? wheelName('minute', this.language), this.minutes.map(String), (one) => one.padStart(2, '0'), String(minute), (one) => this.barredAt(hour * 3600 + Number(one) * 60))}
|
|
325
322
|
${this.seconds
|
|
326
|
-
? this.renderColumn('second', this.secondLabel ?? wheelName('second', this.
|
|
323
|
+
? this.renderColumn('second', this.secondLabel ?? wheelName('second', this.language), this.secondsShown.map(String), (one) => one.padStart(2, '0'), String(second), (one) => this.barredAt(hour * 3600 + minute * 60 + Number(one)))
|
|
327
324
|
: nothing}
|
|
328
325
|
${twelve
|
|
329
|
-
? this.renderColumn('meridiem', this.meridiemLabel ?? wheelName('dayPeriod', this.
|
|
326
|
+
? this.renderColumn('meridiem', this.meridiemLabel ?? wheelName('dayPeriod', this.language), ['AM', 'PM'], (one) => dayPeriod(one, this.clock), meridiem, (one) => this.halfBarred(one))
|
|
330
327
|
: nothing}
|
|
331
328
|
</div>`;
|
|
332
329
|
}
|
|
333
330
|
renderList() {
|
|
334
331
|
return html `<${this.tag('listbox')}
|
|
335
332
|
part="list"
|
|
336
|
-
aria-
|
|
333
|
+
aria-describedby=${this.feedback === '' ? nothing : 'feedback'}
|
|
334
|
+
aria-invalid=${this.marked ? 'true' : nothing}
|
|
337
335
|
exportparts="empty: list-empty, error: list-error, feedback: list-feedback, filter-icon: list-filter-icon,
|
|
338
336
|
filter-mark: list-filter-mark, hint: list-hint, items: list-items, label: list-label,
|
|
339
337
|
live: list-live, loading: list-loading, search: list-search, search-field: list-search-field"
|
|
@@ -365,9 +363,9 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
365
363
|
}
|
|
366
364
|
render() {
|
|
367
365
|
if (this.variant === 'wheels' && this.mode === undefined) {
|
|
368
|
-
return this.renderSpinner()
|
|
366
|
+
return html `${this.renderSpinner()}${this.renderPickerFeedback()}`;
|
|
369
367
|
}
|
|
370
|
-
return html `${this.renderList()}`;
|
|
368
|
+
return html `${this.renderList()}${this.renderPickerFeedback()}`;
|
|
371
369
|
}
|
|
372
370
|
get valueAsDate() {
|
|
373
371
|
const at = valueAsSeconds(this.value);
|
|
@@ -398,9 +396,6 @@ __decorate([
|
|
|
398
396
|
__decorate([
|
|
399
397
|
property({ attribute: 'hour-label' })
|
|
400
398
|
], HelixHeadlessTimePicker.prototype, "hourLabel", void 0);
|
|
401
|
-
__decorate([
|
|
402
|
-
property({ reflect: true, type: Boolean })
|
|
403
|
-
], HelixHeadlessTimePicker.prototype, "invalid", void 0);
|
|
404
399
|
__decorate([
|
|
405
400
|
property()
|
|
406
401
|
], HelixHeadlessTimePicker.prototype, "label", void 0);
|
|
@@ -10,14 +10,15 @@ declare const HelixHeadlessToastItem_base: (new (...args: any[]) => import("@fus
|
|
|
10
10
|
*
|
|
11
11
|
* **Each item runs its own timer.** A timer held by the region would restart
|
|
12
12
|
* with each new message, and the last of three messages would stay for nine
|
|
13
|
-
* seconds.
|
|
13
|
+
* seconds. It pauses while the pointer or focus is on the message, and while
|
|
14
|
+
* the page is hidden, so a message is not spent in a background tab.
|
|
14
15
|
*
|
|
15
16
|
* **Each message is an `alertdialog` named by its words**, which is how a reader
|
|
16
17
|
* who moves into the stack hears which message they are on. Give it a
|
|
17
18
|
* `heading` and a `description`, and the heading names it and the description
|
|
18
|
-
* describes it, for a message with a title and a line of detail.
|
|
19
|
-
*
|
|
20
|
-
* is
|
|
19
|
+
* describes it, for a message with a title and a line of detail. The region
|
|
20
|
+
* says each message once as it arrives, a `danger` one assertively, so a
|
|
21
|
+
* message is never a live region of its own.
|
|
21
22
|
*
|
|
22
23
|
* A touch or a pen swipes a message toward the end of the line, and past
|
|
23
24
|
* halfway, or quickly, dismisses it through the same `helix-dismiss` as its
|
|
@@ -85,8 +86,10 @@ export declare class HelixHeadlessToastItem extends HelixHeadlessToastItem_base
|
|
|
85
86
|
/** Writes how far a swipe has moved the message toward the end of the line. */
|
|
86
87
|
private slide;
|
|
87
88
|
/**
|
|
88
|
-
* The dismiss timer, which pauses while a reader is on the message and
|
|
89
|
-
* continues from what was left.
|
|
89
|
+
* The dismiss timer, which pauses while a reader is on the message, and
|
|
90
|
+
* while the page is hidden, and continues from what was left. A message that
|
|
91
|
+
* arrives in a background tab waits for the reader to come back, as React
|
|
92
|
+
* Aria's toast queue does.
|
|
90
93
|
*
|
|
91
94
|
* Paused is said on the host so the indicator can freeze with the clock. A
|
|
92
95
|
* `data-` attribute rather than a property, because it is written after
|
|
@@ -35,6 +35,7 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
|
|
|
35
35
|
done: () => {
|
|
36
36
|
this.dismiss();
|
|
37
37
|
},
|
|
38
|
+
holdWhileHidden: true,
|
|
38
39
|
paused: (paused) => {
|
|
39
40
|
this.toggleAttribute('data-paused', paused);
|
|
40
41
|
},
|
|
@@ -104,7 +105,6 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
|
|
|
104
105
|
this.toggleAttribute('hidden', !this.open);
|
|
105
106
|
hostAria(this.internals, { role: 'alertdialog' });
|
|
106
107
|
this.internals.ariaModal = 'false';
|
|
107
|
-
this.internals.ariaLive = this.tone === 'danger' ? 'assertive' : null;
|
|
108
108
|
}
|
|
109
109
|
updated(changed) {
|
|
110
110
|
super.updated(changed);
|
|
@@ -9,10 +9,15 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
9
9
|
* announce a region that arrives already holding its message. `Radio.Group` is
|
|
10
10
|
* part of its family for the same reason.
|
|
11
11
|
*
|
|
12
|
-
* **The region is a landmark named by `label`, and
|
|
13
|
-
* `danger` message
|
|
14
|
-
*
|
|
15
|
-
*
|
|
12
|
+
* **The region is a landmark named by `label`, and it says each message once
|
|
13
|
+
* as it arrives**: a `danger` message assertively, and every other one
|
|
14
|
+
* politely. It says the word for the tone, the heading, the description and
|
|
15
|
+
* the text, and not the actions, through two live regions of its own, the
|
|
16
|
+
* `live` parts, which it empties again a moment later. The stack itself is not
|
|
17
|
+
* a live region, so a message is never said twice, and changing the words of a
|
|
18
|
+
* message already showing says nothing. Each message is an `alertdialog` named
|
|
19
|
+
* by its words, so a reader who moves into the stack hears which message they
|
|
20
|
+
* are on.
|
|
16
21
|
*
|
|
17
22
|
* **`hotkey` takes focus to the stack and back**, F8 unless you set it, and
|
|
18
23
|
* `label` says which key: `{hotkey}` in it is filled in, so the default name
|
|
@@ -54,6 +59,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
54
59
|
*
|
|
55
60
|
* @event {HelixDismissEvent} helix-dismiss - A message is being dismissed, by its control or by its timer. The message sends it, and you can listen for it on the region. Cancelable: canceling it keeps the message.
|
|
56
61
|
*
|
|
62
|
+
* @csspart live - The two regions that say each message as it arrives, a polite `status` and an assertive `alert`, inside the stack. Empty at rest, and hide them with the standard clip, never `display: none`.
|
|
57
63
|
* @csspart region - The stack the messages are in. It is in the top layer while a message shows, and takes focus from `hotkey` where no message holds a control.
|
|
58
64
|
*/
|
|
59
65
|
export declare class HelixHeadlessToast extends HelixElement {
|
|
@@ -95,6 +101,36 @@ export declare class HelixHeadlessToast extends HelixElement {
|
|
|
95
101
|
*/
|
|
96
102
|
placement?: 'bottom-center' | 'bottom-end' | 'bottom-start' | 'top-center' | 'top-end' | 'top-start';
|
|
97
103
|
protected willUpdate(changed: PropertyValues): void;
|
|
104
|
+
/** What the polite region is saying. */
|
|
105
|
+
private said;
|
|
106
|
+
/** What the assertive region is saying. */
|
|
107
|
+
private urgent;
|
|
108
|
+
private readonly hush;
|
|
109
|
+
/**
|
|
110
|
+
* Words waiting for the next frame: the polite ones and the urgent ones.
|
|
111
|
+
*
|
|
112
|
+
* Collected rather than written straight in, because the accessibility tree
|
|
113
|
+
* is built once a frame: two messages that arrive in separate tasks of one
|
|
114
|
+
* frame would otherwise each overwrite the region, and only the second
|
|
115
|
+
* would be heard.
|
|
116
|
+
*/
|
|
117
|
+
private readonly pending;
|
|
118
|
+
/** Whether a frame is already coming to say what is pending. */
|
|
119
|
+
private filling;
|
|
120
|
+
/**
|
|
121
|
+
* Says messages that have just arrived, each once, `danger` ones assertively.
|
|
122
|
+
*
|
|
123
|
+
* Emptied first and filled a frame later, so a message with the same words
|
|
124
|
+
* as the one before is still a change, and so a region the stack has just
|
|
125
|
+
* shown is in the accessibility tree before its words land. Every message
|
|
126
|
+
* that arrives before that frame is said in it, each as its own sentence.
|
|
127
|
+
*/
|
|
128
|
+
private announce;
|
|
129
|
+
/**
|
|
130
|
+
* Says the messages that have just arrived: through the regions, or through
|
|
131
|
+
* `ariaNotify` where a modal dialog has made them inert.
|
|
132
|
+
*/
|
|
133
|
+
private tell;
|
|
98
134
|
/** The element focus came from when it entered the stack. */
|
|
99
135
|
private focusOrigin;
|
|
100
136
|
private readonly scope;
|
|
@@ -4,15 +4,21 @@ 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, deepActiveElement, deepContains, FocusScopeController, fillTemplate, focusableElements, HelixElement, hostAria, scrollHolders, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { animationsFinished, customElement, DelayController, deepActiveElement, deepContains, FocusScopeController, fillTemplate, focusableElements, HelixElement, hostAria, scrollHolders, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
|
-
import { property } from 'lit/decorators.js';
|
|
9
|
+
import { property, state } from 'lit/decorators.js';
|
|
10
10
|
import { matchesHotkey, parseHotkey } from '../hotkey.js';
|
|
11
|
+
import { joinSaid, messageWords } from '../words.js';
|
|
11
12
|
let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
12
13
|
constructor() {
|
|
13
14
|
super(...arguments);
|
|
14
15
|
this.hotkey = 'F8';
|
|
15
16
|
this.label = 'Notifications ({hotkey})';
|
|
17
|
+
this.said = '';
|
|
18
|
+
this.urgent = '';
|
|
19
|
+
this.hush = new DelayController(this, { renders: false });
|
|
20
|
+
this.pending = { said: [], urgent: [] };
|
|
21
|
+
this.filling = false;
|
|
16
22
|
this.scope = new FocusScopeController(this, {
|
|
17
23
|
contents: () => this.showing.flatMap((one) => {
|
|
18
24
|
const target = focusTarget(one);
|
|
@@ -85,9 +91,51 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
85
91
|
label: fillTemplate(this.label, { hotkey: this.hotkey }),
|
|
86
92
|
role: 'region',
|
|
87
93
|
});
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
94
|
+
}
|
|
95
|
+
announce(arrived) {
|
|
96
|
+
for (const one of arrived) {
|
|
97
|
+
const words = messageWords(one);
|
|
98
|
+
if (words !== '') {
|
|
99
|
+
;
|
|
100
|
+
(isDanger(one) ? this.pending.urgent : this.pending.said).push(words);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (this.filling || (this.pending.said.length === 0 && this.pending.urgent.length === 0)) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
this.filling = true;
|
|
107
|
+
this.said = '';
|
|
108
|
+
this.urgent = '';
|
|
109
|
+
const fill = () => {
|
|
110
|
+
this.filling = false;
|
|
111
|
+
this.said = joinSaid(this.pending.said);
|
|
112
|
+
this.urgent = joinSaid(this.pending.urgent);
|
|
113
|
+
this.pending.said = [];
|
|
114
|
+
this.pending.urgent = [];
|
|
115
|
+
this.hush.start(1000, () => {
|
|
116
|
+
this.said = '';
|
|
117
|
+
this.urgent = '';
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
if (typeof requestAnimationFrame === 'function') {
|
|
121
|
+
requestAnimationFrame(fill);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
fill();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
tell(added) {
|
|
128
|
+
const showing = this.showing;
|
|
129
|
+
const arrived = added.filter((one) => one instanceof HTMLElement && showing.includes(one));
|
|
130
|
+
if (arrived.length === 0) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (this.blocked()) {
|
|
134
|
+
this.notify(arrived);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
this.announce(arrived);
|
|
138
|
+
}
|
|
91
139
|
}
|
|
92
140
|
add(message, options = {}) {
|
|
93
141
|
const tier = this.constructor.tier;
|
|
@@ -121,8 +169,7 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
121
169
|
continue;
|
|
122
170
|
}
|
|
123
171
|
this.made.delete(one);
|
|
124
|
-
|
|
125
|
-
void Promise.allSettled(running.map((animation) => animation.finished)).then(() => one.remove());
|
|
172
|
+
void animationsFinished(one).then(() => one.remove());
|
|
126
173
|
}
|
|
127
174
|
}
|
|
128
175
|
get showing() {
|
|
@@ -152,13 +199,9 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
152
199
|
if (!open || blocked) {
|
|
153
200
|
region.showPopover();
|
|
154
201
|
}
|
|
155
|
-
if (blocked) {
|
|
156
|
-
this.notify(arrived);
|
|
157
|
-
}
|
|
158
202
|
}
|
|
159
203
|
lowerWhenStill(region) {
|
|
160
|
-
|
|
161
|
-
void Promise.allSettled(running.map((one) => one.finished)).then(() => {
|
|
204
|
+
void animationsFinished(this).then(() => {
|
|
162
205
|
if (this.showing.length === 0 && popoverOpen(region)) {
|
|
163
206
|
region.hidePopover();
|
|
164
207
|
}
|
|
@@ -182,9 +225,9 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
182
225
|
return;
|
|
183
226
|
}
|
|
184
227
|
for (const one of arrived) {
|
|
185
|
-
const words = (one
|
|
228
|
+
const words = messageWords(one);
|
|
186
229
|
if (words !== '') {
|
|
187
|
-
speaker.ariaNotify(words);
|
|
230
|
+
speaker.ariaNotify(words, { priority: isDanger(one) ? 'high' : 'normal' });
|
|
188
231
|
}
|
|
189
232
|
}
|
|
190
233
|
}
|
|
@@ -194,7 +237,9 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
194
237
|
this.addEventListener('helix-dismiss', this.handleDismiss);
|
|
195
238
|
document.addEventListener('keydown', this.handleHotkey);
|
|
196
239
|
this.watcher = new MutationObserver((records) => {
|
|
197
|
-
|
|
240
|
+
const added = records.flatMap((record) => [...record.addedNodes]);
|
|
241
|
+
this.place(added);
|
|
242
|
+
this.tell(added);
|
|
198
243
|
this.sweep();
|
|
199
244
|
});
|
|
200
245
|
this.watcher.observe(this, {
|
|
@@ -220,7 +265,7 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
220
265
|
this.place();
|
|
221
266
|
}
|
|
222
267
|
render() {
|
|
223
|
-
return html `<div part="region" popover="manual" tabindex="-1"><slot></slot></div>`;
|
|
268
|
+
return html `<div part="region" popover="manual" tabindex="-1"><slot></slot><span part="live" role="status">${this.said}</span><span part="live" role="alert">${this.urgent}</span></div>`;
|
|
224
269
|
}
|
|
225
270
|
};
|
|
226
271
|
__decorate([
|
|
@@ -232,10 +277,17 @@ __decorate([
|
|
|
232
277
|
__decorate([
|
|
233
278
|
property({ reflect: true })
|
|
234
279
|
], HelixHeadlessToast.prototype, "placement", void 0);
|
|
280
|
+
__decorate([
|
|
281
|
+
state()
|
|
282
|
+
], HelixHeadlessToast.prototype, "said", void 0);
|
|
283
|
+
__decorate([
|
|
284
|
+
state()
|
|
285
|
+
], HelixHeadlessToast.prototype, "urgent", void 0);
|
|
235
286
|
HelixHeadlessToast = __decorate([
|
|
236
287
|
customElement('helix-headless-toast')
|
|
237
288
|
], HelixHeadlessToast);
|
|
238
289
|
export { HelixHeadlessToast };
|
|
290
|
+
const isDanger = (item) => (item.tone ?? item.getAttribute('tone')) === 'danger';
|
|
239
291
|
const popoverOpen = (region) => {
|
|
240
292
|
try {
|
|
241
293
|
return region.matches(':popover-open');
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pieces of a message joined into one line a screen reader says, with a full
|
|
3
|
+
* stop between two where the first does not already end a sentence, so a
|
|
4
|
+
* heading and its detail are heard as two sentences and not run together.
|
|
5
|
+
*/
|
|
6
|
+
export declare const joinSaid: (pieces: readonly string[]) => string;
|
|
7
|
+
/**
|
|
8
|
+
* What a message says as it arrives: the word for its tone, then its heading,
|
|
9
|
+
* its description and its text, and never its actions or its dismiss control,
|
|
10
|
+
* which a reader finds by moving into the message.
|
|
11
|
+
*/
|
|
12
|
+
export declare const messageWords: (item: Element) => string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { toneMark } from '@fusion.dev/helix-core';
|
|
2
|
+
const UNSAID = new Set(['actions', 'dismiss-icon', 'icon']);
|
|
3
|
+
export const joinSaid = (pieces) => pieces
|
|
4
|
+
.map((piece) => piece.replace(/\s+/gu, ' ').trim())
|
|
5
|
+
.filter((piece) => piece !== '')
|
|
6
|
+
.reduce((line, piece) => line === '' ? piece : `${line}${/[.!?:;]$/u.test(line) ? '' : '.'} ${piece}`, '');
|
|
7
|
+
export const messageWords = (item) => {
|
|
8
|
+
const tone = item.tone ?? item.getAttribute('tone') ?? undefined;
|
|
9
|
+
const label = toneMark(tone)?.label;
|
|
10
|
+
const heading = [];
|
|
11
|
+
const rest = [];
|
|
12
|
+
for (const node of item.childNodes) {
|
|
13
|
+
if (node instanceof Element) {
|
|
14
|
+
const slot = node.getAttribute('slot') ?? '';
|
|
15
|
+
if (!UNSAID.has(slot)) {
|
|
16
|
+
;
|
|
17
|
+
(slot === 'heading' ? heading : rest).push(node.textContent ?? '');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
else if (node.nodeType === 3) {
|
|
21
|
+
rest.push(node.textContent ?? '');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return joinSaid([...(label ? [label] : []), ...heading, ...rest]);
|
|
25
|
+
};
|