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.
- package/dist/components/button/button.svelte +16 -0
- package/dist/components/button/{Button.svelte.d.ts → button.svelte.d.ts} +3 -2
- package/dist/components/button/button.variants.d.ts +46 -0
- package/dist/components/button/button.variants.js +20 -0
- package/dist/components/carousel/carousel.svelte +120 -0
- package/dist/components/carousel/carousel.svelte.d.ts +19 -0
- package/dist/components/checkbox/{Checkbox-group.svelte → checkbox-group.svelte} +1 -1
- package/dist/components/checkbox/{Checkbox.svelte → checkbox.svelte} +6 -2
- package/dist/components/combobox/{Combobox.svelte → combobox.svelte} +23 -26
- package/dist/components/combobox/types.d.ts +1 -1
- package/dist/components/dialog/alert-dialog.svelte +73 -0
- package/dist/components/dialog/alert-dialog.svelte.d.ts +13 -0
- package/dist/components/dialog/dialog.svelte +68 -0
- package/dist/components/dialog/dialog.svelte.d.ts +14 -0
- package/dist/components/field/field-error-text.svelte +11 -0
- package/dist/components/field/field-error-text.svelte.d.ts +4 -0
- package/dist/components/field/field-helper-text.svelte +11 -0
- package/dist/components/field/field-helper-text.svelte.d.ts +4 -0
- package/dist/components/field/field-input.svelte +38 -0
- package/dist/components/field/field-input.svelte.d.ts +4 -0
- package/dist/components/field/field-label.svelte +18 -0
- package/dist/components/field/field-label.svelte.d.ts +4 -0
- package/dist/components/field/field-textarea.svelte +16 -0
- package/dist/components/field/field-textarea.svelte.d.ts +4 -0
- package/dist/components/field/field.svelte +11 -0
- package/dist/components/field/field.svelte.d.ts +5 -0
- package/dist/components/field/index.d.ts +7 -0
- package/dist/components/field/index.js +6 -0
- package/dist/components/field/types.d.ts +22 -0
- package/dist/components/field/types.js +1 -0
- package/dist/components/file-upload/basic-document.svelte +89 -0
- package/dist/components/file-upload/basic-document.svelte.d.ts +4 -0
- package/dist/components/file-upload/basic.svelte +50 -0
- package/dist/components/file-upload/basic.svelte.d.ts +18 -0
- package/dist/components/file-upload/dropzone.svelte +26 -0
- package/dist/components/file-upload/dropzone.svelte.d.ts +4 -0
- package/dist/components/file-upload/files-list.svelte +97 -0
- package/dist/components/file-upload/files-list.svelte.d.ts +18 -0
- package/dist/components/file-upload/icons.d.ts +3 -0
- package/dist/components/file-upload/icons.js +39 -0
- package/dist/components/file-upload/types.d.ts +6 -0
- package/dist/components/file-upload/types.js +1 -0
- package/dist/components/file-upload/utils.d.ts +13 -0
- package/dist/components/file-upload/utils.js +18 -0
- package/dist/components/image-cropper/image-cropper.svelte +109 -0
- package/dist/components/image-cropper/image-cropper.svelte.d.ts +5 -0
- package/dist/components/image-cropper/types.d.ts +16 -0
- package/dist/components/image-cropper/types.js +1 -0
- package/dist/components/listbox/listbox.svelte +116 -0
- package/dist/components/listbox/listbox.svelte.d.ts +27 -0
- package/dist/components/listbox/types.d.ts +16 -0
- package/dist/components/listbox/types.js +1 -0
- package/dist/components/menu/index.d.ts +14 -0
- package/dist/components/menu/index.js +14 -0
- package/dist/components/menu/menu-checkbox-item.svelte +31 -0
- package/dist/components/menu/menu-checkbox-item.svelte.d.ts +12 -0
- package/dist/components/menu/menu-content.svelte +23 -0
- package/dist/components/menu/menu-content.svelte.d.ts +8 -0
- package/dist/components/menu/menu-context-trigger.svelte +20 -0
- package/dist/components/menu/menu-context-trigger.svelte.d.ts +8 -0
- package/dist/components/menu/menu-indicator.svelte +19 -0
- package/dist/components/menu/menu-indicator.svelte.d.ts +9 -0
- package/dist/components/menu/menu-item-group-label.svelte +17 -0
- package/dist/components/menu/menu-item-group-label.svelte.d.ts +9 -0
- package/dist/components/menu/menu-item-group.svelte +14 -0
- package/dist/components/menu/menu-item-group.svelte.d.ts +9 -0
- package/dist/components/menu/menu-item-indicator.svelte +14 -0
- package/dist/components/menu/menu-item-indicator.svelte.d.ts +9 -0
- package/dist/components/menu/menu-item.svelte +20 -0
- package/dist/components/menu/menu-item.svelte.d.ts +9 -0
- package/dist/components/menu/menu-radio-item-group.svelte +14 -0
- package/dist/components/menu/menu-radio-item-group.svelte.d.ts +9 -0
- package/dist/components/menu/menu-radio-item.svelte +28 -0
- package/dist/components/menu/menu-radio-item.svelte.d.ts +10 -0
- package/dist/components/menu/menu-separator.svelte +11 -0
- package/dist/components/menu/menu-separator.svelte.d.ts +7 -0
- package/dist/components/menu/menu-trigger-item.svelte +20 -0
- package/dist/components/menu/menu-trigger-item.svelte.d.ts +9 -0
- package/dist/components/menu/menu-trigger.svelte +19 -0
- package/dist/components/menu/menu-trigger.svelte.d.ts +12 -0
- package/dist/components/menu/menu.svelte +12 -0
- package/dist/components/menu/menu.svelte.d.ts +4 -0
- package/dist/components/number-input/number-input.svelte +67 -0
- package/dist/components/number-input/number-input.svelte.d.ts +5 -0
- package/dist/components/number-input/types.d.ts +7 -0
- package/dist/components/number-input/types.js +1 -0
- package/dist/components/select/select.svelte +93 -0
- package/dist/components/select/select.svelte.d.ts +26 -0
- package/dist/components/select/types.d.ts +13 -0
- package/dist/components/select/types.js +1 -0
- package/dist/components/splitter/splitter.svelte +60 -0
- package/dist/components/splitter/splitter.svelte.d.ts +5 -0
- package/dist/components/splitter/types.d.ts +9 -0
- package/dist/components/splitter/types.js +1 -0
- package/dist/components/switch/index.d.ts +2 -0
- package/dist/components/switch/index.js +1 -0
- package/dist/components/switch/switch.svelte +40 -0
- package/dist/components/switch/switch.svelte.d.ts +8 -0
- package/dist/components/switch/types.d.ts +5 -0
- package/dist/components/switch/types.js +1 -0
- package/dist/components/tabs/index.d.ts +4 -0
- package/dist/components/tabs/index.js +3 -0
- package/dist/components/tabs/tab-content.svelte +18 -0
- package/dist/components/tabs/tab-content.svelte.d.ts +7 -0
- package/dist/components/tabs/tab-trigger.svelte +18 -0
- package/dist/components/tabs/tab-trigger.svelte.d.ts +7 -0
- package/dist/components/tabs/tabs.svelte +39 -0
- package/dist/components/tabs/tabs.svelte.d.ts +5 -0
- package/dist/components/tabs/types.d.ts +8 -0
- package/dist/components/tabs/types.js +1 -0
- package/dist/components/tree-view/tree-view.svelte +210 -0
- package/dist/components/tree-view/tree-view.svelte.d.ts +26 -0
- package/dist/components/tree-view/types.d.ts +12 -0
- package/dist/components/tree-view/types.js +1 -0
- package/dist/icons/PhArrowLeft.svelte +18 -0
- package/dist/icons/PhArrowLeft.svelte.d.ts +5 -0
- package/dist/icons/PhArrowRight.svelte +18 -0
- package/dist/icons/PhArrowRight.svelte.d.ts +5 -0
- package/dist/icons/PhArrowsInSimple.svelte +17 -0
- package/dist/icons/PhArrowsInSimple.svelte.d.ts +5 -0
- package/dist/icons/PhCaretDown.svelte +2 -1
- package/dist/icons/PhCaretRight.svelte +17 -0
- package/dist/icons/PhCaretRight.svelte.d.ts +5 -0
- package/dist/icons/PhCaretUp.svelte +18 -0
- package/dist/icons/PhCaretUp.svelte.d.ts +5 -0
- package/dist/icons/PhCheck.svelte +2 -1
- package/dist/icons/PhFile.svelte +19 -0
- package/dist/icons/PhFile.svelte.d.ts +5 -0
- package/dist/icons/PhFileArchive.svelte +18 -0
- package/dist/icons/PhFileArchive.svelte.d.ts +5 -0
- package/dist/icons/PhFileText.svelte +18 -0
- package/dist/icons/PhFileText.svelte.d.ts +5 -0
- package/dist/icons/PhHeadphones.svelte +17 -0
- package/dist/icons/PhHeadphones.svelte.d.ts +5 -0
- package/dist/icons/PhImage.svelte +18 -0
- package/dist/icons/PhImage.svelte.d.ts +5 -0
- package/dist/icons/PhListMagnifyingGlass.svelte +17 -0
- package/dist/icons/PhListMagnifyingGlass.svelte.d.ts +5 -0
- package/dist/icons/PhMagnifyingGlass.svelte +17 -0
- package/dist/icons/PhMagnifyingGlass.svelte.d.ts +5 -0
- package/dist/icons/PhMicrosoftExcelLogo.svelte +17 -0
- package/dist/icons/PhMicrosoftExcelLogo.svelte.d.ts +5 -0
- package/dist/icons/PhStar.svelte +18 -0
- package/dist/icons/PhStar.svelte.d.ts +5 -0
- package/dist/icons/PhUploadSimple.svelte +18 -0
- package/dist/icons/PhUploadSimple.svelte.d.ts +5 -0
- package/dist/icons/PhUser.svelte +18 -0
- package/dist/icons/PhUser.svelte.d.ts +5 -0
- package/dist/icons/PhVideoCamera.svelte +17 -0
- package/dist/icons/PhVideoCamera.svelte.d.ts +5 -0
- package/dist/index.d.ts +17 -4
- package/dist/index.js +17 -4
- package/dist/open-props/props.colors-oklch-hues.css +14 -0
- package/dist/open-props/props.colors-oklch.css +19 -0
- package/dist/open-props/props.gray-oklch.css +18 -0
- package/dist/theme.css +17 -5
- package/package.json +4 -3
- package/dist/components/button/Button.svelte +0 -33
- package/dist/gray-oklch.min.css +0 -1
- package/dist/green-hsl.min.css +0 -1
- package/dist/props.colors-oklch-hues.css +0 -14
- package/dist/props.colors-oklch.css +0 -19
- package/dist/props.gray-oklch.css +0 -18
- /package/dist/components/checkbox/{Checkbox-group.svelte.d.ts → checkbox-group.svelte.d.ts} +0 -0
- /package/dist/components/checkbox/{Checkbox.svelte.d.ts → checkbox.svelte.d.ts} +0 -0
- /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,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,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,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,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,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 @@
|
|
|
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 {};
|