robot-toast 2.1.1 → 2.1.3

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.
Files changed (2) hide show
  1. package/README.md +197 -349
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,24 +1,17 @@
1
1
  # 🤖 robot-toast
2
2
 
3
- A lightweight, zero-dependency, framework-agnostic toast notification library featuring an animated robot companion. Fully draggable with edge-snapping, typewriter-style messages, multiple themes, rich transitions, a tree-shakeable cast of **16 built-in robots** — and now an optional React hook.
3
+ <video autoplay loop muted width="100%" style="max-width: 100%;">
4
+ <source src="https://raw.githubusercontent.com/Pratham2703005/robot-toast/refs/heads/main/public/offiicial-page/toasts.mp4" type="video/mp4">
5
+ </video>
6
+
7
+ Lightweight toast notifications with complete control.
8
+
9
+ robot-toast gives you a canvas, not a prescription — bring your own robot, colors, buttons, and timing. 16 tree-shakeable robots, fully draggable, zero dependencies.
4
10
 
5
11
  <p align="left">
6
- <a href="https://stackblitz.com/your-demo-link"
7
- style="color:#e53935; font-weight:600; text-decoration:none;">
8
- Demo
9
- </a>
10
- </p>
11
- <p align="center">
12
- <a href="https://pratham-potfolio.vercel.app/" target="_blank">
13
- <img src="https://img.shields.io/badge/Portfolio-000?style=for-the-badge&logo=vercel&logoColor=white" />
14
- </a>
15
- <a href="https://www.linkedin.com/in/pratham-kumar-a6b672275/" target="_blank">
16
- <img src="https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white" />
17
- </a>
18
- <a href="https://github.com/Pratham2703005" target="_blank">
19
- <img src="https://img.shields.io/badge/GitHub-000?style=for-the-badge&logo=github&logoColor=white" />
20
- </a>
12
+ <a href="https://robot-toast-client.vercel.app/" style="color:#e53935; font-weight:600; text-decoration:none;">Demo & Playground →</a>
21
13
  </p>
14
+
22
15
  <p align="center">
23
16
  <a href="https://www.npmjs.com/package/robot-toast">
24
17
  <img src="https://img.shields.io/npm/v/robot-toast?style=flat-square" />
@@ -27,55 +20,64 @@ A lightweight, zero-dependency, framework-agnostic toast notification library fe
27
20
  <img src="https://img.shields.io/bundlephobia/minzip/robot-toast?style=flat-square" />
28
21
  </p>
29
22
 
30
- <p align="center">
31
- <img src="https://raw.githubusercontent.com/Pratham2703005/robot-toast/refs/heads/main/public/offiicial-page/lightmode.png" alt="Light mode" width="320" />
32
- <img src="https://raw.githubusercontent.com/Pratham2703005/robot-toast/refs/heads/main/public/offiicial-page/darkmode.png" alt="Dark mode" width="320" />
33
- <img src="https://raw.githubusercontent.com/Pratham2703005/robot-toast/refs/heads/main/public/offiicial-page/custom.png" alt="Custom styled" width="320" />
34
- </p>
35
-
36
- ---
37
-
38
- ## What's new in v2
39
-
40
- - **36% smaller core bundle** (61 KB 39 KB). Robots moved to a tree-shakeable subpath only the ones you import end up in your bundle.
41
- - **Opt-in robots.** Omitting `robotVariant` renders *no robot* now. Pass `'default'` or import from `robot-toast/robots` to bring one back.
42
- - **Inline buttons.** Pass a `buttons` array for Undo / Retry / Cancel-style inline CTAs rendered in array order, optional `className` per button for custom visual hierarchy.
43
- - **`toast.promise()`** attach loading/success/error toasts to any promise.
44
- - **React subpath.** `useRobotToast()` + `useToastOnMount()` as optional ergonomic bindings.
45
- - **ARIA roles.** `role="alert"` for `error`/`warning`, `role="status"` elsewhere, plus `aria-atomic` and a labeled close button.
46
-
47
- Upgrading from v1? See [MIGRATION.md](./MIGRATION.md) for the five-minute changeover.
48
-
49
- ---
50
-
51
- ## Features
52
-
53
- | Category | Details |
54
- |---|---|
55
- | **Themes** | `light` · `dark` · `colored` |
56
- | **Types** | `default` · `info` · `success` · `warning` · `error` |
57
- | **Transitions** | `bounce` · `flip` · `zoom` · `slide` |
58
- | **Positions** | `top-left` · `top-center` · `top-right` · `bottom-left` · `bottom-center` · `bottom-right` |
59
- | **Robots** | 16 tree-shakeable built-ins import what you use, pass any image path (svg, png, jpg, gif, webp), or skip the robot entirely |
60
- | **Custom styles** | Pass a `style` object to customize the message bubble however you like |
61
- | **Drag & drop** | Full XY drag with viewport clamping; snaps to the nearest screen edge on release |
62
- | **Typewriter effect** | Characters appear one by one — configurable speed or instant |
63
- | **Multi-toast** | Configurable `limit` for simultaneous toasts; excess is auto-queued |
64
- | **Progress bar** | Countdown bar — show or hide it |
65
- | **Pause on hover** | Timer pauses when you hover over the toast |
66
- | **Pause on focus loss** | Timer pauses when the browser tab loses focus |
67
- | **Promise helper** | `toast.promise(p, { loading, success, error })` |
68
- | **React hook** | `useRobotToast()` + `useToastOnMount()` from `robot-toast/react` |
69
- | **RTL** | Right-to-left layout support |
70
- | **Newest on top** | Stack new toasts above existing ones |
71
- | **Auto-close** | Configurable duration, or disable entirely |
72
- | **Accessibility** | `role="alert"` / `role="status"`, `aria-live`, `aria-atomic`, labeled dismiss button |
73
- | **SSR-safe** | All DOM access is guarded — safe for Next.js, Nuxt, etc. |
74
- | **Zero dependencies** | Pure TypeScript — ESM + CJS builds, tree-shakeable |
75
-
76
- ---
77
-
78
- ## Installation
23
+ ## 🤖 Built-in Robots
24
+
25
+ <table>
26
+ <tr>
27
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><path d="M 25 60 Q 15 65, 20 80" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 Q 95 45, 85 25" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="20" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="50" y1="20" x2="50" y2="10" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="8" r="4" fill="#FF6B6B" stroke="#2B3A55" stroke-width="2"/><circle cx="40" cy="38" r="4" fill="#2B3A55"/><path d="M 55 38 Q 60 33, 65 38" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/></svg><br/><strong>wave</strong></td>
28
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><path d="M 25 60 Q 15 70, 25 85" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 Q 85 70, 75 85" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="20" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="50" y1="20" x2="50" y2="10" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="8" r="4" fill="#4D96FF" stroke="#2B3A55" stroke-width="2"/><circle cx="40" cy="38" r="4" fill="#2B3A55"/><circle cx="60" cy="38" r="4" fill="#2B3A55"/><line x1="45" y1="46" x2="55" y2="46" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/></svg><br/><strong>base</strong></td>
29
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#FFFFFF" /><stop offset="100%" stop-color="#D0E3FF" /></linearGradient><linearGradient id="darkGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#A8B2C1" /><stop offset="100%" stop-color="#7B8CA5" /></linearGradient></defs><line x1="50" y1="20" x2="50" y2="6" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="6" r="5" fill="#FFD93D" stroke="#2B3A55" stroke-width="3"/><path d="M 32 60 Q 15 65, 18 80" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="18" cy="80" r="4" fill="url(#darkGrad)" stroke="#2B3A55" stroke-width="3"/><path d="M 68 60 Q 85 65, 82 80" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="82" cy="80" r="4" fill="url(#darkGrad)" stroke="#2B3A55" stroke-width="3"/><rect x="42" y="48" width="16" height="12" fill="url(#darkGrad)" stroke="#2B3A55" stroke-width="4"/><path d="M 36 56 L 64 56 L 68 85 C 68 90, 62 94, 50 94 C 38 94, 32 90, 32 85 Z" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4" stroke-linejoin="round"/><rect x="42" y="66" width="16" height="8" rx="4" fill="#4D96FF" stroke="#2B3A55" stroke-width="3"/><rect x="16" y="28" width="10" height="16" rx="3" fill="url(#darkGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="74" y="28" width="10" height="16" rx="3" fill="url(#darkGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="22" y="20" width="56" height="34" rx="14" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><circle cx="36" cy="38" r="4" fill="#2B3A55"/><circle cx="64" cy="38" r="4" fill="#2B3A55"/><ellipse cx="28" cy="43" rx="4" ry="2" fill="#FF6B6B" opacity="0.5"/><ellipse cx="72" cy="43" rx="4" ry="2" fill="#FF6B6B" opacity="0.5"/><path d="M 46 44 Q 50 48, 54 44" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/></svg><br/><strong>base2</strong></td>
30
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><circle cx="20" cy="20" r="3" fill="#FF6B6B" /><rect x="80" y="25" width="6" height="6" fill="#4D96FF" transform="rotate(45 80 25)"/><circle cx="75" cy="10" r="2" fill="#FFD93D" /><path d="M 25 55 Q 10 40, 20 20" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 55 Q 90 40, 80 20" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="35" y="50" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="15" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="50" y1="15" x2="50" y2="5" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="3" r="4" fill="#4ECB71" stroke="#2B3A55" stroke-width="2"/><path d="M 35 32 Q 40 25, 45 32" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/><path d="M 55 32 Q 60 25, 65 32" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/></svg><br/><strong>success</strong></td>
31
+ </tr>
32
+ <tr>
33
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><path d="M 85 15 L 95 35 L 75 35 Z" fill="#FF6B6B" stroke="#2B3A55" stroke-width="2" stroke-linejoin="round"/><text x="85" y="32" font-family="sans-serif" font-size="14" fill="#FFF" font-weight="bold" text-anchor="middle">!</text><path d="M 25 55 Q 10 50, 20 35" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 Q 90 70, 80 85" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="23" y="20" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="48" y1="20" x2="40" y2="10" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="40" cy="8" r="4" fill="#FF6B6B" stroke="#2B3A55" stroke-width="2"/><path d="M 34 34 L 42 42 M 42 34 L 34 42" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/><path d="M 54 34 L 62 42 M 62 34 L 54 42" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/><path d="M 38 48 L 42 45 L 46 48 L 50 45 L 54 48 L 58 45" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg><br/><strong>error</strong></td>
34
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><path d="M 20 30 Q 10 25, 15 15 Q 25 10, 30 20" fill="none" stroke="#A8B2C1" stroke-width="3" stroke-linecap="round"/><path d="M 80 30 Q 90 25, 85 15 Q 75 10, 70 20" fill="none" stroke="#A8B2C1" stroke-width="3" stroke-linecap="round"/><path d="M 25 60 L 15 75" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="15" cy="75" r="5" fill="#2B3A55"/><path d="M 75 60 L 85 75" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="85" cy="75" r="5" fill="#2B3A55"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="25" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="50" y1="25" x2="50" y2="15" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="13" r="4" fill="#FF3333" stroke="#2B3A55" stroke-width="2"/><path d="M 32 35 L 48 42" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 68 35 L 52 42" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="40" y="48" width="20" height="6" rx="2" fill="#FFF" stroke="#2B3A55" stroke-width="2"/><line x1="45" y1="48" x2="45" y2="54" stroke="#2B3A55" stroke-width="2"/><line x1="50" y1="48" x2="50" y2="54" stroke="#2B3A55" stroke-width="2"/><line x1="55" y1="48" x2="55" y2="54" stroke="#2B3A55" stroke-width="2"/></svg><br/><strong>angry</strong></td>
35
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><path d="M 15 30 Q 10 20, 20 15 M 20 35 Q 15 25, 25 20" fill="none" stroke="#FF6B6B" stroke-width="3" stroke-linecap="round" opacity="0.7"/><path d="M 85 30 Q 90 20, 80 15 M 80 35 Q 85 25, 75 20" fill="none" stroke="#FF6B6B" stroke-width="3" stroke-linecap="round" opacity="0.7"/><path d="M 25 60 L 20 80" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 L 80 80" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="20" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="50" y1="20" x2="50" y2="10" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="8" r="4" fill="#FF6B6B" stroke="#2B3A55" stroke-width="2"/><circle cx="40" cy="38" r="3" fill="#2B3A55"/><circle cx="60" cy="38" r="3" fill="#2B3A55"/><path d="M 32 32 L 45 36 M 68 32 L 55 36" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 40 50 Q 50 44, 60 50" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/></svg><br/><strong>angry2</strong></td>
36
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><path d="M 75 15 Q 95 15, 95 30 Q 95 45, 80 45 L 70 50 L 72 42 Q 60 40, 60 30 Q 60 15, 75 15 Z" fill="#FFF" stroke="#2B3A55" stroke-width="3"/><path d="M 25 60 Q 15 70, 30 80" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 Q 85 40, 70 25" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="20" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="50" y1="20" x2="50" y2="10" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="8" r="4" fill="#4D96FF" stroke="#2B3A55" stroke-width="2"/><circle cx="40" cy="36" r="4" fill="#2B3A55"/><circle cx="60" cy="36" r="4" fill="#2B3A55"/><ellipse cx="50" cy="46" rx="6" ry="3" fill="#2B3A55"/></svg><br/><strong>shock</strong></td>
37
+ </tr>
38
+ <tr>
39
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><circle cx="80" cy="20" r="10" fill="#FFF" stroke="#2B3A55" stroke-width="3"/><text x="80" y="25" font-family="sans-serif" font-size="14" fill="#2B3A55" font-weight="bold" text-anchor="middle">?</text><path d="M 25 60 Q 15 65, 20 80" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 Q 85 55, 65 50" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><g transform="rotate(-5 50 37)"><rect x="25" y="20" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="50" y1="20" x2="50" y2="10" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="8" r="4" fill="#FFD93D" stroke="#2B3A55" stroke-width="2"/><circle cx="40" cy="38" r="4" fill="#2B3A55"/><circle cx="60" cy="38" r="4" fill="#2B3A55"/></g></svg><br/><strong>think</strong></td>
40
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><path d="M 40 38 L 10 20 A 30 30 0 0 0 10 56 Z" fill="#4ECB71" opacity="0.3"/><path d="M 25 60 Q 15 70, 25 85" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 Q 85 70, 75 85" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="20" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="50" y1="20" x2="50" y2="10" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="8" r="4" fill="#4ECB71" stroke="#2B3A55" stroke-width="2"/><circle cx="60" cy="38" r="4" fill="#2B3A55"/><circle cx="40" cy="38" r="6" fill="none" stroke="#4ECB71" stroke-width="2"/><circle cx="40" cy="38" r="2" fill="#4ECB71"/></svg><br/><strong>search</strong></td>
41
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><g stroke="#2B3A55" stroke-width="2" fill="#FFD93D"><circle cx="85" cy="30" r="6" /><path d="M85 22V24 M85 36V38 M93 30H91 M77 30H79" stroke-linecap="round"/><circle cx="15" cy="75" r="5" fill="#A8B2C1"/><path d="M15 68V70 M15 80V82 M22 75H20 M8 75H10" stroke-linecap="round"/></g><path d="M 25 60 Q 15 55, 30 45" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 28 43 L 22 37 M 32 47 L 36 43" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 Q 85 65, 80 80" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="20" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="50" y1="20" x2="50" y2="10" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="8" r="4" fill="#FFD93D" stroke="#2B3A55" stroke-width="2"/><circle cx="40" cy="38" r="4" fill="#2B3A55"/><circle cx="60" cy="38" r="4" fill="#2B3A55"/></svg><br/><strong>loading</strong></td>
42
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><text x="75" y="25" font-family="sans-serif" font-size="12" fill="#2B3A55" font-weight="bold">Z</text><text x="85" y="15" font-family="sans-serif" font-size="10" fill="#2B3A55" font-weight="bold">z</text><path d="M 25 60 Q 15 70, 25 85" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 Q 85 70, 75 85" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="25" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><path d="M 50 25 Q 45 15, 35 12" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="35" cy="12" r="4" fill="#A8B2C1" stroke="#2B3A55" stroke-width="2"/><path d="M 35 42 Q 40 46, 45 42" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/><path d="M 55 42 Q 60 46, 65 42" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/></svg><br/><strong>sleep</strong></td>
43
+ </tr>
44
+ <tr>
45
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><path d="M 25 60 Q 20 40, 35 35" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 Q 80 70, 78 85" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="22" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><path d="M 50 22 Q 55 12, 65 15" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="65" cy="15" r="4" fill="#A8B2C1" stroke="#2B3A55" stroke-width="2"/><path d="M 55 40 Q 60 36, 65 40" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/><rect x="30" y="28" width="20" height="20" rx="8" fill="#E2F0FF" stroke="#2B3A55" stroke-width="4" transform="rotate(-10 40 38)"/><line x1="55" y1="50" x2="65" y2="50" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/></svg><br/><strong>headPalm</strong></td>
46
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><rect x="30" y="80" width="40" height="10" rx="2" fill="#A8B2C1" stroke="#2B3A55" stroke-width="3"/><line x1="35" y1="85" x2="65" y2="85" stroke="#2B3A55" stroke-width="2" stroke-dasharray="4 2"/><path d="M 25 60 Q 25 75, 40 80" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 Q 75 75, 60 80" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="22" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="50" y1="22" x2="50" y2="12" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="10" r="4" fill="#4D96FF" stroke="#2B3A55" stroke-width="2"/><ellipse cx="40" cy="40" rx="4" ry="2" fill="#2B3A55"/><ellipse cx="60" cy="40" rx="4" ry="2" fill="#2B3A55"/></svg><br/><strong>typing</strong></td>
47
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><path d="M 25 60 Q 15 70, 25 85" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 Q 85 50, 85 35" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="80" cy="32" r="5" fill="#B8D8FF" stroke="#2B3A55" stroke-width="3"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="20" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="50" y1="20" x2="50" y2="10" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="8" r="4" fill="#4ECB71" stroke="#2B3A55" stroke-width="2"/><circle cx="40" cy="36" r="4" fill="#2B3A55"/><path d="M 55 36 Q 60 31, 65 36" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/><path d="M 40 46 Q 50 52, 60 46" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/></svg><br/><strong>validation</strong></td>
48
+ <td align="center" width="25%"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="80" height="80"><defs><linearGradient id="roboGrad" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#E2F0FF" /><stop offset="100%" stop-color="#B8D8FF" /></linearGradient></defs><path d="M 25 60 Q 15 70, 25 85" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 75 60 Q 85 55, 85 45" fill="none" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><path d="M 85 45 C 80 45, 78 40, 80 35 C 82 30, 88 30, 90 35 C 92 40, 95 40, 95 48 C 95 52, 90 55, 85 52" fill="#E2F0FF" stroke="#2B3A55" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><rect x="35" y="55" width="30" height="30" rx="8" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><rect x="25" y="20" width="50" height="35" rx="12" fill="url(#roboGrad)" stroke="#2B3A55" stroke-width="4"/><line x1="50" y1="20" x2="50" y2="10" stroke="#2B3A55" stroke-width="4" stroke-linecap="round"/><circle cx="50" cy="8" r="4" fill="#4ECB71" stroke="#2B3A55" stroke-width="2"/><path d="M 35 36 Q 40 42, 45 36" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/><path d="M 55 36 Q 60 42, 65 36" fill="none" stroke="#2B3A55" stroke-width="3" stroke-linecap="round"/></svg><br/><strong>validation2</strong></td>
49
+ </tr>
50
+ </table>
51
+
52
+ [**See them animated in the playground →**](https://robot-toast-client.vercel.app/features)
53
+
54
+ ## 🎨 Features in Action
55
+
56
+ <table>
57
+ <tr>
58
+ <td align="center" width="50%">
59
+ <img src="https://raw.githubusercontent.com/Pratham2703005/robot-toast/refs/heads/main/public/offiicial-page/ad.png" alt="Light Mode" width="100%">
60
+ </td>
61
+ <td align="center" width="50%">
62
+ <img src="https://raw.githubusercontent.com/Pratham2703005/robot-toast/refs/heads/main/public/offiicial-page/darkmode.png" alt="Dark Mode" width="100%">
63
+ </td>
64
+ </tr>
65
+ <tr>
66
+ <td align="center" width="50%">
67
+ <img src="https://raw.githubusercontent.com/Pratham2703005/robot-toast/refs/heads/main/public/offiicial-page/lightmode.png" alt="Light Mode" width="100%">
68
+ </td>
69
+ <td align="center" width="50%">
70
+ <img src="https://raw.githubusercontent.com/Pratham2703005/robot-toast/refs/heads/main/public/offiicial-page/custom.png" alt="Custom Styling" width="100%">
71
+ </td>
72
+ </tr>
73
+ <tr>
74
+ <td align="center" colspan="2">
75
+ <img src="https://raw.githubusercontent.com/Pratham2703005/robot-toast/refs/heads/main/public/offiicial-page/questions_and_new_styles.png" alt="Styles & Questions" width="100%">
76
+ </td>
77
+ </tr>
78
+ </table>
79
+
80
+ ## Install
79
81
 
80
82
  ```bash
81
83
  npm install robot-toast
@@ -84,347 +86,193 @@ npm install robot-toast
84
86
  ## Quick Start
85
87
 
86
88
  ```ts
87
- import { toast } from 'robot-toast';
89
+ import { toast } from "robot-toast";
90
+ import { wave } from "robot-toast/robots";
88
91
 
89
- // Simple string no robot by default in v2
90
- toast('Hello 🤖');
91
-
92
- // With options
93
- toast({
94
- message: 'Operation successful!',
95
- type: 'success',
96
- theme: 'dark',
97
- position: 'top-right',
98
- });
92
+ toast({ message: "Hello! 🤖", robotVariant: wave });
93
+ toast.success("Operation successful!");
94
+ toast.error("Something went wrong");
99
95
  ```
100
96
 
101
- ### Add a robot
97
+ ## Features at a Glance
102
98
 
103
- Robots are opt-in. Import the one you want from the `robot-toast/robots` subpath — bundlers only include what you import:
99
+ | Robots | Layout | Styling | Behavior |
100
+ | ----------------------- | ------------------ | --------------------- | --------------------- |
101
+ | 16 built-in variants | 6 position options | 3 themes | Fully draggable |
102
+ | Tree-shakeable imports | Auto-queuing | Custom inline styles | Typewriter effect |
103
+ | Custom images (SVG/PNG) | Progress bar | Transitions (4 types) | Promise helpers |
104
+ | Custom image paths | Multi-toast queue | CSS overrides | React hook included |
104
105
 
105
- ```ts
106
- import { toast } from 'robot-toast';
107
- import { wave, success, error } from 'robot-toast/robots';
106
+ ---
108
107
 
109
- toast({ message: 'Hi!', robotVariant: wave });
110
- toast({ message: 'Saved!', robotVariant: success, type: 'success' });
111
- toast({ message: 'Failed', robotVariant: error, type: 'error' });
112
- ```
108
+ ## Usage
113
109
 
114
- Prefer the built-in inline SVG with no extra import?
110
+ ### Basic Usage
115
111
 
116
112
  ```ts
117
- toast({ message: 'Hello', robotVariant: 'default' });
118
- ```
113
+ import { toast } from "robot-toast";
114
+ import { wave, success, error } from "robot-toast/robots";
119
115
 
120
- ## Inline buttons
116
+ toast("Simple notification");
117
+ toast({ message: "With options", type: "success", robotVariant: wave });
118
+ toast.success("Shorthand");
119
+ ```
121
120
 
122
- Add inline buttons for patterns like Undo, Retry, or Confirm / Cancel. They render in array order — the caller controls the visual hierarchy:
121
+ ### All Options
123
122
 
124
123
  ```ts
125
- // Undo pattern — one button
126
- toast({
127
- message: 'File deleted',
128
- buttons: [
129
- { label: 'Undo', onClick: () => restoreFile() },
130
- ],
131
- });
132
-
133
- // Confirm + cancel — cancel on the left, primary CTA on the right
134
124
  toast({
135
- message: 'Send this email to 1,200 people?',
136
- buttons: [
137
- { label: 'Cancel', onClick: () => abort() },
138
- { label: 'Send', onClick: () => send(), className: 'my-primary' },
139
- ],
125
+ // Content
126
+ message: 'Notification text',
127
+
128
+ // Appearance
129
+ type: 'default' | 'info' | 'success' | 'warning' | 'error',
130
+ theme: 'light' | 'dark' | 'colored',
131
+ transition: 'bounce' | 'flip' | 'zoom' | 'slide',
132
+ position: 'top-left' | 'top-center' | 'top-right' |
133
+ 'bottom-left' | 'bottom-center' | 'bottom-right',
134
+
135
+ // Robot & Styling
136
+ robotVariant: wave | base | success | error | '...' | 'default' | '/path.svg',
137
+ nearScreen: true,
138
+ style: { background: '...', color: '...' },
139
+
140
+ // Timing & Behavior
141
+ autoClose: 5000 | false,
142
+ typeSpeed: 30,
143
+ hideProgressBar: false,
144
+ draggable: true,
145
+ pauseOnHover: true,
146
+ pauseOnFocusLoss: true,
147
+ rtl: false,
148
+
149
+ // Multi-toast
150
+ limit: 0,
151
+ newestOnTop: false,
152
+
153
+ // Buttons & Callbacks
154
+ buttons: [{ label: 'Undo', onClick: () => {...} }],
155
+ onOpen: () => {...},
156
+ onClose: () => {...},
140
157
  });
141
158
  ```
142
159
 
143
- Clicking any button fires its `onClick` and then closes the toast automatically. A callback that throws is logged and the toast still closes, so a bad handler can't strand the toast on screen.
160
+ ### Inline Buttons
144
161
 
145
- All buttons get a neutral outline style by default. Two ways to customize:
146
-
147
- - **`className`** — appends one or more class names to the button. Use when you have a stylesheet rule already defined (e.g. `.my-primary { background: black; color: white }`) or when using a utility framework like Tailwind.
148
- - **`style`** — inline CSS as a key/value object. Use for one-off styling without touching your stylesheet:
162
+ Add undo/confirm/cancel style buttons to toasts:
149
163
 
150
164
  ```ts
151
165
  toast({
152
- message: 'Send this email to 1,200 people?',
166
+ message: "File deleted",
153
167
  buttons: [
154
- { label: 'Cancel', onClick: () => abort() },
155
- {
156
- label: 'Send',
157
- onClick: () => send(),
158
- style: { background: 'black', color: 'white' },
159
- },
168
+ { label: "Undo", onClick: () => restoreFile() },
169
+ { label: "Keep", onClick: () => {}, style: { color: "gray" } },
160
170
  ],
161
171
  });
162
172
  ```
163
173
 
164
- Inline `style` takes precedence over both `className`-driven rules and the default solo-CTA / outline styles. Kebab-case keys (`'border-radius'`) and camelCase keys (`borderRadius`) both work.
174
+ ### Promise Lifecycle
165
175
 
166
- ## Promise lifecycle
176
+ Attach loading/success/error messages to any promise:
167
177
 
168
178
  ```ts
169
- toast.promise(fetch('/api/save').then(r => r.json()), {
170
- loading: 'Saving…',
171
- success: (data) => `Saved as ${data.name}`,
172
- error: (err) => `Failed: ${err.message}`,
173
- });
179
+ toast.promise(
180
+ fetch("/api/save").then((r) => r.json()),
181
+ {
182
+ loading: "Saving…",
183
+ success: (data) => `Saved as ${data.name}`,
184
+ error: (err) => `Failed: ${err.message}`,
185
+ },
186
+ );
174
187
  ```
175
188
 
176
- The `success` and `error` fields accept a string, a function of the resolved/rejected value, or a partial options object. The original promise's resolution value passes through unchanged — `await toast.promise(...)` still gives you the data.
177
-
178
- ## React bindings
189
+ ### React Bindings
179
190
 
180
191
  ```tsx
181
- import { useRobotToast, useToastOnMount } from 'robot-toast/react';
192
+ import { useRobotToast, useToastOnMount } from "robot-toast/react";
182
193
 
183
- function SaveButton() {
194
+ function App() {
184
195
  const toast = useRobotToast();
185
- return <button onClick={() => toast.success('Saved!')}>Save</button>;
196
+ return <button onClick={() => toast.success("Saved!")}>Save</button>;
186
197
  }
187
198
 
188
- function LoadingBanner() {
189
- // Fires on mount, auto-closes on unmount
190
- useToastOnMount({ message: 'Fetching…', autoClose: false });
199
+ function InitBanner() {
200
+ useToastOnMount({ message: "Welcome!", autoClose: false });
191
201
  return null;
192
202
  }
193
203
  ```
194
204
 
195
- React is an **optional** peer dependency — non-React users aren't affected.
196
-
197
- ## Close Programmatically
198
-
199
- ```ts
200
- // Close a specific toast by id
201
- const id = toast('Working…');
202
- toast.closeById(id);
203
-
204
- // Close all toasts at once
205
- toast.closeAll();
206
- ```
207
-
208
- ---
209
- ## All Options at a Glance
210
-
211
- A single `toast()` call using **every available option** so you can see the full API in one place:
212
-
213
- ```ts
214
- import { toast } from 'robot-toast';
215
- import { wave } from 'robot-toast/robots';
216
-
217
- toast({
218
- // ─── Content ───────────────────────────────────────────
219
- message: 'This is the full kitchen-sink example!',
220
-
221
- // ─── Appearance ────────────────────────────────────────
222
- type: 'success', // 'default' | 'info' | 'success' | 'warning' | 'error'
223
- theme: 'dark', // 'light' | 'dark' | 'colored'
224
- transition: 'bounce', // 'bounce' | 'flip' | 'zoom' | 'slide'
225
- position: 'bottom-right', // 'top-left' | 'top-center' | 'top-right'
226
- // 'bottom-left' | 'bottom-center' | 'bottom-right'
227
-
228
- // ─── Robot ─────────────────────────────────────────────
229
- // Omit (or '' / 'none') to hide. Use 'default' for the inline built-in SVG.
230
- // For a built-in variant, import from 'robot-toast/robots' and pass the value.
231
- // Custom image: pass any path with svg/png/jpg/jpeg/gif/webp extension.
232
- robotVariant: wave,
233
- nearScreen: true, // true = robot near screen edge, false = inner side
234
-
235
- // ─── Timing ────────────────────────────────────────────
236
- autoClose: 5000, // milliseconds, or false to disable auto-close
237
- typeSpeed: 30, // ms per character (0 = instant, no typing effect)
238
-
239
- // ─── Behaviour ─────────────────────────────────────────
240
- hideProgressBar: false, // true to hide the countdown bar
241
- draggable: true, // allow drag & drop; snaps to nearest edge on release
242
- pauseOnHover: true, // pause countdown on mouse hover
243
- pauseOnFocusLoss: true, // pause countdown when tab loses focus
244
- rtl: false, // right-to-left layout
245
-
246
- // ─── Multi-toast ───────────────────────────────────────
247
- limit: 0, // max visible toasts (0 = unlimited, excess is queued)
248
- newestOnTop: false, // stack new toasts above older ones
249
-
250
- // ─── Custom Inline Styles ─────────────────────────────
251
- style: {
252
- background: 'linear-gradient(135deg, #667eea, #764ba2)',
253
- color: '#fff',
254
- borderRadius: '16px',
255
- fontFamily: 'monospace',
256
- },
257
-
258
- // ─── Callbacks ─────────────────────────────────────────
259
- onOpen: () => console.log('Toast appeared!'),
260
- onClose: () => console.log('Toast dismissed!'),
261
- });
262
- ```
263
-
264
- ### Type Shorthands
265
-
266
- ```ts
267
- // These set the `type` automatically — you can also pass a full options object
268
- toast.success('Saved!');
269
- toast.error('Something went wrong');
270
- toast.info('Did you know…');
271
- toast.warning('Check your input');
272
-
273
- // With additional options
274
- import { success } from 'robot-toast/robots';
275
- toast.success({ message: 'Deployed!', theme: 'colored', position: 'top-center', robotVariant: success });
276
- ```
277
-
278
- ---
279
- ## Options
280
-
281
- | Option | Type | Default | Description |
282
- |---|---|---|---|
283
- | `message` | `string` | *required* | The text to display |
284
- | `autoClose` | `number \| false` | `5000` | Auto-close after ms. `false` = stays until dismissed |
285
- | `position` | `string` | `'bottom-right'` | One of the 6 position presets (see above) |
286
- | `type` | `string` | `'default'` | `default` · `info` · `success` · `warning` · `error` |
287
- | `theme` | `string` | `'light'` | `light` · `dark` · `colored` |
288
- | `transition` | `string` | `'bounce'` | `bounce` · `flip` · `zoom` · `slide` |
289
- | `style` | `Record<string, string \| number>` | — | Inline styles applied directly to the message bubble |
290
- | `typeSpeed` | `number` | `30` | Typing speed in ms per character. `0` = instant |
291
- | `robotVariant` | `string` | *hidden* | Data URL from `robot-toast/robots`, `'default'` for built-in SVG, image path, or omit for no robot |
292
- | `hideProgressBar` | `boolean` | `false` | Hide the countdown progress bar |
293
- | `draggable` | `boolean` | `true` | Allow the user to drag the toast; snaps to the nearest edge on release |
294
- | `nearScreen` | `boolean` | `true` | `true` = robot near screen edge; `false` = robot on the inner side |
295
- | `pauseOnHover` | `boolean` | `true` | Pause countdown while the cursor is over the toast |
296
- | `pauseOnFocusLoss` | `boolean` | `true` | Pause countdown when the browser tab loses focus |
297
- | `rtl` | `boolean` | `false` | Right-to-left layout |
298
- | `limit` | `number` | `0` | Max toasts visible at once. `0` = unlimited. Excess is queued |
299
- | `newestOnTop` | `boolean` | `false` | Stack newest toasts above older ones |
300
- | `buttons` | `Array<{ label: string; onClick: (e: MouseEvent) => void; className?: string; style?: Record<string, string \| number> }>` | — | Inline buttons rendered in array order. Each click fires `onClick` then closes the toast. Use `className` for stylesheet classes, `style` for inline CSS. |
301
- | `onOpen` | `() => void` | — | Callback fired when the toast finishes its entrance |
302
- | `onClose` | `() => void` | — | Callback fired after the toast fully exits |
303
-
304
- ---
305
-
306
- ## Built-in Robots
307
-
308
- All 16 robots are importable from `robot-toast/robots`. Each is a pre-encoded data URL — no network fetch, no external files, and bundlers drop the ones you don't use:
309
-
310
- ```ts
311
- import {
312
- wave, base, base2, success, error,
313
- angry, angry2, shock, think, search,
314
- loading, sleep, headPalm, typing,
315
- validation, validation2,
316
- } from 'robot-toast/robots';
317
- ```
205
+ ### Complete Example
318
206
 
319
- > v1 v2 renames: `head-palm` `headPalm`, `type` → `typing` (the dash isn't a valid identifier; `type` clashes with TypeScript's type-only import syntax).
207
+ Combine robots, buttons, theming, and promises in one powerful toast:
320
208
 
321
- For guaranteed per-variant tree-shaking, you can also import from the direct subpath:
322
-
323
- ```ts
324
- import { wave } from 'robot-toast/robots/wave';
325
- ```
326
-
327
- ### Custom Robot Image
209
+ ```tsx
210
+ import { useRobotToast } from "robot-toast/react";
211
+ import { success, error, loading } from "robot-toast/robots";
328
212
 
329
- Point to any image accessible in your app:
213
+ function CompleteExample() {
214
+ const toast = useRobotToast();
330
215
 
331
- ```ts
332
- toast({
333
- message: 'Custom bot!',
334
- robotVariant: '/images/my-robot.png',
335
- });
216
+ const handleUpload = () => {
217
+ toast.promise(
218
+ fetch("/api/upload").then((r) => r.json()),
219
+ {
220
+ loading: {
221
+ message: "Uploading your file...",
222
+ robotVariant: loading,
223
+ theme: "dark",
224
+ },
225
+ success: {
226
+ message: "File uploaded! Ready to go? 🎉",
227
+ robotVariant: success,
228
+ theme: "colored",
229
+ style: { background: "#10b981", color: "white" },
230
+ buttons: [
231
+ { label: "View", onClick: () => window.open("/files") },
232
+ { label: "Done", onClick: () => {} },
233
+ ],
234
+ },
235
+ error: {
236
+ message: "Upload failed. Try again?",
237
+ robotVariant: error,
238
+ theme: "dark",
239
+ style: { background: "#ef4444" },
240
+ buttons: [{ label: "Retry", onClick: handleUpload }],
241
+ },
242
+ },
243
+ );
244
+ };
245
+
246
+ return <button onClick={handleUpload}>Upload File</button>;
247
+ }
336
248
  ```
337
249
 
338
- Supported formats: **svg, png, jpg, jpeg, gif, webp**. Failed loads fall back to the built-in default SVG. Omit `robotVariant` (or pass `''` / `'none'`) to hide the robot entirely.
339
-
340
- ---
341
-
342
- ## Themes & Custom Styles
343
-
344
- ### Built-in Themes
250
+ ### Programmatic Control
345
251
 
346
252
  ```ts
347
- toast({ message: 'Light mode', theme: 'light' });
348
- toast({ message: 'Dark mode', theme: 'dark' });
349
- toast({ message: 'Colored', theme: 'colored', type: 'success' });
253
+ const id = toast("Working…");
254
+ toast.closeById(id);
255
+ toast.closeAll();
350
256
  ```
351
257
 
352
- ### Custom Inline Styles
353
-
354
- Use the `style` option to fully customize the message bubble:
258
+ ### Themes & Custom Styles
355
259
 
356
260
  ```ts
261
+ toast({ message: "Light", theme: "light" });
262
+ toast({ message: "Dark", theme: "dark" });
357
263
  toast({
358
- message: 'Fully custom look',
264
+ message: "Custom gradient",
359
265
  style: {
360
- background: 'linear-gradient(135deg, #667eea, #764ba2)',
361
- color: '#fff',
362
- borderRadius: '16px',
363
- fontFamily: 'monospace',
266
+ background: "linear-gradient(135deg, #667eea, #764ba2)",
267
+ color: "#fff",
268
+ borderRadius: "16px",
364
269
  },
365
270
  });
366
271
  ```
367
272
 
368
- ---
369
-
370
- ## Transitions
371
-
372
- ```ts
373
- toast({ message: 'Bounce!', transition: 'bounce' });
374
- toast({ message: 'Flip!', transition: 'flip' });
375
- toast({ message: 'Zoom!', transition: 'zoom' });
376
- toast({ message: 'Slide!', transition: 'slide' });
377
- ```
273
+ ### Accessibility
378
274
 
379
- ---
380
-
381
- ## Drag & responsive layout
382
-
383
- When `draggable` is on (default):
384
-
385
- - **Drag anywhere** on the toast to move it. On release it snaps to the nearest horizontal edge — including when you drag all the way across the screen.
386
- - `touch-action: none` prevents the browser from fighting the drag, and rect dimensions are cached on pointerdown to eliminate layout-thrash jank on low-end devices.
387
- - Use the **close button**, an **action button**, or `toast.closeById()` / `toast.closeAll()` to dismiss programmatically.
388
-
389
- **On viewports ≤ 600 px** the toast shrinks slightly (tighter gutters, smaller robot, smaller font) but keeps its configured position preset. Drag still works everywhere.
390
-
391
- ---
392
-
393
- ## Accessibility
394
-
395
- Every toast ships with the right ARIA hooks out of the box:
396
-
397
- - `error` and `warning` toasts get `role="alert"` + `aria-live="assertive"` — screen readers announce them immediately.
398
- - All other types get `role="status"` + `aria-live="polite"` — announced when the user is idle.
399
- - `aria-atomic="true"` ensures the full message is re-announced on updates.
400
- - The close button has `type="button"` + `aria-label="Dismiss notification"`.
401
-
402
- ---
403
-
404
- ## Framework Examples
405
-
406
- ### React / Next.js
407
-
408
- ```tsx
409
- 'use client';
410
- import { useRobotToast } from 'robot-toast/react';
411
- import { wave } from 'robot-toast/robots';
412
- import { useEffect } from 'react';
413
-
414
- export default function App() {
415
- const toast = useRobotToast();
416
-
417
- useEffect(() => {
418
- toast({
419
- message: 'Welcome!',
420
- type: 'success',
421
- theme: 'dark',
422
- position: 'top-right',
423
- robotVariant: wave,
424
- transition: 'bounce',
425
- });
426
- }, [toast]);
427
-
428
- return <div>My App</div>;
429
- }
430
- ```
275
+ - `error` / `warning` toasts: `role="alert"` + `aria-live="assertive"`
276
+ - Other types: `role="status"` + `aria-live="polite"`
277
+ - `aria-atomic="true"` ensures full message re-announcement
278
+ - Labeled close button for screen readers
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "robot-toast",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "A lightweight, framework-agnostic toast notification library with an animated robot character. Tree-shakeable robots, draggable with swipe-to-dismiss, toast.promise(), and an optional React hook.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",