feather-toast-vue 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/.vscode/extensions.json +3 -0
- package/README.md +286 -0
- package/desktop.ini +2 -0
- package/env.d.ts +1 -0
- package/index.html +15 -0
- package/package.json +33 -0
- package/public/favicon.ico +0 -0
- package/src/App.vue +711 -0
- package/src/assets/toast.css +305 -0
- package/src/components/Toast.vue +230 -0
- package/src/components/ToastContainer.vue +69 -0
- package/src/composables/useToast.ts +133 -0
- package/src/index.ts +11 -0
- package/src/main.ts +8 -0
- package/src/plugins/toast.ts +17 -0
- package/src/types/toast.ts +41 -0
- package/tsconfig.app.json +18 -0
- package/tsconfig.json +11 -0
- package/tsconfig.node.json +27 -0
- package/vite.config.lib.ts +33 -0
- package/vite.config.ts +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# πͺΆ Feather Toast
|
|
2
|
+
|
|
3
|
+
A lightweight, smooth Vue 3 toast notification plugin with minimalist design and buttery animations.
|
|
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
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Setup
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
// main.ts
|
|
35
|
+
import { createApp } from 'vue'
|
|
36
|
+
import App from './App.vue'
|
|
37
|
+
import { ToastPlugin } from 'feather-toast/plugins/toast'
|
|
38
|
+
import 'feather-toast/assets/toast.css'
|
|
39
|
+
|
|
40
|
+
const app = createApp(App)
|
|
41
|
+
app.use(ToastPlugin)
|
|
42
|
+
app.mount('#app')
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Add `<ToastContainer />` once to your root layout:
|
|
46
|
+
|
|
47
|
+
```vue
|
|
48
|
+
<!-- App.vue -->
|
|
49
|
+
<template>
|
|
50
|
+
<router-view />
|
|
51
|
+
<ToastContainer />
|
|
52
|
+
</template>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## π Usage
|
|
58
|
+
|
|
59
|
+
### Basic
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { useToast } from 'feather-toast/composables/useToast'
|
|
63
|
+
|
|
64
|
+
const { toast } = useToast()
|
|
65
|
+
|
|
66
|
+
toast({
|
|
67
|
+
title: 'Event Created',
|
|
68
|
+
description: 'Your event has been scheduled.',
|
|
69
|
+
})
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Variants
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
toast.success({ title: 'Saved', description: 'Changes applied.' })
|
|
76
|
+
toast.error({ title: 'Error', description: 'Something went wrong.' })
|
|
77
|
+
toast.warning({ title: 'Warning', description: 'Disk space is low.' })
|
|
78
|
+
toast.info({ title: 'Info', description: 'Version 2.4 is available.' })
|
|
79
|
+
toast.loading({ title: 'Uploading...', description: 'Please wait.' })
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Custom Position
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
toast.success({
|
|
86
|
+
title: 'Saved',
|
|
87
|
+
position: 'top-center', // default: 'bottom-right'
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Promise API
|
|
92
|
+
|
|
93
|
+
Automatically transitions `loading β success` or `loading β error`:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
toast.promise(
|
|
97
|
+
fetch('/api/projects', { method: 'POST' }),
|
|
98
|
+
{
|
|
99
|
+
loading: {
|
|
100
|
+
title: 'Creating project...',
|
|
101
|
+
description: 'Setting up your workspace.',
|
|
102
|
+
},
|
|
103
|
+
success: (data) => ({
|
|
104
|
+
title: `"${data.name}" created`,
|
|
105
|
+
description: 'Your project is ready.',
|
|
106
|
+
}),
|
|
107
|
+
error: (err) => ({
|
|
108
|
+
title: 'Failed to create project',
|
|
109
|
+
description: err instanceof Error ? err.message : 'Unknown error.',
|
|
110
|
+
}),
|
|
111
|
+
}
|
|
112
|
+
)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Action Button
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
toast({
|
|
119
|
+
title: 'Message archived',
|
|
120
|
+
description: 'Moved to archive.',
|
|
121
|
+
action: {
|
|
122
|
+
label: 'Undo',
|
|
123
|
+
onClick: () => {
|
|
124
|
+
toast.success({ title: 'Restored', description: 'Message moved back to inbox.' })
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
})
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Dismiss
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
// Dismiss by ID
|
|
134
|
+
const id = toast.loading({ title: 'Working...' })
|
|
135
|
+
toast.dismiss(id)
|
|
136
|
+
|
|
137
|
+
// Dismiss all
|
|
138
|
+
toast.dismissAll()
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## π API Reference
|
|
144
|
+
|
|
145
|
+
### `useToast()`
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
const { toast, toasts, dismiss, dismissAll } = useToast()
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
| Property | Type | Description |
|
|
152
|
+
|----------|------|-------------|
|
|
153
|
+
| `toast(options)` | `(options: ToastOptions) => string` | Show a default toast, returns its ID |
|
|
154
|
+
| `toast.success(options)` | `Function` | Success variant |
|
|
155
|
+
| `toast.error(options)` | `Function` | Error variant |
|
|
156
|
+
| `toast.warning(options)` | `Function` | Warning variant |
|
|
157
|
+
| `toast.info(options)` | `Function` | Info variant |
|
|
158
|
+
| `toast.loading(options)` | `Function` | Loading variant β no auto-dismiss |
|
|
159
|
+
| `toast.promise(promise, opts)` | `Function` | Promise-based toast flow |
|
|
160
|
+
| `toast.dismiss(id)` | `Function` | Dismiss a specific toast by ID |
|
|
161
|
+
| `toast.dismissAll()` | `Function` | Dismiss all active toasts |
|
|
162
|
+
| `toasts` | `Ref<Toast[]>` | Reactive list of all active toasts |
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
### `ToastOptions`
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
interface ToastOptions {
|
|
170
|
+
title?: string
|
|
171
|
+
description?: string
|
|
172
|
+
variant?: 'default' | 'success' | 'error' | 'warning' | 'info' | 'loading'
|
|
173
|
+
position?: 'top-right' | 'top-left' | 'top-center'
|
|
174
|
+
| 'bottom-right' | 'bottom-left' | 'bottom-center'
|
|
175
|
+
duration?: number // ms Β· default: 5000 Β· loading: Infinity
|
|
176
|
+
dismissible?: boolean // default: true (false for loading)
|
|
177
|
+
action?: {
|
|
178
|
+
label: string
|
|
179
|
+
onClick: () => void
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
### Positions
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
ββββββββββββ¬βββββββββββββ¬ββββββββββββ
|
|
190
|
+
β top-left β top-center β top-right β
|
|
191
|
+
β β β β
|
|
192
|
+
β β β β
|
|
193
|
+
β bot-left β bot-center β bot-right β
|
|
194
|
+
ββββββββββββ΄βββββββββββββ΄ββββββββββββ
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## π¨ Design System
|
|
200
|
+
|
|
201
|
+
### Color Tokens
|
|
202
|
+
|
|
203
|
+
| Token | Value | Usage |
|
|
204
|
+
|-------|-------|-------|
|
|
205
|
+
| `--toast-bg` | `#ffffff` | Card background |
|
|
206
|
+
| `--toast-border` | `#e4e4e7` | Card border |
|
|
207
|
+
| `--toast-text` | `#18181b` | Title text |
|
|
208
|
+
| `--toast-text-muted` | `#71717a` | Description text |
|
|
209
|
+
| `--toast-shadow` | `0 2px 8px rgba(0,0,0,0.06)` | Card elevation |
|
|
210
|
+
| `--toast-radius` | `10px` | Card border radius |
|
|
211
|
+
| `--toast-width` | `360px` | Card width |
|
|
212
|
+
|
|
213
|
+
### Icon Accent Colors
|
|
214
|
+
|
|
215
|
+
| Variant | Color | Hex |
|
|
216
|
+
|---------|-------|-----|
|
|
217
|
+
| Success | π’ Green | `#16a34a` |
|
|
218
|
+
| Error | π΄ Red | `#dc2626` |
|
|
219
|
+
| Warning | π‘ Amber | `#d97706` |
|
|
220
|
+
| Info | π΅ Blue | `#2563eb` |
|
|
221
|
+
| Loading | β« Gray | `#71717a` |
|
|
222
|
+
|
|
223
|
+
### Customization via CSS Variables
|
|
224
|
+
|
|
225
|
+
```css
|
|
226
|
+
/* Override in your global CSS */
|
|
227
|
+
:root {
|
|
228
|
+
--toast-bg: #ffffff;
|
|
229
|
+
--toast-border: #e4e4e7;
|
|
230
|
+
--toast-text: #18181b;
|
|
231
|
+
--toast-text-muted: #71717a;
|
|
232
|
+
--toast-radius: 10px;
|
|
233
|
+
--toast-width: 360px;
|
|
234
|
+
--toast-gap: 8px;
|
|
235
|
+
--toast-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## π¬ Animation Spec
|
|
242
|
+
|
|
243
|
+
| Phase | Duration | Easing |
|
|
244
|
+
|-------|----------|--------|
|
|
245
|
+
| **Enter** | 400ms | `cubic-bezier(0.16, 1, 0.3, 1)` β spring |
|
|
246
|
+
| **Exit** | 220ms | `cubic-bezier(0.4, 0, 1, 1)` β snappy |
|
|
247
|
+
| **Sibling reflow** | 350ms | `cubic-bezier(0.16, 1, 0.3, 1)` β spring |
|
|
248
|
+
| **Swipe snap-back** | 360ms | `cubic-bezier(0.16, 1, 0.3, 1)` β spring |
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## π File Structure
|
|
253
|
+
|
|
254
|
+
```
|
|
255
|
+
src/
|
|
256
|
+
βββ assets/
|
|
257
|
+
β βββ toast.css # All styles & animations
|
|
258
|
+
βββ components/
|
|
259
|
+
β βββ Toast.vue # Individual toast card
|
|
260
|
+
β βββ ToastContainer.vue # Positional viewport manager
|
|
261
|
+
βββ composables/
|
|
262
|
+
β βββ useToast.ts # Reactive toast API
|
|
263
|
+
βββ plugins/
|
|
264
|
+
β βββ toast.ts # Vue plugin (app.use)
|
|
265
|
+
βββ types/
|
|
266
|
+
β βββ toast.ts # TypeScript interfaces
|
|
267
|
+
βββ main.ts # App entry point
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## π Bundle Size
|
|
273
|
+
|
|
274
|
+
| File | Raw | Gzipped |
|
|
275
|
+
|------|-----|---------|
|
|
276
|
+
| JS (all files) | ~12 KB | ~4 KB |
|
|
277
|
+
| CSS | ~6 KB | ~2 KB |
|
|
278
|
+
| **Total** | **~18 KB** | **~6 KB** |
|
|
279
|
+
|
|
280
|
+
Zero external dependencies beyond Vue 3.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## π License
|
|
285
|
+
|
|
286
|
+
MIT Β© feather-toast
|
package/desktop.ini
ADDED
package/env.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
package/index.html
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>πͺΆ</text></svg>">
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
8
|
+
<title>feather-toast demo</title>
|
|
9
|
+
</head>
|
|
10
|
+
|
|
11
|
+
<body>
|
|
12
|
+
<div id="app"></div>
|
|
13
|
+
<script type="module" src="/src/main.ts"></script>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "feather-toast-vue",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A lightweight, smooth Vue 3 toast notification plugin",
|
|
5
|
+
"homepage": "https://zin-ix.github.io/feather-toast/",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"dev": "vite",
|
|
9
|
+
"build": "npm-run-all type-check build-only",
|
|
10
|
+
"build-only": "vite build",
|
|
11
|
+
"preview": "vite preview",
|
|
12
|
+
"type-check": "vue-tsc --build",
|
|
13
|
+
"deploy": "npm run build && gh-pages -d dist"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"vue": "^3.5.32"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@tsconfig/node24": "^24.0.4",
|
|
20
|
+
"@types/node": "^24.12.2",
|
|
21
|
+
"@vitejs/plugin-vue": "^6.0.6",
|
|
22
|
+
"@vue/tsconfig": "^0.9.1",
|
|
23
|
+
"gh-pages": "^6.3.0",
|
|
24
|
+
"npm-run-all2": "^8.0.4",
|
|
25
|
+
"typescript": "~6.0.0",
|
|
26
|
+
"vite": "^8.0.8",
|
|
27
|
+
"vite-plugin-vue-devtools": "^8.1.1",
|
|
28
|
+
"vue-tsc": "^3.2.6"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
Binary file
|