@@ -51,11 +51,14 @@ export const VDialog = genericComponent<OverlaySlots>()({
51
51
const { scopeId } = useScopeId ( )
52
52
53
53
const overlay = ref < VOverlay > ( )
54
- function onFocusin ( e : FocusEvent ) {
54
+ async function onFocusin ( e : FocusEvent ) {
55
55
const before = e . relatedTarget as HTMLElement | null
56
56
const after = e . target as HTMLElement | null
57
57
58
+ await nextTick ( )
59
+
58
60
if (
61
+ isActive . value &&
59
62
before !== after &&
60
63
overlay . value ?. contentEl &&
61
64
// We're the topmost dialog
@@ -66,29 +69,43 @@ export const VDialog = genericComponent<OverlaySlots>()({
66
69
! overlay . value . contentEl . contains ( after )
67
70
) {
68
71
const focusable = focusableChildren ( overlay . value . contentEl )
72
+ focusable [ 0 ] ?. focus ( )
73
+ }
74
+ }
69
75
70
- if ( ! focusable . length ) return
76
+ function onKeydown ( e : KeyboardEvent ) {
77
+ if ( e . key !== 'Tab' || ! overlay . value ?. contentEl ) return
71
78
72
- const firstElement = focusable [ 0 ]
73
- const lastElement = focusable [ focusable . length - 1 ]
79
+ const focusable = focusableChildren ( overlay . value . contentEl )
80
+ if ( ! focusable . length ) return
74
81
75
- if ( before === firstElement ) {
76
- lastElement . focus ( )
77
- } else {
78
- firstElement . focus ( )
79
- }
82
+ const firstElement = focusable [ 0 ]
83
+ const lastElement = focusable [ focusable . length - 1 ]
84
+ const active = document . activeElement as HTMLElement | null
85
+
86
+ if ( e . shiftKey && active === firstElement ) {
87
+ e . preventDefault ( )
88
+ lastElement . focus ( )
89
+ } else if ( ! e . shiftKey && active === lastElement ) {
90
+ e . preventDefault ( )
91
+ firstElement . focus ( )
80
92
}
81
93
}
82
94
83
95
onBeforeUnmount ( ( ) => {
84
96
document . removeEventListener ( 'focusin' , onFocusin )
97
+ document . removeEventListener ( 'keydown' , onKeydown )
85
98
} )
86
99
87
100
if ( IN_BROWSER ) {
88
101
watch ( ( ) => isActive . value && props . retainFocus , val => {
89
- val
90
- ? document . addEventListener ( 'focusin' , onFocusin )
91
- : document . removeEventListener ( 'focusin' , onFocusin )
102
+ if ( val ) {
103
+ document . addEventListener ( 'focusin' , onFocusin , { once : true } )
104
+ document . addEventListener ( 'keydown' , onKeydown )
105
+ } else {
106
+ document . removeEventListener ( 'focusin' , onFocusin )
107
+ document . removeEventListener ( 'keydown' , onKeydown )
108
+ }
92
109
} , { immediate : true } )
93
110
}
94
111
0 commit comments