@fusion.dev/helix-headless 0.179.0 → 0.180.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 +160 -50
- package/dist/chat/composer/chat-composer.d.ts +2 -1
- package/dist/chat/composer/chat-composer.js +1 -1
- package/dist/combobox/root/combobox-root.d.ts +12 -0
- package/dist/combobox/root/combobox-root.js +3 -2
- package/dist/command/root/command-root.d.ts +12 -0
- package/dist/command/root/command-root.js +3 -2
- package/dist/data-table/root/data-table-root.d.ts +13 -1
- package/dist/data-table/root/data-table-root.js +18 -15
- package/dist/date-input/root/date-input-root.d.ts +7 -0
- package/dist/date-input/root/date-input-root.js +12 -0
- package/dist/date-picker/root/date-picker-root.d.ts +7 -1
- package/dist/date-picker/root/date-picker-root.js +12 -0
- package/dist/drilldown/root/drilldown-root.js +9 -0
- package/dist/filter-input/root/filter-input-root.d.ts +13 -0
- package/dist/filter-input/root/filter-input-root.js +2 -1
- package/dist/listbox/root/listbox-root.d.ts +16 -2
- package/dist/listbox/root/listbox-root.js +8 -4
- package/dist/meter/root/meter-root.js +1 -2
- package/dist/notifications/notification/notification.js +14 -1
- package/dist/option/among.d.ts +23 -0
- package/dist/option/among.js +2 -0
- package/dist/option/root/option-root.d.ts +1 -17
- package/dist/option/root/option-root.js +1 -4
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +5 -4
- package/dist/scatter-chart/root/scatter-chart-root.js +1 -0
- package/dist/select/root/select-root.d.ts +13 -2
- package/dist/select/root/select-root.js +3 -3
- package/dist/table/column/table-column.d.ts +1 -10
- package/dist/table/column/table-column.js +1 -2
- package/dist/table/edge.d.ts +10 -0
- package/dist/table/edge.js +2 -0
- package/dist/tabs/root/tabs-root.d.ts +1 -0
- package/dist/tabs/root/tabs-root.js +13 -0
- package/dist/tooltip/root/tooltip-root.js +1 -0
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +210 -16
- package/types/vue.d.ts +25 -11
- package/types/words.d.ts +14 -0
|
@@ -4,11 +4,11 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import { customElement, drawStatus, HelixElement, HelixSelectEvent, MixinControllerOpen, matchesChord, StatusController, words, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { auditChildren, customElement, drawStatus, HelixElement, HelixSelectEvent, MixinControllerOpen, matchesChord, StatusController, words, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { nothing } from 'lit';
|
|
9
9
|
import { property, state } from 'lit/decorators.js';
|
|
10
10
|
import { html } from 'lit/static-html.js';
|
|
11
|
-
import { optionsAmong } from '../../option/
|
|
11
|
+
import { optionsAmong } from '../../option/among.js';
|
|
12
12
|
import '../../dialog/index.js';
|
|
13
13
|
import '../../listbox/index.js';
|
|
14
14
|
const says = (element, state) => {
|
|
@@ -145,6 +145,7 @@ let HelixHeadlessCommand = class HelixHeadlessCommand extends MixinControllerOpe
|
|
|
145
145
|
}
|
|
146
146
|
connectedCallback() {
|
|
147
147
|
super.connectedCallback();
|
|
148
|
+
auditChildren(this, 'option', 'option', 'the palette lists no commands');
|
|
148
149
|
this.addEventListener('helix-select', this.swallowOptionSelect);
|
|
149
150
|
this.addEventListener('keydown', this.handleAlternate, { capture: true });
|
|
150
151
|
this.addEventListener('keydown', this.handleBack);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type DataRow, HelixElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
-
import {
|
|
3
|
+
import type { HelixHeadlessTableColumn } from '../../table/column/table-column.js';
|
|
4
4
|
import '../../checkbox/index.js';
|
|
5
5
|
import '../../pagination/index.js';
|
|
6
6
|
declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fusion.dev/helix-core").CollectionElement) & typeof HelixElement;
|
|
@@ -131,6 +131,18 @@ declare const HelixHeadlessDataTable_base: (new (...args: any[]) => import("@fus
|
|
|
131
131
|
* Written on `DataTable`, `columns` has no effect, so watch for it when you
|
|
132
132
|
* move a table from `Table` to `DataTable`.
|
|
133
133
|
*
|
|
134
|
+
* **The columns are an import of their own.** A column is the Table family's
|
|
135
|
+
* `TableColumn`, which the data table does not register, so a page that writes
|
|
136
|
+
* one imports the Table entry beside the data table:
|
|
137
|
+
*
|
|
138
|
+
* ```js
|
|
139
|
+
* import '@fusion.dev/helix/data-table'
|
|
140
|
+
* import '@fusion.dev/helix/table'
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* In development, a data table holding a column nobody registered says so once
|
|
144
|
+
* the page has loaded, with the line to add.
|
|
145
|
+
*
|
|
134
146
|
* @since 0.1.0
|
|
135
147
|
* @status stable
|
|
136
148
|
* @category data
|
|
@@ -5,14 +5,14 @@ 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, 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';
|
|
8
|
+
import { anchorAt, arranged, auditChildren, 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, whenHydrated, 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';
|
|
12
12
|
import { repeat } from 'lit/directives/repeat.js';
|
|
13
13
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
14
14
|
import { html } from 'lit/static-html.js';
|
|
15
|
-
import { edgeOf } from '../../table/
|
|
15
|
+
import { edgeOf } from '../../table/edge.js';
|
|
16
16
|
import '../../checkbox/index.js';
|
|
17
17
|
import '../../pagination/index.js';
|
|
18
18
|
import { toggledOpen } from '../keys.js';
|
|
@@ -1021,19 +1021,21 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
1021
1021
|
const shown = this.shownColumns;
|
|
1022
1022
|
const android = onAndroid();
|
|
1023
1023
|
for (const column of this.tableColumns) {
|
|
1024
|
-
column
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
? '
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1024
|
+
whenHydrated(column, () => {
|
|
1025
|
+
column.movable = this.reorderable && column.field !== '';
|
|
1026
|
+
column.gridCell = true;
|
|
1027
|
+
column.tabStop = shown.indexOf(column) + offset === stop;
|
|
1028
|
+
column.sorted =
|
|
1029
|
+
current && column.canSort && column.field === current.field
|
|
1030
|
+
? current.direction === 'asc'
|
|
1031
|
+
? 'ascending'
|
|
1032
|
+
: 'descending'
|
|
1033
|
+
: undefined;
|
|
1034
|
+
column.sortWords =
|
|
1035
|
+
android && column.sorted
|
|
1036
|
+
? this.sortSaid(column.textContent?.trim() || column.field, column.sorted)
|
|
1037
|
+
: '';
|
|
1038
|
+
});
|
|
1037
1039
|
}
|
|
1038
1040
|
}
|
|
1039
1041
|
renderCell(column, row, picked, place, stop, header, id) {
|
|
@@ -1276,6 +1278,7 @@ let HelixHeadlessDataTable = class HelixHeadlessDataTable extends MixinCollectio
|
|
|
1276
1278
|
}
|
|
1277
1279
|
connectedCallback() {
|
|
1278
1280
|
super.connectedCallback();
|
|
1281
|
+
auditChildren(this, 'table-column', 'table', 'the table draws no columns');
|
|
1279
1282
|
this.addEventListener('click', this.handleHeadClick);
|
|
1280
1283
|
this.addEventListener('click', this.handleRowClick);
|
|
1281
1284
|
this.addEventListener('pointerdown', this.notePress, true);
|
|
@@ -33,6 +33,8 @@ declare const HelixHeadlessDateInput_base: (new (...args: any[]) => import("@fus
|
|
|
33
33
|
* digits or the arrow keys. Alt+Down opens the calendar from a segment. A
|
|
34
34
|
* `range` is two rows with a dash between them, the start and the end, as
|
|
35
35
|
* React Aria's DateRangePicker draws them, and `multiple` keeps the text.
|
|
36
|
+
* A range whose end is before its start reports `rangeUnderflow`, as Date
|
|
37
|
+
* Picker does, with `range-order-message`.
|
|
36
38
|
*
|
|
37
39
|
* Text that is not a date gives the form an empty value, as a native date
|
|
38
40
|
* field does, and `value` keeps the text so it can be corrected.
|
|
@@ -359,6 +361,11 @@ export declare class HelixHeadlessDateInput extends HelixHeadlessDateInput_base
|
|
|
359
361
|
* for the page's language, then the English.
|
|
360
362
|
*/
|
|
361
363
|
rangeLengthMessage: string;
|
|
364
|
+
/**
|
|
365
|
+
* The message shown when a range ends before it starts. `{start}` is
|
|
366
|
+
* replaced with the start, written the way the field writes dates.
|
|
367
|
+
*/
|
|
368
|
+
rangeOrderMessage: string;
|
|
362
369
|
/**
|
|
363
370
|
* The message shown when a date is after `max`. `{max}` is replaced with
|
|
364
371
|
* `max`, written the way the field writes dates.
|
|
@@ -47,6 +47,7 @@ let HelixHeadlessDateInput = class HelixHeadlessDateInput extends MixinSegmented
|
|
|
47
47
|
this.previousYearLabel = 'Previous year';
|
|
48
48
|
this.previousYearsLabel = 'Earlier years';
|
|
49
49
|
this.rangeLengthMessage = 'A range is two dates.';
|
|
50
|
+
this.rangeOrderMessage = 'Choose an end on or after {start}.';
|
|
50
51
|
this.rangeOverflowMessage = 'Choose a date on or before {max}.';
|
|
51
52
|
this.rangeUnderflowMessage = 'Choose a date on or after {min}.';
|
|
52
53
|
this.removeLabel = 'Remove {name}';
|
|
@@ -263,6 +264,13 @@ let HelixHeadlessDateInput = class HelixHeadlessDateInput extends MixinSegmented
|
|
|
263
264
|
if (this.mode === 'range' && held.length > 2) {
|
|
264
265
|
return this.rangeLengthMessage;
|
|
265
266
|
}
|
|
267
|
+
const [start, end] = held;
|
|
268
|
+
if (this.mode === 'range' && start !== undefined && end !== undefined && end < start) {
|
|
269
|
+
return [
|
|
270
|
+
'rangeUnderflow',
|
|
271
|
+
formatWords(this, 'rangeOrderMessage', { start: this.written(start) }),
|
|
272
|
+
];
|
|
273
|
+
}
|
|
266
274
|
return '';
|
|
267
275
|
}
|
|
268
276
|
renderPicker() {
|
|
@@ -547,6 +555,10 @@ __decorate([
|
|
|
547
555
|
words,
|
|
548
556
|
property({ attribute: 'range-length-message' })
|
|
549
557
|
], HelixHeadlessDateInput.prototype, "rangeLengthMessage", void 0);
|
|
558
|
+
__decorate([
|
|
559
|
+
words,
|
|
560
|
+
property({ attribute: 'range-order-message' })
|
|
561
|
+
], HelixHeadlessDateInput.prototype, "rangeOrderMessage", void 0);
|
|
550
562
|
__decorate([
|
|
551
563
|
words,
|
|
552
564
|
property({ attribute: 'range-overflow-message' })
|
|
@@ -48,7 +48,8 @@ declare const HelixHeadlessDatePicker_base: (new (...args: any[]) => import("@fu
|
|
|
48
48
|
* when Previous or Next is pressed. Neither moves past `min` or `max`, and the
|
|
49
49
|
* keys stop at them too. A value outside the bounds, on a barred day, or off
|
|
50
50
|
* `step` reports `rangeUnderflow`, `rangeOverflow`, `badInput` or
|
|
51
|
-
* `stepMismatch`, so a form does not submit it.
|
|
51
|
+
* `stepMismatch`, so a form does not submit it. A range set from a script
|
|
52
|
+
* whose end is before its start reports `rangeUnderflow` as well.
|
|
52
53
|
*
|
|
53
54
|
* @since 0.1.0
|
|
54
55
|
* @status stable
|
|
@@ -278,6 +279,11 @@ export declare class HelixHeadlessDatePicker extends HelixHeadlessDatePicker_bas
|
|
|
278
279
|
* Accessible name for the control that moves back a page, in the years.
|
|
279
280
|
*/
|
|
280
281
|
previousYearsLabel: string;
|
|
282
|
+
/**
|
|
283
|
+
* The validation message for a range that ends before it starts. `{start}`
|
|
284
|
+
* is replaced with the start, written as a date in `locale`.
|
|
285
|
+
*/
|
|
286
|
+
rangeOrderMessage: string;
|
|
281
287
|
/**
|
|
282
288
|
* The validation message for a date after `max`. `{max}` is replaced with
|
|
283
289
|
* `max`, written as a date in `locale`.
|
|
@@ -44,6 +44,7 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
|
|
|
44
44
|
this.previousLabel = 'Previous month';
|
|
45
45
|
this.previousYearLabel = 'Previous year';
|
|
46
46
|
this.previousYearsLabel = 'Earlier years';
|
|
47
|
+
this.rangeOrderMessage = 'Choose an end on or after {start}.';
|
|
47
48
|
this.rangeOverflowMessage = 'Choose a date on or before {max}.';
|
|
48
49
|
this.focused = '';
|
|
49
50
|
this.choosing = false;
|
|
@@ -504,6 +505,13 @@ let HelixHeadlessDatePicker = class HelixHeadlessDatePicker extends MixinPickerF
|
|
|
504
505
|
return [{ [fault[0]]: true }, fault[1]];
|
|
505
506
|
}
|
|
506
507
|
}
|
|
508
|
+
const [start, end] = held;
|
|
509
|
+
if (this.mode === 'range' && start !== undefined && end !== undefined && end < start) {
|
|
510
|
+
return [
|
|
511
|
+
{ rangeUnderflow: true },
|
|
512
|
+
formatWords(this, 'rangeOrderMessage', { start: this.spoken(start) }),
|
|
513
|
+
];
|
|
514
|
+
}
|
|
507
515
|
return undefined;
|
|
508
516
|
}
|
|
509
517
|
get failure() {
|
|
@@ -855,6 +863,10 @@ __decorate([
|
|
|
855
863
|
words,
|
|
856
864
|
property({ attribute: 'previous-years-label' })
|
|
857
865
|
], HelixHeadlessDatePicker.prototype, "previousYearsLabel", void 0);
|
|
866
|
+
__decorate([
|
|
867
|
+
words,
|
|
868
|
+
property({ attribute: 'range-order-message' })
|
|
869
|
+
], HelixHeadlessDatePicker.prototype, "rangeOrderMessage", void 0);
|
|
858
870
|
__decorate([
|
|
859
871
|
words,
|
|
860
872
|
property({ attribute: 'range-overflow-message' })
|
|
@@ -158,8 +158,17 @@ let HelixHeadlessDrilldown = class HelixHeadlessDrilldown extends MixinCollectio
|
|
|
158
158
|
willUpdate(changed) {
|
|
159
159
|
super.willUpdate(changed);
|
|
160
160
|
if (changed.has('page') && (this.drilldown.page?.value ?? '') !== this.page) {
|
|
161
|
+
const leaving = this.drilldown.page;
|
|
162
|
+
const focused = this.contains(document.activeElement);
|
|
161
163
|
this.showPage(this.page);
|
|
162
164
|
this.page = this.drilldown.page?.value ?? '';
|
|
165
|
+
if (focused) {
|
|
166
|
+
this.updateComplete.then(() => {
|
|
167
|
+
const items = this.items;
|
|
168
|
+
const to = leaving && items.includes(leaving) ? leaving : items[0];
|
|
169
|
+
to?.focusItem();
|
|
170
|
+
});
|
|
171
|
+
}
|
|
163
172
|
}
|
|
164
173
|
hostAria(this.internals, {
|
|
165
174
|
label: this.navigation ? this.label : '',
|
|
@@ -128,6 +128,19 @@ declare const HelixHeadlessFilterInput_base: (new (...args: any[]) => import("@f
|
|
|
128
128
|
* filter goes. Set `chips` and the field adds, updates, and removes those
|
|
129
129
|
* chips itself, from every `helix-facet` you do not cancel.
|
|
130
130
|
*
|
|
131
|
+
* **The suggestions you write are an import of their own.** A suggestion is an
|
|
132
|
+
* option, the Option family's, which the field does not register, so a page
|
|
133
|
+
* that slots one imports it beside the field:
|
|
134
|
+
*
|
|
135
|
+
* ```js
|
|
136
|
+
* import '@fusion.dev/helix/filter-input'
|
|
137
|
+
* import '@fusion.dev/helix/option'
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* In development, a field holding an option nobody registered says so once the
|
|
141
|
+
* page has loaded, with the line to add. The options `source` gives are drawn
|
|
142
|
+
* as this Option too, and need the same import.
|
|
143
|
+
*
|
|
131
144
|
* @since 0.1.0
|
|
132
145
|
* @status stable
|
|
133
146
|
* @category forms
|
|
@@ -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, countLabel, customElement, DelayController, drawIcon, drawStatus, formatWords, HelixFacetEvent, HelixFormElement, holdCaret, MixinControllerOpen, MixinControllerValue, MixinField, MixinTokens, PopoverController, reportRuntime, restoreValue, StatusController, scrollItemIntoView, words, wordsLocale, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, auditChildren, countLabel, customElement, DelayController, drawIcon, drawStatus, formatWords, HelixFacetEvent, HelixFormElement, holdCaret, MixinControllerOpen, MixinControllerValue, MixinField, MixinTokens, PopoverController, reportRuntime, restoreValue, StatusController, scrollItemIntoView, words, wordsLocale, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { x } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { html, nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -552,6 +552,7 @@ let HelixHeadlessFilterInput = class HelixHeadlessFilterInput extends MixinContr
|
|
|
552
552
|
}
|
|
553
553
|
connectedCallback() {
|
|
554
554
|
super.connectedCallback();
|
|
555
|
+
auditChildren(this, 'option', 'option', 'the field suggests nothing');
|
|
555
556
|
this.addEventListener('helix-dismiss', this.handleDismiss, { capture: true });
|
|
556
557
|
this.addEventListener(HelixFacetEvent.eventName, this.handleFacet);
|
|
557
558
|
this.addEventListener('helix-select', this.handleSourcedSelect);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AriaForwardController, type DataOptionItem, DisabledCascadeController, HelixFormElement, UpgradeController } from '@fusion.dev/helix-core';
|
|
2
2
|
import { nothing, type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
-
import { HelixHeadlessOption } from '../../option/root/option-root.js';
|
|
3
|
+
import type { HelixHeadlessOption } from '../../option/root/option-root.js';
|
|
4
4
|
declare const HelixHeadlessListbox_base: (new (...args: any[]) => import("@fusion.dev/helix-core").CollectionElement) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
|
|
5
5
|
/**
|
|
6
6
|
* @summary A list of options, from which you choose one or several.
|
|
@@ -76,6 +76,19 @@ declare const HelixHeadlessListbox_base: (new (...args: any[]) => import("@fusio
|
|
|
76
76
|
* filter narrows the list, under `layout="grid"`, or while the list is
|
|
77
77
|
* disabled.
|
|
78
78
|
*
|
|
79
|
+
* **The options are an import of their own.** An option you write is the Option
|
|
80
|
+
* family's, which the list does not register, so a page that writes one imports
|
|
81
|
+
* it beside the list:
|
|
82
|
+
*
|
|
83
|
+
* ```js
|
|
84
|
+
* import '@fusion.dev/helix/listbox'
|
|
85
|
+
* import '@fusion.dev/helix/option'
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
88
|
+
* In development, a list holding an option nobody registered says so once the
|
|
89
|
+
* page has loaded, with the line to add. The options `items` draws are this
|
|
90
|
+
* Option too, and need the same import.
|
|
91
|
+
*
|
|
79
92
|
* @since 0.1.0
|
|
80
93
|
* @status stable
|
|
81
94
|
* @category forms
|
|
@@ -218,7 +231,8 @@ export declare class HelixHeadlessListbox extends HelixHeadlessListbox_base {
|
|
|
218
231
|
*
|
|
219
232
|
* **The list needs a height to scroll in**: the styled tier's
|
|
220
233
|
* `--listbox-max-block-size`, or a `max-block-size` on `::part(items)` in the
|
|
221
|
-
* headless tier.
|
|
234
|
+
* headless tier. The options drawn are this tier's Option, which the page
|
|
235
|
+
* imports, as it imports the options it writes.
|
|
222
236
|
* A server sends the list empty, and the options are drawn once it hydrates.
|
|
223
237
|
*/
|
|
224
238
|
items: readonly DataOptionItem[] | undefined;
|
|
@@ -4,12 +4,12 @@ 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, centerInView, chosenValues, columnStep, countLabel, customElement, DelayController, DisabledCascadeController, drawAutofill, endInSight, filterKeeps, formatWords, HelixFilterEvent, HelixFormElement, HelixLoadMoreEvent, hostAria, inlineStep, MixinCollection, MixinControllerValue, MixinField, markMatches, OptionWindowController, onApple, pageRows, rangeAdd, reportValues, requestChange, scrollItemIntoView, selectsAll, Typeahead, toggleEvery, typesCharacter, UpgradeController, words, wordsLocale, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, auditChildren, centerInView, chosenValues, columnStep, countLabel, customElement, DelayController, DisabledCascadeController, drawAutofill, endInSight, filterKeeps, formatWords, HelixFilterEvent, HelixFormElement, HelixLoadMoreEvent, hostAria, inlineStep, MixinCollection, MixinControllerValue, MixinField, markMatches, OptionWindowController, onApple, pageRows, rangeAdd, reportValues, requestChange, scrollItemIntoView, selectsAll, Typeahead, toggleEvery, typesCharacter, UpgradeController, words, wordsLocale, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { magnifyingGlass } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { html, nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
11
11
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
12
|
-
import {
|
|
12
|
+
import { isOption } from '../../option/among.js';
|
|
13
13
|
const FIELD_MOVES = new Set(['ArrowDown', 'ArrowUp', 'PageDown', 'PageUp']);
|
|
14
14
|
const MOVES = new Set([...FIELD_MOVES, 'End', 'Home']);
|
|
15
15
|
const PAGE = 10;
|
|
@@ -306,7 +306,7 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
|
|
|
306
306
|
return this.multiple ? 'select-multiple' : 'select-one';
|
|
307
307
|
}
|
|
308
308
|
get options() {
|
|
309
|
-
return this.among(
|
|
309
|
+
return this.among(isOption, this.children);
|
|
310
310
|
}
|
|
311
311
|
among(is, nodes) {
|
|
312
312
|
const found = [];
|
|
@@ -421,7 +421,7 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
|
|
|
421
421
|
option.selected = chosen.has(option.value);
|
|
422
422
|
}
|
|
423
423
|
for (const group of this.groups) {
|
|
424
|
-
const inside = this.among(
|
|
424
|
+
const inside = this.among(isOption, group.children);
|
|
425
425
|
group.hidden = inside.length > 0 && inside.every((option) => option.hidden);
|
|
426
426
|
}
|
|
427
427
|
for (const rule of this.among((node) => node.localName.endsWith('-option-separator'), this.children)) {
|
|
@@ -479,6 +479,7 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
|
|
|
479
479
|
this.addEventListener('helix-select', this.handleSelection);
|
|
480
480
|
this.addEventListener('keydown', this.handleKeydown);
|
|
481
481
|
this.addEventListener('click', this.handleClick, true);
|
|
482
|
+
auditChildren(this, 'option', 'option', 'the list offers no choices');
|
|
482
483
|
}
|
|
483
484
|
disconnectedCallback() {
|
|
484
485
|
super.disconnectedCallback();
|
|
@@ -500,6 +501,9 @@ let HelixHeadlessListbox = class HelixHeadlessListbox extends MixinCollection(Mi
|
|
|
500
501
|
if (this.childrenKnown) {
|
|
501
502
|
this.seedDeclared();
|
|
502
503
|
}
|
|
504
|
+
if (changed.has('items') && this.items) {
|
|
505
|
+
auditChildren(this, 'option', 'option', 'the items draw no choices', true);
|
|
506
|
+
}
|
|
503
507
|
if (this.childrenKnown) {
|
|
504
508
|
this.place();
|
|
505
509
|
this.tell(changed);
|
|
@@ -83,8 +83,7 @@ let HelixHeadlessMeter = class HelixHeadlessMeter extends HelixElement {
|
|
|
83
83
|
this.internals.ariaValueMin = String(min);
|
|
84
84
|
this.internals.ariaValueMax = String(max);
|
|
85
85
|
this.internals.ariaValueNow = String(this.reading);
|
|
86
|
-
this.internals.ariaValueText =
|
|
87
|
-
this.valueText || this.formatOptions !== undefined || this.beyond ? this.text : null;
|
|
86
|
+
this.internals.ariaValueText = this.text;
|
|
88
87
|
const band = this.computedBand;
|
|
89
88
|
const beyond = this.beyond;
|
|
90
89
|
this.toggleState('fair', band === 'fair');
|
|
@@ -31,8 +31,14 @@ let HelixHeadlessNotification = class HelixHeadlessNotification extends MixinDis
|
|
|
31
31
|
event.stopPropagation();
|
|
32
32
|
if (this.dismiss()) {
|
|
33
33
|
const next = deepContains(this, deepActiveElement()) ? this.neighbor() : null;
|
|
34
|
+
const holder = this.parentElement;
|
|
34
35
|
this.remove();
|
|
35
36
|
next?.focus();
|
|
37
|
+
if (next && next.getRootNode().activeElement !== next) {
|
|
38
|
+
void Promise.resolve()
|
|
39
|
+
.then(() => holder?.updateComplete)
|
|
40
|
+
.then(() => next.focus());
|
|
41
|
+
}
|
|
36
42
|
}
|
|
37
43
|
};
|
|
38
44
|
}
|
|
@@ -154,7 +160,14 @@ let HelixHeadlessNotification = class HelixHeadlessNotification extends MixinDis
|
|
|
154
160
|
? feed.items
|
|
155
161
|
: [...(this.parentElement?.children ?? [])].filter((one) => 'isNotification' in one);
|
|
156
162
|
const at = rows.indexOf(this);
|
|
157
|
-
const
|
|
163
|
+
const group = this.parentElement;
|
|
164
|
+
const promoted = group && 'isNotificationGroup' in group && this.assignedSlot !== null
|
|
165
|
+
? [...group.children].find((one) => one !== this && 'isNotification' in one)
|
|
166
|
+
: undefined;
|
|
167
|
+
const drawn = (row) => !('isNotificationGroup' in (row.parentElement ?? {})) ||
|
|
168
|
+
row.assignedSlot !== null ||
|
|
169
|
+
row === promoted;
|
|
170
|
+
const order = [...rows.slice(at + 1), ...rows.slice(0, Math.max(at, 0)).reverse()].filter(drawn);
|
|
158
171
|
for (const row of order) {
|
|
159
172
|
const target = row.shadowRoot?.querySelector('[part="item"]');
|
|
160
173
|
if (target) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { HelixHeadlessOption } from './root/option-root.js';
|
|
2
|
+
/**
|
|
3
|
+
* Whether an element is an option, by its shape.
|
|
4
|
+
*
|
|
5
|
+
* **Not by `instanceof`.** A tag is defined once, by whichever copy of this
|
|
6
|
+
* class registered it first, and a second copy in the same document tests
|
|
7
|
+
* against a class no element on the page has: every option failed it, and a
|
|
8
|
+
* select said "Choose" over its value. Two copies are a consumer with a
|
|
9
|
+
* duplicated dependency, or the browser specs, where each family's bundle
|
|
10
|
+
* carries its own and they share one page. An option nobody registered has no
|
|
11
|
+
* such shape, and is no option until its entry is imported.
|
|
12
|
+
*/
|
|
13
|
+
export declare const isOption: (element: Element) => element is HelixHeadlessOption;
|
|
14
|
+
/**
|
|
15
|
+
* The options among some elements, reaching one level into a group.
|
|
16
|
+
*
|
|
17
|
+
* What a control holding options reads its words from, off its own children
|
|
18
|
+
* rather than off the listbox they are slotted into: the slot exists only once a
|
|
19
|
+
* render has made it, so the listbox has none on a first render, and on a page a
|
|
20
|
+
* server rendered the `slotchange` that would correct it fires before anything
|
|
21
|
+
* listens.
|
|
22
|
+
*/
|
|
23
|
+
export declare const optionsAmong: (elements: readonly Element[]) => HelixHeadlessOption[];
|
|
@@ -1,22 +1,6 @@
|
|
|
1
1
|
import { HelixElement, type LinkModifiers } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
-
|
|
4
|
-
* The options among some elements, reaching one level into a group.
|
|
5
|
-
*
|
|
6
|
-
* What a control holding options reads its words from, off its own children
|
|
7
|
-
* rather than off the listbox they are slotted into: the slot exists only once a
|
|
8
|
-
* render has made it, so the listbox has none on a first render, and on a page a
|
|
9
|
-
* server rendered the `slotchange` that would correct it fires before anything
|
|
10
|
-
* listens.
|
|
11
|
-
*
|
|
12
|
-
* **An option by its shape, not by `instanceof`.** A tag is defined once, by
|
|
13
|
-
* whichever copy of this class registered it first, and a second copy in the
|
|
14
|
-
* same document tests against a class no element on the page has: every option
|
|
15
|
-
* failed it, and a select said "Choose" over its value. Two copies are a
|
|
16
|
-
* consumer with a duplicated dependency, or the browser specs, where each
|
|
17
|
-
* family's bundle carries its own and they share one page.
|
|
18
|
-
*/
|
|
19
|
-
export declare const optionsAmong: (elements: readonly Element[]) => HelixHeadlessOption[];
|
|
3
|
+
export { isOption, optionsAmong } from '../among.js';
|
|
20
4
|
/**
|
|
21
5
|
* @summary One choice in a listbox.
|
|
22
6
|
*
|
|
@@ -7,10 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
import { customElement, followLink, HelixElement, HelixSelectEvent, hostAria, slotFilled, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
|
-
export
|
|
11
|
-
const isOption = (element) => 'text' in element && 'value' in element && 'selected' in element;
|
|
12
|
-
return elements.flatMap((element) => isOption(element) ? [element] : [...element.children].filter(isOption));
|
|
13
|
-
};
|
|
10
|
+
export { isOption, optionsAmong } from '../among.js';
|
|
14
11
|
let HelixHeadlessOption = class HelixHeadlessOption extends HelixElement {
|
|
15
12
|
constructor() {
|
|
16
13
|
super(...arguments);
|
|
@@ -62,9 +62,10 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
62
62
|
*
|
|
63
63
|
* The plot runs left to right in every text direction, as a number line does.
|
|
64
64
|
* The plot, its axes, and the axis names sit in a `plane` part with
|
|
65
|
-
* `dir="ltr"
|
|
66
|
-
*
|
|
67
|
-
*
|
|
65
|
+
* `dir="ltr"`, and the arrow keys follow the drawing: Right moves to the next
|
|
66
|
+
* point on a right-to-left page too. The axis names carry `dir="auto"`, so a
|
|
67
|
+
* name in Arabic or Hebrew reads in its own direction. The summary and the
|
|
68
|
+
* tooltip bubble follow the page's direction.
|
|
68
69
|
*
|
|
69
70
|
* **A tap shows the reading under it**, and keeps it until a tap lands
|
|
70
71
|
* elsewhere. `helix-reading-change` says each move of the reading, by pointer,
|
|
@@ -86,7 +87,7 @@ declare const HelixHeadlessScatterChart_base: typeof HelixElement & (new (...arg
|
|
|
86
87
|
* | Key | What it does |
|
|
87
88
|
* |---|---|
|
|
88
89
|
* | Tab | Moves focus to the plot and shows the first reading. |
|
|
89
|
-
* | Right, Left | Moves to the next or the previous point, left to right across the plot
|
|
90
|
+
* | Right, Left | Moves to the next or the previous point, left to right across the plot, on a right-to-left page too. |
|
|
90
91
|
* | Down, Up | Moves among the series of the point. With one series, moves to the next or the previous point. |
|
|
91
92
|
* | Home, End | Moves to the first or the last point. |
|
|
92
93
|
* | Page Down, Page Up | Moves a tenth of the points on or back. |
|
|
@@ -76,6 +76,7 @@ let HelixHeadlessScatterChart = class HelixHeadlessScatterChart extends MixinCha
|
|
|
76
76
|
connectedCallback() {
|
|
77
77
|
super.connectedCallback();
|
|
78
78
|
this.pointer.axis = 'none';
|
|
79
|
+
this.pointer.drawnLtr = true;
|
|
79
80
|
this.pointer.onReading = (heard, detail) => this.dispatchEvent(heard === 'press'
|
|
80
81
|
? new HelixReadingPressEvent(detail)
|
|
81
82
|
: new HelixReadingChangeEvent(detail));
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { AriaForwardController, type DataOptionItem, HelixFormElement, PopoverController, UpgradeController } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
-
import {
|
|
3
|
+
import type { HelixHeadlessOption } from '../../option/root/option-root.js';
|
|
4
4
|
import '../../listbox/index.js';
|
|
5
|
-
import '../../option/index.js';
|
|
6
5
|
declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
|
|
7
6
|
/**
|
|
8
7
|
* @summary A control that opens a list of options to choose from.
|
|
@@ -60,6 +59,18 @@ declare const HelixHeadlessSelect_base: (new (...args: any[]) => import("@fusion
|
|
|
60
59
|
* Set `autocomplete` to let a browser's autofill choose, as a native `<select>`
|
|
61
60
|
* with the same attribute would.
|
|
62
61
|
*
|
|
62
|
+
* **The options are an import of their own.** An option is the Option family's,
|
|
63
|
+
* which the select does not register, so a page that writes one imports it
|
|
64
|
+
* beside the select:
|
|
65
|
+
*
|
|
66
|
+
* ```js
|
|
67
|
+
* import '@fusion.dev/helix/select'
|
|
68
|
+
* import '@fusion.dev/helix/option'
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* In development, a select holding an option nobody registered says so once the
|
|
72
|
+
* page has loaded, with the line to add.
|
|
73
|
+
*
|
|
63
74
|
* @since 0.1.0
|
|
64
75
|
* @status stable
|
|
65
76
|
* @category forms
|
|
@@ -4,15 +4,14 @@ 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, chosenValues, customElement, dataOptions, drawAutofill, drawStatus, HelixFormElement, hostAria, hostWords, inlineStep, isRtl, MixinControllerOpen, MixinControllerValue, MixinField, onApple, PopoverController, reportValues, StatusController, sideOf, typesCharacter, UpgradeController, words, wordsLocale, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, afterLinkFollowed, auditChildren, chosenValues, customElement, dataOptions, drawAutofill, drawStatus, HelixFormElement, hostAria, hostWords, inlineStep, isRtl, MixinControllerOpen, MixinControllerValue, MixinField, onApple, PopoverController, reportValues, StatusController, sideOf, typesCharacter, 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 } from 'lit/decorators.js';
|
|
11
11
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
12
12
|
import { html } from 'lit/static-html.js';
|
|
13
|
-
import { optionsAmong } from '../../option/
|
|
13
|
+
import { optionsAmong } from '../../option/among.js';
|
|
14
14
|
import '../../listbox/index.js';
|
|
15
|
-
import '../../option/index.js';
|
|
16
15
|
import { over } from '../align.js';
|
|
17
16
|
let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(MixinControllerValue(MixinField(HelixFormElement))) {
|
|
18
17
|
constructor() {
|
|
@@ -210,6 +209,7 @@ let HelixHeadlessSelect = class HelixHeadlessSelect extends MixinControllerOpen(
|
|
|
210
209
|
}
|
|
211
210
|
connectedCallback() {
|
|
212
211
|
super.connectedCallback();
|
|
212
|
+
auditChildren(this, 'option', 'option', 'it offers no choices');
|
|
213
213
|
this.addEventListener('helix-select', this.handleLinkFollowed);
|
|
214
214
|
const words = new MutationObserver(() => this.requestUpdate());
|
|
215
215
|
words.observe(this, {
|
|
@@ -10,16 +10,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
10
10
|
* `undefined` falls back to the field.
|
|
11
11
|
*/
|
|
12
12
|
export type CellReader = (row: Readonly<Record<string, unknown>>) => unknown;
|
|
13
|
-
|
|
14
|
-
* The edge a column names, where it names one of the three.
|
|
15
|
-
*
|
|
16
|
-
* **`text-align` is a string anybody can write**, the union on the property being a
|
|
17
|
-
* compile-time claim and nothing else, and both tables put the value straight
|
|
18
|
-
* into CSS: `Table` into a rule in each row's shadow root, `DataTable` into the
|
|
19
|
-
* cell it draws. One guard, here with the property, rather than one in each
|
|
20
|
-
* table and only one of them written.
|
|
21
|
-
*/
|
|
22
|
-
export declare const edgeOf: (align: string | undefined) => string | undefined;
|
|
13
|
+
export { edgeOf } from '../edge.js';
|
|
23
14
|
/**
|
|
24
15
|
* @summary One column of a table: its heading, its width, and the field it reads from each row.
|
|
25
16
|
*
|
|
@@ -10,8 +10,7 @@ import { dotsSixVertical } from '@fusion.dev/helix-icons';
|
|
|
10
10
|
import { html, nothing } from 'lit';
|
|
11
11
|
import { property, state } from 'lit/decorators.js';
|
|
12
12
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
13
|
-
|
|
14
|
-
export const edgeOf = (align) => align && EDGES.has(align) ? align : undefined;
|
|
13
|
+
export { edgeOf } from '../edge.js';
|
|
15
14
|
let HelixHeadlessTableColumn = class HelixHeadlessTableColumn extends HelixElement {
|
|
16
15
|
constructor() {
|
|
17
16
|
super(...arguments);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The edge a column names, where it names one of the three.
|
|
3
|
+
*
|
|
4
|
+
* **`text-align` is a string anybody can write**, the union on the property being a
|
|
5
|
+
* compile-time claim and nothing else, and both tables put the value straight
|
|
6
|
+
* into CSS: `Table` into a rule in each row's shadow root, `DataTable` into the
|
|
7
|
+
* cell it draws. One guard, here with the property, rather than one in each
|
|
8
|
+
* table and only one of them written.
|
|
9
|
+
*/
|
|
10
|
+
export declare const edgeOf: (align: string | undefined) => string | undefined;
|
|
@@ -192,6 +192,7 @@ export declare class HelixHeadlessTabs extends HelixHeadlessTabs_base {
|
|
|
192
192
|
private refocus;
|
|
193
193
|
connectedCallback(): void;
|
|
194
194
|
disconnectedCallback(): void;
|
|
195
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
195
196
|
protected firstUpdated(changed: PropertyValues): void;
|
|
196
197
|
/** Watches the strip's size while `scroll-controls` asks, and reads it. */
|
|
197
198
|
private watchStrip;
|