compote-ui 0.3.0 → 0.5.1

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} +23 -26
  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 { Field } from '@ark-ui/svelte/field';
3
+ import type { FieldTextareaProps } from './types';
4
+ import { cn } from 'tailwind-variants';
5
+
6
+ let { class: className, value = $bindable(), ...rest }: FieldTextareaProps = $props();
7
+ </script>
8
+
9
+ <Field.Textarea
10
+ {...rest}
11
+ {value}
12
+ class={cn(
13
+ 'flex min-h-20 w-full resize-y rounded-md border bg-surface-1 px-3 py-2 text-sm shadow-sm transition-colors 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',
14
+ className
15
+ )}
16
+ />
@@ -0,0 +1,4 @@
1
+ import type { FieldTextareaProps } from './types';
2
+ declare const FieldTextarea: import("svelte").Component<FieldTextareaProps, {}, "value">;
3
+ type FieldTextarea = ReturnType<typeof FieldTextarea>;
4
+ export default FieldTextarea;
@@ -0,0 +1,11 @@
1
+ <script lang="ts">
2
+ import { Field } from '@ark-ui/svelte/field';
3
+ import type { FieldRootProps } from './types';
4
+ import { cn } from 'tailwind-variants';
5
+
6
+ let { class: className, children, ...rest }: FieldRootProps = $props();
7
+ </script>
8
+
9
+ <Field.Root {...rest} class={cn('group flex flex-col gap-1.5', className)}>
10
+ {@render children?.()}
11
+ </Field.Root>
@@ -0,0 +1,5 @@
1
+ import { Field } from '@ark-ui/svelte/field';
2
+ import type { FieldRootProps } from './types';
3
+ declare const Field: import("svelte").Component<FieldRootProps, {}, "">;
4
+ type Field = ReturnType<typeof Field>;
5
+ export default Field;
@@ -0,0 +1,7 @@
1
+ export { default as Root } from './field.svelte';
2
+ export { default as Label } from './field-label.svelte';
3
+ export { default as Input } from './field-input.svelte';
4
+ export { default as Textarea } from './field-textarea.svelte';
5
+ export { default as HelperText } from './field-helper-text.svelte';
6
+ export { default as ErrorText } from './field-error-text.svelte';
7
+ export type { FieldRootProps, FieldLabelProps, FieldInputProps, FieldTextareaProps, FieldHelperTextProps, FieldErrorTextProps } from './types';
@@ -0,0 +1,6 @@
1
+ export { default as Root } from './field.svelte';
2
+ export { default as Label } from './field-label.svelte';
3
+ export { default as Input } from './field-input.svelte';
4
+ export { default as Textarea } from './field-textarea.svelte';
5
+ export { default as HelperText } from './field-helper-text.svelte';
6
+ export { default as ErrorText } from './field-error-text.svelte';
@@ -0,0 +1,22 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { FieldRootBaseProps, FieldLabelBaseProps, FieldInputProps as ArkFieldInputProps, FieldTextareaProps as ArkFieldTextareaProps, FieldHelperTextBaseProps, FieldErrorTextBaseProps } from '@ark-ui/svelte/field';
3
+ export interface FieldRootProps extends FieldRootBaseProps {
4
+ class?: string;
5
+ }
6
+ export interface FieldLabelProps extends FieldLabelBaseProps {
7
+ class?: string;
8
+ }
9
+ export interface FieldInputProps extends ArkFieldInputProps {
10
+ class?: string;
11
+ startIcon?: Snippet;
12
+ endIcon?: Snippet;
13
+ }
14
+ export interface FieldTextareaProps extends ArkFieldTextareaProps {
15
+ class?: string;
16
+ }
17
+ export interface FieldHelperTextProps extends FieldHelperTextBaseProps {
18
+ class?: string;
19
+ }
20
+ export interface FieldErrorTextProps extends FieldErrorTextBaseProps {
21
+ class?: string;
22
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,89 @@
1
+ <script lang="ts">
2
+ import { FileUpload } from '@ark-ui/svelte/file-upload';
3
+ import { Field } from '@ark-ui/svelte/field';
4
+
5
+ import { getFileIcon } from './icons';
6
+
7
+ import { getAcceptAttribute } from './utils';
8
+ import type { Props } from './types';
9
+ import PhFileText from '../../icons/PhFileText.svelte';
10
+
11
+ let {
12
+ fileType,
13
+ acceptedFiles,
14
+ onFileChange = $bindable(),
15
+ label,
16
+ ...restProps
17
+ }: Props = $props();
18
+ const accept = $derived(getAcceptAttribute(fileType));
19
+ // const id = $props.id();
20
+ </script>
21
+
22
+ <!-- {id} -->
23
+
24
+ <Field.Root class="w-full max-w-sm">
25
+ <FileUpload.Root
26
+ {...restProps}
27
+ maxFiles={1}
28
+ {accept}
29
+ {acceptedFiles}
30
+ {onFileChange}
31
+ class="flex flex-col items-start gap-3"
32
+ >
33
+ {#if label}
34
+ <Field.Label>
35
+ {label}
36
+ </Field.Label>
37
+ {/if}
38
+ <FileUpload.Context>
39
+ {#snippet render(context)}
40
+ <div class="flex items-center gap-3">
41
+ <!-- Image Preview / Placeholder -->
42
+ <div
43
+ class="flex h-10 w-10 items-center justify-center overflow-hidden rounded-xl border bg-surface-2"
44
+ >
45
+ {#if context().acceptedFiles.length > 0}
46
+ <FileUpload.ItemGroup>
47
+ {#each context().acceptedFiles as file (file.name)}
48
+ <FileUpload.Item file={context().acceptedFiles[0]}>
49
+ {#if file.type.startsWith('image/')}
50
+ <FileUpload.ItemPreview type="image/*">
51
+ <FileUpload.ItemPreviewImage class="h-full w-full object-cover" />
52
+ </FileUpload.ItemPreview>
53
+ {:else}
54
+ {@const IconComponent = getFileIcon(file)}
55
+ <IconComponent />
56
+ {/if}
57
+ </FileUpload.Item>
58
+ {/each}
59
+ </FileUpload.ItemGroup>
60
+ {:else}
61
+ <PhFileText class="h-5 w-5 text-ink-dim" />
62
+ {/if}
63
+ </div>
64
+
65
+ <!-- Upload/Change Button -->
66
+ <FileUpload.Trigger
67
+ class="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white hover:bg-primary/90 focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:outline-hidden"
68
+ >
69
+ {context().acceptedFiles.length > 0 ? 'Change image' : 'Upload image'}
70
+ </FileUpload.Trigger>
71
+ </div>
72
+
73
+ <!-- Filename and Remove -->
74
+ {#if context().acceptedFiles.length > 0}
75
+ <FileUpload.ItemGroup>
76
+ <FileUpload.Item file={context().acceptedFiles[0]} class="flex items-center gap-2">
77
+ <FileUpload.ItemName class="text-sm text-ink-dim" />
78
+ <FileUpload.ItemDeleteTrigger class="text-sm text-red-500 hover:text-red-600">
79
+ Remove
80
+ </FileUpload.ItemDeleteTrigger>
81
+ </FileUpload.Item>
82
+ </FileUpload.ItemGroup>
83
+ {/if}
84
+ {/snippet}
85
+ </FileUpload.Context>
86
+
87
+ <FileUpload.HiddenInput />
88
+ </FileUpload.Root>
89
+ </Field.Root>
@@ -0,0 +1,4 @@
1
+ import type { Props } from './types';
2
+ declare const BasicDocument: import("svelte").Component<Props, {}, "onFileChange">;
3
+ type BasicDocument = ReturnType<typeof BasicDocument>;
4
+ export default BasicDocument;
@@ -0,0 +1,50 @@
1
+ <script lang="ts">
2
+ import PhUser from '../../icons/PhUser.svelte';
3
+ import { FileUpload } from '@ark-ui/svelte/file-upload';
4
+ </script>
5
+
6
+ <FileUpload.Root maxFiles={1} accept="image/*" class="flex flex-col items-start gap-3">
7
+ <FileUpload.Context>
8
+ {#snippet render(context)}
9
+ <div class="flex items-center gap-3">
10
+ <!-- Image Preview / Placeholder -->
11
+ <div
12
+ class="flex h-10 w-10 items-center justify-center overflow-hidden rounded-xl border bg-surface-2"
13
+ >
14
+ {#if context().acceptedFiles.length > 0}
15
+ <FileUpload.ItemGroup>
16
+ <FileUpload.Item file={context().acceptedFiles[0]}>
17
+ <FileUpload.ItemPreview type="image/*">
18
+ <FileUpload.ItemPreviewImage class="h-full w-full object-cover" />
19
+ </FileUpload.ItemPreview>
20
+ </FileUpload.Item>
21
+ </FileUpload.ItemGroup>
22
+ {:else}
23
+ <PhUser class="h-5 w-5 text-ink-dim" />
24
+ {/if}
25
+ </div>
26
+
27
+ <!-- Upload/Change Button -->
28
+ <FileUpload.Trigger
29
+ class="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-white hover:bg-primary/90 focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:outline-hidden"
30
+ >
31
+ {context().acceptedFiles.length > 0 ? 'Change image' : 'Upload image'}
32
+ </FileUpload.Trigger>
33
+ </div>
34
+
35
+ <!-- Filename and Remove -->
36
+ {#if context().acceptedFiles.length > 0}
37
+ <FileUpload.ItemGroup>
38
+ <FileUpload.Item file={context().acceptedFiles[0]} class="flex items-center gap-2">
39
+ <FileUpload.ItemName class="text-sm text-ink-dim" />
40
+ <FileUpload.ItemDeleteTrigger class="text-sm text-red-500 hover:text-red-600">
41
+ Remove
42
+ </FileUpload.ItemDeleteTrigger>
43
+ </FileUpload.Item>
44
+ </FileUpload.ItemGroup>
45
+ {/if}
46
+ {/snippet}
47
+ </FileUpload.Context>
48
+
49
+ <FileUpload.HiddenInput />
50
+ </FileUpload.Root>
@@ -0,0 +1,18 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const Basic: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type Basic = InstanceType<typeof Basic>;
18
+ export default Basic;
@@ -0,0 +1,26 @@
1
+ <script lang="ts">
2
+ import { FileUpload } from '@ark-ui/svelte/file-upload';
3
+ import { getAcceptAttribute } from './utils';
4
+ import type { Props } from './types';
5
+ import PhUploadSimple from '../../icons/PhUploadSimple.svelte';
6
+
7
+ let {
8
+ fileType,
9
+ label = 'Drag & drop or click to browse',
10
+ maxFiles = 1,
11
+ onFileAccept,
12
+ ...restProps
13
+ }: Props = $props();
14
+
15
+ const accept = $derived(getAcceptAttribute(fileType));
16
+ </script>
17
+
18
+ <FileUpload.Root {maxFiles} {accept} {onFileAccept} {...restProps}>
19
+ <FileUpload.Dropzone
20
+ class="flex cursor-pointer flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed p-6 text-center text-ink-dim transition-colors hover:border-primary/50 data-dragging:border-primary data-dragging:bg-primary/5"
21
+ >
22
+ <PhUploadSimple class="size-8 opacity-60" />
23
+ <span class="text-sm">{label}</span>
24
+ </FileUpload.Dropzone>
25
+ <FileUpload.HiddenInput />
26
+ </FileUpload.Root>
@@ -0,0 +1,4 @@
1
+ import type { Props } from './types';
2
+ declare const Dropzone: import("svelte").Component<Props, {}, "">;
3
+ type Dropzone = ReturnType<typeof Dropzone>;
4
+ export default Dropzone;
@@ -0,0 +1,97 @@
1
+ <script lang="ts">
2
+ import { FileUpload } from '@ark-ui/svelte/file-upload';
3
+ import { getFileIcon } from './icons';
4
+ import PhFileText from '../../icons/PhFileText.svelte';
5
+ import PhX from '../../icons/PhX.svelte';
6
+
7
+ const defaultFiles = [
8
+ new File(['Welcome to Ark UI Svelte`'], 'document.pdf', {
9
+ type: 'text/plain'
10
+ }),
11
+ new File(['Welcome to Ark UI Svelte, this is a zip file`'], 'showcase.zip', {
12
+ type: 'application/zip'
13
+ }),
14
+ new File(['Welcome to Ark UI Svelte, this is an excel file`'], 'data.xlsx', {
15
+ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
16
+ })
17
+ ];
18
+ </script>
19
+
20
+ <FileUpload.Root
21
+ maxFiles={10}
22
+ maxFileSize={100 * 1024 * 1024}
23
+ class="w-full max-w-2xl space-y-4"
24
+ defaultAcceptedFiles={defaultFiles}
25
+ >
26
+ <FileUpload.Context>
27
+ {#snippet render(context)}
28
+ <!-- Dropzone -->
29
+ <FileUpload.Dropzone
30
+ class="flex w-full cursor-pointer flex-col items-center justify-center rounded-xl border-2 border-dashed border-surface-3 bg-surface-2 px-6 py-12 transition-colors hover:bg-surface-3"
31
+ >
32
+ <!-- File Icon -->
33
+ <div
34
+ class="mb-4 flex h-12 w-12 items-center justify-center rounded-full border bg-surface-1"
35
+ >
36
+ <PhFileText class="h-5 w-5 text-ink-dim" />
37
+ </div>
38
+
39
+ <!-- Text -->
40
+ <div class="space-y-2 text-center">
41
+ <h3 class="text-sm font-medium text-ink">Upload files</h3>
42
+ <p class="text-sm text-ink-dim">Drag & drop or click to browse</p>
43
+ <p class="text-xs text-ink-dim">All files • Max 10 files • Up to 100MB</p>
44
+ </div>
45
+ </FileUpload.Dropzone>
46
+
47
+ <!-- Files List -->
48
+ {#if context().acceptedFiles.length > 0}
49
+ <div class="space-y-3">
50
+ <FileUpload.ItemGroup>
51
+ {#each context().acceptedFiles as file (file.name)}
52
+ <FileUpload.Item {file}>
53
+ <div class="flex items-center gap-3 rounded-lg border bg-surface-1 p-3">
54
+ <!-- File Icon/Preview -->
55
+ <div
56
+ class="flex h-10 w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg border bg-surface-2"
57
+ >
58
+ {#if file.type.startsWith('image/')}
59
+ <FileUpload.ItemPreview type="image/*">
60
+ <FileUpload.ItemPreviewImage class="h-full w-full object-cover" />
61
+ </FileUpload.ItemPreview>
62
+ {:else}
63
+ {@const IconComponent = getFileIcon(file)}
64
+ <IconComponent class="h-4 w-4 opacity-60" />
65
+ {/if}
66
+ </div>
67
+
68
+ <!-- File Info -->
69
+ <div class="min-w-0 flex-1">
70
+ <FileUpload.ItemName class="truncate text-sm font-medium text-ink" />
71
+ <FileUpload.ItemSizeText class="text-xs text-ink-dim" />
72
+ </div>
73
+
74
+ <!-- Delete Button -->
75
+ <FileUpload.ItemDeleteTrigger
76
+ class="flex h-6 w-6 shrink-0 items-center justify-center text-ink-dim hover:text-ink"
77
+ >
78
+ <PhX class="h-4 w-4" />
79
+ </FileUpload.ItemDeleteTrigger>
80
+ </div>
81
+ </FileUpload.Item>
82
+ {/each}
83
+ </FileUpload.ItemGroup>
84
+
85
+ <!-- Remove All Button -->
86
+ <FileUpload.ClearTrigger
87
+ class="inline-flex items-center rounded-md border bg-surface-1 px-3 py-1.5 text-xs font-medium text-ink hover:bg-surface-2 focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:outline-hidden"
88
+ >
89
+ Remove all files
90
+ </FileUpload.ClearTrigger>
91
+ </div>
92
+ {/if}
93
+ {/snippet}
94
+ </FileUpload.Context>
95
+
96
+ <FileUpload.HiddenInput />
97
+ </FileUpload.Root>
@@ -0,0 +1,18 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const FilesList: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type FilesList = InstanceType<typeof FilesList>;
18
+ export default FilesList;
@@ -0,0 +1,3 @@
1
+ export declare const getFileIcon: (file: File) => import("svelte").Component<{
2
+ class?: string;
3
+ } & Record<string, any>, {}, "">;
@@ -0,0 +1,39 @@
1
+ import PhFile from '../../icons/PhFile.svelte';
2
+ import PhFileArchive from '../../icons/PhFileArchive.svelte';
3
+ import PhFileText from '../../icons/PhFileText.svelte';
4
+ import PhImage from '../../icons/PhImage.svelte';
5
+ import PhMicrosoftExcelLogo from '../../icons/PhMicrosoftExcelLogo.svelte';
6
+ import PhVideoCamera from '../../icons/PhVideoCamera.svelte';
7
+ import PhHeadphones from '../../icons/PhHeadphones.svelte';
8
+ export const getFileIcon = (file) => {
9
+ const fileType = file.type;
10
+ const fileName = file.name;
11
+ if (fileType.includes('pdf') ||
12
+ fileName.endsWith('.pdf') ||
13
+ fileType.includes('word') ||
14
+ fileName.endsWith('.doc') ||
15
+ fileName.endsWith('.docx')) {
16
+ return PhFileText;
17
+ }
18
+ else if (fileType.includes('zip') ||
19
+ fileType.includes('archive') ||
20
+ fileName.endsWith('.zip') ||
21
+ fileName.endsWith('.rar')) {
22
+ return PhFileArchive;
23
+ }
24
+ else if (fileType.includes('excel') ||
25
+ fileName.endsWith('.xls') ||
26
+ fileName.endsWith('.xlsx')) {
27
+ return PhMicrosoftExcelLogo;
28
+ }
29
+ else if (fileType.includes('video/')) {
30
+ return PhVideoCamera;
31
+ }
32
+ else if (fileType.includes('audio/')) {
33
+ return PhHeadphones;
34
+ }
35
+ else if (fileType.startsWith('image/')) {
36
+ return PhImage;
37
+ }
38
+ return PhFile;
39
+ };
@@ -0,0 +1,6 @@
1
+ import type { FileUploadRootProps } from '@ark-ui/svelte/file-upload';
2
+ import type { FileType } from './utils';
3
+ export interface Props extends FileUploadRootProps {
4
+ fileType: FileType;
5
+ label: string;
6
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ declare const fileTypeMap: {
2
+ excel: string;
3
+ word: string;
4
+ image: string;
5
+ pdf: string;
6
+ video: string;
7
+ audio: string;
8
+ text: string;
9
+ csv: string;
10
+ };
11
+ export type FileType = keyof typeof fileTypeMap;
12
+ export declare const getAcceptAttribute: (fileType?: FileType) => string | undefined;
13
+ export {};
@@ -0,0 +1,18 @@
1
+ const fileTypeMap = {
2
+ excel: 'application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
3
+ word: 'application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document',
4
+ image: 'image/*',
5
+ pdf: 'application/pdf',
6
+ video: 'video/*',
7
+ audio: 'audio/*',
8
+ text: 'text/plain',
9
+ csv: 'text/csv'
10
+ };
11
+ export const getAcceptAttribute = (fileType) => {
12
+ if (!fileType)
13
+ return undefined;
14
+ const accept = fileTypeMap[fileType];
15
+ if (!accept)
16
+ return undefined;
17
+ return accept;
18
+ };
@@ -0,0 +1,109 @@
1
+ <script lang="ts">
2
+ import { ImageCropper, useImageCropper } from '@ark-ui/svelte/image-cropper';
3
+ import type { ImageCropperProps } from './types';
4
+ import { Button } from '../..';
5
+
6
+ let {
7
+ src,
8
+ alt = 'Image',
9
+ aspectRatio = $bindable(),
10
+ // eslint-disable-next-line no-useless-assignment
11
+ getCroppedImage = $bindable(),
12
+ // eslint-disable-next-line no-useless-assignment
13
+ getCropData = $bindable(),
14
+ ...cropperProps
15
+ }: ImageCropperProps = $props();
16
+
17
+ const ASPECT_RATIO_OPTIONS = [
18
+ { label: 'Free', value: undefined as number | undefined },
19
+ { label: '1:1', value: 1 },
20
+ { label: '4:3', value: 4 / 3 },
21
+ { label: '16:9', value: 16 / 9 },
22
+ { label: '9:16', value: 9 / 16 }
23
+ ];
24
+
25
+ let imageAspectRatio = $state<number | undefined>(undefined);
26
+
27
+ $effect(() => {
28
+ if (!src) return;
29
+ const img = new Image();
30
+ let cancelled = false;
31
+ img.onload = () => {
32
+ if (!cancelled) imageAspectRatio = img.naturalWidth / img.naturalHeight;
33
+ };
34
+ img.src = src;
35
+ return () => {
36
+ cancelled = true;
37
+ };
38
+ });
39
+
40
+ const imageCropper = useImageCropper(() => ({ ...cropperProps, aspectRatio }));
41
+
42
+ // eslint-disable-next-line no-useless-assignment
43
+ getCroppedImage = (options) => imageCropper().getCroppedImage(options);
44
+ // eslint-disable-next-line no-useless-assignment
45
+ getCropData = () => imageCropper().getCropData();
46
+
47
+ let cropData = $derived(imageCropper().getCropData());
48
+ </script>
49
+
50
+ <div>
51
+ <div class="mb-2 flex flex-wrap items-center justify-between gap-1.5">
52
+ <div>
53
+ {#each ASPECT_RATIO_OPTIONS as option (option.label)}
54
+ <Button
55
+ variant={aspectRatio === option.value ? 'default' : 'outline'}
56
+ size="sm"
57
+ onclick={() => {
58
+ aspectRatio = option.value;
59
+ }}
60
+ >
61
+ {option.label}
62
+ </Button>
63
+ {/each}
64
+ </div>
65
+ <p>Width: {cropData.width}px / Height: {cropData.height}px</p>
66
+ </div>
67
+
68
+ <ImageCropper.RootProvider value={imageCropper}>
69
+ <ImageCropper.Viewport
70
+ class="relative overflow-hidden rounded-lg bg-surface-2"
71
+ style={imageAspectRatio ? `aspect-ratio: ${imageAspectRatio}` : 'aspect-ratio: 1'}
72
+ >
73
+ <ImageCropper.Image
74
+ {src}
75
+ {alt}
76
+ crossorigin="anonymous"
77
+ class="pointer-events-none absolute inset-0 h-full w-full object-fill select-none"
78
+ />
79
+ <ImageCropper.Selection
80
+ class="cursor-move border-2 border-white/50 [box-shadow:0_0_0_9999px_rgb(0_0_0/0.5)] outline-none focus-visible:border-primary data-dragging:cursor-grabbing data-dragging:border-white/80"
81
+ >
82
+ {#each ImageCropper.handles as position (position)}
83
+ <ImageCropper.Handle
84
+ {position}
85
+ class="absolute flex touch-none items-center justify-center
86
+ data-[position=bottom]:cursor-ns-resize
87
+ data-[position=bottom-left]:cursor-nesw-resize
88
+ data-[position=bottom-right]:cursor-nwse-resize
89
+ data-[position=left]:cursor-ew-resize
90
+ data-[position=right]:cursor-ew-resize
91
+ data-[position=top]:cursor-ns-resize
92
+ data-[position=top-left]:cursor-nwse-resize
93
+ data-[position=top-right]:cursor-nesw-resize"
94
+ >
95
+ <div class="size-2 rounded-full bg-white shadow-md"></div>
96
+ </ImageCropper.Handle>
97
+ {/each}
98
+ <ImageCropper.Grid
99
+ axis="horizontal"
100
+ class="pointer-events-none absolute inset-[33.33%_0] border-y border-white/40 opacity-0 transition-opacity data-dragging:opacity-100 data-panning:opacity-100"
101
+ />
102
+ <ImageCropper.Grid
103
+ axis="vertical"
104
+ class="pointer-events-none absolute inset-[0_33.33%] border-x border-white/40 opacity-0 transition-opacity data-dragging:opacity-100 data-panning:opacity-100"
105
+ />
106
+ </ImageCropper.Selection>
107
+ </ImageCropper.Viewport>
108
+ </ImageCropper.RootProvider>
109
+ </div>
@@ -0,0 +1,5 @@
1
+ import { ImageCropper } from '@ark-ui/svelte/image-cropper';
2
+ import type { ImageCropperProps } from './types';
3
+ declare const ImageCropper: import("svelte").Component<ImageCropperProps, {}, "aspectRatio" | "getCroppedImage" | "getCropData">;
4
+ type ImageCropper = ReturnType<typeof ImageCropper>;
5
+ export default ImageCropper;
@@ -0,0 +1,16 @@
1
+ import type { UseImageCropperProps, ImageCropperGetCroppedImageOptions } from '@ark-ui/svelte/image-cropper';
2
+ export interface CropData {
3
+ x: number;
4
+ y: number;
5
+ width: number;
6
+ height: number;
7
+ rotate: number;
8
+ flipX: boolean;
9
+ flipY: boolean;
10
+ }
11
+ export interface ImageCropperProps extends UseImageCropperProps {
12
+ src: string;
13
+ alt?: string;
14
+ getCroppedImage?: (options?: ImageCropperGetCroppedImageOptions) => Promise<string | Blob | null>;
15
+ getCropData?: () => CropData;
16
+ }
@@ -0,0 +1 @@
1
+ export {};