@fusion.dev/helix-headless 0.142.1 → 0.144.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 +25381 -1202
- package/dist/accordion/item/accordion-item.d.ts +38 -2
- package/dist/accordion/item/accordion-item.js +38 -6
- package/dist/accordion/root/accordion-root.d.ts +23 -1
- package/dist/accordion/root/accordion-root.js +39 -3
- package/dist/announcement/root/announcement-root.d.ts +11 -7
- package/dist/announcement/root/announcement-root.js +1 -1
- package/dist/app-header/root/app-header-root.d.ts +21 -0
- package/dist/app-header/root/app-header-root.js +31 -5
- package/dist/area-chart/root/area-chart-root.d.ts +12 -4
- package/dist/area-chart/root/area-chart-root.js +39 -11
- package/dist/avatar/group/avatar-group.d.ts +24 -3
- package/dist/avatar/group/avatar-group.js +34 -2
- package/dist/avatar/root/avatar-root.d.ts +17 -1
- package/dist/avatar/root/avatar-root.js +31 -10
- package/dist/badge/root/badge-root.d.ts +12 -0
- package/dist/badge/root/badge-root.js +1 -1
- package/dist/bar-chart/root/bar-chart-root.d.ts +30 -5
- package/dist/bar-chart/root/bar-chart-root.js +58 -21
- package/dist/blockquote/root/blockquote-root.d.ts +12 -7
- package/dist/blockquote/root/blockquote-root.js +6 -4
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +9 -3
- package/dist/breadcrumbs/root/breadcrumbs-root.js +9 -1
- package/dist/button/root/button-root.d.ts +84 -1
- package/dist/button/root/button-root.js +81 -3
- package/dist/callout/root/callout-root.d.ts +32 -6
- package/dist/callout/root/callout-root.js +26 -7
- package/dist/canvas/root/canvas-root.d.ts +1 -0
- package/dist/canvas/root/canvas-root.js +10 -1
- package/dist/card/root/card-root.d.ts +30 -1
- package/dist/card/root/card-root.js +38 -5
- package/dist/carousel/root/carousel-root.d.ts +47 -5
- package/dist/carousel/root/carousel-root.js +53 -21
- package/dist/chat/composer/chat-composer.d.ts +13 -11
- package/dist/chat/composer/chat-composer.js +6 -12
- package/dist/chat/message/chat-message.js +8 -1
- package/dist/chat/root/chat-root.d.ts +1 -0
- package/dist/chat/root/chat-root.js +2 -1
- package/dist/checkbox/root/checkbox-root.d.ts +7 -0
- package/dist/checkbox/root/checkbox-root.js +9 -3
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +116 -33
- package/dist/checkbox-group/root/checkbox-group-root.js +141 -44
- package/dist/code/root/code-root.d.ts +1 -1
- package/dist/code-block/lines.d.ts +13 -0
- package/dist/code-block/lines.js +2 -0
- package/dist/code-block/root/code-block-root.d.ts +49 -0
- package/dist/code-block/root/code-block-root.js +44 -3
- package/dist/color-input/root/color-input-root.d.ts +60 -2
- package/dist/color-input/root/color-input-root.js +55 -7
- package/dist/color-picker/channels.d.ts +26 -0
- package/dist/color-picker/channels.js +84 -0
- package/dist/color-picker/root/color-picker-root.d.ts +118 -12
- package/dist/color-picker/root/color-picker-root.js +183 -13
- package/dist/combobox/root/combobox-root.d.ts +126 -3
- package/dist/combobox/root/combobox-root.js +224 -21
- package/dist/command/root/command-root.d.ts +47 -10
- package/dist/command/root/command-root.js +45 -4
- package/dist/copy-button/from.d.ts +22 -0
- package/dist/copy-button/from.js +28 -0
- package/dist/copy-button/root/copy-button-root.d.ts +48 -7
- package/dist/copy-button/root/copy-button-root.js +54 -8
- package/dist/data-table/root/data-table-root.d.ts +164 -10
- package/dist/data-table/root/data-table-root.js +488 -57
- package/dist/date-input/root/date-input-root.d.ts +123 -9
- package/dist/date-input/root/date-input-root.js +147 -45
- package/dist/date-picker/root/date-picker-root.d.ts +229 -18
- package/dist/date-picker/root/date-picker-root.js +342 -46
- package/dist/dialog/description.d.ts +9 -0
- package/dist/dialog/description.js +14 -0
- package/dist/dialog/root/dialog-root.d.ts +101 -10
- package/dist/dialog/root/dialog-root.js +83 -4
- package/dist/donut-chart/root/donut-chart-root.d.ts +61 -16
- package/dist/donut-chart/root/donut-chart-root.js +48 -13
- package/dist/drawer/root/drawer-root.d.ts +93 -7
- package/dist/drawer/root/drawer-root.js +126 -5
- package/dist/drawer/swipe-start.d.ts +9 -0
- package/dist/drawer/swipe-start.js +12 -0
- package/dist/drilldown/item/drilldown-item.d.ts +16 -13
- package/dist/drilldown/item/drilldown-item.js +6 -2
- package/dist/drilldown/root/drilldown-root.d.ts +21 -5
- package/dist/drilldown/root/drilldown-root.js +26 -10
- package/dist/element-events.generated.js +42 -13
- package/dist/empty/root/empty-root.d.ts +1 -1
- package/dist/file-input/root/file-input-root.d.ts +65 -1
- package/dist/file-input/root/file-input-root.js +76 -12
- package/dist/file-input/screen.d.ts +35 -0
- package/dist/file-input/screen.js +49 -0
- package/dist/filter-input/menu/filter-menu.d.ts +9 -0
- package/dist/filter-input/menu/filter-menu.js +8 -0
- package/dist/filter-input/root/filter-input-root.d.ts +43 -6
- package/dist/filter-input/root/filter-input-root.js +89 -10
- package/dist/filter-input/suggest.d.ts +17 -0
- package/dist/filter-input/suggest.js +23 -0
- package/dist/format-date/options.d.ts +33 -0
- package/dist/format-date/options.js +42 -0
- package/dist/format-date/root/format-date-root.d.ts +62 -3
- package/dist/format-date/root/format-date-root.js +78 -37
- package/dist/graph/root/graph-root.d.ts +24 -3
- package/dist/graph/root/graph-root.js +66 -12
- package/dist/heatmap/root/buckets.d.ts +2 -1
- package/dist/heatmap/root/buckets.js +5 -1
- package/dist/heatmap/root/heatmap-root.d.ts +47 -9
- package/dist/heatmap/root/heatmap-root.js +46 -18
- package/dist/icon/index.d.ts +2 -0
- package/dist/icon/index.js +2 -0
- package/dist/icon/registry.d.ts +37 -0
- package/dist/icon/registry.js +83 -0
- package/dist/icon/root/icon-root.d.ts +53 -6
- package/dist/icon/root/icon-root.js +72 -4
- package/dist/icon/root/index.d.ts +2 -0
- package/dist/icon/root/index.js +2 -0
- package/dist/icon/set.d.ts +1 -0
- package/dist/icon/set.js +3 -0
- package/dist/icon-button/root/icon-button-root.d.ts +1 -1
- package/dist/image/root/image-root.d.ts +23 -2
- package/dist/image/root/image-root.js +23 -4
- package/dist/input/root/input-root.d.ts +62 -9
- package/dist/input/root/input-root.js +61 -5
- package/dist/kbd/root/kbd-root.d.ts +26 -11
- package/dist/kbd/root/kbd-root.js +35 -38
- package/dist/kbd/shortcut.d.ts +18 -0
- package/dist/kbd/shortcut.js +35 -0
- package/dist/legend/hidden-series.d.ts +8 -0
- package/dist/legend/hidden-series.js +13 -0
- package/dist/legend/root/legend-root.d.ts +63 -0
- package/dist/legend/root/legend-root.js +61 -7
- package/dist/lightbox/item/lightbox-item.d.ts +17 -1
- package/dist/lightbox/item/lightbox-item.js +10 -1
- package/dist/lightbox/root/lightbox-root.d.ts +77 -6
- package/dist/lightbox/root/lightbox-root.js +116 -5
- package/dist/line-chart/root/line-chart-root.d.ts +29 -4
- package/dist/line-chart/root/line-chart-root.js +58 -17
- package/dist/list/item/list-item.d.ts +11 -5
- package/dist/list/item/list-item.js +5 -6
- package/dist/listbox/range.d.ts +17 -0
- package/dist/listbox/range.js +5 -0
- package/dist/listbox/root/listbox-root.d.ts +184 -4
- package/dist/listbox/root/listbox-root.js +229 -23
- package/dist/loader/busy.d.ts +17 -0
- package/dist/loader/busy.js +24 -0
- package/dist/loader/root/loader-root.d.ts +37 -0
- package/dist/loader/root/loader-root.js +52 -3
- package/dist/map/root/map-root.d.ts +19 -4
- package/dist/map/root/map-root.js +36 -7
- package/dist/megamenu/root/megamenu-root.d.ts +10 -1
- package/dist/megamenu/root/megamenu-root.js +10 -1
- package/dist/menu/item/menu-item.d.ts +41 -12
- package/dist/menu/item/menu-item.js +46 -3
- package/dist/menu/root/menu-root.d.ts +32 -2
- package/dist/menu/root/menu-root.js +48 -8
- package/dist/meter/root/meter-root.d.ts +13 -0
- package/dist/meter/root/meter-root.js +24 -5
- package/dist/navigation/root/navigation-root.d.ts +10 -2
- package/dist/navigation/root/navigation-root.js +13 -2
- package/dist/notifications/feed-keys.d.ts +10 -0
- package/dist/notifications/feed-keys.js +14 -0
- package/dist/notifications/group/notification-group.d.ts +1 -0
- package/dist/notifications/notification/notification.d.ts +29 -0
- package/dist/notifications/notification/notification.js +51 -3
- package/dist/notifications/root/notifications-root.d.ts +49 -0
- package/dist/notifications/root/notifications-root.js +76 -2
- package/dist/number-input/root/number-input-root.d.ts +109 -7
- package/dist/number-input/root/number-input-root.js +109 -21
- package/dist/object-inspector/root/object-inspector-root.d.ts +49 -5
- package/dist/object-inspector/root/object-inspector-root.js +92 -12
- package/dist/option/root/option-root.d.ts +58 -6
- package/dist/option/root/option-root.js +35 -5
- package/dist/outline/root/outline-root.d.ts +13 -2
- package/dist/outline/root/outline-root.js +4 -2
- package/dist/pagination/root/pagination-root.d.ts +19 -1
- package/dist/pagination/root/pagination-root.js +49 -9
- package/dist/pagination/size/pagination-size.d.ts +13 -3
- package/dist/pagination/size/pagination-size.js +7 -0
- package/dist/pin-input/format.d.ts +7 -0
- package/dist/pin-input/format.js +16 -0
- package/dist/pin-input/root/pin-input-root.d.ts +37 -0
- package/dist/pin-input/root/pin-input-root.js +48 -7
- package/dist/popover/root/popover-root.d.ts +78 -3
- package/dist/popover/root/popover-root.js +74 -5
- package/dist/progress/root/progress-root.d.ts +23 -1
- package/dist/progress/root/progress-root.js +40 -10
- package/dist/qr-code/export.d.ts +31 -0
- package/dist/qr-code/export.js +10 -0
- package/dist/qr-code/root/qr-code-root.d.ts +45 -0
- package/dist/qr-code/root/qr-code-root.js +78 -3
- package/dist/radio/group/radio-group.d.ts +64 -0
- package/dist/radio/group/radio-group.js +66 -12
- package/dist/radio/root/radio-root.d.ts +8 -5
- package/dist/radio/root/radio-root.js +1 -2
- package/dist/rating/root/rating-root.d.ts +49 -1
- package/dist/rating/root/rating-root.js +69 -10
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
- package/dist/scatter-chart/root/scatter-chart-root.js +40 -14
- package/dist/select/root/select-root.d.ts +93 -3
- package/dist/select/root/select-root.js +111 -13
- package/dist/skeleton/root/skeleton-root.d.ts +39 -3
- package/dist/skeleton/root/skeleton-root.js +33 -4
- package/dist/skip-link/root/skip-link-root.d.ts +10 -0
- package/dist/skip-link/root/skip-link-root.js +15 -1
- package/dist/slider/root/slider-root.d.ts +59 -2
- package/dist/slider/root/slider-root.js +82 -8
- package/dist/sparkline/root/sparkline-root.d.ts +9 -10
- package/dist/speed-dial/item/speed-dial-item.d.ts +11 -5
- package/dist/speed-dial/item/speed-dial-item.js +7 -2
- package/dist/speed-dial/root/speed-dial-root.d.ts +15 -4
- package/dist/speed-dial/root/speed-dial-root.js +19 -5
- package/dist/splitter/root/splitter-root.d.ts +28 -6
- package/dist/splitter/root/splitter-root.js +35 -1
- package/dist/stat/root/stat-root.d.ts +9 -1
- package/dist/stat/root/stat-root.js +15 -2
- package/dist/steps/root/steps-root.js +1 -1
- package/dist/steps/step/step.d.ts +1 -0
- package/dist/steps/step/step.js +1 -1
- package/dist/switch/root/switch-root.d.ts +14 -2
- package/dist/switch/root/switch-root.js +7 -1
- package/dist/table/cell/table-cell.d.ts +24 -4
- package/dist/table/cell/table-cell.js +21 -1
- package/dist/table/column/table-column.d.ts +32 -6
- package/dist/table/column/table-column.js +36 -6
- package/dist/table/root/table-root.d.ts +94 -3
- package/dist/table/root/table-root.js +128 -5
- package/dist/table/row/table-row.d.ts +7 -0
- package/dist/table/row/table-row.js +9 -1
- package/dist/tabs/root/tabs-root.d.ts +6 -1
- package/dist/tabs/root/tabs-root.js +6 -2
- package/dist/tag/group/tag-group.d.ts +107 -0
- package/dist/tag/group/tag-group.js +157 -0
- package/dist/tag/index.d.ts +1 -0
- package/dist/tag/index.js +1 -0
- package/dist/tag/root/tag-root.d.ts +83 -1
- package/dist/tag/root/tag-root.js +87 -17
- package/dist/tag/selection.d.ts +10 -0
- package/dist/tag/selection.js +12 -0
- package/dist/textarea/grow.d.ts +22 -0
- package/dist/textarea/grow.js +20 -0
- package/dist/textarea/root/textarea-root.d.ts +13 -0
- package/dist/textarea/root/textarea-root.js +10 -2
- package/dist/time-input/root/time-input-root.d.ts +71 -6
- package/dist/time-input/root/time-input-root.js +110 -44
- package/dist/time-picker/root/time-picker-root.d.ts +155 -26
- package/dist/time-picker/root/time-picker-root.js +192 -63
- package/dist/toast/hotkey.d.ts +22 -0
- package/dist/toast/hotkey.js +23 -0
- package/dist/toast/item/toast-item.d.ts +16 -1
- package/dist/toast/item/toast-item.js +41 -13
- package/dist/toast/root/toast-root.d.ts +105 -8
- package/dist/toast/root/toast-root.js +209 -4
- package/dist/toggle/group/toggle-group.d.ts +95 -16
- package/dist/toggle/group/toggle-group.js +99 -13
- package/dist/toggle/root/toggle-root.d.ts +26 -11
- package/dist/toggle/root/toggle-root.js +14 -6
- package/dist/toolbar/root/toolbar-root.d.ts +55 -15
- package/dist/toolbar/root/toolbar-root.js +99 -16
- package/dist/tooltip/focus-target.d.ts +6 -0
- package/dist/tooltip/focus-target.js +9 -0
- package/dist/tooltip/root/tooltip-root.d.ts +73 -15
- package/dist/tooltip/root/tooltip-root.js +96 -7
- package/dist/tour/naming.d.ts +30 -0
- package/dist/tour/naming.js +10 -0
- package/dist/tour/root/tour-root.d.ts +67 -3
- package/dist/tour/root/tour-root.js +105 -17
- package/dist/tour/stop/tour-stop.d.ts +65 -3
- package/dist/tour/stop/tour-stop.js +61 -11
- package/dist/tour/wait.d.ts +11 -0
- package/dist/tour/wait.js +19 -0
- package/dist/tree/item/tree-item.d.ts +21 -5
- package/dist/tree/item/tree-item.js +14 -4
- package/dist/tree/root/tree-root.d.ts +29 -5
- package/dist/tree/root/tree-root.js +64 -8
- package/dist/trend/root/trend-root.d.ts +36 -1
- package/dist/trend/root/trend-root.js +41 -15
- package/dist/video/root/keys.d.ts +5 -0
- package/dist/video/root/keys.js +13 -1
- package/dist/video/root/video-root.d.ts +19 -0
- package/dist/video/root/video-root.js +48 -4
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +20 -2
- package/dist/video-playlist/menu/video-playlist-menu.js +27 -5
- package/dist/video-playlist/root/video-playlist-root.js +6 -3
- package/dist/virtual-list/root/virtual-list-root.d.ts +52 -4
- package/dist/virtual-list/root/virtual-list-root.js +103 -21
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +9140 -1149
- package/types/svelte.d.ts +1 -0
- package/types/vue.d.ts +2089 -267
|
@@ -9,9 +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
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* **The region is a landmark named by `label`, and a polite live region.** A
|
|
13
|
+
* `danger` message is announced assertively, and every other one politely.
|
|
14
|
+
* Each message is an `alertdialog` named by its words, so a reader who moves
|
|
15
|
+
* into the stack hears which message they are on.
|
|
16
|
+
*
|
|
17
|
+
* **`hotkey` takes focus to the stack and back**, F8 unless you set it, and
|
|
18
|
+
* `label` says which key: `{hotkey}` in it is filled in, so the default name
|
|
19
|
+
* is "Notifications (F8)". Pressed while focus is in the stack, it gives focus
|
|
20
|
+
* back to where it was.
|
|
15
21
|
*
|
|
16
22
|
* **The region never creates or removes items.** You render items and remove
|
|
17
23
|
* them. An item requests closing with a cancelable `helix-dismiss` event. A
|
|
@@ -19,9 +25,24 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
19
25
|
* and the DOM stay in sync. It hides on its own unless you set `open`, which
|
|
20
26
|
* makes the state yours.
|
|
21
27
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
28
|
+
* **`add()` shows a message from script**, for a page with no framework state
|
|
29
|
+
* to render them from: it appends a message of the region's own tier and
|
|
30
|
+
* removes it once it has been dismissed and has finished leaving. Messages
|
|
31
|
+
* you render yourself stay yours, and the region never removes them. A touch
|
|
32
|
+
* or a pen swipes a message away toward the end of the line.
|
|
33
|
+
*
|
|
34
|
+
* **The stack is in the top layer.** The `region` part is a `popover="manual"`
|
|
35
|
+
* shown while a message is showing, and shown again above a modal dialog that
|
|
36
|
+
* opened after it. Position the `region` part, which is the box in the top
|
|
37
|
+
* layer. While a modal `Dialog`, `Drawer` or `Lightbox` is open, the browser
|
|
38
|
+
* makes everything outside it inert, the stack included, so a message stays
|
|
39
|
+
* visible and its actions cannot be pressed. Where the browser has
|
|
40
|
+
* `ariaNotify`, a message that arrives then is announced through it. For a
|
|
41
|
+
* message with an action, render a second region inside the dialog.
|
|
42
|
+
*
|
|
43
|
+
* When a message with focus inside it is dismissed, focus moves to the next
|
|
44
|
+
* message, then the one before it, then back to where it was before it entered
|
|
45
|
+
* the stack.
|
|
25
46
|
*
|
|
26
47
|
* @since 0.1.0
|
|
27
48
|
* @status stable
|
|
@@ -33,11 +54,17 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
33
54
|
*
|
|
34
55
|
* @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.
|
|
35
56
|
*
|
|
36
|
-
* @csspart region - The stack the messages are in.
|
|
57
|
+
* @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.
|
|
37
58
|
*/
|
|
38
59
|
export declare class HelixHeadlessToast extends HelixElement {
|
|
39
60
|
/**
|
|
40
|
-
*
|
|
61
|
+
* The key that takes focus to the stack and back, such as `F8` or `Alt+T`:
|
|
62
|
+
* keys joined by `+`, the last one the key. Empty turns it off.
|
|
63
|
+
*/
|
|
64
|
+
hotkey: string;
|
|
65
|
+
/**
|
|
66
|
+
* Accessible name for the region, with `{hotkey}` filled in. Translate it with
|
|
67
|
+
* the rest of your interface.
|
|
41
68
|
*/
|
|
42
69
|
label: string;
|
|
43
70
|
/**
|
|
@@ -68,6 +95,76 @@ export declare class HelixHeadlessToast extends HelixElement {
|
|
|
68
95
|
*/
|
|
69
96
|
placement?: 'bottom-center' | 'bottom-end' | 'bottom-start' | 'top-center' | 'top-end' | 'top-start';
|
|
70
97
|
protected willUpdate(changed: PropertyValues): void;
|
|
98
|
+
/** The element focus came from when it entered the stack. */
|
|
99
|
+
private focusOrigin;
|
|
100
|
+
private readonly scope;
|
|
101
|
+
/** Takes focus to the stack and back, on `hotkey`. */
|
|
102
|
+
private readonly handleHotkey;
|
|
103
|
+
/** Messages `add()` made, which are the region's to remove. */
|
|
104
|
+
private readonly made;
|
|
105
|
+
/**
|
|
106
|
+
* Shows a message from script, and returns the element.
|
|
107
|
+
*
|
|
108
|
+
* The message is the region's own tier of `Toast.Item`, appended to the
|
|
109
|
+
* stack, holding `message` as its text. The region removes it once it has
|
|
110
|
+
* been dismissed and has finished leaving, which is the one case where it
|
|
111
|
+
* removes anything: a message you render stays yours.
|
|
112
|
+
*/
|
|
113
|
+
add(message: string, options?: {
|
|
114
|
+
dismissible?: boolean;
|
|
115
|
+
duration?: number;
|
|
116
|
+
tone?: 'danger' | 'info' | 'success' | 'warning';
|
|
117
|
+
}): HTMLElement;
|
|
118
|
+
/** Removes a message `add()` made, once it has hidden and finished leaving. */
|
|
119
|
+
private sweep;
|
|
120
|
+
/** Watches the messages arrive and hide, to raise or lower the stack. */
|
|
121
|
+
private watcher;
|
|
122
|
+
/** The messages that are showing, in order. */
|
|
123
|
+
private get showing();
|
|
124
|
+
private get region();
|
|
125
|
+
/**
|
|
126
|
+
* Puts the stack in the top layer while a message shows, and on top of it.
|
|
127
|
+
*
|
|
128
|
+
* Shown again when a message arrives under a modal opened after it, because
|
|
129
|
+
* the top layer is ordered by when each element entered it. Only then,
|
|
130
|
+
* because showing it again starts every message's entrance over.
|
|
131
|
+
*/
|
|
132
|
+
private place;
|
|
133
|
+
/**
|
|
134
|
+
* Takes the stack out of the top layer once the last message has finished
|
|
135
|
+
* leaving. Hidden at once, the stack would cut the exit short.
|
|
136
|
+
*/
|
|
137
|
+
private lowerWhenStill;
|
|
138
|
+
/**
|
|
139
|
+
* Whether a modal dialog this stack is not inside is open, which makes the
|
|
140
|
+
* stack inert.
|
|
141
|
+
*
|
|
142
|
+
* Two places to look: the modal `Dialog` and `Drawer` the scroll lock
|
|
143
|
+
* records, whose `<dialog>` is in a shadow root, and an open modal `<dialog>`
|
|
144
|
+
* in the document itself.
|
|
145
|
+
*/
|
|
146
|
+
private blocked;
|
|
147
|
+
/**
|
|
148
|
+
* Announces messages that arrived while the live region is inert.
|
|
149
|
+
*
|
|
150
|
+
* `ariaNotify` speaks without a live region in the accessibility tree, which
|
|
151
|
+
* is the one channel left under a modal. A browser without it says nothing,
|
|
152
|
+
* as it did before.
|
|
153
|
+
*/
|
|
154
|
+
private notify;
|
|
155
|
+
/** Remembers where focus came from when it enters the stack. */
|
|
156
|
+
private readonly handleFocusIn;
|
|
157
|
+
/**
|
|
158
|
+
* Keeps focus on the stack when the message holding it goes.
|
|
159
|
+
*
|
|
160
|
+
* Read after the item's update, because the dismissal is a request a
|
|
161
|
+
* listener after this one can still refuse. A refused one leaves the
|
|
162
|
+
* message, and focus with it.
|
|
163
|
+
*/
|
|
164
|
+
private readonly handleDismiss;
|
|
165
|
+
connectedCallback(): void;
|
|
166
|
+
disconnectedCallback(): void;
|
|
167
|
+
protected firstUpdated(changed: PropertyValues): void;
|
|
71
168
|
protected render(): TemplateResult;
|
|
72
169
|
}
|
|
73
170
|
declare global {
|
|
@@ -4,25 +4,219 @@ 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, deepActiveElement, deepContains, FocusScopeController, fillTemplate, focusableElements, HelixElement, hostAria, scrollHolders, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
+
import { matchesHotkey, parseHotkey } from '../hotkey.js';
|
|
10
11
|
let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
11
12
|
constructor() {
|
|
12
13
|
super(...arguments);
|
|
13
|
-
this.
|
|
14
|
+
this.hotkey = 'F8';
|
|
15
|
+
this.label = 'Notifications ({hotkey})';
|
|
16
|
+
this.scope = new FocusScopeController(this, {
|
|
17
|
+
contents: () => this.showing.flatMap((one) => {
|
|
18
|
+
const target = focusTarget(one);
|
|
19
|
+
return target ? [target] : [];
|
|
20
|
+
}),
|
|
21
|
+
surface: () => this.region,
|
|
22
|
+
});
|
|
23
|
+
this.handleHotkey = (event) => {
|
|
24
|
+
if (event.defaultPrevented || !matchesHotkey(event, parseHotkey(this.hotkey))) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (this.scope.holdsFocus) {
|
|
28
|
+
event.preventDefault();
|
|
29
|
+
this.scope.leave();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (this.showing.length > 0) {
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
this.scope.enter();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
this.made = new WeakSet();
|
|
38
|
+
this.handleFocusIn = (event) => {
|
|
39
|
+
const from = event.relatedTarget;
|
|
40
|
+
if (from instanceof HTMLElement && !deepContains(this, from)) {
|
|
41
|
+
this.focusOrigin = from;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
this.handleDismiss = (event) => {
|
|
45
|
+
const item = event.target;
|
|
46
|
+
if (!(item instanceof HTMLElement) || item.parentElement !== this) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (!deepContains(item, deepActiveElement())) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const before = this.showing;
|
|
53
|
+
const at = before.indexOf(item);
|
|
54
|
+
void Promise.resolve()
|
|
55
|
+
.then(() => item.updateComplete)
|
|
56
|
+
.then(() => {
|
|
57
|
+
if (!item.hidden) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const active = deepActiveElement();
|
|
61
|
+
if (active && active !== document.body && !deepContains(item, active)) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const after = before.slice(at + 1).filter((one) => !one.hidden);
|
|
65
|
+
const earlier = before
|
|
66
|
+
.slice(0, at)
|
|
67
|
+
.filter((one) => !one.hidden)
|
|
68
|
+
.reverse();
|
|
69
|
+
for (const next of [...after, ...earlier]) {
|
|
70
|
+
const target = focusTarget(next);
|
|
71
|
+
if (target) {
|
|
72
|
+
target.focus();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (this.focusOrigin?.isConnected) {
|
|
77
|
+
this.focusOrigin.focus();
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
};
|
|
14
81
|
}
|
|
15
82
|
willUpdate(changed) {
|
|
16
83
|
super.willUpdate(changed);
|
|
17
|
-
hostAria(this.internals, {
|
|
84
|
+
hostAria(this.internals, {
|
|
85
|
+
label: fillTemplate(this.label, { hotkey: this.hotkey }),
|
|
86
|
+
role: 'region',
|
|
87
|
+
});
|
|
18
88
|
this.internals.ariaLive = 'polite';
|
|
19
89
|
this.internals.ariaRelevant = 'additions';
|
|
20
90
|
this.internals.ariaAtomic = 'false';
|
|
21
91
|
}
|
|
92
|
+
add(message, options = {}) {
|
|
93
|
+
const tier = this.constructor.tier;
|
|
94
|
+
const item = document.createElement(`${tier}toast-item`);
|
|
95
|
+
item.textContent = message;
|
|
96
|
+
if (options.tone) {
|
|
97
|
+
item.setAttribute('tone', options.tone);
|
|
98
|
+
}
|
|
99
|
+
if (options.duration !== undefined) {
|
|
100
|
+
item.setAttribute('duration', String(options.duration));
|
|
101
|
+
}
|
|
102
|
+
if (options.dismissible ?? true) {
|
|
103
|
+
item.toggleAttribute('dismissible', true);
|
|
104
|
+
}
|
|
105
|
+
this.made.add(item);
|
|
106
|
+
this.append(item);
|
|
107
|
+
return item;
|
|
108
|
+
}
|
|
109
|
+
sweep() {
|
|
110
|
+
for (const one of [...this.children]) {
|
|
111
|
+
if (!(one instanceof HTMLElement) || !one.hidden || !this.made.has(one)) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
this.made.delete(one);
|
|
115
|
+
const running = typeof one.getAnimations === 'function' ? one.getAnimations({ subtree: true }) : [];
|
|
116
|
+
void Promise.allSettled(running.map((animation) => animation.finished)).then(() => one.remove());
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
get showing() {
|
|
120
|
+
return [...this.children].filter((one) => one instanceof HTMLElement && !one.hidden);
|
|
121
|
+
}
|
|
122
|
+
get region() {
|
|
123
|
+
return this.partNamed('region');
|
|
124
|
+
}
|
|
125
|
+
place(added = []) {
|
|
126
|
+
const region = this.region;
|
|
127
|
+
if (!region || typeof region.showPopover !== 'function') {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const showing = this.showing;
|
|
131
|
+
const open = popoverOpen(region);
|
|
132
|
+
if (showing.length === 0) {
|
|
133
|
+
if (open) {
|
|
134
|
+
this.lowerWhenStill(region);
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const arrived = added.filter((one) => one instanceof HTMLElement && showing.includes(one));
|
|
139
|
+
const blocked = arrived.length > 0 && this.blocked();
|
|
140
|
+
if (open && blocked) {
|
|
141
|
+
region.hidePopover();
|
|
142
|
+
}
|
|
143
|
+
if (!open || blocked) {
|
|
144
|
+
region.showPopover();
|
|
145
|
+
}
|
|
146
|
+
if (blocked) {
|
|
147
|
+
this.notify(arrived);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
lowerWhenStill(region) {
|
|
151
|
+
const running = typeof this.getAnimations === 'function' ? this.getAnimations({ subtree: true }) : [];
|
|
152
|
+
void Promise.allSettled(running.map((one) => one.finished)).then(() => {
|
|
153
|
+
if (this.showing.length === 0 && popoverOpen(region)) {
|
|
154
|
+
region.hidePopover();
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
blocked() {
|
|
159
|
+
const holders = scrollHolders();
|
|
160
|
+
try {
|
|
161
|
+
const native = document.querySelector('dialog:modal');
|
|
162
|
+
if (native) {
|
|
163
|
+
holders.push(native);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
}
|
|
168
|
+
return holders.some((holder) => !deepContains(holder, this));
|
|
169
|
+
}
|
|
170
|
+
notify(arrived) {
|
|
171
|
+
const speaker = document;
|
|
172
|
+
if (typeof speaker.ariaNotify !== 'function') {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
for (const one of arrived) {
|
|
176
|
+
const words = (one.textContent ?? '').replace(/\s+/gu, ' ').trim();
|
|
177
|
+
if (words !== '') {
|
|
178
|
+
speaker.ariaNotify(words);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
connectedCallback() {
|
|
183
|
+
super.connectedCallback();
|
|
184
|
+
this.addEventListener('focusin', this.handleFocusIn);
|
|
185
|
+
this.addEventListener('helix-dismiss', this.handleDismiss);
|
|
186
|
+
document.addEventListener('keydown', this.handleHotkey);
|
|
187
|
+
this.watcher = new MutationObserver((records) => {
|
|
188
|
+
this.place(records.flatMap((record) => [...record.addedNodes]));
|
|
189
|
+
this.sweep();
|
|
190
|
+
});
|
|
191
|
+
this.watcher.observe(this, {
|
|
192
|
+
attributeFilter: ['hidden'],
|
|
193
|
+
attributes: true,
|
|
194
|
+
childList: true,
|
|
195
|
+
subtree: true,
|
|
196
|
+
});
|
|
197
|
+
if (this.hasUpdated) {
|
|
198
|
+
this.place();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
disconnectedCallback() {
|
|
202
|
+
super.disconnectedCallback();
|
|
203
|
+
this.removeEventListener('focusin', this.handleFocusIn);
|
|
204
|
+
this.removeEventListener('helix-dismiss', this.handleDismiss);
|
|
205
|
+
document.removeEventListener('keydown', this.handleHotkey);
|
|
206
|
+
this.watcher?.disconnect();
|
|
207
|
+
this.watcher = undefined;
|
|
208
|
+
}
|
|
209
|
+
firstUpdated(changed) {
|
|
210
|
+
super.firstUpdated(changed);
|
|
211
|
+
this.place();
|
|
212
|
+
}
|
|
22
213
|
render() {
|
|
23
|
-
return html `<div part="region"><slot></slot></div>`;
|
|
214
|
+
return html `<div part="region" popover="manual" tabindex="-1"><slot></slot></div>`;
|
|
24
215
|
}
|
|
25
216
|
};
|
|
217
|
+
__decorate([
|
|
218
|
+
property()
|
|
219
|
+
], HelixHeadlessToast.prototype, "hotkey", void 0);
|
|
26
220
|
__decorate([
|
|
27
221
|
property()
|
|
28
222
|
], HelixHeadlessToast.prototype, "label", void 0);
|
|
@@ -33,3 +227,14 @@ HelixHeadlessToast = __decorate([
|
|
|
33
227
|
customElement('helix-headless-toast')
|
|
34
228
|
], HelixHeadlessToast);
|
|
35
229
|
export { HelixHeadlessToast };
|
|
230
|
+
const popoverOpen = (region) => {
|
|
231
|
+
try {
|
|
232
|
+
return region.matches(':popover-open');
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
const focusTarget = (item) => item.shadowRoot?.querySelector('[part="dismiss"]') ??
|
|
239
|
+
focusableElements(item)[0] ??
|
|
240
|
+
null;
|
|
@@ -14,6 +14,17 @@ declare const HelixHeadlessToggleGroup_base: (new (...args: any[]) => import("@f
|
|
|
14
14
|
* Measurement happens on the client, so the server renders the indicator hidden
|
|
15
15
|
* and it fades in once measured.
|
|
16
16
|
*
|
|
17
|
+
* `selection-mode="multiple"` makes the group a toolbar of buttons that each
|
|
18
|
+
* say whether they are pressed with `aria-pressed`, as React Aria's
|
|
19
|
+
* ToggleButtonGroup and Radix's ToggleGroup do. A press presses or releases
|
|
20
|
+
* one item, the arrow keys move focus without pressing, and `value` is the
|
|
21
|
+
* pressed values, comma separated, which `values` also gives as a list. The
|
|
22
|
+
* form receives one entry per pressed value. The indicator stays hidden, and
|
|
23
|
+
* each pressed item is marked with `:state(pressed)`.
|
|
24
|
+
*
|
|
25
|
+
* `orientation="vertical"` runs the items down a column, says so to the
|
|
26
|
+
* accessibility tree, and the up and down arrows move between them.
|
|
27
|
+
*
|
|
17
28
|
* @since 0.1.0
|
|
18
29
|
* @status stable
|
|
19
30
|
* @aliases SegmentedControl, Segmented, Navigation, Switcher
|
|
@@ -21,10 +32,13 @@ declare const HelixHeadlessToggleGroup_base: (new (...args: any[]) => import("@f
|
|
|
21
32
|
*
|
|
22
33
|
* @slot - The group's items.
|
|
23
34
|
* @slot end - Content after the track, on the same line, such as a count or a reset.
|
|
35
|
+
* @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
|
|
36
|
+
* @slot hint - Help under the control, for content richer than the `hint` text.
|
|
37
|
+
* @slot label - The label, for content richer than the `label` text.
|
|
24
38
|
* @slot start - Content before the track, on the same line, such as an icon or a caption.
|
|
25
39
|
*
|
|
26
40
|
* @event {Event} change - Fired after the value changes.
|
|
27
|
-
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before the choice changes. Cancelable: call `preventDefault()` to keep the current choice.
|
|
41
|
+
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before the choice changes. Cancelable: call `preventDefault()` to keep the current choice.
|
|
28
42
|
* @event {HelixSelectEvent} helix-select - Fired when an item is chosen. The item sends it, and you listen for it on the group. Cancelable: call `preventDefault()` to keep the current choice.
|
|
29
43
|
* @event {Event} input - Fired after the value changes.
|
|
30
44
|
*
|
|
@@ -85,16 +99,91 @@ export declare class HelixHeadlessToggleGroup extends HelixHeadlessToggleGroup_b
|
|
|
85
99
|
private adopt;
|
|
86
100
|
/** Marks the chosen item, separately from placing the indicator. */
|
|
87
101
|
private sync;
|
|
102
|
+
/**
|
|
103
|
+
* The item that holds the group's tab stop: the chosen one.
|
|
104
|
+
*
|
|
105
|
+
* With nothing chosen there is no selection to carry the tab stop, so the
|
|
106
|
+
* first item holds one until there is. Otherwise an unanswered group is a
|
|
107
|
+
* control the keyboard cannot enter, which is what the fallback was quietly
|
|
108
|
+
* also doing for it. A disabled answer takes no focus either, so the entry
|
|
109
|
+
* goes to the first item that can be chosen, as in `Radio.Group`.
|
|
110
|
+
*/
|
|
111
|
+
private entry;
|
|
112
|
+
/** The item focus was last on, in a toolbar, which holds its tab stop. */
|
|
113
|
+
private lastFocused;
|
|
114
|
+
private readonly noteFocus;
|
|
115
|
+
/** Whether several items can be pressed at once. */
|
|
116
|
+
private get multiple();
|
|
117
|
+
/**
|
|
118
|
+
* Whether the group holds a tab stop of its own.
|
|
119
|
+
*
|
|
120
|
+
* A toolbar is one tab stop, so a toolbar the group sits in sets this to
|
|
121
|
+
* `false` while its stop is on another control, and every item, the chosen
|
|
122
|
+
* one too, is then out of the tab order. The arrow keys inside the group
|
|
123
|
+
* work as before once focus is in it.
|
|
124
|
+
*
|
|
125
|
+
* No attribute: it is coordination between elements, and a consumer has no
|
|
126
|
+
* reason to set it.
|
|
127
|
+
*/
|
|
128
|
+
focusable: boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Where the group's label sits. `start` puts it on the track's line.
|
|
131
|
+
*
|
|
132
|
+
* Absent is above, which is what a field looks like and what almost every
|
|
133
|
+
* group wants. `start` is for a row of controls that are labeled rather than
|
|
134
|
+
* a form of fields: a toolbar reads as one line, and a label stacked over
|
|
135
|
+
* every group in it turns one row into two.
|
|
136
|
+
*
|
|
137
|
+
* **A placement rather than a slot, and that is the whole point of it.** A
|
|
138
|
+
* `start` slot would let a consumer put the word there, and would also let
|
|
139
|
+
* them put it there *instead of* setting `label`, which is the group's
|
|
140
|
+
* accessible name: the set would then be named for nobody using a screen
|
|
141
|
+
* reader while looking correct to everybody else. Worse, setting both draws
|
|
142
|
+
* it twice. One property moves the label the consumer already has to give,
|
|
143
|
+
* and cannot be used to remove it.
|
|
144
|
+
*/
|
|
145
|
+
labelPlacement?: 'start';
|
|
146
|
+
/**
|
|
147
|
+
* The direction the items run. `vertical` puts them in a column, and the up
|
|
148
|
+
* and down arrows move between them.
|
|
149
|
+
*
|
|
150
|
+
* Optional, so the attribute is absent until a consumer writes it.
|
|
151
|
+
*/
|
|
152
|
+
orientation?: 'horizontal' | 'vertical';
|
|
153
|
+
/**
|
|
154
|
+
* Whether one item is chosen, as a radio group, or several can be pressed,
|
|
155
|
+
* as a toolbar of buttons with `aria-pressed`.
|
|
156
|
+
*
|
|
157
|
+
* Optional, so the attribute is absent until a consumer writes it.
|
|
158
|
+
*/
|
|
159
|
+
selectionMode?: 'multiple' | 'single';
|
|
160
|
+
/**
|
|
161
|
+
* Focus goes to the item that holds the stop, and to the item that would
|
|
162
|
+
* hold it while a toolbar holds the stop instead, so a label press or a
|
|
163
|
+
* refused submission still lands in the group.
|
|
164
|
+
*/
|
|
165
|
+
protected get focusTarget(): HTMLElement | null;
|
|
88
166
|
private readonly indicator;
|
|
89
167
|
protected readonly keys: KeyboardNavigationController;
|
|
90
168
|
protected readonly cascade: DisabledCascadeController;
|
|
91
169
|
private get items();
|
|
92
170
|
private readonly handleSelection;
|
|
171
|
+
/**
|
|
172
|
+
* Whether the group holds an answer the form can submit: a value an item
|
|
173
|
+
* here carries. A chosen item that was removed is no longer an answer, and
|
|
174
|
+
* `value` keeps the name for an item that arrives later.
|
|
175
|
+
*/
|
|
176
|
+
private get answered();
|
|
93
177
|
connectedCallback(): void;
|
|
94
178
|
disconnectedCallback(): void;
|
|
95
179
|
protected firstUpdated(changed: PropertyValues): void;
|
|
96
180
|
protected updated(changed: PropertyValues): void;
|
|
97
181
|
protected willUpdate(changed: PropertyValues): void;
|
|
182
|
+
/**
|
|
183
|
+
* What the form receives: the value, or under `selection-mode="multiple"`
|
|
184
|
+
* one entry per pressed value, as a native `<select multiple>` sends.
|
|
185
|
+
*/
|
|
186
|
+
private formValue;
|
|
98
187
|
/**
|
|
99
188
|
* The verdict on the answer `required` asks for.
|
|
100
189
|
*
|
|
@@ -108,22 +197,12 @@ export declare class HelixHeadlessToggleGroup extends HelixHeadlessToggleGroup_b
|
|
|
108
197
|
*/
|
|
109
198
|
private validate;
|
|
110
199
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* group wants. `start` is for a row of controls that are labeled rather than
|
|
115
|
-
* a form of fields: a toolbar reads as one line, and a label stacked over
|
|
116
|
-
* every group in it turns one row into two.
|
|
117
|
-
*
|
|
118
|
-
* **A placement rather than a slot, and that is the whole point of it.** A
|
|
119
|
-
* `start` slot would let a consumer put the word there, and would also let
|
|
120
|
-
* them put it there *instead of* setting `label`, which is the group's
|
|
121
|
-
* accessible name: the set would then be named for nobody using a screen
|
|
122
|
-
* reader while looking correct to everybody else. Worse, setting both draws
|
|
123
|
-
* it twice. One property moves the label the consumer already has to give,
|
|
124
|
-
* and cannot be used to remove it.
|
|
200
|
+
* The pressed values as a list, under `selection-mode="multiple"`, in the
|
|
201
|
+
* order the items are written. Written, it presses exactly those items.
|
|
202
|
+
* Where one item is chosen, it is that one value, or none.
|
|
125
203
|
*/
|
|
126
|
-
|
|
204
|
+
get values(): string[];
|
|
205
|
+
set values(next: string[]);
|
|
127
206
|
/**
|
|
128
207
|
* The row the track sits in, so something can sit beside it.
|
|
129
208
|
*
|