@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,20 +4,22 @@ 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, MixinControllerActive, whenHydrated, } from '@fusion.dev/helix-core';
7
+ import { customElement, fillTemplate, HelixElement, hostAria, MixinControllerActive, whenHydrated, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
- import { canReach } from '../reach.js';
10
+ import { canReach, progressOf } from '../reach.js';
11
11
  let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(HelixElement) {
12
12
  constructor() {
13
13
  super(...arguments);
14
14
  this.label = 'Steps';
15
15
  this.linear = false;
16
+ this.progressLabel = '{percent}% complete';
16
17
  this.handleSelection = (event) => {
17
18
  if (event.defaultPrevented || !this.steps.includes(event.target)) {
18
19
  return;
19
20
  }
20
- if (!this.reachable(this.steps.indexOf(event.target))) {
21
+ const index = this.steps.indexOf(event.target);
22
+ if (!this.reachable(index) || !this.valid(index)) {
21
23
  return;
22
24
  }
23
25
  this.requestActive(event.detail.value);
@@ -27,6 +29,9 @@ let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(
27
29
  this.lock();
28
30
  };
29
31
  }
32
+ get progress() {
33
+ return progressOf(this.steps);
34
+ }
30
35
  get steps() {
31
36
  return [...this.querySelectorAll(':scope > *')].filter((one) => 'current' in one);
32
37
  }
@@ -46,11 +51,20 @@ let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(
46
51
  index += delta;
47
52
  }
48
53
  const target = steps[index];
49
- if (!target || !this.reachable(index)) {
54
+ if (!target || !this.reachable(index) || !this.valid(index)) {
50
55
  return false;
51
56
  }
52
57
  return this.requestActive(target.value);
53
58
  }
59
+ valid(index) {
60
+ const from = this.steps[this.at];
61
+ if (!from || index <= this.at || !this.validate || from.optional) {
62
+ return true;
63
+ }
64
+ const valid = this.validate(from);
65
+ from.invalid = !valid;
66
+ return valid;
67
+ }
54
68
  reachable(index) {
55
69
  return !this.linear || canReach(this.steps, this.at, index);
56
70
  }
@@ -79,7 +93,10 @@ let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(
79
93
  connectedCallback() {
80
94
  super.connectedCallback();
81
95
  this.addEventListener('helix-select', this.handleSelection);
82
- this.watcher = new MutationObserver(() => this.lock());
96
+ this.watcher = new MutationObserver(() => {
97
+ this.lock();
98
+ this.requestUpdate();
99
+ });
83
100
  this.watcher.observe(this, {
84
101
  attributeFilter: ['complete', 'current', 'optional'],
85
102
  attributes: true,
@@ -92,9 +109,18 @@ let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(
92
109
  this.watcher?.disconnect();
93
110
  this.watcher = undefined;
94
111
  }
112
+ get known() {
113
+ return this.knownChildren.filter((one) => 'current' in one);
114
+ }
95
115
  willUpdate(changed) {
96
116
  super.willUpdate(changed);
97
117
  hostAria(this.internals, { label: this.label, role: 'list' });
118
+ const known = this.known;
119
+ this.toggleState('complete', known.length > 0 && known.every((step) => step.complete));
120
+ }
121
+ firstUpdated(changed) {
122
+ super.firstUpdated(changed);
123
+ this.finishHydration();
98
124
  }
99
125
  updated(changed) {
100
126
  super.updated(changed);
@@ -106,7 +132,19 @@ let HelixHeadlessSteps = class HelixHeadlessSteps extends MixinControllerActive(
106
132
  }
107
133
  }
108
134
  render() {
109
- return html `<slot @slotchange=${this.handleSlotChange}></slot>`;
135
+ const progress = progressOf(this.known);
136
+ return html `<slot @slotchange=${this.handleSlotChange}></slot>
137
+ <div
138
+ part="progress"
139
+ role="progressbar"
140
+ aria-label=${this.label}
141
+ aria-valuemin="0"
142
+ aria-valuemax="100"
143
+ aria-valuenow=${progress}
144
+ aria-valuetext=${fillTemplate(this.progressLabel, { percent: String(progress) })}
145
+ style="--steps-progress: ${progress}%"
146
+ hidden
147
+ ></div>`;
110
148
  }
111
149
  };
112
150
  __decorate([
@@ -118,6 +156,12 @@ __decorate([
118
156
  __decorate([
119
157
  property({ reflect: true })
120
158
  ], HelixHeadlessSteps.prototype, "orientation", void 0);
159
+ __decorate([
160
+ property({ attribute: 'progress-label' })
161
+ ], HelixHeadlessSteps.prototype, "progressLabel", void 0);
162
+ __decorate([
163
+ property({ attribute: false })
164
+ ], HelixHeadlessSteps.prototype, "validate", void 0);
121
165
  __decorate([
122
166
  property({ reflect: true })
123
167
  ], HelixHeadlessSteps.prototype, "variant", void 0);
@@ -45,11 +45,14 @@ import '../../button/index.js';
45
45
  * @csspart label - The step's name, which is a control.
46
46
  * @csspart label-button - The button inside the label.
47
47
  * @csspart label-live - The live region inside that button, rendered only from the first time the button is pending.
48
+ * @csspart label-spinner - The ring that button turns while it is pending.
48
49
  * @csspart label-text - The words on that button, trimmed to their capitals and baseline.
49
50
  * @csspart live - The live region that says a stage was completed, rendered from the first time one is.
50
51
  * @csspart mark - The glyph inside the marker: a tick, a dot, or an empty ring.
51
52
  * @csspart marker - The shape carrying the number or the check.
52
53
  * @csspart state - The words that describe a finished stage's button. Hidden.
54
+ *
55
+ * @cssstate invalid - The sequence's `validate` last answered that this stage is not valid.
53
56
  */
54
57
  export declare class HelixHeadlessStep extends HelixElement {
55
58
  /**
@@ -69,6 +72,11 @@ export declare class HelixHeadlessStep extends HelixElement {
69
72
  * Whether the stage is disabled, so the user cannot go to it.
70
73
  */
71
74
  disabled: boolean;
75
+ /**
76
+ * @internal Set by the sequence: whether its `validate` last answered that
77
+ * this stage is not valid. Recorded as `:state(invalid)`.
78
+ */
79
+ invalid: boolean;
72
80
  /**
73
81
  * @internal Set by a linear sequence: whether the stage is out of reach
74
82
  * until the ones before it are finished. A property, because the sequence
@@ -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, drawStatus, HelixElement, HelixSelectEvent, hostAria, StatusController, } from '@fusion.dev/helix-core';
7
+ import { customElement, drawStatus, HelixElement, HelixSelectEvent, hostAria, StatusController, slottedWords, } from '@fusion.dev/helix-core';
8
8
  import { check, circle, record } from '@fusion.dev/helix-icons';
9
9
  import { nothing } from 'lit';
10
10
  import { property } from 'lit/decorators.js';
@@ -18,6 +18,7 @@ let HelixHeadlessStep = class HelixHeadlessStep extends HelixElement {
18
18
  this.completeLabel = 'Complete';
19
19
  this.current = false;
20
20
  this.disabled = false;
21
+ this.invalid = false;
21
22
  this.locked = false;
22
23
  this.optional = false;
23
24
  this.value = '';
@@ -40,18 +41,19 @@ let HelixHeadlessStep = class HelixHeadlessStep extends HelixElement {
40
41
  willUpdate(changed) {
41
42
  super.willUpdate(changed);
42
43
  hostAria(this.internals, { role: 'listitem' });
44
+ this.toggleState('invalid', this.invalid);
43
45
  }
44
46
  updated(changed) {
45
47
  super.updated(changed);
46
48
  if (changed.get('complete') === false && this.complete) {
47
- const name = (this.textContent ?? '').replace(/\s+/g, ' ').trim();
49
+ const name = slottedWords(this, ['']);
48
50
  this.status.say(name === '' ? this.completeLabel : `${name}, ${this.completeLabel}`);
49
51
  }
50
52
  }
51
53
  renderLabel() {
52
54
  return html `<${this.tag('button')}
53
55
  part="label"
54
- exportparts="button: label-button, live: label-live, text: label-text"
56
+ exportparts="button: label-button, live: label-live, spinner: label-spinner, text: label-text"
55
57
  emphasis="ghost"
56
58
  aria-current=${this.current ? 'step' : nothing}
57
59
  aria-describedby=${this.complete ? 'state' : nothing}
@@ -84,6 +86,9 @@ __decorate([
84
86
  __decorate([
85
87
  property({ reflect: true, type: Boolean })
86
88
  ], HelixHeadlessStep.prototype, "disabled", void 0);
89
+ __decorate([
90
+ property({ attribute: false })
91
+ ], HelixHeadlessStep.prototype, "invalid", void 0);
87
92
  __decorate([
88
93
  property({ attribute: false })
89
94
  ], HelixHeadlessStep.prototype, "locked", void 0);
@@ -18,6 +18,16 @@ declare const HelixHeadlessSwitch_base: (new (...args: any[]) => import("@fusion
18
18
  * press, the same as a checkbox. The hint and the message go below the row,
19
19
  * because the switch and its label share one line.
20
20
  *
21
+ * **Keyboard.** The switch is one tab stop.
22
+ *
23
+ * | Key | What it does |
24
+ * |---|---|
25
+ * | Space | Turns the switch on or off, as a native checkbox does. |
26
+ *
27
+ * The input carries `role="switch"`, so a screen reader says "on" or "off".
28
+ * `aria-readonly` is set under `readonly`, and `aria-invalid` and
29
+ * `aria-describedby` point at the message while one shows.
30
+ *
21
31
  * @since 0.1.0
22
32
  * @status stable
23
33
  * @category forms
@@ -10,16 +10,6 @@ import { type PropertyValues, type TemplateResult } from 'lit';
10
10
  * `undefined` falls back to the field.
11
11
  */
12
12
  export type CellReader = (row: Readonly<Record<string, unknown>>) => unknown;
13
- /**
14
- * A dot path resolved against a row.
15
- *
16
- * Written here rather than taken from a library, because the whole of what is
17
- * needed is "walk the keys and stop at the first thing that is not an object".
18
- * Returns `undefined` for a path that does not resolve, which the table renders
19
- * as an empty cell: a missing key is a hole in the data and drawing `undefined`
20
- * into a table tells a reader the software is broken rather than the row is.
21
- */
22
- export declare const at: (row: Readonly<Record<string, unknown>>, path: string) => unknown;
23
13
  /**
24
14
  * The edge a column names, where it names one of the three.
25
15
  *
@@ -281,6 +271,12 @@ export declare class HelixHeadlessTableColumn extends HelixElement {
281
271
  * table that sets `gridCell`. Not a consumer's to set.
282
272
  */
283
273
  tabStop: boolean;
274
+ /**
275
+ * @internal The sort said in words on the sort button, written by the table
276
+ * on Android, where TalkBack reads no `aria-sort`. Empty elsewhere. Not a
277
+ * consumer's to set: the table's `sorted-label` holds the words.
278
+ */
279
+ sortWords: string;
284
280
  /** How wide the heading drew, for the separator to report. */
285
281
  private drawn;
286
282
  /** Where a drag of the separator started, while one is running. */
@@ -5,27 +5,11 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  var HelixHeadlessTableColumn_1;
8
- import { customElement, fillTemplate, HelixBeforeResizeEvent, HelixElement, HelixResizedEvent, hostAria, inlineStep, isRtl, requestChange, } from '@fusion.dev/helix-core';
8
+ import { customElement, fillTemplate, HelixBeforeResizeEvent, HelixElement, HelixResizedEvent, hostAria, inlineStep, isRtl, requestChange, valueAt, } from '@fusion.dev/helix-core';
9
9
  import { dotsThreeVertical } from '@fusion.dev/helix-icons';
10
10
  import { html, nothing } from 'lit';
11
11
  import { property, state } from 'lit/decorators.js';
12
12
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
13
- export const at = (row, path) => {
14
- if (path === '') {
15
- return undefined;
16
- }
17
- if (!path.includes('.')) {
18
- return row[path];
19
- }
20
- let cursor = row;
21
- for (const key of path.split('.')) {
22
- if (cursor === null || typeof cursor !== 'object') {
23
- return undefined;
24
- }
25
- cursor = cursor[key];
26
- }
27
- return cursor;
28
- };
29
13
  const EDGES = new Set(['center', 'end', 'start']);
30
14
  export const edgeOf = (align) => align && EDGES.has(align) ? align : undefined;
31
15
  let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixElement {
@@ -46,6 +30,7 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
46
30
  this.movable = false;
47
31
  this.gridCell = false;
48
32
  this.tabStop = false;
33
+ this.sortWords = '';
49
34
  this.drawn = 0;
50
35
  this.handleResizeStart = (event) => {
51
36
  if (event.button !== 0) {
@@ -96,11 +81,11 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
96
81
  }
97
82
  read(row) {
98
83
  const rendered = this.cell?.(row);
99
- return rendered === undefined ? at(row, this.field) : rendered;
84
+ return rendered === undefined ? valueAt(row, this.field) : rendered;
100
85
  }
101
86
  order(row) {
102
87
  const compared = this.compare?.(row);
103
- return compared === undefined ? at(row, this.field) : compared;
88
+ return compared === undefined ? valueAt(row, this.field) : compared;
104
89
  }
105
90
  willUpdate(changed) {
106
91
  super.willUpdate(changed);
@@ -200,7 +185,7 @@ let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixEleme
200
185
  </svg>
201
186
  </button>`
202
187
  : nothing}${this.canSort
203
- ? html `<button part="sort" type="button" tabindex=${control}><slot></slot></button>`
188
+ ? html `<button part="sort" type="button" tabindex=${control} aria-description=${this.sortWords || nothing}><slot></slot></button>`
204
189
  : html `<slot></slot>`}${this.resizable
205
190
  ? html `<span
206
191
  part="resizer"
@@ -266,6 +251,9 @@ __decorate([
266
251
  __decorate([
267
252
  state()
268
253
  ], HelixHeadlessTableColumn.prototype, "tabStop", void 0);
254
+ __decorate([
255
+ state()
256
+ ], HelixHeadlessTableColumn.prototype, "sortWords", void 0);
269
257
  __decorate([
270
258
  state()
271
259
  ], HelixHeadlessTableColumn.prototype, "drawn", void 0);
@@ -17,21 +17,42 @@ declare const HelixHeadlessTable_base: (new (...args: any[]) => import("@fusion.
17
17
  * `rowheader` for a `header` cell in a row of values. Rows are
18
18
  * `display: contents`, so their cells become items of the one grid.
19
19
  *
20
- * A column with `sortable` and a `field` sorts the rows by the text of its
21
- * cells, numbers by their value. Your markup is not reordered: the table draws
22
- * the rows in the sorted order. `helix-sort` asks first, so you can refuse it
23
- * and reorder the rows yourself.
20
+ * **Sorting.** A column with `sortable` and a `field` draws its heading as a
21
+ * button that sorts the rows by the text of its cells, numbers by their value.
22
+ * Your markup is not reordered: the table draws the rows in the sorted order.
23
+ *
24
+ * 1. Each press cycles the column through ascending, descending, and the
25
+ * order the rows were written in, which keeps a server's own ranking
26
+ * reachable.
27
+ * 2. `helix-sort` asks first, with `field:direction`, or empty for the written
28
+ * order. Refuse it to keep the order, or to sort the rows yourself and set
29
+ * `sort`.
30
+ * 3. `helix-sorted` follows once the order stands, and `sort` holds it.
31
+ * 4. The heading carries `aria-sort`, and a screen reader hears `sorted-label`
32
+ * ("Sorted by Name, ascending") or `unsorted-label` from a polite region.
33
+ *
34
+ * Tab reaches each sort button, and Enter or Space presses it.
24
35
  *
25
36
  * The `heading` slot names the table: slot a heading or a line of text into
26
37
  * it, and the table is named by its words. An `aria-label` or `aria-labelledby` on the
27
38
  * host wins over it.
28
39
  *
29
- * `selectable` adds a column of checkboxes. Each row is known by its `value`,
30
- * and `selected` holds the chosen keys, comma separated, the same shape
31
- * `DataTable` uses. The checkbox in the heading selects every row. For a grid
32
- * a reader moves through with the arrow keys, with typeahead and range
33
- * selection, use `DataTable`. To act on one row, put a link or a button in a
34
- * cell.
40
+ * **Selecting.** `selectable` adds a column of checkboxes.
41
+ *
42
+ * 1. Each row is known by its `value`, or by its place among the rows where it
43
+ * has none, and `selected` holds the chosen keys, comma separated, the same
44
+ * shape `DataTable` uses. `default-selected` is where it starts.
45
+ * 2. A row's checkbox is named by `select-row-label` ("Select {row}") with the
46
+ * words of the row's first cell. The checkbox in the heading selects every
47
+ * row, and shows a dash while only some are chosen.
48
+ * 3. `helix-select` asks first, with every key the change would leave.
49
+ * Refuse it to keep the selection. `helix-selected` follows once it stands.
50
+ * 4. A chosen row takes `:state(selected)`, and a screen reader hears
51
+ * `selected-label` ("2 selected") from a polite region.
52
+ *
53
+ * Tab reaches each checkbox, and Space ticks it. For a grid a reader moves
54
+ * through with the arrow keys, with typeahead and range selection, use
55
+ * `DataTable`. To act on one row, put a link or a button in a cell.
35
56
  *
36
57
  * The CSS custom properties listed for this component are written by it and
37
58
  * read by the stylesheet that draws it. Do not set them. Each holds a number
@@ -4,12 +4,11 @@ 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, commaList, customElement, fillTemplate, HelixElement, HelixSelectEvent, HelixSelectedEvent, HelixSortEvent, HelixSortedEvent, MixinCollection, reflectElements, requestChange, splitValues, whenHydrated, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, commaList, customElement, cycle, everyState, fillTemplate, format, HelixElement, HelixSelectEvent, HelixSelectedEvent, HelixSortEvent, HelixSortedEvent, inRowOrder, MixinCollection, onAndroid, parse, reflectElements, requestChange, sort, splitValues, toggleEvery, whenHydrated, } from '@fusion.dev/helix-core';
8
8
  import { nothing } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
10
  import { html } from 'lit/static-html.js';
11
11
  import '../../checkbox/index.js';
12
- import { cycle, format, parse, sort } from '../../data-table/root/order.js';
13
12
  import { edgeOf } from '../column/table-column.js';
14
13
  const tracksOf = (list, wanted) => {
15
14
  const words = splitValues(list, ' ');
@@ -78,17 +77,7 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
78
77
  const keys = this.chosen;
79
78
  if (root === this.renderRoot) {
80
79
  event.preventDefault();
81
- const every = this.keyed.map(({ key }) => key);
82
- const all = every.length > 0 && every.every((key) => keys.has(key));
83
- for (const key of every) {
84
- if (all) {
85
- keys.delete(key);
86
- }
87
- else {
88
- keys.add(key);
89
- }
90
- }
91
- this.requestSelected(keys);
80
+ this.requestSelected(new Set(toggleEvery(keys, this.keyed.map(({ key }) => key))));
92
81
  return;
93
82
  }
94
83
  const found = this.keyed.find(({ row }) => row.shadowRoot === root);
@@ -215,7 +204,7 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
215
204
  },
216
205
  event: (value) => new HelixSelectEvent({ value }),
217
206
  host: this,
218
- next: [...keys].join(','),
207
+ next: inRowOrder(keys, this.keyed.map(({ key }) => key)).join(','),
219
208
  });
220
209
  }
221
210
  markSelected() {
@@ -241,6 +230,7 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
241
230
  }
242
231
  markSorted() {
243
232
  const current = parse(this.sort);
233
+ const android = onAndroid();
244
234
  for (const column of this.tableColumns) {
245
235
  column.sorted =
246
236
  current && column.canSort && column.field === current.field
@@ -248,6 +238,13 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
248
238
  ? 'ascending'
249
239
  : 'descending'
250
240
  : undefined;
241
+ column.sortWords =
242
+ android && column.sorted
243
+ ? fillTemplate(this.sortedLabel, {
244
+ column: column.textContent?.trim() || column.field,
245
+ order: column.sorted === 'ascending' ? this.ascendingLabel : this.descendingLabel,
246
+ })
247
+ : '';
251
248
  }
252
249
  }
253
250
  get tableColumns() {
@@ -377,8 +374,7 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
377
374
  return nothing;
378
375
  }
379
376
  const every = this.childrenKnown ? this.keyed.map(({ key }) => key) : [];
380
- const keys = this.chosen;
381
- const count = every.filter((key) => keys.has(key)).length;
377
+ const { checked, indeterminate } = everyState(this.chosen, every);
382
378
  const checkbox = this.tag('checkbox');
383
379
  return html `<span part="select-all" role="columnheader"
384
380
  ><${checkbox}
@@ -388,8 +384,8 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
388
384
  mark-checked: checkbox-mark-checked, mark-dash: checkbox-mark-dash,
389
385
  mark-indeterminate: checkbox-mark-indeterminate"
390
386
  aria-label=${this.selectAllLabel}
391
- .checked=${every.length > 0 && count === every.length}
392
- .indeterminate=${count > 0 && count < every.length}
387
+ .checked=${checked}
388
+ .indeterminate=${indeterminate}
393
389
  ></${checkbox}
394
390
  ></span>`;
395
391
  }
@@ -13,6 +13,13 @@ import '../../checkbox/index.js';
13
13
  * In a `selectable` table the row draws a checkbox cell before its own cells,
14
14
  * and `value` is the key the table's `selected` lists it by.
15
15
  *
16
+ * **`href` makes the whole row a link**, as a row action does in React Aria's
17
+ * table: a press anywhere on the row follows it, except on a link or a control
18
+ * of the row's own, and Control, Command or Shift open it the way they open a
19
+ * link. A drag that selects text follows nothing. A row in a table is not a
20
+ * stop of its own, so put the same link in a cell, usually the row header,
21
+ * which is what the keyboard and a screen reader reach.
22
+ *
16
23
  * @since 0.1.0
17
24
  * @status stable
18
25
  * @aliases Row, TableRow
@@ -34,6 +41,7 @@ import '../../checkbox/index.js';
34
41
  * @csspart select - The cell that holds the row's checkbox, in a `selectable` table.
35
42
  * @csspart select-selected - Added to `select` while the row is selected.
36
43
  *
44
+ * @cssstate link - While the row has `href`, so a press on it follows the link.
37
45
  * @cssstate selected - While the row is selected, in a `selectable` table.
38
46
  */
39
47
  export declare class HelixHeadlessTableRow extends HelixElement {
@@ -42,6 +50,15 @@ export declare class HelixHeadlessTableRow extends HelixElement {
42
50
  * finds its columns. Not a consumer's to read or set.
43
51
  */
44
52
  readonly isTableRow = true;
53
+ /**
54
+ * The URL a press on the row follows, which makes the whole row a link.
55
+ * Empty, the default, leaves presses to the row's cells.
56
+ */
57
+ href: string;
58
+ /** The `rel` of the row's link. You set it yourself, as on an anchor. */
59
+ rel: string;
60
+ /** Where the row's link opens, such as `_blank`. */
61
+ target: string;
45
62
  /**
46
63
  * The key the table's `selected` lists this row by. Left empty, the row is
47
64
  * known by its place among the rows as written.
@@ -69,6 +86,13 @@ export declare class HelixHeadlessTableRow extends HelixElement {
69
86
  */
70
87
  alignCells(rules: CSSStyleSheet): void;
71
88
  protected willUpdate(changed: PropertyValues): void;
89
+ connectedCallback(): void;
90
+ disconnectedCallback(): void;
91
+ /**
92
+ * A press on the row follows `href`, unless it landed on a link or control
93
+ * of the row's own, or ended a drag that selected text.
94
+ */
95
+ private readonly handleClick;
72
96
  /**
73
97
  * Asks each cell to read its role again once the cells change.
74
98
  *
@@ -4,20 +4,38 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
7
+ import { customElement, followLink, HelixElement, hostAria } from '@fusion.dev/helix-core';
8
8
  import { nothing } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
10
  import { html } from 'lit/static-html.js';
11
11
  import '../../checkbox/index.js';
12
+ const PRESSABLE = 'a[href], button, input, label, select, summary, textarea, [tabindex]';
12
13
  let HelixHeadlessTableRow = class HelixHeadlessTableRow extends HelixElement {
13
14
  constructor() {
14
15
  super(...arguments);
15
16
  this.isTableRow = true;
17
+ this.href = '';
18
+ this.rel = '';
19
+ this.target = '';
16
20
  this.value = '';
17
21
  this.selectable = false;
18
22
  this.selected = false;
19
23
  this.selectLabel = '';
20
24
  this.columnRules = undefined;
25
+ this.handleClick = (event) => {
26
+ if (this.href === '' || event.button !== 0 || event.defaultPrevented) {
27
+ return;
28
+ }
29
+ const path = event.composedPath();
30
+ const inner = path.slice(0, Math.max(0, path.indexOf(this)));
31
+ if (inner.some((node) => node instanceof Element && node.matches(PRESSABLE))) {
32
+ return;
33
+ }
34
+ if (globalThis.getSelection?.()?.toString()) {
35
+ return;
36
+ }
37
+ followLink(this.ownerDocument, { href: this.href, rel: this.rel, target: this.target }, event);
38
+ };
21
39
  this.handleSlotChange = () => {
22
40
  for (const cell of this.children) {
23
41
  if ('isTableCell' in cell) {
@@ -42,6 +60,15 @@ let HelixHeadlessTableRow = class HelixHeadlessTableRow extends HelixElement {
42
60
  super.willUpdate(changed);
43
61
  hostAria(this.internals, { role: 'row' });
44
62
  this.toggleState('selected', this.selectable && this.selected);
63
+ this.toggleState('link', this.href !== '');
64
+ }
65
+ connectedCallback() {
66
+ super.connectedCallback();
67
+ this.addEventListener('click', this.handleClick);
68
+ }
69
+ disconnectedCallback() {
70
+ super.disconnectedCallback();
71
+ this.removeEventListener('click', this.handleClick);
45
72
  }
46
73
  renderSelect() {
47
74
  if (!this.selectable) {
@@ -64,6 +91,15 @@ let HelixHeadlessTableRow = class HelixHeadlessTableRow extends HelixElement {
64
91
  return html `${this.renderSelect()}<slot @slotchange=${this.handleSlotChange}></slot>`;
65
92
  }
66
93
  };
94
+ __decorate([
95
+ property()
96
+ ], HelixHeadlessTableRow.prototype, "href", void 0);
97
+ __decorate([
98
+ property()
99
+ ], HelixHeadlessTableRow.prototype, "rel", void 0);
100
+ __decorate([
101
+ property()
102
+ ], HelixHeadlessTableRow.prototype, "target", void 0);
67
103
  __decorate([
68
104
  property()
69
105
  ], HelixHeadlessTableRow.prototype, "value", void 0);
@@ -10,8 +10,10 @@ import { type PropertyValues, type TemplateResult } from 'lit';
10
10
  *
11
11
  * The host is the `tabpanel` while its tab is selected, through
12
12
  * `ElementInternals`, so the tab's `aria-controls` can reach it from the tab's
13
- * shadow root. The box inside takes the focus, for a panel with nothing
14
- * focusable in it.
13
+ * shadow root. The box inside is a tab stop only while the panel holds nothing
14
+ * focusable, as the ARIA tabs pattern and React Aria's tab panel do: Tab from
15
+ * the tab list lands on the panel's first link or control where there is one,
16
+ * and on the panel itself where there is none.
15
17
  *
16
18
  * @since 0.1.0
17
19
  * @status stable
@@ -20,7 +22,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
20
22
  *
21
23
  * @slot - The panel's content.
22
24
  *
23
- * @csspart panel - The panel container, which takes the focus.
25
+ * @csspart panel - The panel container, which takes the focus while it holds nothing focusable.
24
26
  *
25
27
  * @cssstate selected - While its tab is the one selected.
26
28
  */
@@ -46,6 +48,17 @@ export declare class HelixHeadlessTabPanel extends HelixElement {
46
48
  * Pairs the panel with the tab of the same value.
47
49
  */
48
50
  value: string;
51
+ /**
52
+ * Whether the content holds a tab stop of its own, so the panel needs none.
53
+ * False on a server, which serves the panel as a stop: it cannot look.
54
+ */
55
+ private holdsStop;
56
+ /** Re-reads the content when it changes in a way that adds or removes a stop. */
57
+ private readonly watcher;
58
+ private readonly readStops;
59
+ connectedCallback(): void;
60
+ disconnectedCallback(): void;
61
+ protected updated(changed: PropertyValues): void;
49
62
  /**
50
63
  * Mirrors the chosen state where a stylesheet can select on it.
51
64
  *