@fusion.dev/helix-headless 0.142.0 → 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
|
@@ -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 { valueAsTime as asTime, customElement, timeAsValue as fromTime, HelixFormElement, MixinControllerValue, minutesAsValue, reportValues, valueAsMinutes, writeTime, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { valueAsTime as asTime, customElement, elementById, fillTemplate, timeAsValue as fromTime, HelixFormElement, MixinControllerValue, minutesAsValue, reportValues, valueAsMinutes, writeTime, writtenList, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { html } from 'lit/static-html.js';
|
|
@@ -12,17 +12,22 @@ import '../../listbox/index.js';
|
|
|
12
12
|
import '../../option/index.js';
|
|
13
13
|
const isTwelveHour = (locale) => new Intl.DateTimeFormat(locale || undefined, { timeStyle: 'short' }).resolvedOptions().hour12 ===
|
|
14
14
|
true;
|
|
15
|
+
const dayPeriod = (half, locale) => new Intl.DateTimeFormat(locale || undefined, { hour: 'numeric', hour12: true, timeZone: 'UTC' })
|
|
16
|
+
.formatToParts(new Date(Date.UTC(1970, 0, 1, half === 'AM' ? 9 : 21)))
|
|
17
|
+
.find((part) => part.type === 'dayPeriod')?.value ?? half;
|
|
15
18
|
let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControllerValue(HelixFormElement) {
|
|
16
19
|
constructor() {
|
|
17
20
|
super(...arguments);
|
|
18
21
|
this.disableTimes = '';
|
|
22
|
+
this.hourLabel = 'Hour';
|
|
19
23
|
this.invalid = false;
|
|
20
24
|
this.label = 'Time';
|
|
21
25
|
this.locale = '';
|
|
26
|
+
this.manual = false;
|
|
22
27
|
this.max = '23:59';
|
|
28
|
+
this.meridiemLabel = 'Before or after noon';
|
|
23
29
|
this.min = '00:00';
|
|
24
|
-
this.
|
|
25
|
-
this.required = false;
|
|
30
|
+
this.minuteLabel = 'Minute';
|
|
26
31
|
this.handleListInput = (event) => {
|
|
27
32
|
event.stopPropagation();
|
|
28
33
|
};
|
|
@@ -69,14 +74,17 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
69
74
|
const half = hour % 12;
|
|
70
75
|
next = (half + (to === 'PM' ? 12 : 0)) * 60 + minute;
|
|
71
76
|
}
|
|
72
|
-
const whole = minutesAsValue(next);
|
|
77
|
+
const whole = minutesAsValue(this.nearest(next));
|
|
73
78
|
if (this.barred(whole)) {
|
|
74
79
|
return;
|
|
75
80
|
}
|
|
76
81
|
this.requestValue(whole);
|
|
77
82
|
};
|
|
83
|
+
this.readOnly = false;
|
|
84
|
+
this.required = false;
|
|
78
85
|
this.step = 15;
|
|
79
86
|
this.listRevealed = false;
|
|
87
|
+
this.naming = undefined;
|
|
80
88
|
}
|
|
81
89
|
get times() {
|
|
82
90
|
const from = valueAsMinutes(this.min) ?? 0;
|
|
@@ -89,11 +97,17 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
89
97
|
return found;
|
|
90
98
|
}
|
|
91
99
|
barred(at) {
|
|
92
|
-
return this.disableTimes
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
100
|
+
return writtenList(this.disableTimes).includes(at);
|
|
101
|
+
}
|
|
102
|
+
nearest(minutes) {
|
|
103
|
+
const times = this.times;
|
|
104
|
+
let best = times[0] ?? minutes;
|
|
105
|
+
for (const at of times) {
|
|
106
|
+
if (Math.abs(at - minutes) < Math.abs(best - minutes)) {
|
|
107
|
+
best = at;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return best;
|
|
97
111
|
}
|
|
98
112
|
wholeHourBarred(shown, half) {
|
|
99
113
|
const whole = half === undefined ? shown : (shown % 12) + (half === 'PM' ? 12 : 0);
|
|
@@ -148,6 +162,34 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
148
162
|
}
|
|
149
163
|
return super.requestValue(next);
|
|
150
164
|
}
|
|
165
|
+
fault(at) {
|
|
166
|
+
const minutes = valueAsMinutes(at) ?? 0;
|
|
167
|
+
const floor = valueAsMinutes(this.min) ?? 0;
|
|
168
|
+
const ceiling = valueAsMinutes(this.max) ?? 1439;
|
|
169
|
+
if (minutes < floor) {
|
|
170
|
+
return [
|
|
171
|
+
'rangeUnderflow',
|
|
172
|
+
fillTemplate(this.rangeUnderflowMessage || 'Choose a time at or after {min}.', {
|
|
173
|
+
min: writeTime(this.min, this.locale),
|
|
174
|
+
}),
|
|
175
|
+
];
|
|
176
|
+
}
|
|
177
|
+
if (minutes > ceiling) {
|
|
178
|
+
return [
|
|
179
|
+
'rangeOverflow',
|
|
180
|
+
fillTemplate(this.rangeOverflowMessage || 'Choose a time at or before {max}.', {
|
|
181
|
+
max: writeTime(this.max, this.locale),
|
|
182
|
+
}),
|
|
183
|
+
];
|
|
184
|
+
}
|
|
185
|
+
if (this.barred(at)) {
|
|
186
|
+
return ['badInput', this.unavailableMessage || 'Choose a time that is available.'];
|
|
187
|
+
}
|
|
188
|
+
if (!this.times.includes(minutes)) {
|
|
189
|
+
return ['stepMismatch', this.stepMismatchMessage || 'Choose one of the times on offer.'];
|
|
190
|
+
}
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
151
193
|
reportRequired() {
|
|
152
194
|
const anchor = this.partNamed('list') ?? undefined;
|
|
153
195
|
if (this.required && this.value === '') {
|
|
@@ -162,10 +204,17 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
162
204
|
: 'Enter times as HH:mm, separated by commas.'), anchor);
|
|
163
205
|
return;
|
|
164
206
|
}
|
|
207
|
+
for (const one of held) {
|
|
208
|
+
const fault = this.fault(one);
|
|
209
|
+
if (fault) {
|
|
210
|
+
this.internals.setValidity({ [fault[0]]: true }, fault[1], anchor);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
165
214
|
this.internals.setValidity({});
|
|
166
215
|
}
|
|
167
216
|
report() {
|
|
168
|
-
if (this.
|
|
217
|
+
if (this.isDisabled) {
|
|
169
218
|
this.internals.setFormValue(null);
|
|
170
219
|
return;
|
|
171
220
|
}
|
|
@@ -178,6 +227,25 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
178
227
|
await Promise.all(settling.map((one) => one.updateComplete));
|
|
179
228
|
this.reveal();
|
|
180
229
|
}
|
|
230
|
+
get listName() {
|
|
231
|
+
const named = (this.getAttribute('aria-labelledby') ?? '')
|
|
232
|
+
.split(/\s+/)
|
|
233
|
+
.filter(Boolean)
|
|
234
|
+
.map((id) => elementById(this, id)?.textContent?.trim() ?? '')
|
|
235
|
+
.filter(Boolean)
|
|
236
|
+
.join(' ');
|
|
237
|
+
return named || this.getAttribute('aria-label') || this.label;
|
|
238
|
+
}
|
|
239
|
+
connectedCallback() {
|
|
240
|
+
super.connectedCallback();
|
|
241
|
+
this.naming = new MutationObserver(() => this.requestUpdate());
|
|
242
|
+
this.naming.observe(this, { attributeFilter: ['aria-label', 'aria-labelledby'] });
|
|
243
|
+
}
|
|
244
|
+
disconnectedCallback() {
|
|
245
|
+
super.disconnectedCallback();
|
|
246
|
+
this.naming?.disconnect();
|
|
247
|
+
this.naming = undefined;
|
|
248
|
+
}
|
|
181
249
|
willUpdate(changed) {
|
|
182
250
|
super.willUpdate(changed);
|
|
183
251
|
this.internals.ariaInvalid = this.invalid ? 'true' : null;
|
|
@@ -196,7 +264,8 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
196
264
|
}
|
|
197
265
|
}
|
|
198
266
|
focus(options) {
|
|
199
|
-
|
|
267
|
+
;
|
|
268
|
+
(this.partNamed('list') ?? this.partNamed('column'))?.focus(options);
|
|
200
269
|
}
|
|
201
270
|
renderColumn(part, label, values, written, value, barred = () => false) {
|
|
202
271
|
return html `<${this.tag('listbox')}
|
|
@@ -234,11 +303,16 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
234
303
|
const hours = twelve
|
|
235
304
|
? [...new Set(this.hours.map((one) => (one % 12 === 0 ? 12 : one % 12)))].sort((a, b) => a - b)
|
|
236
305
|
: this.hours;
|
|
237
|
-
return html `<div
|
|
238
|
-
|
|
239
|
-
|
|
306
|
+
return html `<div
|
|
307
|
+
part="columns"
|
|
308
|
+
role="group"
|
|
309
|
+
aria-label=${this.listName}
|
|
310
|
+
data-unset=${this.value === '' ? '' : nothing}
|
|
311
|
+
>
|
|
312
|
+
${this.renderColumn('hour', this.hourLabel, hours.map(String), (one) => (twelve ? one : one.padStart(2, '0')), shownHour, (one) => this.wholeHourBarred(Number(one), twelve ? meridiem : undefined))}
|
|
313
|
+
${this.renderColumn('minute', this.minuteLabel, this.minutes.map(String), (one) => one.padStart(2, '0'), String(minute), (one) => this.barred(minutesAsValue(hour * 60 + Number(one))))}
|
|
240
314
|
${twelve
|
|
241
|
-
? this.renderColumn('meridiem',
|
|
315
|
+
? this.renderColumn('meridiem', this.meridiemLabel, ['AM', 'PM'], (one) => dayPeriod(one, this.locale), meridiem, (one) => this.halfBarred(one))
|
|
242
316
|
: nothing}
|
|
243
317
|
</div>`;
|
|
244
318
|
}
|
|
@@ -249,9 +323,10 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinControl
|
|
|
249
323
|
exportparts="empty: list-empty, feedback: list-feedback, filter-icon: list-filter-icon,
|
|
250
324
|
filter-mark: list-filter-mark, hint: list-hint, items: list-items, label: list-label,
|
|
251
325
|
live: list-live, loading: list-loading, search: list-search, search-field: list-search-field"
|
|
252
|
-
aria-label=${this.
|
|
326
|
+
aria-label=${this.listName}
|
|
253
327
|
data-unset=${this.value === '' ? '' : nothing}
|
|
254
328
|
?disabled=${this.isDisabled}
|
|
329
|
+
?manual=${this.manual}
|
|
255
330
|
?multiple=${this.mode !== undefined}
|
|
256
331
|
.value=${this.value}
|
|
257
332
|
@helix-before-change=${this.handleChange}
|
|
@@ -299,6 +374,9 @@ __decorate([
|
|
|
299
374
|
__decorate([
|
|
300
375
|
property({ attribute: 'disable-times' })
|
|
301
376
|
], HelixHeadlessTimePicker.prototype, "disableTimes", void 0);
|
|
377
|
+
__decorate([
|
|
378
|
+
property({ attribute: 'hour-label' })
|
|
379
|
+
], HelixHeadlessTimePicker.prototype, "hourLabel", void 0);
|
|
302
380
|
__decorate([
|
|
303
381
|
property({ reflect: true, type: Boolean })
|
|
304
382
|
], HelixHeadlessTimePicker.prototype, "invalid", void 0);
|
|
@@ -308,15 +386,30 @@ __decorate([
|
|
|
308
386
|
__decorate([
|
|
309
387
|
property()
|
|
310
388
|
], HelixHeadlessTimePicker.prototype, "locale", void 0);
|
|
389
|
+
__decorate([
|
|
390
|
+
property({ type: Boolean })
|
|
391
|
+
], HelixHeadlessTimePicker.prototype, "manual", void 0);
|
|
311
392
|
__decorate([
|
|
312
393
|
property()
|
|
313
394
|
], HelixHeadlessTimePicker.prototype, "max", void 0);
|
|
395
|
+
__decorate([
|
|
396
|
+
property({ attribute: 'meridiem-label' })
|
|
397
|
+
], HelixHeadlessTimePicker.prototype, "meridiemLabel", void 0);
|
|
314
398
|
__decorate([
|
|
315
399
|
property()
|
|
316
400
|
], HelixHeadlessTimePicker.prototype, "min", void 0);
|
|
401
|
+
__decorate([
|
|
402
|
+
property({ attribute: 'minute-label' })
|
|
403
|
+
], HelixHeadlessTimePicker.prototype, "minuteLabel", void 0);
|
|
317
404
|
__decorate([
|
|
318
405
|
property({ reflect: true })
|
|
319
406
|
], HelixHeadlessTimePicker.prototype, "mode", void 0);
|
|
407
|
+
__decorate([
|
|
408
|
+
property({ attribute: 'range-overflow-message' })
|
|
409
|
+
], HelixHeadlessTimePicker.prototype, "rangeOverflowMessage", void 0);
|
|
410
|
+
__decorate([
|
|
411
|
+
property({ attribute: 'range-underflow-message' })
|
|
412
|
+
], HelixHeadlessTimePicker.prototype, "rangeUnderflowMessage", void 0);
|
|
320
413
|
__decorate([
|
|
321
414
|
property({ attribute: 'readonly', reflect: true, type: Boolean })
|
|
322
415
|
], HelixHeadlessTimePicker.prototype, "readOnly", void 0);
|
|
@@ -326,6 +419,12 @@ __decorate([
|
|
|
326
419
|
__decorate([
|
|
327
420
|
property({ type: Number })
|
|
328
421
|
], HelixHeadlessTimePicker.prototype, "step", void 0);
|
|
422
|
+
__decorate([
|
|
423
|
+
property({ attribute: 'step-mismatch-message' })
|
|
424
|
+
], HelixHeadlessTimePicker.prototype, "stepMismatchMessage", void 0);
|
|
425
|
+
__decorate([
|
|
426
|
+
property({ attribute: 'unavailable-message' })
|
|
427
|
+
], HelixHeadlessTimePicker.prototype, "unavailableMessage", void 0);
|
|
329
428
|
__decorate([
|
|
330
429
|
property({ attribute: 'value-missing-message' })
|
|
331
430
|
], HelixHeadlessTimePicker.prototype, "valueMissingMessage", void 0);
|
|
@@ -23,6 +23,19 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
23
23
|
* your app's state, which also lets you render the same messages on the server,
|
|
24
24
|
* in a test, or more than once.
|
|
25
25
|
*
|
|
26
|
+
* **The stack is in the top layer.** The `region` part is a `popover="manual"`
|
|
27
|
+
* shown while a message is showing, and shown again above a modal dialog that
|
|
28
|
+
* opened after it. Position the `region` part, which is the box in the top
|
|
29
|
+
* layer. While a modal `Dialog`, `Drawer` or `Lightbox` is open, the browser
|
|
30
|
+
* makes everything outside it inert, the stack included, so a message stays
|
|
31
|
+
* visible and its actions cannot be pressed. Where the browser has
|
|
32
|
+
* `ariaNotify`, a message that arrives then is announced through it. For a
|
|
33
|
+
* message with an action, render a second region inside the dialog.
|
|
34
|
+
*
|
|
35
|
+
* When a message with focus inside it is dismissed, focus moves to the next
|
|
36
|
+
* message, then the one before it, then back to where it was before it entered
|
|
37
|
+
* the stack.
|
|
38
|
+
*
|
|
26
39
|
* @since 0.1.0
|
|
27
40
|
* @status stable
|
|
28
41
|
* @category overlays
|
|
@@ -33,7 +46,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
33
46
|
*
|
|
34
47
|
* @event {HelixDismissEvent} helix-dismiss - A message is being dismissed, by its control or by its timer. The message sends it, and you can listen for it on the region. Cancelable: canceling it keeps the message.
|
|
35
48
|
*
|
|
36
|
-
* @csspart region - The stack the messages are in.
|
|
49
|
+
* @csspart region - The stack the messages are in. It is in the top layer while a message shows.
|
|
37
50
|
*/
|
|
38
51
|
export declare class HelixHeadlessToast extends HelixElement {
|
|
39
52
|
/**
|
|
@@ -68,6 +81,56 @@ export declare class HelixHeadlessToast extends HelixElement {
|
|
|
68
81
|
*/
|
|
69
82
|
placement?: 'bottom-center' | 'bottom-end' | 'bottom-start' | 'top-center' | 'top-end' | 'top-start';
|
|
70
83
|
protected willUpdate(changed: PropertyValues): void;
|
|
84
|
+
/** The element focus came from when it entered the stack. */
|
|
85
|
+
private focusOrigin;
|
|
86
|
+
/** Watches the messages arrive and hide, to raise or lower the stack. */
|
|
87
|
+
private watcher;
|
|
88
|
+
/** The messages that are showing, in order. */
|
|
89
|
+
private get showing();
|
|
90
|
+
private get region();
|
|
91
|
+
/**
|
|
92
|
+
* Puts the stack in the top layer while a message shows, and on top of it.
|
|
93
|
+
*
|
|
94
|
+
* Shown again when a message arrives under a modal opened after it, because
|
|
95
|
+
* the top layer is ordered by when each element entered it. Only then,
|
|
96
|
+
* because showing it again starts every message's entrance over.
|
|
97
|
+
*/
|
|
98
|
+
private place;
|
|
99
|
+
/**
|
|
100
|
+
* Takes the stack out of the top layer once the last message has finished
|
|
101
|
+
* leaving. Hidden at once, the stack would cut the exit short.
|
|
102
|
+
*/
|
|
103
|
+
private lowerWhenStill;
|
|
104
|
+
/**
|
|
105
|
+
* Whether a modal dialog this stack is not inside is open, which makes the
|
|
106
|
+
* stack inert.
|
|
107
|
+
*
|
|
108
|
+
* Two places to look: the modal `Dialog` and `Drawer` the scroll lock
|
|
109
|
+
* records, whose `<dialog>` is in a shadow root, and an open modal `<dialog>`
|
|
110
|
+
* in the document itself.
|
|
111
|
+
*/
|
|
112
|
+
private blocked;
|
|
113
|
+
/**
|
|
114
|
+
* Announces messages that arrived while the live region is inert.
|
|
115
|
+
*
|
|
116
|
+
* `ariaNotify` speaks without a live region in the accessibility tree, which
|
|
117
|
+
* is the one channel left under a modal. A browser without it says nothing,
|
|
118
|
+
* as it did before.
|
|
119
|
+
*/
|
|
120
|
+
private notify;
|
|
121
|
+
/** Remembers where focus came from when it enters the stack. */
|
|
122
|
+
private readonly handleFocusIn;
|
|
123
|
+
/**
|
|
124
|
+
* Keeps focus on the stack when the message holding it goes.
|
|
125
|
+
*
|
|
126
|
+
* Read after the item's update, because the dismissal is a request a
|
|
127
|
+
* listener after this one can still refuse. A refused one leaves the
|
|
128
|
+
* message, and focus with it.
|
|
129
|
+
*/
|
|
130
|
+
private readonly handleDismiss;
|
|
131
|
+
connectedCallback(): void;
|
|
132
|
+
disconnectedCallback(): void;
|
|
133
|
+
protected firstUpdated(changed: PropertyValues): void;
|
|
71
134
|
protected render(): TemplateResult;
|
|
72
135
|
}
|
|
73
136
|
declare global {
|
|
@@ -4,13 +4,56 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, deepActiveElement, deepContains, focusableElements, HelixElement, hostAria, scrollHolders, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
11
11
|
constructor() {
|
|
12
12
|
super(...arguments);
|
|
13
13
|
this.label = 'Notifications';
|
|
14
|
+
this.handleFocusIn = (event) => {
|
|
15
|
+
const from = event.relatedTarget;
|
|
16
|
+
if (from instanceof HTMLElement && !deepContains(this, from)) {
|
|
17
|
+
this.focusOrigin = from;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
this.handleDismiss = (event) => {
|
|
21
|
+
const item = event.target;
|
|
22
|
+
if (!(item instanceof HTMLElement) || item.parentElement !== this) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (!deepContains(item, deepActiveElement())) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const before = this.showing;
|
|
29
|
+
const at = before.indexOf(item);
|
|
30
|
+
void Promise.resolve()
|
|
31
|
+
.then(() => item.updateComplete)
|
|
32
|
+
.then(() => {
|
|
33
|
+
if (!item.hidden) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const active = deepActiveElement();
|
|
37
|
+
if (active && active !== document.body && !deepContains(item, active)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const after = before.slice(at + 1).filter((one) => !one.hidden);
|
|
41
|
+
const earlier = before
|
|
42
|
+
.slice(0, at)
|
|
43
|
+
.filter((one) => !one.hidden)
|
|
44
|
+
.reverse();
|
|
45
|
+
for (const next of [...after, ...earlier]) {
|
|
46
|
+
const target = focusTarget(next);
|
|
47
|
+
if (target) {
|
|
48
|
+
target.focus();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (this.focusOrigin?.isConnected) {
|
|
53
|
+
this.focusOrigin.focus();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
};
|
|
14
57
|
}
|
|
15
58
|
willUpdate(changed) {
|
|
16
59
|
super.willUpdate(changed);
|
|
@@ -19,8 +62,99 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
19
62
|
this.internals.ariaRelevant = 'additions';
|
|
20
63
|
this.internals.ariaAtomic = 'false';
|
|
21
64
|
}
|
|
65
|
+
get showing() {
|
|
66
|
+
return [...this.children].filter((one) => one instanceof HTMLElement && !one.hidden);
|
|
67
|
+
}
|
|
68
|
+
get region() {
|
|
69
|
+
return this.partNamed('region');
|
|
70
|
+
}
|
|
71
|
+
place(added = []) {
|
|
72
|
+
const region = this.region;
|
|
73
|
+
if (!region || typeof region.showPopover !== 'function') {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const showing = this.showing;
|
|
77
|
+
const open = popoverOpen(region);
|
|
78
|
+
if (showing.length === 0) {
|
|
79
|
+
if (open) {
|
|
80
|
+
this.lowerWhenStill(region);
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const arrived = added.filter((one) => one instanceof HTMLElement && showing.includes(one));
|
|
85
|
+
const blocked = arrived.length > 0 && this.blocked();
|
|
86
|
+
if (open && blocked) {
|
|
87
|
+
region.hidePopover();
|
|
88
|
+
}
|
|
89
|
+
if (!open || blocked) {
|
|
90
|
+
region.showPopover();
|
|
91
|
+
}
|
|
92
|
+
if (blocked) {
|
|
93
|
+
this.notify(arrived);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
lowerWhenStill(region) {
|
|
97
|
+
const running = typeof this.getAnimations === 'function' ? this.getAnimations({ subtree: true }) : [];
|
|
98
|
+
void Promise.allSettled(running.map((one) => one.finished)).then(() => {
|
|
99
|
+
if (this.showing.length === 0 && popoverOpen(region)) {
|
|
100
|
+
region.hidePopover();
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
blocked() {
|
|
105
|
+
const holders = scrollHolders();
|
|
106
|
+
try {
|
|
107
|
+
const native = document.querySelector('dialog:modal');
|
|
108
|
+
if (native) {
|
|
109
|
+
holders.push(native);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
}
|
|
114
|
+
return holders.some((holder) => !deepContains(holder, this));
|
|
115
|
+
}
|
|
116
|
+
notify(arrived) {
|
|
117
|
+
const speaker = document;
|
|
118
|
+
if (typeof speaker.ariaNotify !== 'function') {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
for (const one of arrived) {
|
|
122
|
+
const words = (one.textContent ?? '').replace(/\s+/gu, ' ').trim();
|
|
123
|
+
if (words !== '') {
|
|
124
|
+
speaker.ariaNotify(words);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
connectedCallback() {
|
|
129
|
+
super.connectedCallback();
|
|
130
|
+
this.addEventListener('focusin', this.handleFocusIn);
|
|
131
|
+
this.addEventListener('helix-dismiss', this.handleDismiss);
|
|
132
|
+
this.watcher = new MutationObserver((records) => {
|
|
133
|
+
this.place(records.flatMap((record) => [...record.addedNodes]));
|
|
134
|
+
});
|
|
135
|
+
this.watcher.observe(this, {
|
|
136
|
+
attributeFilter: ['hidden'],
|
|
137
|
+
attributes: true,
|
|
138
|
+
childList: true,
|
|
139
|
+
subtree: true,
|
|
140
|
+
});
|
|
141
|
+
if (this.hasUpdated) {
|
|
142
|
+
this.place();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
disconnectedCallback() {
|
|
146
|
+
super.disconnectedCallback();
|
|
147
|
+
this.removeEventListener('focusin', this.handleFocusIn);
|
|
148
|
+
this.removeEventListener('helix-dismiss', this.handleDismiss);
|
|
149
|
+
this.watcher?.disconnect();
|
|
150
|
+
this.watcher = undefined;
|
|
151
|
+
}
|
|
152
|
+
firstUpdated(changed) {
|
|
153
|
+
super.firstUpdated(changed);
|
|
154
|
+
this.place();
|
|
155
|
+
}
|
|
22
156
|
render() {
|
|
23
|
-
return html `<div part="region"><slot></slot></div>`;
|
|
157
|
+
return html `<div part="region" popover="manual"><slot></slot></div>`;
|
|
24
158
|
}
|
|
25
159
|
};
|
|
26
160
|
__decorate([
|
|
@@ -33,3 +167,14 @@ HelixHeadlessToast = __decorate([
|
|
|
33
167
|
customElement('helix-headless-toast')
|
|
34
168
|
], HelixHeadlessToast);
|
|
35
169
|
export { HelixHeadlessToast };
|
|
170
|
+
const popoverOpen = (region) => {
|
|
171
|
+
try {
|
|
172
|
+
return region.matches(':popover-open');
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
const focusTarget = (item) => item.shadowRoot?.querySelector('[part="dismiss"]') ??
|
|
179
|
+
focusableElements(item)[0] ??
|
|
180
|
+
null;
|
|
@@ -21,10 +21,13 @@ declare const HelixHeadlessToggleGroup_base: (new (...args: any[]) => import("@f
|
|
|
21
21
|
*
|
|
22
22
|
* @slot - The group's items.
|
|
23
23
|
* @slot end - Content after the track, on the same line, such as a count or a reset.
|
|
24
|
+
* @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
|
|
25
|
+
* @slot hint - Help under the control, for content richer than the `hint` text.
|
|
26
|
+
* @slot label - The label, for content richer than the `label` text.
|
|
24
27
|
* @slot start - Content before the track, on the same line, such as an icon or a caption.
|
|
25
28
|
*
|
|
26
29
|
* @event {Event} change - Fired after the value changes.
|
|
27
|
-
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before the choice changes. Cancelable: call `preventDefault()` to keep the current choice.
|
|
30
|
+
* @event {HelixBeforeChangeEvent} helix-before-change - Fired before the choice changes. Cancelable: call `preventDefault()` to keep the current choice.
|
|
28
31
|
* @event {HelixSelectEvent} helix-select - Fired when an item is chosen. The item sends it, and you listen for it on the group. Cancelable: call `preventDefault()` to keep the current choice.
|
|
29
32
|
* @event {Event} input - Fired after the value changes.
|
|
30
33
|
*
|
|
@@ -85,11 +88,45 @@ export declare class HelixHeadlessToggleGroup extends HelixHeadlessToggleGroup_b
|
|
|
85
88
|
private adopt;
|
|
86
89
|
/** Marks the chosen item, separately from placing the indicator. */
|
|
87
90
|
private sync;
|
|
91
|
+
/**
|
|
92
|
+
* The item that holds the group's tab stop: the chosen one.
|
|
93
|
+
*
|
|
94
|
+
* With nothing chosen there is no selection to carry the tab stop, so the
|
|
95
|
+
* first item holds one until there is. Otherwise an unanswered group is a
|
|
96
|
+
* control the keyboard cannot enter, which is what the fallback was quietly
|
|
97
|
+
* also doing for it. A disabled answer takes no focus either, so the entry
|
|
98
|
+
* goes to the first item that can be chosen, as in `Radio.Group`.
|
|
99
|
+
*/
|
|
100
|
+
private entry;
|
|
101
|
+
/**
|
|
102
|
+
* Whether the group holds a tab stop of its own.
|
|
103
|
+
*
|
|
104
|
+
* A toolbar is one tab stop, so a toolbar the group sits in sets this to
|
|
105
|
+
* `false` while its stop is on another control, and every item, the chosen
|
|
106
|
+
* one too, is then out of the tab order. The arrow keys inside the group
|
|
107
|
+
* work as before once focus is in it.
|
|
108
|
+
*
|
|
109
|
+
* No attribute: it is coordination between elements, and a consumer has no
|
|
110
|
+
* reason to set it.
|
|
111
|
+
*/
|
|
112
|
+
focusable: boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Focus goes to the item that holds the stop, and to the item that would
|
|
115
|
+
* hold it while a toolbar holds the stop instead, so a label press or a
|
|
116
|
+
* refused submission still lands in the group.
|
|
117
|
+
*/
|
|
118
|
+
protected get focusTarget(): HTMLElement | null;
|
|
88
119
|
private readonly indicator;
|
|
89
120
|
protected readonly keys: KeyboardNavigationController;
|
|
90
121
|
protected readonly cascade: DisabledCascadeController;
|
|
91
122
|
private get items();
|
|
92
123
|
private readonly handleSelection;
|
|
124
|
+
/**
|
|
125
|
+
* Whether the group holds an answer the form can submit: a value an item
|
|
126
|
+
* here carries. A chosen item that was removed is no longer an answer, and
|
|
127
|
+
* `value` keeps the name for an item that arrives later.
|
|
128
|
+
*/
|
|
129
|
+
private get answered();
|
|
93
130
|
connectedCallback(): void;
|
|
94
131
|
disconnectedCallback(): void;
|
|
95
132
|
protected firstUpdated(changed: PropertyValues): void;
|
|
@@ -11,6 +11,7 @@ import { HelixHeadlessToggle } from '../root/toggle-root.js';
|
|
|
11
11
|
let HelixHeadlessToggleGroup = class HelixHeadlessToggleGroup extends MixinControllerValue(MixinField(HelixFormElement)) {
|
|
12
12
|
constructor() {
|
|
13
13
|
super(...arguments);
|
|
14
|
+
this.focusable = true;
|
|
14
15
|
this.indicator = new IndicatorController(this, {
|
|
15
16
|
active: () => this.items.find((item) => item.value === this.value),
|
|
16
17
|
indicator: () => this.partNamed('indicator'),
|
|
@@ -22,10 +23,12 @@ let HelixHeadlessToggleGroup = class HelixHeadlessToggleGroup extends MixinContr
|
|
|
22
23
|
items: () => this.items,
|
|
23
24
|
});
|
|
24
25
|
this.handleSelection = (event) => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
queueMicrotask(() => {
|
|
27
|
+
if (event.defaultPrevented) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
this.requestValue(event.detail.value);
|
|
31
|
+
});
|
|
29
32
|
};
|
|
30
33
|
}
|
|
31
34
|
adopt() {
|
|
@@ -39,14 +42,33 @@ let HelixHeadlessToggleGroup = class HelixHeadlessToggleGroup extends MixinContr
|
|
|
39
42
|
}
|
|
40
43
|
sync() {
|
|
41
44
|
const active = this.items.find((item) => item.value === this.value);
|
|
42
|
-
const entry =
|
|
45
|
+
const entry = this.focusable ? this.entry() : undefined;
|
|
43
46
|
for (const item of this.items) {
|
|
44
47
|
item.selected = item === active;
|
|
45
48
|
item.focusable = item === entry;
|
|
46
49
|
}
|
|
47
50
|
}
|
|
51
|
+
entry() {
|
|
52
|
+
const active = this.items.find((item) => item.value === this.value);
|
|
53
|
+
return active && !active.disabled ? active : this.items.find((item) => !item.disabled);
|
|
54
|
+
}
|
|
55
|
+
get focusTarget() {
|
|
56
|
+
return (super.focusTarget ??
|
|
57
|
+
this.entry()?.shadowRoot?.querySelector('[part="item"]') ??
|
|
58
|
+
null);
|
|
59
|
+
}
|
|
48
60
|
get items() {
|
|
49
|
-
return [...this.children].filter((child) => child instanceof HelixHeadlessToggle);
|
|
61
|
+
return [...(this.children ?? [])].filter((child) => child instanceof HelixHeadlessToggle);
|
|
62
|
+
}
|
|
63
|
+
get answered() {
|
|
64
|
+
if (this.value === '') {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if (this.children === undefined) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
const items = this.items;
|
|
71
|
+
return items.length === 0 || items.some((item) => item.value === this.value);
|
|
50
72
|
}
|
|
51
73
|
connectedCallback() {
|
|
52
74
|
super.connectedCallback();
|
|
@@ -71,10 +93,10 @@ let HelixHeadlessToggleGroup = class HelixHeadlessToggleGroup extends MixinContr
|
|
|
71
93
|
super.willUpdate(changed);
|
|
72
94
|
this.adopt();
|
|
73
95
|
hostAria(this.internals, { label: this.label, role: 'radiogroup' });
|
|
74
|
-
this.internals.setFormValue(this.
|
|
96
|
+
this.internals.setFormValue(this.answered ? this.value : null);
|
|
75
97
|
}
|
|
76
98
|
validate() {
|
|
77
|
-
this.reportRequired(this.
|
|
99
|
+
this.reportRequired(!this.answered, 'Choose one to continue.', 'track');
|
|
78
100
|
}
|
|
79
101
|
render() {
|
|
80
102
|
const inside = this.labelPlacement === 'start';
|
|
@@ -90,6 +112,7 @@ let HelixHeadlessToggleGroup = class HelixHeadlessToggleGroup extends MixinContr
|
|
|
90
112
|
this.adopt();
|
|
91
113
|
this.sync();
|
|
92
114
|
this.indicator.place();
|
|
115
|
+
this.requestUpdate();
|
|
93
116
|
}}
|
|
94
117
|
></slot>
|
|
95
118
|
</div>
|
|
@@ -98,6 +121,9 @@ let HelixHeadlessToggleGroup = class HelixHeadlessToggleGroup extends MixinContr
|
|
|
98
121
|
${this.renderHint()}${this.renderFeedback()}`;
|
|
99
122
|
}
|
|
100
123
|
};
|
|
124
|
+
__decorate([
|
|
125
|
+
property({ attribute: false })
|
|
126
|
+
], HelixHeadlessToggleGroup.prototype, "focusable", void 0);
|
|
101
127
|
__decorate([
|
|
102
128
|
property({ attribute: 'label-placement', reflect: true })
|
|
103
129
|
], HelixHeadlessToggleGroup.prototype, "labelPlacement", void 0);
|