toast-23 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,266 @@
1
+ <div align="center">
2
+
3
+ # ๐Ÿž toast-23
4
+
5
+ **A lightweight, accessible, fully-typed React toast notification library.**
6
+
7
+ Zero runtime dependencies ยท CSS animations ยท Dark mode ยท Promise tracking ยท Queue system
8
+
9
+ [![npm version](https://img.shields.io/npm/v/toast-23.svg)](https://www.npmjs.com/package/toast-23)
10
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/toast-23)](https://bundlephobia.com/package/toast-23)
11
+ [![license](https://img.shields.io/npm/l/toast-23)](./LICENSE)
12
+
13
+ </div>
14
+
15
+ ---
16
+
17
+ ## Features
18
+
19
+ - ๐ŸŽจ **5 variants** โ€” success, error, warning, info, default
20
+ - ๐Ÿ“ **6 positions** โ€” top-right, top-left, top-center, bottom-right, bottom-left, bottom-center
21
+ - โณ **Promise API** โ€” track async operations with loading โ†’ success / error
22
+ - โณ **Loading toast** โ€” `toast.loading()` with manual update
23
+ - ๐Ÿงฉ **Custom JSX** โ€” `toast.custom()` for fully custom content
24
+ - ๐Ÿ”„ **Update & Deduplicate** โ€” update existing toasts via `id`, prevent duplicates
25
+ - ๐Ÿ“ฆ **Queue system** โ€” configurable max visible toasts with +N badge
26
+ - ๐Ÿงน **Dismiss & Remove** โ€” dismiss all, remove instantly, configurable `removeDelay`
27
+ - ๐ŸŒ™ **Dark mode** โ€” automatic (`prefers-color-scheme`) + manual (`.dark` class)
28
+ - โ™ฟ **Accessible** โ€” ARIA live regions, keyboard-navigable dismiss
29
+ - ๐ŸŽญ **CSS animations** โ€” smooth enter/exit transitions, hover-pause with progress reversal
30
+ - ๐Ÿชถ **Lightweight** โ€” zero runtime dependencies beyond React
31
+ - ๐Ÿ”’ **Fully typed** โ€” complete TypeScript API
32
+ - ๐ŸŒฒ **Tree-shakeable** โ€” ESM + CJS dual output
33
+ - ๐ŸŒ **Standalone API** โ€” `createToast23()` for Angular, Vue, Svelte, vanilla JS
34
+
35
+ ---
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ npm install toast-23
41
+ ```
42
+
43
+ ```bash
44
+ yarn add toast-23
45
+ ```
46
+
47
+ ```bash
48
+ pnpm add toast-23
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Quick Start
54
+
55
+ ### 1. Import the stylesheet
56
+
57
+ ```tsx
58
+ // In your app entry (e.g., main.tsx or layout.tsx)
59
+ import "toast-23/styles.css";
60
+ ```
61
+
62
+ ### 2. Wrap your app with the provider
63
+
64
+ ```tsx
65
+ import { Toast23Provider } from "toast-23";
66
+
67
+ function App() {
68
+ return (
69
+ <Toast23Provider position="top-right" maxVisible={5} duration={4000}>
70
+ <YourApp />
71
+ </Toast23Provider>
72
+ );
73
+ }
74
+ ```
75
+
76
+ ### 3. Use the hook
77
+
78
+ ```tsx
79
+ import { useToast } from "toast-23";
80
+
81
+ function MyComponent() {
82
+ const toast = useToast();
83
+
84
+ return (
85
+ <div>
86
+ <button onClick={() => toast("Hello world!")}>Default</button>
87
+ <button onClick={() => toast.success("Saved successfully!")}>
88
+ Success
89
+ </button>
90
+ <button onClick={() => toast.error("Something went wrong")}>Error</button>
91
+ <button onClick={() => toast.warning("Please check your input")}>
92
+ Warning
93
+ </button>
94
+ <button onClick={() => toast.info("New update available")}>Info</button>
95
+ </div>
96
+ );
97
+ }
98
+ ```
99
+
100
+ ---
101
+
102
+ ## API Reference
103
+
104
+ ### `<Toast23Provider>`
105
+
106
+ | Prop | Type | Default | Description |
107
+ | ------------ | --------------- | ------------- | ------------------------------------- |
108
+ | `maxVisible` | `number` | `5` | Maximum simultaneously visible toasts |
109
+ | `position` | `ToastPosition` | `"top-right"` | Default screen position |
110
+ | `duration` | `number` | `4000` | Default auto-dismiss duration (ms) |
111
+
112
+ ### `useToast()`
113
+
114
+ Returns a **callable** `ToastApi` object:
115
+
116
+ ```tsx
117
+ const toast = useToast();
118
+
119
+ // Direct call โ€” default variant
120
+ const id = toast("Message", options?);
121
+
122
+ // Variant shortcuts
123
+ toast.success("Saved!", options?);
124
+ toast.error("Failed!", options?);
125
+ toast.warning("Watch out!", options?);
126
+ toast.info("FYI", options?);
127
+
128
+ // Manual dismiss
129
+ toast.dismiss(id);
130
+
131
+ // Promise tracking
132
+ toast.promise(fetchData(), {
133
+ loading: "Loading...",
134
+ success: "Done!",
135
+ error: "Something failed",
136
+ });
137
+ ```
138
+
139
+ ### `ToastOptions`
140
+
141
+ | Property | Type | Default | Description |
142
+ | ------------- | --------------- | ---------------- | ---------------------------------- |
143
+ | `title` | `string` | โ€” | Optional heading |
144
+ | `variant` | `ToastVariant` | `"default"` | Visual variant |
145
+ | `duration` | `number` | Provider default | Auto-dismiss ms (`0` = persistent) |
146
+ | `position` | `ToastPosition` | Provider default | Screen position override |
147
+ | `dismissible` | `boolean` | `true` | Show dismiss button |
148
+
149
+ ### Types
150
+
151
+ ```ts
152
+ type ToastVariant = "success" | "error" | "warning" | "info" | "default";
153
+ type ToastPosition = "top-right" | "top-left" | "bottom-right" | "bottom-left";
154
+ ```
155
+
156
+ ---
157
+
158
+ ## Promise API
159
+
160
+ Track async operations with automatic loading โ†’ result transitions:
161
+
162
+ ```tsx
163
+ const toast = useToast();
164
+
165
+ // Basic
166
+ toast.promise(saveData(), {
167
+ loading: "Saving...",
168
+ success: "Saved!",
169
+ error: "Failed to save",
170
+ });
171
+
172
+ // Dynamic messages
173
+ toast.promise(fetchUser(id), {
174
+ loading: "Fetching user...",
175
+ success: (user) => `Welcome, ${user.name}!`,
176
+ error: (err) => `Error: ${err.message}`,
177
+ });
178
+ ```
179
+
180
+ ---
181
+
182
+ ## Dark Mode
183
+
184
+ toast-23 supports dark mode in two ways:
185
+
186
+ 1. **Automatic** โ€” respects `prefers-color-scheme: dark`
187
+ 2. **Manual** โ€” add the `dark` class to any ancestor (e.g., `<html class="dark">`)
188
+
189
+ ---
190
+
191
+ ## Customization
192
+
193
+ Override CSS variables or classes to customize the look:
194
+
195
+ ```css
196
+ /* Override colors */
197
+ .toast23-item--success {
198
+ background: #d1fae5;
199
+ border-color: #6ee7b7;
200
+ }
201
+
202
+ /* Override progress bar */
203
+ .toast23-progress--success {
204
+ background: #10b981;
205
+ }
206
+ ```
207
+
208
+ ---
209
+
210
+ ## SSR Support
211
+
212
+ toast-23 is SSR-safe. All browser APIs are guarded behind `useEffect`:
213
+
214
+ - โœ… Next.js (App Router & Pages Router)
215
+ - โœ… Remix
216
+ - โœ… Gatsby
217
+ - โœ… Astro (React islands)
218
+ - โœ… Angular (via `createToast23()`)
219
+ - โœ… Vue.js (via `createToast23()`)
220
+
221
+ ---
222
+
223
+ ## Testing
224
+
225
+ toast-23 uses [Vitest](https://vitest.dev/) with [Testing Library](https://testing-library.com/):
226
+
227
+ ```bash
228
+ # Run tests
229
+ npm test
230
+
231
+ # Watch mode
232
+ npm run test:watch
233
+
234
+ # Coverage
235
+ npm run test:coverage
236
+ ```
237
+
238
+ ---
239
+
240
+ ## CI/CD
241
+
242
+ GitHub Actions workflow at `.github/workflows/ci.yml`:
243
+
244
+ - **Lint** โ€” TypeScript type checking
245
+ - **Test** โ€” Vitest test suite (Node 18, 20, 22)
246
+ - **Build** โ€” Vite library build with DTS generation
247
+ - **Publish** โ€” Auto-publish to npm on version bump (requires `NPM_TOKEN` secret)
248
+
249
+ ---
250
+
251
+ ## Suggested Improvements for v2
252
+
253
+ - [ ] Swipe-to-dismiss on mobile
254
+ - [ ] Stacked/collapsed mode for overflow
255
+ - [ ] Undo action support
256
+ - [ ] Theming via CSS custom properties (design tokens)
257
+ - [ ] Headless mode (bring your own UI)
258
+ - [ ] Rich content: icons, avatars, action buttons
259
+ - [ ] Sound notifications
260
+ - [ ] Persistent toasts (survive page navigation)
261
+
262
+ ---
263
+
264
+ ## License
265
+
266
+ MIT ยฉ toast-23 contributors
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),l=require("react"),D=require("react-dom/client");function A(e){const n=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const r in e)if(r!=="default"){const t=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(n,r,t.get?t:{enumerable:!0,get:()=>e[r]})}}return n.default=e,Object.freeze(n)}const y=A(l),k=l.createContext(null);function P(e,n){switch(n.type){case"ADD":return[...e,n.toast];case"UPSERT":return e.some(t=>t.id===n.toast.id)?e.map(t=>t.id===n.toast.id?{...t,...n.toast,version:t.version+1,isExiting:!1}:t):[...e,n.toast];case"UPDATE":return e.map(r=>r.id===n.id?{...r,...n.updates,version:r.version+1,isExiting:!1}:r);case"DISMISS":return n.id?e.map(r=>r.id===n.id?{...r,isExiting:!0}:r):e.map(r=>({...r,isExiting:!0}));case"REMOVE":return n.id?e.filter(r=>r.id!==n.id):[];default:return e}}const _=e=>o.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",width:"1.25em",height:"1.25em",fill:"none",...e,children:[o.jsx("circle",{cx:12,cy:12,r:10,fill:"currentColor"}),o.jsx("path",{d:"M8 12.5l2.5 2.5 5-5",stroke:"#fff",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",fill:"none"})]}),p=e=>o.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",width:"1.25em",height:"1.25em",fill:"none",...e,children:[o.jsx("circle",{cx:12,cy:12,r:10,fill:"currentColor"}),o.jsx("line",{x1:12,y1:8,x2:12,y2:13,stroke:"#fff",strokeWidth:2,strokeLinecap:"round"}),o.jsx("circle",{cx:12,cy:16,r:1,fill:"#fff"})]}),q=e=>o.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",width:"1.25em",height:"1.25em",fill:"none",...e,children:[o.jsx("path",{d:"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z",fill:"currentColor"}),o.jsx("line",{x1:12,y1:9.5,x2:12,y2:14,stroke:"#fff",strokeWidth:2,strokeLinecap:"round"}),o.jsx("circle",{cx:12,cy:17,r:1,fill:"#fff"})]}),b=e=>o.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",width:"1.25em",height:"1.25em",fill:"none",...e,children:[o.jsx("circle",{cx:12,cy:12,r:10,fill:"currentColor"}),o.jsx("line",{x1:12,y1:11,x2:12,y2:16,stroke:"#fff",strokeWidth:2,strokeLinecap:"round"}),o.jsx("circle",{cx:12,cy:8,r:1,fill:"#fff"})]}),$=e=>o.jsxs("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",width:"0.875em",height:"0.875em",...e,children:[o.jsx("line",{x1:18,y1:6,x2:6,y2:18}),o.jsx("line",{x1:6,y1:6,x2:18,y2:18})]}),B=e=>o.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round",width:"1.25em",height:"1.25em",className:"toast23-spinner",...e,children:o.jsx("path",{d:"M21 12a9 9 0 1 1-6.219-8.56"})});let W=0;function U(){return`t23-${++W}-${Math.random().toString(36).slice(2,9)}`}function w(...e){return e.filter(Boolean).join(" ")}const F={success:_,error:p,warning:q,info:b,default:b,loading:B},X=300,z=200,M=y.memo(({toast:e,onDismiss:n,onRemove:r})=>{const[t,u]=l.useState(!1);l.useEffect(()=>{const v=requestAnimationFrame(()=>u(!0));return()=>cancelAnimationFrame(v)},[]),l.useEffect(()=>{if(!e.isExiting)return;const v=e.removeDelay??X,E=setTimeout(()=>r(e.id),v);return()=>clearTimeout(E)},[e.isExiting,e.id,e.removeDelay,r]);const[m,g]=l.useState(!1),d=l.useRef(e.duration),c=l.useRef(0),[x,f]=l.useState(100),[a,i]=l.useState("none"),s=l.useRef(0);l.useEffect(()=>{d.current=e.duration,f(100),i("none")},[e.version,e.duration]),l.useEffect(()=>{if(e.duration<=0||e.variant==="loading"||!t||e.isExiting)return;if(m){const I=Date.now()-c.current;d.current=Math.max(0,d.current-I);const L=Math.max(z,I);i(`width ${L}ms ease-out`),f(100);return}c.current=Date.now();const v=d.current;s.current=requestAnimationFrame(()=>{i(`width ${v}ms linear`),f(0)});const E=setTimeout(()=>{n(e.id)},v);return()=>{clearTimeout(E),cancelAnimationFrame(s.current)}},[m,t,e.isExiting,e.duration,e.variant,e.id,e.version,n]);const h=l.useCallback(()=>g(!0),[]),T=l.useCallback(()=>g(!1),[]),S=F[e.variant]??b;return e.isCustom?o.jsx("div",{className:w("toast23-item toast23-item--custom",!t&&"toast23-item--entering",e.isExiting&&"toast23-item--exiting"),role:"alert","aria-live":"polite","aria-atomic":"true",onMouseEnter:h,onMouseLeave:T,children:e.message}):o.jsxs("div",{className:w("toast23-item",`toast23-item--${e.variant}`,!t&&"toast23-item--entering",e.isExiting&&"toast23-item--exiting"),role:"alert","aria-live":e.variant==="error"?"assertive":"polite","aria-atomic":"true",onMouseEnter:h,onMouseLeave:T,children:[o.jsx("span",{className:w("toast23-icon",`toast23-icon--${e.variant}`),children:o.jsx(S,{})}),o.jsxs("div",{className:"toast23-content",children:[e.title&&o.jsx("div",{className:"toast23-title",children:e.title}),o.jsx("div",{className:w("toast23-message",e.title&&"toast23-message--with-title"),children:e.message})]}),e.dismissible&&o.jsx("button",{type:"button",className:"toast23-dismiss",onClick:()=>n(e.id),"aria-label":"Dismiss notification",children:o.jsx($,{})}),e.duration>0&&e.variant!=="loading"&&o.jsx("div",{className:w("toast23-progress",`toast23-progress--${e.variant}`),style:{width:`${x}%`,transition:a}})]})});M.displayName="ToastItem";const N=y.memo(({position:e,toasts:n,maxVisible:r})=>{const t=l.useContext(k);if(!t)return null;const u=n.filter(c=>!c.isExiting),m=n.filter(c=>c.isExiting),g=[...u.slice(0,r),...m];if(g.length===0)return null;const d=Math.max(0,u.length-r);return o.jsxs("div",{className:w("toast23-container",`toast23-container--${e}`),"aria-label":"Notifications",role:"region",children:[g.map(c=>o.jsx(M,{toast:c,onDismiss:t.dismissToast,onRemove:t.removeToast},c.id)),d>0&&o.jsxs("div",{className:"toast23-queue-badge","aria-live":"polite",children:["+",d," more"]})]})});N.displayName="ToastContainer";const H=["top-right","top-left","top-center","bottom-right","bottom-left","bottom-center"],C=({children:e,maxVisible:n=5,position:r="top-right",duration:t=5e3})=>{const[u,m]=l.useReducer(P,[]),g=l.useCallback((i,s)=>{const h=(s==null?void 0:s.id)??U(),T={id:h,message:i,title:s==null?void 0:s.title,variant:(s==null?void 0:s.variant)??"default",duration:(s==null?void 0:s.duration)??t,position:(s==null?void 0:s.position)??r,dismissible:(s==null?void 0:s.dismissible)??!0,removeDelay:(s==null?void 0:s.removeDelay)??1e3,isExiting:!1,createdAt:Date.now(),version:0,isCustom:s==null?void 0:s.isCustom};return s!=null&&s.id?m({type:"UPSERT",toast:T}):m({type:"ADD",toast:T}),h},[t,r]),d=l.useCallback((i,s)=>{m({type:"UPDATE",id:i,updates:s})},[]),c=l.useCallback(i=>{m({type:"DISMISS",id:i})},[]),x=l.useCallback(i=>{m({type:"REMOVE",id:i})},[]),f=l.useMemo(()=>({addToast:g,updateToast:d,dismissToast:c,removeToast:x,config:{maxVisible:n,position:r,duration:t}}),[g,d,c,x,n,r,t]),a=l.useMemo(()=>{const i={"top-right":[],"top-left":[],"top-center":[],"bottom-right":[],"bottom-left":[],"bottom-center":[]};for(const s of u)i[s.position].push(s);return i},[u]);return o.jsxs(k.Provider,{value:f,children:[e,H.map(i=>a[i].length>0?o.jsx(N,{position:i,toasts:a[i],maxVisible:n},i):null)]})};C.displayName="Toast23Provider";function R(){const e=l.useContext(k);if(!e)throw new Error("[toast-23] useToast() must be used inside a <Toast23Provider>. Wrap your application root with <Toast23Provider> to fix this.");return l.useMemo(()=>{const n=(r,t)=>e.addToast(r,t);return n.success=(r,t)=>e.addToast(r,{...t,variant:"success"}),n.error=(r,t)=>e.addToast(r,{...t,variant:"error"}),n.warning=(r,t)=>e.addToast(r,{...t,variant:"warning"}),n.info=(r,t)=>e.addToast(r,{...t,variant:"info"}),n.loading=(r,t)=>e.addToast(r,{...t,variant:"loading",duration:(t==null?void 0:t.duration)??0,dismissible:(t==null?void 0:t.dismissible)??!1}),n.custom=(r,t)=>e.addToast(r,{...t,variant:"default",isCustom:!0}),n.dismiss=r=>e.dismissToast(r),n.remove=r=>e.removeToast(r),n.promise=async(r,t,u)=>{const m=e.addToast(t.loading,{...u,variant:"loading",duration:0,dismissible:!1}),g=typeof r=="function"?r():r;try{const d=await g,c=typeof t.success=="function"?t.success(d):t.success;return e.updateToast(m,{message:c,variant:"success",duration:(u==null?void 0:u.duration)??e.config.duration,dismissible:!0}),d}catch(d){const c=typeof t.error=="function"?t.error(d):t.error;throw e.updateToast(m,{message:c,variant:"error",duration:(u==null?void 0:u.duration)??e.config.duration,dismissible:!0}),d}},n},[e.addToast,e.updateToast,e.dismissToast,e.removeToast,e.config.duration])}let j=null;function V(){const e=R();return y.useEffect(()=>{j&&(j(e),j=null)},[e]),null}function G(e={}){const{position:n="top-right",maxVisible:r=5,duration:t=5e3}=e,u=document.createElement("div");u.setAttribute("data-toast23-standalone",""),u.style.display="contents",document.body.appendChild(u);let m=D.createRoot(u);const g=new Promise(a=>{j=a}),d=[];let c=null;g.then(a=>{c=a;for(const i of d)i.method==="__call__"?a(...i.args):a[i.method](...i.args);d.length=0}),m.render(y.createElement(C,{position:n,maxVisible:r,duration:t},y.createElement(V)));const x=(a,...i)=>c?c[a](...i):(d.push({method:a,args:i}),"queued"),f=(a,i)=>c?c(a,i):(d.push({method:"__call__",args:[a,i]}),"queued");return f.success=(a,i)=>x("success",a,i),f.error=(a,i)=>x("error",a,i),f.warning=(a,i)=>x("warning",a,i),f.info=(a,i)=>x("info",a,i),f.loading=(a,i)=>x("loading",a,i),f.custom=(a,i)=>x("custom",a,i),f.dismiss=a=>x("dismiss",a),f.remove=a=>x("remove",a),f.promise=(a,i,s)=>c?c.promise(a,i,s):g.then(h=>h.promise(a,i,s)),f.destroy=()=>{m&&(m.unmount(),m=null),u.remove(),c=null},f}exports.Toast23Provider=C;exports.createToast23=G;exports.useToast=R;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/context.tsx","../src/icons.tsx","../src/utils.ts","../src/toast-item.tsx","../src/toast-container.tsx","../src/provider.tsx","../src/use-toast.ts","../src/standalone.ts"],"sourcesContent":["/**\r\n * toast-23 โ€” React Context & Reducer\r\n */\r\n\r\nimport { createContext } from \"react\";\r\nimport type {\r\n InternalToast,\r\n ToasterAction,\r\n ToasterContextValue,\r\n} from \"./types\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Context โ€” consumed by useToast() and internal components\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const ToasterContext = createContext<ToasterContextValue | null>(null);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Reducer โ€” pure state transitions for the toast queue\r\n// ---------------------------------------------------------------------------\r\n\r\nexport function toasterReducer(\r\n state: InternalToast[],\r\n action: ToasterAction,\r\n): InternalToast[] {\r\n switch (action.type) {\r\n case \"ADD\":\r\n return [...state, action.toast];\r\n\r\n case \"UPSERT\": {\r\n const exists = state.some((t) => t.id === action.toast.id);\r\n if (exists) {\r\n return state.map((t) =>\r\n t.id === action.toast.id\r\n ? {\r\n ...t,\r\n ...action.toast,\r\n version: t.version + 1,\r\n isExiting: false,\r\n }\r\n : t,\r\n );\r\n }\r\n return [...state, action.toast];\r\n }\r\n\r\n case \"UPDATE\":\r\n return state.map((t) =>\r\n t.id === action.id\r\n ? {\r\n ...t,\r\n ...action.updates,\r\n // Bump version so progress bar restarts\r\n version: t.version + 1,\r\n // If the toast was exiting, cancel exit on update\r\n isExiting: false,\r\n }\r\n : t,\r\n );\r\n\r\n case \"DISMISS\":\r\n // Omit id โ†’ dismiss all\r\n if (!action.id) {\r\n return state.map((t) => ({ ...t, isExiting: true }));\r\n }\r\n return state.map((t) =>\r\n t.id === action.id ? { ...t, isExiting: true } : t,\r\n );\r\n\r\n case \"REMOVE\":\r\n // Omit id โ†’ remove all instantly\r\n if (!action.id) return [];\r\n return state.filter((t) => t.id !== action.id);\r\n\r\n default:\r\n return state;\r\n }\r\n}\r\n","/**\r\n * toast-23 โ€” Inline SVG Icons (Filled style)\r\n *\r\n * Solid colored circles/triangles with white inner symbols,\r\n * matching the visual design reference.\r\n */\r\n\r\nimport type { SVGProps, FC } from \"react\";\r\n\r\ntype IconProps = SVGProps<SVGSVGElement>;\r\n\r\n/** Green filled circle with white checkmark */\r\nexport const CheckCircleIcon: FC<IconProps> = (props: IconProps) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n width=\"1.25em\"\r\n height=\"1.25em\"\r\n fill=\"none\"\r\n {...props}\r\n >\r\n <circle cx={12} cy={12} r={10} fill=\"currentColor\" />\r\n <path\r\n d=\"M8 12.5l2.5 2.5 5-5\"\r\n stroke=\"#fff\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n fill=\"none\"\r\n />\r\n </svg>\r\n);\r\n\r\n/** Red filled circle with white exclamation */\r\nexport const XCircleIcon: FC<IconProps> = (props: IconProps) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n width=\"1.25em\"\r\n height=\"1.25em\"\r\n fill=\"none\"\r\n {...props}\r\n >\r\n <circle cx={12} cy={12} r={10} fill=\"currentColor\" />\r\n <line\r\n x1={12}\r\n y1={8}\r\n x2={12}\r\n y2={13}\r\n stroke=\"#fff\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n />\r\n <circle cx={12} cy={16} r={1} fill=\"#fff\" />\r\n </svg>\r\n);\r\n\r\n/** Yellow filled triangle with white exclamation */\r\nexport const AlertTriangleIcon: FC<IconProps> = (props: IconProps) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n width=\"1.25em\"\r\n height=\"1.25em\"\r\n fill=\"none\"\r\n {...props}\r\n >\r\n <path\r\n d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"\r\n fill=\"currentColor\"\r\n />\r\n <line\r\n x1={12}\r\n y1={9.5}\r\n x2={12}\r\n y2={14}\r\n stroke=\"#fff\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n />\r\n <circle cx={12} cy={17} r={1} fill=\"#fff\" />\r\n </svg>\r\n);\r\n\r\n/** Blue filled circle with white \"i\" */\r\nexport const InfoIcon: FC<IconProps> = (props: IconProps) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n width=\"1.25em\"\r\n height=\"1.25em\"\r\n fill=\"none\"\r\n {...props}\r\n >\r\n <circle cx={12} cy={12} r={10} fill=\"currentColor\" />\r\n <line\r\n x1={12}\r\n y1={11}\r\n x2={12}\r\n y2={16}\r\n stroke=\"#fff\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n />\r\n <circle cx={12} cy={8} r={1} fill=\"#fff\" />\r\n </svg>\r\n);\r\n\r\n/** Thin X icon for dismiss button */\r\nexport const XIcon: FC<IconProps> = (props: IconProps) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n width=\"0.875em\"\r\n height=\"0.875em\"\r\n {...props}\r\n >\r\n <line x1={18} y1={6} x2={6} y2={18} />\r\n <line x1={6} y1={6} x2={18} y2={18} />\r\n </svg>\r\n);\r\n\r\n/** CSS-only loading spinner */\r\nexport const SpinnerIcon: FC<IconProps> = (props: IconProps) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n width=\"1.25em\"\r\n height=\"1.25em\"\r\n className=\"toast23-spinner\"\r\n {...props}\r\n >\r\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\r\n </svg>\r\n);\r\n","/**\r\n * toast-23 โ€” Utility helpers\r\n */\r\n\r\nlet counter = 0;\r\n\r\n/**\r\n * Generate a unique toast id.\r\n * Works in SSR (no dependency on `crypto`).\r\n */\r\nexport function generateId(): string {\r\n return `t23-${++counter}-${Math.random().toString(36).slice(2, 9)}`;\r\n}\r\n\r\n/**\r\n * Deterministic class-name builder (replaces clsx dependency).\r\n */\r\nexport function cx(...args: (string | false | null | undefined | 0)[]): string {\r\n return args.filter(Boolean).join(\" \");\r\n}\r\n","/**\r\n * toast-23 โ€” Individual Toast Component\r\n *\r\n * Manages its own enter / exit CSS transitions and auto-dismiss timer.\r\n * Progress bar is JS-driven so it can reverse (refill) on hover.\r\n */\r\n\r\n\"use client\";\r\n\r\nimport * as React from \"react\";\r\nimport { useCallback, useEffect, useRef, useState } from \"react\";\r\nimport type { InternalToast } from \"./types\";\r\nimport {\r\n CheckCircleIcon,\r\n XCircleIcon,\r\n AlertTriangleIcon,\r\n InfoIcon,\r\n SpinnerIcon,\r\n XIcon,\r\n} from \"./icons\";\r\nimport { cx } from \"./utils\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Icon map\r\n// ---------------------------------------------------------------------------\r\n\r\nconst variantIcon: Record<string, React.FC<React.SVGProps<SVGSVGElement>>> = {\r\n success: CheckCircleIcon,\r\n error: XCircleIcon,\r\n warning: AlertTriangleIcon,\r\n info: InfoIcon,\r\n default: InfoIcon,\r\n loading: SpinnerIcon,\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Component\r\n// ---------------------------------------------------------------------------\r\n\r\ninterface ToastItemProps {\r\n toast: InternalToast;\r\n onDismiss: (id: string) => void;\r\n onRemove: (id: string) => void;\r\n}\r\n\r\nconst EXIT_DURATION = 300; // ms โ€” must match CSS transition duration\r\nconst MIN_REFILL_DURATION = 200; // ms โ€” minimum refill time so very short hovers aren't instant\r\n\r\nexport const ToastItem: React.FC<ToastItemProps> = React.memo(\r\n ({ toast, onDismiss, onRemove }) => {\r\n // ----- animation state -----\r\n const [hasEntered, setHasEntered] = useState(false);\r\n\r\n // Trigger enter transition on next frame\r\n useEffect(() => {\r\n const raf = requestAnimationFrame(() => setHasEntered(true));\r\n return () => cancelAnimationFrame(raf);\r\n }, []);\r\n\r\n // When the provider marks the toast as exiting, wait for the CSS\r\n // transition to finish then actually remove it from state.\r\n useEffect(() => {\r\n if (!toast.isExiting) return;\r\n const delay = toast.removeDelay ?? EXIT_DURATION;\r\n const timer = setTimeout(() => onRemove(toast.id), delay);\r\n return () => clearTimeout(timer);\r\n }, [toast.isExiting, toast.id, toast.removeDelay, onRemove]);\r\n\r\n // ----- auto-dismiss timer with hover-pause -----\r\n const [isPaused, setIsPaused] = useState(false);\r\n const remainingRef = useRef(toast.duration);\r\n const startRef = useRef(0);\r\n\r\n // ----- JS-driven progress bar -----\r\n // progress: 100 = full, 0 = empty\r\n const [progress, setProgress] = useState(100);\r\n // transition duration for the progress bar\r\n const [progressTransition, setProgressTransition] = useState(\"none\");\r\n const rafRef = useRef<number>(0);\r\n\r\n // Reset remaining time when version changes (e.g. promise resolved)\r\n useEffect(() => {\r\n remainingRef.current = toast.duration;\r\n setProgress(100);\r\n setProgressTransition(\"none\");\r\n }, [toast.version, toast.duration]);\r\n\r\n useEffect(() => {\r\n // Don't auto-dismiss: persistent, loading, still entering, or already exiting\r\n if (\r\n toast.duration <= 0 ||\r\n toast.variant === \"loading\" ||\r\n !hasEntered ||\r\n toast.isExiting\r\n )\r\n return;\r\n\r\n if (isPaused) {\r\n // How long the bar was shrinking before hover\r\n const elapsed = Date.now() - startRef.current;\r\n // Snapshot remaining time\r\n remainingRef.current = Math.max(0, remainingRef.current - elapsed);\r\n\r\n // Reverse at the same speed it was shrinking (proportional duration)\r\n const refillDuration = Math.max(MIN_REFILL_DURATION, elapsed);\r\n setProgressTransition(`width ${refillDuration}ms ease-out`);\r\n setProgress(100);\r\n return;\r\n }\r\n\r\n // Start shrinking\r\n startRef.current = Date.now();\r\n const remaining = remainingRef.current;\r\n\r\n // Set transition to match remaining time and shrink to 0\r\n // Use rAF to ensure the refill transition has settled before starting shrink\r\n rafRef.current = requestAnimationFrame(() => {\r\n setProgressTransition(`width ${remaining}ms linear`);\r\n setProgress(0);\r\n });\r\n\r\n const timer = setTimeout(() => {\r\n onDismiss(toast.id);\r\n }, remaining);\r\n\r\n return () => {\r\n clearTimeout(timer);\r\n cancelAnimationFrame(rafRef.current);\r\n };\r\n }, [\r\n isPaused,\r\n hasEntered,\r\n toast.isExiting,\r\n toast.duration,\r\n toast.variant,\r\n toast.id,\r\n toast.version,\r\n onDismiss,\r\n ]);\r\n\r\n // ----- handlers -----\r\n const handleMouseEnter = useCallback(() => setIsPaused(true), []);\r\n const handleMouseLeave = useCallback(() => setIsPaused(false), []);\r\n\r\n // ----- render -----\r\n const Icon = variantIcon[toast.variant] ?? InfoIcon;\r\n\r\n // Custom toast โ€” render raw content with no default chrome\r\n if (toast.isCustom) {\r\n return (\r\n <div\r\n className={cx(\r\n \"toast23-item toast23-item--custom\",\r\n !hasEntered && \"toast23-item--entering\",\r\n toast.isExiting && \"toast23-item--exiting\",\r\n )}\r\n role=\"alert\"\r\n aria-live=\"polite\"\r\n aria-atomic=\"true\"\r\n onMouseEnter={handleMouseEnter}\r\n onMouseLeave={handleMouseLeave}\r\n >\r\n {toast.message}\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n className={cx(\r\n \"toast23-item\",\r\n `toast23-item--${toast.variant}`,\r\n !hasEntered && \"toast23-item--entering\",\r\n toast.isExiting && \"toast23-item--exiting\",\r\n )}\r\n role=\"alert\"\r\n aria-live={toast.variant === \"error\" ? \"assertive\" : \"polite\"}\r\n aria-atomic=\"true\"\r\n onMouseEnter={handleMouseEnter}\r\n onMouseLeave={handleMouseLeave}\r\n >\r\n {/* Icon */}\r\n <span className={cx(\"toast23-icon\", `toast23-icon--${toast.variant}`)}>\r\n <Icon />\r\n </span>\r\n\r\n {/* Content */}\r\n <div className=\"toast23-content\">\r\n {toast.title && <div className=\"toast23-title\">{toast.title}</div>}\r\n <div\r\n className={cx(\r\n \"toast23-message\",\r\n toast.title && \"toast23-message--with-title\",\r\n )}\r\n >\r\n {toast.message}\r\n </div>\r\n </div>\r\n\r\n {/* Dismiss button */}\r\n {toast.dismissible && (\r\n <button\r\n type=\"button\"\r\n className=\"toast23-dismiss\"\r\n onClick={() => onDismiss(toast.id)}\r\n aria-label=\"Dismiss notification\"\r\n >\r\n <XIcon />\r\n </button>\r\n )}\r\n\r\n {/* Progress bar โ€” JS-driven width for hover reversal */}\r\n {toast.duration > 0 && toast.variant !== \"loading\" && (\r\n <div\r\n className={cx(\r\n \"toast23-progress\",\r\n `toast23-progress--${toast.variant}`,\r\n )}\r\n style={{\r\n width: `${progress}%`,\r\n transition: progressTransition,\r\n }}\r\n />\r\n )}\r\n </div>\r\n );\r\n },\r\n);\r\n\r\nToastItem.displayName = \"ToastItem\";\r\n","/**\r\n * toast-23 โ€” Positioned Toast Container\r\n *\r\n * Renders a group of toasts for a given screen position.\r\n * Handles queue logic: only `maxVisible` non-exiting toasts are shown,\r\n * plus any currently animating-out toasts.\r\n */\r\n\r\n\"use client\";\r\n\r\nimport * as React from \"react\";\r\nimport { useContext } from \"react\";\r\nimport type { InternalToast, ToastPosition } from \"./types\";\r\nimport { ToasterContext } from \"./context\";\r\nimport { ToastItem } from \"./toast-item\";\r\nimport { cx } from \"./utils\";\r\n\r\ninterface ToastContainerProps {\r\n position: ToastPosition;\r\n toasts: InternalToast[];\r\n maxVisible: number;\r\n}\r\n\r\nexport const ToastContainer: React.FC<ToastContainerProps> = React.memo(\r\n ({ position, toasts, maxVisible }: ToastContainerProps) => {\r\n const ctx = useContext(ToasterContext);\r\n if (!ctx) return null;\r\n\r\n // Separate active vs. exiting toasts\r\n const active = toasts.filter((t) => !t.isExiting);\r\n const exiting = toasts.filter((t) => t.isExiting);\r\n\r\n // Only show up to maxVisible active toasts, plus all currently exiting\r\n const visible = [...active.slice(0, maxVisible), ...exiting];\r\n\r\n if (visible.length === 0) return null;\r\n\r\n // Queue count for optional badge\r\n const queuedCount = Math.max(0, active.length - maxVisible);\r\n\r\n return (\r\n <div\r\n className={cx(\"toast23-container\", `toast23-container--${position}`)}\r\n aria-label=\"Notifications\"\r\n role=\"region\"\r\n >\r\n {visible.map((toast) => (\r\n <ToastItem\r\n key={toast.id}\r\n toast={toast}\r\n onDismiss={ctx.dismissToast}\r\n onRemove={ctx.removeToast}\r\n />\r\n ))}\r\n {queuedCount > 0 && (\r\n <div className=\"toast23-queue-badge\" aria-live=\"polite\">\r\n +{queuedCount} more\r\n </div>\r\n )}\r\n </div>\r\n );\r\n },\r\n);\r\n\r\nToastContainer.displayName = \"ToastContainer\";\r\n","/**\r\n * toast-23 โ€” Toast23Provider\r\n *\r\n * Wrap your application with this provider to enable toast notifications.\r\n *\r\n * ```tsx\r\n * <Toast23Provider position=\"top-right\" maxVisible={5}>\r\n * <App />\r\n * </Toast23Provider>\r\n * ```\r\n */\r\n\r\n\"use client\";\r\n\r\nimport { useCallback, useMemo, useReducer } from \"react\";\r\nimport type {\r\n InternalToast,\r\n Toast23ProviderProps,\r\n ToasterContextValue,\r\n ToastOptions,\r\n ToastPosition,\r\n} from \"./types\";\r\nimport type { ReactNode } from \"react\";\r\nimport { ToasterContext, toasterReducer } from \"./context\";\r\nimport { ToastContainer } from \"./toast-container\";\r\nimport { generateId } from \"./utils\";\r\n\r\nconst ALL_POSITIONS: ToastPosition[] = [\r\n \"top-right\",\r\n \"top-left\",\r\n \"top-center\",\r\n \"bottom-right\",\r\n \"bottom-left\",\r\n \"bottom-center\",\r\n];\r\n\r\nexport const Toast23Provider: React.FC<Toast23ProviderProps> = ({\r\n children,\r\n maxVisible = 5,\r\n position: defaultPosition = \"top-right\" as ToastPosition,\r\n duration: defaultDuration = 5000,\r\n}) => {\r\n const [toasts, dispatch] = useReducer(toasterReducer, []);\r\n\r\n // ------ stable callbacks (dispatch is always stable from useReducer) ------\r\n\r\n const addToast = useCallback(\r\n (message: string | ReactNode, options?: ToastOptions & { variant?: any; isCustom?: boolean }): string => {\r\n const id = options?.id ?? generateId();\r\n const toast: InternalToast = {\r\n id,\r\n message,\r\n title: options?.title,\r\n variant: options?.variant ?? \"default\",\r\n duration: options?.duration ?? defaultDuration,\r\n position: options?.position ?? defaultPosition,\r\n dismissible: options?.dismissible ?? true,\r\n removeDelay: options?.removeDelay ?? 1000,\r\n isExiting: false,\r\n createdAt: Date.now(),\r\n version: 0,\r\n isCustom: options?.isCustom,\r\n };\r\n // If an id was provided, upsert (update-or-insert)\r\n if (options?.id) {\r\n dispatch({ type: \"UPSERT\", toast });\r\n } else {\r\n dispatch({ type: \"ADD\", toast });\r\n }\r\n return id;\r\n },\r\n [defaultDuration, defaultPosition],\r\n );\r\n\r\n const updateToast = useCallback(\r\n (\r\n id: string,\r\n updates: Partial<\r\n Pick<\r\n InternalToast,\r\n \"message\" | \"title\" | \"variant\" | \"duration\" | \"dismissible\"\r\n >\r\n >,\r\n ) => {\r\n dispatch({ type: \"UPDATE\", id, updates });\r\n },\r\n [],\r\n );\r\n\r\n const dismissToast = useCallback((id?: string) => {\r\n dispatch({ type: \"DISMISS\", id });\r\n }, []);\r\n\r\n const removeToast = useCallback((id?: string) => {\r\n dispatch({ type: \"REMOVE\", id });\r\n }, []);\r\n\r\n // ------ context value (stable as long as callbacks are stable) ------\r\n\r\n const contextValue: ToasterContextValue = useMemo(\r\n () => ({\r\n addToast,\r\n updateToast,\r\n dismissToast,\r\n removeToast,\r\n config: {\r\n maxVisible,\r\n position: defaultPosition,\r\n duration: defaultDuration,\r\n },\r\n }),\r\n [\r\n addToast,\r\n updateToast,\r\n dismissToast,\r\n removeToast,\r\n maxVisible,\r\n defaultPosition,\r\n defaultDuration,\r\n ],\r\n );\r\n\r\n // ------ group toasts by position ------\r\n\r\n const groupedToasts = useMemo(() => {\r\n const groups: Record<ToastPosition, InternalToast[]> = {\r\n \"top-right\": [],\r\n \"top-left\": [],\r\n \"top-center\": [],\r\n \"bottom-right\": [],\r\n \"bottom-left\": [],\r\n \"bottom-center\": [],\r\n };\r\n for (const t of toasts) {\r\n groups[t.position].push(t);\r\n }\r\n return groups;\r\n }, [toasts]);\r\n\r\n return (\r\n <ToasterContext.Provider value={contextValue}>\r\n {children}\r\n\r\n {/* Render one container per position that has toasts */}\r\n {ALL_POSITIONS.map((pos) =>\r\n groupedToasts[pos].length > 0 ? (\r\n <ToastContainer\r\n key={pos}\r\n position={pos}\r\n toasts={groupedToasts[pos]}\r\n maxVisible={maxVisible}\r\n />\r\n ) : null,\r\n )}\r\n </ToasterContext.Provider>\r\n );\r\n};\r\n\r\nToast23Provider.displayName = \"Toast23Provider\";\r\n","/**\r\n * toast-23 โ€” useToast Hook\r\n *\r\n * Returns a callable `ToastApi` object:\r\n *\r\n * ```ts\r\n * const toast = useToast();\r\n *\r\n * toast(\"Hello!\"); // default variant\r\n * toast.success(\"Done!\"); // success variant\r\n * toast.error(\"Oops\"); // error variant\r\n * toast.promise(fetchData(), { ... }); // promise tracking\r\n * toast.dismiss(id); // manual dismiss\r\n * ```\r\n */\r\n\r\n\"use client\";\r\n\r\nimport { useContext, useMemo } from \"react\";\r\nimport { ToasterContext } from \"./context\";\r\nimport type { ToastApi, ToastOptions, PromiseOptions } from \"./types\";\r\nimport type { ReactNode } from \"react\";\r\n\r\nexport function useToast(): ToastApi {\r\n const ctx = useContext(ToasterContext);\r\n\r\n if (!ctx) {\r\n throw new Error(\r\n \"[toast-23] useToast() must be used inside a <Toast23Provider>. \" +\r\n \"Wrap your application root with <Toast23Provider> to fix this.\",\r\n );\r\n }\r\n\r\n return useMemo(() => {\r\n // Base callable โ€” toast(\"message\", opts?)\r\n const toast = ((message: string | ReactNode, options?: ToastOptions) =>\r\n ctx.addToast(message, options)) as ToastApi;\r\n\r\n // Variant shortcuts\r\n toast.success = (msg, opts) =>\r\n ctx.addToast(msg, { ...opts, variant: \"success\" });\r\n\r\n toast.error = (msg, opts) =>\r\n ctx.addToast(msg, { ...opts, variant: \"error\" });\r\n\r\n toast.warning = (msg, opts) =>\r\n ctx.addToast(msg, { ...opts, variant: \"warning\" });\r\n\r\n toast.info = (msg, opts) => ctx.addToast(msg, { ...opts, variant: \"info\" });\r\n\r\n // Loading shortcut\r\n toast.loading = (msg, opts) =>\r\n ctx.addToast(msg, {\r\n ...opts,\r\n variant: \"loading\" as any,\r\n duration: opts?.duration ?? 0,\r\n dismissible: opts?.dismissible ?? false,\r\n });\r\n\r\n // Custom toast โ€” no default styles\r\n toast.custom = (content, opts) =>\r\n ctx.addToast(content, { ...opts, variant: \"default\", isCustom: true });\r\n\r\n // Dismiss (with optional id โ€” omit to dismiss all)\r\n toast.dismiss = (id?: string) => ctx.dismissToast(id);\r\n\r\n // Remove instantly (with optional id โ€” omit to remove all)\r\n toast.remove = (id?: string) => ctx.removeToast(id);\r\n\r\n // Promise tracking (accepts Promise or () => Promise, optional 3rd arg for toast options)\r\n toast.promise = async <T>(\r\n promiseOrFn: Promise<T> | (() => Promise<T>),\r\n opts: PromiseOptions<T>,\r\n toastOpts?: ToastOptions,\r\n ): Promise<T> => {\r\n const id = ctx.addToast(opts.loading, {\r\n ...toastOpts,\r\n variant: \"loading\" as any,\r\n duration: 0,\r\n dismissible: false,\r\n } as ToastOptions);\r\n\r\n const promise =\r\n typeof promiseOrFn === \"function\" ? promiseOrFn() : promiseOrFn;\r\n\r\n try {\r\n const result = await promise;\r\n const msg =\r\n typeof opts.success === \"function\"\r\n ? opts.success(result)\r\n : opts.success;\r\n ctx.updateToast(id, {\r\n message: msg,\r\n variant: \"success\",\r\n duration: toastOpts?.duration ?? ctx.config.duration,\r\n dismissible: true,\r\n });\r\n return result;\r\n } catch (error) {\r\n const msg =\r\n typeof opts.error === \"function\" ? opts.error(error) : opts.error;\r\n ctx.updateToast(id, {\r\n message: msg,\r\n variant: \"error\",\r\n duration: toastOpts?.duration ?? ctx.config.duration,\r\n dismissible: true,\r\n });\r\n throw error;\r\n }\r\n };\r\n\r\n return toast;\r\n }, [\r\n ctx.addToast,\r\n ctx.updateToast,\r\n ctx.dismissToast,\r\n ctx.removeToast,\r\n ctx.config.duration,\r\n ]);\r\n}\r\n","/**\r\n * toast-23 โ€” Standalone / Imperative API\r\n *\r\n * Use this when you need toast notifications outside of React (Angular, Vue,\r\n * Svelte, vanilla JS, etc.). It internally bootstraps a minimal React root.\r\n *\r\n * ```ts\r\n * import { createToast23 } from \"toast-23\";\r\n *\r\n * const toast = createToast23({ position: \"top-right\" });\r\n *\r\n * toast.success(\"Saved!\");\r\n * toast.error(\"Something went wrong\");\r\n * toast.dismiss(id);\r\n *\r\n * // Cleanup when done (e.g. on app destroy)\r\n * toast.destroy();\r\n * ```\r\n */\r\n\r\nimport * as React from \"react\";\r\nimport { createRoot, type Root } from \"react-dom/client\";\r\nimport { Toast23Provider } from \"./provider\";\r\nimport { useToast } from \"./use-toast\";\r\nimport type {\r\n ToastPosition,\r\n ToastOptions,\r\n PromiseOptions,\r\n ToastApi,\r\n} from \"./types\";\r\nimport type { ReactNode } from \"react\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface StandaloneOptions {\r\n /** Where on screen toasts appear. @default \"top-right\" */\r\n position?: ToastPosition;\r\n /** Max simultaneous toasts. @default 5 */\r\n maxVisible?: number;\r\n /** Default auto-dismiss duration in ms. @default 5000 */\r\n duration?: number;\r\n}\r\n\r\nexport interface StandaloneToastApi {\r\n /** Show a default toast. Returns the toast id. */\r\n (message: string | ReactNode, options?: ToastOptions): string;\r\n /** Show a success toast. */\r\n success: (message: string, options?: Omit<ToastOptions, \"variant\">) => string;\r\n /** Show an error toast. */\r\n error: (message: string, options?: Omit<ToastOptions, \"variant\">) => string;\r\n /** Show a warning toast. */\r\n warning: (message: string, options?: Omit<ToastOptions, \"variant\">) => string;\r\n /** Show an info toast. */\r\n info: (message: string, options?: Omit<ToastOptions, \"variant\">) => string;\r\n /** Show a loading toast. Returns the toast id for later update. */\r\n loading: (message: string, options?: Omit<ToastOptions, \"variant\">) => string;\r\n /** Show a custom toast with JSX content and no default styles. */\r\n custom: (\r\n content: ReactNode,\r\n options?: Omit<ToastOptions, \"variant\">,\r\n ) => string;\r\n /** Track an async operation with loading โ†’ success / error transitions. */\r\n promise: <T>(\r\n promise: Promise<T> | (() => Promise<T>),\r\n options: PromiseOptions<T>,\r\n toastOptions?: ToastOptions,\r\n ) => Promise<T>;\r\n /** Manually dismiss a toast by id. Omit id to dismiss all. */\r\n dismiss: (id?: string) => void;\r\n /** Instantly remove a toast from DOM (no exit animation). Omit id to remove all. */\r\n remove: (id?: string) => void;\r\n /** Unmount the React root and remove the container from the DOM. */\r\n destroy: () => void;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Bridge component โ€” captures the useToast API and passes it out\r\n// ---------------------------------------------------------------------------\r\n\r\nlet _resolveApi: ((api: ToastApi) => void) | null = null;\r\n\r\nfunction Bridge() {\r\n const api = useToast();\r\n\r\n // Resolve the promise on first render; update the ref on every render\r\n // so the external caller always has the latest stable API reference.\r\n React.useEffect(() => {\r\n if (_resolveApi) {\r\n _resolveApi(api);\r\n _resolveApi = null;\r\n }\r\n }, [api]);\r\n\r\n // Also store on ref for synchronous access after first mount\r\n\r\n return null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Factory\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Create a standalone toast API that works outside of React.\r\n *\r\n * Internally mounts a tiny React tree (provider + bridge) into a hidden\r\n * container. Returns a callable toast object with `.success()`, `.error()`, etc.\r\n *\r\n * Call `.destroy()` when your application unmounts to clean up.\r\n */\r\nexport function createToast23(\r\n options: StandaloneOptions = {},\r\n): StandaloneToastApi {\r\n const { position = \"top-right\", maxVisible = 5, duration = 5000 } = options;\r\n\r\n // Create a hidden container\r\n const container = document.createElement(\"div\");\r\n container.setAttribute(\"data-toast23-standalone\", \"\");\r\n container.style.display = \"contents\"; // invisible wrapper\r\n document.body.appendChild(container);\r\n\r\n // We need to wait for React to render before the API is available.\r\n // Use a promise + queue approach so calls before mount are buffered.\r\n let root: Root | null = createRoot(container);\r\n\r\n const apiReady = new Promise<ToastApi>((resolve) => {\r\n _resolveApi = resolve;\r\n });\r\n\r\n // Queue for calls made before React has mounted\r\n type QueuedCall = { method: string; args: unknown[] };\r\n const queue: QueuedCall[] = [];\r\n let resolvedApi: ToastApi | null = null;\r\n\r\n // Flush queued calls once the API is ready\r\n apiReady.then((api) => {\r\n resolvedApi = api;\r\n for (const call of queue) {\r\n if (call.method === \"__call__\") {\r\n (api as any)(...call.args);\r\n } else {\r\n (api as any)[call.method](...call.args);\r\n }\r\n }\r\n queue.length = 0;\r\n });\r\n\r\n // Mount React tree\r\n root.render(\r\n React.createElement(\r\n Toast23Provider,\r\n { position, maxVisible, duration } as any,\r\n React.createElement(Bridge),\r\n ),\r\n );\r\n\r\n // Build the proxy API\r\n const proxyCall = (method: string, ...args: unknown[]): any => {\r\n if (resolvedApi) {\r\n return (resolvedApi as any)[method](...args);\r\n }\r\n queue.push({ method, args });\r\n return \"queued\";\r\n };\r\n\r\n const toast = ((message: string | ReactNode, opts?: ToastOptions) => {\r\n if (resolvedApi) return resolvedApi(message, opts);\r\n queue.push({ method: \"__call__\", args: [message, opts] });\r\n return \"queued\";\r\n }) as StandaloneToastApi;\r\n\r\n toast.success = (msg, opts) => proxyCall(\"success\", msg, opts);\r\n toast.error = (msg, opts) => proxyCall(\"error\", msg, opts);\r\n toast.warning = (msg, opts) => proxyCall(\"warning\", msg, opts);\r\n toast.info = (msg, opts) => proxyCall(\"info\", msg, opts);\r\n toast.loading = (msg, opts) => proxyCall(\"loading\", msg, opts);\r\n toast.custom = (content, opts) => proxyCall(\"custom\", content, opts);\r\n toast.dismiss = (id?) => proxyCall(\"dismiss\", id);\r\n toast.remove = (id?) => proxyCall(\"remove\", id);\r\n\r\n toast.promise = (promise, opts, toastOpts?) => {\r\n if (resolvedApi) return resolvedApi.promise(promise, opts, toastOpts);\r\n // For promises, we need to wait for the API\r\n return apiReady.then((api) => api.promise(promise, opts, toastOpts));\r\n };\r\n\r\n toast.destroy = () => {\r\n if (root) {\r\n root.unmount();\r\n root = null;\r\n }\r\n container.remove();\r\n resolvedApi = null;\r\n };\r\n\r\n return toast;\r\n}\r\n"],"names":["ToasterContext","createContext","toasterReducer","state","action","t","CheckCircleIcon","props","jsxs","jsx","XCircleIcon","AlertTriangleIcon","InfoIcon","XIcon","SpinnerIcon","counter","generateId","cx","args","variantIcon","EXIT_DURATION","MIN_REFILL_DURATION","ToastItem","React","toast","onDismiss","onRemove","hasEntered","setHasEntered","useState","useEffect","raf","delay","timer","isPaused","setIsPaused","remainingRef","useRef","startRef","progress","setProgress","progressTransition","setProgressTransition","rafRef","elapsed","refillDuration","remaining","handleMouseEnter","useCallback","handleMouseLeave","Icon","ToastContainer","position","toasts","maxVisible","ctx","useContext","active","exiting","visible","queuedCount","ALL_POSITIONS","Toast23Provider","children","defaultPosition","defaultDuration","dispatch","useReducer","addToast","message","options","id","updateToast","updates","dismissToast","removeToast","contextValue","useMemo","groupedToasts","groups","pos","useToast","msg","opts","content","promiseOrFn","toastOpts","promise","result","error","_resolveApi","Bridge","api","createToast23","duration","container","root","createRoot","apiReady","resolve","queue","resolvedApi","call","proxyCall","method"],"mappings":"gcAeaA,EAAiBC,EAAAA,cAA0C,IAAI,EAMrE,SAASC,EACdC,EACAC,EACiB,CACjB,OAAQA,EAAO,KAAA,CACb,IAAK,MACH,MAAO,CAAC,GAAGD,EAAOC,EAAO,KAAK,EAEhC,IAAK,SAEH,OADeD,EAAM,KAAM,GAAM,EAAE,KAAOC,EAAO,MAAM,EAAE,EAEhDD,EAAM,IAAK,GAChB,EAAE,KAAOC,EAAO,MAAM,GAClB,CACE,GAAG,EACH,GAAGA,EAAO,MACV,QAAS,EAAE,QAAU,EACrB,UAAW,EAAA,EAEb,CAAA,EAGD,CAAC,GAAGD,EAAOC,EAAO,KAAK,EAGhC,IAAK,SACH,OAAOD,EAAM,IAAKE,GAChBA,EAAE,KAAOD,EAAO,GACZ,CACE,GAAGC,EACH,GAAGD,EAAO,QAEV,QAASC,EAAE,QAAU,EAErB,UAAW,EAAA,EAEbA,CAAA,EAGR,IAAK,UAEH,OAAKD,EAAO,GAGLD,EAAM,IAAKE,GAChBA,EAAE,KAAOD,EAAO,GAAK,CAAE,GAAGC,EAAG,UAAW,IAASA,CAAA,EAH1CF,EAAM,IAAKE,IAAO,CAAE,GAAGA,EAAG,UAAW,EAAA,EAAO,EAMvD,IAAK,SAEH,OAAKD,EAAO,GACLD,EAAM,OAAQE,GAAMA,EAAE,KAAOD,EAAO,EAAE,EADtB,CAAA,EAGzB,QACE,OAAOD,CAAA,CAEb,CCjEO,MAAMG,EAAkCC,GAC7CC,EAAAA,KAAC,MAAA,CACC,MAAM,6BACN,QAAQ,YACR,MAAM,SACN,OAAO,SACP,KAAK,OACJ,GAAGD,EAEJ,SAAA,CAAAE,EAAAA,IAAC,SAAA,CAAO,GAAI,GAAI,GAAI,GAAI,EAAG,GAAI,KAAK,cAAA,CAAe,EACnDA,EAAAA,IAAC,OAAA,CACC,EAAE,sBACF,OAAO,OACP,YAAa,EACb,cAAc,QACd,eAAe,QACf,KAAK,MAAA,CAAA,CACP,CAAA,CACF,EAIWC,EAA8BH,GACzCC,EAAAA,KAAC,MAAA,CACC,MAAM,6BACN,QAAQ,YACR,MAAM,SACN,OAAO,SACP,KAAK,OACJ,GAAGD,EAEJ,SAAA,CAAAE,EAAAA,IAAC,SAAA,CAAO,GAAI,GAAI,GAAI,GAAI,EAAG,GAAI,KAAK,cAAA,CAAe,EACnDA,EAAAA,IAAC,OAAA,CACC,GAAI,GACJ,GAAI,EACJ,GAAI,GACJ,GAAI,GACJ,OAAO,OACP,YAAa,EACb,cAAc,OAAA,CAAA,EAEhBA,EAAAA,IAAC,UAAO,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,KAAK,MAAA,CAAO,CAAA,CAAA,CAC5C,EAIWE,EAAoCJ,GAC/CC,EAAAA,KAAC,MAAA,CACC,MAAM,6BACN,QAAQ,YACR,MAAM,SACN,OAAO,SACP,KAAK,OACJ,GAAGD,EAEJ,SAAA,CAAAE,EAAAA,IAAC,OAAA,CACC,EAAE,2FACF,KAAK,cAAA,CAAA,EAEPA,EAAAA,IAAC,OAAA,CACC,GAAI,GACJ,GAAI,IACJ,GAAI,GACJ,GAAI,GACJ,OAAO,OACP,YAAa,EACb,cAAc,OAAA,CAAA,EAEhBA,EAAAA,IAAC,UAAO,GAAI,GAAI,GAAI,GAAI,EAAG,EAAG,KAAK,MAAA,CAAO,CAAA,CAAA,CAC5C,EAIWG,EAA2BL,GACtCC,EAAAA,KAAC,MAAA,CACC,MAAM,6BACN,QAAQ,YACR,MAAM,SACN,OAAO,SACP,KAAK,OACJ,GAAGD,EAEJ,SAAA,CAAAE,EAAAA,IAAC,SAAA,CAAO,GAAI,GAAI,GAAI,GAAI,EAAG,GAAI,KAAK,cAAA,CAAe,EACnDA,EAAAA,IAAC,OAAA,CACC,GAAI,GACJ,GAAI,GACJ,GAAI,GACJ,GAAI,GACJ,OAAO,OACP,YAAa,EACb,cAAc,OAAA,CAAA,EAEhBA,EAAAA,IAAC,UAAO,GAAI,GAAI,GAAI,EAAG,EAAG,EAAG,KAAK,MAAA,CAAO,CAAA,CAAA,CAC3C,EAIWI,EAAwBN,GACnCC,EAAAA,KAAC,MAAA,CACC,MAAM,6BACN,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAa,EACb,cAAc,QACd,eAAe,QACf,MAAM,UACN,OAAO,UACN,GAAGD,EAEJ,SAAA,CAAAE,EAAAA,IAAC,OAAA,CAAK,GAAI,GAAI,GAAI,EAAG,GAAI,EAAG,GAAI,EAAA,CAAI,EACpCA,EAAAA,IAAC,QAAK,GAAI,EAAG,GAAI,EAAG,GAAI,GAAI,GAAI,EAAA,CAAI,CAAA,CAAA,CACtC,EAIWK,EAA8BP,GACzCE,EAAAA,IAAC,MAAA,CACC,MAAM,6BACN,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAa,EACb,cAAc,QACd,eAAe,QACf,MAAM,SACN,OAAO,SACP,UAAU,kBACT,GAAGF,EAEJ,SAAAE,EAAAA,IAAC,OAAA,CAAK,EAAE,6BAAA,CAA8B,CAAA,CACxC,EC3IF,IAAIM,EAAU,EAMP,SAASC,GAAqB,CACnC,MAAO,OAAO,EAAED,CAAO,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,EAAG,CAAC,CAAC,EACnE,CAKO,SAASE,KAAMC,EAAyD,CAC7E,OAAOA,EAAK,OAAO,OAAO,EAAE,KAAK,GAAG,CACtC,CCOA,MAAMC,EAAuE,CAC3E,QAASb,EACT,MAAOI,EACP,QAASC,EACT,KAAMC,EACN,QAASA,EACT,QAASE,CACX,EAYMM,EAAgB,IAChBC,EAAsB,IAEfC,EAAsCC,EAAM,KACvD,CAAC,CAAE,MAAAC,EAAO,UAAAC,EAAW,SAAAC,KAAe,CAElC,KAAM,CAACC,EAAYC,CAAa,EAAIC,EAAAA,SAAS,EAAK,EAGlDC,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAM,sBAAsB,IAAMH,EAAc,EAAI,CAAC,EAC3D,MAAO,IAAM,qBAAqBG,CAAG,CACvC,EAAG,CAAA,CAAE,EAILD,EAAAA,UAAU,IAAM,CACd,GAAI,CAACN,EAAM,UAAW,OACtB,MAAMQ,EAAQR,EAAM,aAAeJ,EAC7Ba,EAAQ,WAAW,IAAMP,EAASF,EAAM,EAAE,EAAGQ,CAAK,EACxD,MAAO,IAAM,aAAaC,CAAK,CACjC,EAAG,CAACT,EAAM,UAAWA,EAAM,GAAIA,EAAM,YAAaE,CAAQ,CAAC,EAG3D,KAAM,CAACQ,EAAUC,CAAW,EAAIN,EAAAA,SAAS,EAAK,EACxCO,EAAeC,EAAAA,OAAOb,EAAM,QAAQ,EACpCc,EAAWD,EAAAA,OAAO,CAAC,EAInB,CAACE,EAAUC,CAAW,EAAIX,EAAAA,SAAS,GAAG,EAEtC,CAACY,EAAoBC,CAAqB,EAAIb,EAAAA,SAAS,MAAM,EAC7Dc,EAASN,EAAAA,OAAe,CAAC,EAG/BP,EAAAA,UAAU,IAAM,CACdM,EAAa,QAAUZ,EAAM,SAC7BgB,EAAY,GAAG,EACfE,EAAsB,MAAM,CAC9B,EAAG,CAAClB,EAAM,QAASA,EAAM,QAAQ,CAAC,EAElCM,EAAAA,UAAU,IAAM,CAEd,GACEN,EAAM,UAAY,GAClBA,EAAM,UAAY,WAClB,CAACG,GACDH,EAAM,UAEN,OAEF,GAAIU,EAAU,CAEZ,MAAMU,EAAU,KAAK,IAAA,EAAQN,EAAS,QAEtCF,EAAa,QAAU,KAAK,IAAI,EAAGA,EAAa,QAAUQ,CAAO,EAGjE,MAAMC,EAAiB,KAAK,IAAIxB,EAAqBuB,CAAO,EAC5DF,EAAsB,SAASG,CAAc,aAAa,EAC1DL,EAAY,GAAG,EACf,MACF,CAGAF,EAAS,QAAU,KAAK,IAAA,EACxB,MAAMQ,EAAYV,EAAa,QAI/BO,EAAO,QAAU,sBAAsB,IAAM,CAC3CD,EAAsB,SAASI,CAAS,WAAW,EACnDN,EAAY,CAAC,CACf,CAAC,EAED,MAAMP,EAAQ,WAAW,IAAM,CAC7BR,EAAUD,EAAM,EAAE,CACpB,EAAGsB,CAAS,EAEZ,MAAO,IAAM,CACX,aAAab,CAAK,EAClB,qBAAqBU,EAAO,OAAO,CACrC,CACF,EAAG,CACDT,EACAP,EACAH,EAAM,UACNA,EAAM,SACNA,EAAM,QACNA,EAAM,GACNA,EAAM,QACNC,CAAA,CACD,EAGD,MAAMsB,EAAmBC,EAAAA,YAAY,IAAMb,EAAY,EAAI,EAAG,CAAA,CAAE,EAC1Dc,EAAmBD,EAAAA,YAAY,IAAMb,EAAY,EAAK,EAAG,CAAA,CAAE,EAG3De,EAAO/B,EAAYK,EAAM,OAAO,GAAKZ,EAG3C,OAAIY,EAAM,SAENf,EAAAA,IAAC,MAAA,CACC,UAAWQ,EACT,oCACA,CAACU,GAAc,yBACfH,EAAM,WAAa,uBAAA,EAErB,KAAK,QACL,YAAU,SACV,cAAY,OACZ,aAAcuB,EACd,aAAcE,EAEb,SAAAzB,EAAM,OAAA,CAAA,EAMXhB,EAAAA,KAAC,MAAA,CACC,UAAWS,EACT,eACA,iBAAiBO,EAAM,OAAO,GAC9B,CAACG,GAAc,yBACfH,EAAM,WAAa,uBAAA,EAErB,KAAK,QACL,YAAWA,EAAM,UAAY,QAAU,YAAc,SACrD,cAAY,OACZ,aAAcuB,EACd,aAAcE,EAGd,SAAA,CAAAxC,EAAAA,IAAC,OAAA,CAAK,UAAWQ,EAAG,eAAgB,iBAAiBO,EAAM,OAAO,EAAE,EAClE,SAAAf,EAAAA,IAACyC,EAAA,CAAA,CAAK,EACR,EAGA1C,EAAAA,KAAC,MAAA,CAAI,UAAU,kBACZ,SAAA,CAAAgB,EAAM,OAASf,EAAAA,IAAC,MAAA,CAAI,UAAU,gBAAiB,WAAM,MAAM,EAC5DA,EAAAA,IAAC,MAAA,CACC,UAAWQ,EACT,kBACAO,EAAM,OAAS,6BAAA,EAGhB,SAAAA,EAAM,OAAA,CAAA,CACT,EACF,EAGCA,EAAM,aACLf,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,UAAU,kBACV,QAAS,IAAMgB,EAAUD,EAAM,EAAE,EACjC,aAAW,uBAEX,eAACX,EAAA,CAAA,CAAM,CAAA,CAAA,EAKVW,EAAM,SAAW,GAAKA,EAAM,UAAY,WACvCf,EAAAA,IAAC,MAAA,CACC,UAAWQ,EACT,mBACA,qBAAqBO,EAAM,OAAO,EAAA,EAEpC,MAAO,CACL,MAAO,GAAGe,CAAQ,IAClB,WAAYE,CAAA,CACd,CAAA,CACF,CAAA,CAAA,CAIR,CACF,EAEAnB,EAAU,YAAc,YC9MjB,MAAM6B,EAAgD5B,EAAM,KACjE,CAAC,CAAE,SAAA6B,EAAU,OAAAC,EAAQ,WAAAC,KAAsC,CACzD,MAAMC,EAAMC,EAAAA,WAAWxD,CAAc,EACrC,GAAI,CAACuD,EAAK,OAAO,KAGjB,MAAME,EAASJ,EAAO,OAAQhD,GAAM,CAACA,EAAE,SAAS,EAC1CqD,EAAUL,EAAO,OAAQhD,GAAMA,EAAE,SAAS,EAG1CsD,EAAU,CAAC,GAAGF,EAAO,MAAM,EAAGH,CAAU,EAAG,GAAGI,CAAO,EAE3D,GAAIC,EAAQ,SAAW,EAAG,OAAO,KAGjC,MAAMC,EAAc,KAAK,IAAI,EAAGH,EAAO,OAASH,CAAU,EAE1D,OACE9C,EAAAA,KAAC,MAAA,CACC,UAAWS,EAAG,oBAAqB,sBAAsBmC,CAAQ,EAAE,EACnE,aAAW,gBACX,KAAK,SAEJ,SAAA,CAAAO,EAAQ,IAAKnC,GACZf,EAAAA,IAACa,EAAA,CAEC,MAAAE,EACA,UAAW+B,EAAI,aACf,SAAUA,EAAI,WAAA,EAHT/B,EAAM,EAAA,CAKd,EACAoC,EAAc,GACbpD,EAAAA,KAAC,OAAI,UAAU,sBAAsB,YAAU,SAAS,SAAA,CAAA,IACpDoD,EAAY,OAAA,CAAA,CAChB,CAAA,CAAA,CAAA,CAIR,CACF,EAEAT,EAAe,YAAc,iBCrC7B,MAAMU,EAAiC,CACrC,YACA,WACA,aACA,eACA,cACA,eACF,EAEaC,EAAkD,CAAC,CAC9D,SAAAC,EACA,WAAAT,EAAa,EACb,SAAUU,EAAkB,YAC5B,SAAUC,EAAkB,GAC9B,IAAM,CACJ,KAAM,CAACZ,EAAQa,CAAQ,EAAIC,EAAAA,WAAWjE,EAAgB,CAAA,CAAE,EAIlDkE,EAAWpB,EAAAA,YACf,CAACqB,EAA6BC,IAA2E,CACvG,MAAMC,GAAKD,GAAA,YAAAA,EAAS,KAAMtD,EAAA,EACpBQ,EAAuB,CAC3B,GAAA+C,EACA,QAAAF,EACA,MAAOC,GAAA,YAAAA,EAAS,MAChB,SAASA,GAAA,YAAAA,EAAS,UAAW,UAC7B,UAAUA,GAAA,YAAAA,EAAS,WAAYL,EAC/B,UAAUK,GAAA,YAAAA,EAAS,WAAYN,EAC/B,aAAaM,GAAA,YAAAA,EAAS,cAAe,GACrC,aAAaA,GAAA,YAAAA,EAAS,cAAe,IACrC,UAAW,GACX,UAAW,KAAK,IAAA,EAChB,QAAS,EACT,SAAUA,GAAA,YAAAA,EAAS,QAAA,EAGrB,OAAIA,GAAA,MAAAA,EAAS,GACXJ,EAAS,CAAE,KAAM,SAAU,MAAA1C,CAAA,CAAO,EAElC0C,EAAS,CAAE,KAAM,MAAO,MAAA1C,CAAA,CAAO,EAE1B+C,CACT,EACA,CAACN,EAAiBD,CAAe,CAAA,EAG7BQ,EAAcxB,EAAAA,YAClB,CACEuB,EACAE,IAMG,CACHP,EAAS,CAAE,KAAM,SAAU,GAAAK,EAAI,QAAAE,EAAS,CAC1C,EACA,CAAA,CAAC,EAGGC,EAAe1B,cAAauB,GAAgB,CAChDL,EAAS,CAAE,KAAM,UAAW,GAAAK,CAAA,CAAI,CAClC,EAAG,CAAA,CAAE,EAECI,EAAc3B,cAAauB,GAAgB,CAC/CL,EAAS,CAAE,KAAM,SAAU,GAAAK,CAAA,CAAI,CACjC,EAAG,CAAA,CAAE,EAICK,EAAoCC,EAAAA,QACxC,KAAO,CACL,SAAAT,EACA,YAAAI,EACA,aAAAE,EACA,YAAAC,EACA,OAAQ,CACN,WAAArB,EACA,SAAUU,EACV,SAAUC,CAAA,CACZ,GAEF,CACEG,EACAI,EACAE,EACAC,EACArB,EACAU,EACAC,CAAA,CACF,EAKIa,EAAgBD,EAAAA,QAAQ,IAAM,CAClC,MAAME,EAAiD,CACrD,YAAa,CAAA,EACb,WAAY,CAAA,EACZ,aAAc,CAAA,EACd,eAAgB,CAAA,EAChB,cAAe,CAAA,EACf,gBAAiB,CAAA,CAAC,EAEpB,UAAW1E,KAAKgD,EACd0B,EAAO1E,EAAE,QAAQ,EAAE,KAAKA,CAAC,EAE3B,OAAO0E,CACT,EAAG,CAAC1B,CAAM,CAAC,EAEX,OACE7C,EAAAA,KAACR,EAAe,SAAf,CAAwB,MAAO4E,EAC7B,SAAA,CAAAb,EAGAF,EAAc,IAAKmB,GAClBF,EAAcE,CAAG,EAAE,OAAS,EAC1BvE,EAAAA,IAAC0C,EAAA,CAEC,SAAU6B,EACV,OAAQF,EAAcE,CAAG,EACzB,WAAA1B,CAAA,EAHK0B,CAAA,EAKL,IAAA,CACN,EACF,CAEJ,EAEAlB,EAAgB,YAAc,kBCvIvB,SAASmB,GAAqB,CACnC,MAAM1B,EAAMC,EAAAA,WAAWxD,CAAc,EAErC,GAAI,CAACuD,EACH,MAAM,IAAI,MACR,+HAAA,EAKJ,OAAOsB,EAAAA,QAAQ,IAAM,CAEnB,MAAMrD,EAAS,CAAC6C,EAA6BC,IAC3Cf,EAAI,SAASc,EAASC,CAAO,EAG/B,OAAA9C,EAAM,QAAU,CAAC0D,EAAKC,IACpB5B,EAAI,SAAS2B,EAAK,CAAE,GAAGC,EAAM,QAAS,SAAA,CAAW,EAEnD3D,EAAM,MAAQ,CAAC0D,EAAKC,IAClB5B,EAAI,SAAS2B,EAAK,CAAE,GAAGC,EAAM,QAAS,OAAA,CAAS,EAEjD3D,EAAM,QAAU,CAAC0D,EAAKC,IACpB5B,EAAI,SAAS2B,EAAK,CAAE,GAAGC,EAAM,QAAS,SAAA,CAAW,EAEnD3D,EAAM,KAAO,CAAC0D,EAAKC,IAAS5B,EAAI,SAAS2B,EAAK,CAAE,GAAGC,EAAM,QAAS,MAAA,CAAQ,EAG1E3D,EAAM,QAAU,CAAC0D,EAAKC,IACpB5B,EAAI,SAAS2B,EAAK,CAChB,GAAGC,EACH,QAAS,UACT,UAAUA,GAAA,YAAAA,EAAM,WAAY,EAC5B,aAAaA,GAAA,YAAAA,EAAM,cAAe,EAAA,CACnC,EAGH3D,EAAM,OAAS,CAAC4D,EAASD,IACvB5B,EAAI,SAAS6B,EAAS,CAAE,GAAGD,EAAM,QAAS,UAAW,SAAU,GAAM,EAGvE3D,EAAM,QAAW+C,GAAgBhB,EAAI,aAAagB,CAAE,EAGpD/C,EAAM,OAAU+C,GAAgBhB,EAAI,YAAYgB,CAAE,EAGlD/C,EAAM,QAAU,MACd6D,EACAF,EACAG,IACe,CACf,MAAMf,EAAKhB,EAAI,SAAS4B,EAAK,QAAS,CACpC,GAAGG,EACH,QAAS,UACT,SAAU,EACV,YAAa,EAAA,CACE,EAEXC,EACJ,OAAOF,GAAgB,WAAaA,IAAgBA,EAEtD,GAAI,CACF,MAAMG,EAAS,MAAMD,EACfL,EACJ,OAAOC,EAAK,SAAY,WACpBA,EAAK,QAAQK,CAAM,EACnBL,EAAK,QACX,OAAA5B,EAAI,YAAYgB,EAAI,CAClB,QAASW,EACT,QAAS,UACT,UAAUI,GAAA,YAAAA,EAAW,WAAY/B,EAAI,OAAO,SAC5C,YAAa,EAAA,CACd,EACMiC,CACT,OAASC,EAAO,CACd,MAAMP,EACJ,OAAOC,EAAK,OAAU,WAAaA,EAAK,MAAMM,CAAK,EAAIN,EAAK,MAC9D,MAAA5B,EAAI,YAAYgB,EAAI,CAClB,QAASW,EACT,QAAS,QACT,UAAUI,GAAA,YAAAA,EAAW,WAAY/B,EAAI,OAAO,SAC5C,YAAa,EAAA,CACd,EACKkC,CACR,CACF,EAEOjE,CACT,EAAG,CACD+B,EAAI,SACJA,EAAI,YACJA,EAAI,aACJA,EAAI,YACJA,EAAI,OAAO,QAAA,CACZ,CACH,CCtCA,IAAImC,EAAgD,KAEpD,SAASC,GAAS,CAChB,MAAMC,EAAMX,EAAA,EAIZ1D,OAAAA,EAAM,UAAU,IAAM,CAChBmE,IACFA,EAAYE,CAAG,EACfF,EAAc,KAElB,EAAG,CAACE,CAAG,CAAC,EAID,IACT,CAcO,SAASC,EACdvB,EAA6B,GACT,CACpB,KAAM,CAAE,SAAAlB,EAAW,YAAa,WAAAE,EAAa,EAAG,SAAAwC,EAAW,KAASxB,EAG9DyB,EAAY,SAAS,cAAc,KAAK,EAC9CA,EAAU,aAAa,0BAA2B,EAAE,EACpDA,EAAU,MAAM,QAAU,WAC1B,SAAS,KAAK,YAAYA,CAAS,EAInC,IAAIC,EAAoBC,EAAAA,WAAWF,CAAS,EAE5C,MAAMG,EAAW,IAAI,QAAmBC,GAAY,CAClDT,EAAcS,CAChB,CAAC,EAIKC,EAAsB,CAAA,EAC5B,IAAIC,EAA+B,KAGnCH,EAAS,KAAMN,GAAQ,CACrBS,EAAcT,EACd,UAAWU,KAAQF,EACbE,EAAK,SAAW,WACjBV,EAAY,GAAGU,EAAK,IAAI,EAExBV,EAAYU,EAAK,MAAM,EAAE,GAAGA,EAAK,IAAI,EAG1CF,EAAM,OAAS,CACjB,CAAC,EAGDJ,EAAK,OACHzE,EAAM,cACJuC,EACA,CAAE,SAAAV,EAAU,WAAAE,EAAY,SAAAwC,CAAA,EACxBvE,EAAM,cAAcoE,CAAM,CAAA,CAC5B,EAIF,MAAMY,EAAY,CAACC,KAAmBtF,IAChCmF,EACMA,EAAoBG,CAAM,EAAE,GAAGtF,CAAI,GAE7CkF,EAAM,KAAK,CAAE,OAAAI,EAAQ,KAAAtF,CAAA,CAAM,EACpB,UAGHM,EAAS,CAAC6C,EAA6Bc,IACvCkB,EAAoBA,EAAYhC,EAASc,CAAI,GACjDiB,EAAM,KAAK,CAAE,OAAQ,WAAY,KAAM,CAAC/B,EAASc,CAAI,EAAG,EACjD,UAGT,OAAA3D,EAAM,QAAU,CAAC0D,EAAKC,IAASoB,EAAU,UAAWrB,EAAKC,CAAI,EAC7D3D,EAAM,MAAQ,CAAC0D,EAAKC,IAASoB,EAAU,QAASrB,EAAKC,CAAI,EACzD3D,EAAM,QAAU,CAAC0D,EAAKC,IAASoB,EAAU,UAAWrB,EAAKC,CAAI,EAC7D3D,EAAM,KAAO,CAAC0D,EAAKC,IAASoB,EAAU,OAAQrB,EAAKC,CAAI,EACvD3D,EAAM,QAAU,CAAC0D,EAAKC,IAASoB,EAAU,UAAWrB,EAAKC,CAAI,EAC7D3D,EAAM,OAAS,CAAC4D,EAASD,IAASoB,EAAU,SAAUnB,EAASD,CAAI,EACnE3D,EAAM,QAAW+C,GAAQgC,EAAU,UAAWhC,CAAE,EAChD/C,EAAM,OAAU+C,GAAQgC,EAAU,SAAUhC,CAAE,EAE9C/C,EAAM,QAAU,CAAC+D,EAASJ,EAAMG,IAC1Be,EAAoBA,EAAY,QAAQd,EAASJ,EAAMG,CAAS,EAE7DY,EAAS,KAAMN,GAAQA,EAAI,QAAQL,EAASJ,EAAMG,CAAS,CAAC,EAGrE9D,EAAM,QAAU,IAAM,CAChBwE,IACFA,EAAK,QAAA,EACLA,EAAO,MAETD,EAAU,OAAA,EACVM,EAAc,IAChB,EAEO7E,CACT"}
@@ -0,0 +1,119 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ /**
4
+ * Create a standalone toast API that works outside of React.
5
+ *
6
+ * Internally mounts a tiny React tree (provider + bridge) into a hidden
7
+ * container. Returns a callable toast object with `.success()`, `.error()`, etc.
8
+ *
9
+ * Call `.destroy()` when your application unmounts to clean up.
10
+ */
11
+ export declare function createToast23(options?: StandaloneOptions): StandaloneToastApi;
12
+
13
+ /** Options for `toast.promise()`. */
14
+ export declare interface PromiseOptions<T> {
15
+ /** Message shown while the promise is pending. */
16
+ loading: string;
17
+ /** Message on fulfillment. Can be a function receiving the resolved value. */
18
+ success: string | ((data: T) => string);
19
+ /** Message on rejection. Can be a function receiving the error. */
20
+ error: string | ((err: unknown) => string);
21
+ }
22
+
23
+ export declare interface StandaloneOptions {
24
+ /** Where on screen toasts appear. @default "top-right" */
25
+ position?: ToastPosition;
26
+ /** Max simultaneous toasts. @default 5 */
27
+ maxVisible?: number;
28
+ /** Default auto-dismiss duration in ms. @default 5000 */
29
+ duration?: number;
30
+ }
31
+
32
+ export declare interface StandaloneToastApi {
33
+ /** Show a default toast. Returns the toast id. */
34
+ (message: string | ReactNode, options?: ToastOptions): string;
35
+ /** Show a success toast. */
36
+ success: (message: string, options?: Omit<ToastOptions, "variant">) => string;
37
+ /** Show an error toast. */
38
+ error: (message: string, options?: Omit<ToastOptions, "variant">) => string;
39
+ /** Show a warning toast. */
40
+ warning: (message: string, options?: Omit<ToastOptions, "variant">) => string;
41
+ /** Show an info toast. */
42
+ info: (message: string, options?: Omit<ToastOptions, "variant">) => string;
43
+ /** Show a loading toast. Returns the toast id for later update. */
44
+ loading: (message: string, options?: Omit<ToastOptions, "variant">) => string;
45
+ /** Show a custom toast with JSX content and no default styles. */
46
+ custom: (content: ReactNode, options?: Omit<ToastOptions, "variant">) => string;
47
+ /** Track an async operation with loading โ†’ success / error transitions. */
48
+ promise: <T>(promise: Promise<T> | (() => Promise<T>), options: PromiseOptions<T>, toastOptions?: ToastOptions) => Promise<T>;
49
+ /** Manually dismiss a toast by id. Omit id to dismiss all. */
50
+ dismiss: (id?: string) => void;
51
+ /** Instantly remove a toast from DOM (no exit animation). Omit id to remove all. */
52
+ remove: (id?: string) => void;
53
+ /** Unmount the React root and remove the container from the DOM. */
54
+ destroy: () => void;
55
+ }
56
+
57
+ export declare const Toast23Provider: React.FC<Toast23ProviderProps>;
58
+
59
+ /** Props for `<Toast23Provider>`. */
60
+ export declare interface Toast23ProviderProps {
61
+ children: ReactNode;
62
+ /** Maximum number of simultaneously visible toasts. @default 5 */
63
+ maxVisible?: number;
64
+ /** Default position on screen. @default "top-right" */
65
+ position?: ToastPosition;
66
+ /** Default auto-dismiss duration in ms. @default 5000 */
67
+ duration?: number;
68
+ }
69
+
70
+ /**
71
+ * The callable toast API returned by `useToast()`.
72
+ *
73
+ * Can be invoked directly โ€” `toast("hi")` โ€” or via variant helpers.
74
+ */
75
+ export declare interface ToastApi {
76
+ (message: string | ReactNode, options?: ToastOptions): string;
77
+ success: (message: string, options?: Omit<ToastOptions, "variant">) => string;
78
+ error: (message: string, options?: Omit<ToastOptions, "variant">) => string;
79
+ warning: (message: string, options?: Omit<ToastOptions, "variant">) => string;
80
+ info: (message: string, options?: Omit<ToastOptions, "variant">) => string;
81
+ /** Show a loading toast. Returns the toast id for later update. */
82
+ loading: (message: string, options?: Omit<ToastOptions, "variant">) => string;
83
+ /** Show a custom toast with JSX content and no default styles. */
84
+ custom: (content: ReactNode, options?: Omit<ToastOptions, "variant">) => string;
85
+ /** Track an async operation with loading โ†’ success / error transitions. */
86
+ promise: <T>(promise: Promise<T> | (() => Promise<T>), options: PromiseOptions<T>, toastOptions?: ToastOptions) => Promise<T>;
87
+ /** Manually dismiss a toast by id. Omit id to dismiss all. */
88
+ dismiss: (id?: string) => void;
89
+ /** Instantly remove a toast from DOM (no exit animation). Omit id to remove all. */
90
+ remove: (id?: string) => void;
91
+ }
92
+
93
+ /** Options accepted when creating a toast. */
94
+ export declare interface ToastOptions {
95
+ /** Provide a fixed id to update an existing toast or prevent duplicates. */
96
+ id?: string;
97
+ /** Optional heading displayed above the message. */
98
+ title?: string;
99
+ /** Visual variant. Defaults to `"default"`. */
100
+ variant?: ToastVariant;
101
+ /** Auto-dismiss duration in ms. `0` = persistent. Defaults to provider value. */
102
+ duration?: number;
103
+ /** Screen position override. Defaults to provider value. */
104
+ position?: ToastPosition;
105
+ /** Whether the user can manually dismiss the toast. Defaults to `true`. */
106
+ dismissible?: boolean;
107
+ /** Delay in ms before removing from DOM after dismiss (for exit animation). @default 1000 */
108
+ removeDelay?: number;
109
+ }
110
+
111
+ /** Screen position where toasts are rendered. */
112
+ export declare type ToastPosition = "top-right" | "top-left" | "top-center" | "bottom-right" | "bottom-left" | "bottom-center";
113
+
114
+ /** Visual variant of a toast notification. */
115
+ export declare type ToastVariant = "success" | "error" | "warning" | "info" | "default";
116
+
117
+ export declare function useToast(): ToastApi;
118
+
119
+ export { }
package/dist/index.mjs ADDED
@@ -0,0 +1,524 @@
1
+ import { jsx as c, jsxs as h } from "react/jsx-runtime";
2
+ import * as E from "react";
3
+ import { createContext as B, useState as k, useEffect as I, useRef as M, useCallback as T, useContext as D, useReducer as q, useMemo as N } from "react";
4
+ import { createRoot as W } from "react-dom/client";
5
+ const A = B(null);
6
+ function j(e, s) {
7
+ switch (s.type) {
8
+ case "ADD":
9
+ return [...e, s.toast];
10
+ case "UPSERT":
11
+ return e.some((r) => r.id === s.toast.id) ? e.map(
12
+ (r) => r.id === s.toast.id ? {
13
+ ...r,
14
+ ...s.toast,
15
+ version: r.version + 1,
16
+ isExiting: !1
17
+ } : r
18
+ ) : [...e, s.toast];
19
+ case "UPDATE":
20
+ return e.map(
21
+ (t) => t.id === s.id ? {
22
+ ...t,
23
+ ...s.updates,
24
+ // Bump version so progress bar restarts
25
+ version: t.version + 1,
26
+ // If the toast was exiting, cancel exit on update
27
+ isExiting: !1
28
+ } : t
29
+ );
30
+ case "DISMISS":
31
+ return s.id ? e.map(
32
+ (t) => t.id === s.id ? { ...t, isExiting: !0 } : t
33
+ ) : e.map((t) => ({ ...t, isExiting: !0 }));
34
+ case "REMOVE":
35
+ return s.id ? e.filter((t) => t.id !== s.id) : [];
36
+ default:
37
+ return e;
38
+ }
39
+ }
40
+ const U = (e) => /* @__PURE__ */ h(
41
+ "svg",
42
+ {
43
+ xmlns: "http://www.w3.org/2000/svg",
44
+ viewBox: "0 0 24 24",
45
+ width: "1.25em",
46
+ height: "1.25em",
47
+ fill: "none",
48
+ ...e,
49
+ children: [
50
+ /* @__PURE__ */ c("circle", { cx: 12, cy: 12, r: 10, fill: "currentColor" }),
51
+ /* @__PURE__ */ c(
52
+ "path",
53
+ {
54
+ d: "M8 12.5l2.5 2.5 5-5",
55
+ stroke: "#fff",
56
+ strokeWidth: 2,
57
+ strokeLinecap: "round",
58
+ strokeLinejoin: "round",
59
+ fill: "none"
60
+ }
61
+ )
62
+ ]
63
+ }
64
+ ), F = (e) => /* @__PURE__ */ h(
65
+ "svg",
66
+ {
67
+ xmlns: "http://www.w3.org/2000/svg",
68
+ viewBox: "0 0 24 24",
69
+ width: "1.25em",
70
+ height: "1.25em",
71
+ fill: "none",
72
+ ...e,
73
+ children: [
74
+ /* @__PURE__ */ c("circle", { cx: 12, cy: 12, r: 10, fill: "currentColor" }),
75
+ /* @__PURE__ */ c(
76
+ "line",
77
+ {
78
+ x1: 12,
79
+ y1: 8,
80
+ x2: 12,
81
+ y2: 13,
82
+ stroke: "#fff",
83
+ strokeWidth: 2,
84
+ strokeLinecap: "round"
85
+ }
86
+ ),
87
+ /* @__PURE__ */ c("circle", { cx: 12, cy: 16, r: 1, fill: "#fff" })
88
+ ]
89
+ }
90
+ ), X = (e) => /* @__PURE__ */ h(
91
+ "svg",
92
+ {
93
+ xmlns: "http://www.w3.org/2000/svg",
94
+ viewBox: "0 0 24 24",
95
+ width: "1.25em",
96
+ height: "1.25em",
97
+ fill: "none",
98
+ ...e,
99
+ children: [
100
+ /* @__PURE__ */ c(
101
+ "path",
102
+ {
103
+ d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z",
104
+ fill: "currentColor"
105
+ }
106
+ ),
107
+ /* @__PURE__ */ c(
108
+ "line",
109
+ {
110
+ x1: 12,
111
+ y1: 9.5,
112
+ x2: 12,
113
+ y2: 14,
114
+ stroke: "#fff",
115
+ strokeWidth: 2,
116
+ strokeLinecap: "round"
117
+ }
118
+ ),
119
+ /* @__PURE__ */ c("circle", { cx: 12, cy: 17, r: 1, fill: "#fff" })
120
+ ]
121
+ }
122
+ ), L = (e) => /* @__PURE__ */ h(
123
+ "svg",
124
+ {
125
+ xmlns: "http://www.w3.org/2000/svg",
126
+ viewBox: "0 0 24 24",
127
+ width: "1.25em",
128
+ height: "1.25em",
129
+ fill: "none",
130
+ ...e,
131
+ children: [
132
+ /* @__PURE__ */ c("circle", { cx: 12, cy: 12, r: 10, fill: "currentColor" }),
133
+ /* @__PURE__ */ c(
134
+ "line",
135
+ {
136
+ x1: 12,
137
+ y1: 11,
138
+ x2: 12,
139
+ y2: 16,
140
+ stroke: "#fff",
141
+ strokeWidth: 2,
142
+ strokeLinecap: "round"
143
+ }
144
+ ),
145
+ /* @__PURE__ */ c("circle", { cx: 12, cy: 8, r: 1, fill: "#fff" })
146
+ ]
147
+ }
148
+ ), z = (e) => /* @__PURE__ */ h(
149
+ "svg",
150
+ {
151
+ xmlns: "http://www.w3.org/2000/svg",
152
+ viewBox: "0 0 24 24",
153
+ fill: "none",
154
+ stroke: "currentColor",
155
+ strokeWidth: 2,
156
+ strokeLinecap: "round",
157
+ strokeLinejoin: "round",
158
+ width: "0.875em",
159
+ height: "0.875em",
160
+ ...e,
161
+ children: [
162
+ /* @__PURE__ */ c("line", { x1: 18, y1: 6, x2: 6, y2: 18 }),
163
+ /* @__PURE__ */ c("line", { x1: 6, y1: 6, x2: 18, y2: 18 })
164
+ ]
165
+ }
166
+ ), H = (e) => /* @__PURE__ */ c(
167
+ "svg",
168
+ {
169
+ xmlns: "http://www.w3.org/2000/svg",
170
+ viewBox: "0 0 24 24",
171
+ fill: "none",
172
+ stroke: "currentColor",
173
+ strokeWidth: 2,
174
+ strokeLinecap: "round",
175
+ strokeLinejoin: "round",
176
+ width: "1.25em",
177
+ height: "1.25em",
178
+ className: "toast23-spinner",
179
+ ...e,
180
+ children: /* @__PURE__ */ c("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
181
+ }
182
+ );
183
+ let V = 0;
184
+ function G() {
185
+ return `t23-${++V}-${Math.random().toString(36).slice(2, 9)}`;
186
+ }
187
+ function w(...e) {
188
+ return e.filter(Boolean).join(" ");
189
+ }
190
+ const J = {
191
+ success: U,
192
+ error: F,
193
+ warning: X,
194
+ info: L,
195
+ default: L,
196
+ loading: H
197
+ }, K = 300, Q = 200, S = E.memo(
198
+ ({ toast: e, onDismiss: s, onRemove: t }) => {
199
+ const [r, l] = k(!1);
200
+ I(() => {
201
+ const x = requestAnimationFrame(() => l(!0));
202
+ return () => cancelAnimationFrame(x);
203
+ }, []), I(() => {
204
+ if (!e.isExiting) return;
205
+ const x = e.removeDelay ?? K, b = setTimeout(() => t(e.id), x);
206
+ return () => clearTimeout(b);
207
+ }, [e.isExiting, e.id, e.removeDelay, t]);
208
+ const [u, f] = k(!1), d = M(e.duration), a = M(0), [g, m] = k(100), [o, i] = k("none"), n = M(0);
209
+ I(() => {
210
+ d.current = e.duration, m(100), i("none");
211
+ }, [e.version, e.duration]), I(() => {
212
+ if (e.duration <= 0 || e.variant === "loading" || !r || e.isExiting)
213
+ return;
214
+ if (u) {
215
+ const R = Date.now() - a.current;
216
+ d.current = Math.max(0, d.current - R);
217
+ const $ = Math.max(Q, R);
218
+ i(`width ${$}ms ease-out`), m(100);
219
+ return;
220
+ }
221
+ a.current = Date.now();
222
+ const x = d.current;
223
+ n.current = requestAnimationFrame(() => {
224
+ i(`width ${x}ms linear`), m(0);
225
+ });
226
+ const b = setTimeout(() => {
227
+ s(e.id);
228
+ }, x);
229
+ return () => {
230
+ clearTimeout(b), cancelAnimationFrame(n.current);
231
+ };
232
+ }, [
233
+ u,
234
+ r,
235
+ e.isExiting,
236
+ e.duration,
237
+ e.variant,
238
+ e.id,
239
+ e.version,
240
+ s
241
+ ]);
242
+ const v = T(() => f(!0), []), y = T(() => f(!1), []), p = J[e.variant] ?? L;
243
+ return e.isCustom ? /* @__PURE__ */ c(
244
+ "div",
245
+ {
246
+ className: w(
247
+ "toast23-item toast23-item--custom",
248
+ !r && "toast23-item--entering",
249
+ e.isExiting && "toast23-item--exiting"
250
+ ),
251
+ role: "alert",
252
+ "aria-live": "polite",
253
+ "aria-atomic": "true",
254
+ onMouseEnter: v,
255
+ onMouseLeave: y,
256
+ children: e.message
257
+ }
258
+ ) : /* @__PURE__ */ h(
259
+ "div",
260
+ {
261
+ className: w(
262
+ "toast23-item",
263
+ `toast23-item--${e.variant}`,
264
+ !r && "toast23-item--entering",
265
+ e.isExiting && "toast23-item--exiting"
266
+ ),
267
+ role: "alert",
268
+ "aria-live": e.variant === "error" ? "assertive" : "polite",
269
+ "aria-atomic": "true",
270
+ onMouseEnter: v,
271
+ onMouseLeave: y,
272
+ children: [
273
+ /* @__PURE__ */ c("span", { className: w("toast23-icon", `toast23-icon--${e.variant}`), children: /* @__PURE__ */ c(p, {}) }),
274
+ /* @__PURE__ */ h("div", { className: "toast23-content", children: [
275
+ e.title && /* @__PURE__ */ c("div", { className: "toast23-title", children: e.title }),
276
+ /* @__PURE__ */ c(
277
+ "div",
278
+ {
279
+ className: w(
280
+ "toast23-message",
281
+ e.title && "toast23-message--with-title"
282
+ ),
283
+ children: e.message
284
+ }
285
+ )
286
+ ] }),
287
+ e.dismissible && /* @__PURE__ */ c(
288
+ "button",
289
+ {
290
+ type: "button",
291
+ className: "toast23-dismiss",
292
+ onClick: () => s(e.id),
293
+ "aria-label": "Dismiss notification",
294
+ children: /* @__PURE__ */ c(z, {})
295
+ }
296
+ ),
297
+ e.duration > 0 && e.variant !== "loading" && /* @__PURE__ */ c(
298
+ "div",
299
+ {
300
+ className: w(
301
+ "toast23-progress",
302
+ `toast23-progress--${e.variant}`
303
+ ),
304
+ style: {
305
+ width: `${g}%`,
306
+ transition: o
307
+ }
308
+ }
309
+ )
310
+ ]
311
+ }
312
+ );
313
+ }
314
+ );
315
+ S.displayName = "ToastItem";
316
+ const _ = E.memo(
317
+ ({ position: e, toasts: s, maxVisible: t }) => {
318
+ const r = D(A);
319
+ if (!r) return null;
320
+ const l = s.filter((a) => !a.isExiting), u = s.filter((a) => a.isExiting), f = [...l.slice(0, t), ...u];
321
+ if (f.length === 0) return null;
322
+ const d = Math.max(0, l.length - t);
323
+ return /* @__PURE__ */ h(
324
+ "div",
325
+ {
326
+ className: w("toast23-container", `toast23-container--${e}`),
327
+ "aria-label": "Notifications",
328
+ role: "region",
329
+ children: [
330
+ f.map((a) => /* @__PURE__ */ c(
331
+ S,
332
+ {
333
+ toast: a,
334
+ onDismiss: r.dismissToast,
335
+ onRemove: r.removeToast
336
+ },
337
+ a.id
338
+ )),
339
+ d > 0 && /* @__PURE__ */ h("div", { className: "toast23-queue-badge", "aria-live": "polite", children: [
340
+ "+",
341
+ d,
342
+ " more"
343
+ ] })
344
+ ]
345
+ }
346
+ );
347
+ }
348
+ );
349
+ _.displayName = "ToastContainer";
350
+ const Y = [
351
+ "top-right",
352
+ "top-left",
353
+ "top-center",
354
+ "bottom-right",
355
+ "bottom-left",
356
+ "bottom-center"
357
+ ], P = ({
358
+ children: e,
359
+ maxVisible: s = 5,
360
+ position: t = "top-right",
361
+ duration: r = 5e3
362
+ }) => {
363
+ const [l, u] = q(j, []), f = T(
364
+ (i, n) => {
365
+ const v = (n == null ? void 0 : n.id) ?? G(), y = {
366
+ id: v,
367
+ message: i,
368
+ title: n == null ? void 0 : n.title,
369
+ variant: (n == null ? void 0 : n.variant) ?? "default",
370
+ duration: (n == null ? void 0 : n.duration) ?? r,
371
+ position: (n == null ? void 0 : n.position) ?? t,
372
+ dismissible: (n == null ? void 0 : n.dismissible) ?? !0,
373
+ removeDelay: (n == null ? void 0 : n.removeDelay) ?? 1e3,
374
+ isExiting: !1,
375
+ createdAt: Date.now(),
376
+ version: 0,
377
+ isCustom: n == null ? void 0 : n.isCustom
378
+ };
379
+ return n != null && n.id ? u({ type: "UPSERT", toast: y }) : u({ type: "ADD", toast: y }), v;
380
+ },
381
+ [r, t]
382
+ ), d = T(
383
+ (i, n) => {
384
+ u({ type: "UPDATE", id: i, updates: n });
385
+ },
386
+ []
387
+ ), a = T((i) => {
388
+ u({ type: "DISMISS", id: i });
389
+ }, []), g = T((i) => {
390
+ u({ type: "REMOVE", id: i });
391
+ }, []), m = N(
392
+ () => ({
393
+ addToast: f,
394
+ updateToast: d,
395
+ dismissToast: a,
396
+ removeToast: g,
397
+ config: {
398
+ maxVisible: s,
399
+ position: t,
400
+ duration: r
401
+ }
402
+ }),
403
+ [
404
+ f,
405
+ d,
406
+ a,
407
+ g,
408
+ s,
409
+ t,
410
+ r
411
+ ]
412
+ ), o = N(() => {
413
+ const i = {
414
+ "top-right": [],
415
+ "top-left": [],
416
+ "top-center": [],
417
+ "bottom-right": [],
418
+ "bottom-left": [],
419
+ "bottom-center": []
420
+ };
421
+ for (const n of l)
422
+ i[n.position].push(n);
423
+ return i;
424
+ }, [l]);
425
+ return /* @__PURE__ */ h(A.Provider, { value: m, children: [
426
+ e,
427
+ Y.map(
428
+ (i) => o[i].length > 0 ? /* @__PURE__ */ c(
429
+ _,
430
+ {
431
+ position: i,
432
+ toasts: o[i],
433
+ maxVisible: s
434
+ },
435
+ i
436
+ ) : null
437
+ )
438
+ ] });
439
+ };
440
+ P.displayName = "Toast23Provider";
441
+ function Z() {
442
+ const e = D(A);
443
+ if (!e)
444
+ throw new Error(
445
+ "[toast-23] useToast() must be used inside a <Toast23Provider>. Wrap your application root with <Toast23Provider> to fix this."
446
+ );
447
+ return N(() => {
448
+ const s = (t, r) => e.addToast(t, r);
449
+ return s.success = (t, r) => e.addToast(t, { ...r, variant: "success" }), s.error = (t, r) => e.addToast(t, { ...r, variant: "error" }), s.warning = (t, r) => e.addToast(t, { ...r, variant: "warning" }), s.info = (t, r) => e.addToast(t, { ...r, variant: "info" }), s.loading = (t, r) => e.addToast(t, {
450
+ ...r,
451
+ variant: "loading",
452
+ duration: (r == null ? void 0 : r.duration) ?? 0,
453
+ dismissible: (r == null ? void 0 : r.dismissible) ?? !1
454
+ }), s.custom = (t, r) => e.addToast(t, { ...r, variant: "default", isCustom: !0 }), s.dismiss = (t) => e.dismissToast(t), s.remove = (t) => e.removeToast(t), s.promise = async (t, r, l) => {
455
+ const u = e.addToast(r.loading, {
456
+ ...l,
457
+ variant: "loading",
458
+ duration: 0,
459
+ dismissible: !1
460
+ }), f = typeof t == "function" ? t() : t;
461
+ try {
462
+ const d = await f, a = typeof r.success == "function" ? r.success(d) : r.success;
463
+ return e.updateToast(u, {
464
+ message: a,
465
+ variant: "success",
466
+ duration: (l == null ? void 0 : l.duration) ?? e.config.duration,
467
+ dismissible: !0
468
+ }), d;
469
+ } catch (d) {
470
+ const a = typeof r.error == "function" ? r.error(d) : r.error;
471
+ throw e.updateToast(u, {
472
+ message: a,
473
+ variant: "error",
474
+ duration: (l == null ? void 0 : l.duration) ?? e.config.duration,
475
+ dismissible: !0
476
+ }), d;
477
+ }
478
+ }, s;
479
+ }, [
480
+ e.addToast,
481
+ e.updateToast,
482
+ e.dismissToast,
483
+ e.removeToast,
484
+ e.config.duration
485
+ ]);
486
+ }
487
+ let C = null;
488
+ function O() {
489
+ const e = Z();
490
+ return E.useEffect(() => {
491
+ C && (C(e), C = null);
492
+ }, [e]), null;
493
+ }
494
+ function ie(e = {}) {
495
+ const { position: s = "top-right", maxVisible: t = 5, duration: r = 5e3 } = e, l = document.createElement("div");
496
+ l.setAttribute("data-toast23-standalone", ""), l.style.display = "contents", document.body.appendChild(l);
497
+ let u = W(l);
498
+ const f = new Promise((o) => {
499
+ C = o;
500
+ }), d = [];
501
+ let a = null;
502
+ f.then((o) => {
503
+ a = o;
504
+ for (const i of d)
505
+ i.method === "__call__" ? o(...i.args) : o[i.method](...i.args);
506
+ d.length = 0;
507
+ }), u.render(
508
+ E.createElement(
509
+ P,
510
+ { position: s, maxVisible: t, duration: r },
511
+ E.createElement(O)
512
+ )
513
+ );
514
+ const g = (o, ...i) => a ? a[o](...i) : (d.push({ method: o, args: i }), "queued"), m = (o, i) => a ? a(o, i) : (d.push({ method: "__call__", args: [o, i] }), "queued");
515
+ return m.success = (o, i) => g("success", o, i), m.error = (o, i) => g("error", o, i), m.warning = (o, i) => g("warning", o, i), m.info = (o, i) => g("info", o, i), m.loading = (o, i) => g("loading", o, i), m.custom = (o, i) => g("custom", o, i), m.dismiss = (o) => g("dismiss", o), m.remove = (o) => g("remove", o), m.promise = (o, i, n) => a ? a.promise(o, i, n) : f.then((v) => v.promise(o, i, n)), m.destroy = () => {
516
+ u && (u.unmount(), u = null), l.remove(), a = null;
517
+ }, m;
518
+ }
519
+ export {
520
+ P as Toast23Provider,
521
+ ie as createToast23,
522
+ Z as useToast
523
+ };
524
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../src/context.tsx","../src/icons.tsx","../src/utils.ts","../src/toast-item.tsx","../src/toast-container.tsx","../src/provider.tsx","../src/use-toast.ts","../src/standalone.ts"],"sourcesContent":["/**\r\n * toast-23 โ€” React Context & Reducer\r\n */\r\n\r\nimport { createContext } from \"react\";\r\nimport type {\r\n InternalToast,\r\n ToasterAction,\r\n ToasterContextValue,\r\n} from \"./types\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Context โ€” consumed by useToast() and internal components\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const ToasterContext = createContext<ToasterContextValue | null>(null);\r\n\r\n// ---------------------------------------------------------------------------\r\n// Reducer โ€” pure state transitions for the toast queue\r\n// ---------------------------------------------------------------------------\r\n\r\nexport function toasterReducer(\r\n state: InternalToast[],\r\n action: ToasterAction,\r\n): InternalToast[] {\r\n switch (action.type) {\r\n case \"ADD\":\r\n return [...state, action.toast];\r\n\r\n case \"UPSERT\": {\r\n const exists = state.some((t) => t.id === action.toast.id);\r\n if (exists) {\r\n return state.map((t) =>\r\n t.id === action.toast.id\r\n ? {\r\n ...t,\r\n ...action.toast,\r\n version: t.version + 1,\r\n isExiting: false,\r\n }\r\n : t,\r\n );\r\n }\r\n return [...state, action.toast];\r\n }\r\n\r\n case \"UPDATE\":\r\n return state.map((t) =>\r\n t.id === action.id\r\n ? {\r\n ...t,\r\n ...action.updates,\r\n // Bump version so progress bar restarts\r\n version: t.version + 1,\r\n // If the toast was exiting, cancel exit on update\r\n isExiting: false,\r\n }\r\n : t,\r\n );\r\n\r\n case \"DISMISS\":\r\n // Omit id โ†’ dismiss all\r\n if (!action.id) {\r\n return state.map((t) => ({ ...t, isExiting: true }));\r\n }\r\n return state.map((t) =>\r\n t.id === action.id ? { ...t, isExiting: true } : t,\r\n );\r\n\r\n case \"REMOVE\":\r\n // Omit id โ†’ remove all instantly\r\n if (!action.id) return [];\r\n return state.filter((t) => t.id !== action.id);\r\n\r\n default:\r\n return state;\r\n }\r\n}\r\n","/**\r\n * toast-23 โ€” Inline SVG Icons (Filled style)\r\n *\r\n * Solid colored circles/triangles with white inner symbols,\r\n * matching the visual design reference.\r\n */\r\n\r\nimport type { SVGProps, FC } from \"react\";\r\n\r\ntype IconProps = SVGProps<SVGSVGElement>;\r\n\r\n/** Green filled circle with white checkmark */\r\nexport const CheckCircleIcon: FC<IconProps> = (props: IconProps) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n width=\"1.25em\"\r\n height=\"1.25em\"\r\n fill=\"none\"\r\n {...props}\r\n >\r\n <circle cx={12} cy={12} r={10} fill=\"currentColor\" />\r\n <path\r\n d=\"M8 12.5l2.5 2.5 5-5\"\r\n stroke=\"#fff\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n fill=\"none\"\r\n />\r\n </svg>\r\n);\r\n\r\n/** Red filled circle with white exclamation */\r\nexport const XCircleIcon: FC<IconProps> = (props: IconProps) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n width=\"1.25em\"\r\n height=\"1.25em\"\r\n fill=\"none\"\r\n {...props}\r\n >\r\n <circle cx={12} cy={12} r={10} fill=\"currentColor\" />\r\n <line\r\n x1={12}\r\n y1={8}\r\n x2={12}\r\n y2={13}\r\n stroke=\"#fff\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n />\r\n <circle cx={12} cy={16} r={1} fill=\"#fff\" />\r\n </svg>\r\n);\r\n\r\n/** Yellow filled triangle with white exclamation */\r\nexport const AlertTriangleIcon: FC<IconProps> = (props: IconProps) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n width=\"1.25em\"\r\n height=\"1.25em\"\r\n fill=\"none\"\r\n {...props}\r\n >\r\n <path\r\n d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"\r\n fill=\"currentColor\"\r\n />\r\n <line\r\n x1={12}\r\n y1={9.5}\r\n x2={12}\r\n y2={14}\r\n stroke=\"#fff\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n />\r\n <circle cx={12} cy={17} r={1} fill=\"#fff\" />\r\n </svg>\r\n);\r\n\r\n/** Blue filled circle with white \"i\" */\r\nexport const InfoIcon: FC<IconProps> = (props: IconProps) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n width=\"1.25em\"\r\n height=\"1.25em\"\r\n fill=\"none\"\r\n {...props}\r\n >\r\n <circle cx={12} cy={12} r={10} fill=\"currentColor\" />\r\n <line\r\n x1={12}\r\n y1={11}\r\n x2={12}\r\n y2={16}\r\n stroke=\"#fff\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n />\r\n <circle cx={12} cy={8} r={1} fill=\"#fff\" />\r\n </svg>\r\n);\r\n\r\n/** Thin X icon for dismiss button */\r\nexport const XIcon: FC<IconProps> = (props: IconProps) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n width=\"0.875em\"\r\n height=\"0.875em\"\r\n {...props}\r\n >\r\n <line x1={18} y1={6} x2={6} y2={18} />\r\n <line x1={6} y1={6} x2={18} y2={18} />\r\n </svg>\r\n);\r\n\r\n/** CSS-only loading spinner */\r\nexport const SpinnerIcon: FC<IconProps> = (props: IconProps) => (\r\n <svg\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n strokeWidth={2}\r\n strokeLinecap=\"round\"\r\n strokeLinejoin=\"round\"\r\n width=\"1.25em\"\r\n height=\"1.25em\"\r\n className=\"toast23-spinner\"\r\n {...props}\r\n >\r\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\r\n </svg>\r\n);\r\n","/**\r\n * toast-23 โ€” Utility helpers\r\n */\r\n\r\nlet counter = 0;\r\n\r\n/**\r\n * Generate a unique toast id.\r\n * Works in SSR (no dependency on `crypto`).\r\n */\r\nexport function generateId(): string {\r\n return `t23-${++counter}-${Math.random().toString(36).slice(2, 9)}`;\r\n}\r\n\r\n/**\r\n * Deterministic class-name builder (replaces clsx dependency).\r\n */\r\nexport function cx(...args: (string | false | null | undefined | 0)[]): string {\r\n return args.filter(Boolean).join(\" \");\r\n}\r\n","/**\r\n * toast-23 โ€” Individual Toast Component\r\n *\r\n * Manages its own enter / exit CSS transitions and auto-dismiss timer.\r\n * Progress bar is JS-driven so it can reverse (refill) on hover.\r\n */\r\n\r\n\"use client\";\r\n\r\nimport * as React from \"react\";\r\nimport { useCallback, useEffect, useRef, useState } from \"react\";\r\nimport type { InternalToast } from \"./types\";\r\nimport {\r\n CheckCircleIcon,\r\n XCircleIcon,\r\n AlertTriangleIcon,\r\n InfoIcon,\r\n SpinnerIcon,\r\n XIcon,\r\n} from \"./icons\";\r\nimport { cx } from \"./utils\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Icon map\r\n// ---------------------------------------------------------------------------\r\n\r\nconst variantIcon: Record<string, React.FC<React.SVGProps<SVGSVGElement>>> = {\r\n success: CheckCircleIcon,\r\n error: XCircleIcon,\r\n warning: AlertTriangleIcon,\r\n info: InfoIcon,\r\n default: InfoIcon,\r\n loading: SpinnerIcon,\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Component\r\n// ---------------------------------------------------------------------------\r\n\r\ninterface ToastItemProps {\r\n toast: InternalToast;\r\n onDismiss: (id: string) => void;\r\n onRemove: (id: string) => void;\r\n}\r\n\r\nconst EXIT_DURATION = 300; // ms โ€” must match CSS transition duration\r\nconst MIN_REFILL_DURATION = 200; // ms โ€” minimum refill time so very short hovers aren't instant\r\n\r\nexport const ToastItem: React.FC<ToastItemProps> = React.memo(\r\n ({ toast, onDismiss, onRemove }) => {\r\n // ----- animation state -----\r\n const [hasEntered, setHasEntered] = useState(false);\r\n\r\n // Trigger enter transition on next frame\r\n useEffect(() => {\r\n const raf = requestAnimationFrame(() => setHasEntered(true));\r\n return () => cancelAnimationFrame(raf);\r\n }, []);\r\n\r\n // When the provider marks the toast as exiting, wait for the CSS\r\n // transition to finish then actually remove it from state.\r\n useEffect(() => {\r\n if (!toast.isExiting) return;\r\n const delay = toast.removeDelay ?? EXIT_DURATION;\r\n const timer = setTimeout(() => onRemove(toast.id), delay);\r\n return () => clearTimeout(timer);\r\n }, [toast.isExiting, toast.id, toast.removeDelay, onRemove]);\r\n\r\n // ----- auto-dismiss timer with hover-pause -----\r\n const [isPaused, setIsPaused] = useState(false);\r\n const remainingRef = useRef(toast.duration);\r\n const startRef = useRef(0);\r\n\r\n // ----- JS-driven progress bar -----\r\n // progress: 100 = full, 0 = empty\r\n const [progress, setProgress] = useState(100);\r\n // transition duration for the progress bar\r\n const [progressTransition, setProgressTransition] = useState(\"none\");\r\n const rafRef = useRef<number>(0);\r\n\r\n // Reset remaining time when version changes (e.g. promise resolved)\r\n useEffect(() => {\r\n remainingRef.current = toast.duration;\r\n setProgress(100);\r\n setProgressTransition(\"none\");\r\n }, [toast.version, toast.duration]);\r\n\r\n useEffect(() => {\r\n // Don't auto-dismiss: persistent, loading, still entering, or already exiting\r\n if (\r\n toast.duration <= 0 ||\r\n toast.variant === \"loading\" ||\r\n !hasEntered ||\r\n toast.isExiting\r\n )\r\n return;\r\n\r\n if (isPaused) {\r\n // How long the bar was shrinking before hover\r\n const elapsed = Date.now() - startRef.current;\r\n // Snapshot remaining time\r\n remainingRef.current = Math.max(0, remainingRef.current - elapsed);\r\n\r\n // Reverse at the same speed it was shrinking (proportional duration)\r\n const refillDuration = Math.max(MIN_REFILL_DURATION, elapsed);\r\n setProgressTransition(`width ${refillDuration}ms ease-out`);\r\n setProgress(100);\r\n return;\r\n }\r\n\r\n // Start shrinking\r\n startRef.current = Date.now();\r\n const remaining = remainingRef.current;\r\n\r\n // Set transition to match remaining time and shrink to 0\r\n // Use rAF to ensure the refill transition has settled before starting shrink\r\n rafRef.current = requestAnimationFrame(() => {\r\n setProgressTransition(`width ${remaining}ms linear`);\r\n setProgress(0);\r\n });\r\n\r\n const timer = setTimeout(() => {\r\n onDismiss(toast.id);\r\n }, remaining);\r\n\r\n return () => {\r\n clearTimeout(timer);\r\n cancelAnimationFrame(rafRef.current);\r\n };\r\n }, [\r\n isPaused,\r\n hasEntered,\r\n toast.isExiting,\r\n toast.duration,\r\n toast.variant,\r\n toast.id,\r\n toast.version,\r\n onDismiss,\r\n ]);\r\n\r\n // ----- handlers -----\r\n const handleMouseEnter = useCallback(() => setIsPaused(true), []);\r\n const handleMouseLeave = useCallback(() => setIsPaused(false), []);\r\n\r\n // ----- render -----\r\n const Icon = variantIcon[toast.variant] ?? InfoIcon;\r\n\r\n // Custom toast โ€” render raw content with no default chrome\r\n if (toast.isCustom) {\r\n return (\r\n <div\r\n className={cx(\r\n \"toast23-item toast23-item--custom\",\r\n !hasEntered && \"toast23-item--entering\",\r\n toast.isExiting && \"toast23-item--exiting\",\r\n )}\r\n role=\"alert\"\r\n aria-live=\"polite\"\r\n aria-atomic=\"true\"\r\n onMouseEnter={handleMouseEnter}\r\n onMouseLeave={handleMouseLeave}\r\n >\r\n {toast.message}\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div\r\n className={cx(\r\n \"toast23-item\",\r\n `toast23-item--${toast.variant}`,\r\n !hasEntered && \"toast23-item--entering\",\r\n toast.isExiting && \"toast23-item--exiting\",\r\n )}\r\n role=\"alert\"\r\n aria-live={toast.variant === \"error\" ? \"assertive\" : \"polite\"}\r\n aria-atomic=\"true\"\r\n onMouseEnter={handleMouseEnter}\r\n onMouseLeave={handleMouseLeave}\r\n >\r\n {/* Icon */}\r\n <span className={cx(\"toast23-icon\", `toast23-icon--${toast.variant}`)}>\r\n <Icon />\r\n </span>\r\n\r\n {/* Content */}\r\n <div className=\"toast23-content\">\r\n {toast.title && <div className=\"toast23-title\">{toast.title}</div>}\r\n <div\r\n className={cx(\r\n \"toast23-message\",\r\n toast.title && \"toast23-message--with-title\",\r\n )}\r\n >\r\n {toast.message}\r\n </div>\r\n </div>\r\n\r\n {/* Dismiss button */}\r\n {toast.dismissible && (\r\n <button\r\n type=\"button\"\r\n className=\"toast23-dismiss\"\r\n onClick={() => onDismiss(toast.id)}\r\n aria-label=\"Dismiss notification\"\r\n >\r\n <XIcon />\r\n </button>\r\n )}\r\n\r\n {/* Progress bar โ€” JS-driven width for hover reversal */}\r\n {toast.duration > 0 && toast.variant !== \"loading\" && (\r\n <div\r\n className={cx(\r\n \"toast23-progress\",\r\n `toast23-progress--${toast.variant}`,\r\n )}\r\n style={{\r\n width: `${progress}%`,\r\n transition: progressTransition,\r\n }}\r\n />\r\n )}\r\n </div>\r\n );\r\n },\r\n);\r\n\r\nToastItem.displayName = \"ToastItem\";\r\n","/**\r\n * toast-23 โ€” Positioned Toast Container\r\n *\r\n * Renders a group of toasts for a given screen position.\r\n * Handles queue logic: only `maxVisible` non-exiting toasts are shown,\r\n * plus any currently animating-out toasts.\r\n */\r\n\r\n\"use client\";\r\n\r\nimport * as React from \"react\";\r\nimport { useContext } from \"react\";\r\nimport type { InternalToast, ToastPosition } from \"./types\";\r\nimport { ToasterContext } from \"./context\";\r\nimport { ToastItem } from \"./toast-item\";\r\nimport { cx } from \"./utils\";\r\n\r\ninterface ToastContainerProps {\r\n position: ToastPosition;\r\n toasts: InternalToast[];\r\n maxVisible: number;\r\n}\r\n\r\nexport const ToastContainer: React.FC<ToastContainerProps> = React.memo(\r\n ({ position, toasts, maxVisible }: ToastContainerProps) => {\r\n const ctx = useContext(ToasterContext);\r\n if (!ctx) return null;\r\n\r\n // Separate active vs. exiting toasts\r\n const active = toasts.filter((t) => !t.isExiting);\r\n const exiting = toasts.filter((t) => t.isExiting);\r\n\r\n // Only show up to maxVisible active toasts, plus all currently exiting\r\n const visible = [...active.slice(0, maxVisible), ...exiting];\r\n\r\n if (visible.length === 0) return null;\r\n\r\n // Queue count for optional badge\r\n const queuedCount = Math.max(0, active.length - maxVisible);\r\n\r\n return (\r\n <div\r\n className={cx(\"toast23-container\", `toast23-container--${position}`)}\r\n aria-label=\"Notifications\"\r\n role=\"region\"\r\n >\r\n {visible.map((toast) => (\r\n <ToastItem\r\n key={toast.id}\r\n toast={toast}\r\n onDismiss={ctx.dismissToast}\r\n onRemove={ctx.removeToast}\r\n />\r\n ))}\r\n {queuedCount > 0 && (\r\n <div className=\"toast23-queue-badge\" aria-live=\"polite\">\r\n +{queuedCount} more\r\n </div>\r\n )}\r\n </div>\r\n );\r\n },\r\n);\r\n\r\nToastContainer.displayName = \"ToastContainer\";\r\n","/**\r\n * toast-23 โ€” Toast23Provider\r\n *\r\n * Wrap your application with this provider to enable toast notifications.\r\n *\r\n * ```tsx\r\n * <Toast23Provider position=\"top-right\" maxVisible={5}>\r\n * <App />\r\n * </Toast23Provider>\r\n * ```\r\n */\r\n\r\n\"use client\";\r\n\r\nimport { useCallback, useMemo, useReducer } from \"react\";\r\nimport type {\r\n InternalToast,\r\n Toast23ProviderProps,\r\n ToasterContextValue,\r\n ToastOptions,\r\n ToastPosition,\r\n} from \"./types\";\r\nimport type { ReactNode } from \"react\";\r\nimport { ToasterContext, toasterReducer } from \"./context\";\r\nimport { ToastContainer } from \"./toast-container\";\r\nimport { generateId } from \"./utils\";\r\n\r\nconst ALL_POSITIONS: ToastPosition[] = [\r\n \"top-right\",\r\n \"top-left\",\r\n \"top-center\",\r\n \"bottom-right\",\r\n \"bottom-left\",\r\n \"bottom-center\",\r\n];\r\n\r\nexport const Toast23Provider: React.FC<Toast23ProviderProps> = ({\r\n children,\r\n maxVisible = 5,\r\n position: defaultPosition = \"top-right\" as ToastPosition,\r\n duration: defaultDuration = 5000,\r\n}) => {\r\n const [toasts, dispatch] = useReducer(toasterReducer, []);\r\n\r\n // ------ stable callbacks (dispatch is always stable from useReducer) ------\r\n\r\n const addToast = useCallback(\r\n (message: string | ReactNode, options?: ToastOptions & { variant?: any; isCustom?: boolean }): string => {\r\n const id = options?.id ?? generateId();\r\n const toast: InternalToast = {\r\n id,\r\n message,\r\n title: options?.title,\r\n variant: options?.variant ?? \"default\",\r\n duration: options?.duration ?? defaultDuration,\r\n position: options?.position ?? defaultPosition,\r\n dismissible: options?.dismissible ?? true,\r\n removeDelay: options?.removeDelay ?? 1000,\r\n isExiting: false,\r\n createdAt: Date.now(),\r\n version: 0,\r\n isCustom: options?.isCustom,\r\n };\r\n // If an id was provided, upsert (update-or-insert)\r\n if (options?.id) {\r\n dispatch({ type: \"UPSERT\", toast });\r\n } else {\r\n dispatch({ type: \"ADD\", toast });\r\n }\r\n return id;\r\n },\r\n [defaultDuration, defaultPosition],\r\n );\r\n\r\n const updateToast = useCallback(\r\n (\r\n id: string,\r\n updates: Partial<\r\n Pick<\r\n InternalToast,\r\n \"message\" | \"title\" | \"variant\" | \"duration\" | \"dismissible\"\r\n >\r\n >,\r\n ) => {\r\n dispatch({ type: \"UPDATE\", id, updates });\r\n },\r\n [],\r\n );\r\n\r\n const dismissToast = useCallback((id?: string) => {\r\n dispatch({ type: \"DISMISS\", id });\r\n }, []);\r\n\r\n const removeToast = useCallback((id?: string) => {\r\n dispatch({ type: \"REMOVE\", id });\r\n }, []);\r\n\r\n // ------ context value (stable as long as callbacks are stable) ------\r\n\r\n const contextValue: ToasterContextValue = useMemo(\r\n () => ({\r\n addToast,\r\n updateToast,\r\n dismissToast,\r\n removeToast,\r\n config: {\r\n maxVisible,\r\n position: defaultPosition,\r\n duration: defaultDuration,\r\n },\r\n }),\r\n [\r\n addToast,\r\n updateToast,\r\n dismissToast,\r\n removeToast,\r\n maxVisible,\r\n defaultPosition,\r\n defaultDuration,\r\n ],\r\n );\r\n\r\n // ------ group toasts by position ------\r\n\r\n const groupedToasts = useMemo(() => {\r\n const groups: Record<ToastPosition, InternalToast[]> = {\r\n \"top-right\": [],\r\n \"top-left\": [],\r\n \"top-center\": [],\r\n \"bottom-right\": [],\r\n \"bottom-left\": [],\r\n \"bottom-center\": [],\r\n };\r\n for (const t of toasts) {\r\n groups[t.position].push(t);\r\n }\r\n return groups;\r\n }, [toasts]);\r\n\r\n return (\r\n <ToasterContext.Provider value={contextValue}>\r\n {children}\r\n\r\n {/* Render one container per position that has toasts */}\r\n {ALL_POSITIONS.map((pos) =>\r\n groupedToasts[pos].length > 0 ? (\r\n <ToastContainer\r\n key={pos}\r\n position={pos}\r\n toasts={groupedToasts[pos]}\r\n maxVisible={maxVisible}\r\n />\r\n ) : null,\r\n )}\r\n </ToasterContext.Provider>\r\n );\r\n};\r\n\r\nToast23Provider.displayName = \"Toast23Provider\";\r\n","/**\r\n * toast-23 โ€” useToast Hook\r\n *\r\n * Returns a callable `ToastApi` object:\r\n *\r\n * ```ts\r\n * const toast = useToast();\r\n *\r\n * toast(\"Hello!\"); // default variant\r\n * toast.success(\"Done!\"); // success variant\r\n * toast.error(\"Oops\"); // error variant\r\n * toast.promise(fetchData(), { ... }); // promise tracking\r\n * toast.dismiss(id); // manual dismiss\r\n * ```\r\n */\r\n\r\n\"use client\";\r\n\r\nimport { useContext, useMemo } from \"react\";\r\nimport { ToasterContext } from \"./context\";\r\nimport type { ToastApi, ToastOptions, PromiseOptions } from \"./types\";\r\nimport type { ReactNode } from \"react\";\r\n\r\nexport function useToast(): ToastApi {\r\n const ctx = useContext(ToasterContext);\r\n\r\n if (!ctx) {\r\n throw new Error(\r\n \"[toast-23] useToast() must be used inside a <Toast23Provider>. \" +\r\n \"Wrap your application root with <Toast23Provider> to fix this.\",\r\n );\r\n }\r\n\r\n return useMemo(() => {\r\n // Base callable โ€” toast(\"message\", opts?)\r\n const toast = ((message: string | ReactNode, options?: ToastOptions) =>\r\n ctx.addToast(message, options)) as ToastApi;\r\n\r\n // Variant shortcuts\r\n toast.success = (msg, opts) =>\r\n ctx.addToast(msg, { ...opts, variant: \"success\" });\r\n\r\n toast.error = (msg, opts) =>\r\n ctx.addToast(msg, { ...opts, variant: \"error\" });\r\n\r\n toast.warning = (msg, opts) =>\r\n ctx.addToast(msg, { ...opts, variant: \"warning\" });\r\n\r\n toast.info = (msg, opts) => ctx.addToast(msg, { ...opts, variant: \"info\" });\r\n\r\n // Loading shortcut\r\n toast.loading = (msg, opts) =>\r\n ctx.addToast(msg, {\r\n ...opts,\r\n variant: \"loading\" as any,\r\n duration: opts?.duration ?? 0,\r\n dismissible: opts?.dismissible ?? false,\r\n });\r\n\r\n // Custom toast โ€” no default styles\r\n toast.custom = (content, opts) =>\r\n ctx.addToast(content, { ...opts, variant: \"default\", isCustom: true });\r\n\r\n // Dismiss (with optional id โ€” omit to dismiss all)\r\n toast.dismiss = (id?: string) => ctx.dismissToast(id);\r\n\r\n // Remove instantly (with optional id โ€” omit to remove all)\r\n toast.remove = (id?: string) => ctx.removeToast(id);\r\n\r\n // Promise tracking (accepts Promise or () => Promise, optional 3rd arg for toast options)\r\n toast.promise = async <T>(\r\n promiseOrFn: Promise<T> | (() => Promise<T>),\r\n opts: PromiseOptions<T>,\r\n toastOpts?: ToastOptions,\r\n ): Promise<T> => {\r\n const id = ctx.addToast(opts.loading, {\r\n ...toastOpts,\r\n variant: \"loading\" as any,\r\n duration: 0,\r\n dismissible: false,\r\n } as ToastOptions);\r\n\r\n const promise =\r\n typeof promiseOrFn === \"function\" ? promiseOrFn() : promiseOrFn;\r\n\r\n try {\r\n const result = await promise;\r\n const msg =\r\n typeof opts.success === \"function\"\r\n ? opts.success(result)\r\n : opts.success;\r\n ctx.updateToast(id, {\r\n message: msg,\r\n variant: \"success\",\r\n duration: toastOpts?.duration ?? ctx.config.duration,\r\n dismissible: true,\r\n });\r\n return result;\r\n } catch (error) {\r\n const msg =\r\n typeof opts.error === \"function\" ? opts.error(error) : opts.error;\r\n ctx.updateToast(id, {\r\n message: msg,\r\n variant: \"error\",\r\n duration: toastOpts?.duration ?? ctx.config.duration,\r\n dismissible: true,\r\n });\r\n throw error;\r\n }\r\n };\r\n\r\n return toast;\r\n }, [\r\n ctx.addToast,\r\n ctx.updateToast,\r\n ctx.dismissToast,\r\n ctx.removeToast,\r\n ctx.config.duration,\r\n ]);\r\n}\r\n","/**\r\n * toast-23 โ€” Standalone / Imperative API\r\n *\r\n * Use this when you need toast notifications outside of React (Angular, Vue,\r\n * Svelte, vanilla JS, etc.). It internally bootstraps a minimal React root.\r\n *\r\n * ```ts\r\n * import { createToast23 } from \"toast-23\";\r\n *\r\n * const toast = createToast23({ position: \"top-right\" });\r\n *\r\n * toast.success(\"Saved!\");\r\n * toast.error(\"Something went wrong\");\r\n * toast.dismiss(id);\r\n *\r\n * // Cleanup when done (e.g. on app destroy)\r\n * toast.destroy();\r\n * ```\r\n */\r\n\r\nimport * as React from \"react\";\r\nimport { createRoot, type Root } from \"react-dom/client\";\r\nimport { Toast23Provider } from \"./provider\";\r\nimport { useToast } from \"./use-toast\";\r\nimport type {\r\n ToastPosition,\r\n ToastOptions,\r\n PromiseOptions,\r\n ToastApi,\r\n} from \"./types\";\r\nimport type { ReactNode } from \"react\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// Types\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface StandaloneOptions {\r\n /** Where on screen toasts appear. @default \"top-right\" */\r\n position?: ToastPosition;\r\n /** Max simultaneous toasts. @default 5 */\r\n maxVisible?: number;\r\n /** Default auto-dismiss duration in ms. @default 5000 */\r\n duration?: number;\r\n}\r\n\r\nexport interface StandaloneToastApi {\r\n /** Show a default toast. Returns the toast id. */\r\n (message: string | ReactNode, options?: ToastOptions): string;\r\n /** Show a success toast. */\r\n success: (message: string, options?: Omit<ToastOptions, \"variant\">) => string;\r\n /** Show an error toast. */\r\n error: (message: string, options?: Omit<ToastOptions, \"variant\">) => string;\r\n /** Show a warning toast. */\r\n warning: (message: string, options?: Omit<ToastOptions, \"variant\">) => string;\r\n /** Show an info toast. */\r\n info: (message: string, options?: Omit<ToastOptions, \"variant\">) => string;\r\n /** Show a loading toast. Returns the toast id for later update. */\r\n loading: (message: string, options?: Omit<ToastOptions, \"variant\">) => string;\r\n /** Show a custom toast with JSX content and no default styles. */\r\n custom: (\r\n content: ReactNode,\r\n options?: Omit<ToastOptions, \"variant\">,\r\n ) => string;\r\n /** Track an async operation with loading โ†’ success / error transitions. */\r\n promise: <T>(\r\n promise: Promise<T> | (() => Promise<T>),\r\n options: PromiseOptions<T>,\r\n toastOptions?: ToastOptions,\r\n ) => Promise<T>;\r\n /** Manually dismiss a toast by id. Omit id to dismiss all. */\r\n dismiss: (id?: string) => void;\r\n /** Instantly remove a toast from DOM (no exit animation). Omit id to remove all. */\r\n remove: (id?: string) => void;\r\n /** Unmount the React root and remove the container from the DOM. */\r\n destroy: () => void;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Bridge component โ€” captures the useToast API and passes it out\r\n// ---------------------------------------------------------------------------\r\n\r\nlet _resolveApi: ((api: ToastApi) => void) | null = null;\r\n\r\nfunction Bridge() {\r\n const api = useToast();\r\n\r\n // Resolve the promise on first render; update the ref on every render\r\n // so the external caller always has the latest stable API reference.\r\n React.useEffect(() => {\r\n if (_resolveApi) {\r\n _resolveApi(api);\r\n _resolveApi = null;\r\n }\r\n }, [api]);\r\n\r\n // Also store on ref for synchronous access after first mount\r\n\r\n return null;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Factory\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Create a standalone toast API that works outside of React.\r\n *\r\n * Internally mounts a tiny React tree (provider + bridge) into a hidden\r\n * container. Returns a callable toast object with `.success()`, `.error()`, etc.\r\n *\r\n * Call `.destroy()` when your application unmounts to clean up.\r\n */\r\nexport function createToast23(\r\n options: StandaloneOptions = {},\r\n): StandaloneToastApi {\r\n const { position = \"top-right\", maxVisible = 5, duration = 5000 } = options;\r\n\r\n // Create a hidden container\r\n const container = document.createElement(\"div\");\r\n container.setAttribute(\"data-toast23-standalone\", \"\");\r\n container.style.display = \"contents\"; // invisible wrapper\r\n document.body.appendChild(container);\r\n\r\n // We need to wait for React to render before the API is available.\r\n // Use a promise + queue approach so calls before mount are buffered.\r\n let root: Root | null = createRoot(container);\r\n\r\n const apiReady = new Promise<ToastApi>((resolve) => {\r\n _resolveApi = resolve;\r\n });\r\n\r\n // Queue for calls made before React has mounted\r\n type QueuedCall = { method: string; args: unknown[] };\r\n const queue: QueuedCall[] = [];\r\n let resolvedApi: ToastApi | null = null;\r\n\r\n // Flush queued calls once the API is ready\r\n apiReady.then((api) => {\r\n resolvedApi = api;\r\n for (const call of queue) {\r\n if (call.method === \"__call__\") {\r\n (api as any)(...call.args);\r\n } else {\r\n (api as any)[call.method](...call.args);\r\n }\r\n }\r\n queue.length = 0;\r\n });\r\n\r\n // Mount React tree\r\n root.render(\r\n React.createElement(\r\n Toast23Provider,\r\n { position, maxVisible, duration } as any,\r\n React.createElement(Bridge),\r\n ),\r\n );\r\n\r\n // Build the proxy API\r\n const proxyCall = (method: string, ...args: unknown[]): any => {\r\n if (resolvedApi) {\r\n return (resolvedApi as any)[method](...args);\r\n }\r\n queue.push({ method, args });\r\n return \"queued\";\r\n };\r\n\r\n const toast = ((message: string | ReactNode, opts?: ToastOptions) => {\r\n if (resolvedApi) return resolvedApi(message, opts);\r\n queue.push({ method: \"__call__\", args: [message, opts] });\r\n return \"queued\";\r\n }) as StandaloneToastApi;\r\n\r\n toast.success = (msg, opts) => proxyCall(\"success\", msg, opts);\r\n toast.error = (msg, opts) => proxyCall(\"error\", msg, opts);\r\n toast.warning = (msg, opts) => proxyCall(\"warning\", msg, opts);\r\n toast.info = (msg, opts) => proxyCall(\"info\", msg, opts);\r\n toast.loading = (msg, opts) => proxyCall(\"loading\", msg, opts);\r\n toast.custom = (content, opts) => proxyCall(\"custom\", content, opts);\r\n toast.dismiss = (id?) => proxyCall(\"dismiss\", id);\r\n toast.remove = (id?) => proxyCall(\"remove\", id);\r\n\r\n toast.promise = (promise, opts, toastOpts?) => {\r\n if (resolvedApi) return resolvedApi.promise(promise, opts, toastOpts);\r\n // For promises, we need to wait for the API\r\n return apiReady.then((api) => api.promise(promise, opts, toastOpts));\r\n };\r\n\r\n toast.destroy = () => {\r\n if (root) {\r\n root.unmount();\r\n root = null;\r\n }\r\n container.remove();\r\n resolvedApi = null;\r\n };\r\n\r\n return toast;\r\n}\r\n"],"names":["ToasterContext","createContext","toasterReducer","state","action","t","CheckCircleIcon","props","jsxs","jsx","XCircleIcon","AlertTriangleIcon","InfoIcon","XIcon","SpinnerIcon","counter","generateId","cx","args","variantIcon","EXIT_DURATION","MIN_REFILL_DURATION","ToastItem","React","toast","onDismiss","onRemove","hasEntered","setHasEntered","useState","useEffect","raf","delay","timer","isPaused","setIsPaused","remainingRef","useRef","startRef","progress","setProgress","progressTransition","setProgressTransition","rafRef","elapsed","refillDuration","remaining","handleMouseEnter","useCallback","handleMouseLeave","Icon","ToastContainer","position","toasts","maxVisible","ctx","useContext","active","exiting","visible","queuedCount","ALL_POSITIONS","Toast23Provider","children","defaultPosition","defaultDuration","dispatch","useReducer","addToast","message","options","id","updateToast","updates","dismissToast","removeToast","contextValue","useMemo","groupedToasts","groups","pos","useToast","msg","opts","content","promiseOrFn","toastOpts","promise","result","error","_resolveApi","Bridge","api","createToast23","duration","container","root","createRoot","apiReady","resolve","queue","resolvedApi","call","proxyCall","method"],"mappings":";;;;AAeO,MAAMA,IAAiBC,EAA0C,IAAI;AAMrE,SAASC,EACdC,GACAC,GACiB;AACjB,UAAQA,EAAO,MAAA;AAAA,IACb,KAAK;AACH,aAAO,CAAC,GAAGD,GAAOC,EAAO,KAAK;AAAA,IAEhC,KAAK;AAEH,aADeD,EAAM,KAAK,CAACE,MAAMA,EAAE,OAAOD,EAAO,MAAM,EAAE,IAEhDD,EAAM;AAAA,QAAI,CAACE,MAChBA,EAAE,OAAOD,EAAO,MAAM,KAClB;AAAA,UACE,GAAGC;AAAA,UACH,GAAGD,EAAO;AAAA,UACV,SAASC,EAAE,UAAU;AAAA,UACrB,WAAW;AAAA,QAAA,IAEbA;AAAA,MAAA,IAGD,CAAC,GAAGF,GAAOC,EAAO,KAAK;AAAA,IAGhC,KAAK;AACH,aAAOD,EAAM;AAAA,QAAI,CAAC,MAChB,EAAE,OAAOC,EAAO,KACZ;AAAA,UACE,GAAG;AAAA,UACH,GAAGA,EAAO;AAAA;AAAA,UAEV,SAAS,EAAE,UAAU;AAAA;AAAA,UAErB,WAAW;AAAA,QAAA,IAEb;AAAA,MAAA;AAAA,IAGR,KAAK;AAEH,aAAKA,EAAO,KAGLD,EAAM;AAAA,QAAI,CAAC,MAChB,EAAE,OAAOC,EAAO,KAAK,EAAE,GAAG,GAAG,WAAW,OAAS;AAAA,MAAA,IAH1CD,EAAM,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,WAAW,GAAA,EAAO;AAAA,IAMvD,KAAK;AAEH,aAAKC,EAAO,KACLD,EAAM,OAAO,CAAC,MAAM,EAAE,OAAOC,EAAO,EAAE,IADtB,CAAA;AAAA,IAGzB;AACE,aAAOD;AAAA,EAAA;AAEb;ACjEO,MAAMG,IAAiC,CAACC,MAC7C,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,OAAM;AAAA,IACN,SAAQ;AAAA,IACR,OAAM;AAAA,IACN,QAAO;AAAA,IACP,MAAK;AAAA,IACJ,GAAGD;AAAA,IAEJ,UAAA;AAAA,MAAA,gBAAAE,EAAC,UAAA,EAAO,IAAI,IAAI,IAAI,IAAI,GAAG,IAAI,MAAK,eAAA,CAAe;AAAA,MACnD,gBAAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,GAAE;AAAA,UACF,QAAO;AAAA,UACP,aAAa;AAAA,UACb,eAAc;AAAA,UACd,gBAAe;AAAA,UACf,MAAK;AAAA,QAAA;AAAA,MAAA;AAAA,IACP;AAAA,EAAA;AACF,GAIWC,IAA6B,CAACH,MACzC,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,OAAM;AAAA,IACN,SAAQ;AAAA,IACR,OAAM;AAAA,IACN,QAAO;AAAA,IACP,MAAK;AAAA,IACJ,GAAGD;AAAA,IAEJ,UAAA;AAAA,MAAA,gBAAAE,EAAC,UAAA,EAAO,IAAI,IAAI,IAAI,IAAI,GAAG,IAAI,MAAK,eAAA,CAAe;AAAA,MACnD,gBAAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,QAAO;AAAA,UACP,aAAa;AAAA,UACb,eAAc;AAAA,QAAA;AAAA,MAAA;AAAA,MAEhB,gBAAAA,EAAC,YAAO,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG,MAAK,OAAA,CAAO;AAAA,IAAA;AAAA,EAAA;AAC5C,GAIWE,IAAmC,CAACJ,MAC/C,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,OAAM;AAAA,IACN,SAAQ;AAAA,IACR,OAAM;AAAA,IACN,QAAO;AAAA,IACP,MAAK;AAAA,IACJ,GAAGD;AAAA,IAEJ,UAAA;AAAA,MAAA,gBAAAE;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,GAAE;AAAA,UACF,MAAK;AAAA,QAAA;AAAA,MAAA;AAAA,MAEP,gBAAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,QAAO;AAAA,UACP,aAAa;AAAA,UACb,eAAc;AAAA,QAAA;AAAA,MAAA;AAAA,MAEhB,gBAAAA,EAAC,YAAO,IAAI,IAAI,IAAI,IAAI,GAAG,GAAG,MAAK,OAAA,CAAO;AAAA,IAAA;AAAA,EAAA;AAC5C,GAIWG,IAA0B,CAACL,MACtC,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,OAAM;AAAA,IACN,SAAQ;AAAA,IACR,OAAM;AAAA,IACN,QAAO;AAAA,IACP,MAAK;AAAA,IACJ,GAAGD;AAAA,IAEJ,UAAA;AAAA,MAAA,gBAAAE,EAAC,UAAA,EAAO,IAAI,IAAI,IAAI,IAAI,GAAG,IAAI,MAAK,eAAA,CAAe;AAAA,MACnD,gBAAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,QAAO;AAAA,UACP,aAAa;AAAA,UACb,eAAc;AAAA,QAAA;AAAA,MAAA;AAAA,MAEhB,gBAAAA,EAAC,YAAO,IAAI,IAAI,IAAI,GAAG,GAAG,GAAG,MAAK,OAAA,CAAO;AAAA,IAAA;AAAA,EAAA;AAC3C,GAIWI,IAAuB,CAACN,MACnC,gBAAAC;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,OAAM;AAAA,IACN,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,QAAO;AAAA,IACP,aAAa;AAAA,IACb,eAAc;AAAA,IACd,gBAAe;AAAA,IACf,OAAM;AAAA,IACN,QAAO;AAAA,IACN,GAAGD;AAAA,IAEJ,UAAA;AAAA,MAAA,gBAAAE,EAAC,QAAA,EAAK,IAAI,IAAI,IAAI,GAAG,IAAI,GAAG,IAAI,GAAA,CAAI;AAAA,MACpC,gBAAAA,EAAC,UAAK,IAAI,GAAG,IAAI,GAAG,IAAI,IAAI,IAAI,GAAA,CAAI;AAAA,IAAA;AAAA,EAAA;AACtC,GAIWK,IAA6B,CAACP,MACzC,gBAAAE;AAAA,EAAC;AAAA,EAAA;AAAA,IACC,OAAM;AAAA,IACN,SAAQ;AAAA,IACR,MAAK;AAAA,IACL,QAAO;AAAA,IACP,aAAa;AAAA,IACb,eAAc;AAAA,IACd,gBAAe;AAAA,IACf,OAAM;AAAA,IACN,QAAO;AAAA,IACP,WAAU;AAAA,IACT,GAAGF;AAAA,IAEJ,UAAA,gBAAAE,EAAC,QAAA,EAAK,GAAE,8BAAA,CAA8B;AAAA,EAAA;AACxC;AC3IF,IAAIM,IAAU;AAMP,SAASC,IAAqB;AACnC,SAAO,OAAO,EAAED,CAAO,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AACnE;AAKO,SAASE,KAAMC,GAAyD;AAC7E,SAAOA,EAAK,OAAO,OAAO,EAAE,KAAK,GAAG;AACtC;ACOA,MAAMC,IAAuE;AAAA,EAC3E,SAASb;AAAA,EACT,OAAOI;AAAA,EACP,SAASC;AAAA,EACT,MAAMC;AAAA,EACN,SAASA;AAAA,EACT,SAASE;AACX,GAYMM,IAAgB,KAChBC,IAAsB,KAEfC,IAAsCC,EAAM;AAAA,EACvD,CAAC,EAAE,OAAAC,GAAO,WAAAC,GAAW,UAAAC,QAAe;AAElC,UAAM,CAACC,GAAYC,CAAa,IAAIC,EAAS,EAAK;AAGlD,IAAAC,EAAU,MAAM;AACd,YAAMC,IAAM,sBAAsB,MAAMH,EAAc,EAAI,CAAC;AAC3D,aAAO,MAAM,qBAAqBG,CAAG;AAAA,IACvC,GAAG,CAAA,CAAE,GAILD,EAAU,MAAM;AACd,UAAI,CAACN,EAAM,UAAW;AACtB,YAAMQ,IAAQR,EAAM,eAAeJ,GAC7Ba,IAAQ,WAAW,MAAMP,EAASF,EAAM,EAAE,GAAGQ,CAAK;AACxD,aAAO,MAAM,aAAaC,CAAK;AAAA,IACjC,GAAG,CAACT,EAAM,WAAWA,EAAM,IAAIA,EAAM,aAAaE,CAAQ,CAAC;AAG3D,UAAM,CAACQ,GAAUC,CAAW,IAAIN,EAAS,EAAK,GACxCO,IAAeC,EAAOb,EAAM,QAAQ,GACpCc,IAAWD,EAAO,CAAC,GAInB,CAACE,GAAUC,CAAW,IAAIX,EAAS,GAAG,GAEtC,CAACY,GAAoBC,CAAqB,IAAIb,EAAS,MAAM,GAC7Dc,IAASN,EAAe,CAAC;AAG/B,IAAAP,EAAU,MAAM;AACd,MAAAM,EAAa,UAAUZ,EAAM,UAC7BgB,EAAY,GAAG,GACfE,EAAsB,MAAM;AAAA,IAC9B,GAAG,CAAClB,EAAM,SAASA,EAAM,QAAQ,CAAC,GAElCM,EAAU,MAAM;AAEd,UACEN,EAAM,YAAY,KAClBA,EAAM,YAAY,aAClB,CAACG,KACDH,EAAM;AAEN;AAEF,UAAIU,GAAU;AAEZ,cAAMU,IAAU,KAAK,IAAA,IAAQN,EAAS;AAEtC,QAAAF,EAAa,UAAU,KAAK,IAAI,GAAGA,EAAa,UAAUQ,CAAO;AAGjE,cAAMC,IAAiB,KAAK,IAAIxB,GAAqBuB,CAAO;AAC5D,QAAAF,EAAsB,SAASG,CAAc,aAAa,GAC1DL,EAAY,GAAG;AACf;AAAA,MACF;AAGA,MAAAF,EAAS,UAAU,KAAK,IAAA;AACxB,YAAMQ,IAAYV,EAAa;AAI/B,MAAAO,EAAO,UAAU,sBAAsB,MAAM;AAC3C,QAAAD,EAAsB,SAASI,CAAS,WAAW,GACnDN,EAAY,CAAC;AAAA,MACf,CAAC;AAED,YAAMP,IAAQ,WAAW,MAAM;AAC7B,QAAAR,EAAUD,EAAM,EAAE;AAAA,MACpB,GAAGsB,CAAS;AAEZ,aAAO,MAAM;AACX,qBAAab,CAAK,GAClB,qBAAqBU,EAAO,OAAO;AAAA,MACrC;AAAA,IACF,GAAG;AAAA,MACDT;AAAA,MACAP;AAAA,MACAH,EAAM;AAAA,MACNA,EAAM;AAAA,MACNA,EAAM;AAAA,MACNA,EAAM;AAAA,MACNA,EAAM;AAAA,MACNC;AAAA,IAAA,CACD;AAGD,UAAMsB,IAAmBC,EAAY,MAAMb,EAAY,EAAI,GAAG,CAAA,CAAE,GAC1Dc,IAAmBD,EAAY,MAAMb,EAAY,EAAK,GAAG,CAAA,CAAE,GAG3De,IAAO/B,EAAYK,EAAM,OAAO,KAAKZ;AAG3C,WAAIY,EAAM,WAEN,gBAAAf;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWQ;AAAA,UACT;AAAA,UACA,CAACU,KAAc;AAAA,UACfH,EAAM,aAAa;AAAA,QAAA;AAAA,QAErB,MAAK;AAAA,QACL,aAAU;AAAA,QACV,eAAY;AAAA,QACZ,cAAcuB;AAAA,QACd,cAAcE;AAAA,QAEb,UAAAzB,EAAM;AAAA,MAAA;AAAA,IAAA,IAMX,gBAAAhB;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWS;AAAA,UACT;AAAA,UACA,iBAAiBO,EAAM,OAAO;AAAA,UAC9B,CAACG,KAAc;AAAA,UACfH,EAAM,aAAa;AAAA,QAAA;AAAA,QAErB,MAAK;AAAA,QACL,aAAWA,EAAM,YAAY,UAAU,cAAc;AAAA,QACrD,eAAY;AAAA,QACZ,cAAcuB;AAAA,QACd,cAAcE;AAAA,QAGd,UAAA;AAAA,UAAA,gBAAAxC,EAAC,QAAA,EAAK,WAAWQ,EAAG,gBAAgB,iBAAiBO,EAAM,OAAO,EAAE,GAClE,UAAA,gBAAAf,EAACyC,GAAA,CAAA,CAAK,GACR;AAAA,UAGA,gBAAA1C,EAAC,OAAA,EAAI,WAAU,mBACZ,UAAA;AAAA,YAAAgB,EAAM,SAAS,gBAAAf,EAAC,OAAA,EAAI,WAAU,iBAAiB,YAAM,OAAM;AAAA,YAC5D,gBAAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,WAAWQ;AAAA,kBACT;AAAA,kBACAO,EAAM,SAAS;AAAA,gBAAA;AAAA,gBAGhB,UAAAA,EAAM;AAAA,cAAA;AAAA,YAAA;AAAA,UACT,GACF;AAAA,UAGCA,EAAM,eACL,gBAAAf;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS,MAAMgB,EAAUD,EAAM,EAAE;AAAA,cACjC,cAAW;AAAA,cAEX,4BAACX,GAAA,CAAA,CAAM;AAAA,YAAA;AAAA,UAAA;AAAA,UAKVW,EAAM,WAAW,KAAKA,EAAM,YAAY,aACvC,gBAAAf;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAWQ;AAAA,gBACT;AAAA,gBACA,qBAAqBO,EAAM,OAAO;AAAA,cAAA;AAAA,cAEpC,OAAO;AAAA,gBACL,OAAO,GAAGe,CAAQ;AAAA,gBAClB,YAAYE;AAAA,cAAA;AAAA,YACd;AAAA,UAAA;AAAA,QACF;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEAnB,EAAU,cAAc;AC9MjB,MAAM6B,IAAgD5B,EAAM;AAAA,EACjE,CAAC,EAAE,UAAA6B,GAAU,QAAAC,GAAQ,YAAAC,QAAsC;AACzD,UAAMC,IAAMC,EAAWxD,CAAc;AACrC,QAAI,CAACuD,EAAK,QAAO;AAGjB,UAAME,IAASJ,EAAO,OAAO,CAAChD,MAAM,CAACA,EAAE,SAAS,GAC1CqD,IAAUL,EAAO,OAAO,CAAChD,MAAMA,EAAE,SAAS,GAG1CsD,IAAU,CAAC,GAAGF,EAAO,MAAM,GAAGH,CAAU,GAAG,GAAGI,CAAO;AAE3D,QAAIC,EAAQ,WAAW,EAAG,QAAO;AAGjC,UAAMC,IAAc,KAAK,IAAI,GAAGH,EAAO,SAASH,CAAU;AAE1D,WACE,gBAAA9C;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAWS,EAAG,qBAAqB,sBAAsBmC,CAAQ,EAAE;AAAA,QACnE,cAAW;AAAA,QACX,MAAK;AAAA,QAEJ,UAAA;AAAA,UAAAO,EAAQ,IAAI,CAACnC,MACZ,gBAAAf;AAAA,YAACa;AAAA,YAAA;AAAA,cAEC,OAAAE;AAAA,cACA,WAAW+B,EAAI;AAAA,cACf,UAAUA,EAAI;AAAA,YAAA;AAAA,YAHT/B,EAAM;AAAA,UAAA,CAKd;AAAA,UACAoC,IAAc,KACb,gBAAApD,EAAC,SAAI,WAAU,uBAAsB,aAAU,UAAS,UAAA;AAAA,YAAA;AAAA,YACpDoD;AAAA,YAAY;AAAA,UAAA,EAAA,CAChB;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEAT,EAAe,cAAc;ACrC7B,MAAMU,IAAiC;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAEaC,IAAkD,CAAC;AAAA,EAC9D,UAAAC;AAAA,EACA,YAAAT,IAAa;AAAA,EACb,UAAUU,IAAkB;AAAA,EAC5B,UAAUC,IAAkB;AAC9B,MAAM;AACJ,QAAM,CAACZ,GAAQa,CAAQ,IAAIC,EAAWjE,GAAgB,CAAA,CAAE,GAIlDkE,IAAWpB;AAAA,IACf,CAACqB,GAA6BC,MAA2E;AACvG,YAAMC,KAAKD,KAAA,gBAAAA,EAAS,OAAMtD,EAAA,GACpBQ,IAAuB;AAAA,QAC3B,IAAA+C;AAAA,QACA,SAAAF;AAAA,QACA,OAAOC,KAAA,gBAAAA,EAAS;AAAA,QAChB,UAASA,KAAA,gBAAAA,EAAS,YAAW;AAAA,QAC7B,WAAUA,KAAA,gBAAAA,EAAS,aAAYL;AAAA,QAC/B,WAAUK,KAAA,gBAAAA,EAAS,aAAYN;AAAA,QAC/B,cAAaM,KAAA,gBAAAA,EAAS,gBAAe;AAAA,QACrC,cAAaA,KAAA,gBAAAA,EAAS,gBAAe;AAAA,QACrC,WAAW;AAAA,QACX,WAAW,KAAK,IAAA;AAAA,QAChB,SAAS;AAAA,QACT,UAAUA,KAAA,gBAAAA,EAAS;AAAA,MAAA;AAGrB,aAAIA,KAAA,QAAAA,EAAS,KACXJ,EAAS,EAAE,MAAM,UAAU,OAAA1C,EAAA,CAAO,IAElC0C,EAAS,EAAE,MAAM,OAAO,OAAA1C,EAAA,CAAO,GAE1B+C;AAAA,IACT;AAAA,IACA,CAACN,GAAiBD,CAAe;AAAA,EAAA,GAG7BQ,IAAcxB;AAAA,IAClB,CACEuB,GACAE,MAMG;AACH,MAAAP,EAAS,EAAE,MAAM,UAAU,IAAAK,GAAI,SAAAE,GAAS;AAAA,IAC1C;AAAA,IACA,CAAA;AAAA,EAAC,GAGGC,IAAe1B,EAAY,CAACuB,MAAgB;AAChD,IAAAL,EAAS,EAAE,MAAM,WAAW,IAAAK,EAAA,CAAI;AAAA,EAClC,GAAG,CAAA,CAAE,GAECI,IAAc3B,EAAY,CAACuB,MAAgB;AAC/C,IAAAL,EAAS,EAAE,MAAM,UAAU,IAAAK,EAAA,CAAI;AAAA,EACjC,GAAG,CAAA,CAAE,GAICK,IAAoCC;AAAA,IACxC,OAAO;AAAA,MACL,UAAAT;AAAA,MACA,aAAAI;AAAA,MACA,cAAAE;AAAA,MACA,aAAAC;AAAA,MACA,QAAQ;AAAA,QACN,YAAArB;AAAA,QACA,UAAUU;AAAA,QACV,UAAUC;AAAA,MAAA;AAAA,IACZ;AAAA,IAEF;AAAA,MACEG;AAAA,MACAI;AAAA,MACAE;AAAA,MACAC;AAAA,MACArB;AAAA,MACAU;AAAA,MACAC;AAAA,IAAA;AAAA,EACF,GAKIa,IAAgBD,EAAQ,MAAM;AAClC,UAAME,IAAiD;AAAA,MACrD,aAAa,CAAA;AAAA,MACb,YAAY,CAAA;AAAA,MACZ,cAAc,CAAA;AAAA,MACd,gBAAgB,CAAA;AAAA,MAChB,eAAe,CAAA;AAAA,MACf,iBAAiB,CAAA;AAAA,IAAC;AAEpB,eAAW1E,KAAKgD;AACd,MAAA0B,EAAO1E,EAAE,QAAQ,EAAE,KAAKA,CAAC;AAE3B,WAAO0E;AAAA,EACT,GAAG,CAAC1B,CAAM,CAAC;AAEX,SACE,gBAAA7C,EAACR,EAAe,UAAf,EAAwB,OAAO4E,GAC7B,UAAA;AAAA,IAAAb;AAAA,IAGAF,EAAc;AAAA,MAAI,CAACmB,MAClBF,EAAcE,CAAG,EAAE,SAAS,IAC1B,gBAAAvE;AAAA,QAAC0C;AAAA,QAAA;AAAA,UAEC,UAAU6B;AAAA,UACV,QAAQF,EAAcE,CAAG;AAAA,UACzB,YAAA1B;AAAA,QAAA;AAAA,QAHK0B;AAAA,MAAA,IAKL;AAAA,IAAA;AAAA,EACN,GACF;AAEJ;AAEAlB,EAAgB,cAAc;ACvIvB,SAASmB,IAAqB;AACnC,QAAM1B,IAAMC,EAAWxD,CAAc;AAErC,MAAI,CAACuD;AACH,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAKJ,SAAOsB,EAAQ,MAAM;AAEnB,UAAMrD,IAAS,CAAC6C,GAA6BC,MAC3Cf,EAAI,SAASc,GAASC,CAAO;AAG/B,WAAA9C,EAAM,UAAU,CAAC0D,GAAKC,MACpB5B,EAAI,SAAS2B,GAAK,EAAE,GAAGC,GAAM,SAAS,UAAA,CAAW,GAEnD3D,EAAM,QAAQ,CAAC0D,GAAKC,MAClB5B,EAAI,SAAS2B,GAAK,EAAE,GAAGC,GAAM,SAAS,QAAA,CAAS,GAEjD3D,EAAM,UAAU,CAAC0D,GAAKC,MACpB5B,EAAI,SAAS2B,GAAK,EAAE,GAAGC,GAAM,SAAS,UAAA,CAAW,GAEnD3D,EAAM,OAAO,CAAC0D,GAAKC,MAAS5B,EAAI,SAAS2B,GAAK,EAAE,GAAGC,GAAM,SAAS,OAAA,CAAQ,GAG1E3D,EAAM,UAAU,CAAC0D,GAAKC,MACpB5B,EAAI,SAAS2B,GAAK;AAAA,MAChB,GAAGC;AAAA,MACH,SAAS;AAAA,MACT,WAAUA,KAAA,gBAAAA,EAAM,aAAY;AAAA,MAC5B,cAAaA,KAAA,gBAAAA,EAAM,gBAAe;AAAA,IAAA,CACnC,GAGH3D,EAAM,SAAS,CAAC4D,GAASD,MACvB5B,EAAI,SAAS6B,GAAS,EAAE,GAAGD,GAAM,SAAS,WAAW,UAAU,IAAM,GAGvE3D,EAAM,UAAU,CAAC+C,MAAgBhB,EAAI,aAAagB,CAAE,GAGpD/C,EAAM,SAAS,CAAC+C,MAAgBhB,EAAI,YAAYgB,CAAE,GAGlD/C,EAAM,UAAU,OACd6D,GACAF,GACAG,MACe;AACf,YAAMf,IAAKhB,EAAI,SAAS4B,EAAK,SAAS;AAAA,QACpC,GAAGG;AAAA,QACH,SAAS;AAAA,QACT,UAAU;AAAA,QACV,aAAa;AAAA,MAAA,CACE,GAEXC,IACJ,OAAOF,KAAgB,aAAaA,MAAgBA;AAEtD,UAAI;AACF,cAAMG,IAAS,MAAMD,GACfL,IACJ,OAAOC,EAAK,WAAY,aACpBA,EAAK,QAAQK,CAAM,IACnBL,EAAK;AACX,eAAA5B,EAAI,YAAYgB,GAAI;AAAA,UAClB,SAASW;AAAA,UACT,SAAS;AAAA,UACT,WAAUI,KAAA,gBAAAA,EAAW,aAAY/B,EAAI,OAAO;AAAA,UAC5C,aAAa;AAAA,QAAA,CACd,GACMiC;AAAA,MACT,SAASC,GAAO;AACd,cAAMP,IACJ,OAAOC,EAAK,SAAU,aAAaA,EAAK,MAAMM,CAAK,IAAIN,EAAK;AAC9D,cAAA5B,EAAI,YAAYgB,GAAI;AAAA,UAClB,SAASW;AAAA,UACT,SAAS;AAAA,UACT,WAAUI,KAAA,gBAAAA,EAAW,aAAY/B,EAAI,OAAO;AAAA,UAC5C,aAAa;AAAA,QAAA,CACd,GACKkC;AAAA,MACR;AAAA,IACF,GAEOjE;AAAA,EACT,GAAG;AAAA,IACD+B,EAAI;AAAA,IACJA,EAAI;AAAA,IACJA,EAAI;AAAA,IACJA,EAAI;AAAA,IACJA,EAAI,OAAO;AAAA,EAAA,CACZ;AACH;ACtCA,IAAImC,IAAgD;AAEpD,SAASC,IAAS;AAChB,QAAMC,IAAMX,EAAA;AAIZ,SAAA1D,EAAM,UAAU,MAAM;AACpB,IAAImE,MACFA,EAAYE,CAAG,GACfF,IAAc;AAAA,EAElB,GAAG,CAACE,CAAG,CAAC,GAID;AACT;AAcO,SAASC,GACdvB,IAA6B,IACT;AACpB,QAAM,EAAE,UAAAlB,IAAW,aAAa,YAAAE,IAAa,GAAG,UAAAwC,IAAW,QAASxB,GAG9DyB,IAAY,SAAS,cAAc,KAAK;AAC9C,EAAAA,EAAU,aAAa,2BAA2B,EAAE,GACpDA,EAAU,MAAM,UAAU,YAC1B,SAAS,KAAK,YAAYA,CAAS;AAInC,MAAIC,IAAoBC,EAAWF,CAAS;AAE5C,QAAMG,IAAW,IAAI,QAAkB,CAACC,MAAY;AAClD,IAAAT,IAAcS;AAAA,EAChB,CAAC,GAIKC,IAAsB,CAAA;AAC5B,MAAIC,IAA+B;AAGnC,EAAAH,EAAS,KAAK,CAACN,MAAQ;AACrB,IAAAS,IAAcT;AACd,eAAWU,KAAQF;AACjB,MAAIE,EAAK,WAAW,aACjBV,EAAY,GAAGU,EAAK,IAAI,IAExBV,EAAYU,EAAK,MAAM,EAAE,GAAGA,EAAK,IAAI;AAG1C,IAAAF,EAAM,SAAS;AAAA,EACjB,CAAC,GAGDJ,EAAK;AAAA,IACHzE,EAAM;AAAA,MACJuC;AAAA,MACA,EAAE,UAAAV,GAAU,YAAAE,GAAY,UAAAwC,EAAA;AAAA,MACxBvE,EAAM,cAAcoE,CAAM;AAAA,IAAA;AAAA,EAC5B;AAIF,QAAMY,IAAY,CAACC,MAAmBtF,MAChCmF,IACMA,EAAoBG,CAAM,EAAE,GAAGtF,CAAI,KAE7CkF,EAAM,KAAK,EAAE,QAAAI,GAAQ,MAAAtF,EAAA,CAAM,GACpB,WAGHM,IAAS,CAAC6C,GAA6Bc,MACvCkB,IAAoBA,EAAYhC,GAASc,CAAI,KACjDiB,EAAM,KAAK,EAAE,QAAQ,YAAY,MAAM,CAAC/B,GAASc,CAAI,GAAG,GACjD;AAGT,SAAA3D,EAAM,UAAU,CAAC0D,GAAKC,MAASoB,EAAU,WAAWrB,GAAKC,CAAI,GAC7D3D,EAAM,QAAQ,CAAC0D,GAAKC,MAASoB,EAAU,SAASrB,GAAKC,CAAI,GACzD3D,EAAM,UAAU,CAAC0D,GAAKC,MAASoB,EAAU,WAAWrB,GAAKC,CAAI,GAC7D3D,EAAM,OAAO,CAAC0D,GAAKC,MAASoB,EAAU,QAAQrB,GAAKC,CAAI,GACvD3D,EAAM,UAAU,CAAC0D,GAAKC,MAASoB,EAAU,WAAWrB,GAAKC,CAAI,GAC7D3D,EAAM,SAAS,CAAC4D,GAASD,MAASoB,EAAU,UAAUnB,GAASD,CAAI,GACnE3D,EAAM,UAAU,CAAC+C,MAAQgC,EAAU,WAAWhC,CAAE,GAChD/C,EAAM,SAAS,CAAC+C,MAAQgC,EAAU,UAAUhC,CAAE,GAE9C/C,EAAM,UAAU,CAAC+D,GAASJ,GAAMG,MAC1Be,IAAoBA,EAAY,QAAQd,GAASJ,GAAMG,CAAS,IAE7DY,EAAS,KAAK,CAACN,MAAQA,EAAI,QAAQL,GAASJ,GAAMG,CAAS,CAAC,GAGrE9D,EAAM,UAAU,MAAM;AACpB,IAAIwE,MACFA,EAAK,QAAA,GACLA,IAAO,OAETD,EAAU,OAAA,GACVM,IAAc;AAAA,EAChB,GAEO7E;AACT;"}
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .toast23-container,.toast23-container *,.toast23-container *:before,.toast23-container *:after{box-sizing:border-box;margin:0;padding:0}.toast23-container{position:fixed;z-index:9999;display:flex;flex-direction:column;gap:.75rem;padding:1rem;pointer-events:none;max-height:100vh;overflow:hidden}.toast23-container--top-right{top:0;right:0}.toast23-container--top-left{top:0;left:0}.toast23-container--top-center{top:0;left:50%;transform:translate(-50%);align-items:center}.toast23-container--bottom-right{bottom:0;right:0;flex-direction:column-reverse}.toast23-container--bottom-left{bottom:0;left:0;flex-direction:column-reverse}.toast23-container--bottom-center{bottom:0;left:50%;transform:translate(-50%);flex-direction:column-reverse;align-items:center}.toast23-item{pointer-events:auto;position:relative;display:flex;align-items:flex-start;gap:.75rem;min-width:320px;max-width:26rem;padding:.875rem 1rem;border-radius:.75rem;border:1px solid;overflow:hidden;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;line-height:1.5;box-shadow:0 4px 6px -1px #00000014,0 2px 4px -2px #0000000d;transform:translate(0);opacity:1;transition:transform .3s cubic-bezier(.4,0,.2,1),opacity .3s cubic-bezier(.4,0,.2,1);cursor:default}.toast23-item:hover{box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000000f}.toast23-container--top-right .toast23-item--entering,.toast23-container--top-right .toast23-item--exiting,.toast23-container--bottom-right .toast23-item--entering,.toast23-container--bottom-right .toast23-item--exiting{transform:translate(calc(100% + 1rem));opacity:0}.toast23-container--top-left .toast23-item--entering,.toast23-container--top-left .toast23-item--exiting,.toast23-container--bottom-left .toast23-item--entering,.toast23-container--bottom-left .toast23-item--exiting{transform:translate(calc(-100% - 1rem));opacity:0}.toast23-container--top-center .toast23-item--entering,.toast23-container--top-center .toast23-item--exiting{transform:translateY(-100%);opacity:0}.toast23-container--bottom-center .toast23-item--entering,.toast23-container--bottom-center .toast23-item--exiting{transform:translateY(100%);opacity:0}.toast23-item--success{background:#f0fdf4f2;border-color:#bbf7d0}.toast23-item--error{background:#fef2f2f2;border-color:#fecaca}.toast23-item--warning{background:#fefce8f2;border-color:#fef08a}.toast23-item--info{background:#eff6fff2;border-color:#bfdbfe}.toast23-item--default,.toast23-item--loading{background:#f9fafbf2;border-color:#e5e7eb}@media (prefers-color-scheme: dark){.toast23-item--success{background:#16653440;border-color:#166534}.toast23-item--error{background:#991b1b40;border-color:#991b1b}.toast23-item--warning{background:#854d0e40;border-color:#854d0e}.toast23-item--info{background:#1e40af40;border-color:#1e40af}.toast23-item--default,.toast23-item--loading{background:#37415180;border-color:#4b5563}.toast23-title{color:#f9fafb!important}.toast23-message{color:#e5e7eb!important}.toast23-message--with-title{color:#d1d5db!important}.toast23-dismiss{color:#9ca3af!important}.toast23-dismiss:hover{color:#e5e7eb!important}.toast23-queue-badge{color:#d1d5db!important;background:#374151b3!important;border-color:#4b5563!important}}.dark .toast23-item--success{background:#16653440;border-color:#166534}.dark .toast23-item--error{background:#991b1b40;border-color:#991b1b}.dark .toast23-item--warning{background:#854d0e40;border-color:#854d0e}.dark .toast23-item--info{background:#1e40af40;border-color:#1e40af}.dark .toast23-item--default,.dark .toast23-item--loading{background:#37415180;border-color:#4b5563}.dark .toast23-title{color:#f9fafb}.dark .toast23-message{color:#e5e7eb}.dark .toast23-message--with-title{color:#d1d5db}.dark .toast23-dismiss{color:#9ca3af}.dark .toast23-dismiss:hover{color:#e5e7eb}.dark .toast23-queue-badge{color:#d1d5db;background:#374151b3;border-color:#4b5563}.toast23-icon{display:flex;align-items:center;flex-shrink:0;margin-top:1px}.toast23-icon--success{color:#22c55e}.toast23-icon--error{color:#ef4444}.toast23-icon--warning{color:#eab308}.toast23-icon--info{color:#3b82f6}.toast23-icon--default{color:#6b7280}.toast23-icon--loading{color:#3b82f6}.toast23-content{flex:1;min-width:0}.toast23-title{font-size:.875rem;font-weight:600;color:#111827;margin-bottom:.125rem;line-height:1.3}.toast23-message{font-size:.875rem;font-weight:500;color:#1f2937;word-break:break-word}.toast23-message--with-title{color:#6b7280;font-weight:400}.toast23-dismiss{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:1.5rem;height:1.5rem;border:none;background:transparent;color:#9ca3af;cursor:pointer;border-radius:.25rem;transition:color .15s ease,background-color .15s ease;margin:-.125rem -.25rem 0 0;padding:0}.toast23-dismiss:hover{color:#374151;background:#0000000d}.toast23-dismiss:focus-visible{outline:2px solid #3b82f6;outline-offset:1px}.toast23-progress{position:absolute;bottom:0;left:0;height:3.5px;border-radius:0 0 0 .75rem}.toast23-progress--success{background:#22c55e}.toast23-progress--error{background:#ef4444}.toast23-progress--warning{background:#eab308}.toast23-progress--info{background:#3b82f6}.toast23-progress--default{background:#6b7280}.toast23-queue-badge{font-family:inherit;font-size:.75rem;font-weight:500;color:#6b7280;background:#fffc;border:1px solid #e5e7eb;border-radius:9999px;padding:.25rem .75rem;text-align:center;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.toast23-spinner{animation:toast23-spin .7s linear infinite}@keyframes toast23-spin{to{transform:rotate(360deg)}}@media (max-width: 480px){.toast23-container{padding:.75rem;left:0!important;right:0!important}.toast23-item{min-width:0;max-width:100%}}
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "toast-23",
3
+ "version": "1.0.0",
4
+ "description": "A lightweight, accessible, fully-typed React toast notification library with zero dependencies.",
5
+ "author": "",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.mjs",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "import": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.mjs"
16
+ },
17
+ "require": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.cjs"
20
+ }
21
+ },
22
+ "./styles.css": "./dist/style.css"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "sideEffects": [
28
+ "*.css"
29
+ ],
30
+ "scripts": {
31
+ "dev": "vite",
32
+ "build": "tsc --noEmit && vite build",
33
+ "lint": "tsc --noEmit",
34
+ "test": "vitest run",
35
+ "test:watch": "vitest",
36
+ "test:coverage": "vitest run --coverage",
37
+ "prepublishOnly": "npm run build"
38
+ },
39
+ "peerDependencies": {
40
+ "react": ">=18.0.0",
41
+ "react-dom": ">=18.0.0"
42
+ },
43
+ "devDependencies": {
44
+ "@testing-library/jest-dom": "^6.9.1",
45
+ "@testing-library/react": "^16.3.2",
46
+ "@testing-library/user-event": "^14.6.1",
47
+ "@types/react": "^18.2.0",
48
+ "@types/react-dom": "^18.2.0",
49
+ "@vitejs/plugin-react": "^4.2.0",
50
+ "jsdom": "^28.1.0",
51
+ "react": "^18.2.0",
52
+ "react-dom": "^18.2.0",
53
+ "typescript": "^5.3.0",
54
+ "vite": "^5.4.0",
55
+ "vite-plugin-dts": "^3.9.0",
56
+ "vitest": "^4.0.18"
57
+ },
58
+ "keywords": [
59
+ "react",
60
+ "toast",
61
+ "notifications",
62
+ "toaster",
63
+ "alert",
64
+ "snackbar",
65
+ "react-toast",
66
+ "typescript",
67
+ "accessible",
68
+ "toast-23"
69
+ ],
70
+ "repository": {
71
+ "type": "git",
72
+ "url": ""
73
+ },
74
+ "homepage": "",
75
+ "bugs": {
76
+ "url": ""
77
+ }
78
+ }