@fusion.dev/helix-core 0.145.0 → 0.147.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/custom-elements.json +6585 -1920
  2. package/dist/controllers/aria-forward-controller/aria-forward-controller.d.ts +3 -2
  3. package/dist/controllers/aria-forward-controller/aria-forward-controller.js +8 -17
  4. package/dist/controllers/chart-pointer-controller/chart-pointer-controller.d.ts +71 -3
  5. package/dist/controllers/chart-pointer-controller/chart-pointer-controller.js +50 -9
  6. package/dist/controllers/chart-pointer-controller/reading-step.d.ts +7 -1
  7. package/dist/controllers/chart-pointer-controller/reading-step.js +5 -0
  8. package/dist/controllers/copy-controller/copy-controller.d.ts +4 -1
  9. package/dist/controllers/copy-controller/copy-controller.js +2 -1
  10. package/dist/controllers/countdown-controller/countdown-controller.d.ts +4 -1
  11. package/dist/controllers/countdown-controller/countdown-controller.js +3 -1
  12. package/dist/controllers/keyboard-navigation-controller/keyboard-navigation-controller.d.ts +14 -55
  13. package/dist/controllers/keyboard-navigation-controller/keyboard-navigation-controller.js +7 -39
  14. package/dist/controllers/relative-clock-controller/relative-clock-controller.d.ts +44 -0
  15. package/dist/controllers/relative-clock-controller/relative-clock-controller.js +31 -0
  16. package/dist/controllers/source-controller/source-controller.d.ts +10 -3
  17. package/dist/controllers/source-controller/source-controller.js +9 -4
  18. package/dist/controllers/swipe-controller/swipe-controller.d.ts +10 -1
  19. package/dist/controllers/swipe-controller/swipe-controller.js +1 -1
  20. package/dist/controllers/virtualize-controller/virtualize-controller.d.ts +48 -1
  21. package/dist/controllers/virtualize-controller/virtualize-controller.js +52 -7
  22. package/dist/events/action.d.ts +12 -0
  23. package/dist/events/action.js +6 -0
  24. package/dist/events/activate.d.ts +22 -0
  25. package/dist/events/activate.js +11 -0
  26. package/dist/events/aura-fallback.d.ts +12 -0
  27. package/dist/events/aura-fallback.js +11 -0
  28. package/dist/events/band.d.ts +13 -0
  29. package/dist/events/band.js +11 -0
  30. package/dist/events/before-activate.d.ts +24 -0
  31. package/dist/events/before-activate.js +11 -0
  32. package/dist/events/before-change.d.ts +26 -0
  33. package/dist/events/before-change.js +11 -0
  34. package/dist/events/before-close.d.ts +6 -0
  35. package/dist/events/before-close.js +11 -0
  36. package/dist/events/before-collapse.d.ts +6 -0
  37. package/dist/events/before-collapse.js +11 -0
  38. package/dist/events/before-edit.d.ts +6 -0
  39. package/dist/events/before-edit.js +11 -0
  40. package/dist/events/before-move.d.ts +17 -0
  41. package/dist/events/before-move.js +11 -0
  42. package/dist/events/before-open.d.ts +17 -0
  43. package/dist/events/before-open.js +11 -0
  44. package/dist/events/before-panel-resize.d.ts +13 -0
  45. package/dist/events/before-panel-resize.js +11 -0
  46. package/dist/events/before-pin.d.ts +6 -0
  47. package/dist/events/before-pin.js +11 -0
  48. package/dist/events/before-reconnect.d.ts +14 -0
  49. package/dist/events/before-reconnect.js +11 -0
  50. package/dist/events/before-relabel.d.ts +15 -0
  51. package/dist/events/before-relabel.js +11 -0
  52. package/dist/events/before-resize.d.ts +6 -0
  53. package/dist/events/before-resize.js +11 -0
  54. package/dist/events/before-split.d.ts +12 -0
  55. package/dist/events/before-split.js +11 -0
  56. package/dist/events/before-toggle.d.ts +23 -0
  57. package/dist/events/before-toggle.js +11 -0
  58. package/dist/events/canvas-edit.d.ts +16 -0
  59. package/dist/events/canvas-edit.js +11 -0
  60. package/dist/events/canvas-pan.d.ts +13 -0
  61. package/dist/events/canvas-pan.js +11 -0
  62. package/dist/events/canvas-view.d.ts +14 -0
  63. package/dist/events/canvas-view.js +11 -0
  64. package/dist/events/canvas-zoom.d.ts +6 -0
  65. package/dist/events/canvas-zoom.js +11 -0
  66. package/dist/events/caret.d.ts +17 -0
  67. package/dist/events/caret.js +11 -0
  68. package/dist/events/clear.d.ts +11 -0
  69. package/dist/events/clear.js +6 -0
  70. package/dist/events/collapse.d.ts +12 -0
  71. package/dist/events/collapse.js +11 -0
  72. package/dist/events/complete.d.ts +26 -0
  73. package/dist/events/complete.js +11 -0
  74. package/dist/events/connect.d.ts +14 -0
  75. package/dist/events/connect.js +11 -0
  76. package/dist/events/console.d.ts +13 -0
  77. package/dist/events/console.js +11 -0
  78. package/dist/events/copy-error.d.ts +9 -0
  79. package/dist/events/copy-error.js +6 -0
  80. package/dist/events/copy.d.ts +12 -0
  81. package/dist/events/copy.js +10 -0
  82. package/dist/events/create.d.ts +18 -0
  83. package/dist/events/create.js +11 -0
  84. package/dist/events/details.d.ts +459 -0
  85. package/dist/events/details.js +1 -0
  86. package/dist/events/dismiss.d.ts +16 -0
  87. package/dist/events/dismiss.js +11 -0
  88. package/dist/events/edit.d.ts +12 -0
  89. package/dist/events/edit.js +11 -0
  90. package/dist/events/end.d.ts +9 -0
  91. package/dist/events/end.js +6 -0
  92. package/dist/events/events.d.ts +113 -1478
  93. package/dist/events/events.js +93 -863
  94. package/dist/events/expand.d.ts +10 -0
  95. package/dist/events/expand.js +11 -0
  96. package/dist/events/facet.d.ts +17 -0
  97. package/dist/events/facet.js +11 -0
  98. package/dist/events/filter.d.ts +12 -0
  99. package/dist/events/filter.js +11 -0
  100. package/dist/events/filtered.d.ts +12 -0
  101. package/dist/events/filtered.js +11 -0
  102. package/dist/events/graph-filter.d.ts +10 -0
  103. package/dist/events/graph-filter.js +11 -0
  104. package/dist/events/graph-layout.d.ts +10 -0
  105. package/dist/events/graph-layout.js +11 -0
  106. package/dist/events/graph-pan.d.ts +9 -0
  107. package/dist/events/graph-pan.js +11 -0
  108. package/dist/events/graph-part-change.d.ts +10 -0
  109. package/dist/events/graph-part-change.js +11 -0
  110. package/dist/events/graph-ready.d.ts +8 -0
  111. package/dist/events/graph-ready.js +6 -0
  112. package/dist/events/graph-signal.d.ts +11 -0
  113. package/dist/events/graph-signal.js +11 -0
  114. package/dist/events/graph-zoom.d.ts +6 -0
  115. package/dist/events/graph-zoom.js +11 -0
  116. package/dist/events/history.d.ts +16 -0
  117. package/dist/events/history.js +11 -0
  118. package/dist/events/load-more.d.ts +12 -0
  119. package/dist/events/load-more.js +6 -0
  120. package/dist/events/load.d.ts +12 -0
  121. package/dist/events/load.js +6 -0
  122. package/dist/events/map-cluster.d.ts +15 -0
  123. package/dist/events/map-cluster.js +11 -0
  124. package/dist/events/map-pan.d.ts +18 -0
  125. package/dist/events/map-pan.js +11 -0
  126. package/dist/events/map-part-change.d.ts +16 -0
  127. package/dist/events/map-part-change.js +11 -0
  128. package/dist/events/map-ready.d.ts +15 -0
  129. package/dist/events/map-ready.js +6 -0
  130. package/dist/events/map-rotate.d.ts +9 -0
  131. package/dist/events/map-rotate.js +11 -0
  132. package/dist/events/map-tilt.d.ts +9 -0
  133. package/dist/events/map-tilt.js +11 -0
  134. package/dist/events/map-zoom.d.ts +13 -0
  135. package/dist/events/map-zoom.js +11 -0
  136. package/dist/events/move.d.ts +11 -0
  137. package/dist/events/move.js +11 -0
  138. package/dist/events/names.d.ts +18 -0
  139. package/dist/events/names.js +13 -0
  140. package/dist/events/navigate.d.ts +13 -0
  141. package/dist/events/navigate.js +11 -0
  142. package/dist/events/next.d.ts +23 -0
  143. package/dist/events/next.js +11 -0
  144. package/dist/events/panel-resize.d.ts +12 -0
  145. package/dist/events/panel-resize.js +11 -0
  146. package/dist/events/pin.d.ts +12 -0
  147. package/dist/events/pin.js +11 -0
  148. package/dist/events/press.d.ts +19 -0
  149. package/dist/events/press.js +11 -0
  150. package/dist/events/preview.d.ts +14 -0
  151. package/dist/events/preview.js +11 -0
  152. package/dist/events/previous.d.ts +6 -0
  153. package/dist/events/previous.js +11 -0
  154. package/dist/events/range-change.d.ts +10 -0
  155. package/dist/events/range-change.js +11 -0
  156. package/dist/events/read.d.ts +19 -0
  157. package/dist/events/read.js +11 -0
  158. package/dist/events/reconnect.d.ts +6 -0
  159. package/dist/events/reconnect.js +11 -0
  160. package/dist/events/reject.d.ts +13 -0
  161. package/dist/events/reject.js +11 -0
  162. package/dist/events/relabel.d.ts +6 -0
  163. package/dist/events/relabel.js +11 -0
  164. package/dist/events/remove.d.ts +12 -0
  165. package/dist/events/remove.js +11 -0
  166. package/dist/events/reorder.d.ts +18 -0
  167. package/dist/events/reorder.js +11 -0
  168. package/dist/events/reordered.d.ts +12 -0
  169. package/dist/events/reordered.js +11 -0
  170. package/dist/events/resize.d.ts +19 -0
  171. package/dist/events/resize.js +11 -0
  172. package/dist/events/resized.d.ts +16 -0
  173. package/dist/events/resized.js +11 -0
  174. package/dist/events/sample-end.d.ts +5 -0
  175. package/dist/events/sample-end.js +6 -0
  176. package/dist/events/sample-start.d.ts +18 -0
  177. package/dist/events/sample-start.js +6 -0
  178. package/dist/events/scrolled.d.ts +32 -0
  179. package/dist/events/scrolled.js +11 -0
  180. package/dist/events/select.d.ts +12 -0
  181. package/dist/events/select.js +11 -0
  182. package/dist/events/selected.d.ts +12 -0
  183. package/dist/events/selected.js +11 -0
  184. package/dist/events/send.d.ts +18 -0
  185. package/dist/events/send.js +11 -0
  186. package/dist/events/shortcut.d.ts +13 -0
  187. package/dist/events/shortcut.js +11 -0
  188. package/dist/events/sort.d.ts +17 -0
  189. package/dist/events/sort.js +11 -0
  190. package/dist/events/sorted.d.ts +15 -0
  191. package/dist/events/sorted.js +11 -0
  192. package/dist/events/split.d.ts +12 -0
  193. package/dist/events/split.js +11 -0
  194. package/dist/events/toggle.d.ts +15 -0
  195. package/dist/events/toggle.js +11 -0
  196. package/dist/events/tour-ask.d.ts +16 -0
  197. package/dist/events/tour-ask.js +11 -0
  198. package/dist/events/tour-status.d.ts +14 -0
  199. package/dist/events/tour-status.js +11 -0
  200. package/dist/events/typing.d.ts +10 -0
  201. package/dist/events/typing.js +11 -0
  202. package/dist/helix-element/helix-element.js +9 -43
  203. package/dist/helix-element/react-bridge.d.ts +23 -0
  204. package/dist/helix-element/react-bridge.js +2 -2
  205. package/dist/helix-form-element/helix-form-element.d.ts +5 -20
  206. package/dist/helix-form-element/helix-form-element.js +4 -56
  207. package/dist/index.d.ts +30 -9
  208. package/dist/index.js +30 -9
  209. package/dist/mixins/mixin-chart-source/mixin-chart-source.d.ts +24 -2
  210. package/dist/mixins/mixin-chart-source/mixin-chart-source.js +23 -1
  211. package/dist/mixins/mixin-controller-active/mixin-controller-active.js +4 -3
  212. package/dist/mixins/mixin-controller-checked/mixin-controller-checked.d.ts +5 -2
  213. package/dist/mixins/mixin-controller-checked/mixin-controller-checked.js +2 -1
  214. package/dist/mixins/mixin-controller-value/mixin-controller-value.d.ts +4 -2
  215. package/dist/mixins/mixin-controller-value/mixin-controller-value.js +7 -2
  216. package/dist/mixins/mixin-dismissible/mixin-dismissible.js +44 -7
  217. package/dist/mixins/mixin-field/mixin-field.js +2 -2
  218. package/dist/mixins/mixin-picker-feedback/mixin-picker-feedback.d.ts +42 -0
  219. package/dist/mixins/mixin-picker-feedback/mixin-picker-feedback.js +46 -0
  220. package/dist/mixins/mixin-picker-field/mixin-picker-field.d.ts +7 -4
  221. package/dist/mixins/mixin-picker-field/mixin-picker-field.js +6 -4
  222. package/dist/mixins/mixin-segmented-field/mixin-segmented-field.js +19 -9
  223. package/dist/utils/audit-name/audit-name-off.d.ts +10 -0
  224. package/dist/utils/audit-name/audit-name-off.js +1 -0
  225. package/dist/utils/audit-name/audit-name.d.ts +26 -8
  226. package/dist/utils/audit-name/audit-name.js +22 -30
  227. package/dist/utils/audit-source/audit-source-off.d.ts +10 -0
  228. package/dist/utils/audit-source/audit-source-off.js +1 -0
  229. package/dist/utils/audit-source/audit-source.d.ts +19 -0
  230. package/dist/utils/audit-source/audit-source.js +27 -0
  231. package/dist/utils/calendar/calendar.js +7 -7
  232. package/dist/utils/call-listener/call-listener.d.ts +16 -0
  233. package/dist/utils/call-listener/call-listener.js +17 -0
  234. package/dist/utils/chord/chord.d.ts +14 -0
  235. package/dist/utils/chord/chord.js +1 -0
  236. package/dist/utils/clamp/clamp.d.ts +7 -0
  237. package/dist/utils/clamp/clamp.js +1 -0
  238. package/dist/utils/css-color/css-color.js +1 -1
  239. package/dist/utils/draw-tooltip/draw-tooltip.d.ts +1 -1
  240. package/dist/utils/draw-tooltip/draw-tooltip.js +3 -1
  241. package/dist/utils/draw-tooltip/spoken-reading.d.ts +6 -2
  242. package/dist/utils/draw-tooltip/spoken-reading.js +5 -4
  243. package/dist/utils/elapsed-time/elapsed-time.d.ts +1 -1
  244. package/dist/utils/elapsed-time/elapsed-time.js +2 -5
  245. package/dist/utils/heading-level/heading-level.d.ts +8 -0
  246. package/dist/utils/heading-level/heading-level.js +4 -0
  247. package/dist/utils/host-words/host-words.d.ts +16 -0
  248. package/dist/utils/host-words/host-words.js +13 -0
  249. package/dist/utils/implicit-submit/implicit-submit.d.ts +25 -0
  250. package/dist/utils/implicit-submit/implicit-submit.js +52 -0
  251. package/dist/utils/load-more/load-more.d.ts +25 -0
  252. package/dist/utils/load-more/load-more.js +1 -0
  253. package/dist/utils/locale-of/locale-of.d.ts +18 -0
  254. package/dist/utils/locale-of/locale-of.js +26 -0
  255. package/dist/utils/name-text/name-text.d.ts +12 -0
  256. package/dist/utils/name-text/name-text.js +25 -0
  257. package/dist/utils/nearest/nearest.d.ts +9 -0
  258. package/dist/utils/nearest/nearest.js +9 -0
  259. package/dist/utils/number-format/number-format.d.ts +11 -1
  260. package/dist/utils/number-format/number-format.js +17 -5
  261. package/dist/utils/own-rule/own-rule.d.ts +16 -0
  262. package/dist/utils/own-rule/own-rule.js +7 -0
  263. package/dist/utils/plain-click/plain-click.d.ts +10 -0
  264. package/dist/utils/plain-click/plain-click.js +1 -0
  265. package/dist/utils/platform/platform.d.ts +8 -0
  266. package/dist/utils/platform/platform.js +1 -0
  267. package/dist/utils/press-type/press-type.d.ts +20 -0
  268. package/dist/utils/press-type/press-type.js +15 -0
  269. package/dist/utils/read-series/read-series.d.ts +14 -0
  270. package/dist/utils/read-series/read-series.js +15 -0
  271. package/dist/utils/relative-time/relative-time.d.ts +8 -0
  272. package/dist/utils/relative-time/relative-time.js +5 -2
  273. package/dist/utils/report-render/report-render.js +2 -14
  274. package/dist/utils/report-runtime/report-runtime.d.ts +11 -4
  275. package/dist/utils/report-runtime/report-runtime.js +2 -14
  276. package/dist/utils/report-usage/report-usage.js +2 -14
  277. package/dist/utils/row-data/row-data.d.ts +15 -0
  278. package/dist/utils/row-data/row-data.js +17 -0
  279. package/dist/utils/row-order/row-order.d.ts +141 -0
  280. package/dist/utils/row-order/row-order.js +76 -0
  281. package/dist/utils/scroll-item-into-view/scroll-item-into-view.d.ts +33 -0
  282. package/dist/utils/scroll-item-into-view/scroll-item-into-view.js +13 -3
  283. package/dist/utils/slotted-glyph/slotted-glyph.d.ts +33 -0
  284. package/dist/utils/slotted-glyph/slotted-glyph.js +27 -0
  285. package/dist/utils/tell-disclosure/tell-disclosure.d.ts +4 -0
  286. package/dist/utils/tree-arrow/tree-arrow.d.ts +23 -0
  287. package/dist/utils/tree-arrow/tree-arrow.js +9 -0
  288. package/dist/utils/typeahead/typeahead.d.ts +75 -0
  289. package/dist/utils/typeahead/typeahead.js +37 -0
  290. package/dist/utils/value-as/value-as.d.ts +9 -0
  291. package/dist/utils/value-as/value-as.js +9 -1
  292. package/dist/utils/verdict-flags/verdict-flags.d.ts +13 -0
  293. package/dist/utils/verdict-flags/verdict-flags.js +6 -0
  294. package/dist/utils/watch-labels/watch-labels.d.ts +16 -0
  295. package/dist/utils/watch-labels/watch-labels.js +34 -0
  296. package/dist/utils/words-converter/words-converter.d.ts +14 -0
  297. package/dist/utils/words-converter/words-converter.js +15 -0
  298. package/dist/utils/written-list/written-list.d.ts +60 -0
  299. package/dist/utils/written-list/written-list.js +46 -0
  300. package/dist/version.d.ts +1 -1
  301. package/dist/version.js +1 -1
  302. package/package.json +29 -5
@@ -84,7 +84,8 @@ export interface AriaForwardOptions {
84
84
  * and the host is a generic the reader never lands on, so a `<label for>` or a
85
85
  * wrapping `<label>` left the textbox unnamed. The labels travel the same way a
86
86
  * forwarded `aria-labelledby` does, as element references, and are read again
87
- * when focus arrives, since a label can be added without the host hearing.
87
+ * on every update, which a form control asks for whenever a label in its tree
88
+ * changes (`watchLabels`), and as focus arrives.
88
89
  */
89
90
  export declare class AriaForwardController implements ReactiveController {
90
91
  private readonly host;
@@ -128,7 +129,7 @@ export declare class AriaForwardController implements ReactiveController {
128
129
  forward(): void;
129
130
  hostConnected(): void;
130
131
  hostDisconnected(): void;
131
- /** Forwards again as focus arrives, for a label added since the last update. */
132
+ /** Forwards again as focus arrives. */
132
133
  private readonly refresh;
133
134
  hostUpdated(): void;
134
135
  }
@@ -1,17 +1,6 @@
1
- import { auditName } from '../../utils/audit-name/audit-name.js';
1
+ import { auditName } from '#audit-name';
2
2
  import { elementById } from '../../utils/element-by-id/element-by-id.js';
3
- const shownText = (node) => {
4
- if (node instanceof HTMLSlotElement) {
5
- return node.assignedNodes({ flatten: true }).map(shownText).join('');
6
- }
7
- if (node.nodeType === Node.TEXT_NODE) {
8
- return node.textContent ?? '';
9
- }
10
- if (node instanceof HTMLElement && node.hidden) {
11
- return '';
12
- }
13
- return [...node.childNodes].map(shownText).join('');
14
- };
3
+ import { nameText } from '../../utils/name-text/name-text.js';
15
4
  const RELATIONSHIPS = [
16
5
  ['aria-describedby', 'ariaDescribedByElements'],
17
6
  ['aria-labelledby', 'ariaLabelledByElements'],
@@ -49,7 +38,7 @@ export class AriaForwardController {
49
38
  return true;
50
39
  }
51
40
  const own = target.labels;
52
- return [...(own ?? [])].some((label) => shownText(label).trim() !== '');
41
+ return [...(own ?? [])].some((label) => nameText(label).trim() !== '');
53
42
  }
54
43
  hostLabels(target) {
55
44
  const labels = this.host.labels;
@@ -85,9 +74,11 @@ export class AriaForwardController {
85
74
  continue;
86
75
  }
87
76
  const ids = (this.host.getAttribute(attribute) ?? '').split(/\s+/).filter(Boolean);
88
- const referenced = ids
89
- .map((id) => elementById(this.host, id))
90
- .filter((element) => element !== null);
77
+ const referenced = ids.length > 0
78
+ ? ids
79
+ .map((id) => elementById(this.host, id))
80
+ .filter((element) => element !== null)
81
+ : [...(this.host[property] ?? [])];
91
82
  const elements = referenced.length === 0 && attribute === 'aria-labelledby'
92
83
  ? this.hostLabels(target)
93
84
  : referenced;
@@ -34,6 +34,37 @@ export interface ChartPointerHost extends ReactiveControllerHost, HTMLElement {
34
34
  * drawn from, such as a scatter's measure across.
35
35
  */
36
36
  seriesOf?(cell: number): number | undefined;
37
+ /**
38
+ * Whether the series drawn from the cell at this place in a row is shown,
39
+ * which it is unless a legend hid it. Absent, every series is shown.
40
+ *
41
+ * The series keys pass over a hidden one, and the readout leaves it out.
42
+ */
43
+ showsColumn?(cell: number): boolean;
44
+ /**
45
+ * Whether the reading at this place is shown, for a chart whose readings
46
+ * a legend can hide: a ring's slices are its rows. Absent, every reading is
47
+ * shown.
48
+ *
49
+ * The keys pass over a hidden reading, as they pass over a hidden series.
50
+ */
51
+ showsReading?(at: number): boolean;
52
+ /**
53
+ * Where PageUp or PageDown goes from the reading at `at`, by place among the
54
+ * readings, for a chart whose page is no fixed count: a calendar's month.
55
+ * Undefined keeps the fixed page.
56
+ */
57
+ pageFrom?(at: number, forward: boolean): number | undefined;
58
+ /**
59
+ * The words for where a reading stands among them, with `{position}` and
60
+ * `{count}` to fill. Absent or empty, no position is said.
61
+ */
62
+ readonly positionLabel?: string;
63
+ /**
64
+ * The locale the position's numbers are written in. Absent or empty is the
65
+ * runtime's own.
66
+ */
67
+ readonly locale?: string;
37
68
  }
38
69
  /**
39
70
  * Which reading a pointer is nearest, for a chart that draws no markers.
@@ -62,8 +93,9 @@ export interface ChartPointerHost extends ReactiveControllerHost, HTMLElement {
62
93
  * **The keyboard moves the same reading, which is what makes it the reading
63
94
  * and not the pointer's.** A chart's plot takes focus (`tabindex="0"` on the
64
95
  * element carrying `CHART_PLOT`), and while it has it the arrow keys walk the
65
- * readings, Home and End go to the first and the last, and the other pair of
66
- * arrows walks the series within a reading. Escape puts the bubble away, as it
96
+ * readings, Home and End go to the first and the last, PageUp and PageDown
97
+ * move a page of readings, and the other pair of arrows walks the series
98
+ * within a reading. Escape puts the bubble away, as it
67
99
  * does a tooltip. The tooltip follows because it already follows `at`, and the
68
100
  * chart's readout, a polite live region `drawTooltip` renders, says the
69
101
  * reading in words. It speaks only for a key: a pointer crossing a chart is a
@@ -125,8 +157,41 @@ export declare class ChartPointerController implements ReactiveController {
125
157
  * from, and the bubble lists every one of them.
126
158
  */
127
159
  get column(): number | undefined;
128
- /** The cells a series key can rest on: every column a series was drawn from. */
160
+ /**
161
+ * Whether the series drawn from the cell at this place in a row is shown.
162
+ *
163
+ * The readout asks, so a reading said whole leaves out what a legend hid,
164
+ * as the drawing does.
165
+ */
166
+ shows(cell: number): boolean;
167
+ /**
168
+ * How far PageUp and PageDown move: four columns of a grid, which is four
169
+ * weeks of a calendar heatmap, a month near enough; and a tenth of the
170
+ * readings otherwise, at least one.
171
+ */
172
+ private page;
173
+ /**
174
+ * Where the reading stands among the shown readings, in the host's
175
+ * `positionLabel`, such as "2 of 12". Empty with no reading, and where the
176
+ * host gives no words.
177
+ *
178
+ * Counted among the shown readings, so a slice a legend hid is not one of
179
+ * the count.
180
+ */
181
+ get position(): string;
182
+ /**
183
+ * The cells a series key can rest on: every column a series was drawn
184
+ * from, and is still drawn from.
185
+ */
129
186
  private columns;
187
+ /**
188
+ * The readings the keys walk, by place: every one, less those a legend hid.
189
+ *
190
+ * The keys step through this list, so a hidden
191
+ * slice is passed over as if it were not in the table, which is how the
192
+ * ring draws it.
193
+ */
194
+ private shown;
130
195
  /**
131
196
  * Tells the tooltip its anchor moved, which nothing else would.
132
197
  *
@@ -145,6 +210,9 @@ export declare class ChartPointerController implements ReactiveController {
145
210
  /**
146
211
  * The box the readings are laid out in, which is the plot and not the host.
147
212
  *
213
+ * Found by its part, or by the id every chart gives its plot, which is how
214
+ * a sparkline's drawing, whose part is `svg`, is found.
215
+ *
148
216
  * The host also holds the row of labels, so measuring against it would map
149
217
  * the pointer over a box taller than the drawing. That mattered the moment a
150
218
  * chart started measuring down the box rather than across it, which is what
@@ -1,3 +1,5 @@
1
+ import { fillTemplate } from '../../utils/fill-template/fill-template.js';
2
+ import { formatNumbers } from '../../utils/format-numbers/format-numbers.js';
1
3
  import { isRtl } from '../../utils/is-rtl/is-rtl.js';
2
4
  import { stepReading } from './reading-step.js';
3
5
  export const CHART_PLOT = 'helix-chart-plot';
@@ -13,7 +15,8 @@ export class ChartPointerController {
13
15
  if (!this.fromPlot(event) || event.altKey || event.ctrlKey || event.metaKey) {
14
16
  return;
15
17
  }
16
- const count = this.host.readings;
18
+ const shown = this.shown();
19
+ const count = shown.length;
17
20
  if (count === 0) {
18
21
  return;
19
22
  }
@@ -24,17 +27,32 @@ export class ChartPointerController {
24
27
  }
25
28
  return;
26
29
  }
27
- const next = stepReading(event.key, { at: this.at, series: this.series }, {
30
+ const paged = (event.key === 'PageDown' || event.key === 'PageUp') && this.at >= 0
31
+ ? this.host.pageFrom?.(this.at, event.key === 'PageDown')
32
+ : undefined;
33
+ if (paged !== undefined && shown.includes(paged)) {
34
+ event.preventDefault();
35
+ if (paged !== this.at) {
36
+ this.at = paged;
37
+ this.keyed = true;
38
+ this.moved = true;
39
+ this.host.requestUpdate();
40
+ }
41
+ return;
42
+ }
43
+ const next = stepReading(event.key, { at: shown.indexOf(this.at), series: this.series }, {
28
44
  axis: this.axis,
29
45
  count,
30
46
  grid: this.grid,
47
+ page: this.page(count),
31
48
  rtl: isRtl(this.host),
32
49
  series: this.columns().length,
33
50
  });
34
51
  if (next === undefined) {
35
52
  return;
36
53
  }
37
- const { at, series } = next;
54
+ const at = shown[next.at] ?? -1;
55
+ const { series } = next;
38
56
  event.preventDefault();
39
57
  if (at === this.at && series === this.series && this.keyed) {
40
58
  return;
@@ -56,10 +74,11 @@ export class ChartPointerController {
56
74
  }
57
75
  catch {
58
76
  }
59
- if (!visible || this.host.readings === 0) {
77
+ const first = this.shown()[0];
78
+ if (!visible || first === undefined) {
60
79
  return;
61
80
  }
62
- this.at = 0;
81
+ this.at = first;
63
82
  this.keyed = true;
64
83
  this.moved = true;
65
84
  this.host.requestUpdate();
@@ -123,12 +142,32 @@ export class ChartPointerController {
123
142
  get column() {
124
143
  return this.series < 0 ? undefined : this.columns()[this.series];
125
144
  }
145
+ shows(cell) {
146
+ return this.host.showsColumn?.(cell) !== false;
147
+ }
148
+ page(count) {
149
+ return this.grid > 1 ? this.grid * 4 : Math.max(1, Math.round(count / 10));
150
+ }
151
+ get position() {
152
+ const words = this.host.positionLabel ?? '';
153
+ const shown = this.shown();
154
+ const place = shown.indexOf(this.at);
155
+ if (words === '' || place < 0) {
156
+ return '';
157
+ }
158
+ const format = formatNumbers(this.host.locale ?? '');
159
+ return fillTemplate(words, { count: format(shown.length), position: format(place + 1) });
160
+ }
126
161
  columns() {
127
162
  const host = this.host;
128
- const all = host.plottedColumns ?? [];
129
- return host.seriesOf === undefined
163
+ return (host.plottedColumns ?? []).filter((one) => (host.seriesOf === undefined || host.seriesOf(one) !== undefined) && this.shows(one));
164
+ }
165
+ shown() {
166
+ const host = this.host;
167
+ const all = Array.from({ length: host.readings }, (_, at) => at);
168
+ return host.showsReading === undefined
130
169
  ? all
131
- : all.filter((one) => host.seriesOf?.(one) !== undefined);
170
+ : all.filter((at) => host.showsReading?.(at) !== false);
132
171
  }
133
172
  hostUpdated() {
134
173
  if (!this.moved) {
@@ -141,7 +180,9 @@ export class ChartPointerController {
141
180
  }
142
181
  box() {
143
182
  if (!this.plot?.isConnected) {
144
- this.plot = this.host.renderRoot.querySelector('[part="plot"]') ?? undefined;
183
+ this.plot =
184
+ this.host.renderRoot.querySelector(`[part="plot"], #${CHART_PLOT}`) ??
185
+ undefined;
145
186
  }
146
187
  return this.plot?.getBoundingClientRect();
147
188
  }
@@ -18,6 +18,11 @@ export interface ReadingLayout {
18
18
  count: number;
19
19
  /** How many readings stand in one column, for a grid. `1` is a row of them. */
20
20
  grid: number;
21
+ /**
22
+ * How far PageUp and PageDown move, in readings. Absent, they move nothing
23
+ * and the page keeps them.
24
+ */
25
+ page?: number;
21
26
  /** Whether the line of text runs right to left, which turns the inline arrows. */
22
27
  rtl: boolean;
23
28
  /** How many series a reading holds, which the cross pair of arrows walks. */
@@ -49,7 +54,8 @@ export declare const amongSeries: (key: string, layout: ReadingLayout) => number
49
54
  * Where a key moves the reading, or `undefined` for a key that moves nothing,
50
55
  * which the page keeps.
51
56
  *
52
- * Home and End go to the first and the last. From no reading, an arrow moving
57
+ * Home and End go to the first and the last, and PageUp and PageDown move a
58
+ * `page` of readings where the layout gives one. From no reading, an arrow moving
53
59
  * on starts at the first and one moving back at the last, so either arrow
54
60
  * starts somewhere a reader expects. A series key on no reading starts on the
55
61
  * first. Nothing walks off either end.
@@ -29,6 +29,11 @@ export const stepReading = (key, from, layout) => {
29
29
  if (key === 'End') {
30
30
  return { at: last, series: from.series };
31
31
  }
32
+ if ((key === 'PageDown' || key === 'PageUp') && layout.page !== undefined) {
33
+ const step = Math.max(1, layout.page) * (key === 'PageDown' ? 1 : -1);
34
+ const at = from.at < 0 ? (step > 0 ? 0 : last) : Math.min(Math.max(from.at + step, 0), last);
35
+ return { at, series: from.series };
36
+ }
32
37
  const along = alongReadings(key, layout);
33
38
  if (along !== 0) {
34
39
  const at = from.at < 0 ? (along > 0 ? 0 : last) : Math.min(Math.max(from.at + along, 0), last);
@@ -7,8 +7,11 @@ export interface CopyOptions {
7
7
  * On a timer rather than on the pointer leaving, so it survives a hand that
8
8
  * has already moved on: the press and the reading of it are two moments, and
9
9
  * a mark that vanishes with the cursor is one a fast reader never sees.
10
+ *
11
+ * A function is read at each copy, for a host whose duration is a property
12
+ * a page can change, as other controllers' options are.
10
13
  */
11
- after?: number;
14
+ after?: number | (() => number);
12
15
  }
13
16
  /**
14
17
  * Puts text on the clipboard and holds a confirmation for a moment.
@@ -1,5 +1,6 @@
1
1
  import { HelixCopyEvent } from '../../events/events.js';
2
2
  import { deepActiveElement } from '../../utils/focusable-elements/focusable-elements.js';
3
+ const read = (option) => typeof option === 'function' ? option() : option;
3
4
  const write = async (text) => {
4
5
  try {
5
6
  await navigator.clipboard.writeText(text);
@@ -53,7 +54,7 @@ export class CopyController {
53
54
  this.copied = false;
54
55
  this.failed = false;
55
56
  this.host.requestUpdate();
56
- }, this.options.after ?? 1200);
57
+ }, read(this.options.after) ?? 1200);
57
58
  return wrote;
58
59
  }
59
60
  hostDisconnected() {
@@ -46,7 +46,10 @@ export declare class CountdownController implements ReactiveController {
46
46
  pause(): void;
47
47
  /** Runs the clock again from where it stopped. */
48
48
  resume(): void;
49
- /** Stops the clock where it is, as a dismissal does. */
49
+ /**
50
+ * Stops the clock for good, as a dismissal does: nothing is left to resume
51
+ * until the next `start`, so a hold and a release after it run nothing.
52
+ */
50
53
  cancel(): void;
51
54
  /** One more reason to hold the clock, such as a pointer arriving. */
52
55
  hold(): void;
@@ -36,13 +36,15 @@ export class CountdownController {
36
36
  this.startedAt = Date.now();
37
37
  this.options.paused?.(false);
38
38
  this.timer = setTimeout(() => {
39
- this.timer = undefined;
39
+ this.cancel();
40
40
  this.options.done();
41
41
  }, this.remaining);
42
42
  }
43
43
  cancel() {
44
44
  clearTimeout(this.timer);
45
45
  this.timer = undefined;
46
+ this.remaining = undefined;
47
+ this.startedAt = undefined;
46
48
  }
47
49
  hold() {
48
50
  this.holds += 1;
@@ -1,4 +1,5 @@
1
1
  import type { ReactiveController, ReactiveControllerHost } from 'lit';
2
+ import { type TypeaheadBy } from '../../utils/typeahead/typeahead.js';
2
3
  /** What a controller needs of an item to move to it and choose it. */
3
4
  export interface NavigableItem {
4
5
  /**
@@ -18,6 +19,11 @@ export interface NavigableItem {
18
19
  select(): void;
19
20
  /** Whether the item is the current one, which is where movement starts. */
20
21
  selected: boolean;
22
+ /**
23
+ * The words a reader types the start of, for a set that types ahead with
24
+ * `typeaheadByWords`.
25
+ */
26
+ readonly words?: string;
21
27
  }
22
28
  /** Where a move starts from: the item that has focus, or the chosen item. */
23
29
  export type KeyboardOrigin = 'focus' | 'selection';
@@ -70,14 +76,15 @@ export interface KeyboardNavigationOptions {
70
76
  */
71
77
  reserved?: () => string[];
72
78
  /**
73
- * The words of an item, which turns on typeahead: a printable key moves to
74
- * the next item whose words start with what was typed.
79
+ * The search that turns on typeahead, built with `typeaheadBy` from the
80
+ * words of an item: a printable key moves to the next item whose words
81
+ * start with what was typed.
75
82
  *
76
83
  * Off unless given. A set whose items have no words a reader would type, or
77
84
  * that holds a text field of its own, leaves it out. See `Typeahead` for how
78
85
  * the letters are matched.
79
86
  */
80
- typeahead?: (item: NavigableItem) => string;
87
+ typeahead?: TypeaheadBy<NavigableItem>;
81
88
  /**
82
89
  * Whether the ends join up, which they do unless a set says otherwise.
83
90
  *
@@ -98,54 +105,6 @@ export interface KeyboardNavigationOptions {
98
105
  */
99
106
  wrap?: boolean;
100
107
  }
101
- /**
102
- * Whether a press types a character, which is what typeahead reads.
103
- *
104
- * One character with no Control, Command or Alt held, so a shortcut such as
105
- * Control+A is never taken for the letter A. Shift is allowed, because a
106
- * capital is still a letter.
107
- */
108
- export declare const typesCharacter: (event: KeyboardEvent) => boolean;
109
- /**
110
- * Finds an item by the letters a reader types at a set, the way a native
111
- * `<select>` does.
112
- *
113
- * Letters typed within `timeout` milliseconds of each other build one search,
114
- * so typing "ca" moves to "Canada" past "Cambodia". The same letter typed again
115
- * moves to the next item that starts with it, so pressing "c" three times visits
116
- * the first three. A pause starts a new search.
117
- *
118
- * Matching ignores case and leading spaces, and searches from the reader's
119
- * position, wrapping at the end. A search that matches nothing moves nothing.
120
- *
121
- * Holds only the letters, so one instance serves any set: the caller passes the
122
- * words of the items and where the reader is on every key.
123
- */
124
- export declare class Typeahead {
125
- private letters;
126
- private last;
127
- private readonly timeout;
128
- constructor({ timeout }?: {
129
- timeout?: number;
130
- });
131
- /**
132
- * Whether a search is under way.
133
- *
134
- * A set that chooses on Space asks this first, because a Space typed in the
135
- * middle of a search is part of the words, as in "New York".
136
- */
137
- typing(now?: number): boolean;
138
- /**
139
- * Adds a character to the search, and returns the index of the item it
140
- * matches, or `-1` where none does.
141
- *
142
- * `texts` are the words of the items a reader can reach, in order, and
143
- * `from` is the index of the item the reader is on, or `-1`.
144
- */
145
- match(key: string, texts: readonly string[], from: number, now?: number): number;
146
- /** Ends the search, so the next letter starts a new one. */
147
- reset(): void;
148
- }
149
108
  /**
150
109
  * Moves through a set of items with the arrow keys, and chooses as it goes.
151
110
  *
@@ -171,9 +130,10 @@ export declare class Typeahead {
171
130
  * Disabled items are skipped rather than stopped at, so a set with a gap in it
172
131
  * still moves in one press.
173
132
  *
174
- * **Typeahead is opt-in.** Pass `typeahead` with a function that returns an
175
- * item's words, and a printable key moves to the next item whose words start
176
- * with the letters typed, choosing it where arriving chooses. A key that a text
133
+ * **Typeahead is opt-in.** Pass `typeahead`, built by `typeaheadBy` from a
134
+ * function that returns an item's words, and a printable key moves to the next
135
+ * item whose words start with the letters typed, choosing it where arriving
136
+ * chooses. A key that a text
177
137
  * field inside the set is typing into is left to the field.
178
138
  *
179
139
  * A set that starts from focus rather than from the selection, or that moves
@@ -187,7 +147,6 @@ export declare class KeyboardNavigationController implements ReactiveController
187
147
  private readonly selects;
188
148
  private readonly reserved;
189
149
  private readonly wrap;
190
- private readonly words;
191
150
  private readonly typeahead;
192
151
  constructor(host: ReactiveControllerHost & HTMLElement, { items, origin, reserved, selects, typeahead, wrap, }: KeyboardNavigationOptions);
193
152
  /** Where this press starts from, read again on every press. */
@@ -1,41 +1,9 @@
1
1
  import { inlineStep } from '../../utils/inline-step/inline-step.js';
2
2
  import { keyClaimed } from '../../utils/key-claimed/key-claimed.js';
3
+ import { typesCharacter } from '../../utils/typeahead/typeahead.js';
3
4
  const KEYS = new Set(['ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'End', 'Home']);
4
- export const typesCharacter = (event) => event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey;
5
- export class Typeahead {
6
- constructor({ timeout = 500 } = {}) {
7
- this.letters = '';
8
- this.last = 0;
9
- this.timeout = timeout;
10
- }
11
- typing(now = Date.now()) {
12
- return this.letters !== '' && now - this.last <= this.timeout;
13
- }
14
- match(key, texts, from, now = Date.now()) {
15
- if (!this.typing(now)) {
16
- this.letters = '';
17
- }
18
- this.last = now;
19
- this.letters += key.toLowerCase();
20
- const words = texts.map((text) => text.trim().toLowerCase());
21
- const repeated = [...this.letters].every((letter) => letter === this.letters[0]);
22
- const needle = repeated ? (this.letters[0] ?? '') : this.letters;
23
- const start = repeated ? from + 1 : Math.max(from, 0);
24
- for (let step = 0; step < words.length; step += 1) {
25
- const at = (start + step) % words.length;
26
- if (words[at]?.startsWith(needle)) {
27
- return at;
28
- }
29
- }
30
- return -1;
31
- }
32
- reset() {
33
- this.letters = '';
34
- }
35
- }
36
5
  export class KeyboardNavigationController {
37
6
  constructor(host, { items, origin = 'selection', reserved = () => [], selects = () => true, typeahead, wrap = true, }) {
38
- this.typeahead = new Typeahead();
39
7
  this.handleKeydown = (event) => {
40
8
  if (!KEYS.has(event.key)) {
41
9
  this.handleTypeahead(event);
@@ -76,7 +44,7 @@ export class KeyboardNavigationController {
76
44
  next = last;
77
45
  }
78
46
  event.preventDefault();
79
- this.typeahead.reset();
47
+ this.typeahead?.search.reset();
80
48
  this.arrive(items[next]);
81
49
  };
82
50
  this.host = host;
@@ -84,7 +52,7 @@ export class KeyboardNavigationController {
84
52
  this.originOf = typeof origin === 'function' ? origin : () => origin;
85
53
  this.reserved = reserved;
86
54
  this.selects = selects;
87
- this.words = typeahead;
55
+ this.typeahead = typeahead;
88
56
  this.wrap = wrap;
89
57
  host.addController(this);
90
58
  }
@@ -107,11 +75,11 @@ export class KeyboardNavigationController {
107
75
  return selected < 0 ? focused : selected;
108
76
  }
109
77
  handleTypeahead(event) {
110
- const words = this.words;
111
- if (!words || !typesCharacter(event) || keyClaimed(event)) {
78
+ const typeahead = this.typeahead;
79
+ if (!typeahead || !typesCharacter(event) || keyClaimed(event)) {
112
80
  return;
113
81
  }
114
- if (event.key === ' ' && !this.typeahead.typing()) {
82
+ if (event.key === ' ' && !typeahead.search.typing()) {
115
83
  return;
116
84
  }
117
85
  const items = this.items().filter((item) => !item.disabled);
@@ -122,7 +90,7 @@ export class KeyboardNavigationController {
122
90
  if (this.origin === 'focus' && from === -1) {
123
91
  return;
124
92
  }
125
- const at = this.typeahead.match(event.key, items.map(words), from);
93
+ const at = typeahead.search.match(event.key, items.map(typeahead.words), from);
126
94
  event.preventDefault();
127
95
  if (at >= 0 && at !== from) {
128
96
  this.arrive(items[at]);
@@ -0,0 +1,44 @@
1
+ import type { ReactiveController, ReactiveControllerHost } from 'lit';
2
+ /** What the clock reads from its host. */
3
+ export interface RelativeClockOptions {
4
+ /**
5
+ * When the reading drawn at `now` stops being true, as `relativeTime` and
6
+ * `elapsedTime` say in `next`, in milliseconds from `now`; or `undefined`
7
+ * where the host shows no reading, which reads nothing and schedules
8
+ * nothing.
9
+ */
10
+ expires: (now: Date) => number | undefined;
11
+ }
12
+ /**
13
+ * The time a relative reading is drawn against, moved on when the reading
14
+ * would change: "3 minutes ago" becoming "4 minutes ago".
15
+ *
16
+ * **One wakeup when the words go stale, and none in between.** The reading
17
+ * says how long it holds, so the clock asks core's shared ticker for exactly
18
+ * that moment: a reading a minute old wakes once a minute, an hour old once an
19
+ * hour, and a date never. Every reading on the page shares the ticker's one
20
+ * timer. Chat Message and Format Date draw against it.
21
+ *
22
+ * **Only on a page.** A server has nobody to update a reading for, and a
23
+ * subscription there holds the element after its markup is sent, so off the
24
+ * page `tick()` reads the time and schedules nothing.
25
+ */
26
+ export declare class RelativeClockController implements ReactiveController {
27
+ private readonly host;
28
+ private readonly options;
29
+ /** The time the host last drew against, in milliseconds. */
30
+ now: number;
31
+ private stop;
32
+ constructor(host: ReactiveControllerHost & HTMLElement, options: RelativeClockOptions);
33
+ hostConnected(): void;
34
+ hostDisconnected(): void;
35
+ /**
36
+ * Reads the clock again, asks the host to draw against it, and schedules
37
+ * the next reading.
38
+ *
39
+ * The host calls it when what it reads changes, the instant or the locale,
40
+ * and the ticker calls it when the words go stale. A host with no reading
41
+ * is left as it is.
42
+ */
43
+ tick(): void;
44
+ }
@@ -0,0 +1,31 @@
1
+ import { subscribe } from '../../utils/ticker/ticker.js';
2
+ export class RelativeClockController {
3
+ constructor(host, options) {
4
+ this.host = host;
5
+ this.options = options;
6
+ this.now = Date.now();
7
+ this.stop = undefined;
8
+ host.addController(this);
9
+ }
10
+ hostConnected() {
11
+ this.tick();
12
+ }
13
+ hostDisconnected() {
14
+ this.stop?.();
15
+ this.stop = undefined;
16
+ }
17
+ tick() {
18
+ this.stop?.();
19
+ this.stop = undefined;
20
+ const now = Date.now();
21
+ const next = this.options.expires(new Date(now));
22
+ if (next === undefined) {
23
+ return;
24
+ }
25
+ this.now = now;
26
+ this.host.requestUpdate();
27
+ if (Number.isFinite(next) && this.host.isConnected) {
28
+ this.stop = subscribe(next, () => this.tick());
29
+ }
30
+ }
31
+ }