@ailuracode/alpine-toast 1.0.0 → 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 +274 -64
- package/dist/index.d.ts +20 -2
- package/dist/index.js +1 -720
- package/package.json +27 -5
package/README.md
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
1
|
# @ailuracode/alpine-toast
|
|
2
2
|
|
|
3
|
-
Headless in-app toast queue for Alpine.js
|
|
4
|
-
|
|
5
|
-
**CSS-framework agnostic** — no markup, no styles. Only `default`, `bottom-right`, and `promise` are built into the API; you declare variants and positions your UI needs.
|
|
6
|
-
|
|
7
|
-
**[Full documentation →](../../docs/plugins/toast.md)**
|
|
3
|
+
Headless in-app toast queue for Alpine.js. Registers the `$toast` magic and an internal reactive store for UI integrators.
|
|
8
4
|
|
|
9
5
|
## Install
|
|
10
6
|
|
|
11
7
|
```bash
|
|
12
|
-
pnpm add @ailuracode/alpine-toast alpinejs
|
|
8
|
+
pnpm add @ailuracode/alpine-toast @ailuracode/alpine-core alpinejs
|
|
13
9
|
```
|
|
14
10
|
|
|
15
|
-
## Quick
|
|
11
|
+
## Quick start
|
|
16
12
|
|
|
17
|
-
```
|
|
13
|
+
```js
|
|
18
14
|
import Alpine from "alpinejs";
|
|
19
|
-
import {
|
|
15
|
+
import toast, { toastOptions, toastPositions, toastVariants } from "@ailuracode/alpine-toast";
|
|
20
16
|
|
|
21
17
|
Alpine.plugin(
|
|
22
|
-
|
|
23
|
-
variants: toastVariants(["success", "error", "loading"] as const),
|
|
18
|
+
toastOptions({
|
|
19
|
+
variants: toastVariants(["success", "info", "warning", "error", "loading"] as const),
|
|
24
20
|
positions: toastPositions(["top-center", "bottom-right"] as const),
|
|
25
21
|
defaultPosition: "bottom-right",
|
|
26
22
|
promise: {
|
|
@@ -33,82 +29,296 @@ Alpine.plugin(
|
|
|
33
29
|
Alpine.start();
|
|
34
30
|
```
|
|
35
31
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
32
|
+
`toastOptions()`, `toastVariants()`, and `toastPositions()` preserve literal types for strongly typed payloads and `$toast.<variant>()` shortcuts.
|
|
33
|
+
|
|
34
|
+
## CSS-framework agnostic
|
|
35
|
+
|
|
36
|
+
This plugin ships **no HTML, no CSS, and no design tokens**. Variant and position names are **not hardcoded** — you declare the sets your UI needs. The only built-in concepts are:
|
|
37
|
+
|
|
38
|
+
- **`default`** — `$toast('Message')` or `{ variant: 'default' }`
|
|
39
|
+
- **`bottom-right`** — default `position` when omitted
|
|
40
|
+
- **`promise`** — `$toast.promise(factoryOrPromise, messages?)`
|
|
41
|
+
|
|
42
|
+
Map `toast.variant` and `toast.position` to layout/CSS in your own renderer (e.g. `data-position`, Tailwind classes, coordinates).
|
|
43
|
+
|
|
44
|
+
## Magic API
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
$toast("Hello")
|
|
48
|
+
$toast({ title: "Saved", variant: "success", position: "top-center" })
|
|
49
|
+
$toast.success("Saved") // only when "success" is in `variants`
|
|
50
|
+
$toast.dismiss(id)
|
|
51
|
+
$toast.dismissAt("top-center")
|
|
52
|
+
$toast.dismissAll()
|
|
53
|
+
$toast.fromPayload({ title: "Done", variant: "success" })
|
|
54
|
+
await $toast.promise(() => save(), {
|
|
55
|
+
loading: "Saving...",
|
|
56
|
+
success: "Saved",
|
|
57
|
+
error: "Could not save",
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| Method | Description |
|
|
62
|
+
|--------|-------------|
|
|
63
|
+
| `$toast(title, options?)` | Push a `default` toast. Returns the toast id. |
|
|
64
|
+
| `$toast(payload)` | Push with a full payload object. |
|
|
65
|
+
| `$toast.<variant>(title, options?)` | One shortcut per entry in `variants`. |
|
|
66
|
+
| `$toast.dismiss(id)` | Close one toast by id (returned from `$toast()`). |
|
|
67
|
+
| `$toast.update(id, patch)` | Patch the same toast in place (variant, title, content, action, …). |
|
|
68
|
+
| `$toast.dismissAt(position)` | Close every toast in one position stack. |
|
|
69
|
+
| `$toast.dismissAll()` | Close every toast in every stack. |
|
|
70
|
+
| `$toast.pushUnique(key, payload?)` | Dismiss active toasts with the same `key`, then push. |
|
|
71
|
+
| `$toast.fromPayload(payload)` | Push from a plain payload (events, session flash, etc.). |
|
|
72
|
+
| `$toast.promise(factoryOrPromise, messages?)` | `loading` → `success` / `error` on the same toast. |
|
|
73
|
+
|
|
74
|
+
### Payload options
|
|
75
|
+
|
|
76
|
+
| Field | Type | Default |
|
|
77
|
+
|-------|------|---------|
|
|
78
|
+
| `content` | `TContent \| null` | `null` |
|
|
79
|
+
| `title` | `string \| null` | `null` |
|
|
80
|
+
| `description` | `string \| null` | `null` |
|
|
81
|
+
| `variant` | `default \| …your variants` | `default` |
|
|
82
|
+
| `position` | `bottom-right \| …your positions` | `bottom-right` (or `defaultPosition`) |
|
|
83
|
+
| `duration` | `number` (ms) | `4000` (`false` or `0` = no auto-dismiss; stored as `false`) |
|
|
84
|
+
| `action` | `{ label, onClick? }` | `null` |
|
|
85
|
+
| `key` | `string \| null` | `null` — use with `pushUnique` for single-slot toasts |
|
|
86
|
+
|
|
87
|
+
`title` / `description` are optional string shorthands. Use `content` for any shape your renderer understands (objects, arrays, HTML snippets, etc.). The plugin stores it as-is — rendering is up to your UI.
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
type AppToastContent = { user: { name: string; avatar: string } } | { html: string };
|
|
91
|
+
|
|
92
|
+
type Item = ToastItem<typeof variants, typeof positions, AppToastContent>;
|
|
93
|
+
|
|
94
|
+
$toast({
|
|
95
|
+
content: { user: { name: "Ada", avatar: "/ada.png" } },
|
|
96
|
+
variant: "success",
|
|
97
|
+
});
|
|
43
98
|
```
|
|
44
99
|
|
|
45
100
|
```html
|
|
46
|
-
<
|
|
101
|
+
<template x-for="toast in $store.toast.itemsAt(position)" :key="toast.id">
|
|
102
|
+
<div x-show="toast.content?.user">
|
|
103
|
+
<img :src="toast.content.user.avatar" alt="" />
|
|
104
|
+
<span x-text="toast.content.user.name"></span>
|
|
105
|
+
</div>
|
|
106
|
+
<p x-show="toast.title" x-text="toast.title"></p>
|
|
107
|
+
</template>
|
|
47
108
|
```
|
|
48
109
|
|
|
49
|
-
|
|
110
|
+
For `$toast.promise`, optional `loadingContent`, `successContent`, and `errorContent` update the same toast item.
|
|
50
111
|
|
|
51
|
-
##
|
|
112
|
+
## Custom variants
|
|
52
113
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
| **Close** | `$toast.dismiss(id)`, `$toast.dismissAt(position)`, `$toast.dismissAll()` |
|
|
58
|
-
| **Dedupe** | `$toast.pushUnique(key, payload)` — one active toast per key (undo flows) |
|
|
59
|
-
| **Promise** | `$toast.promise(factoryOrPromise, messages?)` |
|
|
60
|
-
| **Variants** | `variants: toastVariants([...])` → `$toast.<name>()` |
|
|
61
|
-
| **Positions** | `positions: toastPositions([...])` → one stack per position |
|
|
62
|
-
| **Queue** | `maxToasts` / `maxVisible` per timed or persistent stack |
|
|
63
|
-
| **UI** | Bring your own markup and CSS |
|
|
114
|
+
```ts
|
|
115
|
+
import toast, { toastOptions, toastVariants, type ToastMagic } from "@ailuracode/alpine-toast";
|
|
116
|
+
|
|
117
|
+
const variants = toastVariants(["queued", "published", "failed"] as const);
|
|
64
118
|
|
|
65
|
-
|
|
119
|
+
Alpine.plugin(toast({ variants }));
|
|
120
|
+
|
|
121
|
+
type AppToast = ToastMagic<typeof variants>;
|
|
122
|
+
// AppToast has .queued(), .published(), .failed()
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Without `variants`, only `$toast()`, `$toast.promise()`, `$toast.dismiss()`, and `$toast.fromPayload()` are available.
|
|
126
|
+
|
|
127
|
+
## Custom positions
|
|
128
|
+
|
|
129
|
+
Each declared position gets its **own stack**. `maxToasts` and `maxVisible` apply **per position**, not globally.
|
|
66
130
|
|
|
67
131
|
```ts
|
|
68
|
-
import {
|
|
132
|
+
import toast, { toastPositions, type ToastPosition } from "@ailuracode/alpine-toast";
|
|
133
|
+
|
|
134
|
+
const positions = toastPositions(["top-center", "bottom-right"] as const);
|
|
135
|
+
|
|
136
|
+
Alpine.plugin(
|
|
137
|
+
toast({
|
|
138
|
+
positions,
|
|
139
|
+
defaultPosition: "bottom-right",
|
|
140
|
+
})
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
type AppPosition = ToastPosition<typeof positions>;
|
|
144
|
+
// "bottom-right" | "top-center"
|
|
145
|
+
```
|
|
69
146
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
147
|
+
The plugin stores the position id on each toast. Render one stack per position in your UI:
|
|
148
|
+
|
|
149
|
+
```html
|
|
150
|
+
<template x-for="position in $store.toast.stackPositions" :key="position">
|
|
151
|
+
<div
|
|
152
|
+
x-bind:data-position="position"
|
|
153
|
+
x-bind:class="{
|
|
154
|
+
'fixed top-4 left-1/2 -translate-x-1/2': position === 'top-center',
|
|
155
|
+
'fixed bottom-4 right-4': position === 'bottom-right',
|
|
156
|
+
}"
|
|
157
|
+
>
|
|
158
|
+
<template x-for="(toast, index) in $store.toast.itemsAt(position)" :key="toast.id">
|
|
159
|
+
<div x-show="!toast.removed && $store.toast.isVisibleAt(position, index)">
|
|
160
|
+
<p x-text="toast.title"></p>
|
|
161
|
+
</div>
|
|
162
|
+
</template>
|
|
163
|
+
</div>
|
|
164
|
+
</template>
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
| Store API | Description |
|
|
168
|
+
|-----------|-------------|
|
|
169
|
+
| `stackPositions` | All stack keys (`defaultPosition` + `positions`) |
|
|
170
|
+
| `itemsAt(position)` | Toasts in that stack, newest first (includes exiting `removed` items) |
|
|
171
|
+
| `timedItemsAt(position)` | Auto-dismiss stack — same order, includes exiting items |
|
|
172
|
+
| `persistentItemsAt(position)` | Persistent stack (`duration: false`) — includes exiting items |
|
|
173
|
+
| `activeTimedItemsAt(position)` | Timed stack without `removed` items — preferred for simple `x-for` |
|
|
174
|
+
| `activePersistentItemsAt(position)` | Persistent stack without `removed` items |
|
|
175
|
+
| `isVisibleAt(position, index)` | Timed stack only — peek/limit visibility (`maxVisible`) |
|
|
176
|
+
| `pushUnique(key, payload?)` | Same as `$toast.pushUnique` |
|
|
177
|
+
| `destroy()` | Clear timers — call when tearing down the plugin |
|
|
178
|
+
| `dismiss(id)` | Close one toast (same as `$toast.dismiss`) |
|
|
179
|
+
| `dismissAt(position)` | Close one entire position (timed + persistent) |
|
|
180
|
+
| `dismissAll()` | Close all stacks |
|
|
181
|
+
|
|
182
|
+
## Promise flow
|
|
183
|
+
|
|
184
|
+
Configure default promise variants in plugin options, or override per call:
|
|
185
|
+
|
|
186
|
+
```js
|
|
187
|
+
Alpine.plugin(
|
|
188
|
+
toast({
|
|
189
|
+
variants: toastVariants(["loading", "success", "error"] as const),
|
|
190
|
+
promise: {
|
|
191
|
+
loading: "Loading...",
|
|
192
|
+
error: "Something went wrong",
|
|
193
|
+
loadingVariant: "loading",
|
|
194
|
+
successVariant: "success",
|
|
195
|
+
errorVariant: "error",
|
|
196
|
+
duration: 4000,
|
|
197
|
+
},
|
|
198
|
+
})
|
|
199
|
+
);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```js
|
|
203
|
+
await $toast.promise(() => save(), {
|
|
204
|
+
loading: "Saving...",
|
|
205
|
+
success: (data) => `Saved ${data.id}`,
|
|
206
|
+
error: "Could not save",
|
|
73
207
|
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
If a named variant is missing from `variants`, promise states fall back to `default`.
|
|
211
|
+
|
|
212
|
+
On failure, the toast updates to the error state and the returned promise **rejects** with the original error so callers can still use `try/catch` or `.catch()`.
|
|
213
|
+
|
|
214
|
+
The **loading** state uses a long timed duration (`PROMISE_LOADING_DURATION`) so it stays in the **timed stack** (not perpetual). The timer is replaced when the promise settles to success or error.
|
|
215
|
+
|
|
216
|
+
Reserved variant names (`dismiss`, `update`, `dismissAt`, `dismissAll`, `fromPayload`, `promise`) cannot override core `$toast` methods.
|
|
217
|
+
|
|
218
|
+
In Alpine templates, wrap multi-argument calls in an arrow function:
|
|
219
|
+
|
|
220
|
+
```html
|
|
221
|
+
<button
|
|
222
|
+
@click="() => $toast.promise(() => save(), { loading: 'Saving...', success: 'Saved!' })"
|
|
223
|
+
>
|
|
224
|
+
Save
|
|
225
|
+
</button>
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Queue limits
|
|
229
|
+
|
|
230
|
+
Each **position** has two independent stacks:
|
|
231
|
+
|
|
232
|
+
1. **Timed** — auto-dismiss toasts (`duration > 0`). `maxVisible` applies here (peek/stack UI).
|
|
233
|
+
2. **Persistent** — `duration: false` (or `0` in payloads; normalized to `false`). Always fully visible in your UI.
|
|
234
|
+
|
|
235
|
+
`maxToasts` applies **per stack per position** (not globally). Example: `maxToasts: 5` allows up to 5 timed + 5 persistent toasts at `bottom-right`.
|
|
236
|
+
|
|
237
|
+
| Option | Default | Description |
|
|
238
|
+
|--------|---------|-------------|
|
|
239
|
+
| `maxToasts` | `5` | Maximum active toasts **per stack per position**. `0` = unlimited. |
|
|
240
|
+
| `maxVisible` | `maxToasts` | Maximum timed toasts shown at once per position (`isVisibleAt`). |
|
|
241
|
+
|
|
242
|
+
Use `activeTimedItemsAt` / `activePersistentItemsAt` when your renderer does not need exiting (`removed`) items. Keep `timedItemsAt` / `persistentItemsAt` when you animate dismiss (Sonner-style).
|
|
243
|
+
|
|
244
|
+
## Window events
|
|
245
|
+
|
|
246
|
+
```js
|
|
247
|
+
window.dispatchEvent(
|
|
248
|
+
new CustomEvent("toast", {
|
|
249
|
+
detail: { title: "From anywhere", variant: "success", position: "top-center" },
|
|
250
|
+
})
|
|
251
|
+
);
|
|
252
|
+
```
|
|
74
253
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
254
|
+
Disable with `toast({ listenToWindowEvents: false })`.
|
|
255
|
+
|
|
256
|
+
## Rendering UI
|
|
257
|
+
|
|
258
|
+
```html
|
|
259
|
+
<template x-for="position in $store.toast.stackPositions" :key="position">
|
|
260
|
+
<div
|
|
261
|
+
role="region"
|
|
262
|
+
x-bind:aria-label="'Toasts ' + position"
|
|
263
|
+
x-bind:data-position="position"
|
|
264
|
+
>
|
|
265
|
+
<template x-for="(toast, index) in $store.toast.itemsAt(position)" :key="toast.id">
|
|
266
|
+
<div
|
|
267
|
+
role="status"
|
|
268
|
+
x-show="!toast.removed && $store.toast.isVisibleAt(position, index)"
|
|
269
|
+
x-bind:data-variant="toast.variant"
|
|
270
|
+
>
|
|
271
|
+
<p x-text="toast.title"></p>
|
|
272
|
+
</div>
|
|
273
|
+
</template>
|
|
274
|
+
</div>
|
|
275
|
+
</template>
|
|
78
276
|
```
|
|
79
277
|
|
|
278
|
+
Style `[data-variant="…"]` and `[data-position="…"]` in your own CSS or component library.
|
|
279
|
+
|
|
80
280
|
## Plugin options
|
|
81
281
|
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
282
|
+
```js
|
|
283
|
+
Alpine.plugin(
|
|
284
|
+
toast({
|
|
285
|
+
variants: toastVariants(["success", "error"] as const),
|
|
286
|
+
positions: toastPositions(["top-center", "bottom-right"] as const),
|
|
287
|
+
defaultPosition: "bottom-right",
|
|
288
|
+
defaultDuration: 5000,
|
|
289
|
+
maxToasts: 5,
|
|
290
|
+
maxVisible: 3,
|
|
291
|
+
listenToWindowEvents: true,
|
|
292
|
+
storeKey: "toast",
|
|
293
|
+
magicKey: "toast",
|
|
294
|
+
promise: {
|
|
295
|
+
loadingVariant: "success",
|
|
296
|
+
successVariant: "success",
|
|
297
|
+
errorVariant: "error",
|
|
298
|
+
},
|
|
299
|
+
})
|
|
300
|
+
);
|
|
99
301
|
```
|
|
100
302
|
|
|
101
|
-
|
|
303
|
+
### Avoiding name collisions
|
|
304
|
+
|
|
305
|
+
If your application already owns a `$toast` store or magic — or another toolkit plugin registers on that name — rename the integration surface without touching the controller:
|
|
102
306
|
|
|
103
307
|
```ts
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
308
|
+
Alpine.plugin(
|
|
309
|
+
toast({
|
|
310
|
+
storeKey: "alerts", // → $store.alerts
|
|
311
|
+
magicKey: "snack", // → $snack
|
|
312
|
+
}),
|
|
313
|
+
);
|
|
110
314
|
```
|
|
111
315
|
|
|
316
|
+
The exposed constants `TOAST_STORE_KEY` and `TOAST_MAGIC_KEY` keep the renames discoverable from TypeScript.
|
|
317
|
+
|
|
318
|
+
## Related packages
|
|
319
|
+
|
|
320
|
+
- [`@ailuracode/alpine-notify`](./notify.md) — OS-level Web Notifications (`$notify`)
|
|
321
|
+
|
|
112
322
|
## License
|
|
113
323
|
|
|
114
324
|
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Alpine, Unsubscribe, PluginCallback, BaseController } from '@ailuracode/alpine-core';
|
|
1
|
+
import { SingletonScope, Alpine, Unsubscribe, PluginCallback, BaseController } from '@ailuracode/alpine-core';
|
|
2
2
|
export { Unsubscribe } from '@ailuracode/alpine-core';
|
|
3
3
|
import { Alpine as Alpine$1 } from 'alpinejs';
|
|
4
4
|
|
|
@@ -13,7 +13,10 @@ import { Alpine as Alpine$1 } from 'alpinejs';
|
|
|
13
13
|
|
|
14
14
|
/** Built-in Alpine store key for the toast queue. */
|
|
15
15
|
declare const TOAST_STORE_KEY: "toast";
|
|
16
|
+
/** Built-in `$toast` magic key registered by {@link toastPlugin}. */
|
|
17
|
+
declare const TOAST_MAGIC_KEY: "toast";
|
|
16
18
|
type ToastStoreKey = typeof TOAST_STORE_KEY;
|
|
19
|
+
type ToastMagicKey = typeof TOAST_MAGIC_KEY;
|
|
17
20
|
/** Built-in position used when none is provided. Map to CSS in your UI layer. */
|
|
18
21
|
type DefaultToastPosition = "bottom-right";
|
|
19
22
|
/** Union of `bottom-right` plus developer-defined positions from plugin options. */
|
|
@@ -87,6 +90,14 @@ interface ToastPluginOptions<TVariants extends readonly string[] = readonly [],
|
|
|
87
90
|
listenToWindowEvents?: boolean;
|
|
88
91
|
/** Internal store key. Default: `"toast"`. */
|
|
89
92
|
storeKey?: ToastStoreKey;
|
|
93
|
+
/**
|
|
94
|
+
* `$toast` magic key the Alpine plugin registers under. Defaults to
|
|
95
|
+
* {@link TOAST_MAGIC_KEY}. Set when the host already owns a `toast`
|
|
96
|
+
* magic or another toolkit plugin would collide on that name — the
|
|
97
|
+
* rename avoids the collision without touching the controller.
|
|
98
|
+
* Ignored by the standalone `createToastController` helper.
|
|
99
|
+
*/
|
|
100
|
+
magicKey?: string;
|
|
90
101
|
}
|
|
91
102
|
interface ToastPromiseMessages<T = unknown, TVariant extends string = string, TContent = unknown> {
|
|
92
103
|
loading?: string;
|
|
@@ -166,6 +177,7 @@ type ResolvedToastPluginConfig<TVariants extends readonly string[] = readonly []
|
|
|
166
177
|
maxVisible: number;
|
|
167
178
|
listenToWindowEvents: boolean;
|
|
168
179
|
storeKey: ToastStoreKey;
|
|
180
|
+
magicKey: string;
|
|
169
181
|
variants: TVariants;
|
|
170
182
|
positions: TPositions;
|
|
171
183
|
promise: ResolvedPromiseConfig<TVariants>;
|
|
@@ -220,6 +232,12 @@ interface CreateToastControllerOptions<TPositions extends readonly string[] = re
|
|
|
220
232
|
* the store in a proxy and observe timer-fired dismissals.
|
|
221
233
|
*/
|
|
222
234
|
readonly getStore?: () => ToastStore<readonly [], TPositions, unknown>;
|
|
235
|
+
/**
|
|
236
|
+
* Singleton scope for this controller. Defaults to the active
|
|
237
|
+
* `document`, an ambient `runWithSingletonScope()` context, or —
|
|
238
|
+
* in SSR — must be provided explicitly as a plain object.
|
|
239
|
+
*/
|
|
240
|
+
readonly scope?: SingletonScope;
|
|
223
241
|
}
|
|
224
242
|
/**
|
|
225
243
|
* Public, framework-agnostic manager returned by {@link createToastController}.
|
|
@@ -572,4 +590,4 @@ declare function toastPlugin<const TVariants extends readonly string[] = readonl
|
|
|
572
590
|
*/
|
|
573
591
|
declare function createToastMagic<const TVariants extends readonly string[], const TPositions extends readonly string[] = readonly [], TContent = unknown>(config: ResolvedToastPluginConfig<TVariants, TPositions>, getStore: () => ToastStore<TVariants, TPositions, TContent>): ToastMagic<TVariants, TPositions, TContent>;
|
|
574
592
|
|
|
575
|
-
export { type CreateToastControllerOptions, type CreateToastStoreOptions, type DefaultToastPosition, type DefaultToastVariant, PROMISE_LOADING_DURATION, RESERVED_TOAST_MAGIC_KEYS, type ResolvedPromiseConfig, type ResolvedToastPluginConfig, TOAST_STORE_KEY, type ToastAction, type ToastAlpine, type ToastChangeDetail, type ToastChangeSource, ToastController, type ToastDuration, type ToastEventPayload, type ToastEvents, type ToastItem, type ToastListener, type ToastMagic, type ToastManager, type ToastPayload, type ToastPayloadWithoutVariant, type ToastPluginCallback, type ToastPluginOptions, type ToastPosition, type ToastPromiseInput, type ToastPromiseMessages, type ToastPromiseOptions, type ToastStore, type ToastStoreKey, type ToastVariant, type ToastVariantMethods, createToastController, createToastMagic, createToastStore, toastPlugin as default, isPersistentDuration, normalizeToastDuration, resolveStackPositions, resolveToastDuration, resolveToastLimits, resolveToastPluginConfig, shouldAutoDismiss, toastOptions, toastPlugin, toastPositions, toastVariants, wrapToastStore };
|
|
593
|
+
export { type CreateToastControllerOptions, type CreateToastStoreOptions, type DefaultToastPosition, type DefaultToastVariant, PROMISE_LOADING_DURATION, RESERVED_TOAST_MAGIC_KEYS, type ResolvedPromiseConfig, type ResolvedToastPluginConfig, TOAST_MAGIC_KEY, TOAST_STORE_KEY, type ToastAction, type ToastAlpine, type ToastChangeDetail, type ToastChangeSource, ToastController, type ToastDuration, type ToastEventPayload, type ToastEvents, type ToastItem, type ToastListener, type ToastMagic, type ToastMagicKey, type ToastManager, type ToastPayload, type ToastPayloadWithoutVariant, type ToastPluginCallback, type ToastPluginOptions, type ToastPosition, type ToastPromiseInput, type ToastPromiseMessages, type ToastPromiseOptions, type ToastStore, type ToastStoreKey, type ToastVariant, type ToastVariantMethods, createToastController, createToastMagic, createToastStore, toastPlugin as default, isPersistentDuration, normalizeToastDuration, resolveStackPositions, resolveToastDuration, resolveToastLimits, resolveToastPluginConfig, shouldAutoDismiss, toastOptions, toastPlugin, toastPositions, toastVariants, wrapToastStore };
|
package/dist/index.js
CHANGED
|
@@ -1,720 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
BaseController,
|
|
4
|
-
clearSingleton,
|
|
5
|
-
createSingleton,
|
|
6
|
-
generateId
|
|
7
|
-
} from "@ailuracode/alpine-core";
|
|
8
|
-
|
|
9
|
-
// src/types.ts
|
|
10
|
-
var TOAST_STORE_KEY = "toast";
|
|
11
|
-
|
|
12
|
-
// src/controller.ts
|
|
13
|
-
var DISMISS_DELAY_MS = 400;
|
|
14
|
-
var DEFAULT_MAX_TOASTS = 5;
|
|
15
|
-
var DEFAULT_DURATION_MS = 4e3;
|
|
16
|
-
var TOAST_SINGLETON_KEY = "@ailuracode/alpine-toast/default";
|
|
17
|
-
function createToastController(options = {}) {
|
|
18
|
-
return createSingleton(TOAST_SINGLETON_KEY, () => {
|
|
19
|
-
const controller = new ToastController(options);
|
|
20
|
-
controller.mount();
|
|
21
|
-
return controller;
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
var ToastController = class extends BaseController {
|
|
25
|
-
#defaultPosition;
|
|
26
|
-
#stackPositions;
|
|
27
|
-
#defaultDuration;
|
|
28
|
-
#maxToasts;
|
|
29
|
-
#maxVisible;
|
|
30
|
-
#storeKey;
|
|
31
|
-
#listenToWindowEvents;
|
|
32
|
-
#getStore;
|
|
33
|
-
#dismissTimers = /* @__PURE__ */ new Map();
|
|
34
|
-
#purgeTimers = /* @__PURE__ */ new Map();
|
|
35
|
-
#items = [];
|
|
36
|
-
constructor(options) {
|
|
37
|
-
super(options.id ?? generateId("toast"));
|
|
38
|
-
this.#defaultPosition = options.defaultPosition ?? "bottom-right";
|
|
39
|
-
this.#stackPositions = resolveStackPositions(this.#defaultPosition, options.positions);
|
|
40
|
-
this.#defaultDuration = options.defaultDuration ?? DEFAULT_DURATION_MS;
|
|
41
|
-
const limits = resolveToastLimits({
|
|
42
|
-
maxToasts: options.maxToasts,
|
|
43
|
-
maxVisible: options.maxVisible
|
|
44
|
-
});
|
|
45
|
-
this.#maxToasts = limits.maxToasts;
|
|
46
|
-
this.#maxVisible = limits.maxVisible;
|
|
47
|
-
this.#storeKey = options.storeKey ?? TOAST_STORE_KEY;
|
|
48
|
-
this.#listenToWindowEvents = options.listenToWindowEvents !== false;
|
|
49
|
-
this.#getStore = options.getStore;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Tears down every side effect. Idempotent. `super.destroy()` runs
|
|
53
|
-
* the registered cleanups (currently just the window listener)
|
|
54
|
-
* first; the timer cleanup runs as a final step. Also releases
|
|
55
|
-
* the singleton slot so the next `createToastController()` call
|
|
56
|
-
* builds a fresh controller.
|
|
57
|
-
*/
|
|
58
|
-
destroy() {
|
|
59
|
-
if (this.isDestroyed) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
super.destroy();
|
|
63
|
-
this.#clearAllTimers();
|
|
64
|
-
clearSingleton(TOAST_SINGLETON_KEY);
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Starts the controller's side effects. The constructor leaves
|
|
68
|
-
* `#items` empty; `mount()` registers the `toast` window event
|
|
69
|
-
* listener (when enabled) and emits the initialization event.
|
|
70
|
-
*
|
|
71
|
-
* Calling `mount()` more than once is a no-op — `BaseController`
|
|
72
|
-
* guards the phase. Calling it after `destroy()` throws.
|
|
73
|
-
*/
|
|
74
|
-
mount() {
|
|
75
|
-
if (this.isMounted) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
super.mount();
|
|
79
|
-
if (this.#listenToWindowEvents && typeof window !== "undefined") {
|
|
80
|
-
const abort = new AbortController();
|
|
81
|
-
const handler = (event) => {
|
|
82
|
-
if (event instanceof CustomEvent) {
|
|
83
|
-
this.fromPayload(event.detail ?? {});
|
|
84
|
-
}
|
|
85
|
-
};
|
|
86
|
-
window.addEventListener("toast", handler, { signal: abort.signal });
|
|
87
|
-
this.registerCleanup(() => abort.abort());
|
|
88
|
-
}
|
|
89
|
-
queueMicrotask(() => {
|
|
90
|
-
if (this.isDestroyed) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
this.#emitChange("initialization");
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
// ── Public state surface ────────────────────────────────────────
|
|
97
|
-
get defaultPosition() {
|
|
98
|
-
return this.#defaultPosition;
|
|
99
|
-
}
|
|
100
|
-
get stackPositions() {
|
|
101
|
-
return this.#stackPositions;
|
|
102
|
-
}
|
|
103
|
-
get maxToasts() {
|
|
104
|
-
return this.#maxToasts;
|
|
105
|
-
}
|
|
106
|
-
get maxVisible() {
|
|
107
|
-
return this.#maxVisible;
|
|
108
|
-
}
|
|
109
|
-
get items() {
|
|
110
|
-
return this.#items;
|
|
111
|
-
}
|
|
112
|
-
// ── Public commands ─────────────────────────────────────────────
|
|
113
|
-
push(payload = {}) {
|
|
114
|
-
if (this.isDestroyed) {
|
|
115
|
-
return "";
|
|
116
|
-
}
|
|
117
|
-
const position = payload.position ?? this.#defaultPosition;
|
|
118
|
-
const id = generateId("toast");
|
|
119
|
-
const toast = {
|
|
120
|
-
id,
|
|
121
|
-
key: payload.key ?? null,
|
|
122
|
-
content: payload.content ?? null,
|
|
123
|
-
title: payload.title ?? null,
|
|
124
|
-
description: payload.description ?? null,
|
|
125
|
-
variant: payload.variant ?? "default",
|
|
126
|
-
position,
|
|
127
|
-
duration: resolveToastDuration(payload.duration, this.#defaultDuration),
|
|
128
|
-
action: payload.action ?? null,
|
|
129
|
-
removed: false
|
|
130
|
-
};
|
|
131
|
-
this.#items = [toast, ...this.#items];
|
|
132
|
-
this.#enforcePositionLimit(
|
|
133
|
-
position,
|
|
134
|
-
shouldAutoDismiss(toast.duration) ? "timed" : "persistent"
|
|
135
|
-
);
|
|
136
|
-
this.#scheduleDismiss(id, toast.duration);
|
|
137
|
-
this.#emitChange("push");
|
|
138
|
-
return id;
|
|
139
|
-
}
|
|
140
|
-
pushUnique(key, payload = {}) {
|
|
141
|
-
if (this.isDestroyed) {
|
|
142
|
-
return "";
|
|
143
|
-
}
|
|
144
|
-
const activeIds = this.#items.filter((item) => !item.removed && item.key === key).map((item) => item.id);
|
|
145
|
-
this.#markRemoved(activeIds);
|
|
146
|
-
return this.push({ ...payload, key });
|
|
147
|
-
}
|
|
148
|
-
update(id, payload = {}) {
|
|
149
|
-
if (this.isDestroyed) {
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
const current = this.#items.find((toast) => toast.id === id);
|
|
153
|
-
if (!current) {
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
const previousPosition = current.position;
|
|
157
|
-
const wasPersistent = isPersistentDuration(current.duration);
|
|
158
|
-
this.#items = this.#items.map(
|
|
159
|
-
(item) => item.id === id ? applyToastPatch(item, payload) : item
|
|
160
|
-
);
|
|
161
|
-
const updated = this.#items.find((toast) => toast.id === id);
|
|
162
|
-
if (!updated) {
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
const nextPosition = updated.position;
|
|
166
|
-
const isNowPersistent = isPersistentDuration(updated.duration);
|
|
167
|
-
const durationStackChanged = payload.duration !== void 0 && wasPersistent !== isNowPersistent;
|
|
168
|
-
const positionChanged = nextPosition !== previousPosition;
|
|
169
|
-
if (positionChanged) {
|
|
170
|
-
this.#enforcePositionLimit(previousPosition, "timed");
|
|
171
|
-
this.#enforcePositionLimit(previousPosition, "persistent");
|
|
172
|
-
}
|
|
173
|
-
if (positionChanged || durationStackChanged) {
|
|
174
|
-
this.#enforcePositionLimit(nextPosition, "timed");
|
|
175
|
-
this.#enforcePositionLimit(nextPosition, "persistent");
|
|
176
|
-
}
|
|
177
|
-
if (payload.duration !== void 0) {
|
|
178
|
-
this.#scheduleDismiss(id, updated.duration);
|
|
179
|
-
}
|
|
180
|
-
this.#emitChange("update");
|
|
181
|
-
}
|
|
182
|
-
dismiss(id) {
|
|
183
|
-
if (this.isDestroyed) {
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
this.#markRemoved([id]);
|
|
187
|
-
this.#emitChange("dismiss");
|
|
188
|
-
}
|
|
189
|
-
dismissAt(position) {
|
|
190
|
-
if (this.isDestroyed) {
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
const ids = this.itemsAt(position).filter((item) => !item.removed).map((item) => item.id);
|
|
194
|
-
this.#markRemoved(ids);
|
|
195
|
-
this.#emitChange("dismissAt");
|
|
196
|
-
}
|
|
197
|
-
dismissAll() {
|
|
198
|
-
if (this.isDestroyed) {
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
const ids = this.#items.filter((item) => !item.removed).map((item) => item.id);
|
|
202
|
-
this.#markRemoved(ids);
|
|
203
|
-
this.#emitChange("dismissAll");
|
|
204
|
-
}
|
|
205
|
-
// ── Query helpers ───────────────────────────────────────────────
|
|
206
|
-
itemsAt(position) {
|
|
207
|
-
return this.#items.filter((item) => item.position === position);
|
|
208
|
-
}
|
|
209
|
-
timedItemsAt(position) {
|
|
210
|
-
return this.itemsAt(position).filter((item) => shouldAutoDismiss(item.duration));
|
|
211
|
-
}
|
|
212
|
-
persistentItemsAt(position) {
|
|
213
|
-
return this.itemsAt(position).filter((item) => isPersistentDuration(item.duration));
|
|
214
|
-
}
|
|
215
|
-
activeTimedItemsAt(position) {
|
|
216
|
-
return this.timedItemsAt(position).filter((item) => !item.removed);
|
|
217
|
-
}
|
|
218
|
-
activePersistentItemsAt(position) {
|
|
219
|
-
return this.persistentItemsAt(position).filter((item) => !item.removed);
|
|
220
|
-
}
|
|
221
|
-
isVisibleAt(position, index) {
|
|
222
|
-
const stack = this.timedItemsAt(position);
|
|
223
|
-
const item = stack[index];
|
|
224
|
-
if (!item || item.removed) {
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
if (this.#maxVisible <= 0) {
|
|
228
|
-
return true;
|
|
229
|
-
}
|
|
230
|
-
let rank = 0;
|
|
231
|
-
for (let i = 0; i <= index; i++) {
|
|
232
|
-
if (stack[i] && !stack[i].removed) {
|
|
233
|
-
rank++;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
return rank <= this.#maxVisible;
|
|
237
|
-
}
|
|
238
|
-
/**
|
|
239
|
-
* Public escape hatch for callers (mainly the magic's `fromPayload`)
|
|
240
|
-
* that need to push a toast from a raw `ToastEventPayload` shape.
|
|
241
|
-
*/
|
|
242
|
-
fromPayload(payload = {}) {
|
|
243
|
-
const { title = null, content = null, variant = "default", ...options } = payload;
|
|
244
|
-
return this.push({
|
|
245
|
-
title,
|
|
246
|
-
content,
|
|
247
|
-
variant,
|
|
248
|
-
...options
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
// ── Internals ───────────────────────────────────────────────────
|
|
252
|
-
#emitChange(source) {
|
|
253
|
-
if (this.isDestroyed) {
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
const detail = {
|
|
257
|
-
source,
|
|
258
|
-
items: this.#items
|
|
259
|
-
};
|
|
260
|
-
this.emit("change", detail);
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Marks the given ids as `removed`. Schedules a purge timer so
|
|
264
|
-
* they drop out of the queue after `DISMISS_DELAY_MS`. Does NOT
|
|
265
|
-
* emit — the caller (push / update / dismiss / dismissAt /
|
|
266
|
-
* dismissAll / pushUnique) emits once after the mutation
|
|
267
|
-
* completes to avoid event storms on bulk dismisses.
|
|
268
|
-
*/
|
|
269
|
-
#markRemoved(ids) {
|
|
270
|
-
if (ids.length === 0) {
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
const idsToRemove = [];
|
|
274
|
-
for (const id of ids) {
|
|
275
|
-
const toast = this.#items.find((item) => item.id === id);
|
|
276
|
-
if (!toast || toast.removed) {
|
|
277
|
-
continue;
|
|
278
|
-
}
|
|
279
|
-
this.#clearDismissTimer(id);
|
|
280
|
-
idsToRemove.push(id);
|
|
281
|
-
}
|
|
282
|
-
if (idsToRemove.length === 0) {
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
const removeSet = new Set(idsToRemove);
|
|
286
|
-
this.#items = this.#items.map(
|
|
287
|
-
(item) => removeSet.has(item.id) ? { ...item, removed: true } : item
|
|
288
|
-
);
|
|
289
|
-
const batchId = generateId("toast-purge");
|
|
290
|
-
const timer = setTimeout(() => {
|
|
291
|
-
this.#purgeTimers.delete(batchId);
|
|
292
|
-
if (this.isDestroyed) {
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
this.#items = this.#items.filter((item) => !removeSet.has(item.id));
|
|
296
|
-
this.#emitChange("dismiss");
|
|
297
|
-
}, DISMISS_DELAY_MS);
|
|
298
|
-
this.#purgeTimers.set(batchId, timer);
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* Trims the active timed or persistent stack at `position` so it
|
|
302
|
-
* doesn't exceed `maxToasts`. Overflow items are marked as
|
|
303
|
-
* `removed` (with the standard delay before purge) — no exception
|
|
304
|
-
* is thrown.
|
|
305
|
-
*/
|
|
306
|
-
#enforcePositionLimit(position, stack) {
|
|
307
|
-
if (this.#maxToasts <= 0) {
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
const itemsAtPosition = this.itemsAt(position);
|
|
311
|
-
const stackItems = stack === "persistent" ? itemsAtPosition.filter((item) => isPersistentDuration(item.duration)) : itemsAtPosition.filter((item) => shouldAutoDismiss(item.duration));
|
|
312
|
-
const activeAtPosition = stackItems.filter((item) => !item.removed);
|
|
313
|
-
const overflowIds = activeAtPosition.slice(this.#maxToasts).map((item) => item.id);
|
|
314
|
-
this.#markRemoved(overflowIds);
|
|
315
|
-
}
|
|
316
|
-
#scheduleDismiss(id, duration) {
|
|
317
|
-
this.#clearDismissTimer(id);
|
|
318
|
-
if (duration === PROMISE_LOADING_DURATION) {
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
if (shouldAutoDismiss(duration)) {
|
|
322
|
-
const timer = setTimeout(() => {
|
|
323
|
-
this.#dismissTimers.delete(id);
|
|
324
|
-
if (this.isDestroyed) {
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
const target = this.#getStore?.() ?? null;
|
|
328
|
-
if (target) {
|
|
329
|
-
target.dismiss(id);
|
|
330
|
-
} else {
|
|
331
|
-
this.dismiss(id);
|
|
332
|
-
}
|
|
333
|
-
}, duration);
|
|
334
|
-
this.#dismissTimers.set(id, timer);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
#clearDismissTimer(id) {
|
|
338
|
-
const timer = this.#dismissTimers.get(id);
|
|
339
|
-
if (timer !== void 0) {
|
|
340
|
-
clearTimeout(timer);
|
|
341
|
-
this.#dismissTimers.delete(id);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
#clearAllTimers() {
|
|
345
|
-
for (const timer of this.#dismissTimers.values()) {
|
|
346
|
-
clearTimeout(timer);
|
|
347
|
-
}
|
|
348
|
-
this.#dismissTimers.clear();
|
|
349
|
-
for (const timer of this.#purgeTimers.values()) {
|
|
350
|
-
clearTimeout(timer);
|
|
351
|
-
}
|
|
352
|
-
this.#purgeTimers.clear();
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
function wrapToastStore(controller) {
|
|
356
|
-
const store = {
|
|
357
|
-
defaultPosition: controller.defaultPosition,
|
|
358
|
-
stackPositions: controller.stackPositions,
|
|
359
|
-
maxToasts: controller.maxToasts,
|
|
360
|
-
maxVisible: controller.maxVisible,
|
|
361
|
-
items: [...controller.items],
|
|
362
|
-
push(payload) {
|
|
363
|
-
return controller.push(payload);
|
|
364
|
-
},
|
|
365
|
-
pushUnique(key, payload) {
|
|
366
|
-
return controller.pushUnique(key, payload ?? {});
|
|
367
|
-
},
|
|
368
|
-
update(id, payload) {
|
|
369
|
-
controller.update(id, payload);
|
|
370
|
-
},
|
|
371
|
-
dismiss(id) {
|
|
372
|
-
controller.dismiss(id);
|
|
373
|
-
},
|
|
374
|
-
dismissAt(position) {
|
|
375
|
-
controller.dismissAt(position);
|
|
376
|
-
},
|
|
377
|
-
dismissAll() {
|
|
378
|
-
controller.dismissAll();
|
|
379
|
-
},
|
|
380
|
-
destroy() {
|
|
381
|
-
unsubscribe();
|
|
382
|
-
controller.destroy();
|
|
383
|
-
},
|
|
384
|
-
itemsAt(position) {
|
|
385
|
-
return this.items.filter((item) => item.position === position);
|
|
386
|
-
},
|
|
387
|
-
timedItemsAt(position) {
|
|
388
|
-
return this.itemsAt(position).filter((item) => shouldAutoDismiss(item.duration));
|
|
389
|
-
},
|
|
390
|
-
persistentItemsAt(position) {
|
|
391
|
-
return this.itemsAt(position).filter((item) => isPersistentDuration(item.duration));
|
|
392
|
-
},
|
|
393
|
-
activeTimedItemsAt(position) {
|
|
394
|
-
return this.timedItemsAt(position).filter((item) => !item.removed);
|
|
395
|
-
},
|
|
396
|
-
activePersistentItemsAt(position) {
|
|
397
|
-
return this.persistentItemsAt(position).filter((item) => !item.removed);
|
|
398
|
-
},
|
|
399
|
-
isVisibleAt(position, index) {
|
|
400
|
-
const stack = this.timedItemsAt(position);
|
|
401
|
-
const item = stack[index];
|
|
402
|
-
if (!item || item.removed) {
|
|
403
|
-
return false;
|
|
404
|
-
}
|
|
405
|
-
if (this.maxVisible <= 0) {
|
|
406
|
-
return true;
|
|
407
|
-
}
|
|
408
|
-
let rank = 0;
|
|
409
|
-
for (let i = 0; i <= index; i++) {
|
|
410
|
-
if (stack[i] && !stack[i].removed) {
|
|
411
|
-
rank++;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
return rank <= this.maxVisible;
|
|
415
|
-
}
|
|
416
|
-
};
|
|
417
|
-
const unsubscribe = controller.on("change", (detail) => {
|
|
418
|
-
store.items = [...detail.items];
|
|
419
|
-
});
|
|
420
|
-
return store;
|
|
421
|
-
}
|
|
422
|
-
function createToastStore(options = {}) {
|
|
423
|
-
const controller = new ToastController(options);
|
|
424
|
-
controller.mount();
|
|
425
|
-
return wrapToastStore(controller);
|
|
426
|
-
}
|
|
427
|
-
var PROMISE_LOADING_DURATION = 36e5;
|
|
428
|
-
function normalizeToastDuration(duration) {
|
|
429
|
-
if (duration === 0) {
|
|
430
|
-
return false;
|
|
431
|
-
}
|
|
432
|
-
return duration;
|
|
433
|
-
}
|
|
434
|
-
function resolveToastDuration(duration, defaultDuration) {
|
|
435
|
-
if (duration === void 0) {
|
|
436
|
-
return normalizeToastDuration(defaultDuration);
|
|
437
|
-
}
|
|
438
|
-
return normalizeToastDuration(duration);
|
|
439
|
-
}
|
|
440
|
-
function shouldAutoDismiss(duration) {
|
|
441
|
-
return typeof duration === "number" && duration > 0 && Number.isFinite(duration);
|
|
442
|
-
}
|
|
443
|
-
function isPersistentDuration(duration) {
|
|
444
|
-
return !shouldAutoDismiss(duration);
|
|
445
|
-
}
|
|
446
|
-
function resolveToastLimits(options = {}) {
|
|
447
|
-
const maxToasts = options.maxToasts ?? DEFAULT_MAX_TOASTS;
|
|
448
|
-
let maxVisible = options.maxVisible ?? maxToasts;
|
|
449
|
-
if (maxToasts > 0 && maxVisible > maxToasts) {
|
|
450
|
-
maxVisible = maxToasts;
|
|
451
|
-
}
|
|
452
|
-
return { maxToasts, maxVisible };
|
|
453
|
-
}
|
|
454
|
-
function resolveStackPositions(defaultPosition, positions) {
|
|
455
|
-
const stacks = [defaultPosition];
|
|
456
|
-
for (const position of positions ?? []) {
|
|
457
|
-
if (!stacks.includes(position)) {
|
|
458
|
-
stacks.push(position);
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
return stacks;
|
|
462
|
-
}
|
|
463
|
-
function applyToastPatch(item, payload) {
|
|
464
|
-
let next = { ...item };
|
|
465
|
-
if (payload.content !== void 0) {
|
|
466
|
-
next = { ...next, content: payload.content };
|
|
467
|
-
}
|
|
468
|
-
if (payload.title !== void 0) {
|
|
469
|
-
next = { ...next, title: payload.title };
|
|
470
|
-
}
|
|
471
|
-
if (payload.description !== void 0) {
|
|
472
|
-
next = { ...next, description: payload.description };
|
|
473
|
-
}
|
|
474
|
-
if (payload.variant !== void 0) {
|
|
475
|
-
next = { ...next, variant: payload.variant };
|
|
476
|
-
}
|
|
477
|
-
if (payload.position !== void 0) {
|
|
478
|
-
next = { ...next, position: payload.position };
|
|
479
|
-
}
|
|
480
|
-
if (payload.duration !== void 0) {
|
|
481
|
-
next = { ...next, duration: normalizeToastDuration(payload.duration) };
|
|
482
|
-
}
|
|
483
|
-
if (payload.action !== void 0) {
|
|
484
|
-
next = { ...next, action: payload.action };
|
|
485
|
-
}
|
|
486
|
-
if (payload.key !== void 0) {
|
|
487
|
-
next = { ...next, key: payload.key };
|
|
488
|
-
}
|
|
489
|
-
return next;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
// src/plugin.ts
|
|
493
|
-
var DEFAULT_PLUGIN_OPTIONS = {
|
|
494
|
-
defaultPosition: "bottom-right",
|
|
495
|
-
defaultDuration: 4e3,
|
|
496
|
-
maxToasts: 5,
|
|
497
|
-
listenToWindowEvents: true
|
|
498
|
-
};
|
|
499
|
-
var RESERVED_TOAST_MAGIC_KEYS = /* @__PURE__ */ new Set([
|
|
500
|
-
"dismiss",
|
|
501
|
-
"update",
|
|
502
|
-
"dismissAt",
|
|
503
|
-
"dismissAll",
|
|
504
|
-
"pushUnique",
|
|
505
|
-
"fromPayload",
|
|
506
|
-
"promise"
|
|
507
|
-
]);
|
|
508
|
-
function variantFromList(variants, preferred) {
|
|
509
|
-
if (variants.includes(preferred)) {
|
|
510
|
-
return preferred;
|
|
511
|
-
}
|
|
512
|
-
return "default";
|
|
513
|
-
}
|
|
514
|
-
function resolvePromiseConfig(variants, promise = {}) {
|
|
515
|
-
return {
|
|
516
|
-
loading: promise.loading ?? "Loading...",
|
|
517
|
-
error: promise.error ?? "Error",
|
|
518
|
-
duration: promise.duration ?? 4e3,
|
|
519
|
-
loadingVariant: promise.loadingVariant ?? variantFromList(variants, "loading"),
|
|
520
|
-
successVariant: promise.successVariant ?? variantFromList(variants, "success"),
|
|
521
|
-
errorVariant: promise.errorVariant ?? variantFromList(variants, "error")
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
function resolveToastPluginConfig(options = {}) {
|
|
525
|
-
const variants = options.variants ?? [];
|
|
526
|
-
const positions = options.positions ?? [];
|
|
527
|
-
const maxToasts = options.maxToasts ?? DEFAULT_PLUGIN_OPTIONS.maxToasts;
|
|
528
|
-
let maxVisible = options.maxVisible ?? maxToasts;
|
|
529
|
-
if (maxToasts > 0 && maxVisible > maxToasts) {
|
|
530
|
-
maxVisible = maxToasts;
|
|
531
|
-
}
|
|
532
|
-
return {
|
|
533
|
-
defaultPosition: options.defaultPosition ?? DEFAULT_PLUGIN_OPTIONS.defaultPosition,
|
|
534
|
-
defaultDuration: options.defaultDuration ?? DEFAULT_PLUGIN_OPTIONS.defaultDuration,
|
|
535
|
-
maxToasts,
|
|
536
|
-
maxVisible,
|
|
537
|
-
listenToWindowEvents: options.listenToWindowEvents ?? DEFAULT_PLUGIN_OPTIONS.listenToWindowEvents,
|
|
538
|
-
storeKey: options.storeKey ?? TOAST_STORE_KEY,
|
|
539
|
-
variants,
|
|
540
|
-
positions,
|
|
541
|
-
promise: resolvePromiseConfig(variants, options.promise)
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
function toastOptions(options) {
|
|
545
|
-
return options;
|
|
546
|
-
}
|
|
547
|
-
function toastVariants(variants) {
|
|
548
|
-
return variants;
|
|
549
|
-
}
|
|
550
|
-
function toastPositions(positions) {
|
|
551
|
-
return positions;
|
|
552
|
-
}
|
|
553
|
-
function toastPlugin(options = {}) {
|
|
554
|
-
return function registerToast(alpine) {
|
|
555
|
-
const Alpine = alpine;
|
|
556
|
-
const controllerOptions = {
|
|
557
|
-
defaultPosition: options.defaultPosition,
|
|
558
|
-
positions: options.positions,
|
|
559
|
-
defaultDuration: options.defaultDuration,
|
|
560
|
-
maxToasts: options.maxToasts,
|
|
561
|
-
maxVisible: options.maxVisible,
|
|
562
|
-
listenToWindowEvents: options.listenToWindowEvents,
|
|
563
|
-
storeKey: options.storeKey
|
|
564
|
-
};
|
|
565
|
-
const controller = createToastController(controllerOptions);
|
|
566
|
-
const config = resolveToastPluginConfig(options);
|
|
567
|
-
const store = wrapToastStore(controller);
|
|
568
|
-
Alpine.store(config.storeKey, store);
|
|
569
|
-
const reactiveStore = Alpine.store(config.storeKey);
|
|
570
|
-
controller.on("change", (detail) => {
|
|
571
|
-
reactiveStore.items = [...detail.items];
|
|
572
|
-
});
|
|
573
|
-
const toast = createToastMagic(
|
|
574
|
-
config,
|
|
575
|
-
() => reactiveStore
|
|
576
|
-
);
|
|
577
|
-
Alpine.magic("toast", () => toast);
|
|
578
|
-
if (typeof Alpine.cleanup === "function") {
|
|
579
|
-
Alpine.cleanup(() => controller.destroy());
|
|
580
|
-
}
|
|
581
|
-
};
|
|
582
|
-
}
|
|
583
|
-
function createToastMagic(config, getStore) {
|
|
584
|
-
const magic = ((titleOrPayload, options) => pushToast(getStore(), titleOrPayload, options ?? {}));
|
|
585
|
-
magic.dismiss = (id) => getStore().dismiss(id);
|
|
586
|
-
magic.update = (id, payload) => getStore().update(id, payload);
|
|
587
|
-
magic.dismissAt = (position) => getStore().dismissAt(position);
|
|
588
|
-
magic.dismissAll = () => getStore().dismissAll();
|
|
589
|
-
magic.pushUnique = (key, payload) => getStore().pushUnique(key, payload ?? {});
|
|
590
|
-
magic.fromPayload = (payload = {}) => {
|
|
591
|
-
const { title = null, content = null, variant = "default", ...options } = payload;
|
|
592
|
-
return pushToast(getStore(), {
|
|
593
|
-
title,
|
|
594
|
-
content,
|
|
595
|
-
variant,
|
|
596
|
-
...options
|
|
597
|
-
});
|
|
598
|
-
};
|
|
599
|
-
magic.promise = async (factoryOrPromise, messages = {}) => {
|
|
600
|
-
const promiseConfig = config.promise;
|
|
601
|
-
const loadingVariant = messages.loadingVariant ?? promiseConfig.loadingVariant;
|
|
602
|
-
const successVariant = messages.successVariant ?? promiseConfig.successVariant;
|
|
603
|
-
const errorVariant = messages.errorVariant ?? promiseConfig.errorVariant;
|
|
604
|
-
const settledDuration = messages.duration ?? promiseConfig.duration;
|
|
605
|
-
const id = getStore().push({
|
|
606
|
-
title: messages.loading ?? promiseConfig.loading,
|
|
607
|
-
content: messages.loadingContent ?? null,
|
|
608
|
-
variant: loadingVariant,
|
|
609
|
-
duration: PROMISE_LOADING_DURATION
|
|
610
|
-
});
|
|
611
|
-
try {
|
|
612
|
-
const data = await resolveToastPromise(factoryOrPromise);
|
|
613
|
-
getStore().update(
|
|
614
|
-
id,
|
|
615
|
-
buildPromiseSuccessPatch(data, messages, successVariant, settledDuration)
|
|
616
|
-
);
|
|
617
|
-
return data;
|
|
618
|
-
} catch (error) {
|
|
619
|
-
getStore().update(
|
|
620
|
-
id,
|
|
621
|
-
buildPromiseErrorPatch(messages, promiseConfig, errorVariant, settledDuration)
|
|
622
|
-
);
|
|
623
|
-
throw error;
|
|
624
|
-
}
|
|
625
|
-
};
|
|
626
|
-
for (const variant of config.variants) {
|
|
627
|
-
if (RESERVED_TOAST_MAGIC_KEYS.has(variant)) {
|
|
628
|
-
continue;
|
|
629
|
-
}
|
|
630
|
-
Object.assign(magic, {
|
|
631
|
-
[variant]: (titleOrPayload, options = {}) => pushVariantToast(getStore(), variant, titleOrPayload, options)
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
return magic;
|
|
635
|
-
}
|
|
636
|
-
function pushToast(store, titleOrPayload, options = {}) {
|
|
637
|
-
if (typeof titleOrPayload === "string") {
|
|
638
|
-
return store.push({
|
|
639
|
-
title: titleOrPayload,
|
|
640
|
-
...options
|
|
641
|
-
});
|
|
642
|
-
}
|
|
643
|
-
return store.push(titleOrPayload);
|
|
644
|
-
}
|
|
645
|
-
function pushVariantToast(store, variant, titleOrPayload, options = {}) {
|
|
646
|
-
if (typeof titleOrPayload === "string") {
|
|
647
|
-
return store.push({
|
|
648
|
-
title: titleOrPayload,
|
|
649
|
-
...options,
|
|
650
|
-
variant
|
|
651
|
-
});
|
|
652
|
-
}
|
|
653
|
-
return store.push({
|
|
654
|
-
...titleOrPayload,
|
|
655
|
-
...options,
|
|
656
|
-
variant
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
function resolveSuccessTitle(data, messages) {
|
|
660
|
-
if (typeof messages.success === "function") {
|
|
661
|
-
return messages.success(data);
|
|
662
|
-
}
|
|
663
|
-
return messages.success;
|
|
664
|
-
}
|
|
665
|
-
function resolveSuccessContent(data, messages) {
|
|
666
|
-
const { successContent } = messages;
|
|
667
|
-
if (typeof successContent === "function") {
|
|
668
|
-
return successContent(data);
|
|
669
|
-
}
|
|
670
|
-
return successContent;
|
|
671
|
-
}
|
|
672
|
-
function resolveErrorTitle(messages, fallbackError) {
|
|
673
|
-
return messages.error ?? fallbackError;
|
|
674
|
-
}
|
|
675
|
-
function resolveToastPromise(factoryOrPromise) {
|
|
676
|
-
if (typeof factoryOrPromise === "function") {
|
|
677
|
-
return Promise.resolve(factoryOrPromise());
|
|
678
|
-
}
|
|
679
|
-
return Promise.resolve(factoryOrPromise);
|
|
680
|
-
}
|
|
681
|
-
function buildPromiseSuccessPatch(data, messages, successVariant, settledDuration) {
|
|
682
|
-
const successTitle = resolveSuccessTitle(data, messages);
|
|
683
|
-
const successContent = resolveSuccessContent(data, messages);
|
|
684
|
-
return {
|
|
685
|
-
...successTitle !== void 0 ? { title: successTitle } : {},
|
|
686
|
-
...successContent !== void 0 ? { content: successContent } : {},
|
|
687
|
-
variant: successVariant,
|
|
688
|
-
duration: settledDuration
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
function buildPromiseErrorPatch(messages, promiseConfig, errorVariant, settledDuration) {
|
|
692
|
-
return {
|
|
693
|
-
title: resolveErrorTitle(messages, promiseConfig.error),
|
|
694
|
-
...messages.errorContent !== void 0 ? { content: messages.errorContent } : {},
|
|
695
|
-
variant: errorVariant,
|
|
696
|
-
duration: settledDuration
|
|
697
|
-
};
|
|
698
|
-
}
|
|
699
|
-
export {
|
|
700
|
-
PROMISE_LOADING_DURATION,
|
|
701
|
-
RESERVED_TOAST_MAGIC_KEYS,
|
|
702
|
-
TOAST_STORE_KEY,
|
|
703
|
-
ToastController,
|
|
704
|
-
createToastController,
|
|
705
|
-
createToastMagic,
|
|
706
|
-
createToastStore,
|
|
707
|
-
toastPlugin as default,
|
|
708
|
-
isPersistentDuration,
|
|
709
|
-
normalizeToastDuration,
|
|
710
|
-
resolveStackPositions,
|
|
711
|
-
resolveToastDuration,
|
|
712
|
-
resolveToastLimits,
|
|
713
|
-
resolveToastPluginConfig,
|
|
714
|
-
shouldAutoDismiss,
|
|
715
|
-
toastOptions,
|
|
716
|
-
toastPlugin,
|
|
717
|
-
toastPositions,
|
|
718
|
-
toastVariants,
|
|
719
|
-
wrapToastStore
|
|
720
|
-
};
|
|
1
|
+
import{BaseController as _,createSingleton as M,generateId as h,releaseSingleton as K}from"@ailuracode/alpine-core";var c="toast",C="toast";var R=400,U=5,W=4e3,A="@ailuracode/alpine-toast/default";function x(s={}){let{scope:t,...o}=s;return M(A,()=>{let n=new y(o);return n.mount(),n},{scope:t})}var y=class extends _{#e;#l;#d;#a;#r;#y;#u;#P;#s=new Map;#T=new Map;#t=[];constructor(t){super(t.id??h("toast")),this.#e=t.defaultPosition??"bottom-right",this.#l=S(this.#e,t.positions),this.#d=t.defaultDuration??W;let o=I({maxToasts:t.maxToasts,maxVisible:t.maxVisible});this.#a=o.maxToasts,this.#r=o.maxVisible,this.#y=t.storeKey??c,this.#u=t.listenToWindowEvents!==!1,this.#P=t.getStore}destroy(){this.isDestroyed||(super.destroy(),this.#p(),K(A,this))}mount(){if(!this.isMounted){if(super.mount(),this.#u&&typeof window<"u"){let t=new AbortController,o=n=>{n instanceof CustomEvent&&this.fromPayload(n.detail??{})};window.addEventListener("toast",o,{signal:t.signal}),this.registerCleanup(()=>t.abort())}queueMicrotask(()=>{this.isDestroyed||this.#o("initialization")})}}get defaultPosition(){return this.#e}get stackPositions(){return this.#l}get maxToasts(){return this.#a}get maxVisible(){return this.#r}get items(){return this.#t}push(t={}){if(this.isDestroyed)return"";let o=t.position??this.#e,n=h("toast"),i={id:n,key:t.key??null,content:t.content??null,title:t.title??null,description:t.description??null,variant:t.variant??"default",position:o,duration:b(t.duration,this.#d),action:t.action??null,removed:!1};return this.#t=[i,...this.#t],this.#i(o,u(i.duration)?"timed":"persistent"),this.#m(n,i.duration),this.#o("push"),n}pushUnique(t,o={}){if(this.isDestroyed)return"";let n=this.#t.filter(i=>!i.removed&&i.key===t).map(i=>i.id);return this.#n(n),this.push({...o,key:t})}update(t,o={}){if(this.isDestroyed)return;let n=this.#t.find(T=>T.id===t);if(!n)return;let i=n.position,a=m(n.duration);this.#t=this.#t.map(T=>T.id===t?N(T,o):T);let e=this.#t.find(T=>T.id===t);if(!e)return;let r=e.position,l=m(e.duration),P=o.duration!==void 0&&a!==l,d=r!==i;d&&(this.#i(i,"timed"),this.#i(i,"persistent")),(d||P)&&(this.#i(r,"timed"),this.#i(r,"persistent")),o.duration!==void 0&&this.#m(t,e.duration),this.#o("update")}dismiss(t){this.isDestroyed||(this.#n([t]),this.#o("dismiss"))}dismissAt(t){if(this.isDestroyed)return;let o=this.itemsAt(t).filter(n=>!n.removed).map(n=>n.id);this.#n(o),this.#o("dismissAt")}dismissAll(){if(this.isDestroyed)return;let t=this.#t.filter(o=>!o.removed).map(o=>o.id);this.#n(t),this.#o("dismissAll")}itemsAt(t){return this.#t.filter(o=>o.position===t)}timedItemsAt(t){return this.itemsAt(t).filter(o=>u(o.duration))}persistentItemsAt(t){return this.itemsAt(t).filter(o=>m(o.duration))}activeTimedItemsAt(t){return this.timedItemsAt(t).filter(o=>!o.removed)}activePersistentItemsAt(t){return this.persistentItemsAt(t).filter(o=>!o.removed)}isVisibleAt(t,o){let n=this.timedItemsAt(t),i=n[o];if(!i||i.removed)return!1;if(this.#r<=0)return!0;let a=0;for(let e=0;e<=o;e++)n[e]&&!n[e].removed&&a++;return a<=this.#r}fromPayload(t={}){let{title:o=null,content:n=null,variant:i="default",...a}=t;return this.push({title:o,content:n,variant:i,...a})}#o(t){if(this.isDestroyed)return;let o={source:t,items:this.#t};this.emit("change",o)}#n(t){if(t.length===0)return;let o=[];for(let e of t){let r=this.#t.find(l=>l.id===e);!r||r.removed||(this.#c(e),o.push(e))}if(o.length===0)return;let n=new Set(o);this.#t=this.#t.map(e=>n.has(e.id)?{...e,removed:!0}:e);let i=h("toast-purge"),a=setTimeout(()=>{this.#T.delete(i),!this.isDestroyed&&(this.#t=this.#t.filter(e=>!n.has(e.id)),this.#o("dismiss"))},R);this.#T.set(i,a)}#i(t,o){if(this.#a<=0)return;let n=this.itemsAt(t),e=(o==="persistent"?n.filter(r=>m(r.duration)):n.filter(r=>u(r.duration))).filter(r=>!r.removed).slice(this.#a).map(r=>r.id);this.#n(e)}#m(t,o){if(this.#c(t),o!==g&&u(o)){let n=setTimeout(()=>{if(this.#s.delete(t),this.isDestroyed)return;let i=this.#P?.()??null;i?i.dismiss(t):this.dismiss(t)},o);this.#s.set(t,n)}}#c(t){let o=this.#s.get(t);o!==void 0&&(clearTimeout(o),this.#s.delete(t))}#p(){for(let t of this.#s.values())clearTimeout(t);this.#s.clear();for(let t of this.#T.values())clearTimeout(t);this.#T.clear()}};function f(s){let t={defaultPosition:s.defaultPosition,stackPositions:s.stackPositions,maxToasts:s.maxToasts,maxVisible:s.maxVisible,items:[...s.items],push(n){return s.push(n)},pushUnique(n,i){return s.pushUnique(n,i??{})},update(n,i){s.update(n,i)},dismiss(n){s.dismiss(n)},dismissAt(n){s.dismissAt(n)},dismissAll(){s.dismissAll()},destroy(){o(),s.destroy()},itemsAt(n){return this.items.filter(i=>i.position===n)},timedItemsAt(n){return this.itemsAt(n).filter(i=>u(i.duration))},persistentItemsAt(n){return this.itemsAt(n).filter(i=>m(i.duration))},activeTimedItemsAt(n){return this.timedItemsAt(n).filter(i=>!i.removed)},activePersistentItemsAt(n){return this.persistentItemsAt(n).filter(i=>!i.removed)},isVisibleAt(n,i){let a=this.timedItemsAt(n),e=a[i];if(!e||e.removed)return!1;if(this.maxVisible<=0)return!0;let r=0;for(let l=0;l<=i;l++)a[l]&&!a[l].removed&&r++;return r<=this.maxVisible}},o=s.on("change",n=>{t.items=[...n.items]});return t}function L(s={}){let t=new y(s);return t.mount(),f(t)}var g=36e5;function p(s){return s===0?!1:s}function b(s,t){return p(s===void 0?t:s)}function u(s){return typeof s=="number"&&s>0&&Number.isFinite(s)}function m(s){return!u(s)}function I(s={}){let t=s.maxToasts??U,o=s.maxVisible??t;return t>0&&o>t&&(o=t),{maxToasts:t,maxVisible:o}}function S(s,t){let o=[s];for(let n of t??[])o.includes(n)||o.push(n);return o}function N(s,t){let o={...s};return t.content!==void 0&&(o={...o,content:t.content}),t.title!==void 0&&(o={...o,title:t.title}),t.description!==void 0&&(o={...o,description:t.description}),t.variant!==void 0&&(o={...o,variant:t.variant}),t.position!==void 0&&(o={...o,position:t.position}),t.duration!==void 0&&(o={...o,duration:p(t.duration)}),t.action!==void 0&&(o={...o,action:t.action}),t.key!==void 0&&(o={...o,key:t.key}),o}import{bridgeControllerStore as Y}from"@ailuracode/alpine-core";var V={defaultPosition:"bottom-right",defaultDuration:4e3,maxToasts:5,listenToWindowEvents:!0},k=new Set(["dismiss","update","dismissAt","dismissAll","pushUnique","fromPayload","promise"]);function v(s,t){return s.includes(t)?t:"default"}function q(s,t={}){return{loading:t.loading??"Loading...",error:t.error??"Error",duration:t.duration??4e3,loadingVariant:t.loadingVariant??v(s,"loading"),successVariant:t.successVariant??v(s,"success"),errorVariant:t.errorVariant??v(s,"error")}}function O(s={}){let t=s.variants??[],o=s.positions??[],n=s.maxToasts??V.maxToasts,i=s.maxVisible??n;return n>0&&i>n&&(i=n),{defaultPosition:s.defaultPosition??V.defaultPosition,defaultDuration:s.defaultDuration??V.defaultDuration,maxToasts:n,maxVisible:i,listenToWindowEvents:s.listenToWindowEvents??V.listenToWindowEvents,storeKey:s.storeKey??c,magicKey:s.magicKey??C,variants:t,positions:o,promise:q(t,s.promise)}}function G(s){return s}function F(s){return s}function z(s){return s}function w(s={}){return function(o){let n=o,i={defaultPosition:s.defaultPosition,positions:s.positions,defaultDuration:s.defaultDuration,maxToasts:s.maxToasts,maxVisible:s.maxVisible,listenToWindowEvents:s.listenToWindowEvents,storeKey:s.storeKey},a=x(i),e=O(s),r=f(a),l=E(e,()=>r);Y({alpine:n,storeKey:e.storeKey,magicKey:e.magicKey,store:r,controller:a,packageName:"toast",magicAccessor:()=>l,subscribe:P=>{let d=P;return a.on("change",T=>{d.items=[...T.items]})}})}}function E(s,t){let o=((n,i)=>D(t(),n,i??{}));o.dismiss=n=>t().dismiss(n),o.update=(n,i)=>t().update(n,i),o.dismissAt=n=>t().dismissAt(n),o.dismissAll=()=>t().dismissAll(),o.pushUnique=(n,i)=>t().pushUnique(n,i??{}),o.fromPayload=(n={})=>{let{title:i=null,content:a=null,variant:e="default",...r}=n;return D(t(),{title:i,content:a,variant:e,...r})},o.promise=async(n,i={})=>{let a=s.promise,e=i.loadingVariant??a.loadingVariant,r=i.successVariant??a.successVariant,l=i.errorVariant??a.errorVariant,P=i.duration??a.duration,d=t().push({title:i.loading??a.loading,content:i.loadingContent??null,variant:e,duration:g});try{let T=await J(n);return t().update(d,Q(T,i,r,P)),T}catch(T){throw t().update(d,Z(i,a,l,P)),T}};for(let n of s.variants)k.has(n)||Object.assign(o,{[n]:(i,a={})=>j(t(),n,i,a)});return o}function D(s,t,o={}){return typeof t=="string"?s.push({title:t,...o}):s.push(t)}function j(s,t,o,n={}){return typeof o=="string"?s.push({title:o,...n,variant:t}):s.push({...o,...n,variant:t})}function B(s,t){return typeof t.success=="function"?t.success(s):t.success}function X(s,t){let{successContent:o}=t;return typeof o=="function"?o(s):o}function H(s,t){return s.error??t}function J(s){return typeof s=="function"?Promise.resolve(s()):Promise.resolve(s)}function Q(s,t,o,n){let i=B(s,t),a=X(s,t);return{...i!==void 0?{title:i}:{},...a!==void 0?{content:a}:{},variant:o,duration:n}}function Z(s,t,o,n){return{title:H(s,t.error),...s.errorContent!==void 0?{content:s.errorContent}:{},variant:o,duration:n}}export{g as PROMISE_LOADING_DURATION,k as RESERVED_TOAST_MAGIC_KEYS,C as TOAST_MAGIC_KEY,c as TOAST_STORE_KEY,y as ToastController,x as createToastController,E as createToastMagic,L as createToastStore,w as default,m as isPersistentDuration,p as normalizeToastDuration,S as resolveStackPositions,b as resolveToastDuration,I as resolveToastLimits,O as resolveToastPluginConfig,u as shouldAutoDismiss,G as toastOptions,w as toastPlugin,z as toastPositions,F as toastVariants,f as wrapToastStore};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ailuracode/alpine-toast",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Alpine.js in-app toast queue magic",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@ailuracode/alpine-core": "^0.
|
|
36
|
+
"@ailuracode/alpine-core": "^0.3.0",
|
|
37
37
|
"alpinejs": "^3.0.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependenciesMeta": {
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/alpinejs": "^3.13.11",
|
|
46
|
-
"
|
|
46
|
+
"alpinejs": "^3.15.12",
|
|
47
|
+
"@ailuracode/alpine-core": "0.3.0"
|
|
47
48
|
},
|
|
48
49
|
"keywords": [
|
|
49
50
|
"alpinejs",
|
|
@@ -53,8 +54,29 @@
|
|
|
53
54
|
"sonner",
|
|
54
55
|
"notifications"
|
|
55
56
|
],
|
|
57
|
+
"toolkit": {
|
|
58
|
+
"bundleBudget": {
|
|
59
|
+
"category": "complex-feature"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"size-limit": [
|
|
63
|
+
{
|
|
64
|
+
"name": "full surface",
|
|
65
|
+
"path": "dist/index.js",
|
|
66
|
+
"import": "*",
|
|
67
|
+
"ignore": [
|
|
68
|
+
"alpinejs",
|
|
69
|
+
"@ailuracode/alpine-core"
|
|
70
|
+
],
|
|
71
|
+
"gzip": true,
|
|
72
|
+
"brotli": true,
|
|
73
|
+
"limit": "3.7 kB"
|
|
74
|
+
}
|
|
75
|
+
],
|
|
56
76
|
"scripts": {
|
|
57
|
-
"build": "tsup src/index.ts --format esm --dts --clean --out-dir dist && cp src/global.d.ts dist/global.d.ts",
|
|
58
|
-
"
|
|
77
|
+
"build": "tsup src/index.ts --format esm --dts --clean --out-dir dist --minify && cp src/global.d.ts dist/global.d.ts",
|
|
78
|
+
"size": "size-limit",
|
|
79
|
+
"test": "vitest run --config ../../vitest.config.ts packages/toast",
|
|
80
|
+
"test:e2e": "playwright test --config playwright.config.ts"
|
|
59
81
|
}
|
|
60
82
|
}
|