@makolabs/ripple 0.0.1-dev.21 → 0.0.1-dev.22

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.
@@ -8,11 +8,8 @@
8
8
  maxSize,
9
9
  class: className = '',
10
10
  dropzoneClass = '',
11
- previewClass = '',
12
11
  id = 'file-upload',
13
- onfiles = undefined,
14
- ondelete = undefined,
15
- files = []
12
+ onfiles = undefined
16
13
  }: FileUploadProps = $props();
17
14
 
18
15
  const disabled = $derived(maxFiles <= 0);
@@ -25,10 +22,6 @@
25
22
  if (onfiles) onfiles(newFiles);
26
23
  }
27
24
 
28
- function handleDeleteFile(fileId: string, index: number) {
29
- if (ondelete) ondelete(fileId, index);
30
- }
31
-
32
25
  function handleDragEnter(e: DragEvent) {
33
26
  e.preventDefault();
34
27
  e.stopPropagation();
@@ -130,84 +123,4 @@
130
123
  </div>
131
124
  </div>
132
125
  </label>
133
-
134
- <!-- File List -->
135
- {#if files.length > 0}
136
- <ul class={cn('mt-6 space-y-3', previewClass)}>
137
- {#each files as file, i (i)}
138
- <li
139
- class={cn('flex items-center justify-between rounded-xl p-4 ring-4', {
140
- 'bg-danger-50 ring-danger-100': file.status === 'error',
141
- 'bg-success-50 ring-success-100': file.status === 'success',
142
- 'ring-primary-100/30 bg-white': file.status === 'uploading'
143
- })}
144
- >
145
- <div class="flex flex-1 items-center gap-3">
146
- <!-- File Icon -->
147
- <div
148
- class={cn('flex size-10 items-center justify-center rounded-full', {
149
- 'bg-danger-100 text-danger-500': file.status === 'error',
150
- 'bg-success-100 text-success-500': file.status === 'success',
151
- 'bg-primary-100 text-primary-500': file.status === 'uploading'
152
- })}
153
- >
154
- <svg xmlns="http://www.w3.org/2000/svg" class="size-5" viewBox="0 0 24 24">
155
- <path
156
- fill="currentColor"
157
- d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"
158
- />
159
- </svg>
160
- </div>
161
-
162
- <div class="flex-1">
163
- <!-- Filename and Size -->
164
- <div class="mb-1 flex items-center justify-between">
165
- <span class="text-default-700 font-medium">{file.OriginalFilename}</span>
166
- <span class="text-default-500 text-sm">{formatFileSize(file.Size)}</span>
167
- </div>
168
-
169
- <!-- Status Information -->
170
- {#if file.status === 'uploading'}
171
- <div class="bg-default-100 h-1.5 w-full rounded-full">
172
- <div
173
- class="bg-primary-500 h-1.5 rounded-full transition-all duration-300"
174
- style="width: {file.progress || 0}%"
175
- ></div>
176
- </div>
177
- <span class="text-default-500 mt-1 text-sm">{file.progress || 0}%</span>
178
- {:else if file.status === 'error'}
179
- <div class="flex items-center justify-between">
180
- <span class="text-danger-500 text-sm">Upload failed!</span>
181
- <span class="text-danger-600 cursor-help text-sm font-medium"
182
- >Please try again!</span
183
- >
184
- </div>
185
- {:else if file.status === 'success'}
186
- <p class="text-success-500 text-sm">Upload Successful!</p>
187
- {/if}
188
- </div>
189
- </div>
190
-
191
- <button
192
- type="button"
193
- aria-label="Delete file"
194
- class={cn('ml-4 flex size-6 cursor-pointer items-center justify-center rounded-lg', {
195
- 'bg-danger-100 text-danger-500': file.status === 'error',
196
- 'bg-success-100 text-success-500': file.status === 'success',
197
- 'bg-default-100 text-default-500': file.status === 'uploading'
198
- })}
199
- onclick={() => (file.FileID ? handleDeleteFile(file.FileID, i) : ondelete?.('', i))}
200
- disabled={file.status === 'uploading'}
201
- >
202
- <svg xmlns="http://www.w3.org/2000/svg" class="size-4" viewBox="0 0 24 24">
203
- <path
204
- fill="currentColor"
205
- 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"
206
- />
207
- </svg>
208
- </button>
209
- </li>
210
- {/each}
211
- </ul>
212
- {/if}
213
126
  </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,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;
package/dist/index.d.ts CHANGED
@@ -517,6 +517,11 @@ export interface FileUploadProps {
517
517
  */
518
518
  metadata?: Record<string, string>;
519
519
  }
520
+ export interface FilePreviewProps {
521
+ files: UploadedFile[];
522
+ ondelete?: (fileId: string, index: number) => void;
523
+ class?: string;
524
+ }
520
525
  export interface UploadedFile {
521
526
  FileID: string;
522
527
  OriginalFilename: string;
@@ -540,6 +545,7 @@ export interface UploadedFile {
540
545
  error?: string;
541
546
  }
542
547
  export { default as FileUpload } from './elements/file-upload/FileUpload.svelte';
548
+ export { default as FilesPreview } from './elements/file-upload/FilesPreview.svelte';
543
549
  export { default as Toaster } from './sonner/sonner.svelte';
544
550
  export interface FormProps<T extends Record<string, unknown>> {
545
551
  form: SuperForm<any>;
package/dist/index.js CHANGED
@@ -48,6 +48,7 @@ export { selectTV } from './elements/dropdown/select.js';
48
48
  export { breadcrumbs } from './header/breadcrumbs.js';
49
49
  export { default as Chart } from './charts/Chart.svelte';
50
50
  export { default as FileUpload } from './elements/file-upload/FileUpload.svelte';
51
+ export { default as FilesPreview } from './elements/file-upload/FilesPreview.svelte';
51
52
  // Toaster: Should be registered in +layout.svelte
52
53
  export { default as Toaster } from './sonner/sonner.svelte';
53
54
  // Form Component Exports
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makolabs/ripple",
3
- "version": "0.0.1-dev.21",
3
+ "version": "0.0.1-dev.22",
4
4
  "description": "Simple Svelte 5 powered component library ✨",
5
5
  "repository": {
6
6
  "type": "git",