@choice-ui/react 1.6.8 → 1.7.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/dist/components/description/dist/index.d.ts +8 -0
- package/dist/components/description/dist/index.js +29 -0
- package/dist/components/description/src/description.d.ts +6 -0
- package/dist/components/description/src/description.js +18 -0
- package/dist/components/description/src/index.d.ts +2 -0
- package/dist/components/description/src/tv.d.ts +13 -0
- package/dist/components/description/src/tv.js +15 -0
- package/dist/components/description/tsup.config.d.ts +2 -0
- package/dist/components/emoji-picker/dist/index.d.ts +1 -0
- package/dist/components/emoji-picker/dist/index.js +4 -2
- package/dist/components/emoji-picker/src/emoji-picker.d.ts +1 -0
- package/dist/components/emoji-picker/src/emoji-picker.js +4 -2
- package/dist/components/error-message/dist/index.d.ts +8 -0
- package/dist/components/error-message/dist/index.js +30 -0
- package/dist/components/error-message/src/error-message.d.ts +6 -0
- package/dist/components/error-message/src/error-message.js +19 -0
- package/dist/components/error-message/src/index.d.ts +2 -0
- package/dist/components/error-message/src/tv.d.ts +13 -0
- package/dist/components/error-message/src/tv.js +15 -0
- package/dist/components/error-message/tsup.config.d.ts +2 -0
- package/dist/components/form/src/adapters/base-adapter.js +4 -2
- package/dist/components/form/src/tv.d.ts +0 -12
- package/dist/components/form/src/tv.js +1 -13
- package/dist/components/index.d.ts +3 -0
- package/dist/components/md-render/dist/index.d.ts +2 -1
- package/dist/components/md-render/dist/index.js +3 -1
- package/dist/components/md-render/src/md-render.js +3 -1
- package/dist/components/md-render/src/types.d.ts +2 -1
- package/dist/components/notifications/dist/index.d.ts +1 -5
- package/dist/components/notifications/src/notifications.d.ts +0 -1
- package/dist/components/notifications/src/notifications.js +0 -1
- package/dist/components/numeric-input/dist/index.d.ts +23 -9
- package/dist/components/numeric-input/dist/index.js +26 -3
- package/dist/components/numeric-input/src/components/numeric-input-menu-trigger.js +4 -1
- package/dist/components/numeric-input/src/hooks/index.d.ts +1 -0
- package/dist/components/numeric-input/src/hooks/use-numeric-long-press.d.ts +13 -0
- package/dist/components/numeric-input/src/hooks/use-numeric-long-press.js +27 -0
- package/dist/components/numeric-input/src/index.d.ts +1 -0
- package/dist/components/numeric-input/src/tv.js +22 -2
- package/dist/components/picture-preview/dist/index.d.ts +5 -0
- package/dist/components/picture-preview/dist/index.js +287 -140
- package/dist/components/picture-preview/src/hooks/useWheelHandler.d.ts +6 -1
- package/dist/components/picture-preview/src/hooks/useWheelHandler.js +25 -7
- package/dist/components/picture-preview/src/picture-preview.d.ts +5 -0
- package/dist/components/picture-preview/src/picture-preview.js +214 -123
- package/dist/components/picture-preview/src/tv.d.ts +93 -3
- package/dist/components/picture-preview/src/tv.js +48 -10
- package/dist/components/separator/dist/index.d.ts +1 -8
- package/dist/components/separator/src/separator.d.ts +1 -8
- package/dist/components/separator/src/separator.js +33 -5
- package/dist/components/separator/src/tv.d.ts +39 -18
- package/dist/components/separator/src/tv.js +37 -7
- package/dist/components/text-field/dist/index.d.ts +2 -3
- package/dist/components/text-field/dist/index.js +4 -19
- package/dist/components/text-field/src/components/index.d.ts +0 -1
- package/dist/components/text-field/src/text-field.d.ts +3 -2
- package/dist/components/text-field/src/text-field.js +2 -2
- package/dist/components/text-field/src/tv.d.ts +3 -3
- package/dist/components/text-field/src/tv.js +1 -6
- package/dist/components/toast/dist/index.d.ts +260 -0
- package/dist/components/toast/src/components/index.d.ts +3 -0
- package/dist/components/toast/src/components/toast-progress-bar.d.ts +7 -0
- package/dist/components/toast/src/components/toast-progress-bar.js +53 -0
- package/dist/components/toast/src/components/toaster-item.d.ts +26 -0
- package/dist/components/toast/src/components/toaster-item.js +412 -0
- package/dist/components/toast/src/components/toaster-slots.d.ts +87 -0
- package/dist/components/toast/src/components/toaster-slots.js +38 -0
- package/dist/components/toast/src/index.d.ts +5 -0
- package/dist/components/toast/src/store.d.ts +113 -0
- package/dist/components/toast/src/store.js +204 -0
- package/dist/components/toast/src/toaster.d.ts +87 -0
- package/dist/components/toast/src/toaster.js +271 -0
- package/dist/components/toast/src/tv.d.ts +365 -0
- package/dist/components/toast/src/tv.js +412 -0
- package/dist/components/toast/src/types.d.ts +79 -0
- package/dist/components/toast/tsup.config.d.ts +2 -0
- package/dist/index.js +11 -2
- package/dist/styles/components.css +2 -0
- package/package.json +1 -1
- package/dist/components/text-field/src/components/field-description.d.ts +0 -2
- package/dist/components/text-field/src/components/field-description.js +0 -16
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { RemoveSmall, LoaderCircle, CircleInfoLargeSolid, CircleWarningLargeSolid, CircleErrorSolid, CircleCheckLargeSolid } from "@choiceform/icons-react";
|
|
3
|
+
import { motion } from "framer-motion";
|
|
4
|
+
import { memo, forwardRef, useId, useRef, useState, useMemo, useEffect } from "react";
|
|
5
|
+
import { useEventCallback } from "usehooks-ts";
|
|
6
|
+
import { dismiss, updateHeight } from "../store.js";
|
|
7
|
+
import { toastRootTv } from "../tv.js";
|
|
8
|
+
import { ToastProgressBar } from "./toast-progress-bar.js";
|
|
9
|
+
import { tcx } from "../../../../shared/utils/tcx/tcx.js";
|
|
10
|
+
import { mergeRefs } from "../../../../shared/utils/merge-refs/merge-refs.js";
|
|
11
|
+
const GAP = 12;
|
|
12
|
+
const DEFAULT_HEIGHT = 56;
|
|
13
|
+
const SWIPE_THRESHOLD = 56;
|
|
14
|
+
const ANIMATION_CONFIG = {
|
|
15
|
+
default: {
|
|
16
|
+
type: "spring",
|
|
17
|
+
stiffness: 150,
|
|
18
|
+
damping: 20,
|
|
19
|
+
mass: 1
|
|
20
|
+
},
|
|
21
|
+
opacity: {
|
|
22
|
+
type: "tween",
|
|
23
|
+
duration: 0.35,
|
|
24
|
+
ease: "easeOut"
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const SuccessIcon = memo(() => /* @__PURE__ */ jsx(CircleCheckLargeSolid, {}));
|
|
28
|
+
SuccessIcon.displayName = "SuccessIcon";
|
|
29
|
+
const ErrorIcon = memo(() => /* @__PURE__ */ jsx(CircleErrorSolid, {}));
|
|
30
|
+
ErrorIcon.displayName = "ErrorIcon";
|
|
31
|
+
const WarningIcon = memo(() => /* @__PURE__ */ jsx(CircleWarningLargeSolid, {}));
|
|
32
|
+
WarningIcon.displayName = "WarningIcon";
|
|
33
|
+
const InfoIcon = memo(() => /* @__PURE__ */ jsx(CircleInfoLargeSolid, {}));
|
|
34
|
+
InfoIcon.displayName = "InfoIcon";
|
|
35
|
+
const LoadingIcon = memo(() => /* @__PURE__ */ jsx(LoaderCircle, { className: "animate-spin" }));
|
|
36
|
+
LoadingIcon.displayName = "LoadingIcon";
|
|
37
|
+
const TOAST_ICONS = {
|
|
38
|
+
success: /* @__PURE__ */ jsx(SuccessIcon, {}),
|
|
39
|
+
error: /* @__PURE__ */ jsx(ErrorIcon, {}),
|
|
40
|
+
warning: /* @__PURE__ */ jsx(WarningIcon, {}),
|
|
41
|
+
info: /* @__PURE__ */ jsx(InfoIcon, {}),
|
|
42
|
+
loading: /* @__PURE__ */ jsx(LoadingIcon, {}),
|
|
43
|
+
default: null
|
|
44
|
+
};
|
|
45
|
+
function getToastIcon(type) {
|
|
46
|
+
return TOAST_ICONS[type] ?? null;
|
|
47
|
+
}
|
|
48
|
+
const HTML_TAG_REGEX = /<[a-z][\s\S]*>/i;
|
|
49
|
+
function isHtmlString(content) {
|
|
50
|
+
return typeof content === "string" && HTML_TAG_REGEX.test(content);
|
|
51
|
+
}
|
|
52
|
+
const ToasterItem = memo(
|
|
53
|
+
forwardRef(function ToasterItem2({
|
|
54
|
+
toast,
|
|
55
|
+
index,
|
|
56
|
+
total,
|
|
57
|
+
expanded,
|
|
58
|
+
position,
|
|
59
|
+
toasterId,
|
|
60
|
+
toastHeights,
|
|
61
|
+
slotProps,
|
|
62
|
+
showProgress = false,
|
|
63
|
+
defaultDuration = 5e3,
|
|
64
|
+
isPaused = false,
|
|
65
|
+
layout = "default"
|
|
66
|
+
}, ref) {
|
|
67
|
+
const titleId = useId();
|
|
68
|
+
const descriptionId = useId();
|
|
69
|
+
const rootRef = useRef(null);
|
|
70
|
+
const [isSwiping, setIsSwiping] = useState(false);
|
|
71
|
+
const [swipeOffset, setSwipeOffset] = useState({ x: 0, y: 0 });
|
|
72
|
+
const [swipeDirection, setSwipeDirection] = useState(null);
|
|
73
|
+
const swipeStartRef = useRef(null);
|
|
74
|
+
const toastDuration = toast.duration ?? defaultDuration;
|
|
75
|
+
const shouldShowProgress = showProgress && toastDuration > 0 && toast.type !== "loading";
|
|
76
|
+
const offsetY = useMemo(() => {
|
|
77
|
+
if (expanded) {
|
|
78
|
+
let offset = 0;
|
|
79
|
+
for (let i = 0; i < index; i++) {
|
|
80
|
+
offset += (toastHeights[i] ?? DEFAULT_HEIGHT) + GAP;
|
|
81
|
+
}
|
|
82
|
+
return offset;
|
|
83
|
+
}
|
|
84
|
+
return index * 8;
|
|
85
|
+
}, [expanded, index, toastHeights]);
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
const node = rootRef.current;
|
|
88
|
+
if (!node) return;
|
|
89
|
+
let rafId = null;
|
|
90
|
+
let lastHeight = 0;
|
|
91
|
+
const measureHeight = () => {
|
|
92
|
+
if (rafId !== null) {
|
|
93
|
+
cancelAnimationFrame(rafId);
|
|
94
|
+
}
|
|
95
|
+
rafId = requestAnimationFrame(() => {
|
|
96
|
+
const height = node.offsetHeight;
|
|
97
|
+
if (height > 0 && height !== lastHeight) {
|
|
98
|
+
lastHeight = height;
|
|
99
|
+
updateHeight(toast.id, height, toasterId);
|
|
100
|
+
}
|
|
101
|
+
rafId = null;
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
measureHeight();
|
|
105
|
+
const resizeObserver = new ResizeObserver(measureHeight);
|
|
106
|
+
resizeObserver.observe(node);
|
|
107
|
+
return () => {
|
|
108
|
+
resizeObserver.disconnect();
|
|
109
|
+
if (rafId !== null) {
|
|
110
|
+
cancelAnimationFrame(rafId);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}, [toast.id, toasterId]);
|
|
114
|
+
const close = useEventCallback((_direction) => {
|
|
115
|
+
dismiss(toast.id, toasterId);
|
|
116
|
+
});
|
|
117
|
+
const handleKeyDown = useEventCallback((e) => {
|
|
118
|
+
if (e.key === "Escape") {
|
|
119
|
+
e.preventDefault();
|
|
120
|
+
close();
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
const handlePointerDown = useEventCallback((e) => {
|
|
124
|
+
const target = e.target;
|
|
125
|
+
if (target.closest("button, a, input, [role='button']")) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
swipeStartRef.current = { x: e.clientX, y: e.clientY };
|
|
129
|
+
setSwipeDirection(null);
|
|
130
|
+
target.setPointerCapture(e.pointerId);
|
|
131
|
+
});
|
|
132
|
+
const handlePointerMove = useEventCallback((e) => {
|
|
133
|
+
if (!swipeStartRef.current) return;
|
|
134
|
+
const deltaX = e.clientX - swipeStartRef.current.x;
|
|
135
|
+
const deltaY = e.clientY - swipeStartRef.current.y;
|
|
136
|
+
const isVerticalPosition = position === "top-center" || position === "bottom-center";
|
|
137
|
+
if (isVerticalPosition) {
|
|
138
|
+
const absDeltaY = Math.abs(deltaY);
|
|
139
|
+
if (!isSwiping && absDeltaY > 10) {
|
|
140
|
+
setIsSwiping(true);
|
|
141
|
+
}
|
|
142
|
+
if (isSwiping) {
|
|
143
|
+
setSwipeDirection(deltaY > 0 ? "down" : "up");
|
|
144
|
+
setSwipeOffset({ x: 0, y: deltaY });
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
const absDeltaX = Math.abs(deltaX);
|
|
148
|
+
if (!isSwiping && absDeltaX > 10) {
|
|
149
|
+
setIsSwiping(true);
|
|
150
|
+
}
|
|
151
|
+
if (isSwiping) {
|
|
152
|
+
setSwipeDirection(deltaX > 0 ? "right" : "left");
|
|
153
|
+
setSwipeOffset({ x: deltaX, y: 0 });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
const handlePointerUp = useEventCallback((e) => {
|
|
158
|
+
if (!swipeStartRef.current) return;
|
|
159
|
+
const target = e.target;
|
|
160
|
+
target.releasePointerCapture(e.pointerId);
|
|
161
|
+
const isVerticalPosition = position === "top-center" || position === "bottom-center";
|
|
162
|
+
const swipeDistance = isVerticalPosition ? Math.abs(swipeOffset.y) : Math.abs(swipeOffset.x);
|
|
163
|
+
if (swipeDistance > SWIPE_THRESHOLD && swipeDirection) {
|
|
164
|
+
close(swipeDirection);
|
|
165
|
+
} else {
|
|
166
|
+
setSwipeOffset({ x: 0, y: 0 });
|
|
167
|
+
}
|
|
168
|
+
swipeStartRef.current = null;
|
|
169
|
+
setIsSwiping(false);
|
|
170
|
+
});
|
|
171
|
+
const handlePointerCancel = useEventCallback((e) => {
|
|
172
|
+
const target = e.target;
|
|
173
|
+
target.releasePointerCapture(e.pointerId);
|
|
174
|
+
swipeStartRef.current = null;
|
|
175
|
+
setIsSwiping(false);
|
|
176
|
+
setSwipeOffset({ x: 0, y: 0 });
|
|
177
|
+
setSwipeDirection(null);
|
|
178
|
+
});
|
|
179
|
+
const displayIcon = getToastIcon(toast.type);
|
|
180
|
+
const isBehind = index > 0 && !expanded;
|
|
181
|
+
const isTop = position.startsWith("top");
|
|
182
|
+
const scale = expanded ? 1 : Math.max(0, 1 - index * 0.05);
|
|
183
|
+
const yPosition = useMemo(() => {
|
|
184
|
+
const swipeY = swipeOffset.y;
|
|
185
|
+
if (expanded) {
|
|
186
|
+
return isTop ? offsetY + swipeY : -offsetY + swipeY;
|
|
187
|
+
}
|
|
188
|
+
const peek = 8;
|
|
189
|
+
const shrink = 1 - scale;
|
|
190
|
+
const height = toast.height || 0;
|
|
191
|
+
const peekOffset = index * peek;
|
|
192
|
+
const shrinkOffset = shrink * height;
|
|
193
|
+
return isTop ? peekOffset + shrinkOffset + swipeY : -(peekOffset + shrinkOffset) + swipeY;
|
|
194
|
+
}, [expanded, isTop, offsetY, swipeOffset.y, scale, toast.height, index]);
|
|
195
|
+
const stackOpacity = useMemo(() => {
|
|
196
|
+
if (expanded) return 1;
|
|
197
|
+
return Math.max(0, 1 - index * 0.2);
|
|
198
|
+
}, [expanded, index]);
|
|
199
|
+
const enterExitY = isTop ? -100 : 100;
|
|
200
|
+
const exitAnimation = useMemo(() => {
|
|
201
|
+
const dir = swipeDirection || toast.swipeDirection;
|
|
202
|
+
const exitBase = { opacity: 0, zIndex: -1, filter: "blur(4px)" };
|
|
203
|
+
if (dir === "right") return { ...exitBase, x: "100%" };
|
|
204
|
+
if (dir === "left") return { ...exitBase, x: "-100%" };
|
|
205
|
+
if (dir === "up") return { ...exitBase, y: "-100%" };
|
|
206
|
+
if (dir === "down") return { ...exitBase, y: "100%" };
|
|
207
|
+
return exitBase;
|
|
208
|
+
}, [swipeDirection, toast.swipeDirection]);
|
|
209
|
+
const tv = useMemo(
|
|
210
|
+
() => toastRootTv({
|
|
211
|
+
layout,
|
|
212
|
+
type: toast.type,
|
|
213
|
+
position,
|
|
214
|
+
hasActions: !!toast.action || !!toast.cancel,
|
|
215
|
+
hasDescription: !!toast.description,
|
|
216
|
+
hasIcon: !!displayIcon,
|
|
217
|
+
behind: isBehind,
|
|
218
|
+
expanded,
|
|
219
|
+
variant: toast.variant
|
|
220
|
+
}),
|
|
221
|
+
[
|
|
222
|
+
layout,
|
|
223
|
+
toast.type,
|
|
224
|
+
position,
|
|
225
|
+
toast.action,
|
|
226
|
+
toast.cancel,
|
|
227
|
+
toast.description,
|
|
228
|
+
displayIcon,
|
|
229
|
+
isBehind,
|
|
230
|
+
expanded,
|
|
231
|
+
toast.variant
|
|
232
|
+
]
|
|
233
|
+
);
|
|
234
|
+
const zIndex = total - index;
|
|
235
|
+
const compactProgress = layout === "compact" && shouldShowProgress;
|
|
236
|
+
const combinedStyle = useMemo(() => {
|
|
237
|
+
const backgroundColorMap = compactProgress ? {
|
|
238
|
+
default: "var(--color-gray-800)",
|
|
239
|
+
accent: "var(--color-accent-hover-background)",
|
|
240
|
+
success: "var(--color-success-hover-background)",
|
|
241
|
+
warning: "var(--color-warning-hover-background)",
|
|
242
|
+
error: "var(--color-danger-hover-background)",
|
|
243
|
+
assistive: "var(--color-assistive-hover-background)"
|
|
244
|
+
} : {
|
|
245
|
+
default: "var(--color-menu-background)",
|
|
246
|
+
accent: "var(--color-accent-background)",
|
|
247
|
+
success: "var(--color-success-background)",
|
|
248
|
+
warning: "var(--color-warning-background)",
|
|
249
|
+
error: "var(--color-danger-background)",
|
|
250
|
+
assistive: "var(--color-assistive-background)"
|
|
251
|
+
};
|
|
252
|
+
const bgColor = backgroundColorMap[toast.variant ?? "default"] ?? "var(--color-menu-background)";
|
|
253
|
+
return {
|
|
254
|
+
"--toast-index": index,
|
|
255
|
+
"--toast-opacity": `${stackOpacity * 100}%`,
|
|
256
|
+
"--toast-background-color": `color-mix(in srgb, ${bgColor} var(--toast-opacity), var(--color-default-background))`,
|
|
257
|
+
"--toast-gap": `${GAP}px`,
|
|
258
|
+
zIndex
|
|
259
|
+
};
|
|
260
|
+
}, [index, stackOpacity, zIndex, compactProgress, toast.variant]);
|
|
261
|
+
const handleActionClick = useEventCallback(() => {
|
|
262
|
+
var _a;
|
|
263
|
+
(_a = toast.action) == null ? void 0 : _a.onClick();
|
|
264
|
+
close();
|
|
265
|
+
});
|
|
266
|
+
const handleDismissClick = useEventCallback(() => {
|
|
267
|
+
close();
|
|
268
|
+
});
|
|
269
|
+
const { renderIcon, renderActions } = slotProps;
|
|
270
|
+
const iconContent = useMemo(() => {
|
|
271
|
+
if (renderIcon) {
|
|
272
|
+
return renderIcon(toast.type, displayIcon);
|
|
273
|
+
}
|
|
274
|
+
return displayIcon;
|
|
275
|
+
}, [renderIcon, toast.type, displayIcon]);
|
|
276
|
+
const titleContent = useMemo(() => {
|
|
277
|
+
if (!toast.title) return null;
|
|
278
|
+
return /* @__PURE__ */ jsx(
|
|
279
|
+
"div",
|
|
280
|
+
{
|
|
281
|
+
id: titleId,
|
|
282
|
+
className: tcx(tv.title(), slotProps.titleClassName),
|
|
283
|
+
style: slotProps.titleStyle,
|
|
284
|
+
...isHtmlString(toast.title) ? { dangerouslySetInnerHTML: { __html: toast.title } } : { children: toast.title }
|
|
285
|
+
}
|
|
286
|
+
);
|
|
287
|
+
}, [toast.title, titleId, tv, slotProps.titleClassName, slotProps.titleStyle]);
|
|
288
|
+
const descriptionContent = useMemo(() => {
|
|
289
|
+
if (!toast.description) return null;
|
|
290
|
+
return /* @__PURE__ */ jsx(
|
|
291
|
+
"div",
|
|
292
|
+
{
|
|
293
|
+
id: descriptionId,
|
|
294
|
+
className: tcx(tv.description(), slotProps.descriptionClassName),
|
|
295
|
+
style: slotProps.descriptionStyle,
|
|
296
|
+
...isHtmlString(toast.description) ? { dangerouslySetInnerHTML: { __html: toast.description } } : { children: toast.description }
|
|
297
|
+
}
|
|
298
|
+
);
|
|
299
|
+
}, [toast.description, descriptionId, tv, slotProps.descriptionClassName, slotProps.descriptionStyle]);
|
|
300
|
+
const actionsContent = useMemo(() => {
|
|
301
|
+
var _a;
|
|
302
|
+
if (!toast.action && !toast.cancel) return null;
|
|
303
|
+
if (renderActions) {
|
|
304
|
+
return renderActions(toast.action, toast.cancel, close);
|
|
305
|
+
}
|
|
306
|
+
return /* @__PURE__ */ jsxs(
|
|
307
|
+
"div",
|
|
308
|
+
{
|
|
309
|
+
className: tcx(tv.actions(), slotProps.actionsClassName),
|
|
310
|
+
style: slotProps.actionsStyle,
|
|
311
|
+
children: [
|
|
312
|
+
toast.action && /* @__PURE__ */ jsx(
|
|
313
|
+
"button",
|
|
314
|
+
{
|
|
315
|
+
type: "button",
|
|
316
|
+
className: tv.button({ buttonVariant: "action" }),
|
|
317
|
+
onClick: handleActionClick,
|
|
318
|
+
children: toast.action.label
|
|
319
|
+
}
|
|
320
|
+
),
|
|
321
|
+
toast.cancel && /* @__PURE__ */ jsx(
|
|
322
|
+
"button",
|
|
323
|
+
{
|
|
324
|
+
type: "button",
|
|
325
|
+
className: tcx(tv.button({ buttonVariant: "cancel" })),
|
|
326
|
+
onClick: handleDismissClick,
|
|
327
|
+
children: layout === "default" ? (_a = toast.cancel) == null ? void 0 : _a.label : /* @__PURE__ */ jsx(RemoveSmall, {})
|
|
328
|
+
}
|
|
329
|
+
)
|
|
330
|
+
]
|
|
331
|
+
}
|
|
332
|
+
);
|
|
333
|
+
}, [
|
|
334
|
+
renderActions,
|
|
335
|
+
toast.action,
|
|
336
|
+
toast.cancel,
|
|
337
|
+
close,
|
|
338
|
+
tv,
|
|
339
|
+
handleActionClick,
|
|
340
|
+
handleDismissClick,
|
|
341
|
+
slotProps.actionsClassName,
|
|
342
|
+
slotProps.actionsStyle
|
|
343
|
+
]);
|
|
344
|
+
const mergedClassName = tcx(tv.root(), slotProps.itemClassName);
|
|
345
|
+
const mergedStyle = useMemo(() => {
|
|
346
|
+
if (slotProps.itemStyle) {
|
|
347
|
+
return { ...combinedStyle, ...slotProps.itemStyle };
|
|
348
|
+
}
|
|
349
|
+
return combinedStyle;
|
|
350
|
+
}, [combinedStyle, slotProps.itemStyle]);
|
|
351
|
+
return /* @__PURE__ */ jsxs(
|
|
352
|
+
motion.div,
|
|
353
|
+
{
|
|
354
|
+
ref: mergeRefs(rootRef, ref),
|
|
355
|
+
initial: { y: enterExitY },
|
|
356
|
+
animate: {
|
|
357
|
+
x: swipeOffset.x,
|
|
358
|
+
y: yPosition,
|
|
359
|
+
scale,
|
|
360
|
+
opacity: 1,
|
|
361
|
+
filter: "blur(0px)"
|
|
362
|
+
},
|
|
363
|
+
exit: exitAnimation,
|
|
364
|
+
transition: isSwiping ? { duration: 0 } : ANIMATION_CONFIG,
|
|
365
|
+
role: toast.type === "error" || toast.type === "warning" ? "alertdialog" : "status",
|
|
366
|
+
"aria-modal": "false",
|
|
367
|
+
"aria-labelledby": toast.title ? titleId : void 0,
|
|
368
|
+
"aria-describedby": toast.description ? descriptionId : void 0,
|
|
369
|
+
"aria-live": toast.type === "error" ? "assertive" : "polite",
|
|
370
|
+
tabIndex: 0,
|
|
371
|
+
"data-toast-root": true,
|
|
372
|
+
"data-type": toast.type,
|
|
373
|
+
className: mergedClassName,
|
|
374
|
+
style: mergedStyle,
|
|
375
|
+
onKeyDown: handleKeyDown,
|
|
376
|
+
onPointerDown: handlePointerDown,
|
|
377
|
+
onPointerMove: handlePointerMove,
|
|
378
|
+
onPointerUp: handlePointerUp,
|
|
379
|
+
onPointerCancel: handlePointerCancel,
|
|
380
|
+
children: [
|
|
381
|
+
/* @__PURE__ */ jsxs("div", { className: tv.content(), children: [
|
|
382
|
+
iconContent && /* @__PURE__ */ jsx(
|
|
383
|
+
"div",
|
|
384
|
+
{
|
|
385
|
+
className: tcx(tv.icon(), slotProps.iconClassName),
|
|
386
|
+
style: slotProps.iconStyle,
|
|
387
|
+
children: iconContent
|
|
388
|
+
}
|
|
389
|
+
),
|
|
390
|
+
titleContent,
|
|
391
|
+
layout === "default" && descriptionContent,
|
|
392
|
+
shouldShowProgress && /* @__PURE__ */ jsx(
|
|
393
|
+
ToastProgressBar,
|
|
394
|
+
{
|
|
395
|
+
duration: toastDuration,
|
|
396
|
+
isPaused,
|
|
397
|
+
tv
|
|
398
|
+
}
|
|
399
|
+
)
|
|
400
|
+
] }),
|
|
401
|
+
actionsContent
|
|
402
|
+
]
|
|
403
|
+
}
|
|
404
|
+
);
|
|
405
|
+
})
|
|
406
|
+
);
|
|
407
|
+
ToasterItem.displayName = "ToasterItem";
|
|
408
|
+
export {
|
|
409
|
+
DEFAULT_HEIGHT,
|
|
410
|
+
GAP,
|
|
411
|
+
ToasterItem
|
|
412
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ToastType } from '../types';
|
|
3
|
+
export interface ToastAction {
|
|
4
|
+
label: ReactNode;
|
|
5
|
+
onClick: () => void;
|
|
6
|
+
}
|
|
7
|
+
export interface ToastCancel {
|
|
8
|
+
label: ReactNode;
|
|
9
|
+
onClick?: () => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Props for Toaster.Item slot component
|
|
13
|
+
*/
|
|
14
|
+
export interface ToasterItemSlotProps {
|
|
15
|
+
className?: string;
|
|
16
|
+
style?: React.CSSProperties;
|
|
17
|
+
children?: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Slot component for customizing toast item container
|
|
21
|
+
*/
|
|
22
|
+
export declare const ToasterItemSlot: import('react').ForwardRefExoticComponent<ToasterItemSlotProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
23
|
+
/**
|
|
24
|
+
* Props for Toaster.Icon slot component
|
|
25
|
+
*/
|
|
26
|
+
export interface ToasterIconSlotProps {
|
|
27
|
+
className?: string;
|
|
28
|
+
style?: React.CSSProperties;
|
|
29
|
+
/** Custom render function - receives type and default icon */
|
|
30
|
+
children?: (type: ToastType, defaultIcon: ReactNode) => ReactNode;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Slot component for customizing toast icon
|
|
34
|
+
*/
|
|
35
|
+
export declare const ToasterIconSlot: import('react').ForwardRefExoticComponent<ToasterIconSlotProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
36
|
+
/**
|
|
37
|
+
* Props for Toaster.Title slot component
|
|
38
|
+
*/
|
|
39
|
+
export interface ToasterTitleSlotProps {
|
|
40
|
+
className?: string;
|
|
41
|
+
style?: React.CSSProperties;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Slot component for customizing toast title
|
|
45
|
+
*/
|
|
46
|
+
export declare const ToasterTitleSlot: import('react').ForwardRefExoticComponent<ToasterTitleSlotProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
47
|
+
/**
|
|
48
|
+
* Props for Toaster.Description slot component
|
|
49
|
+
*/
|
|
50
|
+
export interface ToasterDescriptionSlotProps {
|
|
51
|
+
className?: string;
|
|
52
|
+
style?: React.CSSProperties;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Slot component for customizing toast description
|
|
56
|
+
*/
|
|
57
|
+
export declare const ToasterDescriptionSlot: import('react').ForwardRefExoticComponent<ToasterDescriptionSlotProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
58
|
+
/**
|
|
59
|
+
* Props for Toaster.Actions slot component
|
|
60
|
+
*/
|
|
61
|
+
export interface ToasterActionsSlotProps {
|
|
62
|
+
className?: string;
|
|
63
|
+
style?: React.CSSProperties;
|
|
64
|
+
/** Custom render function for actions */
|
|
65
|
+
children?: (action: ToastAction | undefined, cancel: ToastCancel | undefined, close: () => void) => ReactNode;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Slot component for customizing toast actions
|
|
69
|
+
*/
|
|
70
|
+
export declare const ToasterActionsSlot: import('react').ForwardRefExoticComponent<ToasterActionsSlotProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
71
|
+
/**
|
|
72
|
+
* Collected slot props from Toaster.Item children
|
|
73
|
+
*/
|
|
74
|
+
export interface CollectedSlotProps {
|
|
75
|
+
itemClassName?: string;
|
|
76
|
+
itemStyle?: React.CSSProperties;
|
|
77
|
+
iconClassName?: string;
|
|
78
|
+
iconStyle?: React.CSSProperties;
|
|
79
|
+
renderIcon?: (type: ToastType, defaultIcon: ReactNode) => ReactNode;
|
|
80
|
+
titleClassName?: string;
|
|
81
|
+
titleStyle?: React.CSSProperties;
|
|
82
|
+
descriptionClassName?: string;
|
|
83
|
+
descriptionStyle?: React.CSSProperties;
|
|
84
|
+
actionsClassName?: string;
|
|
85
|
+
actionsStyle?: React.CSSProperties;
|
|
86
|
+
renderActions?: (action: ToastAction | undefined, cancel: ToastCancel | undefined, close: () => void) => ReactNode;
|
|
87
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
const ToasterItemSlot = forwardRef(
|
|
3
|
+
function ToasterItemSlot2(_props, _ref) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
);
|
|
7
|
+
ToasterItemSlot.displayName = "Toaster.Item";
|
|
8
|
+
const ToasterIconSlot = forwardRef(
|
|
9
|
+
function ToasterIconSlot2(_props, _ref) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
);
|
|
13
|
+
ToasterIconSlot.displayName = "Toaster.Icon";
|
|
14
|
+
const ToasterTitleSlot = forwardRef(
|
|
15
|
+
function ToasterTitleSlot2(_props, _ref) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
ToasterTitleSlot.displayName = "Toaster.Title";
|
|
20
|
+
const ToasterDescriptionSlot = forwardRef(
|
|
21
|
+
function ToasterDescriptionSlot2(_props, _ref) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
ToasterDescriptionSlot.displayName = "Toaster.Description";
|
|
26
|
+
const ToasterActionsSlot = forwardRef(
|
|
27
|
+
function ToasterActionsSlot2(_props, _ref) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
ToasterActionsSlot.displayName = "Toaster.Actions";
|
|
32
|
+
export {
|
|
33
|
+
ToasterActionsSlot,
|
|
34
|
+
ToasterDescriptionSlot,
|
|
35
|
+
ToasterIconSlot,
|
|
36
|
+
ToasterItemSlot,
|
|
37
|
+
ToasterTitleSlot
|
|
38
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { ToastPosition, ToastType, ToastVariant } from './types';
|
|
2
|
+
export interface ToastData {
|
|
3
|
+
id: string;
|
|
4
|
+
type: ToastType;
|
|
5
|
+
variant?: ToastVariant;
|
|
6
|
+
/**
|
|
7
|
+
* Title content. Supports:
|
|
8
|
+
* - Plain string: rendered as text
|
|
9
|
+
* - HTML string (containing tags like `<b>`, `<strong>`, etc.): rendered as HTML
|
|
10
|
+
* - ReactNode: rendered as React component
|
|
11
|
+
*/
|
|
12
|
+
title?: React.ReactNode;
|
|
13
|
+
/**
|
|
14
|
+
* Description content. Supports:
|
|
15
|
+
* - Plain string: rendered as text
|
|
16
|
+
* - HTML string (containing tags like `<b>`, `<strong>`, etc.): rendered as HTML
|
|
17
|
+
* - ReactNode: rendered as React component
|
|
18
|
+
*/
|
|
19
|
+
description?: React.ReactNode;
|
|
20
|
+
duration?: number;
|
|
21
|
+
icon?: React.ReactNode;
|
|
22
|
+
action?: {
|
|
23
|
+
label: React.ReactNode;
|
|
24
|
+
onClick: () => void;
|
|
25
|
+
};
|
|
26
|
+
cancel?: {
|
|
27
|
+
label: React.ReactNode;
|
|
28
|
+
onClick?: () => void;
|
|
29
|
+
};
|
|
30
|
+
onClose?: () => void;
|
|
31
|
+
onAutoClose?: () => void;
|
|
32
|
+
dismissible?: boolean;
|
|
33
|
+
createdAt: number;
|
|
34
|
+
height?: number;
|
|
35
|
+
removing?: boolean;
|
|
36
|
+
swipeDirection?: "left" | "right" | "up" | "down";
|
|
37
|
+
}
|
|
38
|
+
export interface ToastOptions {
|
|
39
|
+
id?: string;
|
|
40
|
+
variant?: ToastVariant;
|
|
41
|
+
/**
|
|
42
|
+
* Description content. Supports:
|
|
43
|
+
* - Plain string: rendered as text
|
|
44
|
+
* - HTML string (containing tags like `<b>`, `<strong>`, etc.): rendered as HTML
|
|
45
|
+
* - ReactNode: rendered as React component
|
|
46
|
+
*/
|
|
47
|
+
description?: React.ReactNode;
|
|
48
|
+
duration?: number;
|
|
49
|
+
icon?: React.ReactNode;
|
|
50
|
+
action?: {
|
|
51
|
+
label: React.ReactNode;
|
|
52
|
+
onClick: () => void;
|
|
53
|
+
};
|
|
54
|
+
cancel?: {
|
|
55
|
+
label: React.ReactNode;
|
|
56
|
+
onClick?: () => void;
|
|
57
|
+
};
|
|
58
|
+
onClose?: () => void;
|
|
59
|
+
onAutoClose?: () => void;
|
|
60
|
+
dismissible?: boolean;
|
|
61
|
+
}
|
|
62
|
+
export interface ToasterState {
|
|
63
|
+
toasts: ToastData[];
|
|
64
|
+
expanded: boolean;
|
|
65
|
+
position: ToastPosition;
|
|
66
|
+
}
|
|
67
|
+
type Subscriber = (state?: ToasterState) => void;
|
|
68
|
+
export declare function subscribe(callback: Subscriber, toasterId?: string): () => void;
|
|
69
|
+
export declare function getSnapshot(toasterId?: string): ToasterState;
|
|
70
|
+
export declare function setToasterConfig(config: Partial<Pick<ToasterState, "position" | "expanded">>, toasterId?: string): void;
|
|
71
|
+
export declare function dismiss(id: string, toasterId?: string): void;
|
|
72
|
+
export declare function dismissAll(toasterId?: string): void;
|
|
73
|
+
export declare function updateHeight(id: string, height: number, toasterId?: string): void;
|
|
74
|
+
export declare function setExpanded(expanded: boolean, toasterId?: string): void;
|
|
75
|
+
interface PromiseOptions<T> {
|
|
76
|
+
loading: string | (ToastOptions & {
|
|
77
|
+
title: string;
|
|
78
|
+
});
|
|
79
|
+
success: string | (ToastOptions & {
|
|
80
|
+
title: string;
|
|
81
|
+
}) | ((data: T) => string | (ToastOptions & {
|
|
82
|
+
title: string;
|
|
83
|
+
}));
|
|
84
|
+
error: string | (ToastOptions & {
|
|
85
|
+
title: string;
|
|
86
|
+
}) | ((err: unknown) => string | (ToastOptions & {
|
|
87
|
+
title: string;
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
type ToastFunction = {
|
|
91
|
+
(title: string, options?: ToastOptions): string;
|
|
92
|
+
success: (title: string, options?: ToastOptions) => string;
|
|
93
|
+
error: (title: string, options?: ToastOptions) => string;
|
|
94
|
+
warning: (title: string, options?: ToastOptions) => string;
|
|
95
|
+
info: (title: string, options?: ToastOptions) => string;
|
|
96
|
+
loading: (title: string, options?: ToastOptions) => string;
|
|
97
|
+
promise: <T>(promise: Promise<T>, options: PromiseOptions<T>) => Promise<T>;
|
|
98
|
+
dismiss: (id: string) => void;
|
|
99
|
+
dismissAll: () => void;
|
|
100
|
+
use: (toasterId: string) => {
|
|
101
|
+
(title: string, options?: ToastOptions): string;
|
|
102
|
+
success: (title: string, options?: ToastOptions) => string;
|
|
103
|
+
error: (title: string, options?: ToastOptions) => string;
|
|
104
|
+
warning: (title: string, options?: ToastOptions) => string;
|
|
105
|
+
info: (title: string, options?: ToastOptions) => string;
|
|
106
|
+
loading: (title: string, options?: ToastOptions) => string;
|
|
107
|
+
promise: <T>(promise: Promise<T>, options: PromiseOptions<T>) => Promise<T>;
|
|
108
|
+
dismiss: (id: string) => void;
|
|
109
|
+
dismissAll: () => void;
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
export declare const toast: ToastFunction;
|
|
113
|
+
export {};
|