9
9
import { dispatchFakeEvent } from './dispatch-events' ;
10
10
11
11
function triggerFocusChange ( element : HTMLElement , event : 'focus' | 'blur' ) {
12
+ const hasFocus = document . activeElement === element ;
13
+
14
+ if ( ( event === 'focus' && hasFocus ) || ( event === 'blur' && ! hasFocus ) ) {
15
+ return ;
16
+ }
17
+
12
18
let eventFired = false ;
13
19
const handler = ( ) => ( eventFired = true ) ;
14
20
element . addEventListener ( event , handler ) ;
15
21
element [ event ] ( ) ;
16
22
element . removeEventListener ( event , handler ) ;
23
+
24
+ // Some browsers won't move focus if the browser window is blurred while other will move it
25
+ // asynchronously. If that is the case, we fake the event sequence as a fallback.
17
26
if ( ! eventFired ) {
18
- dispatchFakeEvent ( element , event ) ;
27
+ simulateFocusSequence ( element , event ) ;
19
28
}
20
29
}
21
30
31
+ /** Simulates the full event sequence for a focus event. */
32
+ function simulateFocusSequence ( element : HTMLElement , event : 'focus' | 'blur' ) {
33
+ dispatchFakeEvent ( element , event ) ;
34
+ dispatchFakeEvent ( element , event === 'focus' ? 'focusin' : 'focusout' ) ;
35
+ }
36
+
22
37
/**
23
38
* Patches an elements focus and blur methods to emit events consistently and predictably.
24
39
* This is necessary, because some browsers can call the focus handlers asynchronously,
@@ -28,8 +43,8 @@ function triggerFocusChange(element: HTMLElement, event: 'focus' | 'blur') {
28
43
// TODO: Check if this element focus patching is still needed for local testing,
29
44
// where browser is not necessarily focused.
30
45
export function patchElementFocus ( element : HTMLElement ) {
31
- element . focus = ( ) => dispatchFakeEvent ( element , 'focus' ) ;
32
- element . blur = ( ) => dispatchFakeEvent ( element , 'blur' ) ;
46
+ element . focus = ( ) => simulateFocusSequence ( element , 'focus' ) ;
47
+ element . blur = ( ) => simulateFocusSequence ( element , 'blur' ) ;
33
48
}
34
49
35
50
/** @docs -private */
0 commit comments