@y14e/roving-tabindex 2.1.0 → 2.2.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/README.md CHANGED
@@ -10,14 +10,14 @@ npm i @y14e/roving-tabindex
10
10
 
11
11
  ```ts
12
12
  // npm
13
- import { createRovingTabIndex } from '@y14e/roving-tabindex@2.1.0';
13
+ import { createRovingTabIndex } from '@y14e/roving-tabindex@2.2.0';
14
14
 
15
15
  // CDNs
16
- import { createRovingTabIndex } from 'https://esm.sh/@y14e/roving-tabindex@2.1.0';
16
+ import { createRovingTabIndex } from 'https://esm.sh/@y14e/roving-tabindex@2.2.0';
17
17
  // or
18
- import { createRovingTabIndex } from 'https://cdn.jsdelivr.net/npm/@y14e/roving-tabindex@2.1.0/+esm';
18
+ import { createRovingTabIndex } from 'https://cdn.jsdelivr.net/npm/@y14e/roving-tabindex@2.2.0/+esm';
19
19
  // or
20
- import { createRovingTabIndex } from 'https://esm.unpkg.com/@y14e/roving-tabindex@2.1.0';
20
+ import { createRovingTabIndex } from 'https://esm.unpkg.com/@y14e/roving-tabindex@2.2.0';
21
21
  ```
22
22
 
23
23
  ## 📦 APIs
@@ -41,6 +41,8 @@ interface RovingTabIndexOptions {
41
41
  direction?: 'horizontal' | 'vertical'; // default: both (undefined)
42
42
  navigationOnly?: boolean; // default: false
43
43
  noMemory?: boolean; // default: false
44
+ noStart?: boolean; // default: false
45
+ noStopPropagation?: boolean; // default: false
44
46
  selector?: string;
45
47
  typeahead?: boolean; // default: false
46
48
  wrap?: boolean; // default: false
@@ -55,6 +57,14 @@ If `true`, enables keyboard navigation without modifying `tabindex`. Useful for
55
57
 
56
58
  If `true`, disables focus memory. Focus always starts from the first item.
57
59
 
60
+ ### `noStart`
61
+
62
+ If `true`, does not assign `tabindex="0"` to the first item during initialization.
63
+
64
+ ### `noStopPropagation`
65
+
66
+ If `true`, keyboard navigation will not call `stopPropagation()`.
67
+
58
68
  ### `typeahead`
59
69
 
60
70
  If `true`, enables character-based focus navigation. Typing a character moves focus to the next matching element.
package/dist/index.cjs CHANGED
@@ -300,6 +300,8 @@ function createRovingTabIndex(container, options = {}) {
300
300
  direction,
301
301
  navigationOnly = false,
302
302
  noMemory = false,
303
+ noStart = false,
304
+ noStopPropagation = false,
303
305
  selector,
304
306
  typeahead = false,
305
307
  wrap = false
@@ -316,6 +318,14 @@ function createRovingTabIndex(container, options = {}) {
316
318
  console.warn("Invalid noMemory option. Fallback: false.");
317
319
  noMemory = false;
318
320
  }
321
+ if (typeof noStart !== "boolean") {
322
+ console.warn("Invalid noStart option. Fallback: false.");
323
+ noStart = false;
324
+ }
325
+ if (typeof noStopPropagation !== "boolean") {
326
+ console.warn("Invalid noStopPropagation option. Fallback: false.");
327
+ noStopPropagation = false;
328
+ }
319
329
  if (typeof selector !== "undefined" && (typeof selector !== "string" || !selector.trim())) {
320
330
  console.warn(
321
331
  "Invalid selector. Fallback: all focusable elements (undefined)."
@@ -330,7 +340,14 @@ function createRovingTabIndex(container, options = {}) {
330
340
  console.warn("Invalid wrap option. Fallback: false.");
331
341
  wrap = false;
332
342
  }
333
- const settings = { navigationOnly, noMemory, typeahead, wrap };
343
+ const settings = {
344
+ navigationOnly,
345
+ noMemory,
346
+ noStart,
347
+ noStopPropagation,
348
+ typeahead,
349
+ wrap
350
+ };
334
351
  direction && Object.assign(settings, { direction });
335
352
  selector && Object.assign(settings, { selector });
336
353
  const roving = new RovingTabIndex(container, settings);
@@ -396,7 +413,7 @@ var RovingTabIndex = class {
396
413
  if (altKey || ctrlKey || metaKey || shiftKey) {
397
414
  return;
398
415
  }
399
- const { direction, typeahead, wrap } = this.#options;
416
+ const { direction, noStopPropagation, typeahead, wrap } = this.#options;
400
417
  const isBoth = !direction;
401
418
  const isHorizontal = direction === "horizontal";
402
419
  if (![
@@ -418,7 +435,7 @@ var RovingTabIndex = class {
418
435
  return;
419
436
  }
420
437
  event.preventDefault();
421
- event.stopPropagation();
438
+ !noStopPropagation && event.stopPropagation();
422
439
  const currentIndex = current.indexOf(active);
423
440
  let rawIndex;
424
441
  let newIndex = currentIndex;
@@ -464,7 +481,7 @@ var RovingTabIndex = class {
464
481
  index >= 0 && focusables.splice(index, 1);
465
482
  });
466
483
  }
467
- const { navigationOnly } = this.#options;
484
+ const { navigationOnly, noStart, typeahead } = this.#options;
468
485
  for (const focusable of current) {
469
486
  if (this.#focusables.has(focusable)) {
470
487
  continue;
@@ -474,7 +491,7 @@ var RovingTabIndex = class {
474
491
  saveAttributes([focusable], ["tabindex"]);
475
492
  focusable.setAttribute("tabindex", "-1");
476
493
  }
477
- if (!this.#options.typeahead) {
494
+ if (!typeahead) {
478
495
  continue;
479
496
  }
480
497
  const value = focusable.ariaKeyShortcuts?.trim();
@@ -505,7 +522,7 @@ var RovingTabIndex = class {
505
522
  return;
506
523
  }
507
524
  [...this.#focusables].forEach((focusable, i) => {
508
- focusable.setAttribute("tabindex", i ? "-1" : "0");
525
+ focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
509
526
  });
510
527
  }
511
528
  #createSelectorFilter() {
@@ -536,7 +553,7 @@ function getActiveElement() {
536
553
  * Lightweight roving tabindex utility with fully focus management.
537
554
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
538
555
  *
539
- * @version 2.1.0
556
+ * @version 2.2.1
540
557
  * @author Yusuke Kamiyamane
541
558
  * @license MIT
542
559
  * @copyright Copyright (c) Yusuke Kamiyamane
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 2.1.0
6
+ * @version 2.2.1
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -13,6 +13,8 @@ interface RovingTabIndexOptions {
13
13
  readonly direction?: 'horizontal' | 'vertical';
14
14
  readonly navigationOnly?: boolean;
15
15
  readonly noMemory?: boolean;
16
+ readonly noStart?: boolean;
17
+ readonly noStopPropagation?: boolean;
16
18
  readonly selector?: string;
17
19
  readonly typeahead?: boolean;
18
20
  readonly wrap?: boolean;
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 2.1.0
6
+ * @version 2.2.1
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -13,6 +13,8 @@ interface RovingTabIndexOptions {
13
13
  readonly direction?: 'horizontal' | 'vertical';
14
14
  readonly navigationOnly?: boolean;
15
15
  readonly noMemory?: boolean;
16
+ readonly noStart?: boolean;
17
+ readonly noStopPropagation?: boolean;
16
18
  readonly selector?: string;
17
19
  readonly typeahead?: boolean;
18
20
  readonly wrap?: boolean;
package/dist/index.js CHANGED
@@ -298,6 +298,8 @@ function createRovingTabIndex(container, options = {}) {
298
298
  direction,
299
299
  navigationOnly = false,
300
300
  noMemory = false,
301
+ noStart = false,
302
+ noStopPropagation = false,
301
303
  selector,
302
304
  typeahead = false,
303
305
  wrap = false
@@ -314,6 +316,14 @@ function createRovingTabIndex(container, options = {}) {
314
316
  console.warn("Invalid noMemory option. Fallback: false.");
315
317
  noMemory = false;
316
318
  }
319
+ if (typeof noStart !== "boolean") {
320
+ console.warn("Invalid noStart option. Fallback: false.");
321
+ noStart = false;
322
+ }
323
+ if (typeof noStopPropagation !== "boolean") {
324
+ console.warn("Invalid noStopPropagation option. Fallback: false.");
325
+ noStopPropagation = false;
326
+ }
317
327
  if (typeof selector !== "undefined" && (typeof selector !== "string" || !selector.trim())) {
318
328
  console.warn(
319
329
  "Invalid selector. Fallback: all focusable elements (undefined)."
@@ -328,7 +338,14 @@ function createRovingTabIndex(container, options = {}) {
328
338
  console.warn("Invalid wrap option. Fallback: false.");
329
339
  wrap = false;
330
340
  }
331
- const settings = { navigationOnly, noMemory, typeahead, wrap };
341
+ const settings = {
342
+ navigationOnly,
343
+ noMemory,
344
+ noStart,
345
+ noStopPropagation,
346
+ typeahead,
347
+ wrap
348
+ };
332
349
  direction && Object.assign(settings, { direction });
333
350
  selector && Object.assign(settings, { selector });
334
351
  const roving = new RovingTabIndex(container, settings);
@@ -394,7 +411,7 @@ var RovingTabIndex = class {
394
411
  if (altKey || ctrlKey || metaKey || shiftKey) {
395
412
  return;
396
413
  }
397
- const { direction, typeahead, wrap } = this.#options;
414
+ const { direction, noStopPropagation, typeahead, wrap } = this.#options;
398
415
  const isBoth = !direction;
399
416
  const isHorizontal = direction === "horizontal";
400
417
  if (![
@@ -416,7 +433,7 @@ var RovingTabIndex = class {
416
433
  return;
417
434
  }
418
435
  event.preventDefault();
419
- event.stopPropagation();
436
+ !noStopPropagation && event.stopPropagation();
420
437
  const currentIndex = current.indexOf(active);
421
438
  let rawIndex;
422
439
  let newIndex = currentIndex;
@@ -462,7 +479,7 @@ var RovingTabIndex = class {
462
479
  index >= 0 && focusables.splice(index, 1);
463
480
  });
464
481
  }
465
- const { navigationOnly } = this.#options;
482
+ const { navigationOnly, noStart, typeahead } = this.#options;
466
483
  for (const focusable of current) {
467
484
  if (this.#focusables.has(focusable)) {
468
485
  continue;
@@ -472,7 +489,7 @@ var RovingTabIndex = class {
472
489
  saveAttributes([focusable], ["tabindex"]);
473
490
  focusable.setAttribute("tabindex", "-1");
474
491
  }
475
- if (!this.#options.typeahead) {
492
+ if (!typeahead) {
476
493
  continue;
477
494
  }
478
495
  const value = focusable.ariaKeyShortcuts?.trim();
@@ -503,7 +520,7 @@ var RovingTabIndex = class {
503
520
  return;
504
521
  }
505
522
  [...this.#focusables].forEach((focusable, i) => {
506
- focusable.setAttribute("tabindex", i ? "-1" : "0");
523
+ focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
507
524
  });
508
525
  }
509
526
  #createSelectorFilter() {
@@ -534,7 +551,7 @@ function getActiveElement() {
534
551
  * Lightweight roving tabindex utility with fully focus management.
535
552
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
536
553
  *
537
- * @version 2.1.0
554
+ * @version 2.2.1
538
555
  * @author Yusuke Kamiyamane
539
556
  * @license MIT
540
557
  * @copyright Copyright (c) Yusuke Kamiyamane
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@y14e/roving-tabindex",
3
- "version": "2.1.0",
3
+ "version": "2.2.1",
4
4
  "description": "Lightweight roving tabindex utility with fully focus management",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",