@soft-toast/vue 1.1.0 → 1.1.1

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 +187 -99
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,17 +1,21 @@
1
1
  # @soft-toast/vue
2
2
 
3
- A toast notification library for Vue 3 with soft motion, compact defaults, and flexible customization.
3
+ A toast notification library for Vue 3 with fluid motion, stacked layout, and flexible customization.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Fluid Motion**: Smooth enter, exit, stack, and swipe interactions.
8
- - **Stacked Layout**: Toasts stay compact, readable, and easy to scan.
9
- - **Position Options**: 10 positions including corners and edges.
10
- - **Motion Presets**: Choose from `smooth`, `bouncy`, `subtle`, or `snappy` presets.
11
- - **Rich Content**: Supports titles, descriptions, action buttons, progress bars, and custom icons.
12
- - **Promise Handling**: Built-in support for async operations with loading states.
13
- - **Swipe to Dismiss**: Touch gesture support for mobile devices.
14
- - **TypeScript**: Built with TypeScript for type safety.
7
+ - **Fluid Motion**: Smooth enter, exit, stack, and swipe interactions powered by GSAP.
8
+ - **Stacked Layout**: Toasts stay compact and readable; hover or tap to expand the full stack.
9
+ - **10 Positions**: All corners, edges, and center positions.
10
+ - **Motion Presets**: `smooth`, `bouncy`, `subtle`, or `snappy`.
11
+ - **Rich Content**: Titles, descriptions, action buttons, progress bars, timestamps, and custom icons.
12
+ - **Promise Toasts**: Built-in loading → success / error lifecycle for async operations.
13
+ - **Flash Messages**: Queue toasts that survive page navigation via `sessionStorage`.
14
+ - **Sound Support**: Optional synthesized tones or custom audio URLs per toast.
15
+ - **Smart Deduplication**: Calling with the same `id` updates the existing toast instead of stacking.
16
+ - **Custom Slots**: Override `#icon`, `#title`, `#description`, `#action`, and `#close-button`.
17
+ - **Swipe to Dismiss**: Pointer-event gesture support for both touch and mouse.
18
+ - **TypeScript**: Full type safety with exported types.
15
19
 
16
20
  ## Compatibility
17
21
 
@@ -22,21 +26,14 @@ A toast notification library for Vue 3 with soft motion, compact defaults, and f
22
26
 
23
27
  ## Installation
24
28
 
25
- ### Vue 3
26
-
27
29
  ```bash
28
30
  npm install @soft-toast/vue
31
+ # pnpm add @soft-toast/vue
32
+ # yarn add @soft-toast/vue
33
+ # bun add @soft-toast/vue
29
34
  ```
30
35
 
31
- Package manager equivalents:
32
-
33
- ```bash
34
- pnpm add @soft-toast/vue
35
- yarn add @soft-toast/vue
36
- bun add @soft-toast/vue
37
- ```
38
-
39
- Register the Vue plugin in `main.ts` or `main.js`:
36
+ Register the plugin in `main.ts`:
40
37
 
41
38
  ```typescript
42
39
  import { createApp } from "vue";
@@ -58,34 +55,16 @@ app.mount("#app");
58
55
 
59
56
  ### Nuxt 3 / Nuxt 4
60
57
 
61
- For Nuxt apps, install the companion module:
62
-
63
58
  ```bash
64
59
  npm install @soft-toast/nuxt
65
60
  ```
66
61
 
67
- Package manager equivalents:
68
-
69
- ```bash
70
- pnpm add @soft-toast/nuxt
71
- yarn add @soft-toast/nuxt
72
- bun add @soft-toast/nuxt
73
- ```
74
-
75
- Add it to `nuxt.config.ts`:
76
-
77
- ```typescript
78
- export default defineNuxtConfig({
79
- modules: ["@soft-toast/nuxt"],
80
- });
81
- ```
82
-
83
- `softToast` is optional. Add it only when you want to override global defaults:
84
-
85
62
  ```typescript
63
+ // nuxt.config.ts
86
64
  export default defineNuxtConfig({
87
65
  modules: ["@soft-toast/nuxt"],
88
66
  softToast: {
67
+ position: "top-right",
89
68
  closeButton: true,
90
69
  showProgress: true,
91
70
  },
@@ -94,106 +73,197 @@ export default defineNuxtConfig({
94
73
 
95
74
  ## Quick Start
96
75
 
97
- Use it anywhere in your Vue or Nuxt components:
98
-
99
76
  ```vue
100
- <script setup>
77
+ <script setup lang="ts">
101
78
  import { useSoftToast } from "@soft-toast/vue";
102
79
 
103
- const softToast = useSoftToast();
80
+ const toast = useSoftToast();
104
81
 
105
- const showToast = () => {
106
- softToast.success("Profile saved!", {
82
+ const save = () => {
83
+ toast.success("Profile saved!", {
107
84
  description: "Your changes have been successfully saved.",
108
- position: "top-right",
109
85
  duration: 2500,
110
- closeButton: true,
111
86
  showProgress: true,
112
87
  });
113
88
  };
114
89
  </script>
115
90
 
116
91
  <template>
117
- <button @click="showToast">Save Profile</button>
92
+ <button @click="save">Save Profile</button>
118
93
  </template>
119
94
  ```
120
95
 
121
- The plugin options are global defaults. You can override them per toast when a page needs different behavior:
96
+ Plugin options are global defaults. Override them per toast as needed:
122
97
 
123
98
  ```typescript
124
- softToast.warning("File moved to trash", {
99
+ toast.warning("File moved to trash", {
125
100
  description: "You can restore it from the activity log.",
126
101
  position: "bottom-right",
127
102
  duration: Infinity,
128
103
  closeButton: "top-left",
129
- showProgress: false,
130
104
  });
131
105
  ```
132
106
 
133
- ## API Overview
107
+ ## API
108
+
109
+ ### `useSoftToast()`
110
+
111
+ Returns a composable instance bound to the Vue component lifecycle.
112
+
113
+ ```typescript
114
+ const toast = useSoftToast();
115
+ ```
116
+
117
+ ### `softToast`
134
118
 
135
- ### `softToast[type](title, options)`
119
+ Singleton — works outside Vue components (e.g. in router guards, Pinia stores, API interceptors).
136
120
 
137
- Available types: `default`, `success`, `error`, `warning`, `info`, `promise`.
121
+ ```typescript
122
+ import { softToast } from "@soft-toast/vue";
123
+
124
+ softToast.error("Session expired", { duration: 6000 });
125
+ ```
138
126
 
139
- **Example:**
127
+ ### Methods
128
+
129
+ | Method | Description |
130
+ | ---------------------------------- | ----------------------------------------------------- |
131
+ | `toast.default(title, options?)` | Default (unstyled) toast |
132
+ | `toast.success(title, options?)` | Success toast |
133
+ | `toast.error(title, options?)` | Error toast |
134
+ | `toast.warning(title, options?)` | Warning toast |
135
+ | `toast.info(title, options?)` | Info toast |
136
+ | `toast.loading(title, options?)` | Persistent loading toast (use `update` to resolve it) |
137
+ | `toast.promise(promise, messages)` | Auto-transitions loading → success / error |
138
+ | `toast.custom(options)` | Full control — pass any `ToastOptions` directly |
139
+ | `toast.update(id, options)` | Update a visible toast by ID |
140
+ | `toast.dismiss(id?)` | Dismiss one toast by ID, or all toasts if omitted |
141
+ | `toast.dismissAll()` | Dismiss all visible toasts |
142
+ | `toast.pause(id)` | Pause the auto-close timer |
143
+ | `toast.resume(id)` | Resume the auto-close timer |
144
+ | `toast.flash(title, options?)` | Queue a toast that shows after the next navigation |
145
+ | `toast.showFlashes()` | Consume and show pending flash messages |
146
+ | `toast.hasFlashes()` | Returns `true` if there are pending flash messages |
147
+
148
+ ### `promise` example
140
149
 
141
150
  ```typescript
142
- softToast.error("Network Error", {
143
- description: "Failed to connect to the server.",
144
- duration: 6000,
145
- action: {
146
- label: "Retry",
147
- onClick: () => retryConnection(),
151
+ toast.promise(api.saveProfile(data), {
152
+ loading: "Saving…",
153
+ success: "Profile saved!",
154
+ error: (err) => `Failed: ${err.message}`,
155
+ description: {
156
+ success: "Your changes are live.",
157
+ error: "Please try again.",
148
158
  },
149
159
  });
150
160
  ```
151
161
 
152
- ### Options
162
+ ### `update` example
153
163
 
154
- | Property | Type | Default | Description |
155
- | --------------- | ---------------------------------------------- | ------------- | -------------------------------------------------------------- |
156
- | `position` | `ToastPosition` | `'top-right'` | Position on screen (e.g. `'top'`, `'bottom-left'`, `'right'`) |
157
- | `duration` | `number` | `4000` | Auto-close delay in ms (`Infinity` disables auto-close) |
158
- | `preset` | `'smooth' \| 'bouncy' \| 'subtle' \| 'snappy'` | `'smooth'` | Motion style |
159
- | `description` | `string \| VNode` | `undefined` | Secondary text below the title |
160
- | `action` | `ToastAction \| ToastAction[]` | `undefined` | Interactive button config (`label`, `onClick`) |
161
- | `showProgress` | `boolean` | `false` | Shows a decreasing progress bar |
162
- | `closeButton` | `boolean \| 'top-left' \| 'top-right'` | `false` | Shows a dismiss button for this toast |
163
- | `showTimestamp` | `boolean` | `false` | Shows the time the toast was created |
164
- | `icon` | `string \| VNode \| Component` | `undefined` | Custom icon string (Iconify `line-md` support) or Component |
164
+ ```typescript
165
+ const id = toast.loading("Uploading…");
165
166
 
166
- ## Icons & Customization
167
+ await uploadFile(file);
167
168
 
168
- Supports **Iconify** icons and custom Vue components.
169
+ toast.update(id, {
170
+ type: "success",
171
+ title: "Upload complete!",
172
+ duration: 3000,
173
+ });
174
+ ```
175
+
176
+ ## Toast Options
177
+
178
+ | Option | Type | Default | Description |
179
+ | --------------- | ---------------------------------------------- | ------------- | --------------------------------------------------------- |
180
+ | `id` | `string` | auto | Custom ID — same ID updates the existing toast |
181
+ | `position` | `ToastPosition` | `'top-right'` | Screen position |
182
+ | `duration` | `number` | `4000` | Auto-close delay in ms (`Infinity` disables auto-close) |
183
+ | `description` | `string \| VNode` | `undefined` | Secondary text below the title |
184
+ | `action` | `ToastAction \| ToastAction[]` | `undefined` | One or more action buttons |
185
+ | `icon` | `string \| VNode \| Component` | `undefined` | Iconify icon string, VNode, or Vue component |
186
+ | `preset` | `'smooth' \| 'bouncy' \| 'subtle' \| 'snappy'` | `'smooth'` | Motion style |
187
+ | `showProgress` | `boolean` | `false` | Decreasing progress bar |
188
+ | `closeButton` | `boolean \| 'top-left' \| 'top-right'` | `false` | Dismiss button position |
189
+ | `showTimestamp` | `boolean` | `false` | Shows creation time |
190
+ | `sound` | `boolean \| string` | `undefined` | `true` for built-in tone, or a URL to a custom audio file |
191
+ | `soundVolume` | `number` | `0.5` | Playback volume (0–1) |
192
+ | `classNames` | `ToastClassNames` | `undefined` | Custom CSS classes for individual parts of the toast |
193
+ | `fillColor` | `string` | `undefined` | Custom fill/accent color |
194
+ | `borderColor` | `string` | `undefined` | Custom border color |
195
+ | `borderWidth` | `number` | `undefined` | Custom border width in px |
196
+ | `onDismiss` | `(id: string) => void` | `undefined` | Called when the toast is manually dismissed |
197
+ | `onAutoClose` | `(id: string) => void` | `undefined` | Called when the toast auto-closes |
198
+
199
+ ### `ToastAction`
200
+
201
+ ```typescript
202
+ {
203
+ label: string;
204
+ onClick: () => void | Promise<void>;
205
+ successLabel?: string; // Replaces button with this text on success, then auto-closes
206
+ primary?: boolean; // Applies primary button styling
207
+ class?: string; // Custom CSS class
208
+ }
209
+ ```
210
+
211
+ ## Icons
212
+
213
+ Supports **Iconify** icon strings and custom Vue components:
169
214
 
170
215
  ```typescript
171
- // 1. Using Iconify icon string
172
- softToast.success("Awesome!", { icon: "line-md:star" });
216
+ // Iconify icon string
217
+ toast.success("Deployed!", { icon: "line-md:rocket-launch" });
173
218
 
174
- // 2. Using a Custom Vue Component
219
+ // Custom Vue component
175
220
  import MyIcon from "./MyIcon.vue";
176
- softToast.info("Custom Icon", { icon: MyIcon });
221
+ toast.info("Update available", { icon: MyIcon });
177
222
  ```
178
223
 
179
- ## Slot Architecture
224
+ ## Flash Messages
180
225
 
181
- `@soft-toast/vue` provides customization slots for `<SoftToastContainer>`.
226
+ Queue a toast that survives a page navigation and shows on the next load:
182
227
 
183
- Available slots: `#icon`, `#title`, `#description`, `#action`, `#close-button`.
228
+ ```typescript
229
+ const toast = useSoftToast();
230
+
231
+ const save = async () => {
232
+ await api.save();
233
+ toast.flash("Changes saved!", { type: "success" });
234
+ router.push("/dashboard");
235
+ };
236
+ ```
184
237
 
185
- When you want to provide slots, disable the plugin's automatic container and render the container in your app layout:
238
+ In `App.vue` or your root layout, consume pending flashes on mount:
239
+
240
+ ```vue
241
+ <script setup lang="ts">
242
+ import { onMounted } from "vue";
243
+ import { useSoftToast } from "@soft-toast/vue";
244
+
245
+ const toast = useSoftToast();
246
+ onMounted(() => toast.showFlashes());
247
+ </script>
248
+ ```
249
+
250
+ Flash messages expire automatically after 30 seconds if not consumed.
251
+
252
+ ## Custom Slots
253
+
254
+ Override any part of the toast UI via named slots on `<SoftToastContainer>`.
255
+
256
+ When using slots, disable the plugin's auto-mounted container and place it manually in your layout:
186
257
 
187
258
  ```typescript
188
- app.use(SoftToastPlugin, {
189
- autoMount: false,
190
- });
259
+ app.use(SoftToastPlugin, { autoMount: false });
191
260
  ```
192
261
 
193
262
  ```vue
263
+ <!-- App.vue or layout -->
194
264
  <SoftToastContainer>
195
265
  <template #icon="{ toast }">
196
- <div class="my-custom-icon">{{ toast.type }}</div>
266
+ <img src="/logo.png" alt="" />
197
267
  </template>
198
268
 
199
269
  <template #title="{ toast }">
@@ -204,42 +274,60 @@ app.use(SoftToastPlugin, {
204
274
  <p>{{ toast.description }}</p>
205
275
  </template>
206
276
 
207
- <!-- Override the close button -->
208
- <template #close-button="{ dismiss }">
209
- <button @click="dismiss" class="my-custom-close-btn">Close</button>
210
- </template>
211
-
212
- <!-- Override the action button -->
213
277
  <template #action="{ toast, execute }">
214
278
  <button
215
279
  v-for="action in Array.isArray(toast.action) ? toast.action : [toast.action]"
216
280
  :key="action.label"
217
281
  @click="execute(action)"
218
- class="my-custom-action-btn"
219
282
  >
220
283
  {{ action.label }}
221
284
  </button>
222
285
  </template>
286
+
287
+ <template #close-button="{ dismiss }">
288
+ <button @click="dismiss">Close</button>
289
+ </template>
223
290
  </SoftToastContainer>
224
291
  ```
225
292
 
226
- Use `slotFilter` when only some toasts should use the custom slot renderer. Toasts that do not match the filter keep the built-in icon, title, action, close button, and swipe behavior:
293
+ Use `slotFilter` to apply custom slots only to specific toasts. Toasts that don't match keep the default rendering:
227
294
 
228
295
  ```vue
229
- <SoftToastContainer :slot-filter="(toast) => toast.id === 'custom-toast'">
296
+ <SoftToastContainer :slot-filter="(toast) => toast.id.startsWith('custom-')">
230
297
  <template #title="{ toast }">
231
298
  <strong>{{ toast.title }}</strong>
232
299
  </template>
233
300
  </SoftToastContainer>
234
301
  ```
235
302
 
303
+ ## Container Props
304
+
305
+ | Prop | Type | Default | Description |
306
+ | ---------------- | ---------------------------------------------- | --------------- | ---------------------------------------------------- |
307
+ | `position` | `ToastPosition` | `'top-right'` | Default position for all toasts |
308
+ | `duration` | `number` | `5000` | Default auto-close delay |
309
+ | `theme` | `'light' \| 'dark'` | `'light'` | Color theme |
310
+ | `preset` | `'smooth' \| 'bouncy' \| 'subtle' \| 'snappy'` | `'smooth'` | Default motion preset |
311
+ | `closeButton` | `boolean \| 'top-left' \| 'top-right'` | `false` | Show close button on all toasts |
312
+ | `showProgress` | `boolean` | `false` | Show progress bar on all toasts |
313
+ | `showTimestamp` | `boolean` | `false` | Show timestamp on all toasts |
314
+ | `closeOnEscape` | `boolean` | `true` | Dismiss the most recent toast on `Escape` |
315
+ | `swipeToDismiss` | `boolean` | `true` | Enable swipe-to-dismiss gesture |
316
+ | `maxQueue` | `number` | `Infinity` | Maximum number of toasts visible at once |
317
+ | `queueOverflow` | `'drop-oldest' \| 'drop-newest'` | `'drop-oldest'` | What to drop when queue is full |
318
+ | `gap` | `number` | `12` | Gap in px between expanded toasts |
319
+ | `offset` | `number \| string` | `'24px'` | Distance from the screen edge |
320
+ | `dir` | `'ltr' \| 'rtl'` | `'ltr'` | Text direction |
321
+ | `slotFilter` | `(toast: Toast) => boolean` | `undefined` | Function to select which toasts receive custom slots |
322
+
236
323
  ## Positions
237
324
 
238
325
  10 available positions:
239
- `top-left`, `top-center`, `top-right`, `bottom-left`, `bottom-center`, `bottom-right`, `top`, `bottom`, `left`, `right`.
326
+
327
+ `top-left` · `top-center` · `top-right` · `bottom-left` · `bottom-center` · `bottom-right` · `top` · `bottom` · `left` · `right`
240
328
 
241
329
  ## License
242
330
 
243
331
  MIT License.
244
332
 
245
- > **Note on GSAP:** This library uses [GSAP](https://greensock.com/gsap/) for animations. GSAP is subject to its own [Standard No-Charge License](https://greensock.com/standard-license/).
333
+ > **Note on GSAP:** This library uses [GSAP](https://greensock.com/gsap/) for animations. GSAP is free for most uses under the [Standard No-Charge License](https://greensock.com/standard-license/).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soft-toast/vue",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Soft, fluid toast notifications for Vue 3 — part of the @soft-toast family",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",