@makolabs/ripple 0.0.1-dev.4 → 0.0.1-dev.40
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/README.md +394 -54
- package/dist/button/Button.svelte +5 -3
- package/dist/button/Button.svelte.d.ts +1 -1
- package/dist/button/button.d.ts +40 -63
- package/dist/button/button.js +15 -14
- package/dist/charts/Chart.svelte +545 -0
- package/dist/charts/Chart.svelte.d.ts +4 -0
- package/dist/drawer/Drawer.svelte +13 -2
- package/dist/drawer/Drawer.svelte.d.ts +1 -1
- package/dist/drawer/drawer.d.ts +0 -17
- package/dist/drawer/drawer.js +3 -3
- package/dist/elements/accordion/Accordion.svelte +83 -0
- package/dist/elements/accordion/Accordion.svelte.d.ts +4 -0
- package/dist/elements/accordion/accordion.d.ts +200 -0
- package/dist/elements/accordion/accordion.js +86 -0
- package/dist/elements/alert/Alert.svelte +57 -0
- package/dist/elements/alert/Alert.svelte.d.ts +4 -0
- package/dist/elements/badge/Badge.svelte +13 -5
- package/dist/elements/badge/Badge.svelte.d.ts +1 -1
- package/dist/elements/badge/badge.d.ts +0 -12
- package/dist/elements/dropdown/Dropdown.svelte +32 -37
- package/dist/elements/dropdown/Dropdown.svelte.d.ts +1 -1
- package/dist/elements/dropdown/Select.svelte +143 -59
- package/dist/elements/dropdown/Select.svelte.d.ts +1 -1
- package/dist/elements/dropdown/dropdown.d.ts +34 -57
- package/dist/elements/dropdown/dropdown.js +10 -4
- package/dist/elements/dropdown/select.d.ts +34 -54
- package/dist/elements/dropdown/select.js +22 -14
- package/dist/elements/file-upload/FileUpload.svelte +130 -0
- package/dist/elements/file-upload/FileUpload.svelte.d.ts +4 -0
- package/dist/elements/file-upload/FilesPreview.svelte +93 -0
- package/dist/elements/file-upload/FilesPreview.svelte.d.ts +4 -0
- package/dist/elements/progress/Progress.svelte +145 -0
- package/dist/elements/progress/Progress.svelte.d.ts +4 -0
- package/dist/elements/timeline/Timeline.svelte +92 -0
- package/dist/elements/timeline/Timeline.svelte.d.ts +7 -0
- package/dist/forms/Checkbox.svelte +54 -0
- package/dist/forms/Checkbox.svelte.d.ts +4 -0
- package/dist/forms/DateRange.svelte +493 -0
- package/dist/forms/DateRange.svelte.d.ts +4 -0
- package/dist/forms/Form.svelte +39 -0
- package/dist/forms/Form.svelte.d.ts +4 -0
- package/dist/forms/Input.svelte +86 -0
- package/dist/forms/Input.svelte.d.ts +4 -0
- package/dist/forms/NumberInput.svelte +159 -0
- package/dist/forms/NumberInput.svelte.d.ts +4 -0
- package/dist/forms/RadioInputs.svelte +64 -0
- package/dist/forms/RadioInputs.svelte.d.ts +4 -0
- package/dist/forms/RadioPill.svelte +66 -0
- package/dist/forms/RadioPill.svelte.d.ts +4 -0
- package/dist/forms/Slider.svelte +342 -0
- package/dist/forms/Slider.svelte.d.ts +4 -0
- package/dist/forms/Tags.svelte +181 -0
- package/dist/forms/Tags.svelte.d.ts +4 -0
- package/dist/forms/Toggle.svelte +132 -0
- package/dist/forms/Toggle.svelte.d.ts +4 -0
- package/dist/forms/slider.d.ts +143 -0
- package/dist/forms/slider.js +62 -0
- package/dist/header/Breadcrumbs.svelte +2 -1
- package/dist/header/Breadcrumbs.svelte.d.ts +1 -1
- package/dist/header/PageHeader.svelte +2 -2
- package/dist/header/PageHeader.svelte.d.ts +1 -1
- package/dist/header/breadcrumbs.d.ts +20 -14
- package/dist/header/breadcrumbs.js +6 -0
- package/dist/helper/date.d.ts +7 -0
- package/dist/helper/date.js +15 -0
- package/dist/index.d.ts +762 -9
- package/dist/index.js +70 -16
- package/dist/layout/card/Card.svelte +5 -8
- package/dist/layout/card/Card.svelte.d.ts +1 -1
- package/dist/layout/card/StatsCard.svelte +119 -89
- package/dist/layout/card/StatsCard.svelte.d.ts +1 -1
- package/dist/layout/card/card.d.ts +22 -33
- package/dist/layout/card/card.js +9 -8
- package/dist/layout/card/stats-card.d.ts +22 -39
- package/dist/layout/card/stats-card.js +14 -14
- package/dist/layout/navbar/navbar.d.ts +0 -23
- package/dist/layout/sidebar/NavGroup.svelte +38 -48
- package/dist/layout/sidebar/NavGroup.svelte.d.ts +1 -1
- package/dist/layout/sidebar/NavItem.svelte +3 -3
- package/dist/layout/sidebar/NavItem.svelte.d.ts +1 -1
- package/dist/layout/sidebar/Sidebar.svelte +101 -72
- package/dist/layout/sidebar/Sidebar.svelte.d.ts +1 -1
- package/dist/layout/table/Table.svelte +2 -2
- package/dist/layout/table/Table.svelte.d.ts +1 -1
- package/dist/layout/table/table.d.ts +1 -20
- package/dist/layout/table/table.js +0 -8
- package/dist/layout/tabs/TabGroup.svelte +2 -2
- package/dist/layout/tabs/TabGroup.svelte.d.ts +2 -2
- package/dist/layout/tabs/tabs.d.ts +2 -2
- package/dist/modal/Modal.svelte +2 -1
- package/dist/modal/Modal.svelte.d.ts +1 -1
- package/dist/modal/modal.d.ts +0 -23
- package/dist/modal/modal.js +3 -3
- package/dist/sonner/sonner.svelte +13 -0
- package/dist/sonner/sonner.svelte.d.ts +4 -0
- package/dist/types/variants.d.ts +1 -21
- package/dist/types/variants.js +1 -19
- package/dist/variants.d.ts +30 -0
- package/dist/variants.js +36 -0
- package/package.json +7 -3
- package/dist/button/index.d.ts +0 -1
- package/dist/button/index.js +0 -1
- package/dist/drawer/index.d.ts +0 -2
- package/dist/drawer/index.js +0 -1
- package/dist/elements/badge/index.d.ts +0 -2
- package/dist/elements/badge/index.js +0 -2
- package/dist/elements/dropdown/index.d.ts +0 -3
- package/dist/elements/dropdown/index.js +0 -2
- package/dist/header/index.d.ts +0 -4
- package/dist/header/index.js +0 -2
- package/dist/header/pageheaders.d.ts +0 -10
- package/dist/header/pageheaders.js +0 -1
- package/dist/layout/card/index.d.ts +0 -4
- package/dist/layout/card/index.js +0 -2
- package/dist/layout/index.d.ts +0 -7
- package/dist/layout/index.js +0 -7
- package/dist/layout/navbar/index.d.ts +0 -2
- package/dist/layout/navbar/index.js +0 -2
- package/dist/layout/sidebar/index.d.ts +0 -2
- package/dist/layout/sidebar/index.js +0 -1
- package/dist/layout/sidebar/sidebar.d.ts +0 -46
- package/dist/layout/sidebar/sidebar.js +0 -1
- package/dist/layout/table/index.d.ts +0 -3
- package/dist/layout/table/index.js +0 -2
- package/dist/layout/tabs/index.d.ts +0 -3
- package/dist/layout/tabs/index.js +0 -3
- package/dist/modal/index.d.ts +0 -1
- package/dist/modal/index.js +0 -1
|
@@ -1,44 +1,42 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { VariantSizes } from '../../types/variants.js';
|
|
3
|
-
import type { Component, Snippet } from 'svelte';
|
|
1
|
+
import { Size } from '../../variants.js';
|
|
4
2
|
export declare const selectTV: import("tailwind-variants").TVReturnType<{
|
|
5
3
|
size: {
|
|
6
|
-
|
|
4
|
+
[Size.XS]: {
|
|
7
5
|
trigger: string;
|
|
8
6
|
triggerIcon: string;
|
|
9
7
|
container: string;
|
|
10
8
|
item: string;
|
|
11
9
|
base: string;
|
|
12
10
|
};
|
|
13
|
-
|
|
11
|
+
[Size.SM]: {
|
|
14
12
|
trigger: string;
|
|
15
13
|
triggerIcon: string;
|
|
16
14
|
container: string;
|
|
17
15
|
item: string;
|
|
18
16
|
base: string;
|
|
19
17
|
};
|
|
20
|
-
|
|
18
|
+
[Size.BASE]: {
|
|
21
19
|
trigger: string;
|
|
22
20
|
triggerIcon: string;
|
|
23
21
|
container: string;
|
|
24
22
|
item: string;
|
|
25
23
|
base: string;
|
|
26
24
|
};
|
|
27
|
-
|
|
25
|
+
[Size.LG]: {
|
|
28
26
|
trigger: string;
|
|
29
27
|
triggerIcon: string;
|
|
30
28
|
container: string;
|
|
31
29
|
item: string;
|
|
32
30
|
base: string;
|
|
33
31
|
};
|
|
34
|
-
|
|
32
|
+
[Size.XL]: {
|
|
35
33
|
trigger: string;
|
|
36
34
|
triggerIcon: string;
|
|
37
35
|
container: string;
|
|
38
36
|
item: string;
|
|
39
37
|
base: string;
|
|
40
38
|
};
|
|
41
|
-
|
|
39
|
+
[Size.XXL]: {
|
|
42
40
|
trigger: string;
|
|
43
41
|
triggerIcon: string;
|
|
44
42
|
container: string;
|
|
@@ -53,6 +51,11 @@ export declare const selectTV: import("tailwind-variants").TVReturnType<{
|
|
|
53
51
|
item: string;
|
|
54
52
|
};
|
|
55
53
|
};
|
|
54
|
+
multiple: {
|
|
55
|
+
true: {
|
|
56
|
+
trigger: string;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
56
59
|
}, {
|
|
57
60
|
base: string;
|
|
58
61
|
trigger: string;
|
|
@@ -64,42 +67,42 @@ export declare const selectTV: import("tailwind-variants").TVReturnType<{
|
|
|
64
67
|
emptyMessage: string;
|
|
65
68
|
}, undefined, {
|
|
66
69
|
size: {
|
|
67
|
-
|
|
70
|
+
[Size.XS]: {
|
|
68
71
|
trigger: string;
|
|
69
72
|
triggerIcon: string;
|
|
70
73
|
container: string;
|
|
71
74
|
item: string;
|
|
72
75
|
base: string;
|
|
73
76
|
};
|
|
74
|
-
|
|
77
|
+
[Size.SM]: {
|
|
75
78
|
trigger: string;
|
|
76
79
|
triggerIcon: string;
|
|
77
80
|
container: string;
|
|
78
81
|
item: string;
|
|
79
82
|
base: string;
|
|
80
83
|
};
|
|
81
|
-
|
|
84
|
+
[Size.BASE]: {
|
|
82
85
|
trigger: string;
|
|
83
86
|
triggerIcon: string;
|
|
84
87
|
container: string;
|
|
85
88
|
item: string;
|
|
86
89
|
base: string;
|
|
87
90
|
};
|
|
88
|
-
|
|
91
|
+
[Size.LG]: {
|
|
89
92
|
trigger: string;
|
|
90
93
|
triggerIcon: string;
|
|
91
94
|
container: string;
|
|
92
95
|
item: string;
|
|
93
96
|
base: string;
|
|
94
97
|
};
|
|
95
|
-
|
|
98
|
+
[Size.XL]: {
|
|
96
99
|
trigger: string;
|
|
97
100
|
triggerIcon: string;
|
|
98
101
|
container: string;
|
|
99
102
|
item: string;
|
|
100
103
|
base: string;
|
|
101
104
|
};
|
|
102
|
-
|
|
105
|
+
[Size.XXL]: {
|
|
103
106
|
trigger: string;
|
|
104
107
|
triggerIcon: string;
|
|
105
108
|
container: string;
|
|
@@ -114,6 +117,11 @@ export declare const selectTV: import("tailwind-variants").TVReturnType<{
|
|
|
114
117
|
item: string;
|
|
115
118
|
};
|
|
116
119
|
};
|
|
120
|
+
multiple: {
|
|
121
|
+
true: {
|
|
122
|
+
trigger: string;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
117
125
|
}, {
|
|
118
126
|
base: string;
|
|
119
127
|
trigger: string;
|
|
@@ -125,42 +133,42 @@ export declare const selectTV: import("tailwind-variants").TVReturnType<{
|
|
|
125
133
|
emptyMessage: string;
|
|
126
134
|
}, import("tailwind-variants").TVReturnType<{
|
|
127
135
|
size: {
|
|
128
|
-
|
|
136
|
+
[Size.XS]: {
|
|
129
137
|
trigger: string;
|
|
130
138
|
triggerIcon: string;
|
|
131
139
|
container: string;
|
|
132
140
|
item: string;
|
|
133
141
|
base: string;
|
|
134
142
|
};
|
|
135
|
-
|
|
143
|
+
[Size.SM]: {
|
|
136
144
|
trigger: string;
|
|
137
145
|
triggerIcon: string;
|
|
138
146
|
container: string;
|
|
139
147
|
item: string;
|
|
140
148
|
base: string;
|
|
141
149
|
};
|
|
142
|
-
|
|
150
|
+
[Size.BASE]: {
|
|
143
151
|
trigger: string;
|
|
144
152
|
triggerIcon: string;
|
|
145
153
|
container: string;
|
|
146
154
|
item: string;
|
|
147
155
|
base: string;
|
|
148
156
|
};
|
|
149
|
-
|
|
157
|
+
[Size.LG]: {
|
|
150
158
|
trigger: string;
|
|
151
159
|
triggerIcon: string;
|
|
152
160
|
container: string;
|
|
153
161
|
item: string;
|
|
154
162
|
base: string;
|
|
155
163
|
};
|
|
156
|
-
|
|
164
|
+
[Size.XL]: {
|
|
157
165
|
trigger: string;
|
|
158
166
|
triggerIcon: string;
|
|
159
167
|
container: string;
|
|
160
168
|
item: string;
|
|
161
169
|
base: string;
|
|
162
170
|
};
|
|
163
|
-
|
|
171
|
+
[Size.XXL]: {
|
|
164
172
|
trigger: string;
|
|
165
173
|
triggerIcon: string;
|
|
166
174
|
container: string;
|
|
@@ -175,6 +183,11 @@ export declare const selectTV: import("tailwind-variants").TVReturnType<{
|
|
|
175
183
|
item: string;
|
|
176
184
|
};
|
|
177
185
|
};
|
|
186
|
+
multiple: {
|
|
187
|
+
true: {
|
|
188
|
+
trigger: string;
|
|
189
|
+
};
|
|
190
|
+
};
|
|
178
191
|
}, {
|
|
179
192
|
base: string;
|
|
180
193
|
trigger: string;
|
|
@@ -185,36 +198,3 @@ export declare const selectTV: import("tailwind-variants").TVReturnType<{
|
|
|
185
198
|
item: string;
|
|
186
199
|
emptyMessage: string;
|
|
187
200
|
}, undefined, unknown, unknown, undefined>>;
|
|
188
|
-
export type SelectItem = {
|
|
189
|
-
label: string;
|
|
190
|
-
value: string;
|
|
191
|
-
disabled?: boolean;
|
|
192
|
-
icon?: Component;
|
|
193
|
-
};
|
|
194
|
-
export type SelectProps = {
|
|
195
|
-
items: SelectItem[];
|
|
196
|
-
value?: string;
|
|
197
|
-
placeholder?: string;
|
|
198
|
-
searchable?: boolean;
|
|
199
|
-
disabled?: boolean;
|
|
200
|
-
size?: VariantSizes;
|
|
201
|
-
class?: ClassValue;
|
|
202
|
-
triggerClass?: ClassValue;
|
|
203
|
-
containerClass?: ClassValue;
|
|
204
|
-
listClass?: ClassValue;
|
|
205
|
-
itemClass?: ClassValue;
|
|
206
|
-
searchInputClass?: ClassValue;
|
|
207
|
-
emptyMessageText?: string;
|
|
208
|
-
clearable?: boolean;
|
|
209
|
-
icon?: Component;
|
|
210
|
-
iconClass?: ClassValue;
|
|
211
|
-
triggerContent?: Snippet<[{
|
|
212
|
-
selectedItem?: SelectItem;
|
|
213
|
-
open: boolean;
|
|
214
|
-
}]>;
|
|
215
|
-
onselect?: ({ value }: {
|
|
216
|
-
value?: string;
|
|
217
|
-
}) => void;
|
|
218
|
-
onopen?: () => void;
|
|
219
|
-
onclose?: () => void;
|
|
220
|
-
};
|
|
@@ -1,57 +1,59 @@
|
|
|
1
1
|
import { tv } from 'tailwind-variants';
|
|
2
|
+
import { Size } from '../../variants.js';
|
|
2
3
|
export const selectTV = tv({
|
|
3
4
|
slots: {
|
|
4
5
|
base: 'relative inline-block',
|
|
5
|
-
trigger: `flex items-center justify-between w-full text-left
|
|
6
|
+
trigger: `flex items-center justify-between w-full text-left bg-white border
|
|
6
7
|
border-default-200 text-default-700 hover:border-default-300 rounded-md cursor-pointer`,
|
|
7
8
|
triggerIcon: 'transition-transform duration-200 text-default-500',
|
|
8
9
|
container: 'absolute z-50 w-full mt-1 bg-white overflow-clip border border-default-200 rounded-md shadow-md',
|
|
9
|
-
searchInput: 'w-full outline-none px-2
|
|
10
|
-
list: 'py-1 max-h-60 overflow-auto h-full',
|
|
11
|
-
item: `w-full px-3 py-2 text-sm text-left
|
|
12
|
-
data-[
|
|
13
|
-
data-[selected=true]:
|
|
14
|
-
data-[highlighted=true]:bg-
|
|
10
|
+
searchInput: 'flex items-center gap-x-3 w-full outline-none px-2 h-10 border-b border-b-default-200',
|
|
11
|
+
list: 'py-1 max-h-60 overflow-x-clip overflow-y-auto h-full',
|
|
12
|
+
item: `w-full px-3 py-2 text-sm text-left
|
|
13
|
+
data-[highlighted=true]:bg-default-100 data-[highlighted=true]:text-default-700
|
|
14
|
+
data-[selected=true]:bg-info-100 data-[selected=true]:text-info-500 data-[selected=true]:font-medium
|
|
15
|
+
data-[selected=true]:data-[highlighted=true]:bg-info-200 data-[selected=true]:data-[highlighted=true]:text-info-500
|
|
16
|
+
cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed`,
|
|
15
17
|
emptyMessage: 'px-3 py-2 text-sm text-default-500'
|
|
16
18
|
},
|
|
17
19
|
variants: {
|
|
18
20
|
size: {
|
|
19
|
-
|
|
21
|
+
[Size.XS]: {
|
|
20
22
|
trigger: 'h-6 px-2 py-1 text-xs gap-1',
|
|
21
23
|
triggerIcon: 'h-3 w-3',
|
|
22
24
|
container: 'max-h-40',
|
|
23
25
|
item: 'px-2 py-1 text-xs',
|
|
24
26
|
base: 'w-24'
|
|
25
27
|
},
|
|
26
|
-
|
|
28
|
+
[Size.SM]: {
|
|
27
29
|
trigger: 'h-8 px-2.5 py-1.5 text-xs gap-1.5',
|
|
28
30
|
triggerIcon: 'h-3.5 w-3.5',
|
|
29
31
|
container: 'max-h-48',
|
|
30
32
|
item: 'px-2.5 py-1.5 text-xs',
|
|
31
33
|
base: 'w-32'
|
|
32
34
|
},
|
|
33
|
-
|
|
35
|
+
[Size.BASE]: {
|
|
34
36
|
trigger: 'h-10 px-3 py-2 text-sm gap-2',
|
|
35
37
|
triggerIcon: 'h-4 w-4',
|
|
36
38
|
container: 'max-h-60',
|
|
37
39
|
item: 'px-3 py-2 text-sm',
|
|
38
40
|
base: 'w-40'
|
|
39
41
|
},
|
|
40
|
-
|
|
42
|
+
[Size.LG]: {
|
|
41
43
|
trigger: 'h-11 px-4 py-2.5 text-base gap-2.5',
|
|
42
44
|
triggerIcon: 'h-5 w-5',
|
|
43
45
|
container: 'max-h-72',
|
|
44
46
|
item: 'px-4 py-2.5 text-base',
|
|
45
47
|
base: 'w-48'
|
|
46
48
|
},
|
|
47
|
-
|
|
49
|
+
[Size.XL]: {
|
|
48
50
|
trigger: 'h-12 px-5 py-3 text-lg gap-3',
|
|
49
51
|
triggerIcon: 'h-6 w-6',
|
|
50
52
|
container: 'max-h-80',
|
|
51
53
|
item: 'px-5 py-3 text-lg',
|
|
52
54
|
base: 'w-56'
|
|
53
55
|
},
|
|
54
|
-
|
|
56
|
+
[Size.XXL]: {
|
|
55
57
|
trigger: 'h-14 px-6 py-3.5 text-xl gap-4',
|
|
56
58
|
triggerIcon: 'h-7 w-7',
|
|
57
59
|
container: 'max-h-96',
|
|
@@ -65,10 +67,16 @@ export const selectTV = tv({
|
|
|
65
67
|
container: 'pointer-events-none',
|
|
66
68
|
item: 'disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:bg-transparent'
|
|
67
69
|
}
|
|
70
|
+
},
|
|
71
|
+
multiple: {
|
|
72
|
+
true: {
|
|
73
|
+
trigger: 'flex-wrap min-h-[2.5rem]'
|
|
74
|
+
}
|
|
68
75
|
}
|
|
69
76
|
},
|
|
70
77
|
defaultVariants: {
|
|
71
78
|
size: 'base',
|
|
72
|
-
disabled: false
|
|
79
|
+
disabled: false,
|
|
80
|
+
multiple: false
|
|
73
81
|
}
|
|
74
82
|
});
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../../helper/cls.js';
|
|
3
|
+
import type { FileUploadProps } from '../../index.js';
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
allowedMimeTypes = [],
|
|
7
|
+
maxFiles = 10,
|
|
8
|
+
maxSize,
|
|
9
|
+
class: className = '',
|
|
10
|
+
dropzoneClass = '',
|
|
11
|
+
id = 'file-upload',
|
|
12
|
+
onfiles = undefined
|
|
13
|
+
}: FileUploadProps = $props();
|
|
14
|
+
|
|
15
|
+
const disabled = $derived(maxFiles <= 0);
|
|
16
|
+
|
|
17
|
+
let isDragging = $state(false);
|
|
18
|
+
let inputRef: HTMLInputElement;
|
|
19
|
+
|
|
20
|
+
function handleFiles(newFiles: FileList | File[]) {
|
|
21
|
+
if (disabled) return;
|
|
22
|
+
if (onfiles) onfiles(newFiles);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function handleDragEnter(e: DragEvent) {
|
|
26
|
+
e.preventDefault();
|
|
27
|
+
e.stopPropagation();
|
|
28
|
+
if (!disabled) isDragging = true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function handleDragLeave(e: DragEvent) {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
e.stopPropagation();
|
|
34
|
+
isDragging = false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function handleDrop(e: DragEvent) {
|
|
38
|
+
e.preventDefault();
|
|
39
|
+
e.stopPropagation();
|
|
40
|
+
isDragging = false;
|
|
41
|
+
if (!disabled && e.dataTransfer?.files) {
|
|
42
|
+
handleFiles(e.dataTransfer.files);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function handleInputChange(e: Event) {
|
|
47
|
+
const input = e.target as HTMLInputElement;
|
|
48
|
+
if (input.files) {
|
|
49
|
+
handleFiles(input.files);
|
|
50
|
+
input.value = '';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function handleDragOver(e: DragEvent) {
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
e.stopPropagation();
|
|
57
|
+
if (!disabled) isDragging = true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function formatFileSize(bytes: number): string {
|
|
61
|
+
if (bytes === 0) return '0 B';
|
|
62
|
+
const k = 1024;
|
|
63
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
64
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
65
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))}${sizes[i]}`;
|
|
66
|
+
}
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<div class={cn('w-full', className)}>
|
|
70
|
+
<label
|
|
71
|
+
class={cn(
|
|
72
|
+
'group relative block rounded-[32px] border-2 border-dashed p-12 text-center transition-colors',
|
|
73
|
+
{
|
|
74
|
+
'border-primary-400 bg-primary-50': isDragging,
|
|
75
|
+
'border-default-200 bg-white': !isDragging,
|
|
76
|
+
'cursor-not-allowed opacity-50': disabled,
|
|
77
|
+
'hover:bg-default-50 cursor-pointer': !disabled
|
|
78
|
+
},
|
|
79
|
+
dropzoneClass
|
|
80
|
+
)}
|
|
81
|
+
ondragenter={handleDragEnter}
|
|
82
|
+
ondragleave={handleDragLeave}
|
|
83
|
+
ondragover={handleDragOver}
|
|
84
|
+
ondrop={handleDrop}
|
|
85
|
+
for={id}
|
|
86
|
+
>
|
|
87
|
+
<input
|
|
88
|
+
type="file"
|
|
89
|
+
bind:this={inputRef}
|
|
90
|
+
accept={allowedMimeTypes.join(',')}
|
|
91
|
+
multiple={maxFiles !== 1}
|
|
92
|
+
{disabled}
|
|
93
|
+
class="hidden"
|
|
94
|
+
onchange={handleInputChange}
|
|
95
|
+
{id}
|
|
96
|
+
/>
|
|
97
|
+
|
|
98
|
+
<div class="flex flex-col items-center gap-4">
|
|
99
|
+
<!-- Upload Icon -->
|
|
100
|
+
<div class="bg-primary-100 mb-2 flex size-24 items-center justify-center rounded-full">
|
|
101
|
+
<svg
|
|
102
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
103
|
+
class="text-primary-500 size-12"
|
|
104
|
+
viewBox="0 0 24 24"
|
|
105
|
+
>
|
|
106
|
+
<path
|
|
107
|
+
fill="currentColor"
|
|
108
|
+
d="M11 14.2V6.8l-3.7 3.7L6 9l6-6l6 6l-1.3 1.4L13 6.8v7.4zm-5 4.3h12v2H6z"
|
|
109
|
+
/>
|
|
110
|
+
</svg>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<!-- Upload Text -->
|
|
114
|
+
<div class="text-sm">
|
|
115
|
+
<span class="text-primary-500 font-medium">Click here</span>
|
|
116
|
+
<span class="text-default-600"> to upload your file or drag and drop.</span>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<!-- File Type Info -->
|
|
120
|
+
<div class="text-default-500 text-xs">
|
|
121
|
+
Supported Format: {allowedMimeTypes.length ? allowedMimeTypes.join(', ') : 'SVG, JPG, PNG'}
|
|
122
|
+
{#if maxSize}
|
|
123
|
+
({formatFileSize(maxSize)} each)
|
|
124
|
+
{:else}
|
|
125
|
+
(10MB each)
|
|
126
|
+
{/if}
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
</label>
|
|
130
|
+
</div>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../../helper/cls.js';
|
|
3
|
+
import type { FilePreviewProps } from '../../index.js';
|
|
4
|
+
|
|
5
|
+
let { files = [], ondelete, class: className = '' }: FilePreviewProps = $props();
|
|
6
|
+
|
|
7
|
+
function formatFileSize(bytes: number): string {
|
|
8
|
+
if (bytes === 0) return '0 B';
|
|
9
|
+
const k = 1024;
|
|
10
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
11
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
12
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))}${sizes[i]}`;
|
|
13
|
+
}
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
{#if files.length > 0}
|
|
17
|
+
<ul class={cn('mt-6 space-y-3', className)}>
|
|
18
|
+
{#each files as file, i (i)}
|
|
19
|
+
<li
|
|
20
|
+
class={cn('flex items-center justify-between rounded-xl p-4 ring-4', {
|
|
21
|
+
'bg-danger-50 ring-danger-100': file.status === 'error',
|
|
22
|
+
'bg-success-50 ring-success-100': file.status === 'success',
|
|
23
|
+
'ring-primary-100/30 bg-white': file.status === 'uploading'
|
|
24
|
+
})}
|
|
25
|
+
>
|
|
26
|
+
<div class="flex flex-1 items-center gap-3">
|
|
27
|
+
<!-- File Icon -->
|
|
28
|
+
<div
|
|
29
|
+
class={cn('flex size-10 items-center justify-center rounded-full', {
|
|
30
|
+
'bg-danger-100 text-danger-500': file.status === 'error',
|
|
31
|
+
'bg-success-100 text-success-500': file.status === 'success',
|
|
32
|
+
'bg-primary-100 text-primary-500': file.status === 'uploading'
|
|
33
|
+
})}
|
|
34
|
+
>
|
|
35
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24">
|
|
36
|
+
<path
|
|
37
|
+
fill="currentColor"
|
|
38
|
+
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"
|
|
39
|
+
/>
|
|
40
|
+
</svg>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div class="flex-1">
|
|
44
|
+
<!-- Filename and Size -->
|
|
45
|
+
<div class="mb-1 flex items-center justify-between">
|
|
46
|
+
<span class="text-default-700 font-medium">{file.OriginalFilename}</span>
|
|
47
|
+
<span class="text-default-500 text-sm">{formatFileSize(file.Size)}</span>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<!-- Status Information -->
|
|
51
|
+
{#if file.status === 'uploading'}
|
|
52
|
+
<div class="bg-default-100 h-1.5 w-full rounded-full">
|
|
53
|
+
<div
|
|
54
|
+
class="bg-primary-500 h-1.5 rounded-full transition-all duration-300"
|
|
55
|
+
style="width: {file.progress || 0}%"
|
|
56
|
+
></div>
|
|
57
|
+
</div>
|
|
58
|
+
<span class="text-default-500 mt-1 text-sm">{file.progress || 0}%</span>
|
|
59
|
+
{:else if file.status === 'error'}
|
|
60
|
+
<div class="flex items-center justify-between">
|
|
61
|
+
<span class="text-danger-500 text-sm">Upload failed!</span>
|
|
62
|
+
<span class="text-danger-600 cursor-help text-sm font-medium"
|
|
63
|
+
>Please try again!</span
|
|
64
|
+
>
|
|
65
|
+
</div>
|
|
66
|
+
{:else if file.status === 'success'}
|
|
67
|
+
<p class="text-success-500 text-sm">Upload Successful!</p>
|
|
68
|
+
{/if}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<button
|
|
73
|
+
type="button"
|
|
74
|
+
aria-label="Delete file"
|
|
75
|
+
class={cn('ml-4 flex size-6 cursor-pointer items-center justify-center rounded-lg', {
|
|
76
|
+
'bg-danger-100 text-danger-500': file.status === 'error',
|
|
77
|
+
'bg-success-100 text-success-500': file.status === 'success',
|
|
78
|
+
'bg-default-100 text-default-500': file.status === 'uploading'
|
|
79
|
+
})}
|
|
80
|
+
onclick={() => (file.FileID ? ondelete?.(file.FileID, i) : ondelete?.('', i))}
|
|
81
|
+
disabled={file.status === 'uploading'}
|
|
82
|
+
>
|
|
83
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 24 24">
|
|
84
|
+
<path
|
|
85
|
+
fill="currentColor"
|
|
86
|
+
d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41z"
|
|
87
|
+
/>
|
|
88
|
+
</svg>
|
|
89
|
+
</button>
|
|
90
|
+
</li>
|
|
91
|
+
{/each}
|
|
92
|
+
</ul>
|
|
93
|
+
{/if}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { cn } from '../../helper/cls.js';
|
|
3
|
+
import { Color, Size } from '../../variants.js';
|
|
4
|
+
import type { ProgressProps, ProgressSegment, VariantColors } from '../../index.js';
|
|
5
|
+
|
|
6
|
+
let {
|
|
7
|
+
value,
|
|
8
|
+
max = 100,
|
|
9
|
+
size = Size.BASE,
|
|
10
|
+
color = Color.PRIMARY,
|
|
11
|
+
showLabel = true,
|
|
12
|
+
labelPosition = 'right',
|
|
13
|
+
segments = undefined,
|
|
14
|
+
showValues = false,
|
|
15
|
+
showLabels = false,
|
|
16
|
+
class: className = '',
|
|
17
|
+
labelClass = '',
|
|
18
|
+
barClass = ''
|
|
19
|
+
}: ProgressProps = $props();
|
|
20
|
+
|
|
21
|
+
// Function composition for better readability and maintainability
|
|
22
|
+
function calculatePercentage(val: number, maximum: number): number {
|
|
23
|
+
return Math.min(Math.round((val / maximum) * 100), 100);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getColorClass(color: VariantColors): string {
|
|
27
|
+
const colorMap = {
|
|
28
|
+
[Color.PRIMARY]: 'bg-primary-600',
|
|
29
|
+
[Color.SECONDARY]: 'bg-secondary-600',
|
|
30
|
+
[Color.SUCCESS]: 'bg-success-600',
|
|
31
|
+
[Color.DANGER]: 'bg-danger-600',
|
|
32
|
+
[Color.WARNING]: 'bg-warning-600',
|
|
33
|
+
[Color.INFO]: 'bg-info-600',
|
|
34
|
+
[Color.DEFAULT]: 'bg-default-600'
|
|
35
|
+
};
|
|
36
|
+
return colorMap[color] || colorMap[Color.PRIMARY];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getSizeTextClass(size: string): string {
|
|
40
|
+
if (size === Size.XS || size === Size.SM) return 'text-xs';
|
|
41
|
+
if (size === Size.BASE) return 'text-sm';
|
|
42
|
+
return 'text-base'; // For Size.LG, Size.XL
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Derived values
|
|
46
|
+
const percentage = $derived(segments ? 100 : calculatePercentage(value, max));
|
|
47
|
+
const segmentPercentages = $derived(
|
|
48
|
+
segments?.map(segment => ({
|
|
49
|
+
...segment,
|
|
50
|
+
percentage: calculatePercentage(segment.value, max)
|
|
51
|
+
})) || []
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// Class compositions
|
|
55
|
+
const containerClass = $derived(
|
|
56
|
+
cn(
|
|
57
|
+
'relative',
|
|
58
|
+
{
|
|
59
|
+
'flex items-center': !segments,
|
|
60
|
+
'flex-col gap-1': !segments && (labelPosition === 'top' || labelPosition === 'bottom'),
|
|
61
|
+
'flex-row gap-3': !segments && labelPosition === 'right'
|
|
62
|
+
},
|
|
63
|
+
className
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const progressClass = $derived(
|
|
68
|
+
cn('w-full rounded-full bg-default-200', {
|
|
69
|
+
'h-1.5': size === Size.XS,
|
|
70
|
+
'h-2': size === Size.SM,
|
|
71
|
+
'h-2.5': size === Size.BASE,
|
|
72
|
+
'h-3': size === Size.LG,
|
|
73
|
+
'h-4': size === Size.XL,
|
|
74
|
+
'order-2': !segments && labelPosition === 'top',
|
|
75
|
+
'order-1': !segments && labelPosition === 'bottom',
|
|
76
|
+
'flex overflow-hidden': segments
|
|
77
|
+
})
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
const fillClass = $derived(
|
|
81
|
+
cn(
|
|
82
|
+
'h-full rounded-full transition-all',
|
|
83
|
+
segments ? '' : getColorClass(color),
|
|
84
|
+
barClass
|
|
85
|
+
)
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const labelTextClass = $derived(
|
|
89
|
+
cn(
|
|
90
|
+
'text-default-500',
|
|
91
|
+
getSizeTextClass(size),
|
|
92
|
+
{
|
|
93
|
+
'order-1': !segments && labelPosition === 'top',
|
|
94
|
+
'order-2': !segments && labelPosition === 'bottom',
|
|
95
|
+
'mt-1': segments
|
|
96
|
+
},
|
|
97
|
+
labelClass
|
|
98
|
+
)
|
|
99
|
+
);
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<div class={containerClass}>
|
|
103
|
+
<div
|
|
104
|
+
class={progressClass}
|
|
105
|
+
role="progressbar"
|
|
106
|
+
aria-valuenow={percentage}
|
|
107
|
+
aria-valuemin="0"
|
|
108
|
+
aria-valuemax="100"
|
|
109
|
+
>
|
|
110
|
+
{#if segments}
|
|
111
|
+
{#each segmentPercentages as segment}
|
|
112
|
+
{#if segment.percentage > 0}
|
|
113
|
+
<div
|
|
114
|
+
class={cn(getColorClass(segment.color), barClass)}
|
|
115
|
+
style="width: {segment.percentage}%"
|
|
116
|
+
title={segment.label || `${segment.value} (${segment.percentage}%)`}
|
|
117
|
+
></div>
|
|
118
|
+
{/if}
|
|
119
|
+
{/each}
|
|
120
|
+
{:else}
|
|
121
|
+
<div class={fillClass} style="width: {percentage}%"></div>
|
|
122
|
+
{/if}
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
{#if segments && (showLabels || showValues)}
|
|
126
|
+
<div class="flex justify-between mt-1">
|
|
127
|
+
{#each segmentPercentages as segment}
|
|
128
|
+
{#if segment.percentage > 0}
|
|
129
|
+
<div class={labelTextClass}>
|
|
130
|
+
{#if showLabels && segment.label}
|
|
131
|
+
{segment.label}
|
|
132
|
+
{/if}
|
|
133
|
+
{#if showValues}
|
|
134
|
+
{#if showLabels && segment.label} ({/if}
|
|
135
|
+
{segment.percentage}%
|
|
136
|
+
{#if showLabels && segment.label}){/if}
|
|
137
|
+
{/if}
|
|
138
|
+
</div>
|
|
139
|
+
{/if}
|
|
140
|
+
{/each}
|
|
141
|
+
</div>
|
|
142
|
+
{:else if showLabel}
|
|
143
|
+
<span class={labelTextClass}>{percentage}%</span>
|
|
144
|
+
{/if}
|
|
145
|
+
</div>
|