@y14e/portal 1.1.0 → 1.1.1
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/index.cjs +21 -45
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +21 -45
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -295,8 +295,7 @@ var Portal = class {
|
|
|
295
295
|
#container;
|
|
296
296
|
#entranceSentinel;
|
|
297
297
|
#exitSentinel;
|
|
298
|
-
#
|
|
299
|
-
#tabIndexes = /* @__PURE__ */ new Map();
|
|
298
|
+
#tabIndexes = /* @__PURE__ */ new WeakMap();
|
|
300
299
|
#controller = null;
|
|
301
300
|
#isDestroyed = false;
|
|
302
301
|
constructor(host, container) {
|
|
@@ -313,7 +312,10 @@ var Portal = class {
|
|
|
313
312
|
this.#isDestroyed = true;
|
|
314
313
|
this.#controller?.abort();
|
|
315
314
|
this.#controller = null;
|
|
316
|
-
this.#
|
|
315
|
+
this.#getFocusables().forEach((focusable) => {
|
|
316
|
+
if (!this.#tabIndexes.has(focusable)) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
317
319
|
const index = this.#tabIndexes.get(focusable);
|
|
318
320
|
if (index == null) {
|
|
319
321
|
focusable.removeAttribute("tabindex");
|
|
@@ -321,8 +323,6 @@ var Portal = class {
|
|
|
321
323
|
focusable.setAttribute("tabindex", index);
|
|
322
324
|
}
|
|
323
325
|
});
|
|
324
|
-
this.#focusables.clear();
|
|
325
|
-
this.#tabIndexes.clear();
|
|
326
326
|
this.#exitSentinel.after(this.#host);
|
|
327
327
|
this.#entranceSentinel.remove();
|
|
328
328
|
this.#exitSentinel.remove();
|
|
@@ -332,7 +332,10 @@ var Portal = class {
|
|
|
332
332
|
this.#host.before(this.#entranceSentinel);
|
|
333
333
|
this.#entranceSentinel.after(this.#exitSentinel);
|
|
334
334
|
this.#container.append(this.#host);
|
|
335
|
-
this.#
|
|
335
|
+
this.#getFocusables().forEach((focusable) => {
|
|
336
|
+
this.#tabIndexes.set(focusable, focusable.getAttribute("tabindex"));
|
|
337
|
+
focusable.setAttribute("tabindex", "-1");
|
|
338
|
+
});
|
|
336
339
|
this.#controller = new AbortController();
|
|
337
340
|
const { signal } = this.#controller;
|
|
338
341
|
document.addEventListener("focusin", this.#onFocusIn, {
|
|
@@ -355,16 +358,14 @@ var Portal = class {
|
|
|
355
358
|
if (this.#host.contains(before)) {
|
|
356
359
|
this.#moveFocus("previous");
|
|
357
360
|
} else {
|
|
358
|
-
this.#
|
|
359
|
-
const first = [...this.#focusables][0];
|
|
361
|
+
const first = this.#getFocusables()[0];
|
|
360
362
|
first && focusElement(first);
|
|
361
363
|
}
|
|
362
364
|
} else if (current === this.#exitSentinel) {
|
|
363
365
|
if (this.#host.contains(before)) {
|
|
364
366
|
this.#moveFocus("next");
|
|
365
367
|
} else {
|
|
366
|
-
this.#
|
|
367
|
-
const last = [...this.#focusables].at(-1);
|
|
368
|
+
const last = this.#getFocusables().at(-1);
|
|
368
369
|
last && focusElement(last);
|
|
369
370
|
}
|
|
370
371
|
}
|
|
@@ -380,53 +381,22 @@ var Portal = class {
|
|
|
380
381
|
if (!this.#host.contains(active)) {
|
|
381
382
|
return;
|
|
382
383
|
}
|
|
383
|
-
this.#
|
|
384
|
-
const focusables = [...this.#focusables];
|
|
385
|
-
if (!focusables.length) {
|
|
384
|
+
if (!this.#getFocusables().length) {
|
|
386
385
|
event.preventDefault();
|
|
387
386
|
(event.shiftKey ? this.#entranceSentinel : this.#exitSentinel).focus();
|
|
388
|
-
return;
|
|
389
387
|
}
|
|
390
|
-
const index =
|
|
388
|
+
const index = this.#getFocusables().indexOf(active);
|
|
391
389
|
if (index === -1) {
|
|
392
390
|
return;
|
|
393
391
|
}
|
|
394
392
|
event.preventDefault();
|
|
395
|
-
const focusable =
|
|
393
|
+
const focusable = this.#getFocusables()[index + (event.shiftKey ? -1 : 1)];
|
|
396
394
|
if (focusable) {
|
|
397
395
|
focusElement(focusable);
|
|
398
396
|
} else {
|
|
399
397
|
(event.shiftKey ? this.#entranceSentinel : this.#exitSentinel).focus();
|
|
400
398
|
}
|
|
401
399
|
};
|
|
402
|
-
#update() {
|
|
403
|
-
const current = new Set(
|
|
404
|
-
getFocusables(this.#host, { composed: true })
|
|
405
|
-
);
|
|
406
|
-
this.#focusables.forEach((focusable) => {
|
|
407
|
-
if (current.has(focusable)) {
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
if (focusable.isConnected) {
|
|
411
|
-
const index = this.#tabIndexes.get(focusable);
|
|
412
|
-
if (index == null) {
|
|
413
|
-
focusable.removeAttribute("tabindex");
|
|
414
|
-
} else {
|
|
415
|
-
focusable.setAttribute("tabindex", index);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
this.#focusables.delete(focusable);
|
|
419
|
-
this.#tabIndexes.delete(focusable);
|
|
420
|
-
});
|
|
421
|
-
const active = getActiveElement2();
|
|
422
|
-
current.forEach((c) => {
|
|
423
|
-
if (!this.#tabIndexes.has(c)) {
|
|
424
|
-
this.#tabIndexes.set(c, c.getAttribute("tabindex"));
|
|
425
|
-
}
|
|
426
|
-
c.setAttribute("tabindex", c === active ? "0" : "-1");
|
|
427
|
-
this.#focusables.add(c);
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
400
|
#createSentinel() {
|
|
431
401
|
const sentinel = document.createElement("span");
|
|
432
402
|
sentinel.setAttribute("aria-hidden", "true");
|
|
@@ -435,6 +405,12 @@ var Portal = class {
|
|
|
435
405
|
sentinel.style.cssText += VISUALLY_HIDDEN_CSS;
|
|
436
406
|
return sentinel;
|
|
437
407
|
}
|
|
408
|
+
#getFocusables() {
|
|
409
|
+
return getFocusables(this.#host, {
|
|
410
|
+
composed: true,
|
|
411
|
+
include: (element) => this.#tabIndexes.has(element)
|
|
412
|
+
});
|
|
413
|
+
}
|
|
438
414
|
#moveFocus(direction) {
|
|
439
415
|
const options = {
|
|
440
416
|
anchor: direction === "previous" ? this.#entranceSentinel : this.#exitSentinel,
|
|
@@ -469,7 +445,7 @@ function getActiveElement2() {
|
|
|
469
445
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
470
446
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
471
447
|
*
|
|
472
|
-
* @version 1.1.
|
|
448
|
+
* @version 1.1.1
|
|
473
449
|
* @author Yusuke Kamiyamane
|
|
474
450
|
* @license MIT
|
|
475
451
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.cts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
4
4
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
5
5
|
*
|
|
6
|
-
* @version 1.1.
|
|
6
|
+
* @version 1.1.1
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
4
4
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
5
5
|
*
|
|
6
|
-
* @version 1.1.
|
|
6
|
+
* @version 1.1.1
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.js
CHANGED
|
@@ -293,8 +293,7 @@ var Portal = class {
|
|
|
293
293
|
#container;
|
|
294
294
|
#entranceSentinel;
|
|
295
295
|
#exitSentinel;
|
|
296
|
-
#
|
|
297
|
-
#tabIndexes = /* @__PURE__ */ new Map();
|
|
296
|
+
#tabIndexes = /* @__PURE__ */ new WeakMap();
|
|
298
297
|
#controller = null;
|
|
299
298
|
#isDestroyed = false;
|
|
300
299
|
constructor(host, container) {
|
|
@@ -311,7 +310,10 @@ var Portal = class {
|
|
|
311
310
|
this.#isDestroyed = true;
|
|
312
311
|
this.#controller?.abort();
|
|
313
312
|
this.#controller = null;
|
|
314
|
-
this.#
|
|
313
|
+
this.#getFocusables().forEach((focusable) => {
|
|
314
|
+
if (!this.#tabIndexes.has(focusable)) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
315
317
|
const index = this.#tabIndexes.get(focusable);
|
|
316
318
|
if (index == null) {
|
|
317
319
|
focusable.removeAttribute("tabindex");
|
|
@@ -319,8 +321,6 @@ var Portal = class {
|
|
|
319
321
|
focusable.setAttribute("tabindex", index);
|
|
320
322
|
}
|
|
321
323
|
});
|
|
322
|
-
this.#focusables.clear();
|
|
323
|
-
this.#tabIndexes.clear();
|
|
324
324
|
this.#exitSentinel.after(this.#host);
|
|
325
325
|
this.#entranceSentinel.remove();
|
|
326
326
|
this.#exitSentinel.remove();
|
|
@@ -330,7 +330,10 @@ var Portal = class {
|
|
|
330
330
|
this.#host.before(this.#entranceSentinel);
|
|
331
331
|
this.#entranceSentinel.after(this.#exitSentinel);
|
|
332
332
|
this.#container.append(this.#host);
|
|
333
|
-
this.#
|
|
333
|
+
this.#getFocusables().forEach((focusable) => {
|
|
334
|
+
this.#tabIndexes.set(focusable, focusable.getAttribute("tabindex"));
|
|
335
|
+
focusable.setAttribute("tabindex", "-1");
|
|
336
|
+
});
|
|
334
337
|
this.#controller = new AbortController();
|
|
335
338
|
const { signal } = this.#controller;
|
|
336
339
|
document.addEventListener("focusin", this.#onFocusIn, {
|
|
@@ -353,16 +356,14 @@ var Portal = class {
|
|
|
353
356
|
if (this.#host.contains(before)) {
|
|
354
357
|
this.#moveFocus("previous");
|
|
355
358
|
} else {
|
|
356
|
-
this.#
|
|
357
|
-
const first = [...this.#focusables][0];
|
|
359
|
+
const first = this.#getFocusables()[0];
|
|
358
360
|
first && focusElement(first);
|
|
359
361
|
}
|
|
360
362
|
} else if (current === this.#exitSentinel) {
|
|
361
363
|
if (this.#host.contains(before)) {
|
|
362
364
|
this.#moveFocus("next");
|
|
363
365
|
} else {
|
|
364
|
-
this.#
|
|
365
|
-
const last = [...this.#focusables].at(-1);
|
|
366
|
+
const last = this.#getFocusables().at(-1);
|
|
366
367
|
last && focusElement(last);
|
|
367
368
|
}
|
|
368
369
|
}
|
|
@@ -378,53 +379,22 @@ var Portal = class {
|
|
|
378
379
|
if (!this.#host.contains(active)) {
|
|
379
380
|
return;
|
|
380
381
|
}
|
|
381
|
-
this.#
|
|
382
|
-
const focusables = [...this.#focusables];
|
|
383
|
-
if (!focusables.length) {
|
|
382
|
+
if (!this.#getFocusables().length) {
|
|
384
383
|
event.preventDefault();
|
|
385
384
|
(event.shiftKey ? this.#entranceSentinel : this.#exitSentinel).focus();
|
|
386
|
-
return;
|
|
387
385
|
}
|
|
388
|
-
const index =
|
|
386
|
+
const index = this.#getFocusables().indexOf(active);
|
|
389
387
|
if (index === -1) {
|
|
390
388
|
return;
|
|
391
389
|
}
|
|
392
390
|
event.preventDefault();
|
|
393
|
-
const focusable =
|
|
391
|
+
const focusable = this.#getFocusables()[index + (event.shiftKey ? -1 : 1)];
|
|
394
392
|
if (focusable) {
|
|
395
393
|
focusElement(focusable);
|
|
396
394
|
} else {
|
|
397
395
|
(event.shiftKey ? this.#entranceSentinel : this.#exitSentinel).focus();
|
|
398
396
|
}
|
|
399
397
|
};
|
|
400
|
-
#update() {
|
|
401
|
-
const current = new Set(
|
|
402
|
-
getFocusables(this.#host, { composed: true })
|
|
403
|
-
);
|
|
404
|
-
this.#focusables.forEach((focusable) => {
|
|
405
|
-
if (current.has(focusable)) {
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
if (focusable.isConnected) {
|
|
409
|
-
const index = this.#tabIndexes.get(focusable);
|
|
410
|
-
if (index == null) {
|
|
411
|
-
focusable.removeAttribute("tabindex");
|
|
412
|
-
} else {
|
|
413
|
-
focusable.setAttribute("tabindex", index);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
this.#focusables.delete(focusable);
|
|
417
|
-
this.#tabIndexes.delete(focusable);
|
|
418
|
-
});
|
|
419
|
-
const active = getActiveElement2();
|
|
420
|
-
current.forEach((c) => {
|
|
421
|
-
if (!this.#tabIndexes.has(c)) {
|
|
422
|
-
this.#tabIndexes.set(c, c.getAttribute("tabindex"));
|
|
423
|
-
}
|
|
424
|
-
c.setAttribute("tabindex", c === active ? "0" : "-1");
|
|
425
|
-
this.#focusables.add(c);
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
398
|
#createSentinel() {
|
|
429
399
|
const sentinel = document.createElement("span");
|
|
430
400
|
sentinel.setAttribute("aria-hidden", "true");
|
|
@@ -433,6 +403,12 @@ var Portal = class {
|
|
|
433
403
|
sentinel.style.cssText += VISUALLY_HIDDEN_CSS;
|
|
434
404
|
return sentinel;
|
|
435
405
|
}
|
|
406
|
+
#getFocusables() {
|
|
407
|
+
return getFocusables(this.#host, {
|
|
408
|
+
composed: true,
|
|
409
|
+
include: (element) => this.#tabIndexes.has(element)
|
|
410
|
+
});
|
|
411
|
+
}
|
|
436
412
|
#moveFocus(direction) {
|
|
437
413
|
const options = {
|
|
438
414
|
anchor: direction === "previous" ? this.#entranceSentinel : this.#exitSentinel,
|
|
@@ -467,7 +443,7 @@ function getActiveElement2() {
|
|
|
467
443
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
468
444
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
469
445
|
*
|
|
470
|
-
* @version 1.1.
|
|
446
|
+
* @version 1.1.1
|
|
471
447
|
* @author Yusuke Kamiyamane
|
|
472
448
|
* @license MIT
|
|
473
449
|
* @copyright Copyright (c) Yusuke Kamiyamane
|