@dropi/react-native-design-system 0.3.8 → 0.3.10
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.
|
@@ -18,9 +18,14 @@ const ToastProvider = ({
|
|
|
18
18
|
const [currentToast, setCurrentToast] = (0, _react.useState)(null);
|
|
19
19
|
const [queue, setQueue] = (0, _react.useState)([]);
|
|
20
20
|
const [isAnimating, setIsAnimating] = (0, _react.useState)(false);
|
|
21
|
-
const slideAnim = (0, _react.useRef)(new _reactNative.Animated.Value(-
|
|
21
|
+
const slideAnim = (0, _react.useRef)(new _reactNative.Animated.Value(-200)).current;
|
|
22
22
|
const timeoutRef = (0, _react.useRef)(null);
|
|
23
|
+
const animationRef = (0, _react.useRef)(null);
|
|
23
24
|
const toastIdCounter = (0, _react.useRef)(0);
|
|
25
|
+
const isAnimatingRef = (0, _react.useRef)(false);
|
|
26
|
+
const processQueueRef = (0, _react.useRef)(null);
|
|
27
|
+
const animateInRef = (0, _react.useRef)(null);
|
|
28
|
+
const animateOutRef = (0, _react.useRef)(null);
|
|
24
29
|
|
|
25
30
|
// Cleanup timers on unmount
|
|
26
31
|
(0, _react.useEffect)(() => {
|
|
@@ -28,13 +33,71 @@ const ToastProvider = ({
|
|
|
28
33
|
if (timeoutRef.current) {
|
|
29
34
|
clearTimeout(timeoutRef.current);
|
|
30
35
|
}
|
|
36
|
+
if (animationRef.current) {
|
|
37
|
+
animationRef.current.stop();
|
|
38
|
+
}
|
|
31
39
|
};
|
|
32
40
|
}, []);
|
|
33
41
|
|
|
34
|
-
//
|
|
42
|
+
// Keep isAnimatingRef in sync
|
|
43
|
+
(0, _react.useEffect)(() => {
|
|
44
|
+
isAnimatingRef.current = isAnimating;
|
|
45
|
+
}, [isAnimating]);
|
|
46
|
+
|
|
47
|
+
// Process the next toast in the queue
|
|
48
|
+
const processQueue = (0, _react.useCallback)(() => {
|
|
49
|
+
setTimeout(() => {
|
|
50
|
+
setQueue(prevQueue => {
|
|
51
|
+
if (prevQueue.length === 0) return prevQueue;
|
|
52
|
+
const [nextToast, ...remainingQueue] = prevQueue;
|
|
53
|
+
setCurrentToast(nextToast);
|
|
54
|
+
return remainingQueue;
|
|
55
|
+
});
|
|
56
|
+
}, 0);
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
59
|
+
// Keep processQueueRef updated
|
|
60
|
+
(0, _react.useEffect)(() => {
|
|
61
|
+
processQueueRef.current = processQueue;
|
|
62
|
+
}, [processQueue]);
|
|
63
|
+
|
|
64
|
+
// Animate out the toast - stable with useRef
|
|
65
|
+
const animateOut = (0, _react.useCallback)(callback => {
|
|
66
|
+
if (animationRef.current) {
|
|
67
|
+
animationRef.current.stop();
|
|
68
|
+
}
|
|
69
|
+
setIsAnimating(true);
|
|
70
|
+
animationRef.current = _reactNative.Animated.timing(slideAnim, {
|
|
71
|
+
toValue: -200,
|
|
72
|
+
duration: 400,
|
|
73
|
+
useNativeDriver: true
|
|
74
|
+
});
|
|
75
|
+
animationRef.current.start(({
|
|
76
|
+
finished
|
|
77
|
+
}) => {
|
|
78
|
+
if (finished) {
|
|
79
|
+
setIsAnimating(false);
|
|
80
|
+
requestAnimationFrame(() => {
|
|
81
|
+
setCurrentToast(null);
|
|
82
|
+
if (callback) {
|
|
83
|
+
callback();
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}, [slideAnim]);
|
|
89
|
+
|
|
90
|
+
// Keep animateOutRef updated
|
|
91
|
+
(0, _react.useEffect)(() => {
|
|
92
|
+
animateOutRef.current = animateOut;
|
|
93
|
+
}, [animateOut]);
|
|
94
|
+
|
|
95
|
+
// Animate in the toast - stable with useRef
|
|
35
96
|
const animateIn = (0, _react.useCallback)(() => {
|
|
97
|
+
if (isAnimatingRef.current) return;
|
|
36
98
|
setIsAnimating(true);
|
|
37
|
-
|
|
99
|
+
slideAnim.setValue(-200);
|
|
100
|
+
animationRef.current = _reactNative.Animated.sequence([_reactNative.Animated.timing(slideAnim, {
|
|
38
101
|
toValue: _reactNative.Platform.OS === 'ios' ? 100 : 50 + _utils.statusBarHeight,
|
|
39
102
|
duration: 300,
|
|
40
103
|
useNativeDriver: true
|
|
@@ -42,72 +105,75 @@ const ToastProvider = ({
|
|
|
42
105
|
toValue: _reactNative.Platform.OS === 'ios' ? 80 : 30 + _utils.statusBarHeight,
|
|
43
106
|
duration: 120,
|
|
44
107
|
useNativeDriver: true
|
|
45
|
-
})])
|
|
46
|
-
|
|
108
|
+
})]);
|
|
109
|
+
animationRef.current.start(({
|
|
110
|
+
finished
|
|
111
|
+
}) => {
|
|
112
|
+
if (finished) {
|
|
113
|
+
setIsAnimating(false);
|
|
114
|
+
}
|
|
47
115
|
});
|
|
48
116
|
}, [slideAnim]);
|
|
49
117
|
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
_reactNative.Animated.timing(slideAnim, {
|
|
55
|
-
toValue: -100,
|
|
56
|
-
duration: 400,
|
|
57
|
-
useNativeDriver: true
|
|
58
|
-
}).start(() => {
|
|
59
|
-
setIsAnimating(false);
|
|
60
|
-
setCurrentToast(null);
|
|
61
|
-
callback?.();
|
|
62
|
-
});
|
|
63
|
-
}, [slideAnim, isAnimating]);
|
|
118
|
+
// Keep animateInRef updated
|
|
119
|
+
(0, _react.useEffect)(() => {
|
|
120
|
+
animateInRef.current = animateIn;
|
|
121
|
+
}, [animateIn]);
|
|
64
122
|
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
123
|
+
// Auto-process queue when currentToast is null and queue has items
|
|
124
|
+
(0, _react.useEffect)(() => {
|
|
125
|
+
if (!currentToast && !isAnimating && queue.length > 0) {
|
|
126
|
+
// Defer to avoid state update during render
|
|
127
|
+
setTimeout(() => {
|
|
128
|
+
setQueue(prevQueue => {
|
|
129
|
+
if (prevQueue.length === 0) return prevQueue;
|
|
130
|
+
const [nextToast, ...remainingQueue] = prevQueue;
|
|
131
|
+
setCurrentToast(nextToast);
|
|
132
|
+
return remainingQueue;
|
|
133
|
+
});
|
|
134
|
+
}, 0);
|
|
135
|
+
}
|
|
136
|
+
}, [currentToast, isAnimating, queue.length]);
|
|
74
137
|
|
|
75
|
-
// Handle auto-dismiss
|
|
138
|
+
// Handle auto-dismiss - only depends on currentToast
|
|
76
139
|
(0, _react.useEffect)(() => {
|
|
77
140
|
if (!currentToast) return;
|
|
78
141
|
|
|
79
142
|
// Clear any existing timeout
|
|
80
143
|
if (timeoutRef.current) {
|
|
81
144
|
clearTimeout(timeoutRef.current);
|
|
145
|
+
timeoutRef.current = null;
|
|
82
146
|
}
|
|
83
147
|
|
|
84
|
-
// Animate in
|
|
85
|
-
|
|
148
|
+
// Animate in using ref
|
|
149
|
+
animateInRef.current?.();
|
|
86
150
|
|
|
87
151
|
// Set auto-dismiss if duration > 0
|
|
88
152
|
if (currentToast.duration && currentToast.duration > 0) {
|
|
89
153
|
timeoutRef.current = setTimeout(() => {
|
|
90
|
-
|
|
91
|
-
|
|
154
|
+
animateOutRef.current?.(() => {
|
|
155
|
+
processQueueRef.current?.();
|
|
92
156
|
});
|
|
93
157
|
}, currentToast.duration);
|
|
94
158
|
}
|
|
95
159
|
return () => {
|
|
96
160
|
if (timeoutRef.current) {
|
|
97
161
|
clearTimeout(timeoutRef.current);
|
|
162
|
+
timeoutRef.current = null;
|
|
98
163
|
}
|
|
99
164
|
};
|
|
100
|
-
}, [currentToast
|
|
165
|
+
}, [currentToast]); // Solo depende de currentToast para evitar bucle infinito
|
|
101
166
|
|
|
102
167
|
// Handle manual close
|
|
103
168
|
const handleClose = (0, _react.useCallback)(() => {
|
|
104
169
|
if (timeoutRef.current) {
|
|
105
170
|
clearTimeout(timeoutRef.current);
|
|
171
|
+
timeoutRef.current = null;
|
|
106
172
|
}
|
|
107
173
|
animateOut(() => {
|
|
108
|
-
|
|
174
|
+
processQueueRef.current?.();
|
|
109
175
|
});
|
|
110
|
-
}, [animateOut
|
|
176
|
+
}, [animateOut]);
|
|
111
177
|
|
|
112
178
|
// Public API: showToast
|
|
113
179
|
const showToast = (0, _react.useCallback)(params => {
|