@ilokesto/toast 1.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/README.ko.md +209 -0
- package/README.md +209 -0
- package/dist/components/ToastBar.d.ts +12 -0
- package/dist/components/ToastBar.js +39 -0
- package/dist/components/ToastProvider.d.ts +3 -0
- package/dist/components/ToastProvider.js +16 -0
- package/dist/components/Toaster.d.ts +2 -0
- package/dist/components/Toaster.js +175 -0
- package/dist/components/icons.d.ts +14 -0
- package/dist/components/icons.js +83 -0
- package/dist/core/createToastRuntime.d.ts +2 -0
- package/dist/core/createToastRuntime.js +247 -0
- package/dist/core/createToastStore.d.ts +2 -0
- package/dist/core/createToastStore.js +126 -0
- package/dist/core/registry.d.ts +5 -0
- package/dist/core/registry.js +18 -0
- package/dist/core/toast.d.ts +2 -0
- package/dist/core/toast.js +41 -0
- package/dist/core/utils.d.ts +11 -0
- package/dist/core/utils.js +33 -0
- package/dist/hooks/useToastItems.d.ts +2 -0
- package/dist/hooks/useToastItems.js +4 -0
- package/dist/hooks/useToaster.d.ts +2 -0
- package/dist/hooks/useToaster.js +31 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +7 -0
- package/dist/types/toast.d.ts +137 -0
- package/dist/types/toast.js +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
export const DefaultSpinner = () => {
|
|
4
|
+
const style = useMemo(() => ({
|
|
5
|
+
width: 20,
|
|
6
|
+
height: 20,
|
|
7
|
+
boxSizing: "border-box",
|
|
8
|
+
border: "2px solid",
|
|
9
|
+
borderRadius: "100%",
|
|
10
|
+
borderColor: "#e0e0e0",
|
|
11
|
+
borderRightColor: "#616161",
|
|
12
|
+
animation: "toast-spin 1s linear infinite",
|
|
13
|
+
}), []);
|
|
14
|
+
return _jsx("div", { style: style, className: "toast-motion-spin" });
|
|
15
|
+
};
|
|
16
|
+
export const DefaultSuccess = ({ theme }) => {
|
|
17
|
+
const primary = theme?.primary || "#61d345";
|
|
18
|
+
const secondary = theme?.secondary || "#fff";
|
|
19
|
+
return (_jsx("div", { className: "toast-motion-scale", style: {
|
|
20
|
+
width: 20,
|
|
21
|
+
height: 20,
|
|
22
|
+
background: primary,
|
|
23
|
+
borderRadius: "100%",
|
|
24
|
+
position: "relative",
|
|
25
|
+
animation: "toast-scale 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards",
|
|
26
|
+
}, children: _jsx("div", { style: {
|
|
27
|
+
boxSizing: "border-box",
|
|
28
|
+
position: "absolute",
|
|
29
|
+
top: "45%",
|
|
30
|
+
left: "50%",
|
|
31
|
+
width: 6,
|
|
32
|
+
height: 10,
|
|
33
|
+
border: `2px solid ${secondary}`,
|
|
34
|
+
borderTop: 0,
|
|
35
|
+
borderLeft: 0,
|
|
36
|
+
transform: "translate(-50%, -50%) rotate(45deg)",
|
|
37
|
+
transformOrigin: "center",
|
|
38
|
+
} }) }));
|
|
39
|
+
};
|
|
40
|
+
export const DefaultError = ({ theme }) => {
|
|
41
|
+
const primary = theme?.primary || "#ff4b4b";
|
|
42
|
+
const secondary = theme?.secondary || "#fff";
|
|
43
|
+
return (_jsxs("div", { className: "toast-motion-scale", style: {
|
|
44
|
+
width: 20,
|
|
45
|
+
height: 20,
|
|
46
|
+
background: primary,
|
|
47
|
+
borderRadius: "100%",
|
|
48
|
+
position: "relative",
|
|
49
|
+
animation: "toast-scale 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards",
|
|
50
|
+
}, children: [_jsx("div", { style: {
|
|
51
|
+
position: "absolute",
|
|
52
|
+
top: "50%",
|
|
53
|
+
left: "50%",
|
|
54
|
+
width: 10,
|
|
55
|
+
height: 2,
|
|
56
|
+
background: secondary,
|
|
57
|
+
transform: "translate(-50%, -50%) rotate(45deg)",
|
|
58
|
+
} }), _jsx("div", { style: {
|
|
59
|
+
position: "absolute",
|
|
60
|
+
top: "50%",
|
|
61
|
+
left: "50%",
|
|
62
|
+
width: 10,
|
|
63
|
+
height: 2,
|
|
64
|
+
background: secondary,
|
|
65
|
+
transform: "translate(-50%, -50%) rotate(-45deg)",
|
|
66
|
+
} })] }));
|
|
67
|
+
};
|
|
68
|
+
export const ToastIcon = ({ type, icon, iconTheme, }) => {
|
|
69
|
+
if (icon !== undefined) {
|
|
70
|
+
return _jsx(_Fragment, { children: icon });
|
|
71
|
+
}
|
|
72
|
+
switch (type) {
|
|
73
|
+
case "blank":
|
|
74
|
+
case "custom":
|
|
75
|
+
return null;
|
|
76
|
+
case "loading":
|
|
77
|
+
return _jsx(DefaultSpinner, {});
|
|
78
|
+
case "success":
|
|
79
|
+
return _jsx(DefaultSuccess, { theme: iconTheme });
|
|
80
|
+
case "error":
|
|
81
|
+
return _jsx(DefaultError, { theme: iconTheme });
|
|
82
|
+
}
|
|
83
|
+
};
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { createOverlayStore } from "@ilokesto/overlay";
|
|
2
|
+
import { createToastStore } from "./createToastStore";
|
|
3
|
+
import { DEFAULT_ARIA_PROPS, DEFAULT_DURATION, DEFAULT_ICON_THEME, DEFAULT_POSITION, DEFAULT_REMOVE_DELAY, generateToastId, resolveValue, } from "./utils";
|
|
4
|
+
export function createToastRuntime(toasterId) {
|
|
5
|
+
const store = createToastStore();
|
|
6
|
+
const overlayStore = createOverlayStore();
|
|
7
|
+
const dismissTimers = new Map();
|
|
8
|
+
const removeTimers = new Map();
|
|
9
|
+
const listeners = new Set();
|
|
10
|
+
const view = {
|
|
11
|
+
limit: Number.POSITIVE_INFINITY,
|
|
12
|
+
position: DEFAULT_POSITION,
|
|
13
|
+
};
|
|
14
|
+
store.subscribe(() => {
|
|
15
|
+
for (const listener of listeners) {
|
|
16
|
+
listener();
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
function clearTimer(timerMap, id) {
|
|
20
|
+
const timer = timerMap.get(id);
|
|
21
|
+
if (timer === undefined) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
clearTimeout(timer);
|
|
25
|
+
timerMap.delete(id);
|
|
26
|
+
}
|
|
27
|
+
function clearAllTimers() {
|
|
28
|
+
for (const timer of dismissTimers.values()) {
|
|
29
|
+
clearTimeout(timer);
|
|
30
|
+
}
|
|
31
|
+
for (const timer of removeTimers.values()) {
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
}
|
|
34
|
+
dismissTimers.clear();
|
|
35
|
+
removeTimers.clear();
|
|
36
|
+
}
|
|
37
|
+
function notify() {
|
|
38
|
+
for (const listener of listeners) {
|
|
39
|
+
listener();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function getVisibleItems(items) {
|
|
43
|
+
return items
|
|
44
|
+
.filter((item) => item.position === view.position)
|
|
45
|
+
.slice(0, view.limit);
|
|
46
|
+
}
|
|
47
|
+
function getItem(id) {
|
|
48
|
+
return store.getSnapshot().find((item) => item.id === id);
|
|
49
|
+
}
|
|
50
|
+
function scheduleDismiss(item) {
|
|
51
|
+
clearTimer(dismissTimers, item.id);
|
|
52
|
+
if (!Number.isFinite(item.duration)) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const remaining = item.duration - item.pauseDuration;
|
|
56
|
+
if (remaining <= 0) {
|
|
57
|
+
dismiss(item.id);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const timer = setTimeout(() => {
|
|
61
|
+
dismissTimers.delete(item.id);
|
|
62
|
+
dismiss(item.id);
|
|
63
|
+
}, remaining);
|
|
64
|
+
dismissTimers.set(item.id, timer);
|
|
65
|
+
}
|
|
66
|
+
function scheduleRemove(item) {
|
|
67
|
+
clearTimer(removeTimers, item.id);
|
|
68
|
+
const timer = setTimeout(() => {
|
|
69
|
+
removeTimers.delete(item.id);
|
|
70
|
+
remove(item.id);
|
|
71
|
+
}, item.removeDelay ?? DEFAULT_REMOVE_DELAY);
|
|
72
|
+
removeTimers.set(item.id, timer);
|
|
73
|
+
}
|
|
74
|
+
function ensurePresence(id) {
|
|
75
|
+
const presence = overlayStore.getSnapshot().find((item) => item.id === id);
|
|
76
|
+
if (presence !== undefined) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
overlayStore.open({
|
|
80
|
+
id,
|
|
81
|
+
type: "toast",
|
|
82
|
+
props: {},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function addToast(type, message, options) {
|
|
86
|
+
const id = options?.id ?? generateToastId();
|
|
87
|
+
const current = getItem(id);
|
|
88
|
+
const defaultOptions = view.toastOptions;
|
|
89
|
+
const defaultTypeOptions = defaultOptions?.[type];
|
|
90
|
+
const mergedOptions = {
|
|
91
|
+
...defaultOptions,
|
|
92
|
+
...defaultTypeOptions,
|
|
93
|
+
...options,
|
|
94
|
+
style: {
|
|
95
|
+
...(defaultOptions?.style ?? {}),
|
|
96
|
+
...(defaultTypeOptions?.style ?? {}),
|
|
97
|
+
...(options?.style ?? {}),
|
|
98
|
+
},
|
|
99
|
+
ariaProps: {
|
|
100
|
+
...(DEFAULT_ARIA_PROPS[type] ?? {}),
|
|
101
|
+
...(defaultOptions?.ariaProps ?? {}),
|
|
102
|
+
...(defaultTypeOptions?.ariaProps ?? {}),
|
|
103
|
+
...(options?.ariaProps ?? {}),
|
|
104
|
+
},
|
|
105
|
+
iconTheme: options?.iconTheme
|
|
106
|
+
?? defaultTypeOptions?.iconTheme
|
|
107
|
+
?? defaultOptions?.iconTheme
|
|
108
|
+
?? (type === "success" || type === "error" ? DEFAULT_ICON_THEME[type] : undefined),
|
|
109
|
+
};
|
|
110
|
+
const item = {
|
|
111
|
+
id,
|
|
112
|
+
type,
|
|
113
|
+
message,
|
|
114
|
+
status: "visible",
|
|
115
|
+
createdAt: current?.createdAt ?? Date.now(),
|
|
116
|
+
toasterId,
|
|
117
|
+
duration: mergedOptions.duration ?? current?.duration ?? DEFAULT_DURATION[type],
|
|
118
|
+
position: mergedOptions.position ?? current?.position ?? DEFAULT_POSITION,
|
|
119
|
+
height: current?.height ?? null,
|
|
120
|
+
pauseDuration: 0,
|
|
121
|
+
pausedAt: null,
|
|
122
|
+
ariaProps: mergedOptions.ariaProps ?? current?.ariaProps ?? DEFAULT_ARIA_PROPS[type],
|
|
123
|
+
style: mergedOptions.style,
|
|
124
|
+
className: mergedOptions.className,
|
|
125
|
+
icon: mergedOptions.icon,
|
|
126
|
+
iconTheme: mergedOptions.iconTheme,
|
|
127
|
+
removeDelay: mergedOptions.removeDelay ?? DEFAULT_REMOVE_DELAY,
|
|
128
|
+
};
|
|
129
|
+
ensurePresence(id);
|
|
130
|
+
store.add(item);
|
|
131
|
+
clearTimer(removeTimers, id);
|
|
132
|
+
scheduleDismiss(item);
|
|
133
|
+
return id;
|
|
134
|
+
}
|
|
135
|
+
function configureView(config) {
|
|
136
|
+
const nextLimit = Math.max(0, config.limit);
|
|
137
|
+
const hasChanged = nextLimit !== view.limit || config.position !== view.position || config.toastOptions !== view.toastOptions;
|
|
138
|
+
if (!hasChanged) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
view.limit = nextLimit;
|
|
142
|
+
view.position = config.position;
|
|
143
|
+
if (config.toastOptions !== undefined) {
|
|
144
|
+
view.toastOptions = config.toastOptions;
|
|
145
|
+
}
|
|
146
|
+
notify();
|
|
147
|
+
}
|
|
148
|
+
async function promiseToast(promise, messages, options) {
|
|
149
|
+
const task = typeof promise === "function" ? promise() : promise;
|
|
150
|
+
const id = addToast("loading", messages.loading, {
|
|
151
|
+
...options,
|
|
152
|
+
duration: Number.POSITIVE_INFINITY,
|
|
153
|
+
});
|
|
154
|
+
try {
|
|
155
|
+
const data = await task;
|
|
156
|
+
const successMessage = resolveValue(messages.success, data);
|
|
157
|
+
addToast("success", successMessage, {
|
|
158
|
+
...options,
|
|
159
|
+
id,
|
|
160
|
+
});
|
|
161
|
+
return data;
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
const errorMessage = resolveValue(messages.error, error);
|
|
165
|
+
addToast("error", errorMessage, {
|
|
166
|
+
...options,
|
|
167
|
+
id,
|
|
168
|
+
});
|
|
169
|
+
throw error;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function dismiss(id) {
|
|
173
|
+
const targets = id === undefined ? store.getSnapshot().map((item) => item.id) : [id];
|
|
174
|
+
for (const targetId of targets) {
|
|
175
|
+
const current = getItem(targetId);
|
|
176
|
+
if (current === undefined || current.status === "closing") {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
clearTimer(dismissTimers, targetId);
|
|
180
|
+
overlayStore.close(targetId);
|
|
181
|
+
store.dismiss(targetId);
|
|
182
|
+
scheduleRemove(current);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function remove(id) {
|
|
186
|
+
const targets = id === undefined ? store.getSnapshot().map((item) => item.id) : [id];
|
|
187
|
+
for (const targetId of targets) {
|
|
188
|
+
clearTimer(dismissTimers, targetId);
|
|
189
|
+
clearTimer(removeTimers, targetId);
|
|
190
|
+
overlayStore.remove(targetId);
|
|
191
|
+
store.remove(targetId);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function clear() {
|
|
195
|
+
clearAllTimers();
|
|
196
|
+
overlayStore.clear();
|
|
197
|
+
store.clear();
|
|
198
|
+
}
|
|
199
|
+
function updateHeight(id, height) {
|
|
200
|
+
store.updateHeight(id, height);
|
|
201
|
+
}
|
|
202
|
+
function getRawSnapshot() {
|
|
203
|
+
return store.getSnapshot();
|
|
204
|
+
}
|
|
205
|
+
function startPause() {
|
|
206
|
+
store.startPause();
|
|
207
|
+
for (const item of store.getSnapshot()) {
|
|
208
|
+
clearTimer(dismissTimers, item.id);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function endPause() {
|
|
212
|
+
store.endPause();
|
|
213
|
+
for (const item of store.getSnapshot()) {
|
|
214
|
+
if (item.status === "visible") {
|
|
215
|
+
scheduleDismiss(item);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function subscribe(listener) {
|
|
220
|
+
listeners.add(listener);
|
|
221
|
+
return () => {
|
|
222
|
+
listeners.delete(listener);
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function getSnapshot() {
|
|
226
|
+
return getVisibleItems(store.getSnapshot());
|
|
227
|
+
}
|
|
228
|
+
function getInitialSnapshot() {
|
|
229
|
+
return getVisibleItems(store.getInitialSnapshot());
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
toasterId,
|
|
233
|
+
addToast,
|
|
234
|
+
configureView,
|
|
235
|
+
promiseToast,
|
|
236
|
+
dismiss,
|
|
237
|
+
remove,
|
|
238
|
+
clear,
|
|
239
|
+
updateHeight,
|
|
240
|
+
getRawSnapshot,
|
|
241
|
+
startPause,
|
|
242
|
+
endPause,
|
|
243
|
+
subscribe,
|
|
244
|
+
getSnapshot,
|
|
245
|
+
getInitialSnapshot,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Store } from "@ilokesto/store";
|
|
2
|
+
export function createToastStore() {
|
|
3
|
+
const store = new Store({ items: [], pausedAt: null });
|
|
4
|
+
function add(item) {
|
|
5
|
+
store.setState((prev) => {
|
|
6
|
+
const existingIndex = prev.items.findIndex((current) => current.id === item.id);
|
|
7
|
+
if (existingIndex === -1) {
|
|
8
|
+
return {
|
|
9
|
+
...prev,
|
|
10
|
+
items: [...prev.items, item],
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
...prev,
|
|
15
|
+
items: prev.items.map((current) => current.id === item.id
|
|
16
|
+
? {
|
|
17
|
+
...current,
|
|
18
|
+
...item,
|
|
19
|
+
createdAt: current.createdAt,
|
|
20
|
+
toasterId: current.toasterId,
|
|
21
|
+
}
|
|
22
|
+
: current),
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function update(id, patch) {
|
|
27
|
+
store.setState((prev) => ({
|
|
28
|
+
...prev,
|
|
29
|
+
items: prev.items.map((item) => item.id === id
|
|
30
|
+
? {
|
|
31
|
+
...item,
|
|
32
|
+
...patch,
|
|
33
|
+
}
|
|
34
|
+
: item),
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
function dismiss(id) {
|
|
38
|
+
store.setState((prev) => ({
|
|
39
|
+
...prev,
|
|
40
|
+
items: prev.items.map((item) => {
|
|
41
|
+
if (id !== undefined && item.id !== id) {
|
|
42
|
+
return item;
|
|
43
|
+
}
|
|
44
|
+
if (item.status === "closing") {
|
|
45
|
+
return item;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
...item,
|
|
49
|
+
status: "closing",
|
|
50
|
+
};
|
|
51
|
+
}),
|
|
52
|
+
}));
|
|
53
|
+
}
|
|
54
|
+
function remove(id) {
|
|
55
|
+
store.setState((prev) => ({
|
|
56
|
+
...prev,
|
|
57
|
+
items: id === undefined
|
|
58
|
+
? []
|
|
59
|
+
: prev.items.filter((item) => item.id !== id),
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
function clear() {
|
|
63
|
+
store.setState({ items: [], pausedAt: null });
|
|
64
|
+
}
|
|
65
|
+
function updateHeight(id, height) {
|
|
66
|
+
update(id, { height });
|
|
67
|
+
}
|
|
68
|
+
function startPause() {
|
|
69
|
+
const startedAt = Date.now();
|
|
70
|
+
store.setState((prev) => {
|
|
71
|
+
if (prev.pausedAt !== null) {
|
|
72
|
+
return prev;
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
pausedAt: startedAt,
|
|
76
|
+
items: prev.items.map((item) => ({
|
|
77
|
+
...item,
|
|
78
|
+
pausedAt: item.status === "visible" ? startedAt : item.pausedAt,
|
|
79
|
+
})),
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function endPause() {
|
|
84
|
+
const endedAt = Date.now();
|
|
85
|
+
store.setState((prev) => {
|
|
86
|
+
if (prev.pausedAt === null) {
|
|
87
|
+
return prev;
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
pausedAt: null,
|
|
91
|
+
items: prev.items.map((item) => {
|
|
92
|
+
if (item.pausedAt === null) {
|
|
93
|
+
return item;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
...item,
|
|
97
|
+
pauseDuration: item.pauseDuration + (endedAt - item.pausedAt),
|
|
98
|
+
pausedAt: null,
|
|
99
|
+
};
|
|
100
|
+
}),
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function subscribe(listener) {
|
|
105
|
+
return store.subscribe(listener);
|
|
106
|
+
}
|
|
107
|
+
function getSnapshot() {
|
|
108
|
+
return store.getState().items;
|
|
109
|
+
}
|
|
110
|
+
function getInitialSnapshot() {
|
|
111
|
+
return store.getInitialState().items;
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
add,
|
|
115
|
+
update,
|
|
116
|
+
dismiss,
|
|
117
|
+
remove,
|
|
118
|
+
clear,
|
|
119
|
+
updateHeight,
|
|
120
|
+
startPause,
|
|
121
|
+
endPause,
|
|
122
|
+
subscribe,
|
|
123
|
+
getSnapshot,
|
|
124
|
+
getInitialSnapshot,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ToasterId, ToastRuntimeApi } from "../types/toast";
|
|
2
|
+
export declare function registerRuntime(runtime: ToastRuntimeApi): void;
|
|
3
|
+
export declare function unregisterRuntime(toasterId: ToasterId): void;
|
|
4
|
+
export declare function getRuntime(toasterId: ToasterId): ToastRuntimeApi | undefined;
|
|
5
|
+
export declare function requireRuntime(toasterId: ToasterId): ToastRuntimeApi;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const runtimeMap = new Map();
|
|
2
|
+
export function registerRuntime(runtime) {
|
|
3
|
+
runtimeMap.set(runtime.toasterId, runtime);
|
|
4
|
+
}
|
|
5
|
+
export function unregisterRuntime(toasterId) {
|
|
6
|
+
runtimeMap.delete(toasterId);
|
|
7
|
+
}
|
|
8
|
+
export function getRuntime(toasterId) {
|
|
9
|
+
return runtimeMap.get(toasterId);
|
|
10
|
+
}
|
|
11
|
+
export function requireRuntime(toasterId) {
|
|
12
|
+
const runtime = runtimeMap.get(toasterId);
|
|
13
|
+
if (runtime === undefined) {
|
|
14
|
+
throw new Error(`No toaster runtime registered for toasterId "${toasterId}". ` +
|
|
15
|
+
"Make sure a <Toaster> with this toasterId is mounted.");
|
|
16
|
+
}
|
|
17
|
+
return runtime;
|
|
18
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { requireRuntime } from "./registry";
|
|
2
|
+
import { DEFAULT_TOASTER_ID } from "./utils";
|
|
3
|
+
function resolveToasterId(options) {
|
|
4
|
+
return options?.toasterId ?? DEFAULT_TOASTER_ID;
|
|
5
|
+
}
|
|
6
|
+
function createToast(message, options) {
|
|
7
|
+
const runtime = requireRuntime(resolveToasterId(options));
|
|
8
|
+
return runtime.addToast("blank", message, options);
|
|
9
|
+
}
|
|
10
|
+
createToast.success = function success(message, options) {
|
|
11
|
+
const runtime = requireRuntime(resolveToasterId(options));
|
|
12
|
+
return runtime.addToast("success", message, options);
|
|
13
|
+
};
|
|
14
|
+
createToast.error = function error(message, options) {
|
|
15
|
+
const runtime = requireRuntime(resolveToasterId(options));
|
|
16
|
+
return runtime.addToast("error", message, options);
|
|
17
|
+
};
|
|
18
|
+
createToast.loading = function loading(message, options) {
|
|
19
|
+
const runtime = requireRuntime(resolveToasterId(options));
|
|
20
|
+
return runtime.addToast("loading", message, {
|
|
21
|
+
...options,
|
|
22
|
+
duration: Number.POSITIVE_INFINITY,
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
createToast.custom = function custom(message, options) {
|
|
26
|
+
const runtime = requireRuntime(resolveToasterId(options));
|
|
27
|
+
return runtime.addToast("custom", message, options);
|
|
28
|
+
};
|
|
29
|
+
createToast.promise = function promiseFn(promise, messages, options) {
|
|
30
|
+
const runtime = requireRuntime(resolveToasterId(options));
|
|
31
|
+
return runtime.promiseToast(promise, messages, options);
|
|
32
|
+
};
|
|
33
|
+
createToast.dismiss = function dismiss(id, toasterId) {
|
|
34
|
+
const runtime = requireRuntime(toasterId ?? DEFAULT_TOASTER_ID);
|
|
35
|
+
runtime.dismiss(id);
|
|
36
|
+
};
|
|
37
|
+
createToast.remove = function remove(id, toasterId) {
|
|
38
|
+
const runtime = requireRuntime(toasterId ?? DEFAULT_TOASTER_ID);
|
|
39
|
+
runtime.remove(id);
|
|
40
|
+
};
|
|
41
|
+
export const toast = createToast;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ToastAriaProps, IconTheme, ToastId, ToastPosition, ToastType } from "../types/toast";
|
|
2
|
+
export declare function generateToastId(): ToastId;
|
|
3
|
+
export declare const DEFAULT_TOASTER_ID = "default";
|
|
4
|
+
export declare const DEFAULT_REMOVE_DELAY = 1000;
|
|
5
|
+
export declare const DEFAULT_GUTTER = 8;
|
|
6
|
+
export declare const DEFAULT_LIMIT = 20;
|
|
7
|
+
export declare const DEFAULT_POSITION: ToastPosition;
|
|
8
|
+
export declare const DEFAULT_DURATION: Record<ToastType, number>;
|
|
9
|
+
export declare const DEFAULT_ARIA_PROPS: Record<ToastType, ToastAriaProps>;
|
|
10
|
+
export declare const DEFAULT_ICON_THEME: Record<"success" | "error", IconTheme>;
|
|
11
|
+
export declare function resolveValue<TValue, TArg>(value: TValue | ((arg: TArg) => TValue), arg: TArg): TValue;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
let counter = 0;
|
|
2
|
+
export function generateToastId() {
|
|
3
|
+
counter += 1;
|
|
4
|
+
return `toast-${counter}-${Date.now()}`;
|
|
5
|
+
}
|
|
6
|
+
export const DEFAULT_TOASTER_ID = "default";
|
|
7
|
+
export const DEFAULT_REMOVE_DELAY = 1000;
|
|
8
|
+
export const DEFAULT_GUTTER = 8;
|
|
9
|
+
export const DEFAULT_LIMIT = 20;
|
|
10
|
+
export const DEFAULT_POSITION = "top-right";
|
|
11
|
+
export const DEFAULT_DURATION = {
|
|
12
|
+
blank: 4000,
|
|
13
|
+
success: 2000,
|
|
14
|
+
error: 4000,
|
|
15
|
+
loading: Number.POSITIVE_INFINITY,
|
|
16
|
+
custom: 4000,
|
|
17
|
+
};
|
|
18
|
+
export const DEFAULT_ARIA_PROPS = {
|
|
19
|
+
blank: { role: "status", "aria-live": "polite", "aria-atomic": true },
|
|
20
|
+
success: { role: "status", "aria-live": "polite", "aria-atomic": true },
|
|
21
|
+
error: { role: "alert", "aria-live": "assertive", "aria-atomic": true },
|
|
22
|
+
loading: { role: "status", "aria-live": "polite", "aria-atomic": true },
|
|
23
|
+
custom: { role: "status", "aria-live": "polite", "aria-atomic": true },
|
|
24
|
+
};
|
|
25
|
+
export const DEFAULT_ICON_THEME = {
|
|
26
|
+
success: { primary: "#61d345", secondary: "#ffffff" },
|
|
27
|
+
error: { primary: "#ff4b4b", secondary: "#ffffff" },
|
|
28
|
+
};
|
|
29
|
+
export function resolveValue(value, arg) {
|
|
30
|
+
return typeof value === "function"
|
|
31
|
+
? value(arg)
|
|
32
|
+
: value;
|
|
33
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useCallback, useContext, useMemo } from "react";
|
|
2
|
+
import { ToasterContext } from "../components/ToastProvider";
|
|
3
|
+
import { DEFAULT_GUTTER } from "../core/utils";
|
|
4
|
+
import { useToastItems } from "./useToastItems";
|
|
5
|
+
export function useToaster() {
|
|
6
|
+
const runtime = useContext(ToasterContext);
|
|
7
|
+
if (runtime === null) {
|
|
8
|
+
throw new Error("useToaster must be used within a <Toaster> component.");
|
|
9
|
+
}
|
|
10
|
+
const toasts = useToastItems(runtime);
|
|
11
|
+
const calculateOffset = useCallback((toast, options) => {
|
|
12
|
+
const gutter = options?.gutter ?? DEFAULT_GUTTER;
|
|
13
|
+
const ordered = options?.reverseOrder ? [...toasts].reverse() : toasts;
|
|
14
|
+
const index = ordered.findIndex((item) => item.id === toast.id);
|
|
15
|
+
if (index === -1) {
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
return ordered.slice(0, index).reduce((offset, item) => {
|
|
19
|
+
return offset + (item.height ?? 0) + gutter;
|
|
20
|
+
}, 0);
|
|
21
|
+
}, [toasts]);
|
|
22
|
+
return useMemo(() => ({
|
|
23
|
+
toasts,
|
|
24
|
+
handlers: {
|
|
25
|
+
updateHeight: runtime.updateHeight,
|
|
26
|
+
startPause: runtime.startPause,
|
|
27
|
+
endPause: runtime.endPause,
|
|
28
|
+
calculateOffset,
|
|
29
|
+
},
|
|
30
|
+
}), [calculateOffset, runtime.endPause, runtime.startPause, runtime.updateHeight, toasts]);
|
|
31
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { toast } from "./core/toast";
|
|
2
|
+
export { Toaster } from "./components/Toaster";
|
|
3
|
+
export { ToastBar } from "./components/ToastBar";
|
|
4
|
+
export { ToastIcon } from "./components/icons";
|
|
5
|
+
export { useToaster } from "./hooks/useToaster";
|
|
6
|
+
export { useToastItems } from "./hooks/useToastItems";
|
|
7
|
+
export { createToastRuntime } from "./core/createToastRuntime";
|
|
8
|
+
export type { ToastBarProps } from "./components/ToastBar";
|
|
9
|
+
export type { Renderable, ToastId, ToasterId, ToastType, ToastStatus, ToastPosition, ToastTransport, ToastItem, ToastState, ToastOptions, DefaultToastOptions, IconTheme, ToastStoreApi, ToastFacade, ToasterProps, UseToasterResult, ToastRowHelpers, ToastRuntimeApi, PromiseToastMessages, } from "./types/toast";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { toast } from "./core/toast";
|
|
2
|
+
export { Toaster } from "./components/Toaster";
|
|
3
|
+
export { ToastBar } from "./components/ToastBar";
|
|
4
|
+
export { ToastIcon } from "./components/icons";
|
|
5
|
+
export { useToaster } from "./hooks/useToaster";
|
|
6
|
+
export { useToastItems } from "./hooks/useToastItems";
|
|
7
|
+
export { createToastRuntime } from "./core/createToastRuntime";
|