feather-toast-vue 1.0.1 → 1.0.2
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 +286 -286
- package/dist/assets/index-D8xHyfYy.js +22 -0
- package/dist/assets/index-DYv_FVVl.css +1 -0
- package/{index.html → dist/index.html} +16 -15
- package/package.json +47 -33
- package/.vscode/extensions.json +0 -3
- package/desktop.ini +0 -2
- package/env.d.ts +0 -1
- package/src/App.vue +0 -711
- package/src/assets/toast.css +0 -305
- package/src/components/Toast.vue +0 -230
- package/src/components/ToastContainer.vue +0 -69
- package/src/composables/useToast.ts +0 -133
- package/src/index.ts +0 -11
- package/src/main.ts +0 -8
- package/src/plugins/toast.ts +0 -17
- package/src/types/toast.ts +0 -41
- package/tsconfig.app.json +0 -18
- package/tsconfig.json +0 -11
- package/tsconfig.node.json +0 -27
- package/vite.config.lib.ts +0 -33
- package/vite.config.ts +0 -19
- /package/{public → dist}/favicon.ico +0 -0
package/README.md
CHANGED
|
@@ -1,286 +1,286 @@
|
|
|
1
|
-
# 🪶 Feather Toast Vue
|
|
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
|
|
38
|
-
import 'feather-toast/
|
|
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
|
|
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
|
|
1
|
+
# 🪶 Feather Toast Vue
|
|
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-vue
|
|
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-vue'
|
|
38
|
+
import 'feather-toast-vue/style.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-vue'
|
|
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
|