From 2440975bd224e4c39b633b21c461cb8b8d3c1f9b Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 28 Feb 2024 20:06:26 -0600 Subject: Integrate new dialogs into old back handling (#3023) --- src/components/Dialog/context.ts | 13 +++++++++---- src/components/Dialog/index.tsx | 8 ++++++-- src/components/Dialog/index.web.tsx | 8 ++++++-- src/components/Dialog/types.ts | 19 +++++++++++++++---- 4 files changed, 36 insertions(+), 12 deletions(-) (limited to 'src/components/Dialog') diff --git a/src/components/Dialog/context.ts b/src/components/Dialog/context.ts index f0c7c983a..eb717d8e2 100644 --- a/src/components/Dialog/context.ts +++ b/src/components/Dialog/context.ts @@ -3,7 +3,7 @@ import React from 'react' import {useDialogStateContext} from '#/state/dialogs' import { DialogContextProps, - DialogControlProps, + DialogControlRefProps, DialogOuterProps, } from '#/components/Dialog/types' @@ -17,7 +17,7 @@ export function useDialogContext() { export function useDialogControl(): DialogOuterProps['control'] { const id = React.useId() - const control = React.useRef({ + const control = React.useRef({ open: () => {}, close: () => {}, }) @@ -32,8 +32,13 @@ export function useDialogControl(): DialogOuterProps['control'] { }, [id, activeDialogs]) return { + id, ref: control, - open: () => control.current.open(), - close: cb => control.current.close(cb), + open: () => { + control.current.open() + }, + close: cb => { + control.current.close(cb) + }, } } diff --git a/src/components/Dialog/index.tsx b/src/components/Dialog/index.tsx index 5c0350274..6dfc24f3b 100644 --- a/src/components/Dialog/index.tsx +++ b/src/components/Dialog/index.tsx @@ -12,6 +12,7 @@ import {useTheme, atoms as a, flatten} from '#/alf' import {Portal} from '#/components/Portal' import {createInput} from '#/components/forms/TextField' import {logger} from '#/logger' +import {useDialogStateContext} from '#/state/dialogs' import { DialogOuterProps, @@ -37,6 +38,7 @@ export function Outer({ const hasSnapPoints = !!sheetOptions.snapPoints const insets = useSafeAreaInsets() const closeCallback = React.useRef<() => void>() + const {openDialogs} = useDialogStateContext() /* * Used to manage open/closed, but index is otherwise handled internally by `BottomSheet` @@ -50,10 +52,11 @@ export function Outer({ const open = React.useCallback( ({index} = {}) => { + openDialogs.current.add(control.id) // can be set to any index of `snapPoints`, but `0` is the first i.e. "open" setOpenIndex(index || 0) }, - [setOpenIndex], + [setOpenIndex, openDialogs, control.id], ) const close = React.useCallback(cb => { @@ -85,11 +88,12 @@ export function Outer({ closeCallback.current = undefined } + openDialogs.current.delete(control.id) onClose?.() setOpenIndex(-1) } }, - [onClose, setOpenIndex], + [onClose, setOpenIndex, openDialogs, control.id], ) const context = React.useMemo(() => ({close}), [close]) diff --git a/src/components/Dialog/index.web.tsx b/src/components/Dialog/index.web.tsx index ff05fed91..32163e735 100644 --- a/src/components/Dialog/index.web.tsx +++ b/src/components/Dialog/index.web.tsx @@ -12,6 +12,7 @@ import {DialogOuterProps, DialogInnerProps} from '#/components/Dialog/types' import {Context} from '#/components/Dialog/context' import {Button, ButtonIcon} from '#/components/Button' import {TimesLarge_Stroke2_Corner0_Rounded as X} from '#/components/icons/Times' +import {useDialogStateContext} from '#/state/dialogs' export {useDialogControl, useDialogContext} from '#/components/Dialog/context' export * from '#/components/Dialog/types' @@ -29,18 +30,21 @@ export function Outer({ const {gtMobile} = useBreakpoints() const [isOpen, setIsOpen] = React.useState(false) const [isVisible, setIsVisible] = React.useState(true) + const {openDialogs} = useDialogStateContext() const open = React.useCallback(() => { setIsOpen(true) - }, [setIsOpen]) + openDialogs.current.add(control.id) + }, [setIsOpen, openDialogs, control.id]) const close = React.useCallback(async () => { setIsVisible(false) await new Promise(resolve => setTimeout(resolve, 150)) setIsOpen(false) setIsVisible(true) + openDialogs.current.delete(control.id) onClose?.() - }, [onClose, setIsOpen]) + }, [onClose, setIsOpen, openDialogs, control.id]) useImperativeHandle( control.ref, diff --git a/src/components/Dialog/types.ts b/src/components/Dialog/types.ts index 161c03734..78dfedf5a 100644 --- a/src/components/Dialog/types.ts +++ b/src/components/Dialog/types.ts @@ -6,11 +6,24 @@ import {ViewStyleProp} from '#/alf' type A11yProps = Required -export type DialogControlProps = { +/** + * Mutated by useImperativeHandle to provide a public API for controlling the + * dialog. The methods here will actually become the handlers defined within + * the `Dialog.Outer` component. + */ +export type DialogControlRefProps = { open: (options?: DialogControlOpenOptions) => void close: (callback?: () => void) => void } +/** + * The return type of the useDialogControl hook. + */ +export type DialogControlProps = DialogControlRefProps & { + id: string + ref: React.RefObject +} + export type DialogContextProps = { close: DialogControlProps['close'] } @@ -26,9 +39,7 @@ export type DialogControlOpenOptions = { } export type DialogOuterProps = { - control: { - ref: React.RefObject - } & DialogControlProps + control: DialogControlProps onClose?: () => void nativeOptions?: { sheet?: Omit -- cgit 1.4.1