@lanrenbang/basecoat-ultra-svelte 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.
Files changed (88) hide show
  1. package/dist/components/Accordion.svelte +64 -0
  2. package/dist/components/Accordion.svelte.d.ts +14 -0
  3. package/dist/components/Alert.svelte +51 -0
  4. package/dist/components/Alert.svelte.d.ts +12 -0
  5. package/dist/components/Avatar.svelte +57 -0
  6. package/dist/components/Avatar.svelte.d.ts +13 -0
  7. package/dist/components/Badge.svelte +30 -0
  8. package/dist/components/Badge.svelte.d.ts +10 -0
  9. package/dist/components/Breadcrumb.svelte +54 -0
  10. package/dist/components/Breadcrumb.svelte.d.ts +14 -0
  11. package/dist/components/Button.svelte +38 -0
  12. package/dist/components/Button.svelte.d.ts +12 -0
  13. package/dist/components/ButtonGroup.svelte +26 -0
  14. package/dist/components/ButtonGroup.svelte.d.ts +10 -0
  15. package/dist/components/Card.svelte +67 -0
  16. package/dist/components/Card.svelte.d.ts +13 -0
  17. package/dist/components/Carousel.svelte +142 -0
  18. package/dist/components/Carousel.svelte.d.ts +11 -0
  19. package/dist/components/CatppuccinThemeSwitcher.svelte +132 -0
  20. package/dist/components/CatppuccinThemeSwitcher.svelte.d.ts +3 -0
  21. package/dist/components/Checkbox.svelte +20 -0
  22. package/dist/components/Checkbox.svelte.d.ts +8 -0
  23. package/dist/components/Collapsible.svelte +39 -0
  24. package/dist/components/Collapsible.svelte.d.ts +13 -0
  25. package/dist/components/Command.svelte +78 -0
  26. package/dist/components/Command.svelte.d.ts +12 -0
  27. package/dist/components/DatePicker.svelte +172 -0
  28. package/dist/components/DatePicker.svelte.d.ts +13 -0
  29. package/dist/components/Dialog.svelte +91 -0
  30. package/dist/components/Dialog.svelte.d.ts +14 -0
  31. package/dist/components/Drawer.svelte +127 -0
  32. package/dist/components/Drawer.svelte.d.ts +12 -0
  33. package/dist/components/DropdownMenu.svelte +62 -0
  34. package/dist/components/DropdownMenu.svelte.d.ts +14 -0
  35. package/dist/components/Empty.svelte +58 -0
  36. package/dist/components/Empty.svelte.d.ts +12 -0
  37. package/dist/components/Input.svelte +22 -0
  38. package/dist/components/Input.svelte.d.ts +9 -0
  39. package/dist/components/InputOTP.svelte +189 -0
  40. package/dist/components/InputOTP.svelte.d.ts +12 -0
  41. package/dist/components/Item.svelte +64 -0
  42. package/dist/components/Item.svelte.d.ts +14 -0
  43. package/dist/components/Kbd.svelte +28 -0
  44. package/dist/components/Kbd.svelte.d.ts +9 -0
  45. package/dist/components/Label.svelte +30 -0
  46. package/dist/components/Label.svelte.d.ts +10 -0
  47. package/dist/components/Pagination.svelte +120 -0
  48. package/dist/components/Pagination.svelte.d.ts +35 -0
  49. package/dist/components/Popover.svelte +68 -0
  50. package/dist/components/Popover.svelte.d.ts +16 -0
  51. package/dist/components/Progress.svelte +26 -0
  52. package/dist/components/Progress.svelte.d.ts +9 -0
  53. package/dist/components/Radio.svelte +22 -0
  54. package/dist/components/Radio.svelte.d.ts +9 -0
  55. package/dist/components/Resizable.svelte +66 -0
  56. package/dist/components/Resizable.svelte.d.ts +13 -0
  57. package/dist/components/Select.svelte +183 -0
  58. package/dist/components/Select.svelte.d.ts +16 -0
  59. package/dist/components/Separator.svelte +19 -0
  60. package/dist/components/Separator.svelte.d.ts +8 -0
  61. package/dist/components/Sheet.svelte +182 -0
  62. package/dist/components/Sheet.svelte.d.ts +13 -0
  63. package/dist/components/Skeleton.svelte +27 -0
  64. package/dist/components/Skeleton.svelte.d.ts +8 -0
  65. package/dist/components/Slider.svelte +38 -0
  66. package/dist/components/Slider.svelte.d.ts +11 -0
  67. package/dist/components/Spinner.svelte +28 -0
  68. package/dist/components/Spinner.svelte.d.ts +8 -0
  69. package/dist/components/Switch.svelte +20 -0
  70. package/dist/components/Switch.svelte.d.ts +8 -0
  71. package/dist/components/Table.svelte +61 -0
  72. package/dist/components/Table.svelte.d.ts +13 -0
  73. package/dist/components/Tabs.svelte +97 -0
  74. package/dist/components/Tabs.svelte.d.ts +15 -0
  75. package/dist/components/Textarea.svelte +22 -0
  76. package/dist/components/Textarea.svelte.d.ts +9 -0
  77. package/dist/components/Toast.svelte +73 -0
  78. package/dist/components/Toast.svelte.d.ts +3 -0
  79. package/dist/components/Toggle.svelte +69 -0
  80. package/dist/components/Toggle.svelte.d.ts +13 -0
  81. package/dist/components/ToggleGroup.svelte +69 -0
  82. package/dist/components/ToggleGroup.svelte.d.ts +12 -0
  83. package/dist/components/Tooltip.svelte +32 -0
  84. package/dist/components/Tooltip.svelte.d.ts +11 -0
  85. package/dist/index.d.ts +42 -0
  86. package/dist/index.js +47 -0
  87. package/dist/reference.css +2 -0
  88. package/package.json +70 -0
@@ -0,0 +1,182 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import { onMount } from 'svelte';
4
+ import { fade } from 'svelte/transition';
5
+ import { cubicOut, backOut } from 'svelte/easing';
6
+
7
+ let {
8
+ open = $bindable(false),
9
+ side = 'right',
10
+ title,
11
+ description,
12
+ children,
13
+ class: className = '',
14
+ ...rest
15
+ }: {
16
+ open?: boolean;
17
+ side?: 'left' | 'right' | 'top' | 'bottom';
18
+ title?: string | Snippet;
19
+ description?: string | Snippet;
20
+ children: Snippet;
21
+ class?: string;
22
+ [key: string]: any;
23
+ } = $props();
24
+
25
+ let container: HTMLDivElement | undefined = $state();
26
+
27
+ // Custom spring-like transition for sheet content
28
+ function springSlide(node: Element, { duration = 400, side: s = 'right' }: { duration?: number; side?: string } = {}) {
29
+ const style = getComputedStyle(node);
30
+ const transform = style.transform === 'none' ? '' : style.transform;
31
+
32
+ let axis: 'x' | 'y';
33
+ let distance: number;
34
+
35
+ switch (s) {
36
+ case 'left':
37
+ axis = 'x';
38
+ distance = -node.clientWidth;
39
+ break;
40
+ case 'right':
41
+ axis = 'x';
42
+ distance = node.clientWidth;
43
+ break;
44
+ case 'top':
45
+ axis = 'y';
46
+ distance = -node.clientHeight;
47
+ break;
48
+ case 'bottom':
49
+ axis = 'y';
50
+ distance = node.clientHeight;
51
+ break;
52
+ default:
53
+ axis = 'x';
54
+ distance = node.clientWidth;
55
+ }
56
+
57
+ return {
58
+ duration,
59
+ css: (t: number) => {
60
+ // Use backOut easing for spring-like effect on enter
61
+ const eased = backOut(t);
62
+ const offset = (1 - eased) * distance;
63
+ const translateValue = axis === 'x' ? `translateX(${offset}px)` : `translateY(${offset}px)`;
64
+ return `transform: ${transform} ${translateValue}`;
65
+ }
66
+ };
67
+ }
68
+
69
+ function springSlideOut(node: Element, { duration = 300, side: s = 'right' }: { duration?: number; side?: string } = {}) {
70
+ let axis: 'x' | 'y';
71
+ let distance: number;
72
+
73
+ switch (s) {
74
+ case 'left':
75
+ axis = 'x';
76
+ distance = -node.clientWidth;
77
+ break;
78
+ case 'right':
79
+ axis = 'x';
80
+ distance = node.clientWidth;
81
+ break;
82
+ case 'top':
83
+ axis = 'y';
84
+ distance = -node.clientHeight;
85
+ break;
86
+ case 'bottom':
87
+ axis = 'y';
88
+ distance = node.clientHeight;
89
+ break;
90
+ default:
91
+ axis = 'x';
92
+ distance = node.clientWidth;
93
+ }
94
+
95
+ return {
96
+ duration,
97
+ css: (t: number) => {
98
+ const eased = cubicOut(t);
99
+ const offset = (1 - eased) * distance;
100
+ const translateValue = axis === 'x' ? `translateX(${offset}px)` : `translateY(${offset}px)`;
101
+ return `transform: ${translateValue}`;
102
+ }
103
+ };
104
+ }
105
+
106
+ function handleClickOutside(event: MouseEvent) {
107
+ if (open && event.target === container) {
108
+ open = false;
109
+ }
110
+ }
111
+
112
+ function handleKeyDown(event: KeyboardEvent) {
113
+ if (event.key === 'Escape' && open) {
114
+ open = false;
115
+ }
116
+ }
117
+
118
+ onMount(() => {
119
+ window.addEventListener('keydown', handleKeyDown);
120
+ return () => window.removeEventListener('keydown', handleKeyDown);
121
+ });
122
+
123
+ // Lock body scroll when open
124
+ $effect(() => {
125
+ if (open) {
126
+ document.body.style.overflow = 'hidden';
127
+ } else {
128
+ document.body.style.overflow = '';
129
+ }
130
+ });
131
+ </script>
132
+
133
+ {#if open}
134
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
135
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
136
+ <div
137
+ bind:this={container}
138
+ class="sheet fixed inset-0 z-50"
139
+ onclick={handleClickOutside}
140
+ >
141
+ <div
142
+ class="absolute inset-0 bg-black/80"
143
+ transition:fade={{ duration: 200 }}
144
+ ></div>
145
+ <div
146
+ class={['sheet-content', className].filter(Boolean).join(' ')}
147
+ data-side={side}
148
+ in:springSlide={{ duration: 400, side }}
149
+ out:springSlideOut={{ duration: 300, side }}
150
+ {...rest}
151
+ >
152
+ <button
153
+ class="absolute right-4 top-4 opacity-70 hover:opacity-100 transition-opacity"
154
+ onclick={() => open = false}
155
+ aria-label="Close"
156
+ >
157
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
158
+ </button>
159
+
160
+ {#if title}
161
+ <h2 class="text-lg font-semibold">
162
+ {#if typeof title === 'string'}{title}{:else}{@render title()}{/if}
163
+ </h2>
164
+ {/if}
165
+
166
+ {#if description}
167
+ <p class="text-sm text-muted-foreground">
168
+ {#if typeof description === 'string'}{description}{:else}{@render description()}{/if}
169
+ </p>
170
+ {/if}
171
+
172
+ <div class="mt-4">
173
+ {@render children()}
174
+ </div>
175
+ </div>
176
+ </div>
177
+ {/if}
178
+
179
+ <style>
180
+ @import "../../../../ultra/src/css/parts/custom/sheet.css";
181
+ @reference "../reference.css";
182
+ </style>
@@ -0,0 +1,13 @@
1
+ import type { Snippet } from 'svelte';
2
+ type $$ComponentProps = {
3
+ open?: boolean;
4
+ side?: 'left' | 'right' | 'top' | 'bottom';
5
+ title?: string | Snippet;
6
+ description?: string | Snippet;
7
+ children: Snippet;
8
+ class?: string;
9
+ [key: string]: any;
10
+ };
11
+ declare const Sheet: import("svelte").Component<$$ComponentProps, {}, "open">;
12
+ type Sheet = ReturnType<typeof Sheet>;
13
+ export default Sheet;
@@ -0,0 +1,27 @@
1
+ <script lang="ts">
2
+ let {
3
+ class: className = '',
4
+ rounded = 'md',
5
+ ...rest
6
+ }: {
7
+ class?: string;
8
+ rounded?: 'full' | 'lg' | 'md' | 'sm' | 'none';
9
+ [key: string]: any;
10
+ } = $props();
11
+
12
+ const roundedMap: Record<string, string> = {
13
+ full: 'rounded-full',
14
+ lg: 'rounded-lg',
15
+ md: 'rounded-md',
16
+ sm: 'rounded-sm',
17
+ none: 'rounded-none'
18
+ };
19
+
20
+ const finalClass = $derived([
21
+ 'skeleton bg-muted animate-pulse',
22
+ roundedMap[rounded] || rounded,
23
+ className
24
+ ].filter(Boolean).join(' '));
25
+ </script>
26
+
27
+ <div class={finalClass} {...rest}></div>
@@ -0,0 +1,8 @@
1
+ type $$ComponentProps = {
2
+ class?: string;
3
+ rounded?: 'full' | 'lg' | 'md' | 'sm' | 'none';
4
+ [key: string]: any;
5
+ };
6
+ declare const Skeleton: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type Skeleton = ReturnType<typeof Skeleton>;
8
+ export default Skeleton;
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ let {
3
+ value = $bindable(0),
4
+ min = 0,
5
+ max = 100,
6
+ step = 1,
7
+ class: className = '',
8
+ ...rest
9
+ }: {
10
+ value?: number;
11
+ min?: number;
12
+ max?: number;
13
+ step?: number;
14
+ class?: string;
15
+ [key: string]: any;
16
+ } = $props();
17
+
18
+ const finalClass = $derived(['slider', className].filter(Boolean).join(' '));
19
+
20
+ // Calculate slider value percentage for CSS variable
21
+ const sliderPercent = $derived(((value - min) / (max - min)) * 100);
22
+ </script>
23
+
24
+ <input
25
+ type="range"
26
+ class={finalClass}
27
+ bind:value
28
+ {min}
29
+ {max}
30
+ {step}
31
+ style="--slider-value: {sliderPercent}%"
32
+ {...rest}
33
+ />
34
+
35
+ <style>
36
+ @import "../../../../ultra/src/css/parts/components/range.css";
37
+ @reference "../reference.css";
38
+ </style>
@@ -0,0 +1,11 @@
1
+ type $$ComponentProps = {
2
+ value?: number;
3
+ min?: number;
4
+ max?: number;
5
+ step?: number;
6
+ class?: string;
7
+ [key: string]: any;
8
+ };
9
+ declare const Slider: import("svelte").Component<$$ComponentProps, {}, "value">;
10
+ type Slider = ReturnType<typeof Slider>;
11
+ export default Slider;
@@ -0,0 +1,28 @@
1
+ <script lang="ts">
2
+ let {
3
+ class: className = '',
4
+ size = 'md',
5
+ ...rest
6
+ }: {
7
+ class?: string;
8
+ size?: 'sm' | 'md' | 'lg' | string;
9
+ [key: string]: any;
10
+ } = $props();
11
+
12
+ const sizeMap: Record<string, string> = {
13
+ sm: 'h-4 w-4',
14
+ md: 'h-6 w-6',
15
+ lg: 'h-8 w-8'
16
+ };
17
+
18
+ const finalClass = $derived([
19
+ 'animate-spin text-primary',
20
+ sizeMap[size] || size,
21
+ className
22
+ ].filter(Boolean).join(' '));
23
+ </script>
24
+
25
+ <svg class={finalClass} xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" {...rest}>
26
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
27
+ <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
28
+ </svg>
@@ -0,0 +1,8 @@
1
+ type $$ComponentProps = {
2
+ class?: string;
3
+ size?: 'sm' | 'md' | 'lg' | string;
4
+ [key: string]: any;
5
+ };
6
+ declare const Spinner: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type Spinner = ReturnType<typeof Spinner>;
8
+ export default Spinner;
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ let {
3
+ checked = $bindable(false),
4
+ class: className = '',
5
+ ...rest
6
+ }: {
7
+ checked?: boolean;
8
+ class?: string;
9
+ [key: string]: any;
10
+ } = $props();
11
+
12
+ const finalClass = $derived(['input', className].filter(Boolean).join(' '));
13
+ </script>
14
+
15
+ <input type="checkbox" role="switch" class={finalClass} bind:checked {...rest} />
16
+
17
+ <style>
18
+ @import "../../../../ultra/src/css/parts/components/switch.css";
19
+ @reference "../reference.css";
20
+ </style>
@@ -0,0 +1,8 @@
1
+ type $$ComponentProps = {
2
+ checked?: boolean;
3
+ class?: string;
4
+ [key: string]: any;
5
+ };
6
+ declare const Switch: import("svelte").Component<$$ComponentProps, {}, "checked">;
7
+ type Switch = ReturnType<typeof Switch>;
8
+ export default Switch;
@@ -0,0 +1,61 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ let {
5
+ header,
6
+ children,
7
+ footer,
8
+ caption,
9
+ class: className = '',
10
+ containerClass = '',
11
+ ...rest
12
+ }: {
13
+ header?: Snippet;
14
+ children?: Snippet;
15
+ footer?: Snippet;
16
+ caption?: Snippet | string;
17
+ class?: string;
18
+ containerClass?: string;
19
+ [key: string]: any;
20
+ } = $props();
21
+
22
+ const finalContainerClass = $derived(['border rounded-lg overflow-hidden bg-card w-full', containerClass].filter(Boolean).join(' '));
23
+ const finalTableClass = $derived(['table w-full', className].filter(Boolean).join(' '));
24
+ </script>
25
+
26
+ <div class={finalContainerClass}>
27
+ <table class={finalTableClass} {...rest}>
28
+ {#if caption}
29
+ <caption>
30
+ {#if typeof caption === 'string'}
31
+ {caption}
32
+ {:else}
33
+ {@render caption()}
34
+ {/if}
35
+ </caption>
36
+ {/if}
37
+
38
+ {#if header}
39
+ <thead>
40
+ {@render header()}
41
+ </thead>
42
+ {/if}
43
+
44
+ {#if children}
45
+ <tbody>
46
+ {@render children()}
47
+ </tbody>
48
+ {/if}
49
+
50
+ {#if footer}
51
+ <tfoot>
52
+ {@render footer()}
53
+ </tfoot>
54
+ {/if}
55
+ </table>
56
+ </div>
57
+
58
+ <style>
59
+ @import "../../../../ultra/src/css/parts/components/table.css";
60
+ @reference "../reference.css";
61
+ </style>
@@ -0,0 +1,13 @@
1
+ import type { Snippet } from 'svelte';
2
+ type $$ComponentProps = {
3
+ header?: Snippet;
4
+ children?: Snippet;
5
+ footer?: Snippet;
6
+ caption?: Snippet | string;
7
+ class?: string;
8
+ containerClass?: string;
9
+ [key: string]: any;
10
+ };
11
+ declare const Table: import("svelte").Component<$$ComponentProps, {}, "">;
12
+ type Table = ReturnType<typeof Table>;
13
+ export default Table;
@@ -0,0 +1,97 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ let {
5
+ items = [],
6
+ activeTab = $bindable(''),
7
+ class: className = '',
8
+ contentClass = '',
9
+ ...rest
10
+ }: {
11
+ items: Array<{ id: string; label: string | Snippet; content: string | Snippet }>;
12
+ activeTab?: string;
13
+ class?: string;
14
+ contentClass?: string;
15
+ [key: string]: any;
16
+ } = $props();
17
+
18
+ // Set first item as active when items change and no active tab
19
+ $effect(() => {
20
+ if (!activeTab && items.length > 0) {
21
+ activeTab = items[0].id;
22
+ }
23
+ });
24
+
25
+ function handleKeyDown(event: KeyboardEvent) {
26
+ const currentIndex = items.findIndex(item => item.id === activeTab);
27
+ if (currentIndex === -1) return;
28
+
29
+ let nextIndex: number;
30
+
31
+ switch (event.key) {
32
+ case 'ArrowRight':
33
+ nextIndex = (currentIndex + 1) % items.length;
34
+ break;
35
+ case 'ArrowLeft':
36
+ nextIndex = (currentIndex - 1 + items.length) % items.length;
37
+ break;
38
+ case 'Home':
39
+ nextIndex = 0;
40
+ break;
41
+ case 'End':
42
+ nextIndex = items.length - 1;
43
+ break;
44
+ default:
45
+ return;
46
+ }
47
+
48
+ event.preventDefault();
49
+ activeTab = items[nextIndex].id;
50
+
51
+ const buttons = (event.currentTarget as HTMLElement).querySelectorAll('button');
52
+ (buttons[nextIndex] as HTMLElement).focus();
53
+ }
54
+ </script>
55
+
56
+ <div class={['tabs', className].filter(Boolean).join(' ')} {...rest}>
57
+ <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
58
+ <div role="tablist" onkeydown={handleKeyDown} tabindex="0">
59
+ {#each items as item}
60
+ <button
61
+ role="tab"
62
+ aria-controls={item.id}
63
+ aria-selected={activeTab === item.id}
64
+ tabindex={activeTab === item.id ? 0 : -1}
65
+ onclick={() => activeTab = item.id}
66
+ >
67
+ {#if typeof item.label === 'string'}
68
+ {item.label}
69
+ {:else}
70
+ {@render item.label()}
71
+ {/if}
72
+ </button>
73
+ {/each}
74
+ </div>
75
+
76
+ {#each items as item}
77
+ <section
78
+ id={item.id}
79
+ role="tabpanel"
80
+ hidden={activeTab !== item.id}
81
+ class={['p-4 border rounded-md mt-4', contentClass].filter(Boolean).join(' ')}
82
+ >
83
+ {#if activeTab === item.id}
84
+ {#if typeof item.content === 'string'}
85
+ {item.content}
86
+ {:else}
87
+ {@render item.content()}
88
+ {/if}
89
+ {/if}
90
+ </section>
91
+ {/each}
92
+ </div>
93
+
94
+ <style>
95
+ @import "../../../../ultra/src/css/parts/components/tabs.css";
96
+ @reference "../reference.css";
97
+ </style>
@@ -0,0 +1,15 @@
1
+ import type { Snippet } from 'svelte';
2
+ type $$ComponentProps = {
3
+ items: Array<{
4
+ id: string;
5
+ label: string | Snippet;
6
+ content: string | Snippet;
7
+ }>;
8
+ activeTab?: string;
9
+ class?: string;
10
+ contentClass?: string;
11
+ [key: string]: any;
12
+ };
13
+ declare const Tabs: import("svelte").Component<$$ComponentProps, {}, "activeTab">;
14
+ type Tabs = ReturnType<typeof Tabs>;
15
+ export default Tabs;
@@ -0,0 +1,22 @@
1
+ <script lang="ts">
2
+ let {
3
+ value = $bindable(),
4
+ class: className = '',
5
+ rows = 3,
6
+ ...rest
7
+ }: {
8
+ value?: any;
9
+ class?: string;
10
+ rows?: number;
11
+ [key: string]: any;
12
+ } = $props();
13
+
14
+ const finalClass = $derived(['textarea', className].filter(Boolean).join(' '));
15
+ </script>
16
+
17
+ <textarea class={finalClass} bind:value {rows} {...rest}></textarea>
18
+
19
+ <style>
20
+ @import "../../../../ultra/src/css/parts/components/textarea.css";
21
+ @reference "../reference.css";
22
+ </style>
@@ -0,0 +1,9 @@
1
+ type $$ComponentProps = {
2
+ value?: any;
3
+ class?: string;
4
+ rows?: number;
5
+ [key: string]: any;
6
+ };
7
+ declare const Textarea: import("svelte").Component<$$ComponentProps, {}, "value">;
8
+ type Textarea = ReturnType<typeof Textarea>;
9
+ export default Textarea;
@@ -0,0 +1,73 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import { fade, slide } from 'svelte/transition';
4
+
5
+ interface ToastConfig {
6
+ id: string;
7
+ title: string;
8
+ description?: string;
9
+ category?: 'success' | 'warning' | 'destructive' | 'info';
10
+ duration?: number;
11
+ }
12
+
13
+ let toasts = $state<ToastConfig[]>([]);
14
+
15
+ const addToast = (config: Omit<ToastConfig, 'id'>) => {
16
+ const id = Math.random().toString(36).substring(2, 9);
17
+ const newToast = { ...config, id };
18
+ toasts = [...toasts, newToast];
19
+
20
+ if (config.duration !== 0) {
21
+ setTimeout(() => {
22
+ removeToast(id);
23
+ }, config.duration || 3000);
24
+ }
25
+ };
26
+
27
+ const removeToast = (id: string) => {
28
+ toasts = toasts.filter(t => t.id !== id);
29
+ };
30
+
31
+ onMount(() => {
32
+ const handler = (e: CustomEvent) => {
33
+ if (e.detail && e.detail.config) {
34
+ addToast(e.detail.config);
35
+ }
36
+ };
37
+ document.addEventListener('basecoat:toast', handler as any);
38
+ return () => document.removeEventListener('basecoat:toast', handler as any);
39
+ });
40
+ </script>
41
+
42
+ <section id="toaster" class="toaster fixed top-16 right-0 z-[200] flex max-h-screen w-full flex-col p-4 sm:flex-col md:max-w-[420px]">
43
+ {#each toasts as toast (toast.id)}
44
+ <div
45
+ in:slide={{ axis: 'y', duration: 200 }}
46
+ out:slide={{ axis: 'y', duration: 200 }}
47
+ class={['toast group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all',
48
+ toast.category === 'destructive' ? 'destructive border-destructive bg-destructive text-destructive-foreground' : 'bg-card text-card-foreground border-border'
49
+ ].join(' ')}
50
+ >
51
+ <div class="grid gap-1">
52
+ {#if toast.title}
53
+ <div class="text-sm font-semibold">{toast.title}</div>
54
+ {/if}
55
+ {#if toast.description}
56
+ <div class="text-sm opacity-90">{toast.description}</div>
57
+ {/if}
58
+ </div>
59
+ <button
60
+ class="absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100"
61
+ onclick={() => removeToast(toast.id)}
62
+ aria-label="Close"
63
+ >
64
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
65
+ </button>
66
+ </div>
67
+ {/each}
68
+ </section>
69
+
70
+ <style>
71
+ @import "../../../../ultra/src/css/parts/components/toast.css";
72
+ @reference "../reference.css";
73
+ </style>
@@ -0,0 +1,3 @@
1
+ declare const Toast: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type Toast = ReturnType<typeof Toast>;
3
+ export default Toast;