@pixldocs/canvas-renderer 0.5.410 → 0.5.412

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.
@@ -4722,11 +4722,19 @@ const svgMaskApply = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.define
4722
4722
  syncSvgMaskClipPath
4723
4723
  }, Symbol.toStringTag, { value: "Module" }));
4724
4724
  const SELECTION_BORDER_SCALE$1 = 2;
4725
- const ROTATED_GROUP_IMAGE_RESIZE_DEBUG_PREFIX = "[Pixldocs][rotated-group-image-resize]";
4726
- const ROTATED_GROUP_IMAGE_RESIZE_DEBUG_MAX_ENTRIES = 400;
4725
+ const ROTATED_GROUP_IMAGE_RESIZE_DEBUG_PREFIX$1 = "[Pixldocs][rotated-group-image-resize]";
4726
+ const ROTATED_GROUP_IMAGE_RESIZE_DEBUG_MAX_ENTRIES$1 = 400;
4727
4727
  function isInsideRotatedActiveSelection(obj) {
4728
- const parent = obj.group;
4729
- if (!(parent instanceof fabric__namespace.ActiveSelection)) return false;
4728
+ var _a2;
4729
+ const debugObj = obj;
4730
+ const ownAngle = Math.abs(((obj.angle ?? 0) % 360 + 360) % 360);
4731
+ if ((debugObj.__cropData || debugObj.__cropGroup || ((_a2 = debugObj._ct) == null ? void 0 : _a2.isCropGroup)) && Math.min(ownAngle, 360 - ownAngle) > 0.5) return true;
4732
+ const logicalParentAngle = Math.abs(((debugObj.__pixldocsParentGroupAngle ?? 0) % 360 + 360) % 360);
4733
+ if (debugObj.__pixldocsParentGroupId && Math.min(logicalParentAngle, 360 - logicalParentAngle) > 0.5) return true;
4734
+ const parent = debugObj.group;
4735
+ if (!parent) return false;
4736
+ const pType = parent.type;
4737
+ if (pType !== "activeSelection" && pType !== "group") return false;
4730
4738
  const angle = Math.abs(((parent.angle ?? 0) % 360 + 360) % 360);
4731
4739
  return Math.min(angle, 360 - angle) > 0.5;
4732
4740
  }
@@ -4800,10 +4808,15 @@ function logRotatedGroupImageResize(phase, target, payload = {}) {
4800
4808
  signX: start.signX,
4801
4809
  signY: start.signY
4802
4810
  } : void 0;
4803
- const line = `${ROTATED_GROUP_IMAGE_RESIZE_DEBUG_PREFIX} ${phase} ${JSON.stringify(normalize({
4811
+ const line = `${ROTATED_GROUP_IMAGE_RESIZE_DEBUG_PREFIX$1} ${phase} ${JSON.stringify(normalize({
4804
4812
  ...payload,
4805
4813
  target: summarizeResizeObject(target),
4806
4814
  parent: summarizeResizeObject(parent),
4815
+ logicalParent: debugTarget.__pixldocsParentGroupId ? {
4816
+ id: debugTarget.__pixldocsParentGroupId,
4817
+ type: debugTarget.__pixldocsParentGroupType,
4818
+ angle: debugTarget.__pixldocsParentGroupAngle
4819
+ } : void 0,
4807
4820
  frameW: ct == null ? void 0 : ct.frameW,
4808
4821
  frameH: ct == null ? void 0 : ct.frameH,
4809
4822
  img: summarizeResizeObject(ct == null ? void 0 : ct._img),
@@ -4812,12 +4825,12 @@ function logRotatedGroupImageResize(phase, target, payload = {}) {
4812
4825
  }))}`;
4813
4826
  if (typeof window !== "undefined") {
4814
4827
  const debugWindow = window;
4815
- debugWindow.__pixldocsRotatedGroupImageResizeLogs = Array.isArray(debugWindow.__pixldocsRotatedGroupImageResizeLogs) ? debugWindow.__pixldocsRotatedGroupImageResizeLogs.slice(-ROTATED_GROUP_IMAGE_RESIZE_DEBUG_MAX_ENTRIES + 1) : [];
4828
+ debugWindow.__pixldocsRotatedGroupImageResizeLogs = Array.isArray(debugWindow.__pixldocsRotatedGroupImageResizeLogs) ? debugWindow.__pixldocsRotatedGroupImageResizeLogs.slice(-ROTATED_GROUP_IMAGE_RESIZE_DEBUG_MAX_ENTRIES$1 + 1) : [];
4816
4829
  debugWindow.__pixldocsRotatedGroupImageResizeLogs.push(line);
4817
4830
  }
4818
4831
  console.log(line);
4819
4832
  } catch {
4820
- console.log(ROTATED_GROUP_IMAGE_RESIZE_DEBUG_PREFIX, phase, payload);
4833
+ console.log(ROTATED_GROUP_IMAGE_RESIZE_DEBUG_PREFIX$1, phase, payload);
4821
4834
  }
4822
4835
  }
4823
4836
  function clamp$1(v, min, max) {
@@ -5300,6 +5313,12 @@ function installCanvaMaskControls(g) {
5300
5313
  logRotatedGroupImageResize("snap-skipped-active-selection-child", target, { corner });
5301
5314
  return;
5302
5315
  }
5316
+ const ownAngle = Math.abs(((target.angle ?? 0) % 360 + 360) % 360);
5317
+ const parentAngle = Math.abs(((target.__pixldocsParentGroupAngle ?? 0) % 360 + 360) % 360);
5318
+ if (Math.min(ownAngle, 360 - ownAngle) > 0.5 || Math.min(parentAngle, 360 - parentAngle) > 0.5) {
5319
+ logRotatedGroupImageResize("snap-skipped-rotated-image", target, { corner, ownAngle, parentAngle });
5320
+ return;
5321
+ }
5303
5322
  const handler = target.__resizeSnapHandler;
5304
5323
  if (typeof handler === "function") {
5305
5324
  logRotatedGroupImageResize("snap-before", target, { corner });
@@ -11400,10 +11419,34 @@ const summarizeFabricObjectForResizeDebug = (obj) => {
11400
11419
  const logGroupTextResizeDebug = (phase, payload) => {
11401
11420
  return;
11402
11421
  };
11422
+ const ROTATED_GROUP_IMAGE_RESIZE_DEBUG_PREFIX = "[Pixldocs][rotated-group-image-resize]";
11423
+ const ROTATED_GROUP_IMAGE_RESIZE_DEBUG_MAX_ENTRIES = 400;
11403
11424
  const roundRotDriftNumber = (value) => {
11404
11425
  if (typeof value !== "number") return value;
11405
11426
  return Number.isFinite(value) ? Math.round(value * 1e3) / 1e3 : String(value);
11406
11427
  };
11428
+ const normalizeRotDriftPayload = (value) => {
11429
+ const seen = /* @__PURE__ */ new WeakSet();
11430
+ const normalize = (entry) => {
11431
+ if (entry == null) return entry;
11432
+ const valueType = typeof entry;
11433
+ if (valueType === "number") return roundRotDriftNumber(entry);
11434
+ if (valueType === "string" || valueType === "boolean") return entry;
11435
+ if (Array.isArray(entry)) return entry.map((item) => normalize(item));
11436
+ if (valueType === "object") {
11437
+ if (seen.has(entry)) return "[Circular]";
11438
+ seen.add(entry);
11439
+ if (entry instanceof fabric__namespace.FabricObject) return normalize(summarizeRotDriftObject(entry));
11440
+ const output = {};
11441
+ Object.entries(entry).forEach(([key, item]) => {
11442
+ output[key] = normalize(item);
11443
+ });
11444
+ return output;
11445
+ }
11446
+ return String(entry);
11447
+ };
11448
+ return normalize(value);
11449
+ };
11407
11450
  const matrixForRotDriftLog = (matrix) => {
11408
11451
  if (!matrix) return void 0;
11409
11452
  return matrix.map((entry) => roundRotDriftNumber(entry));
@@ -11461,6 +11504,20 @@ const summarizeRotDriftObject = (obj, worldMatrix) => {
11461
11504
  const logRotGroupImageDrift = (phase, payload) => {
11462
11505
  return;
11463
11506
  };
11507
+ const logRotatedGroupImageResizeDebug = (phase, payload) => {
11508
+ if (typeof console === "undefined") return;
11509
+ try {
11510
+ const line = `${ROTATED_GROUP_IMAGE_RESIZE_DEBUG_PREFIX} ${phase} ${JSON.stringify(normalizeRotDriftPayload(payload))}`;
11511
+ if (typeof window !== "undefined") {
11512
+ const debugWindow = window;
11513
+ debugWindow.__pixldocsRotatedGroupImageResizeLogs = Array.isArray(debugWindow.__pixldocsRotatedGroupImageResizeLogs) ? debugWindow.__pixldocsRotatedGroupImageResizeLogs.slice(-ROTATED_GROUP_IMAGE_RESIZE_DEBUG_MAX_ENTRIES + 1) : [];
11514
+ debugWindow.__pixldocsRotatedGroupImageResizeLogs.push(line);
11515
+ }
11516
+ console.log(line);
11517
+ } catch {
11518
+ console.log(ROTATED_GROUP_IMAGE_RESIZE_DEBUG_PREFIX, phase, payload);
11519
+ }
11520
+ };
11464
11521
  const shouldLogRotDriftLiveTick = (target, phase) => {
11465
11522
  return false;
11466
11523
  };
@@ -12266,6 +12323,22 @@ const PageCanvas = react.forwardRef(
12266
12323
  [canvasWidth, canvasHeight, getLogicalGroupSnapBoundsCallback, getResizeExcludeIdsCallback]
12267
12324
  );
12268
12325
  const installImageResizeControlsWithSnap = react.useCallback((group) => {
12326
+ var _a2;
12327
+ try {
12328
+ const groupId = getObjectId(group);
12329
+ const pageChildrenNow = ((_a2 = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a2.children) ?? [];
12330
+ const parent = groupId ? findParentGroup(pageChildrenNow, groupId) : null;
12331
+ if (parent) {
12332
+ group.__pixldocsParentGroupId = parent.id;
12333
+ group.__pixldocsParentGroupAngle = parent.angle ?? 0;
12334
+ group.__pixldocsParentGroupType = "logical-group";
12335
+ } else {
12336
+ delete group.__pixldocsParentGroupId;
12337
+ delete group.__pixldocsParentGroupAngle;
12338
+ delete group.__pixldocsParentGroupType;
12339
+ }
12340
+ } catch {
12341
+ }
12269
12342
  group.__resizeSnapHandler = (target, corner) => {
12270
12343
  const fc = fabricRef.current ?? target.canvas;
12271
12344
  if (!fc || !isActiveRef.current || !corner) return;
@@ -14299,7 +14372,7 @@ const PageCanvas = react.forwardRef(
14299
14372
  fabricCanvas.on("selection:cleared", () => {
14300
14373
  });
14301
14374
  fabricCanvas.on("object:scaling", (e) => {
14302
- var _a2, _b2, _c2, _d, _e, _f, _g, _h, _i, _j;
14375
+ var _a2, _b2, _c2, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
14303
14376
  if (!isActiveRef.current) return;
14304
14377
  const t = e.target;
14305
14378
  if (t) lastResizeScaleTargetRef.current = t;
@@ -14470,12 +14543,61 @@ const PageCanvas = react.forwardRef(
14470
14543
  const corner = (transform == null ? void 0 : transform.corner) || "";
14471
14544
  if (obj instanceof fabric__namespace.ActiveSelection && corner) {
14472
14545
  activeSelectionResizeHandleRef.current = corner;
14546
+ const imageChildrenForResizeDebug = obj.getObjects().filter(
14547
+ (child) => {
14548
+ var _a3;
14549
+ return child instanceof fabric__namespace.FabricImage || child instanceof fabric__namespace.Group && (child.__cropGroup || ((_a3 = child._ct) == null ? void 0 : _a3.isCropGroup));
14550
+ }
14551
+ );
14552
+ const normalizedSelectionAngle = ((obj.angle ?? 0) % 360 + 360) % 360;
14553
+ const activeLogicalGroupId = obj.__pixldocsGroupSelection;
14554
+ const transformStartForDebug = activeLogicalGroupId && ((_c2 = groupSelectionTransformStartRef.current) == null ? void 0 : _c2.groupId) === activeLogicalGroupId ? groupSelectionTransformStartRef.current : null;
14555
+ const logicalGroupAngle = (transformStartForDebug == null ? void 0 : transformStartForDebug.groupAngle) ?? obj.__pixldocsFrozenGroupAngle ?? 0;
14556
+ const normalizedLogicalGroupAngle = (logicalGroupAngle % 360 + 360) % 360;
14557
+ const isRotatedImageSelection = imageChildrenForResizeDebug.length > 0 && (Math.min(normalizedSelectionAngle, 360 - normalizedSelectionAngle) > 0.5 || Math.min(normalizedLogicalGroupAngle, 360 - normalizedLogicalGroupAngle) > 0.5);
14558
+ if (isRotatedImageSelection) {
14559
+ const countKey = "__pixldocsRotatedImageResizeScaleTickCount";
14560
+ const count = (obj[countKey] ?? 0) + 1;
14561
+ obj[countKey] = count;
14562
+ if (count <= 5 || count % 8 === 0) {
14563
+ logRotatedGroupImageResizeDebug("active-selection-scaling", {
14564
+ time: Math.round(performance.now()),
14565
+ tick: count,
14566
+ handle: corner,
14567
+ groupSelectionId: activeLogicalGroupId,
14568
+ selectedStoreIds: useEditorStore.getState().canvas.selectedIds,
14569
+ route: typeof window !== "undefined" ? window.location.pathname : void 0,
14570
+ transformAction: (_d = fabricCanvas._currentTransform) == null ? void 0 : _d.action,
14571
+ transformCorner: (_e = fabricCanvas._currentTransform) == null ? void 0 : _e.corner,
14572
+ transformOriginal: (() => {
14573
+ var _a3;
14574
+ const original = (_a3 = fabricCanvas._currentTransform) == null ? void 0 : _a3.original;
14575
+ return original ? {
14576
+ left: original.left,
14577
+ top: original.top,
14578
+ width: original.width,
14579
+ height: original.height,
14580
+ scaleX: original.scaleX,
14581
+ scaleY: original.scaleY,
14582
+ angle: original.angle
14583
+ } : null;
14584
+ })(),
14585
+ transformStart: transformStartForDebug,
14586
+ selection: summarizeRotDriftObject(obj),
14587
+ imageChildren: imageChildrenForResizeDebug.map((child, childIndex) => ({
14588
+ childIndex,
14589
+ id: getObjectId(child),
14590
+ object: summarizeRotDriftObject(child)
14591
+ }))
14592
+ });
14593
+ }
14594
+ }
14473
14595
  if (isCornerResizeHandle(corner) && obj.getObjects().some((child) => child instanceof fabric__namespace.Textbox)) {
14474
14596
  obj.__pixldocsLastGroupTextScaleDebug = {
14475
14597
  time: Math.round(performance.now()),
14476
14598
  corner,
14477
14599
  groupSelectionId: obj.__pixldocsGroupSelection,
14478
- currentTransformAction: (_c2 = fabricCanvas._currentTransform) == null ? void 0 : _c2.action,
14600
+ currentTransformAction: (_f = fabricCanvas._currentTransform) == null ? void 0 : _f.action,
14479
14601
  selection: summarizeFabricObjectForResizeDebug(obj),
14480
14602
  textChildren: obj.getObjects().filter((child) => child instanceof fabric__namespace.Textbox).map((child) => summarizeFabricObjectForResizeDebug(child))
14481
14603
  };
@@ -14484,17 +14606,17 @@ const PageCanvas = react.forwardRef(
14484
14606
  if (obj instanceof fabric__namespace.ActiveSelection && (corner === "ml" || corner === "mr" || corner === "mt" || corner === "mb")) {
14485
14607
  const isXSide = corner === "ml" || corner === "mr";
14486
14608
  const _cur = fabricCanvas._currentTransform;
14487
- const startSx = Math.abs(Number(((_d = _cur == null ? void 0 : _cur.original) == null ? void 0 : _d.scaleX) ?? 1)) || 1;
14488
- const startSy = Math.abs(Number(((_e = _cur == null ? void 0 : _cur.original) == null ? void 0 : _e.scaleY) ?? 1)) || 1;
14609
+ const startSx = Math.abs(Number(((_g = _cur == null ? void 0 : _cur.original) == null ? void 0 : _g.scaleX) ?? 1)) || 1;
14610
+ const startSy = Math.abs(Number(((_h = _cur == null ? void 0 : _cur.original) == null ? void 0 : _h.scaleY) ?? 1)) || 1;
14489
14611
  const sAxis = isXSide ? Math.abs((obj.scaleX ?? 1) / startSx) : Math.abs((obj.scaleY ?? 1) / startSy);
14490
14612
  if (sAxis > 1e-3) {
14491
- if (isXSide && ((_f = groupShiftReflowSnapshotRef.current) == null ? void 0 : _f.selection) !== obj) {
14613
+ if (isXSide && ((_i = groupShiftReflowSnapshotRef.current) == null ? void 0 : _i.selection) !== obj) {
14492
14614
  groupShiftReflowSnapshotRef.current = null;
14493
14615
  const logicalGroupId = obj.__pixldocsGroupSelection;
14494
14616
  if (logicalGroupId) {
14495
14617
  try {
14496
14618
  const state = useEditorStore.getState();
14497
- const pageChildren2 = ((_g = state.canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _g.children) ?? [];
14619
+ const pageChildren2 = ((_j = state.canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _j.children) ?? [];
14498
14620
  const groupNode = findNodeById(pageChildren2, logicalGroupId);
14499
14621
  if (groupNode && isGroup(groupNode) && !isStackLayoutMode(groupNode.layoutMode)) {
14500
14622
  const entries = obj.getObjects().map((c) => ({
@@ -14532,7 +14654,7 @@ const PageCanvas = react.forwardRef(
14532
14654
  }
14533
14655
  continue;
14534
14656
  }
14535
- if (child instanceof fabric__namespace.Group && (child.__cropGroup || ((_h = child._ct) == null ? void 0 : _h.isCropGroup))) {
14657
+ if (child instanceof fabric__namespace.Group && (child.__cropGroup || ((_k = child._ct) == null ? void 0 : _k.isCropGroup))) {
14536
14658
  const ct = child.__cropData;
14537
14659
  if (!ct) continue;
14538
14660
  if (child.__asLiveOrigAngle == null) {
@@ -14699,7 +14821,7 @@ const PageCanvas = react.forwardRef(
14699
14821
  child.dirty = true;
14700
14822
  didReflowTextChild = true;
14701
14823
  }
14702
- if (isXSide && ((_i = groupShiftReflowSnapshotRef.current) == null ? void 0 : _i.selection) === obj) {
14824
+ if (isXSide && ((_l = groupShiftReflowSnapshotRef.current) == null ? void 0 : _l.selection) === obj) {
14703
14825
  const snap = groupShiftReflowSnapshotRef.current;
14704
14826
  const anchorEntry = snap.children[0];
14705
14827
  const anchorTopLive = anchorEntry.obj.top ?? 0;
@@ -14860,7 +14982,7 @@ const PageCanvas = react.forwardRef(
14860
14982
  setGuides(gridGuidesForScale.length ? [...scaleGuides, ...gridGuidesForScale] : scaleGuides);
14861
14983
  if (drilledGroupIdRef.current) {
14862
14984
  try {
14863
- (_j = fabricCanvas.__updateDrilledGroupOutline) == null ? void 0 : _j.call(fabricCanvas);
14985
+ (_m = fabricCanvas.__updateDrilledGroupOutline) == null ? void 0 : _m.call(fabricCanvas);
14864
14986
  } catch {
14865
14987
  }
14866
14988
  }
@@ -15084,7 +15206,6 @@ const PageCanvas = react.forwardRef(
15084
15206
  delete child.__asLiveOrigW;
15085
15207
  delete child.__asLiveOrigH;
15086
15208
  delete child.__asLiveRotSnap;
15087
- delete child.__asLiveOrigAngle;
15088
15209
  }
15089
15210
  }
15090
15211
  } catch {
@@ -15647,48 +15768,99 @@ const PageCanvas = react.forwardRef(
15647
15768
  if (obj instanceof fabric__namespace.Group && obj.__cropGroup) {
15648
15769
  const ct = obj.__cropData;
15649
15770
  if (ct) {
15650
- const sourceFrameW = Math.max(1, ct.frameW ?? obj.width ?? 1);
15651
- const sourceFrameH = Math.max(1, ct.frameH ?? obj.height ?? 1);
15652
- const appliedScaleX = isActiveSelection && activeObj ? Math.abs((activeObj.scaleX ?? 1) * (obj.scaleX ?? 1)) : Math.abs(obj.scaleX ?? 1);
15653
- const appliedScaleY = isActiveSelection && activeObj ? Math.abs((activeObj.scaleY ?? 1) * (obj.scaleY ?? 1)) : Math.abs(obj.scaleY ?? 1);
15654
- finalWidth = Math.max(1, sourceFrameW * appliedScaleX);
15655
- finalHeight = Math.max(1, sourceFrameH * appliedScaleY);
15656
- finalScaleX = 1;
15657
- finalScaleY = 1;
15658
- if (isActiveSelection && activeObj instanceof fabric__namespace.ActiveSelection) {
15659
- absoluteLeft = (decomposed.translateX ?? absoluteLeft) - finalWidth / 2;
15660
- absoluteTop = (decomposed.translateY ?? absoluteTop) - finalHeight / 2;
15661
- } else {
15662
- absoluteLeft = (decomposed.translateX ?? absoluteLeft) - finalWidth / 2;
15663
- absoluteTop = (decomposed.translateY ?? absoluteTop) - finalHeight / 2;
15664
- }
15665
- finalAbsoluteMatrix = fabric__namespace.util.composeMatrix({
15666
- translateX: absoluteLeft + finalWidth / 2,
15667
- translateY: absoluteTop + finalHeight / 2,
15668
- angle: decomposed.angle ?? (obj.angle ?? 0),
15669
- scaleX: 1,
15670
- scaleY: 1,
15671
- skewX: 0,
15672
- skewY: 0
15673
- });
15674
- if (isActiveSelection && activeObj instanceof fabric__namespace.ActiveSelection) {
15771
+ const cropChildLocalAngle = obj.__asLiveOrigAngle != null ? obj.__asLiveOrigAngle : obj.angle ?? 0;
15772
+ const cropChildNormAngle = (cropChildLocalAngle % 360 + 360) % 360;
15773
+ const cropChildIsRotated = Math.abs(cropChildNormAngle) > 0.5 && Math.abs(cropChildNormAngle - 360) > 0.5;
15774
+ const cropHandle = activeSelectionResizeHandle;
15775
+ const cropIsSideHandle = cropHandle === "ml" || cropHandle === "mr" || cropHandle === "mt" || cropHandle === "mb";
15776
+ const cropIsXSide = cropHandle === "ml" || cropHandle === "mr";
15777
+ if (isActiveSelection && activeObj instanceof fabric__namespace.ActiveSelection && cropChildIsRotated && cropIsSideHandle) {
15778
+ const sourceFrameW = Math.max(1, ct.frameW ?? obj.width ?? 1);
15779
+ const sourceFrameH = Math.max(1, ct.frameH ?? obj.height ?? 1);
15780
+ const asSx = Math.abs(activeObj.scaleX ?? 1);
15781
+ const asSy = Math.abs(activeObj.scaleY ?? 1);
15782
+ const axisScale = cropIsXSide ? asSx : asSy;
15783
+ const thetaC = fabric__namespace.util.degreesToRadians(cropChildLocalAngle);
15784
+ const cosC = Math.cos(thetaC);
15785
+ const sinC = Math.sin(thetaC);
15786
+ const sLocal = axisScale * cosC * cosC + sinC * sinC;
15787
+ const ownSx = Math.abs(obj.scaleX ?? 1);
15788
+ const ownSy = Math.abs(obj.scaleY ?? 1);
15789
+ const newFrameW = cropIsXSide ? sourceFrameW * ownSx * sLocal : sourceFrameW * ownSx;
15790
+ const newFrameH = cropIsXSide ? sourceFrameH * ownSy : sourceFrameH * ownSy * sLocal;
15791
+ finalWidth = Math.max(1, newFrameW);
15792
+ finalHeight = Math.max(1, newFrameH);
15793
+ finalScaleX = 1;
15794
+ finalScaleY = 1;
15795
+ const worldCx = decomposed.translateX ?? 0;
15796
+ const worldCy = decomposed.translateY ?? 0;
15797
+ const worldAngle = (activeObj.angle ?? 0) + cropChildLocalAngle;
15798
+ absoluteLeft = worldCx - finalWidth / 2;
15799
+ absoluteTop = worldCy - finalHeight / 2;
15800
+ finalAbsoluteMatrix = fabric__namespace.util.composeMatrix({
15801
+ translateX: worldCx,
15802
+ translateY: worldCy,
15803
+ angle: worldAngle,
15804
+ scaleX: 1,
15805
+ scaleY: 1,
15806
+ skewX: 0,
15807
+ skewY: 0
15808
+ });
15675
15809
  pendingCropGroupFrameBakes.push({
15676
15810
  obj,
15677
15811
  width: finalWidth,
15678
15812
  height: finalHeight,
15679
15813
  left: absoluteLeft,
15680
15814
  top: absoluteTop,
15681
- angle: decomposed.angle ?? (obj.angle ?? 0)
15815
+ angle: worldAngle
15682
15816
  });
15683
- } else {
15817
+ obj.__lastResizeHandle = null;
15684
15818
  ct.frameW = finalWidth;
15685
15819
  ct.frameH = finalHeight;
15686
- obj.set({ width: finalWidth, height: finalHeight, scaleX: 1, scaleY: 1 });
15687
- updateCoverLayout(obj);
15688
- }
15689
- obj.__lastResizeHandle = null;
15690
- if (!isActiveSelection) {
15691
- fabricCanvas.setActiveObject(obj);
15820
+ } else {
15821
+ const sourceFrameW = Math.max(1, ct.frameW ?? obj.width ?? 1);
15822
+ const sourceFrameH = Math.max(1, ct.frameH ?? obj.height ?? 1);
15823
+ const appliedScaleX = isActiveSelection && activeObj ? Math.abs((activeObj.scaleX ?? 1) * (obj.scaleX ?? 1)) : Math.abs(obj.scaleX ?? 1);
15824
+ const appliedScaleY = isActiveSelection && activeObj ? Math.abs((activeObj.scaleY ?? 1) * (obj.scaleY ?? 1)) : Math.abs(obj.scaleY ?? 1);
15825
+ finalWidth = Math.max(1, sourceFrameW * appliedScaleX);
15826
+ finalHeight = Math.max(1, sourceFrameH * appliedScaleY);
15827
+ finalScaleX = 1;
15828
+ finalScaleY = 1;
15829
+ if (isActiveSelection && activeObj instanceof fabric__namespace.ActiveSelection) {
15830
+ absoluteLeft = (decomposed.translateX ?? absoluteLeft) - finalWidth / 2;
15831
+ absoluteTop = (decomposed.translateY ?? absoluteTop) - finalHeight / 2;
15832
+ } else {
15833
+ absoluteLeft = (decomposed.translateX ?? absoluteLeft) - finalWidth / 2;
15834
+ absoluteTop = (decomposed.translateY ?? absoluteTop) - finalHeight / 2;
15835
+ }
15836
+ finalAbsoluteMatrix = fabric__namespace.util.composeMatrix({
15837
+ translateX: absoluteLeft + finalWidth / 2,
15838
+ translateY: absoluteTop + finalHeight / 2,
15839
+ angle: decomposed.angle ?? (obj.angle ?? 0),
15840
+ scaleX: 1,
15841
+ scaleY: 1,
15842
+ skewX: 0,
15843
+ skewY: 0
15844
+ });
15845
+ if (isActiveSelection && activeObj instanceof fabric__namespace.ActiveSelection) {
15846
+ pendingCropGroupFrameBakes.push({
15847
+ obj,
15848
+ width: finalWidth,
15849
+ height: finalHeight,
15850
+ left: absoluteLeft,
15851
+ top: absoluteTop,
15852
+ angle: decomposed.angle ?? (obj.angle ?? 0)
15853
+ });
15854
+ } else {
15855
+ ct.frameW = finalWidth;
15856
+ ct.frameH = finalHeight;
15857
+ obj.set({ width: finalWidth, height: finalHeight, scaleX: 1, scaleY: 1 });
15858
+ updateCoverLayout(obj);
15859
+ }
15860
+ obj.__lastResizeHandle = null;
15861
+ if (!isActiveSelection) {
15862
+ fabricCanvas.setActiveObject(obj);
15863
+ }
15692
15864
  }
15693
15865
  }
15694
15866
  } else if (obj instanceof fabric__namespace.FabricImage) {
@@ -15714,79 +15886,130 @@ const PageCanvas = react.forwardRef(
15714
15886
  useEditorStore.getState().updateElement(objId, { src: newSrc }, { recordHistory: false, skipLayoutRecalc: true });
15715
15887
  }
15716
15888
  } else if (isActiveSelection && (Math.abs((decomposed.scaleX ?? 1) - 1) > 1e-3 || Math.abs((decomposed.scaleY ?? 1) - 1) > 1e-3)) {
15717
- const sx = Math.abs(decomposed.scaleX || 1);
15718
- const sy = Math.abs(decomposed.scaleY || 1);
15719
- const handle = activeSelectionResizeHandle;
15720
- const isCornerHandle = handle === "tl" || handle === "tr" || handle === "bl" || handle === "br" || // Fallback: if handle ref is missing and sx≈sy with non-1 magnitude,
15721
- // treat as a uniform corner drag.
15722
- !handle && Math.abs(sx - sy) < 0.01 && Math.abs(sx - 1) > 1e-3;
15723
- let fx;
15724
- let fy;
15725
- if (isCornerHandle) {
15726
- const u = Math.max(1e-3, Math.sqrt(sx * sy));
15727
- fx = u;
15728
- fy = u;
15729
- } else {
15730
- fx = sx;
15731
- fy = sy;
15732
- }
15733
- const bakedW = Math.max(1, intrinsicWidth * fx);
15734
- const bakedH = Math.max(1, intrinsicHeight * fy);
15735
- try {
15736
- const preBakeCenter = obj.getCenterPoint();
15737
- const prevObjCaching = obj.objectCaching;
15738
- obj.set({
15739
- width: bakedW,
15740
- height: bakedH,
15889
+ const imgChildLocalAngle = obj.__asLiveOrigAngle != null ? obj.__asLiveOrigAngle : obj.angle ?? 0;
15890
+ const imgChildNormAngle = (imgChildLocalAngle % 360 + 360) % 360;
15891
+ const imgChildIsRotated = Math.abs(imgChildNormAngle) > 0.5 && Math.abs(imgChildNormAngle - 360) > 0.5;
15892
+ const imgHandle = activeSelectionResizeHandle;
15893
+ const imgIsSideHandle = imgHandle === "ml" || imgHandle === "mr" || imgHandle === "mt" || imgHandle === "mb";
15894
+ const imgIsXSide = imgHandle === "ml" || imgHandle === "mr";
15895
+ if (imgChildIsRotated && imgIsSideHandle && activeObj instanceof fabric__namespace.ActiveSelection) {
15896
+ const asSx = Math.abs(activeObj.scaleX ?? 1);
15897
+ const asSy = Math.abs(activeObj.scaleY ?? 1);
15898
+ const axisScale = imgIsXSide ? asSx : asSy;
15899
+ const thetaI = fabric__namespace.util.degreesToRadians(imgChildLocalAngle);
15900
+ const cI = Math.cos(thetaI);
15901
+ const sI = Math.sin(thetaI);
15902
+ const sLocalI = axisScale * cI * cI + sI * sI;
15903
+ const ownSx = Math.abs(obj.scaleX ?? 1);
15904
+ const ownSy = Math.abs(obj.scaleY ?? 1);
15905
+ const bakedW = Math.max(1, intrinsicWidth * ownSx * (imgIsXSide ? sLocalI : 1));
15906
+ const bakedH = Math.max(1, intrinsicHeight * ownSy * (imgIsXSide ? 1 : sLocalI));
15907
+ try {
15908
+ obj.set({
15909
+ width: bakedW,
15910
+ height: bakedH,
15911
+ scaleX: 1,
15912
+ scaleY: 1,
15913
+ skewX: 0,
15914
+ skewY: 0
15915
+ });
15916
+ obj.dirty = true;
15917
+ obj.setCoords();
15918
+ } catch {
15919
+ }
15920
+ finalWidth = bakedW;
15921
+ finalHeight = bakedH;
15922
+ finalScaleX = 1;
15923
+ finalScaleY = 1;
15924
+ const worldCx = decomposed.translateX ?? 0;
15925
+ const worldCy = decomposed.translateY ?? 0;
15926
+ const worldAngleI = (activeObj.angle ?? 0) + imgChildLocalAngle;
15927
+ absoluteLeft = worldCx - finalWidth / 2;
15928
+ absoluteTop = worldCy - finalHeight / 2;
15929
+ finalAbsoluteMatrix = fabric__namespace.util.composeMatrix({
15930
+ translateX: worldCx,
15931
+ translateY: worldCy,
15932
+ angle: worldAngleI,
15741
15933
  scaleX: 1,
15742
15934
  scaleY: 1,
15743
- objectCaching: false
15935
+ skewX: 0,
15936
+ skewY: 0
15744
15937
  });
15745
- obj.objectCaching = prevObjCaching;
15746
- if (sx > 0 && sy > 0) {
15747
- const localScaleX = 1 / sx;
15748
- const localScaleY = 1 / sy;
15749
- obj.set({ scaleX: localScaleX, scaleY: localScaleY });
15750
- const selectionMatrix = (_h = activeObj == null ? void 0 : activeObj.calcTransformMatrix) == null ? void 0 : _h.call(activeObj);
15751
- const localCenter = selectionMatrix ? fabric__namespace.util.transformPoint(preBakeCenter, fabric__namespace.util.invertTransform(selectionMatrix)) : preBakeCenter;
15752
- const localWidth = bakedW * localScaleX;
15753
- const localHeight = bakedH * localScaleY;
15754
- const isCenterOrigin = obj.originX === "center" || obj.originY === "center";
15755
- if (isCenterOrigin) {
15756
- obj.set({
15757
- left: localCenter.x,
15758
- top: localCenter.y
15759
- });
15760
- } else {
15761
- obj.set({
15762
- left: localCenter.x - localWidth / 2,
15763
- top: localCenter.y - localHeight / 2
15764
- });
15938
+ } else {
15939
+ const sx = Math.abs(decomposed.scaleX || 1);
15940
+ const sy = Math.abs(decomposed.scaleY || 1);
15941
+ const handle = activeSelectionResizeHandle;
15942
+ const isCornerHandle = handle === "tl" || handle === "tr" || handle === "bl" || handle === "br" || // Fallback: if handle ref is missing and sx≈sy with non-1 magnitude,
15943
+ // treat as a uniform corner drag.
15944
+ !handle && Math.abs(sx - sy) < 0.01 && Math.abs(sx - 1) > 1e-3;
15945
+ let fx;
15946
+ let fy;
15947
+ if (isCornerHandle) {
15948
+ const u = Math.max(1e-3, Math.sqrt(sx * sy));
15949
+ fx = u;
15950
+ fy = u;
15951
+ } else {
15952
+ fx = sx;
15953
+ fy = sy;
15954
+ }
15955
+ const bakedW = Math.max(1, intrinsicWidth * fx);
15956
+ const bakedH = Math.max(1, intrinsicHeight * fy);
15957
+ try {
15958
+ const preBakeCenter = obj.getCenterPoint();
15959
+ const prevObjCaching = obj.objectCaching;
15960
+ obj.set({
15961
+ width: bakedW,
15962
+ height: bakedH,
15963
+ scaleX: 1,
15964
+ scaleY: 1,
15965
+ objectCaching: false
15966
+ });
15967
+ obj.objectCaching = prevObjCaching;
15968
+ if (sx > 0 && sy > 0) {
15969
+ const localScaleX = 1 / sx;
15970
+ const localScaleY = 1 / sy;
15971
+ obj.set({ scaleX: localScaleX, scaleY: localScaleY });
15972
+ const selectionMatrix = (_h = activeObj == null ? void 0 : activeObj.calcTransformMatrix) == null ? void 0 : _h.call(activeObj);
15973
+ const localCenter = selectionMatrix ? fabric__namespace.util.transformPoint(preBakeCenter, fabric__namespace.util.invertTransform(selectionMatrix)) : preBakeCenter;
15974
+ const localWidth = bakedW * localScaleX;
15975
+ const localHeight = bakedH * localScaleY;
15976
+ const isCenterOrigin = obj.originX === "center" || obj.originY === "center";
15977
+ if (isCenterOrigin) {
15978
+ obj.set({
15979
+ left: localCenter.x,
15980
+ top: localCenter.y
15981
+ });
15982
+ } else {
15983
+ obj.set({
15984
+ left: localCenter.x - localWidth / 2,
15985
+ top: localCenter.y - localHeight / 2
15986
+ });
15987
+ }
15765
15988
  }
15989
+ obj.dirty = true;
15990
+ if (activeObj) activeObj.dirty = true;
15991
+ obj.setCoords();
15992
+ } catch {
15766
15993
  }
15767
- obj.dirty = true;
15768
- if (activeObj) activeObj.dirty = true;
15769
- obj.setCoords();
15770
- } catch {
15771
- }
15772
- finalWidth = bakedW;
15773
- finalHeight = bakedH;
15774
- finalScaleX = 1;
15775
- finalScaleY = 1;
15776
- try {
15777
- absoluteLeft = (decomposed.translateX ?? absoluteLeft) - finalWidth / 2;
15778
- absoluteTop = (decomposed.translateY ?? absoluteTop) - finalHeight / 2;
15779
- } catch {
15994
+ finalWidth = bakedW;
15995
+ finalHeight = bakedH;
15996
+ finalScaleX = 1;
15997
+ finalScaleY = 1;
15998
+ try {
15999
+ absoluteLeft = (decomposed.translateX ?? absoluteLeft) - finalWidth / 2;
16000
+ absoluteTop = (decomposed.translateY ?? absoluteTop) - finalHeight / 2;
16001
+ } catch {
16002
+ }
16003
+ finalAbsoluteMatrix = fabric__namespace.util.composeMatrix({
16004
+ translateX: decomposed.translateX,
16005
+ translateY: decomposed.translateY,
16006
+ angle: decomposed.angle ?? 0,
16007
+ scaleX: 1,
16008
+ scaleY: 1,
16009
+ skewX: 0,
16010
+ skewY: 0
16011
+ });
15780
16012
  }
15781
- finalAbsoluteMatrix = fabric__namespace.util.composeMatrix({
15782
- translateX: decomposed.translateX,
15783
- translateY: decomposed.translateY,
15784
- angle: decomposed.angle ?? 0,
15785
- scaleX: 1,
15786
- scaleY: 1,
15787
- skewX: 0,
15788
- skewY: 0
15789
- });
15790
16013
  } else {
15791
16014
  finalWidth = intrinsicWidth;
15792
16015
  finalHeight = intrinsicHeight;
@@ -16042,6 +16265,44 @@ const PageCanvas = react.forwardRef(
16042
16265
  }
16043
16266
  }
16044
16267
  }
16268
+ const isCropGroupObj = obj instanceof fabric__namespace.Group && obj.__cropGroup;
16269
+ const isPlainImageObj = obj instanceof fabric__namespace.FabricImage && !obj.__cropGroup && !obj.smartElementType;
16270
+ if (isActiveSelection && isActiveSelectionSideHandle && (isCropGroupObj || isPlainImageObj)) {
16271
+ const childLocalAngleSrc = obj.__asLiveOrigAngle != null ? obj.__asLiveOrigAngle : Number.isFinite(sourceElement == null ? void 0 : sourceElement.angle) ? sourceElement.angle ?? 0 : obj.angle ?? 0;
16272
+ const normAng = (childLocalAngleSrc % 360 + 360) % 360;
16273
+ const isRotatedImg = Math.min(normAng, 360 - normAng) > 0.5;
16274
+ if (isRotatedImg && activeObj instanceof fabric__namespace.ActiveSelection) {
16275
+ try {
16276
+ const cleanAngleI = (activeObj.angle ?? 0) + childLocalAngleSrc;
16277
+ const cleanW = Math.max(1, Number(elementUpdate.width ?? finalWidth));
16278
+ const cleanH = Math.max(1, Number(elementUpdate.height ?? finalHeight));
16279
+ const cx = decomposed.translateX ?? absoluteLeft + cleanW / 2;
16280
+ const cy = decomposed.translateY ?? absoluteTop + cleanH / 2;
16281
+ const cleanAbsLeft = cx - cleanW / 2;
16282
+ const cleanAbsTop = cy - cleanH / 2;
16283
+ const cleanStorePos = absoluteToStorePosition(cleanAbsLeft, cleanAbsTop, objId, pageChildrenForSave);
16284
+ elementUpdate.left = cleanStorePos.left;
16285
+ elementUpdate.top = cleanStorePos.top;
16286
+ elementUpdate.width = cleanW;
16287
+ elementUpdate.height = cleanH;
16288
+ elementUpdate.angle = cleanAngleI;
16289
+ elementUpdate.scaleX = 1;
16290
+ elementUpdate.scaleY = 1;
16291
+ elementUpdate.skewX = 0;
16292
+ elementUpdate.skewY = 0;
16293
+ elementUpdate.transformMatrix = fabric__namespace.util.composeMatrix({
16294
+ translateX: cx,
16295
+ translateY: cy,
16296
+ angle: cleanAngleI,
16297
+ scaleX: 1,
16298
+ scaleY: 1,
16299
+ skewX: 0,
16300
+ skewY: 0
16301
+ });
16302
+ } catch {
16303
+ }
16304
+ }
16305
+ }
16045
16306
  if (debugGroupTextCornerResize && obj instanceof fabric__namespace.Textbox) {
16046
16307
  logGroupTextResizeDebug("store-update-text", {
16047
16308
  time: Math.round(performance.now()),
@@ -16202,6 +16463,15 @@ const PageCanvas = react.forwardRef(
16202
16463
  groupSelectionTransformStartRef.current = null;
16203
16464
  activeSelectionMoveStartRef.current = null;
16204
16465
  activeSelectionResizeHandleRef.current = null;
16466
+ try {
16467
+ const t = e.target;
16468
+ if (t instanceof fabric__namespace.ActiveSelection) {
16469
+ for (const child of t.getObjects()) {
16470
+ delete child.__asLiveOrigAngle;
16471
+ }
16472
+ }
16473
+ } catch {
16474
+ }
16205
16475
  setTimeout(() => modifiedIdsThisRound.forEach((id) => justModifiedIdsRef.current.delete(id)), 150);
16206
16476
  commitHistory();
16207
16477
  unlockEditsSoon();
@@ -25269,9 +25539,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
25269
25539
  }
25270
25540
  return svgString;
25271
25541
  }
25272
- const resolvedPackageVersion = "0.5.410";
25542
+ const resolvedPackageVersion = "0.5.412";
25273
25543
  const PACKAGE_VERSION = resolvedPackageVersion;
25274
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.410";
25544
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.412";
25275
25545
  const roundParityValue = (value) => {
25276
25546
  if (typeof value !== "number") return value;
25277
25547
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -26085,7 +26355,7 @@ class PixldocsRenderer {
26085
26355
  await this.waitForCanvasScene(container, cloned, i);
26086
26356
  }
26087
26357
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
26088
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-BnnUwU40.cjs"));
26358
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-CywX_PY0.cjs"));
26089
26359
  const prepared = preparePagesForExport(
26090
26360
  cloned.pages,
26091
26361
  canvasWidth,
@@ -28405,7 +28675,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
28405
28675
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
28406
28676
  sanitizeSvgTreeForPdf(svgToDraw);
28407
28677
  try {
28408
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-BnnUwU40.cjs"));
28678
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-CywX_PY0.cjs"));
28409
28679
  try {
28410
28680
  await logTextMeasurementDiagnostic(svgToDraw);
28411
28681
  } catch {
@@ -28802,4 +29072,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
28802
29072
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
28803
29073
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
28804
29074
  exports.warmTemplateFromForm = warmTemplateFromForm;
28805
- //# sourceMappingURL=index-xCnkRHXB.cjs.map
29075
+ //# sourceMappingURL=index-Df-U5xVu.cjs.map