import { createContext, useCallback, useContext, useLayoutEffect, useMemo, useState, } from 'react' import {View} from 'react-native' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useTheme} from '#/alf' import {atoms as a} from '#/alf' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' import {useInteractionState} from '#/components/hooks/useInteractionState' import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check' import {ChevronTopBottom_Stroke2_Corner0_Rounded as ChevronUpDownIcon} from '#/components/icons/Chevron' import {Text} from '#/components/Typography' import { type ContentProps, type IconProps, type ItemIndicatorProps, type ItemProps, type ItemTextProps, type RootProps, type TriggerProps, type ValueProps, } from './types' type ContextType = { control: Dialog.DialogControlProps } & Pick const Context = createContext(null) Context.displayName = 'SelectContext' const ValueTextContext = createContext< [any, React.Dispatch>] >([undefined, () => {}]) ValueTextContext.displayName = 'ValueTextContext' function useSelectContext() { const ctx = useContext(Context) if (!ctx) { throw new Error('Select components must must be used within a Select.Root') } return ctx } export function Root({children, value, onValueChange, disabled}: RootProps) { const control = Dialog.useDialogControl() const valueTextCtx = useState() const ctx = useMemo( () => ({ control, value, onValueChange, disabled, }), [control, value, onValueChange, disabled], ) return ( {children} ) } export function Trigger({children, label}: TriggerProps) { const {control} = useSelectContext() const {state: focused, onIn: onFocus, onOut: onBlur} = useInteractionState() const { state: pressed, onIn: onPressIn, onOut: onPressOut, } = useInteractionState() if (typeof children === 'function') { return children({ isNative: true, control, state: { hovered: false, focused, pressed, }, props: { onPress: control.open, onFocus, onBlur, onPressIn, onPressOut, accessibilityLabel: label, }, }) } else { return ( ) } } export function ValueText({ placeholder, children = value => value.label, style, }: ValueProps) { const [value] = useContext(ValueTextContext) const t = useTheme() let text = value && children(value) if (typeof text !== 'string') text = placeholder return ( {text} ) } export function Icon({}: IconProps) { return } export function Content({ items, valueExtractor = defaultItemValueExtractor, ...props }: ContentProps) { const {control, ...context} = useSelectContext() const [, setValue] = useContext(ValueTextContext) useLayoutEffect(() => { const item = items.find(item => valueExtractor(item) === context.value) if (item) { setValue(item) } }, [items, context.value, valueExtractor, setValue]) return ( ) } function ContentInner({ items, renderItem, valueExtractor, ...context }: ContentProps & ContextType) { const control = Dialog.useDialogContext() const {_} = useLingui() const [headerHeight, setHeaderHeight] = useState(50) const render = useCallback( ({item, index}: {item: T; index: number}) => { return renderItem(item, index, context.value) }, [renderItem, context.value], ) const doneButton = useCallback( () => ( ), [control, _], ) return ( setHeaderHeight(evt.nativeEvent.layout.height)} style={[a.absolute, a.top_0, a.left_0, a.right_0, a.z_10]}> Select an option ) } function defaultItemValueExtractor(item: any) { return item.value } const ItemContext = createContext<{ selected: boolean hovered: boolean focused: boolean pressed: boolean }>({ selected: false, hovered: false, focused: false, pressed: false, }) ItemContext.displayName = 'SelectItemContext' export function useItemContext() { return useContext(ItemContext) } export function Item({children, value, label, style}: ItemProps) { const t = useTheme() const control = Dialog.useDialogContext() const {value: selected, onValueChange} = useSelectContext() return ( ) } export function ItemText({children}: ItemTextProps) { const {selected} = useItemContext() const t = useTheme() // eslint-disable-next-line bsky-internal/avoid-unwrapped-text return ( {children} ) } export function ItemIndicator({icon: Icon = CheckIcon}: ItemIndicatorProps) { const {selected} = useItemContext() return {selected && } }