Add dismiss backdrop to native dropdowns (#4711)
parent
1a037d3542
commit
a9fe87b842
|
@ -1,13 +1,15 @@
|
||||||
import React from 'react'
|
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 {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import * as DropdownMenu from 'zeego/dropdown-menu'
|
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 {MenuItemCommonProps} from 'zeego/lib/typescript/menu'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
|
||||||
import {isWeb} from 'platform/detection'
|
|
||||||
import {useTheme} from 'lib/ThemeContext'
|
|
||||||
import {HITSLOP_10} from 'lib/constants'
|
import {HITSLOP_10} from 'lib/constants'
|
||||||
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
|
import {isIOS, isWeb} from 'platform/detection'
|
||||||
|
import {Portal} from '#/components/Portal'
|
||||||
|
|
||||||
// Custom Dropdown Menu Components
|
// Custom Dropdown Menu Components
|
||||||
// ==
|
// ==
|
||||||
|
@ -169,74 +171,105 @@ export function NativeDropdown({
|
||||||
}: React.PropsWithChildren<Props>) {
|
}: React.PropsWithChildren<Props>) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
|
const [isOpen, setIsOpen] = React.useState(false)
|
||||||
const dropDownBackgroundColor =
|
const dropDownBackgroundColor =
|
||||||
theme.colorScheme === 'dark' ? pal.btn : pal.viewLight
|
theme.colorScheme === 'dark' ? pal.btn : pal.viewLight
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenuRoot>
|
<>
|
||||||
<DropdownMenuTrigger
|
{isIOS && isOpen && (
|
||||||
action="press"
|
<Portal>
|
||||||
testID={testID}
|
<Backdrop />
|
||||||
accessibilityLabel={accessibilityLabel}
|
</Portal>
|
||||||
accessibilityHint={accessibilityHint}>
|
)}
|
||||||
{children}
|
<DropdownMenuRoot onOpenWillChange={setIsOpen}>
|
||||||
</DropdownMenuTrigger>
|
<DropdownMenuTrigger
|
||||||
<DropdownMenuContent
|
action="press"
|
||||||
style={[styles.content, dropDownBackgroundColor]}
|
testID={testID}
|
||||||
loop>
|
accessibilityLabel={accessibilityLabel}
|
||||||
{items.map((item, index) => {
|
accessibilityHint={accessibilityHint}>
|
||||||
if (item.label === 'separator') {
|
{children}
|
||||||
return (
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuSeparator
|
<DropdownMenuContent
|
||||||
key={getKey(item.label, index, item.testID)}
|
style={[styles.content, dropDownBackgroundColor]}
|
||||||
/>
|
loop>
|
||||||
)
|
{items.map((item, index) => {
|
||||||
}
|
if (item.label === 'separator') {
|
||||||
if (index > 1 && items[index - 1].label === 'separator') {
|
return (
|
||||||
return (
|
<DropdownMenuSeparator
|
||||||
<DropdownMenu.Group key={getKey(item.label, index, item.testID)}>
|
|
||||||
<DropdownMenuItem
|
|
||||||
key={getKey(item.label, index, item.testID)}
|
key={getKey(item.label, index, item.testID)}
|
||||||
onSelect={item.onPress}>
|
/>
|
||||||
<DropdownMenuItemTitle>{item.label}</DropdownMenuItemTitle>
|
)
|
||||||
{item.icon && (
|
}
|
||||||
<DropdownMenuItemIcon
|
if (index > 1 && items[index - 1].label === 'separator') {
|
||||||
ios={item.icon.ios}
|
return (
|
||||||
// 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
|
<DropdownMenu.Group
|
||||||
>
|
key={getKey(item.label, index, item.testID)}>
|
||||||
<FontAwesomeIcon
|
<DropdownMenuItem
|
||||||
icon={item.icon.web}
|
key={getKey(item.label, index, item.testID)}
|
||||||
size={20}
|
onSelect={item.onPress}>
|
||||||
style={[pal.text]}
|
<DropdownMenuItemTitle>{item.label}</DropdownMenuItemTitle>
|
||||||
/>
|
{item.icon && (
|
||||||
</DropdownMenuItemIcon>
|
<DropdownMenuItemIcon
|
||||||
)}
|
ios={item.icon.ios}
|
||||||
</DropdownMenuItem>
|
// 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
|
||||||
</DropdownMenu.Group>
|
>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={item.icon.web}
|
||||||
|
size={20}
|
||||||
|
style={[pal.text]}
|
||||||
|
/>
|
||||||
|
</DropdownMenuItemIcon>
|
||||||
|
)}
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenu.Group>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
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>
|
||||||
)
|
)
|
||||||
}
|
})}
|
||||||
return (
|
</DropdownMenuContent>
|
||||||
<DropdownMenuItem
|
</DropdownMenuRoot>
|
||||||
key={getKey(item.label, index, item.testID)}
|
</>
|
||||||
onSelect={item.onPress}>
|
)
|
||||||
<DropdownMenuItemTitle>{item.label}</DropdownMenuItemTitle>
|
}
|
||||||
{item.icon && (
|
|
||||||
<DropdownMenuItemIcon
|
function Backdrop() {
|
||||||
ios={item.icon.ios}
|
// Not visible but it eats the click outside.
|
||||||
// androidIconName={item.icon.android}
|
// Only necessary for iOS.
|
||||||
>
|
return (
|
||||||
<FontAwesomeIcon
|
<Pressable
|
||||||
icon={item.icon.web}
|
accessibilityRole="button"
|
||||||
size={20}
|
accessibilityLabel="Dialog backdrop"
|
||||||
style={[pal.text]}
|
accessibilityHint="Press the backdrop to close the dialog"
|
||||||
/>
|
style={{
|
||||||
</DropdownMenuItemIcon>
|
top: 0,
|
||||||
)}
|
left: 0,
|
||||||
</DropdownMenuItem>
|
right: 0,
|
||||||
)
|
bottom: 0,
|
||||||
})}
|
position: 'absolute',
|
||||||
</DropdownMenuContent>
|
}}
|
||||||
</DropdownMenuRoot>
|
onPress={() => {
|
||||||
|
/* noop */
|
||||||
|
}}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue