power-focusable 4.1.1 → 4.1.3

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
@@ -35,10 +35,10 @@ import { ... } 'https://unpkg.com/power-focusable/dist/index.js';
35
35
 
36
36
  ```ts
37
37
  interface PowerFocusableOptions {
38
- anchor?: Element | null; // default: document.activeElement
38
+ anchor?: Element | null; // default: active element
39
39
  composed?: boolean; // default: false
40
- filter?: (element: Element) => boolean; // default: () => true
41
- include?: (element: Element) => boolean; // default: undefined
40
+ filter?: (element: Element) => boolean;
41
+ include?: (element: Element) => boolean;
42
42
  wrap?: boolean; // default: false
43
43
  }
44
44
  ```
package/dist/index.cjs CHANGED
@@ -44,9 +44,18 @@ function getFocusables(container = document.body, options = {}) {
44
44
  console.warn("Invalid container element. Fallback: <body> element.");
45
45
  container = document.body;
46
46
  }
47
- const { composed = false, filter = () => true, include } = options;
47
+ const { composed = false } = options;
48
+ let { filter, include } = options;
49
+ if (filter && typeof filter !== "function") {
50
+ console.warn("Invalid filter function. Fallback: undefined.");
51
+ filter = void 0;
52
+ }
53
+ if (include && typeof include !== "function") {
54
+ console.warn("Invalid include function. Fallback: undefined.");
55
+ include = void 0;
56
+ }
48
57
  const elements = [];
49
- if (composed || typeof include === "function") {
58
+ if (composed || include) {
50
59
  let traverse2 = function(node) {
51
60
  if (node instanceof Element) {
52
61
  if (isFocusable(node) || include?.(node)) {
@@ -75,7 +84,8 @@ function getFocusables(container = document.body, options = {}) {
75
84
  }
76
85
  }
77
86
  }
78
- return normalizeRadioGroup(sortByTabIndex(elements)).filter(filter);
87
+ const unfiltered = normalizeRadioGroup(sortByTabIndex(elements));
88
+ return filter ? unfiltered.filter(filter) : unfiltered;
79
89
  }
80
90
  function getNextFocusable(container = document.body, options = {}) {
81
91
  if (!(container instanceof Element)) {
@@ -154,22 +164,25 @@ function isFocusable(element) {
154
164
  return true;
155
165
  }
156
166
  function getRelativeFocusable(container, offset, options) {
157
- const {
158
- anchor = getActiveElement(),
159
- composed = false,
160
- filter = () => true,
161
- include,
162
- wrap = false
163
- } = options;
164
- const focusables = getFocusables(container, { composed, filter, include });
165
- const { length } = focusables;
166
- if (!length) {
167
- return null;
167
+ let anchor = options.anchor ?? getActiveElement();
168
+ const { composed = false, filter, include, wrap = false } = options;
169
+ if (!(anchor instanceof Element)) {
170
+ const active = getActiveElement();
171
+ if (active instanceof Element) {
172
+ console.warn("Invalid anchor element. Fallback: active element.");
173
+ anchor = active;
174
+ } else {
175
+ console.warn("Invalid anchor element");
176
+ return null;
177
+ }
168
178
  }
169
- if (!anchor || !containsComposed(container, anchor)) {
179
+ if (!containsComposed(container, anchor)) {
180
+ console.warn("Mismatch elements");
170
181
  return null;
171
182
  }
172
- if (!(anchor instanceof Element)) {
183
+ const focusables = getFocusables(container, { composed, filter, include });
184
+ const { length } = focusables;
185
+ if (!length) {
173
186
  return null;
174
187
  }
175
188
  const currentIndex = focusables.indexOf(anchor);
@@ -398,7 +411,7 @@ function isUngroupedRadio(element) {
398
411
  * High-precision focus management utility with full composed tree support.
399
412
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
400
413
  *
401
- * @version 4.1.1
414
+ * @version 4.1.3
402
415
  * @author Yusuke Kamiyamane
403
416
  * @license MIT
404
417
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.d.cts CHANGED
@@ -3,7 +3,7 @@
3
3
  * High-precision focus management utility with full composed tree support.
4
4
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
5
5
  *
6
- * @version 4.1.1
6
+ * @version 4.1.3
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -12,7 +12,7 @@
12
12
  interface PowerFocusableOptions {
13
13
  readonly anchor?: Element | null;
14
14
  readonly composed?: boolean;
15
- readonly filter?: (element: Element) => boolean;
15
+ readonly filter?: ((element: Element) => boolean) | undefined;
16
16
  readonly include?: ((element: Element) => boolean) | undefined;
17
17
  readonly wrap?: boolean;
18
18
  }
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * High-precision focus management utility with full composed tree support.
4
4
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
5
5
  *
6
- * @version 4.1.1
6
+ * @version 4.1.3
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -12,7 +12,7 @@
12
12
  interface PowerFocusableOptions {
13
13
  readonly anchor?: Element | null;
14
14
  readonly composed?: boolean;
15
- readonly filter?: (element: Element) => boolean;
15
+ readonly filter?: ((element: Element) => boolean) | undefined;
16
16
  readonly include?: ((element: Element) => boolean) | undefined;
17
17
  readonly wrap?: boolean;
18
18
  }
package/dist/index.js CHANGED
@@ -42,9 +42,18 @@ function getFocusables(container = document.body, options = {}) {
42
42
  console.warn("Invalid container element. Fallback: <body> element.");
43
43
  container = document.body;
44
44
  }
45
- const { composed = false, filter = () => true, include } = options;
45
+ const { composed = false } = options;
46
+ let { filter, include } = options;
47
+ if (filter && typeof filter !== "function") {
48
+ console.warn("Invalid filter function. Fallback: undefined.");
49
+ filter = void 0;
50
+ }
51
+ if (include && typeof include !== "function") {
52
+ console.warn("Invalid include function. Fallback: undefined.");
53
+ include = void 0;
54
+ }
46
55
  const elements = [];
47
- if (composed || typeof include === "function") {
56
+ if (composed || include) {
48
57
  let traverse2 = function(node) {
49
58
  if (node instanceof Element) {
50
59
  if (isFocusable(node) || include?.(node)) {
@@ -73,7 +82,8 @@ function getFocusables(container = document.body, options = {}) {
73
82
  }
74
83
  }
75
84
  }
76
- return normalizeRadioGroup(sortByTabIndex(elements)).filter(filter);
85
+ const unfiltered = normalizeRadioGroup(sortByTabIndex(elements));
86
+ return filter ? unfiltered.filter(filter) : unfiltered;
77
87
  }
78
88
  function getNextFocusable(container = document.body, options = {}) {
79
89
  if (!(container instanceof Element)) {
@@ -152,22 +162,25 @@ function isFocusable(element) {
152
162
  return true;
153
163
  }
154
164
  function getRelativeFocusable(container, offset, options) {
155
- const {
156
- anchor = getActiveElement(),
157
- composed = false,
158
- filter = () => true,
159
- include,
160
- wrap = false
161
- } = options;
162
- const focusables = getFocusables(container, { composed, filter, include });
163
- const { length } = focusables;
164
- if (!length) {
165
- return null;
165
+ let anchor = options.anchor ?? getActiveElement();
166
+ const { composed = false, filter, include, wrap = false } = options;
167
+ if (!(anchor instanceof Element)) {
168
+ const active = getActiveElement();
169
+ if (active instanceof Element) {
170
+ console.warn("Invalid anchor element. Fallback: active element.");
171
+ anchor = active;
172
+ } else {
173
+ console.warn("Invalid anchor element");
174
+ return null;
175
+ }
166
176
  }
167
- if (!anchor || !containsComposed(container, anchor)) {
177
+ if (!containsComposed(container, anchor)) {
178
+ console.warn("Mismatch elements");
168
179
  return null;
169
180
  }
170
- if (!(anchor instanceof Element)) {
181
+ const focusables = getFocusables(container, { composed, filter, include });
182
+ const { length } = focusables;
183
+ if (!length) {
171
184
  return null;
172
185
  }
173
186
  const currentIndex = focusables.indexOf(anchor);
@@ -396,7 +409,7 @@ function isUngroupedRadio(element) {
396
409
  * High-precision focus management utility with full composed tree support.
397
410
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
398
411
  *
399
- * @version 4.1.1
412
+ * @version 4.1.3
400
413
  * @author Yusuke Kamiyamane
401
414
  * @license MIT
402
415
  * @copyright Copyright (c) Yusuke Kamiyamane
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "power-focusable",
3
- "version": "4.1.1",
3
+ "version": "4.1.3",
4
4
  "description": "High-precision focus management utility with full composed tree support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",