@marianmeres/stuic 2.9.0 → 2.10.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.
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
|
|
25
25
|
let container: HTMLDivElement = $state()!;
|
|
26
26
|
|
|
27
|
+
// Note: completeness and rotate are NOT included here - they're updated via setters
|
|
28
|
+
// to avoid recreating the SVG on every change
|
|
27
29
|
let circle = $derived(
|
|
28
30
|
svgCircle({
|
|
29
31
|
strokeWidth,
|
|
30
|
-
completeness,
|
|
31
32
|
bgStrokeColor,
|
|
32
33
|
roundedEdges,
|
|
33
|
-
rotate,
|
|
34
34
|
strokeWidthRatio,
|
|
35
35
|
class: circleClass,
|
|
36
36
|
circleStyle:
|
|
@@ -43,6 +43,9 @@
|
|
|
43
43
|
|
|
44
44
|
$effect(() => {
|
|
45
45
|
container.appendChild(circle.svg);
|
|
46
|
+
return () => {
|
|
47
|
+
circle.svg.remove();
|
|
48
|
+
};
|
|
46
49
|
});
|
|
47
50
|
|
|
48
51
|
$effect(() => {
|
|
@@ -174,6 +174,7 @@
|
|
|
174
174
|
) => Promise<FieldAssetWithBlobUrl[]>;
|
|
175
175
|
withOnProgress?: boolean;
|
|
176
176
|
classControls?: string;
|
|
177
|
+
isLoading?: boolean;
|
|
177
178
|
}
|
|
178
179
|
</script>
|
|
179
180
|
|
|
@@ -231,6 +232,7 @@
|
|
|
231
232
|
processAssets,
|
|
232
233
|
withOnProgress,
|
|
233
234
|
classControls = "",
|
|
235
|
+
isLoading = false,
|
|
234
236
|
parseValue = (strigifiedModels: string) => {
|
|
235
237
|
const val = strigifiedModels ?? "[]";
|
|
236
238
|
try {
|
|
@@ -280,7 +282,8 @@
|
|
|
280
282
|
// return value and uses it directly as the error message.
|
|
281
283
|
|
|
282
284
|
if (required && !assets.length) return t("field_req_att");
|
|
283
|
-
if (assets.length > cardinality)
|
|
285
|
+
if (assets.length > cardinality)
|
|
286
|
+
return t("cardinality_reached", { max: cardinality });
|
|
284
287
|
|
|
285
288
|
// normally, with other fieldtypes, we would continue with provided validator:
|
|
286
289
|
// return (validate as any)?.customValidator?.(value, context, el) || "";
|
|
@@ -369,72 +372,78 @@
|
|
|
369
372
|
/>
|
|
370
373
|
|
|
371
374
|
{#snippet default_render()}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
class={[objectSize, objectFitStyle, "hover:saturate-150"]}
|
|
392
|
-
/>
|
|
393
|
-
{:else}
|
|
394
|
-
{@html getAssetIcon((asset.name ?? "").split(".").at(-1))({
|
|
395
|
-
size: 32,
|
|
396
|
-
class: "mx-auto",
|
|
397
|
-
})}
|
|
398
|
-
{/if}
|
|
399
|
-
<span
|
|
400
|
-
class="absolute bottom-1 left-1 right-1 grid bg-white/50 rounded"
|
|
401
|
-
use:tooltip={() => ({ content: asset.name })}
|
|
375
|
+
{#if isLoading}
|
|
376
|
+
<div class="p-2 pl-8 flex items-center justify-center min-h-24">
|
|
377
|
+
<SpinnerCircle />
|
|
378
|
+
</div>
|
|
379
|
+
{:else}
|
|
380
|
+
<div class={["p-2 flex items-center gap-0.5 flex-wrap"]}>
|
|
381
|
+
{#each assets as asset, idx}
|
|
382
|
+
{@const { thumb, full, original } = asset_urls(asset)}
|
|
383
|
+
{@const _is_img = isImage(asset.type ?? thumb)}
|
|
384
|
+
<div class="relative group">
|
|
385
|
+
<button
|
|
386
|
+
class={[objectSize, "bg-black/10 grid place-content-center", classControls]}
|
|
387
|
+
onclick={(e) => {
|
|
388
|
+
e.stopPropagation();
|
|
389
|
+
e.preventDefault();
|
|
390
|
+
previewIdx = idx;
|
|
391
|
+
modal.open();
|
|
392
|
+
}}
|
|
393
|
+
type="button"
|
|
402
394
|
>
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
395
|
+
{#if _is_img}
|
|
396
|
+
<img
|
|
397
|
+
src={thumb}
|
|
398
|
+
alt={asset.name}
|
|
399
|
+
class={[objectSize, objectFitStyle, "hover:saturate-150"]}
|
|
400
|
+
/>
|
|
401
|
+
{:else}
|
|
402
|
+
{@html getAssetIcon((asset.name ?? "").split(".").at(-1))({
|
|
403
|
+
size: 32,
|
|
404
|
+
class: "mx-auto",
|
|
405
|
+
})}
|
|
406
|
+
{/if}
|
|
407
407
|
<span
|
|
408
|
-
class="absolute
|
|
408
|
+
class="absolute bottom-1 left-1 right-1 grid bg-white/50 rounded"
|
|
409
|
+
use:tooltip={() => ({ content: asset.name })}
|
|
409
410
|
>
|
|
410
|
-
{
|
|
411
|
-
<Circle
|
|
412
|
-
class="text-white"
|
|
413
|
-
animateCompletenessMs={300}
|
|
414
|
-
bgStrokeColor="rgba(0 0 0 / 0.2)"
|
|
415
|
-
completeness={progress[asset.id] / 100}
|
|
416
|
-
rotate={-90}
|
|
417
|
-
/>
|
|
418
|
-
{:else}
|
|
419
|
-
<SpinnerCircle bgStrokeColor="gray" />
|
|
420
|
-
{/if}
|
|
411
|
+
<span class="truncate px-2 text-xs">{asset.name}</span>
|
|
421
412
|
</span>
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
413
|
+
|
|
414
|
+
{#if asset.meta?.isUploading}
|
|
415
|
+
<span
|
|
416
|
+
class="absolute inset-0 grid place-content-center pointer-events-none text-white"
|
|
417
|
+
>
|
|
418
|
+
{#if withOnProgress}
|
|
419
|
+
<Circle
|
|
420
|
+
class="text-white"
|
|
421
|
+
animateCompletenessMs={300}
|
|
422
|
+
bgStrokeColor="rgba(0 0 0 / 0.2)"
|
|
423
|
+
completeness={progress[asset.id] / 100}
|
|
424
|
+
rotate={-90}
|
|
425
|
+
/>
|
|
426
|
+
{:else}
|
|
427
|
+
<SpinnerCircle bgStrokeColor="gray" />
|
|
428
|
+
{/if}
|
|
429
|
+
</span>
|
|
430
|
+
{/if}
|
|
431
|
+
</button>
|
|
432
|
+
</div>
|
|
433
|
+
{/each}
|
|
434
|
+
<button
|
|
435
|
+
type="button"
|
|
436
|
+
onclick={(e) => {
|
|
437
|
+
e.preventDefault();
|
|
438
|
+
e.stopPropagation();
|
|
439
|
+
inputEl.click();
|
|
440
|
+
}}
|
|
441
|
+
class={[objectSize, " grid place-content-center group", classControls]}
|
|
442
|
+
>
|
|
443
|
+
{@html iconAdd({ size: 32, class: "opacity-75 group-hover:opacity-100" })}
|
|
444
|
+
</button>
|
|
445
|
+
</div>
|
|
446
|
+
{/if}
|
|
438
447
|
{/snippet}
|
|
439
448
|
|
|
440
449
|
<div
|
|
@@ -64,6 +64,7 @@ export interface Props extends Record<string, any> {
|
|
|
64
64
|
processAssets?: (assets: FieldAsset[], onProgress?: (blobUrl: string, progress: number) => any) => Promise<FieldAssetWithBlobUrl[]>;
|
|
65
65
|
withOnProgress?: boolean;
|
|
66
66
|
classControls?: string;
|
|
67
|
+
isLoading?: boolean;
|
|
67
68
|
}
|
|
68
69
|
declare const FieldAssets: import("svelte").Component<Props, {}, "value">;
|
|
69
70
|
type FieldAssets = ReturnType<typeof FieldAssets>;
|