compote-ui 0.3.0 → 0.5.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 (166) hide show
  1. package/dist/components/button/button.svelte +16 -0
  2. package/dist/components/button/{Button.svelte.d.ts → button.svelte.d.ts} +3 -2
  3. package/dist/components/button/button.variants.d.ts +46 -0
  4. package/dist/components/button/button.variants.js +20 -0
  5. package/dist/components/carousel/carousel.svelte +120 -0
  6. package/dist/components/carousel/carousel.svelte.d.ts +19 -0
  7. package/dist/components/checkbox/{Checkbox-group.svelte → checkbox-group.svelte} +1 -1
  8. package/dist/components/checkbox/{Checkbox.svelte → checkbox.svelte} +6 -2
  9. package/dist/components/combobox/{Combobox.svelte → combobox.svelte} +21 -24
  10. package/dist/components/combobox/types.d.ts +1 -1
  11. package/dist/components/dialog/alert-dialog.svelte +73 -0
  12. package/dist/components/dialog/alert-dialog.svelte.d.ts +13 -0
  13. package/dist/components/dialog/dialog.svelte +68 -0
  14. package/dist/components/dialog/dialog.svelte.d.ts +14 -0
  15. package/dist/components/field/field-error-text.svelte +11 -0
  16. package/dist/components/field/field-error-text.svelte.d.ts +4 -0
  17. package/dist/components/field/field-helper-text.svelte +11 -0
  18. package/dist/components/field/field-helper-text.svelte.d.ts +4 -0
  19. package/dist/components/field/field-input.svelte +38 -0
  20. package/dist/components/field/field-input.svelte.d.ts +4 -0
  21. package/dist/components/field/field-label.svelte +18 -0
  22. package/dist/components/field/field-label.svelte.d.ts +4 -0
  23. package/dist/components/field/field-textarea.svelte +16 -0
  24. package/dist/components/field/field-textarea.svelte.d.ts +4 -0
  25. package/dist/components/field/field.svelte +11 -0
  26. package/dist/components/field/field.svelte.d.ts +5 -0
  27. package/dist/components/field/index.d.ts +7 -0
  28. package/dist/components/field/index.js +6 -0
  29. package/dist/components/field/types.d.ts +22 -0
  30. package/dist/components/field/types.js +1 -0
  31. package/dist/components/file-upload/basic-document.svelte +89 -0
  32. package/dist/components/file-upload/basic-document.svelte.d.ts +4 -0
  33. package/dist/components/file-upload/basic.svelte +50 -0
  34. package/dist/components/file-upload/basic.svelte.d.ts +18 -0
  35. package/dist/components/file-upload/dropzone.svelte +26 -0
  36. package/dist/components/file-upload/dropzone.svelte.d.ts +4 -0
  37. package/dist/components/file-upload/files-list.svelte +97 -0
  38. package/dist/components/file-upload/files-list.svelte.d.ts +18 -0
  39. package/dist/components/file-upload/icons.d.ts +3 -0
  40. package/dist/components/file-upload/icons.js +39 -0
  41. package/dist/components/file-upload/types.d.ts +6 -0
  42. package/dist/components/file-upload/types.js +1 -0
  43. package/dist/components/file-upload/utils.d.ts +13 -0
  44. package/dist/components/file-upload/utils.js +18 -0
  45. package/dist/components/image-cropper/image-cropper.svelte +109 -0
  46. package/dist/components/image-cropper/image-cropper.svelte.d.ts +5 -0
  47. package/dist/components/image-cropper/types.d.ts +16 -0
  48. package/dist/components/image-cropper/types.js +1 -0
  49. package/dist/components/listbox/listbox.svelte +116 -0
  50. package/dist/components/listbox/listbox.svelte.d.ts +27 -0
  51. package/dist/components/listbox/types.d.ts +16 -0
  52. package/dist/components/listbox/types.js +1 -0
  53. package/dist/components/menu/index.d.ts +14 -0
  54. package/dist/components/menu/index.js +14 -0
  55. package/dist/components/menu/menu-checkbox-item.svelte +31 -0
  56. package/dist/components/menu/menu-checkbox-item.svelte.d.ts +12 -0
  57. package/dist/components/menu/menu-content.svelte +23 -0
  58. package/dist/components/menu/menu-content.svelte.d.ts +8 -0
  59. package/dist/components/menu/menu-context-trigger.svelte +20 -0
  60. package/dist/components/menu/menu-context-trigger.svelte.d.ts +8 -0
  61. package/dist/components/menu/menu-indicator.svelte +19 -0
  62. package/dist/components/menu/menu-indicator.svelte.d.ts +9 -0
  63. package/dist/components/menu/menu-item-group-label.svelte +17 -0
  64. package/dist/components/menu/menu-item-group-label.svelte.d.ts +9 -0
  65. package/dist/components/menu/menu-item-group.svelte +14 -0
  66. package/dist/components/menu/menu-item-group.svelte.d.ts +9 -0
  67. package/dist/components/menu/menu-item-indicator.svelte +14 -0
  68. package/dist/components/menu/menu-item-indicator.svelte.d.ts +9 -0
  69. package/dist/components/menu/menu-item.svelte +20 -0
  70. package/dist/components/menu/menu-item.svelte.d.ts +9 -0
  71. package/dist/components/menu/menu-radio-item-group.svelte +14 -0
  72. package/dist/components/menu/menu-radio-item-group.svelte.d.ts +9 -0
  73. package/dist/components/menu/menu-radio-item.svelte +28 -0
  74. package/dist/components/menu/menu-radio-item.svelte.d.ts +10 -0
  75. package/dist/components/menu/menu-separator.svelte +11 -0
  76. package/dist/components/menu/menu-separator.svelte.d.ts +7 -0
  77. package/dist/components/menu/menu-trigger-item.svelte +20 -0
  78. package/dist/components/menu/menu-trigger-item.svelte.d.ts +9 -0
  79. package/dist/components/menu/menu-trigger.svelte +19 -0
  80. package/dist/components/menu/menu-trigger.svelte.d.ts +12 -0
  81. package/dist/components/menu/menu.svelte +12 -0
  82. package/dist/components/menu/menu.svelte.d.ts +4 -0
  83. package/dist/components/number-input/number-input.svelte +67 -0
  84. package/dist/components/number-input/number-input.svelte.d.ts +5 -0
  85. package/dist/components/number-input/types.d.ts +7 -0
  86. package/dist/components/number-input/types.js +1 -0
  87. package/dist/components/select/select.svelte +93 -0
  88. package/dist/components/select/select.svelte.d.ts +26 -0
  89. package/dist/components/select/types.d.ts +13 -0
  90. package/dist/components/select/types.js +1 -0
  91. package/dist/components/splitter/splitter.svelte +60 -0
  92. package/dist/components/splitter/splitter.svelte.d.ts +5 -0
  93. package/dist/components/splitter/types.d.ts +9 -0
  94. package/dist/components/splitter/types.js +1 -0
  95. package/dist/components/switch/index.d.ts +2 -0
  96. package/dist/components/switch/index.js +1 -0
  97. package/dist/components/switch/switch.svelte +40 -0
  98. package/dist/components/switch/switch.svelte.d.ts +8 -0
  99. package/dist/components/switch/types.d.ts +5 -0
  100. package/dist/components/switch/types.js +1 -0
  101. package/dist/components/tabs/index.d.ts +4 -0
  102. package/dist/components/tabs/index.js +3 -0
  103. package/dist/components/tabs/tab-content.svelte +18 -0
  104. package/dist/components/tabs/tab-content.svelte.d.ts +7 -0
  105. package/dist/components/tabs/tab-trigger.svelte +18 -0
  106. package/dist/components/tabs/tab-trigger.svelte.d.ts +7 -0
  107. package/dist/components/tabs/tabs.svelte +39 -0
  108. package/dist/components/tabs/tabs.svelte.d.ts +5 -0
  109. package/dist/components/tabs/types.d.ts +8 -0
  110. package/dist/components/tabs/types.js +1 -0
  111. package/dist/components/tree-view/tree-view.svelte +210 -0
  112. package/dist/components/tree-view/tree-view.svelte.d.ts +26 -0
  113. package/dist/components/tree-view/types.d.ts +12 -0
  114. package/dist/components/tree-view/types.js +1 -0
  115. package/dist/icons/PhArrowLeft.svelte +18 -0
  116. package/dist/icons/PhArrowLeft.svelte.d.ts +5 -0
  117. package/dist/icons/PhArrowRight.svelte +18 -0
  118. package/dist/icons/PhArrowRight.svelte.d.ts +5 -0
  119. package/dist/icons/PhArrowsInSimple.svelte +17 -0
  120. package/dist/icons/PhArrowsInSimple.svelte.d.ts +5 -0
  121. package/dist/icons/PhCaretDown.svelte +2 -1
  122. package/dist/icons/PhCaretRight.svelte +17 -0
  123. package/dist/icons/PhCaretRight.svelte.d.ts +5 -0
  124. package/dist/icons/PhCaretUp.svelte +18 -0
  125. package/dist/icons/PhCaretUp.svelte.d.ts +5 -0
  126. package/dist/icons/PhCheck.svelte +2 -1
  127. package/dist/icons/PhFile.svelte +19 -0
  128. package/dist/icons/PhFile.svelte.d.ts +5 -0
  129. package/dist/icons/PhFileArchive.svelte +18 -0
  130. package/dist/icons/PhFileArchive.svelte.d.ts +5 -0
  131. package/dist/icons/PhFileText.svelte +18 -0
  132. package/dist/icons/PhFileText.svelte.d.ts +5 -0
  133. package/dist/icons/PhHeadphones.svelte +17 -0
  134. package/dist/icons/PhHeadphones.svelte.d.ts +5 -0
  135. package/dist/icons/PhImage.svelte +18 -0
  136. package/dist/icons/PhImage.svelte.d.ts +5 -0
  137. package/dist/icons/PhListMagnifyingGlass.svelte +17 -0
  138. package/dist/icons/PhListMagnifyingGlass.svelte.d.ts +5 -0
  139. package/dist/icons/PhMagnifyingGlass.svelte +17 -0
  140. package/dist/icons/PhMagnifyingGlass.svelte.d.ts +5 -0
  141. package/dist/icons/PhMicrosoftExcelLogo.svelte +17 -0
  142. package/dist/icons/PhMicrosoftExcelLogo.svelte.d.ts +5 -0
  143. package/dist/icons/PhStar.svelte +18 -0
  144. package/dist/icons/PhStar.svelte.d.ts +5 -0
  145. package/dist/icons/PhUploadSimple.svelte +18 -0
  146. package/dist/icons/PhUploadSimple.svelte.d.ts +5 -0
  147. package/dist/icons/PhUser.svelte +18 -0
  148. package/dist/icons/PhUser.svelte.d.ts +5 -0
  149. package/dist/icons/PhVideoCamera.svelte +17 -0
  150. package/dist/icons/PhVideoCamera.svelte.d.ts +5 -0
  151. package/dist/index.d.ts +17 -4
  152. package/dist/index.js +17 -4
  153. package/dist/open-props/props.colors-oklch-hues.css +14 -0
  154. package/dist/open-props/props.colors-oklch.css +19 -0
  155. package/dist/open-props/props.gray-oklch.css +18 -0
  156. package/dist/theme.css +17 -5
  157. package/package.json +4 -3
  158. package/dist/components/button/Button.svelte +0 -33
  159. package/dist/gray-oklch.min.css +0 -1
  160. package/dist/green-hsl.min.css +0 -1
  161. package/dist/props.colors-oklch-hues.css +0 -14
  162. package/dist/props.colors-oklch.css +0 -19
  163. package/dist/props.gray-oklch.css +0 -18
  164. /package/dist/components/checkbox/{Checkbox-group.svelte.d.ts → checkbox-group.svelte.d.ts} +0 -0
  165. /package/dist/components/checkbox/{Checkbox.svelte.d.ts → checkbox.svelte.d.ts} +0 -0
  166. /package/dist/components/combobox/{Combobox.svelte.d.ts → combobox.svelte.d.ts} +0 -0
@@ -0,0 +1,16 @@
1
+ <script lang="ts">
2
+ import type { HTMLButtonAttributes } from 'svelte/elements';
3
+ import { button, type ButtonVariant, type ButtonSize } from './button.variants';
4
+
5
+ type Props = Omit<HTMLButtonAttributes, 'class'> & {
6
+ variant?: ButtonVariant;
7
+ size?: ButtonSize;
8
+ class?: string;
9
+ };
10
+
11
+ let { variant, size, class: className, children, ...rest }: Props = $props();
12
+ </script>
13
+
14
+ <button class={button({ variant, size, class: className })} {...rest}>
15
+ {@render children?.()}
16
+ </button>
@@ -1,7 +1,8 @@
1
1
  import type { HTMLButtonAttributes } from 'svelte/elements';
2
+ import { type ButtonVariant, type ButtonSize } from './button.variants';
2
3
  type Props = Omit<HTMLButtonAttributes, 'class'> & {
3
- variant?: 'solid' | 'outline' | 'ghost';
4
- size?: 'sm' | 'md' | 'lg';
4
+ variant?: ButtonVariant;
5
+ size?: ButtonSize;
5
6
  class?: string;
6
7
  };
7
8
  declare const Button: import("svelte").Component<Props, {}, "">;
@@ -0,0 +1,46 @@
1
+ import { type VariantProps } from 'tailwind-variants';
2
+ export declare const button: import("tailwind-variants").TVReturnType<{
3
+ variant: {
4
+ default: string;
5
+ outline: string;
6
+ ghost: string;
7
+ };
8
+ size: {
9
+ sm: string;
10
+ default: string;
11
+ lg: string;
12
+ icon: string;
13
+ 'icon-sm': string;
14
+ 'icon-lg': string;
15
+ };
16
+ }, undefined, "focus-visible:outline-ring inline-flex cursor-pointer items-center justify-center rounded bg-transparent text-sm font-medium transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none disabled:opacity-50", {
17
+ variant: {
18
+ default: string;
19
+ outline: string;
20
+ ghost: string;
21
+ };
22
+ size: {
23
+ sm: string;
24
+ default: string;
25
+ lg: string;
26
+ icon: string;
27
+ 'icon-sm': string;
28
+ 'icon-lg': string;
29
+ };
30
+ }, undefined, import("tailwind-variants").TVReturnType<{
31
+ variant: {
32
+ default: string;
33
+ outline: string;
34
+ ghost: string;
35
+ };
36
+ size: {
37
+ sm: string;
38
+ default: string;
39
+ lg: string;
40
+ icon: string;
41
+ 'icon-sm': string;
42
+ 'icon-lg': string;
43
+ };
44
+ }, undefined, "focus-visible:outline-ring inline-flex cursor-pointer items-center justify-center rounded bg-transparent text-sm font-medium transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none disabled:opacity-50", unknown, unknown, undefined>>;
45
+ export type ButtonVariant = VariantProps<typeof button>['variant'];
46
+ export type ButtonSize = VariantProps<typeof button>['size'];
@@ -0,0 +1,20 @@
1
+ import { tv } from 'tailwind-variants';
2
+ export const button = tv({
3
+ base: 'focus-visible:outline-ring inline-flex cursor-pointer items-center justify-center rounded bg-transparent text-sm font-medium transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none disabled:opacity-50',
4
+ variants: {
5
+ variant: {
6
+ default: 'bg-primary text-white hover:bg-primary/90 active:bg-primary/80',
7
+ outline: 'border text-ink hover:bg-surface-2',
8
+ ghost: 'text-ink hover:bg-surface-2'
9
+ },
10
+ size: {
11
+ sm: 'h-8 gap-1.5 px-2',
12
+ default: 'h-9 gap-2 px-3',
13
+ lg: 'h-10 gap-2.5 px-4',
14
+ icon: 'size-9',
15
+ 'icon-sm': 'size-8',
16
+ 'icon-lg': 'size-10'
17
+ }
18
+ },
19
+ defaultVariants: { variant: 'default', size: 'default' }
20
+ });
@@ -0,0 +1,120 @@
1
+ <script lang="ts">
2
+ import PhArrowLeft from '../../icons/PhArrowLeft.svelte';
3
+ import PhArrowRight from '../../icons/PhArrowRight.svelte';
4
+ import PhCheck from '../../icons/PhCheck.svelte';
5
+ import PhImage from '../../icons/PhImage.svelte';
6
+ import PhStar from '../../icons/PhStar.svelte';
7
+ import { Carousel } from '@ark-ui/svelte/carousel';
8
+ import type { CarouselRootProps } from '@ark-ui/svelte/carousel';
9
+
10
+ interface ImageItem {
11
+ id?: string | number;
12
+ src: string;
13
+ alt?: string;
14
+ is_primary?: boolean;
15
+ position?: number;
16
+ }
17
+
18
+ interface Props extends Omit<CarouselRootProps, 'slideCount'> {
19
+ images: ImageItem[];
20
+ indicator?: boolean;
21
+ selectable?: boolean;
22
+ selectedIds?: (string | number)[];
23
+ onSetStar?: (id: string | number) => void;
24
+ }
25
+
26
+ let {
27
+ images,
28
+ indicator = false,
29
+ selectable = false,
30
+ selectedIds = $bindable([]),
31
+ onSetStar,
32
+ ...rootProps
33
+ }: Props = $props();
34
+
35
+ function toggleSelect(id: string | number) {
36
+ if (selectedIds.includes(id)) {
37
+ selectedIds = selectedIds.filter((i) => i !== id);
38
+ } else {
39
+ selectedIds = [...selectedIds, id];
40
+ }
41
+ }
42
+ </script>
43
+
44
+ {#if images.length === 0}
45
+ <div
46
+ class="flex flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed py-12 text-center text-ink-dim"
47
+ >
48
+ <PhImage class="size-10 opacity-40" />
49
+ <p class="text-sm">No images yet.</p>
50
+ </div>
51
+ {:else}
52
+ <Carousel.Root slideCount={images.length} {...rootProps}>
53
+ <Carousel.Control class="flex items-center gap-2">
54
+ <Carousel.PrevTrigger
55
+ class="inline-flex size-9 items-center justify-center rounded-md border bg-surface-1 shadow-sm hover:bg-surface-2 active:bg-surface-3 disabled:opacity-50"
56
+ >
57
+ <PhArrowLeft class="size-4" />
58
+ </Carousel.PrevTrigger>
59
+ <Carousel.ItemGroup class="flex flex-1 overflow-hidden rounded-lg">
60
+ {#each images as image, index (image.id ?? index)}
61
+ {@const key = image.id ?? index}
62
+ {@const isSelected = selectable && selectedIds.includes(key)}
63
+ <Carousel.Item {index} class="min-w-0 flex-[0_0_100%]">
64
+ <div class="group/slide relative">
65
+ <img
66
+ src={image.src}
67
+ alt={image.alt ?? ''}
68
+ class="aspect-square w-full rounded-lg bg-surface-2 object-contain"
69
+ />
70
+ {#if onSetStar && image.id != null}
71
+ <button
72
+ class="absolute top-2 left-2 z-10 transition-opacity {image.is_primary
73
+ ? 'opacity-100'
74
+ : 'opacity-0 group-hover/slide:opacity-100'}"
75
+ title={image.is_primary ? 'Primary image' : 'Set as primary'}
76
+ onclick={() => onSetStar(image.id!)}
77
+ >
78
+ <PhStar
79
+ class="size-5 drop-shadow {image.is_primary
80
+ ? 'fill-yellow-400 text-yellow-400'
81
+ : 'text-white/70 hover:text-yellow-300'}"
82
+ />
83
+ </button>
84
+ {/if}
85
+ {#if selectable}
86
+ <button
87
+ class="absolute top-2 right-2 z-10 flex size-6 items-center justify-center rounded-full border-2 transition-all {isSelected
88
+ ? 'border-primary bg-primary text-white opacity-100'
89
+ : 'border-white/80 bg-black/40 opacity-0 group-hover/slide:opacity-100'}"
90
+ onclick={() => toggleSelect(key)}
91
+ >
92
+ {#if isSelected}
93
+ <PhCheck class="size-3.5" />
94
+ {/if}
95
+ </button>
96
+ {/if}
97
+ </div>
98
+ </Carousel.Item>
99
+ {/each}
100
+ </Carousel.ItemGroup>
101
+ <Carousel.NextTrigger
102
+ class="inline-flex size-9 items-center justify-center rounded-md border bg-surface-1 shadow-sm hover:bg-surface-2 active:bg-surface-3 disabled:opacity-50"
103
+ >
104
+ <PhArrowRight class="size-4" />
105
+ </Carousel.NextTrigger>
106
+ </Carousel.Control>
107
+ {#if indicator}
108
+ <Carousel.IndicatorGroup class="mt-2 flex justify-center gap-2">
109
+ {#each images as image, index (index)}
110
+ <Carousel.Indicator
111
+ {index}
112
+ class="h-15 w-15 cursor-pointer overflow-hidden rounded-sm border-2 border-transparent opacity-60 transition-all data-current:border-primary data-current:opacity-100"
113
+ >
114
+ <img src={image.src} alt={image.alt ?? ''} class="h-full w-full object-cover" />
115
+ </Carousel.Indicator>
116
+ {/each}
117
+ </Carousel.IndicatorGroup>
118
+ {/if}
119
+ </Carousel.Root>
120
+ {/if}
@@ -0,0 +1,19 @@
1
+ import { Carousel } from '@ark-ui/svelte/carousel';
2
+ import type { CarouselRootProps } from '@ark-ui/svelte/carousel';
3
+ interface ImageItem {
4
+ id?: string | number;
5
+ src: string;
6
+ alt?: string;
7
+ is_primary?: boolean;
8
+ position?: number;
9
+ }
10
+ interface Props extends Omit<CarouselRootProps, 'slideCount'> {
11
+ images: ImageItem[];
12
+ indicator?: boolean;
13
+ selectable?: boolean;
14
+ selectedIds?: (string | number)[];
15
+ onSetStar?: (id: string | number) => void;
16
+ }
17
+ declare const Carousel: import("svelte").Component<Props, {}, "selectedIds">;
18
+ type Carousel = ReturnType<typeof Carousel>;
19
+ export default Carousel;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts" generics="T extends string | number">
2
2
  import { Checkbox } from '@ark-ui/svelte/checkbox';
3
3
  import type { CheckboxGroupProps } from './checkbox-group.types';
4
- import CheckboxItem from './Checkbox.svelte';
4
+ import CheckboxItem from './checkbox.svelte';
5
5
 
6
6
  let {
7
7
  items,
@@ -2,6 +2,7 @@
2
2
  import { Checkbox } from '@ark-ui/svelte/checkbox';
3
3
  import type { CheckboxProps as Props } from './checkbox.types.js';
4
4
  import PhCheck from '../../icons/PhCheck.svelte';
5
+ import PhMinus from '../../icons/PhMinus.svelte';
5
6
 
6
7
  let { checked = $bindable(), label, children, ...rest }: Props = $props();
7
8
  </script>
@@ -14,10 +15,13 @@
14
15
  <Checkbox.Control
15
16
  class="{children
16
17
  ? 'mt-0.5'
17
- : ''} flex size-5 shrink-0 items-center justify-center rounded-sm border border-border bg-transparent transition-colors data-disabled:pointer-events-none data-disabled:opacity-50 data-focus-visible:outline-2 data-focus-visible:outline-offset-2 data-focus-visible:outline-ring data-[state=checked]:border-primary data-[state=checked]:bg-primary"
18
+ : ''} data-focus-visible:outline-ring flex size-5 shrink-0 items-center justify-center rounded-sm border bg-transparent transition-colors hover:border-primary/50 data-disabled:pointer-events-none data-disabled:opacity-50 data-focus-visible:outline-2 data-focus-visible:outline-offset-2 data-invalid:border-danger data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary"
18
19
  >
19
20
  <Checkbox.Indicator>
20
- <PhCheck class="size-3.5 text-primary-foreground" />
21
+ <PhCheck class="size-3.5 text-white" />
22
+ </Checkbox.Indicator>
23
+ <Checkbox.Indicator indeterminate>
24
+ <PhMinus class="size-3.5 text-white" />
21
25
  </Checkbox.Indicator>
22
26
  </Checkbox.Control>
23
27
  {#if label}
@@ -16,8 +16,9 @@
16
16
  placeholder,
17
17
  layout = 'vertical',
18
18
  name,
19
- readonly,
19
+ readOnly,
20
20
  multiple,
21
+ loading = false,
21
22
  ...restProps
22
23
  }: ComboboxProps<T> = $props();
23
24
 
@@ -91,21 +92,22 @@
91
92
  onInputValueChange={handleInputChange}
92
93
  openOnClick
93
94
  {multiple}
94
- readOnly={readonly}
95
+ {readOnly}
95
96
  {...restProps}
96
97
  class={cn(layout === 'horizontal' ? 'flex items-center gap-1.5' : 'grid gap-1.5')}
97
98
  >
98
99
  {#if label}
99
- <Combobox.Label>
100
+ <Combobox.Label class="text-sm">
100
101
  {label}
101
- <Field.RequiredIndicator />
102
+ <Field.RequiredIndicator class="text-danger" />
102
103
  </Combobox.Label>
103
104
  {/if}
104
105
 
105
106
  <Combobox.Control
106
107
  class={cn(
107
108
  'rounded-ark flex min-h-9 items-center gap-1 border px-3 shadow-sm',
108
- 'focus-within:ring-1 focus-within:ring-(--ark-ring)',
109
+ 'focus-within:ring-1 focus-within:ring-primary',
110
+ 'data-invalid:border-danger data-invalid:focus-within:ring-danger',
109
111
  multiple && 'flex-wrap py-1'
110
112
  )}
111
113
  >
@@ -114,21 +116,8 @@
114
116
  {#each value as v (v)}
115
117
  {@const item = items.find((i) => i.value === v)}
116
118
  {#if item}
117
- <span
118
- class="inline-flex items-center gap-1 rounded bg-(--ark-hover-bg) px-2 py-0.5 text-xs"
119
- >
119
+ <span class="inline-flex items-center gap-1 rounded bg-surface-2 px-2 py-0.5 text-xs">
120
120
  {item.label}
121
- {#if !readonly}
122
- <button
123
- type="button"
124
- onclick={() => {
125
- value = (value as (number | string)[]).filter((x) => x !== v);
126
- }}
127
- class="hover:text-(--ark-error)"
128
- >
129
- <PhX class="size-3" />
130
- </button>
131
- {/if}
132
121
  </span>
133
122
  {/if}
134
123
  {/each}
@@ -138,7 +127,7 @@
138
127
  placeholder={placeholder ?? 'Search...'}
139
128
  class="flex-1 bg-transparent text-sm outline-none placeholder:text-ink-dim disabled:cursor-not-allowed disabled:opacity-50"
140
129
  />
141
- {#if value != null && !readonly && !multiple}
130
+ {#if !readOnly}
142
131
  <Combobox.ClearTrigger class="text-ink-dim transition-colors hover:text-ink">
143
132
  <PhX class="size-4" />
144
133
  </Combobox.ClearTrigger>
@@ -153,11 +142,19 @@
153
142
  <Combobox.Content
154
143
  class="data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 z-50 max-h-60 min-w-(--reference-width) overflow-auto rounded-md border bg-surface-1 p-1 shadow-md"
155
144
  >
156
- <Combobox.Empty class="py-2 text-center text-sm text-ink-dim">
157
- No results found
158
- </Combobox.Empty>
145
+ {#if loading}
146
+ <div class="flex items-center justify-center py-4">
147
+ <span
148
+ class="size-5 animate-spin rounded-full border-2 border-surface-3 border-t-ink-dim"
149
+ ></span>
150
+ </div>
151
+ {:else}
152
+ <Combobox.Empty class="py-2 text-center text-sm text-ink-dim">
153
+ No results found
154
+ </Combobox.Empty>
155
+ {/if}
159
156
 
160
- {#each collection.items as item (item.value)}
157
+ {#each loading ? [] : collection.items as item (item.value)}
161
158
  <Combobox.Item
162
159
  {item}
163
160
  class="relative flex cursor-default items-center rounded-sm py-1.5 pr-8 pl-2 text-sm select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-highlighted:bg-surface-2 data-[state=checked]:bg-surface-2"
@@ -9,8 +9,8 @@ export interface ComboboxProps<T extends ComboboxItem> extends Omit<ComboboxRoot
9
9
  items: T[];
10
10
  label?: string;
11
11
  placeholder?: string;
12
- readonly?: boolean;
13
12
  name?: string;
14
13
  multiple?: boolean;
15
14
  layout?: 'vertical' | 'horizontal';
15
+ loading?: boolean;
16
16
  }
@@ -0,0 +1,73 @@
1
+ <script lang="ts">
2
+ import PhX from '../../icons/PhX.svelte';
3
+ import { Dialog } from '@ark-ui/svelte/dialog';
4
+ import { Portal } from '@ark-ui/svelte/portal';
5
+
6
+ type Variant = 'default' | 'destructive';
7
+
8
+ type Props = {
9
+ open: boolean;
10
+ title: string;
11
+ description?: string | string[];
12
+ confirmLabel?: string;
13
+ cancelLabel?: string;
14
+ onConfirm?: () => void;
15
+ variant?: Variant;
16
+ };
17
+
18
+ let {
19
+ open = $bindable(),
20
+ title,
21
+ description,
22
+ confirmLabel = 'Confirm',
23
+ cancelLabel = 'Cancel',
24
+ onConfirm,
25
+ variant = 'default'
26
+ }: Props = $props();
27
+
28
+ const confirmClass = $derived(
29
+ variant === 'destructive'
30
+ ? 'inline-flex h-9 items-center justify-center rounded-md bg-red-600 px-4 text-sm font-medium text-white shadow-sm transition-colors hover:bg-red-700 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary'
31
+ : 'inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-white shadow-sm transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary'
32
+ );
33
+ </script>
34
+
35
+ <Dialog.Root role="alertdialog" bind:open>
36
+ <Portal>
37
+ <Dialog.Backdrop
38
+ class="data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fixed inset-0 z-50 bg-black/50"
39
+ />
40
+ <Dialog.Positioner class="fixed inset-0 z-50 flex items-center justify-center">
41
+ <Dialog.Content
42
+ class="data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 relative w-full max-w-md rounded-lg border bg-surface-1 p-6 shadow-xl"
43
+ >
44
+ <Dialog.Title class="text-lg leading-none font-semibold tracking-tight">
45
+ {title}
46
+ </Dialog.Title>
47
+ {#if description}
48
+ <Dialog.Description class="mt-2 text-sm text-ink-dim">
49
+ {#each Array.isArray(description) ? description : [description] as line, i (i)}
50
+ <span class="block">{line}</span>
51
+ {/each}
52
+ </Dialog.Description>
53
+ {/if}
54
+ <div class="mt-6 flex justify-end gap-3">
55
+ <Dialog.CloseTrigger
56
+ class="inline-flex h-9 items-center justify-center rounded-md border bg-surface-1 px-4 text-sm font-medium shadow-sm transition-colors hover:bg-surface-2 hover:text-ink focus-visible:ring-1 focus-visible:ring-primary focus-visible:outline-none"
57
+ >
58
+ {cancelLabel}
59
+ </Dialog.CloseTrigger>
60
+ <button type="button" class={confirmClass} onclick={onConfirm}>
61
+ {confirmLabel}
62
+ </button>
63
+ </div>
64
+ <Dialog.CloseTrigger
65
+ class="absolute top-3 right-3 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-primary focus:ring-offset-2 focus:outline-none"
66
+ >
67
+ <PhX class="h-4 w-4" />
68
+ <span class="sr-only">Close</span>
69
+ </Dialog.CloseTrigger>
70
+ </Dialog.Content>
71
+ </Dialog.Positioner>
72
+ </Portal>
73
+ </Dialog.Root>
@@ -0,0 +1,13 @@
1
+ type Variant = 'default' | 'destructive';
2
+ type Props = {
3
+ open: boolean;
4
+ title: string;
5
+ description?: string | string[];
6
+ confirmLabel?: string;
7
+ cancelLabel?: string;
8
+ onConfirm?: () => void;
9
+ variant?: Variant;
10
+ };
11
+ declare const AlertDialog: import("svelte").Component<Props, {}, "open">;
12
+ type AlertDialog = ReturnType<typeof AlertDialog>;
13
+ export default AlertDialog;
@@ -0,0 +1,68 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import { Dialog } from '@ark-ui/svelte/dialog';
4
+ import { Portal } from '@ark-ui/svelte/portal';
5
+ import { cn } from 'tailwind-variants';
6
+ import PhX from '../../icons/PhX.svelte';
7
+
8
+ interface Props {
9
+ open: boolean;
10
+ title: string;
11
+ description?: string;
12
+ children: Snippet;
13
+ footer?: Snippet;
14
+ onClose?: () => void;
15
+ contentClass?: string;
16
+ }
17
+
18
+ let {
19
+ open = $bindable(),
20
+ title,
21
+ description,
22
+ children,
23
+ footer,
24
+ onClose,
25
+ contentClass
26
+ }: Props = $props();
27
+ </script>
28
+
29
+ <Dialog.Root bind:open lazyMount unmountOnExit>
30
+ <Portal>
31
+ <Dialog.Backdrop
32
+ class="data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 fixed inset-0 z-50 bg-black/50"
33
+ />
34
+ <Dialog.Positioner class="fixed inset-0 z-50 flex items-center justify-center p-4">
35
+ <Dialog.Content
36
+ class={cn(
37
+ 'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 relative w-full max-w-2xl rounded-lg border bg-surface-1 p-6 shadow-xl',
38
+ contentClass
39
+ )}
40
+ >
41
+ <Dialog.Title class="text-lg font-semibold">{title}</Dialog.Title>
42
+ {#if description}
43
+ <Dialog.Description class="mt-1 text-sm text-ink-dim">
44
+ {description}
45
+ </Dialog.Description>
46
+ {/if}
47
+
48
+ <div class="mt-4">
49
+ {@render children()}
50
+ </div>
51
+
52
+ {#if footer}
53
+ <div class="mt-4 flex justify-end gap-3">
54
+ {@render footer()}
55
+ </div>
56
+ {/if}
57
+
58
+ <Dialog.CloseTrigger
59
+ class="absolute top-3 right-3 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:outline-none active:opacity-50"
60
+ onclick={onClose}
61
+ >
62
+ <PhX class="size-4" />
63
+ <span class="sr-only">Close</span>
64
+ </Dialog.CloseTrigger>
65
+ </Dialog.Content>
66
+ </Dialog.Positioner>
67
+ </Portal>
68
+ </Dialog.Root>
@@ -0,0 +1,14 @@
1
+ import type { Snippet } from 'svelte';
2
+ import { Dialog } from '@ark-ui/svelte/dialog';
3
+ interface Props {
4
+ open: boolean;
5
+ title: string;
6
+ description?: string;
7
+ children: Snippet;
8
+ footer?: Snippet;
9
+ onClose?: () => void;
10
+ contentClass?: string;
11
+ }
12
+ declare const Dialog: import("svelte").Component<Props, {}, "open">;
13
+ type Dialog = ReturnType<typeof Dialog>;
14
+ export default Dialog;
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import { Field } from '@ark-ui/svelte/field';
3
+ import type { FieldErrorTextProps } from './types';
4
+ import { cn } from 'tailwind-variants';
5
+
6
+ let { class: className, children, ...rest }: FieldErrorTextProps = $props();
7
+ </script>
8
+
9
+ <Field.ErrorText {...rest} class={cn('text-xs font-medium text-danger', className)}>
10
+ {@render children?.()}
11
+ </Field.ErrorText>
@@ -0,0 +1,4 @@
1
+ import type { FieldErrorTextProps } from './types';
2
+ declare const FieldErrorText: import("svelte").Component<FieldErrorTextProps, {}, "">;
3
+ type FieldErrorText = ReturnType<typeof FieldErrorText>;
4
+ export default FieldErrorText;
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import { Field } from '@ark-ui/svelte/field';
3
+ import type { FieldHelperTextProps } from './types';
4
+ import { cn } from 'tailwind-variants';
5
+
6
+ let { class: className, children, ...rest }: FieldHelperTextProps = $props();
7
+ </script>
8
+
9
+ <Field.HelperText {...rest} class={cn('text-xs text-ink-dim', className)}>
10
+ {@render children?.()}
11
+ </Field.HelperText>
@@ -0,0 +1,4 @@
1
+ import type { FieldHelperTextProps } from './types';
2
+ declare const FieldHelperText: import("svelte").Component<FieldHelperTextProps, {}, "">;
3
+ type FieldHelperText = ReturnType<typeof FieldHelperText>;
4
+ export default FieldHelperText;
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ import { Field } from '@ark-ui/svelte/field';
3
+ import type { FieldInputProps } from './types';
4
+ import { cn } from 'tailwind-variants';
5
+
6
+ let {
7
+ class: className,
8
+ value = $bindable(),
9
+ startIcon,
10
+ endIcon,
11
+ ...rest
12
+ }: FieldInputProps = $props();
13
+ </script>
14
+
15
+ <div class="relative w-full">
16
+ {#if startIcon}
17
+ <div
18
+ class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-2.5 text-ink-dim"
19
+ >
20
+ {@render startIcon()}
21
+ </div>
22
+ {/if}
23
+ <Field.Input
24
+ {...rest}
25
+ bind:value
26
+ class={cn(
27
+ 'flex h-9 w-full rounded-md border bg-surface-1 px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-ink-dim focus-visible:ring-1 focus-visible:ring-primary focus-visible:outline-none data-disabled:cursor-not-allowed data-disabled:opacity-50 data-invalid:border-danger data-invalid:focus-visible:ring-danger data-readonly:cursor-default data-readonly:opacity-70',
28
+ startIcon && 'pl-9',
29
+ endIcon && 'pr-9',
30
+ className
31
+ )}
32
+ />
33
+ {#if endIcon}
34
+ <div class="absolute inset-y-0 right-0 flex items-center pr-2.5">
35
+ {@render endIcon()}
36
+ </div>
37
+ {/if}
38
+ </div>
@@ -0,0 +1,4 @@
1
+ import type { FieldInputProps } from './types';
2
+ declare const FieldInput: import("svelte").Component<FieldInputProps, {}, "value">;
3
+ type FieldInput = ReturnType<typeof FieldInput>;
4
+ export default FieldInput;
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import { Field } from '@ark-ui/svelte/field';
3
+ import type { FieldLabelProps } from './types';
4
+ import { cn } from 'tailwind-variants';
5
+
6
+ let { class: className, children, ...rest }: FieldLabelProps = $props();
7
+ </script>
8
+
9
+ <Field.Label
10
+ {...rest}
11
+ class={cn(
12
+ 'text-sm leading-none font-medium data-disabled:cursor-not-allowed data-disabled:opacity-70',
13
+ className
14
+ )}
15
+ >
16
+ {@render children?.()}
17
+ <Field.RequiredIndicator class="ml-1 text-danger" />
18
+ </Field.Label>
@@ -0,0 +1,4 @@
1
+ import type { FieldLabelProps } from './types';
2
+ declare const FieldLabel: import("svelte").Component<FieldLabelProps, {}, "">;
3
+ type FieldLabel = ReturnType<typeof FieldLabel>;
4
+ export default FieldLabel;