@fusion.dev/helix-headless 0.2.0 → 0.3.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.
- package/custom-elements.json +234 -234
- package/dist/accordion/item/accordion-item.js +0 -108
- package/dist/accordion/root/accordion-root.js +0 -33
- package/dist/announcement/root/announcement-root.js +1 -76
- package/dist/app-header/root/app-header-root.js +0 -84
- package/dist/avatar/group/avatar-group.js +0 -77
- package/dist/avatar/root/avatar-root.js +0 -72
- package/dist/badge/root/badge-root.js +0 -67
- package/dist/bar-chart/root/bar-chart-root.js +3 -263
- package/dist/blockquote/root/blockquote-root.js +0 -46
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +0 -72
- package/dist/breadcrumbs/root/breadcrumbs-root.js +0 -52
- package/dist/button/root/button-root.js +0 -215
- package/dist/button-group/root/button-group-root.js +0 -30
- package/dist/callout/root/callout-root.js +0 -52
- package/dist/card/root/card-root.js +0 -41
- package/dist/carousel/root/carousel-root.d.ts +2 -2
- package/dist/carousel/root/carousel-root.js +2 -362
- package/dist/chat/composer/chat-composer.js +0 -131
- package/dist/chat/message/chat-message.js +0 -137
- package/dist/chat/root/chat-root.js +0 -193
- package/dist/checkbox/root/checkbox-root.js +0 -113
- package/dist/checkbox-group/root/checkbox-group-root.js +1 -157
- package/dist/code/root/code-root.js +0 -26
- package/dist/code-block/root/code-block-root.js +0 -100
- package/dist/color-input/root/color-input-root.js +0 -217
- package/dist/color-picker/color.js +0 -69
- package/dist/color-picker/root/color-picker-root.js +0 -272
- package/dist/combobox/root/combobox-root.js +0 -428
- package/dist/command/root/command-root.js +0 -177
- package/dist/copy-button/root/copy-button-root.js +0 -134
- package/dist/data-table/root/data-table-root.js +0 -336
- package/dist/data-table/root/order.js +0 -100
- package/dist/date-input/root/date-input-root.js +1 -398
- package/dist/date-picker/root/date-picker-root.js +0 -358
- package/dist/dialog/root/dialog-root.js +0 -189
- package/dist/divider/root/divider-root.js +0 -71
- package/dist/donut-chart/root/donut-chart-root.js +0 -214
- package/dist/drawer/root/drawer-root.js +0 -116
- package/dist/drilldown/item/drilldown-item.js +0 -82
- package/dist/drilldown/root/drilldown-root.js +0 -91
- package/dist/element-events.generated.js +0 -5
- package/dist/empty/root/empty-root.js +0 -35
- package/dist/file-input/root/file-input-root.js +0 -232
- package/dist/format-date/root/format-date-root.js +0 -95
- package/dist/heatmap/root/buckets.js +0 -57
- package/dist/heatmap/root/heatmap-root.js +0 -313
- package/dist/icon/root/icon-root.js +0 -48
- package/dist/icon-button/root/icon-button-root.js +0 -30
- package/dist/image/root/image-root.js +0 -174
- package/dist/index.js +0 -9
- package/dist/input/root/input-root.js +0 -228
- package/dist/kbd/root/kbd-root.js +0 -117
- package/dist/legend/root/legend-root.js +0 -73
- package/dist/line-chart/root/line-chart-root.js +0 -172
- package/dist/list/item/list-item.js +0 -92
- package/dist/list/root/list-root.js +0 -26
- package/dist/listbox/root/listbox-root.js +2 -429
- package/dist/loader/root/loader-root.js +0 -40
- package/dist/megamenu/root/megamenu-root.js +0 -284
- package/dist/menu/item/menu-item.js +1 -221
- package/dist/menu/root/menu-root.js +1 -171
- package/dist/meter/root/meter-root.js +1 -152
- package/dist/navigation/root/navigation-root.js +0 -56
- package/dist/notifications/notification/notification.js +0 -159
- package/dist/notifications/root/notifications-root.js +0 -148
- package/dist/number-input/root/number-input-root.js +1 -263
- package/dist/option/group/option-group.js +0 -26
- package/dist/option/root/option-root.js +0 -157
- package/dist/outline/root/outline-root.js +0 -292
- package/dist/pagination/root/pagination-root.js +0 -361
- package/dist/pagination/size/pagination-size.js +0 -104
- package/dist/pagination/summary/pagination-summary.js +0 -90
- package/dist/pin-input/root/pin-input-root.js +0 -276
- package/dist/popover/root/popover-root.js +0 -103
- package/dist/progress/root/progress-root.js +1 -133
- package/dist/qr-code/root/qr-code-root.js +0 -96
- package/dist/quote/root/quote-root.js +0 -25
- package/dist/radio/group/radio-group.js +0 -81
- package/dist/radio/root/radio-root.js +0 -85
- package/dist/rating/root/rating-root.js +0 -220
- package/dist/scroll-area/root/scroll-area-root.js +0 -100
- package/dist/select/root/select-root.js +2 -218
- package/dist/skeleton/root/skeleton-root.js +0 -20
- package/dist/slider/root/slider-root.js +1 -267
- package/dist/sparkline/root/sparkline-root.js +3 -164
- package/dist/speed-dial/item/speed-dial-item.js +0 -52
- package/dist/speed-dial/root/speed-dial-root.js +1 -116
- package/dist/splitter/root/splitter-root.js +0 -489
- package/dist/stat/group/stat-group.js +0 -18
- package/dist/stat/root/stat-root.js +0 -23
- package/dist/steps/root/steps-root.js +0 -62
- package/dist/steps/step/step.js +0 -131
- package/dist/switch/root/switch-root.js +0 -80
- package/dist/table/cell/table-cell.js +0 -23
- package/dist/table/column/table-column.js +0 -158
- package/dist/table/root/table-root.js +0 -82
- package/dist/table/row/table-row.js +0 -21
- package/dist/tabs/panel/tab-panel.js +0 -49
- package/dist/tabs/root/tabs-root.js +0 -98
- package/dist/tabs/tab/tab.js +0 -59
- package/dist/tag/root/tag-root.js +0 -31
- package/dist/textarea/root/textarea-root.js +0 -162
- package/dist/time-input/root/time-input-root.js +0 -283
- package/dist/time-picker/root/time-picker-root.js +0 -326
- package/dist/timeline/item/timeline-item.js +0 -66
- package/dist/timeline/root/timeline-root.js +0 -41
- package/dist/toast/item/toast-item.js +0 -165
- package/dist/toast/root/toast-root.js +0 -51
- package/dist/toggle/group/toggle-group.js +0 -150
- package/dist/toggle/root/toggle-root.js +0 -78
- package/dist/toolbar/root/toolbar-root.js +0 -116
- package/dist/tooltip/root/tooltip-root.js +0 -427
- package/dist/tour/root/tour-root.js +0 -130
- package/dist/tour/stop/tour-stop.js +1 -127
- package/dist/tree/item/tree-item.js +0 -198
- package/dist/tree/root/tree-root.js +0 -97
- package/dist/trend/root/trend-root.js +0 -53
- package/dist/video/root/video-root.d.ts +8 -12
- package/dist/video/root/video-root.js +5 -756
- package/dist/video-playlist/item/video-playlist-item.js +1 -90
- package/dist/video-playlist/menu/video-playlist-menu.js +1 -132
- package/dist/video-playlist/root/video-playlist-root.js +0 -113
- package/dist/virtual-list/root/virtual-list-root.js +0 -105
- package/jsx.d.ts +1408 -2576
- package/package.json +6 -6
- package/vue.d.ts +1 -1
|
@@ -7,122 +7,33 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { AriaForwardController, customElement, HelixFormElement, holdCaret, MixinControllerValue, MixinField, restoreValue, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
-
/**
|
|
11
|
-
* @summary Several lines of text a reader types into.
|
|
12
|
-
*
|
|
13
|
-
* @description
|
|
14
|
-
* A real `<textarea>`, so the caret, the selection, spellcheck, the resize
|
|
15
|
-
* handle and the keyboard a phone chooses are all the platform's, and it
|
|
16
|
-
* serializes into the server's markup so the field is usable before any script
|
|
17
|
-
* loads.
|
|
18
|
-
*
|
|
19
|
-
* **Not an Input with a taller box.** The difference is the Enter key: in a
|
|
20
|
-
* single-line field it submits the form, and here it inserts a line. That is a
|
|
21
|
-
* behavioral difference the platform owns and cannot be styled into existence,
|
|
22
|
-
* which is why this is its own element rather than `Input` with a property.
|
|
23
|
-
*
|
|
24
|
-
* `rows` sets the height it starts at, and `auto-grow` lets it follow its own
|
|
25
|
-
* content. They are not alternatives: `rows` is where an empty field begins and
|
|
26
|
-
* `auto-grow` is what happens after, so a field that grows still has to start
|
|
27
|
-
* somewhere.
|
|
28
|
-
*
|
|
29
|
-
* @since 0.1.0
|
|
30
|
-
* @status stable
|
|
31
|
-
* @category forms
|
|
32
|
-
* @aliases Multiline, TextArea
|
|
33
|
-
* @documentation https://helix.fusion.dev/components/textarea
|
|
34
|
-
*
|
|
35
|
-
* @event {Event} change - Relayed from the textarea once the reader has finished.
|
|
36
|
-
* @event {HelixBeforeChangeEvent} helix-before-change - Fired as the text changes, and cancelable.
|
|
37
|
-
* @event {Event} input - Announced once the value has moved.
|
|
38
|
-
*
|
|
39
|
-
* @csspart control - The textarea itself.
|
|
40
|
-
* @csspart feedback - What is wrong with it.
|
|
41
|
-
* @csspart field - The box holding the control.
|
|
42
|
-
* @csspart hint - Help under the field, while nothing is wrong.
|
|
43
|
-
* @csspart label - The question, over the field.
|
|
44
|
-
*/
|
|
45
10
|
let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerValue(MixinField(HelixFormElement)) {
|
|
46
11
|
constructor() {
|
|
47
12
|
super(...arguments);
|
|
48
|
-
/* A consumer's `aria-describedby` names ids in their own tree and the control
|
|
49
|
-
is in this shadow root, so the reference has to be carried down as an
|
|
50
|
-
element rather than copied as an id. See `AriaForwardController`: measured
|
|
51
|
-
in Chrome's own tree, the host held the description and the control the
|
|
52
|
-
reader is actually on was exposed without it. */
|
|
53
13
|
this.aria = new AriaForwardController(this, {
|
|
54
14
|
target: () => this.renderRoot?.querySelector('[part="control"]') ?? null,
|
|
55
15
|
});
|
|
56
|
-
/** Typed or dragged, so every edit is announced. See `announcesInput`. */
|
|
57
16
|
this.announcesInput = true;
|
|
58
|
-
/**
|
|
59
|
-
* What the browser may autofill here, as one of the platform's own tokens.
|
|
60
|
-
*
|
|
61
|
-
* Empty leaves the attribute off, which is the browser's default. Set it to
|
|
62
|
-
* a token like `email` or `bday` to ask for autofill, or to `off` to refuse.
|
|
63
|
-
*/
|
|
64
17
|
this.autocomplete = '';
|
|
65
|
-
/**
|
|
66
|
-
* Whether the box follows its own content rather than scrolling.
|
|
67
|
-
*/
|
|
68
18
|
this.autoGrow = false;
|
|
69
|
-
/**
|
|
70
|
-
* The name a second entry carries, holding which way the text runs.
|
|
71
|
-
*
|
|
72
|
-
* **Submitted through `setFormValue`, because the inner control's own
|
|
73
|
-
* `dirname` cannot reach the form.** This host is form-associated and reports
|
|
74
|
-
* its value itself, so the `<textarea>` inside the shadow root participates in
|
|
75
|
-
* no form at all and forwarding the attribute would have looked right and
|
|
76
|
-
* submitted nothing. `ElementInternals` takes a `FormData`, which is how one
|
|
77
|
-
* element sends two entries, and that is what this does.
|
|
78
|
-
*/
|
|
79
19
|
this.dirName = '';
|
|
80
|
-
/**
|
|
81
|
-
* Shown while the field is empty.
|
|
82
|
-
*
|
|
83
|
-
* Not a label: it goes when typing starts.
|
|
84
|
-
*/
|
|
85
20
|
this.placeholder = '';
|
|
86
|
-
/**
|
|
87
|
-
* Whether the field refuses input while still submitting its value.
|
|
88
|
-
*/
|
|
89
21
|
this.readOnly = false;
|
|
90
|
-
/**
|
|
91
|
-
* Every keystroke, cancelable, and put back where it is refused.
|
|
92
|
-
*
|
|
93
|
-
* The control has already taken the character by the time this runs, so
|
|
94
|
-
* refusing has to restore it, or what is on screen and what the form would
|
|
95
|
-
* submit disagree.
|
|
96
|
-
*/
|
|
97
22
|
this.handleInput = (event) => {
|
|
98
|
-
// Stopped for the reason `Input.handleInput` gives: the inner control's own
|
|
99
|
-
// `input` is composed and would reach a consumer beside this element's.
|
|
100
23
|
event.stopPropagation();
|
|
101
24
|
const control = event.target;
|
|
102
25
|
const next = control.value;
|
|
103
|
-
/* Through the mixin, which announces and then applies only if the value is
|
|
104
|
-
the element's to move. The native control has already changed either way,
|
|
105
|
-
so wherever the answer does not follow it has to be put back. */
|
|
106
26
|
this.requestValue(next);
|
|
107
27
|
restoreValue(control, this.value);
|
|
108
28
|
this.grow();
|
|
109
29
|
};
|
|
110
|
-
/** Relayed, because `change` does not cross a shadow boundary on its own. */
|
|
111
30
|
this.handleChange = (event) => {
|
|
112
31
|
event.stopPropagation();
|
|
113
32
|
this.dispatchEvent(new Event('change', { bubbles: true, composed: false }));
|
|
114
33
|
};
|
|
115
|
-
/**
|
|
116
|
-
* How many lines the box is before anything is typed.
|
|
117
|
-
*/
|
|
118
34
|
this.rows = 3;
|
|
119
|
-
/**
|
|
120
|
-
* How the browser wraps the text, and whether the breaks are submitted with
|
|
121
|
-
* it.
|
|
122
|
-
*/
|
|
123
35
|
this.wrap = 'soft';
|
|
124
36
|
}
|
|
125
|
-
/** Focus is delegated to the control, so the host is never the target. */
|
|
126
37
|
static { this.shadowRootOptions = {
|
|
127
38
|
...HelixFormElement.shadowRootOptions,
|
|
128
39
|
delegatesFocus: true,
|
|
@@ -130,49 +41,18 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
|
|
|
130
41
|
get control() {
|
|
131
42
|
return this.renderRoot.querySelector('[part="control"]');
|
|
132
43
|
}
|
|
133
|
-
/**
|
|
134
|
-
* Follows the content, by measuring rather than by counting.
|
|
135
|
-
*
|
|
136
|
-
* `scrollHeight` is what the text actually needs, which no arithmetic over
|
|
137
|
-
* line count and line height gets right: a wrapped line, a pasted paragraph
|
|
138
|
-
* and a font that has not loaded yet all break the arithmetic and none of
|
|
139
|
-
* them break the measurement.
|
|
140
|
-
*
|
|
141
|
-
* Reset to `auto` first, because `scrollHeight` of an element already sized to
|
|
142
|
-
* its content is that size, so without the reset the box can only ever grow.
|
|
143
|
-
*/
|
|
144
44
|
grow() {
|
|
145
45
|
const control = this.control;
|
|
146
46
|
if (!this.autoGrow || !control) {
|
|
147
47
|
return;
|
|
148
48
|
}
|
|
149
49
|
control.style.blockSize = 'auto';
|
|
150
|
-
/* Zero is not a height, it is the absence of a layout box.
|
|
151
|
-
*
|
|
152
|
-
* An element with `display: none` anywhere above it reports `scrollHeight`
|
|
153
|
-
* as zero. Written back as a fixed `block-size` it pins the field there,
|
|
154
|
-
* since every later call then measures a control at zero and measures zero
|
|
155
|
-
* again: a textarea inside a tab panel, an accordion, or anything else that
|
|
156
|
-
* renders shut and opens later comes out as a hairline with the text hidden
|
|
157
|
-
* behind it. `tabs-root` refuses zero for the same reason.
|
|
158
|
-
*
|
|
159
|
-
* The reset to `auto` above has already been written by this point, which
|
|
160
|
-
* is the right state to leave it in: an ungrown auto-grow field is the
|
|
161
|
-
* browser's own height, not a stale number from the last time it had one. */
|
|
162
50
|
const next = control.scrollHeight;
|
|
163
51
|
if (next === 0) {
|
|
164
52
|
return;
|
|
165
53
|
}
|
|
166
54
|
control.style.blockSize = `${next}px`;
|
|
167
55
|
}
|
|
168
|
-
/**
|
|
169
|
-
* What the form receives, which is two entries where `dirName` asks for it.
|
|
170
|
-
*
|
|
171
|
-
* A plain string otherwise, because that is the common case and a `FormData`
|
|
172
|
-
* of one entry says the same thing at more cost. The direction is read off
|
|
173
|
-
* the control rather than assumed, so a field a consumer set `dir="rtl"` on,
|
|
174
|
-
* or one inside an RTL document, submits what the reader actually saw.
|
|
175
|
-
*/
|
|
176
56
|
formValue() {
|
|
177
57
|
const control = this.control;
|
|
178
58
|
if (!this.dirName || !this.name || !control) {
|
|
@@ -183,19 +63,6 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
|
|
|
183
63
|
data.append(this.dirName, getComputedStyle(control).direction === 'rtl' ? 'rtl' : 'ltr');
|
|
184
64
|
return data;
|
|
185
65
|
}
|
|
186
|
-
/**
|
|
187
|
-
* The caret and the selection, under the platform's own names.
|
|
188
|
-
*
|
|
189
|
-
* **The whole reason this renders a real `<textarea>` is the caret**, and the
|
|
190
|
-
* control is inside this shadow root, so `querySelector` does not find it and
|
|
191
|
-
* a consumer has no other way to ask where the selection is, let alone move
|
|
192
|
-
* it. A field that cannot be scripted at the caret cannot do an
|
|
193
|
-
* insert-at-cursor toolbar, which is the first thing anybody builds on a
|
|
194
|
-
* textarea.
|
|
195
|
-
*
|
|
196
|
-
* Written through to the control, and answering zero before there is one,
|
|
197
|
-
* which is where an empty field's caret would be anyway.
|
|
198
|
-
*/
|
|
199
66
|
get selectionDirection() {
|
|
200
67
|
return this.control?.selectionDirection ?? 'none';
|
|
201
68
|
}
|
|
@@ -205,7 +72,6 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
|
|
|
205
72
|
control.selectionDirection = direction;
|
|
206
73
|
}
|
|
207
74
|
}
|
|
208
|
-
/** Where the selection ends, as an offset into the value. */
|
|
209
75
|
get selectionEnd() {
|
|
210
76
|
return this.control?.selectionEnd ?? 0;
|
|
211
77
|
}
|
|
@@ -215,7 +81,6 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
|
|
|
215
81
|
control.selectionEnd = at;
|
|
216
82
|
}
|
|
217
83
|
}
|
|
218
|
-
/** Where the selection starts, as an offset into the value. */
|
|
219
84
|
get selectionStart() {
|
|
220
85
|
return this.control?.selectionStart ?? 0;
|
|
221
86
|
}
|
|
@@ -225,49 +90,27 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
|
|
|
225
90
|
control.selectionStart = at;
|
|
226
91
|
}
|
|
227
92
|
}
|
|
228
|
-
/**
|
|
229
|
-
* Selects a range, which is the one operation the three accessors above
|
|
230
|
-
* cannot express between them.
|
|
231
|
-
*
|
|
232
|
-
* Setting `selectionStart` past the current `selectionEnd` drags the end
|
|
233
|
-
* along, so the two writes a consumer would make in sequence do not compose
|
|
234
|
-
* into the range they asked for. The platform has this method for that reason
|
|
235
|
-
* and so does this.
|
|
236
|
-
*/
|
|
237
93
|
setSelectionRange(start, end, direction) {
|
|
238
94
|
this.control?.setSelectionRange(start, end, direction);
|
|
239
95
|
}
|
|
240
|
-
/** How many characters the value holds. */
|
|
241
96
|
get textLength() {
|
|
242
97
|
return this.value.length;
|
|
243
98
|
}
|
|
244
|
-
/** What kind of control this is, which for a textarea is always the one word. */
|
|
245
99
|
get type() {
|
|
246
100
|
return 'textarea';
|
|
247
101
|
}
|
|
248
|
-
/** Puts the caret in the field, the way a label pointing at one would. */
|
|
249
102
|
focus(options) {
|
|
250
103
|
this.control?.focus(options);
|
|
251
104
|
}
|
|
252
|
-
/** Reports the value and the validity the host stands behind. */
|
|
253
105
|
sync() {
|
|
254
106
|
this.internals.setFormValue(this.formValue());
|
|
255
107
|
const control = this.control;
|
|
256
108
|
if (!control) {
|
|
257
109
|
return;
|
|
258
110
|
}
|
|
259
|
-
// The platform's verdict, copied rather than recomputed, with the control as
|
|
260
|
-
// the anchor so a validity bubble points at the text and not at the host.
|
|
261
111
|
this.internals.setValidity(control.validity, control.validationMessage, control);
|
|
262
112
|
this.refreshFeedback();
|
|
263
113
|
}
|
|
264
|
-
/* Rebuilt on reconnection, because nothing else does it.
|
|
265
|
-
*
|
|
266
|
-
* `firstUpdated` runs once for the life of the element and
|
|
267
|
-
* `disconnectedCallback` runs every time it moves, so without this a
|
|
268
|
-
* framework reordering a list leaves the observer gone with nothing to
|
|
269
|
-
* rebuild it. Guarded on `hasUpdated`, because the first connection happens
|
|
270
|
-
* before the first render and there is nothing to watch yet. */
|
|
271
114
|
connectedCallback() {
|
|
272
115
|
super.connectedCallback();
|
|
273
116
|
if (this.hasUpdated) {
|
|
@@ -283,7 +126,6 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
|
|
|
283
126
|
super.firstUpdated(changed);
|
|
284
127
|
this.watchControl();
|
|
285
128
|
}
|
|
286
|
-
/** Watches the control so the box grows with what is typed into it. */
|
|
287
129
|
watchControl() {
|
|
288
130
|
const control = this.control;
|
|
289
131
|
if (!control) {
|
|
@@ -295,10 +137,6 @@ let HelixHeadlessTextarea = class HelixHeadlessTextarea extends MixinControllerV
|
|
|
295
137
|
}
|
|
296
138
|
willUpdate(changed) {
|
|
297
139
|
super.willUpdate(changed);
|
|
298
|
-
/* Never before the first update, which is the one the server does: there is
|
|
299
|
-
no render root to query there, and `querySelector` is not merely empty on
|
|
300
|
-
Lit's element shim, it is undefined. There is also no caret to keep before
|
|
301
|
-
anything has rendered. */
|
|
302
140
|
if (!this.hasUpdated) {
|
|
303
141
|
return;
|
|
304
142
|
}
|