@fusion.dev/helix-headless 0.209.0 → 0.210.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/canvas/root/canvas-root.d.ts +4 -1
- package/dist/graph/root/graph-root.d.ts +11 -10
- package/dist/graph/root/graph-root.js +8 -18
- package/dist/legend/root/legend-root.d.ts +9 -15
- package/dist/legend/root/legend-root.js +10 -20
- package/dist/map/root/map-root.d.ts +4 -2
- package/dist/map/root/map-root.js +1 -1
- package/dist/toolbar/root/toolbar-root.d.ts +5 -88
- package/dist/toolbar/root/toolbar-root.js +10 -227
- package/lint.json +1 -1
- package/package.json +5 -5
- package/types/jsx.d.ts +24 -10
- package/types/vue.d.ts +3 -3
|
@@ -1,44 +1,8 @@
|
|
|
1
1
|
var HelixHeadlessToolbar_1;
|
|
2
2
|
import { __decorate } from "tslib";
|
|
3
|
-
import { AriaForwardController, closestInstance, customElement, HelixElement,
|
|
3
|
+
import { AriaForwardController, closestInstance, customElement, HelixElement, ToolbarController, toolbarAround, words, } from '@fusion.dev/helix-core';
|
|
4
4
|
import { html, nothing } from 'lit';
|
|
5
5
|
import { property } from 'lit/decorators.js';
|
|
6
|
-
const KEYS = new Set(['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Home', 'End']);
|
|
7
|
-
const ownsTabStop = (node) => 'focusable' in node;
|
|
8
|
-
const NATIVE = 'a[href], button, input, select, textarea, [tabindex], [contenteditable=""], [contenteditable="true"]';
|
|
9
|
-
const TABBABLE = NATIVE.replace('[tabindex]', '[tabindex]:not([tabindex="-1"])');
|
|
10
|
-
const innerStops = new WeakMap();
|
|
11
|
-
const takesFocus = (node) => {
|
|
12
|
-
if (!(node instanceof HTMLElement) ||
|
|
13
|
-
node.hasAttribute('disabled') ||
|
|
14
|
-
node.getAttribute('aria-hidden') === 'true') {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
return (node.matches(NATIVE) ||
|
|
18
|
-
ownsTabStop(node) ||
|
|
19
|
-
node.shadowRoot?.delegatesFocus === true ||
|
|
20
|
-
node.shadowRoot?.querySelector(TABBABLE) != null ||
|
|
21
|
-
innerStops.get(node)?.isConnected === true);
|
|
22
|
-
};
|
|
23
|
-
const stopOf = (node) => {
|
|
24
|
-
if (node.hasAttribute('tabindex')) {
|
|
25
|
-
return node;
|
|
26
|
-
}
|
|
27
|
-
const held = innerStops.get(node);
|
|
28
|
-
if (held?.isConnected && held.getRootNode() === node.shadowRoot) {
|
|
29
|
-
return held;
|
|
30
|
-
}
|
|
31
|
-
const inner = node.localName.includes('-')
|
|
32
|
-
? node.shadowRoot?.querySelector(TABBABLE)
|
|
33
|
-
: null;
|
|
34
|
-
if (!inner) {
|
|
35
|
-
return node;
|
|
36
|
-
}
|
|
37
|
-
innerStops.set(node, inner);
|
|
38
|
-
return inner;
|
|
39
|
-
};
|
|
40
|
-
const flattens = (node) => ownsTabStop(node) &&
|
|
41
|
-
node.selectionMode === 'multiple';
|
|
42
6
|
let HelixHeadlessToolbar = class HelixHeadlessToolbar extends HelixElement {
|
|
43
7
|
constructor() {
|
|
44
8
|
super(...arguments);
|
|
@@ -47,180 +11,16 @@ let HelixHeadlessToolbar = class HelixHeadlessToolbar extends HelixElement {
|
|
|
47
11
|
label: true,
|
|
48
12
|
target: () => this.partNamed('toolbar'),
|
|
49
13
|
});
|
|
50
|
-
this.wroteForeign = false;
|
|
51
14
|
this.stopAtEnds = false;
|
|
52
|
-
this.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
this.setTabStop(control);
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
this.restoreTabStop = () => {
|
|
62
|
-
if (this.nested) {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
const controls = this.controls;
|
|
66
|
-
const held = controls.some((control) => {
|
|
67
|
-
if (control.group) {
|
|
68
|
-
return control.group.focusable;
|
|
69
|
-
}
|
|
70
|
-
const composite = control.stops.length !== 1;
|
|
71
|
-
const element = composite ? control.child : control.stops[0];
|
|
72
|
-
if (ownsTabStop(element)) {
|
|
73
|
-
return element.focusable;
|
|
74
|
-
}
|
|
75
|
-
return composite || stopOf(element).tabIndex === 0;
|
|
76
|
-
});
|
|
77
|
-
if (controls.length > 0 && !held) {
|
|
78
|
-
this.setTabStop(controls[0], false);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
this.handleCompositeKeydown = (event) => {
|
|
82
|
-
if (this.nested) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
const control = this.origin(event);
|
|
86
|
-
if (!control || (control.stops.length === 1 && !control.group)) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
this.handleKeydown(event);
|
|
90
|
-
if (event.defaultPrevented) {
|
|
91
|
-
event.stopPropagation();
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
this.handleKeydown = (event) => {
|
|
95
|
-
if (this.nested || !KEYS.has(event.key) || keyClaimed(event)) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
const along = inlineStep(this, event.key);
|
|
99
|
-
const forward = this.axis === 'horizontal' ? along === 1 : event.key === 'ArrowDown';
|
|
100
|
-
const back = this.axis === 'horizontal' ? along === -1 : event.key === 'ArrowUp';
|
|
101
|
-
const controls = this.controls;
|
|
102
|
-
const origin = this.origin(event);
|
|
103
|
-
const current = origin ? controls.findIndex((control) => control.child === origin.child) : -1;
|
|
104
|
-
if (current === -1) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
let next = current;
|
|
108
|
-
const last = controls.length - 1;
|
|
109
|
-
if (forward) {
|
|
110
|
-
next = this.stopAtEnds ? Math.min(current + 1, last) : (current + 1) % controls.length;
|
|
111
|
-
}
|
|
112
|
-
else if (back) {
|
|
113
|
-
next = this.stopAtEnds
|
|
114
|
-
? Math.max(current - 1, 0)
|
|
115
|
-
: (current - 1 + controls.length) % controls.length;
|
|
116
|
-
}
|
|
117
|
-
else if (event.key === 'Home') {
|
|
118
|
-
next = 0;
|
|
119
|
-
}
|
|
120
|
-
else if (event.key === 'End') {
|
|
121
|
-
next = controls.length - 1;
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
event.preventDefault();
|
|
127
|
-
const target = controls[next];
|
|
128
|
-
this.setTabStop(target);
|
|
129
|
-
const element = target ? this.entry(target) : undefined;
|
|
130
|
-
if (element && 'focusItem' in element && typeof element.focusItem === 'function') {
|
|
131
|
-
element.focusItem();
|
|
132
|
-
}
|
|
133
|
-
else if (element) {
|
|
134
|
-
;
|
|
135
|
-
(ownsTabStop(element) ? element : stopOf(element)).focus();
|
|
136
|
-
}
|
|
137
|
-
};
|
|
15
|
+
this.tabStop = new ToolbarController(this, {
|
|
16
|
+
arrows: () => this.axis,
|
|
17
|
+
members: () => [...this.children],
|
|
18
|
+
nested: () => this.nested,
|
|
19
|
+
stopAtEnds: () => this.stopAtEnds,
|
|
20
|
+
});
|
|
138
21
|
}
|
|
139
22
|
static { HelixHeadlessToolbar_1 = this; }
|
|
140
23
|
static { this.words = 'helix-toolbar'; }
|
|
141
|
-
get controls() {
|
|
142
|
-
const controls = [];
|
|
143
|
-
for (const child of this.members) {
|
|
144
|
-
if (!(child instanceof HTMLElement) ||
|
|
145
|
-
child.hasAttribute('disabled') ||
|
|
146
|
-
child.getAttribute('aria-hidden') === 'true') {
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
if (takesFocus(child)) {
|
|
150
|
-
const stops = this.inside(child);
|
|
151
|
-
if (stops.length > 1 && flattens(child)) {
|
|
152
|
-
for (const stop of stops) {
|
|
153
|
-
controls.push({ child: stop, group: child, stops: [stop] });
|
|
154
|
-
}
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
controls.push({ child, stops });
|
|
158
|
-
continue;
|
|
159
|
-
}
|
|
160
|
-
for (const stop of this.within(child)) {
|
|
161
|
-
controls.push({ child: stop, stops: [stop] });
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return controls;
|
|
165
|
-
}
|
|
166
|
-
get members() {
|
|
167
|
-
return [...this.children].flatMap((child) => child instanceof HTMLSlotElement ? child.assignedElements({ flatten: true }) : [child]);
|
|
168
|
-
}
|
|
169
|
-
within(child) {
|
|
170
|
-
return [...child.querySelectorAll('*')].filter(takesFocus);
|
|
171
|
-
}
|
|
172
|
-
inside(child) {
|
|
173
|
-
if (!ownsTabStop(child)) {
|
|
174
|
-
return [child];
|
|
175
|
-
}
|
|
176
|
-
const members = this.within(child);
|
|
177
|
-
return members.length > 1 ? members : [child];
|
|
178
|
-
}
|
|
179
|
-
entry(control) {
|
|
180
|
-
const { stops } = control;
|
|
181
|
-
if (stops.length === 1) {
|
|
182
|
-
return stops[0];
|
|
183
|
-
}
|
|
184
|
-
return (stops.find((stop) => (ownsTabStop(stop) && stop.focusable) ||
|
|
185
|
-
stop.selected === true) ?? stops[0]);
|
|
186
|
-
}
|
|
187
|
-
origin(event) {
|
|
188
|
-
const path = event.composedPath();
|
|
189
|
-
return this.controls.find((control) => control.stops.some((stop) => path.includes(stop)));
|
|
190
|
-
}
|
|
191
|
-
setTabStop(active, foreign = true) {
|
|
192
|
-
if (foreign) {
|
|
193
|
-
this.wroteForeign = true;
|
|
194
|
-
}
|
|
195
|
-
for (const control of this.controls) {
|
|
196
|
-
if (control.group) {
|
|
197
|
-
control.group.focusable = control.group === active?.group;
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
if (control.stops.length !== 1) {
|
|
201
|
-
if (ownsTabStop(control.child)) {
|
|
202
|
-
control.child.focusable = control.child === active?.child;
|
|
203
|
-
}
|
|
204
|
-
continue;
|
|
205
|
-
}
|
|
206
|
-
const element = control.stops[0];
|
|
207
|
-
const stop = control.child === active?.child;
|
|
208
|
-
if (ownsTabStop(element)) {
|
|
209
|
-
element.focusable = stop;
|
|
210
|
-
}
|
|
211
|
-
else if (foreign || this.wroteForeign) {
|
|
212
|
-
stopOf(element).tabIndex = stop ? 0 : -1;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
async claimTabStop() {
|
|
217
|
-
if (this.nested) {
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
const pending = [...new Set(this.members.map((child) => child.localName))].filter((name) => name.includes('-'));
|
|
221
|
-
await Promise.all(pending.map((name) => customElements.whenDefined(name)));
|
|
222
|
-
this.setTabStop(this.controls[0], false);
|
|
223
|
-
}
|
|
224
24
|
get nested() {
|
|
225
25
|
const parent = this.parentElement;
|
|
226
26
|
if (!parent) {
|
|
@@ -234,27 +34,10 @@ let HelixHeadlessToolbar = class HelixHeadlessToolbar extends HelixElement {
|
|
|
234
34
|
connectedCallback() {
|
|
235
35
|
super.connectedCallback();
|
|
236
36
|
this.requestUpdate();
|
|
237
|
-
this.addEventListener('keydown', this.handleCompositeKeydown, true);
|
|
238
|
-
this.addEventListener('keydown', this.handleKeydown);
|
|
239
|
-
this.addEventListener('focusin', this.handleFocusIn);
|
|
240
|
-
this.watcher = new MutationObserver(this.restoreTabStop);
|
|
241
|
-
this.watcher.observe(this, {
|
|
242
|
-
attributeFilter: ['disabled', 'aria-hidden'],
|
|
243
|
-
attributes: true,
|
|
244
|
-
subtree: true,
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
disconnectedCallback() {
|
|
248
|
-
super.disconnectedCallback();
|
|
249
|
-
this.removeEventListener('keydown', this.handleCompositeKeydown, true);
|
|
250
|
-
this.removeEventListener('keydown', this.handleKeydown);
|
|
251
|
-
this.removeEventListener('focusin', this.handleFocusIn);
|
|
252
|
-
this.watcher?.disconnect();
|
|
253
|
-
this.watcher = undefined;
|
|
254
37
|
}
|
|
255
38
|
firstUpdated(changed) {
|
|
256
39
|
super.firstUpdated(changed);
|
|
257
|
-
void this.
|
|
40
|
+
void this.tabStop.claim();
|
|
258
41
|
}
|
|
259
42
|
willUpdate(changed) {
|
|
260
43
|
super.willUpdate(changed);
|
|
@@ -262,7 +45,7 @@ let HelixHeadlessToolbar = class HelixHeadlessToolbar extends HelixElement {
|
|
|
262
45
|
this.toggleState('horizontal', this.axis === 'horizontal');
|
|
263
46
|
this.toggleState('vertical', this.axis === 'vertical');
|
|
264
47
|
if (this.hasUpdated && changed.has('orientation')) {
|
|
265
|
-
for (const child of this.members) {
|
|
48
|
+
for (const child of this.tabStop.members) {
|
|
266
49
|
;
|
|
267
50
|
child.requestUpdate?.();
|
|
268
51
|
}
|
|
@@ -276,7 +59,7 @@ let HelixHeadlessToolbar = class HelixHeadlessToolbar extends HelixElement {
|
|
|
276
59
|
aria-label=${this.label}
|
|
277
60
|
aria-orientation=${nested ? nothing : this.axis}
|
|
278
61
|
>
|
|
279
|
-
<slot @slotchange=${() => this.
|
|
62
|
+
<slot @slotchange=${() => this.tabStop.claim()}></slot>
|
|
280
63
|
</div>`;
|
|
281
64
|
}
|
|
282
65
|
};
|