diff --git a/packages/core/src/navigationEvents.ts b/packages/core/src/navigationEvents.ts index def2474a4..30c8909b5 100644 --- a/packages/core/src/navigationEvents.ts +++ b/packages/core/src/navigationEvents.ts @@ -1,19 +1,24 @@ +type MouseNavigationEvent = Pick< + MouseEvent, + 'altKey' | 'ctrlKey' | 'shiftKey' | 'metaKey' | 'button' | 'currentTarget' | 'defaultPrevented' | 'target' +> + +type KeyboardNavigationEvent = Pick + +function isContentEditableOrPrevented(event: KeyboardNavigationEvent | MouseNavigationEvent): boolean { + return (event.target instanceof HTMLElement && event.target.isContentEditable) || event.defaultPrevented +} + /** * Determine if this mouse event should be intercepted for navigation purposes. * Links with modifier keys or non-left clicks should not be intercepted. * Content editable elements and prevented events are ignored. */ -export function shouldIntercept( - event: Pick< - MouseEvent, - 'altKey' | 'ctrlKey' | 'defaultPrevented' | 'target' | 'currentTarget' | 'metaKey' | 'shiftKey' | 'button' - >, -): boolean { +export function shouldIntercept(event: MouseNavigationEvent): boolean { const isLink = (event.currentTarget as HTMLElement).tagName.toLowerCase() === 'a' return !( - (event.target && (event?.target as HTMLElement).isContentEditable) || - event.defaultPrevented || + isContentEditableOrPrevented(event) || (isLink && event.altKey) || (isLink && event.ctrlKey) || (isLink && event.metaKey) || @@ -27,8 +32,8 @@ export function shouldIntercept( * Enter triggers navigation for both links and buttons currently. * Space only triggers navigation for buttons specifically. */ -export function shouldNavigate(event: Pick): boolean { +export function shouldNavigate(event: KeyboardNavigationEvent): boolean { const isButton = (event.currentTarget as HTMLElement).tagName.toLowerCase() === 'button' - return event.key === 'Enter' || (isButton && event.key === ' ') + return !isContentEditableOrPrevented(event) && (event.key === 'Enter' || (isButton && event.key === ' ')) } diff --git a/packages/react/src/Link.ts b/packages/react/src/Link.ts index ad2a1dc97..a16d25dba 100755 --- a/packages/react/src/Link.ts +++ b/packages/react/src/Link.ts @@ -16,7 +16,7 @@ const noop = () => undefined interface BaseInertiaLinkProps extends LinkComponentBaseProps { as?: ElementType - onClick?: (event: React.MouseEvent) => void + onClick?: (event: React.MouseEvent) => void } export type InertiaLinkProps = BaseInertiaLinkProps & @@ -181,7 +181,7 @@ const Link = forwardRef( }, prefetchModes) const regularEvents = { - onClick: (event) => { + onClick: (event: React.MouseEvent) => { onClick(event) if (shouldIntercept(event)) { @@ -205,29 +205,29 @@ const Link = forwardRef( } const prefetchClickEvents = { - onMouseDown: (event) => { + onMouseDown: (event: React.MouseEvent) => { if (shouldIntercept(event)) { event.preventDefault() doPrefetch() } }, - onKeyDown: (event) => { - if (shouldIntercept(event) && shouldNavigate(event)) { + onKeyDown: (event: React.KeyboardEvent) => { + if (shouldNavigate(event)) { event.preventDefault() doPrefetch() } }, - onMouseUp: (event) => { + onMouseUp: (event: React.MouseEvent) => { event.preventDefault() router.visit(url, visitParams) }, - onKeyUp: (event) => { + onKeyUp: (event: React.KeyboardEvent) => { if (shouldNavigate(event)) { event.preventDefault() router.visit(url, visitParams) } }, - onClick: (event) => { + onClick: (event: React.MouseEvent) => { onClick(event) if (shouldIntercept(event)) { diff --git a/packages/svelte/src/link.ts b/packages/svelte/src/link.ts index b80c6ebb7..d3ac017a4 100644 --- a/packages/svelte/src/link.ts +++ b/packages/svelte/src/link.ts @@ -62,7 +62,7 @@ function link( let visitParams: VisitOptions const regularEvents: ActionEventHandlers = { - click: (event) => { + click: (event: MouseEvent) => { if (shouldIntercept(event)) { event.preventDefault() router.visit(href, visitParams) @@ -77,29 +77,29 @@ function link( } const prefetchClickEvents: ActionEventHandlers = { - mousedown: (event) => { + mousedown: (event: MouseEvent) => { if (shouldIntercept(event)) { event.preventDefault() prefetch() } }, - keydown: (event) => { - if (shouldIntercept(event) && shouldNavigate(event)) { + keydown: (event: KeyboardEvent) => { + if (shouldNavigate(event)) { event.preventDefault() prefetch() } }, - mouseup: (event) => { + mouseup: (event: MouseEvent) => { event.preventDefault() router.visit(href, visitParams) }, - keyup: (event) => { + keyup: (event: KeyboardEvent) => { if (shouldNavigate(event)) { event.preventDefault() router.visit(href, visitParams) } }, - click: (event) => { + click: (event: MouseEvent) => { if (shouldIntercept(event)) { // Let the mouseup/keyup event handle the visit event.preventDefault() diff --git a/packages/vue3/src/link.ts b/packages/vue3/src/link.ts index bd69021d8..6fc25d21b 100755 --- a/packages/vue3/src/link.ts +++ b/packages/vue3/src/link.ts @@ -258,7 +258,7 @@ const Link: InertiaLink = defineComponent({ } const regularEvents = { - onClick: (event) => { + onClick: (event: MouseEvent) => { if (shouldIntercept(event)) { event.preventDefault() router.visit(href.value, visitParams.value) @@ -279,29 +279,29 @@ const Link: InertiaLink = defineComponent({ } const prefetchClickEvents = { - onMousedown: (event) => { + onMousedown: (event: MouseEvent) => { if (shouldIntercept(event)) { event.preventDefault() prefetch() } }, - onKeydown: (event) => { - if (shouldIntercept(event) && shouldNavigate(event)) { + onKeydown: (event: KeyboardEvent) => { + if (shouldNavigate(event)) { event.preventDefault() prefetch() } }, - onMouseup: (event) => { + onMouseup: (event: MouseEvent) => { event.preventDefault() router.visit(href.value, visitParams.value) }, - onKeyup: (event) => { + onKeyup: (event: KeyboardEvent) => { if (shouldNavigate(event)) { event.preventDefault() router.visit(href.value, visitParams.value) } }, - onClick: (event) => { + onClick: (event: MouseEvent) => { if (shouldIntercept(event)) { // Let the mouseup/keyup event handle the visit event.preventDefault()