@fusion.dev/helix-headless 0.145.0 → 0.146.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/custom-elements.json +7373 -3849
  2. package/dist/accordion/item/accordion-item.d.ts +14 -0
  3. package/dist/accordion/item/accordion-item.js +16 -6
  4. package/dist/accordion/root/accordion-root.d.ts +8 -5
  5. package/dist/announcement/root/announcement-root.d.ts +3 -2
  6. package/dist/announcement/root/announcement-root.js +3 -1
  7. package/dist/app-header/root/app-header-root.d.ts +7 -2
  8. package/dist/app-header/root/app-header-root.js +9 -1
  9. package/dist/app-header/sectioning.d.ts +3 -1
  10. package/dist/app-header/sectioning.js +3 -2
  11. package/dist/avatar/group/avatar-group.d.ts +20 -14
  12. package/dist/avatar/group/avatar-group.js +17 -19
  13. package/dist/badge/root/badge-root.d.ts +3 -1
  14. package/dist/badge/root/badge-root.js +2 -2
  15. package/dist/bar-chart/root/bar-chart-root.d.ts +18 -1
  16. package/dist/bar-chart/root/bar-chart-root.js +52 -15
  17. package/dist/bar-chart/stack.d.ts +15 -0
  18. package/dist/bar-chart/stack.js +19 -0
  19. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +25 -0
  20. package/dist/breadcrumbs/root/breadcrumbs-root.js +50 -3
  21. package/dist/button/root/button-root.d.ts +26 -0
  22. package/dist/button/root/button-root.js +38 -18
  23. package/dist/button-group/root/button-group-root.d.ts +2 -1
  24. package/dist/button-group/root/button-group-root.js +5 -1
  25. package/dist/canvas/node/canvas-node.d.ts +4 -3
  26. package/dist/canvas/node/canvas-node.js +3 -2
  27. package/dist/canvas/root/canvas-root.js +2 -2
  28. package/dist/card/root/card-root.d.ts +24 -3
  29. package/dist/card/root/card-root.js +20 -8
  30. package/dist/carousel/root/carousel-root.d.ts +43 -4
  31. package/dist/carousel/root/carousel-root.js +40 -12
  32. package/dist/carousel/stops.d.ts +20 -0
  33. package/dist/carousel/stops.js +30 -0
  34. package/dist/chat/message/chat-message.js +5 -4
  35. package/dist/chat/naming.d.ts +5 -1
  36. package/dist/chat/naming.js +4 -2
  37. package/dist/chat/root/chat-root.d.ts +25 -3
  38. package/dist/chat/root/chat-root.js +22 -5
  39. package/dist/checkbox/root/checkbox-root.d.ts +20 -0
  40. package/dist/checkbox/root/checkbox-root.js +14 -1
  41. package/dist/checkbox-group/root/checkbox-group-root.d.ts +8 -2
  42. package/dist/checkbox-group/root/checkbox-group-root.js +12 -10
  43. package/dist/checkbox-group/select-all.d.ts +27 -0
  44. package/dist/checkbox-group/select-all.js +12 -0
  45. package/dist/code-block/highlight.d.ts +15 -0
  46. package/dist/code-block/highlight.js +4 -0
  47. package/dist/code-block/root/code-block-root.d.ts +49 -1
  48. package/dist/code-block/root/code-block-root.js +58 -3
  49. package/dist/color-input/root/color-input-root.d.ts +3 -0
  50. package/dist/color-input/root/color-input-root.js +6 -3
  51. package/dist/color-picker/root/color-picker-root.d.ts +33 -4
  52. package/dist/color-picker/root/color-picker-root.js +80 -21
  53. package/dist/color-picker/swatches.d.ts +12 -0
  54. package/dist/color-picker/swatches.js +26 -0
  55. package/dist/combobox/root/combobox-root.d.ts +43 -0
  56. package/dist/combobox/root/combobox-root.js +79 -15
  57. package/dist/command/root/command-root.d.ts +16 -1
  58. package/dist/command/root/command-root.js +22 -4
  59. package/dist/copy-button/root/copy-button-root.d.ts +5 -0
  60. package/dist/copy-button/root/copy-button-root.js +10 -3
  61. package/dist/data-table/index.d.ts +1 -1
  62. package/dist/data-table/index.js +1 -1
  63. package/dist/data-table/keys.d.ts +24 -0
  64. package/dist/data-table/keys.js +24 -0
  65. package/dist/data-table/root/data-table-root.d.ts +27 -18
  66. package/dist/data-table/root/data-table-root.js +20 -52
  67. package/dist/data-table/tree.d.ts +16 -1
  68. package/dist/data-table/tree.js +2 -3
  69. package/dist/date-input/root/date-input-root.d.ts +3 -1
  70. package/dist/date-input/root/date-input-root.js +18 -7
  71. package/dist/date-picker/root/date-picker-root.js +12 -6
  72. package/dist/dialog/description.js +15 -1
  73. package/dist/dialog/root/dialog-root.d.ts +8 -2
  74. package/dist/dialog/root/dialog-root.js +16 -1
  75. package/dist/divider/root/divider-root.d.ts +3 -0
  76. package/dist/divider/root/divider-root.js +2 -1
  77. package/dist/donut-chart/root/donut-chart-root.d.ts +31 -0
  78. package/dist/donut-chart/root/donut-chart-root.js +48 -1
  79. package/dist/drawer/reveal.d.ts +8 -0
  80. package/dist/drawer/reveal.js +1 -0
  81. package/dist/drawer/root/drawer-root.d.ts +59 -0
  82. package/dist/drawer/root/drawer-root.js +63 -4
  83. package/dist/drilldown/item/drilldown-item.js +1 -1
  84. package/dist/drilldown/root/drilldown-root.d.ts +21 -3
  85. package/dist/drilldown/root/drilldown-root.js +21 -3
  86. package/dist/element-events.generated.js +31 -5
  87. package/dist/empty/root/empty-root.d.ts +3 -1
  88. package/dist/empty/root/empty-root.js +3 -2
  89. package/dist/file-input/root/file-input-root.d.ts +69 -6
  90. package/dist/file-input/root/file-input-root.js +82 -19
  91. package/dist/file-input/screen.d.ts +2 -1
  92. package/dist/filter-input/menu/filter-menu.d.ts +2 -0
  93. package/dist/filter-input/menu/filter-menu.js +12 -4
  94. package/dist/filter-input/root/filter-input-root.d.ts +30 -6
  95. package/dist/filter-input/root/filter-input-root.js +1 -1
  96. package/dist/filter-input/suggest.d.ts +28 -3
  97. package/dist/filter-input/suggest.js +18 -8
  98. package/dist/format-date/root/format-date-root.d.ts +9 -16
  99. package/dist/format-date/root/format-date-root.js +10 -27
  100. package/dist/heatmap/root/heatmap-root.d.ts +24 -13
  101. package/dist/heatmap/root/heatmap-root.js +34 -12
  102. package/dist/icon/root/icon-root.d.ts +12 -1
  103. package/dist/icon/root/icon-root.js +21 -10
  104. package/dist/icon/settle.d.ts +7 -0
  105. package/dist/icon/settle.js +10 -0
  106. package/dist/icon-button/root/icon-button-root.d.ts +2 -0
  107. package/dist/image/root/image-root.d.ts +5 -1
  108. package/dist/image/root/image-root.js +1 -1
  109. package/dist/input/root/input-root.d.ts +12 -2
  110. package/dist/input/root/input-root.js +11 -2
  111. package/dist/kbd/root/kbd-root.d.ts +35 -1
  112. package/dist/kbd/root/kbd-root.js +23 -4
  113. package/dist/legend/root/legend-root.d.ts +55 -8
  114. package/dist/legend/root/legend-root.js +55 -13
  115. package/dist/lightbox/root/lightbox-root.d.ts +49 -6
  116. package/dist/lightbox/root/lightbox-root.js +86 -19
  117. package/dist/lightbox/zoom-controller.d.ts +59 -0
  118. package/dist/lightbox/zoom-controller.js +128 -0
  119. package/dist/lightbox/zoom.d.ts +22 -0
  120. package/dist/lightbox/zoom.js +16 -0
  121. package/dist/line-chart/root/line-chart-root.d.ts +22 -1
  122. package/dist/line-chart/root/line-chart-root.js +21 -1
  123. package/dist/list/item/list-item.d.ts +2 -0
  124. package/dist/list/item/list-item.js +11 -2
  125. package/dist/list/root/list-root.d.ts +62 -13
  126. package/dist/list/root/list-root.js +70 -13
  127. package/dist/list/selection.d.ts +37 -7
  128. package/dist/list/selection.js +16 -7
  129. package/dist/listbox/root/listbox-root.d.ts +37 -1
  130. package/dist/listbox/root/listbox-root.js +49 -3
  131. package/dist/loader/busy.d.ts +10 -0
  132. package/dist/loader/busy.js +11 -0
  133. package/dist/loader/root/loader-root.d.ts +9 -2
  134. package/dist/loader/root/loader-root.js +23 -3
  135. package/dist/megamenu/root/megamenu-root.d.ts +51 -10
  136. package/dist/megamenu/root/megamenu-root.js +76 -5
  137. package/dist/menu/item/menu-item.d.ts +51 -2
  138. package/dist/menu/item/menu-item.js +47 -23
  139. package/dist/menu/root/menu-root.d.ts +14 -0
  140. package/dist/menu/root/menu-root.js +2 -2
  141. package/dist/meter/root/meter-root.d.ts +20 -1
  142. package/dist/meter/root/meter-root.js +11 -15
  143. package/dist/navigation/root/navigation-root.d.ts +2 -1
  144. package/dist/navigation/root/navigation-root.js +2 -2
  145. package/dist/notifications/root/notifications-root.d.ts +10 -3
  146. package/dist/notifications/root/notifications-root.js +19 -7
  147. package/dist/number-input/root/number-input-root.d.ts +17 -8
  148. package/dist/number-input/root/number-input-root.js +2 -7
  149. package/dist/object-inspector/root/object-inspector-root.d.ts +75 -27
  150. package/dist/object-inspector/root/object-inspector-root.js +117 -76
  151. package/dist/object-inspector/rows.d.ts +18 -0
  152. package/dist/object-inspector/rows.js +33 -0
  153. package/dist/option/root/option-root.d.ts +5 -3
  154. package/dist/outline/root/outline-root.d.ts +18 -0
  155. package/dist/outline/root/outline-root.js +23 -5
  156. package/dist/pagination/size/pagination-size.d.ts +1 -0
  157. package/dist/pagination/size/pagination-size.js +1 -1
  158. package/dist/pin-input/code.d.ts +10 -0
  159. package/dist/pin-input/code.js +13 -0
  160. package/dist/pin-input/root/pin-input-root.d.ts +25 -1
  161. package/dist/pin-input/root/pin-input-root.js +10 -11
  162. package/dist/popover/hide-outside.d.ts +14 -0
  163. package/dist/popover/hide-outside.js +41 -0
  164. package/dist/popover/root/popover-root.d.ts +57 -7
  165. package/dist/popover/root/popover-root.js +58 -3
  166. package/dist/progress/root/progress-root.d.ts +20 -0
  167. package/dist/progress/root/progress-root.js +15 -15
  168. package/dist/qr-code/export.d.ts +26 -1
  169. package/dist/qr-code/export.js +14 -0
  170. package/dist/qr-code/root/qr-code-root.d.ts +19 -5
  171. package/dist/qr-code/root/qr-code-root.js +58 -9
  172. package/dist/quote/marks.d.ts +8 -0
  173. package/dist/quote/marks.js +5 -0
  174. package/dist/quote/root/quote-root.d.ts +14 -2
  175. package/dist/quote/root/quote-root.js +23 -1
  176. package/dist/radio/root/radio-root.d.ts +6 -2
  177. package/dist/radio/root/radio-root.js +6 -1
  178. package/dist/rating/root/rating-root.d.ts +9 -4
  179. package/dist/rating/root/rating-root.js +31 -7
  180. package/dist/rating/steps.d.ts +7 -0
  181. package/dist/rating/steps.js +9 -0
  182. package/dist/scatter-chart/fit.d.ts +15 -0
  183. package/dist/scatter-chart/fit.js +35 -0
  184. package/dist/scatter-chart/root/scatter-chart-root.d.ts +21 -1
  185. package/dist/scatter-chart/root/scatter-chart-root.js +30 -17
  186. package/dist/scroll-area/root/scroll-area-root.d.ts +22 -51
  187. package/dist/scroll-area/root/scroll-area-root.js +57 -173
  188. package/dist/scroll-area/scrollbar-controller.d.ts +111 -0
  189. package/dist/scroll-area/scrollbar-controller.js +172 -0
  190. package/dist/scroll-area/scrollbar.d.ts +27 -0
  191. package/dist/scroll-area/scrollbar.js +9 -0
  192. package/dist/select/root/select-root.d.ts +15 -0
  193. package/dist/select/root/select-root.js +18 -6
  194. package/dist/skeleton/root/skeleton-root.d.ts +3 -0
  195. package/dist/skeleton/root/skeleton-root.js +4 -2
  196. package/dist/skip-link/root/skip-link-root.js +2 -2
  197. package/dist/slider/root/slider-root.d.ts +41 -4
  198. package/dist/slider/root/slider-root.js +23 -3
  199. package/dist/sparkline/readings.d.ts +18 -0
  200. package/dist/sparkline/readings.js +19 -0
  201. package/dist/sparkline/root/sparkline-root.d.ts +78 -7
  202. package/dist/sparkline/root/sparkline-root.js +118 -23
  203. package/dist/speed-dial/root/speed-dial-root.js +2 -2
  204. package/dist/splitter/root/splitter-root.d.ts +7 -12
  205. package/dist/splitter/root/splitter-root.js +209 -204
  206. package/dist/stat/root/stat-root.d.ts +14 -5
  207. package/dist/stat/root/stat-root.js +21 -5
  208. package/dist/steps/reach.d.ts +5 -0
  209. package/dist/steps/reach.js +3 -0
  210. package/dist/steps/root/steps-root.d.ts +49 -3
  211. package/dist/steps/root/steps-root.js +44 -5
  212. package/dist/steps/step/step.d.ts +7 -0
  213. package/dist/steps/step/step.js +7 -2
  214. package/dist/switch/root/switch-root.d.ts +10 -0
  215. package/dist/table/column/table-column.d.ts +0 -10
  216. package/dist/table/column/table-column.js +3 -19
  217. package/dist/table/root/table-root.d.ts +31 -10
  218. package/dist/table/root/table-root.js +2 -13
  219. package/dist/tabs/panel/tab-panel.d.ts +16 -3
  220. package/dist/tabs/panel/tab-panel.js +34 -5
  221. package/dist/tabs/root/tabs-root.d.ts +12 -0
  222. package/dist/tabs/root/tabs-root.js +1 -1
  223. package/dist/tabs/tab/tab.d.ts +5 -0
  224. package/dist/tabs/tab/tab.js +5 -2
  225. package/dist/tag/group/tag-group.d.ts +31 -4
  226. package/dist/tag/group/tag-group.js +46 -7
  227. package/dist/tag/root/tag-root.js +9 -2
  228. package/dist/textarea/root/textarea-root.d.ts +28 -1
  229. package/dist/textarea/root/textarea-root.js +40 -1
  230. package/dist/time-input/root/time-input-root.d.ts +5 -1
  231. package/dist/time-input/root/time-input-root.js +16 -8
  232. package/dist/time-picker/root/time-picker-root.d.ts +18 -4
  233. package/dist/time-picker/root/time-picker-root.js +7 -10
  234. package/dist/time-picker/wheel-name.d.ts +9 -0
  235. package/dist/time-picker/wheel-name.js +15 -0
  236. package/dist/timeline/group/timeline-group.js +2 -2
  237. package/dist/toast/item/toast-item.d.ts +14 -1
  238. package/dist/toast/item/toast-item.js +22 -5
  239. package/dist/toast/root/toast-root.d.ts +6 -0
  240. package/dist/toast/root/toast-root.js +16 -1
  241. package/dist/toggle/group/toggle-group.d.ts +24 -3
  242. package/dist/toggle/group/toggle-group.js +34 -5
  243. package/dist/tooltip/root/tooltip-root.d.ts +13 -2
  244. package/dist/tooltip/root/tooltip-root.js +9 -1
  245. package/dist/tour/back.d.ts +10 -0
  246. package/dist/tour/back.js +8 -0
  247. package/dist/tour/root/tour-root.d.ts +30 -2
  248. package/dist/tour/root/tour-root.js +34 -8
  249. package/dist/tree/item/tree-item.d.ts +7 -3
  250. package/dist/tree/item/tree-item.js +3 -0
  251. package/dist/tree/root/tree-root.d.ts +24 -3
  252. package/dist/tree/root/tree-root.js +32 -13
  253. package/dist/tree/selection.js +2 -15
  254. package/dist/trend/root/trend-root.d.ts +43 -18
  255. package/dist/trend/root/trend-root.js +31 -6
  256. package/dist/video/media-events.d.ts +13 -18
  257. package/dist/video/media-events.js +1 -5
  258. package/dist/video/root/video-root.d.ts +18 -5
  259. package/dist/video/root/video-root.js +19 -10
  260. package/dist/video-playlist/menu/video-playlist-menu.d.ts +2 -0
  261. package/dist/video-playlist/menu/video-playlist-menu.js +2 -1
  262. package/dist/video-playlist/root/video-playlist-root.d.ts +7 -1
  263. package/dist/virtual-list/fill.d.ts +0 -8
  264. package/dist/virtual-list/fill.js +1 -17
  265. package/dist/virtual-list/plan.d.ts +49 -0
  266. package/dist/virtual-list/plan.js +16 -0
  267. package/dist/virtual-list/root/virtual-list-root.d.ts +114 -13
  268. package/dist/virtual-list/root/virtual-list-root.js +183 -40
  269. package/lint.json +1 -1
  270. package/package.json +8 -8
  271. package/types/jsx.d.ts +4577 -835
  272. package/types/vue.d.ts +926 -168
  273. package/dist/chat/relative-clock.d.ts +0 -39
  274. package/dist/chat/relative-clock.js +0 -31
  275. package/dist/data-table/root/order.d.ts +0 -141
  276. package/dist/data-table/root/order.js +0 -76
  277. package/dist/tag/selection.d.ts +0 -10
  278. package/dist/tag/selection.js +0 -12
@@ -35,6 +35,12 @@ export interface BreadcrumbItem {
35
35
  * array of `{ label, href }`, drawn as crumbs in order, the last one as the
36
36
  * current page. Slotted crumbs follow them. Use one way or the other in a trail.
37
37
  *
38
+ * With `max-items`, a trail drawn from `items` that is longer folds its middle
39
+ * into one crumb: the first crumb, a button, then the last `max-items` less one.
40
+ * The button is named by `expand-label` and shows the whole trail, moving focus
41
+ * to the first crumb it brought back. A new `items` folds again. Slotted crumbs
42
+ * do not fold; write the folded crumb where the gap should be.
43
+ *
38
44
  * @since 0.1.0
39
45
  * @status stable
40
46
  * @category navigation
@@ -45,13 +51,20 @@ export interface BreadcrumbItem {
45
51
  * the crumb that holds the folded items where the gap should appear.
46
52
  *
47
53
  * @csspart crumb - Each crumb drawn from `items`.
54
+ * @csspart crumb-collapsed - The crumb that holds the folded middle of a trail longer than `max-items`.
48
55
  * @csspart crumb-current - The crumb drawn from `items` for the current page.
49
56
  * @csspart crumb-link - The link, or the current page's words, of a crumb drawn from `items`.
50
57
  * @csspart crumb-separator - The separator before a crumb drawn from `items`.
51
58
  * @csspart crumb-separator-mark - The chevron before a crumb drawn from `items`.
59
+ * @csspart expand - The button in the folded crumb that shows the whole trail.
52
60
  * @csspart list - The ordered list.
53
61
  */
54
62
  export declare class HelixHeadlessBreadcrumbs extends HelixElement {
63
+ /**
64
+ * The name of the button that shows a folded trail's hidden crumbs. `{count}`
65
+ * is replaced by how many it shows. Translate it with the page.
66
+ */
67
+ expandLabel: string;
55
68
  /**
56
69
  * The trail as data, drawn as crumbs before any you slot. The last item is the
57
70
  * current page.
@@ -65,7 +78,19 @@ export declare class HelixHeadlessBreadcrumbs extends HelixElement {
65
78
  * wins over it.
66
79
  */
67
80
  label: string;
81
+ /**
82
+ * The most crumbs a trail drawn from `items` shows before it folds its middle
83
+ * into one, counting the first and the last. Unset, it never folds. At least
84
+ * 2, so the first crumb and the current page always show.
85
+ */
86
+ maxItems?: number;
87
+ /** Whether a reader has asked to see the whole of a folded trail. */
88
+ private expanded;
89
+ /** Shows the whole trail and moves focus to the first crumb it brought back. */
90
+ private readonly expand;
68
91
  protected willUpdate(changed: PropertyValues): void;
92
+ /** How many crumbs drawn from `items` are folded away, or 0. */
93
+ private get folded();
69
94
  /** The crumbs `items` describes, each a crumb of this tier. */
70
95
  protected renderItems(): TemplateResult | typeof nothing;
71
96
  protected render(): TemplateResult;
@@ -6,19 +6,36 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
6
6
  };
7
7
  import { customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
8
8
  import { nothing } from 'lit';
9
- import { property } from 'lit/decorators.js';
9
+ import { property, state } from 'lit/decorators.js';
10
10
  import { repeat } from 'lit/directives/repeat.js';
11
11
  import { html } from 'lit/static-html.js';
12
12
  import '../breadcrumb/breadcrumb.js';
13
13
  let HelixHeadlessBreadcrumbs = class HelixHeadlessBreadcrumbs extends HelixElement {
14
14
  constructor() {
15
15
  super(...arguments);
16
+ this.expandLabel = 'Show {count} more';
16
17
  this.items = [];
17
18
  this.label = 'Breadcrumb';
19
+ this.expanded = false;
20
+ this.expand = () => {
21
+ this.expanded = true;
22
+ this.updateComplete.then(() => {
23
+ const crumb = this.renderRoot.querySelectorAll('[part~="crumb"]')[1];
24
+ crumb?.shadowRoot?.querySelector('a, [part="link"]')?.focus();
25
+ });
26
+ };
18
27
  }
19
28
  willUpdate(changed) {
20
29
  super.willUpdate(changed);
21
30
  hostAria(this.internals, { label: this.label, role: 'navigation' });
31
+ if (changed.has('items') && changed.get('items') !== undefined) {
32
+ this.expanded = false;
33
+ }
34
+ }
35
+ get folded() {
36
+ const most = this.maxItems ?? 0;
37
+ const count = this.items.length;
38
+ return !this.expanded && most >= 2 && count > most ? count - most : 0;
22
39
  }
23
40
  renderItems() {
24
41
  if (this.items.length === 0) {
@@ -26,7 +43,27 @@ let HelixHeadlessBreadcrumbs = class HelixHeadlessBreadcrumbs extends HelixEleme
26
43
  }
27
44
  const crumb = this.tag('breadcrumb');
28
45
  const last = this.items.length - 1;
29
- return html `${repeat(this.items, (item, index) => html `<${crumb}
46
+ const folded = this.folded;
47
+ const shown = this.items
48
+ .map((item, index) => ({ index, item }))
49
+ .filter(({ index }) => folded === 0 || index === 0 || index > folded);
50
+ const fold = folded === 0
51
+ ? nothing
52
+ : html `<${crumb}
53
+ part="crumb crumb-collapsed"
54
+ exportparts="link: crumb-link, separator: crumb-separator, separator-mark: crumb-separator-mark"
55
+ ><button
56
+ part="expand"
57
+ type="button"
58
+ aria-label=${this.expandLabel.replace('{count}', String(folded))}
59
+ @click=${this.expand}
60
+ >
61
+ …
62
+ </button></${crumb}
63
+ >`;
64
+ const first = shown.slice(0, 1);
65
+ const rest = shown.slice(1);
66
+ const draw = ({ index, item }) => html `<${crumb}
30
67
  part="crumb${index === last ? ' crumb-current' : ''}"
31
68
  exportparts="link: crumb-link, separator: crumb-separator, separator-mark: crumb-separator-mark"
32
69
  href=${index === last ? nothing : (item.href ?? nothing)}
@@ -34,7 +71,8 @@ let HelixHeadlessBreadcrumbs = class HelixHeadlessBreadcrumbs extends HelixEleme
34
71
  target=${item.target ?? nothing}
35
72
  ?current=${index === last}
36
73
  >${item.label}</${crumb}
37
- >`)}`;
74
+ >`;
75
+ return html `${repeat(first, ({ index }) => index, draw)}${fold}${repeat(rest, ({ index }) => index, draw)}`;
38
76
  }
39
77
  render() {
40
78
  return html `<ol part="list" role="list">
@@ -42,12 +80,21 @@ let HelixHeadlessBreadcrumbs = class HelixHeadlessBreadcrumbs extends HelixEleme
42
80
  </ol>`;
43
81
  }
44
82
  };
83
+ __decorate([
84
+ property({ attribute: 'expand-label' })
85
+ ], HelixHeadlessBreadcrumbs.prototype, "expandLabel", void 0);
45
86
  __decorate([
46
87
  property({ attribute: false })
47
88
  ], HelixHeadlessBreadcrumbs.prototype, "items", void 0);
48
89
  __decorate([
49
90
  property()
50
91
  ], HelixHeadlessBreadcrumbs.prototype, "label", void 0);
92
+ __decorate([
93
+ property({ attribute: 'max-items', type: Number })
94
+ ], HelixHeadlessBreadcrumbs.prototype, "maxItems", void 0);
95
+ __decorate([
96
+ state()
97
+ ], HelixHeadlessBreadcrumbs.prototype, "expanded", void 0);
51
98
  HelixHeadlessBreadcrumbs = __decorate([
52
99
  customElement('helix-headless-breadcrumbs')
53
100
  ], HelixHeadlessBreadcrumbs);
@@ -32,6 +32,15 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
32
32
  * Set `pending` while the action a press started is still running. The button
33
33
  * keeps focus and refuses presses, and a reader on it hears `pending-label`.
34
34
  *
35
+ * Every press that acts sends `helix-press` with what pressed it in
36
+ * `detail.pointerType`: `mouse`, `pen`, `touch`, `keyboard`, or `virtual` for
37
+ * a screen reader's press or a script's `click()`, as React Aria's `onPress`
38
+ * does. It is sent once the press has done its own work, before `click`
39
+ * reaches listeners on the element, and never for a disabled or pending
40
+ * button.
41
+ *
42
+ * **Keyboard.** Enter and Space press the button, as on a native one.
43
+ *
35
44
  * @since 0.1.0
36
45
  * @status stable
37
46
  * @category actions
@@ -41,6 +50,8 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
41
50
  * @slot end - Content after the label.
42
51
  * @slot start - Content before the label, usually an icon.
43
52
  *
53
+ * @event {HelixPressEvent} helix-press - Fired when a press acts, with `detail.pointerType` saying what pressed the button.
54
+ *
44
55
  * @csspart button - The inner control.
45
56
  * @csspart live - The live region that says `pending-label` when the button becomes pending under focus. It is rendered from the first time the button is pending, and the styled button clips it out of view.
46
57
  * @csspart text - The button's words, which the styled button trims to their capitals and baseline so the letters sit at the middle in any font.
@@ -214,7 +225,22 @@ export declare class HelixHeadlessButton extends HelixFormElement {
214
225
  protected renderLive(): TemplateResult | typeof nothing;
215
226
  /** Moves focus to the inner control, so the host is never the focus target. */
216
227
  static shadowRootOptions: ShadowRootInit;
228
+ /** What the control saw before a click that the click may not carry. */
229
+ private recent;
230
+ /**
231
+ * @internal Records what starts a press, a pointer's kind or Enter or Space,
232
+ * for `helix-press`. Bound on the inner control by this render and by any
233
+ * subclass that draws its own.
234
+ */
235
+ protected readonly notePress: (event: Event) => void;
236
+ /**
237
+ * @internal Sends `helix-press` for a click that acted, with what pressed it,
238
+ * and forgets what started it.
239
+ */
240
+ protected announcePress(click: Event): void;
217
241
  private readonly handleClick;
242
+ /** What a press does: sends the command, and submits or resets the form. */
243
+ private act;
218
244
  /**
219
245
  * What activating the button does to its form.
220
246
  */
@@ -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, drawStatus, elementById, HelixFallbackCommandEvent, HelixFormElement, StatusController, supportsInvokers, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, defaultButton, drawStatus, elementById, HelixFallbackCommandEvent, HelixFormElement, HelixPressEvent, pressType, StatusController, submitsOnEnter, supportsInvokers, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
@@ -27,27 +27,23 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
27
27
  this.pending = false;
28
28
  this.pendingLabel = 'Loading';
29
29
  this.status = new StatusController(this);
30
+ this.recent = {};
31
+ this.notePress = (event) => {
32
+ if (event.type === 'pointerdown') {
33
+ this.recent = { pointer: event.pointerType };
34
+ }
35
+ else if (event.key === 'Enter' || event.key === ' ') {
36
+ this.recent = { key: true };
37
+ }
38
+ };
30
39
  this.handleClick = (event) => {
31
40
  if (this.pending) {
32
41
  event.preventDefault();
33
42
  event.stopImmediatePropagation();
34
43
  return;
35
44
  }
36
- this.linkCommand();
37
- this.sendCommand();
38
- if (this.type === 'button') {
39
- return;
40
- }
41
- const { form } = this;
42
- if (!form) {
43
- return;
44
- }
45
- if (this.type === 'submit') {
46
- this.submit(form);
47
- }
48
- else {
49
- form.reset();
50
- }
45
+ this.act();
46
+ this.announcePress(event);
51
47
  };
52
48
  this.type = 'button';
53
49
  this.value = '';
@@ -57,8 +53,8 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
57
53
  if (event.key !== 'Enter' ||
58
54
  event.defaultPrevented ||
59
55
  !form ||
60
- !HelixFormElement.submitsOnEnter(event.composedPath()[0], form) ||
61
- HelixFormElement.defaultButton(form) !== this) {
56
+ !submitsOnEnter(event.composedPath()[0], form) ||
57
+ defaultButton(form) !== this) {
62
58
  return;
63
59
  }
64
60
  event.preventDefault();
@@ -84,6 +80,28 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
84
80
  ...HelixFormElement.shadowRootOptions,
85
81
  delegatesFocus: true,
86
82
  }; }
83
+ announcePress(click) {
84
+ const pointerType = pressType(click, this.recent);
85
+ this.recent = {};
86
+ this.dispatchEvent(new HelixPressEvent({ pointerType }));
87
+ }
88
+ act() {
89
+ this.linkCommand();
90
+ this.sendCommand();
91
+ if (this.type === 'button') {
92
+ return;
93
+ }
94
+ const { form } = this;
95
+ if (!form) {
96
+ return;
97
+ }
98
+ if (this.type === 'submit') {
99
+ this.submit(form);
100
+ }
101
+ else {
102
+ form.reset();
103
+ }
104
+ }
87
105
  submit(form) {
88
106
  const undo = [];
89
107
  const override = (attribute, value) => {
@@ -201,6 +219,8 @@ let HelixHeadlessButton = class HelixHeadlessButton extends HelixFormElement {
201
219
  tabindex=${stop}
202
220
  ?disabled=${this.isDisabled}
203
221
  @click=${this.handleClick}
222
+ @keydown=${this.notePress}
223
+ @pointerdown=${this.notePress}
204
224
  >
205
225
  ${label}
206
226
  </button>${this.renderLive()}`;
@@ -6,7 +6,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
6
6
  * @description
7
7
  * Sets `role="group"` on the host through internals, and `label` names the
8
8
  * group. Without a name, a screen reader announces the buttons as separate
9
- * controls.
9
+ * controls, and a development build warns once with the kind `missing-name`.
10
10
  *
11
11
  * The group does not manage focus, so each button keeps its own tab stop. For
12
12
  * one tab stop with arrow keys between the buttons, the APG toolbar pattern,
@@ -52,6 +52,7 @@ export declare class HelixHeadlessButtonGroup extends HelixElement {
52
52
  */
53
53
  orientation?: 'horizontal' | 'vertical';
54
54
  protected willUpdate(changed: PropertyValues): void;
55
+ protected firstUpdated(changed: PropertyValues): void;
55
56
  protected render(): TemplateResult;
56
57
  }
57
58
  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 { customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
7
+ import { auditName, customElement, HelixElement, hostAria } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  let HelixHeadlessButtonGroup = class HelixHeadlessButtonGroup extends HelixElement {
@@ -16,6 +16,10 @@ let HelixHeadlessButtonGroup = class HelixHeadlessButtonGroup extends HelixEleme
16
16
  super.willUpdate(changed);
17
17
  hostAria(this.internals, { label: this.label, role: 'group' });
18
18
  }
19
+ firstUpdated(changed) {
20
+ super.firstUpdated(changed);
21
+ auditName(this, () => null, 'Give it a `label`, or an `aria-label` that says what the buttons are for.', () => this.label !== '');
22
+ }
19
23
  render() {
20
24
  return html `<slot></slot>`;
21
25
  }
@@ -93,9 +93,10 @@ export declare class HelixHeadlessCanvasNode extends HelixElement {
93
93
  * The card's name as text. A group shows it, and another card's connections
94
94
  * read it out.
95
95
  *
96
- * A group needs one because it has no text of its own; a card that has text
97
- * is named by it, and one holding a picture or a figure is named by nothing
98
- * short enough to read out in another card's connections.
96
+ * A group needs one because it has no text of its own. A card is named by
97
+ * it where it is set, and by its content where it is not, so a screen reader
98
+ * moving between cards hears each one's name. Set it on a card holding a
99
+ * picture or a figure, which has no words short enough to name it.
99
100
  */
100
101
  label: string;
101
102
  /** Where the card was placed, kept in its own shadow root. */
@@ -73,12 +73,13 @@ let HelixHeadlessCanvasNode = class HelixHeadlessCanvasNode extends HelixElement
73
73
  : nothing}<div
74
74
  part="node"
75
75
  aria-describedby=${this.meaning || this.links ? 'about' : nothing}
76
- aria-label=${this.group ? this.label || nothing : nothing}
76
+ aria-label=${this.label || nothing}
77
+ aria-labelledby=${this.label || this.group ? nothing : 'content'}
77
78
  aria-keyshortcuts=${this.connectable ? 'Enter F2 Space Shift+ArrowRight Shift+ArrowDown Alt+ArrowRight Alt+ArrowDown C Delete' : nothing}
78
79
  role=${this.group ? 'group' : 'article'}
79
80
  tabindex=${this.current ? '0' : '-1'}
80
81
  >
81
- <slot></slot>
82
+ <slot id="content"></slot>
82
83
  <slot name="description"></slot>
83
84
  <span id="about" hidden>${[this.meaning, this.links].filter(Boolean).join(', ')}</span>
84
85
  </div>
@@ -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 { capturePointer, customElement, fillTemplate, HelixBeforeMoveEvent, HelixBeforeReconnectEvent, HelixBeforeRelabelEvent, HelixCanvasEditEvent, HelixCanvasPanEvent, HelixCanvasViewEvent, HelixCanvasZoomEvent, HelixConnectEvent, HelixElement, HelixMoveEvent, HelixReconnectEvent, HelixRelabelEvent, HelixRemoveEvent, HelixSelectEvent, hostAria, inlineStep, isRtl, MixinViewport, } from '@fusion.dev/helix-core';
7
+ import { capturePointer, customElement, fillTemplate, HelixBeforeMoveEvent, HelixBeforeReconnectEvent, HelixBeforeRelabelEvent, HelixCanvasEditEvent, HelixCanvasPanEvent, HelixCanvasViewEvent, HelixCanvasZoomEvent, HelixConnectEvent, HelixElement, HelixMoveEvent, HelixReconnectEvent, HelixRelabelEvent, HelixRemoveEvent, HelixSelectEvent, hostAria, inlineStep, isRtl, MixinViewport, wordsConverter, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing, svg } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
10
  import { HelixHeadlessCanvasEdge } from '../edge/canvas-edge.js';
@@ -2043,7 +2043,7 @@ __decorate([
2043
2043
  property({ attribute: 'stopped-label' })
2044
2044
  ], HelixHeadlessCanvas.prototype, "stoppedLabel", void 0);
2045
2045
  __decorate([
2046
- property({ attribute: 'tone-labels', type: Object })
2046
+ property({ attribute: 'tone-labels', converter: wordsConverter })
2047
2047
  ], HelixHeadlessCanvas.prototype, "toneLabels", void 0);
2048
2048
  __decorate([
2049
2049
  state()
@@ -12,12 +12,19 @@ import { type PropertyValues, type TemplateResult } from 'lit';
12
12
  * the grid, so you style `Card` directly and there is no wrapper part to reach
13
13
  * through with `::part`.
14
14
  *
15
- * Name the card with `aria-label` or `aria-labelledby`. These are the only
16
- * names that work with server rendering, because reading a title from the light
17
- * DOM needs a DOM, and the server has none. **A named card is a group**, so a
15
+ * Name the card with `label`, as a Stat Group is named, or with `aria-label`
16
+ * or `aria-labelledby`. These are the only names that work with server
17
+ * rendering, because reading a title from the light DOM needs a DOM, and the
18
+ * server has none. `label` is set through `ElementInternals`, so it writes no
19
+ * attribute onto the card. **A named card is a group**, so a
18
20
  * reader entering it hears its name; an unnamed one has no role, since a group
19
21
  * with no name only adds "group" to what a reader says.
20
22
  *
23
+ * Each region's slot is a part of the same name, `body` for the main content,
24
+ * as Web Awesome's card names its regions. A slot draws no box, so a part
25
+ * passes inherited properties to what is slotted, and a page wanting a box
26
+ * there gives it one with `display`.
27
+ *
21
28
  * `header-actions` and `footer-actions` hold controls at the end of the
22
29
  * header's and the footer's line, as Web Awesome's card does. While one holds
23
30
  * something, its line is a `header-row` or `footer-row` part; otherwise there
@@ -37,10 +44,24 @@ import { type PropertyValues, type TemplateResult } from 'lit';
37
44
  * @slot header-actions - Controls for the whole card at the end of the header's line, such as a menu.
38
45
  * @slot media - Image, video, or chart that runs edge to edge, outside the inset.
39
46
  *
47
+ * @csspart body - The slot the main content arrives through. A slot draws no box, so it passes inherited properties, such as color and font, to the content; `display: block` gives it one.
48
+ * @csspart footer - The slot the footer arrives through, drawing no box, as `body` does.
49
+ * @csspart footer-actions - The slot the footer's controls arrive through, drawing no box, as `body` does.
40
50
  * @csspart footer-row - The line holding `footer` and `footer-actions`, drawn only while `footer-actions` holds something.
51
+ * @csspart header - The slot the header arrives through, drawing no box, as `body` does.
52
+ * @csspart header-actions - The slot the header's controls arrive through, drawing no box, as `body` does.
41
53
  * @csspart header-row - The line holding `header` and `header-actions`, drawn only while `header-actions` holds something.
54
+ * @csspart media - The slot the media arrives through, drawing no box, as `body` does.
42
55
  */
43
56
  export declare class HelixHeadlessCard extends HelixElement {
57
+ /**
58
+ * The card's accessible name, which makes it a named group.
59
+ *
60
+ * The name `Stat.Group` and the other named regions take, set through
61
+ * `ElementInternals`. `aria-label` and `aria-labelledby` written on the card
62
+ * name it too, and win over this, as an author's attribute does.
63
+ */
64
+ label: string;
44
65
  /**
45
66
  * Places the media after the content. By default it comes before.
46
67
  *
@@ -10,6 +10,7 @@ import { property, state } from 'lit/decorators.js';
10
10
  let HelixHeadlessCard = class HelixHeadlessCard extends HelixElement {
11
11
  constructor() {
12
12
  super(...arguments);
13
+ this.label = '';
13
14
  this.labelledBy = null;
14
15
  this.namedBy = null;
15
16
  this.footerActions = false;
@@ -22,26 +23,37 @@ let HelixHeadlessCard = class HelixHeadlessCard extends HelixElement {
22
23
  }
23
24
  willUpdate(changed) {
24
25
  super.willUpdate(changed);
25
- const named = Boolean(this.namedBy?.trim() || this.labelledBy?.trim());
26
- hostAria(this.internals, { role: named ? 'group' : '' });
26
+ const named = Boolean(this.label.trim() || this.namedBy?.trim() || this.labelledBy?.trim());
27
+ hostAria(this.internals, { label: this.label, role: named ? 'group' : '' });
27
28
  }
28
29
  updated(changed) {
29
30
  super.updated(changed);
30
31
  this.readActions();
31
32
  }
32
33
  render() {
33
- const header = html `<slot name="header"></slot
34
- ><slot name="header-actions" @slotchange=${this.readActions}></slot>`;
35
- const footer = html `<slot name="footer"></slot
36
- ><slot name="footer-actions" @slotchange=${this.readActions}></slot>`;
34
+ const header = html `<slot name="header" part="header"></slot
35
+ ><slot
36
+ name="header-actions"
37
+ part="header-actions"
38
+ @slotchange=${this.readActions}
39
+ ></slot>`;
40
+ const footer = html `<slot name="footer" part="footer"></slot
41
+ ><slot
42
+ name="footer-actions"
43
+ part="footer-actions"
44
+ @slotchange=${this.readActions}
45
+ ></slot>`;
37
46
  return html `
38
- <slot name="media"></slot>
47
+ <slot name="media" part="media"></slot>
39
48
  ${this.headerActions ? html `<div part="header-row">${header}</div>` : header}
40
- <slot></slot>
49
+ <slot part="body"></slot>
41
50
  ${this.footerActions ? html `<div part="footer-row">${footer}</div>` : footer}
42
51
  `;
43
52
  }
44
53
  };
54
+ __decorate([
55
+ property()
56
+ ], HelixHeadlessCard.prototype, "label", void 0);
45
57
  __decorate([
46
58
  property({ attribute: 'media-placement', reflect: true })
47
59
  ], HelixHeadlessCard.prototype, "mediaPlacement", void 0);
@@ -24,10 +24,30 @@ import { type PropertyValues, type TemplateResult } from 'lit';
24
24
  * polite live region. While the carousel rotates the region is off, so a
25
25
  * screen reader is not interrupted every few seconds.
26
26
  *
27
- * The indicators are one tab stop. The arrow keys along the track move between
28
- * them, Up and Down on a vertical carousel, and Home and End go to the first
29
- * and the last. Without `loop`, Previous on the first slide and Next on the
30
- * last are marked `aria-disabled`.
27
+ * **Keyboard.** The indicators are one tab stop.
28
+ *
29
+ * | Key | What it does |
30
+ * |---|---|
31
+ * | Tab | Moves through the rotation control, Previous, Next, the slides' own links and buttons, and the indicators, in that order. |
32
+ * | Enter, Space | Presses the control or the indicator that has focus. |
33
+ * | Right, Left | On an indicator, moves to the next or the previous slide and its indicator. Left moves on, on a right-to-left page. |
34
+ * | Down, Up | The same, on a vertical carousel. |
35
+ * | Home, End | On an indicator, moves to the first or the last slide. |
36
+ *
37
+ * Without `loop`, Previous on the first slide and Next on the last are marked
38
+ * `aria-disabled`, and keep focus.
39
+ *
40
+ * **What a screen reader hears.** The carousel is a group named by `label`,
41
+ * announced as `role-label` ("carousel"). Each slide is a group announced as
42
+ * `slide-role-label` ("slide") and named by `slide-label` ("2 of 5"). After a
43
+ * move by a control, an indicator, a key, or a drag, the `live` part says the
44
+ * slide's name politely. While the carousel rotates the region is off.
45
+ *
46
+ * **`slides-per-move` moves several slides at a time.** With `per-view="3"`
47
+ * and `slides-per-move="3"`, Next shows the next three, there is one
48
+ * indicator for each stop, and the track snaps only at the stops. The last
49
+ * stop is always the end of the run, so a run that does not divide evenly
50
+ * ends on its last slides. Unset moves one slide.
31
51
  *
32
52
  * **`mouse-drag` lets a mouse drag the track**, which otherwise only a touch
33
53
  * screen, a trackpad, or the scroll wheel moves. The drag follows the pointer
@@ -282,6 +302,12 @@ export declare class HelixHeadlessCarousel extends HelixElement {
282
302
  * `aria-roledescription`. Translate it with the rest of your text.
283
303
  */
284
304
  slideRoleLabel: string;
305
+ /**
306
+ * How many slides Previous, Next, the indicators, rotation, and a drag move
307
+ * at a time. Unset moves one. The track stops at every `slides-per-move`th
308
+ * position from the first, and at the last.
309
+ */
310
+ slidesPerMove?: number;
285
311
  /**
286
312
  * The name of the rotation control while rotation is stopped.
287
313
  */
@@ -350,6 +376,8 @@ export declare class HelixHeadlessCarousel extends HelixElement {
350
376
  * withheld rather than counted from it. See `across`.
351
377
  */
352
378
  get positions(): number;
379
+ /** The positions the track stops at, `slides-per-move` apart, and the last. See `stopsOf`. */
380
+ private get stops();
353
381
  /**
354
382
  * How many slides the box turned out to hold, from the pane it laid out.
355
383
  *
@@ -494,6 +522,11 @@ export declare class HelixHeadlessCarousel extends HelixElement {
494
522
  * sends neither, being a correction rather than a move anybody asked for.
495
523
  */
496
524
  private applyIndex;
525
+ /**
526
+ * The position one stop forward or back lands on, wrapping where `loop`
527
+ * says so.
528
+ */
529
+ private move;
497
530
  /** Moves to a slide. It wraps past either end only when `loop` is set. */
498
531
  goTo(index: number): void;
499
532
  /**
@@ -795,6 +828,12 @@ export declare class HelixHeadlessCarousel extends HelixElement {
795
828
  * is slotted. A tier above overrides this to draw its own caret.
796
829
  */
797
830
  protected renderNextMark(): TemplateResult;
831
+ /**
832
+ * A pane's own declarations: the last pane's `runEnd`, and no snap point on
833
+ * a pane the track does not stop at under `slides-per-move`, so a swipe
834
+ * settles on a stop as the controls do.
835
+ */
836
+ private paneStyle;
798
837
  protected render(): TemplateResult;
799
838
  }
800
839
  declare global {