@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
@@ -20,6 +20,14 @@ declare const HelixHeadlessTag_base: (new (...args: any[]) => import("@fusion.de
20
20
  * to put the tag's words somewhere else, such as `dismiss-label="{label}
21
21
  * entfernen"`.
22
22
  *
23
+ * `href` makes the label a link, and `disabled` takes the tag out of reach: its
24
+ * link and its remove button stop answering.
25
+ *
26
+ * **In a `Tag.Group` a tag is a row of a grid.** The group gives it its role,
27
+ * its place in the one tab stop and, where the group selects, whether it is
28
+ * selected. Its remove button leaves the tab order there, Delete and Backspace
29
+ * doing its job from the row.
30
+ *
23
31
  * @since 0.1.0
24
32
  * @status stable
25
33
  * @category markers
@@ -27,17 +35,65 @@ declare const HelixHeadlessTag_base: (new (...args: any[]) => import("@fusion.de
27
35
  * @documentation https://fusion.dev/helix/components/tag
28
36
  *
29
37
  * @slot - The tag's label.
38
+ * @slot dismiss-icon - Replaces the glyph on the remove button.
30
39
  * @slot start - The category the label belongs to, shown before it in a heavier weight.
31
40
  *
32
41
  * @event {HelixDismissEvent} helix-dismiss - The remove button was pressed. The tag does not remove itself, so remove it in response. Cancelable.
33
42
  *
43
+ * @csspart cell - The grid cell around everything the tag shows, rendered only in a `Tag.Group`, where it takes focus.
34
44
  * @csspart dismiss - The button that removes the tag.
35
45
  * @csspart dismiss-mark - The icon on the remove button.
36
46
  * @csspart label - The label, which the styled tag trims to its capitals and baseline so the letters sit at the middle in any font.
47
+ * @csspart link - The link around the label, under `href`.
37
48
  * @csspart start - The category before the label.
49
+ *
50
+ * @cssstate selected - The tag is selected in a `Tag.Group` that selects.
38
51
  */
39
52
  export declare class HelixHeadlessTag extends HelixHeadlessTag_base {
40
53
  dismissLabel: string;
54
+ /**
55
+ * Takes the tag out of reach: its link and its remove button stop
56
+ * answering, and in a `Tag.Group` the arrow keys pass over it and it cannot
57
+ * be selected or removed.
58
+ */
59
+ disabled: boolean;
60
+ /**
61
+ * Whether the tag holds its group's tab stop.
62
+ *
63
+ * Written by `Tag.Group` on every tag it holds, and unset outside one, which
64
+ * is how a tag knows it is a row. No attribute: it is coordination between
65
+ * elements, the same shape `Toggle.focusable` has.
66
+ */
67
+ focusable?: boolean;
68
+ /**
69
+ * Makes the label a link to this address.
70
+ */
71
+ href: string;
72
+ /**
73
+ * Whether the tag is selected, in a `Tag.Group` that selects.
74
+ *
75
+ * Written by the group from its own `value`, and unset where nothing can be
76
+ * selected, which is what keeps `aria-selected` off a set that does not
77
+ * select.
78
+ */
79
+ selected?: boolean | undefined;
80
+ /**
81
+ * What the tag stands for in its group's `value`.
82
+ *
83
+ * Absent is the tag's own words, its category first.
84
+ */
85
+ value: string;
86
+ /** The tag's words, its category first, or none where the children are not known yet. */
87
+ get words(): string;
88
+ /** Whether a `Tag.Group` holds this tag, which makes it a row. */
89
+ private get grouped();
90
+ /**
91
+ * Moves focus to the tag: its cell in a group, and otherwise its link or
92
+ * its remove button, whichever it has.
93
+ */
94
+ focusItem(): void;
95
+ protected get returnFocusTo(): HTMLElement | null;
96
+ protected willUpdate(changed: PropertyValues<this>): void;
41
97
  /**
42
98
  * The remove button's name: `dismissLabel` with the tag's own words.
43
99
  *
@@ -54,6 +110,10 @@ export declare class HelixHeadlessTag extends HelixHeadlessTag_base {
54
110
  private get removeName();
55
111
  protected firstUpdated(changed: PropertyValues): void;
56
112
  protected render(): TemplateResult;
113
+ /** The label, inside a link under `href`, behind a seam a tier can move. */
114
+ protected renderLabel(): TemplateResult;
115
+ /** The remove button, behind a seam a tier can move. */
116
+ protected renderDismiss(): TemplateResult;
57
117
  }
58
118
  declare global {
59
119
  interface HTMLElementTagNameMap {
@@ -4,17 +4,45 @@ 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, slottedWords } from '@fusion.dev/helix-core';
8
- import { x } from '@fusion.dev/helix-icons';
7
+ import { customElement, drawDismiss, drawDismissGlyph, HelixElement, hostAria, MixinDismissible, slottedWords, } from '@fusion.dev/helix-core';
9
8
  import { html, nothing } from 'lit';
10
- import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
9
+ import { property } from 'lit/decorators.js';
11
10
  let HelixHeadlessTag = class HelixHeadlessTag extends MixinDismissible(HelixElement) {
12
11
  constructor() {
13
12
  super(...arguments);
14
13
  this.dismissLabel = 'Remove';
14
+ this.disabled = false;
15
+ this.href = '';
16
+ this.value = '';
17
+ }
18
+ get words() {
19
+ return this.childrenKnown ? slottedWords(this, ['start', '']) : '';
20
+ }
21
+ get grouped() {
22
+ return this.focusable !== undefined;
23
+ }
24
+ focusItem() {
25
+ this.renderRoot
26
+ .querySelector(this.grouped ? '[part~="cell"]' : '[part~="link"], [part~="dismiss"]')
27
+ ?.focus();
28
+ }
29
+ get returnFocusTo() {
30
+ if (this.disabled) {
31
+ return null;
32
+ }
33
+ return this.grouped
34
+ ? this.renderRoot.querySelector('[part~="cell"]')
35
+ : super.returnFocusTo;
36
+ }
37
+ willUpdate(changed) {
38
+ super.willUpdate(changed);
39
+ hostAria(this.internals, { role: this.grouped ? 'row' : '' });
40
+ this.internals.ariaSelected = this.selected === undefined ? null : String(this.selected);
41
+ this.internals.ariaDisabled = this.disabled ? 'true' : null;
42
+ this.toggleState('selected', this.selected === true);
15
43
  }
16
44
  get removeName() {
17
- const words = this.childrenKnown ? slottedWords(this, ['start', '']) : '';
45
+ const words = this.words;
18
46
  if (this.dismissLabel.includes('{label}')) {
19
47
  return this.dismissLabel.replace('{label}', words).trim();
20
48
  }
@@ -28,22 +56,50 @@ let HelixHeadlessTag = class HelixHeadlessTag extends MixinDismissible(HelixElem
28
56
  this.finishHydration();
29
57
  }
30
58
  render() {
31
- return html `<slot name="start" part="start"></slot>
32
- <slot part="label"></slot>
33
- ${this.dismissible
34
- ? html `<button
35
- part="dismiss"
36
- type="button"
37
- aria-label=${this.removeName}
38
- @click=${() => this.dismiss()}
39
- >
40
- <svg part="dismiss-mark" fill="currentColor" viewBox=${x.viewBox} aria-hidden="true">
41
- ${unsafeSVG(x.content)}
42
- </svg>
43
- </button>`
44
- : nothing}`;
59
+ const content = html `<slot name="start" part="start"></slot>${this.renderLabel()}${this.dismissible ? this.renderDismiss() : nothing}`;
60
+ return this.grouped
61
+ ? html `<span part="cell" role="gridcell" tabindex=${this.focusable ? '0' : '-1'}
62
+ >${content}</span
63
+ >`
64
+ : content;
65
+ }
66
+ renderLabel() {
67
+ if (this.href === '') {
68
+ return html `<slot part="label"></slot>`;
69
+ }
70
+ return html `<a
71
+ aria-disabled=${this.disabled ? 'true' : nothing}
72
+ href=${this.disabled ? nothing : this.href}
73
+ part="link"
74
+ tabindex=${this.grouped ? '-1' : nothing}
75
+ ><slot part="label"></slot
76
+ ></a>`;
77
+ }
78
+ renderDismiss() {
79
+ return drawDismiss({
80
+ disabled: this.disabled,
81
+ label: this.removeName,
82
+ mark: html `<slot name="dismiss-icon">${drawDismissGlyph()}</slot>`,
83
+ onDismiss: () => this.dismiss(),
84
+ tabindex: this.grouped ? '-1' : undefined,
85
+ });
45
86
  }
46
87
  };
88
+ __decorate([
89
+ property({ reflect: true, type: Boolean })
90
+ ], HelixHeadlessTag.prototype, "disabled", void 0);
91
+ __decorate([
92
+ property({ attribute: false })
93
+ ], HelixHeadlessTag.prototype, "focusable", void 0);
94
+ __decorate([
95
+ property()
96
+ ], HelixHeadlessTag.prototype, "href", void 0);
97
+ __decorate([
98
+ property({ attribute: false })
99
+ ], HelixHeadlessTag.prototype, "selected", void 0);
100
+ __decorate([
101
+ property()
102
+ ], HelixHeadlessTag.prototype, "value", void 0);
47
103
  HelixHeadlessTag = __decorate([
48
104
  customElement('helix-headless-tag')
49
105
  ], HelixHeadlessTag);
@@ -0,0 +1,10 @@
1
+ /** How many tags a group lets a reader select. */
2
+ export type TagSelectionMode = 'multiple' | 'none' | 'single';
3
+ /**
4
+ * The `value` a press on the tag carrying `pressed` leaves.
5
+ *
6
+ * `single` selects that tag alone, or none where it was the one selected.
7
+ * `multiple` adds it, or takes it out. `none` selects nothing and leaves the
8
+ * value as it was.
9
+ */
10
+ export declare const pressedValue: (mode: TagSelectionMode, value: string, pressed: string) => string;
@@ -0,0 +1,12 @@
1
+ import { commaList, toggleValue } from '@fusion.dev/helix-core';
2
+ export const pressedValue = (mode, value, pressed) => {
3
+ const now = commaList(value);
4
+ const held = now.includes(pressed);
5
+ if (mode === 'single') {
6
+ return held ? '' : pressed;
7
+ }
8
+ if (mode === 'multiple') {
9
+ return toggleValue(now, pressed).join(', ');
10
+ }
11
+ return value;
12
+ };
@@ -0,0 +1,22 @@
1
+ /** What a box adds around its lines, and how tall one line is, in pixels. */
2
+ export interface LineMetrics {
3
+ /** Padding and border above and below the lines. */
4
+ readonly around: number;
5
+ /** The height of one line. */
6
+ readonly line: number;
7
+ }
8
+ /**
9
+ * The height a growing field takes: what its text needs, held to `maxRows`
10
+ * lines where that is a positive number. The second answer says whether the
11
+ * text is taller than the cap, so the field scrolls.
12
+ */
13
+ export declare const grownHeight: (needed: number, maxRows: number | undefined, metrics: LineMetrics) => {
14
+ height: number;
15
+ scrolls: boolean;
16
+ };
17
+ /**
18
+ * Reads a box's line height and what it adds around its lines from its
19
+ * computed style. A `normal` line height counts as 1.2 times the font size,
20
+ * which is what browsers draw it as for most fonts.
21
+ */
22
+ export declare const lineMetrics: (style: CSSStyleDeclaration) => LineMetrics;
@@ -0,0 +1,20 @@
1
+ export const grownHeight = (needed, maxRows, metrics) => {
2
+ if (maxRows === undefined || !(maxRows > 0) || metrics.line <= 0) {
3
+ return { height: needed, scrolls: false };
4
+ }
5
+ const cap = Math.ceil(maxRows * metrics.line + metrics.around);
6
+ return needed > cap ? { height: cap, scrolls: true } : { height: needed, scrolls: false };
7
+ };
8
+ export const lineMetrics = (style) => {
9
+ const px = (value) => Number.parseFloat(value) || 0;
10
+ const line = style.lineHeight === 'normal' || style.lineHeight === ''
11
+ ? px(style.fontSize) * 1.2
12
+ : px(style.lineHeight);
13
+ const around = style.boxSizing === 'border-box'
14
+ ? px(style.paddingBlockStart) +
15
+ px(style.paddingBlockEnd) +
16
+ px(style.borderBlockStartWidth) +
17
+ px(style.borderBlockEndWidth)
18
+ : 0;
19
+ return { around, line };
20
+ };
@@ -14,6 +14,8 @@ declare const HelixHeadlessTextarea_base: (new (...args: any[]) => import("@fusi
14
14
  *
15
15
  * `rows` sets the starting height, and `auto-grow` makes the field grow with
16
16
  * its content. You can use both: `rows` sets where an empty field begins.
17
+ * `max-rows` stops the growth at that many lines, and the field scrolls past
18
+ * them.
17
19
  *
18
20
  * @since 0.1.0
19
21
  * @status stable
@@ -21,9 +23,11 @@ declare const HelixHeadlessTextarea_base: (new (...args: any[]) => import("@fusi
21
23
  * @aliases Multiline, TextArea
22
24
  * @documentation https://fusion.dev/helix/components/textarea
23
25
  *
26
+ * @slot end - After the text, for an icon or an action beside it.
24
27
  * @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
25
28
  * @slot hint - Help under the control, for content richer than the `hint` text.
26
29
  * @slot label - The label, for content richer than the `label` text.
30
+ * @slot start - Before the text, for an icon.
27
31
  *
28
32
  * @event {Event} change - Sent from the textarea when the user finishes an edit.
29
33
  * @event {HelixBeforeChangeEvent} helix-before-change - Fired as the text changes, and cancelable.
@@ -79,6 +83,11 @@ export declare class HelixHeadlessTextarea extends HelixHeadlessTextarea_base {
79
83
  * The most characters the value can have.
80
84
  */
81
85
  maxLength?: number;
86
+ /**
87
+ * How many lines an `auto-grow` field grows to before it scrolls. Absent,
88
+ * it grows with all of its text.
89
+ */
90
+ maxRows?: number;
82
91
  /**
83
92
  * The fewest characters the value can have.
84
93
  *
@@ -7,6 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { AriaForwardController, customElement, HelixFormElement, holdCaret, isRtl, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
8
8
  import { html, nothing } from 'lit';
9
9
  import { property } from 'lit/decorators.js';
10
+ import { grownHeight, lineMetrics } from '../grow.js';
10
11
  let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerValue(MixinField(HelixFormElement)) {
11
12
  constructor() {
12
13
  super(...arguments);
@@ -51,7 +52,9 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
51
52
  if (next === 0) {
52
53
  return;
53
54
  }
54
- control.style.blockSize = `${next}px`;
55
+ const grown = grownHeight(next, this.maxRows, lineMetrics(getComputedStyle(control)));
56
+ control.style.blockSize = `${grown.height}px`;
57
+ control.style.overflowY = grown.scrolls ? 'auto' : '';
55
58
  }
56
59
  formValue() {
57
60
  const control = this.control;
@@ -155,6 +158,7 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
155
158
  render() {
156
159
  return html `${this.renderLabel()}
157
160
  <div part="field">
161
+ <slot name="start"></slot>
158
162
  <textarea
159
163
  part="control"
160
164
  id=${this.controlId}
@@ -175,6 +179,7 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
175
179
  @input=${this.handleInput}
176
180
  @change=${this.handleChange}
177
181
  ></textarea>
182
+ <slot name="end"></slot>
178
183
  </div>
179
184
  ${this.renderHint()}${this.renderFeedback()}`;
180
185
  }
@@ -194,6 +199,9 @@ __decorate([
194
199
  __decorate([
195
200
  property({ attribute: 'maxlength', type: Number })
196
201
  ], HelixHeadlessTextarea.prototype, "maxLength", void 0);
202
+ __decorate([
203
+ property({ attribute: 'max-rows', type: Number })
204
+ ], HelixHeadlessTextarea.prototype, "maxRows", void 0);
197
205
  __decorate([
198
206
  property({ attribute: 'minlength', type: Number })
199
207
  ], HelixHeadlessTextarea.prototype, "minLength", void 0);
@@ -1,8 +1,8 @@
1
- import { AriaForwardController, HelixFormElement } from '@fusion.dev/helix-core';
1
+ import { AriaForwardController, HelixFormElement, type HourCycle } from '@fusion.dev/helix-core';
2
2
  import { type PropertyValues, type TemplateResult } from 'lit';
3
3
  import '../../tag/index.js';
4
4
  import '../../time-picker/index.js';
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;
5
+ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinSegmentedFieldInterface) & (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;
6
6
  /**
7
7
  * @summary A field for a time, typed or picked from a list.
8
8
  *
@@ -15,7 +15,8 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
15
15
  * You can type a time or pick one. The list offers times at a step, and the
16
16
  * field lets you enter any time, such as `09:07`.
17
17
  *
18
- * The value is always `HH:mm` on a 24-hour clock, because that is what the form
18
+ * The value is always `HH:mm` on a 24-hour clock, or `HH:mm:ss` with
19
+ * `seconds`, because that is what the form
19
20
  * submits, what `min` and `max` compare against, and what sorts correctly as a
20
21
  * string. While idle, the field shows the time in the user's locale format.
21
22
  * Once the caret is in the field, it shows the value itself, because a
@@ -23,11 +24,16 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
23
24
  * parser for it.
24
25
  *
25
26
  * 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
+ * field. The trigger and ArrowDown open the list, and so does a press into the
28
+ * field; Tab into the field opens nothing. In the list, the arrow keys, typed digits and PageUp and PageDown
27
29
  * move through the times, and Enter, Space or a click chooses one and closes
28
30
  * the panel. With `variant="wheels"` each wheel moves the time as you turn it,
29
31
  * the panel stays open, and Enter or Escape closes it.
30
32
  *
33
+ * With `segmented`, the field is a row of segments in place of the text: an
34
+ * hour, a minute, and AM or PM where the clock has them, each set with digits
35
+ * or the arrow keys. Alt+Down opens the list from a segment.
36
+ *
31
37
  * @since 0.1.0
32
38
  * @status stable
33
39
  * @category forms
@@ -50,6 +56,7 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
50
56
  * @csspart field - The box that holds the text and the trigger.
51
57
  * @csspart hint - Help under the field, while nothing is wrong.
52
58
  * @csspart label - The label above the field.
59
+ * @csspart literal - The text the locale writes between two segments, such as a colon, in `segmented`.
53
60
  * @csspart picker - The time picker inside the panel.
54
61
  * @csspart picker-column - One column of the picker.
55
62
  * @csspart picker-column-empty - The text shown when the filter hides every option.
@@ -85,12 +92,17 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
85
92
  * @csspart picker-option-label - The option's label.
86
93
  * @csspart picker-option-text - The label and the caption, as one column.
87
94
  * @csspart rest - The count of times held beyond the ones shown. A `<button>` with `expandable`, and a `<span>` without it.
95
+ * @csspart segment - One part of the time, an hour, a minute, a second or AM and PM, in `segmented`.
96
+ * @csspart segment-placeholder - A segment with nothing in it yet. Applied with `segment`.
97
+ * @csspart segments - The row of segments that holds the time, in `segmented`.
88
98
  * @csspart surface - The floating panel.
89
99
  * @csspart tags - The row the times sit in.
90
100
  * @csspart time - One held time, as a tag, in `multiple`.
101
+ * @csspart time-cell - The tag's grid cell, which a tag draws only inside a tag group.
91
102
  * @csspart time-dismiss - The remove button, when `dismissible`.
92
103
  * @csspart time-dismiss-mark - The default icon on the remove button, shown when none is slotted.
93
104
  * @csspart time-label - The label, trimmed to its capitals and baseline.
105
+ * @csspart time-link - The tag's link around its label, which a tag draws only with `href`.
94
106
  * @csspart time-start - The category before the label.
95
107
  * @csspart trigger - The control that opens the list.
96
108
  * @csspart trigger-icon - The icon on the button that opens the clock.
@@ -116,6 +128,13 @@ export declare class HelixHeadlessTimeInput extends HelixHeadlessTimeInput_base
116
128
  * a typed time, which is then invalid.
117
129
  */
118
130
  disableTimes: string;
131
+ /**
132
+ * The clock the times are written on: `h12` for twelve hours with a
133
+ * meridiem, `h23` for twenty-four. Absent is the locale's own.
134
+ *
135
+ * Handed to the list. The value is `HH:mm` on twenty-four hours either way.
136
+ */
137
+ hourCycle?: HourCycle;
119
138
  /**
120
139
  * Language tag the times are written in.
121
140
  *
@@ -169,7 +188,14 @@ export declare class HelixHeadlessTimeInput extends HelixHeadlessTimeInput_base
169
188
  */
170
189
  removeLabel: string;
171
190
  /**
172
- * How far apart the offered times are, in minutes.
191
+ * Whether times carry their seconds: the value is `HH:mm:ss`, a typed time
192
+ * may give them, the field writes them, and the list's `step` counts seconds.
193
+ * See Time Picker's `seconds`.
194
+ */
195
+ seconds: boolean;
196
+ /**
197
+ * How far apart the offered times are, in minutes, or in seconds with
198
+ * `seconds`.
173
199
  */
174
200
  step: number;
175
201
  /**
@@ -192,6 +218,19 @@ export declare class HelixHeadlessTimeInput extends HelixHeadlessTimeInput_base
192
218
  unavailableMessage?: string;
193
219
  /** Every time in the value, which may hold more than one. */
194
220
  private get held();
221
+ /**
222
+ * Segments hold one time, so `range` and `multiple` keep the line of text,
223
+ * whose separators and tags are how those modes write several.
224
+ */
225
+ protected get segmentable(): boolean;
226
+ protected get segmentedKind(): 'time';
227
+ protected get segmentLocale(): string;
228
+ protected get segmentOptions(): {
229
+ hourCycle?: HourCycle | undefined;
230
+ seconds: boolean;
231
+ };
232
+ /** Whether a typed time is one this field holds, to the second where it holds seconds. */
233
+ private isTime;
195
234
  /** One time, written the way `time-style` asks for. */
196
235
  private written;
197
236
  /** What the field shows: the value while it is being edited, a reading when not. */