uisv 0.0.13 → 0.0.15

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 (58) hide show
  1. package/dist/components/alert.svelte +8 -2
  2. package/dist/components/alert.svelte.d.ts +2 -2
  3. package/dist/components/badge.svelte +18 -18
  4. package/dist/components/badge.svelte.d.ts +2 -2
  5. package/dist/components/banner.svelte +8 -2
  6. package/dist/components/banner.svelte.d.ts +2 -2
  7. package/dist/components/breadcrumb.svelte +75 -0
  8. package/dist/components/breadcrumb.svelte.d.ts +38 -0
  9. package/dist/components/button.svelte +415 -0
  10. package/dist/components/{button/index.d.ts → button.svelte.d.ts} +9 -4
  11. package/dist/components/calendar.svelte +99 -0
  12. package/dist/components/calendar.svelte.d.ts +16 -0
  13. package/dist/components/card.svelte +11 -10
  14. package/dist/components/card.svelte.d.ts +2 -1
  15. package/dist/components/collapsible.svelte +76 -0
  16. package/dist/components/collapsible.svelte.d.ts +15 -0
  17. package/dist/components/icon.svelte +58 -0
  18. package/dist/components/icon.svelte.d.ts +8 -0
  19. package/dist/components/index.d.ts +18 -3
  20. package/dist/components/index.js +18 -3
  21. package/dist/components/input-number.svelte +175 -0
  22. package/dist/components/input-number.svelte.d.ts +38 -0
  23. package/dist/components/input-time.svelte +233 -0
  24. package/dist/components/input-time.svelte.d.ts +53 -0
  25. package/dist/components/input.svelte +285 -0
  26. package/dist/components/{input/index.d.ts → input.svelte.d.ts} +6 -5
  27. package/dist/components/kbd.svelte +35 -35
  28. package/dist/components/kbd.svelte.d.ts +2 -2
  29. package/dist/components/pin-input.svelte +20 -20
  30. package/dist/components/pin-input.svelte.d.ts +2 -2
  31. package/dist/components/placeholder.svelte +1 -1
  32. package/dist/components/select.svelte +2 -2
  33. package/dist/components/select.svelte.d.ts +2 -2
  34. package/dist/components/seperator.svelte +212 -0
  35. package/dist/components/seperator.svelte.d.ts +22 -0
  36. package/dist/components/tabs.svelte +1 -2
  37. package/dist/date.d.ts +1 -0
  38. package/dist/date.js +1 -0
  39. package/dist/index.d.ts +2 -0
  40. package/dist/utilities.svelte.d.ts +7 -0
  41. package/dist/utilities.svelte.js +20 -0
  42. package/dist/vite.d.ts +1 -1
  43. package/dist/vite.js +24 -39
  44. package/package.json +41 -49
  45. package/dist/components/button/button.svelte +0 -105
  46. package/dist/components/button/button.svelte.d.ts +0 -4
  47. package/dist/components/button/index.js +0 -4
  48. package/dist/components/button/style.d.ts +0 -148
  49. package/dist/components/button/style.js +0 -248
  50. package/dist/components/input/index.js +0 -2
  51. package/dist/components/input/input.svelte +0 -103
  52. package/dist/components/input/input.svelte.d.ts +0 -4
  53. package/dist/components/input/style.d.ts +0 -316
  54. package/dist/components/input/style.js +0 -128
  55. package/dist/components/input-time/index.d.ts +0 -375
  56. package/dist/components/input-time/index.js +0 -144
  57. package/dist/components/input-time/input-time.svelte +0 -39
  58. package/dist/components/input-time/input-time.svelte.d.ts +0 -4
@@ -0,0 +1,415 @@
1
+ <script module lang="ts">
2
+ import { type Component, type Snippet } from 'svelte';
3
+ import { isComponent, type PropColor, type PropVariant } from '../index.js';
4
+ import type { ClassNameValue } from 'tailwind-merge';
5
+ // import { FORM_LOADING_CONTEXT_KEY } from '../utils/keys.js';
6
+ import { isSnippet } from '../index.js';
7
+ import { tv } from 'tailwind-variants';
8
+
9
+ export type ButtonProps = {
10
+ /** The underlying DOM element being rendered. You can bind to this to get a reference to the element. */
11
+ ref?: HTMLButtonElement | HTMLAnchorElement;
12
+ /** Where to display the linked URL, as the name for a browsing context. */
13
+ target?: null | '_blank' | '_parent' | '_self' | '_top' | (string & {});
14
+ /** Force the link to be active independent of the current route. */
15
+ // active?: boolean;
16
+ disabled?: boolean;
17
+ /** The type of the button when not a link. */
18
+ type?: 'submit' | 'reset' | 'button' | null | undefined;
19
+ /** When true, the icon will be displayed on the right side. */
20
+ loadingicon?: string | Snippet | Component;
21
+ /** When true, the loading icon will be displayed. */
22
+ loading?: boolean;
23
+ /** The position of the icon, including the loading icon */
24
+ iconposition?: 'left' | 'right';
25
+ /** Icon when `loading` is `false` */
26
+ icon?: string | Snippet | Component;
27
+ leadingicon?: string | Snippet | Component;
28
+ trailingicon?: string | Snippet | Component;
29
+ /** Route Location the link should navigate to when clicked on. */
30
+ href?: string;
31
+ label?: string;
32
+ /**
33
+ * @defaultValue 'primary'
34
+ */
35
+ color?: PropColor;
36
+ // activecolor?: PropColor;
37
+ /**
38
+ * @defaultValue 'solid'
39
+ */
40
+ variant?: Exclude<PropVariant, 'none'> | 'link';
41
+ // activevariant?: ButtonVariant;
42
+ /**
43
+ * @defaultValue 'md'
44
+ */
45
+ size?: 'md' | 'xs' | 'sm' | 'lg' | 'xl';
46
+ /** Render the button full width. */
47
+ block?: boolean;
48
+ /** Set loading state automatically based on the `@click` promise state */
49
+ loadingauto?: boolean;
50
+ onclick?: (event: MouseEvent) => void | Promise<void>;
51
+ ui?: {
52
+ base?: ClassNameValue;
53
+ icon?: ClassNameValue;
54
+ leadingicon?: ClassNameValue;
55
+ trailingicon?: ClassNameValue;
56
+ };
57
+ children?: Snippet;
58
+ };
59
+ </script>
60
+
61
+ <script lang="ts">
62
+ // let form_loading = getContext<{ value: boolean } | undefined>(FORM_LOADING_CONTEXT_KEY);
63
+ let {
64
+ ref = $bindable(),
65
+ size = 'md',
66
+ variant = 'solid',
67
+ color = 'primary',
68
+ iconposition = 'left',
69
+ children,
70
+ // active,
71
+ // activecolor,
72
+ // activevariant,
73
+ block,
74
+ label,
75
+ loadingauto,
76
+ onclick,
77
+ ui = {},
78
+ disabled,
79
+ href,
80
+ icon,
81
+ loading,
82
+ loadingicon = 'i-lucide-loader-circle',
83
+ target,
84
+ type,
85
+ trailingicon,
86
+ leadingicon,
87
+ }: ButtonProps = $props();
88
+
89
+ let internal_loading = $state(false);
90
+ const is_loading = $derived.by(() => {
91
+ if (loading) return true;
92
+ if (loadingauto) return internal_loading;
93
+ return false;
94
+ });
95
+
96
+ const variants = $derived(
97
+ tv({
98
+ slots: {
99
+ icon: '',
100
+ base: 'transition flex-inline items-center font-sans',
101
+ },
102
+ variants: {
103
+ color: {
104
+ primary: '',
105
+ surface: '',
106
+ error: '',
107
+ success: '',
108
+ info: '',
109
+ warning: '',
110
+ },
111
+ variant: {
112
+ link: '',
113
+ solid: 'text-inverted',
114
+ outline: 'border',
115
+ soft: '',
116
+ subtle: 'border',
117
+ ghost: '',
118
+ },
119
+ size: {
120
+ xs: {
121
+ base: 'font-medium text-xs px-2 h-6 rounded gap-1',
122
+ icon: 'size-4',
123
+ },
124
+ sm: { base: 'font-medium text-xs px-2 h-7 rounded gap-1', icon: 'size-4' },
125
+ md: { base: 'font-medium text-sm rounded-md px-2 h-8 gap-2', icon: 'size-5' },
126
+ lg: { base: 'font-medium text-sm px-3 h-9 rounded-md gap-2', icon: 'size-6' },
127
+ xl: { base: 'font-medium px-3 h-10 rounded-md gap-2', icon: 'size-6' },
128
+ },
129
+ block: {
130
+ true: 'w-full',
131
+ },
132
+ disabled: {
133
+ true: 'cursor-not-allowed',
134
+ false: 'cursor-default',
135
+ },
136
+ },
137
+ compoundVariants: [
138
+ {
139
+ color: 'primary',
140
+ variant: 'solid',
141
+ class: 'bg-primary-500 hover:bg-primary-400',
142
+ },
143
+ {
144
+ color: 'surface',
145
+ variant: 'solid',
146
+ class: 'bg-surface-inverted text-inverted hover:bg-toned',
147
+ },
148
+ {
149
+ color: 'info',
150
+ variant: 'solid',
151
+ class: 'bg-info-500 hover:bg-info-400',
152
+ },
153
+ {
154
+ color: 'success',
155
+ variant: 'solid',
156
+ class: 'bg-success-500 hover:bg-success-400',
157
+ },
158
+ {
159
+ color: 'error',
160
+ variant: 'solid',
161
+ class: 'bg-error-500 hover:bg-error-400',
162
+ },
163
+ {
164
+ color: 'warning',
165
+ variant: 'solid',
166
+ class: 'bg-warning-500 hover:bg-warning-400',
167
+ },
168
+
169
+ {
170
+ color: 'primary',
171
+ variant: 'outline',
172
+ class: {
173
+ base: [
174
+ 'border-primary/50 text-primary-500 hover:bg-primary-50',
175
+ 'dark:hover:bg-primary-950',
176
+ ],
177
+ },
178
+ },
179
+ {
180
+ color: 'surface',
181
+ variant: 'outline',
182
+ class: {
183
+ base: [
184
+ 'border-surface-accented text-surface-inverted hover:bg-surface/10',
185
+ 'dark:hover:bg-surface-800',
186
+ ],
187
+ },
188
+ },
189
+ {
190
+ color: 'info',
191
+ variant: 'outline',
192
+ class: {
193
+ base: ['border-info/50 text-info-500 hover:bg-info/10', 'dark:hover:bg-info-950'],
194
+ },
195
+ },
196
+ {
197
+ color: 'success',
198
+ variant: 'outline',
199
+ class: {
200
+ base: [
201
+ 'border-success/50 text-success-500 hover:bg-success/10',
202
+ 'dark:hover:bg-success-950',
203
+ ],
204
+ },
205
+ },
206
+ {
207
+ color: 'error',
208
+ variant: 'outline',
209
+ class: {
210
+ base: ['border-error/50 text-error-500 hover:bg-error/10', 'dark:hover:bg-error-950'],
211
+ },
212
+ },
213
+ {
214
+ color: 'warning',
215
+ variant: 'outline',
216
+ class: {
217
+ base: [
218
+ 'border-warning/50 text-warning-500 hover:bg-warning/10',
219
+ 'dark:hover:bg-warning-950',
220
+ ],
221
+ },
222
+ },
223
+
224
+ {
225
+ color: 'primary',
226
+ variant: 'soft',
227
+ class: 'bg-primary-50 text-primary-500 hover:bg-primary-100',
228
+ },
229
+ {
230
+ color: 'surface',
231
+ variant: 'soft',
232
+ class: 'bg-surface-100 text-surface-800 hover:bg-surface-200',
233
+ },
234
+ {
235
+ color: 'info',
236
+ variant: 'soft',
237
+ class: 'bg-info-100 text-info-500 hover:bg-info-50',
238
+ },
239
+ {
240
+ color: 'success',
241
+ variant: 'soft',
242
+ class: 'bg-success-100 text-success-500 hover:bg-success-50',
243
+ },
244
+ {
245
+ color: 'error',
246
+ variant: 'soft',
247
+ class: 'bg-error-100 text-error-500 hover:bg-error-50',
248
+ },
249
+ {
250
+ color: 'warning',
251
+ variant: 'soft',
252
+ class: 'bg-warning-100 text-warning-500 hover:bg-warning-50',
253
+ },
254
+
255
+ {
256
+ color: 'primary',
257
+ variant: 'subtle',
258
+ class: 'bg-primary-50 text-primary-500 border-primary-200 hover:bg-primary-100',
259
+ },
260
+ {
261
+ color: 'surface',
262
+ variant: 'subtle',
263
+ class: 'bg-surface-50 text-surface-800 border-surface-300 hover:bg-surface-100',
264
+ },
265
+ {
266
+ color: 'info',
267
+ variant: 'subtle',
268
+ class: 'bg-info-50 text-info-600 border-info-200 hover:bg-info-100',
269
+ },
270
+ {
271
+ color: 'success',
272
+ variant: 'subtle',
273
+ class: 'bg-success-100 text-success-600 border-success-300 hover:bg-success-100',
274
+ },
275
+ {
276
+ color: 'error',
277
+ variant: 'subtle',
278
+ class: 'bg-error-50 text-error-600 border-error-200 hover:bg-error-100',
279
+ },
280
+ {
281
+ color: 'warning',
282
+ variant: 'subtle',
283
+ class: 'bg-warning-50 text-warning-600 border-warning-300 hover:bg-warning-100',
284
+ },
285
+
286
+ {
287
+ color: 'primary',
288
+ variant: 'ghost',
289
+ class: 'text-primary-500 hover:bg-primary-100',
290
+ },
291
+ {
292
+ color: 'surface',
293
+ variant: 'ghost',
294
+ class: 'text-surface-inverted hover-surface-elevated text-surface-inverted)',
295
+ },
296
+ {
297
+ color: 'info',
298
+ variant: 'ghost',
299
+ class: 'text-info-600 hover:bg-info-100',
300
+ },
301
+ {
302
+ color: 'success',
303
+ variant: 'ghost',
304
+ class: 'text-success-600 hover:bg-success-100',
305
+ },
306
+ {
307
+ color: 'error',
308
+ variant: 'ghost',
309
+ class: 'text-error-600 hover:bg-error-100',
310
+ },
311
+ {
312
+ color: 'warning',
313
+ variant: 'ghost',
314
+ class: 'text-warning-600 hover:bg-warning-100',
315
+ },
316
+
317
+ {
318
+ color: 'primary',
319
+ variant: 'link',
320
+ class: 'text-primary-500 hover:text-primary-400',
321
+ },
322
+ {
323
+ color: 'surface',
324
+ variant: 'link',
325
+ class: 'text-muted hover:text-surface-inverted',
326
+ },
327
+ {
328
+ color: 'info',
329
+ variant: 'link',
330
+ class: 'text-info-500 hover:text-info-400',
331
+ },
332
+ {
333
+ color: 'success',
334
+ variant: 'link',
335
+ class: 'text-success-500 hover:text-success-400',
336
+ },
337
+ {
338
+ color: 'error',
339
+ variant: 'link',
340
+ class: 'text-error-500 hover:text-error-400',
341
+ },
342
+ {
343
+ color: 'warning',
344
+ variant: 'link',
345
+ class: 'text-warning-500 hover:text-warning-400',
346
+ },
347
+ ],
348
+ })({ variant, color, size, block, disabled: disabled || is_loading }),
349
+ );
350
+
351
+ const only_icon = $derived(!(children || label) && !!icon);
352
+
353
+ async function onClickWrapper(event: MouseEvent) {
354
+ if (!onclick) return;
355
+ internal_loading = true;
356
+
357
+ await onclick(event);
358
+
359
+ internal_loading = false;
360
+ }
361
+ </script>
362
+
363
+ {#if href}
364
+ <a
365
+ {href}
366
+ {target}
367
+ class={variants.base({
368
+ class: [only_icon ? 'px-0 aspect-square justify-center' : '', 'cursor-pointer', ui.base],
369
+ })}
370
+ onclick={onClickWrapper}
371
+ >
372
+ {@render Content()}
373
+ </a>
374
+ {:else}
375
+ <button
376
+ {type}
377
+ disabled={disabled || is_loading}
378
+ class={variants.base({
379
+ class: [only_icon ? 'px-0 aspect-square justify-center' : '', ui.base],
380
+ })}
381
+ onclick={onClickWrapper}
382
+ >
383
+ {@render Content()}
384
+ </button>
385
+ {/if}
386
+
387
+ {#snippet Content()}
388
+ {#if iconposition === 'left' || leadingicon}
389
+ {@render Icon(is_loading ? loadingicon : leadingicon || icon, ui.leadingicon)}
390
+ {/if}
391
+
392
+ {#if label}
393
+ {label}
394
+ {:else}
395
+ {@render children?.()}
396
+ {/if}
397
+
398
+ {#if iconposition !== 'left' || trailingicon}
399
+ {@render Icon(trailingicon || icon, ui.trailingicon)}
400
+ {/if}
401
+ {/snippet}
402
+
403
+ {#snippet Icon(IconProp?: string | Snippet | Component, classvalue?: ClassNameValue)}
404
+ {#if typeof IconProp === 'string'}
405
+ <div
406
+ class={variants.icon({
407
+ class: [is_loading && 'animate-spin', IconProp, ui.icon, classvalue],
408
+ })}
409
+ ></div>
410
+ {:else if isSnippet(IconProp)}
411
+ {@render IconProp()}
412
+ {:else if isComponent(IconProp)}
413
+ <IconProp />
414
+ {/if}
415
+ {/snippet}
@@ -1,8 +1,6 @@
1
1
  import { type Component, type Snippet } from 'svelte';
2
- import { type PropColor } from '../../index.js';
2
+ import { type PropColor, type PropVariant } from '../index.js';
3
3
  import type { ClassNameValue } from 'tailwind-merge';
4
- export * from './style.js';
5
- export { default as Button } from './button.svelte';
6
4
  export type ButtonProps = {
7
5
  /** The underlying DOM element being rendered. You can bind to this to get a reference to the element. */
8
6
  ref?: HTMLButtonElement | HTMLAnchorElement;
@@ -20,6 +18,8 @@ export type ButtonProps = {
20
18
  iconposition?: 'left' | 'right';
21
19
  /** Icon when `loading` is `false` */
22
20
  icon?: string | Snippet | Component;
21
+ leadingicon?: string | Snippet | Component;
22
+ trailingicon?: string | Snippet | Component;
23
23
  /** Route Location the link should navigate to when clicked on. */
24
24
  href?: string;
25
25
  label?: string;
@@ -30,7 +30,7 @@ export type ButtonProps = {
30
30
  /**
31
31
  * @defaultValue 'solid'
32
32
  */
33
- variant?: 'link' | 'solid' | 'outline' | 'soft' | 'subtle' | 'ghost';
33
+ variant?: Exclude<PropVariant, 'none'> | 'link';
34
34
  /**
35
35
  * @defaultValue 'md'
36
36
  */
@@ -43,6 +43,11 @@ export type ButtonProps = {
43
43
  ui?: {
44
44
  base?: ClassNameValue;
45
45
  icon?: ClassNameValue;
46
+ leadingicon?: ClassNameValue;
47
+ trailingicon?: ClassNameValue;
46
48
  };
47
49
  children?: Snippet;
48
50
  };
51
+ declare const Button: Component<ButtonProps, {}, "ref">;
52
+ type Button = ReturnType<typeof Button>;
53
+ export default Button;
@@ -0,0 +1,99 @@
1
+ <script lang="ts" module>
2
+ import type { Component, Snippet } from 'svelte';
3
+ import { tv } from 'tailwind-variants';
4
+ import { type PropColor, type PropVariant, isSnippet } from '../index.js';
5
+ import type { ClassNameValue } from 'tailwind-merge';
6
+ import { type DateValue, today } from '../date.js';
7
+ import { Calendar, type CalendarRootProps } from 'bits-ui';
8
+
9
+ export type CalendarProps = CalendarRootProps & {
10
+ color?: PropColor;
11
+ variant?: Exclude<PropVariant, 'none' | 'ghost'>;
12
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
13
+ ui?: {
14
+ base?: ClassNameValue;
15
+ icon?: ClassNameValue;
16
+ };
17
+ };
18
+ </script>
19
+
20
+ <script lang="ts">
21
+ let {
22
+ type,
23
+ value = $bindable(),
24
+ label,
25
+ trailingicon,
26
+ color = 'primary',
27
+ size = 'md',
28
+ variant = 'solid',
29
+ ui = {},
30
+ children,
31
+ }: CalendarProps = $props();
32
+
33
+ const classes = $derived.by(() => {
34
+ return tv({
35
+ slots: { icon: '', base: '' },
36
+ variants: {
37
+ color: {
38
+ primary: '',
39
+ surface: '',
40
+ error: '',
41
+ success: '',
42
+ info: '',
43
+ warning: '',
44
+ },
45
+ variant: {
46
+ link: '',
47
+ solid: '',
48
+ outline: '',
49
+ soft: '',
50
+ subtle: '',
51
+ ghost: '',
52
+ },
53
+ size: {
54
+ xs: {},
55
+ sm: {},
56
+ md: {},
57
+ lg: {},
58
+ xl: {},
59
+ },
60
+ },
61
+ compoundVariants: [],
62
+ })({ variant, size, color });
63
+ });
64
+ </script>
65
+
66
+ <Calendar.Root type={type as typeof type} bind:value>
67
+ {#snippet children({ months, weekdays })}
68
+ <Calendar.Header>
69
+ <Calendar.PrevButton />
70
+ <Calendar.Heading />
71
+ <Calendar.NextButton />
72
+ </Calendar.Header>
73
+
74
+ {#each months as month}
75
+ <Calendar.Grid>
76
+ <Calendar.GridHead>
77
+ <Calendar.GridRow>
78
+ {#each weekdays as day, idx (idx)}
79
+ <Calendar.HeadCell>
80
+ {day}
81
+ </Calendar.HeadCell>
82
+ {/each}
83
+ </Calendar.GridRow>
84
+ </Calendar.GridHead>
85
+ <Calendar.GridBody>
86
+ {#each month.weeks as weekDates, wdidx (wdidx)}
87
+ <Calendar.GridRow>
88
+ {#each weekDates as date, didx (didx)}
89
+ <Calendar.Cell {date} month={month.value}>
90
+ <Calendar.Day />
91
+ </Calendar.Cell>
92
+ {/each}
93
+ </Calendar.GridRow>
94
+ {/each}
95
+ </Calendar.GridBody>
96
+ </Calendar.Grid>
97
+ {/each}
98
+ {/snippet}
99
+ </Calendar.Root>
@@ -0,0 +1,16 @@
1
+ import type { Component } from 'svelte';
2
+ import { type PropColor, type PropVariant } from '../index.js';
3
+ import type { ClassNameValue } from 'tailwind-merge';
4
+ import { Calendar, type CalendarRootProps } from 'bits-ui';
5
+ export type CalendarProps = CalendarRootProps & {
6
+ color?: PropColor;
7
+ variant?: Exclude<PropVariant, 'none' | 'ghost'>;
8
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
9
+ ui?: {
10
+ base?: ClassNameValue;
11
+ icon?: ClassNameValue;
12
+ };
13
+ };
14
+ declare const Calendar: Component<CalendarProps, {}, "value">;
15
+ type Calendar = ReturnType<typeof Calendar>;
16
+ export default Calendar;
@@ -1,4 +1,5 @@
1
1
  <script module lang="ts">
2
+ import type { PropVariant } from '../index.js';
2
3
  import type { Snippet } from 'svelte';
3
4
  import type { ClassNameValue } from 'tailwind-merge';
4
5
  import { tv } from 'tailwind-variants';
@@ -7,7 +8,7 @@
7
8
  children: Snippet;
8
9
  header?: Snippet;
9
10
  footer?: Snippet;
10
- variant?: 'solid' | 'outline' | 'soft' | 'subtle';
11
+ variant?: Exclude<PropVariant, 'none' | 'ghost'>;
11
12
  ui?: {
12
13
  base?: ClassNameValue;
13
14
  header?: ClassNameValue;
@@ -26,28 +27,28 @@
26
27
  base: 'rounded overflow-hidden',
27
28
  header: 'p-4 sm:px-6',
28
29
  content: 'p-4 sm:p-6',
29
- footer: 'p-4 sm:px-6'
30
+ footer: 'p-4 sm:px-6',
30
31
  },
31
32
  variants: {
32
33
  variant: {
33
34
  solid: {
34
35
  base: 'bg-surface-900 text-surface-50',
35
36
  header: 'border-transparent',
36
- footer: 'border-transparent'
37
+ footer: 'border-transparent',
37
38
  },
38
39
  outline: {
39
- base: 'border border-surface-300 divide-y divide-surface-300'
40
+ base: 'border border-surface-300 divide-y divide-surface-300',
40
41
  },
41
42
  soft: {
42
- base: 'bg-surface-50 divide-y divide-surface-300'
43
+ base: 'bg-surface-50 divide-y divide-surface-300',
43
44
  },
44
45
  subtle: {
45
- base: 'bg-surface-50 border-surface-300 border divide-y divide-surface-300'
46
- }
47
- }
46
+ base: 'bg-surface-50 border-surface-300 border divide-y divide-surface-300',
47
+ },
48
+ },
48
49
  },
49
- compoundVariants: []
50
- })({ variant })
50
+ compoundVariants: [],
51
+ })({ variant }),
51
52
  );
52
53
  </script>
53
54
 
@@ -1,10 +1,11 @@
1
+ import type { PropVariant } from '../index.js';
1
2
  import type { Snippet } from 'svelte';
2
3
  import type { ClassNameValue } from 'tailwind-merge';
3
4
  export type CardProps = {
4
5
  children: Snippet;
5
6
  header?: Snippet;
6
7
  footer?: Snippet;
7
- variant?: 'solid' | 'outline' | 'soft' | 'subtle';
8
+ variant?: Exclude<PropVariant, 'none' | 'ghost'>;
8
9
  ui?: {
9
10
  base?: ClassNameValue;
10
11
  header?: ClassNameValue;
@@ -0,0 +1,76 @@
1
+ <script module lang="ts">
2
+ import { type ButtonProps, Button } from '../index.js';
3
+ import { Collapsible } from 'bits-ui';
4
+ import { defu } from 'defu';
5
+ import type { ClassNameValue } from 'tailwind-merge';
6
+ import { tv } from 'tailwind-variants';
7
+
8
+ export type CollapsibleProps = ButtonProps & {
9
+ open?: boolean;
10
+ disabled?: boolean;
11
+ class?: ClassNameValue;
12
+ ui?: {
13
+ root?: ClassNameValue;
14
+ content?: ClassNameValue;
15
+ };
16
+ };
17
+ </script>
18
+
19
+ <script lang="ts">
20
+ let {
21
+ open = $bindable(false),
22
+ children,
23
+ ui = {},
24
+ class: root_class,
25
+ ...rest
26
+ }: CollapsibleProps = $props();
27
+
28
+ const variants = $derived(
29
+ tv({
30
+ slots: {
31
+ root: 'flex flex-col gap-2',
32
+ content:
33
+ 'data-[state=open]:animate-[collapsible-down_200ms_ease-out] data-[state=closed]:animate-[collapsible-up_200ms_ease-out] space-y-2 overflow-hidden font-mono text-[15px] tracking-[0.01em] transition-all',
34
+ },
35
+ })(),
36
+ );
37
+ </script>
38
+
39
+ <Collapsible.Root bind:open class={variants.root({ class: [root_class, ui.root] })}>
40
+ <Collapsible.Trigger>
41
+ {#snippet child({ props })}
42
+ <Button
43
+ {...props}
44
+ trailingicon="i-lucide-chevron-down"
45
+ {...rest}
46
+ block
47
+ ui={defu(ui, { trailingicon: 'ms-auto' })}
48
+ />
49
+ {/snippet}
50
+ </Collapsible.Trigger>
51
+ <Collapsible.Content class={variants.content({ class: ui.content })}>
52
+ {@render children?.()}
53
+ </Collapsible.Content>
54
+ </Collapsible.Root>
55
+
56
+ <style>
57
+ :global {
58
+ @keyframes collapsible-down {
59
+ from {
60
+ height: 0;
61
+ }
62
+ to {
63
+ height: var(--bits-collapsible-content-height);
64
+ }
65
+ }
66
+
67
+ @keyframes collapsible-up {
68
+ from {
69
+ height: var(--bits-collapsible-content-height);
70
+ }
71
+ to {
72
+ height: 0;
73
+ }
74
+ }
75
+ }
76
+ </style>