@yusufceng1z/ding 0.0.0-stage → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +38 -2
- package/dist/index.cjs +943 -0
- package/dist/index.d.cts +164 -0
- package/dist/index.d.ts +164 -0
- package/dist/index.js +904 -0
- package/package.json +47 -3
package/dist/index.js
ADDED
|
@@ -0,0 +1,904 @@
|
|
|
1
|
+
// src/sound.ts
|
|
2
|
+
var ctx;
|
|
3
|
+
var CUES = {
|
|
4
|
+
success: [[392, 0, 1], [523.3, 0.1, 1]],
|
|
5
|
+
error: [[233.1, 0, 1], [185, 0.13, 1]],
|
|
6
|
+
warning: [[349.2, 0, 0.8], [349.2, 0.16, 0.6]],
|
|
7
|
+
info: [[466.2, 0, 0.9]]
|
|
8
|
+
};
|
|
9
|
+
function tone(c, out, freq, at, level) {
|
|
10
|
+
const t = c.currentTime + at;
|
|
11
|
+
const f = freq * (1 + (Math.random() - 0.5) * 8e-3);
|
|
12
|
+
for (const [mult, gain, decay] of [[1, 0.6, 0.5], [2, 0.06, 0.15]]) {
|
|
13
|
+
const osc = c.createOscillator();
|
|
14
|
+
const g = c.createGain();
|
|
15
|
+
osc.frequency.value = f * mult;
|
|
16
|
+
g.gain.setValueAtTime(1e-4, t);
|
|
17
|
+
g.gain.linearRampToValueAtTime(gain * level, t + 0.015);
|
|
18
|
+
g.gain.exponentialRampToValueAtTime(1e-4, t + decay);
|
|
19
|
+
osc.connect(g).connect(out);
|
|
20
|
+
osc.start(t);
|
|
21
|
+
osc.stop(t + decay + 0.05);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function chime(type, volume = 0.5) {
|
|
25
|
+
const cue = CUES[type];
|
|
26
|
+
if (!cue || typeof AudioContext === "undefined") return;
|
|
27
|
+
try {
|
|
28
|
+
ctx ??= new AudioContext();
|
|
29
|
+
if (ctx.state === "suspended") void ctx.resume();
|
|
30
|
+
if (ctx.state === "closed") return;
|
|
31
|
+
const master = ctx.createGain();
|
|
32
|
+
master.gain.value = Math.min(1, Math.max(0, volume)) * 0.45;
|
|
33
|
+
const soften = ctx.createBiquadFilter();
|
|
34
|
+
soften.type = "lowpass";
|
|
35
|
+
soften.frequency.value = 1300;
|
|
36
|
+
const echo = ctx.createDelay();
|
|
37
|
+
echo.delayTime.value = 0.11;
|
|
38
|
+
const wet = ctx.createGain();
|
|
39
|
+
wet.gain.value = 0.1;
|
|
40
|
+
master.connect(soften);
|
|
41
|
+
soften.connect(ctx.destination);
|
|
42
|
+
soften.connect(echo).connect(wet).connect(ctx.destination);
|
|
43
|
+
for (const [f, at, level] of cue) tone(ctx, master, f, at, level);
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/store.ts
|
|
49
|
+
var TIMING = {
|
|
50
|
+
/** shape arrives, then the pill opens */
|
|
51
|
+
openDelay: 450,
|
|
52
|
+
/** text erase + shrink back to shape */
|
|
53
|
+
closing: 340,
|
|
54
|
+
/** shape leaves the screen */
|
|
55
|
+
exit: 220,
|
|
56
|
+
duration: 5e3
|
|
57
|
+
};
|
|
58
|
+
var autoDuration = (type, hasAction) => type === "loading" || type === "error" || hasAction ? 0 : TIMING.duration;
|
|
59
|
+
function createToaster() {
|
|
60
|
+
let state = { toasts: [], position: "top-center", theme: "system", status: "", alert: "" };
|
|
61
|
+
let flip = false;
|
|
62
|
+
const subs = /* @__PURE__ */ new Set();
|
|
63
|
+
const entries = /* @__PURE__ */ new Map();
|
|
64
|
+
let counter = 0;
|
|
65
|
+
let sound = false;
|
|
66
|
+
let volume = 0.5;
|
|
67
|
+
const live = /* @__PURE__ */ new Map();
|
|
68
|
+
const owner = /* @__PURE__ */ new Map();
|
|
69
|
+
const emit = () => subs.forEach((fn) => fn());
|
|
70
|
+
const setToasts = (toasts) => {
|
|
71
|
+
state = { ...state, toasts };
|
|
72
|
+
emit();
|
|
73
|
+
};
|
|
74
|
+
const announce = (type, title, description) => {
|
|
75
|
+
if (typeof sound === "function") sound(type);
|
|
76
|
+
else if (sound) chime(type, volume);
|
|
77
|
+
flip = !flip;
|
|
78
|
+
const text = (description ? `${title}. ${description}` : title) + (flip ? "\xA0" : "");
|
|
79
|
+
state = { ...state, [type === "error" ? "alert" : "status"]: text };
|
|
80
|
+
emit();
|
|
81
|
+
};
|
|
82
|
+
const find = (id) => state.toasts.find((t) => t.id === id);
|
|
83
|
+
const patch = (id, p) => setToasts(state.toasts.map((t) => t.id === id ? { ...t, ...p } : t));
|
|
84
|
+
function startLife(id) {
|
|
85
|
+
const e = entries.get(id);
|
|
86
|
+
if (!e) return;
|
|
87
|
+
clearTimeout(e.lifeTimer);
|
|
88
|
+
e.lifeTimer = void 0;
|
|
89
|
+
if (find(id)?.phase !== "open" || e.paused || e.remaining <= 0) return;
|
|
90
|
+
e.startedAt = Date.now();
|
|
91
|
+
e.lifeTimer = setTimeout(() => dismiss(id), e.remaining);
|
|
92
|
+
}
|
|
93
|
+
function show(type, title, opts = {}) {
|
|
94
|
+
if (opts.id === void 0 && !opts.action && !opts.secondary && !opts.image && !opts.meta) {
|
|
95
|
+
const dup = state.toasts.at(-1);
|
|
96
|
+
if (dup && dup.type === type && dup.title === title && dup.description === opts.description && (dup.phase === "enter" || dup.phase === "open")) {
|
|
97
|
+
bump(dup.id);
|
|
98
|
+
return dup.id;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const id = opts.id ?? `toast-${++counter}`;
|
|
102
|
+
const cur = state.toasts.filter((t) => t.phase === "enter" || t.phase === "open").at(-1);
|
|
103
|
+
if (cur) {
|
|
104
|
+
live.set(id, cur.id);
|
|
105
|
+
owner.set(cur.id, id);
|
|
106
|
+
patch(cur.id, { count: 1 });
|
|
107
|
+
apply(cur.id, {
|
|
108
|
+
type,
|
|
109
|
+
title,
|
|
110
|
+
description: opts.description ?? "",
|
|
111
|
+
action: opts.action ?? null,
|
|
112
|
+
secondary: opts.secondary ?? null,
|
|
113
|
+
meta: opts.meta ?? null,
|
|
114
|
+
image: opts.image ?? null,
|
|
115
|
+
progress: opts.progress ?? null,
|
|
116
|
+
...opts.duration !== void 0 && { duration: opts.duration }
|
|
117
|
+
});
|
|
118
|
+
return id;
|
|
119
|
+
}
|
|
120
|
+
owner.set(id, id);
|
|
121
|
+
const first = opts.duration ?? autoDuration(type, !!(opts.action || opts.secondary));
|
|
122
|
+
const e = { startedAt: 0, remaining: first, base: first, paused: false };
|
|
123
|
+
entries.set(id, e);
|
|
124
|
+
setToasts([
|
|
125
|
+
...state.toasts,
|
|
126
|
+
{ id, type, title, description: opts.description, phase: "enter", duration: e.remaining, action: opts.action, secondary: opts.secondary, meta: opts.meta, image: opts.image, progress: opts.progress, count: 1 }
|
|
127
|
+
]);
|
|
128
|
+
announce(type, title, opts.description);
|
|
129
|
+
e.phaseTimer = setTimeout(() => {
|
|
130
|
+
if (find(id)?.phase !== "enter") return;
|
|
131
|
+
patch(id, { phase: "open" });
|
|
132
|
+
startLife(id);
|
|
133
|
+
}, TIMING.openDelay);
|
|
134
|
+
return id;
|
|
135
|
+
}
|
|
136
|
+
function update(callerId, p) {
|
|
137
|
+
const id = live.get(callerId) ?? callerId;
|
|
138
|
+
if (owner.get(id) === callerId) apply(id, p);
|
|
139
|
+
}
|
|
140
|
+
function apply(id, p) {
|
|
141
|
+
const t = find(id);
|
|
142
|
+
const e = entries.get(id);
|
|
143
|
+
if (!t || !e) return;
|
|
144
|
+
patch(id, {
|
|
145
|
+
...p.title !== void 0 && { title: p.title },
|
|
146
|
+
...p.description !== void 0 && { description: p.description },
|
|
147
|
+
...p.progress !== void 0 && { progress: p.progress ?? void 0 },
|
|
148
|
+
...p.action !== void 0 && { action: p.action ?? void 0 },
|
|
149
|
+
...p.secondary !== void 0 && { secondary: p.secondary ?? void 0 },
|
|
150
|
+
...p.meta !== void 0 && { meta: p.meta ?? void 0 },
|
|
151
|
+
...p.image !== void 0 && { image: p.image ?? void 0 },
|
|
152
|
+
...p.type !== void 0 && { type: p.type }
|
|
153
|
+
});
|
|
154
|
+
if (p.duration !== void 0) e.remaining = p.duration;
|
|
155
|
+
else if (p.type !== void 0 || p.action !== void 0 || p.secondary !== void 0) {
|
|
156
|
+
const n = find(id);
|
|
157
|
+
e.remaining = autoDuration(n.type, !!(n.action || n.secondary));
|
|
158
|
+
}
|
|
159
|
+
if (p.duration !== void 0 || p.type !== void 0 || p.action !== void 0 || p.secondary !== void 0) e.base = e.remaining, patch(id, { duration: e.remaining });
|
|
160
|
+
startLife(id);
|
|
161
|
+
const quiet = p.progress !== void 0 && p.type === void 0;
|
|
162
|
+
if (!quiet && (p.title !== void 0 || p.description !== void 0 || p.type !== void 0)) {
|
|
163
|
+
announce(p.type ?? t.type, p.title ?? t.title, p.description ?? t.description);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function act(id, which = "action") {
|
|
167
|
+
const result = find(id)?.[which]?.onClick();
|
|
168
|
+
if (result && typeof result === "object") apply(id, { action: null, secondary: null, ...result });
|
|
169
|
+
else dismiss(id);
|
|
170
|
+
}
|
|
171
|
+
function bump(id) {
|
|
172
|
+
const e = entries.get(id);
|
|
173
|
+
const t = find(id);
|
|
174
|
+
if (!e || !t) return;
|
|
175
|
+
patch(id, { count: t.count + 1 });
|
|
176
|
+
e.remaining = e.base;
|
|
177
|
+
startLife(id);
|
|
178
|
+
}
|
|
179
|
+
function dismiss(id, opts = {}) {
|
|
180
|
+
if (id === void 0) return state.toasts.forEach((t2) => dismiss(t2.id, opts));
|
|
181
|
+
id = live.get(id) ?? id;
|
|
182
|
+
const t = find(id);
|
|
183
|
+
const e = entries.get(id);
|
|
184
|
+
if (!t || !e || t.phase === "exit" || t.phase === "closing" && !opts.immediate) return;
|
|
185
|
+
clearTimeout(e.phaseTimer);
|
|
186
|
+
clearTimeout(e.lifeTimer);
|
|
187
|
+
const leave = () => {
|
|
188
|
+
patch(id, { phase: "exit" });
|
|
189
|
+
e.phaseTimer = setTimeout(() => {
|
|
190
|
+
entries.delete(id);
|
|
191
|
+
owner.delete(id);
|
|
192
|
+
live.forEach((v, k) => v === id && live.delete(k));
|
|
193
|
+
setToasts(state.toasts.filter((x) => x.id !== id));
|
|
194
|
+
}, TIMING.exit);
|
|
195
|
+
};
|
|
196
|
+
if (opts.immediate) return leave();
|
|
197
|
+
patch(id, { phase: "closing" });
|
|
198
|
+
e.phaseTimer = setTimeout(leave, TIMING.closing);
|
|
199
|
+
}
|
|
200
|
+
function pause(id) {
|
|
201
|
+
if (id === void 0) return [...entries.keys()].forEach(pause);
|
|
202
|
+
const e = entries.get(id);
|
|
203
|
+
if (!e || e.paused) return;
|
|
204
|
+
e.paused = true;
|
|
205
|
+
if (e.lifeTimer) {
|
|
206
|
+
clearTimeout(e.lifeTimer);
|
|
207
|
+
e.lifeTimer = void 0;
|
|
208
|
+
e.remaining = Math.max(0, e.remaining - (Date.now() - e.startedAt));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function resume(id) {
|
|
212
|
+
if (id === void 0) return [...entries.keys()].forEach(resume);
|
|
213
|
+
const e = entries.get(id);
|
|
214
|
+
if (!e) return;
|
|
215
|
+
e.paused = false;
|
|
216
|
+
startLife(id);
|
|
217
|
+
}
|
|
218
|
+
function promise(p, m) {
|
|
219
|
+
const id = show("loading", m.loading);
|
|
220
|
+
const pr = typeof p === "function" ? p() : p;
|
|
221
|
+
pr.then(
|
|
222
|
+
(v) => update(id, { type: "success", title: typeof m.success === "function" ? m.success(v) : m.success }),
|
|
223
|
+
(err) => update(id, { type: "error", title: typeof m.error === "function" ? m.error(err) : m.error })
|
|
224
|
+
);
|
|
225
|
+
return pr;
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
show,
|
|
229
|
+
success: (title, o) => show("success", title, o),
|
|
230
|
+
error: (title, o) => show("error", title, o),
|
|
231
|
+
warning: (title, o) => show("warning", title, o),
|
|
232
|
+
info: (title, o) => show("info", title, o),
|
|
233
|
+
loading: (title, o) => show("loading", title, o),
|
|
234
|
+
promise,
|
|
235
|
+
update,
|
|
236
|
+
act,
|
|
237
|
+
dismiss,
|
|
238
|
+
pause,
|
|
239
|
+
resume,
|
|
240
|
+
configure(c) {
|
|
241
|
+
if (c.sound !== void 0) sound = c.sound;
|
|
242
|
+
if (c.volume !== void 0) volume = c.volume;
|
|
243
|
+
state = { ...state, ...c.position && { position: c.position }, ...c.theme && { theme: c.theme } };
|
|
244
|
+
emit();
|
|
245
|
+
},
|
|
246
|
+
subscribe(fn) {
|
|
247
|
+
subs.add(fn);
|
|
248
|
+
return () => void subs.delete(fn);
|
|
249
|
+
},
|
|
250
|
+
getState: () => state
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
var toast = createToaster();
|
|
254
|
+
|
|
255
|
+
// src/spring.ts
|
|
256
|
+
function position(t, k, c, m) {
|
|
257
|
+
const w0 = Math.sqrt(k / m);
|
|
258
|
+
const z = c / (2 * Math.sqrt(k * m));
|
|
259
|
+
if (z < 1) {
|
|
260
|
+
const wd = w0 * Math.sqrt(1 - z * z);
|
|
261
|
+
return 1 - Math.exp(-z * w0 * t) * (Math.cos(wd * t) + z * w0 / wd * Math.sin(wd * t));
|
|
262
|
+
}
|
|
263
|
+
if (z === 1) return 1 - Math.exp(-w0 * t) * (1 + w0 * t);
|
|
264
|
+
const s = w0 * Math.sqrt(z * z - 1);
|
|
265
|
+
const r1 = -z * w0 + s;
|
|
266
|
+
const r2 = -z * w0 - s;
|
|
267
|
+
return 1 - (r2 * Math.exp(r1 * t) - r1 * Math.exp(r2 * t)) / (r2 - r1);
|
|
268
|
+
}
|
|
269
|
+
function springEasing(config = {}) {
|
|
270
|
+
const { stiffness = 170, damping = 18, mass = 1 } = config;
|
|
271
|
+
const f = (t) => position(t, stiffness, damping, mass);
|
|
272
|
+
const dt = 1 / 120;
|
|
273
|
+
const maxT = 5;
|
|
274
|
+
let settle = 0;
|
|
275
|
+
for (let t = 0; t <= maxT; t += dt) if (Math.abs(1 - f(t)) > 1e-3) settle = t;
|
|
276
|
+
settle = Math.max(settle + dt, 0.05);
|
|
277
|
+
const steps = Math.max(2, Math.ceil(settle * 60));
|
|
278
|
+
const pts = [];
|
|
279
|
+
for (let i = 0; i <= steps; i++) pts.push(String(+f(i / steps * settle).toFixed(4)));
|
|
280
|
+
pts[steps] = "1";
|
|
281
|
+
return { easing: `linear(${pts.join(",")})`, duration: Math.round(settle * 1e3) };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// src/styles.ts
|
|
285
|
+
var configs = {
|
|
286
|
+
enter: { stiffness: 320, damping: 26 },
|
|
287
|
+
// arrival: quick, lands with a hint of overshoot
|
|
288
|
+
morph: { stiffness: 340, damping: 27 },
|
|
289
|
+
// pill opening: liquid but controlled
|
|
290
|
+
stack: { stiffness: 400, damping: 36 }
|
|
291
|
+
// stack shuffle + fold/unfold: tight, no wobble
|
|
292
|
+
};
|
|
293
|
+
var cache;
|
|
294
|
+
var getSpringConfigs = () => configs;
|
|
295
|
+
function getSprings() {
|
|
296
|
+
return cache ??= { enter: springEasing(configs.enter), morph: springEasing(configs.morph), stack: springEasing(configs.stack) };
|
|
297
|
+
}
|
|
298
|
+
function setSprings(p) {
|
|
299
|
+
Object.assign(configs.enter, p.enter);
|
|
300
|
+
Object.assign(configs.morph, p.morph);
|
|
301
|
+
Object.assign(configs.stack, p.stack);
|
|
302
|
+
cache = void 0;
|
|
303
|
+
if (typeof document !== "undefined") {
|
|
304
|
+
const el2 = document.querySelector("style[data-toast]");
|
|
305
|
+
if (el2) el2.textContent = buildCss();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function buildCss() {
|
|
309
|
+
const { stack, enter } = getSprings();
|
|
310
|
+
return `
|
|
311
|
+
.tst-viewport{color-scheme:light dark;--tst-stack:${stack.easing};--tst-stack-dur:${stack.duration}ms;--tst-pop:${enter.easing};--tst-pop-dur:${enter.duration}ms;
|
|
312
|
+
--tst-bg:light-dark(#fff,#0c0c0d);--tst-fg:light-dark(#0f0f13,#fafafa);--tst-ring:light-dark(oklch(0 0 0/.08),oklch(1 0 0/.1));
|
|
313
|
+
--tst-shadow:0 0 0 1px var(--tst-ring),0 4px 12px -4px light-dark(oklch(0 0 0/.14),oklch(0 0 0/.45));
|
|
314
|
+
--tst-success:light-dark(#12a36b,#4ade80);--tst-error:light-dark(#e5484d,#f87171);--tst-warning:light-dark(#c77d00,#fbbf24);--tst-info:light-dark(#2f7de1,#60a5fa);
|
|
315
|
+
--tst-size:44px;--tst-radius:22px;--tst-gap:8px;--tst-pad:16px;--tst-stack-offset:10px;--tst-stack-scale:.05;
|
|
316
|
+
position:fixed;inset:0;z-index:2147483647;pointer-events:none;font:500 14px/1.3 ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;-webkit-font-smoothing:antialiased}
|
|
317
|
+
.tst-viewport[data-theme=light]{color-scheme:light}
|
|
318
|
+
.tst-viewport[data-theme=dark]{color-scheme:dark}
|
|
319
|
+
.tst-viewport:dir(rtl){--tst-flip:-1}
|
|
320
|
+
.tst-viewport:dir(rtl) .tst-progress::after{transform-origin:right}
|
|
321
|
+
.tst-viewport[data-position^=top]{--tst-dir:-1}
|
|
322
|
+
.tst-viewport[data-position^=bottom]{--tst-dir:1}
|
|
323
|
+
.tst-viewport{--tst-y0:calc(var(--tst-dir,-1)*(var(--tst-size) + var(--tst-pad) + 24px))}
|
|
324
|
+
.tst-viewport[data-position$=center]{--tst-ox:50%;--tx:-50%}
|
|
325
|
+
.tst-viewport[data-position$=left]{--tst-ox:0%;--tx:0px}
|
|
326
|
+
.tst-viewport[data-position$=right]{--tst-ox:100%;--tx:0px}
|
|
327
|
+
.tst-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
|
|
328
|
+
.tst-slot{position:absolute;pointer-events:auto;touch-action:none;user-select:none;cursor:grab;--tst-i:0;
|
|
329
|
+
--y:calc(var(--tst-dir)*-1*var(--tst-i)*var(--tst-stack-offset));--s:calc(1 - var(--tst-i)*var(--tst-stack-scale));
|
|
330
|
+
transform:translate(calc(var(--tx) + var(--dx,0px)),calc(var(--y) + var(--dy,0px))) scale(var(--s));
|
|
331
|
+
transform-origin:var(--tst-ox) var(--tst-oy);z-index:calc(100 - var(--tst-i));
|
|
332
|
+
transition-property:transform,opacity;transition-duration:var(--tst-stack-dur),.25s;transition-timing-function:var(--tst-stack),ease-out}
|
|
333
|
+
.tst-slot::after{content:'';position:absolute;z-index:-1;left:0;right:0;top:calc(var(--tst-gap)/-2);bottom:calc(var(--tst-gap)/-2)}
|
|
334
|
+
.tst-slot[data-dragging]{transition:none;cursor:grabbing}
|
|
335
|
+
.tst-slot[data-flung]{transition:transform .38s cubic-bezier(.2,.8,.3,1),opacity .25s ease-out;opacity:0;pointer-events:none}
|
|
336
|
+
.tst-viewport[data-position^=top] .tst-slot{top:calc(var(--tst-pad) + env(safe-area-inset-top,0px));--tst-oy:0%}
|
|
337
|
+
.tst-viewport[data-position^=bottom] .tst-slot{bottom:calc(var(--tst-pad) + env(safe-area-inset-bottom,0px));--tst-oy:100%}
|
|
338
|
+
.tst-viewport[data-position$=center] .tst-slot{left:50%}
|
|
339
|
+
.tst-viewport[data-position$=left] .tst-slot{left:var(--tst-pad)}
|
|
340
|
+
.tst-viewport[data-position$=right] .tst-slot{right:var(--tst-pad)}
|
|
341
|
+
/* --c: status color for the glyph \xB7 --fill/--on: status surface + its text (used by filled styles) */
|
|
342
|
+
.tst{--c:var(--tst-fg);--fill:var(--tst-bg);--on:var(--tst-fg);--tp:0;--ap:0;position:relative;box-sizing:border-box;width:var(--tst-size);height:var(--tst-size);border:1px solid transparent;
|
|
343
|
+
border-radius:var(--r,min(var(--tst-radius),calc(var(--tst-size)/2)));overflow:hidden;color:var(--on);background:var(--fill);box-shadow:var(--tst-shadow);
|
|
344
|
+
translate:0 var(--tst-y0);scale:var(--tst-enter-scale,.5);opacity:0;will-change:translate,scale}
|
|
345
|
+
.tst[data-settled]{will-change:auto}
|
|
346
|
+
.tst[data-settled] .tst-body{filter:none;transform:none}
|
|
347
|
+
.tst[data-phase=exit]{animation:tst-out .15s ease-out both}
|
|
348
|
+
.tst[data-type=success]{--c:var(--tst-success)}
|
|
349
|
+
.tst[data-type=error]{--c:var(--tst-error)}
|
|
350
|
+
.tst[data-type=warning]{--c:var(--tst-warning)}
|
|
351
|
+
.tst[data-type=info]{--c:var(--tst-info)}
|
|
352
|
+
|
|
353
|
+
.tst-icon{position:absolute;inset-inline-start:0;top:0;width:var(--tst-size);height:var(--tst-size);display:grid;place-items:center}
|
|
354
|
+
.tst-media{width:28px;height:28px;border-radius:50%;object-fit:cover;outline:1px solid light-dark(oklch(0 0 0/.1),oklch(1 0 0/.1));outline-offset:-1px;animation:tst-swap var(--tst-stack-dur) var(--tst-stack) .1s both}
|
|
355
|
+
.tst-badge{position:relative;width:24px;height:24px;display:grid;place-items:center}
|
|
356
|
+
.tst-svg{width:22px;height:22px;fill:none;stroke:var(--c);stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;transition:stroke .3s cubic-bezier(.2,0,0,1);animation:tst-swap var(--tst-stack-dur) var(--tst-stack) .1s both}
|
|
357
|
+
.tst-svg path{stroke-dasharray:1;stroke-dashoffset:1;animation:tst-draw .5s cubic-bezier(.4,0,.2,1) .15s forwards}
|
|
358
|
+
.tst-svg path:first-child{stroke-dasharray:1 1;transition:stroke-dasharray .65s cubic-bezier(.4,0,.2,1)}
|
|
359
|
+
.tst[data-type=loading] .tst-svg path:first-child{stroke-dasharray:.28 .72}
|
|
360
|
+
.tst{--md:.55s}
|
|
361
|
+
.tst[data-ready]{--md:.05s}
|
|
362
|
+
.tst-svg path{transform-box:fill-box;transform-origin:center}
|
|
363
|
+
.tst-svg path:nth-child(n+2){animation-duration:.32s;animation-delay:var(--md)}
|
|
364
|
+
.tst-svg path:nth-child(3){animation-delay:calc(var(--md) + .08s)}
|
|
365
|
+
/* each status has its own little gesture, built from the parts of its glyph */
|
|
366
|
+
.tst[data-type=success] .tst-svg{animation:tst-swap var(--tst-stack-dur) var(--tst-stack) .1s both,tst-pulse .45s var(--tst-pop) calc(var(--md) + .25s)}
|
|
367
|
+
.tst[data-type=success] .tst-badge::after{content:'';position:absolute;inset:1px;border-radius:50%;border:1.5px solid var(--c);opacity:0;animation:tst-ripple .7s cubic-bezier(.2,0,0,1) calc(var(--md) + .25s)}
|
|
368
|
+
.tst[data-type=error] .tst-svg{animation:tst-swap var(--tst-stack-dur) var(--tst-stack) .1s both,tst-shake .42s cubic-bezier(.3,0,.3,1) calc(var(--md) + .3s)}
|
|
369
|
+
.tst[data-type=warning] .tst-svg path:nth-child(2){stroke-dasharray:none;stroke-dashoffset:0;animation:tst-drop .5s var(--tst-pop) var(--md) both}
|
|
370
|
+
.tst[data-type=warning] .tst-svg path:nth-child(3){stroke-dasharray:none;stroke-dashoffset:0;animation:tst-dot .38s var(--tst-pop) calc(var(--md) + .16s) both}
|
|
371
|
+
.tst[data-type=info] .tst-svg path:nth-child(3){stroke-dasharray:none;stroke-dashoffset:0;animation:tst-dot .4s var(--tst-pop) var(--md) both}
|
|
372
|
+
.tst[data-type=info] .tst-svg path:nth-child(2){animation-delay:calc(var(--md) + .16s)}
|
|
373
|
+
|
|
374
|
+
.tst-body{position:absolute;inset-inline-start:calc(var(--tst-size) - 1px);top:-1px;display:flex;flex-wrap:wrap;align-items:center;gap:0 8px;width:max-content;max-width:calc(100vw - 2*var(--tst-pad) - var(--tst-size) + 1px);min-height:var(--tst-size);padding-inline-end:18px;
|
|
375
|
+
opacity:calc(var(--tp)*1.5 - .25);filter:blur(calc((1 - var(--tp))*10px));transform:translateX(calc((1 - var(--tp))*-12px*var(--tst-flip,1)))}
|
|
376
|
+
.tst-body:has(.tst-action,.tst-close){padding-inline-end:8px;padding-bottom:0}
|
|
377
|
+
.tst-body[data-wrapped]{padding-bottom:10px}
|
|
378
|
+
.tst-body[data-wrapped] .tst-copy{flex-basis:100%;max-width:none}
|
|
379
|
+
.tst-body[data-wrapped] .tst-copy + *{margin-inline-start:auto}
|
|
380
|
+
.tst-copy{width:max-content;max-width:min(340px,calc(100vw - 176px));padding-block:12px;padding-inline:0 6px;line-height:1.4;text-wrap:pretty;overflow-wrap:anywhere}
|
|
381
|
+
.tst-title{font-weight:550;font-variant-numeric:tabular-nums}
|
|
382
|
+
.tst-count,.tst-meta{margin-inline-start:6px;opacity:.7}
|
|
383
|
+
.tst-meta{font-weight:450;font-size:12px}
|
|
384
|
+
.tst-timer{position:absolute;inset:auto 0 0 0;height:2px;background:var(--c);opacity:.45;transform-origin:left;animation:tst-timer var(--tst-life) linear forwards;pointer-events:none}
|
|
385
|
+
.tst-viewport:hover .tst-timer,.tst-viewport:has(:focus-visible) .tst-timer{animation-play-state:paused}
|
|
386
|
+
.tst-viewport:dir(rtl) .tst-timer{transform-origin:right}
|
|
387
|
+
.tst-ghost{position:absolute;inset-inline-start:0;top:0;pointer-events:none}
|
|
388
|
+
.tst-progress{position:absolute;inset:auto 0 0 0;height:3px;background:color-mix(in srgb,var(--tst-fg) 14%,transparent);opacity:var(--tp);pointer-events:none}
|
|
389
|
+
.tst-progress::after{content:'';position:absolute;inset:0;background:var(--c);transform-origin:left;transform:scaleX(var(--pg,0));transition:transform .3s cubic-bezier(.2,0,0,1)}
|
|
390
|
+
.tst-desc{margin-top:3px;font-size:13px;font-weight:450;opacity:.65}
|
|
391
|
+
.tst[data-phase=open] .tst-desc{animation:tst-in-up var(--tst-pop-dur) var(--tst-pop) .1s both}
|
|
392
|
+
.tst[data-phase=open] .tst-action,.tst[data-phase=open] .tst-close{animation:tst-in-btn var(--tst-pop-dur) var(--tst-pop) .16s backwards}
|
|
393
|
+
.tst[data-phase=open] .tst-secondary{animation-delay:.1s}
|
|
394
|
+
.tst-action,.tst-close{flex:none;border:0;color:inherit;font:inherit;cursor:pointer;background:transparent;
|
|
395
|
+
opacity:calc(var(--ap)*1.3 - .15);transform:scale(calc(.85 + var(--ap)*.15));
|
|
396
|
+
transition-property:background-color,scale;transition-duration:.15s;transition-timing-function:ease-out}
|
|
397
|
+
.tst-action{height:30px;padding:0 14px;border-radius:999px;font-size:13px;font-weight:600;background:var(--tst-fg);color:var(--tst-bg)}
|
|
398
|
+
.tst-secondary{background:transparent;color:color-mix(in srgb,var(--tst-fg) 65%,transparent);padding:0 10px}
|
|
399
|
+
.tst-close{width:30px;height:30px;padding:0;border-radius:50%;display:grid;place-items:center}
|
|
400
|
+
.tst-close svg{width:12px;height:12px;fill:none;stroke:currentColor;stroke-width:2.4;stroke-linecap:round}
|
|
401
|
+
@media (hover:hover){.tst-action:hover{background:color-mix(in srgb,var(--tst-fg) 82%,var(--tst-bg))}.tst-secondary:hover,.tst-close:hover{background:color-mix(in srgb,var(--tst-fg) 10%,transparent);color:var(--tst-fg)}}
|
|
402
|
+
.tst-action:not(:disabled):active,.tst-close:not(:disabled):active{scale:.96}
|
|
403
|
+
.tst-action:focus-visible,.tst-close:focus-visible{outline:2px solid var(--tst-fg);outline-offset:2px}
|
|
404
|
+
|
|
405
|
+
@keyframes tst-out{to{transform:translateY(calc(var(--tst-dir)*12px)) scale(.92);opacity:0;filter:blur(4px)}}
|
|
406
|
+
@keyframes tst-swap{from{opacity:0;scale:.25;filter:blur(4px)}}
|
|
407
|
+
@keyframes tst-timer{to{transform:scaleX(0)}}
|
|
408
|
+
@keyframes tst-in-btn{from{opacity:0;translate:0 8px;filter:blur(4px)}}
|
|
409
|
+
@keyframes tst-in-up{from{opacity:0;transform:translateY(12px);filter:blur(4px)}}
|
|
410
|
+
@keyframes tst-draw{to{stroke-dashoffset:0}}
|
|
411
|
+
@keyframes tst-pulse{40%{transform:scale(1.14)}}
|
|
412
|
+
@keyframes tst-ripple{from{opacity:.55;transform:scale(1)}to{opacity:0;transform:scale(1.9)}}
|
|
413
|
+
@keyframes tst-shake{20%{translate:-2.5px 0}45%{translate:2.5px 0}70%{translate:-1.5px 0}to{translate:0}}
|
|
414
|
+
@keyframes tst-drop{from{opacity:0;translate:0 -5px}}
|
|
415
|
+
@keyframes tst-dot{from{opacity:0;scale:0}}
|
|
416
|
+
@keyframes tst-fade{from{opacity:0}}
|
|
417
|
+
@keyframes tst-fade-out{to{opacity:0}}
|
|
418
|
+
@media (prefers-reduced-motion:reduce){
|
|
419
|
+
.tst{translate:none!important;scale:none!important;animation:tst-fade .2s ease-out both}
|
|
420
|
+
.tst[data-phase=exit],.tst-body{filter:none!important;transform:none!important}
|
|
421
|
+
.tst-svg,.tst-desc,.tst-media,.tst-action,.tst-close,.tst-badge::after{animation:none!important}
|
|
422
|
+
.tst-timer{display:none}
|
|
423
|
+
.tst-svg path{animation:none!important;stroke-dashoffset:0!important}
|
|
424
|
+
.tst-slot{transition-property:opacity}
|
|
425
|
+
}
|
|
426
|
+
`;
|
|
427
|
+
}
|
|
428
|
+
function injectStyles(doc = document) {
|
|
429
|
+
if (doc.querySelector("style[data-toast]")) return;
|
|
430
|
+
const el2 = doc.createElement("style");
|
|
431
|
+
el2.setAttribute("data-toast", "");
|
|
432
|
+
el2.textContent = buildCss();
|
|
433
|
+
doc.head.prepend(el2);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// src/motion.ts
|
|
437
|
+
var Spring = class {
|
|
438
|
+
constructor(x, cfg) {
|
|
439
|
+
this.x = x;
|
|
440
|
+
this.to = x;
|
|
441
|
+
this.cfg = { stiffness: 170, damping: 18, mass: 1, ...cfg };
|
|
442
|
+
}
|
|
443
|
+
x;
|
|
444
|
+
v = 0;
|
|
445
|
+
to;
|
|
446
|
+
cfg;
|
|
447
|
+
tune(c) {
|
|
448
|
+
Object.assign(this.cfg, c);
|
|
449
|
+
}
|
|
450
|
+
/** Advance dt seconds. Returns true while still moving. */
|
|
451
|
+
step(dt) {
|
|
452
|
+
const { stiffness: k, damping: c, mass: m } = this.cfg;
|
|
453
|
+
const h = 1 / 240;
|
|
454
|
+
for (let t = 0; t < dt; t += h) {
|
|
455
|
+
this.v += (-k * (this.x - this.to) - c * this.v) / m * h;
|
|
456
|
+
this.x += this.v * h;
|
|
457
|
+
}
|
|
458
|
+
if (Math.abs(this.v) < 0.05 && Math.abs(this.x - this.to) < 0.05) {
|
|
459
|
+
this.x = this.to;
|
|
460
|
+
this.v = 0;
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
var tasks = /* @__PURE__ */ new Set();
|
|
467
|
+
var raf = 0;
|
|
468
|
+
var last = 0;
|
|
469
|
+
function tick(now) {
|
|
470
|
+
const dt = Math.min(0.1, (now - last) / 1e3);
|
|
471
|
+
last = now;
|
|
472
|
+
for (const t of tasks) if (!t(dt)) tasks.delete(t);
|
|
473
|
+
raf = tasks.size ? requestAnimationFrame(tick) : 0;
|
|
474
|
+
}
|
|
475
|
+
function run(task) {
|
|
476
|
+
tasks.add(task);
|
|
477
|
+
if (!raf) {
|
|
478
|
+
last = performance.now();
|
|
479
|
+
raf = requestAnimationFrame(tick);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/bind.ts
|
|
484
|
+
var reduced = () => typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
485
|
+
var clamp = (v, a = 0, b = 1) => Math.min(b, Math.max(a, v));
|
|
486
|
+
function watchMotion(slot, id, t) {
|
|
487
|
+
const pill = slot.firstElementChild;
|
|
488
|
+
if (!(pill instanceof HTMLElement)) return () => {
|
|
489
|
+
};
|
|
490
|
+
const body = pill.querySelector(".tst-body");
|
|
491
|
+
const cs = getComputedStyle(pill);
|
|
492
|
+
const SIZE = parseFloat(cs.getPropertyValue("--tst-size")) || 44;
|
|
493
|
+
const dir = Number(cs.getPropertyValue("--tst-dir")) || -1;
|
|
494
|
+
const Y0 = dir * (SIZE + (parseFloat(cs.getPropertyValue("--tst-pad")) || 16) + 24);
|
|
495
|
+
const maxR = parseFloat(cs.getPropertyValue("--tst-radius")) || 24;
|
|
496
|
+
const num = (name, d) => {
|
|
497
|
+
const v = parseFloat(cs.getPropertyValue(name));
|
|
498
|
+
return Number.isNaN(v) ? d : v;
|
|
499
|
+
};
|
|
500
|
+
const s0 = num("--tst-enter-scale", 0.5);
|
|
501
|
+
const stretchOn = num("--tst-stretch", 1);
|
|
502
|
+
const cfg = getSpringConfigs();
|
|
503
|
+
const w = new Spring(SIZE, cfg.morph);
|
|
504
|
+
const h = new Spring(SIZE, cfg.morph);
|
|
505
|
+
const y = new Spring(Y0, cfg.enter);
|
|
506
|
+
y.to = 0;
|
|
507
|
+
const x = new Spring(0, { stiffness: 520, damping: 13 });
|
|
508
|
+
let phase = t.getState().toasts.find((x2) => x2.id === id)?.phase ?? "enter";
|
|
509
|
+
let copyEnd = SIZE, actionW = 0, fullW = SIZE, fullH = SIZE;
|
|
510
|
+
const apply = () => {
|
|
511
|
+
const tp = clamp((w.x - SIZE) / Math.max(1, copyEnd - SIZE));
|
|
512
|
+
const ap = actionW > 2 ? clamp((w.x - copyEnd) / actionW) : clamp((tp - 0.45) / 0.55);
|
|
513
|
+
const e = (y.x - Y0) / -Y0;
|
|
514
|
+
const stretch = clamp(Math.abs(y.v) / 6e3, 0, 0.18) * stretchOn;
|
|
515
|
+
const squash = clamp(Math.abs(w.v) / 2e4, 0, 0.05);
|
|
516
|
+
const k = s0 + (1 - s0) * e;
|
|
517
|
+
pill.style.width = `${w.x}px`;
|
|
518
|
+
pill.style.height = `${h.x}px`;
|
|
519
|
+
pill.style.setProperty("--r", `${Math.min(h.x / 2, maxR)}px`);
|
|
520
|
+
pill.style.translate = `${x.x}px ${y.x}px`;
|
|
521
|
+
pill.style.scale = `${k * (1 - stretch * 0.7) * (1 + squash * 0.5)} ${k * (1 + stretch) * (1 - squash)}`;
|
|
522
|
+
pill.style.opacity = String(clamp(e * 2));
|
|
523
|
+
pill.style.setProperty("--tp", tp.toFixed(3));
|
|
524
|
+
pill.style.setProperty("--ap", ap.toFixed(3));
|
|
525
|
+
pill.toggleAttribute("data-settled", tp >= 1);
|
|
526
|
+
};
|
|
527
|
+
const task = (dt) => {
|
|
528
|
+
const moving = [w.step(dt), h.step(dt), y.step(dt), x.step(dt)].some(Boolean);
|
|
529
|
+
apply();
|
|
530
|
+
if (!moving && phase !== "exit") {
|
|
531
|
+
pill.style.translate = "none";
|
|
532
|
+
pill.style.scale = "none";
|
|
533
|
+
}
|
|
534
|
+
return moving;
|
|
535
|
+
};
|
|
536
|
+
const kick = () => {
|
|
537
|
+
if (reduced()) {
|
|
538
|
+
[w, h, y, x].forEach((s) => (s.x = s.to, s.v = 0));
|
|
539
|
+
apply();
|
|
540
|
+
} else run(task);
|
|
541
|
+
};
|
|
542
|
+
const aim = () => {
|
|
543
|
+
const open = phase === "open";
|
|
544
|
+
w.to = open ? fullW : SIZE;
|
|
545
|
+
h.to = open ? fullH : SIZE;
|
|
546
|
+
};
|
|
547
|
+
const measure = () => {
|
|
548
|
+
if (!body) return;
|
|
549
|
+
const copy2 = body.querySelector(".tst-copy");
|
|
550
|
+
const action = body.querySelector(".tst-action, .tst-close");
|
|
551
|
+
const wrapped = !!copy2 && [...body.querySelectorAll(".tst-action, .tst-close")].some((b) => b.offsetTop >= copy2.offsetTop + copy2.offsetHeight);
|
|
552
|
+
body.toggleAttribute("data-wrapped", wrapped);
|
|
553
|
+
fullW = Math.ceil((SIZE + body.offsetWidth) / 2) * 2;
|
|
554
|
+
fullH = Math.max(SIZE, body.offsetHeight);
|
|
555
|
+
const stacked = !!action && !!copy2 && action.offsetTop >= copy2.offsetTop + copy2.offsetHeight;
|
|
556
|
+
copyEnd = action && copy2 && !stacked ? SIZE + copy2.offsetWidth + 6 : fullW;
|
|
557
|
+
actionW = fullW - copyEnd;
|
|
558
|
+
if (phase === "open") aim(), kick();
|
|
559
|
+
};
|
|
560
|
+
const ro = new ResizeObserver(measure);
|
|
561
|
+
if (body) ro.observe(body);
|
|
562
|
+
measure();
|
|
563
|
+
if (phase === "open") [w.x, h.x] = [fullW, fullH];
|
|
564
|
+
kick();
|
|
565
|
+
const react = (type) => {
|
|
566
|
+
if (reduced()) return;
|
|
567
|
+
if (type === "error") x.v = 380;
|
|
568
|
+
else if (type === "warning") y.v = -dir * 200;
|
|
569
|
+
else return;
|
|
570
|
+
kick();
|
|
571
|
+
};
|
|
572
|
+
let lastType = t.getState().toasts.find((e) => e.id === id)?.type;
|
|
573
|
+
let count = t.getState().toasts.find((x2) => x2.id === id)?.count ?? 1;
|
|
574
|
+
const unsub = t.subscribe(() => {
|
|
575
|
+
const it = t.getState().toasts.find((x2) => x2.id === id);
|
|
576
|
+
if (!it) return;
|
|
577
|
+
if (it.count > count && phase === "open") {
|
|
578
|
+
y.v = -dir * 240;
|
|
579
|
+
kick();
|
|
580
|
+
}
|
|
581
|
+
count = it.count;
|
|
582
|
+
if (it.type !== lastType) {
|
|
583
|
+
lastType = it.type;
|
|
584
|
+
if (phase === "open") react(it.type);
|
|
585
|
+
}
|
|
586
|
+
if (it.phase === phase) return;
|
|
587
|
+
phase = it.phase;
|
|
588
|
+
if (phase === "closing") {
|
|
589
|
+
w.tune({ stiffness: 380, damping: 36 });
|
|
590
|
+
h.tune({ stiffness: 380, damping: 36 });
|
|
591
|
+
w.v = 320;
|
|
592
|
+
} else {
|
|
593
|
+
w.tune(cfg.morph);
|
|
594
|
+
h.tune(cfg.morph);
|
|
595
|
+
if (phase === "open") {
|
|
596
|
+
w.v = -260;
|
|
597
|
+
setTimeout(() => lastType && react(lastType), 200);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
if (phase !== "exit") aim(), kick();
|
|
601
|
+
});
|
|
602
|
+
const copy = body?.querySelector(".tst-copy");
|
|
603
|
+
let snap = copy ? { html: copy.innerHTML, w: copy.offsetWidth } : void 0;
|
|
604
|
+
let ghost;
|
|
605
|
+
let lastRoll = 0;
|
|
606
|
+
const mo = new MutationObserver(() => {
|
|
607
|
+
if (!copy || !body) return;
|
|
608
|
+
const prev = snap;
|
|
609
|
+
snap = { html: copy.innerHTML, w: copy.offsetWidth };
|
|
610
|
+
if (!prev || prev.html === snap.html || phase !== "open" || reduced()) return;
|
|
611
|
+
if (performance.now() - lastRoll < 450) return;
|
|
612
|
+
lastRoll = performance.now();
|
|
613
|
+
ghost?.remove();
|
|
614
|
+
ghost = document.createElement("div");
|
|
615
|
+
ghost.className = "tst-copy tst-ghost";
|
|
616
|
+
ghost.setAttribute("aria-hidden", "true");
|
|
617
|
+
ghost.style.width = `${prev.w}px`;
|
|
618
|
+
ghost.innerHTML = prev.html;
|
|
619
|
+
body.append(ghost);
|
|
620
|
+
const g = ghost;
|
|
621
|
+
const easing = "cubic-bezier(.2,.8,.2,1)";
|
|
622
|
+
g.animate(
|
|
623
|
+
[{ opacity: 1, transform: "none", filter: "blur(0)" }, { opacity: 0, transform: "translateY(-12px)", filter: "blur(4px)" }],
|
|
624
|
+
{ duration: 280, easing, fill: "forwards" }
|
|
625
|
+
).onfinish = () => g.remove();
|
|
626
|
+
copy.animate(
|
|
627
|
+
[{ opacity: 0, transform: "translateY(12px)", filter: "blur(4px)" }, { opacity: 1, transform: "none", filter: "blur(0)" }],
|
|
628
|
+
{ duration: 380, easing }
|
|
629
|
+
);
|
|
630
|
+
});
|
|
631
|
+
if (copy) mo.observe(copy, { childList: true, characterData: true, subtree: true });
|
|
632
|
+
const getSvg = () => pill.querySelector(".tst-svg");
|
|
633
|
+
let spin;
|
|
634
|
+
let spinOn = null;
|
|
635
|
+
const startSpin = () => {
|
|
636
|
+
spin?.cancel();
|
|
637
|
+
spin = void 0;
|
|
638
|
+
spinOn = getSvg();
|
|
639
|
+
if (spinOn && !reduced()) spin = spinOn.animate([{ rotate: "0deg" }, { rotate: "360deg" }], { duration: 800, iterations: Infinity });
|
|
640
|
+
};
|
|
641
|
+
let curType = pill.dataset.type;
|
|
642
|
+
if (curType === "loading") startSpin();
|
|
643
|
+
const ready = setTimeout(() => pill.setAttribute("data-ready", ""), 900);
|
|
644
|
+
const tmo = new MutationObserver(() => {
|
|
645
|
+
const next = pill.dataset.type;
|
|
646
|
+
if (next === curType) return;
|
|
647
|
+
const was = curType;
|
|
648
|
+
curType = next;
|
|
649
|
+
if (next === "loading") return startSpin();
|
|
650
|
+
const now = getSvg();
|
|
651
|
+
if (now && was !== "loading" && !reduced()) {
|
|
652
|
+
const { easing, duration } = getSprings().stack;
|
|
653
|
+
now.animate([{ scale: 0.6, opacity: 0.3 }, { scale: 1, opacity: 1 }], { duration, easing });
|
|
654
|
+
}
|
|
655
|
+
const svg2 = spinOn;
|
|
656
|
+
if (was === "loading" && spin && svg2?.isConnected) {
|
|
657
|
+
const deg = Number(spin.currentTime) % 800 / 800 * 360;
|
|
658
|
+
spin.cancel();
|
|
659
|
+
spin = void 0;
|
|
660
|
+
svg2.animate([{ rotate: `${deg}deg` }, { rotate: "360deg" }], { duration: 650, easing: "cubic-bezier(.2,.7,.2,1)" });
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
const imo = new MutationObserver(() => {
|
|
664
|
+
if (curType === "loading" && (!spinOn?.isConnected || spinOn !== getSvg())) startSpin();
|
|
665
|
+
});
|
|
666
|
+
imo.observe(pill, { childList: true, subtree: true });
|
|
667
|
+
tmo.observe(pill, { attributes: true, attributeFilter: ["data-type"] });
|
|
668
|
+
return () => {
|
|
669
|
+
clearTimeout(ready);
|
|
670
|
+
imo.disconnect();
|
|
671
|
+
tmo.disconnect();
|
|
672
|
+
spin?.cancel();
|
|
673
|
+
ro.disconnect();
|
|
674
|
+
mo.disconnect();
|
|
675
|
+
unsub();
|
|
676
|
+
ghost?.remove();
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
function watchDrag(slot, id, t) {
|
|
680
|
+
let sx = 0, sy = 0, t0 = 0, active = false;
|
|
681
|
+
const edge = () => slot.closest(".tst-viewport")?.dataset.position?.startsWith("top") ? -1 : 1;
|
|
682
|
+
const down = (e) => {
|
|
683
|
+
if (e.button !== 0 || e.target.closest("button")) return;
|
|
684
|
+
[sx, sy, t0, active] = [e.clientX, e.clientY, e.timeStamp, true];
|
|
685
|
+
slot.setPointerCapture(e.pointerId);
|
|
686
|
+
slot.setAttribute("data-dragging", "");
|
|
687
|
+
};
|
|
688
|
+
const move = (e) => {
|
|
689
|
+
if (!active) return;
|
|
690
|
+
const dx = e.clientX - sx;
|
|
691
|
+
let dy = e.clientY - sy;
|
|
692
|
+
if (dy * edge() < 0) dy *= 0.2;
|
|
693
|
+
slot.style.setProperty("--dx", `${dx}px`);
|
|
694
|
+
slot.style.setProperty("--dy", `${dy}px`);
|
|
695
|
+
};
|
|
696
|
+
const up = (e) => {
|
|
697
|
+
if (!active) return;
|
|
698
|
+
active = false;
|
|
699
|
+
const dx = e.clientX - sx;
|
|
700
|
+
const rawDy = e.clientY - sy;
|
|
701
|
+
const dy = rawDy * edge();
|
|
702
|
+
const speed = Math.hypot(dx, dy) / Math.max(1, e.timeStamp - t0);
|
|
703
|
+
const away = dy > 40 || Math.abs(dx) > 80 || speed > 0.5 && (dy > 15 || Math.abs(dx) > 15);
|
|
704
|
+
slot.removeAttribute("data-dragging");
|
|
705
|
+
if (away) {
|
|
706
|
+
const len = Math.hypot(dx, rawDy) || 1;
|
|
707
|
+
const reach = Math.max(160, speed * 320);
|
|
708
|
+
slot.setAttribute("data-flung", "");
|
|
709
|
+
slot.style.setProperty("--dx", `${dx / len * reach}px`);
|
|
710
|
+
slot.style.setProperty("--dy", `${rawDy / len * reach}px`);
|
|
711
|
+
t.dismiss(id, { immediate: true });
|
|
712
|
+
} else slot.style.removeProperty("--dx"), slot.style.removeProperty("--dy");
|
|
713
|
+
};
|
|
714
|
+
slot.addEventListener("pointerdown", down);
|
|
715
|
+
slot.addEventListener("pointermove", move);
|
|
716
|
+
slot.addEventListener("pointerup", up);
|
|
717
|
+
slot.addEventListener("pointercancel", up);
|
|
718
|
+
return () => {
|
|
719
|
+
slot.removeEventListener("pointerdown", down);
|
|
720
|
+
slot.removeEventListener("pointermove", move);
|
|
721
|
+
slot.removeEventListener("pointerup", up);
|
|
722
|
+
slot.removeEventListener("pointercancel", up);
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
function bindToast(slot, id, t = toast) {
|
|
726
|
+
const stopDrag = watchDrag(slot, id, t);
|
|
727
|
+
const stopMotion = watchMotion(slot, id, t);
|
|
728
|
+
return () => (stopDrag(), stopMotion());
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// src/icons.ts
|
|
732
|
+
var RING = "M12 3a9 9 0 1 0 0 18a9 9 0 1 0 0-18";
|
|
733
|
+
var ICONS = {
|
|
734
|
+
success: [RING, "M7.9 12.4l3 3 5.3-6"],
|
|
735
|
+
error: [RING, "M9.3 9.3l5.4 5.4", "M14.7 9.3l-5.4 5.4"],
|
|
736
|
+
warning: [RING, "M12 7.6v5.2", "M12 16.3h.01"],
|
|
737
|
+
info: [RING, "M12 11v5.2", "M12 7.8h.01"],
|
|
738
|
+
loading: [RING]
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
// src/vanilla.ts
|
|
742
|
+
function onToastKey(e) {
|
|
743
|
+
if (e.defaultPrevented || !toast.getState().toasts.length) return;
|
|
744
|
+
if (e.key === "Escape") toast.dismiss();
|
|
745
|
+
else if (e.altKey && e.code === "KeyT") document.querySelector('.tst-viewport button:not([tabindex="-1"])')?.focus();
|
|
746
|
+
}
|
|
747
|
+
var el = (tag, cls, parent) => {
|
|
748
|
+
const n = document.createElement(tag);
|
|
749
|
+
n.className = cls;
|
|
750
|
+
parent?.append(n);
|
|
751
|
+
return n;
|
|
752
|
+
};
|
|
753
|
+
var svg = (cls, paths) => {
|
|
754
|
+
const s = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
755
|
+
s.setAttribute("viewBox", "0 0 24 24");
|
|
756
|
+
s.setAttribute("aria-hidden", "true");
|
|
757
|
+
s.setAttribute("class", cls);
|
|
758
|
+
for (const d of paths) {
|
|
759
|
+
const p = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
760
|
+
p.setAttribute("d", d);
|
|
761
|
+
p.setAttribute("pathLength", "1");
|
|
762
|
+
s.append(p);
|
|
763
|
+
}
|
|
764
|
+
return s;
|
|
765
|
+
};
|
|
766
|
+
function mountToaster(opts = {}) {
|
|
767
|
+
if (typeof document === "undefined") return () => {
|
|
768
|
+
};
|
|
769
|
+
injectStyles();
|
|
770
|
+
toast.configure(opts);
|
|
771
|
+
const vp = el("div", "tst-viewport", document.body);
|
|
772
|
+
vp.setAttribute("role", "region");
|
|
773
|
+
vp.setAttribute("aria-label", "Notifications");
|
|
774
|
+
const status = el("div", "tst-sr", vp);
|
|
775
|
+
status.setAttribute("role", "status");
|
|
776
|
+
const alert = el("div", "tst-sr", vp);
|
|
777
|
+
alert.setAttribute("role", "alert");
|
|
778
|
+
vp.onpointerenter = () => toast.pause();
|
|
779
|
+
vp.onpointerleave = () => toast.resume();
|
|
780
|
+
vp.addEventListener("focusin", (e) => e.target.matches(":focus-visible") && toast.pause());
|
|
781
|
+
vp.addEventListener("focusout", () => toast.resume());
|
|
782
|
+
document.addEventListener("keydown", onToastKey);
|
|
783
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
784
|
+
function build(t) {
|
|
785
|
+
const slot = el("div", "tst-slot", vp);
|
|
786
|
+
el("div", "tst", slot);
|
|
787
|
+
return { slot };
|
|
788
|
+
}
|
|
789
|
+
function render() {
|
|
790
|
+
const s = toast.getState();
|
|
791
|
+
vp.dataset.position = s.position;
|
|
792
|
+
vp.dataset.theme = s.theme;
|
|
793
|
+
status.textContent = s.status;
|
|
794
|
+
alert.textContent = s.alert;
|
|
795
|
+
const live = new Set(s.toasts.map((t) => t.id));
|
|
796
|
+
for (const [id, n] of nodes) if (!live.has(id)) n.off?.(), n.slot.remove(), nodes.delete(id);
|
|
797
|
+
s.toasts.forEach((t, idx) => {
|
|
798
|
+
let n = nodes.get(t.id);
|
|
799
|
+
if (!n) nodes.set(t.id, n = build(t));
|
|
800
|
+
const i = s.toasts.length - 1 - idx;
|
|
801
|
+
n.slot.style.setProperty("--tst-i", String(i));
|
|
802
|
+
const card = n.slot.firstElementChild;
|
|
803
|
+
card.dataset.phase = t.phase;
|
|
804
|
+
card.dataset.type = t.type;
|
|
805
|
+
card.style.setProperty("--tst-life", `${t.duration}ms`);
|
|
806
|
+
const iconKey = t.image ?? t.type;
|
|
807
|
+
if (n.type !== iconKey) {
|
|
808
|
+
card.querySelector(".tst-icon")?.remove();
|
|
809
|
+
const icon = el("div", "tst-icon");
|
|
810
|
+
if (t.image) Object.assign(el("img", "tst-media", icon), { src: t.image, alt: "" });
|
|
811
|
+
else el("div", "tst-badge", icon).append(svg("tst-svg", ICONS[t.type]));
|
|
812
|
+
card.prepend(icon);
|
|
813
|
+
n.type = iconKey;
|
|
814
|
+
}
|
|
815
|
+
const timed = (t.action || t.secondary) && t.duration > 0;
|
|
816
|
+
const timer = card.querySelector(".tst-timer");
|
|
817
|
+
if (!timed || timer?.dataset.k !== String(t.duration)) {
|
|
818
|
+
timer?.remove();
|
|
819
|
+
if (timed) el("div", "tst-timer", card).dataset.k = String(t.duration);
|
|
820
|
+
}
|
|
821
|
+
let bar = card.querySelector(".tst-progress");
|
|
822
|
+
if (t.progress === void 0) bar?.remove();
|
|
823
|
+
else (bar ??= card.insertBefore(el("div", "tst-progress"), card.firstChild)).style.setProperty("--pg", String(t.progress));
|
|
824
|
+
let body = card.querySelector(".tst-body");
|
|
825
|
+
if (!body) {
|
|
826
|
+
body = el("div", "tst-body", card);
|
|
827
|
+
const copy2 = el("div", "tst-copy", body);
|
|
828
|
+
el("div", "tst-title", copy2);
|
|
829
|
+
}
|
|
830
|
+
const copy = body.querySelector(".tst-copy");
|
|
831
|
+
const title = copy.querySelector(".tst-title");
|
|
832
|
+
const label = `${t.title}|${t.count}|${t.meta ?? ""}`;
|
|
833
|
+
if (title.dataset.k !== label) {
|
|
834
|
+
title.textContent = t.title;
|
|
835
|
+
if (t.count > 1) el("span", "tst-count", title).textContent = `\xD7${t.count}`;
|
|
836
|
+
if (t.meta) el("span", "tst-meta", title).textContent = t.meta;
|
|
837
|
+
title.dataset.k = label;
|
|
838
|
+
}
|
|
839
|
+
let desc = copy.querySelector(".tst-desc");
|
|
840
|
+
if (!t.description) desc?.remove();
|
|
841
|
+
else (desc ??= el("div", "tst-desc", copy)).textContent = t.description;
|
|
842
|
+
let sec = body.querySelector(".tst-secondary");
|
|
843
|
+
if (!t.secondary) sec?.remove();
|
|
844
|
+
else {
|
|
845
|
+
if (!sec) {
|
|
846
|
+
sec = el("button", "tst-action tst-secondary");
|
|
847
|
+
sec.type = "button";
|
|
848
|
+
sec.onclick = () => toast.act(t.id, "secondary");
|
|
849
|
+
body.insertBefore(sec, body.querySelector(".tst-action"));
|
|
850
|
+
}
|
|
851
|
+
sec.textContent = t.secondary.label;
|
|
852
|
+
sec.tabIndex = t.phase === "open" ? 0 : -1;
|
|
853
|
+
}
|
|
854
|
+
let act = body.querySelector(".tst-action:not(.tst-secondary)");
|
|
855
|
+
if (!t.action) act?.remove();
|
|
856
|
+
else {
|
|
857
|
+
if (!act) {
|
|
858
|
+
act = el("button", "tst-action", body);
|
|
859
|
+
act.type = "button";
|
|
860
|
+
act.onclick = () => toast.act(t.id);
|
|
861
|
+
}
|
|
862
|
+
act.textContent = t.action.label;
|
|
863
|
+
act.tabIndex = t.phase === "open" ? 0 : -1;
|
|
864
|
+
}
|
|
865
|
+
const sticky = t.duration === 0 && t.type !== "loading" && !t.secondary;
|
|
866
|
+
let close = body.querySelector(".tst-close");
|
|
867
|
+
if (!sticky) close?.remove();
|
|
868
|
+
else {
|
|
869
|
+
if (!close) {
|
|
870
|
+
close = el("button", "tst-close", body);
|
|
871
|
+
close.type = "button";
|
|
872
|
+
close.setAttribute("aria-label", "Dismiss notification");
|
|
873
|
+
close.append(svg("", ["M6 6l12 12M18 6L6 18"]));
|
|
874
|
+
close.onclick = () => toast.dismiss(t.id);
|
|
875
|
+
}
|
|
876
|
+
close.tabIndex = t.phase === "open" ? 0 : -1;
|
|
877
|
+
}
|
|
878
|
+
n.off ??= bindToast(n.slot, t.id);
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
const off = toast.subscribe(render);
|
|
882
|
+
render();
|
|
883
|
+
return () => {
|
|
884
|
+
off();
|
|
885
|
+
document.removeEventListener("keydown", onToastKey);
|
|
886
|
+
nodes.forEach((n) => n.off?.());
|
|
887
|
+
vp.remove();
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
export {
|
|
891
|
+
ICONS,
|
|
892
|
+
TIMING,
|
|
893
|
+
bindToast,
|
|
894
|
+
buildCss,
|
|
895
|
+
chime,
|
|
896
|
+
createToaster,
|
|
897
|
+
getSprings,
|
|
898
|
+
injectStyles,
|
|
899
|
+
mountToaster,
|
|
900
|
+
onToastKey,
|
|
901
|
+
setSprings,
|
|
902
|
+
springEasing,
|
|
903
|
+
toast
|
|
904
|
+
};
|