related-ui-components 4.2.5 → 4.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/module/contexts/UniversalModalProvider.js +31 -37
- package/lib/module/contexts/UniversalModalProvider.js.map +1 -1
- package/lib/typescript/src/contexts/UniversalModalProvider.d.ts +1 -11
- package/lib/typescript/src/contexts/UniversalModalProvider.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/contexts/UniversalModalProvider.tsx +41 -45
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
3
|
+
import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { BackHandler, StyleSheet, TouchableOpacity, View } from "react-native";
|
|
5
5
|
import { KeyboardAvoidingView } from "react-native-keyboard-controller";
|
|
6
6
|
import Animated, { Easing, runOnJS, useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
|
|
7
7
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
8
|
-
|
|
9
|
-
// --- Types ---
|
|
10
8
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
|
-
// --- Context ---
|
|
12
|
-
|
|
13
9
|
const ModalContext = /*#__PURE__*/createContext(undefined);
|
|
14
10
|
export const DEFAULT_MODAL_HOST = "UniversalModalHost";
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
const DEFAULT_ANIMATION_CONFIG = {
|
|
12
|
+
duration: 300,
|
|
13
|
+
easing: Easing.bezier(0.25, 0.1, 0.25, 1)
|
|
14
|
+
};
|
|
17
15
|
const DefaultModalUI = ({
|
|
18
16
|
isVisible,
|
|
19
17
|
children,
|
|
@@ -23,14 +21,12 @@ const DefaultModalUI = ({
|
|
|
23
21
|
}) => {
|
|
24
22
|
const insets = useSafeAreaInsets();
|
|
25
23
|
const [isRendered, setIsRendered] = useState(isVisible);
|
|
24
|
+
const hasRenderedVisibleModalRef = useRef(false);
|
|
26
25
|
const opacity = useSharedValue(0);
|
|
27
26
|
const {
|
|
28
27
|
closeOnBackdropPress = true,
|
|
29
28
|
closeOnBackButton = true,
|
|
30
|
-
animationConfig =
|
|
31
|
-
duration: 300,
|
|
32
|
-
easing: Easing.bezier(0.25, 0.1, 0.25, 1)
|
|
33
|
-
},
|
|
29
|
+
animationConfig = DEFAULT_ANIMATION_CONFIG,
|
|
34
30
|
position = "center",
|
|
35
31
|
animateFrom = "center",
|
|
36
32
|
avoidKeyboard = true,
|
|
@@ -39,14 +35,22 @@ const DefaultModalUI = ({
|
|
|
39
35
|
closeIconComponent
|
|
40
36
|
} = options;
|
|
41
37
|
useEffect(() => {
|
|
42
|
-
if (isVisible)
|
|
38
|
+
if (isVisible) {
|
|
39
|
+
hasRenderedVisibleModalRef.current = true;
|
|
40
|
+
setIsRendered(true);
|
|
41
|
+
}
|
|
43
42
|
opacity.value = withTiming(isVisible ? 1 : 0, animationConfig, finished => {
|
|
44
43
|
if (finished && !isVisible) {
|
|
45
44
|
runOnJS(setIsRendered)(false);
|
|
46
|
-
runOnJS(onDismiss)();
|
|
47
45
|
}
|
|
48
46
|
});
|
|
49
47
|
}, [isVisible, animationConfig, opacity]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (hasRenderedVisibleModalRef.current && !isVisible && !isRendered) {
|
|
50
|
+
hasRenderedVisibleModalRef.current = false;
|
|
51
|
+
onDismiss();
|
|
52
|
+
}
|
|
53
|
+
}, [isVisible, isRendered, onDismiss]);
|
|
50
54
|
useEffect(() => {
|
|
51
55
|
const backHandler = BackHandler.addEventListener("hardwareBackPress", () => {
|
|
52
56
|
if (isVisible && closeOnBackButton) {
|
|
@@ -64,20 +68,13 @@ const DefaultModalUI = ({
|
|
|
64
68
|
opacity: opacity.value
|
|
65
69
|
}));
|
|
66
70
|
const contentAnimatedStyle = useAnimatedStyle(() => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
translateY: (1 - opacity.value) * -100
|
|
75
|
-
});
|
|
76
|
-
} else {
|
|
77
|
-
transform.push({
|
|
78
|
-
scale: 0.9 + opacity.value * 0.1
|
|
79
|
-
});
|
|
80
|
-
}
|
|
71
|
+
const transform = animateFrom === "bottom" ? [{
|
|
72
|
+
translateY: (1 - opacity.value) * 100
|
|
73
|
+
}] : animateFrom === "top" ? [{
|
|
74
|
+
translateY: (1 - opacity.value) * -100
|
|
75
|
+
}] : [{
|
|
76
|
+
scale: 0.9 + opacity.value * 0.1
|
|
77
|
+
}];
|
|
81
78
|
return {
|
|
82
79
|
opacity: opacity.value,
|
|
83
80
|
transform
|
|
@@ -131,11 +128,9 @@ const DefaultModalUI = ({
|
|
|
131
128
|
})]
|
|
132
129
|
});
|
|
133
130
|
};
|
|
134
|
-
|
|
135
|
-
// --- Provider ---
|
|
136
131
|
export const UniversalModalProvider = ({
|
|
137
132
|
children,
|
|
138
|
-
|
|
133
|
+
defaultOptions,
|
|
139
134
|
CustomModalComponent
|
|
140
135
|
}) => {
|
|
141
136
|
const [state, setState] = useState({
|
|
@@ -143,16 +138,18 @@ export const UniversalModalProvider = ({
|
|
|
143
138
|
content: null,
|
|
144
139
|
options: {}
|
|
145
140
|
});
|
|
146
|
-
const dismissCallbackRef =
|
|
141
|
+
const dismissCallbackRef = useRef(undefined);
|
|
147
142
|
const showModal = useCallback((content, options) => {
|
|
143
|
+
dismissCallbackRef.current = undefined;
|
|
148
144
|
setState({
|
|
149
145
|
isVisible: true,
|
|
150
146
|
content,
|
|
151
147
|
options: {
|
|
148
|
+
...defaultOptions,
|
|
152
149
|
...options
|
|
153
150
|
}
|
|
154
151
|
});
|
|
155
|
-
}, []);
|
|
152
|
+
}, [defaultOptions]);
|
|
156
153
|
const hideModal = useCallback(options => {
|
|
157
154
|
dismissCallbackRef.current = options?.onDismiss;
|
|
158
155
|
setState(prev => ({
|
|
@@ -162,7 +159,7 @@ export const UniversalModalProvider = ({
|
|
|
162
159
|
}, []);
|
|
163
160
|
const handleDismiss = useCallback(() => {
|
|
164
161
|
setState(prev => {
|
|
165
|
-
if (prev.isVisible) return prev;
|
|
162
|
+
if (prev.isVisible || prev.content === null) return prev;
|
|
166
163
|
return {
|
|
167
164
|
...prev,
|
|
168
165
|
content: null
|
|
@@ -196,10 +193,7 @@ export const useModal = () => {
|
|
|
196
193
|
return context;
|
|
197
194
|
};
|
|
198
195
|
const styles = StyleSheet.create({
|
|
199
|
-
overlayWrapper: {
|
|
200
|
-
// zIndex: 1000,
|
|
201
|
-
// elevation: 1000,
|
|
202
|
-
},
|
|
196
|
+
overlayWrapper: {},
|
|
203
197
|
backdrop: {
|
|
204
198
|
backgroundColor: "rgba(0, 0, 0, 0.6)"
|
|
205
199
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","createContext","useCallback","useContext","useEffect","useMemo","useState","BackHandler","StyleSheet","TouchableOpacity","View","KeyboardAvoidingView","Animated","Easing","runOnJS","useAnimatedStyle","useSharedValue","withTiming","useSafeAreaInsets","jsx","_jsx","jsxs","_jsxs","ModalContext","undefined","DEFAULT_MODAL_HOST","DefaultModalUI","isVisible","children","options","onClose","onDismiss","insets","isRendered","setIsRendered","opacity","closeOnBackdropPress","closeOnBackButton","animationConfig","
|
|
1
|
+
{"version":3,"names":["React","createContext","useCallback","useContext","useEffect","useMemo","useRef","useState","BackHandler","StyleSheet","TouchableOpacity","View","KeyboardAvoidingView","Animated","Easing","runOnJS","useAnimatedStyle","useSharedValue","withTiming","useSafeAreaInsets","jsx","_jsx","jsxs","_jsxs","ModalContext","undefined","DEFAULT_MODAL_HOST","DEFAULT_ANIMATION_CONFIG","duration","easing","bezier","DefaultModalUI","isVisible","children","options","onClose","onDismiss","insets","isRendered","setIsRendered","hasRenderedVisibleModalRef","opacity","closeOnBackdropPress","closeOnBackButton","animationConfig","position","animateFrom","avoidKeyboard","backdropStyle","containerStyle","closeIconComponent","current","value","finished","backHandler","addEventListener","remove","backdropAnimatedStyle","closeIconAnimatedStyle","contentAnimatedStyle","transform","translateY","scale","justifyContent","paddingBottom","bottom","paddingTop","top","ContentWrapper","style","absoluteFill","styles","overlayWrapper","backdrop","activeOpacity","onPress","closeIconContainer","pointerEvents","hitSlop","left","right","behavior","keyboardVerticalOffset","keyboardView","baseContainer","UniversalModalProvider","defaultOptions","CustomModalComponent","state","setState","content","dismissCallbackRef","showModal","hideModal","prev","handleDismiss","callback","ModalUI","Provider","useModal","context","Error","create","backgroundColor","alignItems","width","zIndex"],"sourceRoot":"..\\..\\..\\src","sources":["contexts/UniversalModalProvider.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -2,22 +2,14 @@ import React, { ReactNode } from "react";
|
|
|
2
2
|
import { StyleProp, ViewStyle } from "react-native";
|
|
3
3
|
import { WithTimingConfig } from "react-native-reanimated";
|
|
4
4
|
export interface ModalOptions {
|
|
5
|
-
/** Should the modal close when tapping the backdrop? Default: true */
|
|
6
5
|
closeOnBackdropPress?: boolean;
|
|
7
|
-
/** Should the hardware back button close the modal? Default: true */
|
|
8
6
|
closeOnBackButton?: boolean;
|
|
9
|
-
/** Animation configuration for entry/exit */
|
|
10
7
|
animationConfig?: WithTimingConfig;
|
|
11
|
-
/** Custom styles for the backdrop */
|
|
12
8
|
backdropStyle?: StyleProp<ViewStyle>;
|
|
13
|
-
/** Custom styles for the modal container (the white box) */
|
|
14
9
|
containerStyle?: StyleProp<ViewStyle>;
|
|
15
|
-
/** Position of the modal. Default: 'center' */
|
|
16
10
|
position?: "center" | "bottom" | "top";
|
|
17
11
|
animateFrom?: "center" | "bottom" | "top";
|
|
18
|
-
/** If true, avoids keyboard view. Default: true */
|
|
19
12
|
avoidKeyboard?: boolean;
|
|
20
|
-
/** Optional component to render as a close icon at the top right or left of the screen */
|
|
21
13
|
closeIconComponent?: ReactNode;
|
|
22
14
|
}
|
|
23
15
|
interface HideModalOptions {
|
|
@@ -29,16 +21,14 @@ interface ModalContextType {
|
|
|
29
21
|
}
|
|
30
22
|
interface ModalProviderProps {
|
|
31
23
|
children: ReactNode;
|
|
32
|
-
/** Global default options for all modals */
|
|
33
24
|
defaultOptions?: ModalOptions;
|
|
34
|
-
/** Optional: Provide a specific Portal Host name if nesting providers */
|
|
35
25
|
portalHostName?: string;
|
|
36
|
-
/** Optional: Override the internal Modal UI component completely */
|
|
37
26
|
CustomModalComponent?: React.FC<{
|
|
38
27
|
isVisible: boolean;
|
|
39
28
|
children: ReactNode;
|
|
40
29
|
options: ModalOptions;
|
|
41
30
|
onClose: () => void;
|
|
31
|
+
onDismiss: () => void;
|
|
42
32
|
}>;
|
|
43
33
|
}
|
|
44
34
|
export declare const DEFAULT_MODAL_HOST = "UniversalModalHost";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UniversalModalProvider.d.ts","sourceRoot":"","sources":["../../../../src/contexts/UniversalModalProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAEZ,SAAS,
|
|
1
|
+
{"version":3,"file":"UniversalModalProvider.d.ts","sourceRoot":"","sources":["../../../../src/contexts/UniversalModalProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAEZ,SAAS,EAOV,MAAM,OAAO,CAAC;AACf,OAAO,EAEL,SAAS,EAIT,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,OAAiB,EAMf,gBAAgB,EACjB,MAAM,yBAAyB,CAAC;AAGjC,MAAM,WAAW,YAAY;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,gBAAgB,CAAC;IACnC,aAAa,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACrC,cAAc,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,QAAQ,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAC;IACvC,WAAW,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAC;IAC1C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,SAAS,CAAC;CAChC;AAED,UAAU,gBAAgB;IACxB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,UAAU,gBAAgB;IACxB,SAAS,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,IAAI,CAAC;IAChE,SAAS,EAAE,CAAC,OAAO,CAAC,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACjD;AAED,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,SAAS,CAAC;IACpB,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;QAC9B,SAAS,EAAE,OAAO,CAAC;QACnB,QAAQ,EAAE,SAAS,CAAC;QACpB,OAAO,EAAE,YAAY,CAAC;QACtB,OAAO,EAAE,MAAM,IAAI,CAAC;QACpB,SAAS,EAAE,MAAM,IAAI,CAAC;KACvB,CAAC,CAAC;CACJ;AAID,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AAuKvD,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAkE/D,CAAC;AAEF,eAAO,MAAM,QAAQ,wBAQpB,CAAC"}
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ import React, {
|
|
|
5
5
|
useContext,
|
|
6
6
|
useEffect,
|
|
7
7
|
useMemo,
|
|
8
|
+
useRef,
|
|
8
9
|
useState,
|
|
9
10
|
} from "react";
|
|
10
11
|
import {
|
|
@@ -26,24 +27,15 @@ import Animated, {
|
|
|
26
27
|
} from "react-native-reanimated";
|
|
27
28
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
28
29
|
|
|
29
|
-
// --- Types ---
|
|
30
30
|
export interface ModalOptions {
|
|
31
|
-
/** Should the modal close when tapping the backdrop? Default: true */
|
|
32
31
|
closeOnBackdropPress?: boolean;
|
|
33
|
-
/** Should the hardware back button close the modal? Default: true */
|
|
34
32
|
closeOnBackButton?: boolean;
|
|
35
|
-
/** Animation configuration for entry/exit */
|
|
36
33
|
animationConfig?: WithTimingConfig;
|
|
37
|
-
/** Custom styles for the backdrop */
|
|
38
34
|
backdropStyle?: StyleProp<ViewStyle>;
|
|
39
|
-
/** Custom styles for the modal container (the white box) */
|
|
40
35
|
containerStyle?: StyleProp<ViewStyle>;
|
|
41
|
-
/** Position of the modal. Default: 'center' */
|
|
42
36
|
position?: "center" | "bottom" | "top";
|
|
43
37
|
animateFrom?: "center" | "bottom" | "top";
|
|
44
|
-
/** If true, avoids keyboard view. Default: true */
|
|
45
38
|
avoidKeyboard?: boolean;
|
|
46
|
-
/** Optional component to render as a close icon at the top right or left of the screen */
|
|
47
39
|
closeIconComponent?: ReactNode;
|
|
48
40
|
}
|
|
49
41
|
|
|
@@ -58,26 +50,26 @@ interface ModalContextType {
|
|
|
58
50
|
|
|
59
51
|
interface ModalProviderProps {
|
|
60
52
|
children: ReactNode;
|
|
61
|
-
/** Global default options for all modals */
|
|
62
53
|
defaultOptions?: ModalOptions;
|
|
63
|
-
/** Optional: Provide a specific Portal Host name if nesting providers */
|
|
64
54
|
portalHostName?: string;
|
|
65
|
-
/** Optional: Override the internal Modal UI component completely */
|
|
66
55
|
CustomModalComponent?: React.FC<{
|
|
67
56
|
isVisible: boolean;
|
|
68
57
|
children: ReactNode;
|
|
69
58
|
options: ModalOptions;
|
|
70
59
|
onClose: () => void;
|
|
60
|
+
onDismiss: () => void;
|
|
71
61
|
}>;
|
|
72
62
|
}
|
|
73
63
|
|
|
74
|
-
// --- Context ---
|
|
75
|
-
|
|
76
64
|
const ModalContext = createContext<ModalContextType | undefined>(undefined);
|
|
77
65
|
|
|
78
66
|
export const DEFAULT_MODAL_HOST = "UniversalModalHost";
|
|
79
67
|
|
|
80
|
-
|
|
68
|
+
const DEFAULT_ANIMATION_CONFIG: WithTimingConfig = {
|
|
69
|
+
duration: 300,
|
|
70
|
+
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
71
|
+
};
|
|
72
|
+
|
|
81
73
|
const DefaultModalUI: React.FC<{
|
|
82
74
|
isVisible: boolean;
|
|
83
75
|
children: ReactNode;
|
|
@@ -87,25 +79,26 @@ const DefaultModalUI: React.FC<{
|
|
|
87
79
|
}> = ({ isVisible, children, options, onClose, onDismiss }) => {
|
|
88
80
|
const insets = useSafeAreaInsets();
|
|
89
81
|
const [isRendered, setIsRendered] = useState(isVisible);
|
|
82
|
+
const hasRenderedVisibleModalRef = useRef(false);
|
|
90
83
|
const opacity = useSharedValue(0);
|
|
91
84
|
|
|
92
85
|
const {
|
|
93
86
|
closeOnBackdropPress = true,
|
|
94
87
|
closeOnBackButton = true,
|
|
95
|
-
animationConfig =
|
|
96
|
-
duration: 300,
|
|
97
|
-
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
98
|
-
},
|
|
88
|
+
animationConfig = DEFAULT_ANIMATION_CONFIG,
|
|
99
89
|
position = "center",
|
|
100
90
|
animateFrom = "center",
|
|
101
91
|
avoidKeyboard = true,
|
|
102
92
|
backdropStyle,
|
|
103
93
|
containerStyle,
|
|
104
|
-
closeIconComponent
|
|
94
|
+
closeIconComponent,
|
|
105
95
|
} = options;
|
|
106
96
|
|
|
107
97
|
useEffect(() => {
|
|
108
|
-
if (isVisible)
|
|
98
|
+
if (isVisible) {
|
|
99
|
+
hasRenderedVisibleModalRef.current = true;
|
|
100
|
+
setIsRendered(true);
|
|
101
|
+
}
|
|
109
102
|
|
|
110
103
|
opacity.value = withTiming(
|
|
111
104
|
isVisible ? 1 : 0,
|
|
@@ -113,12 +106,18 @@ const DefaultModalUI: React.FC<{
|
|
|
113
106
|
(finished) => {
|
|
114
107
|
if (finished && !isVisible) {
|
|
115
108
|
runOnJS(setIsRendered)(false);
|
|
116
|
-
runOnJS(onDismiss)();
|
|
117
109
|
}
|
|
118
110
|
},
|
|
119
111
|
);
|
|
120
112
|
}, [isVisible, animationConfig, opacity]);
|
|
121
113
|
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
if (hasRenderedVisibleModalRef.current && !isVisible && !isRendered) {
|
|
116
|
+
hasRenderedVisibleModalRef.current = false;
|
|
117
|
+
onDismiss();
|
|
118
|
+
}
|
|
119
|
+
}, [isVisible, isRendered, onDismiss]);
|
|
120
|
+
|
|
122
121
|
useEffect(() => {
|
|
123
122
|
const backHandler = BackHandler.addEventListener(
|
|
124
123
|
"hardwareBackPress",
|
|
@@ -127,9 +126,11 @@ const DefaultModalUI: React.FC<{
|
|
|
127
126
|
onClose();
|
|
128
127
|
return true;
|
|
129
128
|
}
|
|
129
|
+
|
|
130
130
|
return false;
|
|
131
131
|
},
|
|
132
132
|
);
|
|
133
|
+
|
|
133
134
|
return () => backHandler.remove();
|
|
134
135
|
}, [isVisible, closeOnBackButton, onClose]);
|
|
135
136
|
|
|
@@ -142,14 +143,12 @@ const DefaultModalUI: React.FC<{
|
|
|
142
143
|
}));
|
|
143
144
|
|
|
144
145
|
const contentAnimatedStyle = useAnimatedStyle(() => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
transform.push({ scale: 0.9 + opacity.value * 0.1 });
|
|
152
|
-
}
|
|
146
|
+
const transform =
|
|
147
|
+
animateFrom === "bottom"
|
|
148
|
+
? [{ translateY: (1 - opacity.value) * 100 }]
|
|
149
|
+
: animateFrom === "top"
|
|
150
|
+
? [{ translateY: (1 - opacity.value) * -100 }]
|
|
151
|
+
: [{ scale: 0.9 + opacity.value * 0.1 }];
|
|
153
152
|
|
|
154
153
|
return {
|
|
155
154
|
opacity: opacity.value,
|
|
@@ -168,7 +167,6 @@ const DefaultModalUI: React.FC<{
|
|
|
168
167
|
|
|
169
168
|
const paddingBottom = position === "bottom" ? insets.bottom : 0;
|
|
170
169
|
const paddingTop = position === "top" ? insets.top : 0;
|
|
171
|
-
|
|
172
170
|
const ContentWrapper = avoidKeyboard ? KeyboardAvoidingView : View;
|
|
173
171
|
|
|
174
172
|
return (
|
|
@@ -179,7 +177,6 @@ const DefaultModalUI: React.FC<{
|
|
|
179
177
|
{ justifyContent },
|
|
180
178
|
]}
|
|
181
179
|
>
|
|
182
|
-
{/* Backdrop */}
|
|
183
180
|
<Animated.View
|
|
184
181
|
style={[
|
|
185
182
|
StyleSheet.absoluteFill,
|
|
@@ -214,9 +211,8 @@ const DefaultModalUI: React.FC<{
|
|
|
214
211
|
</Animated.View>
|
|
215
212
|
)}
|
|
216
213
|
|
|
217
|
-
{/* Content */}
|
|
218
214
|
<ContentWrapper
|
|
219
|
-
behavior=
|
|
215
|
+
behavior="padding"
|
|
220
216
|
keyboardVerticalOffset={16}
|
|
221
217
|
style={[
|
|
222
218
|
styles.keyboardView,
|
|
@@ -234,10 +230,9 @@ const DefaultModalUI: React.FC<{
|
|
|
234
230
|
);
|
|
235
231
|
};
|
|
236
232
|
|
|
237
|
-
// --- Provider ---
|
|
238
233
|
export const UniversalModalProvider: React.FC<ModalProviderProps> = ({
|
|
239
234
|
children,
|
|
240
|
-
|
|
235
|
+
defaultOptions,
|
|
241
236
|
CustomModalComponent,
|
|
242
237
|
}) => {
|
|
243
238
|
const [state, setState] = useState<{
|
|
@@ -250,17 +245,19 @@ export const UniversalModalProvider: React.FC<ModalProviderProps> = ({
|
|
|
250
245
|
options: {},
|
|
251
246
|
});
|
|
252
247
|
|
|
253
|
-
const dismissCallbackRef =
|
|
248
|
+
const dismissCallbackRef = useRef<(() => void) | undefined>(undefined);
|
|
254
249
|
|
|
255
250
|
const showModal = useCallback(
|
|
256
251
|
(content: ReactNode, options?: ModalOptions) => {
|
|
252
|
+
dismissCallbackRef.current = undefined;
|
|
253
|
+
|
|
257
254
|
setState({
|
|
258
255
|
isVisible: true,
|
|
259
256
|
content,
|
|
260
|
-
options: { ...options },
|
|
257
|
+
options: { ...defaultOptions, ...options },
|
|
261
258
|
});
|
|
262
259
|
},
|
|
263
|
-
[],
|
|
260
|
+
[defaultOptions],
|
|
264
261
|
);
|
|
265
262
|
|
|
266
263
|
const hideModal = useCallback((options?: HideModalOptions) => {
|
|
@@ -270,7 +267,7 @@ export const UniversalModalProvider: React.FC<ModalProviderProps> = ({
|
|
|
270
267
|
|
|
271
268
|
const handleDismiss = useCallback(() => {
|
|
272
269
|
setState((prev) => {
|
|
273
|
-
if (prev.isVisible) return prev;
|
|
270
|
+
if (prev.isVisible || prev.content === null) return prev;
|
|
274
271
|
return { ...prev, content: null };
|
|
275
272
|
});
|
|
276
273
|
|
|
@@ -303,17 +300,16 @@ export const UniversalModalProvider: React.FC<ModalProviderProps> = ({
|
|
|
303
300
|
|
|
304
301
|
export const useModal = () => {
|
|
305
302
|
const context = useContext(ModalContext);
|
|
303
|
+
|
|
306
304
|
if (!context) {
|
|
307
305
|
throw new Error("useModal must be used within a UniversalModalProvider");
|
|
308
306
|
}
|
|
307
|
+
|
|
309
308
|
return context;
|
|
310
309
|
};
|
|
311
310
|
|
|
312
311
|
const styles = StyleSheet.create({
|
|
313
|
-
overlayWrapper: {
|
|
314
|
-
// zIndex: 1000,
|
|
315
|
-
// elevation: 1000,
|
|
316
|
-
},
|
|
312
|
+
overlayWrapper: {},
|
|
317
313
|
backdrop: {
|
|
318
314
|
backgroundColor: "rgba(0, 0, 0, 0.6)",
|
|
319
315
|
},
|
|
@@ -329,4 +325,4 @@ const styles = StyleSheet.create({
|
|
|
329
325
|
right: 16,
|
|
330
326
|
zIndex: 2000,
|
|
331
327
|
},
|
|
332
|
-
});
|
|
328
|
+
});
|