about summary refs log tree commit diff
path: root/src/components/Dialog
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/Dialog')
-rw-r--r--src/components/Dialog/context.ts13
-rw-r--r--src/components/Dialog/index.tsx23
-rw-r--r--src/components/Dialog/index.web.tsx12
-rw-r--r--src/components/Dialog/types.ts29
4 files changed, 55 insertions, 22 deletions
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<DialogControlProps>({
+  const control = React.useRef<DialogControlRefProps>({
     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 27f43afd3..6dfc24f3b 100644
--- a/src/components/Dialog/index.tsx
+++ b/src/components/Dialog/index.tsx
@@ -11,6 +11,8 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context'
 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,
@@ -36,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`
@@ -49,14 +52,15 @@ export function Outer({
 
   const open = React.useCallback<DialogControlProps['open']>(
     ({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<DialogControlProps['close']>(cb => {
-    if (cb) {
+    if (cb && typeof cb === 'function') {
       closeCallback.current = cb
     }
     sheet.current?.close()
@@ -74,13 +78,22 @@ export function Outer({
   const onChange = React.useCallback(
     (index: number) => {
       if (index === -1) {
-        closeCallback.current?.()
-        closeCallback.current = undefined
+        try {
+          closeCallback.current?.()
+        } catch (e: any) {
+          logger.error(`Dialog closeCallback failed`, {
+            message: e.message,
+          })
+        } finally {
+          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 79441fb5e..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,
@@ -188,9 +192,9 @@ export function Close() {
       <Button
         size="small"
         variant="ghost"
-        color="primary"
+        color="secondary"
         shape="round"
-        onPress={close}
+        onPress={() => close()}
         label={_(msg`Close active dialog`)}>
         <ButtonIcon icon={X} size="md" />
       </Button>
diff --git a/src/components/Dialog/types.ts b/src/components/Dialog/types.ts
index 75ba825ac..78dfedf5a 100644
--- a/src/components/Dialog/types.ts
+++ b/src/components/Dialog/types.ts
@@ -6,8 +6,26 @@ import {ViewStyleProp} from '#/alf'
 
 type A11yProps = Required<AccessibilityProps>
 
+/**
+ * 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<DialogControlRefProps>
+}
+
 export type DialogContextProps = {
-  close: () => void
+  close: DialogControlProps['close']
 }
 
 export type DialogControlOpenOptions = {
@@ -20,15 +38,8 @@ export type DialogControlOpenOptions = {
   index?: number
 }
 
-export type DialogControlProps = {
-  open: (options?: DialogControlOpenOptions) => void
-  close: (callback?: () => void) => void
-}
-
 export type DialogOuterProps = {
-  control: {
-    ref: React.RefObject<DialogControlProps>
-  } & DialogControlProps
+  control: DialogControlProps
   onClose?: () => void
   nativeOptions?: {
     sheet?: Omit<BottomSheetProps, 'children'>