@fusion.dev/helix-headless 0.170.0 → 0.172.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 +1045 -154
- package/dist/chat/composer/chat-composer.d.ts +30 -2
- package/dist/chat/composer/chat-composer.js +29 -4
- package/dist/chat/root/chat-root.d.ts +73 -7
- package/dist/chat/root/chat-root.js +90 -5
- package/dist/code-block/root/code-block-root.d.ts +20 -2
- package/dist/code-block/root/code-block-root.js +29 -8
- package/dist/color-input/root/color-input-root.d.ts +15 -1
- package/dist/color-input/root/color-input-root.js +19 -1
- package/dist/color-picker/root/color-picker-root.d.ts +54 -7
- package/dist/color-picker/root/color-picker-root.js +62 -1
- package/dist/combobox/root/combobox-root.d.ts +16 -6
- package/dist/combobox/root/combobox-root.js +9 -2
- package/dist/command/root/command-root.d.ts +16 -1
- package/dist/command/root/command-root.js +8 -0
- package/dist/data-table/root/data-table-root.d.ts +5 -1
- package/dist/data-table/root/data-table-root.js +1 -0
- package/dist/dialog/root/dialog-root.js +1 -0
- package/dist/drawer/root/drawer-root.d.ts +4 -0
- package/dist/drawer/root/drawer-root.js +1 -0
- package/dist/element-events.generated.js +1 -0
- package/dist/filter-input/chip/filter-chip.d.ts +13 -3
- package/dist/filter-input/chip/filter-chip.js +5 -0
- package/dist/filter-input/menu/filter-menu.js +0 -1
- package/dist/filter-input/root/filter-input-root.d.ts +71 -4
- package/dist/filter-input/root/filter-input-root.js +87 -2
- package/dist/format-date/root/format-date-root.d.ts +3 -1
- package/dist/input/root/input-root.d.ts +6 -0
- package/dist/input/root/input-root.js +13 -0
- package/dist/lightbox/root/lightbox-root.js +1 -0
- package/dist/listbox/root/listbox-root.d.ts +8 -1
- package/dist/listbox/root/listbox-root.js +9 -3
- package/dist/menu/item/menu-item.d.ts +2 -0
- package/dist/menu/item/menu-item.js +2 -0
- package/dist/menu/root/menu-root.d.ts +73 -12
- package/dist/menu/root/menu-root.js +103 -7
- package/dist/number-input/root/number-input-root.d.ts +16 -6
- package/dist/number-input/root/number-input-root.js +15 -4
- package/dist/popover/root/popover-root.d.ts +59 -6
- package/dist/popover/root/popover-root.js +51 -3
- package/dist/select/root/select-root.d.ts +2 -2
- package/dist/select/root/select-root.js +4 -2
- package/dist/steps/root/steps-root.d.ts +32 -8
- package/dist/steps/root/steps-root.js +70 -9
- package/dist/steps/step/step.d.ts +9 -1
- package/dist/steps/step/step.js +5 -0
- package/dist/textarea/root/textarea-root.d.ts +8 -0
- package/dist/textarea/root/textarea-root.js +16 -0
- package/dist/video-playlist/root/video-playlist-root.d.ts +19 -1
- package/dist/video-playlist/root/video-playlist-root.js +14 -3
- package/dist/virtual-list/root/virtual-list-root.d.ts +8 -0
- package/dist/virtual-list/root/virtual-list-root.js +7 -2
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +800 -144
- package/types/vue.d.ts +165 -31
- package/types/words.d.ts +20 -2
|
@@ -31,7 +31,8 @@ declare const HelixHeadlessColorInput_base: (new (...args: any[]) => import("@fu
|
|
|
31
31
|
*
|
|
32
32
|
* The trigger and ArrowDown open the panel with focus in the square. Tab moves
|
|
33
33
|
* between the panel's controls without leaving it, and Escape closes it and
|
|
34
|
-
* returns focus to the
|
|
34
|
+
* returns focus to the control that opened it: the trigger after a press, and
|
|
35
|
+
* the field after ArrowDown.
|
|
35
36
|
*
|
|
36
37
|
* The component sets `--color-input-swatch`, so do not set it yourself. It
|
|
37
38
|
* holds the resolved color, so the styled tier can paint the swatch without
|
|
@@ -305,6 +306,19 @@ export declare class HelixHeadlessColorInput extends HelixHeadlessColorInput_bas
|
|
|
305
306
|
*/
|
|
306
307
|
protected sync(): void;
|
|
307
308
|
protected updated(changed: PropertyValues): void;
|
|
309
|
+
/** Whether the trigger's press opened the panel that is open now. */
|
|
310
|
+
private pressedOpen;
|
|
311
|
+
/**
|
|
312
|
+
* The trigger's press, which notes that it opened the panel, so Escape hands
|
|
313
|
+
* focus back to the trigger.
|
|
314
|
+
*/
|
|
315
|
+
private readonly handlePress;
|
|
316
|
+
/**
|
|
317
|
+
* Hands focus back to the control that opened the panel: the trigger after
|
|
318
|
+
* its press, which is the APG date picker dialog's rule, and the text after
|
|
319
|
+
* ArrowDown from it.
|
|
320
|
+
*/
|
|
321
|
+
protected returnFocus(): void;
|
|
308
322
|
/**
|
|
309
323
|
* The picker the field opens, behind a seam the styled tier can move.
|
|
310
324
|
*
|
|
@@ -55,6 +55,12 @@ let HelixHeadlessColorInput = class HelixHeadlessColorInput extends MixinPickerF
|
|
|
55
55
|
this.handleSampleEnd = () => {
|
|
56
56
|
this.requestOpen(true);
|
|
57
57
|
};
|
|
58
|
+
this.pressedOpen = false;
|
|
59
|
+
this.handlePress = () => {
|
|
60
|
+
const opening = !this.open;
|
|
61
|
+
this.handleTriggerClick();
|
|
62
|
+
this.pressedOpen = opening && this.open;
|
|
63
|
+
};
|
|
58
64
|
}
|
|
59
65
|
static { this.words = 'helix-color-input'; }
|
|
60
66
|
requestValue(next) {
|
|
@@ -117,6 +123,18 @@ let HelixHeadlessColorInput = class HelixHeadlessColorInput extends MixinPickerF
|
|
|
117
123
|
if (changed.has('value') && parseColor(this.value)) {
|
|
118
124
|
this.settled = this.value;
|
|
119
125
|
}
|
|
126
|
+
if (changed.has('open') && !this.open) {
|
|
127
|
+
this.pressedOpen = false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
returnFocus() {
|
|
131
|
+
const trigger = this.pressedOpen ? this.partNamed('trigger') : null;
|
|
132
|
+
this.pressedOpen = false;
|
|
133
|
+
if (trigger) {
|
|
134
|
+
trigger.focus();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
super.returnFocus();
|
|
120
138
|
}
|
|
121
139
|
renderPicker() {
|
|
122
140
|
return html `<${this.tag('color-picker')}
|
|
@@ -204,7 +222,7 @@ let HelixHeadlessColorInput = class HelixHeadlessColorInput extends MixinPickerF
|
|
|
204
222
|
: 'swatch-value'
|
|
205
223
|
: nothing}
|
|
206
224
|
?disabled=${this.isDisabled}
|
|
207
|
-
@click=${this.
|
|
225
|
+
@click=${this.handlePress}
|
|
208
226
|
>
|
|
209
227
|
<span
|
|
210
228
|
part="preview"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type Color, type ColorFormat, type ColorWords, HelixFormElement, KeyboardNavigationController } from '@fusion.dev/helix-core';
|
|
2
|
-
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
1
|
+
import { type Color, type ColorFormat, type ColorWords, HelixFormElement, KeyboardNavigationController, type PickerFailure } from '@fusion.dev/helix-core';
|
|
2
|
+
import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
import '../../button/index.js';
|
|
4
4
|
import '../../button-group/index.js';
|
|
5
5
|
import '../../slider/index.js';
|
|
@@ -82,7 +82,7 @@ declare const HelixHeadlessColorPicker_base: (new (...args: any[]) => import("@f
|
|
|
82
82
|
* @csspart eyedropper-live - The live region of the button inside `eyedropper`, which says its pending label.
|
|
83
83
|
* @csspart eyedropper-spinner - The ring the eyedropper button turns while it is pending.
|
|
84
84
|
* @csspart eyedropper-text - The words on the button inside `eyedropper`, trimmed to their capitals and baseline.
|
|
85
|
-
* @csspart feedback - The message under the picker
|
|
85
|
+
* @csspart feedback - The message under the picker: `feedback`, or what is wrong with the answer once the picker is marked invalid.
|
|
86
86
|
* @csspart field - One channel's number field with its label, in `channel-fields`.
|
|
87
87
|
* @csspart field-input - The number input in a channel's field.
|
|
88
88
|
* @csspart field-label - The name above a channel's number input.
|
|
@@ -321,10 +321,11 @@ export declare class HelixHeadlessColorPicker extends HelixHeadlessColorPicker_b
|
|
|
321
321
|
* the anchor the browser points its bubble at.
|
|
322
322
|
*
|
|
323
323
|
* **Text that is not a color is bad input**, so a form does not submit
|
|
324
|
-
* `#00` from a half-typed value. The picker
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
324
|
+
* `#00` from a half-typed value. The picker marks it, and says
|
|
325
|
+
* `badInputMessage` under itself, once the reader leaves the value field or
|
|
326
|
+
* presses Enter, and a missing color once the reader has committed one or a
|
|
327
|
+
* form has refused the picker. Color Input shows its own message against the
|
|
328
|
+
* field the reader typed into.
|
|
328
329
|
*/
|
|
329
330
|
required: boolean;
|
|
330
331
|
/**
|
|
@@ -404,6 +405,52 @@ export declare class HelixHeadlessColorPicker extends HelixHeadlessColorPicker_b
|
|
|
404
405
|
private get hinted();
|
|
405
406
|
/** The ids a control in the picker is described by: the help, then the message. */
|
|
406
407
|
private get describedBy();
|
|
408
|
+
/**
|
|
409
|
+
* Whether the reader is typing into the value field, between the first
|
|
410
|
+
* keystroke and the `change` that ends it.
|
|
411
|
+
*
|
|
412
|
+
* Half-typed text is rarely a color: `#00ff00` passes through `#0` and
|
|
413
|
+
* `#00ff0` on the way. So text that is not a color is refused once the
|
|
414
|
+
* reader leaves the field or presses Enter, and not on every keystroke.
|
|
415
|
+
*/
|
|
416
|
+
private typing;
|
|
417
|
+
/**
|
|
418
|
+
* Text in the value field that is not a color, or undefined while the field
|
|
419
|
+
* holds the value.
|
|
420
|
+
*
|
|
421
|
+
* **Kept in the field and out of the value**, as a native number field keeps
|
|
422
|
+
* "12e": the text stays where the reader can correct it, the value stays the
|
|
423
|
+
* last color, and the picker reports `badInput` until the text is a color or
|
|
424
|
+
* the value moves. Measured before this: typed "nonsense" became the value,
|
|
425
|
+
* so a form read `brand=nonsense` and the square had no color to show.
|
|
426
|
+
*/
|
|
427
|
+
private draft;
|
|
428
|
+
/**
|
|
429
|
+
* A required picker with no color is missing, and text that is not a color
|
|
430
|
+
* is refused, once the reader has finished typing it. See
|
|
431
|
+
* `MixinPickerFeedback.marked`.
|
|
432
|
+
*
|
|
433
|
+
* Measured before this: typed "nonsense" and a required picker its form
|
|
434
|
+
* refused both failed `checkValidity()` while `:state(invalid)` stayed off,
|
|
435
|
+
* the value field had no `aria-invalid`, and nothing was said.
|
|
436
|
+
*/
|
|
437
|
+
protected get failure(): PickerFailure | undefined;
|
|
438
|
+
/**
|
|
439
|
+
* The line under the picker: `feedback`, or, where the picker is marked by
|
|
440
|
+
* its own validation, what is wrong.
|
|
441
|
+
*/
|
|
442
|
+
private get said();
|
|
443
|
+
/**
|
|
444
|
+
* A reset ends any typing and takes back text that was not a color, so the
|
|
445
|
+
* field shows the color the reset put back.
|
|
446
|
+
*/
|
|
447
|
+
formResetCallback(): void;
|
|
448
|
+
/**
|
|
449
|
+
* The line `said` holds, or nothing while it is empty. `role="alert"`, as
|
|
450
|
+
* every field's feedback line has, so the message is announced when it
|
|
451
|
+
* appears.
|
|
452
|
+
*/
|
|
453
|
+
protected renderPickerFeedback(): TemplateResult | typeof nothing;
|
|
407
454
|
/** Whether a pointer is dragging the square's handle, said as `:state(dragging)`. */
|
|
408
455
|
private dragging;
|
|
409
456
|
/** Whether the eyedropper is open, said as `:state(sampling)`. */
|
|
@@ -56,6 +56,8 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
56
56
|
this.handleNamingSlot = () => {
|
|
57
57
|
this.requestUpdate();
|
|
58
58
|
};
|
|
59
|
+
this.typing = false;
|
|
60
|
+
this.draft = undefined;
|
|
59
61
|
this.dragging = false;
|
|
60
62
|
this.picking = false;
|
|
61
63
|
this.owned = false;
|
|
@@ -68,7 +70,14 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
68
70
|
return;
|
|
69
71
|
}
|
|
70
72
|
const typed = event.target.value;
|
|
73
|
+
this.typing = true;
|
|
71
74
|
const parsed = parseColor(typed);
|
|
75
|
+
if (!parsed && typed.trim() !== '') {
|
|
76
|
+
this.draft = typed;
|
|
77
|
+
this.sync();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
this.draft = undefined;
|
|
72
81
|
if (parsed) {
|
|
73
82
|
this.moved = parsed;
|
|
74
83
|
this.owned = typed !== this.value;
|
|
@@ -261,9 +270,47 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
261
270
|
return this.hint !== '' || this.slottedIn('hint').length > 0;
|
|
262
271
|
}
|
|
263
272
|
get describedBy() {
|
|
264
|
-
const ids = [this.hinted ? 'hint' : '', this.
|
|
273
|
+
const ids = [this.hinted ? 'hint' : '', this.said === '' ? '' : 'feedback'].filter(Boolean);
|
|
265
274
|
return ids.length > 0 ? ids.join(' ') : nothing;
|
|
266
275
|
}
|
|
276
|
+
get failure() {
|
|
277
|
+
if (this.draft !== undefined) {
|
|
278
|
+
return this.typing ? undefined : 'refused';
|
|
279
|
+
}
|
|
280
|
+
if (this.value === '') {
|
|
281
|
+
return this.required ? 'missing' : undefined;
|
|
282
|
+
}
|
|
283
|
+
return parseColor(this.value) === null ? 'refused' : undefined;
|
|
284
|
+
}
|
|
285
|
+
get said() {
|
|
286
|
+
if (this.feedback !== '') {
|
|
287
|
+
return this.feedback;
|
|
288
|
+
}
|
|
289
|
+
if (!this.marked || this.invalid) {
|
|
290
|
+
return '';
|
|
291
|
+
}
|
|
292
|
+
const failure = this.failure;
|
|
293
|
+
return failure === 'refused'
|
|
294
|
+
? this.badInputMessage
|
|
295
|
+
: failure === 'missing'
|
|
296
|
+
? this.valueMissingMessage
|
|
297
|
+
: '';
|
|
298
|
+
}
|
|
299
|
+
formResetCallback() {
|
|
300
|
+
super.formResetCallback();
|
|
301
|
+
this.typing = false;
|
|
302
|
+
if (this.draft !== undefined) {
|
|
303
|
+
this.draft = undefined;
|
|
304
|
+
const field = this.partNamed('value');
|
|
305
|
+
if (field) {
|
|
306
|
+
field.value = this.value;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
renderPickerFeedback() {
|
|
311
|
+
const said = this.said;
|
|
312
|
+
return said === '' ? nothing : html `<p part="feedback" id="feedback" role="alert">${said}</p>`;
|
|
313
|
+
}
|
|
267
314
|
settle() {
|
|
268
315
|
if (this.unsettled) {
|
|
269
316
|
this.unsettled = false;
|
|
@@ -299,6 +346,10 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
299
346
|
this.reportRequired();
|
|
300
347
|
}
|
|
301
348
|
reportRequired() {
|
|
349
|
+
if (this.draft !== undefined) {
|
|
350
|
+
this.internals.setValidity({ badInput: true }, this.badInputMessage, this.partNamed('value') ?? this.partNamed('grid') ?? undefined);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
302
353
|
if (this.required && this.value === '') {
|
|
303
354
|
this.internals.setValidity({ valueMissing: true }, this.valueMissingMessage, this.partNamed('grid') ?? undefined);
|
|
304
355
|
return;
|
|
@@ -424,6 +475,9 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
424
475
|
this.move({ [channel]: Number(control.value) });
|
|
425
476
|
}
|
|
426
477
|
willUpdate(changed) {
|
|
478
|
+
if (changed.has('value')) {
|
|
479
|
+
this.draft = undefined;
|
|
480
|
+
}
|
|
427
481
|
super.willUpdate(changed);
|
|
428
482
|
const outside = [...(this.internals.labels ?? [])];
|
|
429
483
|
const named = this.named;
|
|
@@ -630,6 +684,7 @@ let HelixHeadlessColorPicker = class HelixHeadlessColorPicker extends MixinPicke
|
|
|
630
684
|
@input=${this.handleValueInput}
|
|
631
685
|
@change=${(event) => {
|
|
632
686
|
event.stopPropagation();
|
|
687
|
+
this.typing = false;
|
|
633
688
|
this.settle();
|
|
634
689
|
}}
|
|
635
690
|
/>`}
|
|
@@ -770,6 +825,12 @@ __decorate([
|
|
|
770
825
|
__decorate([
|
|
771
826
|
state()
|
|
772
827
|
], HelixHeadlessColorPicker.prototype, "swatchAt", void 0);
|
|
828
|
+
__decorate([
|
|
829
|
+
state()
|
|
830
|
+
], HelixHeadlessColorPicker.prototype, "typing", void 0);
|
|
831
|
+
__decorate([
|
|
832
|
+
state()
|
|
833
|
+
], HelixHeadlessColorPicker.prototype, "draft", void 0);
|
|
773
834
|
__decorate([
|
|
774
835
|
state()
|
|
775
836
|
], HelixHeadlessColorPicker.prototype, "dragging", void 0);
|
|
@@ -240,12 +240,13 @@ export declare class HelixHeadlessCombobox extends HelixHeadlessCombobox_base {
|
|
|
240
240
|
/**
|
|
241
241
|
* Whether more than one option can be chosen.
|
|
242
242
|
*
|
|
243
|
-
* The list already does the work: `value`
|
|
244
|
-
* toggles rather than replaces, and the arrows move without
|
|
245
|
-
* this adds is the tags, and keeping the panel open between
|
|
243
|
+
* The list already does the work: `value` is the chosen values joined with
|
|
244
|
+
* commas, a press toggles rather than replaces, and the arrows move without
|
|
245
|
+
* choosing. What this adds is the tags, and keeping the panel open between
|
|
246
|
+
* picks.
|
|
246
247
|
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
248
|
+
* An option's value may hold a comma, and it is read as one value, as
|
|
249
|
+
* `Select` and `Listbox` read it. So may an answer the reader created.
|
|
249
250
|
*
|
|
250
251
|
* **The list is told, and the field is not.** `aria-multiselectable` belongs
|
|
251
252
|
* to `listbox`, `grid`, `tree` and `tablist`, and `combobox` dropped it in
|
|
@@ -385,8 +386,17 @@ export declare class HelixHeadlessCombobox extends HelixHeadlessCombobox_base {
|
|
|
385
386
|
*/
|
|
386
387
|
protected readonly upgradeWatch: UpgradeController;
|
|
387
388
|
protected readonly panel: PopoverController;
|
|
388
|
-
/**
|
|
389
|
+
/**
|
|
390
|
+
* The values chosen, in the order they were chosen, read against the
|
|
391
|
+
* options' values and the answers created here, so a value that holds a
|
|
392
|
+
* comma is one value. See `chosenValues`.
|
|
393
|
+
*
|
|
394
|
+
* Measured before this: choosing `Paris, France` drew two tags, "Paris" and
|
|
395
|
+
* "France", and the form received two entries.
|
|
396
|
+
*/
|
|
389
397
|
private get values();
|
|
398
|
+
/** The answers created here, which no option holds, kept so their commas read as theirs. */
|
|
399
|
+
private readonly created;
|
|
390
400
|
/**
|
|
391
401
|
* The chosen options themselves, for their words.
|
|
392
402
|
*
|
|
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { AriaForwardController, afterLinkFollowed, countLabel, customElement, DelayController, drawAutofill, drawStatus, formatWords, HelixCreateEvent, HelixFilterEvent, HelixFormElement, handedLocale, MixinControllerOpen, MixinControllerValue, MixinField, MixinTokens, onApple, PopoverController, reportValues, StatusController, submitImplicitly, UpgradeController, words, wordsLocale, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, afterLinkFollowed, chosenValues, countLabel, customElement, DelayController, drawAutofill, drawStatus, formatWords, HelixCreateEvent, HelixFilterEvent, HelixFormElement, handedLocale, MixinControllerOpen, MixinControllerValue, MixinField, MixinTokens, onApple, PopoverController, reportValues, StatusController, submitImplicitly, UpgradeController, words, wordsLocale, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { caretDown } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -69,6 +69,7 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
|
|
|
69
69
|
placement: 'bottom-start',
|
|
70
70
|
surface: () => this.partNamed('surface'),
|
|
71
71
|
});
|
|
72
|
+
this.created = new Set();
|
|
72
73
|
this.handleInput = (event) => {
|
|
73
74
|
event.stopPropagation();
|
|
74
75
|
const typed = event.target.value;
|
|
@@ -252,7 +253,11 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
|
|
|
252
253
|
return this.partNamed('listbox');
|
|
253
254
|
}
|
|
254
255
|
get values() {
|
|
255
|
-
|
|
256
|
+
const known = new Set(this.created);
|
|
257
|
+
for (const option of optionsAmong(this.knownChildren)) {
|
|
258
|
+
known.add(option.value);
|
|
259
|
+
}
|
|
260
|
+
return chosenValues(this.value, known, this.multiple);
|
|
256
261
|
}
|
|
257
262
|
get chosen() {
|
|
258
263
|
const options = optionsAmong(this.knownChildren);
|
|
@@ -296,6 +301,7 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
|
|
|
296
301
|
return;
|
|
297
302
|
}
|
|
298
303
|
const next = this.multiple ? [...this.values, wanted].join(',') : wanted;
|
|
304
|
+
this.created.add(wanted);
|
|
299
305
|
if (!this.requestValue(next)) {
|
|
300
306
|
return;
|
|
301
307
|
}
|
|
@@ -343,6 +349,7 @@ let HelixHeadlessCombobox = class HelixHeadlessCombobox extends MixinControllerO
|
|
|
343
349
|
}
|
|
344
350
|
const named = (this.listbox?.options ?? []).find((option) => option.text.trim().toLowerCase() === typed.toLowerCase());
|
|
345
351
|
const answer = named?.value ?? typed;
|
|
352
|
+
this.created.add(answer);
|
|
346
353
|
if (this.multiple) {
|
|
347
354
|
if (!this.values.includes(answer)) {
|
|
348
355
|
this.requestValue([...this.values, answer].join(','));
|
|
@@ -55,7 +55,8 @@ declare const HelixHeadlessCommand_base: (new (...args: any[]) => import("@fusio
|
|
|
55
55
|
* | `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. |
|
|
56
56
|
* | Down, Up | Moves the highlight to the next or the previous command, round from the last to the first. |
|
|
57
57
|
* | Page Down, Page Up | Moves the highlight by as many commands as the list shows at once. |
|
|
58
|
-
* | Home, End
|
|
58
|
+
* | Home, End | Move the caret in the filter field. With `home-end="list"`, move the highlight to the first or the last command. |
|
|
59
|
+
* | Left, Right | Move the caret in the filter field. |
|
|
59
60
|
* | 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. |
|
|
60
61
|
* | Command or Control with Enter | Takes the highlighted command's `alternate` destination, where it has one. |
|
|
61
62
|
* | Backspace | In an empty filter on a page, goes back to the page before. |
|
|
@@ -144,6 +145,14 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
|
|
|
144
145
|
* property only, there being no way to write a function in markup.
|
|
145
146
|
*/
|
|
146
147
|
filterMatch?: ((text: string, filter: string) => boolean) | undefined;
|
|
148
|
+
/**
|
|
149
|
+
* Where Home and End go from the filter field.
|
|
150
|
+
*
|
|
151
|
+
* Absent, they move the caret, as APG's combobox has them. `list` moves the
|
|
152
|
+
* highlight to the first or the last command, as React Aria's Autocomplete
|
|
153
|
+
* does, and Shift with either still selects the text.
|
|
154
|
+
*/
|
|
155
|
+
homeEnd?: 'list';
|
|
147
156
|
/**
|
|
148
157
|
* The key that opens the palette, written as `mod+k`, `shift+p`, or `k`,
|
|
149
158
|
* in Kbd's chord spelling: `mod` is Command or Control, `ctrl`, `cmd`,
|
|
@@ -178,6 +187,12 @@ export declare class HelixHeadlessCommand extends HelixHeadlessCommand_base {
|
|
|
178
187
|
* Accessible name for the overlay, which has no visible heading.
|
|
179
188
|
*/
|
|
180
189
|
label: string;
|
|
190
|
+
/**
|
|
191
|
+
* How the commands are laid out, as Listbox's `layout`: `grid` draws them in
|
|
192
|
+
* rows and columns, for a palette of icons or emoji, and the arrow keys
|
|
193
|
+
* follow the rows and the columns. Absent is one command under another.
|
|
194
|
+
*/
|
|
195
|
+
layout?: 'grid' | 'stack';
|
|
181
196
|
/**
|
|
182
197
|
* What the list says when its commands could not be loaded, such as after a
|
|
183
198
|
* request to a server fails. Empty, null or no attribute is no error, so
|
|
@@ -246,6 +246,8 @@ let HelixHeadlessCommand = class HelixHeadlessCommand extends MixinControllerOpe
|
|
|
246
246
|
results-label=${this.resultsLabel}
|
|
247
247
|
?loading=${this.loading}
|
|
248
248
|
.items=${this.items}
|
|
249
|
+
.fieldHomeEnd=${this.homeEnd === 'list'}
|
|
250
|
+
layout=${this.layout ?? nothing}
|
|
249
251
|
filterable
|
|
250
252
|
@helix-before-change=${this.handleChange}
|
|
251
253
|
@helix-filter=${this.handleFilter}
|
|
@@ -299,6 +301,9 @@ __decorate([
|
|
|
299
301
|
__decorate([
|
|
300
302
|
property({ attribute: false })
|
|
301
303
|
], HelixHeadlessCommand.prototype, "filterMatch", void 0);
|
|
304
|
+
__decorate([
|
|
305
|
+
property({ attribute: 'home-end' })
|
|
306
|
+
], HelixHeadlessCommand.prototype, "homeEnd", void 0);
|
|
302
307
|
__decorate([
|
|
303
308
|
property()
|
|
304
309
|
], HelixHeadlessCommand.prototype, "hotkey", void 0);
|
|
@@ -312,6 +317,9 @@ __decorate([
|
|
|
312
317
|
words,
|
|
313
318
|
property()
|
|
314
319
|
], HelixHeadlessCommand.prototype, "label", void 0);
|
|
320
|
+
__decorate([
|
|
321
|
+
property({ reflect: true })
|
|
322
|
+
], HelixHeadlessCommand.prototype, "layout", void 0);
|
|
315
323
|
__decorate([
|
|
316
324
|
property({ attribute: 'load-error' })
|
|
317
325
|
], HelixHeadlessCommand.prototype, "loadError", void 0);
|
|
@@ -208,7 +208,7 @@ declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fus
|
|
|
208
208
|
* @csspart select - The cell that holds a row's checkbox.
|
|
209
209
|
* @csspart select-all - The heading that holds the checkbox that selects every row.
|
|
210
210
|
* @csspart select-selected - Added to `select` in a selected row.
|
|
211
|
-
* @csspart table - The grid.
|
|
211
|
+
* @csspart table - The grid. While `windowed`, the box that scrolls, which needs only a block size on this tier.
|
|
212
212
|
* @csspart toggle - The mark in a row header that a press opens and closes its row by, in a tree grid.
|
|
213
213
|
* @csspart toggle-mark - The caret in `toggle`. It points along the line while the row is closed and down while it is open.
|
|
214
214
|
* @csspart toggle-open - Added to `toggle` while its row is open.
|
|
@@ -586,6 +586,10 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
586
586
|
* Off by default. Windowing costs a scroll listener, a measurement per row
|
|
587
587
|
* drawn, and a `block-size` on the scrolling box, and a table of twenty rows
|
|
588
588
|
* should pay none of them.
|
|
589
|
+
*
|
|
590
|
+
* While windowed, the `table` part scrolls on this tier: it carries
|
|
591
|
+
* `data-scroller`, and `core` ships `[data-scroller] { overflow: auto }` into
|
|
592
|
+
* every shadow root. You still need to give it a block size.
|
|
589
593
|
*/
|
|
590
594
|
windowed: boolean;
|
|
591
595
|
private sortState;
|
|
@@ -1228,6 +1228,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
1228
1228
|
part="table"
|
|
1229
1229
|
role="rowgroup"
|
|
1230
1230
|
aria-busy=${this.loading ? 'true' : nothing}
|
|
1231
|
+
?data-scroller=${this.windowed}
|
|
1231
1232
|
style=${template ? `--data-table-template: ${template}` : nothing}
|
|
1232
1233
|
@scroll=${this.handleScroll}
|
|
1233
1234
|
>
|
|
@@ -74,6 +74,10 @@ declare const HelixHeadlessDrawer_base: (new (...args: any[]) => import("@fusion
|
|
|
74
74
|
* <helix-headless-drawer id="nav">…</helix-headless-drawer>
|
|
75
75
|
* ```
|
|
76
76
|
*
|
|
77
|
+
* From its first press, a button that opens the drawer this way says whether
|
|
78
|
+
* the drawer is open: a Helix button through `expanded`, and any other
|
|
79
|
+
* element with `aria-expanded`.
|
|
80
|
+
*
|
|
77
81
|
* @since 0.1.0
|
|
78
82
|
* @status stable
|
|
79
83
|
* @category overlays
|
|
@@ -19,6 +19,7 @@ let HelixHeadlessDrawer = class HelixHeadlessDrawer extends MixinControllerOpen(
|
|
|
19
19
|
'--show': () => this.requestOpen(true),
|
|
20
20
|
'--toggle': () => this.toggleOpen(),
|
|
21
21
|
},
|
|
22
|
+
expanded: () => this.open,
|
|
22
23
|
});
|
|
23
24
|
this.dismissible = false;
|
|
24
25
|
this.dismissLabel = 'Close';
|
|
@@ -196,6 +196,7 @@ registerElementEvents({
|
|
|
196
196
|
'helix-headless-map-terrain': ['helix-map-part-change'],
|
|
197
197
|
'helix-headless-megamenu': ['helix-before-close', 'helix-before-open', 'toggle'],
|
|
198
198
|
'helix-headless-menu': [
|
|
199
|
+
'change',
|
|
199
200
|
'helix-before-close',
|
|
200
201
|
'helix-before-open',
|
|
201
202
|
'helix-filter',
|
|
@@ -28,9 +28,10 @@ declare const HelixHeadlessFilterChip_base: (new (...args: any[]) => import("@fu
|
|
|
28
28
|
* press. `requestChange` documents the pattern.
|
|
29
29
|
*
|
|
30
30
|
* **Keyboard.** The remove button is a tab stop of its own, and Enter or Space
|
|
31
|
-
* on it asks to remove the filter. In a `FilterInput`,
|
|
32
|
-
* field asks to remove the last chip, the
|
|
33
|
-
* and the chips, and Delete or Backspace on
|
|
31
|
+
* on it asks to remove the filter. In a `FilterInput`, the field's text is the
|
|
32
|
+
* one tab stop: Backspace in the empty field asks to remove the last chip, the
|
|
33
|
+
* arrow keys move between the field and the chips, and Delete or Backspace on
|
|
34
|
+
* a chip asks to remove it.
|
|
34
35
|
*
|
|
35
36
|
* The remove button is named `dismiss-label` followed by the chip's words,
|
|
36
37
|
* such as "Remove filter Status is not open", so a row of chips says which
|
|
@@ -78,6 +79,15 @@ export declare class HelixHeadlessFilterChip extends HelixHeadlessFilterChip_bas
|
|
|
78
79
|
* closing a message.
|
|
79
80
|
*/
|
|
80
81
|
dismissLabel: string;
|
|
82
|
+
/**
|
|
83
|
+
* Whether the remove button is a tab stop of its own.
|
|
84
|
+
*
|
|
85
|
+
* `FilterInput` writes `false` on the chips in its `tags` slot: the field's
|
|
86
|
+
* text is its one tab stop, and the arrow keys move from the text to the
|
|
87
|
+
* chips, as in a `multiple` Combobox. No attribute: it is coordination
|
|
88
|
+
* between elements, as `Tag.dismissTabStop` is.
|
|
89
|
+
*/
|
|
90
|
+
dismissTabStop: boolean;
|
|
81
91
|
/**
|
|
82
92
|
* The name of the field the filter is on, as shown on the chip.
|
|
83
93
|
*
|
|
@@ -13,6 +13,7 @@ let HelixHeadlessFilterChip = class HelixHeadlessFilterChip extends MixinDismiss
|
|
|
13
13
|
constructor() {
|
|
14
14
|
super(...arguments);
|
|
15
15
|
this.dismissLabel = 'Remove filter';
|
|
16
|
+
this.dismissTabStop = true;
|
|
16
17
|
this.label = '';
|
|
17
18
|
this.operatorLabel = '';
|
|
18
19
|
}
|
|
@@ -43,6 +44,7 @@ let HelixHeadlessFilterChip = class HelixHeadlessFilterChip extends MixinDismiss
|
|
|
43
44
|
part="dismiss"
|
|
44
45
|
type="button"
|
|
45
46
|
aria-label=${this.removeName}
|
|
47
|
+
tabindex=${this.dismissTabStop ? nothing : '-1'}
|
|
46
48
|
@click=${() => this.dismiss()}
|
|
47
49
|
>
|
|
48
50
|
<svg part="dismiss-mark" fill="currentColor" viewBox=${x.viewBox} aria-hidden="true">
|
|
@@ -56,6 +58,9 @@ __decorate([
|
|
|
56
58
|
words,
|
|
57
59
|
property({ attribute: 'dismiss-label' })
|
|
58
60
|
], HelixHeadlessFilterChip.prototype, "dismissLabel", void 0);
|
|
61
|
+
__decorate([
|
|
62
|
+
property({ attribute: false })
|
|
63
|
+
], HelixHeadlessFilterChip.prototype, "dismissTabStop", void 0);
|
|
59
64
|
__decorate([
|
|
60
65
|
property()
|
|
61
66
|
], HelixHeadlessFilterChip.prototype, "label", void 0);
|
|
@@ -180,7 +180,6 @@ let HelixHeadlessFilterMenu = class HelixHeadlessFilterMenu extends HelixElement
|
|
|
180
180
|
part="divider"
|
|
181
181
|
exportparts="content: divider-content, line: divider-line"
|
|
182
182
|
slot="submenu"
|
|
183
|
-
announced
|
|
184
183
|
></${divider}>`
|
|
185
184
|
: nothing}
|
|
186
185
|
${offered.map((option) => html `<${item}
|