@fusion.dev/helix-headless 0.144.0 → 0.146.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/custom-elements.json +15195 -4240
  2. package/dist/accordion/item/accordion-item.d.ts +62 -12
  3. package/dist/accordion/item/accordion-item.js +41 -10
  4. package/dist/accordion/root/accordion-root.d.ts +14 -5
  5. package/dist/accordion/root/accordion-root.js +7 -1
  6. package/dist/announcement/root/announcement-root.d.ts +24 -3
  7. package/dist/announcement/root/announcement-root.js +39 -2
  8. package/dist/app-header/root/app-header-root.d.ts +12 -0
  9. package/dist/app-header/root/app-header-root.js +13 -1
  10. package/dist/app-header/sectioning.d.ts +9 -0
  11. package/dist/app-header/sectioning.js +27 -0
  12. package/dist/avatar/group/avatar-group.d.ts +20 -14
  13. package/dist/avatar/group/avatar-group.js +17 -19
  14. package/dist/badge/root/badge-root.d.ts +3 -1
  15. package/dist/badge/root/badge-root.js +2 -2
  16. package/dist/bar-chart/root/bar-chart-root.d.ts +18 -1
  17. package/dist/bar-chart/root/bar-chart-root.js +52 -15
  18. package/dist/bar-chart/stack.d.ts +15 -0
  19. package/dist/bar-chart/stack.js +19 -0
  20. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +57 -1
  21. package/dist/breadcrumbs/root/breadcrumbs-root.js +73 -3
  22. package/dist/button/root/button-root.d.ts +26 -0
  23. package/dist/button/root/button-root.js +38 -18
  24. package/dist/button-group/root/button-group-root.d.ts +2 -1
  25. package/dist/button-group/root/button-group-root.js +5 -1
  26. package/dist/canvas/node/canvas-node.d.ts +4 -3
  27. package/dist/canvas/node/canvas-node.js +3 -2
  28. package/dist/canvas/root/canvas-root.d.ts +38 -3
  29. package/dist/canvas/root/canvas-root.js +123 -42
  30. package/dist/card/root/card-root.d.ts +24 -3
  31. package/dist/card/root/card-root.js +20 -8
  32. package/dist/carousel/root/carousel-root.d.ts +133 -4
  33. package/dist/carousel/root/carousel-root.js +174 -24
  34. package/dist/carousel/stops.d.ts +20 -0
  35. package/dist/carousel/stops.js +30 -0
  36. package/dist/chat/composer/chat-composer.d.ts +38 -6
  37. package/dist/chat/composer/chat-composer.js +42 -9
  38. package/dist/chat/message/chat-message.d.ts +32 -1
  39. package/dist/chat/message/chat-message.js +27 -10
  40. package/dist/chat/naming.d.ts +26 -0
  41. package/dist/chat/naming.js +14 -0
  42. package/dist/chat/root/chat-root.d.ts +58 -0
  43. package/dist/chat/root/chat-root.js +43 -3
  44. package/dist/checkbox/root/checkbox-root.d.ts +20 -0
  45. package/dist/checkbox/root/checkbox-root.js +14 -1
  46. package/dist/checkbox-group/root/checkbox-group-root.d.ts +8 -2
  47. package/dist/checkbox-group/root/checkbox-group-root.js +12 -10
  48. package/dist/checkbox-group/select-all.d.ts +27 -0
  49. package/dist/checkbox-group/select-all.js +12 -0
  50. package/dist/code-block/highlight.d.ts +15 -0
  51. package/dist/code-block/highlight.js +4 -0
  52. package/dist/code-block/root/code-block-root.d.ts +57 -2
  53. package/dist/code-block/root/code-block-root.js +63 -8
  54. package/dist/color-input/root/color-input-root.d.ts +3 -0
  55. package/dist/color-input/root/color-input-root.js +6 -3
  56. package/dist/color-picker/root/color-picker-root.d.ts +33 -4
  57. package/dist/color-picker/root/color-picker-root.js +80 -21
  58. package/dist/color-picker/swatches.d.ts +12 -0
  59. package/dist/color-picker/swatches.js +26 -0
  60. package/dist/combobox/root/combobox-root.d.ts +43 -0
  61. package/dist/combobox/root/combobox-root.js +79 -15
  62. package/dist/command/root/command-root.d.ts +16 -1
  63. package/dist/command/root/command-root.js +22 -4
  64. package/dist/copy-button/root/copy-button-root.d.ts +26 -1
  65. package/dist/copy-button/root/copy-button-root.js +12 -5
  66. package/dist/data-table/index.d.ts +1 -1
  67. package/dist/data-table/index.js +1 -1
  68. package/dist/data-table/keys.d.ts +24 -0
  69. package/dist/data-table/keys.js +24 -0
  70. package/dist/data-table/root/data-table-root.d.ts +170 -13
  71. package/dist/data-table/root/data-table-root.js +294 -52
  72. package/dist/data-table/tree.d.ts +55 -0
  73. package/dist/data-table/tree.js +54 -0
  74. package/dist/date-input/root/date-input-root.d.ts +3 -1
  75. package/dist/date-input/root/date-input-root.js +18 -7
  76. package/dist/date-picker/root/date-picker-root.js +12 -6
  77. package/dist/description-list/item/description-list-item.d.ts +17 -2
  78. package/dist/description-list/item/description-list-item.js +15 -2
  79. package/dist/description-list/root/description-list-root.d.ts +27 -1
  80. package/dist/description-list/root/description-list-root.js +26 -1
  81. package/dist/dialog/description.js +15 -1
  82. package/dist/dialog/root/dialog-root.d.ts +8 -2
  83. package/dist/dialog/root/dialog-root.js +16 -1
  84. package/dist/divider/root/divider-root.d.ts +3 -0
  85. package/dist/divider/root/divider-root.js +2 -1
  86. package/dist/donut-chart/root/donut-chart-root.d.ts +31 -0
  87. package/dist/donut-chart/root/donut-chart-root.js +48 -1
  88. package/dist/drawer/reveal.d.ts +8 -0
  89. package/dist/drawer/reveal.js +1 -0
  90. package/dist/drawer/root/drawer-root.d.ts +59 -0
  91. package/dist/drawer/root/drawer-root.js +63 -4
  92. package/dist/drilldown/item/drilldown-item.d.ts +11 -6
  93. package/dist/drilldown/item/drilldown-item.js +8 -5
  94. package/dist/drilldown/root/drilldown-root.d.ts +29 -0
  95. package/dist/drilldown/root/drilldown-root.js +28 -5
  96. package/dist/element-events.generated.js +83 -12
  97. package/dist/empty/root/empty-root.d.ts +3 -1
  98. package/dist/empty/root/empty-root.js +3 -2
  99. package/dist/file-input/root/file-input-root.d.ts +69 -6
  100. package/dist/file-input/root/file-input-root.js +82 -19
  101. package/dist/file-input/screen.d.ts +2 -1
  102. package/dist/filter-input/menu/filter-menu.d.ts +5 -0
  103. package/dist/filter-input/menu/filter-menu.js +16 -4
  104. package/dist/filter-input/root/filter-input-root.d.ts +30 -6
  105. package/dist/filter-input/root/filter-input-root.js +1 -1
  106. package/dist/filter-input/suggest.d.ts +28 -3
  107. package/dist/filter-input/suggest.js +18 -8
  108. package/dist/format-date/root/format-date-root.d.ts +9 -16
  109. package/dist/format-date/root/format-date-root.js +10 -27
  110. package/dist/heatmap/root/heatmap-root.d.ts +24 -13
  111. package/dist/heatmap/root/heatmap-root.js +34 -12
  112. package/dist/icon/root/icon-root.d.ts +12 -1
  113. package/dist/icon/root/icon-root.js +21 -10
  114. package/dist/icon/settle.d.ts +7 -0
  115. package/dist/icon/settle.js +10 -0
  116. package/dist/icon-button/root/icon-button-root.d.ts +2 -0
  117. package/dist/image/root/image-root.d.ts +5 -1
  118. package/dist/image/root/image-root.js +10 -2
  119. package/dist/input/root/input-root.d.ts +13 -3
  120. package/dist/input/root/input-root.js +12 -3
  121. package/dist/kbd/root/kbd-root.d.ts +35 -1
  122. package/dist/kbd/root/kbd-root.js +23 -4
  123. package/dist/legend/root/legend-root.d.ts +55 -8
  124. package/dist/legend/root/legend-root.js +55 -13
  125. package/dist/lightbox/root/lightbox-root.d.ts +49 -6
  126. package/dist/lightbox/root/lightbox-root.js +86 -19
  127. package/dist/lightbox/zoom-controller.d.ts +59 -0
  128. package/dist/lightbox/zoom-controller.js +128 -0
  129. package/dist/lightbox/zoom.d.ts +22 -0
  130. package/dist/lightbox/zoom.js +16 -0
  131. package/dist/line-chart/root/line-chart-root.d.ts +22 -1
  132. package/dist/line-chart/root/line-chart-root.js +21 -1
  133. package/dist/list/item/list-item.d.ts +70 -1
  134. package/dist/list/item/list-item.js +77 -6
  135. package/dist/list/numbering.d.ts +14 -0
  136. package/dist/list/numbering.js +8 -0
  137. package/dist/list/root/list-root.d.ts +155 -9
  138. package/dist/list/root/list-root.js +246 -4
  139. package/dist/list/selection.d.ts +49 -0
  140. package/dist/list/selection.js +30 -0
  141. package/dist/listbox/root/listbox-root.d.ts +37 -1
  142. package/dist/listbox/root/listbox-root.js +49 -4
  143. package/dist/loader/busy.d.ts +10 -0
  144. package/dist/loader/busy.js +11 -0
  145. package/dist/loader/root/loader-root.d.ts +9 -2
  146. package/dist/loader/root/loader-root.js +23 -3
  147. package/dist/map/root/map-root.d.ts +6 -2
  148. package/dist/map/root/map-root.js +5 -2
  149. package/dist/megamenu/root/megamenu-root.d.ts +62 -0
  150. package/dist/megamenu/root/megamenu-root.js +90 -5
  151. package/dist/menu/index.d.ts +1 -0
  152. package/dist/menu/index.js +1 -0
  153. package/dist/menu/item/menu-item.d.ts +87 -11
  154. package/dist/menu/item/menu-item.js +78 -22
  155. package/dist/menu/root/menu-root.d.ts +39 -1
  156. package/dist/menu/root/menu-root.js +65 -8
  157. package/dist/menu/section/menu-section.d.ts +55 -0
  158. package/dist/menu/section/menu-section.js +60 -0
  159. package/dist/meter/root/meter-root.d.ts +20 -1
  160. package/dist/meter/root/meter-root.js +11 -15
  161. package/dist/navigation/root/navigation-root.d.ts +18 -2
  162. package/dist/navigation/root/navigation-root.js +29 -3
  163. package/dist/notifications/root/notifications-root.d.ts +25 -0
  164. package/dist/notifications/root/notifications-root.js +33 -5
  165. package/dist/number-input/root/number-input-root.d.ts +17 -8
  166. package/dist/number-input/root/number-input-root.js +2 -7
  167. package/dist/object-inspector/root/object-inspector-root.d.ts +161 -32
  168. package/dist/object-inspector/root/object-inspector-root.js +264 -123
  169. package/dist/object-inspector/rows.d.ts +75 -0
  170. package/dist/object-inspector/rows.js +119 -0
  171. package/dist/option/root/option-root.d.ts +5 -3
  172. package/dist/outline/levels.d.ts +31 -0
  173. package/dist/outline/levels.js +23 -0
  174. package/dist/outline/root/outline-root.d.ts +86 -3
  175. package/dist/outline/root/outline-root.js +95 -12
  176. package/dist/pagination/size/pagination-size.d.ts +12 -2
  177. package/dist/pagination/size/pagination-size.js +20 -5
  178. package/dist/pin-input/code.d.ts +10 -0
  179. package/dist/pin-input/code.js +13 -0
  180. package/dist/pin-input/root/pin-input-root.d.ts +25 -1
  181. package/dist/pin-input/root/pin-input-root.js +10 -11
  182. package/dist/popover/hide-outside.d.ts +14 -0
  183. package/dist/popover/hide-outside.js +41 -0
  184. package/dist/popover/root/popover-root.d.ts +57 -7
  185. package/dist/popover/root/popover-root.js +58 -3
  186. package/dist/progress/root/progress-root.d.ts +20 -0
  187. package/dist/progress/root/progress-root.js +15 -15
  188. package/dist/qr-code/export.d.ts +26 -1
  189. package/dist/qr-code/export.js +14 -0
  190. package/dist/qr-code/root/qr-code-root.d.ts +19 -5
  191. package/dist/qr-code/root/qr-code-root.js +58 -9
  192. package/dist/quote/marks.d.ts +8 -0
  193. package/dist/quote/marks.js +5 -0
  194. package/dist/quote/root/quote-root.d.ts +14 -2
  195. package/dist/quote/root/quote-root.js +23 -1
  196. package/dist/radio/group/radio-group.d.ts +4 -10
  197. package/dist/radio/group/radio-group.js +5 -10
  198. package/dist/radio/root/radio-root.d.ts +6 -2
  199. package/dist/radio/root/radio-root.js +6 -1
  200. package/dist/rating/root/rating-root.d.ts +10 -5
  201. package/dist/rating/root/rating-root.js +32 -8
  202. package/dist/rating/steps.d.ts +7 -0
  203. package/dist/rating/steps.js +9 -0
  204. package/dist/scatter-chart/fit.d.ts +15 -0
  205. package/dist/scatter-chart/fit.js +35 -0
  206. package/dist/scatter-chart/root/scatter-chart-root.d.ts +21 -1
  207. package/dist/scatter-chart/root/scatter-chart-root.js +30 -17
  208. package/dist/scroll-area/root/scroll-area-root.d.ts +84 -0
  209. package/dist/scroll-area/root/scroll-area-root.js +106 -7
  210. package/dist/scroll-area/scrollbar-controller.d.ts +111 -0
  211. package/dist/scroll-area/scrollbar-controller.js +172 -0
  212. package/dist/scroll-area/scrollbar.d.ts +92 -0
  213. package/dist/scroll-area/scrollbar.js +33 -0
  214. package/dist/select/root/select-root.d.ts +15 -0
  215. package/dist/select/root/select-root.js +18 -6
  216. package/dist/skeleton/root/skeleton-root.d.ts +3 -0
  217. package/dist/skeleton/root/skeleton-root.js +4 -2
  218. package/dist/skip-link/root/skip-link-root.js +2 -2
  219. package/dist/slider/root/slider-root.d.ts +41 -4
  220. package/dist/slider/root/slider-root.js +23 -3
  221. package/dist/sparkline/readings.d.ts +18 -0
  222. package/dist/sparkline/readings.js +19 -0
  223. package/dist/sparkline/root/sparkline-root.d.ts +78 -7
  224. package/dist/sparkline/root/sparkline-root.js +118 -23
  225. package/dist/speed-dial/root/speed-dial-root.js +2 -2
  226. package/dist/splitter/root/splitter-root.d.ts +20 -12
  227. package/dist/splitter/root/splitter-root.js +226 -203
  228. package/dist/splitter/snap.d.ts +9 -0
  229. package/dist/splitter/snap.js +12 -0
  230. package/dist/stat/root/stat-root.d.ts +14 -5
  231. package/dist/stat/root/stat-root.js +21 -5
  232. package/dist/steps/reach.d.ts +20 -0
  233. package/dist/steps/reach.js +15 -0
  234. package/dist/steps/root/steps-root.d.ts +76 -0
  235. package/dist/steps/root/steps-root.js +93 -1
  236. package/dist/steps/step/step.d.ts +45 -2
  237. package/dist/steps/step/step.js +33 -6
  238. package/dist/switch/root/switch-root.d.ts +10 -0
  239. package/dist/table/column/table-column.d.ts +11 -10
  240. package/dist/table/column/table-column.js +8 -19
  241. package/dist/table/root/table-root.d.ts +126 -4
  242. package/dist/table/root/table-root.js +156 -6
  243. package/dist/table/row/table-row.d.ts +47 -1
  244. package/dist/table/row/table-row.js +39 -2
  245. package/dist/tabs/panel/tab-panel.d.ts +22 -5
  246. package/dist/tabs/panel/tab-panel.js +34 -6
  247. package/dist/tabs/root/tabs-root.d.ts +37 -1
  248. package/dist/tabs/root/tabs-root.js +22 -4
  249. package/dist/tabs/tab/tab.d.ts +41 -4
  250. package/dist/tabs/tab/tab.js +49 -3
  251. package/dist/tag/group/tag-group.d.ts +31 -4
  252. package/dist/tag/group/tag-group.js +46 -7
  253. package/dist/tag/root/tag-root.js +9 -2
  254. package/dist/textarea/root/textarea-root.d.ts +28 -1
  255. package/dist/textarea/root/textarea-root.js +40 -1
  256. package/dist/time-input/root/time-input-root.d.ts +5 -1
  257. package/dist/time-input/root/time-input-root.js +16 -8
  258. package/dist/time-picker/root/time-picker-root.d.ts +18 -4
  259. package/dist/time-picker/root/time-picker-root.js +7 -10
  260. package/dist/time-picker/wheel-name.d.ts +9 -0
  261. package/dist/time-picker/wheel-name.js +15 -0
  262. package/dist/timeline/group/timeline-group.d.ts +46 -0
  263. package/dist/timeline/group/timeline-group.js +37 -0
  264. package/dist/timeline/index.d.ts +1 -0
  265. package/dist/timeline/index.js +1 -0
  266. package/dist/timeline/root/timeline-root.d.ts +10 -3
  267. package/dist/toast/item/toast-item.d.ts +24 -18
  268. package/dist/toast/item/toast-item.js +36 -40
  269. package/dist/toast/root/toast-root.d.ts +6 -0
  270. package/dist/toast/root/toast-root.js +16 -1
  271. package/dist/toggle/group/toggle-group.d.ts +24 -3
  272. package/dist/toggle/group/toggle-group.js +34 -5
  273. package/dist/toolbar/root/toolbar-root.d.ts +13 -0
  274. package/dist/toolbar/root/toolbar-root.js +15 -5
  275. package/dist/tooltip/root/tooltip-root.d.ts +13 -2
  276. package/dist/tooltip/root/tooltip-root.js +9 -1
  277. package/dist/tour/back.d.ts +10 -0
  278. package/dist/tour/back.js +8 -0
  279. package/dist/tour/root/tour-root.d.ts +30 -2
  280. package/dist/tour/root/tour-root.js +34 -8
  281. package/dist/tree/item/tree-item.d.ts +61 -4
  282. package/dist/tree/item/tree-item.js +92 -20
  283. package/dist/tree/root/tree-root.d.ts +58 -0
  284. package/dist/tree/root/tree-root.js +80 -16
  285. package/dist/tree/selection.d.ts +24 -0
  286. package/dist/tree/selection.js +13 -0
  287. package/dist/trend/root/trend-root.d.ts +43 -18
  288. package/dist/trend/root/trend-root.js +31 -6
  289. package/dist/video/media-events.d.ts +44 -0
  290. package/dist/video/media-events.js +35 -0
  291. package/dist/video/root/video-root.d.ts +117 -18
  292. package/dist/video/root/video-root.js +93 -47
  293. package/dist/video-playlist/menu/video-playlist-menu.d.ts +5 -0
  294. package/dist/video-playlist/menu/video-playlist-menu.js +3 -1
  295. package/dist/video-playlist/order.d.ts +41 -0
  296. package/dist/video-playlist/order.js +34 -0
  297. package/dist/video-playlist/root/video-playlist-root.d.ts +77 -3
  298. package/dist/video-playlist/root/video-playlist-root.js +60 -16
  299. package/dist/virtual-list/controls.d.ts +4 -0
  300. package/dist/virtual-list/controls.js +30 -0
  301. package/dist/virtual-list/fill.d.ts +22 -0
  302. package/dist/virtual-list/fill.js +23 -0
  303. package/dist/virtual-list/keys.d.ts +15 -0
  304. package/dist/virtual-list/keys.js +24 -0
  305. package/dist/virtual-list/plan.d.ts +49 -0
  306. package/dist/virtual-list/plan.js +16 -0
  307. package/dist/virtual-list/root/virtual-list-root.d.ts +259 -26
  308. package/dist/virtual-list/root/virtual-list-root.js +333 -49
  309. package/lint.json +1 -1
  310. package/package.json +8 -8
  311. package/types/jsx.d.ts +8113 -1394
  312. package/types/svelte.d.ts +2 -0
  313. package/types/vue.d.ts +1678 -353
  314. package/dist/data-table/root/order.d.ts +0 -141
  315. package/dist/data-table/root/order.js +0 -76
  316. package/dist/listbox/range.d.ts +0 -17
  317. package/dist/listbox/range.js +0 -5
  318. package/dist/tag/selection.d.ts +0 -10
  319. package/dist/tag/selection.js +0 -12
@@ -4,35 +4,41 @@ 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';
11
11
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
12
+ const isSection = (element) => 'isMenuSection' in element && element.isMenuSection === true;
12
13
  let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinControllerOpen(HelixElement)) {
13
14
  constructor() {
14
15
  super(...arguments);
15
16
  this.backLabel = 'Back';
17
+ this.context = false;
16
18
  this.label = '';
17
19
  this.offset = 4;
18
20
  this.placement = 'bottom-start';
19
21
  this.drilldown = new DrilldownController(this, {
20
22
  isRow: (element) => 'isMenuItem' in element && element.isMenuItem === true,
21
- root: () => [...this.children].filter((child) => child.slot !== 'trigger'),
23
+ root: () => [...this.children]
24
+ .filter((child) => child.slot !== 'trigger')
25
+ .flatMap((child) => (isSection(child) ? [...child.children] : [child])),
22
26
  slot: 'submenu',
23
27
  });
24
28
  this.keys = new KeyboardNavigationController(this, {
25
29
  items: () => (this.open ? this.items : []),
26
30
  reserved: () => ['ArrowLeft', 'ArrowRight'],
27
31
  selects: () => false,
28
- typeahead: (item) => slottedWords(item, ['']),
32
+ typeahead: typeaheadBy((item) => slottedWords(item, [''])),
29
33
  });
30
34
  this.aria = new AriaForwardController(this, {
31
35
  label: true,
32
36
  target: () => this.partNamed('surface'),
33
37
  });
34
38
  this.panel = new PopoverController(this, {
35
- anchor: () => this.trigger,
39
+ anchor: () => this.context && this.point
40
+ ? this.renderRoot?.querySelector('#point')
41
+ : this.trigger,
36
42
  boundary: () => this,
37
43
  offset: () => this.offset,
38
44
  onDismiss: () => this.hide(),
@@ -40,6 +46,28 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
40
46
  placement: () => this.placement,
41
47
  surface: () => this.partNamed('surface'),
42
48
  });
49
+ this.handleContextMenu = (event) => {
50
+ if (!this.context) {
51
+ return;
52
+ }
53
+ const slot = this.renderRoot?.querySelector('slot[name="trigger"]');
54
+ const areas = slot?.assignedElements({ flatten: true }) ?? [];
55
+ if (!event.composedPath().some((node) => areas.includes(node))) {
56
+ return;
57
+ }
58
+ event.preventDefault();
59
+ const box = this.trigger.getBoundingClientRect();
60
+ const keyed = event.clientX === 0 && event.clientY === 0;
61
+ this.point = keyed ? { x: box.left, y: box.top } : { x: event.clientX, y: event.clientY };
62
+ if (this.open) {
63
+ this.requestUpdate();
64
+ this.updateComplete.then(() => this.panel.reposition());
65
+ return;
66
+ }
67
+ const active = deepActiveElement();
68
+ this.returnTo = active instanceof HTMLElement ? active : undefined;
69
+ this.show();
70
+ };
43
71
  this.handleSelect = (event) => {
44
72
  const item = event.target;
45
73
  if (!this.items.includes(item)) {
@@ -93,6 +121,9 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
93
121
  event.preventDefault();
94
122
  };
95
123
  this.handleTriggerClick = () => {
124
+ if (this.context) {
125
+ return;
126
+ }
96
127
  if (this.open) {
97
128
  this.hide();
98
129
  }
@@ -130,8 +161,11 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
130
161
  this.panel.hide();
131
162
  this.drilldown.reset();
132
163
  if (deepContains(this, deepActiveElement())) {
133
- this.trigger.focus();
164
+ ;
165
+ (this.context ? (this.returnTo ?? this.trigger) : this.trigger).focus();
134
166
  }
167
+ this.point = undefined;
168
+ this.returnTo = undefined;
135
169
  }
136
170
  enter(item) {
137
171
  if (!this.drilldown.enter(item)) {
@@ -149,7 +183,7 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
149
183
  this.updateComplete.then(() => leaving?.focus());
150
184
  }
151
185
  handleClosedKeydown(event) {
152
- if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') {
186
+ if (this.context || (event.key !== 'ArrowDown' && event.key !== 'ArrowUp')) {
153
187
  return;
154
188
  }
155
189
  const slot = this.renderRoot?.querySelector('slot[name="trigger"]');
@@ -165,17 +199,30 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
165
199
  this.addEventListener('helix-select', this.handleSelect, true);
166
200
  this.addEventListener('keydown', this.handleKeydown);
167
201
  this.addEventListener('focusin', this.handleFocusIn);
202
+ this.addEventListener('contextmenu', this.handleContextMenu);
168
203
  }
169
204
  disconnectedCallback() {
170
205
  super.disconnectedCallback();
171
206
  this.removeEventListener('helix-select', this.handleSelect, true);
172
207
  this.removeEventListener('keydown', this.handleKeydown);
173
208
  this.removeEventListener('focusin', this.handleFocusIn);
209
+ this.removeEventListener('contextmenu', this.handleContextMenu);
174
210
  }
175
211
  updated(changed) {
176
212
  super.updated(changed);
177
- this.tellTrigger();
213
+ if (!this.context) {
214
+ this.tellTrigger();
215
+ }
178
216
  for (const child of this.children) {
217
+ if (isSection(child)) {
218
+ child.onPage = this.drilldown.atRoot;
219
+ for (const row of child.children) {
220
+ if (row.isMenuItem === true) {
221
+ this.mark(row, this.drilldown.atRoot);
222
+ }
223
+ }
224
+ continue;
225
+ }
179
226
  const item = child;
180
227
  if (item.isMenuItem !== true) {
181
228
  continue;
@@ -217,7 +264,14 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
217
264
  }
218
265
  }
219
266
  render() {
220
- return html `<slot name="trigger" @click=${this.handleTriggerClick}></slot>
267
+ const point = this.context && this.point;
268
+ return html `<slot name="trigger" @click=${this.handleTriggerClick}></slot>${point
269
+ ? html `<span
270
+ id="point"
271
+ aria-hidden="true"
272
+ style="position: fixed; left: 0; top: 0; translate: ${point.x}px ${point.y}px"
273
+ ></span>`
274
+ : nothing}
221
275
  <div
222
276
  part="surface"
223
277
  popover="manual"
@@ -250,6 +304,9 @@ let HelixHeadlessMenu = class HelixHeadlessMenu extends MixinCollection(MixinCon
250
304
  __decorate([
251
305
  property({ attribute: 'back-label' })
252
306
  ], HelixHeadlessMenu.prototype, "backLabel", void 0);
307
+ __decorate([
308
+ property({ reflect: true, type: Boolean })
309
+ ], HelixHeadlessMenu.prototype, "context", void 0);
253
310
  __decorate([
254
311
  property()
255
312
  ], HelixHeadlessMenu.prototype, "label", void 0);
@@ -0,0 +1,55 @@
1
+ import { HelixElement } from '@fusion.dev/helix-core';
2
+ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
3
+ /**
4
+ * @summary A group of rows in a menu, under a heading.
5
+ *
6
+ * @description
7
+ * The rows inside it are the menu's rows: the arrow keys and typed letters move
8
+ * through them with the rest, and a set of `exclusive` rows is still the run
9
+ * of them next to each other. The section is a `group` named by its heading,
10
+ * as React Aria's menu section is, so a screen reader says which group a row
11
+ * is in as it arrives.
12
+ *
13
+ * A section goes on the menu's first page. A submenu's page takes rows and
14
+ * dividers.
15
+ *
16
+ * @since 0.1.0
17
+ * @status stable
18
+ * @aliases Menu group, Menu heading
19
+ * @documentation https://fusion.dev/helix/components/menu
20
+ *
21
+ * @slot - The rows.
22
+ * @slot heading - The heading, for content richer than `label`.
23
+ *
24
+ * @csspart heading - The words that name the section.
25
+ * @csspart section - The group that holds the heading and the rows.
26
+ */
27
+ export declare class HelixHeadlessMenuSection extends HelixElement {
28
+ /**
29
+ * The heading's words, when they are plain text. Content in the `heading`
30
+ * slot replaces it.
31
+ */
32
+ label: string;
33
+ /**
34
+ * @internal Set by the menu: whether the section is on the page showing. A
35
+ * property, because the menu writes it after the section upgrades.
36
+ */
37
+ onPage: boolean;
38
+ /** @internal What a menu reads to tell a section from a row. */
39
+ readonly isMenuSection = true;
40
+ /**
41
+ * Whether anything is slotted as the heading, read from the children before
42
+ * each render and from the slot after. A section with neither this nor a
43
+ * `label` draws no heading.
44
+ */
45
+ private heading;
46
+ protected willUpdate(changed: PropertyValues): void;
47
+ protected firstUpdated(changed: PropertyValues): void;
48
+ private readonly readHeading;
49
+ protected render(): TemplateResult | typeof nothing;
50
+ }
51
+ declare global {
52
+ interface HTMLElementTagNameMap {
53
+ 'helix-headless-menu-section': HelixHeadlessMenuSection;
54
+ }
55
+ }
@@ -0,0 +1,60 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { customElement, HelixElement } from '@fusion.dev/helix-core';
8
+ import { html, nothing } from 'lit';
9
+ import { property, state } from 'lit/decorators.js';
10
+ let HelixHeadlessMenuSection = class HelixHeadlessMenuSection extends HelixElement {
11
+ constructor() {
12
+ super(...arguments);
13
+ this.label = '';
14
+ this.onPage = true;
15
+ this.isMenuSection = true;
16
+ this.heading = false;
17
+ this.readHeading = (event) => {
18
+ this.heading = event.target.assignedNodes().length > 0;
19
+ };
20
+ }
21
+ willUpdate(changed) {
22
+ super.willUpdate(changed);
23
+ if (this.childrenKnown) {
24
+ this.heading = this.knownChildren.some((child) => child.slot === 'heading');
25
+ }
26
+ }
27
+ firstUpdated(changed) {
28
+ super.firstUpdated(changed);
29
+ this.finishHydration();
30
+ }
31
+ render() {
32
+ if (!this.onPage) {
33
+ return nothing;
34
+ }
35
+ return html `<div part="section" role="group" aria-labelledby="heading">
36
+ <div
37
+ id="heading"
38
+ part="heading"
39
+ role="presentation"
40
+ ?hidden=${this.label === '' && !this.heading}
41
+ >
42
+ <slot name="heading" @slotchange=${this.readHeading}>${this.label}</slot>
43
+ </div>
44
+ <slot></slot>
45
+ </div>`;
46
+ }
47
+ };
48
+ __decorate([
49
+ property()
50
+ ], HelixHeadlessMenuSection.prototype, "label", void 0);
51
+ __decorate([
52
+ property({ attribute: false })
53
+ ], HelixHeadlessMenuSection.prototype, "onPage", void 0);
54
+ __decorate([
55
+ state()
56
+ ], HelixHeadlessMenuSection.prototype, "heading", void 0);
57
+ HelixHeadlessMenuSection = __decorate([
58
+ customElement('helix-headless-menu-section')
59
+ ], HelixHeadlessMenuSection);
60
+ export { HelixHeadlessMenuSection };
@@ -71,6 +71,21 @@ export declare class HelixHeadlessMeter extends HelixElement {
71
71
  * no reader.
72
72
  */
73
73
  band?: MeterBand;
74
+ /**
75
+ * `Intl.NumberFormat` options the reading is written with, as React Aria's
76
+ * Meter and ProgressBar take them: a unit, a currency, or a number of
77
+ * decimals. Written as JSON in the attribute.
78
+ *
79
+ * ```html
80
+ * <helix-meter value="18" max="32" format-options='{"style":"unit","unit":"gigabyte"}'></helix-meter>
81
+ * ```
82
+ *
83
+ * A `percent` style writes the share of the range, and any other the value
84
+ * itself, so the example says "18 GB", and a value past an end as it is.
85
+ * Absent is a whole percentage. The words are announced as well as shown.
86
+ * `value-text` still wins.
87
+ */
88
+ formatOptions?: Intl.NumberFormatOptions;
74
89
  /**
75
90
  * Bottom of the high band.
76
91
  *
@@ -199,7 +214,11 @@ export declare class HelixHeadlessMeter extends HelixElement {
199
214
  * keeps an unbanded meter from being painted as good news.
200
215
  */
201
216
  private get computedBand();
202
- /** What the reading says, which is the consumer's words or a percentage. */
217
+ /**
218
+ * What the reading says: the consumer's words, or the reading in
219
+ * `format-options`, a share of the range for a percent and the value for
220
+ * anything else.
221
+ */
203
222
  private get text();
204
223
  protected willUpdate(changed: PropertyValues): void;
205
224
  /**
@@ -4,21 +4,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, HelixElement, hostAria, slottedWords } from '@fusion.dev/helix-core';
7
+ import { customElement, formatNumber, HelixElement, hostAria, slottedWords, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing, svg } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
- const percents = new Map();
11
- const percent = (share, locale) => {
12
- let format = percents.get(locale);
13
- if (!format) {
14
- format = new Intl.NumberFormat(locale || undefined, {
15
- maximumFractionDigits: 0,
16
- style: 'percent',
17
- });
18
- percents.set(locale, format);
19
- }
20
- return format.format(share);
21
- };
10
+ const WHOLE_PERCENT = { maximumFractionDigits: 0, style: 'percent' };
22
11
  let HelixHeadlessMeter = class HelixHeadlessMeter extends HelixElement {
23
12
  constructor() {
24
13
  super(...arguments);
@@ -80,7 +69,11 @@ let HelixHeadlessMeter = class HelixHeadlessMeter extends HelixElement {
80
69
  return distance === 0 ? 'good' : distance === 1 ? 'fair' : 'poor';
81
70
  }
82
71
  get text() {
83
- return this.valueText || percent(this.ratio, this.locale);
72
+ const options = this.formatOptions;
73
+ return (this.valueText ||
74
+ (options && options.style !== 'percent'
75
+ ? formatNumber(Number.isFinite(this.value) ? this.value : this.span.min, this.locale, options)
76
+ : formatNumber(this.ratio, this.locale, options ?? WHOLE_PERCENT)));
84
77
  }
85
78
  willUpdate(changed) {
86
79
  super.willUpdate(changed);
@@ -90,7 +83,7 @@ let HelixHeadlessMeter = class HelixHeadlessMeter extends HelixElement {
90
83
  this.internals.ariaValueMax = String(max);
91
84
  this.internals.ariaValueNow = String(this.reading);
92
85
  this.internals.ariaValueText =
93
- this.valueText || (this.beyond ? percent(this.ratio, this.locale) : null);
86
+ this.valueText || this.formatOptions !== undefined || this.beyond ? this.text : null;
94
87
  }
95
88
  renderRound() {
96
89
  const bounds = this.thresholds;
@@ -144,6 +137,9 @@ let HelixHeadlessMeter = class HelixHeadlessMeter extends HelixElement {
144
137
  __decorate([
145
138
  property()
146
139
  ], HelixHeadlessMeter.prototype, "band", void 0);
140
+ __decorate([
141
+ property({ attribute: 'format-options', type: Object })
142
+ ], HelixHeadlessMeter.prototype, "formatOptions", void 0);
147
143
  __decorate([
148
144
  property({ type: Number })
149
145
  ], HelixHeadlessMeter.prototype, "high", void 0);
@@ -1,4 +1,4 @@
1
- import { AriaForwardController, HelixElement } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, HelixElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  /**
4
4
  * @summary A set of destinations, with a marker on the current one.
@@ -22,6 +22,13 @@ import { type PropertyValues, type TemplateResult } from 'lit';
22
22
  * Set `orientation="vertical"` to stack the destinations in a column, for a
23
23
  * sidebar.
24
24
  *
25
+ * Set `arrows` and the arrow keys move focus between the destinations, as
26
+ * Radix's navigation menu does: left and right along a row, up and down a
27
+ * column, Home and End to the ends. A `Megamenu` among them is reached at its
28
+ * trigger. Tab still stops at every link, since a navigation is a list of
29
+ * links and not a single control, and the keys across the other axis are
30
+ * left to the page and to an open panel.
31
+ *
25
32
  * @since 0.1.0
26
33
  * @status stable
27
34
  * @category navigation
@@ -29,12 +36,20 @@ import { type PropertyValues, type TemplateResult } from 'lit';
29
36
  * @documentation https://fusion.dev/helix/components/navigation
30
37
  *
31
38
  * @slot - The destinations, as your own links.
39
+ * @slot indicator - A marker of your own, drawn inside the `indicator` part, where the current destination's place and size reach it.
32
40
  *
33
- * @csspart indicator - The marker that moves to the current destination.
41
+ * @csspart indicator - The marker that moves to the current destination. It carries the destination's place and size as `--indicator-x`, `--indicator-y`, `--indicator-inline-size` and `--indicator-block-size`, and `data-placed` once it has been placed.
34
42
  * @csspart nav - The navigation landmark.
35
43
  */
36
44
  export declare class HelixHeadlessNavigation extends HelixElement {
37
45
  private readonly indicator;
46
+ /**
47
+ * Whether the arrow keys move focus between the destinations.
48
+ *
49
+ * Off by default, so a page whose readers scroll with the arrow keys while
50
+ * a link has focus keeps doing so.
51
+ */
52
+ arrows: boolean;
38
53
  /**
39
54
  * The landmark's name, read by screen readers.
40
55
  *
@@ -43,6 +58,7 @@ export declare class HelixHeadlessNavigation extends HelixElement {
43
58
  * second "Main".
44
59
  */
45
60
  label: string;
61
+ protected readonly keys: KeyboardNavigationController;
46
62
  /** Carries a host `aria-label` and `aria-labelledby` to the `<nav>`. */
47
63
  protected readonly aria: AriaForwardController;
48
64
  /**
@@ -4,9 +4,24 @@ 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, HelixElement, IndicatorController, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, focusableElements, HelixElement, IndicatorController, KeyboardNavigationController, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ const FOCUSABLE = 'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])';
11
+ const navigable = (item) => {
12
+ const control = () => item.navigationControl ??
13
+ (item.matches(FOCUSABLE) ? item : focusableElements(item)[0]);
14
+ return {
15
+ contains: (node) => {
16
+ const target = control();
17
+ return target !== undefined && node !== null && (node === target || target.contains(node));
18
+ },
19
+ disabled: false,
20
+ focusItem: () => control()?.focus(),
21
+ select: () => { },
22
+ selected: false,
23
+ };
24
+ };
10
25
  let HelixHeadlessNavigation = class HelixHeadlessNavigation extends HelixElement {
11
26
  constructor() {
12
27
  super(...arguments);
@@ -23,14 +38,22 @@ let HelixHeadlessNavigation = class HelixHeadlessNavigation extends HelixElement
23
38
  observe: () => this.items,
24
39
  surface: () => this.partNamed('nav'),
25
40
  });
41
+ this.arrows = false;
26
42
  this.label = 'Main';
43
+ this.keys = new KeyboardNavigationController(this, {
44
+ items: () => (this.arrows ? this.items.map(navigable) : []),
45
+ origin: 'focus',
46
+ reserved: () => this.orientation === 'vertical' ? ['ArrowLeft', 'ArrowRight'] : ['ArrowDown', 'ArrowUp'],
47
+ selects: () => false,
48
+ wrap: false,
49
+ });
27
50
  this.aria = new AriaForwardController(this, {
28
51
  label: true,
29
52
  target: () => this.partNamed('nav'),
30
53
  });
31
54
  }
32
55
  get items() {
33
- const slot = this.renderRoot.querySelector('slot');
56
+ const slot = this.renderRoot.querySelector('slot:not([name])');
34
57
  return (slot?.assignedElements() ?? []);
35
58
  }
36
59
  watch() {
@@ -57,11 +80,14 @@ let HelixHeadlessNavigation = class HelixHeadlessNavigation extends HelixElement
57
80
  }
58
81
  render() {
59
82
  return html `<nav part="nav" aria-label=${this.label}>
60
- <div part="indicator" aria-hidden="true"></div>
83
+ <div part="indicator" aria-hidden="true"><slot name="indicator"></slot></div>
61
84
  <slot @slotchange=${() => this.watch()}></slot>
62
85
  </nav>`;
63
86
  }
64
87
  };
88
+ __decorate([
89
+ property({ type: Boolean })
90
+ ], HelixHeadlessNavigation.prototype, "arrows", void 0);
65
91
  __decorate([
66
92
  property()
67
93
  ], HelixHeadlessNavigation.prototype, "label", void 0);
@@ -29,6 +29,12 @@ declare const HelixHeadlessNotifications_base: (new (...args: any[]) => import("
29
29
  * the feed holds one page of a longer list, and each row says its place in the
30
30
  * whole of it.
31
31
  *
32
+ * **`load-more` adds a button after the list** that sends `helix-load-more`,
33
+ * for a feed that holds one page of a longer list. Append the next page, set
34
+ * `loading` while it is on its way, and take `load-more` off once there is
35
+ * nothing more. While the feed is loading the button stays, so focus stays on
36
+ * it, and it is `aria-disabled` and sends nothing.
37
+ *
32
38
  * @since 0.1.0
33
39
  * @status stable
34
40
  * @category feedback
@@ -40,6 +46,7 @@ declare const HelixHeadlessNotifications_base: (new (...args: any[]) => import("
40
46
  * @slot header - Above the list, for a title and the mark-all control.
41
47
  *
42
48
  * @event {HelixDismissEvent} helix-dismiss - Fired when the user dismisses a row. The row dispatches it, and you can listen for it on the feed. Cancelable: cancel it to keep the row.
49
+ * @event {HelixLoadMoreEvent} helix-load-more - Fired when a reader presses the `load-more` button, asking for the next page of the feed.
43
50
  * @event {HelixReadEvent} helix-read - Fired by an item when it is marked read or unread, and by the feed when everything is marked read. Cancelable.
44
51
  *
45
52
  * @csspart empty - Shown when there is nothing in the feed.
@@ -49,6 +56,7 @@ declare const HelixHeadlessNotifications_base: (new (...args: any[]) => import("
49
56
  * @csspart live - A copy of the empty and loading messages, in a live region that screen readers announce when they change. Visually hidden in the styled tier.
50
57
  * @csspart loading - Shown while the feed is loading.
51
58
  * @csspart mark-all - The control that marks everything read.
59
+ * @csspart more - The button after the list that asks for more, while `load-more` is set. It is `aria-disabled` while the feed is loading.
52
60
  *
53
61
  * @cssstate media - While a notification in the list holds something in its media slot, so every row keeps that column.
54
62
  */
@@ -67,6 +75,15 @@ export declare class HelixHeadlessNotifications extends HelixHeadlessNotificatio
67
75
  * The feed's name, read by screen readers.
68
76
  */
69
77
  label: string;
78
+ /**
79
+ * Whether to draw a button after the list that asks for the next page, by
80
+ * sending `helix-load-more`. Take it off once there is nothing more.
81
+ */
82
+ loadMore: boolean;
83
+ /**
84
+ * The text of the `load-more` button.
85
+ */
86
+ loadMoreLabel: string;
70
87
  /**
71
88
  * Whether to draw a control that marks everything read.
72
89
  */
@@ -244,6 +261,14 @@ export declare class HelixHeadlessNotifications extends HelixHeadlessNotificatio
244
261
  private markEmpty;
245
262
  protected updated(changed: PropertyValues): void;
246
263
  protected render(): TemplateResult;
264
+ /**
265
+ * Asks for the next page, for the `load-more` button, unless a page is
266
+ * already on its way.
267
+ *
268
+ * The button stays while the feed is loading, marked `aria-disabled`, so
269
+ * focus stays on it: removed, it took focus with it to the body.
270
+ */
271
+ private readonly askForMore;
247
272
  /**
248
273
  * Marks everything read, and keeps focus in the feed.
249
274
  *
@@ -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, deepContains, focusableElements, HelixElement, HelixReadEvent, hostAria, MixinCollection, markRegion, rovingStop, whenHydrated, } from '@fusion.dev/helix-core';
7
+ import { customElement, deepContains, focusableElements, HelixElement, HelixLoadMoreEvent, HelixReadEvent, hostAria, MixinCollection, markRegion, rovingStop, whenHydrated, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { feedStep } from '../feed-keys.js';
@@ -12,6 +12,8 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
12
12
  constructor() {
13
13
  super(...arguments);
14
14
  this.label = '';
15
+ this.loadMore = false;
16
+ this.loadMoreLabel = 'Load more';
15
17
  this.markAll = false;
16
18
  this.markAllLabel = 'Mark all as read';
17
19
  this.handleSlotChange = () => {
@@ -51,6 +53,11 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
51
53
  rowBox(next)?.focus();
52
54
  }
53
55
  };
56
+ this.askForMore = () => {
57
+ if (!this.loading) {
58
+ this.dispatchEvent(new HelixLoadMoreEvent());
59
+ }
60
+ };
54
61
  this.handleMarkAll = (event) => {
55
62
  const button = event.currentTarget;
56
63
  const focused = this.shadowRoot?.activeElement === button;
@@ -146,9 +153,9 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
146
153
  rove() {
147
154
  const rows = this.reachable;
148
155
  const stop = rovingStop(rows, this.stopRow);
149
- const direct = this.rows;
150
- for (const row of this.items) {
151
- const position = direct.indexOf(row) + 1;
156
+ const items = this.items;
157
+ for (const row of items) {
158
+ const position = items.indexOf(row) + 1;
152
159
  whenHydrated(row, () => {
153
160
  row.stop = row === stop;
154
161
  row.position = this.total === undefined ? 0 : position;
@@ -205,17 +212,38 @@ let HelixHeadlessNotifications = class HelixHeadlessNotifications extends MixinC
205
212
  </button>`
206
213
  : nothing}
207
214
  </div>
208
- <div part="list" role="list" aria-busy=${this.loading ? 'true' : nothing}>
215
+ <div
216
+ part="list"
217
+ role="list"
218
+ aria-busy=${this.loading ? 'true' : nothing}
219
+ aria-label=${this.label || nothing}
220
+ >
209
221
  <slot name="items" @slotchange=${this.handleSlotChange}></slot>
210
222
  ${this.renderStatus(hasItems)}
211
223
  </div>
212
224
  ${this.renderLive(hasItems)}
225
+ ${this.loadMore
226
+ ? html `<button
227
+ part="more"
228
+ type="button"
229
+ aria-disabled=${this.loading ? 'true' : nothing}
230
+ @click=${this.askForMore}
231
+ >
232
+ ${this.loadMoreLabel}
233
+ </button>`
234
+ : nothing}
213
235
  <div part="footer"><slot name="footer"></slot></div>`;
214
236
  }
215
237
  };
216
238
  __decorate([
217
239
  property()
218
240
  ], HelixHeadlessNotifications.prototype, "label", void 0);
241
+ __decorate([
242
+ property({ attribute: 'load-more', type: Boolean })
243
+ ], HelixHeadlessNotifications.prototype, "loadMore", void 0);
244
+ __decorate([
245
+ property({ attribute: 'load-more-label' })
246
+ ], HelixHeadlessNotifications.prototype, "loadMoreLabel", void 0);
219
247
  __decorate([
220
248
  property({ attribute: 'mark-all', type: Boolean })
221
249
  ], HelixHeadlessNotifications.prototype, "markAll", void 0);