feather-toast-vue 1.0.12 → 2.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 CHANGED
@@ -1,277 +1,543 @@
1
- # Feather Toast Vue
2
-
3
- A lightweight Vue 3 toast notification plugin. Minimal by design, with smooth animations and a clean API that stays out of your way.
4
-
5
- ---
6
-
7
- ## Features
8
-
9
- | Feature | Description |
10
- |---------|-------------|
11
- | 6 Variants | `default` · `success` · `error` · `warning` · `info` · `loading` |
12
- | 6 Positions | `top-right` · `top-left` · `top-center` · `bottom-right` · `bottom-left` · `bottom-center` |
13
- | Smooth Animations | Spring-based slide + fade + scale with `cubic-bezier(0.16, 1, 0.3, 1)` |
14
- | Swipe to Dismiss | Horizontal swipe gesture with snap-back |
15
- | Hover Pause | Auto-dismiss timer pauses accurately on hover |
16
- | Promise API | `toast.promise()` — loading → success / error |
17
- | Action Button | Optional inline action on any toast |
18
- | Vue Plugin | One-line install with `app.use(ToastPlugin)` |
19
- | Zero Dependencies | Only Vue 3 — no Tailwind, no UI library |
20
- | TypeScript | Fully typed API |
21
- | Accessible | `aria-live`, `role="alert"`, `prefers-reduced-motion` support |
22
-
23
- ---
24
-
25
- ## Installation
26
-
27
- ```bash
28
- npm install feather-toast-vue
29
- ```
30
-
31
- ### Setup
32
-
33
- ```ts
34
- // main.ts
35
- import { createApp } from 'vue'
36
- import App from './App.vue'
37
- import { CreateFeatherToast } from 'feather-toast-vue'
38
-
39
- const app = createApp(App)
40
- app.use(CreateFeatherToast)
41
- app.mount('#app')
42
- ```
43
-
44
- `ToastContainer` and styles are mounted automatically by the plugin.
45
-
46
- ---
47
-
48
- ## Usage
49
-
50
- ### Basic
51
-
52
- ```ts
53
- import { useFeatherToast } from 'feather-toast-vue'
54
-
55
- const { toast } = useFeatherToast()
56
-
57
- toast({
58
- title: 'Event Created',
59
- description: 'Your event has been scheduled.',
60
- })
61
- ```
62
-
63
- ### Variants
64
-
65
- ```ts
66
- toast.success({ title: 'Saved', description: 'Changes applied.' })
67
- toast.error({ title: 'Error', description: 'Something went wrong.' })
68
- toast.warning({ title: 'Warning', description: 'Disk space is low.' })
69
- toast.info({ title: 'Info', description: 'Version 2.4 is available.' })
70
- toast.loading({ title: 'Uploading...', description: 'Please wait.' })
71
- ```
72
-
73
- ### Custom Position
74
-
75
- ```ts
76
- toast.success({
77
- title: 'Saved',
78
- position: 'top-center', // default: 'bottom-right'
79
- })
80
- ```
81
-
82
- ### Promise API
83
-
84
- Automatically transitions `loading → success` or `loading → error`:
85
-
86
- ```ts
87
- toast.promise(
88
- fetch('/api/projects', { method: 'POST' }),
89
- {
90
- loading: {
91
- title: 'Creating project...',
92
- description: 'Setting up your workspace.',
93
- },
94
- success: (data) => ({
95
- title: `"${data.name}" created`,
96
- description: 'Your project is ready.',
97
- }),
98
- error: (err) => ({
99
- title: 'Failed to create project',
100
- description: err instanceof Error ? err.message : 'Unknown error.',
101
- }),
102
- }
103
- )
104
- ```
105
-
106
- ### Action Button
107
-
108
- ```ts
109
- toast({
110
- title: 'Message archived',
111
- description: 'Moved to archive.',
112
- action: {
113
- label: 'Undo',
114
- onClick: () => {
115
- toast.success({ title: 'Restored', description: 'Message moved back to inbox.' })
116
- },
117
- },
118
- })
119
- ```
120
-
121
- ### Dismiss
122
-
123
- ```ts
124
- // Dismiss by ID
125
- const id = toast.loading({ title: 'Working...' })
126
- toast.dismiss(id)
127
-
128
- // Dismiss all
129
- toast.dismissAll()
130
- ```
131
-
132
- ---
133
-
134
- ## API Reference
135
-
136
- ### `useToast()`
137
-
138
- ```ts
139
- const { toast, toasts, dismiss, dismissAll } = useToast()
140
- ```
141
-
142
- | Property | Type | Description |
143
- |----------|------|-------------|
144
- | `toast(options)` | `(options: ToastOptions) => string` | Show a default toast, returns its ID |
145
- | `toast.success(options)` | `Function` | Success variant |
146
- | `toast.error(options)` | `Function` | Error variant |
147
- | `toast.warning(options)` | `Function` | Warning variant |
148
- | `toast.info(options)` | `Function` | Info variant |
149
- | `toast.loading(options)` | `Function` | Loading variant — no auto-dismiss |
150
- | `toast.promise(promise, opts)` | `Function` | Promise-based toast flow |
151
- | `toast.dismiss(id)` | `Function` | Dismiss a specific toast by ID |
152
- | `toast.dismissAll()` | `Function` | Dismiss all active toasts |
153
- | `toasts` | `Ref<Toast[]>` | Reactive list of all active toasts |
154
-
155
- ---
156
-
157
- ### `ToastOptions`
158
-
159
- ```ts
160
- interface ToastOptions {
161
- title?: string
162
- description?: string
163
- variant?: 'default' | 'success' | 'error' | 'warning' | 'info' | 'loading'
164
- position?: 'top-right' | 'top-left' | 'top-center'
165
- | 'bottom-right' | 'bottom-left' | 'bottom-center'
166
- duration?: number // ms · default: 5000 · loading: Infinity
167
- dismissible?: boolean // default: true (false for loading)
168
- action?: {
169
- label: string
170
- onClick: () => void
171
- }
172
- }
173
- ```
174
-
175
- ---
176
-
177
- ### Positions
178
-
179
- ```
180
- +----------+------------+-----------+
181
- | top-left | top-center | top-right |
182
- | | | |
183
- | | | |
184
- | bot-left | bot-center | bot-right |
185
- +----------+------------+-----------+
186
- ```
187
-
188
- ---
189
-
190
- ## Design System
191
-
192
- ### Color Tokens
193
-
194
- | Token | Value | Usage |
195
- |-------|-------|-------|
196
- | `--toast-bg` | `#ffffff` | Card background |
197
- | `--toast-border` | `#e4e4e7` | Card border |
198
- | `--toast-text` | `#18181b` | Title text |
199
- | `--toast-text-muted` | `#71717a` | Description text |
200
- | `--toast-shadow` | `0 2px 8px rgba(0,0,0,0.06)` | Card elevation |
201
- | `--toast-radius` | `10px` | Card border radius |
202
- | `--toast-width` | `360px` | Card width |
203
-
204
- ### Icon Accent Colors
205
-
206
- | Variant | Hex |
207
- |---------|-----|
208
- | Success | `#16a34a` |
209
- | Error | `#dc2626` |
210
- | Warning | `#d97706` |
211
- | Info | `#2563eb` |
212
- | Loading | `#71717a` |
213
-
214
- ### Customization via CSS Variables
215
-
216
- ```css
217
- /* Override in your global CSS */
218
- :root {
219
- --toast-bg: #ffffff;
220
- --toast-border: #e4e4e7;
221
- --toast-text: #18181b;
222
- --toast-text-muted: #71717a;
223
- --toast-radius: 10px;
224
- --toast-width: 360px;
225
- --toast-gap: 8px;
226
- --toast-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
227
- }
228
- ```
229
-
230
- ---
231
-
232
- ## Animation Spec
233
-
234
- | Phase | Duration | Easing |
235
- |-------|----------|--------|
236
- | Enter | 400ms | `cubic-bezier(0.16, 1, 0.3, 1)` — spring |
237
- | Exit | 220ms | `cubic-bezier(0.4, 0, 1, 1)` — snappy |
238
- | Sibling reflow | 350ms | `cubic-bezier(0.16, 1, 0.3, 1)` — spring |
239
- | Swipe snap-back | 360ms | `cubic-bezier(0.16, 1, 0.3, 1)` — spring |
240
-
241
- ---
242
-
243
- ## File Structure
244
-
245
- ```
246
- src/
247
- ├── assets/
248
- │ └── toast.css # All styles & animations
249
- ├── components/
250
- │ ├── Toast.vue # Individual toast card
251
- │ └── ToastContainer.vue # Positional viewport manager
252
- ├── composables/
253
- │ └── useToast.ts # Reactive toast API
254
- ├── plugins/
255
- │ └── toast.ts # Vue plugin (app.use)
256
- ├── types/
257
- │ └── toast.ts # TypeScript interfaces
258
- └── main.ts # App entry point
259
- ```
260
-
261
- ---
262
-
263
- ## Bundle Size
264
-
265
- | File | Raw | Gzipped |
266
- |------|-----|---------|
267
- | JS (all files) | ~12 KB | ~4 KB |
268
- | CSS | ~6 KB | ~2 KB |
269
- | **Total** | **~18 KB** | **~6 KB** |
270
-
271
- Zero external dependencies beyond Vue 3.
272
-
273
- ---
274
-
275
- ## License
276
-
277
- MIT © feather-toast
1
+ # feather-toast-vue
2
+
3
+ Lightweight, accessible toast notifications for Vue 3 with spring-based animations, promise support, swipe-to-dismiss, and a minimal footprint.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Installation](#installation)
10
+ 2. [Setup](#setup)
11
+ 3. [Quick Start](#quick-start)
12
+ 4. [Variants](#variants)
13
+ 5. [Positioning](#positioning)
14
+ 6. [Stack Limit](#stack-limit)
15
+ 7. [Global Configuration](#global-configuration)
16
+ 8. [toast.undo](#toastundo)
17
+ 9. [toast.step](#toapststep)
18
+ 10. [toast.progress](#toastprogress)
19
+ 11. [toast.copy](#toastcopy)
20
+ 12. [toast.promise](#toastpromise)
21
+ 13. [toast.custom](#toastcustom)
22
+ 14. [toast.network](#toastnetwork)
23
+ 15. [TypeScript API Reference](#typescript-api-reference)
24
+ 16. [CSS Theming](#css-custom-properties-theming)
25
+
26
+ ---
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ npm install feather-toast-vue
32
+ # or
33
+ yarn add feather-toast-vue
34
+ # or
35
+ pnpm add feather-toast-vue
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Setup
41
+
42
+ ### Vue 3 (Vite / Webpack)
43
+
44
+ Register the plugin once in your application entry file.
45
+
46
+ **`src/main.ts`**
47
+ ```ts
48
+ import { createApp } from 'vue'
49
+ import App from './App.vue'
50
+ import { CreateFeatherToast } from 'feather-toast-vue'
51
+
52
+ const app = createApp(App)
53
+ app.use(CreateFeatherToast)
54
+ app.mount('#app')
55
+ ```
56
+
57
+ The plugin automatically mounts `<ToastContainer />` and injects the `toast` instance via `provide/inject`.
58
+
59
+ ---
60
+
61
+ ### Nuxt 3
62
+
63
+ Create a client-only plugin file. Toast relies on browser APIs and must run exclusively on the client.
64
+
65
+ **`plugins/toast.client.ts`**
66
+ ```ts
67
+ import { defineNuxtPlugin } from '#app'
68
+ import { CreateFeatherToast } from 'feather-toast-vue'
69
+
70
+ export default defineNuxtPlugin((nuxtApp) => {
71
+ nuxtApp.vueApp.use(CreateFeatherToast)
72
+ })
73
+ ```
74
+
75
+ > The `.client.ts` suffix ensures Nuxt only loads this plugin in the browser, never on the server.
76
+
77
+ ---
78
+
79
+ ## Quick Start
80
+
81
+ Call `useFeatherToast()` inside any Vue component's `<script setup>` to access the `toast` object.
82
+
83
+ ```vue
84
+ <script setup lang="ts">
85
+ import { useFeatherToast } from 'feather-toast-vue'
86
+
87
+ const { toast } = useFeatherToast()
88
+
89
+ function save() {
90
+ toast.success('Changes saved successfully!')
91
+ }
92
+ </script>
93
+
94
+ <template>
95
+ <button @click="save">Save</button>
96
+ </template>
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Variants
102
+
103
+ ```ts
104
+ const { toast } = useFeatherToast()
105
+
106
+ toast('New notification') // default
107
+ toast.success('Profile updated!')
108
+ toast.error('Request failed.')
109
+ toast.warning('Storage running low.')
110
+ toast.info('Version 2.4 available.')
111
+ toast.loading('Uploading files...')
112
+ toast.destructive('3 records deleted permanently.')
113
+ toast.neutral('Session token refreshed.')
114
+
115
+ // Full options object
116
+ toast.success({
117
+ title: 'Payment successful',
118
+ description: 'Your invoice has been paid.',
119
+ duration: 6000,
120
+ position: 'top-right',
121
+ })
122
+ ```
123
+
124
+ | Variant | Duration | Dismissible | Notes |
125
+ |---------------|-------------|-------------|------------------------------------|
126
+ | `default` | 5 000 ms | Yes | Neutral notification |
127
+ | `success` | 5 000 ms | Yes | Positive confirmation |
128
+ | `error` | 5 000 ms | Yes | Failure or exception |
129
+ | `warning` | 5 000 ms | Yes | Caution / low-priority issue |
130
+ | `info` | 5 000 ms | Yes | Informational message |
131
+ | `loading` | Persistent | No | Spinner; use with `toast.promise` |
132
+ | `destructive` | 5 000 ms | Yes | High-severity irreversible action |
133
+ | `offline` | Persistent | No | Network connectivity lost |
134
+ | `update` | 8 000 ms | Yes | App or version update available |
135
+ | `neutral` | 3 000 ms | Yes | Passive ambient notification |
136
+
137
+ ---
138
+
139
+ ## Positioning
140
+
141
+ ```ts
142
+ toast.success({
143
+ title: 'Saved',
144
+ position: 'top-right',
145
+ // 'top-right' | 'top-left' | 'top-center'
146
+ // 'bottom-right' | 'bottom-left' | 'bottom-center'
147
+ })
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Stack Limit
153
+
154
+ When the number of visible toasts at a given position exceeds the configured maximum, the oldest toast is smoothly dismissed.
155
+
156
+ ```ts
157
+ toast.config({ max: 3 }) // Allow at most 3 simultaneous toasts
158
+ toast.config({ max: 0 }) // Unlimited
159
+ ```
160
+
161
+ ---
162
+
163
+ ## Global Configuration
164
+
165
+ Configure defaults once � typically in your root component.
166
+
167
+ ```ts
168
+ import { useFeatherToast } from 'feather-toast-vue'
169
+
170
+ const { toast } = useFeatherToast()
171
+
172
+ toast.config({
173
+ max: 3, // Max visible toasts per position (0 = unlimited)
174
+ duration: 4000, // Default auto-dismiss timeout in milliseconds
175
+ position: 'bottom-right', // Default spawn position
176
+ })
177
+
178
+ const config = toast.getConfig()
179
+ // => { max: 3, duration: 4000, position: 'bottom-right' }
180
+ ```
181
+
182
+ ---
183
+
184
+ ## toast.undo
185
+
186
+ Renders a toast with a live countdown bar and an **Undo** action button. Use this for destructive operations where the user needs a grace period to revert.
187
+
188
+ ```ts
189
+ const { toast } = useFeatherToast()
190
+
191
+ function deleteFile(fileId: string) {
192
+ toast.undo('File "invoice-2026.pdf" deleted', {
193
+ description: 'Click Undo within 5 seconds to restore the file.',
194
+ duration: 5000,
195
+ undoLabel: 'Undo Delete',
196
+ onUndo: async () => {
197
+ await restoreFile(fileId)
198
+ toast.success('File restored to Documents.')
199
+ },
200
+ onDismiss: () => {
201
+ // Called only if countdown expired without clicking Undo
202
+ permanentlyDelete(fileId)
203
+ },
204
+ })
205
+ }
206
+ ```
207
+
208
+ ### UndoToastOptions
209
+
210
+ | Property | Type | Default | Description |
211
+ |---------------|-------------------------------|----------|----------------------------------------------------|
212
+ | `title` | `string` | � | Primary text of the toast. |
213
+ | `description` | `string` | � | Secondary explanation line. |
214
+ | `duration` | `number` | `5000` | Countdown timer in milliseconds. |
215
+ | `undoLabel` | `string` | `'Undo'` | Label for the revert button. |
216
+ | `onUndo` | `() => void \| Promise<void>` | � | Called when the user clicks Undo. |
217
+ | `onDismiss` | `() => void` | � | Called if the countdown expires without undo. |
218
+ | `position` | `ToastPosition` | Global | Overrides the global default position. |
219
+
220
+ ---
221
+
222
+ ## toast.step
223
+
224
+ Renders a single persistent loading toast and transitions it through sequential steps in-place � no flicker, no new cards. Ideal for multi-stage operations (deployments, imports, migrations).
225
+
226
+ ```ts
227
+ const { toast } = useFeatherToast()
228
+
229
+ async function runMigration() {
230
+ const workflow = toast.step({
231
+ title: 'Step 1/3: Validating schema...',
232
+ description: 'Checking data integrity.',
233
+ })
234
+
235
+ await validateSchema()
236
+ workflow.next({
237
+ title: 'Step 2/3: Deploying database migration...',
238
+ description: 'Applying schema patches to PostgreSQL.',
239
+ })
240
+
241
+ try {
242
+ await deployMigration()
243
+ workflow.done({
244
+ title: 'Step 3/3: Migration complete!',
245
+ description: 'Database updated with zero downtime.',
246
+ })
247
+ } catch (err) {
248
+ workflow.fail({
249
+ title: 'Migration failed',
250
+ description: err.message,
251
+ })
252
+ }
253
+ }
254
+ ```
255
+
256
+ ### StepToastController
257
+
258
+ | Method | Signature | Description |
259
+ |--------|-----------------------------------------|-------------------------------------------------|
260
+ | `next` | `(opts: Partial<ToastOptions>) => void` | Updates the toast in-place; keeps loading state.|
261
+ | `done` | `(opts?: Partial<ToastOptions>) => void`| Switches the toast to success variant. |
262
+ | `fail` | `(opts?: Partial<ToastOptions>) => void`| Switches the toast to error variant. |
263
+
264
+ ---
265
+
266
+ ## toast.progress
267
+
268
+ Spawns a loading toast with an explicit progress bar you control programmatically. Use for uploads, downloads, or any task with measurable progress.
269
+
270
+ ```ts
271
+ const { toast } = useFeatherToast()
272
+
273
+ async function uploadFile(file: File) {
274
+ const progressToast = toast.progress({
275
+ title: 'Uploading file...',
276
+ description: '0% completed',
277
+ })
278
+
279
+ xhr.addEventListener('progress', (e) => {
280
+ const pct = Math.round((e.loaded / e.total) * 100)
281
+ progressToast.setProgress(pct, { description: `${pct}% completed` })
282
+ })
283
+
284
+ await uploadPromise
285
+
286
+ progressToast.done({
287
+ title: 'Upload complete!',
288
+ description: `${file.name} saved to storage.`,
289
+ })
290
+ }
291
+ ```
292
+
293
+ ### ProgressToastController
294
+
295
+ | Method | Signature | Description |
296
+ |---------------|-------------------------------------------------------|-----------------------------------------------|
297
+ | `setProgress` | `(pct: number, opts?: Partial<ToastOptions>) => void` | Updates the bar (0�100) and toast text. |
298
+ | `done` | `(opts?: Partial<ToastOptions>) => void` | Completes the task; switches to success. |
299
+ | `fail` | `(opts?: Partial<ToastOptions>) => void` | Marks the task failed; switches to error. |
300
+
301
+ ---
302
+
303
+ ## toast.copy
304
+
305
+ Copies text to the system clipboard and automatically shows a confirmation toast.
306
+
307
+ ```ts
308
+ const { toast } = useFeatherToast()
309
+
310
+ async function copyLink() {
311
+ await toast.copy('https://your-app.dev/share/xyz', {
312
+ title: 'Link copied!',
313
+ description: 'Share link has been copied to your clipboard.',
314
+ })
315
+ }
316
+ ```
317
+
318
+ On success: shows a `success` toast.
319
+ On failure: shows an `error` toast with the browser error message.
320
+
321
+ ---
322
+
323
+ ## toast.promise
324
+
325
+ Tracks an existing promise and automatically transitions loading ? success / error.
326
+
327
+ ```ts
328
+ const { toast } = useFeatherToast()
329
+
330
+ async function createProject(data: ProjectPayload) {
331
+ const request = fetch('/api/projects', {
332
+ method: 'POST',
333
+ body: JSON.stringify(data),
334
+ })
335
+
336
+ await toast.promise(request, {
337
+ loading: {
338
+ title: 'Creating project...',
339
+ description: 'Setting up your workspace.',
340
+ },
341
+ success: () => ({
342
+ title: 'Project created!',
343
+ description: 'Your workspace is ready.',
344
+ }),
345
+ error: (err) => ({
346
+ title: 'Failed to create project',
347
+ description: err instanceof Error ? err.message : 'An unknown error occurred.',
348
+ }),
349
+ })
350
+ }
351
+ ```
352
+
353
+ > `toast.promise` re-throws the rejection after showing the error toast. Wrap calls in `try/catch` or `.catch()` to handle the error downstream.
354
+
355
+ ### ToastPromiseOptions
356
+
357
+ | Property | Type | Description |
358
+ |-----------|---------------------------------------------------|------------------------------------------------|
359
+ | `loading` | `ToastOptions` | Shown while the promise is pending. |
360
+ | `success` | `ToastOptions \| ((data: T) => ToastOptions)` | Shown on fulfillment. |
361
+ | `error` | `ToastOptions \| ((err: unknown) => ToastOptions)`| Shown on rejection. |
362
+
363
+ ---
364
+
365
+ ## toast.custom
366
+
367
+ Render any Vue component, render function, or `h()` VNode directly inside a toast.
368
+
369
+ ```ts
370
+ import { h } from 'vue'
371
+ import { useFeatherToast } from 'feather-toast-vue'
372
+
373
+ const { toast } = useFeatherToast()
374
+
375
+ function showInvite(user: { name: string; initials: string }) {
376
+ toast.custom({
377
+ render: () =>
378
+ h('div', { style: 'display:flex;align-items:center;gap:12px;' }, [
379
+ h('div', {
380
+ style: 'width:32px;height:32px;border-radius:50%;background:#6366f1;color:#fff;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;',
381
+ }, user.initials),
382
+ h('div', [
383
+ h('p', { style: 'font-size:13px;font-weight:500;margin:0;' }, `${user.name} invited you`),
384
+ h('p', { style: 'font-size:11px;opacity:0.65;margin:3px 0 0;' }, 'to collaborate on Project Alpha'),
385
+ ]),
386
+ ]),
387
+ duration: 6000,
388
+ })
389
+ }
390
+ ```
391
+
392
+ You can also pass a single-file component directly:
393
+
394
+ ```ts
395
+ import InviteCard from '@/components/InviteCard.vue'
396
+
397
+ toast.custom({
398
+ render: () => h(InviteCard, { user }),
399
+ duration: 6000,
400
+ })
401
+ ```
402
+
403
+ ---
404
+
405
+ ## toast.network
406
+
407
+ `toast.network()` automatically monitors the browser's `online` and `offline` events. It:
408
+
409
+ - Shows a **persistent, non-dismissible offline toast** the instant the device loses internet.
410
+ - Dismisses it and shows a **success toast** when the connection is restored.
411
+ - Detects if the device is **already offline at registration time** and shows the toast immediately.
412
+
413
+ Returns a `NetworkToastController` with a `stop()` method to clean up listeners.
414
+
415
+ ### Recommended: App-Level Registration
416
+
417
+ Register once in your root `App.vue` to monitor connectivity for the entire application.
418
+
419
+ ```vue
420
+ <!-- App.vue -->
421
+ <script setup lang="ts">
422
+ import { onMounted, onUnmounted } from 'vue'
423
+ import { useFeatherToast } from 'feather-toast-vue'
424
+ import type { NetworkToastController } from 'feather-toast-vue'
425
+
426
+ const { toast } = useFeatherToast()
427
+ let networkMonitor: NetworkToastController | null = null
428
+
429
+ onMounted(() => {
430
+ networkMonitor = toast.network()
431
+ })
432
+
433
+ onUnmounted(() => {
434
+ networkMonitor?.stop()
435
+ })
436
+ </script>
437
+ ```
438
+
439
+ ### Custom Messages
440
+
441
+ ```ts
442
+ const monitor = toast.network({
443
+ offline: {
444
+ title: 'No internet connection',
445
+ description: 'Please check your Wi-Fi or mobile data.',
446
+ position: 'top-center',
447
+ },
448
+ online: {
449
+ title: 'Connection restored',
450
+ description: 'You are back online.',
451
+ position: 'top-center',
452
+ },
453
+ })
454
+
455
+ // Stop monitoring when no longer needed
456
+ monitor.stop()
457
+ ```
458
+
459
+ ### NetworkToastOptions
460
+
461
+ | Option | Type | Default | Description |
462
+ |-----------|-------------------------|----------|------------------------------------------------------|
463
+ | `offline` | `Partial<ToastOptions>` | Built-in | Toast shown when internet connection is lost. |
464
+ | `online` | `Partial<ToastOptions>` | Built-in | Toast shown when internet connection is restored. |
465
+
466
+ ### NetworkToastController
467
+
468
+ | Method | Signature | Description |
469
+ |--------|--------------|-----------------------------------------------------------------|
470
+ | `stop` | `() => void` | Removes event listeners and dismisses the offline toast if present. |
471
+
472
+ ---
473
+
474
+ ## TypeScript API Reference
475
+
476
+ All types are exported directly from the package:
477
+
478
+ ```ts
479
+ import type {
480
+ Toast,
481
+ ToastOptions,
482
+ ToastAction,
483
+ ToastVariant,
484
+ ToastPosition,
485
+ ToastConfig,
486
+ ToastPromiseOptions,
487
+ UndoToastOptions,
488
+ StepToastController,
489
+ ProgressToastController,
490
+ NetworkToastOptions,
491
+ NetworkToastController,
492
+ ToastComponent,
493
+ } from 'feather-toast-vue'
494
+ ```
495
+
496
+ ### ToastOptions
497
+
498
+ | Property | Type | Default | Description |
499
+ |---------------|-----------------------------------------|------------------|------------------------------------------------|
500
+ | `title` | `string` | � | Primary text of the toast. |
501
+ | `description` | `string` | `undefined` | Secondary line below the title. |
502
+ | `variant` | `ToastVariant` | `'default'` | Controls the icon and accent color. |
503
+ | `position` | `ToastPosition` | `'bottom-right'` | One of six supported positions. |
504
+ | `duration` | `number` | `5000` | Auto-dismiss delay in milliseconds. |
505
+ | `dismissible` | `boolean` | `true` | Whether the user can close the toast manually. |
506
+ | `progress` | `number` (0�100) | `undefined` | Explicit progress bar percentage. |
507
+ | `showProgress`| `boolean` | `false` | Renders an animated countdown bar. |
508
+ | `action` | `{ label: string; onClick: () => void }`| `undefined` | Inline action button. |
509
+ | `onDismiss` | `() => void` | `undefined` | Called when the toast is dismissed. |
510
+
511
+ ### ToastConfig
512
+
513
+ | Property | Type | Default | Description |
514
+ |------------|-----------------|------------------|--------------------------------------------------|
515
+ | `max` | `number` | `5` | Max visible toasts per position (0 = unlimited). |
516
+ | `duration` | `number` | `5000` | Default auto-dismiss timeout in milliseconds. |
517
+ | `position` | `ToastPosition` | `'bottom-right'` | Default spawn position. |
518
+
519
+ ---
520
+
521
+ ## CSS Custom Properties (Theming)
522
+
523
+ ```css
524
+ :root {
525
+ --toast-bg: #18181b;
526
+ --toast-border: rgba(255, 255, 255, 0.08);
527
+ --toast-text: #fafafa;
528
+ --toast-text-muted: #a1a1aa;
529
+ --toast-success: #22c55e;
530
+ --toast-error: #ef4444;
531
+ --toast-warning: #f59e0b;
532
+ --toast-info: #3b82f6;
533
+ --toast-radius: 8px;
534
+ --toast-shadow: 0 4px 24px rgba(0, 0, 0, 0.3);
535
+ --toast-z-index: 9999;
536
+ }
537
+ ```
538
+
539
+ ---
540
+
541
+ ## License
542
+
543
+ MIT (c) zin-ix