@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.
Files changed (288) hide show
  1. package/custom-elements.json +9287 -1084
  2. package/dist/accordion/item/accordion-item.d.ts +43 -21
  3. package/dist/accordion/item/accordion-item.js +37 -11
  4. package/dist/accordion/root/accordion-root.d.ts +8 -2
  5. package/dist/accordion/root/accordion-root.js +6 -8
  6. package/dist/announcement/root/announcement-root.d.ts +66 -6
  7. package/dist/announcement/root/announcement-root.js +144 -13
  8. package/dist/area-chart/root/area-chart-root.d.ts +18 -1
  9. package/dist/area-chart/root/area-chart-root.js +14 -7
  10. package/dist/avatar/root/avatar-root.d.ts +31 -1
  11. package/dist/avatar/root/avatar-root.js +11 -1
  12. package/dist/badge/count.d.ts +14 -0
  13. package/dist/badge/count.js +20 -0
  14. package/dist/badge/root/badge-root.d.ts +57 -6
  15. package/dist/badge/root/badge-root.js +77 -8
  16. package/dist/bar-chart/root/bar-chart-root.js +11 -20
  17. package/dist/bar-chart/stack.d.ts +10 -0
  18. package/dist/bar-chart/stack.js +8 -0
  19. package/dist/blockquote/root/blockquote-root.d.ts +66 -8
  20. package/dist/blockquote/root/blockquote-root.js +85 -8
  21. package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +14 -0
  22. package/dist/breadcrumbs/breadcrumb/breadcrumb.js +12 -2
  23. package/dist/breadcrumbs/root/breadcrumbs-root.js +2 -2
  24. package/dist/button/root/button-root.d.ts +24 -38
  25. package/dist/button/root/button-root.js +6 -37
  26. package/dist/button/submitter.d.ts +27 -0
  27. package/dist/button/submitter.js +25 -0
  28. package/dist/button-group/arrows.d.ts +14 -0
  29. package/dist/button-group/arrows.js +10 -0
  30. package/dist/button-group/root/button-group-root.d.ts +141 -3
  31. package/dist/button-group/root/button-group-root.js +142 -2
  32. package/dist/canvas/edge-pan.d.ts +61 -0
  33. package/dist/canvas/edge-pan.js +63 -0
  34. package/dist/canvas/node/canvas-node.d.ts +12 -2
  35. package/dist/canvas/node/canvas-node.js +6 -2
  36. package/dist/canvas/root/canvas-document.d.ts +10 -0
  37. package/dist/canvas/root/canvas-document.js +1 -0
  38. package/dist/canvas/root/canvas-root.d.ts +107 -5
  39. package/dist/canvas/root/canvas-root.js +140 -36
  40. package/dist/canvas/snap.d.ts +42 -0
  41. package/dist/canvas/snap.js +32 -0
  42. package/dist/card/root/card-root.d.ts +12 -1
  43. package/dist/card/root/card-root.js +11 -4
  44. package/dist/carousel/root/carousel-root.d.ts +4 -3
  45. package/dist/carousel/root/carousel-root.js +2 -6
  46. package/dist/chat/root/chat-root.d.ts +28 -4
  47. package/dist/chat/root/chat-root.js +12 -7
  48. package/dist/checkbox/root/checkbox-root.js +5 -7
  49. package/dist/checkbox-group/root/checkbox-group-root.d.ts +13 -0
  50. package/dist/checkbox-group/root/checkbox-group-root.js +16 -7
  51. package/dist/checkbox-group/select-all.d.ts +9 -4
  52. package/dist/checkbox-group/select-all.js +1 -1
  53. package/dist/code-block/root/code-block-root.d.ts +41 -18
  54. package/dist/code-block/root/code-block-root.js +21 -6
  55. package/dist/color-input/root/color-input-root.d.ts +11 -0
  56. package/dist/color-input/root/color-input-root.js +12 -5
  57. package/dist/color-picker/channels.js +1 -2
  58. package/dist/color-picker/root/color-picker-root.d.ts +32 -24
  59. package/dist/color-picker/root/color-picker-root.js +99 -55
  60. package/dist/color-picker/wheel.d.ts +28 -0
  61. package/dist/color-picker/wheel.js +15 -0
  62. package/dist/combobox/root/combobox-root.d.ts +83 -11
  63. package/dist/combobox/root/combobox-root.js +81 -18
  64. package/dist/command/root/command-root.d.ts +7 -4
  65. package/dist/command/root/command-root.js +2 -19
  66. package/dist/copy-button/root/copy-button-root.d.ts +16 -1
  67. package/dist/copy-button/root/copy-button-root.js +7 -2
  68. package/dist/data-table/keys.d.ts +0 -18
  69. package/dist/data-table/keys.js +1 -11
  70. package/dist/data-table/root/data-table-root.js +29 -50
  71. package/dist/date-input/root/date-input-root.d.ts +8 -1
  72. package/dist/date-input/root/date-input-root.js +8 -5
  73. package/dist/date-picker/root/date-picker-root.d.ts +14 -9
  74. package/dist/date-picker/root/date-picker-root.js +21 -16
  75. package/dist/description-list/item/description-list-item.d.ts +22 -4
  76. package/dist/description-list/item/description-list-item.js +14 -4
  77. package/dist/divider/root/divider-root.d.ts +45 -16
  78. package/dist/divider/root/divider-root.js +28 -4
  79. package/dist/donut-chart/root/donut-chart-root.js +13 -6
  80. package/dist/donut-chart/slice-label.d.ts +35 -0
  81. package/dist/donut-chart/slice-label.js +11 -0
  82. package/dist/drawer/root/drawer-root.d.ts +4 -2
  83. package/dist/drawer/root/drawer-root.js +15 -3
  84. package/dist/drilldown/item/drilldown-item.d.ts +21 -1
  85. package/dist/drilldown/item/drilldown-item.js +38 -4
  86. package/dist/drilldown/root/drilldown-root.js +3 -2
  87. package/dist/element-events.generated.js +5 -1
  88. package/dist/empty/root/empty-root.d.ts +46 -2
  89. package/dist/empty/root/empty-root.js +50 -5
  90. package/dist/file-input/root/file-input-root.d.ts +34 -6
  91. package/dist/file-input/root/file-input-root.js +55 -21
  92. package/dist/file-input/status.d.ts +24 -0
  93. package/dist/file-input/status.js +11 -0
  94. package/dist/filter-input/chip/filter-chip.d.ts +23 -0
  95. package/dist/filter-input/chip/filter-chip.js +10 -2
  96. package/dist/filter-input/root/filter-input-root.d.ts +8 -0
  97. package/dist/filter-input/root/filter-input-root.js +17 -27
  98. package/dist/format-date/fields.d.ts +20 -0
  99. package/dist/format-date/fields.js +14 -0
  100. package/dist/format-date/options.d.ts +5 -5
  101. package/dist/format-date/options.js +10 -39
  102. package/dist/format-date/root/format-date-root.d.ts +53 -4
  103. package/dist/format-date/root/format-date-root.js +38 -50
  104. package/dist/graph/root/graph-root.d.ts +23 -5
  105. package/dist/graph/root/graph-root.js +17 -20
  106. package/dist/heatmap/root/buckets.d.ts +21 -0
  107. package/dist/heatmap/root/buckets.js +34 -0
  108. package/dist/heatmap/root/heatmap-root.d.ts +76 -3
  109. package/dist/heatmap/root/heatmap-root.js +105 -20
  110. package/dist/icon/index.d.ts +1 -1
  111. package/dist/icon/index.js +1 -1
  112. package/dist/icon/registry.d.ts +26 -1
  113. package/dist/icon/registry.js +12 -1
  114. package/dist/icon/root/icon-root.d.ts +13 -0
  115. package/dist/icon/root/icon-root.js +23 -2
  116. package/dist/icon/root/index.d.ts +1 -1
  117. package/dist/icon/root/index.js +1 -1
  118. package/dist/image/root/image-root.d.ts +20 -0
  119. package/dist/image/root/image-root.js +6 -1
  120. package/dist/input/root/input-root.d.ts +23 -2
  121. package/dist/input/root/input-root.js +12 -8
  122. package/dist/kbd/root/kbd-root.d.ts +20 -3
  123. package/dist/kbd/root/kbd-root.js +23 -50
  124. package/dist/legend/hidden-series.d.ts +10 -2
  125. package/dist/legend/hidden-series.js +5 -2
  126. package/dist/legend/root/legend-root.d.ts +25 -7
  127. package/dist/legend/root/legend-root.js +25 -26
  128. package/dist/lightbox/root/lightbox-root.d.ts +50 -5
  129. package/dist/lightbox/root/lightbox-root.js +76 -8
  130. package/dist/lightbox/zoom.d.ts +2 -0
  131. package/dist/lightbox/zoom.js +5 -3
  132. package/dist/line-chart/root/line-chart-root.d.ts +16 -0
  133. package/dist/line-chart/root/line-chart-root.js +10 -2
  134. package/dist/list/root/list-root.d.ts +10 -2
  135. package/dist/list/root/list-root.js +31 -24
  136. package/dist/list/selection.d.ts +17 -0
  137. package/dist/list/selection.js +16 -0
  138. package/dist/listbox/root/listbox-root.d.ts +125 -26
  139. package/dist/listbox/root/listbox-root.js +156 -166
  140. package/dist/map/marker/map-marker.d.ts +2 -1
  141. package/dist/map/root/map-root.d.ts +40 -2
  142. package/dist/map/root/map-root.js +64 -23
  143. package/dist/megamenu/hand-over.d.ts +75 -0
  144. package/dist/megamenu/hand-over.js +67 -0
  145. package/dist/megamenu/root/megamenu-root.d.ts +38 -14
  146. package/dist/megamenu/root/megamenu-root.js +29 -50
  147. package/dist/menu/item/menu-item.js +4 -4
  148. package/dist/menu/root/menu-root.d.ts +5 -2
  149. package/dist/meter/root/meter-root.d.ts +42 -0
  150. package/dist/meter/root/meter-root.js +33 -7
  151. package/dist/navigation/root/navigation-root.js +5 -8
  152. package/dist/notifications/group/notification-group.d.ts +8 -1
  153. package/dist/notifications/group/notification-group.js +12 -6
  154. package/dist/notifications/notification/notification.d.ts +12 -1
  155. package/dist/notifications/notification/notification.js +3 -1
  156. package/dist/notifications/root/notifications-root.d.ts +48 -3
  157. package/dist/notifications/root/notifications-root.js +36 -6
  158. package/dist/number-input/grain.d.ts +28 -0
  159. package/dist/number-input/grain.js +14 -0
  160. package/dist/number-input/root/number-input-root.d.ts +17 -1
  161. package/dist/number-input/root/number-input-root.js +29 -18
  162. package/dist/object-inspector/root/object-inspector-root.d.ts +17 -6
  163. package/dist/object-inspector/root/object-inspector-root.js +31 -20
  164. package/dist/option/index.d.ts +1 -0
  165. package/dist/option/index.js +1 -0
  166. package/dist/option/separator/option-separator.d.ts +30 -0
  167. package/dist/option/separator/option-separator.js +21 -0
  168. package/dist/outline/root/outline-root.d.ts +12 -0
  169. package/dist/outline/root/outline-root.js +5 -19
  170. package/dist/pagination/size/pagination-size.d.ts +6 -0
  171. package/dist/pagination/size/pagination-size.js +5 -3
  172. package/dist/pin-input/code.d.ts +51 -1
  173. package/dist/pin-input/code.js +37 -0
  174. package/dist/pin-input/root/pin-input-root.d.ts +98 -121
  175. package/dist/pin-input/root/pin-input-root.js +151 -156
  176. package/dist/popover/hide-outside.js +2 -9
  177. package/dist/popover/root/popover-root.d.ts +7 -1
  178. package/dist/popover/root/popover-root.js +9 -1
  179. package/dist/progress/root/progress-root.d.ts +27 -0
  180. package/dist/progress/root/progress-root.js +25 -7
  181. package/dist/qr-code/export.d.ts +19 -0
  182. package/dist/qr-code/export.js +14 -0
  183. package/dist/qr-code/name.d.ts +11 -0
  184. package/dist/qr-code/name.js +7 -0
  185. package/dist/qr-code/root/qr-code-root.d.ts +31 -9
  186. package/dist/qr-code/root/qr-code-root.js +29 -17
  187. package/dist/radio/group/radio-group.d.ts +15 -0
  188. package/dist/radio/root/radio-root.js +2 -2
  189. package/dist/rating/root/rating-root.d.ts +22 -9
  190. package/dist/rating/root/rating-root.js +15 -39
  191. package/dist/scatter-chart/measures.d.ts +22 -0
  192. package/dist/scatter-chart/measures.js +11 -0
  193. package/dist/scatter-chart/root/scatter-chart-root.d.ts +26 -0
  194. package/dist/scatter-chart/root/scatter-chart-root.js +21 -7
  195. package/dist/scroll-area/scrollbar.d.ts +0 -8
  196. package/dist/scroll-area/scrollbar.js +1 -1
  197. package/dist/select/align.d.ts +47 -0
  198. package/dist/select/align.js +7 -0
  199. package/dist/select/root/select-root.d.ts +115 -11
  200. package/dist/select/root/select-root.js +104 -20
  201. package/dist/slider/root/slider-root.d.ts +18 -1
  202. package/dist/slider/root/slider-root.js +22 -0
  203. package/dist/sparkline/readings.d.ts +30 -12
  204. package/dist/sparkline/readings.js +32 -15
  205. package/dist/sparkline/root/sparkline-root.d.ts +46 -3
  206. package/dist/sparkline/root/sparkline-root.js +60 -21
  207. package/dist/speed-dial/group/speed-dial-group.d.ts +48 -0
  208. package/dist/speed-dial/group/speed-dial-group.js +43 -0
  209. package/dist/speed-dial/index.d.ts +1 -0
  210. package/dist/speed-dial/index.js +1 -0
  211. package/dist/speed-dial/item/speed-dial-item.d.ts +27 -2
  212. package/dist/speed-dial/item/speed-dial-item.js +43 -5
  213. package/dist/speed-dial/long-press.d.ts +50 -0
  214. package/dist/speed-dial/long-press.js +48 -0
  215. package/dist/speed-dial/root/speed-dial-root.d.ts +86 -1
  216. package/dist/speed-dial/root/speed-dial-root.js +123 -6
  217. package/dist/splitter/root/splitter-root.d.ts +9 -2
  218. package/dist/splitter/root/splitter-root.js +18 -3
  219. package/dist/steps/root/steps-root.d.ts +8 -1
  220. package/dist/steps/root/steps-root.js +6 -1
  221. package/dist/steps/step/step.d.ts +1 -0
  222. package/dist/steps/step/step.js +1 -1
  223. package/dist/table/cell/table-cell.d.ts +8 -1
  224. package/dist/table/cell/table-cell.js +6 -2
  225. package/dist/table/column/table-column.d.ts +6 -0
  226. package/dist/table/column/table-column.js +5 -1
  227. package/dist/table/grid-controller.d.ts +117 -0
  228. package/dist/table/grid-controller.js +293 -0
  229. package/dist/table/root/table-root.d.ts +47 -3
  230. package/dist/table/root/table-root.js +93 -29
  231. package/dist/table/row/table-row.d.ts +36 -0
  232. package/dist/table/row/table-row.js +52 -2
  233. package/dist/tabs/root/tabs-root.d.ts +5 -3
  234. package/dist/tag/group/tag-group.d.ts +16 -4
  235. package/dist/tag/group/tag-group.js +23 -20
  236. package/dist/textarea/root/textarea-root.d.ts +14 -2
  237. package/dist/textarea/root/textarea-root.js +6 -7
  238. package/dist/time-input/root/time-input-root.d.ts +5 -1
  239. package/dist/time-input/root/time-input-root.js +10 -7
  240. package/dist/time-picker/root/time-picker-root.d.ts +12 -14
  241. package/dist/time-picker/root/time-picker-root.js +18 -23
  242. package/dist/toast/item/toast-item.d.ts +9 -6
  243. package/dist/toast/item/toast-item.js +1 -1
  244. package/dist/toast/root/toast-root.d.ts +40 -4
  245. package/dist/toast/root/toast-root.js +68 -16
  246. package/dist/toast/words.d.ts +12 -0
  247. package/dist/toast/words.js +25 -0
  248. package/dist/toggle/group/toggle-group.d.ts +29 -5
  249. package/dist/toggle/group/toggle-group.js +26 -43
  250. package/dist/toggle/root/toggle-root.js +2 -4
  251. package/dist/toolbar/root/toolbar-root.d.ts +52 -5
  252. package/dist/toolbar/root/toolbar-root.js +88 -13
  253. package/dist/tooltip/root/tooltip-root.d.ts +7 -1
  254. package/dist/tooltip/root/tooltip-root.js +10 -2
  255. package/dist/tour/root/tour-root.d.ts +15 -0
  256. package/dist/tour/root/tour-root.js +20 -1
  257. package/dist/tour/stop/tour-stop.d.ts +3 -0
  258. package/dist/tour/stop/tour-stop.js +3 -3
  259. package/dist/tree/root/tree-root.js +2 -2
  260. package/dist/trend/figure.d.ts +16 -0
  261. package/dist/trend/figure.js +8 -0
  262. package/dist/trend/root/trend-root.d.ts +41 -2
  263. package/dist/trend/root/trend-root.js +29 -3
  264. package/dist/video/root/extra-controls.d.ts +12 -0
  265. package/dist/video/root/extra-controls.js +6 -2
  266. package/dist/video/root/video-root.d.ts +16 -1
  267. package/dist/video/root/video-root.js +15 -1
  268. package/dist/video-playlist/root/video-playlist-root.d.ts +11 -1
  269. package/dist/video-playlist/root/video-playlist-root.js +3 -0
  270. package/dist/virtual-list/fill.d.ts +11 -0
  271. package/dist/virtual-list/fill.js +9 -0
  272. package/dist/virtual-list/keys.d.ts +16 -7
  273. package/dist/virtual-list/keys.js +17 -6
  274. package/dist/virtual-list/plan.d.ts +17 -1
  275. package/dist/virtual-list/plan.js +13 -2
  276. package/dist/virtual-list/root/virtual-list-root.d.ts +25 -3
  277. package/dist/virtual-list/root/virtual-list-root.js +53 -41
  278. package/lint.json +1 -1
  279. package/package.json +5 -5
  280. package/types/jsx.d.ts +4934 -954
  281. package/types/svelte.d.ts +2 -0
  282. package/types/vue.d.ts +946 -253
  283. package/dist/color-picker/swatches.d.ts +0 -12
  284. package/dist/color-picker/swatches.js +0 -26
  285. package/dist/rating/steps.d.ts +0 -7
  286. package/dist/rating/steps.js +0 -9
  287. package/dist/tooltip/focus-target.d.ts +0 -6
  288. 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.plottedColumns.indexOf(cell);
86
- return depth < 1 ? undefined : seriesIndex(depth - 1);
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 columns = this.plottedColumns;
97
- const [across, ...ups] = columns;
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]) => ({ depth, row, x: along(one), y: up(two) }))
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
- const clamp = (value, low, high) => Math.min(Math.max(value, low), high);
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
- * In the open list the arrow keys, Home, End, PageUp, PageDown and typed
25
- * letters move the highlight, and Enter, Space or a click chooses it and
26
- * closes the list. Tab closes the list and moves on. On the closed trigger,
27
- * ArrowDown, Enter and Space open the list on the chosen option, ArrowUp opens
28
- * it on the chosen or last option, Home and End open it on the first or last,
29
- * and typed letters choose the option whose words start with them, as a native
30
- * `<select>` does.
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: the `label`, the host's `aria-label`,
283
- * or the words of what names the host from outside, its `aria-labelledby`
284
- * or a `<label>` for it.
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, elementById, HelixFormElement, hostAria, MixinControllerOpen, MixinControllerValue, MixinField, PopoverController, reportValues, typesCharacter, } from '@fusion.dev/helix-core';
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.requestValue(match);
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 chosen.size > 0 && !this.childrenKnown ? nothing : this.placeholder;
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
- const own = this.label || this.getAttribute('aria-label');
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 {