@@ -177,20 +177,45 @@ const useTabShortcuts = ({ baseRoute, runtime, tabsRx }: UseTabShortcutsProps) =
177177 } , [ baseRoute , router , runtime , tabsRx ] ) ;
178178} ;
179179
180+ // https://github.com/facebook/react/issues/29832#issuecomment-2490465022
181+ const updateRef = < T , > ( ref : Ref < T > | undefined , node : T | undefined ) => {
182+ if ( ! node ) return ;
183+ if ( typeof ref === 'function' ) ref ( node ) ;
184+ else if ( ref ) ref . current = node ;
185+ } ;
186+
180187export interface UseLinkProps extends ActiveLinkOptions {
181188 children ?: ( ( state : { isActive : boolean ; isTransitioning : boolean } ) => React . ReactNode ) | React . ReactNode ;
189+ onAuxClick ?: ( ) => void ;
182190 ref ?: Ref < unknown > | undefined ;
183191}
184192
185- export const useLink = ( { children, ref, ...props } : UseLinkProps ) => {
186- const _ = useLinkProps ( props , ref as Ref < Element > ) as ComponentProps < 'a' > & Record < string , unknown > ;
193+ export const useLink = ( { children, onAuxClick , ref : refProp , ...props } : UseLinkProps ) => {
194+ const _ = useLinkProps ( props , refProp as Ref < Element > ) as ComponentProps < 'a' > & Record < string , unknown > ;
187195
188196 const isActive = _ [ 'data-status' ] === 'active' ;
189197 const isTransitioning = _ [ 'data-transitioning' ] === 'transitioning' ;
190198
199+ const onAction = fauxEvent ( _ . onClick , { button : 0 } ) ;
200+
201+ const ref = ( node : unknown ) => {
202+ updateRef ( _ . ref , node as HTMLAnchorElement ) ;
203+
204+ let element : HTMLElement | undefined ;
205+ if ( node && typeof node === 'object' && 'addEventListener' in node ) element = node as HTMLElement ;
206+
207+ const onAuxClickHandler = ( event : MouseEvent ) => {
208+ event . preventDefault ( ) ;
209+ if ( onAuxClick ) onAuxClick ( ) ;
210+ else onAction ( ) ;
211+ } ;
212+
213+ element ?. addEventListener ( 'auxclick' , onAuxClickHandler ) ;
214+ return ( ) => element ?. removeEventListener ( 'auxclick' , onAuxClickHandler ) ;
215+ } ;
216+
191217 return {
192- // eslint-disable-next-line @typescript-eslint/no-explicit-any
193- ref : _ . ref as Ref < any > ,
218+ ref,
194219
195220 children : typeof children === 'function' ? children ( { isActive, isTransitioning } ) : children ,
196221 href : _ . href ! ,
@@ -199,7 +224,7 @@ export const useLink = ({ children, ref, ...props }: UseLinkProps) => {
199224 isDisabled : _ [ 'disabled' ] === true ,
200225 isTransitioning,
201226
202- onAction : fauxEvent ( _ . onClick , { button : 0 } ) ,
227+ onAction,
203228 onFocus : fauxEvent ( _ . onFocus ) ,
204229 onHoverEnd : fauxEvent ( _ . onMouseLeave ) ,
205230 onHoverStart : fauxEvent ( _ . onMouseEnter ) ,
@@ -216,7 +241,10 @@ interface TabItemProps extends TabsRouteContext, ToOptions {
216241const TabItem = ( { baseRoute, id, runtime, tab, tabsRx } : TabItemProps ) => {
217242 const removeTab = useRemoveTab ( ) ;
218243
219- const { isActive, ...linkProps } = useLink ( tab . route ) ;
244+ const { isActive, ...linkProps } = useLink ( {
245+ ...tab . route ,
246+ onAuxClick : ( ) => void removeTab ( { baseRoute, id : tab . id , runtime, tabsRx } ) ,
247+ } ) ;
220248
221249 return (
222250 < ListBoxItem
0 commit comments