2
2
namespace OSFramework . OSUI . Behaviors {
3
3
// FocusTrap type
4
4
export type FocusTrapParams = {
5
+ canContainOtherPatterns ?: boolean ;
5
6
focusBottomCallback ?: GlobalCallbacks . Generic ;
6
7
focusTargetElement : HTMLElement ;
7
8
focusTopCallback ?: GlobalCallbacks . Generic ;
@@ -14,6 +15,7 @@ namespace OSFramework.OSUI.Behaviors {
14
15
* @class FocusTrap
15
16
*/
16
17
export class FocusTrap {
18
+ private _canTargetContainOtherPatts = false ;
17
19
private _firstFocusableElement : HTMLElement ;
18
20
private _focusBottomCallback : GlobalCallbacks . Generic ;
19
21
private _focusTopCallback : GlobalCallbacks . Generic ;
@@ -31,13 +33,18 @@ namespace OSFramework.OSUI.Behaviors {
31
33
* @memberof FocusTrap
32
34
*/
33
35
constructor ( opts : FocusTrapParams ) {
36
+ this . _focusableElements = [ ] ;
37
+
34
38
// Store the focus target element
35
39
this . _targetElement = opts . focusTargetElement ;
36
40
37
41
// Set the callbacks to focusable elements
38
42
this . _focusBottomCallback = opts . focusBottomCallback ;
39
43
this . _focusTopCallback = opts . focusTopCallback ;
40
44
45
+ // Set the indicator that will reflect if the target element is capable to have other patterns inside
46
+ this . _canTargetContainOtherPatts = opts . canContainOtherPatterns || false ;
47
+
41
48
// Create the elements needed!
42
49
this . _buildPredictableElements ( ) ;
43
50
}
@@ -115,15 +122,34 @@ namespace OSFramework.OSUI.Behaviors {
115
122
}
116
123
117
124
// Method to set the focusable elements to be used
118
- private _setFocusableElements ( ) : void {
119
- this . _focusableElements = Helper . Dom . GetFocusableElements ( this . _targetElement ) ;
120
-
121
- // Check if predicted elements exist at the _focusableElements
122
- for ( const predictedElement of this . _focusableElements . filter (
123
- ( item ) => item === this . _predictableTopElement || item === this . _predictableBottomElement
124
- ) ) {
125
- // If so, remove them from the array collection of _focusableElements
126
- this . _focusableElements . splice ( this . _focusableElements . indexOf ( predictedElement ) , 1 ) ;
125
+ private _setFocusableElements ( includeTabIndexHidden = false ) : void {
126
+ // Ensure the list of focusable elements is empty
127
+ this . _focusableElements . length = 0 ;
128
+
129
+ // Get all the possible focusable
130
+ const possibleFocusableElements = Helper . Dom . GetFocusableElements (
131
+ this . _targetElement ,
132
+ includeTabIndexHidden
133
+ ) ;
134
+
135
+ // Ensure we get the proper list of focusable elements
136
+ for ( const element of possibleFocusableElements ) {
137
+ // Get the closest data block from the element
138
+ const closestDataBlock = element . closest ( GlobalEnum . DataBlocksTag . DataBlock ) ;
139
+ // Check if the element is a child of the given targetElement
140
+ if ( closestDataBlock === this . _targetElement || closestDataBlock . contains ( this . _targetElement ) ) {
141
+ // Check if element is not a predictable element
142
+ if ( element !== this . _predictableTopElement && element !== this . _predictableBottomElement ) {
143
+ this . _focusableElements . push ( element ) ;
144
+ }
145
+ // If the targetElement is a "special" element, we need to ensure that the focusable elements are not part of the inner patterns
146
+ // Example of having an OverflowMenu inside the Sidebar and also get all the focusable elements from it as a part of the ones at the sideBar context
147
+ } else if ( this . _canTargetContainOtherPatts ) {
148
+ // Ensure the element we bring from the inner pattern is the default tabindex element for it!
149
+ if ( Helper . Dom . Attribute . Has ( element , Constants . FocusableTabIndexDefault ) ) {
150
+ this . _focusableElements . push ( element ) ;
151
+ }
152
+ }
127
153
}
128
154
129
155
// Remove the first element from array, because of predictable top element added for trapping
@@ -204,7 +230,7 @@ namespace OSFramework.OSUI.Behaviors {
204
230
Helper . A11Y . AriaHiddenFalse ( this . _predictableTopElement ) ;
205
231
206
232
// Ensure the list of focusable elements is updated, predictable elements starts with TabIndex Hidden
207
- this . _setFocusableElements ( ) ;
233
+ this . _setFocusableElements ( true ) ;
208
234
}
209
235
210
236
/**
0 commit comments