@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
|
@@ -9,6 +9,7 @@ import { html, nothing, svg } from 'lit';
|
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import '../../tooltip/index.js';
|
|
11
11
|
import { correlation, leastSquares } from '../fit.js';
|
|
12
|
+
import { bubbleWeights, measuresOf } from '../measures.js';
|
|
12
13
|
const REACH = 24;
|
|
13
14
|
const COEFFICIENTS = new Map();
|
|
14
15
|
const coefficientIn = (locale) => {
|
|
@@ -37,6 +38,7 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
37
38
|
super(...arguments);
|
|
38
39
|
this.correlationLabel = 'correlation';
|
|
39
40
|
this.pointsLabel = 'points';
|
|
41
|
+
this.sizeBy = '';
|
|
40
42
|
this.trend = false;
|
|
41
43
|
this.drawn = [];
|
|
42
44
|
this.nearest = undefined;
|
|
@@ -82,8 +84,11 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
82
84
|
this.removeEventListener('pointerleave', this.handleLeave);
|
|
83
85
|
}
|
|
84
86
|
seriesOf(cell) {
|
|
85
|
-
const depth = this.
|
|
86
|
-
return depth <
|
|
87
|
+
const depth = this.measures.ups.indexOf(cell);
|
|
88
|
+
return depth < 0 ? undefined : seriesIndex(depth);
|
|
89
|
+
}
|
|
90
|
+
get measures() {
|
|
91
|
+
return measuresOf(this.plottedColumns, (column) => this.columnName(column), this.sizeBy);
|
|
87
92
|
}
|
|
88
93
|
get rulesX() {
|
|
89
94
|
return this.gridlines !== undefined && this.gridlines !== 'y';
|
|
@@ -93,9 +98,8 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
93
98
|
}
|
|
94
99
|
get field() {
|
|
95
100
|
const rows = this.sourceRows;
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
const name = (column) => column === undefined ? '' : (rows.find((row) => row.cells[column])?.cells[column]?.name ?? '');
|
|
101
|
+
const { across, size, ups } = this.measures;
|
|
102
|
+
const name = (column) => column === undefined ? '' : this.columnName(column);
|
|
99
103
|
const pairs = ups.map((column) => rows.flatMap((row, index) => {
|
|
100
104
|
const x = across === undefined ? undefined : row.cells[across]?.value;
|
|
101
105
|
const y = row.cells[column]?.value;
|
|
@@ -107,10 +111,17 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
107
111
|
const y = nice(extent(all.length > 0 ? all.map(([, one]) => one) : [0]));
|
|
108
112
|
const along = linear(x, [0, PLOT_WIDTH]);
|
|
109
113
|
const up = linear(y, [PLOT_HEIGHT, 0]);
|
|
114
|
+
const weights = bubbleWeights(rows.map((row) => (size === undefined ? undefined : row.cells[size]?.value)));
|
|
110
115
|
return {
|
|
111
116
|
pairs: pairs.map((series) => series.map(([one, two]) => [one, two])),
|
|
112
117
|
points: pairs.flatMap((series, depth) => shown[depth]
|
|
113
|
-
? series.map(([one, two, row]) => ({
|
|
118
|
+
? series.map(([one, two, row]) => ({
|
|
119
|
+
depth,
|
|
120
|
+
row,
|
|
121
|
+
weight: weights[row],
|
|
122
|
+
x: along(one),
|
|
123
|
+
y: up(two),
|
|
124
|
+
}))
|
|
114
125
|
: []),
|
|
115
126
|
x,
|
|
116
127
|
xName: name(across),
|
|
@@ -174,7 +185,7 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
174
185
|
data-series=${index}
|
|
175
186
|
?data-active=${point.row === at}
|
|
176
187
|
part="point${point.row === at ? ' point-active' : ''}"
|
|
177
|
-
style=${`--chart-series: var(--chart-series-${index}); --chart-point-x: ${point.x}%; --chart-point-y: ${point.y}
|
|
188
|
+
style=${`--chart-series: var(--chart-series-${index}); --chart-point-x: ${point.x}%; --chart-point-y: ${point.y}%${point.weight === undefined ? '' : `; --chart-point-weight: ${point.weight}`}`}
|
|
178
189
|
></span>`;
|
|
179
190
|
})}
|
|
180
191
|
${this.renderTooltip()}
|
|
@@ -243,6 +254,9 @@ __decorate([
|
|
|
243
254
|
__decorate([
|
|
244
255
|
property({ attribute: 'points-label' })
|
|
245
256
|
], HelixHeadlessScatterChart.prototype, "pointsLabel", void 0);
|
|
257
|
+
__decorate([
|
|
258
|
+
property({ attribute: 'size-by' })
|
|
259
|
+
], HelixHeadlessScatterChart.prototype, "sizeBy", void 0);
|
|
246
260
|
__decorate([
|
|
247
261
|
property({ reflect: true, type: Boolean })
|
|
248
262
|
], HelixHeadlessScatterChart.prototype, "trend", void 0);
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The arithmetic behind the scrollbars a scroll area draws under `scrollbars`.
|
|
3
|
-
*
|
|
4
|
-
* Every length here is along one axis and counted from that axis' start, which
|
|
5
|
-
* is the right-hand edge on a right-to-left page for the horizontal one. The
|
|
6
|
-
* component turns a pointer and a `scrollLeft` into those counts, so nothing
|
|
7
|
-
* below has to know which way the line runs.
|
|
8
|
-
*/
|
|
9
1
|
/** Which scrollbars are drawn, and when. Absent keeps the browser's own. */
|
|
10
2
|
export type Scrollbars = 'always' | 'auto' | 'hover' | 'scroll';
|
|
11
3
|
/** The two axes a scrollbar runs along. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { clamp } from '@fusion.dev/helix-core';
|
|
2
2
|
export const thumbFraction = ({ client, scroll }) => scroll <= 0 ? 1 : clamp(client / scroll, 0, 1);
|
|
3
3
|
export const scrollFraction = ({ client, offset, scroll }) => {
|
|
4
4
|
const room = scroll - client;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** A box on the screen, in viewport pixels. */
|
|
2
|
+
export interface Box {
|
|
3
|
+
height: number;
|
|
4
|
+
left: number;
|
|
5
|
+
top: number;
|
|
6
|
+
width: number;
|
|
7
|
+
}
|
|
8
|
+
/** What places a list over its trigger. */
|
|
9
|
+
export interface Over {
|
|
10
|
+
/** How far inside the screen's edges the list stays, in pixels. */
|
|
11
|
+
margin: number;
|
|
12
|
+
/** The option to sit on the trigger: its top within the list, and its height. */
|
|
13
|
+
option: {
|
|
14
|
+
height: number;
|
|
15
|
+
top: number;
|
|
16
|
+
};
|
|
17
|
+
/** The list's own size. */
|
|
18
|
+
panel: {
|
|
19
|
+
height: number;
|
|
20
|
+
width: number;
|
|
21
|
+
};
|
|
22
|
+
/** Whether the line of text runs right to left, which aligns the end edges. */
|
|
23
|
+
rtl: boolean;
|
|
24
|
+
/** The trigger. */
|
|
25
|
+
trigger: Box;
|
|
26
|
+
/** The screen. */
|
|
27
|
+
viewport: {
|
|
28
|
+
height: number;
|
|
29
|
+
width: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Where a list opened over its trigger goes, so the option it opens on sits
|
|
34
|
+
* where the trigger is: the native select's place on macOS, and Radix's
|
|
35
|
+
* `item-aligned`.
|
|
36
|
+
*
|
|
37
|
+
* The option's middle on the trigger's middle, then kept on the screen: a
|
|
38
|
+
* list that would run off the bottom moves up, and one that would run off the
|
|
39
|
+
* top moves down, so near an edge the option is beside the trigger rather than
|
|
40
|
+
* on it. A list taller than the screen starts at its top edge. The start edges
|
|
41
|
+
* line up, the left in English and the right in Arabic, kept on the screen the
|
|
42
|
+
* same way.
|
|
43
|
+
*/
|
|
44
|
+
export declare const over: ({ margin, option, panel, rtl, trigger, viewport, }: Over) => {
|
|
45
|
+
left: number;
|
|
46
|
+
top: number;
|
|
47
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const over = ({ margin, option, panel, rtl, trigger, viewport, }) => {
|
|
2
|
+
const centered = trigger.top + trigger.height / 2 - (option.top + option.height / 2);
|
|
3
|
+
const top = Math.max(margin, Math.min(centered, viewport.height - margin - panel.height));
|
|
4
|
+
const start = rtl ? trigger.left + trigger.width - panel.width : trigger.left;
|
|
5
|
+
const left = Math.max(margin, Math.min(start, viewport.width - margin - panel.width));
|
|
6
|
+
return { left: Math.round(left), top: Math.round(top) };
|
|
7
|
+
};
|
|
@@ -21,13 +21,36 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
|
|
|
21
21
|
* Set `valueContent` to draw the trigger's content from the chosen options,
|
|
22
22
|
* and several chosen options are written as a list in the reader's language.
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
24
|
+
* **Keyboard.** On the closed trigger:
|
|
25
|
+
*
|
|
26
|
+
* | Key | What it does |
|
|
27
|
+
* |---|---|
|
|
28
|
+
* | Down, Enter, Space | Opens the list on the chosen option, or the first. |
|
|
29
|
+
* | Up | Opens the list on the chosen option, or the last. |
|
|
30
|
+
* | Home, End | Opens the list on the first or the last option. |
|
|
31
|
+
* | Left, Right | Chooses the option before or after the chosen one without opening, as React Aria's Select does, in either direction of text. |
|
|
32
|
+
* | A letter or a word | Chooses the option whose words start with what you typed, as a native `<select>` does. With `multiple`, opens the list on it. |
|
|
33
|
+
*
|
|
34
|
+
* In the open list, which is a `Listbox`:
|
|
35
|
+
*
|
|
36
|
+
* | Key | What it does |
|
|
37
|
+
* |---|---|
|
|
38
|
+
* | Down, Up, Home, End, Page Down, Page Up | Moves the highlight. |
|
|
39
|
+
* | A letter or a word | Moves the highlight to the next option whose words start with what you typed. |
|
|
40
|
+
* | Enter, Space | Chooses the highlighted option and closes the list. With `multiple`, toggles it and leaves the list open. |
|
|
41
|
+
* | Escape | Closes the list and puts focus back on the trigger. |
|
|
42
|
+
* | Tab | Closes the list and moves on. |
|
|
43
|
+
*
|
|
44
|
+
* A choice made on the closed trigger is said aloud on Apple devices, where
|
|
45
|
+
* VoiceOver does not read the trigger's new name.
|
|
46
|
+
*
|
|
47
|
+
* **ARIA.** The trigger is a `button` with `aria-haspopup="listbox"` and
|
|
48
|
+
* `aria-expanded`, named by the label and then the chosen words, as a native
|
|
49
|
+
* `<select>` is. The list is the listbox `Listbox` describes, named by the
|
|
50
|
+
* label, or by `list-label` where there is none.
|
|
51
|
+
*
|
|
52
|
+
* Set `autocomplete` to let a browser's autofill choose, as a native `<select>`
|
|
53
|
+
* with the same attribute would.
|
|
31
54
|
*
|
|
32
55
|
* @since 0.1.0
|
|
33
56
|
* @status stable
|
|
@@ -69,15 +92,31 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
|
|
|
69
92
|
* @csspart listbox-loading - The text shown while the options load.
|
|
70
93
|
* @csspart listbox-search - The region that holds the filter field.
|
|
71
94
|
* @csspart listbox-search-field - The filter field.
|
|
95
|
+
* @csspart live - The region a screen reader announces a choice made on the closed trigger from, drawn once there is one to say. Visually hidden in the styled tier.
|
|
72
96
|
* @csspart surface - The floating panel.
|
|
73
97
|
* @csspart trigger - The closed control, which shows the chosen value.
|
|
74
98
|
* @csspart value - The chosen option's text inside the trigger.
|
|
75
99
|
*
|
|
100
|
+
* @cssproperty --floating-anchor-inline-size - The trigger's width, written on the panel while it is open, as in `min-inline-size: var(--floating-anchor-inline-size)`. Read it; a value set here is written over.
|
|
101
|
+
* @cssproperty --floating-available-block-size - The room between the panel and the edge of the screen it opens toward, written on the panel while it is open. Read it; a value set here is written over.
|
|
102
|
+
*
|
|
76
103
|
* @cssstate invalid - The control has an error to show, from the browser's validation or from your `feedback`.
|
|
77
104
|
* @cssstate open - While the list is open.
|
|
78
105
|
*/
|
|
79
106
|
export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
80
107
|
protected readonly aria: AriaForwardController;
|
|
108
|
+
/** The region a choice made on the closed trigger is said from. */
|
|
109
|
+
private readonly status;
|
|
110
|
+
/**
|
|
111
|
+
* What a browser's autofill may fill in, as a platform token such as
|
|
112
|
+
* `country` or `cc-exp-month`, as on a native `<select>`.
|
|
113
|
+
*
|
|
114
|
+
* Set, the select keeps a hidden native `<select>` with the same options for
|
|
115
|
+
* the browser to fill, as React Aria's `HiddenSelect` does, and takes the
|
|
116
|
+
* option the browser picks, by its value or its words, as the value. Empty
|
|
117
|
+
* draws no hidden select, and a browser fills nothing.
|
|
118
|
+
*/
|
|
119
|
+
autocomplete: string;
|
|
81
120
|
/**
|
|
82
121
|
* The text shown when no options match the filter.
|
|
83
122
|
*/
|
|
@@ -89,6 +128,29 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
89
128
|
* the filtering, the empty state and the keyboard.
|
|
90
129
|
*/
|
|
91
130
|
filterable: boolean;
|
|
131
|
+
/**
|
|
132
|
+
* Whether the trigger holds its group's tab stop.
|
|
133
|
+
*
|
|
134
|
+
* A toolbar keeps one tab stop across its controls, and writing `tabindex`
|
|
135
|
+
* onto this element would change markup the consumer rendered, which a React
|
|
136
|
+
* consumer's hydration reports. A toolbar sets this property instead, and
|
|
137
|
+
* the stop moves on the trigger inside the shadow root, as Button's does.
|
|
138
|
+
*
|
|
139
|
+
* No attribute, because it is coordination between elements rather than
|
|
140
|
+
* anything a consumer sets.
|
|
141
|
+
*/
|
|
142
|
+
focusable: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* The open list's name where nothing names the Select, read by screen
|
|
145
|
+
* readers. The list has no visible name.
|
|
146
|
+
*
|
|
147
|
+
* A Select named by `label`, `aria-label`, `aria-labelledby` or a `<label>`
|
|
148
|
+
* gives its list that name, and this is not used. Unnamed, the Select is
|
|
149
|
+
* reported once by the missing-name warning, and its list is not reported a
|
|
150
|
+
* second time for a name the page never wrote: the list is this element's,
|
|
151
|
+
* and so is the fallback. Combobox calls its list the same.
|
|
152
|
+
*/
|
|
153
|
+
listLabel: string;
|
|
92
154
|
/**
|
|
93
155
|
* Whether the options are still loading.
|
|
94
156
|
*
|
|
@@ -109,6 +171,18 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
109
171
|
* Shown on the trigger while nothing is chosen.
|
|
110
172
|
*/
|
|
111
173
|
placeholder: string;
|
|
174
|
+
/**
|
|
175
|
+
* Where the list opens: `floating`, under the trigger and above it where
|
|
176
|
+
* there is no room, or `item-aligned`, over the trigger with the chosen
|
|
177
|
+
* option where the trigger is, as a native select does on macOS and Radix
|
|
178
|
+
* Select does by default.
|
|
179
|
+
*
|
|
180
|
+
* Over the trigger, a reader's eye stays on the answer as the list opens
|
|
181
|
+
* round it, and a short move reaches the options either side. Near an edge
|
|
182
|
+
* of the screen the list moves to stay on it, so the option may sit beside
|
|
183
|
+
* the trigger rather than on it. It follows the page as it scrolls.
|
|
184
|
+
*/
|
|
185
|
+
position: 'floating' | 'item-aligned';
|
|
112
186
|
/**
|
|
113
187
|
* What the trigger shows for the chosen options: a function given them, in
|
|
114
188
|
* the order they appear, that returns text, an element or a Lit template.
|
|
@@ -215,8 +289,26 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
215
289
|
private readonly handleLinkFollowed;
|
|
216
290
|
connectedCallback(): void;
|
|
217
291
|
disconnectedCallback(): void;
|
|
292
|
+
/**
|
|
293
|
+
* Puts the open list over the trigger, with the option it opened on where
|
|
294
|
+
* the trigger is, for `position="item-aligned"`.
|
|
295
|
+
*
|
|
296
|
+
* Measured once the list has drawn and scrolled to that option, and again as
|
|
297
|
+
* the page scrolls or the window changes size. The offset of the option in
|
|
298
|
+
* the list is read from the boxes on screen and divided by the list's scale,
|
|
299
|
+
* since a styled list opens from a little under full size. Written as the
|
|
300
|
+
* floating controller writes a position, so the same entrance runs and the
|
|
301
|
+
* controller takes it back on close.
|
|
302
|
+
*/
|
|
303
|
+
private readonly alignOver;
|
|
304
|
+
/** The option the open list was put over the trigger by. */
|
|
305
|
+
private alignedTo;
|
|
306
|
+
/** Stops following the page, once the list over the trigger closes. */
|
|
307
|
+
private stopAligning;
|
|
218
308
|
/** Opens the list with the highlight where the opening key says. */
|
|
219
309
|
private openAt;
|
|
310
|
+
/** Puts focus on the trigger, which is what a toolbar moving its stop here asks. */
|
|
311
|
+
focus(options?: FocusOptions): void;
|
|
220
312
|
/** Closes the list and puts focus back where it came from. */
|
|
221
313
|
private close;
|
|
222
314
|
private readonly handleChange;
|
|
@@ -227,9 +319,21 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
227
319
|
* Aria's Select do, so a reader who knows the answer types it. A Space in the
|
|
228
320
|
* middle of those letters is one of them. With `multiple`, a letter opens the
|
|
229
321
|
* list on the match instead, because adding to a set is a choice the reader
|
|
230
|
-
* makes in the list.
|
|
322
|
+
* makes in the list. ArrowLeft and ArrowRight choose the option before and
|
|
323
|
+
* after the chosen one.
|
|
231
324
|
*/
|
|
232
325
|
private readonly handleTriggerKeydown;
|
|
326
|
+
/**
|
|
327
|
+
* Chooses from the closed trigger, and says the choice on Apple devices.
|
|
328
|
+
*
|
|
329
|
+
* The trigger is named by the label and the chosen words, so a choice made
|
|
330
|
+
* on it renames the control in focus. VoiceOver does not read a name that
|
|
331
|
+
* changes under focus, so a reader there heard nothing as a letter or an
|
|
332
|
+
* arrow changed the answer. The words are said in a live region, as React
|
|
333
|
+
* Aria says a combobox's choice for VoiceOver alone, since other screen
|
|
334
|
+
* readers read the new name.
|
|
335
|
+
*/
|
|
336
|
+
private choose;
|
|
233
337
|
/**
|
|
234
338
|
* Tab closes the list and lets focus move on, as a native `<select>` does.
|
|
235
339
|
*
|
|
@@ -279,9 +383,9 @@ export declare class HelixHeadlessSelect extends HelixHeadlessSelect_base {
|
|
|
279
383
|
*/
|
|
280
384
|
protected renderIndicator(): TemplateResult;
|
|
281
385
|
/**
|
|
282
|
-
* What names the list once it opens
|
|
283
|
-
*
|
|
284
|
-
*
|
|
386
|
+
* What names the list once it opens, read through core's `hostWords` in
|
|
387
|
+
* the order a browser names the host: its `aria-labelledby`, its
|
|
388
|
+
* `aria-label`, the `label`, then a `<label>` for it.
|
|
285
389
|
*
|
|
286
390
|
* **Words rather than a reference**, because the list is inside another
|
|
287
391
|
* element's shadow root and neither an IDREF nor the host's labels reach it.
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { AriaForwardController, afterLinkFollowed, customElement,
|
|
7
|
+
import { AriaForwardController, afterLinkFollowed, customElement, drawAutofill, drawStatus, HelixFormElement, hostAria, hostWords, isRtl, MixinControllerOpen, MixinControllerValue, MixinField, onApple, PopoverController, reportValues, StatusController, typesCharacter, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { caretDown } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { nothing } from 'lit';
|
|
10
10
|
import { property } from 'lit/decorators.js';
|
|
@@ -12,6 +12,7 @@ import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
|
12
12
|
import { html } from 'lit/static-html.js';
|
|
13
13
|
import { optionsAmong } from '../../option/root/option-root.js';
|
|
14
14
|
import '../../listbox/index.js';
|
|
15
|
+
import { over } from '../align.js';
|
|
15
16
|
let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(MixinControllerValue(MixinField(HelixFormElement))) {
|
|
16
17
|
constructor() {
|
|
17
18
|
super(...arguments);
|
|
@@ -22,12 +23,17 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
22
23
|
},
|
|
23
24
|
target: () => this.partNamed('trigger'),
|
|
24
25
|
});
|
|
26
|
+
this.status = new StatusController(this);
|
|
27
|
+
this.autocomplete = '';
|
|
25
28
|
this.emptyText = 'No matches';
|
|
26
29
|
this.filterable = false;
|
|
30
|
+
this.focusable = true;
|
|
31
|
+
this.listLabel = 'Options';
|
|
27
32
|
this.loading = false;
|
|
28
33
|
this.loadingText = 'Loading';
|
|
29
34
|
this.multiple = false;
|
|
30
35
|
this.placeholder = 'Choose';
|
|
36
|
+
this.position = 'floating';
|
|
31
37
|
this.panel = new PopoverController(this, {
|
|
32
38
|
anchor: () => this.partNamed('trigger'),
|
|
33
39
|
boundary: () => [
|
|
@@ -37,6 +43,7 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
37
43
|
offset: () => 4,
|
|
38
44
|
onDismiss: () => this.close(),
|
|
39
45
|
open: () => this.open,
|
|
46
|
+
place: () => this.position !== 'item-aligned',
|
|
40
47
|
placement: 'bottom-start',
|
|
41
48
|
surface: () => this.partNamed('surface'),
|
|
42
49
|
});
|
|
@@ -46,6 +53,45 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
46
53
|
this.handleLinkFollowed = (event) => {
|
|
47
54
|
afterLinkFollowed(event, () => this.requestOpen(false));
|
|
48
55
|
};
|
|
56
|
+
this.alignOver = () => {
|
|
57
|
+
const surface = this.partNamed('surface');
|
|
58
|
+
const trigger = this.partNamed('trigger');
|
|
59
|
+
if (!this.open || this.position !== 'item-aligned' || !surface || !trigger) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const margin = 8;
|
|
63
|
+
const at = trigger.getBoundingClientRect();
|
|
64
|
+
surface.style.setProperty('--floating-anchor-inline-size', `${Math.round(at.width)}px`);
|
|
65
|
+
surface.style.setProperty('--floating-available-block-size', `${Math.max(0, window.innerHeight - margin * 2)}px`);
|
|
66
|
+
const shown = optionsAmong(this.knownChildren).filter((option) => !option.hidden);
|
|
67
|
+
this.alignedTo ??= shown.find((one) => one.active) ?? this.chosenOptions[0] ?? shown[0];
|
|
68
|
+
const option = this.alignedTo;
|
|
69
|
+
const box = surface.getBoundingClientRect();
|
|
70
|
+
const scale = surface.offsetHeight > 0 ? box.height / surface.offsetHeight : 1;
|
|
71
|
+
const row = option?.getBoundingClientRect();
|
|
72
|
+
const { left, top } = over({
|
|
73
|
+
margin,
|
|
74
|
+
option: row
|
|
75
|
+
? { height: row.height / scale, top: (row.top - box.top) / scale }
|
|
76
|
+
: { height: 0, top: 0 },
|
|
77
|
+
panel: { height: surface.offsetHeight, width: surface.offsetWidth },
|
|
78
|
+
rtl: isRtl(this),
|
|
79
|
+
trigger: at,
|
|
80
|
+
viewport: { height: window.innerHeight, width: window.innerWidth },
|
|
81
|
+
});
|
|
82
|
+
for (const [edge, value] of [
|
|
83
|
+
['bottom', 'auto'],
|
|
84
|
+
['left', '0'],
|
|
85
|
+
['right', 'auto'],
|
|
86
|
+
['top', '0'],
|
|
87
|
+
]) {
|
|
88
|
+
surface.style.setProperty(edge, value, 'important');
|
|
89
|
+
}
|
|
90
|
+
surface.style.position = 'fixed';
|
|
91
|
+
surface.style.translate = `${left}px ${top}px`;
|
|
92
|
+
surface.setAttribute('data-placed', '');
|
|
93
|
+
};
|
|
94
|
+
this.alignedTo = undefined;
|
|
49
95
|
this.handleChange = (event) => {
|
|
50
96
|
const next = event.detail.value;
|
|
51
97
|
if (!this.requestValue(next)) {
|
|
@@ -70,7 +116,17 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
70
116
|
this.requestOpen(true);
|
|
71
117
|
}
|
|
72
118
|
else {
|
|
73
|
-
this.
|
|
119
|
+
this.choose(match);
|
|
120
|
+
}
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const step = event.key === 'ArrowRight' ? 1 : event.key === 'ArrowLeft' ? -1 : 0;
|
|
124
|
+
if (step !== 0 && !this.multiple && !(event.altKey || event.ctrlKey || event.metaKey)) {
|
|
125
|
+
event.preventDefault();
|
|
126
|
+
const reachable = listbox?.options.filter((option) => !option.hidden && !option.disabled) ?? [];
|
|
127
|
+
const next = reachable[Math.max(0, reachable.findIndex((one) => one.value === this.value) + step)];
|
|
128
|
+
if (next) {
|
|
129
|
+
this.choose(next.value);
|
|
74
130
|
}
|
|
75
131
|
return;
|
|
76
132
|
}
|
|
@@ -107,12 +163,11 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
107
163
|
return this.partNamed('listbox');
|
|
108
164
|
}
|
|
109
165
|
get display() {
|
|
110
|
-
const chosen = new Set(this.value === '' ? [] : this.value.split(','));
|
|
111
166
|
const words = this.chosenOptions.map((option) => option.text);
|
|
112
167
|
if (words.length > 0) {
|
|
113
168
|
return new Intl.ListFormat(this.lang || undefined, { style: 'short', type: 'unit' }).format(words);
|
|
114
169
|
}
|
|
115
|
-
return
|
|
170
|
+
return this.value !== '' && !this.childrenKnown ? nothing : this.placeholder;
|
|
116
171
|
}
|
|
117
172
|
get chosenOptions() {
|
|
118
173
|
const chosen = new Set(this.value === '' ? [] : this.value.split(','));
|
|
@@ -138,16 +193,24 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
138
193
|
}
|
|
139
194
|
disconnectedCallback() {
|
|
140
195
|
super.disconnectedCallback();
|
|
196
|
+
this.stopAligning();
|
|
141
197
|
this.removeEventListener('helix-select', this.handleLinkFollowed);
|
|
142
198
|
for (const watcher of this.watchers) {
|
|
143
199
|
watcher.disconnect();
|
|
144
200
|
}
|
|
145
201
|
this.watchers = [];
|
|
146
202
|
}
|
|
203
|
+
stopAligning() {
|
|
204
|
+
window.removeEventListener('resize', this.alignOver);
|
|
205
|
+
window.removeEventListener('scroll', this.alignOver, { capture: true });
|
|
206
|
+
}
|
|
147
207
|
openAt(where) {
|
|
148
208
|
this.opening = where;
|
|
149
209
|
this.requestOpen(true);
|
|
150
210
|
}
|
|
211
|
+
focus(options) {
|
|
212
|
+
this.partNamed('trigger')?.focus(options);
|
|
213
|
+
}
|
|
151
214
|
close() {
|
|
152
215
|
if (!this.open) {
|
|
153
216
|
return;
|
|
@@ -155,6 +218,11 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
155
218
|
this.requestOpen(false);
|
|
156
219
|
this.partNamed('trigger')?.focus();
|
|
157
220
|
}
|
|
221
|
+
choose(value) {
|
|
222
|
+
if (this.requestValue(value) && onApple()) {
|
|
223
|
+
this.status.say(String(this.display));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
158
226
|
reconcileOptions() {
|
|
159
227
|
const options = optionsAmong(this.knownChildren);
|
|
160
228
|
if (this.defaultValue === '' && !this.hasAttribute('default-value')) {
|
|
@@ -202,9 +270,16 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
202
270
|
this.listbox?.highlight(this.opening);
|
|
203
271
|
this.opening = 'selected';
|
|
204
272
|
this.listbox?.focus();
|
|
273
|
+
if (this.position === 'item-aligned') {
|
|
274
|
+
this.alignedTo = undefined;
|
|
275
|
+
void this.listbox?.updateComplete.then(() => this.alignOver());
|
|
276
|
+
window.addEventListener('resize', this.alignOver);
|
|
277
|
+
window.addEventListener('scroll', this.alignOver, { capture: true, passive: true });
|
|
278
|
+
}
|
|
205
279
|
}
|
|
206
280
|
}
|
|
207
281
|
else {
|
|
282
|
+
this.stopAligning();
|
|
208
283
|
this.listbox?.requestFilter('');
|
|
209
284
|
}
|
|
210
285
|
}
|
|
@@ -222,14 +297,13 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
222
297
|
?multiple=${this.multiple}
|
|
223
298
|
?filterable=${this.filterable}
|
|
224
299
|
manual
|
|
225
|
-
aria-label=${this.listName || nothing}
|
|
300
|
+
aria-label=${this.listName || this.listLabel || nothing}
|
|
226
301
|
@keydown=${this.handleListKeydown}
|
|
302
|
+
.chosenAgain=${() => this.close()}
|
|
227
303
|
@helix-before-change=${this.handleChange}
|
|
228
304
|
@change=${this.stopInner}
|
|
229
305
|
@input=${this.stopInner}
|
|
230
306
|
>
|
|
231
|
-
<!-- An option arriving or leaving changes no property, so this is what
|
|
232
|
-
schedules the update that rereads the trigger's words. -->
|
|
233
307
|
<slot @slotchange=${() => this.requestUpdate()}></slot>
|
|
234
308
|
</${this.tag('listbox')}>`;
|
|
235
309
|
}
|
|
@@ -241,16 +315,7 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
241
315
|
</slot>`;
|
|
242
316
|
}
|
|
243
317
|
get listName() {
|
|
244
|
-
|
|
245
|
-
if (own) {
|
|
246
|
-
return own;
|
|
247
|
-
}
|
|
248
|
-
const ids = (this.getAttribute('aria-labelledby') ?? '').split(/\s+/).filter(Boolean);
|
|
249
|
-
const named = ids.length > 0 ? ids.map((id) => elementById(this, id)) : [...(this.labels ?? [])];
|
|
250
|
-
return named
|
|
251
|
-
.map((one) => (one?.textContent ?? '').replace(/\s+/g, ' ').trim())
|
|
252
|
-
.filter(Boolean)
|
|
253
|
-
.join(' ');
|
|
318
|
+
return hostWords(this, this.label);
|
|
254
319
|
}
|
|
255
320
|
get triggerNames() {
|
|
256
321
|
const outside = (this.internals.labels?.length ?? 0) > 0 && !this.labeled;
|
|
@@ -270,30 +335,46 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
270
335
|
aria-expanded=${this.open ? 'true' : 'false'}
|
|
271
336
|
aria-describedby=${this.describedBy ?? nothing}
|
|
272
337
|
aria-invalid=${this.invalidity ?? nothing}
|
|
338
|
+
tabindex=${this.focusable ? nothing : '-1'}
|
|
273
339
|
?disabled=${this.isDisabled}
|
|
274
340
|
@click=${() => this.toggleOpen()}
|
|
275
341
|
@keydown=${this.handleTriggerKeydown}
|
|
276
342
|
>
|
|
277
343
|
<slot name="start"></slot>
|
|
278
344
|
<span part="value" id="value">${this.renderValue()}</span>
|
|
279
|
-
${''}
|
|
280
345
|
<slot name="end"></slot>
|
|
281
|
-
${''}
|
|
282
346
|
${this.renderIndicator()}
|
|
283
347
|
</button>
|
|
284
348
|
|
|
285
349
|
<div part="surface" popover="manual" ?hidden=${!this.open}>
|
|
286
350
|
${this.renderListbox()}
|
|
287
351
|
</div>
|
|
288
|
-
${this.renderHint()}${this.renderFeedback()}
|
|
352
|
+
${this.renderHint()}${this.renderFeedback()}${drawStatus(this.status)}
|
|
353
|
+
${drawAutofill({
|
|
354
|
+
autocomplete: this.autocomplete,
|
|
355
|
+
disabled: this.isDisabled,
|
|
356
|
+
multiple: this.multiple,
|
|
357
|
+
onFill: (value) => this.requestValue(value),
|
|
358
|
+
options: optionsAmong(this.knownChildren),
|
|
359
|
+
value: this.value,
|
|
360
|
+
})}`;
|
|
289
361
|
}
|
|
290
362
|
};
|
|
363
|
+
__decorate([
|
|
364
|
+
property()
|
|
365
|
+
], HelixHeadlessSelect.prototype, "autocomplete", void 0);
|
|
291
366
|
__decorate([
|
|
292
367
|
property({ attribute: 'empty-text' })
|
|
293
368
|
], HelixHeadlessSelect.prototype, "emptyText", void 0);
|
|
294
369
|
__decorate([
|
|
295
370
|
property({ reflect: true, type: Boolean })
|
|
296
371
|
], HelixHeadlessSelect.prototype, "filterable", void 0);
|
|
372
|
+
__decorate([
|
|
373
|
+
property({ attribute: false })
|
|
374
|
+
], HelixHeadlessSelect.prototype, "focusable", void 0);
|
|
375
|
+
__decorate([
|
|
376
|
+
property({ attribute: 'list-label' })
|
|
377
|
+
], HelixHeadlessSelect.prototype, "listLabel", void 0);
|
|
297
378
|
__decorate([
|
|
298
379
|
property({ reflect: true, type: Boolean })
|
|
299
380
|
], HelixHeadlessSelect.prototype, "loading", void 0);
|
|
@@ -306,6 +387,9 @@ __decorate([
|
|
|
306
387
|
__decorate([
|
|
307
388
|
property()
|
|
308
389
|
], HelixHeadlessSelect.prototype, "placeholder", void 0);
|
|
390
|
+
__decorate([
|
|
391
|
+
property()
|
|
392
|
+
], HelixHeadlessSelect.prototype, "position", void 0);
|
|
309
393
|
__decorate([
|
|
310
394
|
property({ attribute: false })
|
|
311
395
|
], HelixHeadlessSelect.prototype, "valueContent", void 0);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AriaForwardController, HelixFormElement } from '@fusion.dev/helix-core';
|
|
2
|
-
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
2
|
+
import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
declare const HelixHeadlessSlider_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
|
|
4
4
|
/**
|
|
5
5
|
* @summary A value chosen from a range by dragging.
|
|
@@ -77,7 +77,10 @@ declare const HelixHeadlessSlider_base: (new (...args: any[]) => import("@fusion
|
|
|
77
77
|
* @csspart marker-label - The value a mark stands at, when `marker-labels` is set.
|
|
78
78
|
* @csspart markers - The row of marks along the track.
|
|
79
79
|
* @csspart output - The current value, shown beside the track.
|
|
80
|
+
* @csspart tooltip - One thumb's value in a bubble beside it, under `tooltip`. It carries `data-thumb` on a range, `start` or `end`, and `--slider-at`, where its thumb is as a fraction of the track.
|
|
81
|
+
* @csspart tooltips - The layer over the track that holds the bubbles, under `tooltip`.
|
|
80
82
|
*
|
|
83
|
+
* @cssproperty --slider-at - Where a bubble's thumb is, as a fraction of the track, 0 to 1. Set on each `tooltip` part.
|
|
81
84
|
* @cssproperty --slider-fraction - The value as a fraction of the range, 0 to 1.
|
|
82
85
|
* @cssproperty --slider-from - Where the filled span starts, as a fraction of the track, 0 to 1: a range's lower thumb, or a single thumb's `origin`.
|
|
83
86
|
* @cssproperty --slider-marker-at - Where one marker sits, as a percentage of the track.
|
|
@@ -193,6 +196,13 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
|
|
|
193
196
|
showValue: boolean;
|
|
194
197
|
/** How far one press of an arrow key moves the thumb. */
|
|
195
198
|
step: number;
|
|
199
|
+
/**
|
|
200
|
+
* Whether each thumb shows its value in a bubble beside it, as Web
|
|
201
|
+
* Awesome's `with-tooltip`. The styled slider shows the bubbles while the
|
|
202
|
+
* slider is under the pointer or holds focus. They repeat what each thumb
|
|
203
|
+
* already reports, so a screen reader skips them.
|
|
204
|
+
*/
|
|
205
|
+
tooltip: boolean;
|
|
196
206
|
/**
|
|
197
207
|
* How many characters the readout has to be able to hold, widest case.
|
|
198
208
|
*
|
|
@@ -307,6 +317,13 @@ export declare class HelixHeadlessSlider extends HelixHeadlessSlider_base {
|
|
|
307
317
|
* such as `{value} degrees`. Empty announces the number alone.
|
|
308
318
|
*/
|
|
309
319
|
valueText: string;
|
|
320
|
+
/**
|
|
321
|
+
* A bubble for each thumb, under `tooltip`, saying its value where it is.
|
|
322
|
+
* After the thumbs, so a stylesheet can reach a bubble from a focused
|
|
323
|
+
* thumb, and hidden from the accessibility tree for the reason the readout
|
|
324
|
+
* is: each thumb already reports its value.
|
|
325
|
+
*/
|
|
326
|
+
protected renderTooltips(start: number, end: number): TemplateResult | typeof nothing;
|
|
310
327
|
protected render(): TemplateResult;
|
|
311
328
|
}
|
|
312
329
|
declare global {
|