@fusion.dev/helix-headless 0.143.0 → 0.144.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +8551 -375
- 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/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/card/root/card-root.d.ts +30 -1
- package/dist/card/root/card-root.js +38 -5
- 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 +30 -0
- package/dist/code-block/root/code-block-root.js +23 -2
- 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 +27 -1
- package/dist/copy-button/root/copy-button-root.js +43 -7
- 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/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/element-events.generated.js +8 -5
- 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/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 +15 -2
- package/dist/input/root/input-root.d.ts +11 -0
- package/dist/input/root/input-root.js +15 -0
- 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/listbox/range.d.ts +17 -0
- package/dist/listbox/range.js +5 -0
- package/dist/listbox/root/listbox-root.d.ts +74 -3
- package/dist/listbox/root/listbox-root.js +87 -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/meter/root/meter-root.d.ts +7 -0
- package/dist/meter/root/meter-root.js +6 -3
- 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 +42 -0
- package/dist/notifications/root/notifications-root.js +60 -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 +1 -0
- package/dist/object-inspector/root/object-inspector-root.js +1 -1
- package/dist/option/root/option-root.d.ts +54 -5
- package/dist/option/root/option-root.js +34 -5
- 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 +23 -0
- package/dist/radio/group/radio-group.js +18 -0
- package/dist/rating/root/rating-root.d.ts +25 -0
- package/dist/rating/root/rating-root.js +45 -3
- 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/select/root/select-root.d.ts +24 -0
- package/dist/select/root/select-root.js +20 -6
- 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/stat/root/stat-root.d.ts +2 -0
- package/dist/stat/root/stat-root.js +1 -1
- package/dist/steps/step/step.d.ts +1 -0
- package/dist/steps/step/step.js +1 -1
- package/dist/switch/root/switch-root.d.ts +12 -2
- package/dist/switch/root/switch-root.js +6 -1
- 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/toast/hotkey.d.ts +22 -0
- package/dist/toast/hotkey.js +23 -0
- package/dist/toast/item/toast-item.d.ts +16 -1
- package/dist/toast/item/toast-item.js +41 -13
- package/dist/toast/root/toast-root.d.ts +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/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/trend/root/trend-root.d.ts +13 -0
- package/dist/trend/root/trend-root.js +14 -9
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +4862 -254
- package/types/svelte.d.ts +1 -0
- package/types/vue.d.ts +1149 -67
|
@@ -11,25 +11,40 @@ let HelixHeadlessSkeleton = class HelixHeadlessSkeleton extends HelixElement {
|
|
|
11
11
|
constructor() {
|
|
12
12
|
super(...arguments);
|
|
13
13
|
this.label = '';
|
|
14
|
+
this.loading = false;
|
|
15
|
+
}
|
|
16
|
+
get wraps() {
|
|
17
|
+
return (this.childrenKnown &&
|
|
18
|
+
[...this.childNodes].some((node) => node.nodeType === 1 || (node.textContent ?? '').trim() !== ''));
|
|
14
19
|
}
|
|
15
20
|
willUpdate(changed) {
|
|
16
21
|
super.willUpdate(changed);
|
|
22
|
+
this.internals.ariaBusy = this.loading ? 'true' : null;
|
|
17
23
|
if (this.label) {
|
|
18
24
|
hostAria(this.internals, { label: this.label, role: 'progressbar' });
|
|
19
25
|
this.internals.ariaHidden = null;
|
|
20
26
|
}
|
|
21
27
|
else {
|
|
22
28
|
hostAria(this.internals, { label: '', role: '' });
|
|
23
|
-
this.internals.ariaHidden = 'true';
|
|
29
|
+
this.internals.ariaHidden = this.wraps ? null : 'true';
|
|
24
30
|
}
|
|
25
31
|
}
|
|
32
|
+
firstUpdated(changed) {
|
|
33
|
+
super.firstUpdated(changed);
|
|
34
|
+
this.finishHydration();
|
|
35
|
+
}
|
|
26
36
|
render() {
|
|
27
|
-
return html `<span part="
|
|
37
|
+
return html `<span part="content" ?inert=${this.loading}
|
|
38
|
+
><slot @slotchange=${() => this.requestUpdate()}></slot></span
|
|
39
|
+
><span part="skeleton"></span>`;
|
|
28
40
|
}
|
|
29
41
|
};
|
|
30
42
|
__decorate([
|
|
31
43
|
property()
|
|
32
44
|
], HelixHeadlessSkeleton.prototype, "label", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
property({ reflect: true, type: Boolean })
|
|
47
|
+
], HelixHeadlessSkeleton.prototype, "loading", void 0);
|
|
33
48
|
HelixHeadlessSkeleton = __decorate([
|
|
34
49
|
customElement('helix-headless-skeleton')
|
|
35
50
|
], HelixHeadlessSkeleton);
|
|
@@ -20,6 +20,13 @@ declare const HelixHeadlessSlider_base: (new (...args: any[]) => import("@fusion
|
|
|
20
20
|
*
|
|
21
21
|
* A range with two thumbs is two inputs stacked on one track, because there is
|
|
22
22
|
* no native two-thumb range. Each thumb keeps its own value.
|
|
23
|
+
* `min-steps-between-thumbs` keeps them that many steps apart.
|
|
24
|
+
*
|
|
25
|
+
* `format-options` writes the value with `Intl.NumberFormat` in `locale`, as a
|
|
26
|
+
* currency, a percent or a unit, and `formatter` writes it with a function of
|
|
27
|
+
* your own, such as words for a scale. Either one is what a screen reader
|
|
28
|
+
* hears, what the readout shows and what the marker labels say. `value-text`
|
|
29
|
+
* still wraps it in a sentence, with the formatted value in its place.
|
|
23
30
|
*
|
|
24
31
|
* `required` comes with the field mixin and cannot fail. A range is never
|
|
25
32
|
* empty: the platform shows its midpoint when no value is set, and `willUpdate`
|
|
@@ -62,6 +69,27 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
|
|
|
62
69
|
protected readonly aria: AriaForwardController;
|
|
63
70
|
/** Typed or dragged, so every edit is announced. See `announcesInput`. */
|
|
64
71
|
protected readonly announcesInput = true;
|
|
72
|
+
/**
|
|
73
|
+
* `Intl.NumberFormat` options the value is written with: a currency, a
|
|
74
|
+
* percent, a unit, or a number of decimals. Written as JSON in the
|
|
75
|
+
* attribute.
|
|
76
|
+
*
|
|
77
|
+
* ```html
|
|
78
|
+
* <helix-slider format-options='{"style":"currency","currency":"USD"}'></helix-slider>
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
formatOptions?: Intl.NumberFormatOptions;
|
|
82
|
+
/**
|
|
83
|
+
* Writes a value as text, in place of `format-options`: words for a scale,
|
|
84
|
+
* or anything `Intl.NumberFormat` cannot say. A property, since a function
|
|
85
|
+
* cannot be written in an attribute.
|
|
86
|
+
*/
|
|
87
|
+
formatter?: (value: number) => string;
|
|
88
|
+
/**
|
|
89
|
+
* The locale `format-options` writes the value in, such as `de-DE`. Empty is
|
|
90
|
+
* the reader's own.
|
|
91
|
+
*/
|
|
92
|
+
locale: string;
|
|
65
93
|
/**
|
|
66
94
|
* Shows the value at each mark.
|
|
67
95
|
*/
|
|
@@ -102,6 +130,11 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
|
|
|
102
130
|
min: number;
|
|
103
131
|
/** The name of a range's lower thumb, read after the slider's label. */
|
|
104
132
|
minimumLabel: string;
|
|
133
|
+
/**
|
|
134
|
+
* How many steps a range's two thumbs stay apart, as Zag's
|
|
135
|
+
* `minStepsBetweenThumbs`. A thumb pushed closer stops there.
|
|
136
|
+
*/
|
|
137
|
+
minStepsBetweenThumbs: number;
|
|
105
138
|
/**
|
|
106
139
|
* The direction the track runs. `vertical` stands it on end.
|
|
107
140
|
*
|
|
@@ -223,6 +256,12 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
|
|
|
223
256
|
* step, or for a range, two of them in order.
|
|
224
257
|
*/
|
|
225
258
|
private sanitize;
|
|
259
|
+
/** How far apart a range's thumbs stay, in the slider's own units. */
|
|
260
|
+
private get gap();
|
|
261
|
+
/** Whether the value is written by `formatter` or `format-options`. */
|
|
262
|
+
private get formats();
|
|
263
|
+
/** A value as the reader sees it: formatted where asked, the number otherwise. */
|
|
264
|
+
private said;
|
|
226
265
|
/** What a screen reader says for one thumb, where `value-text` asks. */
|
|
227
266
|
private spoken;
|
|
228
267
|
protected updated(changed: PropertyValues): void;
|
|
@@ -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 { AriaForwardController, customElement, fillTemplate, HelixFormElement, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, customElement, fillTemplate, formatNumber, HelixFormElement, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue(MixinField(HelixFormElement)) {
|
|
@@ -14,12 +14,14 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
|
|
|
14
14
|
target: () => this.partNamed('control'),
|
|
15
15
|
});
|
|
16
16
|
this.announcesInput = true;
|
|
17
|
+
this.locale = '';
|
|
17
18
|
this.markerLabels = false;
|
|
18
19
|
this.markers = 0;
|
|
19
20
|
this.max = 100;
|
|
20
21
|
this.maximumLabel = 'maximum';
|
|
21
22
|
this.min = 0;
|
|
22
23
|
this.minimumLabel = 'minimum';
|
|
24
|
+
this.minStepsBetweenThumbs = 0;
|
|
23
25
|
this.range = false;
|
|
24
26
|
this.showValue = false;
|
|
25
27
|
this.step = 1;
|
|
@@ -29,9 +31,10 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
|
|
|
29
31
|
if (this.range) {
|
|
30
32
|
const [start, end] = this.bounds;
|
|
31
33
|
const moved = Number(control.value);
|
|
34
|
+
const gap = this.gap;
|
|
32
35
|
const pair = control.dataset.thumb === 'start'
|
|
33
|
-
? [Math.min(moved, end), end]
|
|
34
|
-
: [start, Math.max(moved, start)];
|
|
36
|
+
? [Math.min(moved, end - gap), end]
|
|
37
|
+
: [start, Math.max(moved, start + gap)];
|
|
35
38
|
this.requestValue(pair.join(','));
|
|
36
39
|
restoreValue(control, String(control.dataset.thumb === 'start' ? this.bounds[0] : this.bounds[1]));
|
|
37
40
|
return;
|
|
@@ -47,7 +50,7 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
|
|
|
47
50
|
this.valueText = '';
|
|
48
51
|
}
|
|
49
52
|
get reserve() {
|
|
50
|
-
const widest = Math.max(
|
|
53
|
+
const widest = Math.max(this.said(this.min).length, this.said(this.max).length);
|
|
51
54
|
return this.range ? widest * 2 + ' to '.length : widest;
|
|
52
55
|
}
|
|
53
56
|
get precision() {
|
|
@@ -141,8 +144,27 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
|
|
|
141
144
|
const at = Number.isFinite(parsed) ? parsed : this.min + (this.max - this.min) / 2;
|
|
142
145
|
return String(this.settled(at));
|
|
143
146
|
}
|
|
147
|
+
get gap() {
|
|
148
|
+
return Math.max(0, this.minStepsBetweenThumbs) * this.step;
|
|
149
|
+
}
|
|
150
|
+
get formats() {
|
|
151
|
+
return this.formatter !== undefined || this.formatOptions !== undefined;
|
|
152
|
+
}
|
|
153
|
+
said(at) {
|
|
154
|
+
const number = typeof at === 'number' ? at : Number.parseFloat(at);
|
|
155
|
+
if (!Number.isFinite(number)) {
|
|
156
|
+
return String(at);
|
|
157
|
+
}
|
|
158
|
+
if (this.formatter) {
|
|
159
|
+
return this.formatter(number);
|
|
160
|
+
}
|
|
161
|
+
return this.formatOptions ? formatNumber(number, this.locale, this.formatOptions) : String(at);
|
|
162
|
+
}
|
|
144
163
|
spoken(at) {
|
|
145
|
-
|
|
164
|
+
if (this.valueText) {
|
|
165
|
+
return fillTemplate(this.valueText, { value: this.said(at) });
|
|
166
|
+
}
|
|
167
|
+
return this.formats ? this.said(at) : nothing;
|
|
146
168
|
}
|
|
147
169
|
updated(changed) {
|
|
148
170
|
super.updated(changed);
|
|
@@ -161,8 +183,8 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
|
|
|
161
183
|
step=${this.step}
|
|
162
184
|
.value=${String(at)}
|
|
163
185
|
aria-labelledby=${this.labeled ? `${this.labelId} ${which}-name` : `${which}-name`}
|
|
164
|
-
aria-valuemin=${which === 'end' ? start : nothing}
|
|
165
|
-
aria-valuemax=${which === 'start' ? end : nothing}
|
|
186
|
+
aria-valuemin=${which === 'end' ? start + this.gap : nothing}
|
|
187
|
+
aria-valuemax=${which === 'start' ? end - this.gap : nothing}
|
|
166
188
|
aria-valuetext=${this.spoken(at)}
|
|
167
189
|
aria-describedby=${this.describedBy ?? nothing}
|
|
168
190
|
aria-invalid=${this.invalidity ?? nothing}
|
|
@@ -207,7 +229,9 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
|
|
|
207
229
|
${this.markerValues.map((at) => html `<span
|
|
208
230
|
part="marker"
|
|
209
231
|
style="--slider-marker-at: ${((at - this.min) / (this.max - this.min)) * 100}%"
|
|
210
|
-
>${this.markerLabels
|
|
232
|
+
>${this.markerLabels
|
|
233
|
+
? html `<span part="marker-label">${this.said(at)}</span>`
|
|
234
|
+
: nothing}</span
|
|
211
235
|
>`)}
|
|
212
236
|
</div>`
|
|
213
237
|
: nothing}
|
|
@@ -217,13 +241,22 @@ let HelixHeadlessSlider = class HelixHeadlessSlider extends MixinControllerValue
|
|
|
217
241
|
for=${this.range ? 'control control-end' : 'control'}
|
|
218
242
|
aria-hidden="true"
|
|
219
243
|
style=${`--_slider-output-reserve: ${this.reserve}ch`}
|
|
220
|
-
>${this.range ? `${start} to ${end}` : this.value}</output
|
|
244
|
+
>${this.range ? `${this.said(start)} to ${this.said(end)}` : this.said(this.value)}</output
|
|
221
245
|
>`
|
|
222
246
|
: nothing}
|
|
223
247
|
</div>
|
|
224
248
|
${this.renderHint()}${this.renderFeedback()}`;
|
|
225
249
|
}
|
|
226
250
|
};
|
|
251
|
+
__decorate([
|
|
252
|
+
property({ attribute: 'format-options', type: Object })
|
|
253
|
+
], HelixHeadlessSlider.prototype, "formatOptions", void 0);
|
|
254
|
+
__decorate([
|
|
255
|
+
property({ attribute: false })
|
|
256
|
+
], HelixHeadlessSlider.prototype, "formatter", void 0);
|
|
257
|
+
__decorate([
|
|
258
|
+
property()
|
|
259
|
+
], HelixHeadlessSlider.prototype, "locale", void 0);
|
|
227
260
|
__decorate([
|
|
228
261
|
property({ attribute: 'marker-labels', reflect: true, type: Boolean })
|
|
229
262
|
], HelixHeadlessSlider.prototype, "markerLabels", void 0);
|
|
@@ -242,6 +275,9 @@ __decorate([
|
|
|
242
275
|
__decorate([
|
|
243
276
|
property({ attribute: 'minimum-label' })
|
|
244
277
|
], HelixHeadlessSlider.prototype, "minimumLabel", void 0);
|
|
278
|
+
__decorate([
|
|
279
|
+
property({ attribute: 'min-steps-between-thumbs', type: Number })
|
|
280
|
+
], HelixHeadlessSlider.prototype, "minStepsBetweenThumbs", void 0);
|
|
245
281
|
__decorate([
|
|
246
282
|
property({ reflect: true })
|
|
247
283
|
], HelixHeadlessSlider.prototype, "orientation", void 0);
|
|
@@ -21,6 +21,8 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
21
21
|
* @slot - The value.
|
|
22
22
|
* @slot label - What the value measures.
|
|
23
23
|
* @slot unit - The unit, shown beside the value.
|
|
24
|
+
*
|
|
25
|
+
* @csspart value - The slot the value is written in. A slot draws no box, so it takes the inherited properties, such as color and font, and passes them to the value.
|
|
24
26
|
*/
|
|
25
27
|
export declare class HelixHeadlessStat extends HelixElement {
|
|
26
28
|
/**
|
|
@@ -38,6 +38,7 @@ import '../../button/index.js';
|
|
|
38
38
|
* @csspart description - The line under the name.
|
|
39
39
|
* @csspart label - The step's name, which is a control.
|
|
40
40
|
* @csspart label-button - The button inside the label.
|
|
41
|
+
* @csspart label-live - The live region inside that button, rendered only from the first time the button is pending.
|
|
41
42
|
* @csspart label-text - The words on that button, trimmed to their capitals and baseline.
|
|
42
43
|
* @csspart mark - The glyph inside the marker: a tick, a dot, or an empty ring.
|
|
43
44
|
* @csspart marker - The shape carrying the number or the check.
|
package/dist/steps/step/step.js
CHANGED
|
@@ -40,7 +40,7 @@ let HelixHeadlessStep = class HelixHeadlessStep extends HelixElement {
|
|
|
40
40
|
renderLabel() {
|
|
41
41
|
return html `<${this.tag('button')}
|
|
42
42
|
part="label"
|
|
43
|
-
exportparts="button: label-button, text: label-text"
|
|
43
|
+
exportparts="button: label-button, live: label-live, text: label-text"
|
|
44
44
|
emphasis="ghost"
|
|
45
45
|
?disabled=${this.disabled}
|
|
46
46
|
@click=${this.select}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AriaForwardController, HelixFormElement, HostClickController } from '@fusion.dev/helix-core';
|
|
2
|
-
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
2
|
+
import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
declare const HelixHeadlessSwitch_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerCheckedInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
|
|
4
4
|
/**
|
|
5
5
|
* @summary A control that turns something on or off.
|
|
@@ -40,7 +40,9 @@ declare const HelixHeadlessSwitch_base: (new (...args: any[]) => import("@fusion
|
|
|
40
40
|
* @csspart track - The track. Draw the thumb on the track itself, with
|
|
41
41
|
* `::part(track)::after` in your stylesheet. This tier ships no CSS, so it
|
|
42
42
|
* renders no separate thumb element, which would be an empty child that costs
|
|
43
|
-
* your layout as much as any other child. `ListItem` measured that cost.
|
|
43
|
+
* your layout as much as any other child. `ListItem` measured that cost. A
|
|
44
|
+
* subclass that draws one returns it from `renderThumb`, as the styled switch
|
|
45
|
+
* does.
|
|
44
46
|
*
|
|
45
47
|
* @cssstate checked - While it is on.
|
|
46
48
|
* @cssstate invalid - The control has an error to show, from the browser's validation or from your `feedback`.
|
|
@@ -70,6 +72,14 @@ export declare class HelixHeadlessSwitch extends HelixHeadlessSwitch_base {
|
|
|
70
72
|
* rendered, which React reports on hydration and does not patch up.
|
|
71
73
|
*/
|
|
72
74
|
private markEmpty;
|
|
75
|
+
/**
|
|
76
|
+
* The thumb, drawn inside the track after the input: nothing on this tier.
|
|
77
|
+
*
|
|
78
|
+
* A seam for a tier that draws the thumb as an element, so it can be a part
|
|
79
|
+
* and hold icons. An element here would be an empty child on every page that
|
|
80
|
+
* loads only this tier, which is the cost the `track` part notes.
|
|
81
|
+
*/
|
|
82
|
+
protected renderThumb(): TemplateResult | typeof nothing;
|
|
73
83
|
protected render(): TemplateResult;
|
|
74
84
|
}
|
|
75
85
|
declare global {
|
|
@@ -43,6 +43,9 @@ let HelixHeadlessSwitch = class HelixHeadlessSwitch extends MixinControllerCheck
|
|
|
43
43
|
markEmpty() {
|
|
44
44
|
markRegion(this.renderRoot, 'label', ['']);
|
|
45
45
|
}
|
|
46
|
+
renderThumb() {
|
|
47
|
+
return nothing;
|
|
48
|
+
}
|
|
46
49
|
render() {
|
|
47
50
|
return html `<label part="field">
|
|
48
51
|
<span part="track">
|
|
@@ -55,9 +58,11 @@ let HelixHeadlessSwitch = class HelixHeadlessSwitch extends MixinControllerCheck
|
|
|
55
58
|
?required=${this.required}
|
|
56
59
|
aria-describedby=${this.describedBy ?? nothing}
|
|
57
60
|
aria-invalid=${this.invalidity ?? nothing}
|
|
61
|
+
aria-readonly=${this.readOnly ? 'true' : nothing}
|
|
58
62
|
@change=${this.handleChange}
|
|
63
|
+
@click=${this.holdReadOnly}
|
|
59
64
|
@input=${this.stopInner}
|
|
60
|
-
|
|
65
|
+
/>${this.renderThumb()}
|
|
61
66
|
</span>
|
|
62
67
|
<span part="label"><slot>${this.label}</slot></span>
|
|
63
68
|
</label>
|
|
@@ -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