rn-toastify 1.0.8 → 1.0.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.
package/README.MD CHANGED
@@ -1,273 +1,190 @@
1
+ # React Native Toastify
1
2
 
2
- # react-native-toast
3
+ A highly customizable and performant toast notification library for React Native. Featuring smooth animations, swipe gestures, and flexible styling options.
3
4
 
4
-
5
- ## Demo
6
-
7
- Animated toast message component for React Native.
8
5
  ![Demo GIF](https://github.com/muku534/react-native-toast/blob/master/docs/Toast.gif)
9
6
 
7
+ ---
10
8
 
9
+ ## 🚀 Features
11
10
 
12
- ## Features
11
+ - **Single-root container**: Mount once at the app root.
12
+ - **Imperative API**: Use `useToast` hook anywhere in your app.
13
+ - **Light/Dark Theme**: System-aware with optional forced theme.
14
+ - **Promise Helper**: Show loading, success, and error states.
15
+ - **Customizable**: Add custom content, styles, and emojis.
13
16
 
14
- - 🚀 Imperative API
15
- - 🎨 Customizable layouts
16
- - 🔧 Flexible config
17
- - 📅 Promise Handling
18
- - 📍 Position Control
17
+ ---
19
18
 
19
+ ## 📦 Installation
20
20
 
21
-
22
- ## Installation
21
+ Install the package using npm or yarn:
23
22
 
24
23
  ```bash
25
24
  npm install rn-toastify
26
25
  ```
27
-
28
- ## Usage
29
-
30
- To integrate the toast notifications into your application, follow these steps:
31
-
32
- - Import and Setup
33
-
34
- Start by importing the necessary components and hooks from the library:
35
-
36
- ```javascript
37
- import useToast from 'rn-toastify';
38
- import ToastContainer from 'rn-toastify';
39
-
40
- const AppContent = () => {
41
- // Toast functions here
42
-
43
- return (
44
- <View style={styles.container}>
45
- {/* Buttons to trigger toasts */}
46
- <ToastContainer />
47
- </View>
48
- );
49
- };
50
26
 
51
- export default AppContent;
27
+ Or:
52
28
 
29
+ ```bash
30
+ yarn add rn-toastify
53
31
  ```
54
32
 
55
- - Implementing Toasts
56
-
57
- The useToast hook provides access to different types of toasts. Below are examples of how to implement each toast type:
33
+ ### Peer Dependencies
58
34
 
59
- - Success Toast
60
- ```javascript
61
- import useToast from 'rn-toastify';
62
-
63
- const { success } = useToast();
35
+ Ensure the following peer dependencies are installed:
64
36
 
65
- const handleSuccessToast = () => {
66
- success('Operation was successful!', { duration: 1500, position: 'top' });
67
- };
37
+ - `react`
38
+ - `react-native`
39
+ - `react-native-reanimated` (v2+)
40
+ - `lottie-react-native`
68
41
 
42
+ For iOS, run:
69
43
 
44
+ ```bash
45
+ cd ios && pod install
70
46
  ```
71
- - Error Toast
72
- ```javascript
73
- import useToast from 'rn-toastify';
74
47
 
75
- const { error } = useToast();
48
+ ---
76
49
 
77
- const handleErrorToast = () => {
78
- error('Something went wrong!', { duration: 1500, position: 'top' });
79
- };
50
+ ## 🛠️ Quick Start
80
51
 
52
+ ### Step 1: Mount the Toast Container
81
53
 
82
- ```
54
+ Add the `ToastContainer` to your app's root component (e.g., `App.js`):
83
55
 
84
- - Promise Toast
85
56
  ```javascript
86
- import useToast from 'rn-toastify';
87
-
88
- const { promise } = useToast();
89
-
90
- const handlePromiseToast = () => {
91
- const myPromise = new Promise((resolve, reject) => {
92
- setTimeout(() => {
93
- resolve();
94
- // reject();
95
- }, 1500);
96
- });
57
+ import React from 'react';
58
+ import { NavigationContainer } from '@react-navigation/native';
59
+ import MainNavigator from './src/navigation';
60
+ import { ToastContainer } from 'rn-toastify';
97
61
 
98
- promise(myPromise, {
99
- loading: 'Loading...',
100
- success: 'Promise resolved!',
101
- error: 'Promise rejected!',
102
- });
103
- };
62
+ export default function App() {
63
+ return (
64
+ <>
65
+ <NavigationContainer>
66
+ <MainNavigator />
67
+ </NavigationContainer>
68
+ <ToastContainer theme="dark" /> {/* Optional: Force theme */}
69
+ </>
70
+ );
71
+ }
72
+ ```
104
73
 
74
+ ### Step 2: Use the `useToast` Hook
105
75
 
106
- ```
76
+ Call toast methods anywhere in your app:
107
77
 
108
- - Custom Toast
109
78
  ```javascript
110
79
  import React from 'react';
111
- import { View, Text, Image, StyleSheet } from 'react-native';
80
+ import { View, Button } from 'react-native';
112
81
  import useToast from 'rn-toastify';
113
82
 
114
- const { custom } = useToast();
83
+ export default function HomeScreen() {
84
+ const { success, error } = useToast();
115
85
 
116
- const handleCustomToast = () => {
117
- custom(
118
- <View style={styles.customContent}>
119
- <Image
120
- style={styles.image}
121
- source={{
122
- uri: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixqx=6GHAjsWpt9&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2.2&w=160&h=160&q=80',
123
- }}
124
- />
125
- <View style={styles.textContainer}>
126
- <Text style={styles.customText}>Emilia Gates</Text>
127
- <Text style={styles.customSubText}>Sure! 8:30pm works great!</Text>
128
- </View>
129
- </View>,
130
- { duration: 1500, position: 'top' }
86
+ return (
87
+ <View>
88
+ <Button title="Show Success" onPress={() => success('Operation successful!')} />
89
+ <Button title="Show Error" onPress={() => error('Something went wrong.', { position: 'top' })} />
90
+ </View>
131
91
  );
132
- };
133
-
134
- const styles = StyleSheet.create({
135
- customContent: {
136
- flexDirection: 'row',
137
- alignItems: 'center',
138
- },
139
- image: {
140
- width: 50,
141
- height: 50,
142
- borderRadius: 25,
143
- },
144
- textContainer: {
145
- marginLeft: 10,
146
- },
147
- customText: {
148
- fontWeight: 'bold',
149
- },
150
- customSubText: {
151
- color: 'gray',
152
- },
153
- });
154
-
92
+ }
155
93
  ```
156
94
 
157
- - Emoji Toast
158
- ```javascript
159
- import useToast from 'rn-toastify';
95
+ ---
160
96
 
161
- const { emoji } = useToast();
97
+ ## 📖 API Reference
162
98
 
163
- const handleEmojiToast = () => {
164
- emoji('Great job!', '👍', { duration: 1500, position: 'top' });
165
- };
99
+ ### `useToast` Hook
166
100
 
167
- ```
101
+ The `useToast` hook provides the following methods:
168
102
 
169
- - Full Example
103
+ | Method | Description |
104
+ |----------|--------------------------------------|
105
+ | `show` | Display a custom toast. |
106
+ | `success`| Show a success toast. |
107
+ | `error` | Show an error toast. |
108
+ | `custom` | Render a custom React element. |
109
+ | `emoji` | Display a toast with an emoji. |
110
+ | `promise`| Handle promise states with toasts. |
170
111
 
171
- Here's a complete example to demonstrate how all the toast types can be implemented within a single component:
112
+ ### Common Options
172
113
 
173
- ```javascript
174
- import React from 'react';
175
- import { StyleSheet, View, Button } from 'react-native';
176
- import useToast from 'rn-toastify';
177
- import ToastContainer from 'rn-toastify';
114
+ | Option | Type | Description |
115
+ |------------|----------|--------------------------------------|
116
+ | `duration` | `number` | Duration in milliseconds. |
117
+ | `position` | `string` | `'top' | 'bottom' | 'center'`. |
118
+ | `style` | `object` | Custom styles for the toast wrapper. |
178
119
 
179
- const AppContent = () => {
180
- const { success, error, promise, custom, emoji } = useToast();
120
+ ### `promise` Method Options
181
121
 
182
- return (
183
- <View style={styles.container}>
184
- <Button title="Show Success Toast" onPress={() => success('Operation was successful!', { duration: 1500, position: 'top' })} />
185
- <Button title="Show Error Toast" onPress={() => error('Something went wrong!', { duration: 1500, position: 'top' })} />
186
- <Button title="Show Promise Toast" onPress={() => {
187
- const myPromise = new Promise((resolve) => setTimeout(resolve, 1500));
188
- promise(myPromise, { loading: 'Loading...', success: 'Promise resolved!', error: 'Promise rejected!' });
189
- }} />
190
- <Button title="Show Custom Toast" onPress={() => custom(
191
- <View style={styles.customContent}>
192
- <Text>Custom Toast Content</Text>
193
- </View>,
194
- { duration: 1500, position: 'top' }
195
- )} />
196
- <Button title="Show Emoji Toast" onPress={() => emoji('Great job!', '👍', { duration: 1500, position: 'top' })} />
197
- <ToastContainer />
198
- </View>
199
- );
200
- };
201
-
202
- const styles = StyleSheet.create({
203
- container: {
204
- flex: 1,
205
- justifyContent: 'center',
206
- alignItems: 'center',
207
- },
208
- customContent: {
209
- padding: 10,
210
- backgroundColor: '#fff',
211
- borderRadius: 5,
212
- },
213
- });
122
+ | Option | Type | Description |
123
+ |------------|----------|--------------------------------------|
124
+ | `loading` | `string` | Message during loading. |
125
+ | `success` | `string` | Message on success. |
126
+ | `error` | `string` | Message on error. |
214
127
 
215
- export default AppContent;
216
- ```
217
- This example integrates multiple toast types and demonstrates how to trigger each one. It also includes the necessary ToastContainer to display the toasts.
128
+ ---
218
129
 
130
+ ## 🌈 Examples
219
131
 
220
- ## API Reference
132
+ ### Success Toast
133
+
134
+ ```javascript
135
+ const { success } = useToast();
136
+ success('Operation successful!', { duration: 1500, position: 'top' });
137
+ ```
221
138
 
222
- #### useToast Hook Methods
223
- All toast methods accept the following parameters:
139
+ ### Promise Helper
224
140
 
225
- | Parameter | Type | Description |
226
- | :-------- | :------- | :------------------------- |
227
- | `message` | `string` | **Required**. The message to display in the toast. |
228
- | `options` | `object` | **Optional**. Configuration options for the toast (e.g., duration, position). |
141
+ ```javascript
142
+ const { promise } = useToast();
229
143
 
144
+ const myPromise = fetch('/api/save');
230
145
 
231
- - Methods
146
+ promise(myPromise, {
147
+ loading: 'Saving…',
148
+ success: 'Saved successfully!',
149
+ error: 'Save failed.',
150
+ });
151
+ ```
232
152
 
233
- - success : Displays a success toast.
153
+ ### Custom Content
234
154
 
235
- - error : Displays an error toast.
155
+ ```javascript
156
+ const { custom } = useToast();
157
+ custom(<MyCustomComponent />, { duration: 2000 });
158
+ ```
236
159
 
237
- - promise : Handles a promise and displays loading, success, and error toasts based on the promise's state.
160
+ ### Emoji Toast
238
161
 
239
- Additional options for promise method:
240
- | Option | Type | Description |
241
- | :-------- | :------- | :------------------------- |
242
- | `loading` | `string` | The message to display in the toast. |
243
- | `success` | `string` | Message to display if the promise resolves. |
244
- | `error` | `string` | Message to display if the promise is rejected. |
162
+ ```javascript
163
+ const { emoji } = useToast();
164
+ emoji('Great job!', '🎉', { duration: 1300 });
165
+ ```
245
166
 
246
- - custom
167
+ ---
247
168
 
248
- Displays a custom toast with your own content.
169
+ ## 🎨 Theme Support
249
170
 
250
- | Parameter | Type | Description |
251
- | :-------- | :------- | :------------------------- |
252
- | `content` | `element` | **Required**. React element to render in the toast. |
171
+ - **Automatic**: Detects system theme (light/dark).
172
+ - **Forced**: Pass `theme="light"` or `theme="dark"` to `ToastContainer`.
253
173
 
254
- - emoji
174
+ If the system theme is unavailable, the default is `light`.
255
175
 
256
- Displays a custom toast with your own content.
176
+ ---
257
177
 
258
- | Parameter | Type | Description |
259
- | :-------- | :------- | :------------------------- |
260
- | `emoji` | `string` | **Required**. The emoji to display alongside the message. |
178
+ ## 🐛 Troubleshooting
261
179
 
262
- - options
180
+ ### Common Issues
263
181
 
264
- All toast methods accept an options object for configuration:
182
+ - **Toasts not showing**: Ensure `ToastContainer` is mounted at the app root.
183
+ - **Reanimated errors**: Add the Reanimated Babel plugin and rebuild.
184
+ - **Lottie issues on iOS**: Run `cd ios && pod install`.
265
185
 
266
- | Option | Type | Description |
267
- | :-------- | :------- | :------------------------- |
268
- | `duration` | `number` |**Optional**. Duration in milliseconds for which the toast is visible. |
269
- | `position` | `string` | **Optional**. Position of the toast on the screen (top, bottom, center). |
186
+ ---
270
187
 
271
- ## License
188
+ ## 📜 License
272
189
 
273
- [MIT](https://choosealicense.com/licenses/mit/)
190
+ MIT License. See [LICENSE](./LICENSE) for details.
package/docs/Toast.gif CHANGED
Binary file
package/index.js CHANGED
@@ -1,8 +1,31 @@
1
- export { default as toast } from './src/Toast';
2
- export { default as useToast } from './src/hooks/useToast';
3
- export { default as ToastContainer } from './src/context/ToastContainer';
4
- export { SuccessToast } from './src/components/SuccessToast';
5
- export { CustomeToast } from './src/components/CustomeToast';
6
- export { EmojiToast } from './src/components/EmojiToast';
7
- export { ErrorToast } from './src/components/ErrorToast';
8
- export { LoadingToast } from './src/components/LoadingToast';
1
+ // CommonJS-friendly entry to avoid default/import interop issues with Metro in some RN versions
2
+ // We attempt to require modules and use .default if present (handles transpiled ESM)
3
+ const _useToastMod = require('./src/hooks/useToast');
4
+ const _toastMod = require('./src/Toast');
5
+ const _containerMod = require('./src/context/ToastContainer');
6
+ const _successMod = require('./src/components/SuccessToast');
7
+ const _customeMod = require('./src/components/CustomeToast');
8
+ const _emojiMod = require('./src/components/EmojiToast');
9
+ const _errorMod = require('./src/components/ErrorToast');
10
+ const _loadingMod = require('./src/components/LoadingToast');
11
+
12
+ const useToast = (_useToastMod && _useToastMod.__esModule) ? _useToastMod.default : _useToastMod;
13
+ const Toast = (_toastMod && _toastMod.__esModule) ? _toastMod.default : _toastMod;
14
+ const ToastContainer = (_containerMod && _containerMod.__esModule) ? _containerMod.default : _containerMod;
15
+ const SuccessToast = (_successMod && _successMod.__esModule) ? _successMod.default : _successMod;
16
+ const CustomeToast = (_customeMod && _customeMod.__esModule) ? _customeMod.default : _customeMod;
17
+ const EmojiToast = (_emojiMod && _emojiMod.__esModule) ? _emojiMod.default : _emojiMod;
18
+ const ErrorToast = (_errorMod && _errorMod.__esModule) ? _errorMod.default : _errorMod;
19
+ const LoadingToast = (_loadingMod && _loadingMod.__esModule) ? _loadingMod.default : _loadingMod;
20
+
21
+ // Export for both require() and import syntax
22
+ module.exports = useToast;
23
+ module.exports.default = useToast;
24
+ module.exports.useToast = useToast;
25
+ module.exports.Toast = Toast;
26
+ module.exports.ToastContainer = ToastContainer;
27
+ module.exports.SuccessToast = SuccessToast;
28
+ module.exports.CustomeToast = CustomeToast;
29
+ module.exports.EmojiToast = EmojiToast;
30
+ module.exports.ErrorToast = ErrorToast;
31
+ module.exports.LoadingToast = LoadingToast;
package/package.json CHANGED
@@ -1,44 +1,44 @@
1
- {
2
- "name": "rn-toastify",
3
- "version": "1.0.8",
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 <19.0.0",
29
- "react-native": ">=0.60.0 <1.0.0",
30
- "react-native-reanimated": ">=2.0.0 <4.0.0",
31
- "lottie-react-native": ">=3.0.0 <7.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": "1.0.10",
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 <19.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
+ }
44
44
  }
package/src/Toast.js CHANGED
@@ -9,7 +9,7 @@ import Animated, {
9
9
  Easing,
10
10
  } from 'react-native-reanimated';
11
11
 
12
- const Toast = ({ visible, duration, position, children, onHide, style }) => {
12
+ const Toast = ({ visible, duration, position, children, onHide, style, theme }) => {
13
13
  const opacity = useSharedValue(0);
14
14
  const translateY = useSharedValue(position === 'top' ? -50 : 50);
15
15
  const translateX = useSharedValue(0);
@@ -77,12 +77,20 @@ const Toast = ({ visible, duration, position, children, onHide, style }) => {
77
77
 
78
78
  if (!visible) return null;
79
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
+
80
88
  return (
81
89
  <Animated.View
82
90
  {...panResponder.panHandlers}
83
91
  style={[styles.container, animatedStyle, positionStyle, style]}
84
92
  >
85
- {children}
93
+ {renderContent()}
86
94
  </Animated.View>
87
95
  );
88
96
  };
@@ -5,9 +5,11 @@ import {
5
5
  widthPercentageToDP as wp,
6
6
  } from '../utils/Pixel/Index';
7
7
 
8
- const CustomToast = ({ content }) => {
8
+ const CustomToast = ({ content, theme = 'light' }) => {
9
+ const isDark = theme === 'dark';
10
+ const bg = isDark ? '#111827' : '#FFFFFF';
9
11
  return (
10
- <View style={styles.customToast}>
12
+ <View style={[styles.customToast, { backgroundColor: bg }]}>
11
13
  {content}
12
14
  </View>
13
15
  );
@@ -5,10 +5,14 @@ import {
5
5
  widthPercentageToDP as wp,
6
6
  } from '../utils/Pixel/Index';
7
7
 
8
- const EmojiToast = ({ message, emoji }) => {
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
+
9
13
  return (
10
- <View style={styles.emojiToast}>
11
- <Text style={styles.text}>{emoji} {message}</Text>
14
+ <View style={[styles.emojiToast, { backgroundColor: bg }]}>
15
+ <Text style={[styles.text, { color: textColor }]}>{emoji} {message}</Text>
12
16
  </View>
13
17
  );
14
18
  }
@@ -7,9 +7,13 @@ import {
7
7
  widthPercentageToDP as wp,
8
8
  } from '../utils/Pixel/Index';
9
9
 
10
- const ErrorToast = ({ message }) => {
10
+ const ErrorToast = ({ message, theme = 'light' }) => {
11
+ const isDark = theme === 'dark';
12
+ const containerBg = isDark ? '#111827' : '#F7F7FC';
13
+ const textColor = isDark ? '#FEE2E2' : '#991B1B';
14
+
11
15
  return (
12
- <View style={styles.container}>
16
+ <View style={[styles.container, { backgroundColor: containerBg }]}>
13
17
  <LottieView
14
18
  source={require('../../assets/animated_Icon/ErrorAnimation.json')} // Replace with your success Lottie animation path
15
19
  autoPlay
@@ -17,7 +21,7 @@ const ErrorToast = ({ message }) => {
17
21
  speed={1.5}
18
22
  style={styles.lottie}
19
23
  />
20
- <Text style={styles.text}>{message}</Text>
24
+ <Text style={[styles.text, { color: textColor }]}>{message}</Text>
21
25
  </View>
22
26
  );
23
27
  }
@@ -6,10 +6,14 @@ import {
6
6
  widthPercentageToDP as wp,
7
7
  } from '../utils/Pixel/Index';
8
8
 
9
- const LoadingToast = ({ message }) => {
9
+ const LoadingToast = ({ message, theme = 'light' }) => {
10
+ const isDark = theme === 'dark';
11
+ const bg = isDark ? '#111827' : '#FFFFFF';
12
+ const indicatorColor = isDark ? '#9CA3AF' : '#6B7280';
13
+
10
14
  return (
11
- <View style={styles.toast}>
12
- <ActivityIndicator size="large" color={'#a9a9a9'} />
15
+ <View style={[styles.toast, { backgroundColor: bg }]}>
16
+ <ActivityIndicator size="small" color={indicatorColor} />
13
17
  {/** <Text style={styles.text}>{message}</Text> */}
14
18
  </View>
15
19
  );
@@ -6,9 +6,13 @@ import {
6
6
  widthPercentageToDP as wp,
7
7
  } from '../utils/Pixel/Index';
8
8
 
9
- const SuccessToast = ({ message }) => {
9
+ const SuccessToast = ({ message, theme = 'light' }) => {
10
+ const isDark = theme === 'dark';
11
+ const containerBg = isDark ? '#111827' : '#F7F7FC';
12
+ const textColor = isDark ? '#F3F4F6' : '#064E3B';
13
+
10
14
  return (
11
- <View style={styles.container}>
15
+ <View style={[styles.container, { backgroundColor: containerBg }]}>
12
16
  <LottieView
13
17
  source={require('../../assets/animated_Icon/SuccessAnimation.json')} // Replace with your success Lottie animation path
14
18
  autoPlay
@@ -16,7 +20,7 @@ const SuccessToast = ({ message }) => {
16
20
  style={styles.lottie}
17
21
  speed={1.2}
18
22
  />
19
- <Text style={styles.text}>{message}</Text>
23
+ <Text style={[styles.text, { color: textColor }]}>{message}</Text>
20
24
  </View>
21
25
  );
22
26
  };
@@ -27,8 +31,8 @@ const styles = StyleSheet.create({
27
31
  height: hp(6.8),
28
32
  paddingHorizontal: wp(4),
29
33
  borderRadius: wp(4),
30
- // backgroundColor: '#d2f7d2',
31
- backgroundColor: '#F7F7FC',
34
+ // backgroundColor: '#d2f7d2',
35
+ backgroundColor: '#F7F7FC',
32
36
  alignItems: 'center',
33
37
  flexDirection: 'row',
34
38
  },
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useState } from 'react';
2
- import { View, StyleSheet } from 'react-native';
2
+ import { View, StyleSheet, Appearance, StatusBar, Platform, SafeAreaView } from 'react-native';
3
3
  import Toast from '../Toast';
4
4
  import toastManagerInstance from './ToastManager';
5
5
  import {
@@ -7,8 +7,9 @@ import {
7
7
  widthPercentageToDP as wp,
8
8
  } from '../utils/Pixel/Index';
9
9
 
10
- const ToastContainer = () => {
10
+ const ToastContainer = ({ theme: forcedTheme } = {}) => {
11
11
  const [toasts, setToasts] = useState([]);
12
+ const [theme, setTheme] = useState(forcedTheme ?? (Appearance.getColorScheme() || 'light'));
12
13
 
13
14
  useEffect(() => {
14
15
  const handleShow = (toast) => {
@@ -22,44 +23,62 @@ const ToastContainer = () => {
22
23
  toastManagerInstance.on('show', handleShow);
23
24
  toastManagerInstance.on('remove', handleRemove);
24
25
 
26
+ let appearanceSub;
27
+ if (!forcedTheme && Appearance && Appearance.addChangeListener) {
28
+ appearanceSub = Appearance.addChangeListener(({ colorScheme }) => {
29
+ setTheme(colorScheme ?? 'light');
30
+ });
31
+ }
32
+
25
33
  return () => {
26
34
  toastManagerInstance.off('show', handleShow);
27
35
  toastManagerInstance.off('remove', handleRemove);
36
+ if (appearanceSub && appearanceSub.remove) appearanceSub.remove();
28
37
  };
29
38
  }, []);
30
39
 
31
40
  // Separate toasts by position
32
- const topToasts = toasts.filter(toast => toast.options.position === 'top');
33
- const centerToasts = toasts.filter(toast => toast.options.position === 'center');
34
- const bottomToasts = toasts.filter(toast => toast.options.position === 'bottom');
41
+ const topToasts = toasts.filter(toast => toast?.options?.position === 'top');
42
+ const centerToasts = toasts.filter(toast => toast?.options?.position === 'center');
43
+ const bottomToasts = toasts.filter(toast => toast?.options?.position === 'bottom');
35
44
 
36
45
  return (
37
46
  <>
38
47
  {/* Top positioned toasts */}
39
- <View style={styles.topContainer}>
48
+ <SafeAreaView
49
+ style={[
50
+ styles.topContainer,
51
+ {
52
+ top: Platform.OS === 'android' ? StatusBar.currentHeight || 0 : 0,
53
+ },
54
+ ]}
55
+ pointerEvents="box-none"
56
+ >
40
57
  {topToasts.map((toast, index) => (
41
58
  <Toast
42
59
  key={toast.id}
43
60
  visible={true}
44
- duration={toast.options.duration}
61
+ duration={toast?.options?.duration}
45
62
  position="top"
46
- style={[toast.options.style, { top: hp(0.1) + index * 60 }]} // Adjust spacing between top toasts
63
+ theme={theme}
64
+ style={[toast?.options?.style || {}, { marginTop: index * 60 }]} // Adjust spacing between top toasts
47
65
  onHide={() => toastManagerInstance.remove(toast.id)}
48
66
  >
49
67
  {toast.content}
50
68
  </Toast>
51
69
  ))}
52
- </View>
70
+ </SafeAreaView>
53
71
 
54
72
  {/* Center positioned toasts */}
55
- <View style={styles.centerContainer}>
73
+ <View style={styles.centerContainer} pointerEvents="box-none">
56
74
  {centerToasts.map((toast, index) => (
57
75
  <Toast
58
76
  key={toast.id}
59
77
  visible={true}
60
- duration={toast.options.duration}
78
+ duration={toast?.options?.duration}
61
79
  position="center"
62
- style={[toast.options.style, { marginTop: index * 60 }]} // Adjust spacing between center toasts
80
+ theme={theme}
81
+ style={[toast?.options?.style || {}, { marginTop: index * 60 }]} // Adjust spacing between center toasts
63
82
  onHide={() => toastManagerInstance.remove(toast.id)}
64
83
  >
65
84
  {toast.content}
@@ -68,14 +87,15 @@ const ToastContainer = () => {
68
87
  </View>
69
88
 
70
89
  {/* Bottom positioned toasts */}
71
- <View style={styles.bottomContainer}>
90
+ <View style={styles.bottomContainer} pointerEvents="box-none">
72
91
  {bottomToasts.map((toast, index) => (
73
92
  <Toast
74
93
  key={toast.id}
75
94
  visible={true}
76
- duration={toast.options.duration}
95
+ duration={toast?.options?.duration}
77
96
  position="bottom"
78
- style={[toast.options.style, { bottom: hp(2) + index * 60 }]} // Adjust spacing between bottom toasts
97
+ theme={theme}
98
+ style={[toast?.options?.style || {}, { bottom: hp(2) + index * 60 }]} // Adjust spacing between bottom toasts
79
99
  onHide={() => toastManagerInstance.remove(toast.id)}
80
100
  >
81
101
  {toast.content}
@@ -1,14 +1,16 @@
1
1
  import { EventEmitter } from 'events';
2
2
 
3
3
  class ToastManager extends EventEmitter {
4
- show(content, options = {}) {
5
- const id = Date.now().toString();
4
+ // show accepts an optional id so callers (like promise) can control the id lifecycle
5
+ show(content, options = {}, id = null) {
6
+ const _id = id ?? Date.now().toString();
6
7
  const defaultOptions = {
7
8
  duration: 1000,
8
9
  position: 'bottom',
9
10
  style: {},
10
11
  };
11
- this.emit('show', { id, content, options: { ...defaultOptions, ...options } });
12
+ this.emit('show', { id: _id, content, options: { ...defaultOptions, ...options } });
13
+ return _id;
12
14
  }
13
15
 
14
16
  remove(id) {
@@ -17,7 +19,8 @@ class ToastManager extends EventEmitter {
17
19
 
18
20
  async promise(promise, { loading, success, error }) {
19
21
  const id = Date.now().toString();
20
- this.show(loading, { duration: Infinity, position: 'top' });
22
+ // show the loading toast using the same id so we can remove it later
23
+ this.show(loading, { duration: Infinity, position: 'top' }, id);
21
24
  try {
22
25
  await promise;
23
26
  this.remove(id);