this repo has no description
1import {
2 createContext,
3 useCallback,
4 useContext,
5 useMemo,
6 useRef,
7 useState,
8} from 'react'
9
10import {type DialogControlRefProps} from '#/components/Dialog'
11import {Provider as GlobalDialogsProvider} from '#/components/dialogs/Context'
12import {IS_WEB} from '#/env'
13import {BottomSheetNativeComponent} from '../../../modules/bottom-sheet'
14
15interface IDialogContext {
16 /**
17 * The currently active `useDialogControl` hooks.
18 */
19 activeDialogs: React.MutableRefObject<
20 Map<string, React.MutableRefObject<DialogControlRefProps>>
21 >
22 /**
23 * The currently open dialogs, referenced by their IDs, generated from
24 * `useId`.
25 */
26 openDialogs: React.MutableRefObject<Set<string>>
27}
28
29interface IDialogControlContext {
30 closeAllDialogs(): boolean
31 setDialogIsOpen(id: string, isOpen: boolean): void
32 setFullyExpandedCount: React.Dispatch<React.SetStateAction<number>>
33}
34
35const DialogContext = createContext<IDialogContext>({} as IDialogContext)
36DialogContext.displayName = 'DialogContext'
37
38const DialogControlContext = createContext<IDialogControlContext>(
39 {} as IDialogControlContext,
40)
41DialogControlContext.displayName = 'DialogControlContext'
42
43/**
44 * The number of dialogs that are fully expanded. This is used to determine the background color of the status bar
45 * on iOS.
46 */
47const DialogFullyExpandedCountContext = createContext<number>(0)
48DialogFullyExpandedCountContext.displayName = 'DialogFullyExpandedCountContext'
49
50export function useDialogStateContext() {
51 return useContext(DialogContext)
52}
53
54export function useDialogStateControlContext() {
55 return useContext(DialogControlContext)
56}
57
58/** The number of dialogs that are fully expanded */
59export function useDialogFullyExpandedCountContext() {
60 return useContext(DialogFullyExpandedCountContext)
61}
62
63export function Provider({children}: React.PropsWithChildren<{}>) {
64 const [fullyExpandedCount, setFullyExpandedCount] = useState(0)
65
66 const activeDialogs = useRef<
67 Map<string, React.MutableRefObject<DialogControlRefProps>>
68 >(new Map())
69 const openDialogs = useRef<Set<string>>(new Set())
70
71 const closeAllDialogs = useCallback(() => {
72 if (IS_WEB) {
73 openDialogs.current.forEach(id => {
74 const dialog = activeDialogs.current.get(id)
75 if (dialog) dialog.current.close()
76 })
77
78 return openDialogs.current.size > 0
79 } else {
80 BottomSheetNativeComponent.dismissAll()
81 return false
82 }
83 }, [])
84
85 const setDialogIsOpen = useCallback((id: string, isOpen: boolean) => {
86 if (isOpen) {
87 openDialogs.current.add(id)
88 } else {
89 openDialogs.current.delete(id)
90 }
91 }, [])
92
93 const context = useMemo<IDialogContext>(
94 () => ({
95 activeDialogs,
96 openDialogs,
97 }),
98 [activeDialogs, openDialogs],
99 )
100 const controls = useMemo(
101 () => ({
102 closeAllDialogs,
103 setDialogIsOpen,
104 setFullyExpandedCount,
105 }),
106 [closeAllDialogs, setDialogIsOpen, setFullyExpandedCount],
107 )
108
109 return (
110 <DialogContext.Provider value={context}>
111 <DialogControlContext.Provider value={controls}>
112 <DialogFullyExpandedCountContext.Provider value={fullyExpandedCount}>
113 <GlobalDialogsProvider>{children}</GlobalDialogsProvider>
114 </DialogFullyExpandedCountContext.Provider>
115 </DialogControlContext.Provider>
116 </DialogContext.Provider>
117 )
118}
119Provider.displayName = 'DialogsProvider'