@pixldocs/canvas-renderer 0.5.16 → 0.5.18

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/index.cjs CHANGED
@@ -5689,6 +5689,7 @@ const PageCanvas = react.forwardRef(
5689
5689
  onDynamicFieldClick,
5690
5690
  canvasUpdateVersion = 0,
5691
5691
  pageChildren,
5692
+ skipFontReadyWait = false,
5692
5693
  onReady
5693
5694
  }, ref) => {
5694
5695
  const isEditorMode = mode === "editor";
@@ -5974,9 +5975,11 @@ const PageCanvas = react.forwardRef(
5974
5975
  await Promise.all(fontFamilies.map((f) => ensureFontLoaded(f)));
5975
5976
  }
5976
5977
  }
5977
- await waitForFontsReady();
5978
- await waitUntilFontsAvailable(fontFamilies, { timeoutMs: 3500, pollIntervalMs: 60 });
5979
- await new Promise((r) => requestAnimationFrame(() => r()));
5978
+ if (!skipFontReadyWait) {
5979
+ await waitForFontsReady();
5980
+ await waitUntilFontsAvailable(fontFamilies, { timeoutMs: 3500, pollIntervalMs: 60 });
5981
+ await new Promise((r) => requestAnimationFrame(() => r()));
5982
+ }
5980
5983
  clearFabricCharCache();
5981
5984
  clearMeasurementCache();
5982
5985
  setReady(true);
@@ -9413,6 +9416,7 @@ function PreviewCanvas({
9413
9416
  pageIndex = 0,
9414
9417
  zoom = 1,
9415
9418
  absoluteZoom = false,
9419
+ skipFontReadyWait = false,
9416
9420
  className,
9417
9421
  onDynamicFieldClick,
9418
9422
  onReady
@@ -9567,6 +9571,7 @@ function PreviewCanvas({
9567
9571
  selectedIds: [],
9568
9572
  activeTool: "select",
9569
9573
  mode: "preview",
9574
+ skipFontReadyWait,
9570
9575
  dynamicFieldIds,
9571
9576
  onDynamicFieldClick: handleDynamicFieldClick,
9572
9577
  onReady
@@ -12300,6 +12305,49 @@ class PixldocsRenderer {
12300
12305
  setTimeout(check, 0);
12301
12306
  });
12302
12307
  }
12308
+ waitForCanvasScene(container, config, pageIndex, maxWaitMs = 8e3, pollMs = 50) {
12309
+ return new Promise((resolve) => {
12310
+ var _a, _b;
12311
+ const start = Date.now();
12312
+ const pageHasContent = (((_b = (_a = config.pages[pageIndex]) == null ? void 0 : _a.children) == null ? void 0 : _b.length) ?? 0) > 0;
12313
+ const settle = () => requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
12314
+ const check = () => {
12315
+ const fabricCanvas = this.getFabricCanvasFromContainer(container);
12316
+ const lowerCanvas = (fabricCanvas == null ? void 0 : fabricCanvas.lowerCanvasEl) || container.querySelector("canvas.lower-canvas, canvas");
12317
+ const objectCount = typeof (fabricCanvas == null ? void 0 : fabricCanvas.getObjects) === "function" ? fabricCanvas.getObjects().length : 0;
12318
+ const ready = !!lowerCanvas && (!pageHasContent || objectCount > 0);
12319
+ if (ready) {
12320
+ console.log(`[canvas-renderer][scene-wait] ready after ${Date.now() - start}ms (objects=${objectCount})`);
12321
+ settle();
12322
+ return;
12323
+ }
12324
+ if (Date.now() - start >= maxWaitMs) {
12325
+ console.warn(`[canvas-renderer][scene-wait-timeout] elapsed=${Date.now() - start}ms objects=${objectCount} pageHasContent=${pageHasContent}`);
12326
+ settle();
12327
+ return;
12328
+ }
12329
+ setTimeout(check, pollMs);
12330
+ };
12331
+ setTimeout(check, 0);
12332
+ });
12333
+ }
12334
+ async waitForRelevantFonts(config, maxWaitMs = 1800) {
12335
+ if (typeof document === "undefined" || !document.fonts) return;
12336
+ const descriptors = collectFontDescriptorsFromConfig(config);
12337
+ if (descriptors.length === 0) return;
12338
+ const loads = Promise.all(
12339
+ descriptors.map((descriptor) => {
12340
+ const stylePrefix = descriptor.style === "italic" ? "italic " : "";
12341
+ const spec = `${stylePrefix}${descriptor.weight} 16px "${descriptor.family}"`;
12342
+ return document.fonts.load(spec).catch(() => []);
12343
+ })
12344
+ ).then(() => void 0);
12345
+ await Promise.race([
12346
+ loads,
12347
+ new Promise((resolve) => setTimeout(resolve, maxWaitMs))
12348
+ ]);
12349
+ await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));
12350
+ }
12303
12351
  getNormalizedGradientStops(gradient) {
12304
12352
  const stops = Array.isArray(gradient == null ? void 0 : gradient.stops) ? gradient.stops.map((stop) => ({
12305
12353
  offset: Math.max(0, Math.min(1, Number((stop == null ? void 0 : stop.offset) ?? 0))),
@@ -12407,16 +12455,17 @@ class PixldocsRenderer {
12407
12455
  pageIndex,
12408
12456
  zoom: pixelRatio,
12409
12457
  absoluteZoom: true,
12458
+ skipFontReadyWait: true,
12410
12459
  onReady
12411
12460
  })
12412
12461
  );
12413
12462
  return;
12414
12463
  }
12415
- const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
12416
- this.waitForCanvasImages(container, expectedImageCount).then(async () => {
12464
+ this.waitForCanvasScene(container, config, pageIndex).then(async () => {
12417
12465
  try {
12418
12466
  const fabricInstance = this.getFabricCanvasFromContainer(container);
12419
- await this.waitForStableTextMetrics(container, config);
12467
+ const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
12468
+ await this.waitForCanvasImages(container, expectedImageCount);
12420
12469
  const fabricCanvas = container.querySelector("canvas.upper-canvas, canvas");
12421
12470
  const sourceCanvas = (fabricInstance == null ? void 0 : fabricInstance.lowerCanvasEl) || container.querySelector("canvas.lower-canvas") || fabricCanvas;
12422
12471
  if (!sourceCanvas) {
@@ -12455,6 +12504,7 @@ class PixldocsRenderer {
12455
12504
  pageIndex,
12456
12505
  zoom: pixelRatio,
12457
12506
  absoluteZoom: true,
12507
+ skipFontReadyWait: true,
12458
12508
  onReady
12459
12509
  })
12460
12510
  );
@@ -12501,13 +12551,13 @@ class PixldocsRenderer {
12501
12551
  pageIndex,
12502
12552
  zoom: 1,
12503
12553
  absoluteZoom: true,
12554
+ skipFontReadyWait: true,
12504
12555
  onReady
12505
12556
  })
12506
12557
  );
12507
12558
  return;
12508
12559
  }
12509
- const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
12510
- this.waitForCanvasImages(container, expectedImageCount).then(async () => {
12560
+ this.waitForCanvasScene(container, config, pageIndex).then(async () => {
12511
12561
  var _a, _b;
12512
12562
  try {
12513
12563
  const fabricInstance = this.getFabricCanvasFromContainer(container);
@@ -12516,7 +12566,8 @@ class PixldocsRenderer {
12516
12566
  reject(new Error("No Fabric canvas instance found for SVG capture"));
12517
12567
  return;
12518
12568
  }
12519
- await this.waitForStableTextMetrics(container, config);
12569
+ const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
12570
+ await this.waitForCanvasImages(container, expectedImageCount);
12520
12571
  const prevVPT = fabricInstance.viewportTransform ? [...fabricInstance.viewportTransform] : void 0;
12521
12572
  const prevSvgVPT = fabricInstance.svgViewportTransformation;
12522
12573
  const prevRetina = fabricInstance.enableRetinaScaling;
@@ -12567,6 +12618,7 @@ class PixldocsRenderer {
12567
12618
  zoom: 1,
12568
12619
  // 1:1 — no UI scaling for SVG capture
12569
12620
  absoluteZoom: true,
12621
+ skipFontReadyWait: true,
12570
12622
  onReady
12571
12623
  })
12572
12624
  );
@@ -12640,7 +12692,8 @@ class PixldocsRenderer {
12640
12692
  }
12641
12693
  async waitForStableTextMetrics(container, config) {
12642
12694
  if (typeof document !== "undefined") {
12643
- await ensureFontsForResolvedConfig(config);
12695
+ void ensureFontsForResolvedConfig(config);
12696
+ await this.waitForRelevantFonts(config);
12644
12697
  }
12645
12698
  const fabricInstance = this.getFabricCanvasFromContainer(container);
12646
12699
  if (!(fabricInstance == null ? void 0 : fabricInstance.getObjects)) return;