sonner 2.0.6 → 2.0.8

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/dist/index.d.mts CHANGED
@@ -47,6 +47,7 @@ interface Action {
47
47
  }
48
48
  interface ToastT {
49
49
  id: number | string;
50
+ toasterId?: string;
50
51
  title?: (() => React.ReactNode) | React.ReactNode;
51
52
  type?: ToastTypes;
52
53
  icon?: React.ReactNode;
@@ -71,6 +72,7 @@ interface ToastT {
71
72
  classNames?: ToastClassnames;
72
73
  descriptionClassName?: string;
73
74
  position?: Position;
75
+ testId?: string;
74
76
  }
75
77
  type Position = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'top-center' | 'bottom-center';
76
78
  interface ToastOptions {
@@ -84,6 +86,7 @@ interface ToastOptions {
84
86
  unstyled?: boolean;
85
87
  classNames?: ToastClassnames;
86
88
  closeButtonAriaLabel?: string;
89
+ toasterId?: string;
87
90
  }
88
91
  type Offset = {
89
92
  top?: string | number;
@@ -92,6 +95,7 @@ type Offset = {
92
95
  left?: string | number;
93
96
  } | string | number;
94
97
  interface ToasterProps {
98
+ id?: string;
95
99
  invert?: boolean;
96
100
  theme?: 'light' | 'dark' | 'system';
97
101
  position?: Position;
@@ -110,6 +114,7 @@ interface ToasterProps {
110
114
  dir?: 'rtl' | 'ltr' | 'auto';
111
115
  swipeDirections?: SwipeDirection[];
112
116
  icons?: ToastIcons;
117
+ customAriaLabel?: string;
113
118
  containerAriaLabel?: string;
114
119
  }
115
120
  type SwipeDirection = 'top' | 'right' | 'bottom' | 'left';
@@ -119,6 +124,7 @@ interface ToastToDismiss {
119
124
  }
120
125
  type ExternalToast = Omit<ToastT, 'id' | 'type' | 'title' | 'jsx' | 'delete' | 'promise'> & {
121
126
  id?: number | string;
127
+ toasterId?: string;
122
128
  };
123
129
 
124
130
  type titleT = (() => React.ReactNode) | React.ReactNode;
package/dist/index.d.ts CHANGED
@@ -47,6 +47,7 @@ interface Action {
47
47
  }
48
48
  interface ToastT {
49
49
  id: number | string;
50
+ toasterId?: string;
50
51
  title?: (() => React.ReactNode) | React.ReactNode;
51
52
  type?: ToastTypes;
52
53
  icon?: React.ReactNode;
@@ -71,6 +72,7 @@ interface ToastT {
71
72
  classNames?: ToastClassnames;
72
73
  descriptionClassName?: string;
73
74
  position?: Position;
75
+ testId?: string;
74
76
  }
75
77
  type Position = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'top-center' | 'bottom-center';
76
78
  interface ToastOptions {
@@ -84,6 +86,7 @@ interface ToastOptions {
84
86
  unstyled?: boolean;
85
87
  classNames?: ToastClassnames;
86
88
  closeButtonAriaLabel?: string;
89
+ toasterId?: string;
87
90
  }
88
91
  type Offset = {
89
92
  top?: string | number;
@@ -92,6 +95,7 @@ type Offset = {
92
95
  left?: string | number;
93
96
  } | string | number;
94
97
  interface ToasterProps {
98
+ id?: string;
95
99
  invert?: boolean;
96
100
  theme?: 'light' | 'dark' | 'system';
97
101
  position?: Position;
@@ -110,6 +114,7 @@ interface ToasterProps {
110
114
  dir?: 'rtl' | 'ltr' | 'auto';
111
115
  swipeDirections?: SwipeDirection[];
112
116
  icons?: ToastIcons;
117
+ customAriaLabel?: string;
113
118
  containerAriaLabel?: string;
114
119
  }
115
120
  type SwipeDirection = 'top' | 'right' | 'bottom' | 'left';
@@ -119,6 +124,7 @@ interface ToastToDismiss {
119
124
  }
120
125
  type ExternalToast = Omit<ToastT, 'id' | 'type' | 'title' | 'jsx' | 'delete' | 'promise'> & {
121
126
  id?: number | string;
127
+ toasterId?: string;
122
128
  };
123
129
 
124
130
  type titleT = (() => React.ReactNode) | React.ReactNode;
package/dist/index.js CHANGED
@@ -52,7 +52,8 @@ const SuccessIcon = /*#__PURE__*/ React__default.default.createElement("svg", {
52
52
  viewBox: "0 0 20 20",
53
53
  fill: "currentColor",
54
54
  height: "20",
55
- width: "20"
55
+ width: "20",
56
+ "aria-hidden": "true"
56
57
  }, /*#__PURE__*/ React__default.default.createElement("path", {
57
58
  fillRule: "evenodd",
58
59
  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",
@@ -63,7 +64,8 @@ const WarningIcon = /*#__PURE__*/ React__default.default.createElement("svg", {
63
64
  viewBox: "0 0 24 24",
64
65
  fill: "currentColor",
65
66
  height: "20",
66
- width: "20"
67
+ width: "20",
68
+ "aria-hidden": "true"
67
69
  }, /*#__PURE__*/ React__default.default.createElement("path", {
68
70
  fillRule: "evenodd",
69
71
  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",
@@ -74,7 +76,8 @@ const InfoIcon = /*#__PURE__*/ React__default.default.createElement("svg", {
74
76
  viewBox: "0 0 20 20",
75
77
  fill: "currentColor",
76
78
  height: "20",
77
- width: "20"
79
+ width: "20",
80
+ "aria-hidden": "true"
78
81
  }, /*#__PURE__*/ React__default.default.createElement("path", {
79
82
  fillRule: "evenodd",
80
83
  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",
@@ -85,7 +88,8 @@ const ErrorIcon = /*#__PURE__*/ React__default.default.createElement("svg", {
85
88
  viewBox: "0 0 20 20",
86
89
  fill: "currentColor",
87
90
  height: "20",
88
- width: "20"
91
+ width: "20",
92
+ "aria-hidden": "true"
89
93
  }, /*#__PURE__*/ React__default.default.createElement("path", {
90
94
  fillRule: "evenodd",
91
95
  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",
@@ -100,7 +104,8 @@ const CloseIcon = /*#__PURE__*/ React__default.default.createElement("svg", {
100
104
  stroke: "currentColor",
101
105
  strokeWidth: "1.5",
102
106
  strokeLinecap: "round",
103
- strokeLinejoin: "round"
107
+ strokeLinejoin: "round",
108
+ "aria-hidden": "true"
104
109
  }, /*#__PURE__*/ React__default.default.createElement("line", {
105
110
  x1: "18",
106
111
  y1: "6",
@@ -120,17 +125,30 @@ const useIsDocumentHidden = ()=>{
120
125
  setIsDocumentHidden(document.hidden);
121
126
  };
122
127
  document.addEventListener('visibilitychange', callback);
123
- return ()=>window.removeEventListener('visibilitychange', callback);
128
+ return ()=>document.removeEventListener('visibilitychange', callback);
124
129
  }, []);
125
130
  return isDocumentHidden;
126
131
  };
127
132
 
128
133
  let toastsCounter = 1;
134
+ // Amount of toasts kept in `toast.getHistory()`. Dismissed toasts above this limit are
135
+ // dropped so long-running apps don't hold on to them (and their JSX) forever.
136
+ const MAX_HISTORY_SIZE = 100;
137
+ // A toast keeps the id it was given, otherwise it gets the next one from the counter.
138
+ // `custom` needs the same id `create` would pick, as it hands it to the JSX callback.
139
+ const getToastId = (data)=>{
140
+ var _data_id;
141
+ return typeof (data == null ? void 0 : data.id) === 'number' || (data == null ? void 0 : (_data_id = data.id) == null ? void 0 : _data_id.length) > 0 ? data.id : toastsCounter++;
142
+ };
129
143
  class Observer {
130
144
  constructor(){
131
145
  // We use arrow functions to maintain the correct `this` reference
132
146
  this.subscribe = (subscriber)=>{
133
147
  this.subscribers.push(subscriber);
148
+ // A toast can be created before the `Toaster` had a chance to subscribe, e.g. when it's
149
+ // called in an effect of a component rendered above the `Toaster`. Replay whatever is
150
+ // still active so it doesn't get lost.
151
+ this.getActiveToasts().forEach((toast)=>subscriber(toast));
134
152
  return ()=>{
135
153
  const index = this.subscribers.indexOf(subscriber);
136
154
  this.subscribers.splice(index, 1);
@@ -145,18 +163,45 @@ class Observer {
145
163
  ...this.toasts,
146
164
  data
147
165
  ];
166
+ this.trimHistory();
167
+ };
168
+ // Keeps the history bounded without ever dropping a toast that's still on screen.
169
+ this.trimHistory = ()=>{
170
+ let toRemove = this.toasts.length - MAX_HISTORY_SIZE;
171
+ if (toRemove <= 0) return;
172
+ this.toasts = this.toasts.filter((toast)=>{
173
+ if (toRemove > 0 && this.dismissedToasts.has(toast.id)) {
174
+ this.dismissedToasts.delete(toast.id);
175
+ toRemove--;
176
+ return false;
177
+ }
178
+ return true;
179
+ });
148
180
  };
149
181
  this.create = (data)=>{
150
- var _data_id;
151
182
  const { message, ...rest } = data;
152
- const id = typeof (data == null ? void 0 : data.id) === 'number' || ((_data_id = data.id) == null ? void 0 : _data_id.length) > 0 ? data.id : toastsCounter++;
153
- const alreadyExists = this.toasts.find((toast)=>{
154
- return toast.id === id;
155
- });
183
+ const id = getToastId(data);
184
+ // A dismissal that hasn't reached the subscribers yet gets cancelled: the toast is still
185
+ // on screen, so this is an update of it rather than a new toast. Without this, creating a
186
+ // toast right after dismissing the same id (React's double effect in StrictMode does
187
+ // exactly that) would have the pending dismissal remove the toast that just got created.
188
+ const pendingDismissal = this.pendingDismissals.get(id);
189
+ if (pendingDismissal !== undefined) {
190
+ cancelAnimationFrame(pendingDismissal);
191
+ this.pendingDismissals.delete(id);
192
+ this.dismissedToasts.delete(id);
193
+ }
194
+ const wasDismissed = this.dismissedToasts.has(id);
156
195
  const dismissible = data.dismissible === undefined ? true : data.dismissible;
157
- if (this.dismissedToasts.has(id)) {
196
+ if (wasDismissed) {
158
197
  this.dismissedToasts.delete(id);
198
+ // The previous toast with this id is gone, so this is a brand new toast. Drop the old
199
+ // one instead of merging into it, otherwise its props (e.g. `action`) leak into the new one.
200
+ this.toasts = this.toasts.filter((toast)=>toast.id !== id);
159
201
  }
202
+ const alreadyExists = wasDismissed ? undefined : this.toasts.find((toast)=>{
203
+ return toast.id === id;
204
+ });
160
205
  if (alreadyExists) {
161
206
  this.toasts = this.toasts.map((toast)=>{
162
207
  if (toast.id === id) {
@@ -187,26 +232,37 @@ class Observer {
187
232
  return id;
188
233
  };
189
234
  this.dismiss = (id)=>{
190
- if (id) {
191
- this.dismissedToasts.add(id);
192
- requestAnimationFrame(()=>this.subscribers.forEach((subscriber)=>subscriber({
193
- id,
194
- dismiss: true
195
- })));
196
- } else {
197
- this.toasts.forEach((toast)=>{
235
+ if (id === undefined || id === null) {
236
+ this.getActiveToasts().forEach((toast)=>{
237
+ this.dismissedToasts.add(toast.id);
198
238
  this.subscribers.forEach((subscriber)=>subscriber({
199
239
  id: toast.id,
200
240
  dismiss: true
201
241
  }));
202
242
  });
243
+ return id;
203
244
  }
245
+ this.dismissedToasts.add(id);
246
+ const alreadyPending = this.pendingDismissals.get(id);
247
+ if (alreadyPending !== undefined) {
248
+ cancelAnimationFrame(alreadyPending);
249
+ }
250
+ this.pendingDismissals.set(id, requestAnimationFrame(()=>{
251
+ this.pendingDismissals.delete(id);
252
+ this.subscribers.forEach((subscriber)=>subscriber({
253
+ id,
254
+ dismiss: true
255
+ }));
256
+ }));
204
257
  return id;
205
258
  };
206
259
  this.message = (message, data)=>{
260
+ // `type: undefined` resets the type when this updates a toast that had one, e.g. turning
261
+ // a loading toast into a plain one.
207
262
  return this.create({
208
263
  ...data,
209
- message
264
+ message,
265
+ type: undefined
210
266
  });
211
267
  };
212
268
  this.error = (message, data)=>{
@@ -359,11 +415,13 @@ class Observer {
359
415
  }
360
416
  };
361
417
  this.custom = (jsx, data)=>{
362
- const id = (data == null ? void 0 : data.id) || toastsCounter++;
418
+ const id = getToastId(data);
419
+ // A custom toast has no type, so it resets the one of the toast it replaces
363
420
  this.create({
421
+ ...data,
364
422
  jsx: jsx(id),
365
423
  id,
366
- ...data
424
+ type: undefined
367
425
  });
368
426
  return id;
369
427
  };
@@ -373,18 +431,13 @@ class Observer {
373
431
  this.subscribers = [];
374
432
  this.toasts = [];
375
433
  this.dismissedToasts = new Set();
434
+ this.pendingDismissals = new Map();
376
435
  }
377
436
  }
378
437
  const ToastState = new Observer();
379
438
  // bind this to the toast function
380
439
  const toastFunction = (message, data)=>{
381
- const id = (data == null ? void 0 : data.id) || toastsCounter++;
382
- ToastState.addToast({
383
- title: message,
384
- ...data,
385
- id
386
- });
387
- return id;
440
+ return ToastState.message(message, data);
388
441
  };
389
442
  const isHttpResponse = (data)=>{
390
443
  return data && typeof data === 'object' && 'ok' in data && typeof data.ok === 'boolean' && 'status' in data && typeof data.status === 'number';
@@ -408,7 +461,7 @@ const toast = Object.assign(basicToast, {
408
461
  getToasts
409
462
  });
410
463
 
411
- __insertCSS("[data-sonner-toaster][dir=ltr],html[dir=ltr]{--toast-icon-margin-start:-3px;--toast-icon-margin-end:4px;--toast-svg-margin-start:-1px;--toast-svg-margin-end:0px;--toast-button-margin-start:auto;--toast-button-margin-end:0;--toast-close-button-start:0;--toast-close-button-end:unset;--toast-close-button-transform:translate(-35%, -35%)}[data-sonner-toaster][dir=rtl],html[dir=rtl]{--toast-icon-margin-start:4px;--toast-icon-margin-end:-3px;--toast-svg-margin-start:0px;--toast-svg-margin-end:-1px;--toast-button-margin-start:0;--toast-button-margin-end:auto;--toast-close-button-start:unset;--toast-close-button-end:0;--toast-close-button-transform:translate(35%, -35%)}[data-sonner-toaster]{position:fixed;width:var(--width);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;--gray1:hsl(0, 0%, 99%);--gray2:hsl(0, 0%, 97.3%);--gray3:hsl(0, 0%, 95.1%);--gray4:hsl(0, 0%, 93%);--gray5:hsl(0, 0%, 90.9%);--gray6:hsl(0, 0%, 88.7%);--gray7:hsl(0, 0%, 85.8%);--gray8:hsl(0, 0%, 78%);--gray9:hsl(0, 0%, 56.1%);--gray10:hsl(0, 0%, 52.3%);--gray11:hsl(0, 0%, 43.5%);--gray12:hsl(0, 0%, 9%);--border-radius:8px;box-sizing:border-box;padding:0;margin:0;list-style:none;outline:0;z-index:999999999;transition:transform .4s ease}@media (hover:none) and (pointer:coarse){[data-sonner-toaster][data-lifted=true]{transform:none}}[data-sonner-toaster][data-x-position=right]{right:var(--offset-right)}[data-sonner-toaster][data-x-position=left]{left:var(--offset-left)}[data-sonner-toaster][data-x-position=center]{left:50%;transform:translateX(-50%)}[data-sonner-toaster][data-y-position=top]{top:var(--offset-top)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--offset-bottom)}[data-sonner-toast]{--y:translateY(100%);--lift-amount:calc(var(--lift) * var(--gap));z-index:var(--z-index);position:absolute;opacity:0;transform:var(--y);touch-action:none;transition:transform .4s,opacity .4s,height .4s,box-shadow .2s;box-sizing:border-box;outline:0;overflow-wrap:anywhere}[data-sonner-toast][data-styled=true]{padding:16px;background:var(--normal-bg);border:1px solid var(--normal-border);color:var(--normal-text);border-radius:var(--border-radius);box-shadow:0 4px 12px rgba(0,0,0,.1);width:var(--width);font-size:13px;display:flex;align-items:center;gap:6px}[data-sonner-toast]:focus-visible{box-shadow:0 4px 12px rgba(0,0,0,.1),0 0 0 2px rgba(0,0,0,.2)}[data-sonner-toast][data-y-position=top]{top:0;--y:translateY(-100%);--lift:1;--lift-amount:calc(1 * var(--gap))}[data-sonner-toast][data-y-position=bottom]{bottom:0;--y:translateY(100%);--lift:-1;--lift-amount:calc(var(--lift) * var(--gap))}[data-sonner-toast][data-styled=true] [data-description]{font-weight:400;line-height:1.4;color:#3f3f3f}[data-rich-colors=true][data-sonner-toast][data-styled=true] [data-description]{color:inherit}[data-sonner-toaster][data-sonner-theme=dark] [data-description]{color:#e8e8e8}[data-sonner-toast][data-styled=true] [data-title]{font-weight:500;line-height:1.5;color:inherit}[data-sonner-toast][data-styled=true] [data-icon]{display:flex;height:16px;width:16px;position:relative;justify-content:flex-start;align-items:center;flex-shrink:0;margin-left:var(--toast-icon-margin-start);margin-right:var(--toast-icon-margin-end)}[data-sonner-toast][data-promise=true] [data-icon]>svg{opacity:0;transform:scale(.8);transform-origin:center;animation:sonner-fade-in .3s ease forwards}[data-sonner-toast][data-styled=true] [data-icon]>*{flex-shrink:0}[data-sonner-toast][data-styled=true] [data-icon] svg{margin-left:var(--toast-svg-margin-start);margin-right:var(--toast-svg-margin-end)}[data-sonner-toast][data-styled=true] [data-content]{display:flex;flex-direction:column;gap:2px}[data-sonner-toast][data-styled=true] [data-button]{border-radius:4px;padding-left:8px;padding-right:8px;height:24px;font-size:12px;color:var(--normal-bg);background:var(--normal-text);margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end);border:none;font-weight:500;cursor:pointer;outline:0;display:flex;align-items:center;flex-shrink:0;transition:opacity .4s,box-shadow .2s}[data-sonner-toast][data-styled=true] [data-button]:focus-visible{box-shadow:0 0 0 2px rgba(0,0,0,.4)}[data-sonner-toast][data-styled=true] [data-button]:first-of-type{margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end)}[data-sonner-toast][data-styled=true] [data-cancel]{color:var(--normal-text);background:rgba(0,0,0,.08)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-styled=true] [data-cancel]{background:rgba(255,255,255,.3)}[data-sonner-toast][data-styled=true] [data-close-button]{position:absolute;left:var(--toast-close-button-start);right:var(--toast-close-button-end);top:0;height:20px;width:20px;display:flex;justify-content:center;align-items:center;padding:0;color:var(--gray12);background:var(--normal-bg);border:1px solid var(--gray4);transform:var(--toast-close-button-transform);border-radius:50%;cursor:pointer;z-index:1;transition:opacity .1s,background .2s,border-color .2s}[data-sonner-toast][data-styled=true] [data-close-button]:focus-visible{box-shadow:0 4px 12px rgba(0,0,0,.1),0 0 0 2px rgba(0,0,0,.2)}[data-sonner-toast][data-styled=true] [data-disabled=true]{cursor:not-allowed}[data-sonner-toast][data-styled=true]:hover [data-close-button]:hover{background:var(--gray2);border-color:var(--gray5)}[data-sonner-toast][data-swiping=true]::before{content:'';position:absolute;left:-100%;right:-100%;height:100%;z-index:-1}[data-sonner-toast][data-y-position=top][data-swiping=true]::before{bottom:50%;transform:scaleY(3) translateY(50%)}[data-sonner-toast][data-y-position=bottom][data-swiping=true]::before{top:50%;transform:scaleY(3) translateY(-50%)}[data-sonner-toast][data-swiping=false][data-removed=true]::before{content:'';position:absolute;inset:0;transform:scaleY(2)}[data-sonner-toast][data-expanded=true]::after{content:'';position:absolute;left:0;height:calc(var(--gap) + 1px);bottom:100%;width:100%}[data-sonner-toast][data-mounted=true]{--y:translateY(0);opacity:1}[data-sonner-toast][data-expanded=false][data-front=false]{--scale:var(--toasts-before) * 0.05 + 1;--y:translateY(calc(var(--lift-amount) * var(--toasts-before))) scale(calc(-1 * var(--scale)));height:var(--front-toast-height)}[data-sonner-toast]>*{transition:opacity .4s}[data-sonner-toast][data-x-position=right]{right:0}[data-sonner-toast][data-x-position=left]{left:0}[data-sonner-toast][data-expanded=false][data-front=false][data-styled=true]>*{opacity:0}[data-sonner-toast][data-visible=false]{opacity:0;pointer-events:none}[data-sonner-toast][data-mounted=true][data-expanded=true]{--y:translateY(calc(var(--lift) * var(--offset)));height:var(--initial-height)}[data-sonner-toast][data-removed=true][data-front=true][data-swipe-out=false]{--y:translateY(calc(var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=true]{--y:translateY(calc(var(--lift) * var(--offset) + var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=false]{--y:translateY(40%);opacity:0;transition:transform .5s,opacity .2s}[data-sonner-toast][data-removed=true][data-front=false]::before{height:calc(var(--initial-height) + 20%)}[data-sonner-toast][data-swiping=true]{transform:var(--y) translateY(var(--swipe-amount-y,0)) translateX(var(--swipe-amount-x,0));transition:none}[data-sonner-toast][data-swiped=true]{user-select:none}[data-sonner-toast][data-swipe-out=true][data-y-position=bottom],[data-sonner-toast][data-swipe-out=true][data-y-position=top]{animation-duration:.2s;animation-timing-function:ease-out;animation-fill-mode:forwards}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=left]{animation-name:swipe-out-left}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=right]{animation-name:swipe-out-right}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=up]{animation-name:swipe-out-up}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=down]{animation-name:swipe-out-down}@keyframes swipe-out-left{from{transform:var(--y) translateX(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translateX(calc(var(--swipe-amount-x) - 100%));opacity:0}}@keyframes swipe-out-right{from{transform:var(--y) translateX(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translateX(calc(var(--swipe-amount-x) + 100%));opacity:0}}@keyframes swipe-out-up{from{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) - 100%));opacity:0}}@keyframes swipe-out-down{from{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) + 100%));opacity:0}}@media (max-width:600px){[data-sonner-toaster]{position:fixed;right:var(--mobile-offset-right);left:var(--mobile-offset-left);width:100%}[data-sonner-toaster][dir=rtl]{left:calc(var(--mobile-offset-left) * -1)}[data-sonner-toaster] [data-sonner-toast]{left:0;right:0;width:calc(100% - var(--mobile-offset-left) * 2)}[data-sonner-toaster][data-x-position=left]{left:var(--mobile-offset-left)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--mobile-offset-bottom)}[data-sonner-toaster][data-y-position=top]{top:var(--mobile-offset-top)}[data-sonner-toaster][data-x-position=center]{left:var(--mobile-offset-left);right:var(--mobile-offset-right);transform:none}}[data-sonner-toaster][data-sonner-theme=light]{--normal-bg:#fff;--normal-border:var(--gray4);--normal-text:var(--gray12);--success-bg:hsl(143, 85%, 96%);--success-border:hsl(145, 92%, 87%);--success-text:hsl(140, 100%, 27%);--info-bg:hsl(208, 100%, 97%);--info-border:hsl(221, 91%, 93%);--info-text:hsl(210, 92%, 45%);--warning-bg:hsl(49, 100%, 97%);--warning-border:hsl(49, 91%, 84%);--warning-text:hsl(31, 92%, 45%);--error-bg:hsl(359, 100%, 97%);--error-border:hsl(359, 100%, 94%);--error-text:hsl(360, 100%, 45%)}[data-sonner-toaster][data-sonner-theme=light] [data-sonner-toast][data-invert=true]{--normal-bg:#000;--normal-border:hsl(0, 0%, 20%);--normal-text:var(--gray1)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-invert=true]{--normal-bg:#fff;--normal-border:var(--gray3);--normal-text:var(--gray12)}[data-sonner-toaster][data-sonner-theme=dark]{--normal-bg:#000;--normal-bg-hover:hsl(0, 0%, 12%);--normal-border:hsl(0, 0%, 20%);--normal-border-hover:hsl(0, 0%, 25%);--normal-text:var(--gray1);--success-bg:hsl(150, 100%, 6%);--success-border:hsl(147, 100%, 12%);--success-text:hsl(150, 86%, 65%);--info-bg:hsl(215, 100%, 6%);--info-border:hsl(223, 43%, 17%);--info-text:hsl(216, 87%, 65%);--warning-bg:hsl(64, 100%, 6%);--warning-border:hsl(60, 100%, 9%);--warning-text:hsl(46, 87%, 65%);--error-bg:hsl(358, 76%, 10%);--error-border:hsl(357, 89%, 16%);--error-text:hsl(358, 100%, 81%)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]{background:var(--normal-bg);border-color:var(--normal-border);color:var(--normal-text)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]:hover{background:var(--normal-bg-hover);border-color:var(--normal-border-hover)}[data-rich-colors=true][data-sonner-toast][data-type=success]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=success] [data-close-button]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=info]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=info] [data-close-button]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning] [data-close-button]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=error]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}[data-rich-colors=true][data-sonner-toast][data-type=error] [data-close-button]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}.sonner-loading-wrapper{--size:16px;height:var(--size);width:var(--size);position:absolute;inset:0;z-index:10}.sonner-loading-wrapper[data-visible=false]{transform-origin:center;animation:sonner-fade-out .2s ease forwards}.sonner-spinner{position:relative;top:50%;left:50%;height:var(--size);width:var(--size)}.sonner-loading-bar{animation:sonner-spin 1.2s linear infinite;background:var(--gray11);border-radius:6px;height:8%;left:-10%;position:absolute;top:-3.9%;width:24%}.sonner-loading-bar:first-child{animation-delay:-1.2s;transform:rotate(.0001deg) translate(146%)}.sonner-loading-bar:nth-child(2){animation-delay:-1.1s;transform:rotate(30deg) translate(146%)}.sonner-loading-bar:nth-child(3){animation-delay:-1s;transform:rotate(60deg) translate(146%)}.sonner-loading-bar:nth-child(4){animation-delay:-.9s;transform:rotate(90deg) translate(146%)}.sonner-loading-bar:nth-child(5){animation-delay:-.8s;transform:rotate(120deg) translate(146%)}.sonner-loading-bar:nth-child(6){animation-delay:-.7s;transform:rotate(150deg) translate(146%)}.sonner-loading-bar:nth-child(7){animation-delay:-.6s;transform:rotate(180deg) translate(146%)}.sonner-loading-bar:nth-child(8){animation-delay:-.5s;transform:rotate(210deg) translate(146%)}.sonner-loading-bar:nth-child(9){animation-delay:-.4s;transform:rotate(240deg) translate(146%)}.sonner-loading-bar:nth-child(10){animation-delay:-.3s;transform:rotate(270deg) translate(146%)}.sonner-loading-bar:nth-child(11){animation-delay:-.2s;transform:rotate(300deg) translate(146%)}.sonner-loading-bar:nth-child(12){animation-delay:-.1s;transform:rotate(330deg) translate(146%)}@keyframes sonner-fade-in{0%{opacity:0;transform:scale(.8)}100%{opacity:1;transform:scale(1)}}@keyframes sonner-fade-out{0%{opacity:1;transform:scale(1)}100%{opacity:0;transform:scale(.8)}}@keyframes sonner-spin{0%{opacity:1}100%{opacity:.15}}@media (prefers-reduced-motion){.sonner-loading-bar,[data-sonner-toast],[data-sonner-toast]>*{transition:none!important;animation:none!important}}.sonner-loader{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);transform-origin:center;transition:opacity .2s,transform .2s}.sonner-loader[data-visible=false]{opacity:0;transform:scale(.8) translate(-50%,-50%)}");
464
+ __insertCSS("[data-sonner-toaster][dir=ltr],html[dir=ltr]{--toast-icon-margin-start:-3px;--toast-icon-margin-end:4px;--toast-svg-margin-start:-1px;--toast-svg-margin-end:0px;--toast-button-margin-start:auto;--toast-button-margin-end:0;--toast-close-button-start:0;--toast-close-button-end:unset;--toast-close-button-transform:translate(-35%, -35%)}[data-sonner-toaster][dir=rtl],html[dir=rtl]{--toast-icon-margin-start:4px;--toast-icon-margin-end:-3px;--toast-svg-margin-start:0px;--toast-svg-margin-end:-1px;--toast-button-margin-start:0;--toast-button-margin-end:auto;--toast-close-button-start:unset;--toast-close-button-end:0;--toast-close-button-transform:translate(35%, -35%)}[data-sonner-toaster]{position:fixed;width:var(--width);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;--gray1:hsl(0, 0%, 99%);--gray2:hsl(0, 0%, 97.3%);--gray3:hsl(0, 0%, 95.1%);--gray4:hsl(0, 0%, 93%);--gray5:hsl(0, 0%, 90.9%);--gray6:hsl(0, 0%, 88.7%);--gray7:hsl(0, 0%, 85.8%);--gray8:hsl(0, 0%, 78%);--gray9:hsl(0, 0%, 56.1%);--gray10:hsl(0, 0%, 52.3%);--gray11:hsl(0, 0%, 43.5%);--gray12:hsl(0, 0%, 9%);--border-radius:8px;box-sizing:border-box;padding:0;margin:0;list-style:none;outline:0;z-index:999999999;transition:transform .4s ease}@media (hover:none) and (pointer:coarse){[data-sonner-toaster][data-lifted=true]{transform:none}}[data-sonner-toaster][data-x-position=right]{right:var(--offset-right)}[data-sonner-toaster][data-x-position=left]{left:var(--offset-left)}[data-sonner-toaster][data-x-position=center]{left:50%;transform:translateX(-50%)}[data-sonner-toaster][data-y-position=top]{top:var(--offset-top)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--offset-bottom)}[data-sonner-toast]{--y:translateY(100%);--lift-amount:calc(var(--lift) * var(--gap));z-index:var(--z-index);position:absolute;opacity:0;transform:var(--y);touch-action:none;transition:transform .4s,opacity .4s,height .4s,box-shadow .2s;box-sizing:border-box;outline:0;overflow-wrap:anywhere}[data-sonner-toast][data-styled=true]{padding:16px;background:var(--normal-bg);border:1px solid var(--normal-border);color:var(--normal-text);border-radius:var(--border-radius);box-shadow:0 4px 12px rgba(0,0,0,.1);width:var(--width);font-size:13px;display:flex;align-items:center;gap:6px}[data-sonner-toast]:focus-visible{box-shadow:0 4px 12px rgba(0,0,0,.1),0 0 0 2px rgba(0,0,0,.2)}[data-sonner-toast][data-y-position=top]{top:0;--y:translateY(-100%);--lift:1;--lift-amount:calc(1 * var(--gap))}[data-sonner-toast][data-y-position=bottom]{bottom:0;--y:translateY(100%);--lift:-1;--lift-amount:calc(var(--lift) * var(--gap))}[data-sonner-toast][data-styled=true] [data-description]{font-weight:400;line-height:1.4;color:#3f3f3f}[data-rich-colors=true][data-sonner-toast][data-styled=true] [data-description]{color:inherit}[data-sonner-toaster][data-sonner-theme=dark] [data-description]{color:#e8e8e8}[data-sonner-toast][data-styled=true] [data-title]{font-weight:500;line-height:1.5;color:inherit}[data-sonner-toast][data-styled=true] [data-icon]{display:flex;height:16px;width:16px;position:relative;justify-content:flex-start;align-items:center;flex-shrink:0;margin-left:var(--toast-icon-margin-start);margin-right:var(--toast-icon-margin-end)}[data-sonner-toast][data-promise=true] [data-icon]>svg{opacity:0;transform:scale(.8);transform-origin:center;animation:sonner-fade-in .3s ease forwards}[data-sonner-toast][data-styled=true] [data-icon]>*{flex-shrink:0}[data-sonner-toast][data-styled=true] [data-icon] svg{margin-left:var(--toast-svg-margin-start);margin-right:var(--toast-svg-margin-end)}[data-sonner-toast][data-styled=true] [data-content]{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}[data-sonner-toast][data-styled=true] [data-button]{border-radius:4px;padding-left:8px;padding-right:8px;height:24px;font-size:12px;color:var(--normal-bg);background:var(--normal-text);margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end);border:none;font-weight:500;cursor:pointer;outline:0;display:flex;align-items:center;flex-shrink:0;transition:opacity .4s,box-shadow .2s}[data-sonner-toast][data-styled=true] [data-button]:focus-visible{box-shadow:0 0 0 2px rgba(0,0,0,.4)}[data-sonner-toast][data-styled=true] [data-button]:first-of-type{margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end)}[data-sonner-toast][data-styled=true] [data-cancel]{color:var(--normal-text);background:rgba(0,0,0,.08)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-styled=true] [data-cancel]{background:rgba(255,255,255,.3)}[data-sonner-toast][data-styled=true] [data-close-button]{position:absolute;left:var(--toast-close-button-start);right:var(--toast-close-button-end);top:0;height:20px;width:20px;display:flex;justify-content:center;align-items:center;padding:0;color:var(--normal-text);background:var(--normal-bg);border:1px solid var(--normal-border);transform:var(--toast-close-button-transform);border-radius:50%;cursor:pointer;z-index:1;transition:opacity .1s,background .2s,border-color .2s}[data-sonner-toast][data-styled=true] [data-close-button]:focus-visible{box-shadow:0 4px 12px rgba(0,0,0,.1),0 0 0 2px rgba(0,0,0,.2)}[data-sonner-toast][data-styled=true] [data-disabled=true]{cursor:not-allowed}[data-sonner-toast][data-styled=true]:hover [data-close-button]:hover{background:var(--gray2);border-color:var(--gray5)}[data-sonner-toast][data-swiping=true]::before{content:'';position:absolute;left:-100%;right:-100%;height:100%;z-index:-1}[data-sonner-toast][data-y-position=top][data-swiping=true]::before{bottom:50%;transform:scaleY(3) translateY(50%)}[data-sonner-toast][data-y-position=bottom][data-swiping=true]::before{top:50%;transform:scaleY(3) translateY(-50%)}[data-sonner-toast][data-swiping=false][data-removed=true]::before{content:'';position:absolute;inset:0;transform:scaleY(2)}[data-sonner-toast][data-expanded=true]::after{content:'';position:absolute;left:0;height:calc(var(--gap) + 1px);bottom:100%;width:100%}[data-sonner-toast][data-mounted=true]{--y:translateY(0);opacity:1}[data-sonner-toast][data-expanded=false][data-front=false]{--scale:var(--toasts-before) * 0.05 + 1;--y:translateY(calc(var(--lift-amount) * var(--toasts-before))) scale(calc(-1 * var(--scale)));height:var(--front-toast-height)}[data-sonner-toast]>*{transition:opacity .4s}[data-sonner-toast][data-x-position=right]{right:0}[data-sonner-toast][data-x-position=left]{left:0}[data-sonner-toast][data-expanded=false][data-front=false][data-styled=true]>*{opacity:0}[data-sonner-toast][data-visible=false]{opacity:0;pointer-events:none}[data-sonner-toast][data-mounted=true][data-expanded=true]{--y:translateY(calc(var(--lift) * var(--offset)));height:var(--initial-height)}[data-sonner-toast][data-removed=true][data-front=true][data-swipe-out=false]{--y:translateY(calc(var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=true]{--y:translateY(calc(var(--lift) * var(--offset) + var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=false]{--y:translateY(40%);opacity:0;transition:transform .5s,opacity .2s}[data-sonner-toast][data-removed=true][data-front=false]::before{height:calc(var(--initial-height) + 20%)}[data-sonner-toast][data-swiping=true]{transform:var(--y) translateY(var(--swipe-amount-y,0)) translateX(var(--swipe-amount-x,0));transition:none}[data-sonner-toast][data-swiped=true]{-webkit-user-select:none;user-select:none}[data-sonner-toast][data-swipe-out=true][data-y-position=bottom],[data-sonner-toast][data-swipe-out=true][data-y-position=top]{animation-duration:.2s;animation-timing-function:ease-out;animation-fill-mode:forwards}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=left]{animation-name:swipe-out-left}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=right]{animation-name:swipe-out-right}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=up]{animation-name:swipe-out-up}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=down]{animation-name:swipe-out-down}@keyframes swipe-out-left{from{transform:var(--y) translateX(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translateX(calc(var(--swipe-amount-x) - 100%));opacity:0}}@keyframes swipe-out-right{from{transform:var(--y) translateX(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translateX(calc(var(--swipe-amount-x) + 100%));opacity:0}}@keyframes swipe-out-up{from{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) - 100%));opacity:0}}@keyframes swipe-out-down{from{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) + 100%));opacity:0}}@media (max-width:600px){[data-sonner-toaster]{position:fixed;right:var(--mobile-offset-right);left:var(--mobile-offset-left);width:100%}[data-sonner-toaster][dir=rtl]{left:calc(var(--mobile-offset-left) * -1)}[data-sonner-toaster] [data-sonner-toast]{left:0;right:0;width:calc(100% - var(--mobile-offset-left) * 2)}[data-sonner-toaster][data-x-position=left]{left:var(--mobile-offset-left)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--mobile-offset-bottom)}[data-sonner-toaster][data-y-position=top]{top:var(--mobile-offset-top)}[data-sonner-toaster][data-x-position=center]{left:var(--mobile-offset-left);right:var(--mobile-offset-right);transform:none}}[data-sonner-toaster][data-sonner-theme=light]{--normal-bg:#fff;--normal-border:var(--gray4);--normal-text:var(--gray12);--success-bg:hsl(143, 85%, 96%);--success-border:hsl(145, 92%, 87%);--success-text:hsl(140, 100%, 27%);--info-bg:hsl(208, 100%, 97%);--info-border:hsl(221, 91%, 93%);--info-text:hsl(210, 92%, 45%);--warning-bg:hsl(49, 100%, 97%);--warning-border:hsl(49, 91%, 84%);--warning-text:hsl(31, 92%, 45%);--error-bg:hsl(359, 100%, 97%);--error-border:hsl(359, 100%, 94%);--error-text:hsl(360, 100%, 45%)}[data-sonner-toaster][data-sonner-theme=light] [data-sonner-toast][data-invert=true]{--normal-bg:#000;--normal-border:hsl(0, 0%, 20%);--normal-text:var(--gray1)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-invert=true]{--normal-bg:#fff;--normal-border:var(--gray3);--normal-text:var(--gray12)}[data-sonner-toaster][data-sonner-theme=dark]{--normal-bg:#000;--normal-bg-hover:hsl(0, 0%, 12%);--normal-border:hsl(0, 0%, 20%);--normal-border-hover:hsl(0, 0%, 25%);--normal-text:var(--gray1);--success-bg:hsl(150, 100%, 6%);--success-border:hsl(147, 100%, 12%);--success-text:hsl(150, 86%, 65%);--info-bg:hsl(215, 100%, 6%);--info-border:hsl(223, 43%, 17%);--info-text:hsl(216, 87%, 65%);--warning-bg:hsl(64, 100%, 6%);--warning-border:hsl(60, 100%, 9%);--warning-text:hsl(46, 87%, 65%);--error-bg:hsl(358, 76%, 10%);--error-border:hsl(357, 89%, 16%);--error-text:hsl(358, 100%, 81%)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]{background:var(--normal-bg);border-color:var(--normal-border);color:var(--normal-text)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]:hover{background:var(--normal-bg-hover);border-color:var(--normal-border-hover)}[data-rich-colors=true][data-sonner-toast][data-type=success]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=success] [data-close-button]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=info]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=info] [data-close-button]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning] [data-close-button]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=error]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}[data-rich-colors=true][data-sonner-toast][data-type=error] [data-close-button]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}.sonner-loading-wrapper{--size:16px;height:var(--size);width:var(--size);position:absolute;inset:0;z-index:10}.sonner-loading-wrapper[data-visible=false]{transform-origin:center;animation:sonner-fade-out .2s ease forwards}.sonner-spinner{position:relative;top:50%;left:50%;height:var(--size);width:var(--size)}.sonner-loading-bar{animation:sonner-spin 1.2s linear infinite;background:var(--gray11);border-radius:6px;height:8%;left:-10%;position:absolute;top:-3.9%;width:24%}.sonner-loading-bar:first-child{animation-delay:-1.2s;transform:rotate(.0001deg) translate(146%)}.sonner-loading-bar:nth-child(2){animation-delay:-1.1s;transform:rotate(30deg) translate(146%)}.sonner-loading-bar:nth-child(3){animation-delay:-1s;transform:rotate(60deg) translate(146%)}.sonner-loading-bar:nth-child(4){animation-delay:-.9s;transform:rotate(90deg) translate(146%)}.sonner-loading-bar:nth-child(5){animation-delay:-.8s;transform:rotate(120deg) translate(146%)}.sonner-loading-bar:nth-child(6){animation-delay:-.7s;transform:rotate(150deg) translate(146%)}.sonner-loading-bar:nth-child(7){animation-delay:-.6s;transform:rotate(180deg) translate(146%)}.sonner-loading-bar:nth-child(8){animation-delay:-.5s;transform:rotate(210deg) translate(146%)}.sonner-loading-bar:nth-child(9){animation-delay:-.4s;transform:rotate(240deg) translate(146%)}.sonner-loading-bar:nth-child(10){animation-delay:-.3s;transform:rotate(270deg) translate(146%)}.sonner-loading-bar:nth-child(11){animation-delay:-.2s;transform:rotate(300deg) translate(146%)}.sonner-loading-bar:nth-child(12){animation-delay:-.1s;transform:rotate(330deg) translate(146%)}@keyframes sonner-fade-in{0%{opacity:0;transform:scale(.8)}100%{opacity:1;transform:scale(1)}}@keyframes sonner-fade-out{0%{opacity:1;transform:scale(1)}100%{opacity:0;transform:scale(.8)}}@keyframes sonner-spin{0%{opacity:1}100%{opacity:.15}}@media (prefers-reduced-motion){.sonner-loading-bar,[data-sonner-toast],[data-sonner-toast]>*{transition:none!important;animation:none!important}}.sonner-loader{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);transform-origin:center;transition:opacity .2s,transform .2s}.sonner-loader[data-visible=false]{opacity:0;transform:scale(.8) translate(-50%,-50%)}");
412
465
 
413
466
  function isAction(action) {
414
467
  return action.label !== undefined;
@@ -462,6 +515,8 @@ const Toast = (props)=>{
462
515
  const isFront = index === 0;
463
516
  const isVisible = index + 1 <= visibleToasts;
464
517
  const toastType = toast.type;
518
+ // Toasts created with `toast()` have no type, `classNames.default` is the key for those.
519
+ const toastTypeKey = toastType != null ? toastType : 'default';
465
520
  const dismissible = toast.dismissible !== false;
466
521
  const toastClassname = toast.className || '';
467
522
  const toastDescriptionClassname = toast.descriptionClassName || '';
@@ -499,6 +554,13 @@ const Toast = (props)=>{
499
554
  heightIndex
500
555
  ]);
501
556
  const isDocumentHidden = useIsDocumentHidden();
557
+ const swipeDirections = React__default.default.useMemo(()=>{
558
+ var _props_swipeDirections;
559
+ return (_props_swipeDirections = props.swipeDirections) != null ? _props_swipeDirections : getDefaultSwipeDirections(position);
560
+ }, [
561
+ props.swipeDirections,
562
+ position
563
+ ]);
502
564
  const invert = toast.invert || ToasterInvert;
503
565
  const disabled = toastType === 'loading';
504
566
  offset.current = React__default.default.useMemo(()=>heightIndex * gap + toastsHeightBefore, [
@@ -651,7 +713,7 @@ const Toast = (props)=>{
651
713
  return /*#__PURE__*/ React__default.default.createElement("li", {
652
714
  tabIndex: 0,
653
715
  ref: toastRef,
654
- className: cn(className, toastClassname, classNames == null ? void 0 : classNames.toast, toast == null ? void 0 : (_toast_classNames = toast.classNames) == null ? void 0 : _toast_classNames.toast, classNames == null ? void 0 : classNames.default, classNames == null ? void 0 : classNames[toastType], toast == null ? void 0 : (_toast_classNames1 = toast.classNames) == null ? void 0 : _toast_classNames1[toastType]),
716
+ className: cn(className, toastClassname, classNames == null ? void 0 : classNames.toast, toast == null ? void 0 : (_toast_classNames = toast.classNames) == null ? void 0 : _toast_classNames.toast, classNames == null ? void 0 : classNames[toastTypeKey], toast == null ? void 0 : (_toast_classNames1 = toast.classNames) == null ? void 0 : _toast_classNames1[toastTypeKey]),
655
717
  "data-sonner-toast": "",
656
718
  "data-rich-colors": (_toast_richColors = toast.richColors) != null ? _toast_richColors : defaultRichColors,
657
719
  "data-styled": !Boolean(toast.jsx || toast.unstyled || unstyled),
@@ -671,6 +733,7 @@ const Toast = (props)=>{
671
733
  "data-swipe-out": swipeOut,
672
734
  "data-swipe-direction": swipeOutDirection,
673
735
  "data-expanded": Boolean(expanded || expandByDefault && mounted),
736
+ "data-testid": toast.testId,
674
737
  style: {
675
738
  '--index': index,
676
739
  '--toasts-before': index,
@@ -708,7 +771,10 @@ const Toast = (props)=>{
708
771
  const timeTaken = new Date().getTime() - ((_dragStartTime_current = dragStartTime.current) == null ? void 0 : _dragStartTime_current.getTime());
709
772
  const swipeAmount = swipeDirection === 'x' ? swipeAmountX : swipeAmountY;
710
773
  const velocity = Math.abs(swipeAmount) / timeTaken;
711
- if (Math.abs(swipeAmount) >= SWIPE_THRESHOLD || velocity > 0.11) {
774
+ // Movement towards a direction that isn't allowed is dampened, not blocked, so a fast
775
+ // flick can still pass the velocity check. Only dismiss if the direction is allowed.
776
+ const isAllowedDirection = swipeDirection === 'x' ? swipeDirections.includes(swipeAmountX > 0 ? 'right' : 'left') : swipeDirections.includes(swipeAmountY > 0 ? 'bottom' : 'top');
777
+ if (isAllowedDirection && (Math.abs(swipeAmount) >= SWIPE_THRESHOLD || velocity > 0.11)) {
712
778
  setOffsetBeforeRemove(offset.current);
713
779
  toast.onDismiss == null ? void 0 : toast.onDismiss.call(toast, toast);
714
780
  if (swipeDirection === 'x') {
@@ -736,8 +802,6 @@ const Toast = (props)=>{
736
802
  if (isHighlighted) return;
737
803
  const yDelta = event.clientY - pointerStartRef.current.y;
738
804
  const xDelta = event.clientX - pointerStartRef.current.x;
739
- var _props_swipeDirections;
740
- const swipeDirections = (_props_swipeDirections = props.swipeDirections) != null ? _props_swipeDirections : getDefaultSwipeDirections(position);
741
805
  // Determine swipe direction if not already locked
742
806
  if (!swipeDirection && (Math.abs(xDelta) > 1 || Math.abs(yDelta) > 1)) {
743
807
  setSwipeDirection(Math.abs(xDelta) > Math.abs(yDelta) ? 'x' : 'y');
@@ -794,7 +858,7 @@ const Toast = (props)=>{
794
858
  }, (_icons_close = icons == null ? void 0 : icons.close) != null ? _icons_close : CloseIcon) : null, (toastType || toast.icon || toast.promise) && toast.icon !== null && ((icons == null ? void 0 : icons[toastType]) !== null || toast.icon) ? /*#__PURE__*/ React__default.default.createElement("div", {
795
859
  "data-icon": "",
796
860
  className: cn(classNames == null ? void 0 : classNames.icon, toast == null ? void 0 : (_toast_classNames3 = toast.classNames) == null ? void 0 : _toast_classNames3.icon)
797
- }, toast.promise || toast.type === 'loading' && !toast.icon ? toast.icon || getLoadingIcon() : null, toast.type !== 'loading' ? icon : null) : null, /*#__PURE__*/ React__default.default.createElement("div", {
861
+ }, toastType === 'loading' ? toast.icon || getLoadingIcon() : toast.promise ? getLoadingIcon() : null, toastType !== 'loading' ? icon : null) : null, /*#__PURE__*/ React__default.default.createElement("div", {
798
862
  "data-content": "",
799
863
  className: cn(classNames == null ? void 0 : classNames.content, toast == null ? void 0 : (_toast_classNames4 = toast.classNames) == null ? void 0 : _toast_classNames4.content)
800
864
  }, /*#__PURE__*/ React__default.default.createElement("div", {
@@ -920,17 +984,26 @@ function useSonner() {
920
984
  };
921
985
  }
922
986
  const Toaster = /*#__PURE__*/ React__default.default.forwardRef(function Toaster(props, ref) {
923
- const { invert, position = 'bottom-right', hotkey = [
987
+ const { id, invert, position = 'bottom-right', hotkey = [
924
988
  'altKey',
925
989
  'KeyT'
926
- ], expand, closeButton, className, offset, mobileOffset, theme = 'light', richColors, duration, style, visibleToasts = VISIBLE_TOASTS_AMOUNT, toastOptions, dir = getDocumentDirection(), gap = GAP, icons, containerAriaLabel = 'Notifications' } = props;
990
+ ], expand, closeButton, className, offset, mobileOffset, theme = 'light', richColors, duration, style, visibleToasts = VISIBLE_TOASTS_AMOUNT, toastOptions, dir = getDocumentDirection(), gap = GAP, icons, customAriaLabel, containerAriaLabel = 'Notifications' } = props;
927
991
  const [toasts, setToasts] = React__default.default.useState([]);
992
+ const filteredToasts = React__default.default.useMemo(()=>{
993
+ if (id) {
994
+ return toasts.filter((toast)=>toast.toasterId === id);
995
+ }
996
+ return toasts.filter((toast)=>!toast.toasterId);
997
+ }, [
998
+ toasts,
999
+ id
1000
+ ]);
928
1001
  const possiblePositions = React__default.default.useMemo(()=>{
929
1002
  return Array.from(new Set([
930
1003
  position
931
- ].concat(toasts.filter((toast)=>toast.position).map((toast)=>toast.position))));
1004
+ ].concat(filteredToasts.filter((toast)=>toast.position).map((toast)=>toast.position))));
932
1005
  }, [
933
- toasts,
1006
+ filteredToasts,
934
1007
  position
935
1008
  ]);
936
1009
  const [heights, setHeights] = React__default.default.useState([]);
@@ -986,9 +1059,7 @@ const Toaster = /*#__PURE__*/ React__default.default.forwardRef(function Toaster
986
1059
  });
987
1060
  });
988
1061
  });
989
- }, [
990
- toasts
991
- ]);
1062
+ }, []);
992
1063
  React__default.default.useEffect(()=>{
993
1064
  if (theme !== 'system') {
994
1065
  setActualTheme(theme);
@@ -1043,7 +1114,7 @@ const Toaster = /*#__PURE__*/ React__default.default.forwardRef(function Toaster
1043
1114
  React__default.default.useEffect(()=>{
1044
1115
  const handleKeyDown = (event)=>{
1045
1116
  var _listRef_current;
1046
- const isHotkeyPressed = hotkey.every((key)=>event[key] || event.code === key);
1117
+ const isHotkeyPressed = hotkey.length > 0 && hotkey.every((key)=>event[key] || event.code === key);
1047
1118
  if (isHotkeyPressed) {
1048
1119
  var _listRef_current1;
1049
1120
  setExpanded(true);
@@ -1076,16 +1147,17 @@ const Toaster = /*#__PURE__*/ React__default.default.forwardRef(function Toaster
1076
1147
  return(// Remove item from normal navigation flow, only available via hotkey
1077
1148
  /*#__PURE__*/ React__default.default.createElement("section", {
1078
1149
  ref: ref,
1079
- "aria-label": `${containerAriaLabel} ${hotkeyLabel}`,
1150
+ "aria-label": customAriaLabel != null ? customAriaLabel : `${containerAriaLabel} ${hotkeyLabel}`,
1080
1151
  tabIndex: -1,
1081
1152
  "aria-live": "polite",
1082
1153
  "aria-relevant": "additions text",
1083
1154
  "aria-atomic": "false",
1084
- suppressHydrationWarning: true
1155
+ suppressHydrationWarning: true,
1156
+ "data-react-aria-top-layer": true
1085
1157
  }, possiblePositions.map((position, index)=>{
1086
1158
  var _heights_;
1087
1159
  const [y, x] = position.split('-');
1088
- if (!toasts.length) return null;
1160
+ if (!filteredToasts.length) return null;
1089
1161
  return /*#__PURE__*/ React__default.default.createElement("ol", {
1090
1162
  key: position,
1091
1163
  dir: dir === 'auto' ? getDocumentDirection() : dir,
@@ -1137,7 +1209,7 @@ const Toaster = /*#__PURE__*/ React__default.default.forwardRef(function Toaster
1137
1209
  setInteracting(true);
1138
1210
  },
1139
1211
  onPointerUp: ()=>setInteracting(false)
1140
- }, toasts.filter((toast)=>!toast.position && index === 0 || toast.position === position).map((toast, index)=>{
1212
+ }, filteredToasts.filter((toast)=>!toast.position && index === 0 || toast.position === position).map((toast, index)=>{
1141
1213
  var _toastOptions_duration, _toastOptions_closeButton;
1142
1214
  return /*#__PURE__*/ React__default.default.createElement(Toast, {
1143
1215
  key: toast.id,
@@ -1160,7 +1232,7 @@ const Toaster = /*#__PURE__*/ React__default.default.forwardRef(function Toaster
1160
1232
  actionButtonStyle: toastOptions == null ? void 0 : toastOptions.actionButtonStyle,
1161
1233
  closeButtonAriaLabel: toastOptions == null ? void 0 : toastOptions.closeButtonAriaLabel,
1162
1234
  removeToast: removeToast,
1163
- toasts: toasts.filter((t)=>t.position == toast.position),
1235
+ toasts: filteredToasts.filter((t)=>t.position == toast.position),
1164
1236
  heights: heights.filter((h)=>h.position == toast.position),
1165
1237
  setHeights: setHeights,
1166
1238
  expandByDefault: expand,
package/dist/index.mjs CHANGED
@@ -45,7 +45,8 @@ const SuccessIcon = /*#__PURE__*/ React.createElement("svg", {
45
45
  viewBox: "0 0 20 20",
46
46
  fill: "currentColor",
47
47
  height: "20",
48
- width: "20"
48
+ width: "20",
49
+ "aria-hidden": "true"
49
50
  }, /*#__PURE__*/ React.createElement("path", {
50
51
  fillRule: "evenodd",
51
52
  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",
@@ -56,7 +57,8 @@ const WarningIcon = /*#__PURE__*/ React.createElement("svg", {
56
57
  viewBox: "0 0 24 24",
57
58
  fill: "currentColor",
58
59
  height: "20",
59
- width: "20"
60
+ width: "20",
61
+ "aria-hidden": "true"
60
62
  }, /*#__PURE__*/ React.createElement("path", {
61
63
  fillRule: "evenodd",
62
64
  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",
@@ -67,7 +69,8 @@ const InfoIcon = /*#__PURE__*/ React.createElement("svg", {
67
69
  viewBox: "0 0 20 20",
68
70
  fill: "currentColor",
69
71
  height: "20",
70
- width: "20"
72
+ width: "20",
73
+ "aria-hidden": "true"
71
74
  }, /*#__PURE__*/ React.createElement("path", {
72
75
  fillRule: "evenodd",
73
76
  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",
@@ -78,7 +81,8 @@ const ErrorIcon = /*#__PURE__*/ React.createElement("svg", {
78
81
  viewBox: "0 0 20 20",
79
82
  fill: "currentColor",
80
83
  height: "20",
81
- width: "20"
84
+ width: "20",
85
+ "aria-hidden": "true"
82
86
  }, /*#__PURE__*/ React.createElement("path", {
83
87
  fillRule: "evenodd",
84
88
  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",
@@ -93,7 +97,8 @@ const CloseIcon = /*#__PURE__*/ React.createElement("svg", {
93
97
  stroke: "currentColor",
94
98
  strokeWidth: "1.5",
95
99
  strokeLinecap: "round",
96
- strokeLinejoin: "round"
100
+ strokeLinejoin: "round",
101
+ "aria-hidden": "true"
97
102
  }, /*#__PURE__*/ React.createElement("line", {
98
103
  x1: "18",
99
104
  y1: "6",
@@ -113,17 +118,30 @@ const useIsDocumentHidden = ()=>{
113
118
  setIsDocumentHidden(document.hidden);
114
119
  };
115
120
  document.addEventListener('visibilitychange', callback);
116
- return ()=>window.removeEventListener('visibilitychange', callback);
121
+ return ()=>document.removeEventListener('visibilitychange', callback);
117
122
  }, []);
118
123
  return isDocumentHidden;
119
124
  };
120
125
 
121
126
  let toastsCounter = 1;
127
+ // Amount of toasts kept in `toast.getHistory()`. Dismissed toasts above this limit are
128
+ // dropped so long-running apps don't hold on to them (and their JSX) forever.
129
+ const MAX_HISTORY_SIZE = 100;
130
+ // A toast keeps the id it was given, otherwise it gets the next one from the counter.
131
+ // `custom` needs the same id `create` would pick, as it hands it to the JSX callback.
132
+ const getToastId = (data)=>{
133
+ var _data_id;
134
+ return typeof (data == null ? void 0 : data.id) === 'number' || (data == null ? void 0 : (_data_id = data.id) == null ? void 0 : _data_id.length) > 0 ? data.id : toastsCounter++;
135
+ };
122
136
  class Observer {
123
137
  constructor(){
124
138
  // We use arrow functions to maintain the correct `this` reference
125
139
  this.subscribe = (subscriber)=>{
126
140
  this.subscribers.push(subscriber);
141
+ // A toast can be created before the `Toaster` had a chance to subscribe, e.g. when it's
142
+ // called in an effect of a component rendered above the `Toaster`. Replay whatever is
143
+ // still active so it doesn't get lost.
144
+ this.getActiveToasts().forEach((toast)=>subscriber(toast));
127
145
  return ()=>{
128
146
  const index = this.subscribers.indexOf(subscriber);
129
147
  this.subscribers.splice(index, 1);
@@ -138,18 +156,45 @@ class Observer {
138
156
  ...this.toasts,
139
157
  data
140
158
  ];
159
+ this.trimHistory();
160
+ };
161
+ // Keeps the history bounded without ever dropping a toast that's still on screen.
162
+ this.trimHistory = ()=>{
163
+ let toRemove = this.toasts.length - MAX_HISTORY_SIZE;
164
+ if (toRemove <= 0) return;
165
+ this.toasts = this.toasts.filter((toast)=>{
166
+ if (toRemove > 0 && this.dismissedToasts.has(toast.id)) {
167
+ this.dismissedToasts.delete(toast.id);
168
+ toRemove--;
169
+ return false;
170
+ }
171
+ return true;
172
+ });
141
173
  };
142
174
  this.create = (data)=>{
143
- var _data_id;
144
175
  const { message, ...rest } = data;
145
- const id = typeof (data == null ? void 0 : data.id) === 'number' || ((_data_id = data.id) == null ? void 0 : _data_id.length) > 0 ? data.id : toastsCounter++;
146
- const alreadyExists = this.toasts.find((toast)=>{
147
- return toast.id === id;
148
- });
176
+ const id = getToastId(data);
177
+ // A dismissal that hasn't reached the subscribers yet gets cancelled: the toast is still
178
+ // on screen, so this is an update of it rather than a new toast. Without this, creating a
179
+ // toast right after dismissing the same id (React's double effect in StrictMode does
180
+ // exactly that) would have the pending dismissal remove the toast that just got created.
181
+ const pendingDismissal = this.pendingDismissals.get(id);
182
+ if (pendingDismissal !== undefined) {
183
+ cancelAnimationFrame(pendingDismissal);
184
+ this.pendingDismissals.delete(id);
185
+ this.dismissedToasts.delete(id);
186
+ }
187
+ const wasDismissed = this.dismissedToasts.has(id);
149
188
  const dismissible = data.dismissible === undefined ? true : data.dismissible;
150
- if (this.dismissedToasts.has(id)) {
189
+ if (wasDismissed) {
151
190
  this.dismissedToasts.delete(id);
191
+ // The previous toast with this id is gone, so this is a brand new toast. Drop the old
192
+ // one instead of merging into it, otherwise its props (e.g. `action`) leak into the new one.
193
+ this.toasts = this.toasts.filter((toast)=>toast.id !== id);
152
194
  }
195
+ const alreadyExists = wasDismissed ? undefined : this.toasts.find((toast)=>{
196
+ return toast.id === id;
197
+ });
153
198
  if (alreadyExists) {
154
199
  this.toasts = this.toasts.map((toast)=>{
155
200
  if (toast.id === id) {
@@ -180,26 +225,37 @@ class Observer {
180
225
  return id;
181
226
  };
182
227
  this.dismiss = (id)=>{
183
- if (id) {
184
- this.dismissedToasts.add(id);
185
- requestAnimationFrame(()=>this.subscribers.forEach((subscriber)=>subscriber({
186
- id,
187
- dismiss: true
188
- })));
189
- } else {
190
- this.toasts.forEach((toast)=>{
228
+ if (id === undefined || id === null) {
229
+ this.getActiveToasts().forEach((toast)=>{
230
+ this.dismissedToasts.add(toast.id);
191
231
  this.subscribers.forEach((subscriber)=>subscriber({
192
232
  id: toast.id,
193
233
  dismiss: true
194
234
  }));
195
235
  });
236
+ return id;
196
237
  }
238
+ this.dismissedToasts.add(id);
239
+ const alreadyPending = this.pendingDismissals.get(id);
240
+ if (alreadyPending !== undefined) {
241
+ cancelAnimationFrame(alreadyPending);
242
+ }
243
+ this.pendingDismissals.set(id, requestAnimationFrame(()=>{
244
+ this.pendingDismissals.delete(id);
245
+ this.subscribers.forEach((subscriber)=>subscriber({
246
+ id,
247
+ dismiss: true
248
+ }));
249
+ }));
197
250
  return id;
198
251
  };
199
252
  this.message = (message, data)=>{
253
+ // `type: undefined` resets the type when this updates a toast that had one, e.g. turning
254
+ // a loading toast into a plain one.
200
255
  return this.create({
201
256
  ...data,
202
- message
257
+ message,
258
+ type: undefined
203
259
  });
204
260
  };
205
261
  this.error = (message, data)=>{
@@ -352,11 +408,13 @@ class Observer {
352
408
  }
353
409
  };
354
410
  this.custom = (jsx, data)=>{
355
- const id = (data == null ? void 0 : data.id) || toastsCounter++;
411
+ const id = getToastId(data);
412
+ // A custom toast has no type, so it resets the one of the toast it replaces
356
413
  this.create({
414
+ ...data,
357
415
  jsx: jsx(id),
358
416
  id,
359
- ...data
417
+ type: undefined
360
418
  });
361
419
  return id;
362
420
  };
@@ -366,18 +424,13 @@ class Observer {
366
424
  this.subscribers = [];
367
425
  this.toasts = [];
368
426
  this.dismissedToasts = new Set();
427
+ this.pendingDismissals = new Map();
369
428
  }
370
429
  }
371
430
  const ToastState = new Observer();
372
431
  // bind this to the toast function
373
432
  const toastFunction = (message, data)=>{
374
- const id = (data == null ? void 0 : data.id) || toastsCounter++;
375
- ToastState.addToast({
376
- title: message,
377
- ...data,
378
- id
379
- });
380
- return id;
433
+ return ToastState.message(message, data);
381
434
  };
382
435
  const isHttpResponse = (data)=>{
383
436
  return data && typeof data === 'object' && 'ok' in data && typeof data.ok === 'boolean' && 'status' in data && typeof data.status === 'number';
@@ -401,7 +454,7 @@ const toast = Object.assign(basicToast, {
401
454
  getToasts
402
455
  });
403
456
 
404
- __insertCSS("[data-sonner-toaster][dir=ltr],html[dir=ltr]{--toast-icon-margin-start:-3px;--toast-icon-margin-end:4px;--toast-svg-margin-start:-1px;--toast-svg-margin-end:0px;--toast-button-margin-start:auto;--toast-button-margin-end:0;--toast-close-button-start:0;--toast-close-button-end:unset;--toast-close-button-transform:translate(-35%, -35%)}[data-sonner-toaster][dir=rtl],html[dir=rtl]{--toast-icon-margin-start:4px;--toast-icon-margin-end:-3px;--toast-svg-margin-start:0px;--toast-svg-margin-end:-1px;--toast-button-margin-start:0;--toast-button-margin-end:auto;--toast-close-button-start:unset;--toast-close-button-end:0;--toast-close-button-transform:translate(35%, -35%)}[data-sonner-toaster]{position:fixed;width:var(--width);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;--gray1:hsl(0, 0%, 99%);--gray2:hsl(0, 0%, 97.3%);--gray3:hsl(0, 0%, 95.1%);--gray4:hsl(0, 0%, 93%);--gray5:hsl(0, 0%, 90.9%);--gray6:hsl(0, 0%, 88.7%);--gray7:hsl(0, 0%, 85.8%);--gray8:hsl(0, 0%, 78%);--gray9:hsl(0, 0%, 56.1%);--gray10:hsl(0, 0%, 52.3%);--gray11:hsl(0, 0%, 43.5%);--gray12:hsl(0, 0%, 9%);--border-radius:8px;box-sizing:border-box;padding:0;margin:0;list-style:none;outline:0;z-index:999999999;transition:transform .4s ease}@media (hover:none) and (pointer:coarse){[data-sonner-toaster][data-lifted=true]{transform:none}}[data-sonner-toaster][data-x-position=right]{right:var(--offset-right)}[data-sonner-toaster][data-x-position=left]{left:var(--offset-left)}[data-sonner-toaster][data-x-position=center]{left:50%;transform:translateX(-50%)}[data-sonner-toaster][data-y-position=top]{top:var(--offset-top)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--offset-bottom)}[data-sonner-toast]{--y:translateY(100%);--lift-amount:calc(var(--lift) * var(--gap));z-index:var(--z-index);position:absolute;opacity:0;transform:var(--y);touch-action:none;transition:transform .4s,opacity .4s,height .4s,box-shadow .2s;box-sizing:border-box;outline:0;overflow-wrap:anywhere}[data-sonner-toast][data-styled=true]{padding:16px;background:var(--normal-bg);border:1px solid var(--normal-border);color:var(--normal-text);border-radius:var(--border-radius);box-shadow:0 4px 12px rgba(0,0,0,.1);width:var(--width);font-size:13px;display:flex;align-items:center;gap:6px}[data-sonner-toast]:focus-visible{box-shadow:0 4px 12px rgba(0,0,0,.1),0 0 0 2px rgba(0,0,0,.2)}[data-sonner-toast][data-y-position=top]{top:0;--y:translateY(-100%);--lift:1;--lift-amount:calc(1 * var(--gap))}[data-sonner-toast][data-y-position=bottom]{bottom:0;--y:translateY(100%);--lift:-1;--lift-amount:calc(var(--lift) * var(--gap))}[data-sonner-toast][data-styled=true] [data-description]{font-weight:400;line-height:1.4;color:#3f3f3f}[data-rich-colors=true][data-sonner-toast][data-styled=true] [data-description]{color:inherit}[data-sonner-toaster][data-sonner-theme=dark] [data-description]{color:#e8e8e8}[data-sonner-toast][data-styled=true] [data-title]{font-weight:500;line-height:1.5;color:inherit}[data-sonner-toast][data-styled=true] [data-icon]{display:flex;height:16px;width:16px;position:relative;justify-content:flex-start;align-items:center;flex-shrink:0;margin-left:var(--toast-icon-margin-start);margin-right:var(--toast-icon-margin-end)}[data-sonner-toast][data-promise=true] [data-icon]>svg{opacity:0;transform:scale(.8);transform-origin:center;animation:sonner-fade-in .3s ease forwards}[data-sonner-toast][data-styled=true] [data-icon]>*{flex-shrink:0}[data-sonner-toast][data-styled=true] [data-icon] svg{margin-left:var(--toast-svg-margin-start);margin-right:var(--toast-svg-margin-end)}[data-sonner-toast][data-styled=true] [data-content]{display:flex;flex-direction:column;gap:2px}[data-sonner-toast][data-styled=true] [data-button]{border-radius:4px;padding-left:8px;padding-right:8px;height:24px;font-size:12px;color:var(--normal-bg);background:var(--normal-text);margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end);border:none;font-weight:500;cursor:pointer;outline:0;display:flex;align-items:center;flex-shrink:0;transition:opacity .4s,box-shadow .2s}[data-sonner-toast][data-styled=true] [data-button]:focus-visible{box-shadow:0 0 0 2px rgba(0,0,0,.4)}[data-sonner-toast][data-styled=true] [data-button]:first-of-type{margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end)}[data-sonner-toast][data-styled=true] [data-cancel]{color:var(--normal-text);background:rgba(0,0,0,.08)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-styled=true] [data-cancel]{background:rgba(255,255,255,.3)}[data-sonner-toast][data-styled=true] [data-close-button]{position:absolute;left:var(--toast-close-button-start);right:var(--toast-close-button-end);top:0;height:20px;width:20px;display:flex;justify-content:center;align-items:center;padding:0;color:var(--gray12);background:var(--normal-bg);border:1px solid var(--gray4);transform:var(--toast-close-button-transform);border-radius:50%;cursor:pointer;z-index:1;transition:opacity .1s,background .2s,border-color .2s}[data-sonner-toast][data-styled=true] [data-close-button]:focus-visible{box-shadow:0 4px 12px rgba(0,0,0,.1),0 0 0 2px rgba(0,0,0,.2)}[data-sonner-toast][data-styled=true] [data-disabled=true]{cursor:not-allowed}[data-sonner-toast][data-styled=true]:hover [data-close-button]:hover{background:var(--gray2);border-color:var(--gray5)}[data-sonner-toast][data-swiping=true]::before{content:'';position:absolute;left:-100%;right:-100%;height:100%;z-index:-1}[data-sonner-toast][data-y-position=top][data-swiping=true]::before{bottom:50%;transform:scaleY(3) translateY(50%)}[data-sonner-toast][data-y-position=bottom][data-swiping=true]::before{top:50%;transform:scaleY(3) translateY(-50%)}[data-sonner-toast][data-swiping=false][data-removed=true]::before{content:'';position:absolute;inset:0;transform:scaleY(2)}[data-sonner-toast][data-expanded=true]::after{content:'';position:absolute;left:0;height:calc(var(--gap) + 1px);bottom:100%;width:100%}[data-sonner-toast][data-mounted=true]{--y:translateY(0);opacity:1}[data-sonner-toast][data-expanded=false][data-front=false]{--scale:var(--toasts-before) * 0.05 + 1;--y:translateY(calc(var(--lift-amount) * var(--toasts-before))) scale(calc(-1 * var(--scale)));height:var(--front-toast-height)}[data-sonner-toast]>*{transition:opacity .4s}[data-sonner-toast][data-x-position=right]{right:0}[data-sonner-toast][data-x-position=left]{left:0}[data-sonner-toast][data-expanded=false][data-front=false][data-styled=true]>*{opacity:0}[data-sonner-toast][data-visible=false]{opacity:0;pointer-events:none}[data-sonner-toast][data-mounted=true][data-expanded=true]{--y:translateY(calc(var(--lift) * var(--offset)));height:var(--initial-height)}[data-sonner-toast][data-removed=true][data-front=true][data-swipe-out=false]{--y:translateY(calc(var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=true]{--y:translateY(calc(var(--lift) * var(--offset) + var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=false]{--y:translateY(40%);opacity:0;transition:transform .5s,opacity .2s}[data-sonner-toast][data-removed=true][data-front=false]::before{height:calc(var(--initial-height) + 20%)}[data-sonner-toast][data-swiping=true]{transform:var(--y) translateY(var(--swipe-amount-y,0)) translateX(var(--swipe-amount-x,0));transition:none}[data-sonner-toast][data-swiped=true]{user-select:none}[data-sonner-toast][data-swipe-out=true][data-y-position=bottom],[data-sonner-toast][data-swipe-out=true][data-y-position=top]{animation-duration:.2s;animation-timing-function:ease-out;animation-fill-mode:forwards}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=left]{animation-name:swipe-out-left}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=right]{animation-name:swipe-out-right}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=up]{animation-name:swipe-out-up}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=down]{animation-name:swipe-out-down}@keyframes swipe-out-left{from{transform:var(--y) translateX(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translateX(calc(var(--swipe-amount-x) - 100%));opacity:0}}@keyframes swipe-out-right{from{transform:var(--y) translateX(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translateX(calc(var(--swipe-amount-x) + 100%));opacity:0}}@keyframes swipe-out-up{from{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) - 100%));opacity:0}}@keyframes swipe-out-down{from{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) + 100%));opacity:0}}@media (max-width:600px){[data-sonner-toaster]{position:fixed;right:var(--mobile-offset-right);left:var(--mobile-offset-left);width:100%}[data-sonner-toaster][dir=rtl]{left:calc(var(--mobile-offset-left) * -1)}[data-sonner-toaster] [data-sonner-toast]{left:0;right:0;width:calc(100% - var(--mobile-offset-left) * 2)}[data-sonner-toaster][data-x-position=left]{left:var(--mobile-offset-left)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--mobile-offset-bottom)}[data-sonner-toaster][data-y-position=top]{top:var(--mobile-offset-top)}[data-sonner-toaster][data-x-position=center]{left:var(--mobile-offset-left);right:var(--mobile-offset-right);transform:none}}[data-sonner-toaster][data-sonner-theme=light]{--normal-bg:#fff;--normal-border:var(--gray4);--normal-text:var(--gray12);--success-bg:hsl(143, 85%, 96%);--success-border:hsl(145, 92%, 87%);--success-text:hsl(140, 100%, 27%);--info-bg:hsl(208, 100%, 97%);--info-border:hsl(221, 91%, 93%);--info-text:hsl(210, 92%, 45%);--warning-bg:hsl(49, 100%, 97%);--warning-border:hsl(49, 91%, 84%);--warning-text:hsl(31, 92%, 45%);--error-bg:hsl(359, 100%, 97%);--error-border:hsl(359, 100%, 94%);--error-text:hsl(360, 100%, 45%)}[data-sonner-toaster][data-sonner-theme=light] [data-sonner-toast][data-invert=true]{--normal-bg:#000;--normal-border:hsl(0, 0%, 20%);--normal-text:var(--gray1)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-invert=true]{--normal-bg:#fff;--normal-border:var(--gray3);--normal-text:var(--gray12)}[data-sonner-toaster][data-sonner-theme=dark]{--normal-bg:#000;--normal-bg-hover:hsl(0, 0%, 12%);--normal-border:hsl(0, 0%, 20%);--normal-border-hover:hsl(0, 0%, 25%);--normal-text:var(--gray1);--success-bg:hsl(150, 100%, 6%);--success-border:hsl(147, 100%, 12%);--success-text:hsl(150, 86%, 65%);--info-bg:hsl(215, 100%, 6%);--info-border:hsl(223, 43%, 17%);--info-text:hsl(216, 87%, 65%);--warning-bg:hsl(64, 100%, 6%);--warning-border:hsl(60, 100%, 9%);--warning-text:hsl(46, 87%, 65%);--error-bg:hsl(358, 76%, 10%);--error-border:hsl(357, 89%, 16%);--error-text:hsl(358, 100%, 81%)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]{background:var(--normal-bg);border-color:var(--normal-border);color:var(--normal-text)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]:hover{background:var(--normal-bg-hover);border-color:var(--normal-border-hover)}[data-rich-colors=true][data-sonner-toast][data-type=success]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=success] [data-close-button]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=info]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=info] [data-close-button]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning] [data-close-button]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=error]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}[data-rich-colors=true][data-sonner-toast][data-type=error] [data-close-button]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}.sonner-loading-wrapper{--size:16px;height:var(--size);width:var(--size);position:absolute;inset:0;z-index:10}.sonner-loading-wrapper[data-visible=false]{transform-origin:center;animation:sonner-fade-out .2s ease forwards}.sonner-spinner{position:relative;top:50%;left:50%;height:var(--size);width:var(--size)}.sonner-loading-bar{animation:sonner-spin 1.2s linear infinite;background:var(--gray11);border-radius:6px;height:8%;left:-10%;position:absolute;top:-3.9%;width:24%}.sonner-loading-bar:first-child{animation-delay:-1.2s;transform:rotate(.0001deg) translate(146%)}.sonner-loading-bar:nth-child(2){animation-delay:-1.1s;transform:rotate(30deg) translate(146%)}.sonner-loading-bar:nth-child(3){animation-delay:-1s;transform:rotate(60deg) translate(146%)}.sonner-loading-bar:nth-child(4){animation-delay:-.9s;transform:rotate(90deg) translate(146%)}.sonner-loading-bar:nth-child(5){animation-delay:-.8s;transform:rotate(120deg) translate(146%)}.sonner-loading-bar:nth-child(6){animation-delay:-.7s;transform:rotate(150deg) translate(146%)}.sonner-loading-bar:nth-child(7){animation-delay:-.6s;transform:rotate(180deg) translate(146%)}.sonner-loading-bar:nth-child(8){animation-delay:-.5s;transform:rotate(210deg) translate(146%)}.sonner-loading-bar:nth-child(9){animation-delay:-.4s;transform:rotate(240deg) translate(146%)}.sonner-loading-bar:nth-child(10){animation-delay:-.3s;transform:rotate(270deg) translate(146%)}.sonner-loading-bar:nth-child(11){animation-delay:-.2s;transform:rotate(300deg) translate(146%)}.sonner-loading-bar:nth-child(12){animation-delay:-.1s;transform:rotate(330deg) translate(146%)}@keyframes sonner-fade-in{0%{opacity:0;transform:scale(.8)}100%{opacity:1;transform:scale(1)}}@keyframes sonner-fade-out{0%{opacity:1;transform:scale(1)}100%{opacity:0;transform:scale(.8)}}@keyframes sonner-spin{0%{opacity:1}100%{opacity:.15}}@media (prefers-reduced-motion){.sonner-loading-bar,[data-sonner-toast],[data-sonner-toast]>*{transition:none!important;animation:none!important}}.sonner-loader{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);transform-origin:center;transition:opacity .2s,transform .2s}.sonner-loader[data-visible=false]{opacity:0;transform:scale(.8) translate(-50%,-50%)}");
457
+ __insertCSS("[data-sonner-toaster][dir=ltr],html[dir=ltr]{--toast-icon-margin-start:-3px;--toast-icon-margin-end:4px;--toast-svg-margin-start:-1px;--toast-svg-margin-end:0px;--toast-button-margin-start:auto;--toast-button-margin-end:0;--toast-close-button-start:0;--toast-close-button-end:unset;--toast-close-button-transform:translate(-35%, -35%)}[data-sonner-toaster][dir=rtl],html[dir=rtl]{--toast-icon-margin-start:4px;--toast-icon-margin-end:-3px;--toast-svg-margin-start:0px;--toast-svg-margin-end:-1px;--toast-button-margin-start:0;--toast-button-margin-end:auto;--toast-close-button-start:unset;--toast-close-button-end:0;--toast-close-button-transform:translate(35%, -35%)}[data-sonner-toaster]{position:fixed;width:var(--width);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;--gray1:hsl(0, 0%, 99%);--gray2:hsl(0, 0%, 97.3%);--gray3:hsl(0, 0%, 95.1%);--gray4:hsl(0, 0%, 93%);--gray5:hsl(0, 0%, 90.9%);--gray6:hsl(0, 0%, 88.7%);--gray7:hsl(0, 0%, 85.8%);--gray8:hsl(0, 0%, 78%);--gray9:hsl(0, 0%, 56.1%);--gray10:hsl(0, 0%, 52.3%);--gray11:hsl(0, 0%, 43.5%);--gray12:hsl(0, 0%, 9%);--border-radius:8px;box-sizing:border-box;padding:0;margin:0;list-style:none;outline:0;z-index:999999999;transition:transform .4s ease}@media (hover:none) and (pointer:coarse){[data-sonner-toaster][data-lifted=true]{transform:none}}[data-sonner-toaster][data-x-position=right]{right:var(--offset-right)}[data-sonner-toaster][data-x-position=left]{left:var(--offset-left)}[data-sonner-toaster][data-x-position=center]{left:50%;transform:translateX(-50%)}[data-sonner-toaster][data-y-position=top]{top:var(--offset-top)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--offset-bottom)}[data-sonner-toast]{--y:translateY(100%);--lift-amount:calc(var(--lift) * var(--gap));z-index:var(--z-index);position:absolute;opacity:0;transform:var(--y);touch-action:none;transition:transform .4s,opacity .4s,height .4s,box-shadow .2s;box-sizing:border-box;outline:0;overflow-wrap:anywhere}[data-sonner-toast][data-styled=true]{padding:16px;background:var(--normal-bg);border:1px solid var(--normal-border);color:var(--normal-text);border-radius:var(--border-radius);box-shadow:0 4px 12px rgba(0,0,0,.1);width:var(--width);font-size:13px;display:flex;align-items:center;gap:6px}[data-sonner-toast]:focus-visible{box-shadow:0 4px 12px rgba(0,0,0,.1),0 0 0 2px rgba(0,0,0,.2)}[data-sonner-toast][data-y-position=top]{top:0;--y:translateY(-100%);--lift:1;--lift-amount:calc(1 * var(--gap))}[data-sonner-toast][data-y-position=bottom]{bottom:0;--y:translateY(100%);--lift:-1;--lift-amount:calc(var(--lift) * var(--gap))}[data-sonner-toast][data-styled=true] [data-description]{font-weight:400;line-height:1.4;color:#3f3f3f}[data-rich-colors=true][data-sonner-toast][data-styled=true] [data-description]{color:inherit}[data-sonner-toaster][data-sonner-theme=dark] [data-description]{color:#e8e8e8}[data-sonner-toast][data-styled=true] [data-title]{font-weight:500;line-height:1.5;color:inherit}[data-sonner-toast][data-styled=true] [data-icon]{display:flex;height:16px;width:16px;position:relative;justify-content:flex-start;align-items:center;flex-shrink:0;margin-left:var(--toast-icon-margin-start);margin-right:var(--toast-icon-margin-end)}[data-sonner-toast][data-promise=true] [data-icon]>svg{opacity:0;transform:scale(.8);transform-origin:center;animation:sonner-fade-in .3s ease forwards}[data-sonner-toast][data-styled=true] [data-icon]>*{flex-shrink:0}[data-sonner-toast][data-styled=true] [data-icon] svg{margin-left:var(--toast-svg-margin-start);margin-right:var(--toast-svg-margin-end)}[data-sonner-toast][data-styled=true] [data-content]{display:flex;flex-direction:column;gap:2px;flex:1;min-width:0}[data-sonner-toast][data-styled=true] [data-button]{border-radius:4px;padding-left:8px;padding-right:8px;height:24px;font-size:12px;color:var(--normal-bg);background:var(--normal-text);margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end);border:none;font-weight:500;cursor:pointer;outline:0;display:flex;align-items:center;flex-shrink:0;transition:opacity .4s,box-shadow .2s}[data-sonner-toast][data-styled=true] [data-button]:focus-visible{box-shadow:0 0 0 2px rgba(0,0,0,.4)}[data-sonner-toast][data-styled=true] [data-button]:first-of-type{margin-left:var(--toast-button-margin-start);margin-right:var(--toast-button-margin-end)}[data-sonner-toast][data-styled=true] [data-cancel]{color:var(--normal-text);background:rgba(0,0,0,.08)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-styled=true] [data-cancel]{background:rgba(255,255,255,.3)}[data-sonner-toast][data-styled=true] [data-close-button]{position:absolute;left:var(--toast-close-button-start);right:var(--toast-close-button-end);top:0;height:20px;width:20px;display:flex;justify-content:center;align-items:center;padding:0;color:var(--normal-text);background:var(--normal-bg);border:1px solid var(--normal-border);transform:var(--toast-close-button-transform);border-radius:50%;cursor:pointer;z-index:1;transition:opacity .1s,background .2s,border-color .2s}[data-sonner-toast][data-styled=true] [data-close-button]:focus-visible{box-shadow:0 4px 12px rgba(0,0,0,.1),0 0 0 2px rgba(0,0,0,.2)}[data-sonner-toast][data-styled=true] [data-disabled=true]{cursor:not-allowed}[data-sonner-toast][data-styled=true]:hover [data-close-button]:hover{background:var(--gray2);border-color:var(--gray5)}[data-sonner-toast][data-swiping=true]::before{content:'';position:absolute;left:-100%;right:-100%;height:100%;z-index:-1}[data-sonner-toast][data-y-position=top][data-swiping=true]::before{bottom:50%;transform:scaleY(3) translateY(50%)}[data-sonner-toast][data-y-position=bottom][data-swiping=true]::before{top:50%;transform:scaleY(3) translateY(-50%)}[data-sonner-toast][data-swiping=false][data-removed=true]::before{content:'';position:absolute;inset:0;transform:scaleY(2)}[data-sonner-toast][data-expanded=true]::after{content:'';position:absolute;left:0;height:calc(var(--gap) + 1px);bottom:100%;width:100%}[data-sonner-toast][data-mounted=true]{--y:translateY(0);opacity:1}[data-sonner-toast][data-expanded=false][data-front=false]{--scale:var(--toasts-before) * 0.05 + 1;--y:translateY(calc(var(--lift-amount) * var(--toasts-before))) scale(calc(-1 * var(--scale)));height:var(--front-toast-height)}[data-sonner-toast]>*{transition:opacity .4s}[data-sonner-toast][data-x-position=right]{right:0}[data-sonner-toast][data-x-position=left]{left:0}[data-sonner-toast][data-expanded=false][data-front=false][data-styled=true]>*{opacity:0}[data-sonner-toast][data-visible=false]{opacity:0;pointer-events:none}[data-sonner-toast][data-mounted=true][data-expanded=true]{--y:translateY(calc(var(--lift) * var(--offset)));height:var(--initial-height)}[data-sonner-toast][data-removed=true][data-front=true][data-swipe-out=false]{--y:translateY(calc(var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=true]{--y:translateY(calc(var(--lift) * var(--offset) + var(--lift) * -100%));opacity:0}[data-sonner-toast][data-removed=true][data-front=false][data-swipe-out=false][data-expanded=false]{--y:translateY(40%);opacity:0;transition:transform .5s,opacity .2s}[data-sonner-toast][data-removed=true][data-front=false]::before{height:calc(var(--initial-height) + 20%)}[data-sonner-toast][data-swiping=true]{transform:var(--y) translateY(var(--swipe-amount-y,0)) translateX(var(--swipe-amount-x,0));transition:none}[data-sonner-toast][data-swiped=true]{-webkit-user-select:none;user-select:none}[data-sonner-toast][data-swipe-out=true][data-y-position=bottom],[data-sonner-toast][data-swipe-out=true][data-y-position=top]{animation-duration:.2s;animation-timing-function:ease-out;animation-fill-mode:forwards}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=left]{animation-name:swipe-out-left}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=right]{animation-name:swipe-out-right}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=up]{animation-name:swipe-out-up}[data-sonner-toast][data-swipe-out=true][data-swipe-direction=down]{animation-name:swipe-out-down}@keyframes swipe-out-left{from{transform:var(--y) translateX(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translateX(calc(var(--swipe-amount-x) - 100%));opacity:0}}@keyframes swipe-out-right{from{transform:var(--y) translateX(var(--swipe-amount-x));opacity:1}to{transform:var(--y) translateX(calc(var(--swipe-amount-x) + 100%));opacity:0}}@keyframes swipe-out-up{from{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) - 100%));opacity:0}}@keyframes swipe-out-down{from{transform:var(--y) translateY(var(--swipe-amount-y));opacity:1}to{transform:var(--y) translateY(calc(var(--swipe-amount-y) + 100%));opacity:0}}@media (max-width:600px){[data-sonner-toaster]{position:fixed;right:var(--mobile-offset-right);left:var(--mobile-offset-left);width:100%}[data-sonner-toaster][dir=rtl]{left:calc(var(--mobile-offset-left) * -1)}[data-sonner-toaster] [data-sonner-toast]{left:0;right:0;width:calc(100% - var(--mobile-offset-left) * 2)}[data-sonner-toaster][data-x-position=left]{left:var(--mobile-offset-left)}[data-sonner-toaster][data-y-position=bottom]{bottom:var(--mobile-offset-bottom)}[data-sonner-toaster][data-y-position=top]{top:var(--mobile-offset-top)}[data-sonner-toaster][data-x-position=center]{left:var(--mobile-offset-left);right:var(--mobile-offset-right);transform:none}}[data-sonner-toaster][data-sonner-theme=light]{--normal-bg:#fff;--normal-border:var(--gray4);--normal-text:var(--gray12);--success-bg:hsl(143, 85%, 96%);--success-border:hsl(145, 92%, 87%);--success-text:hsl(140, 100%, 27%);--info-bg:hsl(208, 100%, 97%);--info-border:hsl(221, 91%, 93%);--info-text:hsl(210, 92%, 45%);--warning-bg:hsl(49, 100%, 97%);--warning-border:hsl(49, 91%, 84%);--warning-text:hsl(31, 92%, 45%);--error-bg:hsl(359, 100%, 97%);--error-border:hsl(359, 100%, 94%);--error-text:hsl(360, 100%, 45%)}[data-sonner-toaster][data-sonner-theme=light] [data-sonner-toast][data-invert=true]{--normal-bg:#000;--normal-border:hsl(0, 0%, 20%);--normal-text:var(--gray1)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast][data-invert=true]{--normal-bg:#fff;--normal-border:var(--gray3);--normal-text:var(--gray12)}[data-sonner-toaster][data-sonner-theme=dark]{--normal-bg:#000;--normal-bg-hover:hsl(0, 0%, 12%);--normal-border:hsl(0, 0%, 20%);--normal-border-hover:hsl(0, 0%, 25%);--normal-text:var(--gray1);--success-bg:hsl(150, 100%, 6%);--success-border:hsl(147, 100%, 12%);--success-text:hsl(150, 86%, 65%);--info-bg:hsl(215, 100%, 6%);--info-border:hsl(223, 43%, 17%);--info-text:hsl(216, 87%, 65%);--warning-bg:hsl(64, 100%, 6%);--warning-border:hsl(60, 100%, 9%);--warning-text:hsl(46, 87%, 65%);--error-bg:hsl(358, 76%, 10%);--error-border:hsl(357, 89%, 16%);--error-text:hsl(358, 100%, 81%)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]{background:var(--normal-bg);border-color:var(--normal-border);color:var(--normal-text)}[data-sonner-toaster][data-sonner-theme=dark] [data-sonner-toast] [data-close-button]:hover{background:var(--normal-bg-hover);border-color:var(--normal-border-hover)}[data-rich-colors=true][data-sonner-toast][data-type=success]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=success] [data-close-button]{background:var(--success-bg);border-color:var(--success-border);color:var(--success-text)}[data-rich-colors=true][data-sonner-toast][data-type=info]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=info] [data-close-button]{background:var(--info-bg);border-color:var(--info-border);color:var(--info-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=warning] [data-close-button]{background:var(--warning-bg);border-color:var(--warning-border);color:var(--warning-text)}[data-rich-colors=true][data-sonner-toast][data-type=error]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}[data-rich-colors=true][data-sonner-toast][data-type=error] [data-close-button]{background:var(--error-bg);border-color:var(--error-border);color:var(--error-text)}.sonner-loading-wrapper{--size:16px;height:var(--size);width:var(--size);position:absolute;inset:0;z-index:10}.sonner-loading-wrapper[data-visible=false]{transform-origin:center;animation:sonner-fade-out .2s ease forwards}.sonner-spinner{position:relative;top:50%;left:50%;height:var(--size);width:var(--size)}.sonner-loading-bar{animation:sonner-spin 1.2s linear infinite;background:var(--gray11);border-radius:6px;height:8%;left:-10%;position:absolute;top:-3.9%;width:24%}.sonner-loading-bar:first-child{animation-delay:-1.2s;transform:rotate(.0001deg) translate(146%)}.sonner-loading-bar:nth-child(2){animation-delay:-1.1s;transform:rotate(30deg) translate(146%)}.sonner-loading-bar:nth-child(3){animation-delay:-1s;transform:rotate(60deg) translate(146%)}.sonner-loading-bar:nth-child(4){animation-delay:-.9s;transform:rotate(90deg) translate(146%)}.sonner-loading-bar:nth-child(5){animation-delay:-.8s;transform:rotate(120deg) translate(146%)}.sonner-loading-bar:nth-child(6){animation-delay:-.7s;transform:rotate(150deg) translate(146%)}.sonner-loading-bar:nth-child(7){animation-delay:-.6s;transform:rotate(180deg) translate(146%)}.sonner-loading-bar:nth-child(8){animation-delay:-.5s;transform:rotate(210deg) translate(146%)}.sonner-loading-bar:nth-child(9){animation-delay:-.4s;transform:rotate(240deg) translate(146%)}.sonner-loading-bar:nth-child(10){animation-delay:-.3s;transform:rotate(270deg) translate(146%)}.sonner-loading-bar:nth-child(11){animation-delay:-.2s;transform:rotate(300deg) translate(146%)}.sonner-loading-bar:nth-child(12){animation-delay:-.1s;transform:rotate(330deg) translate(146%)}@keyframes sonner-fade-in{0%{opacity:0;transform:scale(.8)}100%{opacity:1;transform:scale(1)}}@keyframes sonner-fade-out{0%{opacity:1;transform:scale(1)}100%{opacity:0;transform:scale(.8)}}@keyframes sonner-spin{0%{opacity:1}100%{opacity:.15}}@media (prefers-reduced-motion){.sonner-loading-bar,[data-sonner-toast],[data-sonner-toast]>*{transition:none!important;animation:none!important}}.sonner-loader{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);transform-origin:center;transition:opacity .2s,transform .2s}.sonner-loader[data-visible=false]{opacity:0;transform:scale(.8) translate(-50%,-50%)}");
405
458
 
406
459
  function isAction(action) {
407
460
  return action.label !== undefined;
@@ -455,6 +508,8 @@ const Toast = (props)=>{
455
508
  const isFront = index === 0;
456
509
  const isVisible = index + 1 <= visibleToasts;
457
510
  const toastType = toast.type;
511
+ // Toasts created with `toast()` have no type, `classNames.default` is the key for those.
512
+ const toastTypeKey = toastType != null ? toastType : 'default';
458
513
  const dismissible = toast.dismissible !== false;
459
514
  const toastClassname = toast.className || '';
460
515
  const toastDescriptionClassname = toast.descriptionClassName || '';
@@ -492,6 +547,13 @@ const Toast = (props)=>{
492
547
  heightIndex
493
548
  ]);
494
549
  const isDocumentHidden = useIsDocumentHidden();
550
+ const swipeDirections = React.useMemo(()=>{
551
+ var _props_swipeDirections;
552
+ return (_props_swipeDirections = props.swipeDirections) != null ? _props_swipeDirections : getDefaultSwipeDirections(position);
553
+ }, [
554
+ props.swipeDirections,
555
+ position
556
+ ]);
495
557
  const invert = toast.invert || ToasterInvert;
496
558
  const disabled = toastType === 'loading';
497
559
  offset.current = React.useMemo(()=>heightIndex * gap + toastsHeightBefore, [
@@ -644,7 +706,7 @@ const Toast = (props)=>{
644
706
  return /*#__PURE__*/ React.createElement("li", {
645
707
  tabIndex: 0,
646
708
  ref: toastRef,
647
- className: cn(className, toastClassname, classNames == null ? void 0 : classNames.toast, toast == null ? void 0 : (_toast_classNames = toast.classNames) == null ? void 0 : _toast_classNames.toast, classNames == null ? void 0 : classNames.default, classNames == null ? void 0 : classNames[toastType], toast == null ? void 0 : (_toast_classNames1 = toast.classNames) == null ? void 0 : _toast_classNames1[toastType]),
709
+ className: cn(className, toastClassname, classNames == null ? void 0 : classNames.toast, toast == null ? void 0 : (_toast_classNames = toast.classNames) == null ? void 0 : _toast_classNames.toast, classNames == null ? void 0 : classNames[toastTypeKey], toast == null ? void 0 : (_toast_classNames1 = toast.classNames) == null ? void 0 : _toast_classNames1[toastTypeKey]),
648
710
  "data-sonner-toast": "",
649
711
  "data-rich-colors": (_toast_richColors = toast.richColors) != null ? _toast_richColors : defaultRichColors,
650
712
  "data-styled": !Boolean(toast.jsx || toast.unstyled || unstyled),
@@ -664,6 +726,7 @@ const Toast = (props)=>{
664
726
  "data-swipe-out": swipeOut,
665
727
  "data-swipe-direction": swipeOutDirection,
666
728
  "data-expanded": Boolean(expanded || expandByDefault && mounted),
729
+ "data-testid": toast.testId,
667
730
  style: {
668
731
  '--index': index,
669
732
  '--toasts-before': index,
@@ -701,7 +764,10 @@ const Toast = (props)=>{
701
764
  const timeTaken = new Date().getTime() - ((_dragStartTime_current = dragStartTime.current) == null ? void 0 : _dragStartTime_current.getTime());
702
765
  const swipeAmount = swipeDirection === 'x' ? swipeAmountX : swipeAmountY;
703
766
  const velocity = Math.abs(swipeAmount) / timeTaken;
704
- if (Math.abs(swipeAmount) >= SWIPE_THRESHOLD || velocity > 0.11) {
767
+ // Movement towards a direction that isn't allowed is dampened, not blocked, so a fast
768
+ // flick can still pass the velocity check. Only dismiss if the direction is allowed.
769
+ const isAllowedDirection = swipeDirection === 'x' ? swipeDirections.includes(swipeAmountX > 0 ? 'right' : 'left') : swipeDirections.includes(swipeAmountY > 0 ? 'bottom' : 'top');
770
+ if (isAllowedDirection && (Math.abs(swipeAmount) >= SWIPE_THRESHOLD || velocity > 0.11)) {
705
771
  setOffsetBeforeRemove(offset.current);
706
772
  toast.onDismiss == null ? void 0 : toast.onDismiss.call(toast, toast);
707
773
  if (swipeDirection === 'x') {
@@ -729,8 +795,6 @@ const Toast = (props)=>{
729
795
  if (isHighlighted) return;
730
796
  const yDelta = event.clientY - pointerStartRef.current.y;
731
797
  const xDelta = event.clientX - pointerStartRef.current.x;
732
- var _props_swipeDirections;
733
- const swipeDirections = (_props_swipeDirections = props.swipeDirections) != null ? _props_swipeDirections : getDefaultSwipeDirections(position);
734
798
  // Determine swipe direction if not already locked
735
799
  if (!swipeDirection && (Math.abs(xDelta) > 1 || Math.abs(yDelta) > 1)) {
736
800
  setSwipeDirection(Math.abs(xDelta) > Math.abs(yDelta) ? 'x' : 'y');
@@ -787,7 +851,7 @@ const Toast = (props)=>{
787
851
  }, (_icons_close = icons == null ? void 0 : icons.close) != null ? _icons_close : CloseIcon) : null, (toastType || toast.icon || toast.promise) && toast.icon !== null && ((icons == null ? void 0 : icons[toastType]) !== null || toast.icon) ? /*#__PURE__*/ React.createElement("div", {
788
852
  "data-icon": "",
789
853
  className: cn(classNames == null ? void 0 : classNames.icon, toast == null ? void 0 : (_toast_classNames3 = toast.classNames) == null ? void 0 : _toast_classNames3.icon)
790
- }, toast.promise || toast.type === 'loading' && !toast.icon ? toast.icon || getLoadingIcon() : null, toast.type !== 'loading' ? icon : null) : null, /*#__PURE__*/ React.createElement("div", {
854
+ }, toastType === 'loading' ? toast.icon || getLoadingIcon() : toast.promise ? getLoadingIcon() : null, toastType !== 'loading' ? icon : null) : null, /*#__PURE__*/ React.createElement("div", {
791
855
  "data-content": "",
792
856
  className: cn(classNames == null ? void 0 : classNames.content, toast == null ? void 0 : (_toast_classNames4 = toast.classNames) == null ? void 0 : _toast_classNames4.content)
793
857
  }, /*#__PURE__*/ React.createElement("div", {
@@ -913,17 +977,26 @@ function useSonner() {
913
977
  };
914
978
  }
915
979
  const Toaster = /*#__PURE__*/ React.forwardRef(function Toaster(props, ref) {
916
- const { invert, position = 'bottom-right', hotkey = [
980
+ const { id, invert, position = 'bottom-right', hotkey = [
917
981
  'altKey',
918
982
  'KeyT'
919
- ], expand, closeButton, className, offset, mobileOffset, theme = 'light', richColors, duration, style, visibleToasts = VISIBLE_TOASTS_AMOUNT, toastOptions, dir = getDocumentDirection(), gap = GAP, icons, containerAriaLabel = 'Notifications' } = props;
983
+ ], expand, closeButton, className, offset, mobileOffset, theme = 'light', richColors, duration, style, visibleToasts = VISIBLE_TOASTS_AMOUNT, toastOptions, dir = getDocumentDirection(), gap = GAP, icons, customAriaLabel, containerAriaLabel = 'Notifications' } = props;
920
984
  const [toasts, setToasts] = React.useState([]);
985
+ const filteredToasts = React.useMemo(()=>{
986
+ if (id) {
987
+ return toasts.filter((toast)=>toast.toasterId === id);
988
+ }
989
+ return toasts.filter((toast)=>!toast.toasterId);
990
+ }, [
991
+ toasts,
992
+ id
993
+ ]);
921
994
  const possiblePositions = React.useMemo(()=>{
922
995
  return Array.from(new Set([
923
996
  position
924
- ].concat(toasts.filter((toast)=>toast.position).map((toast)=>toast.position))));
997
+ ].concat(filteredToasts.filter((toast)=>toast.position).map((toast)=>toast.position))));
925
998
  }, [
926
- toasts,
999
+ filteredToasts,
927
1000
  position
928
1001
  ]);
929
1002
  const [heights, setHeights] = React.useState([]);
@@ -979,9 +1052,7 @@ const Toaster = /*#__PURE__*/ React.forwardRef(function Toaster(props, ref) {
979
1052
  });
980
1053
  });
981
1054
  });
982
- }, [
983
- toasts
984
- ]);
1055
+ }, []);
985
1056
  React.useEffect(()=>{
986
1057
  if (theme !== 'system') {
987
1058
  setActualTheme(theme);
@@ -1036,7 +1107,7 @@ const Toaster = /*#__PURE__*/ React.forwardRef(function Toaster(props, ref) {
1036
1107
  React.useEffect(()=>{
1037
1108
  const handleKeyDown = (event)=>{
1038
1109
  var _listRef_current;
1039
- const isHotkeyPressed = hotkey.every((key)=>event[key] || event.code === key);
1110
+ const isHotkeyPressed = hotkey.length > 0 && hotkey.every((key)=>event[key] || event.code === key);
1040
1111
  if (isHotkeyPressed) {
1041
1112
  var _listRef_current1;
1042
1113
  setExpanded(true);
@@ -1069,16 +1140,17 @@ const Toaster = /*#__PURE__*/ React.forwardRef(function Toaster(props, ref) {
1069
1140
  return(// Remove item from normal navigation flow, only available via hotkey
1070
1141
  /*#__PURE__*/ React.createElement("section", {
1071
1142
  ref: ref,
1072
- "aria-label": `${containerAriaLabel} ${hotkeyLabel}`,
1143
+ "aria-label": customAriaLabel != null ? customAriaLabel : `${containerAriaLabel} ${hotkeyLabel}`,
1073
1144
  tabIndex: -1,
1074
1145
  "aria-live": "polite",
1075
1146
  "aria-relevant": "additions text",
1076
1147
  "aria-atomic": "false",
1077
- suppressHydrationWarning: true
1148
+ suppressHydrationWarning: true,
1149
+ "data-react-aria-top-layer": true
1078
1150
  }, possiblePositions.map((position, index)=>{
1079
1151
  var _heights_;
1080
1152
  const [y, x] = position.split('-');
1081
- if (!toasts.length) return null;
1153
+ if (!filteredToasts.length) return null;
1082
1154
  return /*#__PURE__*/ React.createElement("ol", {
1083
1155
  key: position,
1084
1156
  dir: dir === 'auto' ? getDocumentDirection() : dir,
@@ -1130,7 +1202,7 @@ const Toaster = /*#__PURE__*/ React.forwardRef(function Toaster(props, ref) {
1130
1202
  setInteracting(true);
1131
1203
  },
1132
1204
  onPointerUp: ()=>setInteracting(false)
1133
- }, toasts.filter((toast)=>!toast.position && index === 0 || toast.position === position).map((toast, index)=>{
1205
+ }, filteredToasts.filter((toast)=>!toast.position && index === 0 || toast.position === position).map((toast, index)=>{
1134
1206
  var _toastOptions_duration, _toastOptions_closeButton;
1135
1207
  return /*#__PURE__*/ React.createElement(Toast, {
1136
1208
  key: toast.id,
@@ -1153,7 +1225,7 @@ const Toaster = /*#__PURE__*/ React.forwardRef(function Toaster(props, ref) {
1153
1225
  actionButtonStyle: toastOptions == null ? void 0 : toastOptions.actionButtonStyle,
1154
1226
  closeButtonAriaLabel: toastOptions == null ? void 0 : toastOptions.closeButtonAriaLabel,
1155
1227
  removeToast: removeToast,
1156
- toasts: toasts.filter((t)=>t.position == toast.position),
1228
+ toasts: filteredToasts.filter((t)=>t.position == toast.position),
1157
1229
  heights: heights.filter((h)=>h.position == toast.position),
1158
1230
  setHeights: setHeights,
1159
1231
  expandByDefault: expand,
package/dist/styles.css CHANGED
@@ -176,6 +176,10 @@ html[dir='rtl'],
176
176
  display: flex;
177
177
  flex-direction: column;
178
178
  gap: 2px;
179
+ /* Take the space the icon and the buttons leave, so a custom title or description
180
+ isn't limited to the width of its text */
181
+ flex: 1;
182
+ min-width: 0;
179
183
  }
180
184
 
181
185
  [data-sonner-toast][data-styled='true'] [data-button] {
@@ -227,9 +231,9 @@ html[dir='rtl'],
227
231
  justify-content: center;
228
232
  align-items: center;
229
233
  padding: 0;
230
- color: var(--gray12);
234
+ color: var(--normal-text);
231
235
  background: var(--normal-bg);
232
- border: 1px solid var(--gray4);
236
+ border: 1px solid var(--normal-border);
233
237
  transform: var(--toast-close-button-transform);
234
238
  border-radius: 50%;
235
239
  cursor: pointer;
@@ -348,6 +352,7 @@ html[dir='rtl'],
348
352
  }
349
353
 
350
354
  [data-sonner-toast][data-swiped='true'] {
355
+ -webkit-user-select: none; /* Safari 3+ */
351
356
  user-select: none;
352
357
  }
353
358
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sonner",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "description": "An opinionated toast component for React.",
5
5
  "exports": {
6
6
  ".": {
@@ -59,8 +59,14 @@
59
59
  "typescript": "^4.8.4"
60
60
  },
61
61
  "peerDependencies": {
62
+ "@types/react": "^18.0.0 || ^19.0.0",
62
63
  "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
63
64
  "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
64
65
  },
66
+ "peerDependenciesMeta": {
67
+ "@types/react": {
68
+ "optional": true
69
+ }
70
+ },
65
71
  "packageManager": "pnpm@9.15.9"
66
72
  }