related-ui-components 4.2.6 → 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 -41
- 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 +40 -49
|
@@ -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,19 +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
|
-
useEffect(() => {
|
|
28
|
-
if (!isVisible && !isRendered) {
|
|
29
|
-
onDismiss();
|
|
30
|
-
}
|
|
31
|
-
}, [isVisible, isRendered, onDismiss]);
|
|
32
26
|
const {
|
|
33
27
|
closeOnBackdropPress = true,
|
|
34
28
|
closeOnBackButton = true,
|
|
35
|
-
animationConfig =
|
|
36
|
-
duration: 300,
|
|
37
|
-
easing: Easing.bezier(0.25, 0.1, 0.25, 1)
|
|
38
|
-
},
|
|
29
|
+
animationConfig = DEFAULT_ANIMATION_CONFIG,
|
|
39
30
|
position = "center",
|
|
40
31
|
animateFrom = "center",
|
|
41
32
|
avoidKeyboard = true,
|
|
@@ -44,13 +35,22 @@ const DefaultModalUI = ({
|
|
|
44
35
|
closeIconComponent
|
|
45
36
|
} = options;
|
|
46
37
|
useEffect(() => {
|
|
47
|
-
if (isVisible)
|
|
38
|
+
if (isVisible) {
|
|
39
|
+
hasRenderedVisibleModalRef.current = true;
|
|
40
|
+
setIsRendered(true);
|
|
41
|
+
}
|
|
48
42
|
opacity.value = withTiming(isVisible ? 1 : 0, animationConfig, finished => {
|
|
49
43
|
if (finished && !isVisible) {
|
|
50
44
|
runOnJS(setIsRendered)(false);
|
|
51
45
|
}
|
|
52
46
|
});
|
|
53
47
|
}, [isVisible, animationConfig, opacity]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (hasRenderedVisibleModalRef.current && !isVisible && !isRendered) {
|
|
50
|
+
hasRenderedVisibleModalRef.current = false;
|
|
51
|
+
onDismiss();
|
|
52
|
+
}
|
|
53
|
+
}, [isVisible, isRendered, onDismiss]);
|
|
54
54
|
useEffect(() => {
|
|
55
55
|
const backHandler = BackHandler.addEventListener("hardwareBackPress", () => {
|
|
56
56
|
if (isVisible && closeOnBackButton) {
|
|
@@ -68,20 +68,13 @@ const DefaultModalUI = ({
|
|
|
68
68
|
opacity: opacity.value
|
|
69
69
|
}));
|
|
70
70
|
const contentAnimatedStyle = useAnimatedStyle(() => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
translateY: (1 - opacity.value) * -100
|
|
79
|
-
});
|
|
80
|
-
} else {
|
|
81
|
-
transform.push({
|
|
82
|
-
scale: 0.9 + opacity.value * 0.1
|
|
83
|
-
});
|
|
84
|
-
}
|
|
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
|
+
}];
|
|
85
78
|
return {
|
|
86
79
|
opacity: opacity.value,
|
|
87
80
|
transform
|
|
@@ -135,11 +128,9 @@ const DefaultModalUI = ({
|
|
|
135
128
|
})]
|
|
136
129
|
});
|
|
137
130
|
};
|
|
138
|
-
|
|
139
|
-
// --- Provider ---
|
|
140
131
|
export const UniversalModalProvider = ({
|
|
141
132
|
children,
|
|
142
|
-
|
|
133
|
+
defaultOptions,
|
|
143
134
|
CustomModalComponent
|
|
144
135
|
}) => {
|
|
145
136
|
const [state, setState] = useState({
|
|
@@ -147,16 +138,18 @@ export const UniversalModalProvider = ({
|
|
|
147
138
|
content: null,
|
|
148
139
|
options: {}
|
|
149
140
|
});
|
|
150
|
-
const dismissCallbackRef =
|
|
141
|
+
const dismissCallbackRef = useRef(undefined);
|
|
151
142
|
const showModal = useCallback((content, options) => {
|
|
143
|
+
dismissCallbackRef.current = undefined;
|
|
152
144
|
setState({
|
|
153
145
|
isVisible: true,
|
|
154
146
|
content,
|
|
155
147
|
options: {
|
|
148
|
+
...defaultOptions,
|
|
156
149
|
...options
|
|
157
150
|
}
|
|
158
151
|
});
|
|
159
|
-
}, []);
|
|
152
|
+
}, [defaultOptions]);
|
|
160
153
|
const hideModal = useCallback(options => {
|
|
161
154
|
dismissCallbackRef.current = options?.onDismiss;
|
|
162
155
|
setState(prev => ({
|
|
@@ -166,7 +159,7 @@ export const UniversalModalProvider = ({
|
|
|
166
159
|
}, []);
|
|
167
160
|
const handleDismiss = useCallback(() => {
|
|
168
161
|
setState(prev => {
|
|
169
|
-
if (prev.isVisible) return prev;
|
|
162
|
+
if (prev.isVisible || prev.content === null) return prev;
|
|
170
163
|
return {
|
|
171
164
|
...prev,
|
|
172
165
|
content: null
|
|
@@ -200,10 +193,7 @@ export const useModal = () => {
|
|
|
200
193
|
return context;
|
|
201
194
|
};
|
|
202
195
|
const styles = StyleSheet.create({
|
|
203
|
-
overlayWrapper: {
|
|
204
|
-
// zIndex: 1000,
|
|
205
|
-
// elevation: 1000,
|
|
206
|
-
},
|
|
196
|
+
overlayWrapper: {},
|
|
207
197
|
backdrop: {
|
|
208
198
|
backgroundColor: "rgba(0, 0, 0, 0.6)"
|
|
209
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,21 +79,13 @@ 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
|
-
useEffect(() => {
|
|
93
|
-
if (!isVisible && !isRendered) {
|
|
94
|
-
onDismiss();
|
|
95
|
-
}
|
|
96
|
-
}, [isVisible, isRendered, onDismiss]);
|
|
97
|
-
|
|
98
85
|
const {
|
|
99
86
|
closeOnBackdropPress = true,
|
|
100
87
|
closeOnBackButton = true,
|
|
101
|
-
animationConfig =
|
|
102
|
-
duration: 300,
|
|
103
|
-
easing: Easing.bezier(0.25, 0.1, 0.25, 1),
|
|
104
|
-
},
|
|
88
|
+
animationConfig = DEFAULT_ANIMATION_CONFIG,
|
|
105
89
|
position = "center",
|
|
106
90
|
animateFrom = "center",
|
|
107
91
|
avoidKeyboard = true,
|
|
@@ -111,7 +95,10 @@ const DefaultModalUI: React.FC<{
|
|
|
111
95
|
} = options;
|
|
112
96
|
|
|
113
97
|
useEffect(() => {
|
|
114
|
-
if (isVisible)
|
|
98
|
+
if (isVisible) {
|
|
99
|
+
hasRenderedVisibleModalRef.current = true;
|
|
100
|
+
setIsRendered(true);
|
|
101
|
+
}
|
|
115
102
|
|
|
116
103
|
opacity.value = withTiming(
|
|
117
104
|
isVisible ? 1 : 0,
|
|
@@ -124,6 +111,13 @@ const DefaultModalUI: React.FC<{
|
|
|
124
111
|
);
|
|
125
112
|
}, [isVisible, animationConfig, opacity]);
|
|
126
113
|
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
if (hasRenderedVisibleModalRef.current && !isVisible && !isRendered) {
|
|
116
|
+
hasRenderedVisibleModalRef.current = false;
|
|
117
|
+
onDismiss();
|
|
118
|
+
}
|
|
119
|
+
}, [isVisible, isRendered, onDismiss]);
|
|
120
|
+
|
|
127
121
|
useEffect(() => {
|
|
128
122
|
const backHandler = BackHandler.addEventListener(
|
|
129
123
|
"hardwareBackPress",
|
|
@@ -132,9 +126,11 @@ const DefaultModalUI: React.FC<{
|
|
|
132
126
|
onClose();
|
|
133
127
|
return true;
|
|
134
128
|
}
|
|
129
|
+
|
|
135
130
|
return false;
|
|
136
131
|
},
|
|
137
132
|
);
|
|
133
|
+
|
|
138
134
|
return () => backHandler.remove();
|
|
139
135
|
}, [isVisible, closeOnBackButton, onClose]);
|
|
140
136
|
|
|
@@ -147,14 +143,12 @@ const DefaultModalUI: React.FC<{
|
|
|
147
143
|
}));
|
|
148
144
|
|
|
149
145
|
const contentAnimatedStyle = useAnimatedStyle(() => {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
transform.push({ scale: 0.9 + opacity.value * 0.1 });
|
|
157
|
-
}
|
|
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 }];
|
|
158
152
|
|
|
159
153
|
return {
|
|
160
154
|
opacity: opacity.value,
|
|
@@ -173,7 +167,6 @@ const DefaultModalUI: React.FC<{
|
|
|
173
167
|
|
|
174
168
|
const paddingBottom = position === "bottom" ? insets.bottom : 0;
|
|
175
169
|
const paddingTop = position === "top" ? insets.top : 0;
|
|
176
|
-
|
|
177
170
|
const ContentWrapper = avoidKeyboard ? KeyboardAvoidingView : View;
|
|
178
171
|
|
|
179
172
|
return (
|
|
@@ -184,7 +177,6 @@ const DefaultModalUI: React.FC<{
|
|
|
184
177
|
{ justifyContent },
|
|
185
178
|
]}
|
|
186
179
|
>
|
|
187
|
-
{/* Backdrop */}
|
|
188
180
|
<Animated.View
|
|
189
181
|
style={[
|
|
190
182
|
StyleSheet.absoluteFill,
|
|
@@ -219,9 +211,8 @@ const DefaultModalUI: React.FC<{
|
|
|
219
211
|
</Animated.View>
|
|
220
212
|
)}
|
|
221
213
|
|
|
222
|
-
{/* Content */}
|
|
223
214
|
<ContentWrapper
|
|
224
|
-
behavior=
|
|
215
|
+
behavior="padding"
|
|
225
216
|
keyboardVerticalOffset={16}
|
|
226
217
|
style={[
|
|
227
218
|
styles.keyboardView,
|
|
@@ -239,10 +230,9 @@ const DefaultModalUI: React.FC<{
|
|
|
239
230
|
);
|
|
240
231
|
};
|
|
241
232
|
|
|
242
|
-
// --- Provider ---
|
|
243
233
|
export const UniversalModalProvider: React.FC<ModalProviderProps> = ({
|
|
244
234
|
children,
|
|
245
|
-
|
|
235
|
+
defaultOptions,
|
|
246
236
|
CustomModalComponent,
|
|
247
237
|
}) => {
|
|
248
238
|
const [state, setState] = useState<{
|
|
@@ -255,17 +245,19 @@ export const UniversalModalProvider: React.FC<ModalProviderProps> = ({
|
|
|
255
245
|
options: {},
|
|
256
246
|
});
|
|
257
247
|
|
|
258
|
-
const dismissCallbackRef =
|
|
248
|
+
const dismissCallbackRef = useRef<(() => void) | undefined>(undefined);
|
|
259
249
|
|
|
260
250
|
const showModal = useCallback(
|
|
261
251
|
(content: ReactNode, options?: ModalOptions) => {
|
|
252
|
+
dismissCallbackRef.current = undefined;
|
|
253
|
+
|
|
262
254
|
setState({
|
|
263
255
|
isVisible: true,
|
|
264
256
|
content,
|
|
265
|
-
options: { ...options },
|
|
257
|
+
options: { ...defaultOptions, ...options },
|
|
266
258
|
});
|
|
267
259
|
},
|
|
268
|
-
[],
|
|
260
|
+
[defaultOptions],
|
|
269
261
|
);
|
|
270
262
|
|
|
271
263
|
const hideModal = useCallback((options?: HideModalOptions) => {
|
|
@@ -275,7 +267,7 @@ export const UniversalModalProvider: React.FC<ModalProviderProps> = ({
|
|
|
275
267
|
|
|
276
268
|
const handleDismiss = useCallback(() => {
|
|
277
269
|
setState((prev) => {
|
|
278
|
-
if (prev.isVisible) return prev;
|
|
270
|
+
if (prev.isVisible || prev.content === null) return prev;
|
|
279
271
|
return { ...prev, content: null };
|
|
280
272
|
});
|
|
281
273
|
|
|
@@ -308,17 +300,16 @@ export const UniversalModalProvider: React.FC<ModalProviderProps> = ({
|
|
|
308
300
|
|
|
309
301
|
export const useModal = () => {
|
|
310
302
|
const context = useContext(ModalContext);
|
|
303
|
+
|
|
311
304
|
if (!context) {
|
|
312
305
|
throw new Error("useModal must be used within a UniversalModalProvider");
|
|
313
306
|
}
|
|
307
|
+
|
|
314
308
|
return context;
|
|
315
309
|
};
|
|
316
310
|
|
|
317
311
|
const styles = StyleSheet.create({
|
|
318
|
-
overlayWrapper: {
|
|
319
|
-
// zIndex: 1000,
|
|
320
|
-
// elevation: 1000,
|
|
321
|
-
},
|
|
312
|
+
overlayWrapper: {},
|
|
322
313
|
backdrop: {
|
|
323
314
|
backgroundColor: "rgba(0, 0, 0, 0.6)",
|
|
324
315
|
},
|
|
@@ -334,4 +325,4 @@ const styles = StyleSheet.create({
|
|
|
334
325
|
right: 16,
|
|
335
326
|
zIndex: 2000,
|
|
336
327
|
},
|
|
337
|
-
});
|
|
328
|
+
});
|