@makolabs/ripple 1.14.0 → 2.1.0

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.
@@ -1,36 +1,111 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../helper/cls.js';
3
3
  import { fileUpload } from './file-upload.js';
4
- import type { FileUploadProps } from '../../index.js';
4
+ import Button from '../../button/Button.svelte';
5
+ import Spinner from '../spinner/Spinner.svelte';
6
+ import { Size, Color } from '../../variants.js';
7
+ import type { FileUploadProps, StagedFile } from '../../index.js';
5
8
 
6
9
  let {
7
10
  allowedMimeTypes = [],
8
- maxFiles = 10,
11
+ maxFiles = 1,
9
12
  maxSize,
10
13
  size = 'xl',
11
14
  class: className = '',
12
15
  dropzoneClass = '',
13
16
  id = 'file-upload',
14
17
  onfiles,
15
- uploadContent
18
+ uploadContent,
19
+ files = $bindable<StagedFile[]>([]),
20
+ clearAfterUpload = true,
21
+ uploadButtonLabel = 'Upload All',
22
+ clearButtonLabel = 'Clear All',
23
+ filesListLabel = 'Selected files',
24
+ listMaxHeight = 'max-h-64',
25
+ header
16
26
  }: FileUploadProps = $props();
17
27
 
18
28
  const slots = $derived(fileUpload({ size }));
19
29
 
30
+ /** True when the component operates as a multi-file staging uploader. */
31
+ const isMulti = $derived(maxFiles > 1);
32
+
33
+ /** Hard-disabled dropzone (maxFiles <= 0). */
20
34
  const disabled = $derived(maxFiles <= 0);
21
35
 
36
+ /** Soft-disabled dropzone when the staging list is at capacity. */
37
+ const dropzoneFull = $derived(isMulti && files.length >= maxFiles);
38
+
39
+ /** Effective "can drop files" flag. */
40
+ const dropzoneEnabled = $derived(!disabled && !dropzoneFull);
41
+
22
42
  let isDragging = $state(false);
23
43
  let inputRef: HTMLInputElement;
24
44
 
25
- function handleFiles(newFiles: FileList | File[]) {
26
- if (disabled) return;
27
- if (onfiles) onfiles(newFiles);
45
+ function makeId(): string {
46
+ if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {
47
+ return crypto.randomUUID();
48
+ }
49
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
50
+ }
51
+
52
+ function handleIncoming(newFiles: FileList | File[]) {
53
+ if (!dropzoneEnabled) return;
54
+ const arr = Array.from(newFiles);
55
+ if (!isMulti) {
56
+ // Single-file mode: fire-and-forget, same as pre-v2 FileUpload.
57
+ onfiles?.(arr);
58
+ return;
59
+ }
60
+ // Multi-file mode: cap and stage
61
+ const room = Math.max(0, maxFiles - files.length);
62
+ const accepted = arr.slice(0, room);
63
+ const toAdd: StagedFile[] = accepted.map((file) => ({
64
+ id: makeId(),
65
+ file,
66
+ status: 'ready' as const
67
+ }));
68
+ files = [...files, ...toAdd];
69
+ }
70
+
71
+ function handleRemove(fileId: string) {
72
+ files = files.filter((f) => f.id !== fileId);
73
+ }
74
+
75
+ function handleClearAll() {
76
+ files = [];
77
+ }
78
+
79
+ const readyCount = $derived(files.filter((f) => !f.status || f.status === 'ready').length);
80
+ const hasAnyFile = $derived(files.length > 0);
81
+ const anyUploading = $derived(files.some((f) => f.status === 'uploading'));
82
+ const canUpload = $derived(readyCount > 0 && !anyUploading && !!onfiles);
83
+
84
+ function handleUploadAll() {
85
+ if (!onfiles) return;
86
+ const rawFiles = files.filter((f) => !f.status || f.status === 'ready').map((f) => f.file);
87
+ if (rawFiles.length === 0) return;
88
+ onfiles(rawFiles);
89
+ if (clearAfterUpload) {
90
+ files = [];
91
+ }
92
+ }
93
+
94
+ function handleRetry(fileId: string) {
95
+ const target = files.find((f) => f.id === fileId);
96
+ if (!target || !onfiles) return;
97
+ files = files.map((f) =>
98
+ f.id === fileId
99
+ ? { ...f, status: 'ready' as const, error: undefined, progress: undefined }
100
+ : f
101
+ );
102
+ onfiles([target.file]);
28
103
  }
29
104
 
30
105
  function handleDragEnter(e: DragEvent) {
31
106
  e.preventDefault();
32
107
  e.stopPropagation();
33
- if (!disabled) isDragging = true;
108
+ if (dropzoneEnabled) isDragging = true;
34
109
  }
35
110
 
36
111
  function handleDragLeave(e: DragEvent) {
@@ -43,15 +118,15 @@
43
118
  e.preventDefault();
44
119
  e.stopPropagation();
45
120
  isDragging = false;
46
- if (!disabled && e.dataTransfer?.files) {
47
- handleFiles(e.dataTransfer.files);
121
+ if (dropzoneEnabled && e.dataTransfer?.files) {
122
+ handleIncoming(e.dataTransfer.files);
48
123
  }
49
124
  }
50
125
 
51
126
  function handleInputChange(e: Event) {
52
127
  const input = e.target as HTMLInputElement;
53
128
  if (input.files) {
54
- handleFiles(input.files);
129
+ handleIncoming(input.files);
55
130
  input.value = '';
56
131
  }
57
132
  }
@@ -59,7 +134,7 @@
59
134
  function handleDragOver(e: DragEvent) {
60
135
  e.preventDefault();
61
136
  e.stopPropagation();
62
- if (!disabled) isDragging = true;
137
+ if (dropzoneEnabled) isDragging = true;
63
138
  }
64
139
 
65
140
  function formatFileSize(bytes: number): string {
@@ -71,15 +146,19 @@
71
146
  }
72
147
  </script>
73
148
 
74
- <div class={cn('w-full', className)}>
149
+ <div class={cn('flex w-full flex-col gap-4', className)}>
150
+ {#if header}
151
+ {@render header()}
152
+ {/if}
153
+
75
154
  <label
76
155
  class={cn(
77
156
  slots.dropzone(),
78
157
  {
79
158
  'border-primary-400 bg-primary-50': isDragging,
80
159
  'border-default-200 bg-white': !isDragging,
81
- 'cursor-not-allowed opacity-50': disabled,
82
- 'hover:bg-default-50 cursor-pointer': !disabled
160
+ 'cursor-not-allowed opacity-50': !dropzoneEnabled,
161
+ 'hover:bg-default-50 cursor-pointer': dropzoneEnabled
83
162
  },
84
163
  dropzoneClass
85
164
  )}
@@ -93,15 +172,14 @@
93
172
  type="file"
94
173
  bind:this={inputRef}
95
174
  accept={allowedMimeTypes.join(',')}
96
- multiple={maxFiles !== 1}
97
- {disabled}
175
+ multiple={maxFiles > 1}
176
+ disabled={!dropzoneEnabled}
98
177
  class="hidden"
99
178
  onchange={handleInputChange}
100
179
  {id}
101
180
  />
102
181
 
103
182
  <div class={slots.content()}>
104
- <!-- Upload Icon -->
105
183
  <div class={slots.iconWrapper()} data-fileupload-icon-wrapper="">
106
184
  <svg xmlns="http://www.w3.org/2000/svg" class={slots.icon()} viewBox="0 0 24 24">
107
185
  <path
@@ -111,7 +189,6 @@
111
189
  </svg>
112
190
  </div>
113
191
 
114
- <!-- Text stack (wrapped so row layout in sm can place icon on the left and this block on the right) -->
115
192
  <div class={slots.textBlock()}>
116
193
  {#if !uploadContent}
117
194
  <div class={slots.mainText()}>
@@ -135,4 +212,161 @@
135
212
  </div>
136
213
  </div>
137
214
  </label>
215
+
216
+ {#if isMulti && hasAnyFile}
217
+ <div class="flex flex-col gap-2">
218
+ <div class="flex items-center justify-between">
219
+ <span class="text-default-700 text-sm font-medium">
220
+ {filesListLabel} ({files.length})
221
+ </span>
222
+ <div class="flex gap-2">
223
+ <Button
224
+ size={Size.XS}
225
+ variant="outline"
226
+ color={Color.DEFAULT}
227
+ onclick={handleClearAll}
228
+ disabled={anyUploading}
229
+ >
230
+ {clearButtonLabel}
231
+ </Button>
232
+ <Button
233
+ size={Size.XS}
234
+ color={Color.PRIMARY}
235
+ onclick={handleUploadAll}
236
+ disabled={!canUpload}
237
+ >
238
+ {uploadButtonLabel}{readyCount > 0 ? ` (${readyCount})` : ''}
239
+ </Button>
240
+ </div>
241
+ </div>
242
+
243
+ <ul
244
+ class={cn(
245
+ 'border-default-200 divide-default-100 divide-y overflow-y-auto rounded-lg border',
246
+ listMaxHeight
247
+ )}
248
+ >
249
+ {#each files as stagedFile (stagedFile.id)}
250
+ {@const status = stagedFile.status ?? 'ready'}
251
+ <li
252
+ class={cn('flex items-center gap-3 px-3 py-2', status === 'success' && 'opacity-60')}
253
+ data-fileupload-row=""
254
+ data-status={status}
255
+ >
256
+ {#if status === 'ready'}
257
+ <span
258
+ class="bg-default-100 text-default-500 flex size-7 shrink-0 items-center justify-center rounded-full"
259
+ aria-hidden="true"
260
+ >
261
+ <svg class="size-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
262
+ <path
263
+ stroke-linecap="round"
264
+ stroke-linejoin="round"
265
+ stroke-width="2"
266
+ d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
267
+ />
268
+ </svg>
269
+ </span>
270
+ {:else if status === 'uploading'}
271
+ <div class="flex size-7 shrink-0 items-center justify-center">
272
+ <Spinner size={Size.SM} color={Color.PRIMARY} />
273
+ </div>
274
+ {:else if status === 'success'}
275
+ <span
276
+ class="bg-success-100 text-success-600 flex size-7 shrink-0 items-center justify-center rounded-full"
277
+ aria-hidden="true"
278
+ >
279
+ <svg class="size-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
280
+ <path
281
+ stroke-linecap="round"
282
+ stroke-linejoin="round"
283
+ stroke-width="3"
284
+ d="M5 13l4 4L19 7"
285
+ />
286
+ </svg>
287
+ </span>
288
+ {:else if status === 'error'}
289
+ <span
290
+ class="bg-danger-100 text-danger-600 flex size-7 shrink-0 items-center justify-center rounded-full"
291
+ aria-hidden="true"
292
+ >
293
+ <svg class="size-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
294
+ <path
295
+ stroke-linecap="round"
296
+ stroke-linejoin="round"
297
+ stroke-width="3"
298
+ d="M6 18L18 6M6 6l12 12"
299
+ />
300
+ </svg>
301
+ </span>
302
+ {/if}
303
+
304
+ <div class="flex min-w-0 flex-1 flex-col gap-0.5">
305
+ <span class="text-default-900 truncate text-sm font-medium">
306
+ {stagedFile.file.name}
307
+ </span>
308
+ <span class="text-default-500 text-xs">
309
+ {formatFileSize(stagedFile.file.size)}
310
+ {#if stagedFile.error}
311
+ <span class="text-danger-600"> · {stagedFile.error}</span>
312
+ {/if}
313
+ </span>
314
+ {#if status === 'uploading' && stagedFile.progress !== undefined}
315
+ <div class="bg-default-100 mt-1 h-1 w-full overflow-hidden rounded-full">
316
+ <div
317
+ data-fileupload-progress=""
318
+ class="bg-primary-500 h-full transition-all duration-200"
319
+ style="width: {Math.max(0, Math.min(100, stagedFile.progress))}%"
320
+ ></div>
321
+ </div>
322
+ {/if}
323
+ </div>
324
+
325
+ {#if status === 'error'}
326
+ <button
327
+ type="button"
328
+ onclick={() => handleRetry(stagedFile.id)}
329
+ class="text-default-500 hover:bg-primary-50 hover:text-primary-600 shrink-0 cursor-pointer rounded p-1 transition-colors"
330
+ aria-label="Retry upload for {stagedFile.file.name}"
331
+ title="Retry"
332
+ >
333
+ <svg
334
+ class="size-4"
335
+ fill="none"
336
+ viewBox="0 0 24 24"
337
+ stroke="currentColor"
338
+ stroke-width="2"
339
+ stroke-linecap="round"
340
+ stroke-linejoin="round"
341
+ >
342
+ <polyline points="23 4 23 10 17 10" />
343
+ <polyline points="1 20 1 14 7 14" />
344
+ <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" />
345
+ </svg>
346
+ </button>
347
+ {/if}
348
+
349
+ {#if status !== 'uploading' && status !== 'success'}
350
+ <button
351
+ type="button"
352
+ onclick={() => handleRemove(stagedFile.id)}
353
+ class="text-default-400 hover:bg-default-100 hover:text-danger-500 shrink-0 cursor-pointer rounded p-1 transition-colors"
354
+ aria-label="Remove {stagedFile.file.name}"
355
+ title="Remove"
356
+ >
357
+ <svg class="size-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
358
+ <path
359
+ stroke-linecap="round"
360
+ stroke-linejoin="round"
361
+ stroke-width="2"
362
+ d="M6 18L18 6M6 6l12 12"
363
+ />
364
+ </svg>
365
+ </button>
366
+ {/if}
367
+ </li>
368
+ {/each}
369
+ </ul>
370
+ </div>
371
+ {/if}
138
372
  </div>
@@ -1,4 +1,4 @@
1
1
  import type { FileUploadProps } from '../../index.js';
2
- declare const FileUpload: import("svelte").Component<FileUploadProps, {}, "">;
2
+ declare const FileUpload: import("svelte").Component<FileUploadProps, {}, "files">;
3
3
  type FileUpload = ReturnType<typeof FileUpload>;
4
4
  export default FileUpload;
@@ -1,93 +1,13 @@
1
1
  import type { ClassValue } from 'tailwind-variants';
2
2
  import type { Snippet } from 'svelte';
3
3
  export type FileUploadSize = 'xl' | 'md' | 'sm';
4
- export interface FileUploadProps {
5
- /**
6
- * Array of allowed file MIME types or extensions
7
- * @example ['image/jpeg', 'image/png']
8
- */
9
- allowedMimeTypes?: string[];
10
- /**
11
- * Maximum file size in bytes
12
- */
13
- maxSize?: number;
14
- /**
15
- * Maximum number of files that can be uploaded; maxFiles<=0 is disabled, maxFiles=1 is singular, maxFiles>1 is multiple
16
- * @default 10
17
- */
18
- maxFiles?: number;
19
- /**
20
- * Visual size variant.
21
- *
22
- * - `xl` (default) — hero square card, column layout, 48px padding +
23
- * 96px circular icon. Use for empty-state pages or standalone upload
24
- * dialogs where the dropzone is the main focus of the screen.
25
- * - `md` — wide medium rectangle, row layout, icon-left + text-right,
26
- * ~80-90px tall, full-width. Use as a prominent form section when
27
- * the upload is a primary action alongside other fields.
28
- * - `sm` — compact inline rectangle, row layout, ~56-60px tall. Behaves
29
- * like a single form field; sits next to other inputs without
30
- * dominating.
31
- *
32
- * @default 'xl'
33
- */
34
- size?: FileUploadSize;
35
- /**
36
- * CSS class for the component container
37
- */
38
- class?: ClassValue;
39
- /**
40
- * CSS class for the dropzone
41
- */
42
- dropzoneClass?: ClassValue;
43
- /**
44
- * ID for the file input element
45
- * @default 'file-upload'
46
- */
47
- id?: string;
48
- /**
49
- * Callback when files are selected or dropped
50
- */
51
- onfiles?: (files: FileList | File[]) => void;
52
- /**
53
- * Content to display when no files are uploaded
54
- */
55
- uploadContent?: Snippet;
56
- testId?: string;
57
- }
58
- export interface FilePreviewProps {
59
- files: UploadedFile[];
60
- ondelete?: (fileId: string, index: number) => void;
61
- class?: ClassValue;
62
- testId?: string;
63
- }
64
- export interface UploadedFile {
65
- FileID: string;
66
- OriginalFilename: string;
67
- Size: number;
68
- ContentType: string;
69
- MD5Hash: string;
70
- UploadTimestamp: string;
71
- Expiry?: string;
72
- CustomMetadata?: Record<string, string>;
73
- /**
74
- * Current status of the file
75
- */
76
- status: 'uploading' | 'success' | 'error';
77
- /**
78
- * Upload progress (0-100)
79
- */
80
- progress?: number;
81
- /**
82
- * Error message if upload failed
83
- */
84
- error?: string;
85
- }
86
4
  /**
87
- * A file held in a `MultiFileUpload` component's staging list. Either purely
5
+ * A file held in a multi-file `FileUpload`'s staging list. Either purely
88
6
  * internal (the component owns the state) or bindable (the caller owns the
89
7
  * state and can mutate `status` / `progress` / `error` during upload for
90
8
  * per-file visual feedback).
9
+ *
10
+ * Only used when `maxFiles > 1`.
91
11
  */
92
12
  export interface StagedFile {
93
13
  /** Stable client-generated id for list keys and caller-side updates. */
@@ -104,41 +24,67 @@ export interface StagedFile {
104
24
  /** Optional error message rendered under the file name while status='error'. */
105
25
  error?: string;
106
26
  }
107
- export interface MultiFileUploadProps {
27
+ export interface FileUploadProps {
108
28
  /**
109
29
  * Array of allowed file MIME types or extensions.
110
- * Forwarded to the internal `FileUpload` dropzone.
111
- * @example ['text/csv', '.csv.gz']
30
+ * @example ['image/jpeg', 'image/png', '.csv', '.csv.gz']
112
31
  */
113
32
  allowedMimeTypes?: string[];
114
33
  /**
115
- * Maximum file size in bytes (informational; shown in the dropzone hint).
116
- * Forwarded to the internal `FileUpload` dropzone.
34
+ * Maximum file size in bytes (shown in the dropzone hint).
117
35
  */
118
36
  maxSize?: number;
119
37
  /**
120
- * Maximum number of files that can be in the staging list at once.
121
- * Additional drops beyond this are discarded.
122
- * @default 10
38
+ * Maximum number of files that can be uploaded.
39
+ *
40
+ * - `<= 0` — dropzone is disabled
41
+ * - `=== 1` (default) — single-file mode. `onfiles` fires immediately
42
+ * when the user drops or picks a file. No staging list, no "Upload All"
43
+ * button.
44
+ * - `> 1` — multi-file staging mode. Users drop/pick files which appear in
45
+ * a staging list with per-row remove buttons. `onfiles` fires when the
46
+ * user clicks "Upload All" with all ready-status files. The staging list
47
+ * auto-clears on fire unless `clearAfterUpload={false}` is passed.
48
+ *
49
+ * @default 1
123
50
  */
124
51
  maxFiles?: number;
125
52
  /**
126
- * Dropzone size variant. Forwarded to the internal `FileUpload`.
127
- * @default 'md'
53
+ * Visual size variant of the dropzone.
54
+ *
55
+ * - `xl` (default) — hero square card, column layout, 48px padding +
56
+ * 96px circular icon. For empty-state pages or standalone dialogs.
57
+ * - `md` — wide rectangle, row layout, icon-left + text-right, ~80-90px
58
+ * tall. Form-prominent.
59
+ * - `sm` — compact inline rectangle, row layout, ~56-60px tall. Behaves
60
+ * like a single form field.
61
+ *
62
+ * @default 'xl'
128
63
  */
129
64
  size?: FileUploadSize;
130
- /** CSS class for the component wrapper. */
65
+ /** CSS class for the component container. */
131
66
  class?: ClassValue;
132
- /** CSS class for the internal dropzone. */
67
+ /** CSS class for the dropzone area. */
133
68
  dropzoneClass?: ClassValue;
134
- /** ID for the internal file input element. */
69
+ /** ID for the file input element. */
135
70
  id?: string;
136
71
  /**
137
- * Bindable staging list. Two usage modes:
72
+ * Callback fired with the selected files as a normalized `File[]`.
73
+ *
74
+ * - In **single-file mode** (`maxFiles === 1`) — fires immediately on drop/pick.
75
+ * - In **multi-file mode** (`maxFiles > 1`) — fires when the user clicks
76
+ * "Upload All" with the current ready-status files from the staging list.
77
+ */
78
+ onfiles?: (files: File[]) => void;
79
+ /** Snippet to override the default "Click here / Drag & drop" dropzone copy. */
80
+ uploadContent?: Snippet;
81
+ testId?: string;
82
+ /**
83
+ * Bindable staging list. Only relevant when `maxFiles > 1`.
138
84
  *
139
85
  * - **Simple mode** (omit the prop): the component owns the staging list,
140
86
  * auto-clears it after `onfiles` fires, and never renders status icons.
141
- * Rows show `name + size + ×` only. Exactly like a batched `FileUpload`.
87
+ * Rows show `name + size + ×` only.
142
88
  *
143
89
  * - **Rich mode** (`bind:files`): the caller owns the list. The component
144
90
  * writes adds/removes through the binding, and reads each file's
@@ -149,17 +95,11 @@ export interface MultiFileUploadProps {
149
95
  * the component from emptying the list after firing `onfiles`.
150
96
  */
151
97
  files?: StagedFile[];
152
- /**
153
- * Fires when the user clicks "Upload All", with the raw `File[]` for every
154
- * file currently in the staging list with status `'ready'`. Identical shape
155
- * to `FileUpload.onfiles` — callers that already handle `FileUpload` can
156
- * drop this in as a batched equivalent.
157
- */
158
- onfiles?: (files: File[]) => void;
159
98
  /**
160
99
  * Whether to automatically empty the staging list after `onfiles` fires.
161
- * Set to `false` in rich mode so the caller can keep the list visible
162
- * while updating per-file status during upload.
100
+ * Only relevant when `maxFiles > 1`. Set to `false` in rich mode so the
101
+ * caller can keep the list visible while updating per-file status during
102
+ * upload.
163
103
  * @default true
164
104
  */
165
105
  clearAfterUpload?: boolean;
@@ -178,5 +118,32 @@ export interface MultiFileUploadProps {
178
118
  listMaxHeight?: string;
179
119
  /** Optional snippet rendered above the dropzone (for titles, selects, banners). */
180
120
  header?: Snippet;
121
+ }
122
+ export interface FilePreviewProps {
123
+ files: UploadedFile[];
124
+ ondelete?: (fileId: string, index: number) => void;
125
+ class?: ClassValue;
181
126
  testId?: string;
182
127
  }
128
+ export interface UploadedFile {
129
+ FileID: string;
130
+ OriginalFilename: string;
131
+ Size: number;
132
+ ContentType: string;
133
+ MD5Hash: string;
134
+ UploadTimestamp: string;
135
+ Expiry?: string;
136
+ CustomMetadata?: Record<string, string>;
137
+ /**
138
+ * Current status of the file
139
+ */
140
+ status: 'uploading' | 'success' | 'error';
141
+ /**
142
+ * Upload progress (0-100)
143
+ */
144
+ progress?: number;
145
+ /**
146
+ * Error message if upload failed
147
+ */
148
+ error?: string;
149
+ }
package/dist/index.d.ts CHANGED
@@ -45,8 +45,8 @@ export type { ComboboxItem, ComboboxProps } from './elements/combobox/combobox-t
45
45
  export type { AccordionProps } from './elements/accordion/accordion-types.js';
46
46
  export type { TimelineItem } from './elements/timeline/timeline-types.js';
47
47
  export type { FilterTab, FilterGroup, CompactFiltersProps } from './filters/filter-types.js';
48
- export type { ActivityItemBadge, ActivityItemAction, ActivityItem, ActivityListProps } from './layout/activity-list/activity-list-types.js';
49
- export type { FileUploadProps, FileUploadSize, FilePreviewProps, UploadedFile, StagedFile, MultiFileUploadProps } from './elements/file-upload/file-upload-types.js';
48
+ export type { ActivityItemBadge, ActivityItemAction, ActivityItem, ActivityListProps, ActivityListSize } from './layout/activity-list/activity-list-types.js';
49
+ export type { FileUploadProps, FileUploadSize, FilePreviewProps, UploadedFile, StagedFile } from './elements/file-upload/file-upload-types.js';
50
50
  export type { ChatMessageType, StreamingCallback, ChatAction, ChatMessage, ChatResponse, QuickAction, FileBrowserProps } from './ai/ai-types.js';
51
51
  export type { GetUsersOptions, GetUsersResult, UserEmail, UserPhone, User, Permission, Role, UserTableProps, UserModalProps, UserViewModalProps, UserManagementAdapter, UserManagementProps, FormErrors } from './user-management/user-management-types.js';
52
52
  export { tv, cn } from './helper/cls.js';
@@ -92,7 +92,6 @@ export { default as Timeline } from './elements/timeline/Timeline.svelte';
92
92
  export { default as Chart } from './charts/Chart.svelte';
93
93
  export { default as FileUpload } from './elements/file-upload/FileUpload.svelte';
94
94
  export { default as FilesPreview } from './elements/file-upload/FilesPreview.svelte';
95
- export { default as MultiFileUpload } from './elements/file-upload/MultiFileUpload.svelte';
96
95
  export { default as Toaster } from './sonner/sonner.svelte';
97
96
  export { default as AIChatInterface } from './ai/AIChatInterface.svelte';
98
97
  export { default as MermaidRenderer } from './ai/MermaidRenderer.svelte';
package/dist/index.js CHANGED
@@ -82,7 +82,6 @@ export { default as Chart } from './charts/Chart.svelte';
82
82
  // File Upload
83
83
  export { default as FileUpload } from './elements/file-upload/FileUpload.svelte';
84
84
  export { default as FilesPreview } from './elements/file-upload/FilesPreview.svelte';
85
- export { default as MultiFileUpload } from './elements/file-upload/MultiFileUpload.svelte';
86
85
  // Toaster: Should be registered in +layout.svelte
87
86
  export { default as Toaster } from './sonner/sonner.svelte';
88
87
  // AI Components