@makolabs/ripple 0.0.1-dev.20 → 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.
- package/dist/elements/file-upload/FileUpload.svelte +1 -88
- package/dist/elements/file-upload/FilesPreview.svelte +93 -0
- package/dist/elements/file-upload/FilesPreview.svelte.d.ts +4 -0
- package/dist/index.d.ts +41 -38
- package/dist/index.js +1 -0
- 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 +0 -19
- package/dist/layout/table/table.js +0 -8
- package/package.json +1 -1
|
@@ -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}
|
package/dist/index.d.ts
CHANGED
|
@@ -163,52 +163,49 @@ export type StatsCardProps = {
|
|
|
163
163
|
class?: ClassValue;
|
|
164
164
|
formatLargeNumbers?: boolean;
|
|
165
165
|
};
|
|
166
|
-
export type KeyType = string | number;
|
|
167
166
|
export type DataRow = Record<string, any>;
|
|
168
|
-
export type
|
|
169
|
-
export type
|
|
170
|
-
export type
|
|
171
|
-
|
|
172
|
-
direction: SortDirection;
|
|
173
|
-
};
|
|
174
|
-
export type TableColumn = {
|
|
175
|
-
key: string;
|
|
167
|
+
export type KeyType = keyof DataRow;
|
|
168
|
+
export type StatusType = 'active' | 'inactive' | 'pending' | 'error' | 'default';
|
|
169
|
+
export type TableColumn<T extends DataRow = any> = {
|
|
170
|
+
key: KeyType;
|
|
176
171
|
header: string;
|
|
172
|
+
cell?: Snippet<[row: T, key: KeyType, index?: number]>;
|
|
177
173
|
sortable?: boolean;
|
|
174
|
+
sortKey?: string;
|
|
178
175
|
align?: 'left' | 'center' | 'right';
|
|
179
176
|
width?: string;
|
|
180
|
-
|
|
177
|
+
class?: ClassValue;
|
|
181
178
|
};
|
|
182
|
-
export type
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
179
|
+
export type SortDirection = 'asc' | 'desc' | null;
|
|
180
|
+
export type SortState = {
|
|
181
|
+
column: string | null;
|
|
182
|
+
direction: SortDirection;
|
|
183
|
+
};
|
|
184
|
+
export type TableProps<T extends DataRow = any> = {
|
|
185
|
+
data: T[];
|
|
186
|
+
columns: TableColumn<T>[];
|
|
187
|
+
color?: VariantColors;
|
|
188
|
+
size?: VariantSizes;
|
|
189
|
+
bordered?: boolean;
|
|
190
|
+
striped?: boolean;
|
|
191
|
+
emptyStateText?: string;
|
|
192
|
+
pageSize?: number;
|
|
192
193
|
selectable?: boolean;
|
|
193
|
-
|
|
194
|
-
onSelectionChange?: (selectedRows: DataRow[]) => void;
|
|
195
|
-
onSortChange?: (sortState: SortState) => void;
|
|
196
|
-
onPageChange?: (page: number) => void;
|
|
197
|
-
emptyMessage?: string;
|
|
198
|
-
errorMessage?: string;
|
|
199
|
-
searchPlaceholder?: string;
|
|
194
|
+
selected?: T[];
|
|
200
195
|
class?: ClassValue;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
196
|
+
wrapperclass?: ClassValue;
|
|
197
|
+
tableclass?: ClassValue;
|
|
198
|
+
theadclass?: ClassValue;
|
|
199
|
+
tbodyclass?: ClassValue;
|
|
200
|
+
trclass?: ClassValue;
|
|
201
|
+
thclass?: ClassValue;
|
|
202
|
+
tdclass?: ClassValue;
|
|
203
|
+
footerclass?: ClassValue;
|
|
204
|
+
onrowclick?: (row: T, index: number) => void;
|
|
205
|
+
onsort?: (sortState: SortState) => void;
|
|
206
|
+
onselect?: (selected: T[]) => void;
|
|
207
|
+
rowclass?: (row: T, index: number) => ClassValue;
|
|
208
|
+
loading?: boolean;
|
|
212
209
|
};
|
|
213
210
|
export type BreadcrumbItem = {
|
|
214
211
|
label: string;
|
|
@@ -520,6 +517,11 @@ export interface FileUploadProps {
|
|
|
520
517
|
*/
|
|
521
518
|
metadata?: Record<string, string>;
|
|
522
519
|
}
|
|
520
|
+
export interface FilePreviewProps {
|
|
521
|
+
files: UploadedFile[];
|
|
522
|
+
ondelete?: (fileId: string, index: number) => void;
|
|
523
|
+
class?: string;
|
|
524
|
+
}
|
|
523
525
|
export interface UploadedFile {
|
|
524
526
|
FileID: string;
|
|
525
527
|
OriginalFilename: string;
|
|
@@ -543,6 +545,7 @@ export interface UploadedFile {
|
|
|
543
545
|
error?: string;
|
|
544
546
|
}
|
|
545
547
|
export { default as FileUpload } from './elements/file-upload/FileUpload.svelte';
|
|
548
|
+
export { default as FilesPreview } from './elements/file-upload/FilesPreview.svelte';
|
|
546
549
|
export { default as Toaster } from './sonner/sonner.svelte';
|
|
547
550
|
export interface FormProps<T extends Record<string, unknown>> {
|
|
548
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
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { cn } from '../../helper/cls.js';
|
|
3
|
-
import { table
|
|
4
|
-
|
|
3
|
+
import { table } from './table.js';
|
|
4
|
+
import type { TableProps, SortDirection, SortState } from '../../index.js';
|
|
5
5
|
let {
|
|
6
6
|
data = [],
|
|
7
7
|
columns = [],
|
|
@@ -1,24 +1,5 @@
|
|
|
1
1
|
import type { ClassValue } from 'tailwind-variants';
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
2
|
import type { VariantColors, VariantSizes } from '../../index.js';
|
|
4
|
-
export type DataRow = Record<string, any>;
|
|
5
|
-
export type KeyType = keyof DataRow;
|
|
6
|
-
export type StatusType = 'active' | 'inactive' | 'pending' | 'error' | 'default';
|
|
7
|
-
export type TableColumn<T extends DataRow = any> = {
|
|
8
|
-
key: KeyType;
|
|
9
|
-
header: string;
|
|
10
|
-
cell?: Snippet<[row: T, key: KeyType, index?: number]>;
|
|
11
|
-
sortable?: boolean;
|
|
12
|
-
sortKey?: string;
|
|
13
|
-
align?: 'left' | 'center' | 'right';
|
|
14
|
-
width?: string;
|
|
15
|
-
class?: ClassValue;
|
|
16
|
-
};
|
|
17
|
-
export type SortDirection = 'asc' | 'desc' | null;
|
|
18
|
-
export type SortState = {
|
|
19
|
-
column: string | null;
|
|
20
|
-
direction: SortDirection;
|
|
21
|
-
};
|
|
22
3
|
export declare const table: import("tailwind-variants").TVReturnType<{
|
|
23
4
|
size: {
|
|
24
5
|
xs: {
|
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
import { tv } from 'tailwind-variants';
|
|
2
|
-
// Prebuild Cell rendering options
|
|
3
|
-
// Snippet 1 - Date
|
|
4
|
-
// Snippet 2 - Currency
|
|
5
|
-
// Snippet 3 - Percentage
|
|
6
|
-
// Snippet 4 - Phone Number
|
|
7
|
-
// Snippet 5 - Email
|
|
8
|
-
// Snippet 6 - Status
|
|
9
|
-
// Snippet 7 - Time
|
|
10
2
|
export const table = tv({
|
|
11
3
|
slots: {
|
|
12
4
|
base: 'w-full',
|