@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.
@@ -1,6 +1,7 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+ var _a;
4
5
  import { jsxs, jsx, Fragment } from "react/jsx-runtime";
5
6
  import { forwardRef, useRef, useState, useMemo, useEffect, useCallback, useImperativeHandle, createElement } from "react";
6
7
  import { flushSync } from "react-dom";
@@ -272,12 +273,12 @@ function lineToString(line) {
272
273
  return Array.isArray(line) ? line.join("") : String(line ?? "");
273
274
  }
274
275
  function measureTextLineWithCanvas(textbox, lineText, lineIndex) {
275
- var _a, _b, _c, _d, _e;
276
+ var _a2, _b, _c, _d, _e;
276
277
  if (!lineText) return 0;
277
278
  const ctx = getMeasureContext();
278
279
  if (!ctx) return null;
279
280
  const tb = textbox;
280
- const fontSize = Number(((_a = tb.getValueOfPropertyAt) == null ? void 0 : _a.call(tb, lineIndex, 0, "fontSize")) ?? textbox.fontSize ?? 16);
281
+ const fontSize = Number(((_a2 = tb.getValueOfPropertyAt) == null ? void 0 : _a2.call(tb, lineIndex, 0, "fontSize")) ?? textbox.fontSize ?? 16);
281
282
  const fontStyle = String(((_b = tb.getValueOfPropertyAt) == null ? void 0 : _b.call(tb, lineIndex, 0, "fontStyle")) ?? textbox.fontStyle ?? "normal");
282
283
  const fontWeight = String(((_c = tb.getValueOfPropertyAt) == null ? void 0 : _c.call(tb, lineIndex, 0, "fontWeight")) ?? textbox.fontWeight ?? "400");
283
284
  const fontFamily = String(((_d = tb.getValueOfPropertyAt) == null ? void 0 : _d.call(tb, lineIndex, 0, "fontFamily")) ?? textbox.fontFamily ?? "Open Sans");
@@ -601,7 +602,7 @@ function resolveStackGroupEffectivePositions(group, pageChildren, options) {
601
602
  return out;
602
603
  }
603
604
  function groupBoundsFromChildren(group, pageChildren, options) {
604
- var _a, _b;
605
+ var _a2, _b;
605
606
  const kids = group.children ?? [];
606
607
  if (kids.length === 0) {
607
608
  const w = group.width;
@@ -613,7 +614,7 @@ function groupBoundsFromChildren(group, pageChildren, options) {
613
614
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
614
615
  for (const child of kids) {
615
616
  const b = getNodeBounds(child, pageChildren);
616
- const cl = positions ? ((_a = positions.get(child.id)) == null ? void 0 : _a.left) ?? getNodeLeft(child) : getNodeLeft(child);
617
+ const cl = positions ? ((_a2 = positions.get(child.id)) == null ? void 0 : _a2.left) ?? getNodeLeft(child) : getNodeLeft(child);
617
618
  const ct = positions ? ((_b = positions.get(child.id)) == null ? void 0 : _b.top) ?? getNodeTop(child) : getNodeTop(child);
618
619
  minX = Math.min(minX, cl);
619
620
  minY = Math.min(minY, ct);
@@ -652,13 +653,13 @@ function getNodeBoundsFromChildren(node) {
652
653
  return getNodeBounds(node);
653
654
  }
654
655
  function absoluteBoundsRecur(node, pageChildren, options) {
655
- var _a, _b;
656
+ var _a2, _b;
656
657
  const parent = pageChildren ? findParentGroup(pageChildren, node.id) : null;
657
658
  const b = getNodeBounds(node, pageChildren);
658
659
  if (!parent) return b;
659
660
  const parentAbs = absoluteBoundsRecur(parent, pageChildren);
660
661
  const isStackParent = isStackLayoutMode(parent.layoutMode);
661
- const inParentLeft = isStackParent ? ((_a = resolveStackGroupEffectivePositions(parent, pageChildren).get(node.id)) == null ? void 0 : _a.left) ?? b.left : b.left;
662
+ const inParentLeft = isStackParent ? ((_a2 = resolveStackGroupEffectivePositions(parent, pageChildren).get(node.id)) == null ? void 0 : _a2.left) ?? b.left : b.left;
662
663
  const inParentTop = isStackParent ? ((_b = resolveStackGroupEffectivePositions(parent, pageChildren).get(node.id)) == null ? void 0 : _b.top) ?? b.top : b.top;
663
664
  return {
664
665
  left: parentAbs.left + inParentLeft,
@@ -677,22 +678,41 @@ function absoluteToStorePosition(absoluteLeft, absoluteTop, nodeId, pageChildren
677
678
  const parent = findParentGroup(pageChildren, nodeId);
678
679
  if (!parent) return { left: absoluteLeft, top: absoluteTop };
679
680
  const parentAbs = getAbsoluteBounds(parent, pageChildren);
680
- const storeLeft = absoluteLeft - parentAbs.left;
681
+ const inParentLeft = absoluteLeft - parentAbs.left;
681
682
  const inParentTop = absoluteTop - parentAbs.top;
682
683
  const isStack = isStackLayoutMode(parent.layoutMode);
683
- if (!isStack) return { left: storeLeft, top: inParentTop };
684
+ if (!isStack) return { left: inParentLeft, top: inParentTop };
684
685
  const kids = parent.children ?? [];
685
686
  const idx = kids.findIndex((c) => c.id === nodeId);
686
- if (idx < 0) return { left: storeLeft, top: inParentTop };
687
- if (idx === 0) return { left: storeLeft, top: inParentTop };
687
+ if (idx < 0) return { left: inParentLeft, top: inParentTop };
688
688
  const gap = parent.stackSpacing ?? 8;
689
+ const padTop = parent.paddingTop ?? 0;
690
+ const padLeft = parent.paddingLeft ?? 0;
691
+ const marginTop = node.marginTop ?? 0;
692
+ const marginLeft = node.marginLeft ?? 0;
689
693
  const resolved = resolveStackGroupEffectivePositions(parent, pageChildren);
690
- const prev = kids[idx - 1];
691
- const prevResolved = resolved.get(prev.id);
692
- const prevHeight = getNodeBounds(prev, pageChildren).height;
693
- const prevBottom = prevResolved ? prevResolved.top + prevHeight + (prev.marginBottom ?? 0) : 0;
694
- const storeTop = inParentTop - prevBottom - gap;
695
- return { left: storeLeft, top: Math.max(0, storeTop) };
694
+ if (isVerticalStackLayoutMode(parent.layoutMode)) {
695
+ const baseTop = idx === 0 ? padTop : (() => {
696
+ const prev = kids[idx - 1];
697
+ const prevResolved = resolved.get(prev.id);
698
+ const prevHeight = getNodeBounds(prev, pageChildren).height;
699
+ return (prevResolved ? prevResolved.top + prevHeight + (prev.marginBottom ?? 0) : padTop) + gap;
700
+ })();
701
+ return {
702
+ left: inParentLeft - padLeft - marginLeft,
703
+ top: inParentTop - baseTop - marginTop
704
+ };
705
+ }
706
+ const baseLeft = idx === 0 ? padLeft : (() => {
707
+ const prev = kids[idx - 1];
708
+ const prevResolved = resolved.get(prev.id);
709
+ const prevWidth = getNodeBounds(prev, pageChildren).width;
710
+ return (prevResolved ? prevResolved.left + prevWidth + (prev.marginRight ?? 0) : padLeft) + gap;
711
+ })();
712
+ return {
713
+ left: inParentLeft - baseLeft - marginLeft,
714
+ top: inParentTop - padTop - marginTop
715
+ };
696
716
  }
697
717
  function reflowPageFromRoot(_pageChildren) {
698
718
  return /* @__PURE__ */ new Map();
@@ -790,6 +810,31 @@ function rewriteFieldMappings(mappings, idMap) {
790
810
  if (!(mappings == null ? void 0 : mappings.length)) return [];
791
811
  return mappings.filter((m) => idMap.has(m.elementId)).map((m) => ({ ...m, elementId: idMap.get(m.elementId) }));
792
812
  }
813
+ let canvasRegistry = /* @__PURE__ */ new Map();
814
+ function registerFabricCanvas(pageId, canvas) {
815
+ const existing = canvasRegistry.get(pageId);
816
+ const registryKey = existing && existing !== canvas ? `${pageId}#${Math.random().toString(36).slice(2, 10)}` : pageId;
817
+ canvasRegistry.set(registryKey, canvas);
818
+ return registryKey;
819
+ }
820
+ function unregisterFabricCanvas(pageId, canvas) {
821
+ if (canvas) {
822
+ const existing = canvasRegistry.get(pageId);
823
+ if (existing === canvas) canvasRegistry.delete(pageId);
824
+ return;
825
+ }
826
+ canvasRegistry.delete(pageId);
827
+ }
828
+ function getCanvasForPage(pageId) {
829
+ return canvasRegistry.get(pageId) || null;
830
+ }
831
+ let visibilityOnlyUpdatePendingUntil = 0;
832
+ function markVisibilityOnlyUpdate(ttlMs = 300) {
833
+ visibilityOnlyUpdatePendingUntil = Date.now() + Math.max(0, ttlMs);
834
+ }
835
+ function isVisibilityOnlyUpdatePending() {
836
+ return Date.now() < visibilityOnlyUpdatePendingUntil;
837
+ }
793
838
  const defaultProjectSettings = {
794
839
  showGrid: false,
795
840
  snapToGrid: false,
@@ -1094,7 +1139,7 @@ const useEditorStore = create((set, get) => ({
1094
1139
  return out;
1095
1140
  }),
1096
1141
  updateNode: (id, updates, options) => set((state) => {
1097
- var _a;
1142
+ var _a2;
1098
1143
  const mergedUpdates = { ...updates };
1099
1144
  let nextCanvas = updateCurrentPageChildren(
1100
1145
  state.canvas,
@@ -1167,7 +1212,7 @@ const useEditorStore = create((set, get) => ({
1167
1212
  let next = updateNodeInTree(currentPage.children, id, { children: sortedKids });
1168
1213
  const groupSorted = findNodeById(next, id);
1169
1214
  const orderedKids = (groupSorted == null ? void 0 : groupSorted.children) ?? sortedKids;
1170
- const firstLeft = typeof ((_a = orderedKids[0]) == null ? void 0 : _a.left) === "number" ? orderedKids[0].left : 0;
1215
+ const firstLeft = typeof ((_a2 = orderedKids[0]) == null ? void 0 : _a2.left) === "number" ? orderedKids[0].left : 0;
1171
1216
  let prevBottom = 0;
1172
1217
  for (let i = 0; i < orderedKids.length; i++) {
1173
1218
  const child = orderedKids[i];
@@ -1273,7 +1318,7 @@ const useEditorStore = create((set, get) => ({
1273
1318
  return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };
1274
1319
  }),
1275
1320
  deleteNodes: (ids) => set((state) => {
1276
- var _a;
1321
+ var _a2;
1277
1322
  const currentPage = getCurrentPageFromCanvas(state.canvas);
1278
1323
  let nextChildren = currentPage.children;
1279
1324
  const rootLevelIds = new Set(currentPage.children.map((c) => c.id));
@@ -1311,7 +1356,7 @@ const useEditorStore = create((set, get) => ({
1311
1356
  };
1312
1357
  }
1313
1358
  }
1314
- if ((_a = nextCanvas.dynamicFields) == null ? void 0 : _a.length) {
1359
+ if ((_a2 = nextCanvas.dynamicFields) == null ? void 0 : _a2.length) {
1315
1360
  nextCanvas = {
1316
1361
  ...nextCanvas,
1317
1362
  dynamicFields: nextCanvas.dynamicFields.map((f) => ({
@@ -1583,6 +1628,7 @@ const useEditorStore = create((set, get) => ({
1583
1628
  const node = findNodeById(currentPage.children, id);
1584
1629
  if (!node) return {};
1585
1630
  const newVisible = node.visible === false ? true : false;
1631
+ markVisibilityOnlyUpdate();
1586
1632
  const nextCanvas = updateCurrentPageChildren(
1587
1633
  state.canvas,
1588
1634
  (children) => updateNodeInTree(children, id, { visible: newVisible })
@@ -1620,6 +1666,7 @@ const useEditorStore = create((set, get) => ({
1620
1666
  group.children.forEach((child) => {
1621
1667
  collectChildren(child);
1622
1668
  });
1669
+ markVisibilityOnlyUpdate();
1623
1670
  let nextCanvas = state.canvas;
1624
1671
  nodeIds.forEach((id) => {
1625
1672
  nextCanvas = updateCurrentPageChildren(
@@ -1891,8 +1938,8 @@ const useEditorStore = create((set, get) => ({
1891
1938
  if (stopMatch) {
1892
1939
  const stopIndex = parseInt(stopMatch[1], 10);
1893
1940
  updatedPages = updatedPages.map((p) => {
1894
- var _a;
1895
- if (!((_a = p.settings.backgroundGradient) == null ? void 0 : _a.stops[stopIndex])) return p;
1941
+ var _a2;
1942
+ if (!((_a2 = p.settings.backgroundGradient) == null ? void 0 : _a2.stops[stopIndex])) return p;
1896
1943
  return {
1897
1944
  ...p,
1898
1945
  settings: {
@@ -1968,8 +2015,8 @@ const useEditorStore = create((set, get) => ({
1968
2015
  if (nodesToGroup.length < 2) return {};
1969
2016
  const parentGroups = topLevelIds.map((id) => findParentGroup(currentPage.children, id));
1970
2017
  const commonParent = parentGroups.length > 0 && parentGroups.every((p) => {
1971
- var _a;
1972
- return (p == null ? void 0 : p.id) === ((_a = parentGroups[0]) == null ? void 0 : _a.id);
2018
+ var _a2;
2019
+ return (p == null ? void 0 : p.id) === ((_a2 = parentGroups[0]) == null ? void 0 : _a2.id);
1973
2020
  }) ? parentGroups[0] : null;
1974
2021
  let insertIndex = void 0;
1975
2022
  if (commonParent && topLevelIds.length > 0) {
@@ -2062,20 +2109,36 @@ const useEditorStore = create((set, get) => ({
2062
2109
  const parentId = (parentGroup == null ? void 0 : parentGroup.id) || null;
2063
2110
  const siblings = parentGroup ? parentGroup.children : currentPage.children;
2064
2111
  const groupIndex = siblings.findIndex((n) => n.id === groupId);
2112
+ const childAbs = group.children.map((c) => getAbsoluteBounds(c, currentPage.children));
2113
+ const followingSiblingAbs = siblings.slice(Math.max(0, groupIndex + 1)).map((sibling) => ({ id: sibling.id, abs: getAbsoluteBounds(sibling, currentPage.children) }));
2065
2114
  let nextChildren = removeNodeFromTree(currentPage.children, groupId);
2066
- const parentAbs = parentId ? getAbsoluteBounds(findNodeById(nextChildren, parentId), nextChildren) : null;
2067
- for (let i = 0; i < group.children.length; i++) {
2115
+ const placeStoredToMatchAbs = (tree, nodeId, target) => {
2116
+ let t = updateNodeInTree(tree, nodeId, { left: 0, top: 0 });
2117
+ const placed = findNodeById(t, nodeId);
2118
+ if (!placed) return t;
2119
+ const cur = getAbsoluteBounds(placed, t);
2120
+ const dl = target.left - cur.left;
2121
+ const dt = target.top - cur.top;
2122
+ return updateNodeInTree(t, nodeId, { left: dl, top: dt });
2123
+ };
2124
+ const insertReversed = parentId === null;
2125
+ const promotionOrder = insertReversed ? group.children.map((_, i) => group.children.length - 1 - i) : group.children.map((_, i) => i);
2126
+ for (let slot = 0; slot < promotionOrder.length; slot++) {
2127
+ const i = promotionOrder[slot];
2068
2128
  const child = group.children[i];
2069
- const abs = getAbsoluteBounds(child, currentPage.children);
2070
- const storeLeft = parentAbs ? abs.left - parentAbs.left : abs.left;
2071
- const storeTop = parentAbs ? abs.top - parentAbs.top : abs.top;
2072
- const childWithPos = isElement(child) ? { ...child, left: storeLeft, top: storeTop } : { ...child, left: storeLeft, top: storeTop };
2073
- nextChildren = addNodeToTree(nextChildren, childWithPos, parentId, groupIndex + i);
2129
+ const abs = childAbs[i];
2130
+ const placeholder = isElement(child) ? { ...child, left: 0, top: 0 } : { ...child, left: 0, top: 0 };
2131
+ nextChildren = addNodeToTree(nextChildren, placeholder, parentId, groupIndex + slot);
2132
+ nextChildren = placeStoredToMatchAbs(nextChildren, child.id, { left: abs.left, top: abs.top });
2133
+ }
2134
+ for (const { id, abs } of followingSiblingAbs) {
2135
+ if (!findNodeById(nextChildren, id)) continue;
2136
+ nextChildren = placeStoredToMatchAbs(nextChildren, id, { left: abs.left, top: abs.top });
2074
2137
  }
2075
2138
  const nextCanvas = updateCurrentPageChildren(state.canvas, () => nextChildren);
2076
2139
  nextCanvas.selectedIds = getAllElementIds(group.children);
2077
2140
  const committed = commitFromState(state, nextCanvas);
2078
- return { canvas: nextCanvas, ...committed };
2141
+ return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };
2079
2142
  }),
2080
2143
  renameNode: (id, name) => set((state) => {
2081
2144
  const nextCanvas = updateCurrentPageChildren(
@@ -2147,7 +2210,7 @@ const useEditorStore = create((set, get) => ({
2147
2210
  return { canvas: nextCanvas, ...committed };
2148
2211
  }),
2149
2212
  deletePage: (pageId) => set((state) => {
2150
- var _a;
2213
+ var _a2;
2151
2214
  if (state.canvas.pages.length <= 1) return {};
2152
2215
  const deletedPage = state.canvas.pages.find((p) => p.id === pageId);
2153
2216
  const newPages = state.canvas.pages.filter((p) => p.id !== pageId);
@@ -2183,7 +2246,7 @@ const useEditorStore = create((set, get) => ({
2183
2246
  };
2184
2247
  }
2185
2248
  }
2186
- if (((_a = nextCanvas.dynamicFields) == null ? void 0 : _a.length) && deletedElementIds.size > 0) {
2249
+ if (((_a2 = nextCanvas.dynamicFields) == null ? void 0 : _a2.length) && deletedElementIds.size > 0) {
2187
2250
  nextCanvas = {
2188
2251
  ...nextCanvas,
2189
2252
  dynamicFields: nextCanvas.dynamicFields.map((f) => ({ ...f, mappings: (f.mappings ?? []).filter((m) => !deletedElementIds.has(m.elementId)) })).filter((f) => (f.mappings ?? []).length > 0)
@@ -2296,7 +2359,7 @@ const useEditorStore = create((set, get) => ({
2296
2359
  return { canvas: nextCanvas, ...committed };
2297
2360
  }),
2298
2361
  updatePageSettings: (pageId, settings) => set((state) => {
2299
- var _a;
2362
+ var _a2;
2300
2363
  const updatedPages = state.canvas.pages.map(
2301
2364
  (p) => p.id === pageId ? { ...p, settings: { ...p.settings, ...settings } } : p
2302
2365
  );
@@ -2315,11 +2378,11 @@ const useEditorStore = create((set, get) => ({
2315
2378
  if ("backgroundGradient" in settings) {
2316
2379
  const grad = settings.backgroundGradient;
2317
2380
  const gradStopProps = themeConfig.properties.filter((p) => {
2318
- var _a2;
2319
- return p.elementId === PAGE_BG_ID && p.targetProperty === "backgroundGradient" && ((_a2 = p.svgColorKey) == null ? void 0 : _a2.startsWith("stop:"));
2381
+ var _a3;
2382
+ return p.elementId === PAGE_BG_ID && p.targetProperty === "backgroundGradient" && ((_a3 = p.svgColorKey) == null ? void 0 : _a3.startsWith("stop:"));
2320
2383
  });
2321
2384
  for (const prop of gradStopProps) {
2322
- const stopMatch = (_a = prop.svgColorKey) == null ? void 0 : _a.match(/^stop:(\d+)$/);
2385
+ const stopMatch = (_a2 = prop.svgColorKey) == null ? void 0 : _a2.match(/^stop:(\d+)$/);
2323
2386
  if (stopMatch && grad) {
2324
2387
  const stopIndex = parseInt(stopMatch[1], 10);
2325
2388
  if (grad.stops[stopIndex]) {
@@ -2456,7 +2519,7 @@ const useEditorStore = create((set, get) => ({
2456
2519
  }),
2457
2520
  // === LOAD/RESET ===
2458
2521
  loadConfig: (config) => set((state) => {
2459
- var _a;
2522
+ var _a2;
2460
2523
  const collapsedGroups = /* @__PURE__ */ new Set();
2461
2524
  const collectCollapsedGroups = (nodes) => {
2462
2525
  for (const node of nodes) {
@@ -2524,7 +2587,7 @@ const useEditorStore = create((set, get) => ({
2524
2587
  width: config.canvas.width,
2525
2588
  height: config.canvas.height,
2526
2589
  pages: pagesWithPositions,
2527
- currentPageId: ((_a = config.pages[0]) == null ? void 0 : _a.id) || "page-1",
2590
+ currentPageId: ((_a2 = config.pages[0]) == null ? void 0 : _a2.id) || "page-1",
2528
2591
  selectedIds: [],
2529
2592
  zoom: 1,
2530
2593
  pan: { x: 0, y: 0 },
@@ -2603,24 +2666,6 @@ const useEditorStore = create((set, get) => ({
2603
2666
  };
2604
2667
  })
2605
2668
  }));
2606
- let canvasRegistry = /* @__PURE__ */ new Map();
2607
- function registerFabricCanvas(pageId, canvas) {
2608
- const existing = canvasRegistry.get(pageId);
2609
- const registryKey = existing && existing !== canvas ? `${pageId}#${Math.random().toString(36).slice(2, 10)}` : pageId;
2610
- canvasRegistry.set(registryKey, canvas);
2611
- return registryKey;
2612
- }
2613
- function unregisterFabricCanvas(pageId, canvas) {
2614
- if (canvas) {
2615
- const existing = canvasRegistry.get(pageId);
2616
- if (existing === canvas) canvasRegistry.delete(pageId);
2617
- return;
2618
- }
2619
- canvasRegistry.delete(pageId);
2620
- }
2621
- function getCanvasForPage(pageId) {
2622
- return canvasRegistry.get(pageId) || null;
2623
- }
2624
2669
  const LOCAL_FONTS = /* @__PURE__ */ new Set([
2625
2670
  // Original local fonts (static TTFs)
2626
2671
  "Playfair Display",
@@ -3284,12 +3329,12 @@ const waitUntilFontsAvailable = async (fontFamilies, options) => {
3284
3329
  }
3285
3330
  };
3286
3331
  const clearFabricCharCache = () => {
3287
- var _a;
3332
+ var _a2;
3288
3333
  const fabricAny = fabric;
3289
3334
  if (fabricAny.cache && typeof fabricAny.cache.clearFontCache === "function") {
3290
3335
  fabricAny.cache.clearFontCache();
3291
3336
  }
3292
- if (((_a = fabricAny.cache) == null ? void 0 : _a.charWidthsCache) instanceof Map) {
3337
+ if (((_a2 = fabricAny.cache) == null ? void 0 : _a2.charWidthsCache) instanceof Map) {
3293
3338
  fabricAny.cache.charWidthsCache.clear();
3294
3339
  }
3295
3340
  if (typeof fabricAny.charWidthsCache === "object" && fabricAny.charWidthsCache !== null) {
@@ -3315,14 +3360,14 @@ const clearFontCacheAndRerender = (canvas, options = {}) => {
3315
3360
  }
3316
3361
  };
3317
3362
  const collectUnderlineMetrics = (obj) => {
3318
- var _a, _b;
3363
+ var _a2, _b;
3319
3364
  if (obj instanceof fabric.Textbox) {
3320
3365
  if (!obj.underline) return [];
3321
3366
  const lineWidths = obj.__lineWidths;
3322
3367
  return [{
3323
3368
  id: getObjectId(obj) ?? null,
3324
3369
  text: (obj.text || "").slice(0, 120),
3325
- textLength: ((_a = obj.text) == null ? void 0 : _a.length) ?? 0,
3370
+ textLength: ((_a2 = obj.text) == null ? void 0 : _a2.length) ?? 0,
3326
3371
  fontFamily: obj.fontFamily,
3327
3372
  fontSize: obj.fontSize,
3328
3373
  fontWeight: obj.fontWeight,
@@ -3344,11 +3389,11 @@ const clearFontCacheAndRerender = (canvas, options = {}) => {
3344
3389
  logUnderlineDebug("before-rerender", beforeMetrics);
3345
3390
  }
3346
3391
  const markDirty = (obj) => {
3347
- var _a;
3392
+ var _a2;
3348
3393
  if (obj instanceof fabric.Textbox) {
3349
3394
  obj.dirty = true;
3350
3395
  } else if (obj instanceof fabric.Group) {
3351
- (_a = obj._objects) == null ? void 0 : _a.forEach(markDirty);
3396
+ (_a2 = obj._objects) == null ? void 0 : _a2.forEach(markDirty);
3352
3397
  obj.dirty = true;
3353
3398
  }
3354
3399
  };
@@ -3360,11 +3405,11 @@ const clearFontCacheAndRerender = (canvas, options = {}) => {
3360
3405
  canvas.requestRenderAll();
3361
3406
  };
3362
3407
  const ensureFontLoaded = async (fontFamily) => {
3363
- var _a, _b, _c;
3408
+ var _a2, _b, _c;
3364
3409
  if (!fontFamily) return;
3365
3410
  if (LOCAL_FONTS.has(fontFamily)) {
3366
3411
  try {
3367
- const isLoaded = (_a = document.fonts) == null ? void 0 : _a.check(`16px "${fontFamily}"`);
3412
+ const isLoaded = (_a2 = document.fonts) == null ? void 0 : _a2.check(`16px "${fontFamily}"`);
3368
3413
  if (isLoaded) return;
3369
3414
  await ((_b = document.fonts) == null ? void 0 : _b.load(`16px "${fontFamily}"`));
3370
3415
  await ((_c = document.fonts) == null ? void 0 : _c.load(`bold 16px "${fontFamily}"`));
@@ -3626,9 +3671,9 @@ async function getNormalizedSvgUrl(imageUrl, colorMap, sourceFormat) {
3626
3671
  return `data:image/svg+xml,${encoded}`;
3627
3672
  }
3628
3673
  async function normalizeSvgImageDimensions(fabricImage, imageUrl, sourceFormat) {
3629
- var _a;
3674
+ var _a2;
3630
3675
  if (!isSvgImage(imageUrl, sourceFormat)) return;
3631
- const el = ((_a = fabricImage.getElement) == null ? void 0 : _a.call(fabricImage)) ?? fabricImage._element;
3676
+ const el = ((_a2 = fabricImage.getElement) == null ? void 0 : _a2.call(fabricImage)) ?? fabricImage._element;
3632
3677
  let w = 0;
3633
3678
  let h = 0;
3634
3679
  const dims = await loadSvgDimensions(imageUrl);
@@ -3681,7 +3726,7 @@ function stabilizePlaceholderGroup(group, width, height) {
3681
3726
  }
3682
3727
  function attachEmptyPlaceholderImage(group, width, height) {
3683
3728
  loadPlaceholderTile().then((htmlImg) => {
3684
- var _a;
3729
+ var _a2;
3685
3730
  const objects = group._objects;
3686
3731
  const bgRect = objects == null ? void 0 : objects.find((obj) => obj.__isPlaceholderFrame);
3687
3732
  if (!bgRect) return;
@@ -3709,7 +3754,7 @@ function attachEmptyPlaceholderImage(group, width, height) {
3709
3754
  }
3710
3755
  stabilizePlaceholderGroup(group, width, height);
3711
3756
  group.dirty = true;
3712
- (_a = group.canvas) == null ? void 0 : _a.requestRenderAll();
3757
+ (_a2 = group.canvas) == null ? void 0 : _a2.requestRenderAll();
3713
3758
  }).catch(() => {
3714
3759
  });
3715
3760
  }
@@ -3861,7 +3906,7 @@ function createImageClipPath(element, imgWidth, imgHeight) {
3861
3906
  }
3862
3907
  }
3863
3908
  async function loadImageAsync(element, placeholder, fc, fabricRef, syncLockedRef, isTransforming) {
3864
- var _a, _b, _c, _d;
3909
+ var _a2, _b, _c, _d;
3865
3910
  const imageUrl = element.src || element.imageUrl;
3866
3911
  if (!imageUrl) return;
3867
3912
  const nextSvgColorMap = element.svgColorMap ? JSON.stringify(element.svgColorMap) : "";
@@ -4023,7 +4068,7 @@ async function loadImageAsync(element, placeholder, fc, fabricRef, syncLockedRef
4023
4068
  let panY = 0.5;
4024
4069
  let zoom = 1;
4025
4070
  if (existingCropGroup) {
4026
- const existingImg = (_a = existingCropGroup.__cropData) == null ? void 0 : _a._img;
4071
+ const existingImg = (_a2 = existingCropGroup.__cropData) == null ? void 0 : _a2._img;
4027
4072
  if (existingImg) {
4028
4073
  panX = ((_b = existingImg._ct) == null ? void 0 : _b.panX) ?? existingImg.__panX ?? 0.5;
4029
4074
  panY = ((_c = existingImg._ct) == null ? void 0 : _c.panY) ?? existingImg.__panY ?? 0.5;
@@ -4104,9 +4149,9 @@ const canvasImageLoader = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.d
4104
4149
  updateEmptyPlaceholderLayout
4105
4150
  }, Symbol.toStringTag, { value: "Module" }));
4106
4151
  const isCropGroup = (obj) => {
4107
- var _a;
4152
+ var _a2;
4108
4153
  const g = obj;
4109
- return Boolean(g && (g.__cropGroup || ((_a = g._ct) == null ? void 0 : _a.isCropGroup)));
4154
+ return Boolean(g && (g.__cropGroup || ((_a2 = g._ct) == null ? void 0 : _a2.isCropGroup)));
4110
4155
  };
4111
4156
  function parseLuminance(fill) {
4112
4157
  if (typeof fill !== "string") return null;
@@ -4214,10 +4259,10 @@ function isLuminanceMaskClipPath(clipPath) {
4214
4259
  return Boolean(clipPath && clipPath.__svgMaskType === "luminance");
4215
4260
  }
4216
4261
  function syncSvgMaskClipPath(cropGroup) {
4217
- var _a, _b;
4262
+ var _a2, _b;
4218
4263
  const clipPath = cropGroup.clipPath;
4219
4264
  if (!isCropGroup(cropGroup)) return;
4220
- const frameW = ((_a = cropGroup._ct) == null ? void 0 : _a.frameW) ?? cropGroup.width ?? 0;
4265
+ const frameW = ((_a2 = cropGroup._ct) == null ? void 0 : _a2.frameW) ?? cropGroup.width ?? 0;
4221
4266
  const frameH = ((_b = cropGroup._ct) == null ? void 0 : _b.frameH) ?? cropGroup.height ?? 0;
4222
4267
  if (frameW <= 0 || frameH <= 0) return;
4223
4268
  if (isSvgMaskClipPath(clipPath)) {
@@ -4242,11 +4287,11 @@ async function detectMaskType(svgUrl) {
4242
4287
  }
4243
4288
  }
4244
4289
  async function applySvgMaskToCropGroup(cropGroup, svgUrl) {
4245
- var _a, _b, _c;
4290
+ var _a2, _b, _c;
4246
4291
  if (!isCropGroup(cropGroup)) {
4247
4292
  throw new Error("Selected object is not a crop group / image");
4248
4293
  }
4249
- const frameW = ((_a = cropGroup._ct) == null ? void 0 : _a.frameW) ?? cropGroup.width ?? 0;
4294
+ const frameW = ((_a2 = cropGroup._ct) == null ? void 0 : _a2.frameW) ?? cropGroup.width ?? 0;
4250
4295
  const frameH = ((_b = cropGroup._ct) == null ? void 0 : _b.frameH) ?? cropGroup.height ?? 0;
4251
4296
  if (frameW <= 0 || frameH <= 0) {
4252
4297
  throw new Error("Crop group has no frame dimensions");
@@ -4333,11 +4378,11 @@ async function buildLuminanceAlphaCanvas(svgUrl, frameW, frameH) {
4333
4378
  return canvas;
4334
4379
  }
4335
4380
  async function applyLuminanceMaskToCropGroup(cropGroup, svgUrl) {
4336
- var _a, _b, _c;
4381
+ var _a2, _b, _c;
4337
4382
  if (!isCropGroup(cropGroup)) {
4338
4383
  throw new Error("Selected object is not a crop group / image");
4339
4384
  }
4340
- const frameW = ((_a = cropGroup._ct) == null ? void 0 : _a.frameW) ?? cropGroup.width ?? 0;
4385
+ const frameW = ((_a2 = cropGroup._ct) == null ? void 0 : _a2.frameW) ?? cropGroup.width ?? 0;
4341
4386
  const frameH = ((_b = cropGroup._ct) == null ? void 0 : _b.frameH) ?? cropGroup.height ?? 0;
4342
4387
  if (frameW <= 0 || frameH <= 0) {
4343
4388
  throw new Error("Crop group has no frame dimensions");
@@ -4387,9 +4432,9 @@ function getAppliedSvgMaskType(obj) {
4387
4432
  return t === "luminance" || t === "shape" ? t : null;
4388
4433
  }
4389
4434
  function clearSvgMaskFromCropGroup(cropGroup) {
4390
- var _a, _b, _c;
4435
+ var _a2, _b, _c;
4391
4436
  if (!isCropGroup(cropGroup)) return;
4392
- const frameW = ((_a = cropGroup._ct) == null ? void 0 : _a.frameW) ?? cropGroup.width ?? 0;
4437
+ const frameW = ((_a2 = cropGroup._ct) == null ? void 0 : _a2.frameW) ?? cropGroup.width ?? 0;
4393
4438
  const frameH = ((_b = cropGroup._ct) == null ? void 0 : _b.frameH) ?? cropGroup.height ?? 0;
4394
4439
  const rect = new fabric.Rect({
4395
4440
  width: frameW,
@@ -4430,10 +4475,11 @@ function clamp$1(v, min, max) {
4430
4475
  function applyControlSizeForZoom(canvas, obj) {
4431
4476
  if (!canvas || !obj) return;
4432
4477
  const z = canvas.getZoom() || 1;
4433
- const size = Math.max(6, Math.round(10 * z));
4478
+ const size = Math.max(6, Math.round(8 * z));
4434
4479
  obj.set({
4435
4480
  cornerSize: size,
4436
- borderScaleFactor: z
4481
+ // Subtle but visible border at any zoom (min ~1.25px).
4482
+ borderScaleFactor: Math.max(1.25, 1.25 * z)
4437
4483
  });
4438
4484
  obj.setCoords();
4439
4485
  }
@@ -4448,7 +4494,7 @@ function finalizeCropGroupCoords(g) {
4448
4494
  g.setCoords();
4449
4495
  }
4450
4496
  function updateCoverLayout(g) {
4451
- var _a;
4497
+ var _a2;
4452
4498
  const ct = g.__cropData;
4453
4499
  if (!ct) return;
4454
4500
  const { frameW, frameH, shape, rx: rxRatio, _img: img, _border: border } = ct;
@@ -4595,7 +4641,7 @@ function updateCoverLayout(g) {
4595
4641
  }
4596
4642
  }
4597
4643
  if (!img) {
4598
- const placeholderFrame = ct._placeholderFrame ?? ((_a = g._objects) == null ? void 0 : _a.find((obj) => obj.__isPlaceholderFrame));
4644
+ const placeholderFrame = ct._placeholderFrame ?? ((_a2 = g._objects) == null ? void 0 : _a2.find((obj) => obj.__isPlaceholderFrame));
4599
4645
  if (placeholderFrame && typeof placeholderFrame.set === "function") {
4600
4646
  placeholderFrame.set({
4601
4647
  width: frameW,
@@ -4731,10 +4777,10 @@ const makeRotatedCursorStyleHandler = (controlKey) => {
4731
4777
  return (_eventData, _control, target) => getRotatedControlCursor(controlKey, target);
4732
4778
  };
4733
4779
  function resizeFrameFromCornerUniform(eventData, transform, _x, _y) {
4734
- var _a;
4780
+ var _a2;
4735
4781
  const g = transform.target;
4736
4782
  const ct = g.__cropData;
4737
- if (!ct || !((_a = g._ct) == null ? void 0 : _a.isCropGroup)) return false;
4783
+ if (!ct || !((_a2 = g._ct) == null ? void 0 : _a2.isCropGroup)) return false;
4738
4784
  const canvas = g.canvas;
4739
4785
  if (!canvas) return false;
4740
4786
  const e = getDomEvent(eventData);
@@ -4830,7 +4876,7 @@ function installCanvaMaskControls(g) {
4830
4876
  cursorStyleHandler: makeRotatedCursorStyleHandler(key),
4831
4877
  actionName: "crop",
4832
4878
  actionHandler: (eventData, transform) => {
4833
- var _a;
4879
+ var _a2;
4834
4880
  const t = transform.target;
4835
4881
  const canvas = t.canvas;
4836
4882
  if (canvas && canvas.__editLockRef) {
@@ -4839,7 +4885,7 @@ function installCanvaMaskControls(g) {
4839
4885
  const { localDx, localDy } = getLocalDeltaStable(t, eventData);
4840
4886
  t.__lockScaleDuringCrop = true;
4841
4887
  resizeFrameFromSide(t, side, localDx, localDy);
4842
- (_a = t.canvas) == null ? void 0 : _a.requestRenderAll();
4888
+ (_a2 = t.canvas) == null ? void 0 : _a2.requestRenderAll();
4843
4889
  return true;
4844
4890
  }
4845
4891
  });
@@ -5415,7 +5461,7 @@ function enterCropMode(g) {
5415
5461
  return true;
5416
5462
  }
5417
5463
  function exitCropMode(g, commit = true) {
5418
- var _a;
5464
+ var _a2;
5419
5465
  if (!g[CROP_MODE_FLAG]) return;
5420
5466
  const canvas = g.canvas;
5421
5467
  const handlers = g[CROP_HANDLERS_FLAG];
@@ -5425,7 +5471,7 @@ function exitCropMode(g, commit = true) {
5425
5471
  canvas.off("mouse:down:before", handlers.onCanvasMouseDown);
5426
5472
  if (handlers.onDblClick) canvas.off("mouse:dblclick", handlers.onDblClick);
5427
5473
  window.removeEventListener("keydown", handlers.onKeyDown, true);
5428
- (_a = handlers.upperCanvasEl) == null ? void 0 : _a.removeEventListener("wheel", handlers.onWheel);
5474
+ (_a2 = handlers.upperCanvasEl) == null ? void 0 : _a2.removeEventListener("wheel", handlers.onWheel);
5429
5475
  }
5430
5476
  g[CROP_HANDLERS_FLAG] = void 0;
5431
5477
  const ghost = g[CROP_GHOST_FLAG];
@@ -5878,6 +5924,18 @@ const hasActiveTextPath = (obj) => {
5878
5924
  const tp = obj.textPath;
5879
5925
  return !!tp && !!tp.preset && tp.preset !== "none";
5880
5926
  };
5927
+ const shouldShowOriginalTextBounds = () => {
5928
+ var _a2;
5929
+ try {
5930
+ return typeof window !== "undefined" && ((_a2 = window.localStorage) == null ? void 0 : _a2.getItem("pixldocs:showOriginalTextBounds")) === "1";
5931
+ } catch {
5932
+ return false;
5933
+ }
5934
+ };
5935
+ const hasActiveTextPathDescendant = (obj) => {
5936
+ const kids = (obj == null ? void 0 : obj._objects) || [];
5937
+ return kids.some((child) => hasActiveTextPath(child) || hasActiveTextPathDescendant(child));
5938
+ };
5881
5939
  function applyWarpFillStyle(ctx, obj) {
5882
5940
  const filler = obj.fill;
5883
5941
  if (filler && typeof filler === "object" && Array.isArray(filler.colorStops) && filler.coords) {
@@ -6012,8 +6070,8 @@ function vectorFromFrozenMatrix(matrix, dx, dy) {
6012
6070
  return new fabric.Point(matrix[0] * dx + matrix[2] * dy, matrix[1] * dx + matrix[3] * dy);
6013
6071
  }
6014
6072
  function scaleLocalToScreen(target, p) {
6015
- var _a;
6016
- const vpt = ((_a = target == null ? void 0 : target.canvas) == null ? void 0 : _a.viewportTransform) || [1, 0, 0, 1, 0, 0];
6073
+ var _a2;
6074
+ const vpt = ((_a2 = target == null ? void 0 : target.canvas) == null ? void 0 : _a2.viewportTransform) || [1, 0, 0, 1, 0, 0];
6017
6075
  const zx = Math.abs(vpt[0] || 1);
6018
6076
  const zy = Math.abs(vpt[3] || 1);
6019
6077
  const sx = Math.abs((target == null ? void 0 : target.scaleX) || 1);
@@ -6021,14 +6079,14 @@ function scaleLocalToScreen(target, p) {
6021
6079
  return new fabric.Point(p.x * sx * zx, p.y * sy * zy);
6022
6080
  }
6023
6081
  function applyTextPathControls(textbox) {
6024
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
6082
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
6025
6083
  const obj = textbox;
6026
6084
  if (!hasActiveTextPath(obj)) {
6027
6085
  obj.__pdTextPathHovered = false;
6028
6086
  if (obj.__pdTextPathControls) {
6029
6087
  try {
6030
6088
  const cu2 = fabric.controlsUtils;
6031
- 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));
6089
+ 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));
6032
6090
  if (defaults) obj.controls = defaults;
6033
6091
  } catch {
6034
6092
  }
@@ -6053,43 +6111,23 @@ function applyTextPathControls(textbox) {
6053
6111
  }
6054
6112
  if (!obj.__pdTextPathHoverWired) {
6055
6113
  obj.on("mouseover", () => {
6056
- var _a2;
6114
+ var _a3;
6057
6115
  if (!hasActiveTextPath(obj)) return;
6058
6116
  obj.__pdTextPathHovered = true;
6059
- (_a2 = obj.canvas) == null ? void 0 : _a2.requestRenderAll();
6117
+ (_a3 = obj.canvas) == null ? void 0 : _a3.requestRenderAll();
6060
6118
  });
6061
6119
  obj.on("mouseout", () => {
6062
- var _a2;
6120
+ var _a3;
6063
6121
  obj.__pdTextPathHovered = false;
6064
- (_a2 = obj.canvas) == null ? void 0 : _a2.requestRenderAll();
6122
+ (_a3 = obj.canvas) == null ? void 0 : _a3.requestRenderAll();
6065
6123
  });
6066
6124
  obj.__pdTextPathHoverWired = true;
6067
6125
  }
6068
- obj.controls = {};
6126
+ const cu = fabric.controlsUtils;
6127
+ 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)) ?? {};
6128
+ obj.controls = { ...defaultControls };
6069
6129
  const halfWOf = (t) => (t.width || 0) / 2;
6070
6130
  const halfHOf = (t) => (t.height || 0) / 2;
6071
- const cu = fabric.controlsUtils;
6072
- const renderRotation = (ctx, left, top) => {
6073
- ctx.save();
6074
- ctx.translate(left, top);
6075
- ctx.shadowColor = "rgba(0,0,0,0.25)";
6076
- ctx.shadowBlur = 2;
6077
- ctx.shadowOffsetY = 0.5;
6078
- ctx.fillStyle = "#ffffff";
6079
- ctx.strokeStyle = "#1d9bf0";
6080
- ctx.lineWidth = 1.5;
6081
- ctx.beginPath();
6082
- ctx.arc(0, 0, 6, 0, Math.PI * 2);
6083
- ctx.fill();
6084
- ctx.shadowColor = "transparent";
6085
- ctx.stroke();
6086
- ctx.strokeStyle = "#1d9bf0";
6087
- ctx.lineWidth = 1.25;
6088
- ctx.beginPath();
6089
- ctx.arc(0, 0, 3, -Math.PI * 0.85, Math.PI * 0.75);
6090
- ctx.stroke();
6091
- ctx.restore();
6092
- };
6093
6131
  const renderPivot = (ctx, left, top) => {
6094
6132
  ctx.save();
6095
6133
  ctx.translate(left, top);
@@ -6113,17 +6151,7 @@ function applyTextPathControls(textbox) {
6113
6151
  ctx.restore();
6114
6152
  };
6115
6153
  const addRotationAndPivot = () => {
6116
- var _a2, _b2;
6117
- obj.controls.tpRot = new fabric.Control({
6118
- x: 0,
6119
- y: -0.5,
6120
- offsetY: -28,
6121
- cursorStyleHandler: cu == null ? void 0 : cu.rotationStyleHandler,
6122
- actionHandler: cu == null ? void 0 : cu.rotationWithSnapping,
6123
- actionName: "rotate",
6124
- render: renderRotation,
6125
- withConnection: false
6126
- });
6154
+ var _a3;
6127
6155
  obj.controls.tpPivot = new fabric.Control({
6128
6156
  x: 0,
6129
6157
  y: 0,
@@ -6132,10 +6160,9 @@ function applyTextPathControls(textbox) {
6132
6160
  actionHandler: () => false,
6133
6161
  render: renderPivot
6134
6162
  });
6135
- (_a2 = obj.setControlVisible) == null ? void 0 : _a2.call(obj, "tpRot", true);
6136
- (_b2 = obj.setControlVisible) == null ? void 0 : _b2.call(obj, "tpPivot", true);
6163
+ (_a3 = obj.setControlVisible) == null ? void 0 : _a3.call(obj, "tpPivot", true);
6137
6164
  };
6138
- if (((_d = obj.textPath) == null ? void 0 : _d.preset) === "circle") {
6165
+ if (((_f = obj.textPath) == null ? void 0 : _f.preset) === "circle") {
6139
6166
  const getRadius = (target) => {
6140
6167
  const tp = target.textPath || {};
6141
6168
  const fs = target.fontSize || 16;
@@ -6145,14 +6172,14 @@ function applyTextPathControls(textbox) {
6145
6172
  return Math.max(fs * 0.75, Number.isFinite(r) && r > 0 ? r : auto);
6146
6173
  };
6147
6174
  const setRadius = (target, r) => {
6148
- var _a2;
6175
+ var _a3;
6149
6176
  const fs = target.fontSize || 16;
6150
6177
  const clamped = Math.max(fs * 0.75, r);
6151
6178
  if (!target.textPath) target.textPath = { preset: "circle" };
6152
6179
  target.textPath.preset = "circle";
6153
6180
  target.textPath.radius = clamped;
6154
6181
  target.dirty = true;
6155
- (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6182
+ (_a3 = target.canvas) == null ? void 0 : _a3.requestRenderAll();
6156
6183
  };
6157
6184
  const ringPoint = (target, dir) => {
6158
6185
  const r = getRadius(target);
@@ -6223,11 +6250,111 @@ function applyTextPathControls(textbox) {
6223
6250
  obj.controls.crE = new fabric.Control({ x: 0.5, y: 0, cursorStyle: "ew-resize", actionName: "textPath", actionHandler: dragRadius("E"), positionHandler: positionAtRing("E"), render: renderRingHandle });
6224
6251
  obj.controls.crS = new fabric.Control({ x: 0, y: 0.5, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragRadius("S"), positionHandler: positionAtRing("S"), render: renderRingHandle });
6225
6252
  obj.controls.crW = new fabric.Control({ x: -0.5, y: 0, cursorStyle: "ew-resize", actionName: "textPath", actionHandler: dragRadius("W"), positionHandler: positionAtRing("W"), render: renderRingHandle });
6226
- (_e = obj.setControlVisible) == null ? void 0 : _e.call(obj, "crN", true);
6227
- (_f = obj.setControlVisible) == null ? void 0 : _f.call(obj, "crE", true);
6228
- (_g = obj.setControlVisible) == null ? void 0 : _g.call(obj, "crS", true);
6229
- (_h = obj.setControlVisible) == null ? void 0 : _h.call(obj, "crW", true);
6253
+ (_g = obj.setControlVisible) == null ? void 0 : _g.call(obj, "crN", true);
6254
+ (_h = obj.setControlVisible) == null ? void 0 : _h.call(obj, "crE", true);
6255
+ (_i = obj.setControlVisible) == null ? void 0 : _i.call(obj, "crS", true);
6256
+ (_j = obj.setControlVisible) == null ? void 0 : _j.call(obj, "crW", true);
6230
6257
  addRotationAndPivot();
6258
+ const getPivotLocalCentered = (target) => {
6259
+ var _a3;
6260
+ const r = getRadius(target);
6261
+ const cx = r - halfWOf(target);
6262
+ const cy = r - halfHOf(target);
6263
+ const off = (_a3 = target.textPath) == null ? void 0 : _a3.pivot;
6264
+ const ox = off && Number.isFinite(off.x) ? off.x : 0;
6265
+ const oy = off && Number.isFinite(off.y) ? off.y : 0;
6266
+ return new fabric.Point(cx + ox, cy + oy);
6267
+ };
6268
+ const pivotInCanvas = (target) => {
6269
+ const p = getPivotLocalCentered(target);
6270
+ const m = target.calcTransformMatrix();
6271
+ return fabric.util.transformPoint(p, m);
6272
+ };
6273
+ obj.controls.tpPivot = new fabric.Control({
6274
+ x: 0,
6275
+ y: 0,
6276
+ cursorStyle: "move",
6277
+ actionName: "tpPivot",
6278
+ positionHandler: (_d2, finalMatrix, fabricObject) => scaleLocalToScreen(fabricObject, getPivotLocalCentered(fabricObject)).transform(finalMatrix),
6279
+ actionHandler: (_e2, transform, x, y) => {
6280
+ var _a3, _b2;
6281
+ const target = transform.target;
6282
+ const state = transform.__pdCirclePivotDrag || (transform.__pdCirclePivotDrag = {
6283
+ startMatrix: target.calcTransformMatrix(),
6284
+ startOffset: { ...((_a3 = target.textPath) == null ? void 0 : _a3.pivot) || { x: 0, y: 0 } },
6285
+ startLocal: null
6286
+ });
6287
+ if (!state.startLocal) state.startLocal = localPointFromFrozenMatrix(target, x, y, state.startMatrix);
6288
+ const local = localPointFromFrozenMatrix(target, x, y, state.startMatrix);
6289
+ const dx = local.x - state.startLocal.x;
6290
+ const dy = local.y - state.startLocal.y;
6291
+ if (!target.textPath) target.textPath = { preset: "circle" };
6292
+ target.textPath.pivot = {
6293
+ x: (state.startOffset.x || 0) + dx,
6294
+ y: (state.startOffset.y || 0) + dy
6295
+ };
6296
+ target.setCoords();
6297
+ (_b2 = target.canvas) == null ? void 0 : _b2.requestRenderAll();
6298
+ return true;
6299
+ },
6300
+ render: renderPivot
6301
+ });
6302
+ (_k = obj.setControlVisible) == null ? void 0 : _k.call(obj, "tpPivot", true);
6303
+ if (obj.controls.mtr) {
6304
+ const ROT_OFFSET_PX = 40;
6305
+ obj.controls.mtr.positionHandler = (_d2, finalMatrix, fabricObject) => {
6306
+ const t = fabricObject;
6307
+ const b = computeCircleWarpBoundsLocal(t);
6308
+ const topCenterLocal = b ? new fabric.Point((b.minX + b.maxX) / 2, b.minY) : new fabric.Point(0, -(t.height || 0) / 2);
6309
+ const screen = scaleLocalToScreen(t, topCenterLocal);
6310
+ return new fabric.Point(screen.x, screen.y - ROT_OFFSET_PX).transform(finalMatrix);
6311
+ };
6312
+ obj.controls.mtr.actionHandler = (eventData, transform, x, y) => {
6313
+ var _a3;
6314
+ const target = transform.target;
6315
+ const state = transform.__pdCirclePivotRot || (transform.__pdCirclePivotRot = {
6316
+ pivot: pivotInCanvas(target),
6317
+ startAngleDeg: target.angle || 0,
6318
+ startCenter: target.getCenterPoint(),
6319
+ startPointerAngle: Math.atan2(
6320
+ (transform.ey ?? y) - pivotInCanvas(target).y,
6321
+ (transform.ex ?? x) - pivotInCanvas(target).x
6322
+ )
6323
+ });
6324
+ const curAngle = Math.atan2(y - state.pivot.y, x - state.pivot.x);
6325
+ const dRad = curAngle - state.startPointerAngle;
6326
+ const cos = Math.cos(dRad);
6327
+ const sin = Math.sin(dRad);
6328
+ const dx = state.startCenter.x - state.pivot.x;
6329
+ const dy = state.startCenter.y - state.pivot.y;
6330
+ const newCenter = new fabric.Point(
6331
+ state.pivot.x + dx * cos - dy * sin,
6332
+ state.pivot.y + dx * sin + dy * cos
6333
+ );
6334
+ let newAngleDeg = state.startAngleDeg + dRad * 180 / Math.PI;
6335
+ if (eventData && eventData.shiftKey) {
6336
+ newAngleDeg = Math.round(newAngleDeg / 15) * 15;
6337
+ }
6338
+ target.angle = newAngleDeg;
6339
+ target.setPositionByOrigin(newCenter, "center", "center");
6340
+ target.setCoords();
6341
+ (_a3 = target.canvas) == null ? void 0 : _a3.requestRenderAll();
6342
+ return true;
6343
+ };
6344
+ (_l = obj.setControlVisible) == null ? void 0 : _l.call(obj, "mtr", true);
6345
+ }
6346
+ if (!obj.__pdCirclePivotDblWired) {
6347
+ obj.on("mousedblclick", () => {
6348
+ var _a3, _b2;
6349
+ if (((_a3 = obj.textPath) == null ? void 0 : _a3.preset) !== "circle") return;
6350
+ if (obj.__corner !== "tpPivot") return;
6351
+ if (!obj.textPath.pivot) return;
6352
+ obj.textPath.pivot = { x: 0, y: 0 };
6353
+ obj.setCoords();
6354
+ (_b2 = obj.canvas) == null ? void 0 : _b2.requestRenderAll();
6355
+ });
6356
+ obj.__pdCirclePivotDblWired = true;
6357
+ }
6231
6358
  obj.hasBorders = false;
6232
6359
  obj.hasControls = true;
6233
6360
  obj.objectCaching = false;
@@ -6235,7 +6362,7 @@ function applyTextPathControls(textbox) {
6235
6362
  obj.setCoords();
6236
6363
  return;
6237
6364
  }
6238
- if (((_i = obj.textPath) == null ? void 0 : _i.preset) === "rise") {
6365
+ if (((_m = obj.textPath) == null ? void 0 : _m.preset) === "rise") {
6239
6366
  const getEndpoints = (target) => {
6240
6367
  const w = target.width || 0;
6241
6368
  const fs = target.fontSize || 16;
@@ -6252,7 +6379,7 @@ function applyTextPathControls(textbox) {
6252
6379
  return { leftY, centerY, rightY };
6253
6380
  };
6254
6381
  const setEndpoints = (target, next) => {
6255
- var _a2;
6382
+ var _a3;
6256
6383
  target.width || 1;
6257
6384
  target.fontSize || 16;
6258
6385
  const lineMid = (next.leftY + next.rightY) / 2;
@@ -6266,7 +6393,7 @@ function applyTextPathControls(textbox) {
6266
6393
  };
6267
6394
  if (target.skewY) target.set("skewY", 0);
6268
6395
  target.dirty = true;
6269
- (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6396
+ (_a3 = target.canvas) == null ? void 0 : _a3.requestRenderAll();
6270
6397
  };
6271
6398
  const positionAtAngleHandle = (key) => (_d2, finalMatrix, target) => {
6272
6399
  const ep = getEndpoints(target);
@@ -6300,8 +6427,8 @@ function applyTextPathControls(textbox) {
6300
6427
  if (obj.skewY) obj.set("skewY", 0);
6301
6428
  obj.controls.rsL = new fabric.Control({ x: -0.5, y: 0, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragAngleHandle("leftY"), positionHandler: positionAtAngleHandle("leftY"), render: renderAngleHandle });
6302
6429
  obj.controls.rsR = new fabric.Control({ x: 0.5, y: 0, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragAngleHandle("rightY"), positionHandler: positionAtAngleHandle("rightY"), render: renderAngleHandle });
6303
- (_j = obj.setControlVisible) == null ? void 0 : _j.call(obj, "rsL", true);
6304
- (_k = obj.setControlVisible) == null ? void 0 : _k.call(obj, "rsR", true);
6430
+ (_n = obj.setControlVisible) == null ? void 0 : _n.call(obj, "rsL", true);
6431
+ (_o = obj.setControlVisible) == null ? void 0 : _o.call(obj, "rsR", true);
6305
6432
  addRotationAndPivot();
6306
6433
  obj.hasBorders = false;
6307
6434
  obj.hasControls = true;
@@ -6388,7 +6515,7 @@ function applyTextPathControls(textbox) {
6388
6515
  return scaleLocalToScreen(target, new fabric.Point(px - halfWOf(target), py - halfHOf(target))).transform(finalMatrix);
6389
6516
  };
6390
6517
  const makeMidTangentDrag = (side) => (_e2, transform, x, y) => {
6391
- var _a2;
6518
+ var _a3;
6392
6519
  const target = transform.target;
6393
6520
  const local = localPointFromCanvas(target, x, y);
6394
6521
  const current = ensureBezier(target);
@@ -6415,11 +6542,11 @@ function applyTextPathControls(textbox) {
6415
6542
  bz.c1 = apply(bz.c1[0], bz.c1[1]);
6416
6543
  target.textPath = { ...target.textPath || { preset: "custom" }, bezier: bz };
6417
6544
  target.dirty = true;
6418
- (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6545
+ (_a3 = target.canvas) == null ? void 0 : _a3.requestRenderAll();
6419
6546
  return true;
6420
6547
  };
6421
6548
  const makeDrag = (key) => (_e2, transform, x, y) => {
6422
- var _a2;
6549
+ var _a3;
6423
6550
  const target = transform.target;
6424
6551
  const local = localPointFromCanvas(target, x, y);
6425
6552
  const current = ensureBezier(target);
@@ -6437,11 +6564,11 @@ function applyTextPathControls(textbox) {
6437
6564
  }
6438
6565
  target.textPath = { ...target.textPath || { preset: "custom" }, bezier: bz };
6439
6566
  target.dirty = true;
6440
- (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6567
+ (_a3 = target.canvas) == null ? void 0 : _a3.requestRenderAll();
6441
6568
  return true;
6442
6569
  };
6443
6570
  const makeMidDrag = () => (_e2, transform, x, y) => {
6444
- var _a2;
6571
+ var _a3;
6445
6572
  const target = transform.target;
6446
6573
  const local = localPointFromCanvas(target, x, y);
6447
6574
  const current = ensureBezier(target);
@@ -6458,7 +6585,7 @@ function applyTextPathControls(textbox) {
6458
6585
  bz.c1 = [bz.c1[0] + dx, bz.c1[1] + dy];
6459
6586
  target.textPath = { ...target.textPath || { preset: "custom" }, bezier: bz };
6460
6587
  target.dirty = true;
6461
- (_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
6588
+ (_a3 = target.canvas) == null ? void 0 : _a3.requestRenderAll();
6462
6589
  return true;
6463
6590
  };
6464
6591
  const renderAnchor = (ctx, left, top) => {
@@ -6500,13 +6627,13 @@ function applyTextPathControls(textbox) {
6500
6627
  obj.controls.bzMid = new fabric.Control({ x: 0, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeMidDrag(), positionHandler: positionAtMid, render: renderAnchor });
6501
6628
  obj.controls.bzMidT0 = new fabric.Control({ x: 0, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeMidTangentDrag(-1), positionHandler: positionAtMidTangent(-1), render: renderControlHandle });
6502
6629
  obj.controls.bzMidT1 = new fabric.Control({ x: 0, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeMidTangentDrag(1), positionHandler: positionAtMidTangent(1), render: renderControlHandle });
6503
- (_l = obj.setControlVisible) == null ? void 0 : _l.call(obj, "bzP0", true);
6504
- (_m = obj.setControlVisible) == null ? void 0 : _m.call(obj, "bzC0", true);
6505
- (_n = obj.setControlVisible) == null ? void 0 : _n.call(obj, "bzC1", true);
6506
- (_o = obj.setControlVisible) == null ? void 0 : _o.call(obj, "bzP1", true);
6507
- (_p = obj.setControlVisible) == null ? void 0 : _p.call(obj, "bzMid", true);
6508
- (_q = obj.setControlVisible) == null ? void 0 : _q.call(obj, "bzMidT0", true);
6509
- (_r = obj.setControlVisible) == null ? void 0 : _r.call(obj, "bzMidT1", true);
6630
+ (_p = obj.setControlVisible) == null ? void 0 : _p.call(obj, "bzP0", true);
6631
+ (_q = obj.setControlVisible) == null ? void 0 : _q.call(obj, "bzC0", true);
6632
+ (_r = obj.setControlVisible) == null ? void 0 : _r.call(obj, "bzC1", true);
6633
+ (_s = obj.setControlVisible) == null ? void 0 : _s.call(obj, "bzP1", true);
6634
+ (_t = obj.setControlVisible) == null ? void 0 : _t.call(obj, "bzMid", true);
6635
+ (_u = obj.setControlVisible) == null ? void 0 : _u.call(obj, "bzMidT0", true);
6636
+ (_v = obj.setControlVisible) == null ? void 0 : _v.call(obj, "bzMidT1", true);
6510
6637
  addRotationAndPivot();
6511
6638
  obj.hasBorders = false;
6512
6639
  obj.hasControls = true;
@@ -6514,6 +6641,29 @@ function applyTextPathControls(textbox) {
6514
6641
  obj.setCoords();
6515
6642
  }
6516
6643
  function computeWarpBoundsLocal(obj) {
6644
+ const tp = obj.textPath;
6645
+ if (tp && (tp.preset === "rise" || tp.preset === "angle")) {
6646
+ const w = obj.width || 0;
6647
+ const h = obj.height || 0;
6648
+ const fs2 = obj.fontSize || 16;
6649
+ const ep = tp.endpoints;
6650
+ const defaultLeftY = fs2 * 1.5;
6651
+ const defaultRightY = fs2 * 0.5;
6652
+ const leftY = ep && Number.isFinite(ep.leftY) ? ep.leftY : defaultLeftY;
6653
+ const rightY = ep && Number.isFinite(ep.rightY) ? ep.rightY : defaultRightY;
6654
+ const slope = w > 0 ? (rightY - leftY) / w : 0;
6655
+ const dy = (leftY + rightY) / 2 - h / 2;
6656
+ const halfW2 = w / 2;
6657
+ const halfH2 = h / 2;
6658
+ const yShift = Math.abs(slope) * halfW2;
6659
+ const pad = fs2 * 0.15;
6660
+ return {
6661
+ minX: -halfW2 - pad,
6662
+ maxX: halfW2 + pad,
6663
+ minY: -halfH2 + dy - yShift - pad,
6664
+ maxY: halfH2 + dy + yShift + pad
6665
+ };
6666
+ }
6517
6667
  const resolved = resolveTextPath(obj.textPath, obj.width || 0, obj.fontSize || 16);
6518
6668
  const path = resolved ? measurePath(resolved.d) : null;
6519
6669
  if (!path) return null;
@@ -6539,8 +6689,8 @@ function computeWarpBoundsLocal(obj) {
6539
6689
  };
6540
6690
  }
6541
6691
  function computeCircleWarpBoundsLocal(obj) {
6542
- var _a;
6543
- if (((_a = obj.textPath) == null ? void 0 : _a.preset) !== "circle") return null;
6692
+ var _a2;
6693
+ if (((_a2 = obj.textPath) == null ? void 0 : _a2.preset) !== "circle") return null;
6544
6694
  const fs = obj.fontSize || 16;
6545
6695
  const w = obj.width || 0;
6546
6696
  const auto = Math.max(fs * 1.5, w / Math.PI);
@@ -6550,11 +6700,12 @@ function computeCircleWarpBoundsLocal(obj) {
6550
6700
  const halfH = (obj.height || 0) / 2;
6551
6701
  const cx = r - halfW;
6552
6702
  const cy = r - halfH;
6553
- 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 };
6703
+ const pad = fs * 0.85;
6704
+ return { minX: cx - r - pad, maxX: cx + r + pad, minY: cy - r - pad, maxY: cy + r + pad };
6554
6705
  }
6555
6706
  function getTextPathHitBounds(obj) {
6556
- var _a;
6557
- return ((_a = obj.textPath) == null ? void 0 : _a.preset) === "circle" ? computeCircleWarpBoundsLocal(obj) : computeWarpBoundsLocal(obj);
6707
+ var _a2;
6708
+ return ((_a2 = obj.textPath) == null ? void 0 : _a2.preset) === "circle" ? computeCircleWarpBoundsLocal(obj) : computeWarpBoundsLocal(obj);
6558
6709
  }
6559
6710
  function textPathBoundsContainScenePoint(obj, point) {
6560
6711
  const bounds = getTextPathHitBounds(obj);
@@ -6567,11 +6718,12 @@ function textPathBoundsContainScenePoint(obj, point) {
6567
6718
  return false;
6568
6719
  }
6569
6720
  }
6570
- function drawTextPathBounds(ctx, obj, bounds) {
6571
- var _a;
6572
- if (!obj.canvas) return;
6573
- const retina = ((_a = obj.getCanvasRetinaScaling) == null ? void 0 : _a.call(obj)) || 1;
6574
- const matrix = fabric.util.multiplyTransformMatrices(obj.canvas.viewportTransform || [1, 0, 0, 1, 0, 0], obj.calcTransformMatrix());
6721
+ function drawTextPathBounds(ctx, obj, bounds, hostCanvas) {
6722
+ var _a2, _b, _c;
6723
+ const host = hostCanvas || obj.canvas || ((_a2 = obj.group) == null ? void 0 : _a2.canvas);
6724
+ if (!host) return;
6725
+ const retina = ((_b = host.getRetinaScaling) == null ? void 0 : _b.call(host)) || ((_c = obj.getCanvasRetinaScaling) == null ? void 0 : _c.call(obj)) || 1;
6726
+ const matrix = fabric.util.multiplyTransformMatrices(host.viewportTransform || [1, 0, 0, 1, 0, 0], obj.calcTransformMatrix());
6575
6727
  const corners = [
6576
6728
  new fabric.Point(bounds.minX, bounds.minY),
6577
6729
  new fabric.Point(bounds.maxX, bounds.minY),
@@ -6592,20 +6744,23 @@ function drawTextPathBounds(ctx, obj, bounds) {
6592
6744
  }
6593
6745
  if (typeof TextboxProto._renderControls === "function" && !TextboxProto.__pixldocsOrigRenderControls) {
6594
6746
  let drawWarpGuides = function(ctx) {
6595
- var _a, _b, _c, _d, _e, _f, _g;
6596
- if (!this.canvas) return;
6747
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
6748
+ 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);
6749
+ if (!hostCanvas) return;
6597
6750
  const hoverBounds = getTextPathHitBounds(this);
6598
- if (hoverBounds && (this.__pdTextPathHovered || ((_b = (_a = this.canvas).getActiveObject) == null ? void 0 : _b.call(_a)) === this)) {
6599
- drawTextPathBounds(ctx, this, hoverBounds);
6751
+ const active = (_d = hostCanvas.getActiveObject) == null ? void 0 : _d.call(hostCanvas);
6752
+ const isActiveOrInActive = active === this || !!active && typeof active.contains === "function" && active.contains(this, true);
6753
+ if (hoverBounds && (this.__pdTextPathHovered || isActiveOrInActive)) {
6754
+ drawTextPathBounds(ctx, this, hoverBounds, hostCanvas);
6600
6755
  }
6601
6756
  const resolved = resolveTextPath(this.textPath, this.width || 0, this.fontSize || 16);
6602
6757
  const path = resolved ? measurePath(resolved.d) : null;
6603
6758
  if (!path) return;
6604
6759
  const len = path.getTotalLength();
6605
6760
  if (!Number.isFinite(len) || len <= 0) return;
6606
- const retina = ((_c = this.getCanvasRetinaScaling) == null ? void 0 : _c.call(this)) || 1;
6761
+ const retina = ((_e = hostCanvas.getRetinaScaling) == null ? void 0 : _e.call(hostCanvas)) || ((_f = this.getCanvasRetinaScaling) == null ? void 0 : _f.call(this)) || 1;
6607
6762
  const matrix = fabric.util.multiplyTransformMatrices(
6608
- this.canvas.viewportTransform || [1, 0, 0, 1, 0, 0],
6763
+ hostCanvas.viewportTransform || [1, 0, 0, 1, 0, 0],
6609
6764
  this.calcTransformMatrix()
6610
6765
  );
6611
6766
  const halfW = (this.width || 0) / 2;
@@ -6617,8 +6772,8 @@ if (typeof TextboxProto._renderControls === "function" && !TextboxProto.__pixldo
6617
6772
  const toScreenXY = (x, y) => fabric.util.transformPoint(new fabric.Point(x, y), matrix);
6618
6773
  ctx.save();
6619
6774
  ctx.setTransform(retina, 0, 0, retina, 0, 0);
6620
- const isCircle = ((_d = this.textPath) == null ? void 0 : _d.preset) === "circle";
6621
- const isAngle = ((_e = this.textPath) == null ? void 0 : _e.preset) === "rise" || ((_f = this.textPath) == null ? void 0 : _f.preset) === "angle";
6775
+ const isCircle = ((_g = this.textPath) == null ? void 0 : _g.preset) === "circle";
6776
+ const isAngle = ((_h = this.textPath) == null ? void 0 : _h.preset) === "rise" || ((_i = this.textPath) == null ? void 0 : _i.preset) === "angle";
6622
6777
  ctx.strokeStyle = "rgba(29, 155, 240, 0.95)";
6623
6778
  ctx.lineWidth = 1.25;
6624
6779
  ctx.setLineDash([]);
@@ -6664,7 +6819,7 @@ if (typeof TextboxProto._renderControls === "function" && !TextboxProto.__pixldo
6664
6819
  ctx.closePath();
6665
6820
  ctx.stroke();
6666
6821
  }
6667
- const bz = isCircle ? null : (_g = this.textPath) == null ? void 0 : _g.bezier;
6822
+ const bz = isCircle ? null : (_j = this.textPath) == null ? void 0 : _j.bezier;
6668
6823
  if (bz) {
6669
6824
  const a = toScreenXY(bz.p0[0] - halfW, bz.p0[1] - halfH);
6670
6825
  const ah = toScreenXY(bz.c0[0] - halfW, bz.c0[1] - halfH);
@@ -6704,13 +6859,28 @@ if (typeof TextboxProto._renderControls === "function" && !TextboxProto.__pixldo
6704
6859
  TextboxProto.__pixldocsOrigRenderControls = TextboxProto._renderControls;
6705
6860
  TextboxProto._renderControls = function(ctx, styleOverride) {
6706
6861
  if (hasActiveTextPath(this)) {
6862
+ const showOrig = shouldShowOriginalTextBounds();
6707
6863
  const prevBorders = this.hasBorders;
6708
- this.hasBorders = false;
6864
+ const prevBorderColor = this.borderColor;
6865
+ const prevControls = this.controls;
6866
+ if (!showOrig) {
6867
+ this.hasBorders = false;
6868
+ this.borderColor = "rgba(0,0,0,0)";
6869
+ const filtered = {};
6870
+ for (const key of Object.keys(prevControls || {})) {
6871
+ if (key === "mtr" || key === "tpPivot" || key.startsWith("cr") || key.startsWith("rs") || key.startsWith("bz")) {
6872
+ filtered[key] = prevControls[key];
6873
+ }
6874
+ }
6875
+ this.controls = filtered;
6876
+ }
6709
6877
  try {
6710
6878
  drawWarpGuides.call(this, ctx);
6711
6879
  TextboxProto.__pixldocsOrigRenderControls.call(this, ctx, styleOverride);
6712
6880
  } finally {
6713
6881
  this.hasBorders = prevBorders;
6882
+ this.borderColor = prevBorderColor;
6883
+ this.controls = prevControls;
6714
6884
  }
6715
6885
  return;
6716
6886
  }
@@ -6805,6 +6975,50 @@ if (!TextboxProto.__pixldocsOrigRender && typeof TextboxProto._render === "funct
6805
6975
  };
6806
6976
  }
6807
6977
  TextboxProto.__pixldocsTextboxExtended = true;
6978
+ const GroupProto = (_a = fabric.Group) == null ? void 0 : _a.prototype;
6979
+ if (GroupProto && typeof GroupProto._renderControls === "function" && !GroupProto.__pixldocsOrigRenderControls) {
6980
+ GroupProto.__pixldocsOrigRenderControls = GroupProto._renderControls;
6981
+ GroupProto._renderControls = function(ctx, styleOverride, childrenOverride) {
6982
+ var _a2;
6983
+ const host = this.canvas;
6984
+ const active = (_a2 = host == null ? void 0 : host.getActiveObject) == null ? void 0 : _a2.call(host);
6985
+ const isActiveOrInActive = !!host && (active === this || !!active && typeof active.contains === "function" && active.contains(this, true));
6986
+ const hideWarpChildBounds = isActiveOrInActive && !shouldShowOriginalTextBounds() && hasActiveTextPathDescendant(this);
6987
+ const prevBorders = this.hasBorders;
6988
+ const prevControls = this.hasControls;
6989
+ const prevBorderColor = this.borderColor;
6990
+ if (hideWarpChildBounds) {
6991
+ this.hasBorders = false;
6992
+ this.hasControls = false;
6993
+ this.borderColor = "rgba(0,0,0,0)";
6994
+ styleOverride = { ...styleOverride || {}, hasBorders: false, hasControls: false, borderColor: "rgba(0,0,0,0)" };
6995
+ childrenOverride = { ...childrenOverride || {}, hasBorders: false, borderColor: "rgba(0,0,0,0)" };
6996
+ }
6997
+ try {
6998
+ GroupProto.__pixldocsOrigRenderControls.call(this, ctx, styleOverride, childrenOverride);
6999
+ } finally {
7000
+ if (hideWarpChildBounds) {
7001
+ this.hasBorders = prevBorders;
7002
+ this.hasControls = prevControls;
7003
+ this.borderColor = prevBorderColor;
7004
+ }
7005
+ }
7006
+ if (!host || !isActiveOrInActive) return;
7007
+ const drawForDescendants = (parent) => {
7008
+ const kids = (parent == null ? void 0 : parent._objects) || [];
7009
+ for (const child of kids) {
7010
+ if (child && Array.isArray(child._objects)) {
7011
+ drawForDescendants(child);
7012
+ }
7013
+ if (child && child.textPath && child.textPath.preset && child.textPath.preset !== "none") {
7014
+ const bounds = getTextPathHitBounds(child);
7015
+ if (bounds) drawTextPathBounds(ctx, child, bounds, host);
7016
+ }
7017
+ }
7018
+ };
7019
+ drawForDescendants(this);
7020
+ };
7021
+ }
6808
7022
  const TextboxProtoHit = fabric.Textbox.prototype;
6809
7023
  if (!TextboxProtoHit.__pixldocsOrigGetCoords && typeof TextboxProtoHit.getCoords === "function") {
6810
7024
  TextboxProtoHit.__pixldocsOrigGetCoords = TextboxProtoHit.getCoords;
@@ -6983,7 +7197,7 @@ function buildRoundedRectPath2D(ctx, x, y, w, h, rTL, rTR, rBR, rBL) {
6983
7197
  ctx.closePath();
6984
7198
  }
6985
7199
  function applyTextBackground(obj, cfg) {
6986
- var _a;
7200
+ var _a2;
6987
7201
  obj[PD_BG_KEY] = { ...cfg };
6988
7202
  try {
6989
7203
  const hasOffset = (Number(cfg == null ? void 0 : cfg.shadowOffsetX) || 0) !== 0 || (Number(cfg == null ? void 0 : cfg.shadowOffsetY) || 0) !== 0;
@@ -7229,10 +7443,10 @@ function applyTextBackground(obj, cfg) {
7229
7443
  }
7230
7444
  return out;
7231
7445
  };
7232
- const originalToSVG = (_a = obj.toSVG) == null ? void 0 : _a.bind(obj);
7446
+ const originalToSVG = (_a2 = obj.toSVG) == null ? void 0 : _a2.bind(obj);
7233
7447
  if (typeof originalToSVG === "function") {
7234
7448
  obj.toSVG = function(reviver) {
7235
- var _a2, _b;
7449
+ var _a3, _b;
7236
7450
  let svg = originalToSVG(reviver);
7237
7451
  const bg = this[PD_BG_KEY];
7238
7452
  const shadow = this.shadow;
@@ -7245,7 +7459,7 @@ function applyTextBackground(obj, cfg) {
7245
7459
  const hasBlockShadow = !!bg && bg.shadowType === "block" && hasExtShadowColor && extDist > 0;
7246
7460
  const hasLineShadow = !!bg && bg.shadowType === "line" && hasExtShadowColor && extDist > 0;
7247
7461
  if (!hasBg && !hasShadow && !hasBlockShadow && !hasLineShadow) return svg;
7248
- const hasActiveTextPath2 = !!(((_a2 = this.textPath) == null ? void 0 : _a2.preset) && this.textPath.preset !== "none");
7462
+ const hasActiveTextPath2 = !!(((_a3 = this.textPath) == null ? void 0 : _a3.preset) && this.textPath.preset !== "none");
7249
7463
  const w = this.width ?? 0;
7250
7464
  const h = this.height ?? 0;
7251
7465
  const pT = Math.max(0, Number((bg == null ? void 0 : bg.padTop) ?? 0));
@@ -7392,7 +7606,7 @@ function recolorSvgFills(svg, color, strokeWidth = 0) {
7392
7606
  return _recolorSvgFills(svg, color, strokeWidth);
7393
7607
  }
7394
7608
  function _recolorSvgFills(svg, color, strokeWidth = 0) {
7395
- var _a;
7609
+ var _a2;
7396
7610
  const safe = escapeXmlAttr(color);
7397
7611
  const spread = Math.max(0, Number(strokeWidth) || 0);
7398
7612
  try {
@@ -7402,7 +7616,7 @@ function _recolorSvgFills(svg, color, strokeWidth = 0) {
7402
7616
  if (root && root.nodeName !== "parsererror") {
7403
7617
  for (const g of Array.from(root.querySelectorAll("linearGradient, radialGradient, pattern"))) {
7404
7618
  try {
7405
- (_a = g.parentNode) == null ? void 0 : _a.removeChild(g);
7619
+ (_a2 = g.parentNode) == null ? void 0 : _a2.removeChild(g);
7406
7620
  } catch {
7407
7621
  }
7408
7622
  }
@@ -7490,7 +7704,7 @@ function unionBounds(bounds) {
7490
7704
  return { x: minX, y: minY, w: Math.max(1, maxX - minX), h: Math.max(1, maxY - minY) };
7491
7705
  }
7492
7706
  function computeTextVisualBounds(obj, w, h) {
7493
- var _a;
7707
+ var _a2;
7494
7708
  const lines = (obj == null ? void 0 : obj._textLines) ?? [];
7495
7709
  if (!lines || lines.length === 0) return { x: -w / 2, y: -h / 2, w, h };
7496
7710
  const rects = [];
@@ -7508,7 +7722,7 @@ function computeTextVisualBounds(obj, w, h) {
7508
7722
  lineW = 0;
7509
7723
  }
7510
7724
  try {
7511
- lineLeft = ((_a = obj._getLineLeftOffset) == null ? void 0 : _a.call(obj, i)) ?? 0;
7725
+ lineLeft = ((_a2 = obj._getLineLeftOffset) == null ? void 0 : _a2.call(obj, i)) ?? 0;
7512
7726
  } catch {
7513
7727
  lineLeft = 0;
7514
7728
  }
@@ -7526,7 +7740,7 @@ function computeTextVisualBounds(obj, w, h) {
7526
7740
  return unionBounds(rects.length > 0 ? rects : [{ x: -w / 2, y: -h / 2, w, h }]);
7527
7741
  }
7528
7742
  function computeBgRects(obj, w, h, pT, pR, pB, pL, fit) {
7529
- var _a;
7743
+ var _a2;
7530
7744
  if (!fit) {
7531
7745
  return [{
7532
7746
  x: -w / 2 - pL,
@@ -7559,7 +7773,7 @@ function computeBgRects(obj, w, h, pT, pR, pB, pL, fit) {
7559
7773
  lineW = 0;
7560
7774
  }
7561
7775
  try {
7562
- lineLeft = ((_a = obj._getLineLeftOffset) == null ? void 0 : _a.call(obj, i)) ?? 0;
7776
+ lineLeft = ((_a2 = obj._getLineLeftOffset) == null ? void 0 : _a2.call(obj, i)) ?? 0;
7563
7777
  } catch {
7564
7778
  lineLeft = 0;
7565
7779
  }
@@ -8332,7 +8546,7 @@ function createShape(element) {
8332
8546
  }
8333
8547
  }
8334
8548
  function createText(element) {
8335
- var _a, _b;
8549
+ var _a2, _b, _c;
8336
8550
  const overflowPolicy = element.overflowPolicy || "grow-and-push";
8337
8551
  let text = element.text || "Text";
8338
8552
  let fontSize = element.fontSize || 16;
@@ -8372,7 +8586,7 @@ function createText(element) {
8372
8586
  });
8373
8587
  testTextbox.initDimensions();
8374
8588
  const textHeight = testTextbox.height || 0;
8375
- const renderedLineCount = ((_a = testTextbox.textLines) == null ? void 0 : _a.length) || 1;
8589
+ const renderedLineCount = ((_a2 = testTextbox.textLines) == null ? void 0 : _a2.length) || 1;
8376
8590
  const hasNoImplicitWrap = renderedLineCount <= explicitLineCount;
8377
8591
  const fitsHeight = heightBound <= 0 || textHeight <= heightBound;
8378
8592
  const widthMetrics = getTextboxWidthFitMetrics(testTextbox, fixedWidth);
@@ -8427,7 +8641,7 @@ function createText(element) {
8427
8641
  if (overflowPolicy === "max-lines-ellipsis") {
8428
8642
  const originalText = element.text || "Text";
8429
8643
  const countLines = (testText) => {
8430
- var _a2;
8644
+ var _a3;
8431
8645
  const tb = new fabric.Textbox(testText, {
8432
8646
  width: element.width,
8433
8647
  fontSize,
@@ -8436,7 +8650,7 @@ function createText(element) {
8436
8650
  splitByGrapheme: element.splitByGrapheme ?? element.wordWrap === "break-word"
8437
8651
  });
8438
8652
  tb.initDimensions();
8439
- return ((_a2 = tb.textLines) == null ? void 0 : _a2.length) || 1;
8653
+ return ((_a3 = tb.textLines) == null ? void 0 : _a3.length) || 1;
8440
8654
  };
8441
8655
  let low = 0;
8442
8656
  let high = originalText.length;
@@ -8505,10 +8719,30 @@ function createText(element) {
8505
8719
  minWidth: 1,
8506
8720
  dynamicMinWidth: 0,
8507
8721
  scaleX: targetScaleX,
8508
- scaleY: targetScaleY
8722
+ scaleY: targetScaleY,
8723
+ // Prevent the bottom/top resize handle from flipping the textbox through
8724
+ // zero (which visually "drags" the element up on the page once it can't
8725
+ // shrink any further). Locking flip + a small minScaleLimit makes the
8726
+ // handle simply stop where it is instead of repositioning the element.
8727
+ lockScalingFlip: true,
8728
+ minScaleLimit: 0.01
8509
8729
  });
8510
8730
  textbox.setCoords();
8511
8731
  const widthAfterSet = textbox.width ?? 0;
8732
+ try {
8733
+ (_b = textbox.setControlsVisibility) == null ? void 0 : _b.call(textbox, {
8734
+ tl: true,
8735
+ tr: true,
8736
+ bl: true,
8737
+ br: true,
8738
+ mt: true,
8739
+ mb: true,
8740
+ ml: true,
8741
+ mr: true,
8742
+ mtr: true
8743
+ });
8744
+ } catch {
8745
+ }
8512
8746
  const scaleXAfterSet = textbox.scaleX ?? 1;
8513
8747
  const scaleYAfterSet = textbox.scaleY ?? 1;
8514
8748
  if (Math.abs(widthAfterSet - targetWidth) > 0.01 || Math.abs(scaleXAfterSet - targetScaleX) > 0.01 || Math.abs(scaleYAfterSet - targetScaleY) > 0.01) {
@@ -8539,7 +8773,7 @@ function createText(element) {
8539
8773
  finalFontSize: fontSize,
8540
8774
  textboxWidth: textbox.width,
8541
8775
  textboxHeight: textbox.height,
8542
- lineCount: ((_b = textbox.textLines) == null ? void 0 : _b.length) || 0,
8776
+ lineCount: ((_c = textbox.textLines) == null ? void 0 : _c.length) || 0,
8543
8777
  lines: (textbox.textLines || []).map((line) => Array.isArray(line) ? line.join("") : String(line ?? "")),
8544
8778
  widthMetrics: getTextboxWidthFitMetrics(textbox, targetWidth)
8545
8779
  }));
@@ -8605,6 +8839,23 @@ function createFabricObject(element) {
8605
8839
  if (element.type === "text" && obj instanceof fabric.Textbox) {
8606
8840
  applyTextPathControls(obj);
8607
8841
  }
8842
+ if (element.type === "line") {
8843
+ obj.setControlsVisibility({
8844
+ tl: false,
8845
+ tr: false,
8846
+ bl: false,
8847
+ br: false,
8848
+ mt: false,
8849
+ mb: false,
8850
+ ml: true,
8851
+ mr: true,
8852
+ mtr: true
8853
+ });
8854
+ obj.set({
8855
+ padding: 8,
8856
+ perPixelTargetFind: false
8857
+ });
8858
+ }
8608
8859
  }
8609
8860
  return obj;
8610
8861
  }
@@ -8661,7 +8912,7 @@ function generateQRMatrix(text, errorCorrectionLevel) {
8661
8912
  return { modules: [[true]], size: 1 };
8662
8913
  }
8663
8914
  function renderQRSvg(props, width, height) {
8664
- var _a;
8915
+ var _a2;
8665
8916
  props.value || "https://example.com";
8666
8917
  const fgColor = props.fgColor || "#000000";
8667
8918
  const bgColor = props.bgColor || "#FFFFFF";
@@ -8673,7 +8924,7 @@ function renderQRSvg(props, width, height) {
8673
8924
  let pathData = "";
8674
8925
  for (let row = 0; row < size; row++) {
8675
8926
  for (let col = 0; col < size; col++) {
8676
- if ((_a = modules[row]) == null ? void 0 : _a[col]) {
8927
+ if ((_a2 = modules[row]) == null ? void 0 : _a2[col]) {
8677
8928
  const x = (col + margin) * cellSize;
8678
8929
  const y = (row + margin) * cellSize;
8679
8930
  pathData += `M${x},${y}h${cellSize}v${cellSize}h${-cellSize}Z `;
@@ -9081,6 +9332,21 @@ function renderSmartElementToDataUri(type, props, width, height) {
9081
9332
  if (!svg) return null;
9082
9333
  return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
9083
9334
  }
9335
+ const KEY_SHOW_ORIG_TEXT_BOUNDS = "pixldocs:showOriginalTextBounds";
9336
+ const EVT_SHOW_ORIG_TEXT_BOUNDS = "pixldocs:showOriginalTextBoundsChanged";
9337
+ function getShowOriginalTextBounds() {
9338
+ if (typeof window === "undefined") return false;
9339
+ try {
9340
+ return window.localStorage.getItem(KEY_SHOW_ORIG_TEXT_BOUNDS) === "1";
9341
+ } catch {
9342
+ return false;
9343
+ }
9344
+ }
9345
+ function subscribeShowOriginalTextBounds(cb) {
9346
+ const handler = (e) => cb(!!e.detail);
9347
+ window.addEventListener(EVT_SHOW_ORIG_TEXT_BOUNDS, handler);
9348
+ return () => window.removeEventListener(EVT_SHOW_ORIG_TEXT_BOUNDS, handler);
9349
+ }
9084
9350
  function hasEdgeFade(p) {
9085
9351
  if (!p) return false;
9086
9352
  const sides = [
@@ -9190,9 +9456,71 @@ function bakeEdgeFade(source, fade) {
9190
9456
  ctx.globalCompositeOperation = "destination-in";
9191
9457
  ctx.drawImage(mask, 0, 0);
9192
9458
  ctx.globalCompositeOperation = "source-over";
9459
+ if (amount < 1) {
9460
+ if (side === "top") ctx.clearRect(0, 0, canvas.width, Math.min(2, canvas.height));
9461
+ else if (side === "bottom") ctx.clearRect(0, Math.max(0, canvas.height - 2), canvas.width, Math.min(2, canvas.height));
9462
+ else if (side === "left") ctx.clearRect(0, 0, Math.min(2, canvas.width), canvas.height);
9463
+ else if (side === "right") ctx.clearRect(Math.max(0, canvas.width - 2), 0, Math.min(2, canvas.width), canvas.height);
9464
+ }
9193
9465
  }
9194
9466
  return canvas;
9195
9467
  }
9468
+ const SELECTION_PRIMARY = "hsl(217, 91%, 60%)";
9469
+ try {
9470
+ const InteractiveBase = fabric.InteractiveFabricObject ?? fabric.Object;
9471
+ if (InteractiveBase == null ? void 0 : InteractiveBase.ownDefaults) {
9472
+ Object.assign(InteractiveBase.ownDefaults, {
9473
+ borderColor: SELECTION_PRIMARY,
9474
+ borderScaleFactor: 1.25,
9475
+ cornerColor: SELECTION_PRIMARY,
9476
+ cornerStrokeColor: "#ffffff",
9477
+ cornerStyle: "rect",
9478
+ transparentCorners: false,
9479
+ cornerSize: 8,
9480
+ borderOpacityWhenMoving: 0.9
9481
+ });
9482
+ } else if (InteractiveBase == null ? void 0 : InteractiveBase.prototype) {
9483
+ Object.assign(InteractiveBase.prototype, {
9484
+ borderColor: SELECTION_PRIMARY,
9485
+ borderScaleFactor: 1.25,
9486
+ cornerColor: SELECTION_PRIMARY,
9487
+ cornerStrokeColor: "#ffffff",
9488
+ cornerStyle: "rect",
9489
+ transparentCorners: false,
9490
+ cornerSize: 8,
9491
+ borderOpacityWhenMoving: 0.9
9492
+ });
9493
+ }
9494
+ } catch (e) {
9495
+ console.warn("[PageCanvas] Failed to apply global selection defaults:", e);
9496
+ }
9497
+ function applyWarpAwareSelectionBorders(selection) {
9498
+ if (getShowOriginalTextBounds()) {
9499
+ if (selection.__pixldocsOrigASHasBorders !== void 0) {
9500
+ selection.hasBorders = selection.__pixldocsOrigASHasBorders;
9501
+ }
9502
+ return;
9503
+ }
9504
+ const hasWarpedTextObject = (obj) => {
9505
+ if (obj instanceof fabric.Textbox) {
9506
+ const tp = obj.textPath;
9507
+ return !!(tp && tp.preset && tp.preset !== "none");
9508
+ }
9509
+ const children = obj._objects;
9510
+ return Array.isArray(children) && children.some((child) => hasWarpedTextObject(child));
9511
+ };
9512
+ const hasWarpedText = selection.getObjects().some((obj) => {
9513
+ if (!hasWarpedTextObject(obj)) return false;
9514
+ const tp = obj.textPath;
9515
+ return !tp || tp.preset !== "none";
9516
+ });
9517
+ if (hasWarpedText) {
9518
+ if (selection.__pixldocsOrigASHasBorders === void 0) {
9519
+ selection.__pixldocsOrigASHasBorders = selection.hasBorders;
9520
+ }
9521
+ selection.hasBorders = false;
9522
+ }
9523
+ }
9196
9524
  const PageCanvas = forwardRef(
9197
9525
  ({
9198
9526
  pageId,
@@ -9236,7 +9564,9 @@ const PageCanvas = forwardRef(
9236
9564
  const justModifiedIdsRef = useRef(/* @__PURE__ */ new Set());
9237
9565
  const previousVisibilityRef = useRef(/* @__PURE__ */ new Map());
9238
9566
  const isSyncingSelectionToFabricRef = useRef(false);
9567
+ const suppressGroupMemberBordersRef = useRef([]);
9239
9568
  const editingTextIdRef = useRef(null);
9569
+ const pendingTextEditOnUpRef = useRef(null);
9240
9570
  const syncLockedRef = useRef(false);
9241
9571
  const editLockRef = useRef(false);
9242
9572
  const editLockCountRef = useRef(0);
@@ -9251,6 +9581,8 @@ const PageCanvas = forwardRef(
9251
9581
  const hasClearedCachesBeforeFirstSyncRef = useRef(false);
9252
9582
  const [guides, setGuides] = useState([]);
9253
9583
  const [gridResizeLabel, setGridResizeLabel] = useState(null);
9584
+ const [rotationLabel, setRotationLabel] = useState(null);
9585
+ const [sizeLabel, setSizeLabel] = useState(null);
9254
9586
  const [ready, setReady] = useState(false);
9255
9587
  const [unlockRequestId, setUnlockRequestId] = useState(0);
9256
9588
  useMemo(
@@ -9262,6 +9594,8 @@ const PageCanvas = forwardRef(
9262
9594
  const [groupOverlayLiveBounds, setGroupOverlayLiveBounds] = useState(null);
9263
9595
  const setGroupOverlayLiveBoundsRef = useRef(setGroupOverlayLiveBounds);
9264
9596
  const skipSelectionClearOnDiscardRef = useRef(false);
9597
+ const skipActiveSelectionBakeOnClearRef = useRef(false);
9598
+ const preserveActiveSelectionAfterTransformRef = useRef(null);
9265
9599
  const imageReloadRequestSeqRef = useRef(/* @__PURE__ */ new Map());
9266
9600
  useRef(null);
9267
9601
  const groupBoundsResizingRef = useRef(false);
@@ -9279,6 +9613,8 @@ const PageCanvas = forwardRef(
9279
9613
  useRef(null);
9280
9614
  const lastTextEditDimensionsRef = useRef(null);
9281
9615
  const lastResizeScaleTargetRef = useRef(null);
9616
+ const preserveSelectionAfterTransformIdRef = useRef(null);
9617
+ const groupSelectionTransformStartRef = useRef(null);
9282
9618
  setGroupOverlayLiveBoundsRef.current = setGroupOverlayLiveBounds;
9283
9619
  const {
9284
9620
  selectElements,
@@ -9333,7 +9669,7 @@ const PageCanvas = forwardRef(
9333
9669
  }
9334
9670
  },
9335
9671
  enterTextEditing: (elementId, charToInsert) => {
9336
- var _a;
9672
+ var _a2;
9337
9673
  const fc = fabricRef.current;
9338
9674
  if (!fc || !allowEditing) return false;
9339
9675
  let textbox = null;
@@ -9351,7 +9687,7 @@ const PageCanvas = forwardRef(
9351
9687
  textbox.enterEditing();
9352
9688
  if (charToInsert != null && charToInsert.length > 0) {
9353
9689
  const iText = textbox;
9354
- const start = iText.selectionStart ?? (((_a = iText.text) == null ? void 0 : _a.length) ?? 0);
9690
+ const start = iText.selectionStart ?? (((_a2 = iText.text) == null ? void 0 : _a2.length) ?? 0);
9355
9691
  iText.insertChars(charToInsert, void 0, start);
9356
9692
  }
9357
9693
  fc.requestRenderAll();
@@ -9442,9 +9778,9 @@ const PageCanvas = forwardRef(
9442
9778
  const elementById = new Map(elementsRef.current.map((el) => [el.id, el]));
9443
9779
  let didReflow = false;
9444
9780
  const reflowObject = (obj) => {
9445
- var _a;
9781
+ var _a2;
9446
9782
  if (obj instanceof fabric.Group) {
9447
- (_a = obj._objects) == null ? void 0 : _a.forEach(reflowObject);
9783
+ (_a2 = obj._objects) == null ? void 0 : _a2.forEach(reflowObject);
9448
9784
  obj.dirty = true;
9449
9785
  return;
9450
9786
  }
@@ -9652,6 +9988,7 @@ const PageCanvas = forwardRef(
9652
9988
  fabricCanvas.__fontCleanup = fontCleanup;
9653
9989
  fabricCanvas.__isUserTransforming = false;
9654
9990
  fabricCanvas.on("mouse:down", () => {
9991
+ groupSelectionTransformStartRef.current = null;
9655
9992
  if (fabricCanvas._currentTransform) {
9656
9993
  fabricCanvas.__isUserTransforming = true;
9657
9994
  }
@@ -9663,13 +10000,13 @@ const PageCanvas = forwardRef(
9663
10000
  fabricCanvas.__isUserTransforming = true;
9664
10001
  });
9665
10002
  fabricCanvas.on("object:moving", () => {
9666
- var _a;
10003
+ var _a2;
9667
10004
  fabricCanvas.__isUserTransforming = true;
9668
10005
  didTransformRef.current = true;
9669
10006
  const active = fabricCanvas.getActiveObject();
9670
10007
  if (!active) return;
9671
10008
  const state = useEditorStore.getState();
9672
- const canvasPage = (_a = state.canvas.pages) == null ? void 0 : _a.find((p) => p.id === pageId);
10009
+ const canvasPage = (_a2 = state.canvas.pages) == null ? void 0 : _a2.find((p) => p.id === pageId);
9673
10010
  const children = (canvasPage == null ? void 0 : canvasPage.children) ?? [];
9674
10011
  if (!canvasPage) return;
9675
10012
  const ids = state.canvas.selectedIds ?? [];
@@ -9704,14 +10041,14 @@ const PageCanvas = forwardRef(
9704
10041
  didTransformRef.current = true;
9705
10042
  });
9706
10043
  const syncSelectionToStore = () => {
9707
- var _a, _b;
10044
+ var _a2, _b, _c, _d, _e, _f, _g;
9708
10045
  if (!isActiveRef.current || isRebuildingRef.current || isSyncingSelectionToFabricRef.current || !allowSelection) return;
9709
10046
  const active = fabricCanvas.getActiveObject();
9710
10047
  let ids = fabricCanvas.getActiveObjects().map((o) => getObjectId(o)).filter((id) => !!id && id !== "__background__");
9711
10048
  if (ids.length === 1 && active && active instanceof fabric.Group && active.__docuforgeSectionGroup) {
9712
10049
  const groupId = ids[0];
9713
10050
  const state = useEditorStore.getState();
9714
- const currentPage2 = (_a = state.canvas.pages) == null ? void 0 : _a.find((p) => p.id === pageId);
10051
+ const currentPage2 = (_a2 = state.canvas.pages) == null ? void 0 : _a2.find((p) => p.id === pageId);
9715
10052
  const children = (currentPage2 == null ? void 0 : currentPage2.children) ?? [];
9716
10053
  const node = findNodeById(children, groupId);
9717
10054
  if (node && isGroup(node)) {
@@ -9719,13 +10056,48 @@ const PageCanvas = forwardRef(
9719
10056
  ids = [groupId, ...memberIds];
9720
10057
  }
9721
10058
  }
10059
+ if (active instanceof fabric.ActiveSelection) {
10060
+ const groupSelectionId = active.__pixldocsGroupSelection;
10061
+ if (groupSelectionId) {
10062
+ selectElements([groupSelectionId], false, false);
10063
+ return;
10064
+ }
10065
+ }
9722
10066
  if (ids.length === 1) {
10067
+ const activeEditingGroupId = fabricCanvas.__activeEditingGroupId ?? null;
10068
+ const clickedId = ids[0];
10069
+ const state = useEditorStore.getState();
10070
+ const currentPage2 = (_b = state.canvas.pages) == null ? void 0 : _b.find((p) => p.id === pageId);
10071
+ const children = (currentPage2 == null ? void 0 : currentPage2.children) ?? [];
10072
+ const parent = findParentGroup(children, clickedId);
10073
+ 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));
10074
+ if (parent && !targetIsInCrop && activeEditingGroupId !== parent.id && !(active && active instanceof fabric.Group && active.__docuforgeSectionGroup)) {
10075
+ const memberIdSet = new Set(getAllElementIds(parent.children ?? []));
10076
+ const memberObjs = fabricCanvas.getObjects().filter((o) => {
10077
+ const oid = getObjectId(o);
10078
+ return !!oid && memberIdSet.has(oid);
10079
+ });
10080
+ if (memberObjs.length > 1) {
10081
+ fabricCanvas.__activeEditingGroupId = null;
10082
+ const sel = new fabric.ActiveSelection(memberObjs, { canvas: fabricCanvas });
10083
+ restoreGroupSelectionVisualState(sel, parent.id);
10084
+ isSyncingSelectionToFabricRef.current = true;
10085
+ try {
10086
+ fabricCanvas.setActiveObject(sel);
10087
+ fabricCanvas.requestRenderAll();
10088
+ } finally {
10089
+ isSyncingSelectionToFabricRef.current = false;
10090
+ }
10091
+ selectElements([parent.id], false, false);
10092
+ return;
10093
+ }
10094
+ }
9723
10095
  selectElements(ids, false, false);
9724
10096
  return;
9725
10097
  }
9726
10098
  if (ids.length > 1) {
9727
10099
  const state = useEditorStore.getState();
9728
- const currentPage2 = (_b = state.canvas.pages) == null ? void 0 : _b.find((p) => p.id === pageId);
10100
+ const currentPage2 = (_g = state.canvas.pages) == null ? void 0 : _g.find((p) => p.id === pageId);
9729
10101
  const children = (currentPage2 == null ? void 0 : currentPage2.children) ?? [];
9730
10102
  const currentSelectedIds = state.canvas.selectedIds ?? [];
9731
10103
  for (const sid of currentSelectedIds) {
@@ -9734,7 +10106,7 @@ const PageCanvas = forwardRef(
9734
10106
  const memberIds = new Set(getAllElementIds(node.children ?? []));
9735
10107
  const fabricIdSet = new Set(ids);
9736
10108
  if (memberIds.size === fabricIdSet.size && [...memberIds].every((id) => fabricIdSet.has(id))) {
9737
- selectElements([sid, ...ids], false, true);
10109
+ selectElements([sid], false, false);
9738
10110
  return;
9739
10111
  }
9740
10112
  }
@@ -9742,32 +10114,98 @@ const PageCanvas = forwardRef(
9742
10114
  }
9743
10115
  selectElements(ids, false, true);
9744
10116
  };
10117
+ const restoreSuppressedGroupBorders = () => {
10118
+ const list = suppressGroupMemberBordersRef.current;
10119
+ if (!list || list.length === 0) return;
10120
+ for (const m of list) {
10121
+ const orig = m.__pixldocsOrigHasBorders;
10122
+ if (orig !== void 0) {
10123
+ m.hasBorders = orig;
10124
+ delete m.__pixldocsOrigHasBorders;
10125
+ } else {
10126
+ m.hasBorders = true;
10127
+ }
10128
+ }
10129
+ suppressGroupMemberBordersRef.current = [];
10130
+ };
9745
10131
  fabricCanvas.on("selection:created", () => {
9746
- var _a;
10132
+ var _a2;
9747
10133
  syncSelectionToStore();
9748
10134
  const activeObj = fabricCanvas.getActiveObject();
9749
10135
  if (activeObj) applyControlSizeForZoom(fabricCanvas, activeObj);
9750
- if (activeObj && !(activeObj instanceof fabric.ActiveSelection) && (((_a = activeObj._ct) == null ? void 0 : _a.isCropGroup) || activeObj.__cropGroup)) {
10136
+ if (activeObj && !(activeObj instanceof fabric.ActiveSelection) && (((_a2 = activeObj._ct) == null ? void 0 : _a2.isCropGroup) || activeObj.__cropGroup)) {
9751
10137
  installCanvaMaskControls(activeObj);
9752
10138
  }
9753
10139
  });
9754
10140
  fabricCanvas.on("selection:updated", () => {
9755
- var _a;
10141
+ var _a2;
10142
+ const next = fabricCanvas.getActiveObject();
10143
+ const isGroupSel = next instanceof fabric.ActiveSelection && next.__pixldocsGroupSelection;
10144
+ if (!isGroupSel) restoreSuppressedGroupBorders();
9756
10145
  syncSelectionToStore();
9757
10146
  const activeObj = fabricCanvas.getActiveObject();
9758
10147
  if (activeObj) applyControlSizeForZoom(fabricCanvas, activeObj);
9759
- if (activeObj && !(activeObj instanceof fabric.ActiveSelection) && (((_a = activeObj._ct) == null ? void 0 : _a.isCropGroup) || activeObj.__cropGroup)) {
10148
+ if (activeObj && !(activeObj instanceof fabric.ActiveSelection) && (((_a2 = activeObj._ct) == null ? void 0 : _a2.isCropGroup) || activeObj.__cropGroup)) {
9760
10149
  installCanvaMaskControls(activeObj);
9761
10150
  }
9762
10151
  });
10152
+ fabricCanvas.on("mouse:dblclick", (opt) => {
10153
+ var _a2, _b;
10154
+ const target = opt == null ? void 0 : opt.target;
10155
+ if (!target) return;
10156
+ if (target.isEditing) return;
10157
+ if (((_a2 = target._ct) == null ? void 0 : _a2.isCropGroup) || target.__cropGroup) return;
10158
+ const active = fabricCanvas.getActiveObject();
10159
+ let hitChild = null;
10160
+ if (active instanceof fabric.ActiveSelection) {
10161
+ const pointer = fabricCanvas.getViewportPoint(opt.e);
10162
+ const objs = active.getObjects();
10163
+ for (let i = objs.length - 1; i >= 0; i--) {
10164
+ const o = objs[i];
10165
+ if (o.containsPoint && o.containsPoint(pointer)) {
10166
+ hitChild = o;
10167
+ break;
10168
+ }
10169
+ }
10170
+ } else {
10171
+ hitChild = target;
10172
+ }
10173
+ if (!hitChild) return;
10174
+ const childId = getObjectId(hitChild);
10175
+ if (!childId) return;
10176
+ const stateNow = useEditorStore.getState();
10177
+ const pageNow = (_b = stateNow.canvas.pages) == null ? void 0 : _b.find((p) => p.id === pageId);
10178
+ const childrenNow = (pageNow == null ? void 0 : pageNow.children) ?? [];
10179
+ const parent = findParentGroup(childrenNow, childId);
10180
+ if (!parent) return;
10181
+ fabricCanvas.__activeEditingGroupId = parent.id;
10182
+ isSyncingSelectionToFabricRef.current = true;
10183
+ try {
10184
+ fabricCanvas.discardActiveObject();
10185
+ fabricCanvas.setActiveObject(hitChild);
10186
+ fabricCanvas.requestRenderAll();
10187
+ } finally {
10188
+ isSyncingSelectionToFabricRef.current = false;
10189
+ }
10190
+ selectElements([childId], false, false);
10191
+ });
9763
10192
  fabricCanvas.on("selection:cleared", () => {
9764
10193
  if (!isActiveRef.current || isRebuildingRef.current || !allowSelection) return;
9765
10194
  setGroupOverlayLiveBoundsRef.current(null);
9766
10195
  groupBoundsResizingRef.current = false;
10196
+ fabricCanvas.__activeEditingGroupId = null;
10197
+ const preservedGroupSelection = preserveActiveSelectionAfterTransformRef.current;
10198
+ const shouldRestoreGroupSelection = !!((preservedGroupSelection == null ? void 0 : preservedGroupSelection.groupSelectionId) && (!preservedGroupSelection.expiresAt || preservedGroupSelection.expiresAt > Date.now()));
9767
10199
  if (skipSelectionClearOnDiscardRef.current) {
9768
10200
  skipSelectionClearOnDiscardRef.current = false;
10201
+ if (shouldRestoreGroupSelection) restorePreservedGroupSelectionSoon(preservedGroupSelection);
10202
+ return;
10203
+ }
10204
+ if (editLockRef.current || syncLockedRef.current || didTransformRef.current || preserveSelectionAfterTransformIdRef.current || shouldRestoreGroupSelection) {
10205
+ if (shouldRestoreGroupSelection) restorePreservedGroupSelectionSoon(preservedGroupSelection);
9769
10206
  return;
9770
10207
  }
10208
+ restoreSuppressedGroupBorders();
9771
10209
  editLockRef.current = false;
9772
10210
  syncLockedRef.current = false;
9773
10211
  clearSelection();
@@ -9785,6 +10223,12 @@ const PageCanvas = forwardRef(
9785
10223
  return;
9786
10224
  }
9787
10225
  if (target instanceof fabric.ActiveSelection) {
10226
+ const memberIds = target.getObjects().map((o) => getObjectId(o)).filter((id2) => !!id2 && id2 !== "__background__");
10227
+ if (memberIds.length > 1) {
10228
+ const groupSelectionId = target.__pixldocsGroupSelection;
10229
+ preserveActiveSelectionAfterTransformRef.current = { memberIds, groupSelectionId, expiresAt: Date.now() + 1200 };
10230
+ if (groupSelectionId) preserveSelectionAfterTransformIdRef.current = groupSelectionId;
10231
+ }
9788
10232
  target.getObjects().forEach((o) => {
9789
10233
  const id2 = getObjectId(o);
9790
10234
  if (id2) transformingIdsRef.current.add(id2);
@@ -9797,14 +10241,78 @@ const PageCanvas = forwardRef(
9797
10241
  const clearTransforming = () => {
9798
10242
  transformingIdsRef.current.clear();
9799
10243
  };
10244
+ const prepareGroupSelectionTransformStart = (target) => {
10245
+ var _a2, _b;
10246
+ const active = target instanceof fabric.ActiveSelection ? target : fabricCanvas.getActiveObject();
10247
+ if (!(active instanceof fabric.ActiveSelection)) return;
10248
+ const groupId = active.__pixldocsGroupSelection;
10249
+ if (!groupId) return;
10250
+ if (((_a2 = groupSelectionTransformStartRef.current) == null ? void 0 : _a2.groupId) === groupId && groupSelectionTransformStartRef.current.selection === active) return;
10251
+ const pageChildren2 = ((_b = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _b.children) ?? [];
10252
+ const groupNode = findNodeById(pageChildren2, groupId);
10253
+ if (!groupNode) return;
10254
+ const groupAbs = getAbsoluteBounds(groupNode, pageChildren2);
10255
+ const rect = active.getBoundingRect();
10256
+ groupSelectionTransformStartRef.current = {
10257
+ groupId,
10258
+ selection: active,
10259
+ selectionLeft: rect.left,
10260
+ selectionTop: rect.top,
10261
+ groupLeft: groupAbs.left,
10262
+ groupTop: groupAbs.top
10263
+ };
10264
+ };
10265
+ const restoreGroupSelectionVisualState = (selection, groupId) => {
10266
+ selection.__pixldocsGroupSelection = groupId;
10267
+ const members = selection.getObjects();
10268
+ suppressGroupMemberBordersRef.current = members;
10269
+ for (const m of members) {
10270
+ if (m.__pixldocsOrigHasBorders === void 0) {
10271
+ m.__pixldocsOrigHasBorders = m.hasBorders;
10272
+ }
10273
+ m.hasBorders = false;
10274
+ }
10275
+ };
10276
+ const restorePreservedGroupSelectionSoon = (snapshot = preserveActiveSelectionAfterTransformRef.current) => {
10277
+ if (!(snapshot == null ? void 0 : snapshot.groupSelectionId) || snapshot.memberIds.length < 2) return;
10278
+ const groupId = snapshot.groupSelectionId;
10279
+ const memberIds = [...snapshot.memberIds];
10280
+ selectElements([groupId], false, false);
10281
+ requestAnimationFrame(() => {
10282
+ setTimeout(() => {
10283
+ const fc = fabricRef.current;
10284
+ if (!fc || !isActiveRef.current || editingTextIdRef.current) return;
10285
+ const active = fc.getActiveObject();
10286
+ if (active instanceof fabric.ActiveSelection && active.__pixldocsGroupSelection === groupId) {
10287
+ restoreGroupSelectionVisualState(active, groupId);
10288
+ fc.requestRenderAll();
10289
+ return;
10290
+ }
10291
+ const members = memberIds.map((id) => fc.getObjects().find((o) => getObjectId(o) === id)).filter((o) => !!o);
10292
+ if (members.length < 2) return;
10293
+ isSyncingSelectionToFabricRef.current = true;
10294
+ try {
10295
+ const selection = new fabric.ActiveSelection(members, { canvas: fc });
10296
+ restoreGroupSelectionVisualState(selection, groupId);
10297
+ fc.setActiveObject(selection);
10298
+ selection.setCoords();
10299
+ fc.requestRenderAll();
10300
+ } finally {
10301
+ requestAnimationFrame(() => {
10302
+ isSyncingSelectionToFabricRef.current = false;
10303
+ });
10304
+ }
10305
+ }, 0);
10306
+ });
10307
+ };
9800
10308
  const isCropGroup2 = (o) => {
9801
- var _a;
9802
- return !!(((_a = o == null ? void 0 : o._ct) == null ? void 0 : _a.isCropGroup) || (o == null ? void 0 : o.__cropGroup));
10309
+ var _a2;
10310
+ return !!(((_a2 = o == null ? void 0 : o._ct) == null ? void 0 : _a2.isCropGroup) || (o == null ? void 0 : o.__cropGroup));
9803
10311
  };
9804
10312
  const promoteToCropGroup = (opt) => {
9805
- var _a, _b, _c;
10313
+ var _a2, _b, _c;
9806
10314
  const t = opt.target;
9807
- 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") {
10315
+ 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") {
9808
10316
  if (t && isCropGroup2(t)) {
9809
10317
  fabricCanvas._hoveredTarget = t;
9810
10318
  } else if ((t == null ? void 0 : t.group) && isCropGroup2(t.group)) {
@@ -9885,9 +10393,9 @@ const PageCanvas = forwardRef(
9885
10393
  });
9886
10394
  }
9887
10395
  fabricCanvas.on("mouse:down", (opt) => {
9888
- var _a, _b;
10396
+ var _a2, _b;
9889
10397
  const target = opt.target;
9890
- 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;
10398
+ 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;
9891
10399
  if (cropGroup) {
9892
10400
  lockEdits();
9893
10401
  didTransformRef.current = false;
@@ -9897,10 +10405,10 @@ const PageCanvas = forwardRef(
9897
10405
  }
9898
10406
  });
9899
10407
  fabricCanvas.on("mouse:down:before", (opt) => {
9900
- var _a, _b, _c, _d, _e;
10408
+ var _a2, _b, _c, _d, _e;
9901
10409
  if (editLockRef.current) {
9902
10410
  const active = fabricCanvas.getActiveObject();
9903
- if (active && (((_a = active._ct) == null ? void 0 : _a.isCropGroup) || active.__cropGroup)) {
10411
+ if (active && (((_a2 = active._ct) == null ? void 0 : _a2.isCropGroup) || active.__cropGroup)) {
9904
10412
  opt.target = active;
9905
10413
  if (opt.e) {
9906
10414
  (_c = (_b = opt.e).preventDefault) == null ? void 0 : _c.call(_b);
@@ -9916,22 +10424,25 @@ const PageCanvas = forwardRef(
9916
10424
  promoteToCropGroup(opt);
9917
10425
  });
9918
10426
  fabricCanvas.on("mouse:move:before", promoteToCropGroup);
9919
- fabricCanvas.on("mouse:down", () => {
10427
+ fabricCanvas.on("mouse:down", (ev) => {
9920
10428
  if (fabricCanvas._currentTransform) {
9921
10429
  lockEdits();
9922
10430
  didTransformRef.current = true;
9923
10431
  }
9924
10432
  const o = fabricCanvas.getActiveObject();
10433
+ pendingTextEditOnUpRef.current = null;
9925
10434
  if (!o) return;
9926
10435
  o.__lockScaleDuringCrop = false;
9927
10436
  });
9928
10437
  fabricCanvas.on("mouse:up", (e) => {
9929
- var _a;
10438
+ var _a2;
9930
10439
  clearTransforming();
9931
10440
  setGuides([]);
10441
+ setRotationLabel(null);
10442
+ setSizeLabel(null);
9932
10443
  dragStarted = false;
9933
10444
  const activeObj = fabricCanvas.getActiveObject();
9934
- if (activeObj && (activeObj.__cropGroup || ((_a = activeObj._ct) == null ? void 0 : _a.isCropGroup))) {
10445
+ if (activeObj && (activeObj.__cropGroup || ((_a2 = activeObj._ct) == null ? void 0 : _a2.isCropGroup))) {
9935
10446
  activeObj.__lockScaleDuringCrop = false;
9936
10447
  if (activeObj.__cropDrag) {
9937
10448
  delete activeObj.__cropDrag;
@@ -9972,9 +10483,9 @@ const PageCanvas = forwardRef(
9972
10483
  markTransforming(e.target);
9973
10484
  };
9974
10485
  fabricCanvas.on("object:added", (e) => {
9975
- var _a;
10486
+ var _a2;
9976
10487
  const obj = e.target;
9977
- if (obj && (obj.__cropGroup || ((_a = obj._ct) == null ? void 0 : _a.isCropGroup))) {
10488
+ if (obj && (obj.__cropGroup || ((_a2 = obj._ct) == null ? void 0 : _a2.isCropGroup))) {
9978
10489
  if (!obj.__cropGroupId) {
9979
10490
  obj.__cropGroupId = `crop-${Date.now()}-${Math.random()}`;
9980
10491
  }
@@ -9986,13 +10497,28 @@ const PageCanvas = forwardRef(
9986
10497
  if (!isActiveRef.current) return;
9987
10498
  const t = e.target;
9988
10499
  if (t) lastResizeScaleTargetRef.current = t;
10500
+ prepareGroupSelectionTransformStart(t);
9989
10501
  markTransforming(t);
9990
10502
  didTransformRef.current = true;
10503
+ const transformTargetId = t ? getObjectId(t) : null;
10504
+ if (transformTargetId && transformTargetId !== "__background__") {
10505
+ preserveSelectionAfterTransformIdRef.current = transformTargetId;
10506
+ }
9991
10507
  const obj = t;
9992
10508
  if (!obj) return;
9993
10509
  if (obj instanceof fabric.Rect || obj instanceof fabric.Path || obj instanceof fabric.Circle || obj instanceof fabric.Triangle || obj instanceof fabric.Line) {
9994
10510
  obj.set({ strokeUniform: true });
9995
10511
  }
10512
+ try {
10513
+ const br = obj.getBoundingRect();
10514
+ setSizeLabel({
10515
+ width: Math.round(br.width),
10516
+ height: Math.round(br.height),
10517
+ x: br.left + br.width / 2,
10518
+ y: br.top + br.height + 18
10519
+ });
10520
+ } catch {
10521
+ }
9996
10522
  const objId = getObjectId(obj);
9997
10523
  const sourceEl = objId ? elementsRef.current.find((el) => el.id === objId) : null;
9998
10524
  const isCornerShape = (sourceEl == null ? void 0 : sourceEl.type) === "shape" && (sourceEl.shapeType === "circle" || sourceEl.shapeType === "rounded-rect" || sourceEl.shapeType === "triangle");
@@ -10126,8 +10652,23 @@ const PageCanvas = forwardRef(
10126
10652
  const t = e.target;
10127
10653
  if (t) lastResizeScaleTargetRef.current = t;
10128
10654
  markTransforming(t);
10655
+ didTransformRef.current = true;
10656
+ const transformTargetId = t ? getObjectId(t) : null;
10657
+ if (transformTargetId && transformTargetId !== "__background__") {
10658
+ preserveSelectionAfterTransformIdRef.current = transformTargetId;
10659
+ }
10129
10660
  const obj = t;
10130
10661
  if (!obj) return;
10662
+ try {
10663
+ const br = obj.getBoundingRect();
10664
+ setSizeLabel({
10665
+ width: Math.round(br.width),
10666
+ height: Math.round(br.height),
10667
+ x: br.left + br.width / 2,
10668
+ y: br.top + br.height + 18
10669
+ });
10670
+ } catch {
10671
+ }
10131
10672
  const transform = e.transform;
10132
10673
  const corner = (transform == null ? void 0 : transform.corner) || "";
10133
10674
  const scaleGuides = calculateScaleSnapGuidesCallback(obj, corner);
@@ -10136,6 +10677,23 @@ const PageCanvas = forwardRef(
10136
10677
  fabricCanvas.on("object:rotating", (e) => {
10137
10678
  markSimpleTransform(e);
10138
10679
  didTransformRef.current = true;
10680
+ const tr = e.target;
10681
+ const rotateTargetId = tr ? getObjectId(tr) : null;
10682
+ if (rotateTargetId && rotateTargetId !== "__background__") {
10683
+ preserveSelectionAfterTransformIdRef.current = rotateTargetId;
10684
+ }
10685
+ if (tr) {
10686
+ try {
10687
+ const br = tr.getBoundingRect();
10688
+ let angle = ((tr.angle ?? 0) % 360 + 360) % 360;
10689
+ setRotationLabel({
10690
+ angle: Math.round(angle),
10691
+ x: br.left + br.width / 2,
10692
+ y: br.top + br.height / 2
10693
+ });
10694
+ } catch {
10695
+ }
10696
+ }
10139
10697
  });
10140
10698
  fabricCanvas.on("object:skewing", (e) => {
10141
10699
  markSimpleTransform(e);
@@ -10143,8 +10701,13 @@ const PageCanvas = forwardRef(
10143
10701
  });
10144
10702
  fabricCanvas.on("object:moving", (e) => {
10145
10703
  if (!isActiveRef.current) return;
10704
+ prepareGroupSelectionTransformStart(e.target);
10146
10705
  markTransforming(e.target);
10147
10706
  didTransformRef.current = true;
10707
+ const moveTargetId = e.target ? getObjectId(e.target) : null;
10708
+ if (moveTargetId && moveTargetId !== "__background__") {
10709
+ preserveSelectionAfterTransformIdRef.current = moveTargetId;
10710
+ }
10148
10711
  if (!dragStarted) {
10149
10712
  dragStarted = true;
10150
10713
  const selectedEls = elementsRef.current.filter((el) => selectedIdsRef.current.includes(el.id));
@@ -10164,7 +10727,7 @@ const PageCanvas = forwardRef(
10164
10727
  });
10165
10728
  let cropGroupSaveTimer = null;
10166
10729
  fabricCanvas.on("object:modified", (e) => {
10167
- var _a, _b, _c, _d, _e, _f;
10730
+ var _a2, _b, _c, _d, _e, _f;
10168
10731
  try {
10169
10732
  dragStarted = false;
10170
10733
  setGuides([]);
@@ -10195,12 +10758,8 @@ const PageCanvas = forwardRef(
10195
10758
  }
10196
10759
  const active = fabricCanvas.getActiveObject();
10197
10760
  const activeId = active ? getObjectId(active) : null;
10198
- const activeObjectsForLog = fabricCanvas.getActiveObjects();
10199
- if (typeof console !== "undefined" && console.log) {
10200
- console.log("[object:modified] activeId=", activeId, "isGroup=", active instanceof fabric.Group, "isActiveSelection=", active instanceof fabric.ActiveSelection, "activeObjectsCount=", (activeObjectsForLog == null ? void 0 : activeObjectsForLog.length) ?? 0);
10201
- }
10202
10761
  if (active && activeId && activeId !== "__background__" && !(active instanceof fabric.Group)) {
10203
- const pageChildrenForParent = ((_a = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a.children) ?? [];
10762
+ const pageChildrenForParent = ((_a2 = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a2.children) ?? [];
10204
10763
  const parentGroup = findParentGroup(pageChildrenForParent, activeId);
10205
10764
  if (parentGroup && isGroup(parentGroup) && parentGroup.backgroundColor) {
10206
10765
  let fabricSectionGroup = active.group && active.group instanceof fabric.Group ? active.group : null;
@@ -10309,10 +10868,10 @@ const PageCanvas = forwardRef(
10309
10868
  clearTimeout(cropGroupSaveTimer);
10310
10869
  }
10311
10870
  cropGroupSaveTimer = setTimeout(() => {
10312
- var _a2, _b2, _c2;
10871
+ var _a3, _b2, _c2;
10313
10872
  const { updateElement: updateElement2 } = useEditorStore.getState();
10314
10873
  const img = ct._img;
10315
- const zoom3 = ((_a2 = img == null ? void 0 : img._ct) == null ? void 0 : _a2.zoom) ?? 1;
10874
+ const zoom3 = ((_a3 = img == null ? void 0 : img._ct) == null ? void 0 : _a3.zoom) ?? 1;
10316
10875
  const panX = ((_b2 = img == null ? void 0 : img._ct) == null ? void 0 : _b2.panX) ?? 0.5;
10317
10876
  const panY = ((_c2 = img == null ? void 0 : img._ct) == null ? void 0 : _c2.panY) ?? 0.5;
10318
10877
  const stateCrop = useEditorStore.getState();
@@ -10411,10 +10970,23 @@ const PageCanvas = forwardRef(
10411
10970
  }
10412
10971
  const activeObj = fabricCanvas.getActiveObject();
10413
10972
  let activeObjects = fabricCanvas.getActiveObjects();
10973
+ if (activeObjects.length === 0 && modifiedTarget && getObjectId(modifiedTarget)) {
10974
+ activeObjects = [modifiedTarget];
10975
+ }
10414
10976
  if (activeObjects.length === 1 && typeof activeObjects[0].getObjects === "function" && !getObjectId(activeObjects[0])) {
10415
10977
  activeObjects = activeObjects[0].getObjects();
10416
10978
  }
10417
10979
  const isActiveSelection = activeObj instanceof fabric.ActiveSelection || activeObjects.length > 1;
10980
+ if (activeObj instanceof fabric.ActiveSelection && activeObjects.length > 1) {
10981
+ const memberIds = activeObjects.map((o) => getObjectId(o)).filter((id) => !!id && id !== "__background__");
10982
+ if (memberIds.length > 1) {
10983
+ preserveActiveSelectionAfterTransformRef.current = {
10984
+ memberIds,
10985
+ groupSelectionId: activeObj.__pixldocsGroupSelection,
10986
+ expiresAt: Date.now() + 1200
10987
+ };
10988
+ }
10989
+ }
10418
10990
  const { getCurrentPage: getCurrentPageStore } = useEditorStore.getState();
10419
10991
  const currentPage2 = getCurrentPageStore();
10420
10992
  const selectedElementIds = activeObjects.map((obj) => getObjectId(obj)).filter((id) => !!id && id !== "__background__");
@@ -10437,10 +11009,38 @@ const PageCanvas = forwardRef(
10437
11009
  })();
10438
11010
  const groupToMove = candidateIsStack || allMembersSelected ? candidateGroup : null;
10439
11011
  if (groupToMove) {
11012
+ const activeGroupSelectionId = activeObj instanceof fabric.ActiveSelection ? activeObj.__pixldocsGroupSelection : void 0;
11013
+ const transformStart = activeGroupSelectionId === groupToMove.id ? groupSelectionTransformStartRef.current : null;
10440
11014
  const groupAbs = getAbsoluteBounds(groupToMove, pageChildren2);
10441
11015
  let movedGroupLeft = groupAbs.left;
10442
11016
  let movedGroupTop = groupAbs.top;
10443
- if (activeObj) {
11017
+ if (activeObj instanceof fabric.ActiveSelection && (transformStart == null ? void 0 : transformStart.groupId) === groupToMove.id) {
11018
+ const selectionRect = activeObj.getBoundingRect();
11019
+ movedGroupLeft = transformStart.groupLeft + (selectionRect.left - transformStart.selectionLeft);
11020
+ movedGroupTop = transformStart.groupTop + (selectionRect.top - transformStart.selectionTop);
11021
+ } else if (activeObj instanceof fabric.ActiveSelection && firstId && firstObj) {
11022
+ const firstNode = findNodeById(pageChildren2, firstId);
11023
+ if (firstNode) {
11024
+ try {
11025
+ const oldAbs = getAbsoluteBounds(firstNode, pageChildren2);
11026
+ const m = fabric.util.multiplyTransformMatrices(
11027
+ activeObj.calcTransformMatrix(),
11028
+ firstObj.calcOwnMatrix()
11029
+ );
11030
+ const decomposed = fabric.util.qrDecompose(m);
11031
+ const w = (firstObj.width ?? 0) * Math.abs(decomposed.scaleX || 1);
11032
+ const h = (firstObj.height ?? 0) * Math.abs(decomposed.scaleY || 1);
11033
+ const newAbsLeft = firstObj.originX === "center" ? decomposed.translateX - w / 2 : decomposed.translateX;
11034
+ const newAbsTop = firstObj.originY === "center" ? decomposed.translateY - h / 2 : decomposed.translateY;
11035
+ movedGroupLeft = groupAbs.left + (newAbsLeft - oldAbs.left);
11036
+ movedGroupTop = groupAbs.top + (newAbsTop - oldAbs.top);
11037
+ } catch {
11038
+ const selectionRect = activeObj.getBoundingRect();
11039
+ movedGroupLeft = selectionRect.left;
11040
+ movedGroupTop = selectionRect.top;
11041
+ }
11042
+ }
11043
+ } else if (activeObj) {
10444
11044
  const selectionRect = activeObj.getBoundingRect();
10445
11045
  movedGroupLeft = selectionRect.left;
10446
11046
  movedGroupTop = selectionRect.top;
@@ -10454,44 +11054,22 @@ const PageCanvas = forwardRef(
10454
11054
  const deltaX = movedGroupLeft - groupAbs.left;
10455
11055
  const deltaY = movedGroupTop - groupAbs.top;
10456
11056
  const hadScale = isActiveSelection && activeObj && (Math.abs((activeObj.scaleX ?? 1) - 1) > 0.01 || Math.abs((activeObj.scaleY ?? 1) - 1) > 0.01);
10457
- if (!hadScale && (Math.abs(deltaX) > 0.1 || Math.abs(deltaY) > 0.1)) {
10458
- if (typeof console !== "undefined" && console.log) {
10459
- console.log("[object:modified] plain-groups: moving group id=", groupToMove.id, "newLeft=", (groupToMove.left ?? 0) + deltaX, "newTop=", (groupToMove.top ?? 0) + deltaY);
10460
- }
11057
+ const hadRotation = isActiveSelection && activeObj && Math.abs((activeObj.angle ?? 0) % 360) > 0.01;
11058
+ if (!hadScale && !hadRotation && (Math.abs(deltaX) > 0.1 || Math.abs(deltaY) > 0.1)) {
10461
11059
  const { updateNode: updateNodeStore, commitHistory: commitHistoryStore, getCurrentElements } = useEditorStore.getState();
10462
11060
  const newLeft = (groupToMove.left ?? 0) + deltaX;
10463
11061
  const newTop = (groupToMove.top ?? 0) + deltaY;
10464
11062
  updateNodeStore(groupToMove.id, { left: newLeft, top: newTop }, { recordHistory: false, skipLayoutRecalc: true });
10465
11063
  commitHistoryStore();
10466
- if (isActiveSelection && activeObj instanceof fabric.ActiveSelection) {
10467
- skipSelectionClearOnDiscardRef.current = true;
10468
- fabricCanvas.discardActiveObject();
10469
- }
10470
- const stateAfter = useEditorStore.getState();
10471
- const pageAfter = stateAfter.canvas.pages.find((p) => p.id === pageId);
10472
- const pageChildrenAfter = (pageAfter == null ? void 0 : pageAfter.children) ?? [];
10473
- for (const obj of activeObjects) {
10474
- const objId = getObjectId(obj);
10475
- if (!objId || objId === "__background__") continue;
10476
- const node = findNodeById(pageChildrenAfter, objId);
10477
- if (node) {
10478
- const abs = getAbsoluteBounds(node, pageChildrenAfter);
10479
- const w = (obj.width ?? 0) * (obj.scaleX ?? 1);
10480
- const h = (obj.height ?? 0) * (obj.scaleY ?? 1);
10481
- const nextLeft = obj.originX === "center" ? abs.left + w / 2 : abs.left;
10482
- const nextTop = obj.originY === "center" ? abs.top + h / 2 : abs.top;
10483
- obj.set({ left: nextLeft, top: nextTop });
10484
- obj.setCoords();
10485
- }
10486
- }
10487
- if (isActiveSelection && activeObjects.length > 0) {
10488
- const selection = new fabric.ActiveSelection([...activeObjects], { canvas: fabricCanvas });
10489
- fabricCanvas.setActiveObject(selection);
10490
- skipSelectionClearOnDiscardRef.current = false;
11064
+ const groupSelectionId = isActiveSelection && activeObj instanceof fabric.ActiveSelection ? activeObj.__pixldocsGroupSelection : void 0;
11065
+ const targetObjects = isActiveSelection && activeObj instanceof fabric.ActiveSelection ? activeObj.getObjects() : activeObjects;
11066
+ if (groupSelectionId && activeObj instanceof fabric.ActiveSelection) {
11067
+ restoreGroupSelectionVisualState(activeObj, groupSelectionId);
11068
+ activeObj.setCoords();
10491
11069
  }
10492
11070
  fabricCanvas.requestRenderAll();
10493
11071
  elementsRef.current = getCurrentElements();
10494
- for (const obj of activeObjects) {
11072
+ for (const obj of targetObjects) {
10495
11073
  const objId = getObjectId(obj);
10496
11074
  if (objId && objId !== "__background__") {
10497
11075
  justModifiedIdsRef.current.add(objId);
@@ -10499,6 +11077,11 @@ const PageCanvas = forwardRef(
10499
11077
  }
10500
11078
  }
10501
11079
  setTimeout(() => modifiedIdsThisRound.forEach((id) => justModifiedIdsRef.current.delete(id)), 150);
11080
+ groupSelectionTransformStartRef.current = null;
11081
+ restorePreservedGroupSelectionSoon({
11082
+ memberIds: targetObjects.map((obj) => getObjectId(obj)).filter((id) => !!id && id !== "__background__"),
11083
+ groupSelectionId
11084
+ });
10502
11085
  unlockEditsSoon();
10503
11086
  return;
10504
11087
  }
@@ -10521,7 +11104,10 @@ const PageCanvas = forwardRef(
10521
11104
  intrinsicHeight = obj.height ?? 0;
10522
11105
  } else if (obj instanceof fabric.Line) {
10523
11106
  const x1 = obj.x1 ?? 0, y1 = obj.y1 ?? 0, x2 = obj.x2 ?? 0, y2 = obj.y2 ?? 0;
10524
- intrinsicWidth = Math.hypot(x2 - x1, y2 - y1) * (obj.scaleX ?? 1);
11107
+ const rawLen = Math.hypot(x2 - x1, y2 - y1);
11108
+ const ownScaleX = obj.scaleX ?? 1;
11109
+ const selScaleX = isActiveSelection && activeObj ? Math.abs(activeObj.scaleX ?? 1) : 1;
11110
+ intrinsicWidth = rawLen * Math.abs(ownScaleX) * selScaleX;
10525
11111
  intrinsicHeight = 0;
10526
11112
  } else {
10527
11113
  intrinsicWidth = obj.width ?? 0;
@@ -10692,20 +11278,37 @@ const PageCanvas = forwardRef(
10692
11278
  for (const gid of stackGroupsToReflow) {
10693
11279
  useEditorStore.getState().reflowStackGroupInPage(pageId, gid);
10694
11280
  }
10695
- if (isActiveSelection && activeObj && activeObjects.length > 0) {
10696
- const selectionMatrix = activeObj.calcTransformMatrix();
10697
- for (const obj of activeObjects) {
10698
- const objId = getObjectId(obj);
10699
- if (!objId || objId === "__background__") continue;
10700
- const objOwnMatrix = obj.calcOwnMatrix();
10701
- const absoluteMatrix = fabric.util.multiplyTransformMatrices(selectionMatrix, objOwnMatrix);
10702
- fabric.util.applyTransformToObject(obj, absoluteMatrix);
10703
- obj.setCoords();
11281
+ if (activeObj instanceof fabric.ActiveSelection && activeObjects.length > 0) {
11282
+ const wasGroupSel = activeObj.__pixldocsGroupSelection;
11283
+ const membersToReselect = activeObjects.filter((o) => {
11284
+ const oid = getObjectId(o);
11285
+ return !!oid && oid !== "__background__";
11286
+ });
11287
+ skipSelectionClearOnDiscardRef.current = true;
11288
+ skipActiveSelectionBakeOnClearRef.current = true;
11289
+ try {
11290
+ fabricCanvas.discardActiveObject();
11291
+ } finally {
11292
+ skipActiveSelectionBakeOnClearRef.current = false;
11293
+ }
11294
+ if (membersToReselect.length > 1) {
11295
+ const newSel = new fabric.ActiveSelection(membersToReselect, { canvas: fabricCanvas });
11296
+ if (wasGroupSel) restoreGroupSelectionVisualState(newSel, wasGroupSel);
11297
+ fabricCanvas.setActiveObject(newSel);
11298
+ newSel.setCoords();
11299
+ } else if (membersToReselect.length === 1) {
11300
+ fabricCanvas.setActiveObject(membersToReselect[0]);
11301
+ }
11302
+ skipSelectionClearOnDiscardRef.current = false;
11303
+ if (wasGroupSel) {
11304
+ restorePreservedGroupSelectionSoon({
11305
+ memberIds: membersToReselect.map((obj) => getObjectId(obj)).filter((id) => !!id && id !== "__background__"),
11306
+ groupSelectionId: wasGroupSel
11307
+ });
10704
11308
  }
10705
- activeObj.set({ scaleX: 1, scaleY: 1 });
10706
- activeObj.setCoords();
10707
11309
  fabricCanvas.requestRenderAll();
10708
11310
  }
11311
+ groupSelectionTransformStartRef.current = null;
10709
11312
  setTimeout(() => modifiedIdsThisRound.forEach((id) => justModifiedIdsRef.current.delete(id)), 150);
10710
11313
  commitHistory();
10711
11314
  unlockEditsSoon();
@@ -10722,6 +11325,7 @@ const PageCanvas = forwardRef(
10722
11325
  if (!deselected || deselected.length === 0) return;
10723
11326
  const activeObj = fabricCanvas.getActiveObject();
10724
11327
  if (!(activeObj instanceof fabric.ActiveSelection)) return;
11328
+ if (skipActiveSelectionBakeOnClearRef.current) return;
10725
11329
  const selectionMatrix = activeObj.calcTransformMatrix();
10726
11330
  for (const obj of deselected) {
10727
11331
  const objId = getObjectId(obj);
@@ -10907,7 +11511,8 @@ const PageCanvas = forwardRef(
10907
11511
  }
10908
11512
  }
10909
11513
  }
10910
- const visibilityBatchThreshold = hasAnyVisibilityChange && (totalVisibilityChanges > 0 && visibilityOnlyCount / totalVisibilityChanges >= 0.8 || totalVisibilityChanges >= 5 && visibilityOnlyCount / totalVisibilityChanges >= 0.7);
11514
+ const visibilityOnlySignal = isVisibilityOnlyUpdatePending();
11515
+ const visibilityBatchThreshold = hasAnyVisibilityChange && visibilityOnlySignal || hasAnyVisibilityChange && (totalVisibilityChanges > 0 && visibilityOnlyCount / totalVisibilityChanges >= 0.8 || totalVisibilityChanges >= 5 && visibilityOnlyCount / totalVisibilityChanges >= 0.7);
10911
11516
  if (visibilityBatchThreshold) {
10912
11517
  visibilityUpdateInProgressRef.current = true;
10913
11518
  setTimeout(() => {
@@ -10917,12 +11522,12 @@ const PageCanvas = forwardRef(
10917
11522
  visibilityUpdateInProgressRef.current = false;
10918
11523
  }
10919
11524
  doSyncRef.current = () => {
10920
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
11525
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
10921
11526
  const shouldSkipUpdates2 = syncLockedRef.current || editLockRef.current;
10922
11527
  const state = useEditorStore.getState();
10923
11528
  const elementsToSync = elements;
10924
11529
  elementsRef.current = elementsToSync;
10925
- const pageTree = isPreviewMode && (pageChildren == null ? void 0 : pageChildren.length) ? pageChildren ?? [] : ((_a = state.canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a.children) ?? [];
11530
+ const pageTree = isPreviewMode && (pageChildren == null ? void 0 : pageChildren.length) ? pageChildren ?? [] : ((_a2 = state.canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a2.children) ?? [];
10926
11531
  const selectedIdsFromStore = new Set(((_b = state.canvas) == null ? void 0 : _b.selectedIds) ?? []);
10927
11532
  isRebuildingRef.current = true;
10928
11533
  const allElementIds = new Set(elementsToSync.map((el) => el.id));
@@ -10940,8 +11545,13 @@ const PageCanvas = forwardRef(
10940
11545
  if (!sectionDescendantIds.has(id)) validTopLevelIds.add(id);
10941
11546
  });
10942
11547
  const activeBeforeSync = fc.getActiveObject();
11548
+ const transformSelectionId = preserveSelectionAfterTransformIdRef.current;
10943
11549
  const isTransforming2 = !!fc._currentTransform;
10944
- if (syncTriggeredByPanelRef.current && !shouldSkipUpdates2 && !isTransforming2) {
11550
+ const activeSelectionSnapshot = activeBeforeSync instanceof fabric.ActiveSelection ? {
11551
+ memberIds: activeBeforeSync.getObjects().map((o) => getObjectId(o)).filter((id) => !!id && id !== "__background__"),
11552
+ groupSelectionId: activeBeforeSync.__pixldocsGroupSelection
11553
+ } : preserveActiveSelectionAfterTransformRef.current;
11554
+ if (syncTriggeredByPanelRef.current && !transformSelectionId && !shouldSkipUpdates2 && !isTransforming2) {
10945
11555
  const activeObj = fc.getActiveObject();
10946
11556
  const activeObjId = activeObj ? getObjectId(activeObj) : null;
10947
11557
  const isTextBeingEdited = activeObjId && editingTextIdRef.current === activeObjId;
@@ -10956,15 +11566,44 @@ const PageCanvas = forwardRef(
10956
11566
  currentFabricObjects.set(id, obj);
10957
11567
  }
10958
11568
  });
10959
- const skipRestoreSelection = syncTriggeredByPanelRef.current;
11569
+ const skipRestoreSelection = syncTriggeredByPanelRef.current && !transformSelectionId;
11570
+ const activeId = transformSelectionId || (activeBeforeSync ? getObjectId(activeBeforeSync) : null);
10960
11571
  const activeStillOnCanvas = activeBeforeSync && fc.getObjects().includes(activeBeforeSync);
10961
- const activeId = activeBeforeSync ? getObjectId(activeBeforeSync) : null;
11572
+ const replacementById = !activeStillOnCanvas && activeId ? fc.getObjects().find((o) => getObjectId(o) === activeId) ?? null : null;
11573
+ const restoreTarget = activeStillOnCanvas ? activeBeforeSync : replacementById;
10962
11574
  const isActiveTextBeingEdited = activeId && editingTextIdRef.current === activeId && activeBeforeSync instanceof fabric.Textbox;
10963
- if (!skipRestoreSelection && activeBeforeSync && activeStillOnCanvas && !isActiveTextBeingEdited) {
10964
- const isCropGroup2 = ((_d = activeBeforeSync._ct) == null ? void 0 : _d.isCropGroup) || activeBeforeSync.__cropGroup;
11575
+ if (!skipRestoreSelection && activeSelectionSnapshot && !isActiveTextBeingEdited && !shouldSkipUpdates2) {
11576
+ const freshMembers = activeSelectionSnapshot.memberIds.map((id) => fc.getObjects().find((o) => getObjectId(o) === id)).filter((o) => !!o);
11577
+ if (freshMembers.length > 1) {
11578
+ isSyncingSelectionToFabricRef.current = true;
11579
+ try {
11580
+ const newSel = new fabric.ActiveSelection(freshMembers, { canvas: fc });
11581
+ if (activeSelectionSnapshot.groupSelectionId) {
11582
+ newSel.__pixldocsGroupSelection = activeSelectionSnapshot.groupSelectionId;
11583
+ suppressGroupMemberBordersRef.current = freshMembers;
11584
+ for (const m of freshMembers) {
11585
+ if (m.__pixldocsOrigHasBorders === void 0) {
11586
+ m.__pixldocsOrigHasBorders = m.hasBorders;
11587
+ }
11588
+ m.hasBorders = false;
11589
+ }
11590
+ }
11591
+ fc.setActiveObject(newSel);
11592
+ newSel.setCoords();
11593
+ fc.requestRenderAll();
11594
+ } finally {
11595
+ isSyncingSelectionToFabricRef.current = false;
11596
+ }
11597
+ } else if (freshMembers.length === 1) {
11598
+ fc.setActiveObject(freshMembers[0]);
11599
+ fc.requestRenderAll();
11600
+ }
11601
+ } else if (!skipRestoreSelection && restoreTarget && !isActiveTextBeingEdited) {
11602
+ const isCropGroup2 = ((_d = restoreTarget._ct) == null ? void 0 : _d.isCropGroup) || restoreTarget.__cropGroup;
10965
11603
  const isSectionGroup = activeId && sectionGroupIds.has(activeId);
10966
11604
  if ((isCropGroup2 || !shouldSkipUpdates2) && !isSectionGroup) {
10967
- fc.setActiveObject(activeBeforeSync);
11605
+ fc.setActiveObject(restoreTarget);
11606
+ fc.requestRenderAll();
10968
11607
  }
10969
11608
  }
10970
11609
  for (const id of sectionGroupIds) {
@@ -11053,9 +11692,9 @@ const PageCanvas = forwardRef(
11053
11692
  sectionGroup.__docuforgeSectionGroup = true;
11054
11693
  const bgColor = G.backgroundColor || "#f0f0f0";
11055
11694
  sectionGroup._renderBackground = function(ctx) {
11056
- var _a2;
11695
+ var _a3;
11057
11696
  if (bgColor === "transparent") return;
11058
- const dim = ((_a2 = this._getNonTransformedDimensions) == null ? void 0 : _a2.call(this)) ?? { x: this.width ?? gw, y: this.height ?? gh };
11697
+ const dim = ((_a3 = this._getNonTransformedDimensions) == null ? void 0 : _a3.call(this)) ?? { x: this.width ?? gw, y: this.height ?? gh };
11059
11698
  const w = dim.x ?? gw;
11060
11699
  const h = dim.y ?? gh;
11061
11700
  ctx.save();
@@ -11177,8 +11816,17 @@ const PageCanvas = forwardRef(
11177
11816
  flipX: element.flipX ?? false,
11178
11817
  flipY: element.flipY ?? false
11179
11818
  });
11180
- const clampedOpacity = element.opacity !== void 0 ? Math.max(0, Math.min(1, element.opacity)) : 1;
11181
- existingObj.set({ opacity: clampedOpacity });
11819
+ const baseOpacity = element.opacity !== void 0 ? Math.max(0, Math.min(1, element.opacity)) : 1;
11820
+ const clampedOpacity = isHidden ? 0 : baseOpacity;
11821
+ const isDynamicFieldImg = dynamicFieldIds.includes(element.id);
11822
+ const canBeEventedImg = isEditorMode || isPreviewMode && isDynamicFieldImg;
11823
+ existingObj.set({
11824
+ opacity: clampedOpacity,
11825
+ selectable: allowSelection && !isHidden,
11826
+ evented: canBeEventedImg && !isHidden,
11827
+ hasControls: allowEditing && !isHidden,
11828
+ hasBorders: allowEditing && !isHidden
11829
+ });
11182
11830
  existingObj.set({ width: ct.frameW, height: ct.frameH });
11183
11831
  existingObj.set({ backgroundColor: "transparent" });
11184
11832
  const liveMask = existingObj.clipPath;
@@ -11658,6 +12306,57 @@ const PageCanvas = forwardRef(
11658
12306
  }
11659
12307
  }
11660
12308
  });
12309
+ if (!skipRestoreSelection && activeSelectionSnapshot && !isActiveTextBeingEdited) {
12310
+ const currentActive = fc.getActiveObject();
12311
+ const currentMemberIds = currentActive instanceof fabric.ActiveSelection ? currentActive.getObjects().map((o) => getObjectId(o)).filter((id) => !!id && id !== "__background__") : [];
12312
+ const sameActiveSelection = currentMemberIds.length === activeSelectionSnapshot.memberIds.length && activeSelectionSnapshot.memberIds.every((id) => currentMemberIds.includes(id));
12313
+ if (!sameActiveSelection) {
12314
+ const freshMembers = activeSelectionSnapshot.memberIds.map((id) => fc.getObjects().find((o) => getObjectId(o) === id)).filter((o) => !!o);
12315
+ if (freshMembers.length > 1) {
12316
+ isSyncingSelectionToFabricRef.current = true;
12317
+ try {
12318
+ const newSel = new fabric.ActiveSelection(freshMembers, { canvas: fc });
12319
+ if (activeSelectionSnapshot.groupSelectionId) {
12320
+ newSel.__pixldocsGroupSelection = activeSelectionSnapshot.groupSelectionId;
12321
+ suppressGroupMemberBordersRef.current = freshMembers;
12322
+ for (const m of freshMembers) {
12323
+ if (m.__pixldocsOrigHasBorders === void 0) {
12324
+ m.__pixldocsOrigHasBorders = m.hasBorders;
12325
+ }
12326
+ m.hasBorders = false;
12327
+ }
12328
+ }
12329
+ fc.setActiveObject(newSel);
12330
+ newSel.setCoords();
12331
+ fc.requestRenderAll();
12332
+ } finally {
12333
+ isSyncingSelectionToFabricRef.current = false;
12334
+ }
12335
+ }
12336
+ }
12337
+ } else if (!skipRestoreSelection && activeId && !isActiveTextBeingEdited) {
12338
+ const currentActive = fc.getActiveObject();
12339
+ const currentActiveId = currentActive ? getObjectId(currentActive) : null;
12340
+ if (currentActiveId !== activeId) {
12341
+ const replacement = fc.getObjects().find((o) => getObjectId(o) === activeId) ?? (() => {
12342
+ for (const o of fc.getObjects()) {
12343
+ if (o instanceof fabric.Group && o.__docuforgeSectionGroup) {
12344
+ const child = o.getObjects().find((c) => getObjectId(c) === activeId);
12345
+ if (child) return child;
12346
+ }
12347
+ }
12348
+ return null;
12349
+ })();
12350
+ const isSectionGroup = sectionGroupIds.has(activeId);
12351
+ if (replacement && !isSectionGroup) {
12352
+ fc.setActiveObject(replacement);
12353
+ replacement.setCoords();
12354
+ fc.requestRenderAll();
12355
+ }
12356
+ }
12357
+ }
12358
+ preserveSelectionAfterTransformIdRef.current = null;
12359
+ preserveActiveSelectionAfterTransformRef.current = null;
11661
12360
  syncTriggeredByPanelRef.current = false;
11662
12361
  };
11663
12362
  if (canvasUpdateVersion !== prevCanvasUpdateVersionRef.current) {
@@ -11808,6 +12507,7 @@ const PageCanvas = forwardRef(
11808
12507
  };
11809
12508
  }, [ready, pageId, onReady]);
11810
12509
  useEffect(() => {
12510
+ var _a2;
11811
12511
  const fc = fabricRef.current;
11812
12512
  if (!fc || isRebuildingRef.current || !isActive) return;
11813
12513
  if (isTransforming(fc)) return;
@@ -11815,6 +12515,13 @@ const PageCanvas = forwardRef(
11815
12515
  if (editLockRef.current) return;
11816
12516
  isSyncingSelectionToFabricRef.current = true;
11817
12517
  const selectedSet = new Set(selectedIds);
12518
+ const pageChildrenForSelection = ((_a2 = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a2.children) ?? [];
12519
+ const selectedGroupSelectionId = selectedIds.find((id) => {
12520
+ const node = findNodeById(pageChildrenForSelection, id);
12521
+ return !!(node && isGroup(node));
12522
+ });
12523
+ const selectedGroupNode = selectedGroupSelectionId ? findNodeById(pageChildrenForSelection, selectedGroupSelectionId) : null;
12524
+ const selectedGroupMemberIds = selectedGroupNode && isGroup(selectedGroupNode) ? new Set(getAllElementIds(selectedGroupNode.children ?? [])) : null;
11818
12525
  const toSelect = [];
11819
12526
  for (const obj of fc.getObjects()) {
11820
12527
  const id = getObjectId(obj);
@@ -11823,10 +12530,14 @@ const PageCanvas = forwardRef(
11823
12530
  toSelect.push(obj);
11824
12531
  continue;
11825
12532
  }
12533
+ if (id && (selectedGroupMemberIds == null ? void 0 : selectedGroupMemberIds.has(id))) {
12534
+ toSelect.push(obj);
12535
+ continue;
12536
+ }
11826
12537
  if (obj instanceof fabric.Group && obj.__docuforgeSectionGroup) {
11827
12538
  for (const child of obj.getObjects()) {
11828
12539
  const childId = getObjectId(child);
11829
- if (childId && selectedSet.has(childId)) toSelect.push(child);
12540
+ if (childId && (selectedSet.has(childId) || (selectedGroupMemberIds == null ? void 0 : selectedGroupMemberIds.has(childId)))) toSelect.push(child);
11830
12541
  }
11831
12542
  }
11832
12543
  }
@@ -11847,6 +12558,15 @@ const PageCanvas = forwardRef(
11847
12558
  const active = fc.getActiveObject();
11848
12559
  const sameSelection = active instanceof fabric.ActiveSelection && active.getObjects().length === toSelect.length && toSelect.every((obj) => active.getObjects().includes(obj));
11849
12560
  if (sameSelection && isFlatGroupSelection) {
12561
+ if (selectedGroupSelectionId && active instanceof fabric.ActiveSelection) {
12562
+ active.__pixldocsGroupSelection = selectedGroupSelectionId;
12563
+ suppressGroupMemberBordersRef.current = active.getObjects();
12564
+ active.getObjects().forEach((m) => {
12565
+ if (m.__pixldocsOrigHasBorders === void 0) m.__pixldocsOrigHasBorders = m.hasBorders;
12566
+ m.hasBorders = false;
12567
+ });
12568
+ applyWarpAwareSelectionBorders(active);
12569
+ }
11850
12570
  fc.requestRenderAll();
11851
12571
  } else {
11852
12572
  toSelect.forEach((obj) => {
@@ -11854,6 +12574,15 @@ const PageCanvas = forwardRef(
11854
12574
  if (objId) justModifiedIdsRef.current.add(objId);
11855
12575
  });
11856
12576
  const selection = new fabric.ActiveSelection(toSelect, { canvas: fc });
12577
+ if (selectedGroupSelectionId) {
12578
+ selection.__pixldocsGroupSelection = selectedGroupSelectionId;
12579
+ suppressGroupMemberBordersRef.current = toSelect;
12580
+ toSelect.forEach((m) => {
12581
+ if (m.__pixldocsOrigHasBorders === void 0) m.__pixldocsOrigHasBorders = m.hasBorders;
12582
+ m.hasBorders = false;
12583
+ });
12584
+ applyWarpAwareSelectionBorders(selection);
12585
+ }
11857
12586
  fc.setActiveObject(selection);
11858
12587
  if (!isFlatGroupSelection) {
11859
12588
  selection.setCoords();
@@ -11865,13 +12594,25 @@ const PageCanvas = forwardRef(
11865
12594
  isSyncingSelectionToFabricRef.current = false;
11866
12595
  });
11867
12596
  }, [selectedIds, isActive, ready, elements]);
12597
+ useEffect(() => {
12598
+ const unsub = subscribeShowOriginalTextBounds(() => {
12599
+ const fc = fabricRef.current;
12600
+ if (!fc) return;
12601
+ const active = fc.getActiveObject();
12602
+ if (active instanceof fabric.ActiveSelection) {
12603
+ applyWarpAwareSelectionBorders(active);
12604
+ }
12605
+ fc.requestRenderAll();
12606
+ });
12607
+ return unsub;
12608
+ }, []);
11868
12609
  const updateFabricObject = (obj, element, skipPositionUpdate = false) => {
11869
- var _a, _b, _c;
12610
+ var _a2, _b, _c;
11870
12611
  const fc = fabricRef.current;
11871
12612
  if (fc && isTransforming(fc)) {
11872
12613
  return;
11873
12614
  }
11874
- const currentPageTree = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (_a = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a.children) ?? [];
12615
+ const currentPageTree = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (_a2 = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _a2.children) ?? [];
11875
12616
  const fabricPos = currentPageTree.length > 0 ? (() => {
11876
12617
  const node = findNodeById(currentPageTree, element.id);
11877
12618
  return node ? getAbsoluteBounds(node, currentPageTree) : { left: element.left ?? 0, top: element.top ?? 0 };
@@ -11935,13 +12676,13 @@ const PageCanvas = forwardRef(
11935
12676
  hasRotatingPoint: false,
11936
12677
  // Hide rotation handle
11937
12678
  // Scale with zoom so handles stay same visual size (controls drawn in canvas pixel space)
11938
- cornerSize: Math.max(6, Math.round(10 * (fc.getZoom() || 1))),
11939
- borderScaleFactor: fc.getZoom() || 1,
12679
+ cornerSize: Math.max(6, Math.round(8 * (fc.getZoom() || 1))),
12680
+ borderScaleFactor: Math.max(1.25, 1.25 * (fc.getZoom() || 1)),
11940
12681
  transparentCorners: false,
11941
12682
  cornerStyle: "rect",
11942
- cornerColor: "#ffffff",
11943
- cornerStrokeColor: "#4f46e5",
11944
- borderColor: "#4f46e5",
12683
+ cornerColor: SELECTION_PRIMARY,
12684
+ cornerStrokeColor: "#ffffff",
12685
+ borderColor: SELECTION_PRIMARY,
11945
12686
  padding: 0
11946
12687
  };
11947
12688
  if (!skipPositionUpdate) {
@@ -12273,7 +13014,7 @@ const PageCanvas = forwardRef(
12273
13014
  if (lines.length > maxLines) {
12274
13015
  const originalText = element.text || "Text";
12275
13016
  const countLines = (testText) => {
12276
- var _a2;
13017
+ var _a3;
12277
13018
  const tb = new fabric.Textbox(testText, {
12278
13019
  width: rW,
12279
13020
  fontSize,
@@ -12282,7 +13023,7 @@ const PageCanvas = forwardRef(
12282
13023
  splitByGrapheme
12283
13024
  });
12284
13025
  tb.initDimensions();
12285
- return ((_a2 = tb.textLines) == null ? void 0 : _a2.length) || 1;
13026
+ return ((_a3 = tb.textLines) == null ? void 0 : _a3.length) || 1;
12286
13027
  };
12287
13028
  let low = 0;
12288
13029
  let high = originalText.length;
@@ -12656,7 +13397,7 @@ const PageCanvas = forwardRef(
12656
13397
  return Math.max(min, Math.min(max, v));
12657
13398
  };
12658
13399
  const applyEdgeFadeFrameClipPath = (group, element, frameW, frameH, shape, rxRatio) => {
12659
- var _a, _b, _c;
13400
+ var _a2, _b, _c;
12660
13401
  const fadeElement = element;
12661
13402
  const fadeGroup = group;
12662
13403
  const inputKey = edgeFadeKey(fadeElement);
@@ -12665,7 +13406,7 @@ const PageCanvas = forwardRef(
12665
13406
  fadeGroup.__edgeFadeOriginalDrawObject = group.drawObject;
12666
13407
  }
12667
13408
  if (hasFade) {
12668
- if ((_a = group.clipPath) == null ? void 0 : _a.__edgeFadeMask) {
13409
+ if ((_a2 = group.clipPath) == null ? void 0 : _a2.__edgeFadeMask) {
12669
13410
  group.clipPath = void 0;
12670
13411
  updateCoverLayout(group);
12671
13412
  }
@@ -12704,6 +13445,7 @@ const PageCanvas = forwardRef(
12704
13445
  ctx.globalCompositeOperation = "destination-out";
12705
13446
  let gradient;
12706
13447
  const eraseAtEdge = 1 - amount;
13448
+ const isFullyFadedAtEdge = amount <= 1e-3;
12707
13449
  const STOPS = 64;
12708
13450
  const gamma = 1 / hardness;
12709
13451
  const addStops = (g) => {
@@ -12720,24 +13462,44 @@ const PageCanvas = forwardRef(
12720
13462
  addStops(gradient);
12721
13463
  ctx.fillStyle = gradient;
12722
13464
  ctx.fillRect(x, y, w, band);
13465
+ if (isFullyFadedAtEdge) {
13466
+ ctx.fillStyle = "rgba(0,0,0,1)";
13467
+ const guard = Math.min(2, band);
13468
+ ctx.fillRect(x - 2, y - 2, w + 4, guard + 2);
13469
+ }
12723
13470
  } else if (side === "bottom") {
12724
13471
  const band = Math.max(1, h * size);
12725
13472
  gradient = ctx.createLinearGradient(0, y + h, 0, y + h - band);
12726
13473
  addStops(gradient);
12727
13474
  ctx.fillStyle = gradient;
12728
13475
  ctx.fillRect(x, y + h - band, w, band);
13476
+ if (isFullyFadedAtEdge) {
13477
+ ctx.fillStyle = "rgba(0,0,0,1)";
13478
+ const guard = Math.min(2, band);
13479
+ ctx.fillRect(x - 2, y + h - guard, w + 4, guard + 2);
13480
+ }
12729
13481
  } else if (side === "left") {
12730
13482
  const band = Math.max(1, w * size);
12731
13483
  gradient = ctx.createLinearGradient(x, 0, x + band, 0);
12732
13484
  addStops(gradient);
12733
13485
  ctx.fillStyle = gradient;
12734
13486
  ctx.fillRect(x, y, band, h);
13487
+ if (isFullyFadedAtEdge) {
13488
+ ctx.fillStyle = "rgba(0,0,0,1)";
13489
+ const guard = Math.min(2, band);
13490
+ ctx.fillRect(x - 2, y - 2, guard + 2, h + 4);
13491
+ }
12735
13492
  } else {
12736
13493
  const band = Math.max(1, w * size);
12737
13494
  gradient = ctx.createLinearGradient(x + w, 0, x + w - band, 0);
12738
13495
  addStops(gradient);
12739
13496
  ctx.fillStyle = gradient;
12740
13497
  ctx.fillRect(x + w - band, y, band, h);
13498
+ if (isFullyFadedAtEdge) {
13499
+ ctx.fillStyle = "rgba(0,0,0,1)";
13500
+ const guard = Math.min(2, band);
13501
+ ctx.fillRect(x + w - guard, y - 2, guard + 2, h + 4);
13502
+ }
12741
13503
  }
12742
13504
  ctx.restore();
12743
13505
  };
@@ -12773,7 +13535,7 @@ const PageCanvas = forwardRef(
12773
13535
  (_c = group.canvas) == null ? void 0 : _c.requestRenderAll();
12774
13536
  };
12775
13537
  const loadImageAsync2 = async (element, placeholder, fc) => {
12776
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
13538
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
12777
13539
  const imageUrl = element.src || element.imageUrl;
12778
13540
  if (!imageUrl) return;
12779
13541
  const elementId = element.id;
@@ -12803,7 +13565,7 @@ const PageCanvas = forwardRef(
12803
13565
  if (!fabricRef.current || !isLatestRequest()) return;
12804
13566
  await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat);
12805
13567
  if (!isLatestRequest()) return;
12806
- const imageFitForFade = element.imageFit || ((_a = element.style) == null ? void 0 : _a.imageFit) || "cover";
13568
+ const imageFitForFade = element.imageFit || ((_a2 = element.style) == null ? void 0 : _a2.imageFit) || "cover";
12807
13569
  const clipShapeForFade = element.clipShape ?? ((_b = element.style) == null ? void 0 : _b.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
12808
13570
  const willUseCropGroupForFade = imageFitForFade !== "fill" || clipShapeForFade && clipShapeForFade !== "none";
12809
13571
  try {
@@ -13062,6 +13824,8 @@ const PageCanvas = forwardRef(
13062
13824
  fc.getActiveObjects().map((o) => getObjectId(o)).filter((id) => !!id)
13063
13825
  );
13064
13826
  const wasPlaceholderSelected = activeIdsBeforeReplace.has(elementId);
13827
+ const prevSelectionMembers = activeBeforeReplace instanceof fabric.ActiveSelection ? activeBeforeReplace.getObjects().slice() : null;
13828
+ const prevSelectionGroupId = prevSelectionMembers ? activeBeforeReplace.__pixldocsGroupSelection : null;
13065
13829
  if (!isLatestRequest()) return;
13066
13830
  const canvasObjects = fc.getObjects();
13067
13831
  const idx = canvasObjects.indexOf(placeholder);
@@ -13079,8 +13843,30 @@ const PageCanvas = forwardRef(
13079
13843
  fc.add(finalObject);
13080
13844
  }
13081
13845
  if (wasPlaceholderSelected && allowSelection) {
13082
- fc.setActiveObject(finalObject);
13083
- finalObject.setCoords();
13846
+ if (prevSelectionMembers && prevSelectionMembers.length > 1) {
13847
+ const liveObjects = new Set(fc.getObjects());
13848
+ const swapped = prevSelectionMembers.map((m) => m === placeholder ? finalObject : m).filter((m) => liveObjects.has(m));
13849
+ if (swapped.length > 1) {
13850
+ const selection = new fabric.ActiveSelection(swapped, { canvas: fc });
13851
+ if (prevSelectionGroupId) {
13852
+ selection.__pixldocsGroupSelection = prevSelectionGroupId;
13853
+ suppressGroupMemberBordersRef.current = swapped;
13854
+ swapped.forEach((m) => {
13855
+ if (m.__pixldocsOrigHasBorders === void 0) {
13856
+ m.__pixldocsOrigHasBorders = m.hasBorders;
13857
+ }
13858
+ m.hasBorders = false;
13859
+ });
13860
+ }
13861
+ fc.setActiveObject(selection);
13862
+ } else {
13863
+ fc.setActiveObject(finalObject);
13864
+ finalObject.setCoords();
13865
+ }
13866
+ } else {
13867
+ fc.setActiveObject(finalObject);
13868
+ finalObject.setCoords();
13869
+ }
13084
13870
  requestAnimationFrame(() => {
13085
13871
  skipSelectionClearOnDiscardRef.current = false;
13086
13872
  });
@@ -13098,10 +13884,10 @@ const PageCanvas = forwardRef(
13098
13884
  };
13099
13885
  const handleCanvasClick = useCallback(
13100
13886
  (e) => {
13101
- var _a;
13887
+ var _a2;
13102
13888
  if (!isActive || !fabricRef.current) return;
13103
13889
  fabricRef.current;
13104
- const rect = (_a = canvasElRef.current) == null ? void 0 : _a.getBoundingClientRect();
13890
+ const rect = (_a2 = canvasElRef.current) == null ? void 0 : _a2.getBoundingClientRect();
13105
13891
  if (!rect) return;
13106
13892
  const x = e.clientX - rect.left;
13107
13893
  const y = e.clientY - rect.top;
@@ -13308,6 +14094,53 @@ const PageCanvas = forwardRef(
13308
14094
  )
13309
14095
  ] })
13310
14096
  }
14097
+ ),
14098
+ sizeLabel && /* @__PURE__ */ jsxs(
14099
+ "div",
14100
+ {
14101
+ className: "absolute pointer-events-none flex items-center justify-center rounded-full text-white text-[10px] font-semibold shadow-md",
14102
+ style: {
14103
+ left: sizeLabel.x * zoom,
14104
+ top: sizeLabel.y * zoom,
14105
+ transform: "translate(-50%, 4px)",
14106
+ padding: "2px 6px",
14107
+ backgroundColor: "hsl(256, 80%, 58%)",
14108
+ border: "1px solid rgba(255,255,255,0.9)",
14109
+ fontFamily: "system-ui, -apple-system, sans-serif",
14110
+ lineHeight: 1,
14111
+ whiteSpace: "nowrap"
14112
+ },
14113
+ children: [
14114
+ sizeLabel.width,
14115
+ " × ",
14116
+ sizeLabel.height
14117
+ ]
14118
+ }
14119
+ ),
14120
+ rotationLabel && /* @__PURE__ */ jsxs(
14121
+ "div",
14122
+ {
14123
+ className: "absolute pointer-events-none flex items-center gap-[3px] rounded-full text-white text-[10px] font-semibold shadow-md",
14124
+ style: {
14125
+ left: rotationLabel.x * zoom,
14126
+ top: rotationLabel.y * zoom,
14127
+ transform: "translate(-50%, -50%)",
14128
+ padding: "2px 6px",
14129
+ backgroundColor: "hsl(256, 80%, 58%)",
14130
+ border: "1px solid rgba(255,255,255,0.9)",
14131
+ fontFamily: "system-ui, -apple-system, sans-serif",
14132
+ lineHeight: 1,
14133
+ whiteSpace: "nowrap"
14134
+ },
14135
+ children: [
14136
+ /* @__PURE__ */ jsxs("svg", { width: "9", height: "9", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", children: [
14137
+ /* @__PURE__ */ jsx("path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" }),
14138
+ /* @__PURE__ */ jsx("path", { d: "M21 3v5h-5" })
14139
+ ] }),
14140
+ rotationLabel.angle,
14141
+ "°"
14142
+ ]
14143
+ }
13311
14144
  )
13312
14145
  ]
13313
14146
  }
@@ -13353,12 +14186,12 @@ function PreviewCanvas({
13353
14186
  onDynamicFieldClick,
13354
14187
  onReady
13355
14188
  }) {
13356
- var _a, _b, _c, _d, _e;
14189
+ var _a2, _b, _c, _d, _e;
13357
14190
  const canvasRef = useRef(null);
13358
14191
  const containerRef = useRef(null);
13359
14192
  const [containerWidth, setContainerWidth] = useState(0);
13360
14193
  const [hoveredFieldId, setHoveredFieldId] = useState(null);
13361
- const page = (_a = config == null ? void 0 : config.pages) == null ? void 0 : _a[pageIndex];
14194
+ const page = (_a2 = config == null ? void 0 : config.pages) == null ? void 0 : _a2[pageIndex];
13362
14195
  const canvasWidth = ((_b = config == null ? void 0 : config.canvas) == null ? void 0 : _b.width) || 612;
13363
14196
  const canvasHeight = ((_c = config == null ? void 0 : config.canvas) == null ? void 0 : _c.height) || 792;
13364
14197
  const elementToFieldMap = useMemo(
@@ -13370,8 +14203,8 @@ function PreviewCanvas({
13370
14203
  [elementToFieldMap]
13371
14204
  );
13372
14205
  const laidOutPageChildren = useMemo(() => {
13373
- var _a2;
13374
- if (!((_a2 = page == null ? void 0 : page.children) == null ? void 0 : _a2.length)) return [];
14206
+ var _a3;
14207
+ if (!((_a3 = page == null ? void 0 : page.children) == null ? void 0 : _a3.length)) return [];
13375
14208
  const children = JSON.parse(JSON.stringify(page.children));
13376
14209
  const allUpdates = reflowPageFromRoot();
13377
14210
  if (allUpdates.size === 0) return children;
@@ -13409,15 +14242,15 @@ function PreviewCanvas({
13409
14242
  }
13410
14243
  }, [elements]);
13411
14244
  const pageSettings = useMemo(() => {
13412
- var _a2, _b2;
14245
+ var _a3, _b2;
13413
14246
  return {
13414
- backgroundColor: ((_a2 = page == null ? void 0 : page.settings) == null ? void 0 : _a2.backgroundColor) || "#ffffff",
14247
+ backgroundColor: ((_a3 = page == null ? void 0 : page.settings) == null ? void 0 : _a3.backgroundColor) || "#ffffff",
13415
14248
  backgroundGradient: (_b2 = page == null ? void 0 : page.settings) == null ? void 0 : _b2.backgroundGradient
13416
14249
  };
13417
14250
  }, [(_d = page == null ? void 0 : page.settings) == null ? void 0 : _d.backgroundColor, (_e = page == null ? void 0 : page.settings) == null ? void 0 : _e.backgroundGradient]);
13418
14251
  const projectSettings = useMemo(() => {
13419
- var _a2, _b2, _c2;
13420
- const vars = ((_a2 = config.themeConfig) == null ? void 0 : _a2.variables) || {};
14252
+ var _a3, _b2, _c2;
14253
+ const vars = ((_a3 = config.themeConfig) == null ? void 0 : _a3.variables) || {};
13421
14254
  return {
13422
14255
  showGrid: false,
13423
14256
  snapToGrid: false,
@@ -13449,8 +14282,8 @@ function PreviewCanvas({
13449
14282
  }, [elements, elementToFieldMap]);
13450
14283
  const [actualBounds, setActualBounds] = useState(/* @__PURE__ */ new Map());
13451
14284
  const updateBounds = useCallback(() => {
13452
- var _a2;
13453
- if ((_a2 = canvasRef.current) == null ? void 0 : _a2.getAllElementBounds) {
14285
+ var _a3;
14286
+ if ((_a3 = canvasRef.current) == null ? void 0 : _a3.getAllElementBounds) {
13454
14287
  const bounds = canvasRef.current.getAllElementBounds();
13455
14288
  setActualBounds(bounds);
13456
14289
  }
@@ -13576,10 +14409,10 @@ const PreviewCanvas$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.def
13576
14409
  PreviewCanvas
13577
14410
  }, Symbol.toStringTag, { value: "Module" }));
13578
14411
  function applyThemeToConfig(config, themeOverrides) {
13579
- var _a, _b, _c;
14412
+ var _a2, _b, _c;
13580
14413
  if (!themeOverrides || Object.keys(themeOverrides).length === 0) return config;
13581
14414
  const cloned = JSON.parse(JSON.stringify(config));
13582
- if ((_a = cloned.themeConfig) == null ? void 0 : _a.variables) {
14415
+ if ((_a2 = cloned.themeConfig) == null ? void 0 : _a2.variables) {
13583
14416
  for (const [key, value] of Object.entries(themeOverrides)) {
13584
14417
  if (cloned.themeConfig.variables[key]) {
13585
14418
  cloned.themeConfig.variables[key].value = value;
@@ -13624,7 +14457,7 @@ function mapFormDefFieldType(t) {
13624
14457
  function formDefSectionsToInferred(schemaSections, repeatableNodeMap) {
13625
14458
  const sections = [];
13626
14459
  function convert(defs, parentId) {
13627
- var _a, _b;
14460
+ var _a2, _b;
13628
14461
  for (const def of defs) {
13629
14462
  const isRepeatable = def.repeatable === true || def.type === "repeatable";
13630
14463
  const defFields = def.fields ?? def.entryFields ?? [];
@@ -13658,7 +14491,7 @@ function formDefSectionsToInferred(schemaSections, repeatableNodeMap) {
13658
14491
  };
13659
14492
  if (treeNodeId) section.treeNodeId = treeNodeId;
13660
14493
  sections.push(section);
13661
- if ((_a = def.children) == null ? void 0 : _a.length) {
14494
+ if ((_a2 = def.children) == null ? void 0 : _a2.length) {
13662
14495
  convert(def.children, def.id);
13663
14496
  }
13664
14497
  } else {
@@ -13773,11 +14606,11 @@ function findRepeatableNodesAndElementContainment(pages) {
13773
14606
  return { repeatableNodes, elementIdToRepeatableNodeId };
13774
14607
  }
13775
14608
  function inferFormSchemaFromTemplate(dynamicFields, fieldGroups, options) {
13776
- var _a;
14609
+ var _a2;
13777
14610
  const sections = [];
13778
14611
  const sortedGroups = [...fieldGroups || []].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
13779
14612
  const fieldIdsInTreeRepeatable = /* @__PURE__ */ new Set();
13780
- if ((_a = options == null ? void 0 : options.pages) == null ? void 0 : _a.length) {
14613
+ if ((_a2 = options == null ? void 0 : options.pages) == null ? void 0 : _a2.length) {
13781
14614
  const { repeatableNodes, elementIdToRepeatableNodeId } = findRepeatableNodesAndElementContainment(options.pages);
13782
14615
  const labelNorm = (s) => String(s).trim().toLowerCase();
13783
14616
  for (let idx = 0; idx < repeatableNodes.length; idx++) {
@@ -14252,29 +15085,29 @@ function setInTree(nodes, elementId, targetProperty, value) {
14252
15085
  return false;
14253
15086
  }
14254
15087
  function collectGroupsByBaseId(pages, baseNodeId) {
14255
- var _a;
15088
+ var _a2;
14256
15089
  const groups = [];
14257
15090
  function collect(children) {
14258
- var _a2;
15091
+ var _a3;
14259
15092
  if (!Array.isArray(children)) return;
14260
15093
  for (const node of children) {
14261
15094
  const base = node.__baseNodeId ?? baseId(node.id);
14262
15095
  if (base === baseNodeId) groups.push(node);
14263
- if (isGroup(node) && ((_a2 = node.children) == null ? void 0 : _a2.length)) collect(node.children);
15096
+ if (isGroup(node) && ((_a3 = node.children) == null ? void 0 : _a3.length)) collect(node.children);
14264
15097
  }
14265
15098
  }
14266
- for (const page of pages) if ((_a = page.children) == null ? void 0 : _a.length) collect(page.children);
15099
+ for (const page of pages) if ((_a2 = page.children) == null ? void 0 : _a2.length) collect(page.children);
14267
15100
  return groups;
14268
15101
  }
14269
15102
  function findElementBySourceIdInSubtree(nodes, sourceId) {
14270
- var _a;
15103
+ var _a2;
14271
15104
  const sourceBase = baseId(sourceId);
14272
15105
  for (const node of nodes) {
14273
15106
  const src = node.__sourceId;
14274
15107
  const nodeId = node.id;
14275
15108
  if (src === sourceId || nodeId === sourceId) return node.id;
14276
15109
  if (sourceBase && baseId(src ?? nodeId) === sourceBase) return node.id;
14277
- if (isGroup(node) && ((_a = node.children) == null ? void 0 : _a.length)) {
15110
+ if (isGroup(node) && ((_a2 = node.children) == null ? void 0 : _a2.length)) {
14278
15111
  const found = findElementBySourceIdInSubtree(node.children, sourceId);
14279
15112
  if (found) return found;
14280
15113
  }
@@ -14282,31 +15115,31 @@ function findElementBySourceIdInSubtree(nodes, sourceId) {
14282
15115
  return void 0;
14283
15116
  }
14284
15117
  function findAllRepeatableElementsBySourceId(pages, baseNodeId, oneBasedIndex, sourceElementId, expectedEntriesPerOccurrence) {
14285
- var _a;
15118
+ var _a2;
14286
15119
  const groups = collectGroupsByBaseId(pages, baseNodeId);
14287
15120
  if (!groups.length) return [];
14288
15121
  const N = Math.max(1, expectedEntriesPerOccurrence ?? groups.length);
14289
15122
  const out = [];
14290
15123
  for (let occStart = 0; occStart < groups.length; occStart += N) {
14291
15124
  const group = groups[occStart + (oneBasedIndex - 1)];
14292
- if (!group || !isGroup(group) || !((_a = group.children) == null ? void 0 : _a.length)) continue;
15125
+ if (!group || !isGroup(group) || !((_a2 = group.children) == null ? void 0 : _a2.length)) continue;
14293
15126
  const found = findElementBySourceIdInSubtree(group.children, sourceElementId) ?? (group.__sourceId === sourceElementId ? group.id : void 0);
14294
15127
  if (found) out.push(found);
14295
15128
  }
14296
15129
  return out;
14297
15130
  }
14298
15131
  function findNestedRepeatableElementBySourceId(pages, parentBaseNodeId, parentPi, childBaseNodeId, childCi, sourceElementId) {
14299
- var _a, _b;
15132
+ var _a2, _b;
14300
15133
  const parentGroups = collectGroupsByBaseId(pages, parentBaseNodeId);
14301
15134
  const parentGroup = parentGroups[parentPi - 1];
14302
- if (!parentGroup || !isGroup(parentGroup) || !((_a = parentGroup.children) == null ? void 0 : _a.length)) return void 0;
15135
+ if (!parentGroup || !isGroup(parentGroup) || !((_a2 = parentGroup.children) == null ? void 0 : _a2.length)) return void 0;
14303
15136
  const childGroups = [];
14304
15137
  function collectChild(children) {
14305
- var _a2;
15138
+ var _a3;
14306
15139
  for (const node of children) {
14307
15140
  const base = node.__baseNodeId ?? baseId(node.id);
14308
15141
  if (base === childBaseNodeId) childGroups.push(node);
14309
- if (isGroup(node) && ((_a2 = node.children) == null ? void 0 : _a2.length)) collectChild(node.children);
15142
+ if (isGroup(node) && ((_a3 = node.children) == null ? void 0 : _a3.length)) collectChild(node.children);
14310
15143
  }
14311
15144
  }
14312
15145
  collectChild(parentGroup.children);
@@ -14343,12 +15176,12 @@ function idPrefix(node) {
14343
15176
  function cloneNodeWithNewIds$1(node, cloneSuffix) {
14344
15177
  const oldToNew = /* @__PURE__ */ new Map();
14345
15178
  function clone(n) {
14346
- var _a;
15179
+ var _a2;
14347
15180
  const newId = cloneSuffix ? `${baseId(n.id)}__c${cloneSuffix}` : generateId(idPrefix(n));
14348
15181
  oldToNew.set(n.id, newId);
14349
15182
  const base = baseId(n.id);
14350
15183
  const withMeta = { ...n, id: newId, __baseNodeId: base, __sourceId: n.id };
14351
- if (isGroup(n) && ((_a = n.children) == null ? void 0 : _a.length)) {
15184
+ if (isGroup(n) && ((_a2 = n.children) == null ? void 0 : _a2.length)) {
14352
15185
  return { ...withMeta, children: n.children.map(clone) };
14353
15186
  }
14354
15187
  return withMeta;
@@ -14358,13 +15191,13 @@ function cloneNodeWithNewIds$1(node, cloneSuffix) {
14358
15191
  return [cloned, oldToNew];
14359
15192
  }
14360
15193
  function getRepeatableFromConfig(pages) {
14361
- var _a;
15194
+ var _a2;
14362
15195
  const result = [];
14363
15196
  function walk(children) {
14364
- var _a2, _b;
15197
+ var _a3, _b;
14365
15198
  if (!children) return;
14366
15199
  for (const node of children) {
14367
- if (isGroup(node) && isVerticalStackLayoutMode(node.layoutMode) && ((_a2 = node.children) == null ? void 0 : _a2.length)) {
15200
+ if (isGroup(node) && isVerticalStackLayoutMode(node.layoutMode) && ((_a3 = node.children) == null ? void 0 : _a3.length)) {
14368
15201
  for (const child of node.children) {
14369
15202
  const rep = child.repeatableSection;
14370
15203
  if (rep == null ? void 0 : rep.label) result.push({ nodeId: child.id, label: rep.label });
@@ -14373,24 +15206,24 @@ function getRepeatableFromConfig(pages) {
14373
15206
  if (isGroup(node) && ((_b = node.children) == null ? void 0 : _b.length)) walk(node.children);
14374
15207
  }
14375
15208
  }
14376
- for (const page of pages) if ((_a = page.children) == null ? void 0 : _a.length) walk(page.children);
15209
+ for (const page of pages) if ((_a2 = page.children) == null ? void 0 : _a2.length) walk(page.children);
14377
15210
  return result;
14378
15211
  }
14379
15212
  function findRepeatableByNodeIds(pages, nodeIds) {
14380
- var _a;
15213
+ var _a2;
14381
15214
  const schemaBaseIds = new Set(nodeIds.map((id) => baseId(id)));
14382
15215
  const result = [];
14383
15216
  const clonePattern = /^(.+)_(\d+)$/;
14384
15217
  const hasRepeatableSection = (n) => {
14385
- var _a2;
14386
- return !!((_a2 = n.repeatableSection) == null ? void 0 : _a2.label);
15218
+ var _a3;
15219
+ return !!((_a3 = n.repeatableSection) == null ? void 0 : _a3.label);
14387
15220
  };
14388
15221
  function walk(children, parentRepeatableBaseId, parentInfo, parentRepeatableEntryIndex) {
14389
- var _a2, _b;
15222
+ var _a3, _b;
14390
15223
  if (!Array.isArray(children)) return;
14391
15224
  for (let i = 0; i < children.length; i++) {
14392
15225
  const node = children[i];
14393
- if (isGroup(node) && isVerticalStackLayoutMode(node.layoutMode) && ((_a2 = node.children) == null ? void 0 : _a2.length)) {
15226
+ if (isGroup(node) && isVerticalStackLayoutMode(node.layoutMode) && ((_a3 = node.children) == null ? void 0 : _a3.length)) {
14394
15227
  const kids = node.children;
14395
15228
  let j = 0;
14396
15229
  while (j < kids.length) {
@@ -14463,22 +15296,22 @@ function findRepeatableByNodeIds(pages, nodeIds) {
14463
15296
  }
14464
15297
  }
14465
15298
  }
14466
- for (const page of pages) if ((_a = page.children) == null ? void 0 : _a.length) walk(page.children);
15299
+ for (const page of pages) if ((_a2 = page.children) == null ? void 0 : _a2.length) walk(page.children);
14467
15300
  return result;
14468
15301
  }
14469
15302
  function findAllTopLevelRepeatableBlocks(pages) {
14470
- var _a;
15303
+ var _a2;
14471
15304
  const result = [];
14472
15305
  const hasRepeatableSection = (n) => {
14473
- var _a2;
14474
- return !!((_a2 = n.repeatableSection) == null ? void 0 : _a2.label);
15306
+ var _a3;
15307
+ return !!((_a3 = n.repeatableSection) == null ? void 0 : _a3.label);
14475
15308
  };
14476
15309
  function walk(children) {
14477
- var _a2;
15310
+ var _a3;
14478
15311
  if (!Array.isArray(children)) return;
14479
15312
  for (let i = 0; i < children.length; i++) {
14480
15313
  const node = children[i];
14481
- if (!isGroup(node) || !((_a2 = node.children) == null ? void 0 : _a2.length)) continue;
15314
+ if (!isGroup(node) || !((_a3 = node.children) == null ? void 0 : _a3.length)) continue;
14482
15315
  if (hasRepeatableSection(node) && !result.some((r) => r.baseNodeId === baseId(node.id))) {
14483
15316
  result.push({
14484
15317
  parentChildren: children,
@@ -14492,7 +15325,7 @@ function findAllTopLevelRepeatableBlocks(pages) {
14492
15325
  walk(node.children);
14493
15326
  }
14494
15327
  }
14495
- for (const page of pages) if ((_a = page.children) == null ? void 0 : _a.length) walk(page.children);
15328
+ for (const page of pages) if ((_a2 = page.children) == null ? void 0 : _a2.length) walk(page.children);
14496
15329
  return result;
14497
15330
  }
14498
15331
  function getRepeatableEntryCount(nodeId, formValues) {
@@ -14518,7 +15351,7 @@ function getNestedRepeatableEntryCount(parentId, parentIndex, childId, formValue
14518
15351
  return Math.max(1, maxIndex);
14519
15352
  }
14520
15353
  function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsFromSchema, repeatableEntryCounts, repeatableNestedEntryCounts, displayFormatMap, repeatablePagesFromSchema) {
14521
- var _a, _b, _c;
15354
+ var _a2, _b, _c;
14522
15355
  const cloned = JSON.parse(JSON.stringify(config));
14523
15356
  if (!cloned.pages) return cloned;
14524
15357
  const dynamicFields = cloned.dynamicFields;
@@ -14552,7 +15385,7 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
14552
15385
  clonedPage.__repeatablePagePrefix = prefix;
14553
15386
  clonedPage.__repeatablePageEntryIndex = i;
14554
15387
  clonedPage.__repeatablePageBaseId = basePageId;
14555
- if ((_a = clonedPage.children) == null ? void 0 : _a.length) {
15388
+ if ((_a2 = clonedPage.children) == null ? void 0 : _a2.length) {
14556
15389
  const suffix = `${basePageId}_p${i}`;
14557
15390
  const reidChildren = (nodes) => nodes.map((n) => {
14558
15391
  const [reclone] = cloneNodeWithNewIds$1(n, suffix);
@@ -14598,20 +15431,20 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
14598
15431
  return item == null ? void 0 : item.entryCount;
14599
15432
  };
14600
15433
  const entryFilterFromList = (baseNodeId) => {
14601
- var _a2;
15434
+ var _a3;
14602
15435
  const item = repeatableList.find((r) => baseId(r.nodeId) === baseNodeId || r.nodeId === baseNodeId);
14603
15436
  const filter = item == null ? void 0 : item.entryFilter;
14604
- return (filter == null ? void 0 : filter.mode) === "range" && ((_a2 = filter.range) == null ? void 0 : _a2.trim()) ? filter : void 0;
15437
+ return (filter == null ? void 0 : filter.mode) === "range" && ((_a3 = filter.range) == null ? void 0 : _a3.trim()) ? filter : void 0;
14605
15438
  };
14606
15439
  const entryMetaFromList = (baseNodeId) => {
14607
15440
  const item = repeatableList.find((r) => baseId(r.nodeId) === baseNodeId || r.nodeId === baseNodeId);
14608
15441
  return item == null ? void 0 : item.entryMeta;
14609
15442
  };
14610
15443
  const nestedEntryMetaFromList = (parentBaseNodeId, parentIndex1Based, childBaseNodeId) => {
14611
- var _a2;
15444
+ var _a3;
14612
15445
  for (const { parentBaseId, childBaseId } of getNestedBasePairs(parentBaseNodeId, childBaseNodeId)) {
14613
15446
  const item = repeatableList.find((r) => baseId(r.nodeId) === childBaseId || r.nodeId === childBaseId);
14614
- const meta = (_a2 = item == null ? void 0 : item.nestedEntryMeta) == null ? void 0 : _a2[`${parentBaseId}_${parentIndex1Based}_${childBaseId}`];
15447
+ const meta = (_a3 = item == null ? void 0 : item.nestedEntryMeta) == null ? void 0 : _a3[`${parentBaseId}_${parentIndex1Based}_${childBaseId}`];
14615
15448
  if (meta == null ? void 0 : meta.length) return meta;
14616
15449
  }
14617
15450
  return entryMetaFromList(childBaseNodeId);
@@ -14739,12 +15572,12 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
14739
15572
  for (const [childBaseNodeId, blocks] of byChildBase) {
14740
15573
  const parentBaseNodeId = nestedChildToParent.get(childBaseNodeId);
14741
15574
  blocks.forEach((block, parentIndex0) => {
14742
- var _a2;
15575
+ var _a3;
14743
15576
  const parentIndex1Based = block.parentEntryIndex ?? parentIndex0 + 1;
14744
15577
  const { parentChildren, startIndex, count, node, baseNodeId } = block;
14745
15578
  const N = getNestedCountForBasePair(parentBaseNodeId, parentIndex1Based, baseNodeId);
14746
15579
  const phase1Map = phase1NewToOriginal.get(`${parentBaseNodeId}_${parentIndex1Based}`);
14747
- const nestedEntryFilter = ((_a2 = node.repeatableSection) == null ? void 0 : _a2.entryFilter) ?? entryFilterFromList(baseNodeId);
15580
+ const nestedEntryFilter = ((_a3 = node.repeatableSection) == null ? void 0 : _a3.entryFilter) ?? entryFilterFromList(baseNodeId);
14748
15581
  let nestedEntryIndices;
14749
15582
  if (nestedEntryFilter && nestedEntryFilter.mode === "range" && nestedEntryFilter.range) {
14750
15583
  const parsed = parseEntryRange(nestedEntryFilter.range, N, nestedEntryMetaFromList(parentBaseNodeId, parentIndex1Based, baseNodeId));
@@ -14883,7 +15716,7 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
14883
15716
  return void 0;
14884
15717
  }
14885
15718
  const applyValue = (elementId, targetProperty, value, fieldKey) => {
14886
- var _a2;
15719
+ var _a3;
14887
15720
  const isTextLike = targetProperty === "text" || targetProperty === "content";
14888
15721
  if (value === void 0 || value === null) {
14889
15722
  return false;
@@ -14908,7 +15741,7 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
14908
15741
  }
14909
15742
  }
14910
15743
  if (elementId === PAGE_BACKGROUND_ELEMENT_ID && targetProperty === "backgroundColor" && typeof effectiveValue === "string") {
14911
- if ((_a2 = pages[0]) == null ? void 0 : _a2.settings) {
15744
+ if ((_a3 = pages[0]) == null ? void 0 : _a3.settings) {
14912
15745
  pages[0].settings.backgroundColor = effectiveValue;
14913
15746
  return true;
14914
15747
  }
@@ -15042,14 +15875,14 @@ function applyFormDataToConfig(config, mappings, formValues, repeatableSectionsF
15042
15875
  }
15043
15876
  if ((repeatablePagesFromSchema == null ? void 0 : repeatablePagesFromSchema.length) && (dynamicFields == null ? void 0 : dynamicFields.length)) {
15044
15877
  const findInPage = (page, originalId) => {
15045
- var _a2;
15046
- if (!((_a2 = page.children) == null ? void 0 : _a2.length)) return void 0;
15878
+ var _a3;
15879
+ if (!((_a3 = page.children) == null ? void 0 : _a3.length)) return void 0;
15047
15880
  const findIn = (nodes) => {
15048
- var _a3;
15881
+ var _a4;
15049
15882
  for (const n of nodes) {
15050
15883
  const src = n.__sourceId;
15051
15884
  if (n.id === originalId || src === originalId || baseId(n.id) === baseId(originalId)) return n.id;
15052
- if (isGroup(n) && ((_a3 = n.children) == null ? void 0 : _a3.length)) {
15885
+ if (isGroup(n) && ((_a4 = n.children) == null ? void 0 : _a4.length)) {
15053
15886
  const f = findIn(n.children);
15054
15887
  if (f) return f;
15055
15888
  }
@@ -15145,24 +15978,24 @@ function findFlowStack(pageChildren) {
15145
15978
  return all.length > 0 ? all[0] : null;
15146
15979
  }
15147
15980
  function findAllFlowStacks(pageChildren) {
15148
- var _a;
15981
+ var _a2;
15149
15982
  const result = [];
15150
15983
  for (const node of pageChildren) {
15151
15984
  if (!isGroup(node)) continue;
15152
15985
  const g = node;
15153
- if (!isVerticalStackLayoutMode(g.layoutMode) || !((_a = g.children) == null ? void 0 : _a.length)) continue;
15986
+ if (!isVerticalStackLayoutMode(g.layoutMode) || !((_a2 = g.children) == null ? void 0 : _a2.length)) continue;
15154
15987
  if (g.children.some(hasBaseNodeId)) result.push(g);
15155
15988
  }
15156
15989
  return result;
15157
15990
  }
15158
15991
  function findNestedFlowStack(entry) {
15159
- var _a, _b;
15992
+ var _a2, _b;
15160
15993
  const queue = [...entry.children ?? []];
15161
15994
  while (queue.length > 0) {
15162
15995
  const node = queue.shift();
15163
15996
  if (!isGroup(node)) continue;
15164
15997
  const g = node;
15165
- const hasRepeatableChildren = ((_a = g.children) == null ? void 0 : _a.length) && (g.children.some(hasBaseNodeId) || g.children.some((c) => isGroup(c)));
15998
+ const hasRepeatableChildren = ((_a2 = g.children) == null ? void 0 : _a2.length) && (g.children.some(hasBaseNodeId) || g.children.some((c) => isGroup(c)));
15166
15999
  if (isVerticalStackLayoutMode(g.layoutMode) && hasRepeatableChildren) return g;
15167
16000
  if ((_b = g.children) == null ? void 0 : _b.length) queue.push(...g.children);
15168
16001
  }
@@ -15183,8 +16016,8 @@ function replaceNestedFlowStackChildren(entry, nestedStackId, newChildren, setTo
15183
16016
  return walk(entry);
15184
16017
  }
15185
16018
  function splitEntryAtNested(entry, pageChildren, contentBottom) {
15186
- var _a;
15187
- const entryIsNestedStack = isVerticalStackLayoutMode(entry.layoutMode) && ((_a = entry.children) == null ? void 0 : _a.length) && (entry.children.some(hasBaseNodeId) || entry.children.some((c) => isGroup(c)));
16019
+ var _a2;
16020
+ const entryIsNestedStack = isVerticalStackLayoutMode(entry.layoutMode) && ((_a2 = entry.children) == null ? void 0 : _a2.length) && (entry.children.some(hasBaseNodeId) || entry.children.some((c) => isGroup(c)));
15188
16021
  const nested = entryIsNestedStack ? entry : findNestedFlowStack(entry);
15189
16022
  if (!nested) return { stayVersion: null, overflowVersion: entry };
15190
16023
  const nestedKids = nested.children ?? [];
@@ -15295,8 +16128,8 @@ function splitNestedForOverflow(flowStack, stayChildren, overflowChildren, overf
15295
16128
  return { stayChildren: newStay, overflowChildren: newOverflow };
15296
16129
  }
15297
16130
  function paginateSinglePage(sourcePage, pageOffsetIndex) {
15298
- var _a, _b, _c, _d, _e, _f;
15299
- const contentTop = (_a = sourcePage.settings) == null ? void 0 : _a.contentTop;
16131
+ var _a2, _b, _c, _d, _e, _f;
16132
+ const contentTop = (_a2 = sourcePage.settings) == null ? void 0 : _a2.contentTop;
15300
16133
  const contentBottom = (_b = sourcePage.settings) == null ? void 0 : _b.contentBottom;
15301
16134
  if (contentTop == null || contentBottom == null || contentBottom <= contentTop) {
15302
16135
  return [sourcePage];
@@ -16161,10 +16994,10 @@ const resolveBestRegisteredVariant = (family, weight, italic) => {
16161
16994
  return null;
16162
16995
  };
16163
16996
  const doesVariantSupportChar = (family, weight, italic, char) => {
16164
- var _a;
16997
+ var _a2;
16165
16998
  const cp = char.codePointAt(0);
16166
16999
  if (cp == null) return false;
16167
- return ((_a = registeredVariantCoverage.get(variantKey(family, weight, italic))) == null ? void 0 : _a.has(cp)) === true;
17000
+ return ((_a2 = registeredVariantCoverage.get(variantKey(family, weight, italic))) == null ? void 0 : _a2.has(cp)) === true;
16168
17001
  };
16169
17002
  function bytesToBase64(bytes) {
16170
17003
  let binary = "";
@@ -16172,9 +17005,9 @@ function bytesToBase64(bytes) {
16172
17005
  return btoa(binary);
16173
17006
  }
16174
17007
  function getFontProxyUrl() {
16175
- var _a;
17008
+ var _a2;
16176
17009
  const viteUrl = (__vite_import_meta_env__ == null ? void 0 : __vite_import_meta_env__.VITE_SUPABASE_URL) || "";
16177
- const runtimeUrl = typeof globalThis !== "undefined" ? ((_a = globalThis.__CONFIG__) == null ? void 0 : _a.supabaseUrl) || globalThis.__PIXLDOCS_SUPABASE_URL || "" : "";
17010
+ const runtimeUrl = typeof globalThis !== "undefined" ? ((_a2 = globalThis.__CONFIG__) == null ? void 0 : _a2.supabaseUrl) || globalThis.__PIXLDOCS_SUPABASE_URL || "" : "";
16178
17011
  const baseUrl = (viteUrl || runtimeUrl || "").replace(/\/$/, "");
16179
17012
  return baseUrl ? `${baseUrl}/functions/v1/font-proxy` : null;
16180
17013
  }
@@ -16487,20 +17320,20 @@ function splitIntoRuns(text, mainSupportsChar) {
16487
17320
  return runs;
16488
17321
  }
16489
17322
  function rewriteSvgFontsForJsPDF(svgStr) {
16490
- var _a, _b;
17323
+ var _a2, _b;
16491
17324
  const parser = new DOMParser();
16492
17325
  const doc = parser.parseFromString(svgStr, "image/svg+xml");
16493
17326
  const allTextEls = Array.from(doc.querySelectorAll("text, tspan, textPath"));
16494
17327
  const readStyleToken = (style, prop) => {
16495
- var _a2;
17328
+ var _a3;
16496
17329
  const match = style.match(new RegExp(`${prop}\\s*:\\s*([^;]+)`, "i"));
16497
- return ((_a2 = match == null ? void 0 : match[1]) == null ? void 0 : _a2.trim()) || null;
17330
+ return ((_a3 = match == null ? void 0 : match[1]) == null ? void 0 : _a3.trim()) || null;
16498
17331
  };
16499
17332
  const resolveInheritedValue = (el, attr, styleProp = attr) => {
16500
- var _a2;
17333
+ var _a3;
16501
17334
  let current = el;
16502
17335
  while (current) {
16503
- const attrVal = (_a2 = current.getAttribute(attr)) == null ? void 0 : _a2.trim();
17336
+ const attrVal = (_a3 = current.getAttribute(attr)) == null ? void 0 : _a3.trim();
16504
17337
  if (attrVal) return attrVal;
16505
17338
  const styleVal = readStyleToken(current.getAttribute("style") || "", styleProp);
16506
17339
  if (styleVal) return styleVal;
@@ -16540,7 +17373,7 @@ function rewriteSvgFontsForJsPDF(svgStr) {
16540
17373
  const inlineStyle = el.getAttribute("style") || "";
16541
17374
  const rawFf = resolveInheritedValue(el, "font-family");
16542
17375
  if (!rawFf) continue;
16543
- const clean = (_a = rawFf.split(",")[0]) == null ? void 0 : _a.replace(/['"]/g, "").trim();
17376
+ const clean = (_a2 = rawFf.split(",")[0]) == null ? void 0 : _a2.replace(/['"]/g, "").trim();
16544
17377
  if (!isFontAvailable(clean) && !isFamilyEmbedded(clean)) continue;
16545
17378
  const weightRaw = resolveInheritedValue(el, "font-weight") || "400";
16546
17379
  const styleRaw = resolveInheritedValue(el, "font-style") || "normal";
@@ -16688,20 +17521,20 @@ function extractFontFamiliesFromSvgs(svgs) {
16688
17521
  return families;
16689
17522
  }
16690
17523
  async function embedFontVariantsFromSvg(pdf, svgStr, fontBaseUrl) {
16691
- var _a;
17524
+ var _a2;
16692
17525
  const parser = new DOMParser();
16693
17526
  const doc = parser.parseFromString(svgStr, "image/svg+xml");
16694
17527
  const textEls = Array.from(doc.querySelectorAll("text, tspan, textPath"));
16695
17528
  const readStyleToken = (style, prop) => {
16696
- var _a2;
17529
+ var _a3;
16697
17530
  const m = style.match(new RegExp(`${prop}\\s*:\\s*([^;]+)`, "i"));
16698
- return ((_a2 = m == null ? void 0 : m[1]) == null ? void 0 : _a2.trim()) || null;
17531
+ return ((_a3 = m == null ? void 0 : m[1]) == null ? void 0 : _a3.trim()) || null;
16699
17532
  };
16700
17533
  const resolveInherited = (el, attr, styleProp = attr) => {
16701
- var _a2;
17534
+ var _a3;
16702
17535
  let cur = el;
16703
17536
  while (cur) {
16704
- const a = (_a2 = cur.getAttribute(attr)) == null ? void 0 : _a2.trim();
17537
+ const a = (_a3 = cur.getAttribute(attr)) == null ? void 0 : _a3.trim();
16705
17538
  if (a) return a;
16706
17539
  const s = readStyleToken(cur.getAttribute("style") || "", styleProp);
16707
17540
  if (s) return s;
@@ -16723,7 +17556,7 @@ async function embedFontVariantsFromSvg(pdf, svgStr, fontBaseUrl) {
16723
17556
  for (const el of textEls) {
16724
17557
  const rawFf = resolveInherited(el, "font-family");
16725
17558
  if (!rawFf) continue;
16726
- const family = (_a = rawFf.split(",")[0]) == null ? void 0 : _a.replace(/['"]/g, "").trim();
17559
+ const family = (_a2 = rawFf.split(",")[0]) == null ? void 0 : _a2.replace(/['"]/g, "").trim();
16727
17560
  if (!family) continue;
16728
17561
  const weight = resolveFontWeight(parseWeight(resolveInherited(el, "font-weight") || "400"));
16729
17562
  const italic = /italic|oblique/i.test(resolveInherited(el, "font-style") || "normal");
@@ -16902,9 +17735,9 @@ function appendDataUriFontFaceRule(family, weight, style, dataUri) {
16902
17735
  styleEl.appendChild(document.createTextNode(cssText));
16903
17736
  }
16904
17737
  function resolveHarnessFontProxyUrl() {
16905
- var _a, _b;
17738
+ var _a2, _b;
16906
17739
  try {
16907
- 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)) || "";
17740
+ 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)) || "";
16908
17741
  const base = String(runtimeBase || "").replace(/\/$/, "");
16909
17742
  return base ? `${base}/functions/v1/font-proxy` : "";
16910
17743
  } catch {
@@ -17065,16 +17898,16 @@ async function loadGoogleFontCSS(rawFontFamily) {
17065
17898
  loadingPromises.delete(fontFamily);
17066
17899
  }
17067
17900
  function collectFontsFromConfig(config) {
17068
- var _a;
17901
+ var _a2;
17069
17902
  const fonts = /* @__PURE__ */ new Set();
17070
17903
  fonts.add("Open Sans");
17071
17904
  fonts.add("Hind");
17072
17905
  function walk(nodes) {
17073
- var _a2;
17906
+ var _a3;
17074
17907
  if (!nodes) return;
17075
17908
  for (const node of nodes) {
17076
17909
  if (node.fontFamily) fonts.add(normalizeFontFamily(node.fontFamily));
17077
- if ((_a2 = node.smartProps) == null ? void 0 : _a2.fontFamily) fonts.add(normalizeFontFamily(node.smartProps.fontFamily));
17910
+ if ((_a3 = node.smartProps) == null ? void 0 : _a3.fontFamily) fonts.add(normalizeFontFamily(node.smartProps.fontFamily));
17078
17911
  if (node.styles && Array.isArray(node.styles)) {
17079
17912
  for (const lineStyle of node.styles) {
17080
17913
  if (lineStyle && typeof lineStyle === "object") {
@@ -17090,7 +17923,7 @@ function collectFontsFromConfig(config) {
17090
17923
  for (const page of config.pages || []) {
17091
17924
  walk(page.children || []);
17092
17925
  }
17093
- if ((_a = config.themeConfig) == null ? void 0 : _a.variables) {
17926
+ if ((_a2 = config.themeConfig) == null ? void 0 : _a2.variables) {
17094
17927
  for (const def of Object.values(config.themeConfig.variables)) {
17095
17928
  if (def.value && typeof def.value === "string" && !def.value.startsWith("#") && !def.value.startsWith("rgb")) {
17096
17929
  if (def.label && /font/i.test(def.label)) {
@@ -17102,7 +17935,7 @@ function collectFontsFromConfig(config) {
17102
17935
  return fonts;
17103
17936
  }
17104
17937
  function collectFontDescriptorsFromConfig(config, includeCommonTextVariants = true) {
17105
- var _a;
17938
+ var _a2;
17106
17939
  const seen = /* @__PURE__ */ new Set();
17107
17940
  const descriptors = [];
17108
17941
  function add(family, weight, style) {
@@ -17116,7 +17949,7 @@ function collectFontDescriptorsFromConfig(config, includeCommonTextVariants = tr
17116
17949
  descriptors.push({ family: f, weight: w, style: s });
17117
17950
  }
17118
17951
  function walk(nodes) {
17119
- var _a2;
17952
+ var _a3;
17120
17953
  if (!nodes) return;
17121
17954
  for (const node of nodes) {
17122
17955
  if (node.fontFamily) {
@@ -17144,7 +17977,7 @@ function collectFontDescriptorsFromConfig(config, includeCommonTextVariants = tr
17144
17977
  }
17145
17978
  }
17146
17979
  }
17147
- if ((_a2 = node.smartProps) == null ? void 0 : _a2.fontFamily) {
17980
+ if ((_a3 = node.smartProps) == null ? void 0 : _a3.fontFamily) {
17148
17981
  add(node.smartProps.fontFamily, node.smartProps.fontWeight, node.smartProps.fontStyle);
17149
17982
  }
17150
17983
  if (node.styles) {
@@ -17168,7 +18001,7 @@ function collectFontDescriptorsFromConfig(config, includeCommonTextVariants = tr
17168
18001
  for (const page of config.pages || []) {
17169
18002
  walk(page.children || []);
17170
18003
  }
17171
- if ((_a = config.themeConfig) == null ? void 0 : _a.variables) {
18004
+ if ((_a2 = config.themeConfig) == null ? void 0 : _a2.variables) {
17172
18005
  for (const def of Object.values(config.themeConfig.variables)) {
17173
18006
  if (def.value && typeof def.value === "string" && !def.value.startsWith("#") && !def.value.startsWith("rgb")) {
17174
18007
  if (def.label && /font/i.test(def.label)) {
@@ -17205,8 +18038,8 @@ async function ensureFontsForResolvedConfig(config) {
17205
18038
  }
17206
18039
  }
17207
18040
  function configHasAutoShrinkText$1(config) {
17208
- var _a;
17209
- if (!((_a = config == null ? void 0 : config.pages) == null ? void 0 : _a.length)) return false;
18041
+ var _a2;
18042
+ if (!((_a2 = config == null ? void 0 : config.pages) == null ? void 0 : _a2.length)) return false;
17210
18043
  const walk = (nodes) => {
17211
18044
  for (const node of nodes || []) {
17212
18045
  if (!node) continue;
@@ -17339,8 +18172,8 @@ function mergeRepeatableEntryMeta(target, metaSource, sections) {
17339
18172
  return changed ? next : target;
17340
18173
  }
17341
18174
  function buildRepeatablePagesInputForApply(schema, sectionState) {
17342
- var _a;
17343
- if (!((_a = schema == null ? void 0 : schema.repeatablePages) == null ? void 0 : _a.length)) return [];
18175
+ var _a2;
18176
+ if (!((_a2 = schema == null ? void 0 : schema.repeatablePages) == null ? void 0 : _a2.length)) return [];
17344
18177
  const normalizeTemplateKeyPrefix = (prefix) => {
17345
18178
  if (!prefix || typeof prefix !== "string") return "";
17346
18179
  return prefix.replace(/^field_/, "");
@@ -17566,7 +18399,7 @@ async function resolveTemplateData(options) {
17566
18399
  };
17567
18400
  }
17568
18401
  async function resolveFromForm(options) {
17569
- var _a, _b, _c;
18402
+ var _a2, _b, _c;
17570
18403
  const { templateId, formSchemaId, sectionState, flatFormData: directFlatFormData, themeId, supabaseUrl, supabaseAnonKey, prefetched } = options;
17571
18404
  const hasSectionStateInput = !!sectionState && Object.keys(sectionState).length > 0;
17572
18405
  if (!formSchemaId && !hasSectionStateInput) {
@@ -17611,7 +18444,7 @@ async function resolveFromForm(options) {
17611
18444
  let inferredSections;
17612
18445
  if (schemaSections == null ? void 0 : schemaSections.length) {
17613
18446
  inferredSections = formDefSectionsToInferred(schemaSections, repeatableNodeMap);
17614
- } else if ((_a = templateConfig.dynamicFields) == null ? void 0 : _a.length) {
18447
+ } else if ((_a2 = templateConfig.dynamicFields) == null ? void 0 : _a2.length) {
17615
18448
  const groups = templateConfig.fieldGroups || [];
17616
18449
  inferredSections = inferFormSchemaFromTemplate(
17617
18450
  templateConfig.dynamicFields,
@@ -17799,9 +18632,9 @@ function themeBaseId(id) {
17799
18632
  return out;
17800
18633
  }
17801
18634
  function applyThemeVariantToConfig(config, themeConfig, themeId) {
17802
- var _a, _b, _c, _d;
18635
+ var _a2, _b, _c, _d;
17803
18636
  if (!themeConfig) return config;
17804
- const variant = themeId && themeId !== "default" ? (_a = themeConfig.variants) == null ? void 0 : _a.find((v) => v.id === themeId) : null;
18637
+ const variant = themeId && themeId !== "default" ? (_a2 = themeConfig.variants) == null ? void 0 : _a2.find((v) => v.id === themeId) : null;
17805
18638
  const shouldApplyDefaults = !variant && ((_b = themeConfig.properties) == null ? void 0 : _b.length);
17806
18639
  if (!variant && !shouldApplyDefaults) return config;
17807
18640
  if (!((_c = themeConfig.properties) == null ? void 0 : _c.length)) return config;
@@ -17823,8 +18656,8 @@ function applyThemeVariantToConfig(config, themeConfig, themeId) {
17823
18656
  if (stopMatch) {
17824
18657
  const stopIndex = parseInt(stopMatch[1], 10);
17825
18658
  result.pages.forEach((p) => {
17826
- var _a2, _b2;
17827
- if ((_b2 = (_a2 = p.settings.backgroundGradient) == null ? void 0 : _a2.stops) == null ? void 0 : _b2[stopIndex]) {
18659
+ var _a3, _b2;
18660
+ if ((_b2 = (_a3 = p.settings.backgroundGradient) == null ? void 0 : _a3.stops) == null ? void 0 : _b2[stopIndex]) {
17828
18661
  p.settings.backgroundGradient = {
17829
18662
  ...p.settings.backgroundGradient,
17830
18663
  stops: p.settings.backgroundGradient.stops.map(
@@ -17901,7 +18734,7 @@ function normalizeLayoutModes(config) {
17901
18734
  }
17902
18735
  }
17903
18736
  function paintRepeatableSections(config, repeatableSections, formSchema) {
17904
- var _a, _b;
18737
+ var _a2, _b;
17905
18738
  const pages = config.pages ?? [];
17906
18739
  const entryFilters = (formSchema == null ? void 0 : formSchema.entryFilters) ?? [];
17907
18740
  const entryFilterBases = new Set(entryFilters.map((f) => baseId(f.nodeId)));
@@ -17929,7 +18762,7 @@ function paintRepeatableSections(config, repeatableSections, formSchema) {
17929
18762
  return painted;
17930
18763
  }
17931
18764
  for (const section of repeatableSections) {
17932
- const inlineRange = ((_a = section.entryFilter) == null ? void 0 : _a.mode) === "range" ? (_b = section.entryFilter.range) == null ? void 0 : _b.trim() : void 0;
18765
+ const inlineRange = ((_a2 = section.entryFilter) == null ? void 0 : _a2.mode) === "range" ? (_b = section.entryFilter.range) == null ? void 0 : _b.trim() : void 0;
17933
18766
  const shouldUseInlineFilter = !!inlineRange && !entryFilterBases.has(baseId(section.nodeId));
17934
18767
  const payload = { label: section.label };
17935
18768
  if (section.minEntries !== void 0) payload.minEntries = section.minEntries;
@@ -17942,9 +18775,9 @@ function paintRepeatableSections(config, repeatableSections, formSchema) {
17942
18775
  if (entryFilters.length) {
17943
18776
  const occurrencesByBase = /* @__PURE__ */ new Map();
17944
18777
  const collect = (nodes) => {
17945
- var _a2;
18778
+ var _a3;
17946
18779
  for (const node of nodes ?? []) {
17947
- if ((_a2 = node.repeatableSection) == null ? void 0 : _a2.label) {
18780
+ if ((_a3 = node.repeatableSection) == null ? void 0 : _a3.label) {
17948
18781
  const base = baseId(node.id);
17949
18782
  if (!occurrencesByBase.has(base)) occurrencesByBase.set(base, []);
17950
18783
  occurrencesByBase.get(base).push(node);
@@ -17965,7 +18798,7 @@ function paintRepeatableSections(config, repeatableSections, formSchema) {
17965
18798
  }
17966
18799
  }
17967
18800
  async function getTemplateForm(options) {
17968
- var _a, _b;
18801
+ var _a2, _b;
17969
18802
  const { templateId, supabaseUrl, supabaseAnonKey } = options;
17970
18803
  if (!supabaseUrl || !supabaseAnonKey) {
17971
18804
  throw new Error("[getTemplateForm] supabaseUrl and supabaseAnonKey are required");
@@ -18005,7 +18838,7 @@ async function getTemplateForm(options) {
18005
18838
  let sections;
18006
18839
  if (schemaSections == null ? void 0 : schemaSections.length) {
18007
18840
  sections = formDefSectionsToInferred(schemaSections, repeatableNodeMap);
18008
- } else if ((_a = templateConfig.dynamicFields) == null ? void 0 : _a.length) {
18841
+ } else if ((_a2 = templateConfig.dynamicFields) == null ? void 0 : _a2.length) {
18009
18842
  sections = inferFormSchemaFromTemplate(
18010
18843
  templateConfig.dynamicFields,
18011
18844
  templateConfig.fieldGroups || [],
@@ -18283,28 +19116,28 @@ const previewBlur = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineP
18283
19116
  }, Symbol.toStringTag, { value: "Module" }));
18284
19117
  const PREVIEW_DEBUG_PREFIX = "[canvas-renderer][preview-debug]";
18285
19118
  function computeFontSignature(config) {
18286
- var _a;
18287
- if (!((_a = config == null ? void 0 : config.pages) == null ? void 0 : _a.length)) return "";
19119
+ var _a2;
19120
+ if (!((_a2 = config == null ? void 0 : config.pages) == null ? void 0 : _a2.length)) return "";
18288
19121
  const fams = /* @__PURE__ */ new Set();
18289
19122
  const walk = (nodes) => {
18290
- var _a2;
19123
+ var _a3;
18291
19124
  for (const node of nodes || []) {
18292
19125
  if (node == null ? void 0 : node.fontFamily) fams.add(String(node.fontFamily));
18293
- if ((_a2 = node == null ? void 0 : node.children) == null ? void 0 : _a2.length) walk(node.children);
19126
+ if ((_a3 = node == null ? void 0 : node.children) == null ? void 0 : _a3.length) walk(node.children);
18294
19127
  }
18295
19128
  };
18296
19129
  for (const page of config.pages) walk(page.children || []);
18297
19130
  return Array.from(fams).sort().join("|");
18298
19131
  }
18299
19132
  function countUnderlinedNodes(config) {
18300
- var _a;
18301
- if (!((_a = config == null ? void 0 : config.pages) == null ? void 0 : _a.length)) return 0;
19133
+ var _a2;
19134
+ if (!((_a2 = config == null ? void 0 : config.pages) == null ? void 0 : _a2.length)) return 0;
18302
19135
  let count = 0;
18303
19136
  const walk = (nodes) => {
18304
- var _a2;
19137
+ var _a3;
18305
19138
  for (const node of nodes || []) {
18306
19139
  if (node == null ? void 0 : node.underline) count += 1;
18307
- if ((_a2 = node == null ? void 0 : node.children) == null ? void 0 : _a2.length) walk(node.children);
19140
+ if ((_a3 = node == null ? void 0 : node.children) == null ? void 0 : _a3.length) walk(node.children);
18308
19141
  }
18309
19142
  };
18310
19143
  for (const page of config.pages) walk(page.children || []);
@@ -18336,8 +19169,8 @@ function collectBlurBounds(node, parentLeft, parentTop, inheritedBlur, extraBase
18336
19169
  out.push({ left: absLeft, top: absTop, width: w, height: h });
18337
19170
  }
18338
19171
  function computeFrostedBoundsForPage(config, pageIndex, extraBaseIds, extraExactIds) {
18339
- var _a;
18340
- const page = (_a = config == null ? void 0 : config.pages) == null ? void 0 : _a[pageIndex];
19172
+ var _a2;
19173
+ const page = (_a2 = config == null ? void 0 : config.pages) == null ? void 0 : _a2[pageIndex];
18341
19174
  const children = (page == null ? void 0 : page.children) || (page == null ? void 0 : page.elements);
18342
19175
  if (!Array.isArray(children)) return [];
18343
19176
  const out = [];
@@ -18346,7 +19179,7 @@ function computeFrostedBoundsForPage(config, pageIndex, extraBaseIds, extraExact
18346
19179
  return out;
18347
19180
  }
18348
19181
  function PixldocsPreview(props) {
18349
- var _a, _b;
19182
+ var _a2, _b;
18350
19183
  const {
18351
19184
  pageIndex = 0,
18352
19185
  zoom = 1,
@@ -18357,6 +19190,7 @@ function PixldocsPreview(props) {
18357
19190
  onDynamicFieldClick,
18358
19191
  onReady,
18359
19192
  onError,
19193
+ loadingFallback,
18360
19194
  // Default `false` so PageCanvas blocks textbox creation until the host
18361
19195
  // browser actually has the @font-face rules registered. This matters for
18362
19196
  // `overflowPolicy: 'auto-shrink'` text — `createText` runs the shrink
@@ -18413,10 +19247,10 @@ function PixldocsPreview(props) {
18413
19247
  supabaseUrl: p.supabaseUrl,
18414
19248
  supabaseAnonKey: p.supabaseAnonKey
18415
19249
  }).then((resolved) => {
18416
- var _a2, _b2;
19250
+ var _a3, _b2;
18417
19251
  if (!cancelled) {
18418
19252
  console.log(PREVIEW_DEBUG_PREFIX, "resolve-done", {
18419
- pages: ((_b2 = (_a2 = resolved.config) == null ? void 0 : _a2.pages) == null ? void 0 : _b2.length) ?? 0,
19253
+ pages: ((_b2 = (_a3 = resolved.config) == null ? void 0 : _a3.pages) == null ? void 0 : _b2.length) ?? 0,
18420
19254
  underlinedNodes: countUnderlinedNodes(resolved.config)
18421
19255
  });
18422
19256
  setResolvedConfig(resolved.config);
@@ -18525,15 +19359,15 @@ function PixldocsPreview(props) {
18525
19359
  const blurPx = (frostedBlurOptions == null ? void 0 : frostedBlurOptions.blurPx) ?? 5;
18526
19360
  const satPct = (frostedBlurOptions == null ? void 0 : frostedBlurOptions.saturatePct) ?? 130;
18527
19361
  const bgTint = (frostedBlurOptions == null ? void 0 : frostedBlurOptions.background) ?? "rgba(255,255,255,0.12)";
18528
- const canvasW = getNum((_a = config == null ? void 0 : config.canvas) == null ? void 0 : _a.width, 0);
19362
+ const canvasW = getNum((_a2 = config == null ? void 0 : config.canvas) == null ? void 0 : _a2.width, 0);
18529
19363
  const canvasH = getNum((_b = config == null ? void 0 : config.canvas) == null ? void 0 : _b.height, 0);
18530
19364
  const hasOverlays = frostedBounds.length > 0 && canvasW > 0 && canvasH > 0;
18531
19365
  if (isLoading) {
18532
- return /* @__PURE__ */ jsx("div", { className, style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
19366
+ return /* @__PURE__ */ jsx("div", { className, style: { ...style, position: "relative", minHeight: 200, display: "flex", alignItems: "center", justifyContent: "center" }, children: loadingFallback ?? /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
18533
19367
  }
18534
19368
  if (!config) return null;
18535
19369
  if (!fontsReady) {
18536
- return /* @__PURE__ */ jsx("div", { className, style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
19370
+ return /* @__PURE__ */ jsx("div", { className, style: { ...style, position: "relative", minHeight: 200, display: "flex", alignItems: "center", justifyContent: "center" }, children: loadingFallback ?? /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
18537
19371
  }
18538
19372
  return /* @__PURE__ */ jsxs("div", { className, style: { ...style, position: "relative" }, children: [
18539
19373
  /* @__PURE__ */ jsxs(
@@ -18585,7 +19419,7 @@ function PixldocsPreview(props) {
18585
19419
  ]
18586
19420
  }
18587
19421
  ),
18588
- !canvasSettled && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
19422
+ !canvasSettled && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: loadingFallback ?? /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
18589
19423
  ] });
18590
19424
  }
18591
19425
  function normalizeSvgDimensions(svg, targetWidth, targetHeight) {
@@ -18667,7 +19501,7 @@ function ensureFabricGradientDef(doc, obj, width, height) {
18667
19501
  return `url(#${id})`;
18668
19502
  }
18669
19503
  function warpTextboxSvgAlongPath(svg, obj) {
18670
- var _a, _b, _c, _d, _e;
19504
+ var _a2, _b, _c, _d, _e;
18671
19505
  const tp = obj == null ? void 0 : obj.textPath;
18672
19506
  if (!tp || !tp.preset || tp.preset === "none") return svg;
18673
19507
  if (tp.preset === "rise" || tp.preset === "angle") {
@@ -18725,7 +19559,7 @@ function warpTextboxSvgAlongPath(svg, obj) {
18725
19559
  }
18726
19560
  for (const marker of Array.from(doc.querySelectorAll("g.__pdShadowRaster"))) {
18727
19561
  try {
18728
- (_a = marker.parentNode) == null ? void 0 : _a.removeChild(marker);
19562
+ (_a2 = marker.parentNode) == null ? void 0 : _a2.removeChild(marker);
18729
19563
  } catch {
18730
19564
  }
18731
19565
  }
@@ -18751,9 +19585,9 @@ function warpTextboxSvgAlongPath(svg, obj) {
18751
19585
  const fw = obj.fontWeight ?? 400;
18752
19586
  const fst = obj.fontStyle || "normal";
18753
19587
  const readFill = (el) => {
18754
- var _a2, _b2;
19588
+ var _a3, _b2;
18755
19589
  if (!el) return "";
18756
- 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()) || "";
19590
+ 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()) || "";
18757
19591
  };
18758
19592
  const w = Number(obj.width) || 0;
18759
19593
  const h = Number(obj.height) || 0;
@@ -18946,7 +19780,7 @@ function stampFabricLineMetricsOnTextSvg(svg, obj) {
18946
19780
  const boxWidth = Number(obj.width ?? 0) || 0;
18947
19781
  let lineIndex = 0;
18948
19782
  return svg.replace(/<tspan\b([^>]*)>/gi, (match, attrs) => {
18949
- var _a;
19783
+ var _a2;
18950
19784
  if (lineIndex >= lines.length || !/\sy\s*=/.test(attrs)) return match;
18951
19785
  let lineWidth = 0;
18952
19786
  let lineLeft = 0;
@@ -18956,7 +19790,7 @@ function stampFabricLineMetricsOnTextSvg(svg, obj) {
18956
19790
  lineWidth = 0;
18957
19791
  }
18958
19792
  try {
18959
- lineLeft = Number(((_a = obj._getLineLeftOffset) == null ? void 0 : _a.call(obj, lineIndex)) ?? 0);
19793
+ lineLeft = Number(((_a2 = obj._getLineLeftOffset) == null ? void 0 : _a2.call(obj, lineIndex)) ?? 0);
18960
19794
  } catch {
18961
19795
  lineLeft = 0;
18962
19796
  }
@@ -19105,18 +19939,18 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
19105
19939
  }
19106
19940
  return svgString;
19107
19941
  }
19108
- const resolvedPackageVersion = "0.5.223";
19942
+ const resolvedPackageVersion = "0.5.225";
19109
19943
  const PACKAGE_VERSION = resolvedPackageVersion;
19110
- const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.223";
19944
+ const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.225";
19111
19945
  const roundParityValue = (value) => {
19112
19946
  if (typeof value !== "number") return value;
19113
19947
  return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
19114
19948
  };
19115
19949
  function isolatePageForCapture(config, pageIndex) {
19116
- var _a;
19950
+ var _a2;
19117
19951
  const capturePageId = `__pixldocs_capture_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}_${pageIndex}`;
19118
19952
  const cloned = JSON.parse(JSON.stringify(config));
19119
- if ((_a = cloned.pages) == null ? void 0 : _a[pageIndex]) {
19953
+ if ((_a2 = cloned.pages) == null ? void 0 : _a2[pageIndex]) {
19120
19954
  cloned.pages[pageIndex].id = capturePageId;
19121
19955
  }
19122
19956
  return { config: cloned, pageId: capturePageId };
@@ -19278,14 +20112,14 @@ async function downscaleConfigRasterImages(config, maxEdgePx, maxDataUrlBytes =
19278
20112
  }
19279
20113
  let __underlineFixInstalled = false;
19280
20114
  function installUnderlineFix(fab) {
19281
- var _a;
20115
+ var _a2;
19282
20116
  if (__underlineFixInstalled) return;
19283
- const TextProto = (_a = fab.Text) == null ? void 0 : _a.prototype;
20117
+ const TextProto = (_a2 = fab.Text) == null ? void 0 : _a2.prototype;
19284
20118
  if (!TextProto || typeof TextProto._renderTextDecoration !== "function") return;
19285
20119
  const original = TextProto._renderTextDecoration;
19286
20120
  const measureLineTextWidth = (obj, ctx, lineIndex) => {
19287
- var _a2, _b, _c, _d, _e, _f;
19288
- const rawLine = (_a2 = obj._textLines) == null ? void 0 : _a2[lineIndex];
20121
+ var _a3, _b, _c, _d, _e, _f;
20122
+ const rawLine = (_a3 = obj._textLines) == null ? void 0 : _a3[lineIndex];
19289
20123
  const lineText = Array.isArray(rawLine) ? rawLine.join("") : String(rawLine ?? "");
19290
20124
  if (!lineText) return 0;
19291
20125
  const fontSize = Number(((_b = obj.getValueOfPropertyAt) == null ? void 0 : _b.call(obj, lineIndex, 0, "fontSize")) ?? obj.fontSize ?? 0);
@@ -19377,9 +20211,9 @@ function installUnderlineFix(fab) {
19377
20211
  }
19378
20212
  let __textboxBoxExtensionsInstalled = false;
19379
20213
  function installTextboxBoxExtensions(fab) {
19380
- var _a;
20214
+ var _a2;
19381
20215
  if (__textboxBoxExtensionsInstalled) return;
19382
- const TextboxProto2 = (_a = fab.Textbox) == null ? void 0 : _a.prototype;
20216
+ const TextboxProto2 = (_a2 = fab.Textbox) == null ? void 0 : _a2.prototype;
19383
20217
  if (!TextboxProto2) return;
19384
20218
  if (TextboxProto2.__pixldocsTextboxExtended) {
19385
20219
  __textboxBoxExtensionsInstalled = true;
@@ -19438,8 +20272,8 @@ function installTextboxBoxExtensions(fab) {
19438
20272
  __textboxBoxExtensionsInstalled = true;
19439
20273
  }
19440
20274
  function configHasAutoShrinkText(config) {
19441
- var _a;
19442
- if (!((_a = config == null ? void 0 : config.pages) == null ? void 0 : _a.length)) return false;
20275
+ var _a2;
20276
+ if (!((_a2 = config == null ? void 0 : config.pages) == null ? void 0 : _a2.length)) return false;
19443
20277
  const walk = (nodes) => {
19444
20278
  for (const node of nodes || []) {
19445
20279
  if (!node) continue;
@@ -19690,8 +20524,8 @@ class PixldocsRenderer {
19690
20524
  * Requires `RendererConfig.deliveryServerUrl` to be set.
19691
20525
  */
19692
20526
  async renderAndDeliver(options) {
19693
- var _a;
19694
- const base = (_a = this.config.deliveryServerUrl) == null ? void 0 : _a.replace(/\/+$/, "");
20527
+ var _a2;
20528
+ const base = (_a2 = this.config.deliveryServerUrl) == null ? void 0 : _a2.replace(/\/+$/, "");
19695
20529
  if (!base) {
19696
20530
  throw new Error("renderAndDeliver: RendererConfig.deliveryServerUrl is required");
19697
20531
  }
@@ -19751,7 +20585,7 @@ class PixldocsRenderer {
19751
20585
  * same fonts, same gradients, same draw order, same selectable text.
19752
20586
  */
19753
20587
  async renderPdfViaClientExport(templateConfig, options = {}) {
19754
- var _a;
20588
+ var _a2;
19755
20589
  await ensureFontsForResolvedConfig(templateConfig);
19756
20590
  const hasAutoShrink = configHasAutoShrinkText(templateConfig);
19757
20591
  await this.awaitFontsForConfig(templateConfig, hasAutoShrink ? 4e3 : 1800);
@@ -19851,7 +20685,7 @@ class PixldocsRenderer {
19851
20685
  await this.waitForCanvasScene(container, cloned, i);
19852
20686
  }
19853
20687
  console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
19854
- const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-Cb5fFgNi.js");
20688
+ const { exportMultiPagePdf, preparePagesForExport } = await import("./vectorPdfExport-D46sZGKA.js");
19855
20689
  const prepared = preparePagesForExport(
19856
20690
  cloned.pages,
19857
20691
  canvasWidth,
@@ -19861,7 +20695,7 @@ class PixldocsRenderer {
19861
20695
  title: options.title,
19862
20696
  watermark: !!options.watermark,
19863
20697
  returnBlob: true,
19864
- pdfTextMode: options.textMode ?? (cloned == null ? void 0 : cloned.pdfTextMode) ?? ((_a = cloned.canvas) == null ? void 0 : _a.n) ?? "auto",
20698
+ pdfTextMode: options.textMode ?? (cloned == null ? void 0 : cloned.pdfTextMode) ?? ((_a2 = cloned.canvas) == null ? void 0 : _a2.n) ?? "auto",
19865
20699
  // Safari/WebKit can still let svg2pdf silently drop valid JPEG data-URL
19866
20700
  // <image> nodes even after the data is compressed and Fabric has loaded
19867
20701
  // it. For auto Safari mode, bypass only the full-page SVG->svg2pdf fast
@@ -20068,9 +20902,9 @@ class PixldocsRenderer {
20068
20902
  }
20069
20903
  waitForCanvasScene(container, config, pageIndex, maxWaitMs = 8e3, pollMs = 50) {
20070
20904
  return new Promise((resolve) => {
20071
- var _a, _b;
20905
+ var _a2, _b;
20072
20906
  const start = Date.now();
20073
- const pageHasContent = (((_b = (_a = config.pages[pageIndex]) == null ? void 0 : _a.children) == null ? void 0 : _b.length) ?? 0) > 0;
20907
+ const pageHasContent = (((_b = (_a2 = config.pages[pageIndex]) == null ? void 0 : _a2.children) == null ? void 0 : _b.length) ?? 0) > 0;
20074
20908
  const settle = () => requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
20075
20909
  const check = () => {
20076
20910
  const fabricCanvas = this.getFabricCanvasFromContainer(container);
@@ -20145,8 +20979,8 @@ class PixldocsRenderer {
20145
20979
  return normalized;
20146
20980
  }
20147
20981
  paintPageBackground(ctx, page, width, height) {
20148
- var _a, _b;
20149
- const backgroundColor = ((_a = page == null ? void 0 : page.settings) == null ? void 0 : _a.backgroundColor) || "#ffffff";
20982
+ var _a2, _b;
20983
+ const backgroundColor = ((_a2 = page == null ? void 0 : page.settings) == null ? void 0 : _a2.backgroundColor) || "#ffffff";
20150
20984
  const gradient = (_b = page == null ? void 0 : page.settings) == null ? void 0 : _b.backgroundGradient;
20151
20985
  ctx.clearRect(0, 0, width, height);
20152
20986
  ctx.fillStyle = backgroundColor;
@@ -20395,7 +21229,7 @@ class PixldocsRenderer {
20395
21229
  };
20396
21230
  const onReady = () => {
20397
21231
  this.waitForCanvasScene(container, renderConfig, pageIndex).then(async () => {
20398
- var _a, _b;
21232
+ var _a2, _b;
20399
21233
  try {
20400
21234
  const expectedImageIds = this.getExpectedImageIds(renderConfig, pageIndex);
20401
21235
  await this.waitForCanvasImages(container, expectedImageIds);
@@ -20413,7 +21247,7 @@ class PixldocsRenderer {
20413
21247
  canvasHeight
20414
21248
  );
20415
21249
  const page = renderConfig.pages[pageIndex];
20416
- const backgroundColor = ((_a = page == null ? void 0 : page.settings) == null ? void 0 : _a.backgroundColor) || "#ffffff";
21250
+ const backgroundColor = ((_a2 = page == null ? void 0 : page.settings) == null ? void 0 : _a2.backgroundColor) || "#ffffff";
20417
21251
  const backgroundGradient = (_b = page == null ? void 0 : page.settings) == null ? void 0 : _b.backgroundGradient;
20418
21252
  cleanup();
20419
21253
  resolve({
@@ -20499,11 +21333,11 @@ class PixldocsRenderer {
20499
21333
  return null;
20500
21334
  }
20501
21335
  logFabricTextParitySnapshot(stage, fabricInstance) {
20502
- var _a;
21336
+ var _a2;
20503
21337
  if (typeof window === "undefined" || window.__pixldocsDebugAutoShrink !== true) return;
20504
21338
  const sample = [];
20505
21339
  const visit = (obj, groupPath = "") => {
20506
- var _a2;
21340
+ var _a3;
20507
21341
  if (!obj) return;
20508
21342
  if (isFabricTextboxLike(obj)) {
20509
21343
  const lineWidths = getCanvasMeasuredTextboxLineWidths(obj);
@@ -20520,7 +21354,7 @@ class PixldocsRenderer {
20520
21354
  fontSize: obj.fontSize,
20521
21355
  fontFamily: obj.fontFamily,
20522
21356
  fontWeight: obj.fontWeight,
20523
- lineCount: ((_a2 = obj.textLines) == null ? void 0 : _a2.length) || 0,
21357
+ lineCount: ((_a3 = obj.textLines) == null ? void 0 : _a3.length) || 0,
20524
21358
  lines: (obj.textLines || []).map((line) => Array.isArray(line) ? line.join("") : String(line ?? "")),
20525
21359
  lineWidths,
20526
21360
  maxLineWidth: lineWidths.length ? Math.max(...lineWidths) : 0
@@ -20531,11 +21365,11 @@ class PixldocsRenderer {
20531
21365
  obj.getObjects().forEach((child) => visit(child, nextPath));
20532
21366
  }
20533
21367
  };
20534
- (_a = fabricInstance == null ? void 0 : fabricInstance.getObjects) == null ? void 0 : _a.call(fabricInstance).forEach((obj) => visit(obj));
21368
+ (_a2 = fabricInstance == null ? void 0 : fabricInstance.getObjects) == null ? void 0 : _a2.call(fabricInstance).forEach((obj) => visit(obj));
20535
21369
  logJsonLine("[canvas-renderer][fabric-text-parity]", { stage, textboxes: sample.length, sample });
20536
21370
  }
20537
21371
  async waitForStableTextMetrics(container, config, options = {}) {
20538
- var _a, _b, _c;
21372
+ var _a2, _b, _c;
20539
21373
  if (typeof document !== "undefined") {
20540
21374
  void ensureFontsForResolvedConfig(config);
20541
21375
  await this.waitForRelevantFonts(config);
@@ -20576,7 +21410,7 @@ class PixldocsRenderer {
20576
21410
  }
20577
21411
  }
20578
21412
  fabricInstance.getObjects().forEach(primeCharBounds);
20579
- (_a = fabricInstance.calcOffset) == null ? void 0 : _a.call(fabricInstance);
21413
+ (_a2 = fabricInstance.calcOffset) == null ? void 0 : _a2.call(fabricInstance);
20580
21414
  (_b = fabricInstance.renderAll) == null ? void 0 : _b.call(fabricInstance);
20581
21415
  await waitForPaint();
20582
21416
  (_c = fabricInstance.renderAll) == null ? void 0 : _c.call(fabricInstance);
@@ -20618,7 +21452,7 @@ function dumpSvgTextDiagnostics(svgStr, pageIndex, tag, stage, maxItems = 30) {
20618
21452
  };
20619
21453
  logParityJson(tag, stage, { kind: "summary", ...summary });
20620
21454
  const sample = texts.slice(0, maxItems).map((t, idx) => {
20621
- var _a, _b;
21455
+ var _a2, _b;
20622
21456
  const tspans = Array.from(t.querySelectorAll("tspan"));
20623
21457
  const tspanInfo = tspans.slice(0, 8).map((s) => ({
20624
21458
  x: s.getAttribute("x"),
@@ -20633,7 +21467,7 @@ function dumpSvgTextDiagnostics(svgStr, pageIndex, tag, stage, maxItems = 30) {
20633
21467
  let containerWidth = null;
20634
21468
  let cursor = t.parentElement;
20635
21469
  while (cursor && !containerWidth) {
20636
- containerWidth = (_a = cursor.getAttribute) == null ? void 0 : _a.call(cursor, "width");
21470
+ containerWidth = (_a2 = cursor.getAttribute) == null ? void 0 : _a2.call(cursor, "width");
20637
21471
  cursor = cursor.parentElement;
20638
21472
  if (cursor && ((_b = cursor.tagName) == null ? void 0 : _b.toLowerCase()) === "svg") break;
20639
21473
  }
@@ -20827,7 +21661,7 @@ function rgbToHex(r, g, b) {
20827
21661
  return "#" + [r, g, b].map((x) => Math.max(0, Math.min(255, Math.round(x))).toString(16).padStart(2, "0")).join("");
20828
21662
  }
20829
21663
  function cssColorToHex(css) {
20830
- var _a;
21664
+ var _a2;
20831
21665
  const s = css.trim();
20832
21666
  if (/^#[0-9a-f]{3}$/i.test(s)) {
20833
21667
  const r = s[1] + s[1], g = s[2] + s[2], b = s[3] + s[3];
@@ -20845,17 +21679,17 @@ function cssColorToHex(css) {
20845
21679
  if (typeof document === "undefined") return null;
20846
21680
  const div = document.createElement("div");
20847
21681
  div.style.color = s;
20848
- const computed = (_a = document.defaultView) == null ? void 0 : _a.getComputedStyle(div).color;
21682
+ const computed = (_a2 = document.defaultView) == null ? void 0 : _a2.getComputedStyle(div).color;
20849
21683
  if (!computed || !computed.startsWith("rgb")) return null;
20850
21684
  const m = computed.match(/\d+/g);
20851
21685
  if (!m || m.length < 3) return null;
20852
21686
  return "#" + [m[0], m[1], m[2]].map((v) => Number(v).toString(16).padStart(2, "0")).join("");
20853
21687
  }
20854
21688
  function isInSvgDefinitionSubtree(el) {
20855
- var _a;
21689
+ var _a2;
20856
21690
  let current = el;
20857
21691
  while (current) {
20858
- if (SVG_DEFINITION_CONTAINER_TAGS.has(((_a = current.tagName) == null ? void 0 : _a.toLowerCase()) ?? "")) return true;
21692
+ if (SVG_DEFINITION_CONTAINER_TAGS.has(((_a2 = current.tagName) == null ? void 0 : _a2.toLowerCase()) ?? "")) return true;
20859
21693
  current = current.parentElement;
20860
21694
  }
20861
21695
  return false;
@@ -21015,27 +21849,27 @@ function normalizeSvgExplicitColors(svg) {
21015
21849
  const clone = svg.cloneNode(true);
21016
21850
  inlineSvgStyleBlockDeclarations(clone);
21017
21851
  const getAttr = (el, attr) => {
21018
- var _a;
21019
- const v = el.getAttribute(attr) ?? ((_a = el.style) == null ? void 0 : _a.getPropertyValue(attr));
21852
+ var _a2;
21853
+ const v = el.getAttribute(attr) ?? ((_a2 = el.style) == null ? void 0 : _a2.getPropertyValue(attr));
21020
21854
  if (!v) return null;
21021
21855
  const s = v.trim().toLowerCase();
21022
21856
  if (!s || s === "none" || s === "transparent" || s === "currentcolor") return null;
21023
21857
  return normalizeGradientPaintRef(v);
21024
21858
  };
21025
21859
  const hasExplicitNonePaint = (el, attr) => {
21026
- var _a, _b;
21027
- const raw = (el.getAttribute(attr) ?? ((_a = el.style) == null ? void 0 : _a.getPropertyValue(attr)) ?? "").trim().toLowerCase();
21860
+ var _a2, _b;
21861
+ const raw = (el.getAttribute(attr) ?? ((_a2 = el.style) == null ? void 0 : _a2.getPropertyValue(attr)) ?? "").trim().toLowerCase();
21028
21862
  if (raw === "none" || raw === "transparent") return true;
21029
21863
  const rawOpacity = (el.getAttribute(`${attr}-opacity`) ?? ((_b = el.style) == null ? void 0 : _b.getPropertyValue(`${attr}-opacity`)) ?? "").trim().toLowerCase();
21030
21864
  return rawOpacity === "0" || rawOpacity === "0%" || rawOpacity === "0.0";
21031
21865
  };
21032
21866
  function walk(el, parentFill, parentStroke, parentColor) {
21033
- var _a;
21867
+ var _a2;
21034
21868
  if (isInSvgDefinitionSubtree(el)) {
21035
21869
  for (let i = 0; i < el.children.length; i++) walk(el.children[i], null, null, null);
21036
21870
  return;
21037
21871
  }
21038
- const tag = ((_a = el.tagName) == null ? void 0 : _a.toLowerCase()) ?? "";
21872
+ const tag = ((_a2 = el.tagName) == null ? void 0 : _a2.toLowerCase()) ?? "";
21039
21873
  const isDrawable = SVG_DRAWABLE_TAGS.has(tag);
21040
21874
  let fill = getAttr(el, "fill");
21041
21875
  let stroke = getAttr(el, "stroke");
@@ -21093,12 +21927,12 @@ function normalizeSvgExplicitColors(svg) {
21093
21927
  function bakeGroupOpacityIntoChildren(svg) {
21094
21928
  const DRAWABLE = /* @__PURE__ */ new Set(["path", "rect", "circle", "ellipse", "polygon", "polyline", "line", "text", "tspan"]);
21095
21929
  function walkAndBake(el, inheritedOpacity) {
21096
- var _a, _b, _c, _d;
21930
+ var _a2, _b, _c, _d;
21097
21931
  if (isInSvgDefinitionSubtree(el)) {
21098
21932
  for (let i = 0; i < el.children.length; i++) walkAndBake(el.children[i], 1);
21099
21933
  return;
21100
21934
  }
21101
- const tag = ((_a = el.tagName) == null ? void 0 : _a.toLowerCase()) ?? "";
21935
+ const tag = ((_a2 = el.tagName) == null ? void 0 : _a2.toLowerCase()) ?? "";
21102
21936
  const opacityAttr = parseSvgOpacity(el.getAttribute("opacity"));
21103
21937
  const styleOpacity = parseSvgOpacity(((_b = el.style) == null ? void 0 : _b.getPropertyValue("opacity")) || null);
21104
21938
  const ownOpacity = opacityAttr ?? styleOpacity ?? 1;
@@ -21181,8 +22015,8 @@ function normalizeSvgGradientStopOffsets(svg) {
21181
22015
  }
21182
22016
  }
21183
22017
  function copyGradientAttrsFromRef(gradient, ref) {
21184
- var _a;
21185
- const tag = (_a = gradient.tagName) == null ? void 0 : _a.toLowerCase();
22018
+ var _a2;
22019
+ const tag = (_a2 = gradient.tagName) == null ? void 0 : _a2.toLowerCase();
21186
22020
  const attrs = tag === "radialgradient" ? GRADIENT_ATTRS_RADIAL : GRADIENT_ATTRS_LINEAR;
21187
22021
  for (const name of attrs) {
21188
22022
  if (!gradient.hasAttribute(name) && ref.hasAttribute(name)) {
@@ -21210,7 +22044,7 @@ function expandSvgGradientHrefs(svg) {
21210
22044
  for (const g of svg.querySelectorAll("linearGradient, radialGradient")) expand(g);
21211
22045
  }
21212
22046
  function expandSvgUseElements(svg) {
21213
- var _a;
22047
+ var _a2;
21214
22048
  const doc = svg.ownerDocument;
21215
22049
  for (const use of Array.from(svg.querySelectorAll("use"))) {
21216
22050
  const ref = (use.getAttribute("href") || use.getAttribute("xlink:href") || "").trim();
@@ -21222,7 +22056,7 @@ function expandSvgUseElements(svg) {
21222
22056
  const w = parseFloat(use.getAttribute("width") || "0") || 0;
21223
22057
  const h = parseFloat(use.getAttribute("height") || "0") || 0;
21224
22058
  const g = doc.createElementNS("http://www.w3.org/2000/svg", "g");
21225
- if (((_a = target.tagName) == null ? void 0 : _a.toLowerCase()) === "symbol") {
22059
+ if (((_a2 = target.tagName) == null ? void 0 : _a2.toLowerCase()) === "symbol") {
21226
22060
  const viewBox = target.getAttribute("viewBox");
21227
22061
  for (let i = 0; i < target.children.length; i++) g.appendChild(target.children[i].cloneNode(true));
21228
22062
  if (viewBox && w && h) {
@@ -21349,7 +22183,7 @@ async function readNestedSvgImageMarkup(href) {
21349
22183
  }
21350
22184
  }
21351
22185
  async function inlineNestedSvgImageDataUris(svgString, domParser = new DOMParser()) {
21352
- var _a;
22186
+ var _a2;
21353
22187
  try {
21354
22188
  const doc = domParser.parseFromString(svgString, "image/svg+xml");
21355
22189
  if (doc.querySelector("parsererror")) return svgString;
@@ -21414,7 +22248,7 @@ async function inlineNestedSvgImageDataUris(svgString, domParser = new DOMParser
21414
22248
  }
21415
22249
  }
21416
22250
  for (const child of Array.from(innerSvg.childNodes)) g.appendChild(doc.importNode(child, true));
21417
- (_a = img.parentNode) == null ? void 0 : _a.replaceChild(g, img);
22251
+ (_a2 = img.parentNode) == null ? void 0 : _a2.replaceChild(g, img);
21418
22252
  changed = true;
21419
22253
  inlined++;
21420
22254
  } catch {
@@ -21434,9 +22268,9 @@ function parseSvgLength(value, fallback) {
21434
22268
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
21435
22269
  }
21436
22270
  function isIdentitySvgMatrix(value) {
21437
- var _a;
22271
+ var _a2;
21438
22272
  if (!value) return true;
21439
- const nums = ((_a = value.match(/-?\d*\.?\d+(?:e[-+]?\d+)?/gi)) == null ? void 0 : _a.map(Number)) ?? [];
22273
+ const nums = ((_a2 = value.match(/-?\d*\.?\d+(?:e[-+]?\d+)?/gi)) == null ? void 0 : _a2.map(Number)) ?? [];
21440
22274
  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;
21441
22275
  }
21442
22276
  function isRedundantImageClipPathForInlineSvg(root, clipPathRef, ix, iy, iw, ih) {
@@ -21522,8 +22356,8 @@ function inlineComputedStyles(svg) {
21522
22356
  document.body.appendChild(wrap);
21523
22357
  try {
21524
22358
  let walk = function(el) {
21525
- var _a;
21526
- const tag = (_a = el.tagName) == null ? void 0 : _a.toLowerCase();
22359
+ var _a2;
22360
+ const tag = (_a2 = el.tagName) == null ? void 0 : _a2.toLowerCase();
21527
22361
  if (drawableTags.includes(tag)) {
21528
22362
  const cs = window.getComputedStyle(el);
21529
22363
  const fill = cs.fill;
@@ -21623,9 +22457,9 @@ function getFirstExplicitColorFromSvg(svg) {
21623
22457
  return getGradientStopColorAsHex(svg, gradientId);
21624
22458
  };
21625
22459
  function walk(el) {
21626
- var _a, _b;
22460
+ var _a2, _b;
21627
22461
  if (fill && stroke) return;
21628
- const f = el.getAttribute("fill") ?? ((_a = el.style) == null ? void 0 : _a.getPropertyValue("fill"));
22462
+ const f = el.getAttribute("fill") ?? ((_a2 = el.style) == null ? void 0 : _a2.getPropertyValue("fill"));
21629
22463
  const s = el.getAttribute("stroke") ?? ((_b = el.style) == null ? void 0 : _b.getPropertyValue("stroke"));
21630
22464
  if (!fill) {
21631
22465
  if (isRealColor(f)) fill = f;
@@ -21654,16 +22488,16 @@ function isNearWhite(hex) {
21654
22488
  return r >= 250 && g >= 250 && b >= 250;
21655
22489
  }
21656
22490
  function getStopColorRaw(stop) {
21657
- var _a, _b;
21658
- 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");
22491
+ var _a2, _b;
22492
+ 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");
21659
22493
  }
21660
22494
  function getGradientStopColorAsHex(svgRoot, gradientId, visited = /* @__PURE__ */ new Set()) {
21661
- var _a;
22495
+ var _a2;
21662
22496
  if (visited.has(gradientId)) return null;
21663
22497
  visited.add(gradientId);
21664
22498
  const gradient = findGradientInTree(svgRoot, gradientId);
21665
22499
  if (!gradient) return null;
21666
- const tag = (_a = gradient.tagName) == null ? void 0 : _a.toLowerCase();
22500
+ const tag = (_a2 = gradient.tagName) == null ? void 0 : _a2.toLowerCase();
21667
22501
  if (tag !== "lineargradient" && tag !== "radialgradient") return null;
21668
22502
  const stops = Array.from(gradient.querySelectorAll("stop"));
21669
22503
  if (stops.length > 0) {
@@ -21719,10 +22553,10 @@ async function convertTextDecorationsToLines(svg) {
21719
22553
  else el.removeAttribute("style");
21720
22554
  };
21721
22555
  const resolveInheritedSvgValue = (el, attr, styleProp = attr) => {
21722
- var _a, _b;
22556
+ var _a2, _b;
21723
22557
  let current = el;
21724
22558
  while (current) {
21725
- const attrValue = (_a = current.getAttribute(attr)) == null ? void 0 : _a.trim();
22559
+ const attrValue = (_a2 = current.getAttribute(attr)) == null ? void 0 : _a2.trim();
21726
22560
  if (attrValue) return attrValue;
21727
22561
  const styleValue = (_b = getInlineStyleValue(current, styleProp)) == null ? void 0 : _b.trim();
21728
22562
  if (styleValue) return styleValue;
@@ -21902,14 +22736,14 @@ async function convertSvgTextDecorationsToLinesString(svgStr) {
21902
22736
  }
21903
22737
  }
21904
22738
  async function rasterizeShadowMarkers(svg) {
21905
- var _a, _b, _c, _d, _e, _f;
22739
+ var _a2, _b, _c, _d, _e, _f;
21906
22740
  if (typeof window === "undefined" || typeof document === "undefined") return;
21907
22741
  const markers = Array.from(svg.querySelectorAll("g.__pdShadowRaster"));
21908
22742
  if (markers.length === 0) return;
21909
22743
  const SVG_NS = "http://www.w3.org/2000/svg";
21910
22744
  const XLINK_NS = "http://www.w3.org/1999/xlink";
21911
22745
  try {
21912
- if ((_a = document.fonts) == null ? void 0 : _a.ready) await document.fonts.ready;
22746
+ if ((_a2 = document.fonts) == null ? void 0 : _a2.ready) await document.fonts.ready;
21913
22747
  } catch {
21914
22748
  }
21915
22749
  const fontFaceCss = await collectInlinedFontFaceCss();
@@ -22171,7 +23005,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
22171
23005
  if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
22172
23006
  sanitizeSvgTreeForPdf(svgToDraw);
22173
23007
  try {
22174
- const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-Cb5fFgNi.js");
23008
+ const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import("./vectorPdfExport-D46sZGKA.js");
22175
23009
  try {
22176
23010
  await logTextMeasurementDiagnostic(svgToDraw);
22177
23011
  } catch {
@@ -22187,8 +23021,8 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
22187
23021
  }
22188
23022
  }
22189
23023
  function drawPageBackground(pdf, pageIndex, pageWidth, pageHeight, backgroundColor, backgroundGradient) {
22190
- var _a, _b;
22191
- if (backgroundGradient && ((_a = backgroundGradient.stops) == null ? void 0 : _a.length) >= 2) {
23024
+ var _a2, _b;
23025
+ if (backgroundGradient && ((_a2 = backgroundGradient.stops) == null ? void 0 : _a2.length) >= 2) {
22192
23026
  const grad = backgroundGradient;
22193
23027
  const colorStops = grad.stops.map((s) => {
22194
23028
  const c = parseColor(s.color);
@@ -22255,7 +23089,7 @@ function drawPageBackground(pdf, pageIndex, pageWidth, pageHeight, backgroundCol
22255
23089
  }
22256
23090
  }
22257
23091
  async function assemblePdfFromSvgs(svgResults, options = {}) {
22258
- var _a, _b;
23092
+ var _a2, _b;
22259
23093
  if (svgResults.length === 0) throw new Error("No pages to export");
22260
23094
  const { title, stripPageBackground } = options;
22261
23095
  const firstPage = svgResults[0];
@@ -22288,7 +23122,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
22288
23122
  const pageOrientation = page.width > page.height ? "landscape" : "portrait";
22289
23123
  pdf.addPage([page.width, page.height], pageOrientation);
22290
23124
  }
22291
- const hasGradient = !!((_b = (_a = page.backgroundGradient) == null ? void 0 : _a.stops) == null ? void 0 : _b.length);
23125
+ const hasGradient = !!((_b = (_a2 = page.backgroundGradient) == null ? void 0 : _a2.stops) == null ? void 0 : _b.length);
22292
23126
  drawPageBackground(pdf, i, page.width, page.height, page.backgroundColor, page.backgroundGradient);
22293
23127
  const shouldStripBg = stripPageBackground ?? hasGradient;
22294
23128
  const textMode = options.textMode ?? (options.outlineText === true ? "pixel-perfect" : "selectable");
@@ -22570,4 +23404,4 @@ export {
22570
23404
  buildTeaserBlurFlatKeys as y,
22571
23405
  collectFontDescriptorsFromConfig as z
22572
23406
  };
22573
- //# sourceMappingURL=index-DXJtHKQO.js.map
23407
+ //# sourceMappingURL=index-BpViFQMO.js.map