@fusion.dev/helix-headless 0.142.1 → 0.143.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/custom-elements.json +16710 -707
  2. package/dist/accordion/item/accordion-item.d.ts +38 -2
  3. package/dist/accordion/item/accordion-item.js +38 -6
  4. package/dist/accordion/root/accordion-root.d.ts +23 -1
  5. package/dist/accordion/root/accordion-root.js +39 -3
  6. package/dist/announcement/root/announcement-root.d.ts +11 -7
  7. package/dist/announcement/root/announcement-root.js +1 -1
  8. package/dist/app-header/root/app-header-root.d.ts +21 -0
  9. package/dist/app-header/root/app-header-root.js +31 -5
  10. package/dist/area-chart/root/area-chart-root.js +16 -5
  11. package/dist/avatar/group/avatar-group.d.ts +24 -3
  12. package/dist/avatar/group/avatar-group.js +34 -2
  13. package/dist/avatar/root/avatar-root.d.ts +3 -1
  14. package/dist/avatar/root/avatar-root.js +8 -1
  15. package/dist/badge/root/badge-root.d.ts +8 -0
  16. package/dist/bar-chart/root/bar-chart-root.d.ts +19 -3
  17. package/dist/bar-chart/root/bar-chart-root.js +43 -13
  18. package/dist/blockquote/root/blockquote-root.d.ts +12 -7
  19. package/dist/blockquote/root/blockquote-root.js +6 -4
  20. package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +9 -3
  21. package/dist/breadcrumbs/root/breadcrumbs-root.js +9 -1
  22. package/dist/button/root/button-root.d.ts +37 -0
  23. package/dist/button/root/button-root.js +44 -0
  24. package/dist/callout/root/callout-root.d.ts +14 -5
  25. package/dist/callout/root/callout-root.js +11 -3
  26. package/dist/canvas/root/canvas-root.d.ts +1 -0
  27. package/dist/canvas/root/canvas-root.js +10 -1
  28. package/dist/carousel/root/carousel-root.d.ts +47 -5
  29. package/dist/carousel/root/carousel-root.js +53 -21
  30. package/dist/chat/composer/chat-composer.d.ts +13 -11
  31. package/dist/chat/composer/chat-composer.js +6 -12
  32. package/dist/chat/message/chat-message.js +8 -1
  33. package/dist/chat/root/chat-root.d.ts +1 -0
  34. package/dist/chat/root/chat-root.js +2 -1
  35. package/dist/checkbox/root/checkbox-root.d.ts +7 -0
  36. package/dist/checkbox/root/checkbox-root.js +7 -3
  37. package/dist/checkbox-group/root/checkbox-group-root.d.ts +65 -32
  38. package/dist/checkbox-group/root/checkbox-group-root.js +85 -37
  39. package/dist/code/root/code-root.d.ts +1 -1
  40. package/dist/code-block/root/code-block-root.d.ts +19 -0
  41. package/dist/code-block/root/code-block-root.js +21 -1
  42. package/dist/color-input/root/color-input-root.d.ts +26 -1
  43. package/dist/color-input/root/color-input-root.js +32 -3
  44. package/dist/color-picker/root/color-picker-root.d.ts +37 -7
  45. package/dist/color-picker/root/color-picker-root.js +83 -6
  46. package/dist/combobox/root/combobox-root.d.ts +90 -2
  47. package/dist/combobox/root/combobox-root.js +160 -19
  48. package/dist/command/root/command-root.d.ts +17 -6
  49. package/dist/command/root/command-root.js +12 -1
  50. package/dist/copy-button/root/copy-button-root.d.ts +21 -6
  51. package/dist/copy-button/root/copy-button-root.js +11 -1
  52. package/dist/data-table/root/data-table-root.d.ts +164 -10
  53. package/dist/data-table/root/data-table-root.js +488 -57
  54. package/dist/date-input/root/date-input-root.d.ts +53 -8
  55. package/dist/date-input/root/date-input-root.js +70 -18
  56. package/dist/date-picker/root/date-picker-root.d.ts +84 -17
  57. package/dist/date-picker/root/date-picker-root.js +125 -20
  58. package/dist/dialog/root/dialog-root.d.ts +38 -10
  59. package/dist/dialog/root/dialog-root.js +55 -2
  60. package/dist/donut-chart/root/donut-chart-root.d.ts +39 -15
  61. package/dist/donut-chart/root/donut-chart-root.js +30 -10
  62. package/dist/drawer/root/drawer-root.d.ts +32 -7
  63. package/dist/drawer/root/drawer-root.js +50 -5
  64. package/dist/drilldown/item/drilldown-item.d.ts +16 -13
  65. package/dist/drilldown/item/drilldown-item.js +6 -2
  66. package/dist/drilldown/root/drilldown-root.d.ts +21 -5
  67. package/dist/drilldown/root/drilldown-root.js +26 -10
  68. package/dist/element-events.generated.js +35 -9
  69. package/dist/file-input/root/file-input-root.d.ts +18 -1
  70. package/dist/file-input/root/file-input-root.js +34 -8
  71. package/dist/filter-input/menu/filter-menu.d.ts +9 -0
  72. package/dist/filter-input/menu/filter-menu.js +8 -0
  73. package/dist/filter-input/root/filter-input-root.d.ts +5 -2
  74. package/dist/filter-input/root/filter-input-root.js +22 -7
  75. package/dist/format-date/root/format-date-root.d.ts +11 -3
  76. package/dist/format-date/root/format-date-root.js +26 -5
  77. package/dist/graph/root/graph-root.d.ts +24 -3
  78. package/dist/graph/root/graph-root.js +66 -12
  79. package/dist/heatmap/root/buckets.d.ts +2 -1
  80. package/dist/heatmap/root/buckets.js +5 -1
  81. package/dist/heatmap/root/heatmap-root.d.ts +27 -6
  82. package/dist/heatmap/root/heatmap-root.js +23 -6
  83. package/dist/icon/root/icon-root.d.ts +24 -3
  84. package/dist/icon/root/icon-root.js +34 -1
  85. package/dist/icon-button/root/icon-button-root.d.ts +1 -1
  86. package/dist/image/root/image-root.d.ts +9 -2
  87. package/dist/image/root/image-root.js +8 -2
  88. package/dist/input/root/input-root.d.ts +51 -9
  89. package/dist/input/root/input-root.js +46 -5
  90. package/dist/kbd/root/kbd-root.d.ts +12 -4
  91. package/dist/kbd/root/kbd-root.js +10 -11
  92. package/dist/legend/root/legend-root.d.ts +7 -0
  93. package/dist/legend/root/legend-root.js +7 -2
  94. package/dist/lightbox/item/lightbox-item.d.ts +2 -1
  95. package/dist/lightbox/root/lightbox-root.d.ts +16 -5
  96. package/dist/lightbox/root/lightbox-root.js +24 -3
  97. package/dist/line-chart/root/line-chart-root.d.ts +19 -2
  98. package/dist/line-chart/root/line-chart-root.js +40 -13
  99. package/dist/list/item/list-item.d.ts +11 -5
  100. package/dist/list/item/list-item.js +5 -6
  101. package/dist/listbox/root/listbox-root.d.ts +111 -2
  102. package/dist/listbox/root/listbox-root.js +144 -16
  103. package/dist/map/root/map-root.d.ts +19 -4
  104. package/dist/map/root/map-root.js +36 -7
  105. package/dist/megamenu/root/megamenu-root.d.ts +10 -1
  106. package/dist/megamenu/root/megamenu-root.js +10 -1
  107. package/dist/menu/item/menu-item.d.ts +41 -12
  108. package/dist/menu/item/menu-item.js +46 -3
  109. package/dist/menu/root/menu-root.d.ts +32 -2
  110. package/dist/menu/root/menu-root.js +48 -8
  111. package/dist/meter/root/meter-root.d.ts +6 -0
  112. package/dist/meter/root/meter-root.js +18 -2
  113. package/dist/navigation/root/navigation-root.d.ts +10 -2
  114. package/dist/navigation/root/navigation-root.js +13 -2
  115. package/dist/notifications/group/notification-group.d.ts +1 -0
  116. package/dist/notifications/notification/notification.d.ts +12 -0
  117. package/dist/notifications/notification/notification.js +31 -2
  118. package/dist/notifications/root/notifications-root.d.ts +7 -0
  119. package/dist/notifications/root/notifications-root.js +17 -2
  120. package/dist/number-input/root/number-input-root.d.ts +62 -7
  121. package/dist/number-input/root/number-input-root.js +68 -16
  122. package/dist/object-inspector/root/object-inspector-root.d.ts +48 -5
  123. package/dist/object-inspector/root/object-inspector-root.js +91 -11
  124. package/dist/option/root/option-root.d.ts +4 -1
  125. package/dist/option/root/option-root.js +1 -0
  126. package/dist/outline/root/outline-root.d.ts +13 -2
  127. package/dist/outline/root/outline-root.js +4 -2
  128. package/dist/pagination/root/pagination-root.d.ts +19 -1
  129. package/dist/pagination/root/pagination-root.js +49 -9
  130. package/dist/pagination/size/pagination-size.d.ts +13 -3
  131. package/dist/pagination/size/pagination-size.js +7 -0
  132. package/dist/pin-input/root/pin-input-root.d.ts +16 -0
  133. package/dist/pin-input/root/pin-input-root.js +19 -5
  134. package/dist/popover/root/popover-root.d.ts +19 -2
  135. package/dist/popover/root/popover-root.js +22 -1
  136. package/dist/progress/root/progress-root.d.ts +16 -1
  137. package/dist/progress/root/progress-root.js +31 -7
  138. package/dist/qr-code/root/qr-code-root.d.ts +19 -0
  139. package/dist/qr-code/root/qr-code-root.js +29 -1
  140. package/dist/radio/group/radio-group.d.ts +41 -0
  141. package/dist/radio/group/radio-group.js +50 -14
  142. package/dist/radio/root/radio-root.d.ts +8 -5
  143. package/dist/radio/root/radio-root.js +1 -2
  144. package/dist/rating/root/rating-root.d.ts +24 -1
  145. package/dist/rating/root/rating-root.js +24 -7
  146. package/dist/scatter-chart/root/scatter-chart-root.js +15 -7
  147. package/dist/select/root/select-root.d.ts +69 -3
  148. package/dist/select/root/select-root.js +92 -8
  149. package/dist/skeleton/root/skeleton-root.d.ts +14 -3
  150. package/dist/skeleton/root/skeleton-root.js +17 -3
  151. package/dist/skip-link/root/skip-link-root.d.ts +10 -0
  152. package/dist/skip-link/root/skip-link-root.js +15 -1
  153. package/dist/slider/root/slider-root.d.ts +20 -2
  154. package/dist/slider/root/slider-root.js +41 -3
  155. package/dist/sparkline/root/sparkline-root.d.ts +9 -10
  156. package/dist/speed-dial/item/speed-dial-item.d.ts +11 -5
  157. package/dist/speed-dial/item/speed-dial-item.js +7 -2
  158. package/dist/speed-dial/root/speed-dial-root.d.ts +15 -4
  159. package/dist/speed-dial/root/speed-dial-root.js +19 -5
  160. package/dist/splitter/root/splitter-root.d.ts +28 -6
  161. package/dist/splitter/root/splitter-root.js +35 -1
  162. package/dist/stat/root/stat-root.d.ts +7 -1
  163. package/dist/stat/root/stat-root.js +14 -1
  164. package/dist/steps/root/steps-root.js +1 -1
  165. package/dist/switch/root/switch-root.d.ts +2 -0
  166. package/dist/switch/root/switch-root.js +1 -0
  167. package/dist/table/cell/table-cell.d.ts +24 -4
  168. package/dist/table/cell/table-cell.js +21 -1
  169. package/dist/table/column/table-column.d.ts +32 -6
  170. package/dist/table/column/table-column.js +36 -6
  171. package/dist/table/root/table-root.d.ts +94 -3
  172. package/dist/table/root/table-root.js +128 -5
  173. package/dist/table/row/table-row.d.ts +7 -0
  174. package/dist/table/row/table-row.js +9 -1
  175. package/dist/tabs/root/tabs-root.d.ts +6 -1
  176. package/dist/tabs/root/tabs-root.js +6 -2
  177. package/dist/tag/root/tag-root.d.ts +23 -1
  178. package/dist/tag/root/tag-root.js +16 -2
  179. package/dist/textarea/root/textarea-root.d.ts +4 -0
  180. package/dist/textarea/root/textarea-root.js +1 -1
  181. package/dist/time-input/root/time-input-root.d.ts +28 -2
  182. package/dist/time-input/root/time-input-root.js +46 -10
  183. package/dist/time-picker/root/time-picker-root.d.ts +101 -18
  184. package/dist/time-picker/root/time-picker-root.js +115 -16
  185. package/dist/toast/root/toast-root.d.ts +64 -1
  186. package/dist/toast/root/toast-root.js +147 -2
  187. package/dist/toggle/group/toggle-group.d.ts +38 -1
  188. package/dist/toggle/group/toggle-group.js +34 -8
  189. package/dist/toggle/root/toggle-root.d.ts +14 -10
  190. package/dist/toggle/root/toggle-root.js +3 -3
  191. package/dist/toolbar/root/toolbar-root.d.ts +55 -15
  192. package/dist/toolbar/root/toolbar-root.js +99 -16
  193. package/dist/tooltip/root/tooltip-root.d.ts +37 -4
  194. package/dist/tooltip/root/tooltip-root.js +48 -0
  195. package/dist/tour/root/tour-root.d.ts +34 -5
  196. package/dist/tour/root/tour-root.js +51 -14
  197. package/dist/tour/stop/tour-stop.d.ts +18 -1
  198. package/dist/tour/stop/tour-stop.js +25 -5
  199. package/dist/tree/item/tree-item.d.ts +21 -5
  200. package/dist/tree/item/tree-item.js +14 -4
  201. package/dist/tree/root/tree-root.d.ts +29 -5
  202. package/dist/tree/root/tree-root.js +64 -8
  203. package/dist/trend/root/trend-root.d.ts +23 -1
  204. package/dist/trend/root/trend-root.js +28 -7
  205. package/dist/video/root/keys.d.ts +5 -0
  206. package/dist/video/root/keys.js +13 -1
  207. package/dist/video/root/video-root.d.ts +19 -0
  208. package/dist/video/root/video-root.js +48 -4
  209. package/dist/video-playlist/menu/video-playlist-menu.d.ts +20 -2
  210. package/dist/video-playlist/menu/video-playlist-menu.js +27 -5
  211. package/dist/video-playlist/root/video-playlist-root.js +6 -3
  212. package/dist/virtual-list/root/virtual-list-root.d.ts +52 -4
  213. package/dist/virtual-list/root/virtual-list-root.js +103 -21
  214. package/lint.json +1 -1
  215. package/package.json +5 -5
  216. package/types/jsx.d.ts +4348 -965
  217. package/types/vue.d.ts +972 -232
@@ -1,6 +1,6 @@
1
1
  import { HelixElement } from '@fusion.dev/helix-core';
2
2
  import { type HelixIcon } from '@fusion.dev/helix-icons';
3
- import { nothing, type TemplateResult } from 'lit';
3
+ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
4
4
  /**
5
5
  * @summary A named icon from the Helix set.
6
6
  *
@@ -18,11 +18,13 @@ import { nothing, type TemplateResult } from 'lit';
18
18
  * a dark background. Shapes that set their own `fill` or `stroke` are
19
19
  * unaffected.
20
20
  *
21
- * A name with no match renders nothing.
21
+ * A name with no match renders nothing, and the element fires `error`, so a
22
+ * typo in a name can be heard.
22
23
  *
23
24
  * An icon is decorative by default and hidden from assistive technology. Set
24
25
  * `label` only when the icon is the only carrier of meaning, such as in a
25
- * button with no text.
26
+ * button with no text. An `aria-label` on the element works too: the element
27
+ * is then an image with that name.
26
28
  *
27
29
  * @since 0.1.0
28
30
  * @status stable
@@ -30,6 +32,8 @@ import { nothing, type TemplateResult } from 'lit';
30
32
  * @aliases Glyph, Symbol
31
33
  * @documentation https://fusion.dev/helix/components/icon
32
34
  *
35
+ * @event {Event} error - `name` matches no icon in the set, so nothing is drawn.
36
+ *
33
37
  * @csspart svg - The rendered SVG.
34
38
  */
35
39
  export declare class HelixHeadlessIcon extends HelixElement {
@@ -73,6 +77,23 @@ export declare class HelixHeadlessIcon extends HelixElement {
73
77
  * value instead.
74
78
  */
75
79
  name: string;
80
+ /**
81
+ * Hears an `aria-label` written on the element, which no property mirrors.
82
+ *
83
+ * Lit observes the attributes of its own properties only, and `ariaLabel`
84
+ * belongs to the platform.
85
+ */
86
+ static get observedAttributes(): string[];
87
+ /**
88
+ * Called by the browser when an observed attribute changes. A new
89
+ * `aria-label` asks for an update, because the element takes the image role
90
+ * while one names it.
91
+ */
92
+ attributeChangedCallback(name: string, old: string | null, value: string | null): void;
93
+ /** The name the last `error` was fired for, so it fires once per name. */
94
+ private missed;
95
+ protected willUpdate(changed: PropertyValues): void;
96
+ protected updated(changed: PropertyValues): void;
76
97
  protected render(): TemplateResult | typeof nothing;
77
98
  }
78
99
  declare global {
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { customElement, HelixElement } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixElement, hostAria, reportRuntime } from '@fusion.dev/helix-core';
8
8
  import { icons } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { property } from 'lit/decorators.js';
@@ -15,6 +15,39 @@ let HelixHeadlessIcon = class HelixHeadlessIcon extends HelixElement {
15
15
  this.label = '';
16
16
  this.mirror = false;
17
17
  this.name = '';
18
+ this.missed = '';
19
+ }
20
+ static get observedAttributes() {
21
+ return [...super.observedAttributes, 'aria-label'];
22
+ }
23
+ attributeChangedCallback(name, old, value) {
24
+ super.attributeChangedCallback(name, old, value);
25
+ if (name === 'aria-label') {
26
+ this.requestUpdate();
27
+ }
28
+ }
29
+ willUpdate(changed) {
30
+ super.willUpdate(changed);
31
+ const named = this.label === '' && (this.getAttribute?.('aria-label') ?? '') !== '';
32
+ hostAria(this.internals, { role: named ? 'img' : '' });
33
+ }
34
+ updated(changed) {
35
+ super.updated(changed);
36
+ if (this.icon === undefined && this.name !== '' && !Object.hasOwn(icons, this.name)) {
37
+ if (this.missed !== this.name) {
38
+ this.missed = this.name;
39
+ this.dispatchEvent(new Event('error', { bubbles: false, cancelable: false, composed: false }));
40
+ reportRuntime({
41
+ kind: 'unknown-icon',
42
+ message: `<${this.localName} name="${this.name}"> names no icon in the Helix set, so it draws ` +
43
+ 'nothing. Check the name, or import the glyph and pass it as `icon`.',
44
+ tag: this.localName,
45
+ });
46
+ }
47
+ }
48
+ else {
49
+ this.missed = '';
50
+ }
18
51
  }
19
52
  render() {
20
53
  const named = Object.hasOwn(icons, this.name) ? icons[this.name] : undefined;
@@ -25,7 +25,7 @@ import { HelixHeadlessButton } from '../../button/root/button-root.js';
25
25
  *
26
26
  * @slot - The icon.
27
27
  *
28
- * @csspart button - The inner button or anchor.
28
+ * @csspart button - The inner button.
29
29
  */
30
30
  export declare class HelixHeadlessIconButton extends HelixHeadlessButton {
31
31
  }
@@ -33,9 +33,11 @@ export declare class HelixHeadlessImage extends HelixElement {
33
33
  * A text description of the image, read by screen readers.
34
34
  *
35
35
  * Empty is a real answer and means decoration. Omitting the attribute is not
36
- * the same thing: a reader with nothing to read announces the file name.
36
+ * the same thing: the inner image is then written with no `alt` either, as a
37
+ * native one would be, so a screen reader announces the file name and an
38
+ * accessibility checker reports the missing description.
37
39
  */
38
- alt: string;
40
+ alt?: string;
39
41
  /**
40
42
  * How the image is fetched across origins. It decides whether a canvas can
41
43
  * read the image.
@@ -117,6 +119,11 @@ export declare class HelixHeadlessImage extends HelixElement {
117
119
  * for the event it reports, and `settle` runs twice in the first update.
118
120
  */
119
121
  private reported;
122
+ /**
123
+ * The event `settle` sent for a picture that finished before anything
124
+ * listened, so the platform's own, still on its way, is not sent again.
125
+ */
126
+ private synthesized;
120
127
  /**
121
128
  * Says so under the platform's own name, because the platform's cannot escape.
122
129
  *
@@ -10,7 +10,6 @@ import { property, state } from 'lit/decorators.js';
10
10
  let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
11
11
  constructor() {
12
12
  super(...arguments);
13
- this.alt = '';
14
13
  this.crossOrigin = null;
15
14
  this.decoding = 'async';
16
15
  this.fetchPriority = 'auto';
@@ -21,6 +20,7 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
21
20
  this.status = 'loading';
22
21
  this.answered = '';
23
22
  this.reported = false;
23
+ this.synthesized = undefined;
24
24
  this.handleLoad = (event) => {
25
25
  this.announce('loaded', event);
26
26
  };
@@ -32,10 +32,15 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
32
32
  this.reported = true;
33
33
  const name = status === 'loaded' ? 'load' : 'error';
34
34
  if (event) {
35
+ if (this.synthesized === name) {
36
+ this.synthesized = undefined;
37
+ return;
38
+ }
35
39
  this.status = status;
36
40
  this.relayNativeEvent(event);
37
41
  return;
38
42
  }
43
+ this.synthesized = name;
39
44
  const send = () => {
40
45
  this.status = status;
41
46
  this.dispatchEvent(new Event(name, { bubbles: false, cancelable: false, composed: false }));
@@ -64,6 +69,7 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
64
69
  if (changed.has('src') && this.answered !== this.src) {
65
70
  this.answered = this.src;
66
71
  this.reported = false;
72
+ this.synthesized = undefined;
67
73
  this.status = 'loading';
68
74
  }
69
75
  }
@@ -103,7 +109,7 @@ let HelixHeadlessImage = class HelixHeadlessImage extends HelixElement {
103
109
  render() {
104
110
  return html `<img
105
111
  part="image"
106
- alt=${this.alt}
112
+ alt=${this.alt ?? nothing}
107
113
  loading=${this.loading ?? 'lazy'}
108
114
  decoding=${this.decoding}
109
115
  crossorigin=${this.crossOrigin ?? nothing}
@@ -29,6 +29,9 @@ declare const HelixHeadlessInput_base: (new (...args: any[]) => import("@fusion.
29
29
  * @documentation https://fusion.dev/helix/components/input
30
30
  *
31
31
  * @slot end - After the text, for an icon or a unit.
32
+ * @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
33
+ * @slot hint - Help under the control, for content richer than the `hint` text.
34
+ * @slot label - The label, for content richer than the `label` text.
32
35
  * @slot start - Before the text, for an icon or a prefix.
33
36
  *
34
37
  * @event {Event} change - Sent when the user finishes changing the value. Relayed from the native input.
@@ -50,6 +53,11 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
50
53
  protected readonly aria: AriaForwardController;
51
54
  /** Typed or dragged, so every edit is announced. See `announcesInput`. */
52
55
  protected readonly announcesInput = true;
56
+ /**
57
+ * Whether a phone capitalizes as the reader types: `off`, `sentences`,
58
+ * `words` or `characters`, as the platform's `autocapitalize`.
59
+ */
60
+ autocapitalize: string;
53
61
  /**
54
62
  * What the browser may autofill in the field, as an HTML `autocomplete`
55
63
  * token.
@@ -71,10 +79,30 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
71
79
  * The accessible name of the clear button, which shows only an icon.
72
80
  */
73
81
  clearLabel: string;
82
+ /**
83
+ * The key the on-screen keyboard shows for Enter, as the platform's
84
+ * `enterkeyhint`: `search`, `send`, `go`, `next`, `previous`, `done` or
85
+ * `enter`.
86
+ */
87
+ enterKeyHint: string;
88
+ /**
89
+ * The keyboard a phone offers, as the platform's `inputmode`, such as
90
+ * `numeric` for a code typed as text.
91
+ */
92
+ inputMode: string;
93
+ /**
94
+ * The greatest value, for `type="number"`. Number Input adds steppers and
95
+ * keys to the same bounds.
96
+ */
97
+ max: string;
74
98
  /**
75
99
  * Most characters the value may have.
76
100
  */
77
101
  maxLength?: number;
102
+ /**
103
+ * The least value, for `type="number"`.
104
+ */
105
+ min: string;
78
106
  /**
79
107
  * Fewest characters the value may have.
80
108
  */
@@ -106,6 +134,15 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
106
134
  * form, `readOnly` came back `false`.
107
135
  */
108
136
  readOnly: boolean;
137
+ /**
138
+ * Whether a password field offers a toggle that shows what was typed.
139
+ *
140
+ * Ignored on every other type. A reveal on an email field would be a button
141
+ * that does nothing visible, and guarding it here rather than asking the
142
+ * consumer not to means the property can be set once on a component that
143
+ * changes type.
144
+ */
145
+ reveal: boolean;
109
146
  /**
110
147
  * Whether the password is currently showing.
111
148
  *
@@ -181,6 +218,15 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
181
218
  * where it was.
182
219
  */
183
220
  private readonly handleClear;
221
+ /**
222
+ * Enter submits the form, as it does in a native text field.
223
+ *
224
+ * On `keypress`, where the platform runs its own implicit submission, so a
225
+ * consumer who prevents the `keydown` for Enter stops this too.
226
+ */
227
+ private readonly handleKeypress;
228
+ /** @internal A single line of text counts against implicit submission. */
229
+ protected get blocksImplicitSubmission(): boolean;
184
230
  /** Relayed, because `change` does not cross a shadow boundary on its own. */
185
231
  private readonly handleChange;
186
232
  /** Reports the value and the validity the host stands behind. */
@@ -198,21 +244,17 @@ export declare class HelixHeadlessInput extends HelixHeadlessInput_base {
198
244
  private releaseCaret;
199
245
  protected willUpdate(changed: PropertyValues): void;
200
246
  protected updated(changed: PropertyValues): void;
201
- /**
202
- * Whether a password field offers a toggle that shows what was typed.
203
- *
204
- * Ignored on every other type. A reveal on an email field would be a button
205
- * that does nothing visible, and guarding it here rather than asking the
206
- * consumer not to means the property can be set once on a component that
207
- * changes type.
208
- */
209
- reveal: boolean;
210
247
  /**
211
248
  * The accessible name of the reveal toggle.
212
249
  *
213
250
  * The state is `aria-pressed`, not this.
214
251
  */
215
252
  revealLabel: string;
253
+ /**
254
+ * The step a valid value is a multiple of, counted from `min`, for
255
+ * `type="number"`.
256
+ */
257
+ step: string;
216
258
  /**
217
259
  * The kind of text the field accepts. It sets the on-screen keyboard and the
218
260
  * validation.
@@ -15,12 +15,18 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
15
15
  target: () => this.partNamed('control'),
16
16
  });
17
17
  this.announcesInput = true;
18
+ this.autocapitalize = '';
18
19
  this.autocomplete = '';
19
20
  this.clearable = false;
20
21
  this.clearLabel = 'Clear';
22
+ this.enterKeyHint = '';
23
+ this.inputMode = '';
24
+ this.max = '';
25
+ this.min = '';
21
26
  this.pattern = '';
22
27
  this.placeholder = '';
23
28
  this.readOnly = false;
29
+ this.reveal = false;
24
30
  this.revealed = false;
25
31
  this.handleInput = (event) => {
26
32
  event.stopPropagation();
@@ -30,19 +36,26 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
30
36
  restoreValue(control, this.value);
31
37
  };
32
38
  this.handleClear = () => {
33
- this.requestValue('');
39
+ if (this.value !== '' && this.requestValue('')) {
40
+ this.announceChange();
41
+ }
34
42
  const control = this.control;
35
43
  if (control) {
36
44
  restoreValue(control, this.value);
37
45
  control.focus();
38
46
  }
39
47
  };
48
+ this.handleKeypress = (event) => {
49
+ if (event.key === 'Enter' && !event.defaultPrevented) {
50
+ this.submitImplicitly();
51
+ }
52
+ };
40
53
  this.handleChange = (event) => {
41
54
  event.stopPropagation();
42
55
  this.announceChange();
43
56
  };
44
- this.reveal = false;
45
57
  this.revealLabel = 'Show password';
58
+ this.step = '';
46
59
  this.type = 'text';
47
60
  }
48
61
  get effectiveType() {
@@ -88,6 +101,9 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
88
101
  get control() {
89
102
  return this.partNamed('control');
90
103
  }
104
+ get blocksImplicitSubmission() {
105
+ return true;
106
+ }
91
107
  sync() {
92
108
  this.internals.setFormValue(this.value);
93
109
  const control = this.control;
@@ -134,6 +150,12 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
134
150
  pattern=${this.pattern || nothing}
135
151
  minlength=${this.minLength ?? nothing}
136
152
  maxlength=${this.maxLength ?? nothing}
153
+ min=${this.min || nothing}
154
+ max=${this.max || nothing}
155
+ step=${this.step || nothing}
156
+ inputmode=${this.inputMode || nothing}
157
+ enterkeyhint=${this.enterKeyHint || nothing}
158
+ autocapitalize=${this.autocapitalize || nothing}
137
159
  aria-describedby=${this.describedBy ?? nothing}
138
160
  aria-invalid=${this.invalidity ?? nothing}
139
161
  ?disabled=${this.isDisabled}
@@ -141,6 +163,7 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
141
163
  ?required=${this.required}
142
164
  @input=${this.handleInput}
143
165
  @change=${this.handleChange}
166
+ @keypress=${this.handleKeypress}
144
167
  />
145
168
  <slot name="end"></slot>
146
169
  <!-- In the tab order, unlike the browser's own search clear, which is not
@@ -176,6 +199,9 @@ let HelixHeadlessInput = class HelixHeadlessInput extends MixinControllerValue(M
176
199
  ${this.renderHint()}${this.renderFeedback()}`;
177
200
  }
178
201
  };
202
+ __decorate([
203
+ property()
204
+ ], HelixHeadlessInput.prototype, "autocapitalize", void 0);
179
205
  __decorate([
180
206
  property()
181
207
  ], HelixHeadlessInput.prototype, "autocomplete", void 0);
@@ -185,9 +211,21 @@ __decorate([
185
211
  __decorate([
186
212
  property({ attribute: 'clear-label' })
187
213
  ], HelixHeadlessInput.prototype, "clearLabel", void 0);
214
+ __decorate([
215
+ property({ attribute: 'enterkeyhint' })
216
+ ], HelixHeadlessInput.prototype, "enterKeyHint", void 0);
217
+ __decorate([
218
+ property({ attribute: 'inputmode' })
219
+ ], HelixHeadlessInput.prototype, "inputMode", void 0);
220
+ __decorate([
221
+ property()
222
+ ], HelixHeadlessInput.prototype, "max", void 0);
188
223
  __decorate([
189
224
  property({ attribute: 'maxlength', type: Number })
190
225
  ], HelixHeadlessInput.prototype, "maxLength", void 0);
226
+ __decorate([
227
+ property()
228
+ ], HelixHeadlessInput.prototype, "min", void 0);
191
229
  __decorate([
192
230
  property({ attribute: 'minlength', type: Number })
193
231
  ], HelixHeadlessInput.prototype, "minLength", void 0);
@@ -200,15 +238,18 @@ __decorate([
200
238
  __decorate([
201
239
  property({ attribute: 'readonly', reflect: true, type: Boolean })
202
240
  ], HelixHeadlessInput.prototype, "readOnly", void 0);
203
- __decorate([
204
- state()
205
- ], HelixHeadlessInput.prototype, "revealed", void 0);
206
241
  __decorate([
207
242
  property({ type: Boolean })
208
243
  ], HelixHeadlessInput.prototype, "reveal", void 0);
244
+ __decorate([
245
+ state()
246
+ ], HelixHeadlessInput.prototype, "revealed", void 0);
209
247
  __decorate([
210
248
  property({ attribute: 'reveal-label' })
211
249
  ], HelixHeadlessInput.prototype, "revealLabel", void 0);
250
+ __decorate([
251
+ property()
252
+ ], HelixHeadlessInput.prototype, "step", void 0);
212
253
  __decorate([
213
254
  property()
214
255
  ], HelixHeadlessInput.prototype, "type", void 0);
@@ -31,11 +31,16 @@ import { type PropertyValues, type TemplateResult } from 'lit';
31
31
  */
32
32
  export declare class HelixHeadlessKbd extends HelixElement {
33
33
  /**
34
- * The key or chord to show, such as `mod+k`, `shift+?`, or `/`.
34
+ * The key or chord to show, such as `mod+k`, `?`, or `/`.
35
35
  *
36
36
  * `mod` is the platform's own command modifier, which is the reason to write
37
37
  * a chord here rather than a glyph: it is the one token whose right answer
38
38
  * differs per reader.
39
+ *
40
+ * A symbol such as `?` or `!` is written as itself, without `shift`. It is
41
+ * matched whether or not Shift was held to type it, since that depends on
42
+ * the keyboard layout. Bound to the document, a chord that types a character
43
+ * is not taken from a field a reader is typing in.
39
44
  */
40
45
  keys: string;
41
46
  /**
@@ -67,11 +72,14 @@ export declare class HelixHeadlessKbd extends HelixElement {
67
72
  private deafen;
68
73
  private readonly handleKeydown;
69
74
  /**
70
- * Whether this chord is one bare character, and so indistinguishable from
75
+ * Whether this chord types a character, and so is indistinguishable from
71
76
  * typing.
72
77
  *
73
- * A single part means no modifier, and one code point means a character
74
- * rather than a name: `/` and `?` are printable, `escape` and `enter` are not.
78
+ * One code point means a character rather than a name: `/` and `?` are
79
+ * printable, `escape` and `enter` are not. **Shift is allowed beside it**,
80
+ * because Shift is how a character is typed: `shift+?` and `shift+a` are a
81
+ * question mark and a capital A in a field, and taking them ate every one
82
+ * a reader typed on the page.
75
83
  */
76
84
  private get printable();
77
85
  /** Whether a press is this chord, modifiers and all. */
@@ -132,9 +132,10 @@ let HelixHeadlessKbd = class HelixHeadlessKbd extends HelixElement {
132
132
  get printable() {
133
133
  const parts = this.keys
134
134
  .split('+')
135
- .map((part) => part.trim())
135
+ .map((part) => part.trim().toLowerCase())
136
136
  .filter((part) => part !== '');
137
- return parts.length === 1 && [...(parts[0] ?? '')].length === 1;
137
+ const key = parts.at(-1) ?? '';
138
+ return [...key].length === 1 && parts.slice(0, -1).every((modifier) => modifier === 'shift');
138
139
  }
139
140
  matches_(press) {
140
141
  const parts = this.keys
@@ -146,17 +147,15 @@ let HelixHeadlessKbd = class HelixHeadlessKbd extends HelixElement {
146
147
  }
147
148
  const wanted = parts[parts.length - 1] ?? '';
148
149
  const modifiers = new Set(parts.slice(0, -1));
149
- const mod = onApple() ? press.metaKey : press.ctrlKey;
150
+ const apple = onApple();
151
+ const ctrl = modifiers.has('ctrl') || (modifiers.has('mod') && !apple);
152
+ const meta = modifiers.has('cmd') || modifiers.has('meta') || (modifiers.has('mod') && apple);
153
+ const symbol = wanted.toLowerCase() === wanted.toUpperCase() && [...wanted].length === 1;
150
154
  return (press.key.toLowerCase() === wanted &&
151
- (modifiers.has('mod') ? mod : true) &&
152
- (modifiers.has('shift') ? press.shiftKey : !press.shiftKey) &&
155
+ (modifiers.has('shift') ? press.shiftKey : symbol || !press.shiftKey) &&
153
156
  (modifiers.has('alt') || modifiers.has('opt') ? press.altKey : !press.altKey) &&
154
- (modifiers.has('ctrl') ? press.ctrlKey : modifiers.has('mod') ? true : !press.ctrlKey) &&
155
- (modifiers.has('cmd') || modifiers.has('meta')
156
- ? press.metaKey
157
- : modifiers.has('mod')
158
- ? true
159
- : !press.metaKey));
157
+ (ctrl ? press.ctrlKey : !press.ctrlKey) &&
158
+ (meta ? press.metaKey : !press.metaKey));
160
159
  }
161
160
  firstUpdated(changed) {
162
161
  super.firstUpdated(changed);
@@ -62,6 +62,13 @@ export declare class HelixHeadlessLegend extends HelixElement {
62
62
  * `Tooltip.for` does, so it does not reflect and nothing styles on it.
63
63
  */
64
64
  for: string;
65
+ /**
66
+ * The name of the list, which a screen reader announces before its entries.
67
+ *
68
+ * Absent names the list after the table's caption, so a page with several
69
+ * charts has a legend list for each that says which chart it keys.
70
+ */
71
+ label: string;
65
72
  protected readonly source: SourceController;
66
73
  protected willUpdate(changed: PropertyValues<this>): void;
67
74
  /**
@@ -5,12 +5,13 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  import { customElement, HelixElement, SourceController, seriesIndex, } from '@fusion.dev/helix-core';
8
- import { html } from 'lit';
8
+ import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  let HelixHeadlessLegend = class HelixHeadlessLegend extends HelixElement {
11
11
  constructor() {
12
12
  super(...arguments);
13
13
  this.for = '';
14
+ this.label = '';
14
15
  this.source = new SourceController(this);
15
16
  }
16
17
  willUpdate(changed) {
@@ -26,7 +27,8 @@ let HelixHeadlessLegend = class HelixHeadlessLegend extends HelixElement {
26
27
  return (this.entries === 'measures' ? series.slice(1) : series).map((one) => one.name);
27
28
  }
28
29
  render() {
29
- return html `<ul part="list" role="list">
30
+ const named = this.label || this.source.element?.querySelector('caption')?.textContent?.trim();
31
+ return html `<ul aria-label=${named || nothing} part="list" role="list">
30
32
  ${this.names().map((name, index) => html `<li
31
33
  data-series=${seriesIndex(index)}
32
34
  part="entry"
@@ -44,6 +46,9 @@ __decorate([
44
46
  __decorate([
45
47
  property()
46
48
  ], HelixHeadlessLegend.prototype, "for", void 0);
49
+ __decorate([
50
+ property()
51
+ ], HelixHeadlessLegend.prototype, "label", void 0);
47
52
  HelixHeadlessLegend = __decorate([
48
53
  customElement('helix-headless-legend')
49
54
  ], HelixHeadlessLegend);
@@ -33,7 +33,8 @@ export declare class HelixHeadlessLightboxItem extends HelixElement {
33
33
  */
34
34
  current: boolean;
35
35
  /**
36
- * The item's name, used in the status text that says which item is shown.
36
+ * The item's name. It names the item's group, and fills `{label}` in the
37
+ * lightbox's `status-label`.
37
38
  */
38
39
  label: string;
39
40
  /**
@@ -19,8 +19,10 @@ declare const HelixHeadlessLightbox_base: (new (...args: any[]) => import("@fusi
19
19
  * focus stays in the dialog.
20
20
  *
21
21
  * The chrome hides when there is no input, through `IdleController`, and comes
22
- * back on a pointer move or a focus. `fullscreen` uses `FullscreenController`,
23
- * as `Video` does.
22
+ * back on a pointer move, a key press, or a focus. It stays while focus is on a
23
+ * control in the header or the footer, so a keyboard reader is never left on
24
+ * a control that has gone. `fullscreen` uses `FullscreenController`, as `Video`
25
+ * does. While the viewer is open, the page behind it does not scroll.
24
26
  *
25
27
  * @since 0.100.0
26
28
  * @status stable
@@ -37,7 +39,7 @@ declare const HelixHeadlessLightbox_base: (new (...args: any[]) => import("@fusi
37
39
  * @event {HelixBeforeActivateEvent} helix-before-activate - Fired before the shown item changes. Cancelable: cancel it to keep the current item. It is the only way to stop the change.
38
40
  * @event {HelixBeforeCloseEvent} helix-before-close - Fired before the viewer closes. Cancelable.
39
41
  * @event {HelixBeforeOpenEvent} helix-before-open - Fired before the viewer opens. Cancelable.
40
- * @event {Event} toggle - Fired when the viewer opens or closes, with `newState` and `oldState`.
42
+ * @event {ToggleEvent} toggle - Fired when the viewer opens or closes, with `newState` and `oldState`.
41
43
  *
42
44
  * @csspart dialog - The native dialog element.
43
45
  * @csspart live - The live region that announces which item is shown.
@@ -66,8 +68,8 @@ export declare class HelixHeadlessLightbox extends HelixHeadlessLightbox_base {
66
68
  */
67
69
  loop: boolean;
68
70
  /**
69
- * The status text that says which item is shown, with `{index}` and `{count}`
70
- * filled in.
71
+ * The status text that says which item is shown, with `{index}`, `{count}`
72
+ * and the item's `{label}` filled in.
71
73
  *
72
74
  * Announced rather than only drawn, because the picture changing under a
73
75
  * reader who cannot see it is otherwise silent. A consumer who has their own
@@ -82,6 +84,14 @@ export declare class HelixHeadlessLightbox extends HelixHeadlessLightbox_base {
82
84
  private announcement;
83
85
  private readonly fullscreen;
84
86
  private readonly idle;
87
+ /**
88
+ * Whether focus is on something in the header or the footer.
89
+ *
90
+ * The styled tier hides both with `visibility: hidden` while idle, which
91
+ * takes focus off a control in them and drops it on the body, where the
92
+ * arrow keys no longer reach this element.
93
+ */
94
+ private chromeHasFocus;
85
95
  protected readonly commands: CommandController;
86
96
  /**
87
97
  * The items, read from the host.
@@ -156,6 +166,7 @@ export declare class HelixHeadlessLightbox extends HelixHeadlessLightbox_base {
156
166
  */
157
167
  private readonly handleBackdrop;
158
168
  protected willUpdate(changed: PropertyValues): void;
169
+ disconnectedCallback(): void;
159
170
  protected updated(changed: PropertyValues): void;
160
171
  /**
161
172
  * Tells each item whether it is the one being shown.