about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/view/com/util/forms/Button.tsx12
-rw-r--r--src/view/com/util/forms/DropdownButton.tsx40
2 files changed, 37 insertions, 15 deletions
diff --git a/src/view/com/util/forms/Button.tsx b/src/view/com/util/forms/Button.tsx
index 8f24f8288..e6e05bb04 100644
--- a/src/view/com/util/forms/Button.tsx
+++ b/src/view/com/util/forms/Button.tsx
@@ -9,15 +9,13 @@ import {
   PressableStateCallbackType,
   ActivityIndicator,
   View,
+  NativeSyntheticEvent,
+  NativeTouchEvent,
 } from 'react-native'
 import {Text} from '../text/Text'
 import {useTheme} from 'lib/ThemeContext'
 import {choose} from 'lib/functions'
 
-type Event =
-  | React.MouseEvent<HTMLAnchorElement, MouseEvent>
-  | GestureResponderEvent
-
 export type ButtonType =
   | 'primary'
   | 'secondary'
@@ -59,7 +57,7 @@ export function Button({
   style?: StyleProp<ViewStyle>
   labelContainerStyle?: StyleProp<ViewStyle>
   labelStyle?: StyleProp<TextStyle>
-  onPress?: () => void | Promise<void>
+  onPress?: (e: NativeSyntheticEvent<NativeTouchEvent>) => void | Promise<void>
   testID?: string
   accessibilityLabel?: string
   accessibilityHint?: string
@@ -148,11 +146,11 @@ export function Button({
 
   const [isLoading, setIsLoading] = React.useState(false)
   const onPressWrapped = React.useCallback(
-    async (event: Event) => {
+    async (event: GestureResponderEvent) => {
       event.stopPropagation()
       event.preventDefault()
       withLoading && setIsLoading(true)
-      await onPress?.()
+      await onPress?.(event)
       withLoading && setIsLoading(false)
     },
     [onPress, withLoading],
diff --git a/src/view/com/util/forms/DropdownButton.tsx b/src/view/com/util/forms/DropdownButton.tsx
index 411b77484..2285b0615 100644
--- a/src/view/com/util/forms/DropdownButton.tsx
+++ b/src/view/com/util/forms/DropdownButton.tsx
@@ -1,10 +1,12 @@
 import React, {PropsWithChildren, useMemo, useRef} from 'react'
 import {
   Dimensions,
+  GestureResponderEvent,
   StyleProp,
   StyleSheet,
   TouchableOpacity,
   TouchableWithoutFeedback,
+  useWindowDimensions,
   View,
   ViewStyle,
 } from 'react-native'
@@ -19,6 +21,7 @@ import {useTheme} from 'lib/ThemeContext'
 import {HITSLOP_10} from 'lib/constants'
 import {useLingui} from '@lingui/react'
 import {msg} from '@lingui/macro'
+import {isWeb} from 'platform/detection'
 
 const ESTIMATED_BTN_HEIGHT = 50
 const ESTIMATED_SEP_HEIGHT = 16
@@ -80,21 +83,22 @@ export function DropdownButton({
   const ref1 = useRef<TouchableOpacity>(null)
   const ref2 = useRef<View>(null)
 
-  const onPress = () => {
+  const onPress = (e: GestureResponderEvent) => {
     const ref = ref1.current || ref2.current
+    const {height: winHeight} = Dimensions.get('window')
+    const pressY = e.nativeEvent.pageY
     ref?.measure(
       (
         _x: number,
         _y: number,
         width: number,
-        height: number,
+        _height: number,
         pageX: number,
         pageY: number,
       ) => {
         if (!menuWidth) {
           menuWidth = 200
         }
-        const winHeight = Dimensions.get('window').height
         let estimatedMenuHeight = 0
         for (const item of items) {
           if (item && isSep(item)) {
@@ -108,13 +112,16 @@ export function DropdownButton({
         const newX = openToRight
           ? pageX + width + rightOffset
           : pageX + width - menuWidth
-        let newY = pageY + height + bottomOffset
+
+        // Add a bit of additional room
+        let newY = pressY + bottomOffset + 20
         if (openUpwards || newY + estimatedMenuHeight > winHeight) {
           newY -= estimatedMenuHeight
         }
         createDropdownMenu(
           newX,
           newY,
+          pageY,
           menuWidth,
           items.filter(v => !!v) as DropdownItem[],
         )
@@ -168,6 +175,7 @@ export function DropdownButton({
 function createDropdownMenu(
   x: number,
   y: number,
+  pageY: number,
   width: number,
   items: DropdownItem[],
 ): RootSiblings {
@@ -185,6 +193,7 @@ function createDropdownMenu(
         onOuterPress={onOuterPress}
         x={x}
         y={y}
+        pageY={pageY}
         width={width}
         items={items}
         onPressItem={onPressItem}
@@ -198,6 +207,7 @@ type DropDownItemProps = {
   onOuterPress: () => void
   x: number
   y: number
+  pageY: number
   width: number
   items: DropdownItem[]
   onPressItem: (index: number) => void
@@ -207,6 +217,7 @@ const DropdownItems = ({
   onOuterPress,
   x,
   y,
+  pageY,
   width,
   items,
   onPressItem,
@@ -214,6 +225,7 @@ const DropdownItems = ({
   const pal = usePalette('default')
   const theme = useTheme()
   const {_} = useLingui()
+  const {height: screenHeight} = useWindowDimensions()
   const dropDownBackgroundColor =
     theme.colorScheme === 'dark' ? pal.btn : pal.view
   const separatorColor =
@@ -233,7 +245,21 @@ const DropdownItems = ({
         onPress={onOuterPress}
         accessibilityLabel={_(msg`Toggle dropdown`)}
         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>
       <View
         style={[
@@ -295,10 +321,8 @@ function isBtn(item: DropdownItem): item is DropdownItemButton {
 const styles = StyleSheet.create({
   bg: {
     position: 'absolute',
-    top: 0,
-    right: 0,
-    bottom: 0,
     left: 0,
+    width: '100%',
     backgroundColor: '#000',
     opacity: 0.1,
   },