@pixldocs/canvas-renderer 0.5.395 → 0.5.396

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.
@@ -125,6 +125,7 @@ const createDefaultGroup = (partial) => ({
125
125
  locked: false,
126
126
  left: 0,
127
127
  top: 0,
128
+ angle: 0,
128
129
  ...partial
129
130
  });
130
131
  const PAGE_BACKGROUND_ELEMENT_ID = "__pageBackground__";
@@ -847,9 +848,17 @@ function getNodeBounds(node, pageChildren, options) {
847
848
  let width;
848
849
  let height;
849
850
  if (isGroup(node) && (pageChildren == null ? void 0 : pageChildren.length) !== void 0) {
850
- const size = groupBoundsFromChildren(node, pageChildren ?? []);
851
- width = size.width;
852
- height = size.height;
851
+ const group = node;
852
+ const storedWidth = Number(group.width);
853
+ const storedHeight = Number(group.height);
854
+ if (!isStackLayoutMode(group.layoutMode) && storedWidth > 0 && storedHeight > 0) {
855
+ width = storedWidth;
856
+ height = storedHeight;
857
+ } else {
858
+ const size = groupBoundsFromChildren(group, pageChildren ?? []);
859
+ width = size.width;
860
+ height = size.height;
861
+ }
853
862
  } else {
854
863
  width = simpleWidth(node);
855
864
  height = simpleHeight(node);
@@ -10524,6 +10533,65 @@ const normalizeAngle180 = (angle) => {
10524
10533
  const n = (angle % 360 + 360) % 360;
10525
10534
  return n > 180 ? n - 360 : n;
10526
10535
  };
10536
+ const isValidLogicalGroupFrame = (frame) => !!frame && Number.isFinite(frame.left) && Number.isFinite(frame.top) && Number.isFinite(frame.width) && frame.width > 0 && Number.isFinite(frame.height) && frame.height > 0;
10537
+ const frameFromStoredGroupNode = (group, pageChildren, options) => {
10538
+ const width = Number(group.width);
10539
+ const height = Number(group.height);
10540
+ if (!Number.isFinite(width) || width <= 0 || !Number.isFinite(height) || height <= 0) return null;
10541
+ try {
10542
+ const abs = getAbsoluteBounds(group, pageChildren, options);
10543
+ return { left: abs.left, top: abs.top, width, height };
10544
+ } catch {
10545
+ return null;
10546
+ }
10547
+ };
10548
+ const orientedFrameFromWorldPoints = (points, angle) => {
10549
+ if (points.length === 0 || !Number.isFinite(angle)) return null;
10550
+ const rad = -angle * Math.PI / 180;
10551
+ const cos = Math.cos(rad);
10552
+ const sin = Math.sin(rad);
10553
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
10554
+ for (const p of points) {
10555
+ const xr = p.x * cos - p.y * sin;
10556
+ const yr = p.x * sin + p.y * cos;
10557
+ minX = Math.min(minX, xr);
10558
+ minY = Math.min(minY, yr);
10559
+ maxX = Math.max(maxX, xr);
10560
+ maxY = Math.max(maxY, yr);
10561
+ }
10562
+ if (![minX, minY, maxX, maxY].every(Number.isFinite)) return null;
10563
+ const width = Math.max(1, maxX - minX);
10564
+ const height = Math.max(1, maxY - minY);
10565
+ const centerXRot = minX + width / 2;
10566
+ const centerYRot = minY + height / 2;
10567
+ const back = angle * Math.PI / 180;
10568
+ const c = Math.cos(back);
10569
+ const s = Math.sin(back);
10570
+ const centerX = centerXRot * c - centerYRot * s;
10571
+ const centerY = centerXRot * s + centerYRot * c;
10572
+ return { left: centerX - width / 2, top: centerY - height / 2, width, height };
10573
+ };
10574
+ const collectFabricObjectWorldPoints = (objects) => {
10575
+ const points = [];
10576
+ for (const obj of objects) {
10577
+ try {
10578
+ obj.setCoords();
10579
+ } catch {
10580
+ }
10581
+ const coords = typeof obj.getCoords === "function" ? obj.getCoords() : null;
10582
+ if (Array.isArray(coords) && coords.length) {
10583
+ points.push(...coords.map((p) => ({ x: p.x, y: p.y })));
10584
+ continue;
10585
+ }
10586
+ const aC = obj.aCoords;
10587
+ if (!aC) continue;
10588
+ for (const key of ["tl", "tr", "br", "bl"]) {
10589
+ const p = aC[key];
10590
+ if (p) points.push({ x: p.x, y: p.y });
10591
+ }
10592
+ }
10593
+ return points;
10594
+ };
10527
10595
  let ensureCanvaControlRenders = () => {
10528
10596
  };
10529
10597
  try {
@@ -11680,11 +11748,18 @@ const PageCanvas = react.forwardRef(
11680
11748
  const pageNow = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId);
11681
11749
  const groupNode = pageNow ? findNodeById(pageNow.children ?? [], groupId) : null;
11682
11750
  let groupAngle = groupNode && isGroup(groupNode) && typeof groupNode.angle === "number" ? groupNode.angle : void 0;
11751
+ const members = selection.getObjects();
11752
+ if (groupAngle === void 0 && groupNode && isGroup(groupNode)) {
11753
+ const storedW = Number(groupNode.width);
11754
+ const storedH = Number(groupNode.height);
11755
+ if (storedW > 0 && storedH > 0) {
11756
+ groupAngle = 0;
11757
+ }
11758
+ }
11683
11759
  if (groupAngle === void 0 && groupNode && isGroup(groupNode)) {
11684
11760
  try {
11685
- const kids = selection.getObjects();
11686
11761
  const selectionMatrix = selection.calcTransformMatrix();
11687
- const worldAngles = kids.map((kid) => normalizeAngle180(fabric__namespace.util.qrDecompose(
11762
+ const worldAngles = members.map((kid) => normalizeAngle180(fabric__namespace.util.qrDecompose(
11688
11763
  fabric__namespace.util.multiplyTransformMatrices(
11689
11764
  selectionMatrix,
11690
11765
  kid.calcOwnMatrix()
@@ -11700,15 +11775,41 @@ const PageCanvas = react.forwardRef(
11700
11775
  const inferredAngle = (_a2 = buckets[0]) == null ? void 0 : _a2.angle;
11701
11776
  if (typeof inferredAngle === "number" && Number.isFinite(inferredAngle) && Math.abs(inferredAngle) > 0.01) {
11702
11777
  groupAngle = inferredAngle;
11703
- useEditorStore.getState().updateNode(
11704
- groupId,
11705
- { angle: inferredAngle },
11706
- { recordHistory: false, skipLayoutRecalc: true }
11707
- );
11708
11778
  }
11709
11779
  } catch {
11710
11780
  }
11711
11781
  }
11782
+ let groupFrame = groupNode && isGroup(groupNode) ? frameFromStoredGroupNode(groupNode, (pageNow == null ? void 0 : pageNow.children) ?? []) : null;
11783
+ let groupFrameWasInferred = false;
11784
+ if (!groupFrame && groupNode && isGroup(groupNode) && typeof groupAngle === "number" && Number.isFinite(groupAngle)) {
11785
+ groupFrame = orientedFrameFromWorldPoints(collectFabricObjectWorldPoints(members), normalizeAngle180(groupAngle));
11786
+ groupFrameWasInferred = isValidLogicalGroupFrame(groupFrame);
11787
+ }
11788
+ if (groupNode && isGroup(groupNode)) {
11789
+ const updates = {};
11790
+ if (typeof groupAngle === "number" && Number.isFinite(groupAngle)) {
11791
+ const prevAngle = typeof groupNode.angle === "number" ? groupNode.angle : void 0;
11792
+ if (prevAngle === void 0 || Math.abs(normalizeAngle180(prevAngle - groupAngle)) > 0.01) {
11793
+ updates.angle = normalizeAngle180(groupAngle);
11794
+ }
11795
+ }
11796
+ if (isValidLogicalGroupFrame(groupFrame)) {
11797
+ const prevW = Number(groupNode.width);
11798
+ const prevH = Number(groupNode.height);
11799
+ if (!Number.isFinite(prevW) || Math.abs(prevW - groupFrame.width) > 0.5) updates.width = groupFrame.width;
11800
+ if (!Number.isFinite(prevH) || Math.abs(prevH - groupFrame.height) > 0.5) updates.height = groupFrame.height;
11801
+ if (groupFrameWasInferred) {
11802
+ const storePos = absoluteToStorePosition(groupFrame.left, groupFrame.top, groupId, (pageNow == null ? void 0 : pageNow.children) ?? []);
11803
+ const prevLeft = Number(groupNode.left ?? 0);
11804
+ const prevTop = Number(groupNode.top ?? 0);
11805
+ if (!Number.isFinite(prevLeft) || Math.abs(prevLeft - storePos.left) > 0.5) updates.left = storePos.left;
11806
+ if (!Number.isFinite(prevTop) || Math.abs(prevTop - storePos.top) > 0.5) updates.top = storePos.top;
11807
+ }
11808
+ }
11809
+ if (Object.keys(updates).length > 0) {
11810
+ useEditorStore.getState().updateNode(groupId, updates, { recordHistory: false, skipLayoutRecalc: true });
11811
+ }
11812
+ }
11712
11813
  if (groupAngle !== void 0) {
11713
11814
  selection.__pixldocsGroupAngle = groupAngle;
11714
11815
  const aligned = selection.__pixldocsAlignedAngle;
@@ -11719,7 +11820,6 @@ const PageCanvas = react.forwardRef(
11719
11820
  delete selection.__pixldocsGroupAngle;
11720
11821
  }
11721
11822
  selection.hasBorders = true;
11722
- const members = selection.getObjects();
11723
11823
  for (const prev of suppressGroupMemberBordersRef.current) {
11724
11824
  if (members.includes(prev)) continue;
11725
11825
  const origBorders = prev.__pixldocsOrigHasBorders;
@@ -11751,21 +11851,6 @@ const PageCanvas = react.forwardRef(
11751
11851
  m.lockScalingY = false;
11752
11852
  }
11753
11853
  }
11754
- const groupFrame = groupNode && isGroup(groupNode) ? (() => {
11755
- try {
11756
- const abs = getAbsoluteBounds(groupNode, (pageNow == null ? void 0 : pageNow.children) ?? []);
11757
- const storedW = Number(groupNode.width);
11758
- const storedH = Number(groupNode.height);
11759
- return {
11760
- left: abs.left,
11761
- top: abs.top,
11762
- width: Number.isFinite(storedW) && storedW > 0 ? storedW : abs.width,
11763
- height: Number.isFinite(storedH) && storedH > 0 ? storedH : abs.height
11764
- };
11765
- } catch {
11766
- return null;
11767
- }
11768
- })() : null;
11769
11854
  applyWarpAwareSelectionBorders(selection, groupAngle, groupFrame);
11770
11855
  }, [pageId]);
11771
11856
  const pageBoundsOptions = react.useMemo(
@@ -13334,16 +13419,18 @@ const PageCanvas = react.forwardRef(
13334
13419
  const groupNode = findNodeById(pageChildren2, groupId);
13335
13420
  if (!groupNode) return;
13336
13421
  const groupAbs = getAbsoluteBounds(groupNode, pageChildren2);
13422
+ const storedGroupFrame = groupNode && isGroup(groupNode) ? frameFromStoredGroupNode(groupNode, pageChildren2, pageBoundsOptions) : null;
13423
+ const groupFrame = storedGroupFrame ?? groupAbs;
13337
13424
  const rect = active.getBoundingRect();
13338
13425
  groupSelectionTransformStartRef.current = {
13339
13426
  groupId,
13340
13427
  selection: active,
13341
13428
  selectionLeft: rect.left,
13342
13429
  selectionTop: rect.top,
13343
- groupLeft: groupAbs.left,
13344
- groupTop: groupAbs.top,
13345
- groupWidth: groupAbs.width,
13346
- groupHeight: groupAbs.height,
13430
+ groupLeft: groupFrame.left,
13431
+ groupTop: groupFrame.top,
13432
+ groupWidth: groupFrame.width,
13433
+ groupHeight: groupFrame.height,
13347
13434
  selectionAngle: ((active.angle ?? 0) % 360 + 360) % 360
13348
13435
  };
13349
13436
  logRotDriftSelectionSnapshot("transform-start", active, {
@@ -15480,13 +15567,37 @@ const PageCanvas = react.forwardRef(
15480
15567
  360 - Math.abs(currentSelAngle - startSelAngle)
15481
15568
  );
15482
15569
  const hadRotation = isActiveSelection && activeObj && angleDelta > 0.01;
15483
- if (hadRotation && activeObj instanceof fabric__namespace.ActiveSelection && activeGroupSelectionId === groupToMove.id) {
15484
- useEditorStore.getState().updateNode(
15485
- groupToMove.id,
15486
- { angle: currentSelAngle },
15487
- { recordHistory: false, skipLayoutRecalc: true }
15488
- );
15489
- activeObj.__pixldocsGroupAngle = currentSelAngle;
15570
+ if ((hadScale || hadRotation) && activeObj instanceof fabric__namespace.ActiveSelection && activeGroupSelectionId === groupToMove.id) {
15571
+ const groupTransformUpdates = {};
15572
+ if (hadRotation) {
15573
+ groupTransformUpdates.angle = normalizeAngle180(currentSelAngle);
15574
+ activeObj.__pixldocsGroupAngle = groupTransformUpdates.angle;
15575
+ }
15576
+ if (hadScale && (transformStart == null ? void 0 : transformStart.groupId) === groupToMove.id) {
15577
+ const center = activeObj.getCenterPoint();
15578
+ const nextWidth = Math.max(1, transformStart.groupWidth * Math.abs(activeObj.scaleX ?? 1));
15579
+ const nextHeight = Math.max(1, transformStart.groupHeight * Math.abs(activeObj.scaleY ?? 1));
15580
+ const storePos = absoluteToStorePosition(
15581
+ center.x - nextWidth / 2,
15582
+ center.y - nextHeight / 2,
15583
+ groupToMove.id,
15584
+ pageChildren2
15585
+ );
15586
+ groupTransformUpdates.left = storePos.left;
15587
+ groupTransformUpdates.top = storePos.top;
15588
+ groupTransformUpdates.width = nextWidth;
15589
+ groupTransformUpdates.height = nextHeight;
15590
+ } else if (!Number.isFinite(Number(groupToMove.width)) || !Number.isFinite(Number(groupToMove.height))) {
15591
+ groupTransformUpdates.width = (transformStart == null ? void 0 : transformStart.groupWidth) ?? groupAbs.width;
15592
+ groupTransformUpdates.height = (transformStart == null ? void 0 : transformStart.groupHeight) ?? groupAbs.height;
15593
+ }
15594
+ if (Object.keys(groupTransformUpdates).length > 0) {
15595
+ useEditorStore.getState().updateNode(
15596
+ groupToMove.id,
15597
+ groupTransformUpdates,
15598
+ { recordHistory: false, skipLayoutRecalc: true }
15599
+ );
15600
+ }
15490
15601
  }
15491
15602
  if (!hadScale && !hadRotation && (Math.abs(deltaX) > 0.1 || Math.abs(deltaY) > 0.1)) {
15492
15603
  const { updateNode: updateNodeStore, commitHistory: commitHistoryStore, getCurrentElements } = useEditorStore.getState();
@@ -25240,9 +25351,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
25240
25351
  }
25241
25352
  return svgString;
25242
25353
  }
25243
- const resolvedPackageVersion = "0.5.395";
25354
+ const resolvedPackageVersion = "0.5.396";
25244
25355
  const PACKAGE_VERSION = resolvedPackageVersion;
25245
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.395";
25356
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.396";
25246
25357
  const roundParityValue = (value) => {
25247
25358
  if (typeof value !== "number") return value;
25248
25359
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -26056,7 +26167,7 @@ class PixldocsRenderer {
26056
26167
  await this.waitForCanvasScene(container, cloned, i);
26057
26168
  }
26058
26169
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
26059
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-BFZzT33a.cjs"));
26170
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-oL70Zv8c.cjs"));
26060
26171
  const prepared = preparePagesForExport(
26061
26172
  cloned.pages,
26062
26173
  canvasWidth,
@@ -28376,7 +28487,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
28376
28487
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
28377
28488
  sanitizeSvgTreeForPdf(svgToDraw);
28378
28489
  try {
28379
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-BFZzT33a.cjs"));
28490
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-oL70Zv8c.cjs"));
28380
28491
  try {
28381
28492
  await logTextMeasurementDiagnostic(svgToDraw);
28382
28493
  } catch {
@@ -28773,4 +28884,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
28773
28884
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
28774
28885
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
28775
28886
  exports.warmTemplateFromForm = warmTemplateFromForm;
28776
- //# sourceMappingURL=index-apZqfLuE.cjs.map
28887
+ //# sourceMappingURL=index-DQYnrYMM.cjs.map