@y14e/roving-tabindex 1.0.0 → 1.0.2

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 CHANGED
@@ -1,5 +1,36 @@
1
1
  'use strict';
2
2
 
3
+ // node_modules/@y14e/attributes-utils/dist/index.js
4
+ var snapshots = /* @__PURE__ */ new WeakMap();
5
+ function restoreAttributes(elements) {
6
+ elements.forEach((element) => {
7
+ const snapshot = snapshots.get(element);
8
+ if (!snapshot) {
9
+ return;
10
+ }
11
+ for (const [attribute, value] of snapshot.entries()) {
12
+ if (value === null) {
13
+ element.removeAttribute(attribute);
14
+ } else {
15
+ element.setAttribute(attribute, value);
16
+ }
17
+ }
18
+ snapshots.delete(element);
19
+ });
20
+ }
21
+ function saveAttributes(elements, attributes) {
22
+ elements.forEach((element) => {
23
+ let snapshot = snapshots.get(element);
24
+ if (!snapshot) {
25
+ snapshot = /* @__PURE__ */ new Map();
26
+ snapshots.set(element, snapshot);
27
+ }
28
+ attributes.forEach((attribute) => {
29
+ snapshot.set(attribute, element.getAttribute(attribute));
30
+ });
31
+ });
32
+ }
33
+
3
34
  // node_modules/power-focusable/dist/index.js
4
35
  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"])`;
5
36
  function getFocusables(container = document.body, options = {}) {
@@ -207,6 +238,19 @@ function createRovingTabIndex(container, options = {}) {
207
238
  if (!(container instanceof Element)) {
208
239
  throw new Error("Invalid container element");
209
240
  }
241
+ const { direction, selector, wrap = false } = options;
242
+ if (direction && !["horizontal", "vertical"].includes(direction)) {
243
+ console.warn("Invalid direction. Fallback: both (undefined).");
244
+ Object.assign(options, { direction: void 0 });
245
+ }
246
+ if (typeof selector !== "string") {
247
+ console.warn("Invalid selector. Fallback: all focusable elements.");
248
+ Object.assign(options, { selector: void 0 });
249
+ }
250
+ if (typeof wrap !== "boolean") {
251
+ console.warn("Invalid wrap. Fallback: false.");
252
+ Object.assign(options, { wrap: false });
253
+ }
210
254
  const roving = new RovingTabIndex(container, options);
211
255
  return () => roving.destroy();
212
256
  }
@@ -214,26 +258,12 @@ var RovingTabIndex = class {
214
258
  #container;
215
259
  #options;
216
260
  #focusables = /* @__PURE__ */ new Set();
217
- #tabIndexes = /* @__PURE__ */ new Map();
218
261
  #selectorFilter;
219
262
  #controller = null;
220
263
  #isDestroyed = false;
221
264
  constructor(container, options = {}) {
222
265
  this.#container = container;
223
266
  this.#options = options;
224
- const { direction, selector, wrap = false } = this.#options;
225
- if (direction && !["horizontal", "vertical"].includes(direction)) {
226
- console.warn("Invalid direction. Fallback: both (undefined).");
227
- Object.assign(this.#options, { direction: void 0 });
228
- }
229
- if (typeof selector !== "string") {
230
- console.warn("Invalid selector. Fallback: all focusable elements.");
231
- Object.assign(this.#options, { selector: void 0 });
232
- }
233
- if (typeof wrap !== "boolean") {
234
- console.warn("Invalid wrap. Fallback: false.");
235
- Object.assign(this.#options, { wrap: false });
236
- }
237
267
  this.#selectorFilter = this.#createSelectorFilter();
238
268
  this.#initialize();
239
269
  }
@@ -244,16 +274,8 @@ var RovingTabIndex = class {
244
274
  this.#isDestroyed = true;
245
275
  this.#controller?.abort();
246
276
  this.#controller = null;
247
- this.#focusables.forEach((focusable) => {
248
- const index = this.#tabIndexes.get(focusable);
249
- if (index == null) {
250
- focusable.removeAttribute("tabindex");
251
- } else {
252
- focusable.setAttribute("tabindex", index);
253
- }
254
- });
277
+ restoreAttributes([...this.#focusables]);
255
278
  this.#focusables.clear();
256
- this.#tabIndexes.clear();
257
279
  this.#container.removeAttribute("data-roving-tabindex-initialized");
258
280
  }
259
281
  #initialize() {
@@ -336,22 +358,16 @@ var RovingTabIndex = class {
336
358
  return;
337
359
  }
338
360
  if (focusable.isConnected) {
339
- const index = this.#tabIndexes.get(focusable);
340
- if (index == null) {
341
- focusable.removeAttribute("tabindex");
342
- } else {
343
- focusable.setAttribute("tabindex", index);
344
- }
361
+ restoreAttributes([focusable]);
345
362
  }
346
363
  this.#focusables.delete(focusable);
347
- this.#tabIndexes.delete(focusable);
348
364
  });
349
365
  current.forEach((c) => {
350
366
  if (this.#focusables.has(c)) {
351
367
  return;
352
368
  }
353
369
  this.#focusables.add(c);
354
- this.#tabIndexes.set(c, c.getAttribute("tabindex"));
370
+ saveAttributes([c], ["tabindex"]);
355
371
  c.setAttribute("tabindex", "-1");
356
372
  });
357
373
  if (active && this.#focusables.has(active)) {
@@ -366,7 +382,7 @@ var RovingTabIndex = class {
366
382
  }
367
383
  #createSelectorFilter() {
368
384
  const { selector } = this.#options;
369
- return (element) => !selector || element.matches(selector);
385
+ return (element) => !selector || [...this.#container.querySelectorAll(selector)].includes(element);
370
386
  }
371
387
  #getFocusables() {
372
388
  return getFocusables(this.#container, {
@@ -391,7 +407,7 @@ function getActiveElement() {
391
407
  * Lightweight roving tabindex utility with fully focus management.
392
408
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
393
409
  *
394
- * @version 1.0.0
410
+ * @version 1.0.2
395
411
  * @author Yusuke Kamiyamane
396
412
  * @license MIT
397
413
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -399,6 +415,17 @@ function getActiveElement() {
399
415
  */
400
416
  /*! Bundled license information:
401
417
 
418
+ @y14e/attributes-utils/dist/index.js:
419
+ (**
420
+ * Attributes Utils
421
+ *
422
+ * @version 1.0.0
423
+ * @author Yusuke Kamiyamane
424
+ * @license MIT
425
+ * @copyright Copyright (c) Yusuke Kamiyamane
426
+ * @see {@link https://github.com/y14e/attributes-utils}
427
+ *)
428
+
402
429
  power-focusable/dist/index.js:
403
430
  (**
404
431
  * Power Focusable
package/dist/index.d.cts CHANGED
@@ -3,7 +3,7 @@
3
3
  * Lightweight roving tabindex utility with fully focus management.
4
4
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
5
5
  *
6
- * @version 1.0.0
6
+ * @version 1.0.2
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 roving tabindex utility with fully focus management.
4
4
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
5
5
  *
6
- * @version 1.0.0
6
+ * @version 1.0.2
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.js CHANGED
@@ -1,3 +1,34 @@
1
+ // node_modules/@y14e/attributes-utils/dist/index.js
2
+ var snapshots = /* @__PURE__ */ new WeakMap();
3
+ function restoreAttributes(elements) {
4
+ elements.forEach((element) => {
5
+ const snapshot = snapshots.get(element);
6
+ if (!snapshot) {
7
+ return;
8
+ }
9
+ for (const [attribute, value] of snapshot.entries()) {
10
+ if (value === null) {
11
+ element.removeAttribute(attribute);
12
+ } else {
13
+ element.setAttribute(attribute, value);
14
+ }
15
+ }
16
+ snapshots.delete(element);
17
+ });
18
+ }
19
+ function saveAttributes(elements, attributes) {
20
+ elements.forEach((element) => {
21
+ let snapshot = snapshots.get(element);
22
+ if (!snapshot) {
23
+ snapshot = /* @__PURE__ */ new Map();
24
+ snapshots.set(element, snapshot);
25
+ }
26
+ attributes.forEach((attribute) => {
27
+ snapshot.set(attribute, element.getAttribute(attribute));
28
+ });
29
+ });
30
+ }
31
+
1
32
  // node_modules/power-focusable/dist/index.js
2
33
  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"])`;
3
34
  function getFocusables(container = document.body, options = {}) {
@@ -205,6 +236,19 @@ function createRovingTabIndex(container, options = {}) {
205
236
  if (!(container instanceof Element)) {
206
237
  throw new Error("Invalid container element");
207
238
  }
239
+ const { direction, selector, wrap = false } = options;
240
+ if (direction && !["horizontal", "vertical"].includes(direction)) {
241
+ console.warn("Invalid direction. Fallback: both (undefined).");
242
+ Object.assign(options, { direction: void 0 });
243
+ }
244
+ if (typeof selector !== "string") {
245
+ console.warn("Invalid selector. Fallback: all focusable elements.");
246
+ Object.assign(options, { selector: void 0 });
247
+ }
248
+ if (typeof wrap !== "boolean") {
249
+ console.warn("Invalid wrap. Fallback: false.");
250
+ Object.assign(options, { wrap: false });
251
+ }
208
252
  const roving = new RovingTabIndex(container, options);
209
253
  return () => roving.destroy();
210
254
  }
@@ -212,26 +256,12 @@ var RovingTabIndex = class {
212
256
  #container;
213
257
  #options;
214
258
  #focusables = /* @__PURE__ */ new Set();
215
- #tabIndexes = /* @__PURE__ */ new Map();
216
259
  #selectorFilter;
217
260
  #controller = null;
218
261
  #isDestroyed = false;
219
262
  constructor(container, options = {}) {
220
263
  this.#container = container;
221
264
  this.#options = options;
222
- const { direction, selector, wrap = false } = this.#options;
223
- if (direction && !["horizontal", "vertical"].includes(direction)) {
224
- console.warn("Invalid direction. Fallback: both (undefined).");
225
- Object.assign(this.#options, { direction: void 0 });
226
- }
227
- if (typeof selector !== "string") {
228
- console.warn("Invalid selector. Fallback: all focusable elements.");
229
- Object.assign(this.#options, { selector: void 0 });
230
- }
231
- if (typeof wrap !== "boolean") {
232
- console.warn("Invalid wrap. Fallback: false.");
233
- Object.assign(this.#options, { wrap: false });
234
- }
235
265
  this.#selectorFilter = this.#createSelectorFilter();
236
266
  this.#initialize();
237
267
  }
@@ -242,16 +272,8 @@ var RovingTabIndex = class {
242
272
  this.#isDestroyed = true;
243
273
  this.#controller?.abort();
244
274
  this.#controller = null;
245
- this.#focusables.forEach((focusable) => {
246
- const index = this.#tabIndexes.get(focusable);
247
- if (index == null) {
248
- focusable.removeAttribute("tabindex");
249
- } else {
250
- focusable.setAttribute("tabindex", index);
251
- }
252
- });
275
+ restoreAttributes([...this.#focusables]);
253
276
  this.#focusables.clear();
254
- this.#tabIndexes.clear();
255
277
  this.#container.removeAttribute("data-roving-tabindex-initialized");
256
278
  }
257
279
  #initialize() {
@@ -334,22 +356,16 @@ var RovingTabIndex = class {
334
356
  return;
335
357
  }
336
358
  if (focusable.isConnected) {
337
- const index = this.#tabIndexes.get(focusable);
338
- if (index == null) {
339
- focusable.removeAttribute("tabindex");
340
- } else {
341
- focusable.setAttribute("tabindex", index);
342
- }
359
+ restoreAttributes([focusable]);
343
360
  }
344
361
  this.#focusables.delete(focusable);
345
- this.#tabIndexes.delete(focusable);
346
362
  });
347
363
  current.forEach((c) => {
348
364
  if (this.#focusables.has(c)) {
349
365
  return;
350
366
  }
351
367
  this.#focusables.add(c);
352
- this.#tabIndexes.set(c, c.getAttribute("tabindex"));
368
+ saveAttributes([c], ["tabindex"]);
353
369
  c.setAttribute("tabindex", "-1");
354
370
  });
355
371
  if (active && this.#focusables.has(active)) {
@@ -364,7 +380,7 @@ var RovingTabIndex = class {
364
380
  }
365
381
  #createSelectorFilter() {
366
382
  const { selector } = this.#options;
367
- return (element) => !selector || element.matches(selector);
383
+ return (element) => !selector || [...this.#container.querySelectorAll(selector)].includes(element);
368
384
  }
369
385
  #getFocusables() {
370
386
  return getFocusables(this.#container, {
@@ -389,7 +405,7 @@ function getActiveElement() {
389
405
  * Lightweight roving tabindex utility with fully focus management.
390
406
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
391
407
  *
392
- * @version 1.0.0
408
+ * @version 1.0.2
393
409
  * @author Yusuke Kamiyamane
394
410
  * @license MIT
395
411
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -397,6 +413,17 @@ function getActiveElement() {
397
413
  */
398
414
  /*! Bundled license information:
399
415
 
416
+ @y14e/attributes-utils/dist/index.js:
417
+ (**
418
+ * Attributes Utils
419
+ *
420
+ * @version 1.0.0
421
+ * @author Yusuke Kamiyamane
422
+ * @license MIT
423
+ * @copyright Copyright (c) Yusuke Kamiyamane
424
+ * @see {@link https://github.com/y14e/attributes-utils}
425
+ *)
426
+
400
427
  power-focusable/dist/index.js:
401
428
  (**
402
429
  * Power Focusable
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@y14e/roving-tabindex",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Lightweight roving tabindex utility with fully focus management",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -48,6 +48,7 @@
48
48
  },
49
49
  "homepage": "https://github.com/y14e/roving-tabindex#readme",
50
50
  "devDependencies": {
51
+ "@y14e/attributes-utils": "^1.0.0",
51
52
  "bun-types": "latest",
52
53
  "power-focusable": "^4.1.5",
53
54
  "tsup": "^8.0.0",