@@ -22,51 +22,49 @@ export interface FocusVisibleUtility {
2222
2323export  const  startFocusVisible  =  ( rootEl ?: HTMLElement ) : FocusVisibleUtility  =>  { 
2424  let  currentFocus : Element [ ]  =  [ ] ; 
25-   let  keyboardMode  =  false ; 
26-   let  lastPointerType : string  |  null  =  null ; 
25+   // Tracks if the last interaction was a pointer event (mouse, touch, pen) 
26+   // Used to distinguish between pointer and keyboard navigation for focus styling 
27+   let  hadPointerEvent  =  false ; 
2728
2829  const  ref  =  rootEl  ? rootEl . shadowRoot !  : document ; 
2930  const  root  =  rootEl  ? rootEl  : document . body ; 
3031
32+   // Adds or removes the focused class for styling 
3133  const  setFocus  =  ( elements : Element [ ] )  =>  { 
3234    currentFocus . forEach ( ( el )  =>  el . classList . remove ( ION_FOCUSED ) ) ; 
3335    elements . forEach ( ( el )  =>  el . classList . add ( ION_FOCUSED ) ) ; 
3436    currentFocus  =  elements ; 
3537  } ; 
3638
39+   // Do not set focus on pointer interactions 
3740  const  pointerDown  =  ( ev : Event )  =>  { 
38-     const  pointerEvent  =  ev  as  PointerEvent ; 
39-     lastPointerType  =  pointerEvent . pointerType ; 
40-     keyboardMode  =  false ; 
41-     setFocus ( [ ] ) ; 
41+     if  ( ev  instanceof  PointerEvent  &&  ev . pointerType  !==  '' )  { 
42+       hadPointerEvent  =  true ; 
43+       // Reset after the event loop so only the immediate focusin is suppressed 
44+       setTimeout ( ( )  =>  {  hadPointerEvent  =  false ;  } ,  0 ) ; 
45+     } 
4246  } ; 
4347
48+   // Clear hadPointerEvent so keyboard navigation shows focus 
49+   // Also, clear focus if the key is not a navigation key 
4450  const  onKeydown  =  ( ev : Event )  =>  { 
45-     const  keyboardEvent  =  ev  as  KeyboardEvent ; 
46-     // Always set keyboard mode to true when any key is pressed 
47-     // This handles the WebKit Tab key bug where keydown might not fire 
48-     keyboardMode  =  true ; 
51+     hadPointerEvent  =  false ; 
4952
50-     // If it's not a focus key, clear focus immediately 
53+     const   keyboardEvent   =   ev   as   KeyboardEvent ; 
5154    if  ( ! FOCUS_KEYS . includes ( keyboardEvent . key ) )  { 
5255      setFocus ( [ ] ) ; 
5356    } 
5457  } ; 
5558
59+   // Set focus if the last interaction was NOT a pointer event 
60+   // This works around iOS/Safari bugs where keydown is not fired for Tab 
5661  const  onFocusin  =  ( ev : Event )  =>  { 
57-     // Check if this focus event is likely from keyboard navigation 
58-     // We can detect this by checking if there was a recent keydown event 
59-     // or if the focus target is a focusable element that typically gets focus via keyboard 
6062    const  target  =  ev . target  as  HTMLElement ; 
61- 
62-     if  ( target . classList . contains ( ION_FOCUSABLE ) )  { 
63-       // If we're in keyboard mode or this looks like keyboard navigation 
64-       if  ( keyboardMode  ||  ! lastPointerType )  { 
65-         const  toFocus  =  ev . composedPath ( ) . filter ( ( el ) : el  is HTMLElement  =>  { 
66-           return  el  instanceof  HTMLElement  &&  el . classList . contains ( ION_FOCUSABLE ) ; 
67-         } ) ; 
68-         setFocus ( toFocus ) ; 
69-       } 
63+     if  ( target . classList . contains ( ION_FOCUSABLE )  &&  ! hadPointerEvent )  { 
64+       const  toFocus  =  ev . composedPath ( ) . filter ( ( el ) : el  is HTMLElement  => 
65+         el  instanceof  HTMLElement  &&  el . classList . contains ( ION_FOCUSABLE ) 
66+       ) ; 
67+       setFocus ( toFocus ) ; 
7068    } 
7169  } ; 
7270
@@ -80,16 +78,12 @@ export const startFocusVisible = (rootEl?: HTMLElement): FocusVisibleUtility =>
8078  ref . addEventListener ( 'focusin' ,  onFocusin ) ; 
8179  ref . addEventListener ( 'focusout' ,  onFocusout ) ; 
8280  ref . addEventListener ( 'pointerdown' ,  pointerDown ,  {  passive : true  } ) ; 
83-   ref . addEventListener ( 'touchstart' ,  pointerDown ,  {  passive : true  } ) ; 
84-   ref . addEventListener ( 'mousedown' ,  pointerDown ) ; 
8581
8682  const  destroy  =  ( )  =>  { 
8783    ref . removeEventListener ( 'keydown' ,  onKeydown ) ; 
8884    ref . removeEventListener ( 'focusin' ,  onFocusin ) ; 
8985    ref . removeEventListener ( 'focusout' ,  onFocusout ) ; 
9086    ref . removeEventListener ( 'pointerdown' ,  pointerDown ) ; 
91-     ref . removeEventListener ( 'touchstart' ,  pointerDown ) ; 
92-     ref . removeEventListener ( 'mousedown' ,  pointerDown ) ; 
9387  } ; 
9488
9589  return  { 
0 commit comments