rn-toastify 1.0.11 → 2.0.0

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/index.js CHANGED
@@ -1,35 +1,61 @@
1
- // Fixed index.js - Simplified export structure
2
- const useToastModule = require('./src/hooks/useToast');
3
- const ToastModule = require('./src/Toast');
4
- const ToastContainerModule = require('./src/context/ToastContainer');
5
- const SuccessToastModule = require('./src/components/SuccessToast');
6
- const CustomeToastModule = require('./src/components/CustomeToast');
7
- const EmojiToastModule = require('./src/components/EmojiToast');
8
- const ErrorToastModule = require('./src/components/ErrorToast');
9
- const LoadingToastModule = require('./src/components/LoadingToast');
10
-
11
- // Extract default exports properly
12
- const useToast = useToastModule.default || useToastModule;
13
- const Toast = ToastModule.default || ToastModule;
14
- const ToastContainer = ToastContainerModule.default || ToastContainerModule;
15
- const SuccessToast = SuccessToastModule.default || SuccessToastModule;
16
- const CustomeToast = CustomeToastModule.default || CustomeToastModule;
17
- const EmojiToast = EmojiToastModule.default || EmojiToastModule;
18
- const ErrorToast = ErrorToastModule.default || ErrorToastModule;
19
- const LoadingToast = LoadingToastModule.default || LoadingToastModule;
20
-
21
- // Primary default export
22
- module.exports = useToast;
23
-
24
- // Named exports
25
- module.exports.useToast = useToast;
26
- module.exports.Toast = Toast;
27
- module.exports.ToastContainer = ToastContainer;
28
- module.exports.SuccessToast = SuccessToast;
29
- module.exports.CustomeToast = CustomeToast;
30
- module.exports.EmojiToast = EmojiToast;
31
- module.exports.ErrorToast = ErrorToast;
32
- module.exports.LoadingToast = LoadingToast;
33
-
34
- // Also support default property for ES6 imports
1
+ // rn-toastify v2.0.0 — Production-ready toast notifications for React Native
2
+ const useToastModule = require('./src/hooks/useToast');
3
+ const ToastModule = require('./src/Toast');
4
+ const ToastContainerModule = require('./src/context/ToastContainer');
5
+ const ToastManagerModule = require('./src/context/ToastManager');
6
+ const SuccessToastModule = require('./src/components/SuccessToast');
7
+ const ErrorToastModule = require('./src/components/ErrorToast');
8
+ const InfoToastModule = require('./src/components/InfoToast');
9
+ const WarningToastModule = require('./src/components/WarningToast');
10
+ const LoadingToastModule = require('./src/components/LoadingToast');
11
+ const EmojiToastModule = require('./src/components/EmojiToast');
12
+ const CustomToastModule = require('./src/components/CustomToast');
13
+ const BaseToastModule = require('./src/components/BaseToast');
14
+ const ProgressBarModule = require('./src/components/ProgressBar');
15
+ const themeModule = require('./src/utils/theme');
16
+
17
+ // Extract default exports properly
18
+ const useToast = useToastModule.default || useToastModule;
19
+ const Toast = ToastModule.default || ToastModule;
20
+ const ToastContainer = ToastContainerModule.default || ToastContainerModule;
21
+ const ToastManager = ToastManagerModule.default || ToastManagerModule;
22
+ const SuccessToast = SuccessToastModule.default || SuccessToastModule;
23
+ const ErrorToast = ErrorToastModule.default || ErrorToastModule;
24
+ const InfoToast = InfoToastModule.default || InfoToastModule;
25
+ const WarningToast = WarningToastModule.default || WarningToastModule;
26
+ const LoadingToast = LoadingToastModule.default || LoadingToastModule;
27
+ const EmojiToast = EmojiToastModule.default || EmojiToastModule;
28
+ const CustomToast = CustomToastModule.default || CustomToastModule;
29
+ const BaseToast = BaseToastModule.default || BaseToastModule;
30
+ const ProgressBar = ProgressBarModule.default || ProgressBarModule;
31
+
32
+ // Primary default export
33
+ module.exports = useToast;
34
+
35
+ // Named exports
36
+ module.exports.useToast = useToast;
37
+ module.exports.Toast = Toast;
38
+ module.exports.ToastContainer = ToastContainer;
39
+ module.exports.ToastManager = ToastManager;
40
+
41
+ // Built-in toast components
42
+ module.exports.SuccessToast = SuccessToast;
43
+ module.exports.ErrorToast = ErrorToast;
44
+ module.exports.InfoToast = InfoToast;
45
+ module.exports.WarningToast = WarningToast;
46
+ module.exports.LoadingToast = LoadingToast;
47
+ module.exports.EmojiToast = EmojiToast;
48
+ module.exports.CustomToast = CustomToast;
49
+ module.exports.BaseToast = BaseToast;
50
+ module.exports.ProgressBar = ProgressBar;
51
+
52
+ // Theme utilities
53
+ module.exports.TOAST_COLORS = themeModule.TOAST_COLORS;
54
+ module.exports.TOAST_THEME = themeModule.TOAST_THEME;
55
+ module.exports.TOAST_DEFAULTS = themeModule.TOAST_DEFAULTS;
56
+
57
+ // Backward compatibility aliases
58
+ module.exports.CustomeToast = CustomToast;
59
+
60
+ // ES6 default
35
61
  module.exports.default = useToast;
package/jest.config.js CHANGED
@@ -1,14 +1,14 @@
1
- module.exports = {
2
- preset: 'react-native',
3
- testEnvironment: 'node',
4
- collectCoverage: true,
5
- collectCoverageFrom: ['src/**/*.{ts,tsx}'],
6
- setupFilesAfterEnv: [
7
- '@testing-library/jest-native/extend-expect',
8
- './jest.setup.js'
9
- ],
10
- transformIgnorePatterns: [
11
- 'node_modules/(?!(jest-)?react-native|@react-native|@react-navigation|@react-native-community|@expo)',
12
- ],
13
- moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
14
- };
1
+ module.exports = {
2
+ preset: 'react-native',
3
+ testEnvironment: 'node',
4
+ collectCoverage: true,
5
+ collectCoverageFrom: ['src/**/*.{ts,tsx}'],
6
+ setupFilesAfterEnv: [
7
+ '@testing-library/jest-native/extend-expect',
8
+ './jest.setup.js'
9
+ ],
10
+ transformIgnorePatterns: [
11
+ 'node_modules/(?!(jest-)?react-native|@react-native|@react-navigation|@react-native-community|@expo)',
12
+ ],
13
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
14
+ };
package/jest.setup.js CHANGED
@@ -1 +1 @@
1
- import '@testing-library/jest-native/extend-expect';
1
+ import '@testing-library/jest-native/extend-expect';
package/package.json CHANGED
@@ -1,44 +1,87 @@
1
- {
2
- "name": "rn-toastify",
3
- "version": "1.0.11",
4
- "description": "A customizable and performant toast notification library for React Native, featuring smooth animations, swipe gestures, and flexible styling options.",
5
- "main": "index.js",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/muku534/react-native-toast"
9
- },
10
- "homepage": "https://github.com/muku534/react-native-toast#readme",
11
- "scripts": {
12
- "test": "jest"
13
- },
14
- "keywords": [
15
- "react-native",
16
- "toast",
17
- "react-native-toastify",
18
- "react-native-toast",
19
- "react-native-toast-message",
20
- "rn-toastify",
21
- "alert",
22
- "notification",
23
- "library"
24
- ],
25
- "author": "Mukesh Prajapati",
26
- "license": "MIT",
27
- "peerDependencies": {
28
- "react": ">=16.8.0 <20.0.0",
29
- "react-native": ">=0.60.0 <1.0.0",
30
- "react-native-reanimated": ">=2.0.0 <5.0.0",
31
- "lottie-react-native": ">=3.0.0 <9.0.0"
32
- },
33
- "dependencies": {
34
- "events": "^3.3.0"
35
- },
36
- "devDependencies": {
37
- "@testing-library/jest-native": "^5.4.3",
38
- "@testing-library/react-native": "^12.5.2",
39
- "@types/jest": "^28.1.0",
40
- "@types/react-native": "^0.67.3",
41
- "jest": "^28.1.0",
42
- "react-test-renderer": "^17.0.2"
43
- }
1
+ {
2
+ "name": "rn-toastify",
3
+ "version": "2.0.0",
4
+ "description": "A professional, production-ready toast notification library for React Native. Featuring smooth spring animations, swipe-to-dismiss gestures, progress bars, queue management, and a beautiful design system with light/dark themes.",
5
+ "main": "index.js",
6
+ "types": "src/types.d.ts",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/muku534/react-native-toast"
10
+ },
11
+ "homepage": "https://github.com/muku534/react-native-toast#readme",
12
+ "scripts": {
13
+ "test": "jest"
14
+ },
15
+ "keywords": [
16
+ "react-native",
17
+ "react native",
18
+ "toast",
19
+ "toastify",
20
+ "notification",
21
+ "alert",
22
+ "snackbar",
23
+ "message",
24
+ "popup",
25
+ "react-native-toast",
26
+ "react-native-toastify",
27
+ "react-native-toast-message",
28
+ "react-native-notifications",
29
+ "rn-toast",
30
+ "rn-toastify",
31
+ "animated-toast",
32
+ "swipe-toast",
33
+ "promise-toast",
34
+ "success-toast",
35
+ "error-toast",
36
+ "info-toast",
37
+ "warning-toast",
38
+ "loading-toast",
39
+ "custom-toast",
40
+ "progress-bar",
41
+ "queue",
42
+ "dismiss",
43
+ "ios",
44
+ "android",
45
+ "cross-platform",
46
+ "reanimated",
47
+ "gesture",
48
+ "animation",
49
+ "spring-animation",
50
+ "dark-mode",
51
+ "theme",
52
+ "accessibility",
53
+ "production-ready",
54
+ "typescript",
55
+ "mobile",
56
+ "notification-library",
57
+ "alert-library",
58
+ "toast-notification",
59
+ "react-native-component"
60
+ ],
61
+ "author": {
62
+ "name": "Mukesh Prajapati",
63
+ "url": "https://github.com/muku534"
64
+ },
65
+ "license": "MIT",
66
+ "peerDependencies": {
67
+ "react": ">=16.8.0",
68
+ "react-native": ">=0.60.0",
69
+ "react-native-reanimated": ">=3.0.0"
70
+ },
71
+ "peerDependenciesMeta": {
72
+ "react-native-reanimated": {
73
+ "optional": false
74
+ }
75
+ },
76
+ "dependencies": {
77
+ "events": "^3.3.0"
78
+ },
79
+ "devDependencies": {
80
+ "@testing-library/jest-native": "^5.4.3",
81
+ "@testing-library/react-native": "^12.5.2",
82
+ "@types/jest": "^28.1.0",
83
+ "@types/react-native": "^0.67.3",
84
+ "jest": "^28.1.0",
85
+ "react-test-renderer": "^17.0.2"
86
+ }
44
87
  }
package/src/Toast.js CHANGED
@@ -1,114 +1,194 @@
1
- import React, { useEffect, useMemo } from 'react';
2
- import { PanResponder, StyleSheet } from 'react-native';
3
- import Animated, {
4
- useSharedValue,
5
- useAnimatedStyle,
6
- withTiming,
7
- withSpring,
8
- runOnJS,
9
- Easing,
10
- } from 'react-native-reanimated';
11
-
12
- const Toast = ({ visible, duration, position, children, onHide, style, theme }) => {
13
- const opacity = useSharedValue(0);
14
- const translateY = useSharedValue(position === 'top' ? -50 : 50);
15
- const translateX = useSharedValue(0);
16
- const scale = useSharedValue(0.9);
17
-
18
- const positionStyle = useMemo(() => (position === 'top' ? styles.top : styles.bottom), [position]);
19
-
20
- useEffect(() => {
21
- if (visible) {
22
- opacity.value = withTiming(1, { duration: 300 });
23
- translateY.value = withSpring(0, { damping: 10, stiffness: 120 });
24
- scale.value = withSpring(1, { damping: 10, stiffness: 120 });
25
-
26
- if (duration !== Infinity) {
27
- const hideTimeout = setTimeout(() => {
28
- hideToast();
29
- }, duration);
30
-
31
- return () => clearTimeout(hideTimeout);
32
- }
33
- } else {
34
- hideToast();
35
- }
36
- }, [visible, duration]);
37
-
38
- const hideToast = () => {
39
- opacity.value = withTiming(0, { duration: 300, easing: Easing.ease });
40
- translateY.value = withTiming(position === 'top' ? -50 : 50, { duration: 300, easing: Easing.ease });
41
- scale.value = withTiming(0.9, { duration: 300, easing: Easing.ease });
42
- runOnJS(onHide)();
43
- };
44
-
45
- const animatedStyle = useAnimatedStyle(() => ({
46
- opacity: opacity.value,
47
- transform: [
48
- { translateY: translateY.value },
49
- { translateX: translateX.value },
50
- { scale: scale.value },
51
- ],
52
- }));
53
-
54
- const panResponder = useMemo(
55
- () =>
56
- PanResponder.create({
57
- onMoveShouldSetPanResponder: (evt, gestureState) => {
58
- return Math.abs(gestureState.dx) > 20; // Swipe detection threshold
59
- },
60
- onPanResponderMove: (evt, gestureState) => {
61
- translateX.value = gestureState.dx; // Update translateX as the user swipes
62
- },
63
- onPanResponderRelease: (evt, gestureState) => {
64
- if (Math.abs(gestureState.dx) > 100) { // If the swipe distance is more than 100 pixels, remove the toast
65
- opacity.value = withTiming(0, { duration: 200 });
66
- translateY.value = withTiming(position === 'top' ? -50 : 50, { duration: 200 });
67
- scale.value = withTiming(0.9, { duration: 200 });
68
- runOnJS(onHide)();
69
- } else {
70
- // If the swipe is less than the threshold, reset the position
71
- translateX.value = withSpring(0);
72
- }
73
- },
74
- }),
75
- []
76
- );
77
-
78
- if (!visible) return null;
79
-
80
- // If children is a React element, inject theme prop; otherwise render as-is.
81
- const renderContent = () => {
82
- if (React.isValidElement(children)) {
83
- return React.cloneElement(children, { theme });
84
- }
85
- return children;
86
- };
87
-
88
- return (
89
- <Animated.View
90
- {...panResponder.panHandlers}
91
- style={[styles.container, animatedStyle, positionStyle, style]}
92
- >
93
- {renderContent()}
94
- </Animated.View>
95
- );
96
- };
97
-
98
- const styles = StyleSheet.create({
99
- container: {
100
- position: 'absolute',
101
- left: 0,
102
- right: 0,
103
- alignItems: 'center',
104
- zIndex: 9999,
105
- },
106
- top: {
107
- top: 0,
108
- },
109
- bottom: {
110
- bottom: 20,
111
- },
112
- });
113
-
114
- export default React.memo(Toast);
1
+ import React, { useEffect, useMemo, useCallback, useRef } from 'react';
2
+ import { PanResponder, StyleSheet } from 'react-native';
3
+ import Animated, {
4
+ useSharedValue,
5
+ useAnimatedStyle,
6
+ withTiming,
7
+ withSpring,
8
+ withDelay,
9
+ runOnJS,
10
+ Easing,
11
+ interpolate,
12
+ cancelAnimation,
13
+ } from 'react-native-reanimated';
14
+
15
+ const SPRING_CONFIG = {
16
+ damping: 18,
17
+ stiffness: 160,
18
+ mass: 0.8,
19
+ };
20
+
21
+ const Toast = ({ visible, duration, position, children, onHide, style, theme }) => {
22
+ const opacity = useSharedValue(0);
23
+ const translateY = useSharedValue(position === 'top' ? -80 : position === 'center' ? 30 : 80);
24
+ const translateX = useSharedValue(0);
25
+ const scale = useSharedValue(0.85);
26
+ const hideCalledRef = useRef(false);
27
+
28
+ const positionStyle = useMemo(
29
+ () => {
30
+ if (position === 'top') return styles.top;
31
+ if (position === 'center') return styles.center;
32
+ return styles.bottom;
33
+ },
34
+ [position]
35
+ );
36
+
37
+ const safeOnHide = useCallback(() => {
38
+ if (!hideCalledRef.current) {
39
+ hideCalledRef.current = true;
40
+ onHide?.();
41
+ }
42
+ }, [onHide]);
43
+
44
+ useEffect(() => {
45
+ hideCalledRef.current = false;
46
+
47
+ if (visible) {
48
+ // Entrance animation — smooth spring with overshoot
49
+ opacity.value = withTiming(1, { duration: 280, easing: Easing.out(Easing.cubic) });
50
+ translateY.value = withSpring(0, SPRING_CONFIG);
51
+ scale.value = withSpring(1, { ...SPRING_CONFIG, damping: 14 });
52
+ translateX.value = 0;
53
+
54
+ // Auto-dismiss timer
55
+ if (duration && duration !== Infinity) {
56
+ const hideTimeout = setTimeout(() => {
57
+ hideToast();
58
+ }, duration);
59
+
60
+ return () => clearTimeout(hideTimeout);
61
+ }
62
+ } else {
63
+ hideToast();
64
+ }
65
+ }, [visible, duration]);
66
+
67
+ const hideToast = useCallback(() => {
68
+ const exitY = position === 'top' ? -60 : position === 'center' ? 20 : 60;
69
+
70
+ opacity.value = withTiming(0, {
71
+ duration: 250,
72
+ easing: Easing.in(Easing.cubic),
73
+ });
74
+ translateY.value = withTiming(exitY, {
75
+ duration: 250,
76
+ easing: Easing.in(Easing.cubic),
77
+ });
78
+ scale.value = withTiming(0.9, {
79
+ duration: 250,
80
+ easing: Easing.in(Easing.cubic),
81
+ }, (finished) => {
82
+ // Only fire onHide after animation actually completes
83
+ if (finished) {
84
+ runOnJS(safeOnHide)();
85
+ }
86
+ });
87
+ }, [position, safeOnHide]);
88
+
89
+ const animatedStyle = useAnimatedStyle(() => ({
90
+ opacity: opacity.value,
91
+ transform: [
92
+ { translateY: translateY.value },
93
+ { translateX: translateX.value },
94
+ { scale: scale.value },
95
+ ],
96
+ }));
97
+
98
+ const panResponder = useMemo(
99
+ () =>
100
+ PanResponder.create({
101
+ onMoveShouldSetPanResponder: (evt, gestureState) => {
102
+ // More responsive swipe detection
103
+ return Math.abs(gestureState.dx) > 15 || Math.abs(gestureState.dy) > 15;
104
+ },
105
+ onPanResponderMove: (evt, gestureState) => {
106
+ translateX.value = gestureState.dx;
107
+ // Add subtle vertical follow for natural feel
108
+ if (position === 'top' && gestureState.dy < 0) {
109
+ translateY.value = gestureState.dy * 0.3;
110
+ } else if (position === 'bottom' && gestureState.dy > 0) {
111
+ translateY.value = gestureState.dy * 0.3;
112
+ }
113
+ // Fade as user swipes further
114
+ opacity.value = interpolate(
115
+ Math.abs(gestureState.dx),
116
+ [0, 150],
117
+ [1, 0.3],
118
+ 'clamp'
119
+ );
120
+ },
121
+ onPanResponderRelease: (evt, gestureState) => {
122
+ if (Math.abs(gestureState.dx) > 80) {
123
+ // Dismiss: fly out in swipe direction
124
+ const direction = gestureState.dx > 0 ? 1 : -1;
125
+ translateX.value = withTiming(direction * 400, { duration: 200 });
126
+ opacity.value = withTiming(0, { duration: 200 });
127
+ scale.value = withTiming(0.85, { duration: 200 }, (finished) => {
128
+ if (finished) {
129
+ runOnJS(safeOnHide)();
130
+ }
131
+ });
132
+ } else if (position === 'top' && gestureState.dy < -40) {
133
+ // Swipe up to dismiss (for top toasts)
134
+ translateY.value = withTiming(-100, { duration: 200 });
135
+ opacity.value = withTiming(0, { duration: 200 }, (finished) => {
136
+ if (finished) runOnJS(safeOnHide)();
137
+ });
138
+ } else if (position === 'bottom' && gestureState.dy > 40) {
139
+ // Swipe down to dismiss (for bottom toasts)
140
+ translateY.value = withTiming(100, { duration: 200 });
141
+ opacity.value = withTiming(0, { duration: 200 }, (finished) => {
142
+ if (finished) runOnJS(safeOnHide)();
143
+ });
144
+ } else {
145
+ // Snap back with spring
146
+ translateX.value = withSpring(0, { damping: 15, stiffness: 200 });
147
+ translateY.value = withSpring(0, { damping: 15, stiffness: 200 });
148
+ opacity.value = withSpring(1);
149
+ }
150
+ },
151
+ }),
152
+ [position, safeOnHide]
153
+ );
154
+
155
+ if (!visible) return null;
156
+
157
+ // If children is a React element, inject theme and duration props
158
+ const renderContent = () => {
159
+ if (React.isValidElement(children)) {
160
+ return React.cloneElement(children, { theme, duration });
161
+ }
162
+ return children;
163
+ };
164
+
165
+ return (
166
+ <Animated.View
167
+ {...panResponder.panHandlers}
168
+ style={[styles.container, animatedStyle, positionStyle, style]}
169
+ >
170
+ {renderContent()}
171
+ </Animated.View>
172
+ );
173
+ };
174
+
175
+ const styles = StyleSheet.create({
176
+ container: {
177
+ position: 'absolute',
178
+ left: 0,
179
+ right: 0,
180
+ alignItems: 'center',
181
+ zIndex: 9999,
182
+ },
183
+ top: {
184
+ top: 0,
185
+ },
186
+ center: {
187
+ // Center positioning handled by container
188
+ },
189
+ bottom: {
190
+ bottom: 20,
191
+ },
192
+ });
193
+
194
+ export default React.memo(Toast);