import React from 'react' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import * as DropdownMenu from '@radix-ui/react-dropdown-menu' import {Pressable, StyleSheet, View, Text} from 'react-native' import {IconProp} from '@fortawesome/fontawesome-svg-core' import {MenuItemCommonProps} from 'zeego/lib/typescript/menu' import {usePalette} from 'lib/hooks/usePalette' import {useTheme} from 'lib/ThemeContext' import {HITSLOP_10} from 'lib/constants' // Custom Dropdown Menu Components // == export const DropdownMenuRoot = DropdownMenu.Root export const DropdownMenuContent = DropdownMenu.Content type ItemProps = React.ComponentProps<(typeof DropdownMenu)['Item']> export const DropdownMenuItem = (props: ItemProps & {testID?: string}) => { const theme = useTheme() const [focused, setFocused] = React.useState(false) const backgroundColor = theme.colorScheme === 'dark' ? '#fff1' : '#0001' return ( { setFocused(true) }} onBlur={() => { setFocused(false) }} /> ) } // Types for Dropdown Menu and Items export type DropdownItem = { label: string | 'separator' onPress?: () => void testID?: string icon?: { ios: MenuItemCommonProps['ios'] android: string web: IconProp } } type Props = { items: DropdownItem[] testID?: string accessibilityLabel?: string accessibilityHint?: string } export function NativeDropdown({ items, children, testID, accessibilityLabel, accessibilityHint, }: React.PropsWithChildren) { const pal = usePalette('default') const theme = useTheme() const dropDownBackgroundColor = theme.colorScheme === 'dark' ? pal.btn : pal.view const [open, setOpen] = React.useState(false) const buttonRef = React.useRef(null) const menuRef = React.useRef(null) const {borderColor: separatorColor} = theme.colorScheme === 'dark' ? pal.borderDark : pal.border React.useEffect(() => { function clickHandler(e: MouseEvent) { const t = e.target if (!open) return if (!t) return if (!buttonRef.current || !menuRef.current) return if ( t !== buttonRef.current && !buttonRef.current.contains(t as Node) && t !== menuRef.current && !menuRef.current.contains(t as Node) ) { // prevent clicking through to links beneath dropdown // only applies to mobile web e.preventDefault() e.stopPropagation() // close menu setOpen(false) } } function keydownHandler(e: KeyboardEvent) { if (e.key === 'Escape' && open) { setOpen(false) } } document.addEventListener('click', clickHandler, true) window.addEventListener('keydown', keydownHandler, true) return () => { document.removeEventListener('click', clickHandler, true) window.removeEventListener('keydown', keydownHandler, true) } }, [open, setOpen]) return ( setOpen(o)}> e.preventDefault()}> } testID={testID} accessibilityRole="button" accessibilityLabel={accessibilityLabel} accessibilityHint={accessibilityHint} onPress={() => setOpen(o => !o)} hitSlop={HITSLOP_10}> {children} {items.map((item, index) => { if (item.label === 'separator') { return ( ) } if (index > 1 && items[index - 1].label === 'separator') { return ( {item.label} {item.icon && ( )} ) } return ( {item.label} {item.icon && ( )} ) })} ) } const getKey = (label: string, index: number, id?: string) => { if (id) { return id } return `${label}_${index}` } const styles = StyleSheet.create({ separator: { height: 1, marginTop: 4, marginBottom: 4, }, content: { backgroundColor: '#f0f0f0', borderRadius: 8, paddingTop: 4, paddingBottom: 4, paddingLeft: 4, paddingRight: 4, marginTop: 6, // @ts-ignore web only -prf boxShadow: 'rgba(0, 0, 0, 0.3) 0px 5px 20px', }, item: { display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', columnGap: 20, // @ts-ignore -web cursor: 'pointer', paddingTop: 8, paddingBottom: 8, paddingLeft: 12, paddingRight: 12, borderRadius: 8, }, itemTitle: { fontSize: 16, fontWeight: '500', paddingRight: 10, }, })