@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
@@ -4,11 +4,12 @@ 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, reportRuntime } from '@fusion.dev/helix-core';
7
+ import { auditName, customElement, HelixElement, hostAria, reportRuntime, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
11
- import { resolveIcon, watchIcons } from '../registry.js';
11
+ import { iconMutator, resolveIcon, watchIcons } from '../registry.js';
12
+ import { afterPageSettles } from '../settle.js';
12
13
  let HelixHeadlessIcon = class HelixHeadlessIcon extends HelixElement {
13
14
  constructor() {
14
15
  super(...arguments);
@@ -18,6 +19,7 @@ let HelixHeadlessIcon = class HelixHeadlessIcon extends HelixElement {
18
19
  this.missed = '';
19
20
  this.waiting = false;
20
21
  this.arrived = '';
22
+ this.pending = '';
21
23
  }
22
24
  static get observedAttributes() {
23
25
  return [...super.observedAttributes, 'aria-label'];
@@ -64,27 +66,57 @@ let HelixHeadlessIcon = class HelixHeadlessIcon extends HelixElement {
64
66
  }
65
67
  updated(changed) {
66
68
  super.updated(changed);
69
+ if (this.drawn !== undefined) {
70
+ this.mutate();
71
+ this.auditControl();
72
+ }
67
73
  if (this.arrived === this.name && this.drawn !== undefined) {
68
74
  this.dispatchEvent(new Event('load', { bubbles: false, cancelable: false, composed: false }));
69
75
  }
70
76
  this.arrived = '';
71
77
  if (this.drawn === undefined && this.name !== '' && !this.waiting) {
72
- if (this.missed !== this.name) {
73
- this.missed = this.name;
74
- this.dispatchEvent(new Event('error', { bubbles: false, cancelable: false, composed: false }));
75
- reportRuntime({
76
- kind: 'unknown-icon',
77
- message: `<${this.localName} name="${this.name}"> names no registered icon, so it draws ` +
78
- 'nothing. Check the name, register the glyph with `registerIcons`, or import it ' +
79
- 'and pass it as `icon`.',
80
- tag: this.localName,
81
- });
78
+ if (this.missed !== this.name && this.pending !== this.name) {
79
+ this.pending = this.name;
80
+ afterPageSettles(() => this.reportMissing());
82
81
  }
83
82
  }
84
83
  else {
85
84
  this.missed = '';
86
85
  }
87
86
  }
87
+ mutate() {
88
+ const svg = this.renderRoot.querySelector('svg');
89
+ const mutator = this.icon === undefined ? iconMutator(this.name) : undefined;
90
+ if (svg && mutator) {
91
+ mutator(svg);
92
+ }
93
+ }
94
+ auditControl() {
95
+ if (this.label !== '' || this.hasAttribute('aria-label')) {
96
+ return;
97
+ }
98
+ const control = this.closest('a[href], button, summary, [role="button"], [role="link"]');
99
+ if (control) {
100
+ auditName(control, () => null, `Its only content is <${this.localName}>, which is decorative: give the icon a \`label\`, or the control an \`aria-label\`.`, () => (control.textContent ?? '').trim() !== '' ||
101
+ control.querySelector('[alt]:not([alt=""]), [aria-label]:not([aria-label=""])') !== null);
102
+ }
103
+ }
104
+ reportMissing() {
105
+ const name = this.pending;
106
+ this.pending = '';
107
+ if (this.name !== name || this.drawn !== undefined || this.waiting || !this.isConnected) {
108
+ return;
109
+ }
110
+ this.missed = name;
111
+ this.dispatchEvent(new Event('error', { bubbles: false, cancelable: false, composed: false }));
112
+ reportRuntime({
113
+ kind: 'unknown-icon',
114
+ message: `<${this.localName} name="${name}"> names no registered icon, so it draws ` +
115
+ 'nothing. Check the name, register the glyph with `registerIcons`, or import it ' +
116
+ 'and pass it as `icon`.',
117
+ tag: this.localName,
118
+ });
119
+ }
88
120
  render() {
89
121
  const icon = this.drawn;
90
122
  if (!icon) {
@@ -1,2 +1,2 @@
1
- export { type IconResolver, registerIconLibrary, registerIcons, resolveIcon } from '../registry.js';
1
+ export { type IconLibraryOptions, type IconResolver, registerIconLibrary, registerIcons, resolveIcon, } from '../registry.js';
2
2
  export * from './icon-root.js';
@@ -1,2 +1,2 @@
1
- export { registerIconLibrary, registerIcons, resolveIcon } from '../registry.js';
1
+ export { registerIconLibrary, registerIcons, resolveIcon, } from '../registry.js';
2
2
  export * from './icon-root.js';
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Calls back once the page has loaded and painted a frame after it: every
3
+ * module a page lists has run by then, and with it every `registerIcons` and
4
+ * `registerIconLibrary` they hold. A page that has loaded already waits only
5
+ * the frame.
6
+ */
7
+ export declare const afterPageSettles: (callback: () => void) => void;
@@ -0,0 +1,10 @@
1
+ export const afterPageSettles = (callback) => {
2
+ const frame = () => {
3
+ requestAnimationFrame(() => callback());
4
+ };
5
+ if (document.readyState === 'complete') {
6
+ frame();
7
+ return;
8
+ }
9
+ window.addEventListener('load', frame, { once: true });
10
+ };
@@ -17,6 +17,8 @@ import { HelixHeadlessButton } from '../../button/root/button-root.js';
17
17
  * mean a part of a button, and an icon-only button is a complete button with
18
18
  * different content and a different shape.
19
19
  *
20
+ * **Keyboard.** Enter and Space press the button, as `Button`'s do.
21
+ *
20
22
  * @since 0.1.0
21
23
  * @status stable
22
24
  * @category actions
@@ -12,13 +12,17 @@ import { type PropertyValues, type TemplateResult } from 'lit';
12
12
  * The `placeholder` slot is empty by default, so the headless tier does not
13
13
  * depend on `Skeleton`, which it does not ship.
14
14
  *
15
+ * The placeholder is hidden from screen readers, the picture having a name of
16
+ * its own. The fallback is read once the picture fails, after the picture's
17
+ * `alt`, so a reader hears that it did not load, as a sighted reader sees.
18
+ *
15
19
  * @since 0.1.0
16
20
  * @status stable
17
21
  * @category media
18
22
  * @aliases Picture, Img, Figure
19
23
  * @documentation https://fusion.dev/helix/components/image
20
24
  *
21
- * @slot fallback - Shown in place of the image if it fails to load.
25
+ * @slot fallback - Shown in place of the image if it fails to load, and read by screen readers then, such as "Photo unavailable".
22
26
  * @slot placeholder - Shown until the image loads.
23
27
  *
24
28
  * @event {Event} error - The image failed to load. Relayed from the inner image, whose own event stays inside the shadow root.
@@ -30,6 +34,8 @@ import { type PropertyValues, type TemplateResult } from 'lit';
30
34
  *
31
35
  * @cssstate error - The image failed to load, and the fallback shows.
32
36
  * @cssstate loaded - The image loaded.
37
+ * @cssstate loading - The image is on its way, so neither `loaded` nor `error` is true yet.
38
+ * @cssstate waiting - The image is on its way and `placeholder-delay` still holds the placeholder back.
33
39
  */
34
40
  export declare class HelixHeadlessImage extends HelixElement {
35
41
  /**
@@ -117,6 +123,11 @@ export declare class HelixHeadlessImage extends HelixElement {
117
123
  *
118
124
  * `loading` writes nothing, because it is where every image starts and the
119
125
  * resting state of a mirror is the attribute's absence.
126
+ *
127
+ * **Kept beside the custom states, and what the styled tier draws from.** An
128
+ * engine without `CustomStateSet`, Safari before 17.4 and Firefox before
129
+ * 126, records no state, and a picture faded in by `:state(loaded)` alone
130
+ * would stay transparent there for good. A sheet of your own can read either.
120
131
  */
121
132
  status: 'error' | 'loaded' | 'loading';
122
133
  /**
@@ -190,6 +201,8 @@ export declare class HelixHeadlessImage extends HelixElement {
190
201
  private settle;
191
202
  protected willUpdate(changed: PropertyValues): void;
192
203
  protected updated(changed: PropertyValues): void;
204
+ /** Whether the picture is on its way and the wait still holds the placeholder back. */
205
+ private get waiting();
193
206
  private startWait;
194
207
  protected firstUpdated(changed: PropertyValues): void;
195
208
  /**
@@ -92,7 +92,12 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
92
92
  }
93
93
  this.toggleState('loaded', this.status === 'loaded');
94
94
  this.toggleState('error', this.status === 'error');
95
+ this.toggleState('loading', this.status === 'loading');
95
96
  }
97
+ this.toggleState('waiting', this.waiting);
98
+ }
99
+ get waiting() {
100
+ return this.status === 'loading' && this.placeholderDelay > 0 && !this.wait.elapsed;
96
101
  }
97
102
  startWait() {
98
103
  this.wait.start(this.placeholderDelay > 0 ? this.placeholderDelay : undefined);
@@ -142,12 +147,12 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
142
147
  <span
143
148
  part="placeholder"
144
149
  aria-hidden="true"
145
- ?hidden=${this.status !== 'loading' || (this.placeholderDelay > 0 && !this.wait.elapsed)}
150
+ ?hidden=${this.status !== 'loading' || this.waiting}
146
151
  ><slot name="placeholder"></slot
147
152
  ></span>
148
153
  <span
149
154
  part="fallback"
150
- aria-hidden="true"
155
+ aria-hidden=${this.status === 'error' ? nothing : 'true'}
151
156
  ?hidden=${this.status !== 'error'}
152
157
  ><slot name="fallback"></slot
153
158
  ></span>`;
@@ -1,4 +1,4 @@
1
- import { AriaForwardController, HelixFormElement } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, HelixFormElement, type OwnRule } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  /** What the control accepts, which is text of one kind or another. */
4
4
  export type InputType = 'email' | 'number' | 'password' | 'search' | 'tel' | 'text' | 'url';
@@ -20,7 +20,21 @@ declare const HelixHeadlessInput_base: (new (...args: any[]) => import("@fusion.
20
20
  * which a reset restores.
21
21
  *
22
22
  * Validity comes from the browser. `type` and `required` are set on the real
23
- * input, and its `validity` is copied to the host.
23
+ * input, and its `validity` is copied to the host. `validate` adds your own
24
+ * rule, run on every change once the browser finds nothing wrong, as React
25
+ * Aria's TextField `validate` does. What it returns is the message the field
26
+ * shows once the user has edited it, and the message a submit raises.
27
+ *
28
+ * **Keyboard.** The field's own keys are the platform's. Enter submits the
29
+ * form through its default button, as in a native field. The clear button
30
+ * under `clearable` and the reveal button under `reveal` are tab stops of
31
+ * their own after the field, so a keyboard reaches them.
32
+ *
33
+ * The inner input is named by `label`, or by a host `aria-label`,
34
+ * `aria-labelledby` or `<label for>`, and is described by the hint and the
35
+ * message, with `aria-invalid` while a message shows. The clear button is
36
+ * named `clear-label`, and the reveal button `reveal-label` with
37
+ * `aria-pressed` while the password shows.
24
38
  *
25
39
  * @since 0.1.0
26
40
  * @status stable
@@ -28,10 +42,13 @@ declare const HelixHeadlessInput_base: (new (...args: any[]) => import("@fusion.
28
42
  * @aliases TextField, Field, TextInput
29
43
  * @documentation https://fusion.dev/helix/components/input
30
44
  *
45
+ * @slot clear-icon - Replaces the cross on the clear button, under `clearable`.
46
+ * @slot conceal-icon - Replaces the crossed-out eye on the reveal button while the password shows, under `reveal`.
31
47
  * @slot end - After the text, for an icon or a unit.
32
48
  * @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
33
49
  * @slot hint - Help under the control, for content richer than the `hint` text.
34
50
  * @slot label - The label, for content richer than the `label` text.
51
+ * @slot reveal-icon - Replaces the eye on the reveal button while the password is hidden, under `reveal`.
35
52
  * @slot start - Before the text, for an icon or a prefix.
36
53
  *
37
54
  * @event {Event} change - Sent when the user finishes changing the value. Relayed from the native input.
@@ -48,7 +65,8 @@ declare const HelixHeadlessInput_base: (new (...args: any[]) => import("@fusion.
48
65
  * @csspart reveal - The button that shows and hides a password.
49
66
  * @csspart reveal-pressed - The reveal button while the password is shown, added beside `reveal`.
50
67
  *
51
- * @cssstate invalid - The control has an error to show, from the browser's validation or from your `feedback`.
68
+ * @cssstate blank - The field holds no text.
69
+ * @cssstate invalid - The control has an error to show, from the browser's validation, `validate`, or your `feedback`.
52
70
  */
53
71
  export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
54
72
  protected readonly aria: AriaForwardController;
@@ -281,6 +299,19 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
281
299
  * validation follow.
282
300
  */
283
301
  type: InputType;
302
+ /**
303
+ * Your own rule for the value, run on every change once the browser finds
304
+ * nothing wrong. Return a message, or a list of them, to mark the field
305
+ * invalid, and `true`, `null`, or nothing to accept the value.
306
+ */
307
+ validate?: OwnRule;
308
+ /** The cross on the clear button, behind a seam a tier can move. */
309
+ protected renderClearIcon(): TemplateResult;
310
+ /**
311
+ * The eye on the reveal button, behind a seam a tier can move: open while
312
+ * the password is hidden, and crossed out while it shows.
313
+ */
314
+ protected renderRevealIcon(): TemplateResult;
284
315
  protected render(): TemplateResult;
285
316
  }
286
317
  declare global {
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { AriaForwardController, customElement, drawIcon, HelixClearEvent, HelixFormElement, holdCaret, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, applyOwnRule, customElement, drawIcon, HelixClearEvent, HelixFormElement, holdCaret, MixinControllerValue, MixinField, restoreValue, submitImplicitly, } from '@fusion.dev/helix-core';
8
8
  import { eye, eyeSlash, x } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
@@ -48,7 +48,7 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
48
48
  };
49
49
  this.handleKeypress = (event) => {
50
50
  if (event.key === 'Enter' && !event.defaultPrevented) {
51
- this.submitImplicitly();
51
+ submitImplicitly(this.form);
52
52
  }
53
53
  };
54
54
  this.handleChange = (event) => {
@@ -112,6 +112,7 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
112
112
  return;
113
113
  }
114
114
  this.copyValidity(control);
115
+ applyOwnRule(this.internals, control, this.validate, this.value);
115
116
  this.refreshFeedback();
116
117
  }
117
118
  focus(options) {
@@ -136,6 +137,7 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
136
137
  }
137
138
  willUpdate(changed) {
138
139
  super.willUpdate(changed);
140
+ this.toggleState('blank', this.value === '');
139
141
  if (!this.hasUpdated) {
140
142
  return;
141
143
  }
@@ -150,6 +152,14 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
150
152
  this.releaseCaret = undefined;
151
153
  this.sync();
152
154
  }
155
+ renderClearIcon() {
156
+ return html `<slot name="clear-icon">${drawIcon(x)}</slot>`;
157
+ }
158
+ renderRevealIcon() {
159
+ return this.revealed
160
+ ? html `<slot name="conceal-icon">${drawIcon(eyeSlash)}</slot>`
161
+ : html `<slot name="reveal-icon">${drawIcon(eye)}</slot>`;
162
+ }
153
163
  render() {
154
164
  return html `${this.renderLabel()}
155
165
  <div part="field">
@@ -193,7 +203,7 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
193
203
  aria-label=${this.clearLabel}
194
204
  @click=${this.handleClear}
195
205
  >
196
- ${drawIcon(x)}
206
+ ${this.renderClearIcon()}
197
207
  </button>`
198
208
  : nothing}
199
209
  ${this.reveal && this.type === 'password'
@@ -207,7 +217,7 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
207
217
  this.revealed = !this.revealed;
208
218
  }}
209
219
  >
210
- ${drawIcon(this.revealed ? eyeSlash : eye)}
220
+ ${this.renderRevealIcon()}
211
221
  </button>`
212
222
  : nothing}
213
223
  </div>
@@ -268,6 +278,9 @@ __decorate([
268
278
  __decorate([
269
279
  property()
270
280
  ], HelixHeadlessInput.prototype, "type", void 0);
281
+ __decorate([
282
+ property({ attribute: false })
283
+ ], HelixHeadlessInput.prototype, "validate", void 0);
271
284
  HelixHeadlessInput = __decorate([
272
285
  customElement('helix-headless-input')
273
286
  ], HelixHeadlessInput);
@@ -0,0 +1,29 @@
1
+ /**
2
+ * The words and glyphs a chord is drawn with, per platform.
3
+ *
4
+ * Beside the family's `index.ts`, because which label a key gets is a table
5
+ * and a rule, and not the key's template.
6
+ */
7
+ /** A chord's keys as they are shown, and what is shown between two of them. */
8
+ export interface KeyNames {
9
+ /** Each key's label, in the order the chord names them. */
10
+ keys: string[];
11
+ /** What goes between two keys: `+`, a hyphen, or nothing. */
12
+ separator: string;
13
+ }
14
+ /**
15
+ * The labels of a chord's keys on a platform, with `own` labels in place of
16
+ * the platform's, and what goes between two keys.
17
+ *
18
+ * `parts` are the chord's names as `chordParts` splits them. A name `own`
19
+ * holds takes that label, a name the platform knows takes its glyph or word,
20
+ * and any other single character is shown in capitals.
21
+ *
22
+ * **On an Apple keyboard glyphs run together and words are joined with a
23
+ * hyphen**, as Apple writes `Command-K`. A label of more than one character
24
+ * from `own` is a word, so `{"mod": "Command"}` shows `Command-K` there, where
25
+ * nothing between the two ran them into `CommandK`. The platform's own `Esc`
26
+ * and `Space` keep running on from a glyph, as `⌘Esc` always has. Everywhere
27
+ * else keys are joined with `+`.
28
+ */
29
+ export declare const keyNames: (parts: readonly string[], apple: boolean, own?: Readonly<Record<string, string>>) => KeyNames;
@@ -0,0 +1,52 @@
1
+ const APPLE = {
2
+ alt: '⌥',
3
+ backspace: '⌫',
4
+ cmd: '⌘',
5
+ ctrl: '⌃',
6
+ del: '⌦',
7
+ down: '↓',
8
+ enter: '↵',
9
+ esc: 'Esc',
10
+ left: '←',
11
+ meta: '⌘',
12
+ mod: '⌘',
13
+ opt: '⌥',
14
+ right: '→',
15
+ shift: '⇧',
16
+ space: 'Space',
17
+ tab: '⇥',
18
+ up: '↑',
19
+ };
20
+ const ELSEWHERE = {
21
+ alt: 'Alt',
22
+ backspace: 'Backspace',
23
+ cmd: 'Win',
24
+ ctrl: 'Ctrl',
25
+ del: 'Del',
26
+ down: '↓',
27
+ enter: 'Enter',
28
+ esc: 'Esc',
29
+ left: '←',
30
+ meta: 'Win',
31
+ mod: 'Ctrl',
32
+ opt: 'Alt',
33
+ right: '→',
34
+ shift: 'Shift',
35
+ space: 'Space',
36
+ tab: 'Tab',
37
+ up: '↑',
38
+ };
39
+ export const keyNames = (parts, apple, own = {}) => {
40
+ const names = apple ? APPLE : ELSEWHERE;
41
+ let worded = false;
42
+ const keys = parts.map((part) => {
43
+ const name = part.toLowerCase();
44
+ const mine = own[name];
45
+ if (mine !== undefined) {
46
+ worded ||= [...mine].length > 1;
47
+ return mine;
48
+ }
49
+ return names[name] ?? (part.length === 1 ? part.toUpperCase() : part);
50
+ });
51
+ return { keys, separator: apple ? (worded ? '-' : '') : '+' };
52
+ };
@@ -23,6 +23,17 @@ import { type PropertyValues, type TemplateResult } from 'lit';
23
23
  * the shortcut with the control. A chord the page wrote there itself is left
24
24
  * alone, and the key takes back only what it added.
25
25
  *
26
+ * `caps` draws a chord as a key per key: each is a `key` part and the `+`
27
+ * between two a `separator` part, so a sheet can draw a cap for each.
28
+ * `key-labels` renames any key, on every platform, such as
29
+ * `key-labels='{"mod":"Command"}'`. On an Apple keyboard a word joins the
30
+ * next key with a hyphen, as in `Command-K`.
31
+ *
32
+ * **`activate` makes the shortcut work the control `for` names**, with no
33
+ * script: `activate="focus"` moves focus to it, as `/` does to a search
34
+ * field, and `activate="click"` presses it. It acts once `helix-shortcut` has
35
+ * gone out and no listener canceled it, and only where `within` listens.
36
+ *
26
37
  * @since 0.1.0
27
38
  * @status stable
28
39
  * @category typography
@@ -33,9 +44,29 @@ import { type PropertyValues, type TemplateResult } from 'lit';
33
44
  *
34
45
  * @event {HelixShortcutEvent} helix-shortcut - The chord was pressed. Cancelable: cancel it to let the key press keep its usual effect.
35
46
  *
36
- * @csspart kbd - The key.
47
+ * @csspart kbd - The key, or the chord under `keys`.
48
+ * @csspart key - One key of a chord under `keys` and `caps`, such as `Ctrl` in `Ctrl+K`.
49
+ * @csspart separator - The `+` between two keys of a chord under `keys` and `caps`, drawn where the platform writes one: on Windows and Linux. An Apple keyboard writes none between glyphs, and a hyphen between words from `key-labels`.
37
50
  */
38
51
  export declare class HelixHeadlessKbd extends HelixElement {
52
+ /**
53
+ * What the chord does to the control `for` names once it is pressed:
54
+ * `focus` moves focus to the control and `click` presses it.
55
+ *
56
+ * Unset, the chord sends `helix-shortcut` and does nothing else, for a page
57
+ * that acts on the event itself. It acts only where `within` listens, after
58
+ * `helix-shortcut`, and not when a listener cancels that event.
59
+ */
60
+ activate?: 'click' | 'focus';
61
+ /**
62
+ * Draws a chord under `keys` as one key per key, each a `key` part with a
63
+ * `separator` part between two where the platform writes a `+`, as GitHub
64
+ * and most docs draw `Ctrl` `K`.
65
+ *
66
+ * Absent, a chord is one key holding the whole label, as it always was.
67
+ * Reflected, because the styled tier draws the caps on the keys under it.
68
+ */
69
+ caps: boolean;
39
70
  /**
40
71
  * The id of the control the shortcut works, which is given the chord as its
41
72
  * `aria-keyshortcuts`.
@@ -45,6 +76,18 @@ export declare class HelixHeadlessKbd extends HelixElement {
45
76
  * shortcut the page binds itself.
46
77
  */
47
78
  for: string;
79
+ /**
80
+ * Names for keys in place of the platform's own, by the key's name in
81
+ * `keys`, written as JSON in the attribute: `key-labels='{"mod":"Command",
82
+ * "enter":"Return"}'` shows `Command` and `Return` wherever `mod` and
83
+ * `enter` are written.
84
+ *
85
+ * For a page in another language, or a product with its own word for a key.
86
+ * Absent, the platform's glyphs and words are used. Only what is shown
87
+ * changes: the chord written onto `aria-keyshortcuts` keeps the names a
88
+ * screen reader knows.
89
+ */
90
+ keyLabels: Record<string, string>;
48
91
  /**
49
92
  * The key or chord to show, such as `mod+k`, `?`, or `/`.
50
93
  *
@@ -91,8 +134,16 @@ export declare class HelixHeadlessKbd extends HelixElement {
91
134
  private listen;
92
135
  private deafen;
93
136
  private readonly handleKeydown;
137
+ /** Focuses or presses the control `for` names, as `activate` says. */
138
+ private act;
94
139
  protected firstUpdated(changed: PropertyValues): void;
95
140
  protected render(): TemplateResult;
141
+ /**
142
+ * The chord under `caps`, a part for each key and for each `+` between two,
143
+ * so a sheet can draw a cap per key. Written with no space between, so a
144
+ * chord reads as the one label it was.
145
+ */
146
+ protected renderChord(): TemplateResult;
96
147
  }
97
148
  declare global {
98
149
  interface HTMLElementTagNameMap {
@@ -4,9 +4,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { ariaChord, chordParts, customElement, elementById, HelixElement, HelixShortcutEvent, matchesChord, onApple, printableChord, } from '@fusion.dev/helix-core';
8
- import { html } from 'lit';
7
+ import { ariaChord, chordParts, customElement, elementById, HelixElement, HelixShortcutEvent, matchesChord, onApple, printableChord, wordsConverter, } from '@fusion.dev/helix-core';
8
+ import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ import { keyNames } from '../keys.js';
10
11
  import { claimShortcut, releaseShortcut } from '../shortcut.js';
11
12
  const typing = (node) => {
12
13
  if (node instanceof HTMLTextAreaElement) {
@@ -29,48 +30,12 @@ const UNTYPED = new Set([
29
30
  'reset',
30
31
  'submit',
31
32
  ]);
32
- const APPLE = {
33
- alt: '⌥',
34
- backspace: '⌫',
35
- cmd: '⌘',
36
- ctrl: '⌃',
37
- del: '⌦',
38
- down: '↓',
39
- enter: '↵',
40
- esc: 'Esc',
41
- left: '←',
42
- meta: '⌘',
43
- mod: '⌘',
44
- opt: '⌥',
45
- right: '→',
46
- shift: '⇧',
47
- space: 'Space',
48
- tab: '⇥',
49
- up: '↑',
50
- };
51
- const ELSEWHERE = {
52
- alt: 'Alt',
53
- backspace: 'Backspace',
54
- cmd: 'Win',
55
- ctrl: 'Ctrl',
56
- del: 'Del',
57
- down: '↓',
58
- enter: 'Enter',
59
- esc: 'Esc',
60
- left: '←',
61
- meta: 'Win',
62
- mod: 'Ctrl',
63
- opt: 'Alt',
64
- right: '→',
65
- shift: 'Shift',
66
- space: 'Space',
67
- tab: 'Tab',
68
- up: '↑',
69
- };
70
33
  let HelixHeadlessKbd = class HelixHeadlessKbd extends HelixElement {
71
34
  constructor() {
72
35
  super(...arguments);
36
+ this.caps = false;
73
37
  this.for = '';
38
+ this.keyLabels = {};
74
39
  this.keys = '';
75
40
  this.handleKeydown = (event) => {
76
41
  const press = event;
@@ -87,9 +52,11 @@ let HelixHeadlessKbd = class HelixHeadlessKbd extends HelixElement {
87
52
  }
88
53
  const shortcut = new HelixShortcutEvent({ keys: this.keys });
89
54
  this.dispatchEvent(shortcut);
90
- if (!shortcut.defaultPrevented) {
91
- press.preventDefault();
55
+ if (shortcut.defaultPrevented) {
56
+ return;
92
57
  }
58
+ press.preventDefault();
59
+ this.act();
93
60
  };
94
61
  }
95
62
  connectedCallback() {
@@ -132,10 +99,7 @@ let HelixHeadlessKbd = class HelixHeadlessKbd extends HelixElement {
132
99
  }
133
100
  }
134
101
  get label() {
135
- const apple = !this.hydrating && onApple();
136
- const names = apple ? APPLE : ELSEWHERE;
137
- const parts = chordParts(this.keys).map((part) => names[part.toLowerCase()] ?? (part.length === 1 ? part.toUpperCase() : part));
138
- return parts.join(apple ? '' : '+');
102
+ return keyNames(chordParts(this.keys), !this.hydrating && onApple(), this.keyLabels ?? {});
139
103
  }
140
104
  listen() {
141
105
  if (!this.within || this.keys === '') {
@@ -152,17 +116,46 @@ let HelixHeadlessKbd = class HelixHeadlessKbd extends HelixElement {
152
116
  this.listening?.removeEventListener('keydown', this.handleKeydown);
153
117
  this.listening = undefined;
154
118
  }
119
+ act() {
120
+ const control = this.activate && this.for !== '' ? elementById(this, this.for) : null;
121
+ if (!(control instanceof HTMLElement)) {
122
+ return;
123
+ }
124
+ if (this.activate === 'click') {
125
+ control.click();
126
+ }
127
+ else {
128
+ control.focus();
129
+ }
130
+ }
155
131
  firstUpdated(changed) {
156
132
  super.firstUpdated(changed);
157
133
  this.finishHydration();
158
134
  }
159
135
  render() {
160
- return html `<kbd part="kbd">${this.keys === '' ? html `<slot></slot>` : this.label}</kbd>`;
136
+ if (this.keys === '') {
137
+ return html `<kbd part="kbd"><slot></slot></kbd>`;
138
+ }
139
+ const { keys, separator } = this.label;
140
+ return html `<kbd part="kbd">${this.caps ? this.renderChord() : keys.join(separator)}</kbd>`;
141
+ }
142
+ renderChord() {
143
+ const { keys, separator } = this.label;
144
+ return html `${keys.map((key, index) => html `${index > 0 && separator !== '' ? html `<span part="separator">${separator}</span>` : nothing}<span part="key">${key}</span>`)}`;
161
145
  }
162
146
  };
147
+ __decorate([
148
+ property()
149
+ ], HelixHeadlessKbd.prototype, "activate", void 0);
150
+ __decorate([
151
+ property({ reflect: true, type: Boolean })
152
+ ], HelixHeadlessKbd.prototype, "caps", void 0);
163
153
  __decorate([
164
154
  property()
165
155
  ], HelixHeadlessKbd.prototype, "for", void 0);
156
+ __decorate([
157
+ property({ attribute: 'key-labels', converter: wordsConverter })
158
+ ], HelixHeadlessKbd.prototype, "keyLabels", void 0);
166
159
  __decorate([
167
160
  property()
168
161
  ], HelixHeadlessKbd.prototype, "keys", void 0);