@y14e/portal 1.2.30 → 1.2.32

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/README.md CHANGED
@@ -13,11 +13,11 @@ npm i @y14e/portal
13
13
  import { createPortal } from '@y14e/portal';
14
14
 
15
15
  // CDNs
16
- import { createPortal } from 'https://esm.sh/@y14e/portal@1.2.30';
16
+ import { createPortal } from 'https://esm.sh/@y14e/portal@1.2.32';
17
17
  // or
18
- import { createPortal } from 'https://cdn.jsdelivr.net/npm/@y14e/portal@1.2.30/+esm';
18
+ import { createPortal } from 'https://cdn.jsdelivr.net/npm/@y14e/portal@1.2.32/+esm';
19
19
  // or
20
- import { createPortal } from 'https://esm.unpkg.com/@y14e/portal@1.2.30';
20
+ import { createPortal } from 'https://esm.unpkg.com/@y14e/portal@1.2.32';
21
21
  ```
22
22
 
23
23
  ## 📦 APIs
@@ -2,8 +2,8 @@
2
2
 
3
3
  // node_modules/@y14e/attributes-utils/dist/index.js
4
4
  var snapshots = /* @__PURE__ */ new WeakMap();
5
- function restoreAttributes(elements) {
6
- for (const element of elements) {
5
+ function restoreAttributes(element_or_elements) {
6
+ for (const element of Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]) {
7
7
  const snapshot = snapshots.get(element);
8
8
  if (!snapshot) {
9
9
  continue;
@@ -14,8 +14,9 @@ function restoreAttributes(elements) {
14
14
  snapshots.delete(element);
15
15
  }
16
16
  }
17
- function saveAttributes(elements, attributes) {
18
- elements.forEach((element) => {
17
+ function saveAttributes(element_or_elements, attribute_or_attributes) {
18
+ const attributes = Array.isArray(attribute_or_attributes) ? attribute_or_attributes : [attribute_or_attributes];
19
+ (Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]).forEach((element) => {
19
20
  let snapshot = snapshots.get(element);
20
21
  if (!snapshot) {
21
22
  snapshot = /* @__PURE__ */ new Map();
@@ -29,6 +30,10 @@ function saveAttributes(elements, attributes) {
29
30
 
30
31
  // node_modules/power-focusable/dist/index.js
31
32
  var FOCUSABLE_SELECTOR = `:is(a[href], area[href], button, embed, iframe, input:not([type="hidden" i]), object, select, details > summary:first-of-type, textarea, [contenteditable]:not([contenteditable="false" i]), [controls], [tabindex]):not(:disabled, [hidden], [inert], [tabindex="-1"])`;
33
+ var FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX = FOCUSABLE_SELECTOR.replace(
34
+ /(,\s*)?\[tabindex="-1"\]/g,
35
+ ""
36
+ );
32
37
  function getFocusables(container = document.body, options = {}) {
33
38
  if (!(container instanceof Element)) {
34
39
  console.warn("Invalid container element. Fallback: <body> element.");
@@ -65,36 +70,43 @@ function getFocusables(container = document.body, options = {}) {
65
70
  console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
66
71
  skipVisibilityCheck = false;
67
72
  }
68
- const elements = [];
73
+ const candidates = [];
69
74
  if (composed || include) {
70
75
  let traverse2 = function(node) {
71
- if (!(node instanceof Element)) {
72
- return;
73
- }
74
- if (isFocusable(node, { skipNegativeTabIndexCheck, skipVisibilityCheck }) || include?.(node)) {
75
- elements[elements.length] = node;
76
+ if (isFocusable(node, {
77
+ skipNegativeTabIndexCheck,
78
+ skipVisibilityCheck
79
+ }) || include?.(node)) {
80
+ candidates[candidates.length] = node;
76
81
  }
77
- const children = getComposedChildren(node);
78
- for (let i = 0, l = children.length; i < l; i++) {
79
- const child = children[i];
82
+ const children2 = composed ? getComposedChildren(node) : getChildren(node);
83
+ for (let i = 0, l = children2.length; i < l; i++) {
84
+ const child = children2[i];
80
85
  child && traverse2(child);
81
86
  }
82
87
  };
83
- traverse2(container);
88
+ const children = composed ? getComposedChildren(container) : getChildren(container);
89
+ for (let i = 0, l = children.length; i < l; i++) {
90
+ const child = children[i];
91
+ child && traverse2(child);
92
+ }
84
93
  } else {
85
- const candidates = container.querySelectorAll(FOCUSABLE_SELECTOR);
86
- for (let i = 0, l = candidates.length; i < l; i++) {
87
- const candidate = candidates[i];
88
- if (candidate && isFocusable(candidate, {
94
+ const matches = container.querySelectorAll(
95
+ skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX : FOCUSABLE_SELECTOR
96
+ );
97
+ for (let i = 0, l = matches.length; i < l; i++) {
98
+ const matched = matches[i];
99
+ if (matched && isFocusable(matched, {
89
100
  skipNegativeTabIndexCheck,
90
101
  skipVisibilityCheck
91
102
  })) {
92
- elements[elements.length] = candidate;
103
+ candidates[candidates.length] = matched;
93
104
  }
94
105
  }
95
106
  }
96
- const unfiltered = normalizeRadioGroup(sortByTabIndex(elements));
97
- return filter ? unfiltered.filter(filter) : unfiltered;
107
+ return normalizeRadioGroup(
108
+ sortByTabIndex(filter ? candidates.filter(filter) : candidates)
109
+ );
98
110
  }
99
111
  function getNextFocusable(container = document.body, options = {}) {
100
112
  return getRelativeFocusable(container, 1, options);
@@ -123,7 +135,7 @@ function isFocusable(element, options = {}) {
123
135
  return false;
124
136
  }
125
137
  if (!element.matches(
126
- skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR.replace(/(,\s*)?\[tabindex="-1"\]/g, "") : FOCUSABLE_SELECTOR
138
+ skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX : FOCUSABLE_SELECTOR
127
139
  )) {
128
140
  return false;
129
141
  }
@@ -195,23 +207,23 @@ function getRelativeFocusable(container, offset, options) {
195
207
  console.warn("Invalid wrap option. Fallback: false.");
196
208
  wrap = false;
197
209
  }
198
- const settings = { composed, skipNegativeTabIndexCheck, skipVisibilityCheck };
199
- if (filter !== void 0) {
200
- Object.assign(settings, { filter });
201
- }
202
- if (include !== void 0) {
203
- Object.assign(settings, { include });
204
- }
210
+ const settings = {
211
+ composed,
212
+ filter,
213
+ include,
214
+ skipNegativeTabIndexCheck,
215
+ skipVisibilityCheck
216
+ };
205
217
  const focusables = getFocusables(container, settings);
206
218
  const { length } = focusables;
207
219
  if (!length) {
208
220
  return null;
209
221
  }
210
- const currentIndex = focusables.indexOf(anchor);
211
- if (currentIndex === -1) {
222
+ const anchorIndex = focusables.indexOf(anchor);
223
+ if (anchorIndex === -1) {
212
224
  return null;
213
225
  }
214
- const offsetIndex = currentIndex + offset;
226
+ const offsetIndex = anchorIndex + offset;
215
227
  if ((offsetIndex < 0 || offsetIndex >= length) && !wrap) {
216
228
  return null;
217
229
  }
@@ -259,22 +271,42 @@ function normalizeRadioGroup(elements) {
259
271
  if (!map) {
260
272
  map = /* @__PURE__ */ new Map();
261
273
  }
262
- const key = `${element.form?.id ?? "no-form"}::${element.name}`;
263
- const group = map.get(key) ?? map.set(key, []).get(key);
264
- if (group) {
265
- group[group.length] = element;
274
+ const root = element.getRootNode();
275
+ let value = map.get(root);
276
+ if (!value) {
277
+ value = /* @__PURE__ */ new Map();
278
+ map.set(root, value);
279
+ }
280
+ let v = value.get(element.form);
281
+ if (!v) {
282
+ v = /* @__PURE__ */ new Map();
283
+ value.set(element.form, v);
266
284
  }
285
+ let vv = v.get(element.name);
286
+ if (!vv) {
287
+ vv = [];
288
+ v.set(element.name, vv);
289
+ }
290
+ vv[vv.length] = element;
267
291
  }
268
292
  if (!map) {
269
293
  return elements;
270
294
  }
271
295
  const placeholder = /* @__PURE__ */ new Set();
272
- for (const group of map.values()) {
273
- placeholder.add(group.find((radio) => radio.checked) ?? group[0]);
296
+ for (const value of map.values()) {
297
+ for (const v of value.values()) {
298
+ for (const vv of v.values()) {
299
+ const radio = vv.find((element) => element.checked) ?? vv[0];
300
+ radio && placeholder.add(radio);
301
+ }
302
+ }
274
303
  }
275
- return elements.filter(
276
- (element) => isUngroupedRadio(element) ? placeholder.has(element) : true
277
- );
304
+ return elements.filter((element) => {
305
+ if (!(element instanceof HTMLInputElement)) {
306
+ return true;
307
+ }
308
+ return !isUngroupedRadio(element) || placeholder.has(element);
309
+ });
278
310
  }
279
311
  function sortByTabIndex(elements) {
280
312
  const ordered = [];
@@ -357,7 +389,7 @@ function isInert(element) {
357
389
  return "inert" in element && !!element.inert;
358
390
  }
359
391
  function isUngroupedRadio(element) {
360
- return element instanceof HTMLInputElement && element.type === "radio" && !!element.name;
392
+ return element.type === "radio" && !!element.name;
361
393
  }
362
394
 
363
395
  // src/index.ts
@@ -428,8 +460,7 @@ var Portal = class {
428
460
  this.#host.setAttribute("data-portaled", "");
429
461
  }
430
462
  #onFocus = (event) => {
431
- const sentinel = event.target;
432
- const previous = event.relatedTarget;
463
+ const { currentTarget: sentinel, relatedTarget: previous } = event;
433
464
  if (!(previous instanceof Element)) {
434
465
  return;
435
466
  }
@@ -484,14 +515,14 @@ var Portal = class {
484
515
  ]);
485
516
  for (const focusable of this.#focusables) {
486
517
  if (!current.has(focusable)) {
487
- focusable.isConnected && restoreAttributes([focusable]);
518
+ restoreAttributes(focusable);
488
519
  this.#focusables.delete(focusable);
489
520
  }
490
521
  }
491
522
  for (const focusable of current) {
492
523
  if (!this.#focusables.has(focusable)) {
493
524
  this.#focusables.add(focusable);
494
- saveAttributes([focusable], ["tabindex"]);
525
+ saveAttributes(focusable, "tabindex");
495
526
  focusable.setAttribute("tabindex", "-1");
496
527
  }
497
528
  }
@@ -537,7 +568,7 @@ function containsComposed2(container, element) {
537
568
  * Lightweight DOM portal (teleport) utility with fully focus management.
538
569
  * Designed for accessible dialogs, menus, overlays, popovers.
539
570
  *
540
- * @version 1.2.30
571
+ * @version 1.2.32
541
572
  * @author Yusuke Kamiyamane
542
573
  * @license MIT
543
574
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -549,7 +580,7 @@ function containsComposed2(container, element) {
549
580
  (**
550
581
  * Attributes Utils
551
582
  *
552
- * @version 1.1.3
583
+ * @version 1.1.4
553
584
  * @author Yusuke Kamiyamane
554
585
  * @license MIT
555
586
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -562,7 +593,7 @@ power-focusable/dist/index.js:
562
593
  * High-precision focus management utility with full composed tree support.
563
594
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
564
595
  *
565
- * @version 4.3.8
596
+ * @version 4.3.21
566
597
  * @author Yusuke Kamiyamane
567
598
  * @license MIT
568
599
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1,7 +1,7 @@
1
1
  // node_modules/@y14e/attributes-utils/dist/index.js
2
2
  var snapshots = /* @__PURE__ */ new WeakMap();
3
- function restoreAttributes(elements) {
4
- for (const element of elements) {
3
+ function restoreAttributes(element_or_elements) {
4
+ for (const element of Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]) {
5
5
  const snapshot = snapshots.get(element);
6
6
  if (!snapshot) {
7
7
  continue;
@@ -12,8 +12,9 @@ function restoreAttributes(elements) {
12
12
  snapshots.delete(element);
13
13
  }
14
14
  }
15
- function saveAttributes(elements, attributes) {
16
- elements.forEach((element) => {
15
+ function saveAttributes(element_or_elements, attribute_or_attributes) {
16
+ const attributes = Array.isArray(attribute_or_attributes) ? attribute_or_attributes : [attribute_or_attributes];
17
+ (Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]).forEach((element) => {
17
18
  let snapshot = snapshots.get(element);
18
19
  if (!snapshot) {
19
20
  snapshot = /* @__PURE__ */ new Map();
@@ -27,6 +28,10 @@ function saveAttributes(elements, attributes) {
27
28
 
28
29
  // node_modules/power-focusable/dist/index.js
29
30
  var FOCUSABLE_SELECTOR = `:is(a[href], area[href], button, embed, iframe, input:not([type="hidden" i]), object, select, details > summary:first-of-type, textarea, [contenteditable]:not([contenteditable="false" i]), [controls], [tabindex]):not(:disabled, [hidden], [inert], [tabindex="-1"])`;
31
+ var FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX = FOCUSABLE_SELECTOR.replace(
32
+ /(,\s*)?\[tabindex="-1"\]/g,
33
+ ""
34
+ );
30
35
  function getFocusables(container = document.body, options = {}) {
31
36
  if (!(container instanceof Element)) {
32
37
  console.warn("Invalid container element. Fallback: <body> element.");
@@ -63,36 +68,43 @@ function getFocusables(container = document.body, options = {}) {
63
68
  console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
64
69
  skipVisibilityCheck = false;
65
70
  }
66
- const elements = [];
71
+ const candidates = [];
67
72
  if (composed || include) {
68
73
  let traverse2 = function(node) {
69
- if (!(node instanceof Element)) {
70
- return;
71
- }
72
- if (isFocusable(node, { skipNegativeTabIndexCheck, skipVisibilityCheck }) || include?.(node)) {
73
- elements[elements.length] = node;
74
+ if (isFocusable(node, {
75
+ skipNegativeTabIndexCheck,
76
+ skipVisibilityCheck
77
+ }) || include?.(node)) {
78
+ candidates[candidates.length] = node;
74
79
  }
75
- const children = getComposedChildren(node);
76
- for (let i = 0, l = children.length; i < l; i++) {
77
- const child = children[i];
80
+ const children2 = composed ? getComposedChildren(node) : getChildren(node);
81
+ for (let i = 0, l = children2.length; i < l; i++) {
82
+ const child = children2[i];
78
83
  child && traverse2(child);
79
84
  }
80
85
  };
81
- traverse2(container);
86
+ const children = composed ? getComposedChildren(container) : getChildren(container);
87
+ for (let i = 0, l = children.length; i < l; i++) {
88
+ const child = children[i];
89
+ child && traverse2(child);
90
+ }
82
91
  } else {
83
- const candidates = container.querySelectorAll(FOCUSABLE_SELECTOR);
84
- for (let i = 0, l = candidates.length; i < l; i++) {
85
- const candidate = candidates[i];
86
- if (candidate && isFocusable(candidate, {
92
+ const matches = container.querySelectorAll(
93
+ skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX : FOCUSABLE_SELECTOR
94
+ );
95
+ for (let i = 0, l = matches.length; i < l; i++) {
96
+ const matched = matches[i];
97
+ if (matched && isFocusable(matched, {
87
98
  skipNegativeTabIndexCheck,
88
99
  skipVisibilityCheck
89
100
  })) {
90
- elements[elements.length] = candidate;
101
+ candidates[candidates.length] = matched;
91
102
  }
92
103
  }
93
104
  }
94
- const unfiltered = normalizeRadioGroup(sortByTabIndex(elements));
95
- return filter ? unfiltered.filter(filter) : unfiltered;
105
+ return normalizeRadioGroup(
106
+ sortByTabIndex(filter ? candidates.filter(filter) : candidates)
107
+ );
96
108
  }
97
109
  function getNextFocusable(container = document.body, options = {}) {
98
110
  return getRelativeFocusable(container, 1, options);
@@ -121,7 +133,7 @@ function isFocusable(element, options = {}) {
121
133
  return false;
122
134
  }
123
135
  if (!element.matches(
124
- skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR.replace(/(,\s*)?\[tabindex="-1"\]/g, "") : FOCUSABLE_SELECTOR
136
+ skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX : FOCUSABLE_SELECTOR
125
137
  )) {
126
138
  return false;
127
139
  }
@@ -193,23 +205,23 @@ function getRelativeFocusable(container, offset, options) {
193
205
  console.warn("Invalid wrap option. Fallback: false.");
194
206
  wrap = false;
195
207
  }
196
- const settings = { composed, skipNegativeTabIndexCheck, skipVisibilityCheck };
197
- if (filter !== void 0) {
198
- Object.assign(settings, { filter });
199
- }
200
- if (include !== void 0) {
201
- Object.assign(settings, { include });
202
- }
208
+ const settings = {
209
+ composed,
210
+ filter,
211
+ include,
212
+ skipNegativeTabIndexCheck,
213
+ skipVisibilityCheck
214
+ };
203
215
  const focusables = getFocusables(container, settings);
204
216
  const { length } = focusables;
205
217
  if (!length) {
206
218
  return null;
207
219
  }
208
- const currentIndex = focusables.indexOf(anchor);
209
- if (currentIndex === -1) {
220
+ const anchorIndex = focusables.indexOf(anchor);
221
+ if (anchorIndex === -1) {
210
222
  return null;
211
223
  }
212
- const offsetIndex = currentIndex + offset;
224
+ const offsetIndex = anchorIndex + offset;
213
225
  if ((offsetIndex < 0 || offsetIndex >= length) && !wrap) {
214
226
  return null;
215
227
  }
@@ -257,22 +269,42 @@ function normalizeRadioGroup(elements) {
257
269
  if (!map) {
258
270
  map = /* @__PURE__ */ new Map();
259
271
  }
260
- const key = `${element.form?.id ?? "no-form"}::${element.name}`;
261
- const group = map.get(key) ?? map.set(key, []).get(key);
262
- if (group) {
263
- group[group.length] = element;
272
+ const root = element.getRootNode();
273
+ let value = map.get(root);
274
+ if (!value) {
275
+ value = /* @__PURE__ */ new Map();
276
+ map.set(root, value);
277
+ }
278
+ let v = value.get(element.form);
279
+ if (!v) {
280
+ v = /* @__PURE__ */ new Map();
281
+ value.set(element.form, v);
264
282
  }
283
+ let vv = v.get(element.name);
284
+ if (!vv) {
285
+ vv = [];
286
+ v.set(element.name, vv);
287
+ }
288
+ vv[vv.length] = element;
265
289
  }
266
290
  if (!map) {
267
291
  return elements;
268
292
  }
269
293
  const placeholder = /* @__PURE__ */ new Set();
270
- for (const group of map.values()) {
271
- placeholder.add(group.find((radio) => radio.checked) ?? group[0]);
294
+ for (const value of map.values()) {
295
+ for (const v of value.values()) {
296
+ for (const vv of v.values()) {
297
+ const radio = vv.find((element) => element.checked) ?? vv[0];
298
+ radio && placeholder.add(radio);
299
+ }
300
+ }
272
301
  }
273
- return elements.filter(
274
- (element) => isUngroupedRadio(element) ? placeholder.has(element) : true
275
- );
302
+ return elements.filter((element) => {
303
+ if (!(element instanceof HTMLInputElement)) {
304
+ return true;
305
+ }
306
+ return !isUngroupedRadio(element) || placeholder.has(element);
307
+ });
276
308
  }
277
309
  function sortByTabIndex(elements) {
278
310
  const ordered = [];
@@ -355,7 +387,7 @@ function isInert(element) {
355
387
  return "inert" in element && !!element.inert;
356
388
  }
357
389
  function isUngroupedRadio(element) {
358
- return element instanceof HTMLInputElement && element.type === "radio" && !!element.name;
390
+ return element.type === "radio" && !!element.name;
359
391
  }
360
392
 
361
393
  // src/index.ts
@@ -426,8 +458,7 @@ var Portal = class {
426
458
  this.#host.setAttribute("data-portaled", "");
427
459
  }
428
460
  #onFocus = (event) => {
429
- const sentinel = event.target;
430
- const previous = event.relatedTarget;
461
+ const { currentTarget: sentinel, relatedTarget: previous } = event;
431
462
  if (!(previous instanceof Element)) {
432
463
  return;
433
464
  }
@@ -482,14 +513,14 @@ var Portal = class {
482
513
  ]);
483
514
  for (const focusable of this.#focusables) {
484
515
  if (!current.has(focusable)) {
485
- focusable.isConnected && restoreAttributes([focusable]);
516
+ restoreAttributes(focusable);
486
517
  this.#focusables.delete(focusable);
487
518
  }
488
519
  }
489
520
  for (const focusable of current) {
490
521
  if (!this.#focusables.has(focusable)) {
491
522
  this.#focusables.add(focusable);
492
- saveAttributes([focusable], ["tabindex"]);
523
+ saveAttributes(focusable, "tabindex");
493
524
  focusable.setAttribute("tabindex", "-1");
494
525
  }
495
526
  }
@@ -535,7 +566,7 @@ function containsComposed2(container, element) {
535
566
  * Lightweight DOM portal (teleport) utility with fully focus management.
536
567
  * Designed for accessible dialogs, menus, overlays, popovers.
537
568
  *
538
- * @version 1.2.30
569
+ * @version 1.2.32
539
570
  * @author Yusuke Kamiyamane
540
571
  * @license MIT
541
572
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -547,7 +578,7 @@ function containsComposed2(container, element) {
547
578
  (**
548
579
  * Attributes Utils
549
580
  *
550
- * @version 1.1.3
581
+ * @version 1.1.4
551
582
  * @author Yusuke Kamiyamane
552
583
  * @license MIT
553
584
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -560,7 +591,7 @@ power-focusable/dist/index.js:
560
591
  * High-precision focus management utility with full composed tree support.
561
592
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
562
593
  *
563
- * @version 4.3.8
594
+ * @version 4.3.21
564
595
  * @author Yusuke Kamiyamane
565
596
  * @license MIT
566
597
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.cjs CHANGED
@@ -71,8 +71,7 @@ var Portal = class {
71
71
  this.#host.setAttribute("data-portaled", "");
72
72
  }
73
73
  #onFocus = (event) => {
74
- const sentinel = event.target;
75
- const previous = event.relatedTarget;
74
+ const { currentTarget: sentinel, relatedTarget: previous } = event;
76
75
  if (!(previous instanceof Element)) {
77
76
  return;
78
77
  }
@@ -127,14 +126,14 @@ var Portal = class {
127
126
  ]);
128
127
  for (const focusable of this.#focusables) {
129
128
  if (!current.has(focusable)) {
130
- focusable.isConnected && attributesUtils.restoreAttributes([focusable]);
129
+ attributesUtils.restoreAttributes(focusable);
131
130
  this.#focusables.delete(focusable);
132
131
  }
133
132
  }
134
133
  for (const focusable of current) {
135
134
  if (!this.#focusables.has(focusable)) {
136
135
  this.#focusables.add(focusable);
137
- attributesUtils.saveAttributes([focusable], ["tabindex"]);
136
+ attributesUtils.saveAttributes(focusable, "tabindex");
138
137
  focusable.setAttribute("tabindex", "-1");
139
138
  }
140
139
  }
@@ -180,7 +179,7 @@ function containsComposed(container, element) {
180
179
  * Lightweight DOM portal (teleport) utility with fully focus management.
181
180
  * Designed for accessible dialogs, menus, overlays, popovers.
182
181
  *
183
- * @version 1.2.30
182
+ * @version 1.2.32
184
183
  * @author Yusuke Kamiyamane
185
184
  * @license MIT
186
185
  * @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.2.30
6
+ * @version 1.2.32
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.2.30
6
+ * @version 1.2.32
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.js CHANGED
@@ -69,8 +69,7 @@ var Portal = class {
69
69
  this.#host.setAttribute("data-portaled", "");
70
70
  }
71
71
  #onFocus = (event) => {
72
- const sentinel = event.target;
73
- const previous = event.relatedTarget;
72
+ const { currentTarget: sentinel, relatedTarget: previous } = event;
74
73
  if (!(previous instanceof Element)) {
75
74
  return;
76
75
  }
@@ -125,14 +124,14 @@ var Portal = class {
125
124
  ]);
126
125
  for (const focusable of this.#focusables) {
127
126
  if (!current.has(focusable)) {
128
- focusable.isConnected && restoreAttributes([focusable]);
127
+ restoreAttributes(focusable);
129
128
  this.#focusables.delete(focusable);
130
129
  }
131
130
  }
132
131
  for (const focusable of current) {
133
132
  if (!this.#focusables.has(focusable)) {
134
133
  this.#focusables.add(focusable);
135
- saveAttributes([focusable], ["tabindex"]);
134
+ saveAttributes(focusable, "tabindex");
136
135
  focusable.setAttribute("tabindex", "-1");
137
136
  }
138
137
  }
@@ -178,7 +177,7 @@ function containsComposed(container, element) {
178
177
  * Lightweight DOM portal (teleport) utility with fully focus management.
179
178
  * Designed for accessible dialogs, menus, overlays, popovers.
180
179
  *
181
- * @version 1.2.30
180
+ * @version 1.2.32
182
181
  * @author Yusuke Kamiyamane
183
182
  * @license MIT
184
183
  * @copyright Copyright (c) Yusuke Kamiyamane
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@y14e/portal",
3
- "version": "1.2.30",
3
+ "version": "1.2.32",
4
4
  "description": "Lightweight DOM portal (teleport) utility with fully focus management",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -55,7 +55,7 @@
55
55
  "node": ">=18"
56
56
  },
57
57
  "dependencies": {
58
- "@y14e/attributes-utils": "^1.1.3",
59
- "power-focusable": "^4.3.8"
58
+ "@y14e/attributes-utils": "^1.1.4",
59
+ "power-focusable": "^4.3.21"
60
60
  }
61
61
  }