import React, {useImperativeHandle} from 'react' import {StyleProp, View, ViewStyle} from 'react-native' import {useSafeAreaInsets} from 'react-native-safe-area-context' import { BottomSheetFlatList, BottomSheetFlatListMethods, BottomSheetTextInput, BottomSheetView, } from '@discord/bottom-sheet/src' import {BottomSheetFlatListProps} from '@discord/bottom-sheet/src/components/bottomSheetScrollable/types' import {BlueskyBottomSheetView} from '@haileyok/bluesky-bottom-sheet' import {logger} from '#/logger' import {useDialogStateControlContext} from '#/state/dialogs' import {ScrollView} from '#/view/com/util/Views' import {atoms as a, flatten, useTheme} from '#/alf' import {Context} from '#/components/Dialog/context' import { DialogControlProps, DialogInnerProps, DialogOuterProps, } from '#/components/Dialog/types' import {createInput} from '#/components/forms/TextField' import {Portal} from '#/components/Portal' export {useDialogContext, useDialogControl} from '#/components/Dialog/context' export * from '#/components/Dialog/types' export * from '#/components/Dialog/utils' // @ts-ignore export const Input = createInput(BottomSheetTextInput) export function Outer({ children, control, onClose, nativeOptions, testID, }: React.PropsWithChildren) { const t = useTheme() const ref = React.useRef(null) const insets = useSafeAreaInsets() const closeCallbacks = React.useRef<(() => void)[]>([]) const {setDialogIsOpen} = useDialogStateControlContext() const callQueuedCallbacks = React.useCallback(() => { for (const cb of closeCallbacks.current) { try { cb() } catch (e: any) { logger.error('Error running close callback', e) } } closeCallbacks.current = [] }, []) const open = React.useCallback(() => { // Run any leftover callbacks that might have been queued up before calling `.open()` callQueuedCallbacks() setDialogIsOpen(control.id, true) ref.current?.present() }, [setDialogIsOpen, control.id, callQueuedCallbacks]) // This is the function that we call when we want to dismiss the dialog. const close = React.useCallback(cb => { if (typeof cb === 'function') { closeCallbacks.current.push(cb) } ref.current?.dismiss() }, []) // This is the actual thing we are doing once we "confirm" the dialog. We want the dialog's close animation to // happen before we run this. It is passed to the `BottomSheet` component. const onCloseAnimationComplete = React.useCallback(() => { // This removes the dialog from our list of stored dialogs. Not super necessary on iOS, but on Android this // tells us that we need to toggle the accessibility overlay setting setDialogIsOpen(control.id, false) callQueuedCallbacks() onClose?.() }, [callQueuedCallbacks, control.id, onClose, setDialogIsOpen]) useImperativeHandle( control.ref, () => ({ open, close, }), [open, close], ) const context = React.useMemo(() => ({close}), [close]) return ( { if (e.nativeEvent.state === 'closed') { onCloseAnimationComplete() } }} cornerRadius={20} {...nativeOptions}> {children} ) } export function Inner({children, style}: DialogInnerProps) { const insets = useSafeAreaInsets() return ( {children} ) } export const ScrollableInner = React.forwardRef( function ScrollableInner({children, style}, ref) { const insets = useSafeAreaInsets() return ( {children} ) }, ) export const InnerFlatList = React.forwardRef< BottomSheetFlatListMethods, BottomSheetFlatListProps & {webInnerStyle?: StyleProp} >(function InnerFlatList({style, contentContainerStyle, ...props}, ref) { const insets = useSafeAreaInsets() return ( } ref={ref} {...props} style={[ a.flex_1, a.p_xl, a.pt_0, a.h_full, { marginTop: 40, }, flatten(style), ]} /> ) }) export function Close() { return null }