e.stopPropagation() : undefined}
>
@@ -61,8 +77,8 @@ export default function Toaster({ overlay = false }: { overlay?: boolean }) {
return (
@@ -95,10 +111,8 @@ export default function Toaster({ overlay = false }: { overlay?: boolean }) {
{toast.duration && (
-
+ // Keyed by `ts`: a coalesced repeat re-arms the dismiss timer, so its bar restarts too.
+
)}
);
@@ -106,3 +120,17 @@ export default function Toaster({ overlay = false }: { overlay?: boolean }) {
);
}
+
+/** The auto-dismiss countdown, started as far in as the toast already is. A toast handed to another
+ * host is a new node, and its bar used to start again from full while the dismiss timer — armed
+ * once, at notify time — did not: the toast vanished with the bar still two-thirds full. The offset
+ * is taken once, at mount; recomputed on a later render it would jump the running animation ahead. */
+function CountdownBar({ since, duration, bar }: { since: number; duration: number; bar: string }) {
+ const [elapsed] = useState(() => Math.min(duration, Math.max(0, Date.now() - since)));
+ return (
+
+ );
+}