@rozie-ui/toast-solid 0.1.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.
@@ -0,0 +1,51 @@
1
+ import { JSX } from "solid-js";
2
+
3
+ //#region src/Toaster.d.ts
4
+ interface ToastSlotCtx {
5
+ toast: any;
6
+ dismiss: any;
7
+ }
8
+ interface ToasterProps {
9
+ /**
10
+ * Which corner the toast stack renders in: `'top-left'`, `'top-right'`, `'top-center'`, `'bottom-left'`, `'bottom-right'`, or `'bottom-center'`. Drives the fixed-position layout and the stack direction.
11
+ */
12
+ position?: string;
13
+ /**
14
+ * Default auto-dismiss time in milliseconds, applied to any toast that does not pass its own `duration`. `0` (or a per-toast `duration` of `0`) makes the toast sticky — it stays until explicitly dismissed.
15
+ */
16
+ duration?: number;
17
+ /**
18
+ * Maximum number of visible toasts (`0` = unlimited). When the queue exceeds this, the oldest toasts drop off the stack.
19
+ */
20
+ max?: number;
21
+ /**
22
+ * Opt **out** of pausing the auto-dismiss timers while the pointer is over the stack. By default hovering pauses every timer and leaving restarts them; set this to keep toasts dismissing on schedule regardless of hover.
23
+ */
24
+ disablePauseOnHover?: boolean;
25
+ /**
26
+ * Accessible name for the live region (`role="region"`), applied as its `aria-label`. Defaults to `'Notifications'` when not set, so assistive tech can navigate to the toast stack as a landmark.
27
+ */
28
+ ariaLabel?: (string) | null;
29
+ /**
30
+ * Opt **out** of pointer swipe-to-dismiss. By default, dragging a toast past 45% of its own width/height (direction auto-derived from `position`) or a fast flick dismisses it with reason `'swipe'`; a short drag springs back. A drag starting on the close button (or any button/link) never swipes.
31
+ */
32
+ disableSwipe?: boolean;
33
+ /**
34
+ * Opt **in** to a sonner-style collapsed stack: a single-cell grid overlay with depth-driven transforms (toasts at depth 3+ fade to invisible), newest on top. Hovering the region or moving keyboard focus into it expands to the normal flex-column stack; leaving re-collapses. `false` (default) renders the plain flex column at all times.
35
+ */
36
+ stacked?: boolean;
37
+ onDismissed?: (...args: unknown[]) => void;
38
+ toastSlot?: (ctx: ToastSlotCtx) => JSX.Element;
39
+ slots?: Record<string, (ctx: any) => JSX.Element>;
40
+ ref?: (h: ToasterHandle) => void;
41
+ }
42
+ interface ToasterHandle {
43
+ show: (...args: any[]) => any;
44
+ dismiss: (...args: any[]) => any;
45
+ clear: (...args: any[]) => any;
46
+ patch: (...args: any[]) => any;
47
+ promise: (...args: any[]) => any;
48
+ }
49
+ declare function Toaster(_props: ToasterProps): JSX.Element;
50
+ //#endregion
51
+ export { Toaster, Toaster as default, type ToasterHandle };
package/dist/index.mjs ADDED
@@ -0,0 +1,477 @@
1
+ import { Show, createSignal, mergeProps, onCleanup, onMount, splitProps } from "solid-js";
2
+ import { Key } from "@solid-primitives/keyed";
3
+ import { __rozieInjectStyle, mergeListeners, parseInlineStyle, rozieAttr, rozieClass, rozieDisplay } from "@rozie/runtime-solid";
4
+ //#region src/Toaster.tsx
5
+ __rozieInjectStyle("Toaster-12d4265c", `@media (prefers-reduced-motion: reduce) {
6
+ .rozie-toast[data-rozie-s-12d4265c] {
7
+ animation-name: rozie-toast-fade-in;
8
+ animation-duration: 1ms;
9
+ }
10
+ .rozie-toast--exiting[data-rozie-s-12d4265c] {
11
+ animation-name: rozie-toast-fade-out;
12
+ animation-duration: 1ms;
13
+ }
14
+ }
15
+ .rozie-toaster[data-rozie-s-12d4265c] {
16
+ position: fixed;
17
+ z-index: var(--rozie-toast-z, 9999);
18
+ display: flex;
19
+ flex-direction: column;
20
+ gap: var(--rozie-toast-gap, 0.5rem);
21
+ padding: var(--rozie-toast-region-padding, 1rem);
22
+ max-width: var(--rozie-toast-max-width, calc(100vw - 2rem));
23
+ pointer-events: none;
24
+ font: var(--rozie-toast-font, inherit);
25
+ }
26
+ .rozie-toaster[data-rozie-s-12d4265c] > *[data-rozie-s-12d4265c] {
27
+ pointer-events: auto;
28
+ }
29
+ .rozie-toaster--top-left[data-rozie-s-12d4265c] { top: 0; left: 0; align-items: flex-start; }
30
+ .rozie-toaster--top-right[data-rozie-s-12d4265c] { top: 0; right: 0; align-items: flex-end; }
31
+ .rozie-toaster--top-center[data-rozie-s-12d4265c] { top: 0; left: 50%; transform: translateX(-50%); align-items: center; }
32
+ .rozie-toaster--bottom-left[data-rozie-s-12d4265c] { bottom: 0; left: 0; align-items: flex-start; flex-direction: column-reverse; }
33
+ .rozie-toaster--bottom-right[data-rozie-s-12d4265c] { bottom: 0; right: 0; align-items: flex-end; flex-direction: column-reverse; }
34
+ .rozie-toaster--bottom-center[data-rozie-s-12d4265c] { bottom: 0; left: 50%; transform: translateX(-50%); align-items: center; flex-direction: column-reverse; }
35
+ .rozie-toaster--stacked[data-rozie-s-12d4265c] .rozie-toast[data-rozie-s-12d4265c] {
36
+ grid-area: 1 / 1;
37
+ z-index: calc(100 - var(--rozie-toast-depth, 0));
38
+ }
39
+ .rozie-toaster--stacked[data-rozie-s-12d4265c]:not([data-rozie-s-12d4265c]:hover):not([data-rozie-s-12d4265c]:focus-within) {
40
+ display: grid;
41
+ }
42
+ .rozie-toaster--stacked[data-rozie-s-12d4265c]:not([data-rozie-s-12d4265c]:hover):not([data-rozie-s-12d4265c]:focus-within) .rozie-toast[data-rozie-s-12d4265c] {
43
+ transform:
44
+ translateY(calc(var(--rozie-toast-depth, 0) * var(--rozie-toast-stack-offset, 8px)))
45
+ scale(calc(1 - var(--rozie-toast-depth, 0) * var(--rozie-toast-stack-scale-step, 0.05)));
46
+ opacity: calc(1 - min(1, max(0, var(--rozie-toast-depth, 0) - 2)));
47
+ }
48
+ .rozie-toaster--stacked.rozie-toaster--bottom-left[data-rozie-s-12d4265c]:not([data-rozie-s-12d4265c]:hover):not([data-rozie-s-12d4265c]:focus-within) .rozie-toast[data-rozie-s-12d4265c],
49
+ .rozie-toaster--stacked.rozie-toaster--bottom-right[data-rozie-s-12d4265c]:not([data-rozie-s-12d4265c]:hover):not([data-rozie-s-12d4265c]:focus-within) .rozie-toast[data-rozie-s-12d4265c],
50
+ .rozie-toaster--stacked.rozie-toaster--bottom-center[data-rozie-s-12d4265c]:not([data-rozie-s-12d4265c]:hover):not([data-rozie-s-12d4265c]:focus-within) .rozie-toast[data-rozie-s-12d4265c] {
51
+ transform:
52
+ translateY(calc(var(--rozie-toast-depth, 0) * var(--rozie-toast-stack-offset, 8px) * -1))
53
+ scale(calc(1 - var(--rozie-toast-depth, 0) * var(--rozie-toast-stack-scale-step, 0.05)));
54
+ }
55
+ .rozie-toast[data-rozie-s-12d4265c] {
56
+ display: flex;
57
+ align-items: center;
58
+ gap: var(--rozie-toast-content-gap, 0.75rem);
59
+ min-width: var(--rozie-toast-min-width, 16rem);
60
+ max-width: var(--rozie-toast-toast-max-width, 24rem);
61
+ padding: var(--rozie-toast-padding, 0.75rem 1rem);
62
+ color: var(--rozie-toast-color, #fff);
63
+ background: var(--rozie-toast-bg, #333);
64
+ border-radius: var(--rozie-toast-radius, 0.5rem);
65
+ box-shadow: var(--rozie-toast-shadow, 0 6px 20px rgba(0, 0, 0, 0.25));
66
+ /* Swipe: page scroll stays alive on touch along the axis the toast does
67
+ NOT move on. The transition here drives the spring-back (the active-drag
68
+ :style sets an inline \`transition: none\` to track the finger 1:1;
69
+ releasing it without a further gesture falls back to this transition). */
70
+ touch-action: pan-y;
71
+ transition: transform 200ms ease, opacity 200ms ease;
72
+ }
73
+ .rozie-toaster--top-center[data-rozie-s-12d4265c] .rozie-toast[data-rozie-s-12d4265c],
74
+ .rozie-toaster--bottom-center[data-rozie-s-12d4265c] .rozie-toast[data-rozie-s-12d4265c] {
75
+ touch-action: pan-x;
76
+ }
77
+ .rozie-toast--success[data-rozie-s-12d4265c] { background: var(--rozie-toast-success-bg, #16a34a); }
78
+ .rozie-toast--error[data-rozie-s-12d4265c] { background: var(--rozie-toast-error-bg, #dc2626); }
79
+ .rozie-toast--warning[data-rozie-s-12d4265c] { background: var(--rozie-toast-warning-bg, #ca8a04); }
80
+ .rozie-toast--info[data-rozie-s-12d4265c] { background: var(--rozie-toast-info-bg, var(--rozie-toast-bg, #333)); }
81
+ from[data-rozie-s-12d4265c] { opacity: 0; transform: translateY(-0.5rem); }
82
+ to[data-rozie-s-12d4265c] { opacity: 1; transform: translateY(0); }
83
+ from[data-rozie-s-12d4265c] { opacity: 0; transform: translateY(0.5rem); }
84
+ to[data-rozie-s-12d4265c] { opacity: 1; transform: translateY(0); }
85
+ from[data-rozie-s-12d4265c] { opacity: 1; transform: translateY(0); }
86
+ to[data-rozie-s-12d4265c] { opacity: 0; transform: translateY(-0.5rem); }
87
+ from[data-rozie-s-12d4265c] { opacity: 1; transform: translateY(0); }
88
+ to[data-rozie-s-12d4265c] { opacity: 0; transform: translateY(0.5rem); }
89
+ .rozie-toast[data-rozie-s-12d4265c] {
90
+ animation: rozie-toast-enter var(--rozie-toast-enter-duration, 200ms) ease-out;
91
+ }
92
+ .rozie-toaster--bottom-left[data-rozie-s-12d4265c] .rozie-toast[data-rozie-s-12d4265c],
93
+ .rozie-toaster--bottom-right[data-rozie-s-12d4265c] .rozie-toast[data-rozie-s-12d4265c],
94
+ .rozie-toaster--bottom-center[data-rozie-s-12d4265c] .rozie-toast[data-rozie-s-12d4265c] {
95
+ animation-name: rozie-toast-enter-from-bottom;
96
+ }
97
+ .rozie-toast--exiting[data-rozie-s-12d4265c] {
98
+ animation: rozie-toast-exit var(--rozie-toast-exit-duration, 200ms) ease-in forwards;
99
+ }
100
+ .rozie-toaster--bottom-left[data-rozie-s-12d4265c] .rozie-toast--exiting[data-rozie-s-12d4265c],
101
+ .rozie-toaster--bottom-right[data-rozie-s-12d4265c] .rozie-toast--exiting[data-rozie-s-12d4265c],
102
+ .rozie-toaster--bottom-center[data-rozie-s-12d4265c] .rozie-toast--exiting[data-rozie-s-12d4265c] {
103
+ animation-name: rozie-toast-exit-to-bottom;
104
+ }
105
+ from[data-rozie-s-12d4265c] { opacity: 0; }
106
+ to[data-rozie-s-12d4265c] { opacity: 1; }
107
+ from[data-rozie-s-12d4265c] { opacity: 1; }
108
+ to[data-rozie-s-12d4265c] { opacity: 0; }
109
+ from[data-rozie-s-12d4265c] { opacity: 1; transform: translateX(0); }
110
+ to[data-rozie-s-12d4265c] { opacity: 0; transform: translateX(calc(var(--rozie-toast-swipe-exit, 1) * 100%)); }
111
+ from[data-rozie-s-12d4265c] { opacity: 1; transform: translateY(0); }
112
+ to[data-rozie-s-12d4265c] { opacity: 0; transform: translateY(calc(var(--rozie-toast-swipe-exit, 1) * 100%)); }
113
+ .rozie-toast--exiting.rozie-toast--swipe-exit[data-rozie-s-12d4265c] {
114
+ animation-name: rozie-toast-swipe-exit-x;
115
+ }
116
+ .rozie-toaster--top-center[data-rozie-s-12d4265c] .rozie-toast--exiting.rozie-toast--swipe-exit[data-rozie-s-12d4265c],
117
+ .rozie-toaster--bottom-center[data-rozie-s-12d4265c] .rozie-toast--exiting.rozie-toast--swipe-exit[data-rozie-s-12d4265c] {
118
+ animation-name: rozie-toast-swipe-exit-y;
119
+ }
120
+ .rozie-toast-spinner[data-rozie-s-12d4265c] {
121
+ flex: 0 0 auto;
122
+ width: var(--rozie-toast-spinner-size, 1em);
123
+ height: var(--rozie-toast-spinner-size, 1em);
124
+ border: 2px solid color-mix(in srgb, var(--rozie-toast-spinner-color, currentColor) 25%, transparent);
125
+ border-top-color: var(--rozie-toast-spinner-color, currentColor);
126
+ border-radius: 50%;
127
+ animation: rozie-toast-spin 0.75s linear infinite;
128
+ }
129
+ to[data-rozie-s-12d4265c] { transform: rotate(360deg); }
130
+ .rozie-toast-message[data-rozie-s-12d4265c] {
131
+ flex: 1 1 auto;
132
+ font-size: var(--rozie-toast-font-size, 0.9rem);
133
+ }
134
+ .rozie-toast-close[data-rozie-s-12d4265c] {
135
+ flex: 0 0 auto;
136
+ display: inline-flex;
137
+ align-items: center;
138
+ justify-content: center;
139
+ width: var(--rozie-toast-close-size, 1.25rem);
140
+ height: var(--rozie-toast-close-size, 1.25rem);
141
+ padding: 0;
142
+ font-size: 1.1rem;
143
+ line-height: 1;
144
+ color: inherit;
145
+ background: transparent;
146
+ border: none;
147
+ border-radius: 0.25rem;
148
+ opacity: var(--rozie-toast-close-opacity, 0.75);
149
+ cursor: pointer;
150
+ }
151
+ .rozie-toast-close[data-rozie-s-12d4265c]:hover {
152
+ opacity: 1;
153
+ }`);
154
+ function Toaster(_props) {
155
+ const [local, attrs] = splitProps(mergeProps({
156
+ position: "bottom-right",
157
+ duration: 4e3,
158
+ max: 0,
159
+ disablePauseOnHover: false,
160
+ ariaLabel: null,
161
+ disableSwipe: false,
162
+ stacked: false
163
+ }, _props), [
164
+ "position",
165
+ "duration",
166
+ "max",
167
+ "disablePauseOnHover",
168
+ "ariaLabel",
169
+ "disableSwipe",
170
+ "stacked",
171
+ "ref"
172
+ ]);
173
+ onMount(() => {
174
+ local.ref?.({
175
+ show,
176
+ dismiss,
177
+ clear,
178
+ patch,
179
+ promise
180
+ });
181
+ });
182
+ const [toasts, setToasts] = createSignal([]);
183
+ const [seq, setSeq] = createSignal(0);
184
+ const [swipe, setSwipe] = createSignal(null);
185
+ const [swipeGesture, setSwipeGesture] = createSignal(null);
186
+ onCleanup(() => {
187
+ unmounted = true;
188
+ teardownTimers();
189
+ });
190
+ let timers = {};
191
+ let exitFailsafes = {};
192
+ let unmounted = false;
193
+ let seqLocal = 0;
194
+ let paused = false;
195
+ function startTimer(toast) {
196
+ if (!toast || !toast.duration || toast.duration <= 0) return;
197
+ if (typeof window === "undefined") return;
198
+ const existing = timers[toast.id];
199
+ if (existing && existing.handle != null) window.clearTimeout(existing.handle);
200
+ const remaining = toast.duration;
201
+ const handle = window.setTimeout(() => dismissBegin(toast.id, "timeout"), remaining);
202
+ timers[toast.id] = {
203
+ handle,
204
+ startedAt: Date.now(),
205
+ remaining
206
+ };
207
+ }
208
+ function clearTimer(id) {
209
+ const entry = timers[id];
210
+ if (entry && entry.handle != null && typeof window !== "undefined") window.clearTimeout(entry.handle);
211
+ delete timers[id];
212
+ }
213
+ function pauseTimers() {
214
+ paused = true;
215
+ if (typeof window === "undefined") return;
216
+ for (const id in timers) {
217
+ const entry = timers[id];
218
+ if (entry.handle == null) continue;
219
+ window.clearTimeout(entry.handle);
220
+ const elapsed = Date.now() - entry.startedAt;
221
+ const remaining = Math.max(0, entry.remaining - elapsed);
222
+ timers[id] = {
223
+ handle: null,
224
+ startedAt: entry.startedAt,
225
+ remaining
226
+ };
227
+ }
228
+ }
229
+ function resumeTimers() {
230
+ paused = false;
231
+ if (typeof window === "undefined") return;
232
+ for (const id in timers) {
233
+ const entry = timers[id];
234
+ if (entry.handle != null) continue;
235
+ if (entry.remaining == null || entry.remaining <= 0) {
236
+ dismissBegin(id, "timeout");
237
+ continue;
238
+ }
239
+ const remaining = entry.remaining;
240
+ const handle = window.setTimeout(() => dismissBegin(id, "timeout"), remaining);
241
+ timers[id] = {
242
+ handle,
243
+ startedAt: Date.now(),
244
+ remaining
245
+ };
246
+ }
247
+ }
248
+ function teardownTimers() {
249
+ if (typeof window !== "undefined") {
250
+ for (const id in timers) {
251
+ const entry = timers[id];
252
+ if (entry.handle != null) window.clearTimeout(entry.handle);
253
+ }
254
+ for (const id in exitFailsafes) if (exitFailsafes[id] != null) window.clearTimeout(exitFailsafes[id]);
255
+ }
256
+ timers = {};
257
+ exitFailsafes = {};
258
+ }
259
+ function show(input) {
260
+ const t = input || {};
261
+ let id;
262
+ if (t.id != null) id = String(t.id);
263
+ else {
264
+ const s = Math.max(seq(), seqLocal);
265
+ id = "t" + s;
266
+ seqLocal = s + 1;
267
+ setSeq(s + 1);
268
+ }
269
+ const toast = {
270
+ id,
271
+ message: t.message != null ? t.message : "",
272
+ type: t.type || "info",
273
+ duration: t.duration != null ? t.duration : local.duration
274
+ };
275
+ setToasts(toasts().concat([toast]).slice(local.max > 0 ? Math.max(0, toasts().length + 1 - local.max) : 0));
276
+ startTimer(toast);
277
+ return id;
278
+ }
279
+ const EXIT_FAILSAFE_MS = 350;
280
+ function removeToast(id) {
281
+ if (typeof window !== "undefined" && exitFailsafes[id] != null) window.clearTimeout(exitFailsafes[id]);
282
+ delete exitFailsafes[id];
283
+ setToasts(toasts().filter((t) => t.id !== id));
284
+ }
285
+ function dismissBegin(id, reason, extra) {
286
+ const entry = toasts().find((t) => t.id === id);
287
+ if (!entry || entry.exiting) return;
288
+ clearTimer(id);
289
+ _props.onDismissed?.({
290
+ toast: entry,
291
+ reason
292
+ });
293
+ setToasts(toasts().map((t) => t.id === id ? {
294
+ ...t,
295
+ exiting: true,
296
+ ...extra || {}
297
+ } : t));
298
+ if (typeof window === "undefined") removeToast(id);
299
+ else exitFailsafes[id] = window.setTimeout(() => removeToast(id), EXIT_FAILSAFE_MS);
300
+ }
301
+ function dismiss(id) {
302
+ dismissBegin(id, "api");
303
+ }
304
+ function clear() {
305
+ teardownTimers();
306
+ setToasts([]);
307
+ }
308
+ function patch(id, changes) {
309
+ const c = changes || {};
310
+ let existed = false;
311
+ const next = toasts().map((t) => {
312
+ if (t.id !== id) return t;
313
+ if (t.exiting) return t;
314
+ existed = true;
315
+ const merged = { ...t };
316
+ if (c.message !== void 0) merged.message = c.message;
317
+ if (c.type !== void 0) merged.type = c.type;
318
+ if (c.duration !== void 0) merged.duration = c.duration;
319
+ return merged;
320
+ });
321
+ if (!existed) return false;
322
+ setToasts(next);
323
+ if (c.duration !== void 0) {
324
+ clearTimer(id);
325
+ const patched = next.find((t) => t.id === id);
326
+ if (paused) {
327
+ if (patched && patched.duration > 0 && typeof window !== "undefined") timers[id] = {
328
+ handle: null,
329
+ startedAt: Date.now(),
330
+ remaining: patched.duration
331
+ };
332
+ } else startTimer(patched);
333
+ }
334
+ return true;
335
+ }
336
+ function settlePromise(id, type, messageOrFn, value) {
337
+ if (unmounted) return;
338
+ const entry = toasts().find((t) => t.id === id);
339
+ if (!entry || entry.exiting) return;
340
+ patch(id, {
341
+ type,
342
+ message: typeof messageOrFn === "function" ? messageOrFn(value) : messageOrFn,
343
+ duration: local.duration
344
+ });
345
+ }
346
+ function promise(p, opts) {
347
+ const o = opts || {};
348
+ const id = show({
349
+ type: "loading",
350
+ duration: 0,
351
+ message: o.loading
352
+ });
353
+ if (p && typeof p.then === "function") p.then((value) => settlePromise(id, "success", o.success, value)).catch((err) => settlePromise(id, "error", o.error, err));
354
+ return id;
355
+ }
356
+ function swipeAxisFor(position) {
357
+ return position === "top-center" || position === "bottom-center" ? "y" : "x";
358
+ }
359
+ function swipeSignFor(position) {
360
+ if (position === "top-right" || position === "bottom-right") return 1;
361
+ if (position === "top-left" || position === "bottom-left") return -1;
362
+ if (position === "bottom-center") return 1;
363
+ return -1;
364
+ }
365
+ function onToastPointerDown(t, event) {
366
+ if (local.disableSwipe) return;
367
+ if (event.button != null && event.button !== 0) return;
368
+ if (event.target && event.target.closest ? event.target.closest("button, a") : null) return;
369
+ const axis = swipeAxisFor(local.position);
370
+ const sign = swipeSignFor(local.position);
371
+ const el = event.currentTarget;
372
+ const size = axis === "x" ? el.offsetWidth : el.offsetHeight;
373
+ setSwipeGesture({
374
+ id: t.id,
375
+ axis,
376
+ sign,
377
+ size,
378
+ startX: event.clientX,
379
+ startY: event.clientY,
380
+ startTime: Date.now()
381
+ });
382
+ if (el && el.setPointerCapture) try {
383
+ el.setPointerCapture(event.pointerId);
384
+ } catch (e) {}
385
+ }
386
+ function onToastPointerMove(t, event) {
387
+ if (local.disableSwipe) return;
388
+ const gesture = swipeGesture();
389
+ if (!gesture || gesture.id !== t.id) return;
390
+ const raw = gesture.axis === "x" ? event.clientX - gesture.startX : event.clientY - gesture.startY;
391
+ const d = raw * gesture.sign > 0 ? raw : raw * .15;
392
+ setSwipe({
393
+ id: t.id,
394
+ d,
395
+ axis: gesture.axis,
396
+ sign: gesture.sign,
397
+ size: gesture.size
398
+ });
399
+ }
400
+ function onToastPointerUp(t, event) {
401
+ if (local.disableSwipe) return;
402
+ const gesture = swipeGesture();
403
+ setSwipeGesture(null);
404
+ const dragState = swipe();
405
+ setSwipe(null);
406
+ if (!gesture || gesture.id !== t.id || !dragState) return;
407
+ const elapsed = Math.max(1, Date.now() - gesture.startTime);
408
+ const magnitude = dragState.d * gesture.sign;
409
+ const velocity = magnitude / elapsed;
410
+ if (magnitude > 0 && (magnitude > gesture.size * .45 || velocity > .11)) dismissBegin(t.id, "swipe", { swipeExitSign: gesture.sign });
411
+ }
412
+ function onToastPointerCancel(t) {
413
+ if (local.disableSwipe) return;
414
+ if (swipeGesture() && swipeGesture().id === t.id) setSwipeGesture(null);
415
+ if (swipe() && swipe().id === t.id) setSwipe(null);
416
+ }
417
+ function depth(t) {
418
+ const idx = toasts().findIndex((x) => x.id === t.id);
419
+ return idx === -1 ? 0 : toasts().length - 1 - idx;
420
+ }
421
+ function toastStyle(t) {
422
+ const depthDecl = "--rozie-toast-depth: " + depth(t) + ";";
423
+ if (t.exiting) return t.swipeExitSign != null ? depthDecl + " --rozie-toast-swipe-exit: " + t.swipeExitSign + ";" : depthDecl;
424
+ const dragState = swipe();
425
+ if (!dragState || dragState.id !== t.id) return depthDecl;
426
+ const translate = dragState.axis === "x" ? "translateX(" + dragState.d + "px)" : "translateY(" + dragState.d + "px)";
427
+ const magnitude = dragState.d * dragState.sign;
428
+ const opacity = magnitude > 0 && dragState.size > 0 ? Math.max(.3, 1 - magnitude / dragState.size) : 1;
429
+ return depthDecl + " transform: " + translate + "; opacity: " + opacity + "; transition: none;";
430
+ }
431
+ function onMouseEnter() {
432
+ if (local.disablePauseOnHover) return;
433
+ pauseTimers();
434
+ }
435
+ function onMouseLeave() {
436
+ if (local.disablePauseOnHover) return;
437
+ resumeTimers();
438
+ }
439
+ function regionLabel() {
440
+ return local.ariaLabel != null ? local.ariaLabel : "Notifications";
441
+ }
442
+ function liveFor(type) {
443
+ return type === "error" || type === "warning" ? "assertive" : "polite";
444
+ }
445
+ return <>
446
+ <div role="region" aria-label={rozieAttr(regionLabel())} {...attrs} class={"rozie-toaster " + rozieClass("rozie-toaster--" + local.position + (local.stacked ? " rozie-toaster--stacked" : "")) + (attrs.class ? " " + attrs.class : "")} {...mergeListeners({
447
+ onMouseEnter: ($event) => {
448
+ onMouseEnter();
449
+ },
450
+ onMouseLeave: ($event) => {
451
+ onMouseLeave();
452
+ }
453
+ }, attrs)} data-rozie-s-12d4265c="">
454
+
455
+ <Key each={toasts()} by={(t) => t.id}>{(t) => <div role="status" aria-live={rozieAttr(liveFor(t().type))} class={"rozie-toast " + rozieClass("rozie-toast--" + t().type + (t().exiting ? " rozie-toast--exiting" : "") + (t().swipeExitSign != null ? " rozie-toast--swipe-exit" : ""))} style={parseInlineStyle(toastStyle(t()))} onAnimationEnd={($event) => {
456
+ t().exiting && removeToast(t().id);
457
+ }} onPointerDown={($event) => {
458
+ onToastPointerDown(t(), $event);
459
+ }} onPointerMove={($event) => {
460
+ onToastPointerMove(t(), $event);
461
+ }} onPointerUp={($event) => {
462
+ onToastPointerUp(t(), $event);
463
+ }} onPointerCancel={($event) => {
464
+ onToastPointerCancel(t());
465
+ }} data-rozie-s-12d4265c="">
466
+ {(_props.toastSlot ?? _props.slots?.["toast"])?.({
467
+ toast: t(),
468
+ dismiss
469
+ }) ?? <>{<Show when={t().type === "loading"}><span class={"rozie-toast-spinner"} aria-hidden="true" data-rozie-s-12d4265c="" /></Show>}<span class={"rozie-toast-message"} data-rozie-s-12d4265c="">{rozieDisplay(t().message)}</span><button type="button" aria-label="Dismiss" class={"rozie-toast-close"} onClick={($event) => {
470
+ dismissBegin(t().id, "close");
471
+ }} data-rozie-s-12d4265c="">×</button></>}
472
+ </div>}</Key>
473
+ </div>
474
+ </>;
475
+ }
476
+ //#endregion
477
+ export { Toaster, Toaster as default };
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@rozie-ui/toast-solid",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "private": false,
6
+ "license": "MIT",
7
+ "description": "Idiomatic Solid headless, accessible toast / notification host (queue, auto-dismiss, hover-pause, positioning, imperative show/dismiss/clear handle) — one accessible Rozie source compiled to Solid.",
8
+ "keywords": [
9
+ "rozie",
10
+ "rozie-ui",
11
+ "toast",
12
+ "toaster",
13
+ "notification",
14
+ "snackbar",
15
+ "headless",
16
+ "accessibility",
17
+ "aria",
18
+ "component",
19
+ "solid"
20
+ ],
21
+ "author": "One Learning Community (https://github.com/One-Learning-Community)",
22
+ "homepage": "https://github.com/One-Learning-Community/rozie.js#readme",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/One-Learning-Community/rozie.js.git",
26
+ "directory": "packages/ui/toast/packages/solid"
27
+ },
28
+ "bugs": {
29
+ "url": "https://github.com/One-Learning-Community/rozie.js/issues"
30
+ },
31
+ "main": "./dist/index.cjs",
32
+ "module": "./dist/index.mjs",
33
+ "types": "./dist/index.d.mts",
34
+ "exports": {
35
+ ".": {
36
+ "types": "./dist/index.d.mts",
37
+ "import": "./dist/index.mjs",
38
+ "require": "./dist/index.cjs"
39
+ },
40
+ "./source": "./src/Toaster.tsx",
41
+ "./themes/*": "./src/themes/*"
42
+ },
43
+ "files": [
44
+ "dist",
45
+ "src"
46
+ ],
47
+ "dependencies": {
48
+ "@solid-primitives/keyed": "^1.5.3",
49
+ "@rozie/runtime-solid": "0.2.0"
50
+ },
51
+ "peerDependencies": {
52
+ "solid-js": "^1.8"
53
+ },
54
+ "peerDependenciesMeta": {
55
+ "solid-js": {
56
+ "optional": false
57
+ }
58
+ },
59
+ "publishConfig": {
60
+ "access": "public"
61
+ },
62
+ "scripts": {
63
+ "build": "tsdown",
64
+ "typecheck": "tsc --noEmit"
65
+ }
66
+ }