@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AriaForwardController, HelixFormElement } from '@fusion.dev/helix-core';
|
|
2
|
-
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
2
|
+
import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
/**
|
|
4
4
|
* @summary Triggers an action, submits a form, or navigates.
|
|
5
5
|
*
|
|
@@ -21,6 +21,17 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
21
21
|
* it. To submit, the button calls `requestSubmit()` on its form, which runs
|
|
22
22
|
* validation, unlike `submit()`.
|
|
23
23
|
*
|
|
24
|
+
* A `submit` listener reads `event.submitter` as `null`, because the platform
|
|
25
|
+
* accepts only a native submit button there. The button's `name` and `value`
|
|
26
|
+
* are in the form data, so read them from `new FormData(form)` to tell two
|
|
27
|
+
* submit buttons apart.
|
|
28
|
+
*
|
|
29
|
+
* As the first submit button in its form, it is the form's default button:
|
|
30
|
+
* Enter in a text field of the form presses it, as it presses a native one.
|
|
31
|
+
*
|
|
32
|
+
* Set `pending` while the action a press started is still running. The button
|
|
33
|
+
* keeps focus and refuses presses, and a reader on it hears `pending-label`.
|
|
34
|
+
*
|
|
24
35
|
* @since 0.1.0
|
|
25
36
|
* @status stable
|
|
26
37
|
* @category actions
|
|
@@ -31,10 +42,19 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
31
42
|
* @slot start - Content before the label, usually an icon.
|
|
32
43
|
*
|
|
33
44
|
* @csspart button - The inner control.
|
|
45
|
+
* @csspart live - The live region that says `pending-label` when the button becomes pending under focus. It is rendered from the first time the button is pending, and the styled button clips it out of view.
|
|
34
46
|
* @csspart text - The button's words, which the styled button trims to their capitals and baseline so the letters sit at the middle in any font.
|
|
47
|
+
*
|
|
48
|
+
* @cssstate pending - The button is pending: `pending` is set.
|
|
35
49
|
*/
|
|
36
50
|
export declare class HelixHeadlessButton extends HelixFormElement {
|
|
37
51
|
protected readonly aria: AriaForwardController;
|
|
52
|
+
/**
|
|
53
|
+
* @internal Whether a host `aria-label` names the inner button. A subclass
|
|
54
|
+
* that writes the name itself, as `CopyButton` does while it confirms a
|
|
55
|
+
* copy, says no.
|
|
56
|
+
*/
|
|
57
|
+
protected get forwardsLabel(): boolean;
|
|
38
58
|
/**
|
|
39
59
|
* What to send when the button is activated, and what to send it to.
|
|
40
60
|
*
|
|
@@ -143,6 +163,24 @@ export declare class HelixHeadlessButton extends HelixFormElement {
|
|
|
143
163
|
* "button" and nothing else.
|
|
144
164
|
*/
|
|
145
165
|
label: string;
|
|
166
|
+
/**
|
|
167
|
+
* Whether the action the button started is still running.
|
|
168
|
+
*
|
|
169
|
+
* A pending button keeps focus and stays in the tab order, and refuses every
|
|
170
|
+
* press: a click, Enter and Space, and Enter in a field of its form. The
|
|
171
|
+
* click does not reach your listeners. The inner control carries
|
|
172
|
+
* `aria-busy` and `aria-disabled`, and when the button becomes pending while
|
|
173
|
+
* it has focus, a reader hears `pending-label`. The styled button draws a
|
|
174
|
+
* turning ring over its words.
|
|
175
|
+
*
|
|
176
|
+
* `disabled` takes the button out of reach. Use `pending` for the wait after
|
|
177
|
+
* a press, so focus stays where the reader left it.
|
|
178
|
+
*/
|
|
179
|
+
pending: boolean;
|
|
180
|
+
/**
|
|
181
|
+
* What a reader hears when the button becomes pending while it has focus.
|
|
182
|
+
*/
|
|
183
|
+
pendingLabel: string;
|
|
146
184
|
/**
|
|
147
185
|
* What kind of panel this button opens, where it opens one: `menu` for a
|
|
148
186
|
* `Menu`.
|
|
@@ -153,6 +191,27 @@ export declare class HelixHeadlessButton extends HelixFormElement {
|
|
|
153
191
|
* reported collapsed and expanded and no popup.
|
|
154
192
|
*/
|
|
155
193
|
popup?: 'dialog' | 'grid' | 'listbox' | 'menu' | 'tree';
|
|
194
|
+
/**
|
|
195
|
+
* The status region, rendered from the first time the button is pending, so
|
|
196
|
+
* a button that never waits carries no live region.
|
|
197
|
+
*/
|
|
198
|
+
private readonly status;
|
|
199
|
+
/**
|
|
200
|
+
* Says `pendingLabel` when the button becomes pending under focus, and
|
|
201
|
+
* clears it when the wait ends.
|
|
202
|
+
*
|
|
203
|
+
* **Only under focus**, as React Aria announces it: the reader who pressed
|
|
204
|
+
* the button is the one waiting, and a button elsewhere on the page that
|
|
205
|
+
* starts waiting is not news to them. The region arrives empty and takes its
|
|
206
|
+
* words a frame later, since a region that arrives with its words is read
|
|
207
|
+
* inconsistently.
|
|
208
|
+
*/
|
|
209
|
+
private sayPending;
|
|
210
|
+
/**
|
|
211
|
+
* @internal The live region a pending button speaks in, for a subclass that
|
|
212
|
+
* replaces the template, as `CopyButton` does.
|
|
213
|
+
*/
|
|
214
|
+
protected renderLive(): TemplateResult | typeof nothing;
|
|
156
215
|
/** Moves focus to the inner control, so the host is never the focus target. */
|
|
157
216
|
static shadowRootOptions: ShadowRootInit;
|
|
158
217
|
private readonly handleClick;
|
|
@@ -235,7 +294,31 @@ export declare class HelixHeadlessButton extends HelixFormElement {
|
|
|
235
294
|
* fixes and would only appear on the browsers that work.
|
|
236
295
|
*/
|
|
237
296
|
private sendCommand;
|
|
297
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
238
298
|
protected updated(changed: PropertyValues): void;
|
|
299
|
+
/** @internal A submit button is what its form's implicit submission presses. */
|
|
300
|
+
protected get submitsForm(): boolean;
|
|
301
|
+
/** @internal Pressed as the form's default button, through the inner control. */
|
|
302
|
+
protected activate(): void;
|
|
303
|
+
/** The form whose Enter key this button listens to, as its default button. */
|
|
304
|
+
private watched;
|
|
305
|
+
/**
|
|
306
|
+
* Presses this button for Enter in a native text field of its form, when it
|
|
307
|
+
* is the form's default button.
|
|
308
|
+
*
|
|
309
|
+
* The platform cannot find a default button in a shadow root, so a form whose
|
|
310
|
+
* only submit button is this one found none: with two fields Enter did
|
|
311
|
+
* nothing, and with one it submitted without this button's name, value or
|
|
312
|
+
* overrides. The event's default is prevented so a later native submit button
|
|
313
|
+
* is not pressed instead.
|
|
314
|
+
*/
|
|
315
|
+
private readonly pressOnEnter;
|
|
316
|
+
/** Listens to the form this button now belongs to, and to no other. */
|
|
317
|
+
private watchForm;
|
|
318
|
+
connectedCallback(): void;
|
|
319
|
+
disconnectedCallback(): void;
|
|
320
|
+
/** Called by the browser when the button's form changes. */
|
|
321
|
+
formAssociatedCallback(form: HTMLFormElement | null): void;
|
|
239
322
|
protected render(): TemplateResult;
|
|
240
323
|
}
|
|
241
324
|
declare global {
|
|
@@ -4,14 +4,16 @@ 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, elementById, HelixFallbackCommandEvent, HelixFormElement, supportsInvokers, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, customElement, drawStatus, elementById, HelixFallbackCommandEvent, HelixFormElement, StatusController, supportsInvokers, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
|
|
11
11
|
constructor() {
|
|
12
12
|
super(...arguments);
|
|
13
13
|
this.aria = new AriaForwardController(this, {
|
|
14
|
+
label: () => this.forwardsLabel,
|
|
14
15
|
target: () => this.partNamed('button'),
|
|
16
|
+
unnamed: 'Give it words, a `label`, or an `aria-label`.',
|
|
15
17
|
});
|
|
16
18
|
this.command = '';
|
|
17
19
|
this.commandFor = '';
|
|
@@ -22,7 +24,15 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
|
|
|
22
24
|
this.formNoValidate = false;
|
|
23
25
|
this.formTarget = '';
|
|
24
26
|
this.label = '';
|
|
25
|
-
this.
|
|
27
|
+
this.pending = false;
|
|
28
|
+
this.pendingLabel = 'Loading';
|
|
29
|
+
this.status = new StatusController(this);
|
|
30
|
+
this.handleClick = (event) => {
|
|
31
|
+
if (this.pending) {
|
|
32
|
+
event.preventDefault();
|
|
33
|
+
event.stopImmediatePropagation();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
26
36
|
this.linkCommand();
|
|
27
37
|
this.sendCommand();
|
|
28
38
|
if (this.type === 'button') {
|
|
@@ -41,6 +51,34 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
|
|
|
41
51
|
};
|
|
42
52
|
this.type = 'button';
|
|
43
53
|
this.value = '';
|
|
54
|
+
this.watched = null;
|
|
55
|
+
this.pressOnEnter = (event) => {
|
|
56
|
+
const form = this.watched;
|
|
57
|
+
if (event.key !== 'Enter' ||
|
|
58
|
+
event.defaultPrevented ||
|
|
59
|
+
!form ||
|
|
60
|
+
!HelixFormElement.submitsOnEnter(event.composedPath()[0], form) ||
|
|
61
|
+
HelixFormElement.defaultButton(form) !== this) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
if (!this.isDisabled && !this.pending) {
|
|
66
|
+
this.activate();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
get forwardsLabel() {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
sayPending() {
|
|
74
|
+
const focused = this.renderRoot?.activeElement != null;
|
|
75
|
+
if (!focused && this.status.said === '') {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.status.say(this.pending && focused ? this.pendingLabel : '', { clear: false });
|
|
79
|
+
}
|
|
80
|
+
renderLive() {
|
|
81
|
+
return drawStatus(this.status);
|
|
44
82
|
}
|
|
45
83
|
static { this.shadowRootOptions = {
|
|
46
84
|
...HelixFormElement.shadowRootOptions,
|
|
@@ -112,9 +150,41 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
|
|
|
112
150
|
}
|
|
113
151
|
this.commandTarget()?.dispatchEvent(new HelixFallbackCommandEvent(this.command, this));
|
|
114
152
|
}
|
|
153
|
+
willUpdate(changed) {
|
|
154
|
+
super.willUpdate(changed);
|
|
155
|
+
this.toggleState('pending', this.pending);
|
|
156
|
+
}
|
|
115
157
|
updated(changed) {
|
|
116
158
|
super.updated(changed);
|
|
117
159
|
this.linkCommand();
|
|
160
|
+
if (changed.has('pending') && changed.get('pending') !== undefined) {
|
|
161
|
+
this.sayPending();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
get submitsForm() {
|
|
165
|
+
return this.type === 'submit';
|
|
166
|
+
}
|
|
167
|
+
activate() {
|
|
168
|
+
this.partNamed('button')?.click();
|
|
169
|
+
}
|
|
170
|
+
watchForm(form) {
|
|
171
|
+
if (form === this.watched) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
this.watched?.removeEventListener('keypress', this.pressOnEnter);
|
|
175
|
+
form?.addEventListener('keypress', this.pressOnEnter);
|
|
176
|
+
this.watched = form;
|
|
177
|
+
}
|
|
178
|
+
connectedCallback() {
|
|
179
|
+
super.connectedCallback();
|
|
180
|
+
this.watchForm(this.form);
|
|
181
|
+
}
|
|
182
|
+
disconnectedCallback() {
|
|
183
|
+
super.disconnectedCallback();
|
|
184
|
+
this.watchForm(null);
|
|
185
|
+
}
|
|
186
|
+
formAssociatedCallback(form) {
|
|
187
|
+
this.watchForm(form);
|
|
118
188
|
}
|
|
119
189
|
render() {
|
|
120
190
|
const label = html `<slot name="start"></slot><slot part="text"></slot><slot name="end"></slot>`;
|
|
@@ -124,6 +194,8 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
|
|
|
124
194
|
type="button"
|
|
125
195
|
aria-expanded=${this.expanded === undefined ? nothing : String(this.expanded)}
|
|
126
196
|
aria-haspopup=${this.popup ?? nothing}
|
|
197
|
+
aria-busy=${this.pending ? 'true' : nothing}
|
|
198
|
+
aria-disabled=${this.pending ? 'true' : nothing}
|
|
127
199
|
aria-label=${this.label || nothing}
|
|
128
200
|
command=${this.command || nothing}
|
|
129
201
|
tabindex=${stop}
|
|
@@ -131,7 +203,7 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
|
|
|
131
203
|
@click=${this.handleClick}
|
|
132
204
|
>
|
|
133
205
|
${label}
|
|
134
|
-
</button
|
|
206
|
+
</button>${this.renderLive()}`;
|
|
135
207
|
}
|
|
136
208
|
};
|
|
137
209
|
__decorate([
|
|
@@ -164,6 +236,12 @@ __decorate([
|
|
|
164
236
|
__decorate([
|
|
165
237
|
property()
|
|
166
238
|
], HelixHeadlessButton.prototype, "label", void 0);
|
|
239
|
+
__decorate([
|
|
240
|
+
property({ type: Boolean })
|
|
241
|
+
], HelixHeadlessButton.prototype, "pending", void 0);
|
|
242
|
+
__decorate([
|
|
243
|
+
property({ attribute: 'pending-label' })
|
|
244
|
+
], HelixHeadlessButton.prototype, "pendingLabel", void 0);
|
|
167
245
|
__decorate([
|
|
168
246
|
property({ attribute: false })
|
|
169
247
|
], HelixHeadlessButton.prototype, "popup", void 0);
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
+
declare const HelixHeadlessCallout_base: (new (...args: any[]) => import("@fusion.dev/helix-core").DismissibleElement) & typeof HelixElement;
|
|
3
4
|
/**
|
|
4
5
|
* @summary A passage set apart as a note, information, a warning, or an error.
|
|
5
6
|
*
|
|
6
7
|
* @description
|
|
7
8
|
* `tone` is on the headless tier because it carries meaning. It picks the icon
|
|
8
|
-
* and the icon's accessible name, so a screen reader announces "Error"
|
|
9
|
-
* error callout whether or not the color is seen.
|
|
9
|
+
* and the icon region's accessible name, so a screen reader announces "Error"
|
|
10
|
+
* for an error callout whether or not the color is seen. Set `tone-label` to
|
|
11
|
+
* say the name in another language.
|
|
10
12
|
*
|
|
11
13
|
* The icon is the fallback content of a slot. Slot your own icon to replace it,
|
|
12
|
-
* and the default disappears with no extra check.
|
|
14
|
+
* and the default disappears with no extra check. The tone's name stays on the
|
|
15
|
+
* region around it.
|
|
16
|
+
*
|
|
17
|
+
* Set `dismissible` for a note a reader may put away, as Shoelace's `closable`
|
|
18
|
+
* alert does. The button fires `helix-dismiss` and the callout stays until a
|
|
19
|
+
* listener removes it, so the page decides whether it comes back.
|
|
13
20
|
*
|
|
14
21
|
* A callout sets a passage apart inside a document and is read where it sits.
|
|
15
22
|
* For page-level chrome above the masthead that is a live region and can be
|
|
@@ -22,14 +29,19 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
22
29
|
* @documentation https://fusion.dev/helix/components/callout
|
|
23
30
|
*
|
|
24
31
|
* @slot - The callout's content.
|
|
32
|
+
* @slot dismiss-icon - Replaces the cross inside the dismiss button.
|
|
25
33
|
* @slot heading - A heading above the content.
|
|
26
34
|
* @slot icon - Replaces the icon chosen by `tone`.
|
|
27
35
|
*
|
|
36
|
+
* @event {HelixDismissEvent} helix-dismiss - The dismiss button was pressed. The callout does not remove itself, so remove it in response. Cancelable.
|
|
37
|
+
*
|
|
28
38
|
* @csspart content - The content region.
|
|
29
|
-
* @csspart
|
|
39
|
+
* @csspart dismiss - The button that dismisses the callout, shown when `dismissible` is set.
|
|
40
|
+
* @csspart dismiss-mark - The cross on the dismiss button, shown when the `dismiss-icon` slot is empty.
|
|
41
|
+
* @csspart icon - The icon region, an image named for the tone.
|
|
30
42
|
* @csspart icon-mark - The icon for the tone, shown when no icon is slotted.
|
|
31
43
|
*/
|
|
32
|
-
export declare class HelixHeadlessCallout extends
|
|
44
|
+
export declare class HelixHeadlessCallout extends HelixHeadlessCallout_base {
|
|
33
45
|
protected willUpdate(changed: PropertyValues): void;
|
|
34
46
|
/**
|
|
35
47
|
* What kind of attention the passage needs.
|
|
@@ -40,6 +52,13 @@ export declare class HelixHeadlessCallout extends HelixElement {
|
|
|
40
52
|
* is the whole of the registry, which is why there is no `severity` beside it.
|
|
41
53
|
*/
|
|
42
54
|
tone?: 'danger' | 'info' | 'neutral' | 'success' | 'warning';
|
|
55
|
+
/**
|
|
56
|
+
* What a screen reader is told the tone is, such as "Fehler".
|
|
57
|
+
*
|
|
58
|
+
* Absent is the English for the tone: "Error", "Information", "Note",
|
|
59
|
+
* "Success" or "Warning".
|
|
60
|
+
*/
|
|
61
|
+
toneLabel: string;
|
|
43
62
|
/**
|
|
44
63
|
* The mark for the callout's tone, behind a seam.
|
|
45
64
|
*
|
|
@@ -56,7 +75,13 @@ export declare class HelixHeadlessCallout extends HelixElement {
|
|
|
56
75
|
protected renderIcon(icon: {
|
|
57
76
|
content: string;
|
|
58
77
|
viewBox: string;
|
|
59
|
-
},
|
|
78
|
+
}, _label: string): TemplateResult;
|
|
79
|
+
/**
|
|
80
|
+
* The cross inside the dismiss button, behind a seam, for the reason
|
|
81
|
+
* `renderIcon` gives: the slot answers the page and the method the tier
|
|
82
|
+
* above.
|
|
83
|
+
*/
|
|
84
|
+
protected renderDismissIcon(): TemplateResult;
|
|
60
85
|
protected render(): TemplateResult;
|
|
61
86
|
}
|
|
62
87
|
declare global {
|
|
@@ -64,3 +89,4 @@ declare global {
|
|
|
64
89
|
'helix-headless-callout': HelixHeadlessCallout;
|
|
65
90
|
}
|
|
66
91
|
}
|
|
92
|
+
export {};
|
|
@@ -4,35 +4,54 @@ 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, TONE_MARKS, toneMark } from '@fusion.dev/helix-core';
|
|
8
|
-
import { html } from 'lit';
|
|
7
|
+
import { customElement, drawDismiss, drawDismissGlyph, HelixElement, hostAria, MixinDismissible, TONE_MARKS, toneMark, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
11
11
|
const NOTE = { icon: TONE_MARKS.info.icon, label: 'Note' };
|
|
12
|
-
let HelixHeadlessCallout = class HelixHeadlessCallout extends HelixElement {
|
|
12
|
+
let HelixHeadlessCallout = class HelixHeadlessCallout extends MixinDismissible(HelixElement) {
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
this.toneLabel = '';
|
|
16
|
+
}
|
|
13
17
|
willUpdate(changed) {
|
|
14
18
|
super.willUpdate(changed);
|
|
15
19
|
hostAria(this.internals, { role: 'note' });
|
|
16
20
|
}
|
|
17
|
-
renderIcon(icon,
|
|
21
|
+
renderIcon(icon, _label) {
|
|
18
22
|
return html `<slot name="icon">
|
|
19
|
-
<svg part="icon-mark" fill="currentColor" viewBox=${icon.viewBox}
|
|
23
|
+
<svg part="icon-mark" fill="currentColor" viewBox=${icon.viewBox} aria-hidden="true">
|
|
20
24
|
${unsafeSVG(icon.content)}
|
|
21
25
|
</svg>
|
|
22
26
|
</slot>`;
|
|
23
27
|
}
|
|
28
|
+
renderDismissIcon() {
|
|
29
|
+
return html `<slot name="dismiss-icon">
|
|
30
|
+
${drawDismissGlyph()}
|
|
31
|
+
</slot>`;
|
|
32
|
+
}
|
|
24
33
|
render() {
|
|
25
34
|
const { icon, label } = this.tone === 'neutral' ? NOTE : (toneMark(this.tone) ?? TONE_MARKS.info);
|
|
26
|
-
|
|
35
|
+
const named = this.toneLabel || label;
|
|
36
|
+
return html `<span part="icon" role="img" aria-label=${named}>${this.renderIcon(icon, named)}</span>
|
|
27
37
|
<div part="content">
|
|
28
38
|
<slot name="heading"></slot>
|
|
29
39
|
<slot></slot>
|
|
30
|
-
</div
|
|
40
|
+
</div>${this.dismissible
|
|
41
|
+
? drawDismiss({
|
|
42
|
+
label: this.dismissLabel,
|
|
43
|
+
mark: this.renderDismissIcon(),
|
|
44
|
+
onDismiss: () => this.dismiss(),
|
|
45
|
+
})
|
|
46
|
+
: nothing}`;
|
|
31
47
|
}
|
|
32
48
|
};
|
|
33
49
|
__decorate([
|
|
34
50
|
property({ reflect: true })
|
|
35
51
|
], HelixHeadlessCallout.prototype, "tone", void 0);
|
|
52
|
+
__decorate([
|
|
53
|
+
property({ attribute: 'tone-label' })
|
|
54
|
+
], HelixHeadlessCallout.prototype, "toneLabel", void 0);
|
|
36
55
|
HelixHeadlessCallout = __decorate([
|
|
37
56
|
customElement('helix-headless-callout')
|
|
38
57
|
], HelixHeadlessCallout);
|
|
@@ -72,6 +72,7 @@ declare const HelixHeadlessCanvas_base: (new (...args: any[]) => import("@fusion
|
|
|
72
72
|
* @aliases Board, JSON Canvas, Whiteboard
|
|
73
73
|
* @documentation https://fusion.dev/helix/components/canvas
|
|
74
74
|
*
|
|
75
|
+
* @slot - The board's `helix-canvas-node` and `helix-canvas-edge` elements, drawn on the plane.
|
|
75
76
|
* @slot empty - Content shown when the document has no nodes.
|
|
76
77
|
* @slot footer - Content below the board.
|
|
77
78
|
* @slot header - Content above the board.
|
|
@@ -1738,7 +1738,6 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
|
|
|
1738
1738
|
return html `<svg
|
|
1739
1739
|
part="edges"
|
|
1740
1740
|
role="none"
|
|
1741
|
-
@focusin=${this.handleFocusIn}
|
|
1742
1741
|
viewBox=${`0 0 ${box.width} ${box.height}`}
|
|
1743
1742
|
width=${box.width}
|
|
1744
1743
|
height=${box.height}
|
|
@@ -1889,9 +1888,19 @@ let HelixHeadlessCanvas = class HelixHeadlessCanvas extends MixinViewport(HelixE
|
|
|
1889
1888
|
ruling's own offset is where the document's zero lands, so a line
|
|
1890
1889
|
falls on every multiple of its spacing in the document's units and
|
|
1891
1890
|
a card placed on one sits on a line. -->
|
|
1891
|
+
<!-- **Focus is heard here as well as on the host.** Moving from one
|
|
1892
|
+
connection to the next moves focus inside this shadow root, and a
|
|
1893
|
+
browser does not tell the host about a move that starts and ends
|
|
1894
|
+
in its own tree. So the stop stayed on the first of two
|
|
1895
|
+
connections in a row. Heard on the board and never on the edges'
|
|
1896
|
+
SVG element: Chromium makes an SVG element with a focus listener
|
|
1897
|
+
a Tab stop of its own, an unnamed one between the board and the
|
|
1898
|
+
first card. Heard twice from a card, which the handler answers
|
|
1899
|
+
the same way both times. -->
|
|
1892
1900
|
<div
|
|
1893
1901
|
part="board"
|
|
1894
1902
|
style=${`--_canvas-plane-inline-size: ${box.width}px; --_canvas-plane-block-size: ${box.height}px`}
|
|
1903
|
+
@focusin=${this.handleFocusIn}
|
|
1895
1904
|
>
|
|
1896
1905
|
${this.renderEdges(origin, box)} ${this.renderLabels(origin)}
|
|
1897
1906
|
<slot @slotchange=${this.handleSlotChange}></slot>
|
|
@@ -14,7 +14,15 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
14
14
|
*
|
|
15
15
|
* Name the card with `aria-label` or `aria-labelledby`. These are the only
|
|
16
16
|
* names that work with server rendering, because reading a title from the light
|
|
17
|
-
* DOM needs a DOM, and the server has none.
|
|
17
|
+
* DOM needs a DOM, and the server has none. **A named card is a group**, so a
|
|
18
|
+
* reader entering it hears its name; an unnamed one has no role, since a group
|
|
19
|
+
* with no name only adds "group" to what a reader says.
|
|
20
|
+
*
|
|
21
|
+
* `header-actions` and `footer-actions` hold controls at the end of the
|
|
22
|
+
* header's and the footer's line, as Web Awesome's card does. While one holds
|
|
23
|
+
* something, its line is a `header-row` or `footer-row` part; otherwise there
|
|
24
|
+
* is no wrapper and every region is a bare slot. A server cannot see slotted
|
|
25
|
+
* content, so served actions sit on their own line until the script runs.
|
|
18
26
|
*
|
|
19
27
|
* @since 0.1.0
|
|
20
28
|
* @status stable
|
|
@@ -24,8 +32,13 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
24
32
|
*
|
|
25
33
|
* @slot - The card's main content.
|
|
26
34
|
* @slot footer - Actions that conclude the card.
|
|
35
|
+
* @slot footer-actions - Controls at the end of the footer's line, with the footer at its start.
|
|
27
36
|
* @slot header - Title and any actions for the whole card.
|
|
37
|
+
* @slot header-actions - Controls for the whole card at the end of the header's line, such as a menu.
|
|
28
38
|
* @slot media - Image, video, or chart that runs edge to edge, outside the inset.
|
|
39
|
+
*
|
|
40
|
+
* @csspart footer-row - The line holding `footer` and `footer-actions`, drawn only while `footer-actions` holds something.
|
|
41
|
+
* @csspart header-row - The line holding `header` and `header-actions`, drawn only while `header-actions` holds something.
|
|
29
42
|
*/
|
|
30
43
|
export declare class HelixHeadlessCard extends HelixElement {
|
|
31
44
|
/**
|
|
@@ -42,7 +55,23 @@ export declare class HelixHeadlessCard extends HelixElement {
|
|
|
42
55
|
* with no attribute on it and the stylesheet only describes the departure.
|
|
43
56
|
*/
|
|
44
57
|
mediaPlacement?: 'end';
|
|
58
|
+
/**
|
|
59
|
+
* @internal The host's `aria-labelledby`, observed so the card becomes a
|
|
60
|
+
* group once it is named. Not reflected: the attribute is the consumer's.
|
|
61
|
+
*/
|
|
62
|
+
protected labelledBy: string | null;
|
|
63
|
+
/**
|
|
64
|
+
* @internal The host's `aria-label`, observed for the same reason as
|
|
65
|
+
* `labelledBy`. Not reflected: the attribute is the consumer's.
|
|
66
|
+
*/
|
|
67
|
+
protected namedBy: string | null;
|
|
68
|
+
/** Whether `footer-actions` holds something, read from the slot. */
|
|
69
|
+
private footerActions;
|
|
70
|
+
/** Whether `header-actions` holds something, read from the slot. */
|
|
71
|
+
private headerActions;
|
|
45
72
|
protected willUpdate(changed: PropertyValues): void;
|
|
73
|
+
protected updated(changed: PropertyValues): void;
|
|
74
|
+
private readonly readActions;
|
|
46
75
|
protected render(): TemplateResult;
|
|
47
76
|
}
|
|
48
77
|
declare global {
|
|
@@ -4,26 +4,59 @@ 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, slotFilled } 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
|
let HelixHeadlessCard = class HelixHeadlessCard extends HelixElement {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
13
|
+
this.labelledBy = null;
|
|
14
|
+
this.namedBy = null;
|
|
15
|
+
this.footerActions = false;
|
|
16
|
+
this.headerActions = false;
|
|
17
|
+
this.readActions = () => {
|
|
18
|
+
const filled = (name) => slotFilled(this.renderRoot?.querySelector(`slot[name="${name}"]`));
|
|
19
|
+
this.headerActions = filled('header-actions');
|
|
20
|
+
this.footerActions = filled('footer-actions');
|
|
21
|
+
};
|
|
22
|
+
}
|
|
11
23
|
willUpdate(changed) {
|
|
12
24
|
super.willUpdate(changed);
|
|
13
|
-
|
|
25
|
+
const named = Boolean(this.namedBy?.trim() || this.labelledBy?.trim());
|
|
26
|
+
hostAria(this.internals, { role: named ? 'group' : '' });
|
|
27
|
+
}
|
|
28
|
+
updated(changed) {
|
|
29
|
+
super.updated(changed);
|
|
30
|
+
this.readActions();
|
|
14
31
|
}
|
|
15
32
|
render() {
|
|
33
|
+
const header = html `<slot name="header"></slot
|
|
34
|
+
><slot name="header-actions" @slotchange=${this.readActions}></slot>`;
|
|
35
|
+
const footer = html `<slot name="footer"></slot
|
|
36
|
+
><slot name="footer-actions" @slotchange=${this.readActions}></slot>`;
|
|
16
37
|
return html `
|
|
17
38
|
<slot name="media"></slot>
|
|
18
|
-
|
|
39
|
+
${this.headerActions ? html `<div part="header-row">${header}</div>` : header}
|
|
19
40
|
<slot></slot>
|
|
20
|
-
|
|
41
|
+
${this.footerActions ? html `<div part="footer-row">${footer}</div>` : footer}
|
|
21
42
|
`;
|
|
22
43
|
}
|
|
23
44
|
};
|
|
24
45
|
__decorate([
|
|
25
46
|
property({ attribute: 'media-placement', reflect: true })
|
|
26
47
|
], HelixHeadlessCard.prototype, "mediaPlacement", void 0);
|
|
48
|
+
__decorate([
|
|
49
|
+
property({ attribute: 'aria-labelledby' })
|
|
50
|
+
], HelixHeadlessCard.prototype, "labelledBy", void 0);
|
|
51
|
+
__decorate([
|
|
52
|
+
property({ attribute: 'aria-label' })
|
|
53
|
+
], HelixHeadlessCard.prototype, "namedBy", void 0);
|
|
54
|
+
__decorate([
|
|
55
|
+
state()
|
|
56
|
+
], HelixHeadlessCard.prototype, "footerActions", void 0);
|
|
57
|
+
__decorate([
|
|
58
|
+
state()
|
|
59
|
+
], HelixHeadlessCard.prototype, "headerActions", void 0);
|
|
27
60
|
HelixHeadlessCard = __decorate([
|
|
28
61
|
customElement('helix-headless-card')
|
|
29
62
|
], HelixHeadlessCard);
|
|
@@ -16,7 +16,18 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
16
16
|
*
|
|
17
17
|
* **Rotation stops on focus and on hover, and stays stopped** until the user
|
|
18
18
|
* starts it again, as the APG requires. The rotation control is labeled with
|
|
19
|
-
* the action it performs and is first in the tab order.
|
|
19
|
+
* the action it performs and is first in the tab order. Rotation goes on from
|
|
20
|
+
* the last slide to the first, with or without `loop`, which is about the
|
|
21
|
+
* reader's own moves.
|
|
22
|
+
*
|
|
23
|
+
* A move the reader makes is announced, the slide's position read from a
|
|
24
|
+
* polite live region. While the carousel rotates the region is off, so a
|
|
25
|
+
* screen reader is not interrupted every few seconds.
|
|
26
|
+
*
|
|
27
|
+
* The indicators are one tab stop. The arrow keys along the track move between
|
|
28
|
+
* them, Up and Down on a vertical carousel, and Home and End go to the first
|
|
29
|
+
* and the last. Without `loop`, Previous on the first slide and Next on the
|
|
30
|
+
* last are marked `aria-disabled`.
|
|
20
31
|
*
|
|
21
32
|
* @since 0.1.0
|
|
22
33
|
* @status stable
|
|
@@ -26,12 +37,14 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
26
37
|
*
|
|
27
38
|
* @slot - The slides.
|
|
28
39
|
*
|
|
40
|
+
* @event {HelixActivateEvent} helix-activate - Fired after the slide in view changes, with the new index as a string in `detail.value`.
|
|
29
41
|
* @event {HelixSelectEvent} helix-select - Fired before the slide in view changes, with the requested index. Cancelable: cancel it to keep the current slide. Nothing moves, and a drag returns to the slide the index still holds. See `handleScroll`.
|
|
30
42
|
*
|
|
31
43
|
* @csspart controls - The row of controls.
|
|
32
44
|
* @csspart indicator - One indicator. Pressing it moves to its slide.
|
|
33
45
|
* @csspart indicator-current - The indicator for the slide in view, alongside `indicator`.
|
|
34
46
|
* @csspart indicators - The row of indicators that shows which slide is in view.
|
|
47
|
+
* @csspart live - The region that announces the slide a move lands on. Visually hidden in the styled tier.
|
|
35
48
|
* @csspart next - The control that moves to the next slide.
|
|
36
49
|
* @csspart next-mark - The glyph on the next control.
|
|
37
50
|
* @csspart previous - The control that moves to the previous slide.
|
|
@@ -131,6 +144,8 @@ export declare class HelixHeadlessCarousel extends HelixElement {
|
|
|
131
144
|
private indexState;
|
|
132
145
|
/** How many panes were drawn at the last update, to scroll when the first are. */
|
|
133
146
|
private scrolledFor;
|
|
147
|
+
/** What the live region says: the position of the slide the last move landed on. */
|
|
148
|
+
private said;
|
|
134
149
|
/**
|
|
135
150
|
* The carousel's name, read by screen readers.
|
|
136
151
|
*/
|
|
@@ -336,14 +351,24 @@ export declare class HelixHeadlessCarousel extends HelixElement {
|
|
|
336
351
|
* **A fitted carousel's last position moves with the window**, which a
|
|
337
352
|
* declared one's never does: eight slides at one across has eight places to
|
|
338
353
|
* stand and four across has five, so a track widened while the reader sits on
|
|
339
|
-
* the last of them is a track resting somewhere it can no longer be.
|
|
340
|
-
* `
|
|
341
|
-
* every other index change does and a consumer holding `index` hears it
|
|
342
|
-
* rather than being overwritten.
|
|
354
|
+
* the last of them is a track resting somewhere it can no longer be. See
|
|
355
|
+
* `holdIndex` for why the correction is not a request.
|
|
343
356
|
*
|
|
344
357
|
* Only on a change, so the observer's own re-render cannot feed itself.
|
|
345
358
|
*/
|
|
346
359
|
private readonly readFit;
|
|
360
|
+
/**
|
|
361
|
+
* Puts the index back on the last place the track can stand, where fewer
|
|
362
|
+
* places are left than it counted.
|
|
363
|
+
*
|
|
364
|
+
* **Written, with no request.** Nobody asked for this move: a slide was
|
|
365
|
+
* removed, the window widened, or `per-view` went up. It went out as a
|
|
366
|
+
* cancelable `helix-select`, which a consumer reading the event as a reader's
|
|
367
|
+
* request had no reason to expect, and refusing it left the index past the
|
|
368
|
+
* last slide, with no current indicator and no tab stop, and asked again on
|
|
369
|
+
* every update. An index that cannot be refused is not a request.
|
|
370
|
+
*/
|
|
371
|
+
private holdIndex;
|
|
347
372
|
/**
|
|
348
373
|
* The count handed to the styles, and nothing at all where they work it out.
|
|
349
374
|
*
|
|
@@ -413,6 +438,14 @@ export declare class HelixHeadlessCarousel extends HelixElement {
|
|
|
413
438
|
* the right, the left arrow is the one that moves on.
|
|
414
439
|
*/
|
|
415
440
|
private readonly handleIndicatorKeydown;
|
|
441
|
+
/**
|
|
442
|
+
* Puts a requested slide in view, and says so.
|
|
443
|
+
*
|
|
444
|
+
* `helix-activate` is the notification after `helix-select`, the one Tour
|
|
445
|
+
* and Tabs send once a different member is current. A clamp in `holdIndex`
|
|
446
|
+
* sends neither, being a correction rather than a move anybody asked for.
|
|
447
|
+
*/
|
|
448
|
+
private applyIndex;
|
|
416
449
|
/** Moves to a slide. It wraps past either end only when `loop` is set. */
|
|
417
450
|
goTo(index: number): void;
|
|
418
451
|
/**
|
|
@@ -663,6 +696,15 @@ export declare class HelixHeadlessCarousel extends HelixElement {
|
|
|
663
696
|
* floor.
|
|
664
697
|
*/
|
|
665
698
|
private runEnd;
|
|
699
|
+
/**
|
|
700
|
+
* Whether Previous or Next has nowhere to go, which is only at an end and
|
|
701
|
+
* without `loop`.
|
|
702
|
+
*
|
|
703
|
+
* Said with `aria-disabled` and not `disabled`, so a reader who pressed Next
|
|
704
|
+
* onto the last slide keeps focus on the control they are on. Not on the
|
|
705
|
+
* server, which knows no slides and so no ends.
|
|
706
|
+
*/
|
|
707
|
+
private atEnd;
|
|
666
708
|
protected render(): TemplateResult;
|
|
667
709
|
}
|
|
668
710
|
declare global {
|