@fusion.dev/helix-headless 0.142.1 → 0.144.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 (285) hide show
  1. package/custom-elements.json +25381 -1202
  2. package/dist/accordion/item/accordion-item.d.ts +38 -2
  3. package/dist/accordion/item/accordion-item.js +38 -6
  4. package/dist/accordion/root/accordion-root.d.ts +23 -1
  5. package/dist/accordion/root/accordion-root.js +39 -3
  6. package/dist/announcement/root/announcement-root.d.ts +11 -7
  7. package/dist/announcement/root/announcement-root.js +1 -1
  8. package/dist/app-header/root/app-header-root.d.ts +21 -0
  9. package/dist/app-header/root/app-header-root.js +31 -5
  10. package/dist/area-chart/root/area-chart-root.d.ts +12 -4
  11. package/dist/area-chart/root/area-chart-root.js +39 -11
  12. package/dist/avatar/group/avatar-group.d.ts +24 -3
  13. package/dist/avatar/group/avatar-group.js +34 -2
  14. package/dist/avatar/root/avatar-root.d.ts +17 -1
  15. package/dist/avatar/root/avatar-root.js +31 -10
  16. package/dist/badge/root/badge-root.d.ts +12 -0
  17. package/dist/badge/root/badge-root.js +1 -1
  18. package/dist/bar-chart/root/bar-chart-root.d.ts +30 -5
  19. package/dist/bar-chart/root/bar-chart-root.js +58 -21
  20. package/dist/blockquote/root/blockquote-root.d.ts +12 -7
  21. package/dist/blockquote/root/blockquote-root.js +6 -4
  22. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +9 -3
  23. package/dist/breadcrumbs/root/breadcrumbs-root.js +9 -1
  24. package/dist/button/root/button-root.d.ts +84 -1
  25. package/dist/button/root/button-root.js +81 -3
  26. package/dist/callout/root/callout-root.d.ts +32 -6
  27. package/dist/callout/root/callout-root.js +26 -7
  28. package/dist/canvas/root/canvas-root.d.ts +1 -0
  29. package/dist/canvas/root/canvas-root.js +10 -1
  30. package/dist/card/root/card-root.d.ts +30 -1
  31. package/dist/card/root/card-root.js +38 -5
  32. package/dist/carousel/root/carousel-root.d.ts +47 -5
  33. package/dist/carousel/root/carousel-root.js +53 -21
  34. package/dist/chat/composer/chat-composer.d.ts +13 -11
  35. package/dist/chat/composer/chat-composer.js +6 -12
  36. package/dist/chat/message/chat-message.js +8 -1
  37. package/dist/chat/root/chat-root.d.ts +1 -0
  38. package/dist/chat/root/chat-root.js +2 -1
  39. package/dist/checkbox/root/checkbox-root.d.ts +7 -0
  40. package/dist/checkbox/root/checkbox-root.js +9 -3
  41. package/dist/checkbox-group/root/checkbox-group-root.d.ts +116 -33
  42. package/dist/checkbox-group/root/checkbox-group-root.js +141 -44
  43. package/dist/code/root/code-root.d.ts +1 -1
  44. package/dist/code-block/lines.d.ts +13 -0
  45. package/dist/code-block/lines.js +2 -0
  46. package/dist/code-block/root/code-block-root.d.ts +49 -0
  47. package/dist/code-block/root/code-block-root.js +44 -3
  48. package/dist/color-input/root/color-input-root.d.ts +60 -2
  49. package/dist/color-input/root/color-input-root.js +55 -7
  50. package/dist/color-picker/channels.d.ts +26 -0
  51. package/dist/color-picker/channels.js +84 -0
  52. package/dist/color-picker/root/color-picker-root.d.ts +118 -12
  53. package/dist/color-picker/root/color-picker-root.js +183 -13
  54. package/dist/combobox/root/combobox-root.d.ts +126 -3
  55. package/dist/combobox/root/combobox-root.js +224 -21
  56. package/dist/command/root/command-root.d.ts +47 -10
  57. package/dist/command/root/command-root.js +45 -4
  58. package/dist/copy-button/from.d.ts +22 -0
  59. package/dist/copy-button/from.js +28 -0
  60. package/dist/copy-button/root/copy-button-root.d.ts +48 -7
  61. package/dist/copy-button/root/copy-button-root.js +54 -8
  62. package/dist/data-table/root/data-table-root.d.ts +164 -10
  63. package/dist/data-table/root/data-table-root.js +488 -57
  64. package/dist/date-input/root/date-input-root.d.ts +123 -9
  65. package/dist/date-input/root/date-input-root.js +147 -45
  66. package/dist/date-picker/root/date-picker-root.d.ts +229 -18
  67. package/dist/date-picker/root/date-picker-root.js +342 -46
  68. package/dist/dialog/description.d.ts +9 -0
  69. package/dist/dialog/description.js +14 -0
  70. package/dist/dialog/root/dialog-root.d.ts +101 -10
  71. package/dist/dialog/root/dialog-root.js +83 -4
  72. package/dist/donut-chart/root/donut-chart-root.d.ts +61 -16
  73. package/dist/donut-chart/root/donut-chart-root.js +48 -13
  74. package/dist/drawer/root/drawer-root.d.ts +93 -7
  75. package/dist/drawer/root/drawer-root.js +126 -5
  76. package/dist/drawer/swipe-start.d.ts +9 -0
  77. package/dist/drawer/swipe-start.js +12 -0
  78. package/dist/drilldown/item/drilldown-item.d.ts +16 -13
  79. package/dist/drilldown/item/drilldown-item.js +6 -2
  80. package/dist/drilldown/root/drilldown-root.d.ts +21 -5
  81. package/dist/drilldown/root/drilldown-root.js +26 -10
  82. package/dist/element-events.generated.js +42 -13
  83. package/dist/empty/root/empty-root.d.ts +1 -1
  84. package/dist/file-input/root/file-input-root.d.ts +65 -1
  85. package/dist/file-input/root/file-input-root.js +76 -12
  86. package/dist/file-input/screen.d.ts +35 -0
  87. package/dist/file-input/screen.js +49 -0
  88. package/dist/filter-input/menu/filter-menu.d.ts +9 -0
  89. package/dist/filter-input/menu/filter-menu.js +8 -0
  90. package/dist/filter-input/root/filter-input-root.d.ts +43 -6
  91. package/dist/filter-input/root/filter-input-root.js +89 -10
  92. package/dist/filter-input/suggest.d.ts +17 -0
  93. package/dist/filter-input/suggest.js +23 -0
  94. package/dist/format-date/options.d.ts +33 -0
  95. package/dist/format-date/options.js +42 -0
  96. package/dist/format-date/root/format-date-root.d.ts +62 -3
  97. package/dist/format-date/root/format-date-root.js +78 -37
  98. package/dist/graph/root/graph-root.d.ts +24 -3
  99. package/dist/graph/root/graph-root.js +66 -12
  100. package/dist/heatmap/root/buckets.d.ts +2 -1
  101. package/dist/heatmap/root/buckets.js +5 -1
  102. package/dist/heatmap/root/heatmap-root.d.ts +47 -9
  103. package/dist/heatmap/root/heatmap-root.js +46 -18
  104. package/dist/icon/index.d.ts +2 -0
  105. package/dist/icon/index.js +2 -0
  106. package/dist/icon/registry.d.ts +37 -0
  107. package/dist/icon/registry.js +83 -0
  108. package/dist/icon/root/icon-root.d.ts +53 -6
  109. package/dist/icon/root/icon-root.js +72 -4
  110. package/dist/icon/root/index.d.ts +2 -0
  111. package/dist/icon/root/index.js +2 -0
  112. package/dist/icon/set.d.ts +1 -0
  113. package/dist/icon/set.js +3 -0
  114. package/dist/icon-button/root/icon-button-root.d.ts +1 -1
  115. package/dist/image/root/image-root.d.ts +23 -2
  116. package/dist/image/root/image-root.js +23 -4
  117. package/dist/input/root/input-root.d.ts +62 -9
  118. package/dist/input/root/input-root.js +61 -5
  119. package/dist/kbd/root/kbd-root.d.ts +26 -11
  120. package/dist/kbd/root/kbd-root.js +35 -38
  121. package/dist/kbd/shortcut.d.ts +18 -0
  122. package/dist/kbd/shortcut.js +35 -0
  123. package/dist/legend/hidden-series.d.ts +8 -0
  124. package/dist/legend/hidden-series.js +13 -0
  125. package/dist/legend/root/legend-root.d.ts +63 -0
  126. package/dist/legend/root/legend-root.js +61 -7
  127. package/dist/lightbox/item/lightbox-item.d.ts +17 -1
  128. package/dist/lightbox/item/lightbox-item.js +10 -1
  129. package/dist/lightbox/root/lightbox-root.d.ts +77 -6
  130. package/dist/lightbox/root/lightbox-root.js +116 -5
  131. package/dist/line-chart/root/line-chart-root.d.ts +29 -4
  132. package/dist/line-chart/root/line-chart-root.js +58 -17
  133. package/dist/list/item/list-item.d.ts +11 -5
  134. package/dist/list/item/list-item.js +5 -6
  135. package/dist/listbox/range.d.ts +17 -0
  136. package/dist/listbox/range.js +5 -0
  137. package/dist/listbox/root/listbox-root.d.ts +184 -4
  138. package/dist/listbox/root/listbox-root.js +229 -23
  139. package/dist/loader/busy.d.ts +17 -0
  140. package/dist/loader/busy.js +24 -0
  141. package/dist/loader/root/loader-root.d.ts +37 -0
  142. package/dist/loader/root/loader-root.js +52 -3
  143. package/dist/map/root/map-root.d.ts +19 -4
  144. package/dist/map/root/map-root.js +36 -7
  145. package/dist/megamenu/root/megamenu-root.d.ts +10 -1
  146. package/dist/megamenu/root/megamenu-root.js +10 -1
  147. package/dist/menu/item/menu-item.d.ts +41 -12
  148. package/dist/menu/item/menu-item.js +46 -3
  149. package/dist/menu/root/menu-root.d.ts +32 -2
  150. package/dist/menu/root/menu-root.js +48 -8
  151. package/dist/meter/root/meter-root.d.ts +13 -0
  152. package/dist/meter/root/meter-root.js +24 -5
  153. package/dist/navigation/root/navigation-root.d.ts +10 -2
  154. package/dist/navigation/root/navigation-root.js +13 -2
  155. package/dist/notifications/feed-keys.d.ts +10 -0
  156. package/dist/notifications/feed-keys.js +14 -0
  157. package/dist/notifications/group/notification-group.d.ts +1 -0
  158. package/dist/notifications/notification/notification.d.ts +29 -0
  159. package/dist/notifications/notification/notification.js +51 -3
  160. package/dist/notifications/root/notifications-root.d.ts +49 -0
  161. package/dist/notifications/root/notifications-root.js +76 -2
  162. package/dist/number-input/root/number-input-root.d.ts +109 -7
  163. package/dist/number-input/root/number-input-root.js +109 -21
  164. package/dist/object-inspector/root/object-inspector-root.d.ts +49 -5
  165. package/dist/object-inspector/root/object-inspector-root.js +92 -12
  166. package/dist/option/root/option-root.d.ts +58 -6
  167. package/dist/option/root/option-root.js +35 -5
  168. package/dist/outline/root/outline-root.d.ts +13 -2
  169. package/dist/outline/root/outline-root.js +4 -2
  170. package/dist/pagination/root/pagination-root.d.ts +19 -1
  171. package/dist/pagination/root/pagination-root.js +49 -9
  172. package/dist/pagination/size/pagination-size.d.ts +13 -3
  173. package/dist/pagination/size/pagination-size.js +7 -0
  174. package/dist/pin-input/format.d.ts +7 -0
  175. package/dist/pin-input/format.js +16 -0
  176. package/dist/pin-input/root/pin-input-root.d.ts +37 -0
  177. package/dist/pin-input/root/pin-input-root.js +48 -7
  178. package/dist/popover/root/popover-root.d.ts +78 -3
  179. package/dist/popover/root/popover-root.js +74 -5
  180. package/dist/progress/root/progress-root.d.ts +23 -1
  181. package/dist/progress/root/progress-root.js +40 -10
  182. package/dist/qr-code/export.d.ts +31 -0
  183. package/dist/qr-code/export.js +10 -0
  184. package/dist/qr-code/root/qr-code-root.d.ts +45 -0
  185. package/dist/qr-code/root/qr-code-root.js +78 -3
  186. package/dist/radio/group/radio-group.d.ts +64 -0
  187. package/dist/radio/group/radio-group.js +66 -12
  188. package/dist/radio/root/radio-root.d.ts +8 -5
  189. package/dist/radio/root/radio-root.js +1 -2
  190. package/dist/rating/root/rating-root.d.ts +49 -1
  191. package/dist/rating/root/rating-root.js +69 -10
  192. package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
  193. package/dist/scatter-chart/root/scatter-chart-root.js +40 -14
  194. package/dist/select/root/select-root.d.ts +93 -3
  195. package/dist/select/root/select-root.js +111 -13
  196. package/dist/skeleton/root/skeleton-root.d.ts +39 -3
  197. package/dist/skeleton/root/skeleton-root.js +33 -4
  198. package/dist/skip-link/root/skip-link-root.d.ts +10 -0
  199. package/dist/skip-link/root/skip-link-root.js +15 -1
  200. package/dist/slider/root/slider-root.d.ts +59 -2
  201. package/dist/slider/root/slider-root.js +82 -8
  202. package/dist/sparkline/root/sparkline-root.d.ts +9 -10
  203. package/dist/speed-dial/item/speed-dial-item.d.ts +11 -5
  204. package/dist/speed-dial/item/speed-dial-item.js +7 -2
  205. package/dist/speed-dial/root/speed-dial-root.d.ts +15 -4
  206. package/dist/speed-dial/root/speed-dial-root.js +19 -5
  207. package/dist/splitter/root/splitter-root.d.ts +28 -6
  208. package/dist/splitter/root/splitter-root.js +35 -1
  209. package/dist/stat/root/stat-root.d.ts +9 -1
  210. package/dist/stat/root/stat-root.js +15 -2
  211. package/dist/steps/root/steps-root.js +1 -1
  212. package/dist/steps/step/step.d.ts +1 -0
  213. package/dist/steps/step/step.js +1 -1
  214. package/dist/switch/root/switch-root.d.ts +14 -2
  215. package/dist/switch/root/switch-root.js +7 -1
  216. package/dist/table/cell/table-cell.d.ts +24 -4
  217. package/dist/table/cell/table-cell.js +21 -1
  218. package/dist/table/column/table-column.d.ts +32 -6
  219. package/dist/table/column/table-column.js +36 -6
  220. package/dist/table/root/table-root.d.ts +94 -3
  221. package/dist/table/root/table-root.js +128 -5
  222. package/dist/table/row/table-row.d.ts +7 -0
  223. package/dist/table/row/table-row.js +9 -1
  224. package/dist/tabs/root/tabs-root.d.ts +6 -1
  225. package/dist/tabs/root/tabs-root.js +6 -2
  226. package/dist/tag/group/tag-group.d.ts +107 -0
  227. package/dist/tag/group/tag-group.js +157 -0
  228. package/dist/tag/index.d.ts +1 -0
  229. package/dist/tag/index.js +1 -0
  230. package/dist/tag/root/tag-root.d.ts +83 -1
  231. package/dist/tag/root/tag-root.js +87 -17
  232. package/dist/tag/selection.d.ts +10 -0
  233. package/dist/tag/selection.js +12 -0
  234. package/dist/textarea/grow.d.ts +22 -0
  235. package/dist/textarea/grow.js +20 -0
  236. package/dist/textarea/root/textarea-root.d.ts +13 -0
  237. package/dist/textarea/root/textarea-root.js +10 -2
  238. package/dist/time-input/root/time-input-root.d.ts +71 -6
  239. package/dist/time-input/root/time-input-root.js +110 -44
  240. package/dist/time-picker/root/time-picker-root.d.ts +155 -26
  241. package/dist/time-picker/root/time-picker-root.js +192 -63
  242. package/dist/toast/hotkey.d.ts +22 -0
  243. package/dist/toast/hotkey.js +23 -0
  244. package/dist/toast/item/toast-item.d.ts +16 -1
  245. package/dist/toast/item/toast-item.js +41 -13
  246. package/dist/toast/root/toast-root.d.ts +105 -8
  247. package/dist/toast/root/toast-root.js +209 -4
  248. package/dist/toggle/group/toggle-group.d.ts +95 -16
  249. package/dist/toggle/group/toggle-group.js +99 -13
  250. package/dist/toggle/root/toggle-root.d.ts +26 -11
  251. package/dist/toggle/root/toggle-root.js +14 -6
  252. package/dist/toolbar/root/toolbar-root.d.ts +55 -15
  253. package/dist/toolbar/root/toolbar-root.js +99 -16
  254. package/dist/tooltip/focus-target.d.ts +6 -0
  255. package/dist/tooltip/focus-target.js +9 -0
  256. package/dist/tooltip/root/tooltip-root.d.ts +73 -15
  257. package/dist/tooltip/root/tooltip-root.js +96 -7
  258. package/dist/tour/naming.d.ts +30 -0
  259. package/dist/tour/naming.js +10 -0
  260. package/dist/tour/root/tour-root.d.ts +67 -3
  261. package/dist/tour/root/tour-root.js +105 -17
  262. package/dist/tour/stop/tour-stop.d.ts +65 -3
  263. package/dist/tour/stop/tour-stop.js +61 -11
  264. package/dist/tour/wait.d.ts +11 -0
  265. package/dist/tour/wait.js +19 -0
  266. package/dist/tree/item/tree-item.d.ts +21 -5
  267. package/dist/tree/item/tree-item.js +14 -4
  268. package/dist/tree/root/tree-root.d.ts +29 -5
  269. package/dist/tree/root/tree-root.js +64 -8
  270. package/dist/trend/root/trend-root.d.ts +36 -1
  271. package/dist/trend/root/trend-root.js +41 -15
  272. package/dist/video/root/keys.d.ts +5 -0
  273. package/dist/video/root/keys.js +13 -1
  274. package/dist/video/root/video-root.d.ts +19 -0
  275. package/dist/video/root/video-root.js +48 -4
  276. package/dist/video-playlist/menu/video-playlist-menu.d.ts +20 -2
  277. package/dist/video-playlist/menu/video-playlist-menu.js +27 -5
  278. package/dist/video-playlist/root/video-playlist-root.js +6 -3
  279. package/dist/virtual-list/root/virtual-list-root.d.ts +52 -4
  280. package/dist/virtual-list/root/virtual-list-root.js +103 -21
  281. package/lint.json +1 -1
  282. package/package.json +5 -5
  283. package/types/jsx.d.ts +9140 -1149
  284. package/types/svelte.d.ts +1 -0
  285. package/types/vue.d.ts +2089 -267
@@ -10,24 +10,32 @@ declare const HelixHeadlessTooltip_base: (new (...args: any[]) => import("@fusio
10
10
  * does not clip it and no `z-index` is needed. `FloatingController` positions
11
11
  * it and flips it to another side when the preferred side does not fit.
12
12
  *
13
- * Wrapping the trigger is the convenient form. Use it where the trigger already
14
- * has an accessible name, because the tooltip cannot describe a slotted
15
- * trigger: an IDREF cannot cross a shadow boundary.
16
- *
17
- * To add a description, place the tooltip beside the trigger and name the
18
- * trigger with `for`:
13
+ * **The tooltip describes its trigger itself, in both forms.** Wrap the
14
+ * trigger, or place the tooltip beside it and name the trigger with `for`:
19
15
  *
20
16
  * ```html
21
- * <helix-headless-button id="save" aria-describedby="save-tip">Save</helix-headless-button>
22
- * <helix-headless-tooltip id="save-tip" for="save" content="Save your work"></helix-headless-tooltip>
17
+ * <helix-headless-button id="save">Save</helix-headless-button>
18
+ * <helix-headless-tooltip for="save" content="Save your work"></helix-headless-tooltip>
23
19
  * ```
24
20
  *
25
- * Write the `aria-describedby` yourself, pointing at the tooltip host. Setting
26
- * it at runtime causes a hydration mismatch that React does not fix. With
27
- * `for`, the tooltip warns once on first open if the attribute is missing.
21
+ * The link is an element reference on the control that takes focus, and it is
22
+ * never written into your markup before a reader has acted. A trigger that is a
23
+ * Helix component is described at once, inside its own shadow root. A plain
24
+ * element in your markup is described when a reader first points at it or
25
+ * focuses it, which is after any hydration, and only where you have written no
26
+ * `aria-describedby` or `aria-labelledby` of your own. Write
27
+ * `aria-describedby` pointing at the tooltip yourself to have the link in the
28
+ * server's markup. Where the browser has no element references, write it
29
+ * yourself; the tooltip warns once on first open if nothing links the two.
28
30
  *
29
31
  * The tooltip shows on hover and on focus. It hides on pointer leave, on blur,
30
- * on Escape, and when the trigger is activated.
32
+ * on Escape, and when the trigger is activated. The pointer can move from the
33
+ * trigger onto the bubble and the bubble stays.
34
+ *
35
+ * Once one tooltip is showing, moving to another trigger shows its tooltip
36
+ * with no `delay`, and the first one hides. The same holds for `skip-delay`
37
+ * milliseconds after a tooltip hides, 300 unless you set it. `show-on="focus"`
38
+ * shows the tooltip on keyboard focus only, for a hint a pointer does not need.
31
39
  *
32
40
  * @since 0.1.0
33
41
  * @status stable
@@ -35,13 +43,14 @@ declare const HelixHeadlessTooltip_base: (new (...args: any[]) => import("@fusio
35
43
  * @aliases Hint, Popup label
36
44
  * @documentation https://fusion.dev/helix/components/tooltip
37
45
  *
38
- * @slot - The trigger: the element the tooltip describes.
46
+ * @slot - The trigger, in the wrapping form. The tooltip describes it, as it
47
+ * describes the element `for` names.
39
48
  * @slot content - Rich content for the bubble. It replaces the `content`
40
49
  * property.
41
50
  *
42
51
  * @event {HelixBeforeCloseEvent} helix-before-close - The bubble is about to hide. Cancelable: cancel it to keep it shown.
43
52
  * @event {HelixBeforeOpenEvent} helix-before-open - The bubble is about to show. Cancelable: cancel it to keep it hidden.
44
- * @event {Event} toggle - The bubble opened or closed. The event carries `newState` and `oldState`.
53
+ * @event {ToggleEvent} toggle - The bubble opened or closed. The event carries `newState` and `oldState`.
45
54
  *
46
55
  * @csspart arrow - The arrow that points at the trigger.
47
56
  * @csspart arrow-bottom - Added to `arrow` while the bubble is below its trigger, with the arrow on the bubble's top edge.
@@ -142,6 +151,18 @@ export declare class HelixHeadlessTooltip extends HelixHeadlessTooltip_base {
142
151
  * It moves if that side does not fit.
143
152
  */
144
153
  placement: Placement;
154
+ /**
155
+ * What shows the bubble. Unset, it is a pointer resting on the trigger and
156
+ * keyboard focus. `focus` is keyboard focus alone, for a hint a pointer does
157
+ * not need, such as a shortcut a mouse reader has no use for.
158
+ */
159
+ showOn?: 'focus';
160
+ /**
161
+ * How long after a tooltip hides the next one still shows at once, with no
162
+ * `delay`, in milliseconds. The same skip delay Radix uses. Zero makes every
163
+ * tooltip wait.
164
+ */
165
+ skipDelay: number;
145
166
  /**
146
167
  * The id of a box to keep the bubble inside. Defaults to the viewport.
147
168
  *
@@ -249,8 +270,27 @@ export declare class HelixHeadlessTooltip extends HelixHeadlessTooltip_base {
249
270
  * the reader had moved on to.
250
271
  */
251
272
  hide(): void;
252
- /** Shows after the pointer has rested for `delay`. */
273
+ /**
274
+ * Shows after the pointer has rested for `delay`, or at once while the
275
+ * tooltips are warm.
276
+ *
277
+ * **Warm is another tooltip showing, or one that hid within `skipDelay`.**
278
+ * A reader scanning a toolbar has already waited once, and waiting again on
279
+ * every control turns the scan into a series of pauses.
280
+ */
253
281
  private readonly showLater;
282
+ /**
283
+ * The pointer reached the bubble, in the `for` form.
284
+ *
285
+ * The bubble is not inside the element `for` names, so moving onto it leaves
286
+ * the trigger and would hide it after `delay-out`. WCAG 1.4.13 asks that a
287
+ * reader can move onto it, to read it under a magnifier or to select its
288
+ * text. Wrapping, the bubble is inside the host and the host's own pointer
289
+ * listeners already hold it.
290
+ */
291
+ private readonly holdOnBubble;
292
+ /** The pointer left the bubble, in the `for` form. */
293
+ private readonly leaveBubble;
254
294
  /** Hides after `delayOut`, so crossing the gap to the bubble does not close it. */
255
295
  private readonly hideLater;
256
296
  /**
@@ -318,6 +358,17 @@ export declare class HelixHeadlessTooltip extends HelixHeadlessTooltip_base {
318
358
  * have upgraded, or existed, when this one connected.
319
359
  */
320
360
  private bind;
361
+ /** The control this tooltip has described, so the link can be taken back. */
362
+ private linked;
363
+ /**
364
+ * Describes the control that takes the trigger's focus by this tooltip.
365
+ *
366
+ * `light` says a reader has just acted, which is what allows a write onto a
367
+ * plain element in the consumer's markup. See `linkDescription`.
368
+ */
369
+ private link;
370
+ /** A reader arriving on the trigger, which is late enough to write the link. */
371
+ private readonly linkOnArrival;
321
372
  private unbind;
322
373
  /** Said once per element, however many times it opens. */
323
374
  private audited;
@@ -342,6 +393,13 @@ export declare class HelixHeadlessTooltip extends HelixHeadlessTooltip_base {
342
393
  * this should not be the thing to settle it.
343
394
  */
344
395
  private auditDescription;
396
+ /**
397
+ * Whether the wrapped trigger's own name is the tooltip's text.
398
+ *
399
+ * The name a consumer writes: `aria-label`, then a `label` a Helix control
400
+ * renders as its name, then the trigger's text.
401
+ */
402
+ private triggerSays;
345
403
  connectedCallback(): void;
346
404
  disconnectedCallback(): void;
347
405
  protected firstUpdated(changed: PropertyValues): void;
@@ -4,10 +4,17 @@ 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 { anchorElement, customElement, elementById, HelixElement, hostAria, MixinControllerOpen, PopoverController, reportRuntime, } from '@fusion.dev/helix-core';
7
+ import { anchorElement, arrowReach, customElement, elementById, HelixElement, hostAria, linkDescription, MixinControllerOpen, PopoverController, reportRuntime, sideOf, unlinkDescription, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
+ import { focusTarget } from '../focus-target.js';
10
11
  const GENERIC = new Set(['div', 'p', 'section', 'span']);
12
+ const WARMTH = Symbol.for('fusion.helix.tooltip.warmth');
13
+ const warmth = () => {
14
+ const globals = globalThis;
15
+ globals[WARMTH] ??= { hidAt: Number.NEGATIVE_INFINITY, showing: new Set() };
16
+ return globals[WARMTH];
17
+ };
11
18
  let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpen(HelixElement) {
12
19
  constructor() {
13
20
  super(...arguments);
@@ -19,22 +26,20 @@ let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpe
19
26
  this.offset = 8;
20
27
  this.persist = false;
21
28
  this.placement = 'top';
29
+ this.skipDelay = 300;
22
30
  this.within = '';
23
31
  this.holds = new Set();
24
32
  this.bubbleLayer = new PopoverController(this, {
25
33
  anchor: () => this.trigger,
26
34
  arrow: () => this.partNamed('arrow'),
27
35
  boundary: () => [this, this.named],
28
- offset: () => {
29
- const point = this.partNamed('arrow');
30
- return this.offset + (point?.offsetWidth ?? 0) / Math.SQRT2;
31
- },
36
+ offset: () => this.offset + arrowReach(this.partNamed('arrow')),
32
37
  onDismiss: () => {
33
38
  this.holds.clear();
34
39
  this.hide();
35
40
  },
36
41
  onPlace: (placement) => {
37
- const side = placement.split('-')[0];
42
+ const side = sideOf(placement);
38
43
  this.toggleState('placed-bottom', side === 'bottom');
39
44
  this.toggleState('placed-left', side === 'left');
40
45
  this.toggleState('placed-right', side === 'right');
@@ -49,10 +54,31 @@ let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpe
49
54
  this.requestUpdate();
50
55
  };
51
56
  this.showLater = () => {
57
+ if (this.showOn === 'focus') {
58
+ return;
59
+ }
52
60
  this.holds.add('pointer');
53
61
  clearTimeout(this.timer);
62
+ const warm = warmth();
63
+ const others = [...warm.showing].some((one) => one !== this);
64
+ if (others || performance.now() - warm.hidAt < this.skipDelay) {
65
+ this.show();
66
+ return;
67
+ }
54
68
  this.timer = setTimeout(() => this.show(), this.delay);
55
69
  };
70
+ this.holdOnBubble = () => {
71
+ if (!this.named) {
72
+ return;
73
+ }
74
+ this.holds.add('pointer');
75
+ clearTimeout(this.timer);
76
+ };
77
+ this.leaveBubble = () => {
78
+ if (this.named) {
79
+ this.hideLater();
80
+ }
81
+ };
56
82
  this.hideLater = () => {
57
83
  this.holds.delete('pointer');
58
84
  clearTimeout(this.timer);
@@ -77,6 +103,10 @@ let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpe
77
103
  this.holds.clear();
78
104
  this.hide();
79
105
  };
106
+ this.linkOnArrival = (event) => {
107
+ const first = event.composedPath()[0];
108
+ this.link(true, event.type === 'focusin' && first instanceof Element ? first : undefined);
109
+ };
80
110
  this.audited = false;
81
111
  }
82
112
  get trigger() {
@@ -154,14 +184,41 @@ let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpe
154
184
  return;
155
185
  }
156
186
  this.unbind();
187
+ target.addEventListener('pointerenter', this.linkOnArrival);
188
+ target.addEventListener('focusin', this.linkOnArrival);
157
189
  target.addEventListener('pointerenter', this.showLater);
158
190
  target.addEventListener('pointerleave', this.hideLater);
159
191
  target.addEventListener('focusin', this.showNow);
160
192
  target.addEventListener('focusout', this.releaseFocus);
161
193
  target.addEventListener('click', this.handleActivate);
162
194
  this.bound = target;
195
+ this.link(false);
196
+ const drawn = this.trigger.updateComplete;
197
+ void drawn?.then(() => {
198
+ if (this.bound === target) {
199
+ this.link(false);
200
+ }
201
+ });
202
+ }
203
+ link(light, target = focusTarget(this.trigger)) {
204
+ if (this.linked === target) {
205
+ return;
206
+ }
207
+ if (this.linked) {
208
+ unlinkDescription(this.linked, this);
209
+ this.linked = undefined;
210
+ }
211
+ if (linkDescription(target, this, light)) {
212
+ this.linked = target;
213
+ }
163
214
  }
164
215
  unbind() {
216
+ if (this.linked) {
217
+ unlinkDescription(this.linked, this);
218
+ this.linked = undefined;
219
+ }
220
+ this.bound?.removeEventListener('pointerenter', this.linkOnArrival);
221
+ this.bound?.removeEventListener('focusin', this.linkOnArrival);
165
222
  this.bound?.removeEventListener('pointerenter', this.showLater);
166
223
  this.bound?.removeEventListener('pointerleave', this.hideLater);
167
224
  this.bound?.removeEventListener('click', this.handleActivate);
@@ -174,7 +231,13 @@ let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpe
174
231
  return;
175
232
  }
176
233
  this.audited = true;
234
+ if (this.linked) {
235
+ return;
236
+ }
177
237
  if (this.for === '') {
238
+ if (this.triggerSays(this.describedText)) {
239
+ return;
240
+ }
178
241
  reportRuntime({
179
242
  kind: 'wrapped-trigger',
180
243
  message: `<${this.localName}> is wrapping its trigger rather than naming one, so its text ` +
@@ -211,6 +274,12 @@ let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpe
211
274
  tag: this.localName,
212
275
  });
213
276
  }
277
+ triggerSays(text) {
278
+ const flat = (words) => (words ?? '').replace(/\s+/gu, ' ').trim();
279
+ const trigger = this.trigger;
280
+ const name = trigger.getAttribute('aria-label') ?? trigger.getAttribute('label') ?? trigger.textContent;
281
+ return text !== '' && flat(name) === flat(text);
282
+ }
214
283
  connectedCallback() {
215
284
  super.connectedCallback();
216
285
  if (this.hasUpdated) {
@@ -222,6 +291,7 @@ let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpe
222
291
  this.unbind();
223
292
  this.holds.clear();
224
293
  clearTimeout(this.timer);
294
+ warmth().showing.delete(this);
225
295
  }
226
296
  firstUpdated(changed) {
227
297
  super.firstUpdated(changed);
@@ -233,11 +303,22 @@ let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpe
233
303
  this.bind();
234
304
  }
235
305
  if (changed.has('open')) {
306
+ const warm = warmth();
236
307
  if (this.open) {
308
+ for (const other of [...warm.showing]) {
309
+ if (other !== this) {
310
+ other.holds.clear();
311
+ other.hide();
312
+ }
313
+ }
314
+ warm.showing.add(this);
237
315
  this.bubbleLayer.show();
238
316
  this.auditDescription();
239
317
  }
240
318
  else {
319
+ if (warm.showing.delete(this)) {
320
+ warm.hidAt = performance.now();
321
+ }
241
322
  this.bubbleLayer.hide();
242
323
  }
243
324
  }
@@ -247,7 +328,7 @@ let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpe
247
328
  }
248
329
  hostAria(this.internals, {
249
330
  describedBy: this.hasContent ? [bubble] : [],
250
- label: this.for === '' ? '' : this.describedText,
331
+ label: this.describedText,
251
332
  });
252
333
  }
253
334
  render() {
@@ -257,6 +338,8 @@ let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpe
257
338
  part="tooltip${side ? { bottom: ' tooltip-bottom', left: ' tooltip-left', right: ' tooltip-right', top: ' tooltip-top' }[side] : ''}"
258
339
  popover="manual"
259
340
  role="tooltip"
341
+ @pointerenter=${this.holdOnBubble}
342
+ @pointerleave=${this.leaveBubble}
260
343
  >
261
344
  <span
262
345
  part="arrow${side ? { bottom: ' arrow-bottom', left: ' arrow-left', right: ' arrow-right', top: ' arrow-top' }[side] : ''}"
@@ -291,6 +374,12 @@ __decorate([
291
374
  __decorate([
292
375
  property()
293
376
  ], HelixHeadlessTooltip.prototype, "placement", void 0);
377
+ __decorate([
378
+ property({ attribute: 'show-on' })
379
+ ], HelixHeadlessTooltip.prototype, "showOn", void 0);
380
+ __decorate([
381
+ property({ attribute: 'skip-delay', type: Number })
382
+ ], HelixHeadlessTooltip.prototype, "skipDelay", void 0);
294
383
  __decorate([
295
384
  property()
296
385
  ], HelixHeadlessTooltip.prototype, "within", void 0);
@@ -0,0 +1,30 @@
1
+ /** What names and describes a stop's panel. */
2
+ export interface StopNaming {
3
+ /** The elements that describe the panel, in reading order. */
4
+ describedBy: Element[];
5
+ /** The elements that name the panel, or none where a label names it. */
6
+ labelledBy: Element[];
7
+ }
8
+ /** Where a stop's words are. */
9
+ export interface StopWords {
10
+ /** The elements in the stop's default slot. */
11
+ content: readonly Element[];
12
+ /** The elements in its `description` slot. */
13
+ description: readonly Element[];
14
+ /** The elements in its `heading` slot. */
15
+ heading: readonly Element[];
16
+ /** Whether the stop has a `label` of its own. */
17
+ labeled: boolean;
18
+ /** The element that says the stop's place in the tour, such as "2 of 5". */
19
+ progress: Element | null;
20
+ }
21
+ /**
22
+ * What names a tour stop's panel and what describes it.
23
+ *
24
+ * Named by the `heading` slot, then by the first heading in the content, then
25
+ * by the stop's own `label`, and where there is none of those, by its place in
26
+ * the tour, so no stop is an unnamed group. Described by the `description`
27
+ * slot and by its place, which is how a screen reader hears where it is as
28
+ * focus moves from one stop to the next.
29
+ */
30
+ export declare const stopNaming: ({ content, description, heading, labeled, progress, }: StopWords) => StopNaming;
@@ -0,0 +1,10 @@
1
+ import { headingIn } from '@fusion.dev/helix-core';
2
+ export const stopNaming = ({ content, description, heading, labeled, progress, }) => {
3
+ const first = heading.length > 0 ? null : headingIn(content);
4
+ const found = heading.length > 0 ? [...heading] : first ? [first] : [];
5
+ const place = progress ? [progress] : [];
6
+ if (found.length === 0 && !labeled) {
7
+ return { describedBy: [...description], labelledBy: place };
8
+ }
9
+ return { describedBy: [...description, ...place], labelledBy: found };
10
+ };
@@ -1,6 +1,7 @@
1
1
  import { HelixElement } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  import type { HelixHeadlessTourStop } from '../stop/tour-stop.js';
4
+ declare const HelixHeadlessTour_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & typeof HelixElement;
4
5
  /**
5
6
  * @summary A guided tour of an interface, one stop at a time.
6
7
  *
@@ -17,6 +18,23 @@ import type { HelixHeadlessTourStop } from '../stop/tour-stop.js';
17
18
  * The root measures the target's position in the browser. Nothing is measured
18
19
  * on the server, because a tour starts only on request.
19
20
  *
21
+ * `open`, `default-open`, `helix-before-open`, `helix-before-close` and
22
+ * `toggle` work as they do on `Dialog`. Setting `open` starts the run, and
23
+ * `skip()` and `requestOpen(false)` end it early.
24
+ *
25
+ * Each stop is told its place in the run, from `progress-label`, such as "2 of
26
+ * 5". It describes the stop's panel, so a screen reader says it at every stop,
27
+ * and `progress` draws it in the panel as well. A dialog or a floating stop,
28
+ * which has nothing to light, is shown over the `backdrop` part. At a `wait`
29
+ * stop the run waits for that stop's target to be on the page, and moves on by
30
+ * itself.
31
+ *
32
+ * **Focus follows the run.** Opening moves focus to the first stop's panel,
33
+ * and moving on from a control in a stop moves it to the next one. Ending the
34
+ * tour puts focus back on the element that had it when the tour opened, unless
35
+ * you have moved it somewhere else on the page. A stop does not trap focus, so
36
+ * you can still `Tab` out to the element it describes.
37
+ *
20
38
  * @since 0.1.0
21
39
  * @status stable
22
40
  * @category overlays
@@ -25,15 +43,21 @@ import type { HelixHeadlessTourStop } from '../stop/tour-stop.js';
25
43
  *
26
44
  * @slot - The stops, in the order they are shown.
27
45
  *
46
+ * @event {HelixActivateEvent} helix-activate - Fired after the current stop changes, with the new index.
28
47
  * @event {HelixBeforeActivateEvent} helix-before-activate - Fired before the current stop changes, with the new index. Cancelable: call `preventDefault()` to stay on the current stop.
29
48
  * @event {HelixBeforeCloseEvent} helix-before-close - Fired before the user ends the tour early. Cancelable: call `preventDefault()` to keep the tour open.
49
+ * @event {HelixBeforeOpenEvent} helix-before-open - Fired before `requestOpen(true)` starts the tour. Cancelable: call `preventDefault()` to keep it closed.
30
50
  * @event {HelixCompleteEvent} helix-complete - Fired when the last stop is
31
51
  * finished.
32
52
  * @event {HelixTourAskEvent} helix-tour-ask - Fired when a stop's control is pressed to move the tour. The stop sends it, and the tour handles it.
53
+ * @event {ToggleEvent} toggle - Sent when the tour starts or ends, with `newState` and `oldState`.
33
54
  *
55
+ * @csspart backdrop - Behind a dialog or a floating stop, which lights nothing. It draws no box until you give it one.
34
56
  * @csspart spotlight - The box over the current target. It also draws the dimmed area around the target.
57
+ *
58
+ * @cssstate open - While the tour is running.
35
59
  */
36
- export declare class HelixHeadlessTour extends HelixElement {
60
+ export declare class HelixHeadlessTour extends HelixHeadlessTour_base {
37
61
  /**
38
62
  * Label for the control that goes back, passed to every stop.
39
63
  */
@@ -71,9 +95,14 @@ export declare class HelixHeadlessTour extends HelixElement {
71
95
  */
72
96
  nextLabel: string;
73
97
  /**
74
- * Whether the tour is running.
98
+ * Draws each stop's place in the run in its panel, as well as saying it.
75
99
  */
76
- open: boolean;
100
+ progress: boolean;
101
+ /**
102
+ * Each stop's place in the run, with `{index}` and `{count}` filled in.
103
+ * Translate it with the rest of your text.
104
+ */
105
+ progressLabel: string;
77
106
  /**
78
107
  * Label for the control that leaves the tour.
79
108
  */
@@ -121,6 +150,22 @@ export declare class HelixHeadlessTour extends HelixElement {
121
150
  disconnectedCallback(): void;
122
151
  protected willUpdate(changed: PropertyValues): void;
123
152
  protected updated(changed: PropertyValues): void;
153
+ /** Where focus was when the tour opened, to give it back when it ends. */
154
+ private returnFocus;
155
+ /** Whether `follow` has seen the first update. */
156
+ private followed;
157
+ /**
158
+ * Moves focus with the run.
159
+ *
160
+ * Opening takes it to the current stop. Moving takes it to the new stop when
161
+ * it was in the tour, which is where a reader pressing Next is, and leaves it
162
+ * where it is otherwise. Closing gives it back to where it was before, again
163
+ * only when it was in the tour: a reader who moved to the target has chosen
164
+ * where to be.
165
+ */
166
+ private follow;
167
+ /** Focuses the current stop's panel once the stop has shown it. */
168
+ private focusCurrent;
124
169
  /**
125
170
  * Tells each stop where it is in the run.
126
171
  *
@@ -132,6 +177,24 @@ export declare class HelixHeadlessTour extends HelixElement {
132
177
  private settle;
133
178
  /** The current stop's target while the run is open, which is what the light falls on. */
134
179
  private get lit();
180
+ /** The stop being shown, or nothing where there are no stops. */
181
+ private get current();
182
+ /** Stops waiting, where a `wait` stop is waiting. */
183
+ private unwait;
184
+ /** The `wait` stop being waited on, so a render that changed nothing starts nothing. */
185
+ private waiting;
186
+ /**
187
+ * Waits at a `wait` stop for its target to be on the page, then moves on.
188
+ *
189
+ * On the stop's own root, which is where its `for` resolves.
190
+ */
191
+ private wait;
192
+ /**
193
+ * Whether the current stop is shown over the backdrop: a dialog or a floating
194
+ * stop, or one with no target, which have nothing to light. Read with the
195
+ * light, after the stops are known, since the first render cannot know them.
196
+ */
197
+ private veiled;
135
198
  /** Reads the current target's box, which is where the light falls. */
136
199
  private light;
137
200
  /** Keeps `sizer` on the lit target, and on nothing once there is none. */
@@ -143,3 +206,4 @@ declare global {
143
206
  'helix-headless-tour': HelixHeadlessTour;
144
207
  }
145
208
  }
209
+ export {};