mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React from 'react'
2import {SharedValue, useSharedValue} from 'react-native-reanimated'
3
4import {DialogControlRefProps} from '#/components/Dialog'
5import {Provider as GlobalDialogsProvider} from '#/components/dialogs/Context'
6
7interface IDialogContext {
8 /**
9 * The currently active `useDialogControl` hooks.
10 */
11 activeDialogs: React.MutableRefObject<
12 Map<string, React.MutableRefObject<DialogControlRefProps>>
13 >
14 /**
15 * The currently open dialogs, referenced by their IDs, generated from
16 * `useId`.
17 */
18 openDialogs: React.MutableRefObject<Set<string>>
19 /**
20 * The counterpart to `accessibilityViewIsModal` for Android. This property
21 * applies to the parent of all non-modal views, and prevents TalkBack from
22 * navigating within content beneath an open dialog.
23 *
24 * @see https://reactnative.dev/docs/accessibility#importantforaccessibility-android
25 */
26 importantForAccessibility: SharedValue<'auto' | 'no-hide-descendants'>
27}
28
29const DialogContext = React.createContext<IDialogContext>({} as IDialogContext)
30
31const DialogControlContext = React.createContext<{
32 closeAllDialogs(): boolean
33 setDialogIsOpen(id: string, isOpen: boolean): void
34}>({
35 closeAllDialogs: () => false,
36 setDialogIsOpen: () => {},
37})
38
39export function useDialogStateContext() {
40 return React.useContext(DialogContext)
41}
42
43export function useDialogStateControlContext() {
44 return React.useContext(DialogControlContext)
45}
46
47export function Provider({children}: React.PropsWithChildren<{}>) {
48 const activeDialogs = React.useRef<
49 Map<string, React.MutableRefObject<DialogControlRefProps>>
50 >(new Map())
51 const openDialogs = React.useRef<Set<string>>(new Set())
52 const importantForAccessibility = useSharedValue<
53 'auto' | 'no-hide-descendants'
54 >('auto')
55
56 const closeAllDialogs = React.useCallback(() => {
57 openDialogs.current.forEach(id => {
58 const dialog = activeDialogs.current.get(id)
59 if (dialog) dialog.current.close()
60 })
61 return openDialogs.current.size > 0
62 }, [])
63
64 const setDialogIsOpen = React.useCallback(
65 (id: string, isOpen: boolean) => {
66 if (isOpen) {
67 openDialogs.current.add(id)
68 importantForAccessibility.value = 'no-hide-descendants'
69 } else {
70 openDialogs.current.delete(id)
71 if (openDialogs.current.size < 1) {
72 importantForAccessibility.value = 'auto'
73 }
74 }
75 },
76 [importantForAccessibility],
77 )
78
79 const context = React.useMemo<IDialogContext>(
80 () => ({
81 activeDialogs,
82 openDialogs,
83 importantForAccessibility,
84 }),
85 [importantForAccessibility, activeDialogs, openDialogs],
86 )
87 const controls = React.useMemo(
88 () => ({closeAllDialogs, setDialogIsOpen}),
89 [closeAllDialogs, setDialogIsOpen],
90 )
91
92 return (
93 <DialogContext.Provider value={context}>
94 <DialogControlContext.Provider value={controls}>
95 <GlobalDialogsProvider>{children}</GlobalDialogsProvider>
96 </DialogControlContext.Provider>
97 </DialogContext.Provider>
98 )
99}