import {createContext, useContext, useMemo} from 'react'
import {
type GestureResponderEvent,
type StyleProp,
View,
type ViewStyle,
} from 'react-native'
import {HITSLOP_10} from '#/lib/constants'
import {atoms as a, useTheme, type ViewStyleProp} from '#/alf'
import * as Button from '#/components/Button'
import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRightIcon} from '#/components/icons/Chevron'
import {Link, type LinkProps} from '#/components/Link'
import {createPortalGroup} from '#/components/Portal'
import {Text} from '#/components/Typography'
const ItemContext = createContext({
destructive: false,
withinGroup: false,
})
ItemContext.displayName = 'SettingsListItemContext'
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
}: Omit & {
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
}: Omit & {
contentContainerStyle?: StyleProp
destructive?: boolean
}) {
const t = useTheme()
return (
{args => (
-
{typeof children === 'function' ? children(args) : children}
)}
)
}
export function ItemIcon({
icon: Comp,
size = 'lg',
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({
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,
style,
}: {
children: React.ReactNode
style?: StyleProp
}) {
const t = useTheme()
return (
{children}
)
}
export function BadgeButton({
label,
onPress,
}: {
label: string
onPress: (evt: GestureResponderEvent) => void
}) {
const t = useTheme()
return (
{({pressed}) => (
{label}
)}
)
}