import React, {useImperativeHandle} from 'react' import { FlatList, type FlatListProps, type GestureResponderEvent, type StyleProp, TouchableWithoutFeedback, View, type ViewStyle, } from 'react-native' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {DismissableLayer, FocusGuards, FocusScope} from 'radix-ui/internal' import {RemoveScrollBar} from 'react-remove-scroll-bar' import {logger} from '#/logger' import {useA11y} from '#/state/a11y' import {useDialogStateControlContext} from '#/state/dialogs' import {atoms as a, flatten, useBreakpoints, useTheme, web} from '#/alf' import {Button, ButtonIcon} from '#/components/Button' import {Context} from '#/components/Dialog/context' import { type DialogControlProps, type DialogInnerProps, type DialogOuterProps, } from '#/components/Dialog/types' import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' import {Portal} from '#/components/Portal' export {useDialogContext, useDialogControl} from '#/components/Dialog/context' export * from '#/components/Dialog/shared' export * from '#/components/Dialog/types' export * from '#/components/Dialog/utils' export {Input} from '#/components/forms/TextField' const stopPropagation = (e: any) => e.stopPropagation() const preventDefault = (e: any) => e.preventDefault() export function Outer({ children, control, onClose, webOptions, }: React.PropsWithChildren) { const {_} = useLingui() const {gtMobile} = useBreakpoints() const [isOpen, setIsOpen] = React.useState(false) const {setDialogIsOpen} = useDialogStateControlContext() const open = React.useCallback(() => { setDialogIsOpen(control.id, true) setIsOpen(true) }, [setIsOpen, setDialogIsOpen, control.id]) const close = React.useCallback( cb => { setDialogIsOpen(control.id, false) setIsOpen(false) try { if (cb && typeof cb === 'function') { // This timeout ensures that the callback runs at the same time as it would on native. I.e. // console.log('Step 1') -> close(() => console.log('Step 3')) -> console.log('Step 2') // This should always output 'Step 1', 'Step 2', 'Step 3', but without the timeout it would output // 'Step 1', 'Step 3', 'Step 2'. setTimeout(cb) } } catch (e: any) { logger.error(`Dialog closeCallback failed`, { message: e.message, }) } onClose?.() }, [control.id, onClose, setDialogIsOpen], ) const handleBackgroundPress = React.useCallback( async (e: GestureResponderEvent) => { webOptions?.onBackgroundPress ? webOptions.onBackgroundPress(e) : close() }, [webOptions, close], ) useImperativeHandle( control.ref, () => ({ open, close, }), [close, open], ) const context = React.useMemo( () => ({ close, isNativeDialog: false, nativeSnapPoint: 0, disableDrag: false, setDisableDrag: () => {}, isWithinDialog: true, }), [close], ) return ( <> {isOpen && ( {/** * This is needed to prevent centered dialogs from overflowing * above the screen, and provides a "natural" centering so that * stacked dialogs appear relatively aligned. */} {children} )} ) } export function Inner({ children, style, label, accessibilityLabelledBy, accessibilityDescribedBy, header, contentContainerStyle, }: DialogInnerProps) { const t = useTheme() const {close} = React.useContext(Context) const {gtMobile} = useBreakpoints() const {reduceMotionEnabled} = useA11y() FocusGuards.useFocusGuards() return ( true} onTouchEnd={stopPropagation} style={flatten([ a.relative, a.rounded_md, a.w_full, a.border, t.atoms.bg, { maxWidth: 600, borderColor: t.palette.contrast_200, shadowColor: t.palette.black, shadowOpacity: t.name === 'light' ? 0.1 : 0.4, shadowRadius: 30, }, !reduceMotionEnabled && a.zoom_fade_in, style, ])}> {header} {children} ) } export const ScrollableInner = Inner export const InnerFlatList = React.forwardRef< FlatList, FlatListProps & {label: string} & { webInnerStyle?: StyleProp webInnerContentContainerStyle?: StyleProp } >(function InnerFlatList( {label, style, webInnerStyle, webInnerContentContainerStyle, ...props}, ref, ) { const {gtMobile} = useBreakpoints() return ( ) }) export function Close() { const {_} = useLingui() const {close} = React.useContext(Context) return ( ) } export function Handle() { return null } function Backdrop() { const t = useTheme() const {reduceMotionEnabled} = useA11y() return ( ) }