-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathprovider.tsx
100 lines (86 loc) · 2.74 KB
/
provider.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { type FC, useEffect, useRef, type PropsWithChildren } from 'react';
import { OverlayContextProvider } from './context';
import { dispatchOverlay } from './store';
import { useSyncOverlayStore } from './use-sync-overlay-store';
import { overlay } from '../event';
export function OverlayProvider({ children }: PropsWithChildren) {
const overlayState = useSyncOverlayStore();
if (overlayState == null) {
dispatchOverlay({ type: 'INIT' });
}
useEffect(() => {
return () => {
dispatchOverlay({ type: 'REMOVE_ALL' });
};
}, []);
return (
<OverlayContextProvider value={overlayState}>
{children}
{overlayState != null &&
overlayState.overlayOrderList.map((item) => {
const { id: currentOverlayId, isOpen, controller: currentController } = overlayState.overlayData[item];
return (
<ContentOverlayController
key={currentOverlayId}
isOpen={isOpen}
current={overlayState.current}
overlayId={currentOverlayId}
onMounted={() => {
requestAnimationFrame(() => {
dispatchOverlay({ type: 'OPEN', overlayId: currentOverlayId });
});
}}
onCloseModal={() => overlay.close(currentOverlayId)}
onExitModal={() => overlay.unmount(currentOverlayId)}
controller={currentController}
/>
);
})}
</OverlayContextProvider>
);
}
type OverlayControllerProps = {
overlayId: string;
isOpen: boolean;
close: () => void;
unmount: () => void;
};
type OverlayAsyncControllerProps<T> = Omit<OverlayControllerProps, 'close'> & {
close: (param: T) => void;
};
export type OverlayControllerComponent = FC<OverlayControllerProps>;
export type OverlayAsyncControllerComponent<T> = FC<OverlayAsyncControllerProps<T>>;
type ContentOverlayControllerProps = {
isOpen: boolean;
current: string | null;
overlayId: string;
onMounted: () => void;
onCloseModal: () => void;
onExitModal: () => void;
controller: OverlayControllerComponent;
};
function ContentOverlayController({
isOpen,
current,
overlayId,
onMounted,
onCloseModal,
onExitModal,
controller: Controller,
}: ContentOverlayControllerProps) {
const prevCurrent = useRef(current);
const onMountedRef = useRef(onMounted);
/**
* @description Executes when closing and reopening an overlay without unmounting.
*/
if (prevCurrent.current !== current) {
prevCurrent.current = current;
if (current === overlayId) {
onMountedRef.current();
}
}
useEffect(() => {
onMountedRef.current();
}, []);
return <Controller overlayId={overlayId} isOpen={isOpen} close={onCloseModal} unmount={onExitModal} />;
}