@fusion.dev/helix-headless 0.146.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 (239) hide show
  1. package/custom-elements.json +5266 -785
  2. package/dist/accordion/item/accordion-item.d.ts +38 -19
  3. package/dist/accordion/item/accordion-item.js +31 -9
  4. package/dist/accordion/root/accordion-root.d.ts +8 -2
  5. package/dist/accordion/root/accordion-root.js +3 -3
  6. package/dist/announcement/root/announcement-root.d.ts +13 -4
  7. package/dist/announcement/root/announcement-root.js +34 -6
  8. package/dist/area-chart/root/area-chart-root.d.ts +18 -1
  9. package/dist/area-chart/root/area-chart-root.js +11 -3
  10. package/dist/avatar/root/avatar-root.d.ts +31 -1
  11. package/dist/avatar/root/avatar-root.js +11 -1
  12. package/dist/badge/root/badge-root.d.ts +57 -6
  13. package/dist/badge/root/badge-root.js +88 -5
  14. package/dist/bar-chart/root/bar-chart-root.js +11 -20
  15. package/dist/bar-chart/stack.d.ts +10 -0
  16. package/dist/bar-chart/stack.js +8 -0
  17. package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +14 -0
  18. package/dist/breadcrumbs/breadcrumb/breadcrumb.js +12 -2
  19. package/dist/breadcrumbs/root/breadcrumbs-root.js +2 -2
  20. package/dist/button/root/button-root.d.ts +24 -38
  21. package/dist/button/root/button-root.js +6 -37
  22. package/dist/button/submitter.d.ts +27 -0
  23. package/dist/button/submitter.js +25 -0
  24. package/dist/card/root/card-root.d.ts +12 -1
  25. package/dist/card/root/card-root.js +11 -4
  26. package/dist/chat/root/chat-root.d.ts +15 -1
  27. package/dist/chat/root/chat-root.js +11 -2
  28. package/dist/checkbox/root/checkbox-root.js +5 -7
  29. package/dist/checkbox-group/root/checkbox-group-root.js +4 -3
  30. package/dist/checkbox-group/select-all.d.ts +0 -6
  31. package/dist/checkbox-group/select-all.js +0 -5
  32. package/dist/code-block/root/code-block-root.d.ts +35 -14
  33. package/dist/code-block/root/code-block-root.js +17 -3
  34. package/dist/color-input/root/color-input-root.d.ts +11 -0
  35. package/dist/color-input/root/color-input-root.js +12 -5
  36. package/dist/color-picker/channels.js +1 -2
  37. package/dist/color-picker/root/color-picker-root.d.ts +32 -24
  38. package/dist/color-picker/root/color-picker-root.js +101 -51
  39. package/dist/color-picker/wheel.d.ts +17 -0
  40. package/dist/color-picker/wheel.js +6 -0
  41. package/dist/combobox/root/combobox-root.d.ts +13 -0
  42. package/dist/combobox/root/combobox-root.js +14 -1
  43. package/dist/command/root/command-root.d.ts +3 -1
  44. package/dist/command/root/command-root.js +2 -19
  45. package/dist/copy-button/root/copy-button-root.d.ts +16 -1
  46. package/dist/copy-button/root/copy-button-root.js +7 -2
  47. package/dist/data-table/keys.d.ts +0 -18
  48. package/dist/data-table/keys.js +1 -11
  49. package/dist/data-table/root/data-table-root.js +13 -7
  50. package/dist/date-input/root/date-input-root.d.ts +8 -1
  51. package/dist/date-input/root/date-input-root.js +8 -5
  52. package/dist/date-picker/root/date-picker-root.d.ts +14 -9
  53. package/dist/date-picker/root/date-picker-root.js +21 -16
  54. package/dist/description-list/item/description-list-item.d.ts +18 -4
  55. package/dist/description-list/item/description-list-item.js +8 -4
  56. package/dist/donut-chart/root/donut-chart-root.js +13 -6
  57. package/dist/donut-chart/slice-label.d.ts +35 -0
  58. package/dist/donut-chart/slice-label.js +11 -0
  59. package/dist/drawer/root/drawer-root.d.ts +4 -2
  60. package/dist/drawer/root/drawer-root.js +15 -3
  61. package/dist/drilldown/item/drilldown-item.d.ts +21 -1
  62. package/dist/drilldown/item/drilldown-item.js +39 -4
  63. package/dist/drilldown/root/drilldown-root.js +3 -2
  64. package/dist/element-events.generated.js +4 -1
  65. package/dist/empty/root/empty-root.d.ts +31 -1
  66. package/dist/empty/root/empty-root.js +26 -5
  67. package/dist/file-input/root/file-input-root.d.ts +34 -6
  68. package/dist/file-input/root/file-input-root.js +54 -19
  69. package/dist/file-input/status.d.ts +24 -0
  70. package/dist/file-input/status.js +10 -0
  71. package/dist/filter-input/chip/filter-chip.d.ts +23 -0
  72. package/dist/filter-input/chip/filter-chip.js +11 -2
  73. package/dist/filter-input/root/filter-input-root.d.ts +8 -0
  74. package/dist/filter-input/root/filter-input-root.js +17 -27
  75. package/dist/format-date/options.d.ts +3 -4
  76. package/dist/format-date/options.js +2 -2
  77. package/dist/format-date/root/format-date-root.d.ts +18 -1
  78. package/dist/format-date/root/format-date-root.js +19 -23
  79. package/dist/heatmap/root/buckets.d.ts +21 -0
  80. package/dist/heatmap/root/buckets.js +34 -0
  81. package/dist/heatmap/root/heatmap-root.d.ts +64 -3
  82. package/dist/heatmap/root/heatmap-root.js +89 -19
  83. package/dist/icon/index.d.ts +1 -1
  84. package/dist/icon/index.js +1 -1
  85. package/dist/icon/registry.d.ts +26 -1
  86. package/dist/icon/registry.js +12 -1
  87. package/dist/icon/root/icon-root.d.ts +13 -0
  88. package/dist/icon/root/icon-root.js +23 -2
  89. package/dist/icon/root/index.d.ts +1 -1
  90. package/dist/icon/root/index.js +1 -1
  91. package/dist/image/root/image-root.d.ts +9 -0
  92. package/dist/image/root/image-root.js +6 -1
  93. package/dist/input/root/input-root.d.ts +23 -2
  94. package/dist/input/root/input-root.js +12 -8
  95. package/dist/kbd/keys.d.ts +29 -0
  96. package/dist/kbd/keys.js +52 -0
  97. package/dist/kbd/root/kbd-root.d.ts +20 -3
  98. package/dist/kbd/root/kbd-root.js +24 -50
  99. package/dist/legend/hidden-series.d.ts +10 -2
  100. package/dist/legend/hidden-series.js +5 -2
  101. package/dist/legend/root/legend-root.d.ts +25 -7
  102. package/dist/legend/root/legend-root.js +22 -10
  103. package/dist/lightbox/root/lightbox-root.d.ts +50 -5
  104. package/dist/lightbox/root/lightbox-root.js +76 -8
  105. package/dist/lightbox/zoom.d.ts +2 -0
  106. package/dist/lightbox/zoom.js +5 -3
  107. package/dist/line-chart/root/line-chart-root.d.ts +16 -0
  108. package/dist/line-chart/root/line-chart-root.js +10 -2
  109. package/dist/list/root/list-root.d.ts +10 -2
  110. package/dist/list/root/list-root.js +26 -5
  111. package/dist/list/selection.d.ts +17 -0
  112. package/dist/list/selection.js +16 -0
  113. package/dist/listbox/root/listbox-root.d.ts +9 -5
  114. package/dist/listbox/root/listbox-root.js +29 -37
  115. package/dist/megamenu/hand-over.d.ts +75 -0
  116. package/dist/megamenu/hand-over.js +67 -0
  117. package/dist/megamenu/root/megamenu-root.d.ts +38 -14
  118. package/dist/megamenu/root/megamenu-root.js +36 -50
  119. package/dist/menu/item/menu-item.js +4 -4
  120. package/dist/menu/root/menu-root.d.ts +3 -0
  121. package/dist/meter/root/meter-root.d.ts +42 -0
  122. package/dist/meter/root/meter-root.js +33 -7
  123. package/dist/notifications/root/notifications-root.d.ts +10 -1
  124. package/dist/notifications/root/notifications-root.js +11 -1
  125. package/dist/number-input/grain.d.ts +28 -0
  126. package/dist/number-input/grain.js +14 -0
  127. package/dist/number-input/root/number-input-root.d.ts +17 -1
  128. package/dist/number-input/root/number-input-root.js +29 -18
  129. package/dist/object-inspector/root/object-inspector-root.d.ts +13 -6
  130. package/dist/object-inspector/root/object-inspector-root.js +18 -17
  131. package/dist/option/index.d.ts +1 -0
  132. package/dist/option/index.js +1 -0
  133. package/dist/option/separator/option-separator.d.ts +30 -0
  134. package/dist/option/separator/option-separator.js +21 -0
  135. package/dist/outline/root/outline-root.d.ts +12 -0
  136. package/dist/outline/root/outline-root.js +5 -19
  137. package/dist/pagination/size/pagination-size.d.ts +5 -0
  138. package/dist/pagination/size/pagination-size.js +4 -2
  139. package/dist/pin-input/code.d.ts +28 -1
  140. package/dist/pin-input/code.js +12 -0
  141. package/dist/pin-input/root/pin-input-root.d.ts +98 -121
  142. package/dist/pin-input/root/pin-input-root.js +157 -148
  143. package/dist/popover/hide-outside.js +2 -9
  144. package/dist/popover/root/popover-root.d.ts +7 -1
  145. package/dist/popover/root/popover-root.js +9 -1
  146. package/dist/progress/root/progress-root.d.ts +27 -0
  147. package/dist/progress/root/progress-root.js +25 -7
  148. package/dist/qr-code/export.d.ts +19 -0
  149. package/dist/qr-code/export.js +14 -0
  150. package/dist/qr-code/name.d.ts +11 -0
  151. package/dist/qr-code/name.js +7 -0
  152. package/dist/qr-code/root/qr-code-root.d.ts +17 -6
  153. package/dist/qr-code/root/qr-code-root.js +10 -12
  154. package/dist/radio/group/radio-group.d.ts +15 -0
  155. package/dist/radio/root/radio-root.js +2 -2
  156. package/dist/rating/root/rating-root.d.ts +22 -9
  157. package/dist/rating/root/rating-root.js +15 -39
  158. package/dist/scatter-chart/root/scatter-chart-root.d.ts +30 -0
  159. package/dist/scatter-chart/root/scatter-chart-root.js +34 -7
  160. package/dist/scroll-area/scrollbar.d.ts +0 -8
  161. package/dist/scroll-area/scrollbar.js +1 -1
  162. package/dist/select/align.d.ts +47 -0
  163. package/dist/select/align.js +7 -0
  164. package/dist/select/root/select-root.d.ts +59 -3
  165. package/dist/select/root/select-root.js +72 -12
  166. package/dist/slider/root/slider-root.d.ts +18 -1
  167. package/dist/slider/root/slider-root.js +22 -0
  168. package/dist/sparkline/readings.d.ts +30 -12
  169. package/dist/sparkline/readings.js +32 -15
  170. package/dist/sparkline/root/sparkline-root.d.ts +46 -3
  171. package/dist/sparkline/root/sparkline-root.js +60 -21
  172. package/dist/speed-dial/item/speed-dial-item.d.ts +1 -1
  173. package/dist/speed-dial/item/speed-dial-item.js +2 -2
  174. package/dist/speed-dial/root/speed-dial-root.d.ts +6 -0
  175. package/dist/speed-dial/root/speed-dial-root.js +9 -1
  176. package/dist/splitter/root/splitter-root.d.ts +3 -0
  177. package/dist/splitter/root/splitter-root.js +2 -0
  178. package/dist/steps/root/steps-root.d.ts +8 -1
  179. package/dist/steps/root/steps-root.js +6 -1
  180. package/dist/steps/step/step.d.ts +1 -0
  181. package/dist/steps/step/step.js +1 -1
  182. package/dist/table/column/table-column.d.ts +6 -0
  183. package/dist/table/column/table-column.js +5 -1
  184. package/dist/table/root/table-root.js +13 -6
  185. package/dist/table/row/table-row.d.ts +24 -0
  186. package/dist/table/row/table-row.js +37 -1
  187. package/dist/tabs/root/tabs-root.d.ts +5 -3
  188. package/dist/tag/group/tag-group.d.ts +16 -4
  189. package/dist/tag/group/tag-group.js +19 -7
  190. package/dist/textarea/root/textarea-root.d.ts +14 -2
  191. package/dist/textarea/root/textarea-root.js +6 -7
  192. package/dist/time-input/root/time-input-root.d.ts +5 -1
  193. package/dist/time-input/root/time-input-root.js +10 -7
  194. package/dist/time-picker/root/time-picker-root.d.ts +11 -14
  195. package/dist/time-picker/root/time-picker-root.js +15 -23
  196. package/dist/toast/item/toast-item.d.ts +3 -3
  197. package/dist/toast/item/toast-item.js +0 -1
  198. package/dist/toast/root/toast-root.d.ts +28 -4
  199. package/dist/toast/root/toast-root.js +58 -12
  200. package/dist/toast/words.d.ts +12 -0
  201. package/dist/toast/words.js +25 -0
  202. package/dist/toggle/group/toggle-group.d.ts +29 -5
  203. package/dist/toggle/group/toggle-group.js +26 -41
  204. package/dist/toggle/root/toggle-root.js +2 -4
  205. package/dist/toolbar/root/toolbar-root.d.ts +21 -5
  206. package/dist/toolbar/root/toolbar-root.js +52 -8
  207. package/dist/tooltip/root/tooltip-root.d.ts +7 -1
  208. package/dist/tooltip/root/tooltip-root.js +10 -1
  209. package/dist/tour/root/tour-root.d.ts +15 -0
  210. package/dist/tour/root/tour-root.js +20 -1
  211. package/dist/tour/stop/tour-stop.d.ts +3 -0
  212. package/dist/tour/stop/tour-stop.js +3 -3
  213. package/dist/tree/root/tree-root.js +2 -2
  214. package/dist/trend/figure.d.ts +16 -0
  215. package/dist/trend/figure.js +8 -0
  216. package/dist/trend/root/trend-root.d.ts +41 -2
  217. package/dist/trend/root/trend-root.js +29 -3
  218. package/dist/video/root/extra-controls.d.ts +12 -0
  219. package/dist/video/root/extra-controls.js +6 -2
  220. package/dist/video/root/video-root.d.ts +5 -1
  221. package/dist/video-playlist/root/video-playlist-root.d.ts +11 -1
  222. package/dist/video-playlist/root/video-playlist-root.js +3 -0
  223. package/dist/virtual-list/fill.d.ts +11 -0
  224. package/dist/virtual-list/fill.js +9 -0
  225. package/dist/virtual-list/keys.d.ts +16 -7
  226. package/dist/virtual-list/keys.js +17 -6
  227. package/dist/virtual-list/plan.d.ts +17 -1
  228. package/dist/virtual-list/plan.js +13 -2
  229. package/dist/virtual-list/root/virtual-list-root.d.ts +25 -3
  230. package/dist/virtual-list/root/virtual-list-root.js +48 -24
  231. package/lint.json +1 -1
  232. package/package.json +5 -5
  233. package/types/jsx.d.ts +2979 -738
  234. package/types/svelte.d.ts +1 -0
  235. package/types/vue.d.ts +619 -202
  236. package/dist/color-picker/swatches.d.ts +0 -12
  237. package/dist/color-picker/swatches.js +0 -26
  238. package/dist/rating/steps.d.ts +0 -7
  239. package/dist/rating/steps.js +0 -9
@@ -97,6 +97,7 @@ declare const HelixHeadlessFilterInput_base: (new (...args: any[]) => import("@f
97
97
  * @aliases SearchField, FacetInput, TokenInput
98
98
  * @documentation https://fusion.dev/helix/components/filter-input
99
99
  *
100
+ * @slot clear-icon - Replaces the cross on the clear button, under `clearable`.
100
101
  * @slot end - Content after the text, such as a count or a control.
101
102
  * @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
102
103
  * @slot hint - Help under the control, for content richer than the `hint` text.
@@ -256,6 +257,11 @@ export declare class HelixHeadlessFilterInput extends HelixHeadlessFilterInput_b
256
257
  * and one that pretends it was never there.
257
258
  */
258
259
  private get suggestions();
260
+ /**
261
+ * Every option slotted into `suggestions`, and every option one level inside
262
+ * a group slotted there, hidden or not.
263
+ */
264
+ private get options();
259
265
  /**
260
266
  * The direction of the selection, named as on `<input>`.
261
267
  *
@@ -437,6 +443,8 @@ export declare class HelixHeadlessFilterInput extends HelixHeadlessFilterInput_b
437
443
  private markActive;
438
444
  /** Puts the caret in the text field. */
439
445
  focus(options?: FocusOptions): void;
446
+ /** The cross on the clear button, behind a seam a tier can move. */
447
+ protected renderClearIcon(): TemplateResult;
440
448
  protected render(): TemplateResult;
441
449
  }
442
450
  declare global {
@@ -162,22 +162,18 @@ let HelixHeadlessFilterInput = class HelixHeadlessFilterInput extends MixinContr
162
162
  };
163
163
  }
164
164
  narrow() {
165
- const slot = this.renderRoot?.querySelector('slot[name="suggestions"]');
166
165
  const term = this.filterSuggestions
167
166
  ? currentTerm(this.value, this.control?.selectionStart ?? this.value.length)
168
167
  : '';
169
- for (const node of slot?.assignedElements({ flatten: true }) ?? []) {
170
- const options = isOption(node) ? [node] : [...node.children].filter(isOption);
171
- for (const option of options) {
172
- const hide = !suggests(option.textContent ?? '', term);
173
- if (hide && !option.hidden) {
174
- option.hidden = true;
175
- this.narrowed.add(option);
176
- }
177
- else if (!hide && this.narrowed.has(option)) {
178
- option.hidden = false;
179
- this.narrowed.delete(option);
180
- }
168
+ for (const option of this.options) {
169
+ const hide = !suggests(option.textContent ?? '', term);
170
+ if (hide && !option.hidden) {
171
+ option.hidden = true;
172
+ this.narrowed.add(option);
173
+ }
174
+ else if (!hide && this.narrowed.has(option)) {
175
+ option.hidden = false;
176
+ this.narrowed.delete(option);
181
177
  }
182
178
  }
183
179
  }
@@ -220,20 +216,11 @@ let HelixHeadlessFilterInput = class HelixHeadlessFilterInput extends MixinContr
220
216
  return this.clearable && this.value !== '' && !this.isDisabled;
221
217
  }
222
218
  get suggestions() {
219
+ return this.options.filter((option) => !option.disabled && !option.hidden);
220
+ }
221
+ get options() {
223
222
  const slot = this.renderRoot?.querySelector('slot[name="suggestions"]');
224
- const found = [];
225
- for (const node of slot?.assignedElements({ flatten: true }) ?? []) {
226
- if (isOption(node)) {
227
- found.push(node);
228
- continue;
229
- }
230
- for (const child of node.children) {
231
- if (isOption(child)) {
232
- found.push(child);
233
- }
234
- }
235
- }
236
- return found.filter((option) => !option.disabled && !option.hidden);
223
+ return (slot?.assignedElements({ flatten: true }) ?? []).flatMap((node) => isOption(node) ? [node] : [...node.children].filter(isOption));
237
224
  }
238
225
  get selectionDirection() {
239
226
  return this.control?.selectionDirection ?? 'none';
@@ -392,6 +379,9 @@ let HelixHeadlessFilterInput = class HelixHeadlessFilterInput extends MixinContr
392
379
  focus(options) {
393
380
  this.control?.focus(options);
394
381
  }
382
+ renderClearIcon() {
383
+ return html `<slot name="clear-icon">${drawIcon(x)}</slot>`;
384
+ }
395
385
  render() {
396
386
  return html `${this.renderLabel()}
397
387
  <div part="field" @focusin=${this.handleFocusIn} @focusout=${this.handleFocusOut}>
@@ -426,7 +416,7 @@ let HelixHeadlessFilterInput = class HelixHeadlessFilterInput extends MixinContr
426
416
  aria-label=${this.clearLabel}
427
417
  @click=${this.handleClear}
428
418
  >
429
- ${drawIcon(x)}
419
+ ${this.renderClearIcon()}
430
420
  </button>`
431
421
  : nothing}
432
422
  </div>
@@ -1,9 +1,8 @@
1
1
  /**
2
2
  * What a Format Date was asked for, in its own spelling: the `Intl` options a
3
- * consumer set, and whether the timestamp is a day with no time of day.
3
+ * consumer set. The element itself is one, so it passes itself.
4
4
  */
5
5
  export interface Asked {
6
- dateOnly: boolean;
7
6
  dateStyle?: 'full' | 'long' | 'medium' | 'short' | undefined;
8
7
  day?: 'numeric' | '2-digit' | undefined;
9
8
  era?: 'long' | 'narrow' | 'short' | undefined;
@@ -26,8 +25,8 @@ export interface Asked {
26
25
  * given beside `month` or `hour`, so the fields are left out wherever a style
27
26
  * is set. `hourCycle` and `timeZone` go with either.
28
27
  *
29
- * **A day with no time is read in UTC** unless a zone is given. Parsed, it is
28
+ * **A day with no time, `dateOnly`, is read in UTC** unless a zone is given. Parsed, it is
30
29
  * midnight UTC, and read in a zone west of it that is the day before: measured
31
30
  * before this, `2026-08-04` read "August 3, 2026" in Los Angeles.
32
31
  */
33
- export declare const formatOptions: (asked: Asked) => Intl.DateTimeFormatOptions;
32
+ export declare const formatOptions: (asked: Asked, dateOnly?: boolean) => Intl.DateTimeFormatOptions;
@@ -9,7 +9,7 @@ const FIELDS = [
9
9
  'weekday',
10
10
  'year',
11
11
  ];
12
- export const formatOptions = (asked) => {
12
+ export const formatOptions = (asked, dateOnly = false) => {
13
13
  const options = {};
14
14
  const styled = asked.dateStyle !== undefined || asked.timeStyle !== undefined;
15
15
  if (styled) {
@@ -35,7 +35,7 @@ export const formatOptions = (asked) => {
35
35
  if (asked.timeZone) {
36
36
  options.timeZone = asked.timeZone;
37
37
  }
38
- else if (asked.dateOnly) {
38
+ else if (dateOnly) {
39
39
  options.timeZone = 'UTC';
40
40
  }
41
41
  return options;
@@ -25,6 +25,7 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
25
25
  * **The text refreshes on one timer shared by the page.** Each element
26
26
  * schedules an update for when its current reading expires, and an element
27
27
  * showing a date schedules none, so a long feed left open costs almost nothing.
28
+ * `frozen` draws the reading once and leaves it.
28
29
  *
29
30
  * **The output is always `<time datetime>`**, so copy and paste and scripts
30
31
  * parsing the page get the exact instant, whatever the visible text says. A
@@ -85,6 +86,19 @@ export declare class HelixHeadlessFormatDate extends HelixElement {
85
86
  * How the era is written, such as AD, where a date is shown.
86
87
  */
87
88
  era?: 'long' | 'narrow' | 'short';
89
+ /**
90
+ * Draws an `elapsed` or `relative` reading once and leaves it, where it
91
+ * would otherwise move on as it goes stale.
92
+ *
93
+ * For a reading that describes a moment the page itself is about, such as
94
+ * "3 hours ago" in a report generated then, or a list a reader compares
95
+ * line by line while it should not change under them. The reading is taken
96
+ * when the element draws, and again whenever `date` or another option
97
+ * changes. Turned off, the reading catches up and moves on again.
98
+ * `sl-relative-time` and `wa-relative-time` keep still unless `sync` is
99
+ * set; this keeps moving unless `frozen` is.
100
+ */
101
+ frozen: boolean;
88
102
  /**
89
103
  * How the hour is written, where a time of day is shown.
90
104
  */
@@ -100,9 +114,12 @@ export declare class HelixHeadlessFormatDate extends HelixElement {
100
114
  /**
101
115
  * The locale to format the timestamp in.
102
116
  *
103
- * Empty is the runtime's own.
117
+ * Absent is the page's: the `lang` of the nearest element with one, as
118
+ * Shoelace and Web Awesome read it, then the runtime's own.
104
119
  */
105
120
  locale: string;
121
+ /** The locale the words are written in: `locale`, or the page's `lang`. */
122
+ private get language();
106
123
  /**
107
124
  * How the minute is written, where a time of day is shown.
108
125
  */
@@ -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, elapsedTime, HelixElement, RelativeClockController, relativeTime, } from '@fusion.dev/helix-core';
7
+ import { customElement, elapsedTime, HelixElement, localeOf, RelativeClockController, relativeTime, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
10
  import { formatOptions } from '../options.js';
@@ -14,16 +14,23 @@ let HelixHeadlessFormatDate = class HelixHeadlessFormatDate extends HelixElement
14
14
  super(...arguments);
15
15
  this.date = '';
16
16
  this.elapsed = false;
17
+ this.frozen = false;
17
18
  this.locale = '';
18
19
  this.clock = new RelativeClockController(this, {
19
20
  expires: (now) => {
20
21
  const moment = this.moment;
21
- return moment && this.reading ? this.readingAt(moment, now).next : undefined;
22
+ if (!moment || !this.reading) {
23
+ return undefined;
24
+ }
25
+ return this.frozen ? Number.POSITIVE_INFINITY : this.readingAt(moment, now).next;
22
26
  },
23
27
  });
24
28
  this.written = '';
25
29
  this.watching = undefined;
26
30
  }
31
+ get language() {
32
+ return localeOf(this, this.locale);
33
+ }
27
34
  get dateOnly() {
28
35
  return DATE_ONLY.test((this.date || this.written).trim());
29
36
  }
@@ -36,30 +43,15 @@ let HelixHeadlessFormatDate = class HelixHeadlessFormatDate extends HelixElement
36
43
  return Number.isNaN(parsed.getTime()) ? undefined : parsed;
37
44
  }
38
45
  get options() {
39
- return formatOptions({
40
- dateOnly: this.dateOnly,
41
- dateStyle: this.dateStyle,
42
- day: this.day,
43
- era: this.era,
44
- hour: this.hour,
45
- hourCycle: this.hourCycle,
46
- minute: this.minute,
47
- month: this.month,
48
- second: this.second,
49
- timeStyle: this.timeStyle,
50
- timeZone: this.timeZone,
51
- timeZoneName: this.timeZoneName,
52
- weekday: this.weekday,
53
- year: this.year,
54
- });
46
+ return formatOptions(this, this.dateOnly);
55
47
  }
56
48
  get reading() {
57
49
  return this.elapsed || this.relative !== undefined;
58
50
  }
59
51
  readingAt(moment, now) {
60
52
  return this.elapsed
61
- ? elapsedTime(this.locale)(moment, now)
62
- : relativeTime(this.locale, {
53
+ ? elapsedTime(this.language)(moment, now)
54
+ : relativeTime(this.language, {
63
55
  numeric: this.numeric ?? 'auto',
64
56
  style: this.relative ?? 'long',
65
57
  })(moment, now);
@@ -87,6 +79,7 @@ let HelixHeadlessFormatDate = class HelixHeadlessFormatDate extends HelixElement
87
79
  }
88
80
  if (changed.has('date') ||
89
81
  changed.has('elapsed') ||
82
+ changed.has('frozen') ||
90
83
  changed.has('locale') ||
91
84
  changed.has('numeric') ||
92
85
  changed.has('relative')) {
@@ -115,18 +108,18 @@ let HelixHeadlessFormatDate = class HelixHeadlessFormatDate extends HelixElement
115
108
  }
116
109
  const datetime = this.dateOnly ? (this.date || this.written).trim() : moment.toISOString();
117
110
  if (!this.reading) {
118
- const text = new Intl.DateTimeFormat(this.locale || undefined, this.options).format(moment);
111
+ const text = new Intl.DateTimeFormat(this.language || undefined, this.options).format(moment);
119
112
  return html `<time part="time" datetime=${datetime}>${text}</time>`;
120
113
  }
121
114
  const now = new Date(this.clock.now);
122
115
  const zone = this.timeZone || (this.dateOnly ? 'UTC' : undefined);
123
- const whole = new Intl.DateTimeFormat(this.locale || undefined, {
116
+ const whole = new Intl.DateTimeFormat(this.language || undefined, {
124
117
  dateStyle: 'long',
125
118
  ...(this.dateOnly ? {} : { timeStyle: 'short' }),
126
119
  ...(this.hourCycle ? { hourCycle: this.hourCycle } : {}),
127
120
  ...(zone ? { timeZone: zone } : {}),
128
121
  }).format(moment);
129
- const spoken = relativeTime(this.locale, { numeric: this.numeric ?? 'auto' })(moment, now).text;
122
+ const spoken = relativeTime(this.language, { numeric: this.numeric ?? 'auto' })(moment, now).text;
130
123
  return html `<time
131
124
  part="time"
132
125
  datetime=${datetime}
@@ -150,6 +143,9 @@ __decorate([
150
143
  __decorate([
151
144
  property()
152
145
  ], HelixHeadlessFormatDate.prototype, "era", void 0);
146
+ __decorate([
147
+ property({ type: Boolean })
148
+ ], HelixHeadlessFormatDate.prototype, "frozen", void 0);
153
149
  __decorate([
154
150
  property()
155
151
  ], HelixHeadlessFormatDate.prototype, "hour", void 0);
@@ -57,3 +57,24 @@ export declare const toneOf: (reading: Reading, thresholds: readonly number[], t
57
57
  * the tail slice aligned.
58
58
  */
59
59
  export declare const fits: (total: number, width: number, minimum: number, gap: number, rows?: number) => number;
60
+ /** What the drawn readings come to: where the busiest stands, and their total. */
61
+ export interface Overview {
62
+ /** The place of the busiest reading, the first where several tie, or -1 with none. */
63
+ busiest: number;
64
+ /** The sum of every reading, blanks counting nothing. */
65
+ total: number;
66
+ }
67
+ /**
68
+ * The busiest reading among `cells` and the total of them all, for the
69
+ * strip's `overview`. A blank cell is passed over.
70
+ */
71
+ export declare const overviewOf: (cells: readonly Reading[]) => Overview;
72
+ /**
73
+ * Where a page of a calendar goes from the reading at `at`: the same day a
74
+ * month on, or a month back, by the dates the readings carry, written
75
+ * `YYYY-MM-DD` as a `<time datetime>` gives them. A day the month lacks,
76
+ * such as the 31st, is the month's last. Where that day has no reading, the
77
+ * nearest one past it in the direction of travel, and the last or the first
78
+ * reading past the end. Undefined where the reading at `at` carries no date.
79
+ */
80
+ export declare const monthPage: (whens: readonly (string | undefined)[], at: number, forward: boolean) => number | undefined;
@@ -1,3 +1,4 @@
1
+ import { extremesOf } from '@fusion.dev/helix-core';
1
2
  export const toneOf = (reading, thresholds, tones) => {
2
3
  if (reading.tone) {
3
4
  return reading.tone;
@@ -24,3 +25,36 @@ export const fits = (total, width, minimum, gap, rows = 1) => {
24
25
  const columns = Math.max(1, Math.floor((width + gap) / (minimum + gap)));
25
26
  return Math.min(total, columns * Math.max(1, rows));
26
27
  };
28
+ export const overviewOf = (cells) => {
29
+ const values = cells.map((cell) => cell.value);
30
+ return {
31
+ busiest: extremesOf(values).high ?? -1,
32
+ total: values.reduce((sum, value) => sum + (value ?? 0), 0),
33
+ };
34
+ };
35
+ const dayOf = (when) => {
36
+ const found = /^(\d{4})-(\d{2})-(\d{2})/.exec(when ?? '');
37
+ return found
38
+ ? Date.UTC(Number(found[1]), Number(found[2]) - 1, Number(found[3])) / 86_400_000
39
+ : undefined;
40
+ };
41
+ export const monthPage = (whens, at, forward) => {
42
+ const from = dayOf(whens[at]);
43
+ if (from === undefined) {
44
+ return undefined;
45
+ }
46
+ const date = new Date(from * 86_400_000);
47
+ const month = date.getUTCMonth() + (forward ? 1 : -1);
48
+ const last = new Date(Date.UTC(date.getUTCFullYear(), month + 1, 0)).getUTCDate();
49
+ const target = Date.UTC(date.getUTCFullYear(), month, Math.min(date.getUTCDate(), last)) / 86_400_000;
50
+ const days = whens.map(dayOf);
51
+ const order = days.map((_, index) => index);
52
+ const past = (forward ? order : order.reverse()).find((index) => {
53
+ const day = days[index];
54
+ return day !== undefined && (forward ? day >= target : day <= target);
55
+ });
56
+ if (past !== undefined) {
57
+ return past;
58
+ }
59
+ return forward ? whens.length - 1 : 0;
60
+ };
@@ -31,14 +31,24 @@ declare const HelixHeadlessHeatmap_base: typeof HelixElement & (new (...args: an
31
31
  * down arrows move a cell, the left and right arrows move a column, which is a
32
32
  * week with `rows="7"`, and Home and End go to the first and the last. The
33
33
  * tooltip follows, the `live` part says the cell's row in words, and Escape
34
- * puts the tooltip away. PageUp and PageDown move four columns, which is four
35
- * weeks with `rows="7"`.
34
+ * puts the tooltip away. PageUp and PageDown move a month, to the same day,
35
+ * where each row's header carries its date as a `<time datetime>`, and four
36
+ * columns otherwise, which is four weeks with `rows="7"`.
36
37
  *
37
38
  * **The strip describes itself.** The `overview` part says the busiest
38
- * reading and the total of the readings drawn, "Busiest: 11 Jun 12; Total
39
+ * reading and the total of the readings drawn, "Busiest: 11 Jun, 12; Total
39
40
  * 84", and the strip is described by it, as every chart is by its summary.
40
41
  * Hide it visually. The `summary` slot is still yours, for words of your own.
41
42
  *
43
+ * **`selection-mode` lets a reader select cells**: `single` one at a time and
44
+ * `multiple` any number. Space, Enter or a press selects the cell the keys or
45
+ * the pointer rest on, or lets it go, and under `multiple` Shift with an arrow,
46
+ * Home, End, PageUp or PageDown takes in every cell from the last one pressed
47
+ * to where the key went. `value` holds the selected days, by the names their
48
+ * rows have in the table, separated by commas. A change asks with
49
+ * `helix-before-change` and tells with `change`, and the `selection` part says
50
+ * how many are selected, in `selection-label`.
51
+ *
42
52
  * @since 0.1.0
43
53
  * @status stable
44
54
  * @category charts
@@ -49,16 +59,20 @@ declare const HelixHeadlessHeatmap_base: typeof HelixElement & (new (...args: an
49
59
  * @slot start - Below the strip, at the leading edge: usually the oldest date.
50
60
  * @slot summary - Below the strip, in the middle: a summary of the range shown.
51
61
  *
62
+ * @event {Event} change - Fired once a press or a key has changed which cells are selected.
63
+ * @event {HelixBeforeChangeEvent} helix-before-change - Fired before a press or a key changes which cells are selected, with the `value` it would leave. Cancelable.
52
64
  * @event {HelixResizeEvent} helix-resize - Fired when the number of cells drawn changes, with the new number.
53
65
  *
54
66
  * @csspart cell - One reading.
55
67
  * @csspart cell-active - The cell the pointer or the keys rest on. Set alongside `cell`.
68
+ * @csspart cell-selected - A cell that is selected, under `selection-mode`. Set alongside `cell`.
56
69
  * @csspart empty - Shown when the table has no readings. It stays hidden until the table can be read: on the server and during hydration, there is no document to resolve `for` in.
57
70
  * @csspart end - The trailing slot's box.
58
71
  * @csspart footer - The three-slot row under the strip.
59
72
  * @csspart live - The readout: a polite live region that says the cell the keys moved to. Hide it visually.
60
73
  * @csspart mark - The invisible point the tooltip is anchored to.
61
74
  * @csspart overview - The busiest reading and the total of the readings drawn, written as a sentence for screen readers, which describes the strip. Rendered once there are cells. Hide it visually.
75
+ * @csspart selection - A polite region that says how many cells are selected after a change, rendered from the first change. Hide it visually.
62
76
  * @csspart start - The leading slot's box.
63
77
  * @csspart strip - The grid of cells, which takes focus to be read by key. It is named by the host's `aria-labelledby` or `aria-label`, then by `label`, then by the caption of the table.
64
78
  * @csspart summary - The middle slot's box.
@@ -141,6 +155,17 @@ export declare class HelixHeadlessHeatmap extends HelixHeadlessHeatmap_base {
141
155
  * days.
142
156
  */
143
157
  rows: number;
158
+ /**
159
+ * What the `selection` part says after the selection changes, with `{count}` for
160
+ * how many cells are selected.
161
+ */
162
+ selectionLabel: string;
163
+ /**
164
+ * How many cells a reader can select: `single` or `multiple`.
165
+ *
166
+ * Absent selects nothing, and a press or Space does what it did.
167
+ */
168
+ selectionMode?: 'multiple' | 'single';
144
169
  /**
145
170
  * Lower bounds for the tone buckets, in the order the tones are given.
146
171
  *
@@ -167,6 +192,14 @@ export declare class HelixHeadlessHeatmap extends HelixHeadlessHeatmap_base {
167
192
  * The word the `overview` puts before the total of the readings drawn.
168
193
  */
169
194
  totalLabel: string;
195
+ /**
196
+ * The selected cells, by the names their rows have in the table, such as
197
+ * `2026-06-11`, separated by commas.
198
+ *
199
+ * Set it to start with cells selected. Written by a press or a key under
200
+ * `selection-mode`.
201
+ */
202
+ value: string;
170
203
  /**
171
204
  * How many cells are actually drawn.
172
205
  *
@@ -215,6 +248,28 @@ export declare class HelixHeadlessHeatmap extends HelixHeadlessHeatmap_base {
215
248
  protected readonly aria: AriaForwardController;
216
249
  private observer;
217
250
  private announced;
251
+ /** Where a range taken in with Shift starts: the cell last pressed, or none. */
252
+ private anchor;
253
+ /** The region a change of selection is said in, rendered from the first change. */
254
+ private readonly status;
255
+ /** The name each drawn cell stands for in `value`: its row's name in the table. */
256
+ private keysOf;
257
+ /**
258
+ * Moves `value` to `next`, asking first: `helix-before-change` carries it,
259
+ * a listener that refuses keeps the selection, and `change` follows, with
260
+ * the count said in the `selection` part.
261
+ */
262
+ private choose;
263
+ /** Selects the drawn cell at `index`, or lets it go, as `selection-mode` says. */
264
+ private press;
265
+ /**
266
+ * Space and Enter select the cell the keys rest on, and Shift with a key
267
+ * that moved them takes in the range from the anchor. After the pointer
268
+ * controller, which has already moved `at` for an arrow.
269
+ */
270
+ private readonly onKeydown;
271
+ /** A press on a cell selects it, under `selection-mode`. */
272
+ private readonly onClick;
218
273
  /**
219
274
  * Every row in the table, oldest first, as the table is written, with its
220
275
  * reading where the row has one.
@@ -304,6 +359,12 @@ export declare class HelixHeadlessHeatmap extends HelixHeadlessHeatmap_base {
304
359
  * the reason `BarChart` gives: SSR calls this one.
305
360
  */
306
361
  protected willUpdate(changed: PropertyValues<this>): void;
362
+ /**
363
+ * Where PageUp or PageDown goes from the drawn cell at `at`: the same day a
364
+ * month on or back, by the dates the rows' headers carry. Undefined where
365
+ * they carry none, and the keys move four columns.
366
+ */
367
+ pageFrom(at: number, forward: boolean): number | undefined;
307
368
  connectedCallback(): void;
308
369
  disconnectedCallback(): void;
309
370
  /**