import { isFunction, isNonEmptyString } from '@sniptt/guards'; import { type MouseEvent } from 'react'; import { isDefined } from 'twenty-shared/utils'; import { type RemoteEventHandler } from '@/host/types/RemoteEventHandler'; import { type RequestExternalNavigation } from '@/host/types/RequestExternalNavigation'; import { isExternalNavigationUrl } from '@/host/utils/isExternalNavigationUrl'; const PRIMARY_MOUSE_BUTTON = 0; const MIDDLE_MOUSE_BUTTON = 1; type CreateAnchorNavigationClickHandlerParams = { href: unknown; remoteOnClick: unknown; requestExternalNavigation: RequestExternalNavigation | null; }; export const createAnchorNavigationClickHandler = ({ href, remoteOnClick, requestExternalNavigation, }: CreateAnchorNavigationClickHandlerParams) => (event: MouseEvent) => { // Bound to both onClick and onAuxClick: a middle click opens a new tab // through auxclick, never click. auxclick also fires on right click, which // must stay untouched so the native context menu keeps working. const clickCanOpenNavigation = event.button === PRIMARY_MOUSE_BUTTON || event.button === MIDDLE_MOUSE_BUTTON; if ( isDefined(requestExternalNavigation) && clickCanOpenNavigation && isNonEmptyString(href) && isExternalNavigationUrl(href) ) { event.preventDefault(); requestExternalNavigation({ url: new URL(href, window.location.href).href, }); return; } const clickIsPrimaryActivation = event.button === PRIMARY_MOUSE_BUTTON; if (clickIsPrimaryActivation && isFunction(remoteOnClick)) { (remoteOnClick as RemoteEventHandler)(event); } };