canvu-react 0.3.13 → 0.3.14

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/react.cjs CHANGED
@@ -956,10 +956,32 @@ async function runWithConcurrency(items, concurrency, execute) {
956
956
  async function loadPdfToStore(file, store, options) {
957
957
  const scale = options?.scale ?? 1.5;
958
958
  const pageConcurrency = options?.pageConcurrency ?? 2;
959
+ const storeThumbnails = options?.storeThumbnails ?? false;
959
960
  const pdfjs = await getPdfJs();
960
961
  const arrayBuffer = await file.arrayBuffer();
961
962
  const pdf = await pdfjs.getDocument({ data: arrayBuffer }).promise;
962
963
  const pageNumbers = normalizePdfPageNumbers(options?.pageNumbers, pdf.numPages);
964
+ const bufferedResults = /* @__PURE__ */ new Map();
965
+ let nextEmitIndex = 0;
966
+ let emitChain = Promise.resolve();
967
+ const queuePageEmission = async (pageResult) => {
968
+ bufferedResults.set(pageResult.pageNumber, pageResult);
969
+ const run = async () => {
970
+ while (nextEmitIndex < pageNumbers.length) {
971
+ const nextPageNumber = pageNumbers[nextEmitIndex];
972
+ if (nextPageNumber == null) break;
973
+ const bufferedResult = bufferedResults.get(nextPageNumber);
974
+ if (!bufferedResult) break;
975
+ bufferedResults.delete(nextPageNumber);
976
+ nextEmitIndex += 1;
977
+ await options?.onPageStored?.(bufferedResult);
978
+ }
979
+ };
980
+ const nextChain = emitChain.then(run, run);
981
+ emitChain = nextChain.catch(() => {
982
+ });
983
+ await nextChain;
984
+ };
963
985
  return await runWithConcurrency(
964
986
  pageNumbers,
965
987
  pageConcurrency,
@@ -969,27 +991,31 @@ async function loadPdfToStore(file, store, options) {
969
991
  const mime = "image/png";
970
992
  const pageBlob = await canvasToBlob2(canvas, mime);
971
993
  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 {
994
+ const thumbnailBlobId = storeThumbnails ? await (async () => {
995
+ const thumbScale = Math.min(1, 256 / Math.max(width, height));
996
+ const tw = Math.max(1, Math.round(width * thumbScale));
997
+ const th = Math.max(1, Math.round(height * thumbScale));
998
+ const thumbCanvas = document.createElement("canvas");
999
+ thumbCanvas.width = tw;
1000
+ thumbCanvas.height = th;
1001
+ const tCtx = thumbCanvas.getContext("2d");
1002
+ if (tCtx) {
1003
+ tCtx.imageSmoothingEnabled = true;
1004
+ tCtx.imageSmoothingQuality = "high";
1005
+ tCtx.drawImage(canvas, 0, 0, tw, th);
1006
+ }
1007
+ const thumbBlob = await canvasToBlob2(thumbCanvas, mime);
1008
+ return await store.storeThumbnail(thumbBlob);
1009
+ })() : "";
1010
+ const pageResult = {
987
1011
  blobId,
988
1012
  thumbnailBlobId,
989
1013
  width,
990
1014
  height,
991
1015
  pageNumber
992
1016
  };
1017
+ await queuePageEmission(pageResult);
1018
+ return pageResult;
993
1019
  }
994
1020
  );
995
1021
  }
@@ -1345,9 +1371,10 @@ async function ingestAssetFilesToSceneItems(options) {
1345
1371
  createId = createShapeId,
1346
1372
  gapWorld = 16,
1347
1373
  stepWorld = 48,
1348
- pdfScale = 1.5,
1374
+ pdfScale = 1.15,
1349
1375
  pdfPageConcurrency = 2,
1350
1376
  decorateItem,
1377
+ onItemsReady,
1351
1378
  onError
1352
1379
  } = options;
1353
1380
  const items = [];
@@ -1369,55 +1396,56 @@ async function ingestAssetFilesToSceneItems(options) {
1369
1396
  }
1370
1397
  try {
1371
1398
  if (kind === "pdf") {
1372
- const [uploadResult2, pages] = await Promise.all([
1373
- uploadAssetIfNeeded(assetStore, file, kind),
1374
- loadPdfToStore(file, imageStore, {
1375
- scale: pdfScale,
1376
- pageConcurrency: pdfPageConcurrency
1377
- })
1378
- ]);
1379
- for (const page of pages) {
1380
- const fullUrl2 = await createBlobUrlFromStore(imageStore, page.blobId);
1381
- const naturalTopY2 = worldCenter.y - page.height / 2;
1382
- const stackedTopY = occupiedBottomY == null ? naturalTopY2 : occupiedBottomY + gapWorld;
1383
- const bounds2 = {
1384
- x: worldCenter.x - page.width / 2,
1385
- y: Math.max(naturalTopY2, stackedTopY),
1386
- width: page.width,
1387
- height: page.height
1388
- };
1389
- const itemContext2 = {
1390
- file,
1391
- kind,
1392
- itemIndex: items.length,
1393
- pageNumber: page.pageNumber
1394
- };
1395
- const item2 = finalizeIngestedItem(
1396
- {
1397
- id: createId(),
1398
- x: bounds2.x,
1399
- y: bounds2.y,
1400
- bounds: { ...bounds2 },
1401
- toolKind: "image",
1402
- imageBlobId: page.blobId,
1403
- imageRasterHref: fullUrl2 ?? void 0,
1404
- imageIntrinsicSize: {
1405
- width: page.width,
1406
- height: page.height
1399
+ const uploadResultPromise = uploadAssetIfNeeded(assetStore, file, kind);
1400
+ await loadPdfToStore(file, imageStore, {
1401
+ scale: pdfScale,
1402
+ pageConcurrency: pdfPageConcurrency,
1403
+ storeThumbnails: false,
1404
+ onPageStored: async (page) => {
1405
+ const uploadResult2 = await uploadResultPromise;
1406
+ const fullUrl2 = await createBlobUrlFromStore(imageStore, page.blobId);
1407
+ const naturalTopY2 = worldCenter.y - page.height / 2;
1408
+ const stackedTopY = occupiedBottomY == null ? naturalTopY2 : occupiedBottomY + gapWorld;
1409
+ const bounds2 = {
1410
+ x: worldCenter.x - page.width / 2,
1411
+ y: Math.max(naturalTopY2, stackedTopY),
1412
+ width: page.width,
1413
+ height: page.height
1414
+ };
1415
+ const itemContext2 = {
1416
+ file,
1417
+ kind,
1418
+ itemIndex: items.length,
1419
+ pageNumber: page.pageNumber
1420
+ };
1421
+ const item2 = finalizeIngestedItem(
1422
+ {
1423
+ id: createId(),
1424
+ x: bounds2.x,
1425
+ y: bounds2.y,
1426
+ bounds: { ...bounds2 },
1427
+ toolKind: "image",
1428
+ imageBlobId: page.blobId,
1429
+ imageRasterHref: fullUrl2 ?? void 0,
1430
+ imageIntrinsicSize: {
1431
+ width: page.width,
1432
+ height: page.height
1433
+ },
1434
+ childrenSvg: fullUrl2 ? buildRasterImageChildrenSvg(
1435
+ fullUrl2,
1436
+ { width: page.width, height: page.height },
1437
+ bounds2
1438
+ ) : ""
1407
1439
  },
1408
- childrenSvg: fullUrl2 ? buildRasterImageChildrenSvg(
1409
- fullUrl2,
1410
- { width: page.width, height: page.height },
1411
- bounds2
1412
- ) : ""
1413
- },
1414
- itemContext2,
1415
- uploadResult2,
1416
- decorateItem
1417
- );
1418
- items.push(item2);
1419
- occupiedBottomY = bounds2.y + page.height;
1420
- }
1440
+ itemContext2,
1441
+ uploadResult2,
1442
+ decorateItem
1443
+ );
1444
+ items.push(item2);
1445
+ occupiedBottomY = bounds2.y + page.height;
1446
+ onItemsReady?.([item2], { file, kind });
1447
+ }
1448
+ });
1421
1449
  hasImagePlacementBase = false;
1422
1450
  imagePlacementIndex = 0;
1423
1451
  imageYOffsetAdjustment = 0;
@@ -1470,6 +1498,7 @@ async function ingestAssetFilesToSceneItems(options) {
1470
1498
  decorateItem
1471
1499
  );
1472
1500
  items.push(item);
1501
+ onItemsReady?.([item], { file, kind });
1473
1502
  imagePlacementIndex++;
1474
1503
  occupiedBottomY = occupiedBottomY == null ? bounds.y + height : Math.max(occupiedBottomY, bounds.y + height);
1475
1504
  } catch (error) {
@@ -7382,7 +7411,13 @@ var VectorViewport = react.forwardRef(
7382
7411
  y: worldY
7383
7412
  },
7384
7413
  imageStore: store,
7385
- assetStore: assetStoreRef.current ?? void 0
7414
+ assetStore: assetStoreRef.current ?? void 0,
7415
+ onItemsReady: (nextItems) => {
7416
+ if (nextItems.length === 0) return;
7417
+ setLoadingSkeletons([]);
7418
+ change([...itemsRef.current, ...nextItems]);
7419
+ setEffectiveSelectedIdsRef.current(nextItems.map((item) => item.id));
7420
+ }
7386
7421
  });
7387
7422
  if (result.errors.length > 0) {
7388
7423
  for (const error of result.errors) {
@@ -7390,8 +7425,6 @@ var VectorViewport = react.forwardRef(
7390
7425
  }
7391
7426
  }
7392
7427
  if (result.items.length === 0) return;
7393
- change([...itemsRef.current, ...result.items]);
7394
- setEffectiveSelectedIdsRef.current(result.items.map((item) => item.id));
7395
7428
  } finally {
7396
7429
  setLoadingSkeletons([]);
7397
7430
  }