@fusion.dev/helix-headless 0.146.0 → 0.147.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 +5266 -785
- package/dist/accordion/item/accordion-item.d.ts +38 -19
- package/dist/accordion/item/accordion-item.js +31 -9
- package/dist/accordion/root/accordion-root.d.ts +8 -2
- package/dist/accordion/root/accordion-root.js +3 -3
- package/dist/announcement/root/announcement-root.d.ts +13 -4
- package/dist/announcement/root/announcement-root.js +34 -6
- package/dist/area-chart/root/area-chart-root.d.ts +18 -1
- package/dist/area-chart/root/area-chart-root.js +11 -3
- package/dist/avatar/root/avatar-root.d.ts +31 -1
- package/dist/avatar/root/avatar-root.js +11 -1
- package/dist/badge/root/badge-root.d.ts +57 -6
- package/dist/badge/root/badge-root.js +88 -5
- package/dist/bar-chart/root/bar-chart-root.js +11 -20
- package/dist/bar-chart/stack.d.ts +10 -0
- package/dist/bar-chart/stack.js +8 -0
- package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +14 -0
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +12 -2
- package/dist/breadcrumbs/root/breadcrumbs-root.js +2 -2
- package/dist/button/root/button-root.d.ts +24 -38
- package/dist/button/root/button-root.js +6 -37
- package/dist/button/submitter.d.ts +27 -0
- package/dist/button/submitter.js +25 -0
- package/dist/card/root/card-root.d.ts +12 -1
- package/dist/card/root/card-root.js +11 -4
- package/dist/chat/root/chat-root.d.ts +15 -1
- package/dist/chat/root/chat-root.js +11 -2
- package/dist/checkbox/root/checkbox-root.js +5 -7
- package/dist/checkbox-group/root/checkbox-group-root.js +4 -3
- package/dist/checkbox-group/select-all.d.ts +0 -6
- package/dist/checkbox-group/select-all.js +0 -5
- package/dist/code-block/root/code-block-root.d.ts +35 -14
- package/dist/code-block/root/code-block-root.js +17 -3
- package/dist/color-input/root/color-input-root.d.ts +11 -0
- package/dist/color-input/root/color-input-root.js +12 -5
- package/dist/color-picker/channels.js +1 -2
- package/dist/color-picker/root/color-picker-root.d.ts +32 -24
- package/dist/color-picker/root/color-picker-root.js +101 -51
- package/dist/color-picker/wheel.d.ts +17 -0
- package/dist/color-picker/wheel.js +6 -0
- package/dist/combobox/root/combobox-root.d.ts +13 -0
- package/dist/combobox/root/combobox-root.js +14 -1
- package/dist/command/root/command-root.d.ts +3 -1
- package/dist/command/root/command-root.js +2 -19
- package/dist/copy-button/root/copy-button-root.d.ts +16 -1
- package/dist/copy-button/root/copy-button-root.js +7 -2
- package/dist/data-table/keys.d.ts +0 -18
- package/dist/data-table/keys.js +1 -11
- package/dist/data-table/root/data-table-root.js +13 -7
- package/dist/date-input/root/date-input-root.d.ts +8 -1
- package/dist/date-input/root/date-input-root.js +8 -5
- package/dist/date-picker/root/date-picker-root.d.ts +14 -9
- package/dist/date-picker/root/date-picker-root.js +21 -16
- package/dist/description-list/item/description-list-item.d.ts +18 -4
- package/dist/description-list/item/description-list-item.js +8 -4
- package/dist/donut-chart/root/donut-chart-root.js +13 -6
- package/dist/donut-chart/slice-label.d.ts +35 -0
- package/dist/donut-chart/slice-label.js +11 -0
- package/dist/drawer/root/drawer-root.d.ts +4 -2
- package/dist/drawer/root/drawer-root.js +15 -3
- package/dist/drilldown/item/drilldown-item.d.ts +21 -1
- package/dist/drilldown/item/drilldown-item.js +39 -4
- package/dist/drilldown/root/drilldown-root.js +3 -2
- package/dist/element-events.generated.js +4 -1
- package/dist/empty/root/empty-root.d.ts +31 -1
- package/dist/empty/root/empty-root.js +26 -5
- package/dist/file-input/root/file-input-root.d.ts +34 -6
- package/dist/file-input/root/file-input-root.js +54 -19
- package/dist/file-input/status.d.ts +24 -0
- package/dist/file-input/status.js +10 -0
- package/dist/filter-input/chip/filter-chip.d.ts +23 -0
- package/dist/filter-input/chip/filter-chip.js +11 -2
- package/dist/filter-input/root/filter-input-root.d.ts +8 -0
- package/dist/filter-input/root/filter-input-root.js +17 -27
- package/dist/format-date/options.d.ts +3 -4
- package/dist/format-date/options.js +2 -2
- package/dist/format-date/root/format-date-root.d.ts +18 -1
- package/dist/format-date/root/format-date-root.js +19 -23
- package/dist/heatmap/root/buckets.d.ts +21 -0
- package/dist/heatmap/root/buckets.js +34 -0
- package/dist/heatmap/root/heatmap-root.d.ts +64 -3
- package/dist/heatmap/root/heatmap-root.js +89 -19
- package/dist/icon/index.d.ts +1 -1
- package/dist/icon/index.js +1 -1
- package/dist/icon/registry.d.ts +26 -1
- package/dist/icon/registry.js +12 -1
- package/dist/icon/root/icon-root.d.ts +13 -0
- package/dist/icon/root/icon-root.js +23 -2
- package/dist/icon/root/index.d.ts +1 -1
- package/dist/icon/root/index.js +1 -1
- package/dist/image/root/image-root.d.ts +9 -0
- package/dist/image/root/image-root.js +6 -1
- package/dist/input/root/input-root.d.ts +23 -2
- package/dist/input/root/input-root.js +12 -8
- package/dist/kbd/keys.d.ts +29 -0
- package/dist/kbd/keys.js +52 -0
- package/dist/kbd/root/kbd-root.d.ts +20 -3
- package/dist/kbd/root/kbd-root.js +24 -50
- package/dist/legend/hidden-series.d.ts +10 -2
- package/dist/legend/hidden-series.js +5 -2
- package/dist/legend/root/legend-root.d.ts +25 -7
- package/dist/legend/root/legend-root.js +22 -10
- package/dist/lightbox/root/lightbox-root.d.ts +50 -5
- package/dist/lightbox/root/lightbox-root.js +76 -8
- package/dist/lightbox/zoom.d.ts +2 -0
- package/dist/lightbox/zoom.js +5 -3
- package/dist/line-chart/root/line-chart-root.d.ts +16 -0
- package/dist/line-chart/root/line-chart-root.js +10 -2
- package/dist/list/root/list-root.d.ts +10 -2
- package/dist/list/root/list-root.js +26 -5
- package/dist/list/selection.d.ts +17 -0
- package/dist/list/selection.js +16 -0
- package/dist/listbox/root/listbox-root.d.ts +9 -5
- package/dist/listbox/root/listbox-root.js +29 -37
- package/dist/megamenu/hand-over.d.ts +75 -0
- package/dist/megamenu/hand-over.js +67 -0
- package/dist/megamenu/root/megamenu-root.d.ts +38 -14
- package/dist/megamenu/root/megamenu-root.js +36 -50
- package/dist/menu/item/menu-item.js +4 -4
- package/dist/menu/root/menu-root.d.ts +3 -0
- package/dist/meter/root/meter-root.d.ts +42 -0
- package/dist/meter/root/meter-root.js +33 -7
- package/dist/notifications/root/notifications-root.d.ts +10 -1
- package/dist/notifications/root/notifications-root.js +11 -1
- package/dist/number-input/grain.d.ts +28 -0
- package/dist/number-input/grain.js +14 -0
- package/dist/number-input/root/number-input-root.d.ts +17 -1
- package/dist/number-input/root/number-input-root.js +29 -18
- package/dist/object-inspector/root/object-inspector-root.d.ts +13 -6
- package/dist/object-inspector/root/object-inspector-root.js +18 -17
- package/dist/option/index.d.ts +1 -0
- package/dist/option/index.js +1 -0
- package/dist/option/separator/option-separator.d.ts +30 -0
- package/dist/option/separator/option-separator.js +21 -0
- package/dist/outline/root/outline-root.d.ts +12 -0
- package/dist/outline/root/outline-root.js +5 -19
- package/dist/pagination/size/pagination-size.d.ts +5 -0
- package/dist/pagination/size/pagination-size.js +4 -2
- package/dist/pin-input/code.d.ts +28 -1
- package/dist/pin-input/code.js +12 -0
- package/dist/pin-input/root/pin-input-root.d.ts +98 -121
- package/dist/pin-input/root/pin-input-root.js +157 -148
- package/dist/popover/hide-outside.js +2 -9
- package/dist/popover/root/popover-root.d.ts +7 -1
- package/dist/popover/root/popover-root.js +9 -1
- package/dist/progress/root/progress-root.d.ts +27 -0
- package/dist/progress/root/progress-root.js +25 -7
- package/dist/qr-code/export.d.ts +19 -0
- package/dist/qr-code/export.js +14 -0
- package/dist/qr-code/name.d.ts +11 -0
- package/dist/qr-code/name.js +7 -0
- package/dist/qr-code/root/qr-code-root.d.ts +17 -6
- package/dist/qr-code/root/qr-code-root.js +10 -12
- package/dist/radio/group/radio-group.d.ts +15 -0
- package/dist/radio/root/radio-root.js +2 -2
- package/dist/rating/root/rating-root.d.ts +22 -9
- package/dist/rating/root/rating-root.js +15 -39
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +30 -0
- package/dist/scatter-chart/root/scatter-chart-root.js +34 -7
- package/dist/scroll-area/scrollbar.d.ts +0 -8
- package/dist/scroll-area/scrollbar.js +1 -1
- package/dist/select/align.d.ts +47 -0
- package/dist/select/align.js +7 -0
- package/dist/select/root/select-root.d.ts +59 -3
- package/dist/select/root/select-root.js +72 -12
- package/dist/slider/root/slider-root.d.ts +18 -1
- package/dist/slider/root/slider-root.js +22 -0
- package/dist/sparkline/readings.d.ts +30 -12
- package/dist/sparkline/readings.js +32 -15
- package/dist/sparkline/root/sparkline-root.d.ts +46 -3
- package/dist/sparkline/root/sparkline-root.js +60 -21
- package/dist/speed-dial/item/speed-dial-item.d.ts +1 -1
- package/dist/speed-dial/item/speed-dial-item.js +2 -2
- package/dist/speed-dial/root/speed-dial-root.d.ts +6 -0
- package/dist/speed-dial/root/speed-dial-root.js +9 -1
- package/dist/splitter/root/splitter-root.d.ts +3 -0
- package/dist/splitter/root/splitter-root.js +2 -0
- package/dist/steps/root/steps-root.d.ts +8 -1
- package/dist/steps/root/steps-root.js +6 -1
- package/dist/steps/step/step.d.ts +1 -0
- package/dist/steps/step/step.js +1 -1
- package/dist/table/column/table-column.d.ts +6 -0
- package/dist/table/column/table-column.js +5 -1
- package/dist/table/root/table-root.js +13 -6
- package/dist/table/row/table-row.d.ts +24 -0
- package/dist/table/row/table-row.js +37 -1
- package/dist/tabs/root/tabs-root.d.ts +5 -3
- package/dist/tag/group/tag-group.d.ts +16 -4
- package/dist/tag/group/tag-group.js +19 -7
- package/dist/textarea/root/textarea-root.d.ts +14 -2
- package/dist/textarea/root/textarea-root.js +6 -7
- package/dist/time-input/root/time-input-root.d.ts +5 -1
- package/dist/time-input/root/time-input-root.js +10 -7
- package/dist/time-picker/root/time-picker-root.d.ts +11 -14
- package/dist/time-picker/root/time-picker-root.js +15 -23
- package/dist/toast/item/toast-item.d.ts +3 -3
- package/dist/toast/item/toast-item.js +0 -1
- package/dist/toast/root/toast-root.d.ts +28 -4
- package/dist/toast/root/toast-root.js +58 -12
- package/dist/toast/words.d.ts +12 -0
- package/dist/toast/words.js +25 -0
- package/dist/toggle/group/toggle-group.d.ts +29 -5
- package/dist/toggle/group/toggle-group.js +26 -41
- package/dist/toggle/root/toggle-root.js +2 -4
- package/dist/toolbar/root/toolbar-root.d.ts +21 -5
- package/dist/toolbar/root/toolbar-root.js +52 -8
- package/dist/tooltip/root/tooltip-root.d.ts +7 -1
- package/dist/tooltip/root/tooltip-root.js +10 -1
- package/dist/tour/root/tour-root.d.ts +15 -0
- package/dist/tour/root/tour-root.js +20 -1
- package/dist/tour/stop/tour-stop.d.ts +3 -0
- package/dist/tour/stop/tour-stop.js +3 -3
- package/dist/tree/root/tree-root.js +2 -2
- package/dist/trend/figure.d.ts +16 -0
- package/dist/trend/figure.js +8 -0
- package/dist/trend/root/trend-root.d.ts +41 -2
- package/dist/trend/root/trend-root.js +29 -3
- package/dist/video/root/extra-controls.d.ts +12 -0
- package/dist/video/root/extra-controls.js +6 -2
- package/dist/video/root/video-root.d.ts +5 -1
- package/dist/video-playlist/root/video-playlist-root.d.ts +11 -1
- package/dist/video-playlist/root/video-playlist-root.js +3 -0
- package/dist/virtual-list/fill.d.ts +11 -0
- package/dist/virtual-list/fill.js +9 -0
- package/dist/virtual-list/keys.d.ts +16 -7
- package/dist/virtual-list/keys.js +17 -6
- package/dist/virtual-list/plan.d.ts +17 -1
- package/dist/virtual-list/plan.js +13 -2
- package/dist/virtual-list/root/virtual-list-root.d.ts +25 -3
- package/dist/virtual-list/root/virtual-list-root.js +48 -24
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +2979 -738
- package/types/svelte.d.ts +1 -0
- package/types/vue.d.ts +619 -202
- package/dist/color-picker/swatches.d.ts +0 -12
- package/dist/color-picker/swatches.js +0 -26
- package/dist/rating/steps.d.ts +0 -7
- package/dist/rating/steps.js +0 -9
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
|
-
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
2
|
+
import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
import type { HelixHeadlessNotificationGroup } from '../group/notification-group.js';
|
|
4
4
|
import type { HelixHeadlessNotification } from '../notification/notification.js';
|
|
5
5
|
declare const HelixHeadlessNotifications_base: (new (...args: any[]) => import("@fusion.dev/helix-core").CollectionElement) & typeof HelixElement;
|
|
@@ -42,8 +42,10 @@ declare const HelixHeadlessNotifications_base: (new (...args: any[]) => import("
|
|
|
42
42
|
* @documentation https://fusion.dev/helix/components/notifications
|
|
43
43
|
*
|
|
44
44
|
* @slot - The notifications.
|
|
45
|
+
* @slot empty - Replaces the words of `empty-text` in the `empty` part, such as a picture and a line of your own. The live region still says `empty-text`.
|
|
45
46
|
* @slot footer - Below the list, for a link to everything.
|
|
46
47
|
* @slot header - Above the list, for a title and the mark-all control.
|
|
48
|
+
* @slot loading - Replaces the words of `loading-text` in the `loading` part, such as a loader. The live region still says `loading-text`.
|
|
47
49
|
*
|
|
48
50
|
* @event {HelixDismissEvent} helix-dismiss - Fired when the user dismisses a row. The row dispatches it, and you can listen for it on the feed. Cancelable: cancel it to keep the row.
|
|
49
51
|
* @event {HelixLoadMoreEvent} helix-load-more - Fired when a reader presses the `load-more` button, asking for the next page of the feed.
|
|
@@ -58,6 +60,8 @@ declare const HelixHeadlessNotifications_base: (new (...args: any[]) => import("
|
|
|
58
60
|
* @csspart mark-all - The control that marks everything read.
|
|
59
61
|
* @csspart more - The button after the list that asks for more, while `load-more` is set. It is `aria-disabled` while the feed is loading.
|
|
60
62
|
*
|
|
63
|
+
* @cssstate empty - While the feed holds no notification and is not loading. Never on the server, which cannot count the rows.
|
|
64
|
+
* @cssstate loading - While `loading` is set.
|
|
61
65
|
* @cssstate media - While a notification in the list holds something in its media slot, so every row keeps that column.
|
|
62
66
|
*/
|
|
63
67
|
export declare class HelixHeadlessNotifications extends HelixHeadlessNotifications_base {
|
|
@@ -220,6 +224,11 @@ export declare class HelixHeadlessNotifications extends HelixHeadlessNotificatio
|
|
|
220
224
|
connectedCallback(): void;
|
|
221
225
|
disconnectedCallback(): void;
|
|
222
226
|
protected willUpdate(changed: PropertyValues): void;
|
|
227
|
+
/**
|
|
228
|
+
* The empty or the loading line, each around a slot of the same name whose
|
|
229
|
+
* fallback is the words, so a page can put its own in.
|
|
230
|
+
*/
|
|
231
|
+
protected renderStatus(hasContent: boolean): TemplateResult | typeof nothing;
|
|
223
232
|
/**
|
|
224
233
|
* Says whether anything in the feed has media, so every item can hold the
|
|
225
234
|
* column open whether or not it has one of its own.
|
|
@@ -139,7 +139,7 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
|
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
141
|
list.assign(...this.rows);
|
|
142
|
-
for (const name of ['header', 'footer']) {
|
|
142
|
+
for (const name of ['header', 'footer', 'empty', 'loading']) {
|
|
143
143
|
const slot = root?.querySelector?.(`slot[name="${name}"]`);
|
|
144
144
|
slot?.assign?.(...[...this.children].filter((child) => child.getAttribute('slot') === name));
|
|
145
145
|
}
|
|
@@ -178,6 +178,16 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
|
|
|
178
178
|
willUpdate(changed) {
|
|
179
179
|
super.willUpdate(changed);
|
|
180
180
|
hostAria(this.internals, { label: this.label || 'Notifications', role: 'region' });
|
|
181
|
+
this.toggleState('loading', this.loading);
|
|
182
|
+
this.toggleState('empty', !this.loading && this.childrenKnown && this.items.length === 0);
|
|
183
|
+
}
|
|
184
|
+
renderStatus(hasContent) {
|
|
185
|
+
if (!this.loading && hasContent) {
|
|
186
|
+
return nothing;
|
|
187
|
+
}
|
|
188
|
+
return this.loading
|
|
189
|
+
? html `<p part="loading"><slot name="loading">${this.loadingText}</slot></p>`
|
|
190
|
+
: html `<p part="empty"><slot name="empty">${this.emptyText}</slot></p>`;
|
|
181
191
|
}
|
|
182
192
|
markMedia() {
|
|
183
193
|
this.toggleState('media', this.items.some((item) => item.querySelector(':scope > [slot="media"]') !== null));
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The steps a number field takes when `step` is not set, read off its format.
|
|
3
|
+
*
|
|
4
|
+
* React Aria's NumberField does not round a typed number to whole steps when
|
|
5
|
+
* no step is given: it keeps the fraction the format shows. A field showing
|
|
6
|
+
* dollars keeps cents, and one showing a percent steps by one percent.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* The smallest amount a format shows, which is the grid a typed number is
|
|
10
|
+
* rounded to when no `step` is set: `0.01` for a currency in dollars, `0.001`
|
|
11
|
+
* for a plain decimal, and `0.01` for a whole percent, since a percent shows
|
|
12
|
+
* the number a hundred times over.
|
|
13
|
+
*/
|
|
14
|
+
export declare const formatGrain: (locale: string, options: Intl.NumberFormatOptions) => number;
|
|
15
|
+
/**
|
|
16
|
+
* How far one press moves when no `step` is set: one percent for a percent,
|
|
17
|
+
* as React Aria does, and one otherwise.
|
|
18
|
+
*/
|
|
19
|
+
export declare const strideOf: (options: Intl.NumberFormatOptions | undefined) => number;
|
|
20
|
+
/**
|
|
21
|
+
* How many decimal places a number is written with.
|
|
22
|
+
*
|
|
23
|
+
* Read off the string rather than computed, because the question is about how
|
|
24
|
+
* the consumer wrote the step and not about what the binary can represent.
|
|
25
|
+
* `1e-7` is handled separately: its string form has no dot at all, so counting
|
|
26
|
+
* after one would say zero and round every result to a whole number.
|
|
27
|
+
*/
|
|
28
|
+
export declare const decimals: (value: number) => number;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const formatGrain = (locale, options) => {
|
|
2
|
+
const { maximumFractionDigits = 0 } = new Intl.NumberFormat(locale || undefined, options).resolvedOptions();
|
|
3
|
+
const places = maximumFractionDigits + (options.style === 'percent' ? 2 : 0);
|
|
4
|
+
return Number(`1e-${places}`);
|
|
5
|
+
};
|
|
6
|
+
export const strideOf = (options) => options?.style === 'percent' ? 0.01 : 1;
|
|
7
|
+
export const decimals = (value) => {
|
|
8
|
+
const text = String(value);
|
|
9
|
+
const exponent = /e-(\d+)$/.exec(text);
|
|
10
|
+
if (exponent) {
|
|
11
|
+
return Number(exponent[1]);
|
|
12
|
+
}
|
|
13
|
+
return (text.split('.')[1] ?? '').length;
|
|
14
|
+
};
|
|
@@ -77,6 +77,7 @@ declare const HelixHeadlessNumberInput_base: (new (...args: any[]) => import("@f
|
|
|
77
77
|
* @csspart label - The label above the field. It is also the grip you drag when `scrub` is set.
|
|
78
78
|
*
|
|
79
79
|
* @cssstate invalid - The control has an error to show, from the browser's validation or from your `feedback`.
|
|
80
|
+
* @cssstate scrubbing - The label is being dragged to change the value, under `scrub`, as Zag's scrubber says while it is held.
|
|
80
81
|
*/
|
|
81
82
|
export declare class HelixHeadlessNumberInput extends HelixHeadlessNumberInput_base {
|
|
82
83
|
protected readonly aria: AriaForwardController;
|
|
@@ -182,8 +183,14 @@ export declare class HelixHeadlessNumberInput extends HelixHeadlessNumberInput_b
|
|
|
182
183
|
/**
|
|
183
184
|
* How far one step moves. A value off the step grid, counted from `min`, is
|
|
184
185
|
* invalid, as it is in a native number field.
|
|
186
|
+
*
|
|
187
|
+
* Unset, a step moves by one, or by one percent under a percent format, and
|
|
188
|
+
* a typed number is rounded to the smallest amount `format-options` shows
|
|
189
|
+
* rather than to whole steps, as React Aria's NumberField does: a field
|
|
190
|
+
* showing dollars keeps the cents typed into it. Without `format-options`
|
|
191
|
+
* the grid is whole numbers, as in a native number field.
|
|
185
192
|
*/
|
|
186
|
-
step
|
|
193
|
+
step?: number;
|
|
187
194
|
/**
|
|
188
195
|
* The message the browser shows when the number is off the step grid, with
|
|
189
196
|
* `{below}` and `{above}` filled in with the nearest valid values.
|
|
@@ -222,6 +229,15 @@ export declare class HelixHeadlessNumberInput extends HelixHeadlessNumberInput_b
|
|
|
222
229
|
private get control();
|
|
223
230
|
/** The value as a number, or `null` where the field holds nothing usable. */
|
|
224
231
|
private get numeric();
|
|
232
|
+
/** The grain last read off the format, with the locale and options it was read for. */
|
|
233
|
+
private grainOf?;
|
|
234
|
+
/** How far one press moves: `step`, or the stride the format implies. */
|
|
235
|
+
private get stride();
|
|
236
|
+
/**
|
|
237
|
+
* The grid a typed number is rounded to: `step` where it is set, and
|
|
238
|
+
* otherwise the smallest amount the format shows, or whole numbers.
|
|
239
|
+
*/
|
|
240
|
+
private get grid();
|
|
225
241
|
/** Whether `value` is on the step grid, counted from `min`. */
|
|
226
242
|
private onStep;
|
|
227
243
|
/**
|
|
@@ -9,6 +9,7 @@ import { minus, plus } from '@fusion.dev/helix-icons';
|
|
|
9
9
|
import { html, nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
11
11
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
12
|
+
import { decimals, formatGrain, strideOf } from '../grain.js';
|
|
12
13
|
const SCRUB_PITCH = 4;
|
|
13
14
|
const SCRUB_FINE = 16;
|
|
14
15
|
let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinControllerValue(MixinField(HelixFormElement)) {
|
|
@@ -25,7 +26,6 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
25
26
|
this.placeholder = '';
|
|
26
27
|
this.readOnly = false;
|
|
27
28
|
this.scrub = false;
|
|
28
|
-
this.step = 1;
|
|
29
29
|
this.valueText = '';
|
|
30
30
|
this.wheel = false;
|
|
31
31
|
this.editing = false;
|
|
@@ -57,6 +57,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
57
57
|
this.scrubFrom = event.clientX;
|
|
58
58
|
this.scrubValue = this.numeric ?? this.min ?? 0;
|
|
59
59
|
this.scrubStart = this.value;
|
|
60
|
+
this.toggleState('scrubbing', true);
|
|
60
61
|
event.preventDefault();
|
|
61
62
|
};
|
|
62
63
|
this.handleScrubMove = (event) => {
|
|
@@ -64,7 +65,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
64
65
|
if (!grip.hasPointerCapture(event.pointerId)) {
|
|
65
66
|
return;
|
|
66
67
|
}
|
|
67
|
-
const step =
|
|
68
|
+
const step = this.stride;
|
|
68
69
|
const unit = event.shiftKey ? (this.largeStep ?? 10) * step : step;
|
|
69
70
|
const pitch = event.altKey ? SCRUB_FINE : SCRUB_PITCH;
|
|
70
71
|
const steps = Math.round((event.clientX - this.scrubFrom) / pitch);
|
|
@@ -75,7 +76,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
75
76
|
this.requestValue(next);
|
|
76
77
|
const control = this.control;
|
|
77
78
|
if (control) {
|
|
78
|
-
restoreValue(control, this.
|
|
79
|
+
restoreValue(control, this.shown);
|
|
79
80
|
}
|
|
80
81
|
};
|
|
81
82
|
this.handleScrubEnd = (event) => {
|
|
@@ -84,6 +85,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
84
85
|
return;
|
|
85
86
|
}
|
|
86
87
|
grip.releasePointerCapture(event.pointerId);
|
|
88
|
+
this.toggleState('scrubbing', false);
|
|
87
89
|
if (this.value !== this.scrubStart) {
|
|
88
90
|
this.announceChange();
|
|
89
91
|
}
|
|
@@ -92,7 +94,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
92
94
|
event.stopPropagation();
|
|
93
95
|
const control = event.target;
|
|
94
96
|
this.requestValue(control.value);
|
|
95
|
-
restoreValue(control, this.
|
|
97
|
+
restoreValue(control, this.shown);
|
|
96
98
|
};
|
|
97
99
|
this.handleBlur = () => {
|
|
98
100
|
this.editing = false;
|
|
@@ -158,14 +160,31 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
158
160
|
}
|
|
159
161
|
return parseNumber(text, this.locale, this.formatOptions);
|
|
160
162
|
}
|
|
163
|
+
get stride() {
|
|
164
|
+
return Math.abs(this.step ?? 0) || strideOf(this.formatOptions);
|
|
165
|
+
}
|
|
166
|
+
get grid() {
|
|
167
|
+
const step = Math.abs(this.step ?? 0);
|
|
168
|
+
const options = this.formatOptions;
|
|
169
|
+
if (step || !options) {
|
|
170
|
+
return step || 1;
|
|
171
|
+
}
|
|
172
|
+
const [locale, read, grain] = this.grainOf ?? [];
|
|
173
|
+
if (locale === this.locale && read === options && grain !== undefined) {
|
|
174
|
+
return grain;
|
|
175
|
+
}
|
|
176
|
+
const fresh = formatGrain(this.locale, options);
|
|
177
|
+
this.grainOf = [this.locale, options, fresh];
|
|
178
|
+
return fresh;
|
|
179
|
+
}
|
|
161
180
|
onStep(value) {
|
|
162
|
-
const step =
|
|
181
|
+
const step = this.grid;
|
|
163
182
|
const anchor = this.min ?? 0;
|
|
164
183
|
const steps = (value - anchor) / step;
|
|
165
184
|
return Math.abs(steps - Math.round(steps)) < 1e-9;
|
|
166
185
|
}
|
|
167
186
|
clamp(value) {
|
|
168
|
-
const step =
|
|
187
|
+
const step = this.grid;
|
|
169
188
|
const anchor = this.min ?? 0;
|
|
170
189
|
const stepped = anchor + Math.round((value - anchor) / step) * step;
|
|
171
190
|
const floored = this.min === undefined ? stepped : Math.max(this.min, stepped);
|
|
@@ -177,7 +196,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
177
196
|
if (this.isDisabled || this.readOnly) {
|
|
178
197
|
return;
|
|
179
198
|
}
|
|
180
|
-
const step =
|
|
199
|
+
const step = this.stride;
|
|
181
200
|
const from = this.numeric ?? this.min ?? 0;
|
|
182
201
|
const next = this.clamp(this.numeric === null ? from : from + steps * step);
|
|
183
202
|
this.land(String(next));
|
|
@@ -187,7 +206,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
187
206
|
const applied = this.requestValue(next);
|
|
188
207
|
const control = this.control;
|
|
189
208
|
if (control) {
|
|
190
|
-
restoreValue(control, this.
|
|
209
|
+
restoreValue(control, this.shown);
|
|
191
210
|
}
|
|
192
211
|
if (applied && this.value !== before) {
|
|
193
212
|
this.announceChange();
|
|
@@ -223,7 +242,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
223
242
|
}
|
|
224
243
|
const before = this.value;
|
|
225
244
|
this.requestValue(String(this.clamp(parsed)));
|
|
226
|
-
restoreValue(control, this.
|
|
245
|
+
restoreValue(control, this.shown);
|
|
227
246
|
return this.value !== before;
|
|
228
247
|
}
|
|
229
248
|
sync() {
|
|
@@ -253,7 +272,7 @@ let HelixHeadlessNumberInput = class HelixHeadlessNumberInput extends MixinContr
|
|
|
253
272
|
}), control);
|
|
254
273
|
}
|
|
255
274
|
else if (parsed !== null && !this.onStep(parsed)) {
|
|
256
|
-
const step =
|
|
275
|
+
const step = this.grid;
|
|
257
276
|
const anchor = this.min ?? 0;
|
|
258
277
|
const below = this.clamp(anchor + Math.floor((parsed - anchor) / step) * step);
|
|
259
278
|
const above = this.clamp(anchor + Math.ceil((parsed - anchor) / step) * step);
|
|
@@ -431,11 +450,3 @@ HelixHeadlessNumberInput = __decorate([
|
|
|
431
450
|
customElement('helix-headless-number-input')
|
|
432
451
|
], HelixHeadlessNumberInput);
|
|
433
452
|
export { HelixHeadlessNumberInput };
|
|
434
|
-
const decimals = (value) => {
|
|
435
|
-
const text = String(value);
|
|
436
|
-
const exponent = /e-(\d+)$/.exec(text);
|
|
437
|
-
if (exponent) {
|
|
438
|
-
return Number(exponent[1]);
|
|
439
|
-
}
|
|
440
|
-
return (text.split('.')[1] ?? '').length;
|
|
441
|
-
};
|
|
@@ -23,6 +23,7 @@ import { type Row } from '../rows.js';
|
|
|
23
23
|
* | Right | Opens a closed branch, or moves into an open one. Left on a right-to-left page. |
|
|
24
24
|
* | Left | Closes an open branch, or moves to the parent. Right on a right-to-left page. |
|
|
25
25
|
* | Home, End | Moves to the first or the last row. |
|
|
26
|
+
* | Page Down, Page Up | Moves a box's height of rows, so the row at one edge lands at the other. |
|
|
26
27
|
* | Enter, Space | Opens or closes a branch. |
|
|
27
28
|
* | `*` | Opens every branch beside the active row. |
|
|
28
29
|
* | A letter or a word | Moves to the next row whose key starts with what you typed. |
|
|
@@ -90,6 +91,7 @@ import { type Row } from '../rows.js';
|
|
|
90
91
|
* @csspart copy-button - The button inside the copy control.
|
|
91
92
|
* @csspart copy-live - The live region inside the copy button, which says its `pending-label` when the copy becomes pending under focus.
|
|
92
93
|
* @csspart copy-mark - The clipboard icon, and the confirmation icon that replaces it.
|
|
94
|
+
* @csspart copy-spinner - The ring the copy button turns while it is pending.
|
|
93
95
|
* @csspart copy-text - The words on that button, trimmed to their capitals and baseline.
|
|
94
96
|
* @csspart copy-tooltip - The tooltip, forwarded from the copy button's tooltip.
|
|
95
97
|
* @csspart copy-tooltip-arrow - The tooltip's arrow, pointing at the copy button.
|
|
@@ -254,7 +256,7 @@ export declare class HelixHeadlessObjectInspector extends HelixElement {
|
|
|
254
256
|
/** Whether a row held focus as this update began, so a row the render moved gets it back. */
|
|
255
257
|
private hadFocus;
|
|
256
258
|
/** What has been typed toward a key, and when the last letter came. */
|
|
257
|
-
private typed;
|
|
259
|
+
private readonly typed;
|
|
258
260
|
/** The branches of the last value seen, by path, so a new value can tell old ones from new. */
|
|
259
261
|
private branches;
|
|
260
262
|
/** Carries a host `aria-label` and `aria-labelledby` to the tree, which is what takes focus. */
|
|
@@ -338,13 +340,18 @@ export declare class HelixHeadlessObjectInspector extends HelixElement {
|
|
|
338
340
|
private move;
|
|
339
341
|
private readonly handleKeydown;
|
|
340
342
|
/**
|
|
341
|
-
* Moves to the next row whose key starts with what was typed
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
* keys that start with it.
|
|
343
|
+
* Moves to the next row whose key starts with what was typed, through core's
|
|
344
|
+
* `Typeahead`: letters within half a second run together, so `me` finds
|
|
345
|
+
* `meta` past `message`, and a repeated letter cycles through the keys that
|
|
346
|
+
* start with it.
|
|
346
347
|
*/
|
|
347
348
|
private typeahead;
|
|
349
|
+
/**
|
|
350
|
+
* How many rows Page Down and Page Up move: the rows that fit in the tree's
|
|
351
|
+
* box, or in the window where the box does not scroll, less one, so the row
|
|
352
|
+
* at one edge lands at the other.
|
|
353
|
+
*/
|
|
354
|
+
private pageRows;
|
|
348
355
|
/** A press opens or closes the row it lands on, once that row is the active one. */
|
|
349
356
|
private handleRowClick;
|
|
350
357
|
/** Text typed in the filter field, asked for before the tree narrows to it. */
|
|
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
var HelixHeadlessObjectInspector_1;
|
|
8
|
-
import { AriaForwardController, CopyController, countLabel, customElement, drawStatus, elementById, fillTemplate, formatNumbers, HelixActivateEvent, HelixBeforeActivateEvent, HelixBeforeCloseEvent, HelixBeforeOpenEvent, HelixElement, HelixFilterEvent, HelixFilteredEvent, inlineStep, requestChange, StatusController, scrollItemIntoView, searchableById, treeArrow, VirtualizeController, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { AriaForwardController, CopyController, countLabel, customElement, drawStatus, elementById, fillTemplate, formatNumbers, HelixActivateEvent, HelixBeforeActivateEvent, HelixBeforeCloseEvent, HelixBeforeOpenEvent, HelixElement, HelixFilterEvent, HelixFilteredEvent, inlineStep, requestChange, StatusController, scrollItemIntoView, searchableById, Typeahead, treeArrow, VirtualizeController, } from '@fusion.dev/helix-core';
|
|
9
9
|
import { caretDown, caretRight } from '@fusion.dev/helix-icons';
|
|
10
10
|
import { html, nothing } from 'lit';
|
|
11
11
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -41,7 +41,7 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
41
41
|
this.revealing = false;
|
|
42
42
|
this.focusing = false;
|
|
43
43
|
this.hadFocus = false;
|
|
44
|
-
this.typed =
|
|
44
|
+
this.typed = new Typeahead();
|
|
45
45
|
this.branches = new Set();
|
|
46
46
|
this.aria = new AriaForwardController(this, {
|
|
47
47
|
label: true,
|
|
@@ -84,6 +84,12 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
84
84
|
case 'End':
|
|
85
85
|
this.move(rows.length - 1);
|
|
86
86
|
break;
|
|
87
|
+
case 'PageDown':
|
|
88
|
+
this.move(this.cursor + this.pageRows());
|
|
89
|
+
break;
|
|
90
|
+
case 'PageUp':
|
|
91
|
+
this.move(this.cursor - this.pageRows());
|
|
92
|
+
break;
|
|
87
93
|
case 'ArrowRight':
|
|
88
94
|
case 'ArrowLeft':
|
|
89
95
|
switch (treeArrow(row, inlineStep(this, event.key) === 1 ? 1 : -1)) {
|
|
@@ -364,22 +370,17 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
364
370
|
return true;
|
|
365
371
|
}
|
|
366
372
|
typeahead(letter) {
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const wanted = text.toLocaleLowerCase();
|
|
371
|
-
const repeated = [...wanted].every((one) => one === wanted[0]);
|
|
372
|
-
const rows = this.rows;
|
|
373
|
-
const start = wanted.length === 1 || repeated ? this.cursor + 1 : this.cursor;
|
|
374
|
-
for (let step = 0; step < rows.length; step += 1) {
|
|
375
|
-
const at = (start + step) % rows.length;
|
|
376
|
-
const key = rows[at]?.key?.toLocaleLowerCase();
|
|
377
|
-
if (key?.startsWith(repeated ? (wanted[0] ?? '') : wanted)) {
|
|
378
|
-
this.move(at);
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
373
|
+
const at = this.typed.match(letter, this.rows.map((row) => row.key ?? ''), this.cursor);
|
|
374
|
+
if (at >= 0) {
|
|
375
|
+
this.move(at);
|
|
381
376
|
}
|
|
382
377
|
}
|
|
378
|
+
pageRows() {
|
|
379
|
+
const tree = this.partNamed('tree');
|
|
380
|
+
const room = tree && tree.scrollHeight > tree.clientHeight + 1 ? tree.clientHeight : window.innerHeight;
|
|
381
|
+
const tall = this.virtualize.sizeOf(this.cursor) || HelixHeadlessObjectInspector_1.ESTIMATE;
|
|
382
|
+
return Math.max(1, Math.floor(room / tall) - 1);
|
|
383
|
+
}
|
|
383
384
|
handleRowClick(index, row) {
|
|
384
385
|
if (this.move(index) && row.branch) {
|
|
385
386
|
this.toggle(row);
|
|
@@ -451,7 +452,7 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
451
452
|
renderCopyButton(row) {
|
|
452
453
|
return staticHtml `<${this.tag('copy-button')}
|
|
453
454
|
part="copy"
|
|
454
|
-
exportparts="button: copy-button, live: copy-live, text: copy-text, mark: copy-mark, tooltip: copy-tooltip,
|
|
455
|
+
exportparts="button: copy-button, live: copy-live, spinner: copy-spinner, text: copy-text, mark: copy-mark, tooltip: copy-tooltip,
|
|
455
456
|
tooltip-arrow: copy-tooltip-arrow, tooltip-arrow-bottom: copy-tooltip-arrow-bottom,
|
|
456
457
|
tooltip-arrow-left: copy-tooltip-arrow-left, tooltip-arrow-right: copy-tooltip-arrow-right,
|
|
457
458
|
tooltip-arrow-top: copy-tooltip-arrow-top, tooltip-bottom: copy-tooltip-bottom,
|
package/dist/option/index.d.ts
CHANGED
package/dist/option/index.js
CHANGED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
|
+
import { nothing, type PropertyValues } from 'lit';
|
|
3
|
+
/**
|
|
4
|
+
* @summary A rule between options or groups inside a listbox.
|
|
5
|
+
*
|
|
6
|
+
* @description
|
|
7
|
+
* Sets one run of options apart from the next where a heading would say too
|
|
8
|
+
* much, as React Aria's ListBox takes a `Separator`: actions apart from
|
|
9
|
+
* choices in a command palette, say, or the options a reader uses most apart
|
|
10
|
+
* from the rest.
|
|
11
|
+
*
|
|
12
|
+
* It has `role="separator"`, so a screen reader can say where one run ends,
|
|
13
|
+
* and it is no stop: the arrow keys move from the option before it to the one
|
|
14
|
+
* after. The list hides it while a filter is narrowing the options, since a
|
|
15
|
+
* rule between two runs of which only some options are left separates nothing.
|
|
16
|
+
*
|
|
17
|
+
* @since 0.1.0
|
|
18
|
+
* @status stable
|
|
19
|
+
* @aliases Divider, ListBoxSeparator
|
|
20
|
+
* @documentation https://fusion.dev/helix/components/option
|
|
21
|
+
*/
|
|
22
|
+
export declare class HelixHeadlessOptionSeparator extends HelixElement {
|
|
23
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
24
|
+
protected render(): typeof nothing;
|
|
25
|
+
}
|
|
26
|
+
declare global {
|
|
27
|
+
interface HTMLElementTagNameMap {
|
|
28
|
+
'helix-headless-option-separator': HelixHeadlessOptionSeparator;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
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 { customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
|
|
8
|
+
import { nothing } from 'lit';
|
|
9
|
+
let HelixHeadlessOptionSeparator = class HelixHeadlessOptionSeparator extends HelixElement {
|
|
10
|
+
willUpdate(changed) {
|
|
11
|
+
super.willUpdate(changed);
|
|
12
|
+
hostAria(this.internals, { role: 'separator' });
|
|
13
|
+
}
|
|
14
|
+
render() {
|
|
15
|
+
return nothing;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
HelixHeadlessOptionSeparator = __decorate([
|
|
19
|
+
customElement('helix-headless-option-separator')
|
|
20
|
+
], HelixHeadlessOptionSeparator);
|
|
21
|
+
export { HelixHeadlessOptionSeparator };
|
|
@@ -23,6 +23,18 @@ import { type Branch } from '../levels.js';
|
|
|
23
23
|
* In a contents rail with a scrollbar of its own, `follow` keeps the link of
|
|
24
24
|
* the section in view showing as the reader scrolls the page.
|
|
25
25
|
*
|
|
26
|
+
* **Keyboard.** The links are your anchors, in the tab order as you wrote
|
|
27
|
+
* them, so the outline adds no keys of its own: Tab moves through the links
|
|
28
|
+
* and Enter follows one. Following a link moves focus to its section, so the
|
|
29
|
+
* next Tab goes on from the heading, also with `behavior` set.
|
|
30
|
+
*
|
|
31
|
+
* **What a screen reader hears.** A navigation landmark named by `label`, "On
|
|
32
|
+
* this page", or by the slotted heading. The links are lists, nested by level,
|
|
33
|
+
* so a reader hears how many links a level holds and where each one is. The
|
|
34
|
+
* link to the section in view carries `aria-current="location"`, read as
|
|
35
|
+
* "current location", and it moves as the page scrolls without announcing,
|
|
36
|
+
* which would interrupt the reading it follows.
|
|
37
|
+
*
|
|
26
38
|
* The current section is decided by the headings' positions. An
|
|
27
39
|
* `IntersectionObserver` with a band near the top fails both ways: when
|
|
28
40
|
* headings are far apart, none is in the band and no section is marked, and
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, elementById, HelixActivateEvent, HelixElement, IndicatorController, plainClick, reflectElements, scrollItemIntoView, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, elementById, HelixActivateEvent, HelixElement, IndicatorController, plainClick, reflectElements, scrollItemIntoView, scrollingAncestor, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { levelOf, nest } from '../levels.js';
|
|
@@ -148,16 +148,9 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
148
148
|
}
|
|
149
149
|
reveal(link) {
|
|
150
150
|
const sections = this.scroller;
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (!/auto|scroll|overlay/.test(overflowY) || node.scrollHeight <= node.clientHeight) {
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
if (node !== sections && !node.contains(sections)) {
|
|
158
|
-
scrollItemIntoView(link, { scroller: node });
|
|
159
|
-
}
|
|
160
|
-
return;
|
|
151
|
+
const node = scrollingAncestor(link, { axis: 'y', overflowing: true, stop: this.page });
|
|
152
|
+
if (node && node !== sections && !node.contains(sections)) {
|
|
153
|
+
scrollItemIntoView(link, { scroller: node });
|
|
161
154
|
}
|
|
162
155
|
}
|
|
163
156
|
get atEnd() {
|
|
@@ -169,15 +162,8 @@ let HelixHeadlessOutline = class HelixHeadlessOutline extends HelixElement {
|
|
|
169
162
|
return (doc.scrollingElement ?? doc.documentElement);
|
|
170
163
|
}
|
|
171
164
|
get scroller() {
|
|
172
|
-
const doc = globalThis.document;
|
|
173
165
|
const first = this.sections[0]?.target;
|
|
174
|
-
|
|
175
|
-
const { overflowY } = getComputedStyle(node);
|
|
176
|
-
if (/auto|scroll|overlay/.test(overflowY) && node.scrollHeight > node.clientHeight) {
|
|
177
|
-
return node;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return this.page;
|
|
166
|
+
return (first && scrollingAncestor(first, { axis: 'y', overflowing: true })) || this.page;
|
|
181
167
|
}
|
|
182
168
|
reach() {
|
|
183
169
|
for (const { target } of this.sections) {
|
|
@@ -14,6 +14,11 @@ import '../../select/index.js';
|
|
|
14
14
|
* `currentColor`, and the label is a real `<label for>` pointing at the
|
|
15
15
|
* trigger's id.
|
|
16
16
|
*
|
|
17
|
+
* A `<label for>` pointing at this element, or its own `aria-label` or
|
|
18
|
+
* `aria-labelledby`, names the select in place of `label`, so a reader hears
|
|
19
|
+
* the page's words for it, and the select draws no label of its own beside
|
|
20
|
+
* the page's.
|
|
21
|
+
*
|
|
17
22
|
* The label sits on the same row as the select. `Select`'s host is a column,
|
|
18
23
|
* and an outer-tree rule overrides a `:host` rule, so the row layout needs no
|
|
19
24
|
* property on `Select` and nothing added to your markup.
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, formatNumbers, HelixBeforeChangeEvent, HelixFormElement, requestChange, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, formatNumbers, HelixBeforeChangeEvent, HelixFormElement, hostWords, requestChange, } 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';
|
|
@@ -89,6 +89,7 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
|
|
|
89
89
|
renderSelect() {
|
|
90
90
|
const select = this.tag('select');
|
|
91
91
|
const option = this.tag('option');
|
|
92
|
+
const named = this.isConnected ? hostWords(this) : '';
|
|
92
93
|
return html `<${select}
|
|
93
94
|
part="control"
|
|
94
95
|
exportparts="feedback: control-feedback, hint: control-hint, indicator: control-indicator,
|
|
@@ -99,7 +100,8 @@ let HelixHeadlessPaginationSize = class HelixHeadlessPaginationSize extends Heli
|
|
|
99
100
|
listbox-live: control-listbox-live, listbox-loading: control-listbox-loading, listbox-search: control-listbox-search,
|
|
100
101
|
listbox-search-field: control-listbox-search-field, surface: control-surface,
|
|
101
102
|
trigger: control-trigger, value: control-value"
|
|
102
|
-
label=${this.label}
|
|
103
|
+
label=${named ? '' : this.label}
|
|
104
|
+
aria-label=${named || nothing}
|
|
103
105
|
?disabled=${this.isDisabled}
|
|
104
106
|
.value=${String(this.current)}
|
|
105
107
|
@helix-before-change=${this.handleChange}
|
package/dist/pin-input/code.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/** What a box accepts, which decides the keyboard a phone offers. */
|
|
2
|
+
export type PinType = 'alphanumeric' | 'numeric' | 'text';
|
|
3
|
+
/** How typed letters are cased: as typed, or turned upper or lower case. */
|
|
4
|
+
export type PinCase = 'lower' | 'preserve' | 'upper';
|
|
2
5
|
/**
|
|
3
6
|
* Typed or pasted text as the code's characters: trimmed, with what `type`
|
|
4
7
|
* refuses dropped, and its letters cased as `letterCase` asks. Web Awesome's
|
|
@@ -8,3 +11,27 @@ import type { PinCase, PinType } from './root/pin-input-root.js';
|
|
|
8
11
|
* `text` keeps everything.
|
|
9
12
|
*/
|
|
10
13
|
export declare const cleanCode: (text: string, type: PinType, letterCase?: PinCase) => string;
|
|
14
|
+
/** A code after an edit, and the box the caret is in after it. */
|
|
15
|
+
export interface CodeEdit {
|
|
16
|
+
/** The box the caret is in, from 0, never past the last box. */
|
|
17
|
+
caret: number;
|
|
18
|
+
/** The code's characters, as many as there are boxes at most. */
|
|
19
|
+
code: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* What the one field holds after the platform edited it, as a code: `raw` is
|
|
23
|
+
* the field's text with the caret at `caret`, cleaned and cut at `count`, and
|
|
24
|
+
* the caret is moved past only the characters the code kept before it.
|
|
25
|
+
*/
|
|
26
|
+
export declare const readTyped: (raw: string, caret: number, type: PinType, letterCase: PinCase, count: number) => CodeEdit;
|
|
27
|
+
/**
|
|
28
|
+
* A run of characters written over `code` from box `at` onward, which is what a
|
|
29
|
+
* paste does: the boxes it reaches take its characters and the rest keep
|
|
30
|
+
* theirs, and anything past the last box is dropped.
|
|
31
|
+
*
|
|
32
|
+
* **A code has no holes in it**, so the run starts no later than the end of
|
|
33
|
+
* the code: a whole code pasted into an empty field fills from the first box
|
|
34
|
+
* wherever the caret was, and two characters pasted into box three of a field
|
|
35
|
+
* holding two fill from box three.
|
|
36
|
+
*/
|
|
37
|
+
export declare const overwriteCode: (code: string, at: number, text: string, count: number) => CodeEdit;
|
package/dist/pin-input/code.js
CHANGED
|
@@ -11,3 +11,15 @@ export const cleanCode = (text, type, letterCase = 'preserve') => {
|
|
|
11
11
|
? kept.toLowerCase()
|
|
12
12
|
: kept;
|
|
13
13
|
};
|
|
14
|
+
export const readTyped = (raw, caret, type, letterCase, count) => ({
|
|
15
|
+
caret: Math.min(cleanCode(raw.slice(0, caret), type, letterCase).length, count - 1),
|
|
16
|
+
code: cleanCode(raw, type, letterCase).slice(0, count),
|
|
17
|
+
});
|
|
18
|
+
export const overwriteCode = (code, at, text, count) => {
|
|
19
|
+
const start = Math.min(at, code.length);
|
|
20
|
+
const characters = [...code.slice(0, count)];
|
|
21
|
+
for (let offset = 0; offset < text.length && start + offset < count; offset += 1) {
|
|
22
|
+
characters[start + offset] = text[offset];
|
|
23
|
+
}
|
|
24
|
+
return { caret: Math.min(count - 1, start + text.length), code: characters.join('') };
|
|
25
|
+
};
|