@proveanything/smartlinks-utils-ui 1.13.2 → 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.
@@ -1,9 +1,9 @@
1
1
  import { assertStylesLoaded } from './chunk-OLYC54YT.js';
2
2
  import { cn } from './chunk-L7FQ52F5.js';
3
3
  import React7, { useState, useRef, useEffect, useCallback, useMemo, useLayoutEffect } from 'react';
4
- import * as SL from '@proveanything/smartlinks';
5
4
  import { createPortal } from 'react-dom';
6
- import { Filter, Search, LayoutGrid, List, X, Loader2, AlertCircle, Tag, 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';
5
+ import * as SL from '@proveanything/smartlinks';
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';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
8
 
9
9
  // src/components/AssetPicker/types.ts
@@ -15,6 +15,66 @@ var ASSET_MIME_FILTERS = [
15
15
  { value: "document", label: "Documents", prefix: "application/" },
16
16
  { value: "pdf", label: "PDFs", prefix: "application/pdf" }
17
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
+ }
18
78
  function useAssets({ scope, accept, pageSize, appId, listAppId }) {
19
79
  const [assets, setAssets] = useState([]);
20
80
  const [loading, setLoading] = useState(true);
@@ -42,7 +102,19 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
42
102
  ...listAppId ? { appId: listAppId } : {}
43
103
  });
44
104
  if (mountedRef.current) {
45
- setAssets(result);
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);
46
118
  }
47
119
  } catch (err) {
48
120
  if (mountedRef.current) {
@@ -72,7 +144,7 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
72
144
  }
73
145
  });
74
146
  if (mountedRef.current && !scopeOverride) {
75
- setAssets((prev) => [result, ...prev]);
147
+ setAssets((prev) => dedupeAssetList([result, ...prev]));
76
148
  }
77
149
  return result;
78
150
  } catch (err) {
@@ -117,7 +189,7 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
117
189
  admin: true
118
190
  });
119
191
  if (mountedRef.current && !opts?.scopeOverride) {
120
- setAssets((prev) => [result, ...prev]);
192
+ setAssets((prev) => dedupeAssetList([result, ...prev]));
121
193
  }
122
194
  return result;
123
195
  } catch (err) {
@@ -156,10 +228,10 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
156
228
  try {
157
229
  const result = await SL.asset.restoreAdmin(collectionId, assetId);
158
230
  if (mountedRef.current) {
159
- setAssets((prev) => {
231
+ setAssets((prev) => dedupeAssetList((() => {
160
232
  const exists = prev.some((a) => a.id === assetId);
161
233
  return exists ? prev.map((a) => a.id === assetId ? result : a) : [result, ...prev];
162
- });
234
+ })()));
163
235
  }
164
236
  return result;
165
237
  } catch (err) {
@@ -186,7 +258,7 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
186
258
  }
187
259
  });
188
260
  if (mountedRef.current) {
189
- setAssets((prev) => prev.map((a) => a.id === assetId ? result : a));
261
+ setAssets((prev) => dedupeAssetList(prev.map((a) => a.id === assetId ? result : a)));
190
262
  }
191
263
  return result;
192
264
  } catch (err) {
@@ -208,7 +280,7 @@ function useAssets({ scope, accept, pageSize, appId, listAppId }) {
208
280
  try {
209
281
  const result = await SL.asset.updateAdmin({ collectionId, assetId, ...patch });
210
282
  if (mountedRef.current) {
211
- setAssets((prev) => prev.map((a) => a.id === assetId ? result : a));
283
+ setAssets((prev) => dedupeAssetList(prev.map((a) => a.id === assetId ? result : a)));
212
284
  }
213
285
  return result;
214
286
  } catch (err) {
@@ -436,7 +508,7 @@ var CardMenu = ({ onRename, onReplace, onEditTags, onDelete, position = "absolut
436
508
  "div",
437
509
  {
438
510
  ref: menuRef,
439
- className: "fixed z-[1000] min-w-[160px] rounded-md border border-border bg-popover text-popover-foreground shadow-lg py-1",
511
+ className: "fixed z-[2147483647] min-w-[160px] rounded-md border border-border bg-popover text-popover-foreground shadow-lg py-1",
440
512
  style: pos ? { top: pos.top, left: pos.left } : { visibility: "hidden", top: 0, left: 0 },
441
513
  role: "menu",
442
514
  onClick: (e) => e.stopPropagation(),
@@ -2769,7 +2841,7 @@ var AssetPickerContent = ({
2769
2841
  };
2770
2842
  var PickerDialog = ({ open, onClose, maxWidth, children }) => {
2771
2843
  if (!open) return null;
2772
- return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [
2844
+ const node = /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-[2147483600] flex items-center justify-center", children: [
2773
2845
  /* @__PURE__ */ jsx(
2774
2846
  "div",
2775
2847
  {
@@ -2803,6 +2875,8 @@ var PickerDialog = ({ open, onClose, maxWidth, children }) => {
2803
2875
  }
2804
2876
  )
2805
2877
  ] });
2878
+ if (typeof document === "undefined") return node;
2879
+ return createPortal(node, document.body);
2806
2880
  };
2807
2881
  var AssetPicker = (props) => {
2808
2882
  const { mode = "inline", open: controlledOpen, onClose, trigger, onSelect, multiple, className, dialogMaxWidth } = props;
@@ -2836,5 +2910,5 @@ var AssetPicker = (props) => {
2836
2910
  assertStylesLoaded();
2837
2911
 
2838
2912
  export { ASSET_MIME_FILTERS, AssetPicker, useAppRegistry, useAssets };
2839
- //# sourceMappingURL=chunk-AWWWHHLL.js.map
2840
- //# sourceMappingURL=chunk-AWWWHHLL.js.map
2913
+ //# sourceMappingURL=chunk-VP4LZEEZ.js.map
2914
+ //# sourceMappingURL=chunk-VP4LZEEZ.js.map