@fusion.dev/helix-headless 0.142.1 → 0.143.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 (217) hide show
  1. package/custom-elements.json +16710 -707
  2. package/dist/accordion/item/accordion-item.d.ts +38 -2
  3. package/dist/accordion/item/accordion-item.js +38 -6
  4. package/dist/accordion/root/accordion-root.d.ts +23 -1
  5. package/dist/accordion/root/accordion-root.js +39 -3
  6. package/dist/announcement/root/announcement-root.d.ts +11 -7
  7. package/dist/announcement/root/announcement-root.js +1 -1
  8. package/dist/app-header/root/app-header-root.d.ts +21 -0
  9. package/dist/app-header/root/app-header-root.js +31 -5
  10. package/dist/area-chart/root/area-chart-root.js +16 -5
  11. package/dist/avatar/group/avatar-group.d.ts +24 -3
  12. package/dist/avatar/group/avatar-group.js +34 -2
  13. package/dist/avatar/root/avatar-root.d.ts +3 -1
  14. package/dist/avatar/root/avatar-root.js +8 -1
  15. package/dist/badge/root/badge-root.d.ts +8 -0
  16. package/dist/bar-chart/root/bar-chart-root.d.ts +19 -3
  17. package/dist/bar-chart/root/bar-chart-root.js +43 -13
  18. package/dist/blockquote/root/blockquote-root.d.ts +12 -7
  19. package/dist/blockquote/root/blockquote-root.js +6 -4
  20. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +9 -3
  21. package/dist/breadcrumbs/root/breadcrumbs-root.js +9 -1
  22. package/dist/button/root/button-root.d.ts +37 -0
  23. package/dist/button/root/button-root.js +44 -0
  24. package/dist/callout/root/callout-root.d.ts +14 -5
  25. package/dist/callout/root/callout-root.js +11 -3
  26. package/dist/canvas/root/canvas-root.d.ts +1 -0
  27. package/dist/canvas/root/canvas-root.js +10 -1
  28. package/dist/carousel/root/carousel-root.d.ts +47 -5
  29. package/dist/carousel/root/carousel-root.js +53 -21
  30. package/dist/chat/composer/chat-composer.d.ts +13 -11
  31. package/dist/chat/composer/chat-composer.js +6 -12
  32. package/dist/chat/message/chat-message.js +8 -1
  33. package/dist/chat/root/chat-root.d.ts +1 -0
  34. package/dist/chat/root/chat-root.js +2 -1
  35. package/dist/checkbox/root/checkbox-root.d.ts +7 -0
  36. package/dist/checkbox/root/checkbox-root.js +7 -3
  37. package/dist/checkbox-group/root/checkbox-group-root.d.ts +65 -32
  38. package/dist/checkbox-group/root/checkbox-group-root.js +85 -37
  39. package/dist/code/root/code-root.d.ts +1 -1
  40. package/dist/code-block/root/code-block-root.d.ts +19 -0
  41. package/dist/code-block/root/code-block-root.js +21 -1
  42. package/dist/color-input/root/color-input-root.d.ts +26 -1
  43. package/dist/color-input/root/color-input-root.js +32 -3
  44. package/dist/color-picker/root/color-picker-root.d.ts +37 -7
  45. package/dist/color-picker/root/color-picker-root.js +83 -6
  46. package/dist/combobox/root/combobox-root.d.ts +90 -2
  47. package/dist/combobox/root/combobox-root.js +160 -19
  48. package/dist/command/root/command-root.d.ts +17 -6
  49. package/dist/command/root/command-root.js +12 -1
  50. package/dist/copy-button/root/copy-button-root.d.ts +21 -6
  51. package/dist/copy-button/root/copy-button-root.js +11 -1
  52. package/dist/data-table/root/data-table-root.d.ts +164 -10
  53. package/dist/data-table/root/data-table-root.js +488 -57
  54. package/dist/date-input/root/date-input-root.d.ts +53 -8
  55. package/dist/date-input/root/date-input-root.js +70 -18
  56. package/dist/date-picker/root/date-picker-root.d.ts +84 -17
  57. package/dist/date-picker/root/date-picker-root.js +125 -20
  58. package/dist/dialog/root/dialog-root.d.ts +38 -10
  59. package/dist/dialog/root/dialog-root.js +55 -2
  60. package/dist/donut-chart/root/donut-chart-root.d.ts +39 -15
  61. package/dist/donut-chart/root/donut-chart-root.js +30 -10
  62. package/dist/drawer/root/drawer-root.d.ts +32 -7
  63. package/dist/drawer/root/drawer-root.js +50 -5
  64. package/dist/drilldown/item/drilldown-item.d.ts +16 -13
  65. package/dist/drilldown/item/drilldown-item.js +6 -2
  66. package/dist/drilldown/root/drilldown-root.d.ts +21 -5
  67. package/dist/drilldown/root/drilldown-root.js +26 -10
  68. package/dist/element-events.generated.js +35 -9
  69. package/dist/file-input/root/file-input-root.d.ts +18 -1
  70. package/dist/file-input/root/file-input-root.js +34 -8
  71. package/dist/filter-input/menu/filter-menu.d.ts +9 -0
  72. package/dist/filter-input/menu/filter-menu.js +8 -0
  73. package/dist/filter-input/root/filter-input-root.d.ts +5 -2
  74. package/dist/filter-input/root/filter-input-root.js +22 -7
  75. package/dist/format-date/root/format-date-root.d.ts +11 -3
  76. package/dist/format-date/root/format-date-root.js +26 -5
  77. package/dist/graph/root/graph-root.d.ts +24 -3
  78. package/dist/graph/root/graph-root.js +66 -12
  79. package/dist/heatmap/root/buckets.d.ts +2 -1
  80. package/dist/heatmap/root/buckets.js +5 -1
  81. package/dist/heatmap/root/heatmap-root.d.ts +27 -6
  82. package/dist/heatmap/root/heatmap-root.js +23 -6
  83. package/dist/icon/root/icon-root.d.ts +24 -3
  84. package/dist/icon/root/icon-root.js +34 -1
  85. package/dist/icon-button/root/icon-button-root.d.ts +1 -1
  86. package/dist/image/root/image-root.d.ts +9 -2
  87. package/dist/image/root/image-root.js +8 -2
  88. package/dist/input/root/input-root.d.ts +51 -9
  89. package/dist/input/root/input-root.js +46 -5
  90. package/dist/kbd/root/kbd-root.d.ts +12 -4
  91. package/dist/kbd/root/kbd-root.js +10 -11
  92. package/dist/legend/root/legend-root.d.ts +7 -0
  93. package/dist/legend/root/legend-root.js +7 -2
  94. package/dist/lightbox/item/lightbox-item.d.ts +2 -1
  95. package/dist/lightbox/root/lightbox-root.d.ts +16 -5
  96. package/dist/lightbox/root/lightbox-root.js +24 -3
  97. package/dist/line-chart/root/line-chart-root.d.ts +19 -2
  98. package/dist/line-chart/root/line-chart-root.js +40 -13
  99. package/dist/list/item/list-item.d.ts +11 -5
  100. package/dist/list/item/list-item.js +5 -6
  101. package/dist/listbox/root/listbox-root.d.ts +111 -2
  102. package/dist/listbox/root/listbox-root.js +144 -16
  103. package/dist/map/root/map-root.d.ts +19 -4
  104. package/dist/map/root/map-root.js +36 -7
  105. package/dist/megamenu/root/megamenu-root.d.ts +10 -1
  106. package/dist/megamenu/root/megamenu-root.js +10 -1
  107. package/dist/menu/item/menu-item.d.ts +41 -12
  108. package/dist/menu/item/menu-item.js +46 -3
  109. package/dist/menu/root/menu-root.d.ts +32 -2
  110. package/dist/menu/root/menu-root.js +48 -8
  111. package/dist/meter/root/meter-root.d.ts +6 -0
  112. package/dist/meter/root/meter-root.js +18 -2
  113. package/dist/navigation/root/navigation-root.d.ts +10 -2
  114. package/dist/navigation/root/navigation-root.js +13 -2
  115. package/dist/notifications/group/notification-group.d.ts +1 -0
  116. package/dist/notifications/notification/notification.d.ts +12 -0
  117. package/dist/notifications/notification/notification.js +31 -2
  118. package/dist/notifications/root/notifications-root.d.ts +7 -0
  119. package/dist/notifications/root/notifications-root.js +17 -2
  120. package/dist/number-input/root/number-input-root.d.ts +62 -7
  121. package/dist/number-input/root/number-input-root.js +68 -16
  122. package/dist/object-inspector/root/object-inspector-root.d.ts +48 -5
  123. package/dist/object-inspector/root/object-inspector-root.js +91 -11
  124. package/dist/option/root/option-root.d.ts +4 -1
  125. package/dist/option/root/option-root.js +1 -0
  126. package/dist/outline/root/outline-root.d.ts +13 -2
  127. package/dist/outline/root/outline-root.js +4 -2
  128. package/dist/pagination/root/pagination-root.d.ts +19 -1
  129. package/dist/pagination/root/pagination-root.js +49 -9
  130. package/dist/pagination/size/pagination-size.d.ts +13 -3
  131. package/dist/pagination/size/pagination-size.js +7 -0
  132. package/dist/pin-input/root/pin-input-root.d.ts +16 -0
  133. package/dist/pin-input/root/pin-input-root.js +19 -5
  134. package/dist/popover/root/popover-root.d.ts +19 -2
  135. package/dist/popover/root/popover-root.js +22 -1
  136. package/dist/progress/root/progress-root.d.ts +16 -1
  137. package/dist/progress/root/progress-root.js +31 -7
  138. package/dist/qr-code/root/qr-code-root.d.ts +19 -0
  139. package/dist/qr-code/root/qr-code-root.js +29 -1
  140. package/dist/radio/group/radio-group.d.ts +41 -0
  141. package/dist/radio/group/radio-group.js +50 -14
  142. package/dist/radio/root/radio-root.d.ts +8 -5
  143. package/dist/radio/root/radio-root.js +1 -2
  144. package/dist/rating/root/rating-root.d.ts +24 -1
  145. package/dist/rating/root/rating-root.js +24 -7
  146. package/dist/scatter-chart/root/scatter-chart-root.js +15 -7
  147. package/dist/select/root/select-root.d.ts +69 -3
  148. package/dist/select/root/select-root.js +92 -8
  149. package/dist/skeleton/root/skeleton-root.d.ts +14 -3
  150. package/dist/skeleton/root/skeleton-root.js +17 -3
  151. package/dist/skip-link/root/skip-link-root.d.ts +10 -0
  152. package/dist/skip-link/root/skip-link-root.js +15 -1
  153. package/dist/slider/root/slider-root.d.ts +20 -2
  154. package/dist/slider/root/slider-root.js +41 -3
  155. package/dist/sparkline/root/sparkline-root.d.ts +9 -10
  156. package/dist/speed-dial/item/speed-dial-item.d.ts +11 -5
  157. package/dist/speed-dial/item/speed-dial-item.js +7 -2
  158. package/dist/speed-dial/root/speed-dial-root.d.ts +15 -4
  159. package/dist/speed-dial/root/speed-dial-root.js +19 -5
  160. package/dist/splitter/root/splitter-root.d.ts +28 -6
  161. package/dist/splitter/root/splitter-root.js +35 -1
  162. package/dist/stat/root/stat-root.d.ts +7 -1
  163. package/dist/stat/root/stat-root.js +14 -1
  164. package/dist/steps/root/steps-root.js +1 -1
  165. package/dist/switch/root/switch-root.d.ts +2 -0
  166. package/dist/switch/root/switch-root.js +1 -0
  167. package/dist/table/cell/table-cell.d.ts +24 -4
  168. package/dist/table/cell/table-cell.js +21 -1
  169. package/dist/table/column/table-column.d.ts +32 -6
  170. package/dist/table/column/table-column.js +36 -6
  171. package/dist/table/root/table-root.d.ts +94 -3
  172. package/dist/table/root/table-root.js +128 -5
  173. package/dist/table/row/table-row.d.ts +7 -0
  174. package/dist/table/row/table-row.js +9 -1
  175. package/dist/tabs/root/tabs-root.d.ts +6 -1
  176. package/dist/tabs/root/tabs-root.js +6 -2
  177. package/dist/tag/root/tag-root.d.ts +23 -1
  178. package/dist/tag/root/tag-root.js +16 -2
  179. package/dist/textarea/root/textarea-root.d.ts +4 -0
  180. package/dist/textarea/root/textarea-root.js +1 -1
  181. package/dist/time-input/root/time-input-root.d.ts +28 -2
  182. package/dist/time-input/root/time-input-root.js +46 -10
  183. package/dist/time-picker/root/time-picker-root.d.ts +101 -18
  184. package/dist/time-picker/root/time-picker-root.js +115 -16
  185. package/dist/toast/root/toast-root.d.ts +64 -1
  186. package/dist/toast/root/toast-root.js +147 -2
  187. package/dist/toggle/group/toggle-group.d.ts +38 -1
  188. package/dist/toggle/group/toggle-group.js +34 -8
  189. package/dist/toggle/root/toggle-root.d.ts +14 -10
  190. package/dist/toggle/root/toggle-root.js +3 -3
  191. package/dist/toolbar/root/toolbar-root.d.ts +55 -15
  192. package/dist/toolbar/root/toolbar-root.js +99 -16
  193. package/dist/tooltip/root/tooltip-root.d.ts +37 -4
  194. package/dist/tooltip/root/tooltip-root.js +48 -0
  195. package/dist/tour/root/tour-root.d.ts +34 -5
  196. package/dist/tour/root/tour-root.js +51 -14
  197. package/dist/tour/stop/tour-stop.d.ts +18 -1
  198. package/dist/tour/stop/tour-stop.js +25 -5
  199. package/dist/tree/item/tree-item.d.ts +21 -5
  200. package/dist/tree/item/tree-item.js +14 -4
  201. package/dist/tree/root/tree-root.d.ts +29 -5
  202. package/dist/tree/root/tree-root.js +64 -8
  203. package/dist/trend/root/trend-root.d.ts +23 -1
  204. package/dist/trend/root/trend-root.js +28 -7
  205. package/dist/video/root/keys.d.ts +5 -0
  206. package/dist/video/root/keys.js +13 -1
  207. package/dist/video/root/video-root.d.ts +19 -0
  208. package/dist/video/root/video-root.js +48 -4
  209. package/dist/video-playlist/menu/video-playlist-menu.d.ts +20 -2
  210. package/dist/video-playlist/menu/video-playlist-menu.js +27 -5
  211. package/dist/video-playlist/root/video-playlist-root.js +6 -3
  212. package/dist/virtual-list/root/virtual-list-root.d.ts +52 -4
  213. package/dist/virtual-list/root/virtual-list-root.js +103 -21
  214. package/lint.json +1 -1
  215. package/package.json +5 -5
  216. package/types/jsx.d.ts +4348 -965
  217. package/types/vue.d.ts +972 -232
@@ -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 { CommandController, customElement, FullscreenController, fillTemplate, HelixElement, hostAria, IdleController, inlineStep, keyClaimed, MixinControllerActive, MixinControllerOpen, resolveActiveItem, } from '@fusion.dev/helix-core';
7
+ import { CommandController, customElement, deepActiveElement, deepContains, FullscreenController, fillTemplate, HelixElement, hostAria, IdleController, inlineStep, keyClaimed, lockScroll, MixinControllerActive, MixinControllerOpen, resolveActiveItem, unlockScroll, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
10
  import { HelixHeadlessLightboxItem } from '../item/lightbox-item.js';
@@ -22,7 +22,7 @@ let HelixHeadlessLightbox = class HelixHeadlessLightbox extends MixinControllerA
22
22
  this.filled = full;
23
23
  });
24
24
  this.idle = new IdleController(this, () => this.idleDelay, (resting) => {
25
- this.resting = resting;
25
+ this.resting = resting && !this.chromeHasFocus();
26
26
  });
27
27
  this.commands = new CommandController(this, {
28
28
  commands: {
@@ -45,6 +45,7 @@ let HelixHeadlessLightbox = class HelixHeadlessLightbox extends MixinControllerA
45
45
  this.relayNativeEvent(event);
46
46
  };
47
47
  this.handleKeydown = (event) => {
48
+ this.idle.stir();
48
49
  if (keyClaimed(event) || event.altKey || event.ctrlKey || event.metaKey) {
49
50
  return;
50
51
  }
@@ -81,6 +82,10 @@ let HelixHeadlessLightbox = class HelixHeadlessLightbox extends MixinControllerA
81
82
  this.requestOpen(false);
82
83
  };
83
84
  }
85
+ chromeHasFocus() {
86
+ const active = deepActiveElement();
87
+ return this.knownChildren.some((child) => (child.slot === 'header' || child.slot === 'footer') && deepContains(child, active));
88
+ }
84
89
  get items() {
85
90
  return this.knownChildren.filter((child) => child instanceof HelixHeadlessLightboxItem);
86
91
  }
@@ -135,9 +140,19 @@ let HelixHeadlessLightbox = class HelixHeadlessLightbox extends MixinControllerA
135
140
  this.toggleState('idle', this.resting);
136
141
  this.say(changed);
137
142
  }
143
+ disconnectedCallback() {
144
+ super.disconnectedCallback();
145
+ unlockScroll(this);
146
+ }
138
147
  updated(changed) {
139
148
  super.updated(changed);
140
149
  this.mark();
150
+ if (this.open) {
151
+ lockScroll(this);
152
+ }
153
+ else {
154
+ unlockScroll(this);
155
+ }
141
156
  const dialog = this.dialog;
142
157
  if (!dialog) {
143
158
  return;
@@ -170,7 +185,13 @@ let HelixHeadlessLightbox = class HelixHeadlessLightbox extends MixinControllerA
170
185
  const current = resolveActiveItem(this.active, items);
171
186
  const at = current ? items.indexOf(current) : -1;
172
187
  this.announcement =
173
- at === -1 ? '' : fillTemplate(this.statusLabel, { count: items.length, index: at + 1 });
188
+ at === -1 || !current
189
+ ? ''
190
+ : fillTemplate(this.statusLabel, {
191
+ count: items.length,
192
+ index: at + 1,
193
+ label: current.label,
194
+ });
174
195
  }
175
196
  render() {
176
197
  return html `<dialog
@@ -24,7 +24,8 @@ declare const HelixHeadlessLineChart_base: typeof HelixElement & (new (...args:
24
24
  * render at 10px in a narrow chart and 43px in a wide one.
25
25
  *
26
26
  * The table is the accessible representation, and the drawing is `aria-hidden`.
27
- * Screen reader users get the numbers.
27
+ * Screen reader users get the numbers. The `summary` part names the chart, from
28
+ * `label` or the table's caption, and gives each series' latest reading.
28
29
  *
29
30
  * @since 0.1.0
30
31
  * @status stable
@@ -42,6 +43,7 @@ declare const HelixHeadlessLineChart_base: typeof HelixElement & (new (...args:
42
43
  * @csspart line - The line for one series.
43
44
  * @csspart mark - The invisible point the tooltip is anchored to.
44
45
  * @csspart plot - The drawing.
46
+ * @csspart summary - The chart's name and each series' latest reading, written as a sentence for screen readers. Hide it visually.
45
47
  * @csspart svg - The drawing surface the lines and areas sit on.
46
48
  * @csspart terminus - The mark on one series' last reading.
47
49
  * @csspart tooltip - The bubble, forwarded from `Tooltip`.
@@ -183,6 +185,16 @@ export declare class HelixHeadlessLineChart extends HelixHeadlessLineChart_base
183
185
  */
184
186
  private ends;
185
187
  protected render(): TemplateResult;
188
+ /**
189
+ * What a reader who cannot see the lines is told: the chart's name and the
190
+ * latest reading of each series.
191
+ *
192
+ * The latest, because where a series ended is the question a line over time
193
+ * is asked first, which is what `AreaChart` gives too. Each series' own last
194
+ * reading, so a series with a blank in the last row still says where it was.
195
+ * Written the way the table writes it, such as `$128k` for `128000`.
196
+ */
197
+ protected renderSummary(series: Series[]): TemplateResult;
186
198
  /**
187
199
  * The lines themselves, behind a seam the styled tier can move.
188
200
  *
@@ -235,7 +247,12 @@ export declare class HelixHeadlessLineChart extends HelixHeadlessLineChart_base
235
247
  x: number;
236
248
  y: number;
237
249
  }>): TemplateResult | typeof nothing;
238
- /** One series, its wash first so the line is drawn over its own fill. */
250
+ /**
251
+ * One series, its wash first so the line is drawn over its own fill.
252
+ *
253
+ * Each reading sits at its own row, and the line breaks where a row has no
254
+ * reading: a line drawn across a blank claims a value nobody measured.
255
+ */
239
256
  protected renderSeries(one: Series, depth: number, x: (value: number) => number, y: (value: number) => number): TemplateResult;
240
257
  /**
241
258
  * The reading names, as HTML beside the drawing rather than inside it.
@@ -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 { CHART_PLOT, customElement, drawTooltip, extent, HelixElement, linear, linePath, MixinChartSource, PLOT_HEIGHT, PLOT_WIDTH, seriesIndex, ticks, } from '@fusion.dev/helix-core';
7
+ import { byRow, CHART_PLOT, customElement, drawTooltip, extent, HelixElement, linear, linePath, MixinChartSource, PLOT_HEIGHT, PLOT_WIDTH, seriesIndex, ticks, unbroken, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing, svg } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import '../../tooltip/index.js';
@@ -34,7 +34,7 @@ let HelixHeadlessLineChart = class HelixHeadlessLineChart extends MixinChartSour
34
34
  return [
35
35
  {
36
36
  index: seriesIndex(depth),
37
- x: (x(one.points.length - 1) / PLOT_WIDTH) * 100,
37
+ x: (x(last.at) / PLOT_WIDTH) * 100,
38
38
  y: (y(last.value) / PLOT_HEIGHT) * 100,
39
39
  },
40
40
  ];
@@ -42,7 +42,7 @@ let HelixHeadlessLineChart = class HelixHeadlessLineChart extends MixinChartSour
42
42
  }
43
43
  render() {
44
44
  const series = this.series;
45
- const readings = series[0]?.points.map((point) => point.label) ?? [];
45
+ const readings = series.length === 0 ? [] : this.sourceRows.map((row) => row.label);
46
46
  if (readings.length === 0) {
47
47
  return html `<div id=${CHART_PLOT} part="plot"></div>`;
48
48
  }
@@ -50,7 +50,25 @@ let HelixHeadlessLineChart = class HelixHeadlessLineChart extends MixinChartSour
50
50
  const y = linear(domain, [PLOT_HEIGHT, 0]);
51
51
  const slot = PLOT_WIDTH / readings.length;
52
52
  const x = linear([0, Math.max(readings.length - 1, 1)], [slot / 2, PLOT_WIDTH - slot / 2]);
53
- return html `${this.renderPlot(series, x, y, domain)} ${this.renderLabels(readings)}`;
53
+ return html `${this.renderPlot(series, x, y, domain)} ${this.renderLabels(readings)}${this.renderSummary(series)}`;
54
+ }
55
+ renderSummary(series) {
56
+ const rows = this.sourceRows;
57
+ const columns = this.plottedColumns;
58
+ const latest = series.flatMap((one, depth) => {
59
+ const last = one.points.at(-1);
60
+ if (last === undefined) {
61
+ return [];
62
+ }
63
+ const text = rows[last.at]?.cells[columns[depth] ?? -1]?.text ?? String(last.value);
64
+ return [{ label: last.label, reading: `${one.name} ${text}` }];
65
+ });
66
+ const shared = latest.every((one) => one.label === latest[0]?.label);
67
+ const body = shared
68
+ ? `${latest[0]?.label ?? ''}: ${latest.map((one) => one.reading).join(', ')}`
69
+ : latest.map((one) => `${one.label}: ${one.reading}`).join('; ');
70
+ const named = this.named ? `${this.named}, ` : '';
71
+ return html `<p part="summary">${named}${body}.</p>`;
54
72
  }
55
73
  renderPlot(series, x, y, domain) {
56
74
  const floor = domain[0] <= 0 && domain[1] >= 0 ? y(0) : undefined;
@@ -72,11 +90,11 @@ let HelixHeadlessLineChart = class HelixHeadlessLineChart extends MixinChartSour
72
90
  viewBox="0 0 ${PLOT_WIDTH} ${PLOT_HEIGHT}"
73
91
  xmlns="http://www.w3.org/2000/svg"
74
92
  >
75
- ${this.renderGridlines(x, y, domain, series[0]?.points.length ?? 0)}
93
+ ${this.renderGridlines(x, y, domain, this.readings)}
76
94
  ${floor === undefined
77
95
  ? nothing
78
96
  : svg `<line part="baseline" x1="0" x2=${PLOT_WIDTH} y1=${floor} y2=${floor} />`}
79
- ${this.renderBand(series[0]?.points.length ?? 0)}
97
+ ${this.renderBand(this.readings)}
80
98
  ${this.renderGuide(x)}
81
99
  ${series.map((one, depth) => this.renderSeries(one, depth, x, y))}
82
100
  </svg>
@@ -122,15 +140,24 @@ let HelixHeadlessLineChart = class HelixHeadlessLineChart extends MixinChartSour
122
140
  ></span>`)}`;
123
141
  }
124
142
  renderSeries(one, depth, x, y) {
125
- const points = one.points.map((point, index) => [x(index), y(point.value)]);
126
- const path = linePath(points, this.curve ?? 'smooth');
127
- if (path === '') {
143
+ const runs = unbroken(one)
144
+ .map((run) => {
145
+ const points = run.map((point) => [x(point.at), y(point.value)]);
146
+ return { path: linePath(points, this.curve ?? 'smooth'), points };
147
+ })
148
+ .filter((run) => run.path !== '');
149
+ if (runs.length === 0) {
128
150
  return html `${nothing}`;
129
151
  }
130
152
  const index = seriesIndex(depth);
131
- const first = points[0];
132
- const last = points.at(-1);
133
- const wash = `${path}L${last[0]},${PLOT_HEIGHT}L${first[0]},${PLOT_HEIGHT}Z`;
153
+ const path = runs.map((run) => run.path).join('');
154
+ const wash = runs
155
+ .map((run) => {
156
+ const first = run.points[0];
157
+ const last = run.points.at(-1);
158
+ return `${run.path}L${last[0]},${PLOT_HEIGHT}L${first[0]},${PLOT_HEIGHT}Z`;
159
+ })
160
+ .join('');
134
161
  return svg `${this.area
135
162
  ? svg `<path
136
163
  d=${wash}
@@ -160,7 +187,7 @@ let HelixHeadlessLineChart = class HelixHeadlessLineChart extends MixinChartSour
160
187
  const domain = this.range(series);
161
188
  const scale = linear(domain, [PLOT_HEIGHT, 0]);
162
189
  const tops = series
163
- .map((one) => one.points[at]?.value)
190
+ .map((one) => byRow(one, this.readings)[at]?.value)
164
191
  .filter((one) => one !== undefined)
165
192
  .map((one) => scale(one));
166
193
  const slot = 100 / this.readings;
@@ -6,11 +6,16 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
6
6
  * @description
7
7
  * Provides layout and semantics. The row is a target only when you set `href`.
8
8
  *
9
- * **`href` makes the whole row a link.** The component wraps its own layout in
10
- * an `<a part="row">`, as `Tree.Item` does. An anchor of your own cannot wrap
11
- * slots it does not own. With the anchor, the whole row is a target, Enter
12
- * follows it, middle click opens a new tab, the status bar shows the
13
- * destination, and all of it works before JavaScript runs.
9
+ * **`href` makes the row a link.** The component wraps the leading content,
10
+ * the label, and the description in an `<a part="link">` inside the row, as
11
+ * `Tree.Item` does. An anchor of your own cannot wrap slots it does not own.
12
+ * With the anchor, the row is a target, Enter follows it, middle click opens a
13
+ * new tab, the status bar shows the destination, and all of it works before
14
+ * JavaScript runs.
15
+ *
16
+ * **The `end` slot sits beside the link, outside it**, so a button or a menu
17
+ * there is a control of its own: a click on it does not follow the link, and
18
+ * its name is not part of the link's.
14
19
  *
15
20
  * Client-side routing needs your own handling. A router cannot render its
16
21
  * anchor inside the shadow root, so to navigate without a page load, intercept
@@ -30,6 +35,7 @@ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
30
35
  * @slot end - Trailing content.
31
36
  * @slot start - Leading content, usually an icon or an avatar.
32
37
  *
38
+ * @csspart link - The link, when the row has `href`. It holds every region except `end`.
33
39
  * @csspart row - The row's layout. It sits inside the host so the host can carry a list marker.
34
40
  */
35
41
  export declare class HelixHeadlessListItem extends HelixElement {
@@ -24,17 +24,16 @@ let HelixHeadlessListItem = class HelixHeadlessListItem extends HelixElement {
24
24
  render() {
25
25
  const content = html `${this.renderRail()}<slot name="start"></slot>
26
26
  <slot></slot>
27
- <slot name="description"></slot>
28
- <slot name="end"></slot>`;
27
+ <slot name="description"></slot>`;
29
28
  return this.href === ''
30
- ? html `<div part="row">${content}</div>`
31
- : html `<a
32
- part="row"
29
+ ? html `<div part="row">${content}<slot name="end"></slot></div>`
30
+ : html `<div part="row"><a
31
+ part="link"
33
32
  href=${this.href}
34
33
  target=${this.target || nothing}
35
34
  rel=${this.rel || nothing}
36
35
  >${content}</a
37
- >`;
36
+ ><slot name="end"></slot></div>`;
38
37
  }
39
38
  };
40
39
  __decorate([
@@ -20,6 +20,14 @@ declare const HelixHeadlessListbox_base: (new (...args: any[]) => import("@fusio
20
20
  * active option is where the keyboard is: the arrow keys move it, and
21
21
  * `aria-activedescendant` points to it while focus stays on the list.
22
22
  *
23
+ * The arrow keys, Home, End, PageUp and PageDown move the highlight, and typed
24
+ * letters move it to the next option whose words start with them. In a
25
+ * single-choice list the highlight is the choice unless `manual` is set; then
26
+ * Enter, Space or a click chooses. With `multiple`, Space toggles the
27
+ * highlighted option, Shift with an arrow adds the option it moves to, and
28
+ * Control+A or Command+A chooses every option, or none where all are chosen.
29
+ * In a filter field, Space, Home, End and letters edit the text.
30
+ *
23
31
  * @since 0.1.0
24
32
  * @status stable
25
33
  * @category forms
@@ -27,6 +35,7 @@ declare const HelixHeadlessListbox_base: (new (...args: any[]) => import("@fusio
27
35
  * @documentation https://fusion.dev/helix/components/listbox
28
36
  *
29
37
  * @slot - The options, and any groups of them.
38
+ * @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
30
39
  * @slot filter-icon - The icon in the filter field. Defaults to a magnifying glass.
31
40
  * @slot hint - The hint, for content richer than plain text.
32
41
  * @slot label - The label, for content richer than plain text.
@@ -99,6 +108,15 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
99
108
  * Placeholder text for the filter field.
100
109
  */
101
110
  filterLabel: string;
111
+ /**
112
+ * Stops the arrow keys from choosing each option they move to. Enter, Space
113
+ * or a click chooses the highlighted option.
114
+ *
115
+ * By default a single-choice list chooses as the arrows move, as a radio
116
+ * group does. Select and Time Input set this on the list in their panel, so
117
+ * a reader can move through the options before closing the panel on one.
118
+ */
119
+ manual: boolean;
102
120
  /**
103
121
  * Whether more than one option can be chosen.
104
122
  */
@@ -107,6 +125,18 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
107
125
  * Which option the keyboard is on, which is not what is chosen.
108
126
  */
109
127
  private activeValue;
128
+ /**
129
+ * Whether the highlight was cleared on purpose, so the filter does not put
130
+ * it back on the first match.
131
+ */
132
+ private parked;
133
+ /** The letters typed at the list, which move the highlight to a match. */
134
+ private readonly typeahead;
135
+ /**
136
+ * The values of the options seen on the last pass, so an option that leaves
137
+ * can be told apart from one that has not arrived yet.
138
+ */
139
+ private seen;
110
140
  /**
111
141
  * Whether the key being handled was forwarded rather than typed into this.
112
142
  *
@@ -150,6 +180,26 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
150
180
  */
151
181
  get selectedIndex(): number;
152
182
  set selectedIndex(at: number);
183
+ /**
184
+ * @internal Moves the highlight without choosing, for the control that owns
185
+ * this list: to the first or last option a reader can reach, to the chosen
186
+ * one (or the first where none is), or nowhere.
187
+ *
188
+ * Select opens its panel on the chosen option, or on the last one for
189
+ * ArrowUp, and Combobox moves the highlight off the list onto its create row.
190
+ */
191
+ highlight(where: 'first' | 'last' | 'none' | 'selected'): void;
192
+ /**
193
+ * @internal Moves the highlight to the option whose words start with the
194
+ * letters typed, and returns its value, or nothing where none matches.
195
+ *
196
+ * For a control that takes the letters while this list is not where focus
197
+ * is: Select's closed trigger chooses the option this returns, as a native
198
+ * `<select>` does.
199
+ */
200
+ typeaheadTo(key: string): string | undefined;
201
+ /** @internal Whether letters typed in the last moment are still one search. */
202
+ get typing(): boolean;
153
203
  /**
154
204
  * The kind of list, as the platform names it: `select-one` or
155
205
  * `select-multiple`.
@@ -196,8 +246,37 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
196
246
  * Space and Enter are how a multi-select list chooses, and they are also how
197
247
  * a single-select one confirms what the arrows already did, so they act
198
248
  * either way rather than being guarded on `multiple`.
249
+ *
250
+ * **A reader in a text field is typing.** That is a filter field of this
251
+ * list's own, or a combobox's field that forwards its keys through
252
+ * `navigate`. There a Space is a character, Home and End move the caret, and
253
+ * a letter is a letter. Measured before this: a Space typed into a filter,
254
+ * a combobox or a command palette chose the highlighted option and closed the
255
+ * panel, so a query of two words could not be typed.
199
256
  */
200
257
  private readonly handleKeydown;
258
+ /**
259
+ * Puts the highlight on an option, and chooses it where moving is choosing.
260
+ *
261
+ * Chosen on the way past only where moving is choosing. With `multiple` a
262
+ * reader passing over four options on the way to the fifth did not mean to
263
+ * pick all five, and with `manual` the owner has asked for the same.
264
+ *
265
+ * Nor where the keys were forwarded. A list with the focus on it selects as
266
+ * it moves, which is the pattern for a listbox; a combobox's arrows move the
267
+ * highlight and Enter takes it, which is the pattern for a combobox, and the
268
+ * two differ by exactly which element the reader is in. Measured before
269
+ * this: the first Down in a combobox committed the second option and shut the
270
+ * panel, one keystroke into the interaction.
271
+ */
272
+ private arrive;
273
+ /**
274
+ * How many rows PageUp and PageDown move: as many as the list shows at once.
275
+ *
276
+ * Measured off the rendered list and its first shown row. Where there is no
277
+ * layout to measure, as on a server or in a test double, it is ten.
278
+ */
279
+ private pageSize;
201
280
  /**
202
281
  * Runs the list's own key handling for a caller whose focus is elsewhere.
203
282
  *
@@ -215,8 +294,9 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
215
294
  * flag is set here rather than exposed as a property. The difference between
216
295
  * a listbox and a combobox is not a mode a consumer picks: it is which
217
296
  * element the reader's focus is in, and that is exactly what calling this
218
- * rather than being typed into means. Enter and Space still choose, because
219
- * those are the caller asking for the answer rather than for a move.
297
+ * rather than being typed into means. Enter still chooses, because that is
298
+ * the caller asking for the answer rather than for a move. Space, Home, End
299
+ * and letters are left to the caller's field, where they are typing.
220
300
  */
221
301
  navigate(event: KeyboardEvent): void;
222
302
  /**
@@ -236,6 +316,25 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
236
316
  reveal(): void;
237
317
  /** Hides what the filter excludes, and writes the rest onto the options. */
238
318
  private place;
319
+ /**
320
+ * Whether another Helix component renders this list and binds its value
321
+ * down, as Select, Combobox, Command and Time Picker do. That component seeds
322
+ * and corrects the value, so this list leaves both to it.
323
+ *
324
+ * By the tag rather than by `instanceof`, for the reason `optionsAmong`
325
+ * gives: a second copy of the library on a page is a second class.
326
+ */
327
+ private get owned();
328
+ /**
329
+ * Takes an option that has left the list out of the value.
330
+ *
331
+ * Only one that was here before: a value set ahead of its options, which a
332
+ * list loading them from a server does, is kept until they arrive. Measured
333
+ * before this: removing the chosen option left the list showing nothing
334
+ * chosen while its form still submitted the removed value. A native
335
+ * `<select>` drops it too, and sends no event for it.
336
+ */
337
+ private forgetRemoved;
239
338
  /** Scrolls the active option into view, which needs the rendered list to scroll. */
240
339
  private followActive;
241
340
  /** Reports the answer and the verdict on it. */
@@ -243,6 +342,16 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
243
342
  connectedCallback(): void;
244
343
  disconnectedCallback(): void;
245
344
  protected willUpdate(changed: PropertyValues): void;
345
+ /**
346
+ * Takes `<helix-option selected>` as the list's default value, as a native
347
+ * `<select>` takes `<option selected>`.
348
+ *
349
+ * Only where the list declares no `default-value` of its own, which wins. A
350
+ * form reset returns to it, which is what `Option.defaultSelected` says.
351
+ * Read from the options once they are known, so a list served by a server
352
+ * shows the choice from hydration on.
353
+ */
354
+ private seedDeclared;
246
355
  /**
247
356
  * Where the reader is, and failing that where the answer is.
248
357
  *