@fusion.dev/helix-headless 0.146.0 → 0.148.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 +9287 -1084
- package/dist/accordion/item/accordion-item.d.ts +43 -21
- package/dist/accordion/item/accordion-item.js +37 -11
- package/dist/accordion/root/accordion-root.d.ts +8 -2
- package/dist/accordion/root/accordion-root.js +6 -8
- package/dist/announcement/root/announcement-root.d.ts +66 -6
- package/dist/announcement/root/announcement-root.js +144 -13
- package/dist/area-chart/root/area-chart-root.d.ts +18 -1
- package/dist/area-chart/root/area-chart-root.js +14 -7
- package/dist/avatar/root/avatar-root.d.ts +31 -1
- package/dist/avatar/root/avatar-root.js +11 -1
- package/dist/badge/count.d.ts +14 -0
- package/dist/badge/count.js +20 -0
- package/dist/badge/root/badge-root.d.ts +57 -6
- package/dist/badge/root/badge-root.js +77 -8
- 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/blockquote/root/blockquote-root.d.ts +66 -8
- package/dist/blockquote/root/blockquote-root.js +85 -8
- 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/button-group/arrows.d.ts +14 -0
- package/dist/button-group/arrows.js +10 -0
- package/dist/button-group/root/button-group-root.d.ts +141 -3
- package/dist/button-group/root/button-group-root.js +142 -2
- package/dist/canvas/edge-pan.d.ts +61 -0
- package/dist/canvas/edge-pan.js +63 -0
- package/dist/canvas/node/canvas-node.d.ts +12 -2
- package/dist/canvas/node/canvas-node.js +6 -2
- package/dist/canvas/root/canvas-document.d.ts +10 -0
- package/dist/canvas/root/canvas-document.js +1 -0
- package/dist/canvas/root/canvas-root.d.ts +107 -5
- package/dist/canvas/root/canvas-root.js +140 -36
- package/dist/canvas/snap.d.ts +42 -0
- package/dist/canvas/snap.js +32 -0
- package/dist/card/root/card-root.d.ts +12 -1
- package/dist/card/root/card-root.js +11 -4
- package/dist/carousel/root/carousel-root.d.ts +4 -3
- package/dist/carousel/root/carousel-root.js +2 -6
- package/dist/chat/root/chat-root.d.ts +28 -4
- package/dist/chat/root/chat-root.js +12 -7
- package/dist/checkbox/root/checkbox-root.js +5 -7
- package/dist/checkbox-group/root/checkbox-group-root.d.ts +13 -0
- package/dist/checkbox-group/root/checkbox-group-root.js +16 -7
- package/dist/checkbox-group/select-all.d.ts +9 -4
- package/dist/checkbox-group/select-all.js +1 -1
- package/dist/code-block/root/code-block-root.d.ts +41 -18
- package/dist/code-block/root/code-block-root.js +21 -6
- 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 +99 -55
- package/dist/color-picker/wheel.d.ts +28 -0
- package/dist/color-picker/wheel.js +15 -0
- package/dist/combobox/root/combobox-root.d.ts +83 -11
- package/dist/combobox/root/combobox-root.js +81 -18
- package/dist/command/root/command-root.d.ts +7 -4
- 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 +29 -50
- 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 +22 -4
- package/dist/description-list/item/description-list-item.js +14 -4
- package/dist/divider/root/divider-root.d.ts +45 -16
- package/dist/divider/root/divider-root.js +28 -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 +38 -4
- package/dist/drilldown/root/drilldown-root.js +3 -2
- package/dist/element-events.generated.js +5 -1
- package/dist/empty/root/empty-root.d.ts +46 -2
- package/dist/empty/root/empty-root.js +50 -5
- package/dist/file-input/root/file-input-root.d.ts +34 -6
- package/dist/file-input/root/file-input-root.js +55 -21
- package/dist/file-input/status.d.ts +24 -0
- package/dist/file-input/status.js +11 -0
- package/dist/filter-input/chip/filter-chip.d.ts +23 -0
- package/dist/filter-input/chip/filter-chip.js +10 -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/fields.d.ts +20 -0
- package/dist/format-date/fields.js +14 -0
- package/dist/format-date/options.d.ts +5 -5
- package/dist/format-date/options.js +10 -39
- package/dist/format-date/root/format-date-root.d.ts +53 -4
- package/dist/format-date/root/format-date-root.js +38 -50
- package/dist/graph/root/graph-root.d.ts +23 -5
- package/dist/graph/root/graph-root.js +17 -20
- 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 +76 -3
- package/dist/heatmap/root/heatmap-root.js +105 -20
- 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 +20 -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/root/kbd-root.d.ts +20 -3
- package/dist/kbd/root/kbd-root.js +23 -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 +25 -26
- 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 +31 -24
- package/dist/list/selection.d.ts +17 -0
- package/dist/list/selection.js +16 -0
- package/dist/listbox/root/listbox-root.d.ts +125 -26
- package/dist/listbox/root/listbox-root.js +156 -166
- package/dist/map/marker/map-marker.d.ts +2 -1
- package/dist/map/root/map-root.d.ts +40 -2
- package/dist/map/root/map-root.js +64 -23
- 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 +29 -50
- package/dist/menu/item/menu-item.js +4 -4
- package/dist/menu/root/menu-root.d.ts +5 -2
- package/dist/meter/root/meter-root.d.ts +42 -0
- package/dist/meter/root/meter-root.js +33 -7
- package/dist/navigation/root/navigation-root.js +5 -8
- package/dist/notifications/group/notification-group.d.ts +8 -1
- package/dist/notifications/group/notification-group.js +12 -6
- package/dist/notifications/notification/notification.d.ts +12 -1
- package/dist/notifications/notification/notification.js +3 -1
- package/dist/notifications/root/notifications-root.d.ts +48 -3
- package/dist/notifications/root/notifications-root.js +36 -6
- 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 +17 -6
- package/dist/object-inspector/root/object-inspector-root.js +31 -20
- 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 +6 -0
- package/dist/pagination/size/pagination-size.js +5 -3
- package/dist/pin-input/code.d.ts +51 -1
- package/dist/pin-input/code.js +37 -0
- package/dist/pin-input/root/pin-input-root.d.ts +98 -121
- package/dist/pin-input/root/pin-input-root.js +151 -156
- 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 +31 -9
- package/dist/qr-code/root/qr-code-root.js +29 -17
- 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/measures.d.ts +22 -0
- package/dist/scatter-chart/measures.js +11 -0
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +26 -0
- package/dist/scatter-chart/root/scatter-chart-root.js +21 -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 +115 -11
- package/dist/select/root/select-root.js +104 -20
- 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/group/speed-dial-group.d.ts +48 -0
- package/dist/speed-dial/group/speed-dial-group.js +43 -0
- package/dist/speed-dial/index.d.ts +1 -0
- package/dist/speed-dial/index.js +1 -0
- package/dist/speed-dial/item/speed-dial-item.d.ts +27 -2
- package/dist/speed-dial/item/speed-dial-item.js +43 -5
- package/dist/speed-dial/long-press.d.ts +50 -0
- package/dist/speed-dial/long-press.js +48 -0
- package/dist/speed-dial/root/speed-dial-root.d.ts +86 -1
- package/dist/speed-dial/root/speed-dial-root.js +123 -6
- package/dist/splitter/root/splitter-root.d.ts +9 -2
- package/dist/splitter/root/splitter-root.js +18 -3
- 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/cell/table-cell.d.ts +8 -1
- package/dist/table/cell/table-cell.js +6 -2
- package/dist/table/column/table-column.d.ts +6 -0
- package/dist/table/column/table-column.js +5 -1
- package/dist/table/grid-controller.d.ts +117 -0
- package/dist/table/grid-controller.js +293 -0
- package/dist/table/root/table-root.d.ts +47 -3
- package/dist/table/root/table-root.js +93 -29
- package/dist/table/row/table-row.d.ts +36 -0
- package/dist/table/row/table-row.js +52 -2
- 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 +23 -20
- 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 +12 -14
- package/dist/time-picker/root/time-picker-root.js +18 -23
- package/dist/toast/item/toast-item.d.ts +9 -6
- package/dist/toast/item/toast-item.js +1 -1
- package/dist/toast/root/toast-root.d.ts +40 -4
- package/dist/toast/root/toast-root.js +68 -16
- 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 -43
- package/dist/toggle/root/toggle-root.js +2 -4
- package/dist/toolbar/root/toolbar-root.d.ts +52 -5
- package/dist/toolbar/root/toolbar-root.js +88 -13
- package/dist/tooltip/root/tooltip-root.d.ts +7 -1
- package/dist/tooltip/root/tooltip-root.js +10 -2
- 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 +16 -1
- package/dist/video/root/video-root.js +15 -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 +53 -41
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +4934 -954
- package/types/svelte.d.ts +2 -0
- package/types/vue.d.ts +946 -253
- 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
- package/dist/tooltip/focus-target.d.ts +0 -6
- package/dist/tooltip/focus-target.js +0 -9
|
@@ -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, deepContains, focusableElements, HelixElement, HelixLoadMoreEvent, HelixReadEvent, hostAria, MixinCollection, markRegion, rovingStop, whenHydrated, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { assignSlots, ChildrenController, customElement, deepContains, focusableElements, HelixElement, HelixLoadMoreEvent, 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
10
|
import { feedStep } from '../feed-keys.js';
|
|
@@ -12,6 +12,7 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
|
|
|
12
12
|
constructor() {
|
|
13
13
|
super(...arguments);
|
|
14
14
|
this.label = '';
|
|
15
|
+
this.loadError = '';
|
|
15
16
|
this.loadMore = false;
|
|
16
17
|
this.loadMoreLabel = 'Load more';
|
|
17
18
|
this.markAll = false;
|
|
@@ -20,6 +21,7 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
|
|
|
20
21
|
this.assign();
|
|
21
22
|
this.requestUpdate();
|
|
22
23
|
};
|
|
24
|
+
this.childWatch = new ChildrenController(this, this.handleSlotChange);
|
|
23
25
|
this.handleRead = () => {
|
|
24
26
|
queueMicrotask(() => this.requestUpdate());
|
|
25
27
|
};
|
|
@@ -138,11 +140,8 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
|
|
|
138
140
|
}
|
|
139
141
|
return;
|
|
140
142
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const slot = root?.querySelector?.(`slot[name="${name}"]`);
|
|
144
|
-
slot?.assign?.(...[...this.children].filter((child) => child.getAttribute('slot') === name));
|
|
145
|
-
}
|
|
143
|
+
const rows = this.rows;
|
|
144
|
+
assignSlots(root, this.children, (child) => rows.includes(child) ? 'items' : child.getAttribute('slot') === 'items' ? '' : undefined);
|
|
146
145
|
}
|
|
147
146
|
get reachable() {
|
|
148
147
|
return this.items.filter((row) => !('assignedSlot' in row) || row.assignedSlot !== null);
|
|
@@ -178,6 +177,34 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
|
|
|
178
177
|
willUpdate(changed) {
|
|
179
178
|
super.willUpdate(changed);
|
|
180
179
|
hostAria(this.internals, { label: this.label || 'Notifications', role: 'region' });
|
|
180
|
+
const failed = this.failed;
|
|
181
|
+
this.toggleState('error', failed);
|
|
182
|
+
this.toggleState('loading', this.loading);
|
|
183
|
+
this.toggleState('empty', !this.loading && !failed && this.childrenKnown && this.items.length === 0);
|
|
184
|
+
}
|
|
185
|
+
renderStatus(hasContent) {
|
|
186
|
+
if (this.failed) {
|
|
187
|
+
return html `<p part="error"><slot name="error">${this.loadError}</slot></p>`;
|
|
188
|
+
}
|
|
189
|
+
if (!this.loading && hasContent) {
|
|
190
|
+
return nothing;
|
|
191
|
+
}
|
|
192
|
+
return this.loading
|
|
193
|
+
? html `<p part="loading"><slot name="loading">${this.loadingText}</slot></p>`
|
|
194
|
+
: html `<p part="empty"><slot name="empty">${this.emptyText}</slot></p>`;
|
|
195
|
+
}
|
|
196
|
+
renderLive(hasContent) {
|
|
197
|
+
const said = this.failed
|
|
198
|
+
? this.loadError
|
|
199
|
+
: this.loading
|
|
200
|
+
? this.loadingText
|
|
201
|
+
: hasContent
|
|
202
|
+
? this.announced
|
|
203
|
+
: this.emptyText;
|
|
204
|
+
return html `<span part="live" role="status">${said}</span>`;
|
|
205
|
+
}
|
|
206
|
+
get failed() {
|
|
207
|
+
return Boolean(this.loadError);
|
|
181
208
|
}
|
|
182
209
|
markMedia() {
|
|
183
210
|
this.toggleState('media', this.items.some((item) => item.querySelector(':scope > [slot="media"]') !== null));
|
|
@@ -238,6 +265,9 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
|
|
|
238
265
|
__decorate([
|
|
239
266
|
property()
|
|
240
267
|
], HelixHeadlessNotifications.prototype, "label", void 0);
|
|
268
|
+
__decorate([
|
|
269
|
+
property({ attribute: 'load-error' })
|
|
270
|
+
], HelixHeadlessNotifications.prototype, "loadError", void 0);
|
|
241
271
|
__decorate([
|
|
242
272
|
property({ attribute: 'load-more', type: Boolean })
|
|
243
273
|
], HelixHeadlessNotifications.prototype, "loadMore", void 0);
|
|
@@ -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 pageStep;
|
|
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. */
|
|
@@ -373,6 +380,10 @@ export declare class HelixHeadlessObjectInspector extends HelixElement {
|
|
|
373
380
|
private renderRow;
|
|
374
381
|
/** Whether a row of the tree holds focus. */
|
|
375
382
|
private hasFocusedRow;
|
|
383
|
+
/** Where the row holding focus is among the visible rows, or nothing while none does. */
|
|
384
|
+
private focusedIndex;
|
|
385
|
+
/** Focus on the tree itself, its stop while the active row is not drawn, goes on to that row. */
|
|
386
|
+
private readonly handleTreeFocus;
|
|
376
387
|
/**
|
|
377
388
|
* A row that takes focus some other way than the keys, from a script or a
|
|
378
389
|
* screen reader, becomes the active row, so focus and the keys agree.
|
|
@@ -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, pageRows, requestChange, StatusController, scrollItemIntoView, scrollRoom, 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.pageStep());
|
|
89
|
+
break;
|
|
90
|
+
case 'PageUp':
|
|
91
|
+
this.move(this.cursor - this.pageStep());
|
|
92
|
+
break;
|
|
87
93
|
case 'ArrowRight':
|
|
88
94
|
case 'ArrowLeft':
|
|
89
95
|
switch (treeArrow(row, inlineStep(this, event.key) === 1 ? 1 : -1)) {
|
|
@@ -147,6 +153,11 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
147
153
|
this.requestUpdate();
|
|
148
154
|
}
|
|
149
155
|
};
|
|
156
|
+
this.handleTreeFocus = () => {
|
|
157
|
+
this.revealing = true;
|
|
158
|
+
this.focusing = true;
|
|
159
|
+
this.requestUpdate();
|
|
160
|
+
};
|
|
150
161
|
this.handleFocusIn = (event) => {
|
|
151
162
|
const index = Number(event.target.dataset?.index);
|
|
152
163
|
if (Number.isInteger(index) && index !== this.cursor) {
|
|
@@ -361,25 +372,18 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
361
372
|
}
|
|
362
373
|
this.revealing = true;
|
|
363
374
|
this.focusing = true;
|
|
375
|
+
this.requestUpdate();
|
|
364
376
|
return true;
|
|
365
377
|
}
|
|
366
378
|
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
|
-
}
|
|
379
|
+
const at = this.typed.match(letter, this.rows.map((row) => row.key ?? ''), this.cursor);
|
|
380
|
+
if (at >= 0) {
|
|
381
|
+
this.move(at);
|
|
381
382
|
}
|
|
382
383
|
}
|
|
384
|
+
pageStep() {
|
|
385
|
+
return pageRows(scrollRoom(this.partNamed('tree')), this.virtualize.sizeOf(this.cursor) || HelixHeadlessObjectInspector_1.ESTIMATE);
|
|
386
|
+
}
|
|
383
387
|
handleRowClick(index, row) {
|
|
384
388
|
if (this.move(index) && row.branch) {
|
|
385
389
|
this.toggle(row);
|
|
@@ -445,13 +449,16 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
445
449
|
</div>`;
|
|
446
450
|
}
|
|
447
451
|
hasFocusedRow() {
|
|
452
|
+
return this.focusedIndex() !== undefined;
|
|
453
|
+
}
|
|
454
|
+
focusedIndex() {
|
|
448
455
|
const focused = this.shadowRoot?.activeElement;
|
|
449
|
-
return focused?.getAttribute?.('role') === 'row';
|
|
456
|
+
return focused?.getAttribute?.('role') === 'row' ? Number(focused.dataset.index) : undefined;
|
|
450
457
|
}
|
|
451
458
|
renderCopyButton(row) {
|
|
452
459
|
return staticHtml `<${this.tag('copy-button')}
|
|
453
460
|
part="copy"
|
|
454
|
-
exportparts="button: copy-button, live: copy-live, text: copy-text, mark: copy-mark, tooltip: copy-tooltip,
|
|
461
|
+
exportparts="button: copy-button, live: copy-live, spinner: copy-spinner, text: copy-text, mark: copy-mark, tooltip: copy-tooltip,
|
|
455
462
|
tooltip-arrow: copy-tooltip-arrow, tooltip-arrow-bottom: copy-tooltip-arrow-bottom,
|
|
456
463
|
tooltip-arrow-left: copy-tooltip-arrow-left, tooltip-arrow-right: copy-tooltip-arrow-right,
|
|
457
464
|
tooltip-arrow-top: copy-tooltip-arrow-top, tooltip-bottom: copy-tooltip-bottom,
|
|
@@ -463,8 +470,9 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
463
470
|
render() {
|
|
464
471
|
const rows = this.rows;
|
|
465
472
|
const { first, last } = this.windowed ? this.virtualize.window : { first: 0, last: rows.length };
|
|
466
|
-
const
|
|
467
|
-
|
|
473
|
+
const focused = this.focusedIndex();
|
|
474
|
+
const kept = this.windowed && focused !== undefined && (focused < first || focused >= last)
|
|
475
|
+
? focused
|
|
468
476
|
: undefined;
|
|
469
477
|
const { after, before } = this.windowed
|
|
470
478
|
? this.virtualize.spacers(kept)
|
|
@@ -474,6 +482,7 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
474
482
|
if (kept !== undefined && keptRow) {
|
|
475
483
|
shown.splice(kept < first ? 0 : shown.length, 0, [keptRow, kept]);
|
|
476
484
|
}
|
|
485
|
+
const stopless = rows.length > 0 && !shown.some(([, at]) => at === this.cursor);
|
|
477
486
|
return html `${this.label ? html `<div part="header"><span part="label">${this.label}</span></div>` : nothing}${this.filterable
|
|
478
487
|
? html `<input
|
|
479
488
|
part="search-field"
|
|
@@ -493,8 +502,10 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
493
502
|
id="tree"
|
|
494
503
|
role="treegrid"
|
|
495
504
|
?data-scroller=${this.windowed}
|
|
505
|
+
tabindex=${stopless ? '0' : nothing}
|
|
496
506
|
aria-label=${this.label || this.treeLabel}
|
|
497
507
|
@keydown=${this.handleKeydown}
|
|
508
|
+
@focus=${this.handleTreeFocus}
|
|
498
509
|
@focusin=${this.handleFocusIn}
|
|
499
510
|
@focusout=${this.handleFocusOut}
|
|
500
511
|
@scroll=${() => this.virtualize.measure()}
|
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.
|
|
@@ -60,6 +65,7 @@ import '../../select/index.js';
|
|
|
60
65
|
* @csspart control-listbox-loading - The text shown while the options load.
|
|
61
66
|
* @csspart control-listbox-search - The region that holds the filter field.
|
|
62
67
|
* @csspart control-listbox-search-field - The filter field.
|
|
68
|
+
* @csspart control-live - The select's `live` part, the region a screen reader hears a choice made on the closed trigger from.
|
|
63
69
|
* @csspart control-surface - The floating panel.
|
|
64
70
|
* @csspart control-trigger - The closed control, which shows the chosen size.
|
|
65
71
|
* @csspart control-value - The chosen size inside the trigger.
|