@primer/behaviors 0.0.0-20251214175049 → 0.0.0-20251215031129
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/dist/cjs/focus-trap.js +4 -3
- package/dist/cjs/focus-zone.js +41 -30
- package/dist/cjs/utils/indexed-set.d.ts +12 -0
- package/dist/cjs/utils/indexed-set.js +56 -0
- package/dist/esm/focus-trap.mjs +4 -3
- package/dist/esm/focus-zone.mjs +41 -30
- package/dist/esm/utils/indexed-set.d.ts +12 -0
- package/dist/esm/utils/indexed-set.mjs +54 -0
- package/package.json +1 -1
package/dist/cjs/focus-trap.js
CHANGED
|
@@ -23,9 +23,10 @@ function observeFocusTrap(container, sentinels) {
|
|
|
23
23
|
const observer = new MutationObserver(mutations => {
|
|
24
24
|
for (const mutation of mutations) {
|
|
25
25
|
if (mutation.type === 'childList' && mutation.addedNodes.length) {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
for (const node of mutation.addedNodes) {
|
|
27
|
+
if (node instanceof HTMLElement && node.tagName === 'SPAN' && node.classList.contains('sentinel')) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
29
30
|
}
|
|
30
31
|
const firstChild = container.firstElementChild;
|
|
31
32
|
const lastChild = container.lastElementChild;
|
package/dist/cjs/focus-zone.js
CHANGED
|
@@ -5,6 +5,7 @@ var userAgent = require('./utils/user-agent.js');
|
|
|
5
5
|
var iterateFocusableElements = require('./utils/iterate-focusable-elements.js');
|
|
6
6
|
var uniqueId = require('./utils/unique-id.js');
|
|
7
7
|
var isEditableElement = require('./utils/is-editable-element.js');
|
|
8
|
+
var indexedSet = require('./utils/indexed-set.js');
|
|
8
9
|
|
|
9
10
|
eventListenerSignal.polyfill();
|
|
10
11
|
exports.FocusKeys = void 0;
|
|
@@ -89,17 +90,18 @@ function getDirection(keyboardEvent) {
|
|
|
89
90
|
}
|
|
90
91
|
function shouldIgnoreFocusHandling(keyboardEvent, activeElement) {
|
|
91
92
|
const key = keyboardEvent.key;
|
|
92
|
-
const
|
|
93
|
+
const isSingleChar = key.length === 1 || (key.length === 2 && key.charCodeAt(0) >= 0xd800 && key.charCodeAt(0) <= 0xdbff);
|
|
93
94
|
const isEditable = isEditableElement.isEditableElement(activeElement);
|
|
94
95
|
const isSelect = activeElement instanceof HTMLSelectElement;
|
|
95
|
-
if (isEditable && (
|
|
96
|
+
if (isEditable && (isSingleChar || key === 'Home' || key === 'End')) {
|
|
96
97
|
return true;
|
|
97
98
|
}
|
|
98
99
|
if (isSelect) {
|
|
99
|
-
|
|
100
|
+
const isMac = getIsMac();
|
|
101
|
+
if (key === 'ArrowDown' && isMac && !keyboardEvent.metaKey) {
|
|
100
102
|
return true;
|
|
101
103
|
}
|
|
102
|
-
if (key === 'ArrowDown' && !
|
|
104
|
+
if (key === 'ArrowDown' && !isMac && keyboardEvent.altKey) {
|
|
103
105
|
return true;
|
|
104
106
|
}
|
|
105
107
|
return false;
|
|
@@ -137,7 +139,7 @@ const activeDescendantActivatedIndirectly = 'activated-indirectly';
|
|
|
137
139
|
const hasActiveDescendantAttribute = 'data-has-active-descendant';
|
|
138
140
|
function focusZone(container, settings) {
|
|
139
141
|
var _a, _b, _c, _d, _e, _f;
|
|
140
|
-
const focusableElements =
|
|
142
|
+
const focusableElements = new indexedSet.IndexedSet();
|
|
141
143
|
const savedTabIndex = new WeakMap();
|
|
142
144
|
const bindKeys = (_a = settings === null || settings === void 0 ? void 0 : settings.bindKeys) !== null && _a !== void 0 ? _a : ((settings === null || settings === void 0 ? void 0 : settings.getNextFocusable) ? exports.FocusKeys.ArrowAll : exports.FocusKeys.ArrowVertical) | exports.FocusKeys.HomeAndEnd;
|
|
143
145
|
const focusOutBehavior = (_b = settings === null || settings === void 0 ? void 0 : settings.focusOutBehavior) !== null && _b !== void 0 ? _b : 'stop';
|
|
@@ -149,7 +151,7 @@ function focusZone(container, settings) {
|
|
|
149
151
|
const preventScroll = (_e = settings === null || settings === void 0 ? void 0 : settings.preventScroll) !== null && _e !== void 0 ? _e : false;
|
|
150
152
|
const preventInitialFocus = focusInStrategy === 'initial' && (settings === null || settings === void 0 ? void 0 : settings.activeDescendantControl);
|
|
151
153
|
function getFirstFocusableElement() {
|
|
152
|
-
return focusableElements
|
|
154
|
+
return focusableElements.get(0);
|
|
153
155
|
}
|
|
154
156
|
function isActiveDescendantInputFocused() {
|
|
155
157
|
return document.activeElement === activeDescendantControl;
|
|
@@ -205,7 +207,7 @@ function focusZone(container, settings) {
|
|
|
205
207
|
if (filteredElements.length === 0) {
|
|
206
208
|
return;
|
|
207
209
|
}
|
|
208
|
-
focusableElements.
|
|
210
|
+
focusableElements.insertAt(findInsertionIndex(filteredElements), ...filteredElements);
|
|
209
211
|
for (const element of filteredElements) {
|
|
210
212
|
if (!savedTabIndex.has(element)) {
|
|
211
213
|
savedTabIndex.set(element, element.getAttribute('tabindex'));
|
|
@@ -218,13 +220,13 @@ function focusZone(container, settings) {
|
|
|
218
220
|
}
|
|
219
221
|
function findInsertionIndex(elementsToInsert) {
|
|
220
222
|
const firstElementToInsert = elementsToInsert[0];
|
|
221
|
-
if (focusableElements.
|
|
223
|
+
if (focusableElements.size === 0)
|
|
222
224
|
return 0;
|
|
223
225
|
let iMin = 0;
|
|
224
|
-
let iMax = focusableElements.
|
|
226
|
+
let iMax = focusableElements.size - 1;
|
|
225
227
|
while (iMin <= iMax) {
|
|
226
228
|
const i = Math.floor((iMin + iMax) / 2);
|
|
227
|
-
const element = focusableElements
|
|
229
|
+
const element = focusableElements.get(i);
|
|
228
230
|
if (followsInDocument(firstElementToInsert, element)) {
|
|
229
231
|
iMax = i - 1;
|
|
230
232
|
}
|
|
@@ -239,10 +241,7 @@ function focusZone(container, settings) {
|
|
|
239
241
|
}
|
|
240
242
|
function endFocusManagement(...elements) {
|
|
241
243
|
for (const element of elements) {
|
|
242
|
-
|
|
243
|
-
if (focusableElementIndex >= 0) {
|
|
244
|
-
focusableElements.splice(focusableElementIndex, 1);
|
|
245
|
-
}
|
|
244
|
+
focusableElements.delete(element);
|
|
246
245
|
const savedIndex = savedTabIndex.get(element);
|
|
247
246
|
if (savedIndex !== undefined) {
|
|
248
247
|
if (savedIndex === null) {
|
|
@@ -298,7 +297,12 @@ function focusZone(container, settings) {
|
|
|
298
297
|
}
|
|
299
298
|
}
|
|
300
299
|
if (elementsToRemove.size > 0) {
|
|
301
|
-
const toRemove = [
|
|
300
|
+
const toRemove = [];
|
|
301
|
+
for (const node of elementsToRemove) {
|
|
302
|
+
for (const el of iterateFocusableElements.iterateFocusableElements(node)) {
|
|
303
|
+
toRemove.push(el);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
302
306
|
if (toRemove.length > 0) {
|
|
303
307
|
endFocusManagement(...toRemove);
|
|
304
308
|
}
|
|
@@ -307,9 +311,12 @@ function focusZone(container, settings) {
|
|
|
307
311
|
endFocusManagement(...attributeRemovals);
|
|
308
312
|
}
|
|
309
313
|
if (elementsToAdd.size > 0) {
|
|
310
|
-
const toAdd = [
|
|
311
|
-
|
|
312
|
-
|
|
314
|
+
const toAdd = [];
|
|
315
|
+
for (const node of elementsToAdd) {
|
|
316
|
+
for (const el of iterateFocusableElements.iterateFocusableElements(node, iterateFocusableElementsOptions)) {
|
|
317
|
+
toAdd.push(el);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
313
320
|
if (toAdd.length > 0) {
|
|
314
321
|
beginFocusManagement(...toAdd);
|
|
315
322
|
}
|
|
@@ -338,7 +345,7 @@ function focusZone(container, settings) {
|
|
|
338
345
|
}, { signal });
|
|
339
346
|
if (activeDescendantControl) {
|
|
340
347
|
container.addEventListener('focusin', event => {
|
|
341
|
-
if (event.target instanceof HTMLElement && focusableElements.
|
|
348
|
+
if (event.target instanceof HTMLElement && focusableElements.has(event.target)) {
|
|
342
349
|
activeDescendantControl.focus({ preventScroll });
|
|
343
350
|
updateFocusedElement(event.target);
|
|
344
351
|
}
|
|
@@ -348,6 +355,10 @@ function focusZone(container, settings) {
|
|
|
348
355
|
if (!(target instanceof Node)) {
|
|
349
356
|
return;
|
|
350
357
|
}
|
|
358
|
+
if (target instanceof HTMLElement && focusableElements.has(target)) {
|
|
359
|
+
updateFocusedElement(target);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
351
362
|
const focusableElement = focusableElements.find(element => element.contains(target));
|
|
352
363
|
if (focusableElement) {
|
|
353
364
|
updateFocusedElement(focusableElement);
|
|
@@ -372,8 +383,9 @@ function focusZone(container, settings) {
|
|
|
372
383
|
if (event.target instanceof HTMLElement) {
|
|
373
384
|
if (elementIndexFocusedByClick !== undefined) {
|
|
374
385
|
if (elementIndexFocusedByClick >= 0) {
|
|
375
|
-
|
|
376
|
-
|
|
386
|
+
const clickedElement = focusableElements.get(elementIndexFocusedByClick);
|
|
387
|
+
if (clickedElement && clickedElement !== currentFocusedElement) {
|
|
388
|
+
updateFocusedElement(clickedElement);
|
|
377
389
|
}
|
|
378
390
|
}
|
|
379
391
|
elementIndexFocusedByClick = undefined;
|
|
@@ -384,8 +396,8 @@ function focusZone(container, settings) {
|
|
|
384
396
|
}
|
|
385
397
|
else if (focusInStrategy === 'closest' || focusInStrategy === 'first') {
|
|
386
398
|
if (event.relatedTarget instanceof Element && !container.contains(event.relatedTarget)) {
|
|
387
|
-
const targetElementIndex = lastKeyboardFocusDirection === 'previous' ? focusableElements.
|
|
388
|
-
const targetElement = focusableElements
|
|
399
|
+
const targetElementIndex = lastKeyboardFocusDirection === 'previous' ? focusableElements.size - 1 : 0;
|
|
400
|
+
const targetElement = focusableElements.get(targetElementIndex);
|
|
389
401
|
targetElement === null || targetElement === void 0 ? void 0 : targetElement.focus({ preventScroll });
|
|
390
402
|
return;
|
|
391
403
|
}
|
|
@@ -396,8 +408,7 @@ function focusZone(container, settings) {
|
|
|
396
408
|
else if (typeof focusInStrategy === 'function') {
|
|
397
409
|
if (event.relatedTarget instanceof Element && !container.contains(event.relatedTarget)) {
|
|
398
410
|
const elementToFocus = focusInStrategy(event.relatedTarget);
|
|
399
|
-
|
|
400
|
-
if (requestedFocusElementIndex >= 0 && elementToFocus instanceof HTMLElement) {
|
|
411
|
+
if (elementToFocus && focusableElements.has(elementToFocus)) {
|
|
401
412
|
elementToFocus.focus({ preventScroll });
|
|
402
413
|
return;
|
|
403
414
|
}
|
|
@@ -456,26 +467,26 @@ function focusZone(container, settings) {
|
|
|
456
467
|
nextFocusedIndex += 1;
|
|
457
468
|
}
|
|
458
469
|
else {
|
|
459
|
-
nextFocusedIndex = focusableElements.
|
|
470
|
+
nextFocusedIndex = focusableElements.size - 1;
|
|
460
471
|
}
|
|
461
472
|
if (nextFocusedIndex < 0) {
|
|
462
473
|
if (focusOutBehavior === 'wrap' && event.key !== 'Tab') {
|
|
463
|
-
nextFocusedIndex = focusableElements.
|
|
474
|
+
nextFocusedIndex = focusableElements.size - 1;
|
|
464
475
|
}
|
|
465
476
|
else {
|
|
466
477
|
nextFocusedIndex = 0;
|
|
467
478
|
}
|
|
468
479
|
}
|
|
469
|
-
if (nextFocusedIndex >= focusableElements.
|
|
480
|
+
if (nextFocusedIndex >= focusableElements.size) {
|
|
470
481
|
if (focusOutBehavior === 'wrap' && event.key !== 'Tab') {
|
|
471
482
|
nextFocusedIndex = 0;
|
|
472
483
|
}
|
|
473
484
|
else {
|
|
474
|
-
nextFocusedIndex = focusableElements.
|
|
485
|
+
nextFocusedIndex = focusableElements.size - 1;
|
|
475
486
|
}
|
|
476
487
|
}
|
|
477
488
|
if (lastFocusedIndex !== nextFocusedIndex) {
|
|
478
|
-
nextElementToFocus = focusableElements
|
|
489
|
+
nextElementToFocus = focusableElements.get(nextFocusedIndex);
|
|
479
490
|
}
|
|
480
491
|
}
|
|
481
492
|
if (activeDescendantControl) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class IndexedSet<T> {
|
|
2
|
+
#private;
|
|
3
|
+
insertAt(index: number, ...elements: T[]): void;
|
|
4
|
+
delete(element: T): boolean;
|
|
5
|
+
has(element: T): boolean;
|
|
6
|
+
indexOf(element: T): number;
|
|
7
|
+
get(index: number): T | undefined;
|
|
8
|
+
get size(): number;
|
|
9
|
+
[Symbol.iterator](): Iterator<T>;
|
|
10
|
+
clear(): void;
|
|
11
|
+
find(predicate: (element: T) => boolean): T | undefined;
|
|
12
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tslib = require('tslib');
|
|
4
|
+
|
|
5
|
+
var _IndexedSet_items, _IndexedSet_itemSet;
|
|
6
|
+
class IndexedSet {
|
|
7
|
+
constructor() {
|
|
8
|
+
_IndexedSet_items.set(this, []);
|
|
9
|
+
_IndexedSet_itemSet.set(this, new Set());
|
|
10
|
+
}
|
|
11
|
+
insertAt(index, ...elements) {
|
|
12
|
+
const newElements = elements.filter(e => !tslib.__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").has(e));
|
|
13
|
+
if (newElements.length === 0)
|
|
14
|
+
return;
|
|
15
|
+
tslib.__classPrivateFieldGet(this, _IndexedSet_items, "f").splice(index, 0, ...newElements);
|
|
16
|
+
for (const element of newElements) {
|
|
17
|
+
tslib.__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").add(element);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
delete(element) {
|
|
21
|
+
if (!tslib.__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").has(element))
|
|
22
|
+
return false;
|
|
23
|
+
const index = tslib.__classPrivateFieldGet(this, _IndexedSet_items, "f").indexOf(element);
|
|
24
|
+
if (index >= 0) {
|
|
25
|
+
tslib.__classPrivateFieldGet(this, _IndexedSet_items, "f").splice(index, 1);
|
|
26
|
+
}
|
|
27
|
+
tslib.__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").delete(element);
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
has(element) {
|
|
31
|
+
return tslib.__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").has(element);
|
|
32
|
+
}
|
|
33
|
+
indexOf(element) {
|
|
34
|
+
if (!tslib.__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").has(element))
|
|
35
|
+
return -1;
|
|
36
|
+
return tslib.__classPrivateFieldGet(this, _IndexedSet_items, "f").indexOf(element);
|
|
37
|
+
}
|
|
38
|
+
get(index) {
|
|
39
|
+
return tslib.__classPrivateFieldGet(this, _IndexedSet_items, "f")[index];
|
|
40
|
+
}
|
|
41
|
+
get size() {
|
|
42
|
+
return tslib.__classPrivateFieldGet(this, _IndexedSet_items, "f").length;
|
|
43
|
+
}
|
|
44
|
+
[(_IndexedSet_items = new WeakMap(), _IndexedSet_itemSet = new WeakMap(), Symbol.iterator)]() {
|
|
45
|
+
return tslib.__classPrivateFieldGet(this, _IndexedSet_items, "f")[Symbol.iterator]();
|
|
46
|
+
}
|
|
47
|
+
clear() {
|
|
48
|
+
tslib.__classPrivateFieldSet(this, _IndexedSet_items, [], "f");
|
|
49
|
+
tslib.__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").clear();
|
|
50
|
+
}
|
|
51
|
+
find(predicate) {
|
|
52
|
+
return tslib.__classPrivateFieldGet(this, _IndexedSet_items, "f").find(predicate);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
exports.IndexedSet = IndexedSet;
|
package/dist/esm/focus-trap.mjs
CHANGED
|
@@ -21,9 +21,10 @@ function observeFocusTrap(container, sentinels) {
|
|
|
21
21
|
const observer = new MutationObserver(mutations => {
|
|
22
22
|
for (const mutation of mutations) {
|
|
23
23
|
if (mutation.type === 'childList' && mutation.addedNodes.length) {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
for (const node of mutation.addedNodes) {
|
|
25
|
+
if (node instanceof HTMLElement && node.tagName === 'SPAN' && node.classList.contains('sentinel')) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
27
28
|
}
|
|
28
29
|
const firstChild = container.firstElementChild;
|
|
29
30
|
const lastChild = container.lastElementChild;
|
package/dist/esm/focus-zone.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { isMacOS } from './utils/user-agent.mjs';
|
|
|
3
3
|
import { iterateFocusableElements } from './utils/iterate-focusable-elements.mjs';
|
|
4
4
|
import { uniqueId } from './utils/unique-id.mjs';
|
|
5
5
|
import { isEditableElement } from './utils/is-editable-element.mjs';
|
|
6
|
+
import { IndexedSet } from './utils/indexed-set.mjs';
|
|
6
7
|
|
|
7
8
|
polyfill();
|
|
8
9
|
var FocusKeys;
|
|
@@ -87,17 +88,18 @@ function getDirection(keyboardEvent) {
|
|
|
87
88
|
}
|
|
88
89
|
function shouldIgnoreFocusHandling(keyboardEvent, activeElement) {
|
|
89
90
|
const key = keyboardEvent.key;
|
|
90
|
-
const
|
|
91
|
+
const isSingleChar = key.length === 1 || (key.length === 2 && key.charCodeAt(0) >= 0xd800 && key.charCodeAt(0) <= 0xdbff);
|
|
91
92
|
const isEditable = isEditableElement(activeElement);
|
|
92
93
|
const isSelect = activeElement instanceof HTMLSelectElement;
|
|
93
|
-
if (isEditable && (
|
|
94
|
+
if (isEditable && (isSingleChar || key === 'Home' || key === 'End')) {
|
|
94
95
|
return true;
|
|
95
96
|
}
|
|
96
97
|
if (isSelect) {
|
|
97
|
-
|
|
98
|
+
const isMac = getIsMac();
|
|
99
|
+
if (key === 'ArrowDown' && isMac && !keyboardEvent.metaKey) {
|
|
98
100
|
return true;
|
|
99
101
|
}
|
|
100
|
-
if (key === 'ArrowDown' && !
|
|
102
|
+
if (key === 'ArrowDown' && !isMac && keyboardEvent.altKey) {
|
|
101
103
|
return true;
|
|
102
104
|
}
|
|
103
105
|
return false;
|
|
@@ -135,7 +137,7 @@ const activeDescendantActivatedIndirectly = 'activated-indirectly';
|
|
|
135
137
|
const hasActiveDescendantAttribute = 'data-has-active-descendant';
|
|
136
138
|
function focusZone(container, settings) {
|
|
137
139
|
var _a, _b, _c, _d, _e, _f;
|
|
138
|
-
const focusableElements =
|
|
140
|
+
const focusableElements = new IndexedSet();
|
|
139
141
|
const savedTabIndex = new WeakMap();
|
|
140
142
|
const bindKeys = (_a = settings === null || settings === void 0 ? void 0 : settings.bindKeys) !== null && _a !== void 0 ? _a : ((settings === null || settings === void 0 ? void 0 : settings.getNextFocusable) ? FocusKeys.ArrowAll : FocusKeys.ArrowVertical) | FocusKeys.HomeAndEnd;
|
|
141
143
|
const focusOutBehavior = (_b = settings === null || settings === void 0 ? void 0 : settings.focusOutBehavior) !== null && _b !== void 0 ? _b : 'stop';
|
|
@@ -147,7 +149,7 @@ function focusZone(container, settings) {
|
|
|
147
149
|
const preventScroll = (_e = settings === null || settings === void 0 ? void 0 : settings.preventScroll) !== null && _e !== void 0 ? _e : false;
|
|
148
150
|
const preventInitialFocus = focusInStrategy === 'initial' && (settings === null || settings === void 0 ? void 0 : settings.activeDescendantControl);
|
|
149
151
|
function getFirstFocusableElement() {
|
|
150
|
-
return focusableElements
|
|
152
|
+
return focusableElements.get(0);
|
|
151
153
|
}
|
|
152
154
|
function isActiveDescendantInputFocused() {
|
|
153
155
|
return document.activeElement === activeDescendantControl;
|
|
@@ -203,7 +205,7 @@ function focusZone(container, settings) {
|
|
|
203
205
|
if (filteredElements.length === 0) {
|
|
204
206
|
return;
|
|
205
207
|
}
|
|
206
|
-
focusableElements.
|
|
208
|
+
focusableElements.insertAt(findInsertionIndex(filteredElements), ...filteredElements);
|
|
207
209
|
for (const element of filteredElements) {
|
|
208
210
|
if (!savedTabIndex.has(element)) {
|
|
209
211
|
savedTabIndex.set(element, element.getAttribute('tabindex'));
|
|
@@ -216,13 +218,13 @@ function focusZone(container, settings) {
|
|
|
216
218
|
}
|
|
217
219
|
function findInsertionIndex(elementsToInsert) {
|
|
218
220
|
const firstElementToInsert = elementsToInsert[0];
|
|
219
|
-
if (focusableElements.
|
|
221
|
+
if (focusableElements.size === 0)
|
|
220
222
|
return 0;
|
|
221
223
|
let iMin = 0;
|
|
222
|
-
let iMax = focusableElements.
|
|
224
|
+
let iMax = focusableElements.size - 1;
|
|
223
225
|
while (iMin <= iMax) {
|
|
224
226
|
const i = Math.floor((iMin + iMax) / 2);
|
|
225
|
-
const element = focusableElements
|
|
227
|
+
const element = focusableElements.get(i);
|
|
226
228
|
if (followsInDocument(firstElementToInsert, element)) {
|
|
227
229
|
iMax = i - 1;
|
|
228
230
|
}
|
|
@@ -237,10 +239,7 @@ function focusZone(container, settings) {
|
|
|
237
239
|
}
|
|
238
240
|
function endFocusManagement(...elements) {
|
|
239
241
|
for (const element of elements) {
|
|
240
|
-
|
|
241
|
-
if (focusableElementIndex >= 0) {
|
|
242
|
-
focusableElements.splice(focusableElementIndex, 1);
|
|
243
|
-
}
|
|
242
|
+
focusableElements.delete(element);
|
|
244
243
|
const savedIndex = savedTabIndex.get(element);
|
|
245
244
|
if (savedIndex !== undefined) {
|
|
246
245
|
if (savedIndex === null) {
|
|
@@ -296,7 +295,12 @@ function focusZone(container, settings) {
|
|
|
296
295
|
}
|
|
297
296
|
}
|
|
298
297
|
if (elementsToRemove.size > 0) {
|
|
299
|
-
const toRemove = [
|
|
298
|
+
const toRemove = [];
|
|
299
|
+
for (const node of elementsToRemove) {
|
|
300
|
+
for (const el of iterateFocusableElements(node)) {
|
|
301
|
+
toRemove.push(el);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
300
304
|
if (toRemove.length > 0) {
|
|
301
305
|
endFocusManagement(...toRemove);
|
|
302
306
|
}
|
|
@@ -305,9 +309,12 @@ function focusZone(container, settings) {
|
|
|
305
309
|
endFocusManagement(...attributeRemovals);
|
|
306
310
|
}
|
|
307
311
|
if (elementsToAdd.size > 0) {
|
|
308
|
-
const toAdd = [
|
|
309
|
-
|
|
310
|
-
|
|
312
|
+
const toAdd = [];
|
|
313
|
+
for (const node of elementsToAdd) {
|
|
314
|
+
for (const el of iterateFocusableElements(node, iterateFocusableElementsOptions)) {
|
|
315
|
+
toAdd.push(el);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
311
318
|
if (toAdd.length > 0) {
|
|
312
319
|
beginFocusManagement(...toAdd);
|
|
313
320
|
}
|
|
@@ -336,7 +343,7 @@ function focusZone(container, settings) {
|
|
|
336
343
|
}, { signal });
|
|
337
344
|
if (activeDescendantControl) {
|
|
338
345
|
container.addEventListener('focusin', event => {
|
|
339
|
-
if (event.target instanceof HTMLElement && focusableElements.
|
|
346
|
+
if (event.target instanceof HTMLElement && focusableElements.has(event.target)) {
|
|
340
347
|
activeDescendantControl.focus({ preventScroll });
|
|
341
348
|
updateFocusedElement(event.target);
|
|
342
349
|
}
|
|
@@ -346,6 +353,10 @@ function focusZone(container, settings) {
|
|
|
346
353
|
if (!(target instanceof Node)) {
|
|
347
354
|
return;
|
|
348
355
|
}
|
|
356
|
+
if (target instanceof HTMLElement && focusableElements.has(target)) {
|
|
357
|
+
updateFocusedElement(target);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
349
360
|
const focusableElement = focusableElements.find(element => element.contains(target));
|
|
350
361
|
if (focusableElement) {
|
|
351
362
|
updateFocusedElement(focusableElement);
|
|
@@ -370,8 +381,9 @@ function focusZone(container, settings) {
|
|
|
370
381
|
if (event.target instanceof HTMLElement) {
|
|
371
382
|
if (elementIndexFocusedByClick !== undefined) {
|
|
372
383
|
if (elementIndexFocusedByClick >= 0) {
|
|
373
|
-
|
|
374
|
-
|
|
384
|
+
const clickedElement = focusableElements.get(elementIndexFocusedByClick);
|
|
385
|
+
if (clickedElement && clickedElement !== currentFocusedElement) {
|
|
386
|
+
updateFocusedElement(clickedElement);
|
|
375
387
|
}
|
|
376
388
|
}
|
|
377
389
|
elementIndexFocusedByClick = undefined;
|
|
@@ -382,8 +394,8 @@ function focusZone(container, settings) {
|
|
|
382
394
|
}
|
|
383
395
|
else if (focusInStrategy === 'closest' || focusInStrategy === 'first') {
|
|
384
396
|
if (event.relatedTarget instanceof Element && !container.contains(event.relatedTarget)) {
|
|
385
|
-
const targetElementIndex = lastKeyboardFocusDirection === 'previous' ? focusableElements.
|
|
386
|
-
const targetElement = focusableElements
|
|
397
|
+
const targetElementIndex = lastKeyboardFocusDirection === 'previous' ? focusableElements.size - 1 : 0;
|
|
398
|
+
const targetElement = focusableElements.get(targetElementIndex);
|
|
387
399
|
targetElement === null || targetElement === void 0 ? void 0 : targetElement.focus({ preventScroll });
|
|
388
400
|
return;
|
|
389
401
|
}
|
|
@@ -394,8 +406,7 @@ function focusZone(container, settings) {
|
|
|
394
406
|
else if (typeof focusInStrategy === 'function') {
|
|
395
407
|
if (event.relatedTarget instanceof Element && !container.contains(event.relatedTarget)) {
|
|
396
408
|
const elementToFocus = focusInStrategy(event.relatedTarget);
|
|
397
|
-
|
|
398
|
-
if (requestedFocusElementIndex >= 0 && elementToFocus instanceof HTMLElement) {
|
|
409
|
+
if (elementToFocus && focusableElements.has(elementToFocus)) {
|
|
399
410
|
elementToFocus.focus({ preventScroll });
|
|
400
411
|
return;
|
|
401
412
|
}
|
|
@@ -454,26 +465,26 @@ function focusZone(container, settings) {
|
|
|
454
465
|
nextFocusedIndex += 1;
|
|
455
466
|
}
|
|
456
467
|
else {
|
|
457
|
-
nextFocusedIndex = focusableElements.
|
|
468
|
+
nextFocusedIndex = focusableElements.size - 1;
|
|
458
469
|
}
|
|
459
470
|
if (nextFocusedIndex < 0) {
|
|
460
471
|
if (focusOutBehavior === 'wrap' && event.key !== 'Tab') {
|
|
461
|
-
nextFocusedIndex = focusableElements.
|
|
472
|
+
nextFocusedIndex = focusableElements.size - 1;
|
|
462
473
|
}
|
|
463
474
|
else {
|
|
464
475
|
nextFocusedIndex = 0;
|
|
465
476
|
}
|
|
466
477
|
}
|
|
467
|
-
if (nextFocusedIndex >= focusableElements.
|
|
478
|
+
if (nextFocusedIndex >= focusableElements.size) {
|
|
468
479
|
if (focusOutBehavior === 'wrap' && event.key !== 'Tab') {
|
|
469
480
|
nextFocusedIndex = 0;
|
|
470
481
|
}
|
|
471
482
|
else {
|
|
472
|
-
nextFocusedIndex = focusableElements.
|
|
483
|
+
nextFocusedIndex = focusableElements.size - 1;
|
|
473
484
|
}
|
|
474
485
|
}
|
|
475
486
|
if (lastFocusedIndex !== nextFocusedIndex) {
|
|
476
|
-
nextElementToFocus = focusableElements
|
|
487
|
+
nextElementToFocus = focusableElements.get(nextFocusedIndex);
|
|
477
488
|
}
|
|
478
489
|
}
|
|
479
490
|
if (activeDescendantControl) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class IndexedSet<T> {
|
|
2
|
+
#private;
|
|
3
|
+
insertAt(index: number, ...elements: T[]): void;
|
|
4
|
+
delete(element: T): boolean;
|
|
5
|
+
has(element: T): boolean;
|
|
6
|
+
indexOf(element: T): number;
|
|
7
|
+
get(index: number): T | undefined;
|
|
8
|
+
get size(): number;
|
|
9
|
+
[Symbol.iterator](): Iterator<T>;
|
|
10
|
+
clear(): void;
|
|
11
|
+
find(predicate: (element: T) => boolean): T | undefined;
|
|
12
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { __classPrivateFieldGet, __classPrivateFieldSet } from 'tslib';
|
|
2
|
+
|
|
3
|
+
var _IndexedSet_items, _IndexedSet_itemSet;
|
|
4
|
+
class IndexedSet {
|
|
5
|
+
constructor() {
|
|
6
|
+
_IndexedSet_items.set(this, []);
|
|
7
|
+
_IndexedSet_itemSet.set(this, new Set());
|
|
8
|
+
}
|
|
9
|
+
insertAt(index, ...elements) {
|
|
10
|
+
const newElements = elements.filter(e => !__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").has(e));
|
|
11
|
+
if (newElements.length === 0)
|
|
12
|
+
return;
|
|
13
|
+
__classPrivateFieldGet(this, _IndexedSet_items, "f").splice(index, 0, ...newElements);
|
|
14
|
+
for (const element of newElements) {
|
|
15
|
+
__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").add(element);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
delete(element) {
|
|
19
|
+
if (!__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").has(element))
|
|
20
|
+
return false;
|
|
21
|
+
const index = __classPrivateFieldGet(this, _IndexedSet_items, "f").indexOf(element);
|
|
22
|
+
if (index >= 0) {
|
|
23
|
+
__classPrivateFieldGet(this, _IndexedSet_items, "f").splice(index, 1);
|
|
24
|
+
}
|
|
25
|
+
__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").delete(element);
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
has(element) {
|
|
29
|
+
return __classPrivateFieldGet(this, _IndexedSet_itemSet, "f").has(element);
|
|
30
|
+
}
|
|
31
|
+
indexOf(element) {
|
|
32
|
+
if (!__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").has(element))
|
|
33
|
+
return -1;
|
|
34
|
+
return __classPrivateFieldGet(this, _IndexedSet_items, "f").indexOf(element);
|
|
35
|
+
}
|
|
36
|
+
get(index) {
|
|
37
|
+
return __classPrivateFieldGet(this, _IndexedSet_items, "f")[index];
|
|
38
|
+
}
|
|
39
|
+
get size() {
|
|
40
|
+
return __classPrivateFieldGet(this, _IndexedSet_items, "f").length;
|
|
41
|
+
}
|
|
42
|
+
[(_IndexedSet_items = new WeakMap(), _IndexedSet_itemSet = new WeakMap(), Symbol.iterator)]() {
|
|
43
|
+
return __classPrivateFieldGet(this, _IndexedSet_items, "f")[Symbol.iterator]();
|
|
44
|
+
}
|
|
45
|
+
clear() {
|
|
46
|
+
__classPrivateFieldSet(this, _IndexedSet_items, [], "f");
|
|
47
|
+
__classPrivateFieldGet(this, _IndexedSet_itemSet, "f").clear();
|
|
48
|
+
}
|
|
49
|
+
find(predicate) {
|
|
50
|
+
return __classPrivateFieldGet(this, _IndexedSet_items, "f").find(predicate);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { IndexedSet };
|