@hoddy-ui/core 1.1.4 → 2.0.35
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/README.md +155 -28
- package/next/dist/index.d.mts +113 -41
- package/next/dist/index.d.ts +113 -41
- package/next/dist/index.js +444 -297
- package/next/dist/index.js.map +1 -1
- package/next/dist/index.mjs +460 -307
- package/next/dist/index.mjs.map +1 -1
- package/next/package.json +7 -6
- package/package.json +7 -5
- package/src/Components/AlertX.tsx +4 -4
- package/src/Components/Animators/Animator.tsx +1 -1
- package/src/Components/Animators/hooks/useAppState.ts +4 -11
- package/src/Components/Animators/hooks/useBlinkAnimation.ts +31 -24
- package/src/Components/Animators/hooks/useFadeAnimation.ts +28 -26
- package/src/Components/Animators/hooks/useFloatAnimation.ts +67 -57
- package/src/Components/Animators/hooks/useGrowAnimation.ts +41 -28
- package/src/Components/Animators/hooks/useRollAnimation.ts +77 -57
- package/src/Components/Animators/hooks/useSlideAnimation.ts +44 -35
- package/src/Components/Animators/hooks/useThrownUpAnimation.ts +43 -50
- package/src/Components/Avatar.tsx +13 -7
- package/src/Components/Button.tsx +13 -12
- package/src/Components/FlashMessage.tsx +119 -42
- package/src/Components/FormWrapper.tsx +7 -2
- package/src/Components/Grid.tsx +5 -5
- package/src/Components/Locator.tsx +10 -2
- package/src/Components/OTPInput.tsx +0 -4
- package/src/Components/Popup.tsx +161 -83
- package/src/Components/SafeAreaView.tsx +11 -11
- package/src/Components/SelectMenu.tsx +34 -52
- package/src/Components/TextField.tsx +16 -6
- package/src/Components/Typography.tsx +19 -16
- package/src/config/KeyManager.ts +6 -1
- package/src/config/index.ts +37 -2
- package/src/hooks.ts +21 -14
- package/src/theme/index.tsx +14 -6
- package/src/types.ts +12 -3
- package/src/utility.ts +11 -0
- package/src/Components/Animators/README.md +0 -137
|
@@ -1,47 +1,111 @@
|
|
|
1
|
-
import React, { useEffect, useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
2
|
+
import { TouchableOpacity, View } from "react-native";
|
|
3
|
+
import Animated, {
|
|
4
|
+
runOnJS,
|
|
5
|
+
useAnimatedStyle,
|
|
6
|
+
useSharedValue,
|
|
7
|
+
withTiming,
|
|
8
|
+
} from "react-native-reanimated";
|
|
8
9
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
9
10
|
import { ScaledSheet } from "react-native-size-matters";
|
|
10
11
|
import { useColors } from "../hooks";
|
|
11
|
-
import { MaterialIcons } from "@expo/vector-icons";
|
|
12
12
|
import { FlashMessageProps } from "../types";
|
|
13
13
|
import Typography from "./Typography";
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
// Event-based API to decouple the trigger from the component instance
|
|
16
|
+
type FlashListener = (msg: FlashMessageProps) => void;
|
|
17
|
+
const flashListeners = new Set<FlashListener>();
|
|
18
|
+
|
|
19
|
+
export const showFlashMessage = (msg: FlashMessageProps) => {
|
|
20
|
+
flashListeners.forEach((listener) => listener(msg));
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const subscribeToFlashMessages = (listener: FlashListener) => {
|
|
24
|
+
flashListeners.add(listener);
|
|
25
|
+
return () => {
|
|
26
|
+
flashListeners.delete(listener);
|
|
27
|
+
};
|
|
28
|
+
};
|
|
16
29
|
|
|
17
30
|
const FlashMessage: React.FC = () => {
|
|
18
31
|
const { top } = useSafeAreaInsets();
|
|
19
32
|
const [message, setMessage] = useState<null | FlashMessageProps>(null);
|
|
20
|
-
const [show, setShow] = useState(false);
|
|
21
33
|
const colors = useColors();
|
|
22
34
|
const type = message?.type || "success";
|
|
35
|
+
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
36
|
+
|
|
37
|
+
// Animated values
|
|
38
|
+
const translateY = useSharedValue(-200);
|
|
39
|
+
const opacity = useSharedValue(0);
|
|
40
|
+
|
|
41
|
+
const hideMessage = () => {
|
|
42
|
+
setMessage(null);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const closeMessage = () => {
|
|
46
|
+
// Clear existing timeout if any
|
|
47
|
+
if (timeoutRef.current) {
|
|
48
|
+
clearTimeout(timeoutRef.current);
|
|
49
|
+
timeoutRef.current = null;
|
|
50
|
+
}
|
|
23
51
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
setTimeout(() => {
|
|
31
|
-
setShow(false);
|
|
32
|
-
setTimeout(() => {
|
|
33
|
-
setMessage(null);
|
|
34
|
-
}, 500);
|
|
35
|
-
}, msg.duration || 3000);
|
|
52
|
+
// Animate out immediately
|
|
53
|
+
translateY.value = withTiming(-200, { duration: 300 });
|
|
54
|
+
opacity.value = withTiming(0, { duration: 300 }, () => {
|
|
55
|
+
runOnJS(hideMessage)();
|
|
56
|
+
});
|
|
36
57
|
};
|
|
58
|
+
|
|
37
59
|
useEffect(() => {
|
|
38
|
-
|
|
39
|
-
|
|
60
|
+
const listener: FlashListener = (msg) => {
|
|
61
|
+
// Clear existing timeout if any
|
|
62
|
+
if (timeoutRef.current) {
|
|
63
|
+
clearTimeout(timeoutRef.current);
|
|
64
|
+
timeoutRef.current = null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Reset position immediately before starting new animation
|
|
68
|
+
translateY.value = -200;
|
|
69
|
+
opacity.value = 0;
|
|
70
|
+
|
|
71
|
+
setMessage(msg);
|
|
72
|
+
|
|
73
|
+
// Animate in
|
|
74
|
+
translateY.value = withTiming(0, { duration: 300 });
|
|
75
|
+
opacity.value = withTiming(1, { duration: 300 });
|
|
76
|
+
|
|
77
|
+
// Animate out after duration
|
|
78
|
+
const duration = msg.duration || 3000;
|
|
79
|
+
timeoutRef.current = setTimeout(() => {
|
|
80
|
+
translateY.value = withTiming(-200, { duration: 300 });
|
|
81
|
+
opacity.value = withTiming(0, { duration: 300 }, () => {
|
|
82
|
+
runOnJS(hideMessage)();
|
|
83
|
+
});
|
|
84
|
+
timeoutRef.current = null;
|
|
85
|
+
}, duration);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const unsubscribe = subscribeToFlashMessages(listener);
|
|
89
|
+
return () => {
|
|
90
|
+
if (timeoutRef.current) {
|
|
91
|
+
clearTimeout(timeoutRef.current);
|
|
92
|
+
timeoutRef.current = null;
|
|
93
|
+
}
|
|
94
|
+
unsubscribe();
|
|
95
|
+
};
|
|
96
|
+
}, []);
|
|
97
|
+
|
|
98
|
+
const animatedStyle = useAnimatedStyle(() => {
|
|
99
|
+
return {
|
|
100
|
+
transform: [{ translateY: translateY.value }],
|
|
101
|
+
opacity: opacity.value,
|
|
102
|
+
};
|
|
103
|
+
});
|
|
40
104
|
|
|
41
105
|
const styles = ScaledSheet.create({
|
|
42
106
|
root: {
|
|
43
107
|
position: "absolute",
|
|
44
|
-
top:
|
|
108
|
+
top: 0,
|
|
45
109
|
zIndex: 1000,
|
|
46
110
|
left: 0,
|
|
47
111
|
paddingTop: top + 10,
|
|
@@ -64,33 +128,46 @@ const FlashMessage: React.FC = () => {
|
|
|
64
128
|
},
|
|
65
129
|
});
|
|
66
130
|
|
|
131
|
+
if (!message) return null;
|
|
132
|
+
|
|
67
133
|
return (
|
|
68
|
-
<View style={styles.root}>
|
|
69
|
-
<
|
|
70
|
-
<View style={{
|
|
71
|
-
{
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
134
|
+
<Animated.View style={[styles.root, animatedStyle]}>
|
|
135
|
+
<TouchableOpacity onPress={closeMessage} activeOpacity={0.9}>
|
|
136
|
+
<View style={{ flexDirection: "row" }}>
|
|
137
|
+
<View style={{ flex: 1, marginRight: 10 }}>
|
|
138
|
+
{message?.title && (
|
|
139
|
+
<Typography
|
|
140
|
+
variant="h6"
|
|
141
|
+
fontWeight={600}
|
|
142
|
+
gutterBottom={3}
|
|
143
|
+
style={{ color: "#fff" }}
|
|
144
|
+
>
|
|
145
|
+
{message?.title}
|
|
146
|
+
</Typography>
|
|
147
|
+
)}
|
|
148
|
+
<Typography style={{ color: "#fff" }}>
|
|
149
|
+
{message?.message}
|
|
79
150
|
</Typography>
|
|
80
|
-
|
|
81
|
-
<
|
|
151
|
+
</View>
|
|
152
|
+
{/* <MaterialIcons color="#fff" size={36} name="error-outline" /> */}
|
|
82
153
|
</View>
|
|
83
|
-
|
|
84
|
-
</View>
|
|
154
|
+
</TouchableOpacity>
|
|
85
155
|
|
|
86
156
|
{message?.actions?.map((cur, i) => (
|
|
87
|
-
<TouchableOpacity
|
|
157
|
+
<TouchableOpacity
|
|
158
|
+
key={i}
|
|
159
|
+
style={styles.action}
|
|
160
|
+
onPress={() => {
|
|
161
|
+
cur.onPress?.();
|
|
162
|
+
closeMessage();
|
|
163
|
+
}}
|
|
164
|
+
>
|
|
88
165
|
<Typography fontWeight={700} style={{ color: "#fff" }}>
|
|
89
166
|
{cur.title}
|
|
90
167
|
</Typography>
|
|
91
168
|
</TouchableOpacity>
|
|
92
169
|
))}
|
|
93
|
-
</View>
|
|
170
|
+
</Animated.View>
|
|
94
171
|
);
|
|
95
172
|
};
|
|
96
173
|
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from "react-native";
|
|
9
9
|
import { ScaledSheet } from "react-native-size-matters";
|
|
10
10
|
import { FormWrapperProps } from "../types";
|
|
11
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
11
12
|
export const FormWrapper: React.FC<FormWrapperProps> = ({
|
|
12
13
|
children,
|
|
13
14
|
behavior = Platform.OS === "ios" ? "padding" : "height",
|
|
@@ -17,6 +18,9 @@ export const FormWrapper: React.FC<FormWrapperProps> = ({
|
|
|
17
18
|
style = {},
|
|
18
19
|
onScroll,
|
|
19
20
|
}) => {
|
|
21
|
+
const { bottom } = useSafeAreaInsets();
|
|
22
|
+
|
|
23
|
+
const defaultOffset = Platform.OS === "ios" ? -bottom : -bottom * 2;
|
|
20
24
|
const styles = ScaledSheet.create({
|
|
21
25
|
root: {
|
|
22
26
|
width: "100%",
|
|
@@ -24,13 +28,14 @@ export const FormWrapper: React.FC<FormWrapperProps> = ({
|
|
|
24
28
|
...style,
|
|
25
29
|
},
|
|
26
30
|
});
|
|
31
|
+
|
|
27
32
|
return mode === "static" ? (
|
|
28
33
|
<TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
|
|
29
34
|
<KeyboardAvoidingView
|
|
30
35
|
style={styles.root}
|
|
31
36
|
behavior={behavior}
|
|
32
37
|
contentContainerStyle={styles.root}
|
|
33
|
-
keyboardVerticalOffset={keyboardVerticalOffset}
|
|
38
|
+
keyboardVerticalOffset={keyboardVerticalOffset || defaultOffset}
|
|
34
39
|
>
|
|
35
40
|
{children}
|
|
36
41
|
</KeyboardAvoidingView>
|
|
@@ -39,7 +44,7 @@ export const FormWrapper: React.FC<FormWrapperProps> = ({
|
|
|
39
44
|
<KeyboardAvoidingView
|
|
40
45
|
behavior={behavior}
|
|
41
46
|
style={styles.root}
|
|
42
|
-
keyboardVerticalOffset={keyboardVerticalOffset}
|
|
47
|
+
keyboardVerticalOffset={keyboardVerticalOffset || defaultOffset}
|
|
43
48
|
>
|
|
44
49
|
<ScrollView
|
|
45
50
|
onScroll={onScroll}
|
package/src/Components/Grid.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { View, Text } from "react-native";
|
|
2
1
|
import React from "react";
|
|
3
|
-
import {
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { ms, ScaledSheet } from "react-native-size-matters";
|
|
4
4
|
import { GridItemProps, GridProps } from "../types";
|
|
5
5
|
|
|
6
6
|
export const GridItem: React.FC<GridItemProps> = ({
|
|
@@ -12,8 +12,8 @@ export const GridItem: React.FC<GridItemProps> = ({
|
|
|
12
12
|
}) => {
|
|
13
13
|
const styles = ScaledSheet.create({
|
|
14
14
|
gridItem: {
|
|
15
|
-
width: 100 / col
|
|
16
|
-
padding: spacing * 10
|
|
15
|
+
width: `${100 / col}%`,
|
|
16
|
+
padding: ms(spacing * 10),
|
|
17
17
|
alignItems: alignItems,
|
|
18
18
|
},
|
|
19
19
|
});
|
|
@@ -27,7 +27,7 @@ export const Grid: React.FC<GridProps> = ({
|
|
|
27
27
|
const styles = ScaledSheet.create({
|
|
28
28
|
grid: {
|
|
29
29
|
flexWrap: "wrap",
|
|
30
|
-
margin: -spacing * 10
|
|
30
|
+
margin: `${-spacing * 10}@ms`,
|
|
31
31
|
flexDirection: "row",
|
|
32
32
|
},
|
|
33
33
|
});
|
|
@@ -15,6 +15,7 @@ import Typography from "./Typography";
|
|
|
15
15
|
export type predictionType = {
|
|
16
16
|
id: string;
|
|
17
17
|
description: string;
|
|
18
|
+
types: string[];
|
|
18
19
|
};
|
|
19
20
|
export const getPredictionsFromCoords = async (coords: {
|
|
20
21
|
latitude: number;
|
|
@@ -36,10 +37,15 @@ export const getPredictionsFromCoords = async (coords: {
|
|
|
36
37
|
const p = [];
|
|
37
38
|
|
|
38
39
|
for (let key in res.results) {
|
|
39
|
-
const {
|
|
40
|
+
const {
|
|
41
|
+
formatted_address: description,
|
|
42
|
+
place_id,
|
|
43
|
+
types,
|
|
44
|
+
} = res.results[key];
|
|
40
45
|
p.push({
|
|
41
46
|
description,
|
|
42
47
|
id: place_id,
|
|
48
|
+
types,
|
|
43
49
|
latLng: { lst: coords.latitude, lng: coords.longitude },
|
|
44
50
|
});
|
|
45
51
|
}
|
|
@@ -57,10 +63,11 @@ export const getPredictionsFromQuery = async (
|
|
|
57
63
|
|
|
58
64
|
const p = [];
|
|
59
65
|
for (let key in res.predictions) {
|
|
60
|
-
const { description, place_id } = res.predictions[key];
|
|
66
|
+
const { description, place_id, types } = res.predictions[key];
|
|
61
67
|
p.push({
|
|
62
68
|
description,
|
|
63
69
|
id: place_id,
|
|
70
|
+
types,
|
|
64
71
|
});
|
|
65
72
|
}
|
|
66
73
|
return p;
|
|
@@ -115,6 +122,7 @@ export const Locator: React.FC<LocatorProps> = ({
|
|
|
115
122
|
shadowRadius: float ? 15 : 0,
|
|
116
123
|
shadowOffset: {
|
|
117
124
|
height: 10,
|
|
125
|
+
width: 0,
|
|
118
126
|
},
|
|
119
127
|
borderRadius: 10,
|
|
120
128
|
marginBottom: 10,
|
|
@@ -25,14 +25,10 @@ export const OTPInput: FC<OTPInputProps> = ({
|
|
|
25
25
|
[length]
|
|
26
26
|
);
|
|
27
27
|
|
|
28
|
-
console.log("v", value);
|
|
29
|
-
|
|
30
28
|
const onChangeHandler = (val: string, index: number) => {
|
|
31
29
|
if (value.length >= length && val.length > 0) return;
|
|
32
30
|
// Handle pasting of full OTP
|
|
33
31
|
if (val.length > 1) {
|
|
34
|
-
console.log("reached", val);
|
|
35
|
-
|
|
36
32
|
const digits = val.replace(/\D/g, "").slice(0, length);
|
|
37
33
|
onChange(digits);
|
|
38
34
|
if (digits.length === length) {
|
package/src/Components/Popup.tsx
CHANGED
|
@@ -9,28 +9,110 @@ import {
|
|
|
9
9
|
View,
|
|
10
10
|
} from "react-native";
|
|
11
11
|
|
|
12
|
-
import React, { useState } from "react";
|
|
13
|
-
import {
|
|
12
|
+
import React, { useEffect, useState } from "react";
|
|
13
|
+
import Animated, {
|
|
14
|
+
CurvedTransition,
|
|
15
|
+
LinearTransition,
|
|
16
|
+
runOnJS,
|
|
17
|
+
SequencedTransition,
|
|
18
|
+
useAnimatedStyle,
|
|
19
|
+
useSharedValue,
|
|
20
|
+
withTiming,
|
|
21
|
+
} from "react-native-reanimated";
|
|
22
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
23
|
+
import { ms, ScaledSheet } from "react-native-size-matters";
|
|
14
24
|
import { useColors, useTheme } from "../hooks";
|
|
25
|
+
import { UIThemeProvider } from "../theme";
|
|
15
26
|
import { PopupProps } from "../types";
|
|
16
27
|
import { IconButton } from "./Button";
|
|
17
28
|
import Typography from "./Typography";
|
|
18
|
-
import { UIThemeProvider } from "../theme";
|
|
19
29
|
|
|
20
30
|
export const Popup: React.FC<PopupProps> = ({
|
|
21
31
|
title,
|
|
22
|
-
sheet,
|
|
32
|
+
sheet = true,
|
|
23
33
|
bare = false,
|
|
24
34
|
keyboardVerticalOffset,
|
|
25
35
|
children,
|
|
26
36
|
open,
|
|
27
37
|
onClose = () => {},
|
|
28
38
|
style,
|
|
39
|
+
onModalShow,
|
|
40
|
+
onModalHide,
|
|
41
|
+
disableAutoKeyboardManagement = false,
|
|
29
42
|
}) => {
|
|
30
43
|
const theme = useTheme();
|
|
31
44
|
const colors = useColors();
|
|
32
|
-
const [
|
|
33
|
-
const [
|
|
45
|
+
const [modalVisible, setModalVisible] = useState(false);
|
|
46
|
+
const [modalOpen, setModalOpen] = useState(false);
|
|
47
|
+
const [keyboardVisible, setKeyboardVisible] = useState(false);
|
|
48
|
+
const { bottom } = useSafeAreaInsets();
|
|
49
|
+
|
|
50
|
+
// Animation values
|
|
51
|
+
const backdropOpacity = useSharedValue(0);
|
|
52
|
+
const contentTranslateY = useSharedValue(1000);
|
|
53
|
+
|
|
54
|
+
// Memoized keyboard vertical offset based on platform and keyboard state
|
|
55
|
+
const keyboardVerticalOffsetValue =
|
|
56
|
+
Platform.OS === "ios" ? -bottom : -bottom * 2;
|
|
57
|
+
|
|
58
|
+
// Keyboard event listeners
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
const keyboardDidShowListener = Keyboard.addListener(
|
|
61
|
+
"keyboardDidShow",
|
|
62
|
+
() => {
|
|
63
|
+
setKeyboardVisible(true);
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
const keyboardDidHideListener = Keyboard.addListener(
|
|
67
|
+
"keyboardDidHide",
|
|
68
|
+
() => {
|
|
69
|
+
setKeyboardVisible(false);
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return () => {
|
|
74
|
+
keyboardDidHideListener?.remove();
|
|
75
|
+
keyboardDidShowListener?.remove();
|
|
76
|
+
};
|
|
77
|
+
}, []);
|
|
78
|
+
|
|
79
|
+
const _onModalShow = () => {
|
|
80
|
+
setModalVisible(true);
|
|
81
|
+
onModalShow?.();
|
|
82
|
+
};
|
|
83
|
+
const _onModalHide = () => {
|
|
84
|
+
onModalHide?.();
|
|
85
|
+
setModalOpen(false);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Trigger animations when open prop changes
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
if (open) {
|
|
91
|
+
setModalOpen(true);
|
|
92
|
+
// Opening animation
|
|
93
|
+
backdropOpacity.value = withTiming(1, { duration: 300 });
|
|
94
|
+
contentTranslateY.value = withTiming(0, { duration: 300 }, () => {
|
|
95
|
+
runOnJS(_onModalShow)();
|
|
96
|
+
});
|
|
97
|
+
} else {
|
|
98
|
+
// Closing animation
|
|
99
|
+
setModalVisible(false);
|
|
100
|
+
|
|
101
|
+
backdropOpacity.value = withTiming(0, { duration: 200 });
|
|
102
|
+
contentTranslateY.value = withTiming(1000, { duration: 200 }, () => {
|
|
103
|
+
runOnJS(_onModalHide)();
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}, [open]);
|
|
107
|
+
|
|
108
|
+
// Animated styles
|
|
109
|
+
const backdropAnimatedStyle = useAnimatedStyle(() => ({
|
|
110
|
+
opacity: backdropOpacity.value,
|
|
111
|
+
}));
|
|
112
|
+
|
|
113
|
+
const contentAnimatedStyle = useAnimatedStyle(() => ({
|
|
114
|
+
transform: [{ translateY: contentTranslateY.value }],
|
|
115
|
+
}));
|
|
34
116
|
|
|
35
117
|
const styles: any = ScaledSheet.create({
|
|
36
118
|
root: {
|
|
@@ -38,28 +120,32 @@ export const Popup: React.FC<PopupProps> = ({
|
|
|
38
120
|
width: "100%",
|
|
39
121
|
justifyContent: sheet ? "flex-end" : "center",
|
|
40
122
|
},
|
|
123
|
+
keyboardView: {
|
|
124
|
+
flex: 1,
|
|
125
|
+
zIndex: 1000,
|
|
126
|
+
},
|
|
41
127
|
avoidingView: {
|
|
128
|
+
zIndex: 2,
|
|
42
129
|
minHeight: typeof sheet === "number" ? sheet : undefined,
|
|
43
|
-
maxHeight: "
|
|
44
|
-
zIndex: 1000,
|
|
130
|
+
maxHeight: "90%",
|
|
45
131
|
alignSelf: "center",
|
|
46
132
|
maxWidth: sheet ? undefined : "90%",
|
|
47
|
-
|
|
48
133
|
width: sheet ? "100%" : undefined,
|
|
134
|
+
marginBottom: Platform.OS === "android" && keyboardVisible ? bottom : 0,
|
|
49
135
|
},
|
|
50
136
|
container: {
|
|
51
|
-
paddingBottom: sheet ?
|
|
52
|
-
backgroundColor: theme === "dark" ? "#111" : colors.white[
|
|
137
|
+
paddingBottom: sheet && !bare ? bottom + ms(10) : undefined,
|
|
138
|
+
backgroundColor: theme === "dark" ? "#111" : colors.white[1],
|
|
53
139
|
borderTopLeftRadius: 20,
|
|
54
140
|
borderTopRightRadius: 20,
|
|
55
141
|
borderBottomRightRadius: sheet ? 0 : 20,
|
|
56
142
|
borderBottomLeftRadius: sheet ? 0 : 20,
|
|
57
143
|
width: "100%",
|
|
144
|
+
overflow: "hidden",
|
|
58
145
|
...style,
|
|
59
146
|
},
|
|
60
147
|
content: {
|
|
61
148
|
paddingHorizontal: bare ? undefined : "15@ms",
|
|
62
|
-
// flex: 1,
|
|
63
149
|
},
|
|
64
150
|
title: {
|
|
65
151
|
flexDirection: "row",
|
|
@@ -74,87 +160,79 @@ export const Popup: React.FC<PopupProps> = ({
|
|
|
74
160
|
backdrop: {
|
|
75
161
|
position: "absolute",
|
|
76
162
|
height: "100%",
|
|
77
|
-
zIndex:
|
|
163
|
+
zIndex: 1,
|
|
78
164
|
width: "100%",
|
|
79
165
|
backgroundColor: "#000b",
|
|
80
166
|
},
|
|
81
167
|
});
|
|
82
168
|
|
|
83
|
-
React.useEffect(() => {
|
|
84
|
-
if (open) {
|
|
85
|
-
setShow(open);
|
|
86
|
-
setTimeout(() => {
|
|
87
|
-
setShowSecondary(open);
|
|
88
|
-
}, 500);
|
|
89
|
-
} else {
|
|
90
|
-
closeAction();
|
|
91
|
-
}
|
|
92
|
-
}, [open]);
|
|
93
|
-
|
|
94
169
|
const closeAction = () => {
|
|
95
|
-
|
|
96
|
-
setTimeout(() => {
|
|
97
|
-
setShow(false);
|
|
98
|
-
onClose();
|
|
99
|
-
}, 300);
|
|
170
|
+
onClose();
|
|
100
171
|
};
|
|
101
172
|
|
|
102
173
|
return (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
>
|
|
111
|
-
<View style={styles.backdrop} />
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
174
|
+
<Modal
|
|
175
|
+
transparent
|
|
176
|
+
animationType="none"
|
|
177
|
+
statusBarTranslucent
|
|
178
|
+
visible={modalOpen}
|
|
179
|
+
onRequestClose={closeAction}
|
|
180
|
+
>
|
|
181
|
+
<UIThemeProvider>
|
|
182
|
+
<Animated.View style={[styles.backdrop, backdropAnimatedStyle]} />
|
|
183
|
+
<KeyboardAvoidingView
|
|
184
|
+
style={styles.keyboardView}
|
|
185
|
+
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
186
|
+
keyboardVerticalOffset={
|
|
187
|
+
keyboardVerticalOffset || keyboardVerticalOffsetValue
|
|
188
|
+
}
|
|
189
|
+
>
|
|
190
|
+
<TouchableWithoutFeedback
|
|
191
|
+
onPress={Keyboard.dismiss}
|
|
192
|
+
disabled={disableAutoKeyboardManagement}
|
|
119
193
|
>
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
194
|
+
<View style={styles.root}>
|
|
195
|
+
{modalOpen && (
|
|
196
|
+
<Pressable
|
|
197
|
+
style={[StyleSheet.absoluteFill, { zIndex: 1 }]}
|
|
198
|
+
onPress={closeAction}
|
|
199
|
+
/>
|
|
200
|
+
)}
|
|
201
|
+
|
|
202
|
+
<Animated.View
|
|
203
|
+
style={[styles.avoidingView, contentAnimatedStyle]}
|
|
204
|
+
layout={
|
|
205
|
+
modalVisible
|
|
206
|
+
? LinearTransition.springify()
|
|
207
|
+
.stiffness(200)
|
|
208
|
+
.mass(0.5)
|
|
209
|
+
.damping(100)
|
|
210
|
+
: undefined
|
|
211
|
+
}
|
|
212
|
+
>
|
|
213
|
+
<View style={styles.container}>
|
|
214
|
+
{!bare && (
|
|
215
|
+
<View style={styles.title}>
|
|
216
|
+
<View style={styles.titleIcon}>
|
|
217
|
+
<IconButton
|
|
218
|
+
size={20}
|
|
219
|
+
icon="close"
|
|
220
|
+
onPress={closeAction}
|
|
221
|
+
/>
|
|
147
222
|
</View>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
223
|
+
<Typography align="center" fontWeight={500}>
|
|
224
|
+
{title}
|
|
225
|
+
</Typography>
|
|
226
|
+
</View>
|
|
227
|
+
)}
|
|
228
|
+
|
|
229
|
+
<View style={styles.content}>{children}</View>
|
|
230
|
+
</View>
|
|
231
|
+
</Animated.View>
|
|
232
|
+
</View>
|
|
233
|
+
</TouchableWithoutFeedback>
|
|
234
|
+
</KeyboardAvoidingView>
|
|
235
|
+
</UIThemeProvider>
|
|
236
|
+
</Modal>
|
|
159
237
|
);
|
|
160
238
|
};
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { SafeAreaView as Safe } from "react-native";
|
|
2
1
|
import React from "react";
|
|
2
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
import { moderateScale } from "react-native-size-matters";
|
|
4
|
+
import { StyleSheet, View } from "react-native";
|
|
6
5
|
import { SafeAreaViewProps } from "../types";
|
|
7
6
|
|
|
8
|
-
const styles = StyleSheet.create({
|
|
9
|
-
droidSafeArea: {
|
|
10
|
-
flex: 1,
|
|
11
|
-
paddingTop: Platform.OS === "android" ? moderateScale(35) : 0,
|
|
12
|
-
},
|
|
13
|
-
});
|
|
14
|
-
|
|
15
7
|
export const SafeAreaView: React.FC<SafeAreaViewProps> = ({
|
|
16
8
|
children,
|
|
17
9
|
style,
|
|
18
10
|
}) => {
|
|
19
|
-
|
|
11
|
+
const { top, bottom } = useSafeAreaInsets();
|
|
12
|
+
const styles = StyleSheet.create({
|
|
13
|
+
root: {
|
|
14
|
+
paddingTop: top,
|
|
15
|
+
paddingBottom: bottom,
|
|
16
|
+
flex: 1,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
return <View style={[styles.root, style]}>{children}</View>;
|
|
20
20
|
};
|