@fusion.dev/helix-headless 0.169.0 → 0.171.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 +663 -95
- package/dist/chat/composer/chat-composer.d.ts +2 -1
- package/dist/chat/composer/chat-composer.js +7 -1
- package/dist/chat/root/chat-root.d.ts +36 -6
- package/dist/chat/root/chat-root.js +53 -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-picker/root/color-picker-root.d.ts +50 -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 +40 -5
- package/dist/data-table/root/data-table-root.js +35 -7
- 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/listbox/root/listbox-root.d.ts +6 -0
- package/dist/listbox/root/listbox-root.js +6 -1
- 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/select/root/select-root.js +2 -0
- 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/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 +510 -126
- package/types/vue.d.ts +109 -26
- package/types/words.d.ts +12 -2
|
@@ -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);
|
|
@@ -24,10 +24,15 @@ declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fus
|
|
|
24
24
|
*
|
|
25
25
|
* Sort and filter apply to the whole set, including the rows on other pages.
|
|
26
26
|
*
|
|
27
|
-
* **
|
|
28
|
-
*
|
|
29
|
-
* children to this element, so
|
|
30
|
-
*
|
|
27
|
+
* **Write the first page as rows, so the served HTML carries the values.** The
|
|
28
|
+
* table reads each cell from its column, and a server does not pass the column
|
|
29
|
+
* children to this element, so on its own it serves the headings and no values.
|
|
30
|
+
* Write the first page under the columns as `TableRow` and `TableCell`
|
|
31
|
+
* elements, in the table's sort and page size and formatted as its columns draw
|
|
32
|
+
* them. The table shows your rows until `rows` holds a row, then draws its own
|
|
33
|
+
* in their place and leaves yours in the page, unshown. A development build
|
|
34
|
+
* warns when the two differ. In React, map the first page of the same array in
|
|
35
|
+
* the same server component.
|
|
31
36
|
*
|
|
32
37
|
* `selectable` adds a column of checkboxes, keyed on `row-key`:
|
|
33
38
|
*
|
|
@@ -132,7 +137,7 @@ declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fus
|
|
|
132
137
|
* @aliases Grid, Result table, Data grid
|
|
133
138
|
* @documentation https://fusion.dev/helix/components/data-table
|
|
134
139
|
*
|
|
135
|
-
* @slot - The columns, as `TableColumn` elements.
|
|
140
|
+
* @slot - The columns, as `TableColumn` elements, and the first page served as `TableRow` elements, which show until `rows` holds a row.
|
|
136
141
|
* @slot empty - Content shown when there are no rows to show and none are loading, such as a picture and a link. Falls back to `empty-text`, which the live region still says.
|
|
137
142
|
* @slot error - Content shown while `error-text` is set, such as a button that tries again. Falls back to `error-text`, which the live region still says.
|
|
138
143
|
* @slot footer - Content below the grid. It replaces the built-in pagination.
|
|
@@ -610,6 +615,15 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
610
615
|
private drawnPage;
|
|
611
616
|
/** Whether the last render drew the `more` row, which follows the page's rows. */
|
|
612
617
|
private moreDrawn;
|
|
618
|
+
/**
|
|
619
|
+
* Whether `rows` has held a row, after which the rows the page served are
|
|
620
|
+
* never shown again, whatever `rows` holds later.
|
|
621
|
+
*/
|
|
622
|
+
private drewRows;
|
|
623
|
+
/** Whether the last render showed the rows the page served. */
|
|
624
|
+
private serving;
|
|
625
|
+
/** Whether the render before the last showed them, so the change is checked once. */
|
|
626
|
+
private servedLast;
|
|
613
627
|
/** The letters typed at the grid, which move to the row whose header they start. */
|
|
614
628
|
private readonly typeahead;
|
|
615
629
|
/**
|
|
@@ -841,6 +855,27 @@ export declare class HelixHeadlessDataTable extends HelixHeadlessDataTable_base
|
|
|
841
855
|
* what this replaced.
|
|
842
856
|
*/
|
|
843
857
|
protected get hasRows(): boolean;
|
|
858
|
+
/**
|
|
859
|
+
* The rows the page served: the first page, written as `TableRow` children.
|
|
860
|
+
*
|
|
861
|
+
* By tag, because the page may not register `Table`, and an element that is
|
|
862
|
+
* not defined has no `isTableRow` to find it by.
|
|
863
|
+
*/
|
|
864
|
+
private get servedRows();
|
|
865
|
+
/**
|
|
866
|
+
* Whether this render shows the rows the page served in place of drawing its
|
|
867
|
+
* own.
|
|
868
|
+
*
|
|
869
|
+
* **Until `rows` has held a row, and never after.** A server cannot tell
|
|
870
|
+
* whether the page served any, and a render hydrating what one sent has to
|
|
871
|
+
* render the same, so both show the slot that would hold them. In a browser
|
|
872
|
+
* the rows are shown while `rows` is empty, which is how a framework that
|
|
873
|
+
* renders on a server leaves the property until it hydrates. Once the table
|
|
874
|
+
* has drawn its own rows it stops showing the served ones and never removes
|
|
875
|
+
* them: they are the page's markup, and a framework that rendered them owns
|
|
876
|
+
* them.
|
|
877
|
+
*/
|
|
878
|
+
private serves;
|
|
844
879
|
/**
|
|
845
880
|
* Whether this render can tell a result with no rows from one not yet handed
|
|
846
881
|
* over.
|
|
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
var HelixHeadlessDataTable_1;
|
|
8
|
-
import { anchorAt, arranged, commaList, countLabel, customElement, cycle, deepActiveElement, deepContains, everyState, format, formatWords, gridMove, HelixActivateEvent, HelixElement, HelixExpandEvent, HelixFilterEvent, HelixFilteredEvent, HelixLoadMoreEvent, HelixNavigateEvent, HelixReorderEvent, HelixReorderedEvent, HelixSelectEvent, HelixSelectedEvent, HelixSortEvent, HelixSortedEvent, handedLocale, hostAria, inlineStep, inRowOrder, MixinCollection, markRegion, onAndroid, ordered, pageRows, parse, placeKey, ReorderController, rangeAdd, reportRuntime, requestChange, requestReorder, scrollingAncestor, scrollRoom, selectsAll, Typeahead, toggleEvery, treeArrow, typesCharacter, VirtualizeController, valueAt, window_, words, wordsLocale, writtenList, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { anchorAt, arranged, auditServed, commaList, countLabel, customElement, cycle, deepActiveElement, deepContains, everyState, format, formatWords, gridMove, HelixActivateEvent, HelixElement, HelixExpandEvent, HelixFilterEvent, HelixFilteredEvent, HelixLoadMoreEvent, HelixNavigateEvent, HelixReorderEvent, HelixReorderedEvent, HelixSelectEvent, HelixSelectedEvent, HelixSortEvent, HelixSortedEvent, handedLocale, hostAria, inlineStep, inRowOrder, MixinCollection, markRegion, onAndroid, ordered, pageRows, parse, placeKey, ReorderController, rangeAdd, reportRuntime, requestChange, requestReorder, scrollingAncestor, scrollRoom, selectsAll, Typeahead, toggleEvery, treeArrow, typesCharacter, VirtualizeController, valueAt, window_, words, wordsLocale, writtenList, } from '@fusion.dev/helix-core';
|
|
9
9
|
import { caretDown, caretRight, dotsSixVertical } from '@fusion.dev/helix-icons';
|
|
10
10
|
import { nothing } from 'lit';
|
|
11
11
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -86,6 +86,9 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
86
86
|
this.focusWanted = false;
|
|
87
87
|
this.drawnPage = [];
|
|
88
88
|
this.moreDrawn = false;
|
|
89
|
+
this.drewRows = false;
|
|
90
|
+
this.serving = false;
|
|
91
|
+
this.servedLast = false;
|
|
89
92
|
this.typeahead = new Typeahead();
|
|
90
93
|
this.anchorKey = undefined;
|
|
91
94
|
this.shiftPressed = false;
|
|
@@ -656,7 +659,17 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
656
659
|
})).length;
|
|
657
660
|
}
|
|
658
661
|
get hasRows() {
|
|
659
|
-
return this.view.available > 0 || !this.sourceKnown;
|
|
662
|
+
return this.view.available > 0 || !this.sourceKnown || this.serving;
|
|
663
|
+
}
|
|
664
|
+
get servedRows() {
|
|
665
|
+
return this.knownChildren.filter((child) => /^helix-(headless-)?table-row$/.test(child.localName));
|
|
666
|
+
}
|
|
667
|
+
serves() {
|
|
668
|
+
if (!this.sourceKnown) {
|
|
669
|
+
return true;
|
|
670
|
+
}
|
|
671
|
+
this.drewRows ||= this.rows.length > 0;
|
|
672
|
+
return !this.drewRows && this.servedRows.length > 0;
|
|
660
673
|
}
|
|
661
674
|
get sourceKnown() {
|
|
662
675
|
return this.childrenKnown;
|
|
@@ -909,6 +922,9 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
909
922
|
}
|
|
910
923
|
const columns = this.orderedColumns;
|
|
911
924
|
head.assign(...columns);
|
|
925
|
+
root
|
|
926
|
+
.querySelector('[part="table"] > slot:not([name])')
|
|
927
|
+
?.assign(...(this.serving ? this.servedRows : []));
|
|
912
928
|
const rest = [...this.children].filter((child) => !columns.includes(child));
|
|
913
929
|
for (const [name, wanted] of [
|
|
914
930
|
['toolbar', true],
|
|
@@ -986,6 +1002,10 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
986
1002
|
this.toggleState('empty', !this.loading && !this.hasRows);
|
|
987
1003
|
this.toggleState('loading', this.loading);
|
|
988
1004
|
this.assign();
|
|
1005
|
+
if (this.servedLast && !this.serving) {
|
|
1006
|
+
auditServed(this, this.servedRows, [...this.renderRoot.querySelectorAll('[part~="row"]')], this.drawnPage.length);
|
|
1007
|
+
}
|
|
1008
|
+
this.servedLast = this.serving;
|
|
989
1009
|
this.announceSort();
|
|
990
1010
|
this.quietControls();
|
|
991
1011
|
this.placeFocus();
|
|
@@ -1186,7 +1206,9 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
1186
1206
|
}
|
|
1187
1207
|
render() {
|
|
1188
1208
|
const { available, matched, page } = this.view;
|
|
1189
|
-
|
|
1209
|
+
const serving = this.serves();
|
|
1210
|
+
this.serving = serving;
|
|
1211
|
+
this.drawnPage = serving ? [] : page;
|
|
1190
1212
|
this.moreDrawn = this.loadMore && !this.loading && this.errorText === '' && page.length > 0;
|
|
1191
1213
|
const rows = this.windowOf(page);
|
|
1192
1214
|
const kept = this.keptRow(page);
|
|
@@ -1196,7 +1218,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
1196
1218
|
const columns = this.shownColumns;
|
|
1197
1219
|
const pagination = this.tag('pagination');
|
|
1198
1220
|
const counted = this.mode === 'server' ? Math.max(this.total, available) : matched;
|
|
1199
|
-
const countKnown = counted > 0 || this.sourceKnown;
|
|
1221
|
+
const countKnown = counted > 0 || (this.sourceKnown && !serving);
|
|
1200
1222
|
this.counts = {
|
|
1201
1223
|
columns: columns.length ? columns.length + this.lead : undefined,
|
|
1202
1224
|
rows: countKnown ? counted + 1 + (this.moreDrawn ? 1 : 0) : undefined,
|
|
@@ -1210,13 +1232,19 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
1210
1232
|
@scroll=${this.handleScroll}
|
|
1211
1233
|
>
|
|
1212
1234
|
<div part="head" role="row" aria-rowindex="1">
|
|
1213
|
-
${this.rowGrips
|
|
1235
|
+
${this.rowGrips && this.sourceKnown
|
|
1236
|
+
? this.renderGripHead(headStop && this.currentColumn === 0)
|
|
1237
|
+
: nothing}${this.selectable && this.sourceKnown
|
|
1214
1238
|
? this.renderSelectAll(headStop && this.currentColumn === this.selectAt)
|
|
1215
1239
|
: nothing}${this.assignsByName && !this.hydrating
|
|
1216
1240
|
? this.orderedColumns.map((_, index) => html `<slot name=${`column-${index + 1}`} @slotchange=${this.handleSlotChange}></slot>`)
|
|
1217
|
-
: html `<slot name="columns" @slotchange=${this.handleSlotChange}></slot>`}
|
|
1241
|
+
: html `<slot name="columns" @slotchange=${this.handleSlotChange}></slot>`}${this.sourceKnown ? nothing : html `<slot @slotchange=${this.handleSlotChange}></slot>`}
|
|
1218
1242
|
</div>
|
|
1219
|
-
${
|
|
1243
|
+
${serving
|
|
1244
|
+
? this.sourceKnown
|
|
1245
|
+
? html `<slot @slotchange=${this.handleSlotChange}></slot>`
|
|
1246
|
+
: nothing
|
|
1247
|
+
: html `${this.renderSpacer('before', kept)}${this.renderRows(rows, page)}${this.renderSpacer('after', kept)}`}
|
|
1220
1248
|
${this.renderMore(page)}${this.errorText === '' ? this.renderStatus(filled, 'gridcell') : this.renderError()}
|
|
1221
1249
|
</div>
|
|
1222
1250
|
${this.errorText === '' ? this.renderLive(filled) : html `<span part="live" role="status">${this.errorText}</span>`}
|
|
@@ -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}
|
|
@@ -33,8 +33,9 @@ declare const HelixHeadlessFilterInput_base: (new (...args: any[]) => import("@f
|
|
|
33
33
|
* first colon, reads a leading `-` as the negation, and reads a word in
|
|
34
34
|
* brackets before the colon as the comparison.
|
|
35
35
|
*
|
|
36
|
-
* **Keyboard.** Focus stays in the text
|
|
37
|
-
* suggestion as its `aria-activedescendant
|
|
36
|
+
* **Keyboard.** Focus stays in the text, which is the field's one tab stop. The
|
|
37
|
+
* text names the highlighted suggestion as its `aria-activedescendant`, and the
|
|
38
|
+
* arrow keys reach the tokens.
|
|
38
39
|
*
|
|
39
40
|
* | Key | What it does |
|
|
40
41
|
* |---|---|
|
|
@@ -92,7 +93,8 @@ declare const HelixHeadlessFilterInput_base: (new (...args: any[]) => import("@f
|
|
|
92
93
|
* and removing the chip alone would leave its value ticked in the hidden
|
|
93
94
|
* menu. Its dismissal is treated as the field being filtered by nothing, so
|
|
94
95
|
* it fires `helix-facet` like every other change, and the chip goes when the
|
|
95
|
-
* filter goes.
|
|
96
|
+
* filter goes. Set `chips` and the field adds, updates, and removes those
|
|
97
|
+
* chips itself, from every `helix-facet` you do not cancel.
|
|
96
98
|
*
|
|
97
99
|
* @since 0.1.0
|
|
98
100
|
* @status stable
|
|
@@ -105,6 +107,8 @@ declare const HelixHeadlessFilterInput_base: (new (...args: any[]) => import("@f
|
|
|
105
107
|
* @slot feedback - The message that says what is wrong, for content richer than a string. It shows while there is a message.
|
|
106
108
|
* @slot hint - Help under the control, for content richer than the `hint` text.
|
|
107
109
|
* @slot label - The label, for content richer than the `label` text.
|
|
110
|
+
* @slot loading - What the panel shows while `loading` is set, for content richer than `loading-text`.
|
|
111
|
+
* @slot no-results - What the panel shows when `filter-suggestions` hides every suggestion, for content richer than `no-results-text`.
|
|
108
112
|
* @slot start - Content before the text, such as a search icon.
|
|
109
113
|
* @slot suggestions - Suggestions for what to type next, as `Option`s and `Option.Group`s.
|
|
110
114
|
* @slot tags - The active filters, as `FilterChip`s or `Tag`s.
|
|
@@ -121,17 +125,21 @@ declare const HelixHeadlessFilterInput_base: (new (...args: any[]) => import("@f
|
|
|
121
125
|
*
|
|
122
126
|
* @csspart clear - The button that empties the field.
|
|
123
127
|
* @csspart control - The input itself.
|
|
128
|
+
* @csspart empty - Shown in the panel when `filter-suggestions` hides every suggestion.
|
|
124
129
|
* @csspart feedback - The error message under the field.
|
|
125
130
|
* @csspart field - The box that holds everything.
|
|
126
131
|
* @csspart hint - The help text under the field, shown while there is no error.
|
|
127
132
|
* @csspart label - The label above the field.
|
|
128
133
|
* @csspart lead - The box before the text that holds the `start` slot.
|
|
129
134
|
* @csspart live - The live region that says how many suggestions the open panel offers. It is rendered from the first time the panel opens with suggestions.
|
|
135
|
+
* @csspart loading - Shown in the panel while the suggestions load.
|
|
130
136
|
* @csspart rest - The count of tokens that did not fit. It is a `<button>` with `expandable` and a `<span>` without it.
|
|
131
137
|
* @csspart surface - The floating panel the suggestions sit in.
|
|
132
138
|
* @csspart tags - The row the tokens sit in.
|
|
133
139
|
*
|
|
134
140
|
* @cssstate invalid - The field has an error to show, from the browser's validation or from your `feedback`.
|
|
141
|
+
* @cssstate loading - While `loading` is set.
|
|
142
|
+
* @cssstate no-results - `filter-suggestions` hid every suggestion, and `no-results-text` or the `no-results` slot says so.
|
|
135
143
|
* @cssstate open - The suggestions are open.
|
|
136
144
|
*/
|
|
137
145
|
export declare class HelixHeadlessFilterInput extends HelixHeadlessFilterInput_base {
|
|
@@ -143,6 +151,20 @@ export declare class HelixHeadlessFilterInput extends HelixHeadlessFilterInput_b
|
|
|
143
151
|
protected readonly aria: AriaForwardController;
|
|
144
152
|
/** Typed, so every keystroke is announced. See `announcesInput`. */
|
|
145
153
|
protected readonly announcesInput = true;
|
|
154
|
+
/**
|
|
155
|
+
* Whether the field keeps a `FilterChip` for each filter in its `tags` slot,
|
|
156
|
+
* from the `helix-facet` events it hears.
|
|
157
|
+
*
|
|
158
|
+
* Off, you build the chips, which is what you do when your own model holds
|
|
159
|
+
* the filters. On, a filter typed, picked, or changed adds or updates the
|
|
160
|
+
* chip for its field, one with no values takes it away (unless its
|
|
161
|
+
* comparison takes none, such as "is empty"), and removing the chip clears
|
|
162
|
+
* the filter. A `helix-facet` you cancel changes no chip.
|
|
163
|
+
*
|
|
164
|
+
* The chips are elements the field adds to its own children, so leave this
|
|
165
|
+
* off where a framework renders those children and would remove them.
|
|
166
|
+
*/
|
|
167
|
+
chips: boolean;
|
|
146
168
|
/**
|
|
147
169
|
* Shows a button that empties the field.
|
|
148
170
|
*
|
|
@@ -163,6 +185,27 @@ export declare class HelixHeadlessFilterInput extends HelixHeadlessFilterInput_b
|
|
|
163
185
|
* what you slot and you narrow it.
|
|
164
186
|
*/
|
|
165
187
|
filterSuggestions: boolean;
|
|
188
|
+
/**
|
|
189
|
+
* Whether the suggestions are still loading, such as while a request for the
|
|
190
|
+
* values of a typed key is out.
|
|
191
|
+
*
|
|
192
|
+
* The panel opens on `loading-text`, or the `loading` slot, while the field
|
|
193
|
+
* has focus, and a screen reader hears it. Slot the options and clear this
|
|
194
|
+
* when they arrive.
|
|
195
|
+
*/
|
|
196
|
+
loading: boolean;
|
|
197
|
+
/**
|
|
198
|
+
* Text the panel shows while the suggestions load.
|
|
199
|
+
*/
|
|
200
|
+
loadingText: string;
|
|
201
|
+
/**
|
|
202
|
+
* Text the panel shows when `filter-suggestions` hides every suggestion, such
|
|
203
|
+
* as "No matching filters".
|
|
204
|
+
*
|
|
205
|
+
* Empty, or no `no-results` slot, and the panel closes instead, as it does
|
|
206
|
+
* when it has nothing to offer.
|
|
207
|
+
*/
|
|
208
|
+
noResultsText: string;
|
|
166
209
|
/**
|
|
167
210
|
* The text shown while the field is empty.
|
|
168
211
|
*
|
|
@@ -341,6 +384,16 @@ export declare class HelixHeadlessFilterInput extends HelixHeadlessFilterInput_b
|
|
|
341
384
|
* else could have said it.
|
|
342
385
|
*/
|
|
343
386
|
private announceFacet;
|
|
387
|
+
/**
|
|
388
|
+
* Keeps the chip for a filter in step with it, under `chips`.
|
|
389
|
+
*
|
|
390
|
+
* After every listener has had its turn, so a consumer's `preventDefault()`
|
|
391
|
+
* on the same event, on this element or above it, is read: `dispatchEvent`
|
|
392
|
+
* runs them all before the microtask does.
|
|
393
|
+
*/
|
|
394
|
+
private readonly handleFacet;
|
|
395
|
+
/** Adds, updates or removes the chip for one filter. See `chips`. */
|
|
396
|
+
private drawChip;
|
|
344
397
|
/**
|
|
345
398
|
* A chip asking to go, answered as the filter going.
|
|
346
399
|
*
|
|
@@ -413,6 +466,12 @@ export declare class HelixHeadlessFilterInput extends HelixHeadlessFilterInput_b
|
|
|
413
466
|
* is why `settleOpen` is not called from here.
|
|
414
467
|
*/
|
|
415
468
|
private refreshSuggesting;
|
|
469
|
+
/**
|
|
470
|
+
* Whether `filter-suggestions` has hidden every suggestion there is, where a
|
|
471
|
+
* `no-results-text` or a `no-results` slot says so. The panel stays open on
|
|
472
|
+
* it, and `:state(no-results)` is on the host.
|
|
473
|
+
*/
|
|
474
|
+
private get unmatched();
|
|
416
475
|
/** The panel again, whenever what is in it changes. */
|
|
417
476
|
private readonly handleSuggestions;
|
|
418
477
|
/** Focus arriving in the field is a reader asking what they can type. */
|
|
@@ -426,7 +485,15 @@ export declare class HelixHeadlessFilterInput extends HelixHeadlessFilterInput_b
|
|
|
426
485
|
private readonly handleFocusOut;
|
|
427
486
|
/** The leading box again, whenever what is in front of the text changes. */
|
|
428
487
|
private readonly handleLeading;
|
|
429
|
-
/**
|
|
488
|
+
/**
|
|
489
|
+
* The row again, whenever what is in it changes.
|
|
490
|
+
*
|
|
491
|
+
* **And the text is the field's one tab stop.** Each token's remove button
|
|
492
|
+
* was a stop of its own, so Tab through a field with five filters took six
|
|
493
|
+
* presses. A `Tag` or `FilterChip` takes `dismissTabStop` for this, as the
|
|
494
|
+
* tags of a `multiple` Combobox do, and the arrow keys still reach every one.
|
|
495
|
+
* A token not yet defined is told once it is.
|
|
496
|
+
*/
|
|
430
497
|
private readonly handleTokens;
|
|
431
498
|
/** The tokens slotted in `tags`, which the arrow keys reach from the text. */
|
|
432
499
|
protected tokenElements(): HTMLElement[];
|