@@ -11,13 +11,20 @@ class FocusContext {
11
11
* @param {=Element } preferred Where we should start searching for focusable elements
12
12
*/
13
13
constructor ( root , { source, trap = false , preferred } ) {
14
+ if ( ! root ) {
15
+ throw new Error ( 'Root must be specified to create a FocusContext instance.' )
16
+ }
17
+
14
18
this . root = root
15
19
this . source = source
16
20
this . trap = trap
17
21
this . preferred = preferred
18
22
19
- this . outsideHandler = ( ) => {
20
- this . focusFirst ( true )
23
+ this . outsideStartHandler = ( ) => {
24
+ this . focusAt ( - 2 , true )
25
+ }
26
+ this . outsideEndHandler = ( ) => {
27
+ this . focusAt ( 1 , true )
21
28
}
22
29
23
30
this . init ( )
@@ -29,29 +36,37 @@ class FocusContext {
29
36
* 2. focus `root` by default
30
37
*/
31
38
init ( ) {
32
- this . focusFirst ( )
39
+ this . focusAt ( )
33
40
34
41
if ( this . trap ) {
35
- let ward = document . createElement ( 'div' )
36
- ward . tabIndex = 0
37
- ward . addEventListener ( 'focus' , this . outsideHandler , true )
38
- this . root . appendChild ( ward )
39
- this . ward = ward
42
+ let before = document . createElement ( 'div' )
43
+ before . tabIndex = 0
44
+ let after = before . cloneNode ( )
45
+
46
+ before . addEventListener ( 'focus' , this . outsideStartHandler , true )
47
+ after . addEventListener ( 'focus' , this . outsideEndHandler , true )
48
+
49
+ this . root . insertBefore ( before , this . root . firstChild )
50
+ this . root . appendChild ( after )
51
+
52
+ this . wardBefore = before
53
+ this . wardAfter = after
40
54
}
41
55
}
42
56
43
- focusFirst ( ignoreFocus ) {
57
+ focusAt ( index = 0 , ignoreAutofocus ) {
44
58
Vue . nextTick ( ( ) => {
45
- if ( ! focusIn ( this . preferred || this . root , ignoreFocus ) ) {
59
+ if ( ! focusIn ( this . preferred || this . root , index , ignoreAutofocus ) ) {
46
60
this . root . focus ( )
47
61
}
48
62
} )
49
63
}
50
64
51
65
destroy ( ) {
52
- let { trap, source, ward } = this
66
+ let { trap, source, wardBefore , wardAfter } = this
53
67
if ( trap ) {
54
- ward . removeEventListener ( 'focus' , this . outsideHandler , true )
68
+ wardBefore . removeEventListener ( 'focus' , this . outsideStartHandler , true )
69
+ wardAfter . removeEventListener ( 'focus' , this . outsideEndHandler , true )
55
70
}
56
71
if ( source && typeof source . focus === 'function' ) {
57
72
this . source = null
@@ -62,9 +77,8 @@ class FocusContext {
62
77
source . focus ( )
63
78
} , 0 )
64
79
}
65
- if ( ward ) {
66
- ward . parentElement . removeChild ( ward )
67
- }
80
+ this . root . removeChild ( wardBefore )
81
+ this . root . removeChild ( wardAfter )
68
82
this . preferred = null
69
83
this . root = null
70
84
}
0 commit comments