react-native-bread 0.5.2 → 0.6.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/README.md +27 -11
- package/lib/commonjs/constants.js +25 -1
- package/lib/commonjs/icons/CloseIcon.js +22 -1
- package/lib/commonjs/icons/GreenCheck.js +27 -1
- package/lib/commonjs/icons/InfoIcon.js +24 -1
- package/lib/commonjs/icons/RedX.js +27 -1
- package/lib/commonjs/icons/index.js +34 -1
- package/lib/commonjs/index.js +65 -1
- package/lib/commonjs/pool.js +53 -1
- package/lib/commonjs/toast-api.js +127 -1
- package/lib/commonjs/toast-icons.js +80 -1
- package/lib/commonjs/toast-provider.js +109 -1
- package/lib/commonjs/toast-store.js +252 -1
- package/lib/commonjs/toast.js +351 -1
- package/lib/commonjs/types.js +6 -1
- package/lib/commonjs/use-toast-state.js +72 -1
- package/lib/module/constants.js +21 -1
- package/lib/module/icons/CloseIcon.js +16 -1
- package/lib/module/icons/GreenCheck.js +21 -1
- package/lib/module/icons/InfoIcon.js +18 -1
- package/lib/module/icons/RedX.js +21 -1
- package/lib/module/icons/index.js +7 -1
- package/lib/module/index.js +14 -1
- package/lib/module/pool.js +47 -1
- package/lib/module/toast-api.js +123 -1
- package/lib/module/toast-icons.js +74 -1
- package/lib/module/toast-provider.js +104 -1
- package/lib/module/toast-store.js +248 -1
- package/lib/module/toast.js +345 -1
- package/lib/module/types.js +4 -1
- package/lib/module/use-toast-state.js +67 -1
- package/lib/typescript/index.d.ts +1 -1
- package/lib/typescript/toast-provider.d.ts +28 -0
- package/package.json +7 -3
package/lib/module/toast-api.js
CHANGED
|
@@ -1 +1,123 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { toastStore } from "./toast-store.js";
|
|
4
|
+
const _toast = (title, description, type, duration) => {
|
|
5
|
+
toastStore.show(title, description, type, duration);
|
|
6
|
+
};
|
|
7
|
+
const parseDescriptionOrOptions = arg => {
|
|
8
|
+
if (!arg) return {};
|
|
9
|
+
if (typeof arg === "string") return {
|
|
10
|
+
description: arg
|
|
11
|
+
};
|
|
12
|
+
return {
|
|
13
|
+
description: arg.description,
|
|
14
|
+
duration: arg.duration,
|
|
15
|
+
options: arg
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
const parseMessage = input => typeof input === "string" ? {
|
|
19
|
+
title: input
|
|
20
|
+
} : input;
|
|
21
|
+
const parseErrorMessage = (input, error) => {
|
|
22
|
+
if (typeof input === "function") {
|
|
23
|
+
return parseMessage(input(error));
|
|
24
|
+
}
|
|
25
|
+
return parseMessage(input);
|
|
26
|
+
};
|
|
27
|
+
const promiseToast = async (promise, messages) => {
|
|
28
|
+
const loadingCfg = parseMessage(messages.loading);
|
|
29
|
+
const toastId = toastStore.show(loadingCfg.title, loadingCfg.description, "loading", loadingCfg.duration ?? 60 * 60 * 1000);
|
|
30
|
+
try {
|
|
31
|
+
const result = await promise;
|
|
32
|
+
const successCfg = parseMessage(messages.success);
|
|
33
|
+
toastStore.updateToast(toastId, {
|
|
34
|
+
title: successCfg.title,
|
|
35
|
+
description: successCfg.description,
|
|
36
|
+
type: "success",
|
|
37
|
+
duration: successCfg.duration ?? 4000
|
|
38
|
+
});
|
|
39
|
+
return {
|
|
40
|
+
data: result,
|
|
41
|
+
success: true
|
|
42
|
+
};
|
|
43
|
+
} catch (err) {
|
|
44
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
45
|
+
const errorCfg = parseErrorMessage(messages.error, error);
|
|
46
|
+
toastStore.updateToast(toastId, {
|
|
47
|
+
title: errorCfg.title,
|
|
48
|
+
description: errorCfg.description,
|
|
49
|
+
type: "error",
|
|
50
|
+
duration: errorCfg.duration ?? 4000
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
error,
|
|
54
|
+
success: false
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const toastFn = _toast;
|
|
59
|
+
toastFn.custom = (content, options) => {
|
|
60
|
+
const type = options?.type ?? "info";
|
|
61
|
+
return toastStore.show("", undefined, type, options?.duration, {
|
|
62
|
+
...options,
|
|
63
|
+
customContent: content
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
toastFn.success = (title, descriptionOrOptions, duration) => {
|
|
67
|
+
const {
|
|
68
|
+
description,
|
|
69
|
+
duration: optDuration,
|
|
70
|
+
options
|
|
71
|
+
} = parseDescriptionOrOptions(descriptionOrOptions);
|
|
72
|
+
toastStore.show(title, description, "success", duration ?? optDuration, options);
|
|
73
|
+
};
|
|
74
|
+
toastFn.error = (title, descriptionOrOptions, duration) => {
|
|
75
|
+
const {
|
|
76
|
+
description,
|
|
77
|
+
duration: optDuration,
|
|
78
|
+
options
|
|
79
|
+
} = parseDescriptionOrOptions(descriptionOrOptions);
|
|
80
|
+
toastStore.show(title, description, "error", duration ?? optDuration, options);
|
|
81
|
+
};
|
|
82
|
+
toastFn.info = (title, descriptionOrOptions, duration) => {
|
|
83
|
+
const {
|
|
84
|
+
description,
|
|
85
|
+
duration: optDuration,
|
|
86
|
+
options
|
|
87
|
+
} = parseDescriptionOrOptions(descriptionOrOptions);
|
|
88
|
+
toastStore.show(title, description, "info", duration ?? optDuration, options);
|
|
89
|
+
};
|
|
90
|
+
toastFn.promise = promiseToast;
|
|
91
|
+
toastFn.dismiss = id => {
|
|
92
|
+
toastStore.hide(id);
|
|
93
|
+
};
|
|
94
|
+
toastFn.dismissAll = () => {
|
|
95
|
+
toastStore.hideAll();
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Toast API for showing notifications.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* import { toast } from 'react-native-bread';
|
|
104
|
+
*
|
|
105
|
+
* // Basic toasts
|
|
106
|
+
* toast.success("Saved!", "Your changes have been saved");
|
|
107
|
+
* toast.error("Error", "Something went wrong");
|
|
108
|
+
* toast.info("Tip", "Swipe up to dismiss");
|
|
109
|
+
*
|
|
110
|
+
* // Promise toast (loading → success/error)
|
|
111
|
+
* toast.promise(apiCall(), {
|
|
112
|
+
* loading: { title: "Loading..." },
|
|
113
|
+
* success: { title: "Done!" },
|
|
114
|
+
* error: (err) => ({ title: "Failed", description: err.message }),
|
|
115
|
+
* });
|
|
116
|
+
*
|
|
117
|
+
* // Dismiss toasts
|
|
118
|
+
* toast.dismiss(id);
|
|
119
|
+
* toast.dismissAll();
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export const toast = toastFn;
|
|
123
|
+
//# sourceMappingURL=toast-api.js.map
|
|
@@ -1 +1,74 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { memo, useEffect } from "react";
|
|
4
|
+
import { ActivityIndicator } from "react-native";
|
|
5
|
+
import Animated, { Easing, useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
|
|
6
|
+
import { ICON_ANIMATION_DURATION, ICON_SIZE } from "./constants.js";
|
|
7
|
+
import { GreenCheck, InfoIcon, RedX } from "./icons/index.js";
|
|
8
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
9
|
+
export const resolveIcon = (type, color, custom, config) => {
|
|
10
|
+
if (custom) return typeof custom === "function" ? custom({
|
|
11
|
+
color,
|
|
12
|
+
size: ICON_SIZE
|
|
13
|
+
}) : custom;
|
|
14
|
+
if (config) return config({
|
|
15
|
+
color,
|
|
16
|
+
size: ICON_SIZE
|
|
17
|
+
});
|
|
18
|
+
switch (type) {
|
|
19
|
+
case "success":
|
|
20
|
+
return /*#__PURE__*/_jsx(GreenCheck, {
|
|
21
|
+
width: 36,
|
|
22
|
+
height: 36,
|
|
23
|
+
fill: color
|
|
24
|
+
});
|
|
25
|
+
case "error":
|
|
26
|
+
return /*#__PURE__*/_jsx(RedX, {
|
|
27
|
+
width: ICON_SIZE,
|
|
28
|
+
height: ICON_SIZE,
|
|
29
|
+
fill: color
|
|
30
|
+
});
|
|
31
|
+
case "loading":
|
|
32
|
+
return /*#__PURE__*/_jsx(ActivityIndicator, {
|
|
33
|
+
size: ICON_SIZE,
|
|
34
|
+
color: color
|
|
35
|
+
});
|
|
36
|
+
case "info":
|
|
37
|
+
return /*#__PURE__*/_jsx(InfoIcon, {
|
|
38
|
+
width: ICON_SIZE,
|
|
39
|
+
height: ICON_SIZE,
|
|
40
|
+
fill: color
|
|
41
|
+
});
|
|
42
|
+
default:
|
|
43
|
+
return /*#__PURE__*/_jsx(GreenCheck, {
|
|
44
|
+
width: 36,
|
|
45
|
+
height: 36,
|
|
46
|
+
fill: color
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
export const AnimatedIcon = /*#__PURE__*/memo(({
|
|
51
|
+
type,
|
|
52
|
+
color,
|
|
53
|
+
custom,
|
|
54
|
+
config
|
|
55
|
+
}) => {
|
|
56
|
+
const progress = useSharedValue(0);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
progress.value = withTiming(1, {
|
|
59
|
+
duration: ICON_ANIMATION_DURATION,
|
|
60
|
+
easing: Easing.out(Easing.back(1.5))
|
|
61
|
+
});
|
|
62
|
+
}, [progress]);
|
|
63
|
+
const style = useAnimatedStyle(() => ({
|
|
64
|
+
opacity: progress.value,
|
|
65
|
+
transform: [{
|
|
66
|
+
scale: 0.7 + progress.value * 0.3
|
|
67
|
+
}]
|
|
68
|
+
}));
|
|
69
|
+
return /*#__PURE__*/_jsx(Animated.View, {
|
|
70
|
+
style: style,
|
|
71
|
+
children: resolveIcon(type, color, custom, config)
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=toast-icons.js.map
|
|
@@ -1 +1,104 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import { Platform, StyleSheet, View } from "react-native";
|
|
5
|
+
import { FullWindowOverlay } from "react-native-screens";
|
|
6
|
+
import { ToastContainer } from "./toast.js";
|
|
7
|
+
import { toastStore } from "./toast-store.js";
|
|
8
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
9
|
+
function ToastContent() {
|
|
10
|
+
return /*#__PURE__*/_jsx(View, {
|
|
11
|
+
style: styles.container,
|
|
12
|
+
pointerEvents: "box-none",
|
|
13
|
+
children: /*#__PURE__*/_jsx(ToastContainer, {})
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Toast component that enables toast notifications in your app.
|
|
18
|
+
* Add `<BreadLoaf />` to your root layout to start showing toasts.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```tsx
|
|
22
|
+
* import { BreadLoaf } from 'react-native-bread';
|
|
23
|
+
*
|
|
24
|
+
* // Basic usage - add to your root layout
|
|
25
|
+
* export default function RootLayout() {
|
|
26
|
+
* return (
|
|
27
|
+
* <>
|
|
28
|
+
* <Stack />
|
|
29
|
+
* <BreadLoaf />
|
|
30
|
+
* </>
|
|
31
|
+
* );
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* // With configuration
|
|
35
|
+
* <BreadLoaf
|
|
36
|
+
* config={{
|
|
37
|
+
* position: 'bottom',
|
|
38
|
+
* stacking: false,
|
|
39
|
+
* defaultDuration: 5000,
|
|
40
|
+
* colors: {
|
|
41
|
+
* success: { accent: '#22c55e', background: '#f0fdf4' },
|
|
42
|
+
* error: { accent: '#ef4444', background: '#fef2f2' },
|
|
43
|
+
* },
|
|
44
|
+
* toastStyle: { borderRadius: 12 },
|
|
45
|
+
* }}
|
|
46
|
+
* />
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export function BreadLoaf({
|
|
50
|
+
config
|
|
51
|
+
}) {
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
toastStore.setConfig(config);
|
|
54
|
+
return () => {
|
|
55
|
+
toastStore.setConfig(undefined);
|
|
56
|
+
};
|
|
57
|
+
}, [config]);
|
|
58
|
+
|
|
59
|
+
// iOS: use FullWindowOverlay to render above native modals
|
|
60
|
+
if (Platform.OS === "ios") {
|
|
61
|
+
return /*#__PURE__*/_jsx(FullWindowOverlay, {
|
|
62
|
+
children: /*#__PURE__*/_jsx(ToastContent, {})
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return /*#__PURE__*/_jsx(ToastContent, {});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Lightweight toast renderer for use inside modal screens.
|
|
70
|
+
*
|
|
71
|
+
* On Android, native modals render above the root React view, so toasts from
|
|
72
|
+
* the main `<BreadLoaf />` won't be visible. Add `<ToastPortal />` inside your
|
|
73
|
+
* modal layouts to show toasts above modal content.
|
|
74
|
+
*
|
|
75
|
+
* This component only renders toasts - it does not accept configuration.
|
|
76
|
+
* All styling/behavior is inherited from your root `<BreadLoaf />` config.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```tsx
|
|
80
|
+
* // app/(modal)/_layout.tsx
|
|
81
|
+
* import { Stack } from 'expo-router';
|
|
82
|
+
* import { ToastPortal } from 'react-native-bread';
|
|
83
|
+
* import { Platform } from 'react-native';
|
|
84
|
+
*
|
|
85
|
+
* export default function ModalLayout() {
|
|
86
|
+
* return (
|
|
87
|
+
* <>
|
|
88
|
+
* <Stack screenOptions={{ headerShown: false }} />
|
|
89
|
+
* {Platform.OS === 'android' && <ToastPortal />}
|
|
90
|
+
* </>
|
|
91
|
+
* );
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export function ToastPortal() {
|
|
96
|
+
return /*#__PURE__*/_jsx(ToastContent, {});
|
|
97
|
+
}
|
|
98
|
+
const styles = StyleSheet.create({
|
|
99
|
+
container: {
|
|
100
|
+
...StyleSheet.absoluteFillObject,
|
|
101
|
+
zIndex: 9999
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
//# sourceMappingURL=toast-provider.js.map
|
|
@@ -1 +1,248 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const EXIT_DURATION = 350;
|
|
4
|
+
const DEFAULT_THEME = {
|
|
5
|
+
position: "top",
|
|
6
|
+
offset: 0,
|
|
7
|
+
rtl: false,
|
|
8
|
+
stacking: true,
|
|
9
|
+
maxStack: 3,
|
|
10
|
+
dismissible: true,
|
|
11
|
+
showCloseButton: true,
|
|
12
|
+
colors: {
|
|
13
|
+
success: {
|
|
14
|
+
accent: "#28B770",
|
|
15
|
+
background: "#FFFFFF"
|
|
16
|
+
},
|
|
17
|
+
error: {
|
|
18
|
+
accent: "#F05964",
|
|
19
|
+
background: "#FFFFFF"
|
|
20
|
+
},
|
|
21
|
+
info: {
|
|
22
|
+
accent: "#EDBE43",
|
|
23
|
+
background: "#FFFFFF"
|
|
24
|
+
},
|
|
25
|
+
loading: {
|
|
26
|
+
accent: "#232323",
|
|
27
|
+
background: "#FFFFFF"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
icons: {},
|
|
31
|
+
toastStyle: {},
|
|
32
|
+
titleStyle: {},
|
|
33
|
+
descriptionStyle: {},
|
|
34
|
+
defaultDuration: 4000
|
|
35
|
+
};
|
|
36
|
+
function mergeConfig(config) {
|
|
37
|
+
if (!config) return DEFAULT_THEME;
|
|
38
|
+
const mergedColors = {
|
|
39
|
+
...DEFAULT_THEME.colors
|
|
40
|
+
};
|
|
41
|
+
if (config.colors) {
|
|
42
|
+
for (const type of Object.keys(config.colors)) {
|
|
43
|
+
const userColors = config.colors[type];
|
|
44
|
+
if (userColors) {
|
|
45
|
+
mergedColors[type] = {
|
|
46
|
+
...DEFAULT_THEME.colors[type],
|
|
47
|
+
...userColors
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
position: config.position ?? DEFAULT_THEME.position,
|
|
54
|
+
offset: config.offset ?? DEFAULT_THEME.offset,
|
|
55
|
+
rtl: config.rtl ?? DEFAULT_THEME.rtl,
|
|
56
|
+
stacking: config.stacking ?? DEFAULT_THEME.stacking,
|
|
57
|
+
maxStack: config.maxStack ?? DEFAULT_THEME.maxStack,
|
|
58
|
+
dismissible: config.dismissible ?? DEFAULT_THEME.dismissible,
|
|
59
|
+
showCloseButton: config.showCloseButton ?? DEFAULT_THEME.showCloseButton,
|
|
60
|
+
colors: mergedColors,
|
|
61
|
+
icons: {
|
|
62
|
+
...DEFAULT_THEME.icons,
|
|
63
|
+
...config.icons
|
|
64
|
+
},
|
|
65
|
+
toastStyle: {
|
|
66
|
+
...DEFAULT_THEME.toastStyle,
|
|
67
|
+
...config.toastStyle
|
|
68
|
+
},
|
|
69
|
+
titleStyle: {
|
|
70
|
+
...DEFAULT_THEME.titleStyle,
|
|
71
|
+
...config.titleStyle
|
|
72
|
+
},
|
|
73
|
+
descriptionStyle: {
|
|
74
|
+
...DEFAULT_THEME.descriptionStyle,
|
|
75
|
+
...config.descriptionStyle
|
|
76
|
+
},
|
|
77
|
+
defaultDuration: config.defaultDuration ?? DEFAULT_THEME.defaultDuration
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
class ToastStore {
|
|
81
|
+
state = {
|
|
82
|
+
visibleToasts: []
|
|
83
|
+
};
|
|
84
|
+
theme = DEFAULT_THEME;
|
|
85
|
+
listeners = new Set();
|
|
86
|
+
toastIdCounter = 0;
|
|
87
|
+
timeouts = new Map();
|
|
88
|
+
subscribe = listener => {
|
|
89
|
+
this.listeners.add(listener);
|
|
90
|
+
return () => {
|
|
91
|
+
this.listeners.delete(listener);
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
emit() {
|
|
95
|
+
for (const listener of this.listeners) {
|
|
96
|
+
listener(this.state);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
setState(partial) {
|
|
100
|
+
this.state = {
|
|
101
|
+
...this.state,
|
|
102
|
+
...partial
|
|
103
|
+
};
|
|
104
|
+
this.emit();
|
|
105
|
+
}
|
|
106
|
+
getState = () => this.state;
|
|
107
|
+
getTheme = () => this.theme;
|
|
108
|
+
setConfig = config => {
|
|
109
|
+
this.theme = mergeConfig(config);
|
|
110
|
+
};
|
|
111
|
+
show = (title, description, type = "success", duration, options) => {
|
|
112
|
+
const actualDuration = duration ?? options?.duration ?? this.theme.defaultDuration;
|
|
113
|
+
const maxToasts = this.theme.stacking ? this.theme.maxStack : 1;
|
|
114
|
+
const id = `toast-${++this.toastIdCounter}`;
|
|
115
|
+
const newToast = {
|
|
116
|
+
id,
|
|
117
|
+
title,
|
|
118
|
+
description: description ?? options?.description,
|
|
119
|
+
type,
|
|
120
|
+
duration: actualDuration,
|
|
121
|
+
createdAt: Date.now(),
|
|
122
|
+
isExiting: false,
|
|
123
|
+
options
|
|
124
|
+
};
|
|
125
|
+
const {
|
|
126
|
+
visibleToasts
|
|
127
|
+
} = this.state;
|
|
128
|
+
const activeToasts = visibleToasts.filter(t => !t.isExiting);
|
|
129
|
+
if (activeToasts.length >= maxToasts) {
|
|
130
|
+
const toastsToRemove = activeToasts.slice(maxToasts - 1);
|
|
131
|
+
for (const toast of toastsToRemove) {
|
|
132
|
+
const timeout = this.timeouts.get(toast.id);
|
|
133
|
+
if (timeout) {
|
|
134
|
+
clearTimeout(timeout);
|
|
135
|
+
this.timeouts.delete(toast.id);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const removeIds = new Set(toastsToRemove.map(t => t.id));
|
|
139
|
+
if (this.theme.stacking) {
|
|
140
|
+
this.setState({
|
|
141
|
+
visibleToasts: visibleToasts.filter(t => !removeIds.has(t.id))
|
|
142
|
+
});
|
|
143
|
+
} else {
|
|
144
|
+
this.setState({
|
|
145
|
+
visibleToasts: visibleToasts.map(t => removeIds.has(t.id) ? {
|
|
146
|
+
...t,
|
|
147
|
+
isExiting: true
|
|
148
|
+
} : t)
|
|
149
|
+
});
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
for (const toast of toastsToRemove) {
|
|
152
|
+
this.removeToast(toast.id);
|
|
153
|
+
}
|
|
154
|
+
this.addToast(newToast, actualDuration);
|
|
155
|
+
}, EXIT_DURATION - 220);
|
|
156
|
+
return id;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
this.addToast(newToast, actualDuration);
|
|
160
|
+
return id;
|
|
161
|
+
};
|
|
162
|
+
addToast(toast, duration) {
|
|
163
|
+
this.setState({
|
|
164
|
+
visibleToasts: [toast, ...this.state.visibleToasts.filter(t => !t.isExiting)]
|
|
165
|
+
});
|
|
166
|
+
this.scheduleTimeout(toast.id, duration, 0);
|
|
167
|
+
this.rescheduleAllTimeouts();
|
|
168
|
+
}
|
|
169
|
+
scheduleTimeout(id, baseDuration, index) {
|
|
170
|
+
const existingTimeout = this.timeouts.get(id);
|
|
171
|
+
if (existingTimeout) {
|
|
172
|
+
clearTimeout(existingTimeout);
|
|
173
|
+
}
|
|
174
|
+
const duration = baseDuration * (index + 1);
|
|
175
|
+
const timeout = setTimeout(() => {
|
|
176
|
+
this.hide(id);
|
|
177
|
+
}, duration);
|
|
178
|
+
this.timeouts.set(id, timeout);
|
|
179
|
+
}
|
|
180
|
+
rescheduleAllTimeouts() {
|
|
181
|
+
const {
|
|
182
|
+
visibleToasts
|
|
183
|
+
} = this.state;
|
|
184
|
+
visibleToasts.forEach((toast, index) => {
|
|
185
|
+
if (toast.isExiting || index === 0) return;
|
|
186
|
+
this.scheduleTimeout(toast.id, toast.duration, index);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
hide = id => {
|
|
190
|
+
const {
|
|
191
|
+
visibleToasts
|
|
192
|
+
} = this.state;
|
|
193
|
+
const toast = visibleToasts.find(t => t.id === id);
|
|
194
|
+
if (!toast || toast.isExiting) return;
|
|
195
|
+
const timeout = this.timeouts.get(id);
|
|
196
|
+
if (timeout) {
|
|
197
|
+
clearTimeout(timeout);
|
|
198
|
+
this.timeouts.delete(id);
|
|
199
|
+
}
|
|
200
|
+
this.setState({
|
|
201
|
+
visibleToasts: visibleToasts.map(t => t.id === id ? {
|
|
202
|
+
...t,
|
|
203
|
+
isExiting: true
|
|
204
|
+
} : t)
|
|
205
|
+
});
|
|
206
|
+
setTimeout(() => {
|
|
207
|
+
this.removeToast(id);
|
|
208
|
+
}, EXIT_DURATION);
|
|
209
|
+
};
|
|
210
|
+
removeToast(id) {
|
|
211
|
+
const timeout = this.timeouts.get(id);
|
|
212
|
+
if (timeout) {
|
|
213
|
+
clearTimeout(timeout);
|
|
214
|
+
this.timeouts.delete(id);
|
|
215
|
+
}
|
|
216
|
+
this.setState({
|
|
217
|
+
visibleToasts: this.state.visibleToasts.filter(t => t.id !== id)
|
|
218
|
+
});
|
|
219
|
+
this.rescheduleAllTimeouts();
|
|
220
|
+
}
|
|
221
|
+
updateToast = (id, data) => {
|
|
222
|
+
const {
|
|
223
|
+
visibleToasts
|
|
224
|
+
} = this.state;
|
|
225
|
+
const index = visibleToasts.findIndex(t => t.id === id);
|
|
226
|
+
if (index === -1) return;
|
|
227
|
+
this.setState({
|
|
228
|
+
visibleToasts: visibleToasts.map(t => t.id === id ? {
|
|
229
|
+
...t,
|
|
230
|
+
...data
|
|
231
|
+
} : t)
|
|
232
|
+
});
|
|
233
|
+
if (data.duration !== undefined) {
|
|
234
|
+
this.scheduleTimeout(id, data.duration, index);
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
hideAll = () => {
|
|
238
|
+
for (const timeout of this.timeouts.values()) {
|
|
239
|
+
clearTimeout(timeout);
|
|
240
|
+
}
|
|
241
|
+
this.timeouts.clear();
|
|
242
|
+
this.setState({
|
|
243
|
+
visibleToasts: []
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
export const toastStore = new ToastStore();
|
|
248
|
+
//# sourceMappingURL=toast-store.js.map
|