@fusion.dev/helix-headless 0.215.3 → 0.216.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/api.json +1 -1
- package/custom-elements.json +1 -1
- package/dist/area-chart/root/area-chart-root.d.ts +1 -0
- package/dist/area-chart/root/area-chart-root.js +1 -1
- package/dist/bar-chart/root/bar-chart-root.d.ts +1 -0
- package/dist/bar-chart/root/bar-chart-root.js +1 -1
- package/dist/button/root/button-root.d.ts +3 -1
- package/dist/button/root/button-root.js +2 -1
- package/dist/chat/composer/chat-composer.d.ts +18 -1
- package/dist/chat/composer/chat-composer.js +8 -3
- package/dist/checkbox/root/checkbox-root.d.ts +3 -1
- package/dist/checkbox/root/checkbox-root.js +2 -1
- package/dist/code-block/highlight.d.ts +9 -0
- package/dist/code-block/highlight.js +39 -0
- package/dist/code-block/highlighter.d.ts +44 -0
- package/dist/code-block/highlighter.js +44 -0
- package/dist/code-block/index.d.ts +1 -0
- package/dist/code-block/index.js +1 -0
- package/dist/code-block/keyed-lines.d.ts +23 -0
- package/dist/code-block/keyed-lines.js +75 -0
- package/dist/code-block/root/code-block-root.d.ts +6 -23
- package/dist/code-block/root/code-block-root.js +8 -25
- package/dist/code-editor/index.d.ts +1 -0
- package/dist/code-editor/index.js +1 -0
- package/dist/code-editor/root/code-editor-root.d.ts +367 -0
- package/dist/code-editor/root/code-editor-root.js +746 -0
- package/dist/code-input/index.d.ts +1 -0
- package/dist/code-input/index.js +1 -0
- package/dist/code-input/root/code-input-root.d.ts +119 -0
- package/dist/code-input/root/code-input-root.js +142 -0
- package/dist/combobox/root/combobox-root.d.ts +6 -1
- package/dist/combobox/root/combobox-root.js +4 -2
- package/dist/command/root/command-root.d.ts +61 -11
- package/dist/command/root/command-root.js +88 -3
- package/dist/donut-chart/root/donut-chart-root.d.ts +1 -0
- package/dist/donut-chart/root/donut-chart-root.js +1 -1
- package/dist/element-events.generated.js +36 -3
- package/dist/filter-input/root/filter-input-root.d.ts +9 -1
- package/dist/filter-input/root/filter-input-root.js +7 -3
- package/dist/heatmap/root/heatmap-root.d.ts +1 -0
- package/dist/heatmap/root/heatmap-root.js +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/input/root/input-root.d.ts +14 -2
- package/dist/input/root/input-root.js +11 -3
- package/dist/kbd/root/kbd-root.js +9 -2
- package/dist/line-chart/root/line-chart-root.d.ts +1 -0
- package/dist/line-chart/root/line-chart-root.js +1 -1
- package/dist/listbox/root/listbox-root.d.ts +8 -1
- package/dist/listbox/root/listbox-root.js +7 -4
- package/dist/markdown/blocks.d.ts +66 -0
- package/dist/markdown/blocks.js +326 -0
- package/dist/markdown/index.d.ts +6 -0
- package/dist/markdown/index.js +5 -0
- package/dist/markdown/inline.d.ts +57 -0
- package/dist/markdown/inline.js +483 -0
- package/dist/markdown/root/markdown-root.d.ts +99 -0
- package/dist/markdown/root/markdown-root.js +93 -0
- package/dist/markdown/stream.d.ts +47 -0
- package/dist/markdown/stream.js +62 -0
- package/dist/markdown/tree.d.ts +57 -0
- package/dist/markdown/tree.js +144 -0
- package/dist/markdown/writer.d.ts +33 -0
- package/dist/markdown/writer.js +139 -0
- package/dist/menu/root/menu-root.d.ts +53 -0
- package/dist/menu/root/menu-root.js +92 -15
- package/dist/pagination/size/pagination-size.d.ts +3 -0
- package/dist/pagination/size/pagination-size.js +2 -1
- package/dist/scatter-chart/root/scatter-chart-root.d.ts +1 -0
- package/dist/scatter-chart/root/scatter-chart-root.js +1 -1
- package/dist/select/root/select-root.d.ts +6 -1
- package/dist/select/root/select-root.js +4 -2
- package/dist/shortcut-overlay/index.d.ts +1 -0
- package/dist/shortcut-overlay/index.js +1 -0
- package/dist/shortcut-overlay/root/shortcut-overlay-root.d.ts +128 -0
- package/dist/shortcut-overlay/root/shortcut-overlay-root.js +275 -0
- package/dist/slider/root/slider-root.d.ts +3 -1
- package/dist/slider/root/slider-root.js +2 -1
- package/dist/spatial-bar-chart/root/spatial-bar-chart-root.d.ts +1 -0
- package/dist/spatial-bar-chart/root/spatial-bar-chart-root.js +1 -1
- package/dist/spatial-heatmap/root/spatial-heatmap-root.d.ts +1 -0
- package/dist/spatial-heatmap/root/spatial-heatmap-root.js +1 -1
- package/dist/spatial-ribbon-chart/root/spatial-ribbon-chart-root.d.ts +1 -0
- package/dist/spatial-ribbon-chart/root/spatial-ribbon-chart-root.js +1 -1
- package/dist/spatial-scatter-chart/root/spatial-scatter-chart-root.d.ts +1 -0
- package/dist/spatial-scatter-chart/root/spatial-scatter-chart-root.js +1 -1
- package/dist/spatial-surface-chart/root/spatial-surface-chart-root.d.ts +1 -0
- package/dist/spatial-surface-chart/root/spatial-surface-chart-root.js +1 -1
- package/dist/spatial-treemap/root/spatial-treemap-root.d.ts +1 -0
- package/dist/spatial-treemap/root/spatial-treemap-root.js +1 -1
- package/dist/switch/root/switch-root.d.ts +3 -1
- package/dist/switch/root/switch-root.js +2 -1
- package/dist/tabs/tab/tab.d.ts +3 -1
- package/dist/tabs/tab/tab.js +2 -1
- package/dist/textarea/root/textarea-root.d.ts +20 -4
- package/dist/textarea/root/textarea-root.js +31 -23
- package/dist/time-input/root/time-input-root.d.ts +6 -0
- package/dist/time-input/root/time-input-root.js +4 -2
- package/dist/time-picker/root/time-picker-root.d.ts +6 -0
- package/dist/time-picker/root/time-picker-root.js +4 -2
- package/dist/toast/root/toast-root.d.ts +64 -0
- package/dist/toast/root/toast-root.js +128 -3
- package/dist/toggle/root/toggle-root.d.ts +3 -1
- package/dist/toggle/root/toggle-root.js +2 -1
- package/dist/virtual-list/root/virtual-list-root.d.ts +18 -2
- package/dist/virtual-list/root/virtual-list-root.js +103 -5
- package/examples.json +1 -1
- package/lint.json +1 -1
- package/package.json +6 -6
- package/types/jsx.d.ts +5315 -596
- package/types/svelte.d.ts +4 -0
- package/types/vue.d.ts +1085 -4
- package/types/words.d.ts +491 -0
|
@@ -106,6 +106,9 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
|
|
|
106
106
|
* @csspart picker-column-loading - The text shown while the options load.
|
|
107
107
|
* @csspart picker-column-search - The region that holds the filter field.
|
|
108
108
|
* @csspart picker-column-search-field - The filter field.
|
|
109
|
+
* @csspart picker-column-voice - The dictation button in the filter field.
|
|
110
|
+
* @csspart picker-column-voice-listening - The dictation button while it listens.
|
|
111
|
+
* @csspart picker-column-voice-status - What a screen reader hears as dictation starts and stops.
|
|
109
112
|
* @csspart picker-columns - The row of columns, in `wheels`.
|
|
110
113
|
* @csspart picker-feedback - The picker's own message, under the times, while the picker's `feedback` is set.
|
|
111
114
|
* @csspart picker-hint - The picker's hint, which Time Input never sets: help under the field is the field's own `hint`.
|
|
@@ -123,6 +126,9 @@ declare const HelixHeadlessTimeInput_base: (new (...args: any[]) => import("@fus
|
|
|
123
126
|
* @csspart picker-list-loading - The text shown while the options load.
|
|
124
127
|
* @csspart picker-list-search - The region that holds the filter field.
|
|
125
128
|
* @csspart picker-list-search-field - The filter field.
|
|
129
|
+
* @csspart picker-list-voice - The dictation button in the filter field.
|
|
130
|
+
* @csspart picker-list-voice-listening - The dictation button while it listens.
|
|
131
|
+
* @csspart picker-list-voice-status - What a screen reader hears as dictation starts and stops.
|
|
126
132
|
* @csspart picker-now - The picker's button that chooses the current time, which Time Input does not draw.
|
|
127
133
|
* @csspart picker-option - One time in the picker. Carries `data-between` inside a range.
|
|
128
134
|
* @csspart picker-option-between - A time inside a chosen range, between its two ends. Set together with `picker-option`.
|
|
@@ -227,13 +227,15 @@ let HelixHeadlessTimeInput = class HelixHeadlessTimeInput extends MixinSegmented
|
|
|
227
227
|
column-filter-mark: picker-column-filter-mark, column-hint: picker-column-hint,
|
|
228
228
|
column-items: picker-column-items, column-label: picker-column-label,
|
|
229
229
|
column-live: picker-column-live, column-loading: picker-column-loading, column-search: picker-column-search,
|
|
230
|
-
column-search-field: picker-column-search-field,
|
|
230
|
+
column-search-field: picker-column-search-field, column-voice: picker-column-voice,
|
|
231
|
+
column-voice-listening: picker-column-voice-listening, column-voice-status: picker-column-voice-status, columns: picker-columns, feedback: picker-feedback, hint: picker-hint,
|
|
231
232
|
label: picker-label, list: picker-list,
|
|
232
233
|
list-empty: picker-list-empty, list-error: picker-list-error, list-feedback: picker-list-feedback,
|
|
233
234
|
list-filter-icon: picker-list-filter-icon, list-filter-mark: picker-list-filter-mark,
|
|
234
235
|
list-hint: picker-list-hint, list-items: picker-list-items, list-label: picker-list-label,
|
|
235
236
|
list-live: picker-list-live, list-loading: picker-list-loading, list-search: picker-list-search,
|
|
236
|
-
list-search-field: picker-list-search-field,
|
|
237
|
+
list-search-field: picker-list-search-field, list-voice: picker-list-voice,
|
|
238
|
+
list-voice-listening: picker-list-voice-listening, list-voice-status: picker-list-voice-status, now: picker-now, option: picker-option,
|
|
237
239
|
option-between: picker-option-between, option-item-active: picker-option-item-active,
|
|
238
240
|
option-item-selected: picker-option-item-selected,
|
|
239
241
|
option-description: picker-option-description, option-item: picker-option-item,
|
|
@@ -88,6 +88,9 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
|
|
|
88
88
|
* @csspart column-loading - The text shown while the options load.
|
|
89
89
|
* @csspart column-search - The region that holds the filter field.
|
|
90
90
|
* @csspart column-search-field - The filter field.
|
|
91
|
+
* @csspart column-voice - The dictation button in the filter field.
|
|
92
|
+
* @csspart column-voice-listening - The dictation button while it listens.
|
|
93
|
+
* @csspart column-voice-status - What a screen reader hears as dictation starts and stops.
|
|
91
94
|
* @csspart columns - The row of columns, in `wheels`.
|
|
92
95
|
* @csspart feedback - The message under the times, while `feedback` is set.
|
|
93
96
|
* @csspart hint - Help under the times, shown while there is no message in `feedback`.
|
|
@@ -105,6 +108,9 @@ declare const HelixHeadlessTimePicker_base: (new (...args: any[]) => import("@fu
|
|
|
105
108
|
* @csspart list-loading - The text shown while the options load.
|
|
106
109
|
* @csspart list-search - The region that holds the filter field.
|
|
107
110
|
* @csspart list-search-field - The filter field.
|
|
111
|
+
* @csspart list-voice - The dictation button in the filter field.
|
|
112
|
+
* @csspart list-voice-listening - The dictation button while it listens.
|
|
113
|
+
* @csspart list-voice-status - What a screen reader hears as dictation starts and stops.
|
|
108
114
|
* @csspart now - The button that chooses the current time, drawn with `show-now`.
|
|
109
115
|
* @csspart option - One time in the list. It carries `data-between` inside a range, and inside the run to the time under the pointer while a range waits for its second end.
|
|
110
116
|
* @csspart option-between - A time inside a chosen range, excluding its ends, beside `option`.
|
|
@@ -406,7 +406,8 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
406
406
|
aria-required=${this.required ? 'true' : nothing}
|
|
407
407
|
exportparts="empty: column-empty, error: column-error, feedback: column-feedback, filter-icon: column-filter-icon,
|
|
408
408
|
filter-mark: column-filter-mark, hint: column-hint, items: column-items, label: column-label,
|
|
409
|
-
live: column-live, loading: column-loading, search: column-search, search-field: column-search-field
|
|
409
|
+
live: column-live, loading: column-loading, search: column-search, search-field: column-search-field,
|
|
410
|
+
voice: column-voice, voice-listening: column-voice-listening, voice-status: column-voice-status"
|
|
410
411
|
aria-label=${label}
|
|
411
412
|
?disabled=${this.isDisabled}
|
|
412
413
|
.value=${value}
|
|
@@ -459,7 +460,8 @@ let HelixHeadlessTimePicker = class HelixHeadlessTimePicker extends MixinPickerF
|
|
|
459
460
|
aria-required=${this.required ? 'true' : nothing}
|
|
460
461
|
exportparts="empty: list-empty, error: list-error, feedback: list-feedback, filter-icon: list-filter-icon,
|
|
461
462
|
filter-mark: list-filter-mark, hint: list-hint, items: list-items, label: list-label,
|
|
462
|
-
live: list-live, loading: list-loading, search: list-search, search-field: list-search-field
|
|
463
|
+
live: list-live, loading: list-loading, search: list-search, search-field: list-search-field,
|
|
464
|
+
voice: list-voice, voice-listening: list-voice-listening, voice-status: list-voice-status"
|
|
463
465
|
aria-label=${this.listName}
|
|
464
466
|
data-unset=${this.value === '' ? '' : nothing}
|
|
465
467
|
?disabled=${this.isDisabled}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HelixElement } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
|
+
import '../../button/index.js';
|
|
3
4
|
/**
|
|
4
5
|
* @summary The region that holds toast messages, and the only element that announces them.
|
|
5
6
|
*
|
|
@@ -37,6 +38,13 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
37
38
|
* or a pen swipes a message away toward the end of the line, or toward the
|
|
38
39
|
* edge `swipe-direction` names.
|
|
39
40
|
*
|
|
41
|
+
* **`undoable()` offers to take an action back**, which replaces a
|
|
42
|
+
* confirmation dialog for an action that can be undone: do the action, then
|
|
43
|
+
* call it. The message holds an Undo button and shows for 8 seconds, Command+Z
|
|
44
|
+
* (Control+Z elsewhere) undoes it while it shows, and a screen reader hears
|
|
45
|
+
* which keys do. Keep a confirmation for an action that cannot be taken back or
|
|
46
|
+
* that reaches someone else, such as sending or paying.
|
|
47
|
+
*
|
|
40
48
|
* **Every message's timer waits while a pointer or focus is in the stack**, as
|
|
41
49
|
* React Aria's and Radix's regions do, so a reader moving from one message to
|
|
42
50
|
* the next does not lose the one behind them.
|
|
@@ -63,6 +71,7 @@ import { type PropertyValues, type TemplateResult } from 'lit';
|
|
|
63
71
|
*
|
|
64
72
|
* | Key | What it does |
|
|
65
73
|
* |---|---|
|
|
74
|
+
* | Command+Z, or Control+Z elsewhere, or your `undo-keys` | Undoes the newest message `undoable()` made, while it shows, while focus is not in a text field, and where the app has not handled the key. |
|
|
66
75
|
* | F8, or your `hotkey` | Moves focus to the first control in the stack, and back to where it was when pressed in the stack. |
|
|
67
76
|
* | Tab, Shift+Tab | Moves between the controls of the messages. |
|
|
68
77
|
* | Escape | Dismisses the message holding focus. Focus moves to the next message, then the one before it, then back to where it was. |
|
|
@@ -94,6 +103,8 @@ export declare class HelixHeadlessToast extends HelixElement {
|
|
|
94
103
|
* Empty turns it off.
|
|
95
104
|
*/
|
|
96
105
|
hotkey: string;
|
|
106
|
+
/** What the hotkey does, as a list of the page's shortcuts says it. */
|
|
107
|
+
hotkeyLabel: string;
|
|
97
108
|
/**
|
|
98
109
|
* Accessible name for the region, with `{hotkey}` filled in. Translate it with
|
|
99
110
|
* the rest of your interface.
|
|
@@ -173,6 +184,57 @@ export declare class HelixHeadlessToast extends HelixElement {
|
|
|
173
184
|
private readonly scope;
|
|
174
185
|
/** Takes focus to the stack and back, on `hotkey`. */
|
|
175
186
|
private readonly handleHotkey;
|
|
187
|
+
/**
|
|
188
|
+
* What a message `undoable()` made says after its own words, with `{keys}`
|
|
189
|
+
* for the chord that undoes it, spoken as words.
|
|
190
|
+
*/
|
|
191
|
+
undoHint: string;
|
|
192
|
+
/**
|
|
193
|
+
* The keys that undo the newest message `undoable()` made, as `hotkey`
|
|
194
|
+
* reads them. Empty turns them off, for an app whose own undo holds them,
|
|
195
|
+
* and leaves the Undo button. A key the app already handled, by calling
|
|
196
|
+
* `preventDefault()`, is left to it.
|
|
197
|
+
*/
|
|
198
|
+
undoKeys: string;
|
|
199
|
+
/** The words on the Undo button of a message `undoable()` made. */
|
|
200
|
+
undoLabel: string;
|
|
201
|
+
/** The words said after each message `undoable()` made: the key that undoes it. */
|
|
202
|
+
private readonly hints;
|
|
203
|
+
/** The undoable messages showing, oldest first, each with what undoes it and what keeps it. */
|
|
204
|
+
private readonly undoables;
|
|
205
|
+
/**
|
|
206
|
+
* Shows that an action happened and offers to undo it, which is the pattern
|
|
207
|
+
* that replaces a confirmation dialog for an action that can be taken back.
|
|
208
|
+
*
|
|
209
|
+
* Do the action first, then call this. The message holds an Undo button,
|
|
210
|
+
* shows for `duration` (8 seconds by default, and paused while a pointer or
|
|
211
|
+
* focus is in the stack), and `undo-keys`, Command+Z or Control+Z by
|
|
212
|
+
* default, does what the button does while it shows, unless a text field
|
|
213
|
+
* has focus. A screen reader hears the message and then which keys undo it.
|
|
214
|
+
*
|
|
215
|
+
* `undo` runs if the reader undoes, and `commit` runs if the message closes
|
|
216
|
+
* any other way, for an app that holds the real deletion back until then.
|
|
217
|
+
* The promise settles to `undone` or `kept` accordingly.
|
|
218
|
+
*
|
|
219
|
+
* **A message that is never closed is kept.** `commit` runs as the region
|
|
220
|
+
* leaves the page, as on a route change, and as the page itself is hidden
|
|
221
|
+
* to be closed or reloaded. A browser can end a page without either, so a
|
|
222
|
+
* server holding a deletion back finishes it on a timeout of its own too.
|
|
223
|
+
*/
|
|
224
|
+
undoable(message: string, options: {
|
|
225
|
+
commit?: () => void;
|
|
226
|
+
duration?: number;
|
|
227
|
+
heading?: string;
|
|
228
|
+
tone?: 'danger' | 'info' | 'success' | 'warning';
|
|
229
|
+
undo: () => void;
|
|
230
|
+
}): Promise<'kept' | 'undone'>;
|
|
231
|
+
/** Keeps every undoable message still showing, as the region or the page goes. */
|
|
232
|
+
private keepAll;
|
|
233
|
+
private readonly handlePageHide;
|
|
234
|
+
/** Undoes the newest undoable message on `undo-keys`, unless a field or the app has the keystroke. */
|
|
235
|
+
private readonly handleUndo;
|
|
236
|
+
/** What a message says as it arrives, with the key that undoes it where it has one. */
|
|
237
|
+
private wordsOf;
|
|
176
238
|
/** Messages `add()` made, which are the region's to remove. */
|
|
177
239
|
private readonly made;
|
|
178
240
|
/**
|
|
@@ -267,6 +329,8 @@ export declare class HelixHeadlessToast extends HelixElement {
|
|
|
267
329
|
*/
|
|
268
330
|
private readonly handleDismiss;
|
|
269
331
|
connectedCallback(): void;
|
|
332
|
+
/** Takes the hotkey off the page's list of shortcuts. */
|
|
333
|
+
private unregister;
|
|
270
334
|
disconnectedCallback(): void;
|
|
271
335
|
protected firstUpdated(changed: PropertyValues): void;
|
|
272
336
|
protected updated(changed: PropertyValues): void;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
-
import { animationsFinished, customElement, DelayController, deepActiveElement, deepContains, FocusScopeController, focusableElements, formatWords, HelixElement, hostAria, matchesChord, numberConverter, onApple, scrollHolders, words, } from '@fusion.dev/helix-core';
|
|
2
|
+
import { animationsFinished, ariaChord, chordParts, customElement, DelayController, deepActiveElement, deepContains, FocusScopeController, focusableElements, formatWords, HelixElement, hostAria, keyClaimed, keyNames, matchesChord, numberConverter, onApple, registerShortcut, scrollHolders, words, } from '@fusion.dev/helix-core';
|
|
3
3
|
import { html } from 'lit';
|
|
4
4
|
import { property, state } from 'lit/decorators.js';
|
|
5
|
+
import '../../button/index.js';
|
|
5
6
|
import { joinSaid, messageWords } from '../words.js';
|
|
6
7
|
let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
7
8
|
constructor() {
|
|
8
9
|
super(...arguments);
|
|
9
10
|
this.hotkey = 'F8';
|
|
11
|
+
this.hotkeyLabel = 'Go to notifications';
|
|
10
12
|
this.label = 'Notifications ({hotkey})';
|
|
11
13
|
this.said = '';
|
|
12
14
|
this.urgent = '';
|
|
@@ -34,6 +36,26 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
34
36
|
this.scope.enter();
|
|
35
37
|
}
|
|
36
38
|
};
|
|
39
|
+
this.undoHint = 'Press {keys} to undo.';
|
|
40
|
+
this.undoKeys = 'mod+z';
|
|
41
|
+
this.undoLabel = 'Undo';
|
|
42
|
+
this.hints = new WeakMap();
|
|
43
|
+
this.undoables = [];
|
|
44
|
+
this.handlePageHide = () => {
|
|
45
|
+
this.keepAll();
|
|
46
|
+
};
|
|
47
|
+
this.handleUndo = (event) => {
|
|
48
|
+
const newest = this.undoables.at(-1);
|
|
49
|
+
if (!newest ||
|
|
50
|
+
this.undoKeys === '' ||
|
|
51
|
+
event.defaultPrevented ||
|
|
52
|
+
keyClaimed(event) ||
|
|
53
|
+
!matchesChord(event, this.undoKeys, onApple())) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
newest.undo();
|
|
58
|
+
};
|
|
37
59
|
this.made = new WeakSet();
|
|
38
60
|
this.pointerIn = false;
|
|
39
61
|
this.focusIn = false;
|
|
@@ -112,7 +134,7 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
112
134
|
}
|
|
113
135
|
announce(arrived) {
|
|
114
136
|
for (const one of arrived) {
|
|
115
|
-
const words =
|
|
137
|
+
const words = this.wordsOf(one);
|
|
116
138
|
if (words !== '') {
|
|
117
139
|
;
|
|
118
140
|
(isDanger(one) ? this.pending.urgent : this.pending.said).push(words);
|
|
@@ -155,6 +177,83 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
155
177
|
this.announce(arrived);
|
|
156
178
|
}
|
|
157
179
|
}
|
|
180
|
+
undoable(message, options) {
|
|
181
|
+
const tier = this.constructor.tier;
|
|
182
|
+
const apple = onApple();
|
|
183
|
+
const keys = this.undoKeys;
|
|
184
|
+
const button = document.createElement(`${tier}button`);
|
|
185
|
+
button.textContent = this.undoLabel;
|
|
186
|
+
if (keys !== '') {
|
|
187
|
+
button.setAttribute('aria-keyshortcuts', ariaChord(keys, apple));
|
|
188
|
+
}
|
|
189
|
+
const item = this.add(message, {
|
|
190
|
+
action: button,
|
|
191
|
+
duration: options.duration ?? 8000,
|
|
192
|
+
...(options.heading === undefined ? {} : { heading: options.heading }),
|
|
193
|
+
...(options.tone === undefined ? {} : { tone: options.tone }),
|
|
194
|
+
});
|
|
195
|
+
if (keys !== '') {
|
|
196
|
+
const names = keyNames(chordParts(keys), apple);
|
|
197
|
+
this.hints.set(item, formatWords(this, 'undoHint', { keys: names.spoken || names.keys.join(names.separator) }));
|
|
198
|
+
}
|
|
199
|
+
return new Promise((resolve) => {
|
|
200
|
+
let settled = false;
|
|
201
|
+
const unregister = keys === ''
|
|
202
|
+
? () => { }
|
|
203
|
+
: registerShortcut({
|
|
204
|
+
keys: () => keys,
|
|
205
|
+
label: () => this.undoLabel,
|
|
206
|
+
owner: item,
|
|
207
|
+
});
|
|
208
|
+
const finish = (how) => {
|
|
209
|
+
settled = true;
|
|
210
|
+
unregister();
|
|
211
|
+
button.removeEventListener('click', undo);
|
|
212
|
+
item.removeEventListener('helix-dismiss', closed);
|
|
213
|
+
const at = this.undoables.findIndex((one) => one.item === item);
|
|
214
|
+
if (at >= 0) {
|
|
215
|
+
this.undoables.splice(at, 1);
|
|
216
|
+
}
|
|
217
|
+
resolve(how);
|
|
218
|
+
};
|
|
219
|
+
const undo = () => {
|
|
220
|
+
if (settled) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
options.undo();
|
|
224
|
+
finish('undone');
|
|
225
|
+
item.dismiss?.();
|
|
226
|
+
};
|
|
227
|
+
const keep = () => {
|
|
228
|
+
if (!settled) {
|
|
229
|
+
options.commit?.();
|
|
230
|
+
finish('kept');
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
const closed = (event) => {
|
|
234
|
+
if (event.defaultPrevented) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
queueMicrotask(() => {
|
|
238
|
+
if (!event.defaultPrevented) {
|
|
239
|
+
keep();
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
};
|
|
243
|
+
button.addEventListener('click', undo);
|
|
244
|
+
item.addEventListener('helix-dismiss', closed);
|
|
245
|
+
this.undoables.push({ item, keep, undo });
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
keepAll() {
|
|
249
|
+
for (const one of [...this.undoables]) {
|
|
250
|
+
one.keep();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
wordsOf(item) {
|
|
254
|
+
const hint = this.hints.get(item);
|
|
255
|
+
return hint ? joinSaid([messageWords(item), hint]) : messageWords(item);
|
|
256
|
+
}
|
|
158
257
|
add(message, options = {}) {
|
|
159
258
|
const tier = this.constructor.tier;
|
|
160
259
|
const item = document.createElement(`${tier}toast-item`);
|
|
@@ -291,7 +390,7 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
291
390
|
return;
|
|
292
391
|
}
|
|
293
392
|
for (const one of arrived) {
|
|
294
|
-
const words =
|
|
393
|
+
const words = this.wordsOf(one);
|
|
295
394
|
if (words !== '') {
|
|
296
395
|
speaker.ariaNotify(words, { priority: isDanger(one) ? 'high' : 'normal' });
|
|
297
396
|
}
|
|
@@ -305,6 +404,13 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
305
404
|
this.addEventListener('pointerleave', this.handlePointerLeave);
|
|
306
405
|
this.addEventListener('helix-dismiss', this.handleDismiss);
|
|
307
406
|
document.addEventListener('keydown', this.handleHotkey);
|
|
407
|
+
document.addEventListener('keydown', this.handleUndo);
|
|
408
|
+
window.addEventListener('pagehide', this.handlePageHide);
|
|
409
|
+
this.unregister = registerShortcut({
|
|
410
|
+
keys: () => this.hotkey,
|
|
411
|
+
label: () => this.hotkeyLabel,
|
|
412
|
+
owner: this,
|
|
413
|
+
});
|
|
308
414
|
this.watcher = new MutationObserver((records) => {
|
|
309
415
|
const added = records.flatMap((record) => [...record.addedNodes]);
|
|
310
416
|
this.restack();
|
|
@@ -325,6 +431,10 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
325
431
|
}
|
|
326
432
|
disconnectedCallback() {
|
|
327
433
|
super.disconnectedCallback();
|
|
434
|
+
this.unregister?.();
|
|
435
|
+
this.keepAll();
|
|
436
|
+
document.removeEventListener('keydown', this.handleUndo);
|
|
437
|
+
window.removeEventListener('pagehide', this.handlePageHide);
|
|
328
438
|
this.removeEventListener('focusin', this.handleFocusIn);
|
|
329
439
|
this.removeEventListener('focusout', this.handleFocusOut);
|
|
330
440
|
this.removeEventListener('pointerenter', this.handlePointerEnter);
|
|
@@ -359,6 +469,10 @@ let HelixHeadlessToast = class HelixHeadlessToast extends HelixElement {
|
|
|
359
469
|
__decorate([
|
|
360
470
|
property()
|
|
361
471
|
], HelixHeadlessToast.prototype, "hotkey", void 0);
|
|
472
|
+
__decorate([
|
|
473
|
+
words,
|
|
474
|
+
property({ attribute: 'hotkey-label' })
|
|
475
|
+
], HelixHeadlessToast.prototype, "hotkeyLabel", void 0);
|
|
362
476
|
__decorate([
|
|
363
477
|
words,
|
|
364
478
|
property()
|
|
@@ -378,6 +492,17 @@ __decorate([
|
|
|
378
492
|
__decorate([
|
|
379
493
|
state()
|
|
380
494
|
], HelixHeadlessToast.prototype, "urgent", void 0);
|
|
495
|
+
__decorate([
|
|
496
|
+
words,
|
|
497
|
+
property({ attribute: 'undo-hint' })
|
|
498
|
+
], HelixHeadlessToast.prototype, "undoHint", void 0);
|
|
499
|
+
__decorate([
|
|
500
|
+
property({ attribute: 'undo-keys' })
|
|
501
|
+
], HelixHeadlessToast.prototype, "undoKeys", void 0);
|
|
502
|
+
__decorate([
|
|
503
|
+
words,
|
|
504
|
+
property({ attribute: 'undo-label' })
|
|
505
|
+
], HelixHeadlessToast.prototype, "undoLabel", void 0);
|
|
381
506
|
HelixHeadlessToast = __decorate([
|
|
382
507
|
customElement('helix-headless-toast')
|
|
383
508
|
], HelixHeadlessToast);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HelixElement, HostClickController } from '@fusion.dev/helix-core';
|
|
1
|
+
import { HelixElement, HostClickController, ListedController } from '@fusion.dev/helix-core';
|
|
2
2
|
import { type PropertyValues, type TemplateResult } from 'lit';
|
|
3
3
|
declare const HelixHeadlessToggle_base: (new (...args: any[]) => import("@fusion.dev/helix-core").MixinSelectableItemInterface) & typeof HelixElement;
|
|
4
4
|
/**
|
|
@@ -39,6 +39,8 @@ declare const HelixHeadlessToggle_base: (new (...args: any[]) => import("@fusion
|
|
|
39
39
|
* @interactive button
|
|
40
40
|
*/
|
|
41
41
|
export declare class HelixHeadlessToggle extends HelixHeadlessToggle_base {
|
|
42
|
+
/** On the page's list of controls, where a command palette and a shortcut overlay find it. */
|
|
43
|
+
protected readonly listed: ListedController;
|
|
42
44
|
/** A click on the element itself, `click()` included, chooses it, as on `Radio`. */
|
|
43
45
|
protected readonly clicks: HostClickController;
|
|
44
46
|
/**
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
|
-
import { auditName, customElement, HelixElement, HostClickController, MixinSelectableItem, } from '@fusion.dev/helix-core';
|
|
2
|
+
import { auditName, customElement, HelixElement, HostClickController, ListedController, MixinSelectableItem, } from '@fusion.dev/helix-core';
|
|
3
3
|
import { html, nothing } from 'lit';
|
|
4
4
|
import { property } from 'lit/decorators.js';
|
|
5
5
|
let HelixHeadlessToggle = class HelixHeadlessToggle extends MixinSelectableItem(HelixElement) {
|
|
6
6
|
constructor() {
|
|
7
7
|
super(...arguments);
|
|
8
|
+
this.listed = new ListedController(this, 'press', () => this.internals?.ariaKeyShortcuts);
|
|
8
9
|
this.clicks = new HostClickController(this, () => this.partNamed('item'));
|
|
9
10
|
}
|
|
10
11
|
get defaultSelected() {
|
|
@@ -409,6 +409,8 @@ export declare class HelixHeadlessVirtualList extends HelixElement {
|
|
|
409
409
|
private filledFrom;
|
|
410
410
|
/** The function the drawn rows were filled by, so a new one draws them again. */
|
|
411
411
|
private filledBy;
|
|
412
|
+
/** Whether the drawn rows were cloned from the template or drawn for `renderItem`. */
|
|
413
|
+
private drawnBy;
|
|
412
414
|
/** The script the rows were read from, which the watcher follows. */
|
|
413
415
|
private source;
|
|
414
416
|
/**
|
|
@@ -702,8 +704,13 @@ export declare class HelixHeadlessVirtualList extends HelixElement {
|
|
|
702
704
|
* **A row that stays in the window keeps its element.** Clearing and
|
|
703
705
|
* cloning every row on every move replaced the node a reader had focused,
|
|
704
706
|
* so a link in a row lost focus to the body on any scroll, even with its row
|
|
705
|
-
* still on screen. Rows are keyed by item:
|
|
706
|
-
*
|
|
707
|
+
* still on screen. Rows are keyed by item: a row that stays keeps its
|
|
708
|
+
* element, and a row that leaves gives its element to a row that arrives.
|
|
709
|
+
*
|
|
710
|
+
* **A slotted row added or taken out while the box is moving ends the
|
|
711
|
+
* touch on iOS.** Safari reads a change to what a slot holds as a change to
|
|
712
|
+
* the box. The same nodes, filled with the arriving items, leave the slot
|
|
713
|
+
* as it was. Extra nodes stay in the tree hidden until the box is still.
|
|
707
714
|
*
|
|
708
715
|
* **The row holding focus is drawn outside the window too**, beside it on the
|
|
709
716
|
* side it belongs, and the spacer on that side gives up its room.
|
|
@@ -718,6 +725,15 @@ export declare class HelixHeadlessVirtualList extends HelixElement {
|
|
|
718
725
|
private placedSections;
|
|
719
726
|
/** Whether the rows were last placed in a waterfall. */
|
|
720
727
|
private placedWaterfall;
|
|
728
|
+
/**
|
|
729
|
+
* Row elements taken out of the window while the box is still moving, so
|
|
730
|
+
* the slot keeps the same nodes. Filled again when a row arrives.
|
|
731
|
+
*/
|
|
732
|
+
private pooled;
|
|
733
|
+
/** Hides a row group that has left the window, and leaves it in the tree. */
|
|
734
|
+
private parkRows;
|
|
735
|
+
/** Takes a row group out of the tree. */
|
|
736
|
+
private dropRows;
|
|
721
737
|
/** The lines of a grid drawn on the last pass, each a `row` the render draws a slot in. */
|
|
722
738
|
private drawnLines;
|
|
723
739
|
/** The function the drawn headers were drawn by, so a new one draws them again. */
|
|
@@ -188,6 +188,7 @@ let HelixHeadlessVirtualList = class HelixHeadlessVirtualList extends HelixEleme
|
|
|
188
188
|
};
|
|
189
189
|
this.visited = false;
|
|
190
190
|
this.placedWaterfall = false;
|
|
191
|
+
this.pooled = [];
|
|
191
192
|
this.drawnLines = [];
|
|
192
193
|
this.sectionId = nextSectionId();
|
|
193
194
|
}
|
|
@@ -575,12 +576,16 @@ let HelixHeadlessVirtualList = class HelixHeadlessVirtualList extends HelixEleme
|
|
|
575
576
|
const lined = this.lined;
|
|
576
577
|
element.setAttribute('role', this.selectionMode ? 'option' : lined ? 'gridcell' : 'listitem');
|
|
577
578
|
const across = this.across;
|
|
579
|
+
const keepSlot = lined && this.virtualize.holdsSlot();
|
|
578
580
|
for (const [name, value] of [
|
|
579
581
|
['aria-colindex', lined ? (at % across) + 1 : undefined],
|
|
580
582
|
['aria-posinset', lined ? undefined : at + 1],
|
|
581
583
|
['aria-setsize', lined ? undefined : this.data.length],
|
|
582
|
-
['slot', lined ? `${LINE}${Math.floor(at / across)}` : undefined],
|
|
584
|
+
['slot', lined && !keepSlot ? `${LINE}${Math.floor(at / across)}` : undefined],
|
|
583
585
|
]) {
|
|
586
|
+
if (name === 'slot' && keepSlot) {
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
584
589
|
if (value === undefined) {
|
|
585
590
|
element.removeAttribute(name);
|
|
586
591
|
}
|
|
@@ -656,10 +661,13 @@ let HelixHeadlessVirtualList = class HelixHeadlessVirtualList extends HelixEleme
|
|
|
656
661
|
const children = [
|
|
657
662
|
...[...this.children].filter((child) => child !== template &&
|
|
658
663
|
child instanceof HTMLElement &&
|
|
664
|
+
child.dataset.virtualPool === undefined &&
|
|
659
665
|
(child.dataset.index !== undefined || !child.hasAttribute('slot')) &&
|
|
660
666
|
!child.hasAttribute('data-section')),
|
|
661
667
|
...this.querySelectorAll(':scope > [data-section] > [data-index]'),
|
|
662
668
|
];
|
|
669
|
+
const redraw = regroup ||
|
|
670
|
+
(this.drawnBy !== undefined && this.drawnBy !== (this.renderItem ? 'function' : 'template'));
|
|
663
671
|
const plan = drawPlan({
|
|
664
672
|
across: this.across,
|
|
665
673
|
count,
|
|
@@ -667,24 +675,38 @@ let HelixHeadlessVirtualList = class HelixHeadlessVirtualList extends HelixEleme
|
|
|
667
675
|
first,
|
|
668
676
|
kept: this.keptIndex(),
|
|
669
677
|
last,
|
|
670
|
-
redraw
|
|
678
|
+
redraw,
|
|
671
679
|
});
|
|
672
680
|
const drawn = new Map();
|
|
681
|
+
const reusable = [...this.pooled];
|
|
682
|
+
this.pooled = [];
|
|
683
|
+
const leaving = new Map();
|
|
673
684
|
for (const child of children) {
|
|
674
685
|
const index = Number(child.dataset.index);
|
|
675
686
|
if (plan.remove.has(index)) {
|
|
676
687
|
this.sizes?.unobserve(child);
|
|
677
|
-
|
|
688
|
+
leaving.set(index, [...(leaving.get(index) ?? []), child]);
|
|
678
689
|
continue;
|
|
679
690
|
}
|
|
680
691
|
drawn.set(index, [...(drawn.get(index) ?? []), child]);
|
|
681
692
|
}
|
|
693
|
+
if (redraw) {
|
|
694
|
+
for (const group of [...reusable, ...leaving.values()]) {
|
|
695
|
+
this.dropRows(group);
|
|
696
|
+
}
|
|
697
|
+
reusable.length = 0;
|
|
698
|
+
leaving.clear();
|
|
699
|
+
}
|
|
700
|
+
else {
|
|
701
|
+
reusable.push(...leaving.values());
|
|
702
|
+
}
|
|
682
703
|
const refill = this.filledFrom !== this.data ||
|
|
683
704
|
this.filledBy !== this.renderItem ||
|
|
684
705
|
this.headedBy !== this.renderSection;
|
|
685
706
|
this.filledFrom = this.data;
|
|
686
707
|
this.filledBy = this.renderItem;
|
|
687
708
|
this.headedBy = this.renderSection;
|
|
709
|
+
this.drawnBy = this.renderItem ? 'function' : 'template';
|
|
688
710
|
const groups = this.groups(sections, plan.wanted, regroup, refill);
|
|
689
711
|
const fresh = new Set();
|
|
690
712
|
const anchors = new Map();
|
|
@@ -699,15 +721,67 @@ let HelixHeadlessVirtualList = class HelixHeadlessVirtualList extends HelixEleme
|
|
|
699
721
|
this.fill(group, at);
|
|
700
722
|
fresh.add(at);
|
|
701
723
|
}
|
|
724
|
+
if (!this.waterfall && this.virtualize.holdsSlot()) {
|
|
725
|
+
for (const element of group) {
|
|
726
|
+
;
|
|
727
|
+
element.style.order = String(at);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
702
730
|
anchors.set(parent, group.at(-1).nextElementSibling);
|
|
703
731
|
continue;
|
|
704
732
|
}
|
|
733
|
+
const width = this.renderItem ? 1 : (template?.content.childElementCount ?? 1);
|
|
734
|
+
const recycledAt = reusable.findIndex((one) => one.length === width);
|
|
735
|
+
const recycled = recycledAt === -1 ? undefined : reusable.splice(recycledAt, 1)[0];
|
|
736
|
+
if (recycled) {
|
|
737
|
+
for (const element of recycled) {
|
|
738
|
+
element.hidden = false;
|
|
739
|
+
element.removeAttribute('aria-hidden');
|
|
740
|
+
element.removeAttribute('data-virtual-pool');
|
|
741
|
+
}
|
|
742
|
+
this.fill(recycled, at);
|
|
743
|
+
this.watchSize(recycled);
|
|
744
|
+
drawn.set(at, recycled);
|
|
745
|
+
fresh.add(at);
|
|
746
|
+
if (!this.waterfall && this.virtualize.holdsSlot()) {
|
|
747
|
+
for (const element of recycled) {
|
|
748
|
+
element.style.order = String(at);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
if (recycled[0]?.parentElement !== parent || !this.virtualize.holdsSlot()) {
|
|
752
|
+
for (const element of recycled) {
|
|
753
|
+
parent.insertBefore(element, anchors.get(parent) ?? null);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
anchors.set(parent, recycled.at(-1).nextElementSibling);
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
759
|
+
if (this.virtualize.holdsSlot()) {
|
|
760
|
+
continue;
|
|
761
|
+
}
|
|
705
762
|
const fragment = this.draw(template, at);
|
|
706
763
|
drawn.set(at, [...fragment.children]);
|
|
707
764
|
this.watchSize([...fragment.children]);
|
|
708
765
|
fresh.add(at);
|
|
766
|
+
if (!this.waterfall && this.virtualize.holdsSlot()) {
|
|
767
|
+
for (const element of fragment.children) {
|
|
768
|
+
;
|
|
769
|
+
element.style.order = String(at);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
709
772
|
parent.insertBefore(fragment, anchors.get(parent) ?? null);
|
|
710
773
|
}
|
|
774
|
+
if (this.virtualize.holdsSlot()) {
|
|
775
|
+
for (const group of reusable) {
|
|
776
|
+
this.parkRows(group);
|
|
777
|
+
this.pooled.push(group);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
else {
|
|
781
|
+
for (const group of reusable) {
|
|
782
|
+
this.dropRows(group);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
711
785
|
this.active = stopAfter(this.active, plan.wanted, {
|
|
712
786
|
count,
|
|
713
787
|
first,
|
|
@@ -717,7 +791,7 @@ let HelixHeadlessVirtualList = class HelixHeadlessVirtualList extends HelixEleme
|
|
|
717
791
|
const chosen = this.chosen;
|
|
718
792
|
const off = this.disabled;
|
|
719
793
|
const lines = this.lined ? [...new Set(plan.wanted.map((at) => this.lineOf(at)))] : [];
|
|
720
|
-
if (lines.join() !== this.drawnLines.join()) {
|
|
794
|
+
if (lines.join() !== this.drawnLines.join() && !this.virtualize.holdsSlot()) {
|
|
721
795
|
this.drawnLines = lines;
|
|
722
796
|
this.requestUpdate();
|
|
723
797
|
}
|
|
@@ -726,13 +800,22 @@ let HelixHeadlessVirtualList = class HelixHeadlessVirtualList extends HelixEleme
|
|
|
726
800
|
for (const [at, group] of drawn) {
|
|
727
801
|
for (const element of group) {
|
|
728
802
|
this.mark(element, at, chosen, off);
|
|
803
|
+
const style = element.style;
|
|
804
|
+
if (!this.waterfall && !this.virtualize.holdsSlot()) {
|
|
805
|
+
style.removeProperty('order');
|
|
806
|
+
}
|
|
729
807
|
if (this.waterfall) {
|
|
730
|
-
const style = element.style;
|
|
731
808
|
style.setProperty('position', 'absolute');
|
|
732
809
|
style.setProperty('inset-block-start', `${this.virtualize.offsetOf(at)}px`);
|
|
733
810
|
style.setProperty('inset-inline-start', `calc((100% + ${gap}px) * ${this.lanes.lane(at)} / ${columns})`);
|
|
734
811
|
style.setProperty('inline-size', `calc((100% - ${gap * (columns - 1)}px) / ${columns})`);
|
|
735
812
|
}
|
|
813
|
+
else {
|
|
814
|
+
style.removeProperty('position');
|
|
815
|
+
style.removeProperty('inset-block-start');
|
|
816
|
+
style.removeProperty('inset-inline-start');
|
|
817
|
+
style.removeProperty('inline-size');
|
|
818
|
+
}
|
|
736
819
|
}
|
|
737
820
|
const stop = at === this.active;
|
|
738
821
|
group[0]?.setAttribute('tabindex', stop ? '0' : '-1');
|
|
@@ -755,6 +838,21 @@ let HelixHeadlessVirtualList = class HelixHeadlessVirtualList extends HelixEleme
|
|
|
755
838
|
}, 0);
|
|
756
839
|
}
|
|
757
840
|
}
|
|
841
|
+
parkRows(group) {
|
|
842
|
+
for (const element of group) {
|
|
843
|
+
element.hidden = true;
|
|
844
|
+
element.setAttribute('aria-hidden', 'true');
|
|
845
|
+
element.setAttribute('data-virtual-pool', '');
|
|
846
|
+
element.removeAttribute('data-index');
|
|
847
|
+
element.style.removeProperty('order');
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
dropRows(group) {
|
|
851
|
+
for (const element of group) {
|
|
852
|
+
this.sizes?.unobserve(element);
|
|
853
|
+
element.remove();
|
|
854
|
+
}
|
|
855
|
+
}
|
|
758
856
|
groups(sections, wanted, regroup, refill) {
|
|
759
857
|
const keep = new Set(sections ? wanted.map((at) => sectionAt(sections, at)) : []);
|
|
760
858
|
const groups = new Map();
|