From 3b8b5622688807f6d04c52cbd4d6977b203b75b3 Mon Sep 17 00:00:00 2001
From: Ansh <anshnanda10@gmail.com>
Date: Fri, 28 Jul 2023 14:00:37 -0700
Subject: [APP-737] Accessible native dropdown menu (#988)

* fix comments

* add zeego package

* get basic native dropdown working

* add separator and icon components

* refined native dropdown component

* add android build properties to app.json

* move `PostDropdownBtn` to its own component

* fix selectors issue

* move `PostDropdownBtn` to its own component

* fix hitslop

* fix post dropdown hitslop

* fix android dropdown icons

* move `UserAvatar.tsx` to native dropdown

* use native dropdown in `ProfileHeader.tsx`

* use native dropdown in `PostThreadItem.tsx`

* use native dropdown in `UserBanner.tsx`

* use native dropdown in `CustomFeed.tsx`

* replace `testId` with `testID` (which is what is used everywhere)

* move `Settings.tsx` to use native dropdown

* create jest mocks for zeego

* create jest mock for `zeego/dropdown-menu`

* web styles for native dropdown

* remove example native dropdown

* adjust web styles

* fix propagation

* fix pressable in `Settings.tsx`

* animate dropdown on web

* add keyboard nav and hover styles

* add hitslop to constants

* add comments to NativeDropdown component

* temporarily removed android icons

* add testID to PostDropdownBtn

* add testID back to all NativeDropdown button implementations

* add postDropdownBtn testID

* add testID to dropdown items

* remove testID from dropdown menu item

* refactor home-screen tests for native dropdown

* refactor profile-screen tests for native dropdown

* refactor thread-muting tests for native dropdown

* refactor thread-screen tests for native dropdown

* fix dropdown color for post dropdown button

* remove icons from android dropdown menu

* fix `create-account.test.ts`

* fix `invite-codes.test.ts`
---
 src/view/com/util/forms/DropdownButton.tsx | 125 ++---------------------------
 1 file changed, 8 insertions(+), 117 deletions(-)

(limited to 'src/view/com/util/forms/DropdownButton.tsx')

diff --git a/src/view/com/util/forms/DropdownButton.tsx b/src/view/com/util/forms/DropdownButton.tsx
index 046610b29..a1ee3d589 100644
--- a/src/view/com/util/forms/DropdownButton.tsx
+++ b/src/view/com/util/forms/DropdownButton.tsx
@@ -14,14 +14,10 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {Text} from '../text/Text'
 import {Button, ButtonType} from './Button'
 import {colors} from 'lib/styles'
-import {toShareUrl} from 'lib/strings/url-helpers'
-import {useStores} from 'state/index'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useTheme} from 'lib/ThemeContext'
-import {isWeb} from 'platform/detection'
-import {shareUrl} from 'lib/sharing'
+import {HITSLOP_10} from 'lib/constants'
 
-const HITSLOP = {left: 10, top: 10, right: 10, bottom: 10}
 const ESTIMATED_BTN_HEIGHT = 50
 const ESTIMATED_SEP_HEIGHT = 16
 const ESTIMATED_HEADING_HEIGHT = 60
@@ -140,7 +136,7 @@ export function DropdownButton({
         testID={testID}
         style={style}
         onPress={onPress}
-        hitSlop={HITSLOP}
+        hitSlop={HITSLOP_10}
         ref={ref1}
         accessibilityRole="button"
         accessibilityLabel={accessibilityLabel || `Opens ${numItems} options`}
@@ -163,112 +159,6 @@ export function DropdownButton({
   )
 }
 
-export function PostDropdownBtn({
-  testID,
-  style,
-  children,
-  itemUri,
-  itemCid,
-  itemHref,
-  isAuthor,
-  isThreadMuted,
-  onCopyPostText,
-  onOpenTranslate,
-  onToggleThreadMute,
-  onDeletePost,
-}: {
-  testID?: string
-  style?: StyleProp<ViewStyle>
-  children?: React.ReactNode
-  itemUri: string
-  itemCid: string
-  itemHref: string
-  itemTitle: string
-  isAuthor: boolean
-  isThreadMuted: boolean
-  onCopyPostText: () => void
-  onOpenTranslate: () => void
-  onToggleThreadMute: () => void
-  onDeletePost: () => void
-}) {
-  const store = useStores()
-
-  const dropdownItems: DropdownItem[] = [
-    {
-      testID: 'postDropdownTranslateBtn',
-      icon: 'language',
-      label: 'Translate...',
-      onPress() {
-        onOpenTranslate()
-      },
-    },
-    {
-      testID: 'postDropdownCopyTextBtn',
-      icon: ['far', 'paste'],
-      label: 'Copy post text',
-      onPress() {
-        onCopyPostText()
-      },
-    },
-    {
-      testID: 'postDropdownShareBtn',
-      icon: 'share',
-      label: 'Share...',
-      onPress() {
-        const url = toShareUrl(itemHref)
-        shareUrl(url)
-      },
-    },
-    {sep: true},
-    {
-      testID: 'postDropdownMuteThreadBtn',
-      icon: 'comment-slash',
-      label: isThreadMuted ? 'Unmute thread' : 'Mute thread',
-      onPress() {
-        onToggleThreadMute()
-      },
-    },
-    {sep: true},
-    !isAuthor && {
-      testID: 'postDropdownReportBtn',
-      icon: 'circle-exclamation',
-      label: 'Report post',
-      onPress() {
-        store.shell.openModal({
-          name: 'report-post',
-          postUri: itemUri,
-          postCid: itemCid,
-        })
-      },
-    },
-    isAuthor && {
-      testID: 'postDropdownDeleteBtn',
-      icon: ['far', 'trash-can'],
-      label: 'Delete post',
-      onPress() {
-        store.shell.openModal({
-          name: 'confirm',
-          title: 'Delete this post?',
-          message: 'Are you sure? This can not be undone.',
-          onPressConfirm: onDeletePost,
-        })
-      },
-    },
-  ].filter(Boolean) as DropdownItem[]
-
-  return (
-    <DropdownButton
-      testID={testID}
-      style={style}
-      items={dropdownItems}
-      menuWidth={isWeb ? 220 : 200}
-      accessibilityLabel="Additional post actions"
-      accessibilityHint="">
-      {children}
-    </DropdownButton>
-  )
-}
-
 function createDropdownMenu(
   x: number,
   y: number,
@@ -324,15 +214,16 @@ const DropdownItems = ({
 
   const numItems = items.filter(isBtn).length
 
+  // TODO: Refactor dropdown components to:
+  // - (On web, if not handled by React Native) use semantic <select />
+  // and <option /> elements for keyboard navigation out of the box
+  // - (On mobile) be buttons by default, accept `label` and `nativeID`
+  // props, and always have an explicit label
   return (
     <>
+      {/* This TouchableWithoutFeedback renders the background so if the user clicks outside, the dropdown closes */}
       <TouchableWithoutFeedback
         onPress={onOuterPress}
-        // TODO: Refactor dropdown components to:
-        // - (On web, if not handled by React Native) use semantic <select />
-        // and <option /> elements for keyboard navigation out of the box
-        // - (On mobile) be buttons by default, accept `label` and `nativeID`
-        // props, and always have an explicit label
         accessibilityRole="button"
         accessibilityLabel="Toggle dropdown"
         accessibilityHint="">
-- 
cgit 1.4.1

