lumatoast 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.
- package/LICENSE +0 -0
- package/README.md +522 -0
- package/dist/index.cjs +1011 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +366 -0
- package/dist/index.d.ts +366 -0
- package/dist/index.js +972 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +819 -0
- package/dist/styles.css.map +1 -0
- package/package.json +74 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1011 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/core/tokens.ts
|
|
4
|
+
var DURATION_SHORT = 2e3;
|
|
5
|
+
var DURATION_DEFAULT = 4e3;
|
|
6
|
+
var DURATION_LONG = 6e3;
|
|
7
|
+
var DURATION_INFINITE = Infinity;
|
|
8
|
+
var ANIMATION_ENTER_MS = 320;
|
|
9
|
+
var ANIMATION_EXIT_MS = 300;
|
|
10
|
+
var ANIMATION_STACK_MS = 280;
|
|
11
|
+
var TOAST_WIDTH_PX = 340;
|
|
12
|
+
var TOAST_GAP_PX = 12;
|
|
13
|
+
var Z_INDEX_BASE = 1e3;
|
|
14
|
+
var CSS_VARS = {
|
|
15
|
+
// Card layout
|
|
16
|
+
WIDTH: "--luma-width",
|
|
17
|
+
RADIUS: "--luma-radius",
|
|
18
|
+
PADDING: "--luma-padding",
|
|
19
|
+
GAP: "--luma-gap",
|
|
20
|
+
// Background & border
|
|
21
|
+
BG: "--luma-bg",
|
|
22
|
+
BORDER_COLOR: "--luma-border-color",
|
|
23
|
+
BORDER_WIDTH: "--luma-border-width",
|
|
24
|
+
SHADOW: "--luma-shadow",
|
|
25
|
+
BACKDROP: "--luma-backdrop",
|
|
26
|
+
// Typography
|
|
27
|
+
FONT: "--luma-font",
|
|
28
|
+
TITLE_SIZE: "--luma-title-size",
|
|
29
|
+
TITLE_WEIGHT: "--luma-title-weight",
|
|
30
|
+
TITLE_COLOR: "--luma-title-color",
|
|
31
|
+
DESC_SIZE: "--luma-desc-size",
|
|
32
|
+
DESC_COLOR: "--luma-desc-color",
|
|
33
|
+
LINE_HEIGHT: "--luma-line-height",
|
|
34
|
+
LETTER_SPACING: "--luma-letter-spacing",
|
|
35
|
+
// Icon
|
|
36
|
+
ICON_SIZE: "--luma-icon-size",
|
|
37
|
+
// Close button
|
|
38
|
+
CLOSE_COLOR: "--luma-close-color",
|
|
39
|
+
CLOSE_SIZE: "--luma-close-size",
|
|
40
|
+
// Action button
|
|
41
|
+
ACTION_BG: "--luma-action-bg",
|
|
42
|
+
ACTION_COLOR: "--luma-action-color",
|
|
43
|
+
ACTION_HOVER_BG: "--luma-action-hover-bg",
|
|
44
|
+
ACTION_RADIUS: "--luma-action-radius",
|
|
45
|
+
ACTION_PADDING: "--luma-action-padding",
|
|
46
|
+
ACTION_SIZE: "--luma-action-size",
|
|
47
|
+
ACTION_WEIGHT: "--luma-action-weight",
|
|
48
|
+
ACTION_BORDER: "--luma-action-border",
|
|
49
|
+
ACTION_HOVER_BORDER: "--luma-action-hover-border",
|
|
50
|
+
// Progress bar
|
|
51
|
+
PROGRESS_HEIGHT: "--luma-progress-height",
|
|
52
|
+
PROGRESS_RADIUS: "--luma-progress-radius",
|
|
53
|
+
PROGRESS_SUCCESS: "--luma-progress-success",
|
|
54
|
+
PROGRESS_ERROR: "--luma-progress-error",
|
|
55
|
+
PROGRESS_WARNING: "--luma-progress-warning",
|
|
56
|
+
PROGRESS_INFO: "--luma-progress-info",
|
|
57
|
+
PROGRESS_LOADING: "--luma-progress-loading",
|
|
58
|
+
PROGRESS_CUSTOM: "--luma-progress-custom",
|
|
59
|
+
// Accent colors (used for type-specific accents like border-left)
|
|
60
|
+
ACCENT_SUCCESS: "--luma-accent-success",
|
|
61
|
+
ACCENT_ERROR: "--luma-accent-error",
|
|
62
|
+
ACCENT_WARNING: "--luma-accent-warning",
|
|
63
|
+
ACCENT_INFO: "--luma-accent-info",
|
|
64
|
+
// Animation durations (set by animationSpeed config)
|
|
65
|
+
DURATION_ENTER: "--luma-duration-enter",
|
|
66
|
+
DURATION_EXIT: "--luma-duration-exit",
|
|
67
|
+
DURATION_STACK: "--luma-duration-stack"
|
|
68
|
+
};
|
|
69
|
+
var CLASS_CONTAINER = "luma-toast-container";
|
|
70
|
+
var CLASS_TOAST = "luma-toast";
|
|
71
|
+
var CLASS_CARD = "luma-toast-card";
|
|
72
|
+
var CLASS_ICON = "luma-toast-icon";
|
|
73
|
+
var CLASS_CONTENT = "luma-toast-content";
|
|
74
|
+
var CLASS_TITLE = "luma-toast-title";
|
|
75
|
+
var CLASS_DESCRIPTION = "luma-toast-description";
|
|
76
|
+
var CLASS_ACTION = "luma-toast-action";
|
|
77
|
+
var CLASS_CLOSE = "luma-toast-close";
|
|
78
|
+
var CLASS_PROGRESS = "luma-progress";
|
|
79
|
+
var CLASS_EXIT = "luma-toast-exit";
|
|
80
|
+
|
|
81
|
+
// src/core/constants.ts
|
|
82
|
+
var DEFAULT_DURATION = DURATION_DEFAULT;
|
|
83
|
+
var DEFAULT_POSITION = "top-right";
|
|
84
|
+
var DEFAULT_THEME = "linear";
|
|
85
|
+
var DEFAULT_DISMISSIBLE = true;
|
|
86
|
+
var DEFAULT_SHOW_ICON = true;
|
|
87
|
+
var DEFAULT_CLOSE_ON_CLICK = false;
|
|
88
|
+
var DEFAULT_PROGRESS_POS = "bottom";
|
|
89
|
+
var DEFAULT_ANIMATION_ENTER = "slide";
|
|
90
|
+
var DEFAULT_ANIMATION_EXIT = "slide";
|
|
91
|
+
var DEFAULT_ANIMATION_SPEED = "normal";
|
|
92
|
+
var MAX_VISIBLE_TOASTS = 5;
|
|
93
|
+
var STACK_GAP = TOAST_GAP_PX;
|
|
94
|
+
|
|
95
|
+
// src/utils/id.ts
|
|
96
|
+
var counter = 0;
|
|
97
|
+
function createToastId(prefix = "toast") {
|
|
98
|
+
counter += 1;
|
|
99
|
+
return `${prefix}-${Date.now()}-${counter}`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/utils/events.ts
|
|
103
|
+
var EventEmitter = class {
|
|
104
|
+
listeners = /* @__PURE__ */ new Set();
|
|
105
|
+
subscribe(listener) {
|
|
106
|
+
this.listeners.add(listener);
|
|
107
|
+
return () => {
|
|
108
|
+
this.listeners.delete(listener);
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
emit(payload) {
|
|
112
|
+
this.listeners.forEach((listener) => listener(payload));
|
|
113
|
+
}
|
|
114
|
+
clear() {
|
|
115
|
+
this.listeners.clear();
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// src/core/manager.ts
|
|
120
|
+
var globalConfig = {
|
|
121
|
+
duration: DEFAULT_DURATION,
|
|
122
|
+
position: DEFAULT_POSITION,
|
|
123
|
+
theme: DEFAULT_THEME,
|
|
124
|
+
dismissible: DEFAULT_DISMISSIBLE,
|
|
125
|
+
maxVisible: MAX_VISIBLE_TOASTS,
|
|
126
|
+
showIcon: DEFAULT_SHOW_ICON,
|
|
127
|
+
closeOnClick: DEFAULT_CLOSE_ON_CLICK,
|
|
128
|
+
progressPosition: DEFAULT_PROGRESS_POS,
|
|
129
|
+
animationEnter: DEFAULT_ANIMATION_ENTER,
|
|
130
|
+
animationExit: DEFAULT_ANIMATION_EXIT,
|
|
131
|
+
animationSpeed: DEFAULT_ANIMATION_SPEED
|
|
132
|
+
};
|
|
133
|
+
var SPEED_MAP = {
|
|
134
|
+
slow: { enter: 500, exit: 450, stack: 400 },
|
|
135
|
+
normal: { enter: 320, exit: 300, stack: 280 },
|
|
136
|
+
fast: { enter: 180, exit: 160, stack: 150 }
|
|
137
|
+
};
|
|
138
|
+
function applyAnimationSpeed(speed) {
|
|
139
|
+
if (typeof document === "undefined") return;
|
|
140
|
+
const { enter, exit, stack } = SPEED_MAP[speed];
|
|
141
|
+
const root = document.documentElement;
|
|
142
|
+
root.style.setProperty("--luma-duration-enter", `${enter}ms`);
|
|
143
|
+
root.style.setProperty("--luma-duration-exit", `${exit}ms`);
|
|
144
|
+
root.style.setProperty("--luma-duration-stack", `${stack}ms`);
|
|
145
|
+
}
|
|
146
|
+
function configure(config) {
|
|
147
|
+
globalConfig = { ...globalConfig, ...config };
|
|
148
|
+
if (config.animationSpeed) {
|
|
149
|
+
applyAnimationSpeed(config.animationSpeed);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
var ToastManager = class {
|
|
153
|
+
visible = [];
|
|
154
|
+
queue = [];
|
|
155
|
+
changes = new EventEmitter();
|
|
156
|
+
/**
|
|
157
|
+
* Returns all visible toasts.
|
|
158
|
+
*/
|
|
159
|
+
getToasts() {
|
|
160
|
+
return [...this.visible];
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Create a new toast.
|
|
164
|
+
*/
|
|
165
|
+
create(type, options = {}) {
|
|
166
|
+
const toast2 = {
|
|
167
|
+
id: options.id ?? createToastId(),
|
|
168
|
+
type,
|
|
169
|
+
title: options.title,
|
|
170
|
+
description: options.description,
|
|
171
|
+
duration: options.duration ?? globalConfig.duration,
|
|
172
|
+
dismissible: options.dismissible ?? globalConfig.dismissible,
|
|
173
|
+
position: options.position ?? globalConfig.position,
|
|
174
|
+
theme: options.theme ?? globalConfig.theme,
|
|
175
|
+
action: options.action,
|
|
176
|
+
// customization
|
|
177
|
+
className: options.className,
|
|
178
|
+
style: options.style,
|
|
179
|
+
showIcon: options.showIcon ?? globalConfig.showIcon,
|
|
180
|
+
closeOnClick: options.closeOnClick ?? globalConfig.closeOnClick,
|
|
181
|
+
progressPosition: options.progressPosition ?? globalConfig.progressPosition,
|
|
182
|
+
animationEnter: options.animationEnter ?? globalConfig.animationEnter,
|
|
183
|
+
animationExit: options.animationExit ?? globalConfig.animationExit,
|
|
184
|
+
// internal
|
|
185
|
+
createdAt: Date.now(),
|
|
186
|
+
visible: false
|
|
187
|
+
};
|
|
188
|
+
if (this.visible.length >= globalConfig.maxVisible) {
|
|
189
|
+
this.queue.push(toast2);
|
|
190
|
+
} else {
|
|
191
|
+
toast2.visible = true;
|
|
192
|
+
this.visible.push(toast2);
|
|
193
|
+
this.changes.emit(this.getToasts());
|
|
194
|
+
}
|
|
195
|
+
return toast2;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Remove a toast by id.
|
|
199
|
+
*/
|
|
200
|
+
dismiss(id) {
|
|
201
|
+
const index = this.visible.findIndex((t) => t.id === id);
|
|
202
|
+
if (index === -1) return;
|
|
203
|
+
this.visible.splice(index, 1);
|
|
204
|
+
if (this.queue.length > 0) {
|
|
205
|
+
const next = this.queue.shift();
|
|
206
|
+
next.visible = true;
|
|
207
|
+
this.visible.push(next);
|
|
208
|
+
}
|
|
209
|
+
this.changes.emit(this.getToasts());
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Remove all visible and queued toasts.
|
|
213
|
+
*/
|
|
214
|
+
dismissAll() {
|
|
215
|
+
this.visible = [];
|
|
216
|
+
this.queue = [];
|
|
217
|
+
this.changes.emit([]);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Remove the most recently added visible toast.
|
|
221
|
+
*/
|
|
222
|
+
dismissLatest() {
|
|
223
|
+
const latest = this.visible[this.visible.length - 1];
|
|
224
|
+
if (!latest) return;
|
|
225
|
+
this.dismiss(latest.id);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Update an existing toast by id.
|
|
229
|
+
* Works on both visible and queued toasts.
|
|
230
|
+
*/
|
|
231
|
+
update(id, updates) {
|
|
232
|
+
const visibleToast = this.visible.find((t) => t.id === id);
|
|
233
|
+
if (visibleToast) {
|
|
234
|
+
Object.assign(visibleToast, updates);
|
|
235
|
+
if (updates.duration !== void 0) {
|
|
236
|
+
visibleToast.createdAt = Date.now();
|
|
237
|
+
}
|
|
238
|
+
this.changes.emit(this.getToasts());
|
|
239
|
+
return visibleToast;
|
|
240
|
+
}
|
|
241
|
+
const queuedToast = this.queue.find((t) => t.id === id);
|
|
242
|
+
if (queuedToast) {
|
|
243
|
+
Object.assign(queuedToast, updates);
|
|
244
|
+
if (updates.duration !== void 0) {
|
|
245
|
+
queuedToast.createdAt = Date.now();
|
|
246
|
+
}
|
|
247
|
+
return queuedToast;
|
|
248
|
+
}
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
var toastManager = new ToastManager();
|
|
253
|
+
|
|
254
|
+
// src/core/toast.ts
|
|
255
|
+
var toast = {
|
|
256
|
+
/**
|
|
257
|
+
* Show a success toast.
|
|
258
|
+
*/
|
|
259
|
+
success(message, options = {}) {
|
|
260
|
+
return toastManager.create("success", {
|
|
261
|
+
...options,
|
|
262
|
+
description: message
|
|
263
|
+
});
|
|
264
|
+
},
|
|
265
|
+
/**
|
|
266
|
+
* Show an error toast.
|
|
267
|
+
*/
|
|
268
|
+
error(message, options = {}) {
|
|
269
|
+
return toastManager.create("error", {
|
|
270
|
+
...options,
|
|
271
|
+
description: message
|
|
272
|
+
});
|
|
273
|
+
},
|
|
274
|
+
/**
|
|
275
|
+
* Show a warning toast.
|
|
276
|
+
*/
|
|
277
|
+
warning(message, options = {}) {
|
|
278
|
+
return toastManager.create("warning", {
|
|
279
|
+
...options,
|
|
280
|
+
description: message
|
|
281
|
+
});
|
|
282
|
+
},
|
|
283
|
+
/**
|
|
284
|
+
* Show an info toast.
|
|
285
|
+
*/
|
|
286
|
+
info(message, options = {}) {
|
|
287
|
+
return toastManager.create("info", {
|
|
288
|
+
...options,
|
|
289
|
+
description: message
|
|
290
|
+
});
|
|
291
|
+
},
|
|
292
|
+
/**
|
|
293
|
+
* Show a persistent loading toast that must be dismissed manually
|
|
294
|
+
* or converted via `toast.update()` / `toast.promise()`.
|
|
295
|
+
*/
|
|
296
|
+
loading(message, options = {}) {
|
|
297
|
+
return toastManager.create("loading", {
|
|
298
|
+
...options,
|
|
299
|
+
duration: Infinity,
|
|
300
|
+
dismissible: false,
|
|
301
|
+
description: message
|
|
302
|
+
});
|
|
303
|
+
},
|
|
304
|
+
/**
|
|
305
|
+
* Show a fully custom toast.
|
|
306
|
+
* You control the title, description, action, theme, and position.
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* toast.custom("Custom notification", { title: "Hey!", theme: "cyberpunk" });
|
|
310
|
+
*/
|
|
311
|
+
custom(message, options = {}) {
|
|
312
|
+
return toastManager.create("custom", {
|
|
313
|
+
...options,
|
|
314
|
+
description: message
|
|
315
|
+
});
|
|
316
|
+
},
|
|
317
|
+
/**
|
|
318
|
+
* Dismiss a toast by id.
|
|
319
|
+
*/
|
|
320
|
+
dismiss(id) {
|
|
321
|
+
toastManager.dismiss(id);
|
|
322
|
+
},
|
|
323
|
+
/**
|
|
324
|
+
* Dismiss all visible and queued toasts.
|
|
325
|
+
*/
|
|
326
|
+
dismissAll() {
|
|
327
|
+
toastManager.dismissAll();
|
|
328
|
+
},
|
|
329
|
+
/**
|
|
330
|
+
* Dismiss the most recently added visible toast.
|
|
331
|
+
*/
|
|
332
|
+
dismissLatest() {
|
|
333
|
+
toastManager.dismissLatest();
|
|
334
|
+
},
|
|
335
|
+
/**
|
|
336
|
+
* Update an existing toast's properties.
|
|
337
|
+
* Useful for transitioning a loading toast to success or error.
|
|
338
|
+
*/
|
|
339
|
+
update(id, updates) {
|
|
340
|
+
return toastManager.update(id, updates);
|
|
341
|
+
},
|
|
342
|
+
/**
|
|
343
|
+
* Track a promise: show a loading toast, then auto-transition to
|
|
344
|
+
* success or error based on the promise outcome.
|
|
345
|
+
*
|
|
346
|
+
* @example
|
|
347
|
+
* toast.promise(fetch("/api/save"), {
|
|
348
|
+
* loading: { description: "Saving..." },
|
|
349
|
+
* success: { description: "Saved!" },
|
|
350
|
+
* error: { description: "Failed to save." }
|
|
351
|
+
* });
|
|
352
|
+
*/
|
|
353
|
+
promise(promise, options) {
|
|
354
|
+
const loadingToast = toast.loading(
|
|
355
|
+
options.loading.description ?? "",
|
|
356
|
+
{ ...options.loading }
|
|
357
|
+
);
|
|
358
|
+
return promise.then((result) => {
|
|
359
|
+
toast.update(loadingToast.id, {
|
|
360
|
+
type: "success",
|
|
361
|
+
...options.success,
|
|
362
|
+
duration: options.success.duration ?? 3e3,
|
|
363
|
+
dismissible: true
|
|
364
|
+
});
|
|
365
|
+
return result;
|
|
366
|
+
}).catch((error) => {
|
|
367
|
+
toast.update(loadingToast.id, {
|
|
368
|
+
type: "error",
|
|
369
|
+
...options.error,
|
|
370
|
+
duration: options.error.duration ?? 4e3,
|
|
371
|
+
dismissible: true
|
|
372
|
+
});
|
|
373
|
+
throw error;
|
|
374
|
+
});
|
|
375
|
+
},
|
|
376
|
+
/**
|
|
377
|
+
* Subscribe to toast state changes.
|
|
378
|
+
* Returns an unsubscribe function.
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* const unsub = toast.subscribe((toasts) => console.log(toasts));
|
|
382
|
+
* // later:
|
|
383
|
+
* unsub();
|
|
384
|
+
*/
|
|
385
|
+
subscribe(listener) {
|
|
386
|
+
return toastManager.changes.subscribe(listener);
|
|
387
|
+
},
|
|
388
|
+
/**
|
|
389
|
+
* Set global defaults for all toasts.
|
|
390
|
+
* Per-toast options always override these.
|
|
391
|
+
*
|
|
392
|
+
* @example
|
|
393
|
+
* toast.configure({ position: "bottom-right", theme: "minimal", duration: 3000 });
|
|
394
|
+
*/
|
|
395
|
+
configure
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// src/renderer/gestures.ts
|
|
399
|
+
var DISMISS_THRESHOLD = 120;
|
|
400
|
+
var MAX_ROTATION = 8;
|
|
401
|
+
var EXIT_DISTANCE = 450;
|
|
402
|
+
function attachSwipeGesture(element, toastId, position, onPause, onResume) {
|
|
403
|
+
const isVertical = position === "top-center" || position === "bottom-center";
|
|
404
|
+
const isBottom = position.startsWith("bottom");
|
|
405
|
+
let startX = 0;
|
|
406
|
+
let startY = 0;
|
|
407
|
+
let currentX = 0;
|
|
408
|
+
let currentY = 0;
|
|
409
|
+
let dragging = false;
|
|
410
|
+
const card = element.querySelector(".luma-toast-card");
|
|
411
|
+
card.style.touchAction = isVertical ? "pan-x" : "pan-y";
|
|
412
|
+
const handlePointerDown = (event) => {
|
|
413
|
+
const target = event.target;
|
|
414
|
+
if (target.closest(".luma-toast-close") || target.closest(".luma-toast-action")) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
dragging = true;
|
|
418
|
+
startX = event.clientX;
|
|
419
|
+
startY = event.clientY;
|
|
420
|
+
currentX = 0;
|
|
421
|
+
currentY = 0;
|
|
422
|
+
onPause();
|
|
423
|
+
element.style.transition = "none";
|
|
424
|
+
element.setPointerCapture(event.pointerId);
|
|
425
|
+
};
|
|
426
|
+
const handlePointerMove = (event) => {
|
|
427
|
+
if (!dragging) return;
|
|
428
|
+
currentX = event.clientX - startX;
|
|
429
|
+
currentY = event.clientY - startY;
|
|
430
|
+
if (isVertical) {
|
|
431
|
+
const clampedY = isBottom ? Math.max(0, currentY) : Math.min(0, currentY);
|
|
432
|
+
element.style.transform = `translate3d(0, ${clampedY}px, 0)`;
|
|
433
|
+
element.style.opacity = `${Math.max(0.35, 1 - Math.abs(clampedY) / 180)}`;
|
|
434
|
+
} else {
|
|
435
|
+
const rotate = Math.sign(currentX) * Math.min(Math.abs(currentX) / 20, MAX_ROTATION);
|
|
436
|
+
element.style.transform = `translate3d(${currentX}px, 0, 0) rotate(${rotate}deg)`;
|
|
437
|
+
element.style.opacity = `${Math.max(0.35, 1 - Math.abs(currentX) / 180)}`;
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
const handlePointerUp = (event) => {
|
|
441
|
+
if (!dragging) return;
|
|
442
|
+
dragging = false;
|
|
443
|
+
element.releasePointerCapture(event.pointerId);
|
|
444
|
+
element.style.transition = "transform 280ms cubic-bezier(.2,.8,.2,1), opacity 220ms ease";
|
|
445
|
+
const delta = isVertical ? currentY : currentX;
|
|
446
|
+
if (Math.abs(delta) >= DISMISS_THRESHOLD) {
|
|
447
|
+
if (isVertical) {
|
|
448
|
+
const exitY = delta > 0 ? EXIT_DISTANCE : -EXIT_DISTANCE;
|
|
449
|
+
element.style.transform = `translate3d(0, ${exitY}px, 0)`;
|
|
450
|
+
} else {
|
|
451
|
+
const exitX = delta > 0 ? EXIT_DISTANCE : -EXIT_DISTANCE;
|
|
452
|
+
const exitRotate = delta > 0 ? 12 : -12;
|
|
453
|
+
element.style.transform = `translate3d(${exitX}px, 0, 0) rotate(${exitRotate}deg)`;
|
|
454
|
+
}
|
|
455
|
+
element.style.opacity = "0";
|
|
456
|
+
setTimeout(() => {
|
|
457
|
+
toast.dismiss(toastId);
|
|
458
|
+
}, 280);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
element.style.transform = "";
|
|
462
|
+
element.style.opacity = "1";
|
|
463
|
+
onResume();
|
|
464
|
+
};
|
|
465
|
+
element.addEventListener("pointerdown", handlePointerDown);
|
|
466
|
+
element.addEventListener("pointermove", handlePointerMove);
|
|
467
|
+
element.addEventListener("pointerup", handlePointerUp);
|
|
468
|
+
element.addEventListener("pointercancel", handlePointerUp);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// src/utils/dom.ts
|
|
472
|
+
function createElement(tag, classNames = []) {
|
|
473
|
+
const element = document.createElement(tag);
|
|
474
|
+
if (classNames.length) {
|
|
475
|
+
element.classList.add(...classNames);
|
|
476
|
+
}
|
|
477
|
+
return element;
|
|
478
|
+
}
|
|
479
|
+
function applyStyles(element, style) {
|
|
480
|
+
if (!style || typeof style !== "object") return;
|
|
481
|
+
for (const [key, value] of Object.entries(style)) {
|
|
482
|
+
if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
|
|
483
|
+
if (typeof value !== "string") continue;
|
|
484
|
+
if (key.startsWith("--")) {
|
|
485
|
+
element.style.setProperty(key, value);
|
|
486
|
+
} else {
|
|
487
|
+
element.style[key] = value;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/renderer/container.ts
|
|
493
|
+
var CONTAINER_CLASS = "luma-toast-container";
|
|
494
|
+
var containers = /* @__PURE__ */ new Map();
|
|
495
|
+
function getContainer(position) {
|
|
496
|
+
const existing = containers.get(position);
|
|
497
|
+
if (existing) return existing;
|
|
498
|
+
const container = createElement("div", [
|
|
499
|
+
CONTAINER_CLASS,
|
|
500
|
+
`luma-${position}`
|
|
501
|
+
]);
|
|
502
|
+
container.dataset.position = position;
|
|
503
|
+
container.setAttribute("role", "region");
|
|
504
|
+
container.setAttribute("aria-live", "polite");
|
|
505
|
+
container.setAttribute("aria-atomic", "false");
|
|
506
|
+
container.setAttribute("aria-relevant", "additions removals");
|
|
507
|
+
document.body.appendChild(container);
|
|
508
|
+
containers.set(position, container);
|
|
509
|
+
return container;
|
|
510
|
+
}
|
|
511
|
+
function removeContainer(position) {
|
|
512
|
+
const container = containers.get(position);
|
|
513
|
+
if (!container) return;
|
|
514
|
+
container.remove();
|
|
515
|
+
containers.delete(position);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// src/icons/success.ts
|
|
519
|
+
var successIcon = `
|
|
520
|
+
<svg viewBox="0 0 24 24" width="20" height="20" fill="none">
|
|
521
|
+
<circle cx="12" cy="12" r="10" fill="#22C55E"/>
|
|
522
|
+
<path
|
|
523
|
+
d="M7.5 12.5L10.5 15.5L16.5 9.5"
|
|
524
|
+
stroke="white"
|
|
525
|
+
stroke-width="2"
|
|
526
|
+
stroke-linecap="round"
|
|
527
|
+
stroke-linejoin="round"
|
|
528
|
+
/>
|
|
529
|
+
</svg>
|
|
530
|
+
`;
|
|
531
|
+
|
|
532
|
+
// src/icons/error.ts
|
|
533
|
+
var errorIcon = `
|
|
534
|
+
<svg viewBox="0 0 24 24" width="20" height="20" fill="none">
|
|
535
|
+
<circle cx="12" cy="12" r="10" fill="#EF4444"/>
|
|
536
|
+
<path
|
|
537
|
+
d="M9 9L15 15M15 9L9 15"
|
|
538
|
+
stroke="white"
|
|
539
|
+
stroke-width="2"
|
|
540
|
+
stroke-linecap="round"
|
|
541
|
+
/>
|
|
542
|
+
</svg>
|
|
543
|
+
`;
|
|
544
|
+
|
|
545
|
+
// src/icons/warning.ts
|
|
546
|
+
var warningIcon = `
|
|
547
|
+
<svg viewBox="0 0 24 24" width="20" height="20" fill="none">
|
|
548
|
+
<path
|
|
549
|
+
d="M12 3L22 20H2L12 3Z"
|
|
550
|
+
fill="#F59E0B"
|
|
551
|
+
/>
|
|
552
|
+
<path
|
|
553
|
+
d="M12 9V13"
|
|
554
|
+
stroke="white"
|
|
555
|
+
stroke-width="2"
|
|
556
|
+
stroke-linecap="round"
|
|
557
|
+
/>
|
|
558
|
+
<circle cx="12" cy="17" r="1" fill="white"/>
|
|
559
|
+
</svg>
|
|
560
|
+
`;
|
|
561
|
+
|
|
562
|
+
// src/icons/info.ts
|
|
563
|
+
var infoIcon = `
|
|
564
|
+
<svg viewBox="0 0 24 24" width="20" height="20" fill="none">
|
|
565
|
+
<circle cx="12" cy="12" r="10" fill="#3B82F6"/>
|
|
566
|
+
<path
|
|
567
|
+
d="M12 11V16"
|
|
568
|
+
stroke="white"
|
|
569
|
+
stroke-width="2"
|
|
570
|
+
stroke-linecap="round"
|
|
571
|
+
/>
|
|
572
|
+
<circle cx="12" cy="8" r="1.2" fill="white"/>
|
|
573
|
+
</svg>
|
|
574
|
+
`;
|
|
575
|
+
|
|
576
|
+
// src/icons/loading.ts
|
|
577
|
+
var loadingIcon = `
|
|
578
|
+
<svg class="luma-loading-icon"
|
|
579
|
+
viewBox="0 0 24 24"
|
|
580
|
+
width="20"
|
|
581
|
+
height="20"
|
|
582
|
+
fill="none">
|
|
583
|
+
|
|
584
|
+
<circle
|
|
585
|
+
cx="12"
|
|
586
|
+
cy="12"
|
|
587
|
+
r="9"
|
|
588
|
+
stroke="#64748B"
|
|
589
|
+
stroke-width="2"
|
|
590
|
+
opacity=".25"
|
|
591
|
+
/>
|
|
592
|
+
|
|
593
|
+
<path
|
|
594
|
+
d="M12 3
|
|
595
|
+
A9 9 0 0 1 21 12"
|
|
596
|
+
stroke="#60A5FA"
|
|
597
|
+
stroke-width="2"
|
|
598
|
+
stroke-linecap="round"
|
|
599
|
+
/>
|
|
600
|
+
</svg>
|
|
601
|
+
`;
|
|
602
|
+
|
|
603
|
+
// src/components/toast.ts
|
|
604
|
+
function renderToast(toastItem) {
|
|
605
|
+
const classes = [
|
|
606
|
+
"luma-toast",
|
|
607
|
+
`luma-${toastItem.type}`,
|
|
608
|
+
`luma-theme-${toastItem.theme}`
|
|
609
|
+
];
|
|
610
|
+
if (toastItem.className) {
|
|
611
|
+
classes.push(...toastItem.className.trim().split(/\s+/));
|
|
612
|
+
}
|
|
613
|
+
const wrapper = createElement("div", classes);
|
|
614
|
+
wrapper.dataset.toastId = toastItem.id;
|
|
615
|
+
wrapper.dataset.enter = toastItem.animationEnter;
|
|
616
|
+
wrapper.dataset.exit = toastItem.animationExit;
|
|
617
|
+
wrapper.setAttribute("role", toastItem.type === "error" ? "alert" : "status");
|
|
618
|
+
wrapper.setAttribute("aria-live", toastItem.type === "error" ? "assertive" : "polite");
|
|
619
|
+
const card = createElement("div", ["luma-toast-card"]);
|
|
620
|
+
applyStyles(card, toastItem.style);
|
|
621
|
+
if (toastItem.closeOnClick) {
|
|
622
|
+
card.style.cursor = "pointer";
|
|
623
|
+
card.addEventListener("click", (e) => {
|
|
624
|
+
const target = e.target;
|
|
625
|
+
if (target.closest(".luma-toast-close") || target.closest(".luma-toast-action")) return;
|
|
626
|
+
toast.dismiss(toastItem.id);
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
if (toastItem.showIcon) {
|
|
630
|
+
const icon = createElement("div", ["luma-toast-icon"]);
|
|
631
|
+
icon.innerHTML = getIcon(toastItem.type);
|
|
632
|
+
card.appendChild(icon);
|
|
633
|
+
}
|
|
634
|
+
const content = createElement("div", ["luma-toast-content"]);
|
|
635
|
+
if (toastItem.title) {
|
|
636
|
+
const title = createElement("div", ["luma-toast-title"]);
|
|
637
|
+
title.textContent = toastItem.title;
|
|
638
|
+
content.appendChild(title);
|
|
639
|
+
}
|
|
640
|
+
if (toastItem.description) {
|
|
641
|
+
const desc = createElement("div", ["luma-toast-description"]);
|
|
642
|
+
desc.textContent = toastItem.description;
|
|
643
|
+
content.appendChild(desc);
|
|
644
|
+
}
|
|
645
|
+
if (toastItem.action) {
|
|
646
|
+
const action = buildActionButton(toastItem);
|
|
647
|
+
content.appendChild(action);
|
|
648
|
+
}
|
|
649
|
+
card.appendChild(content);
|
|
650
|
+
const close = createElement("button", ["luma-toast-close"]);
|
|
651
|
+
close.type = "button";
|
|
652
|
+
close.textContent = "\xD7";
|
|
653
|
+
close.setAttribute("aria-label", "Dismiss notification");
|
|
654
|
+
close.setAttribute("title", "Dismiss");
|
|
655
|
+
if (!toastItem.dismissible) {
|
|
656
|
+
close.style.display = "none";
|
|
657
|
+
}
|
|
658
|
+
close.addEventListener("pointerdown", (e) => e.stopPropagation());
|
|
659
|
+
close.addEventListener("click", (e) => {
|
|
660
|
+
e.stopPropagation();
|
|
661
|
+
toast.dismiss(toastItem.id);
|
|
662
|
+
});
|
|
663
|
+
card.appendChild(close);
|
|
664
|
+
if (Number.isFinite(toastItem.duration)) {
|
|
665
|
+
const progress = buildProgressBar(toastItem);
|
|
666
|
+
if (toastItem.progressPosition === "top") {
|
|
667
|
+
card.insertBefore(progress, card.firstChild);
|
|
668
|
+
} else {
|
|
669
|
+
card.appendChild(progress);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
wrapper.appendChild(card);
|
|
673
|
+
return wrapper;
|
|
674
|
+
}
|
|
675
|
+
function buildActionButton(toastItem) {
|
|
676
|
+
const variant = toastItem.action?.variant ?? "solid";
|
|
677
|
+
const action = createElement("button", [
|
|
678
|
+
"luma-toast-action",
|
|
679
|
+
`luma-action-${variant}`
|
|
680
|
+
]);
|
|
681
|
+
action.type = "button";
|
|
682
|
+
action.textContent = toastItem.action.label;
|
|
683
|
+
action.setAttribute("aria-label", toastItem.action.label);
|
|
684
|
+
action.addEventListener("pointerdown", (e) => e.stopPropagation());
|
|
685
|
+
action.addEventListener("click", (e) => {
|
|
686
|
+
e.stopPropagation();
|
|
687
|
+
toastItem.action?.onClick();
|
|
688
|
+
toast.dismiss(toastItem.id);
|
|
689
|
+
});
|
|
690
|
+
return action;
|
|
691
|
+
}
|
|
692
|
+
function buildProgressBar(toastItem) {
|
|
693
|
+
const progress = createElement("div", ["luma-progress"]);
|
|
694
|
+
const elapsed = Date.now() - toastItem.createdAt;
|
|
695
|
+
progress.style.animationDuration = `${toastItem.duration}ms`;
|
|
696
|
+
progress.style.animationDelay = `-${elapsed}ms`;
|
|
697
|
+
if (toastItem.progressPosition === "top") {
|
|
698
|
+
progress.classList.add("luma-progress-top");
|
|
699
|
+
}
|
|
700
|
+
return progress;
|
|
701
|
+
}
|
|
702
|
+
function getIcon(type) {
|
|
703
|
+
switch (type) {
|
|
704
|
+
case "success":
|
|
705
|
+
return successIcon;
|
|
706
|
+
case "error":
|
|
707
|
+
return errorIcon;
|
|
708
|
+
case "warning":
|
|
709
|
+
return warningIcon;
|
|
710
|
+
case "loading":
|
|
711
|
+
return loadingIcon;
|
|
712
|
+
case "info":
|
|
713
|
+
default:
|
|
714
|
+
return infoIcon;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// src/renderer/animations.ts
|
|
719
|
+
var previousPositions = /* @__PURE__ */ new Map();
|
|
720
|
+
var prefersReducedMotion = () => window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
721
|
+
function recordPositions(elements) {
|
|
722
|
+
previousPositions.clear();
|
|
723
|
+
elements.forEach((element, id) => {
|
|
724
|
+
previousPositions.set(id, element.getBoundingClientRect());
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
function animateStack(elements) {
|
|
728
|
+
if (prefersReducedMotion()) return;
|
|
729
|
+
elements.forEach((element, id) => {
|
|
730
|
+
if (element.dataset.removing === "true") return;
|
|
731
|
+
const previous = previousPositions.get(id);
|
|
732
|
+
if (!previous) return;
|
|
733
|
+
const next = element.getBoundingClientRect();
|
|
734
|
+
const deltaY = previous.top - next.top;
|
|
735
|
+
if (deltaY === 0) return;
|
|
736
|
+
element.style.transition = "none";
|
|
737
|
+
element.style.transform = `translateY(${deltaY}px)`;
|
|
738
|
+
requestAnimationFrame(() => {
|
|
739
|
+
element.style.transition = `transform ${ANIMATION_STACK_MS}ms cubic-bezier(.2,.8,.2,1)`;
|
|
740
|
+
element.style.transform = "";
|
|
741
|
+
});
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
function updateDepth(elements) {
|
|
745
|
+
const list = [...elements.values()];
|
|
746
|
+
list.forEach((element, index) => {
|
|
747
|
+
element.style.zIndex = String(1e3 - index);
|
|
748
|
+
element.style.removeProperty("--luma-scale");
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// src/renderer/renderer.ts
|
|
753
|
+
var initialized = false;
|
|
754
|
+
var renderedToasts = /* @__PURE__ */ new Map();
|
|
755
|
+
var timers = /* @__PURE__ */ new Map();
|
|
756
|
+
function initializeRenderer() {
|
|
757
|
+
if (typeof window === "undefined") return;
|
|
758
|
+
if (initialized) return;
|
|
759
|
+
initialized = true;
|
|
760
|
+
toast.subscribe(syncToasts);
|
|
761
|
+
window.addEventListener("keydown", handleEscapeKey);
|
|
762
|
+
}
|
|
763
|
+
function handleEscapeKey(event) {
|
|
764
|
+
if (event.key !== "Escape") return;
|
|
765
|
+
toast.dismissLatest();
|
|
766
|
+
}
|
|
767
|
+
function syncToasts(toasts) {
|
|
768
|
+
recordPositions(renderedToasts);
|
|
769
|
+
const activeIds = new Set(toasts.map((t) => t.id));
|
|
770
|
+
for (const [id, element] of renderedToasts.entries()) {
|
|
771
|
+
if (!activeIds.has(id)) {
|
|
772
|
+
removeToast(id, element);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
776
|
+
toasts.forEach((toastItem) => {
|
|
777
|
+
const list = grouped.get(toastItem.position) ?? [];
|
|
778
|
+
list.push(toastItem);
|
|
779
|
+
grouped.set(toastItem.position, list);
|
|
780
|
+
});
|
|
781
|
+
grouped.forEach((positionToasts, position) => {
|
|
782
|
+
const container = getContainer(position);
|
|
783
|
+
positionToasts.forEach((toastItem) => {
|
|
784
|
+
const existing = renderedToasts.get(toastItem.id);
|
|
785
|
+
if (existing) {
|
|
786
|
+
patchToast(existing, toastItem);
|
|
787
|
+
if (Number.isFinite(toastItem.duration) && !timers.has(toastItem.id)) {
|
|
788
|
+
startTimer(toastItem, existing);
|
|
789
|
+
}
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
const element = renderToast(toastItem);
|
|
793
|
+
container.appendChild(element);
|
|
794
|
+
renderedToasts.set(toastItem.id, element);
|
|
795
|
+
startTimer(toastItem, element);
|
|
796
|
+
});
|
|
797
|
+
});
|
|
798
|
+
requestAnimationFrame(() => {
|
|
799
|
+
animateStack(renderedToasts);
|
|
800
|
+
updateDepth(renderedToasts);
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
function patchToast(element, toastItem) {
|
|
804
|
+
const baseClasses = [
|
|
805
|
+
"luma-toast",
|
|
806
|
+
`luma-${toastItem.type}`,
|
|
807
|
+
`luma-theme-${toastItem.theme}`
|
|
808
|
+
];
|
|
809
|
+
if (toastItem.className) {
|
|
810
|
+
baseClasses.push(...toastItem.className.trim().split(/\s+/));
|
|
811
|
+
}
|
|
812
|
+
element.className = baseClasses.join(" ");
|
|
813
|
+
element.dataset.enter = toastItem.animationEnter;
|
|
814
|
+
element.dataset.exit = toastItem.animationExit;
|
|
815
|
+
const card = element.querySelector(".luma-toast-card");
|
|
816
|
+
if (!card) return;
|
|
817
|
+
applyStyles(card, toastItem.style);
|
|
818
|
+
const iconSlot = card.querySelector(".luma-toast-icon");
|
|
819
|
+
if (toastItem.showIcon) {
|
|
820
|
+
if (iconSlot) {
|
|
821
|
+
iconSlot.innerHTML = resolveIcon(toastItem.type);
|
|
822
|
+
}
|
|
823
|
+
} else {
|
|
824
|
+
iconSlot?.remove();
|
|
825
|
+
}
|
|
826
|
+
const title = card.querySelector(".luma-toast-title");
|
|
827
|
+
if (toastItem.title) {
|
|
828
|
+
if (title) {
|
|
829
|
+
title.textContent = toastItem.title;
|
|
830
|
+
} else {
|
|
831
|
+
const node = document.createElement("div");
|
|
832
|
+
node.className = "luma-toast-title";
|
|
833
|
+
node.textContent = toastItem.title;
|
|
834
|
+
card.querySelector(".luma-toast-content")?.prepend(node);
|
|
835
|
+
}
|
|
836
|
+
} else {
|
|
837
|
+
title?.remove();
|
|
838
|
+
}
|
|
839
|
+
const description = card.querySelector(".luma-toast-description");
|
|
840
|
+
if (toastItem.description) {
|
|
841
|
+
if (description) {
|
|
842
|
+
description.textContent = toastItem.description;
|
|
843
|
+
} else {
|
|
844
|
+
const node = document.createElement("div");
|
|
845
|
+
node.className = "luma-toast-description";
|
|
846
|
+
node.textContent = toastItem.description;
|
|
847
|
+
card.querySelector(".luma-toast-content")?.appendChild(node);
|
|
848
|
+
}
|
|
849
|
+
} else {
|
|
850
|
+
description?.remove();
|
|
851
|
+
}
|
|
852
|
+
const close = card.querySelector(".luma-toast-close");
|
|
853
|
+
if (close) {
|
|
854
|
+
close.style.display = toastItem.dismissible ? "" : "none";
|
|
855
|
+
}
|
|
856
|
+
const existingProgress = card.querySelector(".luma-progress");
|
|
857
|
+
if (Number.isFinite(toastItem.duration)) {
|
|
858
|
+
if (!existingProgress) {
|
|
859
|
+
const progress = document.createElement("div");
|
|
860
|
+
progress.className = "luma-progress";
|
|
861
|
+
progress.style.animationDuration = `${toastItem.duration}ms`;
|
|
862
|
+
if (toastItem.progressPosition === "top") {
|
|
863
|
+
progress.classList.add("luma-progress-top");
|
|
864
|
+
card.insertBefore(progress, card.firstChild);
|
|
865
|
+
} else {
|
|
866
|
+
card.appendChild(progress);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
} else {
|
|
870
|
+
existingProgress?.remove();
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
function resolveIcon(type) {
|
|
874
|
+
switch (type) {
|
|
875
|
+
case "success":
|
|
876
|
+
return successIcon;
|
|
877
|
+
case "error":
|
|
878
|
+
return errorIcon;
|
|
879
|
+
case "warning":
|
|
880
|
+
return warningIcon;
|
|
881
|
+
case "loading":
|
|
882
|
+
return loadingIcon;
|
|
883
|
+
case "info":
|
|
884
|
+
default:
|
|
885
|
+
return infoIcon;
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
function startTimer(toastItem, element) {
|
|
889
|
+
const { duration } = toastItem;
|
|
890
|
+
if (!Number.isFinite(duration)) {
|
|
891
|
+
timers.delete(toastItem.id);
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
const timer = {
|
|
895
|
+
timeoutId: 0,
|
|
896
|
+
startedAt: Date.now(),
|
|
897
|
+
remaining: duration
|
|
898
|
+
};
|
|
899
|
+
const schedule = () => {
|
|
900
|
+
timer.startedAt = Date.now();
|
|
901
|
+
timer.timeoutId = window.setTimeout(() => {
|
|
902
|
+
toast.dismiss(toastItem.id);
|
|
903
|
+
}, timer.remaining);
|
|
904
|
+
};
|
|
905
|
+
schedule();
|
|
906
|
+
timers.set(toastItem.id, timer);
|
|
907
|
+
attachHoverEvents(element, toastItem.id);
|
|
908
|
+
attachSwipeGesture(
|
|
909
|
+
element,
|
|
910
|
+
toastItem.id,
|
|
911
|
+
toastItem.position,
|
|
912
|
+
() => pauseTimer(toastItem.id, element),
|
|
913
|
+
() => resumeTimer(toastItem.id, element)
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
function pauseTimer(id, element) {
|
|
917
|
+
const timer = timers.get(id);
|
|
918
|
+
if (!timer) return;
|
|
919
|
+
clearTimeout(timer.timeoutId);
|
|
920
|
+
timer.remaining -= Date.now() - timer.startedAt;
|
|
921
|
+
const progress = element.querySelector(".luma-progress");
|
|
922
|
+
if (progress) progress.style.animationPlayState = "paused";
|
|
923
|
+
}
|
|
924
|
+
function resumeTimer(id, element) {
|
|
925
|
+
const timer = timers.get(id);
|
|
926
|
+
if (!timer) return;
|
|
927
|
+
timer.startedAt = Date.now();
|
|
928
|
+
timer.timeoutId = window.setTimeout(() => {
|
|
929
|
+
toast.dismiss(id);
|
|
930
|
+
}, timer.remaining);
|
|
931
|
+
const progress = element.querySelector(".luma-progress");
|
|
932
|
+
if (progress) progress.style.animationPlayState = "running";
|
|
933
|
+
}
|
|
934
|
+
function attachHoverEvents(element, toastId) {
|
|
935
|
+
element.addEventListener("mouseenter", () => pauseTimer(toastId, element));
|
|
936
|
+
element.addEventListener("mouseleave", () => resumeTimer(toastId, element));
|
|
937
|
+
}
|
|
938
|
+
function removeToast(id, element) {
|
|
939
|
+
const timer = timers.get(id);
|
|
940
|
+
if (timer) {
|
|
941
|
+
clearTimeout(timer.timeoutId);
|
|
942
|
+
timers.delete(id);
|
|
943
|
+
}
|
|
944
|
+
if (element.dataset.removing === "true") return;
|
|
945
|
+
element.dataset.removing = "true";
|
|
946
|
+
requestAnimationFrame(() => {
|
|
947
|
+
element.classList.add("luma-toast-exit");
|
|
948
|
+
});
|
|
949
|
+
const cleanup = () => {
|
|
950
|
+
const container = element.parentElement;
|
|
951
|
+
element.remove();
|
|
952
|
+
renderedToasts.delete(id);
|
|
953
|
+
if (container && container.childElementCount === 0) {
|
|
954
|
+
const position = container.dataset.position;
|
|
955
|
+
removeContainer(position);
|
|
956
|
+
}
|
|
957
|
+
};
|
|
958
|
+
const handleTransitionEnd = (event) => {
|
|
959
|
+
if (event.target !== element) return;
|
|
960
|
+
element.removeEventListener("transitionend", handleTransitionEnd);
|
|
961
|
+
cleanup();
|
|
962
|
+
};
|
|
963
|
+
element.addEventListener("transitionend", handleTransitionEnd);
|
|
964
|
+
window.setTimeout(() => {
|
|
965
|
+
if (element.isConnected) {
|
|
966
|
+
element.removeEventListener("transitionend", handleTransitionEnd);
|
|
967
|
+
cleanup();
|
|
968
|
+
}
|
|
969
|
+
}, ANIMATION_EXIT_MS + 50);
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
exports.ANIMATION_ENTER_MS = ANIMATION_ENTER_MS;
|
|
973
|
+
exports.ANIMATION_EXIT_MS = ANIMATION_EXIT_MS;
|
|
974
|
+
exports.ANIMATION_STACK_MS = ANIMATION_STACK_MS;
|
|
975
|
+
exports.CLASS_ACTION = CLASS_ACTION;
|
|
976
|
+
exports.CLASS_CARD = CLASS_CARD;
|
|
977
|
+
exports.CLASS_CLOSE = CLASS_CLOSE;
|
|
978
|
+
exports.CLASS_CONTAINER = CLASS_CONTAINER;
|
|
979
|
+
exports.CLASS_CONTENT = CLASS_CONTENT;
|
|
980
|
+
exports.CLASS_DESCRIPTION = CLASS_DESCRIPTION;
|
|
981
|
+
exports.CLASS_EXIT = CLASS_EXIT;
|
|
982
|
+
exports.CLASS_ICON = CLASS_ICON;
|
|
983
|
+
exports.CLASS_PROGRESS = CLASS_PROGRESS;
|
|
984
|
+
exports.CLASS_TITLE = CLASS_TITLE;
|
|
985
|
+
exports.CLASS_TOAST = CLASS_TOAST;
|
|
986
|
+
exports.CSS_VARS = CSS_VARS;
|
|
987
|
+
exports.DEFAULT_ANIMATION_ENTER = DEFAULT_ANIMATION_ENTER;
|
|
988
|
+
exports.DEFAULT_ANIMATION_EXIT = DEFAULT_ANIMATION_EXIT;
|
|
989
|
+
exports.DEFAULT_ANIMATION_SPEED = DEFAULT_ANIMATION_SPEED;
|
|
990
|
+
exports.DEFAULT_CLOSE_ON_CLICK = DEFAULT_CLOSE_ON_CLICK;
|
|
991
|
+
exports.DEFAULT_DISMISSIBLE = DEFAULT_DISMISSIBLE;
|
|
992
|
+
exports.DEFAULT_DURATION = DEFAULT_DURATION;
|
|
993
|
+
exports.DEFAULT_POSITION = DEFAULT_POSITION;
|
|
994
|
+
exports.DEFAULT_PROGRESS_POS = DEFAULT_PROGRESS_POS;
|
|
995
|
+
exports.DEFAULT_SHOW_ICON = DEFAULT_SHOW_ICON;
|
|
996
|
+
exports.DEFAULT_THEME = DEFAULT_THEME;
|
|
997
|
+
exports.DURATION_DEFAULT = DURATION_DEFAULT;
|
|
998
|
+
exports.DURATION_INFINITE = DURATION_INFINITE;
|
|
999
|
+
exports.DURATION_LONG = DURATION_LONG;
|
|
1000
|
+
exports.DURATION_SHORT = DURATION_SHORT;
|
|
1001
|
+
exports.MAX_VISIBLE_TOASTS = MAX_VISIBLE_TOASTS;
|
|
1002
|
+
exports.STACK_GAP = STACK_GAP;
|
|
1003
|
+
exports.TOAST_GAP_PX = TOAST_GAP_PX;
|
|
1004
|
+
exports.TOAST_WIDTH_PX = TOAST_WIDTH_PX;
|
|
1005
|
+
exports.Z_INDEX_BASE = Z_INDEX_BASE;
|
|
1006
|
+
exports.configure = configure;
|
|
1007
|
+
exports.initializeRenderer = initializeRenderer;
|
|
1008
|
+
exports.toast = toast;
|
|
1009
|
+
exports.toastManager = toastManager;
|
|
1010
|
+
//# sourceMappingURL=index.cjs.map
|
|
1011
|
+
//# sourceMappingURL=index.cjs.map
|