@momentum-design/components 0.134.16 → 0.134.17
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/browser/index.js +303 -303
- package/dist/browser/index.js.map +3 -3
- package/dist/components/spatialnavigationprovider/spatialnavigationprovider.component.d.ts +28 -29
- package/dist/components/spatialnavigationprovider/spatialnavigationprovider.component.js +52 -42
- package/dist/components/spatialnavigationprovider/spatialnavigationprovider.constants.d.ts +11 -0
- package/dist/components/spatialnavigationprovider/spatialnavigationprovider.constants.js +11 -0
- package/dist/components/spatialnavigationprovider/spatialnavigationprovider.utils.js +6 -1
- package/dist/custom-elements.json +3 -3
- package/dist/react/spatialnavigationprovider/index.d.ts +26 -26
- package/dist/react/spatialnavigationprovider/index.js +26 -26
- package/dist/utils/dom.d.ts +9 -2
- package/dist/utils/dom.js +24 -41
- package/package.json +1 -1
|
@@ -16,30 +16,30 @@ import type { Events } from '../../components/spatialnavigationprovider/spatialn
|
|
|
16
16
|
*
|
|
17
17
|
* ### Steps
|
|
18
18
|
*
|
|
19
|
-
* Spatial navigation goes
|
|
19
|
+
* Spatial navigation goes through the following steps after each keydown:
|
|
20
20
|
*
|
|
21
21
|
* 1. Handle `keydown` in the capture phase.
|
|
22
|
-
* - When active element has `data-spatial-{direction}` attribute then prevent all component navigation and call the
|
|
23
|
-
* provider own `keydown` handler (see step 3).
|
|
24
|
-
* - When active element's parent is scrollable and it is not fully visible in the given direction and it does not
|
|
25
|
-
* have `data-spatial-noscroll` attribute, prevent all navigation and scroll in the
|
|
22
|
+
* - When the active element has a `data-spatial-{direction}` attribute, then prevent all component navigation and call the
|
|
23
|
+
* provider's own `keydown` handler (see step 3).
|
|
24
|
+
* - When the active element's parent is scrollable and it is not fully visible in the given direction, and it does not
|
|
25
|
+
* have a `data-spatial-noscroll` attribute, prevent all navigation and scroll in the given direction half-size of the
|
|
26
26
|
* scroll view.
|
|
27
27
|
* 2. Component own `keydown` handler executed (bubble phase) (e.g., list moves focus internally) it it was not
|
|
28
28
|
* prevented.
|
|
29
29
|
* 3. Spatial Navigation Provider's `keydown` handler executed (bubble phase)
|
|
30
|
-
* - If key event was not prevented in step 1. emit `navbeforeprocess` to check if any component want to handle
|
|
30
|
+
* - If a key event was not prevented in step 1. emit `navbeforeprocess` to check if any component want to handle
|
|
31
31
|
* the key event itself. If `navbeforeprocess` event is prevented, stop here.
|
|
32
|
-
* - If the component did not handle `keydown`, it
|
|
33
|
-
* - if the active element has `data-spatial-{direction}` attribute, it will try to focus the element with the id.
|
|
32
|
+
* - If the component did not handle `keydown`, it calculates the next focusable item
|
|
33
|
+
* - if the active element has a `data-spatial-{direction}` attribute, it will try to focus the element with the id.
|
|
34
34
|
* - Otherwise calculate the next focused item based on the direction and distances.
|
|
35
35
|
* - If there is no next item, it emits `navnotarget` event
|
|
36
36
|
* - Otherwise emit `navbeforefocus`,
|
|
37
|
-
* - If this event prevented, nothing happens
|
|
37
|
+
* - If this event is prevented, nothing happens
|
|
38
38
|
* - Otherwise the focus moves to the next element
|
|
39
39
|
*
|
|
40
40
|
* ### Determine next focus
|
|
41
41
|
*
|
|
42
|
-
* The provider
|
|
42
|
+
* The provider uses multiple ways to determine the next focused element. The order defined in the "Steps" section.
|
|
43
43
|
*
|
|
44
44
|
* #### Calculated focus
|
|
45
45
|
*
|
|
@@ -50,9 +50,9 @@ import type { Events } from '../../components/spatialnavigationprovider/spatialn
|
|
|
50
50
|
* 3. Compute distances from the current element to candidates using the W3C "find the shortest
|
|
51
51
|
* distance" algorithm: https://www.w3.org/TR/css-nav-1/#find-the-shortest-distance
|
|
52
52
|
* 4. If no candidates are found, repeat from step 1, skipping areas already checked.
|
|
53
|
-
* 5. Focus the closest candidate.
|
|
53
|
+
* 5. Focus on the closest candidate.
|
|
54
54
|
*
|
|
55
|
-
* Elements with `data-spatial-focusable` are treated as focusable even if they
|
|
55
|
+
* Elements with `data-spatial-focusable` are treated as focusable even if they do otherwise not be
|
|
56
56
|
* (e.g., `tabindex="-1"`).
|
|
57
57
|
*
|
|
58
58
|
* Elements with `data-spatial-exclude` are excluded (with its subtree) from the navigation, even if they
|
|
@@ -63,7 +63,7 @@ import type { Events } from '../../components/spatialnavigationprovider/spatialn
|
|
|
63
63
|
* make navigation unpredictable. This is less of an issue on fixed-size TV UIs but can show unexpected
|
|
64
64
|
* behavior in Storybook when resizing. See the "Limitations" section.
|
|
65
65
|
*
|
|
66
|
-
* #### Overwrite next element
|
|
66
|
+
* #### Overwrite the next element
|
|
67
67
|
*
|
|
68
68
|
* Override calculated navigation by adding one of these attributes to a focusable element:
|
|
69
69
|
*
|
|
@@ -106,17 +106,17 @@ import type { Events } from '../../components/spatialnavigationprovider/spatialn
|
|
|
106
106
|
*
|
|
107
107
|
* Supported data attributes:
|
|
108
108
|
*
|
|
109
|
-
* | Attribute | Value | Default | Description
|
|
110
|
-
*
|
|
111
|
-
* | `data-spatial-left` | empty string / id / selector | N/A | Prevent native navigation in Left direction
|
|
112
|
-
* | `data-spatial-up` | empty string / id / selector | N/A | Prevent native navigation in Up direction
|
|
113
|
-
* | `data-spatial-right` | empty string / id / selector | N/A | Prevent native navigation in Right direction
|
|
114
|
-
* | `data-spatial-down` | empty string / id / selector | N/A | Prevent native navigation in Down direction
|
|
115
|
-
* | `data-spatial-go-back` | N/A | N/A | First focusable element with this attribute is clicked on Back/Escape
|
|
116
|
-
* | `data-spatial-focusable` | N/A | N/A | Treat element as focusable even if it normally is not (e.g., `tabindex="-1"`)
|
|
117
|
-
* | `data-spatial-exclude` | N/A | N/A | Exclude focusable element (and its subtree) from the navigation
|
|
118
|
-
* | `data-spatial-noscroll` | N/A | N/A | Prevent scroll for active element in scrollable area even if the is not fit in view
|
|
119
|
-
* | `data-spatial-scroll-parent` | N/A | N/A | When the focusable item in not a direct child of the scrollable aria use this attribute to mark scrollable area element
|
|
109
|
+
* | Attribute | Value | Default | Description |
|
|
110
|
+
* |------------------------------|-------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------|
|
|
111
|
+
* | `data-spatial-left` | empty string / id / selector | N/A | Prevent native navigation in the Left direction, focus it if it's focusable otherwise limit the search in the selected container. |
|
|
112
|
+
* | `data-spatial-up` | empty string / id / selector | N/A | Prevent native navigation in Up direction, focus it if it's focusable otherwise limit the search in the selected container. |
|
|
113
|
+
* | `data-spatial-right` | empty string / id / selector | N/A | Prevent native navigation in the Right direction, focus it if it's focusable otherwise limit the search in the selected container. |
|
|
114
|
+
* | `data-spatial-down` | empty string / id / selector | N/A | Prevent native navigation in Down direction, focus it if it's focusable otherwise limit the search in the selected container. |
|
|
115
|
+
* | `data-spatial-go-back` | N/A | N/A | First focusable element with this attribute is clicked on Back/Escape |
|
|
116
|
+
* | `data-spatial-focusable` | N/A | N/A | Treat element as focusable even if it normally is not (e.g., `tabindex="-1"`) |
|
|
117
|
+
* | `data-spatial-exclude` | N/A | N/A | Exclude focusable element (and its subtree) from the navigation |
|
|
118
|
+
* | `data-spatial-noscroll` | N/A | N/A | Prevent scroll for active element in scrollable area even if the is not fit in view |
|
|
119
|
+
* | `data-spatial-scroll-parent` | N/A | N/A | When the focusable item in not a direct child of the scrollable aria use this attribute to mark scrollable area element |
|
|
120
120
|
*
|
|
121
121
|
* ## Event emitting order
|
|
122
122
|
*
|
|
@@ -155,7 +155,7 @@ import type { Events } from '../../components/spatialnavigationprovider/spatialn
|
|
|
155
155
|
*
|
|
156
156
|
* ## Platform specific behaviors
|
|
157
157
|
*
|
|
158
|
-
* Consider remote/gamepad constraints. Often focus alone is not enough and users press Enter to "enter" an interactive mode:
|
|
158
|
+
* Consider remote/gamepad constraints. Often focus alone is not enough, and users press Enter to "enter" an interactive mode:
|
|
159
159
|
* - Select: Enter opens options rather than arrow keys opening a popover.
|
|
160
160
|
* - Text inputs: see the next section.
|
|
161
161
|
* - Slider: Enter to start adjusting, arrow keys to change value, Enter/Escape to stop.
|
|
@@ -183,7 +183,7 @@ import type { Events } from '../../components/spatialnavigationprovider/spatialn
|
|
|
183
183
|
* - Escape - Escape
|
|
184
184
|
*
|
|
185
185
|
* With wrapper: wraps the component in a 3x3 grid with surrounding buttons for testing.
|
|
186
|
-
* Without wrapper: renders the component alone.
|
|
186
|
+
* Without a wrapper: renders the component alone.
|
|
187
187
|
*
|
|
188
188
|
* ### Visual debugger
|
|
189
189
|
*
|
|
@@ -17,30 +17,30 @@ import { TAG_NAME } from '../../components/spatialnavigationprovider/spatialnavi
|
|
|
17
17
|
*
|
|
18
18
|
* ### Steps
|
|
19
19
|
*
|
|
20
|
-
* Spatial navigation goes
|
|
20
|
+
* Spatial navigation goes through the following steps after each keydown:
|
|
21
21
|
*
|
|
22
22
|
* 1. Handle `keydown` in the capture phase.
|
|
23
|
-
* - When active element has `data-spatial-{direction}` attribute then prevent all component navigation and call the
|
|
24
|
-
* provider own `keydown` handler (see step 3).
|
|
25
|
-
* - When active element's parent is scrollable and it is not fully visible in the given direction and it does not
|
|
26
|
-
* have `data-spatial-noscroll` attribute, prevent all navigation and scroll in the
|
|
23
|
+
* - When the active element has a `data-spatial-{direction}` attribute, then prevent all component navigation and call the
|
|
24
|
+
* provider's own `keydown` handler (see step 3).
|
|
25
|
+
* - When the active element's parent is scrollable and it is not fully visible in the given direction, and it does not
|
|
26
|
+
* have a `data-spatial-noscroll` attribute, prevent all navigation and scroll in the given direction half-size of the
|
|
27
27
|
* scroll view.
|
|
28
28
|
* 2. Component own `keydown` handler executed (bubble phase) (e.g., list moves focus internally) it it was not
|
|
29
29
|
* prevented.
|
|
30
30
|
* 3. Spatial Navigation Provider's `keydown` handler executed (bubble phase)
|
|
31
|
-
* - If key event was not prevented in step 1. emit `navbeforeprocess` to check if any component want to handle
|
|
31
|
+
* - If a key event was not prevented in step 1. emit `navbeforeprocess` to check if any component want to handle
|
|
32
32
|
* the key event itself. If `navbeforeprocess` event is prevented, stop here.
|
|
33
|
-
* - If the component did not handle `keydown`, it
|
|
34
|
-
* - if the active element has `data-spatial-{direction}` attribute, it will try to focus the element with the id.
|
|
33
|
+
* - If the component did not handle `keydown`, it calculates the next focusable item
|
|
34
|
+
* - if the active element has a `data-spatial-{direction}` attribute, it will try to focus the element with the id.
|
|
35
35
|
* - Otherwise calculate the next focused item based on the direction and distances.
|
|
36
36
|
* - If there is no next item, it emits `navnotarget` event
|
|
37
37
|
* - Otherwise emit `navbeforefocus`,
|
|
38
|
-
* - If this event prevented, nothing happens
|
|
38
|
+
* - If this event is prevented, nothing happens
|
|
39
39
|
* - Otherwise the focus moves to the next element
|
|
40
40
|
*
|
|
41
41
|
* ### Determine next focus
|
|
42
42
|
*
|
|
43
|
-
* The provider
|
|
43
|
+
* The provider uses multiple ways to determine the next focused element. The order defined in the "Steps" section.
|
|
44
44
|
*
|
|
45
45
|
* #### Calculated focus
|
|
46
46
|
*
|
|
@@ -51,9 +51,9 @@ import { TAG_NAME } from '../../components/spatialnavigationprovider/spatialnavi
|
|
|
51
51
|
* 3. Compute distances from the current element to candidates using the W3C "find the shortest
|
|
52
52
|
* distance" algorithm: https://www.w3.org/TR/css-nav-1/#find-the-shortest-distance
|
|
53
53
|
* 4. If no candidates are found, repeat from step 1, skipping areas already checked.
|
|
54
|
-
* 5. Focus the closest candidate.
|
|
54
|
+
* 5. Focus on the closest candidate.
|
|
55
55
|
*
|
|
56
|
-
* Elements with `data-spatial-focusable` are treated as focusable even if they
|
|
56
|
+
* Elements with `data-spatial-focusable` are treated as focusable even if they do otherwise not be
|
|
57
57
|
* (e.g., `tabindex="-1"`).
|
|
58
58
|
*
|
|
59
59
|
* Elements with `data-spatial-exclude` are excluded (with its subtree) from the navigation, even if they
|
|
@@ -64,7 +64,7 @@ import { TAG_NAME } from '../../components/spatialnavigationprovider/spatialnavi
|
|
|
64
64
|
* make navigation unpredictable. This is less of an issue on fixed-size TV UIs but can show unexpected
|
|
65
65
|
* behavior in Storybook when resizing. See the "Limitations" section.
|
|
66
66
|
*
|
|
67
|
-
* #### Overwrite next element
|
|
67
|
+
* #### Overwrite the next element
|
|
68
68
|
*
|
|
69
69
|
* Override calculated navigation by adding one of these attributes to a focusable element:
|
|
70
70
|
*
|
|
@@ -107,17 +107,17 @@ import { TAG_NAME } from '../../components/spatialnavigationprovider/spatialnavi
|
|
|
107
107
|
*
|
|
108
108
|
* Supported data attributes:
|
|
109
109
|
*
|
|
110
|
-
* | Attribute | Value | Default | Description
|
|
111
|
-
*
|
|
112
|
-
* | `data-spatial-left` | empty string / id / selector | N/A | Prevent native navigation in Left direction
|
|
113
|
-
* | `data-spatial-up` | empty string / id / selector | N/A | Prevent native navigation in Up direction
|
|
114
|
-
* | `data-spatial-right` | empty string / id / selector | N/A | Prevent native navigation in Right direction
|
|
115
|
-
* | `data-spatial-down` | empty string / id / selector | N/A | Prevent native navigation in Down direction
|
|
116
|
-
* | `data-spatial-go-back` | N/A | N/A | First focusable element with this attribute is clicked on Back/Escape
|
|
117
|
-
* | `data-spatial-focusable` | N/A | N/A | Treat element as focusable even if it normally is not (e.g., `tabindex="-1"`)
|
|
118
|
-
* | `data-spatial-exclude` | N/A | N/A | Exclude focusable element (and its subtree) from the navigation
|
|
119
|
-
* | `data-spatial-noscroll` | N/A | N/A | Prevent scroll for active element in scrollable area even if the is not fit in view
|
|
120
|
-
* | `data-spatial-scroll-parent` | N/A | N/A | When the focusable item in not a direct child of the scrollable aria use this attribute to mark scrollable area element
|
|
110
|
+
* | Attribute | Value | Default | Description |
|
|
111
|
+
* |------------------------------|-------------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------|
|
|
112
|
+
* | `data-spatial-left` | empty string / id / selector | N/A | Prevent native navigation in the Left direction, focus it if it's focusable otherwise limit the search in the selected container. |
|
|
113
|
+
* | `data-spatial-up` | empty string / id / selector | N/A | Prevent native navigation in Up direction, focus it if it's focusable otherwise limit the search in the selected container. |
|
|
114
|
+
* | `data-spatial-right` | empty string / id / selector | N/A | Prevent native navigation in the Right direction, focus it if it's focusable otherwise limit the search in the selected container. |
|
|
115
|
+
* | `data-spatial-down` | empty string / id / selector | N/A | Prevent native navigation in Down direction, focus it if it's focusable otherwise limit the search in the selected container. |
|
|
116
|
+
* | `data-spatial-go-back` | N/A | N/A | First focusable element with this attribute is clicked on Back/Escape |
|
|
117
|
+
* | `data-spatial-focusable` | N/A | N/A | Treat element as focusable even if it normally is not (e.g., `tabindex="-1"`) |
|
|
118
|
+
* | `data-spatial-exclude` | N/A | N/A | Exclude focusable element (and its subtree) from the navigation |
|
|
119
|
+
* | `data-spatial-noscroll` | N/A | N/A | Prevent scroll for active element in scrollable area even if the is not fit in view |
|
|
120
|
+
* | `data-spatial-scroll-parent` | N/A | N/A | When the focusable item in not a direct child of the scrollable aria use this attribute to mark scrollable area element |
|
|
121
121
|
*
|
|
122
122
|
* ## Event emitting order
|
|
123
123
|
*
|
|
@@ -156,7 +156,7 @@ import { TAG_NAME } from '../../components/spatialnavigationprovider/spatialnavi
|
|
|
156
156
|
*
|
|
157
157
|
* ## Platform specific behaviors
|
|
158
158
|
*
|
|
159
|
-
* Consider remote/gamepad constraints. Often focus alone is not enough and users press Enter to "enter" an interactive mode:
|
|
159
|
+
* Consider remote/gamepad constraints. Often focus alone is not enough, and users press Enter to "enter" an interactive mode:
|
|
160
160
|
* - Select: Enter opens options rather than arrow keys opening a popover.
|
|
161
161
|
* - Text inputs: see the next section.
|
|
162
162
|
* - Slider: Enter to start adjusting, arrow keys to change value, Enter/Escape to stop.
|
|
@@ -184,7 +184,7 @@ import { TAG_NAME } from '../../components/spatialnavigationprovider/spatialnavi
|
|
|
184
184
|
* - Escape - Escape
|
|
185
185
|
*
|
|
186
186
|
* With wrapper: wraps the component in a 3x3 grid with surrounding buttons for testing.
|
|
187
|
-
* Without wrapper: renders the component alone.
|
|
187
|
+
* Without a wrapper: renders the component alone.
|
|
188
188
|
*
|
|
189
189
|
* ### Visual debugger
|
|
190
190
|
*
|
package/dist/utils/dom.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { OverflowMixinInterface } from './mixins/OverflowMixin';
|
|
2
|
+
type FindFocusableCommands = 'focusable' | 'continue' | 'stop';
|
|
2
3
|
/**
|
|
3
4
|
* Options for finding focusable elements.
|
|
4
5
|
*/
|
|
5
6
|
type FindFocusableOptions = {
|
|
6
|
-
/** Elements to include (and its subtree) in the search. */
|
|
7
|
-
includeElements?: HTMLElement[];
|
|
8
7
|
/** Elements to exclude (and its subtree) from the search. */
|
|
9
8
|
excludedElements?: HTMLElement[];
|
|
10
9
|
/** Selectors to include in the search. */
|
|
@@ -17,6 +16,14 @@ type FindFocusableOptions = {
|
|
|
17
16
|
* inactive items and their children should not be reachable via Tab navigation.
|
|
18
17
|
*/
|
|
19
18
|
stopAtNonTabbable?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* When it is provided, it is executed after the default checked run.
|
|
21
|
+
* I get the result from the default checked run and can modify it.
|
|
22
|
+
*
|
|
23
|
+
* @param element - The element to check.
|
|
24
|
+
* @param result - The result of the default checked run.
|
|
25
|
+
*/
|
|
26
|
+
customFocusableCheck?: (element: HTMLElement, result: FindFocusableCommands) => FindFocusableCommands;
|
|
20
27
|
};
|
|
21
28
|
/**
|
|
22
29
|
* nodeB precedes nodeA in either a pre-order depth-first traversal of a tree containing both
|
package/dist/utils/dom.js
CHANGED
|
@@ -173,7 +173,7 @@ export const isFocusable = (element) => !isDisabled(element) && isTabbable(eleme
|
|
|
173
173
|
* @returns The list of focusable elements.
|
|
174
174
|
*/
|
|
175
175
|
export const findFocusable = (root, options = {}) => {
|
|
176
|
-
var _a, _b, _c, _d
|
|
176
|
+
var _a, _b, _c, _d;
|
|
177
177
|
if (!root) {
|
|
178
178
|
return [];
|
|
179
179
|
}
|
|
@@ -181,12 +181,14 @@ export const findFocusable = (root, options = {}) => {
|
|
|
181
181
|
const includeSelectors = (_b = options === null || options === void 0 ? void 0 : options.includeSelectors) !== null && _b !== void 0 ? _b : [];
|
|
182
182
|
const excludeSelectors = (_c = options === null || options === void 0 ? void 0 : options.excludeSelectors) !== null && _c !== void 0 ? _c : [];
|
|
183
183
|
const stopAtNonTabbable = (_d = options === null || options === void 0 ? void 0 : options.stopAtNonTabbable) !== null && _d !== void 0 ? _d : false;
|
|
184
|
-
const matches = new Set(
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
184
|
+
const matches = new Set([]);
|
|
185
|
+
const internalFocusableCheck = (element) => {
|
|
186
|
+
// Excluded
|
|
187
|
+
if (excludesSet.has(root) || isMatchAny(element, excludeSelectors))
|
|
188
|
+
return 'stop';
|
|
189
|
+
// Unreachable
|
|
190
|
+
if (isHidden(element) || isDisabled(element))
|
|
188
191
|
return 'stop';
|
|
189
|
-
}
|
|
190
192
|
if (stopAtNonTabbable && !(element instanceof HTMLSlotElement) && element.getAttribute('tabindex') === '-1') {
|
|
191
193
|
// AI-Assisted
|
|
192
194
|
// Do not stop traversal for elements inside a shadow root with delegatesFocus: true.
|
|
@@ -202,49 +204,30 @@ export const findFocusable = (root, options = {}) => {
|
|
|
202
204
|
? 'focusable'
|
|
203
205
|
: 'continue';
|
|
204
206
|
};
|
|
207
|
+
const focusableCheck = options.customFocusableCheck
|
|
208
|
+
? (el) => options.customFocusableCheck(el, internalFocusableCheck(el))
|
|
209
|
+
: internalFocusableCheck;
|
|
205
210
|
const finder = (root) => {
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
+
if (root instanceof HTMLElement) {
|
|
212
|
+
const isFocusableResult = focusableCheck(root);
|
|
213
|
+
if (isFocusableResult === 'focusable') {
|
|
214
|
+
matches.add(root);
|
|
215
|
+
}
|
|
216
|
+
if (isFocusableResult === 'stop') {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
211
219
|
}
|
|
212
220
|
let children = [];
|
|
213
|
-
if (root instanceof
|
|
221
|
+
if (root instanceof HTMLSlotElement) {
|
|
222
|
+
children = root.assignedElements({ flatten: true });
|
|
223
|
+
}
|
|
224
|
+
else if (root instanceof HTMLElement && root.shadowRoot) {
|
|
214
225
|
children = Array.from(root.shadowRoot.children);
|
|
215
226
|
}
|
|
216
227
|
else if (root.children.length) {
|
|
217
228
|
children = Array.from(root.children);
|
|
218
229
|
}
|
|
219
|
-
children.forEach(
|
|
220
|
-
const element = child;
|
|
221
|
-
const isFocusableResult = focusableCheck(element);
|
|
222
|
-
if (isFocusableResult === 'focusable') {
|
|
223
|
-
matches.add(element);
|
|
224
|
-
}
|
|
225
|
-
if (isFocusableResult === 'stop') {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
if (element.shadowRoot) {
|
|
229
|
-
finder(element.shadowRoot);
|
|
230
|
-
}
|
|
231
|
-
else if (element.tagName === 'SLOT') {
|
|
232
|
-
const assignedNodes = element.assignedElements({ flatten: true });
|
|
233
|
-
assignedNodes.forEach(node => {
|
|
234
|
-
if (node instanceof HTMLElement) {
|
|
235
|
-
// When stopAtNonTabbable is enabled, skip non-tabbable slotted elements and their
|
|
236
|
-
// subtrees to support composite widget patterns (e.g., roving tabindex in lists)
|
|
237
|
-
if (stopAtNonTabbable && !(node instanceof HTMLSlotElement) && node.getAttribute('tabindex') === '-1') {
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
finder(node);
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
245
|
-
finder(element);
|
|
246
|
-
}
|
|
247
|
-
});
|
|
230
|
+
children.forEach(finder);
|
|
248
231
|
};
|
|
249
232
|
finder(root);
|
|
250
233
|
return [...matches];
|