fix web aux click on all browsers (#2633)
parent
2f1ce117d7
commit
065a094087
|
@ -1,2 +0,0 @@
|
||||||
// does nothing in native
|
|
||||||
export const useAuxClick = () => {}
|
|
|
@ -1,43 +0,0 @@
|
||||||
import {useEffect} from 'react'
|
|
||||||
|
|
||||||
// This is the handler for the middle mouse button click on the feed.
|
|
||||||
// Normally, we would do this via `onAuxClick` handler on each link element
|
|
||||||
// However, that handler is not supported on react-native-web and there are some
|
|
||||||
// discrepancies between various browsers (i.e: safari doesn't trigger it and routes through click event)
|
|
||||||
// So, this temporary alternative is meant to bridge the gap in an efficient way until the support improves.
|
|
||||||
export const useAuxClick = () => {
|
|
||||||
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
|
|
||||||
useEffect(() => {
|
|
||||||
// On the web, it should always be there but in case it gets accidentally included in native builds
|
|
||||||
const wrapperEl = document?.body
|
|
||||||
|
|
||||||
// Safari already handles auxclick event as click+metaKey so we need to avoid doing this there in case it becomes recursive
|
|
||||||
if (wrapperEl && !isSafari) {
|
|
||||||
const handleAuxClick = (e: MouseEvent & {target: HTMLElement}) => {
|
|
||||||
// Only handle the middle mouse button click
|
|
||||||
// Only handle if the clicked element itself or one of its ancestors is a link
|
|
||||||
if (
|
|
||||||
e.button !== 1 ||
|
|
||||||
e.target.closest('a') ||
|
|
||||||
e.target.tagName === 'A'
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// On the original element, trigger a click event with metaKey set to true so that it triggers
|
|
||||||
// the browser's default behavior of opening the link in a new tab
|
|
||||||
e.target.dispatchEvent(
|
|
||||||
new MouseEvent('click', {metaKey: true, bubbles: true}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// @ts-ignore For web only
|
|
||||||
wrapperEl.addEventListener('auxclick', handleAuxClick)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
// @ts-ignore For web only
|
|
||||||
wrapperEl?.removeEventListener('auxclick', handleAuxClick)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [isSafari])
|
|
||||||
}
|
|
|
@ -31,6 +31,7 @@ import {PressableWithHover} from './PressableWithHover'
|
||||||
import FixedTouchableHighlight from '../pager/FixedTouchableHighlight'
|
import FixedTouchableHighlight from '../pager/FixedTouchableHighlight'
|
||||||
import {useModalControls} from '#/state/modals'
|
import {useModalControls} from '#/state/modals'
|
||||||
import {useOpenLink} from '#/state/preferences/in-app-browser'
|
import {useOpenLink} from '#/state/preferences/in-app-browser'
|
||||||
|
import {WebAuxClickWrapper} from 'view/com/util/WebAuxClickWrapper'
|
||||||
|
|
||||||
type Event =
|
type Event =
|
||||||
| React.MouseEvent<HTMLAnchorElement, MouseEvent>
|
| React.MouseEvent<HTMLAnchorElement, MouseEvent>
|
||||||
|
@ -104,17 +105,19 @@ export const Link = memo(function Link({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<TouchableWithoutFeedback
|
<WebAuxClickWrapper>
|
||||||
testID={testID}
|
<TouchableWithoutFeedback
|
||||||
onPress={onPress}
|
testID={testID}
|
||||||
accessible={accessible}
|
onPress={onPress}
|
||||||
accessibilityRole="link"
|
accessible={accessible}
|
||||||
{...props}>
|
accessibilityRole="link"
|
||||||
{/* @ts-ignore web only -prf */}
|
{...props}>
|
||||||
<View style={style} href={anchorHref}>
|
{/* @ts-ignore web only -prf */}
|
||||||
{children ? children : <Text>{title || 'link'}</Text>}
|
<View style={style} href={anchorHref}>
|
||||||
</View>
|
{children ? children : <Text>{title || 'link'}</Text>}
|
||||||
</TouchableWithoutFeedback>
|
</View>
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
|
</WebAuxClickWrapper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {Platform} from 'react-native'
|
||||||
|
|
||||||
|
const onMouseUp = (e: React.MouseEvent & {target: HTMLElement}) => {
|
||||||
|
// Only handle whenever it is the middle button
|
||||||
|
if (e.button !== 1 || e.target.closest('a') || e.target.tagName === 'A') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.target.dispatchEvent(
|
||||||
|
new MouseEvent('click', {metaKey: true, bubbles: true}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onMouseDown = (e: React.MouseEvent) => {
|
||||||
|
// Prevents the middle click scroll from enabling
|
||||||
|
if (e.button !== 1) return
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WebAuxClickWrapper({children}: React.PropsWithChildren<{}>) {
|
||||||
|
if (Platform.OS !== 'web') return children
|
||||||
|
|
||||||
|
return (
|
||||||
|
// @ts-ignore web only
|
||||||
|
<div onMouseDown={onMouseDown} onMouseUp={onMouseUp}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -11,7 +11,6 @@ import {DrawerContent} from './Drawer'
|
||||||
import {useWebMediaQueries} from '../../lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from '../../lib/hooks/useWebMediaQueries'
|
||||||
import {useNavigation} from '@react-navigation/native'
|
import {useNavigation} from '@react-navigation/native'
|
||||||
import {NavigationProp} from 'lib/routes/types'
|
import {NavigationProp} from 'lib/routes/types'
|
||||||
import {useAuxClick} from 'lib/hooks/useAuxClick'
|
|
||||||
import {t} from '@lingui/macro'
|
import {t} from '@lingui/macro'
|
||||||
import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
|
import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
|
||||||
import {useCloseAllActiveElements} from '#/state/util'
|
import {useCloseAllActiveElements} from '#/state/util'
|
||||||
|
@ -26,7 +25,6 @@ function ShellInner() {
|
||||||
const closeAllActiveElements = useCloseAllActiveElements()
|
const closeAllActiveElements = useCloseAllActiveElements()
|
||||||
|
|
||||||
useWebBodyScrollLock(isDrawerOpen)
|
useWebBodyScrollLock(isDrawerOpen)
|
||||||
useAuxClick()
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribe = navigator.addListener('state', () => {
|
const unsubscribe = navigator.addListener('state', () => {
|
||||||
|
|
Loading…
Reference in New Issue