import React from 'react' import { Platform, Pressable, StyleSheet, View, type ViewStyle, } from 'react-native' import {type IconProp} from '@fortawesome/fontawesome-svg-core' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import * as DropdownMenu from 'zeego/dropdown-menu' import {type MenuItemCommonProps} from 'zeego/lib/typescript/menu' import {usePalette} from '#/lib/hooks/usePalette' import {useTheme} from '#/lib/ThemeContext' import {isIOS} from '#/platform/detection' import {Portal} from '#/components/Portal' // Custom Dropdown Menu Components // == /** * @deprecated use Menu from `#/components/Menu.tsx` instead */ export const DropdownMenuRoot = DropdownMenu.Root // export const DropdownMenuTrigger = DropdownMenu.Trigger /** * @deprecated use Menu from `#/components/Menu.tsx` instead */ export const DropdownMenuContent = DropdownMenu.Content type TriggerProps = Omit< React.ComponentProps<(typeof DropdownMenu)['Trigger']>, 'children' > & React.PropsWithChildren<{ testID?: string accessibilityLabel?: string accessibilityHint?: string }> /** * @deprecated use Menu from `#/components/Menu.tsx` instead */ export const DropdownMenuTrigger = DropdownMenu.create( (props: TriggerProps) => { const theme = useTheme() const defaultCtrlColor = theme.palette.default.postCtrl return ( // This Pressable doesn't actually do anything other than // provide the "pressed state" visual feedback. [{opacity: pressed ? 0.8 : 1}]}> {props.children ? ( props.children ) : ( )} ) }, 'Trigger', ) type ItemProps = React.ComponentProps<(typeof DropdownMenu)['Item']> /** * @deprecated use Menu from `#/components/Menu.tsx` instead */ export const DropdownMenuItem = DropdownMenu.create( (props: ItemProps & {testID?: string}) => { const theme = useTheme() const [focused, setFocused] = React.useState(false) const backgroundColor = theme.colorScheme === 'dark' ? '#fff1' : '#0001' return ( { setFocused(true) props.onFocus && props.onFocus() }} onBlur={() => { setFocused(false) props.onBlur && props.onBlur() }} /> ) }, 'Item', ) type TitleProps = React.ComponentProps<(typeof DropdownMenu)['ItemTitle']> /** * @deprecated use Menu from `#/components/Menu.tsx` instead */ export const DropdownMenuItemTitle = DropdownMenu.create( (props: TitleProps) => { const pal = usePalette('default') return ( ) }, 'ItemTitle', ) type IconProps = React.ComponentProps<(typeof DropdownMenu)['ItemIcon']> /** * @deprecated use Menu from `#/components/Menu.tsx` instead */ export const DropdownMenuItemIcon = DropdownMenu.create((props: IconProps) => { return }, 'ItemIcon') type SeparatorProps = React.ComponentProps<(typeof DropdownMenu)['Separator']> /** * @deprecated use Menu from `#/components/Menu.tsx` instead */ export const DropdownMenuSeparator = DropdownMenu.create( (props: SeparatorProps) => { const pal = usePalette('default') const theme = useTheme() const {borderColor: separatorColor} = theme.colorScheme === 'dark' ? pal.borderDark : pal.border return ( ) }, 'Separator', ) // 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 triggerStyle?: ViewStyle } /** * The `NativeDropdown` function uses native iOS and Android dropdown menus. * It also creates a animated custom dropdown for web that uses * Radix UI primitives under the hood * @prop {DropdownItem[]} items - An array of dropdown items * @prop {React.ReactNode} children - A custom dropdown trigger * * @deprecated use Menu from `#/components/Menu.tsx` instead */ export function NativeDropdown({ items, children, testID, accessibilityLabel, accessibilityHint, }: React.PropsWithChildren) { const pal = usePalette('default') const theme = useTheme() const [isOpen, setIsOpen] = React.useState(false) const dropDownBackgroundColor = theme.colorScheme === 'dark' ? pal.btn : pal.viewLight return ( <> {isIOS && isOpen && ( )} {children} {/* @ts-ignore inheriting props from Radix, which is only for web */} {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 && ( )} ) })} ) } function Backdrop() { // Not visible but it eats the click outside. // Only necessary for iOS. return ( { /* noop */ }} /> ) } const getKey = (label: string, index: number, id?: string) => { if (id) { return id } return `${label}_${index}` } const styles = StyleSheet.create({ separator: { height: 1, marginVertical: 4, }, content: { backgroundColor: '#f0f0f0', borderRadius: 8, paddingVertical: 4, paddingHorizontal: 4, marginTop: 6, ...Platform.select({ web: { animationDuration: '400ms', animationTimingFunction: 'cubic-bezier(0.16, 1, 0.3, 1)', willChange: 'transform, opacity', animationKeyframes: { '0%': {opacity: 0, transform: [{scale: 0.5}]}, '100%': {opacity: 1, transform: [{scale: 1}]}, }, boxShadow: '0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2)', transformOrigin: 'var(--radix-dropdown-menu-content-transform-origin)', }, }), }, item: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', columnGap: 20, // @ts-ignore -web cursor: 'pointer', paddingVertical: 8, paddingHorizontal: 12, borderRadius: 8, }, itemTitle: { fontSize: 18, }, })