@cookified/toastify 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/LICENSE +21 -0
- package/README.md +296 -0
- package/dist/index.cjs +779 -0
- package/dist/index.d.cts +155 -0
- package/dist/index.d.ts +155 -0
- package/dist/index.js +742 -0
- package/package.json +89 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,742 @@
|
|
|
1
|
+
// src/toastify/Toaster.tsx
|
|
2
|
+
import { AnimatePresence, motion as motion4 } from "motion/react";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
|
|
5
|
+
// src/toastify/Toast.tsx
|
|
6
|
+
import { Check, Loader2, X } from "lucide-react";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
function DefaultToastIcon({ type }) {
|
|
9
|
+
const badgeClasses = "flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-neutral-900 text-white shadow-xs dark:bg-white dark:text-neutral-950";
|
|
10
|
+
switch (type) {
|
|
11
|
+
case "loading":
|
|
12
|
+
return /* @__PURE__ */ jsx("span", { className: badgeClasses, children: /* @__PURE__ */ jsx(Loader2, { size: 12, strokeWidth: 2.5, className: "animate-spin" }) });
|
|
13
|
+
case "success":
|
|
14
|
+
return /* @__PURE__ */ jsx("span", { className: badgeClasses, children: /* @__PURE__ */ jsx(Check, { size: 12, strokeWidth: 2.5 }) });
|
|
15
|
+
case "error":
|
|
16
|
+
return /* @__PURE__ */ jsx("span", { className: badgeClasses, children: /* @__PURE__ */ jsx(X, { size: 12, strokeWidth: 2.5 }) });
|
|
17
|
+
case "warning":
|
|
18
|
+
return /* @__PURE__ */ jsx("span", { className: badgeClasses, children: /* @__PURE__ */ jsxs(
|
|
19
|
+
"svg",
|
|
20
|
+
{
|
|
21
|
+
width: "12",
|
|
22
|
+
height: "12",
|
|
23
|
+
viewBox: "0 0 24 24",
|
|
24
|
+
fill: "none",
|
|
25
|
+
stroke: "currentColor",
|
|
26
|
+
strokeWidth: 2.5,
|
|
27
|
+
strokeLinecap: "round",
|
|
28
|
+
strokeLinejoin: "round",
|
|
29
|
+
"aria-hidden": "true",
|
|
30
|
+
children: [
|
|
31
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
|
|
32
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
) });
|
|
36
|
+
case "info":
|
|
37
|
+
case "neutral":
|
|
38
|
+
default:
|
|
39
|
+
return /* @__PURE__ */ jsx("span", { className: badgeClasses, children: /* @__PURE__ */ jsxs(
|
|
40
|
+
"svg",
|
|
41
|
+
{
|
|
42
|
+
width: "12",
|
|
43
|
+
height: "12",
|
|
44
|
+
viewBox: "0 0 24 24",
|
|
45
|
+
fill: "none",
|
|
46
|
+
stroke: "currentColor",
|
|
47
|
+
strokeWidth: 2.5,
|
|
48
|
+
strokeLinecap: "round",
|
|
49
|
+
strokeLinejoin: "round",
|
|
50
|
+
"aria-hidden": "true",
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
|
|
53
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
) });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function Toast({
|
|
60
|
+
toast: toast2,
|
|
61
|
+
onDismiss,
|
|
62
|
+
closeOnClick = false,
|
|
63
|
+
globalIcons,
|
|
64
|
+
globalOptions
|
|
65
|
+
}) {
|
|
66
|
+
if (toast2.customRenderer) {
|
|
67
|
+
return /* @__PURE__ */ jsx(Fragment, { children: toast2.customRenderer(toast2.id) });
|
|
68
|
+
}
|
|
69
|
+
const icon = toast2.icon ?? globalIcons?.[toast2.type] ?? /* @__PURE__ */ jsx(DefaultToastIcon, { type: toast2.type });
|
|
70
|
+
return /* @__PURE__ */ jsxs(
|
|
71
|
+
"div",
|
|
72
|
+
{
|
|
73
|
+
onClick: () => closeOnClick && onDismiss(),
|
|
74
|
+
className: `toastify-toast flex h-14 w-full select-none items-center justify-between gap-3 rounded-md border border-neutral-200/90 bg-white px-3.5 shadow-md shadow-neutral-950/5 dark:border-neutral-800/90 dark:bg-neutral-900 dark:shadow-neutral-950/40 ${globalOptions?.className ?? ""} ${toast2.className ?? ""}`,
|
|
75
|
+
style: { ...globalOptions?.style, ...toast2.style },
|
|
76
|
+
children: [
|
|
77
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-3", children: [
|
|
78
|
+
icon,
|
|
79
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col justify-center", children: [
|
|
80
|
+
/* @__PURE__ */ jsx("div", { className: "truncate text-[13px] font-medium leading-4 text-neutral-900 dark:text-neutral-100", children: toast2.title }),
|
|
81
|
+
toast2.description && /* @__PURE__ */ jsx("div", { className: "mt-0.5 truncate text-[12px] leading-4 text-neutral-500 dark:text-neutral-400", children: toast2.description })
|
|
82
|
+
] })
|
|
83
|
+
] }),
|
|
84
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
|
|
85
|
+
toast2.cancel && /* @__PURE__ */ jsx(
|
|
86
|
+
"button",
|
|
87
|
+
{
|
|
88
|
+
type: "button",
|
|
89
|
+
onClick: (event) => {
|
|
90
|
+
event.stopPropagation();
|
|
91
|
+
try {
|
|
92
|
+
toast2.cancel?.onClick(event);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
console.error("Toast cancel handler failed:", err);
|
|
95
|
+
}
|
|
96
|
+
onDismiss();
|
|
97
|
+
},
|
|
98
|
+
className: "cursor-pointer rounded px-2 py-1 text-xs font-medium text-neutral-600 transition-colors hover:bg-neutral-100 hover:text-neutral-900 dark:text-neutral-400 dark:hover:bg-neutral-800 dark:hover:text-neutral-100",
|
|
99
|
+
children: toast2.cancel.label
|
|
100
|
+
}
|
|
101
|
+
),
|
|
102
|
+
toast2.action && /* @__PURE__ */ jsx(
|
|
103
|
+
"button",
|
|
104
|
+
{
|
|
105
|
+
type: "button",
|
|
106
|
+
onClick: (event) => {
|
|
107
|
+
event.stopPropagation();
|
|
108
|
+
try {
|
|
109
|
+
toast2.action?.onClick(event);
|
|
110
|
+
} catch (err) {
|
|
111
|
+
console.error("Toast action handler failed:", err);
|
|
112
|
+
}
|
|
113
|
+
onDismiss();
|
|
114
|
+
},
|
|
115
|
+
className: "cursor-pointer rounded px-2.5 py-1 text-xs font-medium bg-neutral-900 text-white transition-all hover:bg-neutral-800 shadow-[inset_0_-2px_4px_rgba(0,0,0,0.5),0_1px_2px_rgba(0,0,0,0.08)] active:shadow-[inset_0_2px_4px_rgba(0,0,0,0.4)] dark:bg-neutral-100 dark:text-neutral-900 dark:hover:bg-neutral-200 dark:shadow-[inset_0_-2px_4px_rgba(0,0,0,0.22),0_1px_2px_rgba(0,0,0,0.15)] dark:active:shadow-[inset_0_2px_4px_rgba(0,0,0,0.25)]",
|
|
116
|
+
children: toast2.action.label
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
] })
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/toastify/animations/FadeAnimation.tsx
|
|
126
|
+
import { motion } from "motion/react";
|
|
127
|
+
|
|
128
|
+
// src/toastify/animations/constants.ts
|
|
129
|
+
var defaultSpring = {
|
|
130
|
+
stiffness: 220,
|
|
131
|
+
damping: 26,
|
|
132
|
+
mass: 1
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// src/toastify/animations/FadeAnimation.tsx
|
|
136
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
137
|
+
function FadeAnimation({
|
|
138
|
+
index,
|
|
139
|
+
position,
|
|
140
|
+
isDismissing,
|
|
141
|
+
onDismiss,
|
|
142
|
+
springConfig = defaultSpring,
|
|
143
|
+
children
|
|
144
|
+
}) {
|
|
145
|
+
const isTop = position.startsWith("top");
|
|
146
|
+
const stackStep = 66;
|
|
147
|
+
const targetY = isTop ? index * stackStep : -index * stackStep;
|
|
148
|
+
return /* @__PURE__ */ jsx2(
|
|
149
|
+
motion.article,
|
|
150
|
+
{
|
|
151
|
+
role: "status",
|
|
152
|
+
"aria-live": "polite",
|
|
153
|
+
initial: {
|
|
154
|
+
opacity: 0,
|
|
155
|
+
scale: 0.9,
|
|
156
|
+
y: targetY,
|
|
157
|
+
filter: "blur(4px)"
|
|
158
|
+
},
|
|
159
|
+
animate: {
|
|
160
|
+
opacity: isDismissing ? 0 : 1,
|
|
161
|
+
scale: isDismissing ? 0.9 : 1,
|
|
162
|
+
y: targetY,
|
|
163
|
+
filter: isDismissing ? "blur(4px)" : "blur(0px)",
|
|
164
|
+
zIndex: 50 - index,
|
|
165
|
+
pointerEvents: !isDismissing ? "auto" : "none"
|
|
166
|
+
},
|
|
167
|
+
exit: {
|
|
168
|
+
opacity: 0,
|
|
169
|
+
scale: 0.9,
|
|
170
|
+
filter: "blur(4px)",
|
|
171
|
+
transition: {
|
|
172
|
+
duration: 0.22,
|
|
173
|
+
ease: "easeOut"
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
transition: {
|
|
177
|
+
type: "spring",
|
|
178
|
+
...springConfig
|
|
179
|
+
},
|
|
180
|
+
drag: "x",
|
|
181
|
+
dragConstraints: { left: 0, right: 0 },
|
|
182
|
+
dragElastic: 0.6,
|
|
183
|
+
onDragEnd: (_, info) => {
|
|
184
|
+
if (Math.abs(info.offset.x) > 60 || Math.abs(info.velocity.x) > 500) {
|
|
185
|
+
onDismiss();
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
className: "absolute h-14 w-full select-none cursor-grab active:cursor-grabbing",
|
|
189
|
+
style: {
|
|
190
|
+
[isTop ? "top" : "bottom"]: 0,
|
|
191
|
+
left: 0,
|
|
192
|
+
right: 0
|
|
193
|
+
},
|
|
194
|
+
children
|
|
195
|
+
}
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/toastify/animations/FolderStackAnimation.tsx
|
|
200
|
+
import { motion as motion2 } from "motion/react";
|
|
201
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
202
|
+
function FolderStackAnimation({
|
|
203
|
+
index,
|
|
204
|
+
isHovered,
|
|
205
|
+
position,
|
|
206
|
+
isDismissing,
|
|
207
|
+
onDismiss,
|
|
208
|
+
springConfig = defaultSpring,
|
|
209
|
+
children
|
|
210
|
+
}) {
|
|
211
|
+
const isTop = position.startsWith("top");
|
|
212
|
+
const isCenter = position.endsWith("center");
|
|
213
|
+
const isLeft = position.endsWith("left");
|
|
214
|
+
const collapsed = !isHovered;
|
|
215
|
+
const isVisible = !collapsed || index < 3;
|
|
216
|
+
const stackStep = 66;
|
|
217
|
+
const offset = collapsed ? index * 10 : index * stackStep;
|
|
218
|
+
const targetY = isTop ? offset : -offset;
|
|
219
|
+
const targetScale = collapsed ? Math.max(0.88, 1 - index * 0.05) : 1;
|
|
220
|
+
const targetOpacity = !isVisible ? 0 : collapsed ? index === 0 ? 1 : index === 1 ? 0.94 : 0.84 : 1;
|
|
221
|
+
const exitX = isCenter ? 0 : isLeft ? -36 : 36;
|
|
222
|
+
return /* @__PURE__ */ jsx3(
|
|
223
|
+
motion2.article,
|
|
224
|
+
{
|
|
225
|
+
role: "status",
|
|
226
|
+
"aria-live": "polite",
|
|
227
|
+
initial: {
|
|
228
|
+
opacity: 0,
|
|
229
|
+
x: 0,
|
|
230
|
+
y: isTop ? targetY - 14 : targetY + 14,
|
|
231
|
+
scale: 0.94
|
|
232
|
+
},
|
|
233
|
+
animate: {
|
|
234
|
+
opacity: isDismissing ? 0 : targetOpacity,
|
|
235
|
+
x: isDismissing ? exitX : 0,
|
|
236
|
+
y: targetY,
|
|
237
|
+
scale: isDismissing ? 0.94 : targetScale,
|
|
238
|
+
zIndex: 50 - index,
|
|
239
|
+
pointerEvents: !isDismissing && isVisible ? "auto" : "none"
|
|
240
|
+
},
|
|
241
|
+
exit: {
|
|
242
|
+
opacity: 0,
|
|
243
|
+
x: exitX,
|
|
244
|
+
scale: 0.94,
|
|
245
|
+
transition: {
|
|
246
|
+
duration: 0.24,
|
|
247
|
+
ease: [0.16, 1, 0.3, 1]
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
transition: {
|
|
251
|
+
type: "spring",
|
|
252
|
+
...springConfig
|
|
253
|
+
},
|
|
254
|
+
drag: index === 0 || isHovered ? "x" : false,
|
|
255
|
+
dragConstraints: { left: 0, right: 0 },
|
|
256
|
+
dragElastic: 0.6,
|
|
257
|
+
onDragEnd: (_, info) => {
|
|
258
|
+
if (Math.abs(info.offset.x) > 60 || Math.abs(info.velocity.x) > 500) {
|
|
259
|
+
onDismiss();
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
className: "absolute h-14 w-full select-none cursor-grab active:cursor-grabbing",
|
|
263
|
+
style: {
|
|
264
|
+
[isTop ? "top" : "bottom"]: 0,
|
|
265
|
+
left: 0,
|
|
266
|
+
right: 0,
|
|
267
|
+
transformOrigin: isTop ? "top center" : "bottom center"
|
|
268
|
+
},
|
|
269
|
+
children
|
|
270
|
+
}
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/toastify/animations/SlideAnimation.tsx
|
|
275
|
+
import { motion as motion3 } from "motion/react";
|
|
276
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
277
|
+
function SlideAnimation({
|
|
278
|
+
index,
|
|
279
|
+
position,
|
|
280
|
+
isDismissing,
|
|
281
|
+
onDismiss,
|
|
282
|
+
springConfig = defaultSpring,
|
|
283
|
+
children
|
|
284
|
+
}) {
|
|
285
|
+
const isTop = position.startsWith("top");
|
|
286
|
+
const isCenter = position.endsWith("center");
|
|
287
|
+
const isLeft = position.endsWith("left");
|
|
288
|
+
const stackStep = 66;
|
|
289
|
+
const targetY = isTop ? index * stackStep : -index * stackStep;
|
|
290
|
+
const entryX = isCenter ? 0 : isLeft ? -120 : 120;
|
|
291
|
+
const exitX = isCenter ? 0 : isLeft ? -140 : 140;
|
|
292
|
+
const initialY = isCenter ? isTop ? targetY - 30 : targetY + 30 : targetY;
|
|
293
|
+
return /* @__PURE__ */ jsx4(
|
|
294
|
+
motion3.article,
|
|
295
|
+
{
|
|
296
|
+
role: "status",
|
|
297
|
+
"aria-live": "polite",
|
|
298
|
+
initial: {
|
|
299
|
+
opacity: 0,
|
|
300
|
+
x: entryX,
|
|
301
|
+
y: initialY,
|
|
302
|
+
scale: 0.95
|
|
303
|
+
},
|
|
304
|
+
animate: {
|
|
305
|
+
opacity: isDismissing ? 0 : 1,
|
|
306
|
+
x: isDismissing ? exitX : 0,
|
|
307
|
+
y: targetY,
|
|
308
|
+
scale: 1,
|
|
309
|
+
zIndex: 50 - index,
|
|
310
|
+
pointerEvents: !isDismissing ? "auto" : "none"
|
|
311
|
+
},
|
|
312
|
+
exit: {
|
|
313
|
+
opacity: 0,
|
|
314
|
+
x: exitX,
|
|
315
|
+
scale: 0.95,
|
|
316
|
+
transition: {
|
|
317
|
+
duration: 0.22,
|
|
318
|
+
ease: [0.16, 1, 0.3, 1]
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
transition: {
|
|
322
|
+
type: "spring",
|
|
323
|
+
...springConfig
|
|
324
|
+
},
|
|
325
|
+
drag: "x",
|
|
326
|
+
dragConstraints: { left: 0, right: 0 },
|
|
327
|
+
dragElastic: 0.6,
|
|
328
|
+
onDragEnd: (_, info) => {
|
|
329
|
+
if (Math.abs(info.offset.x) > 60 || Math.abs(info.velocity.x) > 500) {
|
|
330
|
+
onDismiss();
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
className: "absolute h-14 w-full select-none cursor-grab active:cursor-grabbing",
|
|
334
|
+
style: {
|
|
335
|
+
[isTop ? "top" : "bottom"]: 0,
|
|
336
|
+
left: 0,
|
|
337
|
+
right: 0
|
|
338
|
+
},
|
|
339
|
+
children
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// src/toastify/animations/index.tsx
|
|
345
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
346
|
+
function ToastAnimation({
|
|
347
|
+
animation = "stack",
|
|
348
|
+
...props
|
|
349
|
+
}) {
|
|
350
|
+
if (typeof animation === "function") {
|
|
351
|
+
const CustomAnimation = animation;
|
|
352
|
+
return /* @__PURE__ */ jsx5(CustomAnimation, { ...props });
|
|
353
|
+
}
|
|
354
|
+
if (animation === "slide") {
|
|
355
|
+
return /* @__PURE__ */ jsx5(SlideAnimation, { ...props });
|
|
356
|
+
}
|
|
357
|
+
if (animation === "fade") {
|
|
358
|
+
return /* @__PURE__ */ jsx5(FadeAnimation, { ...props });
|
|
359
|
+
}
|
|
360
|
+
return /* @__PURE__ */ jsx5(FolderStackAnimation, { ...props });
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// src/toastify/store.ts
|
|
364
|
+
var MAX_TOASTS = 30;
|
|
365
|
+
var toasts = [];
|
|
366
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
367
|
+
function generateId() {
|
|
368
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
369
|
+
return crypto.randomUUID();
|
|
370
|
+
}
|
|
371
|
+
return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
372
|
+
}
|
|
373
|
+
function sanitizeDuration(duration) {
|
|
374
|
+
if (duration === false) return false;
|
|
375
|
+
if (typeof duration === "number") {
|
|
376
|
+
return Number.isFinite(duration) && duration >= 0 ? duration : 3500;
|
|
377
|
+
}
|
|
378
|
+
return void 0;
|
|
379
|
+
}
|
|
380
|
+
function emit() {
|
|
381
|
+
const snapshot = [...toasts];
|
|
382
|
+
listeners.forEach((listener) => {
|
|
383
|
+
try {
|
|
384
|
+
listener(snapshot);
|
|
385
|
+
} catch (err) {
|
|
386
|
+
console.error("Toast listener threw an error:", err);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
function subscribe(listener) {
|
|
391
|
+
listeners.add(listener);
|
|
392
|
+
try {
|
|
393
|
+
listener([...toasts]);
|
|
394
|
+
} catch (err) {
|
|
395
|
+
console.error("Initial toast listener threw an error:", err);
|
|
396
|
+
}
|
|
397
|
+
return () => {
|
|
398
|
+
listeners.delete(listener);
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
function remove(id) {
|
|
402
|
+
if (id) {
|
|
403
|
+
toasts = toasts.filter((toast2) => toast2.id !== id);
|
|
404
|
+
} else {
|
|
405
|
+
toasts = [];
|
|
406
|
+
}
|
|
407
|
+
emit();
|
|
408
|
+
}
|
|
409
|
+
function update(id, updates) {
|
|
410
|
+
toasts = toasts.map(
|
|
411
|
+
(toast2) => toast2.id === id ? { ...toast2, ...updates } : toast2
|
|
412
|
+
);
|
|
413
|
+
emit();
|
|
414
|
+
}
|
|
415
|
+
function create(type, title, options = {}) {
|
|
416
|
+
const id = options.id ?? generateId();
|
|
417
|
+
const duration = sanitizeDuration(options.autoClose ?? options.duration);
|
|
418
|
+
const existing = toasts.find((t) => t.id === id);
|
|
419
|
+
if (existing) {
|
|
420
|
+
update(id, {
|
|
421
|
+
type,
|
|
422
|
+
title,
|
|
423
|
+
description: options.description,
|
|
424
|
+
action: options.action,
|
|
425
|
+
cancel: options.cancel,
|
|
426
|
+
icon: options.icon,
|
|
427
|
+
className: options.className,
|
|
428
|
+
style: options.style,
|
|
429
|
+
duration
|
|
430
|
+
});
|
|
431
|
+
return id;
|
|
432
|
+
}
|
|
433
|
+
const toastItem = {
|
|
434
|
+
id,
|
|
435
|
+
type,
|
|
436
|
+
title,
|
|
437
|
+
description: options.description,
|
|
438
|
+
action: options.action,
|
|
439
|
+
cancel: options.cancel,
|
|
440
|
+
icon: options.icon,
|
|
441
|
+
className: options.className,
|
|
442
|
+
style: options.style,
|
|
443
|
+
duration,
|
|
444
|
+
createdAt: Date.now()
|
|
445
|
+
};
|
|
446
|
+
toasts = [toastItem, ...toasts].slice(0, MAX_TOASTS);
|
|
447
|
+
emit();
|
|
448
|
+
return id;
|
|
449
|
+
}
|
|
450
|
+
function promise(promiseOrFn, options) {
|
|
451
|
+
const id = create("loading", options.loading, {
|
|
452
|
+
duration: false
|
|
453
|
+
});
|
|
454
|
+
const p = typeof promiseOrFn === "function" ? promiseOrFn() : promiseOrFn;
|
|
455
|
+
const promiseChain = p.then((data) => {
|
|
456
|
+
let successTitle;
|
|
457
|
+
try {
|
|
458
|
+
successTitle = typeof options.success === "function" ? options.success(data) : options.success;
|
|
459
|
+
} catch {
|
|
460
|
+
successTitle = "Completed successfully";
|
|
461
|
+
}
|
|
462
|
+
let description;
|
|
463
|
+
if (options.description) {
|
|
464
|
+
try {
|
|
465
|
+
description = typeof options.description === "function" ? options.description(data) : options.description;
|
|
466
|
+
} catch {
|
|
467
|
+
description = void 0;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
update(id, {
|
|
471
|
+
type: "success",
|
|
472
|
+
title: successTitle,
|
|
473
|
+
description,
|
|
474
|
+
action: options.action,
|
|
475
|
+
cancel: options.cancel,
|
|
476
|
+
duration: 3500
|
|
477
|
+
});
|
|
478
|
+
return data;
|
|
479
|
+
}).catch((err) => {
|
|
480
|
+
let errorTitle;
|
|
481
|
+
try {
|
|
482
|
+
errorTitle = typeof options.error === "function" ? options.error(err) : options.error;
|
|
483
|
+
} catch {
|
|
484
|
+
errorTitle = "An error occurred";
|
|
485
|
+
}
|
|
486
|
+
update(id, {
|
|
487
|
+
type: "error",
|
|
488
|
+
title: errorTitle,
|
|
489
|
+
action: options.action,
|
|
490
|
+
cancel: options.cancel,
|
|
491
|
+
duration: 4e3
|
|
492
|
+
});
|
|
493
|
+
return Promise.reject(err);
|
|
494
|
+
});
|
|
495
|
+
promiseChain.catch(() => {
|
|
496
|
+
});
|
|
497
|
+
return promiseChain;
|
|
498
|
+
}
|
|
499
|
+
var toastStore = {
|
|
500
|
+
subscribe,
|
|
501
|
+
remove,
|
|
502
|
+
update,
|
|
503
|
+
getToasts: () => [...toasts]
|
|
504
|
+
};
|
|
505
|
+
function toastFn(title, options) {
|
|
506
|
+
return create("neutral", title, options);
|
|
507
|
+
}
|
|
508
|
+
var toast = Object.assign(toastFn, {
|
|
509
|
+
show(title, options) {
|
|
510
|
+
return create("neutral", title, options);
|
|
511
|
+
},
|
|
512
|
+
success(title, options) {
|
|
513
|
+
return create("success", title, options);
|
|
514
|
+
},
|
|
515
|
+
error(title, options) {
|
|
516
|
+
return create("error", title, options);
|
|
517
|
+
},
|
|
518
|
+
warning(title, options) {
|
|
519
|
+
return create("warning", title, options);
|
|
520
|
+
},
|
|
521
|
+
info(title, options) {
|
|
522
|
+
return create("info", title, options);
|
|
523
|
+
},
|
|
524
|
+
loading(title, options) {
|
|
525
|
+
return create("loading", title, { ...options, duration: false });
|
|
526
|
+
},
|
|
527
|
+
custom(renderer, options = {}) {
|
|
528
|
+
const id = options.id ?? generateId();
|
|
529
|
+
const duration = sanitizeDuration(options.autoClose ?? options.duration);
|
|
530
|
+
const toastItem = {
|
|
531
|
+
id,
|
|
532
|
+
type: "custom",
|
|
533
|
+
title: "",
|
|
534
|
+
customRenderer: renderer,
|
|
535
|
+
duration,
|
|
536
|
+
className: options.className,
|
|
537
|
+
style: options.style,
|
|
538
|
+
createdAt: Date.now()
|
|
539
|
+
};
|
|
540
|
+
toasts = [toastItem, ...toasts].slice(0, MAX_TOASTS);
|
|
541
|
+
emit();
|
|
542
|
+
return id;
|
|
543
|
+
},
|
|
544
|
+
promise,
|
|
545
|
+
dismiss(id) {
|
|
546
|
+
remove(id);
|
|
547
|
+
},
|
|
548
|
+
update(id, options) {
|
|
549
|
+
update(id, options);
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
// src/toastify/Toaster.tsx
|
|
554
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
555
|
+
var positionClasses = {
|
|
556
|
+
"top-left": "top-6 left-6",
|
|
557
|
+
"top-center": "top-6 left-0 right-0 mx-auto",
|
|
558
|
+
"top-right": "top-6 right-6",
|
|
559
|
+
"bottom-left": "bottom-6 left-6",
|
|
560
|
+
"bottom-center": "bottom-6 left-0 right-0 mx-auto",
|
|
561
|
+
"bottom-right": "bottom-6 right-6"
|
|
562
|
+
};
|
|
563
|
+
function ToasterItem({
|
|
564
|
+
toast: toast2,
|
|
565
|
+
index,
|
|
566
|
+
totalToasts,
|
|
567
|
+
isHovered,
|
|
568
|
+
position,
|
|
569
|
+
duration = 3500,
|
|
570
|
+
autoClose,
|
|
571
|
+
closeOnClick = false,
|
|
572
|
+
animation = "stack",
|
|
573
|
+
springConfig,
|
|
574
|
+
icons,
|
|
575
|
+
toastOptions,
|
|
576
|
+
onDismiss
|
|
577
|
+
}) {
|
|
578
|
+
const itemDuration = toast2.type === "loading" ? false : toast2.duration !== void 0 ? toast2.duration : toastOptions?.duration !== void 0 ? toastOptions.duration : autoClose ?? duration;
|
|
579
|
+
const onDismissRef = useRef(onDismiss);
|
|
580
|
+
useEffect(() => {
|
|
581
|
+
onDismissRef.current = onDismiss;
|
|
582
|
+
}, [onDismiss]);
|
|
583
|
+
const [isDismissing, setIsDismissing] = useState(false);
|
|
584
|
+
const handleDismiss = () => {
|
|
585
|
+
setIsDismissing(true);
|
|
586
|
+
onDismissRef.current();
|
|
587
|
+
};
|
|
588
|
+
const remainingTimeRef = useRef(itemDuration);
|
|
589
|
+
useEffect(() => {
|
|
590
|
+
remainingTimeRef.current = itemDuration;
|
|
591
|
+
}, [itemDuration]);
|
|
592
|
+
useEffect(() => {
|
|
593
|
+
if (itemDuration === false || isHovered) {
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
const startTime = Date.now();
|
|
597
|
+
const currentRemaining = remainingTimeRef.current === false ? itemDuration : remainingTimeRef.current;
|
|
598
|
+
const timer = window.setTimeout(() => {
|
|
599
|
+
handleDismiss();
|
|
600
|
+
}, currentRemaining);
|
|
601
|
+
return () => {
|
|
602
|
+
window.clearTimeout(timer);
|
|
603
|
+
if (remainingTimeRef.current !== false) {
|
|
604
|
+
const elapsed = Date.now() - startTime;
|
|
605
|
+
remainingTimeRef.current = Math.max(0, remainingTimeRef.current - elapsed);
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
}, [isHovered, itemDuration]);
|
|
609
|
+
return /* @__PURE__ */ jsx6(
|
|
610
|
+
ToastAnimation,
|
|
611
|
+
{
|
|
612
|
+
animation,
|
|
613
|
+
toast: toast2,
|
|
614
|
+
index,
|
|
615
|
+
totalToasts,
|
|
616
|
+
isHovered,
|
|
617
|
+
position,
|
|
618
|
+
isDismissing,
|
|
619
|
+
onDismiss: handleDismiss,
|
|
620
|
+
springConfig,
|
|
621
|
+
children: /* @__PURE__ */ jsx6(
|
|
622
|
+
Toast,
|
|
623
|
+
{
|
|
624
|
+
toast: toast2,
|
|
625
|
+
onDismiss: handleDismiss,
|
|
626
|
+
closeOnClick,
|
|
627
|
+
globalIcons: icons,
|
|
628
|
+
globalOptions: toastOptions
|
|
629
|
+
}
|
|
630
|
+
)
|
|
631
|
+
}
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
function Toaster({
|
|
635
|
+
position = "bottom-right",
|
|
636
|
+
duration = 3500,
|
|
637
|
+
autoClose,
|
|
638
|
+
theme = "light",
|
|
639
|
+
className,
|
|
640
|
+
style,
|
|
641
|
+
visibleToasts = 5,
|
|
642
|
+
closeOnClick = false,
|
|
643
|
+
animation = "stack",
|
|
644
|
+
springConfig,
|
|
645
|
+
icons,
|
|
646
|
+
toastOptions
|
|
647
|
+
}) {
|
|
648
|
+
const [toasts2, setToasts] = useState([]);
|
|
649
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
650
|
+
const [hoverExpandedCount, setHoverExpandedCount] = useState(null);
|
|
651
|
+
const leaveTimeoutRef = useRef(null);
|
|
652
|
+
useEffect(() => toastStore.subscribe(setToasts), []);
|
|
653
|
+
const isTop = position.startsWith("top");
|
|
654
|
+
const hasToasts = toasts2.length > 0;
|
|
655
|
+
const activeCount = Math.min(toasts2.length, visibleToasts);
|
|
656
|
+
const effectiveCount = isHovered && hoverExpandedCount !== null ? Math.max(activeCount, hoverExpandedCount) : activeCount;
|
|
657
|
+
const containerHeight = hasToasts && isHovered && effectiveCount > 0 ? (effectiveCount - 1) * 66 + 56 : 56;
|
|
658
|
+
const handleMouseEnter = () => {
|
|
659
|
+
if (leaveTimeoutRef.current) {
|
|
660
|
+
window.clearTimeout(leaveTimeoutRef.current);
|
|
661
|
+
leaveTimeoutRef.current = null;
|
|
662
|
+
}
|
|
663
|
+
setHoverExpandedCount((prev) => Math.max(prev ?? 0, activeCount));
|
|
664
|
+
setIsHovered(true);
|
|
665
|
+
};
|
|
666
|
+
const handleMouseLeave = () => {
|
|
667
|
+
leaveTimeoutRef.current = window.setTimeout(() => {
|
|
668
|
+
setIsHovered(false);
|
|
669
|
+
setHoverExpandedCount(null);
|
|
670
|
+
}, 140);
|
|
671
|
+
};
|
|
672
|
+
useEffect(() => {
|
|
673
|
+
return () => {
|
|
674
|
+
if (leaveTimeoutRef.current) {
|
|
675
|
+
window.clearTimeout(leaveTimeoutRef.current);
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
}, []);
|
|
679
|
+
return /* @__PURE__ */ jsx6(
|
|
680
|
+
motion4.div,
|
|
681
|
+
{
|
|
682
|
+
"data-toastify-toaster": "true",
|
|
683
|
+
role: "region",
|
|
684
|
+
"aria-label": "Notifications",
|
|
685
|
+
"aria-live": "polite",
|
|
686
|
+
tabIndex: -1,
|
|
687
|
+
className: `toastify-toaster fixed z-50 w-[356px] max-w-[calc(100vw-32px)] ${hasToasts ? "pointer-events-auto" : "pointer-events-none"} ${positionClasses[position]} ${theme === "dark" ? "dark" : ""} ${className ?? ""}`,
|
|
688
|
+
style,
|
|
689
|
+
animate: {
|
|
690
|
+
height: containerHeight
|
|
691
|
+
},
|
|
692
|
+
transition: {
|
|
693
|
+
type: "spring",
|
|
694
|
+
stiffness: 220,
|
|
695
|
+
damping: 26,
|
|
696
|
+
mass: 1,
|
|
697
|
+
...springConfig
|
|
698
|
+
},
|
|
699
|
+
onMouseEnter: handleMouseEnter,
|
|
700
|
+
onMouseLeave: handleMouseLeave,
|
|
701
|
+
children: /* @__PURE__ */ jsx6(
|
|
702
|
+
"div",
|
|
703
|
+
{
|
|
704
|
+
className: `relative w-full h-full flex ${isTop ? "flex-col" : "flex-col-reverse"}`,
|
|
705
|
+
children: /* @__PURE__ */ jsx6(AnimatePresence, { children: toasts2.slice(0, visibleToasts).map((toastItem, index) => /* @__PURE__ */ jsx6(
|
|
706
|
+
ToasterItem,
|
|
707
|
+
{
|
|
708
|
+
toast: toastItem,
|
|
709
|
+
index,
|
|
710
|
+
totalToasts: toasts2.length,
|
|
711
|
+
isHovered,
|
|
712
|
+
position,
|
|
713
|
+
duration,
|
|
714
|
+
autoClose,
|
|
715
|
+
closeOnClick,
|
|
716
|
+
animation,
|
|
717
|
+
springConfig,
|
|
718
|
+
icons,
|
|
719
|
+
toastOptions,
|
|
720
|
+
onDismiss: () => toastStore.remove(toastItem.id)
|
|
721
|
+
},
|
|
722
|
+
toastItem.id
|
|
723
|
+
)) })
|
|
724
|
+
}
|
|
725
|
+
)
|
|
726
|
+
}
|
|
727
|
+
);
|
|
728
|
+
}
|
|
729
|
+
var ToastContainer = Toaster;
|
|
730
|
+
export {
|
|
731
|
+
DefaultToastIcon,
|
|
732
|
+
FadeAnimation,
|
|
733
|
+
FolderStackAnimation,
|
|
734
|
+
SlideAnimation,
|
|
735
|
+
Toast,
|
|
736
|
+
ToastAnimation,
|
|
737
|
+
ToastContainer,
|
|
738
|
+
Toaster,
|
|
739
|
+
defaultSpring,
|
|
740
|
+
toast,
|
|
741
|
+
toastStore
|
|
742
|
+
};
|