@fusion.dev/helix-headless 0.143.0 → 0.145.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 (314) hide show
  1. package/custom-elements.json +16990 -1383
  2. package/dist/accordion/item/accordion-item.d.ts +48 -12
  3. package/dist/accordion/item/accordion-item.js +26 -5
  4. package/dist/accordion/root/accordion-root.d.ts +6 -0
  5. package/dist/accordion/root/accordion-root.js +7 -1
  6. package/dist/announcement/root/announcement-root.d.ts +21 -1
  7. package/dist/announcement/root/announcement-root.js +36 -1
  8. package/dist/app-header/root/app-header-root.d.ts +7 -0
  9. package/dist/app-header/root/app-header-root.js +5 -1
  10. package/dist/app-header/sectioning.d.ts +7 -0
  11. package/dist/app-header/sectioning.js +26 -0
  12. package/dist/area-chart/root/area-chart-root.d.ts +12 -4
  13. package/dist/area-chart/root/area-chart-root.js +24 -7
  14. package/dist/avatar/root/avatar-root.d.ts +14 -0
  15. package/dist/avatar/root/avatar-root.js +23 -9
  16. package/dist/badge/root/badge-root.d.ts +11 -7
  17. package/dist/badge/root/badge-root.js +1 -1
  18. package/dist/bar-chart/root/bar-chart-root.d.ts +12 -3
  19. package/dist/bar-chart/root/bar-chart-root.js +17 -10
  20. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +32 -1
  21. package/dist/breadcrumbs/root/breadcrumbs-root.js +25 -2
  22. package/dist/button/root/button-root.d.ts +47 -1
  23. package/dist/button/root/button-root.js +38 -4
  24. package/dist/callout/root/callout-root.d.ts +18 -1
  25. package/dist/callout/root/callout-root.js +15 -4
  26. package/dist/canvas/root/canvas-root.d.ts +38 -3
  27. package/dist/canvas/root/canvas-root.js +121 -40
  28. package/dist/card/root/card-root.d.ts +30 -1
  29. package/dist/card/root/card-root.js +38 -5
  30. package/dist/carousel/root/carousel-root.d.ts +90 -0
  31. package/dist/carousel/root/carousel-root.js +134 -12
  32. package/dist/chat/composer/chat-composer.d.ts +38 -6
  33. package/dist/chat/composer/chat-composer.js +42 -9
  34. package/dist/chat/message/chat-message.d.ts +32 -1
  35. package/dist/chat/message/chat-message.js +25 -9
  36. package/dist/chat/naming.d.ts +22 -0
  37. package/dist/chat/naming.js +12 -0
  38. package/dist/chat/relative-clock.d.ts +39 -0
  39. package/dist/chat/relative-clock.js +31 -0
  40. package/dist/chat/root/chat-root.d.ts +36 -0
  41. package/dist/chat/root/chat-root.js +24 -1
  42. package/dist/checkbox/root/checkbox-root.js +2 -0
  43. package/dist/checkbox-group/root/checkbox-group-root.d.ts +53 -3
  44. package/dist/checkbox-group/root/checkbox-group-root.js +71 -22
  45. package/dist/code-block/lines.d.ts +13 -0
  46. package/dist/code-block/lines.js +2 -0
  47. package/dist/code-block/root/code-block-root.d.ts +38 -1
  48. package/dist/code-block/root/code-block-root.js +28 -7
  49. package/dist/color-input/root/color-input-root.d.ts +34 -1
  50. package/dist/color-input/root/color-input-root.js +23 -4
  51. package/dist/color-picker/channels.d.ts +26 -0
  52. package/dist/color-picker/channels.js +84 -0
  53. package/dist/color-picker/root/color-picker-root.d.ts +81 -5
  54. package/dist/color-picker/root/color-picker-root.js +103 -10
  55. package/dist/combobox/root/combobox-root.d.ts +38 -3
  56. package/dist/combobox/root/combobox-root.js +64 -2
  57. package/dist/command/root/command-root.d.ts +30 -4
  58. package/dist/command/root/command-root.js +33 -3
  59. package/dist/copy-button/from.d.ts +22 -0
  60. package/dist/copy-button/from.js +28 -0
  61. package/dist/copy-button/root/copy-button-root.d.ts +47 -1
  62. package/dist/copy-button/root/copy-button-root.js +44 -8
  63. package/dist/data-table/root/data-table-root.d.ts +150 -2
  64. package/dist/data-table/root/data-table-root.js +303 -29
  65. package/dist/data-table/tree.d.ts +40 -0
  66. package/dist/data-table/tree.js +55 -0
  67. package/dist/date-input/root/date-input-root.d.ts +73 -4
  68. package/dist/date-input/root/date-input-root.js +93 -43
  69. package/dist/date-picker/root/date-picker-root.d.ts +145 -1
  70. package/dist/date-picker/root/date-picker-root.js +239 -48
  71. package/dist/description-list/item/description-list-item.d.ts +17 -2
  72. package/dist/description-list/item/description-list-item.js +15 -2
  73. package/dist/description-list/root/description-list-root.d.ts +27 -1
  74. package/dist/description-list/root/description-list-root.js +26 -1
  75. package/dist/dialog/description.d.ts +9 -0
  76. package/dist/dialog/description.js +14 -0
  77. package/dist/dialog/root/dialog-root.d.ts +64 -1
  78. package/dist/dialog/root/dialog-root.js +49 -23
  79. package/dist/donut-chart/root/donut-chart-root.d.ts +25 -4
  80. package/dist/donut-chart/root/donut-chart-root.js +21 -6
  81. package/dist/drawer/root/drawer-root.d.ts +63 -2
  82. package/dist/drawer/root/drawer-root.js +95 -19
  83. package/dist/drawer/swipe-start.d.ts +9 -0
  84. package/dist/drawer/swipe-start.js +12 -0
  85. package/dist/drilldown/item/drilldown-item.d.ts +11 -6
  86. package/dist/drilldown/item/drilldown-item.js +8 -5
  87. package/dist/drilldown/root/drilldown-root.d.ts +11 -0
  88. package/dist/drilldown/root/drilldown-root.js +8 -3
  89. package/dist/element-events.generated.js +61 -13
  90. package/dist/empty/root/empty-root.d.ts +1 -1
  91. package/dist/file-input/root/file-input-root.d.ts +47 -0
  92. package/dist/file-input/root/file-input-root.js +60 -22
  93. package/dist/file-input/screen.d.ts +35 -0
  94. package/dist/file-input/screen.js +49 -0
  95. package/dist/filter-input/menu/filter-menu.d.ts +3 -0
  96. package/dist/filter-input/menu/filter-menu.js +8 -4
  97. package/dist/filter-input/root/filter-input-root.d.ts +38 -4
  98. package/dist/filter-input/root/filter-input-root.js +67 -3
  99. package/dist/filter-input/suggest.d.ts +17 -0
  100. package/dist/filter-input/suggest.js +23 -0
  101. package/dist/format-date/options.d.ts +33 -0
  102. package/dist/format-date/options.js +42 -0
  103. package/dist/format-date/root/format-date-root.d.ts +51 -0
  104. package/dist/format-date/root/format-date-root.js +58 -38
  105. package/dist/heatmap/root/heatmap-root.d.ts +23 -6
  106. package/dist/heatmap/root/heatmap-root.js +24 -13
  107. package/dist/icon/index.d.ts +2 -0
  108. package/dist/icon/index.js +2 -0
  109. package/dist/icon/registry.d.ts +37 -0
  110. package/dist/icon/registry.js +83 -0
  111. package/dist/icon/root/icon-root.d.ts +30 -4
  112. package/dist/icon/root/icon-root.js +41 -6
  113. package/dist/icon/root/index.d.ts +2 -0
  114. package/dist/icon/root/index.js +2 -0
  115. package/dist/icon/set.d.ts +1 -0
  116. package/dist/icon/set.js +3 -0
  117. package/dist/image/root/image-root.d.ts +14 -0
  118. package/dist/image/root/image-root.js +23 -2
  119. package/dist/input/root/input-root.d.ts +11 -0
  120. package/dist/input/root/input-root.js +16 -1
  121. package/dist/kbd/root/kbd-root.d.ts +20 -13
  122. package/dist/kbd/root/kbd-root.js +35 -37
  123. package/dist/kbd/shortcut.d.ts +18 -0
  124. package/dist/kbd/shortcut.js +35 -0
  125. package/dist/legend/hidden-series.d.ts +8 -0
  126. package/dist/legend/hidden-series.js +13 -0
  127. package/dist/legend/root/legend-root.d.ts +56 -0
  128. package/dist/legend/root/legend-root.js +54 -5
  129. package/dist/lightbox/item/lightbox-item.d.ts +15 -0
  130. package/dist/lightbox/item/lightbox-item.js +10 -1
  131. package/dist/lightbox/root/lightbox-root.d.ts +61 -1
  132. package/dist/lightbox/root/lightbox-root.js +94 -4
  133. package/dist/line-chart/root/line-chart-root.d.ts +11 -3
  134. package/dist/line-chart/root/line-chart-root.js +19 -5
  135. package/dist/list/item/list-item.d.ts +68 -1
  136. package/dist/list/item/list-item.js +66 -4
  137. package/dist/list/numbering.d.ts +14 -0
  138. package/dist/list/numbering.js +8 -0
  139. package/dist/list/root/list-root.d.ts +106 -9
  140. package/dist/list/root/list-root.js +189 -4
  141. package/dist/list/selection.d.ts +19 -0
  142. package/dist/list/selection.js +21 -0
  143. package/dist/listbox/root/listbox-root.d.ts +74 -3
  144. package/dist/listbox/root/listbox-root.js +86 -9
  145. package/dist/loader/busy.d.ts +17 -0
  146. package/dist/loader/busy.js +24 -0
  147. package/dist/loader/root/loader-root.d.ts +37 -0
  148. package/dist/loader/root/loader-root.js +52 -3
  149. package/dist/map/root/map-root.d.ts +6 -2
  150. package/dist/map/root/map-root.js +5 -2
  151. package/dist/megamenu/root/megamenu-root.d.ts +21 -0
  152. package/dist/megamenu/root/megamenu-root.js +16 -2
  153. package/dist/menu/index.d.ts +1 -0
  154. package/dist/menu/index.js +1 -0
  155. package/dist/menu/item/menu-item.d.ts +38 -11
  156. package/dist/menu/item/menu-item.js +33 -1
  157. package/dist/menu/root/menu-root.d.ts +25 -1
  158. package/dist/menu/root/menu-root.js +63 -6
  159. package/dist/menu/section/menu-section.d.ts +55 -0
  160. package/dist/menu/section/menu-section.js +60 -0
  161. package/dist/meter/root/meter-root.d.ts +7 -0
  162. package/dist/meter/root/meter-root.js +6 -3
  163. package/dist/navigation/root/navigation-root.d.ts +16 -1
  164. package/dist/navigation/root/navigation-root.js +27 -1
  165. package/dist/notifications/feed-keys.d.ts +10 -0
  166. package/dist/notifications/feed-keys.js +14 -0
  167. package/dist/notifications/notification/notification.d.ts +17 -0
  168. package/dist/notifications/notification/notification.js +21 -2
  169. package/dist/notifications/root/notifications-root.d.ts +60 -0
  170. package/dist/notifications/root/notifications-root.js +76 -1
  171. package/dist/number-input/root/number-input-root.d.ts +47 -0
  172. package/dist/number-input/root/number-input-root.js +58 -22
  173. package/dist/object-inspector/root/object-inspector-root.d.ts +98 -16
  174. package/dist/object-inspector/root/object-inspector-root.js +180 -80
  175. package/dist/object-inspector/rows.d.ts +57 -0
  176. package/dist/object-inspector/rows.js +86 -0
  177. package/dist/option/root/option-root.d.ts +54 -5
  178. package/dist/option/root/option-root.js +34 -5
  179. package/dist/outline/levels.d.ts +31 -0
  180. package/dist/outline/levels.js +23 -0
  181. package/dist/outline/root/outline-root.d.ts +68 -3
  182. package/dist/outline/root/outline-root.js +73 -8
  183. package/dist/pagination/size/pagination-size.d.ts +11 -2
  184. package/dist/pagination/size/pagination-size.js +19 -4
  185. package/dist/pin-input/format.d.ts +7 -0
  186. package/dist/pin-input/format.js +16 -0
  187. package/dist/pin-input/root/pin-input-root.d.ts +21 -0
  188. package/dist/pin-input/root/pin-input-root.js +29 -2
  189. package/dist/popover/root/popover-root.d.ts +62 -4
  190. package/dist/popover/root/popover-root.js +53 -5
  191. package/dist/progress/root/progress-root.d.ts +7 -0
  192. package/dist/progress/root/progress-root.js +9 -3
  193. package/dist/qr-code/export.d.ts +31 -0
  194. package/dist/qr-code/export.js +10 -0
  195. package/dist/qr-code/root/qr-code-root.d.ts +26 -0
  196. package/dist/qr-code/root/qr-code-root.js +49 -2
  197. package/dist/radio/group/radio-group.d.ts +17 -0
  198. package/dist/radio/group/radio-group.js +14 -1
  199. package/dist/rating/root/rating-root.d.ts +25 -0
  200. package/dist/rating/root/rating-root.js +46 -4
  201. package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
  202. package/dist/scatter-chart/root/scatter-chart-root.js +25 -7
  203. package/dist/scroll-area/root/scroll-area-root.d.ts +113 -0
  204. package/dist/scroll-area/root/scroll-area-root.js +218 -3
  205. package/dist/scroll-area/scrollbar.d.ts +65 -0
  206. package/dist/scroll-area/scrollbar.js +24 -0
  207. package/dist/select/root/select-root.d.ts +24 -0
  208. package/dist/select/root/select-root.js +21 -7
  209. package/dist/skeleton/root/skeleton-root.d.ts +25 -0
  210. package/dist/skeleton/root/skeleton-root.js +17 -2
  211. package/dist/slider/root/slider-root.d.ts +39 -0
  212. package/dist/slider/root/slider-root.js +45 -9
  213. package/dist/splitter/root/splitter-root.d.ts +13 -0
  214. package/dist/splitter/root/splitter-root.js +20 -2
  215. package/dist/splitter/snap.d.ts +9 -0
  216. package/dist/splitter/snap.js +12 -0
  217. package/dist/stat/root/stat-root.d.ts +2 -0
  218. package/dist/stat/root/stat-root.js +1 -1
  219. package/dist/steps/reach.d.ts +15 -0
  220. package/dist/steps/reach.js +12 -0
  221. package/dist/steps/root/steps-root.d.ts +30 -0
  222. package/dist/steps/root/steps-root.js +53 -0
  223. package/dist/steps/step/step.d.ts +39 -2
  224. package/dist/steps/step/step.js +29 -7
  225. package/dist/switch/root/switch-root.d.ts +12 -2
  226. package/dist/switch/root/switch-root.js +6 -1
  227. package/dist/table/column/table-column.d.ts +11 -0
  228. package/dist/table/column/table-column.js +6 -1
  229. package/dist/table/root/table-root.d.ts +101 -0
  230. package/dist/table/root/table-root.js +166 -5
  231. package/dist/table/row/table-row.d.ts +47 -1
  232. package/dist/table/row/table-row.js +39 -2
  233. package/dist/tabs/panel/tab-panel.d.ts +9 -5
  234. package/dist/tabs/panel/tab-panel.js +3 -4
  235. package/dist/tabs/root/tabs-root.d.ts +25 -1
  236. package/dist/tabs/root/tabs-root.js +21 -3
  237. package/dist/tabs/tab/tab.d.ts +36 -4
  238. package/dist/tabs/tab/tab.js +46 -3
  239. package/dist/tag/group/tag-group.d.ts +107 -0
  240. package/dist/tag/group/tag-group.js +157 -0
  241. package/dist/tag/index.d.ts +1 -0
  242. package/dist/tag/index.js +1 -0
  243. package/dist/tag/root/tag-root.d.ts +60 -0
  244. package/dist/tag/root/tag-root.js +74 -18
  245. package/dist/tag/selection.d.ts +10 -0
  246. package/dist/tag/selection.js +12 -0
  247. package/dist/textarea/grow.d.ts +22 -0
  248. package/dist/textarea/grow.js +20 -0
  249. package/dist/textarea/root/textarea-root.d.ts +9 -0
  250. package/dist/textarea/root/textarea-root.js +9 -1
  251. package/dist/time-input/root/time-input-root.d.ts +44 -5
  252. package/dist/time-input/root/time-input-root.js +69 -39
  253. package/dist/time-picker/root/time-picker-root.d.ts +54 -8
  254. package/dist/time-picker/root/time-picker-root.js +121 -91
  255. package/dist/timeline/group/timeline-group.d.ts +46 -0
  256. package/dist/timeline/group/timeline-group.js +37 -0
  257. package/dist/timeline/index.d.ts +1 -0
  258. package/dist/timeline/index.js +1 -0
  259. package/dist/timeline/root/timeline-root.d.ts +10 -3
  260. package/dist/toast/hotkey.d.ts +22 -0
  261. package/dist/toast/hotkey.js +23 -0
  262. package/dist/toast/item/toast-item.d.ts +26 -18
  263. package/dist/toast/item/toast-item.js +55 -48
  264. package/dist/toast/root/toast-root.d.ts +42 -8
  265. package/dist/toast/root/toast-root.js +64 -4
  266. package/dist/toggle/group/toggle-group.d.ts +57 -15
  267. package/dist/toggle/group/toggle-group.js +69 -9
  268. package/dist/toggle/root/toggle-root.d.ts +12 -1
  269. package/dist/toggle/root/toggle-root.js +11 -3
  270. package/dist/toolbar/root/toolbar-root.d.ts +13 -0
  271. package/dist/toolbar/root/toolbar-root.js +15 -5
  272. package/dist/tooltip/focus-target.d.ts +6 -0
  273. package/dist/tooltip/focus-target.js +9 -0
  274. package/dist/tooltip/root/tooltip-root.d.ts +42 -17
  275. package/dist/tooltip/root/tooltip-root.js +50 -9
  276. package/dist/tour/naming.d.ts +30 -0
  277. package/dist/tour/naming.js +10 -0
  278. package/dist/tour/root/tour-root.d.ts +35 -0
  279. package/dist/tour/root/tour-root.js +56 -5
  280. package/dist/tour/stop/tour-stop.d.ts +53 -8
  281. package/dist/tour/stop/tour-stop.js +45 -15
  282. package/dist/tour/wait.d.ts +11 -0
  283. package/dist/tour/wait.js +19 -0
  284. package/dist/tree/item/tree-item.d.ts +54 -1
  285. package/dist/tree/item/tree-item.js +89 -20
  286. package/dist/tree/root/tree-root.d.ts +37 -0
  287. package/dist/tree/root/tree-root.js +51 -6
  288. package/dist/tree/selection.d.ts +24 -0
  289. package/dist/tree/selection.js +26 -0
  290. package/dist/trend/root/trend-root.d.ts +13 -0
  291. package/dist/trend/root/trend-root.js +14 -9
  292. package/dist/video/media-events.d.ts +49 -0
  293. package/dist/video/media-events.js +39 -0
  294. package/dist/video/root/video-root.d.ts +99 -13
  295. package/dist/video/root/video-root.js +84 -47
  296. package/dist/video-playlist/menu/video-playlist-menu.d.ts +3 -0
  297. package/dist/video-playlist/menu/video-playlist-menu.js +2 -1
  298. package/dist/video-playlist/order.d.ts +41 -0
  299. package/dist/video-playlist/order.js +34 -0
  300. package/dist/video-playlist/root/video-playlist-root.d.ts +70 -2
  301. package/dist/video-playlist/root/video-playlist-root.js +60 -16
  302. package/dist/virtual-list/controls.d.ts +4 -0
  303. package/dist/virtual-list/controls.js +30 -0
  304. package/dist/virtual-list/fill.d.ts +30 -0
  305. package/dist/virtual-list/fill.js +39 -0
  306. package/dist/virtual-list/keys.d.ts +15 -0
  307. package/dist/virtual-list/keys.js +24 -0
  308. package/dist/virtual-list/root/virtual-list-root.d.ts +155 -23
  309. package/dist/virtual-list/root/virtual-list-root.js +175 -34
  310. package/lint.json +1 -1
  311. package/package.json +5 -5
  312. package/types/jsx.d.ts +8871 -1286
  313. package/types/svelte.d.ts +3 -0
  314. package/types/vue.d.ts +1918 -269
@@ -1,5 +1,5 @@
1
1
  import { AriaForwardController, DisabledCascadeController, HelixFormElement } from '@fusion.dev/helix-core';
2
- import { type PropertyValues, type TemplateResult } from 'lit';
2
+ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
3
3
  import { HelixHeadlessOption } from '../../option/root/option-root.js';
4
4
  declare const HelixHeadlessListbox_base: (new (...args: any[]) => import("@fusion.dev/helix-core").CollectionElement) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
5
5
  /**
@@ -24,10 +24,18 @@ declare const HelixHeadlessListbox_base: (new (...args: any[]) => import("@fusio
24
24
  * letters move it to the next option whose words start with them. In a
25
25
  * single-choice list the highlight is the choice unless `manual` is set; then
26
26
  * Enter, Space or a click chooses. With `multiple`, Space toggles the
27
- * highlighted option, Shift with an arrow adds the option it moves to, and
27
+ * highlighted option, Shift with an arrow adds the option it moves to, Shift
28
+ * with Home or End adds every option from the highlight to that end, and
28
29
  * Control+A or Command+A chooses every option, or none where all are chosen.
29
30
  * In a filter field, Space, Home, End and letters edit the text.
30
31
  *
32
+ * An option with `href` is a link: Enter or a press follows it and selects
33
+ * nothing, and moving onto it with the arrows does not follow it.
34
+ *
35
+ * As a filter narrows the list, a screen reader hears how many options are
36
+ * left, such as "3 results", from `result-label` and `results-label`. A filter
37
+ * that leaves none says `empty-text`.
38
+ *
31
39
  * @since 0.1.0
32
40
  * @status stable
33
41
  * @category forms
@@ -35,10 +43,12 @@ declare const HelixHeadlessListbox_base: (new (...args: any[]) => import("@fusio
35
43
  * @documentation https://fusion.dev/helix/components/listbox
36
44
  *
37
45
  * @slot - The options, and any groups of them.
46
+ * @slot empty - What the list shows when it has no options to show, for content richer than `empty-text`.
38
47
  * @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
39
48
  * @slot filter-icon - The icon in the filter field. Defaults to a magnifying glass.
40
49
  * @slot hint - The hint, for content richer than plain text.
41
50
  * @slot label - The label, for content richer than plain text.
51
+ * @slot loading - What the list shows while its options load, for content richer than `loading-text`.
42
52
  *
43
53
  * @event {Event} change - Fired after the value changes.
44
54
  * @event {HelixBeforeChangeEvent} helix-before-change - Fired when the value is about to change, and cancelable.
@@ -52,12 +62,14 @@ declare const HelixHeadlessListbox_base: (new (...args: any[]) => import("@fusio
52
62
  * @csspart hint - Help under the list.
53
63
  * @csspart items - The list of options.
54
64
  * @csspart label - The label above the list.
55
- * @csspart live - A copy of the empty and loading text, in a region that screen readers announce when it changes. Visually hidden in the styled tier.
65
+ * @csspart live - A copy of the empty and loading text, and how many options a filter left, in a region that screen readers announce when it changes. Visually hidden in the styled tier.
56
66
  * @csspart loading - The text shown while the options load.
57
67
  * @csspart search - The region that holds the filter field.
58
68
  * @csspart search-field - The filter field.
59
69
  *
70
+ * @cssstate empty - The list has no options to show: none were given, or the filter hid every one.
60
71
  * @cssstate invalid - The control has an error to show, from the browser's validation or from your `feedback`.
72
+ * @cssstate loading - While `loading` is set.
61
73
  */
62
74
  export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
63
75
  protected readonly aria: AriaForwardController;
@@ -104,6 +116,16 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
104
116
  * own search boxes would be three copies of one field.
105
117
  */
106
118
  filterable: boolean;
119
+ /**
120
+ * How long typing in the filter field rests before the list is filtered, in
121
+ * milliseconds. `0` filters on every keystroke.
122
+ *
123
+ * For a list filtered on a server, where `helix-filter` starts a request: a
124
+ * reader typing a word sends one request for the word, not one for each
125
+ * letter. Enter and the arrow keys filter at once on what is typed, so they
126
+ * act on the list the reader expects.
127
+ */
128
+ filterDelay: number;
107
129
  /**
108
130
  * Placeholder text for the filter field.
109
131
  */
@@ -121,6 +143,20 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
121
143
  * Whether more than one option can be chosen.
122
144
  */
123
145
  multiple: boolean;
146
+ /**
147
+ * What a screen reader hears when a filter leaves one option. `{count}` is
148
+ * the count.
149
+ */
150
+ resultLabel: string;
151
+ /**
152
+ * What a screen reader hears when a filter leaves any other number of
153
+ * options. `{count}` is the count.
154
+ *
155
+ * **Two sentences, chosen by `Intl.PluralRules`**, which is Data Table's
156
+ * pair: a language with more forms than two picks the one for its `one` and
157
+ * writes the rest here.
158
+ */
159
+ resultsLabel: string;
124
160
  /**
125
161
  * Which option the keyboard is on, which is not what is chosen.
126
162
  */
@@ -189,6 +225,18 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
189
225
  * ArrowUp, and Combobox moves the highlight off the list onto its create row.
190
226
  */
191
227
  highlight(where: 'first' | 'last' | 'none' | 'selected'): void;
228
+ /**
229
+ * Says how many options a filter left, in the live region.
230
+ *
231
+ * **A reader typing into a filter cannot see the list narrow**, and React
232
+ * Aria and Web Awesome both say the count as it changes. Only "No matches"
233
+ * was said here, so a query that left forty options and one that left one
234
+ * sounded the same. Said when the filter changes and the count with it, so
235
+ * a keystroke that leaves the same options says nothing new. An empty filter
236
+ * says nothing, being the list as it was given; no matches is `empty-text`,
237
+ * which the region says in place of this.
238
+ */
239
+ private tell;
192
240
  /**
193
241
  * @internal Moves the highlight to the option whose words start with the
194
242
  * letters typed, and returns its value, or nothing where none matches.
@@ -376,6 +424,12 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
376
424
  * their answer moved when it did not is worse than telling them nothing.
377
425
  */
378
426
  private readonly handleFilter;
427
+ /** The filter waiting out `filterDelay`, if any. */
428
+ private readonly filtering;
429
+ /** Filters on what the field holds, and puts the field back where that was refused. */
430
+ private takeFilter;
431
+ /** Filters at once on a filter still waiting out `filterDelay`. */
432
+ private flushFilter;
379
433
  /** Requests a new filter, and returns whether the request went through. */
380
434
  requestFilter(next: string): boolean;
381
435
  /**
@@ -414,6 +468,23 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
414
468
  * cannot change.
415
469
  */
416
470
  protected renderFilterIcon(): TemplateResult;
471
+ /**
472
+ * Whether there is anything to show.
473
+ *
474
+ * Showing nothing is not the same as empty. A filter that hides every option
475
+ * is empty, and one with no filter and no options is empty too, but a list
476
+ * still waiting on its options is neither.
477
+ */
478
+ private get showsOptions();
479
+ /**
480
+ * The empty or loading line, with a slot for each so either can be richer
481
+ * than its text.
482
+ *
483
+ * **The text is the slot's fallback**, which is this library's rule for a
484
+ * content property, so `empty-text` still shows where nothing is slotted and
485
+ * the live region still says it.
486
+ */
487
+ protected renderStatus(hasContent: boolean): TemplateResult | typeof nothing;
417
488
  protected render(): TemplateResult;
418
489
  }
419
490
  declare global {
@@ -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, customElement, DisabledCascadeController, HelixFilterEvent, HelixFormElement, hostAria, MixinCollection, MixinControllerValue, MixinField, reportValues, requestChange, scrollItemIntoView, Typeahead, typesCharacter, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, countLabel, customElement, DelayController, DisabledCascadeController, HelixFilterEvent, HelixFormElement, hostAria, MixinCollection, MixinControllerValue, MixinField, rangeAdd, reportValues, requestChange, scrollItemIntoView, Typeahead, typesCharacter, } from '@fusion.dev/helix-core';
8
8
  import { magnifyingGlass } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -68,9 +68,12 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
68
68
  this.emptyText = 'No matches';
69
69
  this.filterState = undefined;
70
70
  this.filterable = false;
71
+ this.filterDelay = 0;
71
72
  this.filterLabel = 'Filter';
72
73
  this.manual = false;
73
74
  this.multiple = false;
75
+ this.resultLabel = '{count} result';
76
+ this.resultsLabel = '{count} results';
74
77
  this.activeValue = '';
75
78
  this.parked = false;
76
79
  this.typeahead = new Typeahead();
@@ -82,6 +85,9 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
82
85
  items: () => this.options,
83
86
  });
84
87
  this.handleSelection = (event) => {
88
+ if (event.detail.href !== undefined) {
89
+ return;
90
+ }
85
91
  event.stopPropagation();
86
92
  if (event.defaultPrevented) {
87
93
  return;
@@ -96,7 +102,14 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
96
102
  }
97
103
  const typing = this.forwarded || event.composedPath()[0] === this.partNamed('search-field');
98
104
  if (event.key === 'Enter' || (event.key === ' ' && !typing && !this.typeahead.typing())) {
99
- if (this.activeValue !== '') {
105
+ const link = shown.find((option) => option.value === this.activeValue && Boolean(option.href));
106
+ if (link !== undefined) {
107
+ event.preventDefault();
108
+ if (event.key === 'Enter') {
109
+ link.select(event);
110
+ }
111
+ }
112
+ else if (this.activeValue !== '') {
100
113
  event.preventDefault();
101
114
  this.choose(this.activeValue);
102
115
  }
@@ -155,6 +168,14 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
155
168
  const target = shown[next];
156
169
  if (target) {
157
170
  this.arrive(target.value);
171
+ const ranged = event.key === 'Home' || event.key === 'End';
172
+ if (this.multiple && !typing && event.shiftKey && ranged) {
173
+ const taken = rangeAdd(this.values, shown.map((option) => option.value), at, next);
174
+ if (taken) {
175
+ this.requestValue(taken.join(','));
176
+ }
177
+ return;
178
+ }
158
179
  if (this.multiple && !typing && event.shiftKey && !this.values.includes(target.value)) {
159
180
  this.choose(target.value);
160
181
  }
@@ -163,16 +184,27 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
163
184
  this.handleFilter = (event) => {
164
185
  event.stopPropagation();
165
186
  const control = event.target;
166
- this.requestFilter(control.value);
167
- if (control.value !== this.filter) {
168
- control.value = this.filter;
187
+ this.filtering.cancel();
188
+ if (this.filterDelay > 0) {
189
+ this.filtering.start(this.filterDelay, () => this.takeFilter(control));
190
+ return;
169
191
  }
192
+ this.takeFilter(control);
170
193
  };
194
+ this.filtering = new DelayController(this, { renders: false });
171
195
  this.handleFilterKeydown = (event) => {
172
- if (event.key === 'Escape' && this.filter !== '') {
196
+ if (event.key === 'Enter' || FIELD_MOVES.has(event.key)) {
197
+ this.flushFilter();
198
+ }
199
+ if (event.key === 'Escape' && (this.filter !== '' || this.filtering.pending)) {
173
200
  event.stopPropagation();
174
201
  event.preventDefault();
202
+ this.filtering.cancel();
175
203
  this.requestFilter('');
204
+ const control = this.partNamed('search-field');
205
+ if (control && control.value !== this.filter) {
206
+ control.value = this.filter;
207
+ }
176
208
  return;
177
209
  }
178
210
  if (!FIELD_MOVES.has(event.key)) {
@@ -218,6 +250,17 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
218
250
  this.place();
219
251
  }
220
252
  }
253
+ tell(changed) {
254
+ if (!changed.has('filter') || !this.hasUpdated) {
255
+ return;
256
+ }
257
+ const count = this.shown.length;
258
+ if (this.filter.trim() === '' || count === 0) {
259
+ this.announced = '';
260
+ return;
261
+ }
262
+ this.announced = countLabel(count, this.resultLabel, this.resultsLabel, this.lang);
263
+ }
221
264
  typeaheadTo(key) {
222
265
  const shown = this.shown.filter((option) => !option.disabled);
223
266
  const from = shown.findIndex((option) => option.value === this.currentValue);
@@ -294,7 +337,8 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
294
337
  arrive(value) {
295
338
  this.parked = false;
296
339
  this.activeValue = value;
297
- if (!this.multiple && !this.manual && !this.forwarded) {
340
+ const link = this.options.some((option) => option.value === value && Boolean(option.href));
341
+ if (!this.multiple && !this.manual && !this.forwarded && !link) {
298
342
  this.choose(value);
299
343
  }
300
344
  }
@@ -423,7 +467,10 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
423
467
  }
424
468
  if (this.childrenKnown) {
425
469
  this.place();
470
+ this.tell(changed);
426
471
  }
472
+ this.toggleState('empty', !this.showsOptions);
473
+ this.toggleState('loading', this.loading);
427
474
  }
428
475
  seedDeclared() {
429
476
  if (this.owned || this.defaultValue !== '' || this.hasAttribute('default-value')) {
@@ -453,6 +500,16 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
453
500
  this.sync();
454
501
  this.linkActive();
455
502
  }
503
+ takeFilter(control) {
504
+ this.filtering.cancel();
505
+ this.requestFilter(control.value);
506
+ if (control.value !== this.filter) {
507
+ control.value = this.filter;
508
+ }
509
+ }
510
+ flushFilter() {
511
+ this.filtering.flush();
512
+ }
456
513
  requestFilter(next) {
457
514
  if (next === this.filter) {
458
515
  return true;
@@ -480,12 +537,23 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
480
537
  </svg>
481
538
  </slot>`;
482
539
  }
483
- render() {
484
- const shown = this.counted && !this.loading
540
+ get showsOptions() {
541
+ return this.counted && !this.loading
485
542
  ? this.filter === ''
486
543
  ? this.options.length > 0
487
544
  : this.hasMatches
488
545
  : true;
546
+ }
547
+ renderStatus(hasContent) {
548
+ if (!this.loading && hasContent) {
549
+ return nothing;
550
+ }
551
+ return this.loading
552
+ ? html `<p part="loading"><slot name="loading">${this.loadingText}</slot></p>`
553
+ : html `<p part="empty"><slot name="empty">${this.emptyText}</slot></p>`;
554
+ }
555
+ render() {
556
+ const shown = this.showsOptions;
489
557
  return html `${this.renderGroupLabel()}
490
558
  ${this.filterable
491
559
  ? html `<div part="search">
@@ -542,6 +610,9 @@ __decorate([
542
610
  __decorate([
543
611
  property({ attribute: 'filterable', reflect: true, type: Boolean })
544
612
  ], HelixHeadlessListbox.prototype, "filterable", void 0);
613
+ __decorate([
614
+ property({ attribute: 'filter-delay', type: Number })
615
+ ], HelixHeadlessListbox.prototype, "filterDelay", void 0);
545
616
  __decorate([
546
617
  property({ attribute: 'filter-label' })
547
618
  ], HelixHeadlessListbox.prototype, "filterLabel", void 0);
@@ -551,6 +622,12 @@ __decorate([
551
622
  __decorate([
552
623
  property({ reflect: true, type: Boolean })
553
624
  ], HelixHeadlessListbox.prototype, "multiple", void 0);
625
+ __decorate([
626
+ property({ attribute: 'result-label' })
627
+ ], HelixHeadlessListbox.prototype, "resultLabel", void 0);
628
+ __decorate([
629
+ property({ attribute: 'results-label' })
630
+ ], HelixHeadlessListbox.prototype, "resultsLabel", void 0);
554
631
  __decorate([
555
632
  state()
556
633
  ], HelixHeadlessListbox.prototype, "activeValue", void 0);
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Marks a region busy for as long as something is loading into it, and
3
+ * counts, so two loaders in one region do not clear each other.
4
+ *
5
+ * Beside the family's `index.ts`, because which element is busy and how many
6
+ * claims it holds is bookkeeping about elements, not about a loader's
7
+ * template.
8
+ */
9
+ /**
10
+ * Adds a claim on the region, setting `aria-busy="true"` on the first.
11
+ *
12
+ * Only an `aria-busy` this file wrote is ever taken off again: a region the
13
+ * page marked busy itself keeps its own attribute.
14
+ */
15
+ export declare const claimBusy: (region: Element) => void;
16
+ /** Takes a claim back, and the attribute with the last one. */
17
+ export declare const releaseBusy: (region: Element) => void;
@@ -0,0 +1,24 @@
1
+ const CLAIMS = new WeakMap();
2
+ export const claimBusy = (region) => {
3
+ const held = CLAIMS.get(region) ?? 0;
4
+ if (held === 0 && region.getAttribute('aria-busy') === 'true') {
5
+ return;
6
+ }
7
+ CLAIMS.set(region, held + 1);
8
+ if (held === 0) {
9
+ region.setAttribute('aria-busy', 'true');
10
+ }
11
+ };
12
+ export const releaseBusy = (region) => {
13
+ const held = CLAIMS.get(region);
14
+ if (held === undefined) {
15
+ return;
16
+ }
17
+ if (held <= 1) {
18
+ CLAIMS.delete(region);
19
+ region.removeAttribute('aria-busy');
20
+ }
21
+ else {
22
+ CLAIMS.set(region, held - 1);
23
+ }
24
+ };
@@ -19,6 +19,15 @@ import { type PropertyValues, type TemplateResult } from 'lit';
19
19
  * a `role` attribute on the host would be missing from React server-rendered
20
20
  * markup.
21
21
  *
22
+ * **`for` names the region being loaded**, and the loader sets
23
+ * `aria-busy="true"` on it for as long as the loader is on the page, so a
24
+ * screen reader waits for the region rather than reading it half filled. Two
25
+ * loaders in one region hold it busy until the last one leaves.
26
+ *
27
+ * **`delay` keeps a quick load from flashing a loader.** The loader stays
28
+ * hidden, and silent, for that many milliseconds, and appears only if the work
29
+ * is still going.
30
+ *
22
31
  * @since 0.1.0
23
32
  * @status stable
24
33
  * @category feedback
@@ -33,11 +42,39 @@ import { type PropertyValues, type TemplateResult } from 'lit';
33
42
  * @csspart track - The full circle behind the indicator.
34
43
  */
35
44
  export declare class HelixHeadlessLoader extends HelixElement {
45
+ /**
46
+ * How long the loader waits before it shows, in milliseconds, so work that
47
+ * finishes quickly never flashes one.
48
+ *
49
+ * Absent shows it at once. Hidden in the served markup too, so a page that
50
+ * loads quickly never draws it.
51
+ */
52
+ delay: number;
53
+ /**
54
+ * The id of the region being loaded, which is marked `aria-busy` while the
55
+ * loader is on the page.
56
+ *
57
+ * Names an element in the same tree. In React it arrives as a property, the
58
+ * way `Tooltip.for` does.
59
+ */
60
+ for: string;
36
61
  /**
37
62
  * The loader's name, announced by screen readers while the work is in
38
63
  * progress.
39
64
  */
40
65
  label: string;
66
+ /** The wait `delay` asks for, and whether it has run out. */
67
+ private readonly due;
68
+ /** The region this loader marked busy, so it is the one released. */
69
+ private region;
70
+ /** Whether the loader is still waiting out its `delay`. */
71
+ private get waiting();
72
+ connectedCallback(): void;
73
+ disconnectedCallback(): void;
74
+ /** Marks the region `for` names busy, releasing one it named before. */
75
+ private mark;
76
+ private release;
77
+ protected updated(changed: PropertyValues<this>): void;
41
78
  protected willUpdate(changed: PropertyValues): void;
42
79
  protected render(): TemplateResult;
43
80
  }
@@ -4,27 +4,76 @@ 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, hostAria } from '@fusion.dev/helix-core';
7
+ import { customElement, DelayController, elementById, HelixElement, hostAria, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ import { claimBusy, releaseBusy } from '../busy.js';
10
11
  let HelixHeadlessLoader = class HelixHeadlessLoader extends HelixElement {
11
12
  constructor() {
12
13
  super(...arguments);
14
+ this.delay = 0;
15
+ this.for = '';
13
16
  this.label = 'Loading';
17
+ this.due = new DelayController(this);
18
+ this.region = null;
19
+ }
20
+ get waiting() {
21
+ return this.delay > 0 && !this.due.elapsed;
22
+ }
23
+ connectedCallback() {
24
+ super.connectedCallback();
25
+ if (this.delay > 0 && !this.due.elapsed) {
26
+ this.due.start(this.delay);
27
+ }
28
+ requestAnimationFrame(() => this.mark());
29
+ }
30
+ disconnectedCallback() {
31
+ super.disconnectedCallback();
32
+ this.release();
33
+ }
34
+ mark() {
35
+ const region = this.isConnected && this.for !== '' ? elementById(this, this.for) : null;
36
+ if (region === this.region) {
37
+ return;
38
+ }
39
+ this.release();
40
+ if (region) {
41
+ claimBusy(region);
42
+ this.region = region;
43
+ }
44
+ }
45
+ release() {
46
+ if (this.region) {
47
+ releaseBusy(this.region);
48
+ this.region = null;
49
+ }
50
+ }
51
+ updated(changed) {
52
+ super.updated(changed);
53
+ if (changed.has('for') && changed.get('for') !== undefined) {
54
+ this.mark();
55
+ }
14
56
  }
15
57
  willUpdate(changed) {
16
58
  super.willUpdate(changed);
17
59
  hostAria(this.internals, { label: this.label, role: 'progressbar' });
18
60
  this.internals.ariaBusy = 'true';
61
+ this.internals.ariaHidden = this.waiting ? 'true' : null;
19
62
  }
20
63
  render() {
21
- return html `<svg part="svg" viewBox="0 0 24 24" aria-hidden="true">
64
+ return html `<svg part="svg" viewBox="0 0 24 24" aria-hidden="true" ?hidden=${this.waiting}>
22
65
  <circle part="track" cx="12" cy="12" r="10" fill="none" />
23
66
  <circle part="indicator" cx="12" cy="12" r="10" fill="none" />
24
67
  </svg>
25
- <span part="mark" aria-hidden="true"><slot></slot></span>`;
68
+ <span part="mark" aria-hidden="true" ?hidden=${this.waiting}><slot></slot></span>`;
26
69
  }
27
70
  };
71
+ __decorate([
72
+ property({ type: Number })
73
+ ], HelixHeadlessLoader.prototype, "delay", void 0);
74
+ __decorate([
75
+ property()
76
+ ], HelixHeadlessLoader.prototype, "for", void 0);
28
77
  __decorate([
29
78
  property()
30
79
  ], HelixHeadlessLoader.prototype, "label", void 0);
@@ -45,7 +45,8 @@ declare const HelixHeadlessMap_base: (new (...args: any[]) => import("@fusion.de
45
45
  * for each layer, which sets the layer's `hidden` attribute. Layers with the
46
46
  * same `group`, such as a route and its dotted legs, share one tile. A tile
47
47
  * sends `helix-before-toggle` from the layer first, so you can store the
48
- * choice or refuse it.
48
+ * choice or refuse it, and `helix-toggle` from it once `hidden` holds the
49
+ * choice.
49
50
  *
50
51
  * Imagery, a `helix-map-raster` with `ground`, is a map type and not a tile.
51
52
  * The menu opens with a card for each type, Standard, Hybrid, and Satellite,
@@ -80,6 +81,7 @@ declare const HelixHeadlessMap_base: (new (...args: any[]) => import("@fusion.de
80
81
  * @event {HelixMapRotateEvent} helix-map-rotate - A rotate or Face north button, or Shift with Left or Right, was pressed. Turn your map in response.
81
82
  * @event {HelixMapTiltEvent} helix-map-tilt - The 3D button, or Shift with Up or Down, was pressed. Tilt your map in response.
82
83
  * @event {HelixMapZoomEvent} helix-map-zoom - A zoom button or key was pressed, with a direction. Zoom your map in response.
84
+ * @event {HelixToggleEvent} helix-toggle - A layer's tile in the layers menu showed or hid it. Sent from the layer once its `hidden` attribute holds the choice, with `checked` true when it is shown.
83
85
  *
84
86
  * @csspart attribution - The strip under the map that holds the credit.
85
87
  * @csspart compass - The compass and the pan and rotate buttons around it.
@@ -291,7 +293,9 @@ export declare class HelixHeadlessMap extends HelixHeadlessMap_base {
291
293
  * **Asked first, from the layer.** The tile wrote `hidden` onto the
292
294
  * consumer's element and said nothing, so a page could neither keep the
293
295
  * choice nor keep its own state in step. The request comes from the first
294
- * layer of the tile, which is the element the page wrote.
296
+ * layer of the tile, which is the element the page wrote. Once `hidden`
297
+ * holds the answer, the same layer sends `helix-toggle`, the request's verb
298
+ * without `before`, since the platform has no word for a layer shown.
295
299
  */
296
300
  private showLayers;
297
301
  /** Asks for a map type, and sends `change` once it holds. */
@@ -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, fillTemplate, formatNumbers, HelixActivateEvent, HelixBeforeChangeEvent, HelixBeforeToggleEvent, HelixElement, HelixMapClusterEvent, HelixMapPanEvent, HelixMapPartChangeEvent, HelixMapReadyEvent, HelixMapRotateEvent, HelixMapTiltEvent, HelixMapZoomEvent, hostAria, KeyboardNavigationController, MixinViewport, requestChange, } from '@fusion.dev/helix-core';
7
+ import { customElement, fillTemplate, formatNumbers, HelixActivateEvent, HelixBeforeChangeEvent, HelixBeforeToggleEvent, HelixElement, HelixMapClusterEvent, HelixMapPanEvent, HelixMapPartChangeEvent, HelixMapReadyEvent, HelixMapRotateEvent, HelixMapTiltEvent, HelixMapZoomEvent, HelixToggleEvent, hostAria, KeyboardNavigationController, MixinViewport, requestChange, } from '@fusion.dev/helix-core';
8
8
  import { buildings, cloudRain, dotsNine, leaf, mountains, path, polygon, stack, target, } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -210,7 +210,7 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
210
210
  if (!first) {
211
211
  return;
212
212
  }
213
- requestChange({
213
+ const applied = requestChange({
214
214
  apply: () => {
215
215
  for (const layer of layers) {
216
216
  layer.hidden = !shown;
@@ -221,6 +221,9 @@ let HelixHeadlessMap = class HelixHeadlessMap extends MixinViewport(HelixElement
221
221
  host: first,
222
222
  next: shown,
223
223
  });
224
+ if (applied) {
225
+ first.dispatchEvent(new HelixToggleEvent({ checked: shown }));
226
+ }
224
227
  }
225
228
  chooseMapType(type) {
226
229
  const applied = requestChange({
@@ -20,6 +20,13 @@ declare const HelixHeadlessMegamenu_base: (new (...args: any[]) => import("@fusi
20
20
  * which. Hover is the default because in a navigation bar people expect to move
21
21
  * along the row and see each section.
22
22
  *
23
+ * When one panel opens in place of another, each says which way the reader
24
+ * moved, as Radix's `data-motion` does: the one opening is
25
+ * `:state(from-start)` or `:state(from-end)`, by where the one closing sits in
26
+ * the bar, and the one closing is `:state(to-start)` or `:state(to-end)`. A
27
+ * stylesheet slides them on that. Put megamenus in a `Navigation` with
28
+ * `arrows` and the arrow keys move between their triggers.
29
+ *
23
30
  * @since 0.1.0
24
31
  * @status stable
25
32
  * @category navigation
@@ -38,8 +45,12 @@ declare const HelixHeadlessMegamenu_base: (new (...args: any[]) => import("@fusi
38
45
  *
39
46
  * @cssproperty --megamenu-top - Where the panel starts, measured from the bar above it.
40
47
  *
48
+ * @cssstate from-end - The panel opened in place of one later in the bar, so it can enter from that side.
49
+ * @cssstate from-start - The panel opened in place of one earlier in the bar.
41
50
  * @cssstate narrow - The page is narrower than `band-below`, so the panel is shown as a band whatever its variant.
42
51
  * @cssstate open - The panel is open, and the trigger is shown as current.
52
+ * @cssstate to-end - The panel closed because one later in the bar opened, so it can leave toward it.
53
+ * @cssstate to-start - The panel closed because one earlier in the bar opened.
43
54
  */
44
55
  export declare class HelixHeadlessMegamenu extends HelixHeadlessMegamenu_base {
45
56
  /**
@@ -119,6 +130,11 @@ export declare class HelixHeadlessMegamenu extends HelixHeadlessMegamenu_base {
119
130
  private get slotted();
120
131
  /** Whatever the consumer slotted, or the button rendered in its place. */
121
132
  private get trigger();
133
+ /**
134
+ * @internal The control a `Navigation`'s arrow keys move to: the trigger
135
+ * the consumer slotted, or the button drawn in its place.
136
+ */
137
+ get navigationControl(): HTMLElement;
122
138
  /** Shuts it and puts the reader back where they were. */
123
139
  private close;
124
140
  /**
@@ -241,6 +257,11 @@ export declare class HelixHeadlessMegamenu extends HelixHeadlessMegamenu_base {
241
257
  * overruled.
242
258
  */
243
259
  protected willUpdate(changed: PropertyValues): void;
260
+ /**
261
+ * Says which way the reader moved when one panel took over from another.
262
+ * Nothing clears all four, for a panel opened on its own.
263
+ */
264
+ private motion;
244
265
  protected updated(changed: PropertyValues): void;
245
266
  /**
246
267
  * The control that opens it, behind a seam the styled tier can move.
@@ -117,6 +117,9 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
117
117
  get trigger() {
118
118
  return anchorElement(this.renderRoot?.querySelector('slot[name="trigger"]'), this.partNamed('trigger') ?? this);
119
119
  }
120
+ get navigationControl() {
121
+ return this.trigger;
122
+ }
120
123
  close() {
121
124
  if (!this.requestOpen(false)) {
122
125
  return;
@@ -184,8 +187,13 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
184
187
  return;
185
188
  }
186
189
  if (this.open) {
187
- if (showing && showing !== this) {
188
- showing.requestOpen(false);
190
+ const previous = showing && showing !== this ? showing : undefined;
191
+ const forward = previous !== undefined &&
192
+ (previous.compareDocumentPosition(this) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0;
193
+ this.motion(previous ? (forward ? 'from-end' : 'from-start') : undefined);
194
+ if (previous) {
195
+ previous.motion(forward ? 'to-end' : 'to-start');
196
+ previous.requestOpen(false);
189
197
  }
190
198
  showing = this;
191
199
  }
@@ -193,6 +201,12 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
193
201
  showing = undefined;
194
202
  }
195
203
  }
204
+ motion(to) {
205
+ this.toggleState('from-end', to === 'from-end');
206
+ this.toggleState('from-start', to === 'from-start');
207
+ this.toggleState('to-end', to === 'to-end');
208
+ this.toggleState('to-start', to === 'to-start');
209
+ }
196
210
  updated(changed) {
197
211
  super.updated?.(changed);
198
212
  if (changed.has('bandBelow')) {