@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
|
@@ -17,6 +17,9 @@ let HelixHeadlessNotification = class HelixHeadlessNotification extends MixinDis
|
|
|
17
17
|
this.at = '';
|
|
18
18
|
this.defaultRead = false;
|
|
19
19
|
this.locale = '';
|
|
20
|
+
this.position = 0;
|
|
21
|
+
this.setSize = 0;
|
|
22
|
+
this.stop = true;
|
|
20
23
|
this.unreadLabel = 'Unread';
|
|
21
24
|
this.isNotification = true;
|
|
22
25
|
this.readState = undefined;
|
|
@@ -58,6 +61,8 @@ let HelixHeadlessNotification = class HelixHeadlessNotification extends MixinDis
|
|
|
58
61
|
willUpdate(changed) {
|
|
59
62
|
super.willUpdate(changed);
|
|
60
63
|
hostAria(this.internals, { role: 'listitem' });
|
|
64
|
+
this.internals.ariaPosInSet = this.position > 0 ? String(this.position) : null;
|
|
65
|
+
this.internals.ariaSetSize = this.setSize === 0 ? null : String(this.setSize);
|
|
61
66
|
this.toggleState('read', this.read);
|
|
62
67
|
}
|
|
63
68
|
updated(changed) {
|
|
@@ -105,10 +110,15 @@ let HelixHeadlessNotification = class HelixHeadlessNotification extends MixinDis
|
|
|
105
110
|
></${stamp}>`;
|
|
106
111
|
}
|
|
107
112
|
render() {
|
|
108
|
-
return html `<div
|
|
113
|
+
return html `<div
|
|
114
|
+
part="item"
|
|
115
|
+
role="group"
|
|
116
|
+
aria-labelledby="label"
|
|
117
|
+
tabindex=${this.stop ? 0 : -1}
|
|
118
|
+
>
|
|
109
119
|
<span part="media"><slot name="media"></slot></span>
|
|
110
120
|
<div part="body">
|
|
111
|
-
<div part="label">${this.read ? nothing : html `<span role="img" aria-label=${this.unreadLabel}></span>`}<slot></slot></div>
|
|
121
|
+
<div id="label" part="label">${this.read ? nothing : html `<span role="img" aria-label=${this.unreadLabel}></span>`}<slot></slot></div>
|
|
112
122
|
<slot name="description"></slot>
|
|
113
123
|
<slot name="detail"></slot>
|
|
114
124
|
<span part="actions"><slot name="actions" @slotchange=${this.handleActions}></slot></span>
|
|
@@ -152,9 +162,18 @@ __decorate([
|
|
|
152
162
|
__decorate([
|
|
153
163
|
property()
|
|
154
164
|
], HelixHeadlessNotification.prototype, "locale", void 0);
|
|
165
|
+
__decorate([
|
|
166
|
+
property({ attribute: false })
|
|
167
|
+
], HelixHeadlessNotification.prototype, "position", void 0);
|
|
155
168
|
__decorate([
|
|
156
169
|
property({ type: Boolean })
|
|
157
170
|
], HelixHeadlessNotification.prototype, "read", null);
|
|
171
|
+
__decorate([
|
|
172
|
+
property({ attribute: false })
|
|
173
|
+
], HelixHeadlessNotification.prototype, "setSize", void 0);
|
|
174
|
+
__decorate([
|
|
175
|
+
property({ attribute: false })
|
|
176
|
+
], HelixHeadlessNotification.prototype, "stop", void 0);
|
|
158
177
|
__decorate([
|
|
159
178
|
property({ attribute: 'unread-label' })
|
|
160
179
|
], HelixHeadlessNotification.prototype, "unreadLabel", void 0);
|
|
@@ -21,6 +21,14 @@ declare const HelixHeadlessNotifications_base: (new (...args: any[]) => import("
|
|
|
21
21
|
* the items and written to an attribute, so a stylesheet and a badge can both
|
|
22
22
|
* use it without counting.
|
|
23
23
|
*
|
|
24
|
+
* **The feed is one `Tab` stop for its rows.** Each row takes focus itself and
|
|
25
|
+
* is read by its label. `ArrowDown` and `ArrowUp` move to the next and the
|
|
26
|
+
* previous row, `Home` and `End` to the first and the last, and `PageDown` and
|
|
27
|
+
* `PageUp` move a row on or back from anywhere inside one, as in the APG feed
|
|
28
|
+
* pattern. The controls inside a row stay in the `Tab` order. Set `total` when
|
|
29
|
+
* the feed holds one page of a longer list, and each row says its place in the
|
|
30
|
+
* whole of it.
|
|
31
|
+
*
|
|
24
32
|
* @since 0.1.0
|
|
25
33
|
* @status stable
|
|
26
34
|
* @category feedback
|
|
@@ -67,6 +75,14 @@ export declare class HelixHeadlessNotifications extends HelixHeadlessNotificatio
|
|
|
67
75
|
* Label for the mark-all control.
|
|
68
76
|
*/
|
|
69
77
|
markAllLabel: string;
|
|
78
|
+
/**
|
|
79
|
+
* How many notifications there are in all, where the feed holds only some of
|
|
80
|
+
* them, read as each row's `aria-setsize`. `-1` says the count is unknown.
|
|
81
|
+
*
|
|
82
|
+
* Unset, the browser counts the rows it can see, which is right for a feed
|
|
83
|
+
* that holds everything.
|
|
84
|
+
*/
|
|
85
|
+
total?: number;
|
|
70
86
|
/**
|
|
71
87
|
* How many items are unread, counted from the items themselves.
|
|
72
88
|
*
|
|
@@ -158,6 +174,32 @@ export declare class HelixHeadlessNotifications extends HelixHeadlessNotificatio
|
|
|
158
174
|
*/
|
|
159
175
|
private readonly handleRead;
|
|
160
176
|
private assign;
|
|
177
|
+
/** The row `Tab` stops on, once a reader has been to one. */
|
|
178
|
+
private stopRow;
|
|
179
|
+
/**
|
|
180
|
+
* The rows a reader can reach with the keys: every row in the feed, in order,
|
|
181
|
+
* less the ones a folded group renders nowhere.
|
|
182
|
+
*/
|
|
183
|
+
private get reachable();
|
|
184
|
+
/** The row whose own box is the element focus is on, if it is one. */
|
|
185
|
+
private rowFocused;
|
|
186
|
+
/** A row taking focus becomes the feed's stop, so `Tab` comes back to it. */
|
|
187
|
+
private readonly handleFocusIn;
|
|
188
|
+
/**
|
|
189
|
+
* Moves between rows.
|
|
190
|
+
*
|
|
191
|
+
* The arrows and `Home` and `End` only from a row's own box, so a control in
|
|
192
|
+
* a row keeps its keys. `PageDown` and `PageUp` from anywhere in a row, which
|
|
193
|
+
* is how the APG feed pattern moves on from inside an article.
|
|
194
|
+
*/
|
|
195
|
+
private readonly handleKeydown;
|
|
196
|
+
/**
|
|
197
|
+
* Tells each row whether it is the stop, and where it sits in the feed.
|
|
198
|
+
*
|
|
199
|
+
* Through each row's own properties, written once it has hydrated, so a
|
|
200
|
+
* server's markup stays the server's: every row is a stop until this runs.
|
|
201
|
+
*/
|
|
202
|
+
private rove;
|
|
161
203
|
connectedCallback(): void;
|
|
162
204
|
disconnectedCallback(): void;
|
|
163
205
|
protected willUpdate(changed: PropertyValues): void;
|
|
@@ -4,9 +4,10 @@ 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, focusableElements, HelixElement, HelixReadEvent, hostAria, MixinCollection, markRegion, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, deepContains, focusableElements, HelixElement, HelixReadEvent, hostAria, MixinCollection, markRegion, rovingStop, whenHydrated, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
+
import { feedStep } from '../feed-keys.js';
|
|
10
11
|
let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinCollection(HelixElement) {
|
|
11
12
|
constructor() {
|
|
12
13
|
super(...arguments);
|
|
@@ -20,6 +21,36 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
|
|
|
20
21
|
this.handleRead = () => {
|
|
21
22
|
queueMicrotask(() => this.requestUpdate());
|
|
22
23
|
};
|
|
24
|
+
this.handleFocusIn = (event) => {
|
|
25
|
+
const row = this.rowFocused(event.composedPath()[0]);
|
|
26
|
+
if (row && row !== this.stopRow) {
|
|
27
|
+
this.stopRow = row;
|
|
28
|
+
this.rove();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
this.handleKeydown = (event) => {
|
|
32
|
+
if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const rows = this.reachable;
|
|
36
|
+
const from = event.composedPath()[0];
|
|
37
|
+
const own = this.rowFocused(from);
|
|
38
|
+
const inside = own ?? rows.find((row) => from instanceof Node && deepContains(row, from));
|
|
39
|
+
if (!inside) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const to = feedStep(event.key, rows.indexOf(inside), rows.length, own !== undefined);
|
|
43
|
+
if (to === undefined) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
const next = rows[to];
|
|
48
|
+
if (next) {
|
|
49
|
+
this.stopRow = next;
|
|
50
|
+
this.rove();
|
|
51
|
+
rowBox(next)?.focus();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
23
54
|
this.handleMarkAll = (event) => {
|
|
24
55
|
const button = event.currentTarget;
|
|
25
56
|
const focused = this.shadowRoot?.activeElement === button;
|
|
@@ -106,13 +137,36 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
|
|
|
106
137
|
slot?.assign?.(...[...this.children].filter((child) => child.getAttribute('slot') === name));
|
|
107
138
|
}
|
|
108
139
|
}
|
|
140
|
+
get reachable() {
|
|
141
|
+
return this.items.filter((row) => !('assignedSlot' in row) || row.assignedSlot !== null);
|
|
142
|
+
}
|
|
143
|
+
rowFocused(target) {
|
|
144
|
+
return this.reachable.find((row) => rowBox(row) === target);
|
|
145
|
+
}
|
|
146
|
+
rove() {
|
|
147
|
+
const rows = this.reachable;
|
|
148
|
+
const stop = rovingStop(rows, this.stopRow);
|
|
149
|
+
const direct = this.rows;
|
|
150
|
+
for (const row of this.items) {
|
|
151
|
+
const position = direct.indexOf(row) + 1;
|
|
152
|
+
whenHydrated(row, () => {
|
|
153
|
+
row.stop = row === stop;
|
|
154
|
+
row.position = this.total === undefined ? 0 : position;
|
|
155
|
+
row.setSize = this.total ?? 0;
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
109
159
|
connectedCallback() {
|
|
110
160
|
super.connectedCallback();
|
|
111
161
|
this.addEventListener('helix-read', this.handleRead);
|
|
162
|
+
this.addEventListener('focusin', this.handleFocusIn);
|
|
163
|
+
this.addEventListener('keydown', this.handleKeydown);
|
|
112
164
|
}
|
|
113
165
|
disconnectedCallback() {
|
|
114
166
|
super.disconnectedCallback();
|
|
115
167
|
this.removeEventListener('helix-read', this.handleRead);
|
|
168
|
+
this.removeEventListener('focusin', this.handleFocusIn);
|
|
169
|
+
this.removeEventListener('keydown', this.handleKeydown);
|
|
116
170
|
}
|
|
117
171
|
willUpdate(changed) {
|
|
118
172
|
super.willUpdate(changed);
|
|
@@ -130,6 +184,7 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
|
|
|
130
184
|
this.assign();
|
|
131
185
|
this.markEmpty();
|
|
132
186
|
this.markMedia();
|
|
187
|
+
this.rove();
|
|
133
188
|
const unread = this.unread > 0 ? String(this.unread) : null;
|
|
134
189
|
if (this.getAttribute('unread') !== unread) {
|
|
135
190
|
if (unread === null) {
|
|
@@ -167,7 +222,11 @@ __decorate([
|
|
|
167
222
|
__decorate([
|
|
168
223
|
property({ attribute: 'mark-all-label' })
|
|
169
224
|
], HelixHeadlessNotifications.prototype, "markAllLabel", void 0);
|
|
225
|
+
__decorate([
|
|
226
|
+
property({ type: Number })
|
|
227
|
+
], HelixHeadlessNotifications.prototype, "total", void 0);
|
|
170
228
|
HelixHeadlessNotifications = __decorate([
|
|
171
229
|
customElement('helix-headless-notifications')
|
|
172
230
|
], HelixHeadlessNotifications);
|
|
173
231
|
export { HelixHeadlessNotifications };
|
|
232
|
+
const rowBox = (row) => row.shadowRoot?.querySelector('[part="item"]') ?? null;
|
|
@@ -18,6 +18,17 @@ declare const HelixHeadlessNumberInput_base: (new (...args: any[]) => import("@f
|
|
|
18
18
|
*
|
|
19
19
|
* `inputmode="decimal"` keeps the numeric keypad on phones.
|
|
20
20
|
*
|
|
21
|
+
* `format-options` shows the number with `Intl.NumberFormat` in `locale`, as a
|
|
22
|
+
* currency, a percent or a unit, while the field is not being edited. Focus
|
|
23
|
+
* shows the number itself, and a typed `$1,200` or `25%` is read back with the
|
|
24
|
+
* same options. The value stays the plain number: `1200`, or `0.25` for 25%.
|
|
25
|
+
* The locale's group separators are read in every field, so `1,234` is a
|
|
26
|
+
* number in `en-US`.
|
|
27
|
+
*
|
|
28
|
+
* On iOS and iPadOS the field is a text field described as a number field,
|
|
29
|
+
* with no `role="spinbutton"`, which VoiceOver reads as a slider you cannot
|
|
30
|
+
* type in. React Aria's NumberField does the same.
|
|
31
|
+
*
|
|
21
32
|
* Validity follows the platform's rules: `min`, `max`, and `step` are checked
|
|
22
33
|
* and reported through the host's own `setValidity`, under the platform's flag
|
|
23
34
|
* names.
|
|
@@ -80,6 +91,16 @@ export declare class HelixHeadlessNumberInput extends HelixHeadlessNumberInput_b
|
|
|
80
91
|
* The name of the step down button, read by screen readers.
|
|
81
92
|
*/
|
|
82
93
|
decrementLabel: string;
|
|
94
|
+
/**
|
|
95
|
+
* `Intl.NumberFormat` options the number is shown with while the field is
|
|
96
|
+
* not being edited: a currency, a percent, a unit, or a number of decimals.
|
|
97
|
+
* Written as JSON in the attribute.
|
|
98
|
+
*
|
|
99
|
+
* ```html
|
|
100
|
+
* <helix-number-input format-options='{"style":"currency","currency":"EUR"}'></helix-number-input>
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
formatOptions?: Intl.NumberFormatOptions;
|
|
83
104
|
/**
|
|
84
105
|
* The name of the step up button, read by screen readers.
|
|
85
106
|
*/
|
|
@@ -133,6 +154,11 @@ export declare class HelixHeadlessNumberInput extends HelixHeadlessNumberInput_b
|
|
|
133
154
|
* Prevents editing. The value is still submitted with the form.
|
|
134
155
|
*/
|
|
135
156
|
readOnly: boolean;
|
|
157
|
+
/**
|
|
158
|
+
* What the field is described as on iOS and iPadOS, where it carries no
|
|
159
|
+
* spinbutton role. See the class description.
|
|
160
|
+
*/
|
|
161
|
+
roleDescription: string;
|
|
136
162
|
/**
|
|
137
163
|
* Makes the label a grip that changes the value when it is dragged.
|
|
138
164
|
*
|
|
@@ -163,6 +189,27 @@ export declare class HelixHeadlessNumberInput extends HelixHeadlessNumberInput_b
|
|
|
163
189
|
* number alone.
|
|
164
190
|
*/
|
|
165
191
|
valueText: string;
|
|
192
|
+
/**
|
|
193
|
+
* Whether the mouse wheel steps the number while the field has focus, as
|
|
194
|
+
* React Aria's NumberField does unless told not to. Off, the wheel scrolls
|
|
195
|
+
* the page, which is what a reader passing over a form expects.
|
|
196
|
+
*/
|
|
197
|
+
wheel: boolean;
|
|
198
|
+
/** Whether the field has focus, so it shows the number itself and not its format. */
|
|
199
|
+
private editing;
|
|
200
|
+
/**
|
|
201
|
+
* What the field shows: the value as written while it is edited, and with
|
|
202
|
+
* `format-options` once it is not.
|
|
203
|
+
*/
|
|
204
|
+
private get shown();
|
|
205
|
+
/** Steps on the wheel, where asked, while the field has focus. */
|
|
206
|
+
private readonly handleWheel;
|
|
207
|
+
private readonly handleFocus;
|
|
208
|
+
/**
|
|
209
|
+
* Whether this is an iPhone or an iPad, read once on the client. A server
|
|
210
|
+
* has no navigator and renders the spinbutton.
|
|
211
|
+
*/
|
|
212
|
+
private readonly touchApple;
|
|
166
213
|
private get control();
|
|
167
214
|
/** The value as a number, or `null` where the field holds nothing usable. */
|
|
168
215
|
private get numeric();
|
|
@@ -4,10 +4,10 @@ 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, valueAsNumber as asNumber, customElement, fillTemplate, numberAsValue as fromNumber, HelixFormElement, holdCaret, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, appleTouch, valueAsNumber as asNumber, customElement, fillTemplate, formatNumber, numberAsValue as fromNumber, HelixFormElement, holdCaret, MixinControllerValue, MixinField, parseNumber, restoreValue, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { minus, plus } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { html, nothing } from 'lit';
|
|
10
|
-
import { property } from 'lit/decorators.js';
|
|
10
|
+
import { property, state } from 'lit/decorators.js';
|
|
11
11
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
12
12
|
const SCRUB_PITCH = 4;
|
|
13
13
|
const SCRUB_FINE = 16;
|
|
@@ -24,9 +24,28 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
24
24
|
this.locale = '';
|
|
25
25
|
this.placeholder = '';
|
|
26
26
|
this.readOnly = false;
|
|
27
|
+
this.roleDescription = 'number field';
|
|
27
28
|
this.scrub = false;
|
|
28
29
|
this.step = 1;
|
|
29
30
|
this.valueText = '';
|
|
31
|
+
this.wheel = false;
|
|
32
|
+
this.editing = false;
|
|
33
|
+
this.handleWheel = (event) => {
|
|
34
|
+
if (!this.wheel || !this.editing || event.deltaY === 0) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
if (event.deltaY < 0) {
|
|
39
|
+
this.stepUp();
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this.stepDown();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
this.handleFocus = () => {
|
|
46
|
+
this.editing = true;
|
|
47
|
+
};
|
|
48
|
+
this.touchApple = appleTouch(typeof navigator === 'undefined' ? undefined : navigator);
|
|
30
49
|
this.scrubFrom = 0;
|
|
31
50
|
this.scrubValue = 0;
|
|
32
51
|
this.scrubStart = '';
|
|
@@ -77,6 +96,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
77
96
|
restoreValue(control, this.value);
|
|
78
97
|
};
|
|
79
98
|
this.handleBlur = () => {
|
|
99
|
+
this.editing = false;
|
|
80
100
|
if (this.settle()) {
|
|
81
101
|
this.announceChange();
|
|
82
102
|
}
|
|
@@ -122,6 +142,13 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
122
142
|
}
|
|
123
143
|
};
|
|
124
144
|
}
|
|
145
|
+
get shown() {
|
|
146
|
+
const parsed = this.numeric;
|
|
147
|
+
if (this.editing || this.formatOptions === undefined || parsed === null) {
|
|
148
|
+
return this.value;
|
|
149
|
+
}
|
|
150
|
+
return formatNumber(parsed, this.locale, this.formatOptions);
|
|
151
|
+
}
|
|
125
152
|
get control() {
|
|
126
153
|
return this.partNamed('control');
|
|
127
154
|
}
|
|
@@ -130,11 +157,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
130
157
|
if (text === '') {
|
|
131
158
|
return null;
|
|
132
159
|
}
|
|
133
|
-
|
|
134
|
-
? text.replace(',', '.')
|
|
135
|
-
: text;
|
|
136
|
-
const parsed = read.includes(',') ? Number.NaN : Number(read);
|
|
137
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
160
|
+
return parseNumber(text, this.locale, this.formatOptions);
|
|
138
161
|
}
|
|
139
162
|
onStep(value) {
|
|
140
163
|
const step = Math.abs(this.step) || 1;
|
|
@@ -291,9 +314,10 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
291
314
|
<input
|
|
292
315
|
part="control"
|
|
293
316
|
id=${this.controlId}
|
|
294
|
-
.value=${this.
|
|
317
|
+
.value=${this.shown}
|
|
295
318
|
type="text"
|
|
296
|
-
role
|
|
319
|
+
role=${this.touchApple ? nothing : 'spinbutton'}
|
|
320
|
+
aria-roledescription=${this.touchApple ? this.roleDescription : nothing}
|
|
297
321
|
inputmode="decimal"
|
|
298
322
|
autocomplete=${this.autocomplete || nothing}
|
|
299
323
|
name=${this.name || nothing}
|
|
@@ -303,17 +327,27 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
303
327
|
aria-valuemin=${this.min ?? nothing}
|
|
304
328
|
aria-valuemax=${this.max ?? nothing}
|
|
305
329
|
aria-valuenow=${parsed ?? nothing}
|
|
306
|
-
aria-valuetext=${
|
|
307
|
-
?
|
|
308
|
-
:
|
|
330
|
+
aria-valuetext=${parsed === null
|
|
331
|
+
? nothing
|
|
332
|
+
: this.valueText
|
|
333
|
+
? fillTemplate(this.valueText, {
|
|
334
|
+
value: this.formatOptions
|
|
335
|
+
? formatNumber(parsed, this.locale, this.formatOptions)
|
|
336
|
+
: this.value,
|
|
337
|
+
})
|
|
338
|
+
: this.formatOptions
|
|
339
|
+
? formatNumber(parsed, this.locale, this.formatOptions)
|
|
340
|
+
: nothing}
|
|
309
341
|
?disabled=${this.isDisabled}
|
|
310
342
|
?readonly=${this.readOnly}
|
|
311
343
|
?required=${this.required}
|
|
312
344
|
@blur=${this.handleBlur}
|
|
313
345
|
@change=${this.handleChange}
|
|
346
|
+
@focus=${this.handleFocus}
|
|
314
347
|
@input=${this.handleInput}
|
|
315
348
|
@keydown=${this.handleKeydown}
|
|
316
349
|
@keypress=${this.handleKeypress}
|
|
350
|
+
@wheel=${this.handleWheel}
|
|
317
351
|
/>
|
|
318
352
|
<slot name="end"></slot>
|
|
319
353
|
<button
|
|
@@ -347,6 +381,9 @@ __decorate([
|
|
|
347
381
|
__decorate([
|
|
348
382
|
property({ attribute: 'decrement-label' })
|
|
349
383
|
], HelixHeadlessNumberInput.prototype, "decrementLabel", void 0);
|
|
384
|
+
__decorate([
|
|
385
|
+
property({ attribute: 'format-options', type: Object })
|
|
386
|
+
], HelixHeadlessNumberInput.prototype, "formatOptions", void 0);
|
|
350
387
|
__decorate([
|
|
351
388
|
property({ attribute: 'increment-label' })
|
|
352
389
|
], HelixHeadlessNumberInput.prototype, "incrementLabel", void 0);
|
|
@@ -374,6 +411,9 @@ __decorate([
|
|
|
374
411
|
__decorate([
|
|
375
412
|
property({ attribute: 'readonly', reflect: true, type: Boolean })
|
|
376
413
|
], HelixHeadlessNumberInput.prototype, "readOnly", void 0);
|
|
414
|
+
__decorate([
|
|
415
|
+
property({ attribute: 'role-description' })
|
|
416
|
+
], HelixHeadlessNumberInput.prototype, "roleDescription", void 0);
|
|
377
417
|
__decorate([
|
|
378
418
|
property({ reflect: true, type: Boolean })
|
|
379
419
|
], HelixHeadlessNumberInput.prototype, "scrub", void 0);
|
|
@@ -386,20 +426,16 @@ __decorate([
|
|
|
386
426
|
__decorate([
|
|
387
427
|
property({ attribute: 'value-text' })
|
|
388
428
|
], HelixHeadlessNumberInput.prototype, "valueText", void 0);
|
|
429
|
+
__decorate([
|
|
430
|
+
property({ type: Boolean })
|
|
431
|
+
], HelixHeadlessNumberInput.prototype, "wheel", void 0);
|
|
432
|
+
__decorate([
|
|
433
|
+
state()
|
|
434
|
+
], HelixHeadlessNumberInput.prototype, "editing", void 0);
|
|
389
435
|
HelixHeadlessNumberInput = __decorate([
|
|
390
436
|
customElement('helix-headless-number-input')
|
|
391
437
|
], HelixHeadlessNumberInput);
|
|
392
438
|
export { HelixHeadlessNumberInput };
|
|
393
|
-
const commas = new Map();
|
|
394
|
-
const decimalComma = (locale) => {
|
|
395
|
-
let comma = commas.get(locale);
|
|
396
|
-
if (comma === undefined) {
|
|
397
|
-
const parts = new Intl.NumberFormat(locale || undefined).formatToParts(1.5);
|
|
398
|
-
comma = parts.find((part) => part.type === 'decimal')?.value === ',';
|
|
399
|
-
commas.set(locale, comma);
|
|
400
|
-
}
|
|
401
|
-
return comma;
|
|
402
|
-
};
|
|
403
439
|
const decimals = (value) => {
|
|
404
440
|
const text = String(value);
|
|
405
441
|
const exponent = /e-(\d+)$/.exec(text);
|
|
@@ -60,6 +60,7 @@ interface Row {
|
|
|
60
60
|
* @csspart boolean - A `true` or `false`.
|
|
61
61
|
* @csspart copy - The copy button, which copies the active row.
|
|
62
62
|
* @csspart copy-button - The button inside the copy control.
|
|
63
|
+
* @csspart copy-live - The live region inside the copy button, which says its `pending-label` when the copy becomes pending under focus.
|
|
63
64
|
* @csspart copy-mark - The clipboard icon, and the confirmation icon that replaces it.
|
|
64
65
|
* @csspart copy-text - The words on that button, trimmed to their capitals and baseline.
|
|
65
66
|
* @csspart copy-tooltip - The tooltip, forwarded from the copy button's tooltip.
|
|
@@ -353,7 +353,7 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
353
353
|
renderCopyButton(row) {
|
|
354
354
|
return staticHtml `<${this.tag('copy-button')}
|
|
355
355
|
part="copy"
|
|
356
|
-
exportparts="button: copy-button, text: copy-text, mark: copy-mark, tooltip: copy-tooltip,
|
|
356
|
+
exportparts="button: copy-button, live: copy-live, text: copy-text, mark: copy-mark, tooltip: copy-tooltip,
|
|
357
357
|
tooltip-arrow: copy-tooltip-arrow, tooltip-arrow-bottom: copy-tooltip-arrow-bottom,
|
|
358
358
|
tooltip-arrow-left: copy-tooltip-arrow-left, tooltip-arrow-right: copy-tooltip-arrow-right,
|
|
359
359
|
tooltip-arrow-top: copy-tooltip-arrow-top, tooltip-bottom: copy-tooltip-bottom,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HelixElement } from '@fusion.dev/helix-core';
|
|
1
|
+
import { HelixElement, type LinkModifiers } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
/**
|
|
4
4
|
* The options among some elements, reaching one level into a group.
|
|
@@ -34,6 +34,9 @@ export declare const optionsAmong: (elements: readonly Element[]) => HelixHeadle
|
|
|
34
34
|
* Filtering belongs to the owner, which hides an option with `hidden`. What
|
|
35
35
|
* counts as a match differs between a select and a command palette.
|
|
36
36
|
*
|
|
37
|
+
* An option with `href` is a link: choosing it follows the link and selects
|
|
38
|
+
* nothing, as an entry in a command palette that goes to a page does.
|
|
39
|
+
*
|
|
37
40
|
* @since 0.1.0
|
|
38
41
|
* @status stable
|
|
39
42
|
* @category forms
|
|
@@ -44,7 +47,7 @@ export declare const optionsAmong: (elements: readonly Element[]) => HelixHeadle
|
|
|
44
47
|
* @slot end - Content after the label, such as a shortcut or a count.
|
|
45
48
|
* @slot start - Content before the label, such as an icon or an avatar.
|
|
46
49
|
*
|
|
47
|
-
* @event {HelixSelectEvent} helix-select - The option was chosen. Cancelable: canceling it leaves the selection as it was
|
|
50
|
+
* @event {HelixSelectEvent} helix-select - The option was chosen. Cancelable: canceling it leaves the selection as it was, and keeps the browser from following an option's `href`.
|
|
48
51
|
*
|
|
49
52
|
* @csspart description - The description under the label, when there is one.
|
|
50
53
|
* @csspart item - The row.
|
|
@@ -148,6 +151,28 @@ export declare class HelixHeadlessOption extends HelixElement {
|
|
|
148
151
|
* Prevents the option from being chosen.
|
|
149
152
|
*/
|
|
150
153
|
disabled: boolean;
|
|
154
|
+
/**
|
|
155
|
+
* Whether following the link downloads what it names. Only meaningful
|
|
156
|
+
* beside an `href`.
|
|
157
|
+
*/
|
|
158
|
+
download: boolean;
|
|
159
|
+
/**
|
|
160
|
+
* The URL the option links to. Setting it makes the option a link: choosing
|
|
161
|
+
* it, with a press, Enter or a click, follows the link and selects nothing,
|
|
162
|
+
* as React Aria's items with `href` do. Command, Control and Shift open it
|
|
163
|
+
* where they open a link, in a new tab or a new window.
|
|
164
|
+
*
|
|
165
|
+
* `helix-select` is said first with the `href` in it, and canceling it keeps
|
|
166
|
+
* the browser from following, so a client-side router follows it instead.
|
|
167
|
+
*
|
|
168
|
+
* **The option stays an option**, and an anchor is never drawn inside it:
|
|
169
|
+
* `role="option"` sits on the host, where a listbox's
|
|
170
|
+
* `aria-activedescendant` can name it, and an `<a>` inside would be exposed
|
|
171
|
+
* as a link within the option and take its name (Menu Item's `href` records
|
|
172
|
+
* the measurement). The link is followed through an anchor made for the
|
|
173
|
+
* moment, which `followLink` describes.
|
|
174
|
+
*/
|
|
175
|
+
href: string;
|
|
151
176
|
/**
|
|
152
177
|
* A shorter name for this choice, for where the row does not fit.
|
|
153
178
|
*
|
|
@@ -161,12 +186,30 @@ export declare class HelixHeadlessOption extends HelixElement {
|
|
|
161
186
|
* nothing for every choice.
|
|
162
187
|
*/
|
|
163
188
|
label: string;
|
|
189
|
+
/**
|
|
190
|
+
* The link's `rel`. Set it whenever you set `target="_blank"`.
|
|
191
|
+
*/
|
|
192
|
+
rel: string;
|
|
164
193
|
/**
|
|
165
194
|
* Whether this choice is currently chosen.
|
|
166
195
|
*
|
|
167
196
|
* Written by the listbox.
|
|
168
197
|
*/
|
|
169
198
|
selected: boolean;
|
|
199
|
+
/**
|
|
200
|
+
* Where the link opens, such as `_blank`, for an option with an `href`.
|
|
201
|
+
*/
|
|
202
|
+
target: string;
|
|
203
|
+
/**
|
|
204
|
+
* The words a reader types to reach this choice, where the row's own words
|
|
205
|
+
* are not them: typeahead, a filter and a combobox match against it, and a
|
|
206
|
+
* select's trigger shows it.
|
|
207
|
+
*
|
|
208
|
+
* For a row whose content is a picture, an avatar beside a name and a role,
|
|
209
|
+
* or a name written in another script, as React Aria's `textValue`. Empty
|
|
210
|
+
* reads the row's words, then `label`.
|
|
211
|
+
*/
|
|
212
|
+
textValue: string;
|
|
170
213
|
/**
|
|
171
214
|
* The value that identifies the option, and that a form submits.
|
|
172
215
|
*/
|
|
@@ -210,11 +253,17 @@ export declare class HelixHeadlessOption extends HelixElement {
|
|
|
210
253
|
* it is in every comparison too.
|
|
211
254
|
*
|
|
212
255
|
* **The `label` where the slot holds nothing**, which is what the row shows
|
|
213
|
-
* then, so the six read the words a reader sees.
|
|
256
|
+
* then, so the six read the words a reader sees. `text-value` wins over both,
|
|
257
|
+
* being the consumer saying outright what the words are.
|
|
214
258
|
*/
|
|
215
259
|
get text(): string;
|
|
216
|
-
/**
|
|
217
|
-
|
|
260
|
+
/**
|
|
261
|
+
* Sends `helix-select` for this option. Does nothing when it is disabled.
|
|
262
|
+
*
|
|
263
|
+
* An option with an `href` then follows its link, unless the event was
|
|
264
|
+
* canceled, with the keys `modifiers` names held.
|
|
265
|
+
*/
|
|
266
|
+
select(modifiers?: LinkModifiers): void;
|
|
218
267
|
/**
|
|
219
268
|
* Mirrors the chosen state where a stylesheet can select on it.
|
|
220
269
|
*
|