@makolabs/ripple 0.0.1-dev.4 → 0.0.1-dev.41

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 (129) hide show
  1. package/README.md +394 -54
  2. package/dist/button/Button.svelte +5 -3
  3. package/dist/button/Button.svelte.d.ts +1 -1
  4. package/dist/button/button.d.ts +40 -63
  5. package/dist/button/button.js +15 -14
  6. package/dist/charts/Chart.svelte +545 -0
  7. package/dist/charts/Chart.svelte.d.ts +4 -0
  8. package/dist/drawer/Drawer.svelte +13 -2
  9. package/dist/drawer/Drawer.svelte.d.ts +1 -1
  10. package/dist/drawer/drawer.d.ts +0 -17
  11. package/dist/drawer/drawer.js +3 -3
  12. package/dist/elements/accordion/Accordion.svelte +83 -0
  13. package/dist/elements/accordion/Accordion.svelte.d.ts +4 -0
  14. package/dist/elements/accordion/accordion.d.ts +200 -0
  15. package/dist/elements/accordion/accordion.js +86 -0
  16. package/dist/elements/alert/Alert.svelte +57 -0
  17. package/dist/elements/alert/Alert.svelte.d.ts +4 -0
  18. package/dist/elements/badge/Badge.svelte +13 -5
  19. package/dist/elements/badge/Badge.svelte.d.ts +1 -1
  20. package/dist/elements/badge/badge.d.ts +0 -12
  21. package/dist/elements/dropdown/Dropdown.svelte +32 -37
  22. package/dist/elements/dropdown/Dropdown.svelte.d.ts +1 -1
  23. package/dist/elements/dropdown/Select.svelte +143 -59
  24. package/dist/elements/dropdown/Select.svelte.d.ts +1 -1
  25. package/dist/elements/dropdown/dropdown.d.ts +34 -57
  26. package/dist/elements/dropdown/dropdown.js +10 -4
  27. package/dist/elements/dropdown/select.d.ts +34 -54
  28. package/dist/elements/dropdown/select.js +22 -14
  29. package/dist/elements/file-upload/FileUpload.svelte +130 -0
  30. package/dist/elements/file-upload/FileUpload.svelte.d.ts +4 -0
  31. package/dist/elements/file-upload/FilesPreview.svelte +93 -0
  32. package/dist/elements/file-upload/FilesPreview.svelte.d.ts +4 -0
  33. package/dist/elements/progress/Progress.svelte +145 -0
  34. package/dist/elements/progress/Progress.svelte.d.ts +4 -0
  35. package/dist/elements/timeline/Timeline.svelte +92 -0
  36. package/dist/elements/timeline/Timeline.svelte.d.ts +7 -0
  37. package/dist/forms/Checkbox.svelte +54 -0
  38. package/dist/forms/Checkbox.svelte.d.ts +4 -0
  39. package/dist/forms/DateRange.svelte +493 -0
  40. package/dist/forms/DateRange.svelte.d.ts +4 -0
  41. package/dist/forms/Form.svelte +39 -0
  42. package/dist/forms/Form.svelte.d.ts +4 -0
  43. package/dist/forms/Input.svelte +86 -0
  44. package/dist/forms/Input.svelte.d.ts +4 -0
  45. package/dist/forms/NumberInput.svelte +159 -0
  46. package/dist/forms/NumberInput.svelte.d.ts +4 -0
  47. package/dist/forms/RadioInputs.svelte +64 -0
  48. package/dist/forms/RadioInputs.svelte.d.ts +4 -0
  49. package/dist/forms/RadioPill.svelte +66 -0
  50. package/dist/forms/RadioPill.svelte.d.ts +4 -0
  51. package/dist/forms/Slider.svelte +342 -0
  52. package/dist/forms/Slider.svelte.d.ts +4 -0
  53. package/dist/forms/Tags.svelte +181 -0
  54. package/dist/forms/Tags.svelte.d.ts +4 -0
  55. package/dist/forms/Toggle.svelte +132 -0
  56. package/dist/forms/Toggle.svelte.d.ts +4 -0
  57. package/dist/forms/slider.d.ts +143 -0
  58. package/dist/forms/slider.js +62 -0
  59. package/dist/header/Breadcrumbs.svelte +2 -1
  60. package/dist/header/Breadcrumbs.svelte.d.ts +1 -1
  61. package/dist/header/PageHeader.svelte +2 -2
  62. package/dist/header/PageHeader.svelte.d.ts +1 -1
  63. package/dist/header/breadcrumbs.d.ts +20 -14
  64. package/dist/header/breadcrumbs.js +6 -0
  65. package/dist/helper/date.d.ts +7 -0
  66. package/dist/helper/date.js +15 -0
  67. package/dist/index.d.ts +762 -9
  68. package/dist/index.js +70 -16
  69. package/dist/layout/card/Card.svelte +5 -8
  70. package/dist/layout/card/Card.svelte.d.ts +1 -1
  71. package/dist/layout/card/StatsCard.svelte +119 -89
  72. package/dist/layout/card/StatsCard.svelte.d.ts +1 -1
  73. package/dist/layout/card/card.d.ts +22 -33
  74. package/dist/layout/card/card.js +9 -8
  75. package/dist/layout/card/stats-card.d.ts +22 -39
  76. package/dist/layout/card/stats-card.js +14 -14
  77. package/dist/layout/navbar/navbar.d.ts +0 -23
  78. package/dist/layout/sidebar/NavGroup.svelte +38 -48
  79. package/dist/layout/sidebar/NavGroup.svelte.d.ts +1 -1
  80. package/dist/layout/sidebar/NavItem.svelte +3 -3
  81. package/dist/layout/sidebar/NavItem.svelte.d.ts +1 -1
  82. package/dist/layout/sidebar/Sidebar.svelte +101 -72
  83. package/dist/layout/sidebar/Sidebar.svelte.d.ts +1 -1
  84. package/dist/layout/table/Table.svelte +2 -2
  85. package/dist/layout/table/Table.svelte.d.ts +1 -1
  86. package/dist/layout/table/table.d.ts +1 -20
  87. package/dist/layout/table/table.js +0 -8
  88. package/dist/layout/tabs/TabGroup.svelte +2 -2
  89. package/dist/layout/tabs/TabGroup.svelte.d.ts +2 -2
  90. package/dist/layout/tabs/tabs.d.ts +2 -2
  91. package/dist/modal/Modal.svelte +2 -1
  92. package/dist/modal/Modal.svelte.d.ts +1 -1
  93. package/dist/modal/modal.d.ts +0 -23
  94. package/dist/modal/modal.js +3 -3
  95. package/dist/sonner/sonner.svelte +13 -0
  96. package/dist/sonner/sonner.svelte.d.ts +4 -0
  97. package/dist/types/variants.d.ts +1 -21
  98. package/dist/types/variants.js +1 -19
  99. package/dist/variants.d.ts +30 -0
  100. package/dist/variants.js +36 -0
  101. package/package.json +7 -3
  102. package/dist/button/index.d.ts +0 -1
  103. package/dist/button/index.js +0 -1
  104. package/dist/drawer/index.d.ts +0 -2
  105. package/dist/drawer/index.js +0 -1
  106. package/dist/elements/badge/index.d.ts +0 -2
  107. package/dist/elements/badge/index.js +0 -2
  108. package/dist/elements/dropdown/index.d.ts +0 -3
  109. package/dist/elements/dropdown/index.js +0 -2
  110. package/dist/header/index.d.ts +0 -4
  111. package/dist/header/index.js +0 -2
  112. package/dist/header/pageheaders.d.ts +0 -10
  113. package/dist/header/pageheaders.js +0 -1
  114. package/dist/layout/card/index.d.ts +0 -4
  115. package/dist/layout/card/index.js +0 -2
  116. package/dist/layout/index.d.ts +0 -7
  117. package/dist/layout/index.js +0 -7
  118. package/dist/layout/navbar/index.d.ts +0 -2
  119. package/dist/layout/navbar/index.js +0 -2
  120. package/dist/layout/sidebar/index.d.ts +0 -2
  121. package/dist/layout/sidebar/index.js +0 -1
  122. package/dist/layout/sidebar/sidebar.d.ts +0 -46
  123. package/dist/layout/sidebar/sidebar.js +0 -1
  124. package/dist/layout/table/index.d.ts +0 -3
  125. package/dist/layout/table/index.js +0 -2
  126. package/dist/layout/tabs/index.d.ts +0 -3
  127. package/dist/layout/tabs/index.js +0 -3
  128. package/dist/modal/index.d.ts +0 -1
  129. package/dist/modal/index.js +0 -1
@@ -1,44 +1,42 @@
1
- import type { ClassValue } from 'tailwind-variants';
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
- xs: {
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
- sm: {
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
- base: {
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
- lg: {
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
- xl: {
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
- '2xl': {
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
- xs: {
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
- sm: {
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
- base: {
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
- lg: {
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
- xl: {
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
- '2xl': {
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
- xs: {
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
- sm: {
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
- base: {
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
- lg: {
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
- xl: {
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
- '2xl': {
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 focus:outline-none bg-white border
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 py-1.5 text-sm h-10 border-b border-b-default-200',
10
- list: 'py-1 max-h-60 overflow-auto h-full',
11
- item: `w-full px-3 py-2 text-sm text-left hover:bg-default-100 focus:bg-default-100
12
- data-[selected=true]:bg-info-100 data-[selected=true]:text-info-500 truncate
13
- data-[selected=true]:font-medium cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed
14
- data-[highlighted=true]:bg-default-100 data-[highlighted=true]:text-default-700`,
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
- xs: {
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
- sm: {
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
- base: {
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
- lg: {
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
- xl: {
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
- '2xl': {
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,4 @@
1
+ import type { FileUploadProps } from '../../index.js';
2
+ declare const FileUpload: import("svelte").Component<FileUploadProps, {}, "">;
3
+ type FileUpload = ReturnType<typeof FileUpload>;
4
+ export default FileUpload;
@@ -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,4 @@
1
+ import type { FilePreviewProps } from '../../index.js';
2
+ declare const FilesPreview: import("svelte").Component<FilePreviewProps, {}, "">;
3
+ type FilesPreview = ReturnType<typeof FilesPreview>;
4
+ export default FilesPreview;
@@ -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>
@@ -0,0 +1,4 @@
1
+ import type { ProgressProps } from '../../index.js';
2
+ declare const Progress: import("svelte").Component<ProgressProps, {}, "">;
3
+ type Progress = ReturnType<typeof Progress>;
4
+ export default Progress;