@fusion.dev/helix-headless 0.154.0 → 0.156.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 +3213 -179
- package/dist/accordion/item/accordion-item.d.ts +15 -0
- package/dist/accordion/item/accordion-item.js +12 -1
- package/dist/accordion/root/accordion-root.d.ts +2 -1
- package/dist/accordion/root/accordion-root.js +1 -0
- package/dist/breadcrumbs/breadcrumb/breadcrumb.d.ts +36 -3
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +42 -2
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +15 -5
- package/dist/breadcrumbs/root/breadcrumbs-root.js +29 -4
- package/dist/button-group/root/button-group-root.d.ts +2 -0
- package/dist/button-group/root/button-group-root.js +1 -0
- package/dist/canvas/node/canvas-node.js +1 -1
- package/dist/canvas/root/canvas-root.d.ts +17 -2
- package/dist/canvas/root/canvas-root.js +23 -6
- package/dist/chat/composer/chat-composer.js +1 -1
- package/dist/chat/root/chat-root.d.ts +14 -1
- package/dist/chat/root/chat-root.js +14 -4
- package/dist/color-input/root/color-input-root.d.ts +9 -3
- package/dist/color-input/root/color-input-root.js +3 -1
- package/dist/color-picker/channels.d.ts +5 -3
- package/dist/color-picker/channels.js +79 -21
- package/dist/color-picker/root/color-picker-root.d.ts +58 -5
- package/dist/color-picker/root/color-picker-root.js +75 -13
- package/dist/combobox/root/combobox-root.d.ts +10 -0
- package/dist/combobox/root/combobox-root.js +18 -3
- package/dist/command/root/command-root.d.ts +116 -1
- package/dist/command/root/command-root.js +124 -15
- package/dist/data-table/root/data-table-root.d.ts +25 -0
- package/dist/data-table/root/data-table-root.js +13 -3
- package/dist/date-input/root/date-input-root.d.ts +33 -1
- package/dist/date-input/root/date-input-root.js +9 -2
- package/dist/date-picker/root/date-picker-root.d.ts +43 -13
- package/dist/date-picker/root/date-picker-root.js +54 -31
- package/dist/element-events.generated.js +3 -1
- package/dist/graph/root/graph-root.d.ts +13 -0
- package/dist/graph/root/graph-root.js +16 -0
- package/dist/list/root/list-root.d.ts +74 -1
- package/dist/list/root/list-root.js +92 -4
- package/dist/list/selection.js +3 -3
- package/dist/map/root/map-root.d.ts +6 -0
- package/dist/map/root/map-root.js +8 -1
- package/dist/navigation/root/navigation-root.d.ts +26 -0
- package/dist/navigation/root/navigation-root.js +58 -1
- package/dist/number-input/root/number-input-root.d.ts +63 -6
- package/dist/number-input/root/number-input-root.js +96 -11
- package/dist/object-inspector/root/object-inspector-root.d.ts +36 -1
- package/dist/object-inspector/root/object-inspector-root.js +26 -2
- package/dist/option/root/option-root.d.ts +32 -0
- package/dist/option/root/option-root.js +44 -5
- package/dist/outline/root/outline-root.d.ts +6 -2
- package/dist/outline/root/outline-root.js +7 -3
- package/dist/select/root/select-root.d.ts +29 -3
- package/dist/select/root/select-root.js +34 -9
- package/dist/slider/root/slider-root.d.ts +71 -9
- package/dist/slider/root/slider-root.js +129 -42
- package/dist/speed-dial/item/speed-dial-item.d.ts +29 -1
- package/dist/speed-dial/item/speed-dial-item.js +48 -7
- package/dist/speed-dial/root/speed-dial-root.d.ts +32 -6
- package/dist/speed-dial/root/speed-dial-root.js +50 -5
- package/dist/splitter/root/splitter-root.d.ts +22 -0
- package/dist/splitter/root/splitter-root.js +36 -7
- package/dist/steps/reach.d.ts +5 -1
- package/dist/steps/reach.js +2 -2
- package/dist/steps/root/steps-root.d.ts +37 -2
- package/dist/steps/root/steps-root.js +49 -7
- package/dist/steps/step/step.d.ts +6 -0
- package/dist/steps/step/step.js +4 -0
- package/dist/table/root/table-root.d.ts +20 -0
- package/dist/table/root/table-root.js +13 -3
- package/dist/tabs/root/tabs-root.d.ts +37 -0
- package/dist/tabs/root/tabs-root.js +92 -2
- package/dist/tabs/tab/tab.d.ts +38 -2
- package/dist/tabs/tab/tab.js +45 -4
- package/dist/tag/group/tag-group.d.ts +29 -3
- package/dist/tag/group/tag-group.js +42 -11
- package/dist/time-input/root/time-input-root.d.ts +32 -1
- package/dist/time-input/root/time-input-root.js +9 -2
- package/dist/time-picker/root/time-picker-root.d.ts +63 -1
- package/dist/time-picker/root/time-picker-root.js +58 -7
- package/dist/timeline/item/timeline-item.d.ts +25 -0
- package/dist/timeline/item/timeline-item.js +27 -2
- package/dist/toggle/root/toggle-root.d.ts +2 -0
- package/dist/toggle/root/toggle-root.js +1 -1
- package/dist/tree/item/tree-item.d.ts +10 -0
- package/dist/tree/item/tree-item.js +12 -0
- package/dist/tree/root/tree-root.d.ts +40 -1
- package/dist/tree/root/tree-root.js +120 -4
- package/dist/tree/selection.d.ts +6 -0
- package/dist/tree/selection.js +11 -0
- package/dist/video/root/keys.d.ts +6 -2
- package/dist/video/root/keys.js +18 -1
- package/dist/video/root/video-root.d.ts +60 -1
- package/dist/video/root/video-root.js +70 -2
- package/dist/video-playlist/item/video-playlist-item.d.ts +15 -1
- package/dist/video-playlist/item/video-playlist-item.js +7 -0
- package/dist/video-playlist/root/video-playlist-root.d.ts +43 -4
- package/dist/video-playlist/root/video-playlist-root.js +69 -2
- package/dist/virtual-list/root/virtual-list-root.d.ts +8 -0
- package/dist/virtual-list/root/virtual-list-root.js +3 -0
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +3885 -383
- package/types/vue.d.ts +1045 -107
- package/types/words.d.ts +146 -1
|
@@ -15,7 +15,7 @@ import { areaAt, hueAt } from '../wheel.js';
|
|
|
15
15
|
import '../../button/index.js';
|
|
16
16
|
import '../../button-group/index.js';
|
|
17
17
|
import '../../slider/index.js';
|
|
18
|
-
const FORMATS = ['hex', 'rgb', 'hsl'];
|
|
18
|
+
const FORMATS = ['hex', 'rgb', 'hsl', 'oklch'];
|
|
19
19
|
const START = { alpha: 100, brightness: 100, hue: 0, saturation: 100 };
|
|
20
20
|
let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPickerFeedback(MixinControllerValue(HelixFormElement)) {
|
|
21
21
|
constructor() {
|
|
@@ -26,13 +26,16 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
26
26
|
this.blueLabel = 'Blue';
|
|
27
27
|
this.brightnessLabel = 'Brightness';
|
|
28
28
|
this.channelFields = false;
|
|
29
|
+
this.chromaLabel = 'Chroma';
|
|
29
30
|
this.colorWords = {};
|
|
30
31
|
this.copiedLabel = 'Copied';
|
|
31
32
|
this.copyLabel = 'Copy {value}';
|
|
32
33
|
this.eyedropperLabel = 'Sample a color from the screen';
|
|
33
34
|
this.formatLabel = 'Syntax: {format}. Change it.';
|
|
34
35
|
this.greenLabel = 'Green';
|
|
36
|
+
this.hint = '';
|
|
35
37
|
this.hueLabel = 'Hue';
|
|
38
|
+
this.label = '';
|
|
36
39
|
this.lightnessLabel = 'Lightness';
|
|
37
40
|
this.noEyedropper = false;
|
|
38
41
|
this.noFormat = false;
|
|
@@ -50,6 +53,11 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
50
53
|
this.valueMissingMessage = 'Choose a color.';
|
|
51
54
|
this.wheel = false;
|
|
52
55
|
this.sampling = false;
|
|
56
|
+
this.handleNamingSlot = () => {
|
|
57
|
+
this.requestUpdate();
|
|
58
|
+
};
|
|
59
|
+
this.dragging = false;
|
|
60
|
+
this.picking = false;
|
|
53
61
|
this.owned = false;
|
|
54
62
|
this.announcesInput = true;
|
|
55
63
|
this.unsettled = false;
|
|
@@ -132,6 +140,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
132
140
|
return;
|
|
133
141
|
}
|
|
134
142
|
this.dispatchEvent(new HelixSampleStartEvent());
|
|
143
|
+
this.picking = true;
|
|
135
144
|
try {
|
|
136
145
|
const { sRGBHex } = await new Dropper().open();
|
|
137
146
|
const parsed = parseColor(sRGBHex);
|
|
@@ -142,6 +151,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
142
151
|
}
|
|
143
152
|
catch {
|
|
144
153
|
}
|
|
154
|
+
this.picking = false;
|
|
145
155
|
this.dispatchEvent(new HelixSampleEndEvent());
|
|
146
156
|
};
|
|
147
157
|
this.handleGridPointer = (event) => {
|
|
@@ -150,12 +160,14 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
150
160
|
}
|
|
151
161
|
const grid = event.currentTarget;
|
|
152
162
|
if (event.type === 'pointerup' || event.type === 'pointercancel') {
|
|
163
|
+
this.dragging = false;
|
|
153
164
|
this.settle();
|
|
154
165
|
return;
|
|
155
166
|
}
|
|
156
167
|
if (event.type === 'pointerdown') {
|
|
168
|
+
this.dragging = true;
|
|
157
169
|
capturePointer(grid, event.pointerId);
|
|
158
|
-
this.partNamed('grid-saturation')?.focus();
|
|
170
|
+
this.partNamed('grid-saturation')?.focus({ preventScroll: true });
|
|
159
171
|
}
|
|
160
172
|
else if (!grid.hasPointerCapture(event.pointerId)) {
|
|
161
173
|
return;
|
|
@@ -181,7 +193,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
181
193
|
}
|
|
182
194
|
if (event.type === 'pointerdown') {
|
|
183
195
|
capturePointer(wheel, event.pointerId);
|
|
184
|
-
this.partNamed('wheel-hue')?.focus();
|
|
196
|
+
this.partNamed('wheel-hue')?.focus({ preventScroll: true });
|
|
185
197
|
}
|
|
186
198
|
else if (!wheel.hasPointerCapture(event.pointerId)) {
|
|
187
199
|
return;
|
|
@@ -232,6 +244,23 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
232
244
|
};
|
|
233
245
|
}
|
|
234
246
|
static { this.words = 'helix-color-picker'; }
|
|
247
|
+
slottedIn(name) {
|
|
248
|
+
return this.knownChildren.filter((child) => child.slot === name);
|
|
249
|
+
}
|
|
250
|
+
get named() {
|
|
251
|
+
return (this.label ||
|
|
252
|
+
this.slottedIn('label')
|
|
253
|
+
.map((child) => child.textContent ?? '')
|
|
254
|
+
.join(' ')
|
|
255
|
+
.trim());
|
|
256
|
+
}
|
|
257
|
+
get hinted() {
|
|
258
|
+
return this.hint !== '' || this.slottedIn('hint').length > 0;
|
|
259
|
+
}
|
|
260
|
+
get describedBy() {
|
|
261
|
+
const ids = [this.hinted ? 'hint' : '', this.feedback === '' ? '' : 'feedback'].filter(Boolean);
|
|
262
|
+
return ids.length > 0 ? ids.join(' ') : nothing;
|
|
263
|
+
}
|
|
235
264
|
settle() {
|
|
236
265
|
if (this.unsettled) {
|
|
237
266
|
this.unsettled = false;
|
|
@@ -299,6 +328,8 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
299
328
|
return {
|
|
300
329
|
alpha: this.opacityLabel,
|
|
301
330
|
blue: this.blueLabel,
|
|
331
|
+
brightness: this.brightnessLabel,
|
|
332
|
+
chroma: this.chromaLabel,
|
|
302
333
|
green: this.greenLabel,
|
|
303
334
|
hue: this.hueLabel,
|
|
304
335
|
lightness: this.lightnessLabel,
|
|
@@ -327,10 +358,10 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
327
358
|
<input
|
|
328
359
|
part="field-input"
|
|
329
360
|
type="number"
|
|
330
|
-
inputmode
|
|
361
|
+
inputmode=${field.step < 1 ? 'decimal' : 'numeric'}
|
|
331
362
|
min=${field.min}
|
|
332
363
|
max=${field.max}
|
|
333
|
-
step
|
|
364
|
+
step=${field.step}
|
|
334
365
|
.value=${live(String(field.value))}
|
|
335
366
|
?disabled=${this.isDisabled}
|
|
336
367
|
?readonly=${this.readOnly}
|
|
@@ -350,7 +381,8 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
350
381
|
exportparts="control: channel-control, feedback: channel-feedback, field: channel-field,
|
|
351
382
|
hint: channel-hint, label: channel-label, marker: channel-marker,
|
|
352
383
|
marker-label: channel-marker-label, markers: channel-markers, output: channel-output,
|
|
353
|
-
|
|
384
|
+
thumb: channel-thumb, thumbs: channel-thumbs, tooltip: channel-tooltip,
|
|
385
|
+
tooltips: channel-tooltips"
|
|
354
386
|
data-channel=${channel}
|
|
355
387
|
aria-invalid=${this.marked ? 'true' : nothing}
|
|
356
388
|
label=${label}
|
|
@@ -391,10 +423,18 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
391
423
|
willUpdate(changed) {
|
|
392
424
|
super.willUpdate(changed);
|
|
393
425
|
const outside = [...(this.internals.labels ?? [])];
|
|
394
|
-
|
|
426
|
+
const named = this.named;
|
|
427
|
+
hostAria(this.internals, {
|
|
428
|
+
label: outside.length > 0 ? '' : named,
|
|
429
|
+
labelledBy: outside,
|
|
430
|
+
role: outside.length > 0 || named !== '' ? 'group' : '',
|
|
431
|
+
});
|
|
395
432
|
if (!this.hydrating) {
|
|
396
433
|
this.sampling = 'EyeDropper' in globalThis;
|
|
397
434
|
}
|
|
435
|
+
this.toggleState('copied', this.copier.copied);
|
|
436
|
+
this.toggleState('dragging', this.dragging);
|
|
437
|
+
this.toggleState('sampling', this.picking);
|
|
398
438
|
}
|
|
399
439
|
renderTools() {
|
|
400
440
|
return html `<${this.tag('button-group')} part="actions" label=${this.toolsLabel}>
|
|
@@ -471,7 +511,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
471
511
|
const reversed = square('brightness');
|
|
472
512
|
const hue = hueName({ alpha: 100, brightness: 100, hue: color.hue, saturation: 100 }, this.colorWords, locale);
|
|
473
513
|
const hueSaid = (value) => new Intl.ListFormat(locale, { style: 'short', type: 'unit' }).format([String(value), hue]);
|
|
474
|
-
const owner = this.getAttribute('aria-label')?.trim();
|
|
514
|
+
const owner = this.getAttribute('aria-label')?.trim() || this.named;
|
|
475
515
|
const axisName = (channel) => (owner ? `${owner}, ${channel}` : channel);
|
|
476
516
|
const area = html `<div
|
|
477
517
|
part="grid"
|
|
@@ -488,7 +528,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
488
528
|
min="0"
|
|
489
529
|
max="100"
|
|
490
530
|
aria-label=${axisName(this.saturationLabel)}
|
|
491
|
-
aria-describedby=${this.
|
|
531
|
+
aria-describedby=${this.describedBy}
|
|
492
532
|
aria-valuetext=${both}
|
|
493
533
|
aria-invalid=${this.marked ? 'true' : nothing}
|
|
494
534
|
.value=${String(color.saturation)}
|
|
@@ -505,7 +545,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
505
545
|
tabindex="-1"
|
|
506
546
|
style="writing-mode: vertical-lr; direction: rtl"
|
|
507
547
|
aria-label=${axisName(this.brightnessLabel)}
|
|
508
|
-
aria-describedby=${this.
|
|
548
|
+
aria-describedby=${this.describedBy}
|
|
509
549
|
aria-valuetext=${reversed}
|
|
510
550
|
aria-invalid=${this.marked ? 'true' : nothing}
|
|
511
551
|
.value=${String(color.brightness)}
|
|
@@ -514,7 +554,10 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
514
554
|
@change=${() => this.settle()}
|
|
515
555
|
/>
|
|
516
556
|
</div>`;
|
|
517
|
-
return html
|
|
557
|
+
return html `<div part="label" ?hidden=${this.named === ''}>
|
|
558
|
+
<slot name="label" @slotchange=${this.handleNamingSlot}>${this.label}</slot>
|
|
559
|
+
</div>
|
|
560
|
+
${this.wheel
|
|
518
561
|
? html `<div
|
|
519
562
|
part="wheel"
|
|
520
563
|
style="--color-picker-hue: ${color.hue}"
|
|
@@ -531,7 +574,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
531
574
|
max="360"
|
|
532
575
|
dir="ltr"
|
|
533
576
|
aria-label=${axisName(this.hueLabel)}
|
|
534
|
-
aria-describedby=${this.
|
|
577
|
+
aria-describedby=${this.describedBy}
|
|
535
578
|
aria-valuetext=${hueSaid(color.hue)}
|
|
536
579
|
aria-invalid=${this.marked ? 'true' : nothing}
|
|
537
580
|
.value=${String(color.hue)}
|
|
@@ -574,7 +617,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
574
617
|
part="value"
|
|
575
618
|
type="text"
|
|
576
619
|
aria-label=${this.valueLabel}
|
|
577
|
-
aria-describedby=${this.
|
|
620
|
+
aria-describedby=${this.describedBy}
|
|
578
621
|
aria-invalid=${this.marked ? 'true' : nothing}
|
|
579
622
|
autocomplete=${this.autocomplete || nothing}
|
|
580
623
|
spellcheck="false"
|
|
@@ -591,6 +634,9 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
591
634
|
</div>
|
|
592
635
|
|
|
593
636
|
${this.presets.length === 0 ? nothing : this.renderSwatches(painted)}
|
|
637
|
+
<div part="hint" id="hint" ?hidden=${!this.hinted}>
|
|
638
|
+
<slot name="hint" @slotchange=${this.handleNamingSlot}>${this.hint}</slot>
|
|
639
|
+
</div>
|
|
594
640
|
${this.renderPickerFeedback()}`;
|
|
595
641
|
}
|
|
596
642
|
};
|
|
@@ -615,6 +661,10 @@ __decorate([
|
|
|
615
661
|
__decorate([
|
|
616
662
|
property({ attribute: 'channel-fields', type: Boolean })
|
|
617
663
|
], HelixHeadlessColorPicker.prototype, "channelFields", void 0);
|
|
664
|
+
__decorate([
|
|
665
|
+
words,
|
|
666
|
+
property({ attribute: 'chroma-label' })
|
|
667
|
+
], HelixHeadlessColorPicker.prototype, "chromaLabel", void 0);
|
|
618
668
|
__decorate([
|
|
619
669
|
property({ attribute: 'color-words', converter: wordsConverter })
|
|
620
670
|
], HelixHeadlessColorPicker.prototype, "colorWords", void 0);
|
|
@@ -641,10 +691,16 @@ __decorate([
|
|
|
641
691
|
words,
|
|
642
692
|
property({ attribute: 'green-label' })
|
|
643
693
|
], HelixHeadlessColorPicker.prototype, "greenLabel", void 0);
|
|
694
|
+
__decorate([
|
|
695
|
+
property()
|
|
696
|
+
], HelixHeadlessColorPicker.prototype, "hint", void 0);
|
|
644
697
|
__decorate([
|
|
645
698
|
words,
|
|
646
699
|
property({ attribute: 'hue-label' })
|
|
647
700
|
], HelixHeadlessColorPicker.prototype, "hueLabel", void 0);
|
|
701
|
+
__decorate([
|
|
702
|
+
property()
|
|
703
|
+
], HelixHeadlessColorPicker.prototype, "label", void 0);
|
|
648
704
|
__decorate([
|
|
649
705
|
words,
|
|
650
706
|
property({ attribute: 'lightness-label' })
|
|
@@ -711,6 +767,12 @@ __decorate([
|
|
|
711
767
|
__decorate([
|
|
712
768
|
state()
|
|
713
769
|
], HelixHeadlessColorPicker.prototype, "swatchAt", void 0);
|
|
770
|
+
__decorate([
|
|
771
|
+
state()
|
|
772
|
+
], HelixHeadlessColorPicker.prototype, "dragging", void 0);
|
|
773
|
+
__decorate([
|
|
774
|
+
state()
|
|
775
|
+
], HelixHeadlessColorPicker.prototype, "picking", void 0);
|
|
714
776
|
HelixHeadlessColorPicker = __decorate([
|
|
715
777
|
customElement('helix-headless-color-picker')
|
|
716
778
|
], HelixHeadlessColorPicker);
|
|
@@ -198,6 +198,16 @@ export declare class HelixHeadlessCombobox extends HelixHeadlessCombobox_base {
|
|
|
198
198
|
* every keystroke. See Listbox's `filter-delay`.
|
|
199
199
|
*/
|
|
200
200
|
filterDelay: number;
|
|
201
|
+
/**
|
|
202
|
+
* What the form receives for each chosen option: `key`, its `value`, or
|
|
203
|
+
* `text`, its words, as React Aria's ComboBox `formValue` offers.
|
|
204
|
+
*
|
|
205
|
+
* `text` is for a server that wants what the reader saw, such as a city's
|
|
206
|
+
* name. A value no option carries, typed with `allows-custom-value` or made
|
|
207
|
+
* with `creatable`, is sent as it is either way. Absent is `key`, and the
|
|
208
|
+
* host carries no attribute for it.
|
|
209
|
+
*/
|
|
210
|
+
formValue?: 'key' | 'text';
|
|
201
211
|
/**
|
|
202
212
|
* The list's name, read by screen readers. The list has no visible name.
|
|
203
213
|
*/
|
|
@@ -453,11 +453,23 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
|
|
|
453
453
|
return this.partNamed('control') ?? super.focusTarget;
|
|
454
454
|
}
|
|
455
455
|
sync() {
|
|
456
|
-
|
|
457
|
-
|
|
456
|
+
const values = this.multiple ? this.values : this.value === '' ? [] : [this.value];
|
|
457
|
+
const words = this.formValue === 'text'
|
|
458
|
+
? new Map(optionsAmong(this.knownChildren).map((option) => [option.value, option.text]))
|
|
459
|
+
: undefined;
|
|
460
|
+
const answers = words ? values.map((value) => words.get(value) ?? value) : values;
|
|
461
|
+
if (!this.multiple) {
|
|
462
|
+
this.internals.setFormValue(answers[0] ?? null, this.value);
|
|
463
|
+
}
|
|
464
|
+
else if (words && this.name !== '' && answers.length > 0) {
|
|
465
|
+
const data = new FormData();
|
|
466
|
+
for (const answer of answers) {
|
|
467
|
+
data.append(this.name, answer);
|
|
468
|
+
}
|
|
469
|
+
this.internals.setFormValue(data, this.value);
|
|
458
470
|
}
|
|
459
471
|
else {
|
|
460
|
-
this.internals
|
|
472
|
+
reportValues(this.internals, this.name, answers);
|
|
461
473
|
}
|
|
462
474
|
this.reportRequired(this.value === '', this.valueMissingMessage, 'control');
|
|
463
475
|
}
|
|
@@ -677,6 +689,9 @@ __decorate([
|
|
|
677
689
|
__decorate([
|
|
678
690
|
property({ attribute: 'filter-delay', type: Number })
|
|
679
691
|
], HelixHeadlessCombobox.prototype, "filterDelay", void 0);
|
|
692
|
+
__decorate([
|
|
693
|
+
property({ attribute: 'form-value' })
|
|
694
|
+
], HelixHeadlessCombobox.prototype, "formValue", void 0);
|
|
680
695
|
__decorate([
|
|
681
696
|
words,
|
|
682
697
|
property({ attribute: 'list-label' })
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HelixElement } from '@fusion.dev/helix-core';
|
|
1
|
+
import { type DataOptionItem, HelixElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
import '../../dialog/index.js';
|
|
4
4
|
import '../../listbox/index.js';
|
|
@@ -22,10 +22,51 @@ declare const HelixHeadlessCommand_base: (new (...args: any[]) => import("@fusio
|
|
|
22
22
|
* palette is open. `mod` means Command on a Mac and Control elsewhere, so you
|
|
23
23
|
* write one binding.
|
|
24
24
|
*
|
|
25
|
+
* With `inline`, the palette is drawn in the page with no dialog, as a search
|
|
26
|
+
* over a list that is always shown.
|
|
27
|
+
*
|
|
28
|
+
* **Pages.** A command can open a page of commands of its own, as a palette
|
|
29
|
+
* offers "Change theme" and then the themes. Give the option `opens` with a
|
|
30
|
+
* name, and slot the page's commands as `page:` and that name:
|
|
31
|
+
*
|
|
32
|
+
* ```html
|
|
33
|
+
* <helix-command>
|
|
34
|
+
* <helix-option value="theme" opens="theme">Change theme</helix-option>
|
|
35
|
+
* <helix-option value="dark" slot="page:theme">Dark</helix-option>
|
|
36
|
+
* <helix-option value="light" slot="page:theme">Light</helix-option>
|
|
37
|
+
* </helix-command>
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* Choosing the opener says `helix-select` with its value, and canceling it
|
|
41
|
+
* keeps the page that is shown. The list then shows the page, named by the
|
|
42
|
+
* opener's words, and Backspace in an empty filter goes back. `page` says
|
|
43
|
+
* which page is shown.
|
|
44
|
+
*
|
|
25
45
|
* The filter is cleared when the palette closes, so each opening starts from
|
|
26
46
|
* the full list. Combobox and Select do the same. As typing narrows the list, a
|
|
27
47
|
* screen reader hears how many commands are left, such as "3 commands".
|
|
28
48
|
*
|
|
49
|
+
* **Keyboard.** Focus goes to the filter field as the palette opens, and the
|
|
50
|
+
* highlight moves through the commands while you type.
|
|
51
|
+
*
|
|
52
|
+
* | Key | What it does |
|
|
53
|
+
* |---|---|
|
|
54
|
+
* | `hotkey`, Command or Control with K by default | Opens the palette from anywhere on the page, or closes it. With `inline`, puts focus in its filter field. |
|
|
55
|
+
* | Down, Up | Moves the highlight to the next or the previous command, round from the last to the first. |
|
|
56
|
+
* | Page Down, Page Up | Moves the highlight by as many commands as the list shows at once. |
|
|
57
|
+
* | Home, End, Left, Right | Move the caret in the filter field. |
|
|
58
|
+
* | Enter | Runs the highlighted command, or follows it where it is a link, and closes the palette. On a command with `opens`, shows its page. |
|
|
59
|
+
* | Command or Control with Enter | Takes the highlighted command's `alternate` destination, where it has one. |
|
|
60
|
+
* | Backspace | In an empty filter on a page, goes back to the page before. |
|
|
61
|
+
* | Escape | Clears the filter. With the filter empty, closes the palette and puts focus back where it was. |
|
|
62
|
+
* | Tab | Stays in the palette, which is modal. With `inline`, moves on through the page. |
|
|
63
|
+
*
|
|
64
|
+
* **ARIA.** The palette is a modal `dialog` named by `label`, or with
|
|
65
|
+
* `inline` no dialog at all. Inside it the filter field is a `combobox` with
|
|
66
|
+
* `aria-activedescendant` on the highlighted command, and the commands are a
|
|
67
|
+
* `listbox` of `option`s. How many commands typing left, the empty text and
|
|
68
|
+
* the loading text are said in a polite live region.
|
|
69
|
+
*
|
|
29
70
|
* @since 0.1.0
|
|
30
71
|
* @status stable
|
|
31
72
|
* @category navigation
|
|
@@ -35,7 +76,9 @@ declare const HelixHeadlessCommand_base: (new (...args: any[]) => import("@fusio
|
|
|
35
76
|
* @slot - The commands, and any groups of them.
|
|
36
77
|
* @slot empty - What the palette shows when typing matches no commands, for content richer than `empty-text`.
|
|
37
78
|
* @slot error - What the palette shows while `load-error` is set, for content richer than its text.
|
|
79
|
+
* @slot filter-icon - Replaces the magnifying glass in the filter field.
|
|
38
80
|
* @slot footer - Content under the list, such as the keys that work in the palette.
|
|
81
|
+
* @slot header - Content above the filter field, such as a title or the scope being searched. A heading here does not rename the palette, which `label` names.
|
|
39
82
|
* @slot loading - What the palette shows while the commands load, for content richer than `loading-text`.
|
|
40
83
|
* @slot no-results - What the palette shows when typing matches no commands, for content richer than `no-results-text`.
|
|
41
84
|
*
|
|
@@ -67,6 +110,10 @@ declare const HelixHeadlessCommand_base: (new (...args: any[]) => import("@fusio
|
|
|
67
110
|
* @csspart listbox-search - The region that holds the filter field.
|
|
68
111
|
* @csspart listbox-search-field - The filter field.
|
|
69
112
|
*
|
|
113
|
+
* @cssstate empty - The list shows no commands: there are none, or typing hid every one.
|
|
114
|
+
* @cssstate error - While `load-error` is set.
|
|
115
|
+
* @cssstate loading - While `loading` is set.
|
|
116
|
+
* @cssstate no-results - Typing hid every one of the commands, where there are some.
|
|
70
117
|
* @cssstate open - While the palette is open.
|
|
71
118
|
*/
|
|
72
119
|
export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
|
|
@@ -95,6 +142,26 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
|
|
|
95
142
|
* with: one key, said once.
|
|
96
143
|
*/
|
|
97
144
|
hotkey: string;
|
|
145
|
+
/**
|
|
146
|
+
* Draws the palette in the page, where it stands, with no dialog: a search
|
|
147
|
+
* over a list of commands, as React Aria's Autocomplete is drawn.
|
|
148
|
+
*
|
|
149
|
+
* The list is always shown, and `hotkey` puts focus in its filter field.
|
|
150
|
+
* Choosing a command says `helix-select` and leaves the list where it is,
|
|
151
|
+
* and `open`, `toggle` and the dialog's parts do nothing.
|
|
152
|
+
*/
|
|
153
|
+
inline: boolean;
|
|
154
|
+
/**
|
|
155
|
+
* The commands as data, for a palette too long to draw whole: each a value,
|
|
156
|
+
* which is also its words, or a record with a `value`, a `label` and
|
|
157
|
+
* `disabled`. Handed to the list, which draws only the commands in sight and
|
|
158
|
+
* reads no children while it is set. See Listbox's `items`.
|
|
159
|
+
*
|
|
160
|
+
* Choosing one says `helix-select` with its value, as a child option does.
|
|
161
|
+
* A command that is a link, or that has an `alternate`, is an option you
|
|
162
|
+
* write as a child.
|
|
163
|
+
*/
|
|
164
|
+
items: readonly DataOptionItem[] | undefined;
|
|
98
165
|
/**
|
|
99
166
|
* Accessible name for the overlay, which has no visible heading.
|
|
100
167
|
*/
|
|
@@ -122,6 +189,19 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
|
|
|
122
189
|
* some. Absent, `empty-text` shows. See Listbox's `no-results-text`.
|
|
123
190
|
*/
|
|
124
191
|
noResultsText?: string;
|
|
192
|
+
/**
|
|
193
|
+
* The page of commands shown, by name: empty for the commands you write
|
|
194
|
+
* with no `slot`, or a name for the commands slotted as `page:` and the
|
|
195
|
+
* name, such as `slot="page:theme"`.
|
|
196
|
+
*
|
|
197
|
+
* An option with `opens` set to a name goes to that page when it is chosen,
|
|
198
|
+
* in place of running, and Backspace in an empty filter goes back to the
|
|
199
|
+
* page before. Closing the palette goes back to the first page. Set it to
|
|
200
|
+
* open the palette on a page of your choosing.
|
|
201
|
+
*/
|
|
202
|
+
page: string;
|
|
203
|
+
/** The pages gone through to reach this one, which Backspace walks back. */
|
|
204
|
+
private trail;
|
|
125
205
|
/**
|
|
126
206
|
* The text shown in the filter field before anything is typed.
|
|
127
207
|
*/
|
|
@@ -169,6 +249,8 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
|
|
|
169
249
|
* palette the reader never sees.
|
|
170
250
|
*/
|
|
171
251
|
private readonly handleHotkey;
|
|
252
|
+
/** The list's filter field, where a reader types. */
|
|
253
|
+
private get searchField();
|
|
172
254
|
/**
|
|
173
255
|
* Takes what the list announced and says it under this element's name.
|
|
174
256
|
*
|
|
@@ -183,6 +265,18 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
|
|
|
183
265
|
* could not be run again: Enter did nothing and the palette stayed open.
|
|
184
266
|
*/
|
|
185
267
|
private readonly handleChange;
|
|
268
|
+
/**
|
|
269
|
+
* Shows a page of commands, with the trail that leads back from it. The
|
|
270
|
+
* filter starts empty, as it does on opening, and the field keeps focus.
|
|
271
|
+
*/
|
|
272
|
+
private goTo;
|
|
273
|
+
/** Backspace in an empty filter, on a page, goes back to the page before. */
|
|
274
|
+
private readonly handleBack;
|
|
275
|
+
/**
|
|
276
|
+
* The list's name: the palette's, or on a page, the words of the command
|
|
277
|
+
* that opens it.
|
|
278
|
+
*/
|
|
279
|
+
private get listName();
|
|
186
280
|
/**
|
|
187
281
|
* The row under the keyboard, read from the `active` property the listbox
|
|
188
282
|
* writes on each option.
|
|
@@ -217,6 +311,20 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
|
|
|
217
311
|
disconnectedCallback(): void;
|
|
218
312
|
protected willUpdate(changed: PropertyValues): void;
|
|
219
313
|
protected firstUpdated(changed: PropertyValues): void;
|
|
314
|
+
/**
|
|
315
|
+
* The list's loading, error and empty states on the host too, so a page
|
|
316
|
+
* styles the whole palette from them, as Combobox does. Read once the list
|
|
317
|
+
* has drawn its filter, since `hidden` is what the filter writes onto a
|
|
318
|
+
* command.
|
|
319
|
+
*/
|
|
320
|
+
private markStatus;
|
|
321
|
+
/**
|
|
322
|
+
* After the list has filtered on what was typed. The event comes before the
|
|
323
|
+
* filter is applied, so the list's update is waited for a turn later.
|
|
324
|
+
*/
|
|
325
|
+
private readonly handleFilter;
|
|
326
|
+
/** Whether a child fills the named slot, so it is handed on to the dialog or the list. */
|
|
327
|
+
private fills;
|
|
220
328
|
protected updated(changed: PropertyValues): void;
|
|
221
329
|
/**
|
|
222
330
|
* The surface the palette opens in, behind a seam the styled tier can move.
|
|
@@ -229,6 +337,13 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
|
|
|
229
337
|
* from the same template.
|
|
230
338
|
*/
|
|
231
339
|
protected renderDialog(): TemplateResult;
|
|
340
|
+
/**
|
|
341
|
+
* The filterable list of commands, which the dialog holds, or the page with
|
|
342
|
+
* `inline`, behind a seam the styled tier can move.
|
|
343
|
+
*/
|
|
344
|
+
protected renderListbox(): TemplateResult;
|
|
345
|
+
/** The row under the list, in the dialog's footer or, `inline`, under the list itself. */
|
|
346
|
+
private renderFooter;
|
|
232
347
|
protected render(): TemplateResult;
|
|
233
348
|
}
|
|
234
349
|
declare global {
|