@hoddy-ui/core 2.5.25 → 2.5.27
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/package.json +1 -1
- package/src/Components/FlashMessage.tsx +53 -29
- package/src/Components/Popup.tsx +25 -14
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useRef, useState } from "react";
|
|
1
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
2
2
|
import { TouchableOpacity, View } from "react-native";
|
|
3
3
|
import Animated, {
|
|
4
4
|
runOnJS,
|
|
@@ -12,7 +12,20 @@ import { useColors } from "../hooks";
|
|
|
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();
|
|
@@ -43,33 +56,44 @@ const FlashMessage: React.FC = () => {
|
|
|
43
56
|
});
|
|
44
57
|
};
|
|
45
58
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
useEffect(() => {
|
|
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
|
+
};
|
|
62
87
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
};
|
|
88
|
+
const unsubscribe = subscribeToFlashMessages(listener);
|
|
89
|
+
return () => {
|
|
90
|
+
if (timeoutRef.current) {
|
|
91
|
+
clearTimeout(timeoutRef.current);
|
|
92
|
+
timeoutRef.current = null;
|
|
93
|
+
}
|
|
94
|
+
unsubscribe();
|
|
95
|
+
};
|
|
96
|
+
}, [message, opacity, translateY]);
|
|
73
97
|
|
|
74
98
|
const animatedStyle = useAnimatedStyle(() => {
|
|
75
99
|
return {
|
|
@@ -104,7 +128,7 @@ const FlashMessage: React.FC = () => {
|
|
|
104
128
|
},
|
|
105
129
|
});
|
|
106
130
|
|
|
107
|
-
if (!message) return null;
|
|
131
|
+
// if (!message) return null;
|
|
108
132
|
|
|
109
133
|
return (
|
|
110
134
|
<Animated.View style={[styles.root, animatedStyle]}>
|
package/src/Components/Popup.tsx
CHANGED
|
@@ -42,6 +42,7 @@ export const Popup: React.FC<PopupProps> = ({
|
|
|
42
42
|
const theme = useTheme();
|
|
43
43
|
const colors = useColors();
|
|
44
44
|
const [modalVisible, setModalVisible] = useState(false);
|
|
45
|
+
const [modalOpen, setModalOpen] = useState(false);
|
|
45
46
|
const [keyboardVisible, setKeyboardVisible] = useState(false);
|
|
46
47
|
const { bottom } = useSafeAreaInsets();
|
|
47
48
|
|
|
@@ -74,25 +75,31 @@ export const Popup: React.FC<PopupProps> = ({
|
|
|
74
75
|
};
|
|
75
76
|
}, []);
|
|
76
77
|
|
|
78
|
+
const _onModalShow = () => {
|
|
79
|
+
setModalVisible(true);
|
|
80
|
+
onModalShow?.();
|
|
81
|
+
};
|
|
82
|
+
const _onModalHide = () => {
|
|
83
|
+
onModalHide?.();
|
|
84
|
+
setModalOpen(false);
|
|
85
|
+
};
|
|
86
|
+
|
|
77
87
|
// Trigger animations when open prop changes
|
|
78
88
|
useEffect(() => {
|
|
79
89
|
if (open) {
|
|
80
|
-
|
|
90
|
+
setModalOpen(true);
|
|
81
91
|
// Opening animation
|
|
82
92
|
backdropOpacity.value = withTiming(1, { duration: 300 });
|
|
83
93
|
contentTranslateY.value = withTiming(0, { duration: 300 }, () => {
|
|
84
|
-
|
|
85
|
-
runOnJS(onModalShow)();
|
|
86
|
-
}
|
|
94
|
+
runOnJS(_onModalShow)();
|
|
87
95
|
});
|
|
88
96
|
} else {
|
|
89
97
|
// Closing animation
|
|
98
|
+
setModalVisible(false);
|
|
99
|
+
|
|
90
100
|
backdropOpacity.value = withTiming(0, { duration: 200 });
|
|
91
101
|
contentTranslateY.value = withTiming(1000, { duration: 200 }, () => {
|
|
92
|
-
runOnJS(
|
|
93
|
-
if (onModalHide) {
|
|
94
|
-
runOnJS(onModalHide)();
|
|
95
|
-
}
|
|
102
|
+
runOnJS(_onModalHide)();
|
|
96
103
|
});
|
|
97
104
|
}
|
|
98
105
|
}, [open]);
|
|
@@ -167,7 +174,7 @@ export const Popup: React.FC<PopupProps> = ({
|
|
|
167
174
|
transparent
|
|
168
175
|
animationType="none"
|
|
169
176
|
statusBarTranslucent
|
|
170
|
-
visible={
|
|
177
|
+
visible={modalOpen}
|
|
171
178
|
onRequestClose={closeAction}
|
|
172
179
|
>
|
|
173
180
|
<UIThemeProvider>
|
|
@@ -181,7 +188,7 @@ export const Popup: React.FC<PopupProps> = ({
|
|
|
181
188
|
>
|
|
182
189
|
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
|
|
183
190
|
<View style={styles.root}>
|
|
184
|
-
{
|
|
191
|
+
{modalOpen && (
|
|
185
192
|
<Pressable
|
|
186
193
|
style={[StyleSheet.absoluteFill, { zIndex: 1 }]}
|
|
187
194
|
onPress={closeAction}
|
|
@@ -190,10 +197,14 @@ export const Popup: React.FC<PopupProps> = ({
|
|
|
190
197
|
|
|
191
198
|
<Animated.View
|
|
192
199
|
style={[styles.avoidingView, contentAnimatedStyle]}
|
|
193
|
-
layout={
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
200
|
+
layout={
|
|
201
|
+
modalVisible
|
|
202
|
+
? LinearTransition.springify()
|
|
203
|
+
.stiffness(200)
|
|
204
|
+
.mass(0.5)
|
|
205
|
+
.damping(100)
|
|
206
|
+
: undefined
|
|
207
|
+
}
|
|
197
208
|
>
|
|
198
209
|
<View style={styles.container}>
|
|
199
210
|
{!bare && (
|