@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.
Files changed (38) hide show
  1. package/README.md +155 -28
  2. package/next/dist/index.d.mts +113 -41
  3. package/next/dist/index.d.ts +113 -41
  4. package/next/dist/index.js +444 -297
  5. package/next/dist/index.js.map +1 -1
  6. package/next/dist/index.mjs +460 -307
  7. package/next/dist/index.mjs.map +1 -1
  8. package/next/package.json +7 -6
  9. package/package.json +7 -5
  10. package/src/Components/AlertX.tsx +4 -4
  11. package/src/Components/Animators/Animator.tsx +1 -1
  12. package/src/Components/Animators/hooks/useAppState.ts +4 -11
  13. package/src/Components/Animators/hooks/useBlinkAnimation.ts +31 -24
  14. package/src/Components/Animators/hooks/useFadeAnimation.ts +28 -26
  15. package/src/Components/Animators/hooks/useFloatAnimation.ts +67 -57
  16. package/src/Components/Animators/hooks/useGrowAnimation.ts +41 -28
  17. package/src/Components/Animators/hooks/useRollAnimation.ts +77 -57
  18. package/src/Components/Animators/hooks/useSlideAnimation.ts +44 -35
  19. package/src/Components/Animators/hooks/useThrownUpAnimation.ts +43 -50
  20. package/src/Components/Avatar.tsx +13 -7
  21. package/src/Components/Button.tsx +13 -12
  22. package/src/Components/FlashMessage.tsx +119 -42
  23. package/src/Components/FormWrapper.tsx +7 -2
  24. package/src/Components/Grid.tsx +5 -5
  25. package/src/Components/Locator.tsx +10 -2
  26. package/src/Components/OTPInput.tsx +0 -4
  27. package/src/Components/Popup.tsx +161 -83
  28. package/src/Components/SafeAreaView.tsx +11 -11
  29. package/src/Components/SelectMenu.tsx +34 -52
  30. package/src/Components/TextField.tsx +16 -6
  31. package/src/Components/Typography.tsx +19 -16
  32. package/src/config/KeyManager.ts +6 -1
  33. package/src/config/index.ts +37 -2
  34. package/src/hooks.ts +21 -14
  35. package/src/theme/index.tsx +14 -6
  36. package/src/types.ts +12 -3
  37. package/src/utility.ts +11 -0
  38. package/src/Components/Animators/README.md +0 -137
@@ -1,47 +1,111 @@
1
- import React, { useEffect, useState } from "react";
2
- import {
3
- LayoutAnimation,
4
- Touchable,
5
- TouchableOpacity,
6
- View,
7
- } from "react-native";
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
- export let showFlashMessage: (msg: FlashMessageProps) => void = () => {};
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
- showFlashMessage = (msg: FlashMessageProps) => {
25
- setMessage(msg);
26
- setTimeout(() => {
27
- setShow(true);
28
- }, 50);
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
- LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
39
- }, [show]);
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: show ? 0 : -200,
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
- <View style={{ flexDirection: "row" }}>
70
- <View style={{ flex: 1, marginRight: 10 }}>
71
- {message?.title && (
72
- <Typography
73
- variant="h6"
74
- fontWeight={600}
75
- gutterBottom={3}
76
- style={{ color: "#fff" }}
77
- >
78
- {message?.title}
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
- <Typography style={{ color: "#fff" }}>{message?.message}</Typography>
151
+ </View>
152
+ {/* <MaterialIcons color="#fff" size={36} name="error-outline" /> */}
82
153
  </View>
83
- {/* <MaterialIcons color="#fff" size={36} name="error-outline" /> */}
84
- </View>
154
+ </TouchableOpacity>
85
155
 
86
156
  {message?.actions?.map((cur, i) => (
87
- <TouchableOpacity key={i} style={styles.action} onPress={cur.onPress}>
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}
@@ -1,6 +1,6 @@
1
- import { View, Text } from "react-native";
2
1
  import React from "react";
3
- import { ScaledSheet } from "react-native-size-matters";
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 + "@ms",
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 + "@ms",
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 { formatted_address: description, place_id } = res.results[key];
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) {
@@ -9,28 +9,110 @@ import {
9
9
  View,
10
10
  } from "react-native";
11
11
 
12
- import React, { useState } from "react";
13
- import { ScaledSheet } from "react-native-size-matters";
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 [show, setShow] = useState(open);
33
- const [showSecondary, setShowSecondary] = useState(false);
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: "80%",
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 ? "30@ms" : 0,
52
- backgroundColor: theme === "dark" ? "#111" : colors.white[2],
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: -1,
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
- setShowSecondary(false);
96
- setTimeout(() => {
97
- setShow(false);
98
- onClose();
99
- }, 300);
170
+ onClose();
100
171
  };
101
172
 
102
173
  return (
103
- <>
104
- <Modal
105
- transparent
106
- animationType="fade"
107
- statusBarTranslucent
108
- visible={show}
109
- onRequestClose={closeAction}
110
- >
111
- <View style={styles.backdrop} />
112
- <UIThemeProvider>
113
- <Modal
114
- transparent
115
- animationType="slide"
116
- statusBarTranslucent
117
- visible={showSecondary}
118
- onRequestClose={closeAction}
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
- <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
121
- <View style={styles.root}>
122
- {open && (
123
- <Pressable
124
- style={StyleSheet.absoluteFill}
125
- onPress={closeAction}
126
- />
127
- )}
128
-
129
- <KeyboardAvoidingView
130
- style={styles.avoidingView}
131
- keyboardVerticalOffset={keyboardVerticalOffset}
132
- behavior={Platform.OS === "ios" ? "position" : "padding"}
133
- >
134
- <View style={styles.container}>
135
- {!bare && (
136
- <View style={styles.title}>
137
- <View style={styles.titleIcon}>
138
- <IconButton
139
- size={20}
140
- icon="close"
141
- onPress={closeAction}
142
- />
143
- </View>
144
- <Typography align="center" fontWeight={500}>
145
- {title}
146
- </Typography>
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
- <View style={styles.content}>{children}</View>
151
- </View>
152
- </KeyboardAvoidingView>
153
- </View>
154
- </TouchableWithoutFeedback>
155
- </Modal>
156
- </UIThemeProvider>
157
- </Modal>
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 { Platform, StyleSheet } from "react-native";
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
- return <Safe style={{ ...styles.droidSafeArea, ...style }}>{children}</Safe>;
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
  };