🐛 Handle middle mouse click on feed list items (#1469)
* 🐛 Handle middle mouse click on feed list items * ♻️ Refactor the event listener and turn it into a dedicated hook for web * 🧹 Cleanup unnecessary Link changes * Fix import * Create native version of useAuxClick --------- Co-authored-by: Paul Frazee <pfrazee@gmail.com>zio/stable
parent
255beb0c1f
commit
3c4899b3c4
|
@ -0,0 +1,2 @@
|
||||||
|
// does nothing in native
|
||||||
|
export const useAuxClick = () => {}
|
|
@ -0,0 +1,43 @@
|
||||||
|
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])
|
||||||
|
}
|
|
@ -59,6 +59,7 @@ export const Link = observer(function Link({
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const navigation = useNavigation<NavigationProp>()
|
const navigation = useNavigation<NavigationProp>()
|
||||||
|
const anchorHref = asAnchor ? sanitizeUrl(href) : undefined
|
||||||
|
|
||||||
const onPress = React.useCallback(
|
const onPress = React.useCallback(
|
||||||
(e?: Event) => {
|
(e?: Event) => {
|
||||||
|
@ -96,7 +97,7 @@ export const Link = observer(function Link({
|
||||||
accessibilityRole="link"
|
accessibilityRole="link"
|
||||||
{...props}>
|
{...props}>
|
||||||
{/* @ts-ignore web only -prf */}
|
{/* @ts-ignore web only -prf */}
|
||||||
<View style={style} href={asAnchor ? sanitizeUrl(href) : undefined}>
|
<View style={style} href={anchorHref}>
|
||||||
{children ? children : <Text>{title || 'link'}</Text>}
|
{children ? children : <Text>{title || 'link'}</Text>}
|
||||||
</View>
|
</View>
|
||||||
</TouchableWithoutFeedback>
|
</TouchableWithoutFeedback>
|
||||||
|
@ -123,7 +124,7 @@ export const Link = observer(function Link({
|
||||||
accessible={accessible}
|
accessible={accessible}
|
||||||
accessibilityRole="link"
|
accessibilityRole="link"
|
||||||
// @ts-ignore web only -prf
|
// @ts-ignore web only -prf
|
||||||
href={asAnchor ? sanitizeUrl(href) : undefined}
|
href={anchorHref}
|
||||||
{...props}>
|
{...props}>
|
||||||
{children ? children : <Text>{title || 'link'}</Text>}
|
{children ? children : <Text>{title || 'link'}</Text>}
|
||||||
</Com>
|
</Com>
|
||||||
|
|
|
@ -16,11 +16,13 @@ import {useWebMediaQueries} from '../../lib/hooks/useWebMediaQueries'
|
||||||
import {BottomBarWeb} from './bottom-bar/BottomBarWeb'
|
import {BottomBarWeb} from './bottom-bar/BottomBarWeb'
|
||||||
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'
|
||||||
|
|
||||||
const ShellInner = observer(function ShellInnerImpl() {
|
const ShellInner = observer(function ShellInnerImpl() {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const {isDesktop, isMobile} = useWebMediaQueries()
|
const {isDesktop, isMobile} = useWebMediaQueries()
|
||||||
const navigator = useNavigation<NavigationProp>()
|
const navigator = useNavigation<NavigationProp>()
|
||||||
|
useAuxClick()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
navigator.addListener('state', () => {
|
navigator.addListener('state', () => {
|
||||||
|
|
Loading…
Reference in New Issue