lumatoast 0.1.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/LICENSE ADDED
File without changes
package/README.md ADDED
@@ -0,0 +1,522 @@
1
+ # LumaToast
2
+
3
+ A beautiful, lightweight, framework-agnostic toast notification library — inspired by Linear, Vercel, and Apple VisionOS.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/lumatoast)](https://www.npmjs.com/package/lumatoast)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Features
9
+
10
+ - âœĻ **Glassmorphism UI** — VisionOS-inspired frosted glass design
11
+ - ðŸŽĻ **9 built-in themes** — linear, aurora, vision, minimal, cupertino, material, terminal, github, cyberpunk
12
+ - ⚡ **Promise API** — show loading → auto-transition to success or error
13
+ - ðŸ“ą **Mobile gestures** — swipe to dismiss, direction-aware
14
+ - 🌙 **Dark & Light mode** — themes support both
15
+ - âŒĻïļ **Keyboard accessible** — Escape to dismiss, full focus management
16
+ - â™ŋ **ARIA compliant** — live regions, roles, labels
17
+ - ðŸ“Ķ **Framework agnostic** — works with Vanilla JS, React, Vue, Angular, Svelte
18
+ - ðŸŠķ **Zero dependencies** — pure TypeScript, no external runtime deps
19
+
20
+ ---
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install lumatoast
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Quick Start
31
+
32
+ ### 1. Import the CSS
33
+
34
+ ```js
35
+ import "lumatoast/styles.css";
36
+ ```
37
+
38
+ > Add this once at your app entry point (e.g. `main.ts`, `App.tsx`).
39
+
40
+ ### 2. Initialize the renderer
41
+
42
+ ```js
43
+ import { initializeRenderer, toast } from "lumatoast";
44
+
45
+ initializeRenderer();
46
+ ```
47
+
48
+ ### 3. Show toasts
49
+
50
+ ```js
51
+ toast.success("Profile updated!");
52
+ toast.error("Something went wrong.");
53
+ toast.warning("Disk space is low.");
54
+ toast.info("New version available.");
55
+ ```
56
+
57
+ ---
58
+
59
+ ## API Reference
60
+
61
+ ### `toast.success(message, options?)`
62
+ ### `toast.error(message, options?)`
63
+ ### `toast.warning(message, options?)`
64
+ ### `toast.info(message, options?)`
65
+ ### `toast.loading(message, options?)`
66
+ ### `toast.custom(message, options?)`
67
+
68
+ Show a toast. All methods return the `ToastItem` (with its `id`).
69
+
70
+ ```ts
71
+ toast.success("Saved!", {
72
+ title: "Success",
73
+ duration: 5000,
74
+ position: "bottom-right",
75
+ theme: "minimal",
76
+ dismissible: true,
77
+ action: {
78
+ label: "Undo",
79
+ onClick: () => console.log("Undo!")
80
+ }
81
+ });
82
+ ```
83
+
84
+ > `toast.loading()` sets `duration: Infinity` and `dismissible: false` automatically.
85
+
86
+ ---
87
+
88
+ ### `toast.promise(promise, options)`
89
+
90
+ Track a promise — shows a loading toast, then auto-transitions to success or error.
91
+
92
+ ```ts
93
+ toast.promise(fetch("/api/save"), {
94
+ loading: { description: "Saving your work..." },
95
+ success: { title: "Saved!", description: "Changes saved successfully." },
96
+ error: { title: "Error", description: "Failed to save changes." }
97
+ });
98
+ ```
99
+
100
+ ---
101
+
102
+ ### `toast.update(id, updates)`
103
+
104
+ Update an existing toast in-place. Useful for manual loading → success transitions.
105
+
106
+ ```ts
107
+ const loading = toast.loading("Uploading...");
108
+
109
+ setTimeout(() => {
110
+ toast.update(loading.id, {
111
+ type: "success",
112
+ description: "Upload complete!",
113
+ duration: 3000,
114
+ dismissible: true
115
+ });
116
+ }, 2000);
117
+ ```
118
+
119
+ ---
120
+
121
+ ### `toast.dismiss(id)`
122
+ ### `toast.dismissAll()`
123
+ ### `toast.dismissLatest()`
124
+
125
+ Programmatically remove toasts. Pressing `Escape` also calls `dismissLatest()`.
126
+
127
+ ---
128
+
129
+ ### `toast.subscribe(listener)`
130
+
131
+ React to toast state changes. Returns an unsubscribe function.
132
+
133
+ ```ts
134
+ const unsub = toast.subscribe((toasts) => {
135
+ console.log("Active toasts:", toasts);
136
+ });
137
+
138
+ // Stop listening:
139
+ unsub();
140
+ ```
141
+
142
+ ---
143
+
144
+ ### `toast.configure(config)`
145
+
146
+ Set global defaults so you don't have to repeat options on every call.
147
+
148
+ ```ts
149
+ toast.configure({
150
+ position: "bottom-right",
151
+ theme: "minimal",
152
+ duration: 3000,
153
+ dismissible: true,
154
+ maxVisible: 3
155
+ });
156
+ ```
157
+
158
+ Per-toast options always override global defaults.
159
+
160
+ ---
161
+
162
+ ## Options
163
+
164
+ | Option | Type | Default | Description |
165
+ |---|---|---|---|
166
+ | `id` | `string` | auto-generated | Stable id for the toast |
167
+ | `title` | `string` | — | Bold title text |
168
+ | `description` | `string` | — | Body text |
169
+ | `duration` | `number` | `4000` | Auto-dismiss delay in ms. `Infinity` = never |
170
+ | `dismissible` | `boolean` | `true` | Show the × close button |
171
+ | `position` | `ToastPosition` | `"top-right"` | Where the toast appears |
172
+ | `theme` | `ToastTheme` | `"linear"` | Visual theme |
173
+ | `action` | `ToastAction` | — | Action button with label and onClick |
174
+
175
+ ### Positions
176
+
177
+ `top-left` · `top-center` · `top-right` · `bottom-left` · `bottom-center` · `bottom-right`
178
+
179
+ ### Themes
180
+
181
+ `linear` · `aurora` · `vision` · `minimal` · `cupertino` · `material` · `terminal` · `github` · `cyberpunk`
182
+
183
+ ---
184
+
185
+ ## Customization
186
+
187
+ LumaToast uses a two-layer system:
188
+
189
+ | Layer | What it controls | How |
190
+ |---|---|---|
191
+ | **CSS custom properties** | Colors, typography, sizes, shadows | Override `--luma-*` variables in your CSS |
192
+ | **JS options** | Layout and structural changes | Options in `configure()` or per-toast |
193
+
194
+ ---
195
+
196
+ ### CSS Custom Properties
197
+
198
+ Override any variable globally on `:root`, or per-theme:
199
+
200
+ ```css
201
+ /* Global overrides */
202
+ :root {
203
+ --luma-font: "Inter", sans-serif;
204
+ --luma-radius: 24px;
205
+ --luma-width: 380px;
206
+ --luma-title-size: 16px;
207
+ --luma-title-weight: 700;
208
+ }
209
+
210
+ /* Override only in the linear theme */
211
+ .luma-theme-linear {
212
+ --luma-bg: rgba(0, 0, 0, 0.85);
213
+ --luma-border-color: rgba(255, 255, 255, .15);
214
+ }
215
+ ```
216
+
217
+ #### Full Variable Reference
218
+
219
+ **Card Layout**
220
+
221
+ | Variable | Default | Description |
222
+ |---|---|---|
223
+ | `--luma-width` | `340px` | Card width |
224
+ | `--luma-radius` | `18px` | Border radius |
225
+ | `--luma-padding` | `14px 16px 18px` | Card padding |
226
+ | `--luma-gap` | `12px` | Gap between icon, content, close button |
227
+
228
+ **Background & Border**
229
+
230
+ | Variable | Default | Description |
231
+ |---|---|---|
232
+ | `--luma-bg` | theme-defined | Card background (supports gradients) |
233
+ | `--luma-border-color` | theme-defined | Border color |
234
+ | `--luma-border-width` | `1px` | Border width |
235
+ | `--luma-shadow` | theme-defined | Box shadow |
236
+ | `--luma-backdrop` | theme-defined | `backdrop-filter` value |
237
+
238
+ **Typography**
239
+
240
+ | Variable | Default | Description |
241
+ |---|---|---|
242
+ | `--luma-font` | `inherit` | Font family |
243
+ | `--luma-title-size` | `15px` | Title font size |
244
+ | `--luma-title-weight` | `600` | Title font weight |
245
+ | `--luma-title-color` | `#ffffff` | Title color |
246
+ | `--luma-desc-size` | `14px` | Description font size |
247
+ | `--luma-desc-color` | `rgba(255,255,255,.72)` | Description color |
248
+ | `--luma-line-height` | `1.5` | Line height |
249
+ | `--luma-letter-spacing` | `normal` | Letter spacing |
250
+
251
+ **Progress Bar**
252
+
253
+ | Variable | Default | Description |
254
+ |---|---|---|
255
+ | `--luma-progress-height` | `3px` | Bar thickness |
256
+ | `--luma-progress-radius` | `0px` | Bar border radius |
257
+ | `--luma-progress-success` | green gradient | Color for success toasts |
258
+ | `--luma-progress-error` | red gradient | Color for error toasts |
259
+ | `--luma-progress-warning` | amber gradient | Color for warning toasts |
260
+ | `--luma-progress-info` | blue gradient | Color for info toasts |
261
+ | `--luma-progress-loading` | gray gradient | Color for loading toasts |
262
+ | `--luma-progress-custom` | purple gradient | Color for custom toasts |
263
+
264
+ **Action Button**
265
+
266
+ | Variable | Default | Description |
267
+ |---|---|---|
268
+ | `--luma-action-bg` | `rgba(255,255,255,.08)` | Button background (solid variant) |
269
+ | `--luma-action-color` | `#ffffff` | Button text color |
270
+ | `--luma-action-hover-bg` | `rgba(255,255,255,.16)` | Hover background |
271
+ | `--luma-action-radius` | `10px` | Button border radius |
272
+ | `--luma-action-padding` | `8px 12px` | Button padding |
273
+ | `--luma-action-size` | `14px` | Font size |
274
+ | `--luma-action-weight` | `500` | Font weight |
275
+ | `--luma-action-border` | `none` | Border (outline/ghost variants) |
276
+
277
+ **Animation Durations** (set automatically by `animationSpeed`)
278
+
279
+ | Variable | Default | Description |
280
+ |---|---|---|
281
+ | `--luma-duration-enter` | `320ms` | Enter animation duration |
282
+ | `--luma-duration-exit` | `300ms` | Exit animation duration |
283
+ | `--luma-duration-stack` | `280ms` | Stack reorder duration |
284
+
285
+ ---
286
+
287
+ ### Animation Options
288
+
289
+ ```ts
290
+ toast.configure({
291
+ animationEnter: "slide", // "slide" | "fade" | "scale" | "bounce" | "none"
292
+ animationExit: "slide", // "slide" | "fade" | "none"
293
+ animationSpeed: "normal", // "slow" | "normal" | "fast" (global speed preset)
294
+ });
295
+
296
+ // Or per-toast:
297
+ toast.success("Bouncy!", { animationEnter: "bounce", animationExit: "fade" });
298
+ ```
299
+
300
+ | `animationEnter` | Effect |
301
+ |---|---|
302
+ | `slide` (default) | Slides down + fades in |
303
+ | `fade` | Fades in only |
304
+ | `scale` | Scales up from center |
305
+ | `bounce` | Spring overshoot |
306
+ | `none` | Instant appearance |
307
+
308
+ | `animationExit` | Effect |
309
+ |---|---|
310
+ | `slide` (default) | Slides right + fades out |
311
+ | `fade` | Fades out + collapses |
312
+ | `none` | Instant removal |
313
+
314
+ ---
315
+
316
+ ### Action Button Variants
317
+
318
+ ```ts
319
+ toast.success("Archived.", {
320
+ action: {
321
+ label: "Undo",
322
+ onClick: () => {},
323
+ variant: "outline", // "solid" | "outline" | "ghost"
324
+ }
325
+ });
326
+ ```
327
+
328
+ | Variant | Appearance |
329
+ |---|---|
330
+ | `solid` (default) | Filled background |
331
+ | `outline` | Transparent + border |
332
+ | `ghost` | Text only, no background or border |
333
+
334
+ ---
335
+
336
+ ### Progress Bar Placement
337
+
338
+ ```ts
339
+ // Move progress bar to top of the card
340
+ toast.success("Saving...", { progressPosition: "top", duration: 5000 });
341
+
342
+ // Or globally:
343
+ toast.configure({ progressPosition: "top" });
344
+ ```
345
+
346
+ ---
347
+
348
+ ### Show/Hide Icon
349
+
350
+ ```ts
351
+ toast.info("No icon here", { showIcon: false });
352
+
353
+ // Globally:
354
+ toast.configure({ showIcon: false });
355
+ ```
356
+
357
+ ---
358
+
359
+ ### Click-to-Dismiss
360
+
361
+ ```ts
362
+ // Dismiss when the user clicks anywhere on the card body
363
+ toast.success("Click me to dismiss", { closeOnClick: true });
364
+
365
+ // Globally:
366
+ toast.configure({ closeOnClick: true });
367
+ ```
368
+
369
+ ---
370
+
371
+ ### Inline Style Overrides
372
+
373
+ Apply inline styles directly to the card — supports both regular CSS properties and CSS custom properties:
374
+
375
+ ```ts
376
+ toast.success("Custom!", {
377
+ style: {
378
+ "--luma-bg": "linear-gradient(135deg, #1a1a2e, #16213e)",
379
+ "--luma-radius": "24px",
380
+ "--luma-shadow": "0 0 30px rgba(138,43,226,.4)",
381
+ }
382
+ });
383
+ ```
384
+
385
+ ---
386
+
387
+ ### Extra CSS Classes
388
+
389
+ Add your own CSS class to the toast wrapper for full control:
390
+
391
+ ```ts
392
+ toast.success("Custom class", { className: "my-brand-toast" });
393
+ ```
394
+
395
+ ```css
396
+ .my-brand-toast .luma-toast-card {
397
+ background: var(--brand-surface);
398
+ border: 2px solid var(--brand-primary);
399
+ }
400
+ ```
401
+
402
+ ---
403
+
404
+ ### Building a Custom Theme
405
+
406
+ Create a CSS file that sets `--luma-*` variables on your theme class:
407
+
408
+ ```css
409
+ /* my-theme.css */
410
+ .luma-theme-brand {
411
+ --luma-bg: #1a1a2e;
412
+ --luma-border-color: #e040fb;
413
+ --luma-border-width: 2px;
414
+ --luma-radius: 20px;
415
+ --luma-shadow: 0 0 24px rgba(224, 64, 251, .3);
416
+ --luma-title-color: #CE93D8;
417
+ --luma-desc-color: #9C27B0;
418
+ --luma-font: "Poppins", sans-serif;
419
+ --luma-progress-success: linear-gradient(90deg, #e040fb, #7c4dff);
420
+ --luma-action-bg: rgba(224, 64, 251, .12);
421
+ --luma-action-color: #e040fb;
422
+ }
423
+ ```
424
+
425
+ Then use it:
426
+
427
+ ```ts
428
+ // Extend the type if using TypeScript:
429
+ // declare module "lumatoast" {
430
+ // interface ToastTheme extends Record<"brand", unknown> {}
431
+ // }
432
+
433
+ toast.success("Custom theme!", { theme: "brand" as any });
434
+ ```
435
+
436
+ ---
437
+
438
+ ## Framework Guides
439
+
440
+
441
+ ### React
442
+
443
+ ```tsx
444
+ // main.tsx
445
+ import "lumatoast/styles.css";
446
+ import { initializeRenderer } from "lumatoast";
447
+
448
+ initializeRenderer();
449
+ ```
450
+
451
+ ```tsx
452
+ // In any component:
453
+ import { toast } from "lumatoast";
454
+
455
+ function SaveButton() {
456
+ const handleClick = async () => {
457
+ await toast.promise(saveData(), {
458
+ loading: { description: "Saving..." },
459
+ success: { description: "Saved!" },
460
+ error: { description: "Error saving." }
461
+ });
462
+ };
463
+
464
+ return <button onClick={handleClick}>Save</button>;
465
+ }
466
+ ```
467
+
468
+ ### Vue
469
+
470
+ ```ts
471
+ // main.ts
472
+ import "lumatoast/styles.css";
473
+ import { initializeRenderer } from "lumatoast";
474
+
475
+ initializeRenderer();
476
+ createApp(App).mount("#app");
477
+ ```
478
+
479
+ ```vue
480
+ <script setup>
481
+ import { toast } from "lumatoast";
482
+ const notify = () => toast.success("Hello from Vue!");
483
+ </script>
484
+ ```
485
+
486
+ ### Angular
487
+
488
+ ```ts
489
+ // main.ts
490
+ import "lumatoast/styles.css";
491
+ import { initializeRenderer } from "lumatoast";
492
+
493
+ initializeRenderer();
494
+ bootstrapApplication(AppComponent, appConfig);
495
+ ```
496
+
497
+ ### Vanilla JS
498
+
499
+ ```html
500
+ <link rel="stylesheet" href="node_modules/lumatoast/dist/styles.css" />
501
+ <script type="module">
502
+ import { initializeRenderer, toast } from "lumatoast";
503
+ initializeRenderer();
504
+ document.querySelector("#btn").onclick = () => toast.success("Hello!");
505
+ </script>
506
+ ```
507
+
508
+ ---
509
+
510
+ ## Keyboard Support
511
+
512
+ | Key | Action |
513
+ |---|---|
514
+ | `Escape` | Dismiss the most recent toast |
515
+ | `Tab` | Focus the action / close button |
516
+ | `Enter` / `Space` | Activate focused button |
517
+
518
+ ---
519
+
520
+ ## License
521
+
522
+ MIT ÂĐ [Krishna Kumar](https://github.com/mekrishnaa)