@fusion.dev/helix-headless 0.143.0 → 0.144.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 (191) hide show
  1. package/custom-elements.json +8551 -375
  2. package/dist/area-chart/root/area-chart-root.d.ts +12 -4
  3. package/dist/area-chart/root/area-chart-root.js +24 -7
  4. package/dist/avatar/root/avatar-root.d.ts +14 -0
  5. package/dist/avatar/root/avatar-root.js +23 -9
  6. package/dist/badge/root/badge-root.d.ts +11 -7
  7. package/dist/badge/root/badge-root.js +1 -1
  8. package/dist/bar-chart/root/bar-chart-root.d.ts +12 -3
  9. package/dist/bar-chart/root/bar-chart-root.js +17 -10
  10. package/dist/button/root/button-root.d.ts +47 -1
  11. package/dist/button/root/button-root.js +38 -4
  12. package/dist/callout/root/callout-root.d.ts +18 -1
  13. package/dist/callout/root/callout-root.js +15 -4
  14. package/dist/card/root/card-root.d.ts +30 -1
  15. package/dist/card/root/card-root.js +38 -5
  16. package/dist/checkbox/root/checkbox-root.js +2 -0
  17. package/dist/checkbox-group/root/checkbox-group-root.d.ts +53 -3
  18. package/dist/checkbox-group/root/checkbox-group-root.js +71 -22
  19. package/dist/code-block/lines.d.ts +13 -0
  20. package/dist/code-block/lines.js +2 -0
  21. package/dist/code-block/root/code-block-root.d.ts +30 -0
  22. package/dist/code-block/root/code-block-root.js +23 -2
  23. package/dist/color-input/root/color-input-root.d.ts +34 -1
  24. package/dist/color-input/root/color-input-root.js +23 -4
  25. package/dist/color-picker/channels.d.ts +26 -0
  26. package/dist/color-picker/channels.js +84 -0
  27. package/dist/color-picker/root/color-picker-root.d.ts +81 -5
  28. package/dist/color-picker/root/color-picker-root.js +103 -10
  29. package/dist/combobox/root/combobox-root.d.ts +38 -3
  30. package/dist/combobox/root/combobox-root.js +64 -2
  31. package/dist/command/root/command-root.d.ts +30 -4
  32. package/dist/command/root/command-root.js +33 -3
  33. package/dist/copy-button/from.d.ts +22 -0
  34. package/dist/copy-button/from.js +28 -0
  35. package/dist/copy-button/root/copy-button-root.d.ts +27 -1
  36. package/dist/copy-button/root/copy-button-root.js +43 -7
  37. package/dist/date-input/root/date-input-root.d.ts +73 -4
  38. package/dist/date-input/root/date-input-root.js +93 -43
  39. package/dist/date-picker/root/date-picker-root.d.ts +145 -1
  40. package/dist/date-picker/root/date-picker-root.js +239 -48
  41. package/dist/dialog/description.d.ts +9 -0
  42. package/dist/dialog/description.js +14 -0
  43. package/dist/dialog/root/dialog-root.d.ts +64 -1
  44. package/dist/dialog/root/dialog-root.js +49 -23
  45. package/dist/donut-chart/root/donut-chart-root.d.ts +25 -4
  46. package/dist/donut-chart/root/donut-chart-root.js +21 -6
  47. package/dist/drawer/root/drawer-root.d.ts +63 -2
  48. package/dist/drawer/root/drawer-root.js +95 -19
  49. package/dist/drawer/swipe-start.d.ts +9 -0
  50. package/dist/drawer/swipe-start.js +12 -0
  51. package/dist/element-events.generated.js +8 -5
  52. package/dist/empty/root/empty-root.d.ts +1 -1
  53. package/dist/file-input/root/file-input-root.d.ts +47 -0
  54. package/dist/file-input/root/file-input-root.js +60 -22
  55. package/dist/file-input/screen.d.ts +35 -0
  56. package/dist/file-input/screen.js +49 -0
  57. package/dist/filter-input/root/filter-input-root.d.ts +38 -4
  58. package/dist/filter-input/root/filter-input-root.js +67 -3
  59. package/dist/filter-input/suggest.d.ts +17 -0
  60. package/dist/filter-input/suggest.js +23 -0
  61. package/dist/format-date/options.d.ts +33 -0
  62. package/dist/format-date/options.js +42 -0
  63. package/dist/format-date/root/format-date-root.d.ts +51 -0
  64. package/dist/format-date/root/format-date-root.js +58 -38
  65. package/dist/heatmap/root/heatmap-root.d.ts +23 -6
  66. package/dist/heatmap/root/heatmap-root.js +24 -13
  67. package/dist/icon/index.d.ts +2 -0
  68. package/dist/icon/index.js +2 -0
  69. package/dist/icon/registry.d.ts +37 -0
  70. package/dist/icon/registry.js +83 -0
  71. package/dist/icon/root/icon-root.d.ts +30 -4
  72. package/dist/icon/root/icon-root.js +41 -6
  73. package/dist/icon/root/index.d.ts +2 -0
  74. package/dist/icon/root/index.js +2 -0
  75. package/dist/icon/set.d.ts +1 -0
  76. package/dist/icon/set.js +3 -0
  77. package/dist/image/root/image-root.d.ts +14 -0
  78. package/dist/image/root/image-root.js +15 -2
  79. package/dist/input/root/input-root.d.ts +11 -0
  80. package/dist/input/root/input-root.js +15 -0
  81. package/dist/kbd/root/kbd-root.d.ts +20 -13
  82. package/dist/kbd/root/kbd-root.js +35 -37
  83. package/dist/kbd/shortcut.d.ts +18 -0
  84. package/dist/kbd/shortcut.js +35 -0
  85. package/dist/legend/hidden-series.d.ts +8 -0
  86. package/dist/legend/hidden-series.js +13 -0
  87. package/dist/legend/root/legend-root.d.ts +56 -0
  88. package/dist/legend/root/legend-root.js +54 -5
  89. package/dist/lightbox/item/lightbox-item.d.ts +15 -0
  90. package/dist/lightbox/item/lightbox-item.js +10 -1
  91. package/dist/lightbox/root/lightbox-root.d.ts +61 -1
  92. package/dist/lightbox/root/lightbox-root.js +94 -4
  93. package/dist/line-chart/root/line-chart-root.d.ts +11 -3
  94. package/dist/line-chart/root/line-chart-root.js +19 -5
  95. package/dist/listbox/range.d.ts +17 -0
  96. package/dist/listbox/range.js +5 -0
  97. package/dist/listbox/root/listbox-root.d.ts +74 -3
  98. package/dist/listbox/root/listbox-root.js +87 -9
  99. package/dist/loader/busy.d.ts +17 -0
  100. package/dist/loader/busy.js +24 -0
  101. package/dist/loader/root/loader-root.d.ts +37 -0
  102. package/dist/loader/root/loader-root.js +52 -3
  103. package/dist/meter/root/meter-root.d.ts +7 -0
  104. package/dist/meter/root/meter-root.js +6 -3
  105. package/dist/notifications/feed-keys.d.ts +10 -0
  106. package/dist/notifications/feed-keys.js +14 -0
  107. package/dist/notifications/notification/notification.d.ts +17 -0
  108. package/dist/notifications/notification/notification.js +21 -2
  109. package/dist/notifications/root/notifications-root.d.ts +42 -0
  110. package/dist/notifications/root/notifications-root.js +60 -1
  111. package/dist/number-input/root/number-input-root.d.ts +47 -0
  112. package/dist/number-input/root/number-input-root.js +58 -22
  113. package/dist/object-inspector/root/object-inspector-root.d.ts +1 -0
  114. package/dist/object-inspector/root/object-inspector-root.js +1 -1
  115. package/dist/option/root/option-root.d.ts +54 -5
  116. package/dist/option/root/option-root.js +34 -5
  117. package/dist/pin-input/format.d.ts +7 -0
  118. package/dist/pin-input/format.js +16 -0
  119. package/dist/pin-input/root/pin-input-root.d.ts +21 -0
  120. package/dist/pin-input/root/pin-input-root.js +29 -2
  121. package/dist/popover/root/popover-root.d.ts +62 -4
  122. package/dist/popover/root/popover-root.js +53 -5
  123. package/dist/progress/root/progress-root.d.ts +7 -0
  124. package/dist/progress/root/progress-root.js +9 -3
  125. package/dist/qr-code/export.d.ts +31 -0
  126. package/dist/qr-code/export.js +10 -0
  127. package/dist/qr-code/root/qr-code-root.d.ts +26 -0
  128. package/dist/qr-code/root/qr-code-root.js +49 -2
  129. package/dist/radio/group/radio-group.d.ts +23 -0
  130. package/dist/radio/group/radio-group.js +18 -0
  131. package/dist/rating/root/rating-root.d.ts +25 -0
  132. package/dist/rating/root/rating-root.js +45 -3
  133. package/dist/scatter-chart/root/scatter-chart-root.d.ts +17 -3
  134. package/dist/scatter-chart/root/scatter-chart-root.js +25 -7
  135. package/dist/select/root/select-root.d.ts +24 -0
  136. package/dist/select/root/select-root.js +20 -6
  137. package/dist/skeleton/root/skeleton-root.d.ts +25 -0
  138. package/dist/skeleton/root/skeleton-root.js +17 -2
  139. package/dist/slider/root/slider-root.d.ts +39 -0
  140. package/dist/slider/root/slider-root.js +45 -9
  141. package/dist/stat/root/stat-root.d.ts +2 -0
  142. package/dist/stat/root/stat-root.js +1 -1
  143. package/dist/steps/step/step.d.ts +1 -0
  144. package/dist/steps/step/step.js +1 -1
  145. package/dist/switch/root/switch-root.d.ts +12 -2
  146. package/dist/switch/root/switch-root.js +6 -1
  147. package/dist/tag/group/tag-group.d.ts +107 -0
  148. package/dist/tag/group/tag-group.js +157 -0
  149. package/dist/tag/index.d.ts +1 -0
  150. package/dist/tag/index.js +1 -0
  151. package/dist/tag/root/tag-root.d.ts +60 -0
  152. package/dist/tag/root/tag-root.js +74 -18
  153. package/dist/tag/selection.d.ts +10 -0
  154. package/dist/tag/selection.js +12 -0
  155. package/dist/textarea/grow.d.ts +22 -0
  156. package/dist/textarea/grow.js +20 -0
  157. package/dist/textarea/root/textarea-root.d.ts +9 -0
  158. package/dist/textarea/root/textarea-root.js +9 -1
  159. package/dist/time-input/root/time-input-root.d.ts +44 -5
  160. package/dist/time-input/root/time-input-root.js +69 -39
  161. package/dist/time-picker/root/time-picker-root.d.ts +54 -8
  162. package/dist/time-picker/root/time-picker-root.js +121 -91
  163. package/dist/toast/hotkey.d.ts +22 -0
  164. package/dist/toast/hotkey.js +23 -0
  165. package/dist/toast/item/toast-item.d.ts +16 -1
  166. package/dist/toast/item/toast-item.js +41 -13
  167. package/dist/toast/root/toast-root.d.ts +42 -8
  168. package/dist/toast/root/toast-root.js +64 -4
  169. package/dist/toggle/group/toggle-group.d.ts +57 -15
  170. package/dist/toggle/group/toggle-group.js +69 -9
  171. package/dist/toggle/root/toggle-root.d.ts +12 -1
  172. package/dist/toggle/root/toggle-root.js +11 -3
  173. package/dist/tooltip/focus-target.d.ts +6 -0
  174. package/dist/tooltip/focus-target.js +9 -0
  175. package/dist/tooltip/root/tooltip-root.d.ts +42 -17
  176. package/dist/tooltip/root/tooltip-root.js +50 -9
  177. package/dist/tour/naming.d.ts +30 -0
  178. package/dist/tour/naming.js +10 -0
  179. package/dist/tour/root/tour-root.d.ts +35 -0
  180. package/dist/tour/root/tour-root.js +56 -5
  181. package/dist/tour/stop/tour-stop.d.ts +53 -8
  182. package/dist/tour/stop/tour-stop.js +45 -15
  183. package/dist/tour/wait.d.ts +11 -0
  184. package/dist/tour/wait.js +19 -0
  185. package/dist/trend/root/trend-root.d.ts +13 -0
  186. package/dist/trend/root/trend-root.js +14 -9
  187. package/lint.json +1 -1
  188. package/package.json +5 -5
  189. package/types/jsx.d.ts +4862 -254
  190. package/types/svelte.d.ts +1 -0
  191. package/types/vue.d.ts +1149 -67
@@ -4,12 +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 { customElement, HelixElement, hostAria, TONE_MARKS, toneMark } from '@fusion.dev/helix-core';
8
- import { html } from 'lit';
7
+ import { customElement, drawDismiss, drawDismissGlyph, HelixElement, hostAria, MixinDismissible, TONE_MARKS, toneMark, } from '@fusion.dev/helix-core';
8
+ import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
10
  import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
11
11
  const NOTE = { icon: TONE_MARKS.info.icon, label: 'Note' };
12
- let HelixHeadlessCallout = class HelixHeadlessCallout extends HelixElement {
12
+ let HelixHeadlessCallout = class HelixHeadlessCallout extends MixinDismissible(HelixElement) {
13
13
  constructor() {
14
14
  super(...arguments);
15
15
  this.toneLabel = '';
@@ -25,6 +25,11 @@ let HelixHeadlessCallout = class HelixHeadlessCallout extends HelixElement {
25
25
  </svg>
26
26
  </slot>`;
27
27
  }
28
+ renderDismissIcon() {
29
+ return html `<slot name="dismiss-icon">
30
+ ${drawDismissGlyph()}
31
+ </slot>`;
32
+ }
28
33
  render() {
29
34
  const { icon, label } = this.tone === 'neutral' ? NOTE : (toneMark(this.tone) ?? TONE_MARKS.info);
30
35
  const named = this.toneLabel || label;
@@ -32,7 +37,13 @@ let HelixHeadlessCallout = class HelixHeadlessCallout extends HelixElement {
32
37
  <div part="content">
33
38
  <slot name="heading"></slot>
34
39
  <slot></slot>
35
- </div>`;
40
+ </div>${this.dismissible
41
+ ? drawDismiss({
42
+ label: this.dismissLabel,
43
+ mark: this.renderDismissIcon(),
44
+ onDismiss: () => this.dismiss(),
45
+ })
46
+ : nothing}`;
36
47
  }
37
48
  };
38
49
  __decorate([
@@ -14,7 +14,15 @@ import { type PropertyValues, type TemplateResult } from 'lit';
14
14
  *
15
15
  * Name the card with `aria-label` or `aria-labelledby`. These are the only
16
16
  * names that work with server rendering, because reading a title from the light
17
- * DOM needs a DOM, and the server has none.
17
+ * DOM needs a DOM, and the server has none. **A named card is a group**, so a
18
+ * reader entering it hears its name; an unnamed one has no role, since a group
19
+ * with no name only adds "group" to what a reader says.
20
+ *
21
+ * `header-actions` and `footer-actions` hold controls at the end of the
22
+ * header's and the footer's line, as Web Awesome's card does. While one holds
23
+ * something, its line is a `header-row` or `footer-row` part; otherwise there
24
+ * is no wrapper and every region is a bare slot. A server cannot see slotted
25
+ * content, so served actions sit on their own line until the script runs.
18
26
  *
19
27
  * @since 0.1.0
20
28
  * @status stable
@@ -24,8 +32,13 @@ import { type PropertyValues, type TemplateResult } from 'lit';
24
32
  *
25
33
  * @slot - The card's main content.
26
34
  * @slot footer - Actions that conclude the card.
35
+ * @slot footer-actions - Controls at the end of the footer's line, with the footer at its start.
27
36
  * @slot header - Title and any actions for the whole card.
37
+ * @slot header-actions - Controls for the whole card at the end of the header's line, such as a menu.
28
38
  * @slot media - Image, video, or chart that runs edge to edge, outside the inset.
39
+ *
40
+ * @csspart footer-row - The line holding `footer` and `footer-actions`, drawn only while `footer-actions` holds something.
41
+ * @csspart header-row - The line holding `header` and `header-actions`, drawn only while `header-actions` holds something.
29
42
  */
30
43
  export declare class HelixHeadlessCard extends HelixElement {
31
44
  /**
@@ -42,7 +55,23 @@ export declare class HelixHeadlessCard extends HelixElement {
42
55
  * with no attribute on it and the stylesheet only describes the departure.
43
56
  */
44
57
  mediaPlacement?: 'end';
58
+ /**
59
+ * @internal The host's `aria-labelledby`, observed so the card becomes a
60
+ * group once it is named. Not reflected: the attribute is the consumer's.
61
+ */
62
+ protected labelledBy: string | null;
63
+ /**
64
+ * @internal The host's `aria-label`, observed for the same reason as
65
+ * `labelledBy`. Not reflected: the attribute is the consumer's.
66
+ */
67
+ protected namedBy: string | null;
68
+ /** Whether `footer-actions` holds something, read from the slot. */
69
+ private footerActions;
70
+ /** Whether `header-actions` holds something, read from the slot. */
71
+ private headerActions;
45
72
  protected willUpdate(changed: PropertyValues): void;
73
+ protected updated(changed: PropertyValues): void;
74
+ private readonly readActions;
46
75
  protected render(): TemplateResult;
47
76
  }
48
77
  declare global {
@@ -4,26 +4,59 @@ 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, hostAria } from '@fusion.dev/helix-core';
7
+ import { customElement, HelixElement, hostAria, slotFilled } from '@fusion.dev/helix-core';
8
8
  import { html } from 'lit';
9
- import { property } from 'lit/decorators.js';
9
+ import { property, state } from 'lit/decorators.js';
10
10
  let HelixHeadlessCard = class HelixHeadlessCard extends HelixElement {
11
+ constructor() {
12
+ super(...arguments);
13
+ this.labelledBy = null;
14
+ this.namedBy = null;
15
+ this.footerActions = false;
16
+ this.headerActions = false;
17
+ this.readActions = () => {
18
+ const filled = (name) => slotFilled(this.renderRoot?.querySelector(`slot[name="${name}"]`));
19
+ this.headerActions = filled('header-actions');
20
+ this.footerActions = filled('footer-actions');
21
+ };
22
+ }
11
23
  willUpdate(changed) {
12
24
  super.willUpdate(changed);
13
- hostAria(this.internals, { role: 'group' });
25
+ const named = Boolean(this.namedBy?.trim() || this.labelledBy?.trim());
26
+ hostAria(this.internals, { role: named ? 'group' : '' });
27
+ }
28
+ updated(changed) {
29
+ super.updated(changed);
30
+ this.readActions();
14
31
  }
15
32
  render() {
33
+ const header = html `<slot name="header"></slot
34
+ ><slot name="header-actions" @slotchange=${this.readActions}></slot>`;
35
+ const footer = html `<slot name="footer"></slot
36
+ ><slot name="footer-actions" @slotchange=${this.readActions}></slot>`;
16
37
  return html `
17
38
  <slot name="media"></slot>
18
- <slot name="header"></slot>
39
+ ${this.headerActions ? html `<div part="header-row">${header}</div>` : header}
19
40
  <slot></slot>
20
- <slot name="footer"></slot>
41
+ ${this.footerActions ? html `<div part="footer-row">${footer}</div>` : footer}
21
42
  `;
22
43
  }
23
44
  };
24
45
  __decorate([
25
46
  property({ attribute: 'media-placement', reflect: true })
26
47
  ], HelixHeadlessCard.prototype, "mediaPlacement", void 0);
48
+ __decorate([
49
+ property({ attribute: 'aria-labelledby' })
50
+ ], HelixHeadlessCard.prototype, "labelledBy", void 0);
51
+ __decorate([
52
+ property({ attribute: 'aria-label' })
53
+ ], HelixHeadlessCard.prototype, "namedBy", void 0);
54
+ __decorate([
55
+ state()
56
+ ], HelixHeadlessCard.prototype, "footerActions", void 0);
57
+ __decorate([
58
+ state()
59
+ ], HelixHeadlessCard.prototype, "headerActions", void 0);
27
60
  HelixHeadlessCard = __decorate([
28
61
  customElement('helix-headless-card')
29
62
  ], HelixHeadlessCard);
@@ -86,7 +86,9 @@ let HelixHeadlessCheckbox = class HelixHeadlessCheckbox extends MixinControllerC
86
86
  ?required=${this.required}
87
87
  aria-describedby=${this.describedBy ?? nothing}
88
88
  aria-invalid=${this.invalidity ?? nothing}
89
+ aria-readonly=${this.readOnly ? 'true' : nothing}
89
90
  @change=${this.handleChange}
91
+ @click=${this.holdReadOnly}
90
92
  @input=${this.stopInner}
91
93
  />
92
94
  <span
@@ -1,6 +1,7 @@
1
1
  import { DisabledCascadeController, HelixFormElement } from '@fusion.dev/helix-core';
2
- import { type PropertyValues, type TemplateResult } from 'lit';
2
+ import { nothing, type PropertyValues, type TemplateResult } from 'lit';
3
3
  import { HelixHeadlessCheckbox } from '../../checkbox/root/checkbox-root.js';
4
+ import '../../checkbox/index.js';
4
5
  declare const HelixHeadlessCheckboxGroup_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
5
6
  /**
6
7
  * @summary A group of related checkboxes under one label, with one value for the set.
@@ -19,6 +20,11 @@ declare const HelixHeadlessCheckboxGroup_base: (new (...args: any[]) => import("
19
20
  * checkboxes are written, read from the boxes themselves. Setting it checks
20
21
  * exactly those values and unchecks the rest.
21
22
  *
23
+ * `select-all` draws a box above the set that checks every enabled box, or
24
+ * unchecks them all once every one is checked. It shows a dash while only some
25
+ * are checked, and changes the set through the same cancelable
26
+ * `helix-before-change` a box does.
27
+ *
22
28
  * A checkbox is a member wherever it sits inside the group, in a row or a grid
23
29
  * cell of your own, unless another group inside this one holds it. A field of
24
30
  * another kind inside the group, such as an "Other" text field, sends its own
@@ -47,19 +53,47 @@ declare const HelixHeadlessCheckboxGroup_base: (new (...args: any[]) => import("
47
53
  * @csspart hint - The help under the checkboxes.
48
54
  * @csspart items - The element that holds the checkboxes, laid out by `orientation`.
49
55
  * @csspart label - The group's label, above the checkboxes.
56
+ * @csspart select-all - The box that checks or unchecks every box, under `select-all`.
57
+ * @csspart select-all-box - The select-all box's box, under the mark.
58
+ * @csspart select-all-control - The select-all box's native input.
59
+ * @csspart select-all-feedback - The select-all box's own message, which it never shows.
60
+ * @csspart select-all-field - The row that holds the select-all box and its label.
61
+ * @csspart select-all-hint - The select-all box's own help, which it never shows.
62
+ * @csspart select-all-label - The words beside the select-all box.
63
+ * @csspart select-all-mark - The select-all box's check mark, or its dash while only some boxes are checked.
64
+ * @csspart select-all-mark-checked - Added to `select-all-mark` while every box is checked.
65
+ * @csspart select-all-mark-dash - Added to `select-all-mark` while only some boxes are checked, and kept until every one is.
66
+ * @csspart select-all-mark-indeterminate - Added to `select-all-mark` while only some boxes are checked.
50
67
  *
51
68
  * @cssstate invalid - The control has an error to show, from the browser's validation or from your `feedback`.
52
69
  */
53
70
  export declare class HelixHeadlessCheckboxGroup extends HelixHeadlessCheckboxGroup_base {
71
+ /**
72
+ * Whether a box above the set checks or unchecks every enabled box.
73
+ */
74
+ selectAll: boolean;
75
+ /**
76
+ * The words beside the box `select-all` draws.
77
+ */
78
+ selectAllLabel: string;
54
79
  /**
55
80
  * The checked values, comma separated.
56
81
  *
57
82
  * Read from the boxes once they are known, so a box a script ticks directly
58
- * is in it at once. Written, it is pushed onto the boxes.
83
+ * is in it at once. Written, it is pushed onto the boxes. A box whose value
84
+ * holds a comma cannot be named here: use `values`.
59
85
  */
60
86
  get value(): string;
61
87
  set value(next: string);
62
- /** The value last written, which the boxes are given at the next update. */
88
+ /**
89
+ * The checked values, as a list, in the order the boxes are written.
90
+ *
91
+ * The same set as `value`, and the one to use where a value may hold a
92
+ * comma. Written, it checks exactly those boxes and unchecks the rest.
93
+ */
94
+ get values(): string[];
95
+ set values(next: string[]);
96
+ /** The values last written, which the boxes are given at the next update. */
63
97
  private declared;
64
98
  /**
65
99
  * Whether `declared` has yet to reach the boxes.
@@ -179,6 +213,22 @@ export declare class HelixHeadlessCheckboxGroup extends HelixHeadlessCheckboxGro
179
213
  */
180
214
  private validate;
181
215
  protected updated(changed: PropertyValues): void;
216
+ /**
217
+ * Checks every enabled box, or unchecks them all once every one is checked.
218
+ *
219
+ * The box's own request is refused, since the box shows what the set holds
220
+ * and the set is moved here, through one cancelable `helix-before-change`
221
+ * for the whole set, as a box moves it.
222
+ */
223
+ private readonly handleSelectAll;
224
+ /**
225
+ * The box above the set that checks or unchecks every box, under
226
+ * `select-all`, behind a seam a tier can move.
227
+ *
228
+ * Checked while every box is, and showing a dash while only some are. It is
229
+ * in this shadow root, so it is no member of the set and submits nothing.
230
+ */
231
+ protected renderSelectAll(): TemplateResult | typeof nothing;
182
232
  protected render(): TemplateResult;
183
233
  }
184
234
  declare global {
@@ -5,19 +5,23 @@ 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
  var HelixHeadlessCheckboxGroup_1;
8
- import { customElement, DisabledCascadeController, HelixBeforeChangeEvent, HelixFormElement, hostAria, MixinField, } from '@fusion.dev/helix-core';
9
- import { html } from 'lit';
8
+ import { commaList, customElement, DisabledCascadeController, HelixBeforeChangeEvent, HelixFormElement, hostAria, MixinField, } from '@fusion.dev/helix-core';
9
+ import { nothing } from 'lit';
10
10
  import { property } from 'lit/decorators.js';
11
+ import { html } from 'lit/static-html.js';
11
12
  import { HelixHeadlessCheckbox } from '../../checkbox/root/checkbox-root.js';
13
+ import '../../checkbox/index.js';
12
14
  let HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = class HelixHeadlessCheckboxGroup extends MixinField(HelixFormElement) {
13
15
  constructor() {
14
16
  super(...arguments);
15
- this.declared = '';
17
+ this.selectAll = false;
18
+ this.selectAllLabel = 'Select all';
19
+ this.declared = [];
16
20
  this.pending = false;
17
21
  this.watched = new Set();
18
22
  this.member = {
19
23
  hostUpdated: () => {
20
- if (this.isConnected && this.value !== this.judged) {
24
+ if (this.isConnected && (this.selectAll || this.value !== this.judged)) {
21
25
  this.requestUpdate();
22
26
  }
23
27
  },
@@ -38,13 +42,12 @@ let HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = class HelixHeadl
38
42
  const wanted = event.detail.checked;
39
43
  const next = this.boxes
40
44
  .filter((box) => (box === changed ? wanted : box.checked))
41
- .map((box) => box.value)
42
- .join(',');
43
- if (!this.dispatchEvent(new HelixBeforeChangeEvent({ value: next }))) {
45
+ .map((box) => box.value);
46
+ if (!this.dispatchEvent(new HelixBeforeChangeEvent({ value: next.join(',') }))) {
44
47
  event.preventDefault();
45
48
  return;
46
49
  }
47
- this.value = next;
50
+ this.values = next;
48
51
  this.announceInput();
49
52
  this.announceChange();
50
53
  };
@@ -53,22 +56,40 @@ let HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = class HelixHeadl
53
56
  event.stopImmediatePropagation();
54
57
  }
55
58
  };
59
+ this.handleSelectAll = (event) => {
60
+ event.preventDefault();
61
+ event.stopPropagation();
62
+ const enabled = this.boxes.filter((box) => !box.isDisabled);
63
+ const every = enabled.length > 0 && enabled.every((box) => box.checked);
64
+ const next = this.boxes
65
+ .filter((box) => (enabled.includes(box) ? !every : box.checked))
66
+ .map((box) => box.value);
67
+ if (!this.dispatchEvent(new HelixBeforeChangeEvent({ value: next.join(',') }))) {
68
+ return;
69
+ }
70
+ this.values = next;
71
+ this.announceInput();
72
+ this.announceChange();
73
+ };
56
74
  }
57
75
  get value() {
76
+ return this.values.join(',');
77
+ }
78
+ set value(next) {
79
+ this.values = commaList(next);
80
+ }
81
+ get values() {
58
82
  if (this.pending || !this.hasUpdated || !this.childrenKnown) {
59
- return this.declared;
83
+ return [...this.declared];
60
84
  }
61
85
  const boxes = this.boxes;
62
86
  return boxes.length === 0
63
- ? this.declared
64
- : boxes
65
- .filter((box) => box.checked)
66
- .map((box) => box.value)
67
- .join(',');
87
+ ? [...this.declared]
88
+ : boxes.filter((box) => box.checked).map((box) => box.value);
68
89
  }
69
- set value(next) {
70
- const previous = this.declared;
71
- this.declared = next;
90
+ set values(next) {
91
+ const previous = this.value;
92
+ this.declared = [...next];
72
93
  this.pending = true;
73
94
  this.requestUpdate('value', previous);
74
95
  }
@@ -105,10 +126,7 @@ let HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = class HelixHeadl
105
126
  return;
106
127
  }
107
128
  this.pending = false;
108
- const wanted = new Set(this.declared
109
- .split(',')
110
- .map((entry) => entry.trim())
111
- .filter(Boolean));
129
+ const wanted = new Set(this.declared);
112
130
  for (const box of boxes) {
113
131
  box.checked = wanted.has(box.value);
114
132
  }
@@ -159,8 +177,30 @@ let HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = class HelixHeadl
159
177
  this.validate();
160
178
  this.linkHost();
161
179
  }
180
+ renderSelectAll() {
181
+ if (!this.selectAll) {
182
+ return nothing;
183
+ }
184
+ const boxes = this.childrenKnown ? this.boxes : [];
185
+ const ticked = boxes.filter((box) => box.checked).length;
186
+ const every = boxes.length > 0 && ticked === boxes.length;
187
+ const box = this.tag('checkbox');
188
+ return html `<${box}
189
+ part="select-all"
190
+ exportparts="box: select-all-box, control: select-all-control,
191
+ feedback: select-all-feedback, field: select-all-field, hint: select-all-hint,
192
+ label: select-all-label, mark: select-all-mark, mark-checked: select-all-mark-checked,
193
+ mark-dash: select-all-mark-dash, mark-indeterminate: select-all-mark-indeterminate"
194
+ .checked=${every}
195
+ .indeterminate=${ticked > 0 && !every}
196
+ ?disabled=${this.isDisabled}
197
+ label=${this.selectAllLabel}
198
+ @helix-before-toggle=${this.handleSelectAll}
199
+ @input=${(event) => event.stopPropagation()}
200
+ ></${box}>`;
201
+ }
162
202
  render() {
163
- return html `${this.renderGroupLabel()}
203
+ return html `${this.renderGroupLabel()}${this.renderSelectAll()}
164
204
  <div part="items">
165
205
  ${''}
166
206
  <slot @slotchange=${() => this.requestUpdate()}></slot>
@@ -168,9 +208,18 @@ let HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = class HelixHeadl
168
208
  ${this.renderHint()}${this.renderFeedback()}`;
169
209
  }
170
210
  };
211
+ __decorate([
212
+ property({ attribute: 'select-all', type: Boolean })
213
+ ], HelixHeadlessCheckboxGroup.prototype, "selectAll", void 0);
214
+ __decorate([
215
+ property({ attribute: 'select-all-label' })
216
+ ], HelixHeadlessCheckboxGroup.prototype, "selectAllLabel", void 0);
171
217
  __decorate([
172
218
  property()
173
219
  ], HelixHeadlessCheckboxGroup.prototype, "value", null);
220
+ __decorate([
221
+ property({ attribute: false })
222
+ ], HelixHeadlessCheckboxGroup.prototype, "values", null);
174
223
  HelixHeadlessCheckboxGroup = HelixHeadlessCheckboxGroup_1 = __decorate([
175
224
  customElement('helix-headless-checkbox-group')
176
225
  ], HelixHeadlessCheckboxGroup);
@@ -0,0 +1,13 @@
1
+ /**
2
+ * How many lines a block of code shows.
3
+ *
4
+ * A final line break ends the last line rather than starting another, which is
5
+ * how an editor counts a file and how the block draws one: `a\nb\n` is two
6
+ * lines. A Windows line break is one break. Empty code has no lines.
7
+ */
8
+ export declare const lineCount: (code: string) => number;
9
+ /**
10
+ * The numbers for a gutter of `count` lines, one to a line, as the text a
11
+ * `<pre>` draws beside the code. The stylesheet aligns them to the end.
12
+ */
13
+ export declare const gutterNumbers: (count: number) => string;
@@ -0,0 +1,2 @@
1
+ export const lineCount = (code) => code === '' ? 0 : code.replace(/\r?\n$/, '').split(/\r?\n/).length;
2
+ export const gutterNumbers = (count) => Array.from({ length: count }, (_, index) => String(index + 1)).join('\n');
@@ -14,6 +14,12 @@ import '../../copy-button/index.js';
14
14
  *
15
15
  * For a fragment of code inside a sentence, use `Code`.
16
16
  *
17
+ * Set `line-numbers` to number the lines in a gutter beside the code, hidden
18
+ * from the accessibility tree and left out of a copy. Set `highlight` to a
19
+ * function that turns the code into highlighted markup, such as one wrapping
20
+ * Shiki or Prism, and the block draws what it returns; the code stays in the
21
+ * slot, so the copy button and the page's own text are the code as written.
22
+ *
17
23
  * Set `diff` to show a change. Put a unified diff, the output of `git diff` or
18
24
  * `diff -u`, in the same slot, and the block draws the lines it added and
19
25
  * removed. The block never computes a diff itself. Line numbers come from the
@@ -42,6 +48,7 @@ import '../../copy-button/index.js';
42
48
  * @csspart context - In a diff, a line both versions share.
43
49
  * @csspart copy - The copy button. It sits in the header when there is one, and beside the code otherwise.
44
50
  * @csspart copy-button - The inner button.
51
+ * @csspart copy-live - The copy button's live region, which speaks while the button is pending.
45
52
  * @csspart copy-mark - The clipboard icon, and the check mark that replaces it after a copy.
46
53
  * @csspart copy-text - The words on that button, trimmed to their capitals and baseline.
47
54
  * @csspart copy-tooltip - The copy button's tooltip.
@@ -57,6 +64,7 @@ import '../../copy-button/index.js';
57
64
  * @csspart file - In a diff, one file's header and block.
58
65
  * @csspart filler - In a split diff, the empty row opposite a line the other side does not have.
59
66
  * @csspart frame - The code, and the copy button beside it where there is no header.
67
+ * @csspart gutter - The line numbers beside the code, shown when `line-numbers` is set.
60
68
  * @csspart header - The bar that holds the name and the copy button, shown when there is a name.
61
69
  * @csspart hunk - In a diff, a `@@` line saying where the lines under it are.
62
70
  * @csspart label - The file name or language, where one is given.
@@ -84,6 +92,19 @@ export declare class HelixHeadlessCodeBlock extends HelixElement {
84
92
  * `false` reflects as no attribute at all.
85
93
  */
86
94
  diff: boolean;
95
+ /**
96
+ * Turns the code into highlighted markup, which the block draws in place of
97
+ * the plain text.
98
+ *
99
+ * Called with the code as written and returning HTML, such as the output of
100
+ * Shiki's `codeToHtml` or Prism's `highlight`. **The markup is drawn as
101
+ * given**, so it has to escape the code it was handed, which those
102
+ * highlighters do. Bind the language in the function you pass. The code
103
+ * stays in the slot, so the copy button copies it as written and a reader
104
+ * without the script still has it. Not called on a server, which has no code
105
+ * to read, nor for a diff.
106
+ */
107
+ highlight?: (code: string) => string;
87
108
  /**
88
109
  * The block's name, usually a file name or a language.
89
110
  *
@@ -91,6 +112,15 @@ export declare class HelixHeadlessCodeBlock extends HelixElement {
91
112
  * carries no name of its own.
92
113
  */
93
114
  label: string;
115
+ /**
116
+ * Whether the lines are numbered in a gutter beside the code.
117
+ *
118
+ * The numbers are hidden from the accessibility tree and are not part of a
119
+ * copy, which takes the code alone. Reflected, because the stylesheet lays
120
+ * the gutter out beside the code. A diff numbers its lines from its hunks
121
+ * whether or not this is set.
122
+ */
123
+ lineNumbers: boolean;
94
124
  /**
95
125
  * Whether to leave the copy button off.
96
126
  *
@@ -7,8 +7,10 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { customElement, HelixElement } from '@fusion.dev/helix-core';
8
8
  import { nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
10
11
  import { html } from 'lit/static-html.js';
11
12
  import '../../copy-button/index.js';
13
+ import { gutterNumbers, lineCount } from '../lines.js';
12
14
  import { pairLines, parsePatch } from '../patch.js';
13
15
  let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
14
16
  constructor() {
@@ -17,6 +19,7 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
17
19
  this.copyLabel = 'Copy code';
18
20
  this.diff = false;
19
21
  this.label = '';
22
+ this.lineNumbers = false;
20
23
  this.noCopy = false;
21
24
  this.parsed = { files: [], text: '' };
22
25
  }
@@ -60,9 +63,21 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
60
63
  if (files.length > 0) {
61
64
  return this.renderDiff(files);
62
65
  }
66
+ const text = this.text;
67
+ const highlighted = this.highlight && text !== '' ? this.highlight(text) : undefined;
68
+ const code = highlighted === undefined
69
+ ? html `<code part="code"><slot @slotchange=${() => this.requestUpdate()}></slot></code>`
70
+ : html `<code part="code">${unsafeHTML(highlighted)}</code><slot
71
+ hidden
72
+ @slotchange=${() => this.requestUpdate()}
73
+ ></slot>`;
74
+ const lines = lineCount(text);
75
+ const gutter = this.lineNumbers
76
+ ? html `<span part="gutter" aria-hidden="true">${lines === 0 ? nothing : gutterNumbers(lines)}</span>`
77
+ : nothing;
63
78
  return html `${this.renderHeader(this.label)}
64
79
  <div part="frame">
65
- <pre part="block"><code part="code"><slot @slotchange=${() => this.requestUpdate()}></slot></code></pre>
80
+ <pre part="block">${gutter}${code}</pre>
66
81
  ${this.label ? nothing : this.renderCopy()}
67
82
  </div>`;
68
83
  }
@@ -77,7 +92,7 @@ let HelixHeadlessCodeBlock = class HelixHeadlessCodeBlock extends HelixElement {
77
92
  renderCopyButton(value = this.text) {
78
93
  return html `<${this.tag('copy-button')}
79
94
  part="copy"
80
- exportparts="button: copy-button, text: copy-text, mark: copy-mark, tooltip: copy-tooltip,
95
+ exportparts="button: copy-button, text: copy-text, mark: copy-mark, live: copy-live, tooltip: copy-tooltip,
81
96
  tooltip-arrow: copy-tooltip-arrow, tooltip-arrow-bottom: copy-tooltip-arrow-bottom,
82
97
  tooltip-arrow-left: copy-tooltip-arrow-left, tooltip-arrow-right: copy-tooltip-arrow-right,
83
98
  tooltip-arrow-top: copy-tooltip-arrow-top, tooltip-bottom: copy-tooltip-bottom,
@@ -144,9 +159,15 @@ __decorate([
144
159
  __decorate([
145
160
  property({ reflect: true, type: Boolean })
146
161
  ], HelixHeadlessCodeBlock.prototype, "diff", void 0);
162
+ __decorate([
163
+ property({ attribute: false })
164
+ ], HelixHeadlessCodeBlock.prototype, "highlight", void 0);
147
165
  __decorate([
148
166
  property()
149
167
  ], HelixHeadlessCodeBlock.prototype, "label", void 0);
168
+ __decorate([
169
+ property({ attribute: 'line-numbers', reflect: true, type: Boolean })
170
+ ], HelixHeadlessCodeBlock.prototype, "lineNumbers", void 0);
150
171
  __decorate([
151
172
  property({ attribute: 'no-copy', reflect: true, type: Boolean })
152
173
  ], HelixHeadlessCodeBlock.prototype, "noCopy", void 0);
@@ -1,4 +1,4 @@
1
- import { AriaForwardController, type ColorFormat, HelixFormElement } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, type ColorFormat, type ColorWords, HelixFormElement } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  import '../../color-picker/index.js';
4
4
  declare const HelixHeadlessColorInput_base: (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").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
@@ -28,6 +28,10 @@ declare const HelixHeadlessColorInput_base: (new (...args: any[]) => import("@fu
28
28
  * waits until you are done. Dragging in the panel sends `input` as the color
29
29
  * moves and `change` when it settles.
30
30
  *
31
+ * The trigger and ArrowDown open the panel with focus in the square. Tab moves
32
+ * between the panel's controls without leaving it, and Escape closes it and
33
+ * returns focus to the field.
34
+ *
31
35
  * The component sets `--color-input-swatch`, so do not set it yourself. It
32
36
  * holds the resolved color, so the styled tier can paint the swatch without
33
37
  * parsing the value.
@@ -72,10 +76,16 @@ declare const HelixHeadlessColorInput_base: (new (...args: any[]) => import("@fu
72
76
  * @csspart picker-controls - The row under the square.
73
77
  * @csspart picker-eyedropper - The control that samples a color from the screen.
74
78
  * @csspart picker-eyedropper-button - The button inside `picker-eyedropper`.
79
+ * @csspart picker-eyedropper-live - The live region of the button inside `picker-eyedropper`, which says its pending label.
75
80
  * @csspart picker-eyedropper-text - The words on the button inside `picker-eyedropper`.
81
+ * @csspart picker-field - One channel's number field with its label, in `channel-fields`.
82
+ * @csspart picker-field-input - The number input in a channel's field.
83
+ * @csspart picker-field-label - The name above a channel's number input.
84
+ * @csspart picker-fields - The row of channel number fields, in `channel-fields`.
76
85
  * @csspart picker-footer - The row holding the value and the tools.
77
86
  * @csspart picker-format - The control that changes the syntax the value is written in.
78
87
  * @csspart picker-format-button - The button inside `picker-format`.
88
+ * @csspart picker-format-live - The live region of the button inside `picker-format`, which says its pending label.
79
89
  * @csspart picker-format-text - The words on the button inside `picker-format`.
80
90
  * @csspart picker-grid - The saturation and brightness square.
81
91
  * @csspart picker-grid-brightness - The range input for the square's vertical axis.
@@ -110,6 +120,20 @@ export declare class HelixHeadlessColorInput extends HelixHeadlessColorInput_bas
110
120
  * consumer who wants autofill can still ask.
111
121
  */
112
122
  autocomplete: string;
123
+ /**
124
+ * Whether the panel shows a number field for each channel of the color.
125
+ * Passed to the panel; see Color Picker's `channel-fields`.
126
+ */
127
+ channelFields: boolean;
128
+ /**
129
+ * The words a color's name is spoken in, as JSON keyed by their English,
130
+ * such as `{"red": "rot", "vibrant": "kräftiges"}`.
131
+ *
132
+ * Passed to the panel, whose square, hue ramp and presets say the color's
133
+ * name, and read by the swatch in `swatch`, which says it before the value.
134
+ * Color Picker lists the keys.
135
+ */
136
+ colorWords: Partial<ColorWords>;
113
137
  /**
114
138
  * The syntax the value is written in: `hex`, `rgb`, or `hsl`.
115
139
  *
@@ -196,6 +220,15 @@ export declare class HelixHeadlessColorInput extends HelixHeadlessColorInput_bas
196
220
  protected get anchor(): HTMLElement | null;
197
221
  /** What the picker should show, which is only ever a color. */
198
222
  private get picked();
223
+ /**
224
+ * What the swatch says in `swatch`: the color's name and then the value, or
225
+ * the trigger's words where there is no color yet.
226
+ *
227
+ * The name first, because it is what a sighted reader takes from the block of
228
+ * color, and the value after it, because it is what the field holds and what
229
+ * a reader may need to copy.
230
+ */
231
+ private get swatchWords();
199
232
  /** What the trigger's swatch paints, which is only ever a color. */
200
233
  private get painted();
201
234
  /** Relayed under this element's name, so a consumer hears one control. */