@@ -5,19 +5,20 @@ import { domFunctions } from '../DomWrapper';
5
5
import { EnhancedNavigationStartEvent , JSEventRegistry } from '../Services/JSEventRegistry' ;
6
6
7
7
const customElementName = 'blazor-focus-on-navigate' ;
8
- const focusOnNavigateRegistrations : FocusOnNavigateRegistration [ ] = [ ] ;
9
-
8
+ let currentFocusOnNavigateElement : FocusOnNavigateElement | null = null ;
10
9
let allowFocusOnEnhancedLoad = false ;
11
10
12
11
export function enableFocusOnNavigate ( jsEventRegistry : JSEventRegistry ) {
13
- customElements . define ( customElementName , FocusOnNavigate ) ;
12
+ customElements . define ( customElementName , FocusOnNavigateElement ) ;
14
13
jsEventRegistry . addEventListener ( 'enhancednavigationstart' , onEnhancedNavigationStart ) ;
15
14
jsEventRegistry . addEventListener ( 'enhancedload' , onEnhancedLoad ) ;
16
15
document . addEventListener ( 'focusin' , onFocusIn ) ;
17
16
document . addEventListener ( 'focusout' , onFocusOut ) ;
18
17
19
- // Focus the element on the initial page load
18
+ // Focus the element on the initial page load.
20
19
if ( document . readyState === 'loading' ) {
20
+ // There may be streaming updates on the initial page load, so we want to allow
21
+ // those to add elements matching the active selector.
21
22
allowFocusOnEnhancedLoad = true ;
22
23
document . addEventListener ( 'DOMContentLoaded' , afterInitialPageLoad ) ;
23
24
} else {
@@ -78,53 +79,21 @@ function tryApplyFocus(forceMoveFocus: boolean) {
78
79
79
80
lastFocusedElement = null ;
80
81
81
- const selector = findActiveSelector ( ) ;
82
+ const selector = currentFocusOnNavigateElement ?. getAttribute ( 'selector' ) ;
82
83
if ( selector ) {
83
84
lastFocusedElement = domFunctions . focusBySelector ( selector ) ;
84
85
}
85
86
}
86
87
87
- function findActiveSelector ( ) : string | null {
88
- // It's unlikely that there will be more than one <blazor-focus-on-navigate> registered
89
- // at a time. But if there is, we'll prefer the one most recently added to the DOM,
90
- // keeping a stack of all previous registrations to fall back on if the current one
91
- // gets removed.
92
- let registration : FocusOnNavigateRegistration | undefined ;
93
- while ( ( registration = focusOnNavigateRegistrations . at ( - 1 ) ) !== undefined ) {
94
- if ( registration . isConnected ) {
95
- return registration . selector ;
96
- }
97
-
98
- focusOnNavigateRegistrations . pop ( ) ;
99
- }
100
-
101
- return null ;
102
- }
103
-
104
- type FocusOnNavigateRegistration = {
105
- isConnected : boolean ;
106
- selector : string | null ;
107
- }
108
-
109
- class FocusOnNavigate extends HTMLElement {
110
- static observedAttributes = [ 'selector' ] ;
111
-
112
- private readonly _registration : FocusOnNavigateRegistration = {
113
- isConnected : true ,
114
- selector : null ,
115
- } ;
116
-
88
+ class FocusOnNavigateElement extends HTMLElement {
117
89
connectedCallback ( ) {
118
- focusOnNavigateRegistrations . push ( this . _registration ) ;
119
- }
120
-
121
- attributeChangedCallback ( name : string , oldValue : string , newValue : string ) {
122
- if ( name === 'selector' ) {
123
- this . _registration . selector = newValue ;
124
- }
90
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
91
+ currentFocusOnNavigateElement = this ;
125
92
}
126
93
127
94
disconnectedCallback ( ) {
128
- this . _registration . isConnected = false ;
95
+ if ( currentFocusOnNavigateElement === this ) {
96
+ currentFocusOnNavigateElement = null ;
97
+ }
129
98
}
130
99
}
0 commit comments