Display the language selection dialog correctly on web (#2719)

* add event to callback

* position translation button correctly based on press position

* properly place the background

* remove worthless comment
zio/stable
Hailey 2024-02-06 12:51:32 -08:00 committed by GitHub
parent 9ccad0ba6c
commit 52f57b3aec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 37 additions and 15 deletions

View File

@ -9,15 +9,13 @@ import {
PressableStateCallbackType, PressableStateCallbackType,
ActivityIndicator, ActivityIndicator,
View, View,
NativeSyntheticEvent,
NativeTouchEvent,
} from 'react-native' } from 'react-native'
import {Text} from '../text/Text' import {Text} from '../text/Text'
import {useTheme} from 'lib/ThemeContext' import {useTheme} from 'lib/ThemeContext'
import {choose} from 'lib/functions' import {choose} from 'lib/functions'
type Event =
| React.MouseEvent<HTMLAnchorElement, MouseEvent>
| GestureResponderEvent
export type ButtonType = export type ButtonType =
| 'primary' | 'primary'
| 'secondary' | 'secondary'
@ -59,7 +57,7 @@ export function Button({
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
labelContainerStyle?: StyleProp<ViewStyle> labelContainerStyle?: StyleProp<ViewStyle>
labelStyle?: StyleProp<TextStyle> labelStyle?: StyleProp<TextStyle>
onPress?: () => void | Promise<void> onPress?: (e: NativeSyntheticEvent<NativeTouchEvent>) => void | Promise<void>
testID?: string testID?: string
accessibilityLabel?: string accessibilityLabel?: string
accessibilityHint?: string accessibilityHint?: string
@ -148,11 +146,11 @@ export function Button({
const [isLoading, setIsLoading] = React.useState(false) const [isLoading, setIsLoading] = React.useState(false)
const onPressWrapped = React.useCallback( const onPressWrapped = React.useCallback(
async (event: Event) => { async (event: GestureResponderEvent) => {
event.stopPropagation() event.stopPropagation()
event.preventDefault() event.preventDefault()
withLoading && setIsLoading(true) withLoading && setIsLoading(true)
await onPress?.() await onPress?.(event)
withLoading && setIsLoading(false) withLoading && setIsLoading(false)
}, },
[onPress, withLoading], [onPress, withLoading],

View File

@ -1,10 +1,12 @@
import React, {PropsWithChildren, useMemo, useRef} from 'react' import React, {PropsWithChildren, useMemo, useRef} from 'react'
import { import {
Dimensions, Dimensions,
GestureResponderEvent,
StyleProp, StyleProp,
StyleSheet, StyleSheet,
TouchableOpacity, TouchableOpacity,
TouchableWithoutFeedback, TouchableWithoutFeedback,
useWindowDimensions,
View, View,
ViewStyle, ViewStyle,
} from 'react-native' } from 'react-native'
@ -19,6 +21,7 @@ import {useTheme} from 'lib/ThemeContext'
import {HITSLOP_10} from 'lib/constants' import {HITSLOP_10} from 'lib/constants'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {msg} from '@lingui/macro' import {msg} from '@lingui/macro'
import {isWeb} from 'platform/detection'
const ESTIMATED_BTN_HEIGHT = 50 const ESTIMATED_BTN_HEIGHT = 50
const ESTIMATED_SEP_HEIGHT = 16 const ESTIMATED_SEP_HEIGHT = 16
@ -80,21 +83,22 @@ export function DropdownButton({
const ref1 = useRef<TouchableOpacity>(null) const ref1 = useRef<TouchableOpacity>(null)
const ref2 = useRef<View>(null) const ref2 = useRef<View>(null)
const onPress = () => { const onPress = (e: GestureResponderEvent) => {
const ref = ref1.current || ref2.current const ref = ref1.current || ref2.current
const {height: winHeight} = Dimensions.get('window')
const pressY = e.nativeEvent.pageY
ref?.measure( ref?.measure(
( (
_x: number, _x: number,
_y: number, _y: number,
width: number, width: number,
height: number, _height: number,
pageX: number, pageX: number,
pageY: number, pageY: number,
) => { ) => {
if (!menuWidth) { if (!menuWidth) {
menuWidth = 200 menuWidth = 200
} }
const winHeight = Dimensions.get('window').height
let estimatedMenuHeight = 0 let estimatedMenuHeight = 0
for (const item of items) { for (const item of items) {
if (item && isSep(item)) { if (item && isSep(item)) {
@ -108,13 +112,16 @@ export function DropdownButton({
const newX = openToRight const newX = openToRight
? pageX + width + rightOffset ? pageX + width + rightOffset
: pageX + width - menuWidth : pageX + width - menuWidth
let newY = pageY + height + bottomOffset
// Add a bit of additional room
let newY = pressY + bottomOffset + 20
if (openUpwards || newY + estimatedMenuHeight > winHeight) { if (openUpwards || newY + estimatedMenuHeight > winHeight) {
newY -= estimatedMenuHeight newY -= estimatedMenuHeight
} }
createDropdownMenu( createDropdownMenu(
newX, newX,
newY, newY,
pageY,
menuWidth, menuWidth,
items.filter(v => !!v) as DropdownItem[], items.filter(v => !!v) as DropdownItem[],
) )
@ -168,6 +175,7 @@ export function DropdownButton({
function createDropdownMenu( function createDropdownMenu(
x: number, x: number,
y: number, y: number,
pageY: number,
width: number, width: number,
items: DropdownItem[], items: DropdownItem[],
): RootSiblings { ): RootSiblings {
@ -185,6 +193,7 @@ function createDropdownMenu(
onOuterPress={onOuterPress} onOuterPress={onOuterPress}
x={x} x={x}
y={y} y={y}
pageY={pageY}
width={width} width={width}
items={items} items={items}
onPressItem={onPressItem} onPressItem={onPressItem}
@ -198,6 +207,7 @@ type DropDownItemProps = {
onOuterPress: () => void onOuterPress: () => void
x: number x: number
y: number y: number
pageY: number
width: number width: number
items: DropdownItem[] items: DropdownItem[]
onPressItem: (index: number) => void onPressItem: (index: number) => void
@ -207,6 +217,7 @@ const DropdownItems = ({
onOuterPress, onOuterPress,
x, x,
y, y,
pageY,
width, width,
items, items,
onPressItem, onPressItem,
@ -214,6 +225,7 @@ const DropdownItems = ({
const pal = usePalette('default') const pal = usePalette('default')
const theme = useTheme() const theme = useTheme()
const {_} = useLingui() const {_} = useLingui()
const {height: screenHeight} = useWindowDimensions()
const dropDownBackgroundColor = const dropDownBackgroundColor =
theme.colorScheme === 'dark' ? pal.btn : pal.view theme.colorScheme === 'dark' ? pal.btn : pal.view
const separatorColor = const separatorColor =
@ -233,7 +245,21 @@ const DropdownItems = ({
onPress={onOuterPress} onPress={onOuterPress}
accessibilityLabel={_(msg`Toggle dropdown`)} accessibilityLabel={_(msg`Toggle dropdown`)}
accessibilityHint=""> accessibilityHint="">
<View style={[styles.bg]} /> <View
style={[
styles.bg,
// On web we need to adjust the top and bottom relative to the scroll position
isWeb
? {
top: -pageY,
bottom: pageY - screenHeight,
}
: {
top: 0,
bottom: 0,
},
]}
/>
</TouchableWithoutFeedback> </TouchableWithoutFeedback>
<View <View
style={[ style={[
@ -295,10 +321,8 @@ function isBtn(item: DropdownItem): item is DropdownItemButton {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
bg: { bg: {
position: 'absolute', position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0, left: 0,
width: '100%',
backgroundColor: '#000', backgroundColor: '#000',
opacity: 0.1, opacity: 0.1,
}, },