@makolabs/ripple 2.3.0 → 2.4.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.
@@ -40,6 +40,8 @@
40
40
  const dropzoneEnabled = $derived(!disabled && !dropzoneFull);
41
41
 
42
42
  let isDragging = $state(false);
43
+ let truncationMessage = $state('');
44
+ let truncationTimer: ReturnType<typeof setTimeout> | undefined;
43
45
  let inputRef: HTMLInputElement;
44
46
 
45
47
  function makeId(): string {
@@ -60,6 +62,18 @@
60
62
  // Multi-file mode: cap and stage
61
63
  const room = Math.max(0, maxFiles - files.length);
62
64
  const accepted = arr.slice(0, room);
65
+ const dropped = arr.length - accepted.length;
66
+
67
+ if (dropped > 0) {
68
+ clearTimeout(truncationTimer);
69
+ truncationMessage = `${dropped} file${dropped > 1 ? 's' : ''} could not be added — maximum of ${maxFiles} reached.`;
70
+ truncationTimer = setTimeout(() => {
71
+ truncationMessage = '';
72
+ }, 5000);
73
+ } else {
74
+ truncationMessage = '';
75
+ }
76
+
63
77
  const toAdd: StagedFile[] = accepted.map((file) => ({
64
78
  id: makeId(),
65
79
  file,
@@ -70,10 +84,12 @@
70
84
 
71
85
  function handleRemove(fileId: string) {
72
86
  files = files.filter((f) => f.id !== fileId);
87
+ truncationMessage = '';
73
88
  }
74
89
 
75
90
  function handleClearAll() {
76
91
  files = [];
92
+ truncationMessage = '';
77
93
  }
78
94
 
79
95
  const readyCount = $derived(files.filter((f) => !f.status || f.status === 'ready').length);
@@ -167,6 +183,7 @@
167
183
  ondragover={handleDragOver}
168
184
  ondrop={handleDrop}
169
185
  for={id}
186
+ data-dropzone-full={dropzoneFull ? 'true' : undefined}
170
187
  >
171
188
  <input
172
189
  type="file"
@@ -190,34 +207,75 @@
190
207
  </div>
191
208
 
192
209
  <div class={slots.textBlock()}>
193
- {#if !uploadContent}
210
+ {#if dropzoneFull}
211
+ <div class={slots.mainText()}>
212
+ <span class="text-default-500 font-medium">Maximum of {maxFiles} files reached.</span>
213
+ </div>
214
+ <div class={slots.hintText()}>Remove a file to add more.</div>
215
+ {:else if !uploadContent}
194
216
  <div class={slots.mainText()}>
195
217
  <span class="text-primary-500 font-medium">Click here</span>
196
218
  <span class="text-default-600"> to upload your file or drag and drop.</span>
197
219
  </div>
220
+ <div class={slots.hintText()}>
221
+ Supported Format: {allowedMimeTypes.length
222
+ ? allowedMimeTypes.join(', ')
223
+ : 'SVG, JPG, PNG'}
224
+ {#if maxSize}
225
+ ({formatFileSize(maxSize)} each)
226
+ {:else}
227
+ (10MB each)
228
+ {/if}
229
+ </div>
198
230
  {:else}
199
231
  {@render uploadContent()}
232
+ <div class={slots.hintText()}>
233
+ Supported Format: {allowedMimeTypes.length
234
+ ? allowedMimeTypes.join(', ')
235
+ : 'SVG, JPG, PNG'}
236
+ {#if maxSize}
237
+ ({formatFileSize(maxSize)} each)
238
+ {:else}
239
+ (10MB each)
240
+ {/if}
241
+ </div>
200
242
  {/if}
201
-
202
- <div class={slots.hintText()}>
203
- Supported Format: {allowedMimeTypes.length
204
- ? allowedMimeTypes.join(', ')
205
- : 'SVG, JPG, PNG'}
206
- {#if maxSize}
207
- ({formatFileSize(maxSize)} each)
208
- {:else}
209
- (10MB each)
210
- {/if}
211
- </div>
212
243
  </div>
213
244
  </div>
214
245
  </label>
215
246
 
247
+ {#if truncationMessage}
248
+ <div
249
+ class="text-warning-700 bg-warning-50 border-warning-200 flex items-center gap-2 rounded-lg border px-3 py-2 text-xs"
250
+ data-fileupload-truncation-warning=""
251
+ >
252
+ <svg
253
+ class="text-warning-500 size-4 shrink-0"
254
+ fill="none"
255
+ viewBox="0 0 24 24"
256
+ stroke="currentColor"
257
+ >
258
+ <path
259
+ stroke-linecap="round"
260
+ stroke-linejoin="round"
261
+ stroke-width="2"
262
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4.5c-.77-.833-2.694-.833-3.464 0L3.34 16.5c-.77.833.192 2.5 1.732 2.5z"
263
+ />
264
+ </svg>
265
+ {truncationMessage}
266
+ </div>
267
+ {/if}
268
+
216
269
  {#if isMulti && hasAnyFile}
217
270
  <div class="flex flex-col gap-2">
218
271
  <div class="flex items-center justify-between">
219
- <span class="text-default-700 text-sm font-medium">
220
- {filesListLabel} ({files.length})
272
+ <span
273
+ class={cn('text-sm font-medium', dropzoneFull ? 'text-warning-600' : 'text-default-700')}
274
+ >
275
+ {filesListLabel} ({files.length}/{maxFiles})
276
+ {#if dropzoneFull}
277
+ <span class="text-warning-500 ml-1 text-xs font-normal">— full</span>
278
+ {/if}
221
279
  </span>
222
280
  <div class="flex gap-2">
223
281
  <Button
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@makolabs/ripple",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Simple Svelte 5 powered component library ✨",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {