@proveanything/smartlinks-utils-ui 1.13.1 → 1.13.3
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/{chunk-HKL24TFC.js → chunk-VP4LZEEZ.js} +344 -112
- package/dist/chunk-VP4LZEEZ.js.map +1 -0
- package/dist/components/AssetPicker/index.css +8 -16
- package/dist/components/AssetPicker/index.css.map +1 -1
- package/dist/components/AssetPicker/index.d.ts +1 -1
- package/dist/components/AssetPicker/index.js +1 -1
- package/dist/components/ConditionsEditor/index.css +8 -16
- package/dist/components/ConditionsEditor/index.css.map +1 -1
- package/dist/components/FontPicker/index.css +8 -16
- package/dist/components/FontPicker/index.css.map +1 -1
- package/dist/components/IconPicker/index.css +8 -16
- package/dist/components/IconPicker/index.css.map +1 -1
- package/dist/components/LinkPicker/index.css +8 -16
- package/dist/components/LinkPicker/index.css.map +1 -1
- package/dist/components/RecordsAdmin/index.css +8 -16
- package/dist/components/RecordsAdmin/index.css.map +1 -1
- package/dist/index.css +8 -16
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{useAssets-tRkW00zx.d.ts → useAssets-Cs0OJs-x.d.ts} +6 -2
- package/package.json +1 -1
- package/dist/chunk-HKL24TFC.js.map +0 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { assertStylesLoaded } from './chunk-OLYC54YT.js';
|
|
2
2
|
import { cn } from './chunk-L7FQ52F5.js';
|
|
3
|
-
import React7, { useState, useRef, useEffect, useCallback, useMemo } from 'react';
|
|
3
|
+
import React7, { useState, useRef, useEffect, useCallback, useMemo, useLayoutEffect } from 'react';
|
|
4
|
+
import { createPortal } from 'react-dom';
|
|
4
5
|
import * as SL from '@proveanything/smartlinks';
|
|
5
|
-
import { Filter, Search, LayoutGrid, List,
|
|
6
|
+
import { Filter, Search, LayoutGrid, List, Loader2, AlertCircle, Tag, X, ImageOff, Wand2, Maximize2, Clipboard, Pencil, Check, Upload, Link, MicOff, Mic, ChevronDown, ChevronRight, Sparkles, Image as Image$1, Plus, FileIcon, Film, Music, FileText, AppWindow, MoreVertical, Trash2 } from 'lucide-react';
|
|
6
7
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
8
|
|
|
8
9
|
// src/components/AssetPicker/types.ts
|
|
@@ -14,6 +15,66 @@ var ASSET_MIME_FILTERS = [
|
|
|
14
15
|
{ value: "document", label: "Documents", prefix: "application/" },
|
|
15
16
|
{ value: "pdf", label: "PDFs", prefix: "application/pdf" }
|
|
16
17
|
];
|
|
18
|
+
function safeDecode(value) {
|
|
19
|
+
if (!value) return "";
|
|
20
|
+
try {
|
|
21
|
+
return decodeURIComponent(value);
|
|
22
|
+
} catch {
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function getAssetIdentityKeys(asset2) {
|
|
27
|
+
const keys = [];
|
|
28
|
+
if (asset2.id) keys.push(`id:${asset2.id}`);
|
|
29
|
+
const normalizedUrl = safeDecode(asset2.url).trim().toLowerCase();
|
|
30
|
+
if (normalizedUrl) keys.push(`url:${normalizedUrl}`);
|
|
31
|
+
const normalizedThumb = safeDecode(asset2.thumbnail).trim().toLowerCase();
|
|
32
|
+
if (normalizedThumb) keys.push(`thumb:${normalizedThumb}`);
|
|
33
|
+
const normalizedHash = asset2.hash?.trim().toLowerCase();
|
|
34
|
+
if (normalizedHash) keys.push(`hash:${normalizedHash}`);
|
|
35
|
+
return keys;
|
|
36
|
+
}
|
|
37
|
+
function scoreAsset(asset2) {
|
|
38
|
+
const productId = asset2.productId ?? asset2.metadata?.productId;
|
|
39
|
+
const proofId = asset2.proofId ?? asset2.metadata?.proofId;
|
|
40
|
+
const plainName = asset2.name && !asset2.name.startsWith("sites/") ? 1 : 0;
|
|
41
|
+
const plainCleanName = asset2.cleanName && !asset2.cleanName.startsWith("sites/") ? 1 : 0;
|
|
42
|
+
return (proofId ? 32 : 0) + (productId ? 16 : 0) + (asset2.thumbnail ? 8 : 0) + (asset2.mimeType ? 4 : 0) + (asset2.size ? 2 : 0) + plainName + plainCleanName;
|
|
43
|
+
}
|
|
44
|
+
function mergeAssets(a, b) {
|
|
45
|
+
const keepB = scoreAsset(b) > scoreAsset(a);
|
|
46
|
+
const primary = keepB ? b : a;
|
|
47
|
+
const secondary = keepB ? a : b;
|
|
48
|
+
return {
|
|
49
|
+
...secondary,
|
|
50
|
+
...primary,
|
|
51
|
+
metadata: {
|
|
52
|
+
...secondary.metadata || {},
|
|
53
|
+
...primary.metadata || {}
|
|
54
|
+
},
|
|
55
|
+
labels: Array.from(/* @__PURE__ */ new Set([...secondary.labels || [], ...primary.labels || []])),
|
|
56
|
+
thumbnail: primary.thumbnail ?? secondary.thumbnail ?? null,
|
|
57
|
+
app: primary.app ?? secondary.app ?? null,
|
|
58
|
+
thumbnails: primary.thumbnails ?? secondary.thumbnails
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function dedupeAssetList(items) {
|
|
62
|
+
const deduped = [];
|
|
63
|
+
const keyToIndex = /* @__PURE__ */ new Map();
|
|
64
|
+
for (const asset2 of items) {
|
|
65
|
+
const keys = getAssetIdentityKeys(asset2);
|
|
66
|
+
const existingIndex = keys.map((key) => keyToIndex.get(key)).find((index) => index !== void 0);
|
|
67
|
+
if (existingIndex === void 0) {
|
|
68
|
+
const nextIndex = deduped.push(asset2) - 1;
|
|
69
|
+
keys.forEach((key) => keyToIndex.set(key, nextIndex));
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const merged = mergeAssets(deduped[existingIndex], asset2);
|
|
73
|
+
deduped[existingIndex] = merged;
|
|
74
|
+
getAssetIdentityKeys(merged).forEach((key) => keyToIndex.set(key, existingIndex));
|
|
75
|
+
}
|
|
76
|
+
return deduped;
|
|
77
|
+
}
|
|
17
78
|
function useAssets({ scope, accept, pageSize, appId, listAppId }) {
|
|
18
79
|
const [assets, setAssets] = useState([]);
|
|
19
80
|
const [loading, setLoading] = useState(true);
|
|
@@ -41,7 +102,19 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
|
|
|
41
102
|
...listAppId ? { appId: listAppId } : {}
|
|
42
103
|
});
|
|
43
104
|
if (mountedRef.current) {
|
|
44
|
-
|
|
105
|
+
const raw = result;
|
|
106
|
+
const deduped = dedupeAssetList(raw);
|
|
107
|
+
const idCounts = /* @__PURE__ */ new Map();
|
|
108
|
+
for (const a of raw) idCounts.set(a.id, (idCounts.get(a.id) || 0) + 1);
|
|
109
|
+
const dupIds = Array.from(idCounts.entries()).filter(([, n]) => n > 1);
|
|
110
|
+
console.debug("[AssetPicker] list", {
|
|
111
|
+
scope,
|
|
112
|
+
listAppId,
|
|
113
|
+
rawCount: raw.length,
|
|
114
|
+
dedupedCount: deduped.length,
|
|
115
|
+
duplicateIds: dupIds
|
|
116
|
+
});
|
|
117
|
+
setAssets(deduped);
|
|
45
118
|
}
|
|
46
119
|
} catch (err) {
|
|
47
120
|
if (mountedRef.current) {
|
|
@@ -55,13 +128,13 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
|
|
|
55
128
|
useEffect(() => {
|
|
56
129
|
fetchAssets();
|
|
57
130
|
}, [fetchAssets]);
|
|
58
|
-
const upload = useCallback(async (file, onProgress) => {
|
|
131
|
+
const upload = useCallback(async (file, onProgress, scopeOverride) => {
|
|
59
132
|
setUploading(true);
|
|
60
133
|
setUploadProgress(0);
|
|
61
134
|
try {
|
|
62
135
|
const result = await SL.asset.upload({
|
|
63
136
|
file,
|
|
64
|
-
scope,
|
|
137
|
+
scope: scopeOverride || scope,
|
|
65
138
|
name: file.name,
|
|
66
139
|
admin: true,
|
|
67
140
|
...appId ? { appId } : {},
|
|
@@ -70,8 +143,8 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
|
|
|
70
143
|
onProgress?.(pct);
|
|
71
144
|
}
|
|
72
145
|
});
|
|
73
|
-
if (mountedRef.current) {
|
|
74
|
-
setAssets((prev) => [result, ...prev]);
|
|
146
|
+
if (mountedRef.current && !scopeOverride) {
|
|
147
|
+
setAssets((prev) => dedupeAssetList([result, ...prev]));
|
|
75
148
|
}
|
|
76
149
|
return result;
|
|
77
150
|
} catch (err) {
|
|
@@ -84,7 +157,7 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
|
|
|
84
157
|
}
|
|
85
158
|
}
|
|
86
159
|
}, [scope, appId]);
|
|
87
|
-
const uploadFromUrl = useCallback(async (url, name) => {
|
|
160
|
+
const uploadFromUrl = useCallback(async (url, name, scopeOverride) => {
|
|
88
161
|
setUploading(true);
|
|
89
162
|
setUploadProgress(0);
|
|
90
163
|
try {
|
|
@@ -93,7 +166,7 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
|
|
|
93
166
|
const blob = await response.blob();
|
|
94
167
|
const fileName = name || url.split("/").pop()?.split("?")[0] || "imported-file";
|
|
95
168
|
const file = new File([blob], fileName, { type: blob.type });
|
|
96
|
-
return await upload(file);
|
|
169
|
+
return await upload(file, void 0, scopeOverride);
|
|
97
170
|
} catch (err) {
|
|
98
171
|
if (mountedRef.current) setError(err?.message || "URL import failed");
|
|
99
172
|
return null;
|
|
@@ -110,13 +183,13 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
|
|
|
110
183
|
try {
|
|
111
184
|
const result = await SL.asset.uploadFromUrl({
|
|
112
185
|
url,
|
|
113
|
-
scope,
|
|
186
|
+
scope: opts?.scopeOverride || scope,
|
|
114
187
|
metadata: { name: opts?.name, ...opts?.metadata || {} },
|
|
115
188
|
...appId ? { appId } : {},
|
|
116
189
|
admin: true
|
|
117
190
|
});
|
|
118
|
-
if (mountedRef.current) {
|
|
119
|
-
setAssets((prev) => [result, ...prev]);
|
|
191
|
+
if (mountedRef.current && !opts?.scopeOverride) {
|
|
192
|
+
setAssets((prev) => dedupeAssetList([result, ...prev]));
|
|
120
193
|
}
|
|
121
194
|
return result;
|
|
122
195
|
} catch (err) {
|
|
@@ -155,10 +228,10 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
|
|
|
155
228
|
try {
|
|
156
229
|
const result = await SL.asset.restoreAdmin(collectionId, assetId);
|
|
157
230
|
if (mountedRef.current) {
|
|
158
|
-
setAssets((prev) => {
|
|
231
|
+
setAssets((prev) => dedupeAssetList((() => {
|
|
159
232
|
const exists = prev.some((a) => a.id === assetId);
|
|
160
233
|
return exists ? prev.map((a) => a.id === assetId ? result : a) : [result, ...prev];
|
|
161
|
-
});
|
|
234
|
+
})()));
|
|
162
235
|
}
|
|
163
236
|
return result;
|
|
164
237
|
} catch (err) {
|
|
@@ -185,7 +258,7 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
|
|
|
185
258
|
}
|
|
186
259
|
});
|
|
187
260
|
if (mountedRef.current) {
|
|
188
|
-
setAssets((prev) => prev.map((a) => a.id === assetId ? result : a));
|
|
261
|
+
setAssets((prev) => dedupeAssetList(prev.map((a) => a.id === assetId ? result : a)));
|
|
189
262
|
}
|
|
190
263
|
return result;
|
|
191
264
|
} catch (err) {
|
|
@@ -207,7 +280,7 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
|
|
|
207
280
|
try {
|
|
208
281
|
const result = await SL.asset.updateAdmin({ collectionId, assetId, ...patch });
|
|
209
282
|
if (mountedRef.current) {
|
|
210
|
-
setAssets((prev) => prev.map((a) => a.id === assetId ? result : a));
|
|
283
|
+
setAssets((prev) => dedupeAssetList(prev.map((a) => a.id === assetId ? result : a)));
|
|
211
284
|
}
|
|
212
285
|
return result;
|
|
213
286
|
} catch (err) {
|
|
@@ -352,13 +425,54 @@ var AppBadge = ({ appId, appName, size = "sm" }) => {
|
|
|
352
425
|
var CardMenu = ({ onRename, onReplace, onEditTags, onDelete, position = "absolute" }) => {
|
|
353
426
|
const [open, setOpen] = useState(false);
|
|
354
427
|
const ref = useRef(null);
|
|
428
|
+
const btnRef = useRef(null);
|
|
429
|
+
const menuRef = useRef(null);
|
|
430
|
+
const [pos, setPos] = useState(null);
|
|
355
431
|
useEffect(() => {
|
|
356
432
|
if (!open) return;
|
|
357
433
|
const handler = (e) => {
|
|
358
|
-
|
|
434
|
+
const t = e.target;
|
|
435
|
+
if (ref.current?.contains(t)) return;
|
|
436
|
+
if (menuRef.current?.contains(t)) return;
|
|
437
|
+
setOpen(false);
|
|
438
|
+
};
|
|
439
|
+
const onKey = (e) => {
|
|
440
|
+
if (e.key === "Escape") setOpen(false);
|
|
359
441
|
};
|
|
360
442
|
document.addEventListener("mousedown", handler);
|
|
361
|
-
|
|
443
|
+
document.addEventListener("keydown", onKey);
|
|
444
|
+
return () => {
|
|
445
|
+
document.removeEventListener("mousedown", handler);
|
|
446
|
+
document.removeEventListener("keydown", onKey);
|
|
447
|
+
};
|
|
448
|
+
}, [open]);
|
|
449
|
+
useLayoutEffect(() => {
|
|
450
|
+
if (!open) {
|
|
451
|
+
setPos(null);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
const update = () => {
|
|
455
|
+
const el = btnRef.current;
|
|
456
|
+
if (!el) return;
|
|
457
|
+
const r = el.getBoundingClientRect();
|
|
458
|
+
const menuW = menuRef.current?.offsetWidth ?? 160;
|
|
459
|
+
const menuH = menuRef.current?.offsetHeight ?? 160;
|
|
460
|
+
const margin = 8;
|
|
461
|
+
let left = Math.min(window.innerWidth - menuW - margin, r.right - menuW);
|
|
462
|
+
left = Math.max(margin, left);
|
|
463
|
+
let top = r.bottom + 4;
|
|
464
|
+
if (top + menuH > window.innerHeight - margin) {
|
|
465
|
+
top = Math.max(margin, r.top - menuH - 4);
|
|
466
|
+
}
|
|
467
|
+
setPos({ top, left });
|
|
468
|
+
};
|
|
469
|
+
update();
|
|
470
|
+
window.addEventListener("resize", update);
|
|
471
|
+
window.addEventListener("scroll", update, true);
|
|
472
|
+
return () => {
|
|
473
|
+
window.removeEventListener("resize", update);
|
|
474
|
+
window.removeEventListener("scroll", update, true);
|
|
475
|
+
};
|
|
362
476
|
}, [open]);
|
|
363
477
|
if (!onRename && !onReplace && !onEditTags && !onDelete) return null;
|
|
364
478
|
return /* @__PURE__ */ jsxs(
|
|
@@ -366,7 +480,7 @@ var CardMenu = ({ onRename, onReplace, onEditTags, onDelete, position = "absolut
|
|
|
366
480
|
{
|
|
367
481
|
ref,
|
|
368
482
|
className: cn(
|
|
369
|
-
position === "absolute" ? "absolute
|
|
483
|
+
position === "absolute" ? "absolute top-1.5 right-1.5 z-10" : "relative flex-shrink-0"
|
|
370
484
|
),
|
|
371
485
|
onClick: (e) => e.stopPropagation(),
|
|
372
486
|
onDoubleClick: (e) => e.stopPropagation(),
|
|
@@ -374,6 +488,7 @@ var CardMenu = ({ onRename, onReplace, onEditTags, onDelete, position = "absolut
|
|
|
374
488
|
/* @__PURE__ */ jsx(
|
|
375
489
|
"button",
|
|
376
490
|
{
|
|
491
|
+
ref: btnRef,
|
|
377
492
|
type: "button",
|
|
378
493
|
onClick: (e) => {
|
|
379
494
|
e.stopPropagation();
|
|
@@ -381,91 +496,96 @@ var CardMenu = ({ onRename, onReplace, onEditTags, onDelete, position = "absolut
|
|
|
381
496
|
},
|
|
382
497
|
className: cn(
|
|
383
498
|
"w-6 h-6 rounded-full flex items-center justify-center transition-all",
|
|
384
|
-
"bg-background/90 border border-border text-foreground hover:bg-background shadow-sm"
|
|
385
|
-
position === "absolute" && "opacity-0 group-hover:opacity-100",
|
|
386
|
-
open && "opacity-100"
|
|
499
|
+
"bg-background/90 border border-border text-foreground hover:bg-background shadow-sm"
|
|
387
500
|
),
|
|
388
501
|
title: "Asset actions",
|
|
389
502
|
"aria-label": "Asset actions",
|
|
390
503
|
children: /* @__PURE__ */ jsx(MoreVertical, { className: "w-3 h-3" })
|
|
391
504
|
}
|
|
392
505
|
),
|
|
393
|
-
open &&
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
506
|
+
open && typeof document !== "undefined" && createPortal(
|
|
507
|
+
/* @__PURE__ */ jsxs(
|
|
508
|
+
"div",
|
|
509
|
+
{
|
|
510
|
+
ref: menuRef,
|
|
511
|
+
className: "fixed z-[2147483647] min-w-[160px] rounded-md border border-border bg-popover text-popover-foreground shadow-lg py-1",
|
|
512
|
+
style: pos ? { top: pos.top, left: pos.left } : { visibility: "hidden", top: 0, left: 0 },
|
|
513
|
+
role: "menu",
|
|
514
|
+
onClick: (e) => e.stopPropagation(),
|
|
515
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
516
|
+
children: [
|
|
517
|
+
onRename && /* @__PURE__ */ jsxs(
|
|
518
|
+
"button",
|
|
519
|
+
{
|
|
520
|
+
type: "button",
|
|
521
|
+
role: "menuitem",
|
|
522
|
+
onClick: (e) => {
|
|
523
|
+
e.stopPropagation();
|
|
524
|
+
setOpen(false);
|
|
525
|
+
onRename();
|
|
526
|
+
},
|
|
527
|
+
className: "w-full flex items-center gap-2 px-2.5 py-1.5 text-xs hover:bg-accent",
|
|
528
|
+
children: [
|
|
529
|
+
/* @__PURE__ */ jsx(Pencil, { className: "w-3 h-3" }),
|
|
530
|
+
" Rename"
|
|
531
|
+
]
|
|
532
|
+
}
|
|
533
|
+
),
|
|
534
|
+
onReplace && /* @__PURE__ */ jsxs(
|
|
535
|
+
"button",
|
|
536
|
+
{
|
|
537
|
+
type: "button",
|
|
538
|
+
role: "menuitem",
|
|
539
|
+
onClick: (e) => {
|
|
540
|
+
e.stopPropagation();
|
|
541
|
+
setOpen(false);
|
|
542
|
+
onReplace();
|
|
543
|
+
},
|
|
544
|
+
className: "w-full flex items-center gap-2 px-2.5 py-1.5 text-xs hover:bg-accent",
|
|
545
|
+
children: [
|
|
546
|
+
/* @__PURE__ */ jsx(Upload, { className: "w-3 h-3" }),
|
|
547
|
+
" Replace file"
|
|
548
|
+
]
|
|
549
|
+
}
|
|
550
|
+
),
|
|
551
|
+
onEditTags && /* @__PURE__ */ jsxs(
|
|
552
|
+
"button",
|
|
553
|
+
{
|
|
554
|
+
type: "button",
|
|
555
|
+
role: "menuitem",
|
|
556
|
+
onClick: (e) => {
|
|
557
|
+
e.stopPropagation();
|
|
558
|
+
setOpen(false);
|
|
559
|
+
onEditTags();
|
|
560
|
+
},
|
|
561
|
+
className: "w-full flex items-center gap-2 px-2.5 py-1.5 text-xs hover:bg-accent",
|
|
562
|
+
children: [
|
|
563
|
+
/* @__PURE__ */ jsx(Tag, { className: "w-3 h-3" }),
|
|
564
|
+
" Edit tags"
|
|
565
|
+
]
|
|
566
|
+
}
|
|
567
|
+
),
|
|
568
|
+
onDelete && /* @__PURE__ */ jsxs(
|
|
569
|
+
"button",
|
|
570
|
+
{
|
|
571
|
+
type: "button",
|
|
572
|
+
role: "menuitem",
|
|
573
|
+
onClick: (e) => {
|
|
574
|
+
e.stopPropagation();
|
|
575
|
+
setOpen(false);
|
|
576
|
+
onDelete();
|
|
577
|
+
},
|
|
578
|
+
className: "w-full flex items-center gap-2 px-2.5 py-1.5 text-xs text-destructive hover:bg-destructive/10",
|
|
579
|
+
children: [
|
|
580
|
+
/* @__PURE__ */ jsx(Trash2, { className: "w-3 h-3" }),
|
|
581
|
+
" Delete"
|
|
582
|
+
]
|
|
583
|
+
}
|
|
584
|
+
)
|
|
585
|
+
]
|
|
586
|
+
}
|
|
587
|
+
),
|
|
588
|
+
document.body
|
|
469
589
|
)
|
|
470
590
|
]
|
|
471
591
|
}
|
|
@@ -545,7 +665,7 @@ var AssetGridItem = ({ asset: asset2, selected, onToggle, onDoubleClick, onDelet
|
|
|
545
665
|
] })
|
|
546
666
|
] })
|
|
547
667
|
] }),
|
|
548
|
-
selected && /* @__PURE__ */ jsx("div", { className: "absolute top-2
|
|
668
|
+
selected && /* @__PURE__ */ jsx("div", { className: "absolute top-2 left-2 w-5 h-5 rounded-full bg-primary flex items-center justify-center z-10", children: /* @__PURE__ */ jsx(Check, { className: "w-3 h-3 text-primary-foreground" }) }),
|
|
549
669
|
/* @__PURE__ */ jsx(
|
|
550
670
|
CardMenu,
|
|
551
671
|
{
|
|
@@ -2025,8 +2145,25 @@ var GlobalUploadToggle = ({ checked, onChange, appName }) => /* @__PURE__ */ jsx
|
|
|
2025
2145
|
/* @__PURE__ */ jsx("span", { className: "block", children: checked ? `Asset will be available to every app in this collection.` : `Asset will be tagged to ${appName}. Tick to share with every app in the collection instead.` })
|
|
2026
2146
|
] })
|
|
2027
2147
|
] });
|
|
2028
|
-
var
|
|
2029
|
-
|
|
2148
|
+
var AttachToContextToggle = ({ checked, onChange, contextLabel }) => /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-2 text-xs text-muted-foreground cursor-pointer select-none p-2 rounded-md border border-border bg-muted/30", children: [
|
|
2149
|
+
/* @__PURE__ */ jsx(
|
|
2150
|
+
"input",
|
|
2151
|
+
{
|
|
2152
|
+
type: "checkbox",
|
|
2153
|
+
checked,
|
|
2154
|
+
onChange: (e) => onChange(e.target.checked),
|
|
2155
|
+
className: "mt-0.5 cursor-pointer"
|
|
2156
|
+
}
|
|
2157
|
+
),
|
|
2158
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2159
|
+
/* @__PURE__ */ jsxs("span", { className: "font-medium text-foreground", children: [
|
|
2160
|
+
"Attach to ",
|
|
2161
|
+
contextLabel
|
|
2162
|
+
] }),
|
|
2163
|
+
/* @__PURE__ */ jsx("span", { className: "block", children: checked ? `Asset will be tagged to ${contextLabel}.` : `Asset will be added to the collection (available everywhere). Tick to attach it to ${contextLabel} instead.` })
|
|
2164
|
+
] })
|
|
2165
|
+
] });
|
|
2166
|
+
var ScopedAssetBrowser = ({ scope: _scope, accept: _accept, pageSize: _pageSize, viewMode, search, selectedIds, onToggleSelect, onDoubleClickSelect, onDelete, allowDelete, emptyText, listAppId: _listAppId, requireProductId, currentAppId, currentAppName, getAppName, assets, loading, error, refresh, remove, updateAsset, replaceFile }) => {
|
|
2030
2167
|
const replaceInputRef = React7.useRef(null);
|
|
2031
2168
|
const replaceTargetRef = React7.useRef(null);
|
|
2032
2169
|
const handleRename = useCallback(async (asset2) => {
|
|
@@ -2250,13 +2387,55 @@ var AssetPickerContent = ({
|
|
|
2250
2387
|
}
|
|
2251
2388
|
return scope;
|
|
2252
2389
|
}, [scope, productScope, scopeTab, hasProductScope]);
|
|
2253
|
-
const
|
|
2390
|
+
const collectionScope = useMemo(() => {
|
|
2391
|
+
const cId = scope.collectionId;
|
|
2392
|
+
return cId ? { type: "collection", collectionId: cId } : null;
|
|
2393
|
+
}, [scope]);
|
|
2394
|
+
const contextScope = useMemo(() => {
|
|
2395
|
+
if (scope.type === "proof") return scope;
|
|
2396
|
+
if (scope.type === "product") return scope;
|
|
2397
|
+
if (productScope) {
|
|
2398
|
+
return { type: "product", collectionId: productScope.collectionId, productId: productScope.productId };
|
|
2399
|
+
}
|
|
2400
|
+
return null;
|
|
2401
|
+
}, [scope, productScope]);
|
|
2402
|
+
const contextLabel = contextScope?.type === "proof" ? "this proof" : "this product";
|
|
2403
|
+
const hasContext = !!contextScope && !!collectionScope;
|
|
2404
|
+
const [attachToContext, setAttachToContext] = useState(true);
|
|
2405
|
+
const uploadScope = useMemo(() => {
|
|
2406
|
+
if (hasContext) return attachToContext ? contextScope : collectionScope;
|
|
2407
|
+
return activeScope;
|
|
2408
|
+
}, [hasContext, attachToContext, contextScope, collectionScope, activeScope]);
|
|
2409
|
+
const {
|
|
2410
|
+
assets,
|
|
2411
|
+
loading: assetsLoading,
|
|
2412
|
+
error: assetsError,
|
|
2413
|
+
refresh: refreshAssets,
|
|
2414
|
+
upload,
|
|
2415
|
+
uploadFromUrl,
|
|
2416
|
+
uploadFromRemoteUrl,
|
|
2417
|
+
remove,
|
|
2418
|
+
updateAsset,
|
|
2419
|
+
replaceFile,
|
|
2420
|
+
uploading,
|
|
2421
|
+
uploadProgress
|
|
2422
|
+
} = useAssets({
|
|
2254
2423
|
scope: activeScope,
|
|
2255
2424
|
accept: acceptProp,
|
|
2256
2425
|
pageSize,
|
|
2257
2426
|
appId: uploadGlobal ? void 0 : appId,
|
|
2258
2427
|
listAppId
|
|
2259
2428
|
});
|
|
2429
|
+
const reconcileAfterUpload = useCallback(async (uploadedScope) => {
|
|
2430
|
+
if (hasProductScope) {
|
|
2431
|
+
const desiredTab = uploadedScope.type === "product" ? "product" : "collection";
|
|
2432
|
+
if (desiredTab !== scopeTab) {
|
|
2433
|
+
setScopeTab(desiredTab);
|
|
2434
|
+
return;
|
|
2435
|
+
}
|
|
2436
|
+
}
|
|
2437
|
+
await refreshAssets();
|
|
2438
|
+
}, [hasProductScope, scopeTab, refreshAssets]);
|
|
2260
2439
|
const toSelection = useCallback((asset2) => ({
|
|
2261
2440
|
id: asset2.id,
|
|
2262
2441
|
url: asset2.url,
|
|
@@ -2293,34 +2472,46 @@ var AssetPickerContent = ({
|
|
|
2293
2472
|
});
|
|
2294
2473
|
}, [multiple, onSelect, onConfirm, toSelection]);
|
|
2295
2474
|
const handleUploadFiles = useCallback(async (files) => {
|
|
2475
|
+
const targetScope = uploadScope;
|
|
2476
|
+
const sameAsActive = targetScope === activeScope;
|
|
2296
2477
|
for (const file of files) {
|
|
2297
|
-
const result = await upload(file);
|
|
2478
|
+
const result = await upload(file, void 0, sameAsActive ? void 0 : targetScope);
|
|
2298
2479
|
if (result && !multiple) {
|
|
2299
2480
|
setSelectedIds(/* @__PURE__ */ new Set([result.id]));
|
|
2300
2481
|
onSelect?.(toSelection(result));
|
|
2301
2482
|
}
|
|
2302
2483
|
}
|
|
2303
2484
|
setTab("browse");
|
|
2304
|
-
|
|
2485
|
+
await reconcileAfterUpload(targetScope);
|
|
2486
|
+
}, [upload, multiple, onSelect, toSelection, uploadScope, activeScope, reconcileAfterUpload]);
|
|
2305
2487
|
const handleUrlImport = useCallback(async (url, name) => {
|
|
2306
|
-
const
|
|
2488
|
+
const targetScope = uploadScope;
|
|
2489
|
+
const sameAsActive = targetScope === activeScope;
|
|
2490
|
+
const result = await uploadFromUrl(url, name, sameAsActive ? void 0 : targetScope);
|
|
2307
2491
|
if (result) {
|
|
2308
2492
|
setTab("browse");
|
|
2309
2493
|
if (!multiple) {
|
|
2310
2494
|
setSelectedIds(/* @__PURE__ */ new Set([result.id]));
|
|
2311
2495
|
onSelect?.(toSelection(result));
|
|
2312
2496
|
}
|
|
2497
|
+
await reconcileAfterUpload(targetScope);
|
|
2313
2498
|
}
|
|
2314
2499
|
return result;
|
|
2315
|
-
}, [uploadFromUrl, multiple, onSelect, toSelection]);
|
|
2500
|
+
}, [uploadFromUrl, multiple, onSelect, toSelection, uploadScope, activeScope, reconcileAfterUpload]);
|
|
2316
2501
|
const handleRemoteIngest = useCallback(async (url, name) => {
|
|
2317
|
-
const
|
|
2502
|
+
const targetScope = uploadScope;
|
|
2503
|
+
const sameAsActive = targetScope === activeScope;
|
|
2504
|
+
const result = await uploadFromRemoteUrl(url, {
|
|
2505
|
+
name,
|
|
2506
|
+
...sameAsActive ? {} : { scopeOverride: targetScope }
|
|
2507
|
+
});
|
|
2318
2508
|
if (result && !multiple) {
|
|
2319
2509
|
setSelectedIds(/* @__PURE__ */ new Set([result.id]));
|
|
2320
2510
|
onSelect?.(toSelection(result));
|
|
2321
2511
|
}
|
|
2512
|
+
if (result) await reconcileAfterUpload(targetScope);
|
|
2322
2513
|
return result;
|
|
2323
|
-
}, [uploadFromRemoteUrl, multiple, onSelect, toSelection]);
|
|
2514
|
+
}, [uploadFromRemoteUrl, multiple, onSelect, toSelection, uploadScope, activeScope, reconcileAfterUpload]);
|
|
2324
2515
|
const handleDelete = useCallback(async (assetId) => {
|
|
2325
2516
|
setSelectedIds((prev) => {
|
|
2326
2517
|
const next = new Set(prev);
|
|
@@ -2508,11 +2699,26 @@ var AssetPickerContent = ({
|
|
|
2508
2699
|
requireProductId: hasProductScope && scopeTab === "product" ? productScope.productId : void 0,
|
|
2509
2700
|
currentAppId: appId,
|
|
2510
2701
|
currentAppName: resolvedAppName,
|
|
2511
|
-
getAppName
|
|
2702
|
+
getAppName,
|
|
2703
|
+
assets,
|
|
2704
|
+
loading: assetsLoading,
|
|
2705
|
+
error: assetsError,
|
|
2706
|
+
refresh: refreshAssets,
|
|
2707
|
+
remove,
|
|
2708
|
+
updateAsset,
|
|
2709
|
+
replaceFile
|
|
2512
2710
|
},
|
|
2513
2711
|
`${activeScope.type}-${activeScope.productId || ""}-${effectiveAccept || "all"}-${listAppId || "no-app-filter"}`
|
|
2514
2712
|
),
|
|
2515
2713
|
tab === "upload" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2714
|
+
hasContext && /* @__PURE__ */ jsx(
|
|
2715
|
+
AttachToContextToggle,
|
|
2716
|
+
{
|
|
2717
|
+
checked: attachToContext,
|
|
2718
|
+
onChange: setAttachToContext,
|
|
2719
|
+
contextLabel
|
|
2720
|
+
}
|
|
2721
|
+
),
|
|
2516
2722
|
hasAppFilter && /* @__PURE__ */ jsx(
|
|
2517
2723
|
GlobalUploadToggle,
|
|
2518
2724
|
{
|
|
@@ -2534,6 +2740,14 @@ var AssetPickerContent = ({
|
|
|
2534
2740
|
)
|
|
2535
2741
|
] }),
|
|
2536
2742
|
tab === "url" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2743
|
+
hasContext && /* @__PURE__ */ jsx(
|
|
2744
|
+
AttachToContextToggle,
|
|
2745
|
+
{
|
|
2746
|
+
checked: attachToContext,
|
|
2747
|
+
onChange: setAttachToContext,
|
|
2748
|
+
contextLabel
|
|
2749
|
+
}
|
|
2750
|
+
),
|
|
2537
2751
|
hasAppFilter && /* @__PURE__ */ jsx(
|
|
2538
2752
|
GlobalUploadToggle,
|
|
2539
2753
|
{
|
|
@@ -2551,6 +2765,14 @@ var AssetPickerContent = ({
|
|
|
2551
2765
|
)
|
|
2552
2766
|
] }),
|
|
2553
2767
|
tab === "ai" && aiEnabled && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2768
|
+
hasContext && /* @__PURE__ */ jsx(
|
|
2769
|
+
AttachToContextToggle,
|
|
2770
|
+
{
|
|
2771
|
+
checked: attachToContext,
|
|
2772
|
+
onChange: setAttachToContext,
|
|
2773
|
+
contextLabel
|
|
2774
|
+
}
|
|
2775
|
+
),
|
|
2554
2776
|
hasAppFilter && /* @__PURE__ */ jsx(
|
|
2555
2777
|
GlobalUploadToggle,
|
|
2556
2778
|
{
|
|
@@ -2569,6 +2791,14 @@ var AssetPickerContent = ({
|
|
|
2569
2791
|
)
|
|
2570
2792
|
] }),
|
|
2571
2793
|
tab === "stock" && stockEnabled && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2794
|
+
hasContext && /* @__PURE__ */ jsx(
|
|
2795
|
+
AttachToContextToggle,
|
|
2796
|
+
{
|
|
2797
|
+
checked: attachToContext,
|
|
2798
|
+
onChange: setAttachToContext,
|
|
2799
|
+
contextLabel
|
|
2800
|
+
}
|
|
2801
|
+
),
|
|
2572
2802
|
hasAppFilter && /* @__PURE__ */ jsx(
|
|
2573
2803
|
GlobalUploadToggle,
|
|
2574
2804
|
{
|
|
@@ -2611,7 +2841,7 @@ var AssetPickerContent = ({
|
|
|
2611
2841
|
};
|
|
2612
2842
|
var PickerDialog = ({ open, onClose, maxWidth, children }) => {
|
|
2613
2843
|
if (!open) return null;
|
|
2614
|
-
|
|
2844
|
+
const node = /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-[2147483600] flex items-center justify-center", children: [
|
|
2615
2845
|
/* @__PURE__ */ jsx(
|
|
2616
2846
|
"div",
|
|
2617
2847
|
{
|
|
@@ -2645,6 +2875,8 @@ var PickerDialog = ({ open, onClose, maxWidth, children }) => {
|
|
|
2645
2875
|
}
|
|
2646
2876
|
)
|
|
2647
2877
|
] });
|
|
2878
|
+
if (typeof document === "undefined") return node;
|
|
2879
|
+
return createPortal(node, document.body);
|
|
2648
2880
|
};
|
|
2649
2881
|
var AssetPicker = (props) => {
|
|
2650
2882
|
const { mode = "inline", open: controlledOpen, onClose, trigger, onSelect, multiple, className, dialogMaxWidth } = props;
|
|
@@ -2678,5 +2910,5 @@ var AssetPicker = (props) => {
|
|
|
2678
2910
|
assertStylesLoaded();
|
|
2679
2911
|
|
|
2680
2912
|
export { ASSET_MIME_FILTERS, AssetPicker, useAppRegistry, useAssets };
|
|
2681
|
-
//# sourceMappingURL=chunk-
|
|
2682
|
-
//# sourceMappingURL=chunk-
|
|
2913
|
+
//# sourceMappingURL=chunk-VP4LZEEZ.js.map
|
|
2914
|
+
//# sourceMappingURL=chunk-VP4LZEEZ.js.map
|