about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/components/Menu/index.web.tsx65
-rw-r--r--src/components/Menu/types.ts28
-rw-r--r--src/view/com/util/forms/PostDropdownBtn.tsx37
-rw-r--r--src/view/screens/Storybook/Menus.tsx2
4 files changed, 78 insertions, 54 deletions
diff --git a/src/components/Menu/index.web.tsx b/src/components/Menu/index.web.tsx
index 054e51b01..f23c39ced 100644
--- a/src/components/Menu/index.web.tsx
+++ b/src/components/Menu/index.web.tsx
@@ -1,3 +1,5 @@
+/* eslint-disable react/prop-types */
+
 import React from 'react'
 import {View, Pressable} from 'react-native'
 import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
@@ -14,6 +16,7 @@ import {
   GroupProps,
   ItemTextProps,
   ItemIconProps,
+  RadixPassThroughTriggerProps,
 } from '#/components/Menu/types'
 import {Context} from '#/components/Menu/context'
 
@@ -76,7 +79,24 @@ export function Root({
   )
 }
 
-export function Trigger({children, label, style}: TriggerProps) {
+const RadixTriggerPassThrough = React.forwardRef(
+  (
+    props: {
+      children: (
+        props: RadixPassThroughTriggerProps & {
+          ref: React.Ref<any>
+        },
+      ) => React.ReactNode
+    },
+    ref,
+  ) => {
+    // @ts-expect-error Radix provides no types of this stuff
+    return props.children({...props, ref})
+  },
+)
+RadixTriggerPassThrough.displayName = 'RadixTriggerPassThrough'
+
+export function Trigger({children, label}: TriggerProps) {
   const {control} = React.useContext(Context)
   const {
     state: hovered,
@@ -87,28 +107,27 @@ export function Trigger({children, label, style}: TriggerProps) {
 
   return (
     <DropdownMenu.Trigger asChild>
-      <Pressable
-        accessibilityHint=""
-        accessibilityLabel={label}
-        onFocus={onFocus}
-        onBlur={onBlur}
-        style={flatten([style, focused && web({outline: 0})])}
-        onPointerDown={() => control.open()}
-        {...web({
-          onMouseEnter,
-          onMouseLeave,
-        })}>
-        {children({
-          isNative: false,
-          control,
-          state: {
-            hovered,
-            focused,
-            pressed: false,
-          },
-          props: {},
-        })}
-      </Pressable>
+      <RadixTriggerPassThrough>
+        {props =>
+          children({
+            isNative: false,
+            control,
+            state: {
+              hovered,
+              focused,
+              pressed: false,
+            },
+            props: {
+              ...props,
+              onFocus: onFocus,
+              onBlur: onBlur,
+              onMouseEnter,
+              onMouseLeave,
+              accessibilityLabel: label,
+            },
+          })
+        }
+      </RadixTriggerPassThrough>
     </DropdownMenu.Trigger>
   )
 }
diff --git a/src/components/Menu/types.ts b/src/components/Menu/types.ts
index 2f52e6390..7d04a3344 100644
--- a/src/components/Menu/types.ts
+++ b/src/components/Menu/types.ts
@@ -1,5 +1,9 @@
 import React from 'react'
-import {GestureResponderEvent, PressableProps} from 'react-native'
+import {
+  GestureResponderEvent,
+  PressableProps,
+  AccessibilityProps,
+} from 'react-native'
 
 import {Props as SVGIconProps} from '#/components/icons/common'
 import * as Dialog from '#/components/Dialog'
@@ -9,7 +13,19 @@ export type ContextType = {
   control: Dialog.DialogOuterProps['control']
 }
 
-export type TriggerProps = ViewStyleProp & {
+export type RadixPassThroughTriggerProps = {
+  id: string
+  type: 'button'
+  disabled: boolean
+  ['data-disabled']: boolean
+  ['data-state']: string
+  ['aria-controls']?: string
+  ['aria-haspopup']?: boolean
+  ['aria-expanded']?: AccessibilityProps['aria-expanded']
+  onKeyDown: (e: React.KeyboardEvent) => void
+  onPointerDown: PressableProps['onPointerDown']
+}
+export type TriggerProps = {
   children(props: TriggerChildProps): React.ReactNode
   label: string
 }
@@ -52,7 +68,13 @@ export type TriggerChildProps =
          */
         pressed: false
       }
-      props: {}
+      props: RadixPassThroughTriggerProps & {
+        onFocus: () => void
+        onBlur: () => void
+        onMouseEnter: () => void
+        onMouseLeave: () => void
+        accessibilityLabel: string
+      }
     }
 
 export type ItemProps = React.PropsWithChildren<
diff --git a/src/view/com/util/forms/PostDropdownBtn.tsx b/src/view/com/util/forms/PostDropdownBtn.tsx
index 6f2ae55b2..3c1a736f3 100644
--- a/src/view/com/util/forms/PostDropdownBtn.tsx
+++ b/src/view/com/util/forms/PostDropdownBtn.tsx
@@ -1,11 +1,5 @@
 import React, {memo} from 'react'
-import {
-  StyleProp,
-  ViewStyle,
-  Pressable,
-  View,
-  PressableProps,
-} from 'react-native'
+import {StyleProp, ViewStyle, Pressable, PressableProps} from 'react-native'
 import Clipboard from '@react-native-clipboard/clipboard'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {useNavigation} from '@react-navigation/native'
@@ -38,7 +32,7 @@ import {isWeb} from '#/platform/detection'
 import {richTextToString} from '#/lib/strings/rich-text-helpers'
 import {useGlobalDialogsControlContext} from '#/components/dialogs/Context'
 
-import {atoms as a, useTheme as useAlf, web} from '#/alf'
+import {atoms as a, useTheme as useAlf} from '#/alf'
 import * as Menu from '#/components/Menu'
 import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '#/components/icons/Clipboard'
 import {Filter_Stroke2_Corner0_Rounded as Filter} from '#/components/icons/Filter'
@@ -174,29 +168,18 @@ let PostDropdownBtn = ({
       <Menu.Root>
         <Menu.Trigger label={_(msg`Open post options menu`)}>
           {({props, state}) => {
-            const styles = [
-              style,
-              a.rounded_full,
-              (state.hovered || state.focused || state.pressed) && [
-                web({outline: 0}),
-                alf.atoms.bg_contrast_25,
-              ],
-            ]
-            return isWeb ? (
-              <View {...props} testID={testID} style={styles}>
-                <FontAwesomeIcon
-                  icon="ellipsis"
-                  size={20}
-                  color={defaultCtrlColor}
-                  style={{pointerEvents: 'none'}}
-                />
-              </View>
-            ) : (
+            return (
               <Pressable
                 {...props}
                 hitSlop={hitSlop}
                 testID={testID}
-                style={styles}>
+                style={[
+                  style,
+                  a.rounded_full,
+                  (state.hovered || state.pressed) && [
+                    alf.atoms.bg_contrast_50,
+                  ],
+                ]}>
                 <FontAwesomeIcon
                   icon="ellipsis"
                   size={20}
diff --git a/src/view/screens/Storybook/Menus.tsx b/src/view/screens/Storybook/Menus.tsx
index 082fb2b6e..2f2b14721 100644
--- a/src/view/screens/Storybook/Menus.tsx
+++ b/src/view/screens/Storybook/Menus.tsx
@@ -16,7 +16,7 @@ export function Menus() {
     <View style={[a.gap_md]}>
       <View style={[a.flex_row, a.align_start]}>
         <Menu.Root control={menuControl}>
-          <Menu.Trigger label="Open basic menu" style={[a.flex_1]}>
+          <Menu.Trigger label="Open basic menu">
             {({state, props}) => {
               return (
                 <Text