@pixldocs/canvas-renderer 0.5.223 → 0.5.225

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.
@@ -2,6 +2,7 @@
2
2
  var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ var _a;
5
6
  const jsxRuntime = require("react/jsx-runtime");
6
7
  const react = require("react");
7
8
  const reactDom = require("react-dom");
@@ -290,12 +291,12 @@ function lineToString(line) {
290
291
  return Array.isArray(line) ? line.join("") : String(line ?? "");
291
292
  }
292
293
  function measureTextLineWithCanvas(textbox, lineText, lineIndex) {
293
- var _a, _b, _c, _d, _e;
294
+ var _a2, _b, _c, _d, _e;
294
295
  if (!lineText) return 0;
295
296
  const ctx = getMeasureContext();
296
297
  if (!ctx) return null;
297
298
  const tb = textbox;
298
- const fontSize = Number(((_a = tb.getValueOfPropertyAt) == null ? void 0 : _a.call(tb, lineIndex, 0, "fontSize")) ?? textbox.fontSize ?? 16);
299
+ const fontSize = Number(((_a2 = tb.getValueOfPropertyAt) == null ? void 0 : _a2.call(tb, lineIndex, 0, "fontSize")) ?? textbox.fontSize ?? 16);
299
300
  const fontStyle = String(((_b = tb.getValueOfPropertyAt) == null ? void 0 : _b.call(tb, lineIndex, 0, "fontStyle")) ?? textbox.fontStyle ?? "normal");
300
301
  const fontWeight = String(((_c = tb.getValueOfPropertyAt) == null ? void 0 : _c.call(tb, lineIndex, 0, "fontWeight")) ?? textbox.fontWeight ?? "400");
301
302
  const fontFamily = String(((_d = tb.getValueOfPropertyAt) == null ? void 0 : _d.call(tb, lineIndex, 0, "fontFamily")) ?? textbox.fontFamily ?? "Open Sans");
@@ -619,7 +620,7 @@ function resolveStackGroupEffectivePositions(group, pageChildren, options) {
619
620
  return out;
620
621
  }
621
622
  function groupBoundsFromChildren(group, pageChildren, options) {
622
- var _a, _b;
623
+ var _a2, _b;
623
624
  const kids = group.children ?? [];
624
625
  if (kids.length === 0) {
625
626
  const w = group.width;
@@ -631,7 +632,7 @@ function groupBoundsFromChildren(group, pageChildren, options) {
631
632
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
632
633
  for (const child of kids) {
633
634
  const b = getNodeBounds(child, pageChildren);
634
- const cl = positions ? ((_a = positions.get(child.id)) == null ? void 0 : _a.left) ?? getNodeLeft(child) : getNodeLeft(child);
635
+ const cl = positions ? ((_a2 = positions.get(child.id)) == null ? void 0 : _a2.left) ?? getNodeLeft(child) : getNodeLeft(child);
635
636
  const ct = positions ? ((_b = positions.get(child.id)) == null ? void 0 : _b.top) ?? getNodeTop(child) : getNodeTop(child);
636
637
  minX = Math.min(minX, cl);
637
638
  minY = Math.min(minY, ct);
@@ -670,13 +671,13 @@ function getNodeBoundsFromChildren(node) {
670
671
  return getNodeBounds(node);
671
672
  }
672
673
  function absoluteBoundsRecur(node, pageChildren, options) {
673
- var _a, _b;
674
+ var _a2, _b;
674
675
  const parent = pageChildren ? findParentGroup(pageChildren, node.id) : null;
675
676
  const b = getNodeBounds(node, pageChildren);
676
677
  if (!parent) return b;
677
678
  const parentAbs = absoluteBoundsRecur(parent, pageChildren);
678
679
  const isStackParent = isStackLayoutMode(parent.layoutMode);
679
- const inParentLeft = isStackParent ? ((_a = resolveStackGroupEffectivePositions(parent, pageChildren).get(node.id)) == null ? void 0 : _a.left) ?? b.left : b.left;
680
+ const inParentLeft = isStackParent ? ((_a2 = resolveStackGroupEffectivePositions(parent, pageChildren).get(node.id)) == null ? void 0 : _a2.left) ?? b.left : b.left;
680
681
  const inParentTop = isStackParent ? ((_b = resolveStackGroupEffectivePositions(parent, pageChildren).get(node.id)) == null ? void 0 : _b.top) ?? b.top : b.top;
681
682
  return {
682
683
  left: parentAbs.left + inParentLeft,
@@ -695,22 +696,41 @@ function absoluteToStorePosition(absoluteLeft, absoluteTop, nodeId, pageChildren
695
696
  const parent = findParentGroup(pageChildren, nodeId);
696
697
  if (!parent) return { left: absoluteLeft, top: absoluteTop };
697
698
  const parentAbs = getAbsoluteBounds(parent, pageChildren);
698
- const storeLeft = absoluteLeft - parentAbs.left;
699
+ const inParentLeft = absoluteLeft - parentAbs.left;
699
700
  const inParentTop = absoluteTop - parentAbs.top;
700
701
  const isStack = isStackLayoutMode(parent.layoutMode);
701
- if (!isStack) return { left: storeLeft, top: inParentTop };
702
+ if (!isStack) return { left: inParentLeft, top: inParentTop };
702
703
  const kids = parent.children ?? [];
703
704
  const idx = kids.findIndex((c) => c.id === nodeId);
704
- if (idx < 0) return { left: storeLeft, top: inParentTop };
705
- if (idx === 0) return { left: storeLeft, top: inParentTop };
705
+ if (idx < 0) return { left: inParentLeft, top: inParentTop };
706
706
  const gap = parent.stackSpacing ?? 8;
707
+ const padTop = parent.paddingTop ?? 0;
708
+ const padLeft = parent.paddingLeft ?? 0;
709
+ const marginTop = node.marginTop ?? 0;
710
+ const marginLeft = node.marginLeft ?? 0;
707
711
  const resolved = resolveStackGroupEffectivePositions(parent, pageChildren);
708
- const prev = kids[idx - 1];
709
- const prevResolved = resolved.get(prev.id);
710
- const prevHeight = getNodeBounds(prev, pageChildren).height;
711
- const prevBottom = prevResolved ? prevResolved.top + prevHeight + (prev.marginBottom ?? 0) : 0;
712
- const storeTop = inParentTop - prevBottom - gap;
713
- return { left: storeLeft, top: Math.max(0, storeTop) };
712
+ if (isVerticalStackLayoutMode(parent.layoutMode)) {
713
+ const baseTop = idx === 0 ? padTop : (() => {
714
+ const prev = kids[idx - 1];
715
+ const prevResolved = resolved.get(prev.id);
716
+ const prevHeight = getNodeBounds(prev, pageChildren).height;
717
+ return (prevResolved ? prevResolved.top + prevHeight + (prev.marginBottom ?? 0) : padTop) + gap;
718
+ })();
719
+ return {
720
+ left: inParentLeft - padLeft - marginLeft,
721
+ top: inParentTop - baseTop - marginTop
722
+ };
723
+ }
724
+ const baseLeft = idx === 0 ? padLeft : (() => {
725
+ const prev = kids[idx - 1];
726
+ const prevResolved = resolved.get(prev.id);
727
+ const prevWidth = getNodeBounds(prev, pageChildren).width;
728
+ return (prevResolved ? prevResolved.left + prevWidth + (prev.marginRight ?? 0) : padLeft) + gap;
729
+ })();
730
+ return {
731
+ left: inParentLeft - baseLeft - marginLeft,
732
+ top: inParentTop - padTop - marginTop
733
+ };
714
734
  }
715
735
  function reflowPageFromRoot(_pageChildren) {
716
736
  return /* @__PURE__ */ new Map();
@@ -808,6 +828,31 @@ function rewriteFieldMappings(mappings, idMap) {
808
828
  if (!(mappings == null ? void 0 : mappings.length)) return [];
809
829
  return mappings.filter((m) => idMap.has(m.elementId)).map((m) => ({ ...m, elementId: idMap.get(m.elementId) }));
810
830
  }
831
+ let canvasRegistry = /* @__PURE__ */ new Map();
832
+ function registerFabricCanvas(pageId, canvas) {
833
+ const existing = canvasRegistry.get(pageId);
834
+ const registryKey = existing && existing !== canvas ? `${pageId}#${Math.random().toString(36).slice(2, 10)}` : pageId;
835
+ canvasRegistry.set(registryKey, canvas);
836
+ return registryKey;
837
+ }
838
+ function unregisterFabricCanvas(pageId, canvas) {
839
+ if (canvas) {
840
+ const existing = canvasRegistry.get(pageId);
841
+ if (existing === canvas) canvasRegistry.delete(pageId);
842
+ return;
843
+ }
844
+ canvasRegistry.delete(pageId);
845
+ }
846
+ function getCanvasForPage(pageId) {
847
+ return canvasRegistry.get(pageId) || null;
848
+ }
849
+ let visibilityOnlyUpdatePendingUntil = 0;
850
+ function markVisibilityOnlyUpdate(ttlMs = 300) {
851
+ visibilityOnlyUpdatePendingUntil = Date.now() + Math.max(0, ttlMs);
852
+ }
853
+ function isVisibilityOnlyUpdatePending() {
854
+ return Date.now() < visibilityOnlyUpdatePendingUntil;
855
+ }
811
856
  const defaultProjectSettings = {
812
857
  showGrid: false,
813
858
  snapToGrid: false,
@@ -1112,7 +1157,7 @@ const useEditorStore = zustand.create((set, get) => ({
1112
1157
  return out;
1113
1158
  }),
1114
1159
  updateNode: (id, updates, options) => set((state) => {
1115
- var _a;
1160
+ var _a2;
1116
1161
  const mergedUpdates = { ...updates };
1117
1162
  let nextCanvas = updateCurrentPageChildren(
1118
1163
  state.canvas,
@@ -1185,7 +1230,7 @@ const useEditorStore = zustand.create((set, get) => ({
1185
1230
  let next = updateNodeInTree(currentPage.children, id, { children: sortedKids });
1186
1231
  const groupSorted = findNodeById(next, id);
1187
1232
  const orderedKids = (groupSorted == null ? void 0 : groupSorted.children) ?? sortedKids;
1188
- const firstLeft = typeof ((_a = orderedKids[0]) == null ? void 0 : _a.left) === "number" ? orderedKids[0].left : 0;
1233
+ const firstLeft = typeof ((_a2 = orderedKids[0]) == null ? void 0 : _a2.left) === "number" ? orderedKids[0].left : 0;
1189
1234
  let prevBottom = 0;
1190
1235
  for (let i = 0; i < orderedKids.length; i++) {
1191
1236
  const child = orderedKids[i];
@@ -1291,7 +1336,7 @@ const useEditorStore = zustand.create((set, get) => ({
1291
1336
  return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };
1292
1337
  }),
1293
1338
  deleteNodes: (ids) => set((state) => {
1294
- var _a;
1339
+ var _a2;
1295
1340
  const currentPage = getCurrentPageFromCanvas(state.canvas);
1296
1341
  let nextChildren = currentPage.children;
1297
1342
  const rootLevelIds = new Set(currentPage.children.map((c) => c.id));
@@ -1329,7 +1374,7 @@ const useEditorStore = zustand.create((set, get) => ({
1329
1374
  };
1330
1375
  }
1331
1376
  }
1332
- if ((_a = nextCanvas.dynamicFields) == null ? void 0 : _a.length) {
1377
+ if ((_a2 = nextCanvas.dynamicFields) == null ? void 0 : _a2.length) {
1333
1378
  nextCanvas = {
1334
1379
  ...nextCanvas,
1335
1380
  dynamicFields: nextCanvas.dynamicFields.map((f) => ({
@@ -1601,6 +1646,7 @@ const useEditorStore = zustand.create((set, get) => ({
1601
1646
  const node = findNodeById(currentPage.children, id);
1602
1647
  if (!node) return {};
1603
1648
  const newVisible = node.visible === false ? true : false;
1649
+ markVisibilityOnlyUpdate();
1604
1650
  const nextCanvas = updateCurrentPageChildren(
1605
1651
  state.canvas,
1606
1652
  (children) => updateNodeInTree(children, id, { visible: newVisible })
@@ -1638,6 +1684,7 @@ const useEditorStore = zustand.create((set, get) => ({
1638
1684
  group.children.forEach((child) => {
1639
1685
  collectChildren(child);
1640
1686
  });
1687
+ markVisibilityOnlyUpdate();
1641
1688
  let nextCanvas = state.canvas;
1642
1689
  nodeIds.forEach((id) => {
1643
1690
  nextCanvas = updateCurrentPageChildren(
@@ -1909,8 +1956,8 @@ const useEditorStore = zustand.create((set, get) => ({
1909
1956
  if (stopMatch) {
1910
1957
  const stopIndex = parseInt(stopMatch[1], 10);
1911
1958
  updatedPages = updatedPages.map((p) => {
1912
- var _a;
1913
- if (!((_a = p.settings.backgroundGradient) == null ? void 0 : _a.stops[stopIndex])) return p;
1959
+ var _a2;
1960
+ if (!((_a2 = p.settings.backgroundGradient) == null ? void 0 : _a2.stops[stopIndex])) return p;
1914
1961
  return {
1915
1962
  ...p,
1916
1963
  settings: {
@@ -1986,8 +2033,8 @@ const useEditorStore = zustand.create((set, get) => ({
1986
2033
  if (nodesToGroup.length < 2) return {};
1987
2034
  const parentGroups = topLevelIds.map((id) => findParentGroup(currentPage.children, id));
1988
2035
  const commonParent = parentGroups.length > 0 && parentGroups.every((p) => {
1989
- var _a;
1990
- return (p == null ? void 0 : p.id) === ((_a = parentGroups[0]) == null ? void 0 : _a.id);
2036
+ var _a2;
2037
+ return (p == null ? void 0 : p.id) === ((_a2 = parentGroups[0]) == null ? void 0 : _a2.id);
1991
2038
  }) ? parentGroups[0] : null;
1992
2039
  let insertIndex = void 0;
1993
2040
  if (commonParent && topLevelIds.length > 0) {
@@ -2080,20 +2127,36 @@ const useEditorStore = zustand.create((set, get) => ({
2080
2127
  const parentId = (parentGroup == null ? void 0 : parentGroup.id) || null;
2081
2128
  const siblings = parentGroup ? parentGroup.children : currentPage.children;
2082
2129
  const groupIndex = siblings.findIndex((n) => n.id === groupId);
2130
+ const childAbs = group.children.map((c) => getAbsoluteBounds(c, currentPage.children));
2131
+ const followingSiblingAbs = siblings.slice(Math.max(0, groupIndex + 1)).map((sibling) => ({ id: sibling.id, abs: getAbsoluteBounds(sibling, currentPage.children) }));
2083
2132
  let nextChildren = removeNodeFromTree(currentPage.children, groupId);
2084
- const parentAbs = parentId ? getAbsoluteBounds(findNodeById(nextChildren, parentId), nextChildren) : null;
2085
- for (let i = 0; i < group.children.length; i++) {
2133
+ const placeStoredToMatchAbs = (tree, nodeId, target) => {
2134
+ let t = updateNodeInTree(tree, nodeId, { left: 0, top: 0 });
2135
+ const placed = findNodeById(t, nodeId);
2136
+ if (!placed) return t;
2137
+ const cur = getAbsoluteBounds(placed, t);
2138
+ const dl = target.left - cur.left;
2139
+ const dt = target.top - cur.top;
2140
+ return updateNodeInTree(t, nodeId, { left: dl, top: dt });
2141
+ };
2142
+ const insertReversed = parentId === null;
2143
+ const promotionOrder = insertReversed ? group.children.map((_, i) => group.children.length - 1 - i) : group.children.map((_, i) => i);
2144
+ for (let slot = 0; slot < promotionOrder.length; slot++) {
2145
+ const i = promotionOrder[slot];
2086
2146
  const child = group.children[i];
2087
- const abs = getAbsoluteBounds(child, currentPage.children);
2088
- const storeLeft = parentAbs ? abs.left - parentAbs.left : abs.left;
2089
- const storeTop = parentAbs ? abs.top - parentAbs.top : abs.top;
2090
- const childWithPos = isElement(child) ? { ...child, left: storeLeft, top: storeTop } : { ...child, left: storeLeft, top: storeTop };
2091
- nextChildren = addNodeToTree(nextChildren, childWithPos, parentId, groupIndex + i);
2147
+ const abs = childAbs[i];
2148
+ const placeholder = isElement(child) ? { ...child, left: 0, top: 0 } : { ...child, left: 0, top: 0 };
2149
+ nextChildren = addNodeToTree(nextChildren, placeholder, parentId, groupIndex + slot);
2150
+ nextChildren = placeStoredToMatchAbs(nextChildren, child.id, { left: abs.left, top: abs.top });
2151
+ }
2152
+ for (const { id, abs } of followingSiblingAbs) {
2153
+ if (!findNodeById(nextChildren, id)) continue;
2154
+ nextChildren = placeStoredToMatchAbs(nextChildren, id, { left: abs.left, top: abs.top });
2092
2155
  }
2093
2156
  const nextCanvas = updateCurrentPageChildren(state.canvas, () => nextChildren);
2094
2157
  nextCanvas.selectedIds = getAllElementIds(group.children);
2095
2158
  const committed = commitFromState(state, nextCanvas);
2096
- return { canvas: nextCanvas, ...committed };
2159
+ return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };
2097
2160
  }),
2098
2161
  renameNode: (id, name) => set((state) => {
2099
2162
  const nextCanvas = updateCurrentPageChildren(
@@ -2165,7 +2228,7 @@ const useEditorStore = zustand.create((set, get) => ({
2165
2228
  return { canvas: nextCanvas, ...committed };
2166
2229
  }),
2167
2230
  deletePage: (pageId) => set((state) => {
2168
- var _a;
2231
+ var _a2;
2169
2232
  if (state.canvas.pages.length <= 1) return {};
2170
2233
  const deletedPage = state.canvas.pages.find((p) => p.id === pageId);
2171
2234
  const newPages = state.canvas.pages.filter((p) => p.id !== pageId);
@@ -2201,7 +2264,7 @@ const useEditorStore = zustand.create((set, get) => ({
2201
2264
  };
2202
2265
  }
2203
2266
  }
2204
- if (((_a = nextCanvas.dynamicFields) == null ? void 0 : _a.length) && deletedElementIds.size > 0) {
2267
+ if (((_a2 = nextCanvas.dynamicFields) == null ? void 0 : _a2.length) && deletedElementIds.size > 0) {
2205
2268
  nextCanvas = {
2206
2269
  ...nextCanvas,
2207
2270
  dynamicFields: nextCanvas.dynamicFields.map((f) => ({ ...f, mappings: (f.mappings ?? []).filter((m) => !deletedElementIds.has(m.elementId)) })).filter((f) => (f.mappings ?? []).length > 0)
@@ -2314,7 +2377,7 @@ const useEditorStore = zustand.create((set, get) => ({
2314
2377
  return { canvas: nextCanvas, ...committed };
2315
2378
  }),
2316
2379
  updatePageSettings: (pageId, settings) => set((state) => {
2317
- var _a;
2380
+ var _a2;
2318
2381
  const updatedPages = state.canvas.pages.map(
2319
2382
  (p) => p.id === pageId ? { ...p, settings: { ...p.settings, ...settings } } : p
2320
2383
  );
@@ -2333,11 +2396,11 @@ const useEditorStore = zustand.create((set, get) => ({
2333
2396
  if ("backgroundGradient" in settings) {
2334
2397
  const grad = settings.backgroundGradient;
2335
2398
  const gradStopProps = themeConfig.properties.filter((p) => {
2336
- var _a2;
2337
- return p.elementId === PAGE_BG_ID && p.targetProperty === "backgroundGradient" && ((_a2 = p.svgColorKey) == null ? void 0 : _a2.startsWith("stop:"));
2399
+ var _a3;
2400
+ return p.elementId === PAGE_BG_ID && p.targetProperty === "backgroundGradient" && ((_a3 = p.svgColorKey) == null ? void 0 : _a3.startsWith("stop:"));
2338
2401
  });
2339
2402
  for (const prop of gradStopProps) {
2340
- const stopMatch = (_a = prop.svgColorKey) == null ? void 0 : _a.match(/^stop:(\d+)$/);
2403
+ const stopMatch = (_a2 = prop.svgColorKey) == null ? void 0 : _a2.match(/^stop:(\d+)$/);
2341
2404
  if (stopMatch && grad) {
2342
2405
  const stopIndex = parseInt(stopMatch[1], 10);
2343
2406
  if (grad.stops[stopIndex]) {
@@ -2474,7 +2537,7 @@ const useEditorStore = zustand.create((set, get) => ({
2474
2537
  }),
2475
2538
  // === LOAD/RESET ===
2476
2539
  loadConfig: (config) => set((state) => {
2477
- var _a;
2540
+ var _a2;
2478
2541
  const collapsedGroups = /* @__PURE__ */ new Set();
2479
2542
  const collectCollapsedGroups = (nodes) => {
2480
2543
  for (const node of nodes) {
@@ -2542,7 +2605,7 @@ const useEditorStore = zustand.create((set, get) => ({
2542
2605
  width: config.canvas.width,
2543
2606
  height: config.canvas.height,
2544
2607
  pages: pagesWithPositions,
2545
- currentPageId: ((_a = config.pages[0]) == null ? void 0 : _a.id) || "page-1",
2608
+ currentPageId: ((_a2 = config.pages[0]) == null ? void 0 : _a2.id) || "page-1",
2546
2609
  selectedIds: [],
2547
2610
  zoom: 1,
2548
2611
  pan: { x: 0, y: 0 },
@@ -2621,24 +2684,6 @@ const useEditorStore = zustand.create((set, get) => ({
2621
2684
  };
2622
2685
  })
2623
2686
  }));
2624
- let canvasRegistry = /* @__PURE__ */ new Map();
2625
- function registerFabricCanvas(pageId, canvas) {
2626
- const existing = canvasRegistry.get(pageId);
2627
- const registryKey = existing && existing !== canvas ? `${pageId}#${Math.random().toString(36).slice(2, 10)}` : pageId;
2628
- canvasRegistry.set(registryKey, canvas);
2629
- return registryKey;
2630
- }
2631
- function unregisterFabricCanvas(pageId, canvas) {
2632
- if (canvas) {
2633
- const existing = canvasRegistry.get(pageId);
2634
- if (existing === canvas) canvasRegistry.delete(pageId);
2635
- return;
2636
- }
2637
- canvasRegistry.delete(pageId);
2638
- }
2639
- function getCanvasForPage(pageId) {
2640
- return canvasRegistry.get(pageId) || null;
2641
- }
2642
2687
  const LOCAL_FONTS = /* @__PURE__ */ new Set([
2643
2688
  // Original local fonts (static TTFs)
2644
2689
  "Playfair Display",
@@ -3302,12 +3347,12 @@ const waitUntilFontsAvailable = async (fontFamilies, options) => {
3302
3347
  }
3303
3348
  };
3304
3349
  const clearFabricCharCache = () => {
3305
- var _a;
3350
+ var _a2;
3306
3351
  const fabricAny = fabric__namespace;
3307
3352
  if (fabricAny.cache && typeof fabricAny.cache.clearFontCache === "function") {
3308
3353
  fabricAny.cache.clearFontCache();
3309
3354
  }
3310
- if (((_a = fabricAny.cache) == null ? void 0 : _a.charWidthsCache) instanceof Map) {
3355
+ if (((_a2 = fabricAny.cache) == null ? void 0 : _a2.charWidthsCache) instanceof Map) {
3311
3356
  fabricAny.cache.charWidthsCache.clear();
3312
3357
  }
3313
3358
  if (typeof fabricAny.charWidthsCache === "object" && fabricAny.charWidthsCache !== null) {
@@ -3333,14 +3378,14 @@ const clearFontCacheAndRerender = (canvas, options = {}) => {
3333
3378
  }
3334
3379
  };
3335
3380
  const collectUnderlineMetrics = (obj) => {
3336
- var _a, _b;
3381
+ var _a2, _b;
3337
3382
  if (obj instanceof fabric__namespace.Textbox) {
3338
3383
  if (!obj.underline) return [];
3339
3384
  const lineWidths = obj.__lineWidths;
3340
3385
  return [{
3341
3386
  id: getObjectId(obj) ?? null,
3342
3387
  text: (obj.text || "").slice(0, 120),
3343
- textLength: ((_a = obj.text) == null ? void 0 : _a.length) ?? 0,
3388
+ textLength: ((_a2 = obj.text) == null ? void 0 : _a2.length) ?? 0,
3344
3389
  fontFamily: obj.fontFamily,
3345
3390
  fontSize: obj.fontSize,
3346
3391
  fontWeight: obj.fontWeight,
@@ -3362,11 +3407,11 @@ const clearFontCacheAndRerender = (canvas, options = {}) => {
3362
3407
  logUnderlineDebug("before-rerender", beforeMetrics);
3363
3408
  }
3364
3409
  const markDirty = (obj) => {
3365
- var _a;
3410
+ var _a2;
3366
3411
  if (obj instanceof fabric__namespace.Textbox) {
3367
3412
  obj.dirty = true;
3368
3413
  } else if (obj instanceof fabric__namespace.Group) {
3369
- (_a = obj._objects) == null ? void 0 : _a.forEach(markDirty);
3414
+ (_a2 = obj._objects) == null ? void 0 : _a2.forEach(markDirty);
3370
3415
  obj.dirty = true;
3371
3416
  }
3372
3417
  };
@@ -3378,11 +3423,11 @@ const clearFontCacheAndRerender = (canvas, options = {}) => {
3378
3423
  canvas.requestRenderAll();
3379
3424
  };
3380
3425
  const ensureFontLoaded = async (fontFamily) => {
3381
- var _a, _b, _c;
3426
+ var _a2, _b, _c;
3382
3427
  if (!fontFamily) return;
3383
3428
  if (LOCAL_FONTS.has(fontFamily)) {
3384
3429
  try {
3385
- const isLoaded = (_a = document.fonts) == null ? void 0 : _a.check(`16px "${fontFamily}"`);
3430
+ const isLoaded = (_a2 = document.fonts) == null ? void 0 : _a2.check(`16px "${fontFamily}"`);
3386
3431
  if (isLoaded) return;
3387
3432
  await ((_b = document.fonts) == null ? void 0 : _b.load(`16px "${fontFamily}"`));
3388
3433
  await ((_c = document.fonts) == null ? void 0 : _c.load(`bold 16px "${fontFamily}"`));
@@ -3644,9 +3689,9 @@ async function getNormalizedSvgUrl(imageUrl, colorMap, sourceFormat) {
3644
3689
  return `data:image/svg+xml,${encoded}`;
3645
3690
  }
3646
3691
  async function normalizeSvgImageDimensions(fabricImage, imageUrl, sourceFormat) {
3647
- var _a;
3692
+ var _a2;
3648
3693
  if (!isSvgImage(imageUrl, sourceFormat)) return;
3649
- const el = ((_a = fabricImage.getElement) == null ? void 0 : _a.call(fabricImage)) ?? fabricImage._element;
3694
+ const el = ((_a2 = fabricImage.getElement) == null ? void 0 : _a2.call(fabricImage)) ?? fabricImage._element;
3650
3695
  let w = 0;
3651
3696
  let h = 0;
3652
3697
  const dims = await loadSvgDimensions(imageUrl);
@@ -3699,7 +3744,7 @@ function stabilizePlaceholderGroup(group, width, height) {
3699
3744
  }
3700
3745
  function attachEmptyPlaceholderImage(group, width, height) {
3701
3746
  loadPlaceholderTile().then((htmlImg) => {
3702
- var _a;
3747
+ var _a2;
3703
3748
  const objects = group._objects;
3704
3749
  const bgRect = objects == null ? void 0 : objects.find((obj) => obj.__isPlaceholderFrame);
3705
3750
  if (!bgRect) return;
@@ -3727,7 +3772,7 @@ function attachEmptyPlaceholderImage(group, width, height) {
3727
3772
  }
3728
3773
  stabilizePlaceholderGroup(group, width, height);
3729
3774
  group.dirty = true;
3730
- (_a = group.canvas) == null ? void 0 : _a.requestRenderAll();
3775
+ (_a2 = group.canvas) == null ? void 0 : _a2.requestRenderAll();
3731
3776
  }).catch(() => {
3732
3777
  });
3733
3778
  }
@@ -3879,7 +3924,7 @@ function createImageClipPath(element, imgWidth, imgHeight) {
3879
3924
  }
3880
3925
  }
3881
3926
  async function loadImageAsync(element, placeholder, fc, fabricRef, syncLockedRef, isTransforming) {
3882
- var _a, _b, _c, _d;
3927
+ var _a2, _b, _c, _d;
3883
3928
  const imageUrl = element.src || element.imageUrl;
3884
3929
  if (!imageUrl) return;
3885
3930
  const nextSvgColorMap = element.svgColorMap ? JSON.stringify(element.svgColorMap) : "";
@@ -4041,7 +4086,7 @@ async function loadImageAsync(element, placeholder, fc, fabricRef, syncLockedRef
4041
4086
  let panY = 0.5;
4042
4087
  let zoom = 1;
4043
4088
  if (existingCropGroup) {
4044
- const existingImg = (_a = existingCropGroup.__cropData) == null ? void 0 : _a._img;
4089
+ const existingImg = (_a2 = existingCropGroup.__cropData) == null ? void 0 : _a2._img;
4045
4090
  if (existingImg) {
4046
4091
  panX = ((_b = existingImg._ct) == null ? void 0 : _b.panX) ?? existingImg.__panX ?? 0.5;
4047
4092
  panY = ((_c = existingImg._ct) == null ? void 0 : _c.panY) ?? existingImg.__panY ?? 0.5;
@@ -4122,9 +4167,9 @@ const canvasImageLoader = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.d
4122
4167
  updateEmptyPlaceholderLayout
4123
4168
  }, Symbol.toStringTag, { value: "Module" }));
4124
4169
  const isCropGroup = (obj) => {
4125
- var _a;
4170
+ var _a2;
4126
4171
  const g = obj;
4127
- return Boolean(g && (g.__cropGroup || ((_a = g._ct) == null ? void 0 : _a.isCropGroup)));
4172
+ return Boolean(g && (g.__cropGroup || ((_a2 = g._ct) == null ? void 0 : _a2.isCropGroup)));
4128
4173
  };
4129
4174
  function parseLuminance(fill) {
4130
4175
  if (typeof fill !== "string") return null;
@@ -4232,10 +4277,10 @@ function isLuminanceMaskClipPath(clipPath) {
4232
4277
  return Boolean(clipPath && clipPath.__svgMaskType === "luminance");
4233
4278
  }
4234
4279
  function syncSvgMaskClipPath(cropGroup) {
4235
- var _a, _b;
4280
+ var _a2, _b;
4236
4281
  const clipPath = cropGroup.clipPath;
4237
4282
  if (!isCropGroup(cropGroup)) return;
4238
- const frameW = ((_a = cropGroup._ct) == null ? void 0 : _a.frameW) ?? cropGroup.width ?? 0;
4283
+ const frameW = ((_a2 = cropGroup._ct) == null ? void 0 : _a2.frameW) ?? cropGroup.width ?? 0;
4239
4284
  const frameH = ((_b = cropGroup._ct) == null ? void 0 : _b.frameH) ?? cropGroup.height ?? 0;
4240
4285
  if (frameW <= 0 || frameH <= 0) return;
4241
4286
  if (isSvgMaskClipPath(clipPath)) {
@@ -4260,11 +4305,11 @@ async function detectMaskType(svgUrl) {
4260
4305
  }
4261
4306
  }
4262
4307
  async function applySvgMaskToCropGroup(cropGroup, svgUrl) {
4263
- var _a, _b, _c;
4308
+ var _a2, _b, _c;
4264
4309
  if (!isCropGroup(cropGroup)) {
4265
4310
  throw new Error("Selected object is not a crop group / image");
4266
4311
  }
4267
- const frameW = ((_a = cropGroup._ct) == null ? void 0 : _a.frameW) ?? cropGroup.width ?? 0;
4312
+ const frameW = ((_a2 = cropGroup._ct) == null ? void 0 : _a2.frameW) ?? cropGroup.width ?? 0;
4268
4313
  const frameH = ((_b = cropGroup._ct) == null ? void 0 : _b.frameH) ?? cropGroup.height ?? 0;
4269
4314
  if (frameW <= 0 || frameH <= 0) {
4270
4315
  throw new Error("Crop group has no frame dimensions");
@@ -4351,11 +4396,11 @@ async function buildLuminanceAlphaCanvas(svgUrl, frameW, frameH) {
4351
4396
  return canvas;
4352
4397
  }
4353
4398
  async function applyLuminanceMaskToCropGroup(cropGroup, svgUrl) {
4354
- var _a, _b, _c;
4399
+ var _a2, _b, _c;
4355
4400
  if (!isCropGroup(cropGroup)) {
4356
4401
  throw new Error("Selected object is not a crop group / image");
4357
4402
  }
4358
- const frameW = ((_a = cropGroup._ct) == null ? void 0 : _a.frameW) ?? cropGroup.width ?? 0;
4403
+ const frameW = ((_a2 = cropGroup._ct) == null ? void 0 : _a2.frameW) ?? cropGroup.width ?? 0;
4359
4404
  const frameH = ((_b = cropGroup._ct) == null ? void 0 : _b.frameH) ?? cropGroup.height ?? 0;
4360
4405
  if (frameW <= 0 || frameH <= 0) {
4361
4406
  throw new Error("Crop group has no frame dimensions");
@@ -4405,9 +4450,9 @@ function getAppliedSvgMaskType(obj) {
4405
4450
  return t === "luminance" || t === "shape" ? t : null;
4406
4451
  }
4407
4452
  function clearSvgMaskFromCropGroup(cropGroup) {
4408
- var _a, _b, _c;
4453
+ var _a2, _b, _c;
4409
4454
  if (!isCropGroup(cropGroup)) return;
4410
- const frameW = ((_a = cropGroup._ct) == null ? void 0 : _a.frameW) ?? cropGroup.width ?? 0;
4455
+ const frameW = ((_a2 = cropGroup._ct) == null ? void 0 : _a2.frameW) ?? cropGroup.width ?? 0;
4411
4456
  const frameH = ((_b = cropGroup._ct) == null ? void 0 : _b.frameH) ?? cropGroup.height ?? 0;
4412
4457
  const rect = new fabric__namespace.Rect({
4413
4458
  width: frameW,
@@ -4448,10 +4493,11 @@ function clamp$1(v, min, max) {
4448
4493
  function applyControlSizeForZoom(canvas, obj) {
4449
4494
  if (!canvas || !obj) return;
4450
4495
  const z = canvas.getZoom() || 1;
4451
- const size = Math.max(6, Math.round(10 * z));
4496
+ const size = Math.max(6, Math.round(8 * z));
4452
4497
  obj.set({
4453
4498
  cornerSize: size,
4454
- borderScaleFactor: z
4499
+ // Subtle but visible border at any zoom (min ~1.25px).
4500
+ borderScaleFactor: Math.max(1.25, 1.25 * z)
4455
4501
  });
4456
4502
  obj.setCoords();
4457
4503
  }
@@ -4466,7 +4512,7 @@ function finalizeCropGroupCoords(g) {
4466
4512
  g.setCoords();
4467
4513
  }
4468
4514
  function updateCoverLayout(g) {
4469
- var _a;
4515
+ var _a2;
4470
4516
  const ct = g.__cropData;
4471
4517
  if (!ct) return;
4472
4518
  const { frameW, frameH, shape, rx: rxRatio, _img: img, _border: border } = ct;
@@ -4613,7 +4659,7 @@ function updateCoverLayout(g) {
4613
4659
  }
4614
4660
  }
4615
4661
  if (!img) {
4616
- const placeholderFrame = ct._placeholderFrame ?? ((_a = g._objects) == null ? void 0 : _a.find((obj) => obj.__isPlaceholderFrame));
4662
+ const placeholderFrame = ct._placeholderFrame ?? ((_a2 = g._objects) == null ? void 0 : _a2.find((obj) => obj.__isPlaceholderFrame));
4617
4663
  if (placeholderFrame && typeof placeholderFrame.set === "function") {
4618
4664
  placeholderFrame.set({
4619
4665
  width: frameW,
@@ -4749,10 +4795,10 @@ const makeRotatedCursorStyleHandler = (controlKey) => {
4749
4795
  return (_eventData, _control, target) => getRotatedControlCursor(controlKey, target);
4750
4796
  };
4751
4797
  function resizeFrameFromCornerUniform(eventData, transform, _x, _y) {
4752
- var _a;
4798
+ var _a2;
4753
4799
  const g = transform.target;
4754
4800
  const ct = g.__cropData;
4755
- if (!ct || !((_a = g._ct) == null ? void 0 : _a.isCropGroup)) return false;
4801
+ if (!ct || !((_a2 = g._ct) == null ? void 0 : _a2.isCropGroup)) return false;
4756
4802
  const canvas = g.canvas;
4757
4803
  if (!canvas) return false;
4758
4804
  const e = getDomEvent(eventData);
@@ -4848,7 +4894,7 @@ function installCanvaMaskControls(g) {
4848
4894
  cursorStyleHandler: makeRotatedCursorStyleHandler(key),
4849
4895
  actionName: "crop",
4850
4896
  actionHandler: (eventData, transform) => {
4851
- var _a;
4897
+ var _a2;
4852
4898
  const t = transform.target;
4853
4899
  const canvas = t.canvas;
4854
4900
  if (canvas && canvas.__editLockRef) {
@@ -4857,7 +4903,7 @@ function installCanvaMaskControls(g) {
4857
4903
  const { localDx, localDy } = getLocalDeltaStable(t, eventData);
4858
4904
  t.__lockScaleDuringCrop = true;
4859
4905
  resizeFrameFromSide(t, side, localDx, localDy);
4860
- (_a = t.canvas) == null ? void 0 : _a.requestRenderAll();
4906
+ (_a2 = t.canvas) == null ? void 0 : _a2.requestRenderAll();
4861
4907
  return true;
4862
4908
  }
4863
4909
  });
@@ -5433,7 +5479,7 @@ function enterCropMode(g) {
5433
5479
  return true;
5434
5480
  }
5435
5481
  function exitCropMode(g, commit = true) {
5436
- var _a;
5482
+ var _a2;
5437
5483
  if (!g[CROP_MODE_FLAG]) return;
5438
5484
  const canvas = g.canvas;
5439
5485
  const handlers = g[CROP_HANDLERS_FLAG];
@@ -5443,7 +5489,7 @@ function exitCropMode(g, commit = true) {
5443
5489
  canvas.off("mouse:down:before", handlers.onCanvasMouseDown);
5444
5490
  if (handlers.onDblClick) canvas.off("mouse:dblclick", handlers.onDblClick);
5445
5491
  window.removeEventListener("keydown", handlers.onKeyDown, true);
5446
- (_a = handlers.upperCanvasEl) == null ? void 0 : _a.removeEventListener("wheel", handlers.onWheel);
5492
+ (_a2 = handlers.upperCanvasEl) == null ? void 0 : _a2.removeEventListener("wheel", handlers.onWheel);
5447
5493
  }
5448
5494
  g[CROP_HANDLERS_FLAG] = void 0;
5449
5495
  const ghost = g[CROP_GHOST_FLAG];
@@ -5896,6 +5942,18 @@ const hasActiveTextPath = (obj) => {
5896
5942
  const tp = obj.textPath;
5897
5943
  return !!tp && !!tp.preset && tp.preset !== "none";
5898
5944
  };
5945
+ const shouldShowOriginalTextBounds = () => {
5946
+ var _a2;
5947
+ try {
5948
+ return typeof window !== "undefined" && ((_a2 = window.localStorage) == null ? void 0 : _a2.getItem("pixldocs:showOriginalTextBounds")) === "1";
5949
+ } catch {
5950
+ return false;
5951
+ }
5952
+ };
5953
+ const hasActiveTextPathDescendant = (obj) => {
5954
+ const kids = (obj == null ? void 0 : obj._objects) || [];
5955
+ return kids.some((child) => hasActiveTextPath(child) || hasActiveTextPathDescendant(child));
5956
+ };
5899
5957
  function applyWarpFillStyle(ctx, obj) {
5900
5958
  const filler = obj.fill;
5901
5959
  if (filler && typeof filler === "object" && Array.isArray(filler.colorStops) && filler.coords) {
@@ -6030,8 +6088,8 @@ function vectorFromFrozenMatrix(matrix, dx, dy) {
6030
6088
  return new fabric__namespace.Point(matrix[0] * dx + matrix[2] * dy, matrix[1] * dx + matrix[3] * dy);
6031
6089
  }
6032
6090
  function scaleLocalToScreen(target, p) {
6033
- var _a;
6034
- const vpt = ((_a = target == null ? void 0 : target.canvas) == null ? void 0 : _a.viewportTransform) || [1, 0, 0, 1, 0, 0];
6091
+ var _a2;
6092
+ const vpt = ((_a2 = target == null ? void 0 : target.canvas) == null ? void 0 : _a2.viewportTransform) || [1, 0, 0, 1, 0, 0];
6035
6093
  const zx = Math.abs(vpt[0] || 1);
6036
6094
  const zy = Math.abs(vpt[3] || 1);
6037
6095
  const sx = Math.abs((target == null ? void 0 : target.scaleX) || 1);
@@ -6039,14 +6097,14 @@ function scaleLocalToScreen(target, p) {
6039
6097
  return new fabric__namespace.Point(p.x * sx * zx, p.y * sy * zy);
6040
6098
  }
6041
6099
  function applyTextPathControls(textbox) {
6042
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
6100
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
6043
6101
  const obj = textbox;
6044
6102
  if (!hasActiveTextPath(obj)) {
6045
6103
  obj.__pdTextPathHovered = false;
6046
6104
  if (obj.__pdTextPathControls) {
6047
6105
  try {
6048
6106
  const cu2 = fabric__namespace.controlsUtils;
6049
- const defaults = ((_a = cu2 == null ? void 0 : cu2.createTextboxDefaultControls) == null ? void 0 : _a.call(cu2)) ?? ((_b = cu2 == null ? void 0 : cu2.createObjectDefaultControls) == null ? void 0 : _b.call(cu2));
6107
+ const defaults = ((_a2 = cu2 == null ? void 0 : cu2.createTextboxDefaultControls) == null ? void 0 : _a2.call(cu2)) ?? ((_b = cu2 == null ? void 0 : cu2.createObjectDefaultControls) == null ? void 0 : _b.call(cu2));
6050
6108
  if (defaults) obj.controls = defaults;
6051
6109
  } catch {
6052
6110
  }
@@ -6071,43 +6129,23 @@ function applyTextPathControls(textbox) {
6071
6129
  }
6072
6130
  if (!obj.__pdTextPathHoverWired) {
6073
6131
  obj.on("mouseover", () => {
6074
- var _a2;
6132
+ var _a3;
6075
6133
  if (!hasActiveTextPath(obj)) return;
6076
6134
  obj.__pdTextPathHovered = true;
6077
- (_a2 = obj.canvas) == null ? void 0 : _a2.requestRenderAll();
6135
+ (_a3 = obj.canvas) == null ? void 0 : _a3.requestRenderAll();
6078
6136
  });
6079
6137
  obj.on("mouseout", () => {
6080
- var _a2;
6138
+ var _a3;
6081
6139
  obj.__pdTextPathHovered = false;
6082
- (_a2 = obj.canvas) == null ? void 0 : _a2.requestRenderAll();
6140
+ (_a3 = obj.canvas) == null ? void 0 : _a3.requestRenderAll();
6083
6141
  });
6084
6142
  obj.__pdTextPathHoverWired = true;
6085
6143
  }
6086
- obj.controls = {};
6144
+ const cu = fabric__namespace.controlsUtils;
6145
+ const defaultControls = ((_d = cu == null ? void 0 : cu.createTextboxDefaultControls) == null ? void 0 : _d.call(cu)) ?? ((_e = cu == null ? void 0 : cu.createObjectDefaultControls) == null ? void 0 : _e.call(cu)) ?? {};
6146
+ obj.controls = { ...defaultControls };
6087
6147
  const halfWOf = (t) => (t.width || 0) / 2;
6088
6148
  const halfHOf = (t) => (t.height || 0) / 2;
6089
- const cu = fabric__namespace.controlsUtils;
6090
- const renderRotation = (ctx, left, top) => {
6091
- ctx.save();
6092
- ctx.translate(left, top);
6093
- ctx.shadowColor = "rgba(0,0,0,0.25)";
6094
- ctx.shadowBlur = 2;
6095
- ctx.shadowOffsetY = 0.5;
6096
- ctx.fillStyle = "#ffffff";
6097
- ctx.strokeStyle = "#1d9bf0";
6098
- ctx.lineWidth = 1.5;
6099
- ctx.beginPath();
6100
- ctx.arc(0, 0, 6, 0, Math.PI * 2);
6101
- ctx.fill();
6102
- ctx.shadowColor = "transparent";
6103
- ctx.stroke();
6104
- ctx.strokeStyle = "#1d9bf0";
6105
- ctx.lineWidth = 1.25;
6106
- ctx.beginPath();
6107
- ctx.arc(0, 0, 3, -Math.PI * 0.85, Math.PI * 0.75);
6108
- ctx.stroke();
6109
- ctx.restore();
6110
- };
6111
6149
  const renderPivot = (ctx, left, top) => {
6112
6150
  ctx.save();
6113
6151
  ctx.translate(left, top);
@@ -6131,17 +6169,7 @@ function applyTextPathControls(textbox) {
6131
6169
  ctx.restore();
6132
6170
  };
6133
6171
  const addRotationAndPivot = () => {
6134
- var _a2, _b2;
6135
- obj.controls.tpRot = new fabric__namespace.Control({
6136
- x: 0,
6137
- y: -0.5,
6138
- offsetY: -28,
6139
- cursorStyleHandler: cu == null ? void 0 : cu.rotationStyleHandler,
6140
- actionHandler: cu == null ? void 0 : cu.rotationWithSnapping,
6141
- actionName: "rotate",
6142
- render: renderRotation,
6143
- withConnection: false
6144
- });
6172
+ var _a3;
6145
6173
  obj.controls.tpPivot = new fabric__namespace.Control({
6146
6174
  x: 0,
6147
6175
  y: 0,
@@ -6150,10 +6178,9 @@ function applyTextPathControls(textbox) {
6150
6178
  actionHandler: () => false,
6151
6179
  render: renderPivot
6152
6180
  });
6153
- (_a2 = obj.setControlVisible) == null ? void 0 : _a2.call(obj, "tpRot", true);
6154
- (_b2 = obj.setControlVisible) == null ? void 0 : _b2.call(obj, "tpPivot", true);
6181
+ (_a3 = obj.setControlVisible) == null ? void 0 : _a3.call(obj, "tpPivot", true);
6155
6182
  };
6156
- if (((_d = obj.textPath) == null ? void 0 : _d.preset) === "circle") {
6183
+ if (((_f = obj.textPath) == null ? void 0 : _f.preset) === "circle") {
6157
6184
  const getRadius = (target) => {
6158
6185
  const tp = target.textPath || {};
6159
6186
  const fs = target.fontSize || 16;
@@ -6163,14 +6190,14 @@ function applyTextPathControls(textbox) {
6163
6190
  return Math.max(fs * 0.75, Number.isFinite(r) && r > 0 ? r : auto);
6164
6191
  };
6165
6192
  const setRadius = (target, r) => {
6166
- var _a2;
6193
+ var _a3;
6167
6194
  const fs = target.fontSize || 16;
6168
6195
  const clamped = Math.max(fs * 0.75, r);
6169
6196
  if (!target.textPath) target.textPath = { preset: "circle" };
6170
6197
  target.textPath.preset = "circle";
6171
6198
  target.textPath.radius = clamped;
6172
6199
  target.dirty = true;
6173
- (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6200
+ (_a3 = target.canvas) == null ? void 0 : _a3.requestRenderAll();
6174
6201
  };
6175
6202
  const ringPoint = (target, dir) => {
6176
6203
  const r = getRadius(target);
@@ -6241,11 +6268,111 @@ function applyTextPathControls(textbox) {
6241
6268
  obj.controls.crE = new fabric__namespace.Control({ x: 0.5, y: 0, cursorStyle: "ew-resize", actionName: "textPath", actionHandler: dragRadius("E"), positionHandler: positionAtRing("E"), render: renderRingHandle });
6242
6269
  obj.controls.crS = new fabric__namespace.Control({ x: 0, y: 0.5, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragRadius("S"), positionHandler: positionAtRing("S"), render: renderRingHandle });
6243
6270
  obj.controls.crW = new fabric__namespace.Control({ x: -0.5, y: 0, cursorStyle: "ew-resize", actionName: "textPath", actionHandler: dragRadius("W"), positionHandler: positionAtRing("W"), render: renderRingHandle });
6244
- (_e = obj.setControlVisible) == null ? void 0 : _e.call(obj, "crN", true);
6245
- (_f = obj.setControlVisible) == null ? void 0 : _f.call(obj, "crE", true);
6246
- (_g = obj.setControlVisible) == null ? void 0 : _g.call(obj, "crS", true);
6247
- (_h = obj.setControlVisible) == null ? void 0 : _h.call(obj, "crW", true);
6271
+ (_g = obj.setControlVisible) == null ? void 0 : _g.call(obj, "crN", true);
6272
+ (_h = obj.setControlVisible) == null ? void 0 : _h.call(obj, "crE", true);
6273
+ (_i = obj.setControlVisible) == null ? void 0 : _i.call(obj, "crS", true);
6274
+ (_j = obj.setControlVisible) == null ? void 0 : _j.call(obj, "crW", true);
6248
6275
  addRotationAndPivot();
6276
+ const getPivotLocalCentered = (target) => {
6277
+ var _a3;
6278
+ const r = getRadius(target);
6279
+ const cx = r - halfWOf(target);
6280
+ const cy = r - halfHOf(target);
6281
+ const off = (_a3 = target.textPath) == null ? void 0 : _a3.pivot;
6282
+ const ox = off && Number.isFinite(off.x) ? off.x : 0;
6283
+ const oy = off && Number.isFinite(off.y) ? off.y : 0;
6284
+ return new fabric__namespace.Point(cx + ox, cy + oy);
6285
+ };
6286
+ const pivotInCanvas = (target) => {
6287
+ const p = getPivotLocalCentered(target);
6288
+ const m = target.calcTransformMatrix();
6289
+ return fabric__namespace.util.transformPoint(p, m);
6290
+ };
6291
+ obj.controls.tpPivot = new fabric__namespace.Control({
6292
+ x: 0,
6293
+ y: 0,
6294
+ cursorStyle: "move",
6295
+ actionName: "tpPivot",
6296
+ positionHandler: (_d2, finalMatrix, fabricObject) => scaleLocalToScreen(fabricObject, getPivotLocalCentered(fabricObject)).transform(finalMatrix),
6297
+ actionHandler: (_e2, transform, x, y) => {
6298
+ var _a3, _b2;
6299
+ const target = transform.target;
6300
+ const state = transform.__pdCirclePivotDrag || (transform.__pdCirclePivotDrag = {
6301
+ startMatrix: target.calcTransformMatrix(),
6302
+ startOffset: { ...((_a3 = target.textPath) == null ? void 0 : _a3.pivot) || { x: 0, y: 0 } },
6303
+ startLocal: null
6304
+ });
6305
+ if (!state.startLocal) state.startLocal = localPointFromFrozenMatrix(target, x, y, state.startMatrix);
6306
+ const local = localPointFromFrozenMatrix(target, x, y, state.startMatrix);
6307
+ const dx = local.x - state.startLocal.x;
6308
+ const dy = local.y - state.startLocal.y;
6309
+ if (!target.textPath) target.textPath = { preset: "circle" };
6310
+ target.textPath.pivot = {
6311
+ x: (state.startOffset.x || 0) + dx,
6312
+ y: (state.startOffset.y || 0) + dy
6313
+ };
6314
+ target.setCoords();
6315
+ (_b2 = target.canvas) == null ? void 0 : _b2.requestRenderAll();
6316
+ return true;
6317
+ },
6318
+ render: renderPivot
6319
+ });
6320
+ (_k = obj.setControlVisible) == null ? void 0 : _k.call(obj, "tpPivot", true);
6321
+ if (obj.controls.mtr) {
6322
+ const ROT_OFFSET_PX = 40;
6323
+ obj.controls.mtr.positionHandler = (_d2, finalMatrix, fabricObject) => {
6324
+ const t = fabricObject;
6325
+ const b = computeCircleWarpBoundsLocal(t);
6326
+ const topCenterLocal = b ? new fabric__namespace.Point((b.minX + b.maxX) / 2, b.minY) : new fabric__namespace.Point(0, -(t.height || 0) / 2);
6327
+ const screen = scaleLocalToScreen(t, topCenterLocal);
6328
+ return new fabric__namespace.Point(screen.x, screen.y - ROT_OFFSET_PX).transform(finalMatrix);
6329
+ };
6330
+ obj.controls.mtr.actionHandler = (eventData, transform, x, y) => {
6331
+ var _a3;
6332
+ const target = transform.target;
6333
+ const state = transform.__pdCirclePivotRot || (transform.__pdCirclePivotRot = {
6334
+ pivot: pivotInCanvas(target),
6335
+ startAngleDeg: target.angle || 0,
6336
+ startCenter: target.getCenterPoint(),
6337
+ startPointerAngle: Math.atan2(
6338
+ (transform.ey ?? y) - pivotInCanvas(target).y,
6339
+ (transform.ex ?? x) - pivotInCanvas(target).x
6340
+ )
6341
+ });
6342
+ const curAngle = Math.atan2(y - state.pivot.y, x - state.pivot.x);
6343
+ const dRad = curAngle - state.startPointerAngle;
6344
+ const cos = Math.cos(dRad);
6345
+ const sin = Math.sin(dRad);
6346
+ const dx = state.startCenter.x - state.pivot.x;
6347
+ const dy = state.startCenter.y - state.pivot.y;
6348
+ const newCenter = new fabric__namespace.Point(
6349
+ state.pivot.x + dx * cos - dy * sin,
6350
+ state.pivot.y + dx * sin + dy * cos
6351
+ );
6352
+ let newAngleDeg = state.startAngleDeg + dRad * 180 / Math.PI;
6353
+ if (eventData && eventData.shiftKey) {
6354
+ newAngleDeg = Math.round(newAngleDeg / 15) * 15;
6355
+ }
6356
+ target.angle = newAngleDeg;
6357
+ target.setPositionByOrigin(newCenter, "center", "center");
6358
+ target.setCoords();
6359
+ (_a3 = target.canvas) == null ? void 0 : _a3.requestRenderAll();
6360
+ return true;
6361
+ };
6362
+ (_l = obj.setControlVisible) == null ? void 0 : _l.call(obj, "mtr", true);
6363
+ }
6364
+ if (!obj.__pdCirclePivotDblWired) {
6365
+ obj.on("mousedblclick", () => {
6366
+ var _a3, _b2;
6367
+ if (((_a3 = obj.textPath) == null ? void 0 : _a3.preset) !== "circle") return;
6368
+ if (obj.__corner !== "tpPivot") return;
6369
+ if (!obj.textPath.pivot) return;
6370
+ obj.textPath.pivot = { x: 0, y: 0 };
6371
+ obj.setCoords();
6372
+ (_b2 = obj.canvas) == null ? void 0 : _b2.requestRenderAll();
6373
+ });
6374
+ obj.__pdCirclePivotDblWired = true;
6375
+ }
6249
6376
  obj.hasBorders = false;
6250
6377
  obj.hasControls = true;
6251
6378
  obj.objectCaching = false;
@@ -6253,7 +6380,7 @@ function applyTextPathControls(textbox) {
6253
6380
  obj.setCoords();
6254
6381
  return;
6255
6382
  }
6256
- if (((_i = obj.textPath) == null ? void 0 : _i.preset) === "rise") {
6383
+ if (((_m = obj.textPath) == null ? void 0 : _m.preset) === "rise") {
6257
6384
  const getEndpoints = (target) => {
6258
6385
  const w = target.width || 0;
6259
6386
  const fs = target.fontSize || 16;
@@ -6270,7 +6397,7 @@ function applyTextPathControls(textbox) {
6270
6397
  return { leftY, centerY, rightY };
6271
6398
  };
6272
6399
  const setEndpoints = (target, next) => {
6273
- var _a2;
6400
+ var _a3;
6274
6401
  target.width || 1;
6275
6402
  target.fontSize || 16;
6276
6403
  const lineMid = (next.leftY + next.rightY) / 2;
@@ -6284,7 +6411,7 @@ function applyTextPathControls(textbox) {
6284
6411
  };
6285
6412
  if (target.skewY) target.set("skewY", 0);
6286
6413
  target.dirty = true;
6287
- (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6414
+ (_a3 = target.canvas) == null ? void 0 : _a3.requestRenderAll();
6288
6415
  };
6289
6416
  const positionAtAngleHandle = (key) => (_d2, finalMatrix, target) => {
6290
6417
  const ep = getEndpoints(target);
@@ -6318,8 +6445,8 @@ function applyTextPathControls(textbox) {
6318
6445
  if (obj.skewY) obj.set("skewY", 0);
6319
6446
  obj.controls.rsL = new fabric__namespace.Control({ x: -0.5, y: 0, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragAngleHandle("leftY"), positionHandler: positionAtAngleHandle("leftY"), render: renderAngleHandle });
6320
6447
  obj.controls.rsR = new fabric__namespace.Control({ x: 0.5, y: 0, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragAngleHandle("rightY"), positionHandler: positionAtAngleHandle("rightY"), render: renderAngleHandle });
6321
- (_j = obj.setControlVisible) == null ? void 0 : _j.call(obj, "rsL", true);
6322
- (_k = obj.setControlVisible) == null ? void 0 : _k.call(obj, "rsR", true);
6448
+ (_n = obj.setControlVisible) == null ? void 0 : _n.call(obj, "rsL", true);
6449
+ (_o = obj.setControlVisible) == null ? void 0 : _o.call(obj, "rsR", true);
6323
6450
  addRotationAndPivot();
6324
6451
  obj.hasBorders = false;
6325
6452
  obj.hasControls = true;
@@ -6406,7 +6533,7 @@ function applyTextPathControls(textbox) {
6406
6533
  return scaleLocalToScreen(target, new fabric__namespace.Point(px - halfWOf(target), py - halfHOf(target))).transform(finalMatrix);
6407
6534
  };
6408
6535
  const makeMidTangentDrag = (side) => (_e2, transform, x, y) => {
6409
- var _a2;
6536
+ var _a3;
6410
6537
  const target = transform.target;
6411
6538
  const local = localPointFromCanvas(target, x, y);
6412
6539
  const current = ensureBezier(target);
@@ -6433,11 +6560,11 @@ function applyTextPathControls(textbox) {
6433
6560
  bz.c1 = apply(bz.c1[0], bz.c1[1]);
6434
6561
  target.textPath = { ...target.textPath || { preset: "custom" }, bezier: bz };
6435
6562
  target.dirty = true;
6436
- (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6563
+ (_a3 = target.canvas) == null ? void 0 : _a3.requestRenderAll();
6437
6564
  return true;
6438
6565
  };
6439
6566
  const makeDrag = (key) => (_e2, transform, x, y) => {
6440
- var _a2;
6567
+ var _a3;
6441
6568
  const target = transform.target;
6442
6569
  const local = localPointFromCanvas(target, x, y);
6443
6570
  const current = ensureBezier(target);
@@ -6455,11 +6582,11 @@ function applyTextPathControls(textbox) {
6455
6582
  }
6456
6583
  target.textPath = { ...target.textPath || { preset: "custom" }, bezier: bz };
6457
6584
  target.dirty = true;
6458
- (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6585
+ (_a3 = target.canvas) == null ? void 0 : _a3.requestRenderAll();
6459
6586
  return true;
6460
6587
  };
6461
6588
  const makeMidDrag = () => (_e2, transform, x, y) => {
6462
- var _a2;
6589
+ var _a3;
6463
6590
  const target = transform.target;
6464
6591
  const local = localPointFromCanvas(target, x, y);
6465
6592
  const current = ensureBezier(target);
@@ -6476,7 +6603,7 @@ function applyTextPathControls(textbox) {
6476
6603
  bz.c1 = [bz.c1[0] + dx, bz.c1[1] + dy];
6477
6604
  target.textPath = { ...target.textPath || { preset: "custom" }, bezier: bz };
6478
6605
  target.dirty = true;
6479
- (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6606
+ (_a3 = target.canvas) == null ? void 0 : _a3.requestRenderAll();
6480
6607
  return true;
6481
6608
  };
6482
6609
  const renderAnchor = (ctx, left, top) => {
@@ -6518,13 +6645,13 @@ function applyTextPathControls(textbox) {
6518
6645
  obj.controls.bzMid = new fabric__namespace.Control({ x: 0, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeMidDrag(), positionHandler: positionAtMid, render: renderAnchor });
6519
6646
  obj.controls.bzMidT0 = new fabric__namespace.Control({ x: 0, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeMidTangentDrag(-1), positionHandler: positionAtMidTangent(-1), render: renderControlHandle });
6520
6647
  obj.controls.bzMidT1 = new fabric__namespace.Control({ x: 0, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeMidTangentDrag(1), positionHandler: positionAtMidTangent(1), render: renderControlHandle });
6521
- (_l = obj.setControlVisible) == null ? void 0 : _l.call(obj, "bzP0", true);
6522
- (_m = obj.setControlVisible) == null ? void 0 : _m.call(obj, "bzC0", true);
6523
- (_n = obj.setControlVisible) == null ? void 0 : _n.call(obj, "bzC1", true);
6524
- (_o = obj.setControlVisible) == null ? void 0 : _o.call(obj, "bzP1", true);
6525
- (_p = obj.setControlVisible) == null ? void 0 : _p.call(obj, "bzMid", true);
6526
- (_q = obj.setControlVisible) == null ? void 0 : _q.call(obj, "bzMidT0", true);
6527
- (_r = obj.setControlVisible) == null ? void 0 : _r.call(obj, "bzMidT1", true);
6648
+ (_p = obj.setControlVisible) == null ? void 0 : _p.call(obj, "bzP0", true);
6649
+ (_q = obj.setControlVisible) == null ? void 0 : _q.call(obj, "bzC0", true);
6650
+ (_r = obj.setControlVisible) == null ? void 0 : _r.call(obj, "bzC1", true);
6651
+ (_s = obj.setControlVisible) == null ? void 0 : _s.call(obj, "bzP1", true);
6652
+ (_t = obj.setControlVisible) == null ? void 0 : _t.call(obj, "bzMid", true);
6653
+ (_u = obj.setControlVisible) == null ? void 0 : _u.call(obj, "bzMidT0", true);
6654
+ (_v = obj.setControlVisible) == null ? void 0 : _v.call(obj, "bzMidT1", true);
6528
6655
  addRotationAndPivot();
6529
6656
  obj.hasBorders = false;
6530
6657
  obj.hasControls = true;
@@ -6532,6 +6659,29 @@ function applyTextPathControls(textbox) {
6532
6659
  obj.setCoords();
6533
6660
  }
6534
6661
  function computeWarpBoundsLocal(obj) {
6662
+ const tp = obj.textPath;
6663
+ if (tp && (tp.preset === "rise" || tp.preset === "angle")) {
6664
+ const w = obj.width || 0;
6665
+ const h = obj.height || 0;
6666
+ const fs2 = obj.fontSize || 16;
6667
+ const ep = tp.endpoints;
6668
+ const defaultLeftY = fs2 * 1.5;
6669
+ const defaultRightY = fs2 * 0.5;
6670
+ const leftY = ep && Number.isFinite(ep.leftY) ? ep.leftY : defaultLeftY;
6671
+ const rightY = ep && Number.isFinite(ep.rightY) ? ep.rightY : defaultRightY;
6672
+ const slope = w > 0 ? (rightY - leftY) / w : 0;
6673
+ const dy = (leftY + rightY) / 2 - h / 2;
6674
+ const halfW2 = w / 2;
6675
+ const halfH2 = h / 2;
6676
+ const yShift = Math.abs(slope) * halfW2;
6677
+ const pad = fs2 * 0.15;
6678
+ return {
6679
+ minX: -halfW2 - pad,
6680
+ maxX: halfW2 + pad,
6681
+ minY: -halfH2 + dy - yShift - pad,
6682
+ maxY: halfH2 + dy + yShift + pad
6683
+ };
6684
+ }
6535
6685
  const resolved = resolveTextPath(obj.textPath, obj.width || 0, obj.fontSize || 16);
6536
6686
  const path = resolved ? measurePath(resolved.d) : null;
6537
6687
  if (!path) return null;
@@ -6557,8 +6707,8 @@ function computeWarpBoundsLocal(obj) {
6557
6707
  };
6558
6708
  }
6559
6709
  function computeCircleWarpBoundsLocal(obj) {
6560
- var _a;
6561
- if (((_a = obj.textPath) == null ? void 0 : _a.preset) !== "circle") return null;
6710
+ var _a2;
6711
+ if (((_a2 = obj.textPath) == null ? void 0 : _a2.preset) !== "circle") return null;
6562
6712
  const fs = obj.fontSize || 16;
6563
6713
  const w = obj.width || 0;
6564
6714
  const auto = Math.max(fs * 1.5, w / Math.PI);
@@ -6568,11 +6718,12 @@ function computeCircleWarpBoundsLocal(obj) {
6568
6718
  const halfH = (obj.height || 0) / 2;
6569
6719
  const cx = r - halfW;
6570
6720
  const cy = r - halfH;
6571
- return { minX: cx - r - fs * 0.2, maxX: cx + r + fs * 0.2, minY: cy - r - fs * 0.6, maxY: cy + r + fs * 0.6 };
6721
+ const pad = fs * 0.85;
6722
+ return { minX: cx - r - pad, maxX: cx + r + pad, minY: cy - r - pad, maxY: cy + r + pad };
6572
6723
  }
6573
6724
  function getTextPathHitBounds(obj) {
6574
- var _a;
6575
- return ((_a = obj.textPath) == null ? void 0 : _a.preset) === "circle" ? computeCircleWarpBoundsLocal(obj) : computeWarpBoundsLocal(obj);
6725
+ var _a2;
6726
+ return ((_a2 = obj.textPath) == null ? void 0 : _a2.preset) === "circle" ? computeCircleWarpBoundsLocal(obj) : computeWarpBoundsLocal(obj);
6576
6727
  }
6577
6728
  function textPathBoundsContainScenePoint(obj, point) {
6578
6729
  const bounds = getTextPathHitBounds(obj);
@@ -6585,11 +6736,12 @@ function textPathBoundsContainScenePoint(obj, point) {
6585
6736
  return false;
6586
6737
  }
6587
6738
  }
6588
- function drawTextPathBounds(ctx, obj, bounds) {
6589
- var _a;
6590
- if (!obj.canvas) return;
6591
- const retina = ((_a = obj.getCanvasRetinaScaling) == null ? void 0 : _a.call(obj)) || 1;
6592
- const matrix = fabric__namespace.util.multiplyTransformMatrices(obj.canvas.viewportTransform || [1, 0, 0, 1, 0, 0], obj.calcTransformMatrix());
6739
+ function drawTextPathBounds(ctx, obj, bounds, hostCanvas) {
6740
+ var _a2, _b, _c;
6741
+ const host = hostCanvas || obj.canvas || ((_a2 = obj.group) == null ? void 0 : _a2.canvas);
6742
+ if (!host) return;
6743
+ const retina = ((_b = host.getRetinaScaling) == null ? void 0 : _b.call(host)) || ((_c = obj.getCanvasRetinaScaling) == null ? void 0 : _c.call(obj)) || 1;
6744
+ const matrix = fabric__namespace.util.multiplyTransformMatrices(host.viewportTransform || [1, 0, 0, 1, 0, 0], obj.calcTransformMatrix());
6593
6745
  const corners = [
6594
6746
  new fabric__namespace.Point(bounds.minX, bounds.minY),
6595
6747
  new fabric__namespace.Point(bounds.maxX, bounds.minY),
@@ -6610,20 +6762,23 @@ function drawTextPathBounds(ctx, obj, bounds) {
6610
6762
  }
6611
6763
  if (typeof TextboxProto._renderControls === "function" && !TextboxProto.__pixldocsOrigRenderControls) {
6612
6764
  let drawWarpGuides = function(ctx) {
6613
- var _a, _b, _c, _d, _e, _f, _g;
6614
- if (!this.canvas) return;
6765
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
6766
+ const hostCanvas = this.canvas || ((_a2 = this.group) == null ? void 0 : _a2.canvas) || ((_c = (_b = this.group) == null ? void 0 : _b.group) == null ? void 0 : _c.canvas);
6767
+ if (!hostCanvas) return;
6615
6768
  const hoverBounds = getTextPathHitBounds(this);
6616
- if (hoverBounds && (this.__pdTextPathHovered || ((_b = (_a = this.canvas).getActiveObject) == null ? void 0 : _b.call(_a)) === this)) {
6617
- drawTextPathBounds(ctx, this, hoverBounds);
6769
+ const active = (_d = hostCanvas.getActiveObject) == null ? void 0 : _d.call(hostCanvas);
6770
+ const isActiveOrInActive = active === this || !!active && typeof active.contains === "function" && active.contains(this, true);
6771
+ if (hoverBounds && (this.__pdTextPathHovered || isActiveOrInActive)) {
6772
+ drawTextPathBounds(ctx, this, hoverBounds, hostCanvas);
6618
6773
  }
6619
6774
  const resolved = resolveTextPath(this.textPath, this.width || 0, this.fontSize || 16);
6620
6775
  const path = resolved ? measurePath(resolved.d) : null;
6621
6776
  if (!path) return;
6622
6777
  const len = path.getTotalLength();
6623
6778
  if (!Number.isFinite(len) || len <= 0) return;
6624
- const retina = ((_c = this.getCanvasRetinaScaling) == null ? void 0 : _c.call(this)) || 1;
6779
+ const retina = ((_e = hostCanvas.getRetinaScaling) == null ? void 0 : _e.call(hostCanvas)) || ((_f = this.getCanvasRetinaScaling) == null ? void 0 : _f.call(this)) || 1;
6625
6780
  const matrix = fabric__namespace.util.multiplyTransformMatrices(
6626
- this.canvas.viewportTransform || [1, 0, 0, 1, 0, 0],
6781
+ hostCanvas.viewportTransform || [1, 0, 0, 1, 0, 0],
6627
6782
  this.calcTransformMatrix()
6628
6783
  );
6629
6784
  const halfW = (this.width || 0) / 2;
@@ -6635,8 +6790,8 @@ if (typeof TextboxProto._renderControls === "function" && !TextboxProto.__pixldo
6635
6790
  const toScreenXY = (x, y) => fabric__namespace.util.transformPoint(new fabric__namespace.Point(x, y), matrix);
6636
6791
  ctx.save();
6637
6792
  ctx.setTransform(retina, 0, 0, retina, 0, 0);
6638
- const isCircle = ((_d = this.textPath) == null ? void 0 : _d.preset) === "circle";
6639
- const isAngle = ((_e = this.textPath) == null ? void 0 : _e.preset) === "rise" || ((_f = this.textPath) == null ? void 0 : _f.preset) === "angle";
6793
+ const isCircle = ((_g = this.textPath) == null ? void 0 : _g.preset) === "circle";
6794
+ const isAngle = ((_h = this.textPath) == null ? void 0 : _h.preset) === "rise" || ((_i = this.textPath) == null ? void 0 : _i.preset) === "angle";
6640
6795
  ctx.strokeStyle = "rgba(29, 155, 240, 0.95)";
6641
6796
  ctx.lineWidth = 1.25;
6642
6797
  ctx.setLineDash([]);
@@ -6682,7 +6837,7 @@ if (typeof TextboxProto._renderControls === "function" && !TextboxProto.__pixldo
6682
6837
  ctx.closePath();
6683
6838
  ctx.stroke();
6684
6839
  }
6685
- const bz = isCircle ? null : (_g = this.textPath) == null ? void 0 : _g.bezier;
6840
+ const bz = isCircle ? null : (_j = this.textPath) == null ? void 0 : _j.bezier;
6686
6841
  if (bz) {
6687
6842
  const a = toScreenXY(bz.p0[0] - halfW, bz.p0[1] - halfH);
6688
6843
  const ah = toScreenXY(bz.c0[0] - halfW, bz.c0[1] - halfH);
@@ -6722,13 +6877,28 @@ if (typeof TextboxProto._renderControls === "function" && !TextboxProto.__pixldo
6722
6877
  TextboxProto.__pixldocsOrigRenderControls = TextboxProto._renderControls;
6723
6878
  TextboxProto._renderControls = function(ctx, styleOverride) {
6724
6879
  if (hasActiveTextPath(this)) {
6880
+ const showOrig = shouldShowOriginalTextBounds();
6725
6881
  const prevBorders = this.hasBorders;
6726
- this.hasBorders = false;
6882
+ const prevBorderColor = this.borderColor;
6883
+ const prevControls = this.controls;
6884
+ if (!showOrig) {
6885
+ this.hasBorders = false;
6886
+ this.borderColor = "rgba(0,0,0,0)";
6887
+ const filtered = {};
6888
+ for (const key of Object.keys(prevControls || {})) {
6889
+ if (key === "mtr" || key === "tpPivot" || key.startsWith("cr") || key.startsWith("rs") || key.startsWith("bz")) {
6890
+ filtered[key] = prevControls[key];
6891
+ }
6892
+ }
6893
+ this.controls = filtered;
6894
+ }
6727
6895
  try {
6728
6896
  drawWarpGuides.call(this, ctx);
6729
6897
  TextboxProto.__pixldocsOrigRenderControls.call(this, ctx, styleOverride);
6730
6898
  } finally {
6731
6899
  this.hasBorders = prevBorders;
6900
+ this.borderColor = prevBorderColor;
6901
+ this.controls = prevControls;
6732
6902
  }
6733
6903
  return;
6734
6904
  }
@@ -6823,6 +6993,50 @@ if (!TextboxProto.__pixldocsOrigRender && typeof TextboxProto._render === "funct
6823
6993
  };
6824
6994
  }
6825
6995
  TextboxProto.__pixldocsTextboxExtended = true;
6996
+ const GroupProto = (_a = fabric__namespace.Group) == null ? void 0 : _a.prototype;
6997
+ if (GroupProto && typeof GroupProto._renderControls === "function" && !GroupProto.__pixldocsOrigRenderControls) {
6998
+ GroupProto.__pixldocsOrigRenderControls = GroupProto._renderControls;
6999
+ GroupProto._renderControls = function(ctx, styleOverride, childrenOverride) {
7000
+ var _a2;
7001
+ const host = this.canvas;
7002
+ const active = (_a2 = host == null ? void 0 : host.getActiveObject) == null ? void 0 : _a2.call(host);
7003
+ const isActiveOrInActive = !!host && (active === this || !!active && typeof active.contains === "function" && active.contains(this, true));
7004
+ const hideWarpChildBounds = isActiveOrInActive && !shouldShowOriginalTextBounds() && hasActiveTextPathDescendant(this);
7005
+ const prevBorders = this.hasBorders;
7006
+ const prevControls = this.hasControls;
7007
+ const prevBorderColor = this.borderColor;
7008
+ if (hideWarpChildBounds) {
7009
+ this.hasBorders = false;
7010
+ this.hasControls = false;
7011
+ this.borderColor = "rgba(0,0,0,0)";
7012
+ styleOverride = { ...styleOverride || {}, hasBorders: false, hasControls: false, borderColor: "rgba(0,0,0,0)" };
7013
+ childrenOverride = { ...childrenOverride || {}, hasBorders: false, borderColor: "rgba(0,0,0,0)" };
7014
+ }
7015
+ try {
7016
+ GroupProto.__pixldocsOrigRenderControls.call(this, ctx, styleOverride, childrenOverride);
7017
+ } finally {
7018
+ if (hideWarpChildBounds) {
7019
+ this.hasBorders = prevBorders;
7020
+ this.hasControls = prevControls;
7021
+ this.borderColor = prevBorderColor;
7022
+ }
7023
+ }
7024
+ if (!host || !isActiveOrInActive) return;
7025
+ const drawForDescendants = (parent) => {
7026
+ const kids = (parent == null ? void 0 : parent._objects) || [];
7027
+ for (const child of kids) {
7028
+ if (child && Array.isArray(child._objects)) {
7029
+ drawForDescendants(child);
7030
+ }
7031
+ if (child && child.textPath && child.textPath.preset && child.textPath.preset !== "none") {
7032
+ const bounds = getTextPathHitBounds(child);
7033
+ if (bounds) drawTextPathBounds(ctx, child, bounds, host);
7034
+ }
7035
+ }
7036
+ };
7037
+ drawForDescendants(this);
7038
+ };
7039
+ }
6826
7040
  const TextboxProtoHit = fabric__namespace.Textbox.prototype;
6827
7041
  if (!TextboxProtoHit.__pixldocsOrigGetCoords && typeof TextboxProtoHit.getCoords === "function") {
6828
7042
  TextboxProtoHit.__pixldocsOrigGetCoords = TextboxProtoHit.getCoords;
@@ -7001,7 +7215,7 @@ function buildRoundedRectPath2D(ctx, x, y, w, h, rTL, rTR, rBR, rBL) {
7001
7215
  ctx.closePath();
7002
7216
  }
7003
7217
  function applyTextBackground(obj, cfg) {
7004
- var _a;
7218
+ var _a2;
7005
7219
  obj[PD_BG_KEY] = { ...cfg };
7006
7220
  try {
7007
7221
  const hasOffset = (Number(cfg == null ? void 0 : cfg.shadowOffsetX) || 0) !== 0 || (Number(cfg == null ? void 0 : cfg.shadowOffsetY) || 0) !== 0;
@@ -7247,10 +7461,10 @@ function applyTextBackground(obj, cfg) {
7247
7461
  }
7248
7462
  return out;
7249
7463
  };
7250
- const originalToSVG = (_a = obj.toSVG) == null ? void 0 : _a.bind(obj);
7464
+ const originalToSVG = (_a2 = obj.toSVG) == null ? void 0 : _a2.bind(obj);
7251
7465
  if (typeof originalToSVG === "function") {
7252
7466
  obj.toSVG = function(reviver) {
7253
- var _a2, _b;
7467
+ var _a3, _b;
7254
7468
  let svg = originalToSVG(reviver);
7255
7469
  const bg = this[PD_BG_KEY];
7256
7470
  const shadow = this.shadow;
@@ -7263,7 +7477,7 @@ function applyTextBackground(obj, cfg) {
7263
7477
  const hasBlockShadow = !!bg && bg.shadowType === "block" && hasExtShadowColor && extDist > 0;
7264
7478
  const hasLineShadow = !!bg && bg.shadowType === "line" && hasExtShadowColor && extDist > 0;
7265
7479
  if (!hasBg && !hasShadow && !hasBlockShadow && !hasLineShadow) return svg;
7266
- const hasActiveTextPath2 = !!(((_a2 = this.textPath) == null ? void 0 : _a2.preset) && this.textPath.preset !== "none");
7480
+ const hasActiveTextPath2 = !!(((_a3 = this.textPath) == null ? void 0 : _a3.preset) && this.textPath.preset !== "none");
7267
7481
  const w = this.width ?? 0;
7268
7482
  const h = this.height ?? 0;
7269
7483
  const pT = Math.max(0, Number((bg == null ? void 0 : bg.padTop) ?? 0));
@@ -7410,7 +7624,7 @@ function recolorSvgFills(svg, color, strokeWidth = 0) {
7410
7624
  return _recolorSvgFills(svg, color, strokeWidth);
7411
7625
  }
7412
7626
  function _recolorSvgFills(svg, color, strokeWidth = 0) {
7413
- var _a;
7627
+ var _a2;
7414
7628
  const safe = escapeXmlAttr(color);
7415
7629
  const spread = Math.max(0, Number(strokeWidth) || 0);
7416
7630
  try {
@@ -7420,7 +7634,7 @@ function _recolorSvgFills(svg, color, strokeWidth = 0) {
7420
7634
  if (root && root.nodeName !== "parsererror") {
7421
7635
  for (const g of Array.from(root.querySelectorAll("linearGradient, radialGradient, pattern"))) {
7422
7636
  try {
7423
- (_a = g.parentNode) == null ? void 0 : _a.removeChild(g);
7637
+ (_a2 = g.parentNode) == null ? void 0 : _a2.removeChild(g);
7424
7638
  } catch {
7425
7639
  }
7426
7640
  }
@@ -7508,7 +7722,7 @@ function unionBounds(bounds) {
7508
7722
  return { x: minX, y: minY, w: Math.max(1, maxX - minX), h: Math.max(1, maxY - minY) };
7509
7723
  }
7510
7724
  function computeTextVisualBounds(obj, w, h) {
7511
- var _a;
7725
+ var _a2;
7512
7726
  const lines = (obj == null ? void 0 : obj._textLines) ?? [];
7513
7727
  if (!lines || lines.length === 0) return { x: -w / 2, y: -h / 2, w, h };
7514
7728
  const rects = [];
@@ -7526,7 +7740,7 @@ function computeTextVisualBounds(obj, w, h) {
7526
7740
  lineW = 0;
7527
7741
  }
7528
7742
  try {
7529
- lineLeft = ((_a = obj._getLineLeftOffset) == null ? void 0 : _a.call(obj, i)) ?? 0;
7743
+ lineLeft = ((_a2 = obj._getLineLeftOffset) == null ? void 0 : _a2.call(obj, i)) ?? 0;
7530
7744
  } catch {
7531
7745
  lineLeft = 0;
7532
7746
  }
@@ -7544,7 +7758,7 @@ function computeTextVisualBounds(obj, w, h) {
7544
7758
  return unionBounds(rects.length > 0 ? rects : [{ x: -w / 2, y: -h / 2, w, h }]);
7545
7759
  }
7546
7760
  function computeBgRects(obj, w, h, pT, pR, pB, pL, fit) {
7547
- var _a;
7761
+ var _a2;
7548
7762
  if (!fit) {
7549
7763
  return [{
7550
7764
  x: -w / 2 - pL,
@@ -7577,7 +7791,7 @@ function computeBgRects(obj, w, h, pT, pR, pB, pL, fit) {
7577
7791
  lineW = 0;
7578
7792
  }
7579
7793
  try {
7580
- lineLeft = ((_a = obj._getLineLeftOffset) == null ? void 0 : _a.call(obj, i)) ?? 0;
7794
+ lineLeft = ((_a2 = obj._getLineLeftOffset) == null ? void 0 : _a2.call(obj, i)) ?? 0;
7581
7795
  } catch {
7582
7796
  lineLeft = 0;
7583
7797
  }
@@ -8350,7 +8564,7 @@ function createShape(element) {
8350
8564
  }
8351
8565
  }
8352
8566
  function createText(element) {
8353
- var _a, _b;
8567
+ var _a2, _b, _c;
8354
8568
  const overflowPolicy = element.overflowPolicy || "grow-and-push";
8355
8569
  let text = element.text || "Text";
8356
8570
  let fontSize = element.fontSize || 16;
@@ -8390,7 +8604,7 @@ function createText(element) {
8390
8604
  });
8391
8605
  testTextbox.initDimensions();
8392
8606
  const textHeight = testTextbox.height || 0;
8393
- const renderedLineCount = ((_a = testTextbox.textLines) == null ? void 0 : _a.length) || 1;
8607
+ const renderedLineCount = ((_a2 = testTextbox.textLines) == null ? void 0 : _a2.length) || 1;
8394
8608
  const hasNoImplicitWrap = renderedLineCount <= explicitLineCount;
8395
8609
  const fitsHeight = heightBound <= 0 || textHeight <= heightBound;
8396
8610
  const widthMetrics = getTextboxWidthFitMetrics(testTextbox, fixedWidth);
@@ -8445,7 +8659,7 @@ function createText(element) {
8445
8659
  if (overflowPolicy === "max-lines-ellipsis") {
8446
8660
  const originalText = element.text || "Text";
8447
8661
  const countLines = (testText) => {
8448
- var _a2;
8662
+ var _a3;
8449
8663
  const tb = new fabric__namespace.Textbox(testText, {
8450
8664
  width: element.width,
8451
8665
  fontSize,
@@ -8454,7 +8668,7 @@ function createText(element) {
8454
8668
  splitByGrapheme: element.splitByGrapheme ?? element.wordWrap === "break-word"
8455
8669
  });
8456
8670
  tb.initDimensions();
8457
- return ((_a2 = tb.textLines) == null ? void 0 : _a2.length) || 1;
8671
+ return ((_a3 = tb.textLines) == null ? void 0 : _a3.length) || 1;
8458
8672
  };
8459
8673
  let low = 0;
8460
8674
  let high = originalText.length;
@@ -8523,10 +8737,30 @@ function createText(element) {
8523
8737
  minWidth: 1,
8524
8738
  dynamicMinWidth: 0,
8525
8739
  scaleX: targetScaleX,
8526
- scaleY: targetScaleY
8740
+ scaleY: targetScaleY,
8741
+ // Prevent the bottom/top resize handle from flipping the textbox through
8742
+ // zero (which visually "drags" the element up on the page once it can't
8743
+ // shrink any further). Locking flip + a small minScaleLimit makes the
8744
+ // handle simply stop where it is instead of repositioning the element.
8745
+ lockScalingFlip: true,
8746
+ minScaleLimit: 0.01
8527
8747
  });
8528
8748
  textbox.setCoords();
8529
8749
  const widthAfterSet = textbox.width ?? 0;
8750
+ try {
8751
+ (_b = textbox.setControlsVisibility) == null ? void 0 : _b.call(textbox, {
8752
+ tl: true,
8753
+ tr: true,
8754
+ bl: true,
8755
+ br: true,
8756
+ mt: true,
8757
+ mb: true,
8758
+ ml: true,
8759
+ mr: true,
8760
+ mtr: true
8761
+ });
8762
+ } catch {
8763
+ }
8530
8764
  const scaleXAfterSet = textbox.scaleX ?? 1;
8531
8765
  const scaleYAfterSet = textbox.scaleY ?? 1;
8532
8766
  if (Math.abs(widthAfterSet - targetWidth) > 0.01 || Math.abs(scaleXAfterSet - targetScaleX) > 0.01 || Math.abs(scaleYAfterSet - targetScaleY) > 0.01) {
@@ -8557,7 +8791,7 @@ function createText(element) {
8557
8791
  finalFontSize: fontSize,
8558
8792
  textboxWidth: textbox.width,
8559
8793
  textboxHeight: textbox.height,
8560
- lineCount: ((_b = textbox.textLines) == null ? void 0 : _b.length) || 0,
8794
+ lineCount: ((_c = textbox.textLines) == null ? void 0 : _c.length) || 0,
8561
8795
  lines: (textbox.textLines || []).map((line) => Array.isArray(line) ? line.join("") : String(line ?? "")),
8562
8796
  widthMetrics: getTextboxWidthFitMetrics(textbox, targetWidth)
8563
8797
  }));
@@ -8623,6 +8857,23 @@ function createFabricObject(element) {
8623
8857
  if (element.type === "text" && obj instanceof fabric__namespace.Textbox) {
8624
8858
  applyTextPathControls(obj);
8625
8859
  }
8860
+ if (element.type === "line") {
8861
+ obj.setControlsVisibility({
8862
+ tl: false,
8863
+ tr: false,
8864
+ bl: false,
8865
+ br: false,
8866
+ mt: false,
8867
+ mb: false,
8868
+ ml: true,
8869
+ mr: true,
8870
+ mtr: true
8871
+ });
8872
+ obj.set({
8873
+ padding: 8,
8874
+ perPixelTargetFind: false
8875
+ });
8876
+ }
8626
8877
  }
8627
8878
  return obj;
8628
8879
  }
@@ -8679,7 +8930,7 @@ function generateQRMatrix(text, errorCorrectionLevel) {
8679
8930
  return { modules: [[true]], size: 1 };
8680
8931
  }
8681
8932
  function renderQRSvg(props, width, height) {
8682
- var _a;
8933
+ var _a2;
8683
8934
  props.value || "https://example.com";
8684
8935
  const fgColor = props.fgColor || "#000000";
8685
8936
  const bgColor = props.bgColor || "#FFFFFF";
@@ -8691,7 +8942,7 @@ function renderQRSvg(props, width, height) {
8691
8942
  let pathData = "";
8692
8943
  for (let row = 0; row < size; row++) {
8693
8944
  for (let col = 0; col < size; col++) {
8694
- if ((_a = modules[row]) == null ? void 0 : _a[col]) {
8945
+ if ((_a2 = modules[row]) == null ? void 0 : _a2[col]) {
8695
8946
  const x = (col + margin) * cellSize;
8696
8947
  const y = (row + margin) * cellSize;
8697
8948
  pathData += `M${x},${y}h${cellSize}v${cellSize}h${-cellSize}Z `;
@@ -9099,6 +9350,21 @@ function renderSmartElementToDataUri(type, props, width, height) {
9099
9350
  if (!svg) return null;
9100
9351
  return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
9101
9352
  }
9353
+ const KEY_SHOW_ORIG_TEXT_BOUNDS = "pixldocs:showOriginalTextBounds";
9354
+ const EVT_SHOW_ORIG_TEXT_BOUNDS = "pixldocs:showOriginalTextBoundsChanged";
9355
+ function getShowOriginalTextBounds() {
9356
+ if (typeof window === "undefined") return false;
9357
+ try {
9358
+ return window.localStorage.getItem(KEY_SHOW_ORIG_TEXT_BOUNDS) === "1";
9359
+ } catch {
9360
+ return false;
9361
+ }
9362
+ }
9363
+ function subscribeShowOriginalTextBounds(cb) {
9364
+ const handler = (e) => cb(!!e.detail);
9365
+ window.addEventListener(EVT_SHOW_ORIG_TEXT_BOUNDS, handler);
9366
+ return () => window.removeEventListener(EVT_SHOW_ORIG_TEXT_BOUNDS, handler);
9367
+ }
9102
9368
  function hasEdgeFade(p) {
9103
9369
  if (!p) return false;
9104
9370
  const sides = [
@@ -9208,9 +9474,71 @@ function bakeEdgeFade(source, fade) {
9208
9474
  ctx.globalCompositeOperation = "destination-in";
9209
9475
  ctx.drawImage(mask, 0, 0);
9210
9476
  ctx.globalCompositeOperation = "source-over";
9477
+ if (amount < 1) {
9478
+ if (side === "top") ctx.clearRect(0, 0, canvas.width, Math.min(2, canvas.height));
9479
+ else if (side === "bottom") ctx.clearRect(0, Math.max(0, canvas.height - 2), canvas.width, Math.min(2, canvas.height));
9480
+ else if (side === "left") ctx.clearRect(0, 0, Math.min(2, canvas.width), canvas.height);
9481
+ else if (side === "right") ctx.clearRect(Math.max(0, canvas.width - 2), 0, Math.min(2, canvas.width), canvas.height);
9482
+ }
9211
9483
  }
9212
9484
  return canvas;
9213
9485
  }
9486
+ const SELECTION_PRIMARY = "hsl(217, 91%, 60%)";
9487
+ try {
9488
+ const InteractiveBase = fabric__namespace.InteractiveFabricObject ?? fabric__namespace.Object;
9489
+ if (InteractiveBase == null ? void 0 : InteractiveBase.ownDefaults) {
9490
+ Object.assign(InteractiveBase.ownDefaults, {
9491
+ borderColor: SELECTION_PRIMARY,
9492
+ borderScaleFactor: 1.25,
9493
+ cornerColor: SELECTION_PRIMARY,
9494
+ cornerStrokeColor: "#ffffff",
9495
+ cornerStyle: "rect",
9496
+ transparentCorners: false,
9497
+ cornerSize: 8,
9498
+ borderOpacityWhenMoving: 0.9
9499
+ });
9500
+ } else if (InteractiveBase == null ? void 0 : InteractiveBase.prototype) {
9501
+ Object.assign(InteractiveBase.prototype, {
9502
+ borderColor: SELECTION_PRIMARY,
9503
+ borderScaleFactor: 1.25,
9504
+ cornerColor: SELECTION_PRIMARY,
9505
+ cornerStrokeColor: "#ffffff",
9506
+ cornerStyle: "rect",
9507
+ transparentCorners: false,
9508
+ cornerSize: 8,
9509
+ borderOpacityWhenMoving: 0.9
9510
+ });
9511
+ }
9512
+ } catch (e) {
9513
+ console.warn("[PageCanvas] Failed to apply global selection defaults:", e);
9514
+ }
9515
+ function applyWarpAwareSelectionBorders(selection) {
9516
+ if (getShowOriginalTextBounds()) {
9517
+ if (selection.__pixldocsOrigASHasBorders !== void 0) {
9518
+ selection.hasBorders = selection.__pixldocsOrigASHasBorders;
9519
+ }
9520
+ return;
9521
+ }
9522
+ const hasWarpedTextObject = (obj) => {
9523
+ if (obj instanceof fabric__namespace.Textbox) {
9524
+ const tp = obj.textPath;
9525
+ return !!(tp && tp.preset && tp.preset !== "none");
9526
+ }
9527
+ const children = obj._objects;
9528
+ return Array.isArray(children) && children.some((child) => hasWarpedTextObject(child));
9529
+ };
9530
+ const hasWarpedText = selection.getObjects().some((obj) => {
9531
+ if (!hasWarpedTextObject(obj)) return false;
9532
+ const tp = obj.textPath;
9533
+ return !tp || tp.preset !== "none";
9534
+ });
9535
+ if (hasWarpedText) {
9536
+ if (selection.__pixldocsOrigASHasBorders === void 0) {
9537
+ selection.__pixldocsOrigASHasBorders = selection.hasBorders;
9538
+ }
9539
+ selection.hasBorders = false;
9540
+ }
9541
+ }
9214
9542
  const PageCanvas = react.forwardRef(
9215
9543
  ({
9216
9544
  pageId,
@@ -9254,7 +9582,9 @@ const PageCanvas = react.forwardRef(
9254
9582
  const justModifiedIdsRef = react.useRef(/* @__PURE__ */ new Set());
9255
9583
  const previousVisibilityRef = react.useRef(/* @__PURE__ */ new Map());
9256
9584
  const isSyncingSelectionToFabricRef = react.useRef(false);
9585
+ const suppressGroupMemberBordersRef = react.useRef([]);
9257
9586
  const editingTextIdRef = react.useRef(null);
9587
+ const pendingTextEditOnUpRef = react.useRef(null);
9258
9588
  const syncLockedRef = react.useRef(false);
9259
9589
  const editLockRef = react.useRef(false);
9260
9590
  const editLockCountRef = react.useRef(0);
@@ -9269,6 +9599,8 @@ const PageCanvas = react.forwardRef(
9269
9599
  const hasClearedCachesBeforeFirstSyncRef = react.useRef(false);
9270
9600
  const [guides, setGuides] = react.useState([]);
9271
9601
  const [gridResizeLabel, setGridResizeLabel] = react.useState(null);
9602
+ const [rotationLabel, setRotationLabel] = react.useState(null);
9603
+ const [sizeLabel, setSizeLabel] = react.useState(null);
9272
9604
  const [ready, setReady] = react.useState(false);
9273
9605
  const [unlockRequestId, setUnlockRequestId] = react.useState(0);
9274
9606
  react.useMemo(
@@ -9280,6 +9612,8 @@ const PageCanvas = react.forwardRef(
9280
9612
  const [groupOverlayLiveBounds, setGroupOverlayLiveBounds] = react.useState(null);
9281
9613
  const setGroupOverlayLiveBoundsRef = react.useRef(setGroupOverlayLiveBounds);
9282
9614
  const skipSelectionClearOnDiscardRef = react.useRef(false);
9615
+ const skipActiveSelectionBakeOnClearRef = react.useRef(false);
9616
+ const preserveActiveSelectionAfterTransformRef = react.useRef(null);
9283
9617
  const imageReloadRequestSeqRef = react.useRef(/* @__PURE__ */ new Map());
9284
9618
  react.useRef(null);
9285
9619
  const groupBoundsResizingRef = react.useRef(false);
@@ -9297,6 +9631,8 @@ const PageCanvas = react.forwardRef(
9297
9631
  react.useRef(null);
9298
9632
  const lastTextEditDimensionsRef = react.useRef(null);
9299
9633
  const lastResizeScaleTargetRef = react.useRef(null);
9634
+ const preserveSelectionAfterTransformIdRef = react.useRef(null);
9635
+ const groupSelectionTransformStartRef = react.useRef(null);
9300
9636
  setGroupOverlayLiveBoundsRef.current = setGroupOverlayLiveBounds;
9301
9637
  const {
9302
9638
  selectElements,
@@ -9351,7 +9687,7 @@ const PageCanvas = react.forwardRef(
9351
9687
  }
9352
9688
  },
9353
9689
  enterTextEditing: (elementId, charToInsert) => {
9354
- var _a;
9690
+ var _a2;
9355
9691
  const fc = fabricRef.current;
9356
9692
  if (!fc || !allowEditing) return false;
9357
9693
  let textbox = null;
@@ -9369,7 +9705,7 @@ const PageCanvas = react.forwardRef(
9369
9705
  textbox.enterEditing();
9370
9706
  if (charToInsert != null && charToInsert.length > 0) {
9371
9707
  const iText = textbox;
9372
- const start = iText.selectionStart ?? (((_a = iText.text) == null ? void 0 : _a.length) ?? 0);
9708
+ const start = iText.selectionStart ?? (((_a2 = iText.text) == null ? void 0 : _a2.length) ?? 0);
9373
9709
  iText.insertChars(charToInsert, void 0, start);
9374
9710
  }
9375
9711
  fc.requestRenderAll();
@@ -9460,9 +9796,9 @@ const PageCanvas = react.forwardRef(
9460
9796
  const elementById = new Map(elementsRef.current.map((el) => [el.id, el]));
9461
9797
  let didReflow = false;
9462
9798
  const reflowObject = (obj) => {
9463
- var _a;
9799
+ var _a2;
9464
9800
  if (obj instanceof fabric__namespace.Group) {
9465
- (_a = obj._objects) == null ? void 0 : _a.forEach(reflowObject);
9801
+ (_a2 = obj._objects) == null ? void 0 : _a2.forEach(reflowObject);
9466
9802
  obj.dirty = true;
9467
9803
  return;
9468
9804
  }
@@ -9670,6 +10006,7 @@ const PageCanvas = react.forwardRef(
9670
10006
  fabricCanvas.__fontCleanup = fontCleanup;
9671
10007
  fabricCanvas.__isUserTransforming = false;
9672
10008
  fabricCanvas.on("mouse:down", () => {
10009
+ groupSelectionTransformStartRef.current = null;
9673
10010
  if (fabricCanvas._currentTransform) {
9674
10011
  fabricCanvas.__isUserTransforming = true;
9675
10012
  }
@@ -9681,13 +10018,13 @@ const PageCanvas = react.forwardRef(
9681
10018
  fabricCanvas.__isUserTransforming = true;
9682
10019
  });
9683
10020
  fabricCanvas.on("object:moving", () => {
9684
- var _a;
10021
+ var _a2;
9685
10022
  fabricCanvas.__isUserTransforming = true;
9686
10023
  didTransformRef.current = true;
9687
10024
  const active = fabricCanvas.getActiveObject();
9688
10025
  if (!active) return;
9689
10026
  const state = useEditorStore.getState();
9690
- const canvasPage = (_a = state.canvas.pages) == null ? void 0 : _a.find((p) => p.id === pageId);
10027
+ const canvasPage = (_a2 = state.canvas.pages) == null ? void 0 : _a2.find((p) => p.id === pageId);
9691
10028
  const children = (canvasPage == null ? void 0 : canvasPage.children) ?? [];
9692
10029
  if (!canvasPage) return;
9693
10030
  const ids = state.canvas.selectedIds ?? [];
@@ -9722,14 +10059,14 @@ const PageCanvas = react.forwardRef(
9722
10059
  didTransformRef.current = true;
9723
10060
  });
9724
10061
  const syncSelectionToStore = () => {
9725
- var _a, _b;
10062
+ var _a2, _b, _c, _d, _e, _f, _g;
9726
10063
  if (!isActiveRef.current || isRebuildingRef.current || isSyncingSelectionToFabricRef.current || !allowSelection) return;
9727
10064
  const active = fabricCanvas.getActiveObject();
9728
10065
  let ids = fabricCanvas.getActiveObjects().map((o) => getObjectId(o)).filter((id) => !!id && id !== "__background__");
9729
10066
  if (ids.length === 1 && active && active instanceof fabric__namespace.Group && active.__docuforgeSectionGroup) {
9730
10067
  const groupId = ids[0];
9731
10068
  const state = useEditorStore.getState();
9732
- const currentPage2 = (_a = state.canvas.pages) == null ? void 0 : _a.find((p) => p.id === pageId);
10069
+ const currentPage2 = (_a2 = state.canvas.pages) == null ? void 0 : _a2.find((p) => p.id === pageId);
9733
10070
  const children = (currentPage2 == null ? void 0 : currentPage2.children) ?? [];
9734
10071
  const node = findNodeById(children, groupId);
9735
10072
  if (node && isGroup(node)) {
@@ -9737,13 +10074,48 @@ const PageCanvas = react.forwardRef(
9737
10074
  ids = [groupId, ...memberIds];
9738
10075
  }
9739
10076
  }
10077
+ if (active instanceof fabric__namespace.ActiveSelection) {
10078
+ const groupSelectionId = active.__pixldocsGroupSelection;
10079
+ if (groupSelectionId) {
10080
+ selectElements([groupSelectionId], false, false);
10081
+ return;
10082
+ }
10083
+ }
9740
10084
  if (ids.length === 1) {
10085
+ const activeEditingGroupId = fabricCanvas.__activeEditingGroupId ?? null;
10086
+ const clickedId = ids[0];
10087
+ const state = useEditorStore.getState();
10088
+ const currentPage2 = (_b = state.canvas.pages) == null ? void 0 : _b.find((p) => p.id === pageId);
10089
+ const children = (currentPage2 == null ? void 0 : currentPage2.children) ?? [];
10090
+ const parent = findParentGroup(children, clickedId);
10091
+ const targetIsInCrop = !!(((_c = active == null ? void 0 : active._ct) == null ? void 0 : _c.isCropGroup) || (active == null ? void 0 : active.__cropGroup) || ((_e = (_d = active == null ? void 0 : active.group) == null ? void 0 : _d._ct) == null ? void 0 : _e.isCropGroup) || ((_f = active == null ? void 0 : active.group) == null ? void 0 : _f.__cropGroup));
10092
+ if (parent && !targetIsInCrop && activeEditingGroupId !== parent.id && !(active && active instanceof fabric__namespace.Group && active.__docuforgeSectionGroup)) {
10093
+ const memberIdSet = new Set(getAllElementIds(parent.children ?? []));
10094
+ const memberObjs = fabricCanvas.getObjects().filter((o) => {
10095
+ const oid = getObjectId(o);
10096
+ return !!oid && memberIdSet.has(oid);
10097
+ });
10098
+ if (memberObjs.length > 1) {
10099
+ fabricCanvas.__activeEditingGroupId = null;
10100
+ const sel = new fabric__namespace.ActiveSelection(memberObjs, { canvas: fabricCanvas });
10101
+ restoreGroupSelectionVisualState(sel, parent.id);
10102
+ isSyncingSelectionToFabricRef.current = true;
10103
+ try {
10104
+ fabricCanvas.setActiveObject(sel);
10105
+ fabricCanvas.requestRenderAll();
10106
+ } finally {
10107
+ isSyncingSelectionToFabricRef.current = false;
10108
+ }
10109
+ selectElements([parent.id], false, false);
10110
+ return;
10111
+ }
10112
+ }
9741
10113
  selectElements(ids, false, false);
9742
10114
  return;
9743
10115
  }
9744
10116
  if (ids.length > 1) {
9745
10117
  const state = useEditorStore.getState();
9746
- const currentPage2 = (_b = state.canvas.pages) == null ? void 0 : _b.find((p) => p.id === pageId);
10118
+ const currentPage2 = (_g = state.canvas.pages) == null ? void 0 : _g.find((p) => p.id === pageId);
9747
10119
  const children = (currentPage2 == null ? void 0 : currentPage2.children) ?? [];
9748
10120
  const currentSelectedIds = state.canvas.selectedIds ?? [];
9749
10121
  for (const sid of currentSelectedIds) {
@@ -9752,7 +10124,7 @@ const PageCanvas = react.forwardRef(
9752
10124
  const memberIds = new Set(getAllElementIds(node.children ?? []));
9753
10125
  const fabricIdSet = new Set(ids);
9754
10126
  if (memberIds.size === fabricIdSet.size && [...memberIds].every((id) => fabricIdSet.has(id))) {
9755
- selectElements([sid, ...ids], false, true);
10127
+ selectElements([sid], false, false);
9756
10128
  return;
9757
10129
  }
9758
10130
  }
@@ -9760,32 +10132,98 @@ const PageCanvas = react.forwardRef(
9760
10132
  }
9761
10133
  selectElements(ids, false, true);
9762
10134
  };
10135
+ const restoreSuppressedGroupBorders = () => {
10136
+ const list = suppressGroupMemberBordersRef.current;
10137
+ if (!list || list.length === 0) return;
10138
+ for (const m of list) {
10139
+ const orig = m.__pixldocsOrigHasBorders;
10140
+ if (orig !== void 0) {
10141
+ m.hasBorders = orig;
10142
+ delete m.__pixldocsOrigHasBorders;
10143
+ } else {
10144
+ m.hasBorders = true;
10145
+ }
10146
+ }
10147
+ suppressGroupMemberBordersRef.current = [];
10148
+ };
9763
10149
  fabricCanvas.on("selection:created", () => {
9764
- var _a;
10150
+ var _a2;
9765
10151
  syncSelectionToStore();
9766
10152
  const activeObj = fabricCanvas.getActiveObject();
9767
10153
  if (activeObj) applyControlSizeForZoom(fabricCanvas, activeObj);
9768
- if (activeObj && !(activeObj instanceof fabric__namespace.ActiveSelection) && (((_a = activeObj._ct) == null ? void 0 : _a.isCropGroup) || activeObj.__cropGroup)) {
10154
+ if (activeObj && !(activeObj instanceof fabric__namespace.ActiveSelection) && (((_a2 = activeObj._ct) == null ? void 0 : _a2.isCropGroup) || activeObj.__cropGroup)) {
9769
10155
  installCanvaMaskControls(activeObj);
9770
10156
  }
9771
10157
  });
9772
10158
  fabricCanvas.on("selection:updated", () => {
9773
- var _a;
10159
+ var _a2;
10160
+ const next = fabricCanvas.getActiveObject();
10161
+ const isGroupSel = next instanceof fabric__namespace.ActiveSelection && next.__pixldocsGroupSelection;
10162
+ if (!isGroupSel) restoreSuppressedGroupBorders();
9774
10163
  syncSelectionToStore();
9775
10164
  const activeObj = fabricCanvas.getActiveObject();
9776
10165
  if (activeObj) applyControlSizeForZoom(fabricCanvas, activeObj);
9777
- if (activeObj && !(activeObj instanceof fabric__namespace.ActiveSelection) && (((_a = activeObj._ct) == null ? void 0 : _a.isCropGroup) || activeObj.__cropGroup)) {
10166
+ if (activeObj && !(activeObj instanceof fabric__namespace.ActiveSelection) && (((_a2 = activeObj._ct) == null ? void 0 : _a2.isCropGroup) || activeObj.__cropGroup)) {
9778
10167
  installCanvaMaskControls(activeObj);
9779
10168
  }
9780
10169
  });
10170
+ fabricCanvas.on("mouse:dblclick", (opt) => {
10171
+ var _a2, _b;
10172
+ const target = opt == null ? void 0 : opt.target;
10173
+ if (!target) return;
10174
+ if (target.isEditing) return;
10175
+ if (((_a2 = target._ct) == null ? void 0 : _a2.isCropGroup) || target.__cropGroup) return;
10176
+ const active = fabricCanvas.getActiveObject();
10177
+ let hitChild = null;
10178
+ if (active instanceof fabric__namespace.ActiveSelection) {
10179
+ const pointer = fabricCanvas.getViewportPoint(opt.e);
10180
+ const objs = active.getObjects();
10181
+ for (let i = objs.length - 1; i >= 0; i--) {
10182
+ const o = objs[i];
10183
+ if (o.containsPoint && o.containsPoint(pointer)) {
10184
+ hitChild = o;
10185
+ break;
10186
+ }
10187
+ }
10188
+ } else {
10189
+ hitChild = target;
10190
+ }
10191
+ if (!hitChild) return;
10192
+ const childId = getObjectId(hitChild);
10193
+ if (!childId) return;
10194
+ const stateNow = useEditorStore.getState();
10195
+ const pageNow = (_b = stateNow.canvas.pages) == null ? void 0 : _b.find((p) => p.id === pageId);
10196
+ const childrenNow = (pageNow == null ? void 0 : pageNow.children) ?? [];
10197
+ const parent = findParentGroup(childrenNow, childId);
10198
+ if (!parent) return;
10199
+ fabricCanvas.__activeEditingGroupId = parent.id;
10200
+ isSyncingSelectionToFabricRef.current = true;
10201
+ try {
10202
+ fabricCanvas.discardActiveObject();
10203
+ fabricCanvas.setActiveObject(hitChild);
10204
+ fabricCanvas.requestRenderAll();
10205
+ } finally {
10206
+ isSyncingSelectionToFabricRef.current = false;
10207
+ }
10208
+ selectElements([childId], false, false);
10209
+ });
9781
10210
  fabricCanvas.on("selection:cleared", () => {
9782
10211
  if (!isActiveRef.current || isRebuildingRef.current || !allowSelection) return;
9783
10212
  setGroupOverlayLiveBoundsRef.current(null);
9784
10213
  groupBoundsResizingRef.current = false;
10214
+ fabricCanvas.__activeEditingGroupId = null;
10215
+ const preservedGroupSelection = preserveActiveSelectionAfterTransformRef.current;
10216
+ const shouldRestoreGroupSelection = !!((preservedGroupSelection == null ? void 0 : preservedGroupSelection.groupSelectionId) && (!preservedGroupSelection.expiresAt || preservedGroupSelection.expiresAt > Date.now()));
9785
10217
  if (skipSelectionClearOnDiscardRef.current) {
9786
10218
  skipSelectionClearOnDiscardRef.current = false;
10219
+ if (shouldRestoreGroupSelection) restorePreservedGroupSelectionSoon(preservedGroupSelection);
10220
+ return;
10221
+ }
10222
+ if (editLockRef.current || syncLockedRef.current || didTransformRef.current || preserveSelectionAfterTransformIdRef.current || shouldRestoreGroupSelection) {
10223
+ if (shouldRestoreGroupSelection) restorePreservedGroupSelectionSoon(preservedGroupSelection);
9787
10224
  return;
9788
10225
  }
10226
+ restoreSuppressedGroupBorders();
9789
10227
  editLockRef.current = false;
9790
10228
  syncLockedRef.current = false;
9791
10229
  clearSelection();
@@ -9803,6 +10241,12 @@ const PageCanvas = react.forwardRef(
9803
10241
  return;
9804
10242
  }
9805
10243
  if (target instanceof fabric__namespace.ActiveSelection) {
10244
+ const memberIds = target.getObjects().map((o) => getObjectId(o)).filter((id2) => !!id2 && id2 !== "__background__");
10245
+ if (memberIds.length > 1) {
10246
+ const groupSelectionId = target.__pixldocsGroupSelection;
10247
+ preserveActiveSelectionAfterTransformRef.current = { memberIds, groupSelectionId, expiresAt: Date.now() + 1200 };
10248
+ if (groupSelectionId) preserveSelectionAfterTransformIdRef.current = groupSelectionId;
10249
+ }
9806
10250
  target.getObjects().forEach((o) => {
9807
10251
  const id2 = getObjectId(o);
9808
10252
  if (id2) transformingIdsRef.current.add(id2);
@@ -9815,14 +10259,78 @@ const PageCanvas = react.forwardRef(
9815
10259
  const clearTransforming = () => {
9816
10260
  transformingIdsRef.current.clear();
9817
10261
  };
10262
+ const prepareGroupSelectionTransformStart = (target) => {
10263
+ var _a2, _b;
10264
+ const active = target instanceof fabric__namespace.ActiveSelection ? target : fabricCanvas.getActiveObject();
10265
+ if (!(active instanceof fabric__namespace.ActiveSelection)) return;
10266
+ const groupId = active.__pixldocsGroupSelection;
10267
+ if (!groupId) return;
10268
+ if (((_a2 = groupSelectionTransformStartRef.current) == null ? void 0 : _a2.groupId) === groupId && groupSelectionTransformStartRef.current.selection === active) return;
10269
+ const pageChildren2 = ((_b = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _b.children) ?? [];
10270
+ const groupNode = findNodeById(pageChildren2, groupId);
10271
+ if (!groupNode) return;
10272
+ const groupAbs = getAbsoluteBounds(groupNode, pageChildren2);
10273
+ const rect = active.getBoundingRect();
10274
+ groupSelectionTransformStartRef.current = {
10275
+ groupId,
10276
+ selection: active,
10277
+ selectionLeft: rect.left,
10278
+ selectionTop: rect.top,
10279
+ groupLeft: groupAbs.left,
10280
+ groupTop: groupAbs.top
10281
+ };
10282
+ };
10283
+ const restoreGroupSelectionVisualState = (selection, groupId) => {
10284
+ selection.__pixldocsGroupSelection = groupId;
10285
+ const members = selection.getObjects();
10286
+ suppressGroupMemberBordersRef.current = members;
10287
+ for (const m of members) {
10288
+ if (m.__pixldocsOrigHasBorders === void 0) {
10289
+ m.__pixldocsOrigHasBorders = m.hasBorders;
10290
+ }
10291
+ m.hasBorders = false;
10292
+ }
10293
+ };
10294
+ const restorePreservedGroupSelectionSoon = (snapshot = preserveActiveSelectionAfterTransformRef.current) => {
10295
+ if (!(snapshot == null ? void 0 : snapshot.groupSelectionId) || snapshot.memberIds.length < 2) return;
10296
+ const groupId = snapshot.groupSelectionId;
10297
+ const memberIds = [...snapshot.memberIds];
10298
+ selectElements([groupId], false, false);
10299
+ requestAnimationFrame(() => {
10300
+ setTimeout(() => {
10301
+ const fc = fabricRef.current;
10302
+ if (!fc || !isActiveRef.current || editingTextIdRef.current) return;
10303
+ const active = fc.getActiveObject();
10304
+ if (active instanceof fabric__namespace.ActiveSelection && active.__pixldocsGroupSelection === groupId) {
10305
+ restoreGroupSelectionVisualState(active, groupId);
10306
+ fc.requestRenderAll();
10307
+ return;
10308
+ }
10309
+ const members = memberIds.map((id) => fc.getObjects().find((o) => getObjectId(o) === id)).filter((o) => !!o);
10310
+ if (members.length < 2) return;
10311
+ isSyncingSelectionToFabricRef.current = true;
10312
+ try {
10313
+ const selection = new fabric__namespace.ActiveSelection(members, { canvas: fc });
10314
+ restoreGroupSelectionVisualState(selection, groupId);
10315
+ fc.setActiveObject(selection);
10316
+ selection.setCoords();
10317
+ fc.requestRenderAll();
10318
+ } finally {
10319
+ requestAnimationFrame(() => {
10320
+ isSyncingSelectionToFabricRef.current = false;
10321
+ });
10322
+ }
10323
+ }, 0);
10324
+ });
10325
+ };
9818
10326
  const isCropGroup2 = (o) => {
9819
- var _a;
9820
- return !!(((_a = o == null ? void 0 : o._ct) == null ? void 0 : _a.isCropGroup) || (o == null ? void 0 : o.__cropGroup));
10327
+ var _a2;
10328
+ return !!(((_a2 = o == null ? void 0 : o._ct) == null ? void 0 : _a2.isCropGroup) || (o == null ? void 0 : o.__cropGroup));
9821
10329
  };
9822
10330
  const promoteToCropGroup = (opt) => {
9823
- var _a, _b, _c;
10331
+ var _a2, _b, _c;
9824
10332
  const t = opt.target;
9825
- if (((_a = opt.e) == null ? void 0 : _a.type) !== "mousedown" && ((_b = opt.e) == null ? void 0 : _b.type) !== "pointerdown" && ((_c = opt.e) == null ? void 0 : _c.type) !== "touchstart") {
10333
+ if (((_a2 = opt.e) == null ? void 0 : _a2.type) !== "mousedown" && ((_b = opt.e) == null ? void 0 : _b.type) !== "pointerdown" && ((_c = opt.e) == null ? void 0 : _c.type) !== "touchstart") {
9826
10334
  if (t && isCropGroup2(t)) {
9827
10335
  fabricCanvas._hoveredTarget = t;
9828
10336
  } else if ((t == null ? void 0 : t.group) && isCropGroup2(t.group)) {
@@ -9903,9 +10411,9 @@ const PageCanvas = react.forwardRef(
9903
10411
  });
9904
10412
  }
9905
10413
  fabricCanvas.on("mouse:down", (opt) => {
9906
- var _a, _b;
10414
+ var _a2, _b;
9907
10415
  const target = opt.target;
9908
- const cropGroup = ((_a = target == null ? void 0 : target._ct) == null ? void 0 : _a.isCropGroup) || (target == null ? void 0 : target.__cropGroup) ? target : (target == null ? void 0 : target.group) && (((_b = target.group._ct) == null ? void 0 : _b.isCropGroup) || target.group.__cropGroup) ? target.group : null;
10416
+ const cropGroup = ((_a2 = target == null ? void 0 : target._ct) == null ? void 0 : _a2.isCropGroup) || (target == null ? void 0 : target.__cropGroup) ? target : (target == null ? void 0 : target.group) && (((_b = target.group._ct) == null ? void 0 : _b.isCropGroup) || target.group.__cropGroup) ? target.group : null;
9909
10417
  if (cropGroup) {
9910
10418
  lockEdits();
9911
10419
  didTransformRef.current = false;
@@ -9915,10 +10423,10 @@ const PageCanvas = react.forwardRef(
9915
10423
  }
9916
10424
  });
9917
10425
  fabricCanvas.on("mouse:down:before", (opt) => {
9918
- var _a, _b, _c, _d, _e;
10426
+ var _a2, _b, _c, _d, _e;
9919
10427
  if (editLockRef.current) {
9920
10428
  const active = fabricCanvas.getActiveObject();
9921
- if (active && (((_a = active._ct) == null ? void 0 : _a.isCropGroup) || active.__cropGroup)) {
10429
+ if (active && (((_a2 = active._ct) == null ? void 0 : _a2.isCropGroup) || active.__cropGroup)) {
9922
10430
  opt.target = active;
9923
10431
  if (opt.e) {
9924
10432
  (_c = (_b = opt.e).preventDefault) == null ? void 0 : _c.call(_b);
@@ -9934,22 +10442,25 @@ const PageCanvas = react.forwardRef(
9934
10442
  promoteToCropGroup(opt);
9935
10443
  });
9936
10444
  fabricCanvas.on("mouse:move:before", promoteToCropGroup);
9937
- fabricCanvas.on("mouse:down", () => {
10445
+ fabricCanvas.on("mouse:down", (ev) => {
9938
10446
  if (fabricCanvas._currentTransform) {
9939
10447
  lockEdits();
9940
10448
  didTransformRef.current = true;
9941
10449
  }
9942
10450
  const o = fabricCanvas.getActiveObject();
10451
+ pendingTextEditOnUpRef.current = null;
9943
10452
  if (!o) return;
9944
10453
  o.__lockScaleDuringCrop = false;
9945
10454
  });
9946
10455
  fabricCanvas.on("mouse:up", (e) => {
9947
- var _a;
10456
+ var _a2;
9948
10457
  clearTransforming();
9949
10458
  setGuides([]);
10459
+ setRotationLabel(null);
10460
+ setSizeLabel(null);
9950
10461
  dragStarted = false;
9951
10462
  const activeObj = fabricCanvas.getActiveObject();
9952
- if (activeObj && (activeObj.__cropGroup || ((_a = activeObj._ct) == null ? void 0 : _a.isCropGroup))) {
10463
+ if (activeObj && (activeObj.__cropGroup || ((_a2 = activeObj._ct) == null ? void 0 : _a2.isCropGroup))) {
9953
10464
  activeObj.__lockScaleDuringCrop = false;
9954
10465
  if (activeObj.__cropDrag) {
9955
10466
  delete activeObj.__cropDrag;
@@ -9990,9 +10501,9 @@ const PageCanvas = react.forwardRef(
9990
10501
  markTransforming(e.target);
9991
10502
  };
9992
10503
  fabricCanvas.on("object:added", (e) => {
9993
- var _a;
10504
+ var _a2;
9994
10505
  const obj = e.target;
9995
- if (obj && (obj.__cropGroup || ((_a = obj._ct) == null ? void 0 : _a.isCropGroup))) {
10506
+ if (obj && (obj.__cropGroup || ((_a2 = obj._ct) == null ? void 0 : _a2.isCropGroup))) {
9996
10507
  if (!obj.__cropGroupId) {
9997
10508
  obj.__cropGroupId = `crop-${Date.now()}-${Math.random()}`;
9998
10509
  }
@@ -10004,13 +10515,28 @@ const PageCanvas = react.forwardRef(
10004
10515
  if (!isActiveRef.current) return;
10005
10516
  const t = e.target;
10006
10517
  if (t) lastResizeScaleTargetRef.current = t;
10518
+ prepareGroupSelectionTransformStart(t);
10007
10519
  markTransforming(t);
10008
10520
  didTransformRef.current = true;
10521
+ const transformTargetId = t ? getObjectId(t) : null;
10522
+ if (transformTargetId && transformTargetId !== "__background__") {
10523
+ preserveSelectionAfterTransformIdRef.current = transformTargetId;
10524
+ }
10009
10525
  const obj = t;
10010
10526
  if (!obj) return;
10011
10527
  if (obj instanceof fabric__namespace.Rect || obj instanceof fabric__namespace.Path || obj instanceof fabric__namespace.Circle || obj instanceof fabric__namespace.Triangle || obj instanceof fabric__namespace.Line) {
10012
10528
  obj.set({ strokeUniform: true });
10013
10529
  }
10530
+ try {
10531
+ const br = obj.getBoundingRect();
10532
+ setSizeLabel({
10533
+ width: Math.round(br.width),
10534
+ height: Math.round(br.height),
10535
+ x: br.left + br.width / 2,
10536
+ y: br.top + br.height + 18
10537
+ });
10538
+ } catch {
10539
+ }
10014
10540
  const objId = getObjectId(obj);
10015
10541
  const sourceEl = objId ? elementsRef.current.find((el) => el.id === objId) : null;
10016
10542
  const isCornerShape = (sourceEl == null ? void 0 : sourceEl.type) === "shape" && (sourceEl.shapeType === "circle" || sourceEl.shapeType === "rounded-rect" || sourceEl.shapeType === "triangle");
@@ -10144,8 +10670,23 @@ const PageCanvas = react.forwardRef(
10144
10670
  const t = e.target;
10145
10671
  if (t) lastResizeScaleTargetRef.current = t;
10146
10672
  markTransforming(t);
10673
+ didTransformRef.current = true;
10674
+ const transformTargetId = t ? getObjectId(t) : null;
10675
+ if (transformTargetId && transformTargetId !== "__background__") {
10676
+ preserveSelectionAfterTransformIdRef.current = transformTargetId;
10677
+ }
10147
10678
  const obj = t;
10148
10679
  if (!obj) return;
10680
+ try {
10681
+ const br = obj.getBoundingRect();
10682
+ setSizeLabel({
10683
+ width: Math.round(br.width),
10684
+ height: Math.round(br.height),
10685
+ x: br.left + br.width / 2,
10686
+ y: br.top + br.height + 18
10687
+ });
10688
+ } catch {
10689
+ }
10149
10690
  const transform = e.transform;
10150
10691
  const corner = (transform == null ? void 0 : transform.corner) || "";
10151
10692
  const scaleGuides = calculateScaleSnapGuidesCallback(obj, corner);
@@ -10154,6 +10695,23 @@ const PageCanvas = react.forwardRef(
10154
10695
  fabricCanvas.on("object:rotating", (e) => {
10155
10696
  markSimpleTransform(e);
10156
10697
  didTransformRef.current = true;
10698
+ const tr = e.target;
10699
+ const rotateTargetId = tr ? getObjectId(tr) : null;
10700
+ if (rotateTargetId && rotateTargetId !== "__background__") {
10701
+ preserveSelectionAfterTransformIdRef.current = rotateTargetId;
10702
+ }
10703
+ if (tr) {
10704
+ try {
10705
+ const br = tr.getBoundingRect();
10706
+ let angle = ((tr.angle ?? 0) % 360 + 360) % 360;
10707
+ setRotationLabel({
10708
+ angle: Math.round(angle),
10709
+ x: br.left + br.width / 2,
10710
+ y: br.top + br.height / 2
10711
+ });
10712
+ } catch {
10713
+ }
10714
+ }
10157
10715
  });
10158
10716
  fabricCanvas.on("object:skewing", (e) => {
10159
10717
  markSimpleTransform(e);
@@ -10161,8 +10719,13 @@ const PageCanvas = react.forwardRef(
10161
10719
  });
10162
10720
  fabricCanvas.on("object:moving", (e) => {
10163
10721
  if (!isActiveRef.current) return;
10722
+ prepareGroupSelectionTransformStart(e.target);
10164
10723
  markTransforming(e.target);
10165
10724
  didTransformRef.current = true;
10725
+ const moveTargetId = e.target ? getObjectId(e.target) : null;
10726
+ if (moveTargetId && moveTargetId !== "__background__") {
10727
+ preserveSelectionAfterTransformIdRef.current = moveTargetId;
10728
+ }
10166
10729
  if (!dragStarted) {
10167
10730
  dragStarted = true;
10168
10731
  const selectedEls = elementsRef.current.filter((el) => selectedIdsRef.current.includes(el.id));
@@ -10182,7 +10745,7 @@ const PageCanvas = react.forwardRef(
10182
10745
  });
10183
10746
  let cropGroupSaveTimer = null;
10184
10747
  fabricCanvas.on("object:modified", (e) => {
10185
- var _a, _b, _c, _d, _e, _f;
10748
+ var _a2, _b, _c, _d, _e, _f;
10186
10749
  try {
10187
10750
  dragStarted = false;
10188
10751
  setGuides([]);
@@ -10213,12 +10776,8 @@ const PageCanvas = react.forwardRef(
10213
10776
  }
10214
10777
  const active = fabricCanvas.getActiveObject();
10215
10778
  const activeId = active ? getObjectId(active) : null;
10216
- const activeObjectsForLog = fabricCanvas.getActiveObjects();
10217
- if (typeof console !== "undefined" && console.log) {
10218
- console.log("[object:modified] activeId=", activeId, "isGroup=", active instanceof fabric__namespace.Group, "isActiveSelection=", active instanceof fabric__namespace.ActiveSelection, "activeObjectsCount=", (activeObjectsForLog == null ? void 0 : activeObjectsForLog.length) ?? 0);
10219
- }
10220
10779
  if (active && activeId && activeId !== "__background__" && !(active instanceof fabric__namespace.Group)) {
10221
- const pageChildrenForParent = ((_a = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a.children) ?? [];
10780
+ const pageChildrenForParent = ((_a2 = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a2.children) ?? [];
10222
10781
  const parentGroup = findParentGroup(pageChildrenForParent, activeId);
10223
10782
  if (parentGroup && isGroup(parentGroup) && parentGroup.backgroundColor) {
10224
10783
  let fabricSectionGroup = active.group && active.group instanceof fabric__namespace.Group ? active.group : null;
@@ -10327,10 +10886,10 @@ const PageCanvas = react.forwardRef(
10327
10886
  clearTimeout(cropGroupSaveTimer);
10328
10887
  }
10329
10888
  cropGroupSaveTimer = setTimeout(() => {
10330
- var _a2, _b2, _c2;
10889
+ var _a3, _b2, _c2;
10331
10890
  const { updateElement: updateElement2 } = useEditorStore.getState();
10332
10891
  const img = ct._img;
10333
- const zoom3 = ((_a2 = img == null ? void 0 : img._ct) == null ? void 0 : _a2.zoom) ?? 1;
10892
+ const zoom3 = ((_a3 = img == null ? void 0 : img._ct) == null ? void 0 : _a3.zoom) ?? 1;
10334
10893
  const panX = ((_b2 = img == null ? void 0 : img._ct) == null ? void 0 : _b2.panX) ?? 0.5;
10335
10894
  const panY = ((_c2 = img == null ? void 0 : img._ct) == null ? void 0 : _c2.panY) ?? 0.5;
10336
10895
  const stateCrop = useEditorStore.getState();
@@ -10429,10 +10988,23 @@ const PageCanvas = react.forwardRef(
10429
10988
  }
10430
10989
  const activeObj = fabricCanvas.getActiveObject();
10431
10990
  let activeObjects = fabricCanvas.getActiveObjects();
10991
+ if (activeObjects.length === 0 && modifiedTarget && getObjectId(modifiedTarget)) {
10992
+ activeObjects = [modifiedTarget];
10993
+ }
10432
10994
  if (activeObjects.length === 1 && typeof activeObjects[0].getObjects === "function" && !getObjectId(activeObjects[0])) {
10433
10995
  activeObjects = activeObjects[0].getObjects();
10434
10996
  }
10435
10997
  const isActiveSelection = activeObj instanceof fabric__namespace.ActiveSelection || activeObjects.length > 1;
10998
+ if (activeObj instanceof fabric__namespace.ActiveSelection && activeObjects.length > 1) {
10999
+ const memberIds = activeObjects.map((o) => getObjectId(o)).filter((id) => !!id && id !== "__background__");
11000
+ if (memberIds.length > 1) {
11001
+ preserveActiveSelectionAfterTransformRef.current = {
11002
+ memberIds,
11003
+ groupSelectionId: activeObj.__pixldocsGroupSelection,
11004
+ expiresAt: Date.now() + 1200
11005
+ };
11006
+ }
11007
+ }
10436
11008
  const { getCurrentPage: getCurrentPageStore } = useEditorStore.getState();
10437
11009
  const currentPage2 = getCurrentPageStore();
10438
11010
  const selectedElementIds = activeObjects.map((obj) => getObjectId(obj)).filter((id) => !!id && id !== "__background__");
@@ -10455,10 +11027,38 @@ const PageCanvas = react.forwardRef(
10455
11027
  })();
10456
11028
  const groupToMove = candidateIsStack || allMembersSelected ? candidateGroup : null;
10457
11029
  if (groupToMove) {
11030
+ const activeGroupSelectionId = activeObj instanceof fabric__namespace.ActiveSelection ? activeObj.__pixldocsGroupSelection : void 0;
11031
+ const transformStart = activeGroupSelectionId === groupToMove.id ? groupSelectionTransformStartRef.current : null;
10458
11032
  const groupAbs = getAbsoluteBounds(groupToMove, pageChildren2);
10459
11033
  let movedGroupLeft = groupAbs.left;
10460
11034
  let movedGroupTop = groupAbs.top;
10461
- if (activeObj) {
11035
+ if (activeObj instanceof fabric__namespace.ActiveSelection && (transformStart == null ? void 0 : transformStart.groupId) === groupToMove.id) {
11036
+ const selectionRect = activeObj.getBoundingRect();
11037
+ movedGroupLeft = transformStart.groupLeft + (selectionRect.left - transformStart.selectionLeft);
11038
+ movedGroupTop = transformStart.groupTop + (selectionRect.top - transformStart.selectionTop);
11039
+ } else if (activeObj instanceof fabric__namespace.ActiveSelection && firstId && firstObj) {
11040
+ const firstNode = findNodeById(pageChildren2, firstId);
11041
+ if (firstNode) {
11042
+ try {
11043
+ const oldAbs = getAbsoluteBounds(firstNode, pageChildren2);
11044
+ const m = fabric__namespace.util.multiplyTransformMatrices(
11045
+ activeObj.calcTransformMatrix(),
11046
+ firstObj.calcOwnMatrix()
11047
+ );
11048
+ const decomposed = fabric__namespace.util.qrDecompose(m);
11049
+ const w = (firstObj.width ?? 0) * Math.abs(decomposed.scaleX || 1);
11050
+ const h = (firstObj.height ?? 0) * Math.abs(decomposed.scaleY || 1);
11051
+ const newAbsLeft = firstObj.originX === "center" ? decomposed.translateX - w / 2 : decomposed.translateX;
11052
+ const newAbsTop = firstObj.originY === "center" ? decomposed.translateY - h / 2 : decomposed.translateY;
11053
+ movedGroupLeft = groupAbs.left + (newAbsLeft - oldAbs.left);
11054
+ movedGroupTop = groupAbs.top + (newAbsTop - oldAbs.top);
11055
+ } catch {
11056
+ const selectionRect = activeObj.getBoundingRect();
11057
+ movedGroupLeft = selectionRect.left;
11058
+ movedGroupTop = selectionRect.top;
11059
+ }
11060
+ }
11061
+ } else if (activeObj) {
10462
11062
  const selectionRect = activeObj.getBoundingRect();
10463
11063
  movedGroupLeft = selectionRect.left;
10464
11064
  movedGroupTop = selectionRect.top;
@@ -10472,44 +11072,22 @@ const PageCanvas = react.forwardRef(
10472
11072
  const deltaX = movedGroupLeft - groupAbs.left;
10473
11073
  const deltaY = movedGroupTop - groupAbs.top;
10474
11074
  const hadScale = isActiveSelection && activeObj && (Math.abs((activeObj.scaleX ?? 1) - 1) > 0.01 || Math.abs((activeObj.scaleY ?? 1) - 1) > 0.01);
10475
- if (!hadScale && (Math.abs(deltaX) > 0.1 || Math.abs(deltaY) > 0.1)) {
10476
- if (typeof console !== "undefined" && console.log) {
10477
- console.log("[object:modified] plain-groups: moving group id=", groupToMove.id, "newLeft=", (groupToMove.left ?? 0) + deltaX, "newTop=", (groupToMove.top ?? 0) + deltaY);
10478
- }
11075
+ const hadRotation = isActiveSelection && activeObj && Math.abs((activeObj.angle ?? 0) % 360) > 0.01;
11076
+ if (!hadScale && !hadRotation && (Math.abs(deltaX) > 0.1 || Math.abs(deltaY) > 0.1)) {
10479
11077
  const { updateNode: updateNodeStore, commitHistory: commitHistoryStore, getCurrentElements } = useEditorStore.getState();
10480
11078
  const newLeft = (groupToMove.left ?? 0) + deltaX;
10481
11079
  const newTop = (groupToMove.top ?? 0) + deltaY;
10482
11080
  updateNodeStore(groupToMove.id, { left: newLeft, top: newTop }, { recordHistory: false, skipLayoutRecalc: true });
10483
11081
  commitHistoryStore();
10484
- if (isActiveSelection && activeObj instanceof fabric__namespace.ActiveSelection) {
10485
- skipSelectionClearOnDiscardRef.current = true;
10486
- fabricCanvas.discardActiveObject();
10487
- }
10488
- const stateAfter = useEditorStore.getState();
10489
- const pageAfter = stateAfter.canvas.pages.find((p) => p.id === pageId);
10490
- const pageChildrenAfter = (pageAfter == null ? void 0 : pageAfter.children) ?? [];
10491
- for (const obj of activeObjects) {
10492
- const objId = getObjectId(obj);
10493
- if (!objId || objId === "__background__") continue;
10494
- const node = findNodeById(pageChildrenAfter, objId);
10495
- if (node) {
10496
- const abs = getAbsoluteBounds(node, pageChildrenAfter);
10497
- const w = (obj.width ?? 0) * (obj.scaleX ?? 1);
10498
- const h = (obj.height ?? 0) * (obj.scaleY ?? 1);
10499
- const nextLeft = obj.originX === "center" ? abs.left + w / 2 : abs.left;
10500
- const nextTop = obj.originY === "center" ? abs.top + h / 2 : abs.top;
10501
- obj.set({ left: nextLeft, top: nextTop });
10502
- obj.setCoords();
10503
- }
10504
- }
10505
- if (isActiveSelection && activeObjects.length > 0) {
10506
- const selection = new fabric__namespace.ActiveSelection([...activeObjects], { canvas: fabricCanvas });
10507
- fabricCanvas.setActiveObject(selection);
10508
- skipSelectionClearOnDiscardRef.current = false;
11082
+ const groupSelectionId = isActiveSelection && activeObj instanceof fabric__namespace.ActiveSelection ? activeObj.__pixldocsGroupSelection : void 0;
11083
+ const targetObjects = isActiveSelection && activeObj instanceof fabric__namespace.ActiveSelection ? activeObj.getObjects() : activeObjects;
11084
+ if (groupSelectionId && activeObj instanceof fabric__namespace.ActiveSelection) {
11085
+ restoreGroupSelectionVisualState(activeObj, groupSelectionId);
11086
+ activeObj.setCoords();
10509
11087
  }
10510
11088
  fabricCanvas.requestRenderAll();
10511
11089
  elementsRef.current = getCurrentElements();
10512
- for (const obj of activeObjects) {
11090
+ for (const obj of targetObjects) {
10513
11091
  const objId = getObjectId(obj);
10514
11092
  if (objId && objId !== "__background__") {
10515
11093
  justModifiedIdsRef.current.add(objId);
@@ -10517,6 +11095,11 @@ const PageCanvas = react.forwardRef(
10517
11095
  }
10518
11096
  }
10519
11097
  setTimeout(() => modifiedIdsThisRound.forEach((id) => justModifiedIdsRef.current.delete(id)), 150);
11098
+ groupSelectionTransformStartRef.current = null;
11099
+ restorePreservedGroupSelectionSoon({
11100
+ memberIds: targetObjects.map((obj) => getObjectId(obj)).filter((id) => !!id && id !== "__background__"),
11101
+ groupSelectionId
11102
+ });
10520
11103
  unlockEditsSoon();
10521
11104
  return;
10522
11105
  }
@@ -10539,7 +11122,10 @@ const PageCanvas = react.forwardRef(
10539
11122
  intrinsicHeight = obj.height ?? 0;
10540
11123
  } else if (obj instanceof fabric__namespace.Line) {
10541
11124
  const x1 = obj.x1 ?? 0, y1 = obj.y1 ?? 0, x2 = obj.x2 ?? 0, y2 = obj.y2 ?? 0;
10542
- intrinsicWidth = Math.hypot(x2 - x1, y2 - y1) * (obj.scaleX ?? 1);
11125
+ const rawLen = Math.hypot(x2 - x1, y2 - y1);
11126
+ const ownScaleX = obj.scaleX ?? 1;
11127
+ const selScaleX = isActiveSelection && activeObj ? Math.abs(activeObj.scaleX ?? 1) : 1;
11128
+ intrinsicWidth = rawLen * Math.abs(ownScaleX) * selScaleX;
10543
11129
  intrinsicHeight = 0;
10544
11130
  } else {
10545
11131
  intrinsicWidth = obj.width ?? 0;
@@ -10710,20 +11296,37 @@ const PageCanvas = react.forwardRef(
10710
11296
  for (const gid of stackGroupsToReflow) {
10711
11297
  useEditorStore.getState().reflowStackGroupInPage(pageId, gid);
10712
11298
  }
10713
- if (isActiveSelection && activeObj && activeObjects.length > 0) {
10714
- const selectionMatrix = activeObj.calcTransformMatrix();
10715
- for (const obj of activeObjects) {
10716
- const objId = getObjectId(obj);
10717
- if (!objId || objId === "__background__") continue;
10718
- const objOwnMatrix = obj.calcOwnMatrix();
10719
- const absoluteMatrix = fabric__namespace.util.multiplyTransformMatrices(selectionMatrix, objOwnMatrix);
10720
- fabric__namespace.util.applyTransformToObject(obj, absoluteMatrix);
10721
- obj.setCoords();
11299
+ if (activeObj instanceof fabric__namespace.ActiveSelection && activeObjects.length > 0) {
11300
+ const wasGroupSel = activeObj.__pixldocsGroupSelection;
11301
+ const membersToReselect = activeObjects.filter((o) => {
11302
+ const oid = getObjectId(o);
11303
+ return !!oid && oid !== "__background__";
11304
+ });
11305
+ skipSelectionClearOnDiscardRef.current = true;
11306
+ skipActiveSelectionBakeOnClearRef.current = true;
11307
+ try {
11308
+ fabricCanvas.discardActiveObject();
11309
+ } finally {
11310
+ skipActiveSelectionBakeOnClearRef.current = false;
11311
+ }
11312
+ if (membersToReselect.length > 1) {
11313
+ const newSel = new fabric__namespace.ActiveSelection(membersToReselect, { canvas: fabricCanvas });
11314
+ if (wasGroupSel) restoreGroupSelectionVisualState(newSel, wasGroupSel);
11315
+ fabricCanvas.setActiveObject(newSel);
11316
+ newSel.setCoords();
11317
+ } else if (membersToReselect.length === 1) {
11318
+ fabricCanvas.setActiveObject(membersToReselect[0]);
11319
+ }
11320
+ skipSelectionClearOnDiscardRef.current = false;
11321
+ if (wasGroupSel) {
11322
+ restorePreservedGroupSelectionSoon({
11323
+ memberIds: membersToReselect.map((obj) => getObjectId(obj)).filter((id) => !!id && id !== "__background__"),
11324
+ groupSelectionId: wasGroupSel
11325
+ });
10722
11326
  }
10723
- activeObj.set({ scaleX: 1, scaleY: 1 });
10724
- activeObj.setCoords();
10725
11327
  fabricCanvas.requestRenderAll();
10726
11328
  }
11329
+ groupSelectionTransformStartRef.current = null;
10727
11330
  setTimeout(() => modifiedIdsThisRound.forEach((id) => justModifiedIdsRef.current.delete(id)), 150);
10728
11331
  commitHistory();
10729
11332
  unlockEditsSoon();
@@ -10740,6 +11343,7 @@ const PageCanvas = react.forwardRef(
10740
11343
  if (!deselected || deselected.length === 0) return;
10741
11344
  const activeObj = fabricCanvas.getActiveObject();
10742
11345
  if (!(activeObj instanceof fabric__namespace.ActiveSelection)) return;
11346
+ if (skipActiveSelectionBakeOnClearRef.current) return;
10743
11347
  const selectionMatrix = activeObj.calcTransformMatrix();
10744
11348
  for (const obj of deselected) {
10745
11349
  const objId = getObjectId(obj);
@@ -10925,7 +11529,8 @@ const PageCanvas = react.forwardRef(
10925
11529
  }
10926
11530
  }
10927
11531
  }
10928
- const visibilityBatchThreshold = hasAnyVisibilityChange && (totalVisibilityChanges > 0 && visibilityOnlyCount / totalVisibilityChanges >= 0.8 || totalVisibilityChanges >= 5 && visibilityOnlyCount / totalVisibilityChanges >= 0.7);
11532
+ const visibilityOnlySignal = isVisibilityOnlyUpdatePending();
11533
+ const visibilityBatchThreshold = hasAnyVisibilityChange && visibilityOnlySignal || hasAnyVisibilityChange && (totalVisibilityChanges > 0 && visibilityOnlyCount / totalVisibilityChanges >= 0.8 || totalVisibilityChanges >= 5 && visibilityOnlyCount / totalVisibilityChanges >= 0.7);
10929
11534
  if (visibilityBatchThreshold) {
10930
11535
  visibilityUpdateInProgressRef.current = true;
10931
11536
  setTimeout(() => {
@@ -10935,12 +11540,12 @@ const PageCanvas = react.forwardRef(
10935
11540
  visibilityUpdateInProgressRef.current = false;
10936
11541
  }
10937
11542
  doSyncRef.current = () => {
10938
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
11543
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
10939
11544
  const shouldSkipUpdates2 = syncLockedRef.current || editLockRef.current;
10940
11545
  const state = useEditorStore.getState();
10941
11546
  const elementsToSync = elements;
10942
11547
  elementsRef.current = elementsToSync;
10943
- const pageTree = isPreviewMode && (pageChildren == null ? void 0 : pageChildren.length) ? pageChildren ?? [] : ((_a = state.canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a.children) ?? [];
11548
+ const pageTree = isPreviewMode && (pageChildren == null ? void 0 : pageChildren.length) ? pageChildren ?? [] : ((_a2 = state.canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a2.children) ?? [];
10944
11549
  const selectedIdsFromStore = new Set(((_b = state.canvas) == null ? void 0 : _b.selectedIds) ?? []);
10945
11550
  isRebuildingRef.current = true;
10946
11551
  const allElementIds = new Set(elementsToSync.map((el) => el.id));
@@ -10958,8 +11563,13 @@ const PageCanvas = react.forwardRef(
10958
11563
  if (!sectionDescendantIds.has(id)) validTopLevelIds.add(id);
10959
11564
  });
10960
11565
  const activeBeforeSync = fc.getActiveObject();
11566
+ const transformSelectionId = preserveSelectionAfterTransformIdRef.current;
10961
11567
  const isTransforming2 = !!fc._currentTransform;
10962
- if (syncTriggeredByPanelRef.current && !shouldSkipUpdates2 && !isTransforming2) {
11568
+ const activeSelectionSnapshot = activeBeforeSync instanceof fabric__namespace.ActiveSelection ? {
11569
+ memberIds: activeBeforeSync.getObjects().map((o) => getObjectId(o)).filter((id) => !!id && id !== "__background__"),
11570
+ groupSelectionId: activeBeforeSync.__pixldocsGroupSelection
11571
+ } : preserveActiveSelectionAfterTransformRef.current;
11572
+ if (syncTriggeredByPanelRef.current && !transformSelectionId && !shouldSkipUpdates2 && !isTransforming2) {
10963
11573
  const activeObj = fc.getActiveObject();
10964
11574
  const activeObjId = activeObj ? getObjectId(activeObj) : null;
10965
11575
  const isTextBeingEdited = activeObjId && editingTextIdRef.current === activeObjId;
@@ -10974,15 +11584,44 @@ const PageCanvas = react.forwardRef(
10974
11584
  currentFabricObjects.set(id, obj);
10975
11585
  }
10976
11586
  });
10977
- const skipRestoreSelection = syncTriggeredByPanelRef.current;
11587
+ const skipRestoreSelection = syncTriggeredByPanelRef.current && !transformSelectionId;
11588
+ const activeId = transformSelectionId || (activeBeforeSync ? getObjectId(activeBeforeSync) : null);
10978
11589
  const activeStillOnCanvas = activeBeforeSync && fc.getObjects().includes(activeBeforeSync);
10979
- const activeId = activeBeforeSync ? getObjectId(activeBeforeSync) : null;
11590
+ const replacementById = !activeStillOnCanvas && activeId ? fc.getObjects().find((o) => getObjectId(o) === activeId) ?? null : null;
11591
+ const restoreTarget = activeStillOnCanvas ? activeBeforeSync : replacementById;
10980
11592
  const isActiveTextBeingEdited = activeId && editingTextIdRef.current === activeId && activeBeforeSync instanceof fabric__namespace.Textbox;
10981
- if (!skipRestoreSelection && activeBeforeSync && activeStillOnCanvas && !isActiveTextBeingEdited) {
10982
- const isCropGroup2 = ((_d = activeBeforeSync._ct) == null ? void 0 : _d.isCropGroup) || activeBeforeSync.__cropGroup;
11593
+ if (!skipRestoreSelection && activeSelectionSnapshot && !isActiveTextBeingEdited && !shouldSkipUpdates2) {
11594
+ const freshMembers = activeSelectionSnapshot.memberIds.map((id) => fc.getObjects().find((o) => getObjectId(o) === id)).filter((o) => !!o);
11595
+ if (freshMembers.length > 1) {
11596
+ isSyncingSelectionToFabricRef.current = true;
11597
+ try {
11598
+ const newSel = new fabric__namespace.ActiveSelection(freshMembers, { canvas: fc });
11599
+ if (activeSelectionSnapshot.groupSelectionId) {
11600
+ newSel.__pixldocsGroupSelection = activeSelectionSnapshot.groupSelectionId;
11601
+ suppressGroupMemberBordersRef.current = freshMembers;
11602
+ for (const m of freshMembers) {
11603
+ if (m.__pixldocsOrigHasBorders === void 0) {
11604
+ m.__pixldocsOrigHasBorders = m.hasBorders;
11605
+ }
11606
+ m.hasBorders = false;
11607
+ }
11608
+ }
11609
+ fc.setActiveObject(newSel);
11610
+ newSel.setCoords();
11611
+ fc.requestRenderAll();
11612
+ } finally {
11613
+ isSyncingSelectionToFabricRef.current = false;
11614
+ }
11615
+ } else if (freshMembers.length === 1) {
11616
+ fc.setActiveObject(freshMembers[0]);
11617
+ fc.requestRenderAll();
11618
+ }
11619
+ } else if (!skipRestoreSelection && restoreTarget && !isActiveTextBeingEdited) {
11620
+ const isCropGroup2 = ((_d = restoreTarget._ct) == null ? void 0 : _d.isCropGroup) || restoreTarget.__cropGroup;
10983
11621
  const isSectionGroup = activeId && sectionGroupIds.has(activeId);
10984
11622
  if ((isCropGroup2 || !shouldSkipUpdates2) && !isSectionGroup) {
10985
- fc.setActiveObject(activeBeforeSync);
11623
+ fc.setActiveObject(restoreTarget);
11624
+ fc.requestRenderAll();
10986
11625
  }
10987
11626
  }
10988
11627
  for (const id of sectionGroupIds) {
@@ -11071,9 +11710,9 @@ const PageCanvas = react.forwardRef(
11071
11710
  sectionGroup.__docuforgeSectionGroup = true;
11072
11711
  const bgColor = G.backgroundColor || "#f0f0f0";
11073
11712
  sectionGroup._renderBackground = function(ctx) {
11074
- var _a2;
11713
+ var _a3;
11075
11714
  if (bgColor === "transparent") return;
11076
- const dim = ((_a2 = this._getNonTransformedDimensions) == null ? void 0 : _a2.call(this)) ?? { x: this.width ?? gw, y: this.height ?? gh };
11715
+ const dim = ((_a3 = this._getNonTransformedDimensions) == null ? void 0 : _a3.call(this)) ?? { x: this.width ?? gw, y: this.height ?? gh };
11077
11716
  const w = dim.x ?? gw;
11078
11717
  const h = dim.y ?? gh;
11079
11718
  ctx.save();
@@ -11195,8 +11834,17 @@ const PageCanvas = react.forwardRef(
11195
11834
  flipX: element.flipX ?? false,
11196
11835
  flipY: element.flipY ?? false
11197
11836
  });
11198
- const clampedOpacity = element.opacity !== void 0 ? Math.max(0, Math.min(1, element.opacity)) : 1;
11199
- existingObj.set({ opacity: clampedOpacity });
11837
+ const baseOpacity = element.opacity !== void 0 ? Math.max(0, Math.min(1, element.opacity)) : 1;
11838
+ const clampedOpacity = isHidden ? 0 : baseOpacity;
11839
+ const isDynamicFieldImg = dynamicFieldIds.includes(element.id);
11840
+ const canBeEventedImg = isEditorMode || isPreviewMode && isDynamicFieldImg;
11841
+ existingObj.set({
11842
+ opacity: clampedOpacity,
11843
+ selectable: allowSelection && !isHidden,
11844
+ evented: canBeEventedImg && !isHidden,
11845
+ hasControls: allowEditing && !isHidden,
11846
+ hasBorders: allowEditing && !isHidden
11847
+ });
11200
11848
  existingObj.set({ width: ct.frameW, height: ct.frameH });
11201
11849
  existingObj.set({ backgroundColor: "transparent" });
11202
11850
  const liveMask = existingObj.clipPath;
@@ -11676,6 +12324,57 @@ const PageCanvas = react.forwardRef(
11676
12324
  }
11677
12325
  }
11678
12326
  });
12327
+ if (!skipRestoreSelection && activeSelectionSnapshot && !isActiveTextBeingEdited) {
12328
+ const currentActive = fc.getActiveObject();
12329
+ const currentMemberIds = currentActive instanceof fabric__namespace.ActiveSelection ? currentActive.getObjects().map((o) => getObjectId(o)).filter((id) => !!id && id !== "__background__") : [];
12330
+ const sameActiveSelection = currentMemberIds.length === activeSelectionSnapshot.memberIds.length && activeSelectionSnapshot.memberIds.every((id) => currentMemberIds.includes(id));
12331
+ if (!sameActiveSelection) {
12332
+ const freshMembers = activeSelectionSnapshot.memberIds.map((id) => fc.getObjects().find((o) => getObjectId(o) === id)).filter((o) => !!o);
12333
+ if (freshMembers.length > 1) {
12334
+ isSyncingSelectionToFabricRef.current = true;
12335
+ try {
12336
+ const newSel = new fabric__namespace.ActiveSelection(freshMembers, { canvas: fc });
12337
+ if (activeSelectionSnapshot.groupSelectionId) {
12338
+ newSel.__pixldocsGroupSelection = activeSelectionSnapshot.groupSelectionId;
12339
+ suppressGroupMemberBordersRef.current = freshMembers;
12340
+ for (const m of freshMembers) {
12341
+ if (m.__pixldocsOrigHasBorders === void 0) {
12342
+ m.__pixldocsOrigHasBorders = m.hasBorders;
12343
+ }
12344
+ m.hasBorders = false;
12345
+ }
12346
+ }
12347
+ fc.setActiveObject(newSel);
12348
+ newSel.setCoords();
12349
+ fc.requestRenderAll();
12350
+ } finally {
12351
+ isSyncingSelectionToFabricRef.current = false;
12352
+ }
12353
+ }
12354
+ }
12355
+ } else if (!skipRestoreSelection && activeId && !isActiveTextBeingEdited) {
12356
+ const currentActive = fc.getActiveObject();
12357
+ const currentActiveId = currentActive ? getObjectId(currentActive) : null;
12358
+ if (currentActiveId !== activeId) {
12359
+ const replacement = fc.getObjects().find((o) => getObjectId(o) === activeId) ?? (() => {
12360
+ for (const o of fc.getObjects()) {
12361
+ if (o instanceof fabric__namespace.Group && o.__docuforgeSectionGroup) {
12362
+ const child = o.getObjects().find((c) => getObjectId(c) === activeId);
12363
+ if (child) return child;
12364
+ }
12365
+ }
12366
+ return null;
12367
+ })();
12368
+ const isSectionGroup = sectionGroupIds.has(activeId);
12369
+ if (replacement && !isSectionGroup) {
12370
+ fc.setActiveObject(replacement);
12371
+ replacement.setCoords();
12372
+ fc.requestRenderAll();
12373
+ }
12374
+ }
12375
+ }
12376
+ preserveSelectionAfterTransformIdRef.current = null;
12377
+ preserveActiveSelectionAfterTransformRef.current = null;
11679
12378
  syncTriggeredByPanelRef.current = false;
11680
12379
  };
11681
12380
  if (canvasUpdateVersion !== prevCanvasUpdateVersionRef.current) {
@@ -11826,6 +12525,7 @@ const PageCanvas = react.forwardRef(
11826
12525
  };
11827
12526
  }, [ready, pageId, onReady]);
11828
12527
  react.useEffect(() => {
12528
+ var _a2;
11829
12529
  const fc = fabricRef.current;
11830
12530
  if (!fc || isRebuildingRef.current || !isActive) return;
11831
12531
  if (isTransforming(fc)) return;
@@ -11833,6 +12533,13 @@ const PageCanvas = react.forwardRef(
11833
12533
  if (editLockRef.current) return;
11834
12534
  isSyncingSelectionToFabricRef.current = true;
11835
12535
  const selectedSet = new Set(selectedIds);
12536
+ const pageChildrenForSelection = ((_a2 = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a2.children) ?? [];
12537
+ const selectedGroupSelectionId = selectedIds.find((id) => {
12538
+ const node = findNodeById(pageChildrenForSelection, id);
12539
+ return !!(node && isGroup(node));
12540
+ });
12541
+ const selectedGroupNode = selectedGroupSelectionId ? findNodeById(pageChildrenForSelection, selectedGroupSelectionId) : null;
12542
+ const selectedGroupMemberIds = selectedGroupNode && isGroup(selectedGroupNode) ? new Set(getAllElementIds(selectedGroupNode.children ?? [])) : null;
11836
12543
  const toSelect = [];
11837
12544
  for (const obj of fc.getObjects()) {
11838
12545
  const id = getObjectId(obj);
@@ -11841,10 +12548,14 @@ const PageCanvas = react.forwardRef(
11841
12548
  toSelect.push(obj);
11842
12549
  continue;
11843
12550
  }
12551
+ if (id && (selectedGroupMemberIds == null ? void 0 : selectedGroupMemberIds.has(id))) {
12552
+ toSelect.push(obj);
12553
+ continue;
12554
+ }
11844
12555
  if (obj instanceof fabric__namespace.Group && obj.__docuforgeSectionGroup) {
11845
12556
  for (const child of obj.getObjects()) {
11846
12557
  const childId = getObjectId(child);
11847
- if (childId && selectedSet.has(childId)) toSelect.push(child);
12558
+ if (childId && (selectedSet.has(childId) || (selectedGroupMemberIds == null ? void 0 : selectedGroupMemberIds.has(childId)))) toSelect.push(child);
11848
12559
  }
11849
12560
  }
11850
12561
  }
@@ -11865,6 +12576,15 @@ const PageCanvas = react.forwardRef(
11865
12576
  const active = fc.getActiveObject();
11866
12577
  const sameSelection = active instanceof fabric__namespace.ActiveSelection && active.getObjects().length === toSelect.length && toSelect.every((obj) => active.getObjects().includes(obj));
11867
12578
  if (sameSelection && isFlatGroupSelection) {
12579
+ if (selectedGroupSelectionId && active instanceof fabric__namespace.ActiveSelection) {
12580
+ active.__pixldocsGroupSelection = selectedGroupSelectionId;
12581
+ suppressGroupMemberBordersRef.current = active.getObjects();
12582
+ active.getObjects().forEach((m) => {
12583
+ if (m.__pixldocsOrigHasBorders === void 0) m.__pixldocsOrigHasBorders = m.hasBorders;
12584
+ m.hasBorders = false;
12585
+ });
12586
+ applyWarpAwareSelectionBorders(active);
12587
+ }
11868
12588
  fc.requestRenderAll();
11869
12589
  } else {
11870
12590
  toSelect.forEach((obj) => {
@@ -11872,6 +12592,15 @@ const PageCanvas = react.forwardRef(
11872
12592
  if (objId) justModifiedIdsRef.current.add(objId);
11873
12593
  });
11874
12594
  const selection = new fabric__namespace.ActiveSelection(toSelect, { canvas: fc });
12595
+ if (selectedGroupSelectionId) {
12596
+ selection.__pixldocsGroupSelection = selectedGroupSelectionId;
12597
+ suppressGroupMemberBordersRef.current = toSelect;
12598
+ toSelect.forEach((m) => {
12599
+ if (m.__pixldocsOrigHasBorders === void 0) m.__pixldocsOrigHasBorders = m.hasBorders;
12600
+ m.hasBorders = false;
12601
+ });
12602
+ applyWarpAwareSelectionBorders(selection);
12603
+ }
11875
12604
  fc.setActiveObject(selection);
11876
12605
  if (!isFlatGroupSelection) {
11877
12606
  selection.setCoords();
@@ -11883,13 +12612,25 @@ const PageCanvas = react.forwardRef(
11883
12612
  isSyncingSelectionToFabricRef.current = false;
11884
12613
  });
11885
12614
  }, [selectedIds, isActive, ready, elements]);
12615
+ react.useEffect(() => {
12616
+ const unsub = subscribeShowOriginalTextBounds(() => {
12617
+ const fc = fabricRef.current;
12618
+ if (!fc) return;
12619
+ const active = fc.getActiveObject();
12620
+ if (active instanceof fabric__namespace.ActiveSelection) {
12621
+ applyWarpAwareSelectionBorders(active);
12622
+ }
12623
+ fc.requestRenderAll();
12624
+ });
12625
+ return unsub;
12626
+ }, []);
11886
12627
  const updateFabricObject = (obj, element, skipPositionUpdate = false) => {
11887
- var _a, _b, _c;
12628
+ var _a2, _b, _c;
11888
12629
  const fc = fabricRef.current;
11889
12630
  if (fc && isTransforming(fc)) {
11890
12631
  return;
11891
12632
  }
11892
- const currentPageTree = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (_a = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a.children) ?? [];
12633
+ const currentPageTree = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (_a2 = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a2.children) ?? [];
11893
12634
  const fabricPos = currentPageTree.length > 0 ? (() => {
11894
12635
  const node = findNodeById(currentPageTree, element.id);
11895
12636
  return node ? getAbsoluteBounds(node, currentPageTree) : { left: element.left ?? 0, top: element.top ?? 0 };
@@ -11953,13 +12694,13 @@ const PageCanvas = react.forwardRef(
11953
12694
  hasRotatingPoint: false,
11954
12695
  // Hide rotation handle
11955
12696
  // Scale with zoom so handles stay same visual size (controls drawn in canvas pixel space)
11956
- cornerSize: Math.max(6, Math.round(10 * (fc.getZoom() || 1))),
11957
- borderScaleFactor: fc.getZoom() || 1,
12697
+ cornerSize: Math.max(6, Math.round(8 * (fc.getZoom() || 1))),
12698
+ borderScaleFactor: Math.max(1.25, 1.25 * (fc.getZoom() || 1)),
11958
12699
  transparentCorners: false,
11959
12700
  cornerStyle: "rect",
11960
- cornerColor: "#ffffff",
11961
- cornerStrokeColor: "#4f46e5",
11962
- borderColor: "#4f46e5",
12701
+ cornerColor: SELECTION_PRIMARY,
12702
+ cornerStrokeColor: "#ffffff",
12703
+ borderColor: SELECTION_PRIMARY,
11963
12704
  padding: 0
11964
12705
  };
11965
12706
  if (!skipPositionUpdate) {
@@ -12291,7 +13032,7 @@ const PageCanvas = react.forwardRef(
12291
13032
  if (lines.length > maxLines) {
12292
13033
  const originalText = element.text || "Text";
12293
13034
  const countLines = (testText) => {
12294
- var _a2;
13035
+ var _a3;
12295
13036
  const tb = new fabric__namespace.Textbox(testText, {
12296
13037
  width: rW,
12297
13038
  fontSize,
@@ -12300,7 +13041,7 @@ const PageCanvas = react.forwardRef(
12300
13041
  splitByGrapheme
12301
13042
  });
12302
13043
  tb.initDimensions();
12303
- return ((_a2 = tb.textLines) == null ? void 0 : _a2.length) || 1;
13044
+ return ((_a3 = tb.textLines) == null ? void 0 : _a3.length) || 1;
12304
13045
  };
12305
13046
  let low = 0;
12306
13047
  let high = originalText.length;
@@ -12674,7 +13415,7 @@ const PageCanvas = react.forwardRef(
12674
13415
  return Math.max(min, Math.min(max, v));
12675
13416
  };
12676
13417
  const applyEdgeFadeFrameClipPath = (group, element, frameW, frameH, shape, rxRatio) => {
12677
- var _a, _b, _c;
13418
+ var _a2, _b, _c;
12678
13419
  const fadeElement = element;
12679
13420
  const fadeGroup = group;
12680
13421
  const inputKey = edgeFadeKey(fadeElement);
@@ -12683,7 +13424,7 @@ const PageCanvas = react.forwardRef(
12683
13424
  fadeGroup.__edgeFadeOriginalDrawObject = group.drawObject;
12684
13425
  }
12685
13426
  if (hasFade) {
12686
- if ((_a = group.clipPath) == null ? void 0 : _a.__edgeFadeMask) {
13427
+ if ((_a2 = group.clipPath) == null ? void 0 : _a2.__edgeFadeMask) {
12687
13428
  group.clipPath = void 0;
12688
13429
  updateCoverLayout(group);
12689
13430
  }
@@ -12722,6 +13463,7 @@ const PageCanvas = react.forwardRef(
12722
13463
  ctx.globalCompositeOperation = "destination-out";
12723
13464
  let gradient;
12724
13465
  const eraseAtEdge = 1 - amount;
13466
+ const isFullyFadedAtEdge = amount <= 1e-3;
12725
13467
  const STOPS = 64;
12726
13468
  const gamma = 1 / hardness;
12727
13469
  const addStops = (g) => {
@@ -12738,24 +13480,44 @@ const PageCanvas = react.forwardRef(
12738
13480
  addStops(gradient);
12739
13481
  ctx.fillStyle = gradient;
12740
13482
  ctx.fillRect(x, y, w, band);
13483
+ if (isFullyFadedAtEdge) {
13484
+ ctx.fillStyle = "rgba(0,0,0,1)";
13485
+ const guard = Math.min(2, band);
13486
+ ctx.fillRect(x - 2, y - 2, w + 4, guard + 2);
13487
+ }
12741
13488
  } else if (side === "bottom") {
12742
13489
  const band = Math.max(1, h * size);
12743
13490
  gradient = ctx.createLinearGradient(0, y + h, 0, y + h - band);
12744
13491
  addStops(gradient);
12745
13492
  ctx.fillStyle = gradient;
12746
13493
  ctx.fillRect(x, y + h - band, w, band);
13494
+ if (isFullyFadedAtEdge) {
13495
+ ctx.fillStyle = "rgba(0,0,0,1)";
13496
+ const guard = Math.min(2, band);
13497
+ ctx.fillRect(x - 2, y + h - guard, w + 4, guard + 2);
13498
+ }
12747
13499
  } else if (side === "left") {
12748
13500
  const band = Math.max(1, w * size);
12749
13501
  gradient = ctx.createLinearGradient(x, 0, x + band, 0);
12750
13502
  addStops(gradient);
12751
13503
  ctx.fillStyle = gradient;
12752
13504
  ctx.fillRect(x, y, band, h);
13505
+ if (isFullyFadedAtEdge) {
13506
+ ctx.fillStyle = "rgba(0,0,0,1)";
13507
+ const guard = Math.min(2, band);
13508
+ ctx.fillRect(x - 2, y - 2, guard + 2, h + 4);
13509
+ }
12753
13510
  } else {
12754
13511
  const band = Math.max(1, w * size);
12755
13512
  gradient = ctx.createLinearGradient(x + w, 0, x + w - band, 0);
12756
13513
  addStops(gradient);
12757
13514
  ctx.fillStyle = gradient;
12758
13515
  ctx.fillRect(x + w - band, y, band, h);
13516
+ if (isFullyFadedAtEdge) {
13517
+ ctx.fillStyle = "rgba(0,0,0,1)";
13518
+ const guard = Math.min(2, band);
13519
+ ctx.fillRect(x + w - guard, y - 2, guard + 2, h + 4);
13520
+ }
12759
13521
  }
12760
13522
  ctx.restore();
12761
13523
  };
@@ -12791,7 +13553,7 @@ const PageCanvas = react.forwardRef(
12791
13553
  (_c = group.canvas) == null ? void 0 : _c.requestRenderAll();
12792
13554
  };
12793
13555
  const loadImageAsync2 = async (element, placeholder, fc) => {
12794
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
13556
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
12795
13557
  const imageUrl = element.src || element.imageUrl;
12796
13558
  if (!imageUrl) return;
12797
13559
  const elementId = element.id;
@@ -12821,7 +13583,7 @@ const PageCanvas = react.forwardRef(
12821
13583
  if (!fabricRef.current || !isLatestRequest()) return;
12822
13584
  await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat);
12823
13585
  if (!isLatestRequest()) return;
12824
- const imageFitForFade = element.imageFit || ((_a = element.style) == null ? void 0 : _a.imageFit) || "cover";
13586
+ const imageFitForFade = element.imageFit || ((_a2 = element.style) == null ? void 0 : _a2.imageFit) || "cover";
12825
13587
  const clipShapeForFade = element.clipShape ?? ((_b = element.style) == null ? void 0 : _b.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
12826
13588
  const willUseCropGroupForFade = imageFitForFade !== "fill" || clipShapeForFade && clipShapeForFade !== "none";
12827
13589
  try {
@@ -13080,6 +13842,8 @@ const PageCanvas = react.forwardRef(
13080
13842
  fc.getActiveObjects().map((o) => getObjectId(o)).filter((id) => !!id)
13081
13843
  );
13082
13844
  const wasPlaceholderSelected = activeIdsBeforeReplace.has(elementId);
13845
+ const prevSelectionMembers = activeBeforeReplace instanceof fabric__namespace.ActiveSelection ? activeBeforeReplace.getObjects().slice() : null;
13846
+ const prevSelectionGroupId = prevSelectionMembers ? activeBeforeReplace.__pixldocsGroupSelection : null;
13083
13847
  if (!isLatestRequest()) return;
13084
13848
  const canvasObjects = fc.getObjects();
13085
13849
  const idx = canvasObjects.indexOf(placeholder);
@@ -13097,8 +13861,30 @@ const PageCanvas = react.forwardRef(
13097
13861
  fc.add(finalObject);
13098
13862
  }
13099
13863
  if (wasPlaceholderSelected && allowSelection) {
13100
- fc.setActiveObject(finalObject);
13101
- finalObject.setCoords();
13864
+ if (prevSelectionMembers && prevSelectionMembers.length > 1) {
13865
+ const liveObjects = new Set(fc.getObjects());
13866
+ const swapped = prevSelectionMembers.map((m) => m === placeholder ? finalObject : m).filter((m) => liveObjects.has(m));
13867
+ if (swapped.length > 1) {
13868
+ const selection = new fabric__namespace.ActiveSelection(swapped, { canvas: fc });
13869
+ if (prevSelectionGroupId) {
13870
+ selection.__pixldocsGroupSelection = prevSelectionGroupId;
13871
+ suppressGroupMemberBordersRef.current = swapped;
13872
+ swapped.forEach((m) => {
13873
+ if (m.__pixldocsOrigHasBorders === void 0) {
13874
+ m.__pixldocsOrigHasBorders = m.hasBorders;
13875
+ }
13876
+ m.hasBorders = false;
13877
+ });
13878
+ }
13879
+ fc.setActiveObject(selection);
13880
+ } else {
13881
+ fc.setActiveObject(finalObject);
13882
+ finalObject.setCoords();
13883
+ }
13884
+ } else {
13885
+ fc.setActiveObject(finalObject);
13886
+ finalObject.setCoords();
13887
+ }
13102
13888
  requestAnimationFrame(() => {
13103
13889
  skipSelectionClearOnDiscardRef.current = false;
13104
13890
  });
@@ -13116,10 +13902,10 @@ const PageCanvas = react.forwardRef(
13116
13902
  };
13117
13903
  const handleCanvasClick = react.useCallback(
13118
13904
  (e) => {
13119
- var _a;
13905
+ var _a2;
13120
13906
  if (!isActive || !fabricRef.current) return;
13121
13907
  fabricRef.current;
13122
- const rect = (_a = canvasElRef.current) == null ? void 0 : _a.getBoundingClientRect();
13908
+ const rect = (_a2 = canvasElRef.current) == null ? void 0 : _a2.getBoundingClientRect();
13123
13909
  if (!rect) return;
13124
13910
  const x = e.clientX - rect.left;
13125
13911
  const y = e.clientY - rect.top;
@@ -13326,6 +14112,53 @@ const PageCanvas = react.forwardRef(
13326
14112
  )
13327
14113
  ] })
13328
14114
  }
14115
+ ),
14116
+ sizeLabel && /* @__PURE__ */ jsxRuntime.jsxs(
14117
+ "div",
14118
+ {
14119
+ className: "absolute pointer-events-none flex items-center justify-center rounded-full text-white text-[10px] font-semibold shadow-md",
14120
+ style: {
14121
+ left: sizeLabel.x * zoom,
14122
+ top: sizeLabel.y * zoom,
14123
+ transform: "translate(-50%, 4px)",
14124
+ padding: "2px 6px",
14125
+ backgroundColor: "hsl(256, 80%, 58%)",
14126
+ border: "1px solid rgba(255,255,255,0.9)",
14127
+ fontFamily: "system-ui, -apple-system, sans-serif",
14128
+ lineHeight: 1,
14129
+ whiteSpace: "nowrap"
14130
+ },
14131
+ children: [
14132
+ sizeLabel.width,
14133
+ " × ",
14134
+ sizeLabel.height
14135
+ ]
14136
+ }
14137
+ ),
14138
+ rotationLabel && /* @__PURE__ */ jsxRuntime.jsxs(
14139
+ "div",
14140
+ {
14141
+ className: "absolute pointer-events-none flex items-center gap-[3px] rounded-full text-white text-[10px] font-semibold shadow-md",
14142
+ style: {
14143
+ left: rotationLabel.x * zoom,
14144
+ top: rotationLabel.y * zoom,
14145
+ transform: "translate(-50%, -50%)",
14146
+ padding: "2px 6px",
14147
+ backgroundColor: "hsl(256, 80%, 58%)",
14148
+ border: "1px solid rgba(255,255,255,0.9)",
14149
+ fontFamily: "system-ui, -apple-system, sans-serif",
14150
+ lineHeight: 1,
14151
+ whiteSpace: "nowrap"
14152
+ },
14153
+ children: [
14154
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "9", height: "9", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
14155
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" }),
14156
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 3v5h-5" })
14157
+ ] }),
14158
+ rotationLabel.angle,
14159
+ "°"
14160
+ ]
14161
+ }
13329
14162
  )
13330
14163
  ]
13331
14164
  }
@@ -13371,12 +14204,12 @@ function PreviewCanvas({
13371
14204
  onDynamicFieldClick,
13372
14205
  onReady
13373
14206
  }) {
13374
- var _a, _b, _c, _d, _e;
14207
+ var _a2, _b, _c, _d, _e;
13375
14208
  const canvasRef = react.useRef(null);
13376
14209
  const containerRef = react.useRef(null);
13377
14210
  const [containerWidth, setContainerWidth] = react.useState(0);
13378
14211
  const [hoveredFieldId, setHoveredFieldId] = react.useState(null);
13379
- const page = (_a = config == null ? void 0 : config.pages) == null ? void 0 : _a[pageIndex];
14212
+ const page = (_a2 = config == null ? void 0 : config.pages) == null ? void 0 : _a2[pageIndex];
13380
14213
  const canvasWidth = ((_b = config == null ? void 0 : config.canvas) == null ? void 0 : _b.width) || 612;
13381
14214
  const canvasHeight = ((_c = config == null ? void 0 : config.canvas) == null ? void 0 : _c.height) || 792;
13382
14215
  const elementToFieldMap = react.useMemo(
@@ -13388,8 +14221,8 @@ function PreviewCanvas({
13388
14221
  [elementToFieldMap]
13389
14222
  );
13390
14223
  const laidOutPageChildren = react.useMemo(() => {
13391
- var _a2;
13392
- if (!((_a2 = page == null ? void 0 : page.children) == null ? void 0 : _a2.length)) return [];
14224
+ var _a3;
14225
+ if (!((_a3 = page == null ? void 0 : page.children) == null ? void 0 : _a3.length)) return [];
13393
14226
  const children = JSON.parse(JSON.stringify(page.children));
13394
14227
  const allUpdates = reflowPageFromRoot();
13395
14228
  if (allUpdates.size === 0) return children;
@@ -13427,15 +14260,15 @@ function PreviewCanvas({
13427
14260
  }
13428
14261
  }, [elements]);
13429
14262
  const pageSettings = react.useMemo(() => {
13430
- var _a2, _b2;
14263
+ var _a3, _b2;
13431
14264
  return {
13432
- backgroundColor: ((_a2 = page == null ? void 0 : page.settings) == null ? void 0 : _a2.backgroundColor) || "#ffffff",
14265
+ backgroundColor: ((_a3 = page == null ? void 0 : page.settings) == null ? void 0 : _a3.backgroundColor) || "#ffffff",
13433
14266
  backgroundGradient: (_b2 = page == null ? void 0 : page.settings) == null ? void 0 : _b2.backgroundGradient
13434
14267
  };
13435
14268
  }, [(_d = page == null ? void 0 : page.settings) == null ? void 0 : _d.backgroundColor, (_e = page == null ? void 0 : page.settings) == null ? void 0 : _e.backgroundGradient]);
13436
14269
  const projectSettings = react.useMemo(() => {
13437
- var _a2, _b2, _c2;
13438
- const vars = ((_a2 = config.themeConfig) == null ? void 0 : _a2.variables) || {};
14270
+ var _a3, _b2, _c2;
14271
+ const vars = ((_a3 = config.themeConfig) == null ? void 0 : _a3.variables) || {};
13439
14272
  return {
13440
14273
  showGrid: false,
13441
14274
  snapToGrid: false,
@@ -13467,8 +14300,8 @@ function PreviewCanvas({
13467
14300
  }, [elements, elementToFieldMap]);
13468
14301
  const [actualBounds, setActualBounds] = react.useState(/* @__PURE__ */ new Map());
13469
14302
  const updateBounds = react.useCallback(() => {
13470
- var _a2;
13471
- if ((_a2 = canvasRef.current) == null ? void 0 : _a2.getAllElementBounds) {
14303
+ var _a3;
14304
+ if ((_a3 = canvasRef.current) == null ? void 0 : _a3.getAllElementBounds) {
13472
14305
  const bounds = canvasRef.current.getAllElementBounds();
13473
14306
  setActualBounds(bounds);
13474
14307
  }
@@ -13594,10 +14427,10 @@ const PreviewCanvas$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.def
13594
14427
  PreviewCanvas
13595
14428
  }, Symbol.toStringTag, { value: "Module" }));
13596
14429
  function applyThemeToConfig(config, themeOverrides) {
13597
- var _a, _b, _c;
14430
+ var _a2, _b, _c;
13598
14431
  if (!themeOverrides || Object.keys(themeOverrides).length === 0) return config;
13599
14432
  const cloned = JSON.parse(JSON.stringify(config));
13600
- if ((_a = cloned.themeConfig) == null ? void 0 : _a.variables) {
14433
+ if ((_a2 = cloned.themeConfig) == null ? void 0 : _a2.variables) {
13601
14434
  for (const [key, value] of Object.entries(themeOverrides)) {
13602
14435
  if (cloned.themeConfig.variables[key]) {
13603
14436
  cloned.themeConfig.variables[key].value = value;
@@ -13642,7 +14475,7 @@ function mapFormDefFieldType(t) {
13642
14475
  function formDefSectionsToInferred(schemaSections, repeatableNodeMap) {
13643
14476
  const sections = [];
13644
14477
  function convert(defs, parentId) {
13645
- var _a, _b;
14478
+ var _a2, _b;
13646
14479
  for (const def of defs) {
13647
14480
  const isRepeatable = def.repeatable === true || def.type === "repeatable";
13648
14481
  const defFields = def.fields ?? def.entryFields ?? [];
@@ -13676,7 +14509,7 @@ function formDefSectionsToInferred(schemaSections, repeatableNodeMap) {
13676
14509
  };
13677
14510
  if (treeNodeId) section.treeNodeId = treeNodeId;
13678
14511
  sections.push(section);
13679
- if ((_a = def.children) == null ? void 0 : _a.length) {
14512
+ if ((_a2 = def.children) == null ? void 0 : _a2.length) {
13680
14513
  convert(def.children, def.id);
13681
14514
  }
13682
14515
  } else {
@@ -13791,11 +14624,11 @@ function findRepeatableNodesAndElementContainment(pages) {
13791
14624
  return { repeatableNodes, elementIdToRepeatableNodeId };
13792
14625
  }
13793
14626
  function inferFormSchemaFromTemplate(dynamicFields, fieldGroups, options) {
13794
- var _a;
14627
+ var _a2;
13795
14628
  const sections = [];
13796
14629
  const sortedGroups = [...fieldGroups || []].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
13797
14630
  const fieldIdsInTreeRepeatable = /* @__PURE__ */ new Set();
13798
- if ((_a = options == null ? void 0 : options.pages) == null ? void 0 : _a.length) {
14631
+ if ((_a2 = options == null ? void 0 : options.pages) == null ? void 0 : _a2.length) {
13799
14632
  const { repeatableNodes, elementIdToRepeatableNodeId } = findRepeatableNodesAndElementContainment(options.pages);
13800
14633
  const labelNorm = (s) => String(s).trim().toLowerCase();
13801
14634
  for (let idx = 0; idx < repeatableNodes.length; idx++) {
@@ -14270,29 +15103,29 @@ function setInTree(nodes, elementId, targetProperty, value) {
14270
15103
  return false;
14271
15104
  }
14272
15105
  function collectGroupsByBaseId(pages, baseNodeId) {
14273
- var _a;
15106
+ var _a2;
14274
15107
  const groups = [];
14275
15108
  function collect(children) {
14276
- var _a2;
15109
+ var _a3;
14277
15110
  if (!Array.isArray(children)) return;
14278
15111
  for (const node of children) {
14279
15112
  const base = node.__baseNodeId ?? baseId(node.id);
14280
15113
  if (base === baseNodeId) groups.push(node);
14281
- if (isGroup(node) && ((_a2 = node.children) == null ? void 0 : _a2.length)) collect(node.children);
15114
+ if (isGroup(node) && ((_a3 = node.children) == null ? void 0 : _a3.length)) collect(node.children);
14282
15115
  }
14283
15116
  }
14284
- for (const page of pages) if ((_a = page.children) == null ? void 0 : _a.length) collect(page.children);
15117
+ for (const page of pages) if ((_a2 = page.children) == null ? void 0 : _a2.length) collect(page.children);
14285
15118
  return groups;
14286
15119
  }
14287
15120
  function findElementBySourceIdInSubtree(nodes, sourceId) {
14288
- var _a;
15121
+ var _a2;
14289
15122
  const sourceBase = baseId(sourceId);
14290
15123
  for (const node of nodes) {
14291
15124
  const src = node.__sourceId;
14292
15125
  const nodeId = node.id;
14293
15126
  if (src === sourceId || nodeId === sourceId) return node.id;
14294
15127
  if (sourceBase && baseId(src ?? nodeId) === sourceBase) return node.id;
14295
- if (isGroup(node) && ((_a = node.children) == null ? void 0 : _a.length)) {
15128
+ if (isGroup(node) && ((_a2 = node.children) == null ? void 0 : _a2.length)) {
14296
15129
  const found = findElementBySourceIdInSubtree(node.children, sourceId);
14297
15130
  if (found) return found;
14298
15131
  }
@@ -14300,31 +15133,31 @@ function findElementBySourceIdInSubtree(nodes, sourceId) {
14300
15133
  return void 0;
14301
15134
  }
14302
15135
  function findAllRepeatableElementsBySourceId(pages, baseNodeId, oneBasedIndex, sourceElementId, expectedEntriesPerOccurrence) {
14303
- var _a;
15136
+ var _a2;
14304
15137
  const groups = collectGroupsByBaseId(pages, baseNodeId);
14305
15138
  if (!groups.length) return [];
14306
15139
  const N = Math.max(1, expectedEntriesPerOccurrence ?? groups.length);
14307
15140
  const out = [];
14308
15141
  for (let occStart = 0; occStart < groups.length; occStart += N) {
14309
15142
  const group = groups[occStart + (oneBasedIndex - 1)];
14310
- if (!group || !isGroup(group) || !((_a = group.children) == null ? void 0 : _a.length)) continue;
15143
+ if (!group || !isGroup(group) || !((_a2 = group.children) == null ? void 0 : _a2.length)) continue;
14311
15144
  const found = findElementBySourceIdInSubtree(group.children, sourceElementId) ?? (group.__sourceId === sourceElementId ? group.id : void 0);
14312
15145
  if (found) out.push(found);
14313
15146
  }
14314
15147
  return out;
14315
15148
  }
14316
15149
  function findNestedRepeatableElementBySourceId(pages, parentBaseNodeId, parentPi, childBaseNodeId, childCi, sourceElementId) {
14317
- var _a, _b;
15150
+ var _a2, _b;
14318
15151
  const parentGroups = collectGroupsByBaseId(pages, parentBaseNodeId);
14319
15152
  const parentGroup = parentGroups[parentPi - 1];
14320
- if (!parentGroup || !isGroup(parentGroup) || !((_a = parentGroup.children) == null ? void 0 : _a.length)) return void 0;
15153
+ if (!parentGroup || !isGroup(parentGroup) || !((_a2 = parentGroup.children) == null ? void 0 : _a2.length)) return void 0;
14321
15154
  const childGroups = [];
14322
15155
  function collectChild(children) {
14323
- var _a2;
15156
+ var _a3;
14324
15157
  for (const node of children) {
14325
15158
  const base = node.__baseNodeId ?? baseId(node.id);
14326
15159
  if (base === childBaseNodeId) childGroups.push(node);
14327
- if (isGroup(node) && ((_a2 = node.children) == null ? void 0 : _a2.length)) collectChild(node.children);
15160
+ if (isGroup(node) && ((_a3 = node.children) == null ? void 0 : _a3.length)) collectChild(node.children);
14328
15161
  }
14329
15162
  }
14330
15163
  collectChild(parentGroup.children);
@@ -14361,12 +15194,12 @@ function idPrefix(node) {
14361
15194
  function cloneNodeWithNewIds$1(node, cloneSuffix) {
14362
15195
  const oldToNew = /* @__PURE__ */ new Map();
14363
15196
  function clone(n) {
14364
- var _a;
15197
+ var _a2;
14365
15198
  const newId = cloneSuffix ? `${baseId(n.id)}__c${cloneSuffix}` : generateId(idPrefix(n));
14366
15199
  oldToNew.set(n.id, newId);
14367
15200
  const base = baseId(n.id);
14368
15201
  const withMeta = { ...n, id: newId, __baseNodeId: base, __sourceId: n.id };
14369
- if (isGroup(n) && ((_a = n.children) == null ? void 0 : _a.length)) {
15202
+ if (isGroup(n) && ((_a2 = n.children) == null ? void 0 : _a2.length)) {
14370
15203
  return { ...withMeta, children: n.children.map(clone) };
14371
15204
  }
14372
15205
  return withMeta;
@@ -14376,13 +15209,13 @@ function cloneNodeWithNewIds$1(node, cloneSuffix) {
14376
15209
  return [cloned, oldToNew];
14377
15210
  }
14378
15211
  function getRepeatableFromConfig(pages) {
14379
- var _a;
15212
+ var _a2;
14380
15213
  const result = [];
14381
15214
  function walk(children) {
14382
- var _a2, _b;
15215
+ var _a3, _b;
14383
15216
  if (!children) return;
14384
15217
  for (const node of children) {
14385
- if (isGroup(node) && isVerticalStackLayoutMode(node.layoutMode) && ((_a2 = node.children) == null ? void 0 : _a2.length)) {
15218
+ if (isGroup(node) && isVerticalStackLayoutMode(node.layoutMode) && ((_a3 = node.children) == null ? void 0 : _a3.length)) {
14386
15219
  for (const child of node.children) {
14387
15220
  const rep = child.repeatableSection;
14388
15221
  if (rep == null ? void 0 : rep.label) result.push({ nodeId: child.id, label: rep.label });
@@ -14391,24 +15224,24 @@ function getRepeatableFromConfig(pages) {
14391
15224
  if (isGroup(node) && ((_b = node.children) == null ? void 0 : _b.length)) walk(node.children);
14392
15225
  }
14393
15226
  }
14394
- for (const page of pages) if ((_a = page.children) == null ? void 0 : _a.length) walk(page.children);
15227
+ for (const page of pages) if ((_a2 = page.children) == null ? void 0 : _a2.length) walk(page.children);
14395
15228
  return result;
14396
15229
  }
14397
15230
  function findRepeatableByNodeIds(pages, nodeIds) {
14398
- var _a;
15231
+ var _a2;
14399
15232
  const schemaBaseIds = new Set(nodeIds.map((id) => baseId(id)));
14400
15233
  const result = [];
14401
15234
  const clonePattern = /^(.+)_(\d+)$/;
14402
15235
  const hasRepeatableSection = (n) => {
14403
- var _a2;
14404
- return !!((_a2 = n.repeatableSection) == null ? void 0 : _a2.label);
15236
+ var _a3;
15237
+ return !!((_a3 = n.repeatableSection) == null ? void 0 : _a3.label);
14405
15238
  };
14406
15239
  function walk(children, parentRepeatableBaseId, parentInfo, parentRepeatableEntryIndex) {
14407
- var _a2, _b;
15240
+ var _a3, _b;
14408
15241
  if (!Array.isArray(children)) return;
14409
15242
  for (let i = 0; i < children.length; i++) {
14410
15243
  const node = children[i];
14411
- if (isGroup(node) && isVerticalStackLayoutMode(node.layoutMode) && ((_a2 = node.children) == null ? void 0 : _a2.length)) {
15244
+ if (isGroup(node) && isVerticalStackLayoutMode(node.layoutMode) && ((_a3 = node.children) == null ? void 0 : _a3.length)) {
14412
15245
  const kids = node.children;
14413
15246
  let j = 0;
14414
15247
  while (j < kids.length) {
@@ -14481,22 +15314,22 @@ function findRepeatableByNodeIds(pages, nodeIds) {
14481
15314
  }
14482
15315
  }
14483
15316
  }
14484
- for (const page of pages) if ((_a = page.children) == null ? void 0 : _a.length) walk(page.children);
15317
+ for (const page of pages) if ((_a2 = page.children) == null ? void 0 : _a2.length) walk(page.children);
14485
15318
  return result;
14486
15319
  }
14487
15320
  function findAllTopLevelRepeatableBlocks(pages) {
14488
- var _a;
15321
+ var _a2;
14489
15322
  const result = [];
14490
15323
  const hasRepeatableSection = (n) => {
14491
- var _a2;
14492
- return !!((_a2 = n.repeatableSection) == null ? void 0 : _a2.label);
15324
+ var _a3;
15325
+ return !!((_a3 = n.repeatableSection) == null ? void 0 : _a3.label);
14493
15326
  };
14494
15327
  function walk(children) {
14495
- var _a2;
15328
+ var _a3;
14496
15329
  if (!Array.isArray(children)) return;
14497
15330
  for (let i = 0; i < children.length; i++) {
14498
15331
  const node = children[i];
14499
- if (!isGroup(node) || !((_a2 = node.children) == null ? void 0 : _a2.length)) continue;
15332
+ if (!isGroup(node) || !((_a3 = node.children) == null ? void 0 : _a3.length)) continue;
14500
15333
  if (hasRepeatableSection(node) && !result.some((r) => r.baseNodeId === baseId(node.id))) {
14501
15334
  result.push({
14502
15335
  parentChildren: children,
@@ -14510,7 +15343,7 @@ function findAllTopLevelRepeatableBlocks(pages) {
14510
15343
  walk(node.children);
14511
15344
  }
14512
15345
  }
14513
- for (const page of pages) if ((_a = page.children) == null ? void 0 : _a.length) walk(page.children);
15346
+ for (const page of pages) if ((_a2 = page.children) == null ? void 0 : _a2.length) walk(page.children);
14514
15347
  return result;
14515
15348
  }
14516
15349
  function getRepeatableEntryCount(nodeId, formValues) {
@@ -14536,7 +15369,7 @@ function getNestedRepeatableEntryCount(parentId, parentIndex, childId, formValue
14536
15369
  return Math.max(1, maxIndex);
14537
15370
  }
14538
15371
  function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsFromSchema, repeatableEntryCounts, repeatableNestedEntryCounts, displayFormatMap, repeatablePagesFromSchema) {
14539
- var _a, _b, _c;
15372
+ var _a2, _b, _c;
14540
15373
  const cloned = JSON.parse(JSON.stringify(config));
14541
15374
  if (!cloned.pages) return cloned;
14542
15375
  const dynamicFields = cloned.dynamicFields;
@@ -14570,7 +15403,7 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
14570
15403
  clonedPage.__repeatablePagePrefix = prefix;
14571
15404
  clonedPage.__repeatablePageEntryIndex = i;
14572
15405
  clonedPage.__repeatablePageBaseId = basePageId;
14573
- if ((_a = clonedPage.children) == null ? void 0 : _a.length) {
15406
+ if ((_a2 = clonedPage.children) == null ? void 0 : _a2.length) {
14574
15407
  const suffix = `${basePageId}_p${i}`;
14575
15408
  const reidChildren = (nodes) => nodes.map((n) => {
14576
15409
  const [reclone] = cloneNodeWithNewIds$1(n, suffix);
@@ -14616,20 +15449,20 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
14616
15449
  return item == null ? void 0 : item.entryCount;
14617
15450
  };
14618
15451
  const entryFilterFromList = (baseNodeId) => {
14619
- var _a2;
15452
+ var _a3;
14620
15453
  const item = repeatableList.find((r) => baseId(r.nodeId) === baseNodeId || r.nodeId === baseNodeId);
14621
15454
  const filter = item == null ? void 0 : item.entryFilter;
14622
- return (filter == null ? void 0 : filter.mode) === "range" && ((_a2 = filter.range) == null ? void 0 : _a2.trim()) ? filter : void 0;
15455
+ return (filter == null ? void 0 : filter.mode) === "range" && ((_a3 = filter.range) == null ? void 0 : _a3.trim()) ? filter : void 0;
14623
15456
  };
14624
15457
  const entryMetaFromList = (baseNodeId) => {
14625
15458
  const item = repeatableList.find((r) => baseId(r.nodeId) === baseNodeId || r.nodeId === baseNodeId);
14626
15459
  return item == null ? void 0 : item.entryMeta;
14627
15460
  };
14628
15461
  const nestedEntryMetaFromList = (parentBaseNodeId, parentIndex1Based, childBaseNodeId) => {
14629
- var _a2;
15462
+ var _a3;
14630
15463
  for (const { parentBaseId, childBaseId } of getNestedBasePairs(parentBaseNodeId, childBaseNodeId)) {
14631
15464
  const item = repeatableList.find((r) => baseId(r.nodeId) === childBaseId || r.nodeId === childBaseId);
14632
- const meta = (_a2 = item == null ? void 0 : item.nestedEntryMeta) == null ? void 0 : _a2[`${parentBaseId}_${parentIndex1Based}_${childBaseId}`];
15465
+ const meta = (_a3 = item == null ? void 0 : item.nestedEntryMeta) == null ? void 0 : _a3[`${parentBaseId}_${parentIndex1Based}_${childBaseId}`];
14633
15466
  if (meta == null ? void 0 : meta.length) return meta;
14634
15467
  }
14635
15468
  return entryMetaFromList(childBaseNodeId);
@@ -14757,12 +15590,12 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
14757
15590
  for (const [childBaseNodeId, blocks] of byChildBase) {
14758
15591
  const parentBaseNodeId = nestedChildToParent.get(childBaseNodeId);
14759
15592
  blocks.forEach((block, parentIndex0) => {
14760
- var _a2;
15593
+ var _a3;
14761
15594
  const parentIndex1Based = block.parentEntryIndex ?? parentIndex0 + 1;
14762
15595
  const { parentChildren, startIndex, count, node, baseNodeId } = block;
14763
15596
  const N = getNestedCountForBasePair(parentBaseNodeId, parentIndex1Based, baseNodeId);
14764
15597
  const phase1Map = phase1NewToOriginal.get(`${parentBaseNodeId}_${parentIndex1Based}`);
14765
- const nestedEntryFilter = ((_a2 = node.repeatableSection) == null ? void 0 : _a2.entryFilter) ?? entryFilterFromList(baseNodeId);
15598
+ const nestedEntryFilter = ((_a3 = node.repeatableSection) == null ? void 0 : _a3.entryFilter) ?? entryFilterFromList(baseNodeId);
14766
15599
  let nestedEntryIndices;
14767
15600
  if (nestedEntryFilter && nestedEntryFilter.mode === "range" && nestedEntryFilter.range) {
14768
15601
  const parsed = parseEntryRange(nestedEntryFilter.range, N, nestedEntryMetaFromList(parentBaseNodeId, parentIndex1Based, baseNodeId));
@@ -14901,7 +15734,7 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
14901
15734
  return void 0;
14902
15735
  }
14903
15736
  const applyValue = (elementId, targetProperty, value, fieldKey) => {
14904
- var _a2;
15737
+ var _a3;
14905
15738
  const isTextLike = targetProperty === "text" || targetProperty === "content";
14906
15739
  if (value === void 0 || value === null) {
14907
15740
  return false;
@@ -14926,7 +15759,7 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
14926
15759
  }
14927
15760
  }
14928
15761
  if (elementId === PAGE_BACKGROUND_ELEMENT_ID && targetProperty === "backgroundColor" && typeof effectiveValue === "string") {
14929
- if ((_a2 = pages[0]) == null ? void 0 : _a2.settings) {
15762
+ if ((_a3 = pages[0]) == null ? void 0 : _a3.settings) {
14930
15763
  pages[0].settings.backgroundColor = effectiveValue;
14931
15764
  return true;
14932
15765
  }
@@ -15060,14 +15893,14 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
15060
15893
  }
15061
15894
  if ((repeatablePagesFromSchema == null ? void 0 : repeatablePagesFromSchema.length) && (dynamicFields == null ? void 0 : dynamicFields.length)) {
15062
15895
  const findInPage = (page, originalId) => {
15063
- var _a2;
15064
- if (!((_a2 = page.children) == null ? void 0 : _a2.length)) return void 0;
15896
+ var _a3;
15897
+ if (!((_a3 = page.children) == null ? void 0 : _a3.length)) return void 0;
15065
15898
  const findIn = (nodes) => {
15066
- var _a3;
15899
+ var _a4;
15067
15900
  for (const n of nodes) {
15068
15901
  const src = n.__sourceId;
15069
15902
  if (n.id === originalId || src === originalId || baseId(n.id) === baseId(originalId)) return n.id;
15070
- if (isGroup(n) && ((_a3 = n.children) == null ? void 0 : _a3.length)) {
15903
+ if (isGroup(n) && ((_a4 = n.children) == null ? void 0 : _a4.length)) {
15071
15904
  const f = findIn(n.children);
15072
15905
  if (f) return f;
15073
15906
  }
@@ -15163,24 +15996,24 @@ function findFlowStack(pageChildren) {
15163
15996
  return all.length > 0 ? all[0] : null;
15164
15997
  }
15165
15998
  function findAllFlowStacks(pageChildren) {
15166
- var _a;
15999
+ var _a2;
15167
16000
  const result = [];
15168
16001
  for (const node of pageChildren) {
15169
16002
  if (!isGroup(node)) continue;
15170
16003
  const g = node;
15171
- if (!isVerticalStackLayoutMode(g.layoutMode) || !((_a = g.children) == null ? void 0 : _a.length)) continue;
16004
+ if (!isVerticalStackLayoutMode(g.layoutMode) || !((_a2 = g.children) == null ? void 0 : _a2.length)) continue;
15172
16005
  if (g.children.some(hasBaseNodeId)) result.push(g);
15173
16006
  }
15174
16007
  return result;
15175
16008
  }
15176
16009
  function findNestedFlowStack(entry) {
15177
- var _a, _b;
16010
+ var _a2, _b;
15178
16011
  const queue = [...entry.children ?? []];
15179
16012
  while (queue.length > 0) {
15180
16013
  const node = queue.shift();
15181
16014
  if (!isGroup(node)) continue;
15182
16015
  const g = node;
15183
- const hasRepeatableChildren = ((_a = g.children) == null ? void 0 : _a.length) && (g.children.some(hasBaseNodeId) || g.children.some((c) => isGroup(c)));
16016
+ const hasRepeatableChildren = ((_a2 = g.children) == null ? void 0 : _a2.length) && (g.children.some(hasBaseNodeId) || g.children.some((c) => isGroup(c)));
15184
16017
  if (isVerticalStackLayoutMode(g.layoutMode) && hasRepeatableChildren) return g;
15185
16018
  if ((_b = g.children) == null ? void 0 : _b.length) queue.push(...g.children);
15186
16019
  }
@@ -15201,8 +16034,8 @@ function replaceNestedFlowStackChildren(entry, nestedStackId, newChildren, setTo
15201
16034
  return walk(entry);
15202
16035
  }
15203
16036
  function splitEntryAtNested(entry, pageChildren, contentBottom) {
15204
- var _a;
15205
- const entryIsNestedStack = isVerticalStackLayoutMode(entry.layoutMode) && ((_a = entry.children) == null ? void 0 : _a.length) && (entry.children.some(hasBaseNodeId) || entry.children.some((c) => isGroup(c)));
16037
+ var _a2;
16038
+ const entryIsNestedStack = isVerticalStackLayoutMode(entry.layoutMode) && ((_a2 = entry.children) == null ? void 0 : _a2.length) && (entry.children.some(hasBaseNodeId) || entry.children.some((c) => isGroup(c)));
15206
16039
  const nested = entryIsNestedStack ? entry : findNestedFlowStack(entry);
15207
16040
  if (!nested) return { stayVersion: null, overflowVersion: entry };
15208
16041
  const nestedKids = nested.children ?? [];
@@ -15313,8 +16146,8 @@ function splitNestedForOverflow(flowStack, stayChildren, overflowChildren, overf
15313
16146
  return { stayChildren: newStay, overflowChildren: newOverflow };
15314
16147
  }
15315
16148
  function paginateSinglePage(sourcePage, pageOffsetIndex) {
15316
- var _a, _b, _c, _d, _e, _f;
15317
- const contentTop = (_a = sourcePage.settings) == null ? void 0 : _a.contentTop;
16149
+ var _a2, _b, _c, _d, _e, _f;
16150
+ const contentTop = (_a2 = sourcePage.settings) == null ? void 0 : _a2.contentTop;
15318
16151
  const contentBottom = (_b = sourcePage.settings) == null ? void 0 : _b.contentBottom;
15319
16152
  if (contentTop == null || contentBottom == null || contentBottom <= contentTop) {
15320
16153
  return [sourcePage];
@@ -16179,10 +17012,10 @@ const resolveBestRegisteredVariant = (family, weight, italic) => {
16179
17012
  return null;
16180
17013
  };
16181
17014
  const doesVariantSupportChar = (family, weight, italic, char) => {
16182
- var _a;
17015
+ var _a2;
16183
17016
  const cp = char.codePointAt(0);
16184
17017
  if (cp == null) return false;
16185
- return ((_a = registeredVariantCoverage.get(variantKey(family, weight, italic))) == null ? void 0 : _a.has(cp)) === true;
17018
+ return ((_a2 = registeredVariantCoverage.get(variantKey(family, weight, italic))) == null ? void 0 : _a2.has(cp)) === true;
16186
17019
  };
16187
17020
  function bytesToBase64(bytes) {
16188
17021
  let binary = "";
@@ -16190,9 +17023,9 @@ function bytesToBase64(bytes) {
16190
17023
  return btoa(binary);
16191
17024
  }
16192
17025
  function getFontProxyUrl() {
16193
- var _a;
17026
+ var _a2;
16194
17027
  const viteUrl = (__vite_import_meta_env__ == null ? void 0 : __vite_import_meta_env__.VITE_SUPABASE_URL) || "";
16195
- const runtimeUrl = typeof globalThis !== "undefined" ? ((_a = globalThis.__CONFIG__) == null ? void 0 : _a.supabaseUrl) || globalThis.__PIXLDOCS_SUPABASE_URL || "" : "";
17028
+ const runtimeUrl = typeof globalThis !== "undefined" ? ((_a2 = globalThis.__CONFIG__) == null ? void 0 : _a2.supabaseUrl) || globalThis.__PIXLDOCS_SUPABASE_URL || "" : "";
16196
17029
  const baseUrl = (viteUrl || runtimeUrl || "").replace(/\/$/, "");
16197
17030
  return baseUrl ? `${baseUrl}/functions/v1/font-proxy` : null;
16198
17031
  }
@@ -16505,20 +17338,20 @@ function splitIntoRuns(text, mainSupportsChar) {
16505
17338
  return runs;
16506
17339
  }
16507
17340
  function rewriteSvgFontsForJsPDF(svgStr) {
16508
- var _a, _b;
17341
+ var _a2, _b;
16509
17342
  const parser = new DOMParser();
16510
17343
  const doc = parser.parseFromString(svgStr, "image/svg+xml");
16511
17344
  const allTextEls = Array.from(doc.querySelectorAll("text, tspan, textPath"));
16512
17345
  const readStyleToken = (style, prop) => {
16513
- var _a2;
17346
+ var _a3;
16514
17347
  const match = style.match(new RegExp(`${prop}\\s*:\\s*([^;]+)`, "i"));
16515
- return ((_a2 = match == null ? void 0 : match[1]) == null ? void 0 : _a2.trim()) || null;
17348
+ return ((_a3 = match == null ? void 0 : match[1]) == null ? void 0 : _a3.trim()) || null;
16516
17349
  };
16517
17350
  const resolveInheritedValue = (el, attr, styleProp = attr) => {
16518
- var _a2;
17351
+ var _a3;
16519
17352
  let current = el;
16520
17353
  while (current) {
16521
- const attrVal = (_a2 = current.getAttribute(attr)) == null ? void 0 : _a2.trim();
17354
+ const attrVal = (_a3 = current.getAttribute(attr)) == null ? void 0 : _a3.trim();
16522
17355
  if (attrVal) return attrVal;
16523
17356
  const styleVal = readStyleToken(current.getAttribute("style") || "", styleProp);
16524
17357
  if (styleVal) return styleVal;
@@ -16558,7 +17391,7 @@ function rewriteSvgFontsForJsPDF(svgStr) {
16558
17391
  const inlineStyle = el.getAttribute("style") || "";
16559
17392
  const rawFf = resolveInheritedValue(el, "font-family");
16560
17393
  if (!rawFf) continue;
16561
- const clean = (_a = rawFf.split(",")[0]) == null ? void 0 : _a.replace(/['"]/g, "").trim();
17394
+ const clean = (_a2 = rawFf.split(",")[0]) == null ? void 0 : _a2.replace(/['"]/g, "").trim();
16562
17395
  if (!isFontAvailable(clean) && !isFamilyEmbedded(clean)) continue;
16563
17396
  const weightRaw = resolveInheritedValue(el, "font-weight") || "400";
16564
17397
  const styleRaw = resolveInheritedValue(el, "font-style") || "normal";
@@ -16706,20 +17539,20 @@ function extractFontFamiliesFromSvgs(svgs) {
16706
17539
  return families;
16707
17540
  }
16708
17541
  async function embedFontVariantsFromSvg(pdf, svgStr, fontBaseUrl) {
16709
- var _a;
17542
+ var _a2;
16710
17543
  const parser = new DOMParser();
16711
17544
  const doc = parser.parseFromString(svgStr, "image/svg+xml");
16712
17545
  const textEls = Array.from(doc.querySelectorAll("text, tspan, textPath"));
16713
17546
  const readStyleToken = (style, prop) => {
16714
- var _a2;
17547
+ var _a3;
16715
17548
  const m = style.match(new RegExp(`${prop}\\s*:\\s*([^;]+)`, "i"));
16716
- return ((_a2 = m == null ? void 0 : m[1]) == null ? void 0 : _a2.trim()) || null;
17549
+ return ((_a3 = m == null ? void 0 : m[1]) == null ? void 0 : _a3.trim()) || null;
16717
17550
  };
16718
17551
  const resolveInherited = (el, attr, styleProp = attr) => {
16719
- var _a2;
17552
+ var _a3;
16720
17553
  let cur = el;
16721
17554
  while (cur) {
16722
- const a = (_a2 = cur.getAttribute(attr)) == null ? void 0 : _a2.trim();
17555
+ const a = (_a3 = cur.getAttribute(attr)) == null ? void 0 : _a3.trim();
16723
17556
  if (a) return a;
16724
17557
  const s = readStyleToken(cur.getAttribute("style") || "", styleProp);
16725
17558
  if (s) return s;
@@ -16741,7 +17574,7 @@ async function embedFontVariantsFromSvg(pdf, svgStr, fontBaseUrl) {
16741
17574
  for (const el of textEls) {
16742
17575
  const rawFf = resolveInherited(el, "font-family");
16743
17576
  if (!rawFf) continue;
16744
- const family = (_a = rawFf.split(",")[0]) == null ? void 0 : _a.replace(/['"]/g, "").trim();
17577
+ const family = (_a2 = rawFf.split(",")[0]) == null ? void 0 : _a2.replace(/['"]/g, "").trim();
16745
17578
  if (!family) continue;
16746
17579
  const weight = resolveFontWeight(parseWeight(resolveInherited(el, "font-weight") || "400"));
16747
17580
  const italic = /italic|oblique/i.test(resolveInherited(el, "font-style") || "normal");
@@ -16920,9 +17753,9 @@ function appendDataUriFontFaceRule(family, weight, style, dataUri) {
16920
17753
  styleEl.appendChild(document.createTextNode(cssText));
16921
17754
  }
16922
17755
  function resolveHarnessFontProxyUrl() {
16923
- var _a, _b;
17756
+ var _a2, _b;
16924
17757
  try {
16925
- const runtimeBase = typeof window !== "undefined" && (window.__PIXLDOCS_SUPABASE_URL || ((_a = window.__CONFIG__) == null ? void 0 : _a.supabaseUrl)) || typeof globalThis !== "undefined" && (globalThis.__PIXLDOCS_SUPABASE_URL || ((_b = globalThis.__CONFIG__) == null ? void 0 : _b.supabaseUrl)) || "";
17758
+ const runtimeBase = typeof window !== "undefined" && (window.__PIXLDOCS_SUPABASE_URL || ((_a2 = window.__CONFIG__) == null ? void 0 : _a2.supabaseUrl)) || typeof globalThis !== "undefined" && (globalThis.__PIXLDOCS_SUPABASE_URL || ((_b = globalThis.__CONFIG__) == null ? void 0 : _b.supabaseUrl)) || "";
16926
17759
  const base = String(runtimeBase || "").replace(/\/$/, "");
16927
17760
  return base ? `${base}/functions/v1/font-proxy` : "";
16928
17761
  } catch {
@@ -17083,16 +17916,16 @@ async function loadGoogleFontCSS(rawFontFamily) {
17083
17916
  loadingPromises.delete(fontFamily);
17084
17917
  }
17085
17918
  function collectFontsFromConfig(config) {
17086
- var _a;
17919
+ var _a2;
17087
17920
  const fonts = /* @__PURE__ */ new Set();
17088
17921
  fonts.add("Open Sans");
17089
17922
  fonts.add("Hind");
17090
17923
  function walk(nodes) {
17091
- var _a2;
17924
+ var _a3;
17092
17925
  if (!nodes) return;
17093
17926
  for (const node of nodes) {
17094
17927
  if (node.fontFamily) fonts.add(normalizeFontFamily(node.fontFamily));
17095
- if ((_a2 = node.smartProps) == null ? void 0 : _a2.fontFamily) fonts.add(normalizeFontFamily(node.smartProps.fontFamily));
17928
+ if ((_a3 = node.smartProps) == null ? void 0 : _a3.fontFamily) fonts.add(normalizeFontFamily(node.smartProps.fontFamily));
17096
17929
  if (node.styles && Array.isArray(node.styles)) {
17097
17930
  for (const lineStyle of node.styles) {
17098
17931
  if (lineStyle && typeof lineStyle === "object") {
@@ -17108,7 +17941,7 @@ function collectFontsFromConfig(config) {
17108
17941
  for (const page of config.pages || []) {
17109
17942
  walk(page.children || []);
17110
17943
  }
17111
- if ((_a = config.themeConfig) == null ? void 0 : _a.variables) {
17944
+ if ((_a2 = config.themeConfig) == null ? void 0 : _a2.variables) {
17112
17945
  for (const def of Object.values(config.themeConfig.variables)) {
17113
17946
  if (def.value && typeof def.value === "string" && !def.value.startsWith("#") && !def.value.startsWith("rgb")) {
17114
17947
  if (def.label && /font/i.test(def.label)) {
@@ -17120,7 +17953,7 @@ function collectFontsFromConfig(config) {
17120
17953
  return fonts;
17121
17954
  }
17122
17955
  function collectFontDescriptorsFromConfig(config, includeCommonTextVariants = true) {
17123
- var _a;
17956
+ var _a2;
17124
17957
  const seen = /* @__PURE__ */ new Set();
17125
17958
  const descriptors = [];
17126
17959
  function add(family, weight, style) {
@@ -17134,7 +17967,7 @@ function collectFontDescriptorsFromConfig(config, includeCommonTextVariants = tr
17134
17967
  descriptors.push({ family: f, weight: w, style: s });
17135
17968
  }
17136
17969
  function walk(nodes) {
17137
- var _a2;
17970
+ var _a3;
17138
17971
  if (!nodes) return;
17139
17972
  for (const node of nodes) {
17140
17973
  if (node.fontFamily) {
@@ -17162,7 +17995,7 @@ function collectFontDescriptorsFromConfig(config, includeCommonTextVariants = tr
17162
17995
  }
17163
17996
  }
17164
17997
  }
17165
- if ((_a2 = node.smartProps) == null ? void 0 : _a2.fontFamily) {
17998
+ if ((_a3 = node.smartProps) == null ? void 0 : _a3.fontFamily) {
17166
17999
  add(node.smartProps.fontFamily, node.smartProps.fontWeight, node.smartProps.fontStyle);
17167
18000
  }
17168
18001
  if (node.styles) {
@@ -17186,7 +18019,7 @@ function collectFontDescriptorsFromConfig(config, includeCommonTextVariants = tr
17186
18019
  for (const page of config.pages || []) {
17187
18020
  walk(page.children || []);
17188
18021
  }
17189
- if ((_a = config.themeConfig) == null ? void 0 : _a.variables) {
18022
+ if ((_a2 = config.themeConfig) == null ? void 0 : _a2.variables) {
17190
18023
  for (const def of Object.values(config.themeConfig.variables)) {
17191
18024
  if (def.value && typeof def.value === "string" && !def.value.startsWith("#") && !def.value.startsWith("rgb")) {
17192
18025
  if (def.label && /font/i.test(def.label)) {
@@ -17223,8 +18056,8 @@ async function ensureFontsForResolvedConfig(config) {
17223
18056
  }
17224
18057
  }
17225
18058
  function configHasAutoShrinkText$1(config) {
17226
- var _a;
17227
- if (!((_a = config == null ? void 0 : config.pages) == null ? void 0 : _a.length)) return false;
18059
+ var _a2;
18060
+ if (!((_a2 = config == null ? void 0 : config.pages) == null ? void 0 : _a2.length)) return false;
17228
18061
  const walk = (nodes) => {
17229
18062
  for (const node of nodes || []) {
17230
18063
  if (!node) continue;
@@ -17357,8 +18190,8 @@ function mergeRepeatableEntryMeta(target, metaSource, sections) {
17357
18190
  return changed ? next : target;
17358
18191
  }
17359
18192
  function buildRepeatablePagesInputForApply(schema, sectionState) {
17360
- var _a;
17361
- if (!((_a = schema == null ? void 0 : schema.repeatablePages) == null ? void 0 : _a.length)) return [];
18193
+ var _a2;
18194
+ if (!((_a2 = schema == null ? void 0 : schema.repeatablePages) == null ? void 0 : _a2.length)) return [];
17362
18195
  const normalizeTemplateKeyPrefix = (prefix) => {
17363
18196
  if (!prefix || typeof prefix !== "string") return "";
17364
18197
  return prefix.replace(/^field_/, "");
@@ -17584,7 +18417,7 @@ async function resolveTemplateData(options) {
17584
18417
  };
17585
18418
  }
17586
18419
  async function resolveFromForm(options) {
17587
- var _a, _b, _c;
18420
+ var _a2, _b, _c;
17588
18421
  const { templateId, formSchemaId, sectionState, flatFormData: directFlatFormData, themeId, supabaseUrl, supabaseAnonKey, prefetched } = options;
17589
18422
  const hasSectionStateInput = !!sectionState && Object.keys(sectionState).length > 0;
17590
18423
  if (!formSchemaId && !hasSectionStateInput) {
@@ -17629,7 +18462,7 @@ async function resolveFromForm(options) {
17629
18462
  let inferredSections;
17630
18463
  if (schemaSections == null ? void 0 : schemaSections.length) {
17631
18464
  inferredSections = formDefSectionsToInferred(schemaSections, repeatableNodeMap);
17632
- } else if ((_a = templateConfig.dynamicFields) == null ? void 0 : _a.length) {
18465
+ } else if ((_a2 = templateConfig.dynamicFields) == null ? void 0 : _a2.length) {
17633
18466
  const groups = templateConfig.fieldGroups || [];
17634
18467
  inferredSections = inferFormSchemaFromTemplate(
17635
18468
  templateConfig.dynamicFields,
@@ -17817,9 +18650,9 @@ function themeBaseId(id) {
17817
18650
  return out;
17818
18651
  }
17819
18652
  function applyThemeVariantToConfig(config, themeConfig, themeId) {
17820
- var _a, _b, _c, _d;
18653
+ var _a2, _b, _c, _d;
17821
18654
  if (!themeConfig) return config;
17822
- const variant = themeId && themeId !== "default" ? (_a = themeConfig.variants) == null ? void 0 : _a.find((v) => v.id === themeId) : null;
18655
+ const variant = themeId && themeId !== "default" ? (_a2 = themeConfig.variants) == null ? void 0 : _a2.find((v) => v.id === themeId) : null;
17823
18656
  const shouldApplyDefaults = !variant && ((_b = themeConfig.properties) == null ? void 0 : _b.length);
17824
18657
  if (!variant && !shouldApplyDefaults) return config;
17825
18658
  if (!((_c = themeConfig.properties) == null ? void 0 : _c.length)) return config;
@@ -17841,8 +18674,8 @@ function applyThemeVariantToConfig(config, themeConfig, themeId) {
17841
18674
  if (stopMatch) {
17842
18675
  const stopIndex = parseInt(stopMatch[1], 10);
17843
18676
  result.pages.forEach((p) => {
17844
- var _a2, _b2;
17845
- if ((_b2 = (_a2 = p.settings.backgroundGradient) == null ? void 0 : _a2.stops) == null ? void 0 : _b2[stopIndex]) {
18677
+ var _a3, _b2;
18678
+ if ((_b2 = (_a3 = p.settings.backgroundGradient) == null ? void 0 : _a3.stops) == null ? void 0 : _b2[stopIndex]) {
17846
18679
  p.settings.backgroundGradient = {
17847
18680
  ...p.settings.backgroundGradient,
17848
18681
  stops: p.settings.backgroundGradient.stops.map(
@@ -17919,7 +18752,7 @@ function normalizeLayoutModes(config) {
17919
18752
  }
17920
18753
  }
17921
18754
  function paintRepeatableSections(config, repeatableSections, formSchema) {
17922
- var _a, _b;
18755
+ var _a2, _b;
17923
18756
  const pages = config.pages ?? [];
17924
18757
  const entryFilters = (formSchema == null ? void 0 : formSchema.entryFilters) ?? [];
17925
18758
  const entryFilterBases = new Set(entryFilters.map((f) => baseId(f.nodeId)));
@@ -17947,7 +18780,7 @@ function paintRepeatableSections(config, repeatableSections, formSchema) {
17947
18780
  return painted;
17948
18781
  }
17949
18782
  for (const section of repeatableSections) {
17950
- const inlineRange = ((_a = section.entryFilter) == null ? void 0 : _a.mode) === "range" ? (_b = section.entryFilter.range) == null ? void 0 : _b.trim() : void 0;
18783
+ const inlineRange = ((_a2 = section.entryFilter) == null ? void 0 : _a2.mode) === "range" ? (_b = section.entryFilter.range) == null ? void 0 : _b.trim() : void 0;
17951
18784
  const shouldUseInlineFilter = !!inlineRange && !entryFilterBases.has(baseId(section.nodeId));
17952
18785
  const payload = { label: section.label };
17953
18786
  if (section.minEntries !== void 0) payload.minEntries = section.minEntries;
@@ -17960,9 +18793,9 @@ function paintRepeatableSections(config, repeatableSections, formSchema) {
17960
18793
  if (entryFilters.length) {
17961
18794
  const occurrencesByBase = /* @__PURE__ */ new Map();
17962
18795
  const collect = (nodes) => {
17963
- var _a2;
18796
+ var _a3;
17964
18797
  for (const node of nodes ?? []) {
17965
- if ((_a2 = node.repeatableSection) == null ? void 0 : _a2.label) {
18798
+ if ((_a3 = node.repeatableSection) == null ? void 0 : _a3.label) {
17966
18799
  const base = baseId(node.id);
17967
18800
  if (!occurrencesByBase.has(base)) occurrencesByBase.set(base, []);
17968
18801
  occurrencesByBase.get(base).push(node);
@@ -17983,7 +18816,7 @@ function paintRepeatableSections(config, repeatableSections, formSchema) {
17983
18816
  }
17984
18817
  }
17985
18818
  async function getTemplateForm(options) {
17986
- var _a, _b;
18819
+ var _a2, _b;
17987
18820
  const { templateId, supabaseUrl, supabaseAnonKey } = options;
17988
18821
  if (!supabaseUrl || !supabaseAnonKey) {
17989
18822
  throw new Error("[getTemplateForm] supabaseUrl and supabaseAnonKey are required");
@@ -18023,7 +18856,7 @@ async function getTemplateForm(options) {
18023
18856
  let sections;
18024
18857
  if (schemaSections == null ? void 0 : schemaSections.length) {
18025
18858
  sections = formDefSectionsToInferred(schemaSections, repeatableNodeMap);
18026
- } else if ((_a = templateConfig.dynamicFields) == null ? void 0 : _a.length) {
18859
+ } else if ((_a2 = templateConfig.dynamicFields) == null ? void 0 : _a2.length) {
18027
18860
  sections = inferFormSchemaFromTemplate(
18028
18861
  templateConfig.dynamicFields,
18029
18862
  templateConfig.fieldGroups || [],
@@ -18301,28 +19134,28 @@ const previewBlur = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineP
18301
19134
  }, Symbol.toStringTag, { value: "Module" }));
18302
19135
  const PREVIEW_DEBUG_PREFIX = "[canvas-renderer][preview-debug]";
18303
19136
  function computeFontSignature(config) {
18304
- var _a;
18305
- if (!((_a = config == null ? void 0 : config.pages) == null ? void 0 : _a.length)) return "";
19137
+ var _a2;
19138
+ if (!((_a2 = config == null ? void 0 : config.pages) == null ? void 0 : _a2.length)) return "";
18306
19139
  const fams = /* @__PURE__ */ new Set();
18307
19140
  const walk = (nodes) => {
18308
- var _a2;
19141
+ var _a3;
18309
19142
  for (const node of nodes || []) {
18310
19143
  if (node == null ? void 0 : node.fontFamily) fams.add(String(node.fontFamily));
18311
- if ((_a2 = node == null ? void 0 : node.children) == null ? void 0 : _a2.length) walk(node.children);
19144
+ if ((_a3 = node == null ? void 0 : node.children) == null ? void 0 : _a3.length) walk(node.children);
18312
19145
  }
18313
19146
  };
18314
19147
  for (const page of config.pages) walk(page.children || []);
18315
19148
  return Array.from(fams).sort().join("|");
18316
19149
  }
18317
19150
  function countUnderlinedNodes(config) {
18318
- var _a;
18319
- if (!((_a = config == null ? void 0 : config.pages) == null ? void 0 : _a.length)) return 0;
19151
+ var _a2;
19152
+ if (!((_a2 = config == null ? void 0 : config.pages) == null ? void 0 : _a2.length)) return 0;
18320
19153
  let count = 0;
18321
19154
  const walk = (nodes) => {
18322
- var _a2;
19155
+ var _a3;
18323
19156
  for (const node of nodes || []) {
18324
19157
  if (node == null ? void 0 : node.underline) count += 1;
18325
- if ((_a2 = node == null ? void 0 : node.children) == null ? void 0 : _a2.length) walk(node.children);
19158
+ if ((_a3 = node == null ? void 0 : node.children) == null ? void 0 : _a3.length) walk(node.children);
18326
19159
  }
18327
19160
  };
18328
19161
  for (const page of config.pages) walk(page.children || []);
@@ -18354,8 +19187,8 @@ function collectBlurBounds(node, parentLeft, parentTop, inheritedBlur, extraBase
18354
19187
  out.push({ left: absLeft, top: absTop, width: w, height: h });
18355
19188
  }
18356
19189
  function computeFrostedBoundsForPage(config, pageIndex, extraBaseIds, extraExactIds) {
18357
- var _a;
18358
- const page = (_a = config == null ? void 0 : config.pages) == null ? void 0 : _a[pageIndex];
19190
+ var _a2;
19191
+ const page = (_a2 = config == null ? void 0 : config.pages) == null ? void 0 : _a2[pageIndex];
18359
19192
  const children = (page == null ? void 0 : page.children) || (page == null ? void 0 : page.elements);
18360
19193
  if (!Array.isArray(children)) return [];
18361
19194
  const out = [];
@@ -18364,7 +19197,7 @@ function computeFrostedBoundsForPage(config, pageIndex, extraBaseIds, extraExact
18364
19197
  return out;
18365
19198
  }
18366
19199
  function PixldocsPreview(props) {
18367
- var _a, _b;
19200
+ var _a2, _b;
18368
19201
  const {
18369
19202
  pageIndex = 0,
18370
19203
  zoom = 1,
@@ -18375,6 +19208,7 @@ function PixldocsPreview(props) {
18375
19208
  onDynamicFieldClick,
18376
19209
  onReady,
18377
19210
  onError,
19211
+ loadingFallback,
18378
19212
  // Default `false` so PageCanvas blocks textbox creation until the host
18379
19213
  // browser actually has the @font-face rules registered. This matters for
18380
19214
  // `overflowPolicy: 'auto-shrink'` text — `createText` runs the shrink
@@ -18431,10 +19265,10 @@ function PixldocsPreview(props) {
18431
19265
  supabaseUrl: p.supabaseUrl,
18432
19266
  supabaseAnonKey: p.supabaseAnonKey
18433
19267
  }).then((resolved) => {
18434
- var _a2, _b2;
19268
+ var _a3, _b2;
18435
19269
  if (!cancelled) {
18436
19270
  console.log(PREVIEW_DEBUG_PREFIX, "resolve-done", {
18437
- pages: ((_b2 = (_a2 = resolved.config) == null ? void 0 : _a2.pages) == null ? void 0 : _b2.length) ?? 0,
19271
+ pages: ((_b2 = (_a3 = resolved.config) == null ? void 0 : _a3.pages) == null ? void 0 : _b2.length) ?? 0,
18438
19272
  underlinedNodes: countUnderlinedNodes(resolved.config)
18439
19273
  });
18440
19274
  setResolvedConfig(resolved.config);
@@ -18543,15 +19377,15 @@ function PixldocsPreview(props) {
18543
19377
  const blurPx = (frostedBlurOptions == null ? void 0 : frostedBlurOptions.blurPx) ?? 5;
18544
19378
  const satPct = (frostedBlurOptions == null ? void 0 : frostedBlurOptions.saturatePct) ?? 130;
18545
19379
  const bgTint = (frostedBlurOptions == null ? void 0 : frostedBlurOptions.background) ?? "rgba(255,255,255,0.12)";
18546
- const canvasW = getNum((_a = config == null ? void 0 : config.canvas) == null ? void 0 : _a.width, 0);
19380
+ const canvasW = getNum((_a2 = config == null ? void 0 : config.canvas) == null ? void 0 : _a2.width, 0);
18547
19381
  const canvasH = getNum((_b = config == null ? void 0 : config.canvas) == null ? void 0 : _b.height, 0);
18548
19382
  const hasOverlays = frostedBounds.length > 0 && canvasW > 0 && canvasH > 0;
18549
19383
  if (isLoading) {
18550
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
19384
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...style, position: "relative", minHeight: 200, display: "flex", alignItems: "center", justifyContent: "center" }, children: loadingFallback ?? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
18551
19385
  }
18552
19386
  if (!config) return null;
18553
19387
  if (!fontsReady) {
18554
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
19388
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...style, position: "relative", minHeight: 200, display: "flex", alignItems: "center", justifyContent: "center" }, children: loadingFallback ?? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
18555
19389
  }
18556
19390
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...style, position: "relative" }, children: [
18557
19391
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -18603,7 +19437,7 @@ function PixldocsPreview(props) {
18603
19437
  ]
18604
19438
  }
18605
19439
  ),
18606
- !canvasSettled && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
19440
+ !canvasSettled && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: loadingFallback ?? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
18607
19441
  ] });
18608
19442
  }
18609
19443
  function normalizeSvgDimensions(svg, targetWidth, targetHeight) {
@@ -18685,7 +19519,7 @@ function ensureFabricGradientDef(doc, obj, width, height) {
18685
19519
  return `url(#${id})`;
18686
19520
  }
18687
19521
  function warpTextboxSvgAlongPath(svg, obj) {
18688
- var _a, _b, _c, _d, _e;
19522
+ var _a2, _b, _c, _d, _e;
18689
19523
  const tp = obj == null ? void 0 : obj.textPath;
18690
19524
  if (!tp || !tp.preset || tp.preset === "none") return svg;
18691
19525
  if (tp.preset === "rise" || tp.preset === "angle") {
@@ -18743,7 +19577,7 @@ function warpTextboxSvgAlongPath(svg, obj) {
18743
19577
  }
18744
19578
  for (const marker of Array.from(doc.querySelectorAll("g.__pdShadowRaster"))) {
18745
19579
  try {
18746
- (_a = marker.parentNode) == null ? void 0 : _a.removeChild(marker);
19580
+ (_a2 = marker.parentNode) == null ? void 0 : _a2.removeChild(marker);
18747
19581
  } catch {
18748
19582
  }
18749
19583
  }
@@ -18769,9 +19603,9 @@ function warpTextboxSvgAlongPath(svg, obj) {
18769
19603
  const fw = obj.fontWeight ?? 400;
18770
19604
  const fst = obj.fontStyle || "normal";
18771
19605
  const readFill = (el) => {
18772
- var _a2, _b2;
19606
+ var _a3, _b2;
18773
19607
  if (!el) return "";
18774
- return el.getAttribute("fill") || ((_b2 = (_a2 = (el.getAttribute("style") || "").match(/(?:^|;)\s*fill\s*:\s*([^;]+)/i)) == null ? void 0 : _a2[1]) == null ? void 0 : _b2.trim()) || "";
19608
+ return el.getAttribute("fill") || ((_b2 = (_a3 = (el.getAttribute("style") || "").match(/(?:^|;)\s*fill\s*:\s*([^;]+)/i)) == null ? void 0 : _a3[1]) == null ? void 0 : _b2.trim()) || "";
18775
19609
  };
18776
19610
  const w = Number(obj.width) || 0;
18777
19611
  const h = Number(obj.height) || 0;
@@ -18964,7 +19798,7 @@ function stampFabricLineMetricsOnTextSvg(svg, obj) {
18964
19798
  const boxWidth = Number(obj.width ?? 0) || 0;
18965
19799
  let lineIndex = 0;
18966
19800
  return svg.replace(/<tspan\b([^>]*)>/gi, (match, attrs) => {
18967
- var _a;
19801
+ var _a2;
18968
19802
  if (lineIndex >= lines.length || !/\sy\s*=/.test(attrs)) return match;
18969
19803
  let lineWidth = 0;
18970
19804
  let lineLeft = 0;
@@ -18974,7 +19808,7 @@ function stampFabricLineMetricsOnTextSvg(svg, obj) {
18974
19808
  lineWidth = 0;
18975
19809
  }
18976
19810
  try {
18977
- lineLeft = Number(((_a = obj._getLineLeftOffset) == null ? void 0 : _a.call(obj, lineIndex)) ?? 0);
19811
+ lineLeft = Number(((_a2 = obj._getLineLeftOffset) == null ? void 0 : _a2.call(obj, lineIndex)) ?? 0);
18978
19812
  } catch {
18979
19813
  lineLeft = 0;
18980
19814
  }
@@ -19123,18 +19957,18 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
19123
19957
  }
19124
19958
  return svgString;
19125
19959
  }
19126
- const resolvedPackageVersion = "0.5.223";
19960
+ const resolvedPackageVersion = "0.5.225";
19127
19961
  const PACKAGE_VERSION = resolvedPackageVersion;
19128
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.223";
19962
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.225";
19129
19963
  const roundParityValue = (value) => {
19130
19964
  if (typeof value !== "number") return value;
19131
19965
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
19132
19966
  };
19133
19967
  function isolatePageForCapture(config, pageIndex) {
19134
- var _a;
19968
+ var _a2;
19135
19969
  const capturePageId = `__pixldocs_capture_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}_${pageIndex}`;
19136
19970
  const cloned = JSON.parse(JSON.stringify(config));
19137
- if ((_a = cloned.pages) == null ? void 0 : _a[pageIndex]) {
19971
+ if ((_a2 = cloned.pages) == null ? void 0 : _a2[pageIndex]) {
19138
19972
  cloned.pages[pageIndex].id = capturePageId;
19139
19973
  }
19140
19974
  return { config: cloned, pageId: capturePageId };
@@ -19296,14 +20130,14 @@ async function downscaleConfigRasterImages(config, maxEdgePx, maxDataUrlBytes =
19296
20130
  }
19297
20131
  let __underlineFixInstalled = false;
19298
20132
  function installUnderlineFix(fab) {
19299
- var _a;
20133
+ var _a2;
19300
20134
  if (__underlineFixInstalled) return;
19301
- const TextProto = (_a = fab.Text) == null ? void 0 : _a.prototype;
20135
+ const TextProto = (_a2 = fab.Text) == null ? void 0 : _a2.prototype;
19302
20136
  if (!TextProto || typeof TextProto._renderTextDecoration !== "function") return;
19303
20137
  const original = TextProto._renderTextDecoration;
19304
20138
  const measureLineTextWidth = (obj, ctx, lineIndex) => {
19305
- var _a2, _b, _c, _d, _e, _f;
19306
- const rawLine = (_a2 = obj._textLines) == null ? void 0 : _a2[lineIndex];
20139
+ var _a3, _b, _c, _d, _e, _f;
20140
+ const rawLine = (_a3 = obj._textLines) == null ? void 0 : _a3[lineIndex];
19307
20141
  const lineText = Array.isArray(rawLine) ? rawLine.join("") : String(rawLine ?? "");
19308
20142
  if (!lineText) return 0;
19309
20143
  const fontSize = Number(((_b = obj.getValueOfPropertyAt) == null ? void 0 : _b.call(obj, lineIndex, 0, "fontSize")) ?? obj.fontSize ?? 0);
@@ -19395,9 +20229,9 @@ function installUnderlineFix(fab) {
19395
20229
  }
19396
20230
  let __textboxBoxExtensionsInstalled = false;
19397
20231
  function installTextboxBoxExtensions(fab) {
19398
- var _a;
20232
+ var _a2;
19399
20233
  if (__textboxBoxExtensionsInstalled) return;
19400
- const TextboxProto2 = (_a = fab.Textbox) == null ? void 0 : _a.prototype;
20234
+ const TextboxProto2 = (_a2 = fab.Textbox) == null ? void 0 : _a2.prototype;
19401
20235
  if (!TextboxProto2) return;
19402
20236
  if (TextboxProto2.__pixldocsTextboxExtended) {
19403
20237
  __textboxBoxExtensionsInstalled = true;
@@ -19456,8 +20290,8 @@ function installTextboxBoxExtensions(fab) {
19456
20290
  __textboxBoxExtensionsInstalled = true;
19457
20291
  }
19458
20292
  function configHasAutoShrinkText(config) {
19459
- var _a;
19460
- if (!((_a = config == null ? void 0 : config.pages) == null ? void 0 : _a.length)) return false;
20293
+ var _a2;
20294
+ if (!((_a2 = config == null ? void 0 : config.pages) == null ? void 0 : _a2.length)) return false;
19461
20295
  const walk = (nodes) => {
19462
20296
  for (const node of nodes || []) {
19463
20297
  if (!node) continue;
@@ -19708,8 +20542,8 @@ class PixldocsRenderer {
19708
20542
  * Requires `RendererConfig.deliveryServerUrl` to be set.
19709
20543
  */
19710
20544
  async renderAndDeliver(options) {
19711
- var _a;
19712
- const base = (_a = this.config.deliveryServerUrl) == null ? void 0 : _a.replace(/\/+$/, "");
20545
+ var _a2;
20546
+ const base = (_a2 = this.config.deliveryServerUrl) == null ? void 0 : _a2.replace(/\/+$/, "");
19713
20547
  if (!base) {
19714
20548
  throw new Error("renderAndDeliver: RendererConfig.deliveryServerUrl is required");
19715
20549
  }
@@ -19769,7 +20603,7 @@ class PixldocsRenderer {
19769
20603
  * same fonts, same gradients, same draw order, same selectable text.
19770
20604
  */
19771
20605
  async renderPdfViaClientExport(templateConfig, options = {}) {
19772
- var _a;
20606
+ var _a2;
19773
20607
  await ensureFontsForResolvedConfig(templateConfig);
19774
20608
  const hasAutoShrink = configHasAutoShrinkText(templateConfig);
19775
20609
  await this.awaitFontsForConfig(templateConfig, hasAutoShrink ? 4e3 : 1800);
@@ -19869,7 +20703,7 @@ class PixldocsRenderer {
19869
20703
  await this.waitForCanvasScene(container, cloned, i);
19870
20704
  }
19871
20705
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
19872
- const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-C-l9Vtku.cjs"));
20706
+ const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-CVeK--lR.cjs"));
19873
20707
  const prepared = preparePagesForExport(
19874
20708
  cloned.pages,
19875
20709
  canvasWidth,
@@ -19879,7 +20713,7 @@ class PixldocsRenderer {
19879
20713
  title: options.title,
19880
20714
  watermark: !!options.watermark,
19881
20715
  returnBlob: true,
19882
- pdfTextMode: options.textMode ?? (cloned == null ? void 0 : cloned.pdfTextMode) ?? ((_a = cloned.canvas) == null ? void 0 : _a.n) ?? "auto",
20716
+ pdfTextMode: options.textMode ?? (cloned == null ? void 0 : cloned.pdfTextMode) ?? ((_a2 = cloned.canvas) == null ? void 0 : _a2.n) ?? "auto",
19883
20717
  // Safari/WebKit can still let svg2pdf silently drop valid JPEG data-URL
19884
20718
  // <image> nodes even after the data is compressed and Fabric has loaded
19885
20719
  // it. For auto Safari mode, bypass only the full-page SVG->svg2pdf fast
@@ -20086,9 +20920,9 @@ class PixldocsRenderer {
20086
20920
  }
20087
20921
  waitForCanvasScene(container, config, pageIndex, maxWaitMs = 8e3, pollMs = 50) {
20088
20922
  return new Promise((resolve) => {
20089
- var _a, _b;
20923
+ var _a2, _b;
20090
20924
  const start = Date.now();
20091
- const pageHasContent = (((_b = (_a = config.pages[pageIndex]) == null ? void 0 : _a.children) == null ? void 0 : _b.length) ?? 0) > 0;
20925
+ const pageHasContent = (((_b = (_a2 = config.pages[pageIndex]) == null ? void 0 : _a2.children) == null ? void 0 : _b.length) ?? 0) > 0;
20092
20926
  const settle = () => requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
20093
20927
  const check = () => {
20094
20928
  const fabricCanvas = this.getFabricCanvasFromContainer(container);
@@ -20163,8 +20997,8 @@ class PixldocsRenderer {
20163
20997
  return normalized;
20164
20998
  }
20165
20999
  paintPageBackground(ctx, page, width, height) {
20166
- var _a, _b;
20167
- const backgroundColor = ((_a = page == null ? void 0 : page.settings) == null ? void 0 : _a.backgroundColor) || "#ffffff";
21000
+ var _a2, _b;
21001
+ const backgroundColor = ((_a2 = page == null ? void 0 : page.settings) == null ? void 0 : _a2.backgroundColor) || "#ffffff";
20168
21002
  const gradient = (_b = page == null ? void 0 : page.settings) == null ? void 0 : _b.backgroundGradient;
20169
21003
  ctx.clearRect(0, 0, width, height);
20170
21004
  ctx.fillStyle = backgroundColor;
@@ -20413,7 +21247,7 @@ class PixldocsRenderer {
20413
21247
  };
20414
21248
  const onReady = () => {
20415
21249
  this.waitForCanvasScene(container, renderConfig, pageIndex).then(async () => {
20416
- var _a, _b;
21250
+ var _a2, _b;
20417
21251
  try {
20418
21252
  const expectedImageIds = this.getExpectedImageIds(renderConfig, pageIndex);
20419
21253
  await this.waitForCanvasImages(container, expectedImageIds);
@@ -20431,7 +21265,7 @@ class PixldocsRenderer {
20431
21265
  canvasHeight
20432
21266
  );
20433
21267
  const page = renderConfig.pages[pageIndex];
20434
- const backgroundColor = ((_a = page == null ? void 0 : page.settings) == null ? void 0 : _a.backgroundColor) || "#ffffff";
21268
+ const backgroundColor = ((_a2 = page == null ? void 0 : page.settings) == null ? void 0 : _a2.backgroundColor) || "#ffffff";
20435
21269
  const backgroundGradient = (_b = page == null ? void 0 : page.settings) == null ? void 0 : _b.backgroundGradient;
20436
21270
  cleanup();
20437
21271
  resolve({
@@ -20517,11 +21351,11 @@ class PixldocsRenderer {
20517
21351
  return null;
20518
21352
  }
20519
21353
  logFabricTextParitySnapshot(stage, fabricInstance) {
20520
- var _a;
21354
+ var _a2;
20521
21355
  if (typeof window === "undefined" || window.__pixldocsDebugAutoShrink !== true) return;
20522
21356
  const sample = [];
20523
21357
  const visit = (obj, groupPath = "") => {
20524
- var _a2;
21358
+ var _a3;
20525
21359
  if (!obj) return;
20526
21360
  if (isFabricTextboxLike(obj)) {
20527
21361
  const lineWidths = getCanvasMeasuredTextboxLineWidths(obj);
@@ -20538,7 +21372,7 @@ class PixldocsRenderer {
20538
21372
  fontSize: obj.fontSize,
20539
21373
  fontFamily: obj.fontFamily,
20540
21374
  fontWeight: obj.fontWeight,
20541
- lineCount: ((_a2 = obj.textLines) == null ? void 0 : _a2.length) || 0,
21375
+ lineCount: ((_a3 = obj.textLines) == null ? void 0 : _a3.length) || 0,
20542
21376
  lines: (obj.textLines || []).map((line) => Array.isArray(line) ? line.join("") : String(line ?? "")),
20543
21377
  lineWidths,
20544
21378
  maxLineWidth: lineWidths.length ? Math.max(...lineWidths) : 0
@@ -20549,11 +21383,11 @@ class PixldocsRenderer {
20549
21383
  obj.getObjects().forEach((child) => visit(child, nextPath));
20550
21384
  }
20551
21385
  };
20552
- (_a = fabricInstance == null ? void 0 : fabricInstance.getObjects) == null ? void 0 : _a.call(fabricInstance).forEach((obj) => visit(obj));
21386
+ (_a2 = fabricInstance == null ? void 0 : fabricInstance.getObjects) == null ? void 0 : _a2.call(fabricInstance).forEach((obj) => visit(obj));
20553
21387
  logJsonLine("[canvas-renderer][fabric-text-parity]", { stage, textboxes: sample.length, sample });
20554
21388
  }
20555
21389
  async waitForStableTextMetrics(container, config, options = {}) {
20556
- var _a, _b, _c;
21390
+ var _a2, _b, _c;
20557
21391
  if (typeof document !== "undefined") {
20558
21392
  void ensureFontsForResolvedConfig(config);
20559
21393
  await this.waitForRelevantFonts(config);
@@ -20594,7 +21428,7 @@ class PixldocsRenderer {
20594
21428
  }
20595
21429
  }
20596
21430
  fabricInstance.getObjects().forEach(primeCharBounds);
20597
- (_a = fabricInstance.calcOffset) == null ? void 0 : _a.call(fabricInstance);
21431
+ (_a2 = fabricInstance.calcOffset) == null ? void 0 : _a2.call(fabricInstance);
20598
21432
  (_b = fabricInstance.renderAll) == null ? void 0 : _b.call(fabricInstance);
20599
21433
  await waitForPaint();
20600
21434
  (_c = fabricInstance.renderAll) == null ? void 0 : _c.call(fabricInstance);
@@ -20636,7 +21470,7 @@ function dumpSvgTextDiagnostics(svgStr, pageIndex, tag, stage, maxItems = 30) {
20636
21470
  };
20637
21471
  logParityJson(tag, stage, { kind: "summary", ...summary });
20638
21472
  const sample = texts.slice(0, maxItems).map((t, idx) => {
20639
- var _a, _b;
21473
+ var _a2, _b;
20640
21474
  const tspans = Array.from(t.querySelectorAll("tspan"));
20641
21475
  const tspanInfo = tspans.slice(0, 8).map((s) => ({
20642
21476
  x: s.getAttribute("x"),
@@ -20651,7 +21485,7 @@ function dumpSvgTextDiagnostics(svgStr, pageIndex, tag, stage, maxItems = 30) {
20651
21485
  let containerWidth = null;
20652
21486
  let cursor = t.parentElement;
20653
21487
  while (cursor && !containerWidth) {
20654
- containerWidth = (_a = cursor.getAttribute) == null ? void 0 : _a.call(cursor, "width");
21488
+ containerWidth = (_a2 = cursor.getAttribute) == null ? void 0 : _a2.call(cursor, "width");
20655
21489
  cursor = cursor.parentElement;
20656
21490
  if (cursor && ((_b = cursor.tagName) == null ? void 0 : _b.toLowerCase()) === "svg") break;
20657
21491
  }
@@ -20845,7 +21679,7 @@ function rgbToHex(r, g, b) {
20845
21679
  return "#" + [r, g, b].map((x) => Math.max(0, Math.min(255, Math.round(x))).toString(16).padStart(2, "0")).join("");
20846
21680
  }
20847
21681
  function cssColorToHex(css) {
20848
- var _a;
21682
+ var _a2;
20849
21683
  const s = css.trim();
20850
21684
  if (/^#[0-9a-f]{3}$/i.test(s)) {
20851
21685
  const r = s[1] + s[1], g = s[2] + s[2], b = s[3] + s[3];
@@ -20863,17 +21697,17 @@ function cssColorToHex(css) {
20863
21697
  if (typeof document === "undefined") return null;
20864
21698
  const div = document.createElement("div");
20865
21699
  div.style.color = s;
20866
- const computed = (_a = document.defaultView) == null ? void 0 : _a.getComputedStyle(div).color;
21700
+ const computed = (_a2 = document.defaultView) == null ? void 0 : _a2.getComputedStyle(div).color;
20867
21701
  if (!computed || !computed.startsWith("rgb")) return null;
20868
21702
  const m = computed.match(/\d+/g);
20869
21703
  if (!m || m.length < 3) return null;
20870
21704
  return "#" + [m[0], m[1], m[2]].map((v) => Number(v).toString(16).padStart(2, "0")).join("");
20871
21705
  }
20872
21706
  function isInSvgDefinitionSubtree(el) {
20873
- var _a;
21707
+ var _a2;
20874
21708
  let current = el;
20875
21709
  while (current) {
20876
- if (SVG_DEFINITION_CONTAINER_TAGS.has(((_a = current.tagName) == null ? void 0 : _a.toLowerCase()) ?? "")) return true;
21710
+ if (SVG_DEFINITION_CONTAINER_TAGS.has(((_a2 = current.tagName) == null ? void 0 : _a2.toLowerCase()) ?? "")) return true;
20877
21711
  current = current.parentElement;
20878
21712
  }
20879
21713
  return false;
@@ -21033,27 +21867,27 @@ function normalizeSvgExplicitColors(svg) {
21033
21867
  const clone = svg.cloneNode(true);
21034
21868
  inlineSvgStyleBlockDeclarations(clone);
21035
21869
  const getAttr = (el, attr) => {
21036
- var _a;
21037
- const v = el.getAttribute(attr) ?? ((_a = el.style) == null ? void 0 : _a.getPropertyValue(attr));
21870
+ var _a2;
21871
+ const v = el.getAttribute(attr) ?? ((_a2 = el.style) == null ? void 0 : _a2.getPropertyValue(attr));
21038
21872
  if (!v) return null;
21039
21873
  const s = v.trim().toLowerCase();
21040
21874
  if (!s || s === "none" || s === "transparent" || s === "currentcolor") return null;
21041
21875
  return normalizeGradientPaintRef(v);
21042
21876
  };
21043
21877
  const hasExplicitNonePaint = (el, attr) => {
21044
- var _a, _b;
21045
- const raw = (el.getAttribute(attr) ?? ((_a = el.style) == null ? void 0 : _a.getPropertyValue(attr)) ?? "").trim().toLowerCase();
21878
+ var _a2, _b;
21879
+ const raw = (el.getAttribute(attr) ?? ((_a2 = el.style) == null ? void 0 : _a2.getPropertyValue(attr)) ?? "").trim().toLowerCase();
21046
21880
  if (raw === "none" || raw === "transparent") return true;
21047
21881
  const rawOpacity = (el.getAttribute(`${attr}-opacity`) ?? ((_b = el.style) == null ? void 0 : _b.getPropertyValue(`${attr}-opacity`)) ?? "").trim().toLowerCase();
21048
21882
  return rawOpacity === "0" || rawOpacity === "0%" || rawOpacity === "0.0";
21049
21883
  };
21050
21884
  function walk(el, parentFill, parentStroke, parentColor) {
21051
- var _a;
21885
+ var _a2;
21052
21886
  if (isInSvgDefinitionSubtree(el)) {
21053
21887
  for (let i = 0; i < el.children.length; i++) walk(el.children[i], null, null, null);
21054
21888
  return;
21055
21889
  }
21056
- const tag = ((_a = el.tagName) == null ? void 0 : _a.toLowerCase()) ?? "";
21890
+ const tag = ((_a2 = el.tagName) == null ? void 0 : _a2.toLowerCase()) ?? "";
21057
21891
  const isDrawable = SVG_DRAWABLE_TAGS.has(tag);
21058
21892
  let fill = getAttr(el, "fill");
21059
21893
  let stroke = getAttr(el, "stroke");
@@ -21111,12 +21945,12 @@ function normalizeSvgExplicitColors(svg) {
21111
21945
  function bakeGroupOpacityIntoChildren(svg) {
21112
21946
  const DRAWABLE = /* @__PURE__ */ new Set(["path", "rect", "circle", "ellipse", "polygon", "polyline", "line", "text", "tspan"]);
21113
21947
  function walkAndBake(el, inheritedOpacity) {
21114
- var _a, _b, _c, _d;
21948
+ var _a2, _b, _c, _d;
21115
21949
  if (isInSvgDefinitionSubtree(el)) {
21116
21950
  for (let i = 0; i < el.children.length; i++) walkAndBake(el.children[i], 1);
21117
21951
  return;
21118
21952
  }
21119
- const tag = ((_a = el.tagName) == null ? void 0 : _a.toLowerCase()) ?? "";
21953
+ const tag = ((_a2 = el.tagName) == null ? void 0 : _a2.toLowerCase()) ?? "";
21120
21954
  const opacityAttr = parseSvgOpacity(el.getAttribute("opacity"));
21121
21955
  const styleOpacity = parseSvgOpacity(((_b = el.style) == null ? void 0 : _b.getPropertyValue("opacity")) || null);
21122
21956
  const ownOpacity = opacityAttr ?? styleOpacity ?? 1;
@@ -21199,8 +22033,8 @@ function normalizeSvgGradientStopOffsets(svg) {
21199
22033
  }
21200
22034
  }
21201
22035
  function copyGradientAttrsFromRef(gradient, ref) {
21202
- var _a;
21203
- const tag = (_a = gradient.tagName) == null ? void 0 : _a.toLowerCase();
22036
+ var _a2;
22037
+ const tag = (_a2 = gradient.tagName) == null ? void 0 : _a2.toLowerCase();
21204
22038
  const attrs = tag === "radialgradient" ? GRADIENT_ATTRS_RADIAL : GRADIENT_ATTRS_LINEAR;
21205
22039
  for (const name of attrs) {
21206
22040
  if (!gradient.hasAttribute(name) && ref.hasAttribute(name)) {
@@ -21228,7 +22062,7 @@ function expandSvgGradientHrefs(svg) {
21228
22062
  for (const g of svg.querySelectorAll("linearGradient, radialGradient")) expand(g);
21229
22063
  }
21230
22064
  function expandSvgUseElements(svg) {
21231
- var _a;
22065
+ var _a2;
21232
22066
  const doc = svg.ownerDocument;
21233
22067
  for (const use of Array.from(svg.querySelectorAll("use"))) {
21234
22068
  const ref = (use.getAttribute("href") || use.getAttribute("xlink:href") || "").trim();
@@ -21240,7 +22074,7 @@ function expandSvgUseElements(svg) {
21240
22074
  const w = parseFloat(use.getAttribute("width") || "0") || 0;
21241
22075
  const h = parseFloat(use.getAttribute("height") || "0") || 0;
21242
22076
  const g = doc.createElementNS("http://www.w3.org/2000/svg", "g");
21243
- if (((_a = target.tagName) == null ? void 0 : _a.toLowerCase()) === "symbol") {
22077
+ if (((_a2 = target.tagName) == null ? void 0 : _a2.toLowerCase()) === "symbol") {
21244
22078
  const viewBox = target.getAttribute("viewBox");
21245
22079
  for (let i = 0; i < target.children.length; i++) g.appendChild(target.children[i].cloneNode(true));
21246
22080
  if (viewBox && w && h) {
@@ -21367,7 +22201,7 @@ async function readNestedSvgImageMarkup(href) {
21367
22201
  }
21368
22202
  }
21369
22203
  async function inlineNestedSvgImageDataUris(svgString, domParser = new DOMParser()) {
21370
- var _a;
22204
+ var _a2;
21371
22205
  try {
21372
22206
  const doc = domParser.parseFromString(svgString, "image/svg+xml");
21373
22207
  if (doc.querySelector("parsererror")) return svgString;
@@ -21432,7 +22266,7 @@ async function inlineNestedSvgImageDataUris(svgString, domParser = new DOMParser
21432
22266
  }
21433
22267
  }
21434
22268
  for (const child of Array.from(innerSvg.childNodes)) g.appendChild(doc.importNode(child, true));
21435
- (_a = img.parentNode) == null ? void 0 : _a.replaceChild(g, img);
22269
+ (_a2 = img.parentNode) == null ? void 0 : _a2.replaceChild(g, img);
21436
22270
  changed = true;
21437
22271
  inlined++;
21438
22272
  } catch {
@@ -21452,9 +22286,9 @@ function parseSvgLength(value, fallback) {
21452
22286
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
21453
22287
  }
21454
22288
  function isIdentitySvgMatrix(value) {
21455
- var _a;
22289
+ var _a2;
21456
22290
  if (!value) return true;
21457
- const nums = ((_a = value.match(/-?\d*\.?\d+(?:e[-+]?\d+)?/gi)) == null ? void 0 : _a.map(Number)) ?? [];
22291
+ const nums = ((_a2 = value.match(/-?\d*\.?\d+(?:e[-+]?\d+)?/gi)) == null ? void 0 : _a2.map(Number)) ?? [];
21458
22292
  return nums.length === 6 && Math.abs(nums[0] - 1) < 1e-3 && Math.abs(nums[1]) < 1e-3 && Math.abs(nums[2]) < 1e-3 && Math.abs(nums[3] - 1) < 1e-3 && Math.abs(nums[4]) < 1e-3 && Math.abs(nums[5]) < 1e-3;
21459
22293
  }
21460
22294
  function isRedundantImageClipPathForInlineSvg(root, clipPathRef, ix, iy, iw, ih) {
@@ -21540,8 +22374,8 @@ function inlineComputedStyles(svg) {
21540
22374
  document.body.appendChild(wrap);
21541
22375
  try {
21542
22376
  let walk = function(el) {
21543
- var _a;
21544
- const tag = (_a = el.tagName) == null ? void 0 : _a.toLowerCase();
22377
+ var _a2;
22378
+ const tag = (_a2 = el.tagName) == null ? void 0 : _a2.toLowerCase();
21545
22379
  if (drawableTags.includes(tag)) {
21546
22380
  const cs = window.getComputedStyle(el);
21547
22381
  const fill = cs.fill;
@@ -21641,9 +22475,9 @@ function getFirstExplicitColorFromSvg(svg) {
21641
22475
  return getGradientStopColorAsHex(svg, gradientId);
21642
22476
  };
21643
22477
  function walk(el) {
21644
- var _a, _b;
22478
+ var _a2, _b;
21645
22479
  if (fill && stroke) return;
21646
- const f = el.getAttribute("fill") ?? ((_a = el.style) == null ? void 0 : _a.getPropertyValue("fill"));
22480
+ const f = el.getAttribute("fill") ?? ((_a2 = el.style) == null ? void 0 : _a2.getPropertyValue("fill"));
21647
22481
  const s = el.getAttribute("stroke") ?? ((_b = el.style) == null ? void 0 : _b.getPropertyValue("stroke"));
21648
22482
  if (!fill) {
21649
22483
  if (isRealColor(f)) fill = f;
@@ -21672,16 +22506,16 @@ function isNearWhite(hex) {
21672
22506
  return r >= 250 && g >= 250 && b >= 250;
21673
22507
  }
21674
22508
  function getStopColorRaw(stop) {
21675
- var _a, _b;
21676
- return stop.getAttribute("stop-color") ?? ((_b = (_a = stop.style) == null ? void 0 : _a.getPropertyValue("stop-color")) == null ? void 0 : _b.trim()) ?? getInlineStyleValue(stop, "stop-color");
22509
+ var _a2, _b;
22510
+ return stop.getAttribute("stop-color") ?? ((_b = (_a2 = stop.style) == null ? void 0 : _a2.getPropertyValue("stop-color")) == null ? void 0 : _b.trim()) ?? getInlineStyleValue(stop, "stop-color");
21677
22511
  }
21678
22512
  function getGradientStopColorAsHex(svgRoot, gradientId, visited = /* @__PURE__ */ new Set()) {
21679
- var _a;
22513
+ var _a2;
21680
22514
  if (visited.has(gradientId)) return null;
21681
22515
  visited.add(gradientId);
21682
22516
  const gradient = findGradientInTree(svgRoot, gradientId);
21683
22517
  if (!gradient) return null;
21684
- const tag = (_a = gradient.tagName) == null ? void 0 : _a.toLowerCase();
22518
+ const tag = (_a2 = gradient.tagName) == null ? void 0 : _a2.toLowerCase();
21685
22519
  if (tag !== "lineargradient" && tag !== "radialgradient") return null;
21686
22520
  const stops = Array.from(gradient.querySelectorAll("stop"));
21687
22521
  if (stops.length > 0) {
@@ -21737,10 +22571,10 @@ async function convertTextDecorationsToLines(svg) {
21737
22571
  else el.removeAttribute("style");
21738
22572
  };
21739
22573
  const resolveInheritedSvgValue = (el, attr, styleProp = attr) => {
21740
- var _a, _b;
22574
+ var _a2, _b;
21741
22575
  let current = el;
21742
22576
  while (current) {
21743
- const attrValue = (_a = current.getAttribute(attr)) == null ? void 0 : _a.trim();
22577
+ const attrValue = (_a2 = current.getAttribute(attr)) == null ? void 0 : _a2.trim();
21744
22578
  if (attrValue) return attrValue;
21745
22579
  const styleValue = (_b = getInlineStyleValue(current, styleProp)) == null ? void 0 : _b.trim();
21746
22580
  if (styleValue) return styleValue;
@@ -21920,14 +22754,14 @@ async function convertSvgTextDecorationsToLinesString(svgStr) {
21920
22754
  }
21921
22755
  }
21922
22756
  async function rasterizeShadowMarkers(svg) {
21923
- var _a, _b, _c, _d, _e, _f;
22757
+ var _a2, _b, _c, _d, _e, _f;
21924
22758
  if (typeof window === "undefined" || typeof document === "undefined") return;
21925
22759
  const markers = Array.from(svg.querySelectorAll("g.__pdShadowRaster"));
21926
22760
  if (markers.length === 0) return;
21927
22761
  const SVG_NS = "http://www.w3.org/2000/svg";
21928
22762
  const XLINK_NS = "http://www.w3.org/1999/xlink";
21929
22763
  try {
21930
- if ((_a = document.fonts) == null ? void 0 : _a.ready) await document.fonts.ready;
22764
+ if ((_a2 = document.fonts) == null ? void 0 : _a2.ready) await document.fonts.ready;
21931
22765
  } catch {
21932
22766
  }
21933
22767
  const fontFaceCss = await collectInlinedFontFaceCss();
@@ -22189,7 +23023,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
22189
23023
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
22190
23024
  sanitizeSvgTreeForPdf(svgToDraw);
22191
23025
  try {
22192
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-C-l9Vtku.cjs"));
23026
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-CVeK--lR.cjs"));
22193
23027
  try {
22194
23028
  await logTextMeasurementDiagnostic(svgToDraw);
22195
23029
  } catch {
@@ -22205,8 +23039,8 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
22205
23039
  }
22206
23040
  }
22207
23041
  function drawPageBackground(pdf, pageIndex, pageWidth, pageHeight, backgroundColor, backgroundGradient) {
22208
- var _a, _b;
22209
- if (backgroundGradient && ((_a = backgroundGradient.stops) == null ? void 0 : _a.length) >= 2) {
23042
+ var _a2, _b;
23043
+ if (backgroundGradient && ((_a2 = backgroundGradient.stops) == null ? void 0 : _a2.length) >= 2) {
22210
23044
  const grad = backgroundGradient;
22211
23045
  const colorStops = grad.stops.map((s) => {
22212
23046
  const c = parseColor(s.color);
@@ -22273,7 +23107,7 @@ function drawPageBackground(pdf, pageIndex, pageWidth, pageHeight, backgroundCol
22273
23107
  }
22274
23108
  }
22275
23109
  async function assemblePdfFromSvgs(svgResults, options = {}) {
22276
- var _a, _b;
23110
+ var _a2, _b;
22277
23111
  if (svgResults.length === 0) throw new Error("No pages to export");
22278
23112
  const { title, stripPageBackground } = options;
22279
23113
  const firstPage = svgResults[0];
@@ -22306,7 +23140,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
22306
23140
  const pageOrientation = page.width > page.height ? "landscape" : "portrait";
22307
23141
  pdf.addPage([page.width, page.height], pageOrientation);
22308
23142
  }
22309
- const hasGradient = !!((_b = (_a = page.backgroundGradient) == null ? void 0 : _a.stops) == null ? void 0 : _b.length);
23143
+ const hasGradient = !!((_b = (_a2 = page.backgroundGradient) == null ? void 0 : _a2.stops) == null ? void 0 : _b.length);
22310
23144
  drawPageBackground(pdf, i, page.width, page.height, page.backgroundColor, page.backgroundGradient);
22311
23145
  const shouldStripBg = stripPageBackground ?? hasGradient;
22312
23146
  const textMode = options.textMode ?? (options.outlineText === true ? "pixel-perfect" : "selectable");
@@ -22585,4 +23419,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
22585
23419
  exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
22586
23420
  exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
22587
23421
  exports.warmTemplateFromForm = warmTemplateFromForm;
22588
- //# sourceMappingURL=index-xWTAswf0.cjs.map
23422
+ //# sourceMappingURL=index-6nrov1rx.cjs.map