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.
@@ -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;