@pixldocs/canvas-renderer 0.5.491 → 0.5.492

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.
@@ -3,7 +3,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  var _a, _b, _c;
5
5
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
6
- import { forwardRef, useRef, useState, useCallback, useMemo, useEffect, useImperativeHandle, createElement } from "react";
6
+ import { forwardRef, useRef, useState, useEffect, useCallback, useMemo, useImperativeHandle, createElement } from "react";
7
7
  import { flushSync } from "react-dom";
8
8
  import { toast } from "sonner";
9
9
  import { create } from "zustand";
@@ -12061,7 +12061,29 @@ const PageCanvas = forwardRef(
12061
12061
  const [rotationLabel, setRotationLabel] = useState(null);
12062
12062
  const [sizeLabel, setSizeLabel] = useState(null);
12063
12063
  const [ready, setReady] = useState(false);
12064
+ const onReadyRef = useRef(onReady);
12065
+ const pendingInitialImageLoadsRef = useRef(0);
12064
12066
  const [unlockRequestId, setUnlockRequestId] = useState(0);
12067
+ useEffect(() => {
12068
+ onReadyRef.current = onReady;
12069
+ }, [onReady]);
12070
+ const trackInitialImageLoad = useCallback((promise) => {
12071
+ if (hasNotifiedReadyForPageRef.current === pageId) {
12072
+ return;
12073
+ }
12074
+ pendingInitialImageLoadsRef.current += 1;
12075
+ let settled = false;
12076
+ const finish = () => {
12077
+ if (settled) return;
12078
+ settled = true;
12079
+ pendingInitialImageLoadsRef.current = Math.max(0, pendingInitialImageLoadsRef.current - 1);
12080
+ };
12081
+ const timeout = window.setTimeout(finish, 12e3);
12082
+ void promise.finally(() => {
12083
+ window.clearTimeout(timeout);
12084
+ finish();
12085
+ });
12086
+ }, [pageId]);
12065
12087
  const applyLogicalGroupSelectionVisualState = useCallback((selection, groupId) => {
12066
12088
  var _a2;
12067
12089
  selection.__pixldocsGroupSelection = groupId;
@@ -18081,7 +18103,7 @@ const PageCanvas = forwardRef(
18081
18103
  placeholder.dirty = true;
18082
18104
  fc.requestRenderAll();
18083
18105
  if (imageUrl) {
18084
- loadImageAsync2(elementForImage, placeholder, fc);
18106
+ trackInitialImageLoad(loadImageAsync2(elementForImage, placeholder, fc));
18085
18107
  }
18086
18108
  } else {
18087
18109
  const resolvedSizeCreate = pageTree.length > 0 ? getNodeBounds(element, pageTree) : { width: typeof element.width === "number" ? element.width : 200, height: typeof element.height === "number" ? element.height : 50 };
@@ -18344,12 +18366,35 @@ const PageCanvas = forwardRef(
18344
18366
  }, [allowEditing, isActive, pageId]);
18345
18367
  useEffect(() => {
18346
18368
  if (!ready || hasRunPostReadyReflowForPageRef.current === pageId) return;
18347
- hasRunPostReadyReflowForPageRef.current = pageId;
18348
18369
  let cancelled = false;
18370
+ let retryTimer = null;
18371
+ const readyWaitStartedAt = performance.now();
18372
+ const maxAssetWaitMs = 2500;
18373
+ let notifyRaf1 = null;
18374
+ let notifyRaf2 = null;
18349
18375
  const notifyReady = () => {
18350
18376
  if (cancelled || hasNotifiedReadyForPageRef.current === pageId) return;
18351
- hasNotifiedReadyForPageRef.current = pageId;
18352
- onReady == null ? void 0 : onReady();
18377
+ const finishWhenAssetsSettle = () => {
18378
+ if (cancelled || hasNotifiedReadyForPageRef.current === pageId) return;
18379
+ if (pendingInitialImageLoadsRef.current > 0 && performance.now() - readyWaitStartedAt < maxAssetWaitMs) {
18380
+ retryTimer = window.setTimeout(finishWhenAssetsSettle, 50);
18381
+ return;
18382
+ }
18383
+ notifyRaf1 = requestAnimationFrame(() => {
18384
+ notifyRaf2 = requestAnimationFrame(() => {
18385
+ var _a2;
18386
+ if (cancelled || hasNotifiedReadyForPageRef.current === pageId) return;
18387
+ if (pendingInitialImageLoadsRef.current > 0 && performance.now() - readyWaitStartedAt < maxAssetWaitMs) {
18388
+ retryTimer = window.setTimeout(finishWhenAssetsSettle, 50);
18389
+ return;
18390
+ }
18391
+ hasRunPostReadyReflowForPageRef.current = pageId;
18392
+ hasNotifiedReadyForPageRef.current = pageId;
18393
+ (_a2 = onReadyRef.current) == null ? void 0 : _a2.call(onReadyRef);
18394
+ });
18395
+ });
18396
+ };
18397
+ finishWhenAssetsSettle();
18353
18398
  };
18354
18399
  const runReflowAndPersist = () => {
18355
18400
  var _a2;
@@ -18357,37 +18402,42 @@ const PageCanvas = forwardRef(
18357
18402
  if (!fc || cancelled) return;
18358
18403
  const state = useEditorStore.getState();
18359
18404
  const repositionTree = isPreviewMode && (pageChildren == null ? void 0 : pageChildren.length) ? pageChildren ?? [] : ((_a2 = state.canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a2.children) ?? [];
18360
- runFontReloadAndReflow({
18361
- canvas: fc,
18362
- pageTree: repositionTree,
18363
- pageBoundsOptions,
18364
- preserveGlobalFontCache,
18365
- // Persist measured Textbox sizes back to the editor store. The
18366
- // headless path passes no callback (it has no store to persist into).
18367
- persistTextboxSize: (id, measured, el) => {
18368
- const storeW = el.width ?? 0;
18369
- const storeH = el.height ?? 0;
18370
- const shouldKeepFixedSize = el.overflowPolicy === "auto-shrink";
18371
- const updates = {};
18372
- if (!shouldKeepFixedSize && measured.width > 0 && typeof storeW === "number" && Math.abs(measured.width - storeW) > 0.1) {
18373
- updates.width = measured.width;
18374
- }
18375
- if (shouldKeepFixedSize) {
18376
- if (measured.height > 0 && typeof storeH === "number" && measured.height < storeH - 0.5) updates.height = measured.height;
18377
- } else {
18378
- if (measured.height > 0 && (typeof storeH !== "number" || Math.abs(measured.height - storeH) > 0.1)) updates.height = measured.height;
18379
- }
18380
- if (Object.keys(updates).length > 0) {
18381
- state.updateElement(id, updates, { recordHistory: false, skipLayoutRecalc: true });
18382
- }
18383
- },
18384
- // Rebuild section/background groups before resnapping top-level objects.
18385
- preResnapSync: (isPreviewMode || isExportMode) && doSyncRef.current ? () => {
18386
- var _a3;
18387
- return (_a3 = doSyncRef.current) == null ? void 0 : _a3.call(doSyncRef);
18388
- } : void 0
18389
- });
18405
+ try {
18406
+ runFontReloadAndReflow({
18407
+ canvas: fc,
18408
+ pageTree: repositionTree,
18409
+ pageBoundsOptions,
18410
+ preserveGlobalFontCache,
18411
+ // Persist measured Textbox sizes back to the editor store. The
18412
+ // headless path passes no callback (it has no store to persist into).
18413
+ persistTextboxSize: (id, measured, el) => {
18414
+ const storeW = el.width ?? 0;
18415
+ const storeH = el.height ?? 0;
18416
+ const shouldKeepFixedSize = el.overflowPolicy === "auto-shrink";
18417
+ const updates = {};
18418
+ if (!shouldKeepFixedSize && measured.width > 0 && typeof storeW === "number" && Math.abs(measured.width - storeW) > 0.1) {
18419
+ updates.width = measured.width;
18420
+ }
18421
+ if (shouldKeepFixedSize) {
18422
+ if (measured.height > 0 && typeof storeH === "number" && measured.height < storeH - 0.5) updates.height = measured.height;
18423
+ } else {
18424
+ if (measured.height > 0 && (typeof storeH !== "number" || Math.abs(measured.height - storeH) > 0.1)) updates.height = measured.height;
18425
+ }
18426
+ if (Object.keys(updates).length > 0) {
18427
+ state.updateElement(id, updates, { recordHistory: false, skipLayoutRecalc: true });
18428
+ }
18429
+ },
18430
+ // Rebuild section/background groups before resnapping top-level objects.
18431
+ preResnapSync: (isPreviewMode || isExportMode) && doSyncRef.current ? () => {
18432
+ var _a3;
18433
+ return (_a3 = doSyncRef.current) == null ? void 0 : _a3.call(doSyncRef);
18434
+ } : void 0
18435
+ });
18436
+ } catch (err) {
18437
+ console.warn("[PageCanvas] post-ready reflow failed; continuing canvas ready state", err);
18438
+ }
18390
18439
  };
18440
+ const fallbackTimer = window.setTimeout(notifyReady, 3500);
18391
18441
  const raf1 = requestAnimationFrame(() => {
18392
18442
  requestAnimationFrame(() => {
18393
18443
  if (cancelled) return;
@@ -18403,9 +18453,13 @@ const PageCanvas = forwardRef(
18403
18453
  });
18404
18454
  return () => {
18405
18455
  cancelled = true;
18456
+ window.clearTimeout(fallbackTimer);
18406
18457
  cancelAnimationFrame(raf1);
18458
+ if (retryTimer !== null) window.clearTimeout(retryTimer);
18459
+ if (notifyRaf1 !== null) cancelAnimationFrame(notifyRaf1);
18460
+ if (notifyRaf2 !== null) cancelAnimationFrame(notifyRaf2);
18407
18461
  };
18408
- }, [ready, pageId, onReady]);
18462
+ }, [ready, pageId]);
18409
18463
  useEffect(() => {
18410
18464
  var _a2;
18411
18465
  const fc = fabricRef.current;
@@ -21988,7 +22042,6 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
21988
22042
  return void 0;
21989
22043
  }
21990
22044
  const applyValue = (elementId, targetProperty, value, fieldKey, svgColorKey) => {
21991
- var _a3;
21992
22045
  const isTextLike = targetProperty === "text" || targetProperty === "content";
21993
22046
  const isImageLike = targetProperty === "src" || targetProperty === "imageUrl";
21994
22047
  if (value === void 0 || value === null) {
@@ -22014,19 +22067,32 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
22014
22067
  }
22015
22068
  }
22016
22069
  if (elementId === PAGE_BACKGROUND_ELEMENT_ID && targetProperty === "backgroundColor") {
22017
- if ((_a3 = pages[0]) == null ? void 0 : _a3.settings) {
22018
- const settings = pages[0].settings;
22070
+ let applied = false;
22071
+ const hasExplicitBg = (settings) => {
22072
+ const raw = settings.backgroundColor;
22073
+ if (typeof raw !== "string") return false;
22074
+ const trimmed = raw.trim().toLowerCase();
22075
+ if (!trimmed) return false;
22076
+ if (trimmed === "transparent" || trimmed === "none") return false;
22077
+ return true;
22078
+ };
22079
+ for (const page of pages) {
22080
+ if (!page.settings) continue;
22081
+ const settings = page.settings;
22082
+ if (hasExplicitBg(settings) && !("backgroundGradient" in settings)) continue;
22019
22083
  if (isGradientConfig(effectiveValue)) {
22020
22084
  settings.backgroundGradient = effectiveValue;
22021
22085
  settings.backgroundColor = "";
22022
- return true;
22086
+ applied = true;
22087
+ continue;
22023
22088
  }
22024
22089
  if (typeof effectiveValue === "string") {
22025
22090
  if ("backgroundGradient" in settings) delete settings.backgroundGradient;
22026
22091
  settings.backgroundColor = effectiveValue;
22027
- return true;
22092
+ applied = true;
22028
22093
  }
22029
22094
  }
22095
+ if (applied) return true;
22030
22096
  }
22031
22097
  for (const page of pages) {
22032
22098
  if (page.children && setInTree(page.children, elementId, targetProperty, effectiveValue, svgColorKey)) return true;
@@ -25741,7 +25807,19 @@ function PixldocsPreview(props) {
25741
25807
  isResolveMode ? props.themeId : void 0
25742
25808
  ]);
25743
25809
  const config = isResolveMode ? resolvedConfig : props.config;
25744
- const previewKey = useMemo(() => `${pageIndex}`, [pageIndex]);
25810
+ const previewKey = useMemo(() => {
25811
+ var _a3, _b3;
25812
+ const page = (_a3 = config == null ? void 0 : config.pages) == null ? void 0 : _a3[pageIndex];
25813
+ const settings = (page == null ? void 0 : page.settings) ?? {};
25814
+ const gradientSignature = settings.backgroundGradient ? JSON.stringify(settings.backgroundGradient) : "";
25815
+ return [
25816
+ pageIndex,
25817
+ (page == null ? void 0 : page.id) ?? "page",
25818
+ settings.backgroundColor ?? "",
25819
+ gradientSignature,
25820
+ ((_b3 = page == null ? void 0 : page.children) == null ? void 0 : _b3.length) ?? 0
25821
+ ].join("|");
25822
+ }, [config, pageIndex]);
25745
25823
  const fontSignature = useMemo(() => computeFontSignature(config), [config]);
25746
25824
  const imageSignature = useMemo(() => computeImageSignature(config), [config]);
25747
25825
  const [imagesReady, setImagesReady] = useState(true);
@@ -26424,9 +26502,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
26424
26502
  }
26425
26503
  return svgString;
26426
26504
  }
26427
- const resolvedPackageVersion = "0.5.491";
26505
+ const resolvedPackageVersion = "0.5.492";
26428
26506
  const PACKAGE_VERSION = resolvedPackageVersion;
26429
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.491";
26507
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.492";
26430
26508
  const roundParityValue = (value) => {
26431
26509
  if (typeof value !== "number") return value;
26432
26510
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -27240,7 +27318,7 @@ class PixldocsRenderer {
27240
27318
  await this.waitForCanvasScene(container, cloned, i);
27241
27319
  }
27242
27320
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
27243
- const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-7V15HkWe.js");
27321
+ const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-rz4LyyuM.js");
27244
27322
  const prepared = preparePagesForExport(
27245
27323
  cloned.pages,
27246
27324
  canvasWidth,
@@ -29560,7 +29638,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
29560
29638
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
29561
29639
  sanitizeSvgTreeForPdf(svgToDraw);
29562
29640
  try {
29563
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-7V15HkWe.js");
29641
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-rz4LyyuM.js");
29564
29642
  try {
29565
29643
  await logTextMeasurementDiagnostic(svgToDraw);
29566
29644
  } catch {
@@ -29877,4 +29955,4 @@ export {
29877
29955
  buildTeaserBlurFlatKeys as y,
29878
29956
  collectFontDescriptorsFromConfig as z
29879
29957
  };
29880
- //# sourceMappingURL=index-Cr96RvlZ.js.map
29958
+ //# sourceMappingURL=index-DHzIvJSN.js.map