@pixldocs/canvas-renderer 0.5.300 → 0.5.302

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.
@@ -209,6 +209,26 @@ function removeNodeFromTree(children, id) {
209
209
  return node;
210
210
  });
211
211
  }
212
+ function pruneEmptyGroups(children) {
213
+ const prunedGroupIds = /* @__PURE__ */ new Set();
214
+ const walk = (nodes) => {
215
+ const next = [];
216
+ for (const node of nodes) {
217
+ if (isGroup(node)) {
218
+ const prunedChildren = walk(node.children);
219
+ if (prunedChildren.length === 0) {
220
+ prunedGroupIds.add(node.id);
221
+ continue;
222
+ }
223
+ next.push({ ...node, children: prunedChildren });
224
+ } else {
225
+ next.push(node);
226
+ }
227
+ }
228
+ return next;
229
+ };
230
+ return { children: walk(children), prunedGroupIds };
231
+ }
212
232
  function addNodeToTree(children, node, parentId, index) {
213
233
  if (!parentId) {
214
234
  if (index !== void 0) {
@@ -1522,8 +1542,16 @@ const useEditorStore = zustand.create((set, get) => ({
1522
1542
  if (rootLevelIds.has(id)) ;
1523
1543
  nextChildren = removeNodeFromTree(nextChildren, id);
1524
1544
  }
1545
+ const { children: prunedChildren, prunedGroupIds } = pruneEmptyGroups(nextChildren);
1546
+ nextChildren = prunedChildren;
1547
+ for (const gid of prunedGroupIds) {
1548
+ allDeletedIds.add(gid);
1549
+ if (rootLevelIds.has(gid)) ;
1550
+ }
1525
1551
  let nextCanvas = updateCurrentPageChildren(state.canvas, () => nextChildren);
1526
- nextCanvas.selectedIds = state.canvas.selectedIds.filter((id) => !ids.includes(id));
1552
+ nextCanvas.selectedIds = state.canvas.selectedIds.filter(
1553
+ (id) => !allDeletedIds.has(id) && !prunedGroupIds.has(id)
1554
+ );
1527
1555
  if (nextCanvas.themeConfig) {
1528
1556
  const remainingProps = nextCanvas.themeConfig.properties.filter((p) => !allDeletedIds.has(p.elementId));
1529
1557
  if (remainingProps.length !== nextCanvas.themeConfig.properties.length) {
@@ -11277,6 +11305,41 @@ const PageCanvas = react.forwardRef(
11277
11305
  const [groupResizeState, setGroupResizeState] = react.useState(null);
11278
11306
  const [groupOverlayLiveBounds, setGroupOverlayLiveBounds] = react.useState(null);
11279
11307
  const setGroupOverlayLiveBoundsRef = react.useRef(setGroupOverlayLiveBounds);
11308
+ const restoreSuppressedGroupMemberVisuals = react.useCallback(() => {
11309
+ const list = suppressGroupMemberBordersRef.current;
11310
+ if (!list || list.length === 0) return;
11311
+ for (const member of list) {
11312
+ const origBorders = member.__pixldocsOrigHasBorders;
11313
+ const origControls = member.__pixldocsOrigHasControls;
11314
+ const origLockX = member.__pixldocsOrigLockScalingX;
11315
+ if (origBorders !== void 0) member.hasBorders = origBorders;
11316
+ else member.hasBorders = true;
11317
+ if (origControls !== void 0) member.hasControls = origControls;
11318
+ else member.hasControls = true;
11319
+ if (origLockX !== void 0) {
11320
+ member.lockScalingX = origLockX;
11321
+ member.lockScalingY = member.__pixldocsOrigLockScalingY;
11322
+ }
11323
+ delete member.__pixldocsOrigHasBorders;
11324
+ delete member.__pixldocsOrigHasControls;
11325
+ delete member.__pixldocsOrigLockScalingX;
11326
+ delete member.__pixldocsOrigLockScalingY;
11327
+ }
11328
+ suppressGroupMemberBordersRef.current = [];
11329
+ }, []);
11330
+ const clearCanvasActiveVisuals = react.useCallback((fc) => {
11331
+ setGroupOverlayLiveBoundsRef.current(null);
11332
+ restoreSuppressedGroupMemberVisuals();
11333
+ try {
11334
+ fc.discardActiveObject();
11335
+ const topContext = fc.contextTop;
11336
+ if (topContext && typeof fc.clearContext === "function") {
11337
+ fc.clearContext(topContext);
11338
+ }
11339
+ fc.requestRenderAll();
11340
+ } catch {
11341
+ }
11342
+ }, [restoreSuppressedGroupMemberVisuals]);
11280
11343
  const skipSelectionClearOnDiscardRef = react.useRef(false);
11281
11344
  const skipActiveSelectionBakeOnClearRef = react.useRef(false);
11282
11345
  const preserveEditingScopeOnSelectionClearRef = react.useRef(false);
@@ -11365,6 +11428,34 @@ const PageCanvas = react.forwardRef(
11365
11428
  react.useEffect(() => {
11366
11429
  selectedIdsRef.current = selectedIds;
11367
11430
  }, [selectedIds]);
11431
+ react.useEffect(() => {
11432
+ const fc = fabricRef.current;
11433
+ if (!fc || !isActive || !currentPage) return;
11434
+ const pageChildren2 = currentPage.children ?? [];
11435
+ const hasMissingSelection = selectedIds.some((id) => !findNodeById(pageChildren2, id));
11436
+ const activeEditingGroupId = fc.__activeEditingGroupId ?? null;
11437
+ const activeEditingGroupMissing = !!activeEditingGroupId && !findNodeById(pageChildren2, activeEditingGroupId);
11438
+ const drilledGroupMissing = !!drilledGroupIdRef.current && !findNodeById(pageChildren2, drilledGroupIdRef.current);
11439
+ const hasGroupEditContext = !!activeEditingGroupId || !!drilledGroupIdRef.current;
11440
+ if (selectedIds.length === 0 && !hasGroupEditContext || hasMissingSelection || activeEditingGroupMissing || drilledGroupMissing) {
11441
+ fc.__activeEditingGroupId = null;
11442
+ drilledGroupIdRef.current = null;
11443
+ setDrilledGroupBounds(null);
11444
+ preserveActiveSelectionAfterTransformRef.current = null;
11445
+ recentGroupSelectionRestoreRef.current = null;
11446
+ clearCanvasActiveVisuals(fc);
11447
+ } else if (hasGroupEditContext) {
11448
+ requestAnimationFrame(() => {
11449
+ var _a2;
11450
+ if (fabricRef.current !== fc) return;
11451
+ try {
11452
+ (_a2 = fc.__updateDrilledGroupOutline) == null ? void 0 : _a2.call(fc);
11453
+ } catch {
11454
+ }
11455
+ fc.requestRenderAll();
11456
+ });
11457
+ }
11458
+ }, [selectedIds, currentPage, isActive, clearCanvasActiveVisuals]);
11368
11459
  react.useEffect(() => {
11369
11460
  isActiveRef.current = isActive;
11370
11461
  if (isEditorMode && isActive && fabricRef.current) ;
@@ -15266,7 +15357,7 @@ const PageCanvas = react.forwardRef(
15266
15357
  visibilityUpdateInProgressRef.current = false;
15267
15358
  }
15268
15359
  doSyncRef.current = () => {
15269
- var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j;
15360
+ var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k;
15270
15361
  const shouldSkipUpdates2 = syncLockedRef.current || editLockRef.current;
15271
15362
  const state = useEditorStore.getState();
15272
15363
  const elementsToSync = elements;
@@ -15291,10 +15382,20 @@ const PageCanvas = react.forwardRef(
15291
15382
  const activeBeforeSync = fc.getActiveObject();
15292
15383
  const transformSelectionId = preserveSelectionAfterTransformIdRef.current;
15293
15384
  const isTransforming2 = !!fc._currentTransform;
15294
- const activeSelectionSnapshot = activeBeforeSync instanceof fabric__namespace.ActiveSelection ? {
15385
+ const rawActiveSelectionSnapshot = activeBeforeSync instanceof fabric__namespace.ActiveSelection ? {
15295
15386
  memberIds: activeBeforeSync.getObjects().map((o) => getObjectId(o)).filter((id) => !!id && id !== "__background__"),
15296
15387
  groupSelectionId: activeBeforeSync.__pixldocsGroupSelection
15297
15388
  } : preserveActiveSelectionAfterTransformRef.current;
15389
+ const activeSelectionSnapshot = rawActiveSelectionSnapshot ? (() => {
15390
+ let memberIds = rawActiveSelectionSnapshot.memberIds.filter((id) => allElementIds.has(id));
15391
+ const groupSelectionId = rawActiveSelectionSnapshot.groupSelectionId;
15392
+ if (groupSelectionId) {
15393
+ const groupNode = findNodeById(pageTree, groupSelectionId);
15394
+ if (!groupNode || !isGroup(groupNode)) return null;
15395
+ memberIds = getAllElementIds(groupNode.children ?? []).filter((id) => allElementIds.has(id));
15396
+ }
15397
+ return memberIds.length > 0 ? { ...rawActiveSelectionSnapshot, memberIds, groupSelectionId } : null;
15398
+ })() : null;
15298
15399
  if (syncTriggeredByPanelRef.current && !transformSelectionId && !shouldSkipUpdates2 && !isTransforming2) {
15299
15400
  const activeObj = fc.getActiveObject();
15300
15401
  const activeObjId = activeObj ? getObjectId(activeObj) : null;
@@ -16088,6 +16189,12 @@ const PageCanvas = react.forwardRef(
16088
16189
  }
16089
16190
  }
16090
16191
  }
16192
+ if (fc.__activeEditingGroupId) {
16193
+ try {
16194
+ (_k = fc.__updateDrilledGroupOutline) == null ? void 0 : _k.call(fc);
16195
+ } catch {
16196
+ }
16197
+ }
16091
16198
  const recentGroupRestore = recentGroupSelectionRestoreRef.current;
16092
16199
  if ((recentGroupRestore == null ? void 0 : recentGroupRestore.groupSelectionId) && recentGroupRestore.expiresAt > Date.now()) {
16093
16200
  restoreGroupSelectionSnapshot(recentGroupRestore);
@@ -24015,9 +24122,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
24015
24122
  }
24016
24123
  return svgString;
24017
24124
  }
24018
- const resolvedPackageVersion = "0.5.300";
24125
+ const resolvedPackageVersion = "0.5.302";
24019
24126
  const PACKAGE_VERSION = resolvedPackageVersion;
24020
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.300";
24127
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.302";
24021
24128
  const roundParityValue = (value) => {
24022
24129
  if (typeof value !== "number") return value;
24023
24130
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
@@ -24831,7 +24938,7 @@ class PixldocsRenderer {
24831
24938
  await this.waitForCanvasScene(container, cloned, i);
24832
24939
  }
24833
24940
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
24834
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-BVHpWHXp.cjs"));
24941
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-DXYVw9V2.cjs"));
24835
24942
  const prepared = preparePagesForExport(
24836
24943
  cloned.pages,
24837
24944
  canvasWidth,
@@ -27151,7 +27258,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
27151
27258
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
27152
27259
  sanitizeSvgTreeForPdf(svgToDraw);
27153
27260
  try {
27154
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-BVHpWHXp.cjs"));
27261
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-DXYVw9V2.cjs"));
27155
27262
  try {
27156
27263
  await logTextMeasurementDiagnostic(svgToDraw);
27157
27264
  } catch {
@@ -27548,4 +27655,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
27548
27655
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
27549
27656
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
27550
27657
  exports.warmTemplateFromForm = warmTemplateFromForm;
27551
- //# sourceMappingURL=index-eWyfu-3k.cjs.map
27658
+ //# sourceMappingURL=index-Basn7lBW.cjs.map