diff options
author | dan <dan.abramov@gmail.com> | 2024-07-01 18:45:15 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-01 18:45:15 +0100 |
commit | a9fe87b842b9e7cfca6f5acbf73aff555ce6eeee (patch) | |
tree | 6b64b303a8df0a126dee1713db18ab1ec94827d1 | |
parent | 1a037d35429b119d1751930068dfcf3b2b94dbde (diff) | |
download | voidsky-a9fe87b842b9e7cfca6f5acbf73aff555ce6eeee.tar.zst |
Add dismiss backdrop to native dropdowns (#4711)
-rw-r--r-- | src/view/com/util/forms/NativeDropdown.tsx | 163 |
1 files changed, 98 insertions, 65 deletions
diff --git a/src/view/com/util/forms/NativeDropdown.tsx b/src/view/com/util/forms/NativeDropdown.tsx index 0a47569f2..c8e5fb2da 100644 --- a/src/view/com/util/forms/NativeDropdown.tsx +++ b/src/view/com/util/forms/NativeDropdown.tsx @@ -1,13 +1,15 @@ import React from 'react' +import {Platform, Pressable, StyleSheet, View, ViewStyle} from 'react-native' +import {IconProp} from '@fortawesome/fontawesome-svg-core' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import * as DropdownMenu from 'zeego/dropdown-menu' -import {Pressable, StyleSheet, Platform, View, ViewStyle} from 'react-native' -import {IconProp} from '@fortawesome/fontawesome-svg-core' import {MenuItemCommonProps} from 'zeego/lib/typescript/menu' + +import {HITSLOP_10} from 'lib/constants' import {usePalette} from 'lib/hooks/usePalette' -import {isWeb} from 'platform/detection' import {useTheme} from 'lib/ThemeContext' -import {HITSLOP_10} from 'lib/constants' +import {isIOS, isWeb} from 'platform/detection' +import {Portal} from '#/components/Portal' // Custom Dropdown Menu Components // == @@ -169,74 +171,105 @@ export function NativeDropdown({ }: React.PropsWithChildren<Props>) { const pal = usePalette('default') const theme = useTheme() + const [isOpen, setIsOpen] = React.useState(false) const dropDownBackgroundColor = theme.colorScheme === 'dark' ? pal.btn : pal.viewLight return ( - <DropdownMenuRoot> - <DropdownMenuTrigger - action="press" - testID={testID} - accessibilityLabel={accessibilityLabel} - accessibilityHint={accessibilityHint}> - {children} - </DropdownMenuTrigger> - <DropdownMenuContent - style={[styles.content, dropDownBackgroundColor]} - loop> - {items.map((item, index) => { - if (item.label === 'separator') { + <> + {isIOS && isOpen && ( + <Portal> + <Backdrop /> + </Portal> + )} + <DropdownMenuRoot onOpenWillChange={setIsOpen}> + <DropdownMenuTrigger + action="press" + testID={testID} + accessibilityLabel={accessibilityLabel} + accessibilityHint={accessibilityHint}> + {children} + </DropdownMenuTrigger> + <DropdownMenuContent + style={[styles.content, dropDownBackgroundColor]} + loop> + {items.map((item, index) => { + if (item.label === 'separator') { + return ( + <DropdownMenuSeparator + key={getKey(item.label, index, item.testID)} + /> + ) + } + if (index > 1 && items[index - 1].label === 'separator') { + return ( + <DropdownMenu.Group + key={getKey(item.label, index, item.testID)}> + <DropdownMenuItem + key={getKey(item.label, index, item.testID)} + onSelect={item.onPress}> + <DropdownMenuItemTitle>{item.label}</DropdownMenuItemTitle> + {item.icon && ( + <DropdownMenuItemIcon + ios={item.icon.ios} + // androidIconName={item.icon.android} TODO: Add custom android icon support, because these ones are based on https://developer.android.com/reference/android/R.drawable.html and they are ugly + > + <FontAwesomeIcon + icon={item.icon.web} + size={20} + style={[pal.text]} + /> + </DropdownMenuItemIcon> + )} + </DropdownMenuItem> + </DropdownMenu.Group> + ) + } return ( - <DropdownMenuSeparator + <DropdownMenuItem key={getKey(item.label, index, item.testID)} - /> - ) - } - if (index > 1 && items[index - 1].label === 'separator') { - return ( - <DropdownMenu.Group key={getKey(item.label, index, item.testID)}> - <DropdownMenuItem - key={getKey(item.label, index, item.testID)} - onSelect={item.onPress}> - <DropdownMenuItemTitle>{item.label}</DropdownMenuItemTitle> - {item.icon && ( - <DropdownMenuItemIcon - ios={item.icon.ios} - // androidIconName={item.icon.android} TODO: Add custom android icon support, because these ones are based on https://developer.android.com/reference/android/R.drawable.html and they are ugly - > - <FontAwesomeIcon - icon={item.icon.web} - size={20} - style={[pal.text]} - /> - </DropdownMenuItemIcon> - )} - </DropdownMenuItem> - </DropdownMenu.Group> + onSelect={item.onPress}> + <DropdownMenuItemTitle>{item.label}</DropdownMenuItemTitle> + {item.icon && ( + <DropdownMenuItemIcon + ios={item.icon.ios} + // androidIconName={item.icon.android} + > + <FontAwesomeIcon + icon={item.icon.web} + size={20} + style={[pal.text]} + /> + </DropdownMenuItemIcon> + )} + </DropdownMenuItem> ) - } - return ( - <DropdownMenuItem - key={getKey(item.label, index, item.testID)} - onSelect={item.onPress}> - <DropdownMenuItemTitle>{item.label}</DropdownMenuItemTitle> - {item.icon && ( - <DropdownMenuItemIcon - ios={item.icon.ios} - // androidIconName={item.icon.android} - > - <FontAwesomeIcon - icon={item.icon.web} - size={20} - style={[pal.text]} - /> - </DropdownMenuItemIcon> - )} - </DropdownMenuItem> - ) - })} - </DropdownMenuContent> - </DropdownMenuRoot> + })} + </DropdownMenuContent> + </DropdownMenuRoot> + </> + ) +} + +function Backdrop() { + // Not visible but it eats the click outside. + // Only necessary for iOS. + return ( + <Pressable + accessibilityRole="button" + accessibilityLabel="Dialog backdrop" + accessibilityHint="Press the backdrop to close the dialog" + style={{ + top: 0, + left: 0, + right: 0, + bottom: 0, + position: 'absolute', + }} + onPress={() => { + /* noop */ + }} + /> ) } |