@fusion.dev/helix-headless 0.142.1 → 0.143.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 +16710 -707
- package/dist/accordion/item/accordion-item.d.ts +38 -2
- package/dist/accordion/item/accordion-item.js +38 -6
- package/dist/accordion/root/accordion-root.d.ts +23 -1
- package/dist/accordion/root/accordion-root.js +39 -3
- package/dist/announcement/root/announcement-root.d.ts +11 -7
- package/dist/announcement/root/announcement-root.js +1 -1
- package/dist/app-header/root/app-header-root.d.ts +21 -0
- package/dist/app-header/root/app-header-root.js +31 -5
- package/dist/area-chart/root/area-chart-root.js +16 -5
- package/dist/avatar/group/avatar-group.d.ts +24 -3
- package/dist/avatar/group/avatar-group.js +34 -2
- package/dist/avatar/root/avatar-root.d.ts +3 -1
- package/dist/avatar/root/avatar-root.js +8 -1
- package/dist/badge/root/badge-root.d.ts +8 -0
- package/dist/bar-chart/root/bar-chart-root.d.ts +19 -3
- package/dist/bar-chart/root/bar-chart-root.js +43 -13
- package/dist/blockquote/root/blockquote-root.d.ts +12 -7
- package/dist/blockquote/root/blockquote-root.js +6 -4
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +9 -3
- package/dist/breadcrumbs/root/breadcrumbs-root.js +9 -1
- package/dist/button/root/button-root.d.ts +37 -0
- package/dist/button/root/button-root.js +44 -0
- package/dist/callout/root/callout-root.d.ts +14 -5
- package/dist/callout/root/callout-root.js +11 -3
- package/dist/canvas/root/canvas-root.d.ts +1 -0
- package/dist/canvas/root/canvas-root.js +10 -1
- package/dist/carousel/root/carousel-root.d.ts +47 -5
- package/dist/carousel/root/carousel-root.js +53 -21
- package/dist/chat/composer/chat-composer.d.ts +13 -11
- package/dist/chat/composer/chat-composer.js +6 -12
- package/dist/chat/message/chat-message.js +8 -1
- package/dist/chat/root/chat-root.d.ts +1 -0
- package/dist/chat/root/chat-root.js +2 -1
- package/dist/checkbox/root/checkbox-root.d.ts +7 -0
- package/dist/checkbox/root/checkbox-root.js +7 -3
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +65 -32
- package/dist/checkbox-group/root/checkbox-group-root.js +85 -37
- package/dist/code/root/code-root.d.ts +1 -1
- package/dist/code-block/root/code-block-root.d.ts +19 -0
- package/dist/code-block/root/code-block-root.js +21 -1
- package/dist/color-input/root/color-input-root.d.ts +26 -1
- package/dist/color-input/root/color-input-root.js +32 -3
- package/dist/color-picker/root/color-picker-root.d.ts +37 -7
- package/dist/color-picker/root/color-picker-root.js +83 -6
- package/dist/combobox/root/combobox-root.d.ts +90 -2
- package/dist/combobox/root/combobox-root.js +160 -19
- package/dist/command/root/command-root.d.ts +17 -6
- package/dist/command/root/command-root.js +12 -1
- package/dist/copy-button/root/copy-button-root.d.ts +21 -6
- package/dist/copy-button/root/copy-button-root.js +11 -1
- package/dist/data-table/root/data-table-root.d.ts +164 -10
- package/dist/data-table/root/data-table-root.js +488 -57
- package/dist/date-input/root/date-input-root.d.ts +53 -8
- package/dist/date-input/root/date-input-root.js +70 -18
- package/dist/date-picker/root/date-picker-root.d.ts +84 -17
- package/dist/date-picker/root/date-picker-root.js +125 -20
- package/dist/dialog/root/dialog-root.d.ts +38 -10
- package/dist/dialog/root/dialog-root.js +55 -2
- package/dist/donut-chart/root/donut-chart-root.d.ts +39 -15
- package/dist/donut-chart/root/donut-chart-root.js +30 -10
- package/dist/drawer/root/drawer-root.d.ts +32 -7
- package/dist/drawer/root/drawer-root.js +50 -5
- package/dist/drilldown/item/drilldown-item.d.ts +16 -13
- package/dist/drilldown/item/drilldown-item.js +6 -2
- package/dist/drilldown/root/drilldown-root.d.ts +21 -5
- package/dist/drilldown/root/drilldown-root.js +26 -10
- package/dist/element-events.generated.js +35 -9
- package/dist/file-input/root/file-input-root.d.ts +18 -1
- package/dist/file-input/root/file-input-root.js +34 -8
- package/dist/filter-input/menu/filter-menu.d.ts +9 -0
- package/dist/filter-input/menu/filter-menu.js +8 -0
- package/dist/filter-input/root/filter-input-root.d.ts +5 -2
- package/dist/filter-input/root/filter-input-root.js +22 -7
- package/dist/format-date/root/format-date-root.d.ts +11 -3
- package/dist/format-date/root/format-date-root.js +26 -5
- package/dist/graph/root/graph-root.d.ts +24 -3
- package/dist/graph/root/graph-root.js +66 -12
- package/dist/heatmap/root/buckets.d.ts +2 -1
- package/dist/heatmap/root/buckets.js +5 -1
- package/dist/heatmap/root/heatmap-root.d.ts +27 -6
- package/dist/heatmap/root/heatmap-root.js +23 -6
- package/dist/icon/root/icon-root.d.ts +24 -3
- package/dist/icon/root/icon-root.js +34 -1
- package/dist/icon-button/root/icon-button-root.d.ts +1 -1
- package/dist/image/root/image-root.d.ts +9 -2
- package/dist/image/root/image-root.js +8 -2
- package/dist/input/root/input-root.d.ts +51 -9
- package/dist/input/root/input-root.js +46 -5
- package/dist/kbd/root/kbd-root.d.ts +12 -4
- package/dist/kbd/root/kbd-root.js +10 -11
- package/dist/legend/root/legend-root.d.ts +7 -0
- package/dist/legend/root/legend-root.js +7 -2
- package/dist/lightbox/item/lightbox-item.d.ts +2 -1
- package/dist/lightbox/root/lightbox-root.d.ts +16 -5
- package/dist/lightbox/root/lightbox-root.js +24 -3
- package/dist/line-chart/root/line-chart-root.d.ts +19 -2
- package/dist/line-chart/root/line-chart-root.js +40 -13
- package/dist/list/item/list-item.d.ts +11 -5
- package/dist/list/item/list-item.js +5 -6
- package/dist/listbox/root/listbox-root.d.ts +111 -2
- package/dist/listbox/root/listbox-root.js +144 -16
- package/dist/map/root/map-root.d.ts +19 -4
- package/dist/map/root/map-root.js +36 -7
- package/dist/megamenu/root/megamenu-root.d.ts +10 -1
- package/dist/megamenu/root/megamenu-root.js +10 -1
- package/dist/menu/item/menu-item.d.ts +41 -12
- package/dist/menu/item/menu-item.js +46 -3
- package/dist/menu/root/menu-root.d.ts +32 -2
- package/dist/menu/root/menu-root.js +48 -8
- package/dist/meter/root/meter-root.d.ts +6 -0
- package/dist/meter/root/meter-root.js +18 -2
- package/dist/navigation/root/navigation-root.d.ts +10 -2
- package/dist/navigation/root/navigation-root.js +13 -2
- package/dist/notifications/group/notification-group.d.ts +1 -0
- package/dist/notifications/notification/notification.d.ts +12 -0
- package/dist/notifications/notification/notification.js +31 -2
- package/dist/notifications/root/notifications-root.d.ts +7 -0
- package/dist/notifications/root/notifications-root.js +17 -2
- package/dist/number-input/root/number-input-root.d.ts +62 -7
- package/dist/number-input/root/number-input-root.js +68 -16
- package/dist/object-inspector/root/object-inspector-root.d.ts +48 -5
- package/dist/object-inspector/root/object-inspector-root.js +91 -11
- package/dist/option/root/option-root.d.ts +4 -1
- package/dist/option/root/option-root.js +1 -0
- package/dist/outline/root/outline-root.d.ts +13 -2
- package/dist/outline/root/outline-root.js +4 -2
- package/dist/pagination/root/pagination-root.d.ts +19 -1
- package/dist/pagination/root/pagination-root.js +49 -9
- package/dist/pagination/size/pagination-size.d.ts +13 -3
- package/dist/pagination/size/pagination-size.js +7 -0
- package/dist/pin-input/root/pin-input-root.d.ts +16 -0
- package/dist/pin-input/root/pin-input-root.js +19 -5
- package/dist/popover/root/popover-root.d.ts +19 -2
- package/dist/popover/root/popover-root.js +22 -1
- package/dist/progress/root/progress-root.d.ts +16 -1
- package/dist/progress/root/progress-root.js +31 -7
- package/dist/qr-code/root/qr-code-root.d.ts +19 -0
- package/dist/qr-code/root/qr-code-root.js +29 -1
- package/dist/radio/group/radio-group.d.ts +41 -0
- package/dist/radio/group/radio-group.js +50 -14
- package/dist/radio/root/radio-root.d.ts +8 -5
- package/dist/radio/root/radio-root.js +1 -2
- package/dist/rating/root/rating-root.d.ts +24 -1
- package/dist/rating/root/rating-root.js +24 -7
- package/dist/scatter-chart/root/scatter-chart-root.js +15 -7
- package/dist/select/root/select-root.d.ts +69 -3
- package/dist/select/root/select-root.js +92 -8
- package/dist/skeleton/root/skeleton-root.d.ts +14 -3
- package/dist/skeleton/root/skeleton-root.js +17 -3
- package/dist/skip-link/root/skip-link-root.d.ts +10 -0
- package/dist/skip-link/root/skip-link-root.js +15 -1
- package/dist/slider/root/slider-root.d.ts +20 -2
- package/dist/slider/root/slider-root.js +41 -3
- package/dist/sparkline/root/sparkline-root.d.ts +9 -10
- package/dist/speed-dial/item/speed-dial-item.d.ts +11 -5
- package/dist/speed-dial/item/speed-dial-item.js +7 -2
- package/dist/speed-dial/root/speed-dial-root.d.ts +15 -4
- package/dist/speed-dial/root/speed-dial-root.js +19 -5
- package/dist/splitter/root/splitter-root.d.ts +28 -6
- package/dist/splitter/root/splitter-root.js +35 -1
- package/dist/stat/root/stat-root.d.ts +7 -1
- package/dist/stat/root/stat-root.js +14 -1
- package/dist/steps/root/steps-root.js +1 -1
- package/dist/switch/root/switch-root.d.ts +2 -0
- package/dist/switch/root/switch-root.js +1 -0
- package/dist/table/cell/table-cell.d.ts +24 -4
- package/dist/table/cell/table-cell.js +21 -1
- package/dist/table/column/table-column.d.ts +32 -6
- package/dist/table/column/table-column.js +36 -6
- package/dist/table/root/table-root.d.ts +94 -3
- package/dist/table/root/table-root.js +128 -5
- package/dist/table/row/table-row.d.ts +7 -0
- package/dist/table/row/table-row.js +9 -1
- package/dist/tabs/root/tabs-root.d.ts +6 -1
- package/dist/tabs/root/tabs-root.js +6 -2
- package/dist/tag/root/tag-root.d.ts +23 -1
- package/dist/tag/root/tag-root.js +16 -2
- package/dist/textarea/root/textarea-root.d.ts +4 -0
- package/dist/textarea/root/textarea-root.js +1 -1
- package/dist/time-input/root/time-input-root.d.ts +28 -2
- package/dist/time-input/root/time-input-root.js +46 -10
- package/dist/time-picker/root/time-picker-root.d.ts +101 -18
- package/dist/time-picker/root/time-picker-root.js +115 -16
- package/dist/toast/root/toast-root.d.ts +64 -1
- package/dist/toast/root/toast-root.js +147 -2
- package/dist/toggle/group/toggle-group.d.ts +38 -1
- package/dist/toggle/group/toggle-group.js +34 -8
- package/dist/toggle/root/toggle-root.d.ts +14 -10
- package/dist/toggle/root/toggle-root.js +3 -3
- package/dist/toolbar/root/toolbar-root.d.ts +55 -15
- package/dist/toolbar/root/toolbar-root.js +99 -16
- package/dist/tooltip/root/tooltip-root.d.ts +37 -4
- package/dist/tooltip/root/tooltip-root.js +48 -0
- package/dist/tour/root/tour-root.d.ts +34 -5
- package/dist/tour/root/tour-root.js +51 -14
- package/dist/tour/stop/tour-stop.d.ts +18 -1
- package/dist/tour/stop/tour-stop.js +25 -5
- package/dist/tree/item/tree-item.d.ts +21 -5
- package/dist/tree/item/tree-item.js +14 -4
- package/dist/tree/root/tree-root.d.ts +29 -5
- package/dist/tree/root/tree-root.js +64 -8
- package/dist/trend/root/trend-root.d.ts +23 -1
- package/dist/trend/root/trend-root.js +28 -7
- package/dist/video/root/keys.d.ts +5 -0
- package/dist/video/root/keys.js +13 -1
- package/dist/video/root/video-root.d.ts +19 -0
- package/dist/video/root/video-root.js +48 -4
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +20 -2
- package/dist/video-playlist/menu/video-playlist-menu.js +27 -5
- package/dist/video-playlist/root/video-playlist-root.js +6 -3
- package/dist/virtual-list/root/virtual-list-root.d.ts +52 -4
- package/dist/virtual-list/root/virtual-list-root.js +103 -21
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +4348 -965
- package/types/vue.d.ts +972 -232
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
|
-
import { type TemplateResult } from 'lit';
|
|
2
|
+
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
declare const HelixHeadlessAccordionItem_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & typeof HelixElement;
|
|
4
4
|
/**
|
|
5
5
|
* @summary One collapsible section of an accordion.
|
|
@@ -8,6 +8,10 @@ declare const HelixHeadlessAccordionItem_base: (new (...args: any[]) => import("
|
|
|
8
8
|
* Holds its own open state. Used alone, outside an accordion, it works as a
|
|
9
9
|
* disclosure.
|
|
10
10
|
*
|
|
11
|
+
* The trigger sits inside a heading, so a screen reader lists the section with
|
|
12
|
+
* the page's headings. The level is the item's `heading-level`, then the
|
|
13
|
+
* accordion's, then 3.
|
|
14
|
+
*
|
|
11
15
|
* Content stays mounted when the item is closed, so it can animate and its text
|
|
12
16
|
* is present in server-rendered HTML. Closed content has both `hidden` and
|
|
13
17
|
* `inert`. `hidden` collapses it when no stylesheet is loaded. `inert` keeps it
|
|
@@ -24,12 +28,13 @@ declare const HelixHeadlessAccordionItem_base: (new (...args: any[]) => import("
|
|
|
24
28
|
*
|
|
25
29
|
* @event {HelixBeforeCloseEvent} helix-before-close - The section is about to close. Cancelable: cancel it to keep it open.
|
|
26
30
|
* @event {HelixBeforeOpenEvent} helix-before-open - The section is about to open. Cancelable: cancel it to keep it closed.
|
|
27
|
-
* @event {
|
|
31
|
+
* @event {ToggleEvent} toggle - The section opened or closed. The event carries `newState` and `oldState`.
|
|
28
32
|
*
|
|
29
33
|
* @csspart chevron - The open and close indicator.
|
|
30
34
|
* @csspart container - The outer wrapper.
|
|
31
35
|
* @csspart content - The region that holds the content.
|
|
32
36
|
* @csspart content-inner - The clipping box inside the animated region.
|
|
37
|
+
* @csspart heading - The heading that holds the trigger.
|
|
33
38
|
* @csspart trigger - The button that opens and closes the section, holding the summary.
|
|
34
39
|
*
|
|
35
40
|
* @cssstate open - While the item is open.
|
|
@@ -48,6 +53,24 @@ export declare class HelixHeadlessAccordionItem extends HelixHeadlessAccordionIt
|
|
|
48
53
|
chevronPlacement?: 'auto' | 'start' | 'end' | 'none';
|
|
49
54
|
/** The chevron, or nothing when suppressed. */
|
|
50
55
|
private renderChevron;
|
|
56
|
+
/**
|
|
57
|
+
* Whether the section is disabled, so its trigger cannot be pressed or
|
|
58
|
+
* reached with the arrow keys. A script can still open and close it.
|
|
59
|
+
*/
|
|
60
|
+
disabled: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* @internal The accordion's `heading-level`, written by the accordion. A
|
|
63
|
+
* property, because an attribute written onto your element after it upgrades
|
|
64
|
+
* causes a hydration mismatch.
|
|
65
|
+
*/
|
|
66
|
+
groupHeadingLevel: number | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* The level of the heading around the trigger, from 1 to 6.
|
|
69
|
+
*
|
|
70
|
+
* Unset takes the accordion's `heading-level`, and 3 where that is unset
|
|
71
|
+
* too.
|
|
72
|
+
*/
|
|
73
|
+
headingLevel?: number;
|
|
51
74
|
/**
|
|
52
75
|
* A group name. Opening an item closes the other items with the same name,
|
|
53
76
|
* as `<details name>` does.
|
|
@@ -69,6 +92,8 @@ export declare class HelixHeadlessAccordionItem extends HelixHeadlessAccordionIt
|
|
|
69
92
|
* absence. Caught by `hydration.dom.spec.ts`.
|
|
70
93
|
*/
|
|
71
94
|
name?: string;
|
|
95
|
+
/** Whether the item was open at the last update, and `undefined` before one. */
|
|
96
|
+
private wasOpen;
|
|
72
97
|
/**
|
|
73
98
|
* The nearest accordion above this item, if there is one.
|
|
74
99
|
*
|
|
@@ -95,6 +120,17 @@ export declare class HelixHeadlessAccordionItem extends HelixHeadlessAccordionIt
|
|
|
95
120
|
* set collapsed after a listener refused it.
|
|
96
121
|
*/
|
|
97
122
|
protected handleToggle: () => void;
|
|
123
|
+
/** Closes the other open items in this item's set, where it has one. */
|
|
124
|
+
private closePeers;
|
|
125
|
+
/**
|
|
126
|
+
* Closes the peers of an item opened any other way than its trigger: `open`
|
|
127
|
+
* set from a script, `requestOpen` or `toggleOpen`. The trigger already
|
|
128
|
+
* closed them, so for a press this finds nothing open.
|
|
129
|
+
*
|
|
130
|
+
* Not on the first update. What the markup opens is the accordion's to
|
|
131
|
+
* settle, once every item is there to compare.
|
|
132
|
+
*/
|
|
133
|
+
protected updated(changed: PropertyValues): void;
|
|
98
134
|
/**
|
|
99
135
|
* Moves focus to this item's trigger.
|
|
100
136
|
*
|
|
@@ -15,7 +15,13 @@ const TRIGGER_ID = 'trigger';
|
|
|
15
15
|
let HelixHeadlessAccordionItem = class HelixHeadlessAccordionItem extends MixinControllerOpen(HelixElement) {
|
|
16
16
|
constructor() {
|
|
17
17
|
super(...arguments);
|
|
18
|
+
this.disabled = false;
|
|
19
|
+
this.groupHeadingLevel = undefined;
|
|
20
|
+
this.wasOpen = undefined;
|
|
18
21
|
this.handleToggle = () => {
|
|
22
|
+
if (this.disabled) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
19
25
|
const next = !this.open;
|
|
20
26
|
const mode = this.accordion?.mode;
|
|
21
27
|
if (!next && mode === 'single') {
|
|
@@ -24,12 +30,8 @@ let HelixHeadlessAccordionItem = class HelixHeadlessAccordionItem extends MixinC
|
|
|
24
30
|
if (!this.requestOpen(next)) {
|
|
25
31
|
return;
|
|
26
32
|
}
|
|
27
|
-
if (next
|
|
28
|
-
|
|
29
|
-
if (peer !== this && peer.open) {
|
|
30
|
-
peer.requestOpen(false);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
+
if (next) {
|
|
34
|
+
this.closePeers();
|
|
33
35
|
}
|
|
34
36
|
};
|
|
35
37
|
}
|
|
@@ -57,25 +59,46 @@ let HelixHeadlessAccordionItem = class HelixHeadlessAccordionItem extends MixinC
|
|
|
57
59
|
}
|
|
58
60
|
return accordion.items;
|
|
59
61
|
}
|
|
62
|
+
closePeers() {
|
|
63
|
+
if (this.accordion?.mode === undefined && (this.name === undefined || this.name === '')) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
for (const peer of this.peers) {
|
|
67
|
+
if (peer !== this && peer.open) {
|
|
68
|
+
peer.requestOpen(false);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
updated(changed) {
|
|
73
|
+
super.updated(changed);
|
|
74
|
+
if (this.wasOpen === false && this.open) {
|
|
75
|
+
this.closePeers();
|
|
76
|
+
}
|
|
77
|
+
this.wasOpen = this.open;
|
|
78
|
+
}
|
|
60
79
|
focusTrigger() {
|
|
61
80
|
this.renderRoot.querySelector(`#${TRIGGER_ID}`)?.focus();
|
|
62
81
|
}
|
|
63
82
|
render() {
|
|
64
83
|
const open = this.open;
|
|
84
|
+
const level = Math.min(6, Math.max(1, this.headingLevel ?? this.groupHeadingLevel ?? 3));
|
|
65
85
|
return html `
|
|
66
86
|
<div part="container">
|
|
87
|
+
<div part="heading" role="heading" aria-level=${level}>
|
|
67
88
|
<button
|
|
68
89
|
id=${TRIGGER_ID}
|
|
69
90
|
aria-controls=${CONTENT_ID}
|
|
70
91
|
aria-expanded=${open ? 'true' : 'false'}
|
|
71
92
|
part="trigger"
|
|
72
93
|
type="button"
|
|
94
|
+
?disabled=${this.disabled}
|
|
73
95
|
@click=${this.handleToggle}
|
|
74
96
|
>
|
|
75
97
|
${this.chevronPlacement === 'start' ? this.renderChevron() : nothing}
|
|
76
98
|
<slot name="summary"></slot>
|
|
77
99
|
${this.chevronPlacement === 'start' ? nothing : this.renderChevron()}
|
|
78
100
|
</button>
|
|
101
|
+
</div>
|
|
79
102
|
<div
|
|
80
103
|
id=${CONTENT_ID}
|
|
81
104
|
aria-labelledby=${TRIGGER_ID}
|
|
@@ -95,6 +118,15 @@ let HelixHeadlessAccordionItem = class HelixHeadlessAccordionItem extends MixinC
|
|
|
95
118
|
__decorate([
|
|
96
119
|
property({ attribute: 'chevron-placement', reflect: true })
|
|
97
120
|
], HelixHeadlessAccordionItem.prototype, "chevronPlacement", void 0);
|
|
121
|
+
__decorate([
|
|
122
|
+
property({ reflect: true, type: Boolean })
|
|
123
|
+
], HelixHeadlessAccordionItem.prototype, "disabled", void 0);
|
|
124
|
+
__decorate([
|
|
125
|
+
property({ attribute: false })
|
|
126
|
+
], HelixHeadlessAccordionItem.prototype, "groupHeadingLevel", void 0);
|
|
127
|
+
__decorate([
|
|
128
|
+
property({ attribute: 'heading-level', type: Number })
|
|
129
|
+
], HelixHeadlessAccordionItem.prototype, "headingLevel", void 0);
|
|
98
130
|
__decorate([
|
|
99
131
|
property({ reflect: true })
|
|
100
132
|
], HelixHeadlessAccordionItem.prototype, "name", void 0);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HelixElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
|
|
2
|
-
import { type TemplateResult } from 'lit';
|
|
2
|
+
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
import { HelixHeadlessAccordionItem } from '../item/accordion-item.js';
|
|
4
4
|
/**
|
|
5
5
|
* @summary A group of collapsible sections.
|
|
@@ -20,6 +20,10 @@ import { HelixHeadlessAccordionItem } from '../item/accordion-item.js';
|
|
|
20
20
|
* The keyboard listener belongs to the controller and is attached on connect,
|
|
21
21
|
* so it does not run on the server.
|
|
22
22
|
*
|
|
23
|
+
* Each trigger sits inside a heading, level 3 unless `heading-level` says
|
|
24
|
+
* otherwise, so the sections are in a screen reader's list of headings. Set the
|
|
25
|
+
* level that fits the page's outline.
|
|
26
|
+
*
|
|
23
27
|
* @since 0.1.0
|
|
24
28
|
* @status stable
|
|
25
29
|
* @category layout
|
|
@@ -29,6 +33,12 @@ import { HelixHeadlessAccordionItem } from '../item/accordion-item.js';
|
|
|
29
33
|
* @slot - The accordion's items.
|
|
30
34
|
*/
|
|
31
35
|
export declare class HelixHeadlessAccordion extends HelixElement {
|
|
36
|
+
/**
|
|
37
|
+
* The level of the heading around each trigger, from 1 to 6.
|
|
38
|
+
*
|
|
39
|
+
* Unset is 3. An item's own `heading-level` wins over this.
|
|
40
|
+
*/
|
|
41
|
+
headingLevel?: number;
|
|
32
42
|
/**
|
|
33
43
|
* How many sections may be open at once.
|
|
34
44
|
*
|
|
@@ -36,6 +46,11 @@ export declare class HelixHeadlessAccordion extends HelixElement {
|
|
|
36
46
|
* no attribute on the host. `single` keeps exactly one open and refuses to
|
|
37
47
|
* close the last; `single-collapsible` keeps at most one and lets it close.
|
|
38
48
|
*
|
|
49
|
+
* Held however a section opens: a press, `open` set from a script,
|
|
50
|
+
* `toggleOpen()`, or `default-open` in the markup. Opening one closes the
|
|
51
|
+
* others, and on first render only the first section written open stays
|
|
52
|
+
* open. Under `single` the first section opens when none is written open.
|
|
53
|
+
*
|
|
39
54
|
* A union rather than a mode plus a `collapsible` boolean, which would make
|
|
40
55
|
* `collapsible` alongside `multiple` expressible and meaningless.
|
|
41
56
|
*/
|
|
@@ -43,6 +58,13 @@ export declare class HelixHeadlessAccordion extends HelixElement {
|
|
|
43
58
|
/** The accordion's own items, in the order they are written. Browser only. */
|
|
44
59
|
get items(): HelixHeadlessAccordionItem[];
|
|
45
60
|
protected readonly keys: KeyboardNavigationController;
|
|
61
|
+
/**
|
|
62
|
+
* Holds the mode over the sections as written, and passes the heading level
|
|
63
|
+
* down. A section opened later closes its peers itself.
|
|
64
|
+
*/
|
|
65
|
+
private settle;
|
|
66
|
+
protected firstUpdated(changed: PropertyValues): void;
|
|
67
|
+
protected updated(changed: PropertyValues): void;
|
|
46
68
|
protected render(): TemplateResult;
|
|
47
69
|
}
|
|
48
70
|
declare global {
|
|
@@ -4,13 +4,13 @@ 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, KeyboardNavigationController, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, HelixElement, KeyboardNavigationController, whenHydrated, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { HelixHeadlessAccordionItem } from '../item/accordion-item.js';
|
|
11
11
|
const navigable = (item) => ({
|
|
12
12
|
contains: (node) => node === item,
|
|
13
|
-
disabled:
|
|
13
|
+
disabled: item.disabled,
|
|
14
14
|
focusItem: () => item.focusTrigger(),
|
|
15
15
|
select: () => { },
|
|
16
16
|
selected: false,
|
|
@@ -27,10 +27,46 @@ let HelixHeadlessAccordion = class HelixHeadlessAccordion extends HelixElement {
|
|
|
27
27
|
get items() {
|
|
28
28
|
return [...this.children].filter((child) => child instanceof HelixHeadlessAccordionItem);
|
|
29
29
|
}
|
|
30
|
+
settle() {
|
|
31
|
+
const items = this.items;
|
|
32
|
+
for (const item of items) {
|
|
33
|
+
whenHydrated(item, () => {
|
|
34
|
+
item.groupHeadingLevel = this.headingLevel;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
if (this.mode === undefined) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const open = items.filter((item) => item.open);
|
|
41
|
+
for (const extra of open.slice(1)) {
|
|
42
|
+
whenHydrated(extra, () => {
|
|
43
|
+
extra.open = false;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const first = items[0];
|
|
47
|
+
if (this.mode === 'single' && open.length === 0 && first) {
|
|
48
|
+
whenHydrated(first, () => {
|
|
49
|
+
first.open = true;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
firstUpdated(changed) {
|
|
54
|
+
super.firstUpdated(changed);
|
|
55
|
+
this.settle();
|
|
56
|
+
}
|
|
57
|
+
updated(changed) {
|
|
58
|
+
super.updated(changed);
|
|
59
|
+
if (this.hasUpdated && (changed.has('mode') || changed.has('headingLevel'))) {
|
|
60
|
+
this.settle();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
30
63
|
render() {
|
|
31
|
-
return html `<slot></slot>`;
|
|
64
|
+
return html `<slot @slotchange=${() => this.settle()}></slot>`;
|
|
32
65
|
}
|
|
33
66
|
};
|
|
67
|
+
__decorate([
|
|
68
|
+
property({ attribute: 'heading-level', type: Number })
|
|
69
|
+
], HelixHeadlessAccordion.prototype, "headingLevel", void 0);
|
|
34
70
|
__decorate([
|
|
35
71
|
property({ reflect: true })
|
|
36
72
|
], HelixHeadlessAccordion.prototype, "mode", void 0);
|
|
@@ -16,12 +16,17 @@ declare const HelixHeadlessAnnouncement_base: (new (...args: any[]) => import("@
|
|
|
16
16
|
*
|
|
17
17
|
* The live region is its own part. When the announcement appears after the page
|
|
18
18
|
* has loaded, the message is written into the region one frame later, so screen
|
|
19
|
-
* readers read it reliably
|
|
20
|
-
*
|
|
19
|
+
* readers read it reliably, and the region is emptied seven seconds later, so
|
|
20
|
+
* the message is not in the page twice. When the announcement is in the served
|
|
21
|
+
* HTML, the region stays empty and nothing is read out.
|
|
21
22
|
*
|
|
22
23
|
* The dismiss button fires `helix-dismiss`, and the announcement stays in the
|
|
23
24
|
* document, so remove it in your listener. The event is cancelable, and
|
|
24
|
-
* `dismiss()` returns `false` when a listener calls `preventDefault()`.
|
|
25
|
+
* `dismiss()` returns `false` when a listener calls `preventDefault()`. When
|
|
26
|
+
* your listener removes an announcement whose dismiss button has focus, focus
|
|
27
|
+
* moves to the dismiss button of the announcement beside it. With no other
|
|
28
|
+
* announcement beside it, move focus yourself, for example to the page's main
|
|
29
|
+
* heading.
|
|
25
30
|
*
|
|
26
31
|
* @since 0.1.0
|
|
27
32
|
* @status stable
|
|
@@ -39,7 +44,7 @@ declare const HelixHeadlessAnnouncement_base: (new (...args: any[]) => import("@
|
|
|
39
44
|
* @csspart content - The region that holds the message.
|
|
40
45
|
* @csspart dismiss - The button that dismisses the announcement.
|
|
41
46
|
* @csspart dismiss-mark - The icon on the dismiss button, shown when the `icon` slot is empty.
|
|
42
|
-
* @csspart live - A copy of the message in a live region, read by screen readers when the announcement appears after the page has loaded. Visually hidden in the styled tier.
|
|
47
|
+
* @csspart live - A copy of the message in a live region, read by screen readers when the announcement appears after the page has loaded, and emptied seven seconds later. Visually hidden in the styled tier.
|
|
43
48
|
*/
|
|
44
49
|
export declare class HelixHeadlessAnnouncement extends HelixHeadlessAnnouncement_base {
|
|
45
50
|
/**
|
|
@@ -55,9 +60,8 @@ export declare class HelixHeadlessAnnouncement extends HelixHeadlessAnnouncement
|
|
|
55
60
|
* components saying what a thing means, in three vocabularies, one of which
|
|
56
61
|
* described itself as a fourth.
|
|
57
62
|
*
|
|
58
|
-
* `accent` is the second emphasis,
|
|
59
|
-
*
|
|
60
|
-
* is the seed itself.
|
|
63
|
+
* `accent` is the second emphasis, the second color a theme names, and the
|
|
64
|
+
* brand itself until one is named. `primary` is the brand.
|
|
61
65
|
*
|
|
62
66
|
* **`surface` was never a color and has moved to `separation`**, which is the
|
|
63
67
|
* axis that owns where a box sits relative to the page. It said the band rode
|
|
@@ -34,7 +34,7 @@ let HelixHeadlessAnnouncement = class HelixHeadlessAnnouncement extends MixinDis
|
|
|
34
34
|
render() {
|
|
35
35
|
return html `<div part="content"><slot @slotchange=${() => this.arrival.say()}></slot></div>
|
|
36
36
|
<span part="live" role="status">${this.arrival.said}</span>
|
|
37
|
-
<div part="actions"><slot name="actions"></slot></div>
|
|
37
|
+
<div part="actions"><slot name="actions" @slotchange=${() => this.markEmpty()}></slot></div>
|
|
38
38
|
${this.dismissible
|
|
39
39
|
? html `<button
|
|
40
40
|
part="dismiss"
|
|
@@ -16,6 +16,9 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
16
16
|
* `ElementInternals.states` is not in the DOM, so hydration has nothing to
|
|
17
17
|
* compare. Select the state with `:state(scrolled)`.
|
|
18
18
|
*
|
|
19
|
+
* The page is the window unless `scroller` names the element that scrolls, for
|
|
20
|
+
* an app shell whose content scrolls inside a container.
|
|
21
|
+
*
|
|
19
22
|
* @since 0.1.0
|
|
20
23
|
* @status stable
|
|
21
24
|
* @category navigation
|
|
@@ -56,7 +59,24 @@ export declare class HelixHeadlessAppHeader extends HelixElement {
|
|
|
56
59
|
* the property carries the part's name, `content`.
|
|
57
60
|
*/
|
|
58
61
|
contentAlign?: 'start';
|
|
62
|
+
/**
|
|
63
|
+
* The id of the element whose scrolling lifts the bar, for an app shell that
|
|
64
|
+
* scrolls a container instead of the window. Unset is the window.
|
|
65
|
+
*/
|
|
66
|
+
scroller?: string;
|
|
59
67
|
private scrolled;
|
|
68
|
+
/** What scroll is listened to now, so a change of `scroller` moves it. */
|
|
69
|
+
private source;
|
|
70
|
+
/** The element `scroller` names, or the window. */
|
|
71
|
+
private findSource;
|
|
72
|
+
/**
|
|
73
|
+
* Listens to the scroll source that `scroller` names now.
|
|
74
|
+
*
|
|
75
|
+
* A named element that is not in the document yet, such as a `<main>` the
|
|
76
|
+
* parser has not reached when the header connects, is looked for once more
|
|
77
|
+
* when the document has loaded.
|
|
78
|
+
*/
|
|
79
|
+
private listen;
|
|
60
80
|
/**
|
|
61
81
|
* A band rather than a line, so the fill cannot flicker at the boundary.
|
|
62
82
|
*
|
|
@@ -79,6 +99,7 @@ export declare class HelixHeadlessAppHeader extends HelixElement {
|
|
|
79
99
|
protected willUpdate(changed: PropertyValues): void;
|
|
80
100
|
connectedCallback(): void;
|
|
81
101
|
disconnectedCallback(): void;
|
|
102
|
+
protected updated(changed: PropertyValues): void;
|
|
82
103
|
protected render(): TemplateResult;
|
|
83
104
|
}
|
|
84
105
|
declare global {
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, HelixElement, HelixScrolledEvent, hostAria } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, elementById, HelixElement, HelixScrolledEvent, hostAria, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
let HelixHeadlessAppHeader = class HelixHeadlessAppHeader extends HelixElement {
|
|
@@ -12,7 +12,8 @@ let HelixHeadlessAppHeader = class HelixHeadlessAppHeader extends HelixElement {
|
|
|
12
12
|
super(...arguments);
|
|
13
13
|
this.scrolled = false;
|
|
14
14
|
this.handleScroll = () => {
|
|
15
|
-
const
|
|
15
|
+
const source = this.source ?? window;
|
|
16
|
+
const y = source instanceof Element ? source.scrollTop : window.scrollY;
|
|
16
17
|
const next = this.scrolled ? y > 2 : y > 8;
|
|
17
18
|
if (next === this.scrolled) {
|
|
18
19
|
return;
|
|
@@ -22,18 +23,40 @@ let HelixHeadlessAppHeader = class HelixHeadlessAppHeader extends HelixElement {
|
|
|
22
23
|
this.dispatchEvent(new HelixScrolledEvent({ scrolled: next }));
|
|
23
24
|
};
|
|
24
25
|
}
|
|
26
|
+
findSource() {
|
|
27
|
+
return (this.scroller ? elementById(this, this.scroller) : null) ?? window;
|
|
28
|
+
}
|
|
29
|
+
listen() {
|
|
30
|
+
const next = this.findSource();
|
|
31
|
+
if (next === window && this.scroller && document.readyState === 'loading') {
|
|
32
|
+
document.addEventListener('DOMContentLoaded', () => this.listen(), { once: true });
|
|
33
|
+
}
|
|
34
|
+
if (next === this.source) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.source?.removeEventListener('scroll', this.handleScroll);
|
|
38
|
+
this.source = next;
|
|
39
|
+
next.addEventListener('scroll', this.handleScroll, { passive: true });
|
|
40
|
+
this.handleScroll();
|
|
41
|
+
}
|
|
25
42
|
willUpdate(changed) {
|
|
26
43
|
super.willUpdate(changed);
|
|
27
44
|
hostAria(this.internals, { role: 'banner' });
|
|
28
45
|
}
|
|
29
46
|
connectedCallback() {
|
|
30
47
|
super.connectedCallback();
|
|
31
|
-
|
|
32
|
-
this.handleScroll();
|
|
48
|
+
this.listen();
|
|
33
49
|
}
|
|
34
50
|
disconnectedCallback() {
|
|
35
51
|
super.disconnectedCallback();
|
|
36
|
-
|
|
52
|
+
this.source?.removeEventListener('scroll', this.handleScroll);
|
|
53
|
+
this.source = undefined;
|
|
54
|
+
}
|
|
55
|
+
updated(changed) {
|
|
56
|
+
super.updated(changed);
|
|
57
|
+
if (changed.has('scroller') && this.isConnected) {
|
|
58
|
+
this.listen();
|
|
59
|
+
}
|
|
37
60
|
}
|
|
38
61
|
render() {
|
|
39
62
|
return html `
|
|
@@ -48,6 +71,9 @@ let HelixHeadlessAppHeader = class HelixHeadlessAppHeader extends HelixElement {
|
|
|
48
71
|
__decorate([
|
|
49
72
|
property({ attribute: 'content-align', reflect: true })
|
|
50
73
|
], HelixHeadlessAppHeader.prototype, "contentAlign", void 0);
|
|
74
|
+
__decorate([
|
|
75
|
+
property()
|
|
76
|
+
], HelixHeadlessAppHeader.prototype, "scroller", void 0);
|
|
51
77
|
HelixHeadlessAppHeader = __decorate([
|
|
52
78
|
customElement('helix-headless-app-header')
|
|
53
79
|
], HelixHeadlessAppHeader);
|
|
@@ -8,7 +8,18 @@ import { CHART_PLOT, customElement, drawTooltip, formatNumbers, HelixElement, li
|
|
|
8
8
|
import { html, nothing, svg } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import '../../tooltip/index.js';
|
|
11
|
-
const
|
|
11
|
+
const PERCENTS = new Map();
|
|
12
|
+
const percentIn = (locale) => {
|
|
13
|
+
let found = PERCENTS.get(locale);
|
|
14
|
+
if (!found) {
|
|
15
|
+
found = new Intl.NumberFormat(locale || undefined, {
|
|
16
|
+
maximumFractionDigits: 0,
|
|
17
|
+
style: 'percent',
|
|
18
|
+
});
|
|
19
|
+
PERCENTS.set(locale, found);
|
|
20
|
+
}
|
|
21
|
+
return found;
|
|
22
|
+
};
|
|
12
23
|
let HelixHeadlessAreaChart = class HelixHeadlessAreaChart extends MixinChartSource(HelixElement) {
|
|
13
24
|
constructor() {
|
|
14
25
|
super(...arguments);
|
|
@@ -150,15 +161,15 @@ let HelixHeadlessAreaChart = class HelixHeadlessAreaChart extends MixinChartSour
|
|
|
150
161
|
renderSummary(stack, rows) {
|
|
151
162
|
const last = rows.length - 1;
|
|
152
163
|
const total = stack.totals[last] ?? 0;
|
|
153
|
-
const format = formatNumbers(
|
|
154
|
-
const shares = stack.names.map((name, depth) => `${name} ${
|
|
164
|
+
const format = formatNumbers(this.locale);
|
|
165
|
+
const shares = stack.names.map((name, depth) => `${name} ${percentIn(this.locale).format(total > 0 ? (stack.values[depth]?.[last] ?? 0) / total : 0)}`);
|
|
155
166
|
const named = this.named ? `${this.named}, ` : '';
|
|
156
167
|
return html `<p part="summary">
|
|
157
168
|
${named}${rows[last]?.label ?? ''}: ${this.totalLabel} ${format(total)}; ${shares.join(', ')}.
|
|
158
169
|
</p>`;
|
|
159
170
|
}
|
|
160
171
|
tallied(rows, stack) {
|
|
161
|
-
const format = formatNumbers(
|
|
172
|
+
const format = formatNumbers(this.locale);
|
|
162
173
|
return rows.map((row, index) => {
|
|
163
174
|
const total = stack.totals[index] ?? 0;
|
|
164
175
|
return {
|
|
@@ -167,7 +178,7 @@ let HelixHeadlessAreaChart = class HelixHeadlessAreaChart extends MixinChartSour
|
|
|
167
178
|
...row.cells.map((cell, column) => this.share && cell.value !== undefined && stack.columns.includes(column) && total > 0
|
|
168
179
|
? {
|
|
169
180
|
...cell,
|
|
170
|
-
text: `${cell.text} (${
|
|
181
|
+
text: `${cell.text} (${percentIn(this.locale).format(Math.max(0, cell.value) / total)})`,
|
|
171
182
|
}
|
|
172
183
|
: cell),
|
|
173
184
|
{ name: this.totalLabel, text: format(total) },
|
|
@@ -20,8 +20,10 @@ export declare const FOLDS_UP_TO = 12;
|
|
|
20
20
|
* There is no slot for it, because the number has to match which avatars are
|
|
21
21
|
* hidden.
|
|
22
22
|
*
|
|
23
|
-
* Avatars past `max` stay in the DOM and are hidden.
|
|
24
|
-
*
|
|
23
|
+
* Avatars past `max` stay in the DOM and are hidden. The group writes `hidden`
|
|
24
|
+
* on each of them, so they are hidden on the headless tier as well, and the
|
|
25
|
+
* count is read out as `overflow-label`, such as "3 more", so a screen reader
|
|
26
|
+
* hears that there are more people than the ones it can reach.
|
|
25
27
|
*
|
|
26
28
|
* @since 0.1.0
|
|
27
29
|
* @status stable
|
|
@@ -30,7 +32,7 @@ export declare const FOLDS_UP_TO = 12;
|
|
|
30
32
|
*
|
|
31
33
|
* @slot - The avatars, in the order they should be read.
|
|
32
34
|
*
|
|
33
|
-
* @csspart overflow - The count of avatars past `max`.
|
|
35
|
+
* @csspart overflow - The count of avatars past `max`, an image named by `overflow-label`.
|
|
34
36
|
*/
|
|
35
37
|
export declare class HelixHeadlessAvatarGroup extends HelixElement {
|
|
36
38
|
/**
|
|
@@ -56,6 +58,15 @@ export declare class HelixHeadlessAvatarGroup extends HelixElement {
|
|
|
56
58
|
* never asked for a limit, including on the server.
|
|
57
59
|
*/
|
|
58
60
|
max?: number;
|
|
61
|
+
/**
|
|
62
|
+
* What a screen reader is told the count is, with `{count}` for the number.
|
|
63
|
+
*
|
|
64
|
+
* The count shows "+3", which reads as "plus three" and says nothing about
|
|
65
|
+
* what was counted.
|
|
66
|
+
*/
|
|
67
|
+
overflowLabel: string;
|
|
68
|
+
/** The avatars this group hid, so it unhides only those. */
|
|
69
|
+
private readonly folded;
|
|
59
70
|
/** The avatars, in light-DOM order. Empty on the server, which has no tree. */
|
|
60
71
|
get avatars(): HTMLElement[];
|
|
61
72
|
/**
|
|
@@ -72,6 +83,16 @@ export declare class HelixHeadlessAvatarGroup extends HelixElement {
|
|
|
72
83
|
protected willUpdate(changed: PropertyValues): void;
|
|
73
84
|
protected firstUpdated(changed: PropertyValues): void;
|
|
74
85
|
protected updated(changed: PropertyValues): void;
|
|
86
|
+
/**
|
|
87
|
+
* Hides the avatars past `max`, with the platform's own `hidden`.
|
|
88
|
+
*
|
|
89
|
+
* **State in markup, so the headless tier folds too.** The fold was a styled
|
|
90
|
+
* rule alone, and on the headless tier every avatar was drawn beside a "+3".
|
|
91
|
+
* The styled rule stays, because it is what folds a server's markup before
|
|
92
|
+
* this runs. Written through `whenHydrated`, so an avatar's hydrating render
|
|
93
|
+
* is the server's, and undone only on the avatars this group hid.
|
|
94
|
+
*/
|
|
95
|
+
private fold;
|
|
75
96
|
protected render(): TemplateResult;
|
|
76
97
|
}
|
|
77
98
|
declare global {
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, HelixElement, hostAria, reportRuntime } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, HelixElement, hostAria, reportRuntime, whenHydrated, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
export const FOLDS_UP_TO = 12;
|
|
@@ -12,6 +12,8 @@ let HelixHeadlessAvatarGroup = class HelixHeadlessAvatarGroup extends HelixEleme
|
|
|
12
12
|
constructor() {
|
|
13
13
|
super(...arguments);
|
|
14
14
|
this.label = '';
|
|
15
|
+
this.overflowLabel = '{count} more';
|
|
16
|
+
this.folded = new WeakSet();
|
|
15
17
|
this.warned = false;
|
|
16
18
|
}
|
|
17
19
|
get avatars() {
|
|
@@ -32,6 +34,7 @@ let HelixHeadlessAvatarGroup = class HelixHeadlessAvatarGroup extends HelixEleme
|
|
|
32
34
|
}
|
|
33
35
|
updated(changed) {
|
|
34
36
|
super.updated(changed);
|
|
37
|
+
this.fold();
|
|
35
38
|
const limit = this.max ?? 0;
|
|
36
39
|
if (limit > FOLDS_UP_TO && this.avatars.length > limit && !this.warned) {
|
|
37
40
|
this.warned = true;
|
|
@@ -44,10 +47,36 @@ let HelixHeadlessAvatarGroup = class HelixHeadlessAvatarGroup extends HelixEleme
|
|
|
44
47
|
});
|
|
45
48
|
}
|
|
46
49
|
}
|
|
50
|
+
fold() {
|
|
51
|
+
const limit = this.max ?? 0;
|
|
52
|
+
const limited = limit > 0 && limit <= FOLDS_UP_TO;
|
|
53
|
+
for (const [index, avatar] of this.avatars.entries()) {
|
|
54
|
+
const past = limited && index >= limit;
|
|
55
|
+
if (past && !avatar.hidden) {
|
|
56
|
+
this.folded.add(avatar);
|
|
57
|
+
whenHydrated(avatar, () => {
|
|
58
|
+
avatar.hidden = true;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
else if (!past && this.folded.has(avatar)) {
|
|
62
|
+
this.folded.delete(avatar);
|
|
63
|
+
whenHydrated(avatar, () => {
|
|
64
|
+
avatar.hidden = false;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
47
69
|
render() {
|
|
48
70
|
const past = this.overflow;
|
|
49
71
|
return html `<slot @slotchange=${() => this.requestUpdate()}></slot>
|
|
50
|
-
${past > 0
|
|
72
|
+
${past > 0
|
|
73
|
+
? html `<span
|
|
74
|
+
part="overflow"
|
|
75
|
+
role="img"
|
|
76
|
+
aria-label=${this.overflowLabel.replace('{count}', String(past))}
|
|
77
|
+
>+${past}</span
|
|
78
|
+
>`
|
|
79
|
+
: ''}`;
|
|
51
80
|
}
|
|
52
81
|
};
|
|
53
82
|
__decorate([
|
|
@@ -56,6 +85,9 @@ __decorate([
|
|
|
56
85
|
__decorate([
|
|
57
86
|
property({ reflect: true, type: Number })
|
|
58
87
|
], HelixHeadlessAvatarGroup.prototype, "max", void 0);
|
|
88
|
+
__decorate([
|
|
89
|
+
property({ attribute: 'overflow-label' })
|
|
90
|
+
], HelixHeadlessAvatarGroup.prototype, "overflowLabel", void 0);
|
|
59
91
|
HelixHeadlessAvatarGroup = __decorate([
|
|
60
92
|
customElement('helix-headless-avatar-group')
|
|
61
93
|
], HelixHeadlessAvatarGroup);
|
|
@@ -46,7 +46,9 @@ export declare class HelixHeadlessAvatar extends HelixElement {
|
|
|
46
46
|
src: string;
|
|
47
47
|
/**
|
|
48
48
|
* The image's state: `loading` while it is on its way, `loaded` once it
|
|
49
|
-
* arrives, or `error` when it fails and the initials replace it.
|
|
49
|
+
* arrives, or `error` when it fails and the initials replace it. An avatar
|
|
50
|
+
* with no `src` has no image to wait for, and reports `error` as well, since
|
|
51
|
+
* the initials are what it shows.
|
|
50
52
|
*
|
|
51
53
|
* Read-only to a consumer: it is a report rather than a setting, and the same
|
|
52
54
|
* report `Image` gives, for the same reason. `load` and `error` fire once, so
|