sileo-sveltekit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +490 -0
- package/dist/SileoToast.svelte +654 -0
- package/dist/SileoToast.svelte.d.ts +22 -0
- package/dist/Toaster.svelte +719 -0
- package/dist/Toaster.svelte.d.ts +29 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/package.json +73 -0
|
@@ -0,0 +1,654 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
export type SileoState = 'success' | 'error' | 'warning' | 'info' | 'action' | 'loading';
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import { spring } from 'svelte/motion';
|
|
7
|
+
import { onMount } from 'svelte';
|
|
8
|
+
|
|
9
|
+
/* --------------------------------- Types --------------------------------- */
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
id: string;
|
|
13
|
+
fill?: string;
|
|
14
|
+
toastState?: SileoState;
|
|
15
|
+
title?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
position?: 'left' | 'center' | 'right';
|
|
18
|
+
expand?: 'top' | 'bottom';
|
|
19
|
+
roundness?: number;
|
|
20
|
+
exiting?: boolean;
|
|
21
|
+
autoExpandDelayMs?: number;
|
|
22
|
+
autoCollapseDelayMs?: number;
|
|
23
|
+
canExpand?: boolean;
|
|
24
|
+
refreshKey?: string;
|
|
25
|
+
onmouseenter?: (e: MouseEvent) => void;
|
|
26
|
+
onmouseleave?: (e: MouseEvent) => void;
|
|
27
|
+
ondismiss?: () => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* -------------------------------- Constants ------------------------------- */
|
|
31
|
+
|
|
32
|
+
const HEIGHT = 40;
|
|
33
|
+
const WIDTH = 350;
|
|
34
|
+
const DEFAULT_ROUNDNESS = 16;
|
|
35
|
+
const BLUR_RATIO = 0.5;
|
|
36
|
+
const PILL_PADDING = 10;
|
|
37
|
+
const MIN_EXPAND_RATIO = 2.25;
|
|
38
|
+
const HEADER_EXIT_MS = 420; // DURATION_MS * 0.7
|
|
39
|
+
const SWAP_COLLAPSE_MS = 200;
|
|
40
|
+
const SWIPE_DISMISS = 30;
|
|
41
|
+
const SWIPE_MAX = 20;
|
|
42
|
+
|
|
43
|
+
/* --------------------------------- Props ---------------------------------- */
|
|
44
|
+
|
|
45
|
+
let {
|
|
46
|
+
id,
|
|
47
|
+
fill,
|
|
48
|
+
toastState = 'success',
|
|
49
|
+
title,
|
|
50
|
+
description,
|
|
51
|
+
position = 'right',
|
|
52
|
+
expand = 'bottom',
|
|
53
|
+
roundness,
|
|
54
|
+
exiting = false,
|
|
55
|
+
autoExpandDelayMs,
|
|
56
|
+
autoCollapseDelayMs,
|
|
57
|
+
canExpand = true,
|
|
58
|
+
refreshKey,
|
|
59
|
+
onmouseenter,
|
|
60
|
+
onmouseleave,
|
|
61
|
+
ondismiss
|
|
62
|
+
}: Props = $props();
|
|
63
|
+
|
|
64
|
+
/* ------------------------------- Resolved -------------------------------- */
|
|
65
|
+
|
|
66
|
+
const resolvedRoundness = $derived(Math.max(0, roundness ?? DEFAULT_ROUNDNESS));
|
|
67
|
+
const blur = $derived(resolvedRoundness * BLUR_RATIO);
|
|
68
|
+
const filterId = `sileo-gooey-${id}`;
|
|
69
|
+
|
|
70
|
+
/* --------------------------------- State ---------------------------------- */
|
|
71
|
+
|
|
72
|
+
let isExpanded = $state(false);
|
|
73
|
+
let ready = $state(false);
|
|
74
|
+
let contentHeight = $state(0);
|
|
75
|
+
let pillMeasuredWidth = $state(0);
|
|
76
|
+
|
|
77
|
+
// View state (for refresh/swap)
|
|
78
|
+
let viewState = $state<SileoState>(toastState);
|
|
79
|
+
let viewTitle = $state(title ?? toastState);
|
|
80
|
+
let viewDescription = $state(description);
|
|
81
|
+
let viewFill = $state(fill);
|
|
82
|
+
|
|
83
|
+
// Header layer for swap animation
|
|
84
|
+
let headerCurrent = $state({
|
|
85
|
+
key: `${toastState}-${title ?? toastState}`,
|
|
86
|
+
toastState,
|
|
87
|
+
title: title ?? toastState
|
|
88
|
+
});
|
|
89
|
+
let headerPrev = $state<{ key: string; toastState: SileoState; title: string } | null>(null);
|
|
90
|
+
|
|
91
|
+
/* ---------------------------------- Refs ---------------------------------- */
|
|
92
|
+
|
|
93
|
+
let buttonRef = $state<HTMLButtonElement | null>(null);
|
|
94
|
+
let headerRef = $state<HTMLDivElement | null>(null);
|
|
95
|
+
let innerRef = $state<HTMLDivElement | null>(null);
|
|
96
|
+
let contentRef = $state<HTMLDivElement | null>(null);
|
|
97
|
+
|
|
98
|
+
/* ----------------------------- Derived values ----------------------------- */
|
|
99
|
+
|
|
100
|
+
const hasDesc = $derived(Boolean(viewDescription));
|
|
101
|
+
const isLoading = $derived(viewState === 'loading');
|
|
102
|
+
const open = $derived(hasDesc && isExpanded && !isLoading && !exiting);
|
|
103
|
+
const allowExpand = $derived(!isLoading && canExpand);
|
|
104
|
+
|
|
105
|
+
const minExpanded = HEIGHT * MIN_EXPAND_RATIO;
|
|
106
|
+
const rawExpanded = $derived(
|
|
107
|
+
hasDesc ? Math.max(minExpanded, HEIGHT + contentHeight) : minExpanded
|
|
108
|
+
);
|
|
109
|
+
const expandedContent = $derived(Math.max(0, rawExpanded - HEIGHT));
|
|
110
|
+
const resolvedPillWidth = $derived(Math.max(pillMeasuredWidth || HEIGHT, HEIGHT));
|
|
111
|
+
const pillHeightExpanded = $derived(HEIGHT + blur * 3);
|
|
112
|
+
const svgHeight = $derived(
|
|
113
|
+
hasDesc ? Math.max(open ? rawExpanded : minExpanded, minExpanded) : HEIGHT
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
const pillXVal = $derived(
|
|
117
|
+
position === 'right'
|
|
118
|
+
? WIDTH - resolvedPillWidth
|
|
119
|
+
: position === 'center'
|
|
120
|
+
? (WIDTH - resolvedPillWidth) / 2
|
|
121
|
+
: 0
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
/* ----------------------------- Spring stores ----------------------------- */
|
|
125
|
+
|
|
126
|
+
// Matching Framer Motion: { type: "spring", bounce: 0.25, duration: 0.6 }
|
|
127
|
+
const SPRING_OPTS = { stiffness: 0.066, damping: 0.53 };
|
|
128
|
+
const NO_BOUNCE_OPTS = { stiffness: 0.066, damping: 0.88 };
|
|
129
|
+
|
|
130
|
+
const sPillX = spring(0, SPRING_OPTS);
|
|
131
|
+
const sPillW = spring(HEIGHT, SPRING_OPTS);
|
|
132
|
+
const sPillH = spring(HEIGHT, SPRING_OPTS);
|
|
133
|
+
const sBodyH = spring(0, SPRING_OPTS);
|
|
134
|
+
const sBodyO = spring(0, SPRING_OPTS);
|
|
135
|
+
|
|
136
|
+
/* ----------------------------- Spring updates ----------------------------- */
|
|
137
|
+
|
|
138
|
+
$effect(() => {
|
|
139
|
+
if (!ready) {
|
|
140
|
+
sPillX.set(pillXVal, { hard: true });
|
|
141
|
+
sPillW.set(resolvedPillWidth, { hard: true });
|
|
142
|
+
sPillH.set(HEIGHT, { hard: true });
|
|
143
|
+
} else {
|
|
144
|
+
sPillX.set(pillXVal);
|
|
145
|
+
sPillW.set(resolvedPillWidth);
|
|
146
|
+
sPillH.set(open ? pillHeightExpanded : HEIGHT);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
$effect(() => {
|
|
151
|
+
if (open) {
|
|
152
|
+
sPillH.stiffness = SPRING_OPTS.stiffness;
|
|
153
|
+
sPillH.damping = SPRING_OPTS.damping;
|
|
154
|
+
sBodyH.stiffness = SPRING_OPTS.stiffness;
|
|
155
|
+
sBodyH.damping = SPRING_OPTS.damping;
|
|
156
|
+
sBodyO.stiffness = SPRING_OPTS.stiffness;
|
|
157
|
+
sBodyO.damping = SPRING_OPTS.damping;
|
|
158
|
+
sBodyH.set(expandedContent);
|
|
159
|
+
sBodyO.set(1);
|
|
160
|
+
} else {
|
|
161
|
+
// No bounce on collapse (matching sileo's { ...SPRING, bounce: 0 })
|
|
162
|
+
sPillH.stiffness = NO_BOUNCE_OPTS.stiffness;
|
|
163
|
+
sPillH.damping = NO_BOUNCE_OPTS.damping;
|
|
164
|
+
sBodyH.stiffness = NO_BOUNCE_OPTS.stiffness;
|
|
165
|
+
sBodyH.damping = NO_BOUNCE_OPTS.damping;
|
|
166
|
+
sBodyO.stiffness = NO_BOUNCE_OPTS.stiffness;
|
|
167
|
+
sBodyO.damping = NO_BOUNCE_OPTS.damping;
|
|
168
|
+
sPillH.set(HEIGHT);
|
|
169
|
+
sBodyH.set(0);
|
|
170
|
+
sBodyO.set(0);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
/* ----------------------------- Measurements ------------------------------ */
|
|
175
|
+
|
|
176
|
+
let headerPadding: number | null = null;
|
|
177
|
+
|
|
178
|
+
$effect(() => {
|
|
179
|
+
if (!innerRef || !headerRef) return;
|
|
180
|
+
|
|
181
|
+
if (headerPadding === null) {
|
|
182
|
+
const cs = getComputedStyle(headerRef);
|
|
183
|
+
headerPadding = parseFloat(cs.paddingLeft) + parseFloat(cs.paddingRight);
|
|
184
|
+
}
|
|
185
|
+
const pad = headerPadding;
|
|
186
|
+
|
|
187
|
+
const measure = () => {
|
|
188
|
+
if (!innerRef) return;
|
|
189
|
+
const w = innerRef.scrollWidth + pad + PILL_PADDING;
|
|
190
|
+
if (w > PILL_PADDING) pillMeasuredWidth = w;
|
|
191
|
+
};
|
|
192
|
+
measure();
|
|
193
|
+
|
|
194
|
+
const ro = new ResizeObserver(() => {
|
|
195
|
+
requestAnimationFrame(measure);
|
|
196
|
+
});
|
|
197
|
+
ro.observe(innerRef);
|
|
198
|
+
|
|
199
|
+
return () => ro.disconnect();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
$effect(() => {
|
|
203
|
+
if (!hasDesc || !contentRef) {
|
|
204
|
+
contentHeight = 0;
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const measure = () => {
|
|
209
|
+
if (!contentRef) return;
|
|
210
|
+
contentHeight = contentRef.scrollHeight;
|
|
211
|
+
};
|
|
212
|
+
measure();
|
|
213
|
+
|
|
214
|
+
const ro = new ResizeObserver(() => {
|
|
215
|
+
requestAnimationFrame(measure);
|
|
216
|
+
});
|
|
217
|
+
ro.observe(contentRef);
|
|
218
|
+
|
|
219
|
+
return () => ro.disconnect();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
/* --------------------------------- Ready --------------------------------- */
|
|
223
|
+
|
|
224
|
+
onMount(() => {
|
|
225
|
+
requestAnimationFrame(() => {
|
|
226
|
+
ready = true;
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
/* ----------------------------- Header layer ------------------------------ */
|
|
231
|
+
|
|
232
|
+
$effect(() => {
|
|
233
|
+
const newKey = `${toastState}-${title ?? toastState}`;
|
|
234
|
+
if (headerCurrent.key !== newKey) {
|
|
235
|
+
headerPrev = headerCurrent;
|
|
236
|
+
headerCurrent = { key: newKey, toastState, title: title ?? toastState };
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
$effect(() => {
|
|
241
|
+
if (!headerPrev) return;
|
|
242
|
+
const timer = setTimeout(() => {
|
|
243
|
+
headerPrev = null;
|
|
244
|
+
}, HEADER_EXIT_MS);
|
|
245
|
+
return () => clearTimeout(timer);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
/* ----------------------------- View refresh ------------------------------ */
|
|
249
|
+
|
|
250
|
+
let lastRefreshKey = refreshKey;
|
|
251
|
+
let pendingSwap: {
|
|
252
|
+
key: string;
|
|
253
|
+
toastState: SileoState;
|
|
254
|
+
title: string;
|
|
255
|
+
description?: string;
|
|
256
|
+
fill?: string;
|
|
257
|
+
} | null = null;
|
|
258
|
+
|
|
259
|
+
$effect(() => {
|
|
260
|
+
if (refreshKey === undefined) {
|
|
261
|
+
viewState = toastState;
|
|
262
|
+
viewTitle = title ?? toastState;
|
|
263
|
+
viewDescription = description;
|
|
264
|
+
viewFill = fill;
|
|
265
|
+
pendingSwap = null;
|
|
266
|
+
lastRefreshKey = refreshKey;
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (lastRefreshKey === refreshKey) return;
|
|
271
|
+
lastRefreshKey = refreshKey;
|
|
272
|
+
|
|
273
|
+
if (open) {
|
|
274
|
+
pendingSwap = { key: refreshKey, toastState, title: title ?? toastState, description, fill };
|
|
275
|
+
isExpanded = false;
|
|
276
|
+
setTimeout(() => {
|
|
277
|
+
if (!pendingSwap) return;
|
|
278
|
+
viewState = pendingSwap.toastState;
|
|
279
|
+
viewTitle = pendingSwap.title;
|
|
280
|
+
viewDescription = pendingSwap.description;
|
|
281
|
+
viewFill = pendingSwap.fill;
|
|
282
|
+
pendingSwap = null;
|
|
283
|
+
}, SWAP_COLLAPSE_MS);
|
|
284
|
+
} else {
|
|
285
|
+
pendingSwap = null;
|
|
286
|
+
viewState = toastState;
|
|
287
|
+
viewTitle = title ?? toastState;
|
|
288
|
+
viewDescription = description;
|
|
289
|
+
viewFill = fill;
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
/* ----------------------------- Auto expand/collapse ---------------------- */
|
|
294
|
+
|
|
295
|
+
$effect(() => {
|
|
296
|
+
if (!hasDesc || exiting || !allowExpand) {
|
|
297
|
+
if (exiting) isExpanded = false;
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (autoExpandDelayMs == null && autoCollapseDelayMs == null) return;
|
|
301
|
+
|
|
302
|
+
const expandDelay = autoExpandDelayMs ?? 0;
|
|
303
|
+
const collapseDelay = autoCollapseDelayMs ?? 0;
|
|
304
|
+
|
|
305
|
+
let expandTimer: ReturnType<typeof setTimeout> | undefined;
|
|
306
|
+
let collapseTimer: ReturnType<typeof setTimeout> | undefined;
|
|
307
|
+
|
|
308
|
+
if (expandDelay > 0) {
|
|
309
|
+
expandTimer = setTimeout(() => {
|
|
310
|
+
isExpanded = true;
|
|
311
|
+
}, expandDelay);
|
|
312
|
+
} else {
|
|
313
|
+
isExpanded = true;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (collapseDelay > 0) {
|
|
317
|
+
collapseTimer = setTimeout(() => {
|
|
318
|
+
isExpanded = false;
|
|
319
|
+
}, collapseDelay);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return () => {
|
|
323
|
+
if (expandTimer) clearTimeout(expandTimer);
|
|
324
|
+
if (collapseTimer) clearTimeout(collapseTimer);
|
|
325
|
+
};
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
/* --------------------------------- Swipe --------------------------------- */
|
|
329
|
+
|
|
330
|
+
let pointerStart: number | null = null;
|
|
331
|
+
|
|
332
|
+
function handlePointerDown(e: PointerEvent) {
|
|
333
|
+
if (exiting || !ondismiss) return;
|
|
334
|
+
const target = e.target as HTMLElement;
|
|
335
|
+
if (target.closest('[data-sileo-button]')) return;
|
|
336
|
+
pointerStart = e.clientY;
|
|
337
|
+
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function handlePointerMove(e: PointerEvent) {
|
|
341
|
+
if (pointerStart === null || !buttonRef) return;
|
|
342
|
+
const dy = e.clientY - pointerStart;
|
|
343
|
+
const sign = dy > 0 ? 1 : -1;
|
|
344
|
+
const clamped = Math.min(Math.abs(dy), SWIPE_MAX) * sign;
|
|
345
|
+
buttonRef.style.transform = `translateY(${clamped}px)`;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function handlePointerUp(e: PointerEvent) {
|
|
349
|
+
if (pointerStart === null || !buttonRef) return;
|
|
350
|
+
const dy = e.clientY - pointerStart;
|
|
351
|
+
pointerStart = null;
|
|
352
|
+
buttonRef.style.transform = '';
|
|
353
|
+
if (Math.abs(dy) > SWIPE_DISMISS) {
|
|
354
|
+
ondismiss?.();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/* ------------------------------- Handlers -------------------------------- */
|
|
359
|
+
|
|
360
|
+
function handleEnter(e: MouseEvent) {
|
|
361
|
+
onmouseenter?.(e);
|
|
362
|
+
if (hasDesc && allowExpand) isExpanded = true;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function handleLeave(e: MouseEvent) {
|
|
366
|
+
onmouseleave?.(e);
|
|
367
|
+
isExpanded = false;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/* ----------------------------- Inline styles ----------------------------- */
|
|
371
|
+
|
|
372
|
+
const rootStyle = $derived(
|
|
373
|
+
`--_h: ${open ? rawExpanded : HEIGHT}px; --_pw: ${resolvedPillWidth}px; --_px: ${pillXVal}px; --_ht: translateY(${open ? (expand === 'bottom' ? 3 : -3) : 0}px) scale(${open ? 0.9 : 1}); --_co: ${open ? 1 : 0};`
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
const resolvedFill = $derived(viewFill || 'var(--sileo-fill, #fff)');
|
|
377
|
+
</script>
|
|
378
|
+
|
|
379
|
+
<button
|
|
380
|
+
bind:this={buttonRef}
|
|
381
|
+
type="button"
|
|
382
|
+
data-sileo-toast
|
|
383
|
+
data-ready={ready}
|
|
384
|
+
data-expanded={open}
|
|
385
|
+
data-exiting={exiting}
|
|
386
|
+
data-edge={expand}
|
|
387
|
+
data-position={position}
|
|
388
|
+
data-state={viewState}
|
|
389
|
+
style={rootStyle}
|
|
390
|
+
onmouseenter={handleEnter}
|
|
391
|
+
onmouseleave={handleLeave}
|
|
392
|
+
onpointerdown={handlePointerDown}
|
|
393
|
+
onpointermove={handlePointerMove}
|
|
394
|
+
onpointerup={handlePointerUp}
|
|
395
|
+
>
|
|
396
|
+
<!-- SVG Gooey Canvas -->
|
|
397
|
+
<div data-sileo-canvas data-edge={expand} style="filter: url(#{filterId})">
|
|
398
|
+
<svg data-sileo-svg width={WIDTH} height={svgHeight} viewBox="0 0 {WIDTH} {svgHeight}">
|
|
399
|
+
<title>Sileo Notification</title>
|
|
400
|
+
<defs>
|
|
401
|
+
<filter
|
|
402
|
+
id={filterId}
|
|
403
|
+
x="-20%"
|
|
404
|
+
y="-20%"
|
|
405
|
+
width="140%"
|
|
406
|
+
height="140%"
|
|
407
|
+
color-interpolation-filters="sRGB"
|
|
408
|
+
>
|
|
409
|
+
<feGaussianBlur in="SourceGraphic" stdDeviation={blur} result="blur" />
|
|
410
|
+
<feColorMatrix
|
|
411
|
+
in="blur"
|
|
412
|
+
mode="matrix"
|
|
413
|
+
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 20 -10"
|
|
414
|
+
result="goo"
|
|
415
|
+
/>
|
|
416
|
+
<feComposite in="SourceGraphic" in2="goo" operator="atop" />
|
|
417
|
+
</filter>
|
|
418
|
+
</defs>
|
|
419
|
+
|
|
420
|
+
<!-- Pill -->
|
|
421
|
+
<rect
|
|
422
|
+
data-sileo-pill
|
|
423
|
+
x={$sPillX}
|
|
424
|
+
width={$sPillW}
|
|
425
|
+
height={$sPillH}
|
|
426
|
+
rx={resolvedRoundness}
|
|
427
|
+
ry={resolvedRoundness}
|
|
428
|
+
fill={resolvedFill}
|
|
429
|
+
/>
|
|
430
|
+
|
|
431
|
+
<!-- Body (expanded area) -->
|
|
432
|
+
<rect
|
|
433
|
+
data-sileo-body
|
|
434
|
+
y={HEIGHT}
|
|
435
|
+
width={WIDTH}
|
|
436
|
+
height={$sBodyH}
|
|
437
|
+
rx={resolvedRoundness}
|
|
438
|
+
ry={resolvedRoundness}
|
|
439
|
+
fill={resolvedFill}
|
|
440
|
+
opacity={$sBodyO}
|
|
441
|
+
/>
|
|
442
|
+
</svg>
|
|
443
|
+
</div>
|
|
444
|
+
|
|
445
|
+
<!-- Header (icon + title) -->
|
|
446
|
+
<div bind:this={headerRef} data-sileo-header data-edge={expand}>
|
|
447
|
+
<div data-sileo-header-stack>
|
|
448
|
+
<!-- Current header -->
|
|
449
|
+
{#key headerCurrent.key}
|
|
450
|
+
<div bind:this={innerRef} data-sileo-header-inner data-layer="current">
|
|
451
|
+
<div data-sileo-badge data-state={headerCurrent.toastState}>
|
|
452
|
+
{#if headerCurrent.toastState === 'success'}
|
|
453
|
+
<svg
|
|
454
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
455
|
+
width="16"
|
|
456
|
+
height="16"
|
|
457
|
+
viewBox="0 0 24 24"
|
|
458
|
+
fill="none"
|
|
459
|
+
stroke="currentColor"
|
|
460
|
+
stroke-width="2"
|
|
461
|
+
stroke-linecap="round"
|
|
462
|
+
stroke-linejoin="round"><title>Success</title><path d="M20 6 9 17l-5-5" /></svg
|
|
463
|
+
>
|
|
464
|
+
{:else if headerCurrent.toastState === 'error'}
|
|
465
|
+
<svg
|
|
466
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
467
|
+
width="16"
|
|
468
|
+
height="16"
|
|
469
|
+
viewBox="0 0 24 24"
|
|
470
|
+
fill="none"
|
|
471
|
+
stroke="currentColor"
|
|
472
|
+
stroke-width="2"
|
|
473
|
+
stroke-linecap="round"
|
|
474
|
+
stroke-linejoin="round"
|
|
475
|
+
><title>Error</title><path d="M18 6 6 18" /><path d="m6 6 12 12" /></svg
|
|
476
|
+
>
|
|
477
|
+
{:else if headerCurrent.toastState === 'warning'}
|
|
478
|
+
<svg
|
|
479
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
480
|
+
width="16"
|
|
481
|
+
height="16"
|
|
482
|
+
viewBox="0 0 24 24"
|
|
483
|
+
fill="none"
|
|
484
|
+
stroke="currentColor"
|
|
485
|
+
stroke-width="2"
|
|
486
|
+
stroke-linecap="round"
|
|
487
|
+
stroke-linejoin="round"
|
|
488
|
+
><title>Warning</title><circle cx="12" cy="12" r="10" /><line
|
|
489
|
+
x1="12"
|
|
490
|
+
x2="12"
|
|
491
|
+
y1="8"
|
|
492
|
+
y2="12"
|
|
493
|
+
/><line x1="12" x2="12.01" y1="16" y2="16" /></svg
|
|
494
|
+
>
|
|
495
|
+
{:else if headerCurrent.toastState === 'info'}
|
|
496
|
+
<svg
|
|
497
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
498
|
+
width="16"
|
|
499
|
+
height="16"
|
|
500
|
+
viewBox="0 0 24 24"
|
|
501
|
+
fill="none"
|
|
502
|
+
stroke="currentColor"
|
|
503
|
+
stroke-width="2"
|
|
504
|
+
stroke-linecap="round"
|
|
505
|
+
stroke-linejoin="round"
|
|
506
|
+
><title>Info</title><circle cx="12" cy="12" r="10" /><path
|
|
507
|
+
d="m4.93 4.93 4.24 4.24"
|
|
508
|
+
/><path d="m14.83 9.17 4.24-4.24" /><path d="m14.83 14.83 4.24 4.24" /><path
|
|
509
|
+
d="m9.17 14.83-4.24 4.24"
|
|
510
|
+
/><circle cx="12" cy="12" r="4" /></svg
|
|
511
|
+
>
|
|
512
|
+
{:else if headerCurrent.toastState === 'loading'}
|
|
513
|
+
<svg
|
|
514
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
515
|
+
width="16"
|
|
516
|
+
height="16"
|
|
517
|
+
viewBox="0 0 24 24"
|
|
518
|
+
fill="none"
|
|
519
|
+
stroke="currentColor"
|
|
520
|
+
stroke-width="2"
|
|
521
|
+
stroke-linecap="round"
|
|
522
|
+
stroke-linejoin="round"
|
|
523
|
+
data-sileo-icon="spin"><title>Loading</title><path d="M21 12a9 9 0 1 1-6.219-8.56" /></svg
|
|
524
|
+
>
|
|
525
|
+
{:else}
|
|
526
|
+
<svg
|
|
527
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
528
|
+
width="16"
|
|
529
|
+
height="16"
|
|
530
|
+
viewBox="0 0 24 24"
|
|
531
|
+
fill="none"
|
|
532
|
+
stroke="currentColor"
|
|
533
|
+
stroke-width="2"
|
|
534
|
+
stroke-linecap="round"
|
|
535
|
+
stroke-linejoin="round"
|
|
536
|
+
><title>Action</title><path d="M5 12h14" /><path d="m12 5 7 7-7 7" /></svg
|
|
537
|
+
>
|
|
538
|
+
{/if}
|
|
539
|
+
</div>
|
|
540
|
+
<span data-sileo-title data-state={headerCurrent.toastState}>{headerCurrent.title}</span
|
|
541
|
+
>
|
|
542
|
+
</div>
|
|
543
|
+
{/key}
|
|
544
|
+
|
|
545
|
+
<!-- Previous header (exiting) -->
|
|
546
|
+
{#if headerPrev}
|
|
547
|
+
{#key headerPrev.key}
|
|
548
|
+
<div data-sileo-header-inner data-layer="prev" data-exiting="true">
|
|
549
|
+
<div data-sileo-badge data-state={headerPrev.toastState}>
|
|
550
|
+
{#if headerPrev.toastState === 'success'}
|
|
551
|
+
<svg
|
|
552
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
553
|
+
width="16"
|
|
554
|
+
height="16"
|
|
555
|
+
viewBox="0 0 24 24"
|
|
556
|
+
fill="none"
|
|
557
|
+
stroke="currentColor"
|
|
558
|
+
stroke-width="2"
|
|
559
|
+
stroke-linecap="round"
|
|
560
|
+
stroke-linejoin="round"><title>Success</title><path d="M20 6 9 17l-5-5" /></svg
|
|
561
|
+
>
|
|
562
|
+
{:else if headerPrev.toastState === 'error'}
|
|
563
|
+
<svg
|
|
564
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
565
|
+
width="16"
|
|
566
|
+
height="16"
|
|
567
|
+
viewBox="0 0 24 24"
|
|
568
|
+
fill="none"
|
|
569
|
+
stroke="currentColor"
|
|
570
|
+
stroke-width="2"
|
|
571
|
+
stroke-linecap="round"
|
|
572
|
+
stroke-linejoin="round"
|
|
573
|
+
><title>Error</title><path d="M18 6 6 18" /><path d="m6 6 12 12" /></svg
|
|
574
|
+
>
|
|
575
|
+
{:else if headerPrev.toastState === 'warning'}
|
|
576
|
+
<svg
|
|
577
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
578
|
+
width="16"
|
|
579
|
+
height="16"
|
|
580
|
+
viewBox="0 0 24 24"
|
|
581
|
+
fill="none"
|
|
582
|
+
stroke="currentColor"
|
|
583
|
+
stroke-width="2"
|
|
584
|
+
stroke-linecap="round"
|
|
585
|
+
stroke-linejoin="round"
|
|
586
|
+
><title>Warning</title><circle cx="12" cy="12" r="10" /><line
|
|
587
|
+
x1="12"
|
|
588
|
+
x2="12"
|
|
589
|
+
y1="8"
|
|
590
|
+
y2="12"
|
|
591
|
+
/><line x1="12" x2="12.01" y1="16" y2="16" /></svg
|
|
592
|
+
>
|
|
593
|
+
{:else if headerPrev.toastState === 'info'}
|
|
594
|
+
<svg
|
|
595
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
596
|
+
width="16"
|
|
597
|
+
height="16"
|
|
598
|
+
viewBox="0 0 24 24"
|
|
599
|
+
fill="none"
|
|
600
|
+
stroke="currentColor"
|
|
601
|
+
stroke-width="2"
|
|
602
|
+
stroke-linecap="round"
|
|
603
|
+
stroke-linejoin="round"
|
|
604
|
+
><title>Info</title><circle cx="12" cy="12" r="10" /><path
|
|
605
|
+
d="m4.93 4.93 4.24 4.24"
|
|
606
|
+
/><path d="m14.83 9.17 4.24-4.24" /><path d="m14.83 14.83 4.24 4.24" /><path
|
|
607
|
+
d="m9.17 14.83-4.24 4.24"
|
|
608
|
+
/><circle cx="12" cy="12" r="4" /></svg
|
|
609
|
+
>
|
|
610
|
+
{:else if headerPrev.toastState === 'loading'}
|
|
611
|
+
<svg
|
|
612
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
613
|
+
width="16"
|
|
614
|
+
height="16"
|
|
615
|
+
viewBox="0 0 24 24"
|
|
616
|
+
fill="none"
|
|
617
|
+
stroke="currentColor"
|
|
618
|
+
stroke-width="2"
|
|
619
|
+
stroke-linecap="round"
|
|
620
|
+
stroke-linejoin="round"
|
|
621
|
+
data-sileo-icon="spin"
|
|
622
|
+
><title>Loading</title><path d="M21 12a9 9 0 1 1-6.219-8.56" /></svg
|
|
623
|
+
>
|
|
624
|
+
{:else}
|
|
625
|
+
<svg
|
|
626
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
627
|
+
width="16"
|
|
628
|
+
height="16"
|
|
629
|
+
viewBox="0 0 24 24"
|
|
630
|
+
fill="none"
|
|
631
|
+
stroke="currentColor"
|
|
632
|
+
stroke-width="2"
|
|
633
|
+
stroke-linecap="round"
|
|
634
|
+
stroke-linejoin="round"
|
|
635
|
+
><title>Action</title><path d="M5 12h14" /><path d="m12 5 7 7-7 7" /></svg
|
|
636
|
+
>
|
|
637
|
+
{/if}
|
|
638
|
+
</div>
|
|
639
|
+
<span data-sileo-title data-state={headerPrev.toastState}>{headerPrev.title}</span>
|
|
640
|
+
</div>
|
|
641
|
+
{/key}
|
|
642
|
+
{/if}
|
|
643
|
+
</div>
|
|
644
|
+
</div>
|
|
645
|
+
|
|
646
|
+
<!-- Content (description) -->
|
|
647
|
+
{#if hasDesc}
|
|
648
|
+
<div data-sileo-content data-edge={expand} data-visible={open}>
|
|
649
|
+
<div bind:this={contentRef} data-sileo-description>
|
|
650
|
+
{viewDescription}
|
|
651
|
+
</div>
|
|
652
|
+
</div>
|
|
653
|
+
{/if}
|
|
654
|
+
</button>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type SileoState = 'success' | 'error' | 'warning' | 'info' | 'action' | 'loading';
|
|
2
|
+
interface Props {
|
|
3
|
+
id: string;
|
|
4
|
+
fill?: string;
|
|
5
|
+
toastState?: SileoState;
|
|
6
|
+
title?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
position?: 'left' | 'center' | 'right';
|
|
9
|
+
expand?: 'top' | 'bottom';
|
|
10
|
+
roundness?: number;
|
|
11
|
+
exiting?: boolean;
|
|
12
|
+
autoExpandDelayMs?: number;
|
|
13
|
+
autoCollapseDelayMs?: number;
|
|
14
|
+
canExpand?: boolean;
|
|
15
|
+
refreshKey?: string;
|
|
16
|
+
onmouseenter?: (e: MouseEvent) => void;
|
|
17
|
+
onmouseleave?: (e: MouseEvent) => void;
|
|
18
|
+
ondismiss?: () => void;
|
|
19
|
+
}
|
|
20
|
+
declare const SileoToast: import("svelte").Component<Props, {}, "">;
|
|
21
|
+
type SileoToast = ReturnType<typeof SileoToast>;
|
|
22
|
+
export default SileoToast;
|