@marv3l/canopy-ui 1.2.5 → 1.2.6
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/dist/index.js +0 -4
- package/package.json +1 -1
- package/templates/toast/toast.tsx +340 -50
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,14 +1,82 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
CheckCircle2,
|
|
6
|
+
AlertCircle,
|
|
7
|
+
AlertTriangle,
|
|
8
|
+
Info,
|
|
9
|
+
Loader2,
|
|
10
|
+
X,
|
|
11
|
+
type LucideIcon,
|
|
12
|
+
} from "lucide-react";
|
|
13
|
+
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// TYPES & INTERFACES
|
|
16
|
+
// =============================================================================
|
|
17
|
+
|
|
18
|
+
export type ToastVariant =
|
|
19
|
+
| "default"
|
|
20
|
+
| "success"
|
|
21
|
+
| "error"
|
|
22
|
+
| "warning"
|
|
23
|
+
| "info"
|
|
24
|
+
| "custom"
|
|
25
|
+
| "loading";
|
|
26
|
+
|
|
27
|
+
export interface ToastOptions {
|
|
28
|
+
/** Optional custom identifier. If omitted, a collision-resistant UUID is generated. */
|
|
29
|
+
id?: string;
|
|
30
|
+
/** Primary title text or JSX element displayed in the toast header. */
|
|
31
|
+
title?: React.ReactNode;
|
|
32
|
+
/** Secondary explanatory text or JSX node rendered below the title. */
|
|
33
|
+
description?: React.ReactNode;
|
|
34
|
+
/** Interactive action button or control rendered at the bottom of the toast. */
|
|
35
|
+
action?: React.ReactNode;
|
|
36
|
+
/** Visual variant styling preset. Defaults to "default". */
|
|
37
|
+
variant?: ToastVariant;
|
|
38
|
+
/** Display duration in milliseconds before auto-dismissing. Set to 0 or Infinity to prevent auto-dismiss. */
|
|
39
|
+
duration?: number;
|
|
40
|
+
/** Maximum number of duplicate message stacks allowed for this specific toast (defaults to 5). */
|
|
41
|
+
maxCount?: number;
|
|
42
|
+
/** Explicitly toggle the animated bottom progress bar. Defaults to true when auto-dismissible. */
|
|
43
|
+
showProgress?: boolean;
|
|
44
|
+
/** Optional custom icon node to override the variant preset icon. */
|
|
45
|
+
icon?: React.ReactNode;
|
|
46
|
+
/** Custom inline token styling overrides for background, border, text, progress bar, and icon. */
|
|
47
|
+
customColor?: {
|
|
48
|
+
bg?: string;
|
|
49
|
+
text?: string;
|
|
50
|
+
border?: string;
|
|
51
|
+
progress?: string;
|
|
52
|
+
icon?: string;
|
|
53
|
+
};
|
|
54
|
+
/** Additional Tailwind or CSS class names to apply to the root toast card container. */
|
|
55
|
+
className?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface ToastItem extends ToastOptions {
|
|
59
|
+
id: string;
|
|
60
|
+
open: boolean;
|
|
61
|
+
count: number;
|
|
62
|
+
maxReached?: boolean;
|
|
63
|
+
}
|
|
6
64
|
|
|
7
65
|
export interface ToasterProps {
|
|
8
66
|
defaultDuration?: number;
|
|
9
|
-
position?:
|
|
67
|
+
position?:
|
|
68
|
+
| "top-right"
|
|
69
|
+
| "bottom-right"
|
|
70
|
+
| "top-center"
|
|
71
|
+
| "bottom-center"
|
|
72
|
+
| "top-left"
|
|
73
|
+
| "bottom-left";
|
|
10
74
|
}
|
|
11
75
|
|
|
76
|
+
// =============================================================================
|
|
77
|
+
// VARIANT STYLING CONFIGURATION
|
|
78
|
+
// =============================================================================
|
|
79
|
+
|
|
12
80
|
const variantStyles: Record<
|
|
13
81
|
string,
|
|
14
82
|
{
|
|
@@ -29,7 +97,8 @@ const variantStyles: Record<
|
|
|
29
97
|
description: "text-neutral-600 dark:text-neutral-200",
|
|
30
98
|
progress: "bg-neutral-900/20 dark:bg-neutral-400",
|
|
31
99
|
iconColor: "text-neutral-700 dark:text-neutral-300",
|
|
32
|
-
badge:
|
|
100
|
+
badge:
|
|
101
|
+
"bg-neutral-200 text-neutral-800 dark:bg-neutral-800 dark:text-neutral-100 border-neutral-300 dark:border-neutral-700",
|
|
33
102
|
icon: null,
|
|
34
103
|
},
|
|
35
104
|
success: {
|
|
@@ -39,7 +108,8 @@ const variantStyles: Record<
|
|
|
39
108
|
description: "text-emerald-800 dark:text-emerald-200/90",
|
|
40
109
|
progress: "bg-emerald-600 dark:bg-emerald-400",
|
|
41
110
|
iconColor: "text-emerald-600 dark:text-emerald-400",
|
|
42
|
-
badge:
|
|
111
|
+
badge:
|
|
112
|
+
"bg-emerald-100 text-emerald-900 dark:bg-emerald-900/80 dark:text-emerald-100 border-emerald-300 dark:border-emerald-700",
|
|
43
113
|
icon: CheckCircle2,
|
|
44
114
|
},
|
|
45
115
|
error: {
|
|
@@ -49,7 +119,8 @@ const variantStyles: Record<
|
|
|
49
119
|
description: "text-red-800 dark:text-red-200/90",
|
|
50
120
|
progress: "bg-destructive dark:bg-red-400",
|
|
51
121
|
iconColor: "text-red-600 dark:text-red-400",
|
|
52
|
-
badge:
|
|
122
|
+
badge:
|
|
123
|
+
"bg-red-100 text-red-900 dark:bg-red-900/80 dark:text-red-100 border-red-300 dark:border-red-700",
|
|
53
124
|
icon: AlertCircle,
|
|
54
125
|
},
|
|
55
126
|
warning: {
|
|
@@ -59,7 +130,8 @@ const variantStyles: Record<
|
|
|
59
130
|
description: "text-amber-800 dark:text-amber-200/90",
|
|
60
131
|
progress: "bg-amber-600 dark:bg-amber-400",
|
|
61
132
|
iconColor: "text-amber-600 dark:text-amber-400",
|
|
62
|
-
badge:
|
|
133
|
+
badge:
|
|
134
|
+
"bg-amber-100 text-amber-900 dark:bg-amber-900/80 dark:text-amber-100 border-amber-300 dark:border-amber-700",
|
|
63
135
|
icon: AlertTriangle,
|
|
64
136
|
},
|
|
65
137
|
info: {
|
|
@@ -69,7 +141,8 @@ const variantStyles: Record<
|
|
|
69
141
|
description: "text-sky-800 dark:text-sky-200/90",
|
|
70
142
|
progress: "bg-primary dark:bg-sky-400",
|
|
71
143
|
iconColor: "text-sky-600 dark:text-sky-400",
|
|
72
|
-
badge:
|
|
144
|
+
badge:
|
|
145
|
+
"bg-sky-100 text-sky-900 dark:bg-sky-900/80 dark:text-sky-100 border-sky-300 dark:border-sky-700",
|
|
73
146
|
icon: Info,
|
|
74
147
|
},
|
|
75
148
|
loading: {
|
|
@@ -79,11 +152,255 @@ const variantStyles: Record<
|
|
|
79
152
|
description: "text-neutral-600 dark:text-neutral-200",
|
|
80
153
|
progress: "bg-primary dark:bg-sky-400",
|
|
81
154
|
iconColor: "text-primary dark:text-sky-400 animate-spin",
|
|
82
|
-
badge:
|
|
155
|
+
badge:
|
|
156
|
+
"bg-neutral-200 text-neutral-800 dark:bg-neutral-800 dark:text-neutral-100 border-neutral-300 dark:border-neutral-700",
|
|
83
157
|
icon: Loader2,
|
|
84
158
|
},
|
|
85
159
|
};
|
|
86
160
|
|
|
161
|
+
// =============================================================================
|
|
162
|
+
// STATE STORE & ENGINE
|
|
163
|
+
// =============================================================================
|
|
164
|
+
|
|
165
|
+
const TOAST_LIMIT = 5;
|
|
166
|
+
const DEFAULT_MAX_COUNT = 5;
|
|
167
|
+
const TOAST_REMOVE_DELAY = 0;
|
|
168
|
+
|
|
169
|
+
type Action =
|
|
170
|
+
| { type: "ADD_TOAST"; toast: ToastItem }
|
|
171
|
+
| { type: "UPDATE_TOAST"; toast: Partial<ToastItem> }
|
|
172
|
+
| { type: "DISMISS_TOAST"; toastId?: string }
|
|
173
|
+
| { type: "REMOVE_TOAST"; toastId?: string };
|
|
174
|
+
|
|
175
|
+
interface State {
|
|
176
|
+
toasts: ToastItem[];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function genId(): string {
|
|
180
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
181
|
+
return crypto.randomUUID();
|
|
182
|
+
}
|
|
183
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const toastTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
|
|
187
|
+
|
|
188
|
+
const addToRemoveQueue = (toastId: string) => {
|
|
189
|
+
if (toastTimeouts.has(toastId)) return;
|
|
190
|
+
|
|
191
|
+
const timeout = setTimeout(() => {
|
|
192
|
+
toastTimeouts.delete(toastId);
|
|
193
|
+
dispatch({ type: "REMOVE_TOAST", toastId });
|
|
194
|
+
}, TOAST_REMOVE_DELAY);
|
|
195
|
+
|
|
196
|
+
toastTimeouts.set(toastId, timeout);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
export const reducer = (state: State, action: Action): State => {
|
|
200
|
+
switch (action.type) {
|
|
201
|
+
case "ADD_TOAST": {
|
|
202
|
+
const existingByIdIndex = state.toasts.findIndex((t) => t.id === action.toast.id);
|
|
203
|
+
|
|
204
|
+
if (existingByIdIndex !== -1) {
|
|
205
|
+
return {
|
|
206
|
+
...state,
|
|
207
|
+
toasts: state.toasts.map((t) =>
|
|
208
|
+
t.id === action.toast.id ? { ...t, ...action.toast, open: true } : t
|
|
209
|
+
),
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const existingIndex = state.toasts.findIndex(
|
|
214
|
+
(t) =>
|
|
215
|
+
t.open &&
|
|
216
|
+
t.title === action.toast.title &&
|
|
217
|
+
t.description === action.toast.description &&
|
|
218
|
+
(t.variant || "default") === (action.toast.variant || "default")
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
if (existingIndex !== -1) {
|
|
222
|
+
const existing = state.toasts[existingIndex];
|
|
223
|
+
const maxLimit = existing.maxCount ?? action.toast.maxCount ?? DEFAULT_MAX_COUNT;
|
|
224
|
+
const newCount = Math.min(existing.count + 1, maxLimit);
|
|
225
|
+
const maxReached = existing.count + 1 >= maxLimit;
|
|
226
|
+
|
|
227
|
+
const updatedToast: ToastItem = {
|
|
228
|
+
...existing,
|
|
229
|
+
...action.toast,
|
|
230
|
+
id: existing.id,
|
|
231
|
+
count: newCount,
|
|
232
|
+
maxReached,
|
|
233
|
+
open: true,
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const rest = state.toasts.filter((t) => t.id !== existing.id);
|
|
237
|
+
return {
|
|
238
|
+
...state,
|
|
239
|
+
toasts: [updatedToast, ...rest].slice(0, TOAST_LIMIT),
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
...state,
|
|
245
|
+
toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
case "UPDATE_TOAST":
|
|
250
|
+
return {
|
|
251
|
+
...state,
|
|
252
|
+
toasts: state.toasts.map((t) =>
|
|
253
|
+
t.id === action.toast.id ? { ...t, ...action.toast } : t
|
|
254
|
+
),
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
case "DISMISS_TOAST": {
|
|
258
|
+
const { toastId } = action;
|
|
259
|
+
|
|
260
|
+
if (toastId) {
|
|
261
|
+
addToRemoveQueue(toastId);
|
|
262
|
+
} else {
|
|
263
|
+
state.toasts.forEach((t) => addToRemoveQueue(t.id));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return {
|
|
267
|
+
...state,
|
|
268
|
+
toasts: state.toasts.map((t) =>
|
|
269
|
+
t.id === toastId || toastId === undefined ? { ...t, open: false } : t
|
|
270
|
+
),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
case "REMOVE_TOAST":
|
|
275
|
+
if (action.toastId === undefined) return { ...state, toasts: [] };
|
|
276
|
+
return {
|
|
277
|
+
...state,
|
|
278
|
+
toasts: state.toasts.filter((t) => t.id !== action.toastId),
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
default:
|
|
282
|
+
return state;
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const listeners: Array<(state: State) => void> = [];
|
|
287
|
+
let memoryState: State = { toasts: [] };
|
|
288
|
+
|
|
289
|
+
function dispatch(action: Action) {
|
|
290
|
+
memoryState = reducer(memoryState, action);
|
|
291
|
+
listeners.forEach((listener) => listener(memoryState));
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// =============================================================================
|
|
295
|
+
// DISPATCHER API & CONVENIENCE METHODS
|
|
296
|
+
// =============================================================================
|
|
297
|
+
|
|
298
|
+
export function toast(props: ToastOptions) {
|
|
299
|
+
const id = props.id || genId();
|
|
300
|
+
|
|
301
|
+
const update = (updatedProps: ToastOptions) =>
|
|
302
|
+
dispatch({ type: "UPDATE_TOAST", toast: { ...updatedProps, id } });
|
|
303
|
+
|
|
304
|
+
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
|
|
305
|
+
|
|
306
|
+
dispatch({
|
|
307
|
+
type: "ADD_TOAST",
|
|
308
|
+
toast: {
|
|
309
|
+
...props,
|
|
310
|
+
id,
|
|
311
|
+
open: true,
|
|
312
|
+
count: 1,
|
|
313
|
+
maxReached: false,
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
return { id, dismiss, update };
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
toast.success = (title: React.ReactNode, options?: Omit<ToastOptions, "title" | "variant">) =>
|
|
321
|
+
toast({ ...options, title, variant: "success" });
|
|
322
|
+
|
|
323
|
+
toast.error = (title: React.ReactNode, options?: Omit<ToastOptions, "title" | "variant">) =>
|
|
324
|
+
toast({ ...options, title, variant: "error" });
|
|
325
|
+
|
|
326
|
+
toast.warning = (title: React.ReactNode, options?: Omit<ToastOptions, "title" | "variant">) =>
|
|
327
|
+
toast({ ...options, title, variant: "warning" });
|
|
328
|
+
|
|
329
|
+
toast.info = (title: React.ReactNode, options?: Omit<ToastOptions, "title" | "variant">) =>
|
|
330
|
+
toast({ ...options, title, variant: "info" });
|
|
331
|
+
|
|
332
|
+
toast.loading = (title: React.ReactNode, options?: Omit<ToastOptions, "title" | "variant">) =>
|
|
333
|
+
toast({ ...options, title, variant: "loading", duration: 0 });
|
|
334
|
+
|
|
335
|
+
toast.dismiss = (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId });
|
|
336
|
+
|
|
337
|
+
toast.promise = <T,>(
|
|
338
|
+
promise: Promise<T> | (() => Promise<T>),
|
|
339
|
+
msgs: {
|
|
340
|
+
loading: React.ReactNode;
|
|
341
|
+
success: React.ReactNode | ((data: T) => React.ReactNode);
|
|
342
|
+
error: React.ReactNode | ((err: unknown) => React.ReactNode);
|
|
343
|
+
},
|
|
344
|
+
options?: ToastOptions
|
|
345
|
+
) => {
|
|
346
|
+
const instance = toast({
|
|
347
|
+
...options,
|
|
348
|
+
variant: "loading",
|
|
349
|
+
title: msgs.loading,
|
|
350
|
+
duration: 0,
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
const promiseFn = typeof promise === "function" ? promise() : promise;
|
|
354
|
+
|
|
355
|
+
promiseFn
|
|
356
|
+
.then((data) => {
|
|
357
|
+
const successTitle = typeof msgs.success === "function" ? msgs.success(data) : msgs.success;
|
|
358
|
+
toast.success(successTitle, {
|
|
359
|
+
...options,
|
|
360
|
+
id: instance.id,
|
|
361
|
+
duration: options?.duration ?? 4000,
|
|
362
|
+
});
|
|
363
|
+
})
|
|
364
|
+
.catch((err: unknown) => {
|
|
365
|
+
const errorTitle = typeof msgs.error === "function" ? msgs.error(err) : msgs.error;
|
|
366
|
+
toast.error(errorTitle, {
|
|
367
|
+
...options,
|
|
368
|
+
id: instance.id,
|
|
369
|
+
duration: options?.duration ?? 5000,
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
return promiseFn;
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
// =============================================================================
|
|
377
|
+
// REACT CONSUMER HOOK
|
|
378
|
+
// =============================================================================
|
|
379
|
+
|
|
380
|
+
export function useToast() {
|
|
381
|
+
const [state, setState] = React.useState<State>(memoryState);
|
|
382
|
+
|
|
383
|
+
React.useEffect(() => {
|
|
384
|
+
listeners.push(setState);
|
|
385
|
+
return () => {
|
|
386
|
+
const index = listeners.indexOf(setState);
|
|
387
|
+
if (index > -1) {
|
|
388
|
+
listeners.splice(index, 1);
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
}, []);
|
|
392
|
+
|
|
393
|
+
return {
|
|
394
|
+
...state,
|
|
395
|
+
toast,
|
|
396
|
+
dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }),
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// =============================================================================
|
|
401
|
+
// UI COMPONENTS (TOASTER & TOAST ELEMENT)
|
|
402
|
+
// =============================================================================
|
|
403
|
+
|
|
87
404
|
export function Toaster({ defaultDuration = 4000, position = "top-center" }: ToasterProps) {
|
|
88
405
|
const { toasts, dismiss } = useToast();
|
|
89
406
|
|
|
@@ -100,52 +417,26 @@ export function Toaster({ defaultDuration = 4000, position = "top-center" }: Toa
|
|
|
100
417
|
<>
|
|
101
418
|
<style>{`
|
|
102
419
|
@keyframes toast-progress {
|
|
103
|
-
from {
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
to {
|
|
107
|
-
transform: scaleX(0);
|
|
108
|
-
}
|
|
420
|
+
from { transform: scaleX(1); }
|
|
421
|
+
to { transform: scaleX(0); }
|
|
109
422
|
}
|
|
110
423
|
@keyframes toast-expand {
|
|
111
|
-
from {
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
to {
|
|
115
|
-
grid-template-rows: 1fr;
|
|
116
|
-
}
|
|
424
|
+
from { grid-template-rows: 0fr; }
|
|
425
|
+
to { grid-template-rows: 1fr; }
|
|
117
426
|
}
|
|
118
427
|
@keyframes toast-fade-in {
|
|
119
|
-
from {
|
|
120
|
-
|
|
121
|
-
transform: translateY(-4px);
|
|
122
|
-
}
|
|
123
|
-
to {
|
|
124
|
-
opacity: 1;
|
|
125
|
-
transform: translateY(0);
|
|
126
|
-
}
|
|
428
|
+
from { opacity: 0; transform: translateY(-4px); }
|
|
429
|
+
to { opacity: 1; transform: translateY(0); }
|
|
127
430
|
}
|
|
128
431
|
@keyframes toast-pop {
|
|
129
|
-
0% {
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
50% {
|
|
133
|
-
transform: scale(1.2);
|
|
134
|
-
}
|
|
135
|
-
100% {
|
|
136
|
-
transform: scale(1);
|
|
137
|
-
}
|
|
432
|
+
0% { transform: scale(0.6); }
|
|
433
|
+
50% { transform: scale(1.2); }
|
|
434
|
+
100% { transform: scale(1); }
|
|
138
435
|
}
|
|
139
436
|
@keyframes toast-shake {
|
|
140
|
-
0%, 100% {
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
25% {
|
|
144
|
-
transform: translateX(-2px);
|
|
145
|
-
}
|
|
146
|
-
75% {
|
|
147
|
-
transform: translateX(2px);
|
|
148
|
-
}
|
|
437
|
+
0%, 100% { transform: translateX(0); }
|
|
438
|
+
25% { transform: translateX(-2px); }
|
|
439
|
+
75% { transform: translateX(2px); }
|
|
149
440
|
}
|
|
150
441
|
`}</style>
|
|
151
442
|
|
|
@@ -223,7 +514,6 @@ function ToastElement({
|
|
|
223
514
|
if (toast.customColor?.border) customInlineStyle.borderColor = toast.customColor.border;
|
|
224
515
|
if (toast.customColor?.text) customInlineStyle.color = toast.customColor.text;
|
|
225
516
|
|
|
226
|
-
// Check if custom colors or custom tailwind classes exist
|
|
227
517
|
const userHasBg = Boolean(toast.customColor?.bg || toast.className?.match(/(?:^|\s)bg-/));
|
|
228
518
|
const userHasBorder = Boolean(toast.customColor?.border || toast.className?.match(/(?:^|\s)border-/));
|
|
229
519
|
const userHasText = Boolean(toast.customColor?.text || toast.className?.match(/(?:^|\s)text-/));
|
|
@@ -317,7 +607,7 @@ function ToastElement({
|
|
|
317
607
|
<X className="w-4 h-4" />
|
|
318
608
|
</button>
|
|
319
609
|
|
|
320
|
-
{/* Progress Bar
|
|
610
|
+
{/* Progress Bar */}
|
|
321
611
|
{showProgress && isAutoDismissible && (
|
|
322
612
|
<div
|
|
323
613
|
key={`${toast.id}-${toast.variant}-${toast.count}`}
|
|
@@ -333,4 +623,4 @@ function ToastElement({
|
|
|
333
623
|
)}
|
|
334
624
|
</div>
|
|
335
625
|
);
|
|
336
|
-
}
|
|
626
|
+
}
|