better-toast 0.0.1
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/README.md +94 -0
- package/fesm2022/better-toast.mjs +1318 -0
- package/fesm2022/better-toast.mjs.map +1 -0
- package/package.json +43 -0
- package/types/better-toast.d.ts +543 -0
|
@@ -0,0 +1,1318 @@
|
|
|
1
|
+
import { NgComponentOutlet } from '@angular/common';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { signal, Injectable, inject, ElementRef, input, output, computed, afterNextRender, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
4
|
+
|
|
5
|
+
/** Fallback when `<app-toaster [duration]>` is absent and a helper omits `durationMs`. */
|
|
6
|
+
const DEFAULT_TOAST_DURATION_MS = 4000;
|
|
7
|
+
/** Default label for {@link ToasterService.action} when {@link ToastMethodButtonConfig.label} is omitted. */
|
|
8
|
+
const DEFAULT_TOAST_ACTION_LABEL = 'Action';
|
|
9
|
+
/** Default label for {@link ToasterService.cancel} when {@link ToastMethodButtonConfig.label} is omitted. */
|
|
10
|
+
const DEFAULT_TOAST_CANCEL_LABEL = 'Cancel';
|
|
11
|
+
/**
|
|
12
|
+
* Use with `[duration]` or `options.durationMs` so a toast stays until manually dismissed.
|
|
13
|
+
* (`0` is still treated as non-auto-dismiss for backward compatibility.)
|
|
14
|
+
*/
|
|
15
|
+
const TOAST_DURATION_MANUAL_DISMISS = Number.POSITIVE_INFINITY;
|
|
16
|
+
/** Coerces {@link ToasterDuration} to ms (only the literal string `"Infinity"` for manual dismiss). */
|
|
17
|
+
function parseToasterDurationMs(value) {
|
|
18
|
+
if (value === 'Infinity') {
|
|
19
|
+
return TOAST_DURATION_MANUAL_DISMISS;
|
|
20
|
+
}
|
|
21
|
+
if (Number.isNaN(value)) {
|
|
22
|
+
return DEFAULT_TOAST_DURATION_MS;
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
function shouldScheduleAutoDismiss(durationMs) {
|
|
27
|
+
return Number.isFinite(durationMs) && durationMs > 0;
|
|
28
|
+
}
|
|
29
|
+
class ToasterService {
|
|
30
|
+
_toasts = signal([], ...(ngDevMode ? [{ debugName: "_toasts" }] : /* istanbul ignore next */ []));
|
|
31
|
+
autoDismissByToastId = new Map();
|
|
32
|
+
/** Updated by `<better-toaster [duration]>`; initial value is {@link DEFAULT_TOAST_DURATION_MS}. */
|
|
33
|
+
defaultDurationMs = DEFAULT_TOAST_DURATION_MS;
|
|
34
|
+
/** Active messages, oldest first. */
|
|
35
|
+
toasts = this._toasts.asReadonly();
|
|
36
|
+
/**
|
|
37
|
+
* Synced from `<better-toaster [duration]>`; used when a service call omits `durationMs`.
|
|
38
|
+
* Does not change timers on toasts already shown.
|
|
39
|
+
*/
|
|
40
|
+
setDefaultDurationMs(ms) {
|
|
41
|
+
const normalizedMs = Number.isNaN(ms) ? DEFAULT_TOAST_DURATION_MS : Math.max(0, ms);
|
|
42
|
+
this.defaultDurationMs = normalizedMs;
|
|
43
|
+
}
|
|
44
|
+
resolveDuration(durationMs) {
|
|
45
|
+
if (durationMs !== undefined) {
|
|
46
|
+
return parseToasterDurationMs(durationMs);
|
|
47
|
+
}
|
|
48
|
+
return this.defaultDurationMs;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Stops any auto-dismiss for this toast: clears a running timeout if present and drops timer state.
|
|
52
|
+
*/
|
|
53
|
+
cancelAutoDismiss(id) {
|
|
54
|
+
const state = this.autoDismissByToastId.get(id);
|
|
55
|
+
if (!state) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (state.kind === 'scheduled') {
|
|
59
|
+
globalThis.clearTimeout(state.timer);
|
|
60
|
+
}
|
|
61
|
+
this.autoDismissByToastId.delete(id);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* (Re)starts auto-dismiss from a concrete duration in milliseconds.
|
|
65
|
+
* Idempotent per toast: always cancels any existing timer first.
|
|
66
|
+
* Manual dismiss (`Infinity`) and non-positive values do not schedule a timer.
|
|
67
|
+
*/
|
|
68
|
+
scheduleAutoDismiss(id, durationMs) {
|
|
69
|
+
this.cancelAutoDismiss(id);
|
|
70
|
+
if (!shouldScheduleAutoDismiss(durationMs)) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const deadline = Date.now() + durationMs;
|
|
74
|
+
const timer = globalThis.setTimeout(() => {
|
|
75
|
+
this.removeToast(id, 'auto');
|
|
76
|
+
}, durationMs);
|
|
77
|
+
this.autoDismissByToastId.set(id, { kind: 'scheduled', timer, deadline });
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Pauses the auto-dismiss timer while the pointer is over the toast (e.g. hover).
|
|
81
|
+
* No-op if the toast has no active auto-dismiss.
|
|
82
|
+
*
|
|
83
|
+
* @param id The toast ID.
|
|
84
|
+
*/
|
|
85
|
+
pauseAutoDismiss(id) {
|
|
86
|
+
const state = this.autoDismissByToastId.get(id);
|
|
87
|
+
if (!state || state.kind !== 'scheduled') {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
globalThis.clearTimeout(state.timer);
|
|
91
|
+
const remainingMs = Math.max(0, state.deadline - Date.now());
|
|
92
|
+
this.autoDismissByToastId.set(id, { kind: 'paused', remainingMs });
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Resumes a paused auto-dismiss with the remaining time from {@link pauseAutoDismiss}.
|
|
96
|
+
*
|
|
97
|
+
* @param id The toast ID.
|
|
98
|
+
*/
|
|
99
|
+
resumeAutoDismiss(id) {
|
|
100
|
+
const state = this.autoDismissByToastId.get(id);
|
|
101
|
+
if (!state || state.kind !== 'paused') {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const { remainingMs } = state;
|
|
105
|
+
this.autoDismissByToastId.delete(id);
|
|
106
|
+
if (remainingMs <= 0) {
|
|
107
|
+
this.removeToast(id, 'auto');
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this.scheduleAutoDismiss(id, remainingMs);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Display a neutral (default) toast notification.
|
|
114
|
+
*
|
|
115
|
+
* @param message The toast content.
|
|
116
|
+
* @param options Optional configuration object {@link ToastOptions}.
|
|
117
|
+
* @returns The toast ID, useful for programmatic dismissal.
|
|
118
|
+
*/
|
|
119
|
+
show(message, options) {
|
|
120
|
+
return this.add(message, 'default', this.resolveDuration(options?.durationMs), options);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Display a toast using the **`description`** variant: same neutral chrome as **`default`**.
|
|
124
|
+
*
|
|
125
|
+
* @param message Title line.
|
|
126
|
+
* @param options Optional configuration object {@link ToastOptions}.
|
|
127
|
+
* @returns The toast ID, useful for programmatic dismissal.
|
|
128
|
+
*/
|
|
129
|
+
description(message, options) {
|
|
130
|
+
return this.add(message, 'description', this.resolveDuration(options?.durationMs), options);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Display a success toast notification.
|
|
134
|
+
*
|
|
135
|
+
* @param message The toast content.
|
|
136
|
+
* @param options Optional configuration object {@link ToastOptions}.
|
|
137
|
+
* @returns The toast ID, useful for programmatic dismissal.
|
|
138
|
+
*/
|
|
139
|
+
success(message, options) {
|
|
140
|
+
return this.add(message, 'success', this.resolveDuration(options?.durationMs), options);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Display an error toast notification.
|
|
144
|
+
*
|
|
145
|
+
* @param message The toast content.
|
|
146
|
+
* @param options Optional configuration object {@link ToastOptions}.
|
|
147
|
+
* @returns The toast ID, useful for programmatic dismissal.
|
|
148
|
+
*/
|
|
149
|
+
error(message, options) {
|
|
150
|
+
return this.add(message, 'error', this.resolveDuration(options?.durationMs), options);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Display an info toast notification.
|
|
154
|
+
*
|
|
155
|
+
* @param message The toast content.
|
|
156
|
+
* @param options Optional configuration object {@link ToastOptions}.
|
|
157
|
+
* @returns The toast ID, useful for programmatic dismissal.
|
|
158
|
+
*/
|
|
159
|
+
info(message, options) {
|
|
160
|
+
return this.add(message, 'info', this.resolveDuration(options?.durationMs), options);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Display a warning toast notification.
|
|
164
|
+
*
|
|
165
|
+
* @param message The toast content.
|
|
166
|
+
* @param options Optional configuration object {@link ToastOptions}.
|
|
167
|
+
* @returns The toast ID, useful for programmatic dismissal.
|
|
168
|
+
*/
|
|
169
|
+
warning(message, options) {
|
|
170
|
+
return this.add(message, 'warning', this.resolveDuration(options?.durationMs), options);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Show a toast whose **message area** is a standalone Angular component while keeping normal toast chrome
|
|
174
|
+
* (surface, icon column when applicable, close button, stack motion).
|
|
175
|
+
*
|
|
176
|
+
* Pass {@link CustomToastOptions.inputs} for `input()` / `@Input()` on that component.
|
|
177
|
+
* The component also receives **`toastId`** (matches the returned id) for programmatic dismiss.
|
|
178
|
+
*
|
|
179
|
+
* @param component The component class (must be usable with `NgComponentOutlet`).
|
|
180
|
+
* @param options Optional configuration object {@link CustomToastOptions}.
|
|
181
|
+
* @returns The toast ID, useful for programmatic dismissal.
|
|
182
|
+
*/
|
|
183
|
+
custom(component, options) {
|
|
184
|
+
return this.addContentComponent(component, 'default', this.resolveDuration(options?.durationMs), options);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Show a toast whose body is a **standalone** Angular component on a headless host: no default border,
|
|
188
|
+
* padding, shadow, or surface color — only stack position and enter/leave animations; the component supplies all visuals.
|
|
189
|
+
*
|
|
190
|
+
* Pass {@link HeadlessToastOptions.inputs} to feed `input()` on that component.
|
|
191
|
+
* The component also automatically receives **`toastId`** (matches the returned id) for programmatic dismiss inside the component.
|
|
192
|
+
*
|
|
193
|
+
* @param component The component class (must be usable with `NgComponentOutlet`).
|
|
194
|
+
* @param options Optional configuration object {@link HeadlessToastOptions}.
|
|
195
|
+
* @returns The toast ID, useful for programmatic dismissal.
|
|
196
|
+
*/
|
|
197
|
+
headless(component, options) {
|
|
198
|
+
return this.addComponent(component, this.resolveDuration(options?.durationMs), options);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Display a loading toast notification.
|
|
202
|
+
*
|
|
203
|
+
* If `options.durationMs` is omitted, the toast stays until you dismiss or replace it (same as {@link TOAST_DURATION_MANUAL_DISMISS}).
|
|
204
|
+
* Passing a finite positive `durationMs` schedules auto-dismiss for loading toasts like other variants.
|
|
205
|
+
* The literal **`"Infinity"`** (or {@link TOAST_DURATION_MANUAL_DISMISS} / `0`) keeps the toast until dismissed.
|
|
206
|
+
*
|
|
207
|
+
* @param message The toast content.
|
|
208
|
+
* @param options Optional configuration object {@link ToastOptions}.
|
|
209
|
+
* @returns The toast ID, useful for programmatic dismissal.
|
|
210
|
+
*/
|
|
211
|
+
loading(message, options) {
|
|
212
|
+
const durationMs = options?.durationMs !== undefined
|
|
213
|
+
? parseToasterDurationMs(options.durationMs)
|
|
214
|
+
: TOAST_DURATION_MANUAL_DISMISS;
|
|
215
|
+
return this.add(message, 'loading', durationMs, options);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Toast with message and a single **action** button. Default action button label is {@link DEFAULT_TOAST_ACTION_LABEL}.
|
|
219
|
+
* Pass `action.label` and `action.onClick` in {@link ToastActionMethodOptions} to customize the action button.
|
|
220
|
+
*
|
|
221
|
+
* @param message The toast content.
|
|
222
|
+
* @param options Optional configuration object {@link ToastActionMethodOptions}.
|
|
223
|
+
* @returns The toast ID, useful for programmatic dismissal.
|
|
224
|
+
*/
|
|
225
|
+
action(message, options) {
|
|
226
|
+
const { action: actionCfg, ...rest } = options;
|
|
227
|
+
const toastAction = {
|
|
228
|
+
role: 'action',
|
|
229
|
+
label: actionCfg.label ?? DEFAULT_TOAST_ACTION_LABEL,
|
|
230
|
+
onClick: actionCfg.onClick,
|
|
231
|
+
};
|
|
232
|
+
return this.add(message, 'default', this.resolveDuration(rest.durationMs), { ...rest, icon: null }, toastAction);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Toast with message and a **cancel**-style button. Default cancel button label is {@link DEFAULT_TOAST_CANCEL_LABEL}.
|
|
236
|
+
* Pass `cancel.label` and `cancel.onClick` in {@link ToastCancelMethodOptions} to customize the cancel button.
|
|
237
|
+
*
|
|
238
|
+
* @param message The toast content.
|
|
239
|
+
* @param options Optional configuration object {@link ToastCancelMethodOptions}.
|
|
240
|
+
* @returns The toast ID, useful for programmatic dismissal.
|
|
241
|
+
*/
|
|
242
|
+
cancel(message, options) {
|
|
243
|
+
const { cancel: cancelCfg, ...rest } = options;
|
|
244
|
+
const toastAction = {
|
|
245
|
+
role: 'cancel',
|
|
246
|
+
label: cancelCfg.label ?? DEFAULT_TOAST_CANCEL_LABEL,
|
|
247
|
+
onClick: cancelCfg.onClick,
|
|
248
|
+
};
|
|
249
|
+
return this.add(message, 'default', this.resolveDuration(rest.durationMs), { ...rest, icon: null }, toastAction);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Shows one toast: loading until `userPromise` settles, then the same toast updates to success or error.
|
|
253
|
+
* Returns the same promise (fulfillment/rejection preserved for callers).
|
|
254
|
+
*
|
|
255
|
+
* @param userPromise The promise to display.
|
|
256
|
+
* @param labels The labels for the loading, success, and error states.
|
|
257
|
+
* @returns The promise (fulfillment/rejection preserved for callers).
|
|
258
|
+
*/
|
|
259
|
+
promise(userPromise, labels) {
|
|
260
|
+
const loadingId = this.loading(labels.loading);
|
|
261
|
+
return Promise.resolve(userPromise).then((value) => {
|
|
262
|
+
const message = typeof labels.success === 'function' ? labels.success(value) : labels.success;
|
|
263
|
+
this.updateToast(loadingId, message, 'success', this.resolveDuration(undefined));
|
|
264
|
+
return value;
|
|
265
|
+
}, (reason) => {
|
|
266
|
+
const message = typeof labels.error === 'function' ? labels.error(reason) : labels.error;
|
|
267
|
+
this.updateToast(loadingId, message, 'error', this.resolveDuration(undefined));
|
|
268
|
+
throw reason;
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Dismiss a toast notification.
|
|
273
|
+
*
|
|
274
|
+
* @param id The toast ID.
|
|
275
|
+
*/
|
|
276
|
+
dismiss(id) {
|
|
277
|
+
this.removeToast(id, 'manual');
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Clear all toast notifications.
|
|
281
|
+
*/
|
|
282
|
+
clear() {
|
|
283
|
+
const snapshot = [...this._toasts()];
|
|
284
|
+
for (const state of this.autoDismissByToastId.values()) {
|
|
285
|
+
if (state.kind === 'scheduled') {
|
|
286
|
+
globalThis.clearTimeout(state.timer);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
this.autoDismissByToastId.clear();
|
|
290
|
+
this._toasts.set([]);
|
|
291
|
+
for (const toast of snapshot) {
|
|
292
|
+
toast.onDismiss?.();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
add(message, variant, durationMs, options, toastAction) {
|
|
296
|
+
const id = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
|
|
297
|
+
const icon = options?.icon;
|
|
298
|
+
const style = options?.style;
|
|
299
|
+
const classNames = options?.classNames;
|
|
300
|
+
const onDismiss = options?.onDismiss;
|
|
301
|
+
const onAutoClose = options?.onAutoClose;
|
|
302
|
+
const description = options?.description;
|
|
303
|
+
const item = {
|
|
304
|
+
id,
|
|
305
|
+
message,
|
|
306
|
+
variant,
|
|
307
|
+
...(icon !== undefined ? { icon } : {}),
|
|
308
|
+
...(style !== undefined ? { style } : {}),
|
|
309
|
+
...(classNames !== undefined ? { classNames } : {}),
|
|
310
|
+
...(description !== undefined ? { description } : {}),
|
|
311
|
+
...(onDismiss !== undefined ? { onDismiss } : {}),
|
|
312
|
+
...(onAutoClose !== undefined ? { onAutoClose } : {}),
|
|
313
|
+
...(toastAction !== undefined ? { toastAction } : {}),
|
|
314
|
+
};
|
|
315
|
+
this._toasts.update((list) => [...list, item]);
|
|
316
|
+
this.scheduleAutoDismiss(id, durationMs);
|
|
317
|
+
return id;
|
|
318
|
+
}
|
|
319
|
+
addContentComponent(component, variant, durationMs, options) {
|
|
320
|
+
const id = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
|
|
321
|
+
const componentInputs = {
|
|
322
|
+
...(options?.inputs ?? {}),
|
|
323
|
+
toastId: id,
|
|
324
|
+
};
|
|
325
|
+
const icon = options?.icon;
|
|
326
|
+
const style = options?.style;
|
|
327
|
+
const classNames = options?.classNames;
|
|
328
|
+
const onDismiss = options?.onDismiss;
|
|
329
|
+
const onAutoClose = options?.onAutoClose;
|
|
330
|
+
const description = options?.description;
|
|
331
|
+
const item = {
|
|
332
|
+
id,
|
|
333
|
+
message: '',
|
|
334
|
+
variant,
|
|
335
|
+
contentComponent: component,
|
|
336
|
+
contentComponentInputs: componentInputs,
|
|
337
|
+
...(icon !== undefined ? { icon } : {}),
|
|
338
|
+
...(style !== undefined ? { style } : {}),
|
|
339
|
+
...(classNames !== undefined ? { classNames } : {}),
|
|
340
|
+
...(description !== undefined ? { description } : {}),
|
|
341
|
+
...(onDismiss !== undefined ? { onDismiss } : {}),
|
|
342
|
+
...(onAutoClose !== undefined ? { onAutoClose } : {}),
|
|
343
|
+
};
|
|
344
|
+
this._toasts.update((list) => [...list, item]);
|
|
345
|
+
this.scheduleAutoDismiss(id, durationMs);
|
|
346
|
+
return id;
|
|
347
|
+
}
|
|
348
|
+
addComponent(component, durationMs, options) {
|
|
349
|
+
const id = globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
|
|
350
|
+
const componentInputs = {
|
|
351
|
+
...(options?.inputs ?? {}),
|
|
352
|
+
toastId: id,
|
|
353
|
+
};
|
|
354
|
+
const classNames = options?.classNames;
|
|
355
|
+
const onDismiss = options?.onDismiss;
|
|
356
|
+
const onAutoClose = options?.onAutoClose;
|
|
357
|
+
const item = {
|
|
358
|
+
id,
|
|
359
|
+
message: '',
|
|
360
|
+
variant: 'default',
|
|
361
|
+
component,
|
|
362
|
+
componentInputs,
|
|
363
|
+
...(classNames !== undefined ? { classNames } : {}),
|
|
364
|
+
...(onDismiss !== undefined ? { onDismiss } : {}),
|
|
365
|
+
...(onAutoClose !== undefined ? { onAutoClose } : {}),
|
|
366
|
+
};
|
|
367
|
+
this._toasts.update((list) => [...list, item]);
|
|
368
|
+
this.scheduleAutoDismiss(id, durationMs);
|
|
369
|
+
return id;
|
|
370
|
+
}
|
|
371
|
+
updateToast(id, message, variant, durationMs) {
|
|
372
|
+
let found = false;
|
|
373
|
+
this._toasts.update((toasts) => toasts.map((toast) => {
|
|
374
|
+
if (toast.id !== id) {
|
|
375
|
+
return toast;
|
|
376
|
+
}
|
|
377
|
+
found = true;
|
|
378
|
+
return { ...toast, message, variant };
|
|
379
|
+
}));
|
|
380
|
+
if (found) {
|
|
381
|
+
this.scheduleAutoDismiss(id, durationMs);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
removeToast(id, cause) {
|
|
385
|
+
const toast = this._toasts().find((t) => t.id === id);
|
|
386
|
+
if (!toast) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
this.cancelAutoDismiss(id);
|
|
390
|
+
this._toasts.update((list) => list.filter((t) => t.id !== id));
|
|
391
|
+
if (cause === 'auto') {
|
|
392
|
+
toast.onAutoClose?.();
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
toast.onDismiss?.();
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ToasterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
399
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ToasterService, providedIn: 'root' });
|
|
400
|
+
}
|
|
401
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: ToasterService, decorators: [{
|
|
402
|
+
type: Injectable,
|
|
403
|
+
args: [{ providedIn: 'root' }]
|
|
404
|
+
}] });
|
|
405
|
+
|
|
406
|
+
const TOASTER_POSITIONS = [
|
|
407
|
+
'top-left',
|
|
408
|
+
'top-center',
|
|
409
|
+
'top-right',
|
|
410
|
+
'bottom-left',
|
|
411
|
+
'bottom-center',
|
|
412
|
+
'bottom-right',
|
|
413
|
+
];
|
|
414
|
+
/** Default `aria-label` for the toaster live region (`<section>`). */
|
|
415
|
+
const DEFAULT_TOASTER_ARIA_NOTIFICATIONS_REGION = 'Notifications';
|
|
416
|
+
/** Default `aria-label` for the per-toast dismiss (close) control. */
|
|
417
|
+
const DEFAULT_TOASTER_ARIA_DISMISS_BUTTON = 'Dismiss';
|
|
418
|
+
const TOAST_VARIANTS = [
|
|
419
|
+
'default',
|
|
420
|
+
'description',
|
|
421
|
+
'success',
|
|
422
|
+
'error',
|
|
423
|
+
'info',
|
|
424
|
+
'warning',
|
|
425
|
+
'loading',
|
|
426
|
+
];
|
|
427
|
+
|
|
428
|
+
const GAP = 16;
|
|
429
|
+
function swipeDirectionForPosition(position) {
|
|
430
|
+
return position.startsWith('bottom') ? 'down' : 'up';
|
|
431
|
+
}
|
|
432
|
+
function resolveToasterOffsetSide(offset, side) {
|
|
433
|
+
if (offset == null) {
|
|
434
|
+
return undefined;
|
|
435
|
+
}
|
|
436
|
+
if (typeof offset === 'string') {
|
|
437
|
+
return offset;
|
|
438
|
+
}
|
|
439
|
+
return offset[side];
|
|
440
|
+
}
|
|
441
|
+
function mergeToastHostStyles(base, override) {
|
|
442
|
+
if (!base && !override)
|
|
443
|
+
return undefined;
|
|
444
|
+
if (!base)
|
|
445
|
+
return override;
|
|
446
|
+
if (!override)
|
|
447
|
+
return base;
|
|
448
|
+
return { ...base, ...override };
|
|
449
|
+
}
|
|
450
|
+
function mergeToastClassNames(base, override) {
|
|
451
|
+
if (!base && !override)
|
|
452
|
+
return undefined;
|
|
453
|
+
if (!base)
|
|
454
|
+
return override;
|
|
455
|
+
if (!override)
|
|
456
|
+
return base;
|
|
457
|
+
return { ...base, ...override };
|
|
458
|
+
}
|
|
459
|
+
class BetterToastItem {
|
|
460
|
+
/** Shared toaster service (e.g. dismiss from the close button). */
|
|
461
|
+
toaster = inject(ToasterService);
|
|
462
|
+
/** Host element ref used to read `offsetHeight` after the first render. */
|
|
463
|
+
host = inject(ElementRef);
|
|
464
|
+
/** Toast payload (message, id, variant from the service). */
|
|
465
|
+
toast = input(...(ngDevMode ? [undefined, { debugName: "toast" }] : /* istanbul ignore next */ []));
|
|
466
|
+
/**
|
|
467
|
+
* Styles from `<app-toaster [toastOptions]>`; merged with {@link ToasterItem.style} so per-toast keys win.
|
|
468
|
+
*/
|
|
469
|
+
toasterStyle = input(...(ngDevMode ? [undefined, { debugName: "toasterStyle" }] : /* istanbul ignore next */ []));
|
|
470
|
+
/**
|
|
471
|
+
* Classes from `<app-toaster [toastOptions]>` — same shape as {@link ToasterToastOptions.classNames}.
|
|
472
|
+
* Merged with {@link ToasterItem.classNames}; per-toast keys replace the same keys from the toaster.
|
|
473
|
+
* Styles for those classes usually need **`!important`** to override the library’s encapsulated CSS; see {@link ToastChromeClassNames}.
|
|
474
|
+
*/
|
|
475
|
+
toasterClassNames = input(...(ngDevMode ? [undefined, { debugName: "toasterClassNames" }] : /* istanbul ignore next */ []));
|
|
476
|
+
/** Which icon and color treatment to show for this row. */
|
|
477
|
+
variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
478
|
+
/** Vertical stack offset in px; bound to `--offset` on the host for layout. */
|
|
479
|
+
offset = input.required(...(ngDevMode ? [{ debugName: "offset" }] : /* istanbul ignore next */ []));
|
|
480
|
+
/** When false, the dismiss control is not rendered (toasts may still auto-dismiss or be cleared via the service). */
|
|
481
|
+
closeButton = input(true, ...(ngDevMode ? [{ debugName: "closeButton" }] : /* istanbul ignore next */ []));
|
|
482
|
+
/**
|
|
483
|
+
* Per-variant icon overrides from `<app-toaster [icons]>`.
|
|
484
|
+
* Each override must be a standalone component whose template includes the SVG artwork.
|
|
485
|
+
*/
|
|
486
|
+
customIcons = input(...(ngDevMode ? [undefined, { debugName: "customIcons" }] : /* istanbul ignore next */ []));
|
|
487
|
+
/**
|
|
488
|
+
* `aria-label` for the dismiss control; set from `<better-toaster [accessibilityLabels]>`.
|
|
489
|
+
* Default {@link DEFAULT_TOASTER_ARIA_DISMISS_BUTTON}.
|
|
490
|
+
*/
|
|
491
|
+
dismissButtonAriaLabel = input(DEFAULT_TOASTER_ARIA_DISMISS_BUTTON, ...(ngDevMode ? [{ debugName: "dismissButtonAriaLabel" }] : /* istanbul ignore next */ []));
|
|
492
|
+
/** Stack anchor from `<better-toaster [position]>` — drives swipe axis and `data-swipe-direction`. */
|
|
493
|
+
stackPosition = input('bottom-right', ...(ngDevMode ? [{ debugName: "stackPosition" }] : /* istanbul ignore next */ []));
|
|
494
|
+
/**
|
|
495
|
+
* Color palette from `<better-toaster [theme]>`; mirrored on the host as `data-theme`
|
|
496
|
+
* so item-scoped CSS can react to the chosen mode without `:host-context()`.
|
|
497
|
+
*/
|
|
498
|
+
theme = input('system', ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
|
|
499
|
+
/** Emits the measured host height in px once after the first render so the parent can stack siblings. */
|
|
500
|
+
heightChange = output();
|
|
501
|
+
/**
|
|
502
|
+
* Stacked title + optional secondary line: {@link ToastVariant} **`description`**, or any variant with
|
|
503
|
+
* non-empty {@link ToasterItem.description} ({@link ToastOptions.description} on `show` / `success` / etc.).
|
|
504
|
+
*/
|
|
505
|
+
hasDescription = computed(() => {
|
|
506
|
+
const toast = this.toast();
|
|
507
|
+
if (!toast)
|
|
508
|
+
return false;
|
|
509
|
+
if (toast.variant === 'description')
|
|
510
|
+
return true;
|
|
511
|
+
return !!toast.description?.trim();
|
|
512
|
+
}, ...(ngDevMode ? [{ debugName: "hasDescription" }] : /* istanbul ignore next */ []));
|
|
513
|
+
/** Merged inline styles for the toast (`[toastOptions].style` then per-toast `style`). */
|
|
514
|
+
hostStyle = computed(() => mergeToastHostStyles(this.toasterStyle(), this.toast()?.style), ...(ngDevMode ? [{ debugName: "hostStyle" }] : /* istanbul ignore next */ []));
|
|
515
|
+
/** Merged `[class]` strings (`[toastOptions].classNames` then per-toast `classNames`). */
|
|
516
|
+
resolvedClassNames = computed(() => mergeToastClassNames(this.toasterClassNames(), this.toast()?.classNames), ...(ngDevMode ? [{ debugName: "resolvedClassNames" }] : /* istanbul ignore next */ []));
|
|
517
|
+
/** Resolved standalone SVG icon component from `[icons]`, if any (not `null`). */
|
|
518
|
+
iconComponent = computed(() => {
|
|
519
|
+
const customIcon = this.customIcons()?.[this.variant()];
|
|
520
|
+
if (customIcon === null) {
|
|
521
|
+
return undefined;
|
|
522
|
+
}
|
|
523
|
+
return customIcon;
|
|
524
|
+
}, ...(ngDevMode ? [{ debugName: "iconComponent" }] : /* istanbul ignore next */ []));
|
|
525
|
+
/**
|
|
526
|
+
* Renders the icon column unless the toast or `[icons]` opts out with `icon: null` / a `null` entry for that variant.
|
|
527
|
+
* The `default` variant has no built-in icon: the column appears only with a per-toast `icon` or `[icons].default`.
|
|
528
|
+
*/
|
|
529
|
+
shouldShowIconColumn = computed(() => {
|
|
530
|
+
const toast = this.toast();
|
|
531
|
+
if (!toast)
|
|
532
|
+
return false;
|
|
533
|
+
if (toast.icon === null)
|
|
534
|
+
return false;
|
|
535
|
+
const toastVariant = toast.variant;
|
|
536
|
+
if (toastVariant === 'default' || toastVariant === 'description') {
|
|
537
|
+
if (toast.icon != null) {
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
const neutralIcon = toastVariant === 'default'
|
|
541
|
+
? this.customIcons()?.default
|
|
542
|
+
: (this.customIcons()?.description ?? this.customIcons()?.default);
|
|
543
|
+
if (neutralIcon === null) {
|
|
544
|
+
return false;
|
|
545
|
+
}
|
|
546
|
+
return neutralIcon !== undefined;
|
|
547
|
+
}
|
|
548
|
+
if (toast.icon != null) {
|
|
549
|
+
return true;
|
|
550
|
+
}
|
|
551
|
+
if (this.customIcons()?.[toastVariant] === null) {
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
return true;
|
|
555
|
+
}, ...(ngDevMode ? [{ debugName: "shouldShowIconColumn" }] : /* istanbul ignore next */ []));
|
|
556
|
+
/** Bound to {@link ToasterItem.componentInputs} for headless (`NgComponentOutlet`) toasts. */
|
|
557
|
+
componentOutletInputs = computed(() => this.toast()?.componentInputs ?? {}, ...(ngDevMode ? [{ debugName: "componentOutletInputs" }] : /* istanbul ignore next */ []));
|
|
558
|
+
/** Bound to {@link ToasterItem.contentComponentInputs} for {@link ToasterService.custom} body components. */
|
|
559
|
+
contentComponentOutletInputs = computed(() => this.toast()?.contentComponentInputs ?? {}, ...(ngDevMode ? [{ debugName: "contentComponentOutletInputs" }] : /* istanbul ignore next */ []));
|
|
560
|
+
/** When true, host uses no default toast chrome (border, padding, surface) — only stack + motion. */
|
|
561
|
+
isHeadless = computed(() => this.toast()?.component != null, ...(ngDevMode ? [{ debugName: "isHeadless" }] : /* istanbul ignore next */ []));
|
|
562
|
+
/** `down` when anchored to the bottom (dismiss by swiping down), `up` when anchored to the top. */
|
|
563
|
+
swipeDirection = computed(() => swipeDirectionForPosition(this.stackPosition()), ...(ngDevMode ? [{ debugName: "swipeDirection" }] : /* istanbul ignore next */ []));
|
|
564
|
+
/**
|
|
565
|
+
* Emits the measured host height in px once after the first render so the parent can stack siblings.
|
|
566
|
+
*/
|
|
567
|
+
constructor() {
|
|
568
|
+
afterNextRender(() => {
|
|
569
|
+
const height = this.host.nativeElement.offsetHeight;
|
|
570
|
+
this.heightChange.emit(height);
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
/** True once the user has passed the drag threshold and is actively swiping. */
|
|
574
|
+
isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : /* istanbul ignore next */ []));
|
|
575
|
+
tracking = false;
|
|
576
|
+
startY = 0;
|
|
577
|
+
pointerId = -1;
|
|
578
|
+
dragStartThreshold = 0;
|
|
579
|
+
swipeCloseThreshold = 30;
|
|
580
|
+
/** Transform applied when swipe-dismiss completes (matches leave direction / headless centering). */
|
|
581
|
+
swipeDismissTransform = computed(() => {
|
|
582
|
+
const pos = this.stackPosition();
|
|
583
|
+
const down = this.swipeDirection() === 'down';
|
|
584
|
+
const y = down ? '130%' : '-130%';
|
|
585
|
+
if (this.isHeadless() && (pos === 'bottom-center' || pos === 'top-center')) {
|
|
586
|
+
return `translateX(-50%) translateY(${y})`;
|
|
587
|
+
}
|
|
588
|
+
return `translateY(${y})`;
|
|
589
|
+
}, ...(ngDevMode ? [{ debugName: "swipeDismissTransform" }] : /* istanbul ignore next */ []));
|
|
590
|
+
/** Prevents swipe-to-dismiss from starting when pressing the row action / cancel control. */
|
|
591
|
+
onRowButtonPointerDown(event) {
|
|
592
|
+
event.stopPropagation();
|
|
593
|
+
}
|
|
594
|
+
/**
|
|
595
|
+
* Dismisses the toast when the row action / cancel control is clicked.
|
|
596
|
+
* @param event - The event object.
|
|
597
|
+
*/
|
|
598
|
+
onToastRowClick(event) {
|
|
599
|
+
const toast = this.toast();
|
|
600
|
+
toast?.toastAction?.onClick(event);
|
|
601
|
+
if (event.defaultPrevented)
|
|
602
|
+
return;
|
|
603
|
+
this.toaster.dismiss(toast?.id ?? '');
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Pauses auto-dismiss when the pointer enters the toast.
|
|
607
|
+
*/
|
|
608
|
+
onPointerEnter() {
|
|
609
|
+
const id = this.toast()?.id;
|
|
610
|
+
if (id) {
|
|
611
|
+
this.toaster.pauseAutoDismiss(id);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Resumes auto-dismiss when the pointer leaves the toast.
|
|
616
|
+
*/
|
|
617
|
+
onPointerLeave() {
|
|
618
|
+
const id = this.toast()?.id;
|
|
619
|
+
if (id) {
|
|
620
|
+
this.toaster.resumeAutoDismiss(id);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Starts tracking the pointer down event.
|
|
625
|
+
* @param event - The pointer down event object.
|
|
626
|
+
*/
|
|
627
|
+
onPointerDown(event) {
|
|
628
|
+
if (this.variant() === 'loading') {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
this.tracking = true;
|
|
632
|
+
this.startY = event.clientY;
|
|
633
|
+
this.pointerId = event.pointerId;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Updates the toast position when the pointer moves.
|
|
637
|
+
* @param event - The pointer move event object.
|
|
638
|
+
*/
|
|
639
|
+
onPointerMove(event) {
|
|
640
|
+
if (!this.tracking && !this.isDragging())
|
|
641
|
+
return;
|
|
642
|
+
const el = this.host.nativeElement;
|
|
643
|
+
const rawDy = event.clientY - this.startY;
|
|
644
|
+
const down = this.swipeDirection() === 'down';
|
|
645
|
+
const dragDy = down ? Math.max(0, rawDy) : Math.min(0, rawDy);
|
|
646
|
+
if (!this.isDragging()) {
|
|
647
|
+
const passed = this.dragStartThreshold > 0
|
|
648
|
+
? down
|
|
649
|
+
? rawDy >= this.dragStartThreshold
|
|
650
|
+
: rawDy <= -this.dragStartThreshold
|
|
651
|
+
: down
|
|
652
|
+
? rawDy > 0
|
|
653
|
+
: rawDy < 0;
|
|
654
|
+
if (passed) {
|
|
655
|
+
this.isDragging.set(true);
|
|
656
|
+
el.setPointerCapture(this.pointerId);
|
|
657
|
+
}
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
el.style.translate = `0 ${dragDy}px`;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Ends tracking the pointer up event and dismisses the toast if the pointer has moved beyond the swipe threshold.
|
|
664
|
+
*/
|
|
665
|
+
onPointerUp() {
|
|
666
|
+
this.tracking = false;
|
|
667
|
+
if (!this.isDragging())
|
|
668
|
+
return;
|
|
669
|
+
this.isDragging.set(false);
|
|
670
|
+
const el = this.host.nativeElement;
|
|
671
|
+
const id = this.toast()?.id ?? '';
|
|
672
|
+
const dy = parseFloat(el.style.translate?.split(' ')[1]) || 0;
|
|
673
|
+
try {
|
|
674
|
+
el.releasePointerCapture(this.pointerId);
|
|
675
|
+
}
|
|
676
|
+
catch {
|
|
677
|
+
/* pointer already released */
|
|
678
|
+
}
|
|
679
|
+
const down = this.swipeDirection() === 'down';
|
|
680
|
+
const shouldDismiss = down ? dy >= this.swipeCloseThreshold : dy <= -this.swipeCloseThreshold;
|
|
681
|
+
if (shouldDismiss) {
|
|
682
|
+
el.style.transform = this.swipeDismissTransform();
|
|
683
|
+
this.toaster.dismiss(id);
|
|
684
|
+
}
|
|
685
|
+
else {
|
|
686
|
+
el.style.transition = 'translate 400ms ease';
|
|
687
|
+
el.style.translate = '0 0';
|
|
688
|
+
const cleanup = () => {
|
|
689
|
+
el.style.transition = '';
|
|
690
|
+
el.style.translate = '';
|
|
691
|
+
};
|
|
692
|
+
el.addEventListener('transitionend', cleanup, { once: true });
|
|
693
|
+
setTimeout(cleanup, 450);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* Ends tracking the pointer cancel event and resets the toast position.
|
|
698
|
+
*/
|
|
699
|
+
onPointerCancel() {
|
|
700
|
+
this.tracking = false;
|
|
701
|
+
if (!this.isDragging())
|
|
702
|
+
return;
|
|
703
|
+
this.isDragging.set(false);
|
|
704
|
+
const el = this.host.nativeElement;
|
|
705
|
+
el.style.translate = '';
|
|
706
|
+
try {
|
|
707
|
+
el.releasePointerCapture(this.pointerId);
|
|
708
|
+
}
|
|
709
|
+
catch {
|
|
710
|
+
/* pointer already released */
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: BetterToastItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
714
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: BetterToastItem, isStandalone: true, selector: "li[betterToastItem]", inputs: { toast: { classPropertyName: "toast", publicName: "toast", isSignal: true, isRequired: false, transformFunction: null }, toasterStyle: { classPropertyName: "toasterStyle", publicName: "toasterStyle", isSignal: true, isRequired: false, transformFunction: null }, toasterClassNames: { classPropertyName: "toasterClassNames", publicName: "toasterClassNames", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: true, transformFunction: null }, closeButton: { classPropertyName: "closeButton", publicName: "closeButton", isSignal: true, isRequired: false, transformFunction: null }, customIcons: { classPropertyName: "customIcons", publicName: "customIcons", isSignal: true, isRequired: false, transformFunction: null }, dismissButtonAriaLabel: { classPropertyName: "dismissButtonAriaLabel", publicName: "dismissButtonAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, stackPosition: { classPropertyName: "stackPosition", publicName: "stackPosition", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { heightChange: "heightChange" }, host: { attributes: { "role": "listitem", "tabindex": "0" }, listeners: { "pointerdown": "onPointerDown($event)", "pointermove": "onPointerMove($event)", "pointerup": "onPointerUp()", "pointercancel": "onPointerCancel()", "pointerenter": "onPointerEnter()", "pointerleave": "onPointerLeave()" }, properties: { "class": "resolvedClassNames()?.toast", "attr.data-variant": "variant()", "attr.data-icon": "shouldShowIconColumn() ? \"true\" : \"false\"", "attr.data-headless": "isHeadless() ? \"true\" : null", "attr.data-swipe-direction": "swipeDirection()", "attr.data-theme": "theme()", "style.--offset": "offset() + \"px\"", "style": "isHeadless() ? undefined : hostStyle()", "animate.leave": "\"leave\"" }, classAttribute: "toast" }, ngImport: i0, template: `
|
|
715
|
+
@if (toast()?.component) {
|
|
716
|
+
<ng-container *ngComponentOutlet="toast()!.component!; inputs: componentOutletInputs()" />
|
|
717
|
+
} @else {
|
|
718
|
+
@if (shouldShowIconColumn()) {
|
|
719
|
+
<span class="toast-icon" aria-hidden="true">
|
|
720
|
+
@if (toast()?.icon) {
|
|
721
|
+
<ng-container *ngComponentOutlet="toast()!.icon!" />
|
|
722
|
+
} @else if (iconComponent(); as IconCmp) {
|
|
723
|
+
<ng-container *ngComponentOutlet="IconCmp" />
|
|
724
|
+
} @else {
|
|
725
|
+
@switch (variant()) {
|
|
726
|
+
@case ('success') {
|
|
727
|
+
<svg
|
|
728
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
729
|
+
fill="none"
|
|
730
|
+
viewBox="0 0 24 24"
|
|
731
|
+
aria-hidden="true"
|
|
732
|
+
>
|
|
733
|
+
<circle
|
|
734
|
+
cx="12"
|
|
735
|
+
cy="12"
|
|
736
|
+
r="9"
|
|
737
|
+
stroke="currentColor"
|
|
738
|
+
stroke-linecap="round"
|
|
739
|
+
stroke-linejoin="round"
|
|
740
|
+
stroke-width="1.75"
|
|
741
|
+
/>
|
|
742
|
+
<path
|
|
743
|
+
stroke="currentColor"
|
|
744
|
+
stroke-linecap="round"
|
|
745
|
+
stroke-linejoin="round"
|
|
746
|
+
stroke-width="1.75"
|
|
747
|
+
d="M8.48 12.22 10.9 14.64 15.74 9.14"
|
|
748
|
+
/>
|
|
749
|
+
</svg>
|
|
750
|
+
}
|
|
751
|
+
@case ('error') {
|
|
752
|
+
<svg
|
|
753
|
+
aria-hidden="true"
|
|
754
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
755
|
+
viewBox="0 0 24 24"
|
|
756
|
+
fill="none"
|
|
757
|
+
stroke="currentColor"
|
|
758
|
+
stroke-width="2"
|
|
759
|
+
stroke-linecap="round"
|
|
760
|
+
stroke-linejoin="round"
|
|
761
|
+
>
|
|
762
|
+
<circle cx="12" cy="12" r="10" />
|
|
763
|
+
<line x1="9" y1="9" x2="15" y2="15" />
|
|
764
|
+
<line x1="15" y1="9" x2="9" y2="15" />
|
|
765
|
+
</svg>
|
|
766
|
+
}
|
|
767
|
+
@case ('info') {
|
|
768
|
+
<svg
|
|
769
|
+
aria-hidden="true"
|
|
770
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
771
|
+
viewBox="0 0 24 24"
|
|
772
|
+
fill="none"
|
|
773
|
+
stroke="currentColor"
|
|
774
|
+
stroke-width="1.75"
|
|
775
|
+
stroke-linecap="round"
|
|
776
|
+
stroke-linejoin="round"
|
|
777
|
+
>
|
|
778
|
+
<circle cx="12" cy="12" r="10" />
|
|
779
|
+
<line x1="12" y1="16" x2="12" y2="12" />
|
|
780
|
+
<line x1="12" y1="8" x2="12.01" y2="8" />
|
|
781
|
+
</svg>
|
|
782
|
+
}
|
|
783
|
+
@case ('warning') {
|
|
784
|
+
<svg
|
|
785
|
+
aria-hidden="true"
|
|
786
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
787
|
+
fill="none"
|
|
788
|
+
viewBox="0 0 24 24"
|
|
789
|
+
>
|
|
790
|
+
<path
|
|
791
|
+
stroke="currentColor"
|
|
792
|
+
stroke-linecap="round"
|
|
793
|
+
stroke-linejoin="round"
|
|
794
|
+
stroke-width="1.75"
|
|
795
|
+
d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z"
|
|
796
|
+
/>
|
|
797
|
+
</svg>
|
|
798
|
+
}
|
|
799
|
+
@case ('loading') {
|
|
800
|
+
<div class="toast-icon-loading" aria-hidden="true"></div>
|
|
801
|
+
}
|
|
802
|
+
@case ('description') {}
|
|
803
|
+
@case ('default') {}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
</span>
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
@if (hasDescription()) {
|
|
810
|
+
<div class="stack">
|
|
811
|
+
@if (toast()?.contentComponent) {
|
|
812
|
+
<div class="msg" [class]="resolvedClassNames()?.message">
|
|
813
|
+
<ng-container
|
|
814
|
+
*ngComponentOutlet="
|
|
815
|
+
toast()!.contentComponent!;
|
|
816
|
+
inputs: contentComponentOutletInputs()
|
|
817
|
+
"
|
|
818
|
+
/>
|
|
819
|
+
</div>
|
|
820
|
+
} @else {
|
|
821
|
+
<p class="msg" [class]="resolvedClassNames()?.message">{{ toast()?.message }}</p>
|
|
822
|
+
}
|
|
823
|
+
@if (toast()?.description) {
|
|
824
|
+
<p class="description" [class]="resolvedClassNames()?.description">
|
|
825
|
+
{{ toast()!.description }}
|
|
826
|
+
</p>
|
|
827
|
+
}
|
|
828
|
+
</div>
|
|
829
|
+
} @else {
|
|
830
|
+
@if (toast()?.contentComponent) {
|
|
831
|
+
<div class="msg" [class]="resolvedClassNames()?.message">
|
|
832
|
+
<ng-container
|
|
833
|
+
*ngComponentOutlet="
|
|
834
|
+
toast()!.contentComponent!;
|
|
835
|
+
inputs: contentComponentOutletInputs()
|
|
836
|
+
"
|
|
837
|
+
/>
|
|
838
|
+
</div>
|
|
839
|
+
} @else {
|
|
840
|
+
<p class="msg" [class]="resolvedClassNames()?.message">{{ toast()?.message }}</p>
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
@if (toast()?.toastAction; as rowAction) {
|
|
845
|
+
@switch (rowAction.role) {
|
|
846
|
+
@case ('action') {
|
|
847
|
+
<button
|
|
848
|
+
type="button"
|
|
849
|
+
class="toast-row-btn action-btn"
|
|
850
|
+
[class]="resolvedClassNames()?.actionButton"
|
|
851
|
+
[attr.data-row-btn]="rowAction.role"
|
|
852
|
+
(pointerdown)="onRowButtonPointerDown($event)"
|
|
853
|
+
(click)="onToastRowClick($event)"
|
|
854
|
+
>
|
|
855
|
+
{{ rowAction.label }}
|
|
856
|
+
</button>
|
|
857
|
+
}
|
|
858
|
+
@case ('cancel') {
|
|
859
|
+
<button
|
|
860
|
+
type="button"
|
|
861
|
+
class="toast-row-btn cancel-btn"
|
|
862
|
+
[class]="resolvedClassNames()?.cancelButton"
|
|
863
|
+
[attr.data-row-btn]="rowAction.role"
|
|
864
|
+
(pointerdown)="onRowButtonPointerDown($event)"
|
|
865
|
+
(click)="onToastRowClick($event)"
|
|
866
|
+
>
|
|
867
|
+
{{ rowAction.label }}
|
|
868
|
+
</button>
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
@if (closeButton() && !isHeadless()) {
|
|
875
|
+
<button
|
|
876
|
+
type="button"
|
|
877
|
+
class="close-btn"
|
|
878
|
+
[class]="resolvedClassNames()?.closeButton"
|
|
879
|
+
(click)="toaster.dismiss(toast()?.id ?? '')"
|
|
880
|
+
[attr.aria-label]="dismissButtonAriaLabel()"
|
|
881
|
+
>
|
|
882
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
883
|
+
<path
|
|
884
|
+
stroke="currentColor"
|
|
885
|
+
stroke-linecap="round"
|
|
886
|
+
stroke-linejoin="round"
|
|
887
|
+
stroke-width="1.75"
|
|
888
|
+
d="M6 18 18 6M6 6l12 12"
|
|
889
|
+
/>
|
|
890
|
+
</svg>
|
|
891
|
+
</button>
|
|
892
|
+
}
|
|
893
|
+
`, isInline: true, styles: [":host{display:flex;align-items:center;gap:.375rem;flex:1;min-width:0;width:100%;padding-inline:.75rem;padding-block:1rem;box-sizing:border-box;border:1px solid var(--toast-border-color);border-radius:.5rem;box-shadow:var(--toast-shadow);background:var(--toast-bg);color:var(--toast-color);--toast-line-height: 1.35;font:500 .875rem/var(--toast-line-height) system-ui,sans-serif;pointer-events:auto;touch-action:none;-webkit-user-select:none;user-select:none;position:absolute;opacity:1;scale:1;transition:opacity .4s ease,transform .4s ease,scale .4s ease}:host([data-variant=\"loading\"]){touch-action:auto}@media(width>=40rem){:host{width:var(--toast-width)}}:host([data-position^=\"bottom\"]){bottom:0;transform:translateY(calc(-1 * var(--offset, 0px)))}@starting-style{:host([data-position^=\"bottom\"]){opacity:0;transform:translateY(100%)}}:host([data-position^=\"top\"]){top:0;transform:translateY(calc(1 * var(--offset, 0px)))}@starting-style{:host([data-position^=\"top\"]){opacity:0;transform:translateY(-100%)}}@starting-style{:host([data-headless=\"true\"][data-position^=\"bottom\"]){opacity:1}}@starting-style{:host([data-headless=\"true\"][data-position^=\"top\"]){opacity:1}}:host([data-variant=\"default\"]) .toast-icon svg,:host([data-variant=\"default\"]) .toast-icon ::ng-deep svg,:host([data-variant=\"description\"]) .toast-icon svg,:host([data-variant=\"description\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-color),var(--toast-bg));color:light-dark(var(--toast-bg),var(--toast-color))}:host([data-rich-colors=\"true\"][data-variant=\"success\"]){background:var(--toast-success-bg);color:var(--toast-success-text);border-color:var(--toast-success-border)}:host([data-rich-colors=\"false\"][data-variant=\"success\"]) .toast-icon svg,:host([data-rich-colors=\"false\"][data-variant=\"success\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-color),var(--toast-bg));color:light-dark(var(--toast-bg),var(--toast-color))}:host([data-rich-colors=\"true\"][data-variant=\"success\"]) .toast-icon svg,:host([data-rich-colors=\"true\"][data-variant=\"success\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-success-text),var(--toast-success-bg));stroke:light-dark(var(--toast-success-bg),var(--toast-success-text));color:light-dark(var(--toast-success-bg),var(--toast-success-text))}:host([data-rich-colors=\"true\"][data-variant=\"error\"]){background:var(--toast-error-bg);color:var(--toast-error-text);border-color:var(--toast-error-border)}:host([data-rich-colors=\"false\"][data-variant=\"error\"]) .toast-icon svg,:host([data-rich-colors=\"false\"][data-variant=\"error\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-color),var(--toast-bg));color:light-dark(var(--toast-bg),var(--toast-color))}:host([data-rich-colors=\"true\"][data-variant=\"error\"]) .toast-icon svg,:host([data-rich-colors=\"true\"][data-variant=\"error\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-error-text),var(--toast-error-bg));stroke:light-dark(var(--toast-error-bg),var(--toast-error-text));color:light-dark(var(--toast-error-bg),var(--toast-error-text))}:host([data-rich-colors=\"true\"][data-variant=\"info\"]){background:var(--toast-info-bg);color:var(--toast-info-text);border-color:var(--toast-info-border)}:host([data-rich-colors=\"false\"][data-variant=\"info\"]) .toast-icon svg,:host([data-rich-colors=\"false\"][data-variant=\"info\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-color),var(--toast-bg));color:light-dark(var(--toast-bg),var(--toast-color))}:host([data-rich-colors=\"true\"][data-variant=\"info\"]) .toast-icon svg,:host([data-rich-colors=\"true\"][data-variant=\"info\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-info-text),var(--toast-info-bg));stroke:light-dark(var(--toast-info-bg),var(--toast-info-text));color:light-dark(var(--toast-info-bg),var(--toast-info-text))}:host([data-rich-colors=\"true\"][data-variant=\"warning\"]){background:var(--toast-warning-bg);color:var(--toast-warning-text);border-color:var(--toast-warning-border)}:host([data-rich-colors=\"false\"][data-variant=\"warning\"]) .toast-icon svg,:host([data-rich-colors=\"false\"][data-variant=\"warning\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-color),var(--toast-bg));color:light-dark(var(--toast-bg),var(--toast-color))}:host([data-rich-colors=\"true\"][data-variant=\"warning\"]) .toast-icon svg,:host([data-rich-colors=\"true\"][data-variant=\"warning\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-warning-text),var(--toast-warning-bg));stroke:light-dark(var(--toast-warning-bg),var(--toast-warning-text));color:light-dark(var(--toast-warning-bg),var(--toast-warning-text))}:host([data-headless=\"true\"]){width:max-content;max-width:calc(100dvw - var(--toast-offset-mobile-left, 16px) - var(--toast-offset-mobile-right, 16px));padding:0;gap:0;border:none;border-radius:0;box-shadow:none;background:transparent;color:inherit;font:inherit;line-height:normal;--toast-line-height: inherit}@media(width>=40rem){:host([data-headless=\"true\"]){max-width:calc(100dvw - var(--toast-offset-left, 24px) - var(--toast-offset-right, 24px))}}@media(width>=40rem){:host([data-headless=\"true\"][data-position$=\"-right\"]){left:auto;right:0}:host([data-headless=\"true\"][data-position$=\"-left\"]){left:0;right:auto}}:host([data-headless=\"true\"][data-position=\"bottom-center\"]){left:50%;right:auto;transform:translate(-50%) translateY(calc(-1 * var(--offset, 0px)))}@starting-style{:host([data-headless=\"true\"][data-position=\"bottom-center\"]){opacity:1;transform:translate(-50%) translateY(100%)}}:host([data-headless=\"true\"][data-position=\"top-center\"]){left:50%;right:auto;transform:translate(-50%) translateY(calc(1 * var(--offset, 0px)))}@starting-style{:host([data-headless=\"true\"][data-position=\"top-center\"]){opacity:1;transform:translate(-50%) translateY(-100%)}}@media(width<40rem){:host([data-headless=\"true\"][data-position^=\"bottom\"]){left:50%;right:auto;transform:translate(-50%) translateY(calc(-1 * var(--offset, 0px)))}@starting-style{:host([data-headless=\"true\"][data-position^=\"bottom\"]){opacity:1;transform:translate(-50%) translateY(100%)}}:host([data-headless=\"true\"][data-position^=\"top\"]){left:50%;right:auto;transform:translate(-50%) translateY(calc(1 * var(--offset, 0px)))}@starting-style{:host([data-headless=\"true\"][data-position^=\"top\"]){opacity:1;transform:translate(-50%) translateY(-100%)}}:host([data-headless=\"true\"][data-swipe-direction=\"down\"].leave){transform:translate(-50%) translateY(100%)}:host([data-headless=\"true\"][data-swipe-direction=\"up\"].leave){transform:translate(-50%) translateY(-100%)}}:host([data-headless=\"true\"][data-rich-colors=\"true\"]){background:transparent;color:inherit;border-color:transparent}:host([data-headless=\"true\"][data-icon=\"false\"]){padding-left:0}:host([data-icon=\"false\"]){padding-left:.925rem}.toast-icon,.toast-icon ::ng-deep{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:1.425rem;height:1.425rem}.toast-icon svg,.toast-icon ::ng-deep svg{display:block;margin-inline:auto;fill:light-dark(var(--toast-color),var(--toast-bg));stroke:light-dark(var(--toast-bg),var(--toast-color));width:95%;height:95%}:host([data-theme=\"dark\"]) .toast-icon svg,:host([data-theme=\"dark\"]) .toast-icon ::ng-deep svg{width:87.5%;height:87.5%}@media(prefers-color-scheme:dark){:host([data-theme=\"system\"]) .toast-icon svg,:host([data-theme=\"system\"]) .toast-icon ::ng-deep svg{width:87.5%;height:87.5%}}.toast-icon-loading{display:block;width:.9rem;height:.9rem;border-radius:50%;border:2px solid currentColor;border-top-color:transparent;border-right-color:transparent;animation:spin .45s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.msg{flex:1;min-width:0;max-width:95%;margin:0;font-size:.825rem;font-weight:500;line-height:calc(1.25 / .875);letter-spacing:.01em}@media(width<40rem){.msg{max-width:90%;font-size:.8rem}}.stack{display:flex;flex-direction:column;align-items:flex-start;gap:.25rem;flex:1;min-width:0}.stack .msg{flex:0 1 auto;max-width:100%}:host([data-icon=\"false\"]) .stack .msg{max-width:90%}.description{margin:0;font-size:.825rem;font-weight:400;line-height:1.35;letter-spacing:.01em;opacity:.9;max-width:100%}@media(width<40rem){.description{font-size:.8rem}}.toast-row-btn{flex-shrink:0;margin:0;margin-inline-start:auto;padding:.35rem .65rem;border-radius:.375rem;border:1px solid transparent;font:inherit;font-size:.8rem;font-weight:600;letter-spacing:.01em;line-height:1.2;cursor:pointer;white-space:nowrap;transition:transform .2s ease}.toast-row-btn:focus-visible{outline:2px solid var(--toast-color);outline-offset:2px}.toast-row-btn:active{transform:scale(.95)}@media(prefers-reduced-motion:reduce){.toast-row-btn:active{transform:none}}.action-btn{background:var(--toast-action-bg);color:var(--toast-action-text);border-color:var(--toast-action-border)}.cancel-btn{background:var(--toast-cancel-bg);color:var(--toast-color);border-color:var(--toast-cancel-border)}.toast-custom{flex:1;min-width:0;width:100%;font-size:.825rem;font-weight:400;line-height:calc(1.25 / .875)}.toast-custom :first-child{margin-top:0}.toast-custom :last-child{margin-bottom:0}.close-btn{position:absolute;top:-.3875rem;right:-.3875rem;flex-shrink:0;margin:-.15rem -.25rem -.15rem 0;border:1px solid var(--toast-border-color);box-shadow:var(--toast-shadow);background:var(--toast-bg);color:var(--toast-color);cursor:pointer;line-height:1;padding:.25rem;border-radius:50%;display:inline-flex;align-items:center;justify-content:center}:host([data-rich-colors=\"true\"][data-variant=\"success\"]) .close-btn{border-color:var(--toast-success-border);background:var(--toast-success-bg);color:var(--toast-success-text)}:host([data-rich-colors=\"true\"][data-variant=\"error\"]) .close-btn{border-color:var(--toast-error-border);background:var(--toast-error-bg);color:var(--toast-error-text)}:host([data-rich-colors=\"true\"][data-variant=\"info\"]) .close-btn{border-color:var(--toast-info-border);background:var(--toast-info-bg);color:var(--toast-info-text)}:host([data-rich-colors=\"true\"][data-variant=\"warning\"]) .close-btn{border-color:var(--toast-warning-border);background:var(--toast-warning-bg);color:var(--toast-warning-text)}.close-btn:focus-visible{outline:2px solid currentColor}.close-btn svg{display:block;width:.825rem;height:.825rem}:host(.leave){opacity:0;scale:.95}:host([data-swipe-direction=\"down\"].leave){transform:translateY(100%)}:host([data-headless=\"true\"][data-position=\"bottom-center\"].leave){transform:translate(-50%) translateY(100%)}:host([data-swipe-direction=\"up\"].leave){transform:translateY(-100%)}:host([data-headless=\"true\"][data-position=\"top-center\"].leave){transform:translate(-50%) translateY(-100%)}@media(prefers-reduced-motion:reduce){:host{transition:none}:host(.leave){scale:1}@starting-style{:host([data-position^=\"bottom\"]){opacity:0;transform:translateY(calc(-1 * var(--offset, 0px)))}}@starting-style{:host([data-position^=\"top\"]){opacity:0;transform:translateY(calc(1 * var(--offset, 0px)))}}@starting-style{:host([data-headless=\"true\"][data-position=\"bottom-center\"]){opacity:1;transform:translate(-50%) translateY(calc(-1 * var(--offset, 0px)))}}@starting-style{:host([data-headless=\"true\"][data-position=\"top-center\"]){opacity:1;transform:translate(-50%) translateY(calc(1 * var(--offset, 0px)))}}:host([data-swipe-direction=\"down\"].leave){transform:translateY(calc(-1 * var(--offset, 0px)))}:host([data-swipe-direction=\"up\"].leave){transform:translateY(calc(1 * var(--offset, 0px)))}:host([data-headless=\"true\"][data-position=\"bottom-center\"].leave){transform:translate(-50%) translateY(calc(-1 * var(--offset, 0px)))}:host([data-headless=\"true\"][data-position=\"top-center\"].leave){transform:translate(-50%) translateY(calc(1 * var(--offset, 0px)))}@media(width<40rem){@starting-style{:host([data-headless=\"true\"][data-position^=\"bottom\"]){opacity:1;transform:translate(-50%) translateY(calc(-1 * var(--offset, 0px)))}}:host([data-headless=\"true\"][data-swipe-direction=\"down\"].leave){transform:translate(-50%) translateY(calc(-1 * var(--offset, 0px)))}@starting-style{:host([data-headless=\"true\"][data-position^=\"top\"]){opacity:1;transform:translate(-50%) translateY(calc(1 * var(--offset, 0px)))}}:host([data-headless=\"true\"][data-swipe-direction=\"up\"].leave){transform:translate(-50%) translateY(calc(1 * var(--offset, 0px)))}}.toast-icon-loading{animation:none}}\n"], dependencies: [{ kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
894
|
+
}
|
|
895
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: BetterToastItem, decorators: [{
|
|
896
|
+
type: Component,
|
|
897
|
+
args: [{ selector: 'li[betterToastItem]', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgComponentOutlet], host: {
|
|
898
|
+
role: 'listitem',
|
|
899
|
+
tabindex: '0',
|
|
900
|
+
class: 'toast',
|
|
901
|
+
'[class]': 'resolvedClassNames()?.toast',
|
|
902
|
+
'[attr.data-variant]': 'variant()',
|
|
903
|
+
'[attr.data-icon]': 'shouldShowIconColumn() ? "true" : "false"',
|
|
904
|
+
'[attr.data-headless]': 'isHeadless() ? "true" : null',
|
|
905
|
+
'[attr.data-swipe-direction]': 'swipeDirection()',
|
|
906
|
+
'[attr.data-theme]': 'theme()',
|
|
907
|
+
'[style.--offset]': 'offset() + "px"',
|
|
908
|
+
'[style]': 'isHeadless() ? undefined : hostStyle()',
|
|
909
|
+
'[animate.leave]': '"leave"',
|
|
910
|
+
'(pointerdown)': 'onPointerDown($event)',
|
|
911
|
+
'(pointermove)': 'onPointerMove($event)',
|
|
912
|
+
'(pointerup)': 'onPointerUp()',
|
|
913
|
+
'(pointercancel)': 'onPointerCancel()',
|
|
914
|
+
'(pointerenter)': 'onPointerEnter()',
|
|
915
|
+
'(pointerleave)': 'onPointerLeave()',
|
|
916
|
+
}, template: `
|
|
917
|
+
@if (toast()?.component) {
|
|
918
|
+
<ng-container *ngComponentOutlet="toast()!.component!; inputs: componentOutletInputs()" />
|
|
919
|
+
} @else {
|
|
920
|
+
@if (shouldShowIconColumn()) {
|
|
921
|
+
<span class="toast-icon" aria-hidden="true">
|
|
922
|
+
@if (toast()?.icon) {
|
|
923
|
+
<ng-container *ngComponentOutlet="toast()!.icon!" />
|
|
924
|
+
} @else if (iconComponent(); as IconCmp) {
|
|
925
|
+
<ng-container *ngComponentOutlet="IconCmp" />
|
|
926
|
+
} @else {
|
|
927
|
+
@switch (variant()) {
|
|
928
|
+
@case ('success') {
|
|
929
|
+
<svg
|
|
930
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
931
|
+
fill="none"
|
|
932
|
+
viewBox="0 0 24 24"
|
|
933
|
+
aria-hidden="true"
|
|
934
|
+
>
|
|
935
|
+
<circle
|
|
936
|
+
cx="12"
|
|
937
|
+
cy="12"
|
|
938
|
+
r="9"
|
|
939
|
+
stroke="currentColor"
|
|
940
|
+
stroke-linecap="round"
|
|
941
|
+
stroke-linejoin="round"
|
|
942
|
+
stroke-width="1.75"
|
|
943
|
+
/>
|
|
944
|
+
<path
|
|
945
|
+
stroke="currentColor"
|
|
946
|
+
stroke-linecap="round"
|
|
947
|
+
stroke-linejoin="round"
|
|
948
|
+
stroke-width="1.75"
|
|
949
|
+
d="M8.48 12.22 10.9 14.64 15.74 9.14"
|
|
950
|
+
/>
|
|
951
|
+
</svg>
|
|
952
|
+
}
|
|
953
|
+
@case ('error') {
|
|
954
|
+
<svg
|
|
955
|
+
aria-hidden="true"
|
|
956
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
957
|
+
viewBox="0 0 24 24"
|
|
958
|
+
fill="none"
|
|
959
|
+
stroke="currentColor"
|
|
960
|
+
stroke-width="2"
|
|
961
|
+
stroke-linecap="round"
|
|
962
|
+
stroke-linejoin="round"
|
|
963
|
+
>
|
|
964
|
+
<circle cx="12" cy="12" r="10" />
|
|
965
|
+
<line x1="9" y1="9" x2="15" y2="15" />
|
|
966
|
+
<line x1="15" y1="9" x2="9" y2="15" />
|
|
967
|
+
</svg>
|
|
968
|
+
}
|
|
969
|
+
@case ('info') {
|
|
970
|
+
<svg
|
|
971
|
+
aria-hidden="true"
|
|
972
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
973
|
+
viewBox="0 0 24 24"
|
|
974
|
+
fill="none"
|
|
975
|
+
stroke="currentColor"
|
|
976
|
+
stroke-width="1.75"
|
|
977
|
+
stroke-linecap="round"
|
|
978
|
+
stroke-linejoin="round"
|
|
979
|
+
>
|
|
980
|
+
<circle cx="12" cy="12" r="10" />
|
|
981
|
+
<line x1="12" y1="16" x2="12" y2="12" />
|
|
982
|
+
<line x1="12" y1="8" x2="12.01" y2="8" />
|
|
983
|
+
</svg>
|
|
984
|
+
}
|
|
985
|
+
@case ('warning') {
|
|
986
|
+
<svg
|
|
987
|
+
aria-hidden="true"
|
|
988
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
989
|
+
fill="none"
|
|
990
|
+
viewBox="0 0 24 24"
|
|
991
|
+
>
|
|
992
|
+
<path
|
|
993
|
+
stroke="currentColor"
|
|
994
|
+
stroke-linecap="round"
|
|
995
|
+
stroke-linejoin="round"
|
|
996
|
+
stroke-width="1.75"
|
|
997
|
+
d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z"
|
|
998
|
+
/>
|
|
999
|
+
</svg>
|
|
1000
|
+
}
|
|
1001
|
+
@case ('loading') {
|
|
1002
|
+
<div class="toast-icon-loading" aria-hidden="true"></div>
|
|
1003
|
+
}
|
|
1004
|
+
@case ('description') {}
|
|
1005
|
+
@case ('default') {}
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
</span>
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
@if (hasDescription()) {
|
|
1012
|
+
<div class="stack">
|
|
1013
|
+
@if (toast()?.contentComponent) {
|
|
1014
|
+
<div class="msg" [class]="resolvedClassNames()?.message">
|
|
1015
|
+
<ng-container
|
|
1016
|
+
*ngComponentOutlet="
|
|
1017
|
+
toast()!.contentComponent!;
|
|
1018
|
+
inputs: contentComponentOutletInputs()
|
|
1019
|
+
"
|
|
1020
|
+
/>
|
|
1021
|
+
</div>
|
|
1022
|
+
} @else {
|
|
1023
|
+
<p class="msg" [class]="resolvedClassNames()?.message">{{ toast()?.message }}</p>
|
|
1024
|
+
}
|
|
1025
|
+
@if (toast()?.description) {
|
|
1026
|
+
<p class="description" [class]="resolvedClassNames()?.description">
|
|
1027
|
+
{{ toast()!.description }}
|
|
1028
|
+
</p>
|
|
1029
|
+
}
|
|
1030
|
+
</div>
|
|
1031
|
+
} @else {
|
|
1032
|
+
@if (toast()?.contentComponent) {
|
|
1033
|
+
<div class="msg" [class]="resolvedClassNames()?.message">
|
|
1034
|
+
<ng-container
|
|
1035
|
+
*ngComponentOutlet="
|
|
1036
|
+
toast()!.contentComponent!;
|
|
1037
|
+
inputs: contentComponentOutletInputs()
|
|
1038
|
+
"
|
|
1039
|
+
/>
|
|
1040
|
+
</div>
|
|
1041
|
+
} @else {
|
|
1042
|
+
<p class="msg" [class]="resolvedClassNames()?.message">{{ toast()?.message }}</p>
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
@if (toast()?.toastAction; as rowAction) {
|
|
1047
|
+
@switch (rowAction.role) {
|
|
1048
|
+
@case ('action') {
|
|
1049
|
+
<button
|
|
1050
|
+
type="button"
|
|
1051
|
+
class="toast-row-btn action-btn"
|
|
1052
|
+
[class]="resolvedClassNames()?.actionButton"
|
|
1053
|
+
[attr.data-row-btn]="rowAction.role"
|
|
1054
|
+
(pointerdown)="onRowButtonPointerDown($event)"
|
|
1055
|
+
(click)="onToastRowClick($event)"
|
|
1056
|
+
>
|
|
1057
|
+
{{ rowAction.label }}
|
|
1058
|
+
</button>
|
|
1059
|
+
}
|
|
1060
|
+
@case ('cancel') {
|
|
1061
|
+
<button
|
|
1062
|
+
type="button"
|
|
1063
|
+
class="toast-row-btn cancel-btn"
|
|
1064
|
+
[class]="resolvedClassNames()?.cancelButton"
|
|
1065
|
+
[attr.data-row-btn]="rowAction.role"
|
|
1066
|
+
(pointerdown)="onRowButtonPointerDown($event)"
|
|
1067
|
+
(click)="onToastRowClick($event)"
|
|
1068
|
+
>
|
|
1069
|
+
{{ rowAction.label }}
|
|
1070
|
+
</button>
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
@if (closeButton() && !isHeadless()) {
|
|
1077
|
+
<button
|
|
1078
|
+
type="button"
|
|
1079
|
+
class="close-btn"
|
|
1080
|
+
[class]="resolvedClassNames()?.closeButton"
|
|
1081
|
+
(click)="toaster.dismiss(toast()?.id ?? '')"
|
|
1082
|
+
[attr.aria-label]="dismissButtonAriaLabel()"
|
|
1083
|
+
>
|
|
1084
|
+
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
1085
|
+
<path
|
|
1086
|
+
stroke="currentColor"
|
|
1087
|
+
stroke-linecap="round"
|
|
1088
|
+
stroke-linejoin="round"
|
|
1089
|
+
stroke-width="1.75"
|
|
1090
|
+
d="M6 18 18 6M6 6l12 12"
|
|
1091
|
+
/>
|
|
1092
|
+
</svg>
|
|
1093
|
+
</button>
|
|
1094
|
+
}
|
|
1095
|
+
`, styles: [":host{display:flex;align-items:center;gap:.375rem;flex:1;min-width:0;width:100%;padding-inline:.75rem;padding-block:1rem;box-sizing:border-box;border:1px solid var(--toast-border-color);border-radius:.5rem;box-shadow:var(--toast-shadow);background:var(--toast-bg);color:var(--toast-color);--toast-line-height: 1.35;font:500 .875rem/var(--toast-line-height) system-ui,sans-serif;pointer-events:auto;touch-action:none;-webkit-user-select:none;user-select:none;position:absolute;opacity:1;scale:1;transition:opacity .4s ease,transform .4s ease,scale .4s ease}:host([data-variant=\"loading\"]){touch-action:auto}@media(width>=40rem){:host{width:var(--toast-width)}}:host([data-position^=\"bottom\"]){bottom:0;transform:translateY(calc(-1 * var(--offset, 0px)))}@starting-style{:host([data-position^=\"bottom\"]){opacity:0;transform:translateY(100%)}}:host([data-position^=\"top\"]){top:0;transform:translateY(calc(1 * var(--offset, 0px)))}@starting-style{:host([data-position^=\"top\"]){opacity:0;transform:translateY(-100%)}}@starting-style{:host([data-headless=\"true\"][data-position^=\"bottom\"]){opacity:1}}@starting-style{:host([data-headless=\"true\"][data-position^=\"top\"]){opacity:1}}:host([data-variant=\"default\"]) .toast-icon svg,:host([data-variant=\"default\"]) .toast-icon ::ng-deep svg,:host([data-variant=\"description\"]) .toast-icon svg,:host([data-variant=\"description\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-color),var(--toast-bg));color:light-dark(var(--toast-bg),var(--toast-color))}:host([data-rich-colors=\"true\"][data-variant=\"success\"]){background:var(--toast-success-bg);color:var(--toast-success-text);border-color:var(--toast-success-border)}:host([data-rich-colors=\"false\"][data-variant=\"success\"]) .toast-icon svg,:host([data-rich-colors=\"false\"][data-variant=\"success\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-color),var(--toast-bg));color:light-dark(var(--toast-bg),var(--toast-color))}:host([data-rich-colors=\"true\"][data-variant=\"success\"]) .toast-icon svg,:host([data-rich-colors=\"true\"][data-variant=\"success\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-success-text),var(--toast-success-bg));stroke:light-dark(var(--toast-success-bg),var(--toast-success-text));color:light-dark(var(--toast-success-bg),var(--toast-success-text))}:host([data-rich-colors=\"true\"][data-variant=\"error\"]){background:var(--toast-error-bg);color:var(--toast-error-text);border-color:var(--toast-error-border)}:host([data-rich-colors=\"false\"][data-variant=\"error\"]) .toast-icon svg,:host([data-rich-colors=\"false\"][data-variant=\"error\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-color),var(--toast-bg));color:light-dark(var(--toast-bg),var(--toast-color))}:host([data-rich-colors=\"true\"][data-variant=\"error\"]) .toast-icon svg,:host([data-rich-colors=\"true\"][data-variant=\"error\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-error-text),var(--toast-error-bg));stroke:light-dark(var(--toast-error-bg),var(--toast-error-text));color:light-dark(var(--toast-error-bg),var(--toast-error-text))}:host([data-rich-colors=\"true\"][data-variant=\"info\"]){background:var(--toast-info-bg);color:var(--toast-info-text);border-color:var(--toast-info-border)}:host([data-rich-colors=\"false\"][data-variant=\"info\"]) .toast-icon svg,:host([data-rich-colors=\"false\"][data-variant=\"info\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-color),var(--toast-bg));color:light-dark(var(--toast-bg),var(--toast-color))}:host([data-rich-colors=\"true\"][data-variant=\"info\"]) .toast-icon svg,:host([data-rich-colors=\"true\"][data-variant=\"info\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-info-text),var(--toast-info-bg));stroke:light-dark(var(--toast-info-bg),var(--toast-info-text));color:light-dark(var(--toast-info-bg),var(--toast-info-text))}:host([data-rich-colors=\"true\"][data-variant=\"warning\"]){background:var(--toast-warning-bg);color:var(--toast-warning-text);border-color:var(--toast-warning-border)}:host([data-rich-colors=\"false\"][data-variant=\"warning\"]) .toast-icon svg,:host([data-rich-colors=\"false\"][data-variant=\"warning\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-color),var(--toast-bg));color:light-dark(var(--toast-bg),var(--toast-color))}:host([data-rich-colors=\"true\"][data-variant=\"warning\"]) .toast-icon svg,:host([data-rich-colors=\"true\"][data-variant=\"warning\"]) .toast-icon ::ng-deep svg{fill:light-dark(var(--toast-warning-text),var(--toast-warning-bg));stroke:light-dark(var(--toast-warning-bg),var(--toast-warning-text));color:light-dark(var(--toast-warning-bg),var(--toast-warning-text))}:host([data-headless=\"true\"]){width:max-content;max-width:calc(100dvw - var(--toast-offset-mobile-left, 16px) - var(--toast-offset-mobile-right, 16px));padding:0;gap:0;border:none;border-radius:0;box-shadow:none;background:transparent;color:inherit;font:inherit;line-height:normal;--toast-line-height: inherit}@media(width>=40rem){:host([data-headless=\"true\"]){max-width:calc(100dvw - var(--toast-offset-left, 24px) - var(--toast-offset-right, 24px))}}@media(width>=40rem){:host([data-headless=\"true\"][data-position$=\"-right\"]){left:auto;right:0}:host([data-headless=\"true\"][data-position$=\"-left\"]){left:0;right:auto}}:host([data-headless=\"true\"][data-position=\"bottom-center\"]){left:50%;right:auto;transform:translate(-50%) translateY(calc(-1 * var(--offset, 0px)))}@starting-style{:host([data-headless=\"true\"][data-position=\"bottom-center\"]){opacity:1;transform:translate(-50%) translateY(100%)}}:host([data-headless=\"true\"][data-position=\"top-center\"]){left:50%;right:auto;transform:translate(-50%) translateY(calc(1 * var(--offset, 0px)))}@starting-style{:host([data-headless=\"true\"][data-position=\"top-center\"]){opacity:1;transform:translate(-50%) translateY(-100%)}}@media(width<40rem){:host([data-headless=\"true\"][data-position^=\"bottom\"]){left:50%;right:auto;transform:translate(-50%) translateY(calc(-1 * var(--offset, 0px)))}@starting-style{:host([data-headless=\"true\"][data-position^=\"bottom\"]){opacity:1;transform:translate(-50%) translateY(100%)}}:host([data-headless=\"true\"][data-position^=\"top\"]){left:50%;right:auto;transform:translate(-50%) translateY(calc(1 * var(--offset, 0px)))}@starting-style{:host([data-headless=\"true\"][data-position^=\"top\"]){opacity:1;transform:translate(-50%) translateY(-100%)}}:host([data-headless=\"true\"][data-swipe-direction=\"down\"].leave){transform:translate(-50%) translateY(100%)}:host([data-headless=\"true\"][data-swipe-direction=\"up\"].leave){transform:translate(-50%) translateY(-100%)}}:host([data-headless=\"true\"][data-rich-colors=\"true\"]){background:transparent;color:inherit;border-color:transparent}:host([data-headless=\"true\"][data-icon=\"false\"]){padding-left:0}:host([data-icon=\"false\"]){padding-left:.925rem}.toast-icon,.toast-icon ::ng-deep{flex-shrink:0;display:flex;align-items:center;justify-content:center;width:1.425rem;height:1.425rem}.toast-icon svg,.toast-icon ::ng-deep svg{display:block;margin-inline:auto;fill:light-dark(var(--toast-color),var(--toast-bg));stroke:light-dark(var(--toast-bg),var(--toast-color));width:95%;height:95%}:host([data-theme=\"dark\"]) .toast-icon svg,:host([data-theme=\"dark\"]) .toast-icon ::ng-deep svg{width:87.5%;height:87.5%}@media(prefers-color-scheme:dark){:host([data-theme=\"system\"]) .toast-icon svg,:host([data-theme=\"system\"]) .toast-icon ::ng-deep svg{width:87.5%;height:87.5%}}.toast-icon-loading{display:block;width:.9rem;height:.9rem;border-radius:50%;border:2px solid currentColor;border-top-color:transparent;border-right-color:transparent;animation:spin .45s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.msg{flex:1;min-width:0;max-width:95%;margin:0;font-size:.825rem;font-weight:500;line-height:calc(1.25 / .875);letter-spacing:.01em}@media(width<40rem){.msg{max-width:90%;font-size:.8rem}}.stack{display:flex;flex-direction:column;align-items:flex-start;gap:.25rem;flex:1;min-width:0}.stack .msg{flex:0 1 auto;max-width:100%}:host([data-icon=\"false\"]) .stack .msg{max-width:90%}.description{margin:0;font-size:.825rem;font-weight:400;line-height:1.35;letter-spacing:.01em;opacity:.9;max-width:100%}@media(width<40rem){.description{font-size:.8rem}}.toast-row-btn{flex-shrink:0;margin:0;margin-inline-start:auto;padding:.35rem .65rem;border-radius:.375rem;border:1px solid transparent;font:inherit;font-size:.8rem;font-weight:600;letter-spacing:.01em;line-height:1.2;cursor:pointer;white-space:nowrap;transition:transform .2s ease}.toast-row-btn:focus-visible{outline:2px solid var(--toast-color);outline-offset:2px}.toast-row-btn:active{transform:scale(.95)}@media(prefers-reduced-motion:reduce){.toast-row-btn:active{transform:none}}.action-btn{background:var(--toast-action-bg);color:var(--toast-action-text);border-color:var(--toast-action-border)}.cancel-btn{background:var(--toast-cancel-bg);color:var(--toast-color);border-color:var(--toast-cancel-border)}.toast-custom{flex:1;min-width:0;width:100%;font-size:.825rem;font-weight:400;line-height:calc(1.25 / .875)}.toast-custom :first-child{margin-top:0}.toast-custom :last-child{margin-bottom:0}.close-btn{position:absolute;top:-.3875rem;right:-.3875rem;flex-shrink:0;margin:-.15rem -.25rem -.15rem 0;border:1px solid var(--toast-border-color);box-shadow:var(--toast-shadow);background:var(--toast-bg);color:var(--toast-color);cursor:pointer;line-height:1;padding:.25rem;border-radius:50%;display:inline-flex;align-items:center;justify-content:center}:host([data-rich-colors=\"true\"][data-variant=\"success\"]) .close-btn{border-color:var(--toast-success-border);background:var(--toast-success-bg);color:var(--toast-success-text)}:host([data-rich-colors=\"true\"][data-variant=\"error\"]) .close-btn{border-color:var(--toast-error-border);background:var(--toast-error-bg);color:var(--toast-error-text)}:host([data-rich-colors=\"true\"][data-variant=\"info\"]) .close-btn{border-color:var(--toast-info-border);background:var(--toast-info-bg);color:var(--toast-info-text)}:host([data-rich-colors=\"true\"][data-variant=\"warning\"]) .close-btn{border-color:var(--toast-warning-border);background:var(--toast-warning-bg);color:var(--toast-warning-text)}.close-btn:focus-visible{outline:2px solid currentColor}.close-btn svg{display:block;width:.825rem;height:.825rem}:host(.leave){opacity:0;scale:.95}:host([data-swipe-direction=\"down\"].leave){transform:translateY(100%)}:host([data-headless=\"true\"][data-position=\"bottom-center\"].leave){transform:translate(-50%) translateY(100%)}:host([data-swipe-direction=\"up\"].leave){transform:translateY(-100%)}:host([data-headless=\"true\"][data-position=\"top-center\"].leave){transform:translate(-50%) translateY(-100%)}@media(prefers-reduced-motion:reduce){:host{transition:none}:host(.leave){scale:1}@starting-style{:host([data-position^=\"bottom\"]){opacity:0;transform:translateY(calc(-1 * var(--offset, 0px)))}}@starting-style{:host([data-position^=\"top\"]){opacity:0;transform:translateY(calc(1 * var(--offset, 0px)))}}@starting-style{:host([data-headless=\"true\"][data-position=\"bottom-center\"]){opacity:1;transform:translate(-50%) translateY(calc(-1 * var(--offset, 0px)))}}@starting-style{:host([data-headless=\"true\"][data-position=\"top-center\"]){opacity:1;transform:translate(-50%) translateY(calc(1 * var(--offset, 0px)))}}:host([data-swipe-direction=\"down\"].leave){transform:translateY(calc(-1 * var(--offset, 0px)))}:host([data-swipe-direction=\"up\"].leave){transform:translateY(calc(1 * var(--offset, 0px)))}:host([data-headless=\"true\"][data-position=\"bottom-center\"].leave){transform:translate(-50%) translateY(calc(-1 * var(--offset, 0px)))}:host([data-headless=\"true\"][data-position=\"top-center\"].leave){transform:translate(-50%) translateY(calc(1 * var(--offset, 0px)))}@media(width<40rem){@starting-style{:host([data-headless=\"true\"][data-position^=\"bottom\"]){opacity:1;transform:translate(-50%) translateY(calc(-1 * var(--offset, 0px)))}}:host([data-headless=\"true\"][data-swipe-direction=\"down\"].leave){transform:translate(-50%) translateY(calc(-1 * var(--offset, 0px)))}@starting-style{:host([data-headless=\"true\"][data-position^=\"top\"]){opacity:1;transform:translate(-50%) translateY(calc(1 * var(--offset, 0px)))}}:host([data-headless=\"true\"][data-swipe-direction=\"up\"].leave){transform:translate(-50%) translateY(calc(1 * var(--offset, 0px)))}}.toast-icon-loading{animation:none}}\n"] }]
|
|
1096
|
+
}], ctorParameters: () => [], propDecorators: { toast: [{ type: i0.Input, args: [{ isSignal: true, alias: "toast", required: false }] }], toasterStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "toasterStyle", required: false }] }], toasterClassNames: [{ type: i0.Input, args: [{ isSignal: true, alias: "toasterClassNames", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: true }] }], closeButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeButton", required: false }] }], customIcons: [{ type: i0.Input, args: [{ isSignal: true, alias: "customIcons", required: false }] }], dismissButtonAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissButtonAriaLabel", required: false }] }], stackPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "stackPosition", required: false }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], heightChange: [{ type: i0.Output, args: ["heightChange"] }] } });
|
|
1097
|
+
/**
|
|
1098
|
+
* Renders the toaster stack. Add once near the root of your app (e.g. in `App`).
|
|
1099
|
+
* Variant-colored surfaces are off by default; set `[richColors]="true"` to enable them.
|
|
1100
|
+
* Set `[duration]` for auto-dismiss when service helpers omit their duration argument.
|
|
1101
|
+
* Use **`duration="Infinity"`** (that exact literal) or `[duration]="…"` with a number / {@link TOAST_DURATION_MANUAL_DISMISS} for persist until dismissed; `0` still works.
|
|
1102
|
+
* Pass `[icons]` with optional **standalone** components for `default` / `description` / `success` / `error` / `info` / `warning` / `loading`:
|
|
1103
|
+
* replace the default artwork (or add an icon for the neutral `default` variant), or use **`null`** to hide that variant’s icon.
|
|
1104
|
+
* Each component should render an **SVG** (import its class where you configure `[icons]`).
|
|
1105
|
+
* Set `[closeButton]="false"` to hide the per-toast dismiss button.
|
|
1106
|
+
* Set `[accessibilityLabels]` to override default English `aria-label` strings (live region and dismiss control).
|
|
1107
|
+
* Set `[offset]` for `--toast-offset-*` and `[mobileOffset]` for `--toast-offset-mobile-*` (string all sides, or per-side object).
|
|
1108
|
+
* Set `[theme]` to `light`, `dark`, or `system` (default): semantic colors follow the chosen mode; `system` uses `prefers-color-scheme`.
|
|
1109
|
+
* {@link ToasterService.action} / {@link ToasterService.cancel} render a message plus one text button (no icon column).
|
|
1110
|
+
*/
|
|
1111
|
+
class BetterToaster {
|
|
1112
|
+
toaster = inject(ToasterService);
|
|
1113
|
+
/**
|
|
1114
|
+
* Default auto-dismiss time in ms for `show` / `success` / `error` / `info` / `warning` when the second argument omits `durationMs`.
|
|
1115
|
+
* Bind **`duration="Infinity"`** (literal only) or a numeric ms value via `[duration]`; {@link TOAST_DURATION_MANUAL_DISMISS} is accepted as a number.
|
|
1116
|
+
* `0` still works. Does not apply to `loading()`. Defaults to the library default (4000ms).
|
|
1117
|
+
*/
|
|
1118
|
+
durationMs = input(DEFAULT_TOAST_DURATION_MS, { ...(ngDevMode ? { debugName: "durationMs" } : /* istanbul ignore next */ {}), alias: 'duration',
|
|
1119
|
+
transform: (value) => {
|
|
1120
|
+
const durationMs = parseToasterDurationMs(value);
|
|
1121
|
+
this.toaster.setDefaultDurationMs(durationMs);
|
|
1122
|
+
return durationMs;
|
|
1123
|
+
} });
|
|
1124
|
+
/** Where the stack is anchored on the viewport. */
|
|
1125
|
+
position = input('bottom-right', ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
|
|
1126
|
+
/**
|
|
1127
|
+
* Viewport inset for the toast stack: a single CSS value for all sides, or an object with any of `top` / `right` / `bottom` / `left`.
|
|
1128
|
+
* Binds `--toast-offset-top` / `right` / `bottom` / `left` on `.toast-container`.
|
|
1129
|
+
*/
|
|
1130
|
+
offset = input(undefined, ...(ngDevMode ? [{ debugName: "offset" }] : /* istanbul ignore next */ []));
|
|
1131
|
+
/**
|
|
1132
|
+
* Viewport inset for narrow layouts: binds `--toast-offset-mobile-top` / `right` / `bottom` / `left` on `.toast-container`.
|
|
1133
|
+
* Same shape as {@link offset}.
|
|
1134
|
+
*/
|
|
1135
|
+
mobileOffset = input(undefined, ...(ngDevMode ? [{ debugName: "mobileOffset" }] : /* istanbul ignore next */ []));
|
|
1136
|
+
/**
|
|
1137
|
+
* When true, success/error/info/warning use semantic background and border colors.
|
|
1138
|
+
*/
|
|
1139
|
+
richColors = input(false, ...(ngDevMode ? [{ debugName: "richColors" }] : /* istanbul ignore next */ []));
|
|
1140
|
+
/**
|
|
1141
|
+
* Color palette for the stack. `system` (default) follows `prefers-color-scheme`; `light` / `dark` pin the palette regardless of OS.
|
|
1142
|
+
* Reflected as `data-theme` on the toast container (`<ol class="toast-container">`).
|
|
1143
|
+
*/
|
|
1144
|
+
theme = input('system', ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
|
|
1145
|
+
/**
|
|
1146
|
+
* Optional per-variant **standalone** components that replace the default SVG (or loading indicator).
|
|
1147
|
+
* Import each icon component in the host and pass its class here; each one should render an SVG
|
|
1148
|
+
* (e.g. root `<svg>` with `stroke="currentColor"` / `fill="currentColor"` where appropriate).
|
|
1149
|
+
* Omitted keys keep the built-in icons (the `default` variant has none unless you set `default` here).
|
|
1150
|
+
* **`null`** for a variant hides that variant’s icon.
|
|
1151
|
+
*/
|
|
1152
|
+
icons = input(...(ngDevMode ? [undefined, { debugName: "icons" }] : /* istanbul ignore next */ []));
|
|
1153
|
+
/**
|
|
1154
|
+
* Defaults for every toast — shape is {@link ToasterToastOptions}.
|
|
1155
|
+
*
|
|
1156
|
+
* - **`style`** — merged onto each toast host with per-toast {@link ToastOptions.style}; identical keys from the service call win.
|
|
1157
|
+
* - **`classNames`** — extra classes on host / `.msg` / `.description` / `.close-btn` / row buttons via **`[class]`**; see {@link ToasterToastOptions.classNames} (**`!important`** is usually required for overrides). Per-toast {@link ToastOptions.classNames} replaces host/message/close keys; row overrides come from {@link ToasterService.action} / {@link ToasterService.cancel}.
|
|
1158
|
+
*/
|
|
1159
|
+
toastOptions = input(...(ngDevMode ? [undefined, { debugName: "toastOptions" }] : /* istanbul ignore next */ []));
|
|
1160
|
+
/** When true, each toast shows a dismiss button. */
|
|
1161
|
+
closeButton = input(true, ...(ngDevMode ? [{ debugName: "closeButton" }] : /* istanbul ignore next */ []));
|
|
1162
|
+
/**
|
|
1163
|
+
* Overrides for built-in English `aria-label` values (live region and per-toast dismiss).
|
|
1164
|
+
* Omitted keys keep {@link DEFAULT_TOASTER_ARIA_NOTIFICATIONS_REGION} and {@link DEFAULT_TOASTER_ARIA_DISMISS_BUTTON}.
|
|
1165
|
+
*/
|
|
1166
|
+
accessibilityLabels = input(...(ngDevMode ? [undefined, { debugName: "accessibilityLabels" }] : /* istanbul ignore next */ []));
|
|
1167
|
+
/** Measured height in px per toast id, updated when a toast item reports `heightChange`. */
|
|
1168
|
+
heights = signal({}, ...(ngDevMode ? [{ debugName: "heights" }] : /* istanbul ignore next */ []));
|
|
1169
|
+
/** Resolved `aria-label` for the outer `<section>` live region. */
|
|
1170
|
+
notificationsRegionAriaLabel = computed(() => this.accessibilityLabels()?.notificationsRegion ?? DEFAULT_TOASTER_ARIA_NOTIFICATIONS_REGION, ...(ngDevMode ? [{ debugName: "notificationsRegionAriaLabel" }] : /* istanbul ignore next */ []));
|
|
1171
|
+
/** Resolved `aria-label` for each toast’s dismiss control. */
|
|
1172
|
+
dismissButtonAriaLabel = computed(() => this.accessibilityLabels()?.dismissButton ?? DEFAULT_TOASTER_ARIA_DISMISS_BUTTON, ...(ngDevMode ? [{ debugName: "dismissButtonAriaLabel" }] : /* istanbul ignore next */ []));
|
|
1173
|
+
/** Vertical offset in px for the toast stack. */
|
|
1174
|
+
offsetTop = computed(() => resolveToasterOffsetSide(this.offset(), 'top'), ...(ngDevMode ? [{ debugName: "offsetTop" }] : /* istanbul ignore next */ []));
|
|
1175
|
+
/** Horizontal offset in px for the toast stack. */
|
|
1176
|
+
offsetRight = computed(() => resolveToasterOffsetSide(this.offset(), 'right'), ...(ngDevMode ? [{ debugName: "offsetRight" }] : /* istanbul ignore next */ []));
|
|
1177
|
+
/** Vertical offset in px for the toast stack. */
|
|
1178
|
+
offsetBottom = computed(() => resolveToasterOffsetSide(this.offset(), 'bottom'), ...(ngDevMode ? [{ debugName: "offsetBottom" }] : /* istanbul ignore next */ []));
|
|
1179
|
+
/** Horizontal offset in px for the toast stack. */
|
|
1180
|
+
offsetLeft = computed(() => resolveToasterOffsetSide(this.offset(), 'left'), ...(ngDevMode ? [{ debugName: "offsetLeft" }] : /* istanbul ignore next */ []));
|
|
1181
|
+
/** Vertical offset in px for the toast stack on narrow layouts. */
|
|
1182
|
+
mobileOffsetTop = computed(() => resolveToasterOffsetSide(this.mobileOffset(), 'top'), ...(ngDevMode ? [{ debugName: "mobileOffsetTop" }] : /* istanbul ignore next */ []));
|
|
1183
|
+
/** Horizontal offset in px for the toast stack on narrow layouts. */
|
|
1184
|
+
mobileOffsetRight = computed(() => resolveToasterOffsetSide(this.mobileOffset(), 'right'), ...(ngDevMode ? [{ debugName: "mobileOffsetRight" }] : /* istanbul ignore next */ []));
|
|
1185
|
+
/** Vertical offset in px for the toast stack on narrow layouts. */
|
|
1186
|
+
mobileOffsetBottom = computed(() => resolveToasterOffsetSide(this.mobileOffset(), 'bottom'), ...(ngDevMode ? [{ debugName: "mobileOffsetBottom" }] : /* istanbul ignore next */ []));
|
|
1187
|
+
/** Horizontal offset in px for the toast stack on narrow layouts. */
|
|
1188
|
+
mobileOffsetLeft = computed(() => resolveToasterOffsetSide(this.mobileOffset(), 'left'), ...(ngDevMode ? [{ debugName: "mobileOffsetLeft" }] : /* istanbul ignore next */ []));
|
|
1189
|
+
/**
|
|
1190
|
+
* Vertical offset in px for each toast id so stacked toasts do not overlap.
|
|
1191
|
+
* Walks newest-to-oldest (end of the list first): the latest toast has offset 0; each older toast sits above by the sum of heights below plus the inter-toast gap.
|
|
1192
|
+
*/
|
|
1193
|
+
offsets = computed(() => {
|
|
1194
|
+
const toastsList = this.toaster.toasts();
|
|
1195
|
+
const heights = this.heights();
|
|
1196
|
+
const result = {};
|
|
1197
|
+
let cumulative = 0;
|
|
1198
|
+
for (let i = toastsList.length - 1; i >= 0; i--) {
|
|
1199
|
+
const toast = toastsList[i];
|
|
1200
|
+
result[toast.id] = cumulative;
|
|
1201
|
+
cumulative += (heights[toast.id] ?? 0) + GAP;
|
|
1202
|
+
}
|
|
1203
|
+
return result;
|
|
1204
|
+
}, ...(ngDevMode ? [{ debugName: "offsets" }] : /* istanbul ignore next */ []));
|
|
1205
|
+
/** Merges a toast item’s reported height into `heights` so `offsets` can recompute. */
|
|
1206
|
+
onHeightChange(toastId, height) {
|
|
1207
|
+
this.heights.update((h) => ({ ...h, [toastId]: height }));
|
|
1208
|
+
}
|
|
1209
|
+
/**
|
|
1210
|
+
* Initializes the toaster service with the default duration.
|
|
1211
|
+
*/
|
|
1212
|
+
ngOnInit() {
|
|
1213
|
+
this.toaster.setDefaultDurationMs(this.durationMs());
|
|
1214
|
+
}
|
|
1215
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: BetterToaster, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1216
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: BetterToaster, isStandalone: true, selector: "better-toaster", inputs: { durationMs: { classPropertyName: "durationMs", publicName: "duration", isSignal: true, isRequired: false, transformFunction: null }, position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, mobileOffset: { classPropertyName: "mobileOffset", publicName: "mobileOffset", isSignal: true, isRequired: false, transformFunction: null }, richColors: { classPropertyName: "richColors", publicName: "richColors", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null }, icons: { classPropertyName: "icons", publicName: "icons", isSignal: true, isRequired: false, transformFunction: null }, toastOptions: { classPropertyName: "toastOptions", publicName: "toastOptions", isSignal: true, isRequired: false, transformFunction: null }, closeButton: { classPropertyName: "closeButton", publicName: "closeButton", isSignal: true, isRequired: false, transformFunction: null }, accessibilityLabels: { classPropertyName: "accessibilityLabels", publicName: "accessibilityLabels", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
1217
|
+
<section
|
|
1218
|
+
[attr.aria-label]="notificationsRegionAriaLabel()"
|
|
1219
|
+
tabindex="-1"
|
|
1220
|
+
aria-live="polite"
|
|
1221
|
+
aria-relevant="additions text"
|
|
1222
|
+
aria-atomic="false"
|
|
1223
|
+
>
|
|
1224
|
+
<ol
|
|
1225
|
+
class="toast-container"
|
|
1226
|
+
[style.--toast-offset-top]="offsetTop()"
|
|
1227
|
+
[style.--toast-offset-right]="offsetRight()"
|
|
1228
|
+
[style.--toast-offset-bottom]="offsetBottom()"
|
|
1229
|
+
[style.--toast-offset-left]="offsetLeft()"
|
|
1230
|
+
[style.--toast-offset-mobile-top]="mobileOffsetTop()"
|
|
1231
|
+
[style.--toast-offset-mobile-right]="mobileOffsetRight()"
|
|
1232
|
+
[style.--toast-offset-mobile-bottom]="mobileOffsetBottom()"
|
|
1233
|
+
[style.--toast-offset-mobile-left]="mobileOffsetLeft()"
|
|
1234
|
+
[attr.data-position]="position()"
|
|
1235
|
+
[attr.data-rich-colors]="richColors()"
|
|
1236
|
+
[attr.data-theme]="theme()"
|
|
1237
|
+
tabindex="-1"
|
|
1238
|
+
>
|
|
1239
|
+
@for (toast of toaster.toasts(); track toast.id) {
|
|
1240
|
+
<li
|
|
1241
|
+
betterToastItem
|
|
1242
|
+
[toast]="toast"
|
|
1243
|
+
[toasterStyle]="toastOptions()?.style"
|
|
1244
|
+
[toasterClassNames]="toastOptions()?.classNames"
|
|
1245
|
+
[variant]="toast.variant"
|
|
1246
|
+
[customIcons]="icons()"
|
|
1247
|
+
[offset]="offsets()[toast.id]"
|
|
1248
|
+
[closeButton]="closeButton()"
|
|
1249
|
+
[dismissButtonAriaLabel]="dismissButtonAriaLabel()"
|
|
1250
|
+
[stackPosition]="position()"
|
|
1251
|
+
[theme]="theme()"
|
|
1252
|
+
(heightChange)="onHeightChange(toast.id, $event)"
|
|
1253
|
+
[attr.data-position]="position()"
|
|
1254
|
+
[attr.data-rich-colors]="richColors()"
|
|
1255
|
+
></li>
|
|
1256
|
+
}
|
|
1257
|
+
</ol>
|
|
1258
|
+
</section>
|
|
1259
|
+
`, isInline: true, styles: [":host{--toast-width: 356px;--toast-gap: 1rem;--toast-z-index: 99999;--toast-offset-top: 24px;--toast-offset-bottom: 24px;--toast-offset-left: 24px;--toast-offset-right: 24px;--toast-offset-mobile-top: 16px;--toast-offset-mobile-bottom: 16px;--toast-offset-mobile-left: 16px;--toast-offset-mobile-right: 16px}.toast-container[data-theme=light]{color-scheme:light}.toast-container[data-theme=dark]{color-scheme:dark}.toast-container[data-theme=system]{color-scheme:light dark}.toast-container{--toast-bg: light-dark(oklch(100% 0 0), oklch(10% 0 0));--toast-color: light-dark(oklch(30% 0 0), oklch(98% 0 0));--toast-border-color: light-dark(oklch(92% .004 286.32 / .65), oklch(37% .013 285.805 / .75));--toast-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--toast-success-bg: light-dark(oklch(97.9% .021 166.113), oklch(26.2% .051 172.552));--toast-success-text: light-dark(oklch(59.6% .145 163.225), oklch(92.5% .084 155.995));--toast-success-border: light-dark( oklch(69.6% .17 162.48 / .1), oklch(92.5% .084 155.995 / .1) );--toast-error-bg: light-dark(oklch(97.5% .012 25), oklch(25.8% .092 26.042));--toast-error-text: light-dark(oklch(57.7% .245 27.325), oklch(88.5% .062 18.334));--toast-error-border: light-dark( oklch(80.8% .114 19.571 / .1), oklch(88.5% .062 18.334 / .125) );--toast-info-bg: light-dark(oklch(97.7% .013 236.62), oklch(29.3% .066 243.157));--toast-info-text: light-dark(oklch(68.5% .169 237.323), oklch(90.1% .058 230.902));--toast-info-border: light-dark( oklch(82.8% .111 230.318 / .15), oklch(90.1% .058 230.902 / .125) );--toast-warning-bg: light-dark(oklch(98.7% .022 95.277), oklch(28.6% .066 53.813));--toast-warning-text: light-dark(oklch(66.6% .179 58.318), oklch(92.4% .12 95.746));--toast-warning-border: light-dark( oklch(76.9% .188 70.08 / .15), oklch(92.4% .12 95.746 / .125) );--toast-action-bg: light-dark(var(--color-black), var(--color-white));--toast-action-text: light-dark(var(--color-white), var(--color-black));--toast-action-border: light-dark(var(--color-black), var(--color-white));--toast-cancel-bg: light-dark(oklch(86.9% .005 56.366 / .3), oklch(26.8% .007 34.298 / .85));--toast-cancel-text: var(--toast-color);--toast-cancel-border: light-dark( oklch(86.9% .005 56.366 / .1), oklch(26.8% .007 34.298 / .5) );position:fixed;z-index:var(--toast-z-index);width:auto;pointer-events:none;overflow:visible;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.toast-container[data-theme=dark]{--toast-shadow: 0 4px 6px -1px rgb(0 0 0 / .5), 0 2px 4px -2px rgb(0 0 0 / .5)}@media(prefers-color-scheme:dark){.toast-container[data-theme=system]{--toast-shadow: 0 4px 6px -1px rgb(0 0 0 / .5), 0 2px 4px -2px rgb(0 0 0 / .5)}}.toast-container[data-position^=top]{top:var(--toast-offset-mobile-top);left:var(--toast-offset-mobile-left);right:var(--toast-offset-mobile-right)}.toast-container[data-position^=bottom]{bottom:var(--toast-offset-mobile-bottom);left:var(--toast-offset-mobile-left);right:var(--toast-offset-mobile-right)}@media(width>=40rem){.toast-container{width:var(--toast-width)}.toast-container[data-position=top-left]{top:var(--toast-offset-top);left:var(--toast-offset-left);right:auto;align-items:flex-start}.toast-container[data-position=top-center]{top:var(--toast-offset-top);left:50%;transform:translate(-50%);align-items:center}.toast-container[data-position=top-right]{top:var(--toast-offset-top);right:var(--toast-offset-right);left:auto;align-items:flex-end}.toast-container[data-position=bottom-left]{bottom:var(--toast-offset-bottom);left:var(--toast-offset-left);right:auto;align-items:flex-start}.toast-container[data-position=bottom-center]{bottom:var(--toast-offset-bottom);left:50%;transform:translate(-50%);align-items:center}.toast-container[data-position=bottom-right]{bottom:var(--toast-offset-bottom);right:var(--toast-offset-right);left:auto;align-items:flex-end}}\n"], dependencies: [{ kind: "component", type: BetterToastItem, selector: "li[betterToastItem]", inputs: ["toast", "toasterStyle", "toasterClassNames", "variant", "offset", "closeButton", "customIcons", "dismissButtonAriaLabel", "stackPosition", "theme"], outputs: ["heightChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1260
|
+
}
|
|
1261
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: BetterToaster, decorators: [{
|
|
1262
|
+
type: Component,
|
|
1263
|
+
args: [{ selector: 'better-toaster', changeDetection: ChangeDetectionStrategy.OnPush, imports: [BetterToastItem], template: `
|
|
1264
|
+
<section
|
|
1265
|
+
[attr.aria-label]="notificationsRegionAriaLabel()"
|
|
1266
|
+
tabindex="-1"
|
|
1267
|
+
aria-live="polite"
|
|
1268
|
+
aria-relevant="additions text"
|
|
1269
|
+
aria-atomic="false"
|
|
1270
|
+
>
|
|
1271
|
+
<ol
|
|
1272
|
+
class="toast-container"
|
|
1273
|
+
[style.--toast-offset-top]="offsetTop()"
|
|
1274
|
+
[style.--toast-offset-right]="offsetRight()"
|
|
1275
|
+
[style.--toast-offset-bottom]="offsetBottom()"
|
|
1276
|
+
[style.--toast-offset-left]="offsetLeft()"
|
|
1277
|
+
[style.--toast-offset-mobile-top]="mobileOffsetTop()"
|
|
1278
|
+
[style.--toast-offset-mobile-right]="mobileOffsetRight()"
|
|
1279
|
+
[style.--toast-offset-mobile-bottom]="mobileOffsetBottom()"
|
|
1280
|
+
[style.--toast-offset-mobile-left]="mobileOffsetLeft()"
|
|
1281
|
+
[attr.data-position]="position()"
|
|
1282
|
+
[attr.data-rich-colors]="richColors()"
|
|
1283
|
+
[attr.data-theme]="theme()"
|
|
1284
|
+
tabindex="-1"
|
|
1285
|
+
>
|
|
1286
|
+
@for (toast of toaster.toasts(); track toast.id) {
|
|
1287
|
+
<li
|
|
1288
|
+
betterToastItem
|
|
1289
|
+
[toast]="toast"
|
|
1290
|
+
[toasterStyle]="toastOptions()?.style"
|
|
1291
|
+
[toasterClassNames]="toastOptions()?.classNames"
|
|
1292
|
+
[variant]="toast.variant"
|
|
1293
|
+
[customIcons]="icons()"
|
|
1294
|
+
[offset]="offsets()[toast.id]"
|
|
1295
|
+
[closeButton]="closeButton()"
|
|
1296
|
+
[dismissButtonAriaLabel]="dismissButtonAriaLabel()"
|
|
1297
|
+
[stackPosition]="position()"
|
|
1298
|
+
[theme]="theme()"
|
|
1299
|
+
(heightChange)="onHeightChange(toast.id, $event)"
|
|
1300
|
+
[attr.data-position]="position()"
|
|
1301
|
+
[attr.data-rich-colors]="richColors()"
|
|
1302
|
+
></li>
|
|
1303
|
+
}
|
|
1304
|
+
</ol>
|
|
1305
|
+
</section>
|
|
1306
|
+
`, styles: [":host{--toast-width: 356px;--toast-gap: 1rem;--toast-z-index: 99999;--toast-offset-top: 24px;--toast-offset-bottom: 24px;--toast-offset-left: 24px;--toast-offset-right: 24px;--toast-offset-mobile-top: 16px;--toast-offset-mobile-bottom: 16px;--toast-offset-mobile-left: 16px;--toast-offset-mobile-right: 16px}.toast-container[data-theme=light]{color-scheme:light}.toast-container[data-theme=dark]{color-scheme:dark}.toast-container[data-theme=system]{color-scheme:light dark}.toast-container{--toast-bg: light-dark(oklch(100% 0 0), oklch(10% 0 0));--toast-color: light-dark(oklch(30% 0 0), oklch(98% 0 0));--toast-border-color: light-dark(oklch(92% .004 286.32 / .65), oklch(37% .013 285.805 / .75));--toast-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--toast-success-bg: light-dark(oklch(97.9% .021 166.113), oklch(26.2% .051 172.552));--toast-success-text: light-dark(oklch(59.6% .145 163.225), oklch(92.5% .084 155.995));--toast-success-border: light-dark( oklch(69.6% .17 162.48 / .1), oklch(92.5% .084 155.995 / .1) );--toast-error-bg: light-dark(oklch(97.5% .012 25), oklch(25.8% .092 26.042));--toast-error-text: light-dark(oklch(57.7% .245 27.325), oklch(88.5% .062 18.334));--toast-error-border: light-dark( oklch(80.8% .114 19.571 / .1), oklch(88.5% .062 18.334 / .125) );--toast-info-bg: light-dark(oklch(97.7% .013 236.62), oklch(29.3% .066 243.157));--toast-info-text: light-dark(oklch(68.5% .169 237.323), oklch(90.1% .058 230.902));--toast-info-border: light-dark( oklch(82.8% .111 230.318 / .15), oklch(90.1% .058 230.902 / .125) );--toast-warning-bg: light-dark(oklch(98.7% .022 95.277), oklch(28.6% .066 53.813));--toast-warning-text: light-dark(oklch(66.6% .179 58.318), oklch(92.4% .12 95.746));--toast-warning-border: light-dark( oklch(76.9% .188 70.08 / .15), oklch(92.4% .12 95.746 / .125) );--toast-action-bg: light-dark(var(--color-black), var(--color-white));--toast-action-text: light-dark(var(--color-white), var(--color-black));--toast-action-border: light-dark(var(--color-black), var(--color-white));--toast-cancel-bg: light-dark(oklch(86.9% .005 56.366 / .3), oklch(26.8% .007 34.298 / .85));--toast-cancel-text: var(--toast-color);--toast-cancel-border: light-dark( oklch(86.9% .005 56.366 / .1), oklch(26.8% .007 34.298 / .5) );position:fixed;z-index:var(--toast-z-index);width:auto;pointer-events:none;overflow:visible;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.toast-container[data-theme=dark]{--toast-shadow: 0 4px 6px -1px rgb(0 0 0 / .5), 0 2px 4px -2px rgb(0 0 0 / .5)}@media(prefers-color-scheme:dark){.toast-container[data-theme=system]{--toast-shadow: 0 4px 6px -1px rgb(0 0 0 / .5), 0 2px 4px -2px rgb(0 0 0 / .5)}}.toast-container[data-position^=top]{top:var(--toast-offset-mobile-top);left:var(--toast-offset-mobile-left);right:var(--toast-offset-mobile-right)}.toast-container[data-position^=bottom]{bottom:var(--toast-offset-mobile-bottom);left:var(--toast-offset-mobile-left);right:var(--toast-offset-mobile-right)}@media(width>=40rem){.toast-container{width:var(--toast-width)}.toast-container[data-position=top-left]{top:var(--toast-offset-top);left:var(--toast-offset-left);right:auto;align-items:flex-start}.toast-container[data-position=top-center]{top:var(--toast-offset-top);left:50%;transform:translate(-50%);align-items:center}.toast-container[data-position=top-right]{top:var(--toast-offset-top);right:var(--toast-offset-right);left:auto;align-items:flex-end}.toast-container[data-position=bottom-left]{bottom:var(--toast-offset-bottom);left:var(--toast-offset-left);right:auto;align-items:flex-start}.toast-container[data-position=bottom-center]{bottom:var(--toast-offset-bottom);left:50%;transform:translate(-50%);align-items:center}.toast-container[data-position=bottom-right]{bottom:var(--toast-offset-bottom);right:var(--toast-offset-right);left:auto;align-items:flex-end}}\n"] }]
|
|
1307
|
+
}], propDecorators: { durationMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "duration", required: false }] }], position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }], mobileOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "mobileOffset", required: false }] }], richColors: [{ type: i0.Input, args: [{ isSignal: true, alias: "richColors", required: false }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], icons: [{ type: i0.Input, args: [{ isSignal: true, alias: "icons", required: false }] }], toastOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "toastOptions", required: false }] }], closeButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeButton", required: false }] }], accessibilityLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "accessibilityLabels", required: false }] }] } });
|
|
1308
|
+
|
|
1309
|
+
/*
|
|
1310
|
+
* Public API Surface of better-toast
|
|
1311
|
+
*/
|
|
1312
|
+
|
|
1313
|
+
/**
|
|
1314
|
+
* Generated bundle index. Do not edit.
|
|
1315
|
+
*/
|
|
1316
|
+
|
|
1317
|
+
export { BetterToaster, DEFAULT_TOASTER_ARIA_DISMISS_BUTTON, DEFAULT_TOASTER_ARIA_NOTIFICATIONS_REGION, DEFAULT_TOAST_ACTION_LABEL, DEFAULT_TOAST_CANCEL_LABEL, DEFAULT_TOAST_DURATION_MS, TOASTER_POSITIONS, TOAST_DURATION_MANUAL_DISMISS, TOAST_VARIANTS, ToasterService };
|
|
1318
|
+
//# sourceMappingURL=better-toast.mjs.map
|