@fusion.dev/helix-headless 0.146.0 → 0.148.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 (288) hide show
  1. package/custom-elements.json +9287 -1084
  2. package/dist/accordion/item/accordion-item.d.ts +43 -21
  3. package/dist/accordion/item/accordion-item.js +37 -11
  4. package/dist/accordion/root/accordion-root.d.ts +8 -2
  5. package/dist/accordion/root/accordion-root.js +6 -8
  6. package/dist/announcement/root/announcement-root.d.ts +66 -6
  7. package/dist/announcement/root/announcement-root.js +144 -13
  8. package/dist/area-chart/root/area-chart-root.d.ts +18 -1
  9. package/dist/area-chart/root/area-chart-root.js +14 -7
  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/count.d.ts +14 -0
  13. package/dist/badge/count.js +20 -0
  14. package/dist/badge/root/badge-root.d.ts +57 -6
  15. package/dist/badge/root/badge-root.js +77 -8
  16. package/dist/bar-chart/root/bar-chart-root.js +11 -20
  17. package/dist/bar-chart/stack.d.ts +10 -0
  18. package/dist/bar-chart/stack.js +8 -0
  19. package/dist/blockquote/root/blockquote-root.d.ts +66 -8
  20. package/dist/blockquote/root/blockquote-root.js +85 -8
  21. package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +14 -0
  22. package/dist/breadcrumbs/breadcrumb/breadcrumb.js +12 -2
  23. package/dist/breadcrumbs/root/breadcrumbs-root.js +2 -2
  24. package/dist/button/root/button-root.d.ts +24 -38
  25. package/dist/button/root/button-root.js +6 -37
  26. package/dist/button/submitter.d.ts +27 -0
  27. package/dist/button/submitter.js +25 -0
  28. package/dist/button-group/arrows.d.ts +14 -0
  29. package/dist/button-group/arrows.js +10 -0
  30. package/dist/button-group/root/button-group-root.d.ts +141 -3
  31. package/dist/button-group/root/button-group-root.js +142 -2
  32. package/dist/canvas/edge-pan.d.ts +61 -0
  33. package/dist/canvas/edge-pan.js +63 -0
  34. package/dist/canvas/node/canvas-node.d.ts +12 -2
  35. package/dist/canvas/node/canvas-node.js +6 -2
  36. package/dist/canvas/root/canvas-document.d.ts +10 -0
  37. package/dist/canvas/root/canvas-document.js +1 -0
  38. package/dist/canvas/root/canvas-root.d.ts +107 -5
  39. package/dist/canvas/root/canvas-root.js +140 -36
  40. package/dist/canvas/snap.d.ts +42 -0
  41. package/dist/canvas/snap.js +32 -0
  42. package/dist/card/root/card-root.d.ts +12 -1
  43. package/dist/card/root/card-root.js +11 -4
  44. package/dist/carousel/root/carousel-root.d.ts +4 -3
  45. package/dist/carousel/root/carousel-root.js +2 -6
  46. package/dist/chat/root/chat-root.d.ts +28 -4
  47. package/dist/chat/root/chat-root.js +12 -7
  48. package/dist/checkbox/root/checkbox-root.js +5 -7
  49. package/dist/checkbox-group/root/checkbox-group-root.d.ts +13 -0
  50. package/dist/checkbox-group/root/checkbox-group-root.js +16 -7
  51. package/dist/checkbox-group/select-all.d.ts +9 -4
  52. package/dist/checkbox-group/select-all.js +1 -1
  53. package/dist/code-block/root/code-block-root.d.ts +41 -18
  54. package/dist/code-block/root/code-block-root.js +21 -6
  55. package/dist/color-input/root/color-input-root.d.ts +11 -0
  56. package/dist/color-input/root/color-input-root.js +12 -5
  57. package/dist/color-picker/channels.js +1 -2
  58. package/dist/color-picker/root/color-picker-root.d.ts +32 -24
  59. package/dist/color-picker/root/color-picker-root.js +99 -55
  60. package/dist/color-picker/wheel.d.ts +28 -0
  61. package/dist/color-picker/wheel.js +15 -0
  62. package/dist/combobox/root/combobox-root.d.ts +83 -11
  63. package/dist/combobox/root/combobox-root.js +81 -18
  64. package/dist/command/root/command-root.d.ts +7 -4
  65. package/dist/command/root/command-root.js +2 -19
  66. package/dist/copy-button/root/copy-button-root.d.ts +16 -1
  67. package/dist/copy-button/root/copy-button-root.js +7 -2
  68. package/dist/data-table/keys.d.ts +0 -18
  69. package/dist/data-table/keys.js +1 -11
  70. package/dist/data-table/root/data-table-root.js +29 -50
  71. package/dist/date-input/root/date-input-root.d.ts +8 -1
  72. package/dist/date-input/root/date-input-root.js +8 -5
  73. package/dist/date-picker/root/date-picker-root.d.ts +14 -9
  74. package/dist/date-picker/root/date-picker-root.js +21 -16
  75. package/dist/description-list/item/description-list-item.d.ts +22 -4
  76. package/dist/description-list/item/description-list-item.js +14 -4
  77. package/dist/divider/root/divider-root.d.ts +45 -16
  78. package/dist/divider/root/divider-root.js +28 -4
  79. package/dist/donut-chart/root/donut-chart-root.js +13 -6
  80. package/dist/donut-chart/slice-label.d.ts +35 -0
  81. package/dist/donut-chart/slice-label.js +11 -0
  82. package/dist/drawer/root/drawer-root.d.ts +4 -2
  83. package/dist/drawer/root/drawer-root.js +15 -3
  84. package/dist/drilldown/item/drilldown-item.d.ts +21 -1
  85. package/dist/drilldown/item/drilldown-item.js +38 -4
  86. package/dist/drilldown/root/drilldown-root.js +3 -2
  87. package/dist/element-events.generated.js +5 -1
  88. package/dist/empty/root/empty-root.d.ts +46 -2
  89. package/dist/empty/root/empty-root.js +50 -5
  90. package/dist/file-input/root/file-input-root.d.ts +34 -6
  91. package/dist/file-input/root/file-input-root.js +55 -21
  92. package/dist/file-input/status.d.ts +24 -0
  93. package/dist/file-input/status.js +11 -0
  94. package/dist/filter-input/chip/filter-chip.d.ts +23 -0
  95. package/dist/filter-input/chip/filter-chip.js +10 -2
  96. package/dist/filter-input/root/filter-input-root.d.ts +8 -0
  97. package/dist/filter-input/root/filter-input-root.js +17 -27
  98. package/dist/format-date/fields.d.ts +20 -0
  99. package/dist/format-date/fields.js +14 -0
  100. package/dist/format-date/options.d.ts +5 -5
  101. package/dist/format-date/options.js +10 -39
  102. package/dist/format-date/root/format-date-root.d.ts +53 -4
  103. package/dist/format-date/root/format-date-root.js +38 -50
  104. package/dist/graph/root/graph-root.d.ts +23 -5
  105. package/dist/graph/root/graph-root.js +17 -20
  106. package/dist/heatmap/root/buckets.d.ts +21 -0
  107. package/dist/heatmap/root/buckets.js +34 -0
  108. package/dist/heatmap/root/heatmap-root.d.ts +76 -3
  109. package/dist/heatmap/root/heatmap-root.js +105 -20
  110. package/dist/icon/index.d.ts +1 -1
  111. package/dist/icon/index.js +1 -1
  112. package/dist/icon/registry.d.ts +26 -1
  113. package/dist/icon/registry.js +12 -1
  114. package/dist/icon/root/icon-root.d.ts +13 -0
  115. package/dist/icon/root/icon-root.js +23 -2
  116. package/dist/icon/root/index.d.ts +1 -1
  117. package/dist/icon/root/index.js +1 -1
  118. package/dist/image/root/image-root.d.ts +20 -0
  119. package/dist/image/root/image-root.js +6 -1
  120. package/dist/input/root/input-root.d.ts +23 -2
  121. package/dist/input/root/input-root.js +12 -8
  122. package/dist/kbd/root/kbd-root.d.ts +20 -3
  123. package/dist/kbd/root/kbd-root.js +23 -50
  124. package/dist/legend/hidden-series.d.ts +10 -2
  125. package/dist/legend/hidden-series.js +5 -2
  126. package/dist/legend/root/legend-root.d.ts +25 -7
  127. package/dist/legend/root/legend-root.js +25 -26
  128. package/dist/lightbox/root/lightbox-root.d.ts +50 -5
  129. package/dist/lightbox/root/lightbox-root.js +76 -8
  130. package/dist/lightbox/zoom.d.ts +2 -0
  131. package/dist/lightbox/zoom.js +5 -3
  132. package/dist/line-chart/root/line-chart-root.d.ts +16 -0
  133. package/dist/line-chart/root/line-chart-root.js +10 -2
  134. package/dist/list/root/list-root.d.ts +10 -2
  135. package/dist/list/root/list-root.js +31 -24
  136. package/dist/list/selection.d.ts +17 -0
  137. package/dist/list/selection.js +16 -0
  138. package/dist/listbox/root/listbox-root.d.ts +125 -26
  139. package/dist/listbox/root/listbox-root.js +156 -166
  140. package/dist/map/marker/map-marker.d.ts +2 -1
  141. package/dist/map/root/map-root.d.ts +40 -2
  142. package/dist/map/root/map-root.js +64 -23
  143. package/dist/megamenu/hand-over.d.ts +75 -0
  144. package/dist/megamenu/hand-over.js +67 -0
  145. package/dist/megamenu/root/megamenu-root.d.ts +38 -14
  146. package/dist/megamenu/root/megamenu-root.js +29 -50
  147. package/dist/menu/item/menu-item.js +4 -4
  148. package/dist/menu/root/menu-root.d.ts +5 -2
  149. package/dist/meter/root/meter-root.d.ts +42 -0
  150. package/dist/meter/root/meter-root.js +33 -7
  151. package/dist/navigation/root/navigation-root.js +5 -8
  152. package/dist/notifications/group/notification-group.d.ts +8 -1
  153. package/dist/notifications/group/notification-group.js +12 -6
  154. package/dist/notifications/notification/notification.d.ts +12 -1
  155. package/dist/notifications/notification/notification.js +3 -1
  156. package/dist/notifications/root/notifications-root.d.ts +48 -3
  157. package/dist/notifications/root/notifications-root.js +36 -6
  158. package/dist/number-input/grain.d.ts +28 -0
  159. package/dist/number-input/grain.js +14 -0
  160. package/dist/number-input/root/number-input-root.d.ts +17 -1
  161. package/dist/number-input/root/number-input-root.js +29 -18
  162. package/dist/object-inspector/root/object-inspector-root.d.ts +17 -6
  163. package/dist/object-inspector/root/object-inspector-root.js +31 -20
  164. package/dist/option/index.d.ts +1 -0
  165. package/dist/option/index.js +1 -0
  166. package/dist/option/separator/option-separator.d.ts +30 -0
  167. package/dist/option/separator/option-separator.js +21 -0
  168. package/dist/outline/root/outline-root.d.ts +12 -0
  169. package/dist/outline/root/outline-root.js +5 -19
  170. package/dist/pagination/size/pagination-size.d.ts +6 -0
  171. package/dist/pagination/size/pagination-size.js +5 -3
  172. package/dist/pin-input/code.d.ts +51 -1
  173. package/dist/pin-input/code.js +37 -0
  174. package/dist/pin-input/root/pin-input-root.d.ts +98 -121
  175. package/dist/pin-input/root/pin-input-root.js +151 -156
  176. package/dist/popover/hide-outside.js +2 -9
  177. package/dist/popover/root/popover-root.d.ts +7 -1
  178. package/dist/popover/root/popover-root.js +9 -1
  179. package/dist/progress/root/progress-root.d.ts +27 -0
  180. package/dist/progress/root/progress-root.js +25 -7
  181. package/dist/qr-code/export.d.ts +19 -0
  182. package/dist/qr-code/export.js +14 -0
  183. package/dist/qr-code/name.d.ts +11 -0
  184. package/dist/qr-code/name.js +7 -0
  185. package/dist/qr-code/root/qr-code-root.d.ts +31 -9
  186. package/dist/qr-code/root/qr-code-root.js +29 -17
  187. package/dist/radio/group/radio-group.d.ts +15 -0
  188. package/dist/radio/root/radio-root.js +2 -2
  189. package/dist/rating/root/rating-root.d.ts +22 -9
  190. package/dist/rating/root/rating-root.js +15 -39
  191. package/dist/scatter-chart/measures.d.ts +22 -0
  192. package/dist/scatter-chart/measures.js +11 -0
  193. package/dist/scatter-chart/root/scatter-chart-root.d.ts +26 -0
  194. package/dist/scatter-chart/root/scatter-chart-root.js +21 -7
  195. package/dist/scroll-area/scrollbar.d.ts +0 -8
  196. package/dist/scroll-area/scrollbar.js +1 -1
  197. package/dist/select/align.d.ts +47 -0
  198. package/dist/select/align.js +7 -0
  199. package/dist/select/root/select-root.d.ts +115 -11
  200. package/dist/select/root/select-root.js +104 -20
  201. package/dist/slider/root/slider-root.d.ts +18 -1
  202. package/dist/slider/root/slider-root.js +22 -0
  203. package/dist/sparkline/readings.d.ts +30 -12
  204. package/dist/sparkline/readings.js +32 -15
  205. package/dist/sparkline/root/sparkline-root.d.ts +46 -3
  206. package/dist/sparkline/root/sparkline-root.js +60 -21
  207. package/dist/speed-dial/group/speed-dial-group.d.ts +48 -0
  208. package/dist/speed-dial/group/speed-dial-group.js +43 -0
  209. package/dist/speed-dial/index.d.ts +1 -0
  210. package/dist/speed-dial/index.js +1 -0
  211. package/dist/speed-dial/item/speed-dial-item.d.ts +27 -2
  212. package/dist/speed-dial/item/speed-dial-item.js +43 -5
  213. package/dist/speed-dial/long-press.d.ts +50 -0
  214. package/dist/speed-dial/long-press.js +48 -0
  215. package/dist/speed-dial/root/speed-dial-root.d.ts +86 -1
  216. package/dist/speed-dial/root/speed-dial-root.js +123 -6
  217. package/dist/splitter/root/splitter-root.d.ts +9 -2
  218. package/dist/splitter/root/splitter-root.js +18 -3
  219. package/dist/steps/root/steps-root.d.ts +8 -1
  220. package/dist/steps/root/steps-root.js +6 -1
  221. package/dist/steps/step/step.d.ts +1 -0
  222. package/dist/steps/step/step.js +1 -1
  223. package/dist/table/cell/table-cell.d.ts +8 -1
  224. package/dist/table/cell/table-cell.js +6 -2
  225. package/dist/table/column/table-column.d.ts +6 -0
  226. package/dist/table/column/table-column.js +5 -1
  227. package/dist/table/grid-controller.d.ts +117 -0
  228. package/dist/table/grid-controller.js +293 -0
  229. package/dist/table/root/table-root.d.ts +47 -3
  230. package/dist/table/root/table-root.js +93 -29
  231. package/dist/table/row/table-row.d.ts +36 -0
  232. package/dist/table/row/table-row.js +52 -2
  233. package/dist/tabs/root/tabs-root.d.ts +5 -3
  234. package/dist/tag/group/tag-group.d.ts +16 -4
  235. package/dist/tag/group/tag-group.js +23 -20
  236. package/dist/textarea/root/textarea-root.d.ts +14 -2
  237. package/dist/textarea/root/textarea-root.js +6 -7
  238. package/dist/time-input/root/time-input-root.d.ts +5 -1
  239. package/dist/time-input/root/time-input-root.js +10 -7
  240. package/dist/time-picker/root/time-picker-root.d.ts +12 -14
  241. package/dist/time-picker/root/time-picker-root.js +18 -23
  242. package/dist/toast/item/toast-item.d.ts +9 -6
  243. package/dist/toast/item/toast-item.js +1 -1
  244. package/dist/toast/root/toast-root.d.ts +40 -4
  245. package/dist/toast/root/toast-root.js +68 -16
  246. package/dist/toast/words.d.ts +12 -0
  247. package/dist/toast/words.js +25 -0
  248. package/dist/toggle/group/toggle-group.d.ts +29 -5
  249. package/dist/toggle/group/toggle-group.js +26 -43
  250. package/dist/toggle/root/toggle-root.js +2 -4
  251. package/dist/toolbar/root/toolbar-root.d.ts +52 -5
  252. package/dist/toolbar/root/toolbar-root.js +88 -13
  253. package/dist/tooltip/root/tooltip-root.d.ts +7 -1
  254. package/dist/tooltip/root/tooltip-root.js +10 -2
  255. package/dist/tour/root/tour-root.d.ts +15 -0
  256. package/dist/tour/root/tour-root.js +20 -1
  257. package/dist/tour/stop/tour-stop.d.ts +3 -0
  258. package/dist/tour/stop/tour-stop.js +3 -3
  259. package/dist/tree/root/tree-root.js +2 -2
  260. package/dist/trend/figure.d.ts +16 -0
  261. package/dist/trend/figure.js +8 -0
  262. package/dist/trend/root/trend-root.d.ts +41 -2
  263. package/dist/trend/root/trend-root.js +29 -3
  264. package/dist/video/root/extra-controls.d.ts +12 -0
  265. package/dist/video/root/extra-controls.js +6 -2
  266. package/dist/video/root/video-root.d.ts +16 -1
  267. package/dist/video/root/video-root.js +15 -1
  268. package/dist/video-playlist/root/video-playlist-root.d.ts +11 -1
  269. package/dist/video-playlist/root/video-playlist-root.js +3 -0
  270. package/dist/virtual-list/fill.d.ts +11 -0
  271. package/dist/virtual-list/fill.js +9 -0
  272. package/dist/virtual-list/keys.d.ts +16 -7
  273. package/dist/virtual-list/keys.js +17 -6
  274. package/dist/virtual-list/plan.d.ts +17 -1
  275. package/dist/virtual-list/plan.js +13 -2
  276. package/dist/virtual-list/root/virtual-list-root.d.ts +25 -3
  277. package/dist/virtual-list/root/virtual-list-root.js +53 -41
  278. package/lint.json +1 -1
  279. package/package.json +5 -5
  280. package/types/jsx.d.ts +4934 -954
  281. package/types/svelte.d.ts +2 -0
  282. package/types/vue.d.ts +946 -253
  283. package/dist/color-picker/swatches.d.ts +0 -12
  284. package/dist/color-picker/swatches.js +0 -26
  285. package/dist/rating/steps.d.ts +0 -7
  286. package/dist/rating/steps.js +0 -9
  287. package/dist/tooltip/focus-target.d.ts +0 -6
  288. package/dist/tooltip/focus-target.js +0 -9
@@ -23,6 +23,7 @@ const percentIn = (locale) => {
23
23
  let HelixHeadlessAreaChart = class HelixHeadlessAreaChart extends MixinChartSource(HelixElement) {
24
24
  constructor() {
25
25
  super(...arguments);
26
+ this.overlap = false;
26
27
  this.share = false;
27
28
  this.totalLabel = 'Total';
28
29
  this.warnedAboutNegatives = false;
@@ -36,7 +37,7 @@ let HelixHeadlessAreaChart = class HelixHeadlessAreaChart extends MixinChartSour
36
37
  get stack() {
37
38
  const rows = this.sourceRows;
38
39
  const columns = this.plottedColumns;
39
- const names = columns.map((column) => rows.find((row) => row.cells[column])?.cells[column]?.name ?? '');
40
+ const names = columns.map((column) => this.columnName(column));
40
41
  const values = columns.map((column, depth) => rows.map((row) => {
41
42
  if (!this.showsSeries(names[depth] ?? '')) {
42
43
  return 0;
@@ -57,7 +58,7 @@ let HelixHeadlessAreaChart = class HelixHeadlessAreaChart extends MixinChartSour
57
58
  const layers = [];
58
59
  let running = rows.map(() => 0);
59
60
  for (const column of drawn) {
60
- running = running.map((sum, index) => sum + (column[index] ?? 0));
61
+ running = this.overlap ? column : running.map((sum, index) => sum + (column[index] ?? 0));
61
62
  layers.push(running);
62
63
  }
63
64
  return {
@@ -88,7 +89,11 @@ let HelixHeadlessAreaChart = class HelixHeadlessAreaChart extends MixinChartSour
88
89
  if (rows.length === 0 || stack.columns.length === 0) {
89
90
  return html `<div id=${CHART_PLOT} part="plot"></div>`;
90
91
  }
91
- const top = this.share ? 1 : Math.max(0, ...stack.totals);
92
+ const top = this.overlap
93
+ ? Math.max(0, ...stack.layers.flat())
94
+ : this.share
95
+ ? 1
96
+ : Math.max(0, ...stack.totals);
92
97
  const domain = [0, top > 0 ? top : 1];
93
98
  const y = linear(domain, [PLOT_HEIGHT, 0]);
94
99
  const slot = PLOT_WIDTH / rows.length;
@@ -181,9 +186,8 @@ let HelixHeadlessAreaChart = class HelixHeadlessAreaChart extends MixinChartSour
181
186
  ]
182
187
  : []);
183
188
  const named = this.named ? `${this.named}, ` : '';
184
- return html `<p id="helix-chart-summary" part="summary">
185
- ${named}${rows[last]?.label ?? ''}: ${this.totalLabel} ${format(total)}; ${shares.join(', ')}.
186
- </p>`;
189
+ const words = `${named}${rows[last]?.label ?? ''}: ${this.totalLabel} ${format(total)}; ${shares.join(', ')}.`;
190
+ return html `<p id="helix-chart-summary" part="summary">${words}</p>`;
187
191
  }
188
192
  tallied(rows, stack) {
189
193
  const format = formatNumbers(this.locale);
@@ -213,7 +217,7 @@ let HelixHeadlessAreaChart = class HelixHeadlessAreaChart extends MixinChartSour
213
217
  return drawTooltip(rows, at, this.tag('tooltip'), {
214
218
  placement: 'top',
215
219
  x: `${at * slot + slot / 2}%`,
216
- y: `${y(stack.layers.at(-1)?.[at] ?? 0)}%`,
220
+ y: `${y(Math.max(0, ...stack.layers.map((layer) => layer[at] ?? 0)))}%`,
217
221
  }, (cell) => this.seriesOf(cell), this.pointer);
218
222
  }
219
223
  };
@@ -223,6 +227,9 @@ __decorate([
223
227
  __decorate([
224
228
  property()
225
229
  ], HelixHeadlessAreaChart.prototype, "gridlines", void 0);
230
+ __decorate([
231
+ property({ reflect: true, type: Boolean })
232
+ ], HelixHeadlessAreaChart.prototype, "overlap", void 0);
226
233
  __decorate([
227
234
  property({ reflect: true, type: Boolean })
228
235
  ], HelixHeadlessAreaChart.prototype, "share", void 0);
@@ -15,7 +15,16 @@ export declare const initialsOf: (name: string) => string;
15
15
  * a person's name does not describe what the avatar stands for.
16
16
  *
17
17
  * `load` and `error` are re-dispatched from the host, because they are not
18
- * composed and would otherwise stop at the shadow boundary.
18
+ * composed and would otherwise stop at the shadow boundary. `status` says
19
+ * which of the two happened, for a listener that arrives after it, and the
20
+ * `loading`, `loaded` and `error` custom states say the same to a stylesheet.
21
+ *
22
+ * **On a server the avatar sends the picture's place**, an `<img>` that the
23
+ * browser fetches while it reads the page. The initials stand in only on the
24
+ * client: at once where the picture failed before the page hydrated, and after
25
+ * `fallback-delay` where it is still on its way. `load` or `error` for a
26
+ * picture that settled before hydration is sent a task after the avatar
27
+ * hydrates, so a page's own scripts are listening by then.
19
28
  *
20
29
  * @since 0.1.0
21
30
  * @status stable
@@ -30,6 +39,10 @@ export declare const initialsOf: (name: string) => string;
30
39
  *
31
40
  * @csspart image - The image, when one is loading or loaded.
32
41
  * @csspart initials - The initials shown when there is no usable image.
42
+ *
43
+ * @cssstate error - The picture failed, or there is none, and the initials show.
44
+ * @cssstate loaded - The picture arrived.
45
+ * @cssstate loading - The picture is on its way.
33
46
  */
34
47
  export declare class HelixHeadlessAvatar extends HelixElement {
35
48
  /**
@@ -43,6 +56,23 @@ export declare class HelixHeadlessAvatar extends HelixElement {
43
56
  * same idea.
44
57
  */
45
58
  fallbackDelay?: number;
59
+ /**
60
+ * The letters shown where no picture loaded, such as `GH`, in place of the
61
+ * ones taken from `name`.
62
+ *
63
+ * For a name whose initials are not its first and last letters, or an
64
+ * entity with a short mark of its own. Absent, the first letters of the
65
+ * first and last words of `name` are shown.
66
+ */
67
+ initials?: string;
68
+ /**
69
+ * When the browser fetches the picture: `lazy` waits until it is near the
70
+ * screen, as an `<img loading="lazy">` does, and `eager` fetches it at once.
71
+ *
72
+ * Absent is the browser's own default, which is `eager`. `lazy` suits a long
73
+ * list of people, most of them off screen.
74
+ */
75
+ loading?: 'eager' | 'lazy';
46
76
  /**
47
77
  * Name of the person or entity.
48
78
  *
@@ -45,6 +45,9 @@ let HelixHeadlessAvatar = class HelixHeadlessAvatar extends HelixElement {
45
45
  label: this.name,
46
46
  role: this.name === '' ? '' : 'img',
47
47
  });
48
+ this.toggleState('error', this.status === 'error');
49
+ this.toggleState('loaded', this.status === 'loaded');
50
+ this.toggleState('loading', this.status === 'loading');
48
51
  }
49
52
  firstUpdated(changed) {
50
53
  super.firstUpdated(changed);
@@ -91,6 +94,7 @@ let HelixHeadlessAvatar = class HelixHeadlessAvatar extends HelixElement {
91
94
  part="image"
92
95
  src=${this.src}
93
96
  alt=""
97
+ loading=${this.loading ?? nothing}
94
98
  ?hidden=${standIn}
95
99
  @error=${this.handleError}
96
100
  @load=${this.handleLoad}
@@ -100,13 +104,19 @@ let HelixHeadlessAvatar = class HelixHeadlessAvatar extends HelixElement {
100
104
  }
101
105
  renderInitials() {
102
106
  return html `<slot>
103
- <span part="initials" aria-hidden="true">${initialsOf(this.name)}</span>
107
+ <span part="initials" aria-hidden="true">${this.initials ?? initialsOf(this.name)}</span>
104
108
  </slot>`;
105
109
  }
106
110
  };
107
111
  __decorate([
108
112
  property({ attribute: 'fallback-delay', type: Number })
109
113
  ], HelixHeadlessAvatar.prototype, "fallbackDelay", void 0);
114
+ __decorate([
115
+ property()
116
+ ], HelixHeadlessAvatar.prototype, "initials", void 0);
117
+ __decorate([
118
+ property()
119
+ ], HelixHeadlessAvatar.prototype, "loading", void 0);
110
120
  __decorate([
111
121
  property()
112
122
  ], HelixHeadlessAvatar.prototype, "name", void 0);
@@ -0,0 +1,14 @@
1
+ /** Whether the value counts nothing, in which case there is no mark. */
2
+ export declare const badgeBlank: (given: string) => boolean;
3
+ /** Whether the count is past `max`, which the mark shows as `{max}+`. */
4
+ export declare const badgeCapped: (given: string, max: number | undefined) => boolean;
5
+ /**
6
+ * What the mark reads once the cap has been applied: the value as given, or
7
+ * written with `options` in `locale` where they are set and it is a number.
8
+ */
9
+ export declare const badgeText: (given: string, max: number | undefined, locale: string, options: Intl.NumberFormatOptions | undefined) => string;
10
+ /**
11
+ * What a reader hears for the mark: `label` with `{count}` filled, or the text
12
+ * alone, and nothing for a blank mark or an unnamed dot.
13
+ */
14
+ export declare const badgeWords: (text: string, label: string, blank: boolean) => string;
@@ -0,0 +1,20 @@
1
+ import { fillTemplate, formatNumber } from '@fusion.dev/helix-core';
2
+ export const badgeBlank = (given) => given.trim() !== '' && Number(given) === 0;
3
+ export const badgeCapped = (given, max) => {
4
+ const count = Number(given);
5
+ return max !== undefined && Number.isFinite(count) && count > max;
6
+ };
7
+ export const badgeText = (given, max, locale, options) => {
8
+ const write = (count) => options ? formatNumber(count, locale, options) : String(count);
9
+ if (badgeCapped(given, max)) {
10
+ return `${write(max)}+`;
11
+ }
12
+ const count = Number(given);
13
+ return options && given.trim() !== '' && Number.isFinite(count) ? write(count) : given;
14
+ };
15
+ export const badgeWords = (text, label, blank) => {
16
+ if (blank || (text === '' && label === '')) {
17
+ return '';
18
+ }
19
+ return fillTemplate(label, { count: text }) || text;
20
+ };
@@ -1,5 +1,5 @@
1
1
  import { HelixElement } from '@fusion.dev/helix-core';
2
- import { type TemplateResult } from 'lit';
2
+ import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  /**
4
4
  * @summary A count or a dot pinned to the corner of another element.
5
5
  *
@@ -14,15 +14,20 @@ import { type TemplateResult } from 'lit';
14
14
  * - Any other value shows the value. Above `max`, the indicator shows `{max}+`,
15
15
  * so its width stays the same as the count grows.
16
16
  *
17
+ * `format-options` writes a count with `Intl.NumberFormat`, in `locale`:
18
+ * `format-options='{"notation":"compact"}'` shows 1,200 as `1.2K`. Absent, the
19
+ * count is shown as it was given.
20
+ *
17
21
  * A count is announced from its own text, and `label` replaces that with a
18
22
  * fuller name, such as `4 unread`. A dot needs a `label`. Without one, the dot
19
23
  * is a colored circle that screen readers do not announce.
20
24
  *
21
- * **A badge wrapped around a control is not part of the control's name.** It
22
- * is a status of its own, read when it changes and when a reader moves to it,
23
- * so focusing a button inside a badge announces the button's name alone. A
24
- * reference from the control to the count would point into the badge's shadow
25
- * root, which the platform does not allow.
25
+ * **A badge wrapped around a control describes it.** The control is the first
26
+ * element in the badge that takes focus, and its description is the badge's
27
+ * words, so focusing `<helix-badge value="8" label="{count} unread"><button>Inbox
28
+ * </button></helix-badge>` announces "Inbox, button, 8 unread", current as the
29
+ * count changes. A control that already has a description keeps its own. The
30
+ * count is also a status of its own, read when it changes.
26
31
  *
27
32
  * **Put the badge inside the control to have its count read with the
28
33
  * control's name**, as Web Awesome and Shoelace do: `<button>Inbox
@@ -39,8 +44,20 @@ import { type TemplateResult } from 'lit';
39
44
  * @slot - The element being decorated.
40
45
  *
41
46
  * @csspart indicator - The count, or the dot when there is no value.
47
+ *
48
+ * @cssstate blank - The value is zero, so there is no mark.
49
+ * @cssstate capped - The count is past `max`, so the mark shows `{max}+`.
50
+ * @cssstate dot - There is no value, so the mark is a dot.
42
51
  */
43
52
  export declare class HelixHeadlessBadge extends HelixElement {
53
+ /**
54
+ * `Intl.NumberFormat` options a count is written with, such as
55
+ * `{"notation":"compact"}` for `1.2K`, written as JSON in the attribute.
56
+ *
57
+ * Absent, a count is shown as it was given. Text that is not a number is
58
+ * shown as it is either way.
59
+ */
60
+ formatOptions?: Intl.NumberFormatOptions;
44
61
  /**
45
62
  * The badge's name, read by screen readers.
46
63
  *
@@ -49,6 +66,12 @@ export declare class HelixHeadlessBadge extends HelixElement {
49
66
  * stays current as `value` changes, with no label of yours to keep in step.
50
67
  */
51
68
  label: string;
69
+ /**
70
+ * The locale a count is written in under `format-options`, such as `de`.
71
+ *
72
+ * Absent uses the runtime's own.
73
+ */
74
+ locale: string;
52
75
  /**
53
76
  * The largest number the badge shows.
54
77
  *
@@ -75,8 +98,36 @@ export declare class HelixHeadlessBadge extends HelixElement {
75
98
  private get given();
76
99
  /** Whether the value counts nothing, in which case there is no mark. */
77
100
  private get blank();
101
+ /** Whether the count is past `max`, which the mark shows as `{max}+`. */
102
+ private get capped();
78
103
  /** What the indicator reads, once the cap has been applied. */
79
104
  private get text();
105
+ /** What a reader hears for the mark, or nothing for a blank or unnamed one. */
106
+ private get words();
107
+ /** The control the badge describes, while it describes one. */
108
+ private described;
109
+ /**
110
+ * The first element the badge wraps that takes focus: one with a tab stop,
111
+ * or a component that hands its focus on.
112
+ */
113
+ private wrapped;
114
+ protected firstUpdated(changed: PropertyValues): void;
115
+ /**
116
+ * Points the wrapped control's description at the badge, which carries its
117
+ * words as its own label, or takes the pointer back.
118
+ *
119
+ * **The badge itself and not the count**, because a reference from the
120
+ * control into the badge's shadow root is one the platform drops, and the
121
+ * badge is in the control's own tree. A control the page described is left
122
+ * alone.
123
+ */
124
+ private describe;
125
+ private undescribe;
126
+ private readonly handleSlotchange;
127
+ disconnectedCallback(): void;
128
+ connectedCallback(): void;
129
+ protected willUpdate(changed: PropertyValues): void;
130
+ protected updated(changed: PropertyValues): void;
80
131
  protected render(): TemplateResult;
81
132
  }
82
133
  declare global {
@@ -4,46 +4,115 @@ 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, fillTemplate, HelixElement } from '@fusion.dev/helix-core';
7
+ import { customElement, focusTarget, HelixElement } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ import { badgeBlank, badgeCapped, badgeText, badgeWords } from '../count.js';
10
11
  let HelixHeadlessBadge = class HelixHeadlessBadge extends HelixElement {
11
12
  constructor() {
12
13
  super(...arguments);
13
14
  this.label = '';
15
+ this.locale = '';
14
16
  this.value = '';
17
+ this.handleSlotchange = () => {
18
+ this.describe();
19
+ };
15
20
  }
16
21
  get given() {
17
22
  return String(this.value ?? '');
18
23
  }
19
24
  get blank() {
20
- return this.given.trim() !== '' && Number(this.given) === 0;
25
+ return badgeBlank(this.given);
26
+ }
27
+ get capped() {
28
+ return badgeCapped(this.given, this.max);
21
29
  }
22
30
  get text() {
23
- const count = Number(this.given);
24
- if (this.max !== undefined && Number.isFinite(count) && count > this.max) {
25
- return `${this.max}+`;
31
+ return badgeText(this.given, this.max, this.locale, this.formatOptions);
32
+ }
33
+ get words() {
34
+ return badgeWords(this.text, this.label, this.blank);
35
+ }
36
+ wrapped() {
37
+ const found = this.renderRoot
38
+ .querySelector('slot:not([name])')
39
+ ?.assignedElements({ flatten: true })
40
+ .find((element) => element instanceof HTMLElement &&
41
+ (element.tabIndex >= 0 || element.shadowRoot?.delegatesFocus === true));
42
+ return found && focusTarget(found);
43
+ }
44
+ firstUpdated(changed) {
45
+ super.firstUpdated(changed);
46
+ requestAnimationFrame(() => this.describe());
47
+ }
48
+ describe() {
49
+ const words = this.words;
50
+ const control = words === '' ? undefined : this.wrapped();
51
+ if (this.described && this.described !== control) {
52
+ this.undescribe();
53
+ }
54
+ if (!control || !('ariaDescribedByElements' in control)) {
55
+ return;
56
+ }
57
+ const own = control.getAttribute('aria-describedby') || control.ariaDescribedByElements?.length;
58
+ if (control !== this.described && own) {
59
+ return;
60
+ }
61
+ this.internals.ariaLabel = words;
62
+ control.ariaDescribedByElements = [this];
63
+ this.described = control;
64
+ }
65
+ undescribe() {
66
+ if (this.described?.ariaDescribedByElements?.includes(this)) {
67
+ this.described.ariaDescribedByElements = null;
26
68
  }
27
- return this.given;
69
+ this.described = undefined;
70
+ this.internals.ariaLabel = null;
71
+ }
72
+ disconnectedCallback() {
73
+ super.disconnectedCallback();
74
+ this.undescribe();
75
+ }
76
+ connectedCallback() {
77
+ super.connectedCallback();
78
+ if (this.hasUpdated) {
79
+ this.describe();
80
+ }
81
+ }
82
+ willUpdate(changed) {
83
+ super.willUpdate(changed);
84
+ this.toggleState('capped', this.capped);
85
+ this.toggleState('dot', this.given.trim() === '');
86
+ this.toggleState('blank', this.blank);
87
+ }
88
+ updated(changed) {
89
+ super.updated(changed);
90
+ this.describe();
28
91
  }
29
92
  render() {
30
93
  const blank = this.blank;
31
94
  const text = this.text;
32
95
  const announced = !blank && (text !== '' || this.label !== '');
33
- return html `<slot></slot>
96
+ return html `<slot @slotchange=${this.handleSlotchange}></slot>
34
97
  <span
35
98
  part="indicator"
36
99
  data-blank=${blank ? '' : nothing}
37
100
  data-single=${text.length <= 1 ? '' : nothing}
38
101
  role="status"
39
- aria-label=${announced ? fillTemplate(this.label, { count: text }) || text : nothing}
102
+ aria-label=${announced ? this.words : nothing}
40
103
  >${blank ? html `<span aria-hidden="true">${text}</span>` : text}</span
41
104
  >`;
42
105
  }
43
106
  };
107
+ __decorate([
108
+ property({ attribute: 'format-options', type: Object })
109
+ ], HelixHeadlessBadge.prototype, "formatOptions", void 0);
44
110
  __decorate([
45
111
  property()
46
112
  ], HelixHeadlessBadge.prototype, "label", void 0);
113
+ __decorate([
114
+ property()
115
+ ], HelixHeadlessBadge.prototype, "locale", void 0);
47
116
  __decorate([
48
117
  property({ type: Number })
49
118
  ], HelixHeadlessBadge.prototype, "max", void 0);
@@ -4,10 +4,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { byRow, CHART_PLOT, customElement, drawTooltip, extent, formatNumbers, HelixElement, linear, linePath, MixinChartSource, PLOT_HEIGHT, PLOT_WIDTH, seriesIndex, seriesNames, ticks, unbroken, } from '@fusion.dev/helix-core';
7
+ import { byRow, CHART_PLOT, customElement, drawTooltip, extent, formatNumbers, HelixElement, linear, linePath, MixinChartSource, PLOT_HEIGHT, PLOT_WIDTH, seriesIndex, seriesKey, seriesNames, ticks, unbroken, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing, svg } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
- import { stackEnds, stackSpans } from '../stack.js';
10
+ import { stackEnds, stackedReadings, stackSpans } from '../stack.js';
11
11
  import '../../tooltip/index.js';
12
12
  let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartSource(HelixElement) {
13
13
  constructor() {
@@ -38,23 +38,13 @@ let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartSource
38
38
  return html `<div id=${CHART_PLOT} part="plot"></div>`;
39
39
  }
40
40
  const scaled = this.scaled;
41
- const own = (one) => scaled.has(one.name.trim().toLowerCase());
41
+ const own = (one) => scaled.has(seriesKey(one.name));
42
42
  const shown = series.filter((one) => this.showsSeries(one.name));
43
43
  const values = shown.flatMap((one) => one.points.map((point) => point.value));
44
44
  const lined = this.lined;
45
- const readingsOf = (group) => {
46
- if (!this.stacked) {
47
- return group.flatMap((one) => one.points.map((point) => point.value));
48
- }
49
- const columns = group.filter((one) => !lined.has(one.name.trim().toLowerCase()));
50
- const slots = columns.map((one) => byRow(one, categories.length));
51
- return [
52
- ...group
53
- .filter((one) => lined.has(one.name.trim().toLowerCase()))
54
- .flatMap((one) => one.points.map((point) => point.value)),
55
- ...stackEnds(categories.map((_, at) => slots.map((one) => one[at]?.value))),
56
- ];
57
- };
45
+ const readingsOf = (group) => this.stacked
46
+ ? stackedReadings(group, categories.length, (one) => lined.has(seriesKey(one.name)))
47
+ : group.flatMap((one) => one.points.map((point) => point.value));
58
48
  const on = (which) => {
59
49
  const found = readingsOf(shown.filter(which));
60
50
  return found.length > 0 ? found : values.length > 0 ? values : [0];
@@ -96,11 +86,11 @@ let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartSource
96
86
  const slot = 100 / categories.length;
97
87
  const lined = this.lined;
98
88
  const scaled = this.scaled;
99
- const own = (one) => scaled.has(one.name.trim().toLowerCase());
89
+ const own = (one) => scaled.has(seriesKey(one.name));
100
90
  const against = (one) => z !== undefined && own(one) ? z : y;
101
91
  const columns = series
102
92
  .map((one, index) => ({ one, slots: byRow(one, categories.length), tone: index }))
103
- .filter(({ one }) => !lined.has(one.name.trim().toLowerCase()) && this.showsSeries(one.name));
93
+ .filter(({ one }) => !lined.has(seriesKey(one.name)) && this.showsSeries(one.name));
104
94
  const abreast = this.stacked ? 1 : columns.length;
105
95
  const stride = (slot * 0.72) / Math.max(abreast, 1);
106
96
  const gap = abreast > 1 ? stride * 0.08 : 0;
@@ -178,7 +168,7 @@ let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartSource
178
168
  : bar(point.value, index, depth, tone, against(one));
179
169
  })}
180
170
  </g>`)}
181
- ${series.map((one) => lined.has(one.name.trim().toLowerCase()) && this.showsSeries(one.name)
171
+ ${series.map((one) => lined.has(seriesKey(one.name)) && this.showsSeries(one.name)
182
172
  ? this.renderLine(one, series.indexOf(one), slot, against(one), sideways)
183
173
  : nothing)}
184
174
  </svg>
@@ -269,8 +259,9 @@ let HelixHeadlessBarChart = class HelixHeadlessBarChart extends MixinChartSource
269
259
  .map((one) => byRow(one, this.readings)[at]?.value)
270
260
  .filter((one) => one !== undefined);
271
261
  const values = this.stacked ? stackEnds([reached]) : reached;
262
+ const lined = this.lined;
272
263
  const all = this.stacked
273
- ? stackEnds(Array.from({ length: this.readings }, (_, row) => shown.map((one) => byRow(one, this.readings)[row]?.value)))
264
+ ? stackedReadings(shown, this.readings, (one) => lined.has(seriesKey(one.name)))
274
265
  : shown.flatMap((one) => one.points.map((point) => point.value));
275
266
  const [low, high] = extent(all.length > 0 ? all : [0]);
276
267
  const domain = [Math.min(0, low), Math.max(0, high)];
@@ -1,3 +1,4 @@
1
+ import { type Series } from '@fusion.dev/helix-core';
1
2
  /** Where a column starts and ends along the measure, in the data's own units. */
2
3
  export type Span = readonly [from: number, to: number];
3
4
  /**
@@ -13,3 +14,12 @@ export declare const stackSpans: (values: readonly (number | undefined)[]) => (S
13
14
  * of negatives. `categories` holds each category's readings, one per column.
14
15
  */
15
16
  export declare const stackEnds: (categories: readonly (readonly (number | undefined)[])[]) => number[];
17
+ /**
18
+ * The readings a stacked scale has to hold, over `count` categories: every
19
+ * reading of a series drawn as a line, which `lined` says, and the top and
20
+ * foot of each category's stack of the others.
21
+ *
22
+ * The plot's scale and the tooltip's placing ask the same question, and
23
+ * answered apart they disagreed about the lines.
24
+ */
25
+ export declare const stackedReadings: (group: readonly Series[], count: number, lined: (one: Series) => boolean) => number[];
@@ -1,3 +1,4 @@
1
+ import { byRow } from '@fusion.dev/helix-core';
1
2
  export const stackSpans = (values) => {
2
3
  let up = 0;
3
4
  let down = 0;
@@ -17,3 +18,10 @@ export const stackSpans = (values) => {
17
18
  });
18
19
  };
19
20
  export const stackEnds = (categories) => categories.flatMap((values) => stackSpans(values).flatMap((span) => (span === undefined ? [] : [span[1]])));
21
+ export const stackedReadings = (group, count, lined) => {
22
+ const slots = group.filter((one) => !lined(one)).map((one) => byRow(one, count));
23
+ return [
24
+ ...group.filter(lined).flatMap((one) => one.points.map((point) => point.value)),
25
+ ...stackEnds(Array.from({ length: count }, (_, at) => slots.map((one) => one[at]?.value))),
26
+ ];
27
+ };
@@ -1,16 +1,36 @@
1
1
  import { HelixElement } from '@fusion.dev/helix-core';
2
- import { type PropertyValues, type TemplateResult } from 'lit';
2
+ import { type CSSResultGroup, type PropertyValues, type TemplateResult } from 'lit';
3
3
  /**
4
4
  * @summary A passage set off from the prose around it.
5
5
  *
6
6
  * @description
7
- * Renders a `<figure>` holding the `<blockquote>` and a `<figcaption>` for the
7
+ * Renders a figure holding the `<blockquote>` and a caption for the
8
8
  * attribution, the structure the HTML spec describes. The attribution sits
9
9
  * outside the quotation because it is about the quotation, and it names the
10
10
  * figure, so a screen reader reads the source as the figure's caption.
11
11
  *
12
- * The figure keeps the browser's default margins on this tier. Set
13
- * `::part(figure) { margin: 0 }` where they are unwanted.
12
+ * **The figure is a `<div role="figure">`**, so the headless tier draws no
13
+ * space around the quotation. A `<figure>` takes a 40px indent and a line of
14
+ * space above and below from the browser's own sheet, which every page had to
15
+ * reset. The `<blockquote>` keeps its own margins, as a bare one does. A
16
+ * screen reader meets the same figure, named by its caption.
17
+ *
18
+ * **A figure only while there is an attribution.** With nothing in the caption
19
+ * the figure has no name and nothing to say, so the role and its name are
20
+ * dropped and a reader meets the quotation alone. A server cannot see what is
21
+ * slotted, so it serves the figure, and the client drops it after hydration;
22
+ * an `attribution` written as words is served exactly.
23
+ *
24
+ * **Quotation marks follow the language**, under `marks`. The opening mark is
25
+ * the one the browser sets for a `<q>` in the element's language, „ under
26
+ * `lang="de"` and « under `lang="fr"`, and a `Quote` inside the passage takes
27
+ * the inner marks. The mark is drawn, not read: a screen reader hears the
28
+ * passage. A passage under `marks` that starts with a mark typed into the text
29
+ * would show two, and warns once, with the runtime kind `typed-marks`.
30
+ *
31
+ * **`cite` is the source's URL**, which the browser keeps and does not show.
32
+ * Words in it, such as the author's name, warn once, with the runtime kind
33
+ * `cite-not-url`.
14
34
  *
15
35
  * For a quotation inside a sentence, use `Quote`.
16
36
  *
@@ -21,17 +41,37 @@ import { type PropertyValues, type TemplateResult } from 'lit';
21
41
  * @documentation https://fusion.dev/helix/components/blockquote
22
42
  *
23
43
  * @slot - The quoted passage.
24
- * @slot attribution - Who said it, and where.
44
+ * @slot attribution - Who said it, and where. Replaces the words of `attribution`.
25
45
  *
26
- * @csspart attribution - The `<figcaption>` carrying the source.
46
+ * @csspart attribution - The caption carrying the source.
27
47
  * @csspart blockquote - The quotation.
28
- * @csspart figure - The `<figure>` holding the quotation and its attribution.
48
+ * @csspart figure - The figure holding the quotation and its attribution, a `<div>` with `role="figure"` while the attribution has words.
29
49
  */
30
50
  export declare class HelixHeadlessBlockquote extends HelixElement {
51
+ static styles: CSSResultGroup;
31
52
  /**
32
- * The URL of the source the passage came from.
53
+ * Who said it, and where, as words, such as "Maria Lopez, operations
54
+ * manager". The `attribution` slot replaces them, for markup such as a link.
55
+ *
56
+ * Words are served with the figure they name, where a server cannot see a
57
+ * slotted attribution.
58
+ */
59
+ attribution: string;
60
+ /**
61
+ * The URL of the source the passage came from. Who said it goes in
62
+ * `attribution`: a `cite` with words in it warns once, with the runtime kind
63
+ * `cite-not-url`.
33
64
  */
34
65
  cite: string;
66
+ /**
67
+ * Whether to draw an opening quotation mark before the passage, in the
68
+ * element's language. Leave the marks out of the text.
69
+ */
70
+ marks: boolean;
71
+ /** Whether this blockquote has said its passage starts with a typed mark, so it says so once. */
72
+ private warned;
73
+ /** Whether this blockquote has said its `cite` holds words, so it says so once. */
74
+ private citeWarned;
35
75
  /**
36
76
  * Says on the caption whether there is an attribution in it.
37
77
  *
@@ -44,8 +84,26 @@ export declare class HelixHeadlessBlockquote extends HelixElement {
44
84
  * rendered, which React reports on hydration.
45
85
  */
46
86
  private markEmpty;
87
+ /**
88
+ * Reads the passage for a mark typed at its start, which `marks` would
89
+ * double. Only the start: the mark drawn is an opening one.
90
+ */
91
+ private readonly readPassage;
92
+ /**
93
+ * Reads `cite` for words where the source's URL belongs, the common mistake
94
+ * of naming the author there. A URL holds no spaces, so words with a space
95
+ * between them are enough to tell.
96
+ */
97
+ private readCite;
98
+ protected firstUpdated(changed: PropertyValues): void;
47
99
  protected updated(changed: PropertyValues): void;
48
100
  protected render(): TemplateResult;
101
+ /**
102
+ * The caption, with the words of `attribution` as its slot's fallback,
103
+ * behind a seam a tier can move. The words are in an element, so the region
104
+ * counts them as its own.
105
+ */
106
+ protected renderAttribution(): TemplateResult;
49
107
  }
50
108
  declare global {
51
109
  interface HTMLElementTagNameMap {