1- import  React ,  {  FC ,  ReactElement ,  cloneElement ,  useEffect ,  useRef  }  from  'react' 
2- import  {  mergeRefs ,  focusableChildren  }  from  './utils' 
1+ import  React ,  {  FC ,  ReactElement ,  cloneElement ,  use ,   useEffect ,  useRef  }  from  'react' 
2+ import  {  mergeRefs ,  focusableChildren ,   getChildRef  }  from  './utils' 
33
44export  interface  CFocusTrapProps  { 
55  /** 
@@ -146,7 +146,10 @@ export const CFocusTrap: FC<CFocusTrapProps> = ({
146146
147147      if  ( elements . length  ===  0 )  { 
148148        container . focus ( {  preventScroll : true  } ) 
149-       }  else  if  ( lastTabNavDirectionRef . current  ===  'backward' )  { 
149+         return 
150+       } 
151+ 
152+       if  ( lastTabNavDirectionRef . current  ===  'backward' )  { 
150153        elements . at ( - 1 ) ?. focus ( {  preventScroll : true  } ) 
151154      }  else  { 
152155        elements [ 0 ] . focus ( {  preventScroll : true  } ) 
@@ -161,20 +164,37 @@ export const CFocusTrap: FC<CFocusTrapProps> = ({
161164      tabEventSourceRef . current  =  container 
162165      lastTabNavDirectionRef . current  =  event . shiftKey  ? 'backward'  : 'forward' 
163166
164-       if  ( ! _additionalContainer )  { 
165-         return 
166-       } 
167- 
168167      const  containerElements  =  focusableChildren ( container ) 
169-       const  additionalElements  =  focusableChildren ( _additionalContainer ) 
168+       const  additionalElements  =  _additionalContainer  ?  focusableChildren ( _additionalContainer )  :  [ ] 
170169
171170      if  ( containerElements . length  ===  0  &&  additionalElements . length  ===  0 )  { 
172171        // No focusable elements, prevent tab 
173172        event . preventDefault ( ) 
174173        return 
175174      } 
176175
176+       const  focusableElements  =  [ ...containerElements ,  ...additionalElements ] 
177+ 
178+       const  firstFocusableElement  =  focusableElements [ 0 ]  as  HTMLElement 
179+       const  lastFocusableElement  =  focusableElements . at ( - 1 )  as  HTMLElement 
177180      const  activeElement  =  document . activeElement  as  HTMLElement 
181+ 
182+       if  ( event . shiftKey  &&  activeElement  ===  firstFocusableElement )  { 
183+         event . preventDefault ( ) 
184+         lastFocusableElement . focus ( ) 
185+         return 
186+       } 
187+ 
188+       if  ( ! event . shiftKey  &&  activeElement  ===  lastFocusableElement )  { 
189+         event . preventDefault ( ) 
190+         firstFocusableElement . focus ( ) 
191+         return 
192+       } 
193+ 
194+       if  ( ! _additionalContainer )  { 
195+         return 
196+       } 
197+ 
178198      const  isInContainer  =  containerElements . includes ( activeElement ) 
179199      const  isInAdditional  =  additionalElements . includes ( activeElement ) 
180200
@@ -245,7 +265,12 @@ export const CFocusTrap: FC<CFocusTrapProps> = ({
245265
246266  // Attach our ref to the ONLY child — no extra wrappers 
247267  const  onlyChild  =  React . Children . only ( children ) 
248-   const  childRef  =  ( onlyChild  as  React . ReactElement  &  {  ref ?: React . Ref < HTMLElement >  } ) . ref 
268+ 
269+   // Handle different ref access patterns between React versions 
270+   // React 19+: ref is accessed via element.props.ref 
271+   // React 18 and earlier: ref is accessed via element.ref 
272+   const  childRef : React . Ref < HTMLElement >  |  undefined  =  getChildRef ( onlyChild ) 
273+ 
249274  const  mergedRef  =  mergeRefs ( childRef ,  ( node : HTMLElement  |  null )  =>  { 
250275    containerRef . current  =  node 
251276  } ) 
0 commit comments