about summary refs log tree commit diff
path: root/src/view/com/util/forms/NativeDropdown.tsx
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-07-28 18:12:21 -0500
committerGitHub <noreply@github.com>2023-07-28 18:12:21 -0500
commit1195f289924ea6263901765e762ff267fa39db9a (patch)
treeb7eb28302ed03f3b065e430d45ce9ce2440a47e2 /src/view/com/util/forms/NativeDropdown.tsx
parent45da8a86c9e4b6993d9b7d8e95c989b97e885108 (diff)
downloadvoidsky-1195f289924ea6263901765e762ff267fa39db9a.tar.zst
Fix keyboard support on the dropdown (#1073)
* Fix: dropdown now supports accessibility labels and keyboard controls

* Fix event propagation around the post dropdown
Diffstat (limited to 'src/view/com/util/forms/NativeDropdown.tsx')
-rw-r--r--src/view/com/util/forms/NativeDropdown.tsx113
1 files changed, 78 insertions, 35 deletions
diff --git a/src/view/com/util/forms/NativeDropdown.tsx b/src/view/com/util/forms/NativeDropdown.tsx
index d8f16ce19..9e6fcaa44 100644
--- a/src/view/com/util/forms/NativeDropdown.tsx
+++ b/src/view/com/util/forms/NativeDropdown.tsx
@@ -1,13 +1,7 @@
 import React from 'react'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import * as DropdownMenu from 'zeego/dropdown-menu'
-import {
-  Pressable,
-  StyleSheet,
-  Platform,
-  StyleProp,
-  ViewStyle,
-} from 'react-native'
+import {Pressable, StyleSheet, Platform, View} from 'react-native'
 import {IconProp} from '@fortawesome/fontawesome-svg-core'
 import {MenuItemCommonProps} from 'zeego/lib/typescript/menu'
 import {usePalette} from 'lib/hooks/usePalette'
@@ -18,16 +12,71 @@ import {HITSLOP_10} from 'lib/constants'
 // Custom Dropdown Menu Components
 // ==
 export const DropdownMenuRoot = DropdownMenu.Root
-export const DropdownMenuTrigger = DropdownMenu.Trigger
+// export const DropdownMenuTrigger = DropdownMenu.Trigger
 export const DropdownMenuContent = DropdownMenu.Content
+
+type TriggerProps = Omit<
+  React.ComponentProps<(typeof DropdownMenu)['Trigger']>,
+  'children'
+> &
+  React.PropsWithChildren<{
+    testID?: string
+    accessibilityLabel?: string
+    accessibilityHint?: string
+  }>
+export const DropdownMenuTrigger = DropdownMenu.create(
+  (props: TriggerProps) => {
+    const theme = useTheme()
+    const defaultCtrlColor = theme.palette.default.postCtrl
+    const ref = React.useRef<View>(null)
+
+    // HACK
+    // fire a click event on the keyboard press to trigger the dropdown
+    // -prf
+    const onPress = isWeb
+      ? (evt: any) => {
+          if (evt instanceof KeyboardEvent) {
+            // @ts-ignore web only -prf
+            ref.current?.click()
+          }
+        }
+      : undefined
+
+    return (
+      <Pressable
+        testID={props.testID}
+        accessibilityRole="button"
+        accessibilityLabel={props.accessibilityLabel}
+        accessibilityHint={props.accessibilityHint}
+        style={({pressed}) => [{opacity: pressed ? 0.5 : 1}]}
+        hitSlop={HITSLOP_10}
+        onPress={onPress}>
+        <DropdownMenu.Trigger action="press">
+          <View ref={ref}>
+            {props.children ? (
+              props.children
+            ) : (
+              <FontAwesomeIcon
+                icon="ellipsis"
+                size={20}
+                color={defaultCtrlColor}
+                style={styles.ellipsis}
+              />
+            )}
+          </View>
+        </DropdownMenu.Trigger>
+      </Pressable>
+    )
+  },
+  'Trigger',
+)
+
 type ItemProps = React.ComponentProps<(typeof DropdownMenu)['Item']>
 export const DropdownMenuItem = DropdownMenu.create(
   (props: ItemProps & {testID?: string}) => {
-    const pal = usePalette('default')
     const theme = useTheme()
     const [focused, setFocused] = React.useState(false)
-    const {borderColor: backgroundColor} =
-      theme.colorScheme === 'dark' ? pal.borderDark : pal.border
+    const backgroundColor = theme.colorScheme === 'dark' ? '#fff1' : '#0001'
 
     return (
       <DropdownMenu.Item
@@ -46,6 +95,7 @@ export const DropdownMenuItem = DropdownMenu.create(
   },
   'Item',
 )
+
 type TitleProps = React.ComponentProps<(typeof DropdownMenu)['ItemTitle']>
 export const DropdownMenuItemTitle = DropdownMenu.create(
   (props: TitleProps) => {
@@ -59,10 +109,12 @@ export const DropdownMenuItemTitle = DropdownMenu.create(
   },
   'ItemTitle',
 )
+
 type IconProps = React.ComponentProps<(typeof DropdownMenu)['ItemIcon']>
 export const DropdownMenuItemIcon = DropdownMenu.create((props: IconProps) => {
   return <DropdownMenu.ItemIcon {...props} />
 }, 'ItemIcon')
+
 type SeparatorProps = React.ComponentProps<(typeof DropdownMenu)['Separator']>
 export const DropdownMenuSeparator = DropdownMenu.create(
   (props: SeparatorProps) => {
@@ -97,8 +149,9 @@ export type DropdownItem = {
 }
 type Props = {
   items: DropdownItem[]
-  children?: React.ReactNode
   testID?: string
+  accessibilityLabel?: string
+  accessibilityHint?: string
 }
 
 /* The `NativeDropdown` function uses native iOS and Android dropdown menus.
@@ -107,36 +160,26 @@ type Props = {
  * @prop {DropdownItem[]} items - An array of dropdown items
  * @prop {React.ReactNode} children - A custom dropdown trigger
  */
-export function NativeDropdown({items, children, testID}: Props) {
+export function NativeDropdown({
+  items,
+  children,
+  testID,
+  accessibilityLabel,
+  accessibilityHint,
+}: React.PropsWithChildren<Props>) {
   const pal = usePalette('default')
   const theme = useTheme()
   const dropDownBackgroundColor =
     theme.colorScheme === 'dark' ? pal.btn : pal.viewLight
-  const defaultCtrlColor = React.useMemo(
-    () => ({
-      color: theme.palette.default.postCtrl,
-    }),
-    [theme],
-  ) as StyleProp<ViewStyle>
 
   return (
     <DropdownMenuRoot>
-      <DropdownMenuTrigger action="press">
-        <Pressable
-          testID={testID}
-          accessibilityRole="button"
-          style={({pressed}) => [{opacity: pressed ? 0.5 : 1}]}
-          hitSlop={HITSLOP_10}>
-          {children ? (
-            children
-          ) : (
-            <FontAwesomeIcon
-              icon="ellipsis"
-              size={20}
-              style={[defaultCtrlColor, styles.ellipsis]}
-            />
-          )}
-        </Pressable>
+      <DropdownMenuTrigger
+        action="press"
+        testID={testID}
+        accessibilityLabel={accessibilityLabel}
+        accessibilityHint={accessibilityHint}>
+        {children}
       </DropdownMenuTrigger>
       <DropdownMenuContent
         style={[styles.content, dropDownBackgroundColor]}