@fusion.dev/helix-headless 0.144.0 → 0.146.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 +15195 -4240
- package/dist/accordion/item/accordion-item.d.ts +62 -12
- package/dist/accordion/item/accordion-item.js +41 -10
- package/dist/accordion/root/accordion-root.d.ts +14 -5
- package/dist/accordion/root/accordion-root.js +7 -1
- package/dist/announcement/root/announcement-root.d.ts +24 -3
- package/dist/announcement/root/announcement-root.js +39 -2
- package/dist/app-header/root/app-header-root.d.ts +12 -0
- package/dist/app-header/root/app-header-root.js +13 -1
- package/dist/app-header/sectioning.d.ts +9 -0
- package/dist/app-header/sectioning.js +27 -0
- package/dist/avatar/group/avatar-group.d.ts +20 -14
- package/dist/avatar/group/avatar-group.js +17 -19
- package/dist/badge/root/badge-root.d.ts +3 -1
- package/dist/badge/root/badge-root.js +2 -2
- package/dist/bar-chart/root/bar-chart-root.d.ts +18 -1
- package/dist/bar-chart/root/bar-chart-root.js +52 -15
- package/dist/bar-chart/stack.d.ts +15 -0
- package/dist/bar-chart/stack.js +19 -0
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +57 -1
- package/dist/breadcrumbs/root/breadcrumbs-root.js +73 -3
- package/dist/button/root/button-root.d.ts +26 -0
- package/dist/button/root/button-root.js +38 -18
- package/dist/button-group/root/button-group-root.d.ts +2 -1
- package/dist/button-group/root/button-group-root.js +5 -1
- package/dist/canvas/node/canvas-node.d.ts +4 -3
- package/dist/canvas/node/canvas-node.js +3 -2
- package/dist/canvas/root/canvas-root.d.ts +38 -3
- package/dist/canvas/root/canvas-root.js +123 -42
- package/dist/card/root/card-root.d.ts +24 -3
- package/dist/card/root/card-root.js +20 -8
- package/dist/carousel/root/carousel-root.d.ts +133 -4
- package/dist/carousel/root/carousel-root.js +174 -24
- package/dist/carousel/stops.d.ts +20 -0
- package/dist/carousel/stops.js +30 -0
- package/dist/chat/composer/chat-composer.d.ts +38 -6
- package/dist/chat/composer/chat-composer.js +42 -9
- package/dist/chat/message/chat-message.d.ts +32 -1
- package/dist/chat/message/chat-message.js +27 -10
- package/dist/chat/naming.d.ts +26 -0
- package/dist/chat/naming.js +14 -0
- package/dist/chat/root/chat-root.d.ts +58 -0
- package/dist/chat/root/chat-root.js +43 -3
- package/dist/checkbox/root/checkbox-root.d.ts +20 -0
- package/dist/checkbox/root/checkbox-root.js +14 -1
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +8 -2
- package/dist/checkbox-group/root/checkbox-group-root.js +12 -10
- package/dist/checkbox-group/select-all.d.ts +27 -0
- package/dist/checkbox-group/select-all.js +12 -0
- package/dist/code-block/highlight.d.ts +15 -0
- package/dist/code-block/highlight.js +4 -0
- package/dist/code-block/root/code-block-root.d.ts +57 -2
- package/dist/code-block/root/code-block-root.js +63 -8
- package/dist/color-input/root/color-input-root.d.ts +3 -0
- package/dist/color-input/root/color-input-root.js +6 -3
- package/dist/color-picker/root/color-picker-root.d.ts +33 -4
- package/dist/color-picker/root/color-picker-root.js +80 -21
- package/dist/color-picker/swatches.d.ts +12 -0
- package/dist/color-picker/swatches.js +26 -0
- package/dist/combobox/root/combobox-root.d.ts +43 -0
- package/dist/combobox/root/combobox-root.js +79 -15
- package/dist/command/root/command-root.d.ts +16 -1
- package/dist/command/root/command-root.js +22 -4
- package/dist/copy-button/root/copy-button-root.d.ts +26 -1
- package/dist/copy-button/root/copy-button-root.js +12 -5
- package/dist/data-table/index.d.ts +1 -1
- package/dist/data-table/index.js +1 -1
- package/dist/data-table/keys.d.ts +24 -0
- package/dist/data-table/keys.js +24 -0
- package/dist/data-table/root/data-table-root.d.ts +170 -13
- package/dist/data-table/root/data-table-root.js +294 -52
- package/dist/data-table/tree.d.ts +55 -0
- package/dist/data-table/tree.js +54 -0
- package/dist/date-input/root/date-input-root.d.ts +3 -1
- package/dist/date-input/root/date-input-root.js +18 -7
- package/dist/date-picker/root/date-picker-root.js +12 -6
- package/dist/description-list/item/description-list-item.d.ts +17 -2
- package/dist/description-list/item/description-list-item.js +15 -2
- package/dist/description-list/root/description-list-root.d.ts +27 -1
- package/dist/description-list/root/description-list-root.js +26 -1
- package/dist/dialog/description.js +15 -1
- package/dist/dialog/root/dialog-root.d.ts +8 -2
- package/dist/dialog/root/dialog-root.js +16 -1
- package/dist/divider/root/divider-root.d.ts +3 -0
- package/dist/divider/root/divider-root.js +2 -1
- package/dist/donut-chart/root/donut-chart-root.d.ts +31 -0
- package/dist/donut-chart/root/donut-chart-root.js +48 -1
- package/dist/drawer/reveal.d.ts +8 -0
- package/dist/drawer/reveal.js +1 -0
- package/dist/drawer/root/drawer-root.d.ts +59 -0
- package/dist/drawer/root/drawer-root.js +63 -4
- package/dist/drilldown/item/drilldown-item.d.ts +11 -6
- package/dist/drilldown/item/drilldown-item.js +8 -5
- package/dist/drilldown/root/drilldown-root.d.ts +29 -0
- package/dist/drilldown/root/drilldown-root.js +28 -5
- package/dist/element-events.generated.js +83 -12
- package/dist/empty/root/empty-root.d.ts +3 -1
- package/dist/empty/root/empty-root.js +3 -2
- package/dist/file-input/root/file-input-root.d.ts +69 -6
- package/dist/file-input/root/file-input-root.js +82 -19
- package/dist/file-input/screen.d.ts +2 -1
- package/dist/filter-input/menu/filter-menu.d.ts +5 -0
- package/dist/filter-input/menu/filter-menu.js +16 -4
- package/dist/filter-input/root/filter-input-root.d.ts +30 -6
- package/dist/filter-input/root/filter-input-root.js +1 -1
- package/dist/filter-input/suggest.d.ts +28 -3
- package/dist/filter-input/suggest.js +18 -8
- package/dist/format-date/root/format-date-root.d.ts +9 -16
- package/dist/format-date/root/format-date-root.js +10 -27
- package/dist/heatmap/root/heatmap-root.d.ts +24 -13
- package/dist/heatmap/root/heatmap-root.js +34 -12
- package/dist/icon/root/icon-root.d.ts +12 -1
- package/dist/icon/root/icon-root.js +21 -10
- package/dist/icon/settle.d.ts +7 -0
- package/dist/icon/settle.js +10 -0
- package/dist/icon-button/root/icon-button-root.d.ts +2 -0
- package/dist/image/root/image-root.d.ts +5 -1
- package/dist/image/root/image-root.js +10 -2
- package/dist/input/root/input-root.d.ts +13 -3
- package/dist/input/root/input-root.js +12 -3
- package/dist/kbd/root/kbd-root.d.ts +35 -1
- package/dist/kbd/root/kbd-root.js +23 -4
- package/dist/legend/root/legend-root.d.ts +55 -8
- package/dist/legend/root/legend-root.js +55 -13
- package/dist/lightbox/root/lightbox-root.d.ts +49 -6
- package/dist/lightbox/root/lightbox-root.js +86 -19
- package/dist/lightbox/zoom-controller.d.ts +59 -0
- package/dist/lightbox/zoom-controller.js +128 -0
- package/dist/lightbox/zoom.d.ts +22 -0
- package/dist/lightbox/zoom.js +16 -0
- package/dist/line-chart/root/line-chart-root.d.ts +22 -1
- package/dist/line-chart/root/line-chart-root.js +21 -1
- package/dist/list/item/list-item.d.ts +70 -1
- package/dist/list/item/list-item.js +77 -6
- package/dist/list/numbering.d.ts +14 -0
- package/dist/list/numbering.js +8 -0
- package/dist/list/root/list-root.d.ts +155 -9
- package/dist/list/root/list-root.js +246 -4
- package/dist/list/selection.d.ts +49 -0
- package/dist/list/selection.js +30 -0
- package/dist/listbox/root/listbox-root.d.ts +37 -1
- package/dist/listbox/root/listbox-root.js +49 -4
- package/dist/loader/busy.d.ts +10 -0
- package/dist/loader/busy.js +11 -0
- package/dist/loader/root/loader-root.d.ts +9 -2
- package/dist/loader/root/loader-root.js +23 -3
- package/dist/map/root/map-root.d.ts +6 -2
- package/dist/map/root/map-root.js +5 -2
- package/dist/megamenu/root/megamenu-root.d.ts +62 -0
- package/dist/megamenu/root/megamenu-root.js +90 -5
- package/dist/menu/index.d.ts +1 -0
- package/dist/menu/index.js +1 -0
- package/dist/menu/item/menu-item.d.ts +87 -11
- package/dist/menu/item/menu-item.js +78 -22
- package/dist/menu/root/menu-root.d.ts +39 -1
- package/dist/menu/root/menu-root.js +65 -8
- package/dist/menu/section/menu-section.d.ts +55 -0
- package/dist/menu/section/menu-section.js +60 -0
- package/dist/meter/root/meter-root.d.ts +20 -1
- package/dist/meter/root/meter-root.js +11 -15
- package/dist/navigation/root/navigation-root.d.ts +18 -2
- package/dist/navigation/root/navigation-root.js +29 -3
- package/dist/notifications/root/notifications-root.d.ts +25 -0
- package/dist/notifications/root/notifications-root.js +33 -5
- package/dist/number-input/root/number-input-root.d.ts +17 -8
- package/dist/number-input/root/number-input-root.js +2 -7
- package/dist/object-inspector/root/object-inspector-root.d.ts +161 -32
- package/dist/object-inspector/root/object-inspector-root.js +264 -123
- package/dist/object-inspector/rows.d.ts +75 -0
- package/dist/object-inspector/rows.js +119 -0
- package/dist/option/root/option-root.d.ts +5 -3
- package/dist/outline/levels.d.ts +31 -0
- package/dist/outline/levels.js +23 -0
- package/dist/outline/root/outline-root.d.ts +86 -3
- package/dist/outline/root/outline-root.js +95 -12
- package/dist/pagination/size/pagination-size.d.ts +12 -2
- package/dist/pagination/size/pagination-size.js +20 -5
- package/dist/pin-input/code.d.ts +10 -0
- package/dist/pin-input/code.js +13 -0
- package/dist/pin-input/root/pin-input-root.d.ts +25 -1
- package/dist/pin-input/root/pin-input-root.js +10 -11
- package/dist/popover/hide-outside.d.ts +14 -0
- package/dist/popover/hide-outside.js +41 -0
- package/dist/popover/root/popover-root.d.ts +57 -7
- package/dist/popover/root/popover-root.js +58 -3
- package/dist/progress/root/progress-root.d.ts +20 -0
- package/dist/progress/root/progress-root.js +15 -15
- package/dist/qr-code/export.d.ts +26 -1
- package/dist/qr-code/export.js +14 -0
- package/dist/qr-code/root/qr-code-root.d.ts +19 -5
- package/dist/qr-code/root/qr-code-root.js +58 -9
- package/dist/quote/marks.d.ts +8 -0
- package/dist/quote/marks.js +5 -0
- package/dist/quote/root/quote-root.d.ts +14 -2
- package/dist/quote/root/quote-root.js +23 -1
- package/dist/radio/group/radio-group.d.ts +4 -10
- package/dist/radio/group/radio-group.js +5 -10
- package/dist/radio/root/radio-root.d.ts +6 -2
- package/dist/radio/root/radio-root.js +6 -1
- package/dist/rating/root/rating-root.d.ts +10 -5
- package/dist/rating/root/rating-root.js +32 -8
- package/dist/rating/steps.d.ts +7 -0
- package/dist/rating/steps.js +9 -0
- package/dist/scatter-chart/fit.d.ts +15 -0
- package/dist/scatter-chart/fit.js +35 -0
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +21 -1
- package/dist/scatter-chart/root/scatter-chart-root.js +30 -17
- package/dist/scroll-area/root/scroll-area-root.d.ts +84 -0
- package/dist/scroll-area/root/scroll-area-root.js +106 -7
- package/dist/scroll-area/scrollbar-controller.d.ts +111 -0
- package/dist/scroll-area/scrollbar-controller.js +172 -0
- package/dist/scroll-area/scrollbar.d.ts +92 -0
- package/dist/scroll-area/scrollbar.js +33 -0
- package/dist/select/root/select-root.d.ts +15 -0
- package/dist/select/root/select-root.js +18 -6
- package/dist/skeleton/root/skeleton-root.d.ts +3 -0
- package/dist/skeleton/root/skeleton-root.js +4 -2
- package/dist/skip-link/root/skip-link-root.js +2 -2
- package/dist/slider/root/slider-root.d.ts +41 -4
- package/dist/slider/root/slider-root.js +23 -3
- package/dist/sparkline/readings.d.ts +18 -0
- package/dist/sparkline/readings.js +19 -0
- package/dist/sparkline/root/sparkline-root.d.ts +78 -7
- package/dist/sparkline/root/sparkline-root.js +118 -23
- package/dist/speed-dial/root/speed-dial-root.js +2 -2
- package/dist/splitter/root/splitter-root.d.ts +20 -12
- package/dist/splitter/root/splitter-root.js +226 -203
- package/dist/splitter/snap.d.ts +9 -0
- package/dist/splitter/snap.js +12 -0
- package/dist/stat/root/stat-root.d.ts +14 -5
- package/dist/stat/root/stat-root.js +21 -5
- package/dist/steps/reach.d.ts +20 -0
- package/dist/steps/reach.js +15 -0
- package/dist/steps/root/steps-root.d.ts +76 -0
- package/dist/steps/root/steps-root.js +93 -1
- package/dist/steps/step/step.d.ts +45 -2
- package/dist/steps/step/step.js +33 -6
- package/dist/switch/root/switch-root.d.ts +10 -0
- package/dist/table/column/table-column.d.ts +11 -10
- package/dist/table/column/table-column.js +8 -19
- package/dist/table/root/table-root.d.ts +126 -4
- package/dist/table/root/table-root.js +156 -6
- package/dist/table/row/table-row.d.ts +47 -1
- package/dist/table/row/table-row.js +39 -2
- package/dist/tabs/panel/tab-panel.d.ts +22 -5
- package/dist/tabs/panel/tab-panel.js +34 -6
- package/dist/tabs/root/tabs-root.d.ts +37 -1
- package/dist/tabs/root/tabs-root.js +22 -4
- package/dist/tabs/tab/tab.d.ts +41 -4
- package/dist/tabs/tab/tab.js +49 -3
- package/dist/tag/group/tag-group.d.ts +31 -4
- package/dist/tag/group/tag-group.js +46 -7
- package/dist/tag/root/tag-root.js +9 -2
- package/dist/textarea/root/textarea-root.d.ts +28 -1
- package/dist/textarea/root/textarea-root.js +40 -1
- package/dist/time-input/root/time-input-root.d.ts +5 -1
- package/dist/time-input/root/time-input-root.js +16 -8
- package/dist/time-picker/root/time-picker-root.d.ts +18 -4
- package/dist/time-picker/root/time-picker-root.js +7 -10
- package/dist/time-picker/wheel-name.d.ts +9 -0
- package/dist/time-picker/wheel-name.js +15 -0
- package/dist/timeline/group/timeline-group.d.ts +46 -0
- package/dist/timeline/group/timeline-group.js +37 -0
- package/dist/timeline/index.d.ts +1 -0
- package/dist/timeline/index.js +1 -0
- package/dist/timeline/root/timeline-root.d.ts +10 -3
- package/dist/toast/item/toast-item.d.ts +24 -18
- package/dist/toast/item/toast-item.js +36 -40
- package/dist/toast/root/toast-root.d.ts +6 -0
- package/dist/toast/root/toast-root.js +16 -1
- package/dist/toggle/group/toggle-group.d.ts +24 -3
- package/dist/toggle/group/toggle-group.js +34 -5
- package/dist/toolbar/root/toolbar-root.d.ts +13 -0
- package/dist/toolbar/root/toolbar-root.js +15 -5
- package/dist/tooltip/root/tooltip-root.d.ts +13 -2
- package/dist/tooltip/root/tooltip-root.js +9 -1
- package/dist/tour/back.d.ts +10 -0
- package/dist/tour/back.js +8 -0
- package/dist/tour/root/tour-root.d.ts +30 -2
- package/dist/tour/root/tour-root.js +34 -8
- package/dist/tree/item/tree-item.d.ts +61 -4
- package/dist/tree/item/tree-item.js +92 -20
- package/dist/tree/root/tree-root.d.ts +58 -0
- package/dist/tree/root/tree-root.js +80 -16
- package/dist/tree/selection.d.ts +24 -0
- package/dist/tree/selection.js +13 -0
- package/dist/trend/root/trend-root.d.ts +43 -18
- package/dist/trend/root/trend-root.js +31 -6
- package/dist/video/media-events.d.ts +44 -0
- package/dist/video/media-events.js +35 -0
- package/dist/video/root/video-root.d.ts +117 -18
- package/dist/video/root/video-root.js +93 -47
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +5 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +3 -1
- package/dist/video-playlist/order.d.ts +41 -0
- package/dist/video-playlist/order.js +34 -0
- package/dist/video-playlist/root/video-playlist-root.d.ts +77 -3
- package/dist/video-playlist/root/video-playlist-root.js +60 -16
- package/dist/virtual-list/controls.d.ts +4 -0
- package/dist/virtual-list/controls.js +30 -0
- package/dist/virtual-list/fill.d.ts +22 -0
- package/dist/virtual-list/fill.js +23 -0
- package/dist/virtual-list/keys.d.ts +15 -0
- package/dist/virtual-list/keys.js +24 -0
- package/dist/virtual-list/plan.d.ts +49 -0
- package/dist/virtual-list/plan.js +16 -0
- package/dist/virtual-list/root/virtual-list-root.d.ts +259 -26
- package/dist/virtual-list/root/virtual-list-root.js +333 -49
- package/lint.json +1 -1
- package/package.json +8 -8
- package/types/jsx.d.ts +8113 -1394
- package/types/svelte.d.ts +2 -0
- package/types/vue.d.ts +1678 -353
- package/dist/data-table/root/order.d.ts +0 -141
- package/dist/data-table/root/order.js +0 -76
- package/dist/listbox/range.d.ts +0 -17
- package/dist/listbox/range.js +0 -5
- package/dist/tag/selection.d.ts +0 -10
- package/dist/tag/selection.js +0 -12
|
@@ -4,47 +4,118 @@ 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, slottedWords } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
+
const CONTROL = 'a[href], button, input, select, textarea, [tabindex]';
|
|
10
11
|
let HelixHeadlessListItem = class HelixHeadlessListItem extends HelixElement {
|
|
11
12
|
constructor() {
|
|
12
13
|
super(...arguments);
|
|
14
|
+
this.disabled = false;
|
|
13
15
|
this.href = '';
|
|
14
16
|
this.rel = '';
|
|
15
17
|
this.target = '';
|
|
18
|
+
this.value = '';
|
|
19
|
+
}
|
|
20
|
+
get words() {
|
|
21
|
+
return this.childrenKnown ? slottedWords(this, ['']) : '';
|
|
22
|
+
}
|
|
23
|
+
get described() {
|
|
24
|
+
return this.childrenKnown && this.knownChildren.some((child) => child.slot === 'description');
|
|
25
|
+
}
|
|
26
|
+
get grouped() {
|
|
27
|
+
return this.focusable !== undefined;
|
|
28
|
+
}
|
|
29
|
+
get cell() {
|
|
30
|
+
return this.renderRoot?.querySelector?.('[part~="row"]') ?? null;
|
|
31
|
+
}
|
|
32
|
+
get controls() {
|
|
33
|
+
const slot = this.renderRoot?.querySelector?.('slot[name="end"]');
|
|
34
|
+
return (slot?.assignedElements({ flatten: true }) ?? [])
|
|
35
|
+
.flatMap((element) => [element, ...element.querySelectorAll('*')])
|
|
36
|
+
.filter((element) => element instanceof HTMLElement &&
|
|
37
|
+
element.matches(CONTROL) &&
|
|
38
|
+
!element.matches(':disabled'));
|
|
39
|
+
}
|
|
40
|
+
focusItem() {
|
|
41
|
+
this.cell?.focus();
|
|
42
|
+
}
|
|
43
|
+
follow() {
|
|
44
|
+
this.renderRoot?.querySelector('[part~="link"]')?.click();
|
|
16
45
|
}
|
|
17
46
|
willUpdate(changed) {
|
|
18
47
|
super.willUpdate(changed);
|
|
19
|
-
hostAria(this.internals, { role: 'listitem' });
|
|
48
|
+
hostAria(this.internals, { role: this.grouped ? 'row' : 'listitem' });
|
|
49
|
+
this.internals.ariaSelected = this.selected === undefined ? null : String(this.selected);
|
|
50
|
+
this.internals.ariaDisabled = this.grouped && this.disabled ? 'true' : null;
|
|
51
|
+
this.internals.ariaCurrent =
|
|
52
|
+
this.current !== undefined && this.href === '' ? this.current : null;
|
|
53
|
+
this.toggleState('selected', this.selected === true);
|
|
20
54
|
}
|
|
21
55
|
renderRail() {
|
|
22
56
|
return nothing;
|
|
23
57
|
}
|
|
24
58
|
render() {
|
|
25
59
|
const content = html `${this.renderRail()}<slot name="start"></slot>
|
|
26
|
-
<slot></slot>
|
|
27
|
-
<slot name="description"></slot>`;
|
|
60
|
+
<slot id="label"></slot>
|
|
61
|
+
<slot name="description" id="description"></slot>`;
|
|
62
|
+
const role = this.grouped ? 'gridcell' : nothing;
|
|
63
|
+
const tabindex = this.grouped ? (this.focusable ? '0' : '-1') : nothing;
|
|
64
|
+
const labelledby = this.grouped && this.words !== '' ? 'label' : nothing;
|
|
65
|
+
const describedby = this.grouped && this.described ? 'description' : nothing;
|
|
28
66
|
return this.href === ''
|
|
29
|
-
? html `<div
|
|
30
|
-
|
|
67
|
+
? html `<div
|
|
68
|
+
part="row${this.current === undefined ? '' : ' row-current'}"
|
|
69
|
+
role=${role}
|
|
70
|
+
tabindex=${tabindex}
|
|
71
|
+
aria-labelledby=${labelledby}
|
|
72
|
+
aria-describedby=${describedby}
|
|
73
|
+
>${content}<slot name="end"></slot></div>`
|
|
74
|
+
: html `<div
|
|
75
|
+
part="row${this.current === undefined ? '' : ' row-current'}"
|
|
76
|
+
role=${role}
|
|
77
|
+
tabindex=${tabindex}
|
|
78
|
+
aria-labelledby=${labelledby}
|
|
79
|
+
aria-describedby=${describedby}
|
|
80
|
+
><a
|
|
31
81
|
part="link"
|
|
32
82
|
href=${this.href}
|
|
33
83
|
target=${this.target || nothing}
|
|
34
84
|
rel=${this.rel || nothing}
|
|
85
|
+
aria-current=${this.current ?? nothing}
|
|
86
|
+
tabindex=${this.grouped ? '-1' : nothing}
|
|
35
87
|
>${content}</a
|
|
36
88
|
><slot name="end"></slot></div>`;
|
|
37
89
|
}
|
|
38
90
|
};
|
|
91
|
+
__decorate([
|
|
92
|
+
property({
|
|
93
|
+
converter: {
|
|
94
|
+
fromAttribute: (value) => value === null || value === 'false' ? undefined : (value || 'true'),
|
|
95
|
+
},
|
|
96
|
+
})
|
|
97
|
+
], HelixHeadlessListItem.prototype, "current", void 0);
|
|
98
|
+
__decorate([
|
|
99
|
+
property({ reflect: true, type: Boolean })
|
|
100
|
+
], HelixHeadlessListItem.prototype, "disabled", void 0);
|
|
101
|
+
__decorate([
|
|
102
|
+
property({ attribute: false })
|
|
103
|
+
], HelixHeadlessListItem.prototype, "focusable", void 0);
|
|
39
104
|
__decorate([
|
|
40
105
|
property()
|
|
41
106
|
], HelixHeadlessListItem.prototype, "href", void 0);
|
|
42
107
|
__decorate([
|
|
43
108
|
property()
|
|
44
109
|
], HelixHeadlessListItem.prototype, "rel", void 0);
|
|
110
|
+
__decorate([
|
|
111
|
+
property({ attribute: false })
|
|
112
|
+
], HelixHeadlessListItem.prototype, "selected", void 0);
|
|
45
113
|
__decorate([
|
|
46
114
|
property()
|
|
47
115
|
], HelixHeadlessListItem.prototype, "target", void 0);
|
|
116
|
+
__decorate([
|
|
117
|
+
property()
|
|
118
|
+
], HelixHeadlessListItem.prototype, "value", void 0);
|
|
48
119
|
HelixHeadlessListItem = __decorate([
|
|
49
120
|
customElement('helix-headless-list-item')
|
|
50
121
|
], HelixHeadlessListItem);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** The first row's number, and what each row after it adds. */
|
|
2
|
+
export interface Numbering {
|
|
3
|
+
first: number;
|
|
4
|
+
step: -1 | 1;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* The numbering `start` and `reversed` ask for, as `<ol>` reads them, or
|
|
8
|
+
* nothing where they ask for the ordinary count from one.
|
|
9
|
+
*
|
|
10
|
+
* Reversed without a start counts down from the number of rows, which is
|
|
11
|
+
* unknown until the rows are: `count` is `undefined` on a server and while
|
|
12
|
+
* hydrating, and the list counts from one until it knows.
|
|
13
|
+
*/
|
|
14
|
+
export declare const numbering: (start: number | undefined, reversed: boolean, count: number | undefined) => Numbering | undefined;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const numbering = (start, reversed, count) => {
|
|
2
|
+
const from = start !== undefined && Number.isFinite(start) ? Math.trunc(start) : undefined;
|
|
3
|
+
if (!reversed) {
|
|
4
|
+
return from === undefined ? undefined : { first: from, step: 1 };
|
|
5
|
+
}
|
|
6
|
+
const first = from ?? count;
|
|
7
|
+
return first === undefined ? undefined : { first, step: -1 };
|
|
8
|
+
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { HelixElement } from '@fusion.dev/helix-core';
|
|
1
|
+
import { HelixElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
+
import { HelixHeadlessListItem } from '../item/list-item.js';
|
|
4
|
+
import { type ListSelectionBehavior, type ListSelectionMode } from '../selection.js';
|
|
3
5
|
/**
|
|
4
6
|
* @summary A set of rows, announced as a list.
|
|
5
7
|
*
|
|
@@ -7,6 +9,47 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
7
9
|
* Sets `role="list"` on the host, so a screen reader counts the rows and
|
|
8
10
|
* announces each one's position, such as "1 of 7".
|
|
9
11
|
*
|
|
12
|
+
* **`selection-mode` makes the list interactive**, in the way of a grid list:
|
|
13
|
+
* a grid of rows that is one tab stop. `single` selects one row at a time and
|
|
14
|
+
* `multiple` any number, and `value` holds the selected rows' values,
|
|
15
|
+
* separated by commas. A change asks with `helix-before-change` and tells
|
|
16
|
+
* with `change`. `none` selects nothing, so a press acts on the row. A
|
|
17
|
+
* `disabled` row is passed over. Each row is named by its label and described
|
|
18
|
+
* by its description, so the words of the controls in `end` are not read as
|
|
19
|
+
* part of its name.
|
|
20
|
+
*
|
|
21
|
+
* `selection-behavior` says what a press does to the rows already selected.
|
|
22
|
+
* `toggle`, the default, adds or takes out the row. `replace` selects the row
|
|
23
|
+
* alone, as a file list does, and the arrow keys carry the selection with
|
|
24
|
+
* them. Control or Command with a press then adds or takes out one row.
|
|
25
|
+
*
|
|
26
|
+
* | Key | What it does |
|
|
27
|
+
* |---|---|
|
|
28
|
+
* | Down, Up | Moves to the next or the previous row. Under `replace`, selects it. |
|
|
29
|
+
* | Home, End | Moves to the first or the last row. Under `replace`, selects it. |
|
|
30
|
+
* | A letter or a word | Moves to the next row whose words start with what you typed. |
|
|
31
|
+
* | Left, Right | Moves between the row and the controls in its `end` slot. |
|
|
32
|
+
* | Space | Selects the row, or lets it go. |
|
|
33
|
+
* | Shift with Down, Up, Home, End or Space | Selects every row from the last one pressed, in `multiple`. |
|
|
34
|
+
* | Control or Command with Down, Up, Home or End | Moves without selecting, under `replace`. |
|
|
35
|
+
* | Control or Command with A | Selects every row, in `multiple`. |
|
|
36
|
+
* | Enter | Acts on the row: follows its link, or sends `helix-action` from it. |
|
|
37
|
+
*
|
|
38
|
+
* A press with Shift selects every row from the last one pressed, and a press
|
|
39
|
+
* with Control or Command adds or takes out one row under `replace`.
|
|
40
|
+
*
|
|
41
|
+
* **Leave `selection-mode` unset for a list a reader reads**, and set it for
|
|
42
|
+
* one a reader chooses from or acts on. The rows of an interactive list are
|
|
43
|
+
* grid rows, which hold controls as a list box option cannot. Give a control
|
|
44
|
+
* in `end` `tabindex="-1"` to leave it to the arrow keys and out of the tab
|
|
45
|
+
* order.
|
|
46
|
+
*
|
|
47
|
+
* `start` and `reversed` number an ordered list as `<ol>` does. The list
|
|
48
|
+
* writes where the numbers start and which way they run as `--list-first` and
|
|
49
|
+
* `--list-step` on its slot, which the styled tier counts from. Reversed with
|
|
50
|
+
* no `start` counts down from the number of rows, which a server cannot know,
|
|
51
|
+
* so served markup counts from one until the list runs.
|
|
52
|
+
*
|
|
10
53
|
* @since 0.1.0
|
|
11
54
|
* @status stable
|
|
12
55
|
* @category data
|
|
@@ -14,6 +57,13 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
14
57
|
* @documentation https://fusion.dev/helix/components/list
|
|
15
58
|
*
|
|
16
59
|
* @slot - The rows.
|
|
60
|
+
*
|
|
61
|
+
* @event {Event} change - Fired once a press has changed which rows are selected.
|
|
62
|
+
* @event {HelixActionEvent} helix-action - Sent from a row when the reader acts on it: Enter, or a press in a list that selects nothing. Read the row from `target`. A row with `href` follows its link instead.
|
|
63
|
+
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before a press changes which rows are selected, with the `value` it would leave. Cancelable.
|
|
64
|
+
*
|
|
65
|
+
* @cssproperty --list-first - The number of the first row, written where `start` or `reversed` moves it.
|
|
66
|
+
* @cssproperty --list-step - What each row adds to the number before it: `1`, or `-1` where `reversed`.
|
|
17
67
|
*/
|
|
18
68
|
export declare class HelixHeadlessList extends HelixElement {
|
|
19
69
|
/**
|
|
@@ -43,6 +93,28 @@ export declare class HelixHeadlessList extends HelixElement {
|
|
|
43
93
|
* The list's name, read by screen readers.
|
|
44
94
|
*/
|
|
45
95
|
label: string;
|
|
96
|
+
/**
|
|
97
|
+
* Numbers an ordered list downward, so the count falls row by row and ends at
|
|
98
|
+
* its last row, as `<ol reversed>` does.
|
|
99
|
+
*/
|
|
100
|
+
reversed: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* What a press does to the rows already selected, in a list that selects:
|
|
103
|
+
* `toggle` adds or takes out the row, and `replace` selects it alone and
|
|
104
|
+
* lets the arrow keys carry the selection.
|
|
105
|
+
*/
|
|
106
|
+
selectionBehavior: ListSelectionBehavior;
|
|
107
|
+
/**
|
|
108
|
+
* Makes the list interactive: `single` selects one row, `multiple` any
|
|
109
|
+
* number, and `none` moves and acts without selecting. Unset is a list a
|
|
110
|
+
* reader reads, with no tab stop of its own.
|
|
111
|
+
*/
|
|
112
|
+
selectionMode?: ListSelectionMode;
|
|
113
|
+
/**
|
|
114
|
+
* The number of an ordered list's first row, as `<ol start>` is. Unset counts
|
|
115
|
+
* from one, or down from the number of rows where `reversed`.
|
|
116
|
+
*/
|
|
117
|
+
start?: number;
|
|
46
118
|
/**
|
|
47
119
|
* The markers an ordered list draws. It takes the five values of `<ol type>`.
|
|
48
120
|
*
|
|
@@ -51,18 +123,92 @@ export declare class HelixHeadlessList extends HelixElement {
|
|
|
51
123
|
* the CSS ones, so `<helix-headless-list kind="ordered" type="i">` is what a
|
|
52
124
|
* consumer would have written on an `<ol>`.
|
|
53
125
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* `list-item` counter, and that counter is not author-resettable. Measured in
|
|
57
|
-
* Chrome 148, `counter-reset: list-item 4` moves nothing on a `<div>`, on a
|
|
58
|
-
* `<ul>`, or even on a real `<ol>`, while `<ol start="5">` does and a *named*
|
|
59
|
-
* counter with explicit `::before` content does. So the markers would have to
|
|
60
|
-
* be rebuilt out of generated content to gain a start, which is a different
|
|
61
|
-
* component. `type` is only `list-style-type` and works.
|
|
126
|
+
* `type` is only `list-style-type`. `start` and `reversed` move the count
|
|
127
|
+
* itself.
|
|
62
128
|
*/
|
|
63
129
|
type?: '1' | 'a' | 'A' | 'i' | 'I';
|
|
130
|
+
/**
|
|
131
|
+
* The selected rows' values, separated by commas, in a list that selects.
|
|
132
|
+
*
|
|
133
|
+
* Set it to start with rows selected. A row's value is its `value`, or its
|
|
134
|
+
* words where it has none.
|
|
135
|
+
*/
|
|
136
|
+
value: string;
|
|
137
|
+
/** The row the reader was last on, which keeps the tab stop. */
|
|
138
|
+
private last;
|
|
139
|
+
/** The value of the row a Shift range runs from: the last row pressed. */
|
|
140
|
+
private anchor;
|
|
141
|
+
/**
|
|
142
|
+
* Shift and Control or Command on the key that is moving focus, read when
|
|
143
|
+
* focus arrives on a row and cleared once the key has been answered.
|
|
144
|
+
*/
|
|
145
|
+
private moving;
|
|
146
|
+
/**
|
|
147
|
+
* Up, Down, Home, End and typed letters, moving focus and choosing nothing,
|
|
148
|
+
* from the focused row and without wrapping. Left and Right are the row's.
|
|
149
|
+
*/
|
|
150
|
+
protected readonly keys: KeyboardNavigationController;
|
|
151
|
+
/** Whether the list is a grid a reader moves through. */
|
|
152
|
+
private get interactive();
|
|
153
|
+
/** The rows the list holds, in order. */
|
|
154
|
+
get rows(): HelixHeadlessListItem[];
|
|
155
|
+
/** The rows a key can land on, in an interactive list. */
|
|
156
|
+
private get reachable();
|
|
157
|
+
/** A row as the keyboard controller sees it: an item it moves focus to and never chooses. */
|
|
158
|
+
private navigable;
|
|
159
|
+
/** What a row stands for in `value`: its own `value`, or its words. */
|
|
160
|
+
private valueFor;
|
|
161
|
+
/**
|
|
162
|
+
* Tells every row its place: whether it holds the one tab stop and whether
|
|
163
|
+
* it is selected, or that it is a plain row. Through `whenHydrated`, so a
|
|
164
|
+
* row a server rendered draws its served markup first.
|
|
165
|
+
*/
|
|
166
|
+
private sync;
|
|
167
|
+
/** The row a press or a key came from, read off the event's path. */
|
|
168
|
+
private rowOf;
|
|
169
|
+
/**
|
|
170
|
+
* Selects what a press or a key leaves, asking first. `helix-before-change`
|
|
171
|
+
* carries the `value` it would leave, and `change` follows once it has moved.
|
|
172
|
+
*/
|
|
173
|
+
private choose;
|
|
174
|
+
/** What `choiceValue` needs of this list for a row. */
|
|
175
|
+
private choice;
|
|
176
|
+
/**
|
|
177
|
+
* Selects the row, or lets it go, by `selection-behavior`: Shift takes in
|
|
178
|
+
* the rows from the last one pressed, and Control or Command toggles one row
|
|
179
|
+
* under `replace`. The row is where the next range runs from.
|
|
180
|
+
*/
|
|
181
|
+
protected press(row: HelixHeadlessListItem, extend?: boolean, toggle?: boolean): void;
|
|
182
|
+
/**
|
|
183
|
+
* A key moved focus onto the row: under `replace` it is selected alone, and
|
|
184
|
+
* with Shift the rows from the anchor are taken in, from `from` where
|
|
185
|
+
* nothing was pressed yet.
|
|
186
|
+
*/
|
|
187
|
+
private arrive;
|
|
188
|
+
/** Acts on the row: follows its link, or says it was acted on. */
|
|
189
|
+
protected act(row: HelixHeadlessListItem): void;
|
|
190
|
+
/** Left and Right inside a row: the cell, then each control in `end`, and back. */
|
|
191
|
+
private moveInRow;
|
|
192
|
+
/**
|
|
193
|
+
* Notes the modifiers of a key before the keyboard controller moves focus
|
|
194
|
+
* with it, which happens first, in the same dispatch.
|
|
195
|
+
*/
|
|
196
|
+
private readonly handleKeyCapture;
|
|
197
|
+
private readonly handleKeydown;
|
|
198
|
+
private readonly handleClick;
|
|
199
|
+
private readonly handleFocusin;
|
|
200
|
+
connectedCallback(): void;
|
|
201
|
+
disconnectedCallback(): void;
|
|
202
|
+
protected firstUpdated(changed: PropertyValues): void;
|
|
203
|
+
protected updated(changed: PropertyValues): void;
|
|
64
204
|
protected willUpdate(changed: PropertyValues): void;
|
|
205
|
+
/**
|
|
206
|
+
* Where the numbers start and which way they run, as custom properties on
|
|
207
|
+
* the slot the rows inherit from, or nothing where they count up from one.
|
|
208
|
+
*/
|
|
209
|
+
private get numbers();
|
|
65
210
|
protected render(): TemplateResult;
|
|
211
|
+
private readonly handleSlotChange;
|
|
66
212
|
}
|
|
67
213
|
declare global {
|
|
68
214
|
interface HTMLElementTagNameMap {
|
|
@@ -4,20 +4,247 @@ 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';
|
|
8
|
-
import { html } from 'lit';
|
|
7
|
+
import { commaList, customElement, HelixActionEvent, HelixBeforeChangeEvent, HelixElement, hostAria, inlineStep, KeyboardNavigationController, requestChange, rovingStop, typeaheadBy, whenHydrated, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
+
import { HelixHeadlessListItem } from '../item/list-item.js';
|
|
11
|
+
import { numbering } from '../numbering.js';
|
|
12
|
+
import { choiceValue, rowStop, } from '../selection.js';
|
|
13
|
+
const PRESSABLE = 'a[href], button, input, label, select, textarea, [tabindex]';
|
|
10
14
|
let HelixHeadlessList = class HelixHeadlessList extends HelixElement {
|
|
11
15
|
constructor() {
|
|
12
16
|
super(...arguments);
|
|
13
17
|
this.label = '';
|
|
18
|
+
this.reversed = false;
|
|
19
|
+
this.selectionBehavior = 'toggle';
|
|
20
|
+
this.value = '';
|
|
21
|
+
this.keys = new KeyboardNavigationController(this, {
|
|
22
|
+
items: () => this.reachable.map((row) => this.navigable(row)),
|
|
23
|
+
origin: 'focus',
|
|
24
|
+
reserved: () => ['ArrowLeft', 'ArrowRight'],
|
|
25
|
+
selects: () => false,
|
|
26
|
+
typeahead: typeaheadBy((item) => item.words),
|
|
27
|
+
wrap: false,
|
|
28
|
+
});
|
|
29
|
+
this.handleKeyCapture = (event) => {
|
|
30
|
+
this.moving = { extend: event.shiftKey, toggle: event.ctrlKey || event.metaKey };
|
|
31
|
+
};
|
|
32
|
+
this.handleKeydown = (event) => {
|
|
33
|
+
this.moving = undefined;
|
|
34
|
+
const row = this.interactive ? this.rowOf(event) : undefined;
|
|
35
|
+
if (!row || row.disabled || event.altKey) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const toggle = event.ctrlKey || event.metaKey;
|
|
39
|
+
if (!toggle && (event.key === 'ArrowLeft' || event.key === 'ArrowRight')) {
|
|
40
|
+
this.moveInRow(row, event);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (event.composedPath()[0] !== row.cell) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (toggle && event.key.toLowerCase() === 'a' && this.selectionMode === 'multiple') {
|
|
47
|
+
event.preventDefault();
|
|
48
|
+
const every = this.reachable.map((one) => this.valueFor(one)).join(', ');
|
|
49
|
+
this.choose(every === this.value ? null : every);
|
|
50
|
+
}
|
|
51
|
+
else if (event.key === 'Enter' && !toggle) {
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
this.act(row);
|
|
54
|
+
}
|
|
55
|
+
else if (event.key === ' ' && !event.defaultPrevented) {
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
this.press(row, event.shiftKey, toggle);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
this.handleClick = (event) => {
|
|
61
|
+
const row = this.interactive ? this.rowOf(event) : undefined;
|
|
62
|
+
if (!row) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const path = event.composedPath();
|
|
66
|
+
const cell = row.cell;
|
|
67
|
+
const end = cell && path.includes(cell) ? path.indexOf(cell) : path.indexOf(row);
|
|
68
|
+
const inner = path.slice(0, Math.max(0, end));
|
|
69
|
+
if (inner.some((node) => node instanceof HTMLElement && node.matches(PRESSABLE))) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (this.selectionMode === 'none') {
|
|
73
|
+
this.act(row);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
this.press(row, event.shiftKey, event.ctrlKey || event.metaKey);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
this.handleFocusin = (event) => {
|
|
80
|
+
const row = this.interactive ? this.rowOf(event) : undefined;
|
|
81
|
+
if (row && row !== this.last) {
|
|
82
|
+
const from = this.last;
|
|
83
|
+
this.last = row;
|
|
84
|
+
if (event.composedPath()[0] === row.cell) {
|
|
85
|
+
this.arrive(row, from);
|
|
86
|
+
}
|
|
87
|
+
this.sync();
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
this.handleSlotChange = () => {
|
|
91
|
+
this.requestUpdate();
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
get interactive() {
|
|
95
|
+
return this.selectionMode !== undefined;
|
|
96
|
+
}
|
|
97
|
+
get rows() {
|
|
98
|
+
return this.knownChildren.filter((child) => child instanceof HelixHeadlessListItem);
|
|
99
|
+
}
|
|
100
|
+
get reachable() {
|
|
101
|
+
return this.interactive ? this.rows.filter((row) => !row.disabled) : [];
|
|
102
|
+
}
|
|
103
|
+
navigable(row) {
|
|
104
|
+
return {
|
|
105
|
+
contains: (node) => row.contains(node),
|
|
106
|
+
disabled: row.disabled,
|
|
107
|
+
focusItem: () => row.focusItem(),
|
|
108
|
+
select: () => { },
|
|
109
|
+
selected: false,
|
|
110
|
+
words: row.words,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
valueFor(row) {
|
|
114
|
+
return row.value || row.words;
|
|
115
|
+
}
|
|
116
|
+
sync() {
|
|
117
|
+
const mode = this.selectionMode;
|
|
118
|
+
const chosen = new Set(commaList(this.value));
|
|
119
|
+
const rows = this.rows;
|
|
120
|
+
const holder = mode
|
|
121
|
+
? rovingStop(rows, this.last, {
|
|
122
|
+
disabled: (row) => row.disabled,
|
|
123
|
+
selected: (row) => chosen.has(this.valueFor(row)),
|
|
124
|
+
})
|
|
125
|
+
: undefined;
|
|
126
|
+
for (const row of rows) {
|
|
127
|
+
whenHydrated(row, () => {
|
|
128
|
+
row.focusable = mode ? row === holder : undefined;
|
|
129
|
+
row.selected =
|
|
130
|
+
mode === undefined || mode === 'none' ? undefined : chosen.has(this.valueFor(row));
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
rowOf(event) {
|
|
135
|
+
return event
|
|
136
|
+
.composedPath()
|
|
137
|
+
.find((node) => node instanceof HelixHeadlessListItem && node.parentElement === this);
|
|
138
|
+
}
|
|
139
|
+
choose(next) {
|
|
140
|
+
if (next === null) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
requestChange({
|
|
144
|
+
apply: (value) => {
|
|
145
|
+
this.value = value;
|
|
146
|
+
this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
|
147
|
+
},
|
|
148
|
+
event: (value) => new HelixBeforeChangeEvent({ value }),
|
|
149
|
+
host: this,
|
|
150
|
+
next,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
choice(row, extend, toggle, arrived) {
|
|
154
|
+
return {
|
|
155
|
+
anchor: this.anchor,
|
|
156
|
+
arrived,
|
|
157
|
+
behavior: this.selectionBehavior,
|
|
158
|
+
extend,
|
|
159
|
+
mode: this.selectionMode ?? 'none',
|
|
160
|
+
pressed: this.valueFor(row),
|
|
161
|
+
shown: this.reachable.map((one) => this.valueFor(one)),
|
|
162
|
+
toggle,
|
|
163
|
+
value: this.value,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
press(row, extend = false, toggle = false) {
|
|
167
|
+
const mode = this.selectionMode;
|
|
168
|
+
if (mode === undefined || mode === 'none' || row.disabled) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const next = choiceValue(this.choice(row, extend, toggle, false));
|
|
172
|
+
if (!extend) {
|
|
173
|
+
this.anchor = this.valueFor(row);
|
|
174
|
+
}
|
|
175
|
+
this.choose(next);
|
|
176
|
+
}
|
|
177
|
+
arrive(row, from) {
|
|
178
|
+
const moving = this.moving;
|
|
179
|
+
if (!moving || this.selectionMode === undefined || this.selectionMode === 'none') {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (moving.extend && this.anchor === undefined && from) {
|
|
183
|
+
this.anchor = this.valueFor(from);
|
|
184
|
+
}
|
|
185
|
+
const next = choiceValue(this.choice(row, moving.extend, moving.toggle, true));
|
|
186
|
+
if (!moving.extend && next !== null) {
|
|
187
|
+
this.anchor = this.valueFor(row);
|
|
188
|
+
}
|
|
189
|
+
this.choose(next);
|
|
190
|
+
}
|
|
191
|
+
act(row) {
|
|
192
|
+
if (row.disabled) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (row.href !== '') {
|
|
196
|
+
row.follow();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
row.dispatchEvent(new HelixActionEvent());
|
|
200
|
+
}
|
|
201
|
+
moveInRow(row, event) {
|
|
202
|
+
const step = inlineStep(this, event.key);
|
|
203
|
+
const cell = row.cell;
|
|
204
|
+
if (step === 0 || !cell) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const stops = [cell, ...row.controls];
|
|
208
|
+
const on = event.composedPath().find((node) => stops.includes(node));
|
|
209
|
+
const at = Math.max(0, stops.indexOf(on));
|
|
210
|
+
event.preventDefault();
|
|
211
|
+
stops[rowStop(stops.length, at, step)]?.focus();
|
|
212
|
+
}
|
|
213
|
+
connectedCallback() {
|
|
214
|
+
super.connectedCallback();
|
|
215
|
+
this.addEventListener('keydown', this.handleKeyCapture, true);
|
|
216
|
+
this.addEventListener('keydown', this.handleKeydown);
|
|
217
|
+
this.addEventListener('click', this.handleClick);
|
|
218
|
+
this.addEventListener('focusin', this.handleFocusin);
|
|
219
|
+
}
|
|
220
|
+
disconnectedCallback() {
|
|
221
|
+
super.disconnectedCallback();
|
|
222
|
+
this.removeEventListener('keydown', this.handleKeyCapture, true);
|
|
223
|
+
this.removeEventListener('keydown', this.handleKeydown);
|
|
224
|
+
this.removeEventListener('click', this.handleClick);
|
|
225
|
+
this.removeEventListener('focusin', this.handleFocusin);
|
|
226
|
+
}
|
|
227
|
+
firstUpdated(changed) {
|
|
228
|
+
super.firstUpdated(changed);
|
|
229
|
+
this.finishHydration();
|
|
230
|
+
}
|
|
231
|
+
updated(changed) {
|
|
232
|
+
super.updated(changed);
|
|
233
|
+
if (this.interactive || changed.get('selectionMode') !== undefined) {
|
|
234
|
+
this.sync();
|
|
235
|
+
}
|
|
14
236
|
}
|
|
15
237
|
willUpdate(changed) {
|
|
16
238
|
super.willUpdate(changed);
|
|
17
|
-
hostAria(this.internals, { label: this.label, role: 'list' });
|
|
239
|
+
hostAria(this.internals, { label: this.label, role: this.interactive ? 'grid' : 'list' });
|
|
240
|
+
this.internals.ariaMultiSelectable = this.selectionMode === 'multiple' ? 'true' : null;
|
|
241
|
+
}
|
|
242
|
+
get numbers() {
|
|
243
|
+
const counted = numbering(this.start, this.reversed, this.childrenKnown ? this.knownChildren.length : undefined);
|
|
244
|
+
return counted ? `--list-first: ${counted.first}; --list-step: ${counted.step}` : nothing;
|
|
18
245
|
}
|
|
19
246
|
render() {
|
|
20
|
-
return html `<slot></slot>`;
|
|
247
|
+
return html `<slot style=${this.numbers} @slotchange=${this.handleSlotChange}></slot>`;
|
|
21
248
|
}
|
|
22
249
|
};
|
|
23
250
|
__decorate([
|
|
@@ -26,9 +253,24 @@ __decorate([
|
|
|
26
253
|
__decorate([
|
|
27
254
|
property()
|
|
28
255
|
], HelixHeadlessList.prototype, "label", void 0);
|
|
256
|
+
__decorate([
|
|
257
|
+
property({ type: Boolean })
|
|
258
|
+
], HelixHeadlessList.prototype, "reversed", void 0);
|
|
259
|
+
__decorate([
|
|
260
|
+
property({ attribute: 'selection-behavior' })
|
|
261
|
+
], HelixHeadlessList.prototype, "selectionBehavior", void 0);
|
|
262
|
+
__decorate([
|
|
263
|
+
property({ attribute: 'selection-mode' })
|
|
264
|
+
], HelixHeadlessList.prototype, "selectionMode", void 0);
|
|
265
|
+
__decorate([
|
|
266
|
+
property({ type: Number })
|
|
267
|
+
], HelixHeadlessList.prototype, "start", void 0);
|
|
29
268
|
__decorate([
|
|
30
269
|
property({ reflect: true })
|
|
31
270
|
], HelixHeadlessList.prototype, "type", void 0);
|
|
271
|
+
__decorate([
|
|
272
|
+
property()
|
|
273
|
+
], HelixHeadlessList.prototype, "value", void 0);
|
|
32
274
|
HelixHeadlessList = __decorate([
|
|
33
275
|
customElement('helix-headless-list')
|
|
34
276
|
], HelixHeadlessList);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type SelectionMode } from '@fusion.dev/helix-core';
|
|
2
|
+
/** How many rows a reader can select in an interactive list: core's `SelectionMode`. */
|
|
3
|
+
export type ListSelectionMode = SelectionMode;
|
|
4
|
+
/**
|
|
5
|
+
* What a press does to the rows already selected: `toggle` adds or takes out
|
|
6
|
+
* the row, and `replace` selects it alone, as a file list does.
|
|
7
|
+
*/
|
|
8
|
+
export type ListSelectionBehavior = 'replace' | 'toggle';
|
|
9
|
+
/** A press on a row, or a key arriving on one, and what the list held then. */
|
|
10
|
+
export interface ListChoice {
|
|
11
|
+
/** The list's `selection-mode`. */
|
|
12
|
+
mode: ListSelectionMode;
|
|
13
|
+
/** The list's `selection-behavior`. */
|
|
14
|
+
behavior: ListSelectionBehavior;
|
|
15
|
+
/** The list's `value`, before the press. */
|
|
16
|
+
value: string;
|
|
17
|
+
/** The value of the row pressed or arrived on. */
|
|
18
|
+
pressed: string;
|
|
19
|
+
/** The values of the rows a reader can reach, in order. */
|
|
20
|
+
shown: readonly string[];
|
|
21
|
+
/** The value of the row a range runs from, where there is one. */
|
|
22
|
+
anchor?: string | undefined;
|
|
23
|
+
/** Whether Shift was held, which takes in the rows from the anchor. */
|
|
24
|
+
extend?: boolean;
|
|
25
|
+
/** Whether Control or Command was held, which toggles under `replace` and moves without choosing. */
|
|
26
|
+
toggle?: boolean;
|
|
27
|
+
/** Whether a key moved focus onto the row, where a press is false. */
|
|
28
|
+
arrived?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The `value` a press or an arrival leaves, or `null` where it changes nothing.
|
|
32
|
+
*
|
|
33
|
+
* - With Shift, in a list that selects many, every row from the anchor to this
|
|
34
|
+
* one is added, as Data Table and Listbox add a range.
|
|
35
|
+
* - Under `replace`, the row is selected alone, by a press or by a key moving
|
|
36
|
+
* onto it. Control or Command toggles it under a press, and moves without
|
|
37
|
+
* choosing under a key.
|
|
38
|
+
* - Under `toggle`, a press adds or takes out the row, and a key only moves.
|
|
39
|
+
*/
|
|
40
|
+
export declare const choiceValue: ({ anchor, arrived, behavior, extend, mode, pressed, shown, toggle, value, }: ListChoice) => string | null;
|
|
41
|
+
/**
|
|
42
|
+
* Where Left or Right goes inside a row: `at` is the row's place among its
|
|
43
|
+
* `count` stops, the cell first and its controls after it, and `step` is the
|
|
44
|
+
* way the key points along the line.
|
|
45
|
+
*
|
|
46
|
+
* Past either end it comes back to the cell, so the keys never leave the row,
|
|
47
|
+
* and from the cell going back reaches the last control.
|
|
48
|
+
*/
|
|
49
|
+
export declare const rowStop: (count: number, at: number, step: -1 | 1) => number;
|