@pixldocs/canvas-renderer 0.5.490 → 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.
@@ -12079,7 +12079,29 @@ const PageCanvas = react.forwardRef(
12079
12079
  const [rotationLabel, setRotationLabel] = react.useState(null);
12080
12080
  const [sizeLabel, setSizeLabel] = react.useState(null);
12081
12081
  const [ready, setReady] = react.useState(false);
12082
+ const onReadyRef = react.useRef(onReady);
12083
+ const pendingInitialImageLoadsRef = react.useRef(0);
12082
12084
  const [unlockRequestId, setUnlockRequestId] = react.useState(0);
12085
+ react.useEffect(() => {
12086
+ onReadyRef.current = onReady;
12087
+ }, [onReady]);
12088
+ const trackInitialImageLoad = react.useCallback((promise) => {
12089
+ if (hasNotifiedReadyForPageRef.current === pageId) {
12090
+ return;
12091
+ }
12092
+ pendingInitialImageLoadsRef.current += 1;
12093
+ let settled = false;
12094
+ const finish = () => {
12095
+ if (settled) return;
12096
+ settled = true;
12097
+ pendingInitialImageLoadsRef.current = Math.max(0, pendingInitialImageLoadsRef.current - 1);
12098
+ };
12099
+ const timeout = window.setTimeout(finish, 12e3);
12100
+ void promise.finally(() => {
12101
+ window.clearTimeout(timeout);
12102
+ finish();
12103
+ });
12104
+ }, [pageId]);
12083
12105
  const applyLogicalGroupSelectionVisualState = react.useCallback((selection, groupId) => {
12084
12106
  var _a2;
12085
12107
  selection.__pixldocsGroupSelection = groupId;
@@ -17251,15 +17273,13 @@ const PageCanvas = react.forwardRef(
17251
17273
  }
17252
17274
  updateElement(elementId, {
17253
17275
  text: newText,
17254
- ...typeof nextHeight === "number" && nextHeight > 0 && { height: nextHeight },
17255
- ...target.styles && Object.keys(target.styles).length > 0 ? { styles: JSON.parse(JSON.stringify(target.styles)) } : {}
17276
+ ...typeof nextHeight === "number" && nextHeight > 0 && { height: nextHeight }
17256
17277
  });
17257
17278
  } else {
17258
17279
  updateElement(elementId, {
17259
17280
  text: newText,
17260
17281
  ...fabricHeight > 0 && { height: fabricHeight },
17261
- ...fabricWidth > 0 && { width: fabricWidth },
17262
- ...target.styles && Object.keys(target.styles).length > 0 ? { styles: JSON.parse(JSON.stringify(target.styles)) } : {}
17282
+ ...fabricWidth > 0 && { width: fabricWidth }
17263
17283
  });
17264
17284
  }
17265
17285
  commitHistory2();
@@ -18101,7 +18121,7 @@ const PageCanvas = react.forwardRef(
18101
18121
  placeholder.dirty = true;
18102
18122
  fc.requestRenderAll();
18103
18123
  if (imageUrl) {
18104
- loadImageAsync2(elementForImage, placeholder, fc);
18124
+ trackInitialImageLoad(loadImageAsync2(elementForImage, placeholder, fc));
18105
18125
  }
18106
18126
  } else {
18107
18127
  const resolvedSizeCreate = pageTree.length > 0 ? getNodeBounds(element, pageTree) : { width: typeof element.width === "number" ? element.width : 200, height: typeof element.height === "number" ? element.height : 50 };
@@ -18364,12 +18384,35 @@ const PageCanvas = react.forwardRef(
18364
18384
  }, [allowEditing, isActive, pageId]);
18365
18385
  react.useEffect(() => {
18366
18386
  if (!ready || hasRunPostReadyReflowForPageRef.current === pageId) return;
18367
- hasRunPostReadyReflowForPageRef.current = pageId;
18368
18387
  let cancelled = false;
18388
+ let retryTimer = null;
18389
+ const readyWaitStartedAt = performance.now();
18390
+ const maxAssetWaitMs = 2500;
18391
+ let notifyRaf1 = null;
18392
+ let notifyRaf2 = null;
18369
18393
  const notifyReady = () => {
18370
18394
  if (cancelled || hasNotifiedReadyForPageRef.current === pageId) return;
18371
- hasNotifiedReadyForPageRef.current = pageId;
18372
- onReady == null ? void 0 : onReady();
18395
+ const finishWhenAssetsSettle = () => {
18396
+ if (cancelled || hasNotifiedReadyForPageRef.current === pageId) return;
18397
+ if (pendingInitialImageLoadsRef.current > 0 && performance.now() - readyWaitStartedAt < maxAssetWaitMs) {
18398
+ retryTimer = window.setTimeout(finishWhenAssetsSettle, 50);
18399
+ return;
18400
+ }
18401
+ notifyRaf1 = requestAnimationFrame(() => {
18402
+ notifyRaf2 = requestAnimationFrame(() => {
18403
+ var _a2;
18404
+ if (cancelled || hasNotifiedReadyForPageRef.current === pageId) return;
18405
+ if (pendingInitialImageLoadsRef.current > 0 && performance.now() - readyWaitStartedAt < maxAssetWaitMs) {
18406
+ retryTimer = window.setTimeout(finishWhenAssetsSettle, 50);
18407
+ return;
18408
+ }
18409
+ hasRunPostReadyReflowForPageRef.current = pageId;
18410
+ hasNotifiedReadyForPageRef.current = pageId;
18411
+ (_a2 = onReadyRef.current) == null ? void 0 : _a2.call(onReadyRef);
18412
+ });
18413
+ });
18414
+ };
18415
+ finishWhenAssetsSettle();
18373
18416
  };
18374
18417
  const runReflowAndPersist = () => {
18375
18418
  var _a2;
@@ -18377,37 +18420,42 @@ const PageCanvas = react.forwardRef(
18377
18420
  if (!fc || cancelled) return;
18378
18421
  const state = useEditorStore.getState();
18379
18422
  const repositionTree = isPreviewMode && (pageChildren == null ? void 0 : pageChildren.length) ? pageChildren ?? [] : ((_a2 = state.canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a2.children) ?? [];
18380
- runFontReloadAndReflow({
18381
- canvas: fc,
18382
- pageTree: repositionTree,
18383
- pageBoundsOptions,
18384
- preserveGlobalFontCache,
18385
- // Persist measured Textbox sizes back to the editor store. The
18386
- // headless path passes no callback (it has no store to persist into).
18387
- persistTextboxSize: (id, measured, el) => {
18388
- const storeW = el.width ?? 0;
18389
- const storeH = el.height ?? 0;
18390
- const shouldKeepFixedSize = el.overflowPolicy === "auto-shrink";
18391
- const updates = {};
18392
- if (!shouldKeepFixedSize && measured.width > 0 && typeof storeW === "number" && Math.abs(measured.width - storeW) > 0.1) {
18393
- updates.width = measured.width;
18394
- }
18395
- if (shouldKeepFixedSize) {
18396
- if (measured.height > 0 && typeof storeH === "number" && measured.height < storeH - 0.5) updates.height = measured.height;
18397
- } else {
18398
- if (measured.height > 0 && (typeof storeH !== "number" || Math.abs(measured.height - storeH) > 0.1)) updates.height = measured.height;
18399
- }
18400
- if (Object.keys(updates).length > 0) {
18401
- state.updateElement(id, updates, { recordHistory: false, skipLayoutRecalc: true });
18402
- }
18403
- },
18404
- // Rebuild section/background groups before resnapping top-level objects.
18405
- preResnapSync: (isPreviewMode || isExportMode) && doSyncRef.current ? () => {
18406
- var _a3;
18407
- return (_a3 = doSyncRef.current) == null ? void 0 : _a3.call(doSyncRef);
18408
- } : void 0
18409
- });
18423
+ try {
18424
+ runFontReloadAndReflow({
18425
+ canvas: fc,
18426
+ pageTree: repositionTree,
18427
+ pageBoundsOptions,
18428
+ preserveGlobalFontCache,
18429
+ // Persist measured Textbox sizes back to the editor store. The
18430
+ // headless path passes no callback (it has no store to persist into).
18431
+ persistTextboxSize: (id, measured, el) => {
18432
+ const storeW = el.width ?? 0;
18433
+ const storeH = el.height ?? 0;
18434
+ const shouldKeepFixedSize = el.overflowPolicy === "auto-shrink";
18435
+ const updates = {};
18436
+ if (!shouldKeepFixedSize && measured.width > 0 && typeof storeW === "number" && Math.abs(measured.width - storeW) > 0.1) {
18437
+ updates.width = measured.width;
18438
+ }
18439
+ if (shouldKeepFixedSize) {
18440
+ if (measured.height > 0 && typeof storeH === "number" && measured.height < storeH - 0.5) updates.height = measured.height;
18441
+ } else {
18442
+ if (measured.height > 0 && (typeof storeH !== "number" || Math.abs(measured.height - storeH) > 0.1)) updates.height = measured.height;
18443
+ }
18444
+ if (Object.keys(updates).length > 0) {
18445
+ state.updateElement(id, updates, { recordHistory: false, skipLayoutRecalc: true });
18446
+ }
18447
+ },
18448
+ // Rebuild section/background groups before resnapping top-level objects.
18449
+ preResnapSync: (isPreviewMode || isExportMode) && doSyncRef.current ? () => {
18450
+ var _a3;
18451
+ return (_a3 = doSyncRef.current) == null ? void 0 : _a3.call(doSyncRef);
18452
+ } : void 0
18453
+ });
18454
+ } catch (err) {
18455
+ console.warn("[PageCanvas] post-ready reflow failed; continuing canvas ready state", err);
18456
+ }
18410
18457
  };
18458
+ const fallbackTimer = window.setTimeout(notifyReady, 3500);
18411
18459
  const raf1 = requestAnimationFrame(() => {
18412
18460
  requestAnimationFrame(() => {
18413
18461
  if (cancelled) return;
@@ -18423,9 +18471,13 @@ const PageCanvas = react.forwardRef(
18423
18471
  });
18424
18472
  return () => {
18425
18473
  cancelled = true;
18474
+ window.clearTimeout(fallbackTimer);
18426
18475
  cancelAnimationFrame(raf1);
18476
+ if (retryTimer !== null) window.clearTimeout(retryTimer);
18477
+ if (notifyRaf1 !== null) cancelAnimationFrame(notifyRaf1);
18478
+ if (notifyRaf2 !== null) cancelAnimationFrame(notifyRaf2);
18427
18479
  };
18428
- }, [ready, pageId, onReady]);
18480
+ }, [ready, pageId]);
18429
18481
  react.useEffect(() => {
18430
18482
  var _a2;
18431
18483
  const fc = fabricRef.current;
@@ -22008,7 +22060,6 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
22008
22060
  return void 0;
22009
22061
  }
22010
22062
  const applyValue = (elementId, targetProperty, value, fieldKey, svgColorKey) => {
22011
- var _a3;
22012
22063
  const isTextLike = targetProperty === "text" || targetProperty === "content";
22013
22064
  const isImageLike = targetProperty === "src" || targetProperty === "imageUrl";
22014
22065
  if (value === void 0 || value === null) {
@@ -22034,19 +22085,32 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
22034
22085
  }
22035
22086
  }
22036
22087
  if (elementId === PAGE_BACKGROUND_ELEMENT_ID && targetProperty === "backgroundColor") {
22037
- if ((_a3 = pages[0]) == null ? void 0 : _a3.settings) {
22038
- const settings = pages[0].settings;
22088
+ let applied = false;
22089
+ const hasExplicitBg = (settings) => {
22090
+ const raw = settings.backgroundColor;
22091
+ if (typeof raw !== "string") return false;
22092
+ const trimmed = raw.trim().toLowerCase();
22093
+ if (!trimmed) return false;
22094
+ if (trimmed === "transparent" || trimmed === "none") return false;
22095
+ return true;
22096
+ };
22097
+ for (const page of pages) {
22098
+ if (!page.settings) continue;
22099
+ const settings = page.settings;
22100
+ if (hasExplicitBg(settings) && !("backgroundGradient" in settings)) continue;
22039
22101
  if (isGradientConfig(effectiveValue)) {
22040
22102
  settings.backgroundGradient = effectiveValue;
22041
22103
  settings.backgroundColor = "";
22042
- return true;
22104
+ applied = true;
22105
+ continue;
22043
22106
  }
22044
22107
  if (typeof effectiveValue === "string") {
22045
22108
  if ("backgroundGradient" in settings) delete settings.backgroundGradient;
22046
22109
  settings.backgroundColor = effectiveValue;
22047
- return true;
22110
+ applied = true;
22048
22111
  }
22049
22112
  }
22113
+ if (applied) return true;
22050
22114
  }
22051
22115
  for (const page of pages) {
22052
22116
  if (page.children && setInTree(page.children, elementId, targetProperty, effectiveValue, svgColorKey)) return true;
@@ -25761,7 +25825,19 @@ function PixldocsPreview(props) {
25761
25825
  isResolveMode ? props.themeId : void 0
25762
25826
  ]);
25763
25827
  const config = isResolveMode ? resolvedConfig : props.config;
25764
- const previewKey = react.useMemo(() => `${pageIndex}`, [pageIndex]);
25828
+ const previewKey = react.useMemo(() => {
25829
+ var _a3, _b3;
25830
+ const page = (_a3 = config == null ? void 0 : config.pages) == null ? void 0 : _a3[pageIndex];
25831
+ const settings = (page == null ? void 0 : page.settings) ?? {};
25832
+ const gradientSignature = settings.backgroundGradient ? JSON.stringify(settings.backgroundGradient) : "";
25833
+ return [
25834
+ pageIndex,
25835
+ (page == null ? void 0 : page.id) ?? "page",
25836
+ settings.backgroundColor ?? "",
25837
+ gradientSignature,
25838
+ ((_b3 = page == null ? void 0 : page.children) == null ? void 0 : _b3.length) ?? 0
25839
+ ].join("|");
25840
+ }, [config, pageIndex]);
25765
25841
  const fontSignature = react.useMemo(() => computeFontSignature(config), [config]);
25766
25842
  const imageSignature = react.useMemo(() => computeImageSignature(config), [config]);
25767
25843
  const [imagesReady, setImagesReady] = react.useState(true);
@@ -26444,9 +26520,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
26444
26520
  }
26445
26521
  return svgString;
26446
26522
  }
26447
- const resolvedPackageVersion = "0.5.490";
26523
+ const resolvedPackageVersion = "0.5.492";
26448
26524
  const PACKAGE_VERSION = resolvedPackageVersion;
26449
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.490";
26525
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.492";
26450
26526
  const roundParityValue = (value) => {
26451
26527
  if (typeof value !== "number") return value;
26452
26528
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -27260,7 +27336,7 @@ class PixldocsRenderer {
27260
27336
  await this.waitForCanvasScene(container, cloned, i);
27261
27337
  }
27262
27338
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
27263
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-mxgjzQsw.cjs"));
27339
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-PMQQ8BkR.cjs"));
27264
27340
  const prepared = preparePagesForExport(
27265
27341
  cloned.pages,
27266
27342
  canvasWidth,
@@ -29580,7 +29656,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
29580
29656
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
29581
29657
  sanitizeSvgTreeForPdf(svgToDraw);
29582
29658
  try {
29583
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-mxgjzQsw.cjs"));
29659
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-PMQQ8BkR.cjs"));
29584
29660
  try {
29585
29661
  await logTextMeasurementDiagnostic(svgToDraw);
29586
29662
  } catch {
@@ -29894,4 +29970,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
29894
29970
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
29895
29971
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
29896
29972
  exports.warmTemplateFromForm = warmTemplateFromForm;
29897
- //# sourceMappingURL=index-C47g5w5y.cjs.map
29973
+ //# sourceMappingURL=index-CoJw0tIl.cjs.map