toastflux 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rahul Bairwa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "toastflux",
3
- "version": "1.0.0",
4
- "description": "A lightweight, beautiful, and fully customizable toast notification library for React & Next.js with modern UI, themes, actions, and progress support.",
3
+ "version": "1.0.1",
4
+ "description": "A lightweight, beautiful, and fully customizable toast notification library for React & Next.js with modern UI, themes, actions, and progress support.",
5
5
  "author": "Rahul",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -36,6 +36,14 @@
36
36
  "sideEffects": [
37
37
  "*.css"
38
38
  ],
39
+ "homepage": "https://github.com/Rahul-Bairwa/toastflux",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/Rahul-Bairwa/toastflux.git"
43
+ },
44
+ "bugs": {
45
+ "url": "https://github.com/Rahul-Bairwa/toastflux/issues"
46
+ },
39
47
  "peerDependencies": {
40
48
  "react": ">=16.8.0",
41
49
  "react-dom": ">=16.8.0"
@@ -25,6 +25,9 @@ __export(index_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(index_exports);
27
27
 
28
+ // packages/react/src/Toaster.tsx
29
+ var import_react3 = require("react");
30
+
28
31
  // packages/react/src/useToast.ts
29
32
  var import_react = require("react");
30
33
 
@@ -120,29 +123,34 @@ var icons = {
120
123
  ] }),
121
124
  default: null
122
125
  };
123
- function ToastItem({ toast: toast2 }) {
126
+ var MAX_STACK_VISIBLE = 3;
127
+ var PEEK_OFFSET = 10;
128
+ var SCALE_STEP = 0.05;
129
+ var OPACITY_STEP = 0.15;
130
+ function ToastItem({ toast: toast2, index, total, isExpanded, isBottom }) {
124
131
  var _a;
125
132
  const duration = (_a = toast2.duration) != null ? _a : 3e3;
126
133
  const [offset, setOffset] = (0, import_react2.useState)(0);
127
134
  const [isDragging, setIsDragging] = (0, import_react2.useState)(false);
128
- const [isHovered, setIsHovered] = (0, import_react2.useState)(false);
135
+ const [isItemHovered, setIsItemHovered] = (0, import_react2.useState)(false);
129
136
  const dragStartX = (0, import_react2.useRef)(null);
130
137
  const remainingTime = (0, import_react2.useRef)(duration);
131
138
  const startTime = (0, import_react2.useRef)(Date.now());
139
+ const isPaused = isExpanded || isItemHovered || isDragging;
132
140
  (0, import_react2.useEffect)(() => {
133
141
  if (duration === Infinity || duration <= 0) return;
134
- if (!isHovered && !isDragging) {
135
- startTime.current = Date.now();
136
- const timer = setTimeout(() => {
137
- toast.dismiss(toast2.id);
138
- }, remainingTime.current);
139
- return () => {
140
- clearTimeout(timer);
141
- remainingTime.current -= Date.now() - startTime.current;
142
- };
143
- }
144
- }, [isHovered, isDragging, duration, toast2.id]);
142
+ if (isPaused) return;
143
+ startTime.current = Date.now();
144
+ const timer = setTimeout(() => {
145
+ toast.dismiss(toast2.id);
146
+ }, remainingTime.current);
147
+ return () => {
148
+ clearTimeout(timer);
149
+ remainingTime.current -= Date.now() - startTime.current;
150
+ };
151
+ }, [isPaused, duration, toast2.id]);
145
152
  const handlePointerDown = (e) => {
153
+ if (!isExpanded && index !== 0) return;
146
154
  if (e.target.closest("button")) return;
147
155
  dragStartX.current = e.clientX;
148
156
  setIsDragging(true);
@@ -166,23 +174,52 @@ function ToastItem({ toast: toast2 }) {
166
174
  setOffset(0);
167
175
  }
168
176
  };
177
+ const stackDepth = index;
178
+ const isHidden = stackDepth >= MAX_STACK_VISIBLE;
179
+ const scale = 1 - stackDepth * SCALE_STEP;
180
+ const peekY = stackDepth * PEEK_OFFSET * (isBottom ? -1 : 1);
181
+ const opacity = isHidden ? 0 : 1 - stackDepth * OPACITY_STEP;
182
+ let containerStyle;
183
+ if (!isExpanded) {
184
+ containerStyle = {
185
+ position: "absolute",
186
+ top: isBottom ? void 0 : 0,
187
+ bottom: isBottom ? 0 : void 0,
188
+ left: 0,
189
+ right: 0,
190
+ transform: `translateY(${peekY}px) scale(${scale})${offset ? ` translateX(${offset}px)` : ""}`,
191
+ opacity,
192
+ zIndex: total - stackDepth,
193
+ visibility: isHidden ? "hidden" : "visible",
194
+ pointerEvents: index === 0 ? "auto" : "none",
195
+ transformOrigin: isBottom ? "bottom center" : "top center"
196
+ };
197
+ } else {
198
+ containerStyle = {
199
+ position: "relative",
200
+ transform: offset ? `translateX(${offset}px)` : void 0,
201
+ opacity: 1,
202
+ zIndex: total - stackDepth,
203
+ pointerEvents: "auto"
204
+ };
205
+ }
169
206
  const dynamicStyle = {
170
207
  ...toast2.style,
171
- transform: offset ? `translateX(${offset}px)` : void 0,
172
- transition: isDragging ? "none" : "transform 0.2s ease",
208
+ ...containerStyle,
209
+ transition: isDragging ? "opacity 0.3s ease, visibility 0.3s ease" : "transform 0.35s cubic-bezier(0.34, 1.15, 0.64, 1), opacity 0.3s ease, visibility 0.3s ease",
173
210
  touchAction: "none"
174
211
  };
175
212
  if (toast2.render) {
176
213
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
177
214
  "div",
178
215
  {
179
- style: { transform: dynamicStyle.transform, transition: dynamicStyle.transition, touchAction: "none" },
216
+ style: dynamicStyle,
180
217
  onPointerDown: handlePointerDown,
181
218
  onPointerMove: handlePointerMove,
182
219
  onPointerUp: handlePointerUp,
183
220
  onPointerCancel: handlePointerUp,
184
- onMouseEnter: () => setIsHovered(true),
185
- onMouseLeave: () => setIsHovered(false),
221
+ onMouseEnter: () => setIsItemHovered(true),
222
+ onMouseLeave: () => setIsItemHovered(false),
186
223
  children: toast2.render()
187
224
  }
188
225
  );
@@ -198,23 +235,23 @@ function ToastItem({ toast: toast2 }) {
198
235
  onPointerMove: handlePointerMove,
199
236
  onPointerUp: handlePointerUp,
200
237
  onPointerCancel: handlePointerUp,
201
- onMouseEnter: () => setIsHovered(true),
202
- onMouseLeave: () => setIsHovered(false),
238
+ onMouseEnter: () => setIsItemHovered(true),
239
+ onMouseLeave: () => setIsItemHovered(false),
203
240
  children: [
204
- Icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tf-icon", style: { alignSelf: "flex-start", marginTop: "2px", color: toast2.iconColor }, children: Icon }),
241
+ Icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
242
+ "span",
243
+ {
244
+ className: "tf-icon",
245
+ style: { alignSelf: "flex-start", marginTop: "2px", color: toast2.iconColor },
246
+ children: Icon
247
+ }
248
+ ),
205
249
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "tf-message", style: { flex: 1, display: "flex", flexDirection: "column" }, children: [
206
250
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: toast2.message }),
207
251
  toast2.description && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "tf-description", children: toast2.description }),
208
252
  toast2.progress !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "tf-progress-bg", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "tf-progress-fill", style: { width: `${toast2.progress}%` } }) })
209
253
  ] }),
210
- toast2.action && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
211
- "button",
212
- {
213
- onClick: toast2.action.onClick,
214
- className: "tf-action-btn",
215
- children: toast2.action.label
216
- }
217
- ),
254
+ toast2.action && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: toast2.action.onClick, className: "tf-action-btn", children: toast2.action.label }),
218
255
  toast2.dismissible && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
219
256
  "button",
220
257
  {
@@ -233,6 +270,7 @@ function ToastItem({ toast: toast2 }) {
233
270
  var import_jsx_runtime2 = require("react/jsx-runtime");
234
271
  function Toaster({ theme = "dark" } = {}) {
235
272
  const toasts = useToastStore();
273
+ const [hoveredPos, setHoveredPos] = (0, import_react3.useState)(null);
236
274
  if (typeof window === "undefined") return null;
237
275
  const positions = [
238
276
  "top-left",
@@ -248,7 +286,47 @@ function Toaster({ theme = "dark" } = {}) {
248
286
  }, {});
249
287
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: positions.map((pos) => {
250
288
  if (!groupedToasts[pos].length) return null;
251
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: `tf-toast-container tf-${pos} tf-theme-${theme}`, children: groupedToasts[pos].map((t) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ToastItem, { toast: t }, t.id)) }, pos);
289
+ const isBottom = pos.startsWith("bottom");
290
+ const posToasts = groupedToasts[pos];
291
+ const isExpanded = hoveredPos === pos;
292
+ const count = posToasts.length;
293
+ const PEEK_OFFSET2 = 10;
294
+ const MAX_VISIBLE_STACK = 3;
295
+ const visibleStack = Math.min(count - 1, MAX_VISIBLE_STACK - 1);
296
+ const collapsedExtraHeight = isExpanded ? 0 : visibleStack * PEEK_OFFSET2;
297
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
298
+ "div",
299
+ {
300
+ className: `tf-toast-container tf-${pos} tf-theme-${theme}`,
301
+ style: { pointerEvents: "auto" },
302
+ onMouseEnter: () => setHoveredPos(pos),
303
+ onMouseLeave: () => setHoveredPos(null),
304
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
305
+ "div",
306
+ {
307
+ className: `tf-stack-wrapper ${isExpanded ? "tf-stack-expanded" : "tf-stack-collapsed"}`,
308
+ style: !isExpanded ? {
309
+ position: "relative",
310
+ // Extra padding at bottom (top positions) or top (bottom positions) for peeking
311
+ paddingBottom: !isBottom ? collapsedExtraHeight : 0,
312
+ paddingTop: isBottom ? collapsedExtraHeight : 0
313
+ } : { display: "flex", flexDirection: "column", gap: "10px" },
314
+ children: posToasts.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
315
+ ToastItem,
316
+ {
317
+ toast: t,
318
+ index: i,
319
+ total: count,
320
+ isExpanded,
321
+ isBottom
322
+ },
323
+ t.id
324
+ ))
325
+ }
326
+ )
327
+ },
328
+ pos
329
+ );
252
330
  }) });
253
331
  }
254
332
  // Annotate the CommonJS export names for ESM import in node:
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/useToast.ts","../../core/src/store.ts","../../core/src/toast.ts","../src/ToastItem.tsx","../src/Toaster.tsx"],"sourcesContent":["export { Toaster } from \"./Toaster\";\r\nexport { toast } from \"../../core/src\";\r\n","import { useEffect, useState } from \"react\";\r\nimport { toastStore } from \"../../core/src\";\r\n\r\nexport function useToastStore() {\r\n const [toasts, setToasts] = useState(toastStore.getToasts());\r\n\r\n useEffect(() => {\r\n return toastStore.subscribe(() => {\r\n setToasts([...toastStore.getToasts()]);\r\n });\r\n }, []);\r\n\r\n return toasts;\r\n}\r\n","import { Toast } from \"./types\";\r\n\r\ntype Listener = () => void;\r\n\r\nclass ToastStore {\r\n private toasts: Toast[] = [];\r\n private listeners: Listener[] = [];\r\n\r\n subscribe(listener: Listener) {\r\n this.listeners.push(listener);\r\n return () => {\r\n this.listeners = this.listeners.filter((l) => l !== listener);\r\n };\r\n }\r\n\r\n getToasts() {\r\n return this.toasts;\r\n }\r\n\r\n add(toast: Toast) {\r\n this.toasts = [toast, ...this.toasts];\r\n this.emit();\r\n }\r\n\r\n remove(id: string) {\r\n this.toasts = this.toasts.filter((t) => t.id !== id);\r\n this.emit();\r\n }\r\n\r\n private emit() {\r\n this.listeners.forEach((l) => l());\r\n }\r\n}\r\n\r\nexport const toastStore = new ToastStore();\r\n","import { toastStore } from \"./store\";\nimport { Toast, ToastType } from \"./types\";\n\nexport type ToastOptions = Partial<Omit<Toast, \"id\" | \"type\" | \"createdAt\">>;\n\nfunction createToast(message: string | undefined, type: ToastType, options?: ToastOptions) {\n const id = crypto.randomUUID();\n\n toastStore.add({\n id,\n message,\n type,\n createdAt: Date.now(),\n ...options,\n });\n\n return id;\n}\n\nconst toastFn = (msg: string | undefined, type: ToastType = \"default\", options?: ToastOptions) => createToast(msg, type, options);\n\ntoastFn.success = (msg: string, options?: ToastOptions) => createToast(msg, \"success\", options);\ntoastFn.error = (msg: string, options?: ToastOptions) => createToast(msg, \"error\", options);\ntoastFn.info = (msg: string, options?: ToastOptions) => createToast(msg, \"info\", options);\ntoastFn.warning = (msg: string, options?: ToastOptions) => createToast(msg, \"warning\", options);\ntoastFn.loading = (msg: string, options?: ToastOptions) => createToast(msg, \"loading\", options);\ntoastFn.default = (msg: string, options?: ToastOptions) => createToast(msg, \"default\", options);\ntoastFn.custom = (options: ToastOptions) => createToast(options.message, \"default\", options);\n\ntoastFn.dismiss = (id: string) => toastStore.remove(id);\n\nexport const toast = toastFn;\n","import React, { useRef, useState, useEffect } from \"react\";\nimport { Toast, toast as toastLib } from \"../../core/src\";\n\nconst icons = {\n success: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 48 48\">\n <rect width=\"48\" height=\"48\" fill=\"none\" />\n <g fill=\"none\" stroke=\"currentColor\" strokeLinejoin=\"round\" strokeWidth=\"4\">\n <path d=\"M24 44a19.94 19.94 0 0 0 14.142-5.858A19.94 19.94 0 0 0 44 24a19.94 19.94 0 0 0-5.858-14.142A19.94 19.94 0 0 0 24 4A19.94 19.94 0 0 0 9.858 9.858A19.94 19.94 0 0 0 4 24a19.94 19.94 0 0 0 5.858 14.142A19.94 19.94 0 0 0 24 44Z\" />\n <path strokeLinecap=\"round\" d=\"m16 24l6 6l12-12\" />\n </g>\n </svg>\n ),\n info: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\">\n <rect width=\"24\" height=\"24\" fill=\"none\" />\n <path fill=\"currentColor\" d=\"M12.002 1.999c5.523 0 10.001 4.478 10.001 10.002c0 5.523-4.478 10.001-10.001 10.001C6.478 22.002 2 17.524 2 12.001C2 6.477 6.478 1.999 12.002 1.999m0 1.5a8.502 8.502 0 1 0 0 17.003a8.502 8.502 0 0 0 0-17.003M12 10.5a.75.75 0 0 1 .75.75v5a.75.75 0 0 1-1.5 0v-5a.75.75 0 0 1 .75-.75M12 9a1 1 0 1 0 0-2a1 1 0 0 0 0 2\" />\n </svg>\n ),\n warning: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 256 256\">\n <rect width=\"256\" height=\"256\" fill=\"none\" />\n <path fill=\"currentColor\" d=\"M236.8 188.09L149.35 36.22a24.76 24.76 0 0 0-42.7 0L19.2 188.09a23.51 23.51 0 0 0 0 23.72A24.35 24.35 0 0 0 40.55 224h174.9a24.35 24.35 0 0 0 21.33-12.19a23.51 23.51 0 0 0 .02-23.72m-13.87 15.71a8.5 8.5 0 0 1-7.48 4.2H40.55a8.5 8.5 0 0 1-7.48-4.2a7.59 7.59 0 0 1 0-7.72l87.45-151.87a8.75 8.75 0 0 1 15 0l87.45 151.87a7.59 7.59 0 0 1-.04 7.72M120 144v-40a8 8 0 0 1 16 0v40a8 8 0 0 1-16 0m20 36a12 12 0 1 1-12-12a12 12 0 0 1 12 12\" />\n </svg>\n ),\n error: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 16 16\">\n <rect width=\"16\" height=\"16\" fill=\"none\" />\n <path fill=\"currentColor\" d=\"M8 1C4.14 1 1 4.14 1 8s3.14 7 7 7s7-3.14 7-7s-3.14-7-7-7m0 13c-3.309 0-6-2.691-6-6s2.691-6 6-6s6 2.691 6 6s-2.691 6-6 6m2.854-8.146L8.708 8l2.146 2.146a.5.5 0 0 1-.708.707L8 8.707l-2.146 2.146a.5.5 0 0 1-.708 0a.5.5 0 0 1 0-.707L7.292 8L5.146 5.854a.5.5 0 0 1 .707-.707l2.146 2.146l2.146-2.146a.5.5 0 0 1 .707.707z\" />\n </svg>\n ),\n loading: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\">\n <rect width=\"24\" height=\"24\" fill=\"none\" />\n <path fill=\"none\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M12 3c4.97 0 9 4.03 9 9\">\n <animateTransform attributeName=\"transform\" dur=\"1.5s\" repeatCount=\"indefinite\" type=\"rotate\" values=\"0 12 12;360 12 12\" />\n </path>\n </svg>\n ),\n default: null,\n};\n\nexport function ToastItem({ toast }: { toast: Toast }) {\n const duration = toast.duration ?? 3000;\n const [offset, setOffset] = useState(0);\n const [isDragging, setIsDragging] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n const dragStartX = useRef<number | null>(null);\n\n const remainingTime = useRef(duration);\n const startTime = useRef(Date.now());\n\n useEffect(() => {\n if (duration === Infinity || duration <= 0) return;\n\n if (!isHovered && !isDragging) {\n startTime.current = Date.now();\n const timer = setTimeout(() => {\n toastLib.dismiss(toast.id);\n }, remainingTime.current);\n\n return () => {\n clearTimeout(timer);\n remainingTime.current -= Date.now() - startTime.current;\n };\n }\n }, [isHovered, isDragging, duration, toast.id]);\n\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n if ((e.target as HTMLElement).closest('button')) return;\n dragStartX.current = e.clientX;\n setIsDragging(true);\n e.currentTarget.setPointerCapture(e.pointerId);\n };\n\n const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!isDragging || dragStartX.current === null) return;\n const deltaX = e.clientX - dragStartX.current;\n \n const pos = toast.position || \"top-right\";\n if (pos.includes(\"right\") && deltaX < 0) return;\n if (pos.includes(\"left\") && deltaX > 0) return;\n\n setOffset(deltaX);\n };\n\n const handlePointerUp = () => {\n if (!isDragging) return;\n setIsDragging(false);\n dragStartX.current = null;\n \n // Dismiss if swiped more than 50px\n if (Math.abs(offset) > 50) {\n toastLib.dismiss(toast.id);\n } else {\n setOffset(0);\n }\n };\n\n const dynamicStyle = {\n ...toast.style,\n transform: offset ? `translateX(${offset}px)` : undefined,\n transition: isDragging ? \"none\" : \"transform 0.2s ease\",\n touchAction: 'none' as const\n };\n\n if (toast.render) {\n return (\n <div \n style={{ transform: dynamicStyle.transform, transition: dynamicStyle.transition, touchAction: 'none' }}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n {toast.render()}\n </div>\n );\n }\n\n const defaultIcon = icons[toast.type as keyof typeof icons] || null;\n const Icon = toast.icon !== undefined ? toast.icon : defaultIcon;\n\n return (\n <div \n className={`tf-toast tf-toast-${toast.type} ${toast.className || \"\"}`}\n style={dynamicStyle}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n {Icon && <span className=\"tf-icon\" style={{ alignSelf: 'flex-start', marginTop: '2px', color: toast.iconColor }}>{Icon}</span>}\n <div className=\"tf-message\" style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>\n <span>{toast.message}</span>\n {toast.description && <span className=\"tf-description\">{toast.description}</span>}\n {toast.progress !== undefined && (\n <div className=\"tf-progress-bg\">\n <div className=\"tf-progress-fill\" style={{ width: `${toast.progress}%` }} />\n </div>\n )}\n </div>\n\n {toast.action && (\n <button \n onClick={toast.action.onClick}\n className=\"tf-action-btn\"\n >\n {toast.action.label}\n </button>\n )}\n\n {toast.dismissible && (\n <button \n title=\"Dismiss\"\n onClick={() => toastLib.dismiss(toast.id)}\n className=\"tf-close-btn\"\n >\n ✖\n </button>\n )}\n </div>\n );\n}\n","\"use client\";\r\n\r\nimport React from \"react\";\r\nimport { useToastStore } from \"./useToast\";\r\nimport { ToastItem } from \"./ToastItem\";\r\n\r\nexport function Toaster({ theme = \"dark\" }: { theme?: \"light\" | \"dark\" } = {}) {\r\n const toasts = useToastStore();\r\n\r\n if (typeof window === \"undefined\") return null;\r\n\r\n const positions = [\r\n \"top-left\",\r\n \"top-center\",\r\n \"top-right\",\r\n \"bottom-left\",\r\n \"bottom-center\",\r\n \"bottom-right\",\r\n ];\r\n\r\n const groupedToasts = positions.reduce((acc, pos) => {\r\n acc[pos] = toasts.filter((t: any) => (t.position || \"top-right\") === pos);\r\n return acc;\r\n }, {} as Record<string, typeof toasts>);\r\n\r\n return (\r\n <>\r\n {positions.map((pos) => {\r\n if (!groupedToasts[pos].length) return null;\r\n\r\n return (\r\n <div key={pos} className={`tf-toast-container tf-${pos} tf-theme-${theme}`}>\r\n {groupedToasts[pos].map((t: any) => (\r\n <ToastItem key={t.id} toast={t} />\r\n ))}\r\n </div>\r\n );\r\n })}\r\n </>\r\n );\r\n}\r\n"],"mappings":"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","names":["toast","import_react","toast","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/Toaster.tsx","../src/useToast.ts","../../core/src/store.ts","../../core/src/toast.ts","../src/ToastItem.tsx"],"sourcesContent":["export { Toaster } from \"./Toaster\";\r\nexport { toast } from \"@toastflux/core\";\r\n","\"use client\";\n\nimport React, { useState } from \"react\";\nimport { useToastStore } from \"./useToast\";\nimport { ToastItem } from \"./ToastItem\";\n\nexport function Toaster({ theme = \"dark\" }: { theme?: \"light\" | \"dark\" } = {}) {\n const toasts = useToastStore();\n const [hoveredPos, setHoveredPos] = useState<string | null>(null);\n\n if (typeof window === \"undefined\") return null;\n\n const positions = [\n \"top-left\",\n \"top-center\",\n \"top-right\",\n \"bottom-left\",\n \"bottom-center\",\n \"bottom-right\",\n ];\n\n const groupedToasts = positions.reduce((acc, pos) => {\n acc[pos] = toasts.filter((t: any) => (t.position || \"top-right\") === pos);\n return acc;\n }, {} as Record<string, typeof toasts>);\n\n return (\n <>\n {positions.map((pos) => {\n if (!groupedToasts[pos].length) return null;\n\n const isBottom = pos.startsWith(\"bottom\");\n const posToasts = groupedToasts[pos];\n const isExpanded = hoveredPos === pos;\n const count = posToasts.length;\n\n // How much extra space to show \"peeking\" toasts behind\n // Each subsequent toast peeks 10px further away\n const PEEK_OFFSET = 10;\n const MAX_VISIBLE_STACK = 3;\n const visibleStack = Math.min(count - 1, MAX_VISIBLE_STACK - 1);\n\n // collapsed container height accounts for peeking\n const collapsedExtraHeight = isExpanded ? 0 : visibleStack * PEEK_OFFSET;\n\n return (\n <div\n key={pos}\n className={`tf-toast-container tf-${pos} tf-theme-${theme}`}\n style={{ pointerEvents: \"auto\" }}\n onMouseEnter={() => setHoveredPos(pos)}\n onMouseLeave={() => setHoveredPos(null)}\n >\n {/* Stack wrapper: relative container so absolute toasts position correctly */}\n <div\n className={`tf-stack-wrapper ${isExpanded ? \"tf-stack-expanded\" : \"tf-stack-collapsed\"}`}\n style={\n !isExpanded\n ? {\n position: \"relative\",\n // Extra padding at bottom (top positions) or top (bottom positions) for peeking\n paddingBottom: !isBottom ? collapsedExtraHeight : 0,\n paddingTop: isBottom ? collapsedExtraHeight : 0,\n }\n : { display: \"flex\", flexDirection: \"column\", gap: \"10px\" }\n }\n >\n {posToasts.map((t: any, i: number) => (\n <ToastItem\n key={t.id}\n toast={t}\n index={i}\n total={count}\n isExpanded={isExpanded}\n isBottom={isBottom}\n />\n ))}\n </div>\n </div>\n );\n })}\n </>\n );\n}\n","\"use client\";\r\n\r\nimport { useEffect, useState } from \"react\";\r\nimport { toastStore } from \"@toastflux/core\";\r\n\r\nexport function useToastStore() {\r\n const [toasts, setToasts] = useState(toastStore.getToasts());\r\n\r\n useEffect(() => {\r\n return toastStore.subscribe(() => {\r\n setToasts([...toastStore.getToasts()]);\r\n });\r\n }, []);\r\n\r\n return toasts;\r\n}\r\n","import { Toast } from \"./types\";\r\n\r\ntype Listener = () => void;\r\n\r\nclass ToastStore {\r\n private toasts: Toast[] = [];\r\n private listeners: Listener[] = [];\r\n\r\n subscribe(listener: Listener) {\r\n this.listeners.push(listener);\r\n return () => {\r\n this.listeners = this.listeners.filter((l) => l !== listener);\r\n };\r\n }\r\n\r\n getToasts() {\r\n return this.toasts;\r\n }\r\n\r\n add(toast: Toast) {\r\n this.toasts = [toast, ...this.toasts];\r\n this.emit();\r\n }\r\n\r\n remove(id: string) {\r\n this.toasts = this.toasts.filter((t) => t.id !== id);\r\n this.emit();\r\n }\r\n\r\n private emit() {\r\n this.listeners.forEach((l) => l());\r\n }\r\n}\r\n\r\nexport const toastStore = new ToastStore();\r\n","import { toastStore } from \"./store\";\nimport { Toast, ToastType } from \"./types\";\n\nexport type ToastOptions = Partial<Omit<Toast, \"id\" | \"type\" | \"createdAt\">>;\n\nfunction createToast(message: string | undefined, type: ToastType, options?: ToastOptions) {\n const id = crypto.randomUUID();\n\n toastStore.add({\n id,\n message,\n type,\n createdAt: Date.now(),\n ...options,\n });\n\n return id;\n}\n\nconst toastFn = (msg: string | undefined, type: ToastType = \"default\", options?: ToastOptions) => createToast(msg, type, options);\n\ntoastFn.success = (msg: string, options?: ToastOptions) => createToast(msg, \"success\", options);\ntoastFn.error = (msg: string, options?: ToastOptions) => createToast(msg, \"error\", options);\ntoastFn.info = (msg: string, options?: ToastOptions) => createToast(msg, \"info\", options);\ntoastFn.warning = (msg: string, options?: ToastOptions) => createToast(msg, \"warning\", options);\ntoastFn.loading = (msg: string, options?: ToastOptions) => createToast(msg, \"loading\", options);\ntoastFn.default = (msg: string, options?: ToastOptions) => createToast(msg, \"default\", options);\ntoastFn.custom = (options: ToastOptions) => createToast(options.message, \"default\", options);\n\ntoastFn.dismiss = (id: string) => toastStore.remove(id);\n\nexport const toast = toastFn;\n","\"use client\";\n\nimport React, { useRef, useState, useEffect } from \"react\";\nimport { Toast, toast as toastLib } from \"@toastflux/core\";\n\nconst icons = {\n success: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 48 48\">\n <rect width=\"48\" height=\"48\" fill=\"none\" />\n <g fill=\"none\" stroke=\"currentColor\" strokeLinejoin=\"round\" strokeWidth=\"4\">\n <path d=\"M24 44a19.94 19.94 0 0 0 14.142-5.858A19.94 19.94 0 0 0 44 24a19.94 19.94 0 0 0-5.858-14.142A19.94 19.94 0 0 0 24 4A19.94 19.94 0 0 0 9.858 9.858A19.94 19.94 0 0 0 4 24a19.94 19.94 0 0 0 5.858 14.142A19.94 19.94 0 0 0 24 44Z\" />\n <path strokeLinecap=\"round\" d=\"m16 24l6 6l12-12\" />\n </g>\n </svg>\n ),\n info: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\">\n <rect width=\"24\" height=\"24\" fill=\"none\" />\n <path fill=\"currentColor\" d=\"M12.002 1.999c5.523 0 10.001 4.478 10.001 10.002c0 5.523-4.478 10.001-10.001 10.001C6.478 22.002 2 17.524 2 12.001C2 6.477 6.478 1.999 12.002 1.999m0 1.5a8.502 8.502 0 1 0 0 17.003a8.502 8.502 0 0 0 0-17.003M12 10.5a.75.75 0 0 1 .75.75v5a.75.75 0 0 1-1.5 0v-5a.75.75 0 0 1 .75-.75M12 9a1 1 0 1 0 0-2a1 1 0 0 0 0 2\" />\n </svg>\n ),\n warning: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 256 256\">\n <rect width=\"256\" height=\"256\" fill=\"none\" />\n <path fill=\"currentColor\" d=\"M236.8 188.09L149.35 36.22a24.76 24.76 0 0 0-42.7 0L19.2 188.09a23.51 23.51 0 0 0 0 23.72A24.35 24.35 0 0 0 40.55 224h174.9a24.35 24.35 0 0 0 21.33-12.19a23.51 23.51 0 0 0 .02-23.72m-13.87 15.71a8.5 8.5 0 0 1-7.48 4.2H40.55a8.5 8.5 0 0 1-7.48-4.2a7.59 7.59 0 0 1 0-7.72l87.45-151.87a8.75 8.75 0 0 1 15 0l87.45 151.87a7.59 7.59 0 0 1-.04 7.72M120 144v-40a8 8 0 0 1 16 0v40a8 8 0 0 1-16 0m20 36a12 12 0 1 1-12-12a12 12 0 0 1 12 12\" />\n </svg>\n ),\n error: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 16 16\">\n <rect width=\"16\" height=\"16\" fill=\"none\" />\n <path fill=\"currentColor\" d=\"M8 1C4.14 1 1 4.14 1 8s3.14 7 7 7s7-3.14 7-7s-3.14-7-7-7m0 13c-3.309 0-6-2.691-6-6s2.691-6 6-6s6 2.691 6 6s-2.691 6-6 6m2.854-8.146L8.708 8l2.146 2.146a.5.5 0 0 1-.708.707L8 8.707l-2.146 2.146a.5.5 0 0 1-.708 0a.5.5 0 0 1 0-.707L7.292 8L5.146 5.854a.5.5 0 0 1 .707-.707l2.146 2.146l2.146-2.146a.5.5 0 0 1 .707.707z\" />\n </svg>\n ),\n loading: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\">\n <rect width=\"24\" height=\"24\" fill=\"none\" />\n <path fill=\"none\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M12 3c4.97 0 9 4.03 9 9\">\n <animateTransform attributeName=\"transform\" dur=\"1.5s\" repeatCount=\"indefinite\" type=\"rotate\" values=\"0 12 12;360 12 12\" />\n </path>\n </svg>\n ),\n default: null,\n};\n\ninterface ToastItemProps {\n toast: Toast;\n index: number;\n total: number;\n isExpanded: boolean;\n isBottom: boolean;\n}\n\nconst MAX_STACK_VISIBLE = 3;\nconst PEEK_OFFSET = 10;\nconst SCALE_STEP = 0.05;\nconst OPACITY_STEP = 0.15;\n\nexport function ToastItem({ toast, index, total, isExpanded, isBottom }: ToastItemProps) {\n const duration = toast.duration ?? 3000;\n const [offset, setOffset] = useState(0);\n const [isDragging, setIsDragging] = useState(false);\n const [isItemHovered, setIsItemHovered] = useState(false);\n const dragStartX = useRef<number | null>(null);\n\n const remainingTime = useRef(duration);\n const startTime = useRef(Date.now());\n\n const isPaused = isExpanded || isItemHovered || isDragging;\n\n useEffect(() => {\n if (duration === Infinity || duration <= 0) return;\n if (isPaused) return;\n\n startTime.current = Date.now();\n const timer = setTimeout(() => {\n toastLib.dismiss(toast.id);\n }, remainingTime.current);\n\n return () => {\n clearTimeout(timer);\n remainingTime.current -= Date.now() - startTime.current;\n };\n }, [isPaused, duration, toast.id]);\n\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!isExpanded && index !== 0) return;\n if ((e.target as HTMLElement).closest('button')) return;\n dragStartX.current = e.clientX;\n setIsDragging(true);\n e.currentTarget.setPointerCapture(e.pointerId);\n };\n\n const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!isDragging || dragStartX.current === null) return;\n const deltaX = e.clientX - dragStartX.current;\n\n const pos = toast.position || \"top-right\";\n if (pos.includes(\"right\") && deltaX < 0) return;\n if (pos.includes(\"left\") && deltaX > 0) return;\n\n setOffset(deltaX);\n };\n\n const handlePointerUp = () => {\n if (!isDragging) return;\n setIsDragging(false);\n dragStartX.current = null;\n\n if (Math.abs(offset) > 50) {\n toastLib.dismiss(toast.id);\n } else {\n setOffset(0);\n }\n };\n\n const stackDepth = index;\n const isHidden = stackDepth >= MAX_STACK_VISIBLE;\n const scale = 1 - stackDepth * SCALE_STEP;\n const peekY = stackDepth * PEEK_OFFSET * (isBottom ? -1 : 1);\n const opacity = isHidden ? 0 : 1 - stackDepth * OPACITY_STEP;\n\n let containerStyle: React.CSSProperties;\n\n if (!isExpanded) {\n containerStyle = {\n position: \"absolute\",\n top: isBottom ? undefined : 0,\n bottom: isBottom ? 0 : undefined,\n left: 0,\n right: 0,\n transform: `translateY(${peekY}px) scale(${scale})${offset ? ` translateX(${offset}px)` : \"\"}`,\n opacity,\n zIndex: total - stackDepth,\n visibility: isHidden ? \"hidden\" : \"visible\",\n pointerEvents: index === 0 ? \"auto\" : \"none\",\n transformOrigin: isBottom ? \"bottom center\" : \"top center\",\n };\n } else {\n containerStyle = {\n position: \"relative\",\n transform: offset ? `translateX(${offset}px)` : undefined,\n opacity: 1,\n zIndex: total - stackDepth,\n pointerEvents: \"auto\",\n };\n }\n\n const dynamicStyle: React.CSSProperties = {\n ...toast.style,\n ...containerStyle,\n transition: isDragging\n ? \"opacity 0.3s ease, visibility 0.3s ease\"\n : \"transform 0.35s cubic-bezier(0.34, 1.15, 0.64, 1), opacity 0.3s ease, visibility 0.3s ease\",\n touchAction: \"none\",\n };\n\n if (toast.render) {\n return (\n <div\n style={dynamicStyle}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onMouseEnter={() => setIsItemHovered(true)}\n onMouseLeave={() => setIsItemHovered(false)}\n >\n {toast.render()}\n </div>\n );\n }\n\n const defaultIcon = icons[toast.type as keyof typeof icons] || null;\n const Icon = toast.icon !== undefined ? toast.icon : defaultIcon;\n\n return (\n <div\n className={`tf-toast tf-toast-${toast.type} ${toast.className || \"\"}`}\n style={dynamicStyle}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onMouseEnter={() => setIsItemHovered(true)}\n onMouseLeave={() => setIsItemHovered(false)}\n >\n {Icon && (\n <span\n className=\"tf-icon\"\n style={{ alignSelf: \"flex-start\", marginTop: \"2px\", color: toast.iconColor }}\n >\n {Icon}\n </span>\n )}\n <div className=\"tf-message\" style={{ flex: 1, display: \"flex\", flexDirection: \"column\" }}>\n <span>{toast.message}</span>\n {toast.description && (\n <span className=\"tf-description\">{toast.description}</span>\n )}\n {toast.progress !== undefined && (\n <div className=\"tf-progress-bg\">\n <div className=\"tf-progress-fill\" style={{ width: `${toast.progress}%` }} />\n </div>\n )}\n </div>\n\n {toast.action && (\n <button onClick={toast.action.onClick} className=\"tf-action-btn\">\n {toast.action.label}\n </button>\n )}\n\n {toast.dismissible && (\n <button\n title=\"Dismiss\"\n onClick={() => toastLib.dismiss(toast.id)}\n className=\"tf-close-btn\"\n >\n ✖\n </button>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","toast","import_react","toast","import_jsx_runtime","PEEK_OFFSET"]}
@@ -1,3 +1,6 @@
1
+ // packages/react/src/Toaster.tsx
2
+ import { useState as useState3 } from "react";
3
+
1
4
  // packages/react/src/useToast.ts
2
5
  import { useEffect, useState } from "react";
3
6
 
@@ -93,29 +96,34 @@ var icons = {
93
96
  ] }),
94
97
  default: null
95
98
  };
96
- function ToastItem({ toast: toast2 }) {
99
+ var MAX_STACK_VISIBLE = 3;
100
+ var PEEK_OFFSET = 10;
101
+ var SCALE_STEP = 0.05;
102
+ var OPACITY_STEP = 0.15;
103
+ function ToastItem({ toast: toast2, index, total, isExpanded, isBottom }) {
97
104
  var _a;
98
105
  const duration = (_a = toast2.duration) != null ? _a : 3e3;
99
106
  const [offset, setOffset] = useState2(0);
100
107
  const [isDragging, setIsDragging] = useState2(false);
101
- const [isHovered, setIsHovered] = useState2(false);
108
+ const [isItemHovered, setIsItemHovered] = useState2(false);
102
109
  const dragStartX = useRef(null);
103
110
  const remainingTime = useRef(duration);
104
111
  const startTime = useRef(Date.now());
112
+ const isPaused = isExpanded || isItemHovered || isDragging;
105
113
  useEffect2(() => {
106
114
  if (duration === Infinity || duration <= 0) return;
107
- if (!isHovered && !isDragging) {
108
- startTime.current = Date.now();
109
- const timer = setTimeout(() => {
110
- toast.dismiss(toast2.id);
111
- }, remainingTime.current);
112
- return () => {
113
- clearTimeout(timer);
114
- remainingTime.current -= Date.now() - startTime.current;
115
- };
116
- }
117
- }, [isHovered, isDragging, duration, toast2.id]);
115
+ if (isPaused) return;
116
+ startTime.current = Date.now();
117
+ const timer = setTimeout(() => {
118
+ toast.dismiss(toast2.id);
119
+ }, remainingTime.current);
120
+ return () => {
121
+ clearTimeout(timer);
122
+ remainingTime.current -= Date.now() - startTime.current;
123
+ };
124
+ }, [isPaused, duration, toast2.id]);
118
125
  const handlePointerDown = (e) => {
126
+ if (!isExpanded && index !== 0) return;
119
127
  if (e.target.closest("button")) return;
120
128
  dragStartX.current = e.clientX;
121
129
  setIsDragging(true);
@@ -139,23 +147,52 @@ function ToastItem({ toast: toast2 }) {
139
147
  setOffset(0);
140
148
  }
141
149
  };
150
+ const stackDepth = index;
151
+ const isHidden = stackDepth >= MAX_STACK_VISIBLE;
152
+ const scale = 1 - stackDepth * SCALE_STEP;
153
+ const peekY = stackDepth * PEEK_OFFSET * (isBottom ? -1 : 1);
154
+ const opacity = isHidden ? 0 : 1 - stackDepth * OPACITY_STEP;
155
+ let containerStyle;
156
+ if (!isExpanded) {
157
+ containerStyle = {
158
+ position: "absolute",
159
+ top: isBottom ? void 0 : 0,
160
+ bottom: isBottom ? 0 : void 0,
161
+ left: 0,
162
+ right: 0,
163
+ transform: `translateY(${peekY}px) scale(${scale})${offset ? ` translateX(${offset}px)` : ""}`,
164
+ opacity,
165
+ zIndex: total - stackDepth,
166
+ visibility: isHidden ? "hidden" : "visible",
167
+ pointerEvents: index === 0 ? "auto" : "none",
168
+ transformOrigin: isBottom ? "bottom center" : "top center"
169
+ };
170
+ } else {
171
+ containerStyle = {
172
+ position: "relative",
173
+ transform: offset ? `translateX(${offset}px)` : void 0,
174
+ opacity: 1,
175
+ zIndex: total - stackDepth,
176
+ pointerEvents: "auto"
177
+ };
178
+ }
142
179
  const dynamicStyle = {
143
180
  ...toast2.style,
144
- transform: offset ? `translateX(${offset}px)` : void 0,
145
- transition: isDragging ? "none" : "transform 0.2s ease",
181
+ ...containerStyle,
182
+ transition: isDragging ? "opacity 0.3s ease, visibility 0.3s ease" : "transform 0.35s cubic-bezier(0.34, 1.15, 0.64, 1), opacity 0.3s ease, visibility 0.3s ease",
146
183
  touchAction: "none"
147
184
  };
148
185
  if (toast2.render) {
149
186
  return /* @__PURE__ */ jsx(
150
187
  "div",
151
188
  {
152
- style: { transform: dynamicStyle.transform, transition: dynamicStyle.transition, touchAction: "none" },
189
+ style: dynamicStyle,
153
190
  onPointerDown: handlePointerDown,
154
191
  onPointerMove: handlePointerMove,
155
192
  onPointerUp: handlePointerUp,
156
193
  onPointerCancel: handlePointerUp,
157
- onMouseEnter: () => setIsHovered(true),
158
- onMouseLeave: () => setIsHovered(false),
194
+ onMouseEnter: () => setIsItemHovered(true),
195
+ onMouseLeave: () => setIsItemHovered(false),
159
196
  children: toast2.render()
160
197
  }
161
198
  );
@@ -171,23 +208,23 @@ function ToastItem({ toast: toast2 }) {
171
208
  onPointerMove: handlePointerMove,
172
209
  onPointerUp: handlePointerUp,
173
210
  onPointerCancel: handlePointerUp,
174
- onMouseEnter: () => setIsHovered(true),
175
- onMouseLeave: () => setIsHovered(false),
211
+ onMouseEnter: () => setIsItemHovered(true),
212
+ onMouseLeave: () => setIsItemHovered(false),
176
213
  children: [
177
- Icon && /* @__PURE__ */ jsx("span", { className: "tf-icon", style: { alignSelf: "flex-start", marginTop: "2px", color: toast2.iconColor }, children: Icon }),
214
+ Icon && /* @__PURE__ */ jsx(
215
+ "span",
216
+ {
217
+ className: "tf-icon",
218
+ style: { alignSelf: "flex-start", marginTop: "2px", color: toast2.iconColor },
219
+ children: Icon
220
+ }
221
+ ),
178
222
  /* @__PURE__ */ jsxs("div", { className: "tf-message", style: { flex: 1, display: "flex", flexDirection: "column" }, children: [
179
223
  /* @__PURE__ */ jsx("span", { children: toast2.message }),
180
224
  toast2.description && /* @__PURE__ */ jsx("span", { className: "tf-description", children: toast2.description }),
181
225
  toast2.progress !== void 0 && /* @__PURE__ */ jsx("div", { className: "tf-progress-bg", children: /* @__PURE__ */ jsx("div", { className: "tf-progress-fill", style: { width: `${toast2.progress}%` } }) })
182
226
  ] }),
183
- toast2.action && /* @__PURE__ */ jsx(
184
- "button",
185
- {
186
- onClick: toast2.action.onClick,
187
- className: "tf-action-btn",
188
- children: toast2.action.label
189
- }
190
- ),
227
+ toast2.action && /* @__PURE__ */ jsx("button", { onClick: toast2.action.onClick, className: "tf-action-btn", children: toast2.action.label }),
191
228
  toast2.dismissible && /* @__PURE__ */ jsx(
192
229
  "button",
193
230
  {
@@ -206,6 +243,7 @@ function ToastItem({ toast: toast2 }) {
206
243
  import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
207
244
  function Toaster({ theme = "dark" } = {}) {
208
245
  const toasts = useToastStore();
246
+ const [hoveredPos, setHoveredPos] = useState3(null);
209
247
  if (typeof window === "undefined") return null;
210
248
  const positions = [
211
249
  "top-left",
@@ -221,7 +259,47 @@ function Toaster({ theme = "dark" } = {}) {
221
259
  }, {});
222
260
  return /* @__PURE__ */ jsx2(Fragment, { children: positions.map((pos) => {
223
261
  if (!groupedToasts[pos].length) return null;
224
- return /* @__PURE__ */ jsx2("div", { className: `tf-toast-container tf-${pos} tf-theme-${theme}`, children: groupedToasts[pos].map((t) => /* @__PURE__ */ jsx2(ToastItem, { toast: t }, t.id)) }, pos);
262
+ const isBottom = pos.startsWith("bottom");
263
+ const posToasts = groupedToasts[pos];
264
+ const isExpanded = hoveredPos === pos;
265
+ const count = posToasts.length;
266
+ const PEEK_OFFSET2 = 10;
267
+ const MAX_VISIBLE_STACK = 3;
268
+ const visibleStack = Math.min(count - 1, MAX_VISIBLE_STACK - 1);
269
+ const collapsedExtraHeight = isExpanded ? 0 : visibleStack * PEEK_OFFSET2;
270
+ return /* @__PURE__ */ jsx2(
271
+ "div",
272
+ {
273
+ className: `tf-toast-container tf-${pos} tf-theme-${theme}`,
274
+ style: { pointerEvents: "auto" },
275
+ onMouseEnter: () => setHoveredPos(pos),
276
+ onMouseLeave: () => setHoveredPos(null),
277
+ children: /* @__PURE__ */ jsx2(
278
+ "div",
279
+ {
280
+ className: `tf-stack-wrapper ${isExpanded ? "tf-stack-expanded" : "tf-stack-collapsed"}`,
281
+ style: !isExpanded ? {
282
+ position: "relative",
283
+ // Extra padding at bottom (top positions) or top (bottom positions) for peeking
284
+ paddingBottom: !isBottom ? collapsedExtraHeight : 0,
285
+ paddingTop: isBottom ? collapsedExtraHeight : 0
286
+ } : { display: "flex", flexDirection: "column", gap: "10px" },
287
+ children: posToasts.map((t, i) => /* @__PURE__ */ jsx2(
288
+ ToastItem,
289
+ {
290
+ toast: t,
291
+ index: i,
292
+ total: count,
293
+ isExpanded,
294
+ isBottom
295
+ },
296
+ t.id
297
+ ))
298
+ }
299
+ )
300
+ },
301
+ pos
302
+ );
225
303
  }) });
226
304
  }
227
305
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/useToast.ts","../../core/src/store.ts","../../core/src/toast.ts","../src/ToastItem.tsx","../src/Toaster.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\r\nimport { toastStore } from \"../../core/src\";\r\n\r\nexport function useToastStore() {\r\n const [toasts, setToasts] = useState(toastStore.getToasts());\r\n\r\n useEffect(() => {\r\n return toastStore.subscribe(() => {\r\n setToasts([...toastStore.getToasts()]);\r\n });\r\n }, []);\r\n\r\n return toasts;\r\n}\r\n","import { Toast } from \"./types\";\r\n\r\ntype Listener = () => void;\r\n\r\nclass ToastStore {\r\n private toasts: Toast[] = [];\r\n private listeners: Listener[] = [];\r\n\r\n subscribe(listener: Listener) {\r\n this.listeners.push(listener);\r\n return () => {\r\n this.listeners = this.listeners.filter((l) => l !== listener);\r\n };\r\n }\r\n\r\n getToasts() {\r\n return this.toasts;\r\n }\r\n\r\n add(toast: Toast) {\r\n this.toasts = [toast, ...this.toasts];\r\n this.emit();\r\n }\r\n\r\n remove(id: string) {\r\n this.toasts = this.toasts.filter((t) => t.id !== id);\r\n this.emit();\r\n }\r\n\r\n private emit() {\r\n this.listeners.forEach((l) => l());\r\n }\r\n}\r\n\r\nexport const toastStore = new ToastStore();\r\n","import { toastStore } from \"./store\";\nimport { Toast, ToastType } from \"./types\";\n\nexport type ToastOptions = Partial<Omit<Toast, \"id\" | \"type\" | \"createdAt\">>;\n\nfunction createToast(message: string | undefined, type: ToastType, options?: ToastOptions) {\n const id = crypto.randomUUID();\n\n toastStore.add({\n id,\n message,\n type,\n createdAt: Date.now(),\n ...options,\n });\n\n return id;\n}\n\nconst toastFn = (msg: string | undefined, type: ToastType = \"default\", options?: ToastOptions) => createToast(msg, type, options);\n\ntoastFn.success = (msg: string, options?: ToastOptions) => createToast(msg, \"success\", options);\ntoastFn.error = (msg: string, options?: ToastOptions) => createToast(msg, \"error\", options);\ntoastFn.info = (msg: string, options?: ToastOptions) => createToast(msg, \"info\", options);\ntoastFn.warning = (msg: string, options?: ToastOptions) => createToast(msg, \"warning\", options);\ntoastFn.loading = (msg: string, options?: ToastOptions) => createToast(msg, \"loading\", options);\ntoastFn.default = (msg: string, options?: ToastOptions) => createToast(msg, \"default\", options);\ntoastFn.custom = (options: ToastOptions) => createToast(options.message, \"default\", options);\n\ntoastFn.dismiss = (id: string) => toastStore.remove(id);\n\nexport const toast = toastFn;\n","import React, { useRef, useState, useEffect } from \"react\";\nimport { Toast, toast as toastLib } from \"../../core/src\";\n\nconst icons = {\n success: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 48 48\">\n <rect width=\"48\" height=\"48\" fill=\"none\" />\n <g fill=\"none\" stroke=\"currentColor\" strokeLinejoin=\"round\" strokeWidth=\"4\">\n <path d=\"M24 44a19.94 19.94 0 0 0 14.142-5.858A19.94 19.94 0 0 0 44 24a19.94 19.94 0 0 0-5.858-14.142A19.94 19.94 0 0 0 24 4A19.94 19.94 0 0 0 9.858 9.858A19.94 19.94 0 0 0 4 24a19.94 19.94 0 0 0 5.858 14.142A19.94 19.94 0 0 0 24 44Z\" />\n <path strokeLinecap=\"round\" d=\"m16 24l6 6l12-12\" />\n </g>\n </svg>\n ),\n info: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\">\n <rect width=\"24\" height=\"24\" fill=\"none\" />\n <path fill=\"currentColor\" d=\"M12.002 1.999c5.523 0 10.001 4.478 10.001 10.002c0 5.523-4.478 10.001-10.001 10.001C6.478 22.002 2 17.524 2 12.001C2 6.477 6.478 1.999 12.002 1.999m0 1.5a8.502 8.502 0 1 0 0 17.003a8.502 8.502 0 0 0 0-17.003M12 10.5a.75.75 0 0 1 .75.75v5a.75.75 0 0 1-1.5 0v-5a.75.75 0 0 1 .75-.75M12 9a1 1 0 1 0 0-2a1 1 0 0 0 0 2\" />\n </svg>\n ),\n warning: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 256 256\">\n <rect width=\"256\" height=\"256\" fill=\"none\" />\n <path fill=\"currentColor\" d=\"M236.8 188.09L149.35 36.22a24.76 24.76 0 0 0-42.7 0L19.2 188.09a23.51 23.51 0 0 0 0 23.72A24.35 24.35 0 0 0 40.55 224h174.9a24.35 24.35 0 0 0 21.33-12.19a23.51 23.51 0 0 0 .02-23.72m-13.87 15.71a8.5 8.5 0 0 1-7.48 4.2H40.55a8.5 8.5 0 0 1-7.48-4.2a7.59 7.59 0 0 1 0-7.72l87.45-151.87a8.75 8.75 0 0 1 15 0l87.45 151.87a7.59 7.59 0 0 1-.04 7.72M120 144v-40a8 8 0 0 1 16 0v40a8 8 0 0 1-16 0m20 36a12 12 0 1 1-12-12a12 12 0 0 1 12 12\" />\n </svg>\n ),\n error: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 16 16\">\n <rect width=\"16\" height=\"16\" fill=\"none\" />\n <path fill=\"currentColor\" d=\"M8 1C4.14 1 1 4.14 1 8s3.14 7 7 7s7-3.14 7-7s-3.14-7-7-7m0 13c-3.309 0-6-2.691-6-6s2.691-6 6-6s6 2.691 6 6s-2.691 6-6 6m2.854-8.146L8.708 8l2.146 2.146a.5.5 0 0 1-.708.707L8 8.707l-2.146 2.146a.5.5 0 0 1-.708 0a.5.5 0 0 1 0-.707L7.292 8L5.146 5.854a.5.5 0 0 1 .707-.707l2.146 2.146l2.146-2.146a.5.5 0 0 1 .707.707z\" />\n </svg>\n ),\n loading: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\">\n <rect width=\"24\" height=\"24\" fill=\"none\" />\n <path fill=\"none\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M12 3c4.97 0 9 4.03 9 9\">\n <animateTransform attributeName=\"transform\" dur=\"1.5s\" repeatCount=\"indefinite\" type=\"rotate\" values=\"0 12 12;360 12 12\" />\n </path>\n </svg>\n ),\n default: null,\n};\n\nexport function ToastItem({ toast }: { toast: Toast }) {\n const duration = toast.duration ?? 3000;\n const [offset, setOffset] = useState(0);\n const [isDragging, setIsDragging] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n const dragStartX = useRef<number | null>(null);\n\n const remainingTime = useRef(duration);\n const startTime = useRef(Date.now());\n\n useEffect(() => {\n if (duration === Infinity || duration <= 0) return;\n\n if (!isHovered && !isDragging) {\n startTime.current = Date.now();\n const timer = setTimeout(() => {\n toastLib.dismiss(toast.id);\n }, remainingTime.current);\n\n return () => {\n clearTimeout(timer);\n remainingTime.current -= Date.now() - startTime.current;\n };\n }\n }, [isHovered, isDragging, duration, toast.id]);\n\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n if ((e.target as HTMLElement).closest('button')) return;\n dragStartX.current = e.clientX;\n setIsDragging(true);\n e.currentTarget.setPointerCapture(e.pointerId);\n };\n\n const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!isDragging || dragStartX.current === null) return;\n const deltaX = e.clientX - dragStartX.current;\n \n const pos = toast.position || \"top-right\";\n if (pos.includes(\"right\") && deltaX < 0) return;\n if (pos.includes(\"left\") && deltaX > 0) return;\n\n setOffset(deltaX);\n };\n\n const handlePointerUp = () => {\n if (!isDragging) return;\n setIsDragging(false);\n dragStartX.current = null;\n \n // Dismiss if swiped more than 50px\n if (Math.abs(offset) > 50) {\n toastLib.dismiss(toast.id);\n } else {\n setOffset(0);\n }\n };\n\n const dynamicStyle = {\n ...toast.style,\n transform: offset ? `translateX(${offset}px)` : undefined,\n transition: isDragging ? \"none\" : \"transform 0.2s ease\",\n touchAction: 'none' as const\n };\n\n if (toast.render) {\n return (\n <div \n style={{ transform: dynamicStyle.transform, transition: dynamicStyle.transition, touchAction: 'none' }}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n {toast.render()}\n </div>\n );\n }\n\n const defaultIcon = icons[toast.type as keyof typeof icons] || null;\n const Icon = toast.icon !== undefined ? toast.icon : defaultIcon;\n\n return (\n <div \n className={`tf-toast tf-toast-${toast.type} ${toast.className || \"\"}`}\n style={dynamicStyle}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n {Icon && <span className=\"tf-icon\" style={{ alignSelf: 'flex-start', marginTop: '2px', color: toast.iconColor }}>{Icon}</span>}\n <div className=\"tf-message\" style={{ flex: 1, display: 'flex', flexDirection: 'column' }}>\n <span>{toast.message}</span>\n {toast.description && <span className=\"tf-description\">{toast.description}</span>}\n {toast.progress !== undefined && (\n <div className=\"tf-progress-bg\">\n <div className=\"tf-progress-fill\" style={{ width: `${toast.progress}%` }} />\n </div>\n )}\n </div>\n\n {toast.action && (\n <button \n onClick={toast.action.onClick}\n className=\"tf-action-btn\"\n >\n {toast.action.label}\n </button>\n )}\n\n {toast.dismissible && (\n <button \n title=\"Dismiss\"\n onClick={() => toastLib.dismiss(toast.id)}\n className=\"tf-close-btn\"\n >\n ✖\n </button>\n )}\n </div>\n );\n}\n","\"use client\";\r\n\r\nimport React from \"react\";\r\nimport { useToastStore } from \"./useToast\";\r\nimport { ToastItem } from \"./ToastItem\";\r\n\r\nexport function Toaster({ theme = \"dark\" }: { theme?: \"light\" | \"dark\" } = {}) {\r\n const toasts = useToastStore();\r\n\r\n if (typeof window === \"undefined\") return null;\r\n\r\n const positions = [\r\n \"top-left\",\r\n \"top-center\",\r\n \"top-right\",\r\n \"bottom-left\",\r\n \"bottom-center\",\r\n \"bottom-right\",\r\n ];\r\n\r\n const groupedToasts = positions.reduce((acc, pos) => {\r\n acc[pos] = toasts.filter((t: any) => (t.position || \"top-right\") === pos);\r\n return acc;\r\n }, {} as Record<string, typeof toasts>);\r\n\r\n return (\r\n <>\r\n {positions.map((pos) => {\r\n if (!groupedToasts[pos].length) return null;\r\n\r\n return (\r\n <div key={pos} className={`tf-toast-container tf-${pos} tf-theme-${theme}`}>\r\n {groupedToasts[pos].map((t: any) => (\r\n <ToastItem key={t.id} toast={t} />\r\n ))}\r\n </div>\r\n );\r\n })}\r\n </>\r\n );\r\n}\r\n"],"mappings":"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","names":["toast","useState","useEffect","toast","useState","useEffect","jsx"]}
1
+ {"version":3,"sources":["../src/Toaster.tsx","../src/useToast.ts","../../core/src/store.ts","../../core/src/toast.ts","../src/ToastItem.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { useState } from \"react\";\nimport { useToastStore } from \"./useToast\";\nimport { ToastItem } from \"./ToastItem\";\n\nexport function Toaster({ theme = \"dark\" }: { theme?: \"light\" | \"dark\" } = {}) {\n const toasts = useToastStore();\n const [hoveredPos, setHoveredPos] = useState<string | null>(null);\n\n if (typeof window === \"undefined\") return null;\n\n const positions = [\n \"top-left\",\n \"top-center\",\n \"top-right\",\n \"bottom-left\",\n \"bottom-center\",\n \"bottom-right\",\n ];\n\n const groupedToasts = positions.reduce((acc, pos) => {\n acc[pos] = toasts.filter((t: any) => (t.position || \"top-right\") === pos);\n return acc;\n }, {} as Record<string, typeof toasts>);\n\n return (\n <>\n {positions.map((pos) => {\n if (!groupedToasts[pos].length) return null;\n\n const isBottom = pos.startsWith(\"bottom\");\n const posToasts = groupedToasts[pos];\n const isExpanded = hoveredPos === pos;\n const count = posToasts.length;\n\n // How much extra space to show \"peeking\" toasts behind\n // Each subsequent toast peeks 10px further away\n const PEEK_OFFSET = 10;\n const MAX_VISIBLE_STACK = 3;\n const visibleStack = Math.min(count - 1, MAX_VISIBLE_STACK - 1);\n\n // collapsed container height accounts for peeking\n const collapsedExtraHeight = isExpanded ? 0 : visibleStack * PEEK_OFFSET;\n\n return (\n <div\n key={pos}\n className={`tf-toast-container tf-${pos} tf-theme-${theme}`}\n style={{ pointerEvents: \"auto\" }}\n onMouseEnter={() => setHoveredPos(pos)}\n onMouseLeave={() => setHoveredPos(null)}\n >\n {/* Stack wrapper: relative container so absolute toasts position correctly */}\n <div\n className={`tf-stack-wrapper ${isExpanded ? \"tf-stack-expanded\" : \"tf-stack-collapsed\"}`}\n style={\n !isExpanded\n ? {\n position: \"relative\",\n // Extra padding at bottom (top positions) or top (bottom positions) for peeking\n paddingBottom: !isBottom ? collapsedExtraHeight : 0,\n paddingTop: isBottom ? collapsedExtraHeight : 0,\n }\n : { display: \"flex\", flexDirection: \"column\", gap: \"10px\" }\n }\n >\n {posToasts.map((t: any, i: number) => (\n <ToastItem\n key={t.id}\n toast={t}\n index={i}\n total={count}\n isExpanded={isExpanded}\n isBottom={isBottom}\n />\n ))}\n </div>\n </div>\n );\n })}\n </>\n );\n}\n","\"use client\";\r\n\r\nimport { useEffect, useState } from \"react\";\r\nimport { toastStore } from \"@toastflux/core\";\r\n\r\nexport function useToastStore() {\r\n const [toasts, setToasts] = useState(toastStore.getToasts());\r\n\r\n useEffect(() => {\r\n return toastStore.subscribe(() => {\r\n setToasts([...toastStore.getToasts()]);\r\n });\r\n }, []);\r\n\r\n return toasts;\r\n}\r\n","import { Toast } from \"./types\";\r\n\r\ntype Listener = () => void;\r\n\r\nclass ToastStore {\r\n private toasts: Toast[] = [];\r\n private listeners: Listener[] = [];\r\n\r\n subscribe(listener: Listener) {\r\n this.listeners.push(listener);\r\n return () => {\r\n this.listeners = this.listeners.filter((l) => l !== listener);\r\n };\r\n }\r\n\r\n getToasts() {\r\n return this.toasts;\r\n }\r\n\r\n add(toast: Toast) {\r\n this.toasts = [toast, ...this.toasts];\r\n this.emit();\r\n }\r\n\r\n remove(id: string) {\r\n this.toasts = this.toasts.filter((t) => t.id !== id);\r\n this.emit();\r\n }\r\n\r\n private emit() {\r\n this.listeners.forEach((l) => l());\r\n }\r\n}\r\n\r\nexport const toastStore = new ToastStore();\r\n","import { toastStore } from \"./store\";\nimport { Toast, ToastType } from \"./types\";\n\nexport type ToastOptions = Partial<Omit<Toast, \"id\" | \"type\" | \"createdAt\">>;\n\nfunction createToast(message: string | undefined, type: ToastType, options?: ToastOptions) {\n const id = crypto.randomUUID();\n\n toastStore.add({\n id,\n message,\n type,\n createdAt: Date.now(),\n ...options,\n });\n\n return id;\n}\n\nconst toastFn = (msg: string | undefined, type: ToastType = \"default\", options?: ToastOptions) => createToast(msg, type, options);\n\ntoastFn.success = (msg: string, options?: ToastOptions) => createToast(msg, \"success\", options);\ntoastFn.error = (msg: string, options?: ToastOptions) => createToast(msg, \"error\", options);\ntoastFn.info = (msg: string, options?: ToastOptions) => createToast(msg, \"info\", options);\ntoastFn.warning = (msg: string, options?: ToastOptions) => createToast(msg, \"warning\", options);\ntoastFn.loading = (msg: string, options?: ToastOptions) => createToast(msg, \"loading\", options);\ntoastFn.default = (msg: string, options?: ToastOptions) => createToast(msg, \"default\", options);\ntoastFn.custom = (options: ToastOptions) => createToast(options.message, \"default\", options);\n\ntoastFn.dismiss = (id: string) => toastStore.remove(id);\n\nexport const toast = toastFn;\n","\"use client\";\n\nimport React, { useRef, useState, useEffect } from \"react\";\nimport { Toast, toast as toastLib } from \"@toastflux/core\";\n\nconst icons = {\n success: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 48 48\">\n <rect width=\"48\" height=\"48\" fill=\"none\" />\n <g fill=\"none\" stroke=\"currentColor\" strokeLinejoin=\"round\" strokeWidth=\"4\">\n <path d=\"M24 44a19.94 19.94 0 0 0 14.142-5.858A19.94 19.94 0 0 0 44 24a19.94 19.94 0 0 0-5.858-14.142A19.94 19.94 0 0 0 24 4A19.94 19.94 0 0 0 9.858 9.858A19.94 19.94 0 0 0 4 24a19.94 19.94 0 0 0 5.858 14.142A19.94 19.94 0 0 0 24 44Z\" />\n <path strokeLinecap=\"round\" d=\"m16 24l6 6l12-12\" />\n </g>\n </svg>\n ),\n info: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\">\n <rect width=\"24\" height=\"24\" fill=\"none\" />\n <path fill=\"currentColor\" d=\"M12.002 1.999c5.523 0 10.001 4.478 10.001 10.002c0 5.523-4.478 10.001-10.001 10.001C6.478 22.002 2 17.524 2 12.001C2 6.477 6.478 1.999 12.002 1.999m0 1.5a8.502 8.502 0 1 0 0 17.003a8.502 8.502 0 0 0 0-17.003M12 10.5a.75.75 0 0 1 .75.75v5a.75.75 0 0 1-1.5 0v-5a.75.75 0 0 1 .75-.75M12 9a1 1 0 1 0 0-2a1 1 0 0 0 0 2\" />\n </svg>\n ),\n warning: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 256 256\">\n <rect width=\"256\" height=\"256\" fill=\"none\" />\n <path fill=\"currentColor\" d=\"M236.8 188.09L149.35 36.22a24.76 24.76 0 0 0-42.7 0L19.2 188.09a23.51 23.51 0 0 0 0 23.72A24.35 24.35 0 0 0 40.55 224h174.9a24.35 24.35 0 0 0 21.33-12.19a23.51 23.51 0 0 0 .02-23.72m-13.87 15.71a8.5 8.5 0 0 1-7.48 4.2H40.55a8.5 8.5 0 0 1-7.48-4.2a7.59 7.59 0 0 1 0-7.72l87.45-151.87a8.75 8.75 0 0 1 15 0l87.45 151.87a7.59 7.59 0 0 1-.04 7.72M120 144v-40a8 8 0 0 1 16 0v40a8 8 0 0 1-16 0m20 36a12 12 0 1 1-12-12a12 12 0 0 1 12 12\" />\n </svg>\n ),\n error: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 16 16\">\n <rect width=\"16\" height=\"16\" fill=\"none\" />\n <path fill=\"currentColor\" d=\"M8 1C4.14 1 1 4.14 1 8s3.14 7 7 7s7-3.14 7-7s-3.14-7-7-7m0 13c-3.309 0-6-2.691-6-6s2.691-6 6-6s6 2.691 6 6s-2.691 6-6 6m2.854-8.146L8.708 8l2.146 2.146a.5.5 0 0 1-.708.707L8 8.707l-2.146 2.146a.5.5 0 0 1-.708 0a.5.5 0 0 1 0-.707L7.292 8L5.146 5.854a.5.5 0 0 1 .707-.707l2.146 2.146l2.146-2.146a.5.5 0 0 1 .707.707z\" />\n </svg>\n ),\n loading: (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\">\n <rect width=\"24\" height=\"24\" fill=\"none\" />\n <path fill=\"none\" stroke=\"currentColor\" strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M12 3c4.97 0 9 4.03 9 9\">\n <animateTransform attributeName=\"transform\" dur=\"1.5s\" repeatCount=\"indefinite\" type=\"rotate\" values=\"0 12 12;360 12 12\" />\n </path>\n </svg>\n ),\n default: null,\n};\n\ninterface ToastItemProps {\n toast: Toast;\n index: number;\n total: number;\n isExpanded: boolean;\n isBottom: boolean;\n}\n\nconst MAX_STACK_VISIBLE = 3;\nconst PEEK_OFFSET = 10;\nconst SCALE_STEP = 0.05;\nconst OPACITY_STEP = 0.15;\n\nexport function ToastItem({ toast, index, total, isExpanded, isBottom }: ToastItemProps) {\n const duration = toast.duration ?? 3000;\n const [offset, setOffset] = useState(0);\n const [isDragging, setIsDragging] = useState(false);\n const [isItemHovered, setIsItemHovered] = useState(false);\n const dragStartX = useRef<number | null>(null);\n\n const remainingTime = useRef(duration);\n const startTime = useRef(Date.now());\n\n const isPaused = isExpanded || isItemHovered || isDragging;\n\n useEffect(() => {\n if (duration === Infinity || duration <= 0) return;\n if (isPaused) return;\n\n startTime.current = Date.now();\n const timer = setTimeout(() => {\n toastLib.dismiss(toast.id);\n }, remainingTime.current);\n\n return () => {\n clearTimeout(timer);\n remainingTime.current -= Date.now() - startTime.current;\n };\n }, [isPaused, duration, toast.id]);\n\n const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!isExpanded && index !== 0) return;\n if ((e.target as HTMLElement).closest('button')) return;\n dragStartX.current = e.clientX;\n setIsDragging(true);\n e.currentTarget.setPointerCapture(e.pointerId);\n };\n\n const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n if (!isDragging || dragStartX.current === null) return;\n const deltaX = e.clientX - dragStartX.current;\n\n const pos = toast.position || \"top-right\";\n if (pos.includes(\"right\") && deltaX < 0) return;\n if (pos.includes(\"left\") && deltaX > 0) return;\n\n setOffset(deltaX);\n };\n\n const handlePointerUp = () => {\n if (!isDragging) return;\n setIsDragging(false);\n dragStartX.current = null;\n\n if (Math.abs(offset) > 50) {\n toastLib.dismiss(toast.id);\n } else {\n setOffset(0);\n }\n };\n\n const stackDepth = index;\n const isHidden = stackDepth >= MAX_STACK_VISIBLE;\n const scale = 1 - stackDepth * SCALE_STEP;\n const peekY = stackDepth * PEEK_OFFSET * (isBottom ? -1 : 1);\n const opacity = isHidden ? 0 : 1 - stackDepth * OPACITY_STEP;\n\n let containerStyle: React.CSSProperties;\n\n if (!isExpanded) {\n containerStyle = {\n position: \"absolute\",\n top: isBottom ? undefined : 0,\n bottom: isBottom ? 0 : undefined,\n left: 0,\n right: 0,\n transform: `translateY(${peekY}px) scale(${scale})${offset ? ` translateX(${offset}px)` : \"\"}`,\n opacity,\n zIndex: total - stackDepth,\n visibility: isHidden ? \"hidden\" : \"visible\",\n pointerEvents: index === 0 ? \"auto\" : \"none\",\n transformOrigin: isBottom ? \"bottom center\" : \"top center\",\n };\n } else {\n containerStyle = {\n position: \"relative\",\n transform: offset ? `translateX(${offset}px)` : undefined,\n opacity: 1,\n zIndex: total - stackDepth,\n pointerEvents: \"auto\",\n };\n }\n\n const dynamicStyle: React.CSSProperties = {\n ...toast.style,\n ...containerStyle,\n transition: isDragging\n ? \"opacity 0.3s ease, visibility 0.3s ease\"\n : \"transform 0.35s cubic-bezier(0.34, 1.15, 0.64, 1), opacity 0.3s ease, visibility 0.3s ease\",\n touchAction: \"none\",\n };\n\n if (toast.render) {\n return (\n <div\n style={dynamicStyle}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onMouseEnter={() => setIsItemHovered(true)}\n onMouseLeave={() => setIsItemHovered(false)}\n >\n {toast.render()}\n </div>\n );\n }\n\n const defaultIcon = icons[toast.type as keyof typeof icons] || null;\n const Icon = toast.icon !== undefined ? toast.icon : defaultIcon;\n\n return (\n <div\n className={`tf-toast tf-toast-${toast.type} ${toast.className || \"\"}`}\n style={dynamicStyle}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onMouseEnter={() => setIsItemHovered(true)}\n onMouseLeave={() => setIsItemHovered(false)}\n >\n {Icon && (\n <span\n className=\"tf-icon\"\n style={{ alignSelf: \"flex-start\", marginTop: \"2px\", color: toast.iconColor }}\n >\n {Icon}\n </span>\n )}\n <div className=\"tf-message\" style={{ flex: 1, display: \"flex\", flexDirection: \"column\" }}>\n <span>{toast.message}</span>\n {toast.description && (\n <span className=\"tf-description\">{toast.description}</span>\n )}\n {toast.progress !== undefined && (\n <div className=\"tf-progress-bg\">\n <div className=\"tf-progress-fill\" style={{ width: `${toast.progress}%` }} />\n </div>\n )}\n </div>\n\n {toast.action && (\n <button onClick={toast.action.onClick} className=\"tf-action-btn\">\n {toast.action.label}\n </button>\n )}\n\n {toast.dismissible && (\n <button\n title=\"Dismiss\"\n onClick={() => toastLib.dismiss(toast.id)}\n className=\"tf-close-btn\"\n >\n ✖\n </button>\n )}\n </div>\n );\n}\n"],"mappings":";AAEA,SAAgB,YAAAA,iBAAgB;;;ACAhC,SAAS,WAAW,gBAAgB;;;ACEpC,IAAM,aAAN,MAAiB;AAAA,EAAjB;AACE,SAAQ,SAAkB,CAAC;AAC3B,SAAQ,YAAwB,CAAC;AAAA;AAAA,EAEjC,UAAU,UAAoB;AAC5B,SAAK,UAAU,KAAK,QAAQ;AAC5B,WAAO,MAAM;AACX,WAAK,YAAY,KAAK,UAAU,OAAO,CAAC,MAAM,MAAM,QAAQ;AAAA,IAC9D;AAAA,EACF;AAAA,EAEA,YAAY;AACV,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAIC,QAAc;AAChB,SAAK,SAAS,CAACA,QAAO,GAAG,KAAK,MAAM;AACpC,SAAK,KAAK;AAAA,EACZ;AAAA,EAEA,OAAO,IAAY;AACjB,SAAK,SAAS,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AACnD,SAAK,KAAK;AAAA,EACZ;AAAA,EAEQ,OAAO;AACb,SAAK,UAAU,QAAQ,CAAC,MAAM,EAAE,CAAC;AAAA,EACnC;AACF;AAEO,IAAM,aAAa,IAAI,WAAW;;;AC7BzC,SAAS,YAAY,SAA6B,MAAiB,SAAwB;AACzF,QAAM,KAAK,OAAO,WAAW;AAE7B,aAAW,IAAI;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,KAAK,IAAI;AAAA,IACpB,GAAG;AAAA,EACL,CAAC;AAED,SAAO;AACT;AAEA,IAAM,UAAU,CAAC,KAAyB,OAAkB,WAAW,YAA2B,YAAY,KAAK,MAAM,OAAO;AAEhI,QAAQ,UAAU,CAAC,KAAa,YAA2B,YAAY,KAAK,WAAW,OAAO;AAC9F,QAAQ,QAAQ,CAAC,KAAa,YAA2B,YAAY,KAAK,SAAS,OAAO;AAC1F,QAAQ,OAAO,CAAC,KAAa,YAA2B,YAAY,KAAK,QAAQ,OAAO;AACxF,QAAQ,UAAU,CAAC,KAAa,YAA2B,YAAY,KAAK,WAAW,OAAO;AAC9F,QAAQ,UAAU,CAAC,KAAa,YAA2B,YAAY,KAAK,WAAW,OAAO;AAC9F,QAAQ,UAAU,CAAC,KAAa,YAA2B,YAAY,KAAK,WAAW,OAAO;AAC9F,QAAQ,SAAS,CAAC,YAA0B,YAAY,QAAQ,SAAS,WAAW,OAAO;AAE3F,QAAQ,UAAU,CAAC,OAAe,WAAW,OAAO,EAAE;AAE/C,IAAM,QAAQ;;;AF1Bd,SAAS,gBAAgB;AAC9B,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,WAAW,UAAU,CAAC;AAE3D,YAAU,MAAM;AACd,WAAO,WAAW,UAAU,MAAM;AAChC,gBAAU,CAAC,GAAG,WAAW,UAAU,CAAC,CAAC;AAAA,IACvC,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,SAAO;AACT;;;AGbA,SAAgB,QAAQ,YAAAC,WAAU,aAAAC,kBAAiB;AAM7C,cACA,YADA;AAHN,IAAM,QAAQ;AAAA,EACZ,SACE,qBAAC,SAAI,OAAM,8BAA6B,OAAM,MAAK,QAAO,MAAK,SAAQ,aACrE;AAAA,wBAAC,UAAK,OAAM,MAAK,QAAO,MAAK,MAAK,QAAO;AAAA,IACzC,qBAAC,OAAE,MAAK,QAAO,QAAO,gBAAe,gBAAe,SAAQ,aAAY,KACtE;AAAA,0BAAC,UAAK,GAAE,oOAAmO;AAAA,MAC3O,oBAAC,UAAK,eAAc,SAAQ,GAAE,oBAAmB;AAAA,OACnD;AAAA,KACF;AAAA,EAEF,MACE,qBAAC,SAAI,OAAM,8BAA6B,OAAM,MAAK,QAAO,MAAK,SAAQ,aACrE;AAAA,wBAAC,UAAK,OAAM,MAAK,QAAO,MAAK,MAAK,QAAO;AAAA,IACzC,oBAAC,UAAK,MAAK,gBAAe,GAAE,6TAA4T;AAAA,KAC1V;AAAA,EAEF,SACE,qBAAC,SAAI,OAAM,8BAA6B,OAAM,MAAK,QAAO,MAAK,SAAQ,eACrE;AAAA,wBAAC,UAAK,OAAM,OAAM,QAAO,OAAM,MAAK,QAAO;AAAA,IAC3C,oBAAC,UAAK,MAAK,gBAAe,GAAE,gbAA+a;AAAA,KAC7c;AAAA,EAEF,OACE,qBAAC,SAAI,OAAM,8BAA6B,OAAM,MAAK,QAAO,MAAK,SAAQ,aACrE;AAAA,wBAAC,UAAK,OAAM,MAAK,QAAO,MAAK,MAAK,QAAO;AAAA,IACzC,oBAAC,UAAK,MAAK,gBAAe,GAAE,8TAA6T;AAAA,KAC3V;AAAA,EAEF,SACE,qBAAC,SAAI,OAAM,8BAA6B,OAAM,MAAK,QAAO,MAAK,SAAQ,aACrE;AAAA,wBAAC,UAAK,OAAM,MAAK,QAAO,MAAK,MAAK,QAAO;AAAA,IACzC,oBAAC,UAAK,MAAK,QAAO,QAAO,gBAAe,eAAc,SAAQ,gBAAe,SAAQ,aAAY,KAAI,GAAE,2BACrG,8BAAC,sBAAiB,eAAc,aAAY,KAAI,QAAO,aAAY,cAAa,MAAK,UAAS,QAAO,qBAAoB,GAC3H;AAAA,KACF;AAAA,EAEF,SAAS;AACX;AAUA,IAAM,oBAAoB;AAC1B,IAAM,cAAc;AACpB,IAAM,aAAa;AACnB,IAAM,eAAe;AAEd,SAAS,UAAU,EAAE,OAAAC,QAAO,OAAO,OAAO,YAAY,SAAS,GAAmB;AAzDzF;AA0DE,QAAM,YAAW,KAAAA,OAAM,aAAN,YAAkB;AACnC,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAAS,CAAC;AACtC,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAS,KAAK;AAClD,QAAM,CAAC,eAAe,gBAAgB,IAAIA,UAAS,KAAK;AACxD,QAAM,aAAa,OAAsB,IAAI;AAE7C,QAAM,gBAAgB,OAAO,QAAQ;AACrC,QAAM,YAAY,OAAO,KAAK,IAAI,CAAC;AAEnC,QAAM,WAAW,cAAc,iBAAiB;AAEhD,EAAAC,WAAU,MAAM;AACd,QAAI,aAAa,YAAY,YAAY,EAAG;AAC5C,QAAI,SAAU;AAEd,cAAU,UAAU,KAAK,IAAI;AAC7B,UAAM,QAAQ,WAAW,MAAM;AAC7B,YAAS,QAAQF,OAAM,EAAE;AAAA,IAC3B,GAAG,cAAc,OAAO;AAExB,WAAO,MAAM;AACX,mBAAa,KAAK;AAClB,oBAAc,WAAW,KAAK,IAAI,IAAI,UAAU;AAAA,IAClD;AAAA,EACF,GAAG,CAAC,UAAU,UAAUA,OAAM,EAAE,CAAC;AAEjC,QAAM,oBAAoB,CAAC,MAA0C;AACnE,QAAI,CAAC,cAAc,UAAU,EAAG;AAChC,QAAK,EAAE,OAAuB,QAAQ,QAAQ,EAAG;AACjD,eAAW,UAAU,EAAE;AACvB,kBAAc,IAAI;AAClB,MAAE,cAAc,kBAAkB,EAAE,SAAS;AAAA,EAC/C;AAEA,QAAM,oBAAoB,CAAC,MAA0C;AACnE,QAAI,CAAC,cAAc,WAAW,YAAY,KAAM;AAChD,UAAM,SAAS,EAAE,UAAU,WAAW;AAEtC,UAAM,MAAMA,OAAM,YAAY;AAC9B,QAAI,IAAI,SAAS,OAAO,KAAK,SAAS,EAAG;AACzC,QAAI,IAAI,SAAS,MAAM,KAAK,SAAS,EAAG;AAExC,cAAU,MAAM;AAAA,EAClB;AAEA,QAAM,kBAAkB,MAAM;AAC5B,QAAI,CAAC,WAAY;AACjB,kBAAc,KAAK;AACnB,eAAW,UAAU;AAErB,QAAI,KAAK,IAAI,MAAM,IAAI,IAAI;AACzB,YAAS,QAAQA,OAAM,EAAE;AAAA,IAC3B,OAAO;AACL,gBAAU,CAAC;AAAA,IACb;AAAA,EACF;AAEA,QAAM,aAAa;AACnB,QAAM,WAAW,cAAc;AAC/B,QAAM,QAAQ,IAAI,aAAa;AAC/B,QAAM,QAAQ,aAAa,eAAe,WAAW,KAAK;AAC1D,QAAM,UAAU,WAAW,IAAI,IAAI,aAAa;AAEhD,MAAI;AAEJ,MAAI,CAAC,YAAY;AACf,qBAAiB;AAAA,MACf,UAAU;AAAA,MACV,KAAK,WAAW,SAAY;AAAA,MAC5B,QAAQ,WAAW,IAAI;AAAA,MACvB,MAAM;AAAA,MACN,OAAO;AAAA,MACP,WAAW,cAAc,KAAK,aAAa,KAAK,IAAI,SAAS,eAAe,MAAM,QAAQ,EAAE;AAAA,MAC5F;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB,YAAY,WAAW,WAAW;AAAA,MAClC,eAAe,UAAU,IAAI,SAAS;AAAA,MACtC,iBAAiB,WAAW,kBAAkB;AAAA,IAChD;AAAA,EACF,OAAO;AACL,qBAAiB;AAAA,MACf,UAAU;AAAA,MACV,WAAW,SAAS,cAAc,MAAM,QAAQ;AAAA,MAChD,SAAS;AAAA,MACT,QAAQ,QAAQ;AAAA,MAChB,eAAe;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,eAAoC;AAAA,IACxC,GAAGA,OAAM;AAAA,IACT,GAAG;AAAA,IACH,YAAY,aACR,4CACA;AAAA,IACJ,aAAa;AAAA,EACf;AAEA,MAAIA,OAAM,QAAQ;AAChB,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,eAAe;AAAA,QACf,eAAe;AAAA,QACf,aAAa;AAAA,QACb,iBAAiB;AAAA,QACjB,cAAc,MAAM,iBAAiB,IAAI;AAAA,QACzC,cAAc,MAAM,iBAAiB,KAAK;AAAA,QAEzC,UAAAA,OAAM,OAAO;AAAA;AAAA,IAChB;AAAA,EAEJ;AAEA,QAAM,cAAc,MAAMA,OAAM,IAA0B,KAAK;AAC/D,QAAM,OAAOA,OAAM,SAAS,SAAYA,OAAM,OAAO;AAErD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,qBAAqBA,OAAM,IAAI,IAAIA,OAAM,aAAa,EAAE;AAAA,MACnE,OAAO;AAAA,MACP,eAAe;AAAA,MACf,eAAe;AAAA,MACf,aAAa;AAAA,MACb,iBAAiB;AAAA,MACjB,cAAc,MAAM,iBAAiB,IAAI;AAAA,MACzC,cAAc,MAAM,iBAAiB,KAAK;AAAA,MAEzC;AAAA,gBACC;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,WAAW,cAAc,WAAW,OAAO,OAAOA,OAAM,UAAU;AAAA,YAE1E;AAAA;AAAA,QACH;AAAA,QAEF,qBAAC,SAAI,WAAU,cAAa,OAAO,EAAE,MAAM,GAAG,SAAS,QAAQ,eAAe,SAAS,GACrF;AAAA,8BAAC,UAAM,UAAAA,OAAM,SAAQ;AAAA,UACpBA,OAAM,eACL,oBAAC,UAAK,WAAU,kBAAkB,UAAAA,OAAM,aAAY;AAAA,UAErDA,OAAM,aAAa,UAClB,oBAAC,SAAI,WAAU,kBACb,8BAAC,SAAI,WAAU,oBAAmB,OAAO,EAAE,OAAO,GAAGA,OAAM,QAAQ,IAAI,GAAG,GAC5E;AAAA,WAEJ;AAAA,QAECA,OAAM,UACL,oBAAC,YAAO,SAASA,OAAM,OAAO,SAAS,WAAU,iBAC9C,UAAAA,OAAM,OAAO,OAChB;AAAA,QAGDA,OAAM,eACL;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN,SAAS,MAAM,MAAS,QAAQA,OAAM,EAAE;AAAA,YACxC,WAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AJpMI,mBAyCY,OAAAG,YAzCZ;AArBG,SAAS,QAAQ,EAAE,QAAQ,OAAO,IAAkC,CAAC,GAAG;AAC7E,QAAM,SAAS,cAAc;AAC7B,QAAM,CAAC,YAAY,aAAa,IAAIC,UAAwB,IAAI;AAEhE,MAAI,OAAO,WAAW,YAAa,QAAO;AAE1C,QAAM,YAAY;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,gBAAgB,UAAU,OAAO,CAAC,KAAK,QAAQ;AACnD,QAAI,GAAG,IAAI,OAAO,OAAO,CAAC,OAAY,EAAE,YAAY,iBAAiB,GAAG;AACxE,WAAO;AAAA,EACT,GAAG,CAAC,CAAkC;AAEtC,SACE,gBAAAD,KAAA,YACG,oBAAU,IAAI,CAAC,QAAQ;AACtB,QAAI,CAAC,cAAc,GAAG,EAAE,OAAQ,QAAO;AAEvC,UAAM,WAAW,IAAI,WAAW,QAAQ;AACxC,UAAM,YAAY,cAAc,GAAG;AACnC,UAAM,aAAa,eAAe;AAClC,UAAM,QAAQ,UAAU;AAIxB,UAAME,eAAc;AACpB,UAAM,oBAAoB;AAC1B,UAAM,eAAe,KAAK,IAAI,QAAQ,GAAG,oBAAoB,CAAC;AAG9D,UAAM,uBAAuB,aAAa,IAAI,eAAeA;AAE7D,WACE,gBAAAF;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,yBAAyB,GAAG,aAAa,KAAK;AAAA,QACzD,OAAO,EAAE,eAAe,OAAO;AAAA,QAC/B,cAAc,MAAM,cAAc,GAAG;AAAA,QACrC,cAAc,MAAM,cAAc,IAAI;AAAA,QAGtC,0BAAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,oBAAoB,aAAa,sBAAsB,oBAAoB;AAAA,YACtF,OACE,CAAC,aACG;AAAA,cACE,UAAU;AAAA;AAAA,cAEV,eAAe,CAAC,WAAW,uBAAuB;AAAA,cAClD,YAAY,WAAW,uBAAuB;AAAA,YAChD,IACA,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,OAAO;AAAA,YAG7D,oBAAU,IAAI,CAAC,GAAQ,MACtB,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBAEC,OAAO;AAAA,gBACP,OAAO;AAAA,gBACP,OAAO;AAAA,gBACP;AAAA,gBACA;AAAA;AAAA,cALK,EAAE;AAAA,YAMT,CACD;AAAA;AAAA,QACH;AAAA;AAAA,MA9BK;AAAA,IA+BP;AAAA,EAEJ,CAAC,GACH;AAEJ;","names":["useState","toast","useState","useEffect","toast","useState","useEffect","jsx","useState","PEEK_OFFSET"]}
@@ -1,174 +1,202 @@
1
- .tf-toast-container {
2
- position: fixed;
3
- z-index: 9999;
4
- display: flex;
5
- flex-direction: column;
6
- gap: 12px;
7
- pointer-events: none;
8
- }
9
-
10
- .tf-toast-container > * {
11
- pointer-events: auto;
12
- }
13
-
14
- .tf-top-left {
15
- top: 20px;
16
- left: 20px;
17
- align-items: flex-start;
18
- }
19
- .tf-top-center {
20
- top: 20px;
21
- left: 50%;
22
- transform: translateX(-50%);
23
- align-items: center;
24
- }
25
- .tf-top-right {
26
- top: 20px;
27
- right: 20px;
28
- align-items: flex-end;
29
- }
30
- .tf-bottom-left {
31
- bottom: 20px;
32
- left: 20px;
33
- flex-direction: column-reverse;
34
- align-items: flex-start;
35
- }
36
- .tf-bottom-center {
37
- bottom: 20px;
38
- left: 50%;
39
- transform: translateX(-50%);
40
- flex-direction: column-reverse;
41
- align-items: center;
42
- }
43
- .tf-bottom-right {
44
- bottom: 20px;
45
- right: 20px;
46
- flex-direction: column-reverse;
47
- align-items: flex-end;
48
- }
49
-
50
- .tf-toast {
51
- display: flex;
52
- align-items: center;
53
- gap: 12px;
54
- padding: 12px 16px;
55
- background: #0f0f0f;
56
- border: 1px solid #2a2a2a;
57
- border-radius: 8px;
58
- color: #f1f1f1;
59
- font-size: 14px;
60
- font-family: var(
61
- --tf-font-family,
62
- system-ui,
63
- -apple-system,
64
- BlinkMacSystemFont,
65
- "Segoe UI",
66
- Roboto,
67
- "Helvetica Neue",
68
- Arial,
69
- sans-serif
70
- );
71
- font-weight: 500;
72
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
73
- animation: tf-fadeIn 0.2s ease-out;
74
- min-width: 320px;
75
- }
76
-
77
- .tf-icon {
78
- display: flex;
79
- align-items: center;
80
- justify-content: center;
81
- color: #f1f1f1;
82
- }
83
-
84
- .tf-message {
85
- text-align: left;
86
- flex: 1;
87
- }
88
-
89
- .tf-description {
90
- font-size: 13px;
91
- color: rgba(241, 241, 241, 0.7);
92
- margin-top: -5px;
93
- }
94
-
95
- /* Progress Bar */
96
- .tf-progress-bg {
97
- margin-top: 10px;
98
- height: 4px;
99
- background: rgba(255, 255, 255, 0.1);
100
- border-radius: 2px;
101
- overflow: hidden;
102
- }
103
- .tf-progress-fill {
104
- height: 100%;
105
- background: #ffffff;
106
- transition: width 0.2s;
107
- }
108
-
109
- /* Action Button */
110
- .tf-action-btn {
111
- background: rgba(255, 255, 255, 0.1);
112
- border: none;
113
- color: #ffffff;
114
- padding: 6px 12px;
115
- border-radius: 4px;
116
- cursor: pointer;
117
- margin-left: 8px;
118
- font-size: 12px;
119
- font-weight: 600;
120
- white-space: nowrap;
121
- }
122
-
123
- /* Close Button */
124
- .tf-close-btn {
125
- background: transparent;
126
- border: none;
127
- color: #888888;
128
- cursor: pointer;
129
- padding: 4px 4px 4px 8px;
130
- font-size: 14px;
131
- align-self: flex-start;
132
- }
133
- .tf-close-btn:hover {
134
- color: #ffffff;
135
- }
136
-
137
- /* ---- LIGHT THEME ---- */
138
- .tf-theme-light .tf-toast {
139
- background: #ffffff;
140
- border: 1px solid #e5e5e5;
141
- color: #171717;
142
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
143
- }
144
- .tf-theme-light .tf-icon {
145
- color: #171717;
146
- }
147
- .tf-theme-light .tf-progress-bg {
148
- background: rgba(0, 0, 0, 0.1);
149
- }
150
- .tf-theme-light .tf-progress-fill {
151
- background: #171717;
152
- }
153
- .tf-theme-light .tf-action-btn {
154
- background: rgba(0, 0, 0, 0.06);
155
- color: #171717;
156
- }
157
- .tf-theme-light .tf-close-btn:hover {
158
- color: #000000;
159
- }
160
- .tf-theme-light .tf-description {
161
- color: rgba(23, 23, 23, 0.7);
162
- }
163
-
164
- @keyframes tf-fadeIn {
165
- from {
166
- opacity: 0;
167
- transform: translateY(10px);
168
- }
169
-
170
- to {
171
- opacity: 1;
172
- transform: translateY(0);
173
- }
174
- }
1
+ .tf-toast-container {
2
+ position: fixed;
3
+ z-index: 99999;
4
+ pointer-events: auto;
5
+ }
6
+
7
+ /* ---- Position placements ---- */
8
+ .tf-top-left {
9
+ top: 20px;
10
+ left: 20px;
11
+ }
12
+ .tf-top-center {
13
+ top: 20px;
14
+ left: 50%;
15
+ transform: translateX(-50%);
16
+ }
17
+ .tf-top-right {
18
+ top: 20px;
19
+ right: 20px;
20
+ }
21
+ .tf-bottom-left {
22
+ bottom: 20px;
23
+ left: 20px;
24
+ }
25
+ .tf-bottom-center {
26
+ bottom: 20px;
27
+ left: 50%;
28
+ transform: translateX(-50%);
29
+ }
30
+ .tf-bottom-right {
31
+ bottom: 20px;
32
+ right: 20px;
33
+ }
34
+
35
+ .tf-stack-collapsed {
36
+ position: relative;
37
+ display: block;
38
+ width: 320px;
39
+ min-height: 46px;
40
+ }
41
+
42
+ .tf-stack-expanded {
43
+ display: flex;
44
+ flex-direction: column;
45
+ gap: 10px;
46
+ width: 320px;
47
+ }
48
+
49
+ .tf-top-left .tf-stack-collapsed,
50
+ .tf-bottom-left .tf-stack-collapsed,
51
+ .tf-top-left .tf-stack-expanded,
52
+ .tf-bottom-left .tf-stack-expanded {
53
+ align-items: flex-start;
54
+ }
55
+
56
+ .tf-top-center .tf-stack-collapsed,
57
+ .tf-bottom-center .tf-stack-collapsed,
58
+ .tf-top-center .tf-stack-expanded,
59
+ .tf-bottom-center .tf-stack-expanded {
60
+ align-items: center;
61
+ }
62
+
63
+ .tf-top-right .tf-stack-collapsed,
64
+ .tf-bottom-right .tf-stack-collapsed,
65
+ .tf-top-right .tf-stack-expanded,
66
+ .tf-bottom-right .tf-stack-expanded {
67
+ align-items: flex-end;
68
+ }
69
+
70
+ /* ---- Toast base ---- */
71
+ .tf-toast {
72
+ display: flex;
73
+ align-items: center;
74
+ gap: 12px;
75
+ padding: 12px 16px;
76
+ background: #0f0f0f;
77
+ border: 1px solid #2a2a2a;
78
+ border-radius: 8px;
79
+ color: #f1f1f1;
80
+ font-size: 14px;
81
+ font-family: var(
82
+ --tf-font-family,
83
+ system-ui,
84
+ -apple-system,
85
+ BlinkMacSystemFont,
86
+ "Segoe UI",
87
+ Roboto,
88
+ "Helvetica Neue",
89
+ Arial,
90
+ sans-serif
91
+ );
92
+ font-weight: 500;
93
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
94
+ min-width: 320px;
95
+ width: 320px;
96
+ box-sizing: border-box;
97
+ }
98
+
99
+ /* New toast entry animation */
100
+ .tf-stack-collapsed > .tf-toast:first-child,
101
+ .tf-stack-expanded > .tf-toast {
102
+ animation: tf-fadeIn 0.22s ease-out;
103
+ }
104
+
105
+ .tf-icon {
106
+ display: flex;
107
+ align-items: center;
108
+ justify-content: center;
109
+ color: #f1f1f1;
110
+ }
111
+
112
+ .tf-message {
113
+ text-align: left;
114
+ flex: 1;
115
+ }
116
+
117
+ .tf-description {
118
+ font-size: 13px;
119
+ color: rgba(241, 241, 241, 0.7);
120
+ margin-top: -5px;
121
+ }
122
+
123
+ /* Progress Bar */
124
+ .tf-progress-bg {
125
+ margin-top: 10px;
126
+ height: 4px;
127
+ background: rgba(255, 255, 255, 0.1);
128
+ border-radius: 2px;
129
+ overflow: hidden;
130
+ }
131
+ .tf-progress-fill {
132
+ height: 100%;
133
+ background: #ffffff;
134
+ transition: width 0.2s;
135
+ }
136
+
137
+ /* Action Button */
138
+ .tf-action-btn {
139
+ background: rgba(255, 255, 255, 0.1);
140
+ border: none;
141
+ color: #ffffff;
142
+ padding: 6px 12px;
143
+ border-radius: 4px;
144
+ cursor: pointer;
145
+ margin-left: 8px;
146
+ font-size: 12px;
147
+ font-weight: 600;
148
+ white-space: nowrap;
149
+ }
150
+
151
+ /* Close Button */
152
+ .tf-close-btn {
153
+ background: transparent;
154
+ border: none;
155
+ color: #888888;
156
+ cursor: pointer;
157
+ padding: 4px 4px 4px 8px;
158
+ font-size: 14px;
159
+ align-self: flex-start;
160
+ }
161
+ .tf-close-btn:hover {
162
+ color: #ffffff;
163
+ }
164
+
165
+ /* ---- LIGHT THEME ---- */
166
+ .tf-theme-light .tf-toast {
167
+ background: #ffffff;
168
+ border: 1px solid #e5e5e5;
169
+ color: #171717;
170
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
171
+ }
172
+ .tf-theme-light .tf-icon {
173
+ color: #171717;
174
+ }
175
+ .tf-theme-light .tf-progress-bg {
176
+ background: rgba(0, 0, 0, 0.1);
177
+ }
178
+ .tf-theme-light .tf-progress-fill {
179
+ background: #171717;
180
+ }
181
+ .tf-theme-light .tf-action-btn {
182
+ background: rgba(0, 0, 0, 0.06);
183
+ color: #171717;
184
+ }
185
+ .tf-theme-light .tf-close-btn:hover {
186
+ color: #000000;
187
+ }
188
+ .tf-theme-light .tf-description {
189
+ color: rgba(23, 23, 23, 0.7);
190
+ }
191
+
192
+ /* ---- Animations ---- */
193
+ @keyframes tf-fadeIn {
194
+ from {
195
+ opacity: 0;
196
+ transform: translateY(-8px) scale(0.96);
197
+ }
198
+ to {
199
+ opacity: 1;
200
+ transform: translateY(0) scale(1);
201
+ }
202
+ }