99import { dispatchFakeEvent } from './dispatch-events' ;
1010
1111function 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+
1218 let eventFired = false ;
1319 const handler = ( ) => ( eventFired = true ) ;
1420 element . addEventListener ( event , handler ) ;
1521 element [ event ] ( ) ;
1622 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.
1726 if ( ! eventFired ) {
18- dispatchFakeEvent ( element , event ) ;
27+ simulateFocusSequence ( element , event ) ;
1928 }
2029}
2130
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+
2237/**
2338 * Patches an elements focus and blur methods to emit events consistently and predictably.
2439 * This is necessary, because some browsers can call the focus handlers asynchronously,
@@ -28,8 +43,8 @@ function triggerFocusChange(element: HTMLElement, event: 'focus' | 'blur') {
2843// TODO: Check if this element focus patching is still needed for local testing,
2944// where browser is not necessarily focused.
3045export 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' ) ;
3348}
3449
3550/** @docs -private */
0 commit comments