canvu-react 0.3.10 → 0.3.12
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/asset-hydration-3Iv5xHxM.d.cts +27 -0
- package/dist/asset-hydration-BEG21hMp.d.ts +27 -0
- package/dist/chatbot.d.cts +2 -2
- package/dist/chatbot.d.ts +2 -2
- package/dist/index.cjs +469 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +468 -9
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +645 -704
- package/dist/native.cjs.map +1 -1
- package/dist/native.js +645 -704
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +354 -137
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +9 -16
- package/dist/react.d.ts +9 -16
- package/dist/react.js +354 -138
- package/dist/react.js.map +1 -1
- package/dist/realtime.cjs +566 -55
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +40 -5
- package/dist/realtime.d.ts +40 -5
- package/dist/realtime.js +566 -56
- package/dist/realtime.js.map +1 -1
- package/dist/{shape-builders-DxPoOecg.d.cts → shape-builders-DFudWDFI.d.cts} +111 -1
- package/dist/{shape-builders-DTYvub8W.d.ts → shape-builders-ENwnK-zT.d.ts} +111 -1
- package/dist/{types-DgEArHkA.d.ts → types-BtAJFS_-.d.ts} +1 -0
- package/dist/{types-BtLGGw0r.d.cts → types-CTyASYIm.d.cts} +2 -105
- package/dist/{types-B58i5k-u.d.cts → types-DNwjgs5U.d.cts} +1 -0
- package/dist/{types-ChnTSRSe.d.ts → types-UvUy2Eed.d.ts} +2 -105
- package/package.json +1 -1
package/dist/react.cjs
CHANGED
|
@@ -928,35 +928,336 @@ function canvasToBlob2(canvas, mime, quality) {
|
|
|
928
928
|
);
|
|
929
929
|
});
|
|
930
930
|
}
|
|
931
|
+
function normalizePdfPageNumbers(pageNumbers, pageCount) {
|
|
932
|
+
if (!pageNumbers || pageNumbers.length === 0) {
|
|
933
|
+
return Array.from({ length: pageCount }, (_, index) => index + 1);
|
|
934
|
+
}
|
|
935
|
+
return [...new Set(pageNumbers)].filter((pageNumber) => pageNumber >= 1 && pageNumber <= pageCount).sort((left, right) => left - right);
|
|
936
|
+
}
|
|
937
|
+
async function runWithConcurrency(items, concurrency, execute) {
|
|
938
|
+
const results = new Array(items.length);
|
|
939
|
+
let nextIndex = 0;
|
|
940
|
+
const workerCount = Math.max(1, Math.min(concurrency, items.length));
|
|
941
|
+
await Promise.all(
|
|
942
|
+
Array.from({ length: workerCount }, async () => {
|
|
943
|
+
while (nextIndex < items.length) {
|
|
944
|
+
const currentIndex = nextIndex;
|
|
945
|
+
nextIndex += 1;
|
|
946
|
+
const item = items[currentIndex];
|
|
947
|
+
if (item === void 0) {
|
|
948
|
+
continue;
|
|
949
|
+
}
|
|
950
|
+
results[currentIndex] = await execute(item);
|
|
951
|
+
}
|
|
952
|
+
})
|
|
953
|
+
);
|
|
954
|
+
return results;
|
|
955
|
+
}
|
|
931
956
|
async function loadPdfToStore(file, store, options) {
|
|
932
957
|
const scale = options?.scale ?? 1.5;
|
|
958
|
+
const pageConcurrency = options?.pageConcurrency ?? 2;
|
|
933
959
|
const pdfjs = await getPdfJs();
|
|
934
960
|
const arrayBuffer = await file.arrayBuffer();
|
|
935
961
|
const pdf = await pdfjs.getDocument({ data: arrayBuffer }).promise;
|
|
936
|
-
const
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
tCtx
|
|
953
|
-
tCtx
|
|
962
|
+
const pageNumbers = normalizePdfPageNumbers(options?.pageNumbers, pdf.numPages);
|
|
963
|
+
return await runWithConcurrency(
|
|
964
|
+
pageNumbers,
|
|
965
|
+
pageConcurrency,
|
|
966
|
+
async (pageNumber) => {
|
|
967
|
+
const page = await pdf.getPage(pageNumber);
|
|
968
|
+
const { canvas, width, height } = await renderPageToCanvas(page, scale);
|
|
969
|
+
const mime = "image/png";
|
|
970
|
+
const pageBlob = await canvasToBlob2(canvas, mime);
|
|
971
|
+
const blobId = await store.storeOriginal(pageBlob);
|
|
972
|
+
const thumbScale = Math.min(1, 256 / Math.max(width, height));
|
|
973
|
+
const tw = Math.max(1, Math.round(width * thumbScale));
|
|
974
|
+
const th = Math.max(1, Math.round(height * thumbScale));
|
|
975
|
+
const thumbCanvas = document.createElement("canvas");
|
|
976
|
+
thumbCanvas.width = tw;
|
|
977
|
+
thumbCanvas.height = th;
|
|
978
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
979
|
+
if (tCtx) {
|
|
980
|
+
tCtx.imageSmoothingEnabled = true;
|
|
981
|
+
tCtx.imageSmoothingQuality = "high";
|
|
982
|
+
tCtx.drawImage(canvas, 0, 0, tw, th);
|
|
983
|
+
}
|
|
984
|
+
const thumbBlob = await canvasToBlob2(thumbCanvas, mime);
|
|
985
|
+
const thumbnailBlobId = await store.storeThumbnail(thumbBlob);
|
|
986
|
+
return {
|
|
987
|
+
blobId,
|
|
988
|
+
thumbnailBlobId,
|
|
989
|
+
width,
|
|
990
|
+
height,
|
|
991
|
+
pageNumber
|
|
992
|
+
};
|
|
954
993
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// src/react/asset-hydration.ts
|
|
998
|
+
init_shape_builders();
|
|
999
|
+
var HYDRATION_CACHE_NAME = "canvu-asset-hydration-v1";
|
|
1000
|
+
var DEFAULT_PDF_SCALE = 1.15;
|
|
1001
|
+
var DEFAULT_PDF_PAGE_CONCURRENCY = 2;
|
|
1002
|
+
var hydrationBlobPromises = /* @__PURE__ */ new Map();
|
|
1003
|
+
function buildImageHydrationKey(assetId) {
|
|
1004
|
+
return `image:${assetId}`;
|
|
1005
|
+
}
|
|
1006
|
+
function buildPdfHydrationKey(assetId, pageNumber, scale) {
|
|
1007
|
+
return `pdf:${assetId}:page:${pageNumber}:scale:${scale}`;
|
|
1008
|
+
}
|
|
1009
|
+
function getCacheRequest(key) {
|
|
1010
|
+
return new Request(
|
|
1011
|
+
`https://canvu.local/asset-hydration/${encodeURIComponent(key)}`
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
1014
|
+
async function openHydrationCache() {
|
|
1015
|
+
if (typeof caches === "undefined") return null;
|
|
1016
|
+
try {
|
|
1017
|
+
return await caches.open(HYDRATION_CACHE_NAME);
|
|
1018
|
+
} catch {
|
|
1019
|
+
return null;
|
|
958
1020
|
}
|
|
959
|
-
|
|
1021
|
+
}
|
|
1022
|
+
async function readCachedHydrationBlob(key) {
|
|
1023
|
+
const cache = await openHydrationCache();
|
|
1024
|
+
if (!cache) return null;
|
|
1025
|
+
try {
|
|
1026
|
+
const response = await cache.match(getCacheRequest(key));
|
|
1027
|
+
if (!response?.ok) return null;
|
|
1028
|
+
return await response.blob();
|
|
1029
|
+
} catch {
|
|
1030
|
+
return null;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
async function writeCachedHydrationBlob(key, blob) {
|
|
1034
|
+
const cache = await openHydrationCache();
|
|
1035
|
+
if (!cache) return;
|
|
1036
|
+
try {
|
|
1037
|
+
await cache.put(getCacheRequest(key), new Response(blob));
|
|
1038
|
+
} catch {
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
async function fetchBlob(url) {
|
|
1042
|
+
try {
|
|
1043
|
+
const response = await fetch(url);
|
|
1044
|
+
if (!response.ok) return null;
|
|
1045
|
+
return await response.blob();
|
|
1046
|
+
} catch {
|
|
1047
|
+
return null;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
async function getHydrationBlob(key, preferCachedRasters, loader) {
|
|
1051
|
+
const cached = preferCachedRasters ? await readCachedHydrationBlob(key) : null;
|
|
1052
|
+
if (cached) return cached;
|
|
1053
|
+
const inFlight = hydrationBlobPromises.get(key);
|
|
1054
|
+
if (inFlight) return await inFlight;
|
|
1055
|
+
const nextPromise = (async () => {
|
|
1056
|
+
const blob = await loader();
|
|
1057
|
+
if (blob) {
|
|
1058
|
+
await writeCachedHydrationBlob(key, blob);
|
|
1059
|
+
}
|
|
1060
|
+
return blob;
|
|
1061
|
+
})();
|
|
1062
|
+
hydrationBlobPromises.set(key, nextPromise);
|
|
1063
|
+
try {
|
|
1064
|
+
return await nextPromise;
|
|
1065
|
+
} finally {
|
|
1066
|
+
hydrationBlobPromises.delete(key);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
function registerObjectUrl(objectUrls, blob) {
|
|
1070
|
+
const href = URL.createObjectURL(blob);
|
|
1071
|
+
objectUrls.push(href);
|
|
1072
|
+
return href;
|
|
1073
|
+
}
|
|
1074
|
+
function getHydrationRequests(items, assetStore, pdfScale) {
|
|
1075
|
+
if (!assetStore.getHydrationRequest) return [];
|
|
1076
|
+
return items.flatMap((item) => {
|
|
1077
|
+
const request = assetStore.getHydrationRequest?.(item);
|
|
1078
|
+
if (!request) return [];
|
|
1079
|
+
return [
|
|
1080
|
+
{
|
|
1081
|
+
request: {
|
|
1082
|
+
...request,
|
|
1083
|
+
scale: request.scale ?? pdfScale
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
];
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
function createPdfHydrationGroups(requests) {
|
|
1090
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1091
|
+
for (const entry of requests) {
|
|
1092
|
+
if (entry.request.kind !== "pdf" || entry.request.pageNumber == null) continue;
|
|
1093
|
+
const scale = entry.request.scale ?? DEFAULT_PDF_SCALE;
|
|
1094
|
+
const key = `${entry.request.assetId}:${scale}`;
|
|
1095
|
+
const existingGroup = groups.get(key);
|
|
1096
|
+
if (existingGroup) {
|
|
1097
|
+
if (!existingGroup.pageNumbers.includes(entry.request.pageNumber)) {
|
|
1098
|
+
existingGroup.pageNumbers.push(entry.request.pageNumber);
|
|
1099
|
+
}
|
|
1100
|
+
continue;
|
|
1101
|
+
}
|
|
1102
|
+
groups.set(key, {
|
|
1103
|
+
assetId: entry.request.assetId,
|
|
1104
|
+
scale,
|
|
1105
|
+
pageNumbers: [entry.request.pageNumber]
|
|
1106
|
+
});
|
|
1107
|
+
}
|
|
1108
|
+
return [...groups.values()];
|
|
1109
|
+
}
|
|
1110
|
+
async function hydrateImageAssets(requests, resolvedAssetUrls, objectUrls, preferCachedRasters) {
|
|
1111
|
+
const uniqueAssetIds = [
|
|
1112
|
+
...new Set(requests.map((entry) => entry.request.assetId))
|
|
1113
|
+
];
|
|
1114
|
+
const hydratedEntries = await Promise.all(
|
|
1115
|
+
uniqueAssetIds.map(async (assetId) => {
|
|
1116
|
+
const resolvedAsset = resolvedAssetUrls[assetId];
|
|
1117
|
+
if (!resolvedAsset?.url) {
|
|
1118
|
+
return [assetId, null];
|
|
1119
|
+
}
|
|
1120
|
+
const blob = await getHydrationBlob(
|
|
1121
|
+
buildImageHydrationKey(assetId),
|
|
1122
|
+
preferCachedRasters,
|
|
1123
|
+
async () => await fetchBlob(resolvedAsset.url)
|
|
1124
|
+
);
|
|
1125
|
+
if (!blob) {
|
|
1126
|
+
return [assetId, null];
|
|
1127
|
+
}
|
|
1128
|
+
return [
|
|
1129
|
+
assetId,
|
|
1130
|
+
{
|
|
1131
|
+
href: registerObjectUrl(objectUrls, blob)
|
|
1132
|
+
}
|
|
1133
|
+
];
|
|
1134
|
+
})
|
|
1135
|
+
);
|
|
1136
|
+
return new Map(hydratedEntries);
|
|
1137
|
+
}
|
|
1138
|
+
async function hydratePdfAssets(requests, resolvedAssetUrls, objectUrls, options) {
|
|
1139
|
+
const hydratedPages = /* @__PURE__ */ new Map();
|
|
1140
|
+
const groups = createPdfHydrationGroups(requests);
|
|
1141
|
+
for (const group of groups) {
|
|
1142
|
+
const resolvedAsset = resolvedAssetUrls[group.assetId];
|
|
1143
|
+
if (!resolvedAsset?.url) {
|
|
1144
|
+
continue;
|
|
1145
|
+
}
|
|
1146
|
+
const missingPages = [];
|
|
1147
|
+
for (const pageNumber of group.pageNumbers) {
|
|
1148
|
+
const cacheKey = buildPdfHydrationKey(group.assetId, pageNumber, group.scale);
|
|
1149
|
+
const cachedBlob = await readCachedHydrationBlob(cacheKey);
|
|
1150
|
+
if (!cachedBlob) {
|
|
1151
|
+
missingPages.push(pageNumber);
|
|
1152
|
+
continue;
|
|
1153
|
+
}
|
|
1154
|
+
hydratedPages.set(cacheKey, {
|
|
1155
|
+
href: registerObjectUrl(objectUrls, cachedBlob)
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
if (missingPages.length === 0) {
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
const pdfBlob = await fetchBlob(resolvedAsset.url);
|
|
1162
|
+
if (!pdfBlob) {
|
|
1163
|
+
continue;
|
|
1164
|
+
}
|
|
1165
|
+
const renderedPages = await loadPdfToStore(pdfBlob, options.imageStore, {
|
|
1166
|
+
scale: group.scale,
|
|
1167
|
+
pageNumbers: missingPages,
|
|
1168
|
+
pageConcurrency: options.pdfPageConcurrency
|
|
1169
|
+
});
|
|
1170
|
+
for (const renderedPage of renderedPages) {
|
|
1171
|
+
const cacheKey = buildPdfHydrationKey(
|
|
1172
|
+
group.assetId,
|
|
1173
|
+
renderedPage.pageNumber,
|
|
1174
|
+
group.scale
|
|
1175
|
+
);
|
|
1176
|
+
const pageBlob = await options.imageStore.getOriginal(renderedPage.blobId);
|
|
1177
|
+
if (!pageBlob) {
|
|
1178
|
+
continue;
|
|
1179
|
+
}
|
|
1180
|
+
await writeCachedHydrationBlob(cacheKey, pageBlob);
|
|
1181
|
+
hydratedPages.set(cacheKey, {
|
|
1182
|
+
href: registerObjectUrl(objectUrls, pageBlob),
|
|
1183
|
+
width: renderedPage.width,
|
|
1184
|
+
height: renderedPage.height
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
return hydratedPages;
|
|
1189
|
+
}
|
|
1190
|
+
async function hydrateSceneItemsWithAssets(items, assetStore, options = {}) {
|
|
1191
|
+
if (!assetStore.resolve || !assetStore.getHydrationRequest) {
|
|
1192
|
+
return {
|
|
1193
|
+
items: [...items],
|
|
1194
|
+
objectUrls: []
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
const pdfScale = options.pdfScale ?? DEFAULT_PDF_SCALE;
|
|
1198
|
+
const pdfPageConcurrency = options.pdfPageConcurrency ?? DEFAULT_PDF_PAGE_CONCURRENCY;
|
|
1199
|
+
const preferCachedRasters = options.preferCachedRasters ?? true;
|
|
1200
|
+
const imageStore = options.imageStore ?? new IndexedDbImageStore();
|
|
1201
|
+
const hydrationRequests = getHydrationRequests(items, assetStore, pdfScale);
|
|
1202
|
+
if (hydrationRequests.length === 0) {
|
|
1203
|
+
return {
|
|
1204
|
+
items: [...items],
|
|
1205
|
+
objectUrls: []
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
const assetIds = [
|
|
1209
|
+
...new Set(hydrationRequests.map((entry) => entry.request.assetId))
|
|
1210
|
+
];
|
|
1211
|
+
const resolvedAssetUrls = await assetStore.resolve({ assetIds });
|
|
1212
|
+
const objectUrls = [];
|
|
1213
|
+
const hydratedImages = await hydrateImageAssets(
|
|
1214
|
+
hydrationRequests.filter((entry) => entry.request.kind === "image"),
|
|
1215
|
+
resolvedAssetUrls,
|
|
1216
|
+
objectUrls,
|
|
1217
|
+
preferCachedRasters
|
|
1218
|
+
);
|
|
1219
|
+
const hydratedPdfPages = await hydratePdfAssets(
|
|
1220
|
+
hydrationRequests.filter((entry) => entry.request.kind === "pdf"),
|
|
1221
|
+
resolvedAssetUrls,
|
|
1222
|
+
objectUrls,
|
|
1223
|
+
{
|
|
1224
|
+
imageStore,
|
|
1225
|
+
pdfPageConcurrency}
|
|
1226
|
+
);
|
|
1227
|
+
return {
|
|
1228
|
+
items: items.map((item) => {
|
|
1229
|
+
const request = assetStore.getHydrationRequest?.(item);
|
|
1230
|
+
if (!request || item.toolKind !== "image") return item;
|
|
1231
|
+
if (request.kind === "image") {
|
|
1232
|
+
const hydratedImage = hydratedImages.get(request.assetId);
|
|
1233
|
+
if (!hydratedImage) return item;
|
|
1234
|
+
return rebuildItemSvg({
|
|
1235
|
+
...item,
|
|
1236
|
+
imageRasterHref: hydratedImage.href,
|
|
1237
|
+
imageThumbnailHref: hydratedImage.href
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
if (request.pageNumber == null) return item;
|
|
1241
|
+
const hydratedPdfPage = hydratedPdfPages.get(
|
|
1242
|
+
buildPdfHydrationKey(
|
|
1243
|
+
request.assetId,
|
|
1244
|
+
request.pageNumber,
|
|
1245
|
+
request.scale ?? pdfScale
|
|
1246
|
+
)
|
|
1247
|
+
);
|
|
1248
|
+
if (!hydratedPdfPage) return item;
|
|
1249
|
+
return rebuildItemSvg({
|
|
1250
|
+
...item,
|
|
1251
|
+
imageRasterHref: hydratedPdfPage.href,
|
|
1252
|
+
imageThumbnailHref: hydratedPdfPage.href,
|
|
1253
|
+
imageIntrinsicSize: {
|
|
1254
|
+
width: item.imageIntrinsicSize?.width ?? Math.max(1, Math.round(hydratedPdfPage.width ?? item.bounds.width)),
|
|
1255
|
+
height: item.imageIntrinsicSize?.height ?? Math.max(1, Math.round(hydratedPdfPage.height ?? item.bounds.height))
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
}),
|
|
1259
|
+
objectUrls
|
|
1260
|
+
};
|
|
960
1261
|
}
|
|
961
1262
|
|
|
962
1263
|
// src/react/asset-ingestion.ts
|
|
@@ -999,6 +1300,7 @@ async function ingestAssetFilesToSceneItems(options) {
|
|
|
999
1300
|
gapWorld = 16,
|
|
1000
1301
|
stepWorld = 48,
|
|
1001
1302
|
pdfScale = 1.5,
|
|
1303
|
+
pdfPageConcurrency = 2,
|
|
1002
1304
|
decorateItem,
|
|
1003
1305
|
onError
|
|
1004
1306
|
} = options;
|
|
@@ -1020,9 +1322,14 @@ async function ingestAssetFilesToSceneItems(options) {
|
|
|
1020
1322
|
continue;
|
|
1021
1323
|
}
|
|
1022
1324
|
try {
|
|
1023
|
-
const uploadResult = await uploadAssetIfNeeded(assetStore, file, kind);
|
|
1024
1325
|
if (kind === "pdf") {
|
|
1025
|
-
const pages = await
|
|
1326
|
+
const [uploadResult2, pages] = await Promise.all([
|
|
1327
|
+
uploadAssetIfNeeded(assetStore, file, kind),
|
|
1328
|
+
loadPdfToStore(file, imageStore, {
|
|
1329
|
+
scale: pdfScale,
|
|
1330
|
+
pageConcurrency: pdfPageConcurrency
|
|
1331
|
+
})
|
|
1332
|
+
]);
|
|
1026
1333
|
for (const page of pages) {
|
|
1027
1334
|
const fullUrl2 = await createBlobUrlFromStore(imageStore, page.blobId);
|
|
1028
1335
|
const naturalTopY2 = worldCenter.y - page.height / 2;
|
|
@@ -1059,7 +1366,7 @@ async function ingestAssetFilesToSceneItems(options) {
|
|
|
1059
1366
|
) : ""
|
|
1060
1367
|
},
|
|
1061
1368
|
itemContext2,
|
|
1062
|
-
|
|
1369
|
+
uploadResult2,
|
|
1063
1370
|
decorateItem
|
|
1064
1371
|
);
|
|
1065
1372
|
items.push(item2);
|
|
@@ -1070,10 +1377,11 @@ async function ingestAssetFilesToSceneItems(options) {
|
|
|
1070
1377
|
imageYOffsetAdjustment = 0;
|
|
1071
1378
|
continue;
|
|
1072
1379
|
}
|
|
1073
|
-
const
|
|
1074
|
-
file,
|
|
1075
|
-
imageStore
|
|
1076
|
-
);
|
|
1380
|
+
const [uploadResult, storedImage] = await Promise.all([
|
|
1381
|
+
uploadAssetIfNeeded(assetStore, file, kind),
|
|
1382
|
+
loadImageToStore(file, imageStore)
|
|
1383
|
+
]);
|
|
1384
|
+
const { blobId, thumbnailBlobId, width, height } = storedImage;
|
|
1077
1385
|
const fullUrl = await createBlobUrlFromStore(imageStore, blobId);
|
|
1078
1386
|
const thumbBlob = await imageStore.getThumbnail(thumbnailBlobId);
|
|
1079
1387
|
const thumbnailHref = thumbBlob ? URL.createObjectURL(thumbBlob) : null;
|
|
@@ -4233,16 +4541,14 @@ function itemHitTestWorldPoint(item, worldX, worldY, options) {
|
|
|
4233
4541
|
return true;
|
|
4234
4542
|
}
|
|
4235
4543
|
}
|
|
4544
|
+
return false;
|
|
4236
4545
|
}
|
|
4237
|
-
if (pts
|
|
4546
|
+
if (pts && pts.length === 1) {
|
|
4238
4547
|
const p = pts[0];
|
|
4239
|
-
if (p)
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
return true;
|
|
4244
|
-
}
|
|
4245
|
-
}
|
|
4548
|
+
if (!p) return false;
|
|
4549
|
+
const cw = itemLocalToWorld(p.x, p.y, item.x, item.y, w, h, rot);
|
|
4550
|
+
const dsq = (worldX - cw.x) ** 2 + (worldY - cw.y) ** 2;
|
|
4551
|
+
return dsq <= tolSq;
|
|
4246
4552
|
}
|
|
4247
4553
|
return hitTestFilledShape(item, worldX, worldY);
|
|
4248
4554
|
}
|
|
@@ -4787,101 +5093,12 @@ init_shape_builders();
|
|
|
4787
5093
|
var HANDLE_ORDER = ["nw", "n", "ne", "e", "se", "s", "sw", "w"];
|
|
4788
5094
|
var ERASER_TINT = "#cbd5e1";
|
|
4789
5095
|
var ERASER_TINT_OPACITY = 0.95;
|
|
5096
|
+
var ERASER_PREVIEW_OPACITY = 0.3;
|
|
4790
5097
|
function pointsToSmoothPath(points) {
|
|
4791
5098
|
if (points.length === 0) return null;
|
|
4792
5099
|
const d = smoothFreehandPointsToPathD(points);
|
|
4793
5100
|
return d || null;
|
|
4794
5101
|
}
|
|
4795
|
-
function renderEraserSkeleton(it, overlayStrokePx) {
|
|
4796
|
-
const b = normalizeRect(it.bounds);
|
|
4797
|
-
const tool = it.toolKind;
|
|
4798
|
-
const strokeWidth = Math.max(it.strokeWidth ?? 2, overlayStrokePx);
|
|
4799
|
-
const common = {
|
|
4800
|
-
stroke: ERASER_TINT,
|
|
4801
|
-
strokeWidth,
|
|
4802
|
-
strokeOpacity: ERASER_TINT_OPACITY,
|
|
4803
|
-
vectorEffect: "non-scaling-stroke",
|
|
4804
|
-
strokeLinecap: "round",
|
|
4805
|
-
strokeLinejoin: "round",
|
|
4806
|
-
fill: "none"
|
|
4807
|
-
};
|
|
4808
|
-
if (tool === "rect") {
|
|
4809
|
-
return /* @__PURE__ */ jsxRuntime.jsx("rect", { x: 0, y: 0, width: b.width, height: b.height, ...common });
|
|
4810
|
-
}
|
|
4811
|
-
if (tool === "ellipse") {
|
|
4812
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4813
|
-
"ellipse",
|
|
4814
|
-
{
|
|
4815
|
-
cx: b.width / 2,
|
|
4816
|
-
cy: b.height / 2,
|
|
4817
|
-
rx: Math.max(0, b.width / 2),
|
|
4818
|
-
ry: Math.max(0, b.height / 2),
|
|
4819
|
-
...common
|
|
4820
|
-
}
|
|
4821
|
-
);
|
|
4822
|
-
}
|
|
4823
|
-
if (tool === "line" || tool === "arrow") {
|
|
4824
|
-
const ln = it.line;
|
|
4825
|
-
if (!ln)
|
|
4826
|
-
return /* @__PURE__ */ jsxRuntime.jsx("rect", { x: 0, y: 0, width: b.width, height: b.height, ...common });
|
|
4827
|
-
const geometry = tool === "arrow" ? computeStraightArrowGeometry(
|
|
4828
|
-
ln,
|
|
4829
|
-
Math.max(it.strokeWidth ?? 2, overlayStrokePx)
|
|
4830
|
-
) : null;
|
|
4831
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4832
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4833
|
-
"line",
|
|
4834
|
-
{
|
|
4835
|
-
x1: ln.x1,
|
|
4836
|
-
y1: ln.y1,
|
|
4837
|
-
x2: geometry?.shaftEndX ?? ln.x2,
|
|
4838
|
-
y2: geometry?.shaftEndY ?? ln.y2,
|
|
4839
|
-
...common
|
|
4840
|
-
}
|
|
4841
|
-
),
|
|
4842
|
-
tool === "arrow" && geometry ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4843
|
-
"path",
|
|
4844
|
-
{
|
|
4845
|
-
d: `M ${geometry.headLeftX} ${geometry.headLeftY} L ${geometry.headTipX} ${geometry.headTipY} L ${geometry.headRightX} ${geometry.headRightY}`,
|
|
4846
|
-
...common
|
|
4847
|
-
}
|
|
4848
|
-
) : null
|
|
4849
|
-
] });
|
|
4850
|
-
}
|
|
4851
|
-
if (tool === "draw" || tool === "marker" || tool === "pencil" || tool === "brush") {
|
|
4852
|
-
const pts = it.pathPointsLocal ?? [];
|
|
4853
|
-
if (pts.length === 1) {
|
|
4854
|
-
const p = pts[0];
|
|
4855
|
-
if (!p) return null;
|
|
4856
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4857
|
-
"circle",
|
|
4858
|
-
{
|
|
4859
|
-
cx: p.x,
|
|
4860
|
-
cy: p.y,
|
|
4861
|
-
r: Math.max((it.strokeWidth ?? 2) / 2, 2),
|
|
4862
|
-
fill: ERASER_TINT,
|
|
4863
|
-
fillOpacity: 0.8,
|
|
4864
|
-
vectorEffect: "non-scaling-stroke"
|
|
4865
|
-
}
|
|
4866
|
-
);
|
|
4867
|
-
}
|
|
4868
|
-
const d = pointsToSmoothPath(pts);
|
|
4869
|
-
if (d) {
|
|
4870
|
-
return /* @__PURE__ */ jsxRuntime.jsx("path", { d, ...common, shapeRendering: "geometricPrecision" });
|
|
4871
|
-
}
|
|
4872
|
-
}
|
|
4873
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4874
|
-
"rect",
|
|
4875
|
-
{
|
|
4876
|
-
x: 0,
|
|
4877
|
-
y: 0,
|
|
4878
|
-
width: b.width,
|
|
4879
|
-
height: b.height,
|
|
4880
|
-
...common,
|
|
4881
|
-
strokeDasharray: "4 4"
|
|
4882
|
-
}
|
|
4883
|
-
);
|
|
4884
|
-
}
|
|
4885
5102
|
function InteractionOverlay({
|
|
4886
5103
|
camera,
|
|
4887
5104
|
cameraVersion: _cameraVersion,
|
|
@@ -5129,16 +5346,15 @@ function InteractionOverlay({
|
|
|
5129
5346
|
}
|
|
5130
5347
|
let eraserPreview = null;
|
|
5131
5348
|
if (eraserPreviewItems.length > 0) {
|
|
5132
|
-
eraserPreview = /* @__PURE__ */ jsxRuntime.jsx("g", { children: eraserPreviewItems.map((it) =>
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
}) });
|
|
5349
|
+
eraserPreview = /* @__PURE__ */ jsxRuntime.jsx("g", { children: eraserPreviewItems.map((it) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5350
|
+
"g",
|
|
5351
|
+
{
|
|
5352
|
+
transform: formatItemPlacementTransform(it),
|
|
5353
|
+
opacity: ERASER_PREVIEW_OPACITY,
|
|
5354
|
+
dangerouslySetInnerHTML: { __html: it.childrenSvg }
|
|
5355
|
+
},
|
|
5356
|
+
`erase-preview-${it.id}`
|
|
5357
|
+
)) });
|
|
5142
5358
|
}
|
|
5143
5359
|
let marqueeCandidates = null;
|
|
5144
5360
|
if (marqueeCandidateItems.length > 0) {
|
|
@@ -8637,6 +8853,7 @@ exports.createNoopPersistenceAdapter = createNoopPersistenceAdapter;
|
|
|
8637
8853
|
exports.createToolPlugin = createToolPlugin;
|
|
8638
8854
|
exports.cursorForVectorToolId = cursorForVectorToolId;
|
|
8639
8855
|
exports.getBoardPositionStyle = getBoardPositionStyle;
|
|
8856
|
+
exports.hydrateSceneItemsWithAssets = hydrateSceneItemsWithAssets;
|
|
8640
8857
|
exports.ingestAssetFilesToSceneItems = ingestAssetFilesToSceneItems;
|
|
8641
8858
|
exports.useCanvuChromeContext = useCanvuChromeContext;
|
|
8642
8859
|
exports.useCanvuDocumentContext = useCanvuDocumentContext;
|