power-focusable 4.1.8 → 4.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
@@ -39,6 +39,7 @@ interface PowerFocusableOptions {
39
39
  composed?: boolean; // default: false
40
40
  filter?: (element: Element) => boolean;
41
41
  include?: (element: Element) => boolean;
42
+ skipVisibilityCheck?: boolean; // default: false
42
43
  wrap?: boolean; // default: false
43
44
  }
44
45
  ```
@@ -71,6 +72,12 @@ The function should return `true` to include the element, or `false` to ignore i
71
72
 
72
73
  Used by `getFocusables`, `getNextFocusable`, `getPreviousFocusable`, and `hasFocusable`.
73
74
 
75
+ ### `skipVisibilityCheck`
76
+
77
+ If `true`, skips `checkVisibility()` when determining focusability. Useful for initializing.
78
+
79
+ Used by `getFocusables`, `getNextFocusable`, `getPreviousFocusable`, `hasFocusable`, and `isFocusable`.
80
+
74
81
  ### `wrap`
75
82
 
76
83
  If `true`, wraps around to the first or last element when reaching the end.
package/dist/index.cjs CHANGED
@@ -44,7 +44,12 @@ function getFocusables(container = document.body, options = {}) {
44
44
  console.warn("Invalid container element. Fallback: <body> element.");
45
45
  container = document.body;
46
46
  }
47
- let { composed = false, filter, include } = options;
47
+ let {
48
+ composed = false,
49
+ filter,
50
+ include,
51
+ skipVisibilityCheck = false
52
+ } = options;
48
53
  if (typeof composed !== "boolean") {
49
54
  console.warn("Invalid composed option. Fallback: false.");
50
55
  composed = false;
@@ -61,11 +66,15 @@ function getFocusables(container = document.body, options = {}) {
61
66
  );
62
67
  include = void 0;
63
68
  }
69
+ if (typeof skipVisibilityCheck !== "boolean") {
70
+ console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
71
+ skipVisibilityCheck = false;
72
+ }
64
73
  const elements = [];
65
74
  if (composed || include) {
66
75
  let traverse2 = function(node) {
67
76
  if (node instanceof Element) {
68
- if (isFocusable(node) || include?.(node)) {
77
+ if (isFocusable(node, { skipVisibilityCheck }) || include?.(node)) {
69
78
  elements[elements.length] = node;
70
79
  }
71
80
  }
@@ -86,7 +95,7 @@ function getFocusables(container = document.body, options = {}) {
86
95
  if (!(candidate instanceof Element)) {
87
96
  continue;
88
97
  }
89
- if (isFocusable(candidate)) {
98
+ if (isFocusable(candidate, { skipVisibilityCheck })) {
90
99
  elements[elements.length] = candidate;
91
100
  }
92
101
  }
@@ -132,11 +141,16 @@ function inertOutside(element) {
132
141
  });
133
142
  };
134
143
  }
135
- function isFocusable(element) {
144
+ function isFocusable(element, options = {}) {
136
145
  if (!(element instanceof Element)) {
137
146
  console.warn("Invalid element");
138
147
  return false;
139
148
  }
149
+ let { skipVisibilityCheck = false } = options;
150
+ if (typeof skipVisibilityCheck !== "boolean") {
151
+ console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
152
+ skipVisibilityCheck = false;
153
+ }
140
154
  if (element.hasAttribute("hidden") || isInert(element)) {
141
155
  return false;
142
156
  }
@@ -149,7 +163,7 @@ function isFocusable(element) {
149
163
  if (isDisabledDeep(element)) {
150
164
  return false;
151
165
  }
152
- if (!element.checkVisibility({
166
+ if (!skipVisibilityCheck && !element.checkVisibility({
153
167
  contentVisibilityAuto: true,
154
168
  opacityProperty: true,
155
169
  visibilityProperty: true
@@ -168,6 +182,7 @@ function getRelativeFocusable(container, offset, options) {
168
182
  composed = false,
169
183
  filter,
170
184
  include,
185
+ skipVisibilityCheck = false,
171
186
  wrap = false
172
187
  } = options;
173
188
  if (!(anchor instanceof Element)) {
@@ -200,11 +215,20 @@ function getRelativeFocusable(container, offset, options) {
200
215
  );
201
216
  include = void 0;
202
217
  }
218
+ if (typeof skipVisibilityCheck !== "boolean") {
219
+ console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
220
+ skipVisibilityCheck = false;
221
+ }
203
222
  if (typeof wrap !== "boolean") {
204
223
  console.warn("Invalid wrap option. Fallback: false.");
205
224
  wrap = false;
206
225
  }
207
- const focusables = getFocusables(container, { composed, filter, include });
226
+ const focusables = getFocusables(container, {
227
+ composed,
228
+ filter,
229
+ include,
230
+ skipVisibilityCheck
231
+ });
208
232
  const { length } = focusables;
209
233
  if (!length) {
210
234
  return null;
@@ -435,7 +459,7 @@ function isUngroupedRadio(element) {
435
459
  * High-precision focus management utility with full composed tree support.
436
460
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
437
461
  *
438
- * @version 4.1.8
462
+ * @version 4.2.1
439
463
  * @author Yusuke Kamiyamane
440
464
  * @license MIT
441
465
  * @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.8
6
+ * @version 4.2.1
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -14,6 +14,7 @@ interface PowerFocusableOptions {
14
14
  readonly composed?: boolean;
15
15
  readonly filter?: ((element: Element) => boolean) | undefined;
16
16
  readonly include?: ((element: Element) => boolean) | undefined;
17
+ readonly skipVisibilityCheck?: boolean;
17
18
  readonly wrap?: boolean;
18
19
  }
19
20
  declare function createFocusTrap(container?: Element): () => void;
@@ -22,6 +23,8 @@ declare function getNextFocusable(container?: Element, options?: PowerFocusableO
22
23
  declare function getPreviousFocusable(container?: Element, options?: PowerFocusableOptions): Element | null;
23
24
  declare function hasFocusable(container?: Element, options?: Omit<PowerFocusableOptions, 'anchor' | 'wrap'>): boolean;
24
25
  declare function inertOutside(element: Element): () => void;
25
- declare function isFocusable(element: Element): boolean;
26
+ declare function isFocusable(element: Element, options?: {
27
+ skipVisibilityCheck?: boolean;
28
+ }): boolean;
26
29
 
27
30
  export { type PowerFocusableOptions, createFocusTrap, getFocusables, getNextFocusable, getPreviousFocusable, hasFocusable, inertOutside, isFocusable };
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.8
6
+ * @version 4.2.1
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -14,6 +14,7 @@ interface PowerFocusableOptions {
14
14
  readonly composed?: boolean;
15
15
  readonly filter?: ((element: Element) => boolean) | undefined;
16
16
  readonly include?: ((element: Element) => boolean) | undefined;
17
+ readonly skipVisibilityCheck?: boolean;
17
18
  readonly wrap?: boolean;
18
19
  }
19
20
  declare function createFocusTrap(container?: Element): () => void;
@@ -22,6 +23,8 @@ declare function getNextFocusable(container?: Element, options?: PowerFocusableO
22
23
  declare function getPreviousFocusable(container?: Element, options?: PowerFocusableOptions): Element | null;
23
24
  declare function hasFocusable(container?: Element, options?: Omit<PowerFocusableOptions, 'anchor' | 'wrap'>): boolean;
24
25
  declare function inertOutside(element: Element): () => void;
25
- declare function isFocusable(element: Element): boolean;
26
+ declare function isFocusable(element: Element, options?: {
27
+ skipVisibilityCheck?: boolean;
28
+ }): boolean;
26
29
 
27
30
  export { type PowerFocusableOptions, createFocusTrap, getFocusables, getNextFocusable, getPreviousFocusable, hasFocusable, inertOutside, isFocusable };
package/dist/index.js CHANGED
@@ -42,7 +42,12 @@ function getFocusables(container = document.body, options = {}) {
42
42
  console.warn("Invalid container element. Fallback: <body> element.");
43
43
  container = document.body;
44
44
  }
45
- let { composed = false, filter, include } = options;
45
+ let {
46
+ composed = false,
47
+ filter,
48
+ include,
49
+ skipVisibilityCheck = false
50
+ } = options;
46
51
  if (typeof composed !== "boolean") {
47
52
  console.warn("Invalid composed option. Fallback: false.");
48
53
  composed = false;
@@ -59,11 +64,15 @@ function getFocusables(container = document.body, options = {}) {
59
64
  );
60
65
  include = void 0;
61
66
  }
67
+ if (typeof skipVisibilityCheck !== "boolean") {
68
+ console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
69
+ skipVisibilityCheck = false;
70
+ }
62
71
  const elements = [];
63
72
  if (composed || include) {
64
73
  let traverse2 = function(node) {
65
74
  if (node instanceof Element) {
66
- if (isFocusable(node) || include?.(node)) {
75
+ if (isFocusable(node, { skipVisibilityCheck }) || include?.(node)) {
67
76
  elements[elements.length] = node;
68
77
  }
69
78
  }
@@ -84,7 +93,7 @@ function getFocusables(container = document.body, options = {}) {
84
93
  if (!(candidate instanceof Element)) {
85
94
  continue;
86
95
  }
87
- if (isFocusable(candidate)) {
96
+ if (isFocusable(candidate, { skipVisibilityCheck })) {
88
97
  elements[elements.length] = candidate;
89
98
  }
90
99
  }
@@ -130,11 +139,16 @@ function inertOutside(element) {
130
139
  });
131
140
  };
132
141
  }
133
- function isFocusable(element) {
142
+ function isFocusable(element, options = {}) {
134
143
  if (!(element instanceof Element)) {
135
144
  console.warn("Invalid element");
136
145
  return false;
137
146
  }
147
+ let { skipVisibilityCheck = false } = options;
148
+ if (typeof skipVisibilityCheck !== "boolean") {
149
+ console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
150
+ skipVisibilityCheck = false;
151
+ }
138
152
  if (element.hasAttribute("hidden") || isInert(element)) {
139
153
  return false;
140
154
  }
@@ -147,7 +161,7 @@ function isFocusable(element) {
147
161
  if (isDisabledDeep(element)) {
148
162
  return false;
149
163
  }
150
- if (!element.checkVisibility({
164
+ if (!skipVisibilityCheck && !element.checkVisibility({
151
165
  contentVisibilityAuto: true,
152
166
  opacityProperty: true,
153
167
  visibilityProperty: true
@@ -166,6 +180,7 @@ function getRelativeFocusable(container, offset, options) {
166
180
  composed = false,
167
181
  filter,
168
182
  include,
183
+ skipVisibilityCheck = false,
169
184
  wrap = false
170
185
  } = options;
171
186
  if (!(anchor instanceof Element)) {
@@ -198,11 +213,20 @@ function getRelativeFocusable(container, offset, options) {
198
213
  );
199
214
  include = void 0;
200
215
  }
216
+ if (typeof skipVisibilityCheck !== "boolean") {
217
+ console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
218
+ skipVisibilityCheck = false;
219
+ }
201
220
  if (typeof wrap !== "boolean") {
202
221
  console.warn("Invalid wrap option. Fallback: false.");
203
222
  wrap = false;
204
223
  }
205
- const focusables = getFocusables(container, { composed, filter, include });
224
+ const focusables = getFocusables(container, {
225
+ composed,
226
+ filter,
227
+ include,
228
+ skipVisibilityCheck
229
+ });
206
230
  const { length } = focusables;
207
231
  if (!length) {
208
232
  return null;
@@ -433,7 +457,7 @@ function isUngroupedRadio(element) {
433
457
  * High-precision focus management utility with full composed tree support.
434
458
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
435
459
  *
436
- * @version 4.1.8
460
+ * @version 4.2.1
437
461
  * @author Yusuke Kamiyamane
438
462
  * @license MIT
439
463
  * @copyright Copyright (c) Yusuke Kamiyamane
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "power-focusable",
3
- "version": "4.1.8",
3
+ "version": "4.2.1",
4
4
  "description": "High-precision focus management utility with full composed tree support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",