import React, {useContext, useMemo} from 'react' import {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native' import {HITSLOP_10} from '#/lib/constants' import {atoms as a, useTheme, ViewStyleProp} from '#/alf' import * as Button from '#/components/Button' import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRightIcon} from '#/components/icons/Chevron' import {Link, LinkProps} from '#/components/Link' import {createPortalGroup} from '#/components/Portal' import {Text} from '#/components/Typography' const ItemContext = React.createContext({ destructive: false, withinGroup: false, }) const Portal = createPortalGroup() export function Container({children}: {children: React.ReactNode}) { return {children} } /** * This uses `Portal` magic ✨ to render the icons and title correctly. ItemIcon and ItemText components * get teleported to the top row, leaving the rest of the children in the bottom row. */ export function Group({ children, destructive = false, iconInset = true, style, contentContainerStyle, }: { children: React.ReactNode destructive?: boolean iconInset?: boolean style?: StyleProp contentContainerStyle?: StyleProp }) { const context = useMemo( () => ({destructive, withinGroup: true}), [destructive], ) return ( {children} ) } export function Item({ children, destructive, iconInset = false, style, }: { children?: React.ReactNode destructive?: boolean /** * Adds left padding so that the content will be aligned with other Items that contain icons * @default false */ iconInset?: boolean style?: StyleProp }) { const context = useContext(ItemContext) const childContext = useMemo(() => { if (typeof destructive !== 'boolean') return context return {...context, destructive} }, [context, destructive]) return ( {children} ) } export function LinkItem({ children, destructive = false, contentContainerStyle, chevronColor, ...props }: LinkProps & { contentContainerStyle?: StyleProp destructive?: boolean chevronColor?: string }) { const t = useTheme() return ( {args => ( {typeof children === 'function' ? children(args) : children} )} ) } export function PressableItem({ children, destructive = false, contentContainerStyle, hoverStyle, ...props }: Button.ButtonProps & { contentContainerStyle?: StyleProp destructive?: boolean }) { const t = useTheme() return ( {args => ( {typeof children === 'function' ? children(args) : children} )} ) } export function ItemIcon({ icon: Comp, size = 'xl', color: colorProp, }: Omit, 'position'> & { color?: string }) { const t = useTheme() const {destructive, withinGroup} = useContext(ItemContext) /* * Copied here from icons/common.tsx so we can tweak if we need to, but * also so that we can calculate transforms. */ const iconSize = { xs: 12, sm: 16, md: 20, lg: 24, xl: 28, '2xl': 32, }[size] const color = colorProp ?? (destructive ? t.palette.negative_500 : t.atoms.text.color) const content = ( ) if (withinGroup) { return {content} } else { return content } } export function ItemText({ // eslint-disable-next-line react/prop-types style, ...props }: React.ComponentProps) { const t = useTheme() const {destructive, withinGroup} = useContext(ItemContext) const content = ( ) if (withinGroup) { return {content} } else { return content } } export function Divider({style}: ViewStyleProp) { const t = useTheme() return ( ) } export function Chevron({color: colorProp}: {color?: string}) { const {destructive} = useContext(ItemContext) const t = useTheme() const color = colorProp ?? (destructive ? t.palette.negative_500 : t.palette.contrast_500) return } export function BadgeText({children}: {children: React.ReactNode}) { const t = useTheme() return ( {children} ) } export function BadgeButton({ label, onPress, }: { label: string onPress: (evt: GestureResponderEvent) => void }) { const t = useTheme() return ( {({pressed}) => ( {label} )} ) }