@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
@@ -17,13 +17,33 @@ declare const HelixHeadlessCombobox_base: (new (...args: any[]) => import("@fusi
17
17
  * reopened combobox starts from the whole list.
18
18
  *
19
19
  * Focus stays in the text field. The arrow keys move through the list with the
20
- * listbox's public `navigate` method. `role="combobox"` is on the input itself.
21
- * ArrowDown and ArrowUp open the list on the chosen option, and Enter chooses
22
- * the highlighted one. As typing narrows the list, a screen reader hears how
23
- * many options are left, such as "3 results". Space, Home, End and letters edit the text, and Enter in
24
- * a closed field is left to the form. Emptying the field and leaving it clears
25
- * a single choice; Escape puts the chosen words back, and a second Escape on
26
- * the closed field clears the choice.
20
+ * listbox's public `navigate` method. As typing narrows the list, a screen
21
+ * reader hears how many options are left, such as "3 results". Emptying the
22
+ * field and leaving it clears a single choice.
23
+ *
24
+ * **Keyboard.**
25
+ *
26
+ * | Key | What it does |
27
+ * |---|---|
28
+ * | Down, Up | On a closed field, opens the list on the chosen option, or the first or the last. In the open list, moves the highlight, round from the last option to the first. |
29
+ * | Page Down, Page Up | In the open list, moves the highlight by as many options as the list shows at once. |
30
+ * | Enter | Chooses the highlighted option. With nothing left in the list, creates what was typed with `creatable`, or takes it with `allows-custom-value`. On a closed field, submits the form. |
31
+ * | Escape | Closes the list and puts the chosen words back. On a closed field, a second Escape clears a single choice. |
32
+ * | Tab | Closes the list and moves on. |
33
+ * | Backspace | With `multiple`, on an empty field, removes the last tag. |
34
+ * | Space, Home, End, letters | Edit the text. |
35
+ *
36
+ * **ARIA.** The input is the `combobox`, named by the label, with
37
+ * `aria-expanded`, `aria-controls` naming the list, `aria-autocomplete`
38
+ * (`both` with `suggest`, `list` otherwise) and `aria-activedescendant` on
39
+ * the highlighted option. The list is the listbox `Listbox` describes.
40
+ *
41
+ * On Apple devices, where VoiceOver does not read the option the field points
42
+ * to, the field says it in a live region as the highlight moves, says how many
43
+ * options there are as the list opens, and says a choice once it is made, as
44
+ * React Aria's combobox does there.
45
+ *
46
+ * Set `autocomplete` to let a browser's autofill choose an option.
27
47
  *
28
48
  * With `multiple`, each chosen option is a tag in the field with its own remove
29
49
  * control. The panel stays open and the filter clears after each choice, so the
@@ -83,6 +103,7 @@ declare const HelixHeadlessCombobox_base: (new (...args: any[]) => import("@fusi
83
103
  * @csspart listbox-loading - Shown while the options are loading.
84
104
  * @csspart listbox-search - The region holding the field that narrows the list.
85
105
  * @csspart listbox-search-field - The filter field inside that region.
106
+ * @csspart live - The region VoiceOver hears the highlight, the count and a choice from on Apple devices, drawn once there is one to say. Visually hidden in the styled tier.
86
107
  * @csspart rest - The count of choices held beyond `max-tags`. A `<button>` with `expandable`, a `<span>` without it.
87
108
  * @csspart surface - The floating panel.
88
109
  * @csspart tag - One chosen option.
@@ -94,11 +115,22 @@ declare const HelixHeadlessCombobox_base: (new (...args: any[]) => import("@fusi
94
115
  * @csspart tag-start - The category before the label.
95
116
  * @csspart tags - The row of chosen options, when `multiple` is set.
96
117
  *
118
+ * @cssstate blank - While nothing is chosen.
119
+ * @cssstate error - While `load-error` is set.
97
120
  * @cssstate invalid - The control has an error to show, from the browser's validation or from your `feedback`.
121
+ * @cssstate loading - While `loading` is set.
122
+ * @cssstate no-results - What was typed hid every option of a list that has some.
98
123
  * @cssstate open - While the list is open.
99
124
  */
100
125
  export declare class HelixHeadlessCombobox extends HelixHeadlessCombobox_base {
101
126
  protected readonly aria: AriaForwardController;
127
+ /** The region VoiceOver hears the highlight, the count and a choice from. */
128
+ private readonly status;
129
+ /**
130
+ * The option, or the create row, the region last said: `null` for none,
131
+ * and `undefined` until it has spoken since the list opened.
132
+ */
133
+ private told;
102
134
  /**
103
135
  * Whether text that names no option is taken as the value, as React Aria's
104
136
  * `allowsCustomValue`.
@@ -111,12 +143,19 @@ export declare class HelixHeadlessCombobox extends HelixHeadlessCombobox_base {
111
143
  */
112
144
  allowsCustomValue: boolean;
113
145
  /**
114
- * What the browser may autofill in the text field, as a platform token.
146
+ * What the browser may autofill, as a platform token such as `country`.
115
147
  *
116
148
  * **Defaults to `off`, which is not the platform's default and is the
117
149
  * point.** The field filters a list rather than collecting a value, so a
118
150
  * browser offering to fill it with a saved address is competing for the same
119
151
  * keystrokes as the listbox. A consumer who wants autofill can still ask.
152
+ *
153
+ * Set, a combobox whose answer is one of its options keeps a hidden native
154
+ * `<select>` with the same options for the browser to fill, as React Aria's
155
+ * combobox and Select do, and the option the browser picks, by its value or
156
+ * its words, becomes the value. The text field itself stays `off`, so the
157
+ * browser fills the answer and not the filter. With `allows-custom-value`
158
+ * the token goes on the text field, whose words are the answer.
120
159
  */
121
160
  autocomplete: string;
122
161
  /**
@@ -153,10 +192,11 @@ export declare class HelixHeadlessCombobox extends HelixHeadlessCombobox_base {
153
192
  listLabel: string;
154
193
  /**
155
194
  * What the list says when its options could not be loaded, such as after a
156
- * request to a server fails. Empty is no error. Passed to the list, which
157
- * shows it under any options there are and tells screen readers.
195
+ * request to a server fails. Empty, null or no attribute is no error, so
196
+ * removing the attribute clears it. Passed to the list, which shows it
197
+ * under any options there are and tells screen readers.
158
198
  */
159
- loadError: string;
199
+ loadError: string | null;
160
200
  /**
161
201
  * Whether the options are still loading.
162
202
  *
@@ -234,6 +274,11 @@ export declare class HelixHeadlessCombobox extends HelixHeadlessCombobox_base {
234
274
  * two.
235
275
  */
236
276
  resultsLabel: string;
277
+ /**
278
+ * What VoiceOver hears for a chosen option, as the highlight reaches it and
279
+ * once it is chosen, on Apple devices. `{name}` is the option's words.
280
+ */
281
+ selectedLabel: string;
237
282
  /**
238
283
  * Whether the field completes the word as the user types.
239
284
  *
@@ -334,6 +379,17 @@ export declare class HelixHeadlessCombobox extends HelixHeadlessCombobox_base {
334
379
  * is a thing a consumer may do.
335
380
  */
336
381
  private get showing();
382
+ /**
383
+ * The list's `error` and `no-results` states on the host too, so a page
384
+ * styles the whole control from them, as WA's combobox and its status slots
385
+ * allow. The list keeps its own, which only a stylesheet inside this shadow
386
+ * root could reach.
387
+ *
388
+ * Read once the list has drawn the filter, since `hidden` is what the
389
+ * filter writes onto an option: a filter that hid every option of a list
390
+ * that has some, with nothing loading.
391
+ */
392
+ private markStatus;
337
393
  /**
338
394
  * What the create row would add, or nothing where there is nothing to add.
339
395
  *
@@ -446,6 +502,20 @@ export declare class HelixHeadlessCombobox extends HelixHeadlessCombobox_base {
446
502
  * is missing.
447
503
  */
448
504
  private linkActive;
505
+ /**
506
+ * Says the highlight, and the count as the list opens, where VoiceOver
507
+ * would not.
508
+ *
509
+ * **VoiceOver does not read the option `aria-activedescendant` points to**
510
+ * while focus is in a text field, so on Apple devices the arrows moved
511
+ * through the list in silence. React Aria says the option there, with
512
+ * "selected" where it is chosen, and how many there are as the list opens.
513
+ * Only when the highlight moves to another option, so an update that leaves
514
+ * it where it was says nothing.
515
+ */
516
+ private tell;
517
+ /** How many options there are, said as the list opens, until an option is said with it. */
518
+ private counted;
449
519
  /**
450
520
  * Takes what the list announced and stops it there.
451
521
  *
@@ -552,6 +622,8 @@ export declare class HelixHeadlessCombobox extends HelixHeadlessCombobox_base {
552
622
  */
553
623
  private renderCreate;
554
624
  protected render(): TemplateResult;
625
+ /** Whether a browser's autofill fills the hidden select, rather than the text field. */
626
+ private get fills();
555
627
  }
556
628
  declare global {
557
629
  interface HTMLElementTagNameMap {
@@ -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, DelayController, fillTemplate, HelixCreateEvent, HelixFilterEvent, HelixFormElement, MixinControllerOpen, MixinControllerValue, MixinField, MixinTokens, PopoverController, reportValues, submitImplicitly, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, afterLinkFollowed, countLabel, customElement, DelayController, drawAutofill, drawStatus, fillTemplate, HelixCreateEvent, HelixFilterEvent, HelixFormElement, MixinControllerOpen, MixinControllerValue, MixinField, MixinTokens, onApple, PopoverController, reportValues, StatusController, submitImplicitly, } from '@fusion.dev/helix-core';
8
8
  import { caretDown } from '@fusion.dev/helix-icons';
9
9
  import { nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -21,6 +21,8 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
21
21
  this.aria = new AriaForwardController(this, {
22
22
  target: () => this.partNamed('control'),
23
23
  });
24
+ this.status = new StatusController(this);
25
+ this.told = undefined;
24
26
  this.allowsCustomValue = false;
25
27
  this.autocomplete = 'off';
26
28
  this.creatable = false;
@@ -38,6 +40,7 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
38
40
  this.removeLabel = 'Remove {name}';
39
41
  this.resultLabel = '{count} result';
40
42
  this.resultsLabel = '{count} results';
43
+ this.selectedLabel = '{name}, selected';
41
44
  this.suggest = false;
42
45
  this.typed = '';
43
46
  this.suggestion = '';
@@ -166,12 +169,17 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
166
169
  submitImplicitly(this.form);
167
170
  }
168
171
  };
172
+ this.counted = '';
169
173
  this.handleChange = (event) => {
170
174
  event.stopPropagation();
171
175
  const { value } = event.detail;
172
176
  if (!this.requestValue(value)) {
173
177
  return;
174
178
  }
179
+ const chosen = this.listbox?.options.find((option) => option.value === value);
180
+ if (chosen && onApple()) {
181
+ this.status.say(fillTemplate(this.selectedLabel, { name: chosen.text }));
182
+ }
175
183
  this.emptied = false;
176
184
  this.typed = '';
177
185
  this.suggestion = '';
@@ -245,6 +253,17 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
245
253
  get showing() {
246
254
  return (this.listbox?.options ?? []).some((option) => !option.hidden);
247
255
  }
256
+ markStatus() {
257
+ const list = this.listbox;
258
+ this.toggleState('blank', this.value === '');
259
+ this.toggleState('loading', this.loading);
260
+ this.toggleState('error', Boolean(this.loadError));
261
+ this.toggleState('no-results', list !== null &&
262
+ !this.loading &&
263
+ list.filter !== '' &&
264
+ list.options.length > 0 &&
265
+ !this.showing);
266
+ }
248
267
  get creation() {
249
268
  const typed = this.typed.trim();
250
269
  if (!this.creatable || typed === '') {
@@ -353,7 +372,10 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
353
372
  const narrowing = new HelixFilterEvent({ value: typed });
354
373
  if (this.dispatchEvent(narrowing)) {
355
374
  this.listbox?.requestFilter(typed);
356
- void this.listbox?.updateComplete.then(() => this.linkActive());
375
+ void this.listbox?.updateComplete.then(() => {
376
+ this.linkActive();
377
+ this.markStatus();
378
+ });
357
379
  }
358
380
  this.suggestion = this.suggest && inserted ? this.completionFor(typed) : '';
359
381
  }
@@ -370,16 +392,47 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
370
392
  }
371
393
  linkActive() {
372
394
  const control = this.partNamed('control');
373
- if (!control || !('ariaActiveDescendantElement' in control)) {
374
- return;
375
- }
376
395
  const active = !this.open
377
396
  ? undefined
378
397
  : this.onCreate
379
398
  ? this.partNamed('create')
380
399
  : (this.listbox?.options ?? []).find((option) => option.active && !option.hidden);
400
+ this.tell(active);
401
+ if (!control || !('ariaActiveDescendantElement' in control)) {
402
+ return;
403
+ }
404
+ ;
381
405
  control.ariaActiveDescendantElement = active ?? null;
382
406
  }
407
+ tell(active) {
408
+ if (!this.open) {
409
+ this.told = undefined;
410
+ return;
411
+ }
412
+ if ((active ?? null) === this.told ||
413
+ !onApple() ||
414
+ this.renderRoot.activeElement !== this.partNamed('control')) {
415
+ return;
416
+ }
417
+ if (this.listbox?.isUpdatePending) {
418
+ void this.listbox.updateComplete.then(() => this.linkActive());
419
+ return;
420
+ }
421
+ if (this.told === undefined) {
422
+ this.counted = countLabel(this.reachable.length, this.resultLabel, this.resultsLabel, this.lang);
423
+ }
424
+ this.told = active ?? null;
425
+ const option = active;
426
+ const words = option?.text === undefined
427
+ ? (active?.textContent?.trim() ?? '')
428
+ : option.selected
429
+ ? fillTemplate(this.selectedLabel, { name: option.text })
430
+ : option.text;
431
+ this.status.say([this.counted, words].filter(Boolean).join('. '));
432
+ if (active) {
433
+ this.counted = '';
434
+ }
435
+ }
383
436
  removeLastToken() {
384
437
  const last = this.values.at(-1);
385
438
  if (last !== undefined) {
@@ -434,6 +487,7 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
434
487
  super.updated?.(changed);
435
488
  this.sync();
436
489
  this.linkActive();
490
+ void (this.listbox?.updateComplete ?? Promise.resolve()).then(() => this.markStatus());
437
491
  const control = this.partNamed('control');
438
492
  const wanted = this.fieldText;
439
493
  if (control && control.value !== wanted) {
@@ -455,7 +509,11 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
455
509
  this.opening = undefined;
456
510
  void this.listbox?.updateComplete.then(() => this.linkActive());
457
511
  }
458
- if (control && !this.editing && !this.multiple && control.value !== '') {
512
+ if (control &&
513
+ !this.editing &&
514
+ !this.multiple &&
515
+ control.value !== '' &&
516
+ this.renderRoot.activeElement === control) {
459
517
  control.select();
460
518
  }
461
519
  }
@@ -484,25 +542,16 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
484
542
  ?loading=${this.loading}
485
543
  ?multiple=${this.multiple}
486
544
  .value=${this.value}
545
+ .chosenAgain=${() => this.close()}
487
546
  @helix-before-change=${this.handleChange}
488
547
  @change=${this.stopInner}
489
548
  @helix-filter=${this.stopInner}
490
549
  @input=${this.stopInner}
491
550
  >
492
- <!-- The field's words are read off the options, and on the first
493
- render there are none: the slot has not been assigned yet, so a
494
- combobox with a value comes up empty. Assignment changes no
495
- property, so nothing else would schedule the update that fixes
496
- it. -->
497
551
  <slot @slotchange=${() => this.requestUpdate()}></slot>
498
- <!-- Handed on to the list's own, with the text as this slot's fallback:
499
- a slot passed into another is assigned there whether or not anything
500
- fills it, so the list's fallback would never show. -->
501
552
  <slot name="empty" slot="empty">${this.emptyText}</slot>
502
553
  <slot name="loading" slot="loading">${this.loadingText}</slot>
503
554
  <slot name="error" slot="error">${this.loadError}</slot>
504
- <!-- Handed on only while something fills it: an assigned slot hides the
505
- list's own fallback, which is no-results-text or empty-text. -->
506
555
  <slot
507
556
  name="no-results"
508
557
  slot=${this.querySelector?.(':scope > [slot="no-results"]') ? 'no-results' : nothing}
@@ -552,7 +601,7 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
552
601
  id=${this.controlId}
553
602
  type="text"
554
603
  role="combobox"
555
- autocomplete=${this.autocomplete || nothing}
604
+ autocomplete=${(this.fills ? 'off' : this.autocomplete) || nothing}
556
605
  spellcheck="false"
557
606
  aria-controls="listbox"
558
607
  aria-autocomplete=${this.suggest ? 'both' : 'list'}
@@ -575,7 +624,18 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
575
624
  ${this.renderListbox()}
576
625
  ${this.renderCreate()}
577
626
  </div>
578
- ${this.renderHint()}${this.renderFeedback()}`;
627
+ ${this.renderHint()}${this.renderFeedback()}${drawStatus(this.status)}
628
+ ${drawAutofill({
629
+ autocomplete: this.fills ? this.autocomplete : '',
630
+ disabled: this.isDisabled || this.readOnly,
631
+ multiple: this.multiple,
632
+ onFill: (value) => this.requestValue(value),
633
+ options: optionsAmong(this.knownChildren),
634
+ value: this.value,
635
+ })}`;
636
+ }
637
+ get fills() {
638
+ return !this.allowsCustomValue && this.autocomplete !== 'off' && this.autocomplete !== '';
579
639
  }
580
640
  };
581
641
  __decorate([
@@ -632,6 +692,9 @@ __decorate([
632
692
  __decorate([
633
693
  property({ attribute: 'results-label' })
634
694
  ], HelixHeadlessCombobox.prototype, "resultsLabel", void 0);
695
+ __decorate([
696
+ property({ attribute: 'selected-label' })
697
+ ], HelixHeadlessCombobox.prototype, "selectedLabel", void 0);
635
698
  __decorate([
636
699
  property({ type: Boolean })
637
700
  ], HelixHeadlessCombobox.prototype, "suggest", void 0);
@@ -81,7 +81,9 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
81
81
  */
82
82
  filterDelay: number;
83
83
  /**
84
- * The key that opens the palette, written as `mod+k`, `shift+p`, or `k`.
84
+ * The key that opens the palette, written as `mod+k`, `shift+p`, or `k`,
85
+ * in Kbd's chord spelling: `mod` is Command or Control, `ctrl`, `cmd`,
86
+ * `alt` and `shift` the keys they name.
85
87
  *
86
88
  * Empty turns it off, for a consumer who opens the palette from a button or
87
89
  * from their own shortcut handler. There is no list of defaults to fight
@@ -94,10 +96,11 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
94
96
  label: string;
95
97
  /**
96
98
  * What the list says when its commands could not be loaded, such as after a
97
- * request to a server fails. Empty is no error. Passed to the list, which
98
- * shows it under any commands there are and tells screen readers.
99
+ * request to a server fails. Empty, null or no attribute is no error, so
100
+ * removing the attribute clears it. Passed to the list, which shows it
101
+ * under any commands there are and tells screen readers.
99
102
  */
100
- loadError: string;
103
+ loadError: string | null;
101
104
  /**
102
105
  * Whether the commands are still loading, for a palette that asks a server
103
106
  * for them as the user types.
@@ -4,21 +4,12 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, HelixElement, HelixSelectEvent, MixinControllerOpen, } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixElement, HelixSelectEvent, MixinControllerOpen, matchesChord, } from '@fusion.dev/helix-core';
8
8
  import { nothing } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
10
  import { html } from 'lit/static-html.js';
11
11
  import '../../dialog/index.js';
12
12
  import '../../listbox/index.js';
13
- const parse = (hotkey) => {
14
- const parts = hotkey.toLowerCase().split('+');
15
- return {
16
- alt: parts.includes('alt'),
17
- key: parts.at(-1) ?? '',
18
- mod: parts.includes('mod'),
19
- shift: parts.includes('shift'),
20
- };
21
- };
22
13
  let HelixHeadlessCommand = class HelixHeadlessCommand extends MixinControllerOpen(HelixElement) {
23
14
  constructor() {
24
15
  super(...arguments);
@@ -34,15 +25,7 @@ let HelixHeadlessCommand = class HelixHeadlessCommand extends MixinControllerOpe
34
25
  this.resultsLabel = '{count} commands';
35
26
  this.footed = false;
36
27
  this.handleHotkey = (event) => {
37
- if (this.hotkey === '') {
38
- return;
39
- }
40
- const wanted = parse(this.hotkey);
41
- const mod = event.metaKey || event.ctrlKey;
42
- if (event.key.toLowerCase() !== wanted.key ||
43
- mod !== wanted.mod ||
44
- event.shiftKey !== wanted.shift ||
45
- event.altKey !== wanted.alt) {
28
+ if (!matchesChord(event, this.hotkey, true) && !matchesChord(event, this.hotkey, false)) {
46
29
  return;
47
30
  }
48
31
  event.preventDefault();
@@ -1,4 +1,4 @@
1
- import { type TemplateResult } from 'lit';
1
+ import { type PropertyValues, type TemplateResult } from 'lit';
2
2
  import { HelixHeadlessIconButton } from '../../icon-button/root/icon-button-root.js';
3
3
  import '../../tooltip/index.js';
4
4
  /**
@@ -26,6 +26,12 @@ import '../../tooltip/index.js';
26
26
  * rendered. An `aria-label` on the element names it before a copy, in place of
27
27
  * `label`.
28
28
  *
29
+ * **Keyboard.** Enter and Space copy, as they press a native button.
30
+ *
31
+ * The button is named `label`, or the host's `aria-label`, and its name
32
+ * changes to `copied-label` or `error-label` for the moment after a press,
33
+ * which is what a screen reader on it hears. The tooltip shows the same words.
34
+ *
29
35
  * @since 0.1.0
30
36
  * @status stable
31
37
  * @category actions
@@ -42,6 +48,7 @@ import '../../tooltip/index.js';
42
48
  * @csspart button - The inner button.
43
49
  * @csspart live - The live region that says `pending-label` when the button becomes pending under focus. It is rendered from the first time the button is pending.
44
50
  * @csspart mark - The clipboard icon, and the confirmation icon that replaces it.
51
+ * @csspart spinner - The ring a pending button turns, an empty element the styled button draws over the icon. It is rendered only while the button is pending.
45
52
  * @csspart tooltip - The tooltip bubble, forwarded from the tooltip inside the button.
46
53
  * @csspart tooltip-arrow - The tooltip's arrow, which points at the button.
47
54
  * @csspart tooltip-arrow-bottom - The arrow while the bubble is below the button, on the bubble's top edge. Set together with `tooltip-arrow`.
@@ -52,6 +59,13 @@ import '../../tooltip/index.js';
52
59
  * @csspart tooltip-left - The bubble while it is left of the button. Set together with `tooltip`.
53
60
  * @csspart tooltip-right - The bubble while it is right of the button. Set together with `tooltip`.
54
61
  * @csspart tooltip-top - The bubble while it is above the button. Set together with `tooltip`.
62
+ *
63
+ * @cssstate copied - The moment after a successful copy, while `copied-label` names the button.
64
+ * @cssstate failed - The moment after a press that put nothing on the clipboard, while `error-label` names the button.
65
+ *
66
+ * @withheld csspart text - Button's words, which this does not render: the label is the icon's name.
67
+ * @withheld slot end - Button's, which this does not render.
68
+ * @withheld slot start - Button's, which this does not render.
55
69
  */
56
70
  export declare class HelixHeadlessCopyButton extends HelixHeadlessIconButton {
57
71
  /**
@@ -135,6 +149,7 @@ export declare class HelixHeadlessCopyButton extends HelixHeadlessIconButton {
135
149
  * cover the confirmation.
136
150
  */
137
151
  protected get forwardsLabel(): boolean;
152
+ protected willUpdate(changed: PropertyValues): void;
138
153
  /** @internal A copy button never submits, so it is no form's default button. */
139
154
  protected get submitsForm(): boolean;
140
155
  /**
@@ -24,7 +24,7 @@ let HelixHeadlessCopyButton = HelixHeadlessCopyButton_1 = class HelixHeadlessCop
24
24
  this.label = 'Copy';
25
25
  this.value = '';
26
26
  this.namedBy = null;
27
- this.clipboard = new CopyController(this, Object.defineProperty({}, 'after', { get: () => this.feedbackDuration }));
27
+ this.clipboard = new CopyController(this, { after: () => this.feedbackDuration });
28
28
  this.handleCopy = async (event) => {
29
29
  if (this.pending) {
30
30
  event.preventDefault();
@@ -51,6 +51,11 @@ let HelixHeadlessCopyButton = HelixHeadlessCopyButton_1 = class HelixHeadlessCop
51
51
  get forwardsLabel() {
52
52
  return false;
53
53
  }
54
+ willUpdate(changed) {
55
+ super.willUpdate(changed);
56
+ this.toggleState('copied', this.copied);
57
+ this.toggleState('failed', this.failed);
58
+ }
54
59
  get submitsForm() {
55
60
  return false;
56
61
  }
@@ -83,7 +88,7 @@ let HelixHeadlessCopyButton = HelixHeadlessCopyButton_1 = class HelixHeadlessCop
83
88
  @keydown=${this.notePress}
84
89
  @pointerdown=${this.notePress}
85
90
  >
86
- ${this.renderCopiedIcon()} ${this.renderFailedIcon()} ${this.renderCopyIcon()}
91
+ ${this.renderCopiedIcon()} ${this.renderFailedIcon()} ${this.renderCopyIcon()}${this.renderSpinner()}
87
92
  </button>`)}${this.renderLive()}`;
88
93
  }
89
94
  renderCopyIcon() {
@@ -1,24 +1,6 @@
1
- /**
2
- * `keys` in the order the rows are, which is `order`: the keys of the whole
3
- * result. A key the result does not hold, a selected row a search has hidden
4
- * say, keeps its place after them in the order it was given.
5
- *
6
- * So `selected` and `expanded`, and the events that carry them, read in row
7
- * order whatever order the rows were chosen in.
8
- */
9
- export declare const inRowOrder: (keys: Iterable<string>, order: readonly string[]) => string[];
10
1
  /**
11
2
  * The `expanded` a toggle of row `key` leaves, in row order, or `undefined`
12
3
  * where the row is open or closed already. Keys are split on commas only, so a
13
4
  * key may hold a space.
14
5
  */
15
6
  export declare const toggledOpen: (expanded: string, key: string, open: boolean, order: readonly string[]) => string | undefined;
16
- /**
17
- * Where a Shift range runs from, as an index into the page's `keys`: the row
18
- * last chosen while it is on the page, and otherwise the row the reader is on,
19
- * `from`, which becomes the one to run from.
20
- */
21
- export declare const anchorAt: (keys: readonly string[], anchorKey: string | undefined, from: number) => {
22
- anchor: number;
23
- anchorKey: string | undefined;
24
- };
@@ -1,10 +1,4 @@
1
- import { commaList } from '@fusion.dev/helix-core';
2
- export const inRowOrder = (keys, order) => {
3
- const wanted = new Set(keys);
4
- const placed = order.filter((key) => wanted.has(key));
5
- const seen = new Set(placed);
6
- return [...placed, ...[...wanted].filter((key) => !seen.has(key))];
7
- };
1
+ import { commaList, inRowOrder } from '@fusion.dev/helix-core';
8
2
  export const toggledOpen = (expanded, key, open, order) => {
9
3
  const keys = new Set(commaList(expanded));
10
4
  if (keys.has(key) === open) {
@@ -18,7 +12,3 @@ export const toggledOpen = (expanded, key, open, order) => {
18
12
  }
19
13
  return inRowOrder(keys, order).join(',');
20
14
  };
21
- export const anchorAt = (keys, anchorKey, from) => {
22
- const anchor = anchorKey === undefined ? -1 : keys.indexOf(anchorKey);
23
- return anchor < 0 ? { anchor: from, anchorKey: keys[from] } : { anchor, anchorKey };
24
- };