@fusion.dev/helix-headless 0.144.0 → 0.145.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 +8312 -881
- package/dist/accordion/item/accordion-item.d.ts +48 -12
- package/dist/accordion/item/accordion-item.js +26 -5
- package/dist/accordion/root/accordion-root.d.ts +6 -0
- package/dist/accordion/root/accordion-root.js +7 -1
- package/dist/announcement/root/announcement-root.d.ts +21 -1
- package/dist/announcement/root/announcement-root.js +36 -1
- package/dist/app-header/root/app-header-root.d.ts +7 -0
- package/dist/app-header/root/app-header-root.js +5 -1
- package/dist/app-header/sectioning.d.ts +7 -0
- package/dist/app-header/sectioning.js +26 -0
- package/dist/breadcrumbs/root/breadcrumbs-root.d.ts +32 -1
- package/dist/breadcrumbs/root/breadcrumbs-root.js +25 -2
- package/dist/canvas/root/canvas-root.d.ts +38 -3
- package/dist/canvas/root/canvas-root.js +121 -40
- package/dist/carousel/root/carousel-root.d.ts +90 -0
- package/dist/carousel/root/carousel-root.js +134 -12
- package/dist/chat/composer/chat-composer.d.ts +38 -6
- package/dist/chat/composer/chat-composer.js +42 -9
- package/dist/chat/message/chat-message.d.ts +32 -1
- package/dist/chat/message/chat-message.js +25 -9
- package/dist/chat/naming.d.ts +22 -0
- package/dist/chat/naming.js +12 -0
- package/dist/chat/relative-clock.d.ts +39 -0
- package/dist/chat/relative-clock.js +31 -0
- package/dist/chat/root/chat-root.d.ts +36 -0
- package/dist/chat/root/chat-root.js +24 -1
- package/dist/code-block/root/code-block-root.d.ts +8 -1
- package/dist/code-block/root/code-block-root.js +5 -5
- package/dist/copy-button/root/copy-button-root.d.ts +21 -1
- package/dist/copy-button/root/copy-button-root.js +2 -2
- package/dist/data-table/root/data-table-root.d.ts +150 -2
- package/dist/data-table/root/data-table-root.js +303 -29
- package/dist/data-table/tree.d.ts +40 -0
- package/dist/data-table/tree.js +55 -0
- package/dist/description-list/item/description-list-item.d.ts +17 -2
- package/dist/description-list/item/description-list-item.js +15 -2
- package/dist/description-list/root/description-list-root.d.ts +27 -1
- package/dist/description-list/root/description-list-root.js +26 -1
- package/dist/drilldown/item/drilldown-item.d.ts +11 -6
- package/dist/drilldown/item/drilldown-item.js +8 -5
- package/dist/drilldown/root/drilldown-root.d.ts +11 -0
- package/dist/drilldown/root/drilldown-root.js +8 -3
- package/dist/element-events.generated.js +53 -8
- package/dist/filter-input/menu/filter-menu.d.ts +3 -0
- package/dist/filter-input/menu/filter-menu.js +8 -4
- package/dist/image/root/image-root.js +9 -1
- package/dist/input/root/input-root.d.ts +1 -1
- package/dist/input/root/input-root.js +2 -2
- package/dist/list/item/list-item.d.ts +68 -1
- package/dist/list/item/list-item.js +66 -4
- package/dist/list/numbering.d.ts +14 -0
- package/dist/list/numbering.js +8 -0
- package/dist/list/root/list-root.d.ts +106 -9
- package/dist/list/root/list-root.js +189 -4
- package/dist/list/selection.d.ts +19 -0
- package/dist/list/selection.js +21 -0
- package/dist/listbox/root/listbox-root.js +1 -2
- package/dist/map/root/map-root.d.ts +6 -2
- package/dist/map/root/map-root.js +5 -2
- package/dist/megamenu/root/megamenu-root.d.ts +21 -0
- package/dist/megamenu/root/megamenu-root.js +16 -2
- package/dist/menu/index.d.ts +1 -0
- package/dist/menu/index.js +1 -0
- package/dist/menu/item/menu-item.d.ts +38 -11
- package/dist/menu/item/menu-item.js +33 -1
- package/dist/menu/root/menu-root.d.ts +25 -1
- package/dist/menu/root/menu-root.js +63 -6
- package/dist/menu/section/menu-section.d.ts +55 -0
- package/dist/menu/section/menu-section.js +60 -0
- package/dist/navigation/root/navigation-root.d.ts +16 -1
- package/dist/navigation/root/navigation-root.js +27 -1
- package/dist/notifications/root/notifications-root.d.ts +18 -0
- package/dist/notifications/root/notifications-root.js +17 -1
- package/dist/object-inspector/root/object-inspector-root.d.ts +97 -16
- package/dist/object-inspector/root/object-inspector-root.js +179 -79
- package/dist/object-inspector/rows.d.ts +57 -0
- package/dist/object-inspector/rows.js +86 -0
- package/dist/outline/levels.d.ts +31 -0
- package/dist/outline/levels.js +23 -0
- package/dist/outline/root/outline-root.d.ts +68 -3
- package/dist/outline/root/outline-root.js +73 -8
- package/dist/pagination/size/pagination-size.d.ts +11 -2
- package/dist/pagination/size/pagination-size.js +19 -4
- package/dist/radio/group/radio-group.d.ts +4 -10
- package/dist/radio/group/radio-group.js +5 -10
- package/dist/rating/root/rating-root.d.ts +1 -1
- package/dist/rating/root/rating-root.js +2 -2
- package/dist/scroll-area/root/scroll-area-root.d.ts +113 -0
- package/dist/scroll-area/root/scroll-area-root.js +218 -3
- package/dist/scroll-area/scrollbar.d.ts +65 -0
- package/dist/scroll-area/scrollbar.js +24 -0
- package/dist/select/root/select-root.js +1 -1
- package/dist/splitter/root/splitter-root.d.ts +13 -0
- package/dist/splitter/root/splitter-root.js +20 -2
- package/dist/splitter/snap.d.ts +9 -0
- package/dist/splitter/snap.js +12 -0
- package/dist/steps/reach.d.ts +15 -0
- package/dist/steps/reach.js +12 -0
- package/dist/steps/root/steps-root.d.ts +30 -0
- package/dist/steps/root/steps-root.js +53 -0
- package/dist/steps/step/step.d.ts +38 -2
- package/dist/steps/step/step.js +28 -6
- package/dist/table/column/table-column.d.ts +11 -0
- package/dist/table/column/table-column.js +6 -1
- package/dist/table/root/table-root.d.ts +101 -0
- package/dist/table/root/table-root.js +166 -5
- package/dist/table/row/table-row.d.ts +47 -1
- package/dist/table/row/table-row.js +39 -2
- package/dist/tabs/panel/tab-panel.d.ts +9 -5
- package/dist/tabs/panel/tab-panel.js +3 -4
- package/dist/tabs/root/tabs-root.d.ts +25 -1
- package/dist/tabs/root/tabs-root.js +21 -3
- package/dist/tabs/tab/tab.d.ts +36 -4
- package/dist/tabs/tab/tab.js +46 -3
- package/dist/timeline/group/timeline-group.d.ts +46 -0
- package/dist/timeline/group/timeline-group.js +37 -0
- package/dist/timeline/index.d.ts +1 -0
- package/dist/timeline/index.js +1 -0
- package/dist/timeline/root/timeline-root.d.ts +10 -3
- package/dist/toast/item/toast-item.d.ts +10 -17
- package/dist/toast/item/toast-item.js +15 -36
- package/dist/toolbar/root/toolbar-root.d.ts +13 -0
- package/dist/toolbar/root/toolbar-root.js +15 -5
- package/dist/tree/item/tree-item.d.ts +54 -1
- package/dist/tree/item/tree-item.js +89 -20
- package/dist/tree/root/tree-root.d.ts +37 -0
- package/dist/tree/root/tree-root.js +51 -6
- package/dist/tree/selection.d.ts +24 -0
- package/dist/tree/selection.js +26 -0
- package/dist/video/media-events.d.ts +49 -0
- package/dist/video/media-events.js +39 -0
- package/dist/video/root/video-root.d.ts +99 -13
- package/dist/video/root/video-root.js +84 -47
- package/dist/video-playlist/menu/video-playlist-menu.d.ts +3 -0
- package/dist/video-playlist/menu/video-playlist-menu.js +2 -1
- package/dist/video-playlist/order.d.ts +41 -0
- package/dist/video-playlist/order.js +34 -0
- package/dist/video-playlist/root/video-playlist-root.d.ts +70 -2
- package/dist/video-playlist/root/video-playlist-root.js +60 -16
- package/dist/virtual-list/controls.d.ts +4 -0
- package/dist/virtual-list/controls.js +30 -0
- package/dist/virtual-list/fill.d.ts +30 -0
- package/dist/virtual-list/fill.js +39 -0
- package/dist/virtual-list/keys.d.ts +15 -0
- package/dist/virtual-list/keys.js +24 -0
- package/dist/virtual-list/root/virtual-list-root.d.ts +155 -23
- package/dist/virtual-list/root/virtual-list-root.js +175 -34
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +3778 -801
- package/types/svelte.d.ts +2 -0
- package/types/vue.d.ts +782 -215
- package/dist/listbox/range.d.ts +0 -17
- package/dist/listbox/range.js +0 -5
|
@@ -5,22 +5,23 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
var HelixHeadlessObjectInspector_1;
|
|
8
|
-
import { AriaForwardController, CopyController, customElement, elementById, fillTemplate, formatNumbers, HelixElement, inlineStep, scrollItemIntoView, searchableById, VirtualizeController, } from '@fusion.dev/helix-core';
|
|
8
|
+
import { AriaForwardController, CopyController, countLabel, customElement, drawStatus, elementById, fillTemplate, formatNumbers, HelixActivateEvent, HelixBeforeActivateEvent, HelixElement, HelixFilterEvent, HelixFilteredEvent, inlineStep, requestChange, StatusController, scrollItemIntoView, searchableById, VirtualizeController, } from '@fusion.dev/helix-core';
|
|
9
9
|
import { caretDown, caretRight } from '@fusion.dev/helix-icons';
|
|
10
10
|
import { html, nothing } from 'lit';
|
|
11
11
|
import { property, state } from 'lit/decorators.js';
|
|
12
12
|
import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
|
|
13
13
|
import { html as staticHtml } from 'lit/static-html.js';
|
|
14
14
|
import '../../copy-button/index.js';
|
|
15
|
-
|
|
16
|
-
const entries = (value) => Array.isArray(value) ? value.map((item, at) => [String(at), item]) : Object.entries(value);
|
|
17
|
-
const child = (path, key) => `${path}/${key.replaceAll('~', '~0').replaceAll('/', '~1')}`;
|
|
15
|
+
import { ancestorsOf, entries, flatten, search, seed } from '../rows.js';
|
|
18
16
|
let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends HelixElement {
|
|
19
17
|
constructor() {
|
|
20
18
|
super(...arguments);
|
|
21
19
|
this.copyLabel = 'Copy {name}';
|
|
22
20
|
this.copyValueLabel = 'Copy value';
|
|
23
21
|
this.defaultDepth = 1;
|
|
22
|
+
this.filter = '';
|
|
23
|
+
this.filterable = false;
|
|
24
|
+
this.filterLabel = 'Filter';
|
|
24
25
|
this.for = '';
|
|
25
26
|
this.itemLabel = '{count} item';
|
|
26
27
|
this.itemsLabel = '{count} items';
|
|
@@ -28,12 +29,14 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
28
29
|
this.keysLabel = '{count} keys';
|
|
29
30
|
this.label = '';
|
|
30
31
|
this.noCopy = false;
|
|
32
|
+
this.resultLabel = '{count} result';
|
|
33
|
+
this.resultsLabel = '{count} results';
|
|
31
34
|
this.treeLabel = 'Value';
|
|
32
35
|
this.value = undefined;
|
|
33
36
|
this.windowed = false;
|
|
34
37
|
this.read = undefined;
|
|
35
38
|
this.opened = new Set();
|
|
36
|
-
this.
|
|
39
|
+
this.cursor = 0;
|
|
37
40
|
this.revealing = false;
|
|
38
41
|
this.typed = { at: 0, text: '' };
|
|
39
42
|
this.branches = new Set();
|
|
@@ -41,6 +44,7 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
41
44
|
label: true,
|
|
42
45
|
target: () => this.partNamed('tree'),
|
|
43
46
|
});
|
|
47
|
+
this.status = new StatusController(this);
|
|
44
48
|
this.virtualize = new VirtualizeController(this, {
|
|
45
49
|
container: () => (this.windowed ? this.partNamed('tree') : null),
|
|
46
50
|
count: () => this.rows.length,
|
|
@@ -52,7 +56,7 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
52
56
|
this.copier = new CopyController(this);
|
|
53
57
|
this.handleKeydown = (event) => {
|
|
54
58
|
const rows = this.rows;
|
|
55
|
-
const row = rows[this.
|
|
59
|
+
const row = rows[this.cursor];
|
|
56
60
|
if (!row) {
|
|
57
61
|
return;
|
|
58
62
|
}
|
|
@@ -66,10 +70,10 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
66
70
|
}
|
|
67
71
|
switch (event.key) {
|
|
68
72
|
case 'ArrowDown':
|
|
69
|
-
this.move(this.
|
|
73
|
+
this.move(this.cursor + 1);
|
|
70
74
|
break;
|
|
71
75
|
case 'ArrowUp':
|
|
72
|
-
this.move(this.
|
|
76
|
+
this.move(this.cursor - 1);
|
|
73
77
|
break;
|
|
74
78
|
case 'Home':
|
|
75
79
|
this.move(0);
|
|
@@ -84,14 +88,14 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
84
88
|
this.toggle(row, true);
|
|
85
89
|
}
|
|
86
90
|
else if (row.open) {
|
|
87
|
-
this.move(this.
|
|
91
|
+
this.move(this.cursor + 1);
|
|
88
92
|
}
|
|
89
93
|
}
|
|
90
94
|
else if (row.open) {
|
|
91
95
|
this.toggle(row, false);
|
|
92
96
|
}
|
|
93
97
|
else {
|
|
94
|
-
const parent = rows.findLastIndex((candidate, at) => at < this.
|
|
98
|
+
const parent = rows.findLastIndex((candidate, at) => at < this.cursor && candidate.depth === row.depth - 1);
|
|
95
99
|
if (parent >= 0) {
|
|
96
100
|
this.move(parent);
|
|
97
101
|
}
|
|
@@ -114,80 +118,123 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
114
118
|
}
|
|
115
119
|
event.preventDefault();
|
|
116
120
|
};
|
|
121
|
+
this.handleFilterInput = (event) => {
|
|
122
|
+
const field = event.currentTarget;
|
|
123
|
+
const applied = requestChange({
|
|
124
|
+
apply: (value) => {
|
|
125
|
+
this.filter = value;
|
|
126
|
+
},
|
|
127
|
+
event: (value) => new HelixFilterEvent({ value }),
|
|
128
|
+
host: this,
|
|
129
|
+
next: field.value,
|
|
130
|
+
});
|
|
131
|
+
if (applied) {
|
|
132
|
+
this.dispatchEvent(new HelixFilteredEvent({ value: field.value }));
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
field.value = this.filter;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
this.handleFilterKeydown = (event) => {
|
|
139
|
+
if (event.key === 'ArrowDown') {
|
|
140
|
+
event.preventDefault();
|
|
141
|
+
this.partNamed('tree')?.focus();
|
|
142
|
+
}
|
|
143
|
+
};
|
|
117
144
|
}
|
|
118
145
|
static { HelixHeadlessObjectInspector_1 = this; }
|
|
146
|
+
get active() {
|
|
147
|
+
return this.wanted ?? this.rows[this.cursor]?.path ?? '';
|
|
148
|
+
}
|
|
149
|
+
set active(path) {
|
|
150
|
+
const previous = this.active;
|
|
151
|
+
this.wanted = path;
|
|
152
|
+
this.requestUpdate('active', previous);
|
|
153
|
+
}
|
|
154
|
+
get expanded() {
|
|
155
|
+
return [...this.opened];
|
|
156
|
+
}
|
|
157
|
+
set expanded(paths) {
|
|
158
|
+
const previous = this.expanded;
|
|
159
|
+
this.declared = new Set(paths);
|
|
160
|
+
this.opened = this.declared;
|
|
161
|
+
this.requestUpdate('expanded', previous);
|
|
162
|
+
}
|
|
119
163
|
static { this.ESTIMATE = 24; }
|
|
120
164
|
get root() {
|
|
121
165
|
return this.value === undefined ? this.read : this.value;
|
|
122
166
|
}
|
|
123
|
-
flatten() {
|
|
124
|
-
const rows = [];
|
|
125
|
-
if (this.root === undefined) {
|
|
126
|
-
return rows;
|
|
127
|
-
}
|
|
128
|
-
const visit = (value, path, depth, position, siblings, key) => {
|
|
129
|
-
const branch = branchy(value);
|
|
130
|
-
const open = branch && this.opened.has(path);
|
|
131
|
-
rows.push({
|
|
132
|
-
branch,
|
|
133
|
-
depth,
|
|
134
|
-
open,
|
|
135
|
-
path,
|
|
136
|
-
position,
|
|
137
|
-
siblings,
|
|
138
|
-
value,
|
|
139
|
-
...(key === undefined ? {} : { key }),
|
|
140
|
-
});
|
|
141
|
-
if (open) {
|
|
142
|
-
const children = entries(value);
|
|
143
|
-
children.forEach(([name, item], at) => {
|
|
144
|
-
visit(item, child(path, name), depth + 1, at + 1, children.length, name);
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
};
|
|
148
|
-
visit(this.root, '', 0, 1, 1);
|
|
149
|
-
return rows;
|
|
150
|
-
}
|
|
151
167
|
seed(keep) {
|
|
152
|
-
const opened =
|
|
153
|
-
const branches = new Set();
|
|
154
|
-
const visit = (value, path, depth) => {
|
|
155
|
-
if (!branchy(value)) {
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
branches.add(path);
|
|
159
|
-
const known = keep && this.branches.has(path);
|
|
160
|
-
if (known ? this.opened.has(path) : depth < this.defaultDepth) {
|
|
161
|
-
opened.add(path);
|
|
162
|
-
}
|
|
163
|
-
for (const [name, item] of entries(value)) {
|
|
164
|
-
visit(item, child(path, name), depth + 1);
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
visit(this.root, '', 0);
|
|
168
|
+
const { branches, opened } = seed(this.root, this.defaultDepth, keep ? this.branches : undefined, this.opened);
|
|
168
169
|
this.branches = branches;
|
|
169
170
|
this.opened = opened;
|
|
170
171
|
if (!keep) {
|
|
171
|
-
this.
|
|
172
|
+
this.cursor = 0;
|
|
172
173
|
}
|
|
173
174
|
}
|
|
175
|
+
openAround(paths) {
|
|
176
|
+
const opened = new Set(this.opened);
|
|
177
|
+
for (const path of paths) {
|
|
178
|
+
for (const above of ancestorsOf(path)) {
|
|
179
|
+
if (this.branches.has(above)) {
|
|
180
|
+
opened.add(above);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
this.opened = opened;
|
|
185
|
+
}
|
|
174
186
|
willUpdate(changed) {
|
|
175
187
|
super.willUpdate(changed);
|
|
176
188
|
if (this.loadedFor !== this.for && searchableById(this) && !this.hydrating) {
|
|
177
189
|
this.loadedFor = this.for;
|
|
178
190
|
this.load();
|
|
179
191
|
}
|
|
180
|
-
const was = this.rows[this.
|
|
181
|
-
|
|
192
|
+
const was = this.rows[this.cursor]?.path;
|
|
193
|
+
const written = this.declared;
|
|
194
|
+
this.declared = undefined;
|
|
195
|
+
const fresh = changed.has('value') || changed.has('read');
|
|
196
|
+
if (fresh || changed.has('defaultDepth')) {
|
|
182
197
|
this.seed(!changed.has('defaultDepth'));
|
|
183
198
|
}
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
this.
|
|
189
|
-
|
|
190
|
-
|
|
199
|
+
if (written) {
|
|
200
|
+
this.opened = written;
|
|
201
|
+
}
|
|
202
|
+
if (fresh || changed.has('filter')) {
|
|
203
|
+
this.found = this.filter.trim() === '' ? undefined : search(this.root, this.filter);
|
|
204
|
+
this.openAround(this.found ?? []);
|
|
205
|
+
}
|
|
206
|
+
const wanted = this.root === undefined ? undefined : this.wanted;
|
|
207
|
+
if (wanted !== undefined) {
|
|
208
|
+
this.wanted = undefined;
|
|
209
|
+
this.openAround([wanted]);
|
|
210
|
+
}
|
|
211
|
+
if (fresh ||
|
|
212
|
+
wanted !== undefined ||
|
|
213
|
+
['active', 'defaultDepth', 'expanded', 'filter', 'opened'].some((name) => changed.has(name))) {
|
|
214
|
+
this.rows = flatten(this.root, this.opened, this.found);
|
|
215
|
+
this.cursor = this.place(wanted ?? was, changed.has('filter'));
|
|
216
|
+
}
|
|
217
|
+
if (changed.has('filter') && this.hasUpdated) {
|
|
218
|
+
this.tell();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
place(path, filtered) {
|
|
222
|
+
const rows = this.rows;
|
|
223
|
+
const at = (one) => rows.findIndex((row) => row.path === one);
|
|
224
|
+
const own = path === undefined ? -1 : at(path);
|
|
225
|
+
if (own >= 0 || path === undefined) {
|
|
226
|
+
return own >= 0 ? own : Math.min(this.cursor, Math.max(0, rows.length - 1));
|
|
227
|
+
}
|
|
228
|
+
const match = filtered ? rows.findIndex((row) => row.match) : -1;
|
|
229
|
+
const around = ancestorsOf(path)
|
|
230
|
+
.reverse()
|
|
231
|
+
.map(at)
|
|
232
|
+
.find((one) => one >= 0);
|
|
233
|
+
return match >= 0 ? match : (around ?? 0);
|
|
234
|
+
}
|
|
235
|
+
tell() {
|
|
236
|
+
if (this.found) {
|
|
237
|
+
this.status.say(countLabel(this.found.size, this.resultLabel, this.resultsLabel, this.lang));
|
|
191
238
|
}
|
|
192
239
|
}
|
|
193
240
|
firstUpdated(changed) {
|
|
@@ -215,7 +262,7 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
215
262
|
}
|
|
216
263
|
reveal(attempts = 8) {
|
|
217
264
|
const tree = this.partNamed('tree');
|
|
218
|
-
const row = tree?.querySelector(`[data-index="${this.
|
|
265
|
+
const row = tree?.querySelector(`[data-index="${this.cursor}"]`);
|
|
219
266
|
if (row) {
|
|
220
267
|
scrollItemIntoView(row);
|
|
221
268
|
return;
|
|
@@ -227,8 +274,8 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
227
274
|
return;
|
|
228
275
|
}
|
|
229
276
|
const height = first.offsetHeight || HelixHeadlessObjectInspector_1.ESTIMATE;
|
|
230
|
-
const from = Number(this.
|
|
231
|
-
tree.scrollTop += (this.
|
|
277
|
+
const from = Number(this.cursor > Number(last.dataset.index) ? last.dataset.index : first.dataset.index);
|
|
278
|
+
tree.scrollTop += (this.cursor - from) * height;
|
|
232
279
|
this.virtualize.measure();
|
|
233
280
|
void this.updateComplete.then(() => this.reveal(attempts - 1));
|
|
234
281
|
}
|
|
@@ -252,9 +299,27 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
252
299
|
this.opened = opened;
|
|
253
300
|
}
|
|
254
301
|
move(to) {
|
|
255
|
-
const
|
|
256
|
-
|
|
302
|
+
const at = Math.max(0, Math.min(to, this.rows.length - 1));
|
|
303
|
+
const path = this.rows[at]?.path;
|
|
304
|
+
if (path === undefined) {
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
if (at !== this.cursor) {
|
|
308
|
+
const moved = requestChange({
|
|
309
|
+
apply: () => {
|
|
310
|
+
this.cursor = at;
|
|
311
|
+
},
|
|
312
|
+
event: (value) => new HelixBeforeActivateEvent({ value }),
|
|
313
|
+
host: this,
|
|
314
|
+
next: path,
|
|
315
|
+
});
|
|
316
|
+
if (!moved) {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
this.dispatchEvent(new HelixActivateEvent({ value: path }));
|
|
320
|
+
}
|
|
257
321
|
this.revealing = true;
|
|
322
|
+
return true;
|
|
258
323
|
}
|
|
259
324
|
openSiblings(row) {
|
|
260
325
|
const parent = row.path.slice(0, row.path.lastIndexOf('/'));
|
|
@@ -275,7 +340,7 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
275
340
|
const wanted = text.toLocaleLowerCase();
|
|
276
341
|
const repeated = [...wanted].every((one) => one === wanted[0]);
|
|
277
342
|
const rows = this.rows;
|
|
278
|
-
const start = wanted.length === 1 || repeated ? this.
|
|
343
|
+
const start = wanted.length === 1 || repeated ? this.cursor + 1 : this.cursor;
|
|
279
344
|
for (let step = 0; step < rows.length; step += 1) {
|
|
280
345
|
const at = (start + step) % rows.length;
|
|
281
346
|
const key = rows[at]?.key?.toLocaleLowerCase();
|
|
@@ -286,8 +351,7 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
286
351
|
}
|
|
287
352
|
}
|
|
288
353
|
handleRowClick(index, row) {
|
|
289
|
-
this.
|
|
290
|
-
if (row.branch) {
|
|
354
|
+
if (this.move(index) && row.branch) {
|
|
291
355
|
this.toggle(row);
|
|
292
356
|
}
|
|
293
357
|
}
|
|
@@ -324,14 +388,15 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
324
388
|
return html `<span part="string" dir="ltr">${String(value)}</span>`;
|
|
325
389
|
}
|
|
326
390
|
renderRow(row, index) {
|
|
327
|
-
const active = index === this.
|
|
391
|
+
const active = index === this.cursor;
|
|
328
392
|
return html `<div
|
|
329
|
-
part="row${active ? ' row-active' : ''}"
|
|
393
|
+
part="row${active ? ' row-active' : ''}${row.match ? ' row-match' : ''}"
|
|
330
394
|
role="treeitem"
|
|
331
395
|
id=${`row-${index}`}
|
|
332
396
|
data-index=${index}
|
|
333
397
|
aria-level=${row.depth + 1}
|
|
334
398
|
aria-posinset=${row.position}
|
|
399
|
+
aria-selected="false"
|
|
335
400
|
aria-setsize=${row.siblings}
|
|
336
401
|
aria-expanded=${row.branch ? String(row.open) : nothing}
|
|
337
402
|
style=${`--object-inspector-level: ${row.depth}`}
|
|
@@ -368,15 +433,28 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
368
433
|
? this.virtualize.window
|
|
369
434
|
: { after: 0, before: 0, first: 0, last: rows.length };
|
|
370
435
|
const shown = rows.slice(first, last);
|
|
371
|
-
return html `${this.label ? html `<div part="header"><span part="label">${this.label}</span></div>` : nothing}
|
|
436
|
+
return html `${this.label ? html `<div part="header"><span part="label">${this.label}</span></div>` : nothing}${this.filterable
|
|
437
|
+
? html `<input
|
|
438
|
+
part="search-field"
|
|
439
|
+
type="search"
|
|
440
|
+
spellcheck="false"
|
|
441
|
+
.value=${this.filter}
|
|
442
|
+
placeholder=${this.filterLabel}
|
|
443
|
+
aria-label=${this.filterLabel}
|
|
444
|
+
aria-controls="tree"
|
|
445
|
+
@input=${this.handleFilterInput}
|
|
446
|
+
@keydown=${this.handleFilterKeydown}
|
|
447
|
+
/>`
|
|
448
|
+
: nothing}
|
|
372
449
|
<div part="frame">
|
|
373
450
|
<div
|
|
374
451
|
part="tree"
|
|
452
|
+
id="tree"
|
|
375
453
|
role="tree"
|
|
376
454
|
tabindex="0"
|
|
377
455
|
?data-scroller=${this.windowed}
|
|
378
456
|
aria-label=${this.label || this.treeLabel}
|
|
379
|
-
aria-activedescendant=${rows.length > 0 ? `row-${this.
|
|
457
|
+
aria-activedescendant=${rows.length > 0 ? `row-${this.cursor}` : nothing}
|
|
380
458
|
@keydown=${this.handleKeydown}
|
|
381
459
|
@scroll=${() => this.virtualize.measure()}
|
|
382
460
|
>
|
|
@@ -384,10 +462,14 @@ let HelixHeadlessObjectInspector = class HelixHeadlessObjectInspector extends He
|
|
|
384
462
|
${shown.map((row, at) => this.renderRow(row, first + at))}
|
|
385
463
|
${this.windowed ? html `<div part="after" role="presentation" style="block-size: ${after}px"></div>` : nothing}
|
|
386
464
|
</div>
|
|
387
|
-
${this.noCopy ? nothing : this.renderCopyButton(rows[this.
|
|
388
|
-
</div
|
|
465
|
+
${this.noCopy ? nothing : this.renderCopyButton(rows[this.cursor])}
|
|
466
|
+
</div>
|
|
467
|
+
${drawStatus(this.status)}`;
|
|
389
468
|
}
|
|
390
469
|
};
|
|
470
|
+
__decorate([
|
|
471
|
+
property()
|
|
472
|
+
], HelixHeadlessObjectInspector.prototype, "active", null);
|
|
391
473
|
__decorate([
|
|
392
474
|
property({ attribute: 'copy-label' })
|
|
393
475
|
], HelixHeadlessObjectInspector.prototype, "copyLabel", void 0);
|
|
@@ -397,6 +479,18 @@ __decorate([
|
|
|
397
479
|
__decorate([
|
|
398
480
|
property({ attribute: 'default-depth', type: Number })
|
|
399
481
|
], HelixHeadlessObjectInspector.prototype, "defaultDepth", void 0);
|
|
482
|
+
__decorate([
|
|
483
|
+
property({ attribute: false })
|
|
484
|
+
], HelixHeadlessObjectInspector.prototype, "expanded", null);
|
|
485
|
+
__decorate([
|
|
486
|
+
property()
|
|
487
|
+
], HelixHeadlessObjectInspector.prototype, "filter", void 0);
|
|
488
|
+
__decorate([
|
|
489
|
+
property({ type: Boolean })
|
|
490
|
+
], HelixHeadlessObjectInspector.prototype, "filterable", void 0);
|
|
491
|
+
__decorate([
|
|
492
|
+
property({ attribute: 'filter-label' })
|
|
493
|
+
], HelixHeadlessObjectInspector.prototype, "filterLabel", void 0);
|
|
400
494
|
__decorate([
|
|
401
495
|
property()
|
|
402
496
|
], HelixHeadlessObjectInspector.prototype, "for", void 0);
|
|
@@ -418,6 +512,12 @@ __decorate([
|
|
|
418
512
|
__decorate([
|
|
419
513
|
property({ attribute: 'no-copy', type: Boolean })
|
|
420
514
|
], HelixHeadlessObjectInspector.prototype, "noCopy", void 0);
|
|
515
|
+
__decorate([
|
|
516
|
+
property({ attribute: 'result-label' })
|
|
517
|
+
], HelixHeadlessObjectInspector.prototype, "resultLabel", void 0);
|
|
518
|
+
__decorate([
|
|
519
|
+
property({ attribute: 'results-label' })
|
|
520
|
+
], HelixHeadlessObjectInspector.prototype, "resultsLabel", void 0);
|
|
421
521
|
__decorate([
|
|
422
522
|
property({ attribute: 'tree-label' })
|
|
423
523
|
], HelixHeadlessObjectInspector.prototype, "treeLabel", void 0);
|
|
@@ -435,7 +535,7 @@ __decorate([
|
|
|
435
535
|
], HelixHeadlessObjectInspector.prototype, "opened", void 0);
|
|
436
536
|
__decorate([
|
|
437
537
|
state()
|
|
438
|
-
], HelixHeadlessObjectInspector.prototype, "
|
|
538
|
+
], HelixHeadlessObjectInspector.prototype, "cursor", void 0);
|
|
439
539
|
HelixHeadlessObjectInspector = HelixHeadlessObjectInspector_1 = __decorate([
|
|
440
540
|
customElement('helix-headless-object-inspector')
|
|
441
541
|
], HelixHeadlessObjectInspector);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** One visible line of the tree: a value, where it sits, and whether it is open. */
|
|
2
|
+
export interface Row {
|
|
3
|
+
branch: boolean;
|
|
4
|
+
depth: number;
|
|
5
|
+
/** The property name or array index this value is under; absent for the root. */
|
|
6
|
+
key?: string;
|
|
7
|
+
/** Whether its key or its value holds what the tree is filtered by. */
|
|
8
|
+
match: boolean;
|
|
9
|
+
open: boolean;
|
|
10
|
+
path: string;
|
|
11
|
+
position: number;
|
|
12
|
+
siblings: number;
|
|
13
|
+
value: unknown;
|
|
14
|
+
}
|
|
15
|
+
/** Whether a value has entries of its own, an object or an array. */
|
|
16
|
+
export declare const branchy: (value: unknown) => value is object;
|
|
17
|
+
/** A branch's entries, an array's under its indexes. */
|
|
18
|
+
export declare const entries: (value: object) => [string, unknown][];
|
|
19
|
+
/** A child's path under its parent's, escaped the way a JSON Pointer escapes one. */
|
|
20
|
+
export declare const child: (path: string, key: string) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Every branch a path sits inside, from the root down, and not the path itself.
|
|
23
|
+
*
|
|
24
|
+
* The root's path is the empty string, so every other path has it first. A
|
|
25
|
+
* key's own `/` is escaped as `~1`, so cutting at each `/` cuts between keys.
|
|
26
|
+
*/
|
|
27
|
+
export declare const ancestorsOf: (path: string) => string[];
|
|
28
|
+
/**
|
|
29
|
+
* The paths of every entry whose key or value holds `query`, ignoring case,
|
|
30
|
+
* across the whole value and not only the open branches.
|
|
31
|
+
*
|
|
32
|
+
* A branch is matched by its key alone: its brackets and its count are drawn,
|
|
33
|
+
* and they are not what a reader is looking for.
|
|
34
|
+
*/
|
|
35
|
+
export declare const search: (root: unknown, query: string) => Set<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Every visible row, in order, for a value with `opened` branches open.
|
|
38
|
+
*
|
|
39
|
+
* With `found`, the paths a filter matched, a branch shows only the entries
|
|
40
|
+
* that matched or lead to one, and a matched entry shows everything under it.
|
|
41
|
+
* Position and set size count the entries shown, which is the set a reader
|
|
42
|
+
* hears.
|
|
43
|
+
*/
|
|
44
|
+
export declare const flatten: (root: unknown, opened: Set<string>, found?: Set<string>) => Row[];
|
|
45
|
+
/**
|
|
46
|
+
* Which branches are open for a value, by path.
|
|
47
|
+
*
|
|
48
|
+
* Every branch shallower than `depth` opens. A branch in `known`, the
|
|
49
|
+
* branches of the last value, keeps whether it was in `opened`, so a new value
|
|
50
|
+
* keeps the branches a reader opened or closed and only a new one takes the
|
|
51
|
+
* default. Returns the open branches and every branch, for the next value to
|
|
52
|
+
* be told apart from this one.
|
|
53
|
+
*/
|
|
54
|
+
export declare const seed: (root: unknown, depth: number, known?: Set<string>, opened?: Set<string>) => {
|
|
55
|
+
branches: Set<string>;
|
|
56
|
+
opened: Set<string>;
|
|
57
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export const branchy = (value) => value !== null && typeof value === 'object';
|
|
2
|
+
export const entries = (value) => Array.isArray(value) ? value.map((item, at) => [String(at), item]) : Object.entries(value);
|
|
3
|
+
export const child = (path, key) => `${path}/${key.replaceAll('~', '~0').replaceAll('/', '~1')}`;
|
|
4
|
+
export const ancestorsOf = (path) => {
|
|
5
|
+
const cuts = [];
|
|
6
|
+
for (let at = path.indexOf('/'); at !== -1; at = path.indexOf('/', at + 1)) {
|
|
7
|
+
cuts.push(path.slice(0, at));
|
|
8
|
+
}
|
|
9
|
+
return cuts;
|
|
10
|
+
};
|
|
11
|
+
const words = (value) => (branchy(value) ? '' : String(value));
|
|
12
|
+
export const search = (root, query) => {
|
|
13
|
+
const found = new Set();
|
|
14
|
+
const wanted = query.trim().toLocaleLowerCase();
|
|
15
|
+
if (wanted === '' || root === undefined) {
|
|
16
|
+
return found;
|
|
17
|
+
}
|
|
18
|
+
const visit = (value, path, key) => {
|
|
19
|
+
if (key?.toLocaleLowerCase().includes(wanted) ||
|
|
20
|
+
words(value).toLocaleLowerCase().includes(wanted)) {
|
|
21
|
+
found.add(path);
|
|
22
|
+
}
|
|
23
|
+
if (branchy(value)) {
|
|
24
|
+
for (const [name, item] of entries(value)) {
|
|
25
|
+
visit(item, child(path, name), name);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
visit(root, '');
|
|
30
|
+
return found;
|
|
31
|
+
};
|
|
32
|
+
export const flatten = (root, opened, found) => {
|
|
33
|
+
const rows = [];
|
|
34
|
+
if (root === undefined) {
|
|
35
|
+
return rows;
|
|
36
|
+
}
|
|
37
|
+
const trail = new Set([...(found ?? [])].flatMap(ancestorsOf));
|
|
38
|
+
const visit = (value, path, depth, position, siblings, under, key) => {
|
|
39
|
+
const branch = branchy(value);
|
|
40
|
+
const open = branch && opened.has(path);
|
|
41
|
+
const match = found?.has(path) === true;
|
|
42
|
+
rows.push({
|
|
43
|
+
branch,
|
|
44
|
+
depth,
|
|
45
|
+
match,
|
|
46
|
+
open,
|
|
47
|
+
path,
|
|
48
|
+
position,
|
|
49
|
+
siblings,
|
|
50
|
+
value,
|
|
51
|
+
...(key === undefined ? {} : { key }),
|
|
52
|
+
});
|
|
53
|
+
if (!open) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const inside = under || match || !found;
|
|
57
|
+
const children = entries(value)
|
|
58
|
+
.map(([name, item]) => [name, item, child(path, name)])
|
|
59
|
+
.filter(([, , at]) => inside || found?.has(at) || trail.has(at));
|
|
60
|
+
children.forEach(([name, item, at], index) => {
|
|
61
|
+
visit(item, at, depth + 1, index + 1, children.length, inside && !!found, name);
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
if (!found || found.has('') || trail.has('')) {
|
|
65
|
+
visit(root, '', 0, 1, 1, false);
|
|
66
|
+
}
|
|
67
|
+
return rows;
|
|
68
|
+
};
|
|
69
|
+
export const seed = (root, depth, known = new Set(), opened = new Set()) => {
|
|
70
|
+
const open = new Set();
|
|
71
|
+
const branches = new Set();
|
|
72
|
+
const visit = (value, path, level) => {
|
|
73
|
+
if (!branchy(value)) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
branches.add(path);
|
|
77
|
+
if (known.has(path) ? opened.has(path) : level < depth) {
|
|
78
|
+
open.add(path);
|
|
79
|
+
}
|
|
80
|
+
for (const [name, item] of entries(value)) {
|
|
81
|
+
visit(item, child(path, name), level + 1);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
visit(root, '', 0);
|
|
85
|
+
return { branches, opened: open };
|
|
86
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The levels of a flat run of links, as the nested lists they describe.
|
|
3
|
+
*
|
|
4
|
+
* A contents list written flat, `<a data-level="2">`, says its depth in an
|
|
5
|
+
* attribute that only a stylesheet reads. The outline turns the run into lists
|
|
6
|
+
* inside list items in its shadow root, so a screen reader hears the levels a
|
|
7
|
+
* nested `<ul>` would have given it, with the links left where they are.
|
|
8
|
+
*/
|
|
9
|
+
/** One link in the tree: its place in the run, and the links nested under it. */
|
|
10
|
+
export interface Branch {
|
|
11
|
+
/** The link's position in the flat run, counted from zero. */
|
|
12
|
+
index: number;
|
|
13
|
+
/** The links one level or more deeper that follow it, before the next at its level. */
|
|
14
|
+
children: Branch[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The level a link's `data-level` asks for, a whole number from 1.
|
|
18
|
+
*
|
|
19
|
+
* Absent, empty, or not a number is the top level, which is how the outline
|
|
20
|
+
* has always read a link without one.
|
|
21
|
+
*/
|
|
22
|
+
export declare const levelOf: (value: string | null) => number;
|
|
23
|
+
/**
|
|
24
|
+
* Nests a run of levels.
|
|
25
|
+
*
|
|
26
|
+
* Each link goes under the nearest link before it with a lower level, and to
|
|
27
|
+
* the top where there is none. A jump of two levels nests one list deeper and
|
|
28
|
+
* not two, since a list item with no link of its own would be read as an empty
|
|
29
|
+
* entry. A run that starts deeper than 1 starts at the top all the same.
|
|
30
|
+
*/
|
|
31
|
+
export declare const nest: (levels: readonly number[]) => Branch[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const levelOf = (value) => {
|
|
2
|
+
const level = Number.parseInt(value ?? '', 10);
|
|
3
|
+
return Number.isFinite(level) && level >= 1 ? level : 1;
|
|
4
|
+
};
|
|
5
|
+
export const nest = (levels) => {
|
|
6
|
+
const top = [];
|
|
7
|
+
const open = [];
|
|
8
|
+
levels.forEach((level, index) => {
|
|
9
|
+
const branch = { children: [], index };
|
|
10
|
+
while (open.length > 0 && (open.at(-1)?.level ?? 0) >= level) {
|
|
11
|
+
open.pop();
|
|
12
|
+
}
|
|
13
|
+
const parent = open.at(-1);
|
|
14
|
+
if (parent) {
|
|
15
|
+
parent.branch.children.push(branch);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
top.push(branch);
|
|
19
|
+
}
|
|
20
|
+
open.push({ branch, level });
|
|
21
|
+
});
|
|
22
|
+
return top;
|
|
23
|
+
};
|