@rkosafo/cai.components 0.0.80 → 0.0.81

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.
@@ -1,3 +1,7 @@
1
+ <script lang="ts" module>
2
+ let openModalCount = 0;
3
+ </script>
4
+
1
5
  <script lang="ts">
2
6
  import clsx, { type ClassValue } from 'clsx';
3
7
  import { sineIn } from 'svelte/easing';
@@ -64,57 +68,52 @@
64
68
  close: closeCls
65
69
  } = $derived(modalStyle({ placement, size }));
66
70
 
67
- const close = (dlg: HTMLDialogElement) => (open = false);
68
- // @ts-expect-error: dlg.requestClose may not be supported
69
- const cancel = (dlg: HTMLDialogElement) =>
70
- typeof dlg.requestClose === 'function' ? dlg.requestClose() : close();
71
-
72
- function _oncancel(ev: Event & { currentTarget: HTMLDialogElement }) {
73
- if (ev.target !== ev.currentTarget) {
74
- return; // ignore if not on dialog
75
- }
71
+ const close = () => (open = false);
76
72
 
77
- // this event gets called when user canceled the dialog:
78
- // pressesed ESC key, clicked outside, pressed submit button with no 'value' like close button
73
+ function _oncancel(ev: Event) {
79
74
  oncancel?.(ev);
80
75
  if (ev.defaultPrevented) return;
81
-
82
- ev.preventDefault(); // prevent anyway, we need clean close
83
- if (!permanent) close(ev.currentTarget);
76
+ ev.preventDefault();
77
+ if (!permanent) close();
84
78
  }
85
79
 
86
- function _onclick(ev: Event & { currentTarget: HTMLDialogElement }) {
87
- const dlg: HTMLDialogElement = ev.currentTarget;
88
- if (outsideclose && ev.target === dlg) {
89
- return cancel(dlg);
80
+ function _onclick(ev: MouseEvent) {
81
+ const target = ev.target as HTMLElement;
82
+ if (outsideclose && target.dataset.modalBackdrop === 'true') {
83
+ const cancelEvent = new Event('cancel', { cancelable: true });
84
+ oncancel?.(cancelEvent);
85
+ if (!cancelEvent.defaultPrevented && !permanent) {
86
+ close();
87
+ }
88
+ return;
90
89
  }
91
90
 
92
- if (autoclose && ev.target instanceof HTMLButtonElement && !permanent) {
93
- return close(dlg);
91
+ if (autoclose && target instanceof HTMLButtonElement && !permanent) {
92
+ close();
94
93
  }
95
94
  }
96
95
 
97
- function _onsubmit(ev: SubmitEvent & { currentTarget: HTMLDialogElement }) {
96
+ function _onsubmit(ev: SubmitEvent & { currentTarget: HTMLFormElement }) {
98
97
  // When dialog contains the <form method="dialog"> and when child with type="submit" was pressed
99
98
 
100
99
  onsubmit?.(ev);
101
100
  if (ev.defaultPrevented) return;
102
101
 
103
- ev.preventDefault(); // stop dialog.close()
104
-
105
- const dlg: HTMLDialogElement = ev.currentTarget;
102
+ ev.preventDefault();
103
+ const panel: HTMLElement = ref as HTMLElement;
106
104
 
107
105
  if (ev.submitter instanceof HTMLButtonElement || ev.submitter instanceof HTMLInputElement) {
108
- dlg.returnValue = ev.submitter.value;
106
+ panel.dataset.returnValue = ev.submitter.value;
109
107
  }
110
108
 
111
- if (!dlg.returnValue) {
112
- return cancel(dlg); // if no action - treat that as cancel
109
+ const returnValue = panel.dataset.returnValue ?? '';
110
+ if (!returnValue) {
111
+ return _oncancel(new Event('cancel', { cancelable: true }));
113
112
  }
114
113
 
115
114
  // MAIN APPROACH: Use only the first nested form's data
116
115
  let formData: FormData;
117
- const nestedForms = dlg.querySelectorAll('form');
116
+ const nestedForms = panel.querySelectorAll('form');
118
117
 
119
118
  if (nestedForms.length > 0) {
120
119
  // Use the first nested form (assuming it contains the input fields)
@@ -127,7 +126,7 @@
127
126
  // ALTERNATIVE APPROACH: Combine data from all nested forms (uncomment to use)
128
127
 
129
128
  const combinedFormData = new FormData();
130
- const allForms = dlg.querySelectorAll('form');
129
+ const allForms = panel.querySelectorAll('form');
131
130
 
132
131
  allForms.forEach((form) => {
133
132
  new FormData(form).forEach((value, key) => {
@@ -141,26 +140,40 @@
141
140
  // explicit false from onaction blocks the form closing
142
141
  if (
143
142
  typeof onaction === 'function' &&
144
- onaction({ action: dlg.returnValue, data: formData }) === false
143
+ onaction({ action: returnValue, data: formData }) === false
145
144
  )
146
145
  return;
147
146
 
148
- close(dlg);
149
- }
150
-
151
- function _ontoggle(ev: ToggleEvent & { currentTarget: HTMLDialogElement }) {
152
- ontoggle?.(ev);
153
- open = ev.newState === 'open'; // for cases when toggle by other means
154
- }
155
-
156
- function init(dlg: HTMLDialogElement) {
157
- modal ? dlg.showModal() : dlg.show();
158
- return () => dlg.close();
147
+ close();
159
148
  }
160
149
 
161
150
  const focusTrap = (node: HTMLElement) => (focustrap ? trapFocus(node) : undefined);
162
151
 
163
- let ref: HTMLDialogElement | undefined = $state(undefined);
152
+ let ref: HTMLDivElement | undefined = $state(undefined);
153
+
154
+ let previousOpen = false;
155
+ $effect(() => {
156
+ if (open && !previousOpen) {
157
+ openModalCount += 1;
158
+ if (modal) document.body.style.overflow = 'hidden';
159
+ ontoggle?.({ newState: 'open', oldState: 'closed' } as ToggleEvent);
160
+ }
161
+ if (!open && previousOpen) {
162
+ openModalCount = Math.max(0, openModalCount - 1);
163
+ if (modal && openModalCount === 0) document.body.style.overflow = '';
164
+ ontoggle?.({ newState: 'closed', oldState: 'open' } as ToggleEvent);
165
+ }
166
+ previousOpen = open;
167
+ });
168
+
169
+ $effect(() => {
170
+ return () => {
171
+ if (previousOpen) {
172
+ openModalCount = Math.max(0, openModalCount - 1);
173
+ if (modal && openModalCount === 0) document.body.style.overflow = '';
174
+ }
175
+ };
176
+ });
164
177
 
165
178
  function close_handler(ev: MouseEvent) {
166
179
  if (form) {
@@ -168,7 +181,9 @@
168
181
  return;
169
182
  }
170
183
 
171
- ref?.dispatchEvent(new Event('cancel', { bubbles: true, cancelable: true }));
184
+ const cancelEvent = new Event('cancel', { cancelable: true });
185
+ oncancel?.(cancelEvent);
186
+ if (!cancelEvent.defaultPrevented && !permanent) close();
172
187
  }
173
188
 
174
189
  createDismissableContext(close_handler);
@@ -180,7 +195,14 @@
180
195
  {#if title}
181
196
  <h3>{title}</h3>
182
197
  {#if dismissable && !permanent}
183
- <CloseButton type="submit" formnovalidate class={clsx(styling.close)} />
198
+ <CloseButton
199
+ type={form ? 'submit' : 'button'}
200
+ formnovalidate
201
+ class={clsx(styling.close)}
202
+ onclick={() => {
203
+ if (!form) close();
204
+ }}
205
+ />
184
206
  {/if}
185
207
  {:else if header}
186
208
  {@render header()}
@@ -197,24 +219,46 @@
197
219
  {/if}
198
220
  {#if dismissable && !permanent && !title}
199
221
  <CloseButton
200
- type="submit"
222
+ type={form ? 'submit' : 'button'}
201
223
  formnovalidate
202
224
  class={closeCls({ class: clsx(theme?.close, styling.close) })}
225
+ onclick={() => {
226
+ if (!form) close();
227
+ }}
203
228
  />
204
229
  {/if}
205
230
  {/snippet}
206
231
 
207
232
  {#if open}
208
- <dialog
209
- {@attach init}
233
+ <div
210
234
  bind:this={ref}
211
235
  use:focusTrap
212
- class={base({ fullscreen, class: clsx(theme?.base, className) })}
236
+ class="fixed inset-0 z-40 flex items-center justify-center p-4"
237
+ onclick={_onclick}
238
+ onkeydown={(ev) => {
239
+ if (ev.key === 'Escape' && !permanent) {
240
+ _oncancel(new Event('cancel', { cancelable: true }));
241
+ }
242
+ }}
243
+ tabindex="-1"
244
+ aria-modal={modal ? 'true' : undefined}
245
+ role="dialog"
246
+ >
247
+ {#if modal}
248
+ <div class="absolute inset-0 bg-black/80" data-modal-backdrop="true"></div>
249
+ {/if}
250
+ <div
251
+ class={base({
252
+ fullscreen,
253
+ class: clsx(
254
+ theme?.base,
255
+ className,
256
+ 'relative z-10',
257
+ !modal && 'shadow-xl'
258
+ )
259
+ })}
213
260
  tabindex="-1"
214
261
  onsubmit={_onsubmit}
215
- oncancel={_oncancel}
216
- onclick={_onclick}
217
- ontoggle={_ontoggle}
218
262
  transition:transition|global={paramsOptions as ParamsType}
219
263
  {...restProps}
220
264
  >
@@ -225,7 +269,8 @@
225
269
  {:else}
226
270
  {@render content()}
227
271
  {/if}
228
- </dialog>
272
+ </div>
273
+ </div>
229
274
  {/if}
230
275
 
231
276
  <!--
@@ -1,337 +1,176 @@
1
1
  <script lang="ts" module>
2
- export type ToastType = 'success' | 'error' | 'warning' | 'info' | 'loading' | 'custom';
3
- export type ToastPosition =
4
- | 'top-left'
5
- | 'top-center'
6
- | 'top-right'
7
- | 'bottom-left'
8
- | 'bottom-center'
9
- | 'bottom-right';
10
-
11
- export interface CustomToastOptions extends ToastOptions {
12
- icon?: string;
13
- showProgress?: boolean;
14
- progressColor?: string;
15
- borderColor?: string;
16
- backgroundColor?: string;
17
- textColor?: string;
18
- iconColor?: string;
19
- style?: any;
20
- action?: {
21
- label: string | boolean;
22
- onClick: () => void;
23
- buttonStyle?: string;
24
- };
25
- }
26
-
27
- export interface ToastTheme {
28
- success?: Partial<CustomToastOptions>;
29
- error?: Partial<CustomToastOptions>;
30
- warning?: Partial<CustomToastOptions>;
31
- info?: Partial<CustomToastOptions>;
32
- loading?: Partial<CustomToastOptions>;
33
- custom?: Partial<CustomToastOptions>;
34
- }
2
+ import {
3
+ toast as originalToast,
4
+ type DefaultToastOptions,
5
+ type Renderable,
6
+ resolveValue,
7
+ type ToastOptions,
8
+ type ToastPosition,
9
+ type ToastType,
10
+ type ValueOrFunction
11
+ } from 'svelte-french-toast';
12
+ export {
13
+ CheckmarkIcon,
14
+ ErrorIcon,
15
+ LoaderIcon,
16
+ ToastBar,
17
+ ToastIcon,
18
+ useToaster,
19
+ useToasterStore
20
+ } from 'svelte-french-toast';
21
+ export { resolveValue };
22
+
23
+ export type {
24
+ DefaultToastOptions,
25
+ IconTheme,
26
+ Toast,
27
+ ToastOptions,
28
+ ToastPosition,
29
+ ToastType,
30
+ Renderable,
31
+ ValueFunction,
32
+ ValueOrFunction
33
+ } from 'svelte-french-toast';
34
+ export type CustomToastOptions = ToastOptions;
35
+ export type ToastTheme = Record<string, never>;
35
36
 
36
37
  export interface ToasterProps {
37
38
  position?: ToastPosition;
38
39
  duration?: number;
39
- theme?: ToastTheme;
40
+ toastOptions?: DefaultToastOptions;
41
+ reverseOrder?: boolean;
42
+ gutter?: number;
43
+ containerStyle?: string;
44
+ containerClassName?: string;
45
+ fireWithSound?: boolean;
46
+ // Kept for backward compatibility (no-op in wrapper mode)
40
47
  className?: string;
41
- toastOptions?: ToastOptions;
48
+ theme?: ToastTheme;
42
49
  richColors?: boolean;
43
50
  customIcons?: boolean;
44
51
  closeButton?: boolean;
45
52
  pauseOnHover?: boolean;
46
- reverseOrder?: boolean;
47
53
  visibleToasts?: number;
48
54
  expand?: boolean;
49
55
  gap?: number;
50
56
  offset?: number | string;
51
57
  }
52
- // Default theme configuration
53
- const defaultTheme: ToastTheme = {
54
- success: {
55
- icon: '✅',
56
- borderColor: '#22c55e',
57
- backgroundColor: '#f0fdf4',
58
- textColor: '#166534',
59
- iconColor: '#16a34a',
60
- progressColor: '#22c55e'
61
- },
62
- error: {
63
- icon: '❌',
64
- borderColor: '#ef4444',
65
- backgroundColor: '#fef2f2',
66
- textColor: '#991b1b',
67
- iconColor: '#dc2626',
68
- progressColor: '#ef4444'
69
- },
70
- warning: {
71
- icon: '⚠️',
72
- borderColor: '#f59e0b',
73
- backgroundColor: '#fffbeb',
74
- textColor: '#92400e',
75
- iconColor: '#d97706',
76
- progressColor: '#f59e0b'
77
- },
78
- info: {
79
- icon: 'ℹ️',
80
- borderColor: '#3b82f6',
81
- backgroundColor: '#eff6ff',
82
- textColor: '#1e40af',
83
- iconColor: '#2563eb',
84
- progressColor: '#3b82f6'
85
- },
86
- loading: {
87
- icon: '⏳',
88
- borderColor: '#6b7280',
89
- backgroundColor: '#f9fafb',
90
- textColor: '#374151',
91
- iconColor: '#6b7280',
92
- progressColor: '#6b7280'
93
- }
94
- };
95
58
 
96
59
  let currentDuration = 4000;
97
- let currentTheme: ToastTheme = {};
98
- let currentRichColors = false;
99
-
100
- function buildToastStyle(
101
- theme: Partial<CustomToastOptions>,
102
- options?: CustomToastOptions,
103
- type?: ToastType,
104
- richColors?: boolean
105
- ): string {
106
- if (options?.style) return options.style;
107
-
108
- const baseStyle = `
109
- border: 1px solid ${options?.borderColor || theme.borderColor || '#e5e7eb'};
110
- background: ${options?.backgroundColor || theme.backgroundColor || '#ffffff'};
111
- color: ${options?.textColor || theme.textColor || '#1f2937'};
112
- padding: 12px 16px;
113
- border-radius: 8px;
114
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
115
- font-size: 14px;
116
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
117
- display: flex;
118
- align-items: center;
119
- gap: 8px;
120
- `;
121
-
122
- if (richColors && type && defaultTheme[type]) {
123
- const richTheme = defaultTheme[type]!;
124
- return `
125
- ${baseStyle}
126
- border-color: ${options?.borderColor || richTheme.borderColor}!important;
127
- background: ${options?.backgroundColor || richTheme.backgroundColor}!important;
128
- color: ${options?.textColor || richTheme.textColor}!important;
129
- `;
60
+ let currentFireWithSound = false;
61
+
62
+ function playToastSound() {
63
+ if (!currentFireWithSound || typeof window === 'undefined') return;
64
+
65
+ try {
66
+ const AudioContextClass = window.AudioContext || (window as Window & { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;
67
+ if (!AudioContextClass) return;
68
+
69
+ const context = new AudioContextClass();
70
+ const oscillator = context.createOscillator();
71
+ const gain = context.createGain();
72
+ oscillator.type = 'sine';
73
+ oscillator.frequency.setValueAtTime(880, context.currentTime);
74
+ gain.gain.setValueAtTime(0.0001, context.currentTime);
75
+ gain.gain.exponentialRampToValueAtTime(0.06, context.currentTime + 0.01);
76
+ gain.gain.exponentialRampToValueAtTime(0.0001, context.currentTime + 0.18);
77
+ oscillator.connect(gain);
78
+ gain.connect(context.destination);
79
+ oscillator.start();
80
+ oscillator.stop(context.currentTime + 0.2);
81
+ } catch {
82
+ // Ignore audio errors.
130
83
  }
131
-
132
- return baseStyle;
133
84
  }
134
85
 
135
- export const toast = {
136
- success: (message: string, options?: CustomToastOptions) => {
137
- const themeOptions = currentTheme?.success || defaultTheme.success || {};
138
- const style = buildToastStyle(themeOptions, options, 'success');
139
-
140
- return originalToast.success(message, {
141
- duration: currentDuration,
142
- ...themeOptions,
143
- ...options,
144
- style,
145
- icon: options?.icon || themeOptions.icon
146
- });
147
- },
148
-
149
- error: (message: string, options?: CustomToastOptions) => {
150
- const themeOptions = currentTheme?.error || defaultTheme.error || {};
151
- const style = buildToastStyle(themeOptions, options, 'error');
152
-
153
- return originalToast.error(message, {
154
- duration: currentDuration,
155
- ...themeOptions,
156
- ...options,
157
- style,
158
- icon: options?.icon || themeOptions.icon
159
- });
160
- },
161
-
162
- warning: (message: string, options?: CustomToastOptions) => {
163
- const themeOptions = currentTheme?.warning || defaultTheme.warning || {};
164
- const style = buildToastStyle(themeOptions, options, 'warning');
165
-
166
- return originalToast(message, {
167
- duration: currentDuration,
168
- ...themeOptions,
169
- ...options,
170
- style,
171
- icon: options?.icon || themeOptions.icon
172
- });
173
- },
174
-
175
- info: (message: string, options?: CustomToastOptions) => {
176
- const themeOptions = currentTheme?.info || defaultTheme.info || {};
177
- const style = buildToastStyle(themeOptions, options, 'info');
178
-
179
- return originalToast(message, {
180
- duration: currentDuration,
181
- ...themeOptions,
182
- ...options,
183
- style,
184
- icon: options?.icon || themeOptions.icon
185
- });
186
- },
187
-
188
- loading: (message: string, options?: CustomToastOptions) => {
189
- const themeOptions = currentTheme?.loading || defaultTheme.loading || {};
190
- const style = buildToastStyle(themeOptions, options, 'loading');
191
-
192
- return originalToast.loading(message, {
193
- duration: currentDuration,
194
- ...themeOptions,
195
- ...options,
196
- style,
197
- icon: options?.icon || themeOptions.icon
198
- });
199
- },
200
-
201
- promise: <T,>(
202
- promise: Promise<T>,
203
- messages: { loading: string; success: string; error: string },
204
- options?: {
205
- loading?: CustomToastOptions;
206
- success?: CustomToastOptions;
207
- error?: CustomToastOptions;
208
- }
209
- ) => {
210
- const loadingTheme = currentTheme?.loading || defaultTheme.loading || {};
211
- const successTheme = currentTheme?.success || defaultTheme.success || {};
212
- const errorTheme = currentTheme?.error || defaultTheme.error || {};
213
-
214
- return originalToast.promise(promise, messages, {
215
- loading: {
216
- ...loadingTheme,
217
- ...options?.loading,
218
- style: buildToastStyle(loadingTheme, options?.loading, 'loading'),
219
- icon: options?.loading?.icon || loadingTheme.icon
220
- },
221
- success: {
222
- ...successTheme,
223
- ...options?.success,
224
- style: buildToastStyle(successTheme, options?.success, 'success'),
225
- icon: options?.success?.icon || successTheme.icon
226
- },
227
- error: {
228
- ...errorTheme,
229
- ...options?.error,
230
- style: buildToastStyle(errorTheme, options?.error, 'error'),
231
- icon: options?.error?.icon || errorTheme.icon
232
- }
233
- });
234
- },
235
-
236
- // Custom toast with complete control
237
- custom: (message: string, type: ToastType = 'info', options?: CustomToastOptions) => {
238
- const themeOptions = currentTheme?.[type] || defaultTheme[type] || defaultTheme.info || {};
239
- const style = buildToastStyle(themeOptions, options, type);
240
-
241
- return originalToast(message, {
242
- duration: currentDuration,
243
- ...themeOptions,
244
- ...options,
245
- style,
246
- icon: options?.icon || themeOptions.icon
247
- });
248
- },
249
-
250
- // Action toast with button
251
- action: (
252
- message: string,
253
- action: { label: string; onClick: () => void },
254
- options?: CustomToastOptions
255
- ) => {
256
- const themeOptions = currentTheme?.info || defaultTheme.info || {};
257
- const style = buildToastStyle(themeOptions, options, 'info');
258
-
259
- return originalToast(message, {
260
- duration: currentDuration,
261
- ...themeOptions,
262
- ...options,
263
- style,
264
- icon: options?.icon || themeOptions.icon,
265
- action: {
266
- label: action.label,
267
- onClick: action.onClick,
268
- buttonStyle:
269
- options?.action?.buttonStyle ||
270
- 'background: #3b82f6; color: white; border: none; padding: 4px 12px; border-radius: 4px; cursor: pointer;'
271
- }
272
- });
273
- },
274
-
275
- // Dismiss specific toast or all toasts
276
- dismiss: (toastId?: string) => {
277
- return originalToast.dismiss(toastId);
278
- },
279
-
280
- // Remove specific toast
281
- remove: (toastId?: string) => {
282
- return originalToast.remove(toastId);
283
- }
284
- };
285
-
286
86
  export function updateToastConfig(config: {
287
87
  duration?: number;
88
+ fireWithSound?: boolean;
288
89
  theme?: ToastTheme;
289
90
  richColors?: boolean;
290
91
  }) {
291
92
  if (config.duration !== undefined) currentDuration = config.duration;
292
- if (config.theme !== undefined) currentTheme = config.theme;
293
- if (config.richColors !== undefined) currentRichColors = config.richColors;
93
+ if (config.fireWithSound !== undefined) currentFireWithSound = config.fireWithSound;
294
94
  }
295
95
 
96
+ export const toast = Object.assign(
97
+ (message: Renderable, options?: ToastOptions) => {
98
+ playToastSound();
99
+ return originalToast(message, { duration: currentDuration, ...options });
100
+ },
101
+ {
102
+ success: (message: Renderable, options?: ToastOptions) => {
103
+ playToastSound();
104
+ return originalToast.success(message, { duration: currentDuration, ...options });
105
+ },
106
+ error: (message: Renderable, options?: ToastOptions) => {
107
+ playToastSound();
108
+ return originalToast.error(message, { duration: currentDuration, ...options });
109
+ },
110
+ loading: (message: Renderable, options?: ToastOptions) => {
111
+ playToastSound();
112
+ return originalToast.loading(message, { duration: currentDuration, ...options });
113
+ },
114
+ promise: <T,>(
115
+ promise: Promise<T>,
116
+ msgs: {
117
+ loading: Renderable;
118
+ success: ValueOrFunction<Renderable, T>;
119
+ error: ValueOrFunction<Renderable, any>;
120
+ },
121
+ opts?: DefaultToastOptions
122
+ ) => {
123
+ playToastSound();
124
+ return originalToast.promise(promise, msgs, opts);
125
+ },
126
+ dismiss: originalToast.dismiss.bind(originalToast),
127
+ remove: originalToast.remove.bind(originalToast),
128
+ custom: originalToast.custom.bind(originalToast)
129
+ }
130
+ );
131
+
296
132
  export { originalToast };
297
133
  export type { ToastOptions };
298
134
  </script>
299
135
 
300
136
  <script lang="ts">
301
- import { Toaster, toast as originalToast, type ToastOptions } from 'svelte-french-toast';
137
+ import { Toaster } from 'svelte-french-toast';
302
138
 
303
139
  let {
304
140
  position = 'top-center',
305
141
  duration = 4000,
306
- theme = {},
307
- className = '',
308
142
  toastOptions = {},
143
+ reverseOrder = false,
144
+ gutter = 8,
145
+ containerStyle,
146
+ containerClassName,
147
+ className = '',
148
+ theme = {},
309
149
  richColors = false,
310
150
  customIcons = true,
311
151
  closeButton = true,
312
152
  pauseOnHover = true,
313
- reverseOrder = false,
314
153
  visibleToasts = 3,
315
154
  expand = false,
316
155
  gap = 8,
317
- offset = '32px'
156
+ offset = '32px',
157
+ fireWithSound = false
318
158
  }: ToasterProps = $props();
319
159
 
320
160
  $effect(() => {
321
- updateToastConfig({ duration, theme, richColors });
161
+ // theme/richColors/customIcons are intentionally ignored in wrapper mode.
162
+ void theme;
163
+ void richColors;
164
+ void customIcons;
165
+ updateToastConfig({ duration, fireWithSound });
322
166
  });
323
167
  </script>
324
168
 
325
169
  <Toaster
326
170
  {position}
327
- {duration}
328
- {className}
329
171
  {toastOptions}
330
- {closeButton}
331
- {pauseOnHover}
332
172
  {reverseOrder}
333
- {visibleToasts}
334
- {expand}
335
- {gap}
336
- {offset}
173
+ {gutter}
174
+ {containerStyle}
175
+ containerClassName={containerClassName || className}
337
176
  />