@hoddy-ui/core 2.5.9 → 2.5.11

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/next/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hoddy-ui/next",
3
- "version": "2.0.51",
3
+ "version": "2.0.58",
4
4
  "description": "Core rich react native components written in typescript, with support for expo-router",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hoddy-ui/core",
3
- "version": "2.5.9",
3
+ "version": "2.5.11",
4
4
  "description": "Core rich react native components written in typescript",
5
5
  "main": "index.ts",
6
6
  "repository": {
@@ -40,9 +40,7 @@ export const useFadeAnimation = ({
40
40
  withTiming(1, { duration }, () => {
41
41
  if (closeAfter) {
42
42
  // Schedule fade-out after closeAfter duration
43
- setTimeout(() => {
44
- opacity.value = withTiming(0, { duration });
45
- }, closeAfter);
43
+ opacity.value = withDelay(closeAfter, withTiming(0, { duration }));
46
44
  }
47
45
  })
48
46
  );
@@ -64,11 +64,6 @@ export const useFloatAnimation = ({
64
64
  }
65
65
  };
66
66
 
67
- const stopFloating = () => {
68
- isFloating.current = false;
69
- translateY.value = withTiming(0, { duration: 200 });
70
- };
71
-
72
67
  useEffect(() => {
73
68
  if (!isActive && Platform.OS === "ios") {
74
69
  opacity.value = 0;
@@ -84,10 +79,15 @@ export const useFloatAnimation = ({
84
79
  startFloating();
85
80
 
86
81
  if (closeAfter) {
87
- setTimeout(() => {
88
- stopFloating();
89
- opacity.value = withTiming(0, { duration: closeDuration });
90
- }, closeAfter);
82
+ opacity.value = withDelay(
83
+ closeAfter,
84
+ withTiming(0, { duration: closeDuration })
85
+ );
86
+ translateY.value = withDelay(
87
+ closeAfter,
88
+ withTiming(0, { duration: closeDuration })
89
+ );
90
+ isFloating.current = false;
91
91
  }
92
92
  })
93
93
  );
@@ -48,12 +48,13 @@ export const useGrowAnimation = ({
48
48
  },
49
49
  () => {
50
50
  if (closeAfter) {
51
- setTimeout(() => {
52
- scale.value = withTiming(initialScale, {
51
+ scale.value = withDelay(
52
+ closeAfter,
53
+ withTiming(initialScale, {
53
54
  duration,
54
55
  easing: Easing.out(Easing.ease),
55
- });
56
- }, closeAfter);
56
+ })
57
+ );
57
58
  }
58
59
  }
59
60
  )
@@ -71,16 +71,20 @@ export const useRollAnimation = ({
71
71
  },
72
72
  () => {
73
73
  if (closeAfter) {
74
- setTimeout(() => {
75
- translateY.value = withTiming(initialTranslateY, {
74
+ translateY.value = withDelay(
75
+ closeAfter,
76
+ withTiming(initialTranslateY, {
76
77
  duration,
77
78
  easing: Easing.out(Easing.ease),
78
- });
79
- rotate.value = withTiming(0, {
79
+ })
80
+ );
81
+ rotate.value = withDelay(
82
+ closeAfter,
83
+ withTiming(0, {
80
84
  duration,
81
85
  easing: Easing.out(Easing.ease),
82
- });
83
- }, closeAfter);
86
+ })
87
+ );
84
88
  }
85
89
  }
86
90
  )
@@ -73,16 +73,13 @@ export const useSlideAnimation = ({
73
73
  );
74
74
 
75
75
  if (closeAfter) {
76
- const timer = setTimeout(() => {
77
- translateValue.value = withTiming(initialPosition, {
76
+ translateValue.value = withDelay(
77
+ closeAfter + duration + delay,
78
+ withTiming(initialPosition, {
78
79
  duration,
79
80
  easing: Easing.out(Easing.ease),
80
- });
81
- }, closeAfter + duration + delay);
82
-
83
- return () => {
84
- clearTimeout(timer);
85
- };
81
+ })
82
+ );
86
83
  }
87
84
  }, [
88
85
  translateValue,
@@ -50,22 +50,19 @@ export const useThrownUpAnimation = ({
50
50
  opacity.value = withDelay(delay, withTiming(1, { duration: 500 }));
51
51
 
52
52
  // Start timer to animate out after duration
53
- let timer: NodeJS.Timeout | null = null;
54
53
  if (closeAfter) {
55
- timer = setTimeout(() => {
56
- if (!isUnmounting.current) {
57
- translateY.value = withSpring(800, {
58
- velocity: 1,
59
- stiffness: 200,
60
- damping: 20,
61
- });
62
- opacity.value = withTiming(0, { duration: 500 });
63
- }
64
- }, closeAfter);
54
+ translateY.value = withDelay(
55
+ closeAfter,
56
+ withSpring(800, {
57
+ velocity: 1,
58
+ stiffness: 200,
59
+ damping: 20,
60
+ })
61
+ );
62
+ opacity.value = withDelay(closeAfter, withTiming(0, { duration: 500 }));
65
63
  }
66
64
 
67
65
  return () => {
68
- if (timer) clearTimeout(timer);
69
66
  translateY.value = 600;
70
67
  opacity.value = 0;
71
68
  isUnmounting.current = true;
@@ -11,25 +11,27 @@ import {
11
11
 
12
12
  import React, { useEffect, useState } from "react";
13
13
  import Animated, {
14
+ CurvedTransition,
14
15
  LinearTransition,
15
16
  runOnJS,
17
+ SequencedTransition,
16
18
  useAnimatedStyle,
17
19
  useSharedValue,
18
20
  withTiming,
19
21
  } from "react-native-reanimated";
22
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
20
23
  import { ms, ScaledSheet } from "react-native-size-matters";
21
24
  import { useColors, useTheme } from "../hooks";
22
25
  import { UIThemeProvider } from "../theme";
23
26
  import { PopupProps } from "../types";
24
27
  import { IconButton } from "./Button";
25
28
  import Typography from "./Typography";
26
- import { useSafeAreaInsets } from "react-native-safe-area-context";
27
29
 
28
30
  export const Popup: React.FC<PopupProps> = ({
29
31
  title,
30
32
  sheet,
31
33
  bare = false,
32
- keyboardVerticalOffset = -10,
34
+ keyboardVerticalOffset,
33
35
  children,
34
36
  open,
35
37
  onClose = () => {},
@@ -40,12 +42,38 @@ export const Popup: React.FC<PopupProps> = ({
40
42
  const theme = useTheme();
41
43
  const colors = useColors();
42
44
  const [modalVisible, setModalVisible] = useState(false);
45
+ const [keyboardVisible, setKeyboardVisible] = useState(false);
43
46
  const { bottom } = useSafeAreaInsets();
44
47
 
45
48
  // Animation values
46
49
  const backdropOpacity = useSharedValue(0);
47
50
  const contentTranslateY = useSharedValue(1000);
48
51
 
52
+ // Memoized keyboard vertical offset based on platform and keyboard state
53
+ const keyboardVerticalOffsetValue =
54
+ Platform.OS === "ios" ? -bottom : -bottom * 2;
55
+
56
+ // Keyboard event listeners
57
+ useEffect(() => {
58
+ const keyboardDidShowListener = Keyboard.addListener(
59
+ "keyboardDidShow",
60
+ () => {
61
+ setKeyboardVisible(true);
62
+ }
63
+ );
64
+ const keyboardDidHideListener = Keyboard.addListener(
65
+ "keyboardDidHide",
66
+ () => {
67
+ setKeyboardVisible(false);
68
+ }
69
+ );
70
+
71
+ return () => {
72
+ keyboardDidHideListener?.remove();
73
+ keyboardDidShowListener?.remove();
74
+ };
75
+ }, []);
76
+
49
77
  // Trigger animations when open prop changes
50
78
  useEffect(() => {
51
79
  if (open) {
@@ -86,14 +114,16 @@ export const Popup: React.FC<PopupProps> = ({
86
114
  },
87
115
  keyboardView: {
88
116
  flex: 1,
117
+ zIndex: 1000,
89
118
  },
90
119
  avoidingView: {
120
+ zIndex: 2,
91
121
  minHeight: typeof sheet === "number" ? sheet : undefined,
92
122
  maxHeight: "90%",
93
- zIndex: 1000,
94
123
  alignSelf: "center",
95
124
  maxWidth: sheet ? undefined : "90%",
96
125
  width: sheet ? "100%" : undefined,
126
+ marginBottom: Platform.OS === "android" && keyboardVisible ? bottom : 0,
97
127
  },
98
128
  container: {
99
129
  paddingBottom: sheet && !bare ? bottom + ms(10) : undefined,
@@ -141,29 +171,31 @@ export const Popup: React.FC<PopupProps> = ({
141
171
  onRequestClose={closeAction}
142
172
  >
143
173
  <UIThemeProvider>
174
+ <Animated.View style={[styles.backdrop, backdropAnimatedStyle]} />
144
175
  <KeyboardAvoidingView
145
176
  style={styles.keyboardView}
146
177
  behavior={Platform.OS === "ios" ? "padding" : "height"}
147
- keyboardVerticalOffset={keyboardVerticalOffset}
178
+ keyboardVerticalOffset={
179
+ keyboardVerticalOffset || keyboardVerticalOffsetValue
180
+ }
148
181
  >
149
182
  <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
150
183
  <View style={styles.root}>
151
- <Animated.View style={[styles.backdrop, backdropAnimatedStyle]} />
152
184
  {open && (
153
185
  <Pressable
154
- style={[StyleSheet.absoluteFill, { zIndex: 2 }]}
186
+ style={[StyleSheet.absoluteFill, { zIndex: 1 }]}
155
187
  onPress={closeAction}
156
188
  />
157
189
  )}
158
190
 
159
191
  <Animated.View
160
192
  style={[styles.avoidingView, contentAnimatedStyle]}
161
- layout={LinearTransition}
193
+ layout={LinearTransition.springify()
194
+ .stiffness(200)
195
+ .mass(0.5)
196
+ .damping(100)}
162
197
  >
163
- <Animated.View
164
- // layout={LinearTransition}
165
- style={styles.container}
166
- >
198
+ <View style={styles.container}>
167
199
  {!bare && (
168
200
  <View style={styles.title}>
169
201
  <View style={styles.titleIcon}>
@@ -180,7 +212,7 @@ export const Popup: React.FC<PopupProps> = ({
180
212
  )}
181
213
 
182
214
  <View style={styles.content}>{children}</View>
183
- </Animated.View>
215
+ </View>
184
216
  </Animated.View>
185
217
  </View>
186
218
  </TouchableWithoutFeedback>