@fusion.dev/helix-headless 0.163.0 → 0.165.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 +1068 -46
- package/dist/callout/root/callout-root.d.ts +43 -4
- package/dist/callout/root/callout-root.js +58 -2
- package/dist/code-block/patch.d.ts +42 -0
- package/dist/code-block/patch.js +118 -0
- package/dist/code-block/root/code-block-root.d.ts +37 -1
- package/dist/code-block/root/code-block-root.js +57 -9
- package/dist/color-picker/root/color-picker-root.d.ts +7 -3
- package/dist/color-picker/root/color-picker-root.js +7 -4
- package/dist/combobox/root/combobox-root.d.ts +1 -0
- package/dist/combobox/root/combobox-root.js +10 -1
- package/dist/data-table/root/data-table-root.d.ts +1 -0
- package/dist/data-table/root/data-table-root.js +1 -0
- package/dist/date-input/root/date-input-root.d.ts +3 -3
- package/dist/date-input/root/date-input-root.js +8 -5
- package/dist/element-events.generated.js +7 -1
- package/dist/format-date/root/format-date-root.d.ts +3 -1
- package/dist/format-date/root/format-date-root.js +4 -1
- package/dist/lightbox/item/lightbox-item.js +3 -1
- package/dist/lightbox/root/lightbox-root.d.ts +28 -0
- package/dist/lightbox/root/lightbox-root.js +21 -2
- package/dist/number-input/root/number-input-root.d.ts +32 -9
- package/dist/number-input/root/number-input-root.js +53 -9
- package/dist/object-inspector/root/object-inspector-root.d.ts +23 -0
- package/dist/object-inspector/root/object-inspector-root.js +19 -1
- package/dist/option/root/index.d.ts +1 -0
- package/dist/option/root/index.js +1 -0
- package/dist/table/grid-controller.d.ts +7 -0
- package/dist/table/grid-controller.js +15 -1
- package/dist/table/root/table-root.d.ts +10 -0
- package/dist/table/root/table-root.js +18 -1
- package/dist/tag/root/index.d.ts +1 -0
- package/dist/tag/root/index.js +1 -0
- package/dist/time-input/root/time-input-root.d.ts +4 -3
- package/dist/time-input/root/time-input-root.js +5 -4
- package/dist/time-picker/root/time-picker-root.d.ts +1 -1
- package/dist/time-picker/root/time-picker-root.js +5 -2
- package/dist/video/root/video-root.js +2 -1
- package/dist/video-playlist/item/video-playlist-item.d.ts +8 -0
- package/dist/video-playlist/item/video-playlist-item.js +7 -0
- package/dist/video-playlist/root/video-playlist-root.d.ts +60 -0
- package/dist/video-playlist/root/video-playlist-root.js +55 -1
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +388 -40
- package/types/vue.d.ts +95 -13
- package/types/words.d.ts +58 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './option-root.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './option-root.js';
|
|
@@ -42,6 +42,13 @@ export interface TableGridOptions {
|
|
|
42
42
|
* carry the selection selects the row there.
|
|
43
43
|
*/
|
|
44
44
|
arrive?: (to: number, control: boolean) => void;
|
|
45
|
+
/**
|
|
46
|
+
* Right or Left on the disclosure cell of drawn row `row`, `forward` for
|
|
47
|
+
* the key that moves on along the line. Says that it opened or shut the
|
|
48
|
+
* row, names the drawn row to move to, or says it did neither, which moves
|
|
49
|
+
* along the row as the key does on any cell.
|
|
50
|
+
*/
|
|
51
|
+
disclose?: (row: number, forward: boolean) => boolean | number;
|
|
45
52
|
/** Whether the table is a grid now. */
|
|
46
53
|
on: () => boolean;
|
|
47
54
|
}
|
|
@@ -71,10 +71,24 @@ export class TableGridController {
|
|
|
71
71
|
}
|
|
72
72
|
return;
|
|
73
73
|
}
|
|
74
|
+
const step = inlineStep(this.host, event.key);
|
|
75
|
+
if (step !== 0 &&
|
|
76
|
+
place.row >= 0 &&
|
|
77
|
+
!(event.shiftKey || event.ctrlKey || event.metaKey) &&
|
|
78
|
+
this.options.lead()[place.column] === 'expand') {
|
|
79
|
+
const done = this.options.disclose?.(place.row, step > 0) ?? false;
|
|
80
|
+
if (done !== false) {
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
if (typeof done === 'number') {
|
|
83
|
+
this.moveTo({ column: place.column, row: done });
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
74
88
|
const to = gridMove(event.key, place, { last: this.options.rows().length - 1, top: this.top, width: this.widthOf(place.row) }, {
|
|
75
89
|
control: event.ctrlKey || event.metaKey,
|
|
76
90
|
page: event.key.startsWith('Page') ? this.pageFrom(place.cell) : 1,
|
|
77
|
-
step
|
|
91
|
+
step,
|
|
78
92
|
});
|
|
79
93
|
if (!to) {
|
|
80
94
|
return;
|
|
@@ -111,6 +111,8 @@ declare const HelixHeadlessTable_base: (new (...args: any[]) => import("@fusion.
|
|
|
111
111
|
* | Enter, Space on a sortable heading | Sorts by the column. |
|
|
112
112
|
* | Space on a row, Enter or Space on its checkbox cell | Selects the row, in a `selectable` table. |
|
|
113
113
|
* | Enter or Space on a disclosure cell | Shows or hides the rows under the row, in a table whose rows nest. |
|
|
114
|
+
* | Right on a disclosure cell | Shows the rows under a shut row, and otherwise moves one cell along the row. Left does, on a right-to-left page. |
|
|
115
|
+
* | Left on a disclosure cell | Hides the rows under an open row, and moves to the row this one sits under from any other. |
|
|
114
116
|
* | Enter or Space on a grip cell | Picks the row up, or drops it, in a `reorderable` table. Up, Down, Home, and End move a row picked up, and Escape puts it back. |
|
|
115
117
|
* | Down, Up, Page Down, Page Up under `selection-behavior="replace"` | Selects the row it moves to alone. Control or Command with the key moves without selecting. |
|
|
116
118
|
* | Shift with Down or Up | Selects the rows it moves across, in a `selectable` table. |
|
|
@@ -184,6 +186,7 @@ declare const HelixHeadlessTable_base: (new (...args: any[]) => import("@fusion.
|
|
|
184
186
|
*
|
|
185
187
|
* @cssstate empty - While there are no rows and none are loading.
|
|
186
188
|
* @cssstate error - While `error-text` is set.
|
|
189
|
+
* @cssstate loading - While `loading` is set, as the rows are on their way.
|
|
187
190
|
*/
|
|
188
191
|
export declare class HelixHeadlessTable extends HelixHeadlessTable_base {
|
|
189
192
|
/**
|
|
@@ -534,6 +537,13 @@ export declare class HelixHeadlessTable extends HelixHeadlessTable_base {
|
|
|
534
537
|
private selectRange;
|
|
535
538
|
/** One row's checkbox, ticked or not. It becomes the row a range runs from. */
|
|
536
539
|
private chooseRow;
|
|
540
|
+
/**
|
|
541
|
+
* Right or Left on a disclosure cell, as on a tree's item and as Data
|
|
542
|
+
* Table's row headers do: on to open a shut row, back to shut an open one.
|
|
543
|
+
* Back on a row that is shut, or has no rows under it, moves to the row it
|
|
544
|
+
* sits under. Anything else moves along the row.
|
|
545
|
+
*/
|
|
546
|
+
private disclose;
|
|
537
547
|
/**
|
|
538
548
|
* Enter, Space or F2 on a cell of a `grid` table, and whether it did
|
|
539
549
|
* anything. Left alone, Enter and F2 move into the cell's controls.
|
|
@@ -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, anchorAt, assignSlots, commaList, customElement, cycle, everyState, followLink, format, formatWords, HelixBeforeToggleEvent, HelixElement, HelixLoadMoreEvent, HelixSelectEvent, HelixSelectedEvent, HelixSortEvent, HelixSortedEvent, HelixToggleEvent, inRowOrder, MixinCollection, onAndroid, parse, ReorderController, rangeAdd, reflectElements, requestChange, scrollingAncestor, sort, splitValues, toggleEvery, whenHydrated, words, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, anchorAt, assignSlots, commaList, customElement, cycle, everyState, followLink, format, formatWords, HelixBeforeToggleEvent, HelixElement, HelixLoadMoreEvent, HelixSelectEvent, HelixSelectedEvent, HelixSortEvent, HelixSortedEvent, HelixToggleEvent, inRowOrder, MixinCollection, onAndroid, parse, ReorderController, rangeAdd, reflectElements, requestChange, scrollingAncestor, sort, splitValues, toggleEvery, treeArrow, whenHydrated, 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';
|
|
@@ -94,6 +94,7 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
|
|
|
94
94
|
}
|
|
95
95
|
},
|
|
96
96
|
columns: () => this.tableColumns.filter((column) => column.shown),
|
|
97
|
+
disclose: (at, forward) => this.disclose(at, forward),
|
|
97
98
|
lead: () => this.lead,
|
|
98
99
|
on: () => this.grid,
|
|
99
100
|
part: (name) => this.partNamed(name),
|
|
@@ -471,6 +472,21 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
|
|
|
471
472
|
}
|
|
472
473
|
this.requestSelected(keys);
|
|
473
474
|
}
|
|
475
|
+
disclose(at, forward) {
|
|
476
|
+
const rows = this.arrangedRows;
|
|
477
|
+
const row = rows[at];
|
|
478
|
+
const found = this.keyed.find((one) => one.row === row);
|
|
479
|
+
if (!(row && found)) {
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
const arrow = treeArrow({ branch: row.branch ?? false, open: this.open.has(found.key) }, forward ? 1 : -1);
|
|
483
|
+
if (arrow === 'open' || arrow === 'close') {
|
|
484
|
+
this.toggleRow(found.key);
|
|
485
|
+
return true;
|
|
486
|
+
}
|
|
487
|
+
const parent = arrow === 'parent' ? rows.indexOf(this.rowFor(row.parent ?? '')) : -1;
|
|
488
|
+
return parent >= 0 ? parent : false;
|
|
489
|
+
}
|
|
474
490
|
activate(place, event) {
|
|
475
491
|
const leads = this.lead;
|
|
476
492
|
const lead = leads[place.column] === 'select';
|
|
@@ -697,6 +713,7 @@ let HelixHeadlessTable = class HelixHeadlessTable extends MixinCollection(HelixE
|
|
|
697
713
|
super.updated(changed);
|
|
698
714
|
this.toggleState('error', this.errorText !== '');
|
|
699
715
|
this.toggleState('empty', !this.loading && !this.hasRows);
|
|
716
|
+
this.toggleState('loading', this.loading);
|
|
700
717
|
this.assign();
|
|
701
718
|
this.alignCells();
|
|
702
719
|
this.markSorted();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './tag-root.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './tag-root.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AriaForwardController, HelixFormElement, type HourCycle } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
-
import '../../tag/index.js';
|
|
3
|
+
import '../../tag/root/index.js';
|
|
4
4
|
import '../../time-picker/index.js';
|
|
5
5
|
declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinSegmentedFieldInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinPickerEditingInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinPickerFieldInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerOpenInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinTokensInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinFieldInterface) & typeof HelixFormElement;
|
|
6
6
|
/**
|
|
@@ -349,8 +349,9 @@ export declare class HelixHeadlessTimeInput extends HelixHeadlessTimeInput_base
|
|
|
349
349
|
/**
|
|
350
350
|
* Each time, where `mode` holds several, sent one entry each.
|
|
351
351
|
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
352
|
+
* Text that is no time, such as `2:45 P`, is sent as one empty entry, as a
|
|
353
|
+
* native time field sends a time it cannot read. Measured before this: a
|
|
354
|
+
* range written `09:00/10:30` was invalid and submitted the text.
|
|
354
355
|
*/
|
|
355
356
|
protected get answers(): readonly string[] | undefined;
|
|
356
357
|
/** What is wrong with the times, which the text input cannot say. */
|
|
@@ -4,13 +4,13 @@ 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, valueAsTime as asTime, clockLocale, customElement, drawIcon, formatWords, timeAsValue as fromTime, HelixClearEvent, HelixFormElement, handedLocale, isClockValue, MixinControllerOpen, MixinControllerValue, MixinField, MixinPickerEditing, MixinPickerField, MixinSegmentedField, MixinTokens, readWrittenTime, timeFault, words, wordsLocale, writeClock, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { AriaForwardController, valueAsTime as asTime, clockLocale, customElement, drawIcon, formatWords, timeAsValue as fromTime, HelixClearEvent, HelixFormElement, handedLocale, hostWords, isClockValue, MixinControllerOpen, MixinControllerValue, MixinField, MixinPickerEditing, MixinPickerField, MixinSegmentedField, MixinTokens, readWrittenTime, slottedWords, timeFault, words, wordsLocale, writeClock, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { clock, x } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { nothing } from 'lit';
|
|
10
10
|
import { property, state } 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 '../../tag/index.js';
|
|
13
|
+
import '../../tag/root/index.js';
|
|
14
14
|
import '../../time-picker/index.js';
|
|
15
15
|
let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmentedField(MixinPickerEditing(MixinPickerField(MixinControllerOpen(MixinTokens(MixinControllerValue(MixinField(HelixFormElement))))))) {
|
|
16
16
|
constructor() {
|
|
@@ -174,7 +174,8 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
174
174
|
}
|
|
175
175
|
get answers() {
|
|
176
176
|
if (this.mode !== undefined) {
|
|
177
|
-
|
|
177
|
+
const held = this.held;
|
|
178
|
+
return held.every((one) => this.isTime(one)) ? held : [''];
|
|
178
179
|
}
|
|
179
180
|
const text = this.value.trim();
|
|
180
181
|
return text === '' || this.isTime(text) ? undefined : [''];
|
|
@@ -242,7 +243,7 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
242
243
|
variant=${this.variant ?? nothing}
|
|
243
244
|
disable-times=${this.disableTimes || nothing}
|
|
244
245
|
manual
|
|
245
|
-
label=${this.label || 'Time'}
|
|
246
|
+
label=${hostWords(this, slottedWords(this, ['label']) || this.label) || 'Time'}
|
|
246
247
|
hour-cycle=${this.hourCycle ?? nothing}
|
|
247
248
|
locale=${handedLocale(this) || nothing}
|
|
248
249
|
max=${this.max}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { HelixFormElement, type HourCycle, type PickerFailure } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
import '../../listbox/index.js';
|
|
4
|
-
import '../../option/index.js';
|
|
4
|
+
import '../../option/root/index.js';
|
|
5
5
|
declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinPickerFeedbackInterface) & (new (...args: any[]) => import("@fusion.dev/helix-core").MixinControllerValueInterface) & typeof HelixFormElement;
|
|
6
6
|
/**
|
|
7
7
|
* @summary A control for choosing a time from a list or from wheels.
|
|
@@ -10,7 +10,7 @@ import { property, state } from 'lit/decorators.js';
|
|
|
10
10
|
import { html } from 'lit/static-html.js';
|
|
11
11
|
import { wheelName } from '../wheel-name.js';
|
|
12
12
|
import '../../listbox/index.js';
|
|
13
|
-
import '../../option/index.js';
|
|
13
|
+
import '../../option/root/index.js';
|
|
14
14
|
let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerFeedback(MixinControllerValue(HelixFormElement)) {
|
|
15
15
|
constructor() {
|
|
16
16
|
super(...arguments);
|
|
@@ -275,7 +275,8 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
275
275
|
this.internals.setFormValue(null);
|
|
276
276
|
return;
|
|
277
277
|
}
|
|
278
|
-
|
|
278
|
+
const held = this.held;
|
|
279
|
+
reportValues(this.internals, this.name, held.every((one) => valueAsSeconds(one) !== null) ? held : ['']);
|
|
279
280
|
}
|
|
280
281
|
async revealWhenSettled() {
|
|
281
282
|
const settling = [
|
|
@@ -356,6 +357,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
356
357
|
data-column=${part}
|
|
357
358
|
aria-describedby=${this.describedBy}
|
|
358
359
|
aria-invalid=${this.marked ? 'true' : nothing}
|
|
360
|
+
aria-required=${this.required ? 'true' : nothing}
|
|
359
361
|
exportparts="empty: column-empty, error: column-error, feedback: column-feedback, filter-icon: column-filter-icon,
|
|
360
362
|
filter-mark: column-filter-mark, hint: column-hint, items: column-items, label: column-label,
|
|
361
363
|
live: column-live, loading: column-loading, search: column-search, search-field: column-search-field"
|
|
@@ -408,6 +410,7 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
408
410
|
part="list"
|
|
409
411
|
aria-describedby=${this.describedBy}
|
|
410
412
|
aria-invalid=${this.marked ? 'true' : nothing}
|
|
413
|
+
aria-required=${this.required ? 'true' : nothing}
|
|
411
414
|
exportparts="empty: list-empty, error: list-error, feedback: list-feedback, filter-icon: list-filter-icon,
|
|
412
415
|
filter-mark: list-filter-mark, hint: list-hint, items: list-items, label: list-label,
|
|
413
416
|
live: list-live, loading: list-loading, search: list-search, search-field: list-search-field"
|
|
@@ -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 { activeCue, adoptTrack, CueController, captionsAmong, captionTracks, copiesOf, customElement, drawIcon, FullscreenController, formatWords, HelixElement, HelixNextEvent, HelixPreviousEvent, IdleController, MediaSessionController, onUnlessFalse, RemotePlaybackController, reportRuntime, SKIP_SECONDS, sameCopies, showCaption, words, writtenList, writtenNumbers, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { activeCue, adoptTrack, auditName, CueController, captionsAmong, captionTracks, copiesOf, customElement, drawIcon, FullscreenController, formatWords, HelixElement, HelixNextEvent, HelixPreviousEvent, IdleController, MediaSessionController, onUnlessFalse, RemotePlaybackController, reportRuntime, SKIP_SECONDS, sameCopies, showCaption, words, writtenList, writtenNumbers, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { airplay, arrowClockwise, arrowCounterClockwise, closedCaptioning, cornersIn, cornersOut, dotsThreeVertical, download, gauge, pause, pictureInPicture, play, skipBack, skipForward, speakerHigh, speakerX, } from '@fusion.dev/helix-icons';
|
|
9
9
|
import { nothing } from 'lit';
|
|
10
10
|
import { property, state } from 'lit/decorators.js';
|
|
@@ -464,6 +464,7 @@ let HelixHeadlessVideo = class HelixHeadlessVideo extends HelixElement {
|
|
|
464
464
|
firstUpdated(changed) {
|
|
465
465
|
super.firstUpdated?.(changed);
|
|
466
466
|
this.finishHydration();
|
|
467
|
+
auditName(this, () => null, 'Give it a `label` that says what the video shows, such as "Product tour".', () => this.label !== '');
|
|
467
468
|
const video = this.video;
|
|
468
469
|
if (video) {
|
|
469
470
|
if (this.defaultMuted || this.silent) {
|
|
@@ -38,6 +38,9 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
38
38
|
* @csspart thumbnail - The image of `poster`, shown when the `media` slot is empty.
|
|
39
39
|
*
|
|
40
40
|
* @cssstate current - The entry that is playing.
|
|
41
|
+
* @cssstate dragging - The entry a pointer is dragging, in a `reorderable` playlist.
|
|
42
|
+
* @cssstate drop-after - The entry the dragged one would land after, which the drop indicator is drawn under.
|
|
43
|
+
* @cssstate drop-before - The entry the dragged one would land before, which the drop indicator is drawn over.
|
|
41
44
|
*/
|
|
42
45
|
export declare class HelixHeadlessVideoPlaylistItem extends HelixElement {
|
|
43
46
|
/**
|
|
@@ -61,6 +64,11 @@ export declare class HelixHeadlessVideoPlaylistItem extends HelixElement {
|
|
|
61
64
|
* current one, and the arrow keys reach the rest.
|
|
62
65
|
*/
|
|
63
66
|
focusable?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* @internal Set by a `reorderable` playlist: where this entry stands in a
|
|
69
|
+
* move, which it says through its states.
|
|
70
|
+
*/
|
|
71
|
+
move: 'dragging' | 'drop-after' | 'drop-before' | undefined;
|
|
64
72
|
/**
|
|
65
73
|
* The image shown before this entry plays, also used as the row's thumbnail.
|
|
66
74
|
*
|
|
@@ -12,6 +12,7 @@ let HelixHeadlessVideoPlaylistItem = class HelixHeadlessVideoPlaylistItem extend
|
|
|
12
12
|
super(...arguments);
|
|
13
13
|
this.current = false;
|
|
14
14
|
this.disabled = false;
|
|
15
|
+
this.move = undefined;
|
|
15
16
|
this.poster = '';
|
|
16
17
|
this.src = '';
|
|
17
18
|
this.value = '';
|
|
@@ -40,6 +41,9 @@ let HelixHeadlessVideoPlaylistItem = class HelixHeadlessVideoPlaylistItem extend
|
|
|
40
41
|
willUpdate(changed) {
|
|
41
42
|
super.willUpdate(changed);
|
|
42
43
|
this.toggleState('current', this.current);
|
|
44
|
+
this.toggleState('dragging', this.move === 'dragging');
|
|
45
|
+
this.toggleState('drop-after', this.move === 'drop-after');
|
|
46
|
+
this.toggleState('drop-before', this.move === 'drop-before');
|
|
43
47
|
}
|
|
44
48
|
render() {
|
|
45
49
|
return html `<div part="container" role="listitem">
|
|
@@ -70,6 +74,9 @@ __decorate([
|
|
|
70
74
|
__decorate([
|
|
71
75
|
property({ attribute: false })
|
|
72
76
|
], HelixHeadlessVideoPlaylistItem.prototype, "focusable", void 0);
|
|
77
|
+
__decorate([
|
|
78
|
+
property({ attribute: false })
|
|
79
|
+
], HelixHeadlessVideoPlaylistItem.prototype, "move", void 0);
|
|
73
80
|
__decorate([
|
|
74
81
|
property()
|
|
75
82
|
], HelixHeadlessVideoPlaylistItem.prototype, "poster", void 0);
|
|
@@ -54,6 +54,21 @@ declare const HelixHeadlessVideoPlaylist_base: (new (...args: any[]) => import("
|
|
|
54
54
|
* the next or the previous entry. The player's previous and next controls
|
|
55
55
|
* move through the entries in the same order the playlist does.
|
|
56
56
|
*
|
|
57
|
+
* **Moving entries.** `reorderable` lets a reader change the order of the
|
|
58
|
+
* queue:
|
|
59
|
+
*
|
|
60
|
+
* - Alt with Up or Down moves the focused entry a place, and Alt with Home or
|
|
61
|
+
* End moves it to either end, as the APG's rearrangeable listbox does.
|
|
62
|
+
* Focus stays on it.
|
|
63
|
+
* - A pointer drags an entry, with a drop indicator, and the page scrolls near
|
|
64
|
+
* an edge. A press that does not travel still plays the entry.
|
|
65
|
+
* - A drop sends `helix-before-reorder`, which you can refuse, and then
|
|
66
|
+
* `helix-reorder`, whose `keys` hold every entry's `value` in the new order.
|
|
67
|
+
* **You move the entries**: the playlist moves no element of yours, and the
|
|
68
|
+
* next entry is the one after the current entry in the order you leave.
|
|
69
|
+
* - Each move is said in the live region, in words you can change:
|
|
70
|
+
* `moved-label`, `dropped-label`, `canceled-label`, and `picked-up-label`.
|
|
71
|
+
*
|
|
57
72
|
* **What a screen reader hears.** A list named by `label`, with a button for
|
|
58
73
|
* each entry. When the playlist moves to another entry, by a press, by the
|
|
59
74
|
* player's controls, or at the end of a clip, a live region says
|
|
@@ -71,7 +86,9 @@ declare const HelixHeadlessVideoPlaylist_base: (new (...args: any[]) => import("
|
|
|
71
86
|
*
|
|
72
87
|
* @event {HelixActivateEvent} helix-activate - The current entry changed. The playlist already holds the new entry when this is sent, and `detail.previous` is the entry it left. `currentEntry` is the entry itself, with its `src`, `poster` and name.
|
|
73
88
|
* @event {HelixBeforeActivateEvent} helix-before-activate - The current entry is about to change, and `detail.cause` says why: `press`, `next`, `previous`, `ended`, or `removed`. Cancelable: cancel it to keep the current entry.
|
|
89
|
+
* @event {HelixBeforeReorderEvent} helix-before-reorder - An entry was moved to a new place, in a `reorderable` playlist, with every entry's value in the new order in `detail.keys`. Cancelable: cancel it to keep the entry where it is.
|
|
74
90
|
* @event {HelixEndEvent} helix-end - The last entry finished playing, and the playlist stopped there. Not sent while `repeat` is set.
|
|
91
|
+
* @event {HelixReorderEvent} helix-reorder - Fired after `helix-before-reorder` when nobody canceled it. Move your entries to the order in `keys`. Cancelable: cancel it to say the move did not happen.
|
|
75
92
|
*
|
|
76
93
|
* @csspart empty - The box that holds the `empty` slot, drawn while there are no entries.
|
|
77
94
|
* @csspart items - The list of entries.
|
|
@@ -86,6 +103,16 @@ export declare class HelixHeadlessVideoPlaylist extends HelixHeadlessVideoPlayli
|
|
|
86
103
|
* `registerWords('de', { 'helix-video-playlist': { label: 'Wiedergabeliste' } })`.
|
|
87
104
|
*/
|
|
88
105
|
static words: string;
|
|
106
|
+
/**
|
|
107
|
+
* What screen readers hear when a move is put back, in a `reorderable`
|
|
108
|
+
* playlist. `{name}` is the entry's words.
|
|
109
|
+
*/
|
|
110
|
+
canceledLabel: string;
|
|
111
|
+
/**
|
|
112
|
+
* What screen readers hear when a moved entry is let go, in a `reorderable`
|
|
113
|
+
* playlist. `{name}` is the entry's words.
|
|
114
|
+
*/
|
|
115
|
+
droppedLabel: string;
|
|
89
116
|
/**
|
|
90
117
|
* What the playlist says while it has no entries. The `empty` slot replaces it.
|
|
91
118
|
*/
|
|
@@ -94,12 +121,23 @@ export declare class HelixHeadlessVideoPlaylist extends HelixHeadlessVideoPlayli
|
|
|
94
121
|
* The list's name, read by screen readers.
|
|
95
122
|
*/
|
|
96
123
|
label: string;
|
|
124
|
+
/**
|
|
125
|
+
* What screen readers hear each time a key moves an entry, in a
|
|
126
|
+
* `reorderable` playlist. `{name}` is the entry's words, `{position}` its
|
|
127
|
+
* new place, counting from 1, and `{count}` the number of entries.
|
|
128
|
+
*/
|
|
129
|
+
movedLabel: string;
|
|
97
130
|
/**
|
|
98
131
|
* Stays on an entry when its clip ends, where the playlist would otherwise
|
|
99
132
|
* play the next one. The player's controls, a press, and `next()` still
|
|
100
133
|
* move. `repeat="one"` still plays the entry again.
|
|
101
134
|
*/
|
|
102
135
|
noAdvance: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* What screen readers hear when a pointer picks up an entry, in a
|
|
138
|
+
* `reorderable` playlist. `{name}` is the entry's words.
|
|
139
|
+
*/
|
|
140
|
+
pickedUpLabel: string;
|
|
103
141
|
/**
|
|
104
142
|
* What the live region says when the playlist moves to another entry.
|
|
105
143
|
* `{title}` is the entry's name.
|
|
@@ -109,8 +147,30 @@ export declare class HelixHeadlessVideoPlaylist extends HelixHeadlessVideoPlayli
|
|
|
109
147
|
* `aria-current` on a button the reader is not on.
|
|
110
148
|
*/
|
|
111
149
|
playingLabel: string;
|
|
150
|
+
/**
|
|
151
|
+
* Lets a reader move the entries, with Alt and the arrow keys or by
|
|
152
|
+
* dragging one. The playlist moves no entry itself: you move your entries
|
|
153
|
+
* on `helix-reorder`.
|
|
154
|
+
*/
|
|
155
|
+
reorderable: boolean;
|
|
112
156
|
/** The live region, rendered from the first move. */
|
|
113
157
|
private readonly status;
|
|
158
|
+
/** The entry an event passed through, where it may move. */
|
|
159
|
+
private entryOf;
|
|
160
|
+
/** The entry with that value. */
|
|
161
|
+
private entryFor;
|
|
162
|
+
/**
|
|
163
|
+
* Moving the entries, as a listbox moves its options: Alt with the arrows
|
|
164
|
+
* on the focused entry, or a pointer dragging a whole entry, where a press
|
|
165
|
+
* that does not travel still plays it.
|
|
166
|
+
*/
|
|
167
|
+
private readonly reorder;
|
|
168
|
+
/**
|
|
169
|
+
* Tells each entry where it stands in a move, which it says through its
|
|
170
|
+
* states for the styled tier to draw: the entry dragged, and the one the
|
|
171
|
+
* drop indicator is before or after.
|
|
172
|
+
*/
|
|
173
|
+
private markMoves;
|
|
114
174
|
/**
|
|
115
175
|
* What happens when an entry ends with no next one to go to. `one` plays the
|
|
116
176
|
* same entry again, and `all` goes from the last entry back to the first.
|
|
@@ -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 { customElement, drawStatus, formatWords, HelixElement, HelixEndEvent, inlineStep, MixinControllerActive, StatusController, words, } from '@fusion.dev/helix-core';
|
|
7
|
+
import { customElement, drawStatus, formatWords, HelixElement, HelixEndEvent, inlineStep, MixinControllerActive, ReorderController, StatusController, words, } from '@fusion.dev/helix-core';
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { HelixHeadlessVideoPlaylistItem } from '../item/video-playlist-item.js';
|
|
@@ -12,11 +12,30 @@ import { playOrder, stepTo } from '../order.js';
|
|
|
12
12
|
let HelixHeadlessVideoPlaylist = class HelixHeadlessVideoPlaylist extends MixinControllerActive(HelixElement) {
|
|
13
13
|
constructor() {
|
|
14
14
|
super(...arguments);
|
|
15
|
+
this.canceledLabel = 'Canceled';
|
|
16
|
+
this.droppedLabel = 'Dropped';
|
|
15
17
|
this.emptyLabel = 'No videos';
|
|
16
18
|
this.label = 'Playlist';
|
|
19
|
+
this.movedLabel = '{name} moved to position {position} of {count}';
|
|
17
20
|
this.noAdvance = false;
|
|
21
|
+
this.pickedUpLabel = 'Picked up {name}';
|
|
18
22
|
this.playingLabel = 'Now playing {title}';
|
|
23
|
+
this.reorderable = false;
|
|
19
24
|
this.status = new StatusController(this);
|
|
25
|
+
this.reorder = new ReorderController(this, {
|
|
26
|
+
axis: 'block',
|
|
27
|
+
box: (value) => this.entryFor(value)?.getBoundingClientRect(),
|
|
28
|
+
current: (event) => this.entryOf(event)?.value,
|
|
29
|
+
grip: (event) => {
|
|
30
|
+
const entry = this.entryOf(event);
|
|
31
|
+
return entry ? { element: entry, key: entry.value } : undefined;
|
|
32
|
+
},
|
|
33
|
+
holds: false,
|
|
34
|
+
keys: () => this.items.map((one) => one.value),
|
|
35
|
+
name: (value) => this.entryFor(value)?.text || value,
|
|
36
|
+
refocus: (value) => this.entryFor(value)?.focus(),
|
|
37
|
+
say: (words) => this.status.say(words),
|
|
38
|
+
});
|
|
20
39
|
this.shuffle = false;
|
|
21
40
|
this.chased = false;
|
|
22
41
|
this.known = {
|
|
@@ -116,6 +135,21 @@ let HelixHeadlessVideoPlaylist = class HelixHeadlessVideoPlaylist extends MixinC
|
|
|
116
135
|
};
|
|
117
136
|
}
|
|
118
137
|
static { this.words = 'helix-video-playlist'; }
|
|
138
|
+
entryOf(event) {
|
|
139
|
+
const items = this.items;
|
|
140
|
+
return event
|
|
141
|
+
.composedPath()
|
|
142
|
+
.find((node) => items.includes(node) &&
|
|
143
|
+
!node.disabled);
|
|
144
|
+
}
|
|
145
|
+
entryFor(value) {
|
|
146
|
+
return this.items.find((one) => one.value === value);
|
|
147
|
+
}
|
|
148
|
+
markMoves() {
|
|
149
|
+
for (const entry of this.items) {
|
|
150
|
+
entry.move = this.reorderable ? this.reorder.moveOf(entry.value) : undefined;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
119
153
|
get items() {
|
|
120
154
|
return [...this.querySelectorAll('*')].filter((one) => one instanceof HelixHeadlessVideoPlaylistItem && one.value !== '');
|
|
121
155
|
}
|
|
@@ -228,6 +262,7 @@ let HelixHeadlessVideoPlaylist = class HelixHeadlessVideoPlaylist extends MixinC
|
|
|
228
262
|
}
|
|
229
263
|
updated(changed) {
|
|
230
264
|
super.updated?.(changed);
|
|
265
|
+
this.markMoves();
|
|
231
266
|
const items = this.items;
|
|
232
267
|
const current = this.resolveActive(items);
|
|
233
268
|
for (const item of items) {
|
|
@@ -270,6 +305,14 @@ let HelixHeadlessVideoPlaylist = class HelixHeadlessVideoPlaylist extends MixinC
|
|
|
270
305
|
${drawStatus(this.status)}`;
|
|
271
306
|
}
|
|
272
307
|
};
|
|
308
|
+
__decorate([
|
|
309
|
+
words,
|
|
310
|
+
property({ attribute: 'canceled-label' })
|
|
311
|
+
], HelixHeadlessVideoPlaylist.prototype, "canceledLabel", void 0);
|
|
312
|
+
__decorate([
|
|
313
|
+
words,
|
|
314
|
+
property({ attribute: 'dropped-label' })
|
|
315
|
+
], HelixHeadlessVideoPlaylist.prototype, "droppedLabel", void 0);
|
|
273
316
|
__decorate([
|
|
274
317
|
words,
|
|
275
318
|
property({ attribute: 'empty-label' })
|
|
@@ -278,13 +321,24 @@ __decorate([
|
|
|
278
321
|
words,
|
|
279
322
|
property()
|
|
280
323
|
], HelixHeadlessVideoPlaylist.prototype, "label", void 0);
|
|
324
|
+
__decorate([
|
|
325
|
+
words,
|
|
326
|
+
property({ attribute: 'moved-label' })
|
|
327
|
+
], HelixHeadlessVideoPlaylist.prototype, "movedLabel", void 0);
|
|
281
328
|
__decorate([
|
|
282
329
|
property({ attribute: 'no-advance', type: Boolean })
|
|
283
330
|
], HelixHeadlessVideoPlaylist.prototype, "noAdvance", void 0);
|
|
331
|
+
__decorate([
|
|
332
|
+
words,
|
|
333
|
+
property({ attribute: 'picked-up-label' })
|
|
334
|
+
], HelixHeadlessVideoPlaylist.prototype, "pickedUpLabel", void 0);
|
|
284
335
|
__decorate([
|
|
285
336
|
words,
|
|
286
337
|
property({ attribute: 'playing-label' })
|
|
287
338
|
], HelixHeadlessVideoPlaylist.prototype, "playingLabel", void 0);
|
|
339
|
+
__decorate([
|
|
340
|
+
property({ reflect: true, type: Boolean })
|
|
341
|
+
], HelixHeadlessVideoPlaylist.prototype, "reorderable", void 0);
|
|
288
342
|
__decorate([
|
|
289
343
|
property()
|
|
290
344
|
], HelixHeadlessVideoPlaylist.prototype, "repeat", void 0);
|