@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.
- package/dist/ui/modal/Modal.svelte +97 -52
- package/dist/ui/toast/Toast.svelte +120 -281
- package/dist/ui/toast/Toast.svelte.d.ts +27 -52
- package/dist/ui/toast/index.d.ts +2 -1
- package/dist/ui/toast/index.js +1 -3
- package/package.json +1 -1
- package/dist/forms/FormSelect/index.d.ts +0 -1
- package/dist/forms/FormSelect/index.js +0 -1
- package/dist/forms/input/index.d.ts +0 -4
- package/dist/forms/input/index.js +0 -5
- package/dist/forms/input/theme.d.ts +0 -301
- package/dist/forms/input/theme.js +0 -100
- package/dist/layout/TF/Sidebar/Sidebar.svelte +0 -148
- package/dist/layout/TF/Sidebar/Sidebar.svelte.d.ts +0 -4
- package/dist/layout/TF/Sidebar/index.d.ts +0 -1
- package/dist/layout/TF/Sidebar/index.js +0 -1
- package/dist/layout/TF/Wrapper/index.d.ts +0 -1
- package/dist/layout/TF/Wrapper/index.js +0 -1
- package/dist/ui/accordion/theme.d.ts +0 -96
- package/dist/ui/accordion/theme.js +0 -59
- package/dist/ui/speedDial/SpeedDial.svelte +0 -77
- package/dist/ui/speedDial/SpeedDial.svelte.d.ts +0 -21
- package/dist/ui/tableLoader/TableLoader.svelte +0 -24
- package/dist/ui/tableLoader/TableLoader.svelte.d.ts +0 -13
|
@@ -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 = (
|
|
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
|
-
|
|
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
|
-
|
|
83
|
-
if (!permanent) close(ev.currentTarget);
|
|
76
|
+
ev.preventDefault();
|
|
77
|
+
if (!permanent) close();
|
|
84
78
|
}
|
|
85
79
|
|
|
86
|
-
function _onclick(ev:
|
|
87
|
-
const
|
|
88
|
-
if (outsideclose &&
|
|
89
|
-
|
|
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 &&
|
|
93
|
-
|
|
91
|
+
if (autoclose && target instanceof HTMLButtonElement && !permanent) {
|
|
92
|
+
close();
|
|
94
93
|
}
|
|
95
94
|
}
|
|
96
95
|
|
|
97
|
-
function _onsubmit(ev: SubmitEvent & { currentTarget:
|
|
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();
|
|
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
|
-
|
|
106
|
+
panel.dataset.returnValue = ev.submitter.value;
|
|
109
107
|
}
|
|
110
108
|
|
|
111
|
-
|
|
112
|
-
|
|
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 =
|
|
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 =
|
|
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:
|
|
143
|
+
onaction({ action: returnValue, data: formData }) === false
|
|
145
144
|
)
|
|
146
145
|
return;
|
|
147
146
|
|
|
148
|
-
close(
|
|
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:
|
|
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
|
-
|
|
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
|
|
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=
|
|
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
|
-
<
|
|
209
|
-
{@attach init}
|
|
233
|
+
<div
|
|
210
234
|
bind:this={ref}
|
|
211
235
|
use:focusTrap
|
|
212
|
-
class=
|
|
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
|
-
|
|
272
|
+
</div>
|
|
273
|
+
</div>
|
|
229
274
|
{/if}
|
|
230
275
|
|
|
231
276
|
<!--
|
|
@@ -1,337 +1,176 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
{
|
|
334
|
-
{
|
|
335
|
-
{
|
|
336
|
-
{offset}
|
|
173
|
+
{gutter}
|
|
174
|
+
{containerStyle}
|
|
175
|
+
containerClassName={containerClassName || className}
|
|
337
176
|
/>
|