@fusion.dev/helix-headless 0.144.0 → 0.146.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 (319) hide show
  1. package/custom-elements.json +15195 -4240
  2. package/dist/accordion/item/accordion-item.d.ts +62 -12
  3. package/dist/accordion/item/accordion-item.js +41 -10
  4. package/dist/accordion/root/accordion-root.d.ts +14 -5
  5. package/dist/accordion/root/accordion-root.js +7 -1
  6. package/dist/announcement/root/announcement-root.d.ts +24 -3
  7. package/dist/announcement/root/announcement-root.js +39 -2
  8. package/dist/app-header/root/app-header-root.d.ts +12 -0
  9. package/dist/app-header/root/app-header-root.js +13 -1
  10. package/dist/app-header/sectioning.d.ts +9 -0
  11. package/dist/app-header/sectioning.js +27 -0
  12. package/dist/avatar/group/avatar-group.d.ts +20 -14
  13. package/dist/avatar/group/avatar-group.js +17 -19
  14. package/dist/badge/root/badge-root.d.ts +3 -1
  15. package/dist/badge/root/badge-root.js +2 -2
  16. package/dist/bar-chart/root/bar-chart-root.d.ts +18 -1
  17. package/dist/bar-chart/root/bar-chart-root.js +52 -15
  18. package/dist/bar-chart/stack.d.ts +15 -0
  19. package/dist/bar-chart/stack.js +19 -0
  20. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +57 -1
  21. package/dist/breadcrumbs/root/breadcrumbs-root.js +73 -3
  22. package/dist/button/root/button-root.d.ts +26 -0
  23. package/dist/button/root/button-root.js +38 -18
  24. package/dist/button-group/root/button-group-root.d.ts +2 -1
  25. package/dist/button-group/root/button-group-root.js +5 -1
  26. package/dist/canvas/node/canvas-node.d.ts +4 -3
  27. package/dist/canvas/node/canvas-node.js +3 -2
  28. package/dist/canvas/root/canvas-root.d.ts +38 -3
  29. package/dist/canvas/root/canvas-root.js +123 -42
  30. package/dist/card/root/card-root.d.ts +24 -3
  31. package/dist/card/root/card-root.js +20 -8
  32. package/dist/carousel/root/carousel-root.d.ts +133 -4
  33. package/dist/carousel/root/carousel-root.js +174 -24
  34. package/dist/carousel/stops.d.ts +20 -0
  35. package/dist/carousel/stops.js +30 -0
  36. package/dist/chat/composer/chat-composer.d.ts +38 -6
  37. package/dist/chat/composer/chat-composer.js +42 -9
  38. package/dist/chat/message/chat-message.d.ts +32 -1
  39. package/dist/chat/message/chat-message.js +27 -10
  40. package/dist/chat/naming.d.ts +26 -0
  41. package/dist/chat/naming.js +14 -0
  42. package/dist/chat/root/chat-root.d.ts +58 -0
  43. package/dist/chat/root/chat-root.js +43 -3
  44. package/dist/checkbox/root/checkbox-root.d.ts +20 -0
  45. package/dist/checkbox/root/checkbox-root.js +14 -1
  46. package/dist/checkbox-group/root/checkbox-group-root.d.ts +8 -2
  47. package/dist/checkbox-group/root/checkbox-group-root.js +12 -10
  48. package/dist/checkbox-group/select-all.d.ts +27 -0
  49. package/dist/checkbox-group/select-all.js +12 -0
  50. package/dist/code-block/highlight.d.ts +15 -0
  51. package/dist/code-block/highlight.js +4 -0
  52. package/dist/code-block/root/code-block-root.d.ts +57 -2
  53. package/dist/code-block/root/code-block-root.js +63 -8
  54. package/dist/color-input/root/color-input-root.d.ts +3 -0
  55. package/dist/color-input/root/color-input-root.js +6 -3
  56. package/dist/color-picker/root/color-picker-root.d.ts +33 -4
  57. package/dist/color-picker/root/color-picker-root.js +80 -21
  58. package/dist/color-picker/swatches.d.ts +12 -0
  59. package/dist/color-picker/swatches.js +26 -0
  60. package/dist/combobox/root/combobox-root.d.ts +43 -0
  61. package/dist/combobox/root/combobox-root.js +79 -15
  62. package/dist/command/root/command-root.d.ts +16 -1
  63. package/dist/command/root/command-root.js +22 -4
  64. package/dist/copy-button/root/copy-button-root.d.ts +26 -1
  65. package/dist/copy-button/root/copy-button-root.js +12 -5
  66. package/dist/data-table/index.d.ts +1 -1
  67. package/dist/data-table/index.js +1 -1
  68. package/dist/data-table/keys.d.ts +24 -0
  69. package/dist/data-table/keys.js +24 -0
  70. package/dist/data-table/root/data-table-root.d.ts +170 -13
  71. package/dist/data-table/root/data-table-root.js +294 -52
  72. package/dist/data-table/tree.d.ts +55 -0
  73. package/dist/data-table/tree.js +54 -0
  74. package/dist/date-input/root/date-input-root.d.ts +3 -1
  75. package/dist/date-input/root/date-input-root.js +18 -7
  76. package/dist/date-picker/root/date-picker-root.js +12 -6
  77. package/dist/description-list/item/description-list-item.d.ts +17 -2
  78. package/dist/description-list/item/description-list-item.js +15 -2
  79. package/dist/description-list/root/description-list-root.d.ts +27 -1
  80. package/dist/description-list/root/description-list-root.js +26 -1
  81. package/dist/dialog/description.js +15 -1
  82. package/dist/dialog/root/dialog-root.d.ts +8 -2
  83. package/dist/dialog/root/dialog-root.js +16 -1
  84. package/dist/divider/root/divider-root.d.ts +3 -0
  85. package/dist/divider/root/divider-root.js +2 -1
  86. package/dist/donut-chart/root/donut-chart-root.d.ts +31 -0
  87. package/dist/donut-chart/root/donut-chart-root.js +48 -1
  88. package/dist/drawer/reveal.d.ts +8 -0
  89. package/dist/drawer/reveal.js +1 -0
  90. package/dist/drawer/root/drawer-root.d.ts +59 -0
  91. package/dist/drawer/root/drawer-root.js +63 -4
  92. package/dist/drilldown/item/drilldown-item.d.ts +11 -6
  93. package/dist/drilldown/item/drilldown-item.js +8 -5
  94. package/dist/drilldown/root/drilldown-root.d.ts +29 -0
  95. package/dist/drilldown/root/drilldown-root.js +28 -5
  96. package/dist/element-events.generated.js +83 -12
  97. package/dist/empty/root/empty-root.d.ts +3 -1
  98. package/dist/empty/root/empty-root.js +3 -2
  99. package/dist/file-input/root/file-input-root.d.ts +69 -6
  100. package/dist/file-input/root/file-input-root.js +82 -19
  101. package/dist/file-input/screen.d.ts +2 -1
  102. package/dist/filter-input/menu/filter-menu.d.ts +5 -0
  103. package/dist/filter-input/menu/filter-menu.js +16 -4
  104. package/dist/filter-input/root/filter-input-root.d.ts +30 -6
  105. package/dist/filter-input/root/filter-input-root.js +1 -1
  106. package/dist/filter-input/suggest.d.ts +28 -3
  107. package/dist/filter-input/suggest.js +18 -8
  108. package/dist/format-date/root/format-date-root.d.ts +9 -16
  109. package/dist/format-date/root/format-date-root.js +10 -27
  110. package/dist/heatmap/root/heatmap-root.d.ts +24 -13
  111. package/dist/heatmap/root/heatmap-root.js +34 -12
  112. package/dist/icon/root/icon-root.d.ts +12 -1
  113. package/dist/icon/root/icon-root.js +21 -10
  114. package/dist/icon/settle.d.ts +7 -0
  115. package/dist/icon/settle.js +10 -0
  116. package/dist/icon-button/root/icon-button-root.d.ts +2 -0
  117. package/dist/image/root/image-root.d.ts +5 -1
  118. package/dist/image/root/image-root.js +10 -2
  119. package/dist/input/root/input-root.d.ts +13 -3
  120. package/dist/input/root/input-root.js +12 -3
  121. package/dist/kbd/root/kbd-root.d.ts +35 -1
  122. package/dist/kbd/root/kbd-root.js +23 -4
  123. package/dist/legend/root/legend-root.d.ts +55 -8
  124. package/dist/legend/root/legend-root.js +55 -13
  125. package/dist/lightbox/root/lightbox-root.d.ts +49 -6
  126. package/dist/lightbox/root/lightbox-root.js +86 -19
  127. package/dist/lightbox/zoom-controller.d.ts +59 -0
  128. package/dist/lightbox/zoom-controller.js +128 -0
  129. package/dist/lightbox/zoom.d.ts +22 -0
  130. package/dist/lightbox/zoom.js +16 -0
  131. package/dist/line-chart/root/line-chart-root.d.ts +22 -1
  132. package/dist/line-chart/root/line-chart-root.js +21 -1
  133. package/dist/list/item/list-item.d.ts +70 -1
  134. package/dist/list/item/list-item.js +77 -6
  135. package/dist/list/numbering.d.ts +14 -0
  136. package/dist/list/numbering.js +8 -0
  137. package/dist/list/root/list-root.d.ts +155 -9
  138. package/dist/list/root/list-root.js +246 -4
  139. package/dist/list/selection.d.ts +49 -0
  140. package/dist/list/selection.js +30 -0
  141. package/dist/listbox/root/listbox-root.d.ts +37 -1
  142. package/dist/listbox/root/listbox-root.js +49 -4
  143. package/dist/loader/busy.d.ts +10 -0
  144. package/dist/loader/busy.js +11 -0
  145. package/dist/loader/root/loader-root.d.ts +9 -2
  146. package/dist/loader/root/loader-root.js +23 -3
  147. package/dist/map/root/map-root.d.ts +6 -2
  148. package/dist/map/root/map-root.js +5 -2
  149. package/dist/megamenu/root/megamenu-root.d.ts +62 -0
  150. package/dist/megamenu/root/megamenu-root.js +90 -5
  151. package/dist/menu/index.d.ts +1 -0
  152. package/dist/menu/index.js +1 -0
  153. package/dist/menu/item/menu-item.d.ts +87 -11
  154. package/dist/menu/item/menu-item.js +78 -22
  155. package/dist/menu/root/menu-root.d.ts +39 -1
  156. package/dist/menu/root/menu-root.js +65 -8
  157. package/dist/menu/section/menu-section.d.ts +55 -0
  158. package/dist/menu/section/menu-section.js +60 -0
  159. package/dist/meter/root/meter-root.d.ts +20 -1
  160. package/dist/meter/root/meter-root.js +11 -15
  161. package/dist/navigation/root/navigation-root.d.ts +18 -2
  162. package/dist/navigation/root/navigation-root.js +29 -3
  163. package/dist/notifications/root/notifications-root.d.ts +25 -0
  164. package/dist/notifications/root/notifications-root.js +33 -5
  165. package/dist/number-input/root/number-input-root.d.ts +17 -8
  166. package/dist/number-input/root/number-input-root.js +2 -7
  167. package/dist/object-inspector/root/object-inspector-root.d.ts +161 -32
  168. package/dist/object-inspector/root/object-inspector-root.js +264 -123
  169. package/dist/object-inspector/rows.d.ts +75 -0
  170. package/dist/object-inspector/rows.js +119 -0
  171. package/dist/option/root/option-root.d.ts +5 -3
  172. package/dist/outline/levels.d.ts +31 -0
  173. package/dist/outline/levels.js +23 -0
  174. package/dist/outline/root/outline-root.d.ts +86 -3
  175. package/dist/outline/root/outline-root.js +95 -12
  176. package/dist/pagination/size/pagination-size.d.ts +12 -2
  177. package/dist/pagination/size/pagination-size.js +20 -5
  178. package/dist/pin-input/code.d.ts +10 -0
  179. package/dist/pin-input/code.js +13 -0
  180. package/dist/pin-input/root/pin-input-root.d.ts +25 -1
  181. package/dist/pin-input/root/pin-input-root.js +10 -11
  182. package/dist/popover/hide-outside.d.ts +14 -0
  183. package/dist/popover/hide-outside.js +41 -0
  184. package/dist/popover/root/popover-root.d.ts +57 -7
  185. package/dist/popover/root/popover-root.js +58 -3
  186. package/dist/progress/root/progress-root.d.ts +20 -0
  187. package/dist/progress/root/progress-root.js +15 -15
  188. package/dist/qr-code/export.d.ts +26 -1
  189. package/dist/qr-code/export.js +14 -0
  190. package/dist/qr-code/root/qr-code-root.d.ts +19 -5
  191. package/dist/qr-code/root/qr-code-root.js +58 -9
  192. package/dist/quote/marks.d.ts +8 -0
  193. package/dist/quote/marks.js +5 -0
  194. package/dist/quote/root/quote-root.d.ts +14 -2
  195. package/dist/quote/root/quote-root.js +23 -1
  196. package/dist/radio/group/radio-group.d.ts +4 -10
  197. package/dist/radio/group/radio-group.js +5 -10
  198. package/dist/radio/root/radio-root.d.ts +6 -2
  199. package/dist/radio/root/radio-root.js +6 -1
  200. package/dist/rating/root/rating-root.d.ts +10 -5
  201. package/dist/rating/root/rating-root.js +32 -8
  202. package/dist/rating/steps.d.ts +7 -0
  203. package/dist/rating/steps.js +9 -0
  204. package/dist/scatter-chart/fit.d.ts +15 -0
  205. package/dist/scatter-chart/fit.js +35 -0
  206. package/dist/scatter-chart/root/scatter-chart-root.d.ts +21 -1
  207. package/dist/scatter-chart/root/scatter-chart-root.js +30 -17
  208. package/dist/scroll-area/root/scroll-area-root.d.ts +84 -0
  209. package/dist/scroll-area/root/scroll-area-root.js +106 -7
  210. package/dist/scroll-area/scrollbar-controller.d.ts +111 -0
  211. package/dist/scroll-area/scrollbar-controller.js +172 -0
  212. package/dist/scroll-area/scrollbar.d.ts +92 -0
  213. package/dist/scroll-area/scrollbar.js +33 -0
  214. package/dist/select/root/select-root.d.ts +15 -0
  215. package/dist/select/root/select-root.js +18 -6
  216. package/dist/skeleton/root/skeleton-root.d.ts +3 -0
  217. package/dist/skeleton/root/skeleton-root.js +4 -2
  218. package/dist/skip-link/root/skip-link-root.js +2 -2
  219. package/dist/slider/root/slider-root.d.ts +41 -4
  220. package/dist/slider/root/slider-root.js +23 -3
  221. package/dist/sparkline/readings.d.ts +18 -0
  222. package/dist/sparkline/readings.js +19 -0
  223. package/dist/sparkline/root/sparkline-root.d.ts +78 -7
  224. package/dist/sparkline/root/sparkline-root.js +118 -23
  225. package/dist/speed-dial/root/speed-dial-root.js +2 -2
  226. package/dist/splitter/root/splitter-root.d.ts +20 -12
  227. package/dist/splitter/root/splitter-root.js +226 -203
  228. package/dist/splitter/snap.d.ts +9 -0
  229. package/dist/splitter/snap.js +12 -0
  230. package/dist/stat/root/stat-root.d.ts +14 -5
  231. package/dist/stat/root/stat-root.js +21 -5
  232. package/dist/steps/reach.d.ts +20 -0
  233. package/dist/steps/reach.js +15 -0
  234. package/dist/steps/root/steps-root.d.ts +76 -0
  235. package/dist/steps/root/steps-root.js +93 -1
  236. package/dist/steps/step/step.d.ts +45 -2
  237. package/dist/steps/step/step.js +33 -6
  238. package/dist/switch/root/switch-root.d.ts +10 -0
  239. package/dist/table/column/table-column.d.ts +11 -10
  240. package/dist/table/column/table-column.js +8 -19
  241. package/dist/table/root/table-root.d.ts +126 -4
  242. package/dist/table/root/table-root.js +156 -6
  243. package/dist/table/row/table-row.d.ts +47 -1
  244. package/dist/table/row/table-row.js +39 -2
  245. package/dist/tabs/panel/tab-panel.d.ts +22 -5
  246. package/dist/tabs/panel/tab-panel.js +34 -6
  247. package/dist/tabs/root/tabs-root.d.ts +37 -1
  248. package/dist/tabs/root/tabs-root.js +22 -4
  249. package/dist/tabs/tab/tab.d.ts +41 -4
  250. package/dist/tabs/tab/tab.js +49 -3
  251. package/dist/tag/group/tag-group.d.ts +31 -4
  252. package/dist/tag/group/tag-group.js +46 -7
  253. package/dist/tag/root/tag-root.js +9 -2
  254. package/dist/textarea/root/textarea-root.d.ts +28 -1
  255. package/dist/textarea/root/textarea-root.js +40 -1
  256. package/dist/time-input/root/time-input-root.d.ts +5 -1
  257. package/dist/time-input/root/time-input-root.js +16 -8
  258. package/dist/time-picker/root/time-picker-root.d.ts +18 -4
  259. package/dist/time-picker/root/time-picker-root.js +7 -10
  260. package/dist/time-picker/wheel-name.d.ts +9 -0
  261. package/dist/time-picker/wheel-name.js +15 -0
  262. package/dist/timeline/group/timeline-group.d.ts +46 -0
  263. package/dist/timeline/group/timeline-group.js +37 -0
  264. package/dist/timeline/index.d.ts +1 -0
  265. package/dist/timeline/index.js +1 -0
  266. package/dist/timeline/root/timeline-root.d.ts +10 -3
  267. package/dist/toast/item/toast-item.d.ts +24 -18
  268. package/dist/toast/item/toast-item.js +36 -40
  269. package/dist/toast/root/toast-root.d.ts +6 -0
  270. package/dist/toast/root/toast-root.js +16 -1
  271. package/dist/toggle/group/toggle-group.d.ts +24 -3
  272. package/dist/toggle/group/toggle-group.js +34 -5
  273. package/dist/toolbar/root/toolbar-root.d.ts +13 -0
  274. package/dist/toolbar/root/toolbar-root.js +15 -5
  275. package/dist/tooltip/root/tooltip-root.d.ts +13 -2
  276. package/dist/tooltip/root/tooltip-root.js +9 -1
  277. package/dist/tour/back.d.ts +10 -0
  278. package/dist/tour/back.js +8 -0
  279. package/dist/tour/root/tour-root.d.ts +30 -2
  280. package/dist/tour/root/tour-root.js +34 -8
  281. package/dist/tree/item/tree-item.d.ts +61 -4
  282. package/dist/tree/item/tree-item.js +92 -20
  283. package/dist/tree/root/tree-root.d.ts +58 -0
  284. package/dist/tree/root/tree-root.js +80 -16
  285. package/dist/tree/selection.d.ts +24 -0
  286. package/dist/tree/selection.js +13 -0
  287. package/dist/trend/root/trend-root.d.ts +43 -18
  288. package/dist/trend/root/trend-root.js +31 -6
  289. package/dist/video/media-events.d.ts +44 -0
  290. package/dist/video/media-events.js +35 -0
  291. package/dist/video/root/video-root.d.ts +117 -18
  292. package/dist/video/root/video-root.js +93 -47
  293. package/dist/video-playlist/menu/video-playlist-menu.d.ts +5 -0
  294. package/dist/video-playlist/menu/video-playlist-menu.js +3 -1
  295. package/dist/video-playlist/order.d.ts +41 -0
  296. package/dist/video-playlist/order.js +34 -0
  297. package/dist/video-playlist/root/video-playlist-root.d.ts +77 -3
  298. package/dist/video-playlist/root/video-playlist-root.js +60 -16
  299. package/dist/virtual-list/controls.d.ts +4 -0
  300. package/dist/virtual-list/controls.js +30 -0
  301. package/dist/virtual-list/fill.d.ts +22 -0
  302. package/dist/virtual-list/fill.js +23 -0
  303. package/dist/virtual-list/keys.d.ts +15 -0
  304. package/dist/virtual-list/keys.js +24 -0
  305. package/dist/virtual-list/plan.d.ts +49 -0
  306. package/dist/virtual-list/plan.js +16 -0
  307. package/dist/virtual-list/root/virtual-list-root.d.ts +259 -26
  308. package/dist/virtual-list/root/virtual-list-root.js +333 -49
  309. package/lint.json +1 -1
  310. package/package.json +8 -8
  311. package/types/jsx.d.ts +8113 -1394
  312. package/types/svelte.d.ts +2 -0
  313. package/types/vue.d.ts +1678 -353
  314. package/dist/data-table/root/order.d.ts +0 -141
  315. package/dist/data-table/root/order.js +0 -76
  316. package/dist/listbox/range.d.ts +0 -17
  317. package/dist/listbox/range.js +0 -5
  318. package/dist/tag/selection.d.ts +0 -10
  319. package/dist/tag/selection.js +0 -12
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, drawDismiss, drawDismissGlyph, HelixElement, hostAria, isRtl, MixinDismissible, requestChange, SwipeController, settleSwipe, swipeEdge, toneMark, towardEdge, } from '@fusion.dev/helix-core';
7
+ import { CountdownController, customElement, drawDismiss, drawDismissGlyph, HelixElement, hostAria, isRtl, MixinDismissible, requestChange, SwipeController, settleSwipe, swipeEdge, toneMark, towardEdge, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
@@ -31,17 +31,31 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
31
31
  start: (_target, event) => event.pointerType !== 'mouse',
32
32
  surface: () => this.partNamed('item'),
33
33
  });
34
+ this.countdown = new CountdownController(this, {
35
+ done: () => {
36
+ this.dismiss();
37
+ },
38
+ paused: (paused) => {
39
+ this.toggleAttribute('data-paused', paused);
40
+ },
41
+ });
34
42
  this.openState = undefined;
35
- this.holds = 0;
36
43
  this.handlePause = () => {
37
- this.holds += 1;
38
- this.pause();
44
+ this.countdown.hold();
39
45
  };
40
46
  this.handleResume = () => {
41
- this.holds = Math.max(this.holds - 1, 0);
42
- if (this.holds === 0) {
43
- this.resume();
47
+ this.countdown.release();
48
+ };
49
+ this.name = () => {
50
+ const words = this.partNamed('content');
51
+ if (!words) {
52
+ return;
44
53
  }
54
+ const heading = this.assigned('heading');
55
+ hostAria(this.internals, {
56
+ describedBy: this.assigned('description'),
57
+ labelledBy: heading.length > 0 ? heading : [words],
58
+ });
45
59
  };
46
60
  }
47
61
  get open() {
@@ -60,8 +74,7 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
60
74
  if (!this.open) {
61
75
  return true;
62
76
  }
63
- clearTimeout(this.timer);
64
- this.timer = undefined;
77
+ this.countdown.cancel();
65
78
  return requestChange({
66
79
  apply: () => {
67
80
  const previous = this.open;
@@ -74,25 +87,10 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
74
87
  });
75
88
  }
76
89
  pause() {
77
- if (this.timer === undefined || this.startedAt === undefined) {
78
- return;
79
- }
80
- clearTimeout(this.timer);
81
- this.timer = undefined;
82
- this.remaining = Math.max((this.remaining ?? 0) - (Date.now() - this.startedAt), 0);
83
- this.startedAt = undefined;
84
- this.toggleAttribute('data-paused', true);
90
+ this.countdown.pause();
85
91
  }
86
92
  resume() {
87
- if (this.timer !== undefined || this.remaining === undefined || this.remaining <= 0) {
88
- return;
89
- }
90
- this.startedAt = Date.now();
91
- this.toggleAttribute('data-paused', false);
92
- this.timer = setTimeout(() => {
93
- this.timer = undefined;
94
- this.dismiss();
95
- }, this.remaining);
93
+ this.countdown.resume();
96
94
  }
97
95
  connectedCallback() {
98
96
  super.connectedCallback();
@@ -100,11 +98,6 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
100
98
  this.resume();
101
99
  }
102
100
  }
103
- disconnectedCallback() {
104
- super.disconnectedCallback();
105
- this.pause();
106
- this.holds = 0;
107
- }
108
101
  willUpdate(changed) {
109
102
  super.willUpdate(changed);
110
103
  this.toggleAttribute('data-closed', !this.open);
@@ -115,17 +108,16 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
115
108
  }
116
109
  updated(changed) {
117
110
  super.updated(changed);
118
- const words = this.partNamed('content');
119
- if (words) {
120
- hostAria(this.internals, { labelledBy: [words] });
121
- }
111
+ this.name();
112
+ }
113
+ assigned(name) {
114
+ return (this.renderRoot
115
+ ?.querySelector(`slot[name="${name}"]`)
116
+ ?.assignedElements({ flatten: true }) ?? []);
122
117
  }
123
118
  firstUpdated(changed) {
124
119
  super.firstUpdated(changed);
125
- if (this.duration !== undefined && this.duration > 0) {
126
- this.remaining = this.duration;
127
- this.resume();
128
- }
120
+ this.countdown.start(this.duration);
129
121
  }
130
122
  renderIcon(mark) {
131
123
  return html `<slot name="icon">
@@ -158,7 +150,11 @@ let HelixHeadlessToastItem = class HelixHeadlessToastItem extends MixinDismissib
158
150
  ${this.renderIcon(mark)}
159
151
  </span>`
160
152
  : nothing}
161
- <div part="content"><slot></slot></div>
153
+ <div part="content">
154
+ <slot name="heading" part="heading" @slotchange=${this.name}></slot>
155
+ <slot name="description" part="description" @slotchange=${this.name}></slot>
156
+ <slot></slot>
157
+ </div>
162
158
  <div part="actions"><slot name="actions"></slot></div>
163
159
  ${this.dismissible
164
160
  ? drawDismiss({
@@ -109,10 +109,16 @@ export declare class HelixHeadlessToast extends HelixElement {
109
109
  * stack, holding `message` as its text. The region removes it once it has
110
110
  * been dismissed and has finished leaving, which is the one case where it
111
111
  * removes anything: a message you render stays yours.
112
+ *
113
+ * `heading` gives the message a title, which names it, and `message` becomes
114
+ * the line of detail under it. `action` is an element for the message's
115
+ * `actions` slot, such as an Undo button you have wired up.
112
116
  */
113
117
  add(message: string, options?: {
118
+ action?: Element;
114
119
  dismissible?: boolean;
115
120
  duration?: number;
121
+ heading?: string;
116
122
  tone?: 'danger' | 'info' | 'success' | 'warning';
117
123
  }): HTMLElement;
118
124
  /** Removes a message `add()` made, once it has hidden and finished leaving. */
@@ -92,7 +92,16 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
92
92
  add(message, options = {}) {
93
93
  const tier = this.constructor.tier;
94
94
  const item = document.createElement(`${tier}toast-item`);
95
- item.textContent = message;
95
+ if (options.heading === undefined) {
96
+ item.textContent = message;
97
+ }
98
+ else {
99
+ item.append(slotted('heading', options.heading), slotted('description', message));
100
+ }
101
+ if (options.action) {
102
+ options.action.setAttribute('slot', 'actions');
103
+ item.append(options.action);
104
+ }
96
105
  if (options.tone) {
97
106
  item.setAttribute('tone', options.tone);
98
107
  }
@@ -238,3 +247,9 @@ const popoverOpen = (region) => {
238
247
  const focusTarget = (item) => item.shadowRoot?.querySelector('[part="dismiss"]') ??
239
248
  focusableElements(item)[0] ??
240
249
  null;
250
+ const slotted = (slot, words) => {
251
+ const element = document.createElement('div');
252
+ element.slot = slot;
253
+ element.textContent = words;
254
+ return element;
255
+ };
@@ -18,9 +18,12 @@ declare const HelixHeadlessToggleGroup_base: (new (...args: any[]) => import("@f
18
18
  * say whether they are pressed with `aria-pressed`, as React Aria's
19
19
  * ToggleButtonGroup and Radix's ToggleGroup do. A press presses or releases
20
20
  * one item, the arrow keys move focus without pressing, and `value` is the
21
- * pressed values, comma separated, which `values` also gives as a list. The
22
- * form receives one entry per pressed value. The indicator stays hidden, and
23
- * each pressed item is marked with `:state(pressed)`.
21
+ * pressed values, comma separated, which `values` also gives as a list. Use
22
+ * `values` where an item's value holds a comma. The form receives one entry
23
+ * per pressed value, and a page the browser brings back presses the same
24
+ * items again. The indicator stays hidden, and each pressed item is marked
25
+ * with `:state(pressed)`. Inside a toolbar it is a named group of that
26
+ * toolbar's controls instead, so a reader meets one toolbar.
24
27
  *
25
28
  * `orientation="vertical"` runs the items down a column, says so to the
26
29
  * accessibility tree, and the up and down arrows move between them.
@@ -178,6 +181,16 @@ export declare class HelixHeadlessToggleGroup extends HelixHeadlessToggleGroup_b
178
181
  disconnectedCallback(): void;
179
182
  protected firstUpdated(changed: PropertyValues): void;
180
183
  protected updated(changed: PropertyValues): void;
184
+ /**
185
+ * The group's role: a radio group, a toolbar of pressed buttons, or, for
186
+ * pressed buttons inside a toolbar, a group.
187
+ *
188
+ * **A toolbar inside a toolbar is a reader's dead end**, so inside one the
189
+ * pressed buttons are a named group of the outer toolbar, as React Aria's
190
+ * ToggleButtonGroup demotes itself. Read by tag and by role, since the
191
+ * outer toolbar is a Helix one or the page's own `role="toolbar"`.
192
+ */
193
+ private get groupRole();
181
194
  protected willUpdate(changed: PropertyValues): void;
182
195
  /**
183
196
  * What the form receives: the value, or under `selection-mode="multiple"`
@@ -203,6 +216,14 @@ export declare class HelixHeadlessToggleGroup extends HelixHeadlessToggleGroup_b
203
216
  */
204
217
  get values(): string[];
205
218
  set values(next: string[]);
219
+ /** The pressed values as a list last written, which `values` reads. */
220
+ private chosen;
221
+ /**
222
+ * Presses the items a page the browser brings back held. Under
223
+ * `selection-mode="multiple"` the saved state is the form's entries, one per
224
+ * pressed value, which the shared restore leaves alone.
225
+ */
226
+ formStateRestoreCallback(state: string | File | FormData | null): void;
206
227
  /**
207
228
  * The row the track sits in, so something can sit beside it.
208
229
  *
@@ -39,11 +39,19 @@ let HelixHeadlessToggleGroup = class HelixHeadlessToggleGroup extends MixinContr
39
39
  return;
40
40
  }
41
41
  const value = event.detail.value;
42
- this.requestValue(this.multiple
43
- ? toggleValue(this.values, value, this.items.map((item) => item.value)).join(',')
44
- : value);
42
+ if (!this.multiple) {
43
+ this.requestValue(value);
44
+ return;
45
+ }
46
+ const next = toggleValue(this.values, value, this.items.map((item) => item.value));
47
+ const was = this.chosen;
48
+ this.chosen = next;
49
+ if (!this.requestValue(next.join(','))) {
50
+ this.chosen = was;
51
+ }
45
52
  });
46
53
  };
54
+ this.chosen = undefined;
47
55
  }
48
56
  adopt() {
49
57
  if (this.value !== '' || this.children === undefined) {
@@ -120,10 +128,18 @@ let HelixHeadlessToggleGroup = class HelixHeadlessToggleGroup extends MixinContr
120
128
  this.validate();
121
129
  this.linkHost();
122
130
  }
131
+ get groupRole() {
132
+ if (!this.multiple) {
133
+ return 'radiogroup';
134
+ }
135
+ return this.parentElement?.closest('[role="toolbar"], helix-toolbar, helix-headless-toolbar')
136
+ ? 'group'
137
+ : 'toolbar';
138
+ }
123
139
  willUpdate(changed) {
124
140
  super.willUpdate(changed);
125
141
  this.adopt();
126
- hostAria(this.internals, { label: this.label, role: this.multiple ? 'toolbar' : 'radiogroup' });
142
+ hostAria(this.internals, { label: this.label, role: this.groupRole });
127
143
  this.internals.ariaOrientation = this.orientation ?? null;
128
144
  this.internals.setFormValue(this.formValue());
129
145
  }
@@ -144,11 +160,24 @@ let HelixHeadlessToggleGroup = class HelixHeadlessToggleGroup extends MixinContr
144
160
  this.reportRequired(!this.answered, 'Choose one to continue.', 'track');
145
161
  }
146
162
  get values() {
147
- return this.multiple ? commaList(this.value) : this.value === '' ? [] : [this.value];
163
+ if (!this.multiple) {
164
+ return this.value === '' ? [] : [this.value];
165
+ }
166
+ return this.chosen && this.chosen.join(',') === this.value
167
+ ? [...this.chosen]
168
+ : commaList(this.value);
148
169
  }
149
170
  set values(next) {
171
+ this.chosen = [...next];
150
172
  this.value = next.join(',');
151
173
  }
174
+ formStateRestoreCallback(state) {
175
+ if (!(state instanceof FormData) || !this.multiple) {
176
+ super.formStateRestoreCallback(state);
177
+ return;
178
+ }
179
+ this.values = state.getAll(this.name).filter((one) => typeof one === 'string');
180
+ }
152
181
  render() {
153
182
  const inside = this.labelPlacement === 'start';
154
183
  const label = this.renderGroupLabel();
@@ -12,6 +12,14 @@ import { type PropertyValues, type TemplateResult } from 'lit';
12
12
  * focus counts as a control, including your own elements. A child that takes no
13
13
  * focus, such as a divider, is skipped. A menu is reached at its trigger.
14
14
  *
15
+ * Controls inside a plain wrapper, such as a `Button Group`, are each a stop
16
+ * of the toolbar's own, as React Aria's toolbar flattens a group: the arrows
17
+ * walk through the group's buttons and on past it, and the group takes no tab
18
+ * stop of its own.
19
+ *
20
+ * The arrows wrap from the last control to the first. Set `stop-at-ends` to
21
+ * keep them at the ends, as Radix's `loop` set to false does.
22
+ *
15
23
  * A nested composite, such as a toggle group, is one stop on the toolbar's
16
24
  * axis: the toolbar's arrows move past it, and the arrows across the toolbar
17
25
  * move inside it. A composite with a `focusable` property, as Toggle Group
@@ -49,6 +57,11 @@ export declare class HelixHeadlessToolbar extends HelixElement {
49
57
  * The direction the arrow keys move focus in.
50
58
  */
51
59
  orientation?: 'horizontal' | 'vertical';
60
+ /**
61
+ * Whether the arrow keys stop at the first and the last control. Unset, they
62
+ * wrap around from one end to the other.
63
+ */
64
+ stopAtEnds: boolean;
52
65
  private watcher;
53
66
  /**
54
67
  * The children that take part in the toolbar, in document order, each with
@@ -31,6 +31,7 @@ let HelixHeadlessToolbar = class HelixHeadlessToolbar extends HelixElement {
31
31
  target: () => this.partNamed('toolbar'),
32
32
  });
33
33
  this.wroteForeign = false;
34
+ this.stopAtEnds = false;
34
35
  this.handleFocusIn = (event) => {
35
36
  const control = this.origin(event);
36
37
  if (control) {
@@ -75,11 +76,14 @@ let HelixHeadlessToolbar = class HelixHeadlessToolbar extends HelixElement {
75
76
  return;
76
77
  }
77
78
  let next = current;
79
+ const last = controls.length - 1;
78
80
  if (forward) {
79
- next = (current + 1) % controls.length;
81
+ next = this.stopAtEnds ? Math.min(current + 1, last) : (current + 1) % controls.length;
80
82
  }
81
83
  else if (back) {
82
- next = (current - 1 + controls.length) % controls.length;
84
+ next = this.stopAtEnds
85
+ ? Math.max(current - 1, 0)
86
+ : (current - 1 + controls.length) % controls.length;
83
87
  }
84
88
  else if (event.key === 'Home') {
85
89
  next = 0;
@@ -110,9 +114,12 @@ let HelixHeadlessToolbar = class HelixHeadlessToolbar extends HelixElement {
110
114
  child.getAttribute('aria-hidden') === 'true') {
111
115
  continue;
112
116
  }
113
- const stops = takesFocus(child) ? this.inside(child) : this.within(child);
114
- if (stops.length > 0) {
115
- controls.push({ child, stops });
117
+ if (takesFocus(child)) {
118
+ controls.push({ child, stops: this.inside(child) });
119
+ continue;
120
+ }
121
+ for (const stop of this.within(child)) {
122
+ controls.push({ child: stop, stops: [stop] });
116
123
  }
117
124
  }
118
125
  return controls;
@@ -204,6 +211,9 @@ __decorate([
204
211
  __decorate([
205
212
  property({ reflect: true })
206
213
  ], HelixHeadlessToolbar.prototype, "orientation", void 0);
214
+ __decorate([
215
+ property({ attribute: 'stop-at-ends', type: Boolean })
216
+ ], HelixHeadlessToolbar.prototype, "stopAtEnds", void 0);
207
217
  HelixHeadlessToolbar = __decorate([
208
218
  customElement('helix-headless-toolbar')
209
219
  ], HelixHeadlessToolbar);
@@ -30,7 +30,9 @@ declare const HelixHeadlessTooltip_base: (new (...args: any[]) => import("@fusio
30
30
  *
31
31
  * The tooltip shows on hover and on focus. It hides on pointer leave, on blur,
32
32
  * on Escape, and when the trigger is activated. The pointer can move from the
33
- * trigger onto the bubble and the bubble stays.
33
+ * trigger onto the bubble and the bubble stays, unless you set
34
+ * `hoverable="false"`. `delay` is how long the pointer rests before it shows,
35
+ * and `delay-out` how long it stays once the pointer leaves.
34
36
  *
35
37
  * Once one tooltip is showing, moving to another trigger shows its tooltip
36
38
  * with no `delay`, and the first one hides. The same holds for `skip-delay`
@@ -87,7 +89,9 @@ export declare class HelixHeadlessTooltip extends HelixHeadlessTooltip_base {
87
89
  */
88
90
  delay: number;
89
91
  /**
90
- * How long the bubble stays after the pointer leaves, in milliseconds.
92
+ * How long the bubble stays after the pointer leaves the trigger or the
93
+ * bubble, in milliseconds: the close delay. It is the time a reader has to
94
+ * cross the gap onto the bubble.
91
95
  */
92
96
  delayOut: number;
93
97
  /**
@@ -115,6 +119,13 @@ export declare class HelixHeadlessTooltip extends HelixHeadlessTooltip_base {
115
119
  * why this does not reflect and nothing styles on it.
116
120
  */
117
121
  for: string;
122
+ /**
123
+ * Whether the pointer can move onto the bubble and the bubble stays, so a
124
+ * reader can read it under a magnifier or select its words, as WCAG 1.4.13
125
+ * asks. `hoverable="false"` hides the bubble once the pointer reaches it,
126
+ * for a bubble that covers something a reader moves on to.
127
+ */
128
+ hoverable: boolean;
118
129
  /**
119
130
  * The space between the trigger and the tip of the bubble, in pixels.
120
131
  *
@@ -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 { anchorElement, arrowReach, customElement, elementById, HelixElement, hostAria, linkDescription, MixinControllerOpen, PopoverController, reportRuntime, sideOf, unlinkDescription, } from '@fusion.dev/helix-core';
7
+ import { anchorElement, arrowReach, customElement, elementById, HelixElement, hostAria, linkDescription, MixinControllerOpen, onUnlessFalse, 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
10
  import { focusTarget } from '../focus-target.js';
@@ -23,6 +23,7 @@ let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpe
23
23
  this.delayOut = 100;
24
24
  this.disabled = false;
25
25
  this.for = '';
26
+ this.hoverable = true;
26
27
  this.offset = 8;
27
28
  this.persist = false;
28
29
  this.placement = 'top';
@@ -68,6 +69,10 @@ let HelixHeadlessTooltip = class HelixHeadlessTooltip extends MixinControllerOpe
68
69
  this.timer = setTimeout(() => this.show(), this.delay);
69
70
  };
70
71
  this.holdOnBubble = () => {
72
+ if (!this.hoverable) {
73
+ this.hideLater();
74
+ return;
75
+ }
71
76
  if (!this.named) {
72
77
  return;
73
78
  }
@@ -365,6 +370,9 @@ __decorate([
365
370
  __decorate([
366
371
  property()
367
372
  ], HelixHeadlessTooltip.prototype, "for", void 0);
373
+ __decorate([
374
+ property({ converter: onUnlessFalse })
375
+ ], HelixHeadlessTooltip.prototype, "hoverable", void 0);
368
376
  __decorate([
369
377
  property({ type: Number })
370
378
  ], HelixHeadlessTooltip.prototype, "offset", void 0);
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The stop Back goes to from `index`: the nearest stop before it that is not a
3
+ * `wait` stop, or `undefined` where there is none.
4
+ *
5
+ * A `wait` stop shows nothing and moves on by itself once its target is on the
6
+ * page, so going back onto one either moves straight on again or leaves the
7
+ * reader at a stop with nothing in it. Back passes over it to the stop that
8
+ * told the reader what to do.
9
+ */
10
+ export declare const stopBefore: (types: readonly (string | undefined)[], index: number) => number | undefined;
@@ -0,0 +1,8 @@
1
+ export const stopBefore = (types, index) => {
2
+ for (let at = Math.min(index, types.length) - 1; at >= 0; at -= 1) {
3
+ if (types[at] !== 'wait') {
4
+ return at;
5
+ }
6
+ }
7
+ return undefined;
8
+ };
@@ -22,6 +22,11 @@ declare const HelixHeadlessTour_base: (new (...args: any[]) => import("@fusion.d
22
22
  * `toggle` work as they do on `Dialog`. Setting `open` starts the run, and
23
23
  * `skip()` and `requestOpen(false)` end it early.
24
24
  *
25
+ * The box the light falls on is on the `spotlight` part as
26
+ * `--tour-spotlight-x`, `--tour-spotlight-y`, `--tour-spotlight-width` and
27
+ * `--tour-spotlight-height`, for a sheet that draws its own light, such as a
28
+ * ring around the target.
29
+ *
25
30
  * Each stop is told its place in the run, from `progress-label`, such as "2 of
26
31
  * 5". It describes the stop's panel, so a screen reader says it at every stop,
27
32
  * and `progress` draws it in the panel as well. A dialog or a floating stop,
@@ -50,12 +55,19 @@ declare const HelixHeadlessTour_base: (new (...args: any[]) => import("@fusion.d
50
55
  * @event {HelixCompleteEvent} helix-complete - Fired when the last stop is
51
56
  * finished.
52
57
  * @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.
58
+ * @event {HelixTourStatusEvent} helix-tour-status - Fired when the tour starts waiting at a `wait` stop, is skipped, or is completed, with the stop's index and `detail.status` saying which.
53
59
  * @event {ToggleEvent} toggle - Sent when the tour starts or ends, with `newState` and `oldState`.
54
60
  *
55
61
  * @csspart backdrop - Behind a dialog or a floating stop, which lights nothing. It draws no box until you give it one.
56
62
  * @csspart spotlight - The box over the current target. It also draws the dimmed area around the target.
57
63
  *
64
+ * @cssproperty --tour-spotlight-height - The lit box's height, in pixels, padding included. Written on the spotlight while it lights a target.
65
+ * @cssproperty --tour-spotlight-width - The lit box's width, in pixels, padding included. Written on the spotlight while it lights a target.
66
+ * @cssproperty --tour-spotlight-x - The lit box's left edge, from the window's left edge, in pixels. Written on the spotlight while it lights a target.
67
+ * @cssproperty --tour-spotlight-y - The lit box's top edge, from the window's top edge, in pixels. Written on the spotlight while it lights a target.
68
+ *
58
69
  * @cssstate open - While the tour is running.
70
+ * @cssstate waiting - While the tour waits at a `wait` stop for its target to be on the page.
59
71
  */
60
72
  export declare class HelixHeadlessTour extends HelixHeadlessTour_base {
61
73
  /**
@@ -131,7 +143,10 @@ export declare class HelixHeadlessTour extends HelixHeadlessTour_base {
131
143
  get length(): number;
132
144
  /** Goes to the next stop, and finishes the tour on the last stop. */
133
145
  next(): void;
134
- /** Goes to the previous stop. It does nothing on the first stop. */
146
+ /**
147
+ * Goes to the previous stop, passing over a `wait` stop, which shows nothing.
148
+ * It does nothing on the first stop, or where only `wait` stops come before.
149
+ */
135
150
  back(): void;
136
151
  /**
137
152
  * Ends the tour early, as a close. `helix-complete` is not fired.
@@ -164,7 +179,20 @@ export declare class HelixHeadlessTour extends HelixHeadlessTour_base {
164
179
  * where to be.
165
180
  */
166
181
  private follow;
167
- /** Focuses the current stop's panel once the stop has shown it. */
182
+ /**
183
+ * Where focus was put while a `wait` stop waits, so the move on from it still
184
+ * counts as a move from inside the tour while focus has stayed there.
185
+ */
186
+ private parked;
187
+ /**
188
+ * Focuses the current stop's panel once the stop has shown it.
189
+ *
190
+ * A `wait` stop shows no panel, and focus would fall to the body. It goes to
191
+ * the target of the stop before instead, which is usually the control the
192
+ * reader is asked to use, such as the button that opens the menu the stop
193
+ * waits for. Where that target holds no control, it goes back to where it
194
+ * was when the tour opened.
195
+ */
168
196
  private focusCurrent;
169
197
  /**
170
198
  * Tells each stop where it is in the run.
@@ -4,9 +4,10 @@ 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, deepActiveElement, deepContains, fillTemplate, HelixActivateEvent, HelixBeforeActivateEvent, HelixCompleteEvent, HelixElement, hostAria, MixinControllerOpen, requestChange, whenHydrated, } from '@fusion.dev/helix-core';
7
+ import { controlsIn, customElement, deepActiveElement, deepContains, fillTemplate, HelixActivateEvent, HelixBeforeActivateEvent, HelixCompleteEvent, HelixElement, HelixTourStatusEvent, hostAria, MixinControllerOpen, requestChange, whenHydrated, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property, queryAssignedElements, state } from 'lit/decorators.js';
10
+ import { stopBefore } from '../back.js';
10
11
  import { onPage, waitFor } from '../wait.js';
11
12
  let HelixHeadlessTour = class HelixHeadlessTour extends MixinControllerOpen(HelixElement) {
12
13
  constructor() {
@@ -69,16 +70,20 @@ let HelixHeadlessTour = class HelixHeadlessTour extends MixinControllerOpen(Heli
69
70
  this.move(this.index + 1);
70
71
  }
71
72
  back() {
72
- if (this.index <= 0) {
73
- return;
73
+ const to = stopBefore(this.stops.map((stop) => stop.type), this.index);
74
+ if (to !== undefined) {
75
+ this.move(to);
74
76
  }
75
- this.move(this.index - 1);
76
77
  }
77
78
  skip() {
78
- this.requestOpen(false);
79
+ const at = this.index;
80
+ if (this.open && this.requestOpen(false)) {
81
+ this.dispatchEvent(new HelixTourStatusEvent({ index: at, status: 'skipped' }));
82
+ }
79
83
  }
80
84
  finish() {
81
85
  this.dispatchEvent(new HelixCompleteEvent({ value: String(this.index) }));
86
+ this.dispatchEvent(new HelixTourStatusEvent({ index: this.index, status: 'completed' }));
82
87
  this.open = false;
83
88
  }
84
89
  move(to) {
@@ -115,6 +120,7 @@ let HelixHeadlessTour = class HelixHeadlessTour extends MixinControllerOpen(Heli
115
120
  this.unwait?.();
116
121
  this.unwait = undefined;
117
122
  this.waiting = undefined;
123
+ this.toggleState('waiting', false);
118
124
  }
119
125
  willUpdate(changed) {
120
126
  super.willUpdate(changed);
@@ -138,7 +144,13 @@ let HelixHeadlessTour = class HelixHeadlessTour extends MixinControllerOpen(Heli
138
144
  const opened = changed.has('open') && this.open && changed.get('open') === false;
139
145
  const closed = changed.has('open') && !this.open && changed.get('open') === true;
140
146
  const active = deepActiveElement();
141
- const inside = active === null || active === document.body || deepContains(this, active);
147
+ const inside = active === null ||
148
+ active === document.body ||
149
+ deepContains(this, active) ||
150
+ (this.parked !== undefined && active === this.parked);
151
+ if (opened || closed || changed.has('index')) {
152
+ this.parked = undefined;
153
+ }
142
154
  if (opened) {
143
155
  if (active instanceof HTMLElement && !deepContains(this, active)) {
144
156
  this.returnFocus = active;
@@ -158,10 +170,21 @@ let HelixHeadlessTour = class HelixHeadlessTour extends MixinControllerOpen(Heli
158
170
  }
159
171
  focusCurrent() {
160
172
  const stops = this.stops;
161
- const stop = stops[Math.max(0, Math.min(this.index, stops.length - 1))];
173
+ const at = Math.max(0, Math.min(this.index, stops.length - 1));
174
+ const stop = stops[at];
162
175
  if (!stop) {
163
176
  return;
164
177
  }
178
+ if (stop.type === 'wait') {
179
+ const before = stopBefore(stops.map((one) => one.type), at);
180
+ const target = before === undefined ? undefined : stops[before]?.target;
181
+ const park = (target ? controlsIn([target])[0] : undefined) ?? this.returnFocus;
182
+ if (park?.isConnected) {
183
+ park.focus();
184
+ this.parked = park;
185
+ }
186
+ return;
187
+ }
165
188
  void stop.updateComplete.then(() => {
166
189
  if (this.open && stop.current) {
167
190
  stop.focus();
@@ -213,12 +236,15 @@ let HelixHeadlessTour = class HelixHeadlessTour extends MixinControllerOpen(Heli
213
236
  this.unwait?.();
214
237
  this.unwait = undefined;
215
238
  this.waiting = next;
239
+ this.toggleState('waiting', next !== undefined);
216
240
  if (!next) {
217
241
  return;
218
242
  }
243
+ this.dispatchEvent(new HelixTourStatusEvent({ index: this.index, status: 'waiting' }));
219
244
  this.unwait = waitFor(next.getRootNode(), () => onPage(next.target), () => {
220
245
  this.waiting = undefined;
221
246
  this.unwait = undefined;
247
+ this.toggleState('waiting', false);
222
248
  queueMicrotask(() => {
223
249
  if (this.open && this.current === next) {
224
250
  this.next();
@@ -274,7 +300,7 @@ let HelixHeadlessTour = class HelixHeadlessTour extends MixinControllerOpen(Heli
274
300
  : html `<div
275
301
  part="spotlight"
276
302
  aria-hidden="true"
277
- style=${`left: ${spot.left}px; top: ${spot.top}px; block-size: ${spot.height}px; inline-size: ${spot.width}px`}
303
+ style=${`left: ${spot.left}px; top: ${spot.top}px; block-size: ${spot.height}px; inline-size: ${spot.width}px; --tour-spotlight-x: ${spot.left}px; --tour-spotlight-y: ${spot.top}px; --tour-spotlight-width: ${spot.width}px; --tour-spotlight-height: ${spot.height}px`}
278
304
  ></div>`}
279
305
  <slot></slot>`;
280
306
  }