@fusion.dev/helix-headless 0.146.0 → 0.147.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (239) hide show
  1. package/custom-elements.json +5266 -785
  2. package/dist/accordion/item/accordion-item.d.ts +38 -19
  3. package/dist/accordion/item/accordion-item.js +31 -9
  4. package/dist/accordion/root/accordion-root.d.ts +8 -2
  5. package/dist/accordion/root/accordion-root.js +3 -3
  6. package/dist/announcement/root/announcement-root.d.ts +13 -4
  7. package/dist/announcement/root/announcement-root.js +34 -6
  8. package/dist/area-chart/root/area-chart-root.d.ts +18 -1
  9. package/dist/area-chart/root/area-chart-root.js +11 -3
  10. package/dist/avatar/root/avatar-root.d.ts +31 -1
  11. package/dist/avatar/root/avatar-root.js +11 -1
  12. package/dist/badge/root/badge-root.d.ts +57 -6
  13. package/dist/badge/root/badge-root.js +88 -5
  14. package/dist/bar-chart/root/bar-chart-root.js +11 -20
  15. package/dist/bar-chart/stack.d.ts +10 -0
  16. package/dist/bar-chart/stack.js +8 -0
  17. package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +14 -0
  18. package/dist/breadcrumbs/breadcrumb/breadcrumb.js +12 -2
  19. package/dist/breadcrumbs/root/breadcrumbs-root.js +2 -2
  20. package/dist/button/root/button-root.d.ts +24 -38
  21. package/dist/button/root/button-root.js +6 -37
  22. package/dist/button/submitter.d.ts +27 -0
  23. package/dist/button/submitter.js +25 -0
  24. package/dist/card/root/card-root.d.ts +12 -1
  25. package/dist/card/root/card-root.js +11 -4
  26. package/dist/chat/root/chat-root.d.ts +15 -1
  27. package/dist/chat/root/chat-root.js +11 -2
  28. package/dist/checkbox/root/checkbox-root.js +5 -7
  29. package/dist/checkbox-group/root/checkbox-group-root.js +4 -3
  30. package/dist/checkbox-group/select-all.d.ts +0 -6
  31. package/dist/checkbox-group/select-all.js +0 -5
  32. package/dist/code-block/root/code-block-root.d.ts +35 -14
  33. package/dist/code-block/root/code-block-root.js +17 -3
  34. package/dist/color-input/root/color-input-root.d.ts +11 -0
  35. package/dist/color-input/root/color-input-root.js +12 -5
  36. package/dist/color-picker/channels.js +1 -2
  37. package/dist/color-picker/root/color-picker-root.d.ts +32 -24
  38. package/dist/color-picker/root/color-picker-root.js +101 -51
  39. package/dist/color-picker/wheel.d.ts +17 -0
  40. package/dist/color-picker/wheel.js +6 -0
  41. package/dist/combobox/root/combobox-root.d.ts +13 -0
  42. package/dist/combobox/root/combobox-root.js +14 -1
  43. package/dist/command/root/command-root.d.ts +3 -1
  44. package/dist/command/root/command-root.js +2 -19
  45. package/dist/copy-button/root/copy-button-root.d.ts +16 -1
  46. package/dist/copy-button/root/copy-button-root.js +7 -2
  47. package/dist/data-table/keys.d.ts +0 -18
  48. package/dist/data-table/keys.js +1 -11
  49. package/dist/data-table/root/data-table-root.js +13 -7
  50. package/dist/date-input/root/date-input-root.d.ts +8 -1
  51. package/dist/date-input/root/date-input-root.js +8 -5
  52. package/dist/date-picker/root/date-picker-root.d.ts +14 -9
  53. package/dist/date-picker/root/date-picker-root.js +21 -16
  54. package/dist/description-list/item/description-list-item.d.ts +18 -4
  55. package/dist/description-list/item/description-list-item.js +8 -4
  56. package/dist/donut-chart/root/donut-chart-root.js +13 -6
  57. package/dist/donut-chart/slice-label.d.ts +35 -0
  58. package/dist/donut-chart/slice-label.js +11 -0
  59. package/dist/drawer/root/drawer-root.d.ts +4 -2
  60. package/dist/drawer/root/drawer-root.js +15 -3
  61. package/dist/drilldown/item/drilldown-item.d.ts +21 -1
  62. package/dist/drilldown/item/drilldown-item.js +39 -4
  63. package/dist/drilldown/root/drilldown-root.js +3 -2
  64. package/dist/element-events.generated.js +4 -1
  65. package/dist/empty/root/empty-root.d.ts +31 -1
  66. package/dist/empty/root/empty-root.js +26 -5
  67. package/dist/file-input/root/file-input-root.d.ts +34 -6
  68. package/dist/file-input/root/file-input-root.js +54 -19
  69. package/dist/file-input/status.d.ts +24 -0
  70. package/dist/file-input/status.js +10 -0
  71. package/dist/filter-input/chip/filter-chip.d.ts +23 -0
  72. package/dist/filter-input/chip/filter-chip.js +11 -2
  73. package/dist/filter-input/root/filter-input-root.d.ts +8 -0
  74. package/dist/filter-input/root/filter-input-root.js +17 -27
  75. package/dist/format-date/options.d.ts +3 -4
  76. package/dist/format-date/options.js +2 -2
  77. package/dist/format-date/root/format-date-root.d.ts +18 -1
  78. package/dist/format-date/root/format-date-root.js +19 -23
  79. package/dist/heatmap/root/buckets.d.ts +21 -0
  80. package/dist/heatmap/root/buckets.js +34 -0
  81. package/dist/heatmap/root/heatmap-root.d.ts +64 -3
  82. package/dist/heatmap/root/heatmap-root.js +89 -19
  83. package/dist/icon/index.d.ts +1 -1
  84. package/dist/icon/index.js +1 -1
  85. package/dist/icon/registry.d.ts +26 -1
  86. package/dist/icon/registry.js +12 -1
  87. package/dist/icon/root/icon-root.d.ts +13 -0
  88. package/dist/icon/root/icon-root.js +23 -2
  89. package/dist/icon/root/index.d.ts +1 -1
  90. package/dist/icon/root/index.js +1 -1
  91. package/dist/image/root/image-root.d.ts +9 -0
  92. package/dist/image/root/image-root.js +6 -1
  93. package/dist/input/root/input-root.d.ts +23 -2
  94. package/dist/input/root/input-root.js +12 -8
  95. package/dist/kbd/keys.d.ts +29 -0
  96. package/dist/kbd/keys.js +52 -0
  97. package/dist/kbd/root/kbd-root.d.ts +20 -3
  98. package/dist/kbd/root/kbd-root.js +24 -50
  99. package/dist/legend/hidden-series.d.ts +10 -2
  100. package/dist/legend/hidden-series.js +5 -2
  101. package/dist/legend/root/legend-root.d.ts +25 -7
  102. package/dist/legend/root/legend-root.js +22 -10
  103. package/dist/lightbox/root/lightbox-root.d.ts +50 -5
  104. package/dist/lightbox/root/lightbox-root.js +76 -8
  105. package/dist/lightbox/zoom.d.ts +2 -0
  106. package/dist/lightbox/zoom.js +5 -3
  107. package/dist/line-chart/root/line-chart-root.d.ts +16 -0
  108. package/dist/line-chart/root/line-chart-root.js +10 -2
  109. package/dist/list/root/list-root.d.ts +10 -2
  110. package/dist/list/root/list-root.js +26 -5
  111. package/dist/list/selection.d.ts +17 -0
  112. package/dist/list/selection.js +16 -0
  113. package/dist/listbox/root/listbox-root.d.ts +9 -5
  114. package/dist/listbox/root/listbox-root.js +29 -37
  115. package/dist/megamenu/hand-over.d.ts +75 -0
  116. package/dist/megamenu/hand-over.js +67 -0
  117. package/dist/megamenu/root/megamenu-root.d.ts +38 -14
  118. package/dist/megamenu/root/megamenu-root.js +36 -50
  119. package/dist/menu/item/menu-item.js +4 -4
  120. package/dist/menu/root/menu-root.d.ts +3 -0
  121. package/dist/meter/root/meter-root.d.ts +42 -0
  122. package/dist/meter/root/meter-root.js +33 -7
  123. package/dist/notifications/root/notifications-root.d.ts +10 -1
  124. package/dist/notifications/root/notifications-root.js +11 -1
  125. package/dist/number-input/grain.d.ts +28 -0
  126. package/dist/number-input/grain.js +14 -0
  127. package/dist/number-input/root/number-input-root.d.ts +17 -1
  128. package/dist/number-input/root/number-input-root.js +29 -18
  129. package/dist/object-inspector/root/object-inspector-root.d.ts +13 -6
  130. package/dist/object-inspector/root/object-inspector-root.js +18 -17
  131. package/dist/option/index.d.ts +1 -0
  132. package/dist/option/index.js +1 -0
  133. package/dist/option/separator/option-separator.d.ts +30 -0
  134. package/dist/option/separator/option-separator.js +21 -0
  135. package/dist/outline/root/outline-root.d.ts +12 -0
  136. package/dist/outline/root/outline-root.js +5 -19
  137. package/dist/pagination/size/pagination-size.d.ts +5 -0
  138. package/dist/pagination/size/pagination-size.js +4 -2
  139. package/dist/pin-input/code.d.ts +28 -1
  140. package/dist/pin-input/code.js +12 -0
  141. package/dist/pin-input/root/pin-input-root.d.ts +98 -121
  142. package/dist/pin-input/root/pin-input-root.js +157 -148
  143. package/dist/popover/hide-outside.js +2 -9
  144. package/dist/popover/root/popover-root.d.ts +7 -1
  145. package/dist/popover/root/popover-root.js +9 -1
  146. package/dist/progress/root/progress-root.d.ts +27 -0
  147. package/dist/progress/root/progress-root.js +25 -7
  148. package/dist/qr-code/export.d.ts +19 -0
  149. package/dist/qr-code/export.js +14 -0
  150. package/dist/qr-code/name.d.ts +11 -0
  151. package/dist/qr-code/name.js +7 -0
  152. package/dist/qr-code/root/qr-code-root.d.ts +17 -6
  153. package/dist/qr-code/root/qr-code-root.js +10 -12
  154. package/dist/radio/group/radio-group.d.ts +15 -0
  155. package/dist/radio/root/radio-root.js +2 -2
  156. package/dist/rating/root/rating-root.d.ts +22 -9
  157. package/dist/rating/root/rating-root.js +15 -39
  158. package/dist/scatter-chart/root/scatter-chart-root.d.ts +30 -0
  159. package/dist/scatter-chart/root/scatter-chart-root.js +34 -7
  160. package/dist/scroll-area/scrollbar.d.ts +0 -8
  161. package/dist/scroll-area/scrollbar.js +1 -1
  162. package/dist/select/align.d.ts +47 -0
  163. package/dist/select/align.js +7 -0
  164. package/dist/select/root/select-root.d.ts +59 -3
  165. package/dist/select/root/select-root.js +72 -12
  166. package/dist/slider/root/slider-root.d.ts +18 -1
  167. package/dist/slider/root/slider-root.js +22 -0
  168. package/dist/sparkline/readings.d.ts +30 -12
  169. package/dist/sparkline/readings.js +32 -15
  170. package/dist/sparkline/root/sparkline-root.d.ts +46 -3
  171. package/dist/sparkline/root/sparkline-root.js +60 -21
  172. package/dist/speed-dial/item/speed-dial-item.d.ts +1 -1
  173. package/dist/speed-dial/item/speed-dial-item.js +2 -2
  174. package/dist/speed-dial/root/speed-dial-root.d.ts +6 -0
  175. package/dist/speed-dial/root/speed-dial-root.js +9 -1
  176. package/dist/splitter/root/splitter-root.d.ts +3 -0
  177. package/dist/splitter/root/splitter-root.js +2 -0
  178. package/dist/steps/root/steps-root.d.ts +8 -1
  179. package/dist/steps/root/steps-root.js +6 -1
  180. package/dist/steps/step/step.d.ts +1 -0
  181. package/dist/steps/step/step.js +1 -1
  182. package/dist/table/column/table-column.d.ts +6 -0
  183. package/dist/table/column/table-column.js +5 -1
  184. package/dist/table/root/table-root.js +13 -6
  185. package/dist/table/row/table-row.d.ts +24 -0
  186. package/dist/table/row/table-row.js +37 -1
  187. package/dist/tabs/root/tabs-root.d.ts +5 -3
  188. package/dist/tag/group/tag-group.d.ts +16 -4
  189. package/dist/tag/group/tag-group.js +19 -7
  190. package/dist/textarea/root/textarea-root.d.ts +14 -2
  191. package/dist/textarea/root/textarea-root.js +6 -7
  192. package/dist/time-input/root/time-input-root.d.ts +5 -1
  193. package/dist/time-input/root/time-input-root.js +10 -7
  194. package/dist/time-picker/root/time-picker-root.d.ts +11 -14
  195. package/dist/time-picker/root/time-picker-root.js +15 -23
  196. package/dist/toast/item/toast-item.d.ts +3 -3
  197. package/dist/toast/item/toast-item.js +0 -1
  198. package/dist/toast/root/toast-root.d.ts +28 -4
  199. package/dist/toast/root/toast-root.js +58 -12
  200. package/dist/toast/words.d.ts +12 -0
  201. package/dist/toast/words.js +25 -0
  202. package/dist/toggle/group/toggle-group.d.ts +29 -5
  203. package/dist/toggle/group/toggle-group.js +26 -41
  204. package/dist/toggle/root/toggle-root.js +2 -4
  205. package/dist/toolbar/root/toolbar-root.d.ts +21 -5
  206. package/dist/toolbar/root/toolbar-root.js +52 -8
  207. package/dist/tooltip/root/tooltip-root.d.ts +7 -1
  208. package/dist/tooltip/root/tooltip-root.js +10 -1
  209. package/dist/tour/root/tour-root.d.ts +15 -0
  210. package/dist/tour/root/tour-root.js +20 -1
  211. package/dist/tour/stop/tour-stop.d.ts +3 -0
  212. package/dist/tour/stop/tour-stop.js +3 -3
  213. package/dist/tree/root/tree-root.js +2 -2
  214. package/dist/trend/figure.d.ts +16 -0
  215. package/dist/trend/figure.js +8 -0
  216. package/dist/trend/root/trend-root.d.ts +41 -2
  217. package/dist/trend/root/trend-root.js +29 -3
  218. package/dist/video/root/extra-controls.d.ts +12 -0
  219. package/dist/video/root/extra-controls.js +6 -2
  220. package/dist/video/root/video-root.d.ts +5 -1
  221. package/dist/video-playlist/root/video-playlist-root.d.ts +11 -1
  222. package/dist/video-playlist/root/video-playlist-root.js +3 -0
  223. package/dist/virtual-list/fill.d.ts +11 -0
  224. package/dist/virtual-list/fill.js +9 -0
  225. package/dist/virtual-list/keys.d.ts +16 -7
  226. package/dist/virtual-list/keys.js +17 -6
  227. package/dist/virtual-list/plan.d.ts +17 -1
  228. package/dist/virtual-list/plan.js +13 -2
  229. package/dist/virtual-list/root/virtual-list-root.d.ts +25 -3
  230. package/dist/virtual-list/root/virtual-list-root.js +48 -24
  231. package/lint.json +1 -1
  232. package/package.json +5 -5
  233. package/types/jsx.d.ts +2979 -738
  234. package/types/svelte.d.ts +1 -0
  235. package/types/vue.d.ts +619 -202
  236. package/dist/color-picker/swatches.d.ts +0 -12
  237. package/dist/color-picker/swatches.js +0 -26
  238. package/dist/rating/steps.d.ts +0 -7
  239. package/dist/rating/steps.js +0 -9
@@ -26,7 +26,13 @@ import { type PropertyValues, type TemplateResult } from 'lit';
26
26
  * `caps` draws a chord as a key per key: each is a `key` part and the `+`
27
27
  * between two a `separator` part, so a sheet can draw a cap for each.
28
28
  * `key-labels` renames any key, on every platform, such as
29
- * `key-labels='{"mod":"Command"}'`.
29
+ * `key-labels='{"mod":"Command"}'`. On an Apple keyboard a word joins the
30
+ * next key with a hyphen, as in `Command-K`.
31
+ *
32
+ * **`activate` makes the shortcut work the control `for` names**, with no
33
+ * script: `activate="focus"` moves focus to it, as `/` does to a search
34
+ * field, and `activate="click"` presses it. It acts once `helix-shortcut` has
35
+ * gone out and no listener canceled it, and only where `within` listens.
30
36
  *
31
37
  * @since 0.1.0
32
38
  * @status stable
@@ -40,9 +46,18 @@ import { type PropertyValues, type TemplateResult } from 'lit';
40
46
  *
41
47
  * @csspart kbd - The key, or the chord under `keys`.
42
48
  * @csspart key - One key of a chord under `keys` and `caps`, such as `Ctrl` in `Ctrl+K`.
43
- * @csspart separator - The `+` between two keys of a chord under `keys` and `caps`, drawn where the platform writes one: on Windows and Linux. An Apple keyboard writes none.
49
+ * @csspart separator - The `+` between two keys of a chord under `keys` and `caps`, drawn where the platform writes one: on Windows and Linux. An Apple keyboard writes none between glyphs, and a hyphen between words from `key-labels`.
44
50
  */
45
51
  export declare class HelixHeadlessKbd extends HelixElement {
52
+ /**
53
+ * What the chord does to the control `for` names once it is pressed:
54
+ * `focus` moves focus to the control and `click` presses it.
55
+ *
56
+ * Unset, the chord sends `helix-shortcut` and does nothing else, for a page
57
+ * that acts on the event itself. It acts only where `within` listens, after
58
+ * `helix-shortcut`, and not when a listener cancels that event.
59
+ */
60
+ activate?: 'click' | 'focus';
46
61
  /**
47
62
  * Draws a chord under `keys` as one key per key, each a `key` part with a
48
63
  * `separator` part between two where the platform writes a `+`, as GitHub
@@ -72,7 +87,7 @@ export declare class HelixHeadlessKbd extends HelixElement {
72
87
  * changes: the chord written onto `aria-keyshortcuts` keeps the names a
73
88
  * screen reader knows.
74
89
  */
75
- keyLabels?: Record<string, string>;
90
+ keyLabels: Record<string, string>;
76
91
  /**
77
92
  * The key or chord to show, such as `mod+k`, `?`, or `/`.
78
93
  *
@@ -119,6 +134,8 @@ export declare class HelixHeadlessKbd extends HelixElement {
119
134
  private listen;
120
135
  private deafen;
121
136
  private readonly handleKeydown;
137
+ /** Focuses or presses the control `for` names, as `activate` says. */
138
+ private act;
122
139
  protected firstUpdated(changed: PropertyValues): void;
123
140
  protected render(): TemplateResult;
124
141
  /**
@@ -4,9 +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 { ariaChord, chordParts, customElement, elementById, HelixElement, HelixShortcutEvent, matchesChord, onApple, printableChord, } from '@fusion.dev/helix-core';
7
+ import { ariaChord, chordParts, customElement, elementById, HelixElement, HelixShortcutEvent, matchesChord, onApple, printableChord, wordsConverter, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ import { keyNames } from '../keys.js';
10
11
  import { claimShortcut, releaseShortcut } from '../shortcut.js';
11
12
  const typing = (node) => {
12
13
  if (node instanceof HTMLTextAreaElement) {
@@ -29,49 +30,12 @@ const UNTYPED = new Set([
29
30
  'reset',
30
31
  'submit',
31
32
  ]);
32
- const APPLE = {
33
- alt: '⌥',
34
- backspace: '⌫',
35
- cmd: '⌘',
36
- ctrl: '⌃',
37
- del: '⌦',
38
- down: '↓',
39
- enter: '↵',
40
- esc: 'Esc',
41
- left: '←',
42
- meta: '⌘',
43
- mod: '⌘',
44
- opt: '⌥',
45
- right: '→',
46
- shift: '⇧',
47
- space: 'Space',
48
- tab: '⇥',
49
- up: '↑',
50
- };
51
- const ELSEWHERE = {
52
- alt: 'Alt',
53
- backspace: 'Backspace',
54
- cmd: 'Win',
55
- ctrl: 'Ctrl',
56
- del: 'Del',
57
- down: '↓',
58
- enter: 'Enter',
59
- esc: 'Esc',
60
- left: '←',
61
- meta: 'Win',
62
- mod: 'Ctrl',
63
- opt: 'Alt',
64
- right: '→',
65
- shift: 'Shift',
66
- space: 'Space',
67
- tab: 'Tab',
68
- up: '↑',
69
- };
70
33
  let HelixHeadlessKbd = class HelixHeadlessKbd extends HelixElement {
71
34
  constructor() {
72
35
  super(...arguments);
73
36
  this.caps = false;
74
37
  this.for = '';
38
+ this.keyLabels = {};
75
39
  this.keys = '';
76
40
  this.handleKeydown = (event) => {
77
41
  const press = event;
@@ -88,9 +52,11 @@ let HelixHeadlessKbd = class HelixHeadlessKbd extends HelixElement {
88
52
  }
89
53
  const shortcut = new HelixShortcutEvent({ keys: this.keys });
90
54
  this.dispatchEvent(shortcut);
91
- if (!shortcut.defaultPrevented) {
92
- press.preventDefault();
55
+ if (shortcut.defaultPrevented) {
56
+ return;
93
57
  }
58
+ press.preventDefault();
59
+ this.act();
94
60
  };
95
61
  }
96
62
  connectedCallback() {
@@ -133,14 +99,7 @@ let HelixHeadlessKbd = class HelixHeadlessKbd extends HelixElement {
133
99
  }
134
100
  }
135
101
  get label() {
136
- const apple = !this.hydrating && onApple();
137
- const names = apple ? APPLE : ELSEWHERE;
138
- const own = this.keyLabels ?? {};
139
- const keys = chordParts(this.keys).map((part) => {
140
- const name = part.toLowerCase();
141
- return own[name] ?? names[name] ?? (part.length === 1 ? part.toUpperCase() : part);
142
- });
143
- return { keys, separator: apple ? '' : '+' };
102
+ return keyNames(chordParts(this.keys), !this.hydrating && onApple(), this.keyLabels ?? {});
144
103
  }
145
104
  listen() {
146
105
  if (!this.within || this.keys === '') {
@@ -157,6 +116,18 @@ let HelixHeadlessKbd = class HelixHeadlessKbd extends HelixElement {
157
116
  this.listening?.removeEventListener('keydown', this.handleKeydown);
158
117
  this.listening = undefined;
159
118
  }
119
+ act() {
120
+ const control = this.activate && this.for !== '' ? elementById(this, this.for) : null;
121
+ if (!(control instanceof HTMLElement)) {
122
+ return;
123
+ }
124
+ if (this.activate === 'click') {
125
+ control.click();
126
+ }
127
+ else {
128
+ control.focus();
129
+ }
130
+ }
160
131
  firstUpdated(changed) {
161
132
  super.firstUpdated(changed);
162
133
  this.finishHydration();
@@ -173,6 +144,9 @@ let HelixHeadlessKbd = class HelixHeadlessKbd extends HelixElement {
173
144
  return html `${keys.map((key, index) => html `${index > 0 && separator !== '' ? html `<span part="separator">${separator}</span>` : nothing}<span part="key">${key}</span>`)}`;
174
145
  }
175
146
  };
147
+ __decorate([
148
+ property()
149
+ ], HelixHeadlessKbd.prototype, "activate", void 0);
176
150
  __decorate([
177
151
  property({ reflect: true, type: Boolean })
178
152
  ], HelixHeadlessKbd.prototype, "caps", void 0);
@@ -180,7 +154,7 @@ __decorate([
180
154
  property()
181
155
  ], HelixHeadlessKbd.prototype, "for", void 0);
182
156
  __decorate([
183
- property({ attribute: 'key-labels', type: Object })
157
+ property({ attribute: 'key-labels', converter: wordsConverter })
184
158
  ], HelixHeadlessKbd.prototype, "keyLabels", void 0);
185
159
  __decorate([
186
160
  property()
@@ -1,8 +1,16 @@
1
+ /** A list as it may be given: names separated by commas, or an array of names. */
2
+ export type NameList = string | readonly string[];
3
+ /**
4
+ * The names in a list, written either way: split on commas from a string,
5
+ * trimmed and without blanks from an array, which is what a framework hands
6
+ * over for `hiddenSeries={['Direct']}`.
7
+ */
8
+ export declare const namesIn: (list: NameList) => string[];
1
9
  /** Whether a name is in the list, matched without regard to case, as a heading is. */
2
- export declare const isHidden: (list: string, name: string) => boolean;
10
+ export declare const isHidden: (list: NameList, name: string) => boolean;
3
11
  /**
4
12
  * The list a press on this name leaves: without it where it was hidden, and
5
13
  * with it at the end where it was shown. Written back with a comma and a
6
14
  * space, as a person writes a list.
7
15
  */
8
- export declare const toggledNames: (list: string, name: string) => string;
16
+ export declare const toggledNames: (list: NameList, name: string) => string;
@@ -1,11 +1,14 @@
1
1
  import { commaList, seriesKey } from '@fusion.dev/helix-core';
2
+ export const namesIn = (list) => typeof list === 'string'
3
+ ? commaList(list)
4
+ : list.map((name) => String(name).trim()).filter((name) => name !== '');
2
5
  export const isHidden = (list, name) => {
3
6
  const key = seriesKey(name);
4
- return commaList(list).some((one) => seriesKey(one) === key);
7
+ return namesIn(list).some((one) => seriesKey(one) === key);
5
8
  };
6
9
  export const toggledNames = (list, name) => {
7
10
  const key = seriesKey(name);
8
- const now = commaList(list);
11
+ const now = namesIn(list);
9
12
  const next = isHidden(list, name)
10
13
  ? now.filter((one) => seriesKey(one) !== key)
11
14
  : [...now, name.trim()];
@@ -1,5 +1,5 @@
1
1
  import { HelixElement, KeyboardNavigationController, SourceController } from '@fusion.dev/helix-core';
2
- import { type PropertyValues, type TemplateResult } from 'lit';
2
+ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
3
3
  /**
4
4
  * @summary A list of the series in a chart, each name beside the color it is drawn in.
5
5
  *
@@ -21,9 +21,10 @@ import { type PropertyValues, type TemplateResult } from 'lit';
21
21
  * **`toggles` makes each entry a button that hides its series.** Every chart
22
22
  * reading the same table draws without a hidden series and fits its scale to
23
23
  * the rest, and the series keeps its color. The button says whether its
24
- * series is shown with `aria-pressed`. The buttons are one tab stop: the
25
- * arrow keys move between them, Home and End go to the first and the last,
26
- * and a typed letter goes to the next name starting with it.
24
+ * series is shown with `aria-pressed`. The buttons are a `toolbar`, named
25
+ * as the list is, and one tab stop: the arrow keys move between them, Home
26
+ * and End go to the first and the last, and a typed letter goes to the next
27
+ * name starting with it.
27
28
  * `hidden-series` holds the hidden names,
28
29
  * so a page can start with some hidden or read which are. Two legends on one
29
30
  * table show the same hidden series: the list written last wins, and the
@@ -42,7 +43,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
42
43
  * `::part(entry)::before` in your stylesheet. The entry holds its series color
43
44
  * as `--chart-series`, and this tier ships no CSS.
44
45
  * @csspart entry-hidden - An entry whose series is hidden. Set alongside `entry`.
45
- * @csspart list - The list of entries.
46
+ * @csspart list - The list of entries, a `toolbar` under `toggles`.
46
47
  * @csspart name - One series name.
47
48
  * @csspart toggle - The button around a name under `toggles`, which hides or shows its series.
48
49
  */
@@ -84,9 +85,11 @@ export declare class HelixHeadlessLegend extends HelixElement {
84
85
  *
85
86
  * Set it to start with series hidden. Every chart reading the same table
86
87
  * draws without them. Commas only, because a column's heading may hold a
87
- * space. For a ring the names are the rows.
88
+ * space. For a ring the names are the rows. An array of names set on the
89
+ * property works too, as React sets `hiddenSeries={['Direct']}`; a toggle
90
+ * writes the list back as a string.
88
91
  */
89
- hiddenSeries: string;
92
+ hiddenSeries: string | readonly string[];
90
93
  /**
91
94
  * The name of the list, which a screen reader announces before its entries.
92
95
  *
@@ -176,6 +179,21 @@ export declare class HelixHeadlessLegend extends HelixElement {
176
179
  */
177
180
  protected names(): string[];
178
181
  protected render(): TemplateResult;
182
+ /**
183
+ * What an entry shows before its name, behind a seam a tier can fill.
184
+ *
185
+ * Nothing on this tier, which ships no CSS: the styled tier and a page draw
186
+ * the swatch with `::part(entry)::before`, from the entry's `--chart-series`.
187
+ * A tier that draws its swatch as an element, or a mark per series, returns
188
+ * it here, and `index` says which palette slot the series takes.
189
+ */
190
+ protected renderSwatch(_name: string, _index: number): TemplateResult | typeof nothing;
191
+ /**
192
+ * An entry's name, behind a seam a tier can move: a value beside the name,
193
+ * or the name in other words. `index` is the series' place among the
194
+ * entries. A toggle holds the same name inside its button.
195
+ */
196
+ protected renderName(name: string, _index: number): TemplateResult;
179
197
  /**
180
198
  * The button around a name under `toggles`, behind a seam a tier can move.
181
199
  *
@@ -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 { commaList, customElement, HelixBeforeChangeEvent, HelixElement, KeyboardNavigationController, requestChange, SourceController, seriesIndex, seriesKey, typeaheadBy, } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixBeforeChangeEvent, HelixElement, KeyboardNavigationController, requestChange, SourceController, seriesIndex, seriesKey, typeaheadBy, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
- import { isHidden, toggledNames } from '../hidden-series.js';
10
+ import { isHidden, namesIn, toggledNames } from '../hidden-series.js';
11
11
  let HelixHeadlessLegend = class HelixHeadlessLegend extends HelixElement {
12
12
  constructor() {
13
13
  super(...arguments);
@@ -41,15 +41,16 @@ let HelixHeadlessLegend = class HelixHeadlessLegend extends HelixElement {
41
41
  }
42
42
  const table = this.source.element;
43
43
  const asked = changed.has('hiddenSeries') &&
44
- !(changed.get('hiddenSeries') === undefined && this.hiddenSeries === '');
45
- this.writes = asked || (table !== null && table !== this.wroteTo && this.hiddenSeries !== '');
44
+ !(changed.get('hiddenSeries') === undefined && namesIn(this.hiddenSeries).length === 0);
45
+ this.writes =
46
+ asked || (table !== null && table !== this.wroteTo && namesIn(this.hiddenSeries).length > 0);
46
47
  if (!this.writes && table !== null) {
47
48
  this.follow();
48
49
  }
49
50
  }
50
51
  follow() {
51
52
  const hidden = this.source.hidden;
52
- const now = commaList(this.hiddenSeries);
53
+ const now = namesIn(this.hiddenSeries);
53
54
  const next = this.names().filter((name) => hidden.has(seriesKey(name)));
54
55
  const same = next.length === now.length &&
55
56
  next.every((name) => now.some((one) => seriesKey(one) === seriesKey(name)));
@@ -61,7 +62,7 @@ let HelixHeadlessLegend = class HelixHeadlessLegend extends HelixElement {
61
62
  super.updated(changed);
62
63
  if (this.writes) {
63
64
  this.writes = false;
64
- this.wroteTo = this.source.hide(commaList(this.hiddenSeries), this.names()) ?? this.wroteTo;
65
+ this.wroteTo = this.source.hide(namesIn(this.hiddenSeries), this.names()) ?? this.wroteTo;
65
66
  }
66
67
  }
67
68
  disconnectedCallback() {
@@ -93,20 +94,31 @@ let HelixHeadlessLegend = class HelixHeadlessLegend extends HelixElement {
93
94
  const named = this.label || this.source.element?.querySelector('caption')?.textContent?.trim();
94
95
  const names = this.names();
95
96
  const stop = Math.min(this.stop, names.length - 1);
96
- return html `<ul aria-label=${named || nothing} part="list" role="list">
97
+ const toolbar = this.toggles;
98
+ return html `<ul
99
+ aria-label=${named || nothing}
100
+ part="list"
101
+ role=${toolbar ? 'toolbar' : 'list'}
102
+ >
97
103
  ${names.map((name, index) => {
98
104
  const off = isHidden(this.hiddenSeries, name);
99
105
  return html `<li
100
106
  data-series=${seriesIndex(index)}
101
107
  part="entry${off ? ' entry-hidden' : ''}"
102
108
  style="--chart-series: var(--chart-series-${seriesIndex(index)})"
103
- role="listitem"
109
+ role=${toolbar ? 'none' : 'listitem'}
104
110
  >
105
- ${this.toggles ? this.renderToggle(name, off, index, index === stop) : html `<span part="name">${name}</span>`}
111
+ ${this.renderSwatch(name, index)}${toolbar ? this.renderToggle(name, off, index, index === stop) : this.renderName(name, index)}
106
112
  </li>`;
107
113
  })}
108
114
  </ul>`;
109
115
  }
116
+ renderSwatch(_name, _index) {
117
+ return nothing;
118
+ }
119
+ renderName(name, _index) {
120
+ return html `<span part="name">${name}</span>`;
121
+ }
110
122
  renderToggle(name, off, index = 0, holds = true) {
111
123
  return html `<button
112
124
  aria-pressed=${off ? 'false' : 'true'}
@@ -118,7 +130,7 @@ let HelixHeadlessLegend = class HelixHeadlessLegend extends HelixElement {
118
130
  this.stop = index;
119
131
  }}
120
132
  >
121
- <span part="name">${name}</span>
133
+ ${this.renderName(name, index)}
122
134
  </button>`;
123
135
  }
124
136
  };
@@ -30,7 +30,11 @@ declare const HelixHeadlessLightbox_base: (new (...args: any[]) => import("@fusi
30
30
  * about. `+` and `-` zoom in and out from the keyboard, and `0` puts it back.
31
31
  * The scale and the offset are on the `viewport` part as `--lightbox-zoom`,
32
32
  * `--lightbox-pan-x` and `--lightbox-pan-y`, written only while zoomed, and a
33
- * swipe moves to the next item only while the item is at its own size.
33
+ * swipe moves to the next item only while the item is at its own size. With
34
+ * `controls`, the viewer also draws zoom-out and zoom-in controls, for a
35
+ * pointer with no wheel and no second finger. Once a reader stops zooming, the
36
+ * live region says the new scale in the words of `zoom-status-label`, such as
37
+ * "Zoomed to 150%".
34
38
  *
35
39
  * Each item is a slide: a `group` with the role description in
36
40
  * `slide-role-label`, named by its `label` or by `slide-label`. A touch or a pen
@@ -55,6 +59,8 @@ declare const HelixHeadlessLightbox_base: (new (...args: any[]) => import("@fusi
55
59
  * @slot header - Content above the item, such as a title and a close button.
56
60
  * @slot next-icon - Replaces the glyph inside the next control.
57
61
  * @slot previous-icon - Replaces the glyph inside the previous control.
62
+ * @slot zoom-in-icon - Replaces the glyph inside the zoom-in control.
63
+ * @slot zoom-out-icon - Replaces the glyph inside the zoom-out control.
58
64
  *
59
65
  * @event {Event} close - Fired when the viewer closes. The component dispatches it again from the host, because the dialog's own event does not leave the shadow root.
60
66
  * @event {HelixActivateEvent} helix-activate - Fired after the shown item changes, when the element already holds the new item.
@@ -67,12 +73,18 @@ declare const HelixHeadlessLightbox_base: (new (...args: any[]) => import("@fusi
67
73
  * @csspart dialog - The native dialog element.
68
74
  * @csspart dismiss - The close control, drawn with `controls`.
69
75
  * @csspart dismiss-mark - The glyph on the close control, where none is slotted.
70
- * @csspart live - The live region that announces which item is shown.
76
+ * @csspart footer - The slot the footer is in. It draws no box until you give it one.
77
+ * @csspart header - The slot the header is in. It draws no box until you give it one.
78
+ * @csspart live - The live region that announces which item is shown, and the scale once a reader has zoomed.
71
79
  * @csspart next - The control that shows the next item, drawn with `controls`.
72
80
  * @csspart next-mark - The glyph on the next control, where none is slotted.
73
81
  * @csspart previous - The control that shows the previous item, drawn with `controls`.
74
82
  * @csspart previous-mark - The glyph on the previous control, where none is slotted.
75
83
  * @csspart viewport - The box the current item is shown in.
84
+ * @csspart zoom-in - The control that zooms in by half again, drawn with `controls` where `max-zoom` allows zooming.
85
+ * @csspart zoom-in-mark - The glyph on the zoom-in control, where none is slotted.
86
+ * @csspart zoom-out - The control that zooms back out, drawn with `controls` where `max-zoom` allows zooming.
87
+ * @csspart zoom-out-mark - The glyph on the zoom-out control, where none is slotted.
76
88
  *
77
89
  * @cssproperty --lightbox-pan-x - How far the zoomed item is moved across from the middle of the viewport, in pixels, toward the right. Written only while zoomed.
78
90
  * @cssproperty --lightbox-pan-y - How far the zoomed item is moved down from the middle of the viewport, in pixels. Written only while zoomed.
@@ -86,12 +98,14 @@ declare const HelixHeadlessLightbox_base: (new (...args: any[]) => import("@fusi
86
98
  */
87
99
  export declare class HelixHeadlessLightbox extends HelixHeadlessLightbox_base {
88
100
  /**
89
- * Draws the viewer's own previous, next and close controls over the picture.
101
+ * Draws the viewer's own previous, next and close controls over the picture,
102
+ * and zoom-out and zoom-in controls where `max-zoom` allows zooming.
90
103
  *
91
104
  * Off by default, for a viewer whose chrome you compose in the `header` and
92
105
  * `footer` slots. The controls hide with the rest of the chrome while the
93
- * reader is idle, and the previous and next ones say they are unavailable at
94
- * either end of a set that does not `loop`.
106
+ * reader is idle, the previous and next ones say they are unavailable at
107
+ * either end of a set that does not `loop`, and the zoom ones at either end
108
+ * of the scale.
95
109
  */
96
110
  controls: boolean;
97
111
  /**
@@ -156,16 +170,36 @@ export declare class HelixHeadlessLightbox extends HelixHeadlessLightbox_base {
156
170
  * counter in the chrome can empty this and say it themselves.
157
171
  */
158
172
  statusLabel: string;
173
+ /**
174
+ * The zoom-in control's accessible name.
175
+ */
176
+ zoomInLabel: string;
177
+ /**
178
+ * The zoom-out control's accessible name.
179
+ */
180
+ zoomOutLabel: string;
181
+ /**
182
+ * What the live region says once a reader has stopped zooming, with the
183
+ * scale as a whole `{percent}` filled in. Empty it to say nothing.
184
+ */
185
+ zoomStatusLabel: string;
159
186
  /** Whether the reader has been still long enough to hide the chrome. */
160
187
  private resting;
161
188
  /** Whether the viewer is filling the screen. */
162
189
  private filled;
163
190
  /** What the live region is currently saying. */
164
191
  private announcement;
192
+ /** The scale the shown item is drawn at, which the zoom controls read. */
193
+ private zoomScale;
194
+ private readonly zoomSaid;
195
+ /** Whether the zoom is being put back because the item changed, which says nothing. */
196
+ private quietZoom;
165
197
  protected readonly swipes: SwipeController;
166
198
  private readonly zoomer;
167
199
  /** Writes the zoom on the viewport, and nothing at the item's own size. */
168
200
  private drawZoom;
201
+ /** Says the new scale in the live region, a moment after the last change. */
202
+ private sayZoom;
169
203
  /**
170
204
  * Zooms the shown item to `scale`, held between `1` and `max-zoom`, about
171
205
  * the middle of the viewport.
@@ -243,6 +277,10 @@ export declare class HelixHeadlessLightbox extends HelixHeadlessLightbox_base {
243
277
  private readonly handleKeydown;
244
278
  /** `+` and `-` zoom in and out by half again, and `0` puts the item back. Returns whether it was one. */
245
279
  private zoomKey;
280
+ /** Zooms in by half again, as `+` and the zoom-in control do. */
281
+ private zoomIn;
282
+ /** Zooms out by as much, as `-` and the zoom-out control do. */
283
+ private zoomOut;
246
284
  /** Home and End, which are an index rather than a step. */
247
285
  private toEnd;
248
286
  /** The item on screen: the one `active` names, or the first where it names none. */
@@ -288,6 +326,13 @@ export declare class HelixHeadlessLightbox extends HelixHeadlessLightbox_base {
288
326
  * control that has just shown the last picture keeps focus.
289
327
  */
290
328
  protected renderControls(): TemplateResult;
329
+ /**
330
+ * Zoom out and zoom in, for a pointer with no wheel and no second finger.
331
+ *
332
+ * Out before in, so they read as a scale runs. `aria-disabled` at either
333
+ * limit, as the previous and next controls are at the ends.
334
+ */
335
+ protected renderZoomControls(): TemplateResult;
291
336
  }
292
337
  declare global {
293
338
  interface HTMLElementTagNameMap {