@fusion.dev/helix-headless 0.143.0 → 0.145.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 +16990 -1383
- package/dist/accordion/item/accordion-item.d.ts +48 -12
- package/dist/accordion/item/accordion-item.js +26 -5
- package/dist/accordion/root/accordion-root.d.ts +6 -0
- package/dist/accordion/root/accordion-root.js +7 -1
- package/dist/announcement/root/announcement-root.d.ts +21 -1
- package/dist/announcement/root/announcement-root.js +36 -1
- package/dist/app-header/root/app-header-root.d.ts +7 -0
- package/dist/app-header/root/app-header-root.js +5 -1
- package/dist/app-header/sectioning.d.ts +7 -0
- package/dist/app-header/sectioning.js +26 -0
- package/dist/area-chart/root/area-chart-root.d.ts +12 -4
- package/dist/area-chart/root/area-chart-root.js +24 -7
- package/dist/avatar/root/avatar-root.d.ts +14 -0
- package/dist/avatar/root/avatar-root.js +23 -9
- package/dist/badge/root/badge-root.d.ts +11 -7
- package/dist/badge/root/badge-root.js +1 -1
- package/dist/bar-chart/root/bar-chart-root.d.ts +12 -3
- package/dist/bar-chart/root/bar-chart-root.js +17 -10
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +32 -1
- package/dist/breadcrumbs/root/breadcrumbs-root.js +25 -2
- package/dist/button/root/button-root.d.ts +47 -1
- package/dist/button/root/button-root.js +38 -4
- package/dist/callout/root/callout-root.d.ts +18 -1
- package/dist/callout/root/callout-root.js +15 -4
- package/dist/canvas/root/canvas-root.d.ts +38 -3
- package/dist/canvas/root/canvas-root.js +121 -40
- 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 +90 -0
- package/dist/carousel/root/carousel-root.js +134 -12
- 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 +25 -9
- package/dist/chat/naming.d.ts +22 -0
- package/dist/chat/naming.js +12 -0
- package/dist/chat/relative-clock.d.ts +39 -0
- package/dist/chat/relative-clock.js +31 -0
- package/dist/chat/root/chat-root.d.ts +36 -0
- package/dist/chat/root/chat-root.js +24 -1
- package/dist/checkbox/root/checkbox-root.js +2 -0
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +53 -3
- package/dist/checkbox-group/root/checkbox-group-root.js +71 -22
- 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 +38 -1
- package/dist/code-block/root/code-block-root.js +28 -7
- package/dist/color-input/root/color-input-root.d.ts +34 -1
- package/dist/color-input/root/color-input-root.js +23 -4
- 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 +81 -5
- package/dist/color-picker/root/color-picker-root.js +103 -10
- package/dist/combobox/root/combobox-root.d.ts +38 -3
- package/dist/combobox/root/combobox-root.js +64 -2
- package/dist/command/root/command-root.d.ts +30 -4
- package/dist/command/root/command-root.js +33 -3
- 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 +47 -1
- package/dist/copy-button/root/copy-button-root.js +44 -8
- package/dist/data-table/root/data-table-root.d.ts +150 -2
- package/dist/data-table/root/data-table-root.js +303 -29
- package/dist/data-table/tree.d.ts +40 -0
- package/dist/data-table/tree.js +55 -0
- package/dist/date-input/root/date-input-root.d.ts +73 -4
- package/dist/date-input/root/date-input-root.js +93 -43
- package/dist/date-picker/root/date-picker-root.d.ts +145 -1
- package/dist/date-picker/root/date-picker-root.js +239 -48
- 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.d.ts +9 -0
- package/dist/dialog/description.js +14 -0
- package/dist/dialog/root/dialog-root.d.ts +64 -1
- package/dist/dialog/root/dialog-root.js +49 -23
- package/dist/donut-chart/root/donut-chart-root.d.ts +25 -4
- package/dist/donut-chart/root/donut-chart-root.js +21 -6
- package/dist/drawer/root/drawer-root.d.ts +63 -2
- package/dist/drawer/root/drawer-root.js +95 -19
- 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 +11 -6
- package/dist/drilldown/item/drilldown-item.js +8 -5
- package/dist/drilldown/root/drilldown-root.d.ts +11 -0
- package/dist/drilldown/root/drilldown-root.js +8 -3
- package/dist/element-events.generated.js +61 -13
- package/dist/empty/root/empty-root.d.ts +1 -1
- package/dist/file-input/root/file-input-root.d.ts +47 -0
- package/dist/file-input/root/file-input-root.js +60 -22
- 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 +3 -0
- package/dist/filter-input/menu/filter-menu.js +8 -4
- package/dist/filter-input/root/filter-input-root.d.ts +38 -4
- package/dist/filter-input/root/filter-input-root.js +67 -3
- 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 +51 -0
- package/dist/format-date/root/format-date-root.js +58 -38
- package/dist/heatmap/root/heatmap-root.d.ts +23 -6
- package/dist/heatmap/root/heatmap-root.js +24 -13
- 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 +30 -4
- package/dist/icon/root/icon-root.js +41 -6
- 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/image/root/image-root.d.ts +14 -0
- package/dist/image/root/image-root.js +23 -2
- package/dist/input/root/input-root.d.ts +11 -0
- package/dist/input/root/input-root.js +16 -1
- package/dist/kbd/root/kbd-root.d.ts +20 -13
- package/dist/kbd/root/kbd-root.js +35 -37
- 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 +56 -0
- package/dist/legend/root/legend-root.js +54 -5
- package/dist/lightbox/item/lightbox-item.d.ts +15 -0
- package/dist/lightbox/item/lightbox-item.js +10 -1
- package/dist/lightbox/root/lightbox-root.d.ts +61 -1
- package/dist/lightbox/root/lightbox-root.js +94 -4
- package/dist/line-chart/root/line-chart-root.d.ts +11 -3
- package/dist/line-chart/root/line-chart-root.js +19 -5
- package/dist/list/item/list-item.d.ts +68 -1
- package/dist/list/item/list-item.js +66 -4
- package/dist/list/numbering.d.ts +14 -0
- package/dist/list/numbering.js +8 -0
- package/dist/list/root/list-root.d.ts +106 -9
- package/dist/list/root/list-root.js +189 -4
- package/dist/list/selection.d.ts +19 -0
- package/dist/list/selection.js +21 -0
- package/dist/listbox/root/listbox-root.d.ts +74 -3
- package/dist/listbox/root/listbox-root.js +86 -9
- 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 +6 -2
- package/dist/map/root/map-root.js +5 -2
- package/dist/megamenu/root/megamenu-root.d.ts +21 -0
- package/dist/megamenu/root/megamenu-root.js +16 -2
- package/dist/menu/index.d.ts +1 -0
- package/dist/menu/index.js +1 -0
- package/dist/menu/item/menu-item.d.ts +38 -11
- package/dist/menu/item/menu-item.js +33 -1
- package/dist/menu/root/menu-root.d.ts +25 -1
- package/dist/menu/root/menu-root.js +63 -6
- 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 +7 -0
- package/dist/meter/root/meter-root.js +6 -3
- package/dist/navigation/root/navigation-root.d.ts +16 -1
- package/dist/navigation/root/navigation-root.js +27 -1
- package/dist/notifications/feed-keys.d.ts +10 -0
- package/dist/notifications/feed-keys.js +14 -0
- package/dist/notifications/notification/notification.d.ts +17 -0
- package/dist/notifications/notification/notification.js +21 -2
- package/dist/notifications/root/notifications-root.d.ts +60 -0
- package/dist/notifications/root/notifications-root.js +76 -1
- package/dist/number-input/root/number-input-root.d.ts +47 -0
- package/dist/number-input/root/number-input-root.js +58 -22
- package/dist/object-inspector/root/object-inspector-root.d.ts +98 -16
- package/dist/object-inspector/root/object-inspector-root.js +180 -80
- package/dist/object-inspector/rows.d.ts +57 -0
- package/dist/object-inspector/rows.js +86 -0
- package/dist/option/root/option-root.d.ts +54 -5
- package/dist/option/root/option-root.js +34 -5
- package/dist/outline/levels.d.ts +31 -0
- package/dist/outline/levels.js +23 -0
- package/dist/outline/root/outline-root.d.ts +68 -3
- package/dist/outline/root/outline-root.js +73 -8
- package/dist/pagination/size/pagination-size.d.ts +11 -2
- package/dist/pagination/size/pagination-size.js +19 -4
- 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 +21 -0
- package/dist/pin-input/root/pin-input-root.js +29 -2
- package/dist/popover/root/popover-root.d.ts +62 -4
- package/dist/popover/root/popover-root.js +53 -5
- package/dist/progress/root/progress-root.d.ts +7 -0
- package/dist/progress/root/progress-root.js +9 -3
- 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 +26 -0
- package/dist/qr-code/root/qr-code-root.js +49 -2
- package/dist/radio/group/radio-group.d.ts +17 -0
- package/dist/radio/group/radio-group.js +14 -1
- package/dist/rating/root/rating-root.d.ts +25 -0
- package/dist/rating/root/rating-root.js +46 -4
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
- package/dist/scatter-chart/root/scatter-chart-root.js +25 -7
- package/dist/scroll-area/root/scroll-area-root.d.ts +113 -0
- package/dist/scroll-area/root/scroll-area-root.js +218 -3
- package/dist/scroll-area/scrollbar.d.ts +65 -0
- package/dist/scroll-area/scrollbar.js +24 -0
- package/dist/select/root/select-root.d.ts +24 -0
- package/dist/select/root/select-root.js +21 -7
- package/dist/skeleton/root/skeleton-root.d.ts +25 -0
- package/dist/skeleton/root/skeleton-root.js +17 -2
- package/dist/slider/root/slider-root.d.ts +39 -0
- package/dist/slider/root/slider-root.js +45 -9
- package/dist/splitter/root/splitter-root.d.ts +13 -0
- package/dist/splitter/root/splitter-root.js +20 -2
- package/dist/splitter/snap.d.ts +9 -0
- package/dist/splitter/snap.js +12 -0
- package/dist/stat/root/stat-root.d.ts +2 -0
- package/dist/stat/root/stat-root.js +1 -1
- package/dist/steps/reach.d.ts +15 -0
- package/dist/steps/reach.js +12 -0
- package/dist/steps/root/steps-root.d.ts +30 -0
- package/dist/steps/root/steps-root.js +53 -0
- package/dist/steps/step/step.d.ts +39 -2
- package/dist/steps/step/step.js +29 -7
- package/dist/switch/root/switch-root.d.ts +12 -2
- package/dist/switch/root/switch-root.js +6 -1
- package/dist/table/column/table-column.d.ts +11 -0
- package/dist/table/column/table-column.js +6 -1
- package/dist/table/root/table-root.d.ts +101 -0
- package/dist/table/root/table-root.js +166 -5
- 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 +9 -5
- package/dist/tabs/panel/tab-panel.js +3 -4
- package/dist/tabs/root/tabs-root.d.ts +25 -1
- package/dist/tabs/root/tabs-root.js +21 -3
- package/dist/tabs/tab/tab.d.ts +36 -4
- package/dist/tabs/tab/tab.js +46 -3
- 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 +60 -0
- package/dist/tag/root/tag-root.js +74 -18
- 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 +9 -0
- package/dist/textarea/root/textarea-root.js +9 -1
- package/dist/time-input/root/time-input-root.d.ts +44 -5
- package/dist/time-input/root/time-input-root.js +69 -39
- package/dist/time-picker/root/time-picker-root.d.ts +54 -8
- package/dist/time-picker/root/time-picker-root.js +121 -91
- 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/hotkey.d.ts +22 -0
- package/dist/toast/hotkey.js +23 -0
- package/dist/toast/item/toast-item.d.ts +26 -18
- package/dist/toast/item/toast-item.js +55 -48
- package/dist/toast/root/toast-root.d.ts +42 -8
- package/dist/toast/root/toast-root.js +64 -4
- package/dist/toggle/group/toggle-group.d.ts +57 -15
- package/dist/toggle/group/toggle-group.js +69 -9
- package/dist/toggle/root/toggle-root.d.ts +12 -1
- package/dist/toggle/root/toggle-root.js +11 -3
- package/dist/toolbar/root/toolbar-root.d.ts +13 -0
- package/dist/toolbar/root/toolbar-root.js +15 -5
- 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 +42 -17
- package/dist/tooltip/root/tooltip-root.js +50 -9
- package/dist/tour/naming.d.ts +30 -0
- package/dist/tour/naming.js +10 -0
- package/dist/tour/root/tour-root.d.ts +35 -0
- package/dist/tour/root/tour-root.js +56 -5
- package/dist/tour/stop/tour-stop.d.ts +53 -8
- package/dist/tour/stop/tour-stop.js +45 -15
- package/dist/tour/wait.d.ts +11 -0
- package/dist/tour/wait.js +19 -0
- package/dist/tree/item/tree-item.d.ts +54 -1
- package/dist/tree/item/tree-item.js +89 -20
- package/dist/tree/root/tree-root.d.ts +37 -0
- package/dist/tree/root/tree-root.js +51 -6
- package/dist/tree/selection.d.ts +24 -0
- package/dist/tree/selection.js +26 -0
- package/dist/trend/root/trend-root.d.ts +13 -0
- package/dist/trend/root/trend-root.js +14 -9
- package/dist/video/media-events.d.ts +49 -0
- package/dist/video/media-events.js +39 -0
- package/dist/video/root/video-root.d.ts +99 -13
- package/dist/video/root/video-root.js +84 -47
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +3 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +2 -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 +70 -2
- 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 +30 -0
- package/dist/virtual-list/fill.js +39 -0
- package/dist/virtual-list/keys.d.ts +15 -0
- package/dist/virtual-list/keys.js +24 -0
- package/dist/virtual-list/root/virtual-list-root.d.ts +155 -23
- package/dist/virtual-list/root/virtual-list-root.js +175 -34
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +8871 -1286
- package/types/svelte.d.ts +3 -0
- package/types/vue.d.ts +1918 -269
|
@@ -8,6 +8,11 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
8
8
|
* still there when the person comes back, and the content of every panel is in
|
|
9
9
|
* the server-rendered markup for crawlers, whichever tab is open.
|
|
10
10
|
*
|
|
11
|
+
* The host is the `tabpanel` while its tab is selected, through
|
|
12
|
+
* `ElementInternals`, so the tab's `aria-controls` can reach it from the tab's
|
|
13
|
+
* shadow root. The box inside takes the focus, for a panel with nothing
|
|
14
|
+
* focusable in it.
|
|
15
|
+
*
|
|
11
16
|
* @since 0.1.0
|
|
12
17
|
* @status stable
|
|
13
18
|
* @aliases TabPanel
|
|
@@ -15,7 +20,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
15
20
|
*
|
|
16
21
|
* @slot - The panel's content.
|
|
17
22
|
*
|
|
18
|
-
* @csspart panel - The panel container.
|
|
23
|
+
* @csspart panel - The panel container, which takes the focus.
|
|
19
24
|
*
|
|
20
25
|
* @cssstate selected - While its tab is the one selected.
|
|
21
26
|
*/
|
|
@@ -28,10 +33,9 @@ export declare class HelixHeadlessTabPanel extends HelixElement {
|
|
|
28
33
|
* writes: the tab already says it.
|
|
29
34
|
*
|
|
30
35
|
* A string and not a reference: an IDREF resolves only in the tree it is
|
|
31
|
-
* written in, and
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* anyway.
|
|
36
|
+
* written in, and the tab's control is inside the tab's shadow root, which no
|
|
37
|
+
* reference from the light DOM can reach. `aria-label` on a `tabpanel` is how
|
|
38
|
+
* the pattern names one anyway.
|
|
35
39
|
*/
|
|
36
40
|
label: string;
|
|
37
41
|
/**
|
|
@@ -4,8 +4,8 @@ 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 } from '@fusion.dev/helix-core';
|
|
8
|
-
import { html
|
|
7
|
+
import { customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
|
|
8
|
+
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
let HelixHeadlessTabPanel = class HelixHeadlessTabPanel extends HelixElement {
|
|
11
11
|
constructor() {
|
|
@@ -17,12 +17,11 @@ let HelixHeadlessTabPanel = class HelixHeadlessTabPanel extends HelixElement {
|
|
|
17
17
|
willUpdate(changed) {
|
|
18
18
|
super.willUpdate(changed);
|
|
19
19
|
this.toggleState('selected', this.selected);
|
|
20
|
+
hostAria(this.internals, { label: this.label, role: this.selected ? 'tabpanel' : '' });
|
|
20
21
|
}
|
|
21
22
|
render() {
|
|
22
23
|
return html `<div
|
|
23
24
|
part="panel"
|
|
24
|
-
role="tabpanel"
|
|
25
|
-
aria-label=${this.label || nothing}
|
|
26
25
|
?hidden=${!this.selected}
|
|
27
26
|
tabindex="0"
|
|
28
27
|
>
|
|
@@ -16,6 +16,18 @@ declare const HelixHeadlessTabs_base: (new (...args: any[]) => import("@fusion.d
|
|
|
16
16
|
* panel is cheap. Set `manual` when showing a panel is expensive, so focus can
|
|
17
17
|
* move without selecting.
|
|
18
18
|
*
|
|
19
|
+
* `orientation="vertical"` sets the tabs in a column beside the panels, and the
|
|
20
|
+
* tab list says `aria-orientation="vertical"`. The arrow keys of both axes move
|
|
21
|
+
* between tabs either way.
|
|
22
|
+
*
|
|
23
|
+
* A tab with an `href` is a link, for tabs that are pages of a site. Pressing
|
|
24
|
+
* it follows the link, and the arrow keys move focus without choosing, so
|
|
25
|
+
* arrowing past a tab never leaves the page. Mark the tab of the page you are
|
|
26
|
+
* on with `selected`, or set `active` to its value.
|
|
27
|
+
*
|
|
28
|
+
* Each tab says which panel it controls through `aria-controls`, set as an
|
|
29
|
+
* element reference to the panel's host, where the engine has reflection.
|
|
30
|
+
*
|
|
19
31
|
* @since 0.1.0
|
|
20
32
|
* @status stable
|
|
21
33
|
* @category navigation
|
|
@@ -29,7 +41,10 @@ declare const HelixHeadlessTabs_base: (new (...args: any[]) => import("@fusion.d
|
|
|
29
41
|
* @event {HelixBeforeActivateEvent} helix-before-activate - Fired before the active tab changes, and cancelable. Canceling it is the only way to block a change.
|
|
30
42
|
* @event {HelixSelectEvent} helix-select - Fired when a tab is chosen. The tab sends it and the root handles it, so you can listen on the root. Cancelable: canceling it stops the change and leaves the decision to you.
|
|
31
43
|
*
|
|
32
|
-
* @csspart indicator - The marker that moves to the selected tab.
|
|
44
|
+
* @csspart indicator - The marker that moves to the selected tab. It carries the selected tab's
|
|
45
|
+
* place and size as `--indicator-x`, `--indicator-y`, `--indicator-inline-size` and
|
|
46
|
+
* `--indicator-block-size`, and `data-placed` once it has been placed, for a mark you draw
|
|
47
|
+
* and animate yourself.
|
|
33
48
|
* @csspart panels - The panel container.
|
|
34
49
|
* @csspart tabs - The tab list.
|
|
35
50
|
*/
|
|
@@ -54,6 +69,13 @@ export declare class HelixHeadlessTabs extends HelixHeadlessTabs_base {
|
|
|
54
69
|
* panels on the way.
|
|
55
70
|
*/
|
|
56
71
|
manual: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* The direction the tabs run. `vertical` sets them in a column beside the
|
|
74
|
+
* panels and tells a screen reader the list is vertical.
|
|
75
|
+
*
|
|
76
|
+
* Optional, so the resting row writes no attribute onto the host.
|
|
77
|
+
*/
|
|
78
|
+
orientation?: 'horizontal' | 'vertical';
|
|
57
79
|
/**
|
|
58
80
|
* How the row of tabs is drawn.
|
|
59
81
|
*
|
|
@@ -80,6 +102,8 @@ export declare class HelixHeadlessTabs extends HelixHeadlessTabs_base {
|
|
|
80
102
|
*/
|
|
81
103
|
variant?: 'segmented' | 'underlined';
|
|
82
104
|
private get tabs();
|
|
105
|
+
/** Whether any tab is a link, so arriving on one chooses nothing. */
|
|
106
|
+
private get linked();
|
|
83
107
|
private get panels();
|
|
84
108
|
private readonly handleSelection;
|
|
85
109
|
/** Pushes the current value down to whichever tab and panel own it. */
|
|
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { AriaForwardController, customElement, HelixElement, IndicatorController, KeyboardNavigationController, MixinControllerActive, whenHydrated, } from '@fusion.dev/helix-core';
|
|
8
|
-
import { html } from 'lit';
|
|
8
|
+
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { HelixHeadlessTabPanel } from '../panel/tab-panel.js';
|
|
11
11
|
import { HelixHeadlessTab } from '../tab/tab.js';
|
|
@@ -15,7 +15,7 @@ let HelixHeadlessTabs = class HelixHeadlessTabs extends MixinControllerActive(He
|
|
|
15
15
|
this.keys = new KeyboardNavigationController(this, {
|
|
16
16
|
items: () => this.tabs,
|
|
17
17
|
origin: 'focus',
|
|
18
|
-
selects: () => !this.manual,
|
|
18
|
+
selects: () => !this.manual && !this.linked,
|
|
19
19
|
});
|
|
20
20
|
this.indicator = new IndicatorController(this, {
|
|
21
21
|
active: () => this.tabs.find((tab) => tab.selected),
|
|
@@ -43,6 +43,9 @@ let HelixHeadlessTabs = class HelixHeadlessTabs extends MixinControllerActive(He
|
|
|
43
43
|
get tabs() {
|
|
44
44
|
return [...this.children].filter((child) => child instanceof HelixHeadlessTab);
|
|
45
45
|
}
|
|
46
|
+
get linked() {
|
|
47
|
+
return this.tabs.some((tab) => (tab.href ?? '') !== '');
|
|
48
|
+
}
|
|
46
49
|
get panels() {
|
|
47
50
|
return [...this.children].filter((child) => child instanceof HelixHeadlessTabPanel);
|
|
48
51
|
}
|
|
@@ -57,6 +60,13 @@ let HelixHeadlessTabs = class HelixHeadlessTabs extends MixinControllerActive(He
|
|
|
57
60
|
});
|
|
58
61
|
}
|
|
59
62
|
const names = new Map(tabs.map((tab) => [tab.value, (tab.textContent ?? '').trim()]));
|
|
63
|
+
const panels = new Map(this.panels.map((panel) => [panel.value, panel]));
|
|
64
|
+
for (const tab of tabs) {
|
|
65
|
+
const panel = panels.get(tab.value);
|
|
66
|
+
whenHydrated(tab, () => {
|
|
67
|
+
tab.controls = panel;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
60
70
|
for (const panel of this.panels) {
|
|
61
71
|
const selected = panel.value === value;
|
|
62
72
|
const label = names.get(panel.value) ?? '';
|
|
@@ -88,7 +98,12 @@ let HelixHeadlessTabs = class HelixHeadlessTabs extends MixinControllerActive(He
|
|
|
88
98
|
this.indicator.place();
|
|
89
99
|
}
|
|
90
100
|
render() {
|
|
91
|
-
return html `<div
|
|
101
|
+
return html `<div
|
|
102
|
+
part="tabs"
|
|
103
|
+
role="tablist"
|
|
104
|
+
aria-label=${this.label}
|
|
105
|
+
aria-orientation=${this.orientation === 'vertical' ? 'vertical' : nothing}
|
|
106
|
+
>
|
|
92
107
|
<slot @slotchange=${this.handleSlotChange}></slot>
|
|
93
108
|
<span part="indicator" aria-hidden="true"></span>
|
|
94
109
|
</div>
|
|
@@ -101,6 +116,9 @@ __decorate([
|
|
|
101
116
|
__decorate([
|
|
102
117
|
property({ reflect: true, type: Boolean })
|
|
103
118
|
], HelixHeadlessTabs.prototype, "manual", void 0);
|
|
119
|
+
__decorate([
|
|
120
|
+
property({ reflect: true })
|
|
121
|
+
], HelixHeadlessTabs.prototype, "orientation", void 0);
|
|
104
122
|
__decorate([
|
|
105
123
|
property({ reflect: true })
|
|
106
124
|
], HelixHeadlessTabs.prototype, "variant", void 0);
|
package/dist/tabs/tab/tab.d.ts
CHANGED
|
@@ -7,10 +7,10 @@ declare const HelixHeadlessTab_base: (new (...args: any[]) => import("@fusion.de
|
|
|
7
7
|
* @description
|
|
8
8
|
* A tab is an element, because it manages selection and its own tab stop.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* With an `href`, the tab is a link: `role="tab"` on an `<a>`, which a press,
|
|
11
|
+
* Enter and the browser's own link gestures follow. `helix-select` is sent
|
|
12
|
+
* first, and canceling it keeps the browser from following, so a client-side
|
|
13
|
+
* router follows it instead.
|
|
14
14
|
*
|
|
15
15
|
* @since 0.1.0
|
|
16
16
|
* @status stable
|
|
@@ -27,6 +27,38 @@ declare const HelixHeadlessTab_base: (new (...args: any[]) => import("@fusion.de
|
|
|
27
27
|
*/
|
|
28
28
|
export declare class HelixHeadlessTab extends HelixHeadlessTab_base {
|
|
29
29
|
protected itemPart: string;
|
|
30
|
+
/**
|
|
31
|
+
* @internal The panel this tab shows, written by the tab set. A property,
|
|
32
|
+
* because it is an element, and it reaches the tab's `aria-controls` as an
|
|
33
|
+
* element reference: the panel is in the light DOM, which a reference from
|
|
34
|
+
* inside this shadow root can reach.
|
|
35
|
+
*/
|
|
36
|
+
controls: Element | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* The URL the tab links to. Setting it renders the tab as a link, for a set
|
|
39
|
+
* of tabs that are pages of a site.
|
|
40
|
+
*/
|
|
41
|
+
href?: string;
|
|
42
|
+
/**
|
|
43
|
+
* The link's `rel`, for a tab with an `href`.
|
|
44
|
+
*/
|
|
45
|
+
rel?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Where the link opens, such as `_blank`, for a tab with an `href`.
|
|
48
|
+
*/
|
|
49
|
+
target?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Chooses the tab before the browser follows its link, and keeps the browser
|
|
52
|
+
* from following where the choice was refused. A press with a modifier, or
|
|
53
|
+
* with a button other than the main one, opens the link where the browser
|
|
54
|
+
* opens it and chooses nothing here.
|
|
55
|
+
*/
|
|
56
|
+
private readonly handleLinkClick;
|
|
57
|
+
/**
|
|
58
|
+
* Points the control's `aria-controls` at the panel, where the engine can.
|
|
59
|
+
* The control is this tab's own, so the reference is always its to clear.
|
|
60
|
+
*/
|
|
61
|
+
protected updated(changed: PropertyValues): void;
|
|
30
62
|
/**
|
|
31
63
|
* Asks for the render that follows a hydration, so the stop stops being every
|
|
32
64
|
* tab's.
|
package/dist/tabs/tab/tab.js
CHANGED
|
@@ -4,31 +4,74 @@ 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, MixinSelectableItem } from '@fusion.dev/helix-core';
|
|
8
|
-
import { html } from 'lit';
|
|
7
|
+
import { customElement, HelixElement, MixinSelectableItem, reflectElements, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { html, nothing } from 'lit';
|
|
9
|
+
import { property } from 'lit/decorators.js';
|
|
9
10
|
let HelixHeadlessTab = class HelixHeadlessTab extends MixinSelectableItem(HelixElement) {
|
|
10
11
|
constructor() {
|
|
11
12
|
super(...arguments);
|
|
12
13
|
this.itemPart = 'tab';
|
|
14
|
+
this.controls = undefined;
|
|
15
|
+
this.handleLinkClick = (event) => {
|
|
16
|
+
if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (!this.select()) {
|
|
20
|
+
event.preventDefault();
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
updated(changed) {
|
|
25
|
+
super.updated(changed);
|
|
26
|
+
const control = this.renderRoot.querySelector('[part="tab"]');
|
|
27
|
+
reflectElements(control, 'ariaControlsElements', this.controls ? [this.controls] : [], true);
|
|
13
28
|
}
|
|
14
29
|
firstUpdated(changed) {
|
|
15
30
|
super.firstUpdated(changed);
|
|
16
31
|
this.finishHydration();
|
|
17
32
|
}
|
|
18
33
|
render() {
|
|
34
|
+
const tabindex = this.selected || !this.childrenKnown ? '0' : '-1';
|
|
35
|
+
if ((this.href ?? '') !== '') {
|
|
36
|
+
return html `<a
|
|
37
|
+
part="tab"
|
|
38
|
+
role="tab"
|
|
39
|
+
href=${this.disabled ? nothing : (this.href ?? nothing)}
|
|
40
|
+
target=${this.target || nothing}
|
|
41
|
+
rel=${this.rel || nothing}
|
|
42
|
+
aria-selected=${this.selected ? 'true' : 'false'}
|
|
43
|
+
aria-disabled=${this.disabled ? 'true' : nothing}
|
|
44
|
+
tabindex=${this.disabled ? nothing : tabindex}
|
|
45
|
+
@click=${this.handleLinkClick}
|
|
46
|
+
>
|
|
47
|
+
<slot></slot>
|
|
48
|
+
</a>`;
|
|
49
|
+
}
|
|
19
50
|
return html `<button
|
|
20
51
|
part="tab"
|
|
21
52
|
role="tab"
|
|
22
53
|
type="button"
|
|
23
54
|
aria-selected=${this.selected ? 'true' : 'false'}
|
|
24
55
|
?disabled=${this.disabled}
|
|
25
|
-
tabindex=${
|
|
56
|
+
tabindex=${tabindex}
|
|
26
57
|
@click=${() => this.select()}
|
|
27
58
|
>
|
|
28
59
|
<slot></slot>
|
|
29
60
|
</button>`;
|
|
30
61
|
}
|
|
31
62
|
};
|
|
63
|
+
__decorate([
|
|
64
|
+
property({ attribute: false })
|
|
65
|
+
], HelixHeadlessTab.prototype, "controls", void 0);
|
|
66
|
+
__decorate([
|
|
67
|
+
property()
|
|
68
|
+
], HelixHeadlessTab.prototype, "href", void 0);
|
|
69
|
+
__decorate([
|
|
70
|
+
property()
|
|
71
|
+
], HelixHeadlessTab.prototype, "rel", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
property()
|
|
74
|
+
], HelixHeadlessTab.prototype, "target", void 0);
|
|
32
75
|
HelixHeadlessTab = __decorate([
|
|
33
76
|
customElement('helix-headless-tab')
|
|
34
77
|
], HelixHeadlessTab);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { HelixElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
|
|
2
|
+
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
+
import { HelixHeadlessTag } from '../root/tag-root.js';
|
|
4
|
+
import { type TagSelectionMode } from '../selection.js';
|
|
5
|
+
/**
|
|
6
|
+
* @summary A set of tags that the arrow keys move through, and that can be removed and selected from the keyboard.
|
|
7
|
+
*
|
|
8
|
+
* @description
|
|
9
|
+
* A part of `Tag` that holds tags as one control: a grid of rows, one tab stop
|
|
10
|
+
* for the whole set. The arrow keys move between tags, Home and End go to the
|
|
11
|
+
* first and the last, and a typed letter goes to the next tag starting with
|
|
12
|
+
* it. Delete or Backspace removes the focused tag where it is `dismissible`,
|
|
13
|
+
* by sending its `helix-dismiss`: remove it from your list in the handler, and
|
|
14
|
+
* focus moves to the next tag, or the previous one after the last.
|
|
15
|
+
*
|
|
16
|
+
* `selection-mode` lets a reader select tags, with Space, Enter or a press:
|
|
17
|
+
* `single` selects one at a time and `multiple` any number. `value` holds the
|
|
18
|
+
* selected tags' values, separated by commas, and a change asks with
|
|
19
|
+
* `helix-before-change` and tells with `change`. Enter on a tag with an
|
|
20
|
+
* `href` follows its link. A `disabled` tag is passed over.
|
|
21
|
+
*
|
|
22
|
+
* Name the set with `label`.
|
|
23
|
+
*
|
|
24
|
+
* @since 0.1.0
|
|
25
|
+
* @status stable
|
|
26
|
+
* @aliases Tag list, Chip group, Token list
|
|
27
|
+
* @documentation https://fusion.dev/helix/components/tag
|
|
28
|
+
*
|
|
29
|
+
* @slot - The tags, in the order they are read.
|
|
30
|
+
*
|
|
31
|
+
* @event {Event} change - Fired once a press has changed which tags are selected.
|
|
32
|
+
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before a press changes which tags are selected, with the `value` it would leave. Cancelable.
|
|
33
|
+
* @event {HelixDismissEvent} helix-dismiss - A tag's remove button was pressed, or Delete or Backspace on the focused tag. Bubbles from that tag, which is its `target`; remove the tag in response. Cancelable.
|
|
34
|
+
*/
|
|
35
|
+
export declare class HelixHeadlessTagGroup extends HelixElement {
|
|
36
|
+
/**
|
|
37
|
+
* The name of the set, such as "Filters", which a screen reader announces
|
|
38
|
+
* before its tags.
|
|
39
|
+
*/
|
|
40
|
+
label: string;
|
|
41
|
+
/**
|
|
42
|
+
* How many tags a reader can select: `single`, `multiple`, or none.
|
|
43
|
+
*
|
|
44
|
+
* Absent selects nothing, and the tags carry no selected state at all.
|
|
45
|
+
*/
|
|
46
|
+
selectionMode?: TagSelectionMode;
|
|
47
|
+
/**
|
|
48
|
+
* The selected tags' values, separated by commas, since a value may hold a
|
|
49
|
+
* space.
|
|
50
|
+
*
|
|
51
|
+
* Set it to start with tags selected. A tag's value is its `value`, or its
|
|
52
|
+
* words where it has none.
|
|
53
|
+
*/
|
|
54
|
+
value: string;
|
|
55
|
+
/** The tag the reader was last on, which keeps the tab stop. */
|
|
56
|
+
private last;
|
|
57
|
+
/**
|
|
58
|
+
* The arrow keys, Home, End and typed letters, moving focus and choosing
|
|
59
|
+
* nothing. From the focused tag rather than the selection, since a reader
|
|
60
|
+
* moves through selected and unselected tags alike, and without wrapping, as
|
|
61
|
+
* a list of tags has a first and a last.
|
|
62
|
+
*/
|
|
63
|
+
protected readonly keys: KeyboardNavigationController;
|
|
64
|
+
/** The tags the group holds, in order. */
|
|
65
|
+
get tags(): HelixHeadlessTag[];
|
|
66
|
+
/** The tags a key can land on, which are the ones that are not disabled. */
|
|
67
|
+
private get reachable();
|
|
68
|
+
/** A tag as the keyboard controller sees it: an item it moves focus to and never chooses. */
|
|
69
|
+
private navigable;
|
|
70
|
+
/**
|
|
71
|
+
* What a tag stands for in `value`: its own `value`, or its words.
|
|
72
|
+
*
|
|
73
|
+
* The words read off the tag's children here rather than through its
|
|
74
|
+
* `words`, which answers nothing until the tag's own first update: the
|
|
75
|
+
* group's first pass runs before that, and would match no tag.
|
|
76
|
+
*/
|
|
77
|
+
private valueFor;
|
|
78
|
+
/**
|
|
79
|
+
* Tells every tag its place: whether it holds the one tab stop and whether
|
|
80
|
+
* it is selected. Through `whenHydrated`, so a tag a server rendered draws
|
|
81
|
+
* its served markup first.
|
|
82
|
+
*/
|
|
83
|
+
private sync;
|
|
84
|
+
/** The tag a press or a key came from, read off the event's path. */
|
|
85
|
+
private tagOf;
|
|
86
|
+
/**
|
|
87
|
+
* Selects the tag, or lets it go, asking first.
|
|
88
|
+
*
|
|
89
|
+
* `helix-before-change` carries the `value` the press would leave, and a
|
|
90
|
+
* listener that refuses it keeps the selection. `change` follows once it
|
|
91
|
+
* has moved.
|
|
92
|
+
*/
|
|
93
|
+
protected press(tag: HelixHeadlessTag): void;
|
|
94
|
+
private readonly handleKeydown;
|
|
95
|
+
private readonly handleClick;
|
|
96
|
+
private readonly handleFocusin;
|
|
97
|
+
connectedCallback(): void;
|
|
98
|
+
disconnectedCallback(): void;
|
|
99
|
+
protected willUpdate(changed: PropertyValues<this>): void;
|
|
100
|
+
protected updated(changed: PropertyValues<this>): void;
|
|
101
|
+
protected render(): TemplateResult;
|
|
102
|
+
}
|
|
103
|
+
declare global {
|
|
104
|
+
interface HTMLElementTagNameMap {
|
|
105
|
+
'helix-headless-tag-group': HelixHeadlessTagGroup;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
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
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { commaList, customElement, HelixBeforeChangeEvent, HelixElement, hostAria, KeyboardNavigationController, requestChange, rovingStop, slottedWords, whenHydrated, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { html } from 'lit';
|
|
9
|
+
import { property } from 'lit/decorators.js';
|
|
10
|
+
import { HelixHeadlessTag } from '../root/tag-root.js';
|
|
11
|
+
import { pressedValue } from '../selection.js';
|
|
12
|
+
let HelixHeadlessTagGroup = class HelixHeadlessTagGroup extends HelixElement {
|
|
13
|
+
constructor() {
|
|
14
|
+
super(...arguments);
|
|
15
|
+
this.label = '';
|
|
16
|
+
this.value = '';
|
|
17
|
+
this.keys = new KeyboardNavigationController(this, {
|
|
18
|
+
items: () => this.reachable.map((tag) => this.navigable(tag)),
|
|
19
|
+
origin: 'focus',
|
|
20
|
+
selects: () => false,
|
|
21
|
+
typeahead: (item) => item.words,
|
|
22
|
+
wrap: false,
|
|
23
|
+
});
|
|
24
|
+
this.handleKeydown = (event) => {
|
|
25
|
+
const tag = this.tagOf(event);
|
|
26
|
+
if (!tag || tag.disabled || event.altKey || event.ctrlKey || event.metaKey) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (event.key === 'Delete' || event.key === 'Backspace') {
|
|
30
|
+
if (tag.dismissible) {
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
tag.dismiss();
|
|
33
|
+
}
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (event.key === 'Enter' && tag.href !== '') {
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
tag.renderRoot.querySelector('[part~="link"]')?.click();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if ((event.key === ' ' || event.key === 'Enter') && this.selectionMode) {
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
this.press(tag);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
this.handleClick = (event) => {
|
|
47
|
+
const tag = this.tagOf(event);
|
|
48
|
+
const control = event
|
|
49
|
+
.composedPath()
|
|
50
|
+
.some((node) => node instanceof Element &&
|
|
51
|
+
/(^| )(dismiss|link)( |$)/.test(node.getAttribute('part') ?? ''));
|
|
52
|
+
if (tag && !control) {
|
|
53
|
+
this.press(tag);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
this.handleFocusin = (event) => {
|
|
57
|
+
const tag = this.tagOf(event);
|
|
58
|
+
if (tag && tag !== this.last) {
|
|
59
|
+
this.last = tag;
|
|
60
|
+
this.sync();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
get tags() {
|
|
65
|
+
return [...(this.children ?? [])].filter((child) => child instanceof HelixHeadlessTag);
|
|
66
|
+
}
|
|
67
|
+
get reachable() {
|
|
68
|
+
return this.tags.filter((tag) => !tag.disabled);
|
|
69
|
+
}
|
|
70
|
+
navigable(tag) {
|
|
71
|
+
return {
|
|
72
|
+
contains: (node) => tag.contains(node),
|
|
73
|
+
disabled: tag.disabled,
|
|
74
|
+
focusItem: () => tag.focusItem(),
|
|
75
|
+
select: () => { },
|
|
76
|
+
selected: false,
|
|
77
|
+
words: tag.words,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
valueFor(tag) {
|
|
81
|
+
return tag.value || slottedWords(tag, ['start', '']);
|
|
82
|
+
}
|
|
83
|
+
sync() {
|
|
84
|
+
const mode = this.selectionMode ?? 'none';
|
|
85
|
+
const chosen = new Set(commaList(this.value));
|
|
86
|
+
const tags = this.tags;
|
|
87
|
+
const items = tags.map((tag) => ({
|
|
88
|
+
disabled: tag.disabled,
|
|
89
|
+
selected: chosen.has(this.valueFor(tag)),
|
|
90
|
+
tag,
|
|
91
|
+
}));
|
|
92
|
+
const holder = rovingStop(items, items.find((item) => item.tag === this.last), { disabled: (item) => item.disabled, selected: (item) => item.selected })?.tag;
|
|
93
|
+
for (const tag of tags) {
|
|
94
|
+
whenHydrated(tag, () => {
|
|
95
|
+
tag.focusable = tag === holder;
|
|
96
|
+
tag.selected = mode === 'none' ? undefined : chosen.has(this.valueFor(tag));
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
tagOf(event) {
|
|
101
|
+
return event
|
|
102
|
+
.composedPath()
|
|
103
|
+
.find((node) => node instanceof HelixHeadlessTag);
|
|
104
|
+
}
|
|
105
|
+
press(tag) {
|
|
106
|
+
const mode = this.selectionMode ?? 'none';
|
|
107
|
+
if (mode === 'none' || tag.disabled) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
requestChange({
|
|
111
|
+
apply: (value) => {
|
|
112
|
+
this.value = value;
|
|
113
|
+
this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
|
114
|
+
},
|
|
115
|
+
event: (value) => new HelixBeforeChangeEvent({ value }),
|
|
116
|
+
host: this,
|
|
117
|
+
next: pressedValue(mode, this.value, this.valueFor(tag)),
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
connectedCallback() {
|
|
121
|
+
super.connectedCallback();
|
|
122
|
+
this.addEventListener('keydown', this.handleKeydown);
|
|
123
|
+
this.addEventListener('click', this.handleClick);
|
|
124
|
+
this.addEventListener('focusin', this.handleFocusin);
|
|
125
|
+
}
|
|
126
|
+
disconnectedCallback() {
|
|
127
|
+
super.disconnectedCallback();
|
|
128
|
+
this.removeEventListener('keydown', this.handleKeydown);
|
|
129
|
+
this.removeEventListener('click', this.handleClick);
|
|
130
|
+
this.removeEventListener('focusin', this.handleFocusin);
|
|
131
|
+
}
|
|
132
|
+
willUpdate(changed) {
|
|
133
|
+
super.willUpdate(changed);
|
|
134
|
+
hostAria(this.internals, { label: this.label, role: 'grid' });
|
|
135
|
+
this.internals.ariaMultiSelectable = this.selectionMode === 'multiple' ? 'true' : null;
|
|
136
|
+
}
|
|
137
|
+
updated(changed) {
|
|
138
|
+
super.updated(changed);
|
|
139
|
+
this.sync();
|
|
140
|
+
}
|
|
141
|
+
render() {
|
|
142
|
+
return html `<slot @slotchange=${() => this.sync()}></slot>`;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
__decorate([
|
|
146
|
+
property()
|
|
147
|
+
], HelixHeadlessTagGroup.prototype, "label", void 0);
|
|
148
|
+
__decorate([
|
|
149
|
+
property({ attribute: 'selection-mode' })
|
|
150
|
+
], HelixHeadlessTagGroup.prototype, "selectionMode", void 0);
|
|
151
|
+
__decorate([
|
|
152
|
+
property()
|
|
153
|
+
], HelixHeadlessTagGroup.prototype, "value", void 0);
|
|
154
|
+
HelixHeadlessTagGroup = __decorate([
|
|
155
|
+
customElement('helix-headless-tag-group')
|
|
156
|
+
], HelixHeadlessTagGroup);
|
|
157
|
+
export { HelixHeadlessTagGroup };
|
package/dist/tag/index.d.ts
CHANGED
package/dist/tag/index.js
CHANGED
|
@@ -20,6 +20,14 @@ declare const HelixHeadlessTag_base: (new (...args: any[]) => import("@fusion.de
|
|
|
20
20
|
* to put the tag's words somewhere else, such as `dismiss-label="{label}
|
|
21
21
|
* entfernen"`.
|
|
22
22
|
*
|
|
23
|
+
* `href` makes the label a link, and `disabled` takes the tag out of reach: its
|
|
24
|
+
* link and its remove button stop answering.
|
|
25
|
+
*
|
|
26
|
+
* **In a `Tag.Group` a tag is a row of a grid.** The group gives it its role,
|
|
27
|
+
* its place in the one tab stop and, where the group selects, whether it is
|
|
28
|
+
* selected. Its remove button leaves the tab order there, Delete and Backspace
|
|
29
|
+
* doing its job from the row.
|
|
30
|
+
*
|
|
23
31
|
* @since 0.1.0
|
|
24
32
|
* @status stable
|
|
25
33
|
* @category markers
|
|
@@ -27,17 +35,65 @@ declare const HelixHeadlessTag_base: (new (...args: any[]) => import("@fusion.de
|
|
|
27
35
|
* @documentation https://fusion.dev/helix/components/tag
|
|
28
36
|
*
|
|
29
37
|
* @slot - The tag's label.
|
|
38
|
+
* @slot dismiss-icon - Replaces the glyph on the remove button.
|
|
30
39
|
* @slot start - The category the label belongs to, shown before it in a heavier weight.
|
|
31
40
|
*
|
|
32
41
|
* @event {HelixDismissEvent} helix-dismiss - The remove button was pressed. The tag does not remove itself, so remove it in response. Cancelable.
|
|
33
42
|
*
|
|
43
|
+
* @csspart cell - The grid cell around everything the tag shows, rendered only in a `Tag.Group`, where it takes focus.
|
|
34
44
|
* @csspart dismiss - The button that removes the tag.
|
|
35
45
|
* @csspart dismiss-mark - The icon on the remove button.
|
|
36
46
|
* @csspart label - The label, which the styled tag trims to its capitals and baseline so the letters sit at the middle in any font.
|
|
47
|
+
* @csspart link - The link around the label, under `href`.
|
|
37
48
|
* @csspart start - The category before the label.
|
|
49
|
+
*
|
|
50
|
+
* @cssstate selected - The tag is selected in a `Tag.Group` that selects.
|
|
38
51
|
*/
|
|
39
52
|
export declare class HelixHeadlessTag extends HelixHeadlessTag_base {
|
|
40
53
|
dismissLabel: string;
|
|
54
|
+
/**
|
|
55
|
+
* Takes the tag out of reach: its link and its remove button stop
|
|
56
|
+
* answering, and in a `Tag.Group` the arrow keys pass over it and it cannot
|
|
57
|
+
* be selected or removed.
|
|
58
|
+
*/
|
|
59
|
+
disabled: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Whether the tag holds its group's tab stop.
|
|
62
|
+
*
|
|
63
|
+
* Written by `Tag.Group` on every tag it holds, and unset outside one, which
|
|
64
|
+
* is how a tag knows it is a row. No attribute: it is coordination between
|
|
65
|
+
* elements, the same shape `Toggle.focusable` has.
|
|
66
|
+
*/
|
|
67
|
+
focusable?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Makes the label a link to this address.
|
|
70
|
+
*/
|
|
71
|
+
href: string;
|
|
72
|
+
/**
|
|
73
|
+
* Whether the tag is selected, in a `Tag.Group` that selects.
|
|
74
|
+
*
|
|
75
|
+
* Written by the group from its own `value`, and unset where nothing can be
|
|
76
|
+
* selected, which is what keeps `aria-selected` off a set that does not
|
|
77
|
+
* select.
|
|
78
|
+
*/
|
|
79
|
+
selected?: boolean | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* What the tag stands for in its group's `value`.
|
|
82
|
+
*
|
|
83
|
+
* Absent is the tag's own words, its category first.
|
|
84
|
+
*/
|
|
85
|
+
value: string;
|
|
86
|
+
/** The tag's words, its category first, or none where the children are not known yet. */
|
|
87
|
+
get words(): string;
|
|
88
|
+
/** Whether a `Tag.Group` holds this tag, which makes it a row. */
|
|
89
|
+
private get grouped();
|
|
90
|
+
/**
|
|
91
|
+
* Moves focus to the tag: its cell in a group, and otherwise its link or
|
|
92
|
+
* its remove button, whichever it has.
|
|
93
|
+
*/
|
|
94
|
+
focusItem(): void;
|
|
95
|
+
protected get returnFocusTo(): HTMLElement | null;
|
|
96
|
+
protected willUpdate(changed: PropertyValues<this>): void;
|
|
41
97
|
/**
|
|
42
98
|
* The remove button's name: `dismissLabel` with the tag's own words.
|
|
43
99
|
*
|
|
@@ -54,6 +110,10 @@ export declare class HelixHeadlessTag extends HelixHeadlessTag_base {
|
|
|
54
110
|
private get removeName();
|
|
55
111
|
protected firstUpdated(changed: PropertyValues): void;
|
|
56
112
|
protected render(): TemplateResult;
|
|
113
|
+
/** The label, inside a link under `href`, behind a seam a tier can move. */
|
|
114
|
+
protected renderLabel(): TemplateResult;
|
|
115
|
+
/** The remove button, behind a seam a tier can move. */
|
|
116
|
+
protected renderDismiss(): TemplateResult;
|
|
57
117
|
}
|
|
58
118
|
declare global {
|
|
59
119
|
interface HTMLElementTagNameMap {
|