sonner-wc 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,1962 @@
1
+ // src/constants.ts
2
+ var VISIBLE_TOASTS_AMOUNT = 3;
3
+ var TOAST_LIFETIME = 4000;
4
+ var TOAST_WIDTH = 356;
5
+ var GAP = 14;
6
+ var SWIPE_THRESHOLD = 45;
7
+ var SWIPE_VELOCITY_THRESHOLD = 0.11;
8
+ var TIME_BEFORE_UNMOUNT = 200;
9
+ var DEFAULT_HOTKEY = ["altKey", "KeyT"];
10
+
11
+ // src/icons.ts
12
+ var SUCCESS_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" height="20" width="20"><path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd"/></svg>';
13
+ var WARNING_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" height="20" width="20"><path fill-rule="evenodd" d="M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z" clip-rule="evenodd"/></svg>';
14
+ var INFO_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" height="20" width="20"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd"/></svg>';
15
+ var ERROR_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" height="20" width="20"><path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-5a.75.75 0 01.75.75v4.5a.75.75 0 01-1.5 0v-4.5A.75.75 0 0110 5zm0 10a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd"/></svg>';
16
+ var CLOSE_ICON = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
17
+ var SPINNER_BARS = Array.from({ length: 12 }, () => '<div class="sonner-loading-bar"></div>').join("");
18
+ var LOADING_SPINNER = '<div class="sonner-loading-wrapper" data-visible="true"><div class="sonner-spinner">' + SPINNER_BARS + "</div></div>";
19
+ function getTypeIcon(type) {
20
+ switch (type) {
21
+ case "success":
22
+ return SUCCESS_ICON;
23
+ case "info":
24
+ return INFO_ICON;
25
+ case "warning":
26
+ return WARNING_ICON;
27
+ case "error":
28
+ return ERROR_ICON;
29
+ case "loading":
30
+ return null;
31
+ default:
32
+ return null;
33
+ }
34
+ }
35
+
36
+ // src/registry.ts
37
+ var toastsById = new Map;
38
+ var toasters = new Set;
39
+ var counter = 1;
40
+ function nextToastId() {
41
+ return counter++;
42
+ }
43
+ function registerToast(el) {
44
+ toastsById.set(el.toastId, el);
45
+ }
46
+ function unregisterToast(el) {
47
+ const current = toastsById.get(el.toastId);
48
+ if (current === el)
49
+ toastsById.delete(el.toastId);
50
+ }
51
+ function getToast(id) {
52
+ return toastsById.get(id);
53
+ }
54
+ function registerToaster(el) {
55
+ toasters.add(el);
56
+ }
57
+ function unregisterToaster(el) {
58
+ toasters.delete(el);
59
+ }
60
+ function defaultToaster() {
61
+ let last;
62
+ for (const t of toasters)
63
+ last = t;
64
+ return last;
65
+ }
66
+ function dismissAllToasts() {
67
+ for (const t of toasters)
68
+ t.dismissAll();
69
+ }
70
+
71
+ // src/styles/toaster.css
72
+ var toaster_default = `:host {
73
+ position: fixed;
74
+ width: var(--width);
75
+ font-family:
76
+ ui-sans-serif,
77
+ system-ui,
78
+ -apple-system,
79
+ BlinkMacSystemFont,
80
+ Segoe UI,
81
+ Roboto,
82
+ Helvetica Neue,
83
+ Arial,
84
+ Noto Sans,
85
+ sans-serif,
86
+ Apple Color Emoji,
87
+ Segoe UI Emoji,
88
+ Segoe UI Symbol,
89
+ Noto Color Emoji;
90
+ --gray1: hsl(0, 0%, 99%);
91
+ --gray2: hsl(0, 0%, 97.3%);
92
+ --gray3: hsl(0, 0%, 95.1%);
93
+ --gray4: hsl(0, 0%, 93%);
94
+ --gray5: hsl(0, 0%, 90.9%);
95
+ --gray6: hsl(0, 0%, 88.7%);
96
+ --gray7: hsl(0, 0%, 85.8%);
97
+ --gray8: hsl(0, 0%, 78%);
98
+ --gray9: hsl(0, 0%, 56.1%);
99
+ --gray10: hsl(0, 0%, 52.3%);
100
+ --gray11: hsl(0, 0%, 43.5%);
101
+ --gray12: hsl(0, 0%, 9%);
102
+ --border-radius: 8px;
103
+ --width: 356px;
104
+ --gap: 14px;
105
+ --offset-top: 24px;
106
+ --offset-right: 24px;
107
+ --offset-bottom: 24px;
108
+ --offset-left: 24px;
109
+ --mobile-offset-top: 16px;
110
+ --mobile-offset-right: 16px;
111
+ --mobile-offset-bottom: 16px;
112
+ --mobile-offset-left: 16px;
113
+ --toast-icon-margin-start: -3px;
114
+ --toast-icon-margin-end: 4px;
115
+ --toast-svg-margin-start: -1px;
116
+ --toast-svg-margin-end: 0px;
117
+ --toast-button-margin-start: auto;
118
+ --toast-button-margin-end: 0;
119
+ --toast-close-button-start: 0;
120
+ --toast-close-button-end: unset;
121
+ --toast-close-button-transform: translate(-35%, -35%);
122
+ box-sizing: border-box;
123
+ padding: 0;
124
+ margin: 0;
125
+ outline: none;
126
+ z-index: 999999999;
127
+ transition: transform 400ms ease;
128
+ display: block;
129
+ }
130
+
131
+ [data-frame] {
132
+ display: block;
133
+ width: 100%;
134
+ height: 100%;
135
+ box-sizing: border-box;
136
+ font-family: inherit;
137
+ }
138
+
139
+ :host([dir='rtl']) {
140
+ --toast-icon-margin-start: 4px;
141
+ --toast-icon-margin-end: -3px;
142
+ --toast-svg-margin-start: 0px;
143
+ --toast-svg-margin-end: -1px;
144
+ --toast-button-margin-start: 0;
145
+ --toast-button-margin-end: auto;
146
+ --toast-close-button-start: unset;
147
+ --toast-close-button-end: 0;
148
+ --toast-close-button-transform: translate(35%, -35%);
149
+ }
150
+
151
+ :host([data-x-position='right']) {
152
+ right: var(--offset-right);
153
+ }
154
+ :host([data-x-position='left']) {
155
+ left: var(--offset-left);
156
+ }
157
+ :host([data-x-position='center']) {
158
+ left: 50%;
159
+ transform: translateX(-50%);
160
+ }
161
+ :host([data-y-position='top']) {
162
+ top: var(--offset-top);
163
+ }
164
+ :host([data-y-position='bottom']) {
165
+ bottom: var(--offset-bottom);
166
+ }
167
+
168
+ @media (hover: none) and (pointer: coarse) {
169
+ :host([data-lifted='true']) {
170
+ transform: none;
171
+ }
172
+ }
173
+
174
+ /* Theme palette via light-dark(). The \`theme\` attribute on <sonner-toaster>
175
+ * (light / dark, or resolved from \`system\`) drives \`color-scheme\` on the host,
176
+ * which determines which side of each light-dark() pair wins. */
177
+ :host([data-sonner-theme='light']) { color-scheme: light; }
178
+ :host([data-sonner-theme='dark']) { color-scheme: dark; }
179
+
180
+ :host {
181
+ --normal-bg: light-dark(#fff, #000);
182
+ --normal-bg-hover: light-dark(var(--gray2), hsl(0, 0%, 12%));
183
+ --normal-border: light-dark(var(--gray4), hsl(0, 0%, 20%));
184
+ --normal-border-hover: light-dark(var(--gray5), hsl(0, 0%, 25%));
185
+ --normal-text: light-dark(var(--gray12), var(--gray1));
186
+ --invert-bg: light-dark(#000, #fff);
187
+ --invert-border: light-dark(hsl(0, 0%, 20%), var(--gray3));
188
+ --invert-text: light-dark(var(--gray1), var(--gray12));
189
+ --description-color: light-dark(#3f3f3f, hsl(0, 0%, 91%));
190
+ --cancel-bg: light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.3));
191
+ --success-bg: light-dark(hsl(143, 85%, 96%), hsl(150, 100%, 6%));
192
+ --success-border: light-dark(hsl(145, 92%, 87%), hsl(147, 100%, 12%));
193
+ --success-text: light-dark(hsl(140, 100%, 27%), hsl(150, 86%, 65%));
194
+ --info-bg: light-dark(hsl(208, 100%, 97%), hsl(215, 100%, 6%));
195
+ --info-border: light-dark(hsl(221, 91%, 93%), hsl(223, 43%, 17%));
196
+ --info-text: light-dark(hsl(210, 92%, 45%), hsl(216, 87%, 65%));
197
+ --warning-bg: light-dark(hsl(49, 100%, 97%), hsl(64, 100%, 6%));
198
+ --warning-border: light-dark(hsl(49, 91%, 84%), hsl(60, 100%, 9%));
199
+ --warning-text: light-dark(hsl(31, 92%, 45%), hsl(46, 87%, 65%));
200
+ --error-bg: light-dark(hsl(359, 100%, 97%), hsl(358, 76%, 10%));
201
+ --error-border: light-dark(hsl(359, 100%, 94%), hsl(357, 89%, 16%));
202
+ --error-text: light-dark(hsl(360, 100%, 45%), hsl(358, 100%, 81%));
203
+ }
204
+
205
+ @media (max-width: 600px) {
206
+ /* width is intentionally \`auto\` so that the toaster respects BOTH offsets
207
+ * and fits between them. Sonner's reference CSS uses width: 100% here, but
208
+ * that's over-constrained with both left and right set — the right offset
209
+ * gets ignored and the element extends past the viewport's right edge by
210
+ * --mobile-offset-right (visible unless body has overflow-x: hidden). */
211
+ :host {
212
+ position: fixed;
213
+ right: var(--mobile-offset-right);
214
+ left: var(--mobile-offset-left);
215
+ width: auto;
216
+ }
217
+ :host([dir='rtl']) {
218
+ left: calc(var(--mobile-offset-left) * -1);
219
+ }
220
+ :host([data-x-position='left']) {
221
+ left: var(--mobile-offset-left);
222
+ }
223
+ :host([data-x-position='right']) {
224
+ right: var(--mobile-offset-right);
225
+ }
226
+ :host([data-y-position='bottom']) {
227
+ bottom: var(--mobile-offset-bottom);
228
+ }
229
+ :host([data-y-position='top']) {
230
+ top: var(--mobile-offset-top);
231
+ }
232
+ :host([data-x-position='center']) {
233
+ left: var(--mobile-offset-left);
234
+ right: var(--mobile-offset-right);
235
+ transform: none;
236
+ }
237
+ }
238
+ `;
239
+
240
+ // src/styles/toast.css
241
+ var toast_default = `:host {
242
+ --y: translateY(100%);
243
+ --lift-amount: calc(var(--lift) * var(--gap, 14px));
244
+ z-index: var(--z-index);
245
+ position: absolute;
246
+ opacity: 0;
247
+ transform: var(--y);
248
+ touch-action: none;
249
+ transition:
250
+ transform 400ms,
251
+ opacity 400ms,
252
+ height 400ms,
253
+ box-shadow 200ms;
254
+ /* Enables the height transition to interpolate to/from auto (intrinsic size).
255
+ * Supported in Chromium ≥129; in other engines the transition gracefully falls
256
+ * back to snapping, same as the React Sonner reference. */
257
+ interpolate-size: allow-keywords;
258
+ box-sizing: border-box;
259
+ width: var(--width);
260
+ }
261
+
262
+ [data-frame] {
263
+ display: flex;
264
+ align-items: center;
265
+ gap: 6px;
266
+ font-family: inherit;
267
+ font-size: 13px;
268
+ font-weight: 400;
269
+ font-style: normal;
270
+ line-height: normal;
271
+ letter-spacing: normal;
272
+ text-align: start;
273
+ text-transform: none;
274
+ color: var(--normal-text);
275
+ outline: none;
276
+ overflow-wrap: anywhere;
277
+ width: 100%;
278
+ height: 100%;
279
+ box-sizing: border-box;
280
+ }
281
+
282
+ :host([data-styled='true']) [data-frame] {
283
+ padding: 16px;
284
+ background: var(--normal-bg);
285
+ border: 1px solid var(--normal-border);
286
+ color: var(--normal-text);
287
+ border-radius: var(--border-radius);
288
+ box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1);
289
+ }
290
+
291
+ /* Unstyled (toast.custom): hide built-in chrome, let the slotted content fill the host. */
292
+ :host([data-styled='false']) [data-frame] {
293
+ display: block;
294
+ }
295
+ :host([data-styled='false']) [data-icon],
296
+ :host([data-styled='false']) [data-content],
297
+ :host([data-styled='false']) [data-close-button] {
298
+ display: none;
299
+ }
300
+
301
+ /* Hide the icon container when no icon has been slotted AND no built-in spinner is
302
+ * showing (default-type toasts have no built-in icon, so otherwise its fixed 16x16 +
303
+ * side margins reserve a phantom gap).
304
+ * The element toggles data-has-icon / data-has-description on slotchange. */
305
+ :host(:not([data-has-icon]):not([data-type='loading'])) [data-icon] {
306
+ display: none;
307
+ }
308
+ :host(:not([data-has-description])) [data-description] {
309
+ display: none;
310
+ }
311
+
312
+ /* Spinner lives in the shadow DOM so its CSS can match its descendants (slotted
313
+ * elements can't be styled past their host from a shadow stylesheet). It is hidden
314
+ * by default and only revealed when type='loading' AND no user icon was slotted. */
315
+ :host([data-type='loading']:not([data-has-icon])) .sonner-loading-wrapper {
316
+ display: block;
317
+ }
318
+ :host(:not([data-type='loading']):not([data-has-icon])) .sonner-loading-wrapper,
319
+ :host([data-has-icon]) .sonner-loading-wrapper {
320
+ display: none;
321
+ }
322
+
323
+ :host(:focus-visible) [data-frame] {
324
+ box-shadow:
325
+ 0px 4px 12px rgba(0, 0, 0, 0.1),
326
+ 0 0 0 2px rgba(0, 0, 0, 0.2);
327
+ }
328
+
329
+ :host([data-y-position='top']) {
330
+ top: 0;
331
+ --y: translateY(-100%);
332
+ --lift: 1;
333
+ --lift-amount: calc(1 * var(--gap, 14px));
334
+ }
335
+
336
+ :host([data-y-position='bottom']) {
337
+ bottom: 0;
338
+ --y: translateY(100%);
339
+ --lift: -1;
340
+ --lift-amount: calc(var(--lift) * var(--gap, 14px));
341
+ }
342
+
343
+ :host([data-x-position='right']) {
344
+ right: 0;
345
+ }
346
+ :host([data-x-position='left']) {
347
+ left: 0;
348
+ }
349
+
350
+ [data-content] {
351
+ display: flex;
352
+ flex-direction: column;
353
+ gap: 2px;
354
+ flex: 1;
355
+ min-width: 0;
356
+ }
357
+
358
+ [data-title],
359
+ ::slotted([slot='title']) {
360
+ font-weight: 500;
361
+ line-height: 1.5;
362
+ color: inherit;
363
+ }
364
+
365
+ [data-description] {
366
+ font-weight: 400;
367
+ line-height: 1.4;
368
+ color: var(--description-color, #3f3f3f);
369
+ }
370
+ :host([data-rich-colors='true']) [data-description] {
371
+ color: inherit;
372
+ }
373
+ ::slotted([slot='description']) {
374
+ color: inherit;
375
+ }
376
+
377
+ [data-icon] {
378
+ display: flex;
379
+ height: 16px;
380
+ width: 16px;
381
+ position: relative;
382
+ justify-content: flex-start;
383
+ align-items: center;
384
+ flex-shrink: 0;
385
+ margin-left: var(--toast-icon-margin-start);
386
+ margin-right: var(--toast-icon-margin-end);
387
+ }
388
+ [data-icon] > * {
389
+ flex-shrink: 0;
390
+ }
391
+ [data-icon] svg {
392
+ margin-left: var(--toast-svg-margin-start);
393
+ margin-right: var(--toast-svg-margin-end);
394
+ }
395
+ :host([data-promise='true']) [data-icon] > svg {
396
+ opacity: 0;
397
+ transform: scale(0.8);
398
+ transform-origin: center;
399
+ animation: sonner-fade-in 300ms ease forwards;
400
+ }
401
+
402
+ [data-button],
403
+ ::slotted(button[slot='action']),
404
+ ::slotted(button[slot='cancel']) {
405
+ border-radius: 4px;
406
+ padding-left: 8px;
407
+ padding-right: 8px;
408
+ height: 24px;
409
+ font-size: 12px;
410
+ background: var(--normal-text);
411
+ color: contrast-color(var(--normal-text));
412
+ margin-left: var(--toast-button-margin-start);
413
+ margin-right: var(--toast-button-margin-end);
414
+ border: none;
415
+ font-weight: 500;
416
+ cursor: pointer;
417
+ outline: none;
418
+ display: flex;
419
+ align-items: center;
420
+ flex-shrink: 0;
421
+ transition:
422
+ opacity 400ms,
423
+ box-shadow 200ms;
424
+ font-family: inherit;
425
+ }
426
+ [data-button]:focus-visible {
427
+ box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.4);
428
+ }
429
+ [data-cancel],
430
+ ::slotted(button[slot='cancel']) {
431
+ color: var(--normal-text);
432
+ background: var(--cancel-bg, rgba(0, 0, 0, 0.08));
433
+ }
434
+
435
+ [data-close-button] {
436
+ position: absolute;
437
+ left: var(--toast-close-button-start);
438
+ right: var(--toast-close-button-end);
439
+ top: 0;
440
+ height: 20px;
441
+ width: 20px;
442
+ display: flex;
443
+ justify-content: center;
444
+ align-items: center;
445
+ padding: 0;
446
+ color: var(--normal-text);
447
+ background: var(--normal-bg);
448
+ border: 1px solid var(--normal-border);
449
+ transform: var(--toast-close-button-transform);
450
+ border-radius: 50%;
451
+ cursor: pointer;
452
+ z-index: 1;
453
+ transition:
454
+ opacity 100ms,
455
+ background 200ms,
456
+ border-color 200ms;
457
+ font: inherit;
458
+ }
459
+ [data-close-button][hidden] {
460
+ display: none;
461
+ }
462
+ [data-close-button]:focus-visible {
463
+ box-shadow:
464
+ 0px 4px 12px rgba(0, 0, 0, 0.1),
465
+ 0 0 0 2px rgba(0, 0, 0, 0.2);
466
+ }
467
+ :host(:hover) [data-close-button]:hover {
468
+ background: var(--normal-bg-hover, var(--gray2));
469
+ border-color: var(--normal-border-hover, var(--gray5));
470
+ }
471
+
472
+ :host([data-swiping='true'])::before {
473
+ content: '';
474
+ position: absolute;
475
+ left: -100%;
476
+ right: -100%;
477
+ height: 100%;
478
+ z-index: -1;
479
+ }
480
+ :host([data-y-position='top'][data-swiping='true'])::before {
481
+ bottom: 50%;
482
+ transform: scaleY(3) translateY(50%);
483
+ }
484
+ :host([data-y-position='bottom'][data-swiping='true'])::before {
485
+ top: 50%;
486
+ transform: scaleY(3) translateY(-50%);
487
+ }
488
+ :host([data-swiping='false'][data-removed='true'])::before {
489
+ content: '';
490
+ position: absolute;
491
+ inset: 0;
492
+ transform: scaleY(2);
493
+ }
494
+ :host([data-expanded='true'])::after {
495
+ content: '';
496
+ position: absolute;
497
+ left: 0;
498
+ height: calc(var(--gap, 14px) + 1px);
499
+ bottom: 100%;
500
+ width: 100%;
501
+ }
502
+
503
+ :host([data-mounted='true']) {
504
+ --y: translateY(0);
505
+ opacity: 1;
506
+ }
507
+
508
+ /* Heights, driven entirely by CSS. With interpolate-size:allow-keywords on :host,
509
+ * transitions between auto (front collapsed) and the pixel var()s animate smoothly. */
510
+ :host([data-mounted='true'][data-front='true'][data-expanded='false']) {
511
+ height: auto;
512
+ }
513
+
514
+ :host([data-expanded='false'][data-front='false']) {
515
+ --scale: var(--toasts-before) * 0.05 + 1;
516
+ --y: translateY(calc(var(--lift-amount) * var(--toasts-before))) scale(calc(-1 * var(--scale)));
517
+ height: var(--front-toast-height);
518
+ }
519
+
520
+ [data-frame] > * {
521
+ transition: opacity 400ms;
522
+ }
523
+ :host([data-expanded='false'][data-front='false'][data-styled='true']) [data-frame] > * {
524
+ opacity: 0;
525
+ }
526
+ :host([data-visible='false']) {
527
+ opacity: 0;
528
+ pointer-events: none;
529
+ }
530
+
531
+ :host([data-mounted='true'][data-expanded='true']) {
532
+ --y: translateY(calc(var(--lift) * var(--offset)));
533
+ height: var(--initial-height);
534
+ }
535
+
536
+ :host([data-removed='true'][data-front='true'][data-swipe-out='false']) {
537
+ --y: translateY(calc(var(--lift) * -100%));
538
+ opacity: 0;
539
+ }
540
+ :host([data-removed='true'][data-front='false'][data-swipe-out='false'][data-expanded='true']) {
541
+ --y: translateY(calc(var(--lift) * var(--offset) + var(--lift) * -100%));
542
+ opacity: 0;
543
+ }
544
+ :host([data-removed='true'][data-front='false'][data-swipe-out='false'][data-expanded='false']) {
545
+ --y: translateY(40%);
546
+ opacity: 0;
547
+ transition:
548
+ transform 500ms,
549
+ opacity 200ms;
550
+ }
551
+ :host([data-removed='true'][data-front='false'])::before {
552
+ height: calc(var(--initial-height) + 20%);
553
+ }
554
+
555
+ :host([data-swiping='true']) {
556
+ transform: var(--y) translateY(var(--swipe-amount-y, 0px)) translateX(var(--swipe-amount-x, 0px));
557
+ transition: none;
558
+ }
559
+ :host([data-swiped='true']) {
560
+ user-select: none;
561
+ -webkit-user-select: none;
562
+ }
563
+ :host([data-swipe-out='true'][data-y-position='bottom']),
564
+ :host([data-swipe-out='true'][data-y-position='top']) {
565
+ animation-duration: 200ms;
566
+ animation-timing-function: ease-out;
567
+ animation-fill-mode: forwards;
568
+ }
569
+ :host([data-swipe-out='true'][data-swipe-direction='left']) {
570
+ animation-name: swipe-out-left;
571
+ }
572
+ :host([data-swipe-out='true'][data-swipe-direction='right']) {
573
+ animation-name: swipe-out-right;
574
+ }
575
+ :host([data-swipe-out='true'][data-swipe-direction='up']) {
576
+ animation-name: swipe-out-up;
577
+ }
578
+ :host([data-swipe-out='true'][data-swipe-direction='down']) {
579
+ animation-name: swipe-out-down;
580
+ }
581
+
582
+ :host([data-invert='true']) {
583
+ --normal-bg: var(--invert-bg);
584
+ --normal-border: var(--invert-border);
585
+ --normal-text: var(--invert-text);
586
+ }
587
+
588
+ :host([data-rich-colors='true'][data-type='success']) [data-frame] {
589
+ background: var(--success-bg);
590
+ border-color: var(--success-border);
591
+ color: var(--success-text);
592
+ }
593
+ :host([data-rich-colors='true'][data-type='success']) [data-close-button] {
594
+ background: var(--success-bg);
595
+ border-color: var(--success-border);
596
+ color: var(--success-text);
597
+ }
598
+ :host([data-rich-colors='true'][data-type='info']) [data-frame] {
599
+ background: var(--info-bg);
600
+ border-color: var(--info-border);
601
+ color: var(--info-text);
602
+ }
603
+ :host([data-rich-colors='true'][data-type='info']) [data-close-button] {
604
+ background: var(--info-bg);
605
+ border-color: var(--info-border);
606
+ color: var(--info-text);
607
+ }
608
+ :host([data-rich-colors='true'][data-type='warning']) [data-frame] {
609
+ background: var(--warning-bg);
610
+ border-color: var(--warning-border);
611
+ color: var(--warning-text);
612
+ }
613
+ :host([data-rich-colors='true'][data-type='warning']) [data-close-button] {
614
+ background: var(--warning-bg);
615
+ border-color: var(--warning-border);
616
+ color: var(--warning-text);
617
+ }
618
+ :host([data-rich-colors='true'][data-type='error']) [data-frame] {
619
+ background: var(--error-bg);
620
+ border-color: var(--error-border);
621
+ color: var(--error-text);
622
+ }
623
+ :host([data-rich-colors='true'][data-type='error']) [data-close-button] {
624
+ background: var(--error-bg);
625
+ border-color: var(--error-border);
626
+ color: var(--error-text);
627
+ }
628
+
629
+ @keyframes swipe-out-left {
630
+ from {
631
+ transform: var(--y) translateX(var(--swipe-amount-x));
632
+ opacity: 1;
633
+ }
634
+ to {
635
+ transform: var(--y) translateX(calc(var(--swipe-amount-x) - 100%));
636
+ opacity: 0;
637
+ }
638
+ }
639
+ @keyframes swipe-out-right {
640
+ from {
641
+ transform: var(--y) translateX(var(--swipe-amount-x));
642
+ opacity: 1;
643
+ }
644
+ to {
645
+ transform: var(--y) translateX(calc(var(--swipe-amount-x) + 100%));
646
+ opacity: 0;
647
+ }
648
+ }
649
+ @keyframes swipe-out-up {
650
+ from {
651
+ transform: var(--y) translateY(var(--swipe-amount-y));
652
+ opacity: 1;
653
+ }
654
+ to {
655
+ transform: var(--y) translateY(calc(var(--swipe-amount-y) - 100%));
656
+ opacity: 0;
657
+ }
658
+ }
659
+ @keyframes swipe-out-down {
660
+ from {
661
+ transform: var(--y) translateY(var(--swipe-amount-y));
662
+ opacity: 1;
663
+ }
664
+ to {
665
+ transform: var(--y) translateY(calc(var(--swipe-amount-y) + 100%));
666
+ opacity: 0;
667
+ }
668
+ }
669
+
670
+ .sonner-loading-wrapper {
671
+ --size: 16px;
672
+ height: var(--size);
673
+ width: var(--size);
674
+ position: absolute;
675
+ inset: 0;
676
+ z-index: 10;
677
+ }
678
+ /* The wrapper is shown/hidden by the :host([data-type='loading']…) rules above; no
679
+ * data-visible attribute needed here. */
680
+ .sonner-spinner {
681
+ position: relative;
682
+ top: 50%;
683
+ left: 50%;
684
+ height: var(--size);
685
+ width: var(--size);
686
+ }
687
+ .sonner-loading-bar {
688
+ animation: sonner-spin 1.2s linear infinite;
689
+ background: var(--gray11, hsl(0, 0%, 43.5%));
690
+ border-radius: 6px;
691
+ height: 8%;
692
+ left: -10%;
693
+ position: absolute;
694
+ top: -3.9%;
695
+ width: 24%;
696
+ }
697
+ .sonner-loading-bar:nth-child(1) {
698
+ animation-delay: -1.2s;
699
+ transform: rotate(0.0001deg) translate(146%);
700
+ }
701
+ .sonner-loading-bar:nth-child(2) {
702
+ animation-delay: -1.1s;
703
+ transform: rotate(30deg) translate(146%);
704
+ }
705
+ .sonner-loading-bar:nth-child(3) {
706
+ animation-delay: -1s;
707
+ transform: rotate(60deg) translate(146%);
708
+ }
709
+ .sonner-loading-bar:nth-child(4) {
710
+ animation-delay: -0.9s;
711
+ transform: rotate(90deg) translate(146%);
712
+ }
713
+ .sonner-loading-bar:nth-child(5) {
714
+ animation-delay: -0.8s;
715
+ transform: rotate(120deg) translate(146%);
716
+ }
717
+ .sonner-loading-bar:nth-child(6) {
718
+ animation-delay: -0.7s;
719
+ transform: rotate(150deg) translate(146%);
720
+ }
721
+ .sonner-loading-bar:nth-child(7) {
722
+ animation-delay: -0.6s;
723
+ transform: rotate(180deg) translate(146%);
724
+ }
725
+ .sonner-loading-bar:nth-child(8) {
726
+ animation-delay: -0.5s;
727
+ transform: rotate(210deg) translate(146%);
728
+ }
729
+ .sonner-loading-bar:nth-child(9) {
730
+ animation-delay: -0.4s;
731
+ transform: rotate(240deg) translate(146%);
732
+ }
733
+ .sonner-loading-bar:nth-child(10) {
734
+ animation-delay: -0.3s;
735
+ transform: rotate(270deg) translate(146%);
736
+ }
737
+ .sonner-loading-bar:nth-child(11) {
738
+ animation-delay: -0.2s;
739
+ transform: rotate(300deg) translate(146%);
740
+ }
741
+ .sonner-loading-bar:nth-child(12) {
742
+ animation-delay: -0.1s;
743
+ transform: rotate(330deg) translate(146%);
744
+ }
745
+
746
+ @keyframes sonner-fade-in {
747
+ 0% {
748
+ opacity: 0;
749
+ transform: scale(0.8);
750
+ }
751
+ 100% {
752
+ opacity: 1;
753
+ transform: scale(1);
754
+ }
755
+ }
756
+ @keyframes sonner-fade-out {
757
+ 0% {
758
+ opacity: 1;
759
+ transform: scale(1);
760
+ }
761
+ 100% {
762
+ opacity: 0;
763
+ transform: scale(0.8);
764
+ }
765
+ }
766
+ @keyframes sonner-spin {
767
+ 0% {
768
+ opacity: 1;
769
+ }
770
+ 100% {
771
+ opacity: 0.15;
772
+ }
773
+ }
774
+
775
+ @media (prefers-reduced-motion) {
776
+ :host,
777
+ [data-frame],
778
+ [data-frame] > *,
779
+ .sonner-loading-bar {
780
+ transition: none !important;
781
+ animation: none !important;
782
+ }
783
+ }
784
+
785
+ /* Mobile: toasts fill the toaster's full width instead of staying pinned to
786
+ * --width (356px). Mirrors Sonner's mobile rule on [data-sonner-toast].
787
+ * Breakpoint matches the toaster's own mobile threshold. */
788
+ @media (max-width: 600px) {
789
+ :host([data-styled='true']),
790
+ :host([data-styled='false']) {
791
+ left: 0;
792
+ right: 0;
793
+ width: 100%;
794
+ }
795
+ }
796
+ `;
797
+
798
+ // src/styles.ts
799
+ var toasterSheet = null;
800
+ var toastSheet = null;
801
+ function getToasterSheet() {
802
+ if (!toasterSheet) {
803
+ toasterSheet = new CSSStyleSheet;
804
+ toasterSheet.replaceSync(toaster_default);
805
+ }
806
+ return toasterSheet;
807
+ }
808
+ function getToastSheet() {
809
+ if (!toastSheet) {
810
+ toastSheet = new CSSStyleSheet;
811
+ toastSheet.replaceSync(toast_default);
812
+ }
813
+ return toastSheet;
814
+ }
815
+
816
+ // src/sonner-toast.ts
817
+ var HTMLElementCtor = typeof HTMLElement !== "undefined" ? HTMLElement : class {
818
+ };
819
+ function isUrgentType(type) {
820
+ return type === "error" || type === "warning";
821
+ }
822
+ function setContent(host, slotName, value) {
823
+ for (const child of Array.from(host.children)) {
824
+ if (child.getAttribute("slot") === slotName)
825
+ host.removeChild(child);
826
+ }
827
+ if (value == null || value === "")
828
+ return;
829
+ const resolved = typeof value === "function" ? value() : value;
830
+ if (resolved instanceof Node) {
831
+ if (resolved instanceof Element)
832
+ resolved.setAttribute("slot", slotName);
833
+ host.appendChild(resolved);
834
+ } else {
835
+ const span = document.createElement("span");
836
+ span.setAttribute("slot", slotName);
837
+ span.textContent = String(resolved);
838
+ host.appendChild(span);
839
+ }
840
+ }
841
+ function setButtonSlot(host, slotName, value, defaultCloseHandler) {
842
+ for (const child of Array.from(host.children)) {
843
+ if (child.getAttribute("slot") === slotName)
844
+ host.removeChild(child);
845
+ }
846
+ if (!value)
847
+ return;
848
+ if (value instanceof HTMLElement) {
849
+ value.setAttribute("slot", slotName);
850
+ host.appendChild(value);
851
+ return;
852
+ }
853
+ const btn = document.createElement("button");
854
+ btn.setAttribute("slot", slotName);
855
+ btn.setAttribute("type", "button");
856
+ if (slotName === "cancel")
857
+ btn.setAttribute("data-cancel", "");
858
+ else
859
+ btn.setAttribute("data-action", "");
860
+ btn.textContent = value.label;
861
+ btn.addEventListener("click", (e) => {
862
+ value.onClick?.(e);
863
+ if (e.defaultPrevented && slotName === "action")
864
+ return;
865
+ defaultCloseHandler();
866
+ });
867
+ host.appendChild(btn);
868
+ }
869
+ var SPINNER_BARS_HTML = Array.from({ length: 12 }, () => '<div class="sonner-loading-bar"></div>').join("");
870
+ var SHADOW_TEMPLATE = `
871
+ <div data-frame part="frame">
872
+ <button type="button" data-close-button part="close-button" hidden aria-label="Close toast"></button>
873
+ <div data-icon part="icon">
874
+ <slot name="icon"></slot>
875
+ <div class="sonner-loading-wrapper" aria-hidden="true">
876
+ <div class="sonner-spinner">${SPINNER_BARS_HTML}</div>
877
+ </div>
878
+ </div>
879
+ <div data-content part="content">
880
+ <div data-title part="title"><slot name="title"></slot></div>
881
+ <div data-description part="description"><slot name="description"></slot></div>
882
+ </div>
883
+ <slot name="cancel"></slot>
884
+ <slot name="action"></slot>
885
+ <slot part="custom"></slot>
886
+ </div>
887
+ `;
888
+
889
+ class SonnerToast extends HTMLElementCtor {
890
+ static get observedAttributes() {
891
+ return ["type", "duration", "dismissible", "position", "close-button", "rich-colors", "invert"];
892
+ }
893
+ toastId = 0;
894
+ #shadow;
895
+ #closeBtn;
896
+ #iconWrap;
897
+ #titleWrap;
898
+ #descWrap;
899
+ #duration = null;
900
+ #remainingTime = TOAST_LIFETIME;
901
+ #timeoutId = null;
902
+ #timerStartedAt = 0;
903
+ #pauseReasons = new Set;
904
+ #pointerStart = null;
905
+ #dragStartTime = 0;
906
+ #swipeDirection = null;
907
+ #swipeDirections = null;
908
+ #mounted = false;
909
+ #removed = false;
910
+ #pendingRemoval = false;
911
+ #onDismiss;
912
+ #onAutoClose;
913
+ #closeButtonAriaLabel = null;
914
+ #prevFocus = null;
915
+ constructor() {
916
+ super();
917
+ this.#shadow = this.attachShadow({ mode: "open" });
918
+ this.#shadow.adoptedStyleSheets = [getToastSheet()];
919
+ const tpl = document.createElement("template");
920
+ tpl.innerHTML = SHADOW_TEMPLATE;
921
+ this.#shadow.appendChild(tpl.content.cloneNode(true));
922
+ this.#closeBtn = this.#shadow.querySelector("[data-close-button]");
923
+ this.#iconWrap = this.#shadow.querySelector("[data-icon]");
924
+ this.#titleWrap = this.#shadow.querySelector("[data-title]");
925
+ this.#descWrap = this.#shadow.querySelector("[data-description]");
926
+ this.#closeBtn.innerHTML = CLOSE_ICON;
927
+ this.#closeBtn.addEventListener("click", () => this.dismiss());
928
+ const iconSlot = this.#shadow.querySelector('slot[name="icon"]');
929
+ const descSlot = this.#shadow.querySelector('slot[name="description"]');
930
+ iconSlot.addEventListener("slotchange", () => this.#reflectSlot("icon", iconSlot));
931
+ descSlot.addEventListener("slotchange", () => this.#reflectSlot("description", descSlot));
932
+ this.addEventListener("pointerdown", this.#onPointerDown);
933
+ this.addEventListener("pointermove", this.#onPointerMove);
934
+ this.addEventListener("pointerup", this.#onPointerUp);
935
+ this.addEventListener("pointercancel", this.#onPointerUp);
936
+ this.addEventListener("mouseenter", () => this.#pauseFor("hover-self"));
937
+ this.addEventListener("mouseleave", () => this.#resumeFrom("hover-self"));
938
+ this.addEventListener("focusin", (e) => {
939
+ this.#pauseFor("focus-self");
940
+ if (this.#prevFocus)
941
+ return;
942
+ const from = e.relatedTarget;
943
+ if (from && !this.contains(from))
944
+ this.#prevFocus = from;
945
+ });
946
+ this.addEventListener("focusout", () => this.#resumeFrom("focus-self"));
947
+ this.addEventListener("keydown", (e) => {
948
+ if (e.key === "Escape" && this.#isDismissible()) {
949
+ e.stopPropagation();
950
+ this.dismiss();
951
+ }
952
+ });
953
+ }
954
+ connectedCallback() {
955
+ if (!this.toastId)
956
+ this.toastId = this.getAttribute("id") || 0;
957
+ if (!this.hasAttribute("tabindex"))
958
+ this.tabIndex = 0;
959
+ this.#applyType();
960
+ this.#applyDismissible();
961
+ this.#applyPosition();
962
+ this.#applyRichColors();
963
+ this.#applyInvert();
964
+ this.#applyCloseButton();
965
+ this.setAttribute("data-sonner-toast", "");
966
+ if (!this.hasAttribute("aria-atomic"))
967
+ this.setAttribute("aria-atomic", "true");
968
+ this.setAttribute("data-mounted", "false");
969
+ this.setAttribute("data-removed", "false");
970
+ this.setAttribute("data-swiping", "false");
971
+ this.setAttribute("data-swiped", "false");
972
+ this.setAttribute("data-swipe-out", "false");
973
+ if (!this.hasAttribute("data-styled"))
974
+ this.setAttribute("data-styled", "true");
975
+ registerToast(this);
976
+ document.addEventListener("visibilitychange", this.#onVisibilityChange);
977
+ requestAnimationFrame(() => {
978
+ this.#mounted = true;
979
+ this.setAttribute("data-mounted", "true");
980
+ this.dispatchEvent(new CustomEvent("sonner-toast-mounted", { bubbles: true, composed: true }));
981
+ this.#startTimer();
982
+ });
983
+ }
984
+ disconnectedCallback() {
985
+ if (this.#timeoutId)
986
+ clearTimeout(this.#timeoutId);
987
+ document.removeEventListener("visibilitychange", this.#onVisibilityChange);
988
+ unregisterToast(this);
989
+ }
990
+ attributeChangedCallback(name, _old, _val) {
991
+ if (!this.isConnected)
992
+ return;
993
+ switch (name) {
994
+ case "type":
995
+ this.#applyType();
996
+ break;
997
+ case "duration":
998
+ this.#duration = this.#readDuration();
999
+ this.#remainingTime = this.#duration ?? TOAST_LIFETIME;
1000
+ break;
1001
+ case "dismissible":
1002
+ this.#applyDismissible();
1003
+ break;
1004
+ case "position":
1005
+ this.#applyPosition();
1006
+ break;
1007
+ case "close-button":
1008
+ this.#applyCloseButton();
1009
+ break;
1010
+ case "rich-colors":
1011
+ this.#applyRichColors();
1012
+ break;
1013
+ case "invert":
1014
+ this.#applyInvert();
1015
+ break;
1016
+ }
1017
+ }
1018
+ get toastType() {
1019
+ return this.getAttribute("type") || "default";
1020
+ }
1021
+ dismiss() {
1022
+ if (this.#removed || this.#pendingRemoval)
1023
+ return;
1024
+ this.#pendingRemoval = true;
1025
+ this.#removed = true;
1026
+ this.setAttribute("data-removed", "true");
1027
+ if (this.#timeoutId)
1028
+ clearTimeout(this.#timeoutId);
1029
+ this.dispatchEvent(new CustomEvent("sonner-toast-dismissed", { bubbles: true, composed: true }));
1030
+ setTimeout(() => {
1031
+ this.#restoreFocusIfInside();
1032
+ this.#onDismiss?.(this);
1033
+ this.remove();
1034
+ }, TIME_BEFORE_UNMOUNT);
1035
+ }
1036
+ #restoreFocusIfInside() {
1037
+ if (!this.#prevFocus)
1038
+ return;
1039
+ const active = document.activeElement;
1040
+ if (!active || !this.contains(active))
1041
+ return;
1042
+ const target = this.#prevFocus;
1043
+ if (!target.isConnected || typeof target.focus !== "function")
1044
+ return;
1045
+ target.focus();
1046
+ }
1047
+ update(options) {
1048
+ const typeChanged = options.type !== undefined && options.type !== this.toastType;
1049
+ const wasUrgent = isUrgentType(this.toastType);
1050
+ if (options.type !== undefined)
1051
+ this.setAttribute("type", options.type);
1052
+ let timerNeedsReset = false;
1053
+ if (options.duration !== undefined) {
1054
+ this.setAttribute("duration", String(options.duration));
1055
+ this.#duration = options.duration;
1056
+ this.#remainingTime = options.duration;
1057
+ timerNeedsReset = true;
1058
+ } else if (typeChanged) {
1059
+ this.#duration = null;
1060
+ this.removeAttribute("duration");
1061
+ this.#remainingTime = 0;
1062
+ timerNeedsReset = true;
1063
+ }
1064
+ if (options.dismissible !== undefined) {
1065
+ if (options.dismissible)
1066
+ this.setAttribute("dismissible", "");
1067
+ else
1068
+ this.removeAttribute("dismissible");
1069
+ }
1070
+ if (options.position !== undefined)
1071
+ this.setAttribute("position", options.position);
1072
+ if (options.closeButton !== undefined) {
1073
+ if (options.closeButton)
1074
+ this.setAttribute("close-button", "");
1075
+ else
1076
+ this.removeAttribute("close-button");
1077
+ }
1078
+ if (options.richColors !== undefined) {
1079
+ if (options.richColors)
1080
+ this.setAttribute("rich-colors", "");
1081
+ else
1082
+ this.removeAttribute("rich-colors");
1083
+ }
1084
+ if (options.invert !== undefined) {
1085
+ if (options.invert)
1086
+ this.setAttribute("invert", "");
1087
+ else
1088
+ this.removeAttribute("invert");
1089
+ }
1090
+ if (options.icon !== undefined)
1091
+ this.setIcon(options.icon);
1092
+ if (options.title !== undefined)
1093
+ this.setTitle(options.title);
1094
+ if (options.description !== undefined)
1095
+ this.setDescription(options.description);
1096
+ if (options.action !== undefined) {
1097
+ setButtonSlot(this, "action", options.action, () => this.dismiss());
1098
+ }
1099
+ if (options.cancel !== undefined) {
1100
+ setButtonSlot(this, "cancel", options.cancel, () => this.dismiss());
1101
+ }
1102
+ if (options.className)
1103
+ this.className = options.className;
1104
+ if (options.testId !== undefined)
1105
+ this.setAttribute("data-testid", options.testId);
1106
+ if (options.closeButtonAriaLabel !== undefined) {
1107
+ this.#closeButtonAriaLabel = options.closeButtonAriaLabel || null;
1108
+ this.#applyCloseButtonAriaLabel();
1109
+ }
1110
+ if (options.onDismiss)
1111
+ this.#onDismiss = options.onDismiss;
1112
+ if (options.onAutoClose)
1113
+ this.#onAutoClose = options.onAutoClose;
1114
+ if (timerNeedsReset)
1115
+ this.#resetTimer();
1116
+ if (this.#mounted && typeChanged && !wasUrgent && isUrgentType(this.toastType)) {
1117
+ const titleEl = Array.from(this.children).find((c) => c.getAttribute("slot") === "title");
1118
+ const text = titleEl?.textContent?.trim();
1119
+ if (text) {
1120
+ const toaster = this.closest("sonner-toaster");
1121
+ toaster?.announceUrgent(text);
1122
+ }
1123
+ }
1124
+ this.dispatchEvent(new CustomEvent("sonner-toast-updated", { bubbles: true, composed: true }));
1125
+ }
1126
+ setTitle(value) {
1127
+ setContent(this, "title", value);
1128
+ this.#applyCloseButtonAriaLabel();
1129
+ }
1130
+ #applyCloseButtonAriaLabel() {
1131
+ if (this.#closeButtonAriaLabel) {
1132
+ this.#closeBtn.setAttribute("aria-label", this.#closeButtonAriaLabel);
1133
+ return;
1134
+ }
1135
+ const titleEl = Array.from(this.children).find((c) => c.getAttribute("slot") === "title");
1136
+ const text = titleEl?.textContent?.trim();
1137
+ this.#closeBtn.setAttribute("aria-label", text ? `Close: ${text}` : "Close toast");
1138
+ }
1139
+ setDescription(value) {
1140
+ setContent(this, "description", value);
1141
+ }
1142
+ setIcon(value) {
1143
+ for (const child of Array.from(this.children)) {
1144
+ if (child.getAttribute("slot") === "icon")
1145
+ this.removeChild(child);
1146
+ }
1147
+ if (value == null)
1148
+ return;
1149
+ if (value instanceof Node) {
1150
+ if (value instanceof Element)
1151
+ value.setAttribute("slot", "icon");
1152
+ this.appendChild(value);
1153
+ } else {
1154
+ const tpl = document.createElement("template");
1155
+ tpl.innerHTML = value;
1156
+ const el = tpl.content.firstElementChild;
1157
+ if (el) {
1158
+ el.setAttribute("slot", "icon");
1159
+ this.appendChild(el);
1160
+ }
1161
+ }
1162
+ }
1163
+ setHandlers(handlers) {
1164
+ this.#onDismiss = handlers.onDismiss;
1165
+ this.#onAutoClose = handlers.onAutoClose;
1166
+ }
1167
+ setPaused(paused) {
1168
+ if (paused)
1169
+ this.#pauseFor("toaster");
1170
+ else
1171
+ this.#resumeFrom("toaster");
1172
+ }
1173
+ #reflectSlot(name, slot) {
1174
+ const has = slot.assignedNodes().length > 0;
1175
+ if (has)
1176
+ this.setAttribute(`data-has-${name}`, "");
1177
+ else
1178
+ this.removeAttribute(`data-has-${name}`);
1179
+ }
1180
+ #applyType() {
1181
+ const type = this.toastType;
1182
+ this.setAttribute("data-type", type);
1183
+ const urgent = isUrgentType(type);
1184
+ this.setAttribute("role", urgent ? "alert" : "status");
1185
+ this.setAttribute("aria-live", urgent ? "assertive" : "polite");
1186
+ if (type === "loading") {
1187
+ this.setAttribute("data-promise", "true");
1188
+ for (const c of Array.from(this.children)) {
1189
+ if (c.getAttribute("slot") === "icon" && c.hasAttribute("data-sonner-default-icon"))
1190
+ this.removeChild(c);
1191
+ }
1192
+ } else {
1193
+ this.removeAttribute("data-promise");
1194
+ const hasUserIcon = Array.from(this.children).some((c) => {
1195
+ if (c.getAttribute("slot") !== "icon")
1196
+ return false;
1197
+ return !c.hasAttribute("data-sonner-default-icon");
1198
+ });
1199
+ if (!hasUserIcon) {
1200
+ for (const c of Array.from(this.children)) {
1201
+ if (c.getAttribute("slot") === "icon" && c.hasAttribute("data-sonner-default-icon"))
1202
+ this.removeChild(c);
1203
+ }
1204
+ const builtin = getTypeIcon(type);
1205
+ if (builtin) {
1206
+ const tpl = document.createElement("template");
1207
+ tpl.innerHTML = builtin;
1208
+ const el = tpl.content.firstElementChild;
1209
+ if (el) {
1210
+ el.setAttribute("slot", "icon");
1211
+ el.setAttribute("data-sonner-default-icon", "");
1212
+ this.appendChild(el);
1213
+ }
1214
+ }
1215
+ }
1216
+ }
1217
+ }
1218
+ #applyDismissible() {
1219
+ const dismissible = this.getAttribute("dismissible") !== "false";
1220
+ this.setAttribute("data-dismissible", String(dismissible));
1221
+ }
1222
+ #applyPosition() {
1223
+ const pos = this.getAttribute("position");
1224
+ if (!pos)
1225
+ return;
1226
+ const [y, x] = pos.split("-");
1227
+ if (y)
1228
+ this.setAttribute("data-y-position", y);
1229
+ if (x)
1230
+ this.setAttribute("data-x-position", x);
1231
+ }
1232
+ #applyCloseButton() {
1233
+ const show = this.hasAttribute("close-button") && this.getAttribute("close-button") !== "false";
1234
+ this.#closeBtn.hidden = !show;
1235
+ }
1236
+ #applyRichColors() {
1237
+ const rich = this.hasAttribute("rich-colors") && this.getAttribute("rich-colors") !== "false";
1238
+ this.setAttribute("data-rich-colors", String(rich));
1239
+ }
1240
+ #applyInvert() {
1241
+ const invert = this.hasAttribute("invert") && this.getAttribute("invert") !== "false";
1242
+ this.setAttribute("data-invert", String(invert));
1243
+ }
1244
+ #readDuration() {
1245
+ const raw = this.getAttribute("duration");
1246
+ if (raw == null)
1247
+ return null;
1248
+ if (raw === "Infinity")
1249
+ return Infinity;
1250
+ const n = Number(raw);
1251
+ return Number.isFinite(n) || n === Infinity ? n : null;
1252
+ }
1253
+ #effectiveDuration() {
1254
+ const explicit = this.#duration ?? this.#readDuration();
1255
+ if (explicit !== null)
1256
+ return explicit;
1257
+ if (this.toastType === "loading")
1258
+ return Infinity;
1259
+ return TOAST_LIFETIME;
1260
+ }
1261
+ #startTimer() {
1262
+ if (!this.#mounted || this.#removed)
1263
+ return;
1264
+ if (this.#pauseReasons.size > 0)
1265
+ return;
1266
+ if (this.#timeoutId !== null)
1267
+ return;
1268
+ const dur = this.#effectiveDuration();
1269
+ if (dur === Infinity)
1270
+ return;
1271
+ this.#remainingTime = this.#remainingTime > 0 ? this.#remainingTime : dur;
1272
+ this.#timerStartedAt = Date.now();
1273
+ this.#timeoutId = setTimeout(() => {
1274
+ this.#timeoutId = null;
1275
+ this.#onAutoClose?.(this);
1276
+ this.dispatchEvent(new CustomEvent("sonner-toast-autoclosed", { bubbles: true, composed: true }));
1277
+ this.dismiss();
1278
+ }, this.#remainingTime);
1279
+ }
1280
+ #pauseFor(reason) {
1281
+ const wasUnpaused = this.#pauseReasons.size === 0;
1282
+ this.#pauseReasons.add(reason);
1283
+ if (wasUnpaused && this.#timeoutId !== null) {
1284
+ clearTimeout(this.#timeoutId);
1285
+ this.#timeoutId = null;
1286
+ const elapsed = Date.now() - this.#timerStartedAt;
1287
+ this.#remainingTime = Math.max(0, this.#remainingTime - elapsed);
1288
+ }
1289
+ }
1290
+ #resumeFrom(reason) {
1291
+ if (!this.#pauseReasons.delete(reason))
1292
+ return;
1293
+ if (this.#pauseReasons.size === 0 && !this.#removed)
1294
+ this.#startTimer();
1295
+ }
1296
+ #resetTimer() {
1297
+ if (this.#timeoutId) {
1298
+ clearTimeout(this.#timeoutId);
1299
+ this.#timeoutId = null;
1300
+ }
1301
+ this.#remainingTime = this.#effectiveDuration();
1302
+ this.#startTimer();
1303
+ }
1304
+ #onVisibilityChange = () => {
1305
+ if (document.visibilityState === "hidden")
1306
+ this.#pauseFor("doc-hidden");
1307
+ else
1308
+ this.#resumeFrom("doc-hidden");
1309
+ };
1310
+ #isDismissible() {
1311
+ return this.getAttribute("dismissible") !== "false";
1312
+ }
1313
+ #onPointerDown = (event) => {
1314
+ if (event.button === 2)
1315
+ return;
1316
+ if (this.toastType === "loading" || !this.#isDismissible())
1317
+ return;
1318
+ const realTarget = event.composedPath()[0];
1319
+ if (realTarget) {
1320
+ const inButton = realTarget.tagName === "BUTTON" || typeof realTarget.closest === "function" && realTarget.closest("button");
1321
+ if (inButton)
1322
+ return;
1323
+ }
1324
+ this.#dragStartTime = Date.now();
1325
+ try {
1326
+ this.setPointerCapture(event.pointerId);
1327
+ } catch {}
1328
+ this.setAttribute("data-swiping", "true");
1329
+ this.#pointerStart = { x: event.clientX, y: event.clientY };
1330
+ if (!this.#swipeDirections) {
1331
+ const y = this.getAttribute("data-y-position");
1332
+ const x = this.getAttribute("data-x-position");
1333
+ const dirs = [];
1334
+ if (y === "top" || y === "bottom")
1335
+ dirs.push(y);
1336
+ if (x === "left" || x === "right")
1337
+ dirs.push(x);
1338
+ this.#swipeDirections = dirs.length > 0 ? dirs : ["bottom", "right"];
1339
+ }
1340
+ };
1341
+ #onPointerMove = (event) => {
1342
+ if (!this.#pointerStart || !this.#isDismissible())
1343
+ return;
1344
+ if ((window.getSelection()?.toString().length ?? 0) > 0)
1345
+ return;
1346
+ const yDelta = event.clientY - this.#pointerStart.y;
1347
+ const xDelta = event.clientX - this.#pointerStart.x;
1348
+ const dirs = this.#swipeDirections;
1349
+ if (!this.#swipeDirection && (Math.abs(xDelta) > 1 || Math.abs(yDelta) > 1)) {
1350
+ this.#swipeDirection = Math.abs(xDelta) > Math.abs(yDelta) ? "x" : "y";
1351
+ }
1352
+ const dampen = (delta) => 1 / (1.5 + Math.abs(delta) / 20);
1353
+ let sx = 0;
1354
+ let sy = 0;
1355
+ if (this.#swipeDirection === "y") {
1356
+ if (dirs.includes("top") || dirs.includes("bottom")) {
1357
+ if (dirs.includes("top") && yDelta < 0 || dirs.includes("bottom") && yDelta > 0) {
1358
+ sy = yDelta;
1359
+ } else {
1360
+ const d = yDelta * dampen(yDelta);
1361
+ sy = Math.abs(d) < Math.abs(yDelta) ? d : yDelta;
1362
+ }
1363
+ }
1364
+ } else if (this.#swipeDirection === "x") {
1365
+ if (dirs.includes("left") || dirs.includes("right")) {
1366
+ if (dirs.includes("left") && xDelta < 0 || dirs.includes("right") && xDelta > 0) {
1367
+ sx = xDelta;
1368
+ } else {
1369
+ const d = xDelta * dampen(xDelta);
1370
+ sx = Math.abs(d) < Math.abs(xDelta) ? d : xDelta;
1371
+ }
1372
+ }
1373
+ }
1374
+ if (Math.abs(sx) > 0 || Math.abs(sy) > 0)
1375
+ this.setAttribute("data-swiped", "true");
1376
+ this.style.setProperty("--swipe-amount-x", `${sx}px`);
1377
+ this.style.setProperty("--swipe-amount-y", `${sy}px`);
1378
+ };
1379
+ #onPointerUp = () => {
1380
+ if (this.getAttribute("data-swipe-out") === "true" || !this.#isDismissible()) {
1381
+ this.#pointerStart = null;
1382
+ this.#swipeDirection = null;
1383
+ this.setAttribute("data-swiping", "false");
1384
+ return;
1385
+ }
1386
+ const sx = parseFloat(this.style.getPropertyValue("--swipe-amount-x")) || 0;
1387
+ const sy = parseFloat(this.style.getPropertyValue("--swipe-amount-y")) || 0;
1388
+ const time = Math.max(1, Date.now() - this.#dragStartTime);
1389
+ const amount = this.#swipeDirection === "x" ? sx : sy;
1390
+ const velocity = Math.abs(amount) / time;
1391
+ if (Math.abs(amount) >= SWIPE_THRESHOLD || velocity > SWIPE_VELOCITY_THRESHOLD) {
1392
+ if (this.#swipeDirection === "x") {
1393
+ this.setAttribute("data-swipe-direction", sx > 0 ? "right" : "left");
1394
+ } else {
1395
+ this.setAttribute("data-swipe-direction", sy > 0 ? "down" : "up");
1396
+ }
1397
+ this.setAttribute("data-swipe-out", "true");
1398
+ this.dismiss();
1399
+ } else {
1400
+ this.style.setProperty("--swipe-amount-x", "0px");
1401
+ this.style.setProperty("--swipe-amount-y", "0px");
1402
+ this.setAttribute("data-swiped", "false");
1403
+ }
1404
+ this.setAttribute("data-swiping", "false");
1405
+ this.#pointerStart = null;
1406
+ this.#swipeDirection = null;
1407
+ };
1408
+ }
1409
+ if (typeof customElements !== "undefined" && !customElements.get("sonner-toast")) {
1410
+ customElements.define("sonner-toast", SonnerToast);
1411
+ }
1412
+ // src/sonner-toaster.ts
1413
+ var HTMLElementCtor2 = typeof HTMLElement !== "undefined" ? HTMLElement : class {
1414
+ };
1415
+ function parseOffsetValue(v, fallback) {
1416
+ if (v == null)
1417
+ return fallback;
1418
+ if (typeof v === "number")
1419
+ return `${v}px`;
1420
+ return v;
1421
+ }
1422
+ function applyOffsetVars(host, opts, prefix, fallback) {
1423
+ const sides = ["top", "right", "bottom", "left"];
1424
+ if (opts == null || typeof opts === "string" || typeof opts === "number") {
1425
+ const v = parseOffsetValue(opts, fallback);
1426
+ for (const side of sides)
1427
+ host.style.setProperty(`${prefix}-${side}`, v);
1428
+ } else {
1429
+ for (const side of sides) {
1430
+ host.style.setProperty(`${prefix}-${side}`, parseOffsetValue(opts[side], fallback));
1431
+ }
1432
+ }
1433
+ }
1434
+
1435
+ class SonnerToaster extends HTMLElementCtor2 {
1436
+ static get observedAttributes() {
1437
+ return [
1438
+ "position",
1439
+ "theme",
1440
+ "rich-colors",
1441
+ "expand",
1442
+ "duration",
1443
+ "gap",
1444
+ "visible-toasts",
1445
+ "close-button",
1446
+ "invert",
1447
+ "dir",
1448
+ "offset",
1449
+ "mobile-offset",
1450
+ "hotkey",
1451
+ "container-aria-label"
1452
+ ];
1453
+ }
1454
+ #shadow;
1455
+ #alertAnnouncer;
1456
+ #childObserver;
1457
+ #resizeObserver;
1458
+ #toasts = [];
1459
+ #heights = new Map;
1460
+ #measuring = false;
1461
+ #expanded = false;
1462
+ #interacting = false;
1463
+ #themeMql = null;
1464
+ #themeMqlHandler = null;
1465
+ constructor() {
1466
+ super();
1467
+ this.#shadow = this.attachShadow({ mode: "open" });
1468
+ this.#shadow.adoptedStyleSheets = [getToasterSheet()];
1469
+ this.#shadow.innerHTML = '<div data-frame part="frame"><slot></slot></div>' + '<div data-alert-announcer role="alert" aria-live="assertive" aria-atomic="true" ' + 'style="position:absolute;left:0;top:0;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;" + 'pointer-events:none"></div>';
1470
+ this.#alertAnnouncer = this.#shadow.querySelector("[data-alert-announcer]");
1471
+ this.#childObserver = new MutationObserver((records) => {
1472
+ let changed = false;
1473
+ for (const r of records) {
1474
+ for (const node of Array.from(r.addedNodes)) {
1475
+ if (node instanceof SonnerToast) {
1476
+ this.#toasts.unshift(node);
1477
+ this.#resizeObserver.observe(node);
1478
+ this.#decorateToast(node);
1479
+ changed = true;
1480
+ }
1481
+ }
1482
+ for (const node of Array.from(r.removedNodes)) {
1483
+ if (node instanceof SonnerToast) {
1484
+ this.#toasts = this.#toasts.filter((t) => t !== node);
1485
+ this.#heights.delete(node);
1486
+ this.#resizeObserver.unobserve(node);
1487
+ changed = true;
1488
+ }
1489
+ }
1490
+ }
1491
+ if (changed)
1492
+ this.#reflow({ remeasure: true });
1493
+ });
1494
+ this.#resizeObserver = new ResizeObserver(() => this.#reflow({ remeasure: false }));
1495
+ this.addEventListener("mouseenter", this.#onPointerEnter);
1496
+ this.addEventListener("mouseleave", this.#onPointerLeave);
1497
+ this.addEventListener("focusin", this.#onFocusIn);
1498
+ this.addEventListener("focusout", this.#onFocusOut);
1499
+ this.addEventListener("sonner-toast-dismissed", () => this.#reflow({ remeasure: false }));
1500
+ this.addEventListener("sonner-toast-updated", () => this.#reflow({ remeasure: true }));
1501
+ this.addEventListener("sonner-toast-mounted", () => this.#reflow({ remeasure: true }));
1502
+ }
1503
+ connectedCallback() {
1504
+ if (!this.hasAttribute("tabindex"))
1505
+ this.tabIndex = -1;
1506
+ if (!this.hasAttribute("role"))
1507
+ this.setAttribute("role", "region");
1508
+ if (!this.hasAttribute("aria-label"))
1509
+ this.setAttribute("aria-label", this.getAttribute("container-aria-label") ?? "Notifications");
1510
+ this.setAttribute("data-sonner-toaster", "");
1511
+ this.#applyPosition();
1512
+ this.#applyTheme();
1513
+ this.#applyDir();
1514
+ this.#applyGap();
1515
+ this.#applyWidth();
1516
+ this.#applyOffsets();
1517
+ this.#childObserver.observe(this, { childList: true });
1518
+ for (const child of Array.from(this.children)) {
1519
+ if (child instanceof SonnerToast) {
1520
+ this.#toasts.unshift(child);
1521
+ this.#resizeObserver.observe(child);
1522
+ this.#decorateToast(child);
1523
+ }
1524
+ }
1525
+ document.addEventListener("keydown", this.#onKeyDown);
1526
+ window.addEventListener("resize", this.#onWindowResize);
1527
+ registerToaster(this);
1528
+ this.#reflow({ remeasure: true });
1529
+ }
1530
+ disconnectedCallback() {
1531
+ this.#childObserver.disconnect();
1532
+ this.#resizeObserver.disconnect();
1533
+ document.removeEventListener("keydown", this.#onKeyDown);
1534
+ window.removeEventListener("resize", this.#onWindowResize);
1535
+ if (this.#themeMql && this.#themeMqlHandler) {
1536
+ this.#themeMql.removeEventListener("change", this.#themeMqlHandler);
1537
+ }
1538
+ unregisterToaster(this);
1539
+ }
1540
+ attributeChangedCallback(name, _old, _val) {
1541
+ if (!this.isConnected)
1542
+ return;
1543
+ switch (name) {
1544
+ case "position":
1545
+ this.#applyPosition();
1546
+ this.#applyToastPositions();
1547
+ this.#reflow();
1548
+ break;
1549
+ case "theme":
1550
+ this.#applyTheme();
1551
+ break;
1552
+ case "dir":
1553
+ this.#applyDir();
1554
+ break;
1555
+ case "gap":
1556
+ this.#applyGap();
1557
+ this.#reflow();
1558
+ break;
1559
+ case "visible-toasts":
1560
+ this.#reflow();
1561
+ break;
1562
+ case "expand":
1563
+ this.#expanded = this.hasAttribute("expand");
1564
+ for (const t of this.#toasts)
1565
+ t.setPaused(this.#expanded || this.#interacting);
1566
+ this.#reflow();
1567
+ break;
1568
+ case "close-button":
1569
+ case "rich-colors":
1570
+ case "invert":
1571
+ this.#propagateBoolean(name);
1572
+ break;
1573
+ case "offset":
1574
+ case "mobile-offset":
1575
+ this.#applyOffsets();
1576
+ break;
1577
+ case "container-aria-label":
1578
+ this.setAttribute("aria-label", this.getAttribute("container-aria-label") ?? "Notifications");
1579
+ break;
1580
+ }
1581
+ }
1582
+ addToast(el) {
1583
+ this.appendChild(el);
1584
+ return el;
1585
+ }
1586
+ announceUrgent(text) {
1587
+ this.#alertAnnouncer.textContent = "";
1588
+ requestAnimationFrame(() => {
1589
+ this.#alertAnnouncer.textContent = text;
1590
+ });
1591
+ }
1592
+ dismissAll() {
1593
+ for (const child of Array.from(this.children)) {
1594
+ if (child instanceof SonnerToast)
1595
+ child.dismiss();
1596
+ }
1597
+ }
1598
+ #getPosition() {
1599
+ return this.getAttribute("position") || "bottom-right";
1600
+ }
1601
+ #applyPosition() {
1602
+ const [y, x] = this.#getPosition().split("-");
1603
+ if (y)
1604
+ this.setAttribute("data-y-position", y);
1605
+ if (x)
1606
+ this.setAttribute("data-x-position", x);
1607
+ }
1608
+ #applyTheme() {
1609
+ if (this.#themeMql && this.#themeMqlHandler) {
1610
+ this.#themeMql.removeEventListener("change", this.#themeMqlHandler);
1611
+ this.#themeMql = null;
1612
+ this.#themeMqlHandler = null;
1613
+ }
1614
+ const theme = this.getAttribute("theme") || "light";
1615
+ if (theme === "system") {
1616
+ this.#themeMql = window.matchMedia("(prefers-color-scheme: dark)");
1617
+ const apply = (mql) => {
1618
+ this.setAttribute("data-sonner-theme", mql.matches ? "dark" : "light");
1619
+ };
1620
+ this.#themeMqlHandler = apply;
1621
+ this.#themeMql.addEventListener("change", apply);
1622
+ apply(this.#themeMql);
1623
+ } else {
1624
+ this.setAttribute("data-sonner-theme", theme);
1625
+ }
1626
+ }
1627
+ #applyDir() {
1628
+ const dir = this.getAttribute("dir");
1629
+ if (dir === "auto" || !dir) {
1630
+ const computed = window.getComputedStyle(document.documentElement).direction || "ltr";
1631
+ this.setAttribute("dir", computed);
1632
+ }
1633
+ }
1634
+ #applyGap() {
1635
+ const raw = this.getAttribute("gap");
1636
+ const gap = raw ? Number(raw) : GAP;
1637
+ this.style.setProperty("--gap", `${Number.isFinite(gap) ? gap : GAP}px`);
1638
+ }
1639
+ #applyWidth() {
1640
+ this.style.setProperty("--width", `${TOAST_WIDTH}px`);
1641
+ }
1642
+ #applyOffsets() {
1643
+ const off = this.getAttribute("offset");
1644
+ const mobileOff = this.getAttribute("mobile-offset");
1645
+ applyOffsetVars(this, off ?? undefined, "--offset", "24px");
1646
+ applyOffsetVars(this, mobileOff ?? undefined, "--mobile-offset", "16px");
1647
+ }
1648
+ #applyToastPositions() {
1649
+ for (const t of this.#toasts) {
1650
+ if (!t.hasAttribute("position")) {
1651
+ const [y, x] = this.#getPosition().split("-");
1652
+ if (y)
1653
+ t.setAttribute("data-y-position", y);
1654
+ if (x)
1655
+ t.setAttribute("data-x-position", x);
1656
+ }
1657
+ }
1658
+ }
1659
+ #propagateBoolean(attr) {
1660
+ const on = this.hasAttribute(attr);
1661
+ for (const t of this.#toasts) {
1662
+ if (t.getAttribute(attr) === "false")
1663
+ continue;
1664
+ if (on)
1665
+ t.setAttribute(attr, "");
1666
+ else
1667
+ t.removeAttribute(attr);
1668
+ }
1669
+ }
1670
+ #decorateToast(toast) {
1671
+ if (!toast.hasAttribute("position")) {
1672
+ const [y, x] = this.#getPosition().split("-");
1673
+ if (y)
1674
+ toast.setAttribute("data-y-position", y);
1675
+ if (x)
1676
+ toast.setAttribute("data-x-position", x);
1677
+ }
1678
+ if (!toast.hasAttribute("duration")) {
1679
+ const inherit = this.getAttribute("duration");
1680
+ if (inherit)
1681
+ toast.setAttribute("duration", inherit);
1682
+ }
1683
+ if (!toast.hasAttribute("close-button") && this.hasAttribute("close-button")) {
1684
+ toast.setAttribute("close-button", "");
1685
+ }
1686
+ if (!toast.hasAttribute("rich-colors") && this.hasAttribute("rich-colors")) {
1687
+ toast.setAttribute("rich-colors", "");
1688
+ }
1689
+ if (!toast.hasAttribute("invert") && this.hasAttribute("invert")) {
1690
+ toast.setAttribute("invert", "");
1691
+ }
1692
+ }
1693
+ #reflow(opts = { remeasure: false }) {
1694
+ const visibleAmount = Number(this.getAttribute("visible-toasts") ?? VISIBLE_TOASTS_AMOUNT);
1695
+ if (opts.remeasure) {
1696
+ this.#measuring = true;
1697
+ for (const t of this.#toasts) {
1698
+ if (t.getAttribute("data-removed") === "true")
1699
+ continue;
1700
+ const prior = t.style.height;
1701
+ t.style.height = "auto";
1702
+ this.#heights.set(t, t.getBoundingClientRect().height);
1703
+ t.style.height = prior;
1704
+ }
1705
+ this.#measuring = false;
1706
+ }
1707
+ const active = this.#toasts.filter((t) => t.getAttribute("data-removed") !== "true");
1708
+ const frontHeight = active.length > 0 ? this.#heights.get(active[0]) ?? 0 : 0;
1709
+ const gap = this.#gapPx();
1710
+ const expanded = this.#expanded || this.#interacting;
1711
+ let cumulative = 0;
1712
+ this.style.setProperty("--front-toast-height", `${frontHeight}px`);
1713
+ for (let i = 0;i < active.length; i++) {
1714
+ const toast = active[i];
1715
+ const h = this.#heights.get(toast) ?? 0;
1716
+ const isFront = i === 0;
1717
+ const offset = i === 0 ? 0 : cumulative + i * gap;
1718
+ cumulative += h;
1719
+ toast.style.setProperty("--index", String(i));
1720
+ toast.style.setProperty("--toasts-before", String(i));
1721
+ toast.style.setProperty("--z-index", String(active.length - i));
1722
+ toast.style.setProperty("--offset", `${offset}px`);
1723
+ toast.style.setProperty("--initial-height", `${h}px`);
1724
+ toast.setAttribute("data-index", String(i));
1725
+ toast.setAttribute("data-front", String(isFront));
1726
+ toast.setAttribute("data-visible", String(i + 1 <= visibleAmount));
1727
+ toast.setAttribute("data-expanded", String(expanded));
1728
+ if (expanded || isFront)
1729
+ toast.removeAttribute("aria-hidden");
1730
+ else
1731
+ toast.setAttribute("aria-hidden", "true");
1732
+ }
1733
+ }
1734
+ #gapPx() {
1735
+ const raw = this.getAttribute("gap");
1736
+ const n = raw ? Number(raw) : GAP;
1737
+ return Number.isFinite(n) ? n : GAP;
1738
+ }
1739
+ #onPointerEnter = () => {
1740
+ this.#interacting = true;
1741
+ for (const t of this.#toasts)
1742
+ t.setPaused(true);
1743
+ this.#reflow();
1744
+ };
1745
+ #onPointerLeave = () => {
1746
+ this.#interacting = false;
1747
+ for (const t of this.#toasts)
1748
+ t.setPaused(false);
1749
+ this.#reflow();
1750
+ };
1751
+ #onFocusIn = () => {
1752
+ this.#interacting = true;
1753
+ for (const t of this.#toasts)
1754
+ t.setPaused(true);
1755
+ this.#reflow();
1756
+ };
1757
+ #onFocusOut = (e) => {
1758
+ const next = e.relatedTarget;
1759
+ if (next && this.contains(next))
1760
+ return;
1761
+ this.#interacting = false;
1762
+ for (const t of this.#toasts)
1763
+ t.setPaused(false);
1764
+ this.#reflow();
1765
+ };
1766
+ #onWindowResize = () => this.#reflow({ remeasure: true });
1767
+ #onKeyDown = (event) => {
1768
+ const target = event.target;
1769
+ if (target) {
1770
+ const tag = target.tagName;
1771
+ if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || target.isContentEditable) {
1772
+ return;
1773
+ }
1774
+ }
1775
+ const hotkey = this.#hotkey();
1776
+ const matches = hotkey.every((key) => {
1777
+ if (key === "altKey" || key === "ctrlKey" || key === "shiftKey" || key === "metaKey") {
1778
+ return event[key];
1779
+ }
1780
+ return event.code === key;
1781
+ });
1782
+ if (matches) {
1783
+ this.#expanded = true;
1784
+ for (const t of this.#toasts)
1785
+ t.setPaused(true);
1786
+ this.focus();
1787
+ this.#reflow();
1788
+ return;
1789
+ }
1790
+ if (event.key === "Escape" && this.#expanded && this.contains(document.activeElement)) {
1791
+ this.#expanded = false;
1792
+ for (const t of this.#toasts)
1793
+ t.setPaused(false);
1794
+ this.#reflow();
1795
+ }
1796
+ };
1797
+ #hotkey() {
1798
+ const raw = this.getAttribute("hotkey");
1799
+ if (!raw)
1800
+ return DEFAULT_HOTKEY;
1801
+ return raw.split("+").map((s) => s.trim());
1802
+ }
1803
+ }
1804
+ if (typeof customElements !== "undefined" && !customElements.get("sonner-toaster")) {
1805
+ customElements.define("sonner-toaster", SonnerToaster);
1806
+ }
1807
+ // src/toast.ts
1808
+ function ensureToaster(toasterId) {
1809
+ if (toasterId) {
1810
+ const byId = document.getElementById(toasterId);
1811
+ if (byId instanceof SonnerToaster)
1812
+ return byId;
1813
+ }
1814
+ let host = defaultToaster();
1815
+ if (!host) {
1816
+ host = document.createElement("sonner-toaster");
1817
+ document.body.appendChild(host);
1818
+ }
1819
+ return host;
1820
+ }
1821
+ function buildOrUpdate(options) {
1822
+ const id = options.id ?? nextToastId();
1823
+ const existing = getToast(id);
1824
+ if (existing) {
1825
+ existing.update(options);
1826
+ return existing;
1827
+ }
1828
+ const el = document.createElement("sonner-toast");
1829
+ el.toastId = id;
1830
+ el.update(options);
1831
+ el.setHandlers({ onDismiss: options.onDismiss, onAutoClose: options.onAutoClose });
1832
+ ensureToaster(options.toasterId).addToast(el);
1833
+ return el;
1834
+ }
1835
+ function variant(type) {
1836
+ return (message, opts) => buildOrUpdate({ ...opts, type, title: message });
1837
+ }
1838
+ function basic(message, opts) {
1839
+ return buildOrUpdate({ ...opts, type: "default", title: message });
1840
+ }
1841
+ function dismiss(id) {
1842
+ if (id !== undefined) {
1843
+ getToast(id)?.dismiss();
1844
+ return;
1845
+ }
1846
+ dismissAllToasts();
1847
+ }
1848
+ function custom(builder, opts) {
1849
+ const id = opts?.id ?? nextToastId();
1850
+ const el = document.createElement("sonner-toast");
1851
+ el.toastId = id;
1852
+ el.setAttribute("data-styled", "false");
1853
+ if (opts?.duration !== undefined)
1854
+ el.setAttribute("duration", String(opts.duration));
1855
+ if (opts?.dismissible === false)
1856
+ el.setAttribute("dismissible", "false");
1857
+ if (opts?.position)
1858
+ el.setAttribute("position", opts.position);
1859
+ if (opts?.testId !== undefined)
1860
+ el.setAttribute("data-testid", opts.testId);
1861
+ const content = builder(id);
1862
+ el.appendChild(content);
1863
+ el.setHandlers({ onDismiss: opts?.onDismiss, onAutoClose: opts?.onAutoClose });
1864
+ ensureToaster(opts?.toasterId).addToast(el);
1865
+ return el;
1866
+ }
1867
+ async function resolveContent(value, arg) {
1868
+ if (value === undefined)
1869
+ return;
1870
+ if (typeof value === "function") {
1871
+ return value.length === 0 ? value() : value(arg);
1872
+ }
1873
+ return value;
1874
+ }
1875
+ function promise(promiseOrFn, options) {
1876
+ const id = options.id ?? nextToastId();
1877
+ const { loading: _l, success: _s, error: _e, description: _d, finally: _f, ...rest } = options;
1878
+ const loadingEl = buildOrUpdate({
1879
+ ...rest,
1880
+ id,
1881
+ type: "loading",
1882
+ title: options.loading,
1883
+ duration: Infinity,
1884
+ dismissible: options.dismissible ?? false
1885
+ });
1886
+ const work = Promise.resolve(typeof promiseOrFn === "function" ? promiseOrFn() : promiseOrFn);
1887
+ let result = null;
1888
+ const settled = work.then(async (value) => {
1889
+ result = ["resolve", value];
1890
+ const title = await resolveContent(options.success, value);
1891
+ const desc = await resolveContent(options.description, value);
1892
+ if (title !== undefined) {
1893
+ loadingEl.update({
1894
+ ...rest,
1895
+ id,
1896
+ type: "success",
1897
+ title,
1898
+ description: desc,
1899
+ duration: options.duration,
1900
+ dismissible: options.dismissible ?? true
1901
+ });
1902
+ } else {
1903
+ loadingEl.dismiss();
1904
+ }
1905
+ }).catch(async (err) => {
1906
+ result = ["reject", err];
1907
+ const title = await resolveContent(options.error, err);
1908
+ const desc = await resolveContent(options.description, err);
1909
+ if (title !== undefined) {
1910
+ loadingEl.update({
1911
+ ...rest,
1912
+ id,
1913
+ type: "error",
1914
+ title,
1915
+ description: desc,
1916
+ duration: options.duration,
1917
+ dismissible: options.dismissible ?? true
1918
+ });
1919
+ } else {
1920
+ loadingEl.dismiss();
1921
+ }
1922
+ }).finally(() => options.finally?.());
1923
+ const unwrap = () => new Promise((resolve, reject) => {
1924
+ settled.then(() => {
1925
+ if (!result)
1926
+ return reject(new Error("promise toast settled without a result"));
1927
+ if (result[0] === "resolve")
1928
+ resolve(result[1]);
1929
+ else
1930
+ reject(result[1]);
1931
+ });
1932
+ });
1933
+ return Object.assign(loadingEl, { unwrap });
1934
+ }
1935
+ var toast = Object.assign(basic, {
1936
+ success: variant("success"),
1937
+ error: variant("error"),
1938
+ info: variant("info"),
1939
+ warning: variant("warning"),
1940
+ loading: (message, opts) => buildOrUpdate({
1941
+ ...opts,
1942
+ type: "loading",
1943
+ title: message,
1944
+ duration: opts?.duration ?? Infinity
1945
+ }),
1946
+ message: basic,
1947
+ promise,
1948
+ custom,
1949
+ dismiss,
1950
+ getToast
1951
+ });
1952
+ // src/index.ts
1953
+ if (typeof window !== "undefined")
1954
+ window.toast = toast;
1955
+ export {
1956
+ toast,
1957
+ SonnerToaster,
1958
+ SonnerToast
1959
+ };
1960
+
1961
+ //# debugId=038A38E1BC01A40B64756E2164756E21
1962
+ //# sourceMappingURL=sonner-wc.js.map