goey-toast 0.2.1 → 0.2.2

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.cjs CHANGED
@@ -2,21 +2,43 @@
2
2
 
3
3
  var react = require('react');
4
4
  var sonner = require('sonner');
5
- var jsxRuntime = require('react/jsx-runtime');
6
5
  var framerMotion = require('framer-motion');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
7
 
8
8
  // src/components/GoeyToaster.tsx
9
9
 
10
+ // src/presets.ts
11
+ var animationPresets = {
12
+ smooth: { bounce: 0.1, spring: true },
13
+ bouncy: { bounce: 0.6, spring: true },
14
+ subtle: { bounce: 0.05, spring: true },
15
+ snappy: { bounce: 0.4, spring: true }
16
+ };
17
+
10
18
  // src/context.ts
11
19
  var _position = "bottom-right";
20
+ var _dir = "ltr";
12
21
  var _spring = true;
13
22
  var _bounce = void 0;
23
+ var _theme = "light";
24
+ function setGoeyTheme(theme) {
25
+ _theme = theme;
26
+ }
27
+ function getGoeyTheme() {
28
+ return _theme;
29
+ }
14
30
  function setGoeyPosition(position) {
15
31
  _position = position;
16
32
  }
17
33
  function getGoeyPosition() {
18
34
  return _position;
19
35
  }
36
+ function setGoeyDir(dir) {
37
+ _dir = dir;
38
+ }
39
+ function getGoeyDir() {
40
+ return _dir;
41
+ }
20
42
  function setGoeySpring(spring) {
21
43
  _spring = spring;
22
44
  }
@@ -36,6 +58,34 @@ function setGoeyVisibleToasts(n) {
36
58
  function getGoeyVisibleToasts() {
37
59
  return _visibleToasts;
38
60
  }
61
+ var _swipeToDismiss = true;
62
+ function setGoeySwipeToDismiss(enabled) {
63
+ _swipeToDismiss = enabled;
64
+ }
65
+ function getGoeySwipeToDismiss() {
66
+ return _swipeToDismiss;
67
+ }
68
+ var _maxQueue = Infinity;
69
+ function setGoeyMaxQueue(n) {
70
+ _maxQueue = n;
71
+ }
72
+ function getGoeyMaxQueue() {
73
+ return _maxQueue;
74
+ }
75
+ var _queueOverflow = "drop-oldest";
76
+ function setGoeyQueueOverflow(strategy) {
77
+ _queueOverflow = strategy;
78
+ }
79
+ function getGoeyQueueOverflow() {
80
+ return _queueOverflow;
81
+ }
82
+ var _showProgress = false;
83
+ function setGoeyShowProgress(show) {
84
+ _showProgress = show;
85
+ }
86
+ function getGoeyShowProgress() {
87
+ return _showProgress;
88
+ }
39
89
  var _containerHovered = false;
40
90
  var _hoverSubs = /* @__PURE__ */ new Set();
41
91
  function setContainerHovered(hovered) {
@@ -52,101 +102,15 @@ function subscribeContainerHovered(cb) {
52
102
  _hoverSubs.delete(cb);
53
103
  };
54
104
  }
55
- function GoeyToaster({
56
- position = "bottom-right",
57
- duration,
58
- gap = 14,
59
- offset = "24px",
60
- theme = "light",
61
- toastOptions,
62
- expand,
63
- closeButton,
64
- richColors,
65
- visibleToasts,
66
- dir,
67
- spring = true,
68
- bounce
69
- }) {
70
- react.useEffect(() => {
71
- setGoeyPosition(position);
72
- }, [position]);
73
- react.useEffect(() => {
74
- setGoeySpring(spring);
75
- }, [spring]);
76
- react.useEffect(() => {
77
- setGoeyBounce(bounce);
78
- }, [bounce]);
79
- react.useEffect(() => {
80
- setGoeyVisibleToasts(visibleToasts ?? 3);
81
- }, [visibleToasts]);
82
- react.useEffect(() => {
83
- let expandObs = null;
84
- let currentOl = null;
85
- const syncFromExpanded = (ol) => {
86
- const anyExpanded = ol.querySelector('[data-sonner-toast][data-expanded="true"]') !== null;
87
- setContainerHovered(anyExpanded);
88
- };
89
- const attach = (ol) => {
90
- if (ol === currentOl) return;
91
- expandObs?.disconnect();
92
- currentOl = ol;
93
- expandObs = new MutationObserver(() => syncFromExpanded(ol));
94
- expandObs.observe(ol, { attributes: true, attributeFilter: ["data-expanded"], subtree: true });
95
- syncFromExpanded(ol);
96
- };
97
- const el = document.querySelector("[data-sonner-toaster]");
98
- if (el) attach(el);
99
- const bodyObs = new MutationObserver(() => {
100
- const found = document.querySelector("[data-sonner-toaster]");
101
- if (found) {
102
- attach(found);
103
- } else if (currentOl) {
104
- expandObs?.disconnect();
105
- currentOl = null;
106
- setContainerHovered(false);
107
- }
108
- });
109
- bodyObs.observe(document.body, { childList: true, subtree: true });
110
- return () => {
111
- bodyObs.disconnect();
112
- expandObs?.disconnect();
113
- setContainerHovered(false);
114
- };
115
- }, []);
116
- react.useEffect(() => {
117
- if (process.env.NODE_ENV !== "development") return;
118
- const el = document.createElement("div");
119
- el.setAttribute("data-goey-toast-css", "");
120
- el.style.position = "absolute";
121
- el.style.width = "0";
122
- el.style.height = "0";
123
- el.style.overflow = "hidden";
124
- el.style.pointerEvents = "none";
125
- document.body.appendChild(el);
126
- const value = getComputedStyle(el).getPropertyValue("--goey-toast");
127
- document.body.removeChild(el);
128
- if (!value) {
129
- console.warn(
130
- '[goey-toast] Styles not found. Make sure to import the CSS:\n\n import "goey-toast/styles.css";\n'
131
- );
132
- }
133
- }, []);
134
- return /* @__PURE__ */ jsxRuntime.jsx(
135
- sonner.Toaster,
136
- {
137
- position,
138
- duration,
139
- gap,
140
- offset,
141
- theme,
142
- toastOptions: { unstyled: true, ...toastOptions },
143
- expand,
144
- closeButton,
145
- richColors,
146
- visibleToasts: 99,
147
- dir
148
- }
149
- );
105
+ var _announceSubs = /* @__PURE__ */ new Set();
106
+ function announce(message, politeness = "polite") {
107
+ _announceSubs.forEach((cb) => cb({ message, politeness }));
108
+ }
109
+ function subscribeAnnouncements(cb) {
110
+ _announceSubs.add(cb);
111
+ return () => {
112
+ _announceSubs.delete(cb);
113
+ };
150
114
  }
151
115
  var DefaultIcon = ({ size = 20, className }) => /* @__PURE__ */ jsxRuntime.jsxs(
152
116
  "svg",
@@ -309,8 +273,18 @@ var styles = {
309
273
  actionSuccess: "goey-actionSuccess",
310
274
  actionError: "goey-actionError",
311
275
  actionWarning: "goey-actionWarning",
312
- actionInfo: "goey-actionInfo"
276
+ actionInfo: "goey-actionInfo",
277
+ progressWrapper: "goey-progressWrapper",
278
+ progressBar: "goey-progressBar",
279
+ progressDefault: "goey-progressDefault",
280
+ progressSuccess: "goey-progressSuccess",
281
+ progressError: "goey-progressError",
282
+ progressWarning: "goey-progressWarning",
283
+ progressInfo: "goey-progressInfo",
284
+ progressPaused: "goey-progressPaused",
285
+ timestamp: "goey-timestamp"
313
286
  };
287
+ var useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
314
288
  var phaseIconMap = {
315
289
  default: DefaultIcon,
316
290
  success: SuccessIcon,
@@ -334,6 +308,14 @@ var actionColorMap = {
334
308
  warning: styles.actionWarning,
335
309
  info: styles.actionInfo
336
310
  };
311
+ var progressColorMap = {
312
+ loading: styles.progressInfo,
313
+ default: styles.progressDefault,
314
+ success: styles.progressSuccess,
315
+ error: styles.progressError,
316
+ warning: styles.progressWarning,
317
+ info: styles.progressInfo
318
+ };
337
319
  var PH = 34;
338
320
  var DEFAULT_DISPLAY_DURATION = 4e3;
339
321
  var DEFAULT_EXPAND_DUR = 0.6;
@@ -425,7 +407,19 @@ function syncSonnerHeights(wrapperEl, includeOffsets = false) {
425
407
  for (const t of toasts) t.style.removeProperty("transition");
426
408
  }
427
409
  }
428
- function morphPath(pw, bw, th, t) {
410
+ function memoizePath(fn) {
411
+ let lastArgs = null;
412
+ let lastResult = "";
413
+ return (pw, bw, th, t) => {
414
+ if (lastArgs && lastArgs[0] === pw && lastArgs[1] === bw && lastArgs[2] === th && lastArgs[3] === t) {
415
+ return lastResult;
416
+ }
417
+ lastResult = fn(pw, bw, th, t);
418
+ lastArgs = [pw, bw, th, t];
419
+ return lastResult;
420
+ };
421
+ }
422
+ function morphPathRaw(pw, bw, th, t) {
429
423
  const pr = PH / 2;
430
424
  const pillW = Math.min(pw, bw);
431
425
  const bodyH = PH + (th - PH) * t;
@@ -462,7 +456,7 @@ function morphPath(pw, bw, th, t) {
462
456
  `Z`
463
457
  ].join(" ");
464
458
  }
465
- function morphPathCenter(pw, bw, th, t) {
459
+ function morphPathCenterRaw(pw, bw, th, t) {
466
460
  const pr = PH / 2;
467
461
  const pillW = Math.min(pw, bw);
468
462
  const pillOffset = (bw - pillW) / 2;
@@ -525,6 +519,8 @@ function morphPathCenter(pw, bw, th, t) {
525
519
  `Z`
526
520
  ].join(" ");
527
521
  }
522
+ var morphPath = memoizePath(morphPathRaw);
523
+ var morphPathCenter = memoizePath(morphPathCenterRaw);
528
524
  var SMOOTH_EASE = [0.4, 0, 0.2, 1];
529
525
  var GoeyToast = ({
530
526
  title,
@@ -533,22 +529,31 @@ var GoeyToast = ({
533
529
  icon,
534
530
  phase,
535
531
  classNames,
536
- fillColor = "#ffffff",
532
+ fillColor: fillColorProp,
537
533
  borderColor,
538
534
  borderWidth,
539
535
  timing,
536
+ preset,
540
537
  spring: springProp,
541
538
  bounce: bounceProp,
539
+ showProgress: showProgressProp,
542
540
  toastId
543
541
  }) => {
542
+ const theme = getGoeyTheme();
543
+ const fillColor = fillColorProp ?? (theme === "dark" ? "#1a1a1a" : "#ffffff");
544
544
  const position = getGoeyPosition();
545
- const isRight = position?.includes("right") ?? false;
545
+ const dir = getGoeyDir();
546
+ const posIsRight = position?.includes("right") ?? false;
546
547
  const isCenter = position?.includes("center") ?? false;
548
+ const isRight = dir === "rtl" ? isCenter ? false : !posIsRight : posIsRight;
547
549
  const prefersReducedMotion = usePrefersReducedMotion();
548
- const useSpring = springProp ?? getGoeySpring();
549
- const bounceVal = bounceProp ?? getGoeyBounce() ?? 0.4;
550
+ const presetConfig = preset ? animationPresets[preset] : void 0;
551
+ const useSpring = springProp ?? presetConfig?.spring ?? getGoeySpring();
552
+ const bounceVal = bounceProp ?? presetConfig?.bounce ?? getGoeyBounce() ?? 0.4;
553
+ const showProgress = showProgressProp ?? getGoeyShowProgress();
550
554
  const [actionSuccess, setActionSuccess] = react.useState(null);
551
555
  const [dismissing, setDismissing] = react.useState(false);
556
+ const [progressKey, setProgressKey] = react.useState(0);
552
557
  const [hovered, setHovered] = react.useState(false);
553
558
  const hoveredRef = react.useRef(false);
554
559
  const containerHoveredRef = react.useRef(getContainerHovered());
@@ -592,8 +597,10 @@ var GoeyToast = ({
592
597
  if (p <= 0 || b <= 0 || h <= 0) return;
593
598
  const t = Math.max(0, Math.min(1, morphTRef.current));
594
599
  const pos = getGoeyPosition();
595
- const rightSide = pos?.includes("right") ?? false;
600
+ const d = getGoeyDir();
596
601
  const centerPos = pos?.includes("center") ?? false;
602
+ const posRight = pos?.includes("right") ?? false;
603
+ const rightSide = d === "rtl" ? centerPos ? false : !posRight : posRight;
597
604
  if (centerPos) {
598
605
  const centerBw = Math.max(dimsRef.current.bw, expandedDimsRef.current.bw, p);
599
606
  pathRef.current?.setAttribute("d", morphPathCenter(p, centerBw, h, t));
@@ -680,7 +687,7 @@ var GoeyToast = ({
680
687
  dimsRef.current = { pw: pw2, bw: bw2, th: th2 };
681
688
  setDims({ pw: pw2, bw: bw2, th: th2 });
682
689
  }, []);
683
- react.useLayoutEffect(() => {
690
+ useIsomorphicLayoutEffect(() => {
684
691
  measure();
685
692
  const t = setTimeout(measure, 100);
686
693
  return () => clearTimeout(t);
@@ -707,8 +714,8 @@ var GoeyToast = ({
707
714
  const el = wrapperRef.current;
708
715
  const springConfig = phase2 === "collapse" ? squishSpring(collapseDur, DEFAULT_COLLAPSE_DUR, bounceVal) : squishSpring(expandDur, DEFAULT_EXPAND_DUR, bounceVal);
709
716
  const bScale = bounceVal / 0.4;
710
- const compressY = (phase2 === "collapse" ? 0.07 : 0.12) * bScale;
711
- const expandX = (phase2 === "collapse" ? 0.035 : 0.06) * bScale;
717
+ const compressY = (phase2 === "collapse" ? 0.035 : 0.12) * bScale;
718
+ const expandX = (phase2 === "collapse" ? 0.018 : 0.06) * bScale;
712
719
  blobSquishCtrl.current = framerMotion.animate(0, 1, {
713
720
  ...springConfig,
714
721
  onUpdate: (v) => {
@@ -726,7 +733,7 @@ var GoeyToast = ({
726
733
  }
727
734
  });
728
735
  }, [prefersReducedMotion, expandDur, collapseDur, useSpring, bounceVal]);
729
- react.useLayoutEffect(() => {
736
+ useIsomorphicLayoutEffect(() => {
730
737
  if (!hasDims || collapsingRef.current) return;
731
738
  const prev = { ...aDims.current };
732
739
  const target = { pw, bw, th };
@@ -778,7 +785,7 @@ var GoeyToast = ({
778
785
  }
779
786
  }, [hasDims, squishDelayMs, triggerLandingSquish]);
780
787
  const prevShowBody = react.useRef(false);
781
- react.useLayoutEffect(() => {
788
+ useIsomorphicLayoutEffect(() => {
782
789
  if (!prevShowBody.current && showBody && !hoveredRef.current) {
783
790
  const t = setTimeout(() => triggerLandingSquish("expand"), 80);
784
791
  return () => clearTimeout(t);
@@ -870,12 +877,14 @@ var GoeyToast = ({
870
877
  }, [isExpanded, flush, prefersReducedMotion, useSpring, triggerLandingSquish]);
871
878
  const remainingRef = react.useRef(null);
872
879
  const timerStartRef = react.useRef(0);
880
+ const progressDelayRef = react.useRef(0);
873
881
  react.useEffect(() => {
874
882
  if (!showBody || actionSuccess || dismissing) return;
875
883
  const expandDelayMs = prefersReducedMotion ? 0 : 330;
876
884
  const collapseMs = prefersReducedMotion ? 10 : 0.9 * 1e3;
877
885
  const displayMs = timing?.displayDuration ?? DEFAULT_DISPLAY_DURATION;
878
886
  const fullDelay = displayMs - expandDelayMs - collapseMs;
887
+ progressDelayRef.current = Math.max(fullDelay, 0);
879
888
  if (fullDelay <= 0) return;
880
889
  if (hoveredRef.current || containerHoveredRef.current) return;
881
890
  const delay = remainingRef.current ?? fullDelay;
@@ -913,6 +922,7 @@ var GoeyToast = ({
913
922
  reExpandingRef.current = true;
914
923
  setDismissing(false);
915
924
  setShowBody(true);
925
+ if (showProgress) setProgressKey((k) => k + 1);
916
926
  const currentT = morphTRef.current;
917
927
  const startDims = { ...aDims.current };
918
928
  const morphExpandTransition = useSpring ? { type: "spring", duration: 0.9, bounce: bounceVal } : { duration: 0.6, ease: SMOOTH_EASE };
@@ -1079,13 +1089,56 @@ var GoeyToast = ({
1079
1089
  } catch {
1080
1090
  }
1081
1091
  }, [effectiveAction]);
1092
+ const SWIPE_THRESHOLD = 100;
1093
+ const swipeStartRef = react.useRef(null);
1094
+ const [swipeOffsetX, setSwipeOffsetX] = react.useState(0);
1095
+ const isSwipingRef = react.useRef(false);
1096
+ const handleTouchStart = react.useCallback((e) => {
1097
+ if (!getGoeySwipeToDismiss()) return;
1098
+ const touch = e.touches[0];
1099
+ swipeStartRef.current = { x: touch.clientX, y: touch.clientY };
1100
+ isSwipingRef.current = false;
1101
+ }, []);
1102
+ const handleTouchMove = react.useCallback((e) => {
1103
+ if (!swipeStartRef.current || !getGoeySwipeToDismiss()) return;
1104
+ const touch = e.touches[0];
1105
+ const dx = touch.clientX - swipeStartRef.current.x;
1106
+ const dy = touch.clientY - swipeStartRef.current.y;
1107
+ if (!isSwipingRef.current && Math.abs(dy) > Math.abs(dx) && Math.abs(dy) > 10) {
1108
+ swipeStartRef.current = null;
1109
+ return;
1110
+ }
1111
+ if (!isSwipingRef.current && Math.abs(dx) > 10) {
1112
+ isSwipingRef.current = true;
1113
+ }
1114
+ if (isSwipingRef.current) {
1115
+ setSwipeOffsetX(dx);
1116
+ }
1117
+ }, []);
1118
+ const handleTouchEnd = react.useCallback(() => {
1119
+ if (!getGoeySwipeToDismiss()) {
1120
+ swipeStartRef.current = null;
1121
+ return;
1122
+ }
1123
+ if (isSwipingRef.current && Math.abs(swipeOffsetX) >= SWIPE_THRESHOLD && toastId) {
1124
+ sonner.toast.dismiss(toastId);
1125
+ }
1126
+ swipeStartRef.current = null;
1127
+ isSwipingRef.current = false;
1128
+ setSwipeOffsetX(0);
1129
+ }, [swipeOffsetX, toastId]);
1130
+ const swipeOpacity = swipeOffsetX !== 0 ? Math.max(0, 1 - Math.abs(swipeOffsetX) / (SWIPE_THRESHOLD * 1.5)) : 1;
1131
+ const swipeTranslate = swipeOffsetX !== 0 ? `translateX(${swipeOffsetX}px)` : "";
1082
1132
  const renderIcon = () => {
1083
1133
  if (!actionSuccess && icon) return icon;
1084
1134
  if (isLoading) return /* @__PURE__ */ jsxRuntime.jsx(SpinnerIcon, { size: 18, className: styles.spinnerSpin });
1085
1135
  const IconComponent = phaseIconMap[effectivePhase];
1086
1136
  return /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { size: 18 });
1087
1137
  };
1088
- const iconTransition = prefersReducedMotion ? { duration: 0.01 } : { duration: 0.2 };
1138
+ const iconTransition = react.useMemo(
1139
+ () => prefersReducedMotion ? { duration: 0.01 } : { duration: 0.2 },
1140
+ [prefersReducedMotion]
1141
+ );
1089
1142
  const iconEl = /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${styles.iconWrapper}${classNames?.icon ? ` ${classNames.icon}` : ""}`, children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "wait", children: /* @__PURE__ */ jsxRuntime.jsx(
1090
1143
  framerMotion.motion.div,
1091
1144
  {
@@ -1098,17 +1151,43 @@ var GoeyToast = ({
1098
1151
  isLoading ? "spinner" : effectivePhase
1099
1152
  ) }) });
1100
1153
  const titleEl = /* @__PURE__ */ jsxRuntime.jsx("span", { className: `${styles.title}${classNames?.title ? ` ${classNames.title}` : ""}`, children: effectiveTitle });
1154
+ const createdAtRef = react.useRef(/* @__PURE__ */ new Date());
1155
+ const timestampStr = react.useMemo(
1156
+ () => createdAtRef.current.toLocaleTimeString(void 0, { hour: "numeric", minute: "2-digit", second: "2-digit" }),
1157
+ []
1158
+ );
1101
1159
  const iconAndTitle = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1102
1160
  iconEl,
1103
1161
  titleEl
1104
1162
  ] });
1105
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: wrapperRef, className: `${styles.wrapper}${classNames?.wrapper ? ` ${classNames.wrapper}` : ""}`, style: isCenter ? { margin: "0 auto" } : isRight ? { marginLeft: "auto", transform: "scaleX(-1)" } : void 0, role: effectivePhase === "error" ? "alert" : "status", "aria-live": effectivePhase === "error" ? "assertive" : "polite", "aria-atomic": "true", onMouseEnter: () => {
1163
+ const basePositionStyle = react.useMemo(
1164
+ () => isCenter ? { margin: "0 auto" } : isRight ? { marginLeft: "auto", transform: "scaleX(-1)" } : {},
1165
+ [isCenter, isRight]
1166
+ );
1167
+ const wrapperStyle = react.useMemo(() => {
1168
+ if (swipeTranslate) {
1169
+ return {
1170
+ ...basePositionStyle,
1171
+ transform: (basePositionStyle.transform ? basePositionStyle.transform + " " : "") + swipeTranslate,
1172
+ opacity: swipeOpacity,
1173
+ transition: "none"
1174
+ };
1175
+ }
1176
+ return Object.keys(basePositionStyle).length > 0 ? basePositionStyle : void 0;
1177
+ }, [basePositionStyle, swipeTranslate, swipeOpacity]);
1178
+ const contentStyle = react.useMemo(
1179
+ () => isCenter ? { textAlign: "center" } : isRight ? { transform: "scaleX(-1)", textAlign: "right" } : { textAlign: "left" },
1180
+ [isCenter, isRight]
1181
+ );
1182
+ const handleMouseEnter = react.useCallback(() => {
1106
1183
  hoveredRef.current = true;
1107
1184
  setHovered(true);
1108
- }, onMouseLeave: () => {
1185
+ }, []);
1186
+ const handleMouseLeave = react.useCallback(() => {
1109
1187
  hoveredRef.current = false;
1110
1188
  setHovered(false);
1111
- }, "data-center": isCenter || void 0, children: [
1189
+ }, []);
1190
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: wrapperRef, className: `${styles.wrapper}${classNames?.wrapper ? ` ${classNames.wrapper}` : ""}`, style: wrapperStyle, role: effectivePhase === "error" || effectivePhase === "warning" ? "alert" : "status", "aria-live": effectivePhase === "error" || effectivePhase === "warning" ? "assertive" : "polite", "aria-atomic": "true", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, "data-center": isCenter || void 0, "data-theme": theme, children: [
1112
1191
  /* @__PURE__ */ jsxRuntime.jsx(
1113
1192
  "svg",
1114
1193
  {
@@ -1130,10 +1209,13 @@ var GoeyToast = ({
1130
1209
  {
1131
1210
  ref: contentRef,
1132
1211
  className: `${styles.content} ${showBody ? styles.contentExpanded : styles.contentCompact}${classNames?.content ? ` ${classNames.content}` : ""}`,
1133
- style: isCenter ? { textAlign: "center" } : isRight ? { transform: "scaleX(-1)", textAlign: "right" } : { textAlign: "left" },
1212
+ style: contentStyle,
1134
1213
  children: [
1135
- /* @__PURE__ */ jsxRuntime.jsx("div", { ref: headerRef, className: `${styles.header} ${titleColorMap[effectivePhase]}${classNames?.header ? ` ${classNames.header}` : ""}`, children: iconAndTitle }),
1136
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: showBody && hasDescription && !dismissing && /* @__PURE__ */ jsxRuntime.jsx(
1214
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: headerRef, className: `${styles.header} ${titleColorMap[effectivePhase]}${classNames?.header ? ` ${classNames.header}` : ""}`, children: [
1215
+ iconAndTitle,
1216
+ !hasDescription && !hasAction && !actionSuccess && /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.timestamp, children: timestampStr })
1217
+ ] }),
1218
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: showBody && hasDescription && !dismissing && /* @__PURE__ */ jsxRuntime.jsxs(
1137
1219
  framerMotion.motion.div,
1138
1220
  {
1139
1221
  className: `${styles.description}${classNames?.description ? ` ${classNames.description}` : ""}`,
@@ -1142,10 +1224,26 @@ var GoeyToast = ({
1142
1224
  animate: { opacity: 1 },
1143
1225
  exit: { opacity: 0 },
1144
1226
  transition: prefersReducedMotion ? { duration: 0.01 } : { duration: 0.35, ease: [0.4, 0, 0.2, 1] },
1145
- children: effectiveDescription
1227
+ children: [
1228
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: styles.timestamp, style: { float: "right", marginLeft: 10, marginTop: 3, paddingLeft: 0 }, children: timestampStr }),
1229
+ effectiveDescription
1230
+ ]
1146
1231
  },
1147
1232
  "description"
1148
1233
  ) }),
1234
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: showBody && !hasDescription && hasAction && !dismissing && /* @__PURE__ */ jsxRuntime.jsx(
1235
+ framerMotion.motion.div,
1236
+ {
1237
+ className: styles.timestamp,
1238
+ style: { textAlign: "right", marginTop: 8, paddingLeft: 0 },
1239
+ initial: prefersReducedMotion ? false : { opacity: 0 },
1240
+ animate: { opacity: 1 },
1241
+ exit: { opacity: 0 },
1242
+ transition: prefersReducedMotion ? { duration: 0.01 } : { duration: 0.35, ease: [0.4, 0, 0.2, 1] },
1243
+ children: timestampStr
1244
+ },
1245
+ "timestamp-body"
1246
+ ) }),
1149
1247
  /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: showBody && hasAction && effectiveAction && !dismissing && /* @__PURE__ */ jsxRuntime.jsx(
1150
1248
  framerMotion.motion.div,
1151
1249
  {
@@ -1166,7 +1264,22 @@ var GoeyToast = ({
1166
1264
  )
1167
1265
  },
1168
1266
  "action"
1169
- ) })
1267
+ ) }),
1268
+ showProgress && /* @__PURE__ */ jsxRuntime.jsx(
1269
+ "div",
1270
+ {
1271
+ className: `${styles.progressWrapper}${hovered || containerHovered ? ` ${styles.progressPaused}` : ""}`,
1272
+ style: { opacity: showBody && !actionSuccess ? 1 : 0 },
1273
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1274
+ "div",
1275
+ {
1276
+ className: `${styles.progressBar} ${progressColorMap[effectivePhase]}`,
1277
+ style: { "--goey-progress-duration": `${progressDelayRef.current || (timing?.displayDuration ?? DEFAULT_DISPLAY_DURATION)}ms` }
1278
+ }
1279
+ )
1280
+ },
1281
+ progressKey
1282
+ )
1170
1283
  ]
1171
1284
  }
1172
1285
  )
@@ -1193,37 +1306,129 @@ var ToastErrorBoundary = class extends react.Component {
1193
1306
  }
1194
1307
  };
1195
1308
  var DEFAULT_EXPANDED_DURATION = 4e3;
1196
- var _activeIds = /* @__PURE__ */ new Set();
1309
+ function getAnnouncePoliteness(type) {
1310
+ return type === "error" || type === "warning" ? "assertive" : "polite";
1311
+ }
1312
+ function buildAnnouncementMessage(title, description) {
1313
+ if (!description || typeof description !== "string") return title;
1314
+ return `${title}: ${description}`;
1315
+ }
1316
+ var _activeIds = /* @__PURE__ */ new Map();
1197
1317
  var _queue = [];
1318
+ var _toastCallbacks = /* @__PURE__ */ new Map();
1319
+ var _autoCloseFlags = /* @__PURE__ */ new Set();
1320
+ var _manualDismissFlags = /* @__PURE__ */ new Set();
1321
+ function _getMostRecentActiveId() {
1322
+ let last;
1323
+ for (const id of _activeIds.keys()) last = id;
1324
+ return last;
1325
+ }
1198
1326
  function _processQueue() {
1199
1327
  const max = getGoeyVisibleToasts();
1200
1328
  while (_queue.length > 0 && _activeIds.size < max) {
1201
1329
  const next = _queue.shift();
1202
- _activeIds.add(next.id);
1330
+ _activeIds.set(next.id, next.type);
1203
1331
  next.create();
1204
1332
  }
1205
1333
  }
1334
+ function _enqueue(entry) {
1335
+ const maxQueue = getGoeyMaxQueue();
1336
+ const overflow = getGoeyQueueOverflow();
1337
+ if (_queue.length >= maxQueue) {
1338
+ if (overflow === "drop-newest") return false;
1339
+ _queue.shift();
1340
+ }
1341
+ _queue.push(entry);
1342
+ return true;
1343
+ }
1206
1344
  function _onToastDismissed(id) {
1207
1345
  if (!_activeIds.delete(id)) return;
1346
+ _toastUpdateListeners.delete(id);
1347
+ const cbs = _toastCallbacks.get(id);
1348
+ if (cbs) {
1349
+ const isAutoClose = _autoCloseFlags.has(id) || !_manualDismissFlags.has(id);
1350
+ if (isAutoClose && cbs.onAutoClose) {
1351
+ try {
1352
+ cbs.onAutoClose(id);
1353
+ } catch {
1354
+ }
1355
+ }
1356
+ if (cbs.onDismiss) {
1357
+ try {
1358
+ cbs.onDismiss(id);
1359
+ } catch {
1360
+ }
1361
+ }
1362
+ _toastCallbacks.delete(id);
1363
+ }
1364
+ _autoCloseFlags.delete(id);
1365
+ _manualDismissFlags.delete(id);
1208
1366
  _processQueue();
1209
1367
  }
1368
+ var _toastUpdateListeners = /* @__PURE__ */ new Map();
1369
+ function updateGoeyToast(id, options) {
1370
+ const listener = _toastUpdateListeners.get(id);
1371
+ if (listener) {
1372
+ listener(options);
1373
+ if (options.type !== void 0 && _activeIds.has(id)) {
1374
+ _activeIds.set(id, options.type);
1375
+ }
1376
+ if (options.title !== void 0) {
1377
+ announce(
1378
+ buildAnnouncementMessage(options.title, options.description),
1379
+ options.type ? getAnnouncePoliteness(options.type) : "polite"
1380
+ );
1381
+ }
1382
+ }
1383
+ }
1210
1384
  function GoeyToastWrapper({
1211
1385
  initialPhase,
1212
- title,
1213
- type,
1214
- description,
1215
- action,
1386
+ title: initialTitle,
1387
+ type: initialType,
1388
+ description: initialDescription,
1389
+ action: initialAction,
1216
1390
  icon,
1217
1391
  classNames,
1218
1392
  fillColor,
1219
1393
  borderColor,
1220
1394
  borderWidth,
1221
1395
  timing,
1396
+ preset,
1222
1397
  spring,
1223
1398
  bounce,
1399
+ showProgress,
1224
1400
  toastId,
1225
- activeId
1401
+ activeId,
1402
+ onDismiss,
1403
+ onAutoClose
1226
1404
  }) {
1405
+ react.useEffect(() => {
1406
+ if (onDismiss || onAutoClose) {
1407
+ _toastCallbacks.set(activeId, { onDismiss, onAutoClose });
1408
+ }
1409
+ }, [activeId, onDismiss, onAutoClose]);
1410
+ const [title, setTitle] = react.useState(initialTitle);
1411
+ const [type, setType] = react.useState(initialType);
1412
+ const [phase, setPhase] = react.useState(initialPhase);
1413
+ const [description, setDescription] = react.useState(initialDescription);
1414
+ const [action, setAction] = react.useState(initialAction);
1415
+ const [currentIcon, setCurrentIcon] = react.useState(icon);
1416
+ react.useEffect(() => {
1417
+ const handleUpdate = (opts) => {
1418
+ if (opts.title !== void 0) setTitle(opts.title);
1419
+ if (opts.description !== void 0) setDescription(opts.description);
1420
+ if (opts.type !== void 0) {
1421
+ setType(opts.type);
1422
+ setPhase(opts.type);
1423
+ }
1424
+ if (opts.action !== void 0) setAction(opts.action);
1425
+ if ("icon" in opts) setCurrentIcon(opts.icon ?? void 0);
1426
+ };
1427
+ _toastUpdateListeners.set(activeId, handleUpdate);
1428
+ return () => {
1429
+ _toastUpdateListeners.delete(activeId);
1430
+ };
1431
+ }, [activeId]);
1227
1432
  const mountedRef = react.useRef(true);
1228
1433
  react.useEffect(() => {
1229
1434
  mountedRef.current = true;
@@ -1241,15 +1446,17 @@ function GoeyToastWrapper({
1241
1446
  description,
1242
1447
  type,
1243
1448
  action,
1244
- icon,
1245
- phase: initialPhase,
1449
+ icon: currentIcon,
1450
+ phase,
1246
1451
  classNames,
1247
1452
  fillColor,
1248
1453
  borderColor,
1249
1454
  borderWidth,
1250
1455
  timing,
1456
+ preset,
1251
1457
  spring,
1252
1458
  bounce,
1459
+ showProgress,
1253
1460
  toastId
1254
1461
  }
1255
1462
  ) });
@@ -1263,6 +1470,11 @@ function PromiseToastWrapper({
1263
1470
  const [title, setTitle] = react.useState(data.loading);
1264
1471
  const [description, setDescription] = react.useState(data.description?.loading);
1265
1472
  const [action, setAction] = react.useState(void 0);
1473
+ react.useEffect(() => {
1474
+ if (data.onDismiss || data.onAutoClose) {
1475
+ _toastCallbacks.set(toastId, { onDismiss: data.onDismiss, onAutoClose: data.onAutoClose });
1476
+ }
1477
+ }, [toastId, data.onDismiss, data.onAutoClose]);
1266
1478
  const mountedRef = react.useRef(true);
1267
1479
  react.useEffect(() => {
1268
1480
  mountedRef.current = true;
@@ -1284,22 +1496,22 @@ function PromiseToastWrapper({
1284
1496
  };
1285
1497
  promise.then((result) => {
1286
1498
  const desc = typeof data.description?.success === "function" ? data.description.success(result) : data.description?.success;
1287
- setTitle(
1288
- typeof data.success === "function" ? data.success(result) : data.success
1289
- );
1499
+ const resolvedTitle = typeof data.success === "function" ? data.success(result) : data.success;
1500
+ setTitle(resolvedTitle);
1290
1501
  setDescription(desc);
1291
1502
  setAction(data.action?.success);
1292
1503
  setPhase("success");
1293
1504
  resetDuration(Boolean(desc || data.action?.success));
1505
+ announce(buildAnnouncementMessage(resolvedTitle, desc), "polite");
1294
1506
  }).catch((err) => {
1295
1507
  const desc = typeof data.description?.error === "function" ? data.description.error(err) : data.description?.error;
1296
- setTitle(
1297
- typeof data.error === "function" ? data.error(err) : data.error
1298
- );
1508
+ const resolvedTitle = typeof data.error === "function" ? data.error(err) : data.error;
1509
+ setTitle(resolvedTitle);
1299
1510
  setDescription(desc);
1300
1511
  setAction(data.action?.error);
1301
1512
  setPhase("error");
1302
1513
  resetDuration(Boolean(desc || data.action?.error));
1514
+ announce(buildAnnouncementMessage(resolvedTitle, desc), "assertive");
1303
1515
  });
1304
1516
  }, []);
1305
1517
  return /* @__PURE__ */ jsxRuntime.jsx(ToastErrorBoundary, { children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -1315,6 +1527,7 @@ function PromiseToastWrapper({
1315
1527
  borderColor: data.borderColor,
1316
1528
  borderWidth: data.borderWidth,
1317
1529
  timing: data.timing,
1530
+ preset: data.preset,
1318
1531
  spring: data.spring,
1319
1532
  bounce: data.bounce
1320
1533
  }
@@ -1341,10 +1554,14 @@ function createGoeyToast(title, type, options) {
1341
1554
  borderColor: options?.borderColor,
1342
1555
  borderWidth: options?.borderWidth,
1343
1556
  timing: options?.timing,
1557
+ preset: options?.preset,
1344
1558
  spring: options?.spring,
1345
1559
  bounce: options?.bounce,
1560
+ showProgress: options?.showProgress,
1346
1561
  toastId: hasExpandedContent ? toastId : void 0,
1347
- activeId: toastId
1562
+ activeId: toastId,
1563
+ onDismiss: options?.onDismiss,
1564
+ onAutoClose: options?.onAutoClose
1348
1565
  }
1349
1566
  ),
1350
1567
  {
@@ -1353,23 +1570,48 @@ function createGoeyToast(title, type, options) {
1353
1570
  }
1354
1571
  );
1355
1572
  };
1573
+ if (options?.onDismiss || options?.onAutoClose) {
1574
+ _toastCallbacks.set(toastId, { onDismiss: options.onDismiss, onAutoClose: options.onAutoClose });
1575
+ }
1576
+ announce(
1577
+ buildAnnouncementMessage(title, options?.description),
1578
+ getAnnouncePoliteness(type)
1579
+ );
1356
1580
  if (_activeIds.size < getGoeyVisibleToasts()) {
1357
- _activeIds.add(toastId);
1581
+ _activeIds.set(toastId, type);
1358
1582
  create();
1359
1583
  } else {
1360
- _queue.push({ id: toastId, create });
1584
+ _enqueue({ id: toastId, type, create });
1361
1585
  }
1362
1586
  return toastId;
1363
1587
  }
1364
- function dismissGoeyToast(id) {
1365
- if (id != null) {
1366
- const idx = _queue.findIndex((q) => q.id === id);
1588
+ function dismissGoeyToast(idOrFilter) {
1589
+ if (idOrFilter != null && typeof idOrFilter === "object") {
1590
+ const filterTypes = Array.isArray(idOrFilter.type) ? idOrFilter.type : [idOrFilter.type];
1591
+ const typesSet = new Set(filterTypes);
1592
+ for (let i = _queue.length - 1; i >= 0; i--) {
1593
+ if (typesSet.has(_queue[i].type)) {
1594
+ _queue.splice(i, 1);
1595
+ }
1596
+ }
1597
+ for (const [id, toastType] of _activeIds) {
1598
+ if (typesSet.has(toastType)) {
1599
+ _manualDismissFlags.add(id);
1600
+ sonner.toast.dismiss(id);
1601
+ }
1602
+ }
1603
+ } else if (idOrFilter != null) {
1604
+ const idx = _queue.findIndex((q) => q.id === idOrFilter);
1367
1605
  if (idx !== -1) {
1368
1606
  _queue.splice(idx, 1);
1369
1607
  return;
1370
1608
  }
1371
- sonner.toast.dismiss(id);
1609
+ _manualDismissFlags.add(idOrFilter);
1610
+ sonner.toast.dismiss(idOrFilter);
1372
1611
  } else {
1612
+ for (const id of _activeIds.keys()) {
1613
+ _manualDismissFlags.add(id);
1614
+ }
1373
1615
  _queue.length = 0;
1374
1616
  _activeIds.clear();
1375
1617
  sonner.toast.dismiss();
@@ -1384,6 +1626,10 @@ var goeyToast = Object.assign(
1384
1626
  info: (title, options) => createGoeyToast(title, "info", options),
1385
1627
  promise: (promise, data) => {
1386
1628
  const id = Math.random().toString(36).slice(2);
1629
+ announce(buildAnnouncementMessage(data.loading, data.description?.loading), "polite");
1630
+ if (data.onDismiss || data.onAutoClose) {
1631
+ _toastCallbacks.set(id, { onDismiss: data.onDismiss, onAutoClose: data.onAutoClose });
1632
+ }
1387
1633
  const create = () => {
1388
1634
  sonner.toast.custom(() => /* @__PURE__ */ jsxRuntime.jsx(PromiseToastWrapper, { promise, data, toastId: id }), {
1389
1635
  id,
@@ -1391,18 +1637,226 @@ var goeyToast = Object.assign(
1391
1637
  });
1392
1638
  };
1393
1639
  if (_activeIds.size < getGoeyVisibleToasts()) {
1394
- _activeIds.add(id);
1640
+ _activeIds.set(id, "info");
1395
1641
  create();
1396
1642
  } else {
1397
- _queue.push({ id, create });
1643
+ _enqueue({ id, type: "info", create });
1398
1644
  }
1399
1645
  return id;
1400
1646
  },
1401
- dismiss: dismissGoeyToast
1647
+ dismiss: dismissGoeyToast,
1648
+ update: updateGoeyToast
1402
1649
  }
1403
1650
  );
1651
+ function AriaLiveAnnouncer() {
1652
+ const [politeMessage, setPoliteMessage] = react.useState("");
1653
+ const [assertiveMessage, setAssertiveMessage] = react.useState("");
1654
+ const handleAnnouncement = react.useCallback(({ message, politeness }) => {
1655
+ if (politeness === "assertive") {
1656
+ setAssertiveMessage("");
1657
+ requestAnimationFrame(() => setAssertiveMessage(message));
1658
+ } else {
1659
+ setPoliteMessage("");
1660
+ requestAnimationFrame(() => setPoliteMessage(message));
1661
+ }
1662
+ }, []);
1663
+ react.useEffect(() => {
1664
+ return subscribeAnnouncements(handleAnnouncement);
1665
+ }, [handleAnnouncement]);
1666
+ react.useEffect(() => {
1667
+ if (!politeMessage) return;
1668
+ const t = setTimeout(() => setPoliteMessage(""), 7e3);
1669
+ return () => clearTimeout(t);
1670
+ }, [politeMessage]);
1671
+ react.useEffect(() => {
1672
+ if (!assertiveMessage) return;
1673
+ const t = setTimeout(() => setAssertiveMessage(""), 7e3);
1674
+ return () => clearTimeout(t);
1675
+ }, [assertiveMessage]);
1676
+ const visuallyHidden = {
1677
+ position: "absolute",
1678
+ width: "1px",
1679
+ height: "1px",
1680
+ padding: 0,
1681
+ margin: "-1px",
1682
+ overflow: "hidden",
1683
+ clip: "rect(0, 0, 0, 0)",
1684
+ whiteSpace: "nowrap",
1685
+ border: 0
1686
+ };
1687
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1688
+ /* @__PURE__ */ jsxRuntime.jsx(
1689
+ "div",
1690
+ {
1691
+ role: "status",
1692
+ "aria-live": "polite",
1693
+ "aria-atomic": "true",
1694
+ style: visuallyHidden,
1695
+ children: politeMessage
1696
+ }
1697
+ ),
1698
+ /* @__PURE__ */ jsxRuntime.jsx(
1699
+ "div",
1700
+ {
1701
+ role: "alert",
1702
+ "aria-live": "assertive",
1703
+ "aria-atomic": "true",
1704
+ style: visuallyHidden,
1705
+ children: assertiveMessage
1706
+ }
1707
+ )
1708
+ ] });
1709
+ }
1710
+ function GoeyToaster({
1711
+ position = "bottom-right",
1712
+ duration,
1713
+ gap = 14,
1714
+ offset = "24px",
1715
+ theme = "light",
1716
+ toastOptions,
1717
+ expand,
1718
+ closeButton,
1719
+ richColors,
1720
+ visibleToasts,
1721
+ dir,
1722
+ preset,
1723
+ spring,
1724
+ bounce,
1725
+ swipeToDismiss = true,
1726
+ closeOnEscape = true,
1727
+ maxQueue = Infinity,
1728
+ queueOverflow = "drop-oldest",
1729
+ showProgress = false
1730
+ }) {
1731
+ const presetConfig = preset ? animationPresets[preset] : void 0;
1732
+ const resolvedSpring = spring ?? presetConfig?.spring ?? true;
1733
+ const resolvedBounce = bounce ?? presetConfig?.bounce;
1734
+ react.useEffect(() => {
1735
+ setGoeyPosition(position);
1736
+ }, [position]);
1737
+ react.useEffect(() => {
1738
+ setGoeyDir(dir ?? "ltr");
1739
+ }, [dir]);
1740
+ react.useEffect(() => {
1741
+ setGoeyTheme(theme);
1742
+ }, [theme]);
1743
+ react.useEffect(() => {
1744
+ setGoeySpring(resolvedSpring);
1745
+ }, [resolvedSpring]);
1746
+ react.useEffect(() => {
1747
+ setGoeyBounce(resolvedBounce);
1748
+ }, [resolvedBounce]);
1749
+ react.useEffect(() => {
1750
+ setGoeySwipeToDismiss(swipeToDismiss);
1751
+ }, [swipeToDismiss]);
1752
+ react.useEffect(() => {
1753
+ }, [closeOnEscape]);
1754
+ react.useEffect(() => {
1755
+ if (!closeOnEscape) return;
1756
+ const handleKeyDown = (e) => {
1757
+ if (e.key === "Escape") {
1758
+ const recentId = _getMostRecentActiveId();
1759
+ if (recentId != null) {
1760
+ goeyToast.dismiss(recentId);
1761
+ }
1762
+ }
1763
+ };
1764
+ document.addEventListener("keydown", handleKeyDown);
1765
+ return () => document.removeEventListener("keydown", handleKeyDown);
1766
+ }, [closeOnEscape]);
1767
+ react.useEffect(() => {
1768
+ setGoeyVisibleToasts(visibleToasts ?? 3);
1769
+ }, [visibleToasts]);
1770
+ react.useEffect(() => {
1771
+ setGoeyMaxQueue(maxQueue);
1772
+ }, [maxQueue]);
1773
+ react.useEffect(() => {
1774
+ setGoeyQueueOverflow(queueOverflow);
1775
+ }, [queueOverflow]);
1776
+ react.useEffect(() => {
1777
+ setGoeyShowProgress(showProgress);
1778
+ }, [showProgress]);
1779
+ react.useEffect(() => {
1780
+ let expandObs = null;
1781
+ let currentOl = null;
1782
+ const syncFromExpanded = (ol) => {
1783
+ const anyExpanded = ol.querySelector('[data-sonner-toast][data-expanded="true"]') !== null;
1784
+ setContainerHovered(anyExpanded);
1785
+ };
1786
+ const attach = (ol) => {
1787
+ if (ol === currentOl) return;
1788
+ expandObs?.disconnect();
1789
+ currentOl = ol;
1790
+ expandObs = new MutationObserver(() => syncFromExpanded(ol));
1791
+ expandObs.observe(ol, { attributes: true, attributeFilter: ["data-expanded"], subtree: true });
1792
+ syncFromExpanded(ol);
1793
+ };
1794
+ const el = document.querySelector("[data-sonner-toaster]");
1795
+ if (el) attach(el);
1796
+ let bodyRafId = 0;
1797
+ const bodyObs = new MutationObserver(() => {
1798
+ if (bodyRafId) return;
1799
+ bodyRafId = requestAnimationFrame(() => {
1800
+ bodyRafId = 0;
1801
+ const found = document.querySelector("[data-sonner-toaster]");
1802
+ if (found) {
1803
+ attach(found);
1804
+ } else if (currentOl) {
1805
+ expandObs?.disconnect();
1806
+ currentOl = null;
1807
+ setContainerHovered(false);
1808
+ }
1809
+ });
1810
+ });
1811
+ bodyObs.observe(document.body, { childList: true, subtree: true });
1812
+ return () => {
1813
+ if (bodyRafId) cancelAnimationFrame(bodyRafId);
1814
+ bodyObs.disconnect();
1815
+ expandObs?.disconnect();
1816
+ setContainerHovered(false);
1817
+ };
1818
+ }, []);
1819
+ react.useEffect(() => {
1820
+ if (process.env.NODE_ENV !== "development") return;
1821
+ const el = document.createElement("div");
1822
+ el.setAttribute("data-goey-toast-css", "");
1823
+ el.style.position = "absolute";
1824
+ el.style.width = "0";
1825
+ el.style.height = "0";
1826
+ el.style.overflow = "hidden";
1827
+ el.style.pointerEvents = "none";
1828
+ document.body.appendChild(el);
1829
+ const value = getComputedStyle(el).getPropertyValue("--goey-toast");
1830
+ document.body.removeChild(el);
1831
+ if (!value) {
1832
+ console.warn(
1833
+ '[goey-toast] Styles not found. Make sure to import the CSS:\n\n import "goey-toast/styles.css";\n'
1834
+ );
1835
+ }
1836
+ }, []);
1837
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1838
+ /* @__PURE__ */ jsxRuntime.jsx(
1839
+ sonner.Toaster,
1840
+ {
1841
+ position,
1842
+ duration,
1843
+ gap,
1844
+ offset,
1845
+ theme,
1846
+ toastOptions: { unstyled: true, ...toastOptions },
1847
+ expand,
1848
+ closeButton,
1849
+ richColors,
1850
+ visibleToasts: 99,
1851
+ dir
1852
+ }
1853
+ ),
1854
+ /* @__PURE__ */ jsxRuntime.jsx(AriaLiveAnnouncer, {})
1855
+ ] });
1856
+ }
1404
1857
 
1405
1858
  exports.GoeyToaster = GoeyToaster;
1859
+ exports.animationPresets = animationPresets;
1406
1860
  exports.goeyToast = goeyToast;
1407
1861
  //# sourceMappingURL=index.cjs.map
1408
1862
  //# sourceMappingURL=index.cjs.map