@fusion.dev/helix-headless 0.1.0 → 0.3.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 +234 -234
- package/dist/accordion/item/accordion-item.js +0 -108
- package/dist/accordion/root/accordion-root.js +0 -33
- package/dist/announcement/root/announcement-root.js +1 -76
- package/dist/app-header/root/app-header-root.js +0 -84
- package/dist/avatar/group/avatar-group.js +0 -77
- package/dist/avatar/root/avatar-root.js +0 -72
- package/dist/badge/root/badge-root.js +0 -67
- package/dist/bar-chart/root/bar-chart-root.js +3 -263
- package/dist/blockquote/root/blockquote-root.js +0 -46
- package/dist/breadcrumbs/breadcrumb/breadcrumb.js +0 -72
- package/dist/breadcrumbs/root/breadcrumbs-root.js +0 -52
- package/dist/button/root/button-root.js +0 -215
- package/dist/button-group/root/button-group-root.js +0 -30
- package/dist/callout/root/callout-root.js +0 -52
- package/dist/card/root/card-root.js +0 -41
- package/dist/carousel/root/carousel-root.d.ts +2 -2
- package/dist/carousel/root/carousel-root.js +2 -362
- package/dist/chat/composer/chat-composer.js +0 -131
- package/dist/chat/message/chat-message.js +0 -137
- package/dist/chat/root/chat-root.js +0 -193
- package/dist/checkbox/root/checkbox-root.js +0 -113
- package/dist/checkbox-group/root/checkbox-group-root.js +1 -157
- package/dist/code/root/code-root.js +0 -26
- package/dist/code-block/root/code-block-root.js +0 -100
- package/dist/color-input/root/color-input-root.js +0 -217
- package/dist/color-picker/color.js +0 -69
- package/dist/color-picker/root/color-picker-root.js +0 -272
- package/dist/combobox/root/combobox-root.js +0 -428
- package/dist/command/root/command-root.js +0 -177
- package/dist/copy-button/root/copy-button-root.js +0 -134
- package/dist/data-table/root/data-table-root.js +0 -336
- package/dist/data-table/root/order.js +0 -100
- package/dist/date-input/root/date-input-root.js +1 -398
- package/dist/date-picker/root/date-picker-root.js +0 -358
- package/dist/dialog/root/dialog-root.js +0 -189
- package/dist/divider/root/divider-root.js +0 -71
- package/dist/donut-chart/root/donut-chart-root.js +0 -214
- package/dist/drawer/root/drawer-root.js +0 -116
- package/dist/drilldown/item/drilldown-item.js +0 -82
- package/dist/drilldown/root/drilldown-root.js +0 -91
- package/dist/element-events.generated.js +0 -5
- package/dist/empty/root/empty-root.js +0 -35
- package/dist/file-input/root/file-input-root.js +0 -232
- package/dist/format-date/root/format-date-root.js +0 -95
- package/dist/heatmap/root/buckets.js +0 -57
- package/dist/heatmap/root/heatmap-root.js +0 -313
- package/dist/icon/root/icon-root.js +0 -48
- package/dist/icon-button/root/icon-button-root.js +0 -30
- package/dist/image/root/image-root.js +0 -174
- package/dist/index.js +0 -9
- package/dist/input/root/input-root.js +0 -228
- package/dist/kbd/root/kbd-root.js +0 -117
- package/dist/legend/root/legend-root.js +0 -73
- package/dist/line-chart/root/line-chart-root.js +0 -172
- package/dist/list/item/list-item.js +0 -92
- package/dist/list/root/list-root.js +0 -26
- package/dist/listbox/root/listbox-root.js +2 -429
- package/dist/loader/root/loader-root.js +0 -40
- package/dist/megamenu/root/megamenu-root.js +0 -284
- package/dist/menu/item/menu-item.js +1 -221
- package/dist/menu/root/menu-root.js +1 -171
- package/dist/meter/root/meter-root.js +1 -152
- package/dist/navigation/root/navigation-root.js +0 -56
- package/dist/notifications/notification/notification.js +0 -159
- package/dist/notifications/root/notifications-root.js +0 -148
- package/dist/number-input/root/number-input-root.js +1 -263
- package/dist/option/group/option-group.js +0 -26
- package/dist/option/root/option-root.js +0 -157
- package/dist/outline/root/outline-root.js +0 -292
- package/dist/pagination/root/pagination-root.js +0 -361
- package/dist/pagination/size/pagination-size.js +0 -104
- package/dist/pagination/summary/pagination-summary.js +0 -90
- package/dist/pin-input/root/pin-input-root.js +0 -276
- package/dist/popover/root/popover-root.js +0 -103
- package/dist/progress/root/progress-root.js +1 -133
- package/dist/qr-code/root/qr-code-root.js +0 -96
- package/dist/quote/root/quote-root.js +0 -25
- package/dist/radio/group/radio-group.js +0 -81
- package/dist/radio/root/radio-root.js +0 -85
- package/dist/rating/root/rating-root.js +0 -220
- package/dist/scroll-area/root/scroll-area-root.js +0 -100
- package/dist/select/root/select-root.js +2 -218
- package/dist/skeleton/root/skeleton-root.js +0 -20
- package/dist/slider/root/slider-root.js +1 -267
- package/dist/sparkline/root/sparkline-root.js +3 -164
- package/dist/speed-dial/item/speed-dial-item.js +0 -52
- package/dist/speed-dial/root/speed-dial-root.js +1 -116
- package/dist/splitter/root/splitter-root.js +0 -489
- package/dist/stat/group/stat-group.js +0 -18
- package/dist/stat/root/stat-root.js +0 -23
- package/dist/steps/root/steps-root.js +0 -62
- package/dist/steps/step/step.js +0 -131
- package/dist/switch/root/switch-root.js +0 -80
- package/dist/table/cell/table-cell.js +0 -23
- package/dist/table/column/table-column.js +0 -158
- package/dist/table/root/table-root.js +0 -82
- package/dist/table/row/table-row.js +0 -21
- package/dist/tabs/panel/tab-panel.js +0 -49
- package/dist/tabs/root/tabs-root.js +0 -98
- package/dist/tabs/tab/tab.js +0 -59
- package/dist/tag/root/tag-root.js +0 -31
- package/dist/textarea/root/textarea-root.js +0 -162
- package/dist/time-input/root/time-input-root.js +0 -283
- package/dist/time-picker/root/time-picker-root.js +0 -326
- package/dist/timeline/item/timeline-item.js +0 -66
- package/dist/timeline/root/timeline-root.js +0 -41
- package/dist/toast/item/toast-item.js +0 -165
- package/dist/toast/root/toast-root.js +0 -51
- package/dist/toggle/group/toggle-group.js +0 -150
- package/dist/toggle/root/toggle-root.js +0 -78
- package/dist/toolbar/root/toolbar-root.js +0 -116
- package/dist/tooltip/root/tooltip-root.js +0 -427
- package/dist/tour/root/tour-root.js +0 -130
- package/dist/tour/stop/tour-stop.js +1 -127
- package/dist/tree/item/tree-item.js +0 -198
- package/dist/tree/root/tree-root.js +0 -97
- package/dist/trend/root/trend-root.js +0 -53
- package/dist/video/root/video-root.d.ts +8 -12
- package/dist/video/root/video-root.js +5 -756
- package/dist/video-playlist/item/video-playlist-item.js +1 -90
- package/dist/video-playlist/menu/video-playlist-menu.js +1 -132
- package/dist/video-playlist/root/video-playlist-root.js +0 -113
- package/dist/virtual-list/root/virtual-list-root.js +0 -105
- package/jsx.d.ts +1408 -2576
- package/package.json +6 -6
- package/vue.d.ts +1 -1
|
@@ -8,7 +8,6 @@ import { closestInstance, customElement, HelixElement, MixinCollection, MixinCon
|
|
|
8
8
|
import { html, nothing } from 'lit';
|
|
9
9
|
import { property } from 'lit/decorators.js';
|
|
10
10
|
import { HelixHeadlessTreeItem } from '../item/tree-item.js';
|
|
11
|
-
/** Keys the tree handles, per the APG tree pattern. */
|
|
12
11
|
const KEYS = new Set([
|
|
13
12
|
'ArrowDown',
|
|
14
13
|
'ArrowUp',
|
|
@@ -19,59 +18,15 @@ const KEYS = new Set([
|
|
|
19
18
|
'Enter',
|
|
20
19
|
' ',
|
|
21
20
|
]);
|
|
22
|
-
/**
|
|
23
|
-
* @summary A tree of items, navigable entirely from the keyboard.
|
|
24
|
-
*
|
|
25
|
-
* @description
|
|
26
|
-
* Focus is a single tab stop, moved with the arrow keys, which is what the tree
|
|
27
|
-
* pattern requires: a sidebar of forty items should not be forty presses of Tab
|
|
28
|
-
* to get past. The tree owns which item is the tab stop and moves it as focus
|
|
29
|
-
* moves, so the browser's own focus order is never fought with.
|
|
30
|
-
*
|
|
31
|
-
* Items are found with `instanceof`, never by tag name, so the headless tier
|
|
32
|
-
* does not learn about the styled one.
|
|
33
|
-
*
|
|
34
|
-
* @since 0.1.0
|
|
35
|
-
* @status experimental
|
|
36
|
-
* @category navigation
|
|
37
|
-
* @aliases FileTree, Navigation tree
|
|
38
|
-
* @documentation https://helix.fusion.dev/components/tree
|
|
39
|
-
*
|
|
40
|
-
* @slot - The tree's items.
|
|
41
|
-
*
|
|
42
|
-
* @event {HelixActivateEvent} helix-activate - Fired once the current one has moved, so the element already holds it.
|
|
43
|
-
* @event {HelixBeforeActivateEvent} helix-before-activate - Fired before the current node moves, and cancelable. The only way to refuse one.
|
|
44
|
-
* @event {HelixSelectEvent} helix-select - Fired when an item is chosen. Dispatched by the item and listened for here, because the tree is what a consumer holds a reference to. Cancelable: refusing it takes the decision and nothing moves.
|
|
45
|
-
*
|
|
46
|
-
* @csspart empty - Shown when there are no rows to show.
|
|
47
|
-
* @csspart loading - Shown while the rows are still on their way.
|
|
48
|
-
* @csspart tree - The tree container.
|
|
49
|
-
*/
|
|
50
21
|
let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinControllerActive(HelixElement)) {
|
|
51
22
|
constructor() {
|
|
52
23
|
super(...arguments);
|
|
53
|
-
/**
|
|
54
|
-
* Accessible name for the tree.
|
|
55
|
-
*/
|
|
56
24
|
this.label = 'Tree';
|
|
57
|
-
/* Through the mixin, so a consumer can refuse the change. Writing the value
|
|
58
|
-
straight from the event makes `helix-before-activate` an announcement
|
|
59
|
-
nobody can answer. */
|
|
60
25
|
this.handleSelection = (event) => {
|
|
61
26
|
this.requestActive(event.detail.value);
|
|
62
27
|
this.syncItems();
|
|
63
28
|
};
|
|
64
29
|
this.handleKeydown = (event) => {
|
|
65
|
-
/* The innermost item the press came from, which `find` cannot give.
|
|
66
|
-
*
|
|
67
|
-
* `items` is every tree item in document order and a nested one is inside
|
|
68
|
-
* all of its ancestors, so `entry.contains(target)` matches the outermost
|
|
69
|
-
* ancestor first and every key pressed on a nested node moves the root of
|
|
70
|
-
* its branch instead. The shallow cases all look right.
|
|
71
|
-
*
|
|
72
|
-
* `closestInstance` walks up by identity and crosses shadow roots on the
|
|
73
|
-
* way, which is the util that exists for exactly this. `closest('*')` is a
|
|
74
|
-
* no-op: it returns the element it was called on. */
|
|
75
30
|
const current = closestInstance(event.target, HelixHeadlessTreeItem);
|
|
76
31
|
if (!current || !this.items.includes(current) || !KEYS.has(event.key)) {
|
|
77
32
|
return;
|
|
@@ -89,8 +44,6 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
89
44
|
this.focusOn(this.visibleItems.at(-1));
|
|
90
45
|
}
|
|
91
46
|
else if (event.key === 'ArrowRight') {
|
|
92
|
-
// Open a closed branch, then step into it. Two presses rather than one
|
|
93
|
-
// that does both, which is what the pattern specifies.
|
|
94
47
|
if (current.isBranch && !current.open) {
|
|
95
48
|
current.requestOpen(true);
|
|
96
49
|
this.syncItems();
|
|
@@ -115,43 +68,18 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
115
68
|
this.syncItems();
|
|
116
69
|
}
|
|
117
70
|
else {
|
|
118
|
-
/* `activate`, not `select`. Announcing the choice and stopping there
|
|
119
|
-
leaves a tree used as navigation walkable with the arrows and never
|
|
120
|
-
enterable: the pointer has a link under it and the keyboard has
|
|
121
|
-
nothing. */
|
|
122
71
|
current.activate();
|
|
123
72
|
}
|
|
124
73
|
}
|
|
125
74
|
event.preventDefault();
|
|
126
75
|
};
|
|
127
|
-
/**
|
|
128
|
-
* A branch opened or closed, whoever did it.
|
|
129
|
-
*
|
|
130
|
-
* Listening for the item's own open events rather than calling `syncItems`
|
|
131
|
-
* from each keyboard path: that misses the pointer, and collapsing a branch
|
|
132
|
-
* by clicking its chevron then leaves the tree's one tab stop on a row inside
|
|
133
|
-
* the subtree just hidden. It also covers a consumer setting `open` directly.
|
|
134
|
-
*/
|
|
135
76
|
this.handleBranch = () => {
|
|
136
77
|
this.syncItems();
|
|
137
78
|
};
|
|
138
79
|
}
|
|
139
|
-
/**
|
|
140
|
-
* Every item, in the order a reader moving down would meet them.
|
|
141
|
-
*
|
|
142
|
-
* Selected by tag, never by `'*'` and a filter: this is the array a single
|
|
143
|
-
* arrow press rebuilds, and `'*'` makes it every descendant element in the
|
|
144
|
-
* tree, labels and icons and whatever a consumer slotted into a row included.
|
|
145
|
-
*
|
|
146
|
-
* The two tag names rather than `instanceof` on everything: a styled
|
|
147
|
-
* `helix-tree-item` extends the base, so both names are needed, and the
|
|
148
|
-
* `instanceof` stays as the type guard because a consumer can write either
|
|
149
|
-
* tag and neither selector proves what the element is.
|
|
150
|
-
*/
|
|
151
80
|
get items() {
|
|
152
81
|
return [...this.querySelectorAll('helix-tree-item, helix-headless-tree-item')].filter((node) => node instanceof HelixHeadlessTreeItem);
|
|
153
82
|
}
|
|
154
|
-
/** Items a reader can actually reach: not inside a collapsed branch. */
|
|
155
83
|
get visibleItems() {
|
|
156
84
|
return this.items.filter((item) => {
|
|
157
85
|
let parent = item.parentElement;
|
|
@@ -164,23 +92,9 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
164
92
|
return true;
|
|
165
93
|
});
|
|
166
94
|
}
|
|
167
|
-
/**
|
|
168
|
-
* Pushes tree-owned state down: which item is selected, which holds the tab
|
|
169
|
-
* stop, and how deep each one sits.
|
|
170
|
-
*
|
|
171
|
-
* Depth is computed here rather than by each item counting its own ancestors,
|
|
172
|
-
* so an item moved in the tree gets the right indent without knowing it moved.
|
|
173
|
-
*/
|
|
174
95
|
syncItems() {
|
|
175
96
|
const visible = this.visibleItems;
|
|
176
|
-
/* Through the mixin, which resolves an exact match and otherwise falls back
|
|
177
|
-
to the first item. No disabled rows are skipped, because `Tree.Item` is
|
|
178
|
-
the only selectable row in the library with no `disabled` property. */
|
|
179
97
|
const chosen = this.resolveActive(visible);
|
|
180
|
-
/* The keyboard keeps its place: the stop moves only when the row holding it
|
|
181
|
-
is no longer reachable. Bound to the selection instead, a branch opening
|
|
182
|
-
or a child arriving throws the reader back to the selected row from
|
|
183
|
-
wherever they had arrowed to. */
|
|
184
98
|
const held = visible.find((item) => item.focusable);
|
|
185
99
|
const stop = held ?? chosen;
|
|
186
100
|
for (const item of this.items) {
|
|
@@ -211,12 +125,6 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
211
125
|
entry.focusable = entry === item;
|
|
212
126
|
}
|
|
213
127
|
item.focusItem();
|
|
214
|
-
/* And bring it into view, or focus lands below the fold and the tree stays
|
|
215
|
-
where it is.
|
|
216
|
-
|
|
217
|
-
Not `scrollIntoView`, which scrolls every scrollable ancestor including
|
|
218
|
-
the page. A reader who pressed Down in a sidebar did not ask the document
|
|
219
|
-
to move. */
|
|
220
128
|
scrollItemIntoView(item, { padding: 4 });
|
|
221
129
|
}
|
|
222
130
|
connectedCallback() {
|
|
@@ -225,11 +133,6 @@ let HelixHeadlessTree = class HelixHeadlessTree extends MixinCollection(MixinCon
|
|
|
225
133
|
this.addEventListener('helix-before-open', this.handleBranch);
|
|
226
134
|
this.addEventListener('helix-before-close', this.handleBranch);
|
|
227
135
|
this.addEventListener('keydown', this.handleKeydown);
|
|
228
|
-
/* Nested items arrive on a *branch's* slot, not on this element's, so the
|
|
229
|
-
root's `slotchange` never fires for them: without this, a subtree
|
|
230
|
-
rendered after first paint gets no `level`, no `selected` and no
|
|
231
|
-
`focusable`, and sits at the wrong indent with no way into it. A
|
|
232
|
-
framework filling a branch on demand is exactly that case. */
|
|
233
136
|
this.watcher = new MutationObserver(() => this.syncItems());
|
|
234
137
|
this.watcher.observe(this, { childList: true, subtree: true });
|
|
235
138
|
}
|
|
@@ -9,73 +9,20 @@ import { arrowDown, arrowUp, minus } from '@fusion.dev/helix-icons';
|
|
|
9
9
|
import { html } from 'lit';
|
|
10
10
|
import { property } from 'lit/decorators.js';
|
|
11
11
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
12
|
-
/** The three directions a measurement can have moved, and how each is drawn. */
|
|
13
12
|
const DIRECTIONS = {
|
|
14
13
|
down: { icon: arrowDown, word: 'Down' },
|
|
15
14
|
neutral: { icon: minus, word: 'Unchanged' },
|
|
16
15
|
up: { icon: arrowUp, word: 'Up' },
|
|
17
16
|
};
|
|
18
|
-
/**
|
|
19
|
-
* Reads the direction, treating an absent or unrecognised one as neutral.
|
|
20
|
-
*
|
|
21
|
-
* The cast is a lie the fallback catches: an attribute is a string and a
|
|
22
|
-
* consumer can write anything into it, so an unrecognised word has to draw
|
|
23
|
-
* something rather than fail to index and throw inside `render`.
|
|
24
|
-
*/
|
|
25
17
|
const readDirection = (value) => DIRECTIONS[value] ?? DIRECTIONS.neutral;
|
|
26
|
-
/**
|
|
27
|
-
* @summary Which way a measurement moved, and whether that is good news.
|
|
28
|
-
*
|
|
29
|
-
* @description
|
|
30
|
-
* Three parts: a direction that is up, down or neutral, the metric that moved,
|
|
31
|
-
* and a label saying over what. The arrow carries the direction and its color
|
|
32
|
-
* carries the judgment, and the two are separate properties because they are
|
|
33
|
-
* separate facts.
|
|
34
|
-
*
|
|
35
|
-
* **`good` is absent by default, so an unjudged trend is gray.** Every
|
|
36
|
-
* dashboard convention says up is green, and for churn, latency, error rate,
|
|
37
|
-
* cost and bounce rate that convention is a lie told in the most legible color
|
|
38
|
-
* on the page. State the metric's polarity once and the component does the part
|
|
39
|
-
* that varies.
|
|
40
|
-
*
|
|
41
|
-
* The direction is also written as a word, because a colored arrow says
|
|
42
|
-
* nothing to a reader who is not looking at it. `part="direction"` is what the
|
|
43
|
-
* styled tier clips out of sight and leaves in the accessibility tree.
|
|
44
|
-
*
|
|
45
|
-
* Both the metric and the label are bare slots. An element whose only job is to
|
|
46
|
-
* assign itself a slot on connect gives its own host an attribute after
|
|
47
|
-
* upgrade, which a React consumer's server markup never had.
|
|
48
|
-
*
|
|
49
|
-
* @since 0.1.0
|
|
50
|
-
* @status stable
|
|
51
|
-
* @category charts
|
|
52
|
-
* @aliases Delta, Change, Movement
|
|
53
|
-
* @documentation https://helix.fusion.dev/components/trend
|
|
54
|
-
*
|
|
55
|
-
* @slot - The metric that moved.
|
|
56
|
-
* @slot label - What it moved over.
|
|
57
|
-
*
|
|
58
|
-
* @csspart direction - The direction as a word, for readers who are not looking.
|
|
59
|
-
* @csspart icon - The arrow.
|
|
60
|
-
*/
|
|
61
18
|
let HelixHeadlessTrend = class HelixHeadlessTrend extends HelixElement {
|
|
62
19
|
render() {
|
|
63
20
|
const direction = readDirection(this.direction);
|
|
64
|
-
/* Silent on a neutral move, whatever `good` says. Neither better nor worse
|
|
65
|
-
is a reading of "unchanged" that the word already carries. */
|
|
66
21
|
const judgment = this.good && this.direction && this.direction !== 'neutral'
|
|
67
22
|
? this.good === this.direction
|
|
68
23
|
? ', better'
|
|
69
24
|
: ', worse'
|
|
70
25
|
: '';
|
|
71
|
-
/* One interpolation rather than two, so the phrase is one text node.
|
|
72
|
-
Lit SSR writes a `<!--lit-part-->` marker around every binding, and two
|
|
73
|
-
bindings put a pair of comments between "Up" and ", worse" in the served
|
|
74
|
-
markup, which a spec then cannot assert in one string. */
|
|
75
|
-
/* Written out rather than through `drawIcon`, because this one needs a
|
|
76
|
-
`part` and a part behind an interpolation is one the manifest cannot see:
|
|
77
|
-
the helper's `part=${…}` binding took `[part="icon"]` out of the
|
|
78
|
-
stylesheet's reach. */
|
|
79
26
|
return html `<svg
|
|
80
27
|
aria-hidden="true"
|
|
81
28
|
data-glyph
|
|
@@ -26,19 +26,15 @@ import '../../menu/index.js';
|
|
|
26
26
|
* The keys are the ones every player uses: Space and `k` to play or pause, the
|
|
27
27
|
* arrows to seek and to change the volume, `m` to mute, `f` for fullscreen.
|
|
28
28
|
* They are bound on this element rather than on the document, because a video
|
|
29
|
-
* is not a palette: keys belong to it only while a reader is on it.
|
|
29
|
+
* is not a palette: keys belong to it only while a reader is on it. Where
|
|
30
|
+
* `controls` is set they are not bound at all, since two handlers on one press
|
|
31
|
+
* is a video that seeks twice, and the focus stop goes with them.
|
|
30
32
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* **`<source>` and `<track>` are copied into the video, not slotted into it.**
|
|
37
|
-
* A media element runs its resource selection over its own child *nodes*, and a
|
|
38
|
-
* slot is one node: the sources and the caption tracks a consumer wrote were
|
|
39
|
-
* assigned into the flattened tree and the video never saw any of them. It had
|
|
40
|
-
* no text tracks, no current source and a `readyState` of zero, so a video
|
|
41
|
-
* given sources this way did not merely lack captions, it did not play.
|
|
33
|
+
* **`<source>` and `<track>` are copied into the video, never slotted into it.**
|
|
34
|
+
* A media element runs resource selection over its own child *nodes*, and a slot
|
|
35
|
+
* is one node, so slotted sources reach it as nothing: no text tracks, no
|
|
36
|
+
* current source, `readyState` zero. A video given sources that way does not
|
|
37
|
+
* merely lack captions, it does not play.
|
|
42
38
|
*
|
|
43
39
|
* They are copied rather than moved, because the consumer's light DOM is theirs
|
|
44
40
|
* and a framework that re-renders it would find its children gone. The copies
|