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.
@@ -1,54 +1,54 @@
1
- import React from 'react';
2
- import { render, act } from '@testing-library/react-native';
3
- import Toast from '../Toast'; // Adjust the import path as needed
4
-
5
- jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper'); // Mock for animated
6
-
7
- describe('Toast Component', () => {
8
- jest.useFakeTimers();
9
-
10
- it('should render and show toast', () => {
11
- const { getByText } = render(
12
- <Toast visible={true} duration={2000} position="bottom">
13
- Test Toast
14
- </Toast>
15
- );
16
-
17
- expect(getByText('Test Toast')).toBeTruthy();
18
- });
19
-
20
- it('should hide toast after duration', () => {
21
- const onHideMock = jest.fn();
22
-
23
- const { queryByText } = render(
24
- <Toast visible={true} duration={2000} position="bottom" onHide={onHideMock}>
25
- Test Toast
26
- </Toast>
27
- );
28
-
29
- act(() => {
30
- jest.advanceTimersByTime(2000);
31
- });
32
-
33
- expect(queryByText('Test Toast')).toBeNull();
34
- expect(onHideMock).toHaveBeenCalled();
35
- });
36
-
37
- it('should apply correct styles based on position', () => {
38
- const { getByText, rerender } = render(
39
- <Toast visible={true} duration={2000} position="top">
40
- Test Toast
41
- </Toast>
42
- );
43
-
44
- expect(getByText('Test Toast').parent.parent.props.style).toContainEqual({ top: 0 });
45
-
46
- rerender(
47
- <Toast visible={true} duration={2000} position="bottom">
48
- Test Toast
49
- </Toast>
50
- );
51
-
52
- expect(getByText('Test Toast').parent.parent.props.style).toContainEqual({ bottom: 50 });
53
- });
54
- });
1
+ import React from 'react';
2
+ import { render, act } from '@testing-library/react-native';
3
+ import Toast from '../Toast'; // Adjust the import path as needed
4
+
5
+ jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper'); // Mock for animated
6
+
7
+ describe('Toast Component', () => {
8
+ jest.useFakeTimers();
9
+
10
+ it('should render and show toast', () => {
11
+ const { getByText } = render(
12
+ <Toast visible={true} duration={2000} position="bottom">
13
+ Test Toast
14
+ </Toast>
15
+ );
16
+
17
+ expect(getByText('Test Toast')).toBeTruthy();
18
+ });
19
+
20
+ it('should hide toast after duration', () => {
21
+ const onHideMock = jest.fn();
22
+
23
+ const { queryByText } = render(
24
+ <Toast visible={true} duration={2000} position="bottom" onHide={onHideMock}>
25
+ Test Toast
26
+ </Toast>
27
+ );
28
+
29
+ act(() => {
30
+ jest.advanceTimersByTime(2000);
31
+ });
32
+
33
+ expect(queryByText('Test Toast')).toBeNull();
34
+ expect(onHideMock).toHaveBeenCalled();
35
+ });
36
+
37
+ it('should apply correct styles based on position', () => {
38
+ const { getByText, rerender } = render(
39
+ <Toast visible={true} duration={2000} position="top">
40
+ Test Toast
41
+ </Toast>
42
+ );
43
+
44
+ expect(getByText('Test Toast').parent.parent.props.style).toContainEqual({ top: 0 });
45
+
46
+ rerender(
47
+ <Toast visible={true} duration={2000} position="bottom">
48
+ Test Toast
49
+ </Toast>
50
+ );
51
+
52
+ expect(getByText('Test Toast').parent.parent.props.style).toContainEqual({ bottom: 50 });
53
+ });
54
+ });
@@ -0,0 +1,163 @@
1
+ import React from 'react';
2
+ import { View, Text, StyleSheet, Platform } from 'react-native';
3
+ import {
4
+ heightPercentageToDP as hp,
5
+ widthPercentageToDP as wp,
6
+ } from '../utils/Pixel/Index';
7
+ import { TOAST_THEME, TOAST_COLORS } from '../utils/theme';
8
+ import ProgressBar from './ProgressBar';
9
+
10
+ /**
11
+ * BaseToast — Premium shared layout for all built-in toast types.
12
+ *
13
+ * Design: Compact card with rounded icon badge, subtle accent,
14
+ * floating shadow, and an edge-to-edge progress indicator.
15
+ */
16
+ const BaseToast = ({
17
+ icon,
18
+ title,
19
+ message,
20
+ accentColor,
21
+ toastType = 'info',
22
+ theme = 'light',
23
+ duration,
24
+ showProgress = true,
25
+ children,
26
+ }) => {
27
+ const isDark = theme === 'dark';
28
+ const themeColors = TOAST_THEME[isDark ? 'dark' : 'light'];
29
+ const colors = TOAST_COLORS[toastType] || TOAST_COLORS.info;
30
+ const iconBgColor = isDark ? colors.iconBgDark : colors.iconBg;
31
+
32
+ return (
33
+ <View
34
+ style={[
35
+ styles.container,
36
+ {
37
+ backgroundColor: themeColors.background,
38
+ borderColor: themeColors.border,
39
+ ...Platform.select({
40
+ ios: {
41
+ shadowColor: themeColors.shadow,
42
+ shadowOffset: { width: 0, height: 8 },
43
+ shadowOpacity: isDark ? 0.6 : 1,
44
+ shadowRadius: 24,
45
+ },
46
+ android: {
47
+ elevation: 8,
48
+ },
49
+ }),
50
+ },
51
+ ]}
52
+ accessibilityRole="alert"
53
+ accessibilityLiveRegion="polite"
54
+ accessibilityLabel={
55
+ [title, message].filter(Boolean).join('. ')
56
+ }
57
+ >
58
+ {/* Left Edge Accent */}
59
+ <View style={[styles.leftAccent, { backgroundColor: accentColor || colors.accent }]} />
60
+
61
+ {/* Content row */}
62
+ <View style={styles.body}>
63
+ {/* Icon wrapper without the heavy badge background */}
64
+ {icon && (
65
+ <View style={styles.iconContainer}>
66
+ {icon}
67
+ </View>
68
+ )}
69
+
70
+ {/* Text content */}
71
+ <View style={styles.textContainer}>
72
+ {title ? (
73
+ <Text
74
+ style={[styles.title, { color: themeColors.title }]}
75
+ numberOfLines={1}
76
+ ellipsizeMode="tail"
77
+ >
78
+ {title}
79
+ </Text>
80
+ ) : null}
81
+ {message ? (
82
+ <Text
83
+ style={[
84
+ styles.message,
85
+ { color: themeColors.message },
86
+ !title && styles.messageSolo,
87
+ ]}
88
+ numberOfLines={2}
89
+ ellipsizeMode="tail"
90
+ >
91
+ {message}
92
+ </Text>
93
+ ) : null}
94
+ {children}
95
+ </View>
96
+ </View>
97
+
98
+ {/* Progress bar — flush to bottom edge */}
99
+ {showProgress && duration && duration !== Infinity && (
100
+ <ProgressBar
101
+ duration={duration}
102
+ color={accentColor}
103
+ trackColor={themeColors.progressTrack}
104
+ />
105
+ )}
106
+ </View>
107
+ );
108
+ };
109
+
110
+ const styles = StyleSheet.create({
111
+ container: {
112
+ width: wp(88),
113
+ maxWidth: 400,
114
+ borderRadius: 24,
115
+ overflow: 'hidden',
116
+ borderWidth: 1,
117
+ },
118
+ leftAccent: {
119
+ position: 'absolute',
120
+ left: 0,
121
+ top: 0,
122
+ bottom: 0,
123
+ width: 4,
124
+ },
125
+ body: {
126
+ flexDirection: 'row',
127
+ alignItems: 'center',
128
+ paddingHorizontal: 16,
129
+ paddingVertical: 14,
130
+ paddingLeft: 20,
131
+ },
132
+ iconContainer: {
133
+ width: 36,
134
+ height: 36,
135
+ alignItems: 'center',
136
+ justifyContent: 'center',
137
+ marginRight: 12,
138
+ },
139
+ textContainer: {
140
+ flex: 1,
141
+ justifyContent: 'center',
142
+ },
143
+ title: {
144
+ fontSize: 15,
145
+ fontWeight: '700',
146
+ letterSpacing: -0.2,
147
+ lineHeight: 20,
148
+ },
149
+ message: {
150
+ fontSize: 13,
151
+ fontWeight: '500',
152
+ marginTop: 2,
153
+ lineHeight: 18,
154
+ letterSpacing: -0.1,
155
+ },
156
+ messageSolo: {
157
+ fontSize: 14,
158
+ fontWeight: '600',
159
+ lineHeight: 20,
160
+ },
161
+ });
162
+
163
+ export default React.memo(BaseToast);
@@ -0,0 +1,58 @@
1
+ import React from 'react';
2
+ import { View, StyleSheet, Platform } from 'react-native';
3
+ import {
4
+ widthPercentageToDP as wp,
5
+ } from '../utils/Pixel/Index';
6
+ import { TOAST_THEME } from '../utils/theme';
7
+
8
+ /**
9
+ * CustomToast — Wrapper for user-provided custom content.
10
+ * Matches the premium design system card style.
11
+ */
12
+ const CustomToast = ({ content, theme = 'light' }) => {
13
+ const isDark = theme === 'dark';
14
+ const themeColors = TOAST_THEME[isDark ? 'dark' : 'light'];
15
+
16
+ return (
17
+ <View
18
+ style={[
19
+ styles.container,
20
+ {
21
+ backgroundColor: themeColors.background,
22
+ borderColor: themeColors.border,
23
+ ...Platform.select({
24
+ ios: {
25
+ shadowColor: themeColors.shadow,
26
+ shadowOffset: { width: 0, height: 8 },
27
+ shadowOpacity: isDark ? 0.6 : 1,
28
+ shadowRadius: 24,
29
+ },
30
+ android: {
31
+ elevation: 8,
32
+ },
33
+ }),
34
+ },
35
+ ]}
36
+ accessibilityRole="alert"
37
+ accessibilityLiveRegion="polite"
38
+ >
39
+ {content}
40
+ </View>
41
+ );
42
+ };
43
+
44
+ const styles = StyleSheet.create({
45
+ container: {
46
+ width: wp(88),
47
+ maxWidth: 400,
48
+ paddingHorizontal: 16,
49
+ paddingVertical: 14,
50
+ borderRadius: 24,
51
+ overflow: 'hidden',
52
+ flexDirection: 'row',
53
+ alignItems: 'center',
54
+ borderWidth: 1,
55
+ },
56
+ });
57
+
58
+ export default CustomToast;
@@ -1,28 +1,5 @@
1
- import React from 'react';
2
- import { View, StyleSheet } from 'react-native';
3
- import {
4
- heightPercentageToDP as hp,
5
- widthPercentageToDP as wp,
6
- } from '../utils/Pixel/Index';
7
-
8
- const CustomToast = ({ content, theme = 'light' }) => {
9
- const isDark = theme === 'dark';
10
- const bg = isDark ? '#111827' : '#FFFFFF';
11
- return (
12
- <View style={[styles.customToast, { backgroundColor: bg }]}>
13
- {content}
14
- </View>
15
- );
16
- };
17
-
18
- const styles = StyleSheet.create({
19
- customToast: {
20
- padding: wp(1),
21
- borderRadius: wp(2),
22
- backgroundColor: 'white',
23
- flexDirection: 'row',
24
- alignItems: 'center',
25
- },
26
- });
27
-
28
- export default CustomToast;
1
+ // Backward compatibility re-export
2
+ // The correct name is "CustomToast" — this file exists for consumers
3
+ // who imported the old misspelled name.
4
+ import CustomToast from './CustomToast';
5
+ export default CustomToast;
@@ -1,38 +1,142 @@
1
- import React from 'react';
2
- import { View, Text, StyleSheet } from 'react-native';
3
- import {
4
- heightPercentageToDP as hp,
5
- widthPercentageToDP as wp,
6
- } from '../utils/Pixel/Index';
7
-
8
- const EmojiToast = ({ message, emoji, theme = 'light' }) => {
9
- const isDark = theme === 'dark';
10
- const bg = isDark ? '#111827' : '#F7F7FC';
11
- const textColor = isDark ? '#F3F4F6' : 'black';
12
-
13
- return (
14
- <View style={[styles.emojiToast, { backgroundColor: bg }]}>
15
- <Text style={[styles.text, { color: textColor }]}>{emoji} {message}</Text>
16
- </View>
17
- );
18
- }
19
- const styles = StyleSheet.create({
20
- emojiToast: {
21
- width: wp(87),
22
- height: hp(6.8),
23
- paddingHorizontal: wp(4),
24
- borderRadius: wp(4),
25
- // backgroundColor: '#d2f7d2',
26
- backgroundColor: '#F7F7FC',
27
- alignItems: 'center',
28
- flexDirection: 'row',
29
-
30
- },
31
- text: {
32
- fontSize: hp(2.2),
33
- color: 'black',
34
- paddingHorizontal: wp(1.5)
35
- },
36
- });
37
-
38
- export default EmojiToast;
1
+ import React, { useEffect } from 'react';
2
+ import { View, Text, StyleSheet, Platform } from 'react-native';
3
+ import Animated, {
4
+ useSharedValue,
5
+ useAnimatedStyle,
6
+ withSpring,
7
+ } from 'react-native-reanimated';
8
+ import {
9
+ widthPercentageToDP as wp,
10
+ } from '../utils/Pixel/Index';
11
+ import { TOAST_THEME } from '../utils/theme';
12
+ import ProgressBar from './ProgressBar';
13
+
14
+ /**
15
+ * EmojiToast Toast with an emoji and bounce animation.
16
+ * Styled to match the premium design system.
17
+ */
18
+ const EmojiToast = ({ title, message, emoji, theme = 'light', duration }) => {
19
+ const isDark = theme === 'dark';
20
+ const themeColors = TOAST_THEME[isDark ? 'dark' : 'light'];
21
+ const emojiScale = useSharedValue(0.3);
22
+
23
+ useEffect(() => {
24
+ emojiScale.value = withSpring(1, { damping: 8, stiffness: 200 });
25
+ }, []);
26
+
27
+ const emojiAnimStyle = useAnimatedStyle(() => ({
28
+ transform: [{ scale: emojiScale.value }],
29
+ }));
30
+
31
+ return (
32
+ <View
33
+ style={[
34
+ styles.container,
35
+ {
36
+ backgroundColor: themeColors.background,
37
+ borderColor: themeColors.border,
38
+ ...Platform.select({
39
+ ios: {
40
+ shadowColor: themeColors.shadow,
41
+ shadowOffset: { width: 0, height: 4 },
42
+ shadowOpacity: isDark ? 0.4 : 0.08,
43
+ shadowRadius: 12,
44
+ },
45
+ android: {
46
+ elevation: 6,
47
+ },
48
+ }),
49
+ },
50
+ ]}
51
+ accessibilityRole="alert"
52
+ accessibilityLiveRegion="polite"
53
+ accessibilityLabel={[emoji, title, message].filter(Boolean).join('. ')}
54
+ >
55
+ <View style={styles.body}>
56
+ <Animated.View style={[styles.emojiBadge, emojiAnimStyle]}>
57
+ <Text style={styles.emojiText}>{emoji}</Text>
58
+ </Animated.View>
59
+ <View style={styles.textContainer}>
60
+ {title ? (
61
+ <Text
62
+ style={[styles.title, { color: themeColors.title }]}
63
+ numberOfLines={1}
64
+ >
65
+ {title}
66
+ </Text>
67
+ ) : null}
68
+ {message ? (
69
+ <Text
70
+ style={[
71
+ styles.message,
72
+ { color: themeColors.message },
73
+ !title && styles.messageSolo,
74
+ ]}
75
+ numberOfLines={2}
76
+ >
77
+ {message}
78
+ </Text>
79
+ ) : null}
80
+ </View>
81
+ </View>
82
+ {duration && duration !== Infinity && (
83
+ <ProgressBar
84
+ duration={duration}
85
+ color="#8B5CF6"
86
+ trackColor={themeColors.progressTrack}
87
+ />
88
+ )}
89
+ </View>
90
+ );
91
+ };
92
+
93
+ const styles = StyleSheet.create({
94
+ container: {
95
+ width: wp(92),
96
+ borderRadius: 16,
97
+ overflow: 'hidden',
98
+ borderWidth: 1,
99
+ },
100
+ body: {
101
+ flexDirection: 'row',
102
+ alignItems: 'center',
103
+ paddingHorizontal: 16,
104
+ paddingVertical: 14,
105
+ },
106
+ emojiBadge: {
107
+ width: 40,
108
+ height: 40,
109
+ borderRadius: 12,
110
+ backgroundColor: 'rgba(139, 92, 246, 0.1)',
111
+ alignItems: 'center',
112
+ justifyContent: 'center',
113
+ marginRight: 12,
114
+ },
115
+ emojiText: {
116
+ fontSize: 22,
117
+ },
118
+ textContainer: {
119
+ flex: 1,
120
+ justifyContent: 'center',
121
+ },
122
+ title: {
123
+ fontSize: 15,
124
+ fontWeight: '600',
125
+ letterSpacing: -0.2,
126
+ lineHeight: 20,
127
+ },
128
+ message: {
129
+ fontSize: 13,
130
+ fontWeight: '400',
131
+ marginTop: 2,
132
+ lineHeight: 18,
133
+ letterSpacing: -0.1,
134
+ },
135
+ messageSolo: {
136
+ fontSize: 14,
137
+ fontWeight: '500',
138
+ lineHeight: 20,
139
+ },
140
+ });
141
+
142
+ export default React.memo(EmojiToast);
@@ -1,52 +1,23 @@
1
- // src/components/ToastHelpers/ErrorToast.js
2
- import LottieView from 'lottie-react-native';
3
- import React from 'react';
4
- import { View, Text, StyleSheet } from 'react-native';
5
- import {
6
- heightPercentageToDP as hp,
7
- widthPercentageToDP as wp,
8
- } from '../utils/Pixel/Index';
9
-
10
- const ErrorToast = ({ message, theme = 'light' }) => {
11
- const isDark = theme === 'dark';
12
- const containerBg = isDark ? '#111827' : '#F7F7FC';
13
- const textColor = isDark ? '#FEE2E2' : '#991B1B';
14
-
15
- return (
16
- <View style={[styles.container, { backgroundColor: containerBg }]}>
17
- <LottieView
18
- source={require('../../assets/animated_Icon/ErrorAnimation.json')} // Replace with your success Lottie animation path
19
- autoPlay
20
- loop={false}
21
- speed={1.5}
22
- style={styles.lottie}
23
- />
24
- <Text style={[styles.text, { color: textColor }]}>{message}</Text>
25
- </View>
26
- );
27
- }
28
-
29
- const styles = StyleSheet.create({
30
- container: {
31
- width: wp(87),
32
- height: hp(6.8),
33
- paddingHorizontal: wp(4),
34
- borderRadius: wp(4),
35
- // backgroundColor: '#f8c4c4',
36
- backgroundColor: '#F7F7FC',
37
- alignItems: 'center',
38
- flexDirection: 'row'
39
- },
40
- text: {
41
- fontSize: hp(2.3),
42
- color: 'black',
43
- fontWeight: '500',
44
- paddingHorizontal: wp(3)
45
- },
46
- lottie: {
47
- width: wp(8.5),
48
- height: hp(4.5),
49
- },
50
- });
51
-
52
- export default ErrorToast;
1
+ import React from 'react';
2
+ import BaseToast from './BaseToast';
3
+ import { CrossIcon } from './icons';
4
+ import { TOAST_COLORS, TOAST_DEFAULTS } from '../utils/theme';
5
+
6
+ const ErrorToast = ({ title, message, theme = 'light', duration }) => {
7
+ const isDark = theme === 'dark';
8
+ const colors = TOAST_COLORS.error;
9
+
10
+ return (
11
+ <BaseToast
12
+ icon={<CrossIcon size={TOAST_DEFAULTS.iconSize} color={isDark ? colors.iconDark : colors.icon} />}
13
+ title={title || null}
14
+ message={message || null}
15
+ accentColor={colors.accent}
16
+ toastType="error"
17
+ theme={theme}
18
+ duration={duration}
19
+ />
20
+ );
21
+ };
22
+
23
+ export default React.memo(ErrorToast);
@@ -0,0 +1,23 @@
1
+ import React from 'react';
2
+ import BaseToast from './BaseToast';
3
+ import { InfoIcon } from './icons';
4
+ import { TOAST_COLORS, TOAST_DEFAULTS } from '../utils/theme';
5
+
6
+ const InfoToast = ({ title, message, theme = 'light', duration }) => {
7
+ const isDark = theme === 'dark';
8
+ const colors = TOAST_COLORS.info;
9
+
10
+ return (
11
+ <BaseToast
12
+ icon={<InfoIcon size={TOAST_DEFAULTS.iconSize} color={isDark ? colors.iconDark : colors.icon} />}
13
+ title={title || null}
14
+ message={message || null}
15
+ accentColor={colors.accent}
16
+ toastType="info"
17
+ theme={theme}
18
+ duration={duration}
19
+ />
20
+ );
21
+ };
22
+
23
+ export default React.memo(InfoToast);