11import { useEffect } from 'react' ;
22import isVisible from './isVisible' ;
3+ import useId from '../hooks/useId' ;
34
45type DisabledElement =
56 | HTMLLinkElement
@@ -102,15 +103,22 @@ export function triggerFocus(
102103// ======================================================
103104let lastFocusElement : HTMLElement | null = null ;
104105let focusElements : HTMLElement [ ] = [ ] ;
105- const ignoredElementMap = new Map < HTMLElement , HTMLElement | null > ( ) ;
106+ // Map lock element to its stable ID
107+ const elementToIdMap = new Map < HTMLElement , string > ( ) ;
108+ // Map stable ID to ignored element
109+ const ignoredElementMap = new Map < string , HTMLElement | null > ( ) ;
106110
107111function getLastElement ( ) {
108112 return focusElements [ focusElements . length - 1 ] ;
109113}
110114
111115function isIgnoredElement ( element : Element | null ) : boolean {
112116 if ( ! element ) return false ;
113- const ignoredEle = ignoredElementMap . get ( getLastElement ( ) ) ;
117+ const lastElement = getLastElement ( ) ;
118+ if ( ! lastElement ) return false ;
119+ const lockId = elementToIdMap . get ( lastElement ) ;
120+ if ( ! lockId ) return false ;
121+ const ignoredEle = ignoredElementMap . get ( lockId ) ;
114122 return (
115123 ! ! ignoredEle && ( ignoredEle === element || ignoredEle . contains ( element ) )
116124 ) ;
@@ -163,9 +171,13 @@ function onWindowKeyDown(e: KeyboardEvent) {
163171/**
164172 * Lock focus in the element.
165173 * It will force back to the first focusable element when focus leaves the element.
174+ * @param id - A stable ID for this lock instance
166175 */
167- export function lockFocus ( element : HTMLElement ) : VoidFunction {
176+ export function lockFocus ( element : HTMLElement , id : string ) : VoidFunction {
168177 if ( element ) {
178+ // Store the mapping between element and its stable ID
179+ elementToIdMap . set ( element , id ) ;
180+
169181 // Refresh focus elements
170182 focusElements = focusElements . filter ( ele => ele !== element ) ;
171183 focusElements . push ( element ) ;
@@ -180,7 +192,8 @@ export function lockFocus(element: HTMLElement): VoidFunction {
180192 return ( ) => {
181193 lastFocusElement = null ;
182194 focusElements = focusElements . filter ( ele => ele !== element ) ;
183- ignoredElementMap . delete ( element ) ;
195+ elementToIdMap . delete ( element ) ;
196+ ignoredElementMap . delete ( id ) ;
184197 if ( focusElements . length === 0 ) {
185198 window . removeEventListener ( 'focusin' , syncFocus ) ;
186199 window . removeEventListener ( 'keydown' , onWindowKeyDown , true ) ;
@@ -198,21 +211,24 @@ export function useLockFocus(
198211 lock : boolean ,
199212 getElement : ( ) => HTMLElement | null ,
200213) : [ ignoreElement : ( ele : HTMLElement ) => void ] {
214+ const id = useId ( ) ;
215+
201216 useEffect ( ( ) => {
202217 if ( lock ) {
203218 const element = getElement ( ) ;
204219 if ( element ) {
205- return lockFocus ( element ) ;
220+ return lockFocus ( element , id ) ;
206221 }
207222 }
208- } , [ lock ] ) ;
223+ } , [ lock , id ] ) ;
209224
210225 const ignoreElement = ( ele : HTMLElement ) => {
211226 const element = getElement ( ) ;
212227 if ( element && ele ) {
213- // Set the ignored element for current lock element
228+ // Set the ignored element for current lock using stable ID
214229 // Only one element can be ignored at a time for this lock
215- ignoredElementMap . set ( element , ele ) ;
230+ const lockId = elementToIdMap . get ( element ) || id ;
231+ ignoredElementMap . set ( lockId , ele ) ;
216232 }
217233 } ;
218234
0 commit comments