@pixldocs/canvas-renderer 0.5.15 → 0.5.17

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
@@ -2703,12 +2703,10 @@ const waitForFontsReady = async () => {
2703
2703
  if (!document.fonts) return;
2704
2704
  await withFontTimeout(document.fonts.ready, 2500);
2705
2705
  };
2706
- const DEFAULT_FONT_CHECK_TIMEOUT_MS = 3500;
2707
- const FONT_CHECK_POLL_MS = 60;
2708
2706
  const waitUntilFontsAvailable = async (fontFamilies, options) => {
2709
2707
  if (!document.fonts || fontFamilies.length === 0) return;
2710
- const timeoutMs = (options == null ? void 0 : options.timeoutMs) ?? DEFAULT_FONT_CHECK_TIMEOUT_MS;
2711
- const pollMs = (options == null ? void 0 : options.pollIntervalMs) ?? FONT_CHECK_POLL_MS;
2708
+ const timeoutMs = options == null ? void 0 : options.timeoutMs;
2709
+ const pollMs = options == null ? void 0 : options.pollIntervalMs;
2712
2710
  const deadline = Date.now() + timeoutMs;
2713
2711
  const check = () => fontFamilies.every(
2714
2712
  (f) => document.fonts.check(`16px "${f}"`) && document.fonts.check(`bold 16px "${f}"`)
@@ -11707,18 +11705,16 @@ function normalizeFontFamily(fontStack) {
11707
11705
  }
11708
11706
  const loadedFonts = /* @__PURE__ */ new Set();
11709
11707
  const loadingPromises = /* @__PURE__ */ new Map();
11710
- async function withTimeout(promise, timeoutMs = 4e3) {
11708
+ function withTimeout(promise, timeoutMs = 4e3) {
11711
11709
  let timeoutId;
11712
- try {
11713
- return await Promise.race([
11714
- promise,
11715
- new Promise((resolve) => {
11716
- timeoutId = setTimeout(resolve, timeoutMs);
11717
- })
11718
- ]);
11719
- } finally {
11710
+ return Promise.race([
11711
+ promise,
11712
+ new Promise((resolve) => {
11713
+ timeoutId = setTimeout(resolve, timeoutMs);
11714
+ })
11715
+ ]).finally(() => {
11720
11716
  if (timeoutId) clearTimeout(timeoutId);
11721
- }
11717
+ });
11722
11718
  }
11723
11719
  async function loadGoogleFontCSS(rawFontFamily) {
11724
11720
  if (!rawFontFamily || typeof document === "undefined") return;
@@ -11740,10 +11736,6 @@ async function loadGoogleFontCSS(rawFontFamily) {
11740
11736
  link.onerror = () => reject(new Error(`Failed to load font: ${fontFamily}`));
11741
11737
  document.head.appendChild(link);
11742
11738
  });
11743
- if (document.fonts) {
11744
- await withTimeout(document.fonts.load(`16px "${fontFamily}"`), 2500);
11745
- await withTimeout(document.fonts.ready, 2500);
11746
- }
11747
11739
  loadedFonts.add(fontFamily);
11748
11740
  } catch (e) {
11749
11741
  console.warn(`[@pixldocs/canvas-renderer] Font load failed: ${fontFamily}`, e);
@@ -11855,17 +11847,15 @@ async function ensureFontsForResolvedConfig(config) {
11855
11847
  if (typeof document === "undefined") return;
11856
11848
  const descriptors = collectFontDescriptorsFromConfig(config);
11857
11849
  const families = new Set(descriptors.map((d) => d.family));
11858
- await withTimeout(Promise.all([...families].map((f) => loadGoogleFontCSS(f))), 8e3);
11850
+ void withTimeout(Promise.all([...families].map((f) => loadGoogleFontCSS(f))), 2500);
11859
11851
  if (document.fonts) {
11860
- const loadPromises = descriptors.map((d) => {
11852
+ descriptors.forEach((d) => {
11861
11853
  const stylePrefix = d.style === "italic" ? "italic " : "";
11862
11854
  const weightStr = String(d.weight);
11863
11855
  const spec = `${stylePrefix}${weightStr} 16px "${d.family}"`;
11864
- return document.fonts.load(spec).catch(() => {
11856
+ document.fonts.load(spec).catch(() => {
11865
11857
  });
11866
11858
  });
11867
- await withTimeout(Promise.all(loadPromises), 8e3);
11868
- await withTimeout(document.fonts.ready, 2500);
11869
11859
  }
11870
11860
  }
11871
11861
  function PixldocsPreview(props) {
@@ -12310,6 +12300,49 @@ class PixldocsRenderer {
12310
12300
  setTimeout(check, 0);
12311
12301
  });
12312
12302
  }
12303
+ waitForCanvasScene(container, config, pageIndex, maxWaitMs = 8e3, pollMs = 50) {
12304
+ return new Promise((resolve) => {
12305
+ var _a, _b;
12306
+ const start = Date.now();
12307
+ const pageHasContent = (((_b = (_a = config.pages[pageIndex]) == null ? void 0 : _a.children) == null ? void 0 : _b.length) ?? 0) > 0;
12308
+ const settle = () => requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
12309
+ const check = () => {
12310
+ const fabricCanvas = this.getFabricCanvasFromContainer(container);
12311
+ const lowerCanvas = (fabricCanvas == null ? void 0 : fabricCanvas.lowerCanvasEl) || container.querySelector("canvas.lower-canvas, canvas");
12312
+ const objectCount = typeof (fabricCanvas == null ? void 0 : fabricCanvas.getObjects) === "function" ? fabricCanvas.getObjects().length : 0;
12313
+ const ready = !!lowerCanvas && (!pageHasContent || objectCount > 0);
12314
+ if (ready) {
12315
+ console.log(`[canvas-renderer][scene-wait] ready after ${Date.now() - start}ms (objects=${objectCount})`);
12316
+ settle();
12317
+ return;
12318
+ }
12319
+ if (Date.now() - start >= maxWaitMs) {
12320
+ console.warn(`[canvas-renderer][scene-wait-timeout] elapsed=${Date.now() - start}ms objects=${objectCount} pageHasContent=${pageHasContent}`);
12321
+ settle();
12322
+ return;
12323
+ }
12324
+ setTimeout(check, pollMs);
12325
+ };
12326
+ setTimeout(check, 0);
12327
+ });
12328
+ }
12329
+ async waitForRelevantFonts(config, maxWaitMs = 1800) {
12330
+ if (typeof document === "undefined" || !document.fonts) return;
12331
+ const descriptors = collectFontDescriptorsFromConfig(config);
12332
+ if (descriptors.length === 0) return;
12333
+ const loads = Promise.all(
12334
+ descriptors.map((descriptor) => {
12335
+ const stylePrefix = descriptor.style === "italic" ? "italic " : "";
12336
+ const spec = `${stylePrefix}${descriptor.weight} 16px "${descriptor.family}"`;
12337
+ return document.fonts.load(spec).catch(() => []);
12338
+ })
12339
+ ).then(() => void 0);
12340
+ await Promise.race([
12341
+ loads,
12342
+ new Promise((resolve) => setTimeout(resolve, maxWaitMs))
12343
+ ]);
12344
+ await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));
12345
+ }
12313
12346
  getNormalizedGradientStops(gradient) {
12314
12347
  const stops = Array.isArray(gradient == null ? void 0 : gradient.stops) ? gradient.stops.map((stop) => ({
12315
12348
  offset: Math.max(0, Math.min(1, Number((stop == null ? void 0 : stop.offset) ?? 0))),
@@ -12422,10 +12455,11 @@ class PixldocsRenderer {
12422
12455
  );
12423
12456
  return;
12424
12457
  }
12425
- const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
12426
- this.waitForCanvasImages(container, expectedImageCount).then(async () => {
12458
+ this.waitForCanvasScene(container, config, pageIndex).then(async () => {
12427
12459
  try {
12428
12460
  const fabricInstance = this.getFabricCanvasFromContainer(container);
12461
+ const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
12462
+ await this.waitForCanvasImages(container, expectedImageCount);
12429
12463
  await this.waitForStableTextMetrics(container, config);
12430
12464
  const fabricCanvas = container.querySelector("canvas.upper-canvas, canvas");
12431
12465
  const sourceCanvas = (fabricInstance == null ? void 0 : fabricInstance.lowerCanvasEl) || container.querySelector("canvas.lower-canvas") || fabricCanvas;
@@ -12516,8 +12550,7 @@ class PixldocsRenderer {
12516
12550
  );
12517
12551
  return;
12518
12552
  }
12519
- const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
12520
- this.waitForCanvasImages(container, expectedImageCount).then(async () => {
12553
+ this.waitForCanvasScene(container, config, pageIndex).then(async () => {
12521
12554
  var _a, _b;
12522
12555
  try {
12523
12556
  const fabricInstance = this.getFabricCanvasFromContainer(container);
@@ -12526,6 +12559,8 @@ class PixldocsRenderer {
12526
12559
  reject(new Error("No Fabric canvas instance found for SVG capture"));
12527
12560
  return;
12528
12561
  }
12562
+ const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
12563
+ await this.waitForCanvasImages(container, expectedImageCount);
12529
12564
  await this.waitForStableTextMetrics(container, config);
12530
12565
  const prevVPT = fabricInstance.viewportTransform ? [...fabricInstance.viewportTransform] : void 0;
12531
12566
  const prevSvgVPT = fabricInstance.svgViewportTransformation;
@@ -12649,14 +12684,9 @@ class PixldocsRenderer {
12649
12684
  return null;
12650
12685
  }
12651
12686
  async waitForStableTextMetrics(container, config) {
12652
- var _a;
12653
12687
  if (typeof document !== "undefined") {
12654
- await ensureFontsForResolvedConfig(config);
12655
- await ((_a = document.fonts) == null ? void 0 : _a.ready);
12656
- const fontFamilies = [...collectFontsFromConfig(config)].filter(Boolean);
12657
- if (fontFamilies.length > 0) {
12658
- await waitUntilFontsAvailable(fontFamilies, { timeoutMs: 4e3, pollIntervalMs: 50 });
12659
- }
12688
+ void ensureFontsForResolvedConfig(config);
12689
+ await this.waitForRelevantFonts(config);
12660
12690
  }
12661
12691
  const fabricInstance = this.getFabricCanvasFromContainer(container);
12662
12692
  if (!(fabricInstance == null ? void 0 : fabricInstance.getObjects)) return;
@@ -12666,9 +12696,9 @@ class PixldocsRenderer {
12666
12696
  clearMeasurementCache();
12667
12697
  };
12668
12698
  const reflowTextboxes = () => {
12669
- var _a2, _b, _c;
12699
+ var _a, _b, _c;
12670
12700
  const walk = (obj) => {
12671
- var _a3, _b2, _c2, _d;
12701
+ var _a2, _b2, _c2, _d;
12672
12702
  if (!obj) return;
12673
12703
  const children = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];
12674
12704
  if (children.length) children.forEach(walk);
@@ -12680,8 +12710,8 @@ class PixldocsRenderer {
12680
12710
  scaleY: obj.scaleY
12681
12711
  };
12682
12712
  const resetTextboxLayoutInternals = () => {
12683
- var _a4;
12684
- (_a4 = obj._clearCache) == null ? void 0 : _a4.call(obj);
12713
+ var _a3;
12714
+ (_a3 = obj._clearCache) == null ? void 0 : _a3.call(obj);
12685
12715
  obj.__charBounds = [];
12686
12716
  obj.__lineWidths = [];
12687
12717
  obj.__lineHeights = [];
@@ -12695,7 +12725,7 @@ class PixldocsRenderer {
12695
12725
  resetTextboxLayoutInternals();
12696
12726
  obj.initDimensions();
12697
12727
  if (saved.width != null) {
12698
- (_a3 = obj.set) == null ? void 0 : _a3.call(obj, {
12728
+ (_a2 = obj.set) == null ? void 0 : _a2.call(obj, {
12699
12729
  width: saved.width,
12700
12730
  scaleX: saved.scaleX,
12701
12731
  scaleY: saved.scaleY
@@ -12714,7 +12744,7 @@ class PixldocsRenderer {
12714
12744
  }
12715
12745
  };
12716
12746
  fabricInstance.getObjects().forEach(walk);
12717
- (_a2 = fabricInstance.calcOffset) == null ? void 0 : _a2.call(fabricInstance);
12747
+ (_a = fabricInstance.calcOffset) == null ? void 0 : _a.call(fabricInstance);
12718
12748
  (_b = fabricInstance.renderAll) == null ? void 0 : _b.call(fabricInstance);
12719
12749
  (_c = fabricInstance.requestRenderAll) == null ? void 0 : _c.call(fabricInstance);
12720
12750
  };