@fusion.dev/helix-headless 0.145.0 → 0.147.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 (343) hide show
  1. package/custom-elements.json +12286 -4281
  2. package/dist/accordion/item/accordion-item.d.ts +51 -18
  3. package/dist/accordion/item/accordion-item.js +45 -13
  4. package/dist/accordion/root/accordion-root.d.ts +16 -7
  5. package/dist/accordion/root/accordion-root.js +3 -3
  6. package/dist/announcement/root/announcement-root.d.ts +16 -6
  7. package/dist/announcement/root/announcement-root.js +37 -7
  8. package/dist/app-header/root/app-header-root.d.ts +7 -2
  9. package/dist/app-header/root/app-header-root.js +9 -1
  10. package/dist/app-header/sectioning.d.ts +3 -1
  11. package/dist/app-header/sectioning.js +3 -2
  12. package/dist/area-chart/root/area-chart-root.d.ts +18 -1
  13. package/dist/area-chart/root/area-chart-root.js +11 -3
  14. package/dist/avatar/group/avatar-group.d.ts +20 -14
  15. package/dist/avatar/group/avatar-group.js +17 -19
  16. package/dist/avatar/root/avatar-root.d.ts +31 -1
  17. package/dist/avatar/root/avatar-root.js +11 -1
  18. package/dist/badge/root/badge-root.d.ts +60 -7
  19. package/dist/badge/root/badge-root.js +89 -6
  20. package/dist/bar-chart/root/bar-chart-root.d.ts +18 -1
  21. package/dist/bar-chart/root/bar-chart-root.js +48 -20
  22. package/dist/bar-chart/stack.d.ts +25 -0
  23. package/dist/bar-chart/stack.js +27 -0
  24. package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +14 -0
  25. package/dist/breadcrumbs/breadcrumb/breadcrumb.js +12 -2
  26. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +25 -0
  27. package/dist/breadcrumbs/root/breadcrumbs-root.js +51 -4
  28. package/dist/button/root/button-root.d.ts +50 -38
  29. package/dist/button/root/button-root.js +42 -53
  30. package/dist/button/submitter.d.ts +27 -0
  31. package/dist/button/submitter.js +25 -0
  32. package/dist/button-group/root/button-group-root.d.ts +2 -1
  33. package/dist/button-group/root/button-group-root.js +5 -1
  34. package/dist/canvas/node/canvas-node.d.ts +4 -3
  35. package/dist/canvas/node/canvas-node.js +3 -2
  36. package/dist/canvas/root/canvas-root.js +2 -2
  37. package/dist/card/root/card-root.d.ts +36 -4
  38. package/dist/card/root/card-root.js +29 -10
  39. package/dist/carousel/root/carousel-root.d.ts +43 -4
  40. package/dist/carousel/root/carousel-root.js +40 -12
  41. package/dist/carousel/stops.d.ts +20 -0
  42. package/dist/carousel/stops.js +30 -0
  43. package/dist/chat/message/chat-message.js +5 -4
  44. package/dist/chat/naming.d.ts +5 -1
  45. package/dist/chat/naming.js +4 -2
  46. package/dist/chat/root/chat-root.d.ts +40 -4
  47. package/dist/chat/root/chat-root.js +32 -6
  48. package/dist/checkbox/root/checkbox-root.d.ts +20 -0
  49. package/dist/checkbox/root/checkbox-root.js +18 -7
  50. package/dist/checkbox-group/root/checkbox-group-root.d.ts +8 -2
  51. package/dist/checkbox-group/root/checkbox-group-root.js +14 -11
  52. package/dist/checkbox-group/select-all.d.ts +21 -0
  53. package/dist/checkbox-group/select-all.js +7 -0
  54. package/dist/code-block/highlight.d.ts +15 -0
  55. package/dist/code-block/highlight.js +4 -0
  56. package/dist/code-block/root/code-block-root.d.ts +79 -10
  57. package/dist/code-block/root/code-block-root.js +74 -5
  58. package/dist/color-input/root/color-input-root.d.ts +14 -0
  59. package/dist/color-input/root/color-input-root.js +17 -7
  60. package/dist/color-picker/channels.js +1 -2
  61. package/dist/color-picker/root/color-picker-root.d.ts +53 -16
  62. package/dist/color-picker/root/color-picker-root.js +155 -46
  63. package/dist/color-picker/wheel.d.ts +17 -0
  64. package/dist/color-picker/wheel.js +6 -0
  65. package/dist/combobox/root/combobox-root.d.ts +56 -0
  66. package/dist/combobox/root/combobox-root.js +92 -15
  67. package/dist/command/root/command-root.d.ts +19 -2
  68. package/dist/command/root/command-root.js +24 -23
  69. package/dist/copy-button/root/copy-button-root.d.ts +21 -1
  70. package/dist/copy-button/root/copy-button-root.js +16 -4
  71. package/dist/data-table/index.d.ts +1 -1
  72. package/dist/data-table/index.js +1 -1
  73. package/dist/data-table/keys.d.ts +6 -0
  74. package/dist/data-table/keys.js +14 -0
  75. package/dist/data-table/root/data-table-root.d.ts +27 -18
  76. package/dist/data-table/root/data-table-root.js +31 -57
  77. package/dist/data-table/tree.d.ts +16 -1
  78. package/dist/data-table/tree.js +2 -3
  79. package/dist/date-input/root/date-input-root.d.ts +11 -2
  80. package/dist/date-input/root/date-input-root.js +26 -12
  81. package/dist/date-picker/root/date-picker-root.d.ts +14 -9
  82. package/dist/date-picker/root/date-picker-root.js +33 -22
  83. package/dist/description-list/item/description-list-item.d.ts +18 -4
  84. package/dist/description-list/item/description-list-item.js +8 -4
  85. package/dist/dialog/description.js +15 -1
  86. package/dist/dialog/root/dialog-root.d.ts +8 -2
  87. package/dist/dialog/root/dialog-root.js +16 -1
  88. package/dist/divider/root/divider-root.d.ts +3 -0
  89. package/dist/divider/root/divider-root.js +2 -1
  90. package/dist/donut-chart/root/donut-chart-root.d.ts +31 -0
  91. package/dist/donut-chart/root/donut-chart-root.js +55 -1
  92. package/dist/donut-chart/slice-label.d.ts +35 -0
  93. package/dist/donut-chart/slice-label.js +11 -0
  94. package/dist/drawer/reveal.d.ts +8 -0
  95. package/dist/drawer/reveal.js +1 -0
  96. package/dist/drawer/root/drawer-root.d.ts +63 -2
  97. package/dist/drawer/root/drawer-root.js +75 -4
  98. package/dist/drilldown/item/drilldown-item.d.ts +21 -1
  99. package/dist/drilldown/item/drilldown-item.js +40 -5
  100. package/dist/drilldown/root/drilldown-root.d.ts +21 -3
  101. package/dist/drilldown/root/drilldown-root.js +22 -3
  102. package/dist/element-events.generated.js +35 -6
  103. package/dist/empty/root/empty-root.d.ts +34 -2
  104. package/dist/empty/root/empty-root.js +26 -4
  105. package/dist/file-input/root/file-input-root.d.ts +99 -8
  106. package/dist/file-input/root/file-input-root.js +120 -22
  107. package/dist/file-input/screen.d.ts +2 -1
  108. package/dist/file-input/status.d.ts +24 -0
  109. package/dist/file-input/status.js +10 -0
  110. package/dist/filter-input/chip/filter-chip.d.ts +23 -0
  111. package/dist/filter-input/chip/filter-chip.js +11 -2
  112. package/dist/filter-input/menu/filter-menu.d.ts +2 -0
  113. package/dist/filter-input/menu/filter-menu.js +12 -4
  114. package/dist/filter-input/root/filter-input-root.d.ts +38 -6
  115. package/dist/filter-input/root/filter-input-root.js +18 -28
  116. package/dist/filter-input/suggest.d.ts +28 -3
  117. package/dist/filter-input/suggest.js +18 -8
  118. package/dist/format-date/options.d.ts +3 -4
  119. package/dist/format-date/options.js +2 -2
  120. package/dist/format-date/root/format-date-root.d.ts +27 -17
  121. package/dist/format-date/root/format-date-root.js +27 -48
  122. package/dist/heatmap/root/buckets.d.ts +21 -0
  123. package/dist/heatmap/root/buckets.js +34 -0
  124. package/dist/heatmap/root/heatmap-root.d.ts +83 -11
  125. package/dist/heatmap/root/heatmap-root.js +104 -12
  126. package/dist/icon/index.d.ts +1 -1
  127. package/dist/icon/index.js +1 -1
  128. package/dist/icon/registry.d.ts +26 -1
  129. package/dist/icon/registry.js +12 -1
  130. package/dist/icon/root/icon-root.d.ts +25 -1
  131. package/dist/icon/root/icon-root.js +44 -12
  132. package/dist/icon/root/index.d.ts +1 -1
  133. package/dist/icon/root/index.js +1 -1
  134. package/dist/icon/settle.d.ts +7 -0
  135. package/dist/icon/settle.js +10 -0
  136. package/dist/icon-button/root/icon-button-root.d.ts +2 -0
  137. package/dist/image/root/image-root.d.ts +14 -1
  138. package/dist/image/root/image-root.js +7 -2
  139. package/dist/input/root/input-root.d.ts +34 -3
  140. package/dist/input/root/input-root.js +17 -4
  141. package/dist/kbd/keys.d.ts +29 -0
  142. package/dist/kbd/keys.js +52 -0
  143. package/dist/kbd/root/kbd-root.d.ts +52 -1
  144. package/dist/kbd/root/kbd-root.js +40 -47
  145. package/dist/legend/hidden-series.d.ts +10 -2
  146. package/dist/legend/hidden-series.js +5 -2
  147. package/dist/legend/root/legend-root.d.ts +77 -12
  148. package/dist/legend/root/legend-root.js +71 -17
  149. package/dist/lightbox/root/lightbox-root.d.ts +98 -10
  150. package/dist/lightbox/root/lightbox-root.js +153 -18
  151. package/dist/lightbox/zoom-controller.d.ts +59 -0
  152. package/dist/lightbox/zoom-controller.js +128 -0
  153. package/dist/lightbox/zoom.d.ts +24 -0
  154. package/dist/lightbox/zoom.js +18 -0
  155. package/dist/line-chart/root/line-chart-root.d.ts +38 -1
  156. package/dist/line-chart/root/line-chart-root.js +31 -3
  157. package/dist/list/item/list-item.d.ts +2 -0
  158. package/dist/list/item/list-item.js +11 -2
  159. package/dist/list/root/list-root.d.ts +70 -13
  160. package/dist/list/root/list-root.js +91 -13
  161. package/dist/list/selection.d.ts +54 -7
  162. package/dist/list/selection.js +32 -7
  163. package/dist/listbox/root/listbox-root.d.ts +44 -4
  164. package/dist/listbox/root/listbox-root.js +72 -34
  165. package/dist/loader/busy.d.ts +10 -0
  166. package/dist/loader/busy.js +11 -0
  167. package/dist/loader/root/loader-root.d.ts +9 -2
  168. package/dist/loader/root/loader-root.js +23 -3
  169. package/dist/megamenu/hand-over.d.ts +75 -0
  170. package/dist/megamenu/hand-over.js +67 -0
  171. package/dist/megamenu/root/megamenu-root.d.ts +80 -15
  172. package/dist/megamenu/root/megamenu-root.js +76 -19
  173. package/dist/menu/item/menu-item.d.ts +51 -2
  174. package/dist/menu/item/menu-item.js +50 -26
  175. package/dist/menu/root/menu-root.d.ts +17 -0
  176. package/dist/menu/root/menu-root.js +2 -2
  177. package/dist/meter/root/meter-root.d.ts +62 -1
  178. package/dist/meter/root/meter-root.js +38 -16
  179. package/dist/navigation/root/navigation-root.d.ts +2 -1
  180. package/dist/navigation/root/navigation-root.js +2 -2
  181. package/dist/notifications/root/notifications-root.d.ts +20 -4
  182. package/dist/notifications/root/notifications-root.js +30 -8
  183. package/dist/number-input/grain.d.ts +28 -0
  184. package/dist/number-input/grain.js +14 -0
  185. package/dist/number-input/root/number-input-root.d.ts +34 -9
  186. package/dist/number-input/root/number-input-root.js +31 -25
  187. package/dist/object-inspector/root/object-inspector-root.d.ts +88 -33
  188. package/dist/object-inspector/root/object-inspector-root.js +134 -92
  189. package/dist/object-inspector/rows.d.ts +18 -0
  190. package/dist/object-inspector/rows.js +33 -0
  191. package/dist/option/index.d.ts +1 -0
  192. package/dist/option/index.js +1 -0
  193. package/dist/option/root/option-root.d.ts +5 -3
  194. package/dist/option/separator/option-separator.d.ts +30 -0
  195. package/dist/option/separator/option-separator.js +21 -0
  196. package/dist/outline/root/outline-root.d.ts +30 -0
  197. package/dist/outline/root/outline-root.js +17 -13
  198. package/dist/pagination/size/pagination-size.d.ts +6 -0
  199. package/dist/pagination/size/pagination-size.js +5 -3
  200. package/dist/pin-input/code.d.ts +37 -0
  201. package/dist/pin-input/code.js +25 -0
  202. package/dist/pin-input/root/pin-input-root.d.ts +116 -115
  203. package/dist/pin-input/root/pin-input-root.js +163 -155
  204. package/dist/popover/hide-outside.d.ts +14 -0
  205. package/dist/popover/hide-outside.js +34 -0
  206. package/dist/popover/root/popover-root.d.ts +64 -8
  207. package/dist/popover/root/popover-root.js +67 -4
  208. package/dist/progress/root/progress-root.d.ts +47 -0
  209. package/dist/progress/root/progress-root.js +34 -16
  210. package/dist/qr-code/export.d.ts +45 -1
  211. package/dist/qr-code/export.js +28 -0
  212. package/dist/qr-code/name.d.ts +11 -0
  213. package/dist/qr-code/name.js +7 -0
  214. package/dist/qr-code/root/qr-code-root.d.ts +36 -11
  215. package/dist/qr-code/root/qr-code-root.js +58 -11
  216. package/dist/quote/marks.d.ts +8 -0
  217. package/dist/quote/marks.js +5 -0
  218. package/dist/quote/root/quote-root.d.ts +14 -2
  219. package/dist/quote/root/quote-root.js +23 -1
  220. package/dist/radio/group/radio-group.d.ts +15 -0
  221. package/dist/radio/root/radio-root.d.ts +6 -2
  222. package/dist/radio/root/radio-root.js +7 -2
  223. package/dist/rating/root/rating-root.d.ts +30 -12
  224. package/dist/rating/root/rating-root.js +27 -27
  225. package/dist/scatter-chart/fit.d.ts +15 -0
  226. package/dist/scatter-chart/fit.js +35 -0
  227. package/dist/scatter-chart/root/scatter-chart-root.d.ts +51 -1
  228. package/dist/scatter-chart/root/scatter-chart-root.js +64 -24
  229. package/dist/scroll-area/root/scroll-area-root.d.ts +22 -51
  230. package/dist/scroll-area/root/scroll-area-root.js +57 -173
  231. package/dist/scroll-area/scrollbar-controller.d.ts +111 -0
  232. package/dist/scroll-area/scrollbar-controller.js +172 -0
  233. package/dist/scroll-area/scrollbar.d.ts +27 -8
  234. package/dist/scroll-area/scrollbar.js +10 -1
  235. package/dist/select/align.d.ts +47 -0
  236. package/dist/select/align.js +7 -0
  237. package/dist/select/root/select-root.d.ts +71 -0
  238. package/dist/select/root/select-root.js +78 -6
  239. package/dist/skeleton/root/skeleton-root.d.ts +3 -0
  240. package/dist/skeleton/root/skeleton-root.js +4 -2
  241. package/dist/skip-link/root/skip-link-root.js +2 -2
  242. package/dist/slider/root/slider-root.d.ts +59 -5
  243. package/dist/slider/root/slider-root.js +45 -3
  244. package/dist/sparkline/readings.d.ts +36 -0
  245. package/dist/sparkline/readings.js +36 -0
  246. package/dist/sparkline/root/sparkline-root.d.ts +121 -7
  247. package/dist/sparkline/root/sparkline-root.js +160 -26
  248. package/dist/speed-dial/item/speed-dial-item.d.ts +1 -1
  249. package/dist/speed-dial/item/speed-dial-item.js +2 -2
  250. package/dist/speed-dial/root/speed-dial-root.d.ts +6 -0
  251. package/dist/speed-dial/root/speed-dial-root.js +11 -3
  252. package/dist/splitter/root/splitter-root.d.ts +10 -12
  253. package/dist/splitter/root/splitter-root.js +211 -204
  254. package/dist/stat/root/stat-root.d.ts +14 -5
  255. package/dist/stat/root/stat-root.js +21 -5
  256. package/dist/steps/reach.d.ts +5 -0
  257. package/dist/steps/reach.js +3 -0
  258. package/dist/steps/root/steps-root.d.ts +56 -3
  259. package/dist/steps/root/steps-root.js +50 -6
  260. package/dist/steps/step/step.d.ts +8 -0
  261. package/dist/steps/step/step.js +8 -3
  262. package/dist/switch/root/switch-root.d.ts +10 -0
  263. package/dist/table/column/table-column.d.ts +6 -10
  264. package/dist/table/column/table-column.js +8 -20
  265. package/dist/table/root/table-root.d.ts +31 -10
  266. package/dist/table/root/table-root.js +14 -18
  267. package/dist/table/row/table-row.d.ts +24 -0
  268. package/dist/table/row/table-row.js +37 -1
  269. package/dist/tabs/panel/tab-panel.d.ts +16 -3
  270. package/dist/tabs/panel/tab-panel.js +34 -5
  271. package/dist/tabs/root/tabs-root.d.ts +17 -3
  272. package/dist/tabs/root/tabs-root.js +1 -1
  273. package/dist/tabs/tab/tab.d.ts +5 -0
  274. package/dist/tabs/tab/tab.js +5 -2
  275. package/dist/tag/group/tag-group.d.ts +44 -5
  276. package/dist/tag/group/tag-group.js +60 -9
  277. package/dist/tag/root/tag-root.js +9 -2
  278. package/dist/textarea/root/textarea-root.d.ts +41 -2
  279. package/dist/textarea/root/textarea-root.js +39 -1
  280. package/dist/time-input/root/time-input-root.d.ts +10 -2
  281. package/dist/time-input/root/time-input-root.js +24 -13
  282. package/dist/time-picker/root/time-picker-root.d.ts +28 -17
  283. package/dist/time-picker/root/time-picker-root.js +18 -29
  284. package/dist/time-picker/wheel-name.d.ts +9 -0
  285. package/dist/time-picker/wheel-name.js +15 -0
  286. package/dist/timeline/group/timeline-group.js +2 -2
  287. package/dist/toast/item/toast-item.d.ts +16 -3
  288. package/dist/toast/item/toast-item.js +22 -6
  289. package/dist/toast/root/toast-root.d.ts +34 -4
  290. package/dist/toast/root/toast-root.js +74 -13
  291. package/dist/toast/words.d.ts +12 -0
  292. package/dist/toast/words.js +25 -0
  293. package/dist/toggle/group/toggle-group.d.ts +52 -7
  294. package/dist/toggle/group/toggle-group.js +58 -44
  295. package/dist/toggle/root/toggle-root.js +2 -4
  296. package/dist/toolbar/root/toolbar-root.d.ts +21 -5
  297. package/dist/toolbar/root/toolbar-root.js +52 -8
  298. package/dist/tooltip/root/tooltip-root.d.ts +20 -3
  299. package/dist/tooltip/root/tooltip-root.js +18 -1
  300. package/dist/tour/back.d.ts +10 -0
  301. package/dist/tour/back.js +8 -0
  302. package/dist/tour/root/tour-root.d.ts +45 -2
  303. package/dist/tour/root/tour-root.js +53 -8
  304. package/dist/tour/stop/tour-stop.d.ts +3 -0
  305. package/dist/tour/stop/tour-stop.js +3 -3
  306. package/dist/tree/item/tree-item.d.ts +7 -3
  307. package/dist/tree/item/tree-item.js +3 -0
  308. package/dist/tree/root/tree-root.d.ts +24 -3
  309. package/dist/tree/root/tree-root.js +32 -13
  310. package/dist/tree/selection.js +2 -15
  311. package/dist/trend/figure.d.ts +16 -0
  312. package/dist/trend/figure.js +8 -0
  313. package/dist/trend/root/trend-root.d.ts +83 -19
  314. package/dist/trend/root/trend-root.js +59 -8
  315. package/dist/video/media-events.d.ts +13 -18
  316. package/dist/video/media-events.js +1 -5
  317. package/dist/video/root/extra-controls.d.ts +12 -0
  318. package/dist/video/root/extra-controls.js +6 -2
  319. package/dist/video/root/video-root.d.ts +23 -6
  320. package/dist/video/root/video-root.js +19 -10
  321. package/dist/video-playlist/menu/video-playlist-menu.d.ts +2 -0
  322. package/dist/video-playlist/menu/video-playlist-menu.js +2 -1
  323. package/dist/video-playlist/root/video-playlist-root.d.ts +17 -1
  324. package/dist/video-playlist/root/video-playlist-root.js +3 -0
  325. package/dist/virtual-list/fill.d.ts +11 -8
  326. package/dist/virtual-list/fill.js +10 -17
  327. package/dist/virtual-list/keys.d.ts +16 -7
  328. package/dist/virtual-list/keys.js +17 -6
  329. package/dist/virtual-list/plan.d.ts +65 -0
  330. package/dist/virtual-list/plan.js +27 -0
  331. package/dist/virtual-list/root/virtual-list-root.d.ts +136 -13
  332. package/dist/virtual-list/root/virtual-list-root.js +218 -51
  333. package/lint.json +1 -1
  334. package/package.json +8 -8
  335. package/types/jsx.d.ts +7441 -1458
  336. package/types/svelte.d.ts +1 -0
  337. package/types/vue.d.ts +1501 -326
  338. package/dist/chat/relative-clock.d.ts +0 -39
  339. package/dist/chat/relative-clock.js +0 -31
  340. package/dist/data-table/root/order.d.ts +0 -141
  341. package/dist/data-table/root/order.js +0 -76
  342. package/dist/tag/selection.d.ts +0 -10
  343. package/dist/tag/selection.js +0 -12
@@ -1,5 +1,5 @@
1
- import { HelixElement, PopoverController } from '@fusion.dev/helix-core';
2
- import { type PropertyValues, type TemplateResult } from 'lit';
1
+ import { HelixElement, KeyboardNavigationController, PopoverController } from '@fusion.dev/helix-core';
2
+ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
3
3
  declare const HelixHeadlessMegamenu_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & typeof HelixElement;
4
4
  /**
5
5
  * @summary A section of a navigation with a trigger that opens a panel of links.
@@ -21,11 +21,36 @@ declare const HelixHeadlessMegamenu_base: (new (...args: any[]) => import("@fusi
21
21
  * along the row and see each section.
22
22
  *
23
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.
24
+ * moved, as Radix's `data-motion` does. Moving toward the end of the bar, the
25
+ * one opening is `:state(from-end)` and the one closing is `:state(to-start)`;
26
+ * moving back, they are `:state(from-start)` and `:state(to-end)`. A
27
+ * stylesheet slides them on that. Start and end follow the reading direction,
28
+ * so on a right-to-left page the end is on the left. A panel that opens or
29
+ * closes on its own carries none of the four. A press on another megamenu's
30
+ * trigger hands over the same way as hovering it.
31
+ *
32
+ * While a panel is open its surface carries its own size, as
33
+ * `--megamenu-surface-inline-size` and `--megamenu-surface-block-size`, and a
34
+ * panel that took over from another also carries that one's size, as
35
+ * `--megamenu-from-inline-size` and `--megamenu-from-block-size`. Radix's
36
+ * navigation menu publishes the same pair from its shared viewport, so a
37
+ * stylesheet can grow or shrink one panel into the next.
38
+ *
39
+ * The panel's default slot is the `columns` part and draws no box, so a sheet
40
+ * can give the columns one of their own. While a panel is open, an
41
+ * `indicator` slot is rendered beside its trigger, as Radix's indicator
42
+ * marks the open one: slot a mark of your own, such as a bar or an arrow
43
+ * pointing at the panel, and it shows only while the panel is open. The styled
44
+ * tier rests it on the trigger's bottom edge.
45
+ *
46
+ * Left and Right Arrow move between the triggers of the megamenus beside this
47
+ * one, and Home and End go to the first and the last, as Radix's navigation
48
+ * menu does. In a `Navigation`, which holds them in a slot, the arrows are the
49
+ * navigation's, and move between its destinations under its `arrows`. Down Arrow on the trigger of an open panel moves
50
+ * focus to the panel's first link, Escape closes the panel and returns focus
51
+ * to its trigger, and Tab moves through the panel's links and closes it on the
52
+ * way out. The trigger says `aria-expanded`, and the panel is a group named by
53
+ * `label`.
29
54
  *
30
55
  * @since 0.1.0
31
56
  * @status stable
@@ -34,25 +59,34 @@ declare const HelixHeadlessMegamenu_base: (new (...args: any[]) => import("@fusi
34
59
  * @documentation https://fusion.dev/helix/components/megamenu
35
60
  *
36
61
  * @slot - The panel's contents, such as your own lists of links and their headings.
62
+ * @slot indicator - A mark for the open trigger, shown while the panel is open, such as a bar or an arrow pointing at the panel.
37
63
  * @slot trigger - The control that opens the panel. When it is empty, a button named by `label` is shown.
38
64
  *
39
65
  * @event {HelixBeforeCloseEvent} helix-before-close - The panel is about to close. Cancelable.
40
66
  * @event {HelixBeforeOpenEvent} helix-before-open - The panel is about to open. Cancelable.
41
67
  * @event {ToggleEvent} toggle - The panel opened or closed. Carries `newState` and `oldState`.
42
68
  *
69
+ * @csspart columns - The panel's default slot. It draws no box until a sheet gives it a `display`.
70
+ * @csspart indicator - The `indicator` slot, rendered while the panel is open.
43
71
  * @csspart surface - The floating panel that opens.
44
72
  * @csspart trigger - The default trigger button, shown when the `trigger` slot is empty.
45
73
  *
74
+ * @cssproperty --megamenu-from-block-size - The height of the panel this one took over from, written on the surface while it is open.
75
+ * @cssproperty --megamenu-from-inline-size - The width of the panel this one took over from, written on the surface while it is open.
76
+ * @cssproperty --megamenu-surface-block-size - The panel's own height, written on the surface while it is open.
77
+ * @cssproperty --megamenu-surface-inline-size - The panel's own width, written on the surface while it is open.
46
78
  * @cssproperty --megamenu-top - Where the panel starts, measured from the bar above it.
47
79
  *
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.
80
+ * @cssstate from-end - The panel opened in place of one earlier in the bar, so it can enter from the end side.
81
+ * @cssstate from-start - The panel opened in place of one later in the bar, so it can enter from the start side.
50
82
  * @cssstate narrow - The page is narrower than `band-below`, so the panel is shown as a band whatever its variant.
51
83
  * @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.
84
+ * @cssstate to-end - The panel closed because one earlier in the bar opened, so it can leave toward the end.
85
+ * @cssstate to-start - The panel closed because one later in the bar opened, so it can leave toward the start.
54
86
  */
55
87
  export declare class HelixHeadlessMegamenu extends HelixHeadlessMegamenu_base {
88
+ /** The bar's one open panel, shared by every megamenu on the page. */
89
+ private static readonly bar;
56
90
  /**
57
91
  * The page width, in pixels, below which a card panel is shown as a band. At
58
92
  * zero, it never is.
@@ -135,6 +169,22 @@ export declare class HelixHeadlessMegamenu extends HelixHeadlessMegamenu_base {
135
169
  * the consumer slotted, or the button drawn in its place.
136
170
  */
137
171
  get navigationControl(): HTMLElement;
172
+ /**
173
+ * The arrows along a bar of megamenus that no component holds in a slot.
174
+ *
175
+ * Each megamenu's trigger is one stop, and a press counts only from a
176
+ * trigger, so an arrow among an open panel's links stays with the panel.
177
+ * Down and Up are reserved: Down enters an open panel. A megamenu whose
178
+ * parent is a component, and so holds it in a slot, passes no stops, so a
179
+ * `Navigation` around it decides the arrows, on or off, for every
180
+ * destination at once.
181
+ */
182
+ protected readonly keys: KeyboardNavigationController;
183
+ /**
184
+ * Down Arrow on the trigger of an open panel moves focus to the panel's first
185
+ * link or control, as Radix's navigation menu does.
186
+ */
187
+ private readonly handleKeyDown;
138
188
  /** Shuts it and puts the reader back where they were. */
139
189
  private close;
140
190
  /**
@@ -252,14 +302,22 @@ export declare class HelixHeadlessMegamenu extends HelixHeadlessMegamenu_base {
252
302
  *
253
303
  * Before the render rather than after it, because the popover controller
254
304
  * raises the panel from its own `hostUpdated`, which runs before `updated`:
255
- * settled there, the two would be up together for a frame. The other closes
256
- * through `requestOpen`, so a consumer holding it open is asked rather than
257
- * overruled.
305
+ * settled there, the two would be up together for a frame. The bookkeeping
306
+ * is `HandOver`'s.
258
307
  */
259
308
  protected willUpdate(changed: PropertyValues): void;
309
+ /** The panel's size the last time it was open, in pixels. */
310
+ private size;
311
+ /** The size of the panel this one took over from, if it took over. */
312
+ private from;
313
+ /**
314
+ * Writes the panel's size onto its surface, and the size of the panel it
315
+ * took over from, for a stylesheet that grows one into the next.
316
+ */
317
+ private measure;
260
318
  /**
261
319
  * 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.
320
+ * Nothing clears all four, for a panel opened or closed on its own.
263
321
  */
264
322
  private motion;
265
323
  protected updated(changed: PropertyValues): void;
@@ -271,6 +329,13 @@ export declare class HelixHeadlessMegamenu extends HelixHeadlessMegamenu_base {
271
329
  * has one reaches this without reimplementing the panel below it.
272
330
  */
273
331
  protected renderTrigger(): TemplateResult;
332
+ /**
333
+ * The mark under the trigger, while the panel is open. Rendered only then,
334
+ * so a mark of your own needs no rule to hide it while the panel is closed,
335
+ * and hidden from the accessibility tree: the trigger's `aria-expanded`
336
+ * already says the panel is open.
337
+ */
338
+ protected renderIndicator(): TemplateResult | typeof nothing;
274
339
  protected render(): TemplateResult;
275
340
  }
276
341
  declare global {
@@ -5,10 +5,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  var HelixHeadlessMegamenu_1;
8
- import { anchorElement, customElement, deepContains, HelixElement, MixinControllerOpen, PopoverController, tellDisclosure, } from '@fusion.dev/helix-core';
8
+ import { anchorElement, customElement, deepContains, focusableElements, HelixElement, KeyboardNavigationController, MixinControllerOpen, PopoverController, tellDisclosure, } from '@fusion.dev/helix-core';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
11
- let showing;
11
+ import { HandOver } from '../hand-over.js';
12
12
  let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerOpen(HelixElement) {
13
13
  constructor() {
14
14
  super(...arguments);
@@ -21,13 +21,45 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
21
21
  };
22
22
  this.panel = new PopoverController(this, {
23
23
  anchor: () => this.trigger,
24
- boundary: () => this,
24
+ boundary: () => [...HelixHeadlessMegamenu_1.bar.connected],
25
25
  onDismiss: () => this.close(),
26
26
  open: () => this.open,
27
27
  place: () => !this.banded,
28
28
  placement: () => 'bottom-start',
29
29
  surface: () => this.partNamed('surface'),
30
30
  });
31
+ this.keys = new KeyboardNavigationController(this, {
32
+ items: () => !this.parentElement?.shadowRoot
33
+ ? HelixHeadlessMegamenu_1.bar.alongside(this).map((megamenu) => ({
34
+ contains: (node) => {
35
+ const control = megamenu.trigger;
36
+ return node === control || control.contains(node);
37
+ },
38
+ disabled: false,
39
+ focusItem: () => megamenu.trigger.focus(),
40
+ select: () => { },
41
+ selected: false,
42
+ }))
43
+ : [],
44
+ origin: 'focus',
45
+ reserved: () => ['ArrowDown', 'ArrowUp'],
46
+ selects: () => false,
47
+ wrap: false,
48
+ });
49
+ this.handleKeyDown = (event) => {
50
+ if (event.key !== 'ArrowDown' || !this.open || event.defaultPrevented) {
51
+ return;
52
+ }
53
+ const trigger = this.trigger;
54
+ if (!event.composedPath().includes(trigger)) {
55
+ return;
56
+ }
57
+ const first = focusableElements(this).find((element) => element !== trigger && !element.closest('[slot="trigger"]'));
58
+ if (first) {
59
+ event.preventDefault();
60
+ first.focus();
61
+ }
62
+ };
31
63
  this.handleScroll = () => {
32
64
  if (!this.open || !this.banded) {
33
65
  return;
@@ -40,11 +72,13 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
40
72
  };
41
73
  this.handlePointerDown = (event) => {
42
74
  this.pointer = event.pointerType;
75
+ HelixHeadlessMegamenu_1.bar.press(this);
43
76
  };
44
77
  this.handlePointerEnter = (event) => {
45
78
  if (this.openOn !== 'hover' || event.pointerType !== 'mouse') {
46
79
  return;
47
80
  }
81
+ const showing = HelixHeadlessMegamenu_1.bar.showing;
48
82
  this.schedule(showing && showing !== this ? 0 : HelixHeadlessMegamenu_1.OPEN_DELAY, () => {
49
83
  this.requestOpen(true);
50
84
  });
@@ -62,6 +96,10 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
62
96
  if (!this.open || next === null || deepContains(this, next)) {
63
97
  return;
64
98
  }
99
+ const pressed = HelixHeadlessMegamenu_1.bar.pressed;
100
+ if (pressed !== undefined && pressed !== this && deepContains(pressed, next)) {
101
+ return;
102
+ }
65
103
  this.requestOpen(false);
66
104
  };
67
105
  this.handleTriggerClick = (event) => {
@@ -72,6 +110,10 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
72
110
  }
73
111
  if (event.detail === 0 || (this.pointer !== undefined && this.pointer !== 'mouse')) {
74
112
  this.requestOpen(!this.open);
113
+ return;
114
+ }
115
+ if (!this.open) {
116
+ this.requestOpen(true);
75
117
  }
76
118
  };
77
119
  this.handleContentClick = (event) => {
@@ -90,6 +132,7 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
90
132
  };
91
133
  }
92
134
  static { HelixHeadlessMegamenu_1 = this; }
135
+ static { this.bar = new HandOver((megamenu, to) => megamenu.motion(to)); }
93
136
  get banded() {
94
137
  return this.variant === 'band' || this.narrow;
95
138
  }
@@ -159,12 +202,14 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
159
202
  connectedCallback() {
160
203
  super.connectedCallback();
161
204
  this.watchWidth();
205
+ HelixHeadlessMegamenu_1.bar.add(this);
162
206
  window.addEventListener('scroll', this.handleScroll, { capture: true, passive: true });
163
207
  this.addEventListener('pointerdown', this.handlePointerDown);
164
208
  this.addEventListener('click', this.handleContentClick);
165
209
  this.addEventListener('pointerenter', this.handlePointerEnter);
166
210
  this.addEventListener('pointerleave', this.handlePointerLeave);
167
211
  this.addEventListener('focusout', this.handleFocusOut);
212
+ this.addEventListener('keydown', this.handleKeyDown);
168
213
  }
169
214
  disconnectedCallback() {
170
215
  super.disconnectedCallback();
@@ -176,10 +221,9 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
176
221
  this.removeEventListener('pointerenter', this.handlePointerEnter);
177
222
  this.removeEventListener('pointerleave', this.handlePointerLeave);
178
223
  this.removeEventListener('focusout', this.handleFocusOut);
224
+ this.removeEventListener('keydown', this.handleKeyDown);
225
+ HelixHeadlessMegamenu_1.bar.remove(this);
179
226
  this.stop();
180
- if (showing === this) {
181
- showing = undefined;
182
- }
183
227
  }
184
228
  willUpdate(changed) {
185
229
  super.willUpdate(changed);
@@ -187,18 +231,25 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
187
231
  return;
188
232
  }
189
233
  if (this.open) {
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);
197
- }
198
- showing = this;
234
+ this.from = HelixHeadlessMegamenu_1.bar.open(this)?.size;
235
+ return;
199
236
  }
200
- else if (showing === this) {
201
- showing = undefined;
237
+ HelixHeadlessMegamenu_1.bar.close(this);
238
+ }
239
+ measure() {
240
+ const surface = this.partNamed('surface');
241
+ if (!surface) {
242
+ return;
243
+ }
244
+ surface.style.removeProperty('--megamenu-from-inline-size');
245
+ surface.style.removeProperty('--megamenu-from-block-size');
246
+ const box = surface.getBoundingClientRect();
247
+ this.size = { block: Math.round(box.height), inline: Math.round(box.width) };
248
+ surface.style.setProperty('--megamenu-surface-inline-size', `${this.size.inline}px`);
249
+ surface.style.setProperty('--megamenu-surface-block-size', `${this.size.block}px`);
250
+ if (this.from) {
251
+ surface.style.setProperty('--megamenu-from-inline-size', `${this.from.inline}px`);
252
+ surface.style.setProperty('--megamenu-from-block-size', `${this.from.block}px`);
202
253
  }
203
254
  }
204
255
  motion(to) {
@@ -216,6 +267,7 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
216
267
  this.tellTrigger();
217
268
  if (this.open) {
218
269
  this.band();
270
+ this.measure();
219
271
  }
220
272
  }
221
273
  renderTrigger() {
@@ -230,8 +282,13 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
230
282
  </button>
231
283
  </slot>`;
232
284
  }
285
+ renderIndicator() {
286
+ return this.open
287
+ ? html `<slot name="indicator" part="indicator" aria-hidden="true"></slot>`
288
+ : nothing;
289
+ }
233
290
  render() {
234
- return html `${this.renderTrigger()}
291
+ return html `${this.renderTrigger()}${this.renderIndicator()}
235
292
  <div
236
293
  part="surface"
237
294
  id="panel"
@@ -240,7 +297,7 @@ let HelixHeadlessMegamenu = class HelixHeadlessMegamenu extends MixinControllerO
240
297
  role="group"
241
298
  ?hidden=${!this.open}
242
299
  >
243
- <slot></slot>
300
+ <slot part="columns"></slot>
244
301
  </div>`;
245
302
  }
246
303
  };
@@ -29,13 +29,25 @@ import '../../kbd/index.js';
29
29
  * nothing: the shortcut is the page's to bind. Other trailing words, such as a
30
30
  * count, go in the `end` slot.
31
31
  *
32
+ * The row is named by its label alone. Words in `description`, a line under the
33
+ * label, and in `end` describe it instead, through `aria-describedby`, as
34
+ * React Aria's menu item does with its description: a reader hears "Copy",
35
+ * then "Copies the selection".
36
+ *
37
+ * The check mark and the caret are the fallbacks of the `check` and `chevron`
38
+ * slots, so a mark of your own replaces either by being slotted. Neither is
39
+ * read as part of the row's name.
40
+ *
32
41
  * @since 0.1.0
33
42
  * @status stable
34
43
  * @aliases Menu option, Menu row
35
44
  * @documentation https://fusion.dev/helix/components/menu
36
45
  *
37
46
  * @slot - The label.
38
- * @slot end - Words after the label, such as a count or a detail, beside any `shortcut`.
47
+ * @slot check - Replaces the check mark of a checked row, such as with your own icon.
48
+ * @slot chevron - Replaces the caret of a row that opens a submenu.
49
+ * @slot description - A line under the label that describes the row. It describes the row to a screen reader and is not part of its name.
50
+ * @slot end - Words after the label, such as a count or a detail, beside any `shortcut`. They describe the row and are not part of its name.
39
51
  * @slot start - Content before the label, such as an icon.
40
52
  * @slot submenu - The rows of a submenu that this row opens.
41
53
  *
@@ -48,6 +60,8 @@ import '../../kbd/index.js';
48
60
  * when it opens a submenu. A row never shows both, so they share one column.
49
61
  * @csspart shortcut - The key drawn for `shortcut`.
50
62
  * @csspart shortcut-kbd - The key inside it.
63
+ * @csspart shortcut-key - One key of the shortcut's chord, such as `Ctrl`.
64
+ * @csspart shortcut-separator - The `+` between two keys of the shortcut, where the platform writes one.
51
65
  * @csspart start - The leading column that holds the `start` slot. It is always rendered.
52
66
  *
53
67
  * @cssstate checked - The row is checked.
@@ -201,6 +215,8 @@ export declare class HelixHeadlessMenuItem extends HelixElement {
201
215
  private start;
202
216
  /** Whether anything is slotted after the label, read the way `start` is. */
203
217
  private end;
218
+ /** Whether anything is slotted under the label, read the way `start` is. */
219
+ private description;
204
220
  /**
205
221
  * Both answers, from the children, before each render.
206
222
  *
@@ -223,13 +239,25 @@ export declare class HelixHeadlessMenuItem extends HelixElement {
223
239
  private readonly readStart;
224
240
  /** Re-reads whether anything is after the label, as `readStart` does before it. */
225
241
  private readonly readEnd;
242
+ /** Re-reads whether anything is under the label, as `readStart` does before it. */
243
+ private readonly readDescription;
244
+ /**
245
+ * The line under the label. The slot is hidden from the row's name and named
246
+ * by the row's `aria-describedby`, which reads it all the same: a description
247
+ * is read from what it points at, hidden or not. No box of its own, so a row
248
+ * with no description lays out as it did; `data-empty` says which it is.
249
+ */
250
+ protected renderDescription(): TemplateResult;
251
+ /** What describes the row: the line under its label and the words after it. */
252
+ private get describedBy();
226
253
  /**
227
254
  * The trailing column: the shortcut's key, then whatever is slotted in `end`.
228
255
  * Drawn by `Kbd`, interpolated so each tier draws its own.
229
256
  *
230
257
  * The key is hidden from the accessibility tree, since the row's
231
258
  * `aria-keyshortcuts` says it in words a screen reader reads as keys: inside
232
- * the row its glyphs became part of the row's name.
259
+ * the row its glyphs became part of the row's name. The `end` words are
260
+ * hidden from the name too, and describe the row instead.
233
261
  */
234
262
  protected renderEnd(): TemplateResult;
235
263
  /**
@@ -311,6 +339,27 @@ export declare class HelixHeadlessMenuItem extends HelixElement {
311
339
  * both announces and navigates.
312
340
  */
313
341
  private readonly handleKeydown;
342
+ /**
343
+ * The trailing mark: the caret of a row that opens a page, or the tick of a
344
+ * checked one, each the fallback of a slot a mark of your own replaces.
345
+ *
346
+ * One trailing column, and a row is never both: a way into a page has nothing
347
+ * to tick, and a choice opens nothing. The tick sits after the label rather
348
+ * than before it, so the labels start at the edge of the row and the marks
349
+ * line up down the side they are read from.
350
+ *
351
+ * `data-mirror` is what tells the two apart. They share a part name because
352
+ * they share a column, and only one of them is directional: a caret has to
353
+ * mirror in a right-to-left document and a tick must not, which Unicode's own
354
+ * mirroring list agrees on. The attribute is on an element in this shadow
355
+ * root rather than on the host, so it is the divider's `data-empty` and not a
356
+ * hydration hazard.
357
+ *
358
+ * Nothing to mark, so nothing is drawn. The column this would have sat in is
359
+ * reserved by the menu when some row on the page needs one, so the labels
360
+ * still line up without every row carrying an empty box to line them up with.
361
+ */
362
+ protected renderMark(submenu: boolean): TemplateResult | typeof nothing;
314
363
  protected render(): TemplateResult | typeof nothing;
315
364
  }
316
365
  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 { ariaChord, customElement, deepActiveElement, HelixBeforeToggleEvent, HelixElement, HelixSelectEvent, onApple, requestChange, } from '@fusion.dev/helix-core';
7
+ import { ariaChord, customElement, deepActiveElement, HelixBeforeToggleEvent, HelixElement, HelixSelectEvent, onApple, requestChange, slotFilled, } from '@fusion.dev/helix-core';
8
8
  import { caretRight, check } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -30,13 +30,18 @@ let HelixHeadlessMenuItem = class HelixHeadlessMenuItem extends HelixElement {
30
30
  this.submenu = false;
31
31
  this.start = false;
32
32
  this.end = false;
33
+ this.description = false;
33
34
  this.readStart = () => {
34
35
  const slot = this.renderRoot.querySelector('slot[name="start"]');
35
- this.start = (slot?.assignedNodes().length ?? 0) > 0;
36
+ this.start = slotFilled(slot);
36
37
  };
37
38
  this.readEnd = () => {
38
39
  const slot = this.renderRoot.querySelector('slot[name="end"]');
39
- this.end = (slot?.assignedNodes().length ?? 0) > 0;
40
+ this.end = slotFilled(slot);
41
+ };
42
+ this.readDescription = () => {
43
+ const slot = this.renderRoot.querySelector('slot[name="description"]');
44
+ this.description = slotFilled(slot);
40
45
  };
41
46
  this.readSubmenu = () => {
42
47
  const slot = this.renderRoot.querySelector('slot[name="submenu"]');
@@ -74,11 +79,27 @@ let HelixHeadlessMenuItem = class HelixHeadlessMenuItem extends HelixElement {
74
79
  this.submenu = named('submenu');
75
80
  this.start = named('start');
76
81
  this.end = named('end');
82
+ this.description = named('description');
77
83
  }
78
84
  firstUpdated(changed) {
79
85
  super.firstUpdated(changed);
80
86
  this.finishHydration();
81
87
  }
88
+ renderDescription() {
89
+ return html `<slot
90
+ id="description"
91
+ name="description"
92
+ aria-hidden="true"
93
+ ?data-empty=${!this.description}
94
+ @slotchange=${this.readDescription}
95
+ ></slot>`;
96
+ }
97
+ get describedBy() {
98
+ const ids = [this.description ? 'description' : '', this.end ? 'end-words' : '']
99
+ .filter((id) => id !== '')
100
+ .join(' ');
101
+ return ids === '' ? nothing : ids;
102
+ }
82
103
  renderEnd() {
83
104
  const kbd = this.tag('kbd');
84
105
  return html `<span part="end" ?data-empty=${!this.end && this.shortcut === ''}
@@ -86,10 +107,10 @@ let HelixHeadlessMenuItem = class HelixHeadlessMenuItem extends HelixElement {
86
107
  ? nothing
87
108
  : staticHtml `<${kbd}
88
109
  part="shortcut"
89
- exportparts="kbd: shortcut-kbd"
110
+ exportparts="kbd: shortcut-kbd, key: shortcut-key, separator: shortcut-separator"
90
111
  aria-hidden="true"
91
112
  keys=${this.shortcut}
92
- ></${kbd}>`}<slot name="end" @slotchange=${this.readEnd}></slot
113
+ ></${kbd}>`}<slot id="end-words" name="end" aria-hidden="true" @slotchange=${this.readEnd}></slot
93
114
  ></span>`;
94
115
  }
95
116
  focus() {
@@ -152,6 +173,23 @@ let HelixHeadlessMenuItem = class HelixHeadlessMenuItem extends HelixElement {
152
173
  this.tick();
153
174
  this.dispatchEvent(new HelixSelectEvent({ value: this.value }));
154
175
  }
176
+ renderMark(submenu) {
177
+ if (submenu) {
178
+ return html `<slot name="chevron" aria-hidden="true"
179
+ ><svg part="mark" data-mirror fill="currentColor" viewBox=${caretRight.viewBox} aria-hidden="true">
180
+ ${unsafeSVG(caretRight.content)}
181
+ </svg></slot
182
+ >`;
183
+ }
184
+ if (this.checked) {
185
+ return html `<slot name="check" aria-hidden="true"
186
+ ><svg part="mark" fill="currentColor" viewBox=${check.viewBox} aria-hidden="true">
187
+ ${unsafeSVG(check.content)}
188
+ </svg></slot
189
+ >`;
190
+ }
191
+ return nothing;
192
+ }
155
193
  render() {
156
194
  if (this.showingSubmenu) {
157
195
  return html `<slot name="submenu" @slotchange=${this.readSubmenu}></slot>`;
@@ -169,28 +207,9 @@ let HelixHeadlessMenuItem = class HelixHeadlessMenuItem extends HelixElement {
169
207
  ><slot name="start" @slotchange=${this.readStart}></slot
170
208
  ></span>
171
209
  <slot></slot>
210
+ ${this.renderDescription()}
172
211
  ${this.renderEnd()}
173
- ${submenu
174
- ? html `<svg
175
- part="mark"
176
- data-mirror
177
- fill="currentColor"
178
- viewBox=${caretRight.viewBox}
179
- aria-hidden="true"
180
- >
181
- ${unsafeSVG(caretRight.content)}
182
- </svg>`
183
- : this.checked
184
- ? html `<svg
185
- part="mark"
186
- fill="currentColor"
187
- viewBox=${check.viewBox}
188
- aria-hidden="true"
189
- >
190
- ${unsafeSVG(check.content)}
191
- </svg>`
192
- :
193
- nothing}`;
212
+ ${this.renderMark(submenu)}`;
194
213
  return html `${linked
195
214
  ? html `<a
196
215
  part="item"
@@ -200,6 +219,7 @@ let HelixHeadlessMenuItem = class HelixHeadlessMenuItem extends HelixElement {
200
219
  ?download=${this.download}
201
220
  role=${role}
202
221
  aria-checked=${checkedState}
222
+ aria-describedby=${this.describedBy}
203
223
  aria-haspopup=${submenu ? 'menu' : nothing}
204
224
  aria-keyshortcuts=${keys}
205
225
  tabindex="-1"
@@ -210,6 +230,7 @@ let HelixHeadlessMenuItem = class HelixHeadlessMenuItem extends HelixElement {
210
230
  part="item"
211
231
  role=${role}
212
232
  aria-checked=${checkedState}
233
+ aria-describedby=${this.describedBy}
213
234
  aria-disabled=${this.disabled ? 'true' : nothing}
214
235
  aria-haspopup=${submenu ? 'menu' : nothing}
215
236
  aria-keyshortcuts=${keys}
@@ -265,6 +286,9 @@ __decorate([
265
286
  __decorate([
266
287
  state()
267
288
  ], HelixHeadlessMenuItem.prototype, "end", void 0);
289
+ __decorate([
290
+ state()
291
+ ], HelixHeadlessMenuItem.prototype, "description", void 0);
268
292
  HelixHeadlessMenuItem = __decorate([
269
293
  customElement('helix-headless-menu-item')
270
294
  ], HelixHeadlessMenuItem);
@@ -28,6 +28,20 @@ declare const HelixHeadlessMenu_base: (new (...args: any[]) => import("@fusion.d
28
28
  * its heading. Between runs of rows, a `<helix-divider announced>` is a
29
29
  * separator a screen reader announces.
30
30
  *
31
+ * Keys: Enter, Space or Down Arrow on the trigger opens the menu on its first
32
+ * row, and Up Arrow on its last. In the menu, Up and Down Arrow move between
33
+ * rows, Home and End go to the first and the last, a typed letter moves to
34
+ * the next row whose name starts with it, Enter and Space choose, Right Arrow
35
+ * opens a row's submenu and Left Arrow goes back, the two swapping on a
36
+ * right-to-left page, and Escape closes the menu and returns focus to the
37
+ * trigger. Tab closes it and moves on.
38
+ *
39
+ * While it is open, the surface carries the trigger's width as
40
+ * `--floating-anchor-inline-size` and the room left below it as
41
+ * `--floating-available-block-size`, as Radix's dropdown menu publishes its
42
+ * trigger's width, for a menu as wide as its trigger:
43
+ * `helix-menu::part(surface) { min-inline-size: var(--floating-anchor-inline-size) }`.
44
+ *
31
45
  * With `context`, the trigger is an area and the menu is its context menu: a
32
46
  * right-click, a long press, Shift+F10 or the menu key over the area opens it
33
47
  * at the pointer, or at the area's corner from the keyboard, as Radix's context
@@ -57,6 +71,9 @@ declare const HelixHeadlessMenu_base: (new (...args: any[]) => import("@fusion.d
57
71
  * @csspart surface - The floating panel the menu is drawn on.
58
72
  * @csspart title - The name of the submenu that is showing.
59
73
  *
74
+ * @cssproperty --floating-anchor-inline-size - The trigger's width, written on the panel while it is open, as in `min-inline-size: var(--floating-anchor-inline-size)`. Read it; a value set here is written over.
75
+ * @cssproperty --floating-available-block-size - The room between the panel and the edge of the screen it opens toward, written on the panel while it is open. Read it; a value set here is written over.
76
+ *
60
77
  * @cssstate drilled - A submenu's page is showing, so content that is not a row can hide with the top page.
61
78
  * @cssstate mark - A row on the current page has a checkbox or a link, so every row keeps the trailing column.
62
79
  * @cssstate open - While the menu is open.
@@ -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, anchorElement, customElement, DrilldownController, deepActiveElement, deepContains, HelixElement, inlineStep, KeyboardNavigationController, MixinCollection, MixinControllerOpen, PopoverController, scrollItemIntoView, slottedWords, tellDisclosure, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, anchorElement, customElement, DrilldownController, deepActiveElement, deepContains, HelixElement, inlineStep, KeyboardNavigationController, MixinCollection, MixinControllerOpen, PopoverController, scrollItemIntoView, slottedWords, tellDisclosure, typeaheadBy, } from '@fusion.dev/helix-core';
8
8
  import { caretLeft } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property } from 'lit/decorators.js';
@@ -29,7 +29,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
29
29
  items: () => (this.open ? this.items : []),
30
30
  reserved: () => ['ArrowLeft', 'ArrowRight'],
31
31
  selects: () => false,
32
- typeahead: (item) => slottedWords(item, ['']),
32
+ typeahead: typeaheadBy((item) => slottedWords(item, [''])),
33
33
  });
34
34
  this.aria = new AriaForwardController(this, {
35
35
  label: true,