@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,4 +1,4 @@
1
- import { HelixElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, HelixElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  declare const HelixHeadlessTabs_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerActiveInterface) & typeof HelixElement;
4
4
  /**
@@ -36,8 +36,13 @@ declare const HelixHeadlessTabs_base: (new (...args: any[]) => import("@fusion.d
36
36
  export declare class HelixHeadlessTabs extends HelixHeadlessTabs_base {
37
37
  protected readonly keys: KeyboardNavigationController;
38
38
  private readonly indicator;
39
+ /** Carries a host `aria-label` and `aria-labelledby` to the tab list. */
40
+ protected readonly aria: AriaForwardController;
39
41
  /**
40
42
  * The tab list's name, read by screen readers.
43
+ *
44
+ * An `aria-label` or `aria-labelledby` on the host names the tab list too,
45
+ * and wins over this.
41
46
  */
42
47
  label: string;
43
48
  /**
@@ -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, IndicatorController, KeyboardNavigationController, MixinControllerActive, whenHydrated, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, customElement, HelixElement, IndicatorController, KeyboardNavigationController, MixinControllerActive, whenHydrated, } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { HelixHeadlessTabPanel } from '../panel/tab-panel.js';
@@ -23,10 +23,14 @@ let HelixHeadlessTabs = class HelixHeadlessTabs extends MixinControllerActive(He
23
23
  observe: () => this.tabs,
24
24
  surface: () => this.partNamed('tabs'),
25
25
  });
26
+ this.aria = new AriaForwardController(this, {
27
+ label: true,
28
+ target: () => this.partNamed('tabs'),
29
+ });
26
30
  this.label = 'Tabs';
27
31
  this.manual = false;
28
32
  this.handleSelection = (event) => {
29
- if (event.defaultPrevented) {
33
+ if (event.defaultPrevented || !this.tabs.includes(event.target)) {
30
34
  return;
31
35
  }
32
36
  this.requestActive(event.detail.value);
@@ -1,5 +1,5 @@
1
1
  import { HelixElement } from '@fusion.dev/helix-core';
2
- import { type TemplateResult } from 'lit';
2
+ import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  declare const HelixHeadlessTag_base: (new (...args: any[]) => import("@fusion.dev/helix-core").DismissibleElement) & typeof HelixElement;
4
4
  /**
5
5
  * @summary A short label that adds metadata to content.
@@ -12,6 +12,13 @@ declare const HelixHeadlessTag_base: (new (...args: any[]) => import("@fusion.de
12
12
  * The remove button sends `helix-dismiss`. The tag does not remove itself,
13
13
  * because your code owns the list it is in, so remove it in your handler. A
14
14
  * listener can cancel `helix-dismiss`, and `dismiss()` then returns `false`.
15
+ * When the handler removes a tag whose remove button has focus, focus moves to
16
+ * the next tag's remove button, or to the previous one's after the last tag.
17
+ *
18
+ * The remove button is named for its tag, such as "Remove Apple", so a list of
19
+ * buttons says which tag each one removes. Write `{label}` in `dismiss-label`
20
+ * to put the tag's words somewhere else, such as `dismiss-label="{label}
21
+ * entfernen"`.
15
22
  *
16
23
  * @since 0.1.0
17
24
  * @status stable
@@ -31,6 +38,21 @@ declare const HelixHeadlessTag_base: (new (...args: any[]) => import("@fusion.de
31
38
  */
32
39
  export declare class HelixHeadlessTag extends HelixHeadlessTag_base {
33
40
  dismissLabel: string;
41
+ /**
42
+ * The remove button's name: `dismissLabel` with the tag's own words.
43
+ *
44
+ * **Named for its tag**, because a set of tags each named "Remove" is a list
45
+ * of buttons that says nothing about which tag each one takes away. The
46
+ * words are the tag's slotted text, its category first, and `{label}` in
47
+ * `dismissLabel` says where they go. Without it they follow the verb, unless
48
+ * the label already holds them, which is what a page naming each button by
49
+ * hand wrote.
50
+ *
51
+ * Read from the children, so empty on a server and while hydrating, where
52
+ * the name is the verb alone until the update after.
53
+ */
54
+ private get removeName();
55
+ protected firstUpdated(changed: PropertyValues): void;
34
56
  protected render(): TemplateResult;
35
57
  }
36
58
  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, MixinDismissible } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixElement, MixinDismissible, slottedWords } from '@fusion.dev/helix-core';
8
8
  import { x } from '@fusion.dev/helix-icons';
9
9
  import { html, nothing } from 'lit';
10
10
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
@@ -13,6 +13,20 @@ let HelixHeadlessTag = class HelixHeadlessTag extends MixinDismissible(HelixElem
13
13
  super(...arguments);
14
14
  this.dismissLabel = 'Remove';
15
15
  }
16
+ get removeName() {
17
+ const words = this.childrenKnown ? slottedWords(this, ['start', '']) : '';
18
+ if (this.dismissLabel.includes('{label}')) {
19
+ return this.dismissLabel.replace('{label}', words).trim();
20
+ }
21
+ return words === '' || this.dismissLabel.includes(words)
22
+ ? this.dismissLabel
23
+ : `${this.dismissLabel} ${words}`;
24
+ }
25
+ firstUpdated(changed) {
26
+ super.firstUpdated(changed);
27
+ this.renderRoot.addEventListener('slotchange', () => this.requestUpdate());
28
+ this.finishHydration();
29
+ }
16
30
  render() {
17
31
  return html `<slot name="start" part="start"></slot>
18
32
  <slot part="label"></slot>
@@ -20,7 +34,7 @@ let HelixHeadlessTag = class HelixHeadlessTag extends MixinDismissible(HelixElem
20
34
  ? html `<button
21
35
  part="dismiss"
22
36
  type="button"
23
- aria-label=${this.dismissLabel}
37
+ aria-label=${this.removeName}
24
38
  @click=${() => this.dismiss()}
25
39
  >
26
40
  <svg part="dismiss-mark" fill="currentColor" viewBox=${x.viewBox} aria-hidden="true">
@@ -21,6 +21,10 @@ declare const HelixHeadlessTextarea_base: (new (...args: any[]) => import("@fusi
21
21
  * @aliases Multiline, TextArea
22
22
  * @documentation https://fusion.dev/helix/components/textarea
23
23
  *
24
+ * @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
25
+ * @slot hint - Help under the control, for content richer than the `hint` text.
26
+ * @slot label - The label, for content richer than the `label` text.
27
+ *
24
28
  * @event {Event} change - Sent from the textarea when the user finishes an edit.
25
29
  * @event {HelixBeforeChangeEvent} helix-before-change - Fired as the text changes, and cancelable.
26
30
  * @event {Event} input - Fired after the value changes.
@@ -103,7 +103,7 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
103
103
  this.control?.focus(options);
104
104
  }
105
105
  sync() {
106
- this.internals.setFormValue(this.formValue());
106
+ this.internals.setFormValue(this.formValue(), this.value);
107
107
  const control = this.control;
108
108
  if (!control) {
109
109
  return;
@@ -1,6 +1,5 @@
1
1
  import { AriaForwardController, HelixFormElement } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
- import '../../icon/index.js';
4
3
  import '../../tag/index.js';
5
4
  import '../../time-picker/index.js';
6
5
  declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinPickerEditingInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinPickerFieldInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinTokensInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
@@ -23,6 +22,12 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
23
22
  * formatted time such as `2:30 PM` cannot be typed back and `Intl` has no
24
23
  * parser for it.
25
24
  *
25
+ * Typing sends `input` on each keystroke and `change` when you leave the
26
+ * field. In the list, the arrow keys, typed digits and PageUp and PageDown
27
+ * move through the times, and Enter, Space or a click chooses one and closes
28
+ * the panel. With `variant="wheels"` each wheel moves the time as you turn it,
29
+ * the panel stays open, and Enter or Escape closes it.
30
+ *
26
31
  * @since 0.1.0
27
32
  * @status stable
28
33
  * @category forms
@@ -38,7 +43,7 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
38
43
  * @event {HelixBeforeCloseEvent} helix-before-close - Fired before the list closes. Cancelable: canceling it keeps the list open and leaves the decision to you.
39
44
  * @event {HelixBeforeOpenEvent} helix-before-open - Fired before the list opens. Cancelable: canceling it keeps the list closed and leaves the decision to you.
40
45
  * @event {Event} input - Fired after the value changes.
41
- * @event {Event} toggle - Fired after the list opens or closes, with `newState` and `oldState`.
46
+ * @event {ToggleEvent} toggle - Fired after the list opens or closes, with `newState` and `oldState`.
42
47
  *
43
48
  * @csspart control - The text input.
44
49
  * @csspart feedback - The message that says what is wrong with the value.
@@ -102,6 +107,15 @@ export declare class HelixHeadlessTimeInput extends HelixHeadlessTimeInput_base
102
107
  * lets autofill work at all.
103
108
  */
104
109
  autocomplete: string;
110
+ /** Typed, so a keystroke is announced as `input` alone. See `announcesInput`. */
111
+ protected readonly announcesInput = true;
112
+ /**
113
+ * Times that cannot be chosen, as `HH:mm`, separated by commas or spaces.
114
+ *
115
+ * Handed to the list, which offers them as unavailable, and checked against
116
+ * a typed time, which is then invalid.
117
+ */
118
+ disableTimes: string;
105
119
  /**
106
120
  * Language tag the times are written in.
107
121
  *
@@ -172,6 +186,10 @@ export declare class HelixHeadlessTimeInput extends HelixHeadlessTimeInput_base
172
186
  * The name of the button that opens the list, read by screen readers.
173
187
  */
174
188
  triggerLabel: string;
189
+ /**
190
+ * The message shown when `disable-times` bars a time.
191
+ */
192
+ unavailableMessage?: string;
175
193
  /** Every time in the value, which may hold more than one. */
176
194
  private get held();
177
195
  /** One time, written the way `time-style` asks for. */
@@ -204,6 +222,14 @@ export declare class HelixHeadlessTimeInput extends HelixHeadlessTimeInput_base
204
222
  private get picked();
205
223
  private readonly handleInput;
206
224
  private readonly handlePicked;
225
+ /**
226
+ * Enter on the wheels closes the panel, the time on them being the answer.
227
+ *
228
+ * The list closes on the choice Enter makes. A wheel turned by the arrows
229
+ * already holds its time, so Enter there chooses nothing new, and this is
230
+ * what says the reader is done.
231
+ */
232
+ private readonly handleWheelEnter;
207
233
  /** Each time, where `mode` holds several, sent one entry each. */
208
234
  protected get answers(): readonly string[] | undefined;
209
235
  /** What is wrong with the times, which the text input cannot say. */
@@ -4,13 +4,12 @@ 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 { AriaForwardController, valueAsTime as asTime, customElement, fillTemplate, timeAsValue as fromTime, HelixFormElement, isTimeValue, MixinControllerOpen, MixinControllerValue, MixinField, MixinPickerEditing, MixinPickerField, MixinTokens, valueAsMinutes, writeTime, } from '@fusion.dev/helix-core';
7
+ import { AriaForwardController, valueAsTime as asTime, customElement, fillTemplate, timeAsValue as fromTime, HelixFormElement, isTimeValue, MixinControllerOpen, MixinControllerValue, MixinField, MixinPickerEditing, MixinPickerField, MixinTokens, valueAsMinutes, writeTime, writtenList, } from '@fusion.dev/helix-core';
8
8
  import { clock } from '@fusion.dev/helix-icons';
9
9
  import { nothing } from 'lit';
10
10
  import { property, state } from 'lit/decorators.js';
11
11
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
12
12
  import { html } from 'lit/static-html.js';
13
- import '../../icon/index.js';
14
13
  import '../../tag/index.js';
15
14
  import '../../time-picker/index.js';
16
15
  let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinPickerEditing(MixinPickerField(MixinControllerOpen(MixinTokens(MixinControllerValue(MixinField(HelixFormElement)))))) {
@@ -20,6 +19,8 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinPickerEdi
20
19
  target: () => this.partNamed('control'),
21
20
  });
22
21
  this.autocomplete = '';
22
+ this.announcesInput = true;
23
+ this.disableTimes = '';
23
24
  this.locale = '';
24
25
  this.max = '23:59';
25
26
  this.min = '00:00';
@@ -37,16 +38,16 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinPickerEdi
37
38
  if (event.key === 'Enter' && isTimeValue(this.draft)) {
38
39
  event.preventDefault();
39
40
  if (!held.includes(this.draft)) {
40
- this.requestValue([...held, this.draft].sort().join(','));
41
+ this.requestPicked([...held, this.draft].sort().join(','));
41
42
  }
42
43
  this.draft = '';
43
44
  }
44
45
  else if (event.key === 'Backspace' && this.draft === '' && held.length > 0) {
45
- this.requestValue(held.slice(0, -1).join(','));
46
+ this.requestPicked(held.slice(0, -1).join(','));
46
47
  }
47
48
  };
48
49
  this.removeTime = (at) => {
49
- this.requestValue(this.held.filter((one) => one !== at).join(','));
50
+ this.requestPicked(this.held.filter((one) => one !== at).join(','));
50
51
  };
51
52
  this.handleInput = (event) => {
52
53
  event.stopPropagation();
@@ -67,13 +68,24 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinPickerEdi
67
68
  };
68
69
  this.handlePicked = (event) => {
69
70
  event.stopPropagation();
70
- this.requestValue(event.detail.value);
71
+ if (!this.requestPicked(event.detail.value)) {
72
+ event.preventDefault();
73
+ this.restore();
74
+ return;
75
+ }
71
76
  this.restore();
72
- if (this.mode === undefined) {
77
+ if (this.mode === undefined && this.variant !== 'wheels') {
73
78
  this.requestOpen(false);
74
79
  this.updateComplete.then(() => this.returnFocus());
75
80
  }
76
81
  };
82
+ this.handleWheelEnter = (event) => {
83
+ if (event.key === 'Enter' && this.variant === 'wheels' && this.open) {
84
+ event.preventDefault();
85
+ this.requestOpen(false);
86
+ this.returnFocus();
87
+ }
88
+ };
77
89
  }
78
90
  get held() {
79
91
  return this.value
@@ -130,6 +142,10 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinPickerEdi
130
142
  max: writeTime(this.max, this.locale),
131
143
  });
132
144
  }
145
+ const barred = writtenList(this.disableTimes);
146
+ if (held.some((one) => barred.includes(one))) {
147
+ return this.unavailableMessage || 'Choose a time that is available.';
148
+ }
133
149
  if (this.mode === 'range' && held.length > 2) {
134
150
  return this.rangeLengthMessage || 'A range is two times.';
135
151
  }
@@ -162,6 +178,8 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinPickerEdi
162
178
  ?invalid=${this.resolvedFeedback !== ''}
163
179
  mode=${this.mode ?? nothing}
164
180
  variant=${this.variant ?? nothing}
181
+ disable-times=${this.disableTimes || nothing}
182
+ manual
165
183
  label=${this.label || 'Time'}
166
184
  locale=${this.locale || nothing}
167
185
  max=${this.max}
@@ -212,25 +230,37 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinPickerEdi
212
230
  ?readonly=${this.readOnly}
213
231
  ?required=${this.required}
214
232
  @blur=${this.handleBlur}
233
+ @change=${this.handleCommit}
215
234
  @focus=${this.handleFocus}
216
235
  @input=${this.handleInput}
217
236
  @keydown=${this.handleDraftKey}
237
+ @keypress=${this.handleKeypress}
218
238
  />
219
239
  <button
220
240
  part="trigger"
221
241
  type="button"
222
242
  aria-controls="surface"
243
+ aria-disabled=${this.readOnly ? 'true' : nothing}
223
244
  aria-expanded=${this.open ? 'true' : 'false'}
224
- aria-haspopup="listbox"
245
+ aria-haspopup="dialog"
225
246
  aria-label=${this.triggerLabel}
226
247
  ?disabled=${this.isDisabled}
227
- @click=${() => this.toggleOpen()}
248
+ @click=${this.handleTriggerClick}
228
249
  >
229
250
  ${this.renderTrigger()}
230
251
  </button>
231
252
  </div>
232
253
 
233
- <div part="surface" id="surface" popover="manual" ?hidden=${!this.open}>
254
+ ${''}
255
+ <div
256
+ part="surface"
257
+ id="surface"
258
+ role="dialog"
259
+ aria-label=${this.triggerLabel}
260
+ popover="manual"
261
+ ?hidden=${!this.open}
262
+ @keydown=${this.handleWheelEnter}
263
+ >
234
264
  ${this.renderPicker()}
235
265
  </div>
236
266
  ${this.renderHint()}${this.renderFeedback()}`;
@@ -251,6 +281,9 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinPickerEdi
251
281
  __decorate([
252
282
  property()
253
283
  ], HelixHeadlessTimeInput.prototype, "autocomplete", void 0);
284
+ __decorate([
285
+ property({ attribute: 'disable-times' })
286
+ ], HelixHeadlessTimeInput.prototype, "disableTimes", void 0);
254
287
  __decorate([
255
288
  property()
256
289
  ], HelixHeadlessTimeInput.prototype, "locale", void 0);
@@ -287,6 +320,9 @@ __decorate([
287
320
  __decorate([
288
321
  property({ attribute: 'trigger-label' })
289
322
  ], HelixHeadlessTimeInput.prototype, "triggerLabel", void 0);
323
+ __decorate([
324
+ property({ attribute: 'unavailable-message' })
325
+ ], HelixHeadlessTimeInput.prototype, "unavailableMessage", void 0);
290
326
  __decorate([
291
327
  state()
292
328
  ], HelixHeadlessTimeInput.prototype, "draft", void 0);
@@ -84,7 +84,7 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
84
84
  */
85
85
  badInputMessage?: string;
86
86
  /**
87
- * Times that cannot be chosen, comma separated, as `HH:mm`.
87
+ * Times that cannot be chosen, as `HH:mm`, separated by commas or spaces.
88
88
  *
89
89
  * The counterpart to Date Picker's `disable-dates`, and it exists for the same
90
90
  * shape of problem: `min` and `max` take away a span, and what a booking
@@ -96,6 +96,10 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
96
96
  * reached honestly rather than by handing over an empty range.
97
97
  */
98
98
  disableTimes: string;
99
+ /**
100
+ * What the wheel of hours is called, read by screen readers.
101
+ */
102
+ hourLabel: string;
99
103
  /**
100
104
  * Whether the current selection fails validation.
101
105
  *
@@ -108,6 +112,8 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
108
112
  invalid: boolean;
109
113
  /**
110
114
  * Accessible name for the list, which has no visible one of its own.
115
+ *
116
+ * An `aria-label` or `aria-labelledby` on the host names the list instead.
111
117
  */
112
118
  label: string;
113
119
  /**
@@ -116,14 +122,31 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
116
122
  * Absent uses the runtime's own.
117
123
  */
118
124
  locale: string;
125
+ /**
126
+ * Stops the arrow keys in the list from choosing each time they move to.
127
+ * Enter, Space or a click chooses.
128
+ *
129
+ * Time Input sets it, so a reader moves through the list before the panel
130
+ * closes on a time.
131
+ */
132
+ manual: boolean;
119
133
  /**
120
134
  * Latest time offered, as `HH:mm`.
121
135
  */
122
136
  max: string;
137
+ /**
138
+ * What the wheel of the half of the day is called, read by screen readers.
139
+ * Its two options are written as the locale writes them, such as AM and PM.
140
+ */
141
+ meridiemLabel: string;
123
142
  /**
124
143
  * Earliest time offered, as `HH:mm`.
125
144
  */
126
145
  min: string;
146
+ /**
147
+ * What the wheel of minutes is called, read by screen readers.
148
+ */
149
+ minuteLabel: string;
127
150
  /**
128
151
  * How many times can be held at once.
129
152
  *
@@ -145,23 +168,15 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
145
168
  */
146
169
  mode?: 'multiple' | 'range';
147
170
  /**
148
- * Blocks changes to the time. The value is still submitted with the form.
149
- *
150
- * **Enforced by refusing every request in one place**, which is the seam this
151
- * component already has: `requestValue` is what every path here comes through,
152
- * and gating it once is what stops the next call site from being written
153
- * without the check.
154
- *
155
- * Not `disabled`, which is the confusion worth naming: a disabled control
156
- * submits nothing and leaves the tab order, and a read-only one submits its
157
- * value and stays reachable, which is what a form showing a value somebody
158
- * else set needs.
171
+ * The validation message for a time after `max`. `{max}` is replaced with
172
+ * `max`, written in `locale`.
159
173
  */
160
- readOnly: boolean;
174
+ rangeOverflowMessage?: string;
161
175
  /**
162
- * Stops the form from submitting while no time is chosen.
176
+ * The validation message for a time before `min`. `{min}` is replaced with
177
+ * `min`, written in `locale`.
163
178
  */
164
- required: boolean;
179
+ rangeUnderflowMessage?: string;
165
180
  /**
166
181
  * Every time on offer, as minutes since midnight.
167
182
  *
@@ -184,6 +199,17 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
184
199
  * outside the bounds is absent rather than present and refused.
185
200
  */
186
201
  private barred;
202
+ /**
203
+ * The offered time nearest to one the wheels built, which keeps them inside
204
+ * `min`, `max` and `step`.
205
+ *
206
+ * A wheel sets one part of a time and keeps the others, so moving the hour
207
+ * from 16:45 to 17 built 17:45 against a `max` of 17:00, and moving the half
208
+ * of the day built 05:45 against a `min` of 09:00. Measured before this,
209
+ * both reported valid and were submitted. The nearest earlier time wins a
210
+ * tie, so a step past `max` lands on `max`'s own row.
211
+ */
212
+ private nearest;
187
213
  /**
188
214
  * Whether every offered time in an hour is barred.
189
215
  *
@@ -252,6 +278,26 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
252
278
  * rather than wrong, which is why it can be left in.
253
279
  */
254
280
  reveal(): void;
281
+ /**
282
+ * Blocks changes to the time. The value is still submitted with the form.
283
+ *
284
+ * **Enforced by refusing every request in one place**, which is the seam this
285
+ * component already has: `requestValue` is what every path here comes through,
286
+ * and gating it once is what stops the next call site from being written
287
+ * without the check.
288
+ *
289
+ * Not `disabled`, which is the confusion worth naming: a disabled control
290
+ * submits nothing and leaves the tab order, and a read-only one submits its
291
+ * value and stays reachable, which is what a form showing a value somebody
292
+ * else set needs.
293
+ */
294
+ readOnly: boolean;
295
+ /** Refuses every change while read-only. See `readOnly`. */
296
+ requestValue(next: string): boolean;
297
+ /**
298
+ * Stops the form from submitting while no time is chosen.
299
+ */
300
+ required: boolean;
255
301
  /**
256
302
  * How far apart the offered times are, in minutes.
257
303
  *
@@ -260,12 +306,27 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
260
306
  * Anything under five is a thousand rows and wants a field instead.
261
307
  */
262
308
  step: number;
263
- /** Refuses every change while read-only. See `readOnly`. */
264
- requestValue(next: string): boolean;
309
+ /**
310
+ * The validation message for a time that `step` skips.
311
+ */
312
+ stepMismatchMessage?: string;
313
+ /**
314
+ * The validation message for a time that `disable-times` bars.
315
+ */
316
+ unavailableMessage?: string;
265
317
  /**
266
318
  * The validation message for a required time picker with no time chosen.
267
319
  */
268
320
  valueMissingMessage?: string;
321
+ /**
322
+ * What is wrong with a time the picker can read, as a validity flag and a
323
+ * message, or nothing.
324
+ *
325
+ * Measured before this: a time past `max` or one `disable-times` bars,
326
+ * whether set by a script or built on the wheels, reported valid and was
327
+ * submitted, where a native time input reports the bound it is past.
328
+ */
329
+ private fault;
269
330
  /**
270
331
  * Shows the times as one `list`, or as `wheels` with a column for each part
271
332
  * of the time.
@@ -346,9 +407,31 @@ export declare class HelixHeadlessTimePicker extends HelixHeadlessTimePicker_bas
346
407
  * and after that only whatever opens a panel calls `reveal`.
347
408
  */
348
409
  private listRevealed;
410
+ /**
411
+ * The list's name: the host's `aria-labelledby` read out, then its
412
+ * `aria-label`, then `label`.
413
+ *
414
+ * Read out as words, because the list is inside two shadow roots and an id on
415
+ * the page reaches neither. Measured before this: `<helix-time-picker
416
+ * aria-label="Slot">` was a listbox named "Time".
417
+ */
418
+ private get listName();
419
+ /**
420
+ * Hears the host's `aria-label` and `aria-labelledby` change, which no
421
+ * property reports. Made on connection, there being no `MutationObserver` on
422
+ * a server.
423
+ */
424
+ private naming;
425
+ connectedCallback(): void;
426
+ disconnectedCallback(): void;
349
427
  protected willUpdate(changed: PropertyValues): void;
350
428
  protected updated(changed: PropertyValues): void;
351
- /** Moves focus to the list, which is the only control in the picker. */
429
+ /**
430
+ * Moves focus to the list, or to the first wheel.
431
+ *
432
+ * The wheels render no list, so focus went nowhere on them and a wrapping
433
+ * component could not move focus into the picker.
434
+ */
352
435
  focus(options?: FocusOptions): void;
353
436
  /**
354
437
  * One wheel, which is a listbox like the whole list is.