@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(-100)).current;
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
- // Animate in the toast
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
- _reactNative.Animated.sequence([_reactNative.Animated.timing(slideAnim, {
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
- })]).start(() => {
46
- setIsAnimating(false);
108
+ })]);
109
+ animationRef.current.start(({
110
+ finished
111
+ }) => {
112
+ if (finished) {
113
+ setIsAnimating(false);
114
+ }
47
115
  });
48
116
  }, [slideAnim]);
49
117
 
50
- // Animate out the toast
51
- const animateOut = (0, _react.useCallback)(callback => {
52
- if (isAnimating) return;
53
- setIsAnimating(true);
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
- // Process the next toast in the queue
66
- const processQueue = (0, _react.useCallback)(() => {
67
- setQueue(prevQueue => {
68
- if (prevQueue.length === 0) return prevQueue;
69
- const [nextToast, ...remainingQueue] = prevQueue;
70
- setCurrentToast(nextToast);
71
- return remainingQueue;
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
- animateIn();
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
- animateOut(() => {
91
- processQueue();
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, animateIn, animateOut, processQueue]);
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
- processQueue();
174
+ processQueueRef.current?.();
109
175
  });
110
- }, [animateOut, processQueue]);
176
+ }, [animateOut]);
111
177
 
112
178
  // Public API: showToast
113
179
  const showToast = (0, _react.useCallback)(params => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dropi/react-native-design-system",
3
- "version": "0.3.8",
3
+ "version": "0.3.10",
4
4
  "description": "A React Native package built from scratch",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",