@pixldocs/canvas-renderer 0.5.181 → 0.5.183
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.
- package/README.md +11 -2
- package/dist/{index-DQBzPXXr.cjs → index-B1BBI3Bg.cjs} +11 -9
- package/dist/index-B1BBI3Bg.cjs.map +1 -0
- package/dist/{index-Ck5VHk_Q.js → index-IYEhmMeo.js} +54 -52
- package/dist/index-IYEhmMeo.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +37 -37
- package/dist/previewBlur-B2SedQxb.cjs +104 -0
- package/dist/previewBlur-B2SedQxb.cjs.map +1 -0
- package/dist/previewBlur-Dkg1mMKM.js +104 -0
- package/dist/previewBlur-Dkg1mMKM.js.map +1 -0
- package/dist/{vectorPdfExport-DPng52xI.cjs → vectorPdfExport-B73_TC4T.cjs} +4 -4
- package/dist/{vectorPdfExport-DPng52xI.cjs.map → vectorPdfExport-B73_TC4T.cjs.map} +1 -1
- package/dist/{vectorPdfExport-KXmgWTkZ.js → vectorPdfExport-C09pvz-H.js} +4 -4
- package/dist/{vectorPdfExport-KXmgWTkZ.js.map → vectorPdfExport-C09pvz-H.js.map} +1 -1
- package/package.json +1 -1
- package/dist/index-Ck5VHk_Q.js.map +0 -1
- package/dist/index-DQBzPXXr.cjs.map +0 -1
- package/dist/previewBlur-BB8gxlmo.cjs +0 -51
- package/dist/previewBlur-BB8gxlmo.cjs.map +0 -1
- package/dist/previewBlur-Dj6dSSNO.js +0 -51
- package/dist/previewBlur-Dj6dSSNO.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-DQBzPXXr.cjs","sources":["../src/shims/app-api.ts","../../../src/types/editor.ts","../../../src/lib/textMeasurement.ts","../../../src/lib/layoutEngine.ts","../../../src/lib/pageClipboard.ts","../../../src/store/editorStore.ts","../../../src/store/fabricCanvasRegistry.ts","../../../src/lib/googleFonts.ts","../../../src/lib/fabricUtils.ts","../../../src/lib/fontLoader.ts","../../../src/lib/canvasImageLoader.ts","../../../src/lib/svgMaskApply.ts","../../../src/lib/canvaMaskedImage.ts","../../../src/lib/imageCropMode.ts","../../../src/lib/snapGuides.ts","../../../src/lib/fabricTextboxExtensions.ts","../../../src/lib/textBackgroundRenderer.ts","../../../src/lib/shapeGeometry.ts","../../../src/lib/textMarkdown.ts","../../../src/lib/gradientUtils.ts","../../../src/lib/fabricObjectCreators.ts","../../../shared/smart-elements/renderers/qrcode.ts","../../../shared/smart-elements/renderers/rating.ts","../../../shared/smart-elements/renderers/progress.ts","../../../shared/smart-elements/utils.ts","../../../shared/smart-elements/renderers/table.ts","../../../shared/smart-elements/renderers/avatar.ts","../../../shared/smart-elements/renderers/badge.ts","../../../shared/smart-elements/registry.ts","../../../src/lib/imageEdgeFade.ts","../../../src/components/editor/PageCanvas.tsx","../../../src/components/PreviewCanvas.tsx","../src/theme.ts","../../../src/lib/inferFormSchemaFromTemplate.ts","../../../src/lib/formSchema.ts","../../../src/lib/applyFormDataToConfig.ts","../../../src/lib/repeatableEntryIds.ts","../../../src/lib/layoutWithContentBounds.ts","../src/pdf-fonts.ts","../src/font-loader.ts","../src/data-resolver.ts","../src/PixldocsPreview.tsx","../../../src/lib/canvasSvgCapture.ts","../src/renderer.ts","../src/pdf-export.ts","../src/templates-api.ts","../src/warm.ts","../src/index.ts"],"sourcesContent":["export let API_URL = '';\n\nexport function setPackageApiUrl(imageProxyUrl?: string): void {\n if (!imageProxyUrl) {\n API_URL = '';\n return;\n }\n\n API_URL = imageProxyUrl.replace(/\\/image-proxy(?:\\?.*)?$/, '');\n}\n\n/**\n * Fetch options for the Supabase image-proxy edge function. The package\n * harness runs against the same Supabase project as the client, so we can\n * just forward the anon key from the same env hook the renderer uses.\n * Falls back to no-credentials/no-headers if no project is configured.\n */\nexport function getImageProxyFetchOptions(): RequestInit {\n try {\n const anon = (typeof window !== 'undefined' && (window as any).__PIXLDOCS_SUPABASE_ANON_KEY) || '';\n if (anon) {\n return {\n headers: {\n apikey: anon,\n authorization: `Bearer ${anon}`,\n },\n };\n }\n } catch {}\n return {};\n}\n\n// --- Type stubs consumed by transitive imports (formSchema.ts, applyFormDataToConfig.ts) ---\n\n/** Form rendering presets */\nexport type FormRenderPreset = 'default' | 'compact' | 'cards' | 'minimal' | 'biodata';\n\n/** Form definition (schema layer) */\nexport type FormSchema = {\n dynamicFields?: unknown[];\n fieldGroups?: unknown[];\n repeatableSections?: { nodeId: string; label: string; minEntries?: number; maxEntries?: number }[];\n defaultData?: Record<string, unknown> | null;\n formRenderPreset?: FormRenderPreset;\n} | null;\n\n/** Mapping entry between a form field and a template element */\nexport interface FormTemplateMappingEntry {\n field_key: string;\n element_id: string;\n property?: string;\n target_property?: string;\n}\n","// ============================================\n// NESTED CHILDREN SCHEMA v2.2\n// Supports true tree structure with groups containing children\n// Project settings separated from page settings\n// Centralized Dynamic Fields system\n// ============================================\n\nexport type ElementType = 'text' | 'shape' | 'image' | 'line';\nexport type NodeType = ElementType | 'group';\n\nexport type ShapeType = \n | 'rectangle' \n | 'circle' \n | 'rounded-rect' \n | 'triangle' \n | 'diamond' \n | 'pentagon' \n | 'hexagon' \n | 'octagon'\n | 'star' \n | 'heart' \n | 'arrow'\n | 'parallelogram'\n | 'trapezoid'\n | 'cross'\n | 'ring'\n | 'badge';\n\nexport type LineType = 'solid' | 'dashed' | 'dotted';\n\n// ============================================\n// CSS-LIKE LAYOUT (canvas units, not px)\n// Padding, margin, position, display (flex/grid), auto width/height\n// ============================================\n\n/** Spacing in canvas units. Number = all sides; object = per side */\nexport type SpacingValue = number | { top?: number; right?: number; bottom?: number; left?: number };\n\n/** Resolve SpacingValue to { top, right, bottom, left } in canvas units */\nexport function resolveSpacing(v: SpacingValue | undefined): { top: number; right: number; bottom: number; left: number } {\n if (v === undefined) return { top: 0, right: 0, bottom: 0, left: 0 };\n if (typeof v === 'number') return { top: v, right: v, bottom: v, left: v };\n return {\n top: v.top ?? 0,\n right: v.right ?? 0,\n bottom: v.bottom ?? 0,\n left: v.left ?? 0,\n };\n}\n\n/** Container display: block (absolute flow), flex, or grid */\nexport type Display = 'block' | 'flex' | 'grid';\n\n/**\n * Position type (CSS-like). Default is static.\n * @see https://www.w3schools.com/css/css_positioning.asp\n * - static: default; normal flow, not affected by top/left (layout engine computes position)\n * - relative: positioned relative to normal position; top/left adjust\n * - absolute: out of flow; positioned relative to nearest positioned ancestor\n * - fixed: relative to viewport/page\n */\nexport type PositionType = 'static' | 'relative' | 'absolute' | 'fixed';\n\n/** Width/height: CSS-like. auto = content-based, initial = default (fallback), inherit = from parent. */\nexport type SizeValue = number | 'auto' | 'initial' | 'inherit';\n\n/** @deprecated Use SizeValue. Kept for backward compatibility. */\nexport type AutoSize = SizeValue;\n\n/** Flexbox alignment (main axis) */\nexport type JustifyContent = 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly';\n\n/** Flexbox alignment (cross axis) */\nexport type AlignItems = 'flex-start' | 'flex-end' | 'center' | 'stretch' | 'baseline';\n\n/** Grid template: e.g. \"1fr 1fr\", \"100 200 100\", \"auto 1fr\" */\nexport type GridTemplate = string;\n\n/** Check if width/height is content-based (auto) */\nexport function isAutoSize(v: SizeValue | undefined): v is 'auto' {\n return v === 'auto';\n}\n\n/**\n * Resolve width/height to a number.\n * - number: use as-is\n * - 'auto': use contentSize (content-based)\n * - 'initial': use fallback (default)\n * - 'inherit': use parentSize if provided, else fallback\n */\nexport function resolveSize(\n value: SizeValue | undefined,\n contentSize: number,\n fallback: number,\n parentSize?: number\n): number {\n if (value === undefined) return fallback;\n if (typeof value === 'number') return value;\n if (value === 'auto') return contentSize;\n if (value === 'initial') return fallback;\n if (value === 'inherit') return parentSize ?? fallback;\n return fallback;\n}\n\n// Position helper type (used by editorStore)\nexport interface Position {\n x: number;\n y: number;\n}\n\n// Origin types for transform anchor\nexport type OriginX = 'left' | 'center' | 'right';\nexport type OriginY = 'top' | 'center' | 'bottom';\n\n// ============================================\n// GRADIENT SUPPORT\n// ============================================\n\nexport interface GradientStop {\n color: string; // hex color\n offset: number; // 0–1\n}\n\nexport interface GradientConfig {\n type: 'linear' | 'radial' | 'conic';\n /** Angle in degrees (0–360) for linear gradients. 0 = left→right, 90 = top→bottom */\n angle?: number;\n /** Color stops (2–5) */\n stops: GradientStop[];\n /** Center X for radial (0–1, default 0.5) */\n cx?: number;\n /** Center Y for radial (0–1, default 0.5) */\n cy?: number;\n /** Radius for radial (0–1, default 0.5) */\n r?: number;\n}\n\n/** Check if a fill value is a gradient config or a solid color string */\nexport function isGradientConfig(value: any): value is GradientConfig {\n return value && typeof value === 'object' && 'type' in value && 'stops' in value && Array.isArray(value.stops);\n}\n\n/** Create a default linear gradient */\nexport function createDefaultGradient(color1 = '#3b82f6', color2 = '#8b5cf6'): GradientConfig {\n return {\n type: 'linear',\n angle: 90,\n stops: [\n { color: color1, offset: 0 },\n { color: color2, offset: 1 },\n ],\n };\n}\n\n// ============================================\n// BASE CANVAS ELEMENT - Fabric.js native properties\n// ============================================\nexport interface PercentageBarConfig {\n value?: number;\n max?: number;\n showLabel?: boolean;\n label?: string;\n}\n\nexport interface CanvasElement {\n // === METADATA ===\n id: string;\n type: ElementType; // 'text' | 'shape' | 'image' | 'line' (NOT 'group')\n name: string;\n \n \n // Type-specific metadata\n shapeType?: ShapeType;\n lineType?: LineType;\n\n // === FABRIC.JS NATIVE PROPERTIES ===\n left: number;\n top: number;\n width: number;\n height: number;\n scaleX: number;\n scaleY: number;\n angle: number;\n skewX: number;\n skewY: number;\n flipX: boolean;\n flipY: boolean;\n originX: OriginX;\n originY: OriginY;\n \n // === RAW TRANSFORM MATRIX (optional, for precise transforms) ===\n transformMatrix?: [number, number, number, number, number, number];\n opacity: number;\n fill: string;\n fillGradient?: GradientConfig;\n stroke: string;\n strokeGradient?: GradientConfig;\n strokeWidth: number;\n strokeDashArray?: number[];\n visible: boolean;\n selectable: boolean;\n evented: boolean;\n\n // === ANTI-SCREENSHOT (preview-only) ===\n /**\n * When true, this element is redacted in watermarked previews (free preview\n * for paid templates) to discourage screenshot theft. Has no effect on the\n * editor canvas or on clean / paid exports. For text elements, the content\n * is replaced with block characters (█). Off by default.\n */\n previewBlur?: boolean;\n \n // === TEXT-SPECIFIC ===\n text?: string;\n fontSize?: number;\n fontFamily?: string;\n fontWeight?: number | string;\n fontStyle?: 'normal' | 'italic' | 'oblique';\n textAlign?: 'left' | 'center' | 'right' | 'justify';\n lineHeight?: number;\n charSpacing?: number;\n letterSpacing?: number;\n underline?: boolean;\n linethrough?: boolean;\n\n /**\n * Inline markdown formatting toggle. When true, text content may contain\n * markers like **bold**, *italic*, __underline__, ~~strike~~, ==highlight==,\n * [c=primary]X[/c], [bg=secondary]X[/bg]. Off by default.\n */\n formattingEnabled?: boolean;\n \n // === TEXT BACKGROUND (Phase 1 — text element box styling) ===\n /** Background fill color behind text. Use 'transparent' or undefined for none. */\n textBgColor?: string;\n /** @deprecated Legacy uniform padding — use textBgPaddingTop/Right/Bottom/Left. Read as fallback when per-side values are absent. */\n textBgPadding?: number;\n /** Per-side inner padding (canvas units) around text inside its background box. */\n textBgPaddingTop?: number;\n textBgPaddingRight?: number;\n textBgPaddingBottom?: number;\n textBgPaddingLeft?: number;\n /** Per-corner border radius for the text background box. */\n textBgRxTL?: number;\n textBgRxTR?: number;\n textBgRxBR?: number;\n textBgRxBL?: number;\n /** Opacity (0..1) applied to the text background fill only. Defaults to 1. */\n textBgOpacity?: number;\n /**\n * When true, the background fill is drawn per text line — sized to the\n * actual line width (similar to how underline behaves) instead of filling\n * the full text-box width. Defaults to false (full-width box).\n */\n textBgFitToText?: boolean;\n\n // === TEXT SHADOW ===\n textShadowColor?: string;\n textShadowBlur?: number;\n textShadowOffsetX?: number;\n textShadowOffsetY?: number;\n /**\n * When true (default), the text shadow is also painted under the text\n * background rectangle so the whole box casts a shadow. When false, the\n * shadow is restricted to the glyph silhouettes only.\n */\n textShadowAffectsBg?: boolean;\n /**\n * When true (default), the text shadow is painted on the glyph silhouettes.\n * Set to false to keep the shadow only on the background box (requires\n * textShadowAffectsBg=true) or to disable it on text entirely.\n */\n textShadowAffectsText?: boolean;\n\n // === SHAPE-SPECIFIC ===\n rx?: number;\n ry?: number;\n /** Per-corner border radius for rounded-rect */\n rxTL?: number;\n rxTR?: number;\n rxBR?: number;\n rxBL?: number;\n /** Per-corner border radius for triangle (top, bottom-right, bottom-left) */\n triRTop?: number;\n triRBR?: number;\n triRBL?: number;\n \n // === IMAGE-SPECIFIC ===\n src?: string;\n imageUrl?: string;\n clipShape?: 'none' | 'rectangle' | 'rounded' | 'circle';\n imageFit?: 'cover' | 'contain' | 'fill' | 'none';\n maintainResolution?: boolean;\n useCropHandles?: boolean;\n imageNaturalWidth?: number;\n imageNaturalHeight?: number;\n sourceFormat?: 'svg' | 'png';\n /** Map of original SVG color → replacement color for recoloring */\n svgColorMap?: Record<string, string>;\n /** Optional icon-scoped palette used to constrain SVG color editor swatches */\n svgSourceColors?: string[];\n cropPanX?: number;\n cropPanY?: number;\n cropZoom?: number;\n /** Optional SVG mask URL applied as a clipPath to the image (overrides clipShape geometry) */\n maskSvgUrl?: string;\n /** How the SVG mask is interpreted: 'shape' = vector clipPath (binary, PDF-friendly),\n * 'luminance' = soft alpha mask (gradients/feathered edges; falls back to raster in PDF). */\n maskType?: 'shape' | 'luminance';\n \n // === EDGE FADE (per-side feather) ===\n // Amount: 0 = fully transparent at the edge, 1 = no fade. Default 1 (off).\n fadeTopAmount?: number;\n fadeRightAmount?: number;\n fadeBottomAmount?: number;\n fadeLeftAmount?: number;\n // Size: 0..1 fraction of the side dimension that the gradient occupies.\n fadeTopSize?: number;\n fadeRightSize?: number;\n fadeBottomSize?: number;\n fadeLeftSize?: number;\n // Hardness: inverse falloff curve over kept alpha. <1 = softer/longer blend,\n // 1 = linear, >1 = harder/sharper edge. Default 1.\n fadeTopHardness?: number;\n fadeRightHardness?: number;\n fadeBottomHardness?: number;\n fadeLeftHardness?: number;\n\n // === ALTERNATE PROPERTY NAMES (AI responses may use these) ===\n position?: { x: number; y: number };\n size?: { width: number; height: number };\n rotation?: number;\n content?: string;\n locked?: boolean;\n style?: {\n fill?: string;\n stroke?: string;\n strokeWidth?: number;\n opacity?: number;\n fontSize?: number;\n fontFamily?: string;\n fontWeight?: number | string;\n fontStyle?: string;\n textAlign?: string;\n lineHeight?: number;\n letterSpacing?: number;\n borderRadius?: number;\n strokeDasharray?: string;\n imageFrameShape?: string;\n imageFit?: string;\n textDecoration?: string;\n };\n \n // === LAYOUT ORDER (flex/grid) ===\n order?: number;\n\n // === STACK SPACING (used when this node is a child of a stack group) ===\n /** Extra space above the element in a vertical stack (before gap). Acts like CSS marginTop. */\n marginTop?: number;\n /** Extra space to the left of the element in a horizontal stack (before gap). Acts like CSS marginLeft. */\n marginLeft?: number;\n /** Extra space below the element in a vertical stack (after gap). Acts like CSS marginBottom. */\n marginBottom?: number;\n /** Extra space to the right of the element in a horizontal stack (after gap). Acts like CSS marginRight. */\n marginRight?: number;\n\n /** When set, this element is a repeatable section */\n repeatableSection?: { label: string };\n\n /** When true, this element is copied onto new pages */\n staticOnNewPage?: boolean;\n\n // === SPECIAL ELEMENT PROPERTIES ===\n textMode?: 'plain' | 'bullets' | 'link';\n dynamicHeight?: boolean;\n linkConfig?: LinkConfig;\n bulletConfig?: BulletConfig;\n bulletItems?: string[];\n\n // === BACKWARD COMPATIBILITY (old schema) ===\n isDynamic?: boolean;\n fieldName?: string;\n groupId?: string;\n validation?: any;\n repeatable?: any;\n percentageBar?: PercentageBarConfig;\n \n // === SMART ELEMENT ===\n /** When set, this element is a smart element (QR code, rating, progress bar, etc.) */\n smartElementType?: import('@/lib/smartElements').SmartElementType;\n /** Smart element-specific properties (value, colors, etc.) */\n smartProps?: Record<string, any>;\n \n // === TEXT CASE TRANSFORM ===\n textCase?: 'none' | 'uppercase' | 'lowercase' | 'capitalize';\n \n // === TEXT OVERFLOW & LAYOUT BEHAVIOR ===\n overflowPolicy?: 'auto-shrink' | 'grow-and-push' | 'max-lines-ellipsis';\n maxLines?: number;\n minFontSize?: number;\n \n // === FABRIC TEXTBOX SETTINGS ===\n wordWrap?: 'break-word' | 'keep-word' | 'no-wrap';\n splitByGrapheme?: boolean;\n\n // === TEXTBOX VERTICAL SIZING (text only) ===\n /**\n * Minimum visual height (canvas units) of the text box. The bottom/top/corner\n * resize handles bake their scaleY into this value so the box can be\n * resized vertically without stretching the glyphs. Acts as a floor in\n * grow-and-push mode (content pushes beyond it) and is ignored in\n * auto-shrink mode (where height stays fixed via the existing path).\n */\n minBoxHeight?: number;\n /**\n * Vertical alignment of text content inside the box when minBoxHeight is\n * larger than the natural content height. Defaults to 'top'.\n */\n verticalAlign?: 'top' | 'middle' | 'bottom';\n}\n\n// ============================================\n// GROUP NODE - Container with children\n// ============================================\n\n/** Native Fabric-style group: position and visibility only; size comes from Fabric (content). */\nexport interface GroupNode {\n id: string;\n type: 'group';\n name: string;\n children: CanvasNode[];\n collapsed?: boolean;\n locked?: boolean;\n visible?: boolean;\n left?: number;\n top?: number;\n layoutMode?: GroupLayoutMode;\n stackSpacing?: number;\n /** Stack-only: distribution of children along the main axis (vertical = Y, horizontal = X). */\n justifyContent?: 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly';\n /** Stack-only: alignment of children along the cross axis. 'stretch' makes children fill the cross-axis container box. */\n alignItems?: 'start' | 'center' | 'end' | 'stretch';\n /** Inner padding (canvas units) inside a stack group. Insets stacked children from the group's edges. */\n paddingTop?: number;\n paddingRight?: number;\n paddingBottom?: number;\n paddingLeft?: number;\n /** Extra space below this group in a vertical-stack parent / right in horizontal-stack parent. */\n marginTop?: number;\n marginLeft?: number;\n marginBottom?: number;\n marginRight?: number;\n backgroundColor?: string;\n width?: number;\n height?: number;\n repeatableSection?: {\n label: string;\n minEntries?: number;\n maxEntries?: number;\n formDefId?: string;\n formDefSectionPrefix?: string;\n /** Optional filter: which entries (by 1-based index) this group should render.\n * Undefined / 'all' / empty range = render every entry (default). */\n entryFilter?: {\n mode: 'all' | 'range';\n /** Range expression like \"1-2\", \"1,3,5\", \"2-\", \"-3\", \"1-2,5\". 1-based, inclusive. */\n range?: string;\n };\n };\n staticOnNewPage?: boolean;\n /** Resize behavior for grid groups */\n resizeMode?: 'freeform' | 'discreteGrid';\n}\n\nexport type GroupLayoutMode = 'absolute' | 'stack' | 'stacked' | 'vertical-stack' | 'horizontal-stack';\n\n/** True if group uses stack layout (vertical or horizontal); reflow and repeatables apply. */\nexport function isStackLayoutMode(mode?: GroupLayoutMode): boolean {\n const m = mode ?? 'absolute';\n return m === 'stack' || m === 'vertical-stack' || m === 'horizontal-stack';\n}\n/** True if vertical stacking (top-to-bottom). */\nexport function isVerticalStackLayoutMode(mode?: GroupLayoutMode): boolean {\n const m = mode ?? 'absolute';\n return m === 'stack' || m === 'vertical-stack';\n}\n/** True if horizontal stacking (left-to-right). */\nexport function isHorizontalStackLayoutMode(mode?: GroupLayoutMode): boolean {\n return mode === 'horizontal-stack';\n}\n\n// ============================================\n// CANVAS NODE - Union type for tree structure\n// ============================================\nexport type CanvasNode = CanvasElement | GroupNode;\n\n// Type guards\nexport function isGroup(node: CanvasNode): node is GroupNode {\n return node.type === 'group';\n}\n\nexport function isElement(node: CanvasNode): node is CanvasElement {\n return node.type !== 'group';\n}\n\n// ============================================\n// HELPER: Generate stable unique ID\n// Uses crypto.randomUUID for truly unique IDs that never collide\n// ============================================\nexport const generateId = (prefix: string = 'el'): string => {\n // Use crypto.randomUUID if available (modern browsers), fallback to custom implementation\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return `${prefix}-${crypto.randomUUID()}`;\n }\n // Fallback: Generate a UUID-like string\n return `${prefix}-${Date.now().toString(36)}-${Math.random().toString(36).substr(2, 9)}-${Math.random().toString(36).substr(2, 9)}`;\n};\n\n// ============================================\n// HELPER: Create default element with Fabric defaults\n// ============================================\nexport const createDefaultElement = (\n partial: Partial<CanvasElement> & Pick<CanvasElement, 'id' | 'type' | 'name'>\n): CanvasElement => {\n const base: CanvasElement = {\n left: 48,\n top: 48,\n width: 100,\n height: 100,\n scaleX: 1,\n scaleY: 1,\n angle: 0,\n skewX: 0,\n skewY: 0,\n flipX: false,\n flipY: false,\n originX: 'left',\n originY: 'top',\n opacity: 1,\n fill: '#e2e8f0',\n stroke: '#64748b',\n strokeWidth: 1,\n visible: true,\n selectable: true,\n evented: true,\n ...partial,\n };\n \n // Add text-specific defaults (Keep Words = break at spaces, not mid-word)\n if (base.type === 'text') {\n return {\n ...base,\n wordWrap: base.wordWrap ?? 'keep-word',\n splitByGrapheme: base.splitByGrapheme ?? (base.wordWrap === 'break-word'),\n overflowPolicy: base.overflowPolicy ?? 'grow-and-push',\n };\n }\n \n return base;\n};\n\n// ============================================\n// HELPER: Create default group\n// ============================================\n/** Native Fabric-style group: position and visibility; size from content (Fabric). */\nexport const createDefaultGroup = (\n partial: Partial<GroupNode> & Pick<GroupNode, 'id' | 'name'>\n): GroupNode => ({\n type: 'group',\n children: [],\n collapsed: false,\n visible: true,\n locked: false,\n left: 0,\n top: 0,\n ...partial,\n});\n\n/**\n * Collect all group nodes that have at least one child (for group-bounds Rect on canvas).\n */\nexport function getGroupsWithChildren(children: CanvasNode[], depth = 0): GroupNode[] {\n if (depth > 50) return [];\n const result: GroupNode[] = [];\n for (const node of children) {\n if (isGroup(node) && (node as GroupNode).children?.length > 0) {\n result.push(node as GroupNode);\n result.push(...getGroupsWithChildren((node as GroupNode).children, depth + 1));\n }\n }\n return result;\n}\n\n// ============================================\n// CANVAS SETTINGS & STATE\n// ============================================\n\n// Project-level settings (apply to entire document)\nexport interface ProjectSettings {\n showGrid: boolean;\n snapToGrid: boolean;\n gridSize: number;\n snapToGuides: boolean;\n snapThreshold: number;\n /** Template-level brand colors used by inline markdown tokens like [c=primary]. */\n primaryColor?: string;\n secondaryColor?: string;\n}\n\n/** Special elementId for binding a dynamic field to the first page's background color. */\nexport const PAGE_BACKGROUND_ELEMENT_ID = '__pageBackground__';\n\n// Page-level settings (each page can have its own)\nexport interface PageSettings {\n backgroundColor: string;\n backgroundGradient?: GradientConfig;\n contentTop?: number;\n contentBottom?: number;\n // Backward compatibility (old schema stored these per-page)\n showGrid?: boolean;\n gridSize?: number;\n snapToGrid?: boolean;\n snapToGuides?: boolean;\n snapThreshold?: number;\n}\n\nexport interface CanvasPage {\n id: string;\n name: string;\n children: CanvasNode[]; // Tree structure - elements and groups\n settings: PageSettings;\n /**\n * When set, this page is bound to a `repeatablePage` definition in the form schema.\n * At render time the page is cloned once per entry the user provides\n * (or omitted entirely when entries = 0 and minEntries allows it).\n * Mutually exclusive with binding the page's children to a repeatableSection — a\n * `repeatablePage` can ONLY be bound to a page, never to a group.\n */\n boundRepeatablePageId?: string;\n}\n\nexport interface CanvasState {\n width: number;\n height: number;\n pages: CanvasPage[];\n currentPageId: string;\n selectedIds: string[];\n zoom: number;\n pan: { x: number; y: number };\n projectSettings: ProjectSettings;\n \n // Dynamic fields system (centralized)\n dynamicFields: DynamicField[];\n fieldGroups: FieldGroup[];\n /** Form rendering preset for Use Template page (default | compact | cards | minimal). */\n formRenderPreset?: string;\n \n /** Form binding mode: 'dynamic' = manual fields, 'preset' = bound to a Form Definition. undefined = not yet chosen. */\n formBindingMode?: 'dynamic' | 'preset';\n /** When formBindingMode is 'preset', the bound form definition ID. */\n boundFormDefId?: string;\n /** When formBindingMode is 'preset', the bound form definition name (for display). */\n boundFormDefName?: string;\n \n // Theme system\n themeConfig?: ThemeConfig;\n\n /**\n * Default PDF text rendering mode for this template (mirrors TemplateConfig.pdfTextMode).\n * Persisted into the saved config so the editor and Use Template page stay in sync.\n */\n pdfTextMode?: 'auto' | 'selectable' | 'pixel-perfect';\n}\n\n// ============================================\n// THEME SYSTEM\n// ============================================\n\n/**\n * A property bound to the theme system.\n * When a theme variant is selected, this property's value changes.\n */\nexport interface ThemeProperty {\n id: string; // unique ID\n label: string; // e.g., \"Page Background\", \"Heading Color\"\n elementId: string; // element ID or PAGE_BACKGROUND_ELEMENT_ID\n targetProperty: FieldTargetProperty; // e.g., 'backgroundColor', 'fill', 'stroke'\n svgColorKey?: string; // for SVG color map bindings (original color key)\n /**\n * If set, this property reuses values from another ThemeProperty (the master).\n * Variant values lookups are read from `linkedTo` instead of `id`, so one\n * \"theme variable\" (the master) can drive multiple element bindings.\n */\n linkedTo?: string;\n}\n\n/**\n * A named theme variant with specific values for all theme properties.\n */\nexport interface ThemeVariant {\n id: string;\n name: string; // e.g., \"Maroon\", \"Ocean Blue\"\n swatchColor: string; // color swatch shown in selector\n values: Record<string, string>; // themePropertyId -> value (color hex, font name, etc.)\n isDefault?: boolean; // the default variant auto-syncs with builder values\n}\n\n/**\n * Theme configuration for a template.\n */\nexport interface ThemeConfig {\n properties: ThemeProperty[];\n variants: ThemeVariant[];\n}\n\n/**\n * Resolve the variant-values lookup id for a theme property.\n * Linked properties read from their master's id so a single value\n * drives multiple bindings.\n */\nexport function resolveThemeValueId(\n prop: Pick<ThemeProperty, 'id' | 'linkedTo'>,\n properties?: ThemeProperty[]\n): string {\n if (!prop.linkedTo) return prop.id;\n if (properties && !properties.some(p => p.id === prop.linkedTo)) return prop.id;\n return prop.linkedTo;\n}\n\n/** Create an empty theme config */\nexport const createEmptyThemeConfig = (): ThemeConfig => ({\n properties: [],\n variants: [{\n id: 'default',\n name: 'Default',\n swatchColor: '#ffffff',\n values: {},\n isDefault: true,\n }],\n});\n\nexport interface AlignmentGuide {\n type: 'vertical' | 'horizontal';\n position: number;\n start: number;\n end: number;\n}\n\nexport type Tool = 'select' | 'text' | 'rectangle' | 'circle' | 'line' | 'image' | 'hand';\n\n// ============================================\n// DYNAMIC FIELDS SYSTEM v2.2\n// Centralized form field configuration\n// ============================================\n\n/**\n * All supported form field types\n */\nexport type DynamicFieldType = \n | 'text' // Single line text input\n | 'textarea' // Multi-line text with optional rich formatting\n | 'number' // Numeric input (integer, decimal, currency, percentage)\n | 'date' // Date picker\n | 'email' // Email with validation\n | 'phone' // Phone number with formatting\n | 'url' // URL/link input\n | 'image' // Image upload with preview\n | 'color' // Color picker\n | 'select' // Single selection dropdown\n | 'multiselect' // Multiple selection (tags)\n | 'rating' // Star/numeric rating\n | 'toggle' // Boolean toggle/switch\n | 'currency'; // Currency input with symbol\n\n/**\n * Number format variants\n */\nexport type NumberFormat = 'integer' | 'decimal' | 'percentage';\n\n/**\n * Target properties that can be updated on elements\n */\nexport type FieldTargetProperty =\n | 'text' // Text content\n | 'content' // Text content (alternate)\n | 'fill' // Fill color\n | 'stroke' // Stroke/border color\n | 'backgroundColor' // Page background color (special: applies to page settings)\n | 'backgroundGradient' // Page background gradient (JSON-serialized GradientConfig)\n | 'src' // Image source\n | 'fontSize' // Font size (number fields)\n | 'fontFamily' // Font family (select fields)\n | 'fontWeight' // Font weight\n | 'opacity' // Opacity (number 0-1)\n | 'visible' // Visibility toggle\n | 'width' // Element width\n | 'height' // Element height\n | 'borderRadius' // Shape/image corner radius\n | 'link' // URL link (applies to any element)\n | `smartProp:${string}`; // Smart element property (e.g. smartProp:value)\n\n/**\n * Option for select/multiselect fields\n */\nexport interface SelectOption {\n value: string;\n label: string;\n icon?: string; // Optional emoji or icon name\n color?: string; // Optional color for visual distinction\n}\n\n/**\n * Validation rules for form fields\n */\nexport interface DynamicFieldValidation {\n required?: boolean;\n minLength?: number;\n maxLength?: number;\n min?: number; // For numbers\n max?: number; // For numbers\n pattern?: string; // Regex pattern\n patternMessage?: string; // Custom error for pattern\n customMessage?: string; // Override default required message\n \n // URL-specific\n validateUrl?: boolean; // Enable URL format validation\n allowedProtocols?: string[]; // e.g., ['https', 'http'] - defaults to ['https', 'http']\n requireHttps?: boolean; // Only allow https URLs\n \n // Image-specific\n maxFileSize?: number; // In bytes\n acceptedFormats?: string[]; // e.g., ['image/png', 'image/jpeg']\n minWidth?: number; // Min image width\n minHeight?: number; // Min image height\n aspectRatio?: number; // Required aspect ratio (width/height)\n \n // Select-specific\n minSelections?: number; // For multiselect\n maxSelections?: number; // For multiselect\n}\n\n/**\n * Mapping from a dynamic field to an element property\n */\nexport interface FieldMapping {\n elementId: string;\n targetProperty: FieldTargetProperty;\n \n // Optional transformations\n transform?: 'uppercase' | 'lowercase' | 'capitalize' | 'none';\n prefix?: string; // Text to prepend\n suffix?: string; // Text to append\n formatPattern?: string; // For dates, numbers (e.g., \"MMM DD, YYYY\")\n}\n\n/**\n * Dynamic field configuration\n */\nexport interface DynamicField {\n id: string; // Unique identifier (e.g., \"full_name\", \"primary_color\")\n label: string; // Display label in form\n type: DynamicFieldType;\n description?: string; // Help text shown under field\n placeholder?: string; // Placeholder text\n defaultValue?: string | number | boolean | string[];\n \n // Element mappings (one field can update multiple elements)\n mappings: FieldMapping[];\n \n // Validation rules\n validation?: DynamicFieldValidation;\n \n // Organization\n group?: string; // Group ID for form sections\n order?: number; // Display order within group\n \n // Type-specific options\n // Number fields\n numberFormat?: NumberFormat;\n currencySymbol?: string; // e.g., \"$\", \"€\", \"£\"\n currencyCode?: string; // e.g., \"USD\", \"EUR\"\n decimalPlaces?: number;\n step?: number; // Increment step for number input\n \n // Select fields\n options?: SelectOption[];\n allowCustomOption?: boolean; // Allow user to add custom option\n \n // Rating fields\n maxRating?: number; // Max stars (default 5)\n allowHalf?: boolean; // Allow half ratings\n \n // Date fields\n dateFormat?: string; // Display format\n minDate?: string; // ISO date string\n maxDate?: string; // ISO date string\n \n // Image fields\n cropAspectRatio?: number; // Enable cropping with aspect ratio\n showPreview?: boolean; // Show image preview\n \n // Textarea fields\n rows?: number; // Initial rows\n maxRows?: number; // Max auto-expand rows\n enableMarkdown?: boolean; // Enable markdown preview\n /**\n * When true, render text/textarea inputs with the inline-formatting\n * editor (toolbar for bold/italic/underline/strike/highlight/color/bg).\n * Set automatically when binding to a text element with\n * `formattingEnabled === true`.\n */\n formattingEnabled?: boolean;\n \n // UI hints\n width?: 'full' | 'half' | 'third'; // Form layout width\n hidden?: boolean; // Hide from form (for computed fields)\n readonly?: boolean; // Show but don't allow editing\n icon?: string; // Icon to show with field\n}\n\n/**\n * Field group for organizing form sections\n */\nexport interface FieldGroup {\n id: string;\n label: string;\n description?: string;\n icon?: string; // Icon for group header\n order: number;\n collapsible?: boolean;\n defaultCollapsed?: boolean;\n}\n\n/**\n * Helper to create a dynamic field with defaults\n */\nexport const createDynamicField = (\n partial: Partial<DynamicField> & Pick<DynamicField, 'id' | 'label' | 'type'>\n): DynamicField => ({\n mappings: [],\n order: 0,\n ...partial,\n});\n\n/**\n * Property-to-FieldType compatibility mapping\n * Defines which field types can bind to which element properties\n */\nexport const PROPERTY_FIELD_COMPATIBILITY: Partial<Record<FieldTargetProperty, DynamicFieldType[]>> & Record<string, DynamicFieldType[]> = {\n text: ['text', 'textarea', 'email', 'phone', 'url', 'date', 'number', 'currency', 'select'],\n content: ['text', 'textarea', 'email', 'phone', 'url', 'date', 'number', 'currency', 'select'],\n src: ['image', 'url'],\n fill: ['color'],\n stroke: ['color'],\n backgroundColor: ['color'],\n backgroundGradient: ['color'],\n fontSize: ['number'],\n fontFamily: ['select'],\n fontWeight: ['number', 'select'],\n opacity: ['number'],\n visible: ['toggle'],\n width: ['number'],\n height: ['number'],\n borderRadius: ['number'],\n link: ['url', 'text'], // URL field type or text for dynamic links\n};\n\n/**\n * Element type to relevant properties mapping\n * Defines which properties are shown for each element type\n */\nexport const ELEMENT_TYPE_PROPERTIES: Record<NodeType, FieldTargetProperty[]> = {\n text: ['text', 'fill', 'fontSize', 'fontFamily', 'fontWeight', 'opacity', 'visible', 'link'],\n image: ['src', 'opacity', 'borderRadius', 'visible', 'link'],\n shape: ['fill', 'stroke', 'opacity', 'borderRadius', 'visible', 'link'],\n line: ['stroke', 'opacity', 'visible', 'link'],\n group: ['visible', 'link'],\n};\n\n/**\n * Get compatible field types for a given target property.\n * For smartProp:* properties, infers compatibility from the smart element definition.\n */\nexport const getCompatibleFieldTypes = (targetProperty: FieldTargetProperty): DynamicFieldType[] => {\n if (PROPERTY_FIELD_COMPATIBILITY[targetProperty]) {\n return PROPERTY_FIELD_COMPATIBILITY[targetProperty];\n }\n // Smart prop: infer from suffix pattern\n if (targetProperty.startsWith('smartProp:')) {\n const key = targetProperty.slice('smartProp:'.length).toLowerCase();\n if (key.includes('color') || key === 'fg' || key === 'bg') return ['color'];\n if (key.includes('url') || key.includes('link')) return ['url', 'text'];\n if (key.includes('rating') || key.includes('progress') || key.includes('percent')) return ['number'];\n return ['text', 'textarea', 'url', 'number'];\n }\n return ['text'];\n};\n\n/**\n * Check if a field type is compatible with a target property\n */\nexport const isFieldCompatible = (fieldType: DynamicFieldType, targetProperty: FieldTargetProperty): boolean => {\n const compatible = getCompatibleFieldTypes(targetProperty);\n return compatible.includes(fieldType);\n};\n\n/**\n * Get relevant properties for an element type\n */\nexport const getElementProperties = (elementType: NodeType): FieldTargetProperty[] => {\n return ELEMENT_TYPE_PROPERTIES[elementType] || ['visible'];\n};\n\n/**\n * Helper to create a field group\n */\nexport const createFieldGroup = (\n partial: Partial<FieldGroup> & Pick<FieldGroup, 'id' | 'label'>\n): FieldGroup => ({\n order: 0,\n ...partial,\n});\n\n/**\n * Field type metadata for UI\n */\nexport const FIELD_TYPE_META: Record<DynamicFieldType, {\n label: string;\n icon: string;\n description: string;\n defaultTargetProperty: FieldTargetProperty;\n}> = {\n text: { label: 'Text', icon: 'type', description: 'Single line text', defaultTargetProperty: 'text' },\n textarea: { label: 'Long Text', icon: 'align-left', description: 'Multi-line text', defaultTargetProperty: 'text' },\n number: { label: 'Number', icon: 'hash', description: 'Numeric value', defaultTargetProperty: 'text' },\n date: { label: 'Date', icon: 'calendar', description: 'Date picker', defaultTargetProperty: 'text' },\n email: { label: 'Email', icon: 'mail', description: 'Email address', defaultTargetProperty: 'text' },\n phone: { label: 'Phone', icon: 'phone', description: 'Phone number', defaultTargetProperty: 'text' },\n url: { label: 'URL', icon: 'link', description: 'Web link', defaultTargetProperty: 'text' },\n image: { label: 'Image', icon: 'image', description: 'Image upload', defaultTargetProperty: 'src' },\n color: { label: 'Color', icon: 'palette', description: 'Color picker', defaultTargetProperty: 'fill' },\n select: { label: 'Select', icon: 'chevron-down', description: 'Single choice', defaultTargetProperty: 'text' },\n multiselect: { label: 'Multi-Select', icon: 'check-square', description: 'Multiple choices', defaultTargetProperty: 'text' },\n rating: { label: 'Rating', icon: 'star', description: 'Star rating', defaultTargetProperty: 'text' },\n toggle: { label: 'Toggle', icon: 'toggle-left', description: 'On/Off switch', defaultTargetProperty: 'visible' },\n currency: { label: 'Currency', icon: 'dollar-sign', description: 'Money amount', defaultTargetProperty: 'text' },\n};\n\n// ============================================\n// TEMPLATE CONFIG (for saving/loading) - v2.2\n// ============================================\nexport interface TemplateConfigPage {\n id: string;\n name: string;\n children: CanvasNode[]; // Nested tree structure\n settings: PageSettings;\n /**\n * When set, this page is bound to a `repeatablePage` definition in the form schema.\n * At render time the page is cloned once per entry the user provides\n * (or omitted entirely when entries = 0 and minEntries allows it).\n * Mutually exclusive with binding the page's children to a repeatableSection — a\n * `repeatablePage` can ONLY be bound to a page, never to a group.\n */\n boundRepeatablePageId?: string;\n}\n\nexport interface TemplateConfig {\n version: string; // \"2.2\" for dynamic fields system\n name: string;\n description?: string;\n canvas: {\n width: number;\n height: number;\n };\n projectSettings: ProjectSettings;\n pages: TemplateConfigPage[];\n \n // NEW: Centralized dynamic fields configuration\n dynamicFields: DynamicField[];\n fieldGroups?: FieldGroup[];\n \n // Theme system\n themeConfig?: ThemeConfig;\n \n /** Form binding mode: 'dynamic' = manual fields, 'preset' = bound to a Form Definition. */\n formBindingMode?: 'dynamic' | 'preset';\n /** When formBindingMode is 'preset', the bound form definition ID. */\n boundFormDefId?: string;\n /** When formBindingMode is 'preset', the bound form definition name (for display). */\n boundFormDefName?: string;\n \n // UI state preferences\n showSections?: boolean; // Show section highlights on canvas\n showDynamicLabels?: boolean; // Show dynamic field labels\n \n /** When true, group children left/top are stored relative to parent (v2.2+). Omit/false = legacy absolute. */\n relativeGroupPositions?: boolean;\n\n /** When true, template has only structure/properties (display, position, auto, inherit); layout engine computes dimensions/positions on demand (no script layout, no reflow on load). */\n layoutEngineDriven?: boolean;\n\n /** Auto pagination: when content overflows the page, flow to a new page (future). For now, use \"Add page\" for multi-page docs. */\n autoPagination?: boolean;\n\n /**\n * How text should be rendered in exported PDFs.\n * - 'selectable' (default): force real, selectable text everywhere. Best for resumes/biodata/invoices/certificates.\n * May drift slightly on rare/decorative fonts.\n * - 'auto': selectable text where we can guarantee fidelity (Latin / standard Google Fonts);\n * outlined paths for complex scripts (Devanagari, etc.) — best of both worlds.\n * - 'pixel-perfect': outline ALL text into vector paths. Pixel-perfect parity but text is not selectable\n * or searchable. Best for marketing/poster templates.\n */\n pdfTextMode?: 'auto' | 'selectable' | 'pixel-perfect';\n\n /**\n * When autoPagination is true: which root-level group is the flow region (allowed to overflow),\n * and which root-level node ids to repeat on continuation pages (e.g. header, footer).\n * Flow region = the one group whose content can be split across pages; all other content is fixed on page 1.\n */\n paginationConfig?: {\n /** Root-level group id that is allowed to grow and overflow; its content is split across pages. */\n flowRegionId?: string;\n /** Root-level node ids to clone on every continuation page (e.g. header, footer). */\n repeatOnContinuationIds?: string[];\n };\n\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface DocumentTemplate {\n id: string;\n name: string;\n category: 'resume' | 'certificate' | 'id-card' | 'biodata' | 'other';\n canvas: CanvasState;\n createdAt: Date;\n updatedAt: Date;\n}\n\n// Available fonts for professional documents\nexport const AVAILABLE_FONTS = [\n // Serif - Professional & Traditional\n { name: 'Playfair Display', category: 'Serif', style: 'Elegant headlines' },\n { name: 'Merriweather', category: 'Serif', style: 'Readable body text' },\n { name: 'Lora', category: 'Serif', style: 'Classic look' },\n \n // Sans-Serif - Modern & Clean\n { name: 'Montserrat', category: 'Sans-Serif', style: 'Modern headers' },\n { name: 'Open Sans', category: 'Sans-Serif', style: 'Clean body text' },\n { name: 'Roboto', category: 'Sans-Serif', style: 'Versatile' },\n { name: 'Lato', category: 'Sans-Serif', style: 'Friendly' },\n { name: 'Raleway', category: 'Sans-Serif', style: 'Elegant thin' },\n { name: 'Poppins', category: 'Sans-Serif', style: 'Geometric' },\n { name: 'Inter', category: 'Sans-Serif', style: 'UI friendly' },\n { name: 'Nunito', category: 'Sans-Serif', style: 'Rounded' },\n { name: 'Source Sans Pro', category: 'Sans-Serif', style: 'Professional' },\n { name: 'Work Sans', category: 'Sans-Serif', style: 'Modern' },\n \n // Display - Creative\n { name: 'Oswald', category: 'Display', style: 'Bold impact' },\n { name: 'Bebas Neue', category: 'Display', style: 'All caps' },\n { name: 'Abril Fatface', category: 'Display', style: 'Poster style' },\n \n // Handwriting - Personal touch\n { name: 'Dancing Script', category: 'Handwriting', style: 'Signatures' },\n { name: 'Pacifico', category: 'Handwriting', style: 'Casual' },\n { name: 'Great Vibes', category: 'Handwriting', style: 'Elegant cursive' },\n] as const;\n\nexport type FontName = typeof AVAILABLE_FONTS[number]['name'];\n\n// Config interfaces for special element features\n\nexport interface LinkConfig {\n url?: string;\n openInNewTab?: boolean;\n}\n\nexport interface BulletConfig {\n style: 'disc' | 'circle' | 'square' | 'number' | 'dash';\n bulletColor?: string;\n itemSpacing?: number;\n}\n\nexport interface SmartFormData {\n [fieldName: string]: string | number | string[] | SmartFormData[];\n}\n\nexport interface ValidationError {\n fieldName: string;\n message: string;\n}\n\n// ============================================\n// TREE UTILITY FUNCTIONS\n// ============================================\n\n/**\n * Flatten children tree to get all elements (for Fabric.js rendering)\n * Returns elements in z-order (first = bottom, last = top)\n * Includes depth guard to prevent infinite recursion from circular references\n */\nexport function flattenChildren(children: CanvasNode[], visited?: Set<string>, depth = 0): CanvasElement[] {\n // Safety guard: prevent infinite recursion\n const MAX_DEPTH = 50;\n if (depth > MAX_DEPTH) {\n console.warn('flattenChildren: Maximum depth exceeded, possible circular reference');\n return [];\n }\n \n const seen = visited || new Set<string>();\n const result: CanvasElement[] = [];\n \n for (const node of children) {\n // Skip if we've already processed this node (circular reference guard)\n if (seen.has(node.id)) {\n console.warn(`flattenChildren: Circular reference detected for node ${node.id}`);\n continue;\n }\n seen.add(node.id);\n \n if (isGroup(node)) {\n result.push(...flattenChildren(node.children, seen, depth + 1));\n } else {\n result.push(node as CanvasElement);\n }\n }\n \n return result;\n}\n\n/**\n * Find a node by ID in the tree\n * Includes depth guard to prevent infinite recursion\n */\nexport function findNodeById(children: CanvasNode[], id: string, depth = 0): CanvasNode | null {\n if (depth > 50) return null; // Safety guard\n \n for (const node of children) {\n if (node.id === id) return node;\n if (isGroup(node)) {\n const found = findNodeById(node.children, id, depth + 1);\n if (found) return found;\n }\n }\n return null;\n}\n\n/**\n * Collect all groups that have no children (empty groups). Used so the canvas can render a draggable placeholder for them.\n */\nexport function getEmptyGroups(children: CanvasNode[], depth = 0): GroupNode[] {\n if (depth > 50) return [];\n const result: GroupNode[] = [];\n for (const node of children) {\n if (isGroup(node)) {\n if (node.children.length === 0) result.push(node);\n result.push(...getEmptyGroups(node.children, depth + 1));\n }\n }\n return result;\n}\n\n/**\n * Find parent group of a node\n * Includes depth guard to prevent infinite recursion\n */\nexport function findParentGroup(children: CanvasNode[], targetId: string, depth = 0): GroupNode | null {\n if (depth > 50) return null; // Safety guard\n \n for (const node of children) {\n if (isGroup(node)) {\n // Check if target is direct child\n if (node.children.some(child => child.id === targetId)) {\n return node;\n }\n // Recurse into group\n const found = findParentGroup(node.children, targetId, depth + 1);\n if (found) return found;\n }\n }\n return null;\n}\n\n/**\n * Update a node in the tree (immutably)\n */\nexport function updateNodeInTree(\n children: CanvasNode[],\n id: string,\n updates: Partial<CanvasNode>\n): CanvasNode[] {\n return children.map(node => {\n if (node.id === id) {\n return { ...node, ...updates } as CanvasNode;\n }\n if (isGroup(node)) {\n return {\n ...node,\n children: updateNodeInTree(node.children, id, updates),\n };\n }\n return node;\n });\n}\n\n/**\n * Remove a node from the tree (immutably)\n */\nexport function removeNodeFromTree(children: CanvasNode[], id: string): CanvasNode[] {\n return children\n .filter(node => node.id !== id)\n .map(node => {\n if (isGroup(node)) {\n return {\n ...node,\n children: removeNodeFromTree(node.children, id),\n };\n }\n return node;\n });\n}\n\n/**\n * Add a node to a specific parent (or root if parentId is null)\n */\nexport function addNodeToTree(\n children: CanvasNode[],\n node: CanvasNode,\n parentId: string | null,\n index?: number\n): CanvasNode[] {\n if (!parentId) {\n // Add to root\n if (index !== undefined) {\n const result = [...children];\n result.splice(index, 0, node);\n return result;\n }\n return [...children, node];\n }\n \n return children.map(child => {\n if (child.id === parentId && isGroup(child)) {\n const newChildren = [...child.children];\n if (index !== undefined) {\n newChildren.splice(index, 0, node);\n } else {\n newChildren.push(node);\n }\n return { ...child, children: newChildren };\n }\n if (isGroup(child)) {\n return {\n ...child,\n children: addNodeToTree(child.children, node, parentId, index),\n };\n }\n return child;\n });\n}\n\n/**\n * Move a node to a new position in the tree\n */\nexport function moveNodeInTree(\n children: CanvasNode[],\n nodeId: string,\n newParentId: string | null,\n newIndex: number\n): CanvasNode[] {\n // First, find and remove the node\n const node = findNodeById(children, nodeId);\n if (!node) return children;\n \n const withoutNode = removeNodeFromTree(children, nodeId);\n \n // Then add it to the new position\n return addNodeToTree(withoutNode, node, newParentId, newIndex);\n}\n\n/**\n * Get all node IDs in a subtree (for selection expansion)\n */\nexport function getAllNodeIds(nodes: CanvasNode[]): string[] {\n const ids: string[] = [];\n for (const node of nodes) {\n ids.push(node.id);\n if (isGroup(node)) {\n ids.push(...getAllNodeIds(node.children));\n }\n }\n return ids;\n}\n\n/**\n * Get all element IDs in a subtree (excluding group IDs)\n */\nexport function getAllElementIds(nodes: CanvasNode[]): string[] {\n const ids: string[] = [];\n for (const node of nodes) {\n if (isGroup(node)) {\n ids.push(...getAllElementIds(node.children));\n } else {\n ids.push(node.id);\n }\n }\n return ids;\n}\n\n/**\n * Find the smallest (deepest) group that contains all of the given node IDs.\n * Used when moving a selection: move the common ancestor group instead of each element.\n */\nexport function findCommonAncestorGroup(selectedIds: string[], pageChildren: CanvasNode[]): GroupNode | null {\n if (selectedIds.length === 0) return null;\n const firstId = selectedIds[0];\n let candidate = findParentGroup(pageChildren, firstId);\n while (candidate) {\n const descendantIds = new Set([candidate.id, ...getAllNodeIds(candidate.children ?? [])]);\n if (selectedIds.every((id) => descendantIds.has(id))) return candidate;\n candidate = findParentGroup(pageChildren, candidate.id);\n }\n return null;\n}\n","/**\n * Text Measurement Service\n * \n * Uses Fabric.js Textbox to accurately measure text dimensions.\n * This provides pixel-accurate measurements instead of estimations.\n */\n\nimport * as fabric from 'fabric';\nimport { CanvasElement } from '@/types/editor';\n\n// Cache for measured heights to avoid redundant calculations\nconst heightCache = new Map<string, { height: number; timestamp: number }>();\nconst CACHE_TTL = 5000; // 5 seconds cache\n\n/** Width bucket (px) so small resize changes hit cache during drag (e.g. 8px). */\nconst WIDTH_BUCKET_PX = 8;\nfunction bucketWidth(w: number): number {\n return Math.round(w / WIDTH_BUCKET_PX) * WIDTH_BUCKET_PX;\n}\n\nlet measureCanvas: HTMLCanvasElement | null = null;\n\nfunction getMeasureContext(): CanvasRenderingContext2D | null {\n if (typeof document === 'undefined') return null;\n measureCanvas ??= document.createElement('canvas');\n return measureCanvas.getContext('2d');\n}\n\nfunction lineToString(line: unknown): string {\n return Array.isArray(line) ? line.join('') : String(line ?? '');\n}\n\nfunction measureTextLineWithCanvas(textbox: fabric.Textbox, lineText: string, lineIndex: number): number | null {\n if (!lineText) return 0;\n const ctx = getMeasureContext();\n if (!ctx) return null;\n\n const tb = textbox as any;\n const fontSize = Number(tb.getValueOfPropertyAt?.(lineIndex, 0, 'fontSize') ?? textbox.fontSize ?? 16);\n const fontStyle = String(tb.getValueOfPropertyAt?.(lineIndex, 0, 'fontStyle') ?? textbox.fontStyle ?? 'normal');\n const fontWeight = String(tb.getValueOfPropertyAt?.(lineIndex, 0, 'fontWeight') ?? textbox.fontWeight ?? '400');\n const fontFamily = String(tb.getValueOfPropertyAt?.(lineIndex, 0, 'fontFamily') ?? textbox.fontFamily ?? 'Open Sans');\n const charSpacing = Number(tb.getValueOfPropertyAt?.(lineIndex, 0, 'charSpacing') ?? textbox.charSpacing ?? 0);\n\n ctx.save();\n ctx.font = `${fontStyle} normal ${fontWeight} ${fontSize}px ${fontFamily}`;\n const measured = ctx.measureText(lineText).width;\n ctx.restore();\n\n const graphemeCount = Array.from(lineText).length;\n const spacingWidth = graphemeCount > 1 ? ((charSpacing / 1000) * fontSize) * (graphemeCount - 1) : 0;\n return Math.max(0, measured + spacingWidth);\n}\n\n/**\n * Canvas-measured textbox line widths, independent from Fabric's cached\n * `__lineWidths`. This mirrors the underline fidelity fix: when Fabric's\n * wrap/cache state was created with stale font metrics, direct canvas metrics\n * are the reliable source for final glyph width.\n */\nexport function getCanvasMeasuredTextboxLineWidths(textbox: fabric.Textbox): number[] {\n const rawLines = ((textbox as any)._textLines ?? textbox.textLines ?? []) as unknown[];\n const fallback = ((textbox as any).__lineWidths ?? []) as number[];\n if (!rawLines.length) return fallback;\n\n const measured = rawLines.map((line, index) => measureTextLineWithCanvas(textbox, lineToString(line), index));\n if (measured.some((w) => w == null || Number.isNaN(w))) return fallback;\n return measured as number[];\n}\n\nexport function getTextboxWidthFitMetrics(textbox: fabric.Textbox, targetWidth: number): {\n actualTextboxWidth: number;\n dynamicMinWidth: number;\n maxLineWidth: number;\n widthDidGrow: boolean;\n fitsWidth: boolean;\n} {\n const actualTextboxWidth = Number(textbox.width ?? targetWidth);\n const dynamicMinWidth = Number((textbox as any).dynamicMinWidth ?? 0);\n const lineWidths = getCanvasMeasuredTextboxLineWidths(textbox);\n const maxLineWidth = lineWidths.length > 0 ? Math.max(...lineWidths) : 0;\n // Use canvas-measured glyph widths as the single source of truth.\n // `dynamicMinWidth` over-reports when Fabric reserves space for an\n // unsplittable token even though the rendered lines actually fit — using it\n // in the fit check made the auto-shrink loop overshrink in the PDF/SVG\n // capture path, where the loop runs to completion before the textbox is\n // forced back to `width: targetWidth`. Rely solely on real glyph metrics.\n const widthDidGrow = actualTextboxWidth > targetWidth + 0.5;\n return {\n actualTextboxWidth,\n dynamicMinWidth,\n maxLineWidth,\n widthDidGrow,\n fitsWidth: maxLineWidth <= targetWidth + 1,\n };\n}\n\n/**\n * Generate a cache key for an element based on all properties that affect text bounds.\n * Uses width bucket so live group resize hits cache often (no recompute every pixel).\n */\nfunction getCacheKey(element: CanvasElement): string {\n const widthPx = typeof element.width === 'number' ? element.width : 200;\n return JSON.stringify({\n text: element.text,\n widthBucket: bucketWidth(widthPx),\n fontSize: element.fontSize,\n fontFamily: element.fontFamily,\n fontWeight: element.fontWeight,\n fontStyle: element.fontStyle,\n textAlign: element.textAlign,\n lineHeight: element.lineHeight,\n charSpacing: element.charSpacing,\n underline: element.underline,\n linethrough: element.linethrough,\n scaleX: element.scaleX,\n scaleY: element.scaleY,\n splitByGrapheme: element.splitByGrapheme,\n overflowPolicy: element.overflowPolicy,\n height: element.overflowPolicy === 'auto-shrink' ? element.height : undefined,\n minBoxHeight: (element as any).minBoxHeight,\n verticalAlign: (element as any).verticalAlign,\n });\n}\n\n/**\n * Measure text height using Fabric.js Textbox\n * This creates an off-screen Textbox, sets the text, and measures the actual rendered height.\n */\nexport function measureTextHeight(element: CanvasElement): number {\n if (element.type !== 'text') {\n return element.height || 20;\n }\n // For empty text, measure a single space to get consistent line height\n const textToMeasure = element.text || ' ';\n\n // Check cache first\n const cacheKey = getCacheKey(element);\n const cached = heightCache.get(cacheKey);\n if (cached && Date.now() - cached.timestamp < CACHE_TTL) {\n return cached.height;\n }\n\n try {\n const widthPx = typeof element.width === 'number' ? element.width : 200;\n const measureWidth = Math.max(1, bucketWidth(widthPx)); // measure at bucket so cache hits during drag\n let fontSize = element.fontSize || 16;\n\n // Auto-shrink: reduce font size until text fits within stored width & height (mirrors createText logic)\n const overflowPolicy = element.overflowPolicy || 'grow-and-push';\n if (overflowPolicy === 'auto-shrink') {\n const minBoxH = Math.max(0, Number((element as any).minBoxHeight) || 0);\n const baseHeight =\n typeof element.height === 'number'\n ? Math.max(element.height, minBoxH)\n : (minBoxH > 0 ? minBoxH : element.height);\n while (fontSize > 1) {\n const testTb = new fabric.Textbox(textToMeasure, {\n width: measureWidth,\n fontSize,\n fontFamily: element.fontFamily || 'Open Sans',\n fontWeight: element.fontWeight as number || 400,\n fontStyle: element.fontStyle || 'normal',\n lineHeight: element.lineHeight || 1.2,\n charSpacing: element.charSpacing || 0,\n splitByGrapheme: false,\n });\n testTb.initDimensions();\n const textHeight = testTb.height || 0;\n // Auto-shrink: wrap by width, shrink until wrapped content fits height.\n const fitsHeight = !baseHeight || textHeight <= baseHeight;\n const { fitsWidth } = getTextboxWidthFitMetrics(testTb, measureWidth);\n if (fitsHeight && fitsWidth) break;\n fontSize--;\n }\n // For auto-shrink, measure at the shrunk font size and cap to stored height\n const finalTb = new fabric.Textbox(textToMeasure, {\n width: measureWidth,\n fontSize,\n fontFamily: element.fontFamily || 'Open Sans',\n fontWeight: element.fontWeight as number || 400,\n fontStyle: element.fontStyle || 'normal',\n lineHeight: element.lineHeight || 1.2,\n charSpacing: element.charSpacing || 0,\n splitByGrapheme: false,\n });\n finalTb.initDimensions();\n const measuredH = (finalTb.height || element.height || 20) * (element.scaleY || 1);\n const cappedH = typeof baseHeight === 'number'\n ? Math.max(baseHeight * (element.scaleY || 1), measuredH)\n : measuredH;\n heightCache.set(cacheKey, { height: cappedH, timestamp: Date.now() });\n return cappedH;\n }\n\n const textbox = new fabric.Textbox(textToMeasure, {\n width: measureWidth,\n fontSize,\n fontFamily: element.fontFamily || 'Open Sans',\n fontWeight: element.fontWeight as number || 400,\n fontStyle: element.fontStyle || 'normal',\n textAlign: (element.textAlign as any) || 'left',\n lineHeight: element.lineHeight || 1.2,\n charSpacing: element.charSpacing || 0,\n underline: element.underline ?? false,\n linethrough: element.linethrough ?? false,\n splitByGrapheme: element.splitByGrapheme ?? (element.wordWrap === 'break-word'),\n left: 0,\n top: 0,\n });\n\n // Initialize dimensions to trigger text reflow\n textbox.initDimensions();\n\n // Get the actual height\n const height = textbox.height || element.height || 20;\n \n // Apply scale\n const scaledHeight = height * (element.scaleY || 1);\n\n // Cache the result\n heightCache.set(cacheKey, { height: scaledHeight, timestamp: Date.now() });\n\n return scaledHeight;\n } catch (error) {\n console.warn('[measureTextHeight] Failed to measure text, using fallback:', error);\n return fallbackEstimateHeight(element);\n }\n}\n\n/**\n * Minimum width so text doesn't overflow horizontally (longest line width).\n * Uses a temporary Textbox with large width to measure actual line widths.\n */\nexport function getMinTextWidth(element: CanvasElement): number {\n if (element.type !== 'text' || !element.text) {\n return typeof element.width === 'number' ? element.width : 200;\n }\n try {\n const textbox = new fabric.Textbox(element.text, {\n width: 10000,\n fontSize: element.fontSize || 16,\n fontFamily: element.fontFamily || 'Open Sans',\n fontWeight: element.fontWeight as number || 400,\n fontStyle: element.fontStyle || 'normal',\n lineHeight: element.lineHeight || 1.2,\n charSpacing: element.charSpacing || 0,\n splitByGrapheme: element.splitByGrapheme ?? (element.wordWrap === 'break-word'),\n left: 0,\n top: 0,\n });\n textbox.initDimensions();\n const lineWidths = (textbox as any).__lineWidths as number[] | undefined;\n if (lineWidths && lineWidths.length > 0) {\n const maxLine = Math.max(...lineWidths);\n return Math.ceil(maxLine) + 2;\n }\n } catch (_) {\n // ignore\n }\n return typeof element.width === 'number' ? element.width : 200;\n}\n\n/**\n * Fallback height estimation when Fabric measurement fails\n * Uses a simple character-based estimation\n */\nfunction fallbackEstimateHeight(element: CanvasElement): number {\n if (element.type !== 'text' || !element.text) {\n return element.height || 20;\n }\n\n const text = element.text;\n const fontSize = element.fontSize || 16;\n const lineHeight = element.lineHeight || 1.2;\n const fontStyle = element.fontStyle || 'normal';\n const width = (element.width || 200) * (element.scaleX || 1);\n\n // Estimate characters per line based on average character width (~0.5 * fontSize)\n const avgCharWidth = fontSize * 0.5;\n const charsPerLine = Math.max(1, Math.floor(width / avgCharWidth));\n\n // Count explicit line breaks and wrapped lines\n const lines = text.split('\\n');\n let totalLines = 0;\n\n for (const line of lines) {\n const wrappedLines = Math.max(1, Math.ceil(line.length / charsPerLine));\n totalLines += wrappedLines;\n }\n\n const estimatedHeight = totalLines * fontSize * lineHeight;\n return Math.max(element.height || 20, estimatedHeight) * (element.scaleY || 1);\n}\n\n/**\n * Measure text and return full bounding box\n */\nexport function measureTextBounds(element: CanvasElement): {\n width: number;\n height: number;\n left: number;\n top: number;\n bottom: number;\n right: number;\n} {\n const width = (element.width || 100) * (element.scaleX || 1);\n const height = element.type === 'text' \n ? measureTextHeight(element)\n : (element.height || 20) * (element.scaleY || 1);\n\n return {\n left: element.left,\n top: element.top,\n width,\n height,\n bottom: element.top + height,\n right: element.left + width,\n };\n}\n\n/**\n * Clear the measurement cache\n * Call this when making bulk updates or when memory is a concern\n */\nexport function clearMeasurementCache(): void {\n heightCache.clear();\n}\n\n/**\n * Apply auto-shrink policy to text element\n * Reduces font size until text fits within the specified bounds\n * Returns the new fontSize to use\n */\nexport function calculateAutoShrinkFontSize(\n element: CanvasElement,\n maxWidth: number,\n maxHeight: number\n): number {\n if (element.type !== 'text' || !element.text) {\n return element.fontSize || 16;\n }\n\n const minFontSize = element.minFontSize || 8;\n let fontSize = element.fontSize || 16;\n\n // Binary search for the right font size\n let low = minFontSize;\n let high = fontSize;\n\n while (low < high - 1) {\n const mid = Math.floor((low + high) / 2);\n \n const testElement = { ...element, fontSize: mid };\n const bounds = measureTextBounds(testElement);\n\n if (bounds.width <= maxWidth && bounds.height <= maxHeight) {\n low = mid;\n } else {\n high = mid;\n }\n }\n\n return low;\n}\n\n/**\n * Apply max-lines-ellipsis policy to text\n * Truncates text to fit within maxLines and adds ellipsis\n * Returns the truncated text\n */\nexport function truncateTextToMaxLines(\n element: CanvasElement,\n maxLines: number\n): string {\n if (element.type !== 'text' || !element.text) {\n return element.text || '';\n }\n\n const text = element.text;\n const fontSize = element.fontSize || 16;\n const width = (element.width || 200) * (element.scaleX || 1);\n\n // Estimate characters per line\n const avgCharWidth = fontSize * 0.5;\n const charsPerLine = Math.max(1, Math.floor(width / avgCharWidth));\n\n const lines = text.split('\\n');\n const outputLines: string[] = [];\n let lineCount = 0;\n\n for (const line of lines) {\n if (lineCount >= maxLines) break;\n\n // Check if this line needs to wrap\n if (line.length <= charsPerLine) {\n outputLines.push(line);\n lineCount++;\n } else {\n // Split into multiple lines\n let remaining = line;\n while (remaining.length > 0 && lineCount < maxLines) {\n const chunk = remaining.substring(0, charsPerLine);\n remaining = remaining.substring(charsPerLine);\n \n if (lineCount === maxLines - 1 && remaining.length > 0) {\n // Last allowed line with more content - add ellipsis\n outputLines.push(chunk.trim() + '…');\n } else {\n outputLines.push(chunk);\n }\n lineCount++;\n }\n }\n }\n\n return outputLines.join('\\n');\n}\n","/**\n * Layout Engine (stub) – start from scratch.\n * Exports minimal no-op/simple implementations so the app runs without the previous layout logic.\n */\n\nimport type { CanvasElement, CanvasNode, CanvasState, CanvasPage, GroupNode } from '@/types/editor';\nimport type { GroupLayoutMode } from '@/types/editor';\nimport { isElement, isGroup, findParentGroup, findNodeById, isVerticalStackLayoutMode, isStackLayoutMode, generateId } from '@/types/editor';\nimport { measureTextHeight } from '@/lib/textMeasurement';\n\n/** Config for which nodes repeat on continuation pages and which group is the flow region. */\nexport interface PaginationConfig {\n flowRegionId?: string;\n repeatOnContinuationIds?: string[];\n}\n\nexport interface BoundsOptions {\n pageContentWidth?: number;\n pageContentHeight?: number;\n resolvedContentWidth?: number;\n resolvedContentHeight?: number;\n}\n\nexport interface LayoutRecalcResult {\n updates: Map<string, { top?: number; left?: number; width?: number; height?: number }>;\n boundsChanged: boolean;\n newBounds: { top: number; bottom: number; height: number; width?: number };\n}\n\nfunction simpleWidth(node: CanvasNode): number {\n if (isElement(node)) {\n const w = (node as CanvasElement).width;\n return typeof w === 'number' ? w : 100;\n }\n return 1; // Group: size from content (see getNodeBounds)\n}\n\nfunction simpleHeight(node: CanvasNode): number {\n if (isElement(node)) {\n const el = node as CanvasElement;\n const h = el.height;\n if (typeof h === 'number') return h;\n // For text elements without explicit height, measure actual text height\n if (el.type === 'text' && el.text) {\n return measureTextHeight(el);\n }\n return 20;\n }\n return 1; // Group: size from content (see getNodeBounds)\n}\n\nfunction getNodeLeft(node: CanvasNode): number {\n return typeof node.left === 'number' ? node.left : 0;\n}\n\nfunction getNodeTop(node: CanvasNode): number {\n return typeof node.top === 'number' ? node.top : 0;\n}\n\n/** Stub: return absolute layout for all sections (native Fabric group, no flex/grid). */\nexport function getDefaultLayoutMode(_sectionType?: string): GroupLayoutMode {\n return 'absolute';\n}\n\n/** Stack group: vertical = first child top; rest top = prevBottom + gap; horizontal = first left; rest left = prevRight + gap. Returns group-relative { top, left } per child id. */\nexport function resolveStackGroupEffectivePositions(\n group: GroupNode,\n pageChildren: CanvasNode[],\n options?: BoundsOptions\n): Map<string, { top: number; left: number }> {\n const mode = group.layoutMode ?? 'absolute';\n if (!isStackLayoutMode(mode)) return new Map();\n const gap = group.stackSpacing ?? 8;\n const padTop = group.paddingTop ?? 0;\n const padLeft = group.paddingLeft ?? 0;\n const padRight = group.paddingRight ?? 0;\n const padBottom = group.paddingBottom ?? 0;\n const justify = group.justifyContent ?? 'start';\n const align = group.alignItems ?? 'start';\n const isVertical = isVerticalStackLayoutMode(mode);\n const kids = group.children ?? [];\n const out = new Map<string, { top: number; left: number }>();\n // Capture per-child sizes once (used by both the chain pass and justify/align pass)\n const sizes = new Map<string, { width: number; height: number }>();\n for (const c of kids) {\n const b = getNodeBounds(c, pageChildren, options);\n sizes.set(c.id, { width: b.width, height: b.height });\n }\n if (isVertical) {\n let prevBottom = padTop;\n let firstSeen = false;\n for (let i = 0; i < kids.length; i++) {\n const child = kids[i];\n const storedTop = getNodeTop(child);\n const storedLeft = getNodeLeft(child);\n const mTop = (child as any).marginTop ?? 0;\n const mLeft = (child as any).marginLeft ?? 0;\n const effectiveTop = !firstSeen\n ? padTop + storedTop + mTop\n : prevBottom + gap + storedTop + mTop;\n firstSeen = true;\n out.set(child.id, { top: effectiveTop, left: padLeft + storedLeft + mLeft });\n const h = sizes.get(child.id)!.height;\n prevBottom = effectiveTop + h + ((child as any).marginBottom ?? 0);\n }\n } else {\n let prevRight = padLeft;\n let firstSeen = false;\n for (let i = 0; i < kids.length; i++) {\n const child = kids[i];\n const storedLeft = getNodeLeft(child);\n const storedTop = getNodeTop(child);\n const mTop = (child as any).marginTop ?? 0;\n const mLeft = (child as any).marginLeft ?? 0;\n const effectiveLeft = !firstSeen\n ? padLeft + storedLeft + mLeft\n : prevRight + gap + storedLeft + mLeft;\n firstSeen = true;\n out.set(child.id, { top: padTop + storedTop + mTop, left: effectiveLeft });\n const w = sizes.get(child.id)!.width;\n prevRight = effectiveLeft + w + ((child as any).marginRight ?? 0);\n }\n }\n\n // Justify (main axis) + align (cross axis): only meaningful when group has an\n // explicit container size on the relevant axis. Without it, default 'start'/'start'\n // matches the chain output exactly so this is a no-op for legacy templates.\n const containerW = typeof group.width === 'number' ? group.width : undefined;\n const containerH = typeof group.height === 'number' ? group.height : undefined;\n const mainContainer = isVertical ? containerH : containerW;\n const crossContainer = isVertical ? containerW : containerH;\n\n // Cross axis: align\n if (align !== 'start' && crossContainer != null && kids.length > 0) {\n const crossPad0 = isVertical ? padLeft : padTop;\n const crossPadEnd = isVertical ? padRight : padBottom;\n const innerCross = Math.max(0, crossContainer - crossPad0 - crossPadEnd);\n for (const child of kids) {\n const pos = out.get(child.id);\n if (!pos) continue;\n const sz = sizes.get(child.id)!;\n const childCross = isVertical ? sz.width : sz.height;\n let crossPos: number;\n if (align === 'stretch') {\n // Stretch: position at pad0; the renderer that consumes positions\n // should also expand child width/height to innerCross. We expose the\n // intent through alignItems on the parent; the child size pass handles it.\n crossPos = crossPad0;\n } else if (align === 'center') {\n crossPos = crossPad0 + (innerCross - childCross) / 2;\n } else {\n // 'end'\n crossPos = crossPad0 + (innerCross - childCross);\n }\n if (isVertical) {\n out.set(child.id, { top: pos.top, left: crossPos });\n } else {\n out.set(child.id, { top: crossPos, left: pos.left });\n }\n }\n }\n\n // Main axis: justify\n if (justify !== 'start' && mainContainer != null && kids.length > 0) {\n const mainPad0 = isVertical ? padTop : padLeft;\n const mainPadEnd = isVertical ? padBottom : padRight;\n const innerMain = Math.max(0, mainContainer - mainPad0 - mainPadEnd);\n // Total intrinsic main size of children with default gaps and margins\n let totalMain = 0;\n for (let i = 0; i < kids.length; i++) {\n const child = kids[i];\n const sz = sizes.get(child.id)!;\n totalMain += isVertical ? sz.height : sz.width;\n const marginStart = isVertical ? ((child as any).marginTop ?? 0) : ((child as any).marginLeft ?? 0);\n const marginEnd = isVertical ? ((child as any).marginBottom ?? 0) : ((child as any).marginRight ?? 0);\n totalMain += marginStart + marginEnd;\n }\n const baseGapTotal = gap * Math.max(0, kids.length - 1);\n const free = innerMain - totalMain - baseGapTotal;\n let offset = 0;\n let extraGap = 0;\n if (free > 0) {\n switch (justify) {\n case 'center':\n offset = free / 2;\n break;\n case 'end':\n offset = free;\n break;\n case 'space-between':\n if (kids.length > 1) extraGap = free / (kids.length - 1);\n else offset = free / 2;\n break;\n case 'space-around':\n if (kids.length > 0) {\n extraGap = free / kids.length;\n offset = extraGap / 2;\n }\n break;\n case 'space-evenly':\n extraGap = free / (kids.length + 1);\n offset = extraGap;\n break;\n }\n }\n if (offset !== 0 || extraGap !== 0) {\n // Recompute main-axis chain with offset + extra gap, preserving cross axis\n let cursor = mainPad0 + offset;\n for (let i = 0; i < kids.length; i++) {\n const child = kids[i];\n const sz = sizes.get(child.id)!;\n const marginStart = isVertical ? ((child as any).marginTop ?? 0) : ((child as any).marginLeft ?? 0);\n const marginEnd = isVertical ? ((child as any).marginBottom ?? 0) : ((child as any).marginRight ?? 0);\n const main = (isVertical ? sz.height : sz.width);\n const pos = out.get(child.id);\n if (!pos) continue;\n const startMain = cursor + marginStart;\n if (isVertical) {\n out.set(child.id, { top: startMain, left: pos.left });\n } else {\n out.set(child.id, { top: pos.top, left: startMain });\n }\n cursor = startMain + main + marginEnd + gap + extraGap;\n }\n }\n }\n\n return out;\n}\n\n/** Group size from children (or explicit width/height when empty). For stack groups uses resolved positions. */\nfunction groupBoundsFromChildren(\n group: GroupNode,\n pageChildren: CanvasNode[],\n options?: BoundsOptions\n): { width: number; height: number } {\n const kids = group.children ?? [];\n if (kids.length === 0) {\n const w = group.width;\n const h = group.height;\n return { width: typeof w === 'number' && w > 0 ? w : 1, height: typeof h === 'number' && h > 0 ? h : 1 };\n }\n const isStack = isStackLayoutMode(group.layoutMode);\n const positions = isStack ? resolveStackGroupEffectivePositions(group, pageChildren, options) : null;\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const child of kids) {\n const b = getNodeBounds(child, pageChildren, options);\n const cl = positions ? (positions.get(child.id)?.left ?? getNodeLeft(child)) : getNodeLeft(child);\n const ct = positions ? (positions.get(child.id)?.top ?? getNodeTop(child)) : getNodeTop(child);\n minX = Math.min(minX, cl);\n minY = Math.min(minY, ct);\n maxX = Math.max(maxX, cl + b.width);\n maxY = Math.max(maxY, ct + b.height);\n }\n if (isStack) {\n const padRight = group.paddingRight ?? 0;\n const padBottom = group.paddingBottom ?? 0;\n // For stacks, padding-top/left is already baked into child positions.\n // Group's box starts at 0,0 and extends to maxChildExtent + padRight/padBottom.\n return {\n width: Math.max(1, maxX + padRight),\n height: Math.max(1, maxY + padBottom),\n };\n }\n return {\n width: Math.max(1, maxX - minX),\n height: Math.max(1, maxY - minY),\n };\n}\n\nexport function getNodeBounds(\n node: CanvasNode,\n pageChildren?: CanvasNode[],\n options?: BoundsOptions\n): { left: number; top: number; width: number; height: number; bottom: number; right: number } {\n const left = getNodeLeft(node);\n const top = getNodeTop(node);\n let width: number;\n let height: number;\n if (isGroup(node) && pageChildren?.length !== undefined) {\n const size = groupBoundsFromChildren(node as GroupNode, pageChildren ?? [], options);\n width = size.width;\n height = size.height;\n } else {\n width = simpleWidth(node);\n height = simpleHeight(node);\n }\n return { left, top, width, height, bottom: top + height, right: left + width };\n}\n\nexport function getNodeBoundsFromChildren(node: CanvasNode): {\n left: number;\n top: number;\n width: number;\n height: number;\n bottom: number;\n right: number;\n} {\n return getNodeBounds(node);\n}\n\nfunction absoluteBoundsRecur(node: CanvasNode, pageChildren: CanvasNode[], options?: BoundsOptions): { left: number; top: number; width: number; height: number } {\n const parent = pageChildren ? findParentGroup(pageChildren, node.id) : null;\n const b = getNodeBounds(node, pageChildren, options);\n if (!parent) return b;\n const parentAbs = absoluteBoundsRecur(parent, pageChildren, options);\n // Stack group: use resolved position (first child group-relative, rest chain) not stored left/top\n const isStackParent = isStackLayoutMode(parent.layoutMode);\n const inParentLeft = isStackParent\n ? (resolveStackGroupEffectivePositions(parent, pageChildren, options).get(node.id)?.left ?? b.left)\n : b.left;\n const inParentTop = isStackParent\n ? (resolveStackGroupEffectivePositions(parent, pageChildren, options).get(node.id)?.top ?? b.top)\n : b.top;\n return {\n left: parentAbs.left + inParentLeft,\n top: parentAbs.top + inParentTop,\n width: b.width,\n height: b.height,\n };\n}\n\nexport function getAbsoluteBounds(\n node: CanvasNode,\n pageChildren: CanvasNode[],\n options?: BoundsOptions\n): { left: number; top: number; width: number; height: number; bottom: number; right: number } {\n const { left, top, width, height } = absoluteBoundsRecur(node, pageChildren, options);\n return { left, top, width, height, bottom: top + height, right: left + width };\n}\n\nexport function absoluteToStorePosition(\n absoluteLeft: number,\n absoluteTop: number,\n nodeId: string,\n pageChildren: CanvasNode[]\n): { left: number; top: number } {\n const node = findNodeById(pageChildren, nodeId);\n if (!node) return { left: absoluteLeft, top: absoluteTop };\n const parent = findParentGroup(pageChildren, nodeId);\n if (!parent) return { left: absoluteLeft, top: absoluteTop };\n const parentAbs = getAbsoluteBounds(parent, pageChildren);\n const storeLeft = absoluteLeft - parentAbs.left;\n const inParentTop = absoluteTop - parentAbs.top;\n const isStack = isStackLayoutMode((parent as GroupNode).layoutMode);\n if (!isStack) return { left: storeLeft, top: inParentTop };\n const kids = (parent as GroupNode).children ?? [];\n const idx = kids.findIndex((c) => c.id === nodeId);\n if (idx < 0) return { left: storeLeft, top: inParentTop };\n if (idx === 0) return { left: storeLeft, top: inParentTop };\n const gap = (parent as GroupNode).stackSpacing ?? 8;\n const resolved = resolveStackGroupEffectivePositions(parent as GroupNode, pageChildren);\n const prev = kids[idx - 1];\n const prevResolved = resolved.get(prev.id);\n const prevHeight = getNodeBounds(prev, pageChildren).height;\n const prevBottom = prevResolved ? prevResolved.top + prevHeight + ((prev as any).marginBottom ?? 0) : 0;\n const storeTop = inParentTop - prevBottom - gap;\n return { left: storeLeft, top: Math.max(0, storeTop) };\n}\n\nexport function getEffectiveGroupDisplay(_group: GroupNode): 'block' | 'flex' | 'grid' {\n return 'block';\n}\n\nexport function getEffectiveGroupFlexDirection(_group: GroupNode): 'row' | 'column' {\n return 'column';\n}\n\nexport function getGroupContentBox(\n group: GroupNode,\n pageChildren?: CanvasNode[],\n options?: BoundsOptions\n): { left: number; top: number; width: number; height: number } {\n const b = getNodeBounds(group, pageChildren, options);\n return { left: b.left, top: b.top, width: b.width, height: b.height };\n}\n\nexport function reflowPageFromRoot(_pageChildren: CanvasNode[]): Map<string, { left?: number; top?: number; width?: number; height?: number }> {\n return new Map();\n}\n\nexport function reflowFromGroup(_pageChildren: CanvasNode[], _groupId: string): Map<string, { left?: number; top?: number; width?: number; height?: number }> {\n return new Map();\n}\n\n/** Reflow stack group: recompute stored top/left so children form a vertical or horizontal stack. */\nexport function reflowStackGroup(\n group: GroupNode,\n pageChildren: CanvasNode[],\n spacing?: number\n): Map<string, { top?: number; left?: number }> {\n const mode = group.layoutMode ?? 'absolute';\n if (!isStackLayoutMode(mode)) return new Map();\n const gap = spacing ?? group.stackSpacing ?? 8;\n const kids = group.children ?? [];\n if (kids.length <= 1) return new Map();\n const updates = new Map<string, { top?: number; left?: number }>();\n if (isVerticalStackLayoutMode(mode)) {\n const firstLeft = getNodeLeft(kids[0]);\n let prevBottom = 0;\n for (let i = 0; i < kids.length; i++) {\n const child = kids[i];\n const b = getNodeBounds(child, pageChildren);\n const currentTop = getNodeTop(child);\n const effectiveTop = i === 0 ? currentTop : prevBottom + gap;\n prevBottom = effectiveTop + b.height + ((child as any).marginBottom ?? 0);\n if (i > 0) updates.set(child.id, { top: 0, left: firstLeft });\n }\n } else {\n const firstTop = getNodeTop(kids[0]);\n let prevRight = 0;\n for (let i = 0; i < kids.length; i++) {\n const child = kids[i];\n const b = getNodeBounds(child, pageChildren);\n const currentLeft = getNodeLeft(child);\n const effectiveLeft = i === 0 ? currentLeft : prevRight + gap;\n prevRight = effectiveLeft + b.width + ((child as any).marginRight ?? 0);\n if (i > 0) updates.set(child.id, { left: 0, top: firstTop });\n }\n }\n return updates;\n}\n\n/** Fill text heights in tree using measureTextHeight so stack reflow uses correct heights (e.g. on use page when user types). Always re-measures text so current content drives layout. */\nfunction fillTextHeightsInTree(\n children: CanvasNode[],\n options?: { preserveExplicitTextHeights?: boolean }\n): CanvasNode[] {\n return children.map((node) => {\n if (isGroup(node)) {\n return { ...node, children: fillTextHeightsInTree((node as GroupNode).children ?? [], options) };\n }\n if (isElement(node)) {\n const el = node as CanvasElement;\n if (el.type === 'text') {\n if (options?.preserveExplicitTextHeights && typeof el.height === 'number') {\n return el;\n }\n const h = measureTextHeight(el);\n return { ...el, height: h };\n }\n return node;\n }\n return node;\n });\n}\n\n/** Fill text heights for use/preview so resolved stack positions use correct heights. Positions are chain-relative and resolved on read; no top overwriting. */\nexport function applyStackReflowToPageTree(\n children: CanvasNode[],\n options?: { preserveExplicitTextHeights?: boolean }\n): CanvasNode[] {\n return fillTextHeightsInTree(children, options);\n}\n\nlet _dragBoundsOverride: Record<string, { left: number; top: number; width: number; height: number }> | null = null;\nexport function setDragBoundsOverride(_overrides: Record<string, { left: number; top: number; width: number; height: number } | null> | null): void {\n _dragBoundsOverride = _overrides as Record<string, { left: number; top: number; width: number; height: number }> | null;\n}\nexport function clearDragBoundsOverride(): void {\n _dragBoundsOverride = null;\n}\n\nexport function computeGroupResizeLayoutKey(\n _group: GroupNode,\n _contentWidth: number,\n _contentHeight: number,\n _bucketPx?: number,\n _pageChildren?: CanvasNode[]\n): string {\n return '';\n}\n\nexport function getGroupLayoutSnapTargets(\n _group: GroupNode,\n _pageChildren: CanvasNode[],\n _box: { left: number; top: number; width: number; height: number }\n): { verticalTargets: number[]; horizontalTargets: number[] } {\n return { verticalTargets: [], horizontalTargets: [] };\n}\n\nexport function computeDiscreteGridSnappedBox(\n _group: GroupNode,\n _pageChildren: CanvasNode[],\n box: { left: number; top: number; width: number; height: number }\n): { snappedBox: { left: number; top: number; width: number; height: number }; cols: number; rows: number } {\n return { snappedBox: box, cols: 1, rows: 1 };\n}\n\nexport function getDiscreteGridSnapGuides(\n _group: GroupNode,\n _pageChildren: CanvasNode[],\n _anchorBox: { left: number; top: number; width: number; height: number },\n _cols: number,\n _rows: number,\n _fixedCellH?: number\n): { vertical: Array<{ position: number; active: boolean }>; horizontal: Array<{ position: number; active: boolean }> } {\n return { vertical: [], horizontal: [] };\n}\n\nexport function getOrderedFlexOrGridChildren(parent: GroupNode): CanvasNode[] {\n return parent.children;\n}\n\nexport function isGridGroupForResize(_group: GroupNode): boolean {\n return false;\n}\n\nexport function handleElementChange(\n _pageChildren: CanvasNode[],\n _changedElementId: string,\n _updateElementFn: (id: string, updates: Partial<CanvasElement>) => void\n): void {}\n\nexport function recalculateSiblingsBelow(\n _parent: GroupNode,\n _changedNodeId: string,\n _direction: 'vertical' | 'horizontal' = 'vertical',\n _pageChildren?: CanvasNode[],\n _pendingUpdates?: Map<string, { width?: number; height?: number; top?: number; left?: number }>,\n _options?: BoundsOptions\n): LayoutRecalcResult {\n return {\n updates: new Map(),\n boundsChanged: false,\n newBounds: { top: 0, bottom: 0, height: 0, width: 0 },\n };\n}\n\nexport function propagateLayoutChange(\n _pageChildren: CanvasNode[],\n _groupId: string,\n _updateElementFn: (id: string, updates: Partial<CanvasElement>) => void,\n _pendingUpdates: Map<string, { width?: number; height?: number; top?: number; left?: number }>\n): void {}\n\nexport function calculateFlatLayout(\n _group: GroupNode,\n _options?: { pageChildren?: CanvasNode[]; options?: BoundsOptions }\n): Map<string, { left?: number; top?: number; width?: number; height?: number }> {\n return new Map();\n}\n\n/** Returns true if the group's content extends below the given page height (group is measured with getAbsoluteBounds). */\nexport function detectOverflow(\n group: GroupNode,\n pageChildren: CanvasNode[],\n pageHeight: number,\n options?: BoundsOptions\n): boolean {\n const b = getAbsoluteBounds(group, pageChildren, options);\n return b.bottom > pageHeight;\n}\n\n/**\n * Returns root-level node ids whose absolute bottom extends beyond pageHeight.\n * Use this to know which nodes overflow the page; when using paginationConfig.flowRegionId,\n * only that group is considered the \"flow\" and the rest are fixed (header/footer).\n */\nexport function detectPageOverflow(\n pageChildren: CanvasNode[],\n pageHeight: number,\n options?: BoundsOptions\n): string[] {\n const overflowIds: string[] = [];\n for (const node of pageChildren) {\n const b = getAbsoluteBounds(node, pageChildren, options);\n if (b.bottom > pageHeight) overflowIds.push(node.id);\n }\n return overflowIds;\n}\n\n/**\n * Result of splitting flow-region content across pages: which child indices fit on the first page\n * and which overflow to the continuation page. Flow region is assumed to be a vertical stack.\n */\nexport interface FlowSplitResult {\n /** Number of flow-region children that fit on the first page. */\n firstPageCount: number;\n /** Index in flow-region children at which overflow starts (first item on continuation page). */\n overflowFromIndex: number;\n /** Absolute top of the flow region (so caller can compute available height = pageHeight - flowTop). */\n flowRegionTop: number;\n /** Absolute bottom of the flow region. */\n flowRegionBottom: number;\n}\n\n/**\n * Given a flow region (vertical stack group), compute how to split its children across page 1 and continuation.\n * Uses absolute bounds; available height on page 1 = pageHeight - flowRegionTop.\n * Returns firstPageCount = how many children fit on page 1, overflowFromIndex = first child index that goes to page 2.\n */\nexport function computeFlowSplit(\n flowGroup: GroupNode,\n pageChildren: CanvasNode[],\n pageHeight: number,\n options?: BoundsOptions\n): FlowSplitResult {\n const flowAbs = getAbsoluteBounds(flowGroup, pageChildren, options);\n const flowTop = flowAbs.top;\n const flowBottom = flowAbs.bottom;\n const availableHeight = Math.max(0, pageHeight - flowTop);\n const kids = flowGroup.children ?? [];\n const gap = flowGroup.stackSpacing ?? 8;\n if (kids.length === 0) {\n return { firstPageCount: 0, overflowFromIndex: 0, flowRegionTop: flowTop, flowRegionBottom: flowBottom };\n }\n let cumulative = 0;\n let firstPageCount = 0;\n for (let i = 0; i < kids.length; i++) {\n if (i > 0) cumulative += gap;\n const b = getNodeBounds(kids[i], pageChildren, options);\n const h = b.height;\n const mTop = (kids[i] as any).marginTop ?? 0;\n cumulative += mTop;\n if (cumulative + h > availableHeight && firstPageCount === 0) {\n firstPageCount = 1;\n break;\n }\n cumulative += h + ((kids[i] as any).marginBottom ?? 0);\n firstPageCount = i + 1;\n if (cumulative >= availableHeight) break;\n }\n return {\n firstPageCount,\n overflowFromIndex: Math.min(firstPageCount, kids.length),\n flowRegionTop: flowTop,\n flowRegionBottom: flowBottom,\n };\n}\n\n/** Deep-clone a node tree with new ids (for continuation page structure). */\nfunction cloneNodeWithNewIds(node: CanvasNode): CanvasNode {\n if (isGroup(node)) {\n const g = node as GroupNode;\n return {\n ...g,\n id: generateId('group'),\n children: (g.children ?? []).map(cloneNodeWithNewIds),\n };\n }\n const el = node as CanvasElement;\n return { ...el, id: generateId('el') };\n}\n\n/** Clone a group but replace its children with an empty array (for flow region placeholder on continuation page). */\nfunction cloneFlowRegionPlaceholder(flowGroup: GroupNode): GroupNode {\n return {\n ...flowGroup,\n id: generateId('group'),\n children: [],\n };\n}\n\n/**\n * Describes the root-level structure of a continuation page: cloned repeat nodes + flow region placeholder.\n * Use this when auto-pagination is enabled to build \"page 2\" from page 1.\n */\nexport interface ContinuationPageStructure {\n /** Root-level children for the continuation page: clones of repeat nodes (header/footer) + one flow region placeholder (empty group). */\n rootChildren: CanvasNode[];\n /** Id of the flow region placeholder group (so caller can fill it with overflow content or use for layout). */\n flowRegionPlaceholderId: string;\n}\n\n/**\n * Build the structure of a new (continuation) page from page 1's root children and pagination config.\n * - Repeats: nodes whose id is in repeatOnContinuationIds are cloned (new ids) and appear on the continuation page.\n * - Flow region: the group identified by flowRegionId is cloned once with empty children; overflow content is placed there at render/apply time.\n * Order on continuation page = same as on page 1: repeat nodes first (in page 1 order), then flow region placeholder.\n */\nexport function getContinuationPageStructure(\n page1RootChildren: CanvasNode[],\n config: PaginationConfig\n): ContinuationPageStructure {\n const repeatIds = new Set(config.repeatOnContinuationIds ?? []);\n const flowId = config.flowRegionId;\n const rootChildren: CanvasNode[] = [];\n let flowPlaceholder: GroupNode | null = null;\n for (const node of page1RootChildren) {\n if (repeatIds.has(node.id)) rootChildren.push(cloneNodeWithNewIds(node));\n if (flowId && node.id === flowId && isGroup(node)) {\n flowPlaceholder = cloneFlowRegionPlaceholder(node as GroupNode);\n }\n }\n if (flowPlaceholder) rootChildren.push(flowPlaceholder);\n return {\n rootChildren,\n flowRegionPlaceholderId: flowPlaceholder?.id ?? '',\n };\n}\n\nexport function reflowPageRootChildren(\n _children: CanvasNode[],\n _gap?: number,\n _direction?: 'vertical' | 'horizontal'\n): Map<string, { left?: number; top?: number }> {\n return new Map();\n}\n\nexport function constrainChildrenToGroupBounds(\n _group: GroupNode,\n _pageChildren: CanvasNode[]\n): Map<string, Partial<CanvasElement> & Partial<GroupNode>> {\n return new Map();\n}\n\nexport function normalizeGroupChildrenPositions(_children: CanvasNode[]): CanvasNode[] {\n return _children;\n}\n\nexport function applyLayoutToCanvas(canvas: CanvasState): CanvasState {\n return canvas;\n}\n","/**\n * Page clipboard — Copy a full page (canvas + bound dynamic fields + theme properties)\n * from one template to another via localStorage. Cross-tab safe.\n *\n * v2: Smart paste — carries field bindings and theme properties that reference any element on\n * the copied page, with element IDs rewritten to the new (re-IDed) nodes. The paste step then\n * merges them into the target template (reuse fields by exact id+type match, otherwise create\n * fresh suffixed ids; theme properties are inserted into ALL existing variants).\n *\n * Design intent: a copied page is a \"smart page\" — it carries its own form schema and theme\n * fragment, so dropping it into another template just works without re-binding by hand.\n */\nimport type {\n CanvasPage,\n CanvasNode,\n GroupNode,\n DynamicField,\n FieldMapping,\n ThemeProperty,\n} from '@/types/editor';\nimport { isGroup, generateId, getAllElementIds, PAGE_BACKGROUND_ELEMENT_ID } from '@/types/editor';\n\nexport const PAGE_CLIPBOARD_KEY = 'pixldocs:page-clipboard';\nexport const PAGE_CLIPBOARD_VERSION = 2;\n\n/** A theme property carried with the clipboard, plus its current value from the source's default variant. */\nexport interface CarriedThemeProperty {\n property: ThemeProperty;\n /** Value resolved from the source template's default theme variant (used to hydrate target variants). */\n defaultValue?: string;\n}\n\nexport interface PageClipboardPayload {\n version: number;\n copiedAt: string;\n sourceTemplateId?: string;\n sourceTemplateName?: string;\n page: CanvasPage;\n /** Dynamic fields whose mappings touch elements on this page. elementIds inside mappings reference the (re-IDed) page nodes. */\n dynamicFields: DynamicField[];\n /** Theme properties referencing elements on this page (with their default-variant values). elementIds reference re-IDed page nodes. */\n themeProperties: CarriedThemeProperty[];\n /** Snapshot summary for the paste-confirm UI without re-walking the tree. */\n meta: {\n nodeCount: number;\n elementCount: number;\n groupCount: number;\n fieldCount: number;\n themePropertyCount: number;\n repeatableSectionCount: number;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Counting / inspection\n// ---------------------------------------------------------------------------\n\nfunction countNodes(nodes: CanvasNode[]): { nodeCount: number; elementCount: number; groupCount: number; repeatableSectionCount: number } {\n let nodeCount = 0;\n let elementCount = 0;\n let groupCount = 0;\n let repeatableSectionCount = 0;\n const walk = (list: CanvasNode[]) => {\n for (const n of list) {\n nodeCount++;\n const rep = (n as CanvasNode & { repeatableSection?: { label: string } }).repeatableSection;\n if (rep?.label) repeatableSectionCount++;\n if (isGroup(n)) {\n groupCount++;\n walk((n as GroupNode).children ?? []);\n } else {\n elementCount++;\n }\n }\n };\n walk(nodes);\n return { nodeCount, elementCount, groupCount, repeatableSectionCount };\n}\n\n/** Collect all element IDs on the page, including the page-background sentinel (so theme bindings to page bg are picked up). */\nfunction collectPageElementIds(page: CanvasPage): Set<string> {\n const ids = new Set<string>(getAllElementIds(page.children ?? []));\n ids.add(PAGE_BACKGROUND_ELEMENT_ID);\n return ids;\n}\n\n// ---------------------------------------------------------------------------\n// Re-ID + binding rewrite\n// ---------------------------------------------------------------------------\n\n/** Strip cross-template metadata that should not survive the hop. Repeatable sections keep label + min/max. */\nfunction stripCrossTemplateMetadata<T extends Record<string, any>>(node: T): T {\n const cleaned: Record<string, any> = { ...node };\n // Strip references to a source-template form definition (target may not have it).\n if (cleaned.repeatableSection && typeof cleaned.repeatableSection === 'object') {\n const { formDefId: _f, formDefSectionPrefix: _p, ...keep } = cleaned.repeatableSection as Record<string, unknown>;\n cleaned.repeatableSection = keep;\n }\n return cleaned as T;\n}\n\n/**\n * Deep-clone a node tree, regenerating every id. Returns the cloned tree and an oldId→newId map\n * so the caller can rewrite external references (dynamic field mappings, theme properties).\n *\n * Exported so the paste step can re-ID the clipboard's page on EVERY paste — otherwise pasting\n * the same payload twice would produce two pages sharing identical node IDs (and deleting one\n * would silently remove the other).\n */\nexport function reIdSubtree(nodes: CanvasNode[]): { nodes: CanvasNode[]; idMap: Map<string, string> } {\n const idMap = new Map<string, string>();\n // Page-background sentinel maps to itself — it's a constant across templates.\n idMap.set(PAGE_BACKGROUND_ELEMENT_ID, PAGE_BACKGROUND_ELEMENT_ID);\n\n const cloneOne = (node: CanvasNode): CanvasNode => {\n if (isGroup(node)) {\n const g = node as GroupNode;\n const newId = generateId('group');\n idMap.set(g.id, newId);\n return {\n ...stripCrossTemplateMetadata(g),\n id: newId,\n children: (g.children ?? []).map(cloneOne),\n };\n }\n const prefix =\n node.type === 'text' ? 'text' :\n node.type === 'image' ? 'img' :\n node.type === 'shape' ? 'shape' :\n node.type === 'line' ? 'line' : 'el';\n const newId = generateId(prefix);\n idMap.set(node.id, newId);\n return {\n ...stripCrossTemplateMetadata(node),\n id: newId,\n };\n };\n\n return { nodes: nodes.map(cloneOne), idMap };\n}\n\n/** Filter mappings to those whose elementId is in the id-map; rewrite to new ids. Returns [] if no mappings survive. */\nexport function rewriteFieldMappings(mappings: FieldMapping[] | undefined, idMap: Map<string, string>): FieldMapping[] {\n if (!mappings?.length) return [];\n return mappings\n .filter((m) => idMap.has(m.elementId))\n .map((m) => ({ ...m, elementId: idMap.get(m.elementId)! }));\n}\n\n// ---------------------------------------------------------------------------\n// Copy\n// ---------------------------------------------------------------------------\n\n/** Save a page (with bindings + theme fragment) to the clipboard. Returns the saved payload. */\nexport function copyPageToClipboard(\n page: CanvasPage,\n source: {\n templateId?: string;\n templateName?: string;\n dynamicFields?: DynamicField[];\n themeProperties?: ThemeProperty[];\n /** Source template's default theme variant values (themePropertyId → value) */\n themeDefaultValues?: Record<string, string>;\n }\n): PageClipboardPayload {\n // 1) Re-ID the entire page subtree up-front. The clipboard always stores a fresh-ID copy\n // so that pasting (even into the SAME template) never collides with existing nodes.\n const { nodes: reIdedChildren, idMap } = reIdSubtree(page.children ?? []);\n const reIdedPage: CanvasPage = {\n id: generateId('page'),\n name: page.name,\n children: reIdedChildren,\n settings: { backgroundColor: '#ffffff', ...(page.settings ?? {}) },\n };\n\n // 2) Pick up dynamic fields whose mappings touch any element on this page; rewrite mapping ids.\n // Note: PAGE_BACKGROUND_ELEMENT_ID is in idMap (mapped to itself) so page-bg bindings survive.\n const carriedFields: DynamicField[] = [];\n for (const field of source.dynamicFields ?? []) {\n const survivors = rewriteFieldMappings(field.mappings, idMap);\n if (survivors.length > 0) {\n carriedFields.push({ ...field, mappings: survivors });\n }\n }\n\n // 3) Pick up theme properties referencing elements on this page; carry their default-variant value too.\n const carriedTheme: CarriedThemeProperty[] = [];\n for (const prop of source.themeProperties ?? []) {\n if (!idMap.has(prop.elementId)) continue;\n carriedTheme.push({\n property: { ...prop, elementId: idMap.get(prop.elementId)! },\n defaultValue: source.themeDefaultValues?.[prop.id],\n });\n }\n\n const nodeMeta = countNodes(reIdedPage.children ?? []);\n const payload: PageClipboardPayload = {\n version: PAGE_CLIPBOARD_VERSION,\n copiedAt: new Date().toISOString(),\n sourceTemplateId: source.templateId,\n sourceTemplateName: source.templateName,\n // JSON round-trip to fully detach from live store references.\n page: JSON.parse(JSON.stringify(reIdedPage)),\n dynamicFields: JSON.parse(JSON.stringify(carriedFields)),\n themeProperties: JSON.parse(JSON.stringify(carriedTheme)),\n meta: {\n ...nodeMeta,\n fieldCount: carriedFields.length,\n themePropertyCount: carriedTheme.length,\n },\n };\n try {\n localStorage.setItem(PAGE_CLIPBOARD_KEY, JSON.stringify(payload));\n } catch (err) {\n console.warn('[pageClipboard] failed to persist:', err);\n }\n return payload;\n}\n\n// ---------------------------------------------------------------------------\n// Read / clear\n// ---------------------------------------------------------------------------\n\n/** Read the current clipboard payload, or null if empty/invalid. */\nexport function readPageClipboard(): PageClipboardPayload | null {\n try {\n const raw = localStorage.getItem(PAGE_CLIPBOARD_KEY);\n if (!raw) return null;\n const parsed = JSON.parse(raw) as PageClipboardPayload;\n if (!parsed || parsed.version !== PAGE_CLIPBOARD_VERSION || !parsed.page) return null;\n // v2 payloads always have these arrays, but be defensive in case the shape drifts.\n parsed.dynamicFields = parsed.dynamicFields ?? [];\n parsed.themeProperties = parsed.themeProperties ?? [];\n return parsed;\n } catch {\n return null;\n }\n}\n\n/** Clear the clipboard. */\nexport function clearPageClipboard(): void {\n try { localStorage.removeItem(PAGE_CLIPBOARD_KEY); } catch { /* noop */ }\n}\n","import { create } from 'zustand';\nimport { \n CanvasElement, \n CanvasState, \n CanvasNode, \n GroupNode,\n Position, \n Tool, \n CanvasPage,\n ProjectSettings,\n PageSettings,\n DynamicField,\n FieldGroup,\n FieldMapping,\n GroupLayoutMode,\n ThemeConfig,\n ThemeProperty,\n ThemeVariant,\n createDefaultElement,\n createDefaultGroup,\n createDynamicField,\n createEmptyThemeConfig,\n generateId,\n isGroup,\n isElement,\n flattenChildren,\n findNodeById,\n findParentGroup,\n updateNodeInTree,\n removeNodeFromTree,\n addNodeToTree,\n moveNodeInTree,\n getAllElementIds,\n isStackLayoutMode,\n} from '@/types/editor';\nimport { getNodeBounds, getNodeBoundsFromChildren, getAbsoluteBounds, constrainChildrenToGroupBounds, reflowPageFromRoot, reflowStackGroup } from '@/lib/layoutEngine';\nimport { clearMeasurementCache } from '@/lib/textMeasurement';\nimport { reIdSubtree, rewriteFieldMappings } from '@/lib/pageClipboard';\n\nconst defaultProjectSettings: ProjectSettings = {\n showGrid: false,\n snapToGrid: false,\n gridSize: 20,\n snapToGuides: true,\n snapThreshold: 5,\n};\n\nconst defaultPageSettings: PageSettings = {\n backgroundColor: '#ffffff',\n};\n\nconst createDefaultPage = (id: string, name: string): CanvasPage => ({\n id,\n name,\n children: [],\n settings: { ...defaultPageSettings },\n});\n\n// Reference to the Fabric canvas for PDF export\nlet fabricCanvasRef: import('fabric').Canvas | null = null;\n\nexport const setFabricCanvasRef = (canvas: import('fabric').Canvas | null) => {\n fabricCanvasRef = canvas;\n};\n\nexport const getFabricCanvasRef = () => fabricCanvasRef;\n\ninterface EditorState {\n canvas: CanvasState;\n /** Bumped on updateNode/updateElement so canvas sync effect runs when panel changes something */\n canvasUpdateVersion: number;\n activeTool: Tool;\n clipboard: CanvasNode[];\n collapsedGroups: Set<string>; // UI state for collapsed groups in layers panel\n showDynamicLabels: boolean;\n showSections: boolean; // Show section highlights on canvas\n hoveredGroupId: string | null; // Group ID being hovered in layers panel\n\n // Undo/redo\n history: CanvasState[];\n historyIndex: number;\n lastCommittedSignature: string;\n\n // Selectors (computed from pages)\n getCurrentPage: () => CanvasPage;\n getCurrentChildren: () => CanvasNode[];\n getCurrentElements: () => CanvasElement[]; // Flattened elements for Fabric.js\n\n // Actions\n setActiveTool: (tool: Tool) => void;\n setShowDynamicLabels: (show: boolean) => void;\n setShowSections: (show: boolean) => void;\n setHoveredGroupId: (groupId: string | null) => void;\n \n // Node operations (works for both elements and groups)\n addNode: (node: CanvasNode, parentId?: string | null, index?: number) => void;\n addElement: (element: CanvasElement, parentId?: string | null) => void;\n updateNode: (id: string, updates: Partial<CanvasNode>, options?: { recordHistory?: boolean; skipLayoutRecalc?: boolean }) => void;\n updateElement: (id: string, updates: Partial<CanvasElement>, options?: { recordHistory?: boolean; skipLayoutRecalc?: boolean; skipStackReflow?: boolean }) => void;\n deleteNodes: (ids: string[]) => void;\n deleteElements: (ids: string[]) => void;\n \n // Selection\n selectElements: (ids: string[], addToSelection?: boolean, expandGroups?: boolean) => void;\n clearSelection: () => void;\n \n // Canvas\n setZoom: (zoom: number) => void;\n setPan: (pan: Position) => void;\n setCanvasSize: (width: number, height: number) => void;\n // Z-order (now just reordering in children array)\n bringForward: (id: string) => void;\n sendBackward: (id: string) => void;\n moveNodeToIndex: (nodeId: string, parentId: string | null, newIndex: number) => void;\n \n // Clipboard\n copyElements: (ids: string[]) => void;\n cutElements: (ids: string[]) => void;\n pasteElements: (targetParentId?: string | null) => void;\n duplicateElements: (ids: string[]) => void;\n addEntryToStackGroup: (groupId: string) => void; // Add new entry (subgroup) to vertical-stack/horizontal-stack group\n duplicateEntryInStackGroup: (groupId: string, entryId: string) => void; // Duplicate entry as sibling in stack group\n \n // Element properties\n toggleElementVisibility: (id: string) => void;\n toggleElementLock: (id: string) => void;\n setGroupVisibility: (groupId: string, visible: boolean) => void; // Set visibility for group and all children\n \n // Form rendering (Use Template page style)\n setFormRenderPreset: (preset: string | undefined) => void;\n \n // Form binding mode\n setFormBindingMode: (mode: 'dynamic' | 'preset' | undefined, formDefId?: string, formDefName?: string) => void;\n\n // Dynamic Fields (centralized field management)\n addDynamicField: (field: DynamicField) => void;\n updateDynamicField: (id: string, updates: Partial<DynamicField>) => void;\n removeDynamicField: (id: string) => void;\n addFieldMapping: (fieldId: string, mapping: FieldMapping) => void;\n removeFieldMapping: (fieldId: string, elementId: string) => void;\n reorderFields: (fieldIds: string[]) => void;\n getDynamicFieldById: (id: string) => DynamicField | undefined;\n getFieldsForElement: (elementId: string) => DynamicField[];\n \n // Field Groups\n addFieldGroup: (group: FieldGroup) => void;\n updateFieldGroup: (id: string, updates: Partial<FieldGroup>) => void;\n removeFieldGroup: (id: string) => void;\n reorderFieldGroups: (groupIds: string[]) => void;\n \n // Theme system\n addThemeProperty: (property: ThemeProperty, currentValue: string) => void;\n updateThemeProperty: (propertyId: string, updates: Partial<ThemeProperty>) => void;\n removeThemeProperty: (propertyId: string) => void;\n addThemeVariant: (variant: ThemeVariant) => void;\n updateThemeVariant: (variantId: string, updates: Partial<ThemeVariant>) => void;\n removeThemeVariant: (variantId: string) => void;\n setThemeConfig: (config: ThemeConfig) => void;\n syncDefaultThemeProperty: (propertyId: string, value: string) => void;\n applyThemeAsOriginal: (variantId: string) => void;\n \n // Grouping\n groupNodes: (ids: string[], name?: string) => void;\n addEmptyGroup: (name?: string) => void;\n ungroupNodes: (groupId: string) => void;\n renameNode: (id: string, name: string) => void;\n moveNodeToGroup: (nodeId: string, groupId: string | null, index?: number) => void;\n toggleGroupCollapse: (groupId: string) => void;\n \n // Convenience aliases (element/group specific naming)\n groupElements: (ids: string[], name?: string) => void;\n ungroupElements: (groupId: string) => void;\n renameGroup: (groupId: string, name: string) => void;\n renameElement: (elementId: string, name: string) => void;\n \n // Settings\n updateProjectSettings: (settings: Partial<ProjectSettings>) => void;\n /** Set the default PDF text rendering mode for this template. */\n setPdfTextMode: (mode: 'auto' | 'selectable' | 'pixel-perfect') => void;\n\n // Page management\n addPage: () => void;\n /** Add a new page and copy all elements/groups marked \"Static on new page\" from the current page. */\n addPageWithStaticElements: () => void;\n deletePage: (pageId: string) => void;\n duplicatePage: (pageId: string) => void;\n /**\n * Paste a clipboard payload after the current page. Inserts the page (already re-IDed),\n * merges carried dynamic fields (reuse on exact id+type match, otherwise suffix to a fresh id),\n * and adds carried theme properties to ALL existing variants. Returns the new page id.\n */\n pastePage: (payload: import('@/lib/pageClipboard').PageClipboardPayload) => string | null;\n renamePage: (pageId: string, name: string) => void;\n setCurrentPage: (pageId: string) => void;\n reorderPages: (fromIndex: number, toIndex: number) => void;\n updatePageSettings: (pageId: string, settings: Partial<PageSettings>) => void;\n setPageBoundRepeatablePage: (pageId: string, repeatablePageId: string | undefined) => void;\n moveElementsToPage: (elementIds: string[], targetPageId: string) => void;\n moveElementsToPageWithPositions: (\n elementIds: string[],\n targetPageId: string,\n positionsById: Record<string, { left: number; top: number }>\n ) => void;\n \n // Reorder (used by AI operations)\n reorderElements: (pageId: string, orderedIds: string[]) => void;\n\n // Import/Load config\n loadConfig: (config: import('@/types/editor').TemplateConfig) => void;\n\n // Run full reflow on current page and apply to store (e.g. after fonts ready so group auto dimensions are correct)\n applyReflowToCurrentPage: () => void;\n /** Run vertical stack reflow for a group on a given page (e.g. after persisting section children so siblings shift). */\n reflowStackGroupInPage: (pageId: string, groupId: string) => void;\n\n // Reset canvas to initial state\n resetCanvas: () => void;\n\n commitHistory: () => void;\n undo: () => void;\n redo: () => void;\n}\n\nconst defaultPageId = 'page-1';\nconst defaultPage = createDefaultPage(defaultPageId, 'Page 1');\n\nconst initialCanvas: CanvasState = {\n width: 595,\n height: 842,\n pages: [defaultPage],\n currentPageId: defaultPageId,\n selectedIds: [],\n zoom: 1,\n pan: { x: 0, y: 0 },\n projectSettings: { ...defaultProjectSettings },\n dynamicFields: [],\n fieldGroups: [], // Groups are created on-demand by user\n formRenderPreset: undefined,\n formBindingMode: undefined,\n boundFormDefId: undefined,\n boundFormDefName: undefined,\n};\n\n// Helper function to deep clone a node with new unique IDs for all nested children\nconst cloneNodeWithNewIds = (node: CanvasNode): CanvasNode => {\n if (isGroup(node)) {\n return {\n ...node,\n id: generateId('group'),\n children: node.children.map(cloneNodeWithNewIds),\n };\n }\n // For elements, generate new ID based on type\n const prefix = node.type === 'text' ? 'text' : node.type === 'image' ? 'img' : node.type === 'shape' ? 'shape' : 'line';\n return {\n ...node,\n id: generateId(prefix),\n };\n};\n\n// Old cloneNode kept for backward compatibility (doesn't regenerate IDs)\nconst cloneNode = (node: CanvasNode): CanvasNode => {\n if (isGroup(node)) {\n return {\n ...node,\n children: node.children.map(cloneNode),\n };\n }\n return { ...node };\n};\n\nconst cloneCanvas = (canvas: CanvasState): CanvasState => ({\n width: canvas.width,\n height: canvas.height,\n zoom: canvas.zoom,\n pan: { ...canvas.pan },\n selectedIds: [...canvas.selectedIds],\n pages: canvas.pages.map((page) => ({\n ...page,\n children: page.children.map(cloneNode),\n settings: { ...page.settings },\n })),\n currentPageId: canvas.currentPageId,\n projectSettings: { ...canvas.projectSettings },\n dynamicFields: canvas.dynamicFields.map(f => {\n // Handle both new format (mappings) and old format (elementIds)\n if (f.mappings && Array.isArray(f.mappings)) {\n // New format: clone mappings array\n return { ...f, mappings: [...f.mappings] };\n } else if ((f as any).elementIds && Array.isArray((f as any).elementIds)) {\n // Old format: preserve elementIds\n return { ...f, elementIds: [...(f as any).elementIds] };\n } else {\n // Fallback: ensure mappings exists as empty array\n return { ...f, mappings: [] };\n }\n }),\n fieldGroups: canvas.fieldGroups.map(g => ({ ...g })),\n formRenderPreset: canvas.formRenderPreset,\n formBindingMode: canvas.formBindingMode,\n boundFormDefId: canvas.boundFormDefId,\n boundFormDefName: canvas.boundFormDefName,\n themeConfig: canvas.themeConfig ? {\n properties: canvas.themeConfig.properties.map(p => ({ ...p })),\n variants: canvas.themeConfig.variants.map(v => ({ ...v, values: { ...v.values } })),\n } : undefined,\n pdfTextMode: canvas.pdfTextMode,\n});\n\nconst sameIdSet = (a: string[], b: string[]): boolean => {\n if (a.length !== b.length) return false;\n const setA = new Set(a);\n for (const id of b) {\n if (!setA.has(id)) return false;\n }\n return true;\n};\n\nconst canvasSignature = (canvas: CanvasState) =>\n JSON.stringify({\n width: canvas.width,\n height: canvas.height,\n zoom: canvas.zoom,\n pan: canvas.pan,\n pages: canvas.pages,\n currentPageId: canvas.currentPageId,\n });\n\nconst MAX_HISTORY = 100;\n\n/** Timeout for deferred reflow after text-only panel edits. 0 = run on next tick for document-like responsiveness (no overlap). */\nlet deferredTextReflowTimeoutId: ReturnType<typeof setTimeout> | null = null;\nconst DEFERRED_TEXT_REFLOW_MS = 0;\n\n/** When true, bypass debounce for text reflow so layout runs immediately while user is typing (Word-like). Set by PageCanvas on text:editing:entered/exited. */\nlet isEditingTextRef: { current: boolean } = { current: false };\nexport function setEditingText(value: boolean) {\n isEditingTextRef.current = value;\n}\n\nconst commitFromState = (state: Pick<EditorState, 'history' | 'historyIndex' | 'lastCommittedSignature'>, canvas: CanvasState) => {\n const signature = canvasSignature(canvas);\n if (signature === state.lastCommittedSignature) {\n return {\n history: state.history,\n historyIndex: state.historyIndex,\n lastCommittedSignature: state.lastCommittedSignature,\n };\n }\n\n const base = state.history.slice(0, state.historyIndex + 1);\n base.push(cloneCanvas(canvas));\n const trimmed = base.length > MAX_HISTORY ? base.slice(base.length - MAX_HISTORY) : base;\n\n return {\n history: trimmed,\n historyIndex: trimmed.length - 1,\n lastCommittedSignature: signature,\n };\n};\n\n// Helper to get current page from canvas state\nconst getCurrentPageFromCanvas = (canvas: CanvasState): CanvasPage => {\n return canvas.pages.find(p => p.id === canvas.currentPageId) || canvas.pages[0];\n};\n\n// Helper to update current page's children\nconst updateCurrentPageChildren = (\n canvas: CanvasState,\n updater: (children: CanvasNode[]) => CanvasNode[]\n): CanvasState => {\n const updatedPages = canvas.pages.map(p =>\n p.id === canvas.currentPageId\n ? { ...p, children: updater(p.children) }\n : p\n );\n return { ...canvas, pages: updatedPages };\n};\n\nconst reflowFlexOrGridAfterReorder = (canvas: CanvasState): CanvasState => canvas;\n\nconst applyReflowToCanvas = (canvas: CanvasState): CanvasState => canvas;\n\n/** Apply vertical stack reflow to a group (and recursively to nested stack subgroups). Returns new page children. */\nfunction applyStackReflowToGroup(pageChildren: CanvasNode[], groupId: string): CanvasNode[] {\n const group = findNodeById(pageChildren, groupId) as GroupNode | null;\n if (!group || !isGroup(group) || !isStackLayoutMode(group.layoutMode)) return pageChildren;\n let next = pageChildren;\n // Reflow nested stack subgroups first so their bounds and positions are correct before we reflow this group\n const kids = group.children ?? [];\n for (const child of kids) {\n if (isGroup(child) && isStackLayoutMode(child.layoutMode)) {\n next = applyStackReflowToGroup(next, child.id);\n }\n }\n const groupAfter = findNodeById(next, groupId) as GroupNode | null;\n if (!groupAfter || !isGroup(groupAfter)) return next;\n const updates = reflowStackGroup(groupAfter, next, groupAfter.stackSpacing);\n if (updates.size === 0) return next;\n updates.forEach((u, id) => {\n next = updateNodeInTree(next, id, u);\n });\n return next;\n}\n\n// Page-space bounds for a root-level node (no parent). Used for paste/duplicate placement.\nconst getRootLevelBounds = (node: CanvasNode): { left: number; top: number; right: number; bottom: number } => {\n const b = getNodeBoundsFromChildren(node);\n if (isGroup(node)) {\n const l = node.left ?? 0;\n const t = node.top ?? 0;\n return { left: l + b.left, top: t + b.top, right: l + b.right, bottom: t + b.bottom };\n }\n return { left: b.left, top: b.top, right: b.right, bottom: b.bottom };\n};\n\nconst getBoundingBoxOfRoots = (nodes: CanvasNode[]): { left: number; top: number; right: number; bottom: number } => {\n if (nodes.length === 0) return { left: 0, top: 0, right: 0, bottom: 0 };\n const first = getRootLevelBounds(nodes[0]);\n let left = first.left, top = first.top, right = first.right, bottom = first.bottom;\n for (let i = 1; i < nodes.length; i++) {\n const b = getRootLevelBounds(nodes[i]);\n left = Math.min(left, b.left);\n top = Math.min(top, b.top);\n right = Math.max(right, b.right);\n bottom = Math.max(bottom, b.bottom);\n }\n return { left, top, right, bottom };\n};\n\nconst shiftNodeBy = (node: CanvasNode, dx: number, dy: number): CanvasNode => {\n if (isElement(node)) {\n return { ...node, left: (node.left ?? 0) + dx, top: (node.top ?? 0) + dy };\n }\n const g = node as GroupNode;\n return {\n ...g,\n left: (g.left ?? 0) + dx,\n top: (g.top ?? 0) + dy,\n children: g.children.map((c) => shiftNodeBy(c, dx, dy)),\n };\n};\n\nexport const useEditorStore = create<EditorState>((set, get) => ({\n canvas: initialCanvas,\n canvasUpdateVersion: 0,\n activeTool: 'select',\n clipboard: [],\n collapsedGroups: new Set(),\n showDynamicLabels: false,\n showSections: false,\n hoveredGroupId: null,\n\n history: [cloneCanvas(initialCanvas)],\n historyIndex: 0,\n lastCommittedSignature: canvasSignature(initialCanvas),\n\n // Selectors\n getCurrentPage: () => getCurrentPageFromCanvas(get().canvas),\n getCurrentChildren: () => getCurrentPageFromCanvas(get().canvas).children,\n getCurrentElements: () => flattenChildren(getCurrentPageFromCanvas(get().canvas).children),\n\n setActiveTool: (tool) => set({ activeTool: tool }),\n setShowDynamicLabels: (show) => set({ showDynamicLabels: show }),\n setShowSections: (show) => set({ showSections: show }),\n setHoveredGroupId: (groupId) => set({ hoveredGroupId: groupId }),\n\n setFormRenderPreset: (preset) =>\n set((state) => {\n const nextCanvas: CanvasState = { ...state.canvas, formRenderPreset: preset || undefined };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n setFormBindingMode: (mode, formDefId, formDefName) =>\n set((state) => {\n const nextCanvas: CanvasState = {\n ...state.canvas,\n formBindingMode: mode,\n boundFormDefId: formDefId,\n boundFormDefName: formDefName,\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n commitHistory: () =>\n set((state) => {\n const committed = commitFromState(state, state.canvas);\n return committed;\n }),\n\n undo: () =>\n set((state) => {\n if (state.historyIndex <= 0) return {};\n const nextIndex = state.historyIndex - 1;\n // Restore canvas exactly from history; do not re-run reflow so we keep the committed\n // dimensions (Fabric-based text heights, auto group heights) and avoid \"heighted\" sections.\n const nextCanvas = cloneCanvas(state.history[nextIndex]);\n return {\n canvas: nextCanvas,\n historyIndex: nextIndex,\n lastCommittedSignature: canvasSignature(nextCanvas),\n canvasUpdateVersion: state.canvasUpdateVersion + 1,\n };\n }),\n\n redo: () =>\n set((state) => {\n if (state.historyIndex >= state.history.length - 1) return {};\n const nextIndex = state.historyIndex + 1;\n const nextCanvas = cloneCanvas(state.history[nextIndex]);\n return {\n canvas: nextCanvas,\n historyIndex: nextIndex,\n lastCommittedSignature: canvasSignature(nextCanvas),\n canvasUpdateVersion: state.canvasUpdateVersion + 1,\n };\n }),\n\n // === NODE OPERATIONS ===\n \n addNode: (node, parentId = null, index) =>\n set((state) => {\n let nextCanvas = updateCurrentPageChildren(state.canvas, (children) =>\n addNodeToTree(children, node, parentId, index)\n );\n nextCanvas.selectedIds = [node.id];\n const committed = commitFromState(state, nextCanvas);\n const out = { canvas: nextCanvas, ...committed };\n return out;\n }),\n\n addElement: (element, parentId = null) =>\n set((state) => {\n let elementToAdd = element;\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const pageChildren = currentPage?.children ?? [];\n if (parentId == null) {\n const PAGE_MARGIN = 48;\n const PAGE_GAP = 16;\n let maxBottom = PAGE_MARGIN;\n for (const node of pageChildren) {\n const b = getNodeBounds(node, pageChildren);\n if (b.bottom > maxBottom) maxBottom = b.bottom;\n }\n let newTop = maxBottom + PAGE_GAP;\n // Clamp top so the element stays visible within the canvas\n const pageHeight = state.canvas.height ?? 842;\n const elHeight = element.height ?? 50;\n const maxAllowedTop = Math.max(PAGE_MARGIN, pageHeight - elHeight - PAGE_MARGIN);\n if (newTop > maxAllowedTop) {\n newTop = Math.min(PAGE_MARGIN, maxAllowedTop);\n }\n elementToAdd = { ...element, left: PAGE_MARGIN, top: newTop };\n } else {\n const parent = findNodeById(pageChildren, parentId) as GroupNode | null;\n if (parent && isGroup(parent) && isStackLayoutMode(parent.layoutMode)) {\n elementToAdd = { ...elementToAdd, left: 0, top: 0 };\n }\n }\n let nextCanvas = updateCurrentPageChildren(state.canvas, (children) =>\n addNodeToTree(children, elementToAdd, parentId)\n );\n nextCanvas.selectedIds = [elementToAdd.id];\n const committed = commitFromState(state, nextCanvas);\n const out = { canvas: nextCanvas, ...committed };\n return out;\n }),\n\n updateNode: (id, updates, options) =>\n set((state) => {\n const mergedUpdates = { ...updates };\n let nextCanvas = updateCurrentPageChildren(state.canvas, (children) =>\n updateNodeInTree(children, id, mergedUpdates)\n );\n\n // When group width/height changes, constrain children to content box (div-like: wrap inside) and reflow\n const groupSizeChanged = (updates.width !== undefined || updates.height !== undefined) && !options?.skipLayoutRecalc;\n if (groupSizeChanged) {\n const currentPage = nextCanvas.pages.find((p) => p.id === nextCanvas.currentPageId);\n if (currentPage) {\n let updatedGroup = findNodeById(currentPage.children, id);\n if (updatedGroup && isGroup(updatedGroup)) {\n // Ensure group has explicit left/top (like a div) so contentBox is correct and children stay in place\n const g = updatedGroup as GroupNode;\n const pageChildrenForBounds = currentPage.children;\n if (g.left === undefined || g.top === undefined) {\n const b = getNodeBounds(g, pageChildrenForBounds);\n nextCanvas = updateCurrentPageChildren(nextCanvas, (children) =>\n updateNodeInTree(children, id, { left: b.left, top: b.top })\n );\n const pageAfter = nextCanvas.pages.find((p) => p.id === nextCanvas.currentPageId);\n updatedGroup = pageAfter ? findNodeById(pageAfter.children, id) : updatedGroup;\n }\n const childUpdates = constrainChildrenToGroupBounds(updatedGroup as GroupNode, pageChildrenForBounds);\n if (childUpdates.size > 0) {\n nextCanvas = updateCurrentPageChildren(nextCanvas, (children) => {\n let c = children;\n childUpdates.forEach((u, nodeId) => {\n c = updateNodeInTree(c, nodeId, u);\n });\n return c;\n });\n // Recursively constrain nested groups (child groups that got a new width)\n let nestedUpdates = childUpdates;\n while (nestedUpdates.size > 0) {\n const nextPage = nextCanvas.pages.find((p) => p.id === nextCanvas.currentPageId)!;\n const nextPageChildren = nextPage.children;\n const nextNested = new Map<string, Partial<CanvasElement> & Partial<GroupNode>>();\n nestedUpdates.forEach((_u, nodeId) => {\n const node = findNodeById(nextPageChildren, nodeId);\n if (node && isGroup(node)) {\n const sub = constrainChildrenToGroupBounds(node as GroupNode, nextPageChildren);\n sub.forEach((up, id) => nextNested.set(id, up));\n }\n });\n if (nextNested.size === 0) break;\n nestedUpdates = nextNested;\n nextCanvas = updateCurrentPageChildren(nextCanvas, (children) => {\n let c = children;\n nextNested.forEach((u, nodeId) => {\n c = updateNodeInTree(c, nodeId, u);\n });\n return c;\n });\n }\n }\n }\n }\n }\n\n // When group is set to stack layout, normalize children to chain-relative (top 0, left = first's left) so subgroups align.\n const nextLayoutMode = (updates as Partial<GroupNode>).layoutMode;\n if (nextLayoutMode && isStackLayoutMode(nextLayoutMode)) {\n const currentPage = nextCanvas.pages.find((p) => p.id === nextCanvas.currentPageId);\n const group = currentPage ? (findNodeById(currentPage.children, id) as GroupNode | null) : null;\n if (currentPage && group && isGroup(group) && isStackLayoutMode(group.layoutMode)) {\n const kids = group.children ?? [];\n const gap = group.stackSpacing ?? 8;\n const pageChildren = currentPage.children;\n if (kids.length > 0) {\n // Sort by effective top (use absolute for consistent order when stored tops differ)\n const sortedKids = [...kids].sort(\n (a, b) => getAbsoluteBounds(a, pageChildren).top - getAbsoluteBounds(b, pageChildren).top\n );\n let next = updateNodeInTree(currentPage.children, id, { children: sortedKids });\n const groupSorted = findNodeById(next, id) as GroupNode;\n const orderedKids = groupSorted?.children ?? sortedKids;\n const firstLeft = typeof orderedKids[0]?.left === 'number' ? orderedKids[0].left : 0;\n let prevBottom = 0;\n for (let i = 0; i < orderedKids.length; i++) {\n const child = orderedKids[i];\n const currentTop = typeof child.top === 'number' ? child.top : 0;\n const height = getNodeBounds(child, next).height;\n if (i === 0) {\n prevBottom = currentTop + height;\n continue;\n }\n const storedTop = Math.max(0, currentTop - prevBottom - gap);\n next = updateNodeInTree(next, child.id, { top: storedTop, left: firstLeft });\n prevBottom = currentTop + height;\n }\n // Recursively reflow nested stack subgroups (e.g. Content with Title inside)\n next = applyStackReflowToGroup(next, id);\n nextCanvas = updateCurrentPageChildren(nextCanvas, () => next);\n }\n }\n }\n\n if (options?.recordHistory === false) {\n return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1 };\n }\n\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };\n }),\n\n updateElement: (id, updates, options) =>\n set((state) => {\n let nextCanvas = updateCurrentPageChildren(state.canvas, (children) =>\n updateNodeInTree(children, id, updates)\n );\n\n // When any text/font/word-wrap property changes on a text element, persist measured height so\n // flex layout reflows (siblings reposition) and store stays in sync with Fabric textbox bounds\n const textRelatedProps = [\n 'text', 'fontSize', 'lineHeight', 'width', 'fontFamily', 'fontWeight',\n 'fontStyle', 'charSpacing', 'textAlign', 'splitByGrapheme', 'wordWrap',\n 'underline', 'linethrough',\n ];\n const textRelatedChange = textRelatedProps.some(prop => prop in updates);\n // When text-related props change, only persist height/width when caller provided them (e.g. from Fabric).\n // Do not overwrite with manual measurement - use Fabric bounds only.\n if (textRelatedChange && typeof updates.height === 'number') {\n nextCanvas = updateCurrentPageChildren(nextCanvas, (children) =>\n updateNodeInTree(children, id, { height: updates.height as number })\n );\n }\n\n // Check if this update affects layout (size/height/position or any text property that changes bounds)\n const layoutAffectingProps = [\n 'height', 'width', 'scaleX', 'scaleY', 'top', 'left',\n 'text', 'fontSize', 'lineHeight', 'fontFamily', 'fontWeight',\n 'fontStyle', 'charSpacing', 'textAlign', 'splitByGrapheme', 'wordWrap',\n 'underline', 'linethrough',\n ];\n const affectsLayout = layoutAffectingProps.some(prop => prop in updates);\n // Props that actually change size/position and should trigger stack reflow (reflow overwrites stored top for non-first children)\n const dimensionOrPositionProps = ['height', 'width', 'scaleX', 'scaleY', 'top', 'left'];\n const updatesDimensionOrPosition = dimensionOrPositionProps.some(prop => prop in updates);\n // Stack groups: reflow only when dimension/position changed; skip when caller says so (e.g. Fabric sync after font/size/weight change so top is not reset)\n const shouldReflowStack = affectsLayout && updatesDimensionOrPosition && !options?.skipStackReflow && !Object.keys(updates).every(k => k === 'left' || k === 'top');\n if (shouldReflowStack) {\n const currentPage = nextCanvas.pages.find((p) => p.id === nextCanvas.currentPageId);\n if (currentPage) {\n const parent = findParentGroup(currentPage.children, id);\n if (parent && isGroup(parent) && isStackLayoutMode(parent.layoutMode)) {\n const reflowed = applyStackReflowToGroup(currentPage.children, parent.id);\n nextCanvas = updateCurrentPageChildren(nextCanvas, () => reflowed);\n }\n }\n }\n // When user edits only left/top from the panel, don't run layout recalc or we overwrite their manual position\n const positionOnlyEdit = Object.keys(updates).every(k => k === 'left' || k === 'top');\n // Text-only from panel: skip heavy reflow so canvas updates instantly; run reflow after a short delay\n const onlyTextChange = affectsLayout && Object.keys(updates).every(k => k === 'text');\n if (onlyTextChange && options?.recordHistory !== false && !options?.skipLayoutRecalc) {\n if (isEditingTextRef.current) {\n get().applyReflowToCurrentPage();\n } else {\n clearTimeout(deferredTextReflowTimeoutId ?? undefined);\n deferredTextReflowTimeoutId = setTimeout(() => {\n get().applyReflowToCurrentPage();\n deferredTextReflowTimeoutId = null;\n }, DEFERRED_TEXT_REFLOW_MS);\n }\n }\n if (options?.recordHistory === false) {\n return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1 };\n }\n\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };\n }),\n\n deleteNodes: (ids) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n let nextChildren = currentPage.children;\n const rootLevelIds = new Set(currentPage.children.map((c) => c.id));\n\n // Collect ALL element IDs being deleted (including children of deleted groups)\n const allDeletedIds = new Set<string>();\n for (const id of ids) {\n allDeletedIds.add(id);\n const node = findNodeById(currentPage.children, id);\n if (node && isGroup(node)) {\n getAllElementIds(node.children).forEach(eid => allDeletedIds.add(eid));\n }\n }\n\n let deletedAnyRootLevel = false;\n for (const id of ids) {\n if (rootLevelIds.has(id)) deletedAnyRootLevel = true;\n nextChildren = removeNodeFromTree(nextChildren, id);\n }\n\n let nextCanvas = updateCurrentPageChildren(state.canvas, () => nextChildren);\n nextCanvas.selectedIds = state.canvas.selectedIds.filter((id) => !ids.includes(id));\n\n // Clean up theme properties for deleted elements\n if (nextCanvas.themeConfig) {\n const remainingProps = nextCanvas.themeConfig.properties.filter(p => !allDeletedIds.has(p.elementId));\n if (remainingProps.length !== nextCanvas.themeConfig.properties.length) {\n const removedPropIds = new Set(\n nextCanvas.themeConfig.properties.filter(p => allDeletedIds.has(p.elementId)).map(p => p.id)\n );\n nextCanvas = {\n ...nextCanvas,\n themeConfig: {\n ...nextCanvas.themeConfig,\n properties: remainingProps,\n variants: nextCanvas.themeConfig.variants.map(v => {\n const values = { ...v.values };\n for (const pid of removedPropIds) delete values[pid];\n return { ...v, values };\n }),\n },\n };\n }\n }\n\n // Clean up dynamic fields for deleted elements\n if (nextCanvas.dynamicFields?.length) {\n nextCanvas = {\n ...nextCanvas,\n dynamicFields: nextCanvas.dynamicFields\n .map(f => ({\n ...f,\n mappings: (f.mappings ?? []).filter(m => !allDeletedIds.has(m.elementId)),\n }))\n .filter(f => (f.mappings ?? []).length > 0),\n };\n }\n\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n deleteElements: (ids) => get().deleteNodes(ids),\n\n selectElements: (ids, addToSelection = false, expandGroups = false) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const currentIds = state.canvas.selectedIds;\n\n // Expand selection to include all elements in the same group (only when expandGroups is true)\n const expandWithGroupMembers = (elementIds: string[]): string[] => {\n if (!expandGroups) return elementIds;\n \n const expandedIds = new Set<string>(elementIds);\n \n for (const id of elementIds) {\n const parent = findParentGroup(currentPage.children, id);\n if (parent) {\n // Add all element IDs in this group\n getAllElementIds(parent.children).forEach(elId => expandedIds.add(elId));\n }\n }\n \n return Array.from(expandedIds);\n };\n\n const expandedIds = expandWithGroupMembers(ids);\n\n if (addToSelection) {\n const newIds = expandedIds.filter((id) => !currentIds.includes(id));\n const removedIds = expandedIds.filter((id) => currentIds.includes(id));\n const finalIds = [...currentIds.filter((id) => !removedIds.includes(id)), ...newIds];\n const fullyExpandedIds = expandWithGroupMembers(finalIds);\n\n if (sameIdSet(fullyExpandedIds, currentIds)) return {};\n return { canvas: { ...state.canvas, selectedIds: fullyExpandedIds } };\n }\n\n if (sameIdSet(expandedIds, currentIds)) return {};\n return { canvas: { ...state.canvas, selectedIds: expandedIds } };\n }),\n\n clearSelection: () =>\n set((state) => (state.canvas.selectedIds.length ? { canvas: { ...state.canvas, selectedIds: [] } } : {})),\n\n updateProjectSettings: (settings) =>\n set((state) => {\n const nextCanvas: CanvasState = {\n ...state.canvas,\n projectSettings: { ...state.canvas.projectSettings, ...settings },\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n setPdfTextMode: (mode) =>\n set((state) => {\n if (state.canvas.pdfTextMode === mode) return {} as any;\n const nextCanvas: CanvasState = { ...state.canvas, pdfTextMode: mode };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n setZoom: (zoom) =>\n set((state) => ({\n canvas: { ...state.canvas, zoom: Math.max(0.1, Math.min(10, zoom)) },\n })),\n\n setPan: (pan) => set((state) => ({ canvas: { ...state.canvas, pan } })),\n\n setCanvasSize: (width, height) =>\n set((state) => {\n const nextCanvas: CanvasState = {\n ...state.canvas,\n width,\n height,\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n\n // === Z-ORDER (reordering in tree) ===\n \n bringForward: (id) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const parent = findParentGroup(currentPage.children, id);\n const siblings = parent ? parent.children : currentPage.children;\n const index = siblings.findIndex(n => n.id === id);\n \n if (index < siblings.length - 1) {\n const newSiblings = [...siblings];\n [newSiblings[index], newSiblings[index + 1]] = [newSiblings[index + 1], newSiblings[index]];\n \n let nextCanvas = updateCurrentPageChildren(state.canvas, (children) => {\n if (!parent) return newSiblings;\n return updateNodeInTree(children, parent.id, { children: newSiblings });\n });\n nextCanvas = reflowFlexOrGridAfterReorder(nextCanvas);\n if (parent && isGroup(parent) && isStackLayoutMode(parent.layoutMode)) {\n const page = nextCanvas.pages.find((p) => p.id === nextCanvas.currentPageId);\n if (page) {\n const reflowed = applyStackReflowToGroup(page.children, parent.id);\n nextCanvas = updateCurrentPageChildren(nextCanvas, () => reflowed);\n }\n }\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };\n }\n return {};\n }),\n\n sendBackward: (id) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const parent = findParentGroup(currentPage.children, id);\n const siblings = parent ? parent.children : currentPage.children;\n const index = siblings.findIndex(n => n.id === id);\n \n if (index > 0) {\n const newSiblings = [...siblings];\n [newSiblings[index], newSiblings[index - 1]] = [newSiblings[index - 1], newSiblings[index]];\n \n let nextCanvas = updateCurrentPageChildren(state.canvas, (children) => {\n if (!parent) return newSiblings;\n return updateNodeInTree(children, parent.id, { children: newSiblings });\n });\n nextCanvas = reflowFlexOrGridAfterReorder(nextCanvas);\n if (parent && isGroup(parent) && isStackLayoutMode(parent.layoutMode)) {\n const page = nextCanvas.pages.find((p) => p.id === nextCanvas.currentPageId);\n if (page) {\n const reflowed = applyStackReflowToGroup(page.children, parent.id);\n nextCanvas = updateCurrentPageChildren(nextCanvas, () => reflowed);\n }\n }\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };\n }\n return {};\n }),\n\n moveNodeToIndex: (nodeId, parentId, newIndex) =>\n set((state) => {\n let nextCanvas = updateCurrentPageChildren(state.canvas, (children) =>\n moveNodeInTree(children, nodeId, parentId, newIndex)\n );\n \n nextCanvas = reflowFlexOrGridAfterReorder(nextCanvas);\n\n // Stack groups: store chain-relative positions; set left/top to 0 when moving into a stack group\n if (parentId) {\n const currentPage = nextCanvas.pages.find((p) => p.id === nextCanvas.currentPageId);\n if (currentPage) {\n const parent = findNodeById(currentPage.children, parentId) as GroupNode | null;\n if (parent && isGroup(parent) && isStackLayoutMode(parent.layoutMode)) {\n nextCanvas = updateCurrentPageChildren(nextCanvas, (children) =>\n updateNodeInTree(children, nodeId, { left: 0, top: 0 })\n );\n }\n }\n }\n\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };\n }),\n\n // === CLIPBOARD ===\n \n copyElements: (ids) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const nodesToCopy: CanvasNode[] = [];\n \n for (const id of ids) {\n const node = findNodeById(currentPage.children, id);\n if (node) nodesToCopy.push(cloneNode(node));\n }\n \n return { clipboard: nodesToCopy };\n }),\n\n cutElements: (ids) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const nodesToCut: CanvasNode[] = [];\n \n for (const id of ids) {\n const node = findNodeById(currentPage.children, id);\n if (node) nodesToCut.push(cloneNode(node));\n }\n \n let nextChildren = currentPage.children;\n for (const id of ids) {\n nextChildren = removeNodeFromTree(nextChildren, id);\n }\n \n const nextCanvas = updateCurrentPageChildren(state.canvas, () => nextChildren);\n nextCanvas.selectedIds = [];\n \n const committed = commitFromState(state, nextCanvas);\n return { \n canvas: nextCanvas, \n clipboard: nodesToCut,\n ...committed \n };\n }),\n\n pasteElements: (targetParentId = null) =>\n set((state) => {\n if (state.clipboard.length === 0) return {};\n \n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const targetParent = targetParentId ? findNodeById(currentPage.children, targetParentId) : null;\n\n const timestamp = Date.now();\n const cloneWithNewIds = (node: CanvasNode, index: number, posOffset: number): CanvasNode => {\n const newId = `${node.id}-paste-${timestamp}-${index}`;\n if (isGroup(node)) {\n return {\n ...node,\n id: newId,\n left: (node.left ?? 0) + posOffset,\n top: (node.top ?? 0) + posOffset,\n children: node.children.map((child, i) => cloneWithNewIds(child, i, 0)),\n };\n }\n return {\n ...node,\n id: newId,\n left: (node.left ?? 0) + posOffset,\n top: (node.top ?? 0) + posOffset,\n };\n };\n \n let newNodes = state.clipboard.map((node, i) => cloneWithNewIds(node, i, 0));\n const isPastingIntoStack = targetParent && isGroup(targetParent) && isStackLayoutMode(targetParent.layoutMode);\n if (isPastingIntoStack) {\n newNodes = newNodes.map((n) => ({ ...n, left: 0, top: 0 } as CanvasNode));\n } else {\n const PAGE_MARGIN = 48;\n const PAGE_GAP = 16;\n let maxBottom = PAGE_MARGIN;\n for (const node of currentPage.children) {\n const b = getNodeBounds(node, currentPage.children);\n if (b.bottom > maxBottom) maxBottom = b.bottom;\n }\n const bbox = getBoundingBoxOfRoots(newNodes);\n const shiftX = PAGE_MARGIN - bbox.left;\n const shiftY = maxBottom + PAGE_GAP - bbox.top;\n newNodes = newNodes.map((n) => shiftNodeBy(n, shiftX, shiftY));\n }\n\n let nextChildren = currentPage.children;\n for (const node of newNodes) {\n nextChildren = addNodeToTree(nextChildren, node, targetParentId);\n }\n \n let nextCanvas = updateCurrentPageChildren(state.canvas, () => nextChildren);\n nextCanvas.selectedIds = newNodes.map(n => n.id);\n\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n duplicateElements: (ids) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n let nextChildren = currentPage.children;\n const newNodes: CanvasNode[] = [];\n const duplicateAtPageLevel: string[] = []; // ids duplicated at page level (no flex parent)\n\n for (const id of ids) {\n const node = findNodeById(nextChildren, id);\n if (!node) continue;\n const parent = findParentGroup(nextChildren, id);\n let cloned = cloneNodeWithNewIds(node);\n if (parent && isGroup(parent) && isStackLayoutMode(parent.layoutMode)) {\n cloned = { ...cloned, left: 0, top: 0 } as CanvasNode;\n }\n duplicateAtPageLevel.push(cloned.id);\n newNodes.push(cloned);\n\n const parentId = parent ? parent.id : null;\n const index = parent\n ? parent.children.findIndex((c) => c.id === id)\n : nextChildren.findIndex((c) => c.id === id);\n const insertIndex = index >= 0 ? index + 1 : undefined;\n nextChildren = addNodeToTree(nextChildren, cloned, parentId, insertIndex);\n }\n\n // Place page-level duplicates below existing content so they never overlap (document-like)\n const pageLevelIds = new Set(duplicateAtPageLevel);\n if (pageLevelIds.size > 0) {\n const PAGE_MARGIN = 48;\n const PAGE_GAP = 16;\n let maxBottom = PAGE_MARGIN;\n for (const node of currentPage.children) {\n const b = getNodeBounds(node, currentPage.children);\n if (b.bottom > maxBottom) maxBottom = b.bottom;\n }\n const pageLevelClones = newNodes.filter((n) => pageLevelIds.has(n.id));\n const bbox = getBoundingBoxOfRoots(pageLevelClones);\n const shiftX = PAGE_MARGIN - bbox.left;\n const shiftY = maxBottom + PAGE_GAP - bbox.top;\n nextChildren = nextChildren.map((node) =>\n pageLevelIds.has(node.id) ? shiftNodeBy(node, shiftX, shiftY) : node\n );\n }\n\n let nextCanvas = updateCurrentPageChildren(state.canvas, () => nextChildren);\n nextCanvas.selectedIds = newNodes.map((n) => n.id);\n\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };\n }),\n\n addEntryToStackGroup: (_groupId) =>\n set(() => {\n // Stack/flex/grid layout removed; groups are plain Fabric groups\n return {};\n }),\n\n duplicateEntryInStackGroup: (_groupId, _entryId) =>\n set(() => {\n // Stack/flex/grid layout removed; groups are plain Fabric groups\n return {};\n }),\n\n // === ELEMENT PROPERTIES ===\n \n toggleElementVisibility: (id) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const node = findNodeById(currentPage.children, id);\n if (!node) return {};\n \n const newVisible = node.visible === false ? true : false;\n const nextCanvas = updateCurrentPageChildren(state.canvas, (children) =>\n updateNodeInTree(children, id, { visible: newVisible })\n );\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n toggleElementLock: (id) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const node = findNodeById(currentPage.children, id);\n if (!node || isGroup(node)) return {};\n \n const nextCanvas = updateCurrentPageChildren(state.canvas, (children) =>\n updateNodeInTree(children, id, { \n selectable: !node.selectable, \n evented: !node.evented \n })\n );\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n setGroupVisibility: (groupId, visible) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const group = findNodeById(currentPage.children, groupId) as GroupNode | null;\n if (!group || !isGroup(group)) return {};\n \n // Collect all node IDs to update (group + all children recursively, including nested groups)\n const nodeIds: string[] = [groupId];\n \n const collectChildren = (node: CanvasNode) => {\n // Add this node's ID\n nodeIds.push(node.id);\n \n // If it's a group, recursively collect all its children (elements and subgroups)\n if (isGroup(node)) {\n node.children.forEach(child => {\n collectChildren(child); // Recursive call for nested groups\n });\n }\n };\n \n // Start collecting from the group's direct children\n group.children.forEach(child => {\n collectChildren(child);\n });\n \n // Update all nodes in a single batch operation\n // Visibility changes shouldn't affect positions, so we update directly without triggering layout recalculation\n let nextCanvas = state.canvas;\n nodeIds.forEach(id => {\n nextCanvas = updateCurrentPageChildren(nextCanvas, (children) =>\n updateNodeInTree(children, id, { visible })\n );\n });\n \n // Don't commit history for visibility-only changes to avoid triggering unnecessary syncs\n // Visibility is a rendering property, not a layout property\n return { canvas: nextCanvas };\n }),\n\n // === DYNAMIC FIELDS (Centralized) ===\n \n addDynamicField: (field) =>\n set((state) => {\n // Check if field with same ID already exists - don't add duplicates\n const existingField = state.canvas.dynamicFields.find(f => f.id === field.id);\n if (existingField) {\n // Field already exists, don't add duplicate\n console.warn(`Dynamic field with ID \"${field.id}\" already exists`);\n return {};\n }\n \n const nextCanvas = {\n ...state.canvas,\n dynamicFields: [...state.canvas.dynamicFields, field],\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n updateDynamicField: (id, updates) =>\n set((state) => {\n const nextCanvas = {\n ...state.canvas,\n dynamicFields: state.canvas.dynamicFields.map(f =>\n f.id === id ? { ...f, ...updates } : f\n ),\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n removeDynamicField: (id) =>\n set((state) => {\n const nextCanvas = {\n ...state.canvas,\n dynamicFields: state.canvas.dynamicFields.filter(f => f.id !== id),\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n addFieldMapping: (fieldId, mapping) =>\n set((state) => {\n const nextCanvas = {\n ...state.canvas,\n dynamicFields: state.canvas.dynamicFields.map(f => {\n if (f.id !== fieldId) return f;\n const mappings = (f.mappings && Array.isArray(f.mappings)) ? f.mappings : [];\n // Avoid duplicate: same elementId + targetProperty\n if (mappings.some(m => m.elementId === mapping.elementId && m.targetProperty === mapping.targetProperty)) {\n return f;\n }\n return { ...f, mappings: [...mappings, mapping] };\n }),\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n removeFieldMapping: (fieldId, elementId) =>\n set((state) => {\n const nextCanvas = {\n ...state.canvas,\n dynamicFields: state.canvas.dynamicFields.map(f => {\n if (f.id !== fieldId) return f;\n // Handle both formats\n if (f.mappings && Array.isArray(f.mappings)) {\n return { ...f, mappings: f.mappings.filter(m => m.elementId !== elementId) };\n } else if ((f as any).elementIds && Array.isArray((f as any).elementIds)) {\n // Old format: remove from elementIds\n return { ...f, elementIds: (f as any).elementIds.filter((id: string) => id !== elementId) };\n } else {\n return f;\n }\n }),\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n reorderFields: (fieldIds) =>\n set((state) => {\n const fieldMap = new Map(state.canvas.dynamicFields.map(f => [f.id, f]));\n const reordered = fieldIds\n .map(id => fieldMap.get(id))\n .filter((f): f is DynamicField => f !== undefined)\n .map((f, i) => ({ ...f, order: i }));\n \n // Add any fields not in the list at the end\n const missingFields = state.canvas.dynamicFields\n .filter(f => !fieldIds.includes(f.id))\n .map((f, i) => ({ ...f, order: reordered.length + i }));\n \n const nextDynamicFields = [...reordered, ...missingFields];\n const nextCanvas = {\n ...state.canvas,\n dynamicFields: nextDynamicFields,\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };\n }),\n\n getDynamicFieldById: (id) => {\n return useEditorStore.getState().canvas.dynamicFields.find(f => f.id === id);\n },\n\n getFieldsForElement: (elementId) => {\n return useEditorStore.getState().canvas.dynamicFields.filter(f => {\n // Handle both formats\n if (f.mappings && Array.isArray(f.mappings)) {\n return f.mappings.some(m => m.elementId === elementId);\n } else if ((f as any).elementIds && Array.isArray((f as any).elementIds)) {\n // Old format: check elementIds\n return (f as any).elementIds.includes(elementId);\n }\n return false;\n });\n },\n\n // === FIELD GROUPS ===\n \n addFieldGroup: (group) =>\n set((state) => {\n // Check if group with same ID already exists - don't add duplicates\n const existingGroup = state.canvas.fieldGroups.find(g => g.id === group.id);\n if (existingGroup) {\n // Group already exists, don't add duplicate\n return {};\n }\n \n const nextCanvas = {\n ...state.canvas,\n fieldGroups: [...state.canvas.fieldGroups, group],\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n updateFieldGroup: (id, updates) =>\n set((state) => {\n const nextCanvas = {\n ...state.canvas,\n fieldGroups: state.canvas.fieldGroups.map(g =>\n g.id === id ? { ...g, ...updates } : g\n ),\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n removeFieldGroup: (id) =>\n set((state) => {\n // Also clear group reference from fields\n const nextCanvas = {\n ...state.canvas,\n fieldGroups: state.canvas.fieldGroups.filter(g => g.id !== id),\n dynamicFields: state.canvas.dynamicFields.map(f =>\n f.group === id ? { ...f, group: undefined } : f\n ),\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n reorderFieldGroups: (groupIds) =>\n set((state) => {\n const groupMap = new Map(state.canvas.fieldGroups.map(g => [g.id, g]));\n const reordered = groupIds\n .map(id => groupMap.get(id))\n .filter((g): g is FieldGroup => g !== undefined)\n .map((g, i) => ({ ...g, order: i }));\n \n const missingGroups = state.canvas.fieldGroups\n .filter(g => !groupIds.includes(g.id))\n .map((g, i) => ({ ...g, order: reordered.length + i }));\n \n const nextCanvas = {\n ...state.canvas,\n fieldGroups: [...reordered, ...missingGroups],\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n // === THEME SYSTEM ===\n\n addThemeProperty: (property, currentValue) =>\n set((state) => {\n const themeConfig = state.canvas.themeConfig ?? createEmptyThemeConfig();\n // Don't add duplicate\n if (themeConfig.properties.some(p => p.id === property.id)) return {};\n const updatedProperties = [...themeConfig.properties, property];\n // For linked properties, do NOT overwrite the master's value — the\n // linked property reuses the master's entry in `variant.values`.\n const updatedVariants = property.linkedTo\n ? themeConfig.variants\n : themeConfig.variants.map(v =>\n v.isDefault ? { ...v, values: { ...v.values, [property.id]: currentValue } } : v\n );\n const nextCanvas = {\n ...state.canvas,\n themeConfig: { properties: updatedProperties, variants: updatedVariants },\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n updateThemeProperty: (propertyId, updates) =>\n set((state) => {\n const themeConfig = state.canvas.themeConfig;\n if (!themeConfig) return {};\n const updatedProperties = themeConfig.properties.map(p =>\n p.id === propertyId ? { ...p, ...updates } : p\n );\n const nextCanvas = {\n ...state.canvas,\n themeConfig: { ...themeConfig, properties: updatedProperties },\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n removeThemeProperty: (propertyId) =>\n set((state) => {\n const themeConfig = state.canvas.themeConfig;\n if (!themeConfig) return {};\n // If this property is a master with linked children, promote children:\n // copy the master's current value into each linked child's own id, then\n // strip their `linkedTo`.\n const linkedChildren = themeConfig.properties.filter(p => p.linkedTo === propertyId);\n const updatedProperties = themeConfig.properties\n .filter(p => p.id !== propertyId)\n .map(p => p.linkedTo === propertyId ? { ...p, linkedTo: undefined } : p);\n const updatedVariants = themeConfig.variants.map(v => {\n const { [propertyId]: removedValue, ...rest } = v.values;\n if (linkedChildren.length && removedValue !== undefined) {\n const seeded = { ...rest };\n for (const child of linkedChildren) {\n if (seeded[child.id] === undefined) seeded[child.id] = removedValue;\n }\n return { ...v, values: seeded };\n }\n return { ...v, values: rest };\n });\n const nextCanvas = {\n ...state.canvas,\n themeConfig: { ...themeConfig, properties: updatedProperties, variants: updatedVariants },\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n addThemeVariant: (variant) =>\n set((state) => {\n const themeConfig = state.canvas.themeConfig ?? createEmptyThemeConfig();\n const nextCanvas = {\n ...state.canvas,\n themeConfig: { ...themeConfig, variants: [...themeConfig.variants, variant] },\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n updateThemeVariant: (variantId, updates) =>\n set((state) => {\n const themeConfig = state.canvas.themeConfig;\n if (!themeConfig) return {};\n const nextCanvas = {\n ...state.canvas,\n themeConfig: {\n ...themeConfig,\n variants: themeConfig.variants.map(v => v.id === variantId ? { ...v, ...updates } : v),\n },\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n removeThemeVariant: (variantId) =>\n set((state) => {\n const themeConfig = state.canvas.themeConfig;\n if (!themeConfig) return {};\n // Don't allow removing default variant\n const variant = themeConfig.variants.find(v => v.id === variantId);\n if (variant?.isDefault) return {};\n const nextCanvas = {\n ...state.canvas,\n themeConfig: {\n ...themeConfig,\n variants: themeConfig.variants.filter(v => v.id !== variantId),\n },\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n setThemeConfig: (config) =>\n set((state) => {\n const nextCanvas = { ...state.canvas, themeConfig: config };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n syncDefaultThemeProperty: (propertyId, value) =>\n set((state) => {\n const themeConfig = state.canvas.themeConfig;\n if (!themeConfig) return {};\n const nextCanvas = {\n ...state.canvas,\n themeConfig: {\n ...themeConfig,\n variants: themeConfig.variants.map(v =>\n v.isDefault ? { ...v, values: { ...v.values, [propertyId]: value } } : v\n ),\n },\n };\n // Don't commit history for default theme sync (it's automatic)\n return { canvas: nextCanvas };\n }),\n\n applyThemeAsOriginal: (variantId) =>\n set((state) => {\n const themeConfig = state.canvas.themeConfig;\n if (!themeConfig) return {};\n const variant = themeConfig.variants.find(v => v.id === variantId);\n if (!variant || variant.isDefault) return {};\n\n const PAGE_BG_ID = '__pageBackground__';\n let updatedPages = [...state.canvas.pages];\n\n for (const prop of themeConfig.properties) {\n const value = variant.values[prop.linkedTo ?? prop.id];\n if (value === undefined) continue;\n\n if (prop.elementId === PAGE_BG_ID) {\n if (prop.targetProperty === 'backgroundColor') {\n updatedPages = updatedPages.map(p => ({\n ...p,\n settings: { ...p.settings, backgroundColor: value },\n }));\n } else if (prop.targetProperty === 'backgroundGradient' && prop.svgColorKey) {\n const stopMatch = prop.svgColorKey.match(/^stop:(\\d+)$/);\n if (stopMatch) {\n const stopIndex = parseInt(stopMatch[1], 10);\n updatedPages = updatedPages.map(p => {\n if (!p.settings.backgroundGradient?.stops[stopIndex]) return p;\n return {\n ...p,\n settings: {\n ...p.settings,\n backgroundGradient: {\n ...p.settings.backgroundGradient!,\n stops: p.settings.backgroundGradient!.stops.map((s, i) =>\n i === stopIndex ? { ...s, color: value } : s\n ),\n },\n },\n };\n });\n }\n }\n continue;\n }\n\n const updateNode = (node: CanvasNode): CanvasNode => {\n if (isGroup(node)) {\n return { ...node, children: node.children.map(updateNode) };\n }\n const el = node as CanvasElement;\n if (el.id !== prop.elementId) return node;\n if (prop.svgColorKey && el.svgColorMap) {\n return { ...el, svgColorMap: { ...el.svgColorMap, [prop.svgColorKey]: value } };\n }\n return { ...el, [prop.targetProperty]: value };\n };\n\n updatedPages = updatedPages.map(p => ({\n ...p,\n children: p.children.map(updateNode),\n }));\n }\n\n // Swap: default gets variant's values, variant gets old default's values + swaps name/swatch\n const defaultVariant = themeConfig.variants.find(v => v.isDefault);\n const oldDefaultValues = defaultVariant ? { ...defaultVariant.values } : {};\n const oldDefaultSwatch = defaultVariant?.swatchColor ?? '#ffffff';\n const oldDefaultName = defaultVariant?.name ?? 'Default';\n\n const updatedThemeConfig = {\n ...themeConfig,\n variants: themeConfig.variants.map(v => {\n if (v.isDefault) return { ...v, values: { ...variant.values }, swatchColor: variant.swatchColor, name: variant.name };\n if (v.id === variantId) return { ...v, values: oldDefaultValues, swatchColor: oldDefaultSwatch, name: oldDefaultName };\n return v;\n }),\n };\n\n const nextCanvas: CanvasState = {\n ...state.canvas,\n pages: updatedPages,\n themeConfig: updatedThemeConfig,\n };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n // === GROUPING ===\n \n groupNodes: (ids, name) =>\n set((state) => {\n if (ids.length < 2) return {};\n \n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const idSet = new Set(ids);\n\n // When user selects a group, selection includes the group + all descendants.\n // Only group the top-level selected nodes (exclude any id whose ancestor is also selected).\n const topLevelIds = ids.filter((id) => {\n let parent = findParentGroup(currentPage.children, id);\n while (parent) {\n if (idSet.has(parent.id)) return false;\n parent = findParentGroup(currentPage.children, parent.id);\n }\n return true;\n });\n\n if (topLevelIds.length < 2) return {};\n\n const nodesToGroup: CanvasNode[] = [];\n for (const id of topLevelIds) {\n const node = findNodeById(currentPage.children, id);\n if (node) nodesToGroup.push(cloneNode(node));\n }\n \n if (nodesToGroup.length < 2) return {};\n \n // Find common parent of all nodes to group\n const parentGroups = topLevelIds.map(id => findParentGroup(currentPage.children, id));\n const commonParent = parentGroups.length > 0 && parentGroups.every(p => p?.id === parentGroups[0]?.id)\n ? parentGroups[0]\n : null;\n \n // Find the index where to insert the new group (use first node's index in its parent)\n let insertIndex: number | undefined = undefined;\n if (commonParent && topLevelIds.length > 0) {\n const firstNodeId = topLevelIds[0];\n const firstNodeIndex = commonParent.children.findIndex(child => child.id === firstNodeId);\n if (firstNodeIndex >= 0) {\n insertIndex = firstNodeIndex;\n }\n }\n \n // Sort by visual order (top ascending) so first in array = topmost on canvas. Use absolute bounds so stack children (stored 0,0) sort correctly.\n const pageChildrenForBounds = currentPage.children;\n nodesToGroup.sort((a, b) => {\n const aTop = getAbsoluteBounds(a, pageChildrenForBounds).top ?? 0;\n const bTop = getAbsoluteBounds(b, pageChildrenForBounds).top ?? 0;\n return aTop - bTop;\n });\n\n // Bounding box and relative positions from absolute bounds so subgroups with stored 0,0 (e.g. in a stack) get correct placement\n const pageChildren = currentPage.children;\n let groupLeft = Infinity, groupTop = Infinity;\n let groupRight = -Infinity, groupBottom = -Infinity;\n for (const node of nodesToGroup) {\n const b = getAbsoluteBounds(node, pageChildren);\n groupLeft = Math.min(groupLeft, b.left ?? 0);\n groupTop = Math.min(groupTop, b.top ?? 0);\n groupRight = Math.max(groupRight, b.right ?? 0);\n groupBottom = Math.max(groupBottom, b.bottom ?? 0);\n }\n if (groupLeft === Infinity) groupLeft = 0;\n if (groupTop === Infinity) groupTop = 0;\n const groupWidth = groupRight > -Infinity ? Math.max(0, groupRight - groupLeft) : 100;\n const groupHeight = groupBottom > -Infinity ? Math.max(0, groupBottom - groupTop) : 100;\n\n // Convert child positions to relative to the new group (use absolute bounds so stack children with stored 0,0 get correct rel top/left)\n const childrenWithRelativePos = nodesToGroup.map((node) => {\n const b = getAbsoluteBounds(node, pageChildren);\n const relLeft = (b.left ?? 0) - groupLeft;\n const relTop = (b.top ?? 0) - groupTop;\n return isElement(node)\n ? { ...node, left: relLeft, top: relTop }\n : { ...node, left: relLeft, top: relTop } as GroupNode;\n });\n\n const groupId = generateId('group');\n const newGroup = createDefaultGroup({\n id: groupId,\n name: name || `Group ${state.collapsedGroups.size + 1}`,\n children: childrenWithRelativePos,\n left: groupLeft,\n top: groupTop,\n width: groupWidth,\n height: groupHeight,\n });\n\n let nextChildren = currentPage.children;\n for (const id of topLevelIds) {\n nextChildren = removeNodeFromTree(nextChildren, id);\n }\n const parentId = commonParent?.id || null;\n nextChildren = addNodeToTree(nextChildren, newGroup, parentId, insertIndex);\n\n const nextCanvas = updateCurrentPageChildren(state.canvas, () => nextChildren);\n nextCanvas.selectedIds = [groupId]; // Select the new group\n \n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };\n }),\n\n addEmptyGroup: (name?: string) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const pageChildren = currentPage?.children ?? [];\n const PAGE_MARGIN = 48;\n const PAGE_GAP = 16;\n const MIN_EMPTY_GROUP_SIZE = 48;\n let maxBottom = PAGE_MARGIN;\n for (const node of pageChildren) {\n const b = getNodeBounds(node, pageChildren);\n if (b.bottom > maxBottom) maxBottom = b.bottom;\n }\n const groupId = generateId('group');\n const newGroup = createDefaultGroup({\n id: groupId,\n name: name ?? `Group ${state.collapsedGroups.size + 1}`,\n left: PAGE_MARGIN,\n top: maxBottom + PAGE_GAP,\n width: Math.max(MIN_EMPTY_GROUP_SIZE, 120),\n height: Math.max(MIN_EMPTY_GROUP_SIZE, 80),\n children: [],\n ...(name === 'Section' ? { backgroundColor: '#e2e8f0' } : {}),\n });\n const nextChildren = addNodeToTree(pageChildren, newGroup, null);\n const nextCanvas = updateCurrentPageChildren(state.canvas, () => nextChildren);\n nextCanvas.selectedIds = [groupId];\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, canvasUpdateVersion: state.canvasUpdateVersion + 1, ...committed };\n }),\n\n ungroupNodes: (groupId) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const group = findNodeById(currentPage.children, groupId);\n \n if (!group || !isGroup(group)) return {};\n \n // Get parent of the group\n const parentGroup = findParentGroup(currentPage.children, groupId);\n const parentId = parentGroup?.id || null;\n \n // Find index of group in parent\n const siblings = parentGroup ? parentGroup.children : currentPage.children;\n const groupIndex = siblings.findIndex(n => n.id === groupId);\n \n let nextChildren = removeNodeFromTree(currentPage.children, groupId);\n const parentAbs = parentId ? getAbsoluteBounds(findNodeById(nextChildren, parentId)!, nextChildren) : null;\n\n // Iterate forward (0 to length-1) so order is preserved: first in stack = first in parent (top to bottom)\n for (let i = 0; i < group.children.length; i++) {\n const child = group.children[i];\n const abs = getAbsoluteBounds(child, currentPage.children);\n const storeLeft = parentAbs ? abs.left - parentAbs.left : abs.left;\n const storeTop = parentAbs ? abs.top - parentAbs.top : abs.top;\n const childWithPos = isElement(child)\n ? { ...child, left: storeLeft, top: storeTop }\n : { ...child, left: storeLeft, top: storeTop } as GroupNode;\n nextChildren = addNodeToTree(nextChildren, childWithPos, parentId, groupIndex + i);\n }\n \n const nextCanvas = updateCurrentPageChildren(state.canvas, () => nextChildren);\n nextCanvas.selectedIds = getAllElementIds(group.children);\n \n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n renameNode: (id, name) =>\n set((state) => {\n const nextCanvas = updateCurrentPageChildren(state.canvas, (children) =>\n updateNodeInTree(children, id, { name })\n );\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n moveNodeToGroup: (nodeId, groupId, index) =>\n set((state) => {\n const nextCanvas = updateCurrentPageChildren(state.canvas, (children) =>\n moveNodeInTree(children, nodeId, groupId, index ?? 0)\n );\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n toggleGroupCollapse: (groupId) =>\n set((state) => {\n // Toggle ONLY the UI Set. We intentionally do NOT mutate `state.canvas`\n // here — doing so creates new `pages`/`children` references which cause\n // PageCanvas memos and sync effects to re-run, briefly re-applying\n // positions to Fabric objects and producing a visible \"jump\" even\n // though logical positions didn't change. It also flags the template\n // as having unsaved changes purely from collapsing a layer group.\n // Persistence of the `collapsed` flag is handled at save time\n // (see saveTemplate in useTemplate.ts).\n const newCollapsedSet = new Set(state.collapsedGroups);\n const isCollapsed = newCollapsedSet.has(groupId);\n\n if (isCollapsed) {\n newCollapsedSet.delete(groupId);\n } else {\n newCollapsedSet.add(groupId);\n }\n\n return { collapsedGroups: newCollapsedSet };\n }),\n\n // Convenience aliases\n groupElements: (ids, name) => get().groupNodes(ids, name),\n ungroupElements: (groupId) => get().ungroupNodes(groupId),\n renameGroup: (groupId, name) => get().renameNode(groupId, name),\n renameElement: (elementId, name) => get().renameNode(elementId, name),\n\n // === PAGE MANAGEMENT ===\n \n addPage: () =>\n set((state) => {\n const pageNumber = state.canvas.pages.length + 1;\n const newPageId = `page-${Date.now()}`;\n const newPage = createDefaultPage(newPageId, `Page ${pageNumber}`);\n\n const nextCanvas: CanvasState = {\n ...state.canvas,\n pages: [...state.canvas.pages, newPage],\n currentPageId: newPageId,\n selectedIds: [],\n };\n\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n addPageWithStaticElements: () =>\n set((state) => {\n const currentPage = state.canvas.pages.find(p => p.id === state.canvas.currentPageId);\n if (!currentPage) return {};\n const staticNodes = currentPage.children.filter(\n (n): n is CanvasNode => (n as CanvasNode & { staticOnNewPage?: boolean }).staticOnNewPage === true\n );\n const clonedChildren = staticNodes.map(cloneNodeWithNewIds);\n const pageNumber = state.canvas.pages.length + 1;\n const newPageId = `page-${Date.now()}`;\n const newPage: CanvasPage = {\n id: newPageId,\n name: `Page ${pageNumber}`,\n children: clonedChildren,\n settings: { ...currentPage.settings },\n };\n\n const nextCanvas: CanvasState = {\n ...state.canvas,\n pages: [...state.canvas.pages, newPage],\n currentPageId: newPageId,\n selectedIds: [],\n };\n\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n deletePage: (pageId) =>\n set((state) => {\n if (state.canvas.pages.length <= 1) return {};\n\n const deletedPage = state.canvas.pages.find(p => p.id === pageId);\n const newPages = state.canvas.pages.filter(p => p.id !== pageId);\n const currentPageDeleted = state.canvas.currentPageId === pageId;\n const newCurrentPageId = currentPageDeleted ? newPages[0].id : state.canvas.currentPageId;\n\n // Collect element ids on the deleted page, then exclude any that ALSO exist on a remaining\n // page (defensive — element ids should be unique, but never orphan a binding still in use).\n // We deliberately do NOT include the page-background sentinel here — that's a shared\n // constant across pages and bindings to it remain valid as long as any page exists.\n const deletedElementIds = new Set<string>(getAllElementIds(deletedPage?.children ?? []));\n const remainingElementIds = new Set<string>();\n for (const p of newPages) for (const id of getAllElementIds(p.children ?? [])) remainingElementIds.add(id);\n for (const id of remainingElementIds) deletedElementIds.delete(id);\n\n let nextCanvas: CanvasState = {\n ...state.canvas,\n pages: newPages,\n currentPageId: newCurrentPageId,\n selectedIds: currentPageDeleted ? [] : state.canvas.selectedIds,\n };\n\n // Prune theme properties referencing elements that no longer exist.\n if (nextCanvas.themeConfig && deletedElementIds.size > 0) {\n const remainingProps = nextCanvas.themeConfig.properties.filter(p => !deletedElementIds.has(p.elementId));\n if (remainingProps.length !== nextCanvas.themeConfig.properties.length) {\n const removedPropIds = new Set(\n nextCanvas.themeConfig.properties.filter(p => deletedElementIds.has(p.elementId)).map(p => p.id)\n );\n nextCanvas = {\n ...nextCanvas,\n themeConfig: {\n ...nextCanvas.themeConfig,\n properties: remainingProps,\n variants: nextCanvas.themeConfig.variants.map(v => {\n const values = { ...v.values };\n for (const pid of removedPropIds) delete values[pid];\n return { ...v, values };\n }),\n },\n };\n }\n }\n\n // Prune dynamic field mappings to deleted elements; drop any field left with zero mappings.\n if (nextCanvas.dynamicFields?.length && deletedElementIds.size > 0) {\n nextCanvas = {\n ...nextCanvas,\n dynamicFields: nextCanvas.dynamicFields\n .map(f => ({ ...f, mappings: (f.mappings ?? []).filter(m => !deletedElementIds.has(m.elementId)) }))\n .filter(f => (f.mappings ?? []).length > 0),\n };\n }\n\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n duplicatePage: (pageId) =>\n set((state) => {\n const page = state.canvas.pages.find(p => p.id === pageId);\n if (!page) return {};\n\n const newPageId = generateId('page');\n const newPage: CanvasPage = {\n ...page,\n id: newPageId,\n name: `${page.name} (copy)`,\n children: page.children.map(cloneNodeWithNewIds), // Use cloneNodeWithNewIds to regenerate all IDs\n };\n\n const pageIndex = state.canvas.pages.findIndex(p => p.id === pageId);\n const newPages = [...state.canvas.pages];\n newPages.splice(pageIndex + 1, 0, newPage);\n\n const nextCanvas: CanvasState = {\n ...state.canvas,\n pages: newPages,\n currentPageId: newPageId,\n selectedIds: [],\n };\n\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n pastePage: (payload) => {\n let resultPageId: string | null = null;\n set((state) => {\n // ---- 0. Re-ID the clipboard's page subtree FRESH on every paste. The clipboard payload\n // is reused across multiple pastes (and may even be pasted into the same template that\n // already has nodes with these ids), so we must regenerate every node id and rewrite the\n // carried fields' mappings + theme properties' elementId through the new id map.\n // Without this, two pastes would share identical node IDs and deleting one page would\n // silently affect the other.\n\n const { nodes: freshChildren, idMap } = reIdSubtree(payload.page.children ?? []);\n const freshPage: CanvasPage = {\n id: generateId('page'),\n name: payload.page.name,\n children: freshChildren,\n settings: { ...defaultPageSettings, ...(payload.page.settings ?? {}) },\n };\n\n const carriedFields = (payload.dynamicFields ?? [])\n .map(f => ({ ...f, mappings: rewriteFieldMappings(f.mappings, idMap) }))\n .filter(f => f.mappings.length > 0);\n\n const carriedTheme = (payload.themeProperties ?? [])\n .filter(t => idMap.has(t.property.elementId))\n .map(t => ({ ...t, property: { ...t.property, elementId: idMap.get(t.property.elementId)! } }));\n\n // ---- 1. Insert the freshly re-IDed page after the current page.\n const currentIndex = state.canvas.pages.findIndex(p => p.id === state.canvas.currentPageId);\n const insertAt = currentIndex >= 0 ? currentIndex + 1 : state.canvas.pages.length;\n const newPages = [...state.canvas.pages];\n newPages.splice(insertAt, 0, freshPage);\n\n // ---- 2. Merge dynamic fields. ALWAYS create new suffixed ids so the pasted page gets its own\n // independent fields (even when pasting into the same template). Otherwise one field would end\n // up driving multiple pages, which is never what the user wants for a \"smart page\" copy.\n const existingFields = state.canvas.dynamicFields ?? [];\n const mergedFields: DynamicField[] = [...existingFields];\n const taken = new Set(mergedFields.map(f => f.id));\n\n for (const incoming of carriedFields) {\n let candidate = incoming.id;\n let n = 2;\n while (taken.has(candidate)) {\n candidate = `${incoming.id}_${n++}`;\n }\n taken.add(candidate);\n mergedFields.push({ ...incoming, id: candidate });\n }\n\n // ---- 3. Merge theme properties. Always add fresh theme props (even on dupes) so the pasted\n // page's theme bindings are independent from any existing same-element bindings in the target.\n let themeConfig = state.canvas.themeConfig;\n if (carriedTheme.length > 0) {\n themeConfig = themeConfig\n ? {\n properties: [...themeConfig.properties],\n variants: themeConfig.variants.map(v => ({ ...v, values: { ...v.values } })),\n }\n : createEmptyThemeConfig();\n\n for (const carried of carriedTheme) {\n const newProp: ThemeProperty = { ...carried.property, id: generateId('themeprop') };\n themeConfig.properties.push(newProp);\n // Push the source's default value into EVERY variant (including the target's default).\n if (carried.defaultValue !== undefined) {\n for (const v of themeConfig.variants) {\n v.values[newProp.id] = carried.defaultValue;\n }\n }\n }\n }\n\n const nextCanvas: CanvasState = {\n ...state.canvas,\n pages: newPages,\n currentPageId: freshPage.id,\n selectedIds: [],\n dynamicFields: mergedFields,\n themeConfig,\n };\n\n resultPageId = freshPage.id;\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n });\n return resultPageId;\n },\n\n renamePage: (pageId, name) =>\n set((state) => {\n const trimmedName = name.trim();\n if (!trimmedName) return {};\n \n const updatedPages = state.canvas.pages.map(p =>\n p.id === pageId ? { ...p, name: trimmedName } : p\n );\n \n const nextCanvas: CanvasState = { ...state.canvas, pages: updatedPages };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n setCurrentPage: (pageId) =>\n set((state) => {\n if (state.canvas.currentPageId === pageId) return {};\n return { canvas: { ...state.canvas, currentPageId: pageId, selectedIds: [] } };\n }),\n\n reorderPages: (fromIndex, toIndex) =>\n set((state) => {\n const pages = [...state.canvas.pages];\n const [removed] = pages.splice(fromIndex, 1);\n pages.splice(toIndex, 0, removed);\n\n const nextCanvas: CanvasState = { ...state.canvas, pages };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n updatePageSettings: (pageId, settings) =>\n set((state) => {\n const updatedPages = state.canvas.pages.map(p =>\n p.id === pageId ? { ...p, settings: { ...p.settings, ...settings } } : p\n );\n let themeConfig = state.canvas.themeConfig;\n // Auto-sync default theme variant when page background changes\n if (themeConfig) {\n const PAGE_BG_ID = '__pageBackground__';\n let needsSync = false;\n const syncUpdates: Record<string, string> = {};\n if ('backgroundColor' in settings) {\n const bgProp = themeConfig.properties.find(p => p.elementId === PAGE_BG_ID && p.targetProperty === 'backgroundColor');\n if (bgProp) { syncUpdates[bgProp.id] = settings.backgroundColor || '#ffffff'; needsSync = true; }\n }\n if ('backgroundGradient' in settings) {\n const grad = settings.backgroundGradient;\n // Sync per-stop gradient theme properties\n const gradStopProps = themeConfig.properties.filter(p => p.elementId === PAGE_BG_ID && p.targetProperty === 'backgroundGradient' && p.svgColorKey?.startsWith('stop:'));\n for (const prop of gradStopProps) {\n const stopMatch = prop.svgColorKey?.match(/^stop:(\\d+)$/);\n if (stopMatch && grad) {\n const stopIndex = parseInt(stopMatch[1], 10);\n if (grad.stops[stopIndex]) {\n syncUpdates[prop.id] = grad.stops[stopIndex].color;\n needsSync = true;\n }\n }\n }\n }\n if (needsSync) {\n themeConfig = {\n ...themeConfig,\n variants: themeConfig.variants.map(v =>\n v.isDefault ? { ...v, values: { ...v.values, ...syncUpdates } } : v\n ),\n };\n }\n }\n const nextCanvas: CanvasState = { ...state.canvas, pages: updatedPages, themeConfig };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n setPageBoundRepeatablePage: (pageId, repeatablePageId) =>\n set((state) => {\n const updatedPages = state.canvas.pages.map(p => {\n if (p.id !== pageId) return p;\n const next: CanvasPage = { ...p };\n if (repeatablePageId) next.boundRepeatablePageId = repeatablePageId;\n else delete next.boundRepeatablePageId;\n return next;\n });\n const nextCanvas: CanvasState = { ...state.canvas, pages: updatedPages };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n moveElementsToPage: (elementIds, targetPageId) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const nodesToMove: CanvasNode[] = [];\n \n for (const id of elementIds) {\n const node = findNodeById(currentPage.children, id);\n if (node) nodesToMove.push(cloneNode(node));\n }\n \n if (nodesToMove.length === 0) return {};\n\n // Remove from current page\n let nextCurrentChildren = currentPage.children;\n for (const id of elementIds) {\n nextCurrentChildren = removeNodeFromTree(nextCurrentChildren, id);\n }\n\n const updatedPages = state.canvas.pages.map(p => {\n if (p.id === state.canvas.currentPageId) {\n return { ...p, children: nextCurrentChildren };\n }\n if (p.id === targetPageId) {\n let newChildren = p.children;\n for (const node of nodesToMove) {\n newChildren = addNodeToTree(newChildren, node, null);\n }\n return { ...p, children: newChildren };\n }\n return p;\n });\n\n const nextCanvas: CanvasState = {\n ...state.canvas,\n pages: updatedPages,\n selectedIds: [],\n };\n\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n moveElementsToPageWithPositions: (elementIds, targetPageId, positionsById) =>\n set((state) => {\n const currentPage = getCurrentPageFromCanvas(state.canvas);\n const nodesToMove: CanvasNode[] = [];\n \n for (const id of elementIds) {\n const node = findNodeById(currentPage.children, id);\n if (node && isElement(node)) {\n const pos = positionsById[id];\n if (pos) {\n nodesToMove.push({ ...node, left: pos.left, top: pos.top });\n } else {\n nodesToMove.push(cloneNode(node));\n }\n }\n }\n \n if (nodesToMove.length === 0) return {};\n\n let nextCurrentChildren = currentPage.children;\n for (const id of elementIds) {\n nextCurrentChildren = removeNodeFromTree(nextCurrentChildren, id);\n }\n\n const updatedPages = state.canvas.pages.map(p => {\n if (p.id === state.canvas.currentPageId) {\n return { ...p, children: nextCurrentChildren };\n }\n if (p.id === targetPageId) {\n let newChildren = p.children;\n for (const node of nodesToMove) {\n newChildren = addNodeToTree(newChildren, node, null);\n }\n return { ...p, children: newChildren };\n }\n return p;\n });\n\n const nextCanvas: CanvasState = {\n ...state.canvas,\n pages: updatedPages,\n currentPageId: targetPageId,\n selectedIds: elementIds,\n };\n\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n // Legacy reorder methods - simplified with tree structure\n reorderElements: (pageId, orderedIds) =>\n set((state) => {\n const targetPage = state.canvas.pages.find(p => p.id === pageId);\n if (!targetPage) return {};\n \n // Reorder root-level nodes based on orderedIds\n const nodeMap = new Map(targetPage.children.map(n => [n.id, n]));\n const reorderedChildren: CanvasNode[] = [];\n const usedIds = new Set<string>();\n \n for (const id of orderedIds) {\n const node = nodeMap.get(id);\n if (node) {\n reorderedChildren.push(node);\n usedIds.add(id);\n }\n }\n \n // Add any nodes not in orderedIds\n for (const node of targetPage.children) {\n if (!usedIds.has(node.id)) {\n reorderedChildren.push(node);\n }\n }\n \n const updatedPages = state.canvas.pages.map(p =>\n p.id === pageId ? { ...p, children: reorderedChildren } : p\n );\n \n const nextCanvas: CanvasState = { ...state.canvas, pages: updatedPages };\n const committed = commitFromState(state, nextCanvas);\n return { canvas: nextCanvas, ...committed };\n }),\n\n // === LOAD/RESET ===\n \n loadConfig: (config) =>\n set((state) => {\n const collapsedGroups = new Set<string>();\n \n // Collect collapsed group IDs from config\n const collectCollapsedGroups = (nodes: CanvasNode[]) => {\n for (const node of nodes) {\n if (isGroup(node) && node.collapsed) {\n collapsedGroups.add(node.id);\n }\n if (isGroup(node)) {\n collectCollapsedGroups(node.children);\n }\n }\n };\n \n config.pages.forEach(p => collectCollapsedGroups(p.children));\n\n clearMeasurementCache();\n\n // Normalize legacy stored widths for specific groups to keep config load resilient.\n const EXPERIENCE_TITLE_ROW_IDS = new Set(['resume-exp-1-title-row', 'resume-exp-2-title-row']);\n function normalizeExperienceTitleRowWidth(nodes: CanvasNode[]): CanvasNode[] {\n return nodes.map((node) => {\n if (isGroup(node)) {\n const g = node as GroupNode;\n const width = EXPERIENCE_TITLE_ROW_IDS.has(g.id) ? (typeof g.width === 'number' ? g.width : undefined) : g.width;\n const height = g.height;\n return { ...g, width, height, children: normalizeExperienceTitleRowWidth(g.children) };\n }\n return node;\n });\n }\n\n // Legacy: normalize group children positions (no-op when tree is already correct).\n function normalizeGroupChildrenPositions(\n nodes: CanvasNode[],\n _pageChildren: CanvasNode[],\n _opts?: { legacyAbsolutePositions?: boolean }\n ): CanvasNode[] {\n return nodes.map((node) => {\n if (isGroup(node)) {\n const g = node as GroupNode;\n return { ...g, children: normalizeGroupChildrenPositions(g.children ?? [], _pageChildren, _opts) };\n }\n return node;\n });\n }\n\n // Legacy: normalize absolute positions. Layout-engine-driven: only normalize experience title row width.\n const legacyAbsolute = config.relativeGroupPositions !== true;\n let pagesWithPositions = config.pages.map(p => {\n const children = legacyAbsolute\n ? normalizeGroupChildrenPositions(p.children, p.children, { legacyAbsolutePositions: true })\n : normalizeExperienceTitleRowWidth(p.children);\n return {\n id: p.id,\n name: p.name,\n children,\n settings: { backgroundColor: '#ffffff', ...p.settings },\n ...((p as any).boundRepeatablePageId ? { boundRepeatablePageId: (p as any).boundRepeatablePageId } : {}),\n };\n });\n\n // Always run reflow on load so layout (including auto dimensions) is correct. Legacy needs it for positions;\n // layout-engine-driven needs it so builder shows correct layout with real measureTextHeight (seed bake used rough estimate).\n pagesWithPositions = pagesWithPositions.map(p => {\n const reflowUpdates = reflowPageFromRoot(p.children);\n if (reflowUpdates.size === 0) return p;\n let children = p.children;\n reflowUpdates.forEach((u, nodeId) => {\n const dims: Partial<CanvasElement> & Partial<GroupNode> = {};\n if (u.width !== undefined) dims.width = u.width;\n if (u.height !== undefined) dims.height = u.height;\n if (Object.keys(dims).length > 0) children = updateNodeInTree(children, nodeId, dims);\n });\n reflowUpdates.forEach((u, nodeId) => {\n const pos: Partial<CanvasElement> & Partial<GroupNode> = {};\n if (u.left !== undefined) pos.left = u.left;\n if (u.top !== undefined) pos.top = u.top;\n if (Object.keys(pos).length > 0) children = updateNodeInTree(children, nodeId, pos);\n });\n return { ...p, children };\n });\n const nextCanvas: CanvasState = {\n width: config.canvas.width,\n height: config.canvas.height,\n pages: pagesWithPositions,\n currentPageId: config.pages[0]?.id || 'page-1',\n selectedIds: [],\n zoom: 1,\n pan: { x: 0, y: 0 },\n projectSettings: config.projectSettings ?? { ...defaultProjectSettings },\n dynamicFields: (config.dynamicFields ?? []).map(f => {\n // Normalize fields: ensure mappings exists or convert from old format\n if (f.mappings && Array.isArray(f.mappings)) {\n // New format: already correct\n return f;\n } else if ((f as any).elementIds && Array.isArray((f as any).elementIds)) {\n // Old format: create mappings from elementIds (keep elementIds for backward compat)\n const elementIds = (f as any).elementIds;\n const mappings = elementIds.map((elementId: string) => ({\n elementId,\n targetProperty: (f.type === 'image' ? 'src' : f.type === 'color' ? 'fill' : 'text') as any,\n }));\n return { ...f, mappings } as DynamicField;\n } else {\n // Fallback: ensure mappings exists as empty array\n return { ...f, mappings: [] } as DynamicField;\n }\n }),\n fieldGroups: config.fieldGroups ?? [],\n formRenderPreset: (config as unknown as { formRenderPreset?: string }).formRenderPreset,\n formBindingMode: (config as any).formBindingMode,\n boundFormDefId: (config as any).boundFormDefId,\n boundFormDefName: (config as any).boundFormDefName,\n themeConfig: config.themeConfig ?? undefined,\n pdfTextMode: (config as any).pdfTextMode ?? 'selectable',\n };\n\n const committed = commitFromState(state, nextCanvas);\n const out: Record<string, unknown> = {\n canvas: nextCanvas,\n canvasUpdateVersion: state.canvasUpdateVersion + 1,\n ...committed,\n collapsedGroups,\n showSections: config.showSections ?? false,\n showDynamicLabels: config.showDynamicLabels ?? false,\n };\n return out;\n }),\n\n applyReflowToCurrentPage: () =>\n set((state) => ({\n canvas: applyReflowToCanvas(state.canvas),\n canvasUpdateVersion: state.canvasUpdateVersion + 1,\n })),\n\n reflowStackGroupInPage: (pageId, groupId) =>\n set((state) => {\n const page = state.canvas.pages.find((p) => p.id === pageId);\n if (!page) return {};\n const reflowed = applyStackReflowToGroup(page.children, groupId);\n const updatedPages = state.canvas.pages.map((p) =>\n p.id === pageId ? { ...p, children: reflowed } : p\n );\n return {\n canvas: { ...state.canvas, pages: updatedPages },\n canvasUpdateVersion: state.canvasUpdateVersion + 1,\n };\n }),\n\n resetCanvas: () =>\n set((state) => {\n const newPageId = `page-${Date.now()}`;\n const newPage = createDefaultPage(newPageId, 'Page 1');\n \n const nextCanvas: CanvasState = {\n width: 595,\n height: 842,\n pages: [newPage],\n currentPageId: newPageId,\n selectedIds: [],\n zoom: 1,\n pan: { x: 0, y: 0 },\n projectSettings: { ...defaultProjectSettings },\n dynamicFields: [],\n fieldGroups: [], // Groups are created on-demand by user\n };\n\n const committed = commitFromState(state, nextCanvas);\n return { \n canvas: nextCanvas, \n ...committed,\n collapsedGroups: new Set(),\n activeTool: 'select' as Tool,\n };\n }),\n}));\n","import * as fabric from 'fabric';\n\n/**\n * Global registry for Fabric.js canvas instances\n * Each page has its own canvas - we need to access them for:\n * - PDF export (iterate all pages)\n * - RightPanel property editing (current page)\n */\n\ntype CanvasMap = Map<string, fabric.Canvas>;\n\nlet canvasRegistry: CanvasMap = new Map();\nlet activePageId: string | null = null;\n\nexport function registerFabricCanvas(pageId: string, canvas: fabric.Canvas): string {\n const existing = canvasRegistry.get(pageId);\n const registryKey = existing && existing !== canvas\n ? `${pageId}#${Math.random().toString(36).slice(2, 10)}`\n : pageId;\n canvasRegistry.set(registryKey, canvas);\n return registryKey;\n}\n\nexport function unregisterFabricCanvas(pageId: string, canvas?: fabric.Canvas) {\n if (canvas) {\n const existing = canvasRegistry.get(pageId);\n if (existing === canvas) canvasRegistry.delete(pageId);\n return;\n }\n canvasRegistry.delete(pageId);\n}\n\nexport function setActivePageCanvas(pageId: string) {\n activePageId = pageId;\n}\n\nexport function getActiveCanvas(): fabric.Canvas | null {\n if (!activePageId) return null;\n return canvasRegistry.get(activePageId) || null;\n}\n\nexport function getCanvasForPage(pageId: string): fabric.Canvas | null {\n return canvasRegistry.get(pageId) || null;\n}\n\nexport function getAllCanvases(): Map<string, fabric.Canvas> {\n return new Map(canvasRegistry);\n}\n\nexport function clearCanvasRegistry() {\n canvasRegistry.clear();\n activePageId = null;\n}\n\n/**\n * Capture all pages as a combined base64 PNG screenshot for AI vision analysis.\n * Returns a data:image/png;base64,... string or null if no canvases registered.\n */\nexport function captureCanvasScreenshot(maxWidth = 800): string | null {\n const entries = Array.from(canvasRegistry.entries());\n if (entries.length === 0) return null;\n\n try {\n // For single page, just export directly\n if (entries.length === 1) {\n const [, fc] = entries[0];\n const scale = Math.min(1, maxWidth / (fc.getWidth() || 595));\n return fc.toDataURL({ format: 'png', multiplier: scale });\n }\n\n // Multi-page: stack vertically on an offscreen canvas\n const gap = 10;\n const pageImages: { dataUrl: string; w: number; h: number }[] = [];\n let totalHeight = 0;\n let maxW = 0;\n\n for (const [, fc] of entries) {\n const w = fc.getWidth() || 595;\n const h = fc.getHeight() || 842;\n const scale = Math.min(1, maxWidth / w);\n const dataUrl = fc.toDataURL({ format: 'png', multiplier: scale });\n const scaledW = Math.round(w * scale);\n const scaledH = Math.round(h * scale);\n pageImages.push({ dataUrl, w: scaledW, h: scaledH });\n totalHeight += scaledH + gap;\n if (scaledW > maxW) maxW = scaledW;\n }\n totalHeight -= gap; // Remove last gap\n\n // Draw onto offscreen canvas\n const offscreen = document.createElement('canvas');\n offscreen.width = maxW;\n offscreen.height = totalHeight;\n const ctx = offscreen.getContext('2d');\n if (!ctx) return pageImages[0]?.dataUrl || null;\n\n let yOffset = 0;\n const loadPromises = pageImages.map((pi, idx) => {\n return new Promise<void>((resolve) => {\n const img = new Image();\n img.onload = () => {\n ctx.drawImage(img, 0, yOffset);\n yOffset += pi.h + gap;\n resolve();\n };\n img.onerror = () => resolve();\n img.src = pi.dataUrl;\n });\n });\n\n // Since toDataURL is synchronous on fabric, we can return directly for single page\n // For multi-page, we need async - but let's just return first page for simplicity\n return pageImages[0]?.dataUrl || null;\n } catch (e) {\n console.error('Failed to capture canvas screenshot:', e);\n return null;\n }\n}\n\n/**\n * Capture first page canvas as base64 synchronously. Most reliable for AI vision.\n */\nexport function captureFirstPageScreenshot(maxWidth = 600): string | null {\n const entries = Array.from(canvasRegistry.entries());\n if (entries.length === 0) return null;\n try {\n const [, fc] = entries[0];\n const w = fc.getWidth() || 595;\n const scale = Math.min(1, maxWidth / w);\n return fc.toDataURL({ format: 'png', multiplier: scale });\n } catch (e) {\n console.error('Failed to capture page screenshot:', e);\n return null;\n }\n}\n\n// For debugging\nexport function getRegistryDebugInfo() {\n return {\n activePageId,\n registeredPages: Array.from(canvasRegistry.keys()),\n };\n}\n\n// Expose to window for console debugging (dev only)\nif (typeof window !== 'undefined' && import.meta.env.DEV) {\n (window as any).__fabricCanvasRegistry = {\n getActiveCanvas,\n getCanvasForPage,\n getAllCanvases,\n getRegistryDebugInfo,\n };\n}\n","/**\n * Font Library Loader\n * Loads fonts on-demand from multiple sources:\n * - Local TTFs in public/fonts/ (highest priority, zero-latency)\n * - Google Fonts CSS API (fallback for ~250 curated families)\n * - Fontshare CSS API (premium-feel free fonts: Satoshi, Cabinet Grotesk, etc.)\n */\n\n// Fonts we have locally as TTF files — these don't need Google Fonts\nexport const LOCAL_FONTS = new Set([\n // Original local fonts (static TTFs)\n 'Playfair Display', 'Merriweather', 'Lora',\n 'Montserrat', 'Open Sans', 'Roboto', 'Lato', 'Raleway', 'Poppins',\n 'Inter', 'Nunito', 'Source Sans Pro', 'Work Sans',\n 'Oswald', 'Bebas Neue', 'Abril Fatface',\n 'Dancing Script', 'Pacifico', 'Great Vibes',\n // Newly added local fonts (variable + static TTFs)\n 'DM Sans', 'Outfit', 'Figtree', 'Manrope', 'Space Grotesk',\n 'League Spartan', 'EB Garamond', 'Libre Baskerville', 'Crimson Text',\n 'DM Serif Display', 'Libre Franklin', 'Mulish', 'Quicksand', 'Rubik',\n 'Karla', 'Plus Jakarta Sans', 'Sora', 'Urbanist', 'Lexend',\n 'Albert Sans', 'Noto Sans', 'Cabin', 'Barlow', 'Josefin Sans',\n 'Archivo', 'Overpass', 'Exo 2',\n 'Roboto Mono', 'Fira Code', 'JetBrains Mono', 'Source Code Pro',\n 'IBM Plex Mono', 'Space Mono',\n 'Sacramento', 'Alex Brush', 'Allura', 'Caveat', 'Lobster', 'Comfortaa',\n 'Anton', 'Teko',\n // Indic script fallback fonts\n 'Noto Sans Devanagari',\n 'Hind',\n]);\n\n// Track which Google Fonts we've already loaded\nconst loadedGoogleFonts = new Set<string>();\nconst failedGoogleFonts = new Set<string>(); // Fonts that failed to load — don't retry\nconst loadedFontshareFonts = new Set<string>();\nconst failedFontshareFonts = new Set<string>();\n\n// Track loading promises to avoid duplicate requests\nconst loadingPromises = new Map<string, Promise<boolean>>();\n\n/**\n * Load a font from Google Fonts if it's not available locally.\n * Returns true if the font was loaded (or already available).\n */\nexport async function loadGoogleFont(fontFamily: string, weights?: number[]): Promise<boolean> {\n if (LOCAL_FONTS.has(fontFamily)) return true;\n if (loadedGoogleFonts.has(fontFamily)) return true;\n if (failedGoogleFonts.has(fontFamily)) return false;\n\n\n // Check if already loading\n const existing = loadingPromises.get(`google:${fontFamily}`);\n if (existing) return existing;\n\n const promise = _doLoadGoogleFont(fontFamily, weights);\n loadingPromises.set(`google:${fontFamily}`, promise);\n\n try {\n const result = await promise;\n if (result) {\n loadedGoogleFonts.add(fontFamily);\n } else {\n failedGoogleFonts.add(fontFamily);\n }\n return result;\n } finally {\n loadingPromises.delete(`google:${fontFamily}`);\n }\n}\n\n/**\n * Try a Google Fonts CSS URL by injecting a <link>. Resolves true on load,\n * false on error. We use <link> instead of fetch() so we benefit from\n * browser caching and don't trip CORS on the CSS endpoint.\n */\nfunction tryInjectGoogleFontsLink(url: string, fontFamily: string): Promise<boolean> {\n // Already injected?\n if (document.querySelector(`link[href=\"${url}\"]`)) return Promise.resolve(true);\n return new Promise((resolve) => {\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = url;\n link.onload = async () => {\n try {\n await document.fonts.load(`16px \"${fontFamily}\"`);\n } catch { /* ignore */ }\n resolve(true);\n };\n link.onerror = () => resolve(false);\n document.head.appendChild(link);\n });\n}\n\n/**\n * Load a Google Font with progressive fallback URLs.\n *\n * Many Google Fonts (especially Display / Handwriting / Decorative families)\n * only publish a single weight (400) — requesting `:wght@300;400;500;600;700`\n * makes the API return 400 and the font never loads. We retry with smaller\n * weight sets, ending with the bare family name which always works for any\n * published Google Font.\n */\nasync function _doLoadGoogleFont(fontFamily: string, weights?: number[]): Promise<boolean> {\n const encodedFamily = encodeURIComponent(fontFamily);\n const weightSet = weights || [300, 400, 500, 600, 700];\n const fullWeightStr = weightSet.join(';');\n const coreWeightStr = '400;700';\n\n // Ordered fallback list — first one that succeeds wins.\n const candidates = [\n `https://fonts.googleapis.com/css2?family=${encodedFamily}:ital,wght@0,${fullWeightStr};1,${fullWeightStr}&display=swap`,\n `https://fonts.googleapis.com/css2?family=${encodedFamily}:wght@${fullWeightStr}&display=swap`,\n `https://fonts.googleapis.com/css2?family=${encodedFamily}:ital,wght@0,${coreWeightStr};1,${coreWeightStr}&display=swap`,\n `https://fonts.googleapis.com/css2?family=${encodedFamily}:wght@${coreWeightStr}&display=swap`,\n // Plainest possible URL — works for any published Google Font, even\n // single-weight display/script families like \"Frijole\" or \"Creepster\".\n `https://fonts.googleapis.com/css2?family=${encodedFamily}&display=swap`,\n ];\n\n for (const url of candidates) {\n const ok = await tryInjectGoogleFontsLink(url, fontFamily);\n if (ok) return true;\n }\n console.warn(`[GoogleFonts] Failed to load: ${fontFamily}`);\n return false;\n}\n\n/**\n * Load a Fontshare font (Satoshi, Cabinet Grotesk, Clash Display, etc.).\n * Uses Fontshare's official CSS API. Slug = lowercase name with hyphens.\n */\nexport async function loadFontshareFont(fontFamily: string, slug: string, weights?: number[]): Promise<boolean> {\n if (loadedFontshareFonts.has(fontFamily)) return true;\n if (failedFontshareFonts.has(fontFamily)) return false;\n\n const existing = loadingPromises.get(`fontshare:${fontFamily}`);\n if (existing) return existing;\n\n const promise = (async (): Promise<boolean> => {\n try {\n const weightStr = (weights || [300, 400, 500, 600, 700]).join(',');\n const url = `https://api.fontshare.com/v2/css?f[]=${slug}@${weightStr}&display=swap`;\n if (document.querySelector(`link[href=\"${url}\"]`)) return true;\n\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = url;\n return await new Promise<boolean>((resolve) => {\n link.onload = async () => {\n try {\n await document.fonts.load(`16px \"${fontFamily}\"`);\n await document.fonts.load(`bold 16px \"${fontFamily}\"`);\n } catch { /* ignore */ }\n resolve(true);\n };\n link.onerror = () => {\n console.warn(`[Fontshare] Failed to load: ${fontFamily}`);\n resolve(false);\n };\n document.head.appendChild(link);\n });\n } catch (e) {\n console.warn(`[Fontshare] Error loading ${fontFamily}:`, e);\n return false;\n }\n })();\n\n loadingPromises.set(`fontshare:${fontFamily}`, promise);\n try {\n const result = await promise;\n if (result) loadedFontshareFonts.add(fontFamily);\n else failedFontshareFonts.add(fontFamily);\n return result;\n } finally {\n loadingPromises.delete(`fontshare:${fontFamily}`);\n }\n}\n\n/**\n * Unified font loader: dispatches to the correct source based on font entry metadata.\n * Use this everywhere instead of loadGoogleFont/loadFontshareFont directly.\n */\nexport async function loadFont(fontFamily: string): Promise<boolean> {\n if (LOCAL_FONTS.has(fontFamily)) return true;\n const entry = findFontEntry(fontFamily);\n if (entry?.source === 'fontshare' && entry.fontshareSlug) {\n return loadFontshareFont(fontFamily, entry.fontshareSlug);\n }\n return loadGoogleFont(fontFamily);\n}\n\n/**\n * Check if a font is available locally (no Google Fonts needed)\n */\nexport function isLocalFont(fontFamily: string): boolean {\n return LOCAL_FONTS.has(fontFamily);\n}\n\n/**\n * Get the list of all available fonts (local + previously loaded Google Fonts)\n */\nexport function getLoadedFonts(): string[] {\n return [...LOCAL_FONTS, ...loadedGoogleFonts];\n}\n\n// ── Shared font catalogue ──\n\n/**\n * Extended font list: all popular Canva fonts organized by category.\n * Local fonts are marked; others will be loaded from Google Fonts on-demand.\n */\nexport interface FontEntry {\n name: string;\n category: string;\n local: boolean; // true = we have the TTF file locally\n source?: 'google' | 'fontshare'; // default: 'google'\n fontshareSlug?: string; // required when source === 'fontshare'\n popular?: boolean; // surface in a \"Popular\" section\n /** Optional explicit weight ladder. If omitted, defaults are inferred from category. */\n weights?: number[];\n}\n\nexport const EXTENDED_FONT_LIST: FontEntry[] = [\n // ═══════════════════════════════════════════════════════════════════\n // PREMIUM (Fontshare) — modern, professional aesthetic\n // ═══════════════════════════════════════════════════════════════════\n { name: 'Satoshi', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'satoshi', popular: true },\n { name: 'Cabinet Grotesk', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'cabinet-grotesk', popular: true },\n { name: 'Clash Display', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'clash-display', popular: true },\n { name: 'Clash Grotesk', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'clash-grotesk', popular: true },\n { name: 'General Sans', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'general-sans', popular: true },\n { name: 'Switzer', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'switzer' },\n { name: 'Supreme', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'supreme' },\n { name: 'Author', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'author' },\n { name: 'Boska', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'boska' },\n { name: 'Excon', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'excon' },\n { name: 'Khand', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'khand' },\n { name: 'Sentient', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'sentient' },\n { name: 'Synonym', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'synonym' },\n { name: 'Erode', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'erode' },\n { name: 'Ranade', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'ranade' },\n { name: 'Tanker', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'tanker' },\n { name: 'Zodiak', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'zodiak' },\n { name: 'Gambarino', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'gambarino' },\n { name: 'Melodrama', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'melodrama' },\n { name: 'Bespoke Serif', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'bespoke-serif' },\n { name: 'Bespoke Stencil', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'bespoke-stencil' },\n { name: 'Panchang', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'panchang' },\n { name: 'Pally', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'pally' },\n { name: 'Tabular', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'tabular' },\n { name: 'Sharpie', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'sharpie' },\n { name: 'Stardom', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'stardom' },\n { name: 'Telma', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'telma' },\n { name: 'Nippo', category: 'Premium', local: false, source: 'fontshare', fontshareSlug: 'nippo' },\n\n // ═══════════════════════════════════════════════════════════════════\n // SERIF — editorial, classical, elegant\n // ═══════════════════════════════════════════════════════════════════\n { name: 'Playfair Display', category: 'Serif', local: true, popular: true },\n { name: 'Cormorant', category: 'Serif', local: false, popular: true },\n { name: 'Cormorant Garamond', category: 'Serif', local: false },\n { name: 'Cinzel', category: 'Serif', local: false, popular: true },\n { name: 'Cinzel Decorative', category: 'Serif', local: false },\n { name: 'Bodoni Moda', category: 'Serif', local: false, popular: true },\n { name: 'DM Serif Display', category: 'Serif', local: true },\n { name: 'DM Serif Text', category: 'Serif', local: false },\n { name: 'Italiana', category: 'Serif', local: false },\n { name: 'Marcellus', category: 'Serif', local: false },\n { name: 'Marcellus SC', category: 'Serif', local: false },\n { name: 'Yeseva One', category: 'Serif', local: false },\n { name: 'Prata', category: 'Serif', local: false },\n { name: 'Tenor Sans', category: 'Serif', local: false },\n { name: 'Fraunces', category: 'Serif', local: false, popular: true },\n { name: 'Newsreader', category: 'Serif', local: false },\n { name: 'Source Serif Pro', category: 'Serif', local: false },\n { name: 'Merriweather', category: 'Serif', local: true },\n { name: 'Lora', category: 'Serif', local: true },\n { name: 'EB Garamond', category: 'Serif', local: true },\n { name: 'Libre Baskerville', category: 'Serif', local: true },\n { name: 'Libre Caslon Text', category: 'Serif', local: false },\n { name: 'Libre Caslon Display', category: 'Serif', local: false },\n { name: 'Crimson Text', category: 'Serif', local: true },\n { name: 'Crimson Pro', category: 'Serif', local: false },\n { name: 'Noto Serif', category: 'Serif', local: false },\n { name: 'Noto Serif Display', category: 'Serif', local: false },\n { name: 'PT Serif', category: 'Serif', local: false },\n { name: 'Bitter', category: 'Serif', local: false },\n { name: 'Spectral', category: 'Serif', local: false },\n { name: 'Cardo', category: 'Serif', local: false },\n { name: 'Old Standard TT', category: 'Serif', local: false },\n { name: 'Vollkorn', category: 'Serif', local: false },\n { name: 'Cantata One', category: 'Serif', local: false },\n { name: 'Domine', category: 'Serif', local: false },\n { name: 'Gentium Plus', category: 'Serif', local: false },\n { name: 'Tinos', category: 'Serif', local: false },\n { name: 'Trirong', category: 'Serif', local: false },\n { name: 'Sorts Mill Goudy', category: 'Serif', local: false },\n { name: 'IM Fell English', category: 'Serif', local: false },\n { name: 'IM Fell DW Pica', category: 'Serif', local: false },\n { name: 'Petrona', category: 'Serif', local: false },\n { name: 'Rozha One', category: 'Serif', local: false },\n { name: 'Tiro Devanagari Hindi', category: 'Serif', local: false },\n // ── Newly added popular serif families ──\n { name: 'Roboto Serif', category: 'Serif', local: false, popular: true },\n { name: 'Roboto Slab', category: 'Serif', local: false, popular: true },\n { name: 'Inria Serif', category: 'Serif', local: false },\n { name: 'Instrument Serif', category: 'Serif', local: false, popular: true },\n { name: 'Young Serif', category: 'Serif', local: false },\n { name: 'Gloock', category: 'Serif', local: false },\n { name: 'Castoro', category: 'Serif', local: false },\n { name: 'Source Serif 4', category: 'Serif', local: false },\n { name: 'IBM Plex Serif', category: 'Serif', local: false },\n { name: 'Pridi', category: 'Serif', local: false },\n { name: 'Eczar', category: 'Serif', local: false },\n { name: 'Faustina', category: 'Serif', local: false },\n\n // ═══════════════════════════════════════════════════════════════════\n // SANS-SERIF — clean, modern, workhorse\n // ═══════════════════════════════════════════════════════════════════\n { name: 'Inter', category: 'Sans-Serif', local: true, popular: true },\n { name: 'Montserrat', category: 'Sans-Serif', local: true, popular: true },\n { name: 'Poppins', category: 'Sans-Serif', local: true, popular: true },\n { name: 'Open Sans', category: 'Sans-Serif', local: true },\n { name: 'Roboto', category: 'Sans-Serif', local: true },\n { name: 'Lato', category: 'Sans-Serif', local: true },\n { name: 'Raleway', category: 'Sans-Serif', local: true },\n { name: 'Nunito', category: 'Sans-Serif', local: true },\n { name: 'Source Sans Pro', category: 'Sans-Serif', local: true },\n { name: 'Work Sans', category: 'Sans-Serif', local: true },\n { name: 'DM Sans', category: 'Sans-Serif', local: true, popular: true },\n { name: 'Outfit', category: 'Sans-Serif', local: true, popular: true },\n { name: 'Figtree', category: 'Sans-Serif', local: true },\n { name: 'Manrope', category: 'Sans-Serif', local: true, popular: true },\n { name: 'Space Grotesk', category: 'Sans-Serif', local: true, popular: true },\n { name: 'Mulish', category: 'Sans-Serif', local: true },\n { name: 'Quicksand', category: 'Sans-Serif', local: true },\n { name: 'Rubik', category: 'Sans-Serif', local: true },\n { name: 'Karla', category: 'Sans-Serif', local: true },\n { name: 'Plus Jakarta Sans', category: 'Sans-Serif', local: true },\n { name: 'Libre Franklin', category: 'Sans-Serif', local: true },\n { name: 'Sora', category: 'Sans-Serif', local: true },\n { name: 'Urbanist', category: 'Sans-Serif', local: true },\n { name: 'Lexend', category: 'Sans-Serif', local: true },\n { name: 'Albert Sans', category: 'Sans-Serif', local: true },\n { name: 'Noto Sans', category: 'Sans-Serif', local: true },\n { name: 'Cabin', category: 'Sans-Serif', local: true },\n { name: 'Barlow', category: 'Sans-Serif', local: true },\n { name: 'Barlow Condensed', category: 'Sans-Serif', local: false },\n { name: 'Josefin Sans', category: 'Sans-Serif', local: true },\n { name: 'Archivo', category: 'Sans-Serif', local: true },\n { name: 'Archivo Narrow', category: 'Sans-Serif', local: false },\n { name: 'Overpass', category: 'Sans-Serif', local: true },\n { name: 'Exo 2', category: 'Sans-Serif', local: true },\n { name: 'Onest', category: 'Sans-Serif', local: false, popular: true },\n { name: 'Be Vietnam Pro', category: 'Sans-Serif', local: false },\n { name: 'Public Sans', category: 'Sans-Serif', local: false },\n { name: 'Red Hat Display', category: 'Sans-Serif', local: false },\n { name: 'Red Hat Text', category: 'Sans-Serif', local: false },\n { name: 'Sen', category: 'Sans-Serif', local: false },\n { name: 'Hanken Grotesk', category: 'Sans-Serif', local: false },\n { name: 'Schibsted Grotesk', category: 'Sans-Serif', local: false },\n { name: 'Reddit Sans', category: 'Sans-Serif', local: false },\n { name: 'Instrument Sans', category: 'Sans-Serif', local: false },\n { name: 'Geist', category: 'Sans-Serif', local: false, popular: true },\n { name: 'Nunito Sans', category: 'Sans-Serif', local: false },\n { name: 'PT Sans', category: 'Sans-Serif', local: false },\n { name: 'PT Sans Narrow', category: 'Sans-Serif', local: false },\n { name: 'Mukta', category: 'Sans-Serif', local: false },\n { name: 'Anek Devanagari', category: 'Sans-Serif', local: false },\n { name: 'Hind', category: 'Sans-Serif', local: true },\n { name: 'Hind Vadodara', category: 'Sans-Serif', local: false },\n // ── Newly added popular sans-serif families (Google Fonts; loaded on demand) ──\n { name: 'Ubuntu', category: 'Sans-Serif', local: false, popular: true },\n { name: 'Ubuntu Condensed', category: 'Sans-Serif', local: false },\n { name: 'Ubuntu Sans', category: 'Sans-Serif', local: false },\n { name: 'Roboto Condensed', category: 'Sans-Serif', local: false, popular: true },\n { name: 'Roboto Flex', category: 'Sans-Serif', local: false },\n { name: 'Jost', category: 'Sans-Serif', local: false, popular: true },\n { name: 'Inter Tight', category: 'Sans-Serif', local: false },\n { name: 'Mona Sans', category: 'Sans-Serif', local: false },\n { name: 'Hubot Sans', category: 'Sans-Serif', local: false },\n { name: 'Funnel Sans', category: 'Sans-Serif', local: false },\n { name: 'Funnel Display', category: 'Sans-Serif', local: false },\n { name: 'Geologica', category: 'Sans-Serif', local: false },\n { name: 'Bricolage Grotesque', category: 'Sans-Serif', local: false, popular: true },\n { name: 'Familjen Grotesk', category: 'Sans-Serif', local: false },\n { name: 'Wix Madefor Display', category: 'Sans-Serif', local: false },\n { name: 'Wix Madefor Text', category: 'Sans-Serif', local: false },\n { name: 'Atkinson Hyperlegible', category: 'Sans-Serif', local: false },\n { name: 'Maven Pro', category: 'Sans-Serif', local: false },\n { name: 'Asap', category: 'Sans-Serif', local: false },\n { name: 'Asap Condensed', category: 'Sans-Serif', local: false },\n { name: 'Saira', category: 'Sans-Serif', local: false },\n { name: 'Saira Condensed', category: 'Sans-Serif', local: false },\n { name: 'Saira Semi Condensed', category: 'Sans-Serif', local: false },\n { name: 'Yanone Kaffeesatz', category: 'Sans-Serif', local: false },\n { name: 'Sarabun', category: 'Sans-Serif', local: false },\n { name: 'Prompt', category: 'Sans-Serif', local: false },\n { name: 'Kanit', category: 'Sans-Serif', local: false, popular: true },\n { name: 'Chivo', category: 'Sans-Serif', local: false },\n { name: 'Commissioner', category: 'Sans-Serif', local: false },\n { name: 'Inria Sans', category: 'Sans-Serif', local: false },\n { name: 'Tomorrow', category: 'Sans-Serif', local: false },\n { name: 'Catamaran', category: 'Sans-Serif', local: false },\n { name: 'Heebo', category: 'Sans-Serif', local: false },\n { name: 'Assistant', category: 'Sans-Serif', local: false },\n { name: 'Cairo', category: 'Sans-Serif', local: false },\n { name: 'Tajawal', category: 'Sans-Serif', local: false },\n\n // ═══════════════════════════════════════════════════════════════════\n // DISPLAY — bold, attention-grabbing headlines\n // ═══════════════════════════════════════════════════════════════════\n { name: 'Bebas Neue', category: 'Display', local: true, popular: true },\n { name: 'Anton', category: 'Display', local: true, popular: true },\n { name: 'Oswald', category: 'Display', local: true },\n { name: 'Abril Fatface', category: 'Display', local: true, popular: true },\n { name: 'League Spartan', category: 'Display', local: true },\n { name: 'Teko', category: 'Display', local: true },\n { name: 'Righteous', category: 'Display', local: false },\n { name: 'Alfa Slab One', category: 'Display', local: false, popular: true },\n { name: 'Archivo Black', category: 'Display', local: false },\n { name: 'Fredoka', category: 'Display', local: false },\n { name: 'Passion One', category: 'Display', local: false },\n { name: 'Bowlby One', category: 'Display', local: false },\n { name: 'Bowlby One SC', category: 'Display', local: false },\n { name: 'Secular One', category: 'Display', local: false },\n { name: 'Lilita One', category: 'Display', local: false },\n { name: 'Titan One', category: 'Display', local: false },\n { name: 'Russo One', category: 'Display', local: false },\n { name: 'Staatliches', category: 'Display', local: false, popular: true },\n { name: 'Dela Gothic One', category: 'Display', local: false },\n { name: 'Ultra', category: 'Display', local: false },\n { name: 'Sigmar One', category: 'Display', local: false },\n { name: 'Sigmar', category: 'Display', local: false },\n { name: 'Modak', category: 'Display', local: false },\n { name: 'Bagel Fat One', category: 'Display', local: false },\n { name: 'Climate Crisis', category: 'Display', local: false },\n { name: 'Yatra One', category: 'Display', local: false },\n { name: 'Bungee', category: 'Display', local: false },\n { name: 'Bungee Shade', category: 'Display', local: false },\n { name: 'Bungee Outline', category: 'Display', local: false },\n { name: 'Bungee Inline', category: 'Display', local: false },\n { name: 'Monoton', category: 'Display', local: false, popular: true },\n { name: 'Black Ops One', category: 'Display', local: false },\n { name: 'Faster One', category: 'Display', local: false },\n { name: 'Rubik Glitch', category: 'Display', local: false },\n { name: 'Rubik Mono One', category: 'Display', local: false },\n { name: 'Rubik Wet Paint', category: 'Display', local: false },\n { name: 'Rubik Bubbles', category: 'Display', local: false },\n { name: 'Rubik Beastly', category: 'Display', local: false },\n { name: 'Rubik Burned', category: 'Display', local: false },\n { name: 'Rubik Distressed', category: 'Display', local: false },\n { name: 'Rubik Iso', category: 'Display', local: false },\n { name: 'Rubik Marker Hatch', category: 'Display', local: false },\n { name: 'Rubik Maze', category: 'Display', local: false },\n { name: 'Rubik Pixels', category: 'Display', local: false },\n { name: 'Rubik Puddles', category: 'Display', local: false },\n { name: 'Rubik Spray Paint', category: 'Display', local: false },\n { name: 'Rubik Vinyl', category: 'Display', local: false },\n { name: 'Saira Stencil One', category: 'Display', local: false },\n { name: 'Audiowide', category: 'Display', local: false },\n { name: 'Orbitron', category: 'Display', local: false },\n { name: 'Plaster', category: 'Display', local: false },\n // ── Newly added display families ──\n { name: 'Black Han Sans', category: 'Display', local: false },\n { name: 'Bungee Spice', category: 'Display', local: false },\n { name: 'Sansita Swashed', category: 'Display', local: false },\n { name: 'Honk', category: 'Display', local: false },\n { name: 'Sixtyfour', category: 'Display', local: false },\n\n // ═══════════════════════════════════════════════════════════════════\n // HANDWRITING / SCRIPT — fluid, personal, calligraphic\n // ═══════════════════════════════════════════════════════════════════\n { name: 'Dancing Script', category: 'Handwriting', local: true, popular: true },\n { name: 'Pacifico', category: 'Handwriting', local: true, popular: true },\n { name: 'Great Vibes', category: 'Handwriting', local: true, popular: true },\n { name: 'Sacramento', category: 'Handwriting', local: true },\n { name: 'Alex Brush', category: 'Handwriting', local: true },\n { name: 'Allura', category: 'Handwriting', local: true },\n { name: 'Caveat', category: 'Handwriting', local: true },\n { name: 'Caveat Brush', category: 'Handwriting', local: false },\n { name: 'Lobster', category: 'Handwriting', local: true },\n { name: 'Lobster Two', category: 'Handwriting', local: false },\n { name: 'Comfortaa', category: 'Handwriting', local: true },\n { name: 'Tangerine', category: 'Handwriting', local: false, popular: true },\n { name: 'Yellowtail', category: 'Handwriting', local: false, popular: true },\n { name: 'Kaushan Script', category: 'Handwriting', local: false, popular: true },\n { name: 'Parisienne', category: 'Handwriting', local: false },\n { name: 'Petit Formal Script', category: 'Handwriting', local: false },\n { name: 'Pinyon Script', category: 'Handwriting', local: false },\n { name: 'Mrs Saint Delafield', category: 'Handwriting', local: false },\n { name: 'Marck Script', category: 'Handwriting', local: false },\n { name: 'Niconne', category: 'Handwriting', local: false },\n { name: 'Homemade Apple', category: 'Handwriting', local: false },\n { name: 'Permanent Marker', category: 'Handwriting', local: false },\n { name: 'Reenie Beanie', category: 'Handwriting', local: false },\n { name: 'Satisfy', category: 'Handwriting', local: false },\n { name: 'Kalam', category: 'Handwriting', local: false },\n { name: 'Indie Flower', category: 'Handwriting', local: false },\n { name: 'Courgette', category: 'Handwriting', local: false },\n { name: 'Cookie', category: 'Handwriting', local: false },\n { name: 'Shadows Into Light', category: 'Handwriting', local: false },\n { name: 'Patrick Hand', category: 'Handwriting', local: false },\n { name: 'Amatic SC', category: 'Handwriting', local: false },\n { name: 'Architects Daughter', category: 'Handwriting', local: false },\n { name: 'Gloria Hallelujah', category: 'Handwriting', local: false },\n { name: 'La Belle Aurore', category: 'Handwriting', local: false },\n { name: 'Mr Dafoe', category: 'Handwriting', local: false },\n { name: 'Italianno', category: 'Handwriting', local: false },\n { name: 'Rouge Script', category: 'Handwriting', local: false },\n { name: 'Grand Hotel', category: 'Handwriting', local: false },\n { name: 'Bilbo Swash Caps', category: 'Handwriting', local: false },\n\n // ═══════════════════════════════════════════════════════════════════\n // DECORATIVE / FUN — quirky, themed, special-occasion\n // ═══════════════════════════════════════════════════════════════════\n { name: 'Frijole', category: 'Decorative', local: false },\n { name: 'Creepster', category: 'Decorative', local: false },\n { name: 'Nosifer', category: 'Decorative', local: false },\n { name: 'Ewert', category: 'Decorative', local: false },\n { name: 'Lakki Reddy', category: 'Decorative', local: false },\n { name: 'Henny Penny', category: 'Decorative', local: false },\n { name: 'Special Elite', category: 'Decorative', local: false, popular: true },\n { name: 'Vast Shadow', category: 'Decorative', local: false },\n { name: 'Almendra Display', category: 'Decorative', local: false },\n { name: 'Eater', category: 'Decorative', local: false },\n { name: 'Butcherman', category: 'Decorative', local: false },\n { name: 'Pirata One', category: 'Decorative', local: false },\n { name: 'Metamorphous', category: 'Decorative', local: false },\n { name: 'MedievalSharp', category: 'Decorative', local: false },\n { name: 'Fascinate', category: 'Decorative', local: false },\n { name: 'Fascinate Inline', category: 'Decorative', local: false },\n { name: 'Sancreek', category: 'Decorative', local: false },\n { name: 'Smokum', category: 'Decorative', local: false },\n { name: 'Vampiro One', category: 'Decorative', local: false },\n { name: 'Mountains of Christmas', category: 'Decorative', local: false },\n { name: 'Caesar Dressing', category: 'Decorative', local: false },\n { name: 'Megrim', category: 'Decorative', local: false },\n\n // ═══════════════════════════════════════════════════════════════════\n // BLACKLETTER — gothic, medieval, formal\n // ═══════════════════════════════════════════════════════════════════\n { name: 'UnifrakturCook', category: 'Blackletter', local: false },\n { name: 'UnifrakturMaguntia', category: 'Blackletter', local: false },\n\n // ═══════════════════════════════════════════════════════════════════\n // MONOSPACE — code, technical\n // ═══════════════════════════════════════════════════════════════════\n { name: 'Roboto Mono', category: 'Monospace', local: true },\n { name: 'Fira Code', category: 'Monospace', local: true },\n { name: 'JetBrains Mono', category: 'Monospace', local: true },\n { name: 'Source Code Pro', category: 'Monospace', local: true },\n { name: 'IBM Plex Mono', category: 'Monospace', local: true },\n { name: 'Space Mono', category: 'Monospace', local: true },\n { name: 'Geist Mono', category: 'Monospace', local: false },\n { name: 'DM Mono', category: 'Monospace', local: false },\n { name: 'Inconsolata', category: 'Monospace', local: false },\n { name: 'Cousine', category: 'Monospace', local: false },\n { name: 'Anonymous Pro', category: 'Monospace', local: false },\n { name: 'Cutive Mono', category: 'Monospace', local: false },\n { name: 'Major Mono Display', category: 'Monospace', local: false },\n { name: 'VT323', category: 'Monospace', local: false },\n { name: 'Share Tech Mono', category: 'Monospace', local: false },\n // ── Newly added monospace families ──\n { name: 'Ubuntu Mono', category: 'Monospace', local: false, popular: true },\n { name: 'Ubuntu Sans Mono', category: 'Monospace', local: false },\n { name: 'Noto Sans Mono', category: 'Monospace', local: false },\n { name: 'Martian Mono', category: 'Monospace', local: false },\n { name: 'Atkinson Hyperlegible Mono', category: 'Monospace', local: false },\n];\n\n/** Quick lookup: normalized name → font entry */\nconst _fontLookupCache = new Map<string, FontEntry>();\nexport function findFontEntry(name: string): FontEntry | undefined {\n const key = name.toLowerCase().replace(/[\\s\\-_]/g, '');\n if (_fontLookupCache.has(key)) return _fontLookupCache.get(key);\n const entry = EXTENDED_FONT_LIST.find(f =>\n f.name.toLowerCase().replace(/[\\s\\-_]/g, '') === key\n );\n if (entry) _fontLookupCache.set(key, entry);\n return entry;\n}\n","import * as fabric from 'fabric';\n\n// ============================================\n// FABRIC OBJECT METADATA\n// ============================================\nexport type FabricObjectWithMeta = fabric.FabricObject & {\n __docuforgeId?: string; // Element ID for individual objects\n __docuforgeGroupId?: string; // Group ID for fabric.Group objects\n};\n\nexport const getObjectId = (obj: fabric.FabricObject): string | undefined =>\n (obj as FabricObjectWithMeta).__docuforgeId;\n\nexport const getFabricGroupId = (obj: fabric.FabricObject): string | undefined =>\n (obj as FabricObjectWithMeta).__docuforgeGroupId;\n\nexport const setObjectData = (obj: fabric.FabricObject, id: string): void => {\n (obj as FabricObjectWithMeta).__docuforgeId = id;\n};\n\nexport const setFabricGroupId = (obj: fabric.FabricObject, groupId: string): void => {\n (obj as FabricObjectWithMeta).__docuforgeGroupId = groupId;\n};\n","/**\n * Font Loading Utilities\n *\n * Long-standing issue (since early in the project): text overflowing its box on load\n * because bounds were measured before fonts were ready. Fabric and our text measurement\n * use font metrics; if fonts load after first paint, we get wrong width/height.\n *\n * Safeguards in place:\n * - preloadAllFonts() + document.fonts.ready before first canvas sync (PageCanvas)\n * - Preload fonts used by text elements on the current page (not just FONTS_TO_PRELOAD)\n * - clearFabricCharCache() before setReady so Fabric doesn't use stale char width cache\n * - clearMeasurementCache() so getMinTextWidth / measureTextHeight don't use old cache\n * - setupFontLoadingListener: on late font load, reflow textboxes and persist height to store\n * - ensureFontLoaded: automatically loads Google Fonts on-demand for non-local fonts\n */\n\nimport * as fabric from 'fabric';\nimport { LOCAL_FONTS, loadGoogleFont, loadFont as loadFontUnified } from '@/lib/googleFonts';\nimport { getObjectId } from '@/lib/fabricUtils';\n\n// List of all fonts used in the application\nexport const FONTS_TO_PRELOAD = [\n 'Open Sans',\n 'Playfair Display',\n 'Merriweather',\n 'Lora',\n 'Montserrat',\n 'Roboto',\n 'Lato',\n 'Raleway',\n 'Poppins',\n 'Inter',\n 'Nunito',\n 'Source Sans Pro',\n 'Work Sans',\n 'Oswald',\n 'Bebas Neue',\n 'Abril Fatface',\n 'Dancing Script',\n 'Pacifico',\n 'Great Vibes',\n // Newly added local fonts\n 'DM Sans',\n 'Outfit',\n 'Figtree',\n 'Manrope',\n 'Space Grotesk',\n 'League Spartan',\n 'EB Garamond',\n 'Libre Baskerville',\n 'Crimson Text',\n 'DM Serif Display',\n 'Libre Franklin',\n 'Mulish',\n 'Quicksand',\n 'Rubik',\n 'Karla',\n 'Plus Jakarta Sans',\n 'Sora',\n 'Urbanist',\n 'Lexend',\n 'Albert Sans',\n 'Noto Sans',\n 'Cabin',\n 'Barlow',\n 'Josefin Sans',\n 'Archivo',\n 'Overpass',\n 'Exo 2',\n 'Roboto Mono',\n 'Fira Code',\n 'JetBrains Mono',\n 'Source Code Pro',\n 'IBM Plex Mono',\n 'Space Mono',\n 'Sacramento',\n 'Alex Brush',\n 'Allura',\n 'Caveat',\n 'Lobster',\n 'Comfortaa',\n 'Anton',\n 'Teko',\n 'Hind',\n];\n\n// Track font loading state globally\nlet fontsLoaded = false;\nlet fontsLoadingPromise: Promise<void> | null = null;\n\nconst withFontTimeout = async <T,>(promise: Promise<T>, timeoutMs = 4000): Promise<T | void> => {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<void>((resolve) => {\n timeoutId = setTimeout(resolve, timeoutMs);\n }),\n ]);\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n};\n\n/**\n * Preload a specific font by using the CSS Font Loading API\n */\nexport const preloadFont = async (fontFamily: string): Promise<boolean> => {\n try {\n if (document.fonts) {\n await document.fonts.load(`16px \"${fontFamily}\"`);\n await document.fonts.load(`bold 16px \"${fontFamily}\"`);\n return true;\n }\n return false;\n } catch (e) {\n console.warn(`Failed to preload font: ${fontFamily}`, e);\n return false;\n }\n};\n\n/**\n * Preload all fonts used in the application\n * Returns a promise that resolves when all fonts are loaded\n */\nexport const preloadAllFonts = async (): Promise<void> => {\n if (fontsLoaded) return;\n \n if (fontsLoadingPromise) {\n return fontsLoadingPromise;\n }\n \n fontsLoadingPromise = (async () => {\n if (document.fonts) {\n await withFontTimeout(document.fonts.ready, 2500);\n }\n await withFontTimeout(Promise.all(FONTS_TO_PRELOAD.map(font => preloadFont(font))).then(() => undefined), 5000);\n // Wait again so the browser has applied the new fonts before we resolve (reduces intermittent wrong metrics)\n if (document.fonts) {\n await withFontTimeout(document.fonts.ready, 2500);\n }\n fontsLoaded = true;\n })();\n\n return fontsLoadingPromise;\n};\n\n/** Call after loading page-specific fonts; ensures browser has applied them before first sync. */\nexport const waitForFontsReady = async (): Promise<void> => {\n if (!document.fonts) return;\n await withFontTimeout(document.fonts.ready, 2500);\n};\n\nconst DEFAULT_FONT_CHECK_TIMEOUT_MS = 3500;\nconst FONT_CHECK_POLL_MS = 60;\n\n/**\n * Resolves when the browser reports all given fonts as loaded (document.fonts.check),\n * or after timeout. Polls so we don't setReady until fonts are actually available.\n */\nexport const waitUntilFontsAvailable = async (\n fontFamilies: string[],\n options?: { timeoutMs?: number; pollIntervalMs?: number }\n): Promise<void> => {\n if (!document.fonts || fontFamilies.length === 0) return;\n const timeoutMs = options?.timeoutMs ?? DEFAULT_FONT_CHECK_TIMEOUT_MS;\n const pollMs = options?.pollIntervalMs ?? FONT_CHECK_POLL_MS;\n const deadline = Date.now() + timeoutMs;\n const check = (): boolean =>\n fontFamilies.every(\n (f) => document.fonts!.check(`16px \"${f}\"`) && document.fonts!.check(`bold 16px \"${f}\"`)\n );\n while (!check()) {\n if (Date.now() >= deadline) break;\n await new Promise((r) => setTimeout(r, pollMs));\n }\n};\n\n/**\n * Check if fonts have been loaded\n */\nexport const areFontsLoaded = (): boolean => fontsLoaded;\n\n/**\n * Clear only Fabric's global character width cache (no canvas needed).\n * Call this after fonts load and before creating/measuring text so Fabric\n * doesn't use stale metrics from before fonts were ready.\n */\nexport const clearFabricCharCache = (): void => {\n const fabricAny = fabric as any;\n if (fabricAny.cache && typeof fabricAny.cache.clearFontCache === 'function') {\n fabricAny.cache.clearFontCache();\n }\n if (fabricAny.cache?.charWidthsCache instanceof Map) {\n fabricAny.cache.charWidthsCache.clear();\n }\n if (typeof fabricAny.charWidthsCache === 'object' && fabricAny.charWidthsCache !== null) {\n if (fabricAny.charWidthsCache instanceof Map) {\n fabricAny.charWidthsCache.clear();\n } else {\n Object.keys(fabricAny.charWidthsCache).forEach(key => {\n delete fabricAny.charWidthsCache[key];\n });\n }\n }\n if (typeof fabric.util !== 'undefined' && typeof (fabric.util as any).clearFabricFontCache === 'function') {\n (fabric.util as any).clearFabricFontCache();\n }\n};\n\n/**\n * Clear Fabric.js font cache and re-render all textboxes on a canvas\n * This should be called after fonts are loaded to fix text measurement issues\n */\nexport const clearFontCacheAndRerender = (\n canvas: fabric.Canvas,\n options: { clearGlobalCharCache?: boolean } = {},\n): void => {\n if (options.clearGlobalCharCache !== false) clearFabricCharCache();\n\n const logUnderlineDebug = (stage: string, payload: unknown) => {\n try {\n console.log(`[canvas-renderer][underline-debug] ${stage} ${JSON.stringify(payload)}`);\n } catch {\n console.log('[canvas-renderer][underline-debug]', stage, payload);\n }\n };\n\n const collectUnderlineMetrics = (obj: fabric.Object): Array<Record<string, unknown>> => {\n if (obj instanceof fabric.Textbox) {\n if (!obj.underline) return [];\n const lineWidths = (obj as any).__lineWidths as number[] | undefined;\n return [{\n id: getObjectId(obj) ?? null,\n text: (obj.text || '').slice(0, 120),\n textLength: obj.text?.length ?? 0,\n fontFamily: obj.fontFamily,\n fontSize: obj.fontSize,\n fontWeight: obj.fontWeight,\n width: obj.width ?? null,\n height: obj.height ?? null,\n scaleX: obj.scaleX,\n scaleY: obj.scaleY,\n lineCount: obj.textLines?.length ?? 0,\n maxLineWidth: lineWidths && lineWidths.length > 0 ? Math.max(...lineWidths) : null,\n }];\n }\n if (obj instanceof fabric.Group) {\n return ((obj as any)._objects || []).flatMap((child: fabric.Object) => collectUnderlineMetrics(child));\n }\n return [];\n };\n\n const beforeMetrics = canvas.getObjects().flatMap(collectUnderlineMetrics);\n if (beforeMetrics.length > 0) {\n logUnderlineDebug('before-rerender', beforeMetrics);\n }\n\n // Mark textboxes dirty so Fabric re-renders them with the now-loaded fonts,\n // but DO NOT call initDimensions / _clearCache. Those wipe `__lineWidths`\n // (the per-line metrics that underline geometry depends on) and the underline\n // then falls back to the full container width instead of the actual text width.\n // Fabric repopulates `__lineWidths` naturally on the next render() pass.\n const markDirty = (obj: fabric.Object) => {\n if (obj instanceof fabric.Textbox) {\n obj.dirty = true;\n } else if (obj instanceof fabric.Group) {\n (obj as any)._objects?.forEach(markDirty);\n obj.dirty = true;\n }\n };\n\n canvas.getObjects().forEach(markDirty);\n\n const afterMetrics = canvas.getObjects().flatMap(collectUnderlineMetrics);\n if (afterMetrics.length > 0) {\n logUnderlineDebug('after-rerender', afterMetrics);\n }\n \n canvas.requestRenderAll();\n};\n\n/**\n * Ensure a specific font is loaded before using it.\n * For local fonts (TTF in public/fonts/), uses CSS Font Loading API.\n * For non-local fonts, dynamically loads from Google Fonts.\n */\nexport const ensureFontLoaded = async (fontFamily: string): Promise<void> => {\n if (!fontFamily) return;\n\n // If it's a local font, just check/load via browser API\n if (LOCAL_FONTS.has(fontFamily)) {\n try {\n const isLoaded = document.fonts?.check(`16px \"${fontFamily}\"`);\n if (isLoaded) return;\n await document.fonts?.load(`16px \"${fontFamily}\"`);\n await document.fonts?.load(`bold 16px \"${fontFamily}\"`);\n } catch (e) {\n console.warn(`Failed to ensure local font loaded: ${fontFamily}`, e);\n }\n return;\n }\n\n // For non-local fonts, dispatch through the unified loader so Fontshare\n // families (Excon, Satoshi, Clash Display, ...) load via Fontshare's CSS\n // API instead of Google Fonts (which 404s for them and leaves the canvas\n // measuring with a system fallback until the user \"wakes it up\" by\n // selecting the element — at which point FontPicker calls loadFont()\n // and the real font finally swaps in).\n try {\n await loadFontUnified(fontFamily);\n } catch (e) {\n console.warn(`Failed to load font: ${fontFamily}`, e);\n try { await loadGoogleFont(fontFamily); } catch {}\n }\n // Block on actual binary load so the next synchronous Fabric measurement\n // uses the real font (matches the awaitFontsForConfig polling pattern).\n try {\n if (document.fonts) {\n await Promise.race([\n Promise.all([\n document.fonts.load(`16px \"${fontFamily}\"`),\n document.fonts.load(`bold 16px \"${fontFamily}\"`),\n document.fonts.load(`italic 16px \"${fontFamily}\"`),\n document.fonts.load(`bold italic 16px \"${fontFamily}\"`),\n ]),\n new Promise((r) => setTimeout(r, 2500)),\n ]);\n }\n } catch {}\n};\n\n/**\n * Setup font loading listener for a canvas\n * Automatically re-renders textboxes when fonts finish loading\n * @param afterRerender - Optional callback run after reflow (e.g. persist text dimensions to store)\n * Returns a cleanup function to remove the listener\n */\nexport const setupFontLoadingListener = (\n canvas: fabric.Canvas,\n afterRerender?: (canvas: fabric.Canvas) => void,\n options: { clearGlobalCharCache?: boolean } = {},\n): (() => void) => {\n const handleFontLoad = () => {\n clearFontCacheAndRerender(canvas, options);\n afterRerender?.(canvas);\n };\n\n if (document.fonts) {\n document.fonts.addEventListener('loadingdone', handleFontLoad);\n }\n\n return () => {\n if (document.fonts) {\n document.fonts.removeEventListener('loadingdone', handleFontLoad);\n }\n };\n};\n\n// Start preloading fonts immediately when this module is imported\n// This ensures fonts start loading as early as possible\npreloadAllFonts();\n","import * as fabric from 'fabric';\nimport { CanvasElement } from '@/types/editor';\nimport { setObjectData, getObjectId } from './fabricUtils';\nimport { updateCoverLayout, createMaskedImageElement } from './canvaMaskedImage';\nimport type { MutableRefObject } from 'react';\n\nimport { API_URL } from '@/lib/api';\n\n// ── In-memory caches to avoid re-fetching on theme switches ──\n\n/** Cache fetched SVG text by URL so repeated loads skip the network. */\nconst svgTextCache = new Map<string, string | null>();\n\n/** Cache resolved HTMLImageElements by URL so Fabric.fromURL hits memory. */\nconst htmlImageCache = new Map<string, HTMLImageElement>();\n\nconst MAX_CACHE_ENTRIES = 200;\n\nfunction trimCache<K, V>(map: Map<K, V>) {\n if (map.size > MAX_CACHE_ENTRIES) {\n const keysToDelete = Array.from(map.keys()).slice(0, map.size - MAX_CACHE_ENTRIES);\n keysToDelete.forEach(k => map.delete(k));\n }\n}\n\n/**\n * Preload an image URL into the browser's in-memory cache.\n * Subsequent fabric.FabricImage.fromURL calls for the same URL\n * will resolve from memory instead of hitting the network.\n */\nexport function preloadImage(url: string): Promise<HTMLImageElement> {\n const cached = htmlImageCache.get(url);\n if (cached) return Promise.resolve(cached);\n\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.onload = () => {\n htmlImageCache.set(url, img);\n trimCache(htmlImageCache);\n resolve(img);\n };\n img.onerror = reject;\n img.src = url;\n });\n}\n\n/**\n * Batch-preload multiple image URLs in parallel.\n * Best called before mounting the canvas so assets are warm.\n */\nexport function preloadImages(urls: string[]): Promise<void> {\n const unique = [...new Set(urls)].filter(u => u && !htmlImageCache.has(u));\n if (unique.length === 0) return Promise.resolve();\n return Promise.allSettled(unique.map(preloadImage)).then(() => {});\n}\n\n/** Check if a URL points to a private/localhost host that can't be proxied. */\nexport function isPrivateUrl(url: string): boolean {\n try {\n const h = new URL(url).hostname.toLowerCase();\n return h === 'localhost' || h === '127.0.0.1' || h === '0.0.0.0' || h.endsWith('.local') || /^(10\\.|192\\.168\\.|169\\.254\\.)/.test(h);\n } catch { return false; }\n}\n\n// ─── Bundled-asset prefix support ───────────────────────────────────────\n// Hosts can ship a build-time snapshot of templates where image URLs are\n// rewritten to same-app static paths (e.g. `/pixldocs-bundled-assets/<hash>.svg`).\n// Those URLs are served directly by the host (Next.js / Vite `public/` folder)\n// and MUST NOT be routed through the Supabase image-proxy: the proxy needs an\n// absolute URL, and treating `localhost` as \"private\" would blank them out.\n\nconst DEFAULT_BUNDLED_PREFIXES = ['/pixldocs-bundled-assets/'];\nlet bundledPrefixes: string[] = [...DEFAULT_BUNDLED_PREFIXES];\n\n/**\n * Configure additional URL path prefixes that should be treated as\n * same-origin bundled static assets (skip proxy, skip private-URL guard).\n * Hosts call this once at startup. Always includes `/pixldocs-bundled-assets/`.\n */\nexport function setBundledAssetPrefixes(prefixes: string[]): void {\n const combined = new Set<string>([...DEFAULT_BUNDLED_PREFIXES]);\n for (const p of prefixes || []) {\n if (typeof p === 'string' && p.startsWith('/')) combined.add(p);\n }\n bundledPrefixes = Array.from(combined);\n}\n\nfunction pathnameStartsWithBundledPrefix(pathname: string): boolean {\n return bundledPrefixes.some((prefix) => pathname.startsWith(prefix));\n}\n\n/**\n * Returns true if `url` points to a host-served bundled asset.\n * Accepts either a relative path (`/pixldocs-bundled-assets/...`) or an\n * absolute same-origin URL whose pathname starts with a bundled prefix.\n */\nexport function isBundledAssetUrl(url: string): boolean {\n if (!url) return false;\n // Relative path form\n if (url.startsWith('/') && !url.startsWith('//')) {\n return pathnameStartsWithBundledPrefix(url);\n }\n try {\n const parsed = new URL(url);\n if (typeof window !== 'undefined' && parsed.origin !== window.location.origin) {\n return false;\n }\n return pathnameStartsWithBundledPrefix(parsed.pathname);\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve a bundled-asset URL (relative or absolute same-origin) to an\n * absolute URL the browser can load directly. Returns null if not bundled.\n */\nfunction resolveBundledAssetUrl(url: string): string | null {\n if (!url) return null;\n if (url.startsWith('/') && !url.startsWith('//') && pathnameStartsWithBundledPrefix(url)) {\n const origin = typeof window !== 'undefined' ? window.location.origin : '';\n return origin ? new URL(url, origin).toString() : url;\n }\n try {\n const parsed = new URL(url);\n if (typeof window !== 'undefined' && parsed.origin !== window.location.origin) return null;\n if (pathnameStartsWithBundledPrefix(parsed.pathname)) return parsed.toString();\n } catch {\n return null;\n }\n return null;\n}\n\n// Throttle the noisy \"Skipping private URL\" log to once per session per URL.\nconst loggedPrivateSkips = new Set<string>();\n\n/** Convert a storage URL to a public URL when possible (bucket is public). */\nfunction toPublicStorageUrl(url: string): string | null {\n try {\n const parsed = new URL(url);\n const origin = parsed.origin;\n\n // Match signed URL pattern: /storage/v1/object/sign/<bucket>/<path>?token=...\n const signedMatch = parsed.pathname.match(/\\/storage\\/v1\\/object\\/sign\\/([^?]+)/);\n if (signedMatch) {\n return `${origin}/storage/v1/object/public/${signedMatch[1]}`;\n }\n\n // Already a public storage URL — no proxy needed\n if (parsed.pathname.includes('/storage/v1/object/public/')) return url;\n } catch {\n return null;\n }\n\n return null;\n}\n\n/**\n * CloudFront asset URLs currently need the image proxy because the CDN response\n * does not include browser-safe CORS headers for Fabric/image canvas loading.\n */\n\nexport function getProxiedImageUrl(imageUrl: string): string {\n if (!imageUrl) return '';\n if (imageUrl.startsWith('data:') || imageUrl.startsWith('blob:')) return imageUrl;\n // Same-origin bundled static assets: bypass proxy and private-URL guard.\n // Works for both relative paths (`/pixldocs-bundled-assets/x.svg`) and\n // absolute same-origin URLs (`http://localhost:3000/pixldocs-bundled-assets/x.svg`).\n const bundled = resolveBundledAssetUrl(imageUrl);\n if (bundled) return bundled;\n // Relative URLs that aren't bundled assets: resolve to same-origin so the\n // browser/Fabric can load them directly (the proxy can't handle bare paths).\n if (imageUrl.startsWith('/') && !imageUrl.startsWith('//')) {\n if (typeof window !== 'undefined') return new URL(imageUrl, window.location.origin).toString();\n return imageUrl;\n }\n if (isPrivateUrl(imageUrl)) {\n if (!loggedPrivateSkips.has(imageUrl)) {\n loggedPrivateSkips.add(imageUrl);\n console.debug('[image-proxy] Skipping private URL:', imageUrl.substring(0, 80));\n }\n return '';\n }\n // Supabase storage URLs don't need proxying — use public URL directly\n const publicUrl = toPublicStorageUrl(imageUrl);\n if (publicUrl) return publicUrl;\n return `${API_URL}/image-proxy?url=${encodeURIComponent(imageUrl)}`;\n}\n\n/** Whether the image is SVG (by URL or explicit format). */\nexport function isSvgImage(imageUrl: string, sourceFormat?: 'svg' | 'png'): boolean {\n if (sourceFormat === 'svg') return true;\n const lower = (imageUrl || '').toLowerCase();\n return lower.includes('.svg') || lower.startsWith('data:image/svg+xml');\n}\n\n/** Parse width/height from SVG string (viewBox \"0 0 W H\" or width/height attributes). */\nexport function parseSvgDimensionsFromText(svgText: string): { width: number; height: number } | null {\n if (!svgText || typeof svgText !== 'string') return null;\n const viewBoxMatch = svgText.match(/viewBox\\s*=\\s*[\"']?\\s*(-?[\\d.]+)\\s+(-?[\\d.]+)\\s+([\\d.]+)\\s+([\\d.]+)/i);\n if (viewBoxMatch) {\n const w = parseFloat(viewBoxMatch[3]);\n const h = parseFloat(viewBoxMatch[4]);\n if (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) return { width: w, height: h };\n }\n const widthMatch = svgText.match(/\\bwidth\\s*=\\s*[\"']?\\s*([\\d.]+)/i);\n const heightMatch = svgText.match(/\\bheight\\s*=\\s*[\"']?\\s*([\\d.]+)/i);\n if (widthMatch && heightMatch) {\n const w = parseFloat(widthMatch[1]);\n const h = parseFloat(heightMatch[1]);\n if (Number.isFinite(w) && Number.isFinite(h) && w > 0 && h > 0) return { width: w, height: h };\n }\n return null;\n}\n\n/** Fetch SVG from URL and return its text. Public wrapper that also accepts sourceFormat. */\nexport async function fetchSvgTextPublic(imageUrl: string, sourceFormat?: 'svg' | 'png'): Promise<string | null> {\n return fetchSvgText(imageUrl, sourceFormat);\n}\n\nasync function fetchSvgText(imageUrl: string, sourceFormat?: 'svg' | 'png'): Promise<string | null> {\n try {\n // Handle inline SVG data URLs directly (no caching needed)\n if (imageUrl.startsWith('data:image/svg+xml;base64,')) {\n return atob(imageUrl.slice('data:image/svg+xml;base64,'.length));\n }\n if (imageUrl.startsWith('data:image/svg+xml,')) {\n return decodeURIComponent(imageUrl.slice('data:image/svg+xml,'.length).replace(/\\+/g, ' '));\n }\n\n // Check in-memory cache first\n if (svgTextCache.has(imageUrl)) {\n return svgTextCache.get(imageUrl) ?? null;\n }\n\n // For non-SVG-looking sources, still attempt fetch if sourceFormat says svg\n const canBeSvg = sourceFormat === 'svg' || isSvgImage(imageUrl, sourceFormat) || imageUrl.startsWith('blob:') || imageUrl.startsWith('http');\n if (!canBeSvg) return null;\n\n const fetchWithTimeout = async (url: string) => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 8000);\n try {\n return await fetch(url, { signal: controller.signal });\n } finally {\n clearTimeout(timeoutId);\n }\n };\n\n const url = imageUrl.startsWith('blob:') || imageUrl.startsWith('data:')\n ? imageUrl\n : getProxiedImageUrl(imageUrl);\n\n const res = await fetchWithTimeout(url);\n if (!res.ok) {\n svgTextCache.set(imageUrl, null);\n return null;\n }\n\n const text = await res.text();\n // Guard: only treat as SVG when markup actually contains <svg ...>\n if (!/<svg[\\s>]/i.test(text)) {\n svgTextCache.set(imageUrl, null);\n return null;\n }\n svgTextCache.set(imageUrl, text);\n trimCache(svgTextCache);\n return text;\n } catch {\n return null;\n }\n}\n\n/** Fetch SVG from URL and return its intrinsic dimensions (viewBox or width/height). */\nexport async function loadSvgDimensions(imageUrl: string): Promise<{ width: number; height: number } | null> {\n const text = await fetchSvgText(imageUrl);\n return text ? parseSvgDimensionsFromText(text) : null;\n}\n\n/**\n * Ensure root <svg> has explicit width and height (from viewBox if missing) so the browser\n * renders at the correct size. Returns modified SVG string.\n */\nfunction injectSvgExplicitDimensions(svgText: string, width: number, height: number): string {\n if (!svgText || width <= 0 || height <= 0) return svgText;\n const w = String(Math.round(width));\n const h = String(Math.round(height));\n // Replace or add width/height on the opening <svg ...> tag\n const svgOpenMatch = svgText.match(/<svg([^>]*)>/i);\n if (!svgOpenMatch) return svgText;\n const attrs = svgOpenMatch[1];\n let newAttrs = attrs\n .replace(/\\bwidth\\s*=\\s*[\"'][^\"']*[\"']/gi, `width=\"${w}\"`)\n .replace(/\\bheight\\s*=\\s*[\"'][^\"']*[\"']/gi, `height=\"${h}\"`);\n if (!/\\bwidth\\s*=/i.test(newAttrs)) newAttrs = ` width=\"${w}\"${newAttrs}`;\n if (!/\\bheight\\s*=/i.test(newAttrs)) newAttrs = ` height=\"${h}\"${newAttrs}`;\n return svgText.replace(/<svg[^>]*>/i, `<svg${newAttrs}>`);\n}\n\n/**\n * For SVG URLs: fetch SVG, inject explicit width/height from viewBox so the browser\n * renders at correct intrinsic size. Returns a data URL so Fabric's image loads with\n * correct naturalWidth/naturalHeight and the full image is not clipped.\n * Returns null for non-SVG or on failure (caller should use original URL).\n */\nexport async function getNormalizedSvgUrl(imageUrl: string, colorMap?: Record<string, string>, sourceFormat?: 'svg' | 'png'): Promise<string | null> {\n if (!isSvgImage(imageUrl, sourceFormat)) return null;\n let text = await fetchSvgText(imageUrl, sourceFormat);\n if (!text) return null;\n // Apply color replacements if provided\n if (colorMap && Object.keys(colorMap).length > 0) {\n const { applySvgColorMap } = await import('./svgColorUtils');\n text = applySvgColorMap(text, colorMap);\n }\n const dims = parseSvgDimensionsFromText(text);\n if (!dims || dims.width <= 0 || dims.height <= 0) return null;\n const normalized = injectSvgExplicitDimensions(text, dims.width, dims.height);\n const encoded = encodeURIComponent(normalized);\n return `data:image/svg+xml,${encoded}`;\n}\n\n/**\n * Normalize Fabric image dimensions for SVG. Browsers often report 0 or wrong size for SVG\n * loaded into HTMLImageElement; this sets width/height from natural dimensions or by\n * parsing the SVG so object-fit (cover/contain/fill) and crop zoom behave correctly.\n */\nexport async function normalizeSvgImageDimensions(\n fabricImage: fabric.FabricImage,\n imageUrl: string,\n sourceFormat?: 'svg' | 'png'\n): Promise<void> {\n if (!isSvgImage(imageUrl, sourceFormat)) return;\n const el = (fabricImage as any).getElement?.() ?? (fabricImage as any)._element;\n let w = 0;\n let h = 0;\n if (el && typeof el.naturalWidth === 'number' && typeof el.naturalHeight === 'number' && el.naturalWidth > 0 && el.naturalHeight > 0) {\n w = el.naturalWidth;\n h = el.naturalHeight;\n }\n if (w <= 0 || h <= 0) {\n const dims = await loadSvgDimensions(imageUrl);\n if (dims && dims.width > 0 && dims.height > 0) {\n w = dims.width;\n h = dims.height;\n }\n }\n if (w > 0 && h > 0) {\n fabricImage.set({ width: w, height: h });\n fabricImage.setCoords();\n }\n}\n\n// Placeholder image for empty image elements — tiled as a repeating pattern.\n// One tile = 400x300 (matches default new-image element so single tile shows once at default size,\n// and tiles repeat naturally when the user enlarges the frame using crop handles).\nconst EMPTY_IMAGE_PLACEHOLDER_URL = '/image-placeholder.png';\nconst PLACEHOLDER_TILE_W = 400;\nconst PLACEHOLDER_TILE_H = 300;\n\n// Cache the loaded HTMLImageElement so subsequent placeholders reuse it (no flicker).\nlet placeholderTileImage: HTMLImageElement | null = null;\nlet placeholderTilePromise: Promise<HTMLImageElement> | null = null;\nfunction loadPlaceholderTile(): Promise<HTMLImageElement> {\n if (placeholderTileImage) return Promise.resolve(placeholderTileImage);\n if (placeholderTilePromise) return placeholderTilePromise;\n placeholderTilePromise = new Promise((resolve, reject) => {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.onload = () => {\n placeholderTileImage = img;\n resolve(img);\n };\n img.onerror = (e) => {\n placeholderTilePromise = null;\n reject(e);\n };\n img.src = EMPTY_IMAGE_PLACEHOLDER_URL;\n });\n return placeholderTilePromise;\n}\n\nexport function isEmptyImagePlaceholderGroup(obj: fabric.FabricObject | null | undefined): obj is fabric.Group {\n return obj instanceof fabric.Group && Boolean((obj as any).__emptyImagePlaceholder);\n}\n\nfunction getPlaceholderLocalOffset(frameW: number, frameH: number, contentW: number, contentH: number) {\n return {\n left: -frameW / 2 + (frameW - contentW) / 2,\n top: -frameH / 2 + (frameH - contentH) / 2,\n };\n}\n\nfunction stabilizePlaceholderGroup(group: fabric.Group, width: number, height: number): void {\n group.set({ width, height, scaleX: 1, scaleY: 1 });\n\n // Prevent Fabric from recomputing placeholder group bounds from children.\n if ((group as any).layoutManager) {\n if (typeof fabric.FixedLayout === 'function') {\n (group as any).layoutManager.strategy = new fabric.FixedLayout();\n } else {\n (group as any).layoutManager.performLayout = () => {};\n }\n }\n\n group.setCoords();\n}\n\n/** Async-load the placeholder image and apply it as a repeating tile pattern on the bg rect. */\nfunction attachEmptyPlaceholderImage(\n group: fabric.Group,\n width: number,\n height: number,\n): void {\n loadPlaceholderTile()\n .then((htmlImg) => {\n const objects = (group as any)._objects as fabric.FabricObject[] | undefined;\n const bgRect = objects?.find((obj) => (obj as any).__isPlaceholderFrame) as fabric.Rect | undefined;\n if (!bgRect) return;\n\n const pattern = new fabric.Pattern({\n source: htmlImg,\n repeat: 'repeat',\n });\n // Tag for later identification / re-use on resize.\n (pattern as any).__isPlaceholderPattern = true;\n bgRect.set({ fill: pattern as unknown as string });\n (bgRect as any).dirty = true;\n\n // Group-local clipPath ensures the pattern stays inside the frame bounds.\n if (!group.clipPath) {\n const clip = new fabric.Rect({\n width,\n height,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n selectable: false,\n evented: false,\n });\n (clip as any).absolutePositioned = false;\n (clip as any).excludeFromExport = true;\n group.clipPath = clip;\n }\n\n stabilizePlaceholderGroup(group, width, height);\n group.dirty = true;\n group.canvas?.requestRenderAll();\n })\n .catch(() => { /* silent: fall back to transparent */ });\n}\n\nexport function updateEmptyPlaceholderLayout(group: fabric.Group, width: number, height: number): void {\n const objects = (group as any)._objects as fabric.FabricObject[] | undefined;\n const backgroundRect = objects?.find((obj) => (obj as any).__isPlaceholderFrame) as fabric.Rect | undefined;\n const cropData = (group as any).__cropData;\n if (cropData) {\n cropData.frameW = width;\n cropData.frameH = height;\n }\n\n // Resize the bg rect that holds the pattern fill — pattern naturally tiles to fill new size.\n backgroundRect?.set({\n width,\n height,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n });\n if (backgroundRect) (backgroundRect as any).dirty = true;\n\n // If the pattern hasn't been attached yet (still loading), try again now.\n if (backgroundRect && !((backgroundRect.fill as any) instanceof fabric.Pattern)) {\n attachEmptyPlaceholderImage(group, width, height);\n }\n\n if (group.clipPath && (group.clipPath instanceof fabric.Rect || group.clipPath instanceof fabric.Ellipse)) {\n group.clipPath.set({\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n ...(group.clipPath instanceof fabric.Ellipse\n ? { rx: width / 2, ry: height / 2 }\n : { width, height }),\n });\n group.clipPath.setCoords();\n (group.clipPath as any).dirty = true;\n }\n\n stabilizePlaceholderGroup(group, width, height);\n group.dirty = true;\n}\n\nexport function createImagePlaceholder(element: CanvasElement): fabric.FabricObject {\n const visualWidth = Number(element.width) * (element.scaleX ?? 1);\n const visualHeight = Number(element.height) * (element.scaleY ?? 1);\n\n const hasImage = !!(element.src || element.imageUrl);\n\n const bgRect = new fabric.Rect({\n originX: 'center',\n originY: 'center',\n left: 0,\n top: 0,\n width: visualWidth,\n height: visualHeight,\n fill: 'transparent',\n stroke: 'transparent',\n strokeWidth: 0,\n rx: element.clipShape === 'rounded' ? (element.rx || 8) : 0,\n ry: element.clipShape === 'rounded' ? (element.ry || 8) : 0,\n });\n (bgRect as any).__isPlaceholderFrame = true;\n\n const group = new fabric.Group([bgRect], {\n left: (element.left ?? 0) + visualWidth / 2,\n top: (element.top ?? 0) + visualHeight / 2,\n originX: 'center',\n originY: 'center',\n width: visualWidth,\n height: visualHeight,\n scaleX: 1,\n scaleY: 1,\n angle: element.angle ?? 0,\n opacity: element.opacity ?? 1,\n flipX: element.flipX ?? false,\n flipY: element.flipY ?? false,\n selectable: element.selectable,\n evented: element.evented,\n hasControls: true,\n hasBorders: true,\n interactive: true,\n subTargetCheck: false,\n objectCaching: false,\n });\n (group as any).__emptyImagePlaceholder = true;\n (group as any).__imageSrc = '';\n (group as any).__cropData = {\n shape: element.clipShape === 'circle' ? 'circle' : element.clipShape === 'rounded' ? 'roundRect' : 'rect',\n rx: element.clipShape === 'rounded' ? (element.rx || 0.1) : 0,\n frameW: visualWidth,\n frameH: visualHeight,\n fit: 'cover',\n _img: null,\n _border: null,\n _placeholderFrame: bgRect,\n };\n (group as any)._ct = (group as any)._ct || {};\n (group as any)._ct.isCropGroup = true;\n (group as any).__cropGroup = true;\n\n const clipPath = createImageClipPath(\n {\n ...element,\n clipShape: element.clipShape && element.clipShape !== 'none' ? element.clipShape : 'rectangle',\n },\n visualWidth,\n visualHeight,\n );\n if (clipPath) {\n (clipPath as any).absolutePositioned = false;\n (clipPath as any).excludeFromExport = true;\n group.clipPath = clipPath;\n }\n\n stabilizePlaceholderGroup(group, visualWidth, visualHeight);\n\n // Canva-style empty state: when no image is set, show a friendly mountain placeholder\n // inside the frame so users immediately see where the image will appear.\n if (!hasImage) {\n attachEmptyPlaceholderImage(group, visualWidth, visualHeight);\n }\n\n return group;\n}\n\nexport function createImagePlaceholderForGroup(element: CanvasElement): fabric.FabricObject {\n return createImagePlaceholder(element);\n}\n\nexport function createImageClipPath(\n element: CanvasElement,\n imgWidth: number,\n imgHeight: number\n): fabric.FabricObject | undefined {\n const clipShape = element.clipShape || 'none';\n if (clipShape === 'none') return undefined;\n\n switch (clipShape) {\n case 'rectangle':\n return new fabric.Rect({\n width: imgWidth,\n height: imgHeight,\n originX: 'center',\n originY: 'center',\n });\n case 'rounded': {\n // Calculate radius from ratio\n const rxRatio = element.rx || 0.1;\n const minDim = Math.min(imgWidth, imgHeight);\n const radius = rxRatio > 0.5 \n ? Math.min(rxRatio, imgWidth / 2, imgHeight / 2) // Old pixel value\n : Math.min(rxRatio * minDim, imgWidth / 2, imgHeight / 2); // New ratio value\n return new fabric.Rect({\n width: imgWidth,\n height: imgHeight,\n rx: radius,\n ry: radius,\n originX: 'center',\n originY: 'center',\n });\n }\n case 'circle': {\n const radius = Math.min(imgWidth, imgHeight) / 2;\n return new fabric.Ellipse({\n rx: radius,\n ry: radius,\n originX: 'center',\n originY: 'center',\n });\n }\n default:\n return undefined;\n }\n}\n\nexport async function loadImageAsync(\n element: CanvasElement,\n placeholder: fabric.FabricObject,\n fc: fabric.Canvas,\n fabricRef: MutableRefObject<fabric.Canvas | null>,\n syncLockedRef: MutableRefObject<boolean>,\n isTransforming: (canvas: fabric.Canvas) => boolean\n): Promise<fabric.FabricObject | void> {\n const imageUrl = element.src || element.imageUrl;\n if (!imageUrl) return;\n const nextSvgColorMap = element.svgColorMap ? JSON.stringify(element.svgColorMap) : '';\n\n // CRITICAL: Early return for crop groups - don't remove/recreate if only crop/resize changed\n if (placeholder instanceof fabric.Group && (placeholder as any).__cropGroup) {\n const ct = (placeholder as any).__cropData;\n const existingImg = ct?._img;\n const existingSrc = (placeholder as any).__imageSrc;\n const existingSvgColorMap = (placeholder as any).__svgColorMap || '';\n\n if (existingImg && existingSrc === imageUrl && existingSvgColorMap === nextSvgColorMap) {\n return placeholder;\n }\n }\n\n try {\n let url = getProxiedImageUrl(imageUrl);\n const hasColorOverrides = Boolean(element.svgColorMap && Object.keys(element.svgColorMap).length > 0);\n const isInlineSvgDataUrl = imageUrl.startsWith('data:image/svg+xml');\n\n // Preserve imported SVG fidelity: do not re-normalize inline SVG data URLs unless\n // we explicitly need color remapping from the editor.\n if (isSvgImage(imageUrl, element.sourceFormat) && (!isInlineSvgDataUrl || hasColorOverrides)) {\n const normalized = await getNormalizedSvgUrl(imageUrl, element.svgColorMap, element.sourceFormat);\n if (normalized) url = normalized;\n }\n console.log('[canvas-image-loader] loading image', {\n id: element.id,\n sourceFormat: element.sourceFormat,\n originalUrl: imageUrl.slice(0, 240),\n resolvedUrl: url.slice(0, 240),\n usedProxy: !url.startsWith('data:') && !url.startsWith('blob:') && url !== imageUrl,\n });\n const img = await fabric.FabricImage.fromURL(url, { crossOrigin: 'anonymous' });\n\n if (!fabricRef.current) return;\n\n await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat);\n\n const isHidden = !element.visible;\n img.set({\n originX: 'left',\n originY: 'top',\n visible: !isHidden,\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n selectable: !isHidden && element.selectable,\n evented: !isHidden && element.evented,\n hasControls: !isHidden && element.selectable,\n hasBorders: !isHidden && element.selectable,\n lockMovementX: !element.selectable,\n lockMovementY: !element.selectable,\n flipX: element.flipX ?? false,\n flipY: element.flipY ?? false,\n objectCaching: false,\n noScaleCache: true,\n });\n\n // Handle transform matrix or calculate scale based on imageFit\n if (element.transformMatrix && element.transformMatrix.length === 6) {\n img.set({\n left: element.left,\n top: element.top,\n scaleX: element.scaleX ?? 1,\n scaleY: element.scaleY ?? 1,\n angle: element.angle ?? 0,\n skewX: element.skewX ?? 0,\n skewY: element.skewY ?? 0,\n });\n img.setCoords();\n } else {\n const imageFit = element.imageFit || 'cover';\n const imgNaturalWidth = img.width || 1;\n const imgNaturalHeight = img.height || 1;\n const elementWidth = Number(element.width);\n const elementHeight = Number(element.height);\n \n let baseScaleX: number;\n let baseScaleY: number;\n \n if (imageFit === 'fill') {\n baseScaleX = elementWidth / imgNaturalWidth;\n baseScaleY = elementHeight / imgNaturalHeight;\n } else if (imageFit === 'cover') {\n const scaleX = elementWidth / imgNaturalWidth;\n const scaleY = elementHeight / imgNaturalHeight;\n const scale = Math.max(scaleX, scaleY);\n baseScaleX = scale;\n baseScaleY = scale;\n } else if (imageFit === 'contain') {\n const scaleX = elementWidth / imgNaturalWidth;\n const scaleY = elementHeight / imgNaturalHeight;\n const scale = Math.min(scaleX, scaleY);\n baseScaleX = scale;\n baseScaleY = scale;\n } else {\n baseScaleX = 1;\n baseScaleY = 1;\n }\n \n if (imageFit === 'fill') {\n const finalScaleX = baseScaleX * (element.scaleX ?? 1);\n const finalScaleY = baseScaleY * (element.scaleY ?? 1);\n const visualW = Number(elementWidth) * (element.scaleX ?? 1);\n const visualH = Number(elementHeight) * (element.scaleY ?? 1);\n // Use center origin so scaling with corner handles keeps the image centered\n const centerX = element.left + visualW / 2;\n const centerY = element.top + visualH / 2;\n\n img.set({\n originX: 'center',\n originY: 'center',\n left: centerX,\n top: centerY,\n scaleX: finalScaleX,\n scaleY: finalScaleY,\n angle: element.angle ?? 0,\n skewX: element.skewX ?? 0,\n skewY: element.skewY ?? 0,\n });\n \n const clipPath = createImageClipPath(element, img.width || 1, img.height || 1);\n if (clipPath) {\n img.clipPath = clipPath;\n }\n } else {\n const elementWidth = Number(element.width) * (element.scaleX ?? 1);\n const elementHeight = Number(element.height) * (element.scaleY ?? 1);\n const scaledImageWidth = imgNaturalWidth * baseScaleX;\n const scaledImageHeight = imgNaturalHeight * baseScaleY;\n const imageLeft = (elementWidth - scaledImageWidth) / 2;\n const imageTop = (elementHeight - scaledImageHeight) / 2;\n \n img.set({\n originX: 'left',\n originY: 'top',\n left: imageLeft,\n top: imageTop,\n scaleX: baseScaleX,\n scaleY: baseScaleY,\n angle: 0,\n skewX: 0,\n skewY: 0,\n });\n \n (img as any).__cropBaseScaleX = baseScaleX;\n (img as any).__cropBaseScaleY = baseScaleY;\n }\n }\n\n (img as any).__imageSrc = imageUrl;\n (img as any).__svgColorMap = nextSvgColorMap;\n\n const imageFit = element.imageFit || 'cover';\n let finalObject: fabric.FabricObject = img;\n \n if (imageFit !== 'fill') {\n const elementWidth = Number(element.width) * (element.scaleX ?? 1);\n const elementHeight = Number(element.height) * (element.scaleY ?? 1);\n const clipShape = element.clipShape || 'none';\n // rx is stored as ratio (0-0.5), convert old pixel values if needed\n let rxRatio = 0;\n if (clipShape === 'rounded') {\n const elementRx = element.rx || 0.1; // Default to 10% if not set\n // If rx > 0.5, it's likely an old pixel value, convert to ratio\n if (elementRx > 0.5) {\n const minDim = Math.min(elementWidth, elementHeight);\n rxRatio = Math.min(elementRx / minDim, 0.5); // Cap at 50%\n } else {\n rxRatio = elementRx;\n }\n }\n \n let shape: 'circle' | 'roundRect' | 'rect' = 'rect';\n if (clipShape === 'circle') {\n shape = 'circle';\n } else if (clipShape === 'rounded' || clipShape === 'rectangle') {\n shape = 'roundRect';\n }\n \n const existingCropGroup = fc.getObjects().find(\n (obj) => obj instanceof fabric.Group && \n (obj as any).__cropGroup && \n getObjectId(obj) === element.id\n ) as fabric.Group | undefined;\n \n let panX = 0.5;\n let panY = 0.5;\n let zoom = 1;\n if (existingCropGroup) {\n const existingImg = (existingCropGroup as any).__cropData?._img;\n if (existingImg) {\n panX = (existingImg as any)._ct?.panX ?? (existingImg as any).__panX ?? 0.5;\n panY = (existingImg as any)._ct?.panY ?? (existingImg as any).__panY ?? 0.5;\n zoom = (existingImg as any)._ct?.zoom ?? 1;\n }\n }\n \n const cropGroup = await createMaskedImageElement({\n image: img,\n frameW: elementWidth,\n frameH: elementHeight,\n left: element.left,\n top: element.top,\n angle: element.angle ?? 0,\n opacity: element.opacity ?? 1,\n visible: element.visible,\n shape,\n rx: rxRatio, // Pass ratio, not pixel value\n stroke: element.stroke,\n strokeWidth: element.strokeWidth,\n panX,\n panY,\n zoom,\n });\n\n // Store maintainResolution flag on the crop group (default to true)\n (cropGroup as any).__maintainResolution = element.maintainResolution !== false;\n \n // CRITICAL: Update layout again after setting maintainResolution\n // This ensures zoom is adjusted correctly for the current maintainResolution setting\n updateCoverLayout(cropGroup);\n\n setObjectData(cropGroup, element.id);\n (cropGroup as any).__imageSrc = imageUrl;\n (cropGroup as any).__svgColorMap = nextSvgColorMap;\n finalObject = cropGroup;\n } else {\n setObjectData(img, element.id);\n finalObject = img;\n }\n\n const idx = fc.getObjects().indexOf(placeholder);\n fc.remove(placeholder);\n if (idx >= 0) {\n fc.insertAt(idx, finalObject);\n } else {\n fc.add(finalObject);\n }\n\n fc.requestRenderAll();\n return finalObject;\n } catch (error) {\n console.error('[canvas-image-loader] failed to load image', {\n id: element.id,\n originalUrl: imageUrl.slice(0, 240),\n proxiedUrl: getProxiedImageUrl(imageUrl).slice(0, 240),\n error: error instanceof Error ? error.message : String(error),\n });\n // Failed to load image - keep placeholder\n return;\n }\n}\n","/**\n * SVG Mask POC: applies an external SVG (e.g. a Freepik frame) as a fabric.js\n * clipPath on an existing crop group.\n *\n * Strategy:\n * 1. Load the SVG via fabric.loadSVGFromURL — gives us parsed Path objects.\n * 2. Group all paths so we can treat the whole mask as one clip shape.\n * 3. Force `fillRule: 'evenodd'` so frame-style SVGs (outer rect + inner cutouts)\n * render their hole as the visible region.\n * 4. Scale + center the group to the crop group's frameW × frameH dimensions.\n * 5. Assign as `g.clipPath` (group-local, not absolutePositioned) so it follows\n * the existing pan/zoom of the inner image without further changes.\n *\n * This is a non-destructive POC — it does NOT persist anything to the schema.\n * It only mutates the live Fabric object so we can validate the visual result\n * and confirm crop-mode pan/zoom still works inside the new mask shape.\n */\n\nimport * as fabric from 'fabric';\n\ntype CropGroup = fabric.Group & {\n __cropGroup?: boolean;\n _ct?: { isCropGroup?: boolean; frameW?: number; frameH?: number };\n};\n\nconst isCropGroup = (obj: unknown): obj is CropGroup => {\n const g = obj as CropGroup | null;\n return Boolean(g && (g.__cropGroup || g._ct?.isCropGroup));\n};\n\n/**\n * Load an SVG file and return a single fabric.Group containing all its visible\n * paths. We strip the wrapper <svg> transform — we'll apply our own scaling.\n */\n/**\n * Parse a fabric color string and return its perceived luminance (0..1).\n * Returns null when the value can't be parsed (e.g. gradient, pattern).\n */\nfunction parseLuminance(fill: unknown): number | null {\n if (typeof fill !== 'string') return null;\n const f = fill.trim().toLowerCase();\n if (!f || f === 'none' || f === 'transparent') return null;\n // Named whites/blacks shortcut\n if (f === 'white' || f === '#fff' || f === '#ffffff') return 1;\n if (f === 'black' || f === '#000' || f === '#000000') return 0;\n // #rgb / #rrggbb\n const hex = f.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/);\n if (hex) {\n const h = hex[1];\n const full = h.length === 3 ? h.split('').map((c) => c + c).join('') : h;\n const r = parseInt(full.slice(0, 2), 16) / 255;\n const g = parseInt(full.slice(2, 4), 16) / 255;\n const b = parseInt(full.slice(4, 6), 16) / 255;\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n }\n // rgb(a)\n const rgb = f.match(/^rgba?\\(([^)]+)\\)$/);\n if (rgb) {\n const parts = rgb[1].split(',').map((s) => parseFloat(s.trim()));\n if (parts.length >= 3) {\n const r = parts[0] / 255;\n const g = parts[1] / 255;\n const b = parts[2] / 255;\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n }\n }\n return null;\n}\n\nfunction getObjectRenderedSize(obj: fabric.FabricObject): { width: number; height: number } {\n const bbox = typeof (obj as any).getBoundingRect === 'function'\n ? (obj as any).getBoundingRect()\n : null;\n const width = Math.abs(Number(bbox?.width) || ((obj.width ?? 0) * Math.abs(obj.scaleX ?? 1)));\n const height = Math.abs(Number(bbox?.height) || ((obj.height ?? 0) * Math.abs(obj.scaleY ?? 1)));\n return { width, height };\n}\n\nfunction isLikelyFullFrameBackground(\n obj: fabric.FabricObject,\n luminance: number | null,\n viewBoxW: number,\n viewBoxH: number,\n totalObjects: number\n): boolean {\n if (totalObjects <= 1 || viewBoxW <= 0 || viewBoxH <= 0 || luminance === null) return false;\n const { width, height } = getObjectRenderedSize(obj);\n const widthRatio = width / viewBoxW;\n const heightRatio = height / viewBoxH;\n const areaRatio = (width * height) / (viewBoxW * viewBoxH);\n return widthRatio >= 0.96 && heightRatio >= 0.96 && areaRatio >= 0.9;\n}\n\nasync function loadSvgAsGroup(url: string): Promise<{\n group: fabric.Group;\n viewBoxW: number;\n viewBoxH: number;\n}> {\n const result = await fabric.loadSVGFromURL(url);\n const allObjects = (result.objects || []).filter(Boolean) as fabric.FabricObject[];\n const options = result.options || {};\n\n if (allObjects.length === 0) {\n throw new Error('SVG contained no parseable shapes');\n }\n\n const hintedViewBoxW = Number(options.width) || 0;\n const hintedViewBoxH = Number(options.height) || 0;\n\n // Many \"frame\" SVGs are actually full Adobe Illustrator scenes with a single\n // full-canvas background shape behind the real mask geometry. If we keep that\n // background, the clip becomes a near-full rectangle and the user sees\n // \"applied\" with no visible change. So we strip only likely page-sized\n // backgrounds, then keep the remaining geometry intact.\n const sourceLuminances = allObjects.map((o) => parseLuminance((o as any).fill));\n\n // Ignore the common \"full-canvas background\" object exported by Illustrator.\n // Without this, a white page-sized background can become the only retained mask\n // shape, making the app say \"applied\" while the image looks unchanged.\n let objects = allObjects.filter((obj, i) => !isLikelyFullFrameBackground(\n obj,\n sourceLuminances[i],\n hintedViewBoxW,\n hintedViewBoxH,\n allObjects.length,\n ));\n if (objects.length === 0) objects = allObjects;\n\n if (objects.length === 0) objects = allObjects;\n\n for (const obj of objects) {\n (obj as any).fillRule = 'evenodd';\n (obj as any).fill = '#000';\n (obj as any).stroke = null;\n (obj as any).strokeWidth = 0;\n }\n\n const group = new fabric.Group(objects, {\n originX: 'center',\n originY: 'center',\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n\n const viewBoxW = Number(options.width) || group.width || 1;\n const viewBoxH = Number(options.height) || group.height || 1;\n\n return { group, viewBoxW, viewBoxH };\n}\n\nfunction fitMaskGroupToFrame(maskGroup: fabric.Group, frameW: number, frameH: number): void {\n const viewBoxW = Number((maskGroup as any).__svgMaskViewBoxW) || maskGroup.width || 1;\n const viewBoxH = Number((maskGroup as any).__svgMaskViewBoxH) || maskGroup.height || 1;\n\n maskGroup.set({\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n scaleX: frameW / viewBoxW,\n scaleY: frameH / viewBoxH,\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n (maskGroup as any).absolutePositioned = false;\n (maskGroup as any).excludeFromExport = true;\n (maskGroup as any).inverted = false;\n (maskGroup as any).dirty = true;\n maskGroup.setCoords();\n}\n\nexport function isSvgMaskClipPath(clipPath: unknown): clipPath is fabric.Group {\n return Boolean(clipPath && (clipPath as any).__svgMask && clipPath instanceof fabric.Group);\n}\n\nexport function isLuminanceMaskClipPath(clipPath: unknown): boolean {\n return Boolean(clipPath && (clipPath as any).__svgMaskType === 'luminance');\n}\n\nexport function syncSvgMaskClipPath(cropGroup: fabric.FabricObject): void {\n const clipPath = (cropGroup as any).clipPath;\n if (!isCropGroup(cropGroup)) return;\n const frameW = cropGroup._ct?.frameW ?? cropGroup.width ?? 0;\n const frameH = cropGroup._ct?.frameH ?? cropGroup.height ?? 0;\n if (frameW <= 0 || frameH <= 0) return;\n if (isSvgMaskClipPath(clipPath)) {\n fitMaskGroupToFrame(clipPath, frameW, frameH);\n }\n // For luminance image masks we'd need to re-bake at frame size — caller should\n // re-invoke applyLuminanceMaskToCropGroup when the frame size changes.\n}\n\nexport type MaskType = 'shape' | 'luminance';\n\n/**\n * Heuristically detect whether an SVG should be rendered as a luminance (soft)\n * mask. We sniff for: gradients, embedded raster images, mask-type=luminance,\n * filters, or fill-opacity values < 1. If any present, soft mode is recommended.\n */\nexport async function detectMaskType(svgUrl: string): Promise<MaskType> {\n try {\n const res = await fetch(svgUrl);\n if (!res.ok) return 'shape';\n const text = await res.text();\n const t = text.toLowerCase();\n if (t.includes('<lineargradient') || t.includes('<radialgradient')) return 'luminance';\n if (t.includes('<image ') || t.includes('<image>')) return 'luminance';\n if (t.includes('mask-type=\"luminance\"') || t.includes(\"mask-type='luminance'\")) return 'luminance';\n if (t.includes('<filter')) return 'luminance';\n if (/fill-opacity\\s*=\\s*[\"'](0?\\.\\d+)/.test(t)) return 'luminance';\n if (/opacity\\s*=\\s*[\"'](0?\\.\\d+)/.test(t)) return 'luminance';\n return 'shape';\n } catch {\n return 'shape';\n }\n}\n\n/**\n * Apply an SVG as a SHAPE clipPath (binary, vector, PDF-friendly).\n */\nexport async function applySvgMaskToCropGroup(\n cropGroup: fabric.FabricObject,\n svgUrl: string\n): Promise<void> {\n if (!isCropGroup(cropGroup)) {\n throw new Error('Selected object is not a crop group / image');\n }\n\n const frameW = cropGroup._ct?.frameW ?? cropGroup.width ?? 0;\n const frameH = cropGroup._ct?.frameH ?? cropGroup.height ?? 0;\n if (frameW <= 0 || frameH <= 0) {\n throw new Error('Crop group has no frame dimensions');\n }\n\n const { group: maskGroup, viewBoxW, viewBoxH } = await loadSvgAsGroup(svgUrl);\n\n // Sanity-check: some SVGs produce a clip group with zero bounds (e.g. all\n // shapes were filtered out, or the viewBox is missing). A zero-area clipPath\n // would clip the entire image to nothing — making the mask appear \"applied\"\n // but invisible. Fail loudly here so the UI shows an error instead.\n const mw = maskGroup.width ?? 0;\n const mh = maskGroup.height ?? 0;\n if (mw <= 0 || mh <= 0 || viewBoxW <= 0 || viewBoxH <= 0) {\n throw new Error(\"This mask has no usable shapes (try the 'Soft' mode instead)\");\n }\n\n (maskGroup as any).__svgMask = true;\n (maskGroup as any).__svgMaskUrl = svgUrl;\n (maskGroup as any).__svgMaskType = 'shape';\n (maskGroup as any).__svgMaskViewBoxW = viewBoxW;\n (maskGroup as any).__svgMaskViewBoxH = viewBoxH;\n fitMaskGroupToFrame(maskGroup, frameW, frameH);\n\n cropGroup.clipPath = maskGroup;\n (cropGroup as any).__svgMaskUrl = svgUrl;\n (cropGroup as any).__svgMaskType = 'shape';\n (cropGroup as any).dirty = true;\n // Invalidate any cached child renders inside the crop group.\n if ((cropGroup as any)._objects) {\n for (const child of (cropGroup as any)._objects) {\n (child as any).dirty = true;\n }\n }\n cropGroup.canvas?.requestRenderAll();\n}\n\n/**\n * Load an SVG URL into an HTMLImageElement. Tries crossOrigin first, then\n * falls back to fetch → blob → object URL so that strict-CORS hosts (e.g.\n * Supabase storage without an Access-Control-Allow-Origin header) still work.\n * Without this fallback the canvas would become \"tainted\" and `getImageData`\n * would throw, leaving the user with a \"mask applied\" toast but no visible\n * result.\n */\nfunction loadSvgAsImage(svgUrl: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const tryFetch = async () => {\n try {\n const res = await fetch(svgUrl, { mode: 'cors' });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const blob = await res.blob();\n const objectUrl = URL.createObjectURL(blob);\n const img = new Image();\n img.onload = () => resolve(img);\n img.onerror = () => reject(new Error('Failed to load SVG (after fetch fallback)'));\n img.src = objectUrl;\n } catch (e: any) {\n reject(new Error(`Failed to load SVG: ${e?.message || 'network error'}`));\n }\n };\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.onload = () => resolve(img);\n img.onerror = () => tryFetch();\n img.src = svgUrl;\n });\n}\n\n/**\n * Render the SVG into a frame-sized offscreen canvas, then convert luminance\n * to alpha so it can be used as a Fabric image clipPath (which respects pixel\n * alpha for soft masking).\n */\nasync function buildLuminanceAlphaCanvas(\n svgUrl: string,\n frameW: number,\n frameH: number\n): Promise<HTMLCanvasElement> {\n const w = Math.max(2, Math.round(frameW));\n const h = Math.max(2, Math.round(frameH));\n const img = await loadSvgAsImage(svgUrl);\n\n const canvas = document.createElement('canvas');\n canvas.width = w;\n canvas.height = h;\n const ctx = canvas.getContext('2d');\n if (!ctx) throw new Error('Failed to get 2D context for mask canvas');\n\n ctx.clearRect(0, 0, w, h);\n ctx.drawImage(img, 0, 0, w, h);\n\n let data: ImageData;\n try {\n data = ctx.getImageData(0, 0, w, h);\n } catch (e: any) {\n throw new Error(\n 'Could not read SVG pixels (CORS / tainted canvas). Try a different mask source.'\n );\n }\n const px = data.data;\n for (let i = 0; i < px.length; i += 4) {\n const r = px[i];\n const g = px[i + 1];\n const b = px[i + 2];\n const a = px[i + 3];\n const lum = 0.2126 * r + 0.7152 * g + 0.0722 * b;\n const alpha = (lum / 255) * a;\n px[i] = 255;\n px[i + 1] = 255;\n px[i + 2] = 255;\n px[i + 3] = Math.round(alpha);\n }\n ctx.putImageData(data, 0, 0);\n return canvas;\n}\n\n/**\n * Apply an SVG as a LUMINANCE (soft) clipPath. Uses a FabricImage as clipPath\n * whose alpha channel encodes the SVG's luminance — Fabric will respect pixel\n * alpha for the clip, giving true gradient/feathered transparency.\n *\n * Note: PDF/vector exports of soft masks fall back to raster (clipPath becomes\n * an embedded image). Use shape mode for pure-vector PDF parity.\n */\nexport async function applyLuminanceMaskToCropGroup(\n cropGroup: fabric.FabricObject,\n svgUrl: string\n): Promise<void> {\n if (!isCropGroup(cropGroup)) {\n throw new Error('Selected object is not a crop group / image');\n }\n const frameW = cropGroup._ct?.frameW ?? cropGroup.width ?? 0;\n const frameH = cropGroup._ct?.frameH ?? cropGroup.height ?? 0;\n if (frameW <= 0 || frameH <= 0) {\n throw new Error('Crop group has no frame dimensions');\n }\n\n const alphaCanvas = await buildLuminanceAlphaCanvas(svgUrl, frameW, frameH);\n const maskImg = new fabric.FabricImage(alphaCanvas, {\n originX: 'center',\n originY: 'center',\n left: 0,\n top: 0,\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n (maskImg as any).absolutePositioned = false;\n (maskImg as any).excludeFromExport = true;\n (maskImg as any).inverted = false;\n (maskImg as any).__svgMask = true;\n (maskImg as any).__svgMaskUrl = svgUrl;\n (maskImg as any).__svgMaskType = 'luminance';\n\n cropGroup.clipPath = maskImg;\n (cropGroup as any).__svgMaskUrl = svgUrl;\n (cropGroup as any).__svgMaskType = 'luminance';\n (cropGroup as any).dirty = true;\n if ((cropGroup as any)._objects) {\n for (const child of (cropGroup as any)._objects) {\n (child as any).dirty = true;\n }\n }\n cropGroup.canvas?.requestRenderAll();\n}\n\n/** Apply a mask in either mode. */\nexport async function applyMaskToCropGroup(\n cropGroup: fabric.FabricObject,\n svgUrl: string,\n maskType: MaskType\n): Promise<void> {\n if (maskType === 'luminance') {\n return applyLuminanceMaskToCropGroup(cropGroup, svgUrl);\n }\n return applySvgMaskToCropGroup(cropGroup, svgUrl);\n}\n\nexport function getAppliedSvgMaskUrl(obj: fabric.FabricObject | null | undefined): string | null {\n if (!obj) return null;\n const url = (obj as any).__svgMaskUrl;\n return typeof url === 'string' ? url : null;\n}\n\nexport function getAppliedSvgMaskType(obj: fabric.FabricObject | null | undefined): MaskType | null {\n if (!obj) return null;\n const t = (obj as any).__svgMaskType;\n return t === 'luminance' || t === 'shape' ? t : null;\n}\n\nexport function clearSvgMaskFromCropGroup(cropGroup: fabric.FabricObject): void {\n if (!isCropGroup(cropGroup)) return;\n const frameW = cropGroup._ct?.frameW ?? cropGroup.width ?? 0;\n const frameH = cropGroup._ct?.frameH ?? cropGroup.height ?? 0;\n\n const rect = new fabric.Rect({\n width: frameW,\n height: frameH,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n (rect as any).absolutePositioned = false;\n (rect as any).excludeFromExport = true;\n\n cropGroup.clipPath = rect;\n delete (cropGroup as any).__svgMaskUrl;\n delete (cropGroup as any).__svgMaskType;\n (cropGroup as any).dirty = true;\n cropGroup.canvas?.requestRenderAll();\n}\n\n","import * as fabric from 'fabric';\nimport { getProxiedImageUrl } from './canvasImageLoader';\nimport { isLuminanceMaskClipPath, isSvgMaskClipPath, syncSvgMaskClipPath } from './svgMaskApply';\n\n/**\n * Helper function to clamp a value between min and max\n */\nfunction clamp(v: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, v));\n}\n\n/**\n * Scale control/border size with zoom so handles look the same at any zoom level.\n * The canvas element is (width*zoom)×(height*zoom) px; controls are drawn in that pixel space.\n * So we set cornerSize = 10 * zoom so handles stay the same visual size relative to the canvas.\n */\nexport function applyControlSizeForZoom(canvas: fabric.Canvas, obj: fabric.Object) {\n if (!canvas || !obj) return;\n const z = canvas.getZoom() || 1;\n const size = Math.max(6, Math.round(10 * z));\n obj.set({\n cornerSize: size,\n borderScaleFactor: z,\n });\n obj.setCoords();\n}\n\n/**\n * Finalize crop group coords after layout updates\n * CRITICAL: Must be called after every layout mutation to ensure corner hit-testing works\n */\nfunction finalizeCropGroupCoords(g: fabric.Group) {\n const ct = (g as any).__cropData;\n if (!ct) return;\n \n // CRITICAL: Ensure group width/height exactly equals frameW/frameH BEFORE setCoords\n // If width/height don't match, controls land in wrong spot\n g.set({ width: ct.frameW, height: ct.frameH });\n \n // Mark dirty for repaint\n (g as any).dirty = true;\n \n // DO NOT call _calcBounds() — it recalculates group dimensions from children,\n // overriding our explicit frameW/frameH. For crop groups the frame size is the\n // source of truth, not the child image's natural/scaled bounds.\n\n if (typeof (g as any)._updateObjectsCoords === 'function') {\n (g as any)._updateObjectsCoords();\n }\n \n // CRITICAL: Always call setCoords after layout changes\n // This ensures corner controls are hittable\n g.setCoords();\n}\n\n/**\n * Recompute image scale & position so it covers the frame,\n * and apply pan (crop) without showing empty background.\n */\nexport function updateCoverLayout(g: fabric.Group) {\n const ct = (g as any).__cropData;\n if (!ct) return;\n\n const { frameW, frameH, shape, rx: rxRatio, _img: img, _border: border } = ct;\n // Calculate actual rx from ratio (rxRatio is 0-0.5, representing 0-50% of smaller dimension)\n // If rxRatio is > 0.5, it's likely an old pixel value, so convert it\n const minDim = Math.min(frameW, frameH);\n let rx = rxRatio > 0.5 ? rxRatio : rxRatio * minDim;\n \n // CRITICAL: Cap rx at half of each dimension to ensure valid rounded corners\n // This ensures corners are uniform and don't exceed the maximum possible radius\n // Also ensure rx is at least 0 (can't be negative)\n rx = Math.max(0, Math.min(rx, frameW / 2, frameH / 2));\n\n // Preserve custom SVG masks during crop pan/zoom/resize instead of replacing\n // them with the default rect/circle clipPath.\n const currentClipPath = (g as any).clipPath;\n const hasCustomSvgMask = Boolean(\n currentClipPath &&\n (isSvgMaskClipPath(currentClipPath) ||\n isLuminanceMaskClipPath(currentClipPath) ||\n (currentClipPath as any).__svgMask)\n );\n const hasEdgeFadeMask = Boolean(currentClipPath && (currentClipPath as any).__edgeFadeMask);\n\n if (hasCustomSvgMask || hasEdgeFadeMask) {\n if (isSvgMaskClipPath(currentClipPath)) {\n syncSvgMaskClipPath(g);\n } else if (currentClipPath && typeof (currentClipPath as any).set === 'function') {\n if (hasEdgeFadeMask) {\n // Frame-level fade masks are regenerated by PageCanvas after layout updates.\n (currentClipPath as any).dirty = true;\n } else {\n const baseW = Math.max(1, Number((currentClipPath as any).width) || frameW);\n const baseH = Math.max(1, Number((currentClipPath as any).height) || frameH);\n (currentClipPath as fabric.FabricObject).set({\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n scaleX: frameW / baseW,\n scaleY: frameH / baseH,\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n (currentClipPath as any).absolutePositioned = false;\n (currentClipPath as any).excludeFromExport = true;\n (currentClipPath as any).dirty = true;\n currentClipPath.setCoords();\n }\n }\n } else {\n const needsNewClipPath = \n !g.clipPath ||\n (shape === 'circle' && !(g.clipPath instanceof fabric.Ellipse)) ||\n (shape !== 'circle' && !(g.clipPath instanceof fabric.Rect));\n\n if (needsNewClipPath) {\n const clip = shape === 'circle'\n ? new fabric.Ellipse({\n rx: frameW / 2,\n ry: frameH / 2,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n })\n : new fabric.Rect({\n width: frameW,\n height: frameH,\n rx: rx,\n ry: rx,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n (clip as any).absolutePositioned = false;\n (clip as any).excludeFromExport = true;\n clip.setCoords();\n (clip as any).dirty = true;\n g.clipPath = clip;\n } else if (g.clipPath && typeof (g.clipPath as any).set === 'function') {\n if (shape === 'circle') {\n (g.clipPath as fabric.FabricObject).set({ \n rx: frameW / 2, \n ry: frameH / 2,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n } else {\n const clipPathObj = g.clipPath as fabric.FabricObject;\n const currentRx = (clipPathObj as any).rx || 0;\n const currentWidth = (clipPathObj as any).width || 0;\n const currentHeight = (clipPathObj as any).height || 0;\n const rxChanged = Math.abs(currentRx - rx) > 0.01;\n const dimsChanged = Math.abs(currentWidth - frameW) > 0.1 || Math.abs(currentHeight - frameH) > 0.1;\n\n if (rxChanged || dimsChanged) {\n const newClip = new fabric.Rect({\n width: frameW,\n height: frameH,\n rx: rx,\n ry: rx,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n (newClip as any).absolutePositioned = false;\n (newClip as any).excludeFromExport = true;\n newClip.setCoords();\n (newClip as any).dirty = true;\n g.clipPath = newClip;\n } else {\n clipPathObj.set({ \n width: frameW, \n height: frameH, \n rx: rx,\n ry: rx,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n clipPathObj.setCoords();\n (clipPathObj as any).dirty = true;\n }\n }\n (g.clipPath as any).absolutePositioned = false;\n (g.clipPath as any).excludeFromExport = true;\n }\n }\n\n // Update optional border geometry\n if (border) {\n if (shape === 'circle') {\n border.set({ rx: frameW / 2, ry: frameH / 2 });\n } else {\n // Calculate actual rx from ratio for border (use same calculation as clip path)\n const minDim = Math.min(frameW, frameH);\n let actualRx = rxRatio > 0.5 ? rxRatio : rxRatio * minDim;\n // Cap at half of each dimension to ensure valid rounded corners\n actualRx = Math.max(0, Math.min(actualRx, frameW / 2, frameH / 2));\n border.set({ width: frameW, height: frameH, rx: actualRx, ry: actualRx });\n }\n }\n\n if (!img) {\n const placeholderFrame = ct._placeholderFrame\n ?? ((g as any)._objects as fabric.FabricObject[] | undefined)?.find((obj) => (obj as any).__isPlaceholderFrame);\n\n if (placeholderFrame && typeof (placeholderFrame as any).set === 'function') {\n placeholderFrame.set({\n width: frameW,\n height: frameH,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n ...(placeholderFrame instanceof fabric.Rect ? { rx, ry: rx } : {}),\n });\n (placeholderFrame as any).dirty = true;\n ct._placeholderFrame = placeholderFrame;\n }\n\n finalizeCropGroupCoords(g);\n if (g.canvas) {\n g.setCoords();\n g.canvas.requestRenderAll();\n }\n return;\n }\n\n // Initialize crop state if needed\n (img as any)._ct = (img as any)._ct || { panX: 0.5, panY: 0.5, zoom: 1 };\n \n // Migrate from old format if needed\n if ((img as any).__panX !== undefined || (img as any).__panY !== undefined) {\n (img as any)._ct.panX = (img as any).__panX ?? 0.5;\n (img as any)._ct.panY = (img as any).__panY ?? 0.5;\n }\n\n const iw = img.width || 1;\n const ih = img.height || 1;\n\n // fit === 'contain': scale image to fit inside frame (no clipping, full image visible)\n // otherwise cover: fill frame (may crop image)\n const fitContain = (ct as any).fit === 'contain';\n const baseScale = fitContain\n ? Math.min(frameW / iw, frameH / ih)\n : Math.max(frameW / iw, frameH / ih);\n\n // Zoom factor (>=1) - crop mode only; contain mode ignores zoom\n const zoom = fitContain ? 1 : Math.max(1, (img as any)._ct.zoom ?? 1);\n const finalScale = baseScale * zoom;\n\n img.set({\n scaleX: finalScale,\n scaleY: finalScale,\n originX: 'center',\n originY: 'center',\n });\n\n const dispW = iw * finalScale;\n const dispH = ih * finalScale;\n\n const overflowX = Math.max(0, dispW - frameW);\n const overflowY = Math.max(0, dispH - frameH);\n\n // Contain: always centered (no pan). Cover: use pan\n const panX = clamp((img as any)._ct.panX ?? 0.5, 0, 1);\n const panY = clamp((img as any)._ct.panY ?? 0.5, 0, 1);\n const offsetX = fitContain ? 0 : (overflowX > 0 ? -overflowX * (panX - 0.5) : 0);\n const offsetY = fitContain ? 0 : (overflowY > 0 ? -overflowY * (panY - 0.5) : 0);\n\n img.set({ left: offsetX, top: offsetY });\n\n // Mark everything dirty for live repaint during drag\n (g as any).dirty = true;\n (img as any).dirty = true;\n \n if (g.clipPath) {\n (g.clipPath as any).dirty = true;\n }\n\n // CRITICAL: Finalize coords after every layout update\n // This ensures corner controls are hittable\n finalizeCropGroupCoords(g);\n \n // CRITICAL: Request immediate render to show clip shape changes\n if (g.canvas) {\n g.setCoords();\n g.canvas.requestRenderAll();\n }\n}\n\n/**\n * Safely extract DOM event from Fabric eventData\n * Fabric v6 control handlers can have inconsistent event structure\n */\nfunction getDomEvent(eventData: any): any {\n return eventData?.e ?? eventData ?? null;\n}\n\n/**\n * Convert pointer delta to group-local delta (handles zoom/rotation)\n * CRITICAL: Store last pointer on target object, not transform (transform gets recreated)\n * \n * @param target - The fabric.Group object\n * @param eventData - The full eventData from Fabric control handler (NOT eventData.e)\n */\nexport function getLocalDeltaStable(\n target: fabric.Group,\n eventData: any\n): { localDx: number; localDy: number } {\n const canvas = target.canvas;\n if (!canvas) return { localDx: 0, localDy: 0 };\n\n // Safely extract DOM event - handle inconsistent Fabric v6 event structure\n const e = getDomEvent(eventData);\n if (!e) {\n return { localDx: 0, localDy: 0 };\n }\n\n // Get current pointer position\n const p = canvas.getPointer(e);\n \n // Store last pointer on target object (not transform - transform gets recreated)\n const last = (target as any).__lastPointerForCrop || p;\n (target as any).__lastPointerForCrop = p;\n\n // Calculate delta in canvas coordinates\n const dx = p.x - last.x;\n const dy = p.y - last.y;\n\n // Convert to group-local coordinates accounting for rotation\n const angle = fabric.util.degreesToRadians(target.angle || 0);\n const cos = Math.cos(-angle);\n const sin = Math.sin(-angle);\n\n return {\n localDx: dx * cos - dy * sin,\n localDy: dx * sin + dy * cos,\n };\n}\n\n/**\n * Pan image inside frame (crop)\n * This is called from canvas mouse:move during crop drag\n * CRITICAL: Updates panX/panY (source of truth), then calls updateCoverLayout to apply it\n */\nexport function panImageInside(g: fabric.Group, axis: 'x' | 'y', localDelta: number) {\n const img = (g as any).__cropData?._img;\n if (!img) return;\n\n const { frameW, frameH } = (g as any).__cropData;\n\n const iw = img.width || 1;\n const ih = img.height || 1;\n const s = img.scaleX || 1; // cover scale already applied\n\n const dispW = iw * s;\n const dispH = ih * s;\n const overflowX = Math.max(0, dispW - frameW);\n const overflowY = Math.max(0, dispH - frameH);\n\n // Initialize pan state if needed\n (img as any)._ct = (img as any)._ct || { panX: 0.5, panY: 0.5 };\n\n if (axis === 'x' && overflowX === 0) return;\n if (axis === 'y' && overflowY === 0) return;\n\n if (axis === 'x' && overflowX > 0) {\n const dPan = localDelta / overflowX;\n (img as any)._ct.panX = clamp((img as any)._ct.panX - dPan, 0, 1);\n }\n if (axis === 'y' && overflowY > 0) {\n const dPan = localDelta / overflowY;\n (img as any)._ct.panY = clamp((img as any)._ct.panY - dPan, 0, 1);\n }\n\n // Update layout - this applies panX/panY to img.left/top\n updateCoverLayout(g);\n \n // Mark dirty for live repaint\n (g as any).dirty = true;\n (img as any).dirty = true;\n g.setCoords();\n}\n\n/**\n * Convert world-space delta to the crop group's local (unrotated) axes.\n */\nfunction worldDeltaToLocal(dx: number, dy: number, angleDeg: number): { x: number; y: number } {\n const rad = fabric.util.degreesToRadians(angleDeg || 0);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n return {\n x: dx * cos + dy * sin,\n y: -dx * sin + dy * cos,\n };\n}\n\n/**\n * Convert local-space delta to world-space delta using the crop group's rotation.\n */\nfunction localDeltaToWorld(dx: number, dy: number, angleDeg: number): { x: number; y: number } {\n const rad = fabric.util.degreesToRadians(angleDeg || 0);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n return {\n x: dx * cos - dy * sin,\n y: dx * sin + dy * cos,\n };\n}\n\nfunction getOppositeAnchor(aCoords: any, corner: string): fabric.Point {\n return corner === 'br'\n ? aCoords.tl\n : corner === 'bl'\n ? aCoords.tr\n : corner === 'tr'\n ? aCoords.bl\n : aCoords.br;\n}\n\nfunction getCornerDefaultSigns(corner: string): { x: number; y: number } {\n switch (corner) {\n case 'tr':\n return { x: 1, y: -1 };\n case 'bl':\n return { x: -1, y: 1 };\n case 'br':\n return { x: 1, y: 1 };\n case 'tl':\n default:\n return { x: -1, y: -1 };\n }\n}\n\n/**\n * Returns resize cursor that rotates with object angle so handle direction matches visual orientation.\n */\nfunction getRotatedControlCursor(controlKey: string, target?: fabric.FabricObject | null): string {\n const cursors = ['ns-resize', 'nesw-resize', 'ew-resize', 'nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize', 'nwse-resize'];\n const baseOffsetByControl: Record<string, number> = {\n mt: 0,\n tr: 1,\n mr: 2,\n br: 3,\n mb: 4,\n bl: 5,\n ml: 6,\n tl: 7,\n };\n\n const baseOffset = baseOffsetByControl[controlKey] ?? 0;\n const angle = ((target?.angle ?? 0) % 360 + 360) % 360;\n const angleSteps = Math.round(angle / 45) % 8;\n return cursors[(baseOffset + angleSteps) % 8] ?? 'move';\n}\n\nconst makeRotatedCursorStyleHandler = (controlKey: string) => {\n return (_eventData: any, _control: fabric.Control, target: fabric.FabricObject) =>\n getRotatedControlCursor(controlKey, target);\n};\n\n/**\n * Resize frame from corner (corner handles) - resizes the frame box, image scales to cover\n */\nfunction resizeFrameFromCorner(\n eventData: any,\n transform: any,\n _x: number,\n _y: number\n): boolean {\n const g = transform.target as fabric.Group;\n const ct = (g as any).__cropData;\n if (!ct || !(g as any)._ct?.isCropGroup) return false;\n\n const canvas = g.canvas;\n if (!canvas) return false;\n\n const e = getDomEvent(eventData);\n if (!e) return false;\n\n const pointer = canvas.getPointer(e);\n g.setCoords();\n const a = (g as any).aCoords;\n if (!a) return false;\n\n const corner = transform.corner as string; // 'tl','tr','br','bl'\n const anchor = getOppositeAnchor(a, corner);\n\n const MIN_W = 20;\n const MIN_H = 20;\n const angle = g.angle || 0;\n\n const deltaWorldX = pointer.x - anchor.x;\n const deltaWorldY = pointer.y - anchor.y;\n const localDelta = worldDeltaToLocal(deltaWorldX, deltaWorldY, angle);\n const defaultSigns = getCornerDefaultSigns(corner);\n\n const signX = Math.abs(localDelta.x) < 0.001 ? defaultSigns.x : (localDelta.x >= 0 ? 1 : -1);\n const signY = Math.abs(localDelta.y) < 0.001 ? defaultSigns.y : (localDelta.y >= 0 ? 1 : -1);\n\n const newW = Math.max(MIN_W, Math.abs(localDelta.x));\n const newH = Math.max(MIN_H, Math.abs(localDelta.y));\n\n ct.frameW = newW;\n ct.frameH = newH;\n\n const centerLocal = {\n x: signX * (newW / 2),\n y: signY * (newH / 2),\n };\n const centerWorld = localDeltaToWorld(centerLocal.x, centerLocal.y, angle);\n\n g.set({\n left: anchor.x + centerWorld.x,\n top: anchor.y + centerWorld.y,\n originX: 'center',\n originY: 'center',\n width: newW,\n height: newH,\n });\n\n updateCoverLayout(g);\n canvas.requestRenderAll();\n return true;\n}\n\n/**\n * Resize frame from corner with aspect ratio locked (simple scale mode).\n * Updates ct.frameW/frameH so object:modified can persist the same way as crop handles.\n */\nfunction resizeFrameFromCornerUniform(\n eventData: any,\n transform: any,\n _x: number,\n _y: number\n): boolean {\n const g = transform.target as fabric.Group;\n const ct = (g as any).__cropData;\n if (!ct || !(g as any)._ct?.isCropGroup) return false;\n\n const canvas = g.canvas;\n if (!canvas) return false;\n\n const e = getDomEvent(eventData);\n if (!e) return false;\n\n const pointer = canvas.getPointer(e);\n g.setCoords();\n const a = (g as any).aCoords;\n if (!a) return false;\n\n const corner = transform.corner as string;\n const anchor = getOppositeAnchor(a, corner);\n const defaultSigns = getCornerDefaultSigns(corner);\n\n const MIN_SIZE = 20;\n const baseW = Math.max(MIN_SIZE, ct.frameW || g.width || 1);\n const baseH = Math.max(MIN_SIZE, ct.frameH || g.height || 1);\n\n const angle = g.angle || 0;\n const deltaWorldX = pointer.x - anchor.x;\n const deltaWorldY = pointer.y - anchor.y;\n const localDelta = worldDeltaToLocal(deltaWorldX, deltaWorldY, angle);\n\n const signX = Math.abs(localDelta.x) < 0.001 ? defaultSigns.x : (localDelta.x >= 0 ? 1 : -1);\n const signY = Math.abs(localDelta.y) < 0.001 ? defaultSigns.y : (localDelta.y >= 0 ? 1 : -1);\n\n const rawW = Math.max(MIN_SIZE, Math.abs(localDelta.x));\n const rawH = Math.max(MIN_SIZE, Math.abs(localDelta.y));\n const scaleFromW = rawW / baseW;\n const scaleFromH = rawH / baseH;\n const s = Math.min(scaleFromW, scaleFromH);\n const newW = Math.max(MIN_SIZE, baseW * s);\n const newH = Math.max(MIN_SIZE, baseH * s);\n\n ct.frameW = newW;\n ct.frameH = newH;\n\n const centerLocal = {\n x: signX * (newW / 2),\n y: signY * (newH / 2),\n };\n const centerWorld = localDeltaToWorld(centerLocal.x, centerLocal.y, angle);\n\n g.set({\n left: anchor.x + centerWorld.x,\n top: anchor.y + centerWorld.y,\n originX: 'center',\n originY: 'center',\n width: newW,\n height: newH,\n });\n\n updateCoverLayout(g);\n canvas.requestRenderAll();\n return true;\n}\n\n/**\n * Resize frame from side (side handles) - crops by resizing the mask box\n */\nfunction resizeFrameFromSide(\n g: fabric.Group,\n side: 'ml' | 'mr' | 'mt' | 'mb',\n localDx: number,\n localDy: number\n) {\n const ct = (g as any).__cropData;\n if (!ct) return;\n\n const minSize = 30;\n\n // Move center along local axis to keep dragged edge under cursor\n const moveCenterAlongLocalAxis = (obj: fabric.Group, localX: number, localY: number) => {\n const worldDelta = localDeltaToWorld(localX, localY, obj.angle || 0);\n obj.set({ left: (obj.left || 0) + worldDelta.x, top: (obj.top || 0) + worldDelta.y });\n };\n\n if (side === 'mr') {\n ct.frameW = Math.max(minSize, ct.frameW + localDx);\n moveCenterAlongLocalAxis(g, localDx / 2, 0);\n }\n if (side === 'ml') {\n ct.frameW = Math.max(minSize, ct.frameW - localDx);\n moveCenterAlongLocalAxis(g, localDx / 2, 0);\n }\n if (side === 'mb') {\n ct.frameH = Math.max(minSize, ct.frameH + localDy);\n moveCenterAlongLocalAxis(g, 0, localDy / 2);\n }\n if (side === 'mt') {\n ct.frameH = Math.max(minSize, ct.frameH - localDy);\n moveCenterAlongLocalAxis(g, 0, localDy / 2);\n }\n\n updateCoverLayout(g);\n}\n\n/**\n * Install Canva-style controls on a crop group:\n * - Corner handles → uniform scale of the frame (image scales with it, no crop)\n * - Side handles → crop (resize frame on one axis only, image stays at same scale)\n *\n * This is the single, default control set for image elements (no more mode toggle).\n */\nexport function installCanvaMaskControls(g: fabric.Group) {\n const ct = (g as any).__cropData;\n if (ct) (ct as any).fit = (ct as any).fit ?? 'cover';\n\n g.setControlsVisibility({\n mt: true,\n mb: true,\n ml: true,\n mr: true,\n tl: true,\n tr: true,\n bl: true,\n br: true,\n mtr: true,\n });\n\n g.padding = 0;\n\n const makeSideControl = (\n key: 'ml' | 'mr' | 'mt' | 'mb',\n x: number,\n y: number,\n cursor: string,\n side: 'ml' | 'mr' | 'mt' | 'mb'\n ) => {\n return new fabric.Control({\n x,\n y,\n cursorStyle: cursor,\n cursorStyleHandler: makeRotatedCursorStyleHandler(key),\n actionName: 'crop',\n actionHandler: (eventData: any, transform: any) => {\n const t = transform.target as fabric.Group;\n const canvas = t.canvas;\n\n if (canvas && (canvas as any).__editLockRef) {\n (canvas as any).__editLockRef.current = true;\n }\n\n const { localDx, localDy } = getLocalDeltaStable(t, eventData);\n (t as any).__lockScaleDuringCrop = true;\n\n resizeFrameFromSide(t, side, localDx, localDy);\n\n t.canvas?.requestRenderAll();\n return true;\n },\n });\n };\n\n g.controls.ml = makeSideControl('ml', -0.5, 0, 'ew-resize', 'ml');\n g.controls.mr = makeSideControl('mr', 0.5, 0, 'ew-resize', 'mr');\n g.controls.mt = makeSideControl('mt', 0, -0.5, 'ns-resize', 'mt');\n g.controls.mb = makeSideControl('mb', 0, 0.5, 'ns-resize', 'mb');\n\n g.lockScalingX = true;\n g.lockScalingY = true;\n\n // Corner handles → uniform scale (aspect-ratio locked). Image scales with the frame.\n const makeCornerControl = (key: 'tl' | 'tr' | 'bl' | 'br', x: number, y: number, cursor: string) => {\n return new fabric.Control({\n x,\n y,\n cursorStyle: cursor,\n cursorStyleHandler: makeRotatedCursorStyleHandler(key),\n actionName: 'resize',\n actionHandler: (eventData: any, transform: any) => {\n const t = transform.target as fabric.Group;\n const canvas = t.canvas;\n\n if (canvas && (canvas as any).__editLockRef) {\n (canvas as any).__editLockRef.current = true;\n }\n\n return resizeFrameFromCornerUniform(eventData, transform, 0, 0);\n },\n });\n };\n\n g.controls.tl = makeCornerControl('tl', -0.5, -0.5, 'nwse-resize');\n g.controls.tr = makeCornerControl('tr', 0.5, -0.5, 'nesw-resize');\n g.controls.bl = makeCornerControl('bl', -0.5, 0.5, 'nesw-resize');\n g.controls.br = makeCornerControl('br', 0.5, 0.5, 'nwse-resize');\n\n (g as any).__hasCustomControls = true;\n}\n\n/**\n * Simple scale mode (crop handles unchecked): corner handles only, aspect ratio locked.\n * Does not change fit/clip — image stays clipped to the frame (cover); only the controls change (no pan/zoom handles).\n * Custom control updates ct.frameW/frameH so save/reload works like crop handles.\n */\nexport function setSimpleScaleControls(g: fabric.Group) {\n if (!(g as any).__cropGroup) return;\n\n const ct = (g as any).__cropData;\n if (ct) {\n updateCoverLayout(g);\n }\n\n g.lockScalingX = true;\n g.lockScalingY = true;\n\n g.setControlsVisibility({\n mt: false,\n mb: false,\n ml: false,\n mr: false,\n tl: true,\n tr: true,\n bl: true,\n br: true,\n mtr: true,\n });\n\n g.padding = 0;\n\n const makeCornerControl = (key: 'tl' | 'tr' | 'bl' | 'br', x: number, y: number, cursor: string) =>\n new fabric.Control({\n x,\n y,\n cursorStyle: cursor,\n cursorStyleHandler: makeRotatedCursorStyleHandler(key),\n actionName: 'resize',\n actionHandler: (eventData: any, transform: any) => {\n const t = transform.target as fabric.Group;\n if (t.canvas && (t.canvas as any).__editLockRef) {\n (t.canvas as any).__editLockRef.current = true;\n }\n return resizeFrameFromCornerUniform(eventData, transform, 0, 0);\n },\n });\n\n g.controls.tl = makeCornerControl('tl', -0.5, -0.5, 'nwse-resize');\n g.controls.tr = makeCornerControl('tr', 0.5, -0.5, 'nesw-resize');\n g.controls.bl = makeCornerControl('bl', -0.5, 0.5, 'nesw-resize');\n g.controls.br = makeCornerControl('br', 0.5, 0.5, 'nwse-resize');\n\n (g as any).__hasCustomControls = true;\n g.setCoords();\n}\n\n/**\n * Creates a Canva-like masked image element:\n * - Group contains: image + frame (optional visible border)\n * - clipPath is the frame shape (absolutePositioned)\n * - Maintains \"object-fit: cover\" via img._ct = { panX, panY } normalized [0..1]\n */\nexport async function createMaskedImageElement({\n url,\n image,\n frameW = 300,\n frameH = 200,\n shape = 'roundRect', // 'circle' | 'roundRect' | 'rect'\n rx = 24, // only for roundRect\n stroke = null, // border if you want: \"#999\"\n strokeWidth = 0,\n left = 100,\n top = 100,\n angle = 0,\n opacity = 1,\n selectable = true,\n evented = true,\n visible = true,\n panX = 0.5,\n panY = 0.5,\n zoom = 1,\n}: {\n url?: string;\n image?: fabric.FabricImage;\n frameW?: number;\n frameH?: number;\n shape?: 'circle' | 'roundRect' | 'rect';\n rx?: number;\n stroke?: string | null;\n strokeWidth?: number;\n left?: number;\n top?: number;\n angle?: number;\n opacity?: number;\n selectable?: boolean;\n evented?: boolean;\n visible?: boolean;\n panX?: number;\n panY?: number;\n zoom?: number;\n}): Promise<fabric.Group> {\n // Use provided image or load from URL\n // CRITICAL: Use proxy URL to avoid CORS taint issues in export\n const img = image || (url ? await fabric.FabricImage.fromURL(getProxiedImageUrl(url), { crossOrigin: 'anonymous' }) : null);\n if (!img) {\n throw new Error('Either url or image must be provided');\n }\n\n // frame (clip)\n const frame =\n shape === 'circle'\n ? new fabric.Ellipse({\n rx: frameW / 2,\n ry: frameH / 2,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n })\n : new fabric.Rect({\n width: frameW,\n height: frameH,\n rx,\n ry: rx,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n });\n\n // Optional visible border (separate object so clipPath stays clean)\n const border =\n stroke\n ? (shape === 'circle'\n ? new fabric.Ellipse({\n rx: frameW / 2,\n ry: frameH / 2,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n fill: 'transparent',\n stroke,\n strokeWidth,\n selectable: false,\n evented: false,\n })\n : new fabric.Rect({\n width: frameW,\n height: frameH,\n rx,\n ry: rx,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n fill: 'transparent',\n stroke,\n strokeWidth,\n selectable: false,\n evented: false,\n }))\n : null;\n\n // Put image initially centered; we will scale+offset with updateCover()\n // IMPORTANT: children should not receive events - they should be non-interactive\n // CRITICAL: Don't set opacity on the image - opacity should only be on the group\n // Setting opacity on both group and child would double-apply it\n img.set({\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n selectable: false, // group is selectable; image should not be\n evented: false,\n opacity: 1, // CRITICAL: Always 1 for child - group handles opacity\n // Preserve image-level caching settings if they exist\n objectCaching: (img as any).objectCaching ?? false,\n noScaleCache: (img as any).noScaleCache ?? true,\n });\n\n // Store crop state on image (normalized pan 0..1, zoom >= 1)\n (img as any)._ct = { panX: panX ?? 0.5, panY: panY ?? 0.5, zoom: zoom ?? 1 };\n\n // IMPORTANT: children should not receive events\n img.set({ selectable: false, evented: false });\n border?.set({ selectable: false, evented: false });\n\n // Ensure the crop group is marked and children are absolutely non-targetable\n img.set({ \n evented: false, \n selectable: false, \n hasControls: false, \n hasBorders: false \n });\n if (border) {\n border.set({ evented: false, selectable: false });\n }\n\n const groupItems = border ? [img, border] : [img];\n const g = new fabric.Group(groupItems, {\n left,\n top,\n originX: 'center',\n originY: 'center',\n angle,\n opacity,\n visible,\n evented: true,\n selectable: true,\n hasControls: true,\n hasBorders: true,\n subTargetCheck: false, // don't look inside group\n interactive: true, // CRITICAL: Keep interactive for proper control detection\n perPixelTargetFind: false,\n objectCaching: false,\n });\n\n // CRITICAL: Disable Fabric v6's auto-layout that recalculates group dimensions from children.\n // Crop groups use explicit frameW/frameH — the layout manager would override those with\n // child-based bounds, making small images (e.g. bullets) grow to the SVG's natural size.\n if ((g as any).layoutManager) {\n // Use FixedLayout strategy if available, otherwise disable performLayout\n if (typeof fabric.FixedLayout === 'function') {\n (g as any).layoutManager.strategy = new fabric.FixedLayout();\n } else {\n // Fallback: stub out performLayout to prevent auto-resize\n (g as any).layoutManager.performLayout = () => {};\n }\n }\n\n // Attach our frame data to group. Default fit = 'cover' so image is clipped to frame (matches editor).\n (g as any).__cropData = {\n shape,\n rx,\n frameW,\n frameH,\n fit: 'cover', // clip image to frame; use 'contain' only when simple-scale mode is set\n _img: img,\n _border: border,\n };\n \n // Mark as crop group for promotion logic\n (g as any)._ct = (g as any)._ct || {};\n (g as any)._ct.isCropGroup = true;\n (g as any).__cropGroup = true; // Keep for backwards compatibility\n\n // ClipPath: use group-local positioning for better live resize behavior\n // Group-local is recommended over absolutePositioned for live updates\n const clip = shape === 'circle'\n ? new fabric.Ellipse({\n rx: frameW / 2,\n ry: frameH / 2,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n // CRITICAL: Make clipPath non-interactive so it doesn't intercept clicks\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n })\n : new fabric.Rect({\n width: frameW,\n height: frameH,\n rx,\n ry: rx,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n // CRITICAL: Make clipPath non-interactive so it doesn't intercept clicks\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n // Use group-local positioning (not absolutePositioned) for better live updates\n (clip as any).absolutePositioned = false;\n (clip as any).excludeFromExport = true; // Don't export clipPath\n g.clipPath = clip;\n \n // CRITICAL: Ensure crop group is always selectable and evented\n g.set({\n selectable: true,\n evented: true,\n hasControls: true,\n hasBorders: true,\n interactive: true,\n subTargetCheck: false,\n });\n\n // CRITICAL: Set group dimensions to frame size initially\n // This ensures controls are positioned correctly from the start\n g.set({\n width: frameW,\n height: frameH,\n });\n \n // setCoords() will recalculate everything needed for controls\n g.setCoords();\n\n // apply initial layout\n updateCoverLayout(g);\n\n // Default Canva-style controls: corner handles uniform-scale, side handles crop.\n installCanvaMaskControls(g);\n\n return g;\n}\n","/**\n * Canva/Figma-style true crop mode for image elements.\n *\n * UX:\n * - Double-click an image element → enter crop mode\n * - The full underlying image becomes visible at low opacity (ghost) so the user\n * sees what's outside the mask\n * - A dashed outline marks the visible mask area\n * - User drags the image to pan it inside the mask (moves image only, not the frame)\n * - Corner handles inside crop mode SCALE the image (zoom in/out) — frame stays fixed\n * - Escape / Enter / click outside → commit & exit\n *\n * Implementation notes:\n * - Crop state lives on `cropGroup.__cropData._(img as any)._ct = { panX, panY, zoom }`.\n * `updateCoverLayout()` already applies these to the actual image inside the mask.\n * We just mutate them; existing persistence in PageCanvas debounces them\n * into `cropPanX/Y/Zoom` element fields on `object:modified`.\n * - The \"ghost\" is a clone of the inner image with no clipPath, low opacity,\n * placed in the same group-local position as the real image. We render it\n * on the canvas (not inside the group) so it can extend OUTSIDE the mask.\n */\nimport * as fabric from 'fabric';\nimport { updateCoverLayout, installCanvaMaskControls } from './canvaMaskedImage';\n\nconst CROP_MODE_FLAG = '__inCropMode';\nconst CROP_GHOST_FLAG = '__cropGhost';\nconst CROP_OUTLINE_FLAG = '__cropOutline';\nconst CROP_HANDLERS_FLAG = '__cropHandlers';\n\nexport function isCropGroupInCropMode(g: fabric.Group): boolean {\n return Boolean((g as any)[CROP_MODE_FLAG]);\n}\n\nfunction clamp(v: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, v));\n}\n\n/** Reapply ghost transform to mirror the inner image's current pan/zoom in canvas-space. */\nfunction syncGhostTransform(g: fabric.Group) {\n const ghost = (g as any)[CROP_GHOST_FLAG] as fabric.FabricImage | undefined;\n const ct = (g as any).__cropData;\n if (!ghost || !ct?._img) return;\n const img = ct._img as fabric.FabricImage;\n const finalScale = img.scaleX || 1;\n\n // Group center in canvas coords\n const gLeft = g.left ?? 0;\n const gTop = g.top ?? 0;\n const angle = g.angle ?? 0;\n\n // Image's group-local offset (image is center-origin within the group)\n const imgLocalLeft = img.left ?? 0;\n const imgLocalTop = img.top ?? 0;\n\n // Rotate local offset into world coords\n const rad = fabric.util.degreesToRadians(angle);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const worldDx = imgLocalLeft * cos - imgLocalTop * sin;\n const worldDy = imgLocalLeft * sin + imgLocalTop * cos;\n\n ghost.set({\n left: gLeft + worldDx,\n top: gTop + worldDy,\n scaleX: finalScale,\n scaleY: finalScale,\n angle,\n originX: 'center',\n originY: 'center',\n });\n ghost.setCoords();\n}\n\n/** Reapply outline transform to mirror the mask frame in canvas-space. */\nfunction syncOutlineTransform(g: fabric.Group) {\n const outline = (g as any)[CROP_OUTLINE_FLAG] as fabric.FabricObject | undefined;\n const ct = (g as any).__cropData;\n if (!outline || !ct) return;\n outline.set({\n left: g.left ?? 0,\n top: g.top ?? 0,\n width: ct.frameW,\n height: ct.frameH,\n angle: g.angle ?? 0,\n originX: 'center',\n originY: 'center',\n });\n if (outline instanceof fabric.Rect) {\n const minDim = Math.min(ct.frameW, ct.frameH);\n const rxRatio = ct.rx ?? 0;\n let rx = rxRatio > 0.5 ? rxRatio : rxRatio * minDim;\n rx = Math.max(0, Math.min(rx, ct.frameW / 2, ct.frameH / 2));\n outline.set({ rx, ry: rx });\n }\n outline.setCoords();\n}\n\n/** Install crop-mode visuals: hide all handles, keep accent border only. */\nfunction installCropModeVisuals(g: fabric.Group) {\n // Hide ALL handles in crop mode — resizing happens after exit\n g.setControlsVisibility({\n mt: false, mb: false, ml: false, mr: false,\n tl: false, tr: false, bl: false, br: false,\n mtr: false,\n });\n\n g.hasControls = false;\n g.lockScalingX = true;\n g.lockScalingY = true;\n g.lockRotation = true;\n // Movement: we'll intercept and redirect to image pan, so allow it at fabric level\n g.lockMovementX = false;\n g.lockMovementY = false;\n\n // Visual: brighter accent border for crop mode\n g.borderColor = 'hsl(256, 80%, 58%)';\n g.borderDashArray = [4, 4];\n\n g.setCoords();\n}\n\n/**\n * Enter crop mode on a crop group. Returns true if entered, false if already in mode\n * or not a crop group.\n */\nexport function enterCropMode(g: fabric.Group): boolean {\n const ct = (g as any).__cropData;\n if (!ct?._img) return false;\n if ((g as any)[CROP_MODE_FLAG]) return false;\n const canvas = g.canvas;\n if (!canvas) return false;\n\n (g as any)[CROP_MODE_FLAG] = true;\n\n const innerImg = ct._img as fabric.FabricImage;\n const imgEl = (innerImg as any)._element;\n if (!imgEl) {\n (g as any)[CROP_MODE_FLAG] = false;\n return false;\n }\n\n // 1) Build the dimmed ghost (full image, no clip), placed under the group's image\n const ghost = new fabric.FabricImage(imgEl, {\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n opacity: 0.35,\n originX: 'center',\n originY: 'center',\n objectCaching: false,\n });\n (ghost as any).excludeFromExport = true;\n (ghost as any)[CROP_GHOST_FLAG] = true;\n\n // 2) Build a dashed outline of the mask frame for visual reference\n const outlineShape = ct.shape;\n const outline = outlineShape === 'circle'\n ? new fabric.Ellipse({\n rx: ct.frameW / 2,\n ry: ct.frameH / 2,\n fill: 'transparent',\n stroke: 'hsl(256, 80%, 58%)',\n strokeWidth: 1.5,\n strokeDashArray: [6, 4],\n strokeUniform: true,\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n originX: 'center',\n originY: 'center',\n objectCaching: false,\n })\n : new fabric.Rect({\n width: ct.frameW,\n height: ct.frameH,\n fill: 'transparent',\n stroke: 'hsl(256, 80%, 58%)',\n strokeWidth: 1.5,\n strokeDashArray: [6, 4],\n strokeUniform: true,\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n originX: 'center',\n originY: 'center',\n objectCaching: false,\n });\n (outline as any).excludeFromExport = true;\n (outline as any)[CROP_OUTLINE_FLAG] = true;\n\n (g as any)[CROP_GHOST_FLAG] = ghost;\n (g as any)[CROP_OUTLINE_FLAG] = outline;\n\n // Insert ghost just under the group, outline just above (still under group? — above so it's visible)\n // Order: ghost (lowest), then group with clipped image, then outline on top\n const groupIndex = (canvas as any)._objects.indexOf(g);\n if (groupIndex >= 0) {\n canvas.insertAt(groupIndex, ghost);\n canvas.add(outline);\n // Ensure group sits above ghost; bring outline to front above group\n canvas.bringObjectToFront(g);\n canvas.bringObjectToFront(outline);\n } else {\n canvas.add(ghost);\n canvas.add(g);\n canvas.add(outline);\n }\n\n syncGhostTransform(g);\n syncOutlineTransform(g);\n\n // 3) Drag-to-pan: let Fabric move the group, snap it back, and convert the\n // accumulated world delta into pan. RAF-throttled for smooth tracking.\n const groupAnchor = { left: g.left ?? 0, top: g.top ?? 0 };\n let panRafId: number | null = null;\n let pendingDx = 0;\n let pendingDy = 0;\n let lastDragDx = 0;\n let lastDragDy = 0;\n\n const flushPan = () => {\n panRafId = null;\n if (pendingDx === 0 && pendingDy === 0) return;\n const innerCt = (g as any).__cropData;\n const img = innerCt?._img as fabric.FabricImage | undefined;\n if (!img) {\n pendingDx = 0;\n pendingDy = 0;\n return;\n }\n\n const angle = g.angle ?? 0;\n const rad = fabric.util.degreesToRadians(-angle);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const localDx = pendingDx * cos - pendingDy * sin;\n const localDy = pendingDx * sin + pendingDy * cos;\n pendingDx = 0;\n pendingDy = 0;\n\n const iw = img.width || 1;\n const ih = img.height || 1;\n const finalScale = img.scaleX || 1;\n const dispW = iw * finalScale;\n const dispH = ih * finalScale;\n const overflowX = Math.max(0, dispW - innerCt.frameW);\n const overflowY = Math.max(0, dispH - innerCt.frameH);\n\n (img as any)._ct = (img as any)._ct || { panX: 0.5, panY: 0.5, zoom: 1 };\n const ct = (img as any)._ct;\n if (overflowX > 0) ct.panX = clamp((ct.panX ?? 0.5) - localDx / overflowX, 0, 1);\n if (overflowY > 0) ct.panY = clamp((ct.panY ?? 0.5) - localDy / overflowY, 0, 1);\n\n updateCoverLayout(g);\n syncGhostTransform(g);\n g.setCoords();\n canvas.requestRenderAll();\n };\n\n const onMoving = (opt: any) => {\n const target = opt?.target as fabric.Group | undefined;\n if (target !== g) return;\n\n const rawDx = (g.left ?? 0) - groupAnchor.left;\n const rawDy = (g.top ?? 0) - groupAnchor.top;\n const dx = rawDx - lastDragDx;\n const dy = rawDy - lastDragDy;\n lastDragDx = rawDx;\n lastDragDy = rawDy;\n\n g.left = groupAnchor.left;\n g.top = groupAnchor.top;\n if (dx === 0 && dy === 0) return;\n\n pendingDx += dx;\n pendingDy += dy;\n if (panRafId == null) panRafId = requestAnimationFrame(flushPan);\n };\n\n const onModified = (opt: any) => {\n const target = opt?.target as fabric.Group | undefined;\n if (target !== g) return;\n if (panRafId != null) {\n cancelAnimationFrame(panRafId);\n panRafId = null;\n flushPan();\n }\n lastDragDx = 0;\n lastDragDy = 0;\n g.left = groupAnchor.left;\n g.top = groupAnchor.top;\n g.setCoords();\n };\n\n const onCanvasMouseDown = (opt: fabric.TEvent) => {\n const target = (opt as any).target as fabric.FabricObject | null;\n if (target === g || target === ghost || target === outline) return;\n setTimeout(() => exitCropMode(g, true), 0);\n };\n\n // Double-click on the group/ghost/outline → exit crop mode (Canva-style toggle).\n const onDblClick = (opt: any) => {\n const target = opt?.target as fabric.FabricObject | null;\n if (target !== g && target !== ghost && target !== outline) return;\n exitCropMode(g, true);\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape' || e.key === 'Enter') {\n e.preventDefault();\n e.stopPropagation();\n exitCropMode(g, true);\n }\n };\n\n // Wheel / pinch zoom inside the mask, anchored at cursor. RAF-throttled.\n let wheelCommitTimer: ReturnType<typeof setTimeout> | null = null;\n let zoomRafId: number | null = null;\n let pendingZoomDelta = 0;\n let pendingZoomCenter: { x: number; y: number } | null = null;\n let lastWheelWasPinch = false;\n\n const flushZoom = () => {\n zoomRafId = null;\n if (pendingZoomDelta === 0 || !pendingZoomCenter) return;\n const innerCt = (g as any).__cropData;\n const img = innerCt?._img as fabric.FabricImage | undefined;\n if (!img) {\n pendingZoomDelta = 0;\n pendingZoomCenter = null;\n return;\n }\n\n const factor = lastWheelWasPinch ? 0.012 : 0.0022;\n const ratio = Math.exp(-pendingZoomDelta * factor);\n pendingZoomDelta = 0;\n\n (img as any)._ct = (img as any)._ct || { panX: 0.5, panY: 0.5, zoom: 1 };\n const ct = (img as any)._ct;\n const prevZoom = ct.zoom ?? 1;\n const nextZoom = clamp(prevZoom * ratio, 1, 8);\n if (nextZoom === prevZoom) {\n pendingZoomCenter = null;\n return;\n }\n\n // Cursor-anchored zoom: keep the image point under the cursor stationary.\n const angle = g.angle ?? 0;\n const rad = fabric.util.degreesToRadians(-angle);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const cx = g.left ?? 0;\n const cy = g.top ?? 0;\n const wx = pendingZoomCenter.x - cx;\n const wy = pendingZoomCenter.y - cy;\n const localCx = wx * cos - wy * sin;\n const localCy = wx * sin + wy * cos;\n\n const iw = img.width || 1;\n const ih = img.height || 1;\n const prevScale = img.scaleX || 1;\n const prevOverflowX = Math.max(0, iw * prevScale - innerCt.frameW);\n const prevOverflowY = Math.max(0, ih * prevScale - innerCt.frameH);\n const prevPanX = ct.panX ?? 0.5;\n const prevPanY = ct.panY ?? 0.5;\n const prevOffsetX = prevOverflowX > 0 ? -prevOverflowX * (prevPanX - 0.5) : 0;\n const prevOffsetY = prevOverflowY > 0 ? -prevOverflowY * (prevPanY - 0.5) : 0;\n const imgPxX = (localCx - prevOffsetX) / prevScale + iw / 2;\n const imgPxY = (localCy - prevOffsetY) / prevScale + ih / 2;\n\n ct.zoom = nextZoom;\n updateCoverLayout(g);\n\n const newScale = img.scaleX || 1;\n const newOverflowX = Math.max(0, iw * newScale - innerCt.frameW);\n const newOverflowY = Math.max(0, ih * newScale - innerCt.frameH);\n\n if (newOverflowX > 0) {\n const desiredOffsetX = localCx - (imgPxX - iw / 2) * newScale;\n ct.panX = clamp(0.5 - desiredOffsetX / newOverflowX, 0, 1);\n } else {\n ct.panX = 0.5;\n }\n if (newOverflowY > 0) {\n const desiredOffsetY = localCy - (imgPxY - ih / 2) * newScale;\n ct.panY = clamp(0.5 - desiredOffsetY / newOverflowY, 0, 1);\n } else {\n ct.panY = 0.5;\n }\n\n updateCoverLayout(g);\n syncGhostTransform(g);\n g.setCoords();\n canvas.requestRenderAll();\n\n if (wheelCommitTimer) clearTimeout(wheelCommitTimer);\n wheelCommitTimer = setTimeout(() => {\n canvas.fire('object:modified', { target: g } as any);\n g.left = groupAnchor.left;\n g.top = groupAnchor.top;\n g.setCoords();\n }, 200);\n\n pendingZoomCenter = null;\n };\n\n const onWheel = (e: WheelEvent) => {\n if (!canvas) return;\n const innerCt = (g as any).__cropData;\n if (!innerCt) return;\n\n const pointer = canvas.getPointer(e as any, false);\n const br = g.getBoundingRect();\n if (\n pointer.x < br.left ||\n pointer.x > br.left + br.width ||\n pointer.y < br.top ||\n pointer.y > br.top + br.height\n ) return;\n\n const img = innerCt._img as fabric.FabricImage | undefined;\n if (!img) return;\n\n e.preventDefault();\n e.stopPropagation();\n\n pendingZoomDelta += e.deltaY;\n pendingZoomCenter = pointer;\n lastWheelWasPinch = !!e.ctrlKey;\n if (zoomRafId == null) zoomRafId = requestAnimationFrame(flushZoom);\n };\n\n canvas.on('object:moving', onMoving);\n canvas.on('object:modified', onModified);\n canvas.on('mouse:down:before', onCanvasMouseDown);\n canvas.on('mouse:dblclick', onDblClick);\n window.addEventListener('keydown', onKeyDown, true);\n const upperCanvasEl = (canvas as any).upperCanvasEl as HTMLCanvasElement | undefined;\n upperCanvasEl?.addEventListener('wheel', onWheel, { passive: false });\n\n (g as any)[CROP_HANDLERS_FLAG] = {\n onMoving, onModified, onCanvasMouseDown, onDblClick, onKeyDown, onWheel, upperCanvasEl,\n };\n\n // 4) Install crop-mode visuals (no handles)\n installCropModeVisuals(g);\n\n // Ensure group stays selected and on top\n canvas.setActiveObject(g);\n canvas.requestRenderAll();\n return true;\n}\n\n/**\n * Exit crop mode. If `commit` is true, fires object:modified to persist.\n */\nexport function exitCropMode(g: fabric.Group, commit = true): void {\n if (!(g as any)[CROP_MODE_FLAG]) return;\n const canvas = g.canvas;\n\n const handlers = (g as any)[CROP_HANDLERS_FLAG];\n if (handlers && canvas) {\n canvas.off('object:moving', handlers.onMoving);\n canvas.off('object:modified', handlers.onModified);\n canvas.off('mouse:down:before', handlers.onCanvasMouseDown);\n if (handlers.onDblClick) canvas.off('mouse:dblclick', handlers.onDblClick);\n window.removeEventListener('keydown', handlers.onKeyDown, true);\n handlers.upperCanvasEl?.removeEventListener('wheel', handlers.onWheel);\n }\n (g as any)[CROP_HANDLERS_FLAG] = undefined;\n\n const ghost = (g as any)[CROP_GHOST_FLAG] as fabric.FabricObject | undefined;\n const outline = (g as any)[CROP_OUTLINE_FLAG] as fabric.FabricObject | undefined;\n if (canvas && ghost) canvas.remove(ghost);\n if (canvas && outline) canvas.remove(outline);\n (g as any)[CROP_GHOST_FLAG] = undefined;\n (g as any)[CROP_OUTLINE_FLAG] = undefined;\n\n // Restore movement, controls & default canva mask controls\n g.lockMovementX = false;\n g.lockMovementY = false;\n g.lockRotation = false;\n g.lockScalingX = false;\n g.lockScalingY = false;\n g.hasControls = true;\n (g as any).borderDashArray = undefined;\n installCanvaMaskControls(g);\n // Restore brand-styled border/corner colors. Setting these to `undefined`\n // makes Fabric fall back to its built-in defaults (black border + black\n // corners), which is what was causing the handles/outline to flip from\n // violet to black after exiting crop mode.\n (g as any).borderColor = '#4f46e5';\n (g as any).borderDashArray = undefined;\n (g as any).cornerColor = '#ffffff';\n (g as any).cornerStrokeColor = '#4f46e5';\n (g as any).cornerStyle = 'rect';\n (g as any).transparentCorners = false;\n\n (g as any)[CROP_MODE_FLAG] = false;\n (g as any).__cropZoomLastPointer = undefined;\n (g as any).__lastPointerForCrop = undefined;\n\n if (commit && canvas) {\n canvas.fire('object:modified', { target: g } as any);\n }\n canvas?.requestRenderAll();\n}\n\n/** Convenience: toggle crop mode on a group. */\nexport function toggleCropMode(g: fabric.Group): void {\n if ((g as any)[CROP_MODE_FLAG]) exitCropMode(g, true);\n else enterCropMode(g);\n}\n","import * as fabric from 'fabric';\nimport { getObjectId } from './fabricUtils';\n\nexport interface SnapGuide {\n type: 'vertical' | 'horizontal';\n position: number;\n start?: number;\n end?: number;\n /** When true, guide is the current snap target (e.g. grid column/row boundary); draw with emphasis. */\n active?: boolean;\n /** Distance in pixels (e.g. from moving edge to guide); shown on the guide when set. */\n distance?: number;\n}\n\ninterface SnapPoints {\n left: number;\n right: number;\n top: number;\n bottom: number;\n centerX: number;\n centerY: number;\n}\n\nfunction getObjectSnapPoints(obj: fabric.FabricObject): SnapPoints {\n try {\n obj.setCoords();\n const bounds = obj.getBoundingRect();\n return {\n left: bounds.left,\n right: bounds.left + bounds.width,\n top: bounds.top,\n bottom: bounds.top + bounds.height,\n centerX: bounds.left + bounds.width / 2,\n centerY: bounds.top + bounds.height / 2,\n };\n } catch {\n const left = obj.left ?? 0;\n const top = obj.top ?? 0;\n const width = (obj.width ?? 0) * (obj.scaleX ?? 1);\n const height = (obj.height ?? 0) * (obj.scaleY ?? 1);\n return {\n left,\n right: left + width,\n top,\n bottom: top + height,\n centerX: left + width / 2,\n centerY: top + height / 2,\n };\n }\n}\n\ninterface SnapCandidate {\n delta: number;\n distance: number;\n guide: SnapGuide;\n}\n\nexport function calculateSnapGuides(\n movingObj: fabric.FabricObject,\n canvas: fabric.Canvas,\n canvasWidth: number,\n canvasHeight: number,\n snapToGuides: boolean,\n snapThreshold: number\n): { guides: SnapGuide[]; snapDx: number; snapDy: number } {\n if (!snapToGuides) return { guides: [], snapDx: 0, snapDy: 0 };\n\n const threshold = snapThreshold || 5;\n const newGuides: SnapGuide[] = [];\n const horizontalSnaps: SnapCandidate[] = [];\n const verticalSnaps: SnapCandidate[] = [];\n\n const moving = getObjectSnapPoints(movingObj);\n const movingId = getObjectId(movingObj);\n const canvasCenterX = canvasWidth / 2;\n const canvasCenterY = canvasHeight / 2;\n\n const addVerticalSnap = (objPoint: number, targetPoint: number, guide: SnapGuide) => {\n const distance = Math.abs(objPoint - targetPoint);\n if (distance < threshold) {\n verticalSnaps.push({ delta: targetPoint - objPoint, distance, guide });\n }\n };\n\n const addHorizontalSnap = (objPoint: number, targetPoint: number, guide: SnapGuide) => {\n const distance = Math.abs(objPoint - targetPoint);\n if (distance < threshold) {\n horizontalSnaps.push({ delta: targetPoint - objPoint, distance, guide });\n }\n };\n\n // Canvas edge snapping\n addVerticalSnap(moving.left, 0, { type: 'vertical', position: 0 });\n addVerticalSnap(moving.right, canvasWidth, { type: 'vertical', position: canvasWidth });\n addHorizontalSnap(moving.top, 0, { type: 'horizontal', position: 0 });\n addHorizontalSnap(moving.bottom, canvasHeight, { type: 'horizontal', position: canvasHeight });\n\n addVerticalSnap(moving.centerX, canvasCenterX, { type: 'vertical', position: canvasCenterX });\n addHorizontalSnap(moving.centerY, canvasCenterY, { type: 'horizontal', position: canvasCenterY });\n\n const rawObjects = canvas.getObjects();\n const allObjects: fabric.FabricObject[] = [];\n\n for (const obj of rawObjects) {\n if (obj === movingObj) continue;\n const objId = getObjectId(obj);\n if (objId === '__background__') continue;\n if (movingObj.type === 'activeselection') {\n const activeSelection = movingObj as fabric.ActiveSelection;\n if (activeSelection.contains(obj)) continue;\n }\n if (movingObj instanceof fabric.Group && typeof (movingObj as any).getObjects === 'function') {\n const inner = (movingObj as fabric.Group).getObjects();\n if (inner.includes(obj)) continue;\n }\n if (objId && objId === movingId) continue;\n allObjects.push(obj);\n }\n\n for (const otherObj of allObjects) {\n const other = getObjectSnapPoints(otherObj);\n\n addVerticalSnap(moving.left, other.left, { type: 'vertical', position: other.left, start: Math.min(moving.top, other.top), end: Math.max(moving.bottom, other.bottom) });\n addVerticalSnap(moving.right, other.right, { type: 'vertical', position: other.right, start: Math.min(moving.top, other.top), end: Math.max(moving.bottom, other.bottom) });\n addVerticalSnap(moving.left, other.right, { type: 'vertical', position: other.right, start: Math.min(moving.top, other.top), end: Math.max(moving.bottom, other.bottom) });\n addVerticalSnap(moving.right, other.left, { type: 'vertical', position: other.left, start: Math.min(moving.top, other.top), end: Math.max(moving.bottom, other.bottom) });\n addVerticalSnap(moving.centerX, other.centerX, { type: 'vertical', position: other.centerX, start: Math.min(moving.top, other.top), end: Math.max(moving.bottom, other.bottom) });\n\n addHorizontalSnap(moving.top, other.top, { type: 'horizontal', position: other.top, start: Math.min(moving.left, other.left), end: Math.max(moving.right, other.right) });\n addHorizontalSnap(moving.bottom, other.bottom, { type: 'horizontal', position: other.bottom, start: Math.min(moving.left, other.left), end: Math.max(moving.right, other.right) });\n addHorizontalSnap(moving.top, other.bottom, { type: 'horizontal', position: other.bottom, start: Math.min(moving.left, other.left), end: Math.max(moving.right, other.right) });\n addHorizontalSnap(moving.bottom, other.top, { type: 'horizontal', position: other.top, start: Math.min(moving.left, other.left), end: Math.max(moving.right, other.right) });\n addHorizontalSnap(moving.centerY, other.centerY, { type: 'horizontal', position: other.centerY, start: Math.min(moving.left, other.left), end: Math.max(moving.right, other.right) });\n }\n\n // Only show guides for the closest snap (sibling/edge we're snapping to) with distance\n let snapDx = 0;\n let snapDy = 0;\n\n if (verticalSnaps.length > 0) {\n verticalSnaps.sort((a, b) => a.distance - b.distance);\n const bestSnap = verticalSnaps[0];\n snapDx = bestSnap.delta;\n newGuides.push({ ...bestSnap.guide, distance: Math.round(bestSnap.distance) });\n }\n\n if (horizontalSnaps.length > 0) {\n horizontalSnaps.sort((a, b) => a.distance - b.distance);\n const bestSnap = horizontalSnaps[0];\n snapDy = bestSnap.delta;\n newGuides.push({ ...bestSnap.guide, distance: Math.round(bestSnap.distance) });\n }\n\n return { guides: newGuides, snapDx, snapDy };\n}\n\nexport function calculateScaleSnapGuides(\n scalingObj: fabric.FabricObject,\n corner: string,\n canvas: fabric.Canvas,\n canvasWidth: number,\n canvasHeight: number,\n snapToGuides: boolean,\n snapThreshold: number\n): SnapGuide[] {\n if (!snapToGuides) return [];\n\n const threshold = snapThreshold || 5;\n const newGuides: SnapGuide[] = [];\n const scaling = getObjectSnapPoints(scalingObj);\n const scalingId = getObjectId(scalingObj);\n const canvasCenterX = canvasWidth / 2;\n const canvasCenterY = canvasHeight / 2;\n\n const resizingLeft = corner.includes('l');\n const resizingRight = corner.includes('r');\n const resizingTop = corner.includes('t');\n const resizingBottom = corner.includes('b');\n\n const checkVerticalSnap = (edgePosition: number, targetPosition: number, guide: SnapGuide): boolean => {\n const dist = Math.abs(edgePosition - targetPosition);\n if (dist < threshold) {\n newGuides.push({ ...guide, distance: Math.round(dist) });\n return true;\n }\n return false;\n };\n\n const checkHorizontalSnap = (edgePosition: number, targetPosition: number, guide: SnapGuide): boolean => {\n const dist = Math.abs(edgePosition - targetPosition);\n if (dist < threshold) {\n newGuides.push({ ...guide, distance: Math.round(dist) });\n return true;\n }\n return false;\n };\n\n // Canvas edge/center snapping\n if (resizingLeft) {\n checkVerticalSnap(scaling.left, 0, { type: 'vertical', position: 0 });\n checkVerticalSnap(scaling.left, canvasCenterX, { type: 'vertical', position: canvasCenterX });\n }\n if (resizingRight) {\n checkVerticalSnap(scaling.right, canvasWidth, { type: 'vertical', position: canvasWidth });\n checkVerticalSnap(scaling.right, canvasCenterX, { type: 'vertical', position: canvasCenterX });\n }\n if (resizingTop) {\n checkHorizontalSnap(scaling.top, 0, { type: 'horizontal', position: 0 });\n checkHorizontalSnap(scaling.top, canvasCenterY, { type: 'horizontal', position: canvasCenterY });\n }\n if (resizingBottom) {\n checkHorizontalSnap(scaling.bottom, canvasHeight, { type: 'horizontal', position: canvasHeight });\n checkHorizontalSnap(scaling.bottom, canvasCenterY, { type: 'horizontal', position: canvasCenterY });\n }\n\n // Element-to-element snapping\n const rawObjects = canvas.getObjects();\n \n for (const obj of rawObjects) {\n if (obj === scalingObj) continue;\n const objId = getObjectId(obj);\n if (objId === '__background__') continue;\n if (objId && objId === scalingId) continue;\n\n const other = getObjectSnapPoints(obj);\n\n if (resizingLeft) {\n checkVerticalSnap(scaling.left, other.left, { \n type: 'vertical', position: other.left,\n start: Math.min(scaling.top, other.top),\n end: Math.max(scaling.bottom, other.bottom)\n });\n checkVerticalSnap(scaling.left, other.right, { \n type: 'vertical', position: other.right,\n start: Math.min(scaling.top, other.top),\n end: Math.max(scaling.bottom, other.bottom)\n });\n checkVerticalSnap(scaling.left, other.centerX, { \n type: 'vertical', position: other.centerX,\n start: Math.min(scaling.top, other.top),\n end: Math.max(scaling.bottom, other.bottom)\n });\n }\n if (resizingRight) {\n checkVerticalSnap(scaling.right, other.left, { \n type: 'vertical', position: other.left,\n start: Math.min(scaling.top, other.top),\n end: Math.max(scaling.bottom, other.bottom)\n });\n checkVerticalSnap(scaling.right, other.right, { \n type: 'vertical', position: other.right,\n start: Math.min(scaling.top, other.top),\n end: Math.max(scaling.bottom, other.bottom)\n });\n checkVerticalSnap(scaling.right, other.centerX, { \n type: 'vertical', position: other.centerX,\n start: Math.min(scaling.top, other.top),\n end: Math.max(scaling.bottom, other.bottom)\n });\n }\n\n if (resizingTop) {\n checkHorizontalSnap(scaling.top, other.top, { \n type: 'horizontal', position: other.top,\n start: Math.min(scaling.left, other.left),\n end: Math.max(scaling.right, other.right)\n });\n checkHorizontalSnap(scaling.top, other.bottom, { \n type: 'horizontal', position: other.bottom,\n start: Math.min(scaling.left, other.left),\n end: Math.max(scaling.right, other.right)\n });\n checkHorizontalSnap(scaling.top, other.centerY, { \n type: 'horizontal', position: other.centerY,\n start: Math.min(scaling.left, other.left),\n end: Math.max(scaling.right, other.right)\n });\n }\n if (resizingBottom) {\n checkHorizontalSnap(scaling.bottom, other.top, { \n type: 'horizontal', position: other.top,\n start: Math.min(scaling.left, other.left),\n end: Math.max(scaling.right, other.right)\n });\n checkHorizontalSnap(scaling.bottom, other.bottom, { \n type: 'horizontal', position: other.bottom,\n start: Math.min(scaling.left, other.left),\n end: Math.max(scaling.right, other.right)\n });\n checkHorizontalSnap(scaling.bottom, other.centerY, { \n type: 'horizontal', position: other.centerY,\n start: Math.min(scaling.left, other.left),\n end: Math.max(scaling.right, other.right)\n });\n }\n }\n\n // Deduplicate guides\n const seen = new Set<string>();\n return newGuides.filter((guide) => {\n const key = `${guide.type}-${guide.position.toFixed(1)}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** Minimum size after snap so box doesn't collapse */\nconst MIN_SNAP_BOX = 20;\n\nconst SNAP_HYSTERESIS_PX = 6;\n\nexport type ActiveSnapState = { left?: number; right?: number; top?: number; bottom?: number } | null;\n\nexport interface ApplyScaleSnapOptions {\n /** Hysteresis (px) before releasing from a snap. Default 6. */\n hysteresis?: number;\n /** Ref to hold sticky snap values per edge; clear on mouseup. */\n activeSnapRef?: { current: ActiveSnapState };\n /** If true, round only the snapped edge(s) during drag; if false, round whole box (mouseup). */\n roundSnappedOnly?: boolean;\n /** Extra X positions (e.g. layout breakpoints: 1 col, 2 col width) for left/right edge snap. */\n verticalTargetsExtra?: number[];\n /** Extra Y positions (e.g. 1 row, 2 row height) for top/bottom edge snap. */\n horizontalTargetsExtra?: number[];\n}\n\n/**\n * Apply scale snapping to a box (e.g. group bounds rect during resize).\n * Only snaps the moving edge(s) for the given corner. Uses sticky snap + hysteresis to avoid ping-pong.\n */\nexport function applyScaleSnapToBox(\n box: { left: number; top: number; width: number; height: number },\n corner: string,\n canvas: fabric.Canvas,\n canvasWidth: number,\n canvasHeight: number,\n snapToGuides: boolean,\n snapThreshold: number,\n excludeObjectId?: string,\n options?: ApplyScaleSnapOptions\n): { left: number; top: number; width: number; height: number } {\n const hysteresis = options?.hysteresis ?? SNAP_HYSTERESIS_PX;\n const activeSnapRef = options?.activeSnapRef;\n const roundSnappedOnly = options?.roundSnappedOnly ?? false;\n\n if (!snapToGuides || !canvas) {\n if (roundSnappedOnly) return { ...box };\n return {\n left: Math.round(box.left),\n top: Math.round(box.top),\n width: Math.round(box.width),\n height: Math.round(box.height),\n };\n }\n const threshold = snapThreshold || 5;\n const releaseDist = threshold + hysteresis;\n const right = box.left + box.width;\n const bottom = box.top + box.height;\n const canvasCenterX = canvasWidth / 2;\n const canvasCenterY = canvasHeight / 2;\n\n const resizingLeft = corner.includes('l');\n const resizingRight = corner.includes('r');\n const resizingTop = corner.includes('t');\n const resizingBottom = corner.includes('b');\n\n const verticalTargets: number[] = [0, canvasWidth, canvasCenterX];\n const horizontalTargets: number[] = [0, canvasHeight, canvasCenterY];\n if (options?.verticalTargetsExtra?.length) verticalTargets.push(...options.verticalTargetsExtra);\n if (options?.horizontalTargetsExtra?.length) horizontalTargets.push(...options.horizontalTargetsExtra);\n\n const rawObjects = canvas.getObjects();\n for (const obj of rawObjects) {\n const objId = getObjectId(obj);\n if (objId === '__background__') continue;\n if (excludeObjectId && objId === excludeObjectId) continue;\n const pts = getObjectSnapPoints(obj);\n verticalTargets.push(pts.left, pts.right, pts.centerX);\n horizontalTargets.push(pts.top, pts.bottom, pts.centerY);\n }\n\n const findBestSnap = (edgePos: number, targets: number[]): { value: number; dist: number } => {\n let best = edgePos;\n let bestDist = threshold + 1;\n for (const t of targets) {\n const d = Math.abs(edgePos - t);\n if (d < bestDist) {\n bestDist = d;\n best = t;\n }\n }\n return { value: best, dist: bestDist };\n };\n\n let left = box.left;\n let top = box.top;\n let width = box.width;\n let height = box.height;\n let snappedLeft = false;\n let snappedRight = false;\n let snappedTop = false;\n let snappedBottom = false;\n\n if (resizingLeft) {\n const stick = activeSnapRef?.current?.left;\n if (stick !== undefined) {\n const dist = Math.abs(box.left - stick);\n if (dist <= hysteresis) {\n left = stick;\n width = right - left;\n snappedLeft = true;\n } else if (dist > releaseDist) {\n if (activeSnapRef.current) delete activeSnapRef.current.left;\n const { value, dist: d } = findBestSnap(box.left, verticalTargets);\n if (d <= threshold) {\n if (!activeSnapRef?.current) activeSnapRef!.current = {};\n activeSnapRef!.current!.left = value;\n left = value;\n width = right - left;\n snappedLeft = true;\n } else {\n left = box.left;\n width = right - left;\n }\n } else {\n left = box.left;\n width = right - left;\n }\n } else {\n const { value, dist } = findBestSnap(box.left, verticalTargets);\n if (dist <= threshold) {\n if (activeSnapRef) {\n if (!activeSnapRef.current) activeSnapRef.current = {};\n activeSnapRef.current.left = value;\n }\n left = value;\n width = right - left;\n snappedLeft = true;\n } else {\n left = box.left;\n width = right - left;\n }\n }\n }\n if (resizingRight) {\n const stick = activeSnapRef?.current?.right;\n if (stick !== undefined) {\n const dist = Math.abs(right - stick);\n if (dist <= hysteresis) {\n width = stick - left;\n snappedRight = true;\n } else if (dist > releaseDist) {\n if (activeSnapRef?.current) delete activeSnapRef.current.right;\n const { value, dist: d } = findBestSnap(right, verticalTargets);\n if (d <= threshold) {\n if (!activeSnapRef?.current) activeSnapRef!.current = {};\n activeSnapRef!.current!.right = value;\n width = value - left;\n snappedRight = true;\n } else {\n width = box.width;\n }\n } else {\n width = box.width;\n }\n } else {\n const { value, dist } = findBestSnap(right, verticalTargets);\n if (dist <= threshold) {\n if (activeSnapRef) {\n if (!activeSnapRef.current) activeSnapRef.current = {};\n activeSnapRef.current.right = value;\n }\n width = value - left;\n snappedRight = true;\n } else {\n width = box.width;\n }\n }\n }\n if (resizingTop) {\n const stick = activeSnapRef?.current?.top;\n if (stick !== undefined) {\n const dist = Math.abs(box.top - stick);\n if (dist <= hysteresis) {\n top = stick;\n height = bottom - top;\n snappedTop = true;\n } else if (dist > releaseDist) {\n if (activeSnapRef?.current) delete activeSnapRef.current.top;\n const { value, dist: d } = findBestSnap(box.top, horizontalTargets);\n if (d <= threshold) {\n if (!activeSnapRef?.current) activeSnapRef!.current = {};\n activeSnapRef!.current!.top = value;\n top = value;\n height = bottom - top;\n snappedTop = true;\n } else {\n top = box.top;\n height = bottom - top;\n }\n } else {\n top = box.top;\n height = bottom - top;\n }\n } else {\n const { value, dist } = findBestSnap(box.top, horizontalTargets);\n if (dist <= threshold) {\n if (activeSnapRef) {\n if (!activeSnapRef.current) activeSnapRef.current = {};\n activeSnapRef.current.top = value;\n }\n top = value;\n height = bottom - top;\n snappedTop = true;\n } else {\n top = box.top;\n height = bottom - top;\n }\n }\n }\n if (resizingBottom) {\n const stick = activeSnapRef?.current?.bottom;\n if (stick !== undefined) {\n const dist = Math.abs(bottom - stick);\n if (dist <= hysteresis) {\n height = stick - top;\n snappedBottom = true;\n } else if (dist > releaseDist) {\n if (activeSnapRef?.current) delete activeSnapRef.current.bottom;\n const { value, dist: d } = findBestSnap(bottom, horizontalTargets);\n if (d <= threshold) {\n if (!activeSnapRef?.current) activeSnapRef!.current = {};\n activeSnapRef!.current!.bottom = value;\n height = value - top;\n snappedBottom = true;\n } else {\n height = box.height;\n }\n } else {\n height = box.height;\n }\n } else {\n const { value, dist } = findBestSnap(bottom, horizontalTargets);\n if (dist <= threshold) {\n if (activeSnapRef) {\n if (!activeSnapRef.current) activeSnapRef.current = {};\n activeSnapRef.current.bottom = value;\n }\n height = value - top;\n snappedBottom = true;\n } else {\n height = box.height;\n }\n }\n }\n\n width = Math.max(MIN_SNAP_BOX, width);\n height = Math.max(MIN_SNAP_BOX, height);\n if (resizingLeft && !resizingRight) left = right - width;\n if (resizingTop && !resizingBottom) top = bottom - height;\n\n if (roundSnappedOnly) {\n return {\n left: snappedLeft ? Math.round(left) : left,\n top: snappedTop ? Math.round(top) : top,\n width: snappedRight ? Math.round(width) : width,\n height: snappedBottom ? Math.round(height) : height,\n };\n }\n return {\n left: Math.round(left),\n top: Math.round(top),\n width: Math.round(width),\n height: Math.round(height),\n };\n}\n","/**\n * Fabric.js Textbox prototype extensions.\n *\n * Adds two new properties to every Textbox instance:\n * - `minBoxHeight` (number, default 0) — a floor on the textbox visual\n * height. When set, the box renders at least this tall regardless of\n * the natural text content height. Bottom/top/corner resize handles\n * bake their scaleY into this value so the user can resize the box\n * vertically without stretching glyphs.\n * - `verticalAlign` ('top' | 'middle' | 'bottom', default 'top') —\n * positions the text content inside the (potentially taller) box.\n *\n * This module mutates Fabric prototypes once on import. Side-effect only.\n */\nimport * as fabric from 'fabric';\n\ntype ExtendedTextbox = fabric.Textbox & {\n minBoxHeight?: number;\n verticalAlign?: 'top' | 'middle' | 'bottom';\n _contentHeight?: number;\n __pixldocsTextboxExtended?: boolean;\n};\n\nconst TextboxProto = fabric.Textbox.prototype as unknown as ExtendedTextbox & {\n calcTextHeight: (this: ExtendedTextbox) => number;\n _getTopOffset: (this: ExtendedTextbox) => number;\n __pixldocsOrigCalcTextHeight?: (this: ExtendedTextbox) => number;\n __pixldocsOrigGetTopOffset?: (this: ExtendedTextbox) => number;\n _getSVGLeftTopOffsets?: (this: ExtendedTextbox) => { textLeft: number; textTop: number; lineTop: number };\n __pixldocsOrigGetSVGLeftTopOffsets?: (this: ExtendedTextbox) => { textLeft: number; textTop: number; lineTop: number };\n};\n\nif (!TextboxProto.__pixldocsOrigCalcTextHeight) {\n TextboxProto.__pixldocsOrigCalcTextHeight = TextboxProto.calcTextHeight;\n\n TextboxProto.calcTextHeight = function (this: ExtendedTextbox) {\n const orig = (TextboxProto.__pixldocsOrigCalcTextHeight as () => number).call(this);\n // Cache content height for _getTopOffset to compute vertical alignment.\n this._contentHeight = orig;\n const min = this.minBoxHeight || 0;\n return min > orig ? min : orig;\n };\n}\n\nif (!TextboxProto.__pixldocsOrigGetTopOffset) {\n TextboxProto.__pixldocsOrigGetTopOffset = TextboxProto._getTopOffset;\n\n TextboxProto._getTopOffset = function (this: ExtendedTextbox) {\n const baseOffset = (TextboxProto.__pixldocsOrigGetTopOffset as () => number).call(this);\n const valign = this.verticalAlign || 'top';\n if (valign === 'top') return baseOffset;\n const content =\n typeof this._contentHeight === 'number'\n ? this._contentHeight\n : (TextboxProto.__pixldocsOrigCalcTextHeight as () => number).call(this);\n const padding = (this.height || 0) - content;\n if (padding <= 0) return baseOffset;\n if (valign === 'middle') return baseOffset + padding / 2;\n if (valign === 'bottom') return baseOffset + padding;\n return baseOffset;\n };\n}\n\n// Fabric's `_getSVGLeftTopOffsets` is independent of `_getTopOffset` and\n// hard-codes textTop = -height/2. Override so SVG (and downstream PDF via\n// svg2pdf) honors `verticalAlign`. `this.height` already reflects\n// `minBoxHeight` because `calcTextHeight` is overridden above and\n// `initDimensions` writes height = calcTextHeight() + 2*padding.\nif (TextboxProto._getSVGLeftTopOffsets && !TextboxProto.__pixldocsOrigGetSVGLeftTopOffsets) {\n TextboxProto.__pixldocsOrigGetSVGLeftTopOffsets = TextboxProto._getSVGLeftTopOffsets;\n\n TextboxProto._getSVGLeftTopOffsets = function (this: ExtendedTextbox) {\n const base = (TextboxProto.__pixldocsOrigGetSVGLeftTopOffsets as () => { textLeft: number; textTop: number; lineTop: number }).call(this);\n const valign = this.verticalAlign || 'top';\n if (valign === 'top') return base;\n const content =\n typeof this._contentHeight === 'number'\n ? this._contentHeight\n : (TextboxProto.__pixldocsOrigCalcTextHeight as () => number).call(this);\n const padding = (this.height || 0) - content;\n if (padding <= 0) return base;\n const extra = valign === 'middle' ? padding / 2 : padding;\n return { ...base, textTop: base.textTop + extra };\n };\n}\n\n// Tell Fabric these are real Textbox properties so its internal cloning,\n// state tracking, and dirty-checking pick them up.\nconst stateProps = (fabric.Textbox.prototype as unknown as { stateProperties?: string[] }).stateProperties;\nif (Array.isArray(stateProps)) {\n if (!stateProps.includes('minBoxHeight')) stateProps.push('minBoxHeight');\n if (!stateProps.includes('verticalAlign')) stateProps.push('verticalAlign');\n}\nconst cacheProps = (fabric.Textbox.prototype as unknown as { cacheProperties?: string[] }).cacheProperties;\nif (Array.isArray(cacheProps)) {\n if (!cacheProps.includes('minBoxHeight')) cacheProps.push('minBoxHeight');\n if (!cacheProps.includes('verticalAlign')) cacheProps.push('verticalAlign');\n}\n\n(TextboxProto as ExtendedTextbox).__pixldocsTextboxExtended = true;\n\nexport {};","import * as fabric from 'fabric';\nimport type { CanvasElement } from '@/types/editor';\n\n/**\n * Text Background + Shadow Augmentation\n * ======================================\n * Augments standard fabric.Textbox instances with Pixldocs-specific text styling:\n * - Rounded background rect (per-corner radii)\n * - Inner padding (visual breathing room around text)\n * - Native Fabric shadow (handled via obj.shadow — auto-serialized for EC2)\n *\n * Strategy: We do NOT subclass fabric.Textbox (avoids classRegistry + serialization\n * pain). Instead we attach a __pdBg config object onto the textbox and wrap its\n * _render to draw the rounded background BEFORE the text glyphs, then expand the\n * dimensions by 2 * padding when computing layout.\n *\n * EC2 + canvas-renderer parity (Commit B) will read these same __pdBg fields off\n * the serialized JSON via toObject() additions.\n */\n\nexport interface TextBgConfig {\n color?: string;\n /** Per-side padding. */\n padTop?: number;\n padRight?: number;\n padBottom?: number;\n padLeft?: number;\n rxTL?: number;\n rxTR?: number;\n rxBR?: number;\n rxBL?: number;\n /** Opacity (0..1) applied to bg fill only. Defaults to 1 when omitted. */\n opacity?: number;\n /** When false, the text shadow is NOT painted behind the bg rect. Defaults to true. */\n shadowAffectsBg?: boolean;\n /** When false, the text shadow is NOT painted on the glyphs. Defaults to true. */\n shadowAffectsText?: boolean;\n /**\n * When true, draw a per-line rounded rect sized to each line's measured\n * width (like an underline highlighter) instead of one full-width box.\n */\n fitToText?: boolean;\n}\n\nconst PD_BG_KEY = '__pdBg';\nconst PATCHED_KEY = '__pdBgPatched';\n\n/** Read TextBgConfig values directly from a CanvasElement schema entry. */\nexport function extractTextBgConfig(element: CanvasElement): TextBgConfig {\n const legacy = Math.max(0, Number((element as any).textBgPadding ?? 0)) || 0;\n const pick = (v: any) => {\n const n = Number(v);\n return Number.isFinite(n) && n >= 0 ? n : undefined;\n };\n return {\n color: element.textBgColor,\n padTop: pick(element.textBgPaddingTop) ?? legacy,\n padRight: pick(element.textBgPaddingRight) ?? legacy,\n padBottom: pick(element.textBgPaddingBottom) ?? legacy,\n padLeft: pick(element.textBgPaddingLeft) ?? legacy,\n rxTL: Math.max(0, Number(element.textBgRxTL ?? 0)) || 0,\n rxTR: Math.max(0, Number(element.textBgRxTR ?? 0)) || 0,\n rxBR: Math.max(0, Number(element.textBgRxBR ?? 0)) || 0,\n rxBL: Math.max(0, Number(element.textBgRxBL ?? 0)) || 0,\n opacity: (() => {\n const n = Number((element as any).textBgOpacity);\n if (!Number.isFinite(n)) return undefined;\n return Math.max(0, Math.min(1, n));\n })(),\n shadowAffectsBg: (element as any).textShadowAffectsBg !== false,\n shadowAffectsText: (element as any).textShadowAffectsText !== false,\n fitToText: (element as any).textBgFitToText === true,\n };\n}\n\n/** True if the config has any visible background (color set + non-transparent). */\nexport function hasTextBackground(cfg: TextBgConfig | undefined | null): boolean {\n if (!cfg) return false;\n const c = (cfg.color || '').toString().trim().toLowerCase();\n return !!c && c !== 'transparent' && c !== 'none' && c !== 'rgba(0,0,0,0)';\n}\n\n/** Build a fabric.Shadow from CanvasElement fields, or null if none configured. */\nexport function buildTextShadow(element: CanvasElement): fabric.Shadow | null {\n const color = element.textShadowColor;\n const blur = Number(element.textShadowBlur ?? 0);\n const ox = Number(element.textShadowOffsetX ?? 0);\n const oy = Number(element.textShadowOffsetY ?? 0);\n if (!color || color === 'transparent') return null;\n // Always return a Shadow when a color is set — even if blur+offsets are 0\n // the user may want a tiny offset later. Returning null here was making the\n // shadow appear \"missing\" when blur/offsets defaulted to 0.\n return new fabric.Shadow({\n color: String(color),\n blur: blur || 0,\n offsetX: ox || 0,\n offsetY: oy || 0,\n affectStroke: false,\n nonScaling: false,\n });\n}\n\nfunction buildRoundedRectPath2D(\n ctx: CanvasRenderingContext2D,\n x: number, y: number, w: number, h: number,\n rTL: number, rTR: number, rBR: number, rBL: number\n) {\n const maxR = Math.min(w, h) / 2;\n const tl = Math.min(Math.max(0, rTL), maxR);\n const tr = Math.min(Math.max(0, rTR), maxR);\n const br = Math.min(Math.max(0, rBR), maxR);\n const bl = Math.min(Math.max(0, rBL), maxR);\n ctx.beginPath();\n ctx.moveTo(x + tl, y);\n ctx.lineTo(x + w - tr, y);\n if (tr > 0) ctx.quadraticCurveTo(x + w, y, x + w, y + tr);\n ctx.lineTo(x + w, y + h - br);\n if (br > 0) ctx.quadraticCurveTo(x + w, y + h, x + w - br, y + h);\n ctx.lineTo(x + bl, y + h);\n if (bl > 0) ctx.quadraticCurveTo(x, y + h, x, y + h - bl);\n ctx.lineTo(x, y + tl);\n if (tl > 0) ctx.quadraticCurveTo(x, y, x + tl, y);\n ctx.closePath();\n}\n\n/**\n * Apply (or update) the background config on a Textbox and patch its _render\n * to draw the rounded background + padding. Idempotent: patches once per object.\n */\nexport function applyTextBackground(\n obj: fabric.Textbox,\n cfg: TextBgConfig\n): void {\n // Store the config on the object so toObject can serialize it (Commit B parity)\n (obj as any)[PD_BG_KEY] = { ...cfg };\n\n if ((obj as any)[PATCHED_KEY]) return;\n (obj as any)[PATCHED_KEY] = true;\n\n // Wrap _render — keep the original around and call it after drawing the bg.\n const originalRender = obj._render.bind(obj);\n (obj as any)._render = function (ctx: CanvasRenderingContext2D) {\n const bg: TextBgConfig | undefined = (this as any)[PD_BG_KEY];\n if (hasTextBackground(bg)) {\n const w = (this.width as number) ?? 0;\n const h = (this.height as number) ?? 0;\n const pT = Math.max(0, Number(bg!.padTop ?? 0));\n const pR = Math.max(0, Number(bg!.padRight ?? 0));\n const pB = Math.max(0, Number(bg!.padBottom ?? 0));\n const pL = Math.max(0, Number(bg!.padLeft ?? 0));\n ctx.save();\n // When shadow is set on the textbox AND user opted out of shadow-on-bg,\n // suppress shadow for the bg fill. Fabric's native shadow otherwise\n // applies to every painted shape, including this rounded rectangle.\n const suppressShadowOnBg = bg!.shadowAffectsBg === false;\n if (suppressShadowOnBg) {\n ctx.shadowColor = 'transparent';\n ctx.shadowBlur = 0;\n ctx.shadowOffsetX = 0;\n ctx.shadowOffsetY = 0;\n }\n const op = typeof bg!.opacity === 'number' ? Math.max(0, Math.min(1, bg!.opacity)) : 1;\n if (op < 1) ctx.globalAlpha = (ctx.globalAlpha ?? 1) * op;\n ctx.fillStyle = bg!.color!;\n const rects = computeBgRects(this, w, h, pT, pR, pB, pL, !!bg!.fitToText);\n for (const r of rects) {\n buildRoundedRectPath2D(\n ctx, r.x, r.y, r.w, r.h,\n bg!.rxTL ?? 0, bg!.rxTR ?? 0, bg!.rxBR ?? 0, bg!.rxBL ?? 0\n );\n ctx.fill();\n }\n ctx.restore();\n }\n const suppressShadowOnText = bg && bg.shadowAffectsText === false;\n if (suppressShadowOnText) {\n ctx.save();\n ctx.shadowColor = 'transparent';\n ctx.shadowBlur = 0;\n ctx.shadowOffsetX = 0;\n ctx.shadowOffsetY = 0;\n originalRender(ctx);\n ctx.restore();\n } else {\n originalRender(ctx);\n }\n };\n\n // Extend toObject so the bg config travels with serialization.\n // This is what EC2 + canvas-renderer (Commit B) will read.\n const originalToObject = obj.toObject.bind(obj);\n (obj as any).toObject = function (propertiesToInclude?: string[]) {\n const out = originalToObject(propertiesToInclude);\n const bg: TextBgConfig | undefined = (this as any)[PD_BG_KEY];\n if (hasTextBackground(bg)) {\n out.__pdBg = { ...bg };\n }\n return out;\n };\n\n // Patch toSVG so the rounded background also renders into Fabric's SVG\n // output — this is what the canvas-renderer's vector PDF path consumes.\n // We wrap the original textbox SVG markup inside a <g> that first paints a\n // rounded <path> behind it (using object-local coordinates: the parent <g>\n // already has the textbox's transform applied).\n const originalToSVG = (obj as any).toSVG?.bind(obj);\n if (typeof originalToSVG === 'function') {\n (obj as any).toSVG = function (reviver?: (markup: string) => string) {\n let svg: string = originalToSVG(reviver);\n const bg: TextBgConfig | undefined = (this as any)[PD_BG_KEY];\n const shadow: any = (this as any).shadow;\n const hasBg = hasTextBackground(bg);\n const hasShadow = !!shadow && !!shadow.color && shadow.color !== 'transparent';\n if (!hasBg && !hasShadow) return svg;\n\n // ─── Compute background rect geometry (object-local coordinates) ───\n const w = (this.width as number) ?? 0;\n const h = (this.height as number) ?? 0;\n const pT = Math.max(0, Number(bg?.padTop ?? 0));\n const pR = Math.max(0, Number(bg?.padRight ?? 0));\n const pB = Math.max(0, Number(bg?.padBottom ?? 0));\n const pL = Math.max(0, Number(bg?.padLeft ?? 0));\n const fit = !!bg?.fitToText;\n const rects = computeBgRects(this, w, h, pT, pR, pB, pL, fit);\n const bgD = rects.map(r => buildRoundedRectPathD(\n r.x, r.y, r.w, r.h,\n bg?.rxTL ?? 0, bg?.rxTR ?? 0, bg?.rxBR ?? 0, bg?.rxBL ?? 0\n )).join(' ');\n const bgFill = bg?.color || '';\n const bgOpacity = typeof bg?.opacity === 'number'\n ? Math.max(0, Math.min(1, bg!.opacity))\n : 1;\n const bgOpacityAttr = bgOpacity < 1 ? ` fill-opacity=\"${bgOpacity}\"` : '';\n const bgPath = hasBg\n ? `<path d=\"${bgD}\" fill=\"${escapeXmlAttr(bgFill)}\"${bgOpacityAttr} />`\n : '';\n\n // ─── Strip Fabric's filter reference from the root <g> (svg2pdf can't render it) ───\n // Fabric emits e.g. `<g style=\"filter: url(#SVGID_1);\" ...>` when shadow is set.\n // Drop the style entirely (it only contained the filter ref).\n svg = svg.replace(/style=\"[^\"]*filter:\\s*url\\([^)]+\\)[^\"]*\"/i, '');\n // Also drop top-level <filter id=\"SVGID_..\">…</filter> defs that may appear\n // alongside the text markup (svg2pdf would silently ignore them anyway).\n svg = svg.replace(/<filter[\\s\\S]*?<\\/filter>/gi, '');\n // ─── Build PDF-safe shadow layers ───\n // Blur 0 stays fully vector. Blur > 0 is emitted as a marker that the PDF\n // pipeline rasterizes with a real Gaussian blur, because svg2pdf cannot\n // render SVG filters.\n //\n // We split into TWO markers to preserve canvas-preview ordering:\n // 1. bg-shadow → drawn behind bg fill\n // 2. text-shadow → drawn between bg fill and real text glyphs\n let bgShadowMarker = '';\n let textShadowMarker = '';\n if (hasShadow) {\n const ox = Number(shadow.offsetX ?? 0) || 0;\n const oy = Number(shadow.offsetY ?? 0) || 0;\n const blur = Math.max(0, Number(shadow.blur ?? 0));\n const shadowColor = String(shadow.color);\n // bbox padding: enough room around the geometry for the blur tail to\n // fully decay to ~0 alpha. We map blur → SVG `stdDeviation` 1:1, so the\n // visible Gaussian tail extends ~3·stdDev px in every direction. We use\n // 4× as a safety multiplier so even the faintest falloff lands inside\n // the rasterized image — otherwise the PNG ends with a hard edge that\n // is visible in the PDF as a \"cutoff\" rectangle.\n const pad = Math.max(16, Math.ceil(blur * 4) + Math.ceil(Math.max(Math.abs(ox), Math.abs(oy))) + 8);\n // IMPORTANT: don't size the shadow raster box from textbox.width only.\n // Fabric text can visually extend outside that stored box (center/right\n // align, stale dynamicMinWidth/cache, glyph overhangs). When the PNG\n // viewBox is too narrow, the right side of the shadow simply disappears\n // in the downloaded vector PDF. Use the union of bg rects + actual line\n // bounds so every glyph silhouette fits inside the rasterized marker.\n const shadowBounds = unionBounds([\n ...rects,\n computeTextVisualBounds(this, w, h),\n ]);\n const bx = shadowBounds.x - pad;\n const by = shadowBounds.y - pad;\n const bw = shadowBounds.w + pad * 2;\n const bh = shadowBounds.h + pad * 2;\n const dataAttrs = `data-blur=\"${blur.toFixed(3)}\" data-ox=\"${ox.toFixed(3)}\" data-oy=\"${oy.toFixed(3)}\" data-bx=\"${bx.toFixed(3)}\" data-by=\"${by.toFixed(3)}\" data-bw=\"${bw.toFixed(3)}\" data-bh=\"${bh.toFixed(3)}\" data-color=\"${escapeXmlAttr(shadowColor)}\"`;\n const wrapShadow = (markup: string) => blur <= 0\n ? `<g transform=\"translate(${ox.toFixed(3)} ${oy.toFixed(3)})\">${markup}</g>`\n : `<g class=\"__pdShadowRaster\" ${dataAttrs}>${markup}</g>`;\n if (hasBg && bg?.shadowAffectsBg !== false) {\n const shadowOpacityAttr = bgOpacity < 1 ? ` fill-opacity=\"${bgOpacity}\"` : '';\n const shadowBgPath = `<path d=\"${bgD}\" fill=\"${escapeXmlAttr(shadowColor)}\"${shadowOpacityAttr} />`;\n bgShadowMarker = wrapShadow(shadowBgPath);\n }\n // Recolor a clone of the original INNER markup (without the outer\n // <g transform=...> wrapper) so the text glyphs become solid shadow\n // color silhouettes.\n if (bg?.shadowAffectsText !== false) {\n const inner = extractGInnerMarkup(svg);\n const recoloredText = recolorSvgFills(inner, shadowColor);\n if (recoloredText) textShadowMarker = wrapShadow(recoloredText);\n }\n }\n\n // ─── Inject markers + bg inside the root <g> ───\n // Order: bg-shadow → bg fill → text-shadow → (real text glyphs follow)\n const openTagMatch = svg.match(/^\\s*<g\\b[^>]*>/);\n const inserted = bgShadowMarker + bgPath + textShadowMarker;\n // PARITY TAGS: decorated textboxes (background and/or blurred shadow)\n // must use one deterministic text path in PDF export. Background boxes\n // make right/center alignment drift obvious when svg2pdf/jsPDF or\n // opentype re-measures text differently from Fabric's Canvas2D metrics.\n const shadowBlur = hasShadow ? Math.max(0, Number(shadow.blur ?? 0)) : 0;\n const decorationTags = [\n shadowBlur > 0 ? 'data-pd-shadow-blur=\"1\"' : '',\n hasBg ? 'data-pd-text-bg=\"1\"' : '',\n ].filter(Boolean).join(' ');\n const decorationAttr = decorationTags ? ` ${decorationTags}` : '';\n if (openTagMatch) {\n const openTag = openTagMatch[0];\n const taggedOpenTag = decorationAttr\n ? openTag\n .replace(/^<g\\b/, `<g${decorationAttr}`)\n .replace(/\\s(data-pd-shadow-blur=\"1\")(?=[^>]*\\s\\1)/i, '')\n .replace(/\\s(data-pd-text-bg=\"1\")(?=[^>]*\\s\\1)/i, '')\n : openTag;\n return svg.replace(openTag, taggedOpenTag + inserted);\n }\n return `<g${decorationAttr}>${inserted}${svg}</g>`;\n };\n }\n}\n\n/**\n * Replace every fill attribute on text/tspan/path elements in an SVG markup\n * fragment with a single color. Used to build the shadow layer by recoloring\n * a clone of the original text markup. Does not touch fill=\"none\".\n */\nfunction recolorSvgFills(svg: string, color: string): string {\n return _recolorSvgFills(svg, color);\n}\n\nfunction _recolorSvgFills(svg: string, color: string): string {\n const safe = escapeXmlAttr(color);\n // Replace any fill=\"…\" attribute that isn't \"none\" / \"transparent\".\n let out = svg.replace(/(<(?:text|tspan|path|rect)\\b[^>]*?\\sfill=\")([^\"]*)(\"[^>]*>)/gi,\n (_m, pre, val, post) => {\n const v = val.trim().toLowerCase();\n if (v === 'none' || v === 'transparent') return pre + val + post;\n return pre + safe + post;\n }\n );\n // Also handle CSS-style fill: x; inside style attributes\n out = out.replace(/(<(?:text|tspan|path|rect)\\b[^>]*?\\sstyle=\")([^\"]*)(\"[^>]*>)/gi,\n (_m, pre, styleVal, post) => {\n const replaced = styleVal.replace(/fill\\s*:\\s*[^;\"]+/gi, `fill: ${color}`);\n return pre + replaced + post;\n }\n );\n return out;\n}\n\nfunction buildRoundedRectPathD(\n x: number, y: number, w: number, h: number,\n rTL: number, rTR: number, rBR: number, rBL: number\n): string {\n const maxR = Math.min(w, h) / 2;\n const tl = Math.min(Math.max(0, rTL), maxR);\n const tr = Math.min(Math.max(0, rTR), maxR);\n const br = Math.min(Math.max(0, rBR), maxR);\n const bl = Math.min(Math.max(0, rBL), maxR);\n const fmt = (n: number) => Number.isFinite(n) ? Number(n.toFixed(3)) : 0;\n const parts: string[] = [];\n parts.push(`M ${fmt(x + tl)} ${fmt(y)}`);\n parts.push(`L ${fmt(x + w - tr)} ${fmt(y)}`);\n if (tr > 0) parts.push(`Q ${fmt(x + w)} ${fmt(y)} ${fmt(x + w)} ${fmt(y + tr)}`);\n parts.push(`L ${fmt(x + w)} ${fmt(y + h - br)}`);\n if (br > 0) parts.push(`Q ${fmt(x + w)} ${fmt(y + h)} ${fmt(x + w - br)} ${fmt(y + h)}`);\n parts.push(`L ${fmt(x + bl)} ${fmt(y + h)}`);\n if (bl > 0) parts.push(`Q ${fmt(x)} ${fmt(y + h)} ${fmt(x)} ${fmt(y + h - bl)}`);\n parts.push(`L ${fmt(x)} ${fmt(y + tl)}`);\n if (tl > 0) parts.push(`Q ${fmt(x)} ${fmt(y)} ${fmt(x + tl)} ${fmt(y)}`);\n parts.push('Z');\n return parts.join(' ');\n}\n\ntype LocalBounds = { x: number; y: number; w: number; h: number };\n\nfunction unionBounds(bounds: LocalBounds[]): LocalBounds {\n const valid = bounds.filter((b) => Number.isFinite(b.x) && Number.isFinite(b.y) && b.w > 0 && b.h > 0);\n if (valid.length === 0) return { x: 0, y: 0, w: 1, h: 1 };\n const minX = Math.min(...valid.map((b) => b.x));\n const minY = Math.min(...valid.map((b) => b.y));\n const maxX = Math.max(...valid.map((b) => b.x + b.w));\n const maxY = Math.max(...valid.map((b) => b.y + b.h));\n return { x: minX, y: minY, w: Math.max(1, maxX - minX), h: Math.max(1, maxY - minY) };\n}\n\nfunction computeTextVisualBounds(obj: any, w: number, h: number): LocalBounds {\n const lines: any[] = obj?._textLines ?? [];\n if (!lines || lines.length === 0) return { x: -w / 2, y: -h / 2, w, h };\n\n const rects: LocalBounds[] = [];\n const halfW = w / 2;\n const halfH = h / 2;\n const lineHeightRatio = Math.max(0.01, Number(obj?.lineHeight ?? 1) || 1);\n let cursorY = -halfH;\n for (let i = 0; i < lines.length; i++) {\n let lineW = 0;\n let lineLeft = 0;\n let lineH = 0;\n try { lineW = obj.getLineWidth(i) || 0; } catch { lineW = 0; }\n try { lineLeft = obj._getLineLeftOffset?.(i) ?? 0; } catch { lineLeft = 0; }\n try { lineH = obj.getHeightOfLine(i) || 0; } catch { lineH = 0; }\n const rawSlotH = i === lines.length - 1 ? lineH / lineHeightRatio : lineH;\n const usedH = cursorY + halfH;\n const slotH = Math.max(0, Math.min(rawSlotH, h - usedH));\n if (lineW > 0 && slotH > 0) rects.push({ x: -halfW + lineLeft, y: cursorY, w: lineW, h: slotH });\n cursorY += slotH;\n }\n return unionBounds(rects.length > 0 ? rects : [{ x: -w / 2, y: -h / 2, w, h }]);\n}\n\n/**\n * Compute the set of background rectangles (in object-local coordinates,\n * where the textbox center is 0,0) that should be filled.\n *\n * - When `fit` is false → one rect covering the full textbox + padding.\n * - When `fit` is true → one rect per visual line, sized to that line's\n * measured width + horizontal padding, positioned by Fabric's own line\n * left-offset / line-height APIs (parity with how Fabric renders text).\n */\nfunction computeBgRects(\n obj: any,\n w: number,\n h: number,\n pT: number,\n pR: number,\n pB: number,\n pL: number,\n fit: boolean\n): Array<{ x: number; y: number; w: number; h: number }> {\n if (!fit) {\n return [{\n x: -w / 2 - pL,\n y: -h / 2 - pT,\n w: w + pL + pR,\n h: h + pT + pB,\n }];\n }\n const lines: any[] = obj?._textLines ?? [];\n if (!lines || lines.length === 0) {\n return [{\n x: -w / 2 - pL,\n y: -h / 2 - pT,\n w: w + pL + pR,\n h: h + pT + pB,\n }];\n }\n const rects: Array<{ x: number; y: number; w: number; h: number }> = [];\n const halfW = w / 2;\n const halfH = h / 2;\n const lineHeightRatio = Math.max(0.01, Number(obj?.lineHeight ?? 1) || 1);\n let cursorY = -halfH;\n for (let i = 0; i < lines.length; i++) {\n let lineW = 0;\n let lineLeft = 0;\n let lineH = 0;\n try { lineW = obj.getLineWidth(i) || 0; } catch { lineW = 0; }\n try { lineLeft = obj._getLineLeftOffset?.(i) ?? 0; } catch { lineLeft = 0; }\n try { lineH = obj.getHeightOfLine(i) || 0; } catch { lineH = 0; }\n const rawSlotH = i === lines.length - 1 ? lineH / lineHeightRatio : lineH;\n const usedH = cursorY + halfH;\n const slotH = Math.max(0, Math.min(rawSlotH, h - usedH));\n if (lineW <= 0 || slotH <= 0) {\n cursorY += slotH;\n continue;\n }\n // Match the non-fit behavior exactly — same vertical extent (full line\n // slot + padding), only the width changes per line.\n rects.push({\n x: -halfW + lineLeft - pL,\n y: cursorY - pT,\n w: lineW + pL + pR,\n h: slotH + pT + pB,\n });\n cursorY += slotH;\n }\n if (rects.length === 0) {\n return [{\n x: -w / 2 - pL,\n y: -h / 2 - pT,\n w: w + pL + pR,\n h: h + pT + pB,\n }];\n }\n return rects;\n}\n\nfunction escapeXmlAttr(s: string): string {\n return String(s)\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n\n/**\n * Extract the inner content of the outermost <g> tag in an SVG markup string.\n * Falls back to returning the original markup if no outer <g> is found.\n */\nfunction extractGInnerMarkup(markup: string): string {\n const openMatch = markup.match(/^\\s*<g\\b[^>]*>/);\n if (!openMatch) return markup;\n const closeIdx = markup.lastIndexOf('</g>');\n if (closeIdx <= openMatch[0].length) return markup;\n return markup.slice(openMatch[0].length, closeIdx);\n}\n\n/** Clear the background config (so the wrapped _render becomes a no-op for bg). */\nexport function clearTextBackground(obj: fabric.Textbox): void {\n (obj as any)[PD_BG_KEY] = undefined;\n}","import { ShapeType } from '@/types/editor';\n\nexport type CoreShapeType = 'rounded-rect' | 'circle' | 'triangle';\nexport type NormalizedShapeType = CoreShapeType | 'unsupported';\n\nexport const TRIANGLE_STROKE_MITER_LIMIT = 1_000_000;\n\nexport interface RoundedRectRadiiInput {\n rx?: number;\n rxTL?: number;\n rxTR?: number;\n rxBR?: number;\n rxBL?: number;\n}\n\nexport interface RoundedRectRadii {\n tl: number;\n tr: number;\n br: number;\n bl: number;\n}\n\nconst toSafeNumber = (value: number | undefined, fallback = 0): number =>\n Number.isFinite(value) ? Math.max(0, Number(value)) : fallback;\n\nexport function normalizeShapeType(shapeType: ShapeType | string | undefined): NormalizedShapeType {\n if (shapeType === 'rectangle' || shapeType === 'rounded-rect') return 'rounded-rect';\n if (shapeType === 'circle') return 'circle';\n if (shapeType === 'triangle') return 'triangle';\n return 'unsupported';\n}\n\nexport function hasIndividualCornerRadii(radii: RoundedRectRadiiInput): boolean {\n return (radii.rxTL != null && radii.rxTL > 0) || (radii.rxTR != null && radii.rxTR > 0) || (radii.rxBR != null && radii.rxBR > 0) || (radii.rxBL != null && radii.rxBL > 0);\n}\n\nexport function getRoundedRectRadii(\n width: number,\n height: number,\n radii: RoundedRectRadiiInput\n): RoundedRectRadii {\n const maxR = Math.max(0, Math.min(width, height) / 2);\n const uniform = toSafeNumber(radii.rx, 0);\n\n return {\n tl: Math.min(toSafeNumber(radii.rxTL, uniform), maxR),\n tr: Math.min(toSafeNumber(radii.rxTR, uniform), maxR),\n br: Math.min(toSafeNumber(radii.rxBR, uniform), maxR),\n bl: Math.min(toSafeNumber(radii.rxBL, uniform), maxR),\n };\n}\n\nexport function buildRoundedRectPath(\n width: number,\n height: number,\n radii: RoundedRectRadii\n): string {\n const { tl, tr, br, bl } = radii;\n\n return [\n `M ${tl} 0`,\n `L ${width - tr} 0`,\n tr > 0 ? `A ${tr} ${tr} 0 0 1 ${width} ${tr}` : `L ${width} 0`,\n `L ${width} ${height - br}`,\n br > 0 ? `A ${br} ${br} 0 0 1 ${width - br} ${height}` : `L ${width} ${height}`,\n `L ${bl} ${height}`,\n bl > 0 ? `A ${bl} ${bl} 0 0 1 0 ${height - bl}` : `L 0 ${height}`,\n `L 0 ${tl}`,\n tl > 0 ? `A ${tl} ${tl} 0 0 1 ${tl} 0` : `L 0 0`,\n 'Z',\n ].join(' ');\n}\n\nexport function getTrianglePoints(x: number, y: number, width: number, height: number): { x: number; y: number }[] {\n return [\n { x: x + width / 2, y },\n { x: x + width, y: y + height },\n { x, y: y + height },\n ];\n}\n\n/**\n * Build a rounded triangle SVG path.\n * Vertices: top-center, bottom-right, bottom-left.\n * rTop = radius at top vertex, rBR = bottom-right, rBL = bottom-left.\n * Each corner is replaced with a quadratic bezier curve when radius > 0.\n */\nexport function buildRoundedTrianglePath(\n w: number,\n h: number,\n rTop: number,\n rBR: number,\n rBL: number\n): string {\n // Triangle vertices (local coords, origin top-left)\n const A = { x: w / 2, y: 0 }; // top\n const B = { x: w, y: h }; // bottom-right\n const C = { x: 0, y: h }; // bottom-left\n\n const maxR = Math.min(w, h) / 2;\n const rt = Math.min(Math.max(0, rTop), maxR);\n const rbr = Math.min(Math.max(0, rBR), maxR);\n const rbl = Math.min(Math.max(0, rBL), maxR);\n\n // Helper: get unit vector from p1 to p2\n const unitVec = (p1: { x: number; y: number }, p2: { x: number; y: number }) => {\n const dx = p2.x - p1.x;\n const dy = p2.y - p1.y;\n const len = Math.sqrt(dx * dx + dy * dy);\n return len > 0 ? { x: dx / len, y: dy / len } : { x: 0, y: 0 };\n };\n\n // For each corner, we offset along the two adjacent edges by `r`\n // and draw a quadratic bezier through the original vertex.\n const cornerSegment = (\n prev: { x: number; y: number },\n curr: { x: number; y: number },\n next: { x: number; y: number },\n r: number\n ): string => {\n if (r <= 0) {\n return `L ${curr.x} ${curr.y}`;\n }\n const uPrev = unitVec(curr, prev);\n const uNext = unitVec(curr, next);\n const startX = curr.x + uPrev.x * r;\n const startY = curr.y + uPrev.y * r;\n const endX = curr.x + uNext.x * r;\n const endY = curr.y + uNext.y * r;\n return `L ${startX} ${startY} Q ${curr.x} ${curr.y} ${endX} ${endY}`;\n };\n\n // Start from mid-point of edge C→A (bottom-left to top)\n const uCA = unitVec(C, A);\n const startX = C.x + uCA.x * (rbl > 0 ? rbl : 0);\n const startY = C.y + uCA.y * (rbl > 0 ? rbl : 0);\n\n // If bottom-left has no rounding, start from C directly \n const actualStartX = rbl > 0 ? startX : C.x;\n const actualStartY = rbl > 0 ? startY : C.y;\n\n const parts: string[] = [\n `M ${actualStartX} ${actualStartY}`,\n cornerSegment(C, A, B, rt), // top corner\n cornerSegment(A, B, C, rbr), // bottom-right corner\n cornerSegment(B, C, A, rbl), // bottom-left corner\n 'Z',\n ];\n\n return parts.join(' ');\n}\n","/**\n * Inline text markdown parser for canvas text elements.\n *\n * Syntax (opt-in via element.formattingEnabled):\n * **bold** -> fontWeight: 700\n * *italic* -> fontStyle: italic\n * __underline__ -> underline\n * ~~strike~~ -> linethrough\n * ==highlight== -> background = secondary color\n * [c=primary]X[/c] -> fill = primary (also: secondary, or any #hex / css color)\n * [bg=primary]X[/bg] -> textBackgroundColor = primary\n * \\* \\_ \\[ \\\\ -> escape\n */\n\nexport type CharStyle = {\n fontWeight?: number;\n fontStyle?: 'italic' | 'normal';\n underline?: boolean;\n linethrough?: boolean;\n fill?: string;\n textBackgroundColor?: string;\n};\n\nexport type FabricStylesMap = Record<number, Record<number, CharStyle>>;\n\nexport interface ThemeColorMap {\n primary?: string;\n secondary?: string;\n}\n\nlet activeThemeColors: ThemeColorMap = {};\nexport function setMarkdownThemeColors(c: ThemeColorMap): void {\n activeThemeColors = { ...c };\n}\nexport function getMarkdownThemeColors(): ThemeColorMap {\n return activeThemeColors;\n}\n\nfunction resolveColorToken(token: string, theme: ThemeColorMap): string | undefined {\n const raw = token.trim();\n const t = raw.toLowerCase();\n if (t === 'primary') return theme.primary;\n if (t === 'secondary') return theme.secondary;\n if (/^#([0-9a-f]{3,8})$/i.test(raw)) return raw;\n if (/^(rgb|rgba|hsl|hsla)\\(/i.test(raw)) return raw;\n if (/^[a-z]+$/i.test(raw)) return raw;\n return undefined;\n}\n\ninterface Run { text: string; style: CharStyle; }\n\nfunction mergeStyle(a: CharStyle, b: CharStyle): CharStyle { return { ...a, ...b }; }\n\nfunction tokenize(input: string, theme: ThemeColorMap): Run[] {\n const runs: Run[] = [];\n const stack: Array<{ kind: string; style: CharStyle; closer: string }> = [];\n let buf = '';\n\n const activeStyle = (): CharStyle => {\n let s: CharStyle = {};\n for (const e of stack) s = mergeStyle(s, e.style);\n return s;\n };\n const flush = () => {\n if (buf.length === 0) return;\n runs.push({ text: buf, style: activeStyle() });\n buf = '';\n };\n\n let i = 0;\n const n = input.length;\n const peek = (s: string, at: number = i) => input.startsWith(s, at);\n const findUnescaped = (needle: string, from: number): number => {\n let p = from;\n while (p < n) {\n if (input[p] === '\\\\' && p + 1 < n) { p += 2; continue; }\n if (input.startsWith(needle, p)) return p;\n p++;\n }\n return -1;\n };\n\n const tryOpenBracket = (): number => {\n if (input[i] !== '[') return -1;\n const m = /^\\[(c|bg)=([^\\]]+)\\]/.exec(input.slice(i));\n if (!m) return -1;\n const kind = m[1];\n const tokenRaw = m[2];\n const closer = kind === 'c' ? '[/c]' : '[/bg]';\n if (findUnescaped(closer, i + m[0].length) === -1) return -1;\n const color = resolveColorToken(tokenRaw, theme);\n const style: CharStyle = {};\n if (color) {\n if (kind === 'c') style.fill = color;\n else style.textBackgroundColor = color;\n }\n flush();\n stack.push({ kind, style, closer });\n return i + m[0].length;\n };\n\n const tryCloseBracket = (): number => {\n for (let s = stack.length - 1; s >= 0; s--) {\n const top = stack[s];\n if (top.kind !== 'c' && top.kind !== 'bg') continue;\n if (peek(top.closer)) {\n if (s !== stack.length - 1) stack.length = s + 1;\n flush();\n stack.pop();\n return i + top.closer.length;\n }\n break;\n }\n return -1;\n };\n\n const toggle = (delim: string, kind: string, style: CharStyle): number | null => {\n if (!peek(delim)) return null;\n const topIdx = stack.findIndex(e => e.kind === kind);\n if (topIdx >= 0) {\n // Only close when this kind is the top-most open entry. Otherwise, return\n // null so a different (innermost) delimiter gets a chance to close first.\n // This makes ***x*** correctly close italic with `*` before bold with `**`.\n if (topIdx !== stack.length - 1) return null;\n flush();\n stack.length = topIdx;\n return i + delim.length;\n }\n if (findUnescaped(delim, i + delim.length) === -1) return null;\n flush();\n stack.push({ kind, style, closer: delim });\n return i + delim.length;\n };\n\n while (i < n) {\n const ch = input[i];\n if (ch === '\\\\' && i + 1 < n) { buf += input[i + 1]; i += 2; continue; }\n if (ch === '[') {\n const closed = tryCloseBracket();\n if (closed > 0) { i = closed; continue; }\n const opened = tryOpenBracket();\n if (opened > 0) { i = opened; continue; }\n }\n let next: number | null;\n if ((next = toggle('**', 'bold', { fontWeight: 700 })) !== null) { i = next; continue; }\n if ((next = toggle('__', 'under', { underline: true })) !== null) { i = next; continue; }\n if ((next = toggle('~~', 'strike', { linethrough: true })) !== null) { i = next; continue; }\n if ((next = toggle('==', 'highlight', { textBackgroundColor: theme.secondary || '#ffe066' })) !== null) { i = next; continue; }\n if ((next = toggle('*', 'italic', { fontStyle: 'italic' })) !== null) { i = next; continue; }\n buf += ch; i++;\n }\n flush();\n return runs;\n}\n\nexport function parseTextMarkdown(\n input: string,\n themeColors?: ThemeColorMap,\n): { plainText: string; styles: FabricStylesMap; hasFormatting: boolean } {\n const theme = themeColors ?? activeThemeColors;\n const runs = tokenize(input ?? '', theme);\n let plain = '';\n const styles: FabricStylesMap = {};\n let lineIdx = 0;\n let charIdx = 0;\n let hasFormatting = false;\n for (const run of runs) {\n const styleHasContent = Object.keys(run.style).length > 0;\n if (styleHasContent) hasFormatting = true;\n for (const ch of run.text) {\n if (ch === '\\n') { plain += '\\n'; lineIdx++; charIdx = 0; continue; }\n plain += ch;\n if (styleHasContent) {\n if (!styles[lineIdx]) styles[lineIdx] = {};\n styles[lineIdx][charIdx] = { ...run.style };\n }\n charIdx++;\n }\n }\n return { plainText: plain, styles, hasFormatting };\n}\n\nexport function stripTextMarkdown(input: string): string {\n return parseTextMarkdown(input).plainText;\n}\n","/**\n * Gradient utilities for Fabric.js, PDF export, and server-side rendering.\n */\nimport { GradientConfig, GradientStop, isGradientConfig } from '@/types/editor';\nimport * as fabric from 'fabric';\n\n/**\n * Convert angle in degrees to x1,y1,x2,y2 coordinates for a linear gradient.\n * The coordinates are in the range [0,1] (normalized).\n */\nfunction angleToCoords(angleDeg: number): { x1: number; y1: number; x2: number; y2: number } {\n const rad = (angleDeg * Math.PI) / 180;\n // CSS angle: 0deg = bottom-to-top, 90deg = left-to-right\n // Fabric: coords relative to object bounds\n const x1 = 0.5 - Math.sin(rad) * 0.5;\n const y1 = 0.5 + Math.cos(rad) * 0.5;\n const x2 = 0.5 + Math.sin(rad) * 0.5;\n const y2 = 0.5 - Math.cos(rad) * 0.5;\n return { x1, y1, x2, y2 };\n}\n\n/**\n * Normalize gradient stops for engines that require deterministic ordering.\n * - clamps offsets to [0,1]\n * - sorts by offset\n * - ensures boundary stops at 0 and 1 for full-range interpolation\n */\nfunction normalizeGradientStops(stops: GradientStop[]): GradientStop[] {\n const normalized = stops\n .map((stop) => ({\n color: stop.color,\n offset: Math.max(0, Math.min(1, Number(stop.offset) || 0)),\n }))\n .sort((a, b) => a.offset - b.offset);\n\n if (normalized.length === 0) return normalized;\n\n if (normalized[0].offset > 0) {\n normalized.unshift({ color: normalized[0].color, offset: 0 });\n }\n if (normalized[normalized.length - 1].offset < 1) {\n normalized.push({ color: normalized[normalized.length - 1].color, offset: 1 });\n }\n\n return normalized;\n}\n\n/**\n * Convert a GradientConfig to a Fabric.js Gradient object.\n */\nexport function gradientToFabric(\n gradient: GradientConfig,\n width: number,\n height: number,\n): fabric.Gradient<'linear'> | fabric.Gradient<'radial'> {\n const colorStops = normalizeGradientStops(gradient.stops).map((s) => ({\n offset: s.offset,\n color: s.color,\n }));\n\n if (gradient.type === 'linear' || gradient.type === 'conic') {\n // Conic gradients aren't natively supported by Fabric, fallback to linear\n const coords = angleToCoords(gradient.angle ?? 90);\n return new fabric.Gradient({\n type: 'linear',\n coords: {\n x1: coords.x1 * width,\n y1: coords.y1 * height,\n x2: coords.x2 * width,\n y2: coords.y2 * height,\n },\n colorStops,\n });\n }\n\n // Radial gradient\n const cx = (gradient.cx ?? 0.5) * width;\n const cy = (gradient.cy ?? 0.5) * height;\n const r = (gradient.r ?? 0.5) * Math.max(width, height);\n return new fabric.Gradient({\n type: 'radial',\n coords: {\n x1: cx,\n y1: cy,\n r1: 0,\n x2: cx,\n y2: cy,\n r2: r,\n },\n colorStops,\n });\n}\n\n/**\n * Convert GradientConfig to CSS background string.\n */\nexport function gradientToCss(g: GradientConfig): string {\n const stopsStr = g.stops.map(s => `${s.color} ${Math.round(s.offset * 100)}%`).join(', ');\n if (g.type === 'linear') {\n return `linear-gradient(${g.angle ?? 90}deg, ${stopsStr})`;\n }\n if (g.type === 'radial') {\n const cx = (g.cx ?? 0.5) * 100;\n const cy = (g.cy ?? 0.5) * 100;\n return `radial-gradient(circle at ${cx}% ${cy}%, ${stopsStr})`;\n }\n if (g.type === 'conic') {\n const cx = (g.cx ?? 0.5) * 100;\n const cy = (g.cy ?? 0.5) * 100;\n return `conic-gradient(from ${g.angle ?? 0}deg at ${cx}% ${cy}%, ${stopsStr})`;\n }\n return `linear-gradient(90deg, ${stopsStr})`;\n}\n\n/**\n * Convert GradientConfig to SVG gradient definition string.\n * Returns { defXml, fillUrl } where defXml goes into <defs> and fillUrl is the fill attribute.\n */\nexport function gradientToSvgDef(\n g: GradientConfig,\n id: string,\n width: number,\n height: number,\n): { defXml: string; fillUrl: string } {\n const stopsXml = g.stops\n .map(s => `<stop offset=\"${s.offset}\" stop-color=\"${s.color}\" />`)\n .join('\\n ');\n\n if (g.type === 'linear' || g.type === 'conic') {\n const coords = angleToCoords(g.angle ?? 90);\n const defXml = `\n <linearGradient id=\"${id}\" x1=\"${coords.x1}\" y1=\"${coords.y1}\" x2=\"${coords.x2}\" y2=\"${coords.y2}\">\n ${stopsXml}\n </linearGradient>`;\n return { defXml, fillUrl: `url(#${id})` };\n }\n\n // Radial\n const cx = g.cx ?? 0.5;\n const cy = g.cy ?? 0.5;\n const r = g.r ?? 0.5;\n const defXml = `\n <radialGradient id=\"${id}\" cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fx=\"${cx}\" fy=\"${cy}\">\n ${stopsXml}\n </radialGradient>`;\n return { defXml, fillUrl: `url(#${id})` };\n}\n\n/**\n * Parse hex color to RGB.\n */\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } | null {\n const match = /^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/.exec(hex);\n if (!match) return null;\n return {\n r: parseInt(match[1], 16),\n g: parseInt(match[2], 16),\n b: parseInt(match[3], 16),\n };\n}\n\n/**\n * For jsPDF: apply gradient using GState and shading.\n * jsPDF doesn't have great native gradient API, so we use advancedAPI pattern.\n */\nexport function applyGradientToPdf(\n pdf: any,\n gradient: GradientConfig,\n x: number,\n y: number,\n width: number,\n height: number,\n): void {\n // jsPDF supports linear and radial gradients via the advancedAPI\n const colors = gradient.stops.map(s => {\n const rgb = hexToRgb(s.color);\n return rgb || { r: 0, g: 0, b: 0 };\n });\n const offsets = gradient.stops.map(s => s.offset);\n\n if (gradient.type === 'linear' || gradient.type === 'conic') {\n const coords = angleToCoords(gradient.angle ?? 90);\n const x1 = x + coords.x1 * width;\n const y1 = y + coords.y1 * height;\n const x2 = x + coords.x2 * width;\n const y2 = y + coords.y2 * height;\n\n try {\n // Use jsPDF's linearGradient if available (advancedAPI)\n if (typeof pdf.linearGradient === 'function') {\n const grad = pdf.linearGradient(x1, y1, x2, y2);\n for (let i = 0; i < colors.length; i++) {\n grad.addColorStop(offsets[i], [colors[i].r, colors[i].g, colors[i].b]);\n }\n grad.fill();\n return;\n }\n } catch (_) {\n // fallback to first color\n }\n }\n\n // Fallback: use first stop color\n const first = colors[0] || { r: 0, g: 0, b: 0 };\n pdf.setFillColor(first.r, first.g, first.b);\n}\n","import * as fabric from 'fabric';\nimport { CanvasElement } from '@/types/editor';\n// Side-effect import: extends fabric.Textbox prototype with `minBoxHeight`\n// (vertical resize floor) and `verticalAlign` (top/middle/bottom). Must be\n// imported before any Textbox is constructed.\nimport './fabricTextboxExtensions';\nimport { setObjectData } from './fabricUtils';\nimport { getTextboxWidthFitMetrics } from './textMeasurement';\nimport { applyTextBackground, extractTextBgConfig, buildTextShadow } from './textBackgroundRenderer';\nimport {\n buildRoundedRectPath as buildCanonicalRoundedRectPath,\n getRoundedRectRadii,\n hasIndividualCornerRadii,\n normalizeShapeType,\n buildRoundedTrianglePath,\n TRIANGLE_STROKE_MITER_LIMIT,\n} from './shapeGeometry';\nimport { applyTriangleCacheSettings } from './triangleCache';\nimport { parseTextMarkdown } from './textMarkdown';\nimport { gradientToFabric } from './gradientUtils';\nimport { isGradientConfig } from '@/types/editor';\n\n/**\n * Apply fillGradient / strokeGradient to a freshly created shape/line so the\n * very first render (use page preview, package preview, off-screen capture)\n * shows the gradient — without needing a follow-up updateFabricObject sync.\n * Mirrors the gradient block in PageCanvas's updateFabricObject.\n */\nfunction applyInitialGradients(obj: fabric.FabricObject, element: CanvasElement): void {\n const w = (typeof obj.width === 'number' && obj.width > 0) ? obj.width : Number(element.width) || 0;\n const h = (typeof obj.height === 'number' && obj.height > 0) ? obj.height : Number(element.height) || 0;\n if (w <= 0 || h <= 0) return;\n const fg = (element as any).fillGradient;\n if (fg && isGradientConfig(fg)) {\n try {\n obj.set({ fill: gradientToFabric(fg, w, h), objectCaching: false });\n (obj as any).__lastFillGradientJson = JSON.stringify(fg);\n obj.dirty = true;\n } catch (e) {\n console.warn('[fabricObjectCreators] fillGradient apply failed:', e);\n }\n }\n const sg = (element as any).strokeGradient;\n if (sg && isGradientConfig(sg)) {\n try {\n obj.set({ stroke: gradientToFabric(sg, w, h), objectCaching: false });\n (obj as any).__lastStrokeGradientJson = JSON.stringify(sg);\n obj.dirty = true;\n } catch (e) {\n console.warn('[fabricObjectCreators] strokeGradient apply failed:', e);\n }\n }\n}\n\nconst roundDiag = (value: unknown): unknown => {\n if (typeof value !== 'number') return value;\n return Number.isFinite(value) ? Number(value.toFixed(3)) : value;\n};\n\nconst stringifyDiag = (payload: Record<string, unknown>): string => {\n try {\n return JSON.stringify(payload, (_key, value) => roundDiag(value));\n } catch {\n return String(payload);\n }\n};\n\n/**\n * Older text elements may store underline/linethrough as per-character flags\n * inside Fabric's `styles` map (`{ [lineIdx]: { [charIdx]: { underline: true } } }`)\n * instead of as a top-level boolean. When ANY character has the flag, treat the\n * whole textbox as having that decoration so the SVG/PDF pipeline (which only\n * looks at the top-level attribute / text-decoration on <text>) renders it.\n */\nfunction hasAnyCharStyleFlag(styles: any, flag: 'underline' | 'linethrough'): boolean | undefined {\n if (!styles || typeof styles !== 'object') return undefined;\n const lineEntries = Array.isArray(styles) ? styles : Object.values(styles);\n for (const lineStyle of lineEntries) {\n if (!lineStyle || typeof lineStyle !== 'object') continue;\n for (const charStyle of Object.values(lineStyle as Record<string, any>)) {\n if (charStyle && (charStyle as any)[flag] === true) return true;\n }\n }\n return undefined;\n}\n\nexport function buildRoundedRectPath(w: number, h: number, tl: number, tr: number, br: number, bl: number): string {\n return buildCanonicalRoundedRectPath(w, h, getRoundedRectRadii(w, h, { rxTL: tl, rxTR: tr, rxBR: br, rxBL: bl }));\n}\n\n\nexport function createShape(element: CanvasElement): fabric.FabricObject | null {\n const fill = element.fill || 'transparent';\n const stroke = element.stroke || 'transparent';\n const strokeWidth = element.strokeWidth || 0;\n const w = Number(element.width);\n const h = Number(element.height);\n const shapeType = normalizeShapeType(element.shapeType);\n\n switch (shapeType) {\n case 'rounded-rect': {\n if (hasIndividualCornerRadii(element)) {\n const radii = getRoundedRectRadii(w, h, {\n rx: element.rx ?? 0,\n rxTL: element.rxTL,\n rxTR: element.rxTR,\n rxBR: element.rxBR,\n rxBL: element.rxBL,\n });\n const path = buildCanonicalRoundedRectPath(w, h, radii);\n return new fabric.Path(path, {\n fill,\n stroke,\n strokeWidth,\n strokeUniform: true,\n strokeLineJoin: 'miter',\n strokeLineCap: 'butt',\n objectCaching: true,\n });\n }\n\n const maxR = Math.min(w, h) / 2;\n const rx = Math.min(Math.max(0, Number(element.rx ?? 0)), maxR);\n const rySource = element.ry ?? element.rx ?? 0;\n const ry = Math.min(Math.max(0, Number(rySource)), maxR);\n\n if (rx === 0 && ry === 0) {\n return new fabric.Rect({\n width: w,\n height: h,\n fill,\n stroke,\n strokeWidth,\n strokeUniform: true,\n strokeLineJoin: 'miter',\n strokeLineCap: 'butt',\n objectCaching: true,\n });\n }\n\n return new fabric.Rect({\n width: w,\n height: h,\n fill,\n stroke,\n strokeWidth,\n rx,\n ry,\n strokeUniform: true,\n strokeLineJoin: 'round',\n strokeLineCap: 'round',\n objectCaching: true,\n });\n }\n\n case 'circle': {\n const radius = Math.min(w, h) / 2;\n return new fabric.Circle({\n radius,\n fill,\n stroke,\n strokeWidth,\n originX: 'left',\n originY: 'top',\n objectCaching: true,\n strokeUniform: true,\n strokeLineJoin: 'round',\n strokeLineCap: 'round',\n lockUniScaling: true,\n });\n }\n\n case 'triangle': {\n const rTop = Math.max(0, Number(element.triRTop ?? 0));\n const rBR = Math.max(0, Number(element.triRBR ?? 0));\n const rBL = Math.max(0, Number(element.triRBL ?? 0));\n const path = buildRoundedTrianglePath(w, h, rTop, rBR, rBL);\n\n const triangle = new fabric.Path(path, {\n fill,\n stroke,\n strokeWidth,\n strokeUniform: true,\n strokeLineJoin: 'miter',\n strokeLineCap: 'butt',\n strokeMiterLimit: TRIANGLE_STROKE_MITER_LIMIT,\n objectCaching: false,\n });\n\n return triangle;\n }\n\n default:\n return new fabric.Rect({\n width: w,\n height: h,\n fill,\n stroke,\n strokeWidth,\n strokeUniform: true,\n strokeLineJoin: 'miter',\n strokeLineCap: 'butt',\n objectCaching: true,\n });\n }\n}\n\nexport function createText(element: CanvasElement): fabric.FabricObject {\n const overflowPolicy = element.overflowPolicy || 'grow-and-push';\n let text = element.text || 'Text';\n let fontSize = element.fontSize || 16;\n const minFontSize = element.minFontSize || 8;\n const maxLines = element.maxLines || 3;\n // Inline markdown — strip markers from text for measurement, apply parsed\n // styles to the final Textbox below.\n const formattingEnabled = element.formattingEnabled === true;\n let parsedStyles: Record<number, Record<number, any>> = {};\n if (formattingEnabled) {\n const parsed = parseTextMarkdown(text);\n text = parsed.plainText || ' ';\n parsedStyles = parsed.styles;\n }\n \n const baseWidth = element.width && element.width > 0 ? element.width : 200;\n const baseHeight = element.height;\n const fixedWidth = Math.max(baseWidth, 1);\n const splitByGrapheme = overflowPolicy === 'auto-shrink'\n ? false\n : (element.splitByGrapheme ?? (element.wordWrap === 'break-word'));\n \n // For auto-shrink: keep width fixed, prevent implicit wrapping, and reduce font size until it fits.\n if (overflowPolicy === 'auto-shrink') {\n // Match PageCanvas update-path: the fit-target is max(stored height,\n // minBoxHeight) so a vertically-grown box keeps its larger fit target\n // and the font doesn't shrink below what fits the visible box.\n const minBoxHForShrink = Math.max(0, Number((element as any).minBoxHeight) || 0);\n const heightBound = Math.max(baseHeight || 0, minBoxHForShrink);\n const explicitLineCount = Math.max(1, text.split('\\n').length);\n const debugAutoShrink = typeof window !== 'undefined' && (window as any).__pixldocsDebugAutoShrink === true;\n const startFontSize = fontSize;\n let breakReason = 'min-font-size-reached';\n let lastIter: any = null;\n const iterationSamples: any[] = [];\n while (fontSize > 1) {\n const testTextbox = new fabric.Textbox(text, {\n width: fixedWidth,\n fontSize,\n fontFamily: element.fontFamily || 'Open Sans',\n fontWeight: element.fontWeight as number || 400,\n fontStyle: element.fontStyle || 'normal',\n lineHeight: element.lineHeight || 1.2,\n charSpacing: element.charSpacing || 0,\n splitByGrapheme: false,\n ...(formattingEnabled ? { styles: parsedStyles } : {}),\n });\n testTextbox.initDimensions();\n \n const textHeight = testTextbox.height || 0;\n const renderedLineCount = testTextbox.textLines?.length || 1;\n const hasNoImplicitWrap = renderedLineCount <= explicitLineCount;\n const fitsHeight = heightBound <= 0 || textHeight <= heightBound;\n // Also check that no line overflows the fixed width (single long word case).\n // Use canvas metrics rather than Fabric's cached __lineWidths, matching\n // the underline fidelity fix where stale Fabric text caches caused width drift.\n const widthMetrics = getTextboxWidthFitMetrics(testTextbox, fixedWidth);\n const { maxLineWidth, widthDidGrow, fitsWidth } = widthMetrics;\n\n if (debugAutoShrink) {\n lastIter = {\n fontSize, renderedLineCount, explicitLineCount, textHeight,\n ...widthMetrics, fixedWidth, hasNoImplicitWrap, fitsHeight, fitsWidth,\n textLines: (testTextbox.textLines || []).map((line: unknown) => Array.isArray(line) ? line.join('') : String(line ?? '')),\n };\n if (iterationSamples.length < 6 || fontSize <= minFontSize + 2) {\n iterationSamples.push(lastIter);\n }\n }\n\n // Auto-shrink now allows word-wrap by width — the box wraps to its\n // configured width, then the font shrinks until the wrapped content\n // height fits the box height. (Earlier we required no implicit wrap,\n // which made auto-shrink ignore the box height entirely.)\n if (fitsHeight && fitsWidth) {\n breakReason = 'fits';\n break;\n }\n fontSize--;\n }\n if (debugAutoShrink) {\n // eslint-disable-next-line no-console\n console.log('[auto-shrink][diag] ' + stringifyDiag({\n id: element.id, name: element.name, text: text.slice(0, 180), textLength: text.length,\n fontFamily: element.fontFamily, fontWeight: element.fontWeight,\n elementWidth: element.width, elementHeight: element.height,\n scaleX: element.scaleX ?? 1, scaleY: element.scaleY ?? 1,\n fixedWidth, baseHeight,\n startFontSize, finalFontSize: fontSize, breakReason,\n iterations: iterationSamples,\n lastIter,\n fontCheckRegular: typeof document !== 'undefined' && document.fonts\n ? document.fonts.check(`16px \"${element.fontFamily || 'Open Sans'}\"`)\n : null,\n fontCheckBold: typeof document !== 'undefined' && document.fonts\n ? document.fonts.check(`bold 16px \"${element.fontFamily || 'Open Sans'}\"`)\n : null,\n }));\n }\n }\n \n // For max-lines-ellipsis: truncate text to fit max lines\n if (overflowPolicy === 'max-lines-ellipsis') {\n const originalText = element.text || 'Text';\n const countLines = (testText: string): number => {\n const tb = new fabric.Textbox(testText, {\n width: element.width,\n fontSize,\n fontFamily: element.fontFamily || 'Open Sans',\n lineHeight: element.lineHeight || 1.2,\n splitByGrapheme: element.splitByGrapheme ?? (element.wordWrap === 'break-word'),\n });\n tb.initDimensions();\n return tb.textLines?.length || 1;\n };\n \n let low = 0;\n let high = originalText.length;\n let result = originalText;\n \n while (low < high) {\n const mid = Math.floor((low + high + 1) / 2);\n const testText = originalText.slice(0, mid) + '...';\n const lineCount = countLines(testText);\n \n if (lineCount <= maxLines) {\n low = mid;\n result = testText;\n } else {\n high = mid - 1;\n }\n }\n \n if (result.endsWith('...') && result.length > 3) {\n const beforeEllipsis = result.slice(0, -3).trimEnd();\n result = beforeEllipsis + '...';\n }\n \n text = result;\n }\n \n // Preserve the stored textbox width for every mode. Expanding to the longest\n // measured line prevents wrapping in preview/PDF and breaks builder parity.\n const targetWidth = fixedWidth;\n const targetScaleX = element.scaleX ?? 1;\n const targetScaleY = element.scaleY ?? 1;\n\n const textbox = new fabric.Textbox(text, {\n width: targetWidth,\n minWidth: 1,\n dynamicMinWidth: 0,\n scaleX: targetScaleX,\n scaleY: targetScaleY,\n fontSize,\n fontFamily: element.fontFamily || 'Open Sans',\n fill: element.fill || '#1a1a1a',\n fontWeight: (element.fontWeight as number) || 400,\n textAlign: (element.textAlign as any) || 'left',\n fontStyle: element.fontStyle || 'normal',\n underline: element.underline ?? hasAnyCharStyleFlag((element as any).styles, 'underline') ?? false,\n linethrough: element.linethrough ?? hasAnyCharStyleFlag((element as any).styles, 'linethrough') ?? false,\n lineHeight: element.lineHeight || 1.2,\n charSpacing: element.charSpacing || 0,\n objectCaching: false,\n noScaleCache: true,\n splitByGrapheme,\n // When inline markdown formatting is enabled, the displayed text is the\n // PARSED plain text (markdown source lives separately on the element).\n // Allowing canvas inline editing would let the user edit that plain text\n // and on commit we'd save it back as the new markdown source — wiping all\n // formatting tokens (**, __, [c=...], etc). Disable inline edit and steer\n // users to the right-panel text field which exposes the raw markdown.\n editable: !formattingEnabled,\n ...(formattingEnabled ? { styles: parsedStyles } : ((element as any).styles ? { styles: (element as any).styles } : {})),\n // Vertical sizing extensions (see fabricTextboxExtensions.ts). Apply for\n // every overflow policy — in auto-shrink mode `minBoxHeight` acts as a\n // visual floor so the box renders at the user's chosen height even after\n // the font shrinks to fit. PageCanvas's auto-shrink loop already uses the\n // same value as a fit-target, so the rendered box and the shrink target\n // stay in sync (parity with the Use page / EC2 renderer).\n ...((element.minBoxHeight ?? 0) > 0\n ? { minBoxHeight: element.minBoxHeight }\n : {}),\n verticalAlign: element.verticalAlign || 'top',\n } as any);\n // Tag the textbox so canvas-level handlers can show a friendly toast when\n // someone double-clicks a formatting-enabled text element.\n (textbox as any).__formattingEnabled = formattingEnabled;\n \n textbox.initDimensions();\n \n textbox.set({ \n width: targetWidth,\n minWidth: 1,\n dynamicMinWidth: 0,\n scaleX: targetScaleX,\n scaleY: targetScaleY,\n });\n textbox.setCoords();\n \n const widthAfterSet = textbox.width ?? 0;\n const scaleXAfterSet = textbox.scaleX ?? 1;\n const scaleYAfterSet = textbox.scaleY ?? 1;\n \n if (Math.abs(widthAfterSet - targetWidth) > 0.01 || \n Math.abs(scaleXAfterSet - targetScaleX) > 0.01 ||\n Math.abs(scaleYAfterSet - targetScaleY) > 0.01) {\n (textbox as any).width = targetWidth;\n (textbox as any).dynamicMinWidth = 0;\n (textbox as any).scaleX = targetScaleX;\n (textbox as any).scaleY = targetScaleY;\n textbox.setCoords();\n }\n \n textbox.dirty = true;\n // When inline markdown formatting is enabled, force-invalidate fabric's\n // text caches so per-character styles (bold/italic/underline/color)\n // paint correctly on first render without requiring the user to click\n // the textbox to \"wake it up\".\n if (formattingEnabled) {\n try {\n (textbox as any)._forceClearCache = true;\n if (typeof (textbox as any)._clearCache === 'function') {\n (textbox as any)._clearCache();\n }\n } catch {}\n }\n\n if (overflowPolicy === 'auto-shrink' && typeof window !== 'undefined' && (window as any).__pixldocsDebugAutoShrink === true) {\n // eslint-disable-next-line no-console\n console.log('[auto-shrink][final-textbox] ' + stringifyDiag({\n id: element.id,\n name: element.name,\n text: text.slice(0, 180),\n targetWidth,\n targetScaleX,\n targetScaleY,\n finalFontSize: fontSize,\n textboxWidth: textbox.width,\n textboxHeight: textbox.height,\n lineCount: textbox.textLines?.length || 0,\n lines: (textbox.textLines || []).map((line: unknown) => Array.isArray(line) ? line.join('') : String(line ?? '')),\n widthMetrics: getTextboxWidthFitMetrics(textbox, targetWidth),\n }));\n }\n\n // Apply text background (rounded bg + padding) and shadow. Both are no-ops when\n // the corresponding props are absent on the element.\n applyTextBackground(textbox, extractTextBgConfig(element));\n const shadow = buildTextShadow(element);\n if (shadow) textbox.set('shadow', shadow);\n\n return textbox;\n}\n\nexport function createLine(element: CanvasElement): fabric.FabricObject {\n const lineLength = element.width * (element.scaleX ?? 1);\n return new fabric.Line([0, 0, lineLength, 0], {\n stroke: element.stroke || '#1a1a1a',\n strokeWidth: element.strokeWidth || 2,\n strokeDashArray: element.strokeDashArray,\n scaleX: 1,\n scaleY: 1,\n });\n}\n\nexport function createFabricObject(element: CanvasElement): fabric.FabricObject | null {\n let obj: fabric.FabricObject | null = null;\n\n switch (element.type) {\n case 'shape':\n obj = createShape(element);\n break;\n case 'text':\n obj = createText(element);\n break;\n case 'line':\n obj = createLine(element);\n break;\n default:\n return null;\n }\n\n if (obj) {\n obj.set({\n originX: 'left',\n originY: 'top',\n });\n \n const isLine = element.type === 'line';\n obj.set({\n left: element.left,\n top: element.top,\n angle: element.angle ?? 0,\n skewX: isLine ? 0 : (element.skewX ?? 0),\n skewY: isLine ? 0 : (element.skewY ?? 0),\n scaleX: isLine ? 1 : (element.scaleX ?? 1),\n scaleY: isLine ? 1 : (element.scaleY ?? 1),\n opacity: element.opacity ?? 1,\n selectable: element.selectable !== false,\n evented: element.evented !== false,\n visible: element.visible !== false,\n hasControls: element.selectable !== false,\n hasBorders: element.selectable !== false,\n lockMovementX: element.selectable === false,\n lockMovementY: element.selectable === false,\n flipX: element.flipX ?? false,\n flipY: element.flipY ?? false,\n });\n setObjectData(obj, element.id);\n if (element.type === 'shape' || element.type === 'line' || element.type === 'text') {\n applyInitialGradients(obj, element);\n }\n }\n\n return obj;\n}\n\nexport function createFabricObjectForGroupMember(element: CanvasElement): fabric.FabricObject | null {\n let obj: fabric.FabricObject | null = null;\n\n switch (element.type) {\n case 'shape':\n obj = createShape(element);\n break;\n case 'text':\n obj = createText(element);\n break;\n case 'line':\n obj = createLine(element);\n break;\n case 'image':\n obj = new fabric.Rect({\n width: element.width,\n height: element.height,\n fill: 'transparent',\n stroke: 'transparent',\n strokeWidth: 0,\n });\n break;\n default:\n return null;\n }\n\n if (obj) {\n const isLine = element.type === 'line';\n const isText = element.type === 'text';\n const skipScale = isLine || isText;\n obj.set({\n originX: 'left',\n originY: 'top',\n left: element.left,\n top: element.top,\n angle: element.angle ?? 0,\n skewX: skipScale ? 0 : (element.skewX ?? 0),\n skewY: skipScale ? 0 : (element.skewY ?? 0),\n scaleX: skipScale ? 1 : (element.scaleX ?? 1),\n scaleY: skipScale ? 1 : (element.scaleY ?? 1),\n opacity: element.opacity ?? 1,\n flipX: element.flipX ?? false,\n flipY: element.flipY ?? false,\n });\n setObjectData(obj, element.id);\n if (element.type === 'shape' || element.type === 'line' || element.type === 'text') {\n applyInitialGradients(obj, element);\n }\n }\n\n return obj;\n}\n","/**\n * QR Code smart element renderer — isomorphic.\n * QR library is injected to avoid environment-specific imports.\n */\nimport type { SmartElementDefinition } from '../types';\n\nexport interface QRCodeLibrary {\n create: (text: string, options: { errorCorrectionLevel: string }) => {\n modules: { size: number; data: Uint8Array | number[] };\n };\n}\n\n/** Module-level injection point for the QR code library */\nlet _qrLib: QRCodeLibrary | null = null;\n\nexport function injectQRCodeLibrary(lib: QRCodeLibrary) {\n _qrLib = lib;\n}\n\nfunction generateQRMatrix(text: string, errorCorrectionLevel: string): { modules: boolean[][]; size: number } {\n const lib = _qrLib;\n if (!lib) return { modules: [[true]], size: 1 };\n try {\n const qr = lib.create(text, { errorCorrectionLevel });\n const size = qr.modules.size;\n const data = qr.modules.data;\n const modules: boolean[][] = [];\n for (let row = 0; row < size; row++) {\n const rowData: boolean[] = [];\n for (let col = 0; col < size; col++) {\n rowData.push(data[row * size + col] === 1);\n }\n modules.push(rowData);\n }\n return { modules, size };\n } catch (e) {\n console.warn('QR generation failed:', e);\n return { modules: [[true]], size: 1 };\n }\n}\n\nfunction renderQRSvg(props: Record<string, any>, width: number, height: number): string {\n const value = props.value || 'https://example.com';\n const fgColor = props.fgColor || '#000000';\n const bgColor = props.bgColor || '#FFFFFF';\n const errorCorrection = props.errorCorrection || 'M';\n const margin = props.margin ?? 2;\n\n const { modules, size } = generateQRMatrix(value, errorCorrection);\n const totalSize = size + margin * 2;\n const cellSize = Math.min(width, height) / totalSize;\n\n let pathData = '';\n for (let row = 0; row < size; row++) {\n for (let col = 0; col < size; col++) {\n if (modules[row]?.[col]) {\n const x = (col + margin) * cellSize;\n const y = (row + margin) * cellSize;\n pathData += `M${x},${y}h${cellSize}v${cellSize}h${-cellSize}Z `;\n }\n }\n }\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"0 0 ${width} ${height}\">\n <rect width=\"${width}\" height=\"${height}\" fill=\"${bgColor}\"/>\n <path d=\"${pathData}\" fill=\"${fgColor}\"/>\n</svg>`;\n}\n\nexport const qrCodeDefinition: SmartElementDefinition = {\n type: 'qrcode',\n label: 'QR Code',\n icon: 'QrCode',\n defaultWidth: 150,\n defaultHeight: 150,\n properties: [\n { key: 'value', label: 'Value / URL', type: 'text', default: 'https://example.com', bindable: true },\n { key: 'fgColor', label: 'Foreground', type: 'color', default: '#000000' },\n { key: 'bgColor', label: 'Background', type: 'color', default: '#FFFFFF' },\n {\n key: 'errorCorrection', label: 'Error Correction', type: 'select', default: 'M',\n options: [\n { value: 'L', label: 'Low (7%)' },\n { value: 'M', label: 'Medium (15%)' },\n { value: 'Q', label: 'Quartile (25%)' },\n { value: 'H', label: 'High (30%)' },\n ],\n },\n { key: 'margin', label: 'Margin', type: 'number', default: 2, min: 0, max: 10, step: 1 },\n ],\n render: renderQRSvg,\n};\n","import type { SmartElementDefinition } from '../types';\n\nfunction renderStarPath(cx: number, cy: number, outerR: number, innerR: number): string {\n const points: [number, number][] = [];\n for (let i = 0; i < 10; i++) {\n const angle = (Math.PI / 2) * -1 + (Math.PI / 5) * i;\n const r = i % 2 === 0 ? outerR : innerR;\n points.push([cx + r * Math.cos(angle), cy + r * Math.sin(angle)]);\n }\n return 'M' + points.map(p => `${p[0].toFixed(2)},${p[1].toFixed(2)}`).join('L') + 'Z';\n}\n\nfunction renderRatingSvg(props: Record<string, any>, width: number, height: number): string {\n const value = Math.max(0, Math.min(props.maxStars || 5, props.value ?? 3));\n const maxStars = props.maxStars || 5;\n const filledColor = props.filledColor || '#FBBF24';\n const emptyColor = props.emptyColor || '#D1D5DB';\n const starSpacing = props.spacing ?? 4;\n\n const totalSpacing = starSpacing * (maxStars - 1);\n const starSize = Math.min((width - totalSpacing) / maxStars, height);\n const outerR = starSize / 2;\n const innerR = outerR * 0.4;\n const cy = height / 2;\n\n let stars = '';\n for (let i = 0; i < maxStars; i++) {\n const cx = outerR + i * (starSize + starSpacing);\n const path = renderStarPath(cx, cy, outerR, innerR);\n if (i < Math.floor(value)) {\n stars += `<path d=\"${path}\" fill=\"${filledColor}\"/>`;\n } else if (i < value) {\n const fraction = value - Math.floor(value);\n const clipId = `clip-${i}`;\n stars += `<defs><clipPath id=\"${clipId}\"><rect x=\"${cx - outerR}\" y=\"0\" width=\"${starSize * fraction}\" height=\"${height}\"/></clipPath></defs>`;\n stars += `<path d=\"${path}\" fill=\"${emptyColor}\"/>`;\n stars += `<path d=\"${path}\" fill=\"${filledColor}\" clip-path=\"url(#${clipId})\"/>`;\n } else {\n stars += `<path d=\"${path}\" fill=\"${emptyColor}\"/>`;\n }\n }\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"0 0 ${width} ${height}\">\n ${stars}\n</svg>`;\n}\n\nexport const ratingDefinition: SmartElementDefinition = {\n type: 'rating',\n label: 'Star Rating',\n icon: 'Star',\n defaultWidth: 200,\n defaultHeight: 40,\n properties: [\n { key: 'value', label: 'Rating Value', type: 'number', default: 3.5, min: 0, max: 10, step: 0.5, bindable: true },\n { key: 'maxStars', label: 'Max Stars', type: 'number', default: 5, min: 1, max: 10, step: 1 },\n { key: 'filledColor', label: 'Filled Color', type: 'color', default: '#FBBF24' },\n { key: 'emptyColor', label: 'Empty Color', type: 'color', default: '#D1D5DB' },\n { key: 'spacing', label: 'Star Spacing', type: 'number', default: 4, min: 0, max: 20, step: 1 },\n ],\n render: renderRatingSvg,\n};\n","import type { SmartElementDefinition } from '../types';\n\nfunction renderProgressSvg(props: Record<string, any>, width: number, height: number): string {\n const value = Math.max(0, Math.min(100, props.value ?? 65));\n const trackColor = props.trackColor || '#E5E7EB';\n const fillColor = props.fillColor || '#3B82F6';\n const borderRadius = Math.min(props.borderRadius ?? Math.round(height / 2), height / 2);\n\n const fillWidth = (width * value) / 100;\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"0 0 ${width} ${height}\">\n <rect width=\"${width}\" height=\"${height}\" rx=\"${borderRadius}\" ry=\"${borderRadius}\" fill=\"${trackColor}\"/>\n <rect width=\"${Math.max(fillWidth, borderRadius * 2)}\" height=\"${height}\" rx=\"${borderRadius}\" ry=\"${borderRadius}\" fill=\"${fillColor}\" style=\"${fillWidth < borderRadius * 2 ? `clip-path: inset(0 ${width - fillWidth}px 0 0)` : ''}\"/>\n</svg>`;\n}\n\nexport const progressDefinition: SmartElementDefinition = {\n type: 'progress',\n label: 'Progress Bar',\n icon: 'BarChart3',\n defaultWidth: 250,\n defaultHeight: 28,\n properties: [\n { key: 'value', label: 'Value (%)', type: 'number', default: 65, min: 0, max: 100, step: 1, bindable: true },\n { key: 'fillColor', label: 'Fill Color', type: 'color', default: '#3B82F6' },\n { key: 'trackColor', label: 'Track Color', type: 'color', default: '#E5E7EB' },\n { key: 'borderRadius', label: 'Corner Radius', type: 'number', default: 14, min: 0, max: 50, step: 1 },\n ],\n render: renderProgressSvg,\n};\n","/** Shared utilities for smart element renderers */\n\nexport function escapeXml(str: string): string {\n return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\n}\n\n/**\n * Estimate text width using average character widths for sans-serif.\n */\nexport function estimateTextWidth(text: string, fontSize: number, fontWeight: string): number {\n const ratio = fontWeight === '700' ? 0.62 : fontWeight === '600' ? 0.6 : 0.56;\n return text.length * fontSize * ratio;\n}\n","import type { SmartElementDefinition } from '../types';\nimport { escapeXml } from '../utils';\n\nfunction renderTableSvg(props: Record<string, any>, width: number, height: number): string {\n const rows = Math.max(1, Math.min(props.rows ?? 3, 20));\n const cols = Math.max(1, Math.min(props.cols ?? 3, 10));\n const fontFamily = props.fontFamily || 'sans-serif';\n const headerBg = props.headerBg || '#1a1a1a';\n const headerText = props.headerText || '#ffffff';\n const cellBg = props.cellBg || '#ffffff';\n const cellText = props.cellText || '#1a1a1a';\n const borderColor = props.borderColor || '#e5e7eb';\n const borderWidth = props.borderWidth ?? 1;\n const fontSize = props.fontSize ?? 12;\n const showHeader = props.showHeader !== false;\n const headerData = props.headerValues || '';\n const cellData = props.cellValues || '';\n\n const totalRows = showHeader ? rows + 1 : rows;\n const cellW = width / cols;\n const cellH = height / totalRows;\n\n const headerValues = headerData ? headerData.split(',').map((s: string) => s.trim()) : [];\n const cellValues = cellData ? cellData.split(',').map((s: string) => s.trim()) : [];\n\n let svg = '';\n\n for (let r = 0; r < totalRows; r++) {\n const isHeader = showHeader && r === 0;\n const bg = isHeader ? headerBg : cellBg;\n const textColor = isHeader ? headerText : cellText;\n const fontWeight = isHeader ? 'bold' : 'normal';\n const y = r * cellH;\n\n for (let c = 0; c < cols; c++) {\n const x = c * cellW;\n svg += `<rect x=\"${x}\" y=\"${y}\" width=\"${cellW}\" height=\"${cellH}\" fill=\"${bg}\" stroke=\"${borderColor}\" stroke-width=\"${borderWidth}\"/>`;\n\n let text = '';\n if (isHeader) {\n text = headerValues[c] || `Col ${c + 1}`;\n } else {\n const dataRow = showHeader ? r - 1 : r;\n const idx = dataRow * cols + c;\n text = cellValues[idx] || '';\n }\n\n if (text) {\n const maxChars = Math.max(3, Math.floor(cellW / (fontSize * 0.55)));\n const displayText = text.length > maxChars ? text.slice(0, maxChars - 1) + '…' : text;\n svg += `<text x=\"${x + cellW / 2}\" y=\"${y + cellH / 2}\" text-anchor=\"middle\" dominant-baseline=\"central\" font-size=\"${fontSize}\" font-family=\"${escapeXml(fontFamily)}\" font-weight=\"${fontWeight}\" fill=\"${textColor}\">${escapeXml(displayText)}</text>`;\n }\n }\n }\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"0 0 ${width} ${height}\">${svg}</svg>`;\n}\n\nexport const tableDefinition: SmartElementDefinition = {\n type: 'table',\n label: 'Table',\n icon: 'Table',\n defaultWidth: 400,\n defaultHeight: 200,\n properties: [\n { key: 'rows', label: 'Data Rows', type: 'number', default: 3, min: 1, max: 20, step: 1 },\n { key: 'cols', label: 'Columns', type: 'number', default: 3, min: 1, max: 10, step: 1 },\n {\n key: 'showHeader', label: 'Header Row', type: 'select', default: 'true',\n options: [{ value: 'true', label: 'Show' }, { value: 'false', label: 'Hide' }],\n },\n { key: 'headerValues', label: 'Header Labels', type: 'text', default: 'Name,Value,Status', bindable: true },\n { key: 'cellValues', label: 'Cell Data (comma-sep)', type: 'text', default: 'Item 1,100,Active,Item 2,200,Pending,Item 3,300,Done', bindable: true },\n { key: 'fontSize', label: 'Font Size', type: 'number', default: 12, min: 8, max: 24, step: 1 },\n { key: 'headerBg', label: 'Header Background', type: 'color', default: '#1a1a1a' },\n { key: 'headerText', label: 'Header Text', type: 'color', default: '#ffffff' },\n { key: 'cellBg', label: 'Cell Background', type: 'color', default: '#ffffff' },\n { key: 'cellText', label: 'Cell Text', type: 'color', default: '#1a1a1a' },\n { key: 'borderColor', label: 'Border Color', type: 'color', default: '#e5e7eb' },\n { key: 'borderWidth', label: 'Border Width', type: 'number', default: 1, min: 0, max: 4, step: 0.5 },\n ],\n render: (props, width, height) => {\n const normalizedProps = { ...props, showHeader: props.showHeader !== 'false' };\n return renderTableSvg(normalizedProps, width, height);\n },\n};\n","import type { SmartElementDefinition } from '../types';\nimport { escapeXml } from '../utils';\n\nfunction getInitials(name: string, maxChars: number): string {\n if (!name.trim()) return '?';\n const parts = name.trim().split(/\\s+/).filter(Boolean);\n if (parts.length === 1) return parts[0].slice(0, maxChars).toUpperCase();\n return parts.slice(0, maxChars).map(p => p[0]).join('').toUpperCase();\n}\n\nfunction renderAvatarSvg(props: Record<string, any>, width: number, height: number): string {\n const name = props.name || 'John Doe';\n const bgColor = props.bgColor || '#6366f1';\n const textColor = props.textColor || '#ffffff';\n const fontSize = props.fontSize ?? Math.min(width, height) * 0.38;\n const fontFamily = props.fontFamily || 'sans-serif';\n const shape = props.shape || 'circle';\n const maxInitials = props.maxInitials ?? 2;\n const borderColor = props.borderColor || 'transparent';\n const borderWidth = props.borderWidth ?? 0;\n\n const initials = getInitials(name, maxInitials);\n const cx = width / 2;\n const cy = height / 2;\n const r = Math.min(width, height) / 2 - borderWidth;\n\n let shapeSvg = '';\n if (shape === 'circle') {\n shapeSvg = `<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${r}\" fill=\"${bgColor}\" stroke=\"${borderColor}\" stroke-width=\"${borderWidth}\"/>`;\n } else {\n const inset = borderWidth / 2;\n const rx = shape === 'rounded' ? Math.min(width, height) * 0.15 : 0;\n shapeSvg = `<rect x=\"${inset}\" y=\"${inset}\" width=\"${width - borderWidth}\" height=\"${height - borderWidth}\" rx=\"${rx}\" fill=\"${bgColor}\" stroke=\"${borderColor}\" stroke-width=\"${borderWidth}\"/>`;\n }\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${width}\" height=\"${height}\" viewBox=\"0 0 ${width} ${height}\">\n ${shapeSvg}\n <text x=\"${cx}\" y=\"${cy}\" text-anchor=\"middle\" dominant-baseline=\"central\" font-size=\"${fontSize}\" font-family=\"${escapeXml(fontFamily)}\" font-weight=\"600\" fill=\"${textColor}\">${initials}</text>\n</svg>`;\n}\n\nexport const avatarDefinition: SmartElementDefinition = {\n type: 'avatar',\n label: 'Avatar',\n icon: 'UserCircle',\n defaultWidth: 80,\n defaultHeight: 80,\n properties: [\n { key: 'name', label: 'Name', type: 'text', default: 'John Doe', bindable: true },\n { key: 'maxInitials', label: 'Max Initials', type: 'number', default: 2, min: 1, max: 3, step: 1 },\n {\n key: 'shape', label: 'Shape', type: 'select', default: 'circle',\n options: [\n { value: 'circle', label: 'Circle' },\n { value: 'rounded', label: 'Rounded Square' },\n { value: 'square', label: 'Square' },\n ],\n },\n { key: 'bgColor', label: 'Background', type: 'color', default: '#6366f1' },\n { key: 'textColor', label: 'Text Color', type: 'color', default: '#ffffff' },\n { key: 'fontSize', label: 'Font Size', type: 'number', default: 30, min: 8, max: 100, step: 1 },\n { key: 'borderColor', label: 'Border Color', type: 'color', default: '#ffffff' },\n { key: 'borderWidth', label: 'Border Width', type: 'number', default: 0, min: 0, max: 10, step: 1 },\n ],\n render: renderAvatarSvg,\n};\n","import type { SmartElementDefinition } from '../types';\nimport { escapeXml, estimateTextWidth } from '../utils';\n\nexport interface BadgeRenderResult {\n svg: string;\n /** If overflow is 'grow', this is the computed ideal width */\n computedWidth?: number;\n /** Anchor mode — used by the caller to adjust x position */\n anchor?: 'left' | 'center' | 'right';\n}\n\nfunction renderBadgeInternal(\n props: Record<string, any>,\n width: number,\n height: number\n): BadgeRenderResult {\n const text = props.text || 'Badge';\n const bgColor = props.bgColor || '#6366f1';\n const textColor = props.textColor || '#ffffff';\n const borderRadius = props.borderRadius ?? Math.min(width, height) / 2;\n let fontSize = props.fontSize ?? Math.max(10, height * 0.45);\n const borderColor = props.borderColor || 'transparent';\n const borderWidth = props.borderWidth ?? 0;\n const fontWeight = props.fontWeight || '600';\n const fontFamily = props.fontFamily || 'sans-serif';\n const icon = props.icon || 'none';\n const overflow = props.overflow || 'grow';\n const anchor = props.anchor || 'center';\n\n const hPad = Math.max(12, height * 0.4);\n const iconSize = fontSize * 1.1;\n const iconGap = icon !== 'none' ? iconSize + 6 : 0;\n\n const textWidth = estimateTextWidth(text, fontSize, fontWeight);\n const contentWidth = iconGap + textWidth;\n const idealWidth = contentWidth + hPad * 2;\n\n let finalWidth = width;\n let displayText = text;\n let computedWidth: number | undefined;\n\n if (overflow === 'grow') {\n finalWidth = Math.max(width, Math.ceil(idealWidth));\n computedWidth = finalWidth;\n } else {\n finalWidth = width;\n const availableTextWidth = width - hPad * 2 - iconGap;\n while (fontSize > 6 && estimateTextWidth(text, fontSize, fontWeight) > availableTextWidth) {\n fontSize--;\n }\n if (estimateTextWidth(text, fontSize, fontWeight) > availableTextWidth) {\n const maxChars = Math.max(2, Math.floor(availableTextWidth / (fontSize * 0.55)));\n displayText = text.length > maxChars ? text.slice(0, maxChars - 1) + '…' : text;\n }\n }\n\n const rx = Math.min(borderRadius, Math.min(finalWidth, height) / 2);\n const inset = borderWidth / 2;\n\n let iconSvg = '';\n const iconX = hPad;\n const iconY = height / 2;\n const textX = icon !== 'none' ? hPad + iconGap + (finalWidth - hPad * 2 - iconGap) / 2 : finalWidth / 2;\n\n if (icon === 'dot') {\n const dotR = fontSize * 0.25;\n iconSvg = `<circle cx=\"${iconX + iconSize / 2}\" cy=\"${iconY}\" r=\"${dotR}\" fill=\"${textColor}\"/>`;\n } else if (icon === 'check') {\n const s = iconSize * 0.7;\n const ox = iconX + (iconSize - s) / 2;\n const oy = iconY - s / 2;\n iconSvg = `<polyline points=\"${ox + s * 0.15},${oy + s * 0.55} ${ox + s * 0.4},${oy + s * 0.8} ${ox + s * 0.85},${oy + s * 0.2}\" fill=\"none\" stroke=\"${textColor}\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>`;\n } else if (icon === 'x') {\n const s = iconSize * 0.55;\n const ox = iconX + (iconSize - s) / 2;\n const oy = iconY - s / 2;\n iconSvg = `<line x1=\"${ox}\" y1=\"${oy}\" x2=\"${ox + s}\" y2=\"${oy + s}\" stroke=\"${textColor}\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n <line x1=\"${ox + s}\" y1=\"${oy}\" x2=\"${ox}\" y2=\"${oy + s}\" stroke=\"${textColor}\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>`;\n }\n\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${finalWidth}\" height=\"${height}\" viewBox=\"0 0 ${finalWidth} ${height}\">\n <rect x=\"${inset}\" y=\"${inset}\" width=\"${finalWidth - borderWidth}\" height=\"${height - borderWidth}\" rx=\"${rx}\" fill=\"${bgColor}\" stroke=\"${borderColor}\" stroke-width=\"${borderWidth}\"/>\n ${iconSvg}\n <text x=\"${textX}\" y=\"${height / 2}\" text-anchor=\"middle\" dominant-baseline=\"central\" font-size=\"${fontSize}\" font-family=\"${escapeXml(fontFamily)}\" font-weight=\"${fontWeight}\" fill=\"${textColor}\">${escapeXml(displayText)}</text>\n</svg>`;\n\n return { svg, computedWidth, anchor };\n}\n\nfunction renderBadgeSvg(props: Record<string, any>, width: number, height: number): string {\n return renderBadgeInternal(props, width, height).svg;\n}\n\n/**\n * Render badge and return computed dimensions (used for auto-grow).\n */\nexport function renderBadgeWithSize(\n props: Record<string, any>,\n width: number,\n height: number\n): BadgeRenderResult {\n return renderBadgeInternal(props, width, height);\n}\n\nexport const badgeDefinition: SmartElementDefinition = {\n type: 'badge',\n label: 'Badge',\n icon: 'Tag',\n defaultWidth: 120,\n defaultHeight: 32,\n properties: [\n { key: 'text', label: 'Text', type: 'text', default: 'Badge', bindable: true },\n { key: 'bgColor', label: 'Background', type: 'color', default: '#6366f1' },\n { key: 'textColor', label: 'Text Color', type: 'color', default: '#ffffff' },\n { key: 'fontSize', label: 'Font Size', type: 'number', default: 14, min: 8, max: 36, step: 1 },\n {\n key: 'fontWeight', label: 'Font Weight', type: 'select', default: '600',\n options: [\n { value: '400', label: 'Normal' },\n { value: '600', label: 'Semi Bold' },\n { value: '700', label: 'Bold' },\n ],\n },\n { key: 'borderRadius', label: 'Border Radius', type: 'number', default: 16, min: 0, max: 50, step: 1 },\n {\n key: 'overflow', label: 'Overflow', type: 'select', default: 'grow',\n options: [\n { value: 'grow', label: 'Auto Grow' },\n { value: 'shrink', label: 'Auto Shrink' },\n ],\n },\n {\n key: 'anchor', label: 'Grow Anchor', type: 'select', default: 'center',\n options: [\n { value: 'left', label: 'Left (grow right)' },\n { value: 'center', label: 'Center (grow both)' },\n { value: 'right', label: 'Right (grow left)' },\n ],\n },\n {\n key: 'icon', label: 'Icon', type: 'select', default: 'none',\n options: [\n { value: 'none', label: 'None' },\n { value: 'dot', label: 'Dot' },\n { value: 'check', label: 'Checkmark' },\n { value: 'x', label: 'Cross' },\n ],\n },\n { key: 'borderColor', label: 'Border Color', type: 'color', default: '#4f46e5' },\n { key: 'borderWidth', label: 'Border Width', type: 'number', default: 0, min: 0, max: 4, step: 0.5 },\n ],\n render: renderBadgeSvg,\n};\n","/**\n * Smart Element Registry — Isomorphic, single source of truth.\n * Used by BOTH client (Vite/browser) and server (Node.js/EC2).\n */\n\nimport type { SmartElementDefinition, SmartElementType } from './types';\nimport { qrCodeDefinition } from './renderers/qrcode';\nimport { ratingDefinition } from './renderers/rating';\nimport { progressDefinition } from './renderers/progress';\nimport { tableDefinition } from './renderers/table';\nimport { avatarDefinition } from './renderers/avatar';\nimport { badgeDefinition } from './renderers/badge';\n\nconst registry = new Map<SmartElementType, SmartElementDefinition>();\n\nregistry.set('qrcode', qrCodeDefinition);\nregistry.set('rating', ratingDefinition);\nregistry.set('progress', progressDefinition);\nregistry.set('table', tableDefinition);\nregistry.set('avatar', avatarDefinition);\nregistry.set('badge', badgeDefinition);\n\n/** Get a smart element definition by type */\nexport function getSmartElementDef(type: SmartElementType): SmartElementDefinition | undefined {\n return registry.get(type);\n}\n\n/** Get all registered smart element definitions */\nexport function getAllSmartElements(): SmartElementDefinition[] {\n return Array.from(registry.values());\n}\n\n/** Register a new smart element type (for user-created elements) */\nexport function registerSmartElement(def: SmartElementDefinition) {\n registry.set(def.type, def);\n}\n\n/**\n * Render a smart element to SVG string.\n */\nexport function renderSmartElementToSvg(\n type: SmartElementType,\n props: Record<string, any>,\n width: number,\n height: number\n): string | null {\n const def = registry.get(type);\n if (!def) return null;\n return def.render(props, width, height);\n}\n\n/**\n * Render a smart element to data URI.\n */\nexport function renderSmartElementToDataUri(\n type: SmartElementType,\n props: Record<string, any>,\n width: number,\n height: number\n): string | null {\n const svg = renderSmartElementToSvg(type, props, width, height);\n if (!svg) return null;\n return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;\n}\n","/**\n * Image Edge Fade — bakes per-side feather into a raster image.\n *\n * Returns a new HTMLCanvasElement (or HTMLImageElement passthrough if no fade\n * is active) suitable for assignment via `fabricImage.setElement(canvas)`.\n *\n * Algorithm:\n * 1. Draw source onto an offscreen canvas at native resolution.\n * 2. For each side with size > 0, paint a linear gradient using\n * globalCompositeOperation = 'destination-in'. The gradient goes from\n * `amount` opacity at the edge to fully opaque (alpha 1) at the inner\n * end of the fade band. Combining 4 destination-in passes multiplies\n * alphas, so corners naturally blend.\n *\n * Pure function: doesn't mutate inputs.\n */\n\nexport interface EdgeFadeProps {\n fadeTopAmount?: number;\n fadeRightAmount?: number;\n fadeBottomAmount?: number;\n fadeLeftAmount?: number;\n fadeTopSize?: number;\n fadeRightSize?: number;\n fadeBottomSize?: number;\n fadeLeftSize?: number;\n fadeTopHardness?: number;\n fadeRightHardness?: number;\n fadeBottomHardness?: number;\n fadeLeftHardness?: number;\n}\n\nexport function hasEdgeFade(p: EdgeFadeProps | null | undefined): boolean {\n if (!p) return false;\n const sides: Array<[number | undefined, number | undefined]> = [\n [p.fadeTopSize, p.fadeTopAmount],\n [p.fadeRightSize, p.fadeRightAmount],\n [p.fadeBottomSize, p.fadeBottomAmount],\n [p.fadeLeftSize, p.fadeLeftAmount],\n ];\n for (const [size, amount] of sides) {\n const s = Number(size) || 0;\n const a = amount == null ? 1 : Number(amount);\n if (s > 0 && a < 1) return true;\n }\n return false;\n}\n\n/** Stable cache key so we can avoid re-baking on every render. */\nexport function edgeFadeKey(p: EdgeFadeProps | null | undefined): string {\n if (!hasEdgeFade(p)) return '';\n return [\n p?.fadeTopSize ?? 0, p?.fadeTopAmount ?? 1,\n p?.fadeRightSize ?? 0, p?.fadeRightAmount ?? 1,\n p?.fadeBottomSize ?? 0, p?.fadeBottomAmount ?? 1,\n p?.fadeLeftSize ?? 0, p?.fadeLeftAmount ?? 1,\n p?.fadeTopHardness ?? 1,\n p?.fadeRightHardness ?? 1,\n p?.fadeBottomHardness ?? 1,\n p?.fadeLeftHardness ?? 1,\n ].join('|');\n}\n\nfunction clamp01(n: number): number {\n if (!Number.isFinite(n)) return 0;\n return Math.max(0, Math.min(1, n));\n}\n\n/**\n * Bake fade into a fresh canvas. Source can be HTMLImageElement,\n * HTMLCanvasElement, or ImageBitmap.\n */\nexport function bakeEdgeFade(\n source: HTMLImageElement | HTMLCanvasElement | ImageBitmap,\n fade: EdgeFadeProps,\n): HTMLCanvasElement {\n const w = (source as any).naturalWidth || (source as any).width || 0;\n const h = (source as any).naturalHeight || (source as any).height || 0;\n const canvas = document.createElement('canvas');\n canvas.width = Math.max(1, w);\n canvas.height = Math.max(1, h);\n const ctx = canvas.getContext('2d');\n if (!ctx) return canvas;\n ctx.drawImage(source as CanvasImageSource, 0, 0, canvas.width, canvas.height);\n\n type Side = 'top' | 'right' | 'bottom' | 'left';\n const clampHardness = (n: number | undefined) => {\n const v = Number(n);\n if (!Number.isFinite(v) || v <= 0) return 1;\n return Math.max(0.1, Math.min(5, v));\n };\n const sides: Array<{ side: Side; size: number; amount: number; hardness: number }> = [\n { side: 'top', size: clamp01(fade.fadeTopSize ?? 0), amount: clamp01(fade.fadeTopAmount ?? 1), hardness: clampHardness(fade.fadeTopHardness) },\n { side: 'right', size: clamp01(fade.fadeRightSize ?? 0), amount: clamp01(fade.fadeRightAmount ?? 1), hardness: clampHardness(fade.fadeRightHardness) },\n { side: 'bottom', size: clamp01(fade.fadeBottomSize ?? 0), amount: clamp01(fade.fadeBottomAmount ?? 1), hardness: clampHardness(fade.fadeBottomHardness) },\n { side: 'left', size: clamp01(fade.fadeLeftSize ?? 0), amount: clamp01(fade.fadeLeftAmount ?? 1), hardness: clampHardness(fade.fadeLeftHardness) },\n ];\n\n for (const { side, size, amount, hardness } of sides) {\n if (size <= 0 || amount >= 1) continue;\n\n // Build full-canvas alpha mask: opaque black everywhere, gradient band painted on top.\n const mask = document.createElement('canvas');\n mask.width = canvas.width;\n mask.height = canvas.height;\n const mctx = mask.getContext('2d');\n if (!mctx) continue;\n mctx.fillStyle = '#000';\n mctx.fillRect(0, 0, mask.width, mask.height);\n\n let g: CanvasGradient;\n let x = 0, y = 0, rectW = mask.width, rectH = mask.height;\n // Non-linear falloff matches the in-builder preview (PageCanvas.edgeFadeDrawObject).\n // Hardness maps inversely to the gamma curve: 0.1 = very soft/long blend,\n // 1 = linear, >1 = harder/punchier edge.\n const STOPS = 64;\n const gamma = 1 / hardness;\n const innerAlpha = (t: number) => {\n // alpha used to KEEP the pixel: at edge -> (1 - amount), at inner end -> 1\n const keepProgress = Math.pow(t, gamma);\n const erase = (1 - amount) * (1 - keepProgress);\n return 1 - erase;\n };\n const fillStops = (grad: CanvasGradient, reverse: boolean) => {\n for (let i = 0; i <= STOPS; i++) {\n const t = i / STOPS;\n const a = innerAlpha(reverse ? 1 - t : t);\n grad.addColorStop(t, `rgba(0,0,0,${a})`);\n }\n };\n if (side === 'top') {\n const band = Math.max(1, Math.round(mask.height * size));\n g = mctx.createLinearGradient(0, 0, 0, band);\n fillStops(g, false);\n rectH = band;\n } else if (side === 'bottom') {\n const band = Math.max(1, Math.round(mask.height * size));\n y = mask.height - band;\n g = mctx.createLinearGradient(0, mask.height, 0, y);\n fillStops(g, false);\n rectH = band;\n } else if (side === 'left') {\n const band = Math.max(1, Math.round(mask.width * size));\n g = mctx.createLinearGradient(0, 0, band, 0);\n fillStops(g, false);\n rectW = band;\n } else {\n const band = Math.max(1, Math.round(mask.width * size));\n x = mask.width - band;\n g = mctx.createLinearGradient(mask.width, 0, x, 0);\n fillStops(g, false);\n rectW = band;\n }\n mctx.fillStyle = g;\n mctx.fillRect(x, y, rectW, rectH);\n\n // Apply mask to the main canvas via destination-in (multiplies alpha).\n ctx.globalCompositeOperation = 'destination-in';\n ctx.drawImage(mask, 0, 0);\n ctx.globalCompositeOperation = 'source-over';\n }\n\n return canvas;\n}\n","import { useEffect, useRef, useCallback, useState, forwardRef, useImperativeHandle, useMemo } from 'react';\nimport { flushSync } from 'react-dom';\nimport { toast } from 'sonner';\nimport { useEditorStore, setEditingText } from '@/store/editorStore';\nimport { CanvasElement, PageSettings, ProjectSettings, createDefaultElement, findParentGroup, findNodeById, getAllElementIds, isElement, CanvasNode, GroupNode, isGroup, updateNodeInTree, findCommonAncestorGroup, isStackLayoutMode, isGradientConfig } from '@/types/editor';\nimport { registerFabricCanvas, unregisterFabricCanvas, setActivePageCanvas } from '@/store/fabricCanvasRegistry';\nimport { preloadAllFonts, clearFontCacheAndRerender, clearFabricCharCache, setupFontLoadingListener, ensureFontLoaded, waitForFontsReady, waitUntilFontsAvailable } from '@/lib/fontLoader';\nimport { createMaskedImageElement, updateCoverLayout, installCanvaMaskControls, setSimpleScaleControls, panImageInside, getLocalDeltaStable, applyControlSizeForZoom } from '@/lib/canvaMaskedImage';\nimport { enterCropMode, exitCropMode, isCropGroupInCropMode } from '@/lib/imageCropMode';\nimport { getObjectId, getFabricGroupId, setObjectData, setFabricGroupId } from '@/lib/fabricUtils';\nimport { calculateSnapGuides, calculateScaleSnapGuides, applyScaleSnapToBox, SnapGuide, type ActiveSnapState } from '@/lib/snapGuides';\nimport { createFabricObject, createFabricObjectForGroupMember, createShape, createText, createLine, buildRoundedRectPath } from '@/lib/fabricObjectCreators';\nimport { buildRoundedTrianglePath, TRIANGLE_STROKE_MITER_LIMIT } from '@/lib/shapeGeometry';\nimport { applyTriangleCacheSettings } from '@/lib/triangleCache';\nimport { createImagePlaceholder, createImagePlaceholderForGroup, getProxiedImageUrl, createImageClipPath, normalizeSvgImageDimensions, isSvgImage, getNormalizedSvgUrl, isEmptyImagePlaceholderGroup, updateEmptyPlaceholderLayout } from '@/lib/canvasImageLoader';\nimport { renderSmartElementToDataUri } from '@/lib/smartElements';\nimport { getNodeBounds, getNodeBoundsFromChildren, getAbsoluteBounds, absoluteToStorePosition, getEffectiveGroupDisplay, getGroupContentBox, reflowPageFromRoot, reflowFromGroup, setDragBoundsOverride, clearDragBoundsOverride, computeGroupResizeLayoutKey, getGroupLayoutSnapTargets, computeDiscreteGridSnappedBox, getDiscreteGridSnapGuides, getOrderedFlexOrGridChildren, isGridGroupForResize, type BoundsOptions } from '@/lib/layoutEngine';\nimport { getMinTextWidth, clearMeasurementCache, getTextboxWidthFitMetrics } from '@/lib/textMeasurement';\nimport { applyTextBackground, extractTextBgConfig, buildTextShadow } from '@/lib/textBackgroundRenderer';\nimport { hasEdgeFade, bakeEdgeFade, edgeFadeKey } from '@/lib/imageEdgeFade';\nimport { flattenChildren } from '@/types/editor';\nimport * as fabric from 'fabric';\nimport { stripTextMarkdown, setMarkdownThemeColors, parseTextMarkdown } from '@/lib/textMarkdown';\nimport { gradientToFabric } from '@/lib/gradientUtils';\n\n/** Compute new left/top/width/height from Fabric transform (original + scale + corner). Use this instead of getBoundingRect(true) so left/top handles shrink correctly. */\nfunction computeBoxFromTransform(\n target: fabric.FabricObject,\n transform: { corner: string; original: { left?: number; top?: number }; width?: number; height?: number },\n opts: { minW?: number; minH?: number } = {}\n): { left: number; top: number; width: number; height: number } {\n const minW = opts.minW ?? 20;\n const minH = opts.minH ?? 20;\n const corner = transform.corner;\n const orig = transform.original;\n const sx = Math.abs((target as any).scaleX ?? 1);\n const sy = Math.abs((target as any).scaleY ?? 1);\n const origW = transform.width ?? (target as any).width ?? 0;\n const origH = transform.height ?? (target as any).height ?? 0;\n let newW = Math.max(minW, origW * sx);\n let newH = Math.max(minH, origH * sy);\n const isLeftHandle = corner === 'ml' || corner === 'tl' || corner === 'bl';\n const isTopHandle = corner === 'mt' || corner === 'tl' || corner === 'tr';\n const isWidthOnly = corner === 'ml' || corner === 'mr';\n const isHeightOnly = corner === 'mt' || corner === 'mb';\n if (isWidthOnly) newH = origH;\n if (isHeightOnly) newW = origW;\n let left = orig?.left ?? (target as any).left ?? 0;\n let top = orig?.top ?? (target as any).top ?? 0;\n if (isLeftHandle) left = left + (origW - newW);\n if (isTopHandle) top = top + (origH - newH);\n return { left, top, width: newW, height: newH };\n}\n\n\n// ============================================\n// COMPONENT\n// ============================================\nexport interface ElementBounds {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport interface PageCanvasRef {\n fabricCanvas: fabric.Canvas | null;\n discardActiveObject: () => void;\n /** Enter text editing on the given element (or active object if single Textbox). Optionally insert a character (e.g. first keypress). Returns true if editing was started. */\n enterTextEditing: (elementId?: string, charToInsert?: string) => boolean;\n /** Get the actual rendered bounds of an element by ID */\n getElementBounds: (elementId: string) => ElementBounds | null;\n /** Get bounds for all elements */\n getAllElementBounds: () => Map<string, ElementBounds>;\n}\n\nexport type CanvasMode = 'editor' | 'preview' | 'export';\n\ninterface PageCanvasProps {\n pageId: string;\n elements: CanvasElement[];\n pageSettings: PageSettings;\n projectSettings: ProjectSettings;\n canvasWidth: number;\n canvasHeight: number;\n isActive: boolean;\n workspaceZoom: number;\n selectedIds: string[];\n activeTool: string;\n onDragStart?: (elements: CanvasElement[], mouseEvent: MouseEvent, pageId: string) => void;\n onDragEnd?: () => void;\n onActivate?: () => void;\n // New props for unified canvas\n mode?: CanvasMode;\n dynamicFieldIds?: string[]; // Element IDs that are bound to dynamic fields\n onDynamicFieldClick?: (elementId: string) => void; // Callback when clicking a dynamic field element\n /** Bumped by store on updateNode/updateElement so sync runs when panel changes something */\n canvasUpdateVersion?: number;\n /** Top-level page children (tree); when provided, positions sync using absolute bounds (div-like relative positioning) */\n pageChildren?: CanvasNode[];\n /** Allow preview/export callers to render before font readiness settles */\n skipFontReadyWait?: boolean;\n /** Export-only: don't clear Fabric's process-global font caches while a visible preview may be mounted. */\n preserveGlobalFontCache?: boolean;\n /** Called once when fonts are loaded and canvas is ready (editor only). Use to reflow with correct text dimensions. */\n onReady?: () => void;\n}\n\nexport const PageCanvas = forwardRef<PageCanvasRef, PageCanvasProps>(\n (\n {\n pageId,\n elements,\n pageSettings,\n projectSettings,\n canvasWidth,\n canvasHeight,\n isActive,\n workspaceZoom,\n selectedIds,\n activeTool,\n onDragStart,\n onDragEnd,\n onActivate,\n mode = 'editor',\n dynamicFieldIds = [],\n onDynamicFieldClick,\n canvasUpdateVersion = 0,\n pageChildren,\n skipFontReadyWait = false,\n preserveGlobalFontCache = false,\n onReady,\n },\n ref\n ) => {\n setMarkdownThemeColors({\n primary: projectSettings.primaryColor || '#7c3aed',\n secondary: projectSettings.secondaryColor || '#ffe066',\n });\n // Determine interaction capabilities based on mode\n const isEditorMode = mode === 'editor';\n const isPreviewMode = mode === 'preview';\n const isExportMode = mode === 'export';\n const allowEditing = isEditorMode;\n const allowSelection = isEditorMode;\n const allowDynamicFieldClick = isPreviewMode && dynamicFieldIds.length > 0;\n const canvasElRef = useRef<HTMLCanvasElement>(null);\n const fabricRef = useRef<fabric.Canvas | null>(null);\n const elementsRef = useRef<CanvasElement[]>(elements);\n const selectedIdsRef = useRef<string[]>(selectedIds);\n const isActiveRef = useRef(isActive);\n const isRebuildingRef = useRef(false);\n const transformingIdsRef = useRef<Set<string>>(new Set());\n const justModifiedIdsRef = useRef<Set<string>>(new Set()); // IDs that were just modified, skip next sync\n const previousVisibilityRef = useRef<Map<string, boolean>>(new Map()); // Track previous visibility state\n const isSyncingSelectionToFabricRef = useRef(false); // Prevent feedback loop when syncing selection\n const editingTextIdRef = useRef<string | null>(null); // ID of element currently being text-edited\n const syncLockedRef = useRef(false); // Global sync lock to prevent store→canvas writes during transform\n const editLockRef = useRef(false); // Edit lock to prevent selection clearing during/after transforms\n const editLockCountRef = useRef(0); // Counter to track lock generations\n const didTransformRef = useRef(false); // Track if a transform happened during this pointer session\n const pendingSyncRef = useRef(false); // Track if sync was deferred due to lock\n const doSyncRef = useRef<(() => void) | null>(null); // Store sync function to run later\n const visibilityUpdateInProgressRef = useRef(false); // Flag to prevent layout recalculation during visibility updates\n const prevCanvasUpdateVersionRef = useRef(canvasUpdateVersion); // Detect panel-driven updates so we apply left/top\n const syncTriggeredByPanelRef = useRef(false); // When true: discard selection before applying updates so positions apply to loose objects (no shift)\n const hasRunPostReadyReflowForPageRef = useRef<string | null>(null);\n const hasNotifiedReadyForPageRef = useRef<string | null>(null);\n const hasClearedCachesBeforeFirstSyncRef = useRef(false); // clear Fabric/measurement caches once right before first sync (fresh metrics)\n\n const [guides, setGuides] = useState<SnapGuide[]>([]);\n const [gridResizeLabel, setGridResizeLabel] = useState<{ cols: number; rows: number; x: number; y: number } | null>(null);\n const [ready, setReady] = useState(false);\n // Increment to request unlock+sync from effect (avoids calling doSync in setTimeout which can trigger \"Maximum update depth\" via panels setRef)\n const [unlockRequestId, setUnlockRequestId] = useState(0);\n\n /** Pass to getNodeBounds/getGroupContentBox so root groups with width/height 'inherit' resolve to page size. */\n const pageBoundsOptions: BoundsOptions = useMemo(\n () => ({ pageContentWidth: canvasWidth, pageContentHeight: canvasHeight }),\n [canvasWidth, canvasHeight]\n );\n\n // Group bounds overlay: resize state and wrapper ref for client→canvas conversion\n const groupOverlayWrapperRef = useRef<HTMLDivElement>(null);\n const [groupResizeState, setGroupResizeState] = useState<{\n groupId: string;\n handle: 'e' | 's' | 'se';\n startBounds: { left: number; top: number; width: number; height: number };\n startClientX: number;\n startClientY: number;\n } | null>(null);\n // Live bounds during group drag so the overlay moves with the group (not only after release)\n const [groupOverlayLiveBounds, setGroupOverlayLiveBounds] = useState<{ left: number; top: number; width: number; height: number } | null>(null);\n const setGroupOverlayLiveBoundsRef = useRef(setGroupOverlayLiveBounds);\n const skipSelectionClearOnDiscardRef = useRef(false);\n // Prevent stale async image reloads (e.g. rapid SVG recolor changes) from inserting duplicate objects\n const imageReloadRequestSeqRef = useRef<Map<string, number>>(new Map());\n const containerResizeRafRef = useRef<number | null>(null);\n const groupBoundsResizingRef = useRef(false);\n /** Latest group bounds during drag; no store write until mouseup (avoids lag). */\n const lastGroupBoundsBoxRef = useRef<{ groupId: string; left: number; top: number; width: number; height: number } | null>(null);\n /** Group we've already frozen for wrap resize (freeze once per drag, not every event). */\n const wrapResizeFrozenGroupIdRef = useRef<string | null>(null);\n /** Cached node + transformMode for current resize group (avoid store read every pointer move). */\n const wrapResizeNodeRef = useRef<GroupNode | null>(null);\n const wrapResizeTransformModeRef = useRef<boolean>(false);\n /** Throttle guide updates during group resize to once per frame (reduces setState jitter). */\n const groupBoundsGuidesRafRef = useRef<number | null>(null);\n /** Last layout key during wrap resize; reflow only when this changes (cols / width bucket). */\n const lastGroupResizeLayoutKeyRef = useRef<string | null>(null);\n /** Last applied box per child during conditional reflow (diff to avoid redundant Fabric updates). */\n const lastGroupResizeAppliedRef = useRef<Map<string, { left: number; top: number; width: number; height: number }>>(new Map());\n /** Sticky snap state during group resize; cleared on mouseup to avoid ping-pong. */\n const groupResizeActiveSnapRef = useRef<ActiveSnapState>(null);\n /** Discrete grid: current column/row count during resize (midpoint hysteresis); cleared on mouseup. */\n const lastDiscreteGridColsRef = useRef<number | null>(null);\n const lastDiscreteGridRowsRef = useRef<number | null>(null);\n /** Discrete grid: box at drag start for anchoring the fixed edge; cleared on mouseup. */\n const discreteGridDragStartBoxRef = useRef<{ left: number; top: number; width: number; height: number } | null>(null);\n /** Discrete grid: fixed row height during drag (avoids jitter from text wrap); cleared on mouseup. */\n const lastDiscreteGridCellHRef = useRef<number | null>(null);\n /** Last dimensions synced during text edit (for live reflow throttle). */\n const lastTextEditDimensionsRef = useRef<{ id: string; w: number; h: number } | null>(null);\n /** Target of the current resize/scale gesture; used to detect child resize inside section group (object:modified often reports group as target). */\n const lastResizeScaleTargetRef = useRef<fabric.FabricObject | null>(null);\n setGroupOverlayLiveBoundsRef.current = setGroupOverlayLiveBounds;\n\n const {\n selectElements,\n clearSelection,\n addElement,\n updateNode,\n commitHistory,\n setActiveTool,\n showSections,\n canvas,\n hoveredGroupId,\n } = useEditorStore();\n const storeSelectedIds = canvas.selectedIds ?? [];\n\n // Current page tree (for selected group overlay)\n const currentPage = useMemo(() => (canvas.pages ?? []).find((p) => p.id === pageId), [canvas.pages, pageId]);\n\n // When exactly one group (or empty group) is selected, show its bounds + overlay resize. Never expand to children — selection is only the bounds rect.\n const selectedGroup = useMemo((): GroupNode | null => {\n const ids = storeSelectedIds ?? [];\n const children = currentPage?.children ?? [];\n if (!currentPage || ids.length === 0) return null;\n for (const id of ids) {\n const node = findNodeById(children, id);\n if (node && isGroup(node)) return node as GroupNode;\n }\n const firstId = ids[0];\n const parent = findParentGroup(children, firstId);\n if (!parent) return null;\n const memberIds = new Set(getAllElementIds(parent.children ?? []));\n const allSelectedAreInGroup = ids.every((id) => memberIds.has(id) || id === parent.id);\n return allSelectedAreInGroup ? parent : null;\n }, [currentPage, storeSelectedIds]);\n\n // Keep refs up to date\n useEffect(() => {\n elementsRef.current = elements;\n }, [elements]);\n\n useEffect(() => {\n selectedIdsRef.current = selectedIds;\n }, [selectedIds]);\n\n useEffect(() => {\n isActiveRef.current = isActive;\n if (isEditorMode && isActive && fabricRef.current) {\n setActivePageCanvas(pageId);\n }\n }, [isActive, isEditorMode, pageId]);\n\n // Helper to get object ID\n const getObjId = useCallback((obj: fabric.FabricObject): string | undefined => {\n return (obj as any).__docuforgeId;\n }, []);\n\n // Expose Fabric canvas through ref\n // IMPORTANT: Empty dependency array to prevent ref object identity changes\n // which can cause infinite loops with inline ref callbacks\n useImperativeHandle(ref, () => ({\n fabricCanvas: fabricRef.current,\n discardActiveObject: () => {\n if (fabricRef.current) {\n // CRITICAL: Don't discard if edits are locked (during handle drag)\n if (editLockRef.current) {\n return; // Do nothing during transform\n }\n fabricRef.current.discardActiveObject();\n fabricRef.current.requestRenderAll();\n }\n },\n enterTextEditing: (elementId?: string, charToInsert?: string): boolean => {\n const fc = fabricRef.current;\n if (!fc || !allowEditing) return false;\n let textbox: fabric.Textbox | null = null;\n if (elementId) {\n const obj = fc.getObjects().find((o) => getObjectId(o) === elementId);\n if (obj instanceof fabric.Textbox) textbox = obj;\n } else {\n const active = fc.getActiveObject();\n if (active instanceof fabric.Textbox) textbox = active;\n else if (active instanceof fabric.ActiveSelection && active.getObjects().length === 1 && active.getObjects()[0] instanceof fabric.Textbox) textbox = active.getObjects()[0] as fabric.Textbox;\n }\n if (!textbox) return false;\n const id = getObjectId(textbox);\n if (id) editingTextIdRef.current = id;\n textbox.enterEditing();\n if (charToInsert != null && charToInsert.length > 0) {\n const iText = textbox as fabric.IText;\n const start = iText.selectionStart ?? (iText.text?.length ?? 0);\n iText.insertChars(charToInsert, undefined, start);\n }\n fc.requestRenderAll();\n return true;\n },\n getElementBounds: (elementId: string): ElementBounds | null => {\n const canvas = fabricRef.current;\n if (!canvas) return null;\n \n const obj = canvas.getObjects().find(o => getObjId(o) === elementId);\n if (!obj) return null;\n \n // Use object properties directly (in canvas coordinate space, not viewport)\n // For textboxes, width/height reflect actual rendered dimensions after initDimensions()\n const width = (obj.width ?? 0) * (obj.scaleX ?? 1);\n const height = (obj.height ?? 0) * (obj.scaleY ?? 1);\n \n // CRITICAL: Account for origin point (center vs top-left)\n // For crop groups with originX: 'center', left/top represent the center\n let left = obj.left ?? 0;\n let top = obj.top ?? 0;\n \n if (obj instanceof fabric.Group && (obj as any).__cropGroup) {\n // Crop groups use center origin, so convert to top-left\n left = left - width / 2;\n top = top - height / 2;\n } else if (obj.originX === 'center' || obj.originY === 'center') {\n // For any center-origin object, convert to top-left\n const offsetX = obj.originX === 'center' ? width / 2 : 0;\n const offsetY = obj.originY === 'center' ? height / 2 : 0;\n left = left - offsetX;\n top = top - offsetY;\n }\n \n return { left, top, width, height };\n },\n getAllElementBounds: (): Map<string, ElementBounds> => {\n const canvas = fabricRef.current;\n const result = new Map<string, ElementBounds>();\n if (!canvas) return result;\n \n canvas.getObjects().forEach(obj => {\n const id = getObjId(obj);\n if (id && id !== '__background__') {\n // Use object properties directly (in canvas coordinate space, not viewport)\n const width = (obj.width ?? 0) * (obj.scaleX ?? 1);\n const height = (obj.height ?? 0) * (obj.scaleY ?? 1);\n \n // CRITICAL: Account for origin point (center vs top-left)\n // For crop groups with originX: 'center', left/top represent the center\n let left = obj.left ?? 0;\n let top = obj.top ?? 0;\n \n if (obj instanceof fabric.Group && (obj as any).__cropGroup) {\n // Crop groups use center origin, so convert to top-left\n left = left - width / 2;\n top = top - height / 2;\n } else if (obj.originX === 'center' || obj.originY === 'center') {\n // For any center-origin object, convert to top-left\n const offsetX = obj.originX === 'center' ? width / 2 : 0;\n const offsetY = obj.originY === 'center' ? height / 2 : 0;\n left = left - offsetX;\n top = top - offsetY;\n }\n \n result.set(id, { left, top, width, height });\n }\n });\n \n return result;\n },\n }), [getObjId]);\n\n // === SNAP GUIDES ===\n const calculateSnapGuidesCallback = useCallback(\n (movingObj: fabric.FabricObject): { guides: SnapGuide[]; snapDx: number; snapDy: number } => {\n const fabricCanvas = fabricRef.current;\n if (!fabricCanvas) return { guides: [], snapDx: 0, snapDy: 0 };\n return calculateSnapGuides(\n movingObj,\n fabricCanvas,\n canvasWidth,\n canvasHeight,\n projectSettings.snapToGuides,\n projectSettings.snapThreshold\n );\n },\n [canvasWidth, canvasHeight, projectSettings.snapToGuides, projectSettings.snapThreshold]\n );\n\n // === SNAP GUIDES FOR SCALING ===\n const calculateScaleSnapGuidesCallback = useCallback(\n (scalingObj: fabric.FabricObject, corner: string): SnapGuide[] => {\n const fabricCanvas = fabricRef.current;\n if (!fabricCanvas) return [];\n return calculateScaleSnapGuides(\n scalingObj,\n corner,\n fabricCanvas,\n canvasWidth,\n canvasHeight,\n projectSettings.snapToGuides,\n projectSettings.snapThreshold\n );\n },\n [canvasWidth, canvasHeight, projectSettings.snapToGuides, projectSettings.snapThreshold]\n );\n\n // Helper to check if we're currently transforming (must be accessible to all useEffects)\n const isTransforming = useCallback((canvas: fabric.Canvas | null) => {\n if (!canvas) return false;\n return !!(canvas as any)._currentTransform || !!(canvas as any).__isUserTransforming;\n }, []);\n\n const reflowTextboxesFromCurrentElements = useCallback((canvas: fabric.Canvas) => {\n const elementById = new Map(elementsRef.current.map((el) => [el.id, el]));\n let didReflow = false;\n const reflowObject = (obj: fabric.FabricObject) => {\n if (obj instanceof fabric.Group) {\n ((obj as any)._objects as fabric.FabricObject[] | undefined)?.forEach(reflowObject);\n obj.dirty = true;\n return;\n }\n if (!(obj instanceof fabric.Textbox)) return;\n const id = getObjectId(obj);\n const element = id ? elementById.get(id) : undefined;\n if (!element) return;\n // GLITCH FIX: never reset font/dimensions on auto-shrink text from the\n // font-loading listener. `createText`'s shrink loop already chose a\n // fontSize that fits the box; re-applying `element.fontSize` here\n // (the ORIGINAL pre-shrink size) and re-running `initDimensions`\n // makes the textbox reflow to its natural (grow-and-push) height.\n // This was the source of the on-screen glitch when the use-page PDF\n // export mounted hidden PreviewCanvas pages — those mounts call\n // `ensureFontLoaded`, which triggers `document.fonts.loadingdone` on\n // the whole document, and the live preview's listener then ran this\n // reflow against the visible canvas. Just mark the textbox dirty so\n // it repaints with current metrics; no field reset.\n if ((element as CanvasElement).overflowPolicy === 'auto-shrink') {\n // FIX: when fonts load late, the original `createText` shrink loop\n // measured against fallback font metrics and may have settled on\n // the un-shrunk fontSize (single line). Re-run the shrink loop now\n // that the real font is available and apply the corrected\n // fontSize so the textbox wraps to multiple lines on first paint.\n try {\n const measured = createText(element as CanvasElement) as fabric.Textbox;\n const newFontSize = (measured as any).fontSize;\n const newWidth = (measured as any).width;\n const currentFontSize = (obj as any).fontSize;\n if (typeof newFontSize === 'number' && newFontSize > 0 && newFontSize !== currentFontSize) {\n obj.set({ fontSize: newFontSize });\n if (typeof newWidth === 'number' && newWidth > 0) {\n (obj as any).width = newWidth;\n }\n obj.initDimensions();\n obj.setCoords();\n didReflow = true;\n }\n } catch {}\n obj.dirty = true;\n try {\n (obj as any)._forceClearCache = true;\n if (typeof (obj as any)._clearCache === 'function') (obj as any)._clearCache();\n } catch {}\n return;\n }\n const targetWidth = Math.max(1, Number(element.width) > 0 ? Number(element.width) : Number(obj.width ?? 200));\n const overflowPolicy = element.overflowPolicy || 'grow-and-push';\n const splitByGrapheme = overflowPolicy === 'auto-shrink'\n ? false\n : (element.splitByGrapheme ?? (element.wordWrap === 'break-word'));\n\n let reflowText = element.text || 'Text';\n let reflowParsedStyles: Record<number, Record<number, any>> | null = null;\n if (element.formattingEnabled === true) {\n const parsed = parseTextMarkdown(reflowText);\n reflowText = parsed.plainText || ' ';\n reflowParsedStyles = parsed.styles;\n }\n\n obj.set({\n width: targetWidth,\n minWidth: 1,\n dynamicMinWidth: 0,\n text: reflowText,\n fontSize: element.fontSize || 16,\n fontFamily: element.fontFamily || 'Open Sans',\n fontWeight: (element.fontWeight as number) || 400,\n fontStyle: element.fontStyle || 'normal',\n lineHeight: element.lineHeight || 1.2,\n charSpacing: element.charSpacing || 0,\n splitByGrapheme,\n });\n if (element.formattingEnabled === true) {\n (obj as any).styles = reflowParsedStyles || {};\n }\n // Keep canvas inline-edit state in sync with formattingEnabled so\n // toggling the flag at runtime also flips dblclick/keyboard editing.\n (obj as any).editable = element.formattingEnabled !== true;\n (obj as any).__formattingEnabled = element.formattingEnabled === true;\n obj.initDimensions();\n if (Math.abs((obj.width ?? 0) - targetWidth) > 0.01) {\n (obj as any).width = targetWidth;\n }\n (obj as any).dynamicMinWidth = 0;\n obj.setCoords();\n obj.dirty = true;\n // Force fabric to discard any cached text bitmap so per-character\n // markdown styles (bold/italic/underline/color) actually paint on\n // the next render. Without this, the textbox appears as plain text\n // on first mount and only \"wakes up\" after the user selects it.\n try {\n (obj as any)._forceClearCache = true;\n if (typeof (obj as any)._clearCache === 'function') (obj as any)._clearCache();\n } catch {}\n didReflow = true;\n };\n\n canvas.getObjects().forEach(reflowObject);\n if (didReflow) {\n canvas.requestRenderAll();\n // Second render on next frame — fabric occasionally swallows the\n // first paint when fonts/styles are settling, leaving the textbox\n // showing plain text until the user interacts.\n try {\n requestAnimationFrame(() => {\n try { canvas.requestRenderAll(); } catch {}\n });\n } catch {}\n }\n }, []);\n\n // === INIT FABRIC CANVAS ===\n useEffect(() => {\n if (!canvasElRef.current) return;\n\n const zoom = workspaceZoom || 1;\n const scaledWidth = canvasWidth * zoom;\n const scaledHeight = canvasHeight * zoom;\n\n const fabricCanvas = new fabric.Canvas(canvasElRef.current, {\n // Start with zoomed dimensions immediately\n width: scaledWidth,\n height: scaledHeight,\n selection: allowSelection,\n preserveObjectStacking: true,\n renderOnAddRemove: false,\n // In preview/export mode, disable all interactions\n interactive: isEditorMode || isPreviewMode,\n enableRetinaScaling: true,\n // Turn OFF sub-targeting at the canvas level (this is the big hammer)\n subTargetCheck: false,\n // Ensure canvas is not doing \"per-pixel\" target find (it makes images win hits)\n perPixelTargetFind: false,\n targetFindTolerance: 20, // Increased to help picking controls/edges (especially corners)\n // Ensure controls are above overlay for better hit-testing\n controlsAboveOverlay: true,\n // Transparent so underlay (page bg + group bgs) shows through\n backgroundColor: 'transparent',\n });\n \n // CRITICAL: In preview mode, disable selection entirely to prevent selection borders\n if (!allowSelection) {\n fabricCanvas.selection = false;\n // Also prevent any objects from being selected\n fabricCanvas.on('selection:created', () => {\n fabricCanvas.discardActiveObject();\n });\n fabricCanvas.on('selection:updated', () => {\n fabricCanvas.discardActiveObject();\n });\n }\n\n // Apply viewport transform immediately during init\n fabricCanvas.setViewportTransform([zoom, 0, 0, zoom, 0, 0]);\n \n // Store editLockRef on canvas for access from control handlers\n (fabricCanvas as any).__editLockRef = editLockRef;\n\n // Page background is drawn in the HTML underlay; section group backgrounds are drawn via fabric.Group _renderBackground (no separate rect)\n\n // Clip to bounds (original dimensions)\n fabricCanvas.clipPath = new fabric.Rect({\n left: 0,\n top: 0,\n width: canvasWidth,\n height: canvasHeight,\n absolutePositioned: true,\n });\n\n fabricRef.current = fabricCanvas;\n const storeRegistryKey = registerFabricCanvas(pageId, fabricCanvas);\n (fabricCanvas as any).__storeRegistryKey = storeRegistryKey;\n // Don't setReady yet — wait for fonts so first sync creates/updates text with correct metrics (fixes text overflow on load)\n\n // === FONT LOADING: strict sequence — no sync until fonts are ready (no delays, standard rAF) ===\n // In preview mode we get fonts from the elements prop (Templates/Use page); in editor mode from the store\n const initFonts = async () => {\n try {\n await preloadAllFonts();\n let fontFamilies: string[] = [];\n if (isPreviewMode && elements.length > 0) {\n fontFamilies = [...new Set(\n elements\n .filter((el): el is CanvasElement => isElement(el) && el.type === 'text')\n .map((el) => (el as CanvasElement).fontFamily)\n .filter(Boolean)\n )] as string[];\n await Promise.all(fontFamilies.map((f) => ensureFontLoaded(f)));\n } else {\n const state = useEditorStore.getState();\n const page = state.canvas.pages.find((p) => p.id === pageId);\n if (page) {\n const pageElements = flattenChildren(page.children);\n fontFamilies = [...new Set(\n pageElements\n .filter((el): el is CanvasElement => isElement(el) && el.type === 'text')\n .map((el) => (el as CanvasElement).fontFamily)\n .filter(Boolean)\n )] as string[];\n await Promise.all(fontFamilies.map((f) => ensureFontLoaded(f)));\n }\n }\n if (!skipFontReadyWait) {\n await waitForFontsReady();\n await waitUntilFontsAvailable(fontFamilies, { timeoutMs: 3500, pollIntervalMs: 60 });\n await new Promise<void>((r) => requestAnimationFrame(() => r()));\n }\n if (!preserveGlobalFontCache) clearFabricCharCache();\n clearMeasurementCache();\n setReady(true);\n } catch (e) {\n setReady(true);\n }\n };\n initFonts();\n\n // Setup font loading listener to catch late-loading fonts; persist text width/height so text doesn't overflow on save/reload\n const persistTextDimensionsAfterFontLoad = (canvas: fabric.Canvas) => {\n reflowTextboxesFromCurrentElements(canvas);\n if (isPreviewMode) return;\n const state = useEditorStore.getState();\n const page = state.canvas.pages.find((p) => p.id === pageId);\n if (!page) return;\n const elements = flattenChildren(page.children);\n canvas.getObjects().forEach((obj) => {\n if (obj instanceof fabric.Textbox) {\n const id = getObjectId(obj);\n if (!id) return;\n const w = obj.width ?? 0;\n const h = obj.height ?? 0;\n const el = elements.find((e) => e.id === id);\n if (!el) return;\n const storeW = (el as CanvasElement).width ?? 0;\n const storeH = (el as CanvasElement).height ?? 0;\n const updates: Partial<CanvasElement> = {};\n const shouldKeepFixedHeight = (el as CanvasElement).overflowPolicy === 'auto-shrink';\n // Don't overwrite width when user chose 'inherit' or 'auto'\n if (!shouldKeepFixedHeight && w > 0 && typeof storeW === 'number' && Math.abs(w - storeW) > 0.1) updates.width = w;\n // Auto-shrink: allow height to SHRINK (for stack reflow) but never grow\n if (shouldKeepFixedHeight) {\n if (h > 0 && typeof storeH === 'number' && h < storeH - 0.5) updates.height = h;\n } else {\n if (h > 0 && (typeof storeH !== 'number' || Math.abs(h - storeH) > 0.1)) updates.height = h;\n }\n if (Object.keys(updates).length > 0) {\n state.updateElement(id, updates, { recordHistory: false, skipLayoutRecalc: true });\n }\n }\n });\n };\n const fontCleanup = setupFontLoadingListener(\n fabricCanvas,\n persistTextDimensionsAfterFontLoad,\n { clearGlobalCharCache: !preserveGlobalFontCache },\n );\n (fabricCanvas as any).__fontCleanup = fontCleanup;\n\n // === EVENTS ===\n \n \n // Transform state tracking (bullet-proof guard)\n // Store on canvas so it's accessible everywhere\n (fabricCanvas as any).__isUserTransforming = false;\n \n fabricCanvas.on('mouse:down', () => {\n if ((fabricCanvas as any)._currentTransform) {\n (fabricCanvas as any).__isUserTransforming = true;\n }\n });\n \n fabricCanvas.on('mouse:up', () => {\n (fabricCanvas as any).__isUserTransforming = false;\n });\n \n // Also track on object events\n fabricCanvas.on('object:scaling', () => {\n (fabricCanvas as any).__isUserTransforming = true;\n });\n \n fabricCanvas.on('object:moving', () => {\n (fabricCanvas as any).__isUserTransforming = true;\n didTransformRef.current = true; // Mark that a transform happened\n // Update group overlay immediately during drag: if a group is selected, show live bounds of whatever is moving\n const active = fabricCanvas.getActiveObject();\n if (!active) return;\n const state = useEditorStore.getState();\n const canvasPage = state.canvas.pages?.find((p) => p.id === pageId);\n const children = canvasPage?.children ?? [];\n if (!canvasPage) return;\n const ids = state.canvas.selectedIds ?? [];\n let selectedGroup: GroupNode | null = null;\n for (const id of ids) {\n const node = findNodeById(children, id);\n if (node && isGroup(node)) {\n selectedGroup = node as GroupNode;\n break;\n }\n }\n if (!selectedGroup) {\n const firstId = ids[0];\n const parent = firstId ? findParentGroup(children, firstId) : null;\n if (parent) {\n const memberIds = new Set(getAllElementIds(parent.children ?? []));\n const allSelectedInGroup = ids.every((id) => memberIds.has(id) || id === parent.id);\n if (allSelectedInGroup) selectedGroup = parent;\n }\n }\n if (!selectedGroup) return;\n const rect = active.getBoundingRect();\n if (rect.width > 0 && rect.height > 0) {\n const bounds = { left: rect.left, top: rect.top, width: rect.width, height: rect.height };\n flushSync(() => {\n setGroupOverlayLiveBoundsRef.current(bounds);\n });\n }\n });\n \n fabricCanvas.on('object:rotating', () => {\n (fabricCanvas as any).__isUserTransforming = true;\n didTransformRef.current = true; // Mark that a transform happened\n });\n \n // Selection sync TO store\n const syncSelectionToStore = () => {\n // Skip if we're currently syncing FROM store TO fabric (prevents feedback loop)\n // Also skip in preview/export mode - no selection sync needed\n if (!isActiveRef.current || isRebuildingRef.current || isSyncingSelectionToFabricRef.current || !allowSelection) return;\n\n const active = fabricCanvas.getActiveObject();\n\n // Regular selection (single element or ActiveSelection for multi-select)\n let ids = fabricCanvas\n .getActiveObjects()\n .map((o) => getObjectId(o))\n .filter((id): id is string => !!id && id !== '__background__');\n\n // Section group (fabric.Group) selected: include group id + all member element ids so UI and logic see \"group + elements\" selected\n if (ids.length === 1 && active && active instanceof fabric.Group && (active as any).__docuforgeSectionGroup) {\n const groupId = ids[0];\n const state = useEditorStore.getState();\n const currentPage = state.canvas.pages?.find((p) => p.id === pageId);\n const children = currentPage?.children ?? [];\n const node = findNodeById(children, groupId);\n if (node && isGroup(node)) {\n const memberIds = getAllElementIds((node as GroupNode).children ?? []);\n ids = [groupId, ...memberIds];\n }\n }\n\n // Single element selected (and not a section group): do not expand to group — show that element's properties and allow moving it\n if (ids.length === 1) {\n selectElements(ids, false, false);\n return;\n }\n\n // Preserve group id when Fabric selection matches a group's members (e.g. after group move we recreate selection)\n if (ids.length > 1) {\n const state = useEditorStore.getState();\n const currentPage = state.canvas.pages?.find((p) => p.id === pageId);\n const children = currentPage?.children ?? [];\n const currentSelectedIds = state.canvas.selectedIds ?? [];\n for (const sid of currentSelectedIds) {\n const node = findNodeById(children, sid);\n if (node && isGroup(node)) {\n const memberIds = new Set(getAllElementIds((node as GroupNode).children ?? []));\n const fabricIdSet = new Set(ids);\n if (memberIds.size === fabricIdSet.size && [...memberIds].every((id) => fabricIdSet.has(id))) {\n selectElements([sid, ...ids], false, true);\n return;\n }\n }\n }\n }\n selectElements(ids, false, true);\n };\n\n fabricCanvas.on('selection:created', () => {\n syncSelectionToStore();\n const activeObj = fabricCanvas.getActiveObject();\n if (activeObj) applyControlSizeForZoom(fabricCanvas, activeObj);\n // Crop group: always install Canva-style controls (corners=scale, sides=crop)\n if (activeObj && !(activeObj instanceof fabric.ActiveSelection) && ((activeObj as any)._ct?.isCropGroup || (activeObj as any).__cropGroup)) {\n installCanvaMaskControls(activeObj as any);\n }\n });\n fabricCanvas.on('selection:updated', () => {\n syncSelectionToStore();\n const activeObj = fabricCanvas.getActiveObject();\n if (activeObj) applyControlSizeForZoom(fabricCanvas, activeObj);\n // Crop group: always install Canva-style controls (corners=scale, sides=crop)\n if (activeObj && !(activeObj instanceof fabric.ActiveSelection) && ((activeObj as any)._ct?.isCropGroup || (activeObj as any).__cropGroup)) {\n installCanvaMaskControls(activeObj as any);\n }\n });\n\n fabricCanvas.on('selection:cleared', () => {\n if (!isActiveRef.current || isRebuildingRef.current || !allowSelection) return;\n setGroupOverlayLiveBoundsRef.current(null);\n groupBoundsResizingRef.current = false;\n if (skipSelectionClearOnDiscardRef.current) {\n skipSelectionClearOnDiscardRef.current = false;\n return;\n }\n editLockRef.current = false;\n syncLockedRef.current = false;\n clearSelection();\n });\n\n let dragStarted = false;\n\n const markTransforming = (target?: fabric.FabricObject | null) => {\n if (!target) return;\n\n const targetId = getObjectId(target);\n if (targetId) transformingIdsRef.current.add(targetId);\n \n // If it's a fabric.Group, mark all member element IDs as transforming\n if (target instanceof fabric.Group) {\n target.getObjects().forEach(obj => {\n const id = getObjectId(obj);\n if (id) transformingIdsRef.current.add(id);\n });\n return;\n }\n \n if (target instanceof fabric.ActiveSelection) {\n target.getObjects().forEach((o) => {\n const id = getObjectId(o);\n if (id) transformingIdsRef.current.add(id);\n });\n return;\n }\n const id = getObjectId(target);\n if (id) transformingIdsRef.current.add(id);\n };\n\n const clearTransforming = () => {\n transformingIdsRef.current.clear();\n };\n\n // Force \"hit → promote to crop group\" BEFORE Fabric finalizes target\n // This is the key difference: we do it in :before, and also handle move\n const isCropGroup = (o: any) => !!(o?._ct?.isCropGroup || o?.__cropGroup);\n\n const promoteToCropGroup = (opt: any) => {\n const t = opt.target;\n \n // CRITICAL: Only handle mouse:down events, not mouse:move (hover)\n // This prevents auto-selection on hover\n if (opt.e?.type !== 'mousedown' && opt.e?.type !== 'pointerdown' && opt.e?.type !== 'touchstart') {\n // For mouse:move, only set hover target, don't select\n if (t && isCropGroup(t)) {\n (fabricCanvas as any)._hoveredTarget = t;\n } else if (t?.group && isCropGroup(t.group)) {\n (fabricCanvas as any)._hoveredTarget = t.group;\n }\n return;\n }\n \n // CRITICAL: If no target, try to find crop group at click position\n if (!t) {\n const pointer = fabricCanvas.getPointer(opt.e);\n const objects = fabricCanvas.getObjects();\n // Find crop group at pointer position\n for (const obj of objects) {\n if (isCropGroup(obj) && obj.containsPoint(pointer)) {\n fabricCanvas.setActiveObject(obj);\n opt.target = obj;\n (fabricCanvas as any)._hoveredTarget = obj;\n return;\n }\n }\n return;\n }\n\n // If clicked a child inside a crop group\n const g = t.group;\n if (g && isCropGroup(g)) {\n fabricCanvas.setActiveObject(g);\n opt.target = g; // override Fabric's target for this event\n (fabricCanvas as any)._hoveredTarget = g; // helps with hover/control hit-tests\n return;\n }\n\n // If clicked the crop group itself, ensure it's selected\n if (isCropGroup(t)) {\n fabricCanvas.setActiveObject(t);\n // CRITICAL: Ensure crop group is selectable and evented\n t.set({\n selectable: true,\n evented: true,\n hasControls: true,\n hasBorders: true,\n });\n t.setCoords();\n }\n };\n\n // Edit lock helpers - prevent selection clearing during/after transforms\n const lockEdits = () => {\n editLockRef.current = true;\n editLockCountRef.current++;\n };\n \n const unlockEditsSoon = () => {\n // Unlock after React effects and store updates have committed.\n // Don't call doSync from here - that can trigger \"Maximum update depth\" (panels setRef during commit).\n // Instead: set refs and request a tick; an effect runs the sync so it happens after commit.\n const token = editLockCountRef.current;\n requestAnimationFrame(() => {\n setTimeout(() => {\n if (editLockCountRef.current !== token) return;\n editLockRef.current = false;\n if (pendingSyncRef.current) {\n pendingSyncRef.current = false;\n setUnlockRequestId((n) => n + 1);\n }\n }, 10);\n });\n };\n \n // Force unlock edits immediately (for when adding new elements)\n const forceUnlockEdits = () => {\n editLockCountRef.current++;\n editLockRef.current = false;\n syncLockedRef.current = false; // Also unlock sync\n \n // CRITICAL: Always run sync when forcing unlock (even if not pending)\n // This ensures latest state is applied immediately\n if (doSyncRef.current) {\n pendingSyncRef.current = false;\n doSyncRef.current();\n } else {\n // If sync function doesn't exist, the effect will run on next render\n // But we should still clear the pending flag\n pendingSyncRef.current = false;\n }\n };\n \n // Expose forceUnlockEdits to canvas for external use\n (fabricCanvas as any).__forceUnlockEdits = forceUnlockEdits;\n \n // Also expose via global registry for easy access\n if (typeof window !== 'undefined') {\n // Ensure registry exists and is a Map\n if (!(window as any).__fabricCanvasRegistry || !((window as any).__fabricCanvasRegistry instanceof Map)) {\n (window as any).__fabricCanvasRegistry = new Map();\n }\n // CRITICAL: do NOT overwrite an existing entry for this pageId.\n // The same pageId may already be registered by the visible\n // PageCanvas while an offscreen capture (vector PDF) mounts a\n // second PageCanvas with the same pageId. Overwriting would cause\n // the visible preview to lose its registry entry, and on cleanup\n // both entries would vanish — leading to flicker / formatting\n // damage on the live preview when the offscreen capture finishes.\n // Use a unique suffix when a primary entry already exists; the\n // capture flow looks up by `container.contains(canvas.lowerCanvasEl)`\n // so any key works as long as the entry is present.\n const reg = (window as any).__fabricCanvasRegistry as Map<string, any>;\n const registryKey = reg.has(pageId)\n ? `${pageId}#${Math.random().toString(36).slice(2, 10)}`\n : pageId;\n (fabricCanvas as any).__registryKey = registryKey;\n reg.set(registryKey, {\n canvas: fabricCanvas,\n forceUnlockEdits,\n });\n }\n\n fabricCanvas.on('mouse:down', (opt) => {\n // CRITICAL: Lock selection on click (not just drag) for crop groups\n const target = opt.target as any;\n const cropGroup = target?._ct?.isCropGroup || target?.__cropGroup \n ? target \n : target?.group && ((target.group as any)._ct?.isCropGroup || (target.group as any).__cropGroup)\n ? target.group\n : null;\n \n if (cropGroup) {\n // Lock edits immediately on click (even if just a click, not drag)\n lockEdits();\n didTransformRef.current = false; // Reset transform flag\n \n // Force selection immediately (so controls appear)\n fabricCanvas.setActiveObject(cropGroup);\n cropGroup.setCoords();\n fabricCanvas.requestRenderAll();\n }\n });\n\n fabricCanvas.on('mouse:down:before', (opt) => {\n // CRITICAL: Prevent Fabric from clearing selection during handle drag\n // Only lock when actually dragging a control (not just clicking)\n if (editLockRef.current) {\n // During handle drag, prevent Fabric from processing the click\n // This prevents deselection during resize/crop operations\n const active = fabricCanvas.getActiveObject() as any;\n if (active && ((active as any)._ct?.isCropGroup || (active as any).__cropGroup)) {\n // Keep crop group selected during drag\n opt.target = active;\n if (opt.e) {\n opt.e.preventDefault?.();\n opt.e.stopPropagation?.();\n }\n }\n }\n \n // Lock sync and edits as soon as a transform is about to start\n if ((fabricCanvas as any)._currentTransform) {\n (fabricCanvas as any).__isUserTransforming = true;\n syncLockedRef.current = true; // Lock sync during transform\n lockEdits(); // Lock edits to prevent selection clearing\n }\n // Also promote crop groups\n promoteToCropGroup(opt);\n });\n fabricCanvas.on('mouse:move:before', promoteToCropGroup);\n\n // Safety: prevent Fabric scaling during crop operations\n // NOTE: Crop group click locking is now handled in the debug mouse:down handler above\n fabricCanvas.on('mouse:down', () => {\n // Lock edits if transform is active\n if ((fabricCanvas as any)._currentTransform) {\n lockEdits();\n didTransformRef.current = true; // Transform is already active\n }\n \n const o = fabricCanvas.getActiveObject();\n if (!o) return;\n (o as any).__lockScaleDuringCrop = false;\n });\n\n // Side handles now resize frame directly via actionHandler\n // No need for mouse:move handler anymore\n\n fabricCanvas.on('mouse:up', (e) => {\n clearTransforming();\n setGuides([]);\n dragStarted = false;\n \n // Clear last pointer and crop lock for crop groups\n const activeObj = fabricCanvas.getActiveObject();\n if (activeObj && ((activeObj as any).__cropGroup || (activeObj as any)._ct?.isCropGroup)) {\n // Clear crop lock\n (activeObj as any).__lockScaleDuringCrop = false;\n \n // Clear crop drag mode\n if ((activeObj as any).__cropDrag) {\n delete (activeObj as any).__cropDrag;\n }\n \n // Clear pointer tracking (stored on target object)\n if ((activeObj as any).__lastPointerForCrop) {\n delete (activeObj as any).__lastPointerForCrop;\n }\n }\n \n // CRITICAL: If it was just a click (no transform), unlock immediately\n // This allows selection to be released properly\n if (!didTransformRef.current) {\n // Just a click - unlock immediately to allow deselection\n editLockRef.current = false;\n syncLockedRef.current = false;\n } else {\n // Transform happened - clear lock after a short delay\n setTimeout(() => {\n editLockRef.current = false;\n syncLockedRef.current = false;\n }, 50);\n }\n \n // Reset transform flag for next pointer session\n didTransformRef.current = false;\n \n // CRITICAL: Always ensure unlock happens eventually (safety net)\n // This prevents editLock from being stuck true forever\n setTimeout(() => {\n if (!(fabricCanvas as any)._currentTransform) {\n // No active transform - safe to unlock\n editLockRef.current = false;\n syncLockedRef.current = false;\n }\n }, 100);\n \n // Unlock sync and edits after Fabric finalizes transform (on next tick)\n setTimeout(() => {\n syncLockedRef.current = false;\n }, 0);\n unlockEditsSoon(); // Unlock edits after React effects settle\n \n // In preview mode, handle click on dynamic field elements\n if (allowDynamicFieldClick && onDynamicFieldClick && e.target) {\n const clickedId = getObjectId(e.target);\n if (clickedId && dynamicFieldIds.includes(clickedId)) {\n onDynamicFieldClick(clickedId);\n }\n }\n });\n\n const markSimpleTransform = (e: any) => {\n if (!isActiveRef.current) return;\n markTransforming(e.target);\n };\n \n // Identity test: assign stable ID to crop groups\n fabricCanvas.on('object:added', (e) => {\n const obj = e.target;\n if (obj && ((obj as any).__cropGroup || (obj as any)._ct?.isCropGroup)) {\n if (!(obj as any).__cropGroupId) {\n (obj as any).__cropGroupId = `crop-${Date.now()}-${Math.random()}`;\n }\n }\n });\n \n // Debug: log selection clearing\n fabricCanvas.on('selection:cleared', () => {\n // Selection cleared - handled by sync logic\n });\n \n // Helpers: prevent ActiveSelection during group-bounds resize by freezing child selection\n function freezeChildrenSelection(canvas: fabric.Canvas, groupNode: GroupNode) {\n const childIds = getAllElementIds(groupNode.children ?? []);\n childIds.forEach((childId) => {\n const fabricChild = canvas.getObjects().find((o) => getObjectId(o) === childId);\n if (fabricChild) {\n (fabricChild as any).__wasSelectable = fabricChild.selectable;\n (fabricChild as any).__wasEvented = fabricChild.evented;\n fabricChild.selectable = false;\n fabricChild.evented = false;\n }\n });\n }\n function unfreezeChildrenSelection(canvas: fabric.Canvas, groupNode: GroupNode) {\n const childIds = getAllElementIds(groupNode.children ?? []);\n childIds.forEach((childId) => {\n const fabricChild = canvas.getObjects().find((o) => getObjectId(o) === childId);\n if (fabricChild && (fabricChild as any).__wasSelectable !== undefined) {\n fabricChild.selectable = !!(fabricChild as any).__wasSelectable;\n fabricChild.evented = !!(fabricChild as any).__wasEvented;\n delete (fabricChild as any).__wasSelectable;\n delete (fabricChild as any).__wasEvented;\n }\n });\n }\n\n fabricCanvas.on('object:scaling', (e) => {\n if (!isActiveRef.current) return;\n const t = e.target;\n if (t) lastResizeScaleTargetRef.current = t;\n markTransforming(t as any);\n didTransformRef.current = true; // Mark that a transform happened\n\n const obj = t;\n if (!obj) return;\n\n if (\n obj instanceof fabric.Rect ||\n obj instanceof fabric.Path ||\n obj instanceof fabric.Circle ||\n obj instanceof fabric.Triangle ||\n obj instanceof fabric.Line\n ) {\n obj.set({ strokeUniform: true });\n }\n\n // Live dimension baking for shapes that need corner/stroke geometry preservation\n // This makes scaling look correct DURING the drag, not just after release\n const objId = getObjectId(obj);\n const sourceEl = objId ? elementsRef.current.find(el => el.id === objId) : null;\n const isCornerShape = sourceEl?.type === 'shape' && (\n sourceEl.shapeType === 'circle' ||\n sourceEl.shapeType === 'rounded-rect' ||\n sourceEl.shapeType === 'triangle'\n );\n\n if (isCornerShape) {\n obj.set({ objectCaching: false });\n obj.dirty = true;\n }\n\n if (isCornerShape && !(obj instanceof fabric.FabricImage)) {\n const sx = obj.scaleX ?? 1;\n const sy = obj.scaleY ?? 1;\n if (Math.abs(sx - 1) > 0.001 || Math.abs(sy - 1) > 0.001) {\n const intrW = obj.width ?? 1;\n const intrH = obj.height ?? 1;\n let newW = Math.max(1, intrW * Math.abs(sx));\n let newH = Math.max(1, intrH * Math.abs(sy));\n\n if (obj instanceof fabric.Circle) {\n const diameter = Math.max(1, Math.min(newW, newH));\n newW = diameter;\n newH = diameter;\n (obj as fabric.Circle).set({ radius: diameter / 2 });\n }\n\n if (obj instanceof fabric.Triangle) {\n const triCenter = obj.getCenterPoint();\n obj.set({\n width: newW,\n height: newH,\n scaleX: 1,\n scaleY: 1,\n strokeLineJoin: 'miter',\n strokeLineCap: 'butt',\n strokeMiterLimit: TRIANGLE_STROKE_MITER_LIMIT,\n });\n obj.setPositionByOrigin(triCenter, 'center', 'center');\n } else if (obj instanceof fabric.Rect) {\n // Re-clamp corner radii to new dimensions\n const maxR = Math.min(newW, newH) / 2;\n const curRx = Math.min((obj as fabric.Rect).rx ?? 0, maxR);\n const curRy = Math.min((obj as fabric.Rect).ry ?? 0, maxR);\n obj.set({ width: newW, height: newH, scaleX: 1, scaleY: 1, rx: curRx, ry: curRy });\n } else if (obj instanceof fabric.Path && (sourceEl?.shapeType === 'rounded-rect' || sourceEl?.shapeType === 'triangle')) {\n const centerBeforeBake = obj.getCenterPoint();\n const triRTop = Math.max(0, Number(sourceEl.triRTop ?? 0));\n const triRBR = Math.max(0, Number(sourceEl.triRBR ?? 0));\n const triRBL = Math.max(0, Number(sourceEl.triRBL ?? 0));\n const pathStr = sourceEl.shapeType === 'rounded-rect'\n ? buildRoundedRectPath(\n newW,\n newH,\n Math.max(0, Number(sourceEl.rxTL ?? sourceEl.rx ?? 0)),\n Math.max(0, Number(sourceEl.rxTR ?? sourceEl.rx ?? 0)),\n Math.max(0, Number(sourceEl.rxBR ?? sourceEl.rx ?? 0)),\n Math.max(0, Number(sourceEl.rxBL ?? sourceEl.rx ?? 0))\n )\n : buildRoundedTrianglePath(newW, newH, triRTop, triRBR, triRBL);\n\n const tempPath = new fabric.Path(pathStr);\n const isTrianglePath = sourceEl.shapeType === 'triangle';\n const tempWidth = tempPath.width ?? newW;\n const tempHeight = tempPath.height ?? newH;\n const targetWidth = isTrianglePath ? newW : tempWidth;\n const targetHeight = isTrianglePath ? newH : tempHeight;\n const tempPathOffset = (tempPath as any).pathOffset ?? new fabric.Point(tempWidth / 2, tempHeight / 2);\n\n (obj as fabric.Path).set({\n path: (tempPath as any).path,\n pathOffset: tempPathOffset,\n width: targetWidth,\n height: targetHeight,\n scaleX: 1,\n scaleY: 1,\n ...(isTrianglePath\n ? {\n strokeMiterLimit: TRIANGLE_STROKE_MITER_LIMIT,\n strokeLineJoin: 'miter',\n strokeLineCap: 'butt',\n objectCaching: false,\n }\n : {}),\n });\n (obj as fabric.Path).setPositionByOrigin(centerBeforeBake, 'center', 'center');\n } else {\n obj.set({ width: newW, height: newH, scaleX: 1, scaleY: 1 });\n }\n\n obj.setCoords();\n obj.dirty = true;\n }\n }\n\n // Textbox vertical resize: bake scaleY into minBoxHeight so the\n // glyphs don't stretch. Width is already handled by Fabric's native\n // 'resizing' event (mr/ml). For auto-shrink we also bake into\n // minBoxHeight — the box never stretches, and the auto-shrink\n // reflow uses minBoxHeight as the target height bound (so font\n // shrinks to fit the user-chosen container height).\n if (obj instanceof fabric.Textbox) {\n const sy = obj.scaleY ?? 1;\n if (Math.abs(sy - 1) > 0.001) {\n const center = obj.getCenterPoint();\n const newMinH = Math.max(0, (obj.height ?? 0) * Math.abs(sy));\n (obj as any).minBoxHeight = newMinH;\n (obj as any).scaleY = 1;\n try { (obj as fabric.Textbox).initDimensions(); } catch {}\n obj.setPositionByOrigin(center, 'center', 'center');\n obj.setCoords();\n obj.dirty = true;\n }\n }\n\n // Prevent Fabric scaling during crop operations\n if ((obj as any).__lockScaleDuringCrop || (obj as any).__cropDrag) {\n // Cancel any scaling changes Fabric tried to apply\n obj.set({ scaleX: 1, scaleY: 1 });\n obj.setCoords();\n // Preserve selection\n fabricCanvas.setActiveObject(obj);\n return;\n }\n \n // Crop groups: both modes use custom controls that update frame; block Fabric default scaling\n if (obj instanceof fabric.Group && (obj as any).__cropGroup) {\n const transform = (e as any).transform;\n const corner = transform?.corner || '';\n const isCorner = ['tl', 'tr', 'bl', 'br'].includes(corner);\n const isSide = ['mt', 'mb', 'ml', 'mr'].includes(corner);\n if (isCorner) {\n obj.set({ scaleX: 1, scaleY: 1 });\n obj.setCoords();\n fabricCanvas.setActiveObject(obj);\n return;\n } else if (isSide) {\n obj.set({ scaleX: 1, scaleY: 1 });\n obj.setCoords();\n fabricCanvas.setActiveObject(obj);\n return;\n }\n setTimeout(() => {\n (obj as any).__isInternalCropUpdate = false;\n }, 0);\n return;\n }\n\n // Native groups: no proxy rect; scaling is handled by Fabric.Group object:modified\n if (false && (obj as any).__groupBounds && obj instanceof fabric.Rect) {\n groupBoundsResizingRef.current = true;\n const objId = getObjectId(obj);\n if (objId) {\n const transform = (e as any).transform;\n const cornerRaw = transform?.corner ?? '';\n const corner = cornerRaw || (obj as any).__lastResizeCorner || 'mr';\n (obj as any).__lastResizeCorner = corner;\n const state = useEditorStore.getState();\n const page = state.canvas.pages.find((p) => p.id === pageId);\n const pageChildrenForSnap = page?.children ?? [];\n let node = wrapResizeNodeRef.current?.id === objId ? wrapResizeNodeRef.current : null;\n let transformMode = wrapResizeNodeRef.current?.id === objId ? wrapResizeTransformModeRef.current : false;\n if (!node) {\n node = findNodeById(pageChildrenForSnap, objId) as GroupNode | null;\n transformMode = !!(node && isGroup(node)); // Native Fabric groups always use transform (scale) on resize\n if (node && isGroup(node)) {\n wrapResizeNodeRef.current = node as GroupNode;\n wrapResizeTransformModeRef.current = transformMode;\n }\n }\n\n // Wrap mode: only update bounds rect every event; snap to page/element bounds; reflow on mouse release.\n if (!transformMode && node && isGroup(node)) {\n if (wrapResizeFrozenGroupIdRef.current !== objId) {\n wrapResizeFrozenGroupIdRef.current = objId;\n lastDiscreteGridColsRef.current = null;\n lastDiscreteGridRowsRef.current = null;\n discreteGridDragStartBoxRef.current = null;\n lastDiscreteGridCellHRef.current = null;\n setGridResizeLabel(null);\n freezeChildrenSelection(fabricCanvas, node as GroupNode);\n obj.set({ originX: 'left', originY: 'top', lockScalingFlip: true, angle: 0, skewX: 0, skewY: 0, stroke: undefined });\n }\n let box: { left: number; top: number; width: number; height: number };\n if (transform?.corner != null && transform?.original != null) {\n box = computeBoxFromTransform(obj, transform, { minW: 20, minH: 20 });\n } else {\n obj.setCoords();\n const b = obj.getBoundingRect();\n box = { left: b.left, top: b.top, width: Math.max(20, b.width), height: Math.max(20, b.height) };\n }\n const groupNode = node as GroupNode;\n const orderedChildren = getOrderedFlexOrGridChildren(groupNode);\n const isGrid = isGridGroupForResize(groupNode);\n const useDiscreteGrid = isGrid && orderedChildren.length > 0 && (groupNode.resizeMode === 'discreteGrid' || groupNode.resizeMode !== 'freeform');\n if (useDiscreteGrid) {\n if (discreteGridDragStartBoxRef.current === null) {\n const lastBox = lastGroupBoundsBoxRef.current?.groupId === objId ? lastGroupBoundsBoxRef.current : null;\n const fallback = lastBox ?? (() => {\n const b = getNodeBounds(groupNode, pageChildrenForSnap, pageBoundsOptions);\n return { left: b.left, top: b.top, width: Math.max(20, b.width ?? 0), height: Math.max(20, b.height ?? 0) };\n })();\n discreteGridDragStartBoxRef.current = (box.width >= 20 && box.height >= 20) ? { ...box } : { ...fallback };\n const childHeights = orderedChildren.map((c) => (getNodeBounds(c, pageChildrenForSnap, pageBoundsOptions).height ?? 0) || 20);\n lastDiscreteGridCellHRef.current = Math.max(...childHeights, 1);\n }\n const fixedCellH = lastDiscreteGridCellHRef.current ?? undefined;\n const { snappedBox, cols, rows } = computeDiscreteGridSnappedBox(\n groupNode,\n pageChildrenForSnap,\n box\n );\n box = snappedBox;\n const anchorBox = discreteGridDragStartBoxRef.current ?? box;\n const { vertical: vGuides, horizontal: hGuides } = getDiscreteGridSnapGuides(groupNode, pageChildrenForSnap, anchorBox, cols, rows, fixedCellH ?? undefined);\n const gridGuides: SnapGuide[] = [\n ...vGuides.map((v) => ({ type: 'vertical' as const, position: v.position, start: box.top - 48, end: box.top + box.height + 48, active: v.active })),\n ...hGuides.map((h) => ({ type: 'horizontal' as const, position: h.position, start: box.left - 48, end: box.left + box.width + 48, active: h.active })),\n ];\n setGuides(gridGuides);\n setGridResizeLabel({ cols, rows, x: box.left + box.width / 2, y: box.top - 32 });\n } else {\n const layoutSnap = getGroupLayoutSnapTargets(groupNode, pageChildrenForSnap, box);\n box = applyScaleSnapToBox(box, corner, fabricCanvas, canvasWidth, canvasHeight, projectSettings.snapToGuides, projectSettings.snapThreshold, objId, {\n hysteresis: 6,\n activeSnapRef: groupResizeActiveSnapRef,\n roundSnappedOnly: true,\n verticalTargetsExtra: layoutSnap.verticalTargets,\n horizontalTargetsExtra: layoutSnap.horizontalTargets,\n });\n }\n lastGroupBoundsBoxRef.current = { groupId: objId, ...box };\n obj.set({ left: box.left, top: box.top, width: box.width, height: box.height, scaleX: 1, scaleY: 1, angle: 0, skewX: 0, skewY: 0, stroke: undefined });\n obj.setCoords();\n if (!useDiscreteGrid && groupBoundsGuidesRafRef.current === null) {\n groupBoundsGuidesRafRef.current = requestAnimationFrame(() => {\n groupBoundsGuidesRafRef.current = null;\n const active = fabricCanvas.getActiveObject();\n const c = (active as any)?.__lastResizeCorner ?? corner;\n if (active) setGuides(calculateScaleSnapGuidesCallback(active, c));\n });\n }\n if (containerResizeRafRef.current === null) {\n containerResizeRafRef.current = requestAnimationFrame(() => {\n containerResizeRafRef.current = null;\n const fc = fabricRef.current;\n const active = fc?.getActiveObject();\n const pending = lastGroupBoundsBoxRef.current;\n const groupNodeRAF = wrapResizeNodeRef.current;\n if (!fc || active !== obj || !(obj as any).__groupBounds || !pending || pending.groupId !== objId || !groupNodeRAF || groupNodeRAF.id !== objId) return;\n const isDiscreteGridResize = (groupNodeRAF.resizeMode === 'discreteGrid' || groupNodeRAF.resizeMode !== 'freeform') && isGridGroupForResize(groupNodeRAF);\n if (isDiscreteGridResize) {\n fc.requestRenderAll();\n return;\n }\n const pageChildrenAfter = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)?.children ?? [];\n const layoutKey = computeGroupResizeLayoutKey(groupNodeRAF, pending.width, pending.height, 16, pageChildrenAfter);\n if (layoutKey === lastGroupResizeLayoutKeyRef.current) {\n fc.requestRenderAll();\n return;\n }\n lastGroupResizeLayoutKeyRef.current = layoutKey;\n setDragBoundsOverride({ [pending.groupId]: { left: pending.left, top: pending.top, width: pending.width, height: pending.height } });\n const reflowUpdates = reflowFromGroup(pageChildrenAfter, pending.groupId);\n const contentBox = getGroupContentBox(groupNodeRAF, pageChildrenAfter, pageBoundsOptions);\n clearDragBoundsOverride();\n const applied = lastGroupResizeAppliedRef.current;\n const EPS = 0.5;\n const WIDTH_BUCKET = 8;\n const childIds = getAllElementIds(groupNodeRAF.children ?? []);\n for (const childId of childIds) {\n const fabricObj = fc.getObjects().find((o) => getObjectId(o) === childId);\n if (!fabricObj) continue;\n const childNode = findNodeById(pageChildrenAfter, childId);\n if (!childNode) continue;\n const u = reflowUpdates.get(childId);\n const relLeft = u?.left ?? (childNode.left ?? 0);\n const relTop = u?.top ?? (childNode.top ?? 0);\n const absLeft = contentBox.left + relLeft;\n const absTop = contentBox.top + relTop;\n const size = getNodeBounds(childNode, pageChildrenAfter, pageBoundsOptions);\n const w = Math.max(1, u?.width ?? size.width);\n const h = Math.max(1, u?.height ?? size.height);\n const next = { left: absLeft, top: absTop, width: w, height: h };\n const prev = applied.get(childId);\n const changed = !prev || Math.abs(prev.left - next.left) > EPS || Math.abs(prev.top - next.top) > EPS || Math.abs(prev.width - next.width) > EPS || Math.abs(prev.height - next.height) > EPS;\n if (!changed) continue;\n applied.set(childId, next);\n fabricObj.set({ left: absLeft, top: absTop, scaleX: 1, scaleY: 1 });\n if (fabricObj instanceof fabric.Textbox) {\n const prevW = prev?.width ?? 0;\n const bucketChanged = Math.floor(prevW / WIDTH_BUCKET) !== Math.floor(w / WIDTH_BUCKET);\n if (bucketChanged || !prev) {\n fabricObj.set({ width: w, objectCaching: false });\n fabricObj.initDimensions();\n (fabricObj as any).dirty = true;\n }\n fabricObj.setCoords();\n } else {\n if ('width' in fabricObj && 'height' in fabricObj) (fabricObj as any).set({ width: w, height: h });\n fabricObj.setCoords();\n }\n }\n fc.requestRenderAll();\n });\n }\n fabricCanvas.requestRenderAll();\n return;\n }\n\n // Transform mode: freeze children so Fabric never builds ActiveSelection during drag\n if (transformMode && node && isGroup(node)) {\n freezeChildrenSelection(fabricCanvas, node);\n }\n\n // Transform mode or non-group: use RAF for scale/axis-locked logic\n if (containerResizeRafRef.current !== null) cancelAnimationFrame(containerResizeRafRef.current);\n containerResizeRafRef.current = requestAnimationFrame(() => {\n containerResizeRafRef.current = null;\n const fc = fabricRef.current;\n const active = fc?.getActiveObject();\n if (!fc || active !== obj || !(obj as any).__groupBounds) return;\n const stateInner = useEditorStore.getState();\n const pageInner = stateInner.canvas.pages.find((p) => p.id === pageId);\n const pageChildrenInner = pageInner?.children ?? [];\n const nodeInner = findNodeById(pageChildrenInner, objId) as GroupNode | null;\n const transformModeInner = !!(nodeInner && isGroup(nodeInner)); // Native Fabric groups always transform on resize\n\n if (transformModeInner && nodeInner && isGroup(nodeInner)) {\n // Transform mode: scale children (Photoshop-like). No reflow; bake rect and scale each child's pos/size.\n const cornerInner = (obj as any).__lastResizeCorner ?? '';\n const isWidthOnly = cornerInner === 'ml' || cornerInner === 'mr';\n const isHeightOnly = cornerInner === 'mt' || cornerInner === 'mb';\n const b = obj.getBoundingRect();\n const scaleX = isHeightOnly ? 1 : (obj.scaleX ?? 1);\n const scaleY = isWidthOnly ? 1 : (obj.scaleY ?? 1);\n const contentBox = getGroupContentBox(nodeInner, pageChildrenInner, pageBoundsOptions);\n const childUpdates: { id: string; left: number; top: number; width: number; height: number }[] = [];\n for (const child of nodeInner.children ?? []) {\n const childId = isElement(child) ? child.id : (child as GroupNode).id;\n const childNode = findNodeById(pageChildrenInner, childId);\n if (!childNode) continue;\n const abs = getAbsoluteBounds(childNode, pageChildrenInner);\n const relLeft = abs.left - contentBox.left;\n const relTop = abs.top - contentBox.top;\n const bounds = getNodeBounds(childNode, pageChildrenInner);\n childUpdates.push({\n id: childId,\n left: relLeft * scaleX,\n top: relTop * scaleY,\n width: Math.max(1, bounds.width * scaleX),\n height: Math.max(1, bounds.height * scaleY),\n });\n }\n for (const u of childUpdates) {\n useEditorStore.getState().updateNode(u.id, { left: u.left, top: u.top, width: u.width, height: u.height }, { recordHistory: false, skipLayoutRecalc: true });\n }\n useEditorStore.getState().updateNode(objId, { left: b.left, top: b.top }, { recordHistory: false, skipLayoutRecalc: true });\n obj.set({ left: b.left, top: b.top, scaleX: 1, scaleY: 1 });\n obj.setCoords();\n const stateAfter = useEditorStore.getState();\n const pageAfter = stateAfter.canvas.pages.find((p) => p.id === pageId);\n const pageChildrenAfter = pageAfter?.children ?? [];\n const groupAfter = findNodeById(pageChildrenAfter, objId);\n if (groupAfter && isGroup(groupAfter)) {\n const childIds = getAllElementIds((groupAfter as GroupNode).children ?? []);\n for (const childId of childIds) {\n const fabricObj = fc.getObjects().find((o) => getObjectId(o) === childId);\n if (!fabricObj) continue;\n const childNode = findNodeById(pageChildrenAfter, childId);\n if (!childNode) continue;\n const abs = getAbsoluteBounds(childNode, pageChildrenAfter);\n const size = getNodeBounds(childNode, pageChildrenAfter, pageBoundsOptions);\n fabricObj.set({ left: abs.left, top: abs.top, width: size.width, height: size.height, scaleX: 1, scaleY: 1 });\n fabricObj.setCoords();\n if (fabricObj instanceof fabric.Textbox) {\n fabricObj.set({ objectCaching: false });\n (fabricObj as any).dirty = true;\n }\n }\n }\n fc.requestRenderAll();\n return;\n }\n\n // Wrap mode: axis-locked resize, reflow children (Textbox-like)\n const cornerRAF = (obj as any).__lastResizeCorner ?? '';\n const isWidthOnly = cornerRAF === 'ml' || cornerRAF === 'mr';\n const isHeightOnly = cornerRAF === 'mt' || cornerRAF === 'mb';\n if (isWidthOnly) {\n obj.set({ scaleY: 1 });\n obj.setCoords();\n } else if (isHeightOnly) {\n obj.set({ scaleX: 1 });\n obj.setCoords();\n }\n const b = obj.getBoundingRect();\n useEditorStore.getState().updateNode(objId, { left: b.left, top: b.top }, { recordHistory: false, skipLayoutRecalc: true });\n obj.set({ left: b.left, top: b.top, scaleX: 1, scaleY: 1 });\n obj.setCoords();\n const stateAfter = useEditorStore.getState();\n const pageAfter = stateAfter.canvas.pages.find((p) => p.id === pageId);\n const pageChildrenAfter = pageAfter?.children ?? [];\n const groupAfter = findNodeById(pageChildrenAfter, objId);\n if (groupAfter && isGroup(groupAfter)) {\n const childIds = getAllElementIds((groupAfter as GroupNode).children ?? []);\n for (const childId of childIds) {\n const fabricObj = fc.getObjects().find((o) => getObjectId(o) === childId);\n if (!fabricObj) continue;\n const childNode = findNodeById(pageChildrenAfter, childId);\n if (!childNode) continue;\n const abs = getAbsoluteBounds(childNode, pageChildrenAfter);\n const size = getNodeBounds(childNode, pageChildrenAfter, pageBoundsOptions);\n fabricObj.set({\n left: abs.left,\n top: abs.top,\n width: size.width,\n height: size.height,\n scaleX: 1,\n scaleY: 1,\n });\n fabricObj.setCoords();\n if (fabricObj instanceof fabric.Textbox) {\n fabricObj.set({ width: Math.max(1, size.width), objectCaching: false });\n fabricObj.initDimensions();\n (fabricObj as any).dirty = true;\n }\n }\n }\n fc.requestRenderAll();\n });\n }\n return;\n }\n\n // ActiveSelection (group or multiselect): scaling is handled by Fabric; we persist on object:modified.\n // Get the corner/control being used for scaling\n const transform = (e as any).transform;\n const corner = transform?.corner || '';\n \n const scaleGuides = calculateScaleSnapGuidesCallback(obj, corner);\n setGuides(scaleGuides);\n });\n\n // Textbox uses 'resizing' event instead of 'scaling' when changing width\n fabricCanvas.on('object:resizing', (e) => {\n if (!isActiveRef.current) return;\n const t = e.target;\n if (t) lastResizeScaleTargetRef.current = t;\n markTransforming(t as any);\n \n const obj = t;\n if (!obj) return;\n \n // Get the corner/control being used for resizing\n const transform = (e as any).transform;\n const corner = transform?.corner || '';\n \n const scaleGuides = calculateScaleSnapGuidesCallback(obj, corner);\n setGuides(scaleGuides);\n });\n fabricCanvas.on('object:rotating', (e) => {\n markSimpleTransform(e);\n didTransformRef.current = true; // Mark that a transform happened\n });\n fabricCanvas.on('object:skewing', (e) => {\n markSimpleTransform(e);\n didTransformRef.current = true; // Mark that a transform happened\n });\n\n fabricCanvas.on('object:moving', (e) => {\n if (!isActiveRef.current) return;\n markTransforming(e.target as any);\n didTransformRef.current = true; // Mark that a transform happened\n\n if (!dragStarted) {\n dragStarted = true;\n const selectedEls = elementsRef.current.filter((el) => selectedIdsRef.current.includes(el.id));\n const mouseEvent = e.e as MouseEvent;\n if (selectedEls.length > 0 && mouseEvent) {\n onDragStart?.(selectedEls, mouseEvent, pageId);\n }\n }\n\n const obj = e.target;\n if (!obj) return;\n const snapTarget = fabricCanvas.getActiveObject() ?? obj;\n\n const { guides: newGuides, snapDx, snapDy } = calculateSnapGuidesCallback(snapTarget);\n setGuides(newGuides);\n\n if (snapDx !== 0 || snapDy !== 0) {\n snapTarget.set({ left: (snapTarget.left ?? 0) + snapDx, top: (snapTarget.top ?? 0) + snapDy });\n }\n });\n\n // Debounce timer for persisting crop group updates\n let cropGroupSaveTimer: NodeJS.Timeout | null = null;\n\n fabricCanvas.on('object:modified', (e: { target?: fabric.FabricObject }) => {\n try {\n dragStarted = false;\n setGuides([]);\n setGroupOverlayLiveBoundsRef.current(null);\n onDragEnd?.();\n\n // CRITICAL: Lock immediately so any re-render from our store update sees edit locked.\n lockEdits();\n\n const modifiedTarget = e.target;\n const modifiedTargetId = modifiedTarget ? getObjectId(modifiedTarget) : null;\n const modifiedTargetElement = modifiedTargetId\n ? elementsRef.current.find((el) => el.id === modifiedTargetId)\n : null;\n\n if (modifiedTarget && modifiedTargetElement?.type === 'shape') {\n if (modifiedTargetElement.shapeType === 'triangle') {\n modifiedTarget.set({\n objectCaching: false,\n strokeLineJoin: 'miter',\n strokeLineCap: 'butt',\n strokeMiterLimit: TRIANGLE_STROKE_MITER_LIMIT,\n });\n } else {\n modifiedTarget.set({ objectCaching: true });\n }\n modifiedTarget.dirty = true;\n modifiedTarget.setCoords();\n }\n\n // IDs we add to justModifiedIdsRef this run; clear them after a delay so future syncs can apply non-position updates\n const modifiedIdsThisRound = new Set<string>();\n\n // Only update store in editor mode\n if (!allowEditing) {\n unlockEditsSoon();\n return;\n }\n\n const active = fabricCanvas.getActiveObject();\n const activeId = active ? getObjectId(active) : null;\n const activeObjectsForLog = fabricCanvas.getActiveObjects();\n if (typeof console !== 'undefined' && console.log) {\n console.log('[object:modified] activeId=', activeId, 'isGroup=', active instanceof fabric.Group, 'isActiveSelection=', active instanceof fabric.ActiveSelection, 'activeObjectsCount=', activeObjectsForLog?.length ?? 0);\n }\n\n // When the modified object is a single element (e.g. text) that belongs to a section group, Fabric often\n // reports the child as active when the user actually dragged the group. Prioritise group position: if the\n // section group moved, update only the group's left/top and return. Otherwise persist child (resize).\n if (active && activeId && activeId !== '__background__' && !(active instanceof fabric.Group)) {\n const pageChildrenForParent = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)?.children ?? [];\n const parentGroup = findParentGroup(pageChildrenForParent, activeId);\n if (parentGroup && isGroup(parentGroup) && parentGroup.backgroundColor) {\n let fabricSectionGroup: fabric.Group | null = (active as any).group && (active as any).group instanceof fabric.Group ? (active as any).group : null;\n if (!fabricSectionGroup || !(fabricSectionGroup as any).__docuforgeSectionGroup) {\n fabricSectionGroup = fabricCanvas.getObjects().find((o) => getObjectId(o) === parentGroup.id && (o as any).__docuforgeSectionGroup) as fabric.Group ?? null;\n }\n if (fabricSectionGroup && (fabricSectionGroup as any).__docuforgeSectionGroup) {\n const fabricGroupId = getObjectId(fabricSectionGroup);\n const groupId = parentGroup.id;\n const pageChildrenSec = pageChildrenForParent;\n const groupNodeForCompare = fabricGroupId ? findNodeById(pageChildrenSec, fabricGroupId) : null;\n const storeBounds = groupNodeForCompare ? getAbsoluteBounds(groupNodeForCompare, pageChildrenSec) : null;\n const storeCenterX = storeBounds ? storeBounds.left + storeBounds.width / 2 : (fabricSectionGroup.left ?? 0);\n const storeCenterY = storeBounds ? storeBounds.top + storeBounds.height / 2 : (fabricSectionGroup.top ?? 0);\n const fabricCenterX = fabricSectionGroup.left ?? 0;\n const fabricCenterY = fabricSectionGroup.top ?? 0;\n const groupMoved = Math.abs(fabricCenterX - storeCenterX) > 2 || Math.abs(fabricCenterY - storeCenterY) > 2;\n if (groupMoved) {\n lastResizeScaleTargetRef.current = null;\n const movedGroupId = getObjectId(fabricSectionGroup);\n if (movedGroupId) {\n const w = (fabricSectionGroup.width ?? 0) * (fabricSectionGroup.scaleX ?? 1);\n const h = (fabricSectionGroup.height ?? 0) * (fabricSectionGroup.scaleY ?? 1);\n const groupLeft = fabricCenterX - w / 2;\n const groupTop = fabricCenterY - h / 2;\n const storePosGroup = absoluteToStorePosition(groupLeft, groupTop, movedGroupId, pageChildrenSec);\n useEditorStore.getState().updateNode(movedGroupId, { left: storePosGroup.left, top: storePosGroup.top }, { recordHistory: false, skipLayoutRecalc: true });\n }\n commitHistory();\n unlockEditsSoon();\n return;\n }\n lastResizeScaleTargetRef.current = null;\n const node = findNodeById(pageChildrenSec, groupId) as GroupNode | null;\n if (node && isGroup(node)) {\n const objs = fabricSectionGroup.getObjects();\n const kids = node.children ?? [];\n const gap = isStackLayoutMode(node.layoutMode) ? (node.stackSpacing ?? 8) : 0;\n const groupScaleX = fabricSectionGroup.scaleX ?? 1;\n const groupScaleY = fabricSectionGroup.scaleY ?? 1;\n const w = (fabricSectionGroup.width ?? 0) * (fabricSectionGroup.scaleX ?? 1);\n const h = (fabricSectionGroup.height ?? 0) * (fabricSectionGroup.scaleY ?? 1);\n let prevBottom = 0;\n for (let i = 0; i < objs.length; i++) {\n const childObj = objs[i];\n const childId = getObjectId(childObj);\n const child = kids[i];\n if (!childId || !child || child.id !== childId) continue;\n const cW = (childObj.width ?? 0) * (childObj.scaleX ?? 1) * groupScaleX;\n const cH = (childObj.height ?? 0) * (childObj.scaleY ?? 1) * groupScaleY;\n const grLeft = (childObj.left ?? 0) + w / 2;\n const grTop = (childObj.top ?? 0) + h / 2;\n let storeTop: number;\n if (isStackLayoutMode(node.layoutMode) && i > 0) {\n storeTop = Math.max(0, grTop - prevBottom - gap);\n } else {\n storeTop = grTop;\n }\n prevBottom = grTop + cH;\n const updates: { left: number; top: number; width?: number; height?: number } = { left: grLeft, top: storeTop };\n const lockWidthForAutoShrinkText = isElement(child) && child.type === 'text' && child.overflowPolicy === 'auto-shrink';\n // Auto-shrink text: keep width fixed, but allow height changes so stack reflow can pull siblings up.\n if (!lockWidthForAutoShrinkText && cW > 0) updates.width = cW;\n if (lockWidthForAutoShrinkText) {\n const storedChildHeight = isElement(child) && typeof child.height === 'number' ? child.height : undefined;\n if (cH > 0) {\n // Auto-shrink must never persist growth, otherwise stack siblings get pushed downward incorrectly.\n updates.height = typeof storedChildHeight === 'number' ? Math.min(storedChildHeight, cH) : cH;\n }\n } else if (cH > 0) {\n updates.height = cH;\n }\n useEditorStore.getState().updateNode(childId, updates, { recordHistory: false, skipLayoutRecalc: false });\n if (childId !== '__background__') {\n modifiedIdsThisRound.add(childId);\n justModifiedIdsRef.current.add(childId);\n }\n }\n }\n if (node && isStackLayoutMode(node.layoutMode)) {\n useEditorStore.getState().reflowStackGroupInPage(pageId, groupId);\n }\n const stateAfter = useEditorStore.getState();\n const pageAfter = stateAfter.canvas.pages.find((p) => p.id === pageId)?.children ?? [];\n const groupNodeAfter = findNodeById(pageAfter, groupId);\n if (groupNodeAfter) {\n const abs = getAbsoluteBounds(groupNodeAfter, pageAfter);\n const centerX = abs.left + abs.width / 2;\n const centerY = abs.top + abs.height / 2;\n fabricSectionGroup.set({ left: centerX, top: centerY });\n fabricSectionGroup.setCoords();\n }\n setTimeout(() => modifiedIdsThisRound.forEach((id) => justModifiedIdsRef.current.delete(id)), 150);\n commitHistory();\n unlockEditsSoon();\n return;\n }\n }\n }\n\n // Handle crop groups - persist AFTER interaction completes (debounced)\n if (active && (active as any).__cropGroup) {\n const objId = getObjectId(active);\n if (objId) {\n // So the next sync (after unlockEditsSoon) skips overwriting position from store\n modifiedIdsThisRound.add(objId);\n justModifiedIdsRef.current.add(objId);\n const ct = (active as any).__cropData;\n if (ct) {\n // Clear any pending save\n if (cropGroupSaveTimer) {\n clearTimeout(cropGroupSaveTimer);\n }\n \n // Debounce save to avoid React rerenders during drag\n cropGroupSaveTimer = setTimeout(() => {\n const { updateElement } = useEditorStore.getState();\n const img = ct._img;\n const zoom = (img as any)?._ct?.zoom ?? 1;\n const panX = (img as any)?._ct?.panX ?? 0.5;\n const panY = (img as any)?._ct?.panY ?? 0.5;\n \n const stateCrop = useEditorStore.getState();\n const pageCrop = stateCrop.canvas.pages.find((p) => p.id === pageId);\n const pageChildrenCrop = pageCrop?.children ?? [];\n // Crop group uses center in Fabric; store expects top-left\n const absLeft = (active.left ?? 0) - ct.frameW / 2;\n const absTop = (active.top ?? 0) - ct.frameH / 2;\n const storePosCrop = absoluteToStorePosition(absLeft, absTop, objId, pageChildrenCrop);\n \n updateElement(objId, {\n width: ct.frameW,\n height: ct.frameH,\n left: storePosCrop.left,\n top: storePosCrop.top,\n angle: active.angle ?? 0,\n cropPanX: panX,\n cropPanY: panY,\n cropZoom: zoom,\n }, { recordHistory: false });\n \n // Clear the flag\n (active as any).__isInternalCropUpdate = false;\n \n // Preserve selection\n fabricCanvas.setActiveObject(active);\n // Clear justModified after delay so future syncs can apply position from store\n setTimeout(() => justModifiedIdsRef.current.delete(objId), 150);\n }, 0);\n \n unlockEditsSoon();\n return; // Skip normal processing for crop groups\n }\n }\n }\n\n // Section groups (fabric.Group with __docuforgeSectionGroup): persist group position and child positions/sizes.\n // When the user repositions the group, always update the group's left/top (not the children). When a child is resized, revert group and update children.\n if (active && active instanceof fabric.Group && (active as any).__docuforgeSectionGroup && getObjectId(active)) {\n const groupId = getObjectId(active)!;\n const pageChildrenSec = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)?.children ?? [];\n const modifiedTarget = e?.target;\n const resizeScaleTarget = lastResizeScaleTargetRef.current;\n lastResizeScaleTargetRef.current = null;\n const children = active.getObjects();\n const groupNodeSec = findNodeById(pageChildrenSec, groupId);\n const storeBounds = groupNodeSec ? getAbsoluteBounds(groupNodeSec, pageChildrenSec) : null;\n const storeCenterX = storeBounds ? storeBounds.left + storeBounds.width / 2 : (active.left ?? 0);\n const storeCenterY = storeBounds ? storeBounds.top + storeBounds.height / 2 : (active.top ?? 0);\n const fabricCenterX = active.left ?? 0;\n const fabricCenterY = active.top ?? 0;\n const moveDx = Math.abs(fabricCenterX - storeCenterX);\n const moveDy = Math.abs(fabricCenterY - storeCenterY);\n const groupMoved = moveDx > 2 || moveDy > 2;\n // Child modified = user resized a child (target is child or we had a resize); only then revert group and don't update group position\n let isChildModified =\n (modifiedTarget && children.includes(modifiedTarget)) ||\n (resizeScaleTarget && children.includes(resizeScaleTarget));\n if (!isChildModified && !groupMoved && groupNodeSec && (active.scaleX ?? 1) === 1 && (active.scaleY ?? 1) === 1) {\n if (moveDx < 4 && moveDy < 4) isChildModified = true;\n }\n // Always update group position when the group was moved (repositioned); never skip this so group left/top stay correct\n if (groupMoved || !isChildModified) {\n const centerX = active.left ?? 0;\n const centerY = active.top ?? 0;\n const w = (active.width ?? 0) * (active.scaleX ?? 1);\n const h = (active.height ?? 0) * (active.scaleY ?? 1);\n const groupLeft = centerX - w / 2;\n const groupTop = centerY - h / 2;\n const storePosGroup = absoluteToStorePosition(groupLeft, groupTop, groupId, pageChildrenSec);\n useEditorStore.getState().updateNode(groupId, { left: storePosGroup.left, top: storePosGroup.top }, { recordHistory: false, skipLayoutRecalc: true });\n }\n // Do not persist children's left/top: section group getObjects() are flattened leaf elements\n // while node.children are direct children (subgroups), so writing would corrupt positions.\n const node = findNodeById(pageChildrenSec, groupId) as GroupNode | null;\n if (isChildModified && node && !groupMoved) {\n const stateAfter = useEditorStore.getState();\n const pageAfter = stateAfter.canvas.pages.find((p) => p.id === pageId)?.children ?? [];\n const groupNodeAfter = findNodeById(pageAfter, groupId);\n if (groupNodeAfter) {\n const abs = getAbsoluteBounds(groupNodeAfter, pageAfter);\n const centerX = abs.left + abs.width / 2;\n const centerY = abs.top + abs.height / 2;\n active.set({ left: centerX, top: centerY });\n active.setCoords();\n }\n }\n commitHistory();\n unlockEditsSoon();\n return;\n }\n\n // Single Fabric group (not section, not ActiveSelection): when repositioned, update only the group's left/top.\n // Skip ActiveSelection so multi-select falls through to the move-parent path (update parent group, not children).\n // Never update children here: prioritise group position so the moved group's position is what gets persisted.\n if (active && active instanceof fabric.Group && !(active instanceof fabric.ActiveSelection) && getObjectId(active)) {\n const groupId = getObjectId(active)!;\n const pageChildren = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)?.children ?? [];\n const w = (active.width ?? 0) * (active.scaleX ?? 1);\n const h = (active.height ?? 0) * (active.scaleY ?? 1);\n const centerX = active.left ?? 0;\n const centerY = active.top ?? 0;\n const groupLeft = active.originX === 'center' ? centerX - w / 2 : centerX;\n const groupTop = active.originY === 'center' ? centerY - h / 2 : centerY;\n const storePos = absoluteToStorePosition(groupLeft, groupTop, groupId, pageChildren);\n useEditorStore.getState().updateNode(groupId, { left: storePos.left, top: storePos.top }, { recordHistory: false, skipLayoutRecalc: true });\n commitHistory();\n unlockEditsSoon();\n return;\n }\n\n const { updateElement } = useEditorStore.getState();\n \n // Unlock scaling for all objects after modification (in case it was locked)\n if (active instanceof fabric.FabricImage) {\n active.set({\n lockScalingX: false,\n lockScalingY: false,\n });\n }\n\n // Regular element(s) modified (single or ActiveSelection)\n const activeObj = fabricCanvas.getActiveObject();\n let activeObjects = fabricCanvas.getActiveObjects();\n // Fabric may return [activeSelection] when active is ActiveSelection (e.g. in minified build\n // activeObj.constructor.name !== 'ActiveSelection'), so the only item has no __docuforgeId.\n // Unwrap: if the single item has getObjects and no id, use its getObjects() as the real list.\n if (activeObjects.length === 1 && typeof (activeObjects[0] as any).getObjects === 'function' && !getObjectId(activeObjects[0])) {\n activeObjects = (activeObjects[0] as any).getObjects();\n }\n \n // Check if we're inside an ActiveSelection (multi-select; include unwrapped case when active has no id)\n const isActiveSelection = activeObj instanceof fabric.ActiveSelection || activeObjects.length > 1;\n \n // Check if all selected elements belong to the same group\n // If so, move the entire group together instead of individual elements\n const { getCurrentPage: getCurrentPageStore } = useEditorStore.getState();\n const currentPage = getCurrentPageStore();\n const selectedElementIds = activeObjects\n .map(obj => getObjectId(obj))\n .filter((id): id is string => !!id && id !== '__background__');\n \n // Never take \"group move only\" path when a crop group is selected - we must persist its dimensions (scale bake)\n const anyCropGroup = activeObjects.some((o: fabric.FabricObject) => (o as any).__cropGroup);\n\n if (selectedElementIds.length > 0 && !anyCropGroup) {\n const pageChildren = currentPage.children ?? [];\n const firstObj = activeObjects[0];\n const firstId = getObjectId(firstObj);\n const parentGroups = selectedElementIds\n .map((id) => findParentGroup(pageChildren, id))\n .filter((g): g is GroupNode => g !== null);\n const sameDirectParent = parentGroups.length > 0 && parentGroups.every((g) => g.id === parentGroups[0].id);\n const commonAncestor = findCommonAncestorGroup(selectedElementIds, pageChildren);\n // Move the whole group when:\n // (a) it's a stack-based group (children layout is auto-managed), OR\n // (b) ALL leaf members of an absolute group are selected (user is moving the group as a unit).\n // For an absolute group with only a SUBSET of members selected, fall through so the user\n // can drag individual children freely.\n const candidateGroup = sameDirectParent ? parentGroups[0] : commonAncestor;\n const candidateIsStack = candidateGroup && isStackLayoutMode(candidateGroup.layoutMode);\n const allMembersSelected = (() => {\n if (!candidateGroup) return false;\n const memberIds = getAllElementIds(candidateGroup.children ?? []);\n if (memberIds.length === 0) return false;\n const selectedSet = new Set(selectedElementIds);\n return memberIds.every((mid) => selectedSet.has(mid));\n })();\n const groupToMove = candidateIsStack || allMembersSelected ? candidateGroup : null;\n\n if (groupToMove) {\n const groupAbs = getAbsoluteBounds(groupToMove, pageChildren);\n let movedGroupLeft = groupAbs.left;\n let movedGroupTop = groupAbs.top;\n\n if (activeObj) {\n const selectionRect = activeObj.getBoundingRect();\n movedGroupLeft = selectionRect.left;\n movedGroupTop = selectionRect.top;\n } else if (firstId) {\n const firstNode = findNodeById(pageChildren, firstId);\n if (firstNode) {\n movedGroupLeft = getAbsoluteBounds(firstNode, pageChildren).left;\n movedGroupTop = getAbsoluteBounds(firstNode, pageChildren).top;\n }\n }\n\n const deltaX = movedGroupLeft - groupAbs.left;\n const deltaY = movedGroupTop - groupAbs.top;\n const hadScale = isActiveSelection && activeObj && (Math.abs((activeObj.scaleX ?? 1) - 1) > 0.01 || Math.abs((activeObj.scaleY ?? 1) - 1) > 0.01);\n\n if (!hadScale && (Math.abs(deltaX) > 0.1 || Math.abs(deltaY) > 0.1)) {\n if (typeof console !== 'undefined' && console.log) {\n console.log('[object:modified] plain-groups: moving group id=', groupToMove.id, 'newLeft=', (groupToMove.left ?? 0) + deltaX, 'newTop=', (groupToMove.top ?? 0) + deltaY);\n }\n const { updateNode: updateNodeStore, commitHistory: commitHistoryStore, getCurrentElements } = useEditorStore.getState();\n const newLeft = (groupToMove.left ?? 0) + deltaX;\n const newTop = (groupToMove.top ?? 0) + deltaY;\n updateNodeStore(groupToMove.id, { left: newLeft, top: newTop }, { recordHistory: false, skipLayoutRecalc: true });\n commitHistoryStore();\n\n if (isActiveSelection && activeObj instanceof fabric.ActiveSelection) {\n skipSelectionClearOnDiscardRef.current = true;\n fabricCanvas.discardActiveObject();\n }\n const stateAfter = useEditorStore.getState();\n const pageAfter = stateAfter.canvas.pages.find((p) => p.id === pageId);\n const pageChildrenAfter = pageAfter?.children ?? [];\n for (const obj of activeObjects) {\n const objId = getObjectId(obj);\n if (!objId || objId === '__background__') continue;\n const node = findNodeById(pageChildrenAfter, objId);\n if (node) {\n const abs = getAbsoluteBounds(node, pageChildrenAfter);\n const w = (obj.width ?? 0) * (obj.scaleX ?? 1);\n const h = (obj.height ?? 0) * (obj.scaleY ?? 1);\n const nextLeft = obj.originX === 'center' ? abs.left + w / 2 : abs.left;\n const nextTop = obj.originY === 'center' ? abs.top + h / 2 : abs.top;\n obj.set({ left: nextLeft, top: nextTop });\n obj.setCoords();\n }\n }\n if (isActiveSelection && activeObjects.length > 0) {\n const selection = new fabric.ActiveSelection([...activeObjects], { canvas: fabricCanvas });\n fabricCanvas.setActiveObject(selection);\n skipSelectionClearOnDiscardRef.current = false;\n }\n fabricCanvas.requestRenderAll();\n\n elementsRef.current = getCurrentElements();\n for (const obj of activeObjects) {\n const objId = getObjectId(obj);\n if (objId && objId !== '__background__') {\n justModifiedIdsRef.current.add(objId);\n modifiedIdsThisRound.add(objId);\n }\n }\n setTimeout(() => modifiedIdsThisRound.forEach((id) => justModifiedIdsRef.current.delete(id)), 150);\n unlockEditsSoon();\n return;\n }\n }\n }\n\n for (const obj of activeObjects) {\n const objId = getObjectId(obj);\n if (!objId || objId === '__background__') continue;\n\n let intrinsicWidth: number;\n let intrinsicHeight: number;\n\n if (obj instanceof fabric.Circle) {\n const r = (obj as any).radius ?? 0;\n intrinsicWidth = r * 2;\n intrinsicHeight = r * 2;\n } else if (obj instanceof fabric.Ellipse) {\n intrinsicWidth = (obj.rx ?? 0) * 2;\n intrinsicHeight = (obj.ry ?? 0) * 2;\n } else if (obj instanceof fabric.Textbox) {\n intrinsicWidth = obj.width ?? 0;\n intrinsicHeight = obj.height ?? 0;\n } else if (obj instanceof fabric.Line) {\n // Line: length from coordinates; no height (avoid slant from scaleY/skew)\n const x1 = (obj as any).x1 ?? 0, y1 = (obj as any).y1 ?? 0, x2 = (obj as any).x2 ?? 0, y2 = (obj as any).y2 ?? 0;\n intrinsicWidth = Math.hypot(x2 - x1, y2 - y1) * (obj.scaleX ?? 1);\n intrinsicHeight = 0;\n } else {\n intrinsicWidth = obj.width ?? 0;\n intrinsicHeight = obj.height ?? 0;\n }\n\n // Get the absolute transform matrix directly from Fabric\n // This is the most reliable approach - no decomposition/recomposition errors\n let absoluteMatrix: [number, number, number, number, number, number];\n \n if (isActiveSelection && activeObj) {\n // For ActiveSelection, combine selection transform with object transform\n const selectionMatrix = activeObj.calcTransformMatrix();\n const objOwnMatrix = obj.calcOwnMatrix();\n const combined = fabric.util.multiplyTransformMatrices(selectionMatrix, objOwnMatrix);\n absoluteMatrix = combined as [number, number, number, number, number, number];\n } else {\n // Single object - get its full transform matrix\n const matrix = obj.calcTransformMatrix();\n absoluteMatrix = matrix as [number, number, number, number, number, number];\n }\n \n // Decompose for the individual properties (needed for backwards compatibility and some operations)\n const decomposed = fabric.util.qrDecompose(absoluteMatrix);\n\n justModifiedIdsRef.current.add(objId);\n modifiedIdsThisRound.add(objId);\n\n // Calculate absolute left/top position\n // When in ActiveSelection, obj.left/top are relative to selection center\n // We need to transform to absolute canvas coordinates\n let absoluteLeft: number;\n let absoluteTop: number;\n \n if (isActiveSelection && activeObj) {\n // Transform the object's origin point through the selection matrix\n // to get the absolute canvas position\n const selectionMatrix = activeObj.calcTransformMatrix();\n const relativePoint = { x: obj.left ?? 0, y: obj.top ?? 0 };\n const absolutePoint = fabric.util.transformPoint(relativePoint, selectionMatrix);\n absoluteLeft = absolutePoint.x;\n absoluteTop = absolutePoint.y;\n } else {\n // Single object - use direct values\n absoluteLeft = obj.left ?? 0;\n absoluteTop = obj.top ?? 0;\n }\n\n // For crop groups Fabric stores center (origin center); store expects top-left\n if (obj instanceof fabric.Group && (obj as any).__cropGroup) {\n const ct = (obj as any).__cropData;\n const w = ct?.frameW ?? (obj.width ?? 0) * (obj.scaleX ?? 1);\n const h = ct?.frameH ?? (obj.height ?? 0) * (obj.scaleY ?? 1);\n absoluteLeft = (absoluteLeft ?? 0) - w / 2;\n absoluteTop = (absoluteTop ?? 0) - h / 2;\n } else if (obj instanceof fabric.FabricImage && (obj.originX === 'center' || obj.originY === 'center')) {\n // Plain images with center origin (imageFit fill): convert center to top-left for store\n const w = (obj.width ?? 0) * (obj.scaleX ?? 1);\n const h = (obj.height ?? 0) * (obj.scaleY ?? 1);\n absoluteLeft = (absoluteLeft ?? 0) - w / 2;\n absoluteTop = (absoluteTop ?? 0) - h / 2;\n }\n\n // For images with crop mode (imageFit !== 'fill'), handle differently based on handle type\n // Corner handles: scale the image (normal behavior)\n // Side handles: resize crop window, keep image scale fixed\n // CRITICAL: For Textbox, finalWidth/finalHeight are already set above to preserve stored width\n const sourceElement = elementsRef.current.find(el => el.id === objId);\n const preserveCornerGeometry =\n sourceElement?.type === 'shape' &&\n (\n sourceElement.shapeType === 'circle' ||\n sourceElement.shapeType === 'rounded-rect' ||\n sourceElement.shapeType === 'triangle'\n );\n\n let finalWidth = intrinsicWidth;\n let finalHeight = intrinsicHeight;\n let finalScaleX = decomposed.scaleX;\n let finalScaleY = decomposed.scaleY;\n let finalAbsoluteMatrix = absoluteMatrix;\n \n // Handle crop groups (Canva-style: frame + image)\n // Both crop handles and simple scale use custom controls that update ct.frameW/frameH; same persist path\n if (obj instanceof fabric.Group && (obj as any).__cropGroup) {\n const ct = (obj as any).__cropData;\n if (ct) {\n finalWidth = ct.frameW;\n finalHeight = ct.frameH;\n finalScaleX = 1;\n finalScaleY = 1;\n obj.set({ scaleX: 1, scaleY: 1 });\n // CRITICAL: Don't run updateCoverLayout / setActiveObject inside an\n // ActiveSelection iteration — it discards the multi-selection and reparents\n // sibling objects mid-loop, which causes other selected elements to \"jump\"\n // to wrong positions. Layout will resync via the regular store→canvas effect.\n if (!isActiveSelection) {\n updateCoverLayout(obj);\n (obj as any).__lastResizeHandle = null;\n fabricCanvas.setActiveObject(obj);\n } else {\n (obj as any).__lastResizeHandle = null;\n }\n }\n } else if (obj instanceof fabric.FabricImage) {\n // Smart elements: bake scale into width/height and re-render SVG at new dimensions\n if (sourceElement?.smartElementType && sourceElement.smartProps) {\n const bakedW = Math.max(1, intrinsicWidth * Math.abs(decomposed.scaleX || 1));\n const bakedH = Math.max(1, intrinsicHeight * Math.abs(decomposed.scaleY || 1));\n finalWidth = bakedW;\n finalHeight = bakedH;\n finalScaleX = 1;\n finalScaleY = 1;\n obj.set({ scaleX: 1, scaleY: 1 });\n // Re-render SVG at new dimensions\n const newSrc = renderSmartElementToDataUri(sourceElement.smartElementType, sourceElement.smartProps, bakedW, bakedH);\n if (newSrc) {\n const imgEl = new Image();\n imgEl.src = newSrc;\n imgEl.onload = () => {\n (obj as fabric.FabricImage).setElement(imgEl);\n (obj as fabric.FabricImage).set({ width: bakedW, height: bakedH, scaleX: 1, scaleY: 1 });\n obj.setCoords();\n obj.dirty = true;\n fabricCanvas.requestRenderAll();\n };\n // Also update src in store\n useEditorStore.getState().updateElement(objId, { src: newSrc }, { recordHistory: false, skipLayoutRecalc: true });\n }\n } else {\n finalWidth = intrinsicWidth;\n finalHeight = intrinsicHeight;\n }\n } else if (obj instanceof fabric.Line) {\n // Line: persist length as width, no vertical scale/skew so it stays horizontal (no slant)\n finalWidth = intrinsicWidth;\n finalHeight = 0;\n finalScaleX = 1;\n finalScaleY = 1;\n } else if (preserveCornerGeometry) {\n // Keep core shape geometry stable by baking transform into width/height (circle, rounded-rect, triangle)\n const scaledW = Math.max(1, intrinsicWidth * Math.abs(decomposed.scaleX || 1));\n const scaledH = Math.max(1, intrinsicHeight * Math.abs(decomposed.scaleY || 1));\n\n if (sourceElement?.shapeType === 'circle') {\n const diameter = Math.max(1, Math.min(scaledW, scaledH));\n finalWidth = diameter;\n finalHeight = diameter;\n } else {\n finalWidth = scaledW;\n finalHeight = scaledH;\n }\n\n finalScaleX = 1;\n finalScaleY = 1;\n obj.set({ scaleX: 1, scaleY: 1 });\n\n if (isActiveSelection && activeObj) {\n const selectionMatrix = activeObj.calcTransformMatrix();\n const objOwnMatrix = obj.calcOwnMatrix();\n const combined = fabric.util.multiplyTransformMatrices(selectionMatrix, objOwnMatrix);\n finalAbsoluteMatrix = combined as [number, number, number, number, number, number];\n } else {\n finalAbsoluteMatrix = obj.calcTransformMatrix() as [number, number, number, number, number, number];\n }\n } else {\n finalWidth = intrinsicWidth;\n finalHeight = intrinsicHeight;\n }\n\n // Convert absolute canvas position to store position (relative when inside a group)\n const state = useEditorStore.getState();\n const page = state.canvas.pages.find((p) => p.id === pageId);\n const pageChildrenForSave = page?.children ?? [];\n const storePos = absoluteToStorePosition(absoluteLeft, absoluteTop, objId, pageChildrenForSave);\n \n const isLineObj = obj instanceof fabric.Line;\n const isAutoShrinkText =\n sourceElement?.type === 'text' && sourceElement.overflowPolicy === 'auto-shrink';\n const autoShrinkStoredWidth = isAutoShrinkText ? sourceElement.width : undefined;\n const autoShrinkStoredHeight = isAutoShrinkText ? sourceElement.height : undefined;\n const elementUpdate: Partial<CanvasElement> = {\n left: storePos.left,\n top: storePos.top,\n // Auto-shrink: lock width, but let height shrink to actual rendered height for proper stack reflow.\n width: isAutoShrinkText ? (autoShrinkStoredWidth ?? finalWidth) : finalWidth,\n height: isLineObj\n ? 0\n : (isAutoShrinkText\n ? (typeof autoShrinkStoredHeight === 'number' ? Math.min(autoShrinkStoredHeight, finalHeight) : finalHeight)\n : finalHeight),\n angle: decomposed.angle,\n skewX: isLineObj ? 0 : decomposed.skewX,\n skewY: isLineObj ? 0 : decomposed.skewY,\n scaleX: finalScaleX,\n scaleY: finalScaleY,\n transformMatrix: finalAbsoluteMatrix,\n };\n \n // Persist textbox vertical-resize floor (baked from scaleY in\n // the object:scaling handler). Applies to both grow-and-push\n // (acts as a min height floor) and auto-shrink (acts as the\n // fit-target height so font shrinks into the chosen box height).\n if (obj instanceof fabric.Textbox) {\n const baked = (obj as any).minBoxHeight;\n if (typeof baked === 'number' && baked > 0) {\n (elementUpdate as any).minBoxHeight = baked;\n }\n }\n\n // Intentionally do NOT write `obj.text` back to the element on\n // object:modified — move/resize/rotate never change text content.\n // The dedicated `text:editing:exited` handler is the only path\n // that should persist edited text. Writing here was clobbering\n // markdown source whenever the user toggled \"Enable inline\n // formatting\" off (obj.text held the stripped plain text from\n // the prior render and would overwrite element.text with it).\n \n if (sourceElement && sourceElement.opacity !== undefined) {\n elementUpdate.opacity = sourceElement.opacity;\n }\n \n updateElement(objId, elementUpdate, { recordHistory: false, skipLayoutRecalc: true });\n\n obj.setCoords();\n }\n\n // If any modified element belongs to a stack group (with or without backgroundColor), reflow so siblings shift\n const pageChildrenForReflow = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)?.children ?? [];\n const stackGroupsToReflow = new Set<string>();\n for (const id of modifiedIdsThisRound) {\n const parent = findParentGroup(pageChildrenForReflow, id);\n if (parent && isGroup(parent) && (parent.layoutMode ?? 'absolute') === 'stack') {\n stackGroupsToReflow.add(parent.id);\n }\n }\n for (const gid of stackGroupsToReflow) {\n useEditorStore.getState().reflowStackGroupInPage(pageId, gid);\n }\n\n // After persisting an ActiveSelection (group or multiselect), bake the selection transform\n // onto each object so Fabric state matches the store and sync won't overwrite or fight.\n if (isActiveSelection && activeObj && activeObjects.length > 0) {\n const selectionMatrix = activeObj.calcTransformMatrix();\n for (const obj of activeObjects) {\n const objId = getObjectId(obj);\n if (!objId || objId === '__background__') continue;\n const objOwnMatrix = obj.calcOwnMatrix();\n const absoluteMatrix = fabric.util.multiplyTransformMatrices(selectionMatrix, objOwnMatrix);\n fabric.util.applyTransformToObject(obj, absoluteMatrix);\n obj.setCoords();\n }\n activeObj.set({ scaleX: 1, scaleY: 1 });\n activeObj.setCoords();\n fabricCanvas.requestRenderAll();\n }\n \n setTimeout(() => modifiedIdsThisRound.forEach(id => justModifiedIdsRef.current.delete(id)), 150);\n commitHistory();\n unlockEditsSoon();\n } catch (e) {\n unlockEditsSoon();\n }\n });\n\n // When selection is cleared, bake transforms into Fabric objects\n // The store was already updated during object:modified, so we only update Fabric objects here\n // BUT: Only do this if we actually had a transform, not just a click\n fabricCanvas.on('before:selection:cleared', (e) => {\n if (!isActiveRef.current) return;\n \n // Only apply transforms if we actually transformed (not just clicked)\n if (!didTransformRef.current) {\n return; // Skip transform baking if it was just a click\n }\n \n const deselected = e.deselected;\n if (!deselected || deselected.length === 0) return;\n \n // Get the selection that's being cleared\n const activeObj = fabricCanvas.getActiveObject();\n if (!(activeObj instanceof fabric.ActiveSelection)) return;\n \n const selectionMatrix = activeObj.calcTransformMatrix();\n \n for (const obj of deselected) {\n const objId = getObjectId(obj);\n if (!objId || objId === '__background__') continue;\n \n // Get the absolute transform matrix (same as object:modified)\n const objOwnMatrix = obj.calcOwnMatrix();\n const absoluteMatrix = fabric.util.multiplyTransformMatrices(selectionMatrix, objOwnMatrix);\n \n // Use Fabric's built-in utility to apply the matrix\n // This is the most reliable way as it handles all edge cases\n fabric.util.applyTransformToObject(obj, absoluteMatrix);\n obj.setCoords();\n }\n });\n \n // Double-click: enter text editing for textboxes, OR enter true-crop mode for image crop groups\n fabricCanvas.on('mouse:dblclick', (e) => {\n if (!isActiveRef.current || !allowEditing) return;\n let target: fabric.FabricObject | null = e.target;\n\n // If dblclick lands on the selection border / outside the visible bbox,\n // Fabric reports `target = null`. Fall back to the active object so\n // double-clicking on an already-selected image still enters crop mode.\n if (!target) {\n const active = fabricCanvas.getActiveObject();\n if (active) target = active;\n }\n\n // Image crop group → enter crop mode (Canva/Figma style: pan + zoom inside the mask)\n if (target && target instanceof fabric.Group && (target as any).__cropGroup) {\n const ct = (target as any).__cropData;\n // Only enter for groups that actually have an image (not empty placeholders)\n if (ct?._img && !isCropGroupInCropMode(target)) {\n enterCropMode(target);\n return;\n }\n }\n\n // If click wasn't on a Textbox (e.g. selection border), use active object when it's a single Textbox\n if (!target || !(target instanceof fabric.Textbox)) {\n const active = fabricCanvas.getActiveObject();\n if (active instanceof fabric.Textbox) target = active;\n else if (active instanceof fabric.ActiveSelection && active.getObjects().length === 1 && active.getObjects()[0] instanceof fabric.Textbox) target = active.getObjects()[0];\n }\n if (target && target instanceof fabric.Textbox) {\n const elementId = getObjectId(target);\n // If inline markdown formatting is enabled, on-canvas editing is\n // disabled to protect the markdown source. Nudge the user toward\n // the right-panel text field instead.\n if ((target as any).__formattingEnabled === true || target.editable === false) {\n toast.info('Inline formatting is on — edit the text in the right panel.', {\n description: 'This protects your **bold**, [c=...] and other formatting tokens.',\n });\n return;\n }\n editingTextIdRef.current = elementId || null;\n target.enterEditing();\n target.selectAll();\n }\n });\n\n // Track when text editing starts (can also happen via keyboard). Bypass reflow debounce so layout is immediate.\n fabricCanvas.on('text:editing:entered', (e) => {\n const target = e.target;\n if (target && target instanceof fabric.Textbox) {\n const elementId = getObjectId(target);\n editingTextIdRef.current = elementId || null;\n setEditingText(true);\n }\n });\n\n // Save text content when editing is finished - only in editor mode\n // Note: We don't check isActiveRef here because text should always be saved\n // even if the user clicks to another page to finish editing\n fabricCanvas.on('text:editing:exited', (e) => {\n const target = e.target;\n if (!target || !(target instanceof fabric.Textbox)) return;\n \n const elementId = getObjectId(target);\n if (!elementId) return;\n \n // Clear the editing flag so store can use debounced reflow again\n editingTextIdRef.current = null;\n setEditingText(false);\n\n // Only update store in editor mode\n if (!allowEditing) return;\n \n // Re-initialize dimensions so Fabric has correct bounds\n target.initDimensions();\n target.setCoords();\n \n const newText = target.text || '';\n const state = useEditorStore.getState();\n const currentElement = state.getCurrentElements().find(el => el.id === elementId);\n const overflowPolicy = currentElement?.overflowPolicy || 'grow-and-push';\n \n // Use Fabric textbox bounds only - no manual measurement (store uses unscaled width/height like persistTextDimensionsAfterFontLoad)\n const fabricHeight = target.height ?? 0;\n const fabricWidth = target.width ?? 0;\n \n const { updateElement, commitHistory } = state;\n \n if (overflowPolicy === 'auto-shrink' && currentElement) {\n // Auto-shrink: keep width fixed and persist the post-shrink rendered height\n // so vertical stack siblings reflow upward correctly.\n let nextHeight: number | undefined;\n try {\n const measuredObj = createText({ ...currentElement, text: newText } as CanvasElement);\n if (measuredObj instanceof fabric.Textbox) {\n const measuredHeight = measuredObj.height ?? 0;\n if (measuredHeight > 0) {\n if (typeof currentElement.height === 'number') {\n // Never grow height for auto-shrink; only keep or shrink.\n nextHeight = Math.min(currentElement.height, measuredHeight);\n } else {\n nextHeight = measuredHeight;\n }\n }\n }\n } catch {\n // Fallback to current Fabric target height if measurement fails.\n if (\n fabricHeight > 0 &&\n typeof currentElement.height === 'number' &&\n fabricHeight < currentElement.height - 0.5\n ) {\n nextHeight = fabricHeight;\n }\n }\n updateElement(elementId, {\n text: newText,\n ...(typeof nextHeight === 'number' && nextHeight > 0 && { height: nextHeight }),\n });\n } else {\n updateElement(elementId, {\n text: newText,\n ...(fabricHeight > 0 && { height: fabricHeight }),\n ...(fabricWidth > 0 && { width: fabricWidth }),\n });\n }\n \n commitHistory();\n });\n\n return () => {\n setReady(false);\n unregisterFabricCanvas((fabricCanvas as any).__storeRegistryKey ?? pageId, fabricCanvas);\n // Remove our entry from the global window registry too. Without\n // this, an offscreen capture's disposed canvas can linger under\n // the same pageId and shadow the live preview entry.\n try {\n if (typeof window !== 'undefined') {\n const reg = (window as any).__fabricCanvasRegistry;\n if (reg instanceof Map) {\n const key = (fabricCanvas as any).__registryKey ?? pageId;\n const entry = reg.get(key);\n const entryCanvas = entry?.canvas ?? entry;\n if (entryCanvas === fabricCanvas) reg.delete(key);\n }\n }\n } catch {}\n // Clean up font loading listener\n if ((fabricCanvas as any).__fontCleanup) {\n (fabricCanvas as any).__fontCleanup();\n }\n fabricCanvas.dispose();\n fabricRef.current = null;\n };\n }, [pageId]);\n\n // === SYNC CANVAS SIZE + BACKGROUND ===\n useEffect(() => {\n const fc = fabricRef.current;\n if (!fc) return;\n\n fc.setDimensions({ width: canvasWidth, height: canvasHeight });\n\n fc.clipPath = new fabric.Rect({\n left: 0,\n top: 0,\n width: canvasWidth,\n height: canvasHeight,\n absolutePositioned: true,\n });\n\n fc.requestRenderAll();\n }, [canvasWidth, canvasHeight]);\n\n // === APPLY VIEWPORT ZOOM FOR CRISP RENDERING ===\n // This handles zoom changes AFTER initialization (init already applies initial zoom)\n useEffect(() => {\n const fc = fabricRef.current;\n if (!fc) return;\n \n const zoom = workspaceZoom || 1;\n const scaledWidth = canvasWidth * zoom;\n const scaledHeight = canvasHeight * zoom;\n \n // Update canvas dimensions to match zoomed size\n fc.setDimensions({ width: scaledWidth, height: scaledHeight });\n \n // Apply zoom via viewport transform - this gives true vector zoom\n fc.setViewportTransform([zoom, 0, 0, zoom, 0, 0]);\n \n // Keep control/handle size consistent at any zoom: inverse scale so handles stay same on-screen size\n fc.getObjects().forEach((obj) => applyControlSizeForZoom(fc, obj));\n const active = fc.getActiveObject();\n if (active && active instanceof fabric.ActiveSelection) applyControlSizeForZoom(fc, active);\n fc.requestRenderAll();\n }, [workspaceZoom, canvasWidth, canvasHeight]);\n\n // === SYNC ELEMENTS TO FABRIC (keeping hidden elements on canvas but invisible) ===\n // PARITY FIX: previously preview mode bypassed the `ready` gate and ran sync\n // immediately. That meant Fabric's synchronous Textbox `initDimensions` ran\n // before `initFonts()` had injected/loaded non-local Google fonts (e.g.\n // Bungee Shade), measuring against a system fallback whose narrower glyphs\n // made multi-line text fit on one line at the saved size — producing the\n // \"no wrap in preview, wraps in builder\" disparity. Gate on `ready` for\n // both modes so the first sync always measures with real font metrics.\n useEffect(() => {\n const fc = fabricRef.current;\n if (!fc) return;\n if (!ready) {\n hasClearedCachesBeforeFirstSyncRef.current = false;\n return;\n }\n \n // Check if this is a visibility-only update batch BEFORE creating sync function\n // This helps detect group visibility toggles\n const currentFabricObjectsMap = new Map<string, fabric.FabricObject>();\n fc.getObjects().forEach((obj: fabric.FabricObject) => {\n const id = getObjId(obj);\n if (id) currentFabricObjectsMap.set(id, obj);\n });\n \n let visibilityOnlyCount = 0;\n let totalVisibilityChanges = 0;\n let hasAnyVisibilityChange = false;\n \n for (const el of elements) {\n const prevVisible = previousVisibilityRef.current.get(el.id) ?? true;\n const currVisible = el.visible !== false;\n const visibilityChanged = prevVisible !== currVisible;\n \n if (visibilityChanged) {\n hasAnyVisibilityChange = true;\n totalVisibilityChanges++;\n const existingObj = currentFabricObjectsMap.get(el.id);\n if (existingObj) {\n const positionChanged = \n Math.abs((existingObj.left ?? 0) - (el.left ?? 0)) > 0.1 ||\n Math.abs((existingObj.top ?? 0) - (el.top ?? 0)) > 0.1;\n \n if (!positionChanged) {\n visibilityOnlyCount++;\n }\n } else {\n // If object doesn't exist yet, treat as visibility-only (new elements shouldn't cause position issues)\n visibilityOnlyCount++;\n }\n }\n }\n \n // If we have visibility changes and most/all are position-only, it's likely a group visibility toggle\n // Set flag to skip updateFabricObject for all elements to prevent position recalculation\n // This is especially important when groups with subgroups are selected\n // Use a threshold: if 80%+ of visibility changes are position-only, treat as visibility batch\n // OR if we have many visibility changes (5+) and most are position-only, also treat as batch\n const visibilityBatchThreshold = hasAnyVisibilityChange && (\n (totalVisibilityChanges > 0 && visibilityOnlyCount / totalVisibilityChanges >= 0.8) ||\n (totalVisibilityChanges >= 5 && visibilityOnlyCount / totalVisibilityChanges >= 0.7)\n );\n \n if (visibilityBatchThreshold) {\n visibilityUpdateInProgressRef.current = true;\n // Reset flag after sync completes (use longer timeout for groups with many children)\n setTimeout(() => {\n visibilityUpdateInProgressRef.current = false;\n }, 200);\n } else if (!hasAnyVisibilityChange) {\n // Only reset flag if there are no visibility changes at all\n // This prevents resetting during a visibility batch\n visibilityUpdateInProgressRef.current = false;\n }\n \n // CRITICAL: Always store the sync function FIRST (before any early returns)\n // When run deferred (after unlock), use latest store so we don't overwrite with stale closure\n doSyncRef.current = () => {\n // Recalculate shouldSkipUpdates inside the function (refs may have changed)\n const shouldSkipUpdates = syncLockedRef.current || editLockRef.current;\n const state = useEditorStore.getState();\n // Use this page's elements (prop): in multi-page editor each PageCanvas gets its own elements from FabricCanvas; getCurrentElements() is the selected page only and would clear other pages when adding a new page\n const elementsToSync = elements;\n elementsRef.current = elementsToSync;\n // In editor use store for this pageId so group backgrounds and z-order see latest; in preview use prop\n const pageTree = (isPreviewMode && pageChildren?.length) ? (pageChildren ?? []) : (state.canvas.pages.find((p) => p.id === pageId)?.children ?? []);\n // selectedIds from store: skip applying position to selected elements even when SYNC runs before SELECTION_SYNC (no Fabric active object yet)\n const selectedIdsFromStore = new Set(state.canvas?.selectedIds ?? []);\n \n isRebuildingRef.current = true;\n \n // Keep ALL elements on canvas (both visible and hidden)\n const allElementIds = new Set(elementsToSync.map(el => el.id));\n\n // Section groups (top-level groups with backgroundColor) are rendered as fabric.Group so bg moves with the group\n const sectionGroups = (pageTree as CanvasNode[]).filter(\n (n): n is GroupNode => isGroup(n) && !!(n as GroupNode).backgroundColor && (n as GroupNode).backgroundColor !== 'transparent'\n );\n const sectionDescendantIds = new Set<string>();\n const sectionGroupIds = new Set<string>();\n for (const g of sectionGroups) {\n sectionGroupIds.add(g.id);\n getAllElementIds(g.children ?? []).forEach((id) => sectionDescendantIds.add(id));\n }\n const validTopLevelIds = new Set<string>(sectionGroupIds);\n allElementIds.forEach((id) => {\n if (!sectionDescendantIds.has(id)) validTopLevelIds.add(id);\n });\n\n // Helper: find object by id in canvas (top-level only; nested search done during group build)\n const getObjectById = (id: string): fabric.FabricObject | null =>\n fc.getObjects().find((o) => getObjectId(o) === id) ?? null;\n \n // CRITICAL: Preserve active object during sync - don't discard unless absolutely necessary\n // This prevents deselection during drag and after transforms\n const activeBeforeSync = fc.getActiveObject();\n const isTransforming = !!(fc as any)._currentTransform;\n \n // When sync was triggered by a panel update (layout/display/property change), discard selection\n // so position updates apply to loose objects (absolute coords). Otherwise setting left/top on\n // objects inside ActiveSelection uses group-relative coords and causes shift. SELECTION_SYNC\n // will re-select after this effect.\n // CRITICAL: Never discard when the active object is the Textbox being edited - that would exit editing.\n if (syncTriggeredByPanelRef.current && !shouldSkipUpdates && !isTransforming) {\n const activeObj = fc.getActiveObject();\n const activeObjId = activeObj ? getObjectId(activeObj) : null;\n const isTextBeingEdited = activeObjId && editingTextIdRef.current === activeObjId;\n if (activeObj && !((activeObj as any)._ct?.isCropGroup || (activeObj as any).__cropGroup) && !isTextBeingEdited) {\n fc.discardActiveObject();\n }\n }\n\n // Get current fabric objects\n const currentFabricObjects = new Map<string, fabric.FabricObject>();\n \n fc.getObjects().forEach((obj) => {\n const id = getObjectId(obj);\n if (id && id !== '__background__') {\n currentFabricObjects.set(id, obj);\n }\n });\n \n // Restore active object after sync if it still exists (skip when panel-driven; SELECTION_SYNC will re-select)\n // CRITICAL: Never call setActiveObject when the active object is the Textbox currently being edited - it steals focus from the hidden textarea and exits editing.\n const skipRestoreSelection = syncTriggeredByPanelRef.current;\n const activeStillOnCanvas = activeBeforeSync && fc.getObjects().includes(activeBeforeSync);\n const activeId = activeBeforeSync ? getObjectId(activeBeforeSync) : null;\n const isActiveTextBeingEdited = activeId && editingTextIdRef.current === activeId && activeBeforeSync instanceof fabric.Textbox;\n if (!skipRestoreSelection && activeBeforeSync && activeStillOnCanvas && !isActiveTextBeingEdited) {\n const isCropGroup = (activeBeforeSync as any)._ct?.isCropGroup || (activeBeforeSync as any).__cropGroup;\n const isSectionGroup = activeId && sectionGroupIds.has(activeId);\n if ((isCropGroup || !shouldSkipUpdates) && !isSectionGroup) {\n fc.setActiveObject(activeBeforeSync);\n }\n }\n\n // Remove section groups (we recreate them below so bg is part of the group)\n for (const id of sectionGroupIds) {\n const obj = fc.getObjects().find((o) => getObjectId(o) === id);\n if (obj) fc.remove(obj);\n }\n // Remove top-level objects that are no longer valid (not in validTopLevelIds)\n [...fc.getObjects()].forEach((obj) => {\n const id = getObjectId(obj);\n if (id && id !== '__background__' && !validTopLevelIds.has(id)) {\n fc.remove(obj);\n }\n });\n\n // Create section groups (fabric.Group with native backgroundColor). Use center origin so Fabric's\n // _renderBackground (fillRect -dim/2, -dim/2, dim, dim) and child layout match; we convert to/from store (top-left) on persist.\n for (const G of sectionGroups) {\n const descElements = flattenChildren(G.children ?? []);\n // Compute group visual bounds from children's absolute positions and scaled dimensions (so scaled children don't shift)\n let gw: number;\n let gh: number;\n let centerX: number;\n let centerY: number;\n let Gabs: { left: number; top: number; width: number; height: number };\n const childAbsAndBounds: Array<{ el: CanvasElement; elAbs: { left: number; top: number }; bounds: { width: number; height: number }; scaleX: number; scaleY: number }> = [];\n if (descElements.length === 0) {\n const fallback = getAbsoluteBounds(G, pageTree);\n gw = Math.max(1, fallback.width);\n gh = Math.max(1, fallback.height);\n centerX = fallback.left + gw / 2;\n centerY = fallback.top + gh / 2;\n Gabs = { left: fallback.left, top: fallback.top, width: gw, height: gh };\n } else {\n let gMinX = Infinity, gMinY = Infinity, gMaxX = -Infinity, gMaxY = -Infinity;\n for (const el of descElements) {\n const node = findNodeById(pageTree, el.id);\n const bounds = node && pageTree.length ? getNodeBounds(node, pageTree, pageBoundsOptions) : { width: el.width ?? 100, height: el.height ?? 50 };\n const w = Math.max(1, Number(bounds.width) || 100);\n const h = Math.max(1, Number(bounds.height) || 50);\n const sx = el.scaleX ?? 1;\n const sy = el.scaleY ?? 1;\n const elAbs = node ? getAbsoluteBounds(node, pageTree) : { left: el.left ?? 0, top: el.top ?? 0, width: w, height: h };\n childAbsAndBounds.push({ el, elAbs, bounds: { width: w, height: h }, scaleX: sx, scaleY: sy });\n const visW = w * sx;\n const visH = h * sy;\n gMinX = Math.min(gMinX, elAbs.left);\n gMinY = Math.min(gMinY, elAbs.top);\n gMaxX = Math.max(gMaxX, elAbs.left + visW);\n gMaxY = Math.max(gMaxY, elAbs.top + visH);\n }\n gw = Math.max(1, gMaxX - gMinX);\n gh = Math.max(1, gMaxY - gMinY);\n centerX = gMinX + gw / 2;\n centerY = gMinY + gh / 2;\n Gabs = { left: gMinX, top: gMinY, width: gw, height: gh };\n }\n const children: fabric.FabricObject[] = [];\n for (const { el, elAbs, bounds, scaleX, scaleY } of childAbsAndBounds) {\n const elForCreate = { ...el, width: bounds.width, height: bounds.height };\n const childObj = createFabricObjectForGroupMember(elForCreate);\n if (childObj) {\n const relLeft = elAbs.left - Gabs.left;\n const relTop = elAbs.top - Gabs.top;\n childObj.set({\n left: relLeft - gw / 2,\n top: relTop - gh / 2,\n visible: el.visible !== false,\n scaleX,\n scaleY,\n });\n setObjectData(childObj, el.id);\n children.push(childObj);\n }\n }\n const groupOpts: Partial<fabric.GroupProps> & { backgroundColor?: string } = {\n left: centerX,\n top: centerY,\n originX: 'center',\n originY: 'center',\n width: gw,\n height: gh,\n backgroundColor: G.backgroundColor || '#f0f0f0',\n subTargetCheck: true,\n selectable: allowSelection,\n evented: allowSelection,\n hasControls: allowEditing,\n hasBorders: allowEditing,\n };\n const sectionGroup = new fabric.Group(children, groupOpts as any);\n setObjectData(sectionGroup, G.id);\n (sectionGroup as any).__docuforgeSectionGroup = true;\n // Custom render: draw section bg with Fabric renderer (no separate rect). Center origin so fillRect matches group bounds (same as Object._renderBackground).\n const bgColor = G.backgroundColor || '#f0f0f0';\n sectionGroup._renderBackground = function (this: fabric.Group, ctx: CanvasRenderingContext2D) {\n if (!bgColor || bgColor === 'transparent') return;\n const dim = (this as any)._getNonTransformedDimensions?.() ?? { x: this.width ?? gw, y: this.height ?? gh };\n const w = dim.x ?? gw;\n const h = dim.y ?? gh;\n ctx.save();\n ctx.fillStyle = bgColor;\n ctx.fillRect(-w / 2, -h / 2, w, h);\n ctx.restore();\n };\n fc.add(sectionGroup);\n }\n\n // Add or update ALL elements (visible and hidden) — skip elements that live inside section groups\n for (const element of elementsToSync) {\n if (sectionDescendantIds.has(element.id)) continue;\n let existingObj = currentFabricObjects.get(element.id);\n \n // Determine if this element should be visible on canvas\n const isHidden = !element.visible;\n \n if (existingObj) {\n const isBeingTransformed = transformingIdsRef.current.has(element.id);\n const wasJustModified = justModifiedIdsRef.current.has(element.id);\n const isBeingTextEdited = editingTextIdRef.current === element.id;\n \n // For images, check if URL changed and reload if needed\n if (element.type === 'image') {\n const currentImageUrl = element.src || element.imageUrl || '';\n const storedImageUrl = (existingObj as any).__imageSrc;\n \n // Normalize empty values\n const currentUrlNormalized = currentImageUrl.trim();\n const storedUrlNormalized = storedImageUrl ? String(storedImageUrl).trim() : '';\n \n const hasUrl = currentUrlNormalized !== '';\n const isCropGroup = existingObj instanceof fabric.Group && (existingObj as any).__cropGroup;\n const isPlaceholderGroup = isEmptyImagePlaceholderGroup(existingObj);\n const isPlaceholder = isPlaceholderGroup || !(existingObj instanceof fabric.FabricImage) || (existingObj instanceof fabric.Group && !isCropGroup);\n\n // If URL or SVG recolor map changed, reload the image\n const svgColorMapStr = element.svgColorMap ? JSON.stringify(element.svgColorMap) : '';\n const storedColorMapStr = (existingObj as any).__svgColorMap || '';\n const colorMapChanged = svgColorMapStr !== storedColorMapStr;\n const sourceUrlChanged = currentUrlNormalized !== storedUrlNormalized;\n // Edge fade key change → must rebake bitmap\n const newFadeKey = edgeFadeKey(element as any);\n const oldFadeKey = isCropGroup\n ? ((existingObj as any).__edgeFadeInputKey || '')\n : ((existingObj as any).__edgeFadeKey || '');\n const innerImg = (existingObj as any)?.__cropData?._img;\n const innerOldKey = isCropGroup ? oldFadeKey : (innerImg ? (innerImg.__edgeFadeKey || '') : oldFadeKey);\n const cropFadeRendererMissing = isCropGroup && Boolean(newFadeKey) && !(existingObj as any).__edgeFadeRenderConfig;\n const fadeKeyChanged = newFadeKey !== oldFadeKey || newFadeKey !== innerOldKey || cropFadeRendererMissing;\n const needsReload = sourceUrlChanged || colorMapChanged || (fadeKeyChanged && !isCropGroup);\n const needsCropGroupFadeUpdate = isCropGroup && fadeKeyChanged;\n \n // If URL was removed (empty string), replace with placeholder\n // Check if we had a URL before (storedImageUrl exists and is not empty) and now we don't\n const hadUrlBefore = storedImageUrl && String(storedImageUrl).trim() !== '';\n if (!hasUrl && hadUrlBefore) {\n // For crop groups, we need to replace the entire group with a placeholder.\n // Preserve the resolved canvas bounds; mapped image fields inside groups store\n // left/top relative to the group, so using element.left/top directly shifts the\n // cleared placeholder toward the page origin.\n const resolvedSizeImg = pageChildren?.length ? getNodeBounds(element, pageChildren, pageBoundsOptions) : { width: typeof element.width === 'number' ? element.width : 200, height: typeof element.height === 'number' ? element.height : 50 };\n const hasExplicitSize =\n typeof element.width === 'number' && Number.isFinite(element.width) && element.width > 0 &&\n typeof element.height === 'number' && Number.isFinite(element.height) && element.height > 0;\n const minVisiblePlaceholder = hasExplicitSize ? 1 : 20;\n const nextWidth = Math.max(minVisiblePlaceholder, Number(resolvedSizeImg.width) || 200);\n const nextHeight = Math.max(minVisiblePlaceholder, Number(resolvedSizeImg.height) || 50);\n const storePosImg = pageChildren\n ? (() => {\n const node = findNodeById(pageChildren, element.id);\n return node ? getAbsoluteBounds(node, pageChildren) : { left: element.left ?? 0, top: element.top ?? 0 };\n })()\n : { left: element.left ?? 0, top: element.top ?? 0 };\n const elementForPlaceholder = { ...element, width: nextWidth, height: nextHeight };\n const placeholder = isCropGroup \n ? createImagePlaceholderForGroup(elementForPlaceholder)\n : createImagePlaceholder(elementForPlaceholder);\n setObjectData(placeholder, element.id);\n (placeholder as any).__imageSrc = '';\n placeholder.set({\n left: storePosImg.left + nextWidth / 2,\n top: storePosImg.top + nextHeight / 2,\n originX: 'center',\n originY: 'center',\n });\n placeholder.setCoords();\n \n const idx = fc.getObjects().indexOf(existingObj);\n fc.remove(existingObj);\n if (idx >= 0) {\n fc.insertAt(idx, placeholder);\n } else {\n fc.add(placeholder);\n }\n fc.requestRenderAll();\n continue;\n }\n \n // In preview, we may need a crop group (clipped) but currently have a plain image — replace it\n const imageFitForReplace = element.imageFit || (element as any).style?.imageFit || 'cover';\n const clipShapeForReplace = element.clipShape ?? (element as any).style?.imageFrameShape ?? (isPreviewMode ? 'rectangle' : 'none');\n const needCropGroupForElement = imageFitForReplace !== 'fill' || (clipShapeForReplace && clipShapeForReplace !== 'none');\n const plainImageNeedsCropGroup = hasUrl && !isCropGroup && existingObj instanceof fabric.FabricImage && needCropGroupForElement;\n\n if (hasUrl && (needsReload || isPlaceholder || plainImageNeedsCropGroup || needsCropGroupFadeUpdate)) {\n // CRITICAL: Only reload when not transforming (but always reload for source URL changes like background removal)\n if (needsReload && !isBeingTransformed && (!wasJustModified || sourceUrlChanged)) {\n // DO NOT update __imageSrc or __svgColorMap before loadImageAsync.\n // Crop groups use those markers to detect whether a reload is needed,\n // so mutating them here makes source changes look like no-ops.\n loadImageAsync(element, existingObj, fc);\n } else if (plainImageNeedsCropGroup) {\n // Preview (or element now has clip): replace plain image with crop group so image is clipped\n loadImageAsync(element, existingObj, fc);\n } else if ((!needsReload || needsCropGroupFadeUpdate) && isCropGroup) {\n // URL didn't change - this is just a crop/resize/zoom/clipShape update\n // Update crop group properties in place (don't reload image)\n const ct = (existingObj as any).__cropData;\n if (ct) {\n // Store is source of truth: use element width/height (with scale) so save/reload shows same size (especially when crop handles are off)\n const resolvedCrop = pageTree.length > 0 ? getNodeBounds(element, pageTree, pageBoundsOptions) : { width: typeof element.width === 'number' ? element.width : 200, height: typeof element.height === 'number' ? element.height : 50 };\n const hasExplicitCropSize =\n typeof element.width === 'number' && Number.isFinite(element.width) && element.width > 0 &&\n typeof element.height === 'number' && Number.isFinite(element.height) && element.height > 0;\n const minCropVisible = hasExplicitCropSize ? 1 : 20;\n const fallbackCropW = hasExplicitCropSize ? Number(element.width) : 200;\n const fallbackCropH = hasExplicitCropSize ? Number(element.height) : 50;\n const elementWidth = Math.max(minCropVisible, Number(resolvedCrop.width) || fallbackCropW) * (element.scaleX ?? 1);\n const elementHeight = Math.max(minCropVisible, Number(resolvedCrop.height) || fallbackCropH) * (element.scaleY ?? 1);\n // Always push store dimensions into crop frame so saved state matches after reload\n ct.frameW = elementWidth;\n ct.frameH = elementHeight;\n // Check if clipShape changed - if so, we need to update clipPath\n const clipShape = element.clipShape || 'none';\n const newShape = clipShape === 'circle' ? 'circle' : clipShape === 'rounded' ? 'roundRect' : 'rect';\n const shapeChanged = ct.shape !== newShape;\n \n // Update shape and rx if changed\n if (shapeChanged || element.clipShape !== undefined) {\n ct.shape = newShape;\n // CRITICAL: Only use rx if clipShape is 'rounded', otherwise set to 0\n // rx is stored as ratio (0-0.5), convert old pixel values if needed\n let rxRatio = 0;\n if (clipShape === 'rounded') {\n const elementRx = element.rx || 0.1; // Default to 10% if not set\n // If rx > 0.5, it's likely an old pixel value, convert to ratio\n if (elementRx > 0.5) {\n const minDim = Math.min(elementWidth, elementHeight);\n rxRatio = Math.min(elementRx / minDim, 0.5); // Cap at 50%\n } else {\n rxRatio = elementRx;\n }\n }\n ct.rx = rxRatio;\n }\n \n // Update group position/angle/opacity if changed (use absolute when pageChildren provided)\n const cropPos = pageChildren ? (() => {\n const node = findNodeById(pageChildren, element.id);\n return node ? getAbsoluteBounds(node, pageChildren) : { left: element.left ?? 0, top: element.top ?? 0 };\n })() : { left: element.left ?? 0, top: element.top ?? 0 };\n // Crop groups use center origin — convert top-left to center\n const cropCenterX = cropPos.left + (ct.frameW ?? 0) / 2;\n const cropCenterY = cropPos.top + (ct.frameH ?? 0) / 2;\n if (element.left !== undefined) existingObj.set({ left: cropCenterX });\n if (element.top !== undefined) existingObj.set({ top: cropCenterY });\n if (element.angle !== undefined) existingObj.set({ angle: element.angle });\n // CRITICAL: Apply flips on crop-group itself (this is the rendered object on canvas)\n existingObj.set({\n flipX: element.flipX ?? false,\n flipY: element.flipY ?? false,\n });\n // CRITICAL: Always update opacity (even if 1.0) to ensure it's applied correctly\n // Clamp opacity to valid range [0, 1]\n const clampedOpacity = element.opacity !== undefined \n ? Math.max(0, Math.min(1, element.opacity)) \n : 1;\n existingObj.set({ opacity: clampedOpacity });\n \n // Update group dimensions to match frame\n existingObj.set({ width: ct.frameW, height: ct.frameH });\n \n // Use transparent so PNG/SVG transparent pixels show through (no white fill)\n existingObj.set({ backgroundColor: 'transparent' });\n \n // CRITICAL: Detect SVG mask removal — if the live clipPath is an SVG mask\n // but the schema no longer has maskSvgUrl, strip it before any layout update.\n const liveMask = (existingObj as any).clipPath;\n const liveMaskUrl = (existingObj as any).__svgMaskUrl;\n const liveMaskType = (existingObj as any).__svgMaskType;\n const schemaMaskUrl = (element as any).maskSvgUrl;\n const schemaMaskType = (element as any).maskType || 'shape';\n if (liveMask && (liveMask as any).__svgMask && !schemaMaskUrl) {\n existingObj.clipPath = undefined;\n delete (existingObj as any).__svgMaskUrl;\n delete (existingObj as any).__svgMaskType;\n (existingObj as any).dirty = true;\n } else if (\n schemaMaskUrl &&\n (schemaMaskUrl !== liveMaskUrl || schemaMaskType !== liveMaskType)\n ) {\n // Schema mask changed (or just got applied/swapped mode) — re-apply async.\n import('@/lib/svgMaskApply').then(({ applyMaskToCropGroup }) => {\n applyMaskToCropGroup(existingObj, schemaMaskUrl, schemaMaskType).catch(() => {});\n });\n }\n\n // CRITICAL: If clipShape changed, recreate clipPath\n if (shapeChanged) {\n const needsNewClipPath = \n !existingObj.clipPath ||\n (newShape === 'circle' && !(existingObj.clipPath instanceof fabric.Ellipse)) ||\n (newShape !== 'circle' && !(existingObj.clipPath instanceof fabric.Rect));\n \n if (needsNewClipPath) {\n const rx = ct.rx || 0;\n const newClip = newShape === 'circle'\n ? new fabric.Ellipse({\n rx: ct.frameW / 2,\n ry: ct.frameH / 2,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n })\n : new fabric.Rect({\n width: ct.frameW,\n height: ct.frameH,\n rx: rx,\n ry: rx,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n (newClip as any).absolutePositioned = false;\n (newClip as any).excludeFromExport = true;\n existingObj.clipPath = newClip;\n }\n }\n \n // Reapply layout (this handles zoom/pan and updates clipPath geometry)\n updateCoverLayout(existingObj);\n applyEdgeFadeFrameClipPath(existingObj, element, ct.frameW, ct.frameH, ct.shape || 'rect', ct.rx || 0);\n \n // CRITICAL: In preview mode, disable controls and borders for crop groups\n // In editor mode always install Canva-style controls (corners=scale, sides=crop)\n if (allowEditing) {\n installCanvaMaskControls(existingObj);\n } else {\n // Preview mode - disable all controls and borders\n existingObj.set({\n hasControls: false,\n hasBorders: false,\n selectable: false,\n evented: isPreviewMode && dynamicFieldIds.includes(element.id), // Only allow click if dynamic field\n });\n }\n \n // CRITICAL: Force immediate render to show clip shape and opacity changes\n existingObj.setCoords();\n (existingObj as any).dirty = true;\n if (existingObj.clipPath) {\n (existingObj.clipPath as any).dirty = true;\n }\n fc.requestRenderAll();\n }\n continue; // Skip to next element, don't exit the entire sync function\n }\n } else if (!hasUrl && !isPlaceholder) {\n // If URL was removed, replace image with placeholder\n // Keep explicit tiny dimensions (e.g. PDF bullets/borders) instead of forcing 20px.\n const resolvedSizeImg = pageChildren?.length ? getNodeBounds(element, pageChildren, pageBoundsOptions) : { width: typeof element.width === 'number' ? element.width : 200, height: typeof element.height === 'number' ? element.height : 50 };\n const hasExplicitSize =\n typeof element.width === 'number' && Number.isFinite(element.width) && element.width > 0 &&\n typeof element.height === 'number' && Number.isFinite(element.height) && element.height > 0;\n const minVisiblePlaceholder = hasExplicitSize ? 1 : 20;\n const elementForPlaceholder = {\n ...element,\n width: Math.max(minVisiblePlaceholder, Number(resolvedSizeImg.width) || 200),\n height: Math.max(minVisiblePlaceholder, Number(resolvedSizeImg.height) || 50),\n };\n const placeholder = createImagePlaceholder(elementForPlaceholder);\n setObjectData(placeholder, element.id);\n \n const isDynamicField = dynamicFieldIds.includes(element.id);\n const canBeEvented = isEditorMode || (isPreviewMode && isDynamicField);\n \n placeholder.set({\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n selectable: allowSelection && !isHidden,\n evented: canBeEvented && !isHidden,\n hasControls: allowEditing && !isHidden,\n hasBorders: allowEditing && !isHidden,\n hoverCursor: isDynamicField && isPreviewMode ? 'pointer' : undefined,\n });\n \n const idx = fc.getObjects().indexOf(existingObj);\n fc.remove(existingObj);\n if (idx >= 0) {\n fc.insertAt(idx, placeholder);\n } else {\n fc.add(placeholder);\n }\n (placeholder as any).__imageSrc = undefined;\n } else if (!isBeingTransformed && !isBeingTextEdited && !shouldSkipUpdates) {\n if (isPlaceholderGroup) {\n const storePosImg = pageChildren\n ? (() => {\n const node = findNodeById(pageChildren, element.id);\n return node ? getAbsoluteBounds(node, pageChildren) : { left: element.left ?? 0, top: element.top ?? 0 };\n })()\n : { left: element.left ?? 0, top: element.top ?? 0 };\n const resolvedSizeImg = pageChildren?.length\n ? getNodeBounds(element, pageChildren, pageBoundsOptions)\n : { width: typeof element.width === 'number' ? element.width : 200, height: typeof element.height === 'number' ? element.height : 50 };\n const hasExplicitSize =\n typeof element.width === 'number' && Number.isFinite(element.width) && element.width > 0 &&\n typeof element.height === 'number' && Number.isFinite(element.height) && element.height > 0;\n const minVisiblePlaceholder = hasExplicitSize ? 1 : 20;\n const nextWidth = Math.max(minVisiblePlaceholder, Number(resolvedSizeImg.width) || 200);\n const nextHeight = Math.max(minVisiblePlaceholder, Number(resolvedSizeImg.height) || 50);\n const isDynamicField = dynamicFieldIds.includes(element.id);\n const canBeEvented = isEditorMode || (isPreviewMode && isDynamicField);\n\n updateEmptyPlaceholderLayout(existingObj, nextWidth, nextHeight);\n existingObj.set({\n left: storePosImg.left + nextWidth / 2,\n top: storePosImg.top + nextHeight / 2,\n originX: 'center',\n originY: 'center',\n angle: element.angle ?? 0,\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n flipX: element.flipX ?? false,\n flipY: element.flipY ?? false,\n selectable: allowSelection && !isHidden,\n evented: canBeEvented && !isHidden,\n hasControls: allowEditing && !isHidden,\n hasBorders: allowEditing && !isHidden,\n interactive: allowEditing && !isHidden,\n subTargetCheck: false,\n lockMovementX: !allowSelection,\n lockMovementY: !allowSelection,\n hoverCursor: isDynamicField && isPreviewMode ? 'pointer' : undefined,\n });\n if (allowEditing) {\n installCanvaMaskControls(existingObj);\n }\n existingObj.setCoords();\n fc.requestRenderAll();\n continue;\n }\n\n // CRITICAL: Skip updateFabricObject for crop groups - they handle their own updates\n if (existingObj instanceof fabric.Group && (existingObj as any).__cropGroup) {\n // Crop groups are updated in place above - don't call updateFabricObject\n // But still apply flip and opacity which are safe to set on the group\n existingObj.set({\n flipX: element.flipX ?? false,\n flipY: element.flipY ?? false,\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n });\n existingObj.setCoords();\n fc.requestRenderAll();\n continue; // Skip to next element, don't exit the loop\n }\n \n // CRITICAL: For Textbox, skip updateFabricObject if it was just modified on canvas — unless sync was triggered by panel (width/height from properties panel must apply)\n if (existingObj instanceof fabric.Textbox && wasJustModified && !syncTriggeredByPanelRef.current) {\n justModifiedIdsRef.current.delete(element.id);\n continue;\n }\n \n // Also check if currently transforming (double safety)\n if (existingObj instanceof fabric.Textbox) {\n const fc = fabricRef.current;\n const isCurrentlyTransforming = fc && (fc as any)._currentTransform && \n (fc as any)._currentTransform.target === existingObj;\n \n if (isCurrentlyTransforming) {\n // Textbox is being resized - skip update completely\n continue;\n }\n }\n \n // Check if only visibility changed for images (preserve position)\n const previousVisible = previousVisibilityRef.current.get(element.id) ?? true;\n const currentVisible = element.visible !== false;\n const visibilityChanged = previousVisible !== currentVisible;\n \n // Check if position properties changed (compare with store's absolute when pageChildren provided)\n const storePosForImg = pageChildren ? (() => {\n const node = findNodeById(pageChildren, element.id);\n return node ? getAbsoluteBounds(node, pageChildren) : { left: element.left ?? 0, top: element.top ?? 0 };\n })() : { left: element.left ?? 0, top: element.top ?? 0 };\n const positionChanged = \n Math.abs((existingObj.left ?? 0) - storePosForImg.left) > 0.1 ||\n Math.abs((existingObj.top ?? 0) - storePosForImg.top) > 0.1;\n \n // If visibility changed and position didn't, OR if we're in a visibility batch update,\n // skip updateFabricObject to preserve position\n if ((visibilityChanged && !positionChanged) || visibilityUpdateInProgressRef.current) {\n // Only visibility changed - skip updateFabricObject to preserve position\n const isDynamicField = dynamicFieldIds.includes(element.id);\n const canBeEvented = isEditorMode || (isPreviewMode && isDynamicField);\n \n existingObj.set({\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n selectable: allowSelection && !isHidden,\n evented: canBeEvented && !isHidden,\n hasControls: allowEditing && !isHidden,\n hasBorders: allowEditing && !isHidden,\n hoverCursor: isDynamicField && isPreviewMode ? 'pointer' : undefined,\n });\n \n // Don't call setCoords() to avoid position recalculation\n previousVisibilityRef.current.set(element.id, currentVisible);\n } else {\n // Normal update for images (position, scale, etc.)\n // BUT: if visibility batch is in progress, still skip updateFabricObject to preserve position\n if (!visibilityUpdateInProgressRef.current) {\n updateFabricObject(existingObj, element, wasJustModified);\n }\n \n // Set visibility and interaction properties based on mode\n const isDynamicField = dynamicFieldIds.includes(element.id);\n const canBeEvented = isEditorMode || (isPreviewMode && isDynamicField);\n \n existingObj.set({\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n selectable: allowSelection && !isHidden,\n evented: canBeEvented && !isHidden,\n hasControls: allowEditing && !isHidden,\n hasBorders: allowEditing && !isHidden,\n hoverCursor: isDynamicField && isPreviewMode ? 'pointer' : undefined,\n });\n \n // Only call setCoords if not in visibility batch (to preserve position)\n if (!visibilityUpdateInProgressRef.current) {\n existingObj.setCoords();\n }\n previousVisibilityRef.current.set(element.id, currentVisible);\n }\n }\n } else {\n // Skip updating if being actively transformed, was just modified, or is being text-edited\n // (to prevent sync from interrupting user interaction) - only in editor mode\n // Also skip if sync is locked (but still allow adding new elements)\n if (!isBeingTransformed && !isBeingTextEdited && !shouldSkipUpdates) {\n // Check if only visibility changed (preserve position)\n const previousVisible = previousVisibilityRef.current.get(element.id) ?? true;\n const currentVisible = element.visible !== false;\n const visibilityChanged = previousVisible !== currentVisible;\n \n // Check if position properties changed (compare Fabric absolute with store's absolute when pageChildren provided)\n const fabricLeft = existingObj.left ?? 0;\n const fabricTop = existingObj.top ?? 0;\n const storePos = pageChildren ? (() => {\n const node = findNodeById(pageChildren, element.id);\n return node ? getAbsoluteBounds(node, pageChildren) : { left: element.left ?? 0, top: element.top ?? 0 };\n })() : { left: element.left ?? 0, top: element.top ?? 0 };\n const storeLeft = storePos.left;\n const storeTop = storePos.top;\n const deltaX = Math.abs(fabricLeft - storeLeft);\n const deltaY = Math.abs(fabricTop - storeTop);\n let positionChanged = deltaX > 0.1 || deltaY > 0.1;\n \n // CRITICAL: Don't overwrite Fabric position from store when this object is selected (Fabric active or store selectedIds).\n // SYNC can run before SELECTION_SYNC, so fc.getActiveObject() may be null; use store selectedIds so we still skip (flat group shift fix).\n const activeObj = fc.getActiveObject();\n const isInActiveSelection = activeObj &&\n (activeObj instanceof fabric.ActiveSelection\n ? activeObj.getObjects().includes(existingObj)\n : activeObj === existingObj);\n const isInSelectedIds = selectedIdsFromStore.has(element.id);\n const isSelected = isInActiveSelection || isInSelectedIds;\n // Only trust Fabric position for selected objects when user just dragged/transformed\n // (so layout recalc from properties panel still applies in real time)\n if (positionChanged && isSelected && (wasJustModified || isBeingTransformed)) {\n positionChanged = false; // Trust Fabric position during/after user drag\n }\n \n // Check if other properties changed (excluding position) - use resolved size when element has auto/inherit\n const resolvedSizeForCompare = pageChildren?.length ? getNodeBounds(element, pageChildren, pageBoundsOptions) : { width: typeof element.width === 'number' ? element.width : 0, height: typeof element.height === 'number' ? element.height : 0 };\n const fabricText = (existingObj as any).text ?? '';\n const storeText = (element as any).text ?? '';\n const otherPropsChanged =\n Math.abs((existingObj.width ?? 0) - resolvedSizeForCompare.width) > 0.1 ||\n Math.abs((existingObj.height ?? 0) - resolvedSizeForCompare.height) > 0.1 ||\n Math.abs((existingObj.angle ?? 0) - (element.angle ?? 0)) > 0.1 ||\n Math.abs((existingObj.scaleX ?? 1) - (element.scaleX ?? 1)) > 0.01 ||\n Math.abs((existingObj.scaleY ?? 1) - (element.scaleY ?? 1)) > 0.01 ||\n (existingObj.flipX ?? false) !== (element.flipX ?? false) ||\n (existingObj.flipY ?? false) !== (element.flipY ?? false) ||\n fabricText !== storeText ||\n (existingObj.fill as string) !== (element.fill ?? '') ||\n (existingObj.stroke as string) !== (element.stroke ?? '') ||\n Math.abs((existingObj.strokeWidth ?? 0) - (element.strokeWidth ?? 0)) > 0.01 ||\n Math.abs((existingObj.opacity ?? 1) - (element.opacity ?? 1)) > 0.01 ||\n ((existingObj as any).fontSize ?? 0) !== (element.fontSize ?? 0) ||\n ((existingObj as any).fontFamily ?? '') !== (element.fontFamily ?? '') ||\n // Vertical alignment & min box height: panel-driven changes must trigger a re-apply\n // so _getTopOffset (verticalAlign) and calcTextHeight (minBoxHeight) repaint correctly.\n (((existingObj as any).verticalAlign ?? 'top') !== ((element as any).verticalAlign ?? 'top')) ||\n (Math.abs(((existingObj as any).minBoxHeight ?? 0) - ((element as any).minBoxHeight ?? 0)) > 0.1) ||\n // Detect text background + shadow changes so panel edits flow into Fabric.\n JSON.stringify({\n c: (element as any).textBgColor ?? null,\n p: (element as any).textBgPadding ?? 0,\n pt: (element as any).textBgPaddingTop ?? null,\n pr: (element as any).textBgPaddingRight ?? null,\n pb: (element as any).textBgPaddingBottom ?? null,\n pl: (element as any).textBgPaddingLeft ?? null,\n tl: (element as any).textBgRxTL ?? 0,\n tr: (element as any).textBgRxTR ?? 0,\n br: (element as any).textBgRxBR ?? 0,\n bl: (element as any).textBgRxBL ?? 0,\n ft: (element as any).textBgFitToText === true,\n bo: (element as any).textBgOpacity ?? 1,\n sc: (element as any).textShadowColor ?? null,\n sb: (element as any).textShadowBlur ?? 0,\n sx: (element as any).textShadowOffsetX ?? 0,\n sy: (element as any).textShadowOffsetY ?? 0,\n st: (element as any).textShadowAffectsText !== false,\n sa: (element as any).textShadowAffectsBg !== false,\n }) !== ((existingObj as any).__lastTextBgShadowJson ?? '') ||\n // CRITICAL: Detect gradient fill/stroke changes — serialise to JSON for deep comparison\n JSON.stringify((element as any).fillGradient || null) !== ((existingObj as any).__lastFillGradientJson ?? 'null') ||\n JSON.stringify((element as any).strokeGradient || null) !== ((existingObj as any).__lastStrokeGradientJson ?? 'null');\n \n // When sync was triggered by panel, always apply store → Fabric so every element (incl. 2nd text) syncs\n const forceApplyFromPanel = syncTriggeredByPanelRef.current;\n \n // CRITICAL: If position didn't change AND no other significant properties changed,\n // preserve current Fabric object position completely (unless panel-driven)\n const noPropsOrPositionChanged = !positionChanged && !otherPropsChanged;\n if ((noPropsOrPositionChanged && !forceApplyFromPanel) || visibilityUpdateInProgressRef.current) {\n // Only visibility changed, not position - skip updateFabricObject to preserve position\n const isDynamicField = dynamicFieldIds.includes(element.id);\n const canBeEvented = isEditorMode || (isPreviewMode && isDynamicField);\n \n existingObj.set({\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n selectable: allowSelection && !isHidden,\n evented: canBeEvented && !isHidden,\n hasControls: allowEditing && !isHidden,\n hasBorders: allowEditing && !isHidden,\n hoverCursor: isDynamicField && isPreviewMode ? 'pointer' : undefined,\n });\n \n // Don't call setCoords() to avoid position recalculation\n // Update visibility tracking\n previousVisibilityRef.current.set(element.id, currentVisible);\n } else {\n // Normal update for other property changes\n // When isSelected and store position differs and user just dragged, apply all props but preserve Fabric position\n const skipPositionBecauseSelection = isSelected && (deltaX > 0.1 || deltaY > 0.1) && (wasJustModified || isBeingTransformed);\n const anyChange = positionChanged || otherPropsChanged || forceApplyFromPanel;\n if (!visibilityUpdateInProgressRef.current) {\n if (anyChange && !skipPositionBecauseSelection) {\n updateFabricObject(existingObj, element, wasJustModified);\n if (wasJustModified) justModifiedIdsRef.current.delete(element.id);\n } else if (skipPositionBecauseSelection && anyChange) {\n // In selection and store position differs: apply all panel props but preserve Fabric position (user's drag)\n const savedLeft = existingObj.left;\n const savedTop = existingObj.top;\n updateFabricObject(existingObj, element, true);\n existingObj.set({ left: savedLeft, top: savedTop });\n existingObj.setCoords();\n if (wasJustModified) justModifiedIdsRef.current.delete(element.id);\n const isDynamicField = dynamicFieldIds.includes(element.id);\n const canBeEvented = isEditorMode || (isPreviewMode && isDynamicField);\n existingObj.set({\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n selectable: allowSelection && !isHidden,\n evented: canBeEvented && !isHidden,\n hasControls: allowEditing && !isHidden,\n hasBorders: allowEditing && !isHidden,\n hoverCursor: isDynamicField && isPreviewMode ? 'pointer' : undefined,\n });\n previousVisibilityRef.current.set(element.id, currentVisible);\n } else {\n // Position and other props didn't change - just update non-position properties\n // This prevents shift when only selection or UI state changes\n const isDynamicField = dynamicFieldIds.includes(element.id);\n const canBeEvented = isEditorMode || (isPreviewMode && isDynamicField);\n \n existingObj.set({\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n selectable: allowSelection && !isHidden,\n evented: canBeEvented && !isHidden,\n hasControls: allowEditing && !isHidden,\n hasBorders: allowEditing && !isHidden,\n hoverCursor: isDynamicField && isPreviewMode ? 'pointer' : undefined,\n // Preserve current position - don't update left/top\n });\n // Don't call setCoords() to preserve position\n }\n }\n \n // Set visibility and interaction properties based on mode\n const isDynamicField = dynamicFieldIds.includes(element.id);\n const canBeEvented = isEditorMode || (isPreviewMode && isDynamicField);\n \n existingObj.set({\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n selectable: allowSelection && !isHidden,\n evented: canBeEvented && !isHidden,\n hasControls: allowEditing && !isHidden,\n hasBorders: allowEditing && !isHidden,\n hoverCursor: isDynamicField && isPreviewMode ? 'pointer' : undefined,\n });\n \n // Only call setCoords if position actually changed (to avoid unnecessary recalculation)\n if (!visibilityUpdateInProgressRef.current && positionChanged) {\n existingObj.setCoords();\n }\n // Update visibility tracking\n previousVisibilityRef.current.set(element.id, currentVisible);\n }\n }\n }\n // Only clear just-modified when we actually applied an update (above); never clear when we skipped (preserves skip on next sync)\n } else {\n // Add new element\n if (element.type === 'image') {\n // Resolve width/height for auto/inherit so placeholder and loadImageAsync have correct dimensions.\n // Preserve explicit tiny sizes for precise imported vectors (borders, bullets, dividers).\n const resolvedSizeImg = pageTree.length > 0 ? getNodeBounds(element, pageTree, pageBoundsOptions) : { width: typeof element.width === 'number' ? element.width : 200, height: typeof element.height === 'number' ? element.height : 50 };\n const hasExplicitSize =\n typeof element.width === 'number' && Number.isFinite(element.width) && element.width > 0 &&\n typeof element.height === 'number' && Number.isFinite(element.height) && element.height > 0;\n const minVisibleImage = hasExplicitSize ? 1 : 20;\n const elementForImage = {\n ...element,\n width: Math.max(minVisibleImage, Number(resolvedSizeImg.width) || 200),\n height: Math.max(minVisibleImage, Number(resolvedSizeImg.height) || 50),\n };\n const placeholder = createImagePlaceholder(elementForImage);\n setObjectData(placeholder, element.id);\n \n // CRITICAL: Apply absolute position from page tree (same as non-image elements)\n // createImagePlaceholder uses element.left/top which may be relative; resolve to absolute\n const absPosImg = pageTree.length > 0 ? (() => {\n const node = findNodeById(pageTree, element.id);\n return node ? getAbsoluteBounds(node, pageTree) : { left: element.left ?? 0, top: element.top ?? 0 };\n })() : { left: element.left ?? 0, top: element.top ?? 0 };\n const placeholderWidth = Number((placeholder.width ?? 0) * (placeholder.scaleX ?? 1));\n const placeholderHeight = Number((placeholder.height ?? 0) * (placeholder.scaleY ?? 1));\n placeholder.set({\n left: absPosImg.left + placeholderWidth / 2,\n top: absPosImg.top + placeholderHeight / 2,\n originX: 'center',\n originY: 'center',\n });\n placeholder.setCoords();\n \n // Store the image URL on the placeholder\n const imageUrl = element.src || element.imageUrl;\n (placeholder as any).__imageSrc = imageUrl;\n \n // Set visibility and interaction properties based on mode\n const isDynamicField = dynamicFieldIds.includes(element.id);\n const canBeEvented = isEditorMode || (isPreviewMode && isDynamicField);\n \n placeholder.set({\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n visible: true, // CRITICAL: Always visible when added (isHidden only affects opacity)\n selectable: allowSelection && !isHidden,\n evented: canBeEvented && !isHidden,\n hasControls: allowEditing && !isHidden,\n hasBorders: allowEditing && !isHidden,\n hoverCursor: isDynamicField && isPreviewMode ? 'pointer' : undefined,\n });\n \n // CRITICAL: Bring new elements to front so they're visible\n fc.add(placeholder);\n fc.bringObjectToFront(placeholder);\n \n // CRITICAL: Don't auto-select new elements if a crop group is active\n // This prevents selection jumping to image element\n const activeObj = fc.getActiveObject();\n if (activeObj && ((activeObj as any)._ct?.isCropGroup || (activeObj as any).__cropGroup)) {\n // Keep crop group selected, don't switch to new element\n fc.setActiveObject(activeObj);\n }\n \n // Force render to ensure element is visible\n (placeholder as any).dirty = true;\n fc.requestRenderAll();\n \n if (imageUrl) {\n loadImageAsync(elementForImage, placeholder, fc);\n }\n } else {\n // Resolve width/height for auto/inherit so created Fabric object has correct dimensions.\n // Preserve explicit tiny sizes from imports instead of forcing 20px minimum.\n const resolvedSizeCreate = pageTree.length > 0 ? getNodeBounds(element, pageTree, pageBoundsOptions) : { width: typeof element.width === 'number' ? element.width : 200, height: typeof element.height === 'number' ? element.height : 50 };\n const hasExplicitSize =\n typeof element.width === 'number' && Number.isFinite(element.width) && element.width > 0 &&\n typeof element.height === 'number' && Number.isFinite(element.height) && element.height > 0;\n const minVisibleCreate = hasExplicitSize ? 1 : 20;\n const elementForCreate = {\n ...element,\n width: Math.max(minVisibleCreate, Number(resolvedSizeCreate.width) || 200),\n height: Math.max(minVisibleCreate, Number(resolvedSizeCreate.height) || 50),\n };\n const obj = createFabricObject(elementForCreate);\n if (obj) {\n // Position: use absolute canvas coords from page tree (group children have relative in store; preview uses pageChildren prop)\n const absPos = pageTree.length > 0 ? (() => {\n const node = findNodeById(pageTree, element.id);\n return node ? getAbsoluteBounds(node, pageTree) : { left: element.left ?? 0, top: element.top ?? 0 };\n })() : { left: element.left ?? 0, top: element.top ?? 0 };\n obj.set({ left: absPos.left, top: absPos.top });\n obj.setCoords();\n // In preview/export mode, elements are not selectable/editable\n // But in preview mode, dynamic field elements can be clicked\n const isDynamicField = dynamicFieldIds.includes(element.id);\n const canBeEvented = isEditorMode || (isPreviewMode && isDynamicField);\n \n // Set visibility and interaction properties\n // CRITICAL: Ensure visible is true and opacity is correct\n obj.set({\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n visible: true, // CRITICAL: Always visible when added (isHidden only affects opacity)\n selectable: allowSelection && !isHidden,\n evented: canBeEvented && !isHidden,\n hasControls: allowEditing && !isHidden,\n hasBorders: allowEditing && !isHidden,\n hoverCursor: isDynamicField && isPreviewMode ? 'pointer' : undefined,\n });\n\n // Triangles always use caching with custom cache padding to avoid\n // low-opacity overlap artifacts while keeping sharp miter tips un-clipped.\n \n // CRITICAL: Bring new elements to front so they're visible\n fc.add(obj);\n fc.bringObjectToFront(obj);\n \n // CRITICAL: Don't auto-select new elements if a crop group is active\n // This prevents selection jumping to image element\n const activeObj = fc.getActiveObject();\n if (activeObj && ((activeObj as any)._ct?.isCropGroup || (activeObj as any).__cropGroup)) {\n // Keep crop group selected, don't switch to new element\n fc.setActiveObject(activeObj);\n }\n \n // Force render to ensure element is visible\n obj.dirty = true;\n fc.requestRenderAll();\n }\n }\n }\n }\n\n // Z-order: depth-first tree order. Section groups (fabric.Group) get their id in the list; inside groups we visit children in reverse.\n if (!shouldSkipUpdates) {\n const dfsIds: string[] = [];\n const visit = (nodes: CanvasNode[], reverseGroupChildren = false) => {\n const list = reverseGroupChildren ? [...nodes].reverse() : nodes;\n for (const n of list) {\n if (isElement(n)) dfsIds.push(n.id);\n else if (isGroup(n)) {\n const g = n as GroupNode;\n if (sectionGroupIds.has(g.id)) dfsIds.push(g.id);\n visit(g.children ?? [], true);\n }\n }\n };\n visit(pageTree, false);\n const allFabricObjects = fc.getObjects();\n allFabricObjects.sort((a, b) => {\n const aIndex = dfsIds.indexOf(getObjectId(a) || '');\n const bIndex = dfsIds.indexOf(getObjectId(b) || '');\n return aIndex - bIndex;\n });\n allFabricObjects.forEach((obj) => fc.bringObjectToFront(obj));\n }\n\n isRebuildingRef.current = false;\n \n // CRITICAL: Force render after adding new elements to ensure they're visible\n fc.requestRenderAll();\n \n // CRITICAL: If a crop group was active before sync, restore it\n // This prevents selection from jumping to newly added elements\n if (activeBeforeSync && fc.getObjects().includes(activeBeforeSync)) {\n const isCropGroup = (activeBeforeSync as any)._ct?.isCropGroup || (activeBeforeSync as any).__cropGroup;\n if (isCropGroup) {\n // Always restore crop group selection\n fc.setActiveObject(activeBeforeSync);\n fc.requestRenderAll();\n }\n }\n\n // Fabric -> store for text: use Fabric textbox bounds so layout/reflow sees correct height/width.\n // Include textboxes inside section groups (nested) so stack auto-shift and section height work.\n // Skip the textbox currently being edited - the live reflow rAF handles it.\n const stateAfterSync = useEditorStore.getState();\n const elementsAfterSync = stateAfterSync.getCurrentElements();\n const editingId = editingTextIdRef.current;\n const visitAllObjects = (fn: (obj: fabric.FabricObject) => void) => {\n fc.getObjects().forEach((obj) => {\n if (obj instanceof fabric.Group && (obj as any).__docuforgeSectionGroup) {\n obj.getObjects().forEach(fn);\n } else {\n fn(obj);\n }\n });\n };\n visitAllObjects((obj) => {\n if (obj instanceof fabric.Textbox) {\n const id = getObjectId(obj);\n if (!id || id === editingId) return;\n const w = obj.width ?? 0;\n const h = obj.height ?? 0;\n const el = elementsAfterSync.find((e) => e.id === id);\n if (!el || el.type !== 'text') return;\n const storeW = (el as CanvasElement).width;\n const storeH = (el as CanvasElement).height;\n const shouldKeepFixedHeight = el.overflowPolicy === 'auto-shrink';\n const needW = !shouldKeepFixedHeight && w > 0 && (typeof storeW !== 'number' || Math.abs(storeW - w) > 0.1);\n // Auto-shrink: allow height to shrink for proper stack reflow, but never grow\n const needH = shouldKeepFixedHeight\n ? (h > 0 && typeof storeH === 'number' && h < (storeH as number) - 0.5)\n : (h > 0 && (typeof storeH !== 'number' || Math.abs((storeH as number) - h) > 0.1));\n if (needW || needH) {\n const updates: Partial<CanvasElement> = {};\n if (needW) updates.width = w;\n if (needH) updates.height = h;\n // When sync was triggered by panel (font/size/weight change), don't run stack reflow so stored top is not reset\n stateAfterSync.updateElement(id, updates, { recordHistory: false, skipLayoutRecalc: false, skipStackReflow: syncTriggeredByPanelRef.current });\n }\n }\n });\n\n syncTriggeredByPanelRef.current = false;\n }; // End of doSyncRef.current function\n \n // When sync was triggered by a panel update (canvasUpdateVersion bumped), clear \"just modified\"\n // and mark so we discard selection before applying updates (positions apply to loose objects, no shift)\n if (canvasUpdateVersion !== prevCanvasUpdateVersionRef.current) {\n justModifiedIdsRef.current.clear();\n prevCanvasUpdateVersionRef.current = canvasUpdateVersion;\n syncTriggeredByPanelRef.current = true;\n } else {\n syncTriggeredByPanelRef.current = false;\n }\n\n // CRITICAL: Check if we should skip/defer sync\n // When locked, defer sync instead of skipping (so it runs when unlocked)\n const shouldSkipUpdates = syncLockedRef.current || editLockRef.current;\n \n // If locked, defer sync instead of skipping\n if (shouldSkipUpdates) {\n pendingSyncRef.current = true;\n return; // Defer sync, don't run it now\n }\n \n pendingSyncRef.current = false;\n if (ready && !hasClearedCachesBeforeFirstSyncRef.current) {\n hasClearedCachesBeforeFirstSyncRef.current = true;\n if (!preserveGlobalFontCache) clearFabricCharCache();\n clearMeasurementCache();\n }\n doSyncRef.current();\n \n // In preview mode, force a repaint when canvas gets non-zero size (e.g. after container measures)\n if (isPreviewMode && fc && (fc.width ?? 0) > 0 && (fc.height ?? 0) > 0) {\n fc.requestRenderAll();\n }\n \n // CRITICAL: After running sync, check if there was a pending sync that we just fulfilled\n // This handles the case where elements changed while locked, then we unlocked\n if (pendingSyncRef.current) {\n pendingSyncRef.current = false;\n }\n // In preview mode re-run sync when scale becomes non-zero (container measured), so canvas paints after resize\n }, [elements, ready, canvasUpdateVersion, ...(isPreviewMode ? [workspaceZoom] : [])]);\n\n // Run deferred sync when unlock requested (from object:modified). Keeps doSync out of setTimeout to avoid \"Maximum update depth\".\n useEffect(() => {\n if (unlockRequestId === 0) return;\n if (doSyncRef.current) doSyncRef.current();\n }, [unlockRequestId]);\n\n // Live reflow during text edit: sync Fabric textbox dimensions to store every frame so siblings move down (document-like, no overlap).\n useEffect(() => {\n if (!allowEditing || !isActive) return;\n let rafId: number;\n const tick = () => {\n const id = editingTextIdRef.current;\n if (!id) {\n lastTextEditDimensionsRef.current = null;\n rafId = requestAnimationFrame(tick);\n return;\n }\n const fc = fabricRef.current;\n if (!fc) {\n rafId = requestAnimationFrame(tick);\n return;\n }\n let obj: fabric.FabricObject | null = fc.getObjects().find((o) => getObjectId(o) === id) ?? null;\n if (!obj) {\n for (const o of fc.getObjects()) {\n if (o instanceof fabric.Group && (o as any).__docuforgeSectionGroup) {\n const found = o.getObjects().find((c) => getObjectId(c) === id);\n if (found) {\n obj = found;\n break;\n }\n }\n }\n }\n if (!(obj instanceof fabric.Textbox)) {\n rafId = requestAnimationFrame(tick);\n return;\n }\n const w = obj.width ?? 0;\n const h = obj.height ?? 0;\n const last = lastTextEditDimensionsRef.current;\n if (last?.id === id && last.w === w && last.h === h) {\n rafId = requestAnimationFrame(tick);\n return;\n }\n lastTextEditDimensionsRef.current = { id, w, h };\n if (w > 0 && h > 0) {\n const state = useEditorStore.getState();\n const currentElement = state.getCurrentElements().find((el) => el.id === id);\n const isAutoShrinkText =\n currentElement?.type === 'text' && currentElement.overflowPolicy === 'auto-shrink';\n\n if (isAutoShrinkText) {\n const storeH = currentElement.height;\n // During live editing, auto-shrink elements may momentarily report larger textbox heights.\n // Persist only shrink so vertical stack siblings never move downward by mistake.\n if (h > 0 && (typeof storeH !== 'number' || h < storeH - 0.5)) {\n state.updateElement(id, { height: h }, { recordHistory: false, skipLayoutRecalc: false });\n }\n } else {\n state.updateElement(id, { width: w, height: h }, { recordHistory: false, skipLayoutRecalc: false });\n }\n }\n rafId = requestAnimationFrame(tick);\n };\n rafId = requestAnimationFrame(tick);\n return () => cancelAnimationFrame(rafId);\n }, [allowEditing, isActive, pageId]);\n\n // === POST-READY REFLOW: run twice (2 rAFs, reflow+persist, then 2 rAFs again) to settle text metrics after fonts load ===\n useEffect(() => {\n if (!ready || hasRunPostReadyReflowForPageRef.current === pageId) return;\n hasRunPostReadyReflowForPageRef.current = pageId;\n let cancelled = false;\n const notifyReady = () => {\n if (cancelled || hasNotifiedReadyForPageRef.current === pageId) return;\n hasNotifiedReadyForPageRef.current = pageId;\n onReady?.();\n };\n const runReflowAndPersist = () => {\n const fc = fabricRef.current;\n if (!fc || cancelled) return;\n clearFontCacheAndRerender(fc, { clearGlobalCharCache: !preserveGlobalFontCache });\n const state = useEditorStore.getState();\n const page = state.canvas.pages.find((p) => p.id === pageId);\n if (page) {\n const elements = flattenChildren(page.children);\n fc.getObjects().forEach((obj) => {\n if (obj instanceof fabric.Textbox) {\n const id = getObjectId(obj);\n if (!id) return;\n const w = obj.width ?? 0;\n const h = obj.height ?? 0;\n const el = elements.find((e) => e.id === id);\n if (!el) return;\n const storeW = (el as CanvasElement).width ?? 0;\n const storeH = (el as CanvasElement).height ?? 0;\n const updates: Partial<CanvasElement> = {};\n const shouldKeepFixedSize = (el as CanvasElement).overflowPolicy === 'auto-shrink';\n // Persist width only when store has numeric width and it differs (don't overwrite 'inherit'/'auto')\n if (!shouldKeepFixedSize && w > 0 && typeof storeW === 'number' && Math.abs(w - storeW) > 0.1) updates.width = w;\n if (shouldKeepFixedSize) {\n if (h > 0 && typeof storeH === 'number' && h < storeH - 0.5) updates.height = h;\n } else {\n if (h > 0 && (typeof storeH !== 'number' || Math.abs(h - storeH) > 0.1)) updates.height = h;\n }\n if (Object.keys(updates).length > 0) {\n state.updateElement(id, updates, { recordHistory: false, skipLayoutRecalc: true });\n }\n }\n });\n }\n };\n const raf1 = requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (cancelled) return;\n runReflowAndPersist();\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (cancelled) return;\n runReflowAndPersist();\n notifyReady();\n });\n });\n });\n });\n return () => {\n cancelled = true;\n cancelAnimationFrame(raf1);\n };\n }, [ready, pageId, onReady]);\n\n // === SYNC SELECTION (Store -> Fabric) ===\n useEffect(() => {\n const fc = fabricRef.current;\n // CRITICAL: Do not rebuild while transforming (prevents deselection and recreation)\n if (!fc || isRebuildingRef.current || !isActive) return;\n if (isTransforming(fc)) return; // <-- critical guard\n \n // CRITICAL: Never touch Fabric selection when user is editing text on canvas (double-click then type).\n // Otherwise we call setActiveObject/discardActiveObject and the textbox loses focus / exits editing.\n if (editingTextIdRef.current) return;\n \n // CRITICAL: Never touch Fabric selection when editLocked (e.g. during/after group move).\n // Running SELECTION_SYNC while locked causes a second ActiveSelection + setCoords() which\n // can move objects and cause visual shift (selectedIds often has group id so hasUnselectedNewElements\n // is true and we used to allow sync - that was wrong).\n if (editLockRef.current) return;\n\n // Set flag to prevent feedback loop (Fabric selection events -> store -> Fabric)\n isSyncingSelectionToFabricRef.current = true;\n\n // Build a set of selected IDs for faster lookup.\n // When a group is selected we pass the group id only; Fabric selects the group-bounds Rect (or empty-group Rect) for native handles.\n const selectedSet = new Set(selectedIds);\n\n // Find objects to select - top-level elements, fabric.Groups, and objects inside section groups\n const toSelect: fabric.FabricObject[] = [];\n \n for (const obj of fc.getObjects()) {\n const id = getObjectId(obj);\n if (id === '__background__') continue;\n if (id && selectedSet.has(id)) {\n toSelect.push(obj);\n continue;\n }\n // Section groups: selected ids may refer to elements inside the group\n if (obj instanceof fabric.Group && (obj as any).__docuforgeSectionGroup) {\n for (const child of obj.getObjects()) {\n const childId = getObjectId(child);\n if (childId && selectedSet.has(childId)) toSelect.push(child);\n }\n }\n }\n\n // CRITICAL: Don't discard selection if sync is locked (during transform) OR if edits are locked\n if (toSelect.length === 0) {\n // CRITICAL: Don't discard if edits are locked (during handle drag)\n // Also check if clicked on an object (Fabric's findTarget)\n // BUT: Allow deselection if it's a clean click (not during transform)\n if (!syncLockedRef.current && !editLockRef.current) {\n fc.discardActiveObject();\n }\n } else if (toSelect.length === 1) {\n const objId = getObjectId(toSelect[0]);\n const obj = toSelect[0];\n \n if (objId) {\n justModifiedIdsRef.current.add(objId);\n }\n fc.setActiveObject(obj);\n obj.setCoords();\n } else {\n // Flat group = multiple elements, no fabric.Group in selection.\n // setCoords() on ActiveSelection of multiple loose objects can recalc and shift positions (Fabric quirk).\n // Groups with subgroup often have a single fabric.Group, so they take the single-object path above and don't shift.\n const isFlatGroupSelection = toSelect.length > 1 && toSelect.every(o => !(o instanceof fabric.Group));\n \n // Reuse existing ActiveSelection when same set of objects — avoids recreate + setCoords() that causes shift\n const active = fc.getActiveObject();\n const sameSelection =\n active instanceof fabric.ActiveSelection &&\n active.getObjects().length === toSelect.length &&\n toSelect.every(obj => active.getObjects().includes(obj));\n \n if (sameSelection && isFlatGroupSelection) {\n // Don't recreate or call setCoords(); positions are already correct\n fc.requestRenderAll();\n } else {\n toSelect.forEach(obj => {\n const objId = getObjectId(obj);\n if (objId) justModifiedIdsRef.current.add(objId);\n });\n \n const selection = new fabric.ActiveSelection(toSelect, { canvas: fc });\n fc.setActiveObject(selection);\n // Flat group: setCoords() on ActiveSelection of loose objects can recalc and shift positions (Fabric quirk).\n // Skip it; control box may update on next interaction; avoids visual jump.\n if (!isFlatGroupSelection) {\n selection.setCoords();\n }\n }\n }\n\n fc.requestRenderAll();\n \n // Clear flag after a short delay to allow Fabric events to fire and be ignored\n requestAnimationFrame(() => {\n isSyncingSelectionToFabricRef.current = false;\n });\n }, [selectedIds, isActive, ready, elements]);\n\n // === HELPER FUNCTIONS ===\n // Note: createFabricObject and createFabricObjectForGroupMember are imported from fabricObjectCreators\n\n const updateFabricObject = (obj: fabric.FabricObject, element: CanvasElement, skipPositionUpdate = false) => {\n // CRITICAL: Do not update while transforming (prevents recreation during drag)\n const fc = fabricRef.current;\n if (fc && isTransforming(fc)) {\n return; // Skip updates during drag - prevents deselection\n }\n \n // Position for Fabric: always use absolute canvas coords. In preview use pageChildren prop; in editor use store.\n // When skipPositionUpdate (e.g. object just modified by user), don't overwrite left/top to prevent shift-after-drag.\n const currentPageTree = (pageChildren?.length ? pageChildren : useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)?.children) ?? [];\n const fabricPos = currentPageTree.length > 0\n ? (() => {\n const node = findNodeById(currentPageTree, element.id);\n return node ? getAbsoluteBounds(node, currentPageTree) : { left: element.left ?? 0, top: element.top ?? 0 };\n })()\n : { left: element.left ?? 0, top: element.top ?? 0 };\n\n // Resolved width/height for Fabric (element may have auto/inherit — resolve from parent when in group)\n const resolvedSize = currentPageTree.length > 0 ? getNodeBounds(element, currentPageTree, pageBoundsOptions) : { width: typeof element.width === 'number' ? element.width : 200, height: typeof element.height === 'number' ? element.height : 50 };\n // Keep explicit small dimensions (e.g. imported bullets/borders) while still guarding unresolved auto/inherit sizes.\n const shouldPreserveSmallSize =\n typeof element.width === 'number' && Number.isFinite(element.width) && element.width > 0 &&\n typeof element.height === 'number' && Number.isFinite(element.height) && element.height > 0;\n const minVisible = shouldPreserveSmallSize ? 1 : 20;\n const rW = Math.max(minVisible, Number(resolvedSize.width) || 200);\n const rH = Math.max(minVisible, Number(resolvedSize.height) || 50);\n const preserveCornerGeometry =\n element.type === 'shape' &&\n (element.shapeType === 'circle' || element.shapeType === 'rounded-rect' || element.shapeType === 'triangle');\n const cornerSafeW = preserveCornerGeometry ? Math.max(1, rW * Math.abs(element.scaleX ?? 1)) : rW;\n const cornerSafeH = preserveCornerGeometry ? Math.max(1, rH * Math.abs(element.scaleY ?? 1)) : rH;\n // Textbox-like container semantics: children of flex/grid must not scale; use width/height from layout so text wraps\n const parentGroup = currentPageTree.length > 0 ? findParentGroup(currentPageTree, element.id) : null;\n const isInFlexOrGridGroup = parentGroup && (getEffectiveGroupDisplay(parentGroup) === 'flex' || getEffectiveGroupDisplay(parentGroup) === 'grid');\n const effectiveScaleX = preserveCornerGeometry ? 1 : (isInFlexOrGridGroup ? 1 : (element.scaleX ?? 1));\n const effectiveScaleY = preserveCornerGeometry ? 1 : (isInFlexOrGridGroup ? 1 : (element.scaleY ?? 1));\n \n // IMPORTANT:\n // Images need special handling based on imageFit mode\n const isImage = obj instanceof fabric.FabricImage;\n const isTextbox = obj instanceof fabric.Textbox;\n \n // For images in crop groups (not \"fill\"), update group and image inside IN PLACE\n if (obj instanceof fabric.Group && (obj as any).__cropGroup) {\n const ct = (obj as any).__cropData;\n if (ct) {\n const elementWidth = rW * (element.scaleX ?? 1);\n const elementHeight = rH * (element.scaleY ?? 1);\n const clipShape = element.clipShape || 'none';\n // CRITICAL: Only use rx if clipShape is 'rounded', otherwise set to 0\n // rx is stored as a ratio (0-0.5), convert old pixel values if needed\n let rxRatio = 0;\n if (clipShape === 'rounded') {\n const elementRx = element.rx || 0.1; // Default to 10% if not set\n // If rx > 0.5, it's likely an old pixel value, convert to ratio\n if (elementRx > 0.5) {\n const minDim = Math.min(elementWidth, elementHeight);\n rxRatio = Math.min(elementRx / minDim, 0.5); // Cap at 50%\n } else {\n rxRatio = elementRx;\n }\n }\n \n // Update frame dimensions IN PLACE (no recreation)\n ct.frameW = elementWidth;\n ct.frameH = elementHeight;\n ct.shape = clipShape === 'circle' ? 'circle' : clipShape === 'rounded' ? 'roundRect' : 'rect';\n ct.rx = rxRatio; // Store as ratio\n \n // Update maintainResolution flag (default to true)\n (obj as any).__maintainResolution = element.maintainResolution !== false;\n \n // Update group position and properties IN PLACE\n // Crop groups use originX/Y 'center' in Fabric — convert top-left (getAbsoluteBounds) to center\n const centerX = fabricPos.left + elementWidth / 2;\n const centerY = fabricPos.top + elementHeight / 2;\n const cropSetProps: Record<string, unknown> = {\n width: elementWidth,\n height: elementHeight,\n scaleX: 1,\n scaleY: 1,\n angle: element.angle ?? 0,\n flipX: element.flipX ?? false,\n flipY: element.flipY ?? false,\n opacity: element.opacity ?? 1,\n evented: true,\n selectable: true,\n hasControls: true,\n hasBorders: true,\n subTargetCheck: false, // don't look inside group\n interactive: true, // CRITICAL: Keep interactive for proper control detection\n perPixelTargetFind: false,\n lockRotation: true, // Disable rotation for crop groups (simplifies resize math)\n hasRotatingPoint: false, // Hide rotation handle\n // Scale with zoom so handles stay same visual size (controls drawn in canvas pixel space)\n cornerSize: Math.max(6, Math.round(10 * (fc.getZoom() || 1))),\n borderScaleFactor: fc.getZoom() || 1,\n transparentCorners: false,\n cornerStyle: 'rect',\n cornerColor: '#ffffff',\n cornerStrokeColor: '#4f46e5',\n borderColor: '#4f46e5',\n padding: 0,\n };\n if (!skipPositionUpdate) {\n cropSetProps.left = centerX;\n cropSetProps.top = centerY;\n }\n obj.set(cropSetProps);\n \n // Ensure children are absolutely non-targetable\n const img = ct._img;\n if (img) {\n img.set({ \n evented: false, \n selectable: false, \n hasControls: false, \n hasBorders: false \n });\n }\n if (ct._border) {\n ct._border.set({ evented: false, selectable: false });\n }\n \n // Mark as crop group for promotion logic\n (obj as any)._ct = (obj as any)._ct || {};\n (obj as any)._ct.isCropGroup = true;\n \n // CRITICAL: Handle clipShape 'none' - remove clipPath\n if (clipShape === 'none') {\n obj.clipPath = undefined;\n } else {\n // Update clipPath with group-local positioning\n // CRITICAL: If clipShape changed, we may need to recreate the clipPath (Rect vs Ellipse)\n const needsNewClipPath = \n !obj.clipPath ||\n (clipShape === 'circle' && !(obj.clipPath instanceof fabric.Ellipse)) ||\n (clipShape !== 'circle' && !(obj.clipPath instanceof fabric.Rect));\n \n if (needsNewClipPath) {\n // Recreate clipPath with correct type\n const newClip = clipShape === 'circle'\n ? new fabric.Ellipse({\n rx: elementWidth / 2,\n ry: elementHeight / 2,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n })\n : new fabric.Rect({\n width: elementWidth,\n height: elementHeight,\n rx: element.rx || 0,\n ry: element.rx || 0,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n (newClip as any).absolutePositioned = false;\n (newClip as any).excludeFromExport = true;\n // CRITICAL: Set coordinates and mark as dirty to ensure proper rendering\n newClip.setCoords();\n (newClip as any).dirty = true;\n obj.clipPath = newClip;\n } else if (obj.clipPath && typeof (obj.clipPath as any).set === 'function') {\n // Update existing clipPath properties\n // CRITICAL: Force refresh to ensure rx/ry changes are rendered\n if (clipShape === 'circle') {\n const clipPathObj = obj.clipPath as fabric.FabricObject;\n clipPathObj.set({\n rx: elementWidth / 2,\n ry: elementHeight / 2,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n // CRITICAL: Make clipPath non-interactive\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n // CRITICAL: Force update coordinates and mark as dirty to ensure re-render\n clipPathObj.setCoords();\n (clipPathObj as any).dirty = true;\n } else {\n // CRITICAL: Always update rx/ry, even if it's 0 (to remove rounded corners)\n const clipPathObj = obj.clipPath as fabric.FabricObject;\n clipPathObj.set({\n width: elementWidth,\n height: elementHeight,\n rx: element.rx || 0,\n ry: element.rx || 0,\n left: 0,\n top: 0,\n originX: 'center',\n originY: 'center',\n // CRITICAL: Make clipPath non-interactive\n selectable: false,\n evented: false,\n hasControls: false,\n hasBorders: false,\n });\n // CRITICAL: Force update coordinates and mark as dirty to ensure re-render\n clipPathObj.setCoords();\n (clipPathObj as any).dirty = true;\n }\n // Ensure clipPath is group-local for live updates\n (obj.clipPath as any).absolutePositioned = false;\n (obj.clipPath as any).excludeFromExport = true;\n }\n }\n \n // CRITICAL: Update layout to apply new clipPath shape\n updateCoverLayout(obj);\n applyEdgeFadeFrameClipPath(obj, element, elementWidth, elementHeight, ct.shape || 'rect', ct.rx || 0);\n \n // CRITICAL: Force immediate render to show clip shape change\n obj.setCoords();\n (obj as any).dirty = true;\n if (obj.clipPath) {\n (obj.clipPath as any).dirty = true;\n (obj.clipPath as any).setCoords();\n }\n \n // After update, always install Canva-style controls (corners=scale, sides=crop)\n installCanvaMaskControls(obj);\n \n // CRITICAL: Ensure crop group is always selectable and evented after updates\n obj.set({\n selectable: true,\n evented: true,\n hasControls: true,\n hasBorders: true,\n interactive: true,\n subTargetCheck: false,\n });\n obj.setCoords();\n \n // CRITICAL: Force immediate render to show clip shape change in live preview\n fc.requestRenderAll();\n }\n } else if (isImage && element.imageFit && element.imageFit !== 'fill') {\n // Legacy: direct image with clipPath (shouldn't happen with new group approach)\n // Keep for backwards compatibility\n const baseScaleX = (obj as any).__cropBaseScaleX;\n const baseScaleY = (obj as any).__cropBaseScaleY;\n \n if (baseScaleX && baseScaleY) {\n const imgNaturalWidth = obj.width || 1;\n const imgNaturalHeight = obj.height || 1;\n const elementWidth = rW * (element.scaleX ?? 1);\n const elementHeight = rH * (element.scaleY ?? 1);\n \n // Keep image at fixed scale\n const scaledImageWidth = imgNaturalWidth * baseScaleX;\n const scaledImageHeight = imgNaturalHeight * baseScaleY;\n const imageLeft = fabricPos.left + (elementWidth - scaledImageWidth) / 2;\n const imageTop = fabricPos.top + (elementHeight - scaledImageHeight) / 2;\n \n obj.set({\n left: imageLeft,\n top: imageTop,\n scaleX: baseScaleX,\n scaleY: baseScaleY,\n });\n \n // Update clipPath\n const clipShape = element.clipShape || 'none';\n const cropWidth = elementWidth / baseScaleX;\n const cropHeight = elementHeight / baseScaleY;\n const clipLeft = (scaledImageWidth - elementWidth) / 2;\n const clipTop = (scaledImageHeight - elementHeight) / 2;\n \n let cropClip: fabric.FabricObject;\n if (clipShape === 'circle') {\n const radius = Math.min(cropWidth, cropHeight) / 2;\n cropClip = new fabric.Ellipse({\n left: -clipLeft / baseScaleX,\n top: -clipTop / baseScaleY,\n rx: radius,\n ry: radius,\n originX: 'left',\n originY: 'top',\n });\n } else if (clipShape === 'rounded') {\n const radius = Math.min(element.rx || 16, cropWidth / 2, cropHeight / 2);\n cropClip = new fabric.Rect({\n left: -clipLeft / baseScaleX,\n top: -clipTop / baseScaleY,\n width: cropWidth,\n height: cropHeight,\n rx: radius,\n ry: radius,\n originX: 'left',\n originY: 'top',\n });\n } else {\n cropClip = new fabric.Rect({\n left: -clipLeft / baseScaleX,\n top: -clipTop / baseScaleY,\n width: cropWidth,\n height: cropHeight,\n originX: 'left',\n originY: 'top',\n });\n }\n obj.clipPath = cropClip;\n }\n }\n \n const baseScaleX = isImage && element.imageFit === 'fill' ? (rW / ((obj.width ?? 1) || 1)) : 1;\n const baseScaleY = isImage && element.imageFit === 'fill' ? (rH / ((obj.height ?? 1) || 1)) : 1;\n\n // Line: set length from width, no scaleY/skew so it stays horizontal (no slant)\n const isLine = obj instanceof fabric.Line;\n if (isLine) {\n const lineLen = Math.max(1, Number(element.width) || rW || 100);\n const lineSet: Record<string, unknown> = {\n x1: 0,\n y1: 0,\n x2: lineLen,\n y2: 0,\n angle: element.angle ?? 0,\n scaleX: 1,\n scaleY: 1,\n skewX: 0,\n skewY: 0,\n };\n if (!skipPositionUpdate) {\n lineSet.left = fabricPos.left;\n lineSet.top = fabricPos.top;\n }\n obj.set(lineSet);\n obj.setCoords();\n }\n\n // If we have a raw transform matrix, use the stored decomposed values\n // For Line we already set position/angle/scale above; skip to avoid overwriting with slant\n if (!isLine) {\n let posIfNotSkipped: { left?: number; top?: number } = skipPositionUpdate ? {} : { left: fabricPos.left, top: fabricPos.top };\n if (!skipPositionUpdate && obj instanceof fabric.FabricImage && obj.originX === 'center') {\n const vW = rW * effectiveScaleX;\n const vH = rH * effectiveScaleY;\n posIfNotSkipped = { left: fabricPos.left + vW / 2, top: fabricPos.top + vH / 2 };\n }\n if (element.transformMatrix && element.transformMatrix.length === 6) {\n if (isTextbox) {\n obj.set({\n ...posIfNotSkipped,\n width: rW,\n scaleX: effectiveScaleX,\n scaleY: effectiveScaleY,\n angle: element.angle ?? 0,\n skewX: element.skewX ?? 0,\n skewY: element.skewY ?? 0,\n });\n } else {\n obj.set({\n ...posIfNotSkipped,\n scaleX: effectiveScaleX,\n scaleY: effectiveScaleY,\n angle: element.angle ?? 0,\n skewX: element.skewX ?? 0,\n skewY: element.skewY ?? 0,\n });\n }\n obj.setCoords();\n } else {\n if (isTextbox) {\n obj.set({\n ...posIfNotSkipped,\n width: rW,\n angle: element.angle ?? 0,\n skewX: element.skewX ?? 0,\n skewY: element.skewY ?? 0,\n scaleX: effectiveScaleX * baseScaleX,\n scaleY: effectiveScaleY * baseScaleY,\n });\n } else {\n obj.set({\n ...posIfNotSkipped,\n angle: element.angle ?? 0,\n skewX: element.skewX ?? 0,\n skewY: element.skewY ?? 0,\n scaleX: effectiveScaleX * baseScaleX,\n scaleY: effectiveScaleY * baseScaleY,\n });\n }\n }\n }\n \n // Always set these properties regardless of matrix usage\n obj.set({\n opacity: element.opacity ?? 1,\n selectable: element.selectable,\n evented: element.evented,\n hasControls: element.selectable,\n hasBorders: element.selectable,\n lockMovementX: !element.selectable,\n lockMovementY: !element.selectable,\n flipX: element.flipX ?? false,\n flipY: element.flipY ?? false,\n });\n\n if (obj instanceof fabric.Circle) {\n obj.set({\n radius: Math.min(cornerSafeW, cornerSafeH) / 2,\n fill: element.fill || 'transparent',\n stroke: element.stroke || 'transparent',\n strokeWidth: element.strokeWidth || 0,\n strokeUniform: true,\n strokeLineJoin: 'round',\n strokeLineCap: 'round',\n lockUniScaling: true,\n objectCaching: true,\n });\n } else if (obj instanceof fabric.Ellipse) {\n obj.set({ rx: rW / 2, ry: rH / 2 });\n } else if (obj instanceof fabric.Textbox) {\n const overflowPolicy = element.overflowPolicy || 'grow-and-push';\n let text = element.text || 'Text';\n let parsedStyles: Record<number, Record<number, any>> | null = null;\n if (element.formattingEnabled === true) {\n const parsed = parseTextMarkdown(text);\n text = parsed.plainText || ' ';\n parsedStyles = parsed.styles;\n }\n let fontSize = element.fontSize || 16;\n const minFontSize = element.minFontSize || 8;\n const maxLines = element.maxLines || 3;\n const storedWidth = rW > 0 ? rW : 200;\n const fixedWidth = Math.max(storedWidth, 1);\n const splitByGrapheme = overflowPolicy === 'auto-shrink'\n ? false\n : (element.splitByGrapheme ?? (element.wordWrap === 'break-word'));\n \n // For auto-shrink: keep width fixed, avoid implicit wrapping, and shrink font until text fits.\n if (overflowPolicy === 'auto-shrink') {\n // The fit-target height is the larger of the stored element\n // height and the user-dragged minBoxHeight. This lets the\n // bottom handle grow the box vertically without stretching\n // glyphs — the font shrinks to fill the larger container.\n const minBoxHForShrink = Math.max(0, Number((element as any).minBoxHeight) || 0);\n const heightBound = Math.max(rH || 0, minBoxHForShrink);\n while (fontSize > 1) {\n const testTextbox = new fabric.Textbox(text, {\n width: fixedWidth,\n fontSize,\n fontFamily: element.fontFamily || 'Open Sans',\n fontWeight: element.fontWeight as number || 400,\n fontStyle: element.fontStyle || 'normal',\n lineHeight: element.lineHeight || 1.2,\n charSpacing: element.charSpacing || 0,\n splitByGrapheme: element.splitByGrapheme ?? false,\n });\n testTextbox.initDimensions();\n \n const textHeight = testTextbox.height || 0;\n // Auto-shrink: allow word wrap by width. Shrink font size until the\n // wrapped text height fits the textbox height. Width fit covers the\n // single-very-long-word case where wrapping alone can't help.\n const fitsHeight = heightBound <= 0 || textHeight <= heightBound;\n // Also check that no line overflows the fixed width (single long word case).\n // Use canvas metrics rather than Fabric's cached __lineWidths, matching\n // the underline fidelity fix where stale Fabric text caches caused width drift.\n const { fitsWidth } = getTextboxWidthFitMetrics(testTextbox, fixedWidth);\n\n if (fitsHeight && fitsWidth) {\n break;\n }\n fontSize--;\n }\n }\n \n // For max-lines-ellipsis: truncate text to fit max lines\n if (overflowPolicy === 'max-lines-ellipsis') {\n const testTextbox = new fabric.Textbox(element.text || 'Text', {\n width: rW,\n fontSize,\n fontFamily: element.fontFamily || 'Open Sans',\n lineHeight: element.lineHeight || 1.2,\n splitByGrapheme,\n });\n testTextbox.initDimensions();\n \n const lines = testTextbox.textLines || [];\n if (lines.length > maxLines) {\n const originalText = element.text || 'Text';\n \n // Helper to count lines for a given text\n const countLines = (testText: string): number => {\n const tb = new fabric.Textbox(testText, {\n width: rW,\n fontSize,\n fontFamily: element.fontFamily || 'Open Sans',\n lineHeight: element.lineHeight || 1.2,\n splitByGrapheme,\n });\n tb.initDimensions();\n return tb.textLines?.length || 1;\n };\n \n // Binary search for the right cutoff point\n let low = 0;\n let high = originalText.length;\n let result = originalText;\n \n while (low < high) {\n const mid = Math.floor((low + high + 1) / 2);\n const testText = originalText.slice(0, mid) + '...';\n const lineCount = countLines(testText);\n \n if (lineCount <= maxLines) {\n low = mid;\n result = testText;\n } else {\n high = mid - 1;\n }\n }\n \n // Trim trailing spaces before ellipsis\n if (result.endsWith('...') && result.length > 3) {\n const beforeEllipsis = result.slice(0, -3).trimEnd();\n result = beforeEllipsis + '...';\n }\n \n text = result;\n }\n }\n \n // Keep the saved textbox width in preview/editor updates too.\n // `createText()` already preserves this width, but this update path used\n // to expand non-auto-shrink text to the longest unwrapped line. On the\n // use-package live preview, zoom/container changes hit this path after\n // first mount and widened \"Deekshant Malvi\" into one line, while the\n // builder stayed constrained/wrapped. Width must be data-driven, not\n // recalculated from min text width, for canvas parity.\n const textboxWidth = fixedWidth;\n obj.set({\n width: textboxWidth,\n minWidth: 1,\n dynamicMinWidth: 0,\n fontSize,\n fontFamily: element.fontFamily || 'Open Sans',\n fill: element.fill || '#1a1a1a',\n fontWeight: (element.fontWeight as number) || 400,\n textAlign: (element.textAlign as any) || 'left',\n fontStyle: element.fontStyle || 'normal',\n underline: element.underline ?? false,\n linethrough: element.linethrough ?? false,\n lineHeight: element.lineHeight || 1.2,\n charSpacing: element.charSpacing || 0,\n objectCaching: false,\n noScaleCache: true,\n splitByGrapheme,\n text,\n });\n\n // Apply our custom Textbox extensions (see src/lib/fabricTextboxExtensions.ts).\n // These must be set BEFORE initDimensions() so calcTextHeight() picks up\n // minBoxHeight, and they must be re-applied here on every panel-driven sync\n // (otherwise vertical-align changes silently no-op in the editor preview).\n // In both grow-and-push and auto-shrink modes minBoxHeight is the\n // floor for the rendered box height. In auto-shrink it doubles as\n // the fit-target (font is shrunk above to fill it without stretching).\n const valign = ((element as any).verticalAlign as 'top' | 'middle' | 'bottom') || 'top';\n const minBoxH = Math.max(0, Number((element as any).minBoxHeight) || 0);\n (obj as any).verticalAlign = valign;\n (obj as any).minBoxHeight = minBoxH;\n\n // Apply (or clear) inline-formatting per-character styles. Without this,\n // the live editor Textbox keeps stale styles or never receives the parsed\n // ones, so markdown shows as stripped plain text.\n if (element.formattingEnabled === true) {\n (obj as any).styles = parsedStyles || {};\n } else {\n (obj as any).styles = (element as any).styles || {};\n }\n\n // Re-initialize dimensions so Textbox height matches content (keeps text inside bounds)\n obj.initDimensions();\n // CRITICAL: Force-set width back after initDimensions — Fabric may shrink it,\n // causing underline/linethrough to end short of the last few characters.\n if (Math.abs((obj.width ?? 0) - textboxWidth) > 0.01) {\n (obj as any).width = textboxWidth;\n }\n (obj as any).dynamicMinWidth = 0;\n obj.setCoords();\n obj.dirty = true;\n\n // Apply text background (rounded bg + padding) and text shadow live.\n // Both helpers handle \"no config\" gracefully so existing templates render unchanged.\n try {\n applyTextBackground(obj as fabric.Textbox, extractTextBgConfig(element));\n const shadow = buildTextShadow(element);\n (obj as fabric.Textbox).set('shadow', shadow ?? null);\n // Ensure Fabric repaints — clear any internal cache and mark dirty.\n try {\n (obj as any)._cacheCanvas = null;\n (obj as any)._cacheContext = null;\n } catch {}\n (obj as any).dirty = true;\n (obj as any).setCoords?.();\n (obj as any).__lastTextBgShadowJson = JSON.stringify({\n c: element.textBgColor ?? null,\n p: element.textBgPadding ?? 0,\n pt: element.textBgPaddingTop ?? null,\n pr: element.textBgPaddingRight ?? null,\n pb: element.textBgPaddingBottom ?? null,\n pl: element.textBgPaddingLeft ?? null,\n tl: element.textBgRxTL ?? 0,\n tr: element.textBgRxTR ?? 0,\n br: element.textBgRxBR ?? 0,\n bl: element.textBgRxBL ?? 0,\n ft: (element as any).textBgFitToText === true,\n bo: (element as any).textBgOpacity ?? 1,\n sc: element.textShadowColor ?? null,\n sb: element.textShadowBlur ?? 0,\n sx: element.textShadowOffsetX ?? 0,\n sy: element.textShadowOffsetY ?? 0,\n st: (element as any).textShadowAffectsText !== false,\n sa: (element as any).textShadowAffectsBg !== false,\n });\n (obj as any).dirty = true;\n } catch (err) {\n // Non-fatal — fall through to default render.\n console.warn('[text-bg] failed to apply background/shadow', err);\n }\n } else if (!isImage && !isLine) {\n // For shapes: use resolved width/height. Circle + rounded-rect + triangle bake scale into dimensions to preserve geometry and stroke behavior.\n if (obj instanceof fabric.Circle) {\n obj.set({\n radius: Math.min(cornerSafeW, cornerSafeH) / 2,\n fill: element.fill || 'transparent',\n stroke: element.stroke || 'transparent',\n strokeWidth: element.strokeWidth || 0,\n strokeUniform: true,\n objectCaching: true,\n });\n } else if (obj instanceof fabric.Rect && element.shapeType === 'rounded-rect') {\n const toRadius = (value: number | undefined, fallback: number) =>\n Number.isFinite(value) ? Math.max(0, Number(value)) : fallback;\n const baseRx = Math.max(0, Number(element.rx ?? 0));\n const baseRy = Math.max(0, Number(element.ry ?? element.rx ?? 0));\n const hasIndividualCornerValues =\n element.rxTL != null || element.rxTR != null || element.rxBR != null || element.rxBL != null;\n const tl = toRadius(element.rxTL, baseRx);\n const tr = toRadius(element.rxTR, baseRx);\n const br = toRadius(element.rxBR, baseRx);\n const bl = toRadius(element.rxBL, baseRx);\n const hasNonUniformCorners = hasIndividualCornerValues && (tl !== tr || tr !== br || br !== bl);\n const shouldUsePath = hasNonUniformCorners;\n const rectRx = hasIndividualCornerValues ? tl : baseRx;\n const rectRy = hasIndividualCornerValues ? tl : baseRy;\n const hasRoundedCorners = shouldUsePath\n ? (tl > 0 || tr > 0 || br > 0 || bl > 0)\n : (rectRx > 0 || rectRy > 0);\n\n if (shouldUsePath) {\n const pathStr = buildRoundedRectPath(cornerSafeW, cornerSafeH, tl, tr, br, bl);\n const pathObj = new fabric.Path(pathStr, {\n fill: element.fill || 'transparent',\n stroke: element.stroke || 'transparent',\n strokeWidth: element.strokeWidth || 0,\n strokeUniform: true,\n strokeLineJoin: 'miter',\n strokeLineCap: 'butt',\n left: obj.left,\n top: obj.top,\n angle: obj.angle,\n scaleX: 1,\n scaleY: 1,\n opacity: obj.opacity,\n originX: 'left',\n originY: 'top',\n selectable: obj.selectable,\n evented: obj.evented,\n objectCaching: true,\n });\n setObjectData(pathObj, element.id);\n const fc2 = fabricRef.current;\n if (fc2) {\n const idx = fc2.getObjects().indexOf(obj);\n fc2.remove(obj);\n if (idx >= 0) {\n fc2.insertAt(idx, pathObj);\n } else {\n fc2.add(pathObj);\n }\n }\n } else {\n obj.set({\n width: cornerSafeW,\n height: cornerSafeH,\n fill: element.fill || 'transparent',\n stroke: element.stroke || 'transparent',\n strokeWidth: element.strokeWidth || 0,\n strokeUniform: true,\n strokeLineJoin: hasRoundedCorners ? 'round' : 'miter',\n strokeLineCap: hasRoundedCorners ? 'round' : 'butt',\n objectCaching: true,\n rx: rectRx,\n ry: rectRy,\n });\n }\n } else if (obj instanceof fabric.Path && element.shapeType === 'rounded-rect') {\n const toRadius = (value: number | undefined, fallback: number) =>\n Number.isFinite(value) ? Math.max(0, Number(value)) : fallback;\n const baseRx = Math.max(0, Number(element.rx ?? 0));\n const hasIndividualCornerValues =\n element.rxTL != null || element.rxTR != null || element.rxBR != null || element.rxBL != null;\n const tl = toRadius(element.rxTL, baseRx);\n const tr = toRadius(element.rxTR, baseRx);\n const br = toRadius(element.rxBR, baseRx);\n const bl = toRadius(element.rxBL, baseRx);\n const hasNonUniformCorners = hasIndividualCornerValues && (tl !== tr || tr !== br || br !== bl);\n const shouldUsePath = hasNonUniformCorners;\n // For path-based shapes, always use miter — Bezier curves handle the rounding\n\n if (!shouldUsePath) {\n const rectRadius = hasIndividualCornerValues ? tl : baseRx;\n const rectObj = new fabric.Rect({\n width: cornerSafeW,\n height: cornerSafeH,\n fill: element.fill || 'transparent',\n stroke: element.stroke || 'transparent',\n strokeWidth: element.strokeWidth || 0,\n rx: rectRadius,\n ry: rectRadius,\n strokeUniform: true,\n strokeLineJoin: rectRadius > 0 ? 'round' : 'miter',\n strokeLineCap: rectRadius > 0 ? 'round' : 'butt',\n left: obj.left,\n top: obj.top,\n angle: obj.angle,\n scaleX: 1,\n scaleY: 1,\n opacity: obj.opacity,\n originX: 'left',\n originY: 'top',\n selectable: obj.selectable,\n evented: obj.evented,\n objectCaching: true,\n });\n setObjectData(rectObj, element.id);\n const fc2 = fabricRef.current;\n if (fc2) {\n const idx = fc2.getObjects().indexOf(obj);\n fc2.remove(obj);\n if (idx >= 0) {\n fc2.insertAt(idx, rectObj);\n } else {\n fc2.add(rectObj);\n }\n }\n } else {\n const pathStr = buildRoundedRectPath(cornerSafeW, cornerSafeH, tl, tr, br, bl);\n const pathObj = new fabric.Path(pathStr, {\n fill: element.fill || 'transparent',\n stroke: element.stroke || 'transparent',\n strokeWidth: element.strokeWidth || 0,\n strokeUniform: true,\n strokeLineJoin: 'miter',\n strokeLineCap: 'butt',\n left: obj.left,\n top: obj.top,\n angle: obj.angle,\n scaleX: 1,\n scaleY: 1,\n opacity: obj.opacity,\n originX: 'left',\n originY: 'top',\n selectable: obj.selectable,\n evented: obj.evented,\n objectCaching: true,\n });\n setObjectData(pathObj, element.id);\n const fc2 = fabricRef.current;\n if (fc2) {\n const idx = fc2.getObjects().indexOf(obj);\n fc2.remove(obj);\n if (idx >= 0) {\n fc2.insertAt(idx, pathObj);\n } else {\n fc2.add(pathObj);\n }\n }\n }\n } else if (element.shapeType === 'triangle') {\n // Render triangles as Path to keep geometry consistent. In preview, disable caching to preserve sharp mitered tips.\n const rTop = Math.max(0, Number(element.triRTop ?? 0));\n const rBR = Math.max(0, Number(element.triRBR ?? 0));\n const rBL = Math.max(0, Number(element.triRBL ?? 0));\n const pathStr = buildRoundedTrianglePath(cornerSafeW, cornerSafeH, rTop, rBR, rBL);\n\n if (obj instanceof fabric.Path) {\n const newPath = new fabric.Path(pathStr);\n const newPathOffset = (newPath as any).pathOffset ?? new fabric.Point(cornerSafeW / 2, cornerSafeH / 2);\n (obj as fabric.Path).set({\n path: (newPath as any).path,\n pathOffset: newPathOffset,\n width: cornerSafeW,\n height: cornerSafeH,\n fill: element.fill || 'transparent',\n stroke: element.stroke || 'transparent',\n strokeWidth: element.strokeWidth || 0,\n strokeUniform: true,\n strokeLineJoin: 'miter',\n strokeLineCap: 'butt',\n strokeMiterLimit: TRIANGLE_STROKE_MITER_LIMIT,\n scaleX: 1,\n scaleY: 1,\n objectCaching: false,\n });\n } else {\n const pathObj = new fabric.Path(pathStr, {\n fill: element.fill || 'transparent',\n stroke: element.stroke || 'transparent',\n strokeWidth: element.strokeWidth || 0,\n strokeUniform: true,\n strokeLineJoin: 'miter',\n strokeLineCap: 'butt',\n strokeMiterLimit: TRIANGLE_STROKE_MITER_LIMIT,\n left: obj.left,\n top: obj.top,\n angle: obj.angle,\n scaleX: 1,\n scaleY: 1,\n opacity: obj.opacity,\n originX: 'left',\n originY: 'top',\n selectable: obj.selectable,\n evented: obj.evented,\n objectCaching: false,\n });\n setObjectData(pathObj, element.id);\n const fc2 = fabricRef.current;\n if (fc2) {\n const idx = fc2.getObjects().indexOf(obj);\n fc2.remove(obj);\n if (idx >= 0) fc2.insertAt(idx, pathObj);\n else fc2.add(pathObj);\n }\n }\n } else {\n // Generic shapes (backwards-compatible legacy shapes)\n obj.set({\n width: rW,\n height: rH,\n fill: element.fill || 'transparent',\n stroke: element.stroke || 'transparent',\n strokeWidth: element.strokeWidth || 0,\n strokeUniform: true,\n strokeLineJoin: 'miter',\n strokeLineCap: 'butt',\n objectCaching: true,\n });\n }\n\n // CRITICAL: Mark dirty and force render so Fabric re-renders the shape\n obj.dirty = true;\n obj.setCoords();\n const fcShape = fabricRef.current;\n if (fcShape) fcShape.renderAll();\n }\n\n // Line: always sync stroke (color) and strokeWidth (thickness) — Line uses stroke, not fill, so the 'fill' in obj block above is skipped\n if (isLine) {\n obj.set({\n stroke: element.stroke || '#1a1a1a',\n strokeWidth: typeof element.strokeWidth === 'number' ? element.strokeWidth : 2,\n strokeUniform: true,\n strokeLineCap: 'round',\n strokeLineJoin: 'round',\n ...(element.strokeDashArray && { strokeDashArray: element.strokeDashArray }),\n });\n }\n\n // === GRADIENT FILL/STROKE APPLICATION ===\n // Apply Fabric.js gradient objects when fillGradient or strokeGradient is set\n // CRITICAL: Disable objectCaching for gradient fills — Fabric's cache doesn't\n // reliably invalidate when gradient stops/colors change, causing stale renders.\n if (element.fillGradient && isGradientConfig(element.fillGradient)) {\n const objWidth = typeof obj.width === 'number' ? obj.width : rW;\n const objHeight = typeof obj.height === 'number' ? obj.height : rH;\n if (objWidth > 0 && objHeight > 0) {\n obj.set({\n fill: gradientToFabric(element.fillGradient, objWidth, objHeight),\n objectCaching: false,\n });\n (obj as any).__lastFillGradientJson = JSON.stringify(element.fillGradient);\n obj.dirty = true;\n const fcGrad = fabricRef.current;\n if (fcGrad) fcGrad.requestRenderAll();\n }\n } else {\n (obj as any).__lastFillGradientJson = 'null';\n }\n if (element.strokeGradient && isGradientConfig(element.strokeGradient)) {\n const objWidth = typeof obj.width === 'number' ? obj.width : rW;\n const objHeight = typeof obj.height === 'number' ? obj.height : rH;\n if (objWidth > 0 && objHeight > 0) {\n obj.set({\n stroke: gradientToFabric(element.strokeGradient, objWidth, objHeight),\n objectCaching: false,\n });\n (obj as any).__lastStrokeGradientJson = JSON.stringify(element.strokeGradient);\n obj.dirty = true;\n const fcGrad = fabricRef.current;\n if (fcGrad) fcGrad.requestRenderAll();\n }\n } else {\n (obj as any).__lastStrokeGradientJson = 'null';\n }\n };\n\n // Note: createShape, createText, createLine, createImagePlaceholder, etc. are imported from modules\n // Keeping loadImageAsync local as it needs component refs (fabricRef, syncLockedRef, isTransforming)\n\n // Helper function to clamp a value between min and max\n const clamp = (v: number, min: number, max: number): number => {\n return Math.max(min, Math.min(max, v));\n };\n\n const applyEdgeFadeFrameClipPath = (\n group: fabric.Group,\n element: CanvasElement,\n frameW: number,\n frameH: number,\n shape: 'circle' | 'roundRect' | 'rect',\n rxRatio: number,\n ) => {\n type EdgeFadeElement = CanvasElement & {\n fadeTopAmount?: number;\n fadeRightAmount?: number;\n fadeBottomAmount?: number;\n fadeLeftAmount?: number;\n fadeTopSize?: number;\n fadeRightSize?: number;\n fadeBottomSize?: number;\n fadeLeftSize?: number;\n fadeTopHardness?: number;\n fadeRightHardness?: number;\n fadeBottomHardness?: number;\n fadeLeftHardness?: number;\n };\n type EdgeFadeGroup = fabric.Group & {\n __edgeFadeOriginalDrawObject?: fabric.Group['drawObject'];\n __edgeFadeRenderConfig?: {\n key: string;\n frameW: number;\n frameH: number;\n topSize: number;\n topAmount: number;\n rightSize: number;\n rightAmount: number;\n bottomSize: number;\n bottomAmount: number;\n leftSize: number;\n leftAmount: number;\n topHardness: number;\n rightHardness: number;\n bottomHardness: number;\n leftHardness: number;\n };\n __edgeFadeKey?: string;\n __edgeFadeInputKey?: string;\n };\n type EdgeFadeClip = fabric.FabricObject & { __edgeFadeMask?: boolean };\n\n const fadeElement = element as EdgeFadeElement;\n const fadeGroup = group as EdgeFadeGroup;\n const inputKey = edgeFadeKey(fadeElement);\n const hasFade = hasEdgeFade(fadeElement);\n\n // Fabric clipPath is fundamentally a hard clipping system; using a gradient\n // FabricImage as a clipPath is inconsistent across Fabric v6 cache paths.\n // Keep the normal hard frame clipPath, then multiply the already-rendered\n // crop-group cache with a direct canvas alpha gradient.\n if (!fadeGroup.__edgeFadeOriginalDrawObject) {\n fadeGroup.__edgeFadeOriginalDrawObject = group.drawObject;\n }\n\n if (hasFade) {\n if ((group.clipPath as EdgeFadeClip | undefined)?.__edgeFadeMask) {\n group.clipPath = undefined;\n updateCoverLayout(group);\n }\n\n fadeGroup.__edgeFadeRenderConfig = {\n key: `${inputKey}|${Math.round(frameW)}|${Math.round(frameH)}|${shape}|${rxRatio}`,\n frameW: Math.max(1, Number(frameW) || 1),\n frameH: Math.max(1, Number(frameH) || 1),\n topSize: clamp(Number(fadeElement.fadeTopSize) || 0, 0, 1),\n topAmount: clamp(fadeElement.fadeTopAmount == null ? 1 : Number(fadeElement.fadeTopAmount), 0, 1),\n rightSize: clamp(Number(fadeElement.fadeRightSize) || 0, 0, 1),\n rightAmount: clamp(fadeElement.fadeRightAmount == null ? 1 : Number(fadeElement.fadeRightAmount), 0, 1),\n bottomSize: clamp(Number(fadeElement.fadeBottomSize) || 0, 0, 1),\n bottomAmount: clamp(fadeElement.fadeBottomAmount == null ? 1 : Number(fadeElement.fadeBottomAmount), 0, 1),\n leftSize: clamp(Number(fadeElement.fadeLeftSize) || 0, 0, 1),\n leftAmount: clamp(fadeElement.fadeLeftAmount == null ? 1 : Number(fadeElement.fadeLeftAmount), 0, 1),\n topHardness: clamp(Number(fadeElement.fadeTopHardness) || 1, 0.1, 5),\n rightHardness: clamp(Number(fadeElement.fadeRightHardness) || 1, 0.1, 5),\n bottomHardness: clamp(Number(fadeElement.fadeBottomHardness) || 1, 0.1, 5),\n leftHardness: clamp(Number(fadeElement.fadeLeftHardness) || 1, 0.1, 5),\n };\n\n const originalDrawObject = fadeGroup.__edgeFadeOriginalDrawObject ?? group.drawObject;\n group.drawObject = function edgeFadeDrawObject(ctx: CanvasRenderingContext2D, forClipping: boolean | undefined, context: Parameters<fabric.Group['drawObject']>[2]) {\n originalDrawObject.call(this, ctx, forClipping, context);\n if (forClipping) return;\n const cfg = (this as EdgeFadeGroup).__edgeFadeRenderConfig;\n if (!cfg) return;\n\n // Use the group's live dimensions so the fade follows resize/crop edits\n // in real time. Fall back to cached frame size if width/height are\n // momentarily unavailable.\n const liveW = Number((this as fabric.Group).width) || 0;\n const liveH = Number((this as fabric.Group).height) || 0;\n const w = liveW > 0 ? liveW : cfg.frameW;\n const h = liveH > 0 ? liveH : cfg.frameH;\n const x = -w / 2;\n const y = -h / 2;\n const paintBand = (side: 'top' | 'right' | 'bottom' | 'left', size: number, amount: number, hardness: number) => {\n if (size <= 0 || amount >= 1) return;\n ctx.save();\n ctx.globalCompositeOperation = 'destination-out';\n let gradient: CanvasGradient;\n const eraseAtEdge = 1 - amount;\n // Hardness maps inversely to the gamma curve over kept image alpha:\n // 0.1 = very soft/long blend, 1 = linear, >1 = harder/punchier fade.\n const STOPS = 64;\n const gamma = 1 / hardness;\n const addStops = (g: CanvasGradient) => {\n for (let i = 0; i <= STOPS; i++) {\n const t = i / STOPS;\n const keepProgress = Math.pow(t, gamma);\n const a = eraseAtEdge * (1 - keepProgress);\n g.addColorStop(t, `rgba(0,0,0,${a})`);\n }\n };\n if (side === 'top') {\n const band = Math.max(1, h * size);\n gradient = ctx.createLinearGradient(0, y, 0, y + band);\n addStops(gradient);\n ctx.fillStyle = gradient;\n ctx.fillRect(x, y, w, band);\n } else if (side === 'bottom') {\n const band = Math.max(1, h * size);\n gradient = ctx.createLinearGradient(0, y + h, 0, y + h - band);\n addStops(gradient);\n ctx.fillStyle = gradient;\n ctx.fillRect(x, y + h - band, w, band);\n } else if (side === 'left') {\n const band = Math.max(1, w * size);\n gradient = ctx.createLinearGradient(x, 0, x + band, 0);\n addStops(gradient);\n ctx.fillStyle = gradient;\n ctx.fillRect(x, y, band, h);\n } else {\n const band = Math.max(1, w * size);\n gradient = ctx.createLinearGradient(x + w, 0, x + w - band, 0);\n addStops(gradient);\n ctx.fillStyle = gradient;\n ctx.fillRect(x + w - band, y, band, h);\n }\n ctx.restore();\n };\n\n paintBand('top', cfg.topSize, cfg.topAmount, cfg.topHardness);\n paintBand('right', cfg.rightSize, cfg.rightAmount, cfg.rightHardness);\n paintBand('bottom', cfg.bottomSize, cfg.bottomAmount, cfg.bottomHardness);\n paintBand('left', cfg.leftSize, cfg.leftAmount, cfg.leftHardness);\n };\n\n group.set({ objectCaching: true, noScaleCache: false });\n fadeGroup.__edgeFadeKey = fadeGroup.__edgeFadeRenderConfig.key;\n fadeGroup.__edgeFadeInputKey = inputKey;\n } else {\n if (fadeGroup.__edgeFadeOriginalDrawObject) {\n group.drawObject = fadeGroup.__edgeFadeOriginalDrawObject;\n }\n delete fadeGroup.__edgeFadeRenderConfig;\n delete fadeGroup.__edgeFadeKey;\n delete fadeGroup.__edgeFadeInputKey;\n if ((group.clipPath as EdgeFadeClip | undefined)?.__edgeFadeMask) {\n group.clipPath = undefined;\n updateCoverLayout(group);\n }\n }\n\n if (group.clipPath) {\n (group.clipPath as fabric.FabricObject).dirty = true;\n group.clipPath.setCoords();\n }\n fadeGroup.dirty = true;\n const children = group.getObjects();\n children.forEach((child) => { child.dirty = true; });\n group.canvas?.requestRenderAll();\n };\n\n const loadImageAsync = async (\n element: CanvasElement,\n placeholder: fabric.FabricObject,\n fc: fabric.Canvas\n ) => {\n const imageUrl = element.src || element.imageUrl;\n if (!imageUrl) return;\n const elementId = element.id;\n const nextSvgColorMap = element.svgColorMap ? JSON.stringify(element.svgColorMap) : '';\n\n // Monotonic request id per element to avoid race conditions creating duplicate objects\n const nextRequestSeq = (imageReloadRequestSeqRef.current.get(elementId) ?? 0) + 1;\n imageReloadRequestSeqRef.current.set(elementId, nextRequestSeq);\n const isLatestRequest = () => imageReloadRequestSeqRef.current.get(elementId) === nextRequestSeq;\n\n // CRITICAL: Early return for crop groups - don't remove/recreate if only crop/resize changed\n // This prevents deselection during drag\n if (placeholder instanceof fabric.Group && (placeholder as any).__cropGroup) {\n const ct = (placeholder as any).__cropData;\n const existingImg = ct?._img;\n const existingSrc = (placeholder as any).__imageSrc;\n const existingSvgColorMap = (placeholder as any).__svgColorMap || '';\n const existingFadeKey = (existingImg && (existingImg as any).__edgeFadeKey) || (placeholder as any).__edgeFadeKey || '';\n const nextFadeKey = edgeFadeKey(element as any);\n\n // If image URL and SVG color map haven't changed and image exists, don't remove/recreate\n if (existingImg && existingSrc === imageUrl && existingSvgColorMap === nextSvgColorMap && existingFadeKey === nextFadeKey) {\n // Crop/resize changed; image source did not.\n // Do not remove/recreate the object - just update in place if needed\n return placeholder;\n }\n }\n\n try {\n // Preserve imported SVG fidelity: avoid normalization/re-encoding for inline SVG data URLs\n // unless user explicitly applied SVG color overrides.\n let url = getProxiedImageUrl(imageUrl);\n const hasColorOverrides = Boolean((element as any).svgColorMap && Object.keys((element as any).svgColorMap).length > 0);\n const isInlineSvgDataUrl = imageUrl.startsWith('data:image/svg+xml');\n\n if (isSvgImage(imageUrl, (element as any).sourceFormat) && (!isInlineSvgDataUrl || hasColorOverrides)) {\n const normalized = await getNormalizedSvgUrl(imageUrl, (element as any).svgColorMap, (element as any).sourceFormat);\n if (!isLatestRequest()) return;\n if (normalized) url = normalized;\n }\n const img = await fabric.FabricImage.fromURL(url, { crossOrigin: 'anonymous' });\n\n if (!fabricRef.current || !isLatestRequest()) return;\n\n // Fallback: ensure Fabric has correct dimensions if browser still reported wrong\n await normalizeSvgImageDimensions(img, imageUrl, (element as any).sourceFormat);\n if (!isLatestRequest()) return;\n\n const imageFitForFade = element.imageFit || (element as any).style?.imageFit || 'cover';\n const clipShapeForFade = element.clipShape ?? (element as any).style?.imageFrameShape ?? (isPreviewMode ? 'rectangle' : 'none');\n const willUseCropGroupForFade = imageFitForFade !== 'fill' || (clipShapeForFade && clipShapeForFade !== 'none');\n\n // Edge fade: direct fill images bake into the bitmap; crop groups get a frame-sized alpha clip below.\n try {\n if (hasEdgeFade(element as any) && !willUseCropGroupForFade) {\n const srcEl = (img as any).getElement?.() as HTMLImageElement | HTMLCanvasElement | undefined;\n if (srcEl) {\n const baked = bakeEdgeFade(srcEl, element as any);\n img.setElement(baked);\n (img as any).__edgeFadeKey = edgeFadeKey(element as any);\n img.dirty = true;\n }\n }\n } catch (e) {\n // Non-fatal — proceed without fade.\n console.warn('[edgeFade] bake failed:', e);\n }\n\n // Set basic properties first\n // Account for visibility state - hidden elements should have opacity 0\n const isHidden = !element.visible;\n // NOTE: opacity is set on the OUTER object only (crop group or raw image in fill mode).\n // Setting it on the inner img AND the crop group causes double-multiplication.\n img.set({\n originX: 'left',\n originY: 'top',\n visible: !isHidden,\n opacity: 1, // opacity applied on final wrapper, not here\n selectable: !isHidden && element.selectable,\n evented: !isHidden && element.evented,\n hasControls: !isHidden && element.selectable,\n hasBorders: !isHidden && element.selectable,\n lockMovementX: !element.selectable,\n lockMovementY: !element.selectable,\n // NOTE: flipX/flipY are set on the OUTER object only (crop group or raw image in fill mode).\n // Setting it on the inner img AND the crop group causes double-flip (cancels out).\n // Flip will be applied below: on cropGroup for crop mode, on img for fill mode.\n // Disable caching to ensure proper transparency rendering\n objectCaching: false,\n noScaleCache: true,\n });\n\n // If we have a stored transformMatrix, use the stored element values\n // The element.left/top/scale/angle were saved from the actual Fabric object properties\n if (element.transformMatrix && element.transformMatrix.length === 6) {\n img.set({\n left: element.left,\n top: element.top,\n scaleX: element.scaleX ?? 1,\n scaleY: element.scaleY ?? 1,\n angle: element.angle ?? 0,\n skewX: element.skewX ?? 0,\n skewY: element.skewY ?? 0,\n });\n img.setCoords();\n } else {\n // Calculate image scale based on imageFit mode\n const imageFit = element.imageFit || (element as any).style?.imageFit || 'cover';\n // In preview mode use same fallback as form thumbnail/export: clipShape ?? style.imageFrameShape ?? 'rectangle'\n const clipShape = element.clipShape ?? (element as any).style?.imageFrameShape ?? (isPreviewMode ? 'rectangle' : 'none');\n const needCropGroup = imageFit !== 'fill' || (clipShape && clipShape !== 'none');\n const imgNaturalWidth = img.width || 1;\n const imgNaturalHeight = img.height || 1;\n const elementWidth = Number(element.width);\n const elementHeight = Number(element.height);\n \n let baseScaleX: number;\n let baseScaleY: number;\n \n if (imageFit === 'fill' && !needCropGroup) {\n // Fill (no clip shape): stretch to fit element dimensions\n baseScaleX = elementWidth / imgNaturalWidth;\n baseScaleY = elementHeight / imgNaturalHeight;\n } else if (imageFit === 'contain') {\n const scaleX = elementWidth / imgNaturalWidth;\n const scaleY = elementHeight / imgNaturalHeight;\n const scale = Math.min(scaleX, scaleY);\n baseScaleX = scale;\n baseScaleY = scale;\n } else {\n // Cover (or fill + clipShape: use cover so frame is filled and clipped)\n const scaleX = elementWidth / imgNaturalWidth;\n const scaleY = elementHeight / imgNaturalHeight;\n const scale = Math.max(scaleX, scaleY);\n baseScaleX = scale;\n baseScaleY = scale;\n }\n \n // When needCropGroup we wrap in crop group; otherwise use image directly (fill, no clip)\n if (imageFit === 'fill' && !needCropGroup) {\n // Fill mode: apply element scale on top\n const finalScaleX = baseScaleX * (element.scaleX ?? 1);\n const finalScaleY = baseScaleY * (element.scaleY ?? 1);\n \n const pageTreeForCreate = (pageChildren?.length ? pageChildren : useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)?.children) ?? [];\n const createPos = pageTreeForCreate.length > 0 ? (() => {\n const node = findNodeById(pageTreeForCreate, element.id);\n return node ? getAbsoluteBounds(node, pageTreeForCreate) : { left: element.left ?? 0, top: element.top ?? 0 };\n })() : { left: element.left ?? 0, top: element.top ?? 0 };\n img.set({\n left: createPos.left,\n top: createPos.top,\n scaleX: finalScaleX,\n scaleY: finalScaleY,\n angle: element.angle ?? 0,\n skewX: element.skewX ?? 0,\n skewY: element.skewY ?? 0,\n flipX: element.flipX ?? false,\n flipY: element.flipY ?? false,\n });\n \n // Apply clipShape if specified\n const clipPath = createImageClipPath(element, img.width || Number(element.width), img.height || Number(element.height));\n if (clipPath) {\n img.clipPath = clipPath;\n }\n } else {\n // Crop mode: image stays at base scale, position it centered\n // The image will be wrapped in a group that acts as the crop window\n const elementWidth = Number(element.width) * (element.scaleX ?? 1);\n const elementHeight = Number(element.height) * (element.scaleY ?? 1);\n \n // Calculate scaled image dimensions\n const scaledImageWidth = imgNaturalWidth * baseScaleX;\n const scaledImageHeight = imgNaturalHeight * baseScaleY;\n \n // Center the image within the group (group will be created below)\n // Position relative to group's top-left (0,0)\n const imageLeft = (elementWidth - scaledImageWidth) / 2;\n const imageTop = (elementHeight - scaledImageHeight) / 2;\n \n // Set image properties with correct origin\n img.set({\n originX: 'left',\n originY: 'top',\n left: imageLeft,\n top: imageTop,\n scaleX: baseScaleX,\n scaleY: baseScaleY,\n angle: 0, // Image rotation handled by group\n skewX: 0,\n skewY: 0,\n });\n \n // Store base scale for later use\n (img as any).__cropBaseScaleX = baseScaleX;\n (img as any).__cropBaseScaleY = baseScaleY;\n }\n }\n\n // Store the image URL and color map on the loaded image\n (img as any).__imageSrc = imageUrl;\n (img as any).__svgColorMap = element.svgColorMap ? JSON.stringify(element.svgColorMap) : '';\n\n // Use crop group when imageFit is cover/contain, or when any clip shape is set (so preview clips like editor)\n const imageFitFinal = element.imageFit || (element as any).style?.imageFit || 'cover';\n const clipShapeFinal = element.clipShape ?? (element as any).style?.imageFrameShape ?? (isPreviewMode ? 'rectangle' : 'none');\n const needCropGroup = imageFitFinal !== 'fill' || (clipShapeFinal && clipShapeFinal !== 'none');\n let finalObject: fabric.FabricObject = img;\n \n if (needCropGroup) {\n // Resolve frame size from store so reload uses saved dimensions (avoid stale closure)\n const pageTreeForCropResolve = (pageChildren?.length ? pageChildren : useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)?.children) ?? [];\n const nodeForSize = pageTreeForCropResolve.length ? findNodeById(pageTreeForCropResolve, element.id) : null;\n const w = nodeForSize && isElement(nodeForSize) ? (nodeForSize as CanvasElement).width : element.width;\n const h = nodeForSize && isElement(nodeForSize) ? (nodeForSize as CanvasElement).height : element.height;\n const sx = nodeForSize && isElement(nodeForSize) ? ((nodeForSize as CanvasElement).scaleX ?? 1) : (element.scaleX ?? 1);\n const sy = nodeForSize && isElement(nodeForSize) ? ((nodeForSize as CanvasElement).scaleY ?? 1) : (element.scaleY ?? 1);\n const elementWidth = Math.max(1, Number(w) || 200) * sx;\n const elementHeight = Math.max(1, Number(h) || 50) * sy;\n const clipShape = clipShapeFinal;\n // rx is stored as ratio (0-0.5), convert old pixel values if needed\n let rxRatio = 0;\n if (clipShape === 'rounded') {\n const elementRx = element.rx || 0.1; // Default to 10% if not set\n // If rx > 0.5, it's likely an old pixel value, convert to ratio\n if (elementRx > 0.5) {\n const minDim = Math.min(elementWidth, elementHeight);\n rxRatio = Math.min(elementRx / minDim, 0.5); // Cap at 50%\n } else {\n rxRatio = elementRx;\n }\n }\n \n // Map clipShape to createMaskedImageElement shape format\n let shape: 'circle' | 'roundRect' | 'rect' = 'rect';\n if (clipShape === 'circle') {\n shape = 'circle';\n } else if (clipShape === 'rounded' || clipShape === 'rectangle') {\n shape = 'roundRect';\n }\n \n // Check if there's an existing crop group to preserve pan values\n const existingCropGroup = fc.getObjects().find(\n (obj) => obj instanceof fabric.Group && \n (obj as any).__cropGroup && \n getObjectId(obj) === element.id\n ) as fabric.Group | undefined;\n \n let panX = (element as any).cropPanX ?? 0.5;\n let panY = (element as any).cropPanY ?? 0.5;\n let zoom = (element as any).cropZoom ?? 1;\n if (existingCropGroup) {\n const existingImg = (existingCropGroup as any).__cropData?._img;\n if (existingImg) {\n // Prefer live _ct; fallback to stored element values\n panX = (existingImg as any)._ct?.panX ?? (existingImg as any).__panX ?? panX;\n panY = (existingImg as any)._ct?.panY ?? (existingImg as any).__panY ?? panY;\n zoom = (existingImg as any)._ct?.zoom ?? zoom;\n }\n }\n \n // Create the masked image element using the new utility\n // Use the already-loaded image instead of loading again\n const isDynamicField = dynamicFieldIds.includes(element.id);\n const canBeEvented = isEditorMode || (isPreviewMode && isDynamicField);\n \n const pageTreeForCrop = (pageChildren?.length ? pageChildren : useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)?.children) ?? [];\n const createPosForCrop = pageTreeForCrop.length > 0 ? (() => {\n const node = findNodeById(pageTreeForCrop, element.id);\n return node ? getAbsoluteBounds(node, pageTreeForCrop) : { left: element.left ?? 0, top: element.top ?? 0 };\n })() : { left: element.left ?? 0, top: element.top ?? 0 };\n // Re-resolve frame size from same tree so create uses exact saved dimensions (fixes reload scale)\n const nodeForCreate = pageTreeForCrop.length ? findNodeById(pageTreeForCrop, element.id) : null;\n const createW = nodeForCreate && isElement(nodeForCreate) ? (nodeForCreate as CanvasElement).width : elementWidth;\n const createH = nodeForCreate && isElement(nodeForCreate) ? (nodeForCreate as CanvasElement).height : elementHeight;\n const createSx = nodeForCreate && isElement(nodeForCreate) ? ((nodeForCreate as CanvasElement).scaleX ?? 1) : (element.scaleX ?? 1);\n const createSy = nodeForCreate && isElement(nodeForCreate) ? ((nodeForCreate as CanvasElement).scaleY ?? 1) : (element.scaleY ?? 1);\n const frameW = Math.max(1, Number(createW) || 200) * createSx;\n const frameH = Math.max(1, Number(createH) || 50) * createSy;\n // Crop groups use center origin in Fabric — convert top-left (getAbsoluteBounds) to center\n const createCenterX = createPosForCrop.left + frameW / 2;\n const createCenterY = createPosForCrop.top + frameH / 2;\n const cropGroup = await createMaskedImageElement({\n image: img,\n frameW,\n frameH,\n shape,\n rx: rxRatio, // Pass ratio, not pixel value\n stroke: null, // No border by default\n strokeWidth: 0,\n left: createCenterX,\n top: createCenterY,\n angle: element.angle ?? 0,\n opacity: isHidden ? 0 : (element.opacity ?? 1),\n selectable: allowSelection && !isHidden,\n evented: canBeEvented && !isHidden,\n visible: !isHidden,\n panX,\n panY,\n zoom,\n });\n \n // Store maintainResolution flag on the crop group (default to true)\n (cropGroup as any).__maintainResolution = element.maintainResolution !== false;\n \n // Use transparent so PNG/SVG transparent pixels show through (no white fill)\n cropGroup.set({\n backgroundColor: 'transparent',\n flipX: element.flipX ?? false,\n flipY: element.flipY ?? false,\n });\n \n // CRITICAL: In preview mode, disable controls and borders for crop groups\n // DO NOT install controls in preview mode\n if (!allowEditing) {\n cropGroup.set({\n hasControls: false,\n hasBorders: false,\n selectable: false,\n evented: canBeEvented && !isHidden,\n });\n } else {\n // Editor mode — always Canva-style controls (corners=scale, sides=crop)\n installCanvaMaskControls(cropGroup);\n }\n \n // Restore pan/zoom on image\n const cropImg = (cropGroup as any).__cropData?._img;\n if (cropImg) {\n (cropImg as any)._ct = { panX, panY, zoom };\n updateCoverLayout(cropGroup);\n }\n applyEdgeFadeFrameClipPath(cropGroup, element, frameW, frameH, shape, rxRatio);\n \n // Store metadata\n setObjectData(cropGroup, element.id);\n (cropGroup as any).__imageElement = cropImg;\n (cropGroup as any).__imageSrc = imageUrl;\n (cropGroup as any).__svgColorMap = nextSvgColorMap;\n \n // Persist natural dimensions to store so export never relies on Fabric baked state after move\n if (cropImg && (element as any).imageNaturalWidth == null) {\n const el = (cropImg as any).getElement?.() ?? (cropImg as any)._element;\n const orig = typeof (cropImg as any).getOriginalSize === 'function' ? (cropImg as any).getOriginalSize() : null;\n const nw = orig?.width ?? el?.naturalWidth ?? (cropImg as any).width;\n const nh = orig?.height ?? el?.naturalHeight ?? (cropImg as any).height;\n if (typeof nw === 'number' && typeof nh === 'number' && nw > 0 && nh > 0) {\n useEditorStore.getState().updateElement(element.id, { imageNaturalWidth: nw, imageNaturalHeight: nh }, { recordHistory: false });\n }\n }\n\n // Re-apply persisted SVG mask (from schema) so it survives reloads.\n const persistedMaskUrl = (element as any).maskSvgUrl;\n if (persistedMaskUrl && typeof persistedMaskUrl === 'string') {\n try {\n const { applyMaskToCropGroup } = await import('@/lib/svgMaskApply');\n const persistedMaskType = ((element as any).maskType as 'shape' | 'luminance') || 'shape';\n await applyMaskToCropGroup(cropGroup, persistedMaskUrl, persistedMaskType);\n } catch (err) {\n console.warn('[mask] failed to re-apply persisted mask', err);\n }\n }\n\n finalObject = cropGroup;\n } else {\n // Fill mode: use image directly — apply opacity here since there's no crop group wrapper\n const isHiddenFill = !element.visible;\n img.set({ opacity: isHiddenFill ? 0 : (element.opacity ?? 1) });\n setObjectData(img, element.id);\n }\n\n // CRITICAL: Only remove placeholder if we're not transforming\n // This prevents deselection during drag\n if (!syncLockedRef.current && !isTransforming(fc)) {\n const activeBeforeReplace = fc.getActiveObject();\n const activeIdsBeforeReplace = new Set(\n fc.getActiveObjects()\n .map((o) => getObjectId(o))\n .filter((id): id is string => !!id)\n );\n const wasPlaceholderSelected = activeIdsBeforeReplace.has(elementId);\n\n // Drop stale async reloads (older recolor/image loads) so they can't override newer state\n if (!isLatestRequest()) return;\n\n const canvasObjects = fc.getObjects();\n const idx = canvasObjects.indexOf(placeholder);\n\n if (idx >= 0) {\n // Prevent store selection clear only when we are actually removing selected placeholder\n if (wasPlaceholderSelected) {\n skipSelectionClearOnDiscardRef.current = true;\n }\n fc.remove(placeholder);\n fc.insertAt(idx, finalObject);\n } else {\n const existingForElement = canvasObjects.find((obj) => getObjectId(obj) === elementId);\n if (existingForElement) {\n // Placeholder already replaced by a newer request; avoid duplicate overlay\n return;\n }\n fc.add(finalObject);\n }\n\n // Restore active selection immediately for the replaced element\n if (wasPlaceholderSelected && allowSelection) {\n // Keep behavior predictable: restore the recolored object as active\n fc.setActiveObject(finalObject);\n finalObject.setCoords();\n // Safety reset in case no selection:cleared event fired\n requestAnimationFrame(() => {\n skipSelectionClearOnDiscardRef.current = false;\n });\n } else if (activeBeforeReplace && fc.getObjects().includes(activeBeforeReplace)) {\n // Preserve previously active object when it still exists\n fc.setActiveObject(activeBeforeReplace);\n }\n } else {\n // During transform, just update in place if possible\n // For crop groups, we should never need to remove/recreate\n if (finalObject instanceof fabric.Group && (finalObject as any).__cropGroup) {\n // Don't remove - just update the existing object\n // The placeholder will be replaced on next non-transform sync\n return;\n }\n }\n\n fc.requestRenderAll();\n } catch (error) {\n // Failed to load image - non-critical\n }\n };\n\n // Note: loadImageIntoGroup is imported from canvasImageLoader\n\n // Handle canvas click for adding elements\n const handleCanvasClick = useCallback(\n (e: React.MouseEvent<HTMLCanvasElement>) => {\n if (!isActive || !fabricRef.current) return;\n const fc = fabricRef.current;\n const rect = canvasElRef.current?.getBoundingClientRect();\n if (!rect) return;\n\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n\n if (activeTool === 'text') {\n const newElement = createDefaultElement({\n id: `text-${Date.now()}`,\n type: 'text',\n name: 'Text',\n left: x,\n top: y,\n width: 200,\n height: 32,\n fill: '#1a1a1a',\n text: 'Type something...',\n fontSize: 16,\n fontFamily: 'Open Sans',\n fontWeight: 400,\n textAlign: 'left',\n });\n addElement(newElement);\n setActiveTool('select');\n }\n },\n [isActive, activeTool, addElement, setActiveTool]\n );\n\n // Handle click/mousedown on wrapper to activate page\n // Using mousedown for more reliable activation before Fabric.js processes the event\n const handleWrapperMouseDown = useCallback((e: React.MouseEvent) => {\n if (!isActive && onActivate) {\n e.stopPropagation();\n onActivate();\n }\n }, [isActive, onActivate]);\n\n // Fabric.js creates a wrapper div with upper-canvas and lower-canvas\n // We need to control pointer events on the wrapper level\n useEffect(() => {\n const fc = fabricRef.current;\n if (!fc) return;\n \n const wrapperEl = fc.wrapperEl;\n if (wrapperEl) {\n wrapperEl.style.pointerEvents = isActive ? 'auto' : 'none';\n // In preview mode, allow vertical scrolling to pass through to parent\n if (isPreviewMode) {\n wrapperEl.style.touchAction = 'pan-y';\n }\n }\n // Also set touch-action on the upper canvas so Fabric doesn't block scrolling in preview\n const upperCanvas = wrapperEl?.querySelector('.upper-canvas') as HTMLElement;\n if (upperCanvas && isPreviewMode) {\n upperCanvas.style.touchAction = 'pan-y';\n }\n }, [isActive, isPreviewMode]);\n\n const zoom = workspaceZoom || 1;\n const scaledWidth = canvasWidth * zoom;\n const scaledHeight = canvasHeight * zoom;\n\n // Page background only (group bgs are drawn as part of fabric.Group sections)\n const pageTreeForUnderlay = (isPreviewMode && pageChildren?.length) ? (pageChildren ?? []) : (currentPage?.children ?? []);\n\n // Groups are logical only (multiselect); no sections overlay\n const sectionsOverlay = useMemo(() => null, []);\n\n const groupBoundsOverlay = useMemo(() => null, []);\n\n return (\n <div \n ref={groupOverlayWrapperRef}\n className=\"relative\" \n style={{ width: scaledWidth, height: scaledHeight }}\n onMouseDown={handleWrapperMouseDown}\n >\n {/* Underlay: page bg only; section bgs are part of fabric.Group on canvas */}\n <div\n className=\"absolute inset-0 pointer-events-none\"\n style={{\n width: canvasWidth,\n height: canvasHeight,\n transform: `scale(${zoom})`,\n transformOrigin: '0 0',\n }}\n >\n <div\n className=\"absolute inset-0\"\n style={{ \n left: 0, top: 0, width: canvasWidth, height: canvasHeight, \n backgroundColor: pageSettings.backgroundColor || '#ffffff',\n ...(pageSettings.backgroundGradient && isGradientConfig(pageSettings.backgroundGradient) ? {\n background: (() => {\n const g = pageSettings.backgroundGradient;\n const stopsStr = g.stops.map(s => `${s.color} ${Math.round(s.offset * 100)}%`).join(', ');\n if (g.type === 'linear') return `linear-gradient(${g.angle ?? 90}deg, ${stopsStr})`;\n if (g.type === 'radial') return `radial-gradient(circle at ${(g.cx ?? 0.5) * 100}% ${(g.cy ?? 0.5) * 100}%, ${stopsStr})`;\n if (g.type === 'conic') return `conic-gradient(from ${g.angle ?? 0}deg at ${(g.cx ?? 0.5) * 100}% ${(g.cy ?? 0.5) * 100}%, ${stopsStr})`;\n return undefined;\n })(),\n } : {}),\n }}\n />\n </div>\n <canvas\n ref={canvasElRef}\n onClick={handleCanvasClick}\n />\n \n {/* Sections highlight overlay */}\n {sectionsOverlay}\n\n {/* Group bounds + resize overlay (when a group is selected; independent of show sections) */}\n {groupBoundsOverlay}\n \n {/* Snap guides overlay - scaled to match canvas zoom */}\n {guides.length > 0 && (\n <svg\n className=\"absolute inset-0 pointer-events-none\"\n style={{ width: scaledWidth, height: scaledHeight }}\n viewBox={`0 0 ${canvasWidth} ${canvasHeight}`}\n >\n {/* Deduplicate guides by position and type */}\n {(() => {\n const seen = new Set<string>();\n return guides.filter((guide) => {\n const key = `${guide.type}-${guide.position.toFixed(1)}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n }).map((guide, i) => {\n // Use element-relative extents if available, otherwise full canvas\n const isElementRelative = guide.start !== undefined && guide.end !== undefined;\n \n const isActive = guide.active === true;\n const strokeColor = isActive ? '#22c55e' : (isElementRelative ? '#f43f5e' : '#3b82f6');\n const strokeWidth = isActive ? 2.5 : 1;\n const strokeDasharray = isActive ? 'none' : (isElementRelative ? '3,3' : '4,4');\n\n const showDistance = typeof guide.distance === 'number';\n const labelText = showDistance ? String(Math.round(guide.distance)) : '';\n const labelW = Math.max(24, labelText.length * 7);\n\n if (guide.type === 'vertical') {\n const padding = isElementRelative || isActive ? 20 : 0;\n const y1 = (guide.start != null && guide.end != null) ? Math.max(0, guide.start - padding) : 0;\n const y2 = (guide.start != null && guide.end != null) ? Math.min(canvasHeight, guide.end + padding) : canvasHeight;\n const labelY = (guide.start != null && guide.end != null) ? (guide.start + guide.end) / 2 : canvasHeight / 2;\n\n return (\n <g key={i}>\n <line x1={guide.position} y1={y1} x2={guide.position} y2={y2} stroke={strokeColor} strokeWidth={strokeWidth} strokeDasharray={strokeDasharray} />\n {isActive && <circle cx={guide.position} cy={y2} r={4} fill=\"#22c55e\" opacity={0.9} />}\n {isElementRelative && !isActive && (\n <>\n <circle cx={guide.position} cy={y1} r={2} fill=\"#f43f5e\" />\n <circle cx={guide.position} cy={y2} r={2} fill=\"#f43f5e\" />\n </>\n )}\n {showDistance && (\n <g transform={`translate(${guide.position + 6}, ${labelY})`}>\n <rect x={-2} y={-9} width={labelW} height={16} rx={4} fill=\"rgba(0,0,0,0.75)\" />\n <text x={labelW / 2 - 2} y={4} textAnchor=\"middle\" fill=\"#fff\" fontSize={10} fontFamily=\"system-ui, sans-serif\" fontWeight={500}>{labelText}</text>\n </g>\n )}\n </g>\n );\n } else {\n const padding = isElementRelative || isActive ? 20 : 0;\n const x1 = (guide.start != null && guide.end != null) ? Math.max(0, guide.start - padding) : 0;\n const x2 = (guide.start != null && guide.end != null) ? Math.min(canvasWidth, guide.end + padding) : canvasWidth;\n const labelX = (guide.start != null && guide.end != null) ? (guide.start + guide.end) / 2 : canvasWidth / 2;\n\n return (\n <g key={i}>\n <line x1={x1} y1={guide.position} x2={x2} y2={guide.position} stroke={strokeColor} strokeWidth={strokeWidth} strokeDasharray={strokeDasharray} />\n {isActive && <circle cx={x2} cy={guide.position} r={4} fill=\"#22c55e\" opacity={0.9} />}\n {isElementRelative && !isActive && (\n <>\n <circle cx={x1} cy={guide.position} r={2} fill=\"#f43f5e\" />\n <circle cx={x2} cy={guide.position} r={2} fill=\"#f43f5e\" />\n </>\n )}\n {showDistance && (\n <g transform={`translate(${labelX}, ${guide.position - 10})`}>\n <rect x={-2} y={-9} width={labelW} height={16} rx={4} fill=\"rgba(0,0,0,0.75)\" />\n <text x={labelW / 2 - 2} y={4} textAnchor=\"middle\" fill=\"#fff\" fontSize={10} fontFamily=\"system-ui, sans-serif\" fontWeight={500}>{labelText}</text>\n </g>\n )}\n </g>\n );\n }\n });\n })()}\n </svg>\n )}\n\n {/* Grid resize label: cols × rows while dragging grid group handle */}\n {gridResizeLabel && (\n <svg\n className=\"absolute inset-0 pointer-events-none\"\n style={{ width: scaledWidth, height: scaledHeight }}\n viewBox={`0 0 ${canvasWidth} ${canvasHeight}`}\n >\n <g transform={`translate(${gridResizeLabel.x}, ${gridResizeLabel.y})`}>\n <defs>\n <filter id=\"grid-label-shadow\" x=\"-20%\" y=\"-20%\" width=\"140%\" height=\"140%\">\n <feDropShadow dx={0} dy={1} stdDeviation={2} floodColor=\"#000\" floodOpacity={0.25} />\n </filter>\n </defs>\n <rect\n x={-36}\n y={-14}\n width={72}\n height={28}\n rx={14}\n ry={14}\n fill=\"rgba(34, 197, 94, 0.95)\"\n stroke=\"rgba(255,255,255,0.9)\"\n strokeWidth={1.5}\n filter=\"url(#grid-label-shadow)\"\n />\n <text\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n fill=\"white\"\n fontSize={13}\n fontWeight={600}\n fontFamily=\"system-ui, -apple-system, sans-serif\"\n >\n {gridResizeLabel.cols} × {gridResizeLabel.rows}\n </text>\n </g>\n </svg>\n )}\n </div>\n );\n }\n);\n\nPageCanvas.displayName = 'PageCanvas';\n","/**\n * PreviewCanvas - Unified preview component using PageCanvas\n * \n * Uses the same PageCanvas as the builder but in preview mode,\n * ensuring consistent rendering and behavior.\n */\n\nimport { useRef, useMemo, useCallback, useEffect, useState } from 'react';\nimport { PageCanvas, PageCanvasRef, ElementBounds } from '@/components/editor/PageCanvas';\nimport { \n TemplateConfig, \n CanvasElement, \n CanvasNode,\n flattenChildren,\n updateNodeInTree,\n PageSettings,\n ProjectSettings,\n DynamicField,\n} from '@/types/editor';\nimport { reflowPageFromRoot } from '@/lib/layoutEngine';\nimport { preloadImages, getProxiedImageUrl } from '@/lib/canvasImageLoader';\n\ninterface PreviewCanvasProps {\n config: TemplateConfig;\n pageIndex?: number;\n zoom?: number;\n /** When true, zoom is used as-is without auto-fit calculation */\n absoluteZoom?: boolean;\n /** Package renderer can skip the initial blocking font wait to avoid off-screen timeouts */\n skipFontReadyWait?: boolean;\n /** Internal export-only flag: avoid clearing Fabric's process-global font caches while a live preview is mounted. */\n preserveGlobalFontCache?: boolean;\n /** Internal capture-only override so offscreen canvases never share the visible preview page registry key. */\n pageIdOverride?: string;\n className?: string;\n onDynamicFieldClick?: (elementId: string, fieldId: string) => void;\n /** Called when the canvas has fully loaded fonts and is ready to display */\n onReady?: () => void;\n}\n\ninterface FieldInfo {\n fieldId: string;\n label: string;\n}\n\n/**\n * Build a map of elementId -> field info for quick lookup\n * Handles both old format (elementIds) and new format (mappings)\n */\nfunction buildElementToFieldMap(dynamicFields: DynamicField[] | undefined): Map<string, FieldInfo> {\n const map = new Map<string, FieldInfo>();\n if (!dynamicFields) return map;\n \n for (const field of dynamicFields) {\n // New format: field.mappings array\n if (field.mappings && Array.isArray(field.mappings)) {\n for (const mapping of field.mappings) {\n if (mapping.elementId) {\n map.set(mapping.elementId, {\n fieldId: field.id,\n label: field.label,\n });\n }\n }\n }\n // Old format: field.elementIds array (backward compatibility)\n else if ((field as any).elementIds && Array.isArray((field as any).elementIds)) {\n for (const elementId of (field as any).elementIds) {\n if (elementId) {\n map.set(elementId, {\n fieldId: field.id,\n label: field.label,\n });\n }\n }\n }\n }\n return map;\n}\n\nexport function PreviewCanvas({\n config,\n pageIndex = 0,\n zoom = 1,\n absoluteZoom = false,\n skipFontReadyWait = false,\n preserveGlobalFontCache = false,\n pageIdOverride,\n className,\n onDynamicFieldClick,\n onReady,\n}: PreviewCanvasProps) {\n const canvasRef = useRef<PageCanvasRef>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const [containerWidth, setContainerWidth] = useState(0);\n const [hoveredFieldId, setHoveredFieldId] = useState<string | null>(null);\n \n // Get page data\n const page = config?.pages?.[pageIndex];\n const canvasWidth = config?.canvas?.width || 612;\n const canvasHeight = config?.canvas?.height || 792;\n\n // Build element to field mapping\n const elementToFieldMap = useMemo(() => \n buildElementToFieldMap(config?.dynamicFields),\n [config?.dynamicFields]\n );\n \n // Get all dynamic field element IDs\n const dynamicFieldIds = useMemo(() => \n Array.from(elementToFieldMap.keys()),\n [elementToFieldMap]\n );\n\n // Run layout (reflow) on page tree so auto/inherit dimensions and flex/grid positions match the builder.\n // Always reflow when children change so that when form data updates text, text is measured and elements below move (auto layout).\n const laidOutPageChildren = useMemo((): CanvasNode[] => {\n if (!page?.children?.length) return [];\n const children = JSON.parse(JSON.stringify(page.children)) as CanvasNode[];\n const allUpdates = reflowPageFromRoot(children);\n if (allUpdates.size === 0) return children;\n let updated = children;\n allUpdates.forEach((u, nodeId) => {\n const dims: Partial<CanvasElement> & Record<string, unknown> = {};\n if (u.width !== undefined) dims.width = u.width;\n if (u.height !== undefined) dims.height = u.height;\n if (Object.keys(dims).length > 0) updated = updateNodeInTree(updated, nodeId, dims);\n });\n allUpdates.forEach((u, nodeId) => {\n const pos: Partial<CanvasElement> & Record<string, unknown> = {};\n if (u.left !== undefined) pos.left = u.left;\n if (u.top !== undefined) pos.top = u.top;\n if (Object.keys(pos).length > 0) updated = updateNodeInTree(updated, nodeId, pos);\n });\n return updated;\n }, [page?.children, page?.id, config?.layoutEngineDriven]);\n\n // Flatten elements from laid-out page (so positions/sizes match builder)\n const elements = useMemo(() => {\n if (!laidOutPageChildren.length) {\n return [];\n }\n return flattenChildren(laidOutPageChildren).filter(el => el.visible !== false);\n }, [laidOutPageChildren]);\n\n // Preload all image URLs so they're in browser memory before Fabric requests them\n useEffect(() => {\n const urls: string[] = [];\n for (const el of elements) {\n const src = el.src || el.imageUrl;\n if (src && !src.startsWith('data:')) {\n urls.push(getProxiedImageUrl(src));\n }\n }\n if (urls.length > 0) {\n preloadImages(urls);\n }\n }, [elements]);\n \n // Page settings\n const pageSettings: PageSettings = useMemo(() => ({\n backgroundColor: page?.settings?.backgroundColor || '#ffffff',\n backgroundGradient: page?.settings?.backgroundGradient,\n }), [page?.settings?.backgroundColor, page?.settings?.backgroundGradient]);\n \n // Project settings (minimal for preview). Pull primary/secondary from\n // themeConfig variables so inline markdown formatting ([c=primary],\n // ==highlight==, etc.) resolves the correct palette in the package preview.\n const projectSettings: ProjectSettings = useMemo(() => {\n const vars = (config.themeConfig as any)?.variables || {};\n return {\n showGrid: false,\n snapToGrid: false,\n gridSize: 10,\n snapToGuides: false,\n snapThreshold: 5,\n primaryColor: vars.primary?.value,\n secondaryColor: vars.secondary?.value,\n };\n }, [config.themeConfig]);\n \n // Handle dynamic field click\n const handleDynamicFieldClick = useCallback((elementId: string) => {\n const fieldInfo = elementToFieldMap.get(elementId);\n if (fieldInfo && onDynamicFieldClick) {\n onDynamicFieldClick(elementId, fieldInfo.fieldId);\n }\n }, [elementToFieldMap, onDynamicFieldClick]);\n \n // Get dynamic field elements with their positions for overlay\n // CRITICAL: Filter to avoid duplicates - only show overlay for elements that are actually dynamic fields\n const dynamicFieldElements = useMemo(() => {\n const result: Array<{ element: CanvasElement; label: string }> = [];\n const seenIds = new Set<string>();\n for (const element of elements) {\n // Skip if we've already added this element (prevent duplicates)\n if (seenIds.has(element.id)) continue;\n const fieldInfo = elementToFieldMap.get(element.id);\n if (fieldInfo) {\n seenIds.add(element.id);\n result.push({ element, label: fieldInfo.label });\n }\n }\n return result;\n }, [elements, elementToFieldMap]);\n \n // Track actual element bounds from the Fabric canvas (for accurate overlay positioning)\n const [actualBounds, setActualBounds] = useState<Map<string, ElementBounds>>(new Map());\n \n // Update actual bounds after canvas renders\n const updateBounds = useCallback(() => {\n if (canvasRef.current?.getAllElementBounds) {\n const bounds = canvasRef.current.getAllElementBounds();\n setActualBounds(bounds);\n }\n }, []);\n \n // Update bounds when elements change (after a short delay to let canvas render)\n useEffect(() => {\n const timer = setTimeout(updateBounds, 100);\n return () => clearTimeout(timer);\n }, [elements, updateBounds]);\n \n // Calculate scale to fit container\n const fitScale = useMemo(() => {\n if (!containerWidth || !canvasWidth) return 1;\n return Math.min(containerWidth / canvasWidth, 1);\n }, [containerWidth, canvasWidth]);\n \n // When absoluteZoom is true, use zoom directly without fitScale multiplication\n const scale = absoluteZoom ? zoom : fitScale * zoom;\n \n // Observe container size\n useEffect(() => {\n if (!containerRef.current) return;\n const w = containerRef.current.clientWidth;\n const resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n setContainerWidth(entry.contentRect.width);\n }\n });\n resizeObserver.observe(containerRef.current);\n setContainerWidth(w);\n return () => resizeObserver.disconnect();\n }, [canvasWidth]);\n \n if (!page) return null;\n \n return (\n <div \n ref={containerRef} \n className={className}\n style={{ width: '100%', overflow: 'hidden' }}\n >\n {/* Mount when width is known, or immediately in absoluteZoom mode (where scale doesn't depend on container width). */}\n {(containerWidth > 0 || absoluteZoom) && (\n <div\n style={{\n width: canvasWidth * scale,\n height: canvasHeight * scale,\n boxShadow: '0 2px 8px rgba(0,0,0,0.1)',\n position: 'relative',\n }}\n >\n {/* PageCanvas now uses viewport transform for crisp zoom */}\n <PageCanvas\n ref={canvasRef}\n pageId={pageIdOverride || page.id || `page-${pageIndex}`}\n elements={elements}\n pageChildren={laidOutPageChildren}\n pageSettings={pageSettings}\n projectSettings={projectSettings}\n canvasWidth={canvasWidth}\n canvasHeight={canvasHeight}\n isActive={true}\n workspaceZoom={scale}\n selectedIds={[]}\n activeTool=\"select\"\n mode=\"preview\"\n skipFontReadyWait={skipFontReadyWait}\n preserveGlobalFontCache={preserveGlobalFontCache}\n dynamicFieldIds={dynamicFieldIds}\n onDynamicFieldClick={handleDynamicFieldClick}\n onReady={onReady}\n />\n \n {/* Dynamic field click overlays - use actual bounds from canvas for accurate positioning */}\n {onDynamicFieldClick && dynamicFieldElements.map(({ element, label }) => {\n // Use actual bounds from Fabric canvas if available, otherwise fall back to element data\n const bounds = actualBounds.get(element.id);\n const isHovered = hoveredFieldId === element.id;\n \n // Bounds are in canvas coordinate space, so we need to apply scale\n let left: number, top: number, width: number, height: number;\n \n if (bounds) {\n // Use actual rendered bounds from canvas (e.g., text that grew in height)\n left = bounds.left * scale;\n top = bounds.top * scale;\n width = bounds.width * scale;\n height = bounds.height * scale;\n } else {\n // Fallback to element data\n left = element.left * scale;\n top = element.top * scale;\n width = Number(element.width) * (element.scaleX || 1) * scale;\n height = Number(element.height) * (element.scaleY || 1) * scale;\n }\n \n return (\n <div\n key={`overlay-${element.id}`}\n className=\"absolute cursor-pointer transition-all duration-150\"\n style={{\n left,\n top,\n width,\n height,\n border: isHovered ? '2px solid rgb(59 130 246)' : 'none',\n backgroundColor: isHovered ? 'rgba(59, 130, 246, 0.1)' : 'transparent',\n borderRadius: 4,\n pointerEvents: 'auto',\n }}\n onMouseEnter={() => setHoveredFieldId(element.id)}\n onMouseLeave={() => setHoveredFieldId(null)}\n onClick={() => {\n const fieldInfo = elementToFieldMap.get(element.id);\n if (fieldInfo && onDynamicFieldClick) {\n onDynamicFieldClick(element.id, fieldInfo.fieldId);\n }\n }}\n >\n {/* Label badge on hover */}\n {isHovered && (\n <div\n className=\"absolute -top-6 left-0 bg-primary text-primary-foreground text-xs px-2 py-0.5 rounded shadow-sm whitespace-nowrap\"\n style={{ fontSize: 10 }}\n >\n {label}\n </div>\n )}\n </div>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n","/**\n * Theme — Apply theme variable overrides to a template config.\n */\n\nimport type { TemplateConfig, CanvasNode } from './types';\n\nexport interface ThemeVariables {\n [variableName: string]: string;\n}\n\n/**\n * Apply theme variable overrides to a template config.\n * Walks the tree and replaces any property value that matches a theme variable reference.\n * \n * Theme variables in config look like: {{theme.variableName}}\n * Or are stored in themeConfig.variables as { [name]: { value, label } }\n */\nexport function applyThemeToConfig(\n config: TemplateConfig,\n themeOverrides: ThemeVariables\n): TemplateConfig {\n if (!themeOverrides || Object.keys(themeOverrides).length === 0) return config;\n\n const cloned = JSON.parse(JSON.stringify(config)) as TemplateConfig;\n\n // Update themeConfig.variables with overrides\n if (cloned.themeConfig?.variables) {\n for (const [key, value] of Object.entries(themeOverrides)) {\n if (cloned.themeConfig.variables[key]) {\n cloned.themeConfig.variables[key].value = value;\n }\n }\n }\n\n // Build a map of variable name -> new value\n const varMap = new Map<string, string>();\n if (cloned.themeConfig?.variables) {\n for (const [key, def] of Object.entries(cloned.themeConfig.variables)) {\n varMap.set(key, themeOverrides[key] ?? def.value);\n }\n }\n\n // Walk tree and apply theme bindings\n function walkAndApply(nodes: CanvasNode[]) {\n if (!nodes) return;\n for (const node of nodes) {\n // Check for theme bindings on the node\n const bindings = (node as any).themeBindings as Record<string, string> | undefined;\n if (bindings) {\n for (const [prop, varName] of Object.entries(bindings)) {\n const value = varMap.get(varName);\n if (value !== undefined) {\n (node as any)[prop] = value;\n }\n }\n }\n if (node.children) walkAndApply(node.children);\n }\n }\n\n for (const page of cloned.pages || []) {\n // Apply to page settings\n const bgBinding = (page as any).themeBindings?.backgroundColor;\n if (bgBinding && varMap.has(bgBinding) && page.settings) {\n page.settings.backgroundColor = varMap.get(bgBinding)!;\n }\n walkAndApply(page.children || []);\n }\n\n return cloned;\n}\n","/**\n * Infer a generic form schema from template.config.dynamicFields + fieldGroups.\n * Works for any template (resume, invoice, certificate, etc.): sections, repeatable entries,\n * min entries (can't delete below that), add/delete driven by template field IDs.\n *\n * Repeatable sections can come from:\n * 1. Tree: a group or element that is a direct child of a vertical stack and has repeatableSection set.\n * 2. Field ID convention: field_<prefix>_<index>_<suffix> or field_<prefix>_<index>.\n */\n\nimport type { DynamicField, FieldGroup } from '@/types/editor';\nimport type { CanvasNode, TemplateConfigPage } from '@/types/editor';\nimport { isGroup, isElement, flattenChildren, isVerticalStackLayoutMode } from '@/types/editor';\n\nexport type InferredFieldType = 'text' | 'email' | 'tel' | 'textarea' | 'date' | 'url' | 'number' | 'toggle' | 'list' | 'color' | 'image';\n\nexport interface InferredFieldDef {\n key: string;\n label: string;\n type: InferredFieldType;\n order: number;\n templateKey: string; // full template key (field id) for single; suffix for repeatable\n placeholder?: string;\n rows?: number;\n}\n\nexport interface InferredSectionSingle {\n id: string;\n label: string;\n order: number;\n type: 'single';\n fields: InferredFieldDef[];\n}\n\nexport interface InferredSectionRepeatable {\n id: string;\n label: string;\n order: number;\n type: 'repeatable';\n templateKeyPrefix: string; // e.g. \"field_exp\"\n minEntries: number;\n maxEntries?: number; // optional cap on entries (form disables \"Add\" when at max)\n entryFields: InferredFieldDef[];\n initialEntryCount: number;\n /** When set, this repeatable is nested inside another repeatable section (render inside parent entries). */\n parentId?: string;\n /** Optional: key of an entry field whose value labels the entry in the form UI. */\n entryNameFieldKey?: string;\n /** True when this repeatable was produced from a `repeatablePage` definition (vs an actual repeatable section). */\n isRepeatablePage?: boolean;\n}\n\nexport type InferredSection = InferredSectionSingle | InferredSectionRepeatable;\n\n// ── Convert FormDefSection[] (from form_schemas table) → InferredSection[] ──\n// Preserves original section IDs so saved form values (keyed by section ID) match.\n\nimport type { FormDefSection, FormDefField } from '@/lib/formSchemasApi';\n\nfunction mapFormDefFieldType(t: FormDefField['type']): InferredFieldType {\n if (['text', 'email', 'tel', 'textarea', 'date', 'url', 'number', 'toggle', 'color', 'image'].includes(t)) return t as InferredFieldType;\n if (t === 'currency') return 'number';\n return 'text';\n}\n\n/**\n * Convert schema sections (from form_schemas table) into InferredSection[].\n * This ensures section IDs match those used when the form was configured/saved.\n *\n * @param schemaSections — sections from FormDefSchema.sections\n * @param repeatableNodeMap — optional map from section label → tree nodeId (from template's form_schema.repeatableSections)\n * Used to populate `treeNodeId` so the preview can find the right template nodes.\n */\nexport function formDefSectionsToInferred(\n schemaSections: FormDefSection[],\n repeatableNodeMap?: Map<string, string>,\n): InferredSection[] {\n const sections: InferredSection[] = [];\n\n function convert(defs: FormDefSection[], parentId?: string): void {\n for (const def of defs) {\n if (def.repeatable) {\n const rawPrefix = def.templateKeyPrefix || def.label.toLowerCase().replace(/\\s+/g, '_');\n const labelPrefix = rawPrefix.startsWith('field_') ? rawPrefix : `field_${rawPrefix}`;\n // Try to find the tree nodeId by label match\n const treeNodeId = repeatableNodeMap?.get(def.label.trim().toLowerCase());\n // Use treeNodeId-based prefix so flattenSectionStateToFormData produces keys\n // that match what applyFormDataToConfig expects (field_<nodeId>_N_<fieldId>)\n const prefix = treeNodeId ? `field_${treeNodeId}` : labelPrefix;\n\n const minEntries = def.minEntries != null ? Math.max(0, def.minEntries) : 1;\n const section: InferredSectionRepeatable = {\n id: def.id,\n label: def.label,\n order: def.order ?? 0,\n type: 'repeatable',\n templateKeyPrefix: prefix,\n minEntries,\n maxEntries: def.maxEntries,\n entryFields: def.fields.map((f, i) => ({\n key: f.key,\n label: f.label,\n type: mapFormDefFieldType(f.type),\n order: f.order ?? i,\n templateKey: f.key,\n placeholder: f.placeholder,\n })),\n // Honor minEntries: 0 — start with no entries, user adds via \"+ Add\" button.\n initialEntryCount: minEntries,\n parentId,\n entryNameFieldKey: def.entryNameFieldKey,\n isRepeatablePage: def.isRepeatablePage,\n };\n // Store tree nodeId for preview mapping\n if (treeNodeId) (section as any).treeNodeId = treeNodeId;\n\n sections.push(section);\n\n if (def.children?.length) {\n convert(def.children, def.id);\n }\n } else {\n sections.push({\n id: def.id,\n label: def.label,\n order: def.order ?? 0,\n type: 'single',\n fields: def.fields.map((f, i) => ({\n key: f.key,\n label: f.label,\n type: mapFormDefFieldType(f.type),\n order: f.order ?? i,\n templateKey: `field_${f.key}`,\n placeholder: f.placeholder,\n })),\n });\n // Process children of non-repeatable sections (e.g. a single \"Skills\" section with a repeatable \"Skill\" child)\n if (def.children?.length) {\n convert(def.children, def.id);\n }\n }\n }\n }\n\n convert(schemaSections);\n return sections.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\nconst REPEATABLE_PATTERN = /^field_(.+)_(\\d+)_(.+)$/; // field_exp_1_title\nconst REPEATABLE_LIST_PATTERN = /^field_(.+)_(\\d+)$/; // field_skills_1\n/** Form definition canonical key pattern: field_{prefix}_N_{suffix} (supports deep nesting). */\nconst FORMDEF_REPEATABLE_PATTERN = /^field_(.+)_N_(.+)$/;\n\nfunction parseFormDefCanonicalFieldId(fieldId: string): { path: string[]; suffix: string } | null {\n if (!FORMDEF_REPEATABLE_PATTERN.test(fieldId)) return null;\n const raw = fieldId.replace(/^field_/, '');\n const segments = raw\n .split('_N_')\n .map((s) => s.trim())\n .filter(Boolean);\n if (segments.length < 2) return null;\n return {\n path: segments.slice(0, -1),\n suffix: segments[segments.length - 1],\n };\n}\n\nfunction humanizeToken(token: string): string {\n return token\n .replace(/_/g, ' ')\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\nfunction mapDynamicTypeToInferred(t: string): InferredFieldType {\n if (['text', 'email', 'tel', 'textarea', 'date', 'url', 'number', 'toggle', 'color', 'image'].includes(t)) return t as InferredFieldType;\n if (t === 'currency') return 'number';\n return 'text';\n}\n\n/** Repeatable section node info from the tree. */\ninterface RepeatableNodeInfo {\n nodeId: string;\n label: string;\n minEntries?: number;\n maxEntries?: number;\n parentNodeId?: string;\n}\n\n/**\n * Walk the tree and build:\n * 1. List of repeatable section nodes (direct children of a stack with repeatableSection set).\n * 2. Map: elementId -> nodeId of the innermost repeatable section that contains that element (direct or nested).\n */\nfunction findRepeatableNodesAndElementContainment(pages: TemplateConfigPage[]): {\n repeatableNodes: RepeatableNodeInfo[];\n elementIdToRepeatableNodeId: Map<string, string>;\n} {\n const repeatableNodes: RepeatableNodeInfo[] = [];\n const repeatableNodeIds = new Set<string>();\n const elementIdToRepeatableNodeId = new Map<string, string>();\n let order = 0;\n\n function walk(\n children: CanvasNode[],\n repeatableStack: string[],\n parentRepeatableNodeId?: string\n ): void {\n if (!Array.isArray(children)) return;\n for (const node of children) {\n if (isElement(node)) {\n if (repeatableStack.length > 0) {\n elementIdToRepeatableNodeId.set(node.id, repeatableStack[repeatableStack.length - 1]);\n }\n continue;\n }\n if (!isGroup(node)) continue;\n const nodeChildren = node.children;\n if (!Array.isArray(nodeChildren) || nodeChildren.length === 0) continue;\n\n const selfRep = (node as CanvasNode & { repeatableSection?: { label: string; minEntries?: number; maxEntries?: number } }).repeatableSection;\n if (selfRep?.label && !repeatableNodeIds.has(node.id)) {\n repeatableNodeIds.add(node.id);\n repeatableNodes.push({\n nodeId: node.id,\n label: selfRep.label,\n minEntries: selfRep.minEntries,\n maxEntries: selfRep.maxEntries,\n parentNodeId: parentRepeatableNodeId,\n });\n repeatableStack.push(node.id);\n elementIdToRepeatableNodeId.set(node.id, node.id);\n walk(nodeChildren, repeatableStack, node.id);\n repeatableStack.pop();\n continue;\n }\n\n if (isVerticalStackLayoutMode(node.layoutMode)) {\n for (const child of nodeChildren) {\n const rep = (child as CanvasNode & { repeatableSection?: { label: string; minEntries?: number; maxEntries?: number } }).repeatableSection;\n const childChildren = isGroup(child) ? (child as CanvasNode & { children?: unknown }).children : undefined;\n if (rep?.label) {\n const dedupeKey = parentRepeatableNodeId != null ? `${parentRepeatableNodeId}_${child.id}` : child.id;\n if (!repeatableNodeIds.has(dedupeKey)) {\n repeatableNodeIds.add(dedupeKey);\n repeatableNodes.push({\n nodeId: child.id,\n label: rep.label,\n minEntries: rep.minEntries,\n maxEntries: rep.maxEntries,\n parentNodeId: parentRepeatableNodeId,\n });\n }\n repeatableStack.push(child.id);\n elementIdToRepeatableNodeId.set(child.id, child.id);\n if (Array.isArray(childChildren)) walk(childChildren as CanvasNode[], repeatableStack, child.id);\n repeatableStack.pop();\n } else {\n if (Array.isArray(childChildren)) walk(childChildren as CanvasNode[], repeatableStack, parentRepeatableNodeId);\n }\n }\n continue;\n }\n\n walk(nodeChildren, repeatableStack, parentRepeatableNodeId);\n }\n }\n\n for (const page of pages) {\n if (Array.isArray(page.children) && page.children.length > 0) walk(page.children, []);\n }\n\n return { repeatableNodes, elementIdToRepeatableNodeId };\n}\n\nexport function inferFormSchemaFromTemplate(\n dynamicFields: DynamicField[],\n fieldGroups: FieldGroup[],\n options?: { pages?: TemplateConfigPage[] }\n): InferredSection[] {\n const sections: InferredSection[] = [];\n const sortedGroups = [...(fieldGroups || [])].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n\n // Tree-based repeatable sections: use actual structure – which elements sit inside which repeatable node (direct or nested).\n // Order them by field group order (match by label) so Use page section order matches Fields tab.\n const fieldIdsInTreeRepeatable = new Set<string>();\n if (options?.pages?.length) {\n const { repeatableNodes, elementIdToRepeatableNodeId } = findRepeatableNodesAndElementContainment(options.pages);\n const labelNorm = (s: string) => String(s).trim().toLowerCase();\n\n for (let idx = 0; idx < repeatableNodes.length; idx++) {\n const { nodeId, label, minEntries: minFromNode, maxEntries: maxFromNode, parentNodeId } = repeatableNodes[idx];\n const entryFields: InferredFieldDef[] = [];\n\n for (const field of dynamicFields) {\n const mappings = field.mappings ?? [];\n const mapsIntoThisNode = mappings.some((m) => {\n if (!m.elementId) return false;\n return elementIdToRepeatableNodeId.get(m.elementId) === nodeId;\n });\n if (mapsIntoThisNode) {\n fieldIdsInTreeRepeatable.add(field.id);\n entryFields.push({\n key: field.id.replace(/^field_/, '') || field.id,\n label: field.label,\n type: mapDynamicTypeToInferred(field.type),\n order: field.order ?? 0,\n templateKey: field.id,\n placeholder: field.placeholder,\n rows: (field as { rows?: number }).rows,\n });\n }\n }\n\n entryFields.sort((a, b) => a.order - b.order);\n if (entryFields.length > 0) {\n const matchingGroup = sortedGroups.find((g) => labelNorm(g.label) === labelNorm(label));\n const sectionOrder = matchingGroup !== undefined ? (matchingGroup.order ?? 0) : 500 + idx;\n sections.push({\n id: nodeId,\n label,\n order: sectionOrder,\n type: 'repeatable',\n templateKeyPrefix: `field_${nodeId}`,\n minEntries: minFromNode !== undefined && minFromNode !== null ? Math.max(0, minFromNode) : 1,\n maxEntries: maxFromNode !== undefined && maxFromNode !== null ? Math.max(1, maxFromNode) : undefined,\n entryFields,\n initialEntryCount: 1,\n parentId: parentNodeId,\n });\n }\n }\n }\n\n for (const group of sortedGroups) {\n const groupFields = dynamicFields\n .filter((f) => f.group === group.id && !fieldIdsInTreeRepeatable.has(f.id))\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n if (groupFields.length === 0) continue;\n\n const withIndexSuffix = groupFields.filter((f) => REPEATABLE_PATTERN.test(f.id));\n const withIndexOnly = groupFields.filter((f) => REPEATABLE_LIST_PATTERN.test(f.id) && !REPEATABLE_PATTERN.test(f.id));\n\n // ── Form definition canonical repeatables (supports deep nesting): field_a_N_b_N_c_N_field ──\n const parsedFormDef = groupFields\n .map((field) => {\n const parsed = parseFormDefCanonicalFieldId(field.id);\n return parsed ? { field, parsed } : null;\n })\n .filter((x): x is { field: DynamicField; parsed: { path: string[]; suffix: string } } => x !== null);\n\n if (parsedFormDef.length > 0) {\n type RepeatableDraft = InferredSectionRepeatable & { depth: number };\n const sectionByPath = new Map<string, RepeatableDraft>();\n\n for (const { field, parsed } of parsedFormDef) {\n for (let depth = 0; depth < parsed.path.length; depth++) {\n const pathParts = parsed.path.slice(0, depth + 1);\n const pathKey = pathParts.join('::');\n if (!sectionByPath.has(pathKey)) {\n const sectionId = `formdef_${pathParts.join('__')}`;\n const parentId = depth > 0 ? `formdef_${pathParts.slice(0, -1).join('__')}` : undefined;\n sectionByPath.set(pathKey, {\n id: sectionId,\n label: depth === 0 ? group.label : humanizeToken(pathParts[depth]),\n order: (group.order ?? 0) + depth * 0.01,\n type: 'repeatable',\n templateKeyPrefix: `field_${pathParts[depth]}`,\n minEntries: 1,\n entryFields: [],\n initialEntryCount: 1,\n parentId,\n depth,\n });\n }\n\n // Attach field to the deepest section of the parsed path.\n if (depth === parsed.path.length - 1) {\n const draft = sectionByPath.get(pathKey)!;\n const fieldKey = parsed.suffix;\n if (!draft.entryFields.some((f) => f.key === fieldKey && f.templateKey === fieldKey)) {\n draft.entryFields.push({\n key: fieldKey,\n label: field.label,\n type: mapDynamicTypeToInferred(field.type),\n order: field.order ?? 0,\n templateKey: fieldKey,\n placeholder: field.placeholder,\n rows: field.rows,\n });\n }\n }\n }\n }\n\n const drafts = [...sectionByPath.values()]\n .map((d) => ({ ...d, entryFields: [...d.entryFields].sort((a, b) => a.order - b.order) }))\n .sort((a, b) => (a.order !== b.order ? a.order - b.order : a.depth - b.depth));\n\n for (const draft of drafts) {\n const { depth: _depth, ...section } = draft;\n sections.push(section);\n }\n\n const parsedFieldIds = new Set(parsedFormDef.map(({ field }) => field.id));\n const nonFormDefFields = groupFields.filter((f) => !parsedFieldIds.has(f.id));\n if (nonFormDefFields.length > 0) {\n sections.push({\n id: `${group.id}_single`,\n label: group.label,\n order: group.order - 0.1,\n type: 'single',\n fields: nonFormDefFields.map((f) => ({\n key: f.id.replace(/^field_/, '') || f.id,\n label: f.label,\n type: mapDynamicTypeToInferred(f.type),\n order: f.order ?? 0,\n templateKey: f.id,\n placeholder: f.placeholder,\n rows: f.rows,\n })),\n });\n }\n\n continue;\n }\n\n\n if (withIndexSuffix.length > 0) {\n // Repeatable: field_exp_1_title, field_exp_1_company, field_exp_2_title, ...\n const byPrefix = new Map<string, { index: number; suffix: string; field: DynamicField }[]>();\n for (const field of groupFields) {\n const m = field.id.match(REPEATABLE_PATTERN);\n if (m) {\n const [, prefix, indexStr, suffix] = m;\n const index = parseInt(indexStr, 10);\n const key = `field_${prefix}`;\n if (!byPrefix.has(key)) byPrefix.set(key, []);\n byPrefix.get(key)!.push({ index, suffix, field });\n }\n }\n const firstPrefix = byPrefix.keys().next().value;\n if (firstPrefix) {\n const entries = byPrefix.get(firstPrefix)!;\n const indices = [...new Set(entries.map((e) => e.index))].sort((a, b) => a - b);\n const suffixOrder = new Map<string, number>();\n entries.forEach((e) => {\n if (!suffixOrder.has(e.suffix)) suffixOrder.set(e.suffix, e.field.order ?? 0);\n });\n const entryFields: InferredFieldDef[] = [...new Set(entries.map((e) => e.suffix))]\n .sort((a, b) => (suffixOrder.get(a) ?? 0) - (suffixOrder.get(b) ?? 0))\n .map((suffix) => {\n const entry = entries.find((e) => e.suffix === suffix)!;\n return {\n key: suffix,\n label: entry.field.label,\n type: mapDynamicTypeToInferred(entry.field.type),\n order: entry.field.order ?? 0,\n templateKey: suffix,\n placeholder: entry.field.placeholder,\n rows: entry.field.rows,\n };\n });\n sections.push({\n id: group.id,\n label: group.label,\n order: group.order,\n type: 'repeatable',\n templateKeyPrefix: firstPrefix,\n minEntries: 1,\n entryFields,\n initialEntryCount: Math.max(1, indices.length),\n });\n }\n continue;\n }\n\n if (withIndexOnly.length > 0) {\n // List-like repeatable: field_skills_1, field_skills_2, field_skills_3\n const byPrefix = new Map<string, DynamicField[]>();\n for (const field of withIndexOnly) {\n const m = field.id.match(REPEATABLE_LIST_PATTERN);\n if (m) {\n const [, prefix] = m;\n const key = `field_${prefix}`;\n if (!byPrefix.has(key)) byPrefix.set(key, []);\n byPrefix.get(key)!.push(field);\n }\n }\n const firstPrefix = byPrefix.keys().next().value;\n if (firstPrefix) {\n const fields = byPrefix.get(firstPrefix)!;\n const count = fields.length;\n const first = fields[0];\n sections.push({\n id: group.id,\n label: group.label,\n order: group.order,\n type: 'repeatable',\n templateKeyPrefix: firstPrefix,\n minEntries: 1,\n entryFields: [\n {\n key: 'item',\n label: first.label.replace(/\\s*\\d+$/, '').trim() || 'Item',\n type: 'text',\n order: 0,\n templateKey: '',\n placeholder: first.placeholder,\n },\n ],\n initialEntryCount: Math.max(1, count),\n });\n }\n continue;\n }\n\n // Single section: field_full_name, field_email, ...\n const fields: InferredFieldDef[] = groupFields.map((f) => ({\n key: f.id.replace(/^field_/, '') || f.id,\n label: f.label,\n type: mapDynamicTypeToInferred(f.type),\n order: f.order ?? 0,\n templateKey: f.id,\n placeholder: f.placeholder,\n rows: f.rows,\n }));\n sections.push({\n id: group.id,\n label: group.label,\n order: group.order,\n type: 'single',\n fields,\n });\n }\n\n // Ungrouped fields → one \"Other\" single section (exclude fields that belong to tree repeatable sections)\n const ungrouped = dynamicFields.filter(\n (f) => !fieldIdsInTreeRepeatable.has(f.id) && (!f.group || !fieldGroups.some((g) => g.id === f.group))\n );\n if (ungrouped.length > 0) {\n sections.push({\n id: 'ungrouped',\n label: 'Other',\n order: 999,\n type: 'single',\n fields: ungrouped\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0))\n .map((f) => ({\n key: f.id.replace(/^field_/, '') || f.id,\n label: f.label,\n type: mapDynamicTypeToInferred(f.type),\n order: f.order ?? 0,\n templateKey: f.id,\n placeholder: f.placeholder,\n rows: f.rows,\n })),\n });\n }\n\n return sections.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\n/** Section form state: single = object, repeatable = array of entries */\nexport type SectionFormState = Record<string, Record<string, string | string[]> | Array<Record<string, string | string[]>>>;\n\n/** Version 2 default_data: store nested sectionState so save/load round-trip is exact; flatten only when applying to template. */\nexport const DEFAULT_DATA_V2_VERSION = 2;\nexport type DefaultDataV2 = { version: 2; sectionState: SectionFormState };\n\nexport function isDefaultDataV2(data: unknown): data is DefaultDataV2 {\n return (\n typeof data === 'object' &&\n data !== null &&\n !Array.isArray(data) &&\n (data as { version?: number }).version === DEFAULT_DATA_V2_VERSION &&\n typeof (data as { sectionState?: unknown }).sectionState === 'object' &&\n (data as { sectionState: unknown }).sectionState !== null\n );\n}\n\nexport function defaultSectionState(sections: InferredSection[]): SectionFormState {\n const state: SectionFormState = {};\n const repeatables = sections.filter((s): s is InferredSectionRepeatable => s.type === 'repeatable');\n const childrenByParent = new Map<string, InferredSectionRepeatable[]>();\n for (const section of repeatables) {\n if (!section.parentId) continue;\n if (!childrenByParent.has(section.parentId)) childrenByParent.set(section.parentId, []);\n childrenByParent.get(section.parentId)!.push(section);\n }\n\n const createEmptyEntry = (section: InferredSectionRepeatable): Record<string, string | string[]> => {\n const entry: Record<string, string | string[]> = {};\n for (const field of section.entryFields) {\n entry[field.key] = field.type === 'list' ? [] : field.type === 'toggle' ? 'false' : '';\n }\n return entry;\n };\n\n const createInitialEntries = (section: InferredSectionRepeatable): Array<Record<string, string | string[]>> => {\n // Allow 0 entries when initialEntryCount/minEntries is 0 (optional repeatable page/section).\n const count = Math.max(0, section.initialEntryCount ?? 1);\n return Array.from({ length: count }, () => createEmptyEntry(section));\n };\n\n const seedNested = (parentSection: InferredSectionRepeatable, parentStateKey: string, parentEntryIndex: number): void => {\n const children = childrenByParent.get(parentSection.id) ?? [];\n for (const child of children) {\n const childStateKey = `${parentStateKey}_${parentEntryIndex}_${child.id}`;\n const childEntries = createInitialEntries(child);\n state[childStateKey] = childEntries;\n childEntries.forEach((_, childEntryIndex) => seedNested(child, childStateKey, childEntryIndex));\n }\n };\n\n for (const section of sections) {\n if (section.type !== 'single') continue;\n const obj: Record<string, string | string[]> = {};\n for (const f of section.fields) {\n obj[f.key] = f.type === 'list' ? [] : f.type === 'toggle' ? 'false' : '';\n }\n state[section.id] = obj;\n }\n\n const topLevelRepeatables = repeatables.filter((s) => !s.parentId);\n for (const section of topLevelRepeatables) {\n const entries = createInitialEntries(section);\n state[section.id] = entries;\n entries.forEach((_, entryIndex) => seedNested(section, section.id, entryIndex));\n }\n\n // Seed repeatable sections whose parent is a single (non-repeatable) section.\n // These are direct children of single sections and use their own id as state key (not composite).\n const singleSectionIds = new Set(sections.filter((s) => s.type === 'single').map((s) => s.id));\n for (const section of repeatables) {\n if (section.parentId && singleSectionIds.has(section.parentId)) {\n const entries = createInitialEntries(section);\n state[section.id] = entries;\n entries.forEach((_, entryIndex) => seedNested(section, section.id, entryIndex));\n }\n }\n\n return state;\n}\n\n/** Flatten section state to flat formData (field_id -> value) for applyFormDataToConfig */\nexport function flattenSectionStateToFormData(\n sectionState: SectionFormState,\n sections: InferredSection[]\n): Record<string, unknown> {\n const flat: Record<string, unknown> = {};\n const repeatables = sections.filter((s): s is InferredSectionRepeatable => s.type === 'repeatable');\n const childrenByParent = new Map<string, InferredSectionRepeatable[]>();\n for (const section of repeatables) {\n if (!section.parentId) continue;\n if (!childrenByParent.has(section.parentId)) childrenByParent.set(section.parentId, []);\n childrenByParent.get(section.parentId)!.push(section);\n }\n\n for (const section of sections) {\n if (section.type !== 'single') continue;\n const value = sectionState[section.id];\n if (value === undefined) continue;\n const obj = value as Record<string, string | string[]>;\n for (const f of section.fields) {\n const v = obj[f.key];\n flat[f.templateKey] = v ?? '';\n }\n }\n\n const emitRepeatable = (\n section: InferredSectionRepeatable,\n sectionStateKey: string,\n sectionPrefix: string\n ): void => {\n const entries = sectionState[sectionStateKey] as Array<Record<string, string | string[]>> | undefined;\n if (!Array.isArray(entries)) return;\n const sectionLabel = (section as { label?: string }).label ?? section.id;\n const children = childrenByParent.get(section.id) ?? [];\n\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i];\n const oneBased = i + 1;\n flat[`${sectionPrefix}_${oneBased}_sectionLabel`] = sectionLabel;\n flat[`${sectionPrefix}_${oneBased}_label`] = sectionLabel;\n\n for (const f of section.entryFields) {\n // Skip reserved per-entry meta keys (`__entryId`, `__entryName`).\n if (f.key === '__entryId' || f.key === '__entryName') continue;\n const v = entry[f.key];\n if (f.templateKey) {\n if (f.type === 'list' && Array.isArray(v)) {\n v.forEach((item, j) => {\n flat[`${sectionPrefix}_${oneBased}_${f.templateKey}_${j + 1}`] = String(item ?? '');\n });\n } else {\n flat[`${sectionPrefix}_${oneBased}_${f.templateKey}`] = v ?? '';\n }\n } else {\n flat[`${sectionPrefix}_${oneBased}`] = v ?? '';\n }\n }\n\n for (const child of children) {\n const childToken = child.templateKeyPrefix.startsWith('field_')\n ? child.templateKeyPrefix.slice(6)\n : child.templateKeyPrefix;\n const childStateKey = `${sectionStateKey}_${i}_${child.id}`;\n\n // Primary key style: parent_N_childToken_N_field (compact)\n const compactPrefix = `${sectionPrefix}_${oneBased}_${childToken}`;\n emitRepeatable(child, childStateKey, compactPrefix);\n\n // Alias key style: parent_N_field_childToken_N_field (with _field_ separator)\n // This is the format NESTED_REPEATABLE_KEY_REGEX expects in applyFormDataToConfig\n const aliasPrefix = `${sectionPrefix}_${oneBased}_field_${childToken}`;\n if (aliasPrefix !== compactPrefix) {\n emitRepeatable(child, childStateKey, aliasPrefix);\n }\n\n // Also emit with child's section ID as token for nodeId-based matching\n const childIdToken = child.id;\n if (childIdToken !== childToken) {\n const idPrefix = `${sectionPrefix}_${oneBased}_${childIdToken}`;\n emitRepeatable(child, childStateKey, idPrefix);\n const idAliasPrefix = `${sectionPrefix}_${oneBased}_field_${childIdToken}`;\n emitRepeatable(child, childStateKey, idAliasPrefix);\n }\n }\n }\n };\n\n // Emit top-level repeatables AND repeatables whose parent is a \"single\" section\n // (single parents don't go through emitRepeatable, so their children would be missed)\n const singleSectionIds = new Set(sections.filter((s) => s.type === 'single').map((s) => s.id));\n const effectiveTopLevel = repeatables.filter((s) => !s.parentId || singleSectionIds.has(s.parentId));\n for (const section of effectiveTopLevel) {\n emitRepeatable(section, section.id, section.templateKeyPrefix);\n }\n\n return flat;\n}\n\n/** Build section state from flat formData (e.g. from template elements on load). Pre-fills form so it matches preview. */\nexport function formDataToSectionState(\n flatFormData: Record<string, unknown>,\n sections: InferredSection[]\n): SectionFormState {\n const state: SectionFormState = {};\n\n const repeatables = sections.filter((s): s is InferredSectionRepeatable => s.type === 'repeatable');\n const childrenByParent = new Map<string, InferredSectionRepeatable[]>();\n for (const section of repeatables) {\n if (!section.parentId) continue;\n if (!childrenByParent.has(section.parentId)) childrenByParent.set(section.parentId, []);\n childrenByParent.get(section.parentId)!.push(section);\n }\n\n const escapeRegex = (v: string) => v.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n const buildEntriesForPrefix = (\n section: InferredSectionRepeatable,\n prefix: string\n ): Array<Record<string, string | string[]>> => {\n const hasEntrySuffixes = section.entryFields.some((f) => f.templateKey);\n\n if (hasEntrySuffixes) {\n const indexSet = new Set<number>();\n const prefixRegex = new RegExp(`^${escapeRegex(prefix)}_(\\\\d+)_`);\n for (const key of Object.keys(flatFormData)) {\n const match = key.match(prefixRegex);\n if (match) indexSet.add(parseInt(match[1], 10));\n }\n const indices = [...indexSet].sort((a, b) => a - b);\n if (indices.length === 0) indices.push(1);\n\n return indices.map((oneBased) => {\n const entry: Record<string, string | string[]> = {};\n for (const f of section.entryFields) {\n if (f.templateKey) {\n if (f.type === 'list') {\n const listKeys = Object.keys(flatFormData).filter((k) =>\n k.startsWith(`${prefix}_${oneBased}_${f.templateKey}_`) && /_\\d+$/.test(k)\n );\n entry[f.key] = listKeys\n .sort((a, b) => {\n const na = parseInt(a.split('_').pop()!, 10);\n const nb = parseInt(b.split('_').pop()!, 10);\n return na - nb;\n })\n .map((k) => String(flatFormData[k] ?? ''));\n } else {\n const v = flatFormData[`${prefix}_${oneBased}_${f.templateKey}`];\n entry[f.key] =\n f.type === 'toggle' ? (v === true || v === 'true' ? 'true' : 'false') : String(v ?? '');\n }\n } else {\n const v = flatFormData[`${prefix}_${oneBased}`];\n entry[f.key] = String(v ?? '');\n }\n }\n return entry;\n });\n }\n\n const listKeyRegex = new RegExp(`^${escapeRegex(prefix)}_(\\\\d+)$`);\n const indices = Object.keys(flatFormData)\n .map((k) => k.match(listKeyRegex))\n .filter((m): m is RegExpMatchArray => m !== null)\n .map((m) => parseInt(m[1], 10))\n .filter((n) => !Number.isNaN(n))\n .sort((a, b) => a - b);\n\n if (indices.length === 0) {\n return [{ [section.entryFields[0]?.key ?? 'item']: '' }];\n }\n\n return indices.map((oneBased) => {\n const entry: Record<string, string | string[]> = {};\n for (const f of section.entryFields) {\n entry[f.key] = String(flatFormData[`${prefix}_${oneBased}`] ?? '');\n }\n return entry;\n });\n };\n\n const parseRepeatable = (\n section: InferredSectionRepeatable,\n sectionStateKey: string,\n sectionPrefix: string\n ): void => {\n const entries = buildEntriesForPrefix(section, sectionPrefix);\n state[sectionStateKey] = entries;\n const children = childrenByParent.get(section.id) ?? [];\n\n entries.forEach((_, entryIndex) => {\n const oneBased = entryIndex + 1;\n for (const child of children) {\n const childToken = child.templateKeyPrefix.startsWith('field_')\n ? child.templateKeyPrefix.slice(6)\n : child.templateKeyPrefix;\n const childPrefix = `${sectionPrefix}_${oneBased}_${childToken}`;\n const childStateKey = `${sectionStateKey}_${entryIndex}_${child.id}`;\n parseRepeatable(child, childStateKey, childPrefix);\n }\n });\n };\n\n for (const section of sections) {\n if (section.type === 'single') {\n const obj: Record<string, string | string[]> = {};\n for (const f of section.fields) {\n const v = flatFormData[f.templateKey];\n obj[f.key] = f.type === 'list' ? (Array.isArray(v) ? v.map(String) : []) : f.type === 'toggle' ? (v === true || v === 'true' ? 'true' : 'false') : String(v ?? '');\n }\n state[section.id] = obj;\n }\n }\n\n const topLevelRepeatables = repeatables.filter((s) => !s.parentId);\n for (const section of topLevelRepeatables) {\n parseRepeatable(section, section.id, section.templateKeyPrefix);\n }\n\n return state;\n}\n","/**\n * Form schema (middle layer): dynamicFields, fieldGroups, repeatableSections.\n * Stored separately from config (structure). Used for load/merge and build from canvas.\n */\n\nimport type { TemplateConfig, TemplateConfigPage, CanvasNode } from '@/types/editor';\nimport { isGroup, isVerticalStackLayoutMode } from '@/types/editor';\nimport type { FormSchema, FormRenderPreset } from '@/lib/api';\n\nconst CLONE_SUFFIX = /_\\d+$/;\n\n/** Strip trailing _1, _2, etc. to get the base id (e.g. text-xxx_1_1_1 -> text-xxx). Use for storing clean ids. */\nexport function baseId(id: string): string {\n let s = id;\n while (CLONE_SUFFIX.test(s)) s = s.replace(CLONE_SUFFIX, '');\n return s;\n}\n\n/** Build form_schema from current canvas for persisting the Schema layer. Bindings (mappings) live in dynamicFields. */\nexport function buildFormSchemaFromCanvas(\n canvas: {\n dynamicFields: unknown[];\n fieldGroups: unknown[];\n pages: TemplateConfigPage[];\n formRenderPreset?: string;\n },\n options?: { defaultData?: Record<string, unknown> | null }\n): FormSchema {\n const repeatableSections: {\n nodeId: string;\n label: string;\n minEntries?: number;\n maxEntries?: number;\n entryFilter?: { mode: 'all' | 'range'; range?: string };\n }[] = [];\n const seenBaseIds = new Set<string>();\n const entryFilters: { nodeId: string; occurrenceIndex: number; mode: 'all' | 'range'; range?: string }[] = [];\n const occurrenceCountByBase = new Map<string, number>();\n\n function walk(children: CanvasNode[]) {\n for (const node of children) {\n const rep = (node as CanvasNode & {\n repeatableSection?: {\n label: string;\n minEntries?: number;\n maxEntries?: number;\n entryFilter?: { mode: 'all' | 'range'; range?: string };\n };\n }).repeatableSection;\n if (rep?.label) {\n // Same repeatable section can be painted on multiple groups (multi-bind). Dedupe by baseId\n // so the saved schema has one entry per logical section, not one per occurrence.\n const base = baseId(node.id);\n if (!seenBaseIds.has(base)) {\n seenBaseIds.add(base);\n repeatableSections.push({\n nodeId: node.id,\n label: rep.label,\n ...(rep.minEntries !== undefined && rep.minEntries !== null ? { minEntries: rep.minEntries } : {}),\n ...(rep.maxEntries !== undefined && rep.maxEntries !== null ? { maxEntries: rep.maxEntries } : {}),\n ...(rep.entryFilter?.mode === 'range' && rep.entryFilter.range?.trim()\n ? { entryFilter: { mode: 'range' as const, range: rep.entryFilter.range.trim() } }\n : {}),\n });\n }\n // Track occurrence index per baseId so the filter survives ID normalization on save.\n const occIdx = (occurrenceCountByBase.get(base) ?? 0) + 1;\n occurrenceCountByBase.set(base, occIdx);\n // Per-occurrence entry filter — keyed by (baseNodeId, occurrenceIndex). Skip 'all'/no-range filters.\n if (rep.entryFilter && rep.entryFilter.mode !== 'all' && rep.entryFilter.range && rep.entryFilter.range.trim()) {\n entryFilters.push({ nodeId: base, occurrenceIndex: occIdx, mode: rep.entryFilter.mode, range: rep.entryFilter.range.trim() });\n }\n }\n if (isGroup(node) && node.children?.length) walk(node.children);\n }\n }\n for (const page of canvas.pages ?? []) {\n if (page.children?.length) walk(page.children);\n }\n\n // Do not infer repeatable sections from clone IDs (e.g. group-xxx_1, group-xxx_2). Only nodes with\n // explicit repeatableSection are included. Otherwise after saving repeatableSections: [] the Schema\n // JSON would show inferred sections again because clone nodes still exist in the canvas.\n\n const out: NonNullable<FormSchema> = {\n dynamicFields: canvas.dynamicFields ?? [],\n fieldGroups: canvas.fieldGroups ?? [],\n repeatableSections,\n };\n if (entryFilters.length) {\n (out as NonNullable<FormSchema> & { entryFilters?: typeof entryFilters }).entryFilters = entryFilters;\n }\n if (options?.defaultData !== undefined) out.defaultData = options.defaultData;\n if (canvas.formRenderPreset) out.formRenderPreset = canvas.formRenderPreset as FormRenderPreset;\n return out;\n}\n\n/** Strip repeatableSection from every node in the tree (mutates in place). */\nfunction stripRepeatableFromNodes(nodes: CanvasNode[] | undefined): void {\n if (!nodes) return;\n for (const node of nodes) {\n delete (node as CanvasNode & { repeatableSection?: unknown }).repeatableSection;\n if (isGroup(node) && node.children?.length) stripRepeatableFromNodes(node.children);\n }\n}\n\n/** Merge form_schema into config (structure): add dynamicFields, fieldGroups, paint repeatableSection on nodes. */\nexport function mergeFormSchemaIntoConfig(\n config: TemplateConfig,\n formSchema: FormSchema | null | undefined\n): TemplateConfig {\n if (!formSchema || (typeof formSchema !== 'object')) return config;\n const cloned = JSON.parse(JSON.stringify(config)) as TemplateConfig;\n cloned.dynamicFields = (formSchema.dynamicFields ?? []) as TemplateConfig['dynamicFields'];\n cloned.fieldGroups = (formSchema.fieldGroups ?? []) as TemplateConfig['fieldGroups'];\n if (formSchema.formRenderPreset) {\n (cloned as TemplateConfig & { formRenderPreset?: FormRenderPreset }).formRenderPreset = formSchema.formRenderPreset;\n }\n const repeatableSections = formSchema.repeatableSections ?? [];\n const entryFilters = ((formSchema as NonNullable<FormSchema> & {\n entryFilters?: { nodeId: string; occurrenceIndex?: number; mode: 'all' | 'range'; range?: string }[];\n }).entryFilters) ?? [];\n const entryFilterBases = new Set(entryFilters.map((f) => baseId(f.nodeId)));\n\n // Always strip repeatableSection from all nodes first, so saving empty list actually clears them\n for (const page of cloned.pages ?? []) {\n if (page.children) stripRepeatableFromNodes(page.children);\n }\n\n // Paint repeatableSection on EVERY matching node (by id or baseId), not just the first.\n // This allows binding the same repeatable section to multiple groups on the template;\n // each matching group is then expanded with the same N entries at render time.\n const setRepeatableAll = (\n nodes: CanvasNode[] | undefined,\n nodeId: string,\n section: { label: string; minEntries?: number; maxEntries?: number; entryFilter?: { mode: 'all' | 'range'; range?: string } }\n ): number => {\n if (!nodes) return 0;\n let painted = 0;\n for (const node of nodes) {\n if (node.id === nodeId || baseId(node.id) === baseId(nodeId)) {\n (node as CanvasNode & { repeatableSection?: { label: string; minEntries?: number; maxEntries?: number } }).repeatableSection = { ...section };\n painted++;\n }\n if (isGroup(node) && node.children?.length) painted += setRepeatableAll(node.children, nodeId, section);\n }\n return painted;\n };\n for (const section of repeatableSections) {\n const { nodeId, label, minEntries, maxEntries } = section;\n const inlineFilter = (section as typeof section & { entryFilter?: { mode: 'all' | 'range'; range?: string } }).entryFilter;\n const inlineRange = inlineFilter?.mode === 'range' ? inlineFilter.range?.trim() : undefined;\n const shouldUseInlineFilter = !!inlineRange && !entryFilterBases.has(baseId(nodeId));\n const payload = {\n label,\n ...(minEntries !== undefined && minEntries !== null ? { minEntries } : {}),\n ...(maxEntries !== undefined && maxEntries !== null ? { maxEntries } : {}),\n ...(shouldUseInlineFilter\n ? { entryFilter: { mode: 'range' as const, range: inlineRange } }\n : {}),\n };\n for (const page of cloned.pages ?? []) {\n if (page.children) setRepeatableAll(page.children, nodeId, payload);\n }\n }\n\n // Apply per-occurrence entryFilter. Filters are keyed by (baseNodeId, occurrenceIndex);\n // legacy filters that use a full nodeId without occurrenceIndex are matched by exact id.\n if (entryFilters.length) {\n // Collect all painted occurrences (in document order) per baseId.\n const occurrencesByBase = new Map<string, CanvasNode[]>();\n const collect = (nodes: CanvasNode[] | undefined): void => {\n if (!nodes) return;\n for (const node of nodes) {\n const rep = (node as CanvasNode & { repeatableSection?: { label: string } }).repeatableSection;\n if (rep?.label) {\n const base = baseId(node.id);\n if (!occurrencesByBase.has(base)) occurrencesByBase.set(base, []);\n occurrencesByBase.get(base)!.push(node);\n }\n if (isGroup(node) && node.children?.length) collect(node.children);\n }\n };\n for (const page of cloned.pages ?? []) collect(page.children);\n\n for (const ef of entryFilters) {\n const filter = { mode: ef.mode, ...(ef.range ? { range: ef.range } : {}) };\n const base = baseId(ef.nodeId);\n const list = occurrencesByBase.get(base);\n if (!list || list.length === 0) continue;\n let target: CanvasNode | undefined;\n if (ef.occurrenceIndex && ef.occurrenceIndex >= 1) {\n target = list[ef.occurrenceIndex - 1];\n } else {\n // Legacy: match by exact id, fallback to first occurrence.\n target = list.find((n) => n.id === ef.nodeId) ?? list[0];\n }\n if (target) {\n const rep = (target as CanvasNode & { repeatableSection?: { label: string; entryFilter?: { mode: 'all' | 'range'; range?: string } } }).repeatableSection;\n if (rep) rep.entryFilter = filter;\n }\n }\n }\n return cloned;\n}\n\n/** Normalize repeatableSections nodeIds to base ids only (dynamic field mappings keep full ids to match structure). */\nexport function normalizeFormSchemaToBaseIds(schema: FormSchema): FormSchema {\n const out = JSON.parse(JSON.stringify(schema)) as FormSchema;\n if (out.repeatableSections?.length) {\n out.repeatableSections = out.repeatableSections.map((s) => ({\n ...s,\n nodeId: baseId(s.nodeId),\n }));\n }\n const filters = (out as NonNullable<FormSchema> & {\n entryFilters?: { nodeId: string; occurrenceIndex?: number; mode: 'all' | 'range'; range?: string }[];\n }).entryFilters;\n if (filters?.length) {\n (out as NonNullable<FormSchema> & { entryFilters?: typeof filters }).entryFilters = filters.map((f) => ({\n ...f,\n nodeId: baseId(f.nodeId),\n }));\n }\n return out;\n}\n\n/** Normalize ids inside repeatable section subtrees to base ids (mutates config). Call before saving structure so we persist clean ids. */\nexport function normalizeRepeatableSubtreesToBaseIds(config: TemplateConfig): void {\n const pages = config.pages ?? [];\n function normalizeNodeId(n: CanvasNode): void {\n (n as { id: string }).id = baseId(n.id);\n if (isGroup(n) && n.children?.length) n.children.forEach(normalizeNodeId);\n }\n function walk(children: CanvasNode[]): void {\n for (const node of children) {\n if (isGroup(node) && isVerticalStackLayoutMode(node.layoutMode) && node.children?.length) {\n for (const child of node.children) {\n const rep = (child as CanvasNode & { repeatableSection?: { label: string } }).repeatableSection;\n if (rep?.label) {\n normalizeNodeId(child);\n }\n }\n for (const child of node.children) {\n if (isGroup(child) && child.children?.length) walk(child.children);\n }\n return;\n }\n if (isGroup(node) && node.children?.length) walk(node.children);\n }\n }\n for (const page of pages) {\n if (page.children?.length) walk(page.children);\n }\n}\n","/**\n * Apply form field values to a template config using a form-template mapping.\n * Returns a new config with element properties updated (e.g. text, src) so preview shows filled data.\n * Supports repeatable sections: expands nodes marked repeatableSection (direct children of stack)\n * using form keys field_<nodeId>_<index>_<fieldId>, then applies values to cloned elements.\n * Runs stack reflow so vertical stack groups shift when text/height changes.\n */\n\nimport type { TemplateConfig, TemplateConfigPage, CanvasNode, DynamicField, CanvasElement } from '@/types/editor';\nimport type { FormTemplateMappingEntry } from '@/lib/api';\nimport { applyStackReflowToPageTree } from '@/lib/layoutEngine';\nimport { isGroup, isElement, isVerticalStackLayoutMode, generateId, PAGE_BACKGROUND_ELEMENT_ID } from '@/types/editor';\nimport { baseId } from '@/lib/formSchema';\nimport { renderSmartElementToDataUri } from '@/lib/smartElements';\nimport type { EntryMeta } from '@/lib/repeatableEntryIds';\n\n/** Form key pattern for repeatable entries: field_<nodeId>_<oneBasedIndex>_<fieldId> */\nconst REPEATABLE_KEY_REGEX = /^field_(.+)_(\\d+)_(.+)$/;\n/** Nested: field_<parentId>_<parentIndex>_field_<childId>_<childIndex>_<fieldId> */\nconst NESTED_REPEATABLE_KEY_REGEX = /^field_(.+)_(\\d+)_field_(.+)_(\\d+)_(.+)$/;\n/** Canonical form key pattern: field_<path>_N_<suffix> (can include multiple _N_) */\nconst FORMDEF_CANONICAL_KEY_REGEX = /^field_.+_N_.+$/;\n\n/**\n * Parse a 1-based range expression into a unique list of indices in filter order.\n * Supports: \"1-2\", \"1,3,5\", \"2-\" (open end -> max), \"-3\" (1..3), and `#token`\n * tokens that match an entry's `__entryId` or `__entryName` (case-insensitive,\n * resolved via the optional `entryMeta` 1-based array).\n * Returns null on empty/invalid -> caller treats as \"all\".\n */\nfunction parseEntryRange(range: string | undefined, max: number, entryMeta?: EntryMeta[]): number[] | null {\n if (!range || !range.trim()) return null;\n const normalizeToken = (value: string | undefined): string[] => {\n const raw = String(value ?? '').trim().toLowerCase();\n if (!raw) return [];\n const slug = raw.replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');\n const withoutTrailingS = slug.endsWith('s') ? slug.slice(0, -1) : '';\n return Array.from(new Set([raw, slug, withoutTrailingS].filter(Boolean)));\n };\n const out: number[] = [];\n const seen = new Set<number>();\n const addIndex = (idx: number) => {\n if (idx < 1 || idx > max || seen.has(idx)) return;\n seen.add(idx);\n out.push(idx);\n };\n let sawSelector = false;\n for (const partRaw of range.split(',')) {\n const part = partRaw.trim();\n if (!part) continue;\n // Token reference: `#abc123` or `#father` matches by entryId or entryName.\n if (part.startsWith('#')) {\n sawSelector = true;\n const tokens = normalizeToken(part.slice(1));\n if (!tokens.length || !entryMeta?.length) continue;\n for (let i = 0; i < entryMeta.length; i++) {\n const m = entryMeta[i];\n if (!m) continue;\n const candidates = [...normalizeToken(m.id), ...normalizeToken(m.name)];\n if (candidates.some((candidate) => tokens.includes(candidate))) {\n addIndex(i + 1);\n }\n }\n continue;\n }\n if (/^\\d+$/.test(part)) {\n sawSelector = true;\n const n = parseInt(part, 10);\n addIndex(n);\n continue;\n }\n const m = /^(\\d*)\\s*-\\s*(\\d*)$/.exec(part);\n if (!m) continue;\n sawSelector = true;\n const start = m[1] === '' ? 1 : Math.max(1, parseInt(m[1], 10));\n const end = m[2] === '' ? max : Math.min(max, parseInt(m[2], 10));\n for (let i = start; i <= end; i++) addIndex(i);\n }\n if (out.length === 0) return sawSelector ? [] : null;\n return out;\n}\n\n/** Apply textCase transform to a string value */\nfunction applyTextCase(text: string, textCase?: string): string {\n if (!textCase || textCase === 'none') return text;\n switch (textCase) {\n case 'uppercase': return text.toUpperCase();\n case 'lowercase': return text.toLowerCase();\n case 'capitalize': return text.replace(/(?<!\\S)\\w|(?<=[-])\\w/g, (c) => c.toUpperCase());\n default: return text;\n }\n}\n\nfunction setInTree(nodes: any[], elementId: string, targetProperty: string, value: unknown): boolean {\n for (const node of nodes) {\n if (node.id === elementId) {\n if (targetProperty === 'link') {\n node.linkConfig = { ...(node.linkConfig || {}), url: String(value ?? '') };\n } else if (targetProperty.startsWith('smartProp:') && node.smartElementType) {\n // Smart element property binding: update the specific smart prop and re-render SVG\n const propKey = targetProperty.slice('smartProp:'.length);\n const newSmartProps = { ...(node.smartProps || {}), [propKey]: value };\n node.smartProps = newSmartProps;\n // Re-render SVG data URI for the smart element\n const newSrc = renderSmartElementToDataUri(node.smartElementType, newSmartProps, node.width, node.height);\n if (newSrc) node.src = newSrc;\n } else if (targetProperty === 'text' && node.type === 'text' && typeof value === 'string') {\n // Use a space for empty text so Fabric renders blank instead of showing \"Text\" placeholder\n const textVal = value === '' ? ' ' : value;\n node[targetProperty] = applyTextCase(textVal, node.textCase);\n } else {\n node[targetProperty] = value;\n }\n // When text changes, clear height so layout reflow will measure and siblings below move correctly.\n // Exception: auto-shrink textboxes need their explicit height preserved as the shrink target.\n // The UsePackage client manual-preview path preserves this height; deleting it in the\n // schemaless EC2/package resolver made staging choose a different font size/width.\n if (targetProperty === 'text' && node.type === 'text') {\n const overflowPolicy = String((node as CanvasElement).overflowPolicy ?? 'grow-and-push');\n // PARITY FIX (v2): mirror the EC2 form-api setInTree behaviour, which\n // ALWAYS clears stale measured height after binding text. Preserving the\n // height here (previous fix) broke vertical-stack auto-shift on client\n // preview and client PDF export, because bound text could no longer\n // grow taller than its editor-time height — siblings below didn't move.\n // Auto-shrink keeps its explicit height as the shrink-target ceiling;\n // everything else gets re-measured by the stack reflow pass below.\n if (overflowPolicy !== 'auto-shrink') {\n delete node.height;\n }\n }\n // When image src changes, clear stale natural dimensions so the server\n // renderer computes cover layout from the actual loaded image dimensions.\n if ((targetProperty === 'src' || targetProperty === 'imageUrl') && node.type === 'image') {\n delete node.imageNaturalWidth;\n delete node.imageNaturalHeight;\n }\n return true;\n }\n if (node.children && Array.isArray(node.children)) {\n if (setInTree(node.children, elementId, targetProperty, value)) return true;\n }\n }\n return false;\n}\n\n/** Collect all groups whose __baseNodeId or baseId(id) equals baseNodeId, in tree order. */\nfunction collectGroupsByBaseId(pages: TemplateConfigPage[], baseNodeId: string): CanvasNode[] {\n const groups: CanvasNode[] = [];\n function collect(children: CanvasNode[]) {\n if (!Array.isArray(children)) return;\n for (const node of children) {\n const base = (node as CanvasNode & { __baseNodeId?: string }).__baseNodeId ?? baseId(node.id);\n if (base === baseNodeId) groups.push(node);\n if (isGroup(node) && node.children?.length) collect(node.children);\n }\n }\n for (const page of pages) if (page.children?.length) collect(page.children);\n return groups;\n}\n\n/** Find descendant with __sourceId === sourceId or id === sourceId (for unexpanded trees). Also matches by baseId when mapping has base id but clone has suffixed id. */\nfunction findElementBySourceIdInSubtree(nodes: CanvasNode[], sourceId: string): string | undefined {\n const sourceBase = baseId(sourceId);\n for (const node of nodes) {\n const src = (node as CanvasNode & { __sourceId?: string }).__sourceId;\n const nodeId = node.id;\n if (src === sourceId || nodeId === sourceId) return node.id;\n if (sourceBase && (baseId(src ?? nodeId) === sourceBase)) return node.id;\n if (isGroup(node) && node.children?.length) {\n const found = findElementBySourceIdInSubtree(node.children, sourceId);\n if (found) return found;\n }\n }\n return undefined;\n}\n\n/** Find the resolved element id for a repeatable entry when map lookup fails: i-th group with __baseNodeId, then descendant with __sourceId === sourceElementId. */\nfunction findRepeatableElementBySourceId(\n pages: TemplateConfigPage[],\n baseNodeId: string,\n oneBasedIndex: number,\n sourceElementId: string\n): string | undefined {\n const groups = collectGroupsByBaseId(pages, baseNodeId);\n const group = groups[oneBasedIndex - 1];\n if (!group) return undefined;\n if (!isGroup(group) || !group.children?.length) return undefined;\n return findElementBySourceIdInSubtree(group.children, sourceElementId) ?? ((group as CanvasNode & { __sourceId?: string }).__sourceId === sourceElementId ? group.id : undefined);\n}\n\n/**\n * Find resolved element ids across ALL occurrences of a repeatable section bound to multiple groups.\n * After Phase 1, groups with the same baseNodeId expand to N children each, in tree order. Per-entry\n * lookups must therefore index *within* each occurrence (every Nth group), not into a flat list.\n */\nfunction findAllRepeatableElementsBySourceId(\n pages: TemplateConfigPage[],\n baseNodeId: string,\n oneBasedIndex: number,\n sourceElementId: string,\n expectedEntriesPerOccurrence?: number,\n): string[] {\n const groups = collectGroupsByBaseId(pages, baseNodeId);\n if (!groups.length) return [];\n const N = Math.max(1, expectedEntriesPerOccurrence ?? groups.length);\n // groups is flat: [occ1_e1, occ1_e2, ..., occ1_eN, occ2_e1, ...]\n const out: string[] = [];\n for (let occStart = 0; occStart < groups.length; occStart += N) {\n const group = groups[occStart + (oneBasedIndex - 1)];\n if (!group || !isGroup(group) || !group.children?.length) continue;\n const found = findElementBySourceIdInSubtree(group.children, sourceElementId)\n ?? ((group as CanvasNode & { __sourceId?: string }).__sourceId === sourceElementId ? group.id : undefined);\n if (found) out.push(found);\n }\n return out;\n}\n\n/** Find element in nested repeatable when map fails: parentPi-th parent group, then childCi-th child group inside it, then descendant with __sourceId. */\nfunction findNestedRepeatableElementBySourceId(\n pages: TemplateConfigPage[],\n parentBaseNodeId: string,\n parentPi: number,\n childBaseNodeId: string,\n childCi: number,\n sourceElementId: string\n): string | undefined {\n const parentGroups = collectGroupsByBaseId(pages, parentBaseNodeId);\n const parentGroup = parentGroups[parentPi - 1];\n if (!parentGroup || !isGroup(parentGroup) || !parentGroup.children?.length) return undefined;\n const childGroups: CanvasNode[] = [];\n function collectChild(children: CanvasNode[]) {\n for (const node of children) {\n const base = (node as CanvasNode & { __baseNodeId?: string }).__baseNodeId ?? baseId(node.id);\n if (base === childBaseNodeId) childGroups.push(node);\n if (isGroup(node) && node.children?.length) collectChild(node.children);\n }\n }\n collectChild(parentGroup.children);\n const childGroup = childGroups[childCi - 1];\n if (!childGroup || !isGroup(childGroup) || !childGroup.children?.length) return undefined;\n return findElementBySourceIdInSubtree(childGroup.children, sourceElementId) ?? ((childGroup as CanvasNode & { __sourceId?: string }).__sourceId === sourceElementId ? childGroup.id : undefined);\n}\n\nfunction repeatableLabelKey(label: string | undefined): string {\n return String(label ?? '').trim().toLowerCase();\n}\n\nfunction repeatableLabelSlug(label: string | undefined): string {\n return repeatableLabelKey(label).replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');\n}\n\nfunction addToSetMap(map: Map<string, Set<string>>, key: string, value: string): void {\n if (!key || !value) return;\n const set = map.get(key);\n if (set) set.add(value);\n else map.set(key, new Set([value]));\n}\n\nfunction getFieldKeyAliases(fieldId: string): string[] {\n const aliases = new Set<string>([fieldId]);\n const canonicalParts = fieldId.split('_N_');\n if (canonicalParts.length > 1) aliases.add(canonicalParts[canonicalParts.length - 1]);\n return Array.from(aliases).filter(Boolean);\n}\n\n/** Prefix for generateId based on node type. */\nfunction idPrefix(node: CanvasNode): string {\n if (isGroup(node)) return 'group';\n const t = (node as CanvasElement).type;\n if (t === 'text') return 'text';\n if (t === 'image') return 'img';\n if (t === 'shape') return 'shape';\n return 'el';\n}\n\n/**\n * Deep clone a node and every descendant with new ids. When `cloneSuffix` is\n * provided, ids are made deterministic — `${baseId(oldId)}__c${cloneSuffix}` —\n * so re-running this on the same source node produces the same ids across\n * renders. This is critical for the live preview: stable ids let React/Fabric\n * diff existing objects (and reuse cached images) instead of treating every\n * keystroke as a brand-new tree (which causes images to flicker/refetch).\n *\n * When `cloneSuffix` is omitted, a random UUID per node is generated (legacy).\n *\n * Returns [clone, map of oldId -> newId].\n */\nfunction cloneNodeWithNewIds(\n node: CanvasNode,\n cloneSuffix?: string\n): [CanvasNode, Map<string, string>] {\n const oldToNew = new Map<string, string>();\n function clone(n: CanvasNode): CanvasNode {\n const newId = cloneSuffix\n ? `${baseId(n.id)}__c${cloneSuffix}`\n : generateId(idPrefix(n));\n oldToNew.set(n.id, newId);\n const base = baseId(n.id);\n const withMeta = { ...n, id: newId, __baseNodeId: base, __sourceId: n.id } as CanvasNode & { __baseNodeId?: string; __sourceId?: string };\n if (isGroup(n) && n.children?.length) {\n return { ...withMeta, children: n.children.map(clone) } as CanvasNode;\n }\n return withMeta as CanvasNode;\n }\n const copy = JSON.parse(JSON.stringify(node)) as CanvasNode;\n const cloned = clone(copy);\n return [cloned, oldToNew];\n}\n\ntype RepeatableInfo = { parentChildren: CanvasNode[]; startIndex: number; count: number; node: CanvasNode; baseNodeId: string; parentBaseNodeId?: string; parentEntryIndex?: number };\n\n/** Derive repeatable list from config (legacy: nodes with repeatableSection). Single source of shape { nodeId, label }. */\nfunction getRepeatableFromConfig(pages: TemplateConfigPage[]): { nodeId: string; label: string }[] {\n const result: { nodeId: string; label: string }[] = [];\n function walk(children: CanvasNode[]) {\n if (!children) return;\n for (const node of children) {\n if (isGroup(node) && isVerticalStackLayoutMode(node.layoutMode) && node.children?.length) {\n for (const child of node.children) {\n const rep = (child as CanvasNode & { repeatableSection?: { label: string } }).repeatableSection;\n if (rep?.label) result.push({ nodeId: child.id, label: rep.label });\n }\n }\n if (isGroup(node) && node.children?.length) walk(node.children);\n }\n }\n for (const page of pages) if (page.children?.length) walk(page.children);\n return result;\n}\n\n/** Find repeatable blocks by node id or base id. Supports unexpanded (one node) or expanded (base_1, base_2, ...). Returns one entry per repeatable so we replace the whole block with N clones. parentBaseNodeId = base id of the stack that contains this block (for nested sections). */\nfunction findRepeatableByNodeIds(\n pages: TemplateConfigPage[],\n nodeIds: string[]\n): RepeatableInfo[] {\n const schemaBaseIds = new Set(nodeIds.map((id) => baseId(id)));\n const result: RepeatableInfo[] = [];\n const clonePattern = /^(.+)_(\\d+)$/;\n const hasRepeatableSection = (n: CanvasNode) => !!(n as CanvasNode & { repeatableSection?: { label?: string } }).repeatableSection?.label;\n\n function walk(children: CanvasNode[], parentRepeatableBaseId?: string, parentInfo?: { parentChildren: CanvasNode[]; startIndex: number }, parentRepeatableEntryIndex?: number) {\n if (!Array.isArray(children)) return;\n for (let i = 0; i < children.length; i++) {\n const node = children[i];\n if (isGroup(node) && isVerticalStackLayoutMode(node.layoutMode) && node.children?.length) {\n const kids = node.children;\n let j = 0;\n while (j < kids.length) {\n const child = kids[j];\n const childBase = baseId(child.id);\n const childBaseFromMeta = (child as { __baseNodeId?: string }).__baseNodeId;\n const isMatch =\n schemaBaseIds.has(child.id) ||\n schemaBaseIds.has(childBase) ||\n (childBaseFromMeta != null && schemaBaseIds.has(childBaseFromMeta));\n if (!isMatch) {\n if (isGroup(child) && Array.isArray(child.children)) walk(child.children, parentRepeatableBaseId, undefined, parentRepeatableEntryIndex);\n j++;\n continue;\n }\n let count = 1;\n const nextBaseFromMeta = (child as { __baseNodeId?: string }).__baseNodeId;\n const effectiveChildBase = nextBaseFromMeta ?? childBase;\n if (child.id !== childBase && child.id !== effectiveChildBase) {\n while (j + count < kids.length) {\n const next = kids[j + count];\n const nextMatch = next.id.match(clonePattern);\n const nextMeta = (next as { __baseNodeId?: string }).__baseNodeId;\n const nextBase = nextMeta ?? (nextMatch ? baseId(nextMatch[1]) : baseId(next.id));\n if (nextBase === effectiveChildBase) count++;\n else break;\n }\n }\n result.push({\n parentChildren: kids,\n startIndex: j,\n count,\n node: child,\n baseNodeId: childBaseFromMeta ?? childBase,\n parentBaseNodeId: parentRepeatableBaseId,\n parentEntryIndex: parentRepeatableEntryIndex,\n });\n const childEntryIndex = (child as { __repeatableEntryIndex?: number }).__repeatableEntryIndex;\n if (isGroup(child) && Array.isArray(child.children)) walk(child.children, effectiveChildBase, undefined, childEntryIndex);\n j += count;\n }\n } else if (isGroup(node) && node.children?.length) {\n // Also find repeatable groups that are not direct children of a stack (match by id so inference and apply use same nodes)\n const nodeBase = baseId(node.id);\n const selfMatch =\n schemaBaseIds.has(node.id) ||\n schemaBaseIds.has(nodeBase) ||\n ((node as { __baseNodeId?: string }).__baseNodeId != null && schemaBaseIds.has((node as { __baseNodeId?: string }).__baseNodeId!));\n const isSelfRepeatable = selfMatch && hasRepeatableSection(node);\n let matchedSelfBase: string | undefined;\n if (selfMatch) matchedSelfBase = (node as { __baseNodeId?: string }).__baseNodeId ?? nodeBase;\n if (isSelfRepeatable) {\n const parentChildren = parentInfo?.parentChildren ?? children;\n const startIndex = parentInfo ? parentInfo.startIndex : i;\n let count = 1;\n const effectiveBase = matchedSelfBase ?? nodeBase;\n if (node.id !== nodeBase && node.id !== effectiveBase) {\n while (i + count < children.length) {\n const next = children[i + count];\n const nextMatch = next.id.match(clonePattern);\n const nextMeta = (next as { __baseNodeId?: string }).__baseNodeId;\n const nextBase = nextMeta ?? (nextMatch ? baseId(nextMatch[1]) : baseId(next.id));\n if (nextBase === effectiveBase) count++;\n else break;\n }\n }\n result.push({\n parentChildren: children,\n startIndex: i,\n count,\n node,\n baseNodeId: effectiveBase,\n parentBaseNodeId: parentRepeatableBaseId,\n parentEntryIndex: parentRepeatableEntryIndex,\n });\n }\n const nodeEntryIndex = (node as { __repeatableEntryIndex?: number }).__repeatableEntryIndex;\n walk(node.children, matchedSelfBase ?? parentRepeatableBaseId, undefined, nodeEntryIndex ?? parentRepeatableEntryIndex);\n }\n }\n }\n for (const page of pages) if (page.children?.length) walk(page.children);\n return result;\n}\n\n/** Find every group that has repeatableSection (for fallback when nodeIds don't match). Tree order, top-level only. */\nfunction findAllTopLevelRepeatableBlocks(pages: TemplateConfigPage[]): RepeatableInfo[] {\n const result: RepeatableInfo[] = [];\n const hasRepeatableSection = (n: CanvasNode) => !!(n as CanvasNode & { repeatableSection?: { label?: string } }).repeatableSection?.label;\n function walk(children: CanvasNode[]) {\n if (!Array.isArray(children)) return;\n for (let i = 0; i < children.length; i++) {\n const node = children[i];\n if (!isGroup(node) || !node.children?.length) continue;\n if (hasRepeatableSection(node) && !result.some((r) => r.baseNodeId === baseId(node.id))) {\n result.push({\n parentChildren: children,\n startIndex: i,\n count: 1,\n node,\n baseNodeId: baseId(node.id),\n parentBaseNodeId: undefined,\n });\n }\n walk(node.children);\n }\n }\n for (const page of pages) if (page.children?.length) walk(page.children);\n return result;\n}\n\n/** Infer entry count for a repeatable nodeId from form value keys field_<nodeId>_<i>_*. */\nfunction getRepeatableEntryCount(nodeId: string, formValues: Record<string, unknown>): number {\n let maxIndex = 0;\n const prefix = `field_${baseId(nodeId)}_`;\n for (const key of Object.keys(formValues)) {\n if (!key.startsWith(prefix)) continue;\n const rest = key.slice(prefix.length);\n const match = /^(\\d+)_/.exec(rest);\n if (match) maxIndex = Math.max(maxIndex, parseInt(match[1], 10));\n }\n return Math.max(1, maxIndex);\n}\n\n/** Infer max child index for nested: field_<parentId>_<pi>_field_<childId>_<ci>_* */\nfunction getNestedRepeatableEntryCount(parentId: string, parentIndex: number, childId: string, formValues: Record<string, unknown>): number {\n let maxIndex = 0;\n const prefix = `field_${baseId(parentId)}_${parentIndex}_field_${baseId(childId)}_`;\n for (const key of Object.keys(formValues)) {\n if (!key.startsWith(prefix)) continue;\n const rest = key.slice(prefix.length);\n const match = /^(\\d+)(_|$)/.exec(rest);\n if (match) maxIndex = Math.max(maxIndex, parseInt(match[1], 10));\n }\n return Math.max(1, maxIndex);\n}\n\n\n/** Repeatable section from schema or inferred; entryCount from form state so \"Add\" reflects in preview. */\nexport type RepeatableSectionInput = {\n nodeId: string;\n label: string;\n entryCount?: number;\n entryFilter?: { mode: 'all' | 'range'; range?: string };\n /**\n * 1-based per-entry metadata used to resolve `#token` filters.\n * For nested repeatables, this is the meta for the specific (parent index, child) pair.\n */\n entryMeta?: EntryMeta[];\n /** Nested repeatable metadata keyed as `${parentBaseNodeId}_${parentIndex1Based}_${childBaseNodeId}`. */\n nestedEntryMeta?: Record<string, EntryMeta[]>;\n};\n\n/** Repeatable page from schema; one config page is cloned N times when its `boundRepeatablePageId` matches `pageId`. */\nexport type RepeatablePageInput = {\n /** The repeatable page id (matches `TemplateConfigPage.boundRepeatablePageId`). */\n pageId: string;\n /** The schema's `templateKeyPrefix` used in form keys: `field_<prefix>_<i>_<fieldKey>`. */\n templateKeyPrefix: string;\n /** Number of entries to render. Defaults to inferred from form keys (>=1). */\n entryCount?: number;\n};\n\n/**\n * Returns a deep clone of config with form values applied per mapping.\n * Repeatable: single code path. List comes from schema when provided, else derived from config (legacy).\n * Always expand via findRepeatableByNodeIds.\n * When repeatable list items have entryCount (from section state), that drives how many clones are created.\n */\nexport function applyFormDataToConfig(\n config: TemplateConfig,\n mappings: FormTemplateMappingEntry[],\n formValues: Record<string, unknown>,\n repeatableSectionsFromSchema?: RepeatableSectionInput[] | { nodeId: string; label: string; entryFilter?: { mode: 'all' | 'range'; range?: string }; entryMeta?: EntryMeta[]; nestedEntryMeta?: Record<string, EntryMeta[]> }[],\n repeatableEntryCounts?: Record<string, number>,\n repeatableNestedEntryCounts?: Record<string, number>,\n /** Map of field key -> inputDisplay type (e.g. 'date', 'time') for formatting values on preview */\n displayFormatMap?: Map<string, string>,\n /** Repeatable pages from schema. For each, the matching `boundRepeatablePageId` page is cloned N times and per-entry form values are applied. */\n repeatablePagesFromSchema?: RepeatablePageInput[]\n): TemplateConfig {\n const cloned = JSON.parse(JSON.stringify(config)) as TemplateConfig;\n if (!cloned.pages) return cloned;\n\n const dynamicFields = cloned.dynamicFields as DynamicField[] | undefined;\n let pages = cloned.pages;\n\n // ── Phase 0: Expand pages with `boundRepeatablePageId` into N clones ────────\n // For each bound page, deep-clone N times (suffix-style page ids) with fresh\n // element ids tagged with __sourceId so `applyValue` can resolve clones.\n // Per-entry form values like `field_<prefix>_<i>_<fieldKey>` are then\n // applied to clone i's elements via dynamic-field id `field_<prefix>_N_<fieldKey>`.\n if (repeatablePagesFromSchema?.length) {\n const expanded: typeof pages = [];\n for (const page of pages) {\n const boundId = (page as TemplateConfigPage & { boundRepeatablePageId?: string }).boundRepeatablePageId;\n const schemaEntry = boundId ? repeatablePagesFromSchema.find((p) => p.pageId === boundId) : undefined;\n if (!schemaEntry) {\n expanded.push(page);\n continue;\n }\n const prefix = schemaEntry.templateKeyPrefix;\n // Determine N: explicit entryCount > infer from `field_<prefix>_<i>_*` keys > default 1.\n // entryCount === 0 is honored (the page is dropped entirely — used when the\n // schema's repeatablePage has minEntries: 0 and the user hasn't added any).\n let inferredN = 1;\n const keyPrefix = `field_${prefix}_`;\n for (const k of Object.keys(formValues)) {\n if (!k.startsWith(keyPrefix)) continue;\n const rest = k.slice(keyPrefix.length);\n const m = /^(\\d+)_/.exec(rest);\n if (m) inferredN = Math.max(inferredN, parseInt(m[1], 10));\n }\n const N = Math.max(0, schemaEntry.entryCount ?? inferredN);\n if (N === 0) {\n // Skip this page entirely — no entries means no rendered page.\n continue;\n }\n const basePageId = baseId(page.id);\n for (let i = 1; i <= N; i++) {\n const clonedPage = JSON.parse(JSON.stringify(page)) as TemplateConfigPage;\n clonedPage.id = N === 1 && i === 1 ? page.id : `${basePageId}_${i}`;\n // Track which entry this page represents so we can route per-entry values.\n (clonedPage as TemplateConfigPage & { __repeatablePagePrefix?: string; __repeatablePageEntryIndex?: number; __repeatablePageBaseId?: string }).__repeatablePagePrefix = prefix;\n (clonedPage as TemplateConfigPage & { __repeatablePageEntryIndex?: number }).__repeatablePageEntryIndex = i;\n (clonedPage as TemplateConfigPage & { __repeatablePageBaseId?: string }).__repeatablePageBaseId = basePageId;\n // Re-id every descendant so each clone has unique ids; remember source ids\n // so per-entry binding can resolve elements through dynamicField.mappings.\n if (clonedPage.children?.length) {\n // Use a deterministic suffix tied to the page+entry so re-rendering on\n // every keystroke produces stable element ids (no image refetching).\n const suffix = `${basePageId}_p${i}`;\n const reidChildren = (nodes: CanvasNode[]): CanvasNode[] => nodes.map((n) => {\n const [reclone] = cloneNodeWithNewIds(n, suffix);\n return reclone;\n });\n // For the first clone, keep original ids so non-repeatable mappings (and\n // any other code that targets the page) still work as before.\n if (i > 1) clonedPage.children = reidChildren(clonedPage.children);\n }\n expanded.push(clonedPage);\n }\n }\n pages = expanded;\n cloned.pages = pages;\n }\n\n const repeatableList =\n repeatableSectionsFromSchema?.length\n ? repeatableSectionsFromSchema\n : getRepeatableFromConfig(pages);\n const nodeIds = repeatableList.map((r) => r.nodeId);\n const repeatableBasesByLabel = new Map<string, Set<string>>();\n for (const r of repeatableList) {\n const base = baseId(r.nodeId);\n addToSetMap(repeatableBasesByLabel, repeatableLabelKey(r.label), base);\n addToSetMap(repeatableBasesByLabel, repeatableLabelSlug(r.label), base);\n }\n const repeatableTokenToBaseIds = new Map<string, Set<string>>();\n for (const r of repeatableList) {\n const base = baseId(r.nodeId);\n const labelBases = new Set<string>([\n base,\n ...(repeatableBasesByLabel.get(repeatableLabelKey(r.label)) ?? []),\n ...(repeatableBasesByLabel.get(repeatableLabelSlug(r.label)) ?? []),\n ]);\n for (const targetBase of labelBases) {\n addToSetMap(repeatableTokenToBaseIds, base, targetBase);\n addToSetMap(repeatableTokenToBaseIds, r.nodeId, targetBase);\n addToSetMap(repeatableTokenToBaseIds, repeatableLabelKey(r.label), targetBase);\n addToSetMap(repeatableTokenToBaseIds, repeatableLabelSlug(r.label), targetBase);\n }\n }\n const getRepeatableBaseIdsForToken = (token: string): string[] => {\n const direct = repeatableTokenToBaseIds.get(token) ?? repeatableTokenToBaseIds.get(baseId(token));\n return direct ? Array.from(direct) : [baseId(token)];\n };\n const entryCountFromList = (baseNodeId: string): number | undefined => {\n const item = repeatableList.find((r) => baseId(r.nodeId) === baseNodeId || r.nodeId === baseNodeId);\n return (item as RepeatableSectionInput | undefined)?.entryCount;\n };\n const entryFilterFromList = (baseNodeId: string): RepeatableSectionInput['entryFilter'] | undefined => {\n const item = repeatableList.find((r) => baseId(r.nodeId) === baseNodeId || r.nodeId === baseNodeId) as RepeatableSectionInput | undefined;\n const filter = item?.entryFilter;\n return filter?.mode === 'range' && filter.range?.trim() ? filter : undefined;\n };\n const entryMetaFromList = (baseNodeId: string): EntryMeta[] | undefined => {\n const item = repeatableList.find((r) => baseId(r.nodeId) === baseNodeId || r.nodeId === baseNodeId) as RepeatableSectionInput | undefined;\n return item?.entryMeta;\n };\n const nestedEntryMetaFromList = (parentBaseNodeId: string, parentIndex1Based: number, childBaseNodeId: string): EntryMeta[] | undefined => {\n for (const { parentBaseId, childBaseId } of getNestedBasePairs(parentBaseNodeId, childBaseNodeId)) {\n const item = repeatableList.find((r) => baseId(r.nodeId) === childBaseId || r.nodeId === childBaseId) as RepeatableSectionInput | undefined;\n const meta = item?.nestedEntryMeta?.[`${parentBaseId}_${parentIndex1Based}_${childBaseId}`];\n if (meta?.length) return meta;\n }\n return entryMetaFromList(childBaseNodeId);\n };\n /** Map key `${baseNodeId}_${entryIndex}_${oldElementId}` or same with fieldId (e.g. company_name) for apply; nested: `${parentId}_${pi}_${childId}_${ci}_${oldId}`.\n * Value is an array because the same repeatable section can be bound to multiple groups on the template;\n * every occurrence of entry i needs to receive the same value. */\n const resolvedIdMap = new Map<string, string[]>();\n const addResolved = (key: string, id: string) => {\n const arr = resolvedIdMap.get(key);\n if (arr) { if (!arr.includes(id)) arr.push(id); } else resolvedIdMap.set(key, [id]);\n };\n const mappedNewIds = new Set<string>();\n /** elementId -> field.id so we can store baseNodeId_i_fieldId in resolvedIdMap for form-key lookup. */\n const elementIdToFieldId = new Map<string, string>();\n if (dynamicFields?.length) {\n for (const f of dynamicFields) {\n for (const m of f.mappings ?? []) {\n const elId = (m as { elementId?: string } | undefined)?.elementId;\n if (elId) elementIdToFieldId.set(elId, f.id);\n }\n }\n }\n\n const repeatableInfosFirst = findRepeatableByNodeIds(pages, nodeIds);\n let topLevel = repeatableInfosFirst.filter((r) => !r.parentBaseNodeId);\n if (topLevel.length === 0 && repeatableList.length > 0) {\n topLevel = findAllTopLevelRepeatableBlocks(pages);\n }\n const nestedFirst = repeatableInfosFirst.filter((r) => r.parentBaseNodeId);\n /** For nested sections we need parent base id when building map keys in phase 2. */\n const nestedChildToParent = new Map<string, string>();\n for (const r of nestedFirst) {\n if (r.parentBaseNodeId) nestedChildToParent.set(r.baseNodeId, r.parentBaseNodeId);\n }\n const getNestedBasePairs = (parentToken: string, childToken: string): Array<{ parentBaseId: string; childBaseId: string }> => {\n const pairs: Array<{ parentBaseId: string; childBaseId: string }> = [];\n const seen = new Set<string>();\n for (const parentBaseId of getRepeatableBaseIdsForToken(parentToken)) {\n for (const childBaseId of getRepeatableBaseIdsForToken(childToken)) {\n const key = `${parentBaseId}::${childBaseId}`;\n if (seen.has(key)) continue;\n seen.add(key);\n pairs.push({ parentBaseId, childBaseId });\n }\n }\n return pairs.length ? pairs : [{ parentBaseId: baseId(parentToken), childBaseId: baseId(childToken) }];\n };\n const getNestedCountForBasePair = (parentBaseNodeId: string, parentIndex1Based: number, childBaseNodeId: string): number => {\n let maxCount = 0;\n for (const { parentBaseId, childBaseId } of getNestedBasePairs(parentBaseNodeId, childBaseNodeId)) {\n const aliasKey = `${parentBaseId}_${parentIndex1Based}_${childBaseId}`;\n maxCount = Math.max(\n maxCount,\n repeatableNestedEntryCounts?.[aliasKey] ?? 0,\n getNestedRepeatableEntryCount(parentBaseId, parentIndex1Based, childBaseId, formValues)\n );\n }\n return Math.max(1, maxCount);\n };\n\n // Phase 1: expand each occurrence of every top-level repeatable independently. Multiple groups\n // can be bound to the same repeatable section (same baseNodeId). Each occurrence is spliced\n // in place with N clones using a unique suffix so element ids never collide across occurrences.\n const phase1NewToOriginal = new Map<string, Map<string, string>>(); // key: `${parentBaseNodeId}_${i}` (last occurrence wins; nested phase only needs one parent map per entry index)\n // Track entry count per baseNodeId so nested phase 2 (and id-resolution helpers) know how many\n // entries each occurrence holds.\n const entryCountByBase = new Map<string, number>();\n // Process in reverse so later splices don't shift earlier startIndex values within the same parent.\n const orderedTopLevel = [...topLevel].sort((a, b) => {\n if (a.parentChildren !== b.parentChildren) return 0;\n return b.startIndex - a.startIndex;\n });\n // Group occurrences by reference-equal parentChildren so we can splice from end to start safely.\n const occByParent = new Map<CanvasNode[], RepeatableInfo[]>();\n for (const r of topLevel) {\n if (!occByParent.has(r.parentChildren)) occByParent.set(r.parentChildren, []);\n occByParent.get(r.parentChildren)!.push(r);\n }\n // Determine N per baseNodeId once.\n const computeN = (baseNodeId: string, sampleNodeId: string): number => {\n if (entryCountByBase.has(baseNodeId)) return entryCountByBase.get(baseNodeId)!;\n const countFromList = entryCountFromList(baseNodeId);\n const countFromState =\n countFromList ??\n repeatableEntryCounts?.[baseNodeId] ??\n repeatableEntryCounts?.[sampleNodeId] ??\n (repeatableEntryCounts && (() => {\n for (const k of Object.keys(repeatableEntryCounts)) {\n if (baseId(k) === baseNodeId) return repeatableEntryCounts[k];\n }\n return undefined;\n })());\n const N = Math.max(1, countFromState ?? getRepeatableEntryCount(baseNodeId, formValues));\n entryCountByBase.set(baseNodeId, N);\n return N;\n };\n // Tag each occurrence with a stable index (per baseNodeId) so suffixes are unique across occurrences.\n const occurrenceIndexByBase = new Map<string, number>();\n // Walk in tree order to assign occurrence indices, but we still splice from the back.\n for (const r of topLevel) {\n const idx = (occurrenceIndexByBase.get(r.baseNodeId) ?? 0) + 1;\n occurrenceIndexByBase.set(r.baseNodeId, idx);\n (r as RepeatableInfo & { __occurrenceIndex?: number }).__occurrenceIndex = idx;\n }\n for (const [parentChildren, blocks] of occByParent) {\n const sorted = [...blocks].sort((a, b) => b.startIndex - a.startIndex);\n for (const block of sorted) {\n const { node, baseNodeId, startIndex, count } = block;\n const occIdx = (block as RepeatableInfo & { __occurrenceIndex?: number }).__occurrenceIndex ?? 1;\n const N = computeN(baseNodeId, node.id);\n // Per-occurrence entry filter: if set, only entry indices listed are cloned in this group.\n // Indices are still 1-based and refer to the original entry list (so values look up by their\n // original index, e.g. range \"2-3\" still pulls field_..._2_* and field_..._3_* values).\n const entryFilter = (node as CanvasNode & {\n repeatableSection?: { entryFilter?: { mode: 'all' | 'range'; range?: string } };\n }).repeatableSection?.entryFilter ?? entryFilterFromList(baseNodeId);\n let entryIndices: number[];\n if (entryFilter && entryFilter.mode === 'range' && entryFilter.range) {\n const parsed = parseEntryRange(entryFilter.range, N, entryMetaFromList(baseNodeId));\n entryIndices = parsed ?? Array.from({ length: N }, (_, k) => k + 1);\n } else {\n entryIndices = Array.from({ length: N }, (_, k) => k + 1);\n }\n const clones: CanvasNode[] = [];\n for (const i of entryIndices) {\n // Suffix includes occurrence index so the same baseNodeId bound to two groups produces unique ids.\n const [clone, oldToNew] = cloneNodeWithNewIds(node, `${baseNodeId}_o${occIdx}_e${i}`);\n (clone as CanvasNode & { __repeatableEntryIndex?: number }).__repeatableEntryIndex = i;\n delete (clone as unknown as Record<string, unknown>).repeatableSection;\n clones.push(clone);\n const newToOriginal = new Map<string, string>();\n for (const [oldId, newId] of oldToNew) {\n addResolved(`${baseNodeId}_${i}_${oldId}`, newId);\n newToOriginal.set(newId, oldId);\n const fieldId = elementIdToFieldId.get(oldId);\n if (fieldId) {\n for (const alias of getFieldKeyAliases(fieldId)) addResolved(`${baseNodeId}_${i}_${alias}`, newId);\n }\n mappedNewIds.add(newId);\n }\n // For nested resolution we keep the last occurrence's mapping (originals are identical across occurrences).\n phase1NewToOriginal.set(`${baseNodeId}_${i}`, newToOriginal);\n }\n parentChildren.splice(startIndex, count, ...clones);\n }\n }\n\n // Phase 2: if we had nested sections, find blocks again (now one per parent clone) and expand.\n // Nodes we clone here have Phase-1 ids; mappings use original template ids. Resolve via phase1NewToOriginal.\n if (nestedChildToParent.size > 0) {\n const repeatableInfosSecond = findRepeatableByNodeIds(pages, nodeIds);\n const nestedBlocks = repeatableInfosSecond.filter((r) => nestedChildToParent.has(r.baseNodeId));\n const byChildBase = new Map<string, RepeatableInfo[]>();\n for (const r of nestedBlocks) {\n if (!byChildBase.has(r.baseNodeId)) byChildBase.set(r.baseNodeId, []);\n byChildBase.get(r.baseNodeId)!.push(r);\n }\n for (const [childBaseNodeId, blocks] of byChildBase) {\n const parentBaseNodeId = nestedChildToParent.get(childBaseNodeId)!;\n blocks.forEach((block, parentIndex0) => {\n const parentIndex1Based = block.parentEntryIndex ?? (parentIndex0 + 1);\n const { parentChildren, startIndex, count, node, baseNodeId } = block;\n const N = getNestedCountForBasePair(parentBaseNodeId, parentIndex1Based, baseNodeId);\n const phase1Map = phase1NewToOriginal.get(`${parentBaseNodeId}_${parentIndex1Based}`);\n // Per-occurrence entry filter for nested section: limits which entries render in this nested group.\n const nestedEntryFilter = (node as CanvasNode & {\n repeatableSection?: { entryFilter?: { mode: 'all' | 'range'; range?: string } };\n }).repeatableSection?.entryFilter ?? entryFilterFromList(baseNodeId);\n let nestedEntryIndices: number[];\n if (nestedEntryFilter && nestedEntryFilter.mode === 'range' && nestedEntryFilter.range) {\n const parsed = parseEntryRange(nestedEntryFilter.range, N, nestedEntryMetaFromList(parentBaseNodeId, parentIndex1Based, baseNodeId));\n nestedEntryIndices = parsed ?? Array.from({ length: N }, (_, k) => k + 1);\n } else {\n nestedEntryIndices = Array.from({ length: N }, (_, k) => k + 1);\n }\n const clones: CanvasNode[] = [];\n for (const i of nestedEntryIndices) {\n // Deterministic suffix per (parent, child base, entry index) — see Phase 1.\n const [clone, oldToNew] = cloneNodeWithNewIds(node, `${parentBaseNodeId}_p${parentIndex1Based}_${baseNodeId}_e${i}`);\n delete (clone as unknown as Record<string, unknown>).repeatableSection;\n clones.push(clone);\n for (const [oldId, newId] of oldToNew) {\n const originalId = phase1Map?.get(oldId) ?? oldId;\n addResolved(`${parentBaseNodeId}_${parentIndex1Based}_${baseNodeId}_${i}_${originalId}`, newId);\n addResolved(`${parentBaseNodeId}_${parentIndex1Based}_${baseNodeId}_${i}_${oldId}`, newId);\n for (const { parentBaseId, childBaseId } of getNestedBasePairs(parentBaseNodeId, baseNodeId)) {\n addResolved(`${parentBaseId}_${parentIndex1Based}_${childBaseId}_${i}_${originalId}`, newId);\n addResolved(`${parentBaseId}_${parentIndex1Based}_${childBaseId}_${i}_${oldId}`, newId);\n }\n const fieldId = elementIdToFieldId.get(originalId) ?? elementIdToFieldId.get(oldId);\n if (fieldId) {\n for (const alias of getFieldKeyAliases(fieldId)) {\n addResolved(`${parentBaseNodeId}_${parentIndex1Based}_${baseNodeId}_${i}_${alias}`, newId);\n for (const { parentBaseId, childBaseId } of getNestedBasePairs(parentBaseNodeId, baseNodeId)) {\n addResolved(`${parentBaseId}_${parentIndex1Based}_${childBaseId}_${i}_${alias}`, newId);\n }\n }\n }\n mappedNewIds.add(newId);\n }\n }\n parentChildren.splice(startIndex, count, ...clones);\n });\n }\n }\n\n (cloned as unknown as Record<string, unknown>).__cloneIdMap = Object.fromEntries(\n Array.from(resolvedIdMap.entries()).map(([k, v]) => [k, v.length === 1 ? v[0] : v])\n );\n (cloned as unknown as Record<string, unknown>).__mappedElementIds = Array.from(mappedNewIds);\n\n // Field label as fallback when value is empty (preview shows \"Text Content\" instead of template placeholder \"Text\")\n const fieldLabelByKey = new Map<string, string>();\n const fieldTypeByKey = new Map<string, string>();\n if (dynamicFields?.length) {\n for (const f of dynamicFields) {\n fieldLabelByKey.set(f.id, f.label ?? f.id);\n if (f.type) fieldTypeByKey.set(f.id, f.type);\n }\n }\n\n const pad2 = (v: string) => v.padStart(2, '0');\n\n /** Format date from yyyy-mm-dd (and ISO datetime variants) to dd/mm/yyyy for display */\n function formatDateForDisplay(val: string): string {\n if (!val || typeof val !== 'string') return val;\n const trimmed = val.trim();\n\n const isoMatch = trimmed.match(/^(\\d{4})-(\\d{1,2})-(\\d{1,2})(?:$|[T\\s])/);\n if (isoMatch) {\n const [, y, m, d] = isoMatch;\n return `${pad2(d)}/${pad2(m)}/${y}`;\n }\n\n const yFirstSlashMatch = trimmed.match(/^(\\d{4})\\/(\\d{1,2})\\/(\\d{1,2})$/);\n if (yFirstSlashMatch) {\n const [, y, m, d] = yFirstSlashMatch;\n return `${pad2(d)}/${pad2(m)}/${y}`;\n }\n\n const dmyOrMdyMatch = trimmed.match(/^(\\d{1,2})[/-](\\d{1,2})[/-](\\d{4})$/);\n if (dmyOrMdyMatch) {\n const [, d, m, y] = dmyOrMdyMatch;\n return `${pad2(d)}/${pad2(m)}/${y}`;\n }\n\n return val;\n }\n\n /** Format time from HH:MM (24h) to hh:mm AM/PM (12h) for display */\n function formatTimeForDisplay(val: string): string {\n if (!val || typeof val !== 'string') return val;\n const timeMatch = val.trim().match(/^(\\d{1,2}):(\\d{2})/);\n if (!timeMatch) return val;\n let h = parseInt(timeMatch[1], 10);\n const min = timeMatch[2];\n if (isNaN(h)) return val;\n const ampm = h >= 12 ? 'PM' : 'AM';\n h = h % 12 || 12;\n return `${h}:${min} ${ampm}`;\n }\n\n function formatDateTimeForDisplay(val: string): string {\n if (!val || typeof val !== 'string') return val;\n const trimmed = val.trim();\n const isoDateTimeMatch = trimmed.match(/^(\\d{4}-\\d{1,2}-\\d{1,2})[T\\s](\\d{1,2}:\\d{2})/);\n if (!isoDateTimeMatch) return formatDateForDisplay(trimmed);\n const [, datePart, timePart] = isoDateTimeMatch;\n return `${formatDateForDisplay(datePart)} ${formatTimeForDisplay(timePart)}`;\n }\n\n /** Resolve the display format for a given fieldKey. Checks displayFormatMap first, then falls back to dynamicField type. */\n function resolveDisplayFormat(fieldKey: string | undefined): string | undefined {\n if (!fieldKey) return undefined;\n\n const getCanonicalSuffix = (key: string): string | undefined => {\n if (!FORMDEF_CANONICAL_KEY_REGEX.test(key)) return undefined;\n const raw = key.replace(/^field_/, '');\n const parts = raw.split('_N_').map((p) => p.trim()).filter(Boolean);\n return parts.length > 1 ? parts[parts.length - 1] : undefined;\n };\n\n // Check displayFormatMap (from form config inputDisplay) first\n if (displayFormatMap) {\n const direct = displayFormatMap.get(fieldKey);\n if (direct) return direct;\n\n const canonicalSuffix = getCanonicalSuffix(fieldKey);\n if (canonicalSuffix) {\n const fmt = displayFormatMap.get(canonicalSuffix);\n if (fmt) return fmt;\n }\n\n if (fieldKey.startsWith('field_')) {\n const noPrefix = fieldKey.replace(/^field_/, '');\n const byNoPrefix = displayFormatMap.get(noPrefix);\n if (byNoPrefix) return byNoPrefix;\n }\n\n // For repeatable keys, extract the trailing fieldId\n const nestedMatch = fieldKey.match(NESTED_REPEATABLE_KEY_REGEX);\n if (nestedMatch) {\n const fmt = displayFormatMap.get(nestedMatch[5]);\n if (fmt) return fmt;\n }\n const match = fieldKey.match(REPEATABLE_KEY_REGEX);\n if (match) {\n const fmt = displayFormatMap.get(match[3]);\n if (fmt) return fmt;\n }\n }\n // Fall back to dynamic field type\n const direct = fieldTypeByKey.get(fieldKey);\n if (direct) return direct;\n\n const canonicalSuffix = getCanonicalSuffix(fieldKey);\n if (canonicalSuffix) {\n const byCanonicalSuffix = fieldTypeByKey.get(canonicalSuffix);\n if (byCanonicalSuffix) return byCanonicalSuffix;\n }\n\n const nestedMatch = fieldKey.match(NESTED_REPEATABLE_KEY_REGEX);\n if (nestedMatch) {\n return fieldTypeByKey.get(nestedMatch[5]);\n }\n const match = fieldKey.match(REPEATABLE_KEY_REGEX);\n if (match) {\n return fieldTypeByKey.get(match[3]);\n }\n return undefined;\n }\n\n const applyValue = (elementId: string, targetProperty: string, value: unknown, fieldKey?: string): boolean => {\n const isTextLike = targetProperty === 'text' || targetProperty === 'content';\n // Do not apply missing values so template defaults stay intact in preview/export.\n if (value === undefined || value === null) {\n return false;\n }\n // For non-text properties (color, stroke, font, opacity, link, image src, etc.), empty string means \"unchanged\".\n if (value === '' && !isTextLike) {\n return false;\n }\n let effectiveValue = (value === undefined || value === null || value === '') && isTextLike && fieldKey\n ? (fieldLabelByKey.get(fieldKey) ?? value)\n : value;\n if (effectiveValue === undefined) return false;\n\n // Format date/time values for text display on the template preview\n if (isTextLike && typeof effectiveValue === 'string' && effectiveValue !== '') {\n const fType = resolveDisplayFormat(fieldKey);\n const trimmed = effectiveValue.trim();\n const isIsoDateTimeLike = /^\\d{4}-\\d{1,2}-\\d{1,2}[T\\s]\\d{1,2}:\\d{2}/.test(trimmed);\n const isIsoDateLike = /^\\d{4}-\\d{1,2}-\\d{1,2}(?:$|[T\\s])/.test(trimmed);\n const is24hTimeLike = /^\\d{1,2}:\\d{2}(?::\\d{2})?$/.test(trimmed);\n\n // Value-shape detection takes precedence to handle repeated generic keys (e.g. many rows using key=\"value\")\n // where one row might be date and another time.\n if (fType === 'datetime-local' || isIsoDateTimeLike) {\n effectiveValue = formatDateTimeForDisplay(effectiveValue);\n } else if (fType === 'date' || isIsoDateLike) {\n effectiveValue = formatDateForDisplay(effectiveValue);\n } else if (fType === 'time' || is24hTimeLike) {\n effectiveValue = formatTimeForDisplay(effectiveValue);\n }\n }\n\n // Page background: apply to first page's settings.backgroundColor when mapping targets __pageBackground__.\n if (elementId === PAGE_BACKGROUND_ELEMENT_ID && targetProperty === 'backgroundColor' && typeof effectiveValue === 'string') {\n if (pages[0]?.settings) {\n pages[0].settings.backgroundColor = effectiveValue;\n return true;\n }\n }\n for (const page of pages) {\n if (page.children && setInTree(page.children, elementId, targetProperty, effectiveValue)) return true;\n }\n return false;\n };\n\n /** Find dynamic field by id or by mapping elementId (form key may use either). Tries fullKey so nested keys like field_parent_1_field_child_1_company_name match. Also matches by canonical suffix (field_<prefix>_N_<fieldId> ending with _<fieldId>). */\n const getFieldForRepeatableKey = (fieldId: string, fullKey?: string): DynamicField | undefined => {\n if (!dynamicFields?.length) return undefined;\n if (fullKey) {\n const byFullId = dynamicFields.find((f) => f.id === fullKey);\n if (byFullId) return byFullId;\n }\n const byId = dynamicFields.find((f) => f.id === fieldId);\n if (byId) return byId;\n const byElementId = dynamicFields.find((f) => (f.mappings ?? []).some((m) => (m as { elementId?: string } | undefined)?.elementId === fieldId));\n if (byElementId) return byElementId;\n // Try matching by canonical suffix: dynamic field id ends with _N_<fieldId> or _<fieldId>\n const suffixMatch = dynamicFields.find((f) => {\n if (f.id.endsWith(`_N_${fieldId}`)) return true;\n if (f.id.endsWith(`_${fieldId}`) && f.id.includes('_N_')) return true;\n return false;\n });\n return suffixMatch;\n };\n\n // 2) Apply nested repeatable form values: field_<parentId>_<pi>_field_<childId>_<ci>_<fieldId>\n if (dynamicFields?.length) {\n for (const key of Object.keys(formValues)) {\n const nestedMatch = key.match(NESTED_REPEATABLE_KEY_REGEX);\n if (nestedMatch) {\n const [, parentId, parentIndexStr, childId, childIndexStr, fieldId] = nestedMatch;\n const value = formValues[key];\n const field = getFieldForRepeatableKey(fieldId, key);\n for (const mapping of field?.mappings ?? []) {\n const oldElementId = (mapping as { elementId: string }).elementId;\n const mapKeyByElement = `${baseId(parentId)}_${parentIndexStr}_${baseId(childId)}_${childIndexStr}_${oldElementId}`;\n let elementIds: string[] | undefined = resolvedIdMap.get(mapKeyByElement);\n if (!elementIds || elementIds.length === 0) {\n const mapKeyByElementBase = `${baseId(parentId)}_${parentIndexStr}_${baseId(childId)}_${childIndexStr}_${baseId(oldElementId)}`;\n elementIds = resolvedIdMap.get(mapKeyByElementBase);\n }\n if (!elementIds || elementIds.length === 0) {\n const fallback = findNestedRepeatableElementBySourceId(\n pages, baseId(parentId), parseInt(parentIndexStr, 10), baseId(childId), parseInt(childIndexStr, 10), oldElementId\n ) ?? findNestedRepeatableElementBySourceId(\n pages, baseId(parentId), parseInt(parentIndexStr, 10), baseId(childId), parseInt(childIndexStr, 10), baseId(oldElementId)\n );\n if (fallback) elementIds = [fallback];\n }\n if (!elementIds || elementIds.length === 0) continue;\n const targetProperty = (mapping as { targetProperty: string }).targetProperty || 'text';\n for (const elementId of elementIds) applyValue(elementId, targetProperty, value, key);\n }\n }\n }\n }\n\n // 3) Apply top-level repeatable form values: field_<nodeId>_<i>_<fieldId> (skip if looks like nested)\n // Build a set of repeatable-page prefixes so we don't double-apply page-entry keys\n // here (those are handled in 4b against the per-page clones).\n const repeatablePagePrefixSet = new Set(\n (repeatablePagesFromSchema ?? []).map((p) => `field_${p.templateKeyPrefix}_`)\n );\n if (dynamicFields?.length) {\n for (const key of Object.keys(formValues)) {\n if (NESTED_REPEATABLE_KEY_REGEX.test(key)) continue;\n // Skip keys that belong to a repeatable page (handled in pass 4b).\n let isPageKey = false;\n for (const pfx of repeatablePagePrefixSet) {\n if (key.startsWith(pfx)) { isPageKey = true; break; }\n }\n if (isPageKey) continue;\n const match = key.match(REPEATABLE_KEY_REGEX);\n if (!match) continue;\n const [, nodeId, indexStr, fieldId] = match;\n const value = formValues[key];\n const field = getFieldForRepeatableKey(fieldId);\n for (const mapping of field?.mappings ?? []) {\n const oldElementId = (mapping as { elementId: string }).elementId;\n const elementIds = new Set<string>();\n for (const candidateBaseId of getRepeatableBaseIdsForToken(nodeId)) {\n const mapKeyByElement = `${candidateBaseId}_${indexStr}_${oldElementId}`;\n const foundByMap = resolvedIdMap.get(mapKeyByElement);\n for (const id of foundByMap ?? []) elementIds.add(id);\n\n if (!foundByMap?.length) {\n // Fallback: search every occurrence's i-th group for an element with this source id.\n const N = entryCountByBase.get(candidateBaseId);\n const found = findAllRepeatableElementsBySourceId(\n pages, candidateBaseId, parseInt(indexStr, 10), oldElementId, N\n );\n for (const id of found) elementIds.add(id);\n }\n }\n if (elementIds.size === 0) continue;\n const targetProperty = (mapping as { targetProperty: string }).targetProperty || 'text';\n for (const elementId of elementIds) applyValue(elementId, targetProperty, value, key);\n }\n }\n }\n\n // 4) Apply non-repeatable mappings (skip keys that look like repeatable so we don't double-apply)\n const repeatableKeySet = new Set(\n Object.keys(formValues).filter((k) => REPEATABLE_KEY_REGEX.test(k) || NESTED_REPEATABLE_KEY_REGEX.test(k))\n );\n for (const m of mappings) {\n if (repeatableKeySet.has(m.field_key)) continue;\n const value = formValues[m.field_key];\n applyValue(m.element_id, m.target_property, value, m.field_key);\n }\n\n // 4b) Apply per-entry values to repeatable-page clones.\n // dynamicFields bound to repeatable-page elements have id `field_<prefix>_N_<fieldKey>`.\n // For clone i of a page tagged with __repeatablePagePrefix=prefix, look up\n // `formValues['field_<prefix>_<i>_<fieldKey>']` and apply to the clone's\n // descendant whose original id (or __sourceId) matches mapping.elementId.\n if (repeatablePagesFromSchema?.length && dynamicFields?.length) {\n /** Find element id inside a page subtree by original id (matches id, __sourceId, or baseId). */\n const findInPage = (page: TemplateConfigPage, originalId: string): string | undefined => {\n if (!page.children?.length) return undefined;\n const findIn = (nodes: CanvasNode[]): string | undefined => {\n for (const n of nodes) {\n const src = (n as CanvasNode & { __sourceId?: string }).__sourceId;\n if (n.id === originalId || src === originalId || baseId(n.id) === baseId(originalId)) return n.id;\n if (isGroup(n) && n.children?.length) {\n const f = findIn(n.children);\n if (f) return f;\n }\n }\n return undefined;\n };\n return findIn(page.children);\n };\n for (const page of pages) {\n const meta = page as TemplateConfigPage & { __repeatablePagePrefix?: string; __repeatablePageEntryIndex?: number };\n const prefix = meta.__repeatablePagePrefix;\n const entryIndex = meta.__repeatablePageEntryIndex;\n if (!prefix || !entryIndex) continue;\n const fieldIdPrefix = `field_${prefix}_N_`;\n for (const field of dynamicFields) {\n if (!field.id.startsWith(fieldIdPrefix)) continue;\n const fieldKeySuffix = field.id.slice(fieldIdPrefix.length);\n const formKey = `field_${prefix}_${entryIndex}_${fieldKeySuffix}`;\n if (!(formKey in formValues)) continue;\n const value = formValues[formKey];\n for (const m of field.mappings ?? []) {\n const originalId = (m as { elementId?: string }).elementId;\n const targetProperty = (m as { targetProperty?: string }).targetProperty || 'text';\n if (!originalId) continue;\n const resolvedId = findInPage(page, originalId);\n if (!resolvedId) continue;\n if (page.children) setInTree(page.children, resolvedId, targetProperty, value);\n }\n }\n }\n }\n\n // 5) Stack reflow\n for (const page of pages) {\n if (page.children?.length) {\n page.children = applyStackReflowToPageTree(page.children, { preserveExplicitTextHeights: true });\n }\n }\n\n return cloned;\n}\n\n/**\n * Returns a copy of config with only structure: no dynamicFields, no fieldGroups, no repeatableSection on nodes.\n * Use when persisting the \"Structure\" layer; schema lives in form_schema, data in default_data.\n */\nexport function stripConfigToStructure(config: TemplateConfig): TemplateConfig {\n const cloned = JSON.parse(JSON.stringify(config)) as TemplateConfig;\n delete (cloned as unknown as Record<string, unknown>).dynamicFields;\n delete (cloned as unknown as Record<string, unknown>).fieldGroups;\n delete (cloned as unknown as Record<string, unknown>).__cloneIdMap;\n delete (cloned as unknown as Record<string, unknown>).__mappedElementIds;\n function walk(nodes: CanvasNode[] | undefined) {\n if (!nodes) return;\n for (const node of nodes) {\n delete (node as unknown as Record<string, unknown>).repeatableSection;\n if (isGroup(node) && node.children?.length) walk(node.children);\n }\n }\n for (const page of cloned.pages ?? []) {\n if (page.children?.length) walk(page.children);\n }\n return cloned;\n}\n\n/**\n * Returns a copy of config with all mapped element values cleared (structure only).\n * Uses dynamicFields mappings; supports both suffix-style clone ids and UUID clones (via __mappedElementIds).\n * Use when exporting or saving \"structure only\" so data lives only in default_data.\n */\nexport function stripMappedContentFromConfig(config: TemplateConfig): TemplateConfig {\n const cloned = JSON.parse(JSON.stringify(config)) as TemplateConfig;\n const dynamicFields = cloned.dynamicFields as DynamicField[] | undefined;\n const pages = cloned.pages ?? [];\n const mappedIds = new Set((cloned as unknown as Record<string, unknown>).__mappedElementIds as string[] | undefined);\n if (!dynamicFields?.length && mappedIds.size === 0) return cloned;\n\n function clearNode(node: CanvasNode, isUuidClone: boolean) {\n const n = node as unknown as Record<string, unknown>;\n if (isUuidClone) {\n // UUID clone: clear common mapped properties (we don't have mapping for this id)\n n.text = '';\n n.content = '';\n n.src = '';\n n.fill = '';\n n.stroke = '';\n n.opacity = '';\n n.linkConfig = { ...((n.linkConfig as object) || {}), url: '' };\n if ((node as { type?: string }).type === 'text') delete n.height;\n return;\n }\n for (const field of dynamicFields!) {\n for (const mapping of field.mappings ?? []) {\n const base = mapping.elementId;\n const targetProperty = mapping.targetProperty || 'text';\n if (node.id === base || node.id.startsWith(base + '_')) {\n if (targetProperty === 'link') {\n n.linkConfig = { ...((n.linkConfig as object) || {}), url: '' };\n } else {\n n[targetProperty] = '';\n }\n if (targetProperty === 'text' && (node as { type?: string }).type === 'text') {\n delete n.height;\n }\n return;\n }\n }\n }\n }\n\n function walk(nodes: CanvasNode[]) {\n if (!nodes) return;\n for (const node of nodes) {\n const id = node.id;\n const matchSuffix = dynamicFields?.length && dynamicFields.some((f) =>\n (f.mappings ?? []).some((m) => id === m.elementId || id.startsWith((m.elementId ?? '') + '_'))\n );\n const isUuidClone = mappedIds.has(id);\n if (matchSuffix || isUuidClone) clearNode(node, isUuidClone);\n if (isGroup(node) && node.children?.length) walk(node.children);\n }\n }\n for (const page of pages) if (page.children?.length) walk(page.children);\n return cloned;\n}\n","/**\n * Utilities for stable entry IDs on repeatable section entries.\n *\n * Each entry object in V2 sectionState carries two reserved keys:\n * - `__entryId` auto-generated short id (6 chars), assigned on creation\n * - `__entryName` optional user-set friendly name (free text)\n *\n * These IDs let the user reference specific repeatable entries from the\n * `entryFilter.range` field (e.g. `#abc123, #father, 1-2`) so the selection\n * survives reordering, additions, and deletions. They are stripped before\n * flattening to flat formData so they never reach the canvas renderer as\n * dynamic-field values.\n */\n\nimport type { InferredSection, InferredSectionRepeatable, SectionFormState } from '@/lib/inferFormSchemaFromTemplate';\n\nexport const ENTRY_ID_KEY = '__entryId';\nexport const ENTRY_NAME_KEY = '__entryName';\n\n/** Reserved per-entry keys that must never be flattened to form data or treated as fields. */\nexport const RESERVED_ENTRY_META_KEYS: ReadonlySet<string> = new Set([ENTRY_ID_KEY, ENTRY_NAME_KEY]);\n\n/** 1-based per-entry meta exposed to the entry-filter resolver. */\nexport interface EntryMeta {\n id?: string;\n name?: string;\n}\n\n/** Generate a short, URL-safe, lowercase id. ~36^6 ≈ 2.1B combinations — collision-safe within a section. */\nexport function generateEntryId(): string {\n // 6 chars from base36; pad in the rare case of leading zeros being trimmed.\n const raw = Math.floor(Math.random() * 36 ** 6).toString(36);\n return raw.padStart(6, '0');\n}\n\n/** Read meta from an entry object without mutation. */\nexport function readEntryMeta(entry: Record<string, unknown> | undefined | null): EntryMeta {\n if (!entry || typeof entry !== 'object') return {};\n const id = entry[ENTRY_ID_KEY];\n const name = entry[ENTRY_NAME_KEY];\n return {\n id: typeof id === 'string' && id.trim() ? id.trim() : undefined,\n name: typeof name === 'string' && name.trim() ? name.trim() : undefined,\n };\n}\n\n/** Assign a stable `__entryId` to an entry if missing. Returns the (possibly mutated) entry. */\nexport function ensureEntryId<T extends Record<string, any>>(entry: T): T {\n if (!entry || typeof entry !== 'object') return entry;\n if (typeof entry[ENTRY_ID_KEY] !== 'string' || !entry[ENTRY_ID_KEY].trim()) {\n (entry as any)[ENTRY_ID_KEY] = generateEntryId();\n }\n return entry;\n}\n\n/**\n * Walk every repeatable entry in the section state and ensure each entry has a `__entryId`.\n * Returns a NEW state object only when at least one id was added, otherwise the original\n * reference is returned (so React effects can short-circuit).\n */\nexport function ensureEntryIdsInSectionState(\n state: SectionFormState,\n sections: InferredSection[]\n): SectionFormState {\n if (!state || typeof state !== 'object') return state;\n const repeatables = sections.filter((s): s is InferredSectionRepeatable => s.type === 'repeatable');\n if (repeatables.length === 0) return state;\n\n let changed = false;\n const next: SectionFormState = { ...state };\n\n const childrenByParent = new Map<string, InferredSectionRepeatable[]>();\n for (const r of repeatables) {\n if (!r.parentId) continue;\n if (!childrenByParent.has(r.parentId)) childrenByParent.set(r.parentId, []);\n childrenByParent.get(r.parentId)!.push(r);\n }\n\n const visit = (section: InferredSectionRepeatable, stateKey: string): void => {\n const entries = next[stateKey];\n if (!Array.isArray(entries)) return;\n let cloned: Array<Record<string, string | string[]>> | null = null;\n for (let i = 0; i < entries.length; i++) {\n const entry = entries[i] ?? {};\n const hasId = typeof (entry as any)[ENTRY_ID_KEY] === 'string' && (entry as any)[ENTRY_ID_KEY].trim();\n if (!hasId) {\n if (!cloned) cloned = [...entries];\n cloned[i] = { ...entry, [ENTRY_ID_KEY]: generateEntryId() };\n changed = true;\n }\n }\n if (cloned) next[stateKey] = cloned;\n // Recurse into nested children using composite key.\n const children = childrenByParent.get(section.id) ?? [];\n if (!children.length) return;\n const visited = (next[stateKey] as Array<Record<string, string | string[]>>) ?? [];\n for (let pi = 0; pi < visited.length; pi++) {\n for (const child of children) {\n visit(child, `${stateKey}_${pi}_${child.id}`);\n }\n }\n };\n\n // Top-level repeatables (no parent OR parent is a single section) are keyed directly by section.id.\n const singleSectionIds = new Set(sections.filter((s) => s.type === 'single').map((s) => s.id));\n const topLevel = repeatables.filter((s) => !s.parentId || singleSectionIds.has(s.parentId));\n for (const section of topLevel) visit(section, section.id);\n\n return changed ? next : state;\n}\n\n/**\n * Build entry-meta lookup maps for every repeatable in the inferred sections,\n * keyed by `section.id`. Used by `applyFormDataToConfig` to resolve `#token`\n * references inside `entryFilter.range`.\n */\nexport interface RepeatableEntryMetaMaps {\n /** Top-level (or single-parent) repeatable: section.id → 1-based EntryMeta[] */\n topLevel: Map<string, EntryMeta[]>;\n /** Nested repeatable: section.id (child) → parentIndex(1-based) → EntryMeta[] */\n nested: Map<string, Map<number, EntryMeta[]>>;\n}\n\nexport function buildRepeatableEntryMetaMaps(\n state: SectionFormState | undefined,\n sections: InferredSection[]\n): RepeatableEntryMetaMaps {\n const topLevel = new Map<string, EntryMeta[]>();\n const nested = new Map<string, Map<number, EntryMeta[]>>();\n if (!state) return { topLevel, nested };\n\n const repeatables = sections.filter((s): s is InferredSectionRepeatable => s.type === 'repeatable');\n const singleSectionIds = new Set(sections.filter((s) => s.type === 'single').map((s) => s.id));\n\n const metaFromEntries = (entries: Array<Record<string, unknown>>): EntryMeta[] =>\n entries.map((e) => readEntryMeta(e));\n\n for (const section of repeatables) {\n const isTopLevel = !section.parentId || singleSectionIds.has(section.parentId);\n if (isTopLevel) {\n const entries = state[section.id];\n if (Array.isArray(entries)) topLevel.set(section.id, metaFromEntries(entries));\n continue;\n }\n // Nested: iterate parent entries and collect meta per parent index.\n const parentId = section.parentId!;\n const parentEntries = state[parentId];\n if (!Array.isArray(parentEntries)) continue;\n const byParent = new Map<number, EntryMeta[]>();\n for (let pi = 0; pi < parentEntries.length; pi++) {\n const compositeKey = `${parentId}_${pi}_${section.id}`;\n const childEntries = state[compositeKey];\n if (Array.isArray(childEntries)) byParent.set(pi + 1, metaFromEntries(childEntries));\n }\n if (byParent.size) nested.set(section.id, byParent);\n }\n\n return { topLevel, nested };\n}\n\n/**\n * Resolve EntryMeta[] for a given section. For nested sections, returns the\n * meta of the first parent entry (1-based) — sufficient because clones across\n * parent entries share the same meta source. Returns undefined when not found.\n */\nexport function resolveEntryMetaForSection(\n maps: RepeatableEntryMetaMaps,\n sectionId: string\n): EntryMeta[] | undefined {\n const top = maps.topLevel.get(sectionId);\n if (top) return top;\n const byParent = maps.nested.get(sectionId);\n if (byParent && byParent.size) {\n // Merge across parents into one ordered list (used only for #token matching, indices irrelevant here).\n const merged: EntryMeta[] = [];\n for (const arr of byParent.values()) merged.push(...arr);\n return merged;\n }\n return undefined;\n}\n","/**\n * Content-bounds pagination: when the first page has contentTop/contentBottom and a\n * single root-level repeatable stack (vertical stack with __baseNodeId children),\n * split overflow to continuation pages (with static elements copied) and remove\n * empty last pages (underflow). Used on the Use page for auto-paginate.\n * Supports nested repeatable sections: if an overflowing entry contains a nested\n * vertical stack with __baseNodeId children, we split at that level so part stays\n * and part overflows to the next page.\n */\n\nimport type { TemplateConfig, TemplateConfigPage, CanvasNode, GroupNode, CanvasElement } from '@/types/editor';\nimport { isGroup, isVerticalStackLayoutMode, generateId } from '@/types/editor';\nimport {\n getAbsoluteBounds,\n getNodeBounds,\n applyStackReflowToPageTree,\n} from '@/lib/layoutEngine';\n\nfunction hasBaseNodeId(node: CanvasNode): boolean {\n return (node as CanvasNode & { __baseNodeId?: string }).__baseNodeId != null;\n}\n\nfunction isStaticOnNewPage(node: CanvasNode): boolean {\n return !!(node as CanvasNode & { staticOnNewPage?: boolean }).staticOnNewPage;\n}\n\nfunction nodeLeft(node: CanvasNode): number {\n return typeof node.left === 'number' ? node.left : 0;\n}\n\nfunction nodeTop(node: CanvasNode): number {\n return typeof node.top === 'number' ? node.top : 0;\n}\n\nfunction cloneNodeWithNewIds(node: CanvasNode): CanvasNode {\n const base = (node as CanvasNode & { __baseNodeId?: string }).__baseNodeId;\n const source = (node as CanvasNode & { __sourceId?: string }).__sourceId;\n if (isGroup(node)) {\n const g = node as GroupNode;\n const cloned: GroupNode & { __baseNodeId?: string; __sourceId?: string } = {\n ...g,\n id: generateId('group'),\n children: (g.children ?? []).map(cloneNodeWithNewIds),\n } as GroupNode;\n if (base != null) cloned.__baseNodeId = base;\n if (source != null) cloned.__sourceId = source;\n return cloned as GroupNode;\n }\n const el = node as CanvasElement;\n const prefix = el.type === 'text' ? 'text' : el.type === 'image' ? 'img' : el.type === 'shape' ? 'shape' : 'line';\n const cloned = { ...el, id: generateId(prefix) } as CanvasElement & { __baseNodeId?: string; __sourceId?: string };\n if (base != null) cloned.__baseNodeId = base;\n if (source != null) cloned.__sourceId = source;\n return cloned as CanvasElement;\n}\n\n/** Clone node tree with deterministic ids so continuation page doesn't remount on form change. */\nfunction cloneNodeWithStableIds(node: CanvasNode, baseId: string, path: string): CanvasNode {\n const base = (node as CanvasNode & { __baseNodeId?: string }).__baseNodeId;\n const source = (node as CanvasNode & { __sourceId?: string }).__sourceId;\n const stableId = `${baseId}-${path}`;\n // Preserve link to original element for theme matching: if no __sourceId exists,\n // use the original node's ID so applyThemeToConfig can find these clones.\n const effectiveSource = source ?? node.id;\n if (isGroup(node)) {\n const g = node as GroupNode;\n const cloned: GroupNode & { __baseNodeId?: string; __sourceId?: string } = {\n ...g,\n id: stableId,\n children: (g.children ?? []).map((child, i) => cloneNodeWithStableIds(child, baseId, `${path}-${i}`)),\n } as GroupNode;\n if (base != null) cloned.__baseNodeId = base;\n cloned.__sourceId = effectiveSource;\n return cloned as GroupNode;\n }\n const el = node as CanvasElement;\n const cloned = { ...el, id: stableId } as CanvasElement & { __baseNodeId?: string; __sourceId?: string };\n if (base != null) cloned.__baseNodeId = base;\n cloned.__sourceId = effectiveSource;\n return cloned as CanvasElement;\n}\n\nfunction findFlowStack(pageChildren: CanvasNode[]): GroupNode | null {\n const all = findAllFlowStacks(pageChildren);\n return all.length > 0 ? all[0] : null;\n}\n\nfunction findAllFlowStacks(pageChildren: CanvasNode[]): GroupNode[] {\n const result: GroupNode[] = [];\n for (const node of pageChildren) {\n if (!isGroup(node)) continue;\n const g = node as GroupNode;\n if (!isVerticalStackLayoutMode(g.layoutMode) || !g.children?.length) continue;\n if (g.children.some(hasBaseNodeId)) result.push(g);\n }\n return result;\n}\n\n/** Find a nested vertical stack with repeatable-style children (__baseNodeId or group children) inside an entry. */\nfunction findNestedFlowStack(entry: GroupNode): GroupNode | null {\n const queue: CanvasNode[] = [...(entry.children ?? [])];\n while (queue.length > 0) {\n const node = queue.shift()!;\n if (!isGroup(node)) continue;\n const g = node as GroupNode;\n const hasRepeatableChildren =\n g.children?.length &&\n (g.children.some(hasBaseNodeId) || g.children.some((c) => isGroup(c)));\n if (isVerticalStackLayoutMode(g.layoutMode) && hasRepeatableChildren) return g;\n if (g.children?.length) queue.push(...g.children);\n }\n return null;\n}\n\n/** Replace a nested flow stack's children inside an entry (by id); optionally set all child tops to 0 for continuation layout. */\nfunction replaceNestedFlowStackChildren(\n entry: GroupNode,\n nestedStackId: string,\n newChildren: CanvasNode[],\n setTopsToZero: boolean\n): GroupNode {\n function walk(node: CanvasNode): CanvasNode {\n if (isGroup(node)) {\n const g = node as GroupNode;\n if (g.id === nestedStackId) {\n const children = setTopsToZero\n ? newChildren.map((c) => ({ ...c, top: 0 } as CanvasNode))\n : newChildren;\n return { ...g, children } as GroupNode;\n }\n return { ...g, children: (g.children ?? []).map(walk) } as GroupNode;\n }\n return node;\n }\n return walk(entry) as GroupNode;\n}\n\n/**\n * If entry contains a nested repeatable stack and it can be split by contentBottom,\n * return { stayVersion, overflowVersion }. Otherwise return { stayVersion: null, overflowVersion: entry } (whole entry overflows).\n * The \"entry\" from the root flow stack may itself BE the nested stack (e.g. \"Family Details\" section is a vertical stack\n * whose children are the family members). In that case we split the entry's own children.\n */\nfunction splitEntryAtNested(\n entry: GroupNode,\n pageChildren: CanvasNode[],\n contentBottom: number\n): { stayVersion: GroupNode | null; overflowVersion: GroupNode | null } {\n // Case 1: Entry itself is the nested flow stack (section = vertical stack, children = nested items).\n const entryIsNestedStack =\n isVerticalStackLayoutMode(entry.layoutMode) &&\n entry.children?.length &&\n (entry.children.some(hasBaseNodeId) || entry.children.some((c) => isGroup(c)));\n const nested = entryIsNestedStack ? entry : findNestedFlowStack(entry);\n if (!nested) return { stayVersion: null, overflowVersion: entry };\n\n const nestedKids = nested.children ?? [];\n const { stayIndices: nestedStay, overflowIndices: nestedOverflow } = splitFlowStackByBounds(\n nested,\n pageChildren,\n contentBottom\n );\n if (nestedOverflow.length === 0) return { stayVersion: entry, overflowVersion: null };\n if (nestedStay.length === 0) return { stayVersion: null, overflowVersion: entry };\n\n const nestedStayChildren = nestedStay.map((i) => nestedKids[i]);\n const nestedOverflowChildren = nestedOverflow.map((i) => nestedKids[i]).map((c) => cloneNodeWithNewIds(c));\n // Keep each child's own left position — don't force firstLeft from nestedKids[0]\n // which could be a section title at a different x than the data rows.\n const overflowWithZeroTop = nestedOverflowChildren.map((c) => ({\n ...c,\n top: 0,\n })) as CanvasNode[];\n\n if (entryIsNestedStack) {\n // Entry is the stack: stay = entry with stay children only, overflow = clone of entry with overflow children only.\n const nestedStayCloned = nestedStayChildren.map((c) => cloneNodeWithNewIds(c));\n const stayVersion = { ...entry, children: nestedStayCloned } as GroupNode;\n const overflowEntryClone = cloneNodeWithNewIds(entry) as GroupNode;\n const overflowVersion = { ...overflowEntryClone, children: overflowWithZeroTop } as GroupNode;\n return { stayVersion, overflowVersion };\n }\n\n // Case 2: Nested stack is inside entry — copy whole parent for both stay and overflow.\n const stayEntryClone = cloneNodeWithNewIds(entry) as GroupNode;\n const nestedInStayClone = findNestedFlowStack(stayEntryClone);\n if (!nestedInStayClone) return { stayVersion: null, overflowVersion: entry };\n const nestedStayCloned = nestedStayChildren.map((c) => cloneNodeWithNewIds(c));\n const stayVersion = replaceNestedFlowStackChildren(stayEntryClone, nestedInStayClone.id, nestedStayCloned, false);\n\n const overflowEntryClone = cloneNodeWithNewIds(entry) as GroupNode;\n const nestedInClone = findNestedFlowStack(overflowEntryClone);\n if (!nestedInClone) return { stayVersion, overflowVersion: entry };\n const overflowVersion = replaceNestedFlowStackChildren(overflowEntryClone, nestedInClone.id, overflowWithZeroTop, false);\n\n return { stayVersion, overflowVersion };\n}\n\nfunction splitFlowStackByBounds(\n flowStack: GroupNode,\n pageChildren: CanvasNode[],\n contentBottom: number\n): { stayIndices: number[]; overflowIndices: number[] } {\n const kids = flowStack.children ?? [];\n const stayIndices: number[] = [];\n const overflowIndices: number[] = [];\n for (let i = 0; i < kids.length; i++) {\n const abs = getAbsoluteBounds(kids[i], pageChildren);\n if (abs.bottom <= contentBottom) stayIndices.push(i);\n else overflowIndices.push(i);\n }\n return { stayIndices, overflowIndices };\n}\n\nfunction applyStackPositionsToGroup(group: GroupNode, pageChildren: CanvasNode[]): GroupNode {\n const kids = group.children ?? [];\n if (kids.length === 0) return group;\n const gap = group.stackSpacing ?? 8;\n const firstLeft = nodeLeft(kids[0]);\n let prevBottom = 0;\n const newKids = kids.map((child, i) => {\n const b = getNodeBounds(child, pageChildren);\n const top = i === 0 ? nodeTop(child) : prevBottom + gap;\n prevBottom = top + b.height + ((child as any).marginBottom ?? 0);\n return { ...child, top, left: i === 0 ? nodeLeft(child) : firstLeft } as CanvasNode;\n });\n return { ...group, children: newKids } as GroupNode;\n}\n\nfunction buildContinuationPage(\n sourcePage: TemplateConfigPage,\n overflowStacks: Array<{ flowStack: GroupNode; overflowChildren: CanvasNode[] }>,\n contentTop: number,\n pageIndex: number\n): TemplateConfigPage {\n const newPageId = `page-continuation-${pageIndex}`;\n const stableBaseId = `cont-${pageIndex}`;\n const rootChildren: CanvasNode[] = [];\n let staticIndex = 0;\n for (const node of sourcePage.children ?? []) {\n if (isStaticOnNewPage(node)) {\n rootChildren.push(cloneNodeWithStableIds(node, stableBaseId, `static-${staticIndex++}`));\n }\n }\n\n const overflowStackTop = contentTop;\n\n for (let si = 0; si < overflowStacks.length; si++) {\n const { flowStack: flowStackOriginal, overflowChildren } = overflowStacks[si];\n const stackLeft = (flowStackOriginal.left ?? 0) as number;\n const clonedOverflow = overflowChildren.map((child, i) => {\n const cloned = cloneNodeWithStableIds(child, stableBaseId, `entry-${si}-${i}`);\n return { ...cloned, top: 0 } as CanvasNode;\n });\n const overflowStack: GroupNode = {\n ...flowStackOriginal,\n id: `${stableBaseId}-stack-${si}`,\n left: stackLeft,\n top: overflowStackTop,\n children: clonedOverflow,\n layoutMode: flowStackOriginal.layoutMode ?? 'vertical-stack',\n } as GroupNode;\n rootChildren.push(overflowStack);\n }\n\n const withHeights = applyStackReflowToPageTree(rootChildren);\n const finalChildren = withHeights;\n return {\n id: newPageId,\n name: `Page ${pageIndex + 2}`,\n children: finalChildren,\n settings: { ...sourcePage.settings },\n };\n}\n\ninterface FlowStackOverflow {\n flowStack: GroupNode;\n flowStackIndex: number;\n stayChildren: CanvasNode[];\n overflowChildren: CanvasNode[];\n}\n\n/** Try to split nested entries for a single flow stack's overflow, returns updated stay/overflow. */\nfunction splitNestedForOverflow(\n flowStack: GroupNode,\n stayChildren: CanvasNode[],\n overflowChildren: CanvasNode[],\n overflowIndices: number[],\n pageChildren: CanvasNode[],\n contentBottom: number\n): { stayChildren: CanvasNode[]; overflowChildren: CanvasNode[] } {\n const kids = flowStack.children ?? [];\n let newStay = [...stayChildren];\n let newOverflow = [...overflowChildren];\n\n for (let j = 0; j < overflowIndices.length; j++) {\n const entry = kids[overflowIndices[j]] as GroupNode;\n const { stayVersion, overflowVersion } = splitEntryAtNested(entry, pageChildren, contentBottom);\n if (stayVersion != null && overflowVersion != null) {\n newStay = newStay.concat(stayVersion);\n newOverflow = [\n ...overflowIndices.slice(0, j).map((i) => kids[i]),\n overflowVersion as CanvasNode,\n ...overflowIndices.slice(j + 1).map((i) => kids[i]),\n ];\n break;\n }\n if (stayVersion != null && overflowVersion == null) {\n newStay = newStay.concat(stayVersion);\n newOverflow = [\n ...overflowIndices.slice(0, j).map((i) => kids[i]),\n ...overflowIndices.slice(j + 1).map((i) => kids[i]),\n ];\n break;\n }\n }\n return { stayChildren: newStay, overflowChildren: newOverflow };\n}\n\n/**\n * Paginate a single source page using its own contentTop/contentBottom.\n * Returns the (trimmed) source page plus any continuation pages it produced.\n * If the page has no contentBottom or no overflow, returns [page] unchanged.\n */\nfunction paginateSinglePage(\n sourcePage: TemplateConfigPage,\n pageOffsetIndex: number\n): TemplateConfigPage[] {\n const contentTop = sourcePage.settings?.contentTop;\n const contentBottom = sourcePage.settings?.contentBottom;\n if (contentTop == null || contentBottom == null || contentBottom <= contentTop) {\n return [sourcePage];\n }\n\n const pageChildren = sourcePage.children ?? [];\n const allFlowStacks = findAllFlowStacks(pageChildren);\n if (allFlowStacks.length === 0) return [sourcePage];\n\n // Process each flow stack independently\n const stackResults: FlowStackOverflow[] = [];\n let anyOverflow = false;\n\n for (const flowStack of allFlowStacks) {\n const flowStackIndex = pageChildren.findIndex((n) => n.id === flowStack.id);\n const kids = flowStack.children ?? [];\n const { stayIndices, overflowIndices } = splitFlowStackByBounds(flowStack, pageChildren, contentBottom);\n\n let stayChildren: CanvasNode[] = stayIndices.map((i) => kids[i]);\n let overflowChildren: CanvasNode[] = overflowIndices.map((i) => kids[i]);\n\n if (overflowIndices.length > 0) {\n anyOverflow = true;\n const result = splitNestedForOverflow(flowStack, stayChildren, overflowChildren, overflowIndices, pageChildren, contentBottom);\n stayChildren = result.stayChildren;\n overflowChildren = result.overflowChildren;\n }\n\n stackResults.push({ flowStack, flowStackIndex, stayChildren, overflowChildren });\n }\n\n if (!anyOverflow) return [sourcePage];\n\n // Build trimmed source page with all flow stacks limited to stay children\n const flowStackIds = new Set(allFlowStacks.map((s) => s.id));\n let newSourceRoot = pageChildren.map((node) => {\n if (!flowStackIds.has(node.id)) return node;\n const result = stackResults.find((r) => r.flowStack.id === node.id)!;\n const newStack: GroupNode = { ...result.flowStack, children: result.stayChildren };\n return applyStackReflowToPageTree([newStack])[0] as GroupNode;\n });\n newSourceRoot = applyStackReflowToPageTree(newSourceRoot);\n\n const newSourcePage: TemplateConfigPage = {\n ...sourcePage,\n children: newSourceRoot,\n };\n\n const resultPages: TemplateConfigPage[] = [newSourcePage];\n\n // Collect overflow from all stacks\n let currentOverflows = stackResults\n .filter((r) => r.overflowChildren.length > 0)\n .map((r) => ({ flowStack: r.flowStack, overflowChildren: r.overflowChildren }));\n\n let currentPageIndex = 1;\n const MAX_CONTINUATION_PAGES = 50;\n\n while (currentOverflows.length > 0 && currentPageIndex < MAX_CONTINUATION_PAGES) {\n // Use a unique continuation index that includes the source page offset so ids stay stable across multi-page docs\n const continuationGlobalIndex = pageOffsetIndex * 1000 + currentPageIndex;\n const contPage = buildContinuationPage(sourcePage, currentOverflows, contentTop, continuationGlobalIndex);\n resultPages.push(contPage);\n\n const contChildren = contPage.children ?? [];\n const contFlowStacks = findAllFlowStacks(contChildren);\n if (contFlowStacks.length === 0) break;\n\n const nextOverflows: Array<{ flowStack: GroupNode; overflowChildren: CanvasNode[] }> = [];\n let anyStay = false;\n\n for (let si = 0; si < contFlowStacks.length; si++) {\n const contFlowStack = contFlowStacks[si];\n const contKids = contFlowStack.children ?? [];\n const { stayIndices: contStay, overflowIndices: contOverflow } = splitFlowStackByBounds(\n contFlowStack, contChildren, contentBottom\n );\n\n if (contStay.length > 0) anyStay = true;\n\n if (contOverflow.length === 0) continue;\n\n let contStayChildren: CanvasNode[] = contStay.map((i) => contKids[i]);\n let nextOverflowChildren: CanvasNode[] = contOverflow.map((i) => contKids[i]);\n\n if (contOverflow.length > 0) {\n const result = splitNestedForOverflow(contFlowStack, contStayChildren, nextOverflowChildren, contOverflow, contChildren, contentBottom);\n contStayChildren = result.stayChildren;\n nextOverflowChildren = result.overflowChildren;\n }\n\n const updatedContChildren = contChildren.map((node) => {\n if (node.id !== contFlowStack.id) return node;\n return applyStackReflowToPageTree([{ ...contFlowStack, children: contStayChildren }])[0] as GroupNode;\n });\n resultPages[resultPages.length - 1] = {\n ...contPage,\n children: applyStackReflowToPageTree(updatedContChildren),\n };\n\n if (nextOverflowChildren.length > 0) {\n const originalFlowStack = currentOverflows[si]?.flowStack ?? contFlowStack;\n nextOverflows.push({ flowStack: originalFlowStack, overflowChildren: nextOverflowChildren });\n }\n }\n\n if (!anyStay) break;\n currentOverflows = nextOverflows;\n currentPageIndex++;\n }\n\n // Remove trailing empty continuation pages produced by THIS source page only.\n // We never pop the source page itself (index 0 of resultPages).\n while (resultPages.length > 1) {\n const last = resultPages[resultPages.length - 1];\n const lastChildren = last.children ?? [];\n if (lastChildren.length === 0) {\n resultPages.pop();\n continue;\n }\n let hasContent = false;\n for (const node of lastChildren) {\n if (!isGroup(node)) continue;\n const g = node as GroupNode;\n if (isVerticalStackLayoutMode(g.layoutMode) && (g.children?.length ?? 0) > 0) {\n hasContent = true;\n break;\n }\n }\n let lastFlow = findFlowStack(lastChildren);\n if (!lastFlow && lastChildren.length > 0) {\n const lastRoot = lastChildren[lastChildren.length - 1];\n if (isGroup(lastRoot) && isVerticalStackLayoutMode((lastRoot as GroupNode).layoutMode) && (lastRoot as GroupNode).children?.length) {\n lastFlow = lastRoot as GroupNode;\n }\n }\n const flowChildCount = lastFlow ? (lastFlow.children?.length ?? 0) : -1;\n if (flowChildCount === 0 && !hasContent) resultPages.pop();\n else break;\n }\n\n return resultPages;\n}\n\n/**\n * Apply content-bounds pagination to every page in the config.\n * Each source page is paginated independently using its OWN contentTop/contentBottom,\n * and any continuation pages it produces are inserted right after it (preserving\n * the original page order). This means overflow on page 2, 3, etc. is now handled\n * the same way as overflow on page 1.\n */\nexport function applyContentBoundsPagination(config: TemplateConfig): TemplateConfig {\n const pages = config.pages ?? [];\n if (pages.length === 0) return config;\n\n const resultPages: TemplateConfigPage[] = [];\n let mutated = false;\n\n for (let i = 0; i < pages.length; i++) {\n const sourcePage = pages[i];\n const paginated = paginateSinglePage(sourcePage, i);\n if (paginated.length !== 1 || paginated[0] !== sourcePage) mutated = true;\n resultPages.push(...paginated);\n }\n\n if (!mutated) return config;\n return { ...config, pages: resultPages };\n}\n","/**\n * PDF Font Embedding for @pixldocs/canvas-renderer\n *\n * Ported 1:1 from the working client-side flow (src/lib/pdfFonts.ts).\n * Each font weight is registered as a separate jsPDF font name\n * (e.g. \"JosefinSans-SemiBold\") with style \"normal\", and the SVG\n * text elements are rewritten to use these names with font-weight: normal\n * so that svg2pdf can find them.\n */\n\nimport { jsPDF } from 'jspdf';\nimport { parseTextMarkdown } from '@/lib/textMarkdown';\n\n// ─── Font weight labels (matches pdfFonts.ts in main app) ───\n\nexport const FONT_WEIGHT_LABELS: Record<number, string> = {\n 300: 'Light',\n 400: 'Regular',\n 500: 'Medium',\n 600: 'SemiBold',\n 700: 'Bold',\n};\n\nexport function resolveFontWeight(weight: number): number {\n if (weight <= 350) return 300;\n if (weight <= 450) return 400;\n if (weight <= 550) return 500;\n if (weight <= 650) return 600;\n return 700;\n}\n\n// ─── Font file mapping ───\n\nexport type FontWeightFiles = {\n regular: string;\n bold?: string;\n light?: string;\n medium?: string;\n semibold?: string;\n italic?: string;\n boldItalic?: string;\n lightItalic?: string;\n mediumItalic?: string;\n semiboldItalic?: string;\n};\n\n/** Font used for symbols (● ◆ ★ etc.) */\nexport const FONT_FALLBACK_SYMBOLS = 'Noto Sans';\n/** Font used for Devanagari / Hindi script */\nexport const FONT_FALLBACK_DEVANAGARI = 'Hind';\n/** Font used only when the active font lacks math/operator glyphs. */\nexport const FONT_FALLBACK_MATH = 'Noto Sans Math';\n\n/**\n * Maps font family names to their TTF file names (relative to fontBaseUrl).\n */\nexport const FONT_FILES: Record<string, FontWeightFiles> = {\n 'Playfair Display': {\n regular: 'PlayfairDisplay-Regular.ttf',\n bold: 'PlayfairDisplay-Bold.ttf',\n italic: 'PlayfairDisplay-Italic.ttf',\n boldItalic: 'PlayfairDisplay-BoldItalic.ttf',\n },\n 'Merriweather': {\n regular: 'Merriweather-Regular.ttf',\n bold: 'Merriweather-Bold.ttf',\n light: 'Merriweather-Light.ttf',\n italic: 'Merriweather-Italic.ttf',\n boldItalic: 'Merriweather-BoldItalic.ttf',\n lightItalic: 'Merriweather-LightItalic.ttf',\n },\n 'Lora': {\n regular: 'Lora-Regular.ttf',\n bold: 'Lora-Bold.ttf',\n italic: 'Lora-Italic.ttf',\n boldItalic: 'Lora-BoldItalic.ttf',\n },\n 'Montserrat': {\n regular: 'Montserrat-Regular.ttf',\n bold: 'Montserrat-Bold.ttf',\n light: 'Montserrat-Light.ttf',\n medium: 'Montserrat-Medium.ttf',\n semibold: 'Montserrat-SemiBold.ttf',\n italic: 'Montserrat-Italic.ttf',\n boldItalic: 'Montserrat-BoldItalic.ttf',\n lightItalic: 'Montserrat-LightItalic.ttf',\n mediumItalic: 'Montserrat-MediumItalic.ttf',\n semiboldItalic: 'Montserrat-SemiBoldItalic.ttf',\n },\n 'Open Sans': {\n regular: 'OpenSans-Regular.ttf',\n bold: 'OpenSans-Bold.ttf',\n light: 'OpenSans-Light.ttf',\n semibold: 'OpenSans-SemiBold.ttf',\n italic: 'OpenSans-Italic.ttf',\n boldItalic: 'OpenSans-BoldItalic.ttf',\n lightItalic: 'OpenSans-LightItalic.ttf',\n semiboldItalic: 'OpenSans-SemiBoldItalic.ttf',\n },\n 'Roboto': {\n regular: 'Roboto-Regular.ttf',\n bold: 'Roboto-Bold.ttf',\n light: 'Roboto-Light.ttf',\n medium: 'Roboto-Medium.ttf',\n italic: 'Roboto-Italic.ttf',\n boldItalic: 'Roboto-BoldItalic.ttf',\n lightItalic: 'Roboto-LightItalic.ttf',\n mediumItalic: 'Roboto-MediumItalic.ttf',\n },\n 'Lato': {\n regular: 'Lato-Regular.ttf',\n bold: 'Lato-Bold.ttf',\n light: 'Lato-Light.ttf',\n italic: 'Lato-Italic.ttf',\n boldItalic: 'Lato-BoldItalic.ttf',\n lightItalic: 'Lato-LightItalic.ttf',\n },\n 'Raleway': {\n regular: 'Raleway-Regular.ttf',\n bold: 'Raleway-Bold.ttf',\n light: 'Raleway-Light.ttf',\n medium: 'Raleway-Medium.ttf',\n semibold: 'Raleway-SemiBold.ttf',\n italic: 'Raleway-Italic.ttf',\n boldItalic: 'Raleway-BoldItalic.ttf',\n lightItalic: 'Raleway-LightItalic.ttf',\n },\n 'Poppins': {\n regular: 'Poppins-Regular.ttf',\n bold: 'Poppins-Bold.ttf',\n light: 'Poppins-Light.ttf',\n medium: 'Poppins-Medium.ttf',\n semibold: 'Poppins-SemiBold.ttf',\n italic: 'Poppins-Italic.ttf',\n boldItalic: 'Poppins-BoldItalic.ttf',\n lightItalic: 'Poppins-LightItalic.ttf',\n mediumItalic: 'Poppins-MediumItalic.ttf',\n semiboldItalic: 'Poppins-SemiBoldItalic.ttf',\n },\n 'Inter': {\n regular: 'Inter-Regular.ttf',\n bold: 'Inter-Bold.ttf',\n italic: 'Inter-Italic.ttf',\n boldItalic: 'Inter-BoldItalic.ttf',\n },\n 'Nunito': {\n regular: 'Nunito-Regular.ttf',\n bold: 'Nunito-Bold.ttf',\n light: 'Nunito-Light.ttf',\n medium: 'Nunito-Medium.ttf',\n semibold: 'Nunito-SemiBold.ttf',\n italic: 'Nunito-Italic.ttf',\n boldItalic: 'Nunito-BoldItalic.ttf',\n },\n 'Source Sans Pro': {\n regular: 'SourceSansPro-Regular.ttf',\n bold: 'SourceSansPro-Bold.ttf',\n light: 'SourceSansPro-Light.ttf',\n italic: 'SourceSansPro-Italic.ttf',\n boldItalic: 'SourceSansPro-BoldItalic.ttf',\n },\n 'Work Sans': {\n regular: 'WorkSans-Regular.ttf',\n bold: 'WorkSans-Bold.ttf',\n italic: 'WorkSans-Italic.ttf',\n boldItalic: 'WorkSans-BoldItalic.ttf',\n },\n 'Oswald': { regular: 'Oswald-Regular.ttf', bold: 'Oswald-Bold.ttf' },\n 'Bebas Neue': { regular: 'BebasNeue-Regular.ttf' },\n 'Abril Fatface': { regular: 'AbrilFatface-Regular.ttf' },\n 'Dancing Script': { regular: 'DancingScript-Regular.ttf', bold: 'DancingScript-Bold.ttf' },\n 'Pacifico': { regular: 'Pacifico-Regular.ttf' },\n 'Great Vibes': { regular: 'GreatVibes-Regular.ttf' },\n 'DM Sans': {\n regular: 'DMSans-Regular.ttf',\n bold: 'DMSans-Bold.ttf',\n light: 'DMSans-Light.ttf',\n medium: 'DMSans-Medium.ttf',\n semibold: 'DMSans-SemiBold.ttf',\n italic: 'DMSans-RegularItalic.ttf',\n boldItalic: 'DMSans-BoldItalic.ttf',\n lightItalic: 'DMSans-LightItalic.ttf',\n mediumItalic: 'DMSans-MediumItalic.ttf',\n semiboldItalic: 'DMSans-SemiBoldItalic.ttf',\n },\n 'Outfit': {\n regular: 'Outfit-Regular.ttf',\n bold: 'Outfit-Bold.ttf',\n light: 'Outfit-Light.ttf',\n medium: 'Outfit-Medium.ttf',\n semibold: 'Outfit-SemiBold.ttf',\n },\n 'Figtree': {\n regular: 'Figtree-Regular.ttf',\n bold: 'Figtree-Bold.ttf',\n light: 'Figtree-Light.ttf',\n medium: 'Figtree-Medium.ttf',\n semibold: 'Figtree-SemiBold.ttf',\n italic: 'Figtree-RegularItalic.ttf',\n boldItalic: 'Figtree-BoldItalic.ttf',\n lightItalic: 'Figtree-LightItalic.ttf',\n mediumItalic: 'Figtree-MediumItalic.ttf',\n semiboldItalic: 'Figtree-SemiBoldItalic.ttf',\n },\n 'Manrope': {\n regular: 'Manrope-Regular.ttf',\n bold: 'Manrope-Bold.ttf',\n light: 'Manrope-Light.ttf',\n medium: 'Manrope-Medium.ttf',\n semibold: 'Manrope-SemiBold.ttf',\n },\n 'Space Grotesk': {\n regular: 'SpaceGrotesk-Regular.ttf',\n bold: 'SpaceGrotesk-Bold.ttf',\n light: 'SpaceGrotesk-Light.ttf',\n medium: 'SpaceGrotesk-Medium.ttf',\n semibold: 'SpaceGrotesk-SemiBold.ttf',\n },\n 'League Spartan': {\n regular: 'LeagueSpartan-Regular.ttf',\n bold: 'LeagueSpartan-Bold.ttf',\n light: 'LeagueSpartan-Light.ttf',\n medium: 'LeagueSpartan-Medium.ttf',\n semibold: 'LeagueSpartan-SemiBold.ttf',\n },\n 'EB Garamond': {\n regular: 'EBGaramond-Regular.ttf',\n bold: 'EBGaramond-Bold.ttf',\n medium: 'EBGaramond-Medium.ttf',\n semibold: 'EBGaramond-SemiBold.ttf',\n italic: 'EBGaramond-RegularItalic.ttf',\n boldItalic: 'EBGaramond-BoldItalic.ttf',\n mediumItalic: 'EBGaramond-MediumItalic.ttf',\n semiboldItalic: 'EBGaramond-SemiBoldItalic.ttf',\n },\n 'Libre Baskerville': {\n regular: 'LibreBaskerville-Regular.ttf',\n bold: 'LibreBaskerville-Bold.ttf',\n italic: 'LibreBaskerville-RegularItalic.ttf',\n boldItalic: 'LibreBaskerville-BoldItalic.ttf',\n },\n 'Crimson Text': {\n regular: 'CrimsonText-Regular.ttf',\n bold: 'CrimsonText-Bold.ttf',\n italic: 'CrimsonText-Italic.ttf',\n boldItalic: 'CrimsonText-BoldItalic.ttf',\n },\n 'DM Serif Display': {\n regular: 'DMSerifDisplay-Regular.ttf',\n italic: 'DMSerifDisplay-Italic.ttf',\n },\n 'Libre Franklin': {\n regular: 'LibreFranklin-Regular.ttf',\n bold: 'LibreFranklin-Bold.ttf',\n light: 'LibreFranklin-Light.ttf',\n medium: 'LibreFranklin-Medium.ttf',\n semibold: 'LibreFranklin-SemiBold.ttf',\n italic: 'LibreFranklin-RegularItalic.ttf',\n boldItalic: 'LibreFranklin-BoldItalic.ttf',\n lightItalic: 'LibreFranklin-LightItalic.ttf',\n mediumItalic: 'LibreFranklin-MediumItalic.ttf',\n semiboldItalic: 'LibreFranklin-SemiBoldItalic.ttf',\n },\n 'Mulish': {\n regular: 'Mulish-Regular.ttf',\n bold: 'Mulish-Bold.ttf',\n light: 'Mulish-Light.ttf',\n medium: 'Mulish-Medium.ttf',\n semibold: 'Mulish-SemiBold.ttf',\n italic: 'Mulish-RegularItalic.ttf',\n boldItalic: 'Mulish-BoldItalic.ttf',\n lightItalic: 'Mulish-LightItalic.ttf',\n mediumItalic: 'Mulish-MediumItalic.ttf',\n semiboldItalic: 'Mulish-SemiBoldItalic.ttf',\n },\n 'Quicksand': {\n regular: 'Quicksand-Regular.ttf',\n bold: 'Quicksand-Bold.ttf',\n light: 'Quicksand-Light.ttf',\n medium: 'Quicksand-Medium.ttf',\n semibold: 'Quicksand-SemiBold.ttf',\n },\n 'Rubik': {\n regular: 'Rubik-Regular.ttf',\n bold: 'Rubik-Bold.ttf',\n light: 'Rubik-Light.ttf',\n medium: 'Rubik-Medium.ttf',\n semibold: 'Rubik-SemiBold.ttf',\n italic: 'Rubik-RegularItalic.ttf',\n boldItalic: 'Rubik-BoldItalic.ttf',\n lightItalic: 'Rubik-LightItalic.ttf',\n mediumItalic: 'Rubik-MediumItalic.ttf',\n semiboldItalic: 'Rubik-SemiBoldItalic.ttf',\n },\n 'Karla': {\n regular: 'Karla-Regular.ttf',\n bold: 'Karla-Bold.ttf',\n light: 'Karla-Light.ttf',\n medium: 'Karla-Medium.ttf',\n semibold: 'Karla-SemiBold.ttf',\n italic: 'Karla-RegularItalic.ttf',\n boldItalic: 'Karla-BoldItalic.ttf',\n lightItalic: 'Karla-LightItalic.ttf',\n mediumItalic: 'Karla-MediumItalic.ttf',\n semiboldItalic: 'Karla-SemiBoldItalic.ttf',\n },\n 'Plus Jakarta Sans': {\n regular: 'PlusJakartaSans-Regular.ttf',\n bold: 'PlusJakartaSans-Bold.ttf',\n light: 'PlusJakartaSans-Light.ttf',\n medium: 'PlusJakartaSans-Medium.ttf',\n semibold: 'PlusJakartaSans-SemiBold.ttf',\n italic: 'PlusJakartaSans-RegularItalic.ttf',\n boldItalic: 'PlusJakartaSans-BoldItalic.ttf',\n lightItalic: 'PlusJakartaSans-LightItalic.ttf',\n mediumItalic: 'PlusJakartaSans-MediumItalic.ttf',\n semiboldItalic: 'PlusJakartaSans-SemiBoldItalic.ttf',\n },\n 'Sora': {\n regular: 'Sora-Regular.ttf',\n bold: 'Sora-Bold.ttf',\n light: 'Sora-Light.ttf',\n medium: 'Sora-Medium.ttf',\n semibold: 'Sora-SemiBold.ttf',\n },\n 'Urbanist': {\n regular: 'Urbanist-Regular.ttf',\n bold: 'Urbanist-Bold.ttf',\n light: 'Urbanist-Light.ttf',\n medium: 'Urbanist-Medium.ttf',\n semibold: 'Urbanist-SemiBold.ttf',\n italic: 'Urbanist-RegularItalic.ttf',\n boldItalic: 'Urbanist-BoldItalic.ttf',\n lightItalic: 'Urbanist-LightItalic.ttf',\n mediumItalic: 'Urbanist-MediumItalic.ttf',\n semiboldItalic: 'Urbanist-SemiBoldItalic.ttf',\n },\n 'Lexend': {\n regular: 'Lexend-Regular.ttf',\n bold: 'Lexend-Bold.ttf',\n light: 'Lexend-Light.ttf',\n medium: 'Lexend-Medium.ttf',\n semibold: 'Lexend-SemiBold.ttf',\n },\n 'Albert Sans': {\n regular: 'AlbertSans-Regular.ttf',\n bold: 'AlbertSans-Bold.ttf',\n light: 'AlbertSans-Light.ttf',\n medium: 'AlbertSans-Medium.ttf',\n semibold: 'AlbertSans-SemiBold.ttf',\n italic: 'AlbertSans-RegularItalic.ttf',\n boldItalic: 'AlbertSans-BoldItalic.ttf',\n lightItalic: 'AlbertSans-LightItalic.ttf',\n mediumItalic: 'AlbertSans-MediumItalic.ttf',\n semiboldItalic: 'AlbertSans-SemiBoldItalic.ttf',\n },\n 'Noto Sans': {\n regular: 'NotoSans-Regular.ttf',\n bold: 'NotoSans-Bold.ttf',\n light: 'NotoSans-Light.ttf',\n medium: 'NotoSans-Medium.ttf',\n semibold: 'NotoSans-SemiBold.ttf',\n italic: 'NotoSans-RegularItalic.ttf',\n boldItalic: 'NotoSans-BoldItalic.ttf',\n lightItalic: 'NotoSans-LightItalic.ttf',\n mediumItalic: 'NotoSans-MediumItalic.ttf',\n semiboldItalic: 'NotoSans-SemiBoldItalic.ttf',\n },\n 'Cabin': {\n regular: 'Cabin-Regular.ttf',\n bold: 'Cabin-Bold.ttf',\n medium: 'Cabin-Medium.ttf',\n semibold: 'Cabin-SemiBold.ttf',\n italic: 'Cabin-RegularItalic.ttf',\n boldItalic: 'Cabin-BoldItalic.ttf',\n mediumItalic: 'Cabin-MediumItalic.ttf',\n semiboldItalic: 'Cabin-SemiBoldItalic.ttf',\n },\n 'Barlow': {\n regular: 'Barlow-Regular.ttf',\n bold: 'Barlow-Bold.ttf',\n light: 'Barlow-Light.ttf',\n medium: 'Barlow-Medium.ttf',\n semibold: 'Barlow-SemiBold.ttf',\n italic: 'Barlow-Italic.ttf',\n boldItalic: 'Barlow-BoldItalic.ttf',\n },\n 'Josefin Sans': {\n regular: 'JosefinSans-Regular.ttf',\n bold: 'JosefinSans-Bold.ttf',\n light: 'JosefinSans-Light.ttf',\n medium: 'JosefinSans-Medium.ttf',\n semibold: 'JosefinSans-SemiBold.ttf',\n italic: 'JosefinSans-RegularItalic.ttf',\n boldItalic: 'JosefinSans-BoldItalic.ttf',\n lightItalic: 'JosefinSans-LightItalic.ttf',\n mediumItalic: 'JosefinSans-MediumItalic.ttf',\n semiboldItalic: 'JosefinSans-SemiBoldItalic.ttf',\n },\n 'Archivo': {\n regular: 'Archivo-Regular.ttf',\n bold: 'Archivo-Bold.ttf',\n light: 'Archivo-Light.ttf',\n medium: 'Archivo-Medium.ttf',\n semibold: 'Archivo-SemiBold.ttf',\n italic: 'Archivo-RegularItalic.ttf',\n boldItalic: 'Archivo-BoldItalic.ttf',\n lightItalic: 'Archivo-LightItalic.ttf',\n mediumItalic: 'Archivo-MediumItalic.ttf',\n semiboldItalic: 'Archivo-SemiBoldItalic.ttf',\n },\n 'Overpass': {\n regular: 'Overpass-Regular.ttf',\n bold: 'Overpass-Bold.ttf',\n light: 'Overpass-Light.ttf',\n medium: 'Overpass-Medium.ttf',\n semibold: 'Overpass-SemiBold.ttf',\n italic: 'Overpass-RegularItalic.ttf',\n boldItalic: 'Overpass-BoldItalic.ttf',\n lightItalic: 'Overpass-LightItalic.ttf',\n mediumItalic: 'Overpass-MediumItalic.ttf',\n semiboldItalic: 'Overpass-SemiBoldItalic.ttf',\n },\n 'Exo 2': {\n regular: 'Exo2-Regular.ttf',\n bold: 'Exo2-Bold.ttf',\n light: 'Exo2-Light.ttf',\n medium: 'Exo2-Medium.ttf',\n semibold: 'Exo2-SemiBold.ttf',\n italic: 'Exo2-RegularItalic.ttf',\n boldItalic: 'Exo2-BoldItalic.ttf',\n lightItalic: 'Exo2-LightItalic.ttf',\n mediumItalic: 'Exo2-MediumItalic.ttf',\n semiboldItalic: 'Exo2-SemiBoldItalic.ttf',\n },\n 'Roboto Mono': {\n regular: 'RobotoMono-Regular.ttf',\n bold: 'RobotoMono-Bold.ttf',\n light: 'RobotoMono-Light.ttf',\n medium: 'RobotoMono-Medium.ttf',\n semibold: 'RobotoMono-SemiBold.ttf',\n italic: 'RobotoMono-RegularItalic.ttf',\n boldItalic: 'RobotoMono-BoldItalic.ttf',\n lightItalic: 'RobotoMono-LightItalic.ttf',\n mediumItalic: 'RobotoMono-MediumItalic.ttf',\n semiboldItalic: 'RobotoMono-SemiBoldItalic.ttf',\n },\n 'Fira Code': {\n regular: 'FiraCode-Regular.ttf',\n bold: 'FiraCode-Bold.ttf',\n light: 'FiraCode-Light.ttf',\n medium: 'FiraCode-Medium.ttf',\n semibold: 'FiraCode-SemiBold.ttf',\n },\n 'JetBrains Mono': {\n regular: 'JetBrainsMono-Regular.ttf',\n bold: 'JetBrainsMono-Bold.ttf',\n light: 'JetBrainsMono-Light.ttf',\n medium: 'JetBrainsMono-Medium.ttf',\n semibold: 'JetBrainsMono-SemiBold.ttf',\n italic: 'JetBrainsMono-RegularItalic.ttf',\n boldItalic: 'JetBrainsMono-BoldItalic.ttf',\n lightItalic: 'JetBrainsMono-LightItalic.ttf',\n mediumItalic: 'JetBrainsMono-MediumItalic.ttf',\n semiboldItalic: 'JetBrainsMono-SemiBoldItalic.ttf',\n },\n 'Source Code Pro': {\n regular: 'SourceCodePro-Regular.ttf',\n bold: 'SourceCodePro-Bold.ttf',\n light: 'SourceCodePro-Light.ttf',\n medium: 'SourceCodePro-Medium.ttf',\n semibold: 'SourceCodePro-SemiBold.ttf',\n italic: 'SourceCodePro-RegularItalic.ttf',\n boldItalic: 'SourceCodePro-BoldItalic.ttf',\n lightItalic: 'SourceCodePro-LightItalic.ttf',\n mediumItalic: 'SourceCodePro-MediumItalic.ttf',\n semiboldItalic: 'SourceCodePro-SemiBoldItalic.ttf',\n },\n 'IBM Plex Mono': {\n regular: 'IBMPlexMono-Regular.ttf',\n bold: 'IBMPlexMono-Bold.ttf',\n },\n 'Space Mono': {\n regular: 'SpaceMono-Regular.ttf',\n bold: 'SpaceMono-Bold.ttf',\n italic: 'SpaceMono-Italic.ttf',\n boldItalic: 'SpaceMono-BoldItalic.ttf',\n },\n 'Sacramento': { regular: 'Sacramento-Regular.ttf' },\n 'Alex Brush': { regular: 'AlexBrush-Regular.ttf' },\n 'Allura': { regular: 'Allura-Regular.ttf' },\n 'Caveat': {\n regular: 'Caveat-Regular.ttf',\n bold: 'Caveat-Bold.ttf',\n medium: 'Caveat-Medium.ttf',\n semibold: 'Caveat-SemiBold.ttf',\n },\n 'Lobster': { regular: 'Lobster-Regular.ttf' },\n 'Comfortaa': {\n regular: 'Comfortaa-Regular.ttf',\n bold: 'Comfortaa-Bold.ttf',\n light: 'Comfortaa-Light.ttf',\n medium: 'Comfortaa-Medium.ttf',\n semibold: 'Comfortaa-SemiBold.ttf',\n },\n 'Anton': { regular: 'Anton-Regular.ttf' },\n 'Teko': {\n regular: 'Teko-Regular.ttf',\n bold: 'Teko-Bold.ttf',\n light: 'Teko-Light.ttf',\n medium: 'Teko-Medium.ttf',\n semibold: 'Teko-SemiBold.ttf',\n },\n 'Noto Sans Devanagari': {\n regular: 'NotoSansDevanagari-Regular.ttf',\n bold: 'NotoSansDevanagari-Bold.ttf',\n light: 'NotoSansDevanagari-Light.ttf',\n medium: 'NotoSansDevanagari-Medium.ttf',\n semibold: 'NotoSansDevanagari-SemiBold.ttf',\n },\n 'Hind': {\n regular: 'Hind-Regular.ttf',\n bold: 'Hind-Bold.ttf',\n light: 'Hind-Light.ttf',\n medium: 'Hind-Medium.ttf',\n semibold: 'Hind-SemiBold.ttf',\n },\n 'Noto Sans Math': {\n regular: 'NotoSansMath-Regular.ttf',\n },\n 'Cinzel': { regular: 'Cinzel-Regular.ttf', bold: 'Cinzel-Bold.ttf' },\n 'Cormorant Garamond': {\n regular: 'CormorantGaramond-Regular.ttf',\n bold: 'CormorantGaramond-Bold.ttf',\n light: 'CormorantGaramond-Light.ttf',\n medium: 'CormorantGaramond-Medium.ttf',\n semibold: 'CormorantGaramond-SemiBold.ttf',\n italic: 'CormorantGaramond-Italic.ttf',\n boldItalic: 'CormorantGaramond-BoldItalic.ttf',\n },\n};\n\n// ─── Weight/style resolution ───\n\nconst WEIGHT_TO_KEYS: Record<number, (keyof FontWeightFiles)[]> = {\n 300: ['light', 'regular'],\n 400: ['regular'],\n 500: ['medium', 'regular'],\n 600: ['semibold', 'bold', 'regular'],\n 700: ['bold', 'regular'],\n};\n\nconst WEIGHT_TO_ITALIC_KEYS: Record<number, (keyof FontWeightFiles)[]> = {\n 300: ['lightItalic', 'italic', 'light', 'regular'],\n 400: ['italic', 'regular'],\n 500: ['mediumItalic', 'italic', 'medium', 'regular'],\n 600: ['semiboldItalic', 'boldItalic', 'italic', 'semibold', 'bold', 'regular'],\n 700: ['boldItalic', 'italic', 'bold', 'regular'],\n};\n\nexport function getFontPathForWeight(files: FontWeightFiles, weight: number, isItalic = false): string {\n const keys = isItalic ? WEIGHT_TO_ITALIC_KEYS[weight] : WEIGHT_TO_KEYS[weight];\n if (!keys) return files.regular;\n for (const k of keys) {\n const path = files[k];\n if (path) return path;\n }\n return files.regular;\n}\n\nfunction isExactWeightItalicMatch(files: FontWeightFiles, weight: number, isItalic: boolean, path: string): boolean {\n const exactKey: keyof FontWeightFiles = isItalic\n ? weight === 300 ? 'lightItalic' : weight === 500 ? 'mediumItalic' : weight === 600 ? 'semiboldItalic' : weight === 700 ? 'boldItalic' : 'italic'\n : weight === 300 ? 'light' : weight === 500 ? 'medium' : weight === 600 ? 'semibold' : weight === 700 ? 'bold' : 'regular';\n return files[exactKey] === path;\n}\n\nfunction getJsPDFFontName(fontName: string): string {\n return fontName.replace(/\\s+/g, '');\n}\n\n/**\n * Get the embedded jsPDF font name for a given font family + weight + italic.\n * This is the name used for pdf.setFont() and must match the font-family\n * attribute rewritten in SVG text elements.\n */\nexport function getEmbeddedJsPDFFontName(fontName: string, weight: number, isItalic = false): string {\n const resolved = resolveFontWeight(weight);\n const label = FONT_WEIGHT_LABELS[resolved];\n const italicSuffix = isItalic ? 'Italic' : '';\n return `${getJsPDFFontName(fontName)}-${label}${italicSuffix}`;\n}\n\n/** Check if a font is in our local mapping */\nexport function isFontAvailable(fontName: string): boolean {\n return fontName in FONT_FILES;\n}\n\n// ─── Runtime registry of fonts that have been embedded into jsPDF ───\n// Includes both local TTFs and Google/Fontshare fallbacks fetched at runtime.\n// Used by rewriteSvgFontsForJsPDF to decide whether to rewrite a font-family\n// to its embedded jsPDF name (otherwise svg2pdf falls back to Helvetica).\nconst registeredFamilies: Set<string> = new Set();\nfunction isFamilyEmbedded(family: string): boolean {\n return registeredFamilies.has(family);\n}\n\n// ─── TTF fetching + caching ───\n\nconst ttfCache = new Map<string, string>(); // cacheKey → base64\n\nasync function fetchTTFAsBase64(url: string): Promise<string | null> {\n const cached = ttfCache.get(url);\n if (cached) return cached;\n try {\n const res = await fetch(url);\n if (!res.ok) return null;\n const buf = await res.arrayBuffer();\n const bytes = new Uint8Array(buf);\n if (!isJsPdfEmbeddableTrueType(bytes)) return null;\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n const b64 = btoa(binary);\n ttfCache.set(url, b64);\n return b64;\n } catch {\n return null;\n }\n}\n\nfunction isJsPdfEmbeddableTrueType(bytes: Uint8Array): boolean {\n if (bytes.length < 12) return false;\n const signature = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3]);\n if (signature !== '\\x00\\x01\\x00\\x00' && signature !== 'true') return false;\n\n const u16 = (offset: number) => (bytes[offset] << 8) | bytes[offset + 1];\n const u32 = (offset: number) => ((bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]) >>> 0;\n const tableCount = u16(4);\n for (let i = 0; i < tableCount; i++) {\n const recordOffset = 12 + i * 16;\n if (recordOffset + 16 > bytes.length) return false;\n const tag = String.fromCharCode(bytes[recordOffset], bytes[recordOffset + 1], bytes[recordOffset + 2], bytes[recordOffset + 3]);\n if (tag !== 'cmap') continue;\n const cmapOffset = u32(recordOffset + 8);\n const cmapLength = u32(recordOffset + 12);\n if (cmapOffset + Math.min(cmapLength, 4) > bytes.length) return false;\n const subtables = u16(cmapOffset + 2);\n for (let j = 0; j < subtables; j++) {\n const encOffset = cmapOffset + 4 + j * 8;\n if (encOffset + 8 > bytes.length) return false;\n const platform = u16(encOffset);\n const encoding = u16(encOffset + 2);\n if (platform === 0 || (platform === 3 && (encoding === 1 || encoding === 10))) return true;\n }\n return false;\n }\n return false;\n}\n\nfunction base64ToBytes(b64: string): Uint8Array {\n const binary = atob(b64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\nfunction extractSupportedCodePointsFromTtf(bytes: Uint8Array): Set<number> {\n const out = new Set<number>();\n if (bytes.length < 12) return out;\n const u16 = (o: number) => (bytes[o] << 8) | bytes[o + 1];\n const i16 = (o: number) => { const v = u16(o); return v & 0x8000 ? v - 0x10000 : v; };\n const u32 = (o: number) => ((bytes[o] << 24) | (bytes[o + 1] << 16) | (bytes[o + 2] << 8) | bytes[o + 3]) >>> 0;\n let cmap = 0;\n for (let i = 0, n = u16(4); i < n; i++) {\n const off = 12 + i * 16;\n if (String.fromCharCode(bytes[off], bytes[off + 1], bytes[off + 2], bytes[off + 3]) === 'cmap') { cmap = u32(off + 8); break; }\n }\n if (!cmap) return out;\n const candidates: Array<{ format: number; off: number; score: number }> = [];\n for (let i = 0, n = u16(cmap + 2); i < n; i++) {\n const enc = cmap + 4 + i * 8;\n const platform = u16(enc), encoding = u16(enc + 2), off = cmap + u32(enc + 4), format = u16(off);\n const score = (format === 12 ? 40 : format === 4 ? 30 : 0) + (platform === 3 && encoding === 10 ? 2 : platform === 0 ? 1 : 0);\n if (score) candidates.push({ format, off, score });\n }\n candidates.sort((a, b) => b.score - a.score);\n const best = candidates[0];\n if (!best) return out;\n if (best.format === 12) {\n for (let i = 0, n = u32(best.off + 12); i < n; i++) {\n const off = best.off + 16 + i * 12, start = u32(off), end = u32(off + 4);\n for (let cp = start; cp <= end && cp <= 0x10ffff; cp++) out.add(cp);\n }\n } else if (best.format === 4) {\n const segCount = u16(best.off + 6) / 2, endCodes = best.off + 14, startCodes = endCodes + segCount * 2 + 2, deltas = startCodes + segCount * 2, ranges = deltas + segCount * 2;\n for (let i = 0; i < segCount; i++) for (let cp = u16(startCodes + i * 2), end = u16(endCodes + i * 2); cp <= end && cp !== 0xffff; cp++) {\n const ro = u16(ranges + i * 2);\n if (ro === 0 ? ((cp + i16(deltas + i * 2)) & 0xffff) !== 0 : u16(ranges + i * 2 + ro + (cp - u16(startCodes + i * 2)) * 2) !== 0) out.add(cp);\n }\n }\n return out;\n}\n\n// ─── Single font embedding (matches client-side embedFont) ───\n\n/**\n * Load and embed a single font weight into jsPDF.\n * Each weight is registered as a SEPARATE jsPDF font name like \"JosefinSans-SemiBold\"\n * with style \"normal\". This is the key difference from the old approach.\n */\nexport async function embedFont(\n pdf: jsPDF,\n fontName: string,\n weight: number,\n fontBaseUrl: string,\n isItalic = false,\n): Promise<boolean> {\n const fontFiles = FONT_FILES[fontName];\n if (!fontFiles) return false;\n\n const baseUrl = fontBaseUrl.endsWith('/') ? fontBaseUrl : fontBaseUrl + '/';\n const resolvedWeight = resolveFontWeight(weight);\n const fontPath = getFontPathForWeight(fontFiles, resolvedWeight, isItalic);\n if (!fontPath) return false;\n if (!isExactWeightItalicMatch(fontFiles, resolvedWeight, isItalic, fontPath)) return false;\n\n const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, weight, isItalic);\n const label = FONT_WEIGHT_LABELS[resolvedWeight];\n const italicSuffix = isItalic ? 'Italic' : '';\n const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;\n\n const url = baseUrl + fontPath;\n\n try {\n const b64 = await fetchTTFAsBase64(url);\n if (!b64) return false;\n registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(base64ToBytes(b64)));\n\n pdf.addFileToVFS(fileName, b64);\n // Register with the weight-specific name, always with style \"normal\"\n pdf.addFont(fileName, jsPdfFontName, 'normal');\n // Also register under the raw family name for svg2pdf compatibility\n if (fontName !== jsPdfFontName) {\n try { pdf.addFont(fileName, fontName, 'normal'); } catch { /* ignore duplicate */ }\n }\n registeredFamilies.add(fontName);\n registeredVariants.add(variantKey(fontName, resolvedWeight, isItalic));\n return true;\n } catch (e) {\n console.warn(`[pdf-fonts] Failed to embed ${fontName} w${weight}:`, e);\n return false;\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Google Fonts / Fontshare dynamic TTF fallback (parity with main app)\n// Lets us embed any font referenced in the template even if there's no\n// local TTF in /public/fonts (e.g. \"Rubik Maze\", display fonts, etc.).\n// Without this, svg2pdf falls back to Helvetica for those families.\n// ═══════════════════════════════════════════════════════════════\n\nconst googleFontNotFound: Set<string> = new Set();\nconst fontshareNotFound: Set<string> = new Set();\n\nconst remoteVariantKey = (family: string, weight: number, isItalic: boolean): string =>\n `${family}|${resolveFontWeight(weight)}|${isItalic ? 'i' : 'n'}`;\n\nconst registeredVariants: Set<string> = new Set();\nconst registeredVariantCoverage: Map<string, Set<number>> = new Map();\nconst variantKey = (family: string, weight: number, italic: boolean): string =>\n `${family}|${resolveFontWeight(weight)}|${italic ? 'i' : 'n'}`;\n\n/** True if the (family, weight, italic) variant is currently registered in jsPDF. */\nexport function isVariantEmbedded(family: string, weight: number, italic: boolean): boolean {\n return registeredVariants.has(variantKey(family, weight, italic));\n}\n\nexport const resolveBestRegisteredVariant = (\n family: string,\n weight: number,\n italic: boolean,\n): { weight: number; italic: boolean } | null => {\n const want = resolveFontWeight(weight);\n const weights = [300, 400, 500, 600, 700];\n if (registeredVariants.has(variantKey(family, want, italic))) return { weight: want, italic };\n const nearest = [...weights].sort((a, b) => Math.abs(a - want) - Math.abs(b - want) || (want >= 500 ? b - a : a - b));\n for (const w of nearest) if (registeredVariants.has(variantKey(family, w, italic))) return { weight: w, italic };\n for (const w of nearest) if (registeredVariants.has(variantKey(family, w, !italic))) return { weight: w, italic: !italic };\n return null;\n};\n\nconst doesVariantSupportChar = (family: string, weight: number, italic: boolean, char: string): boolean => {\n const cp = char.codePointAt(0);\n if (cp == null) return false;\n return registeredVariantCoverage.get(variantKey(family, weight, italic))?.has(cp) === true;\n};\n\nfunction bytesToBase64(bytes: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);\n return btoa(binary);\n}\n\nfunction getFontProxyUrl(): string | null {\n const viteUrl = (import.meta as any).env?.VITE_SUPABASE_URL || '';\n const runtimeUrl = typeof globalThis !== 'undefined'\n ? ((globalThis as any).__CONFIG__?.supabaseUrl || (globalThis as any).__PIXLDOCS_SUPABASE_URL || '')\n : '';\n const baseUrl = (viteUrl || runtimeUrl || '').replace(/\\/$/, '');\n return baseUrl ? `${baseUrl}/functions/v1/font-proxy` : null;\n}\n\nasync function fetchTtfViaProxy(\n family: string,\n weight: number,\n isItalic: boolean,\n source: 'google' | 'fontshare',\n): Promise<Uint8Array | null> {\n const proxyUrl = getFontProxyUrl();\n if (!proxyUrl) return null;\n try {\n const url = `${proxyUrl}?family=${encodeURIComponent(family)}&weight=${weight}&italic=${isItalic ? 1 : 0}&source=${source}`;\n const res = await fetch(url);\n if (!res.ok) return null;\n const bytes = new Uint8Array(await res.arrayBuffer());\n return isJsPdfEmbeddableTrueType(bytes) ? bytes : null;\n } catch {\n return null;\n }\n}\n\n/** Fetch a TTF (base64) from Google Fonts directly. Uses a legacy UA so the\n * CDN returns TTF instead of WOFF2 (which jsPDF can't embed). */\nasync function fetchGoogleFontTTF(\n fontFamily: string,\n weight: number,\n isItalic = false,\n): Promise<string | null> {\n const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? 'i' : 'n'}`;\n if (ttfCache.has(cacheKey)) return ttfCache.get(cacheKey)!;\n const notFoundKey = remoteVariantKey(fontFamily, weight, isItalic);\n if (googleFontNotFound.has(notFoundKey)) return null;\n const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, 'google');\n if (proxyBytes) {\n const b64 = bytesToBase64(proxyBytes);\n ttfCache.set(cacheKey, b64);\n return b64;\n }\n try {\n const ital = isItalic ? '1' : '0';\n const cssUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(\n fontFamily,\n )}:ital,wght@${ital},${weight}&display=swap`;\n const cssRes = await fetch(cssUrl, {\n headers: {\n 'User-Agent':\n 'Mozilla/5.0 (Linux; U; Android 2.2; en-us) AppleWebKit/533.1 (KHTML, like Gecko)',\n },\n });\n if (!cssRes.ok) {\n if (cssRes.status === 400 || cssRes.status === 404) googleFontNotFound.add(notFoundKey);\n return null;\n }\n const css = await cssRes.text();\n const urlMatch = css.match(/url\\(([^)]+)\\)\\s+format\\(['\"]?truetype['\"]?\\)/i)\n || css.match(/url\\(([^)]+)\\)/);\n if (!urlMatch) return null;\n const ttfUrl = urlMatch[1].replace(/['\"]/g, '');\n const ttfRes = await fetch(ttfUrl);\n if (!ttfRes.ok) return null;\n const buf = await ttfRes.arrayBuffer();\n const bytes = new Uint8Array(buf);\n if (!isJsPdfEmbeddableTrueType(bytes)) {\n console.warn(`[pdf-fonts] Google Fonts returned a non-TTF for ${fontFamily} (${weight}); skipping`);\n return null;\n }\n const b64 = bytesToBase64(bytes);\n ttfCache.set(cacheKey, b64);\n return b64;\n } catch (err) {\n console.warn(`[pdf-fonts] fetchGoogleFontTTF failed for ${fontFamily} (${weight}):`, err);\n return null;\n }\n}\n\n/** Fetch a TTF (base64) from Fontshare (Satoshi, Clash Display, etc.). */\nasync function fetchFontshareTTF(\n fontFamily: string,\n weight: number,\n isItalic = false,\n): Promise<string | null> {\n const cacheKey = `fs:${fontFamily}:${weight}:${isItalic ? 'i' : 'n'}`;\n if (ttfCache.has(cacheKey)) return ttfCache.get(cacheKey)!;\n const notFoundKey = remoteVariantKey(fontFamily, weight, isItalic);\n if (fontshareNotFound.has(notFoundKey)) return null;\n const slug = fontFamily.trim().toLowerCase().replace(/\\s+/g, '-');\n const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, 'fontshare');\n if (proxyBytes) {\n const b64 = bytesToBase64(proxyBytes);\n ttfCache.set(cacheKey, b64);\n return b64;\n }\n try {\n const styleSuffix = isItalic ? 'i' : '';\n const cssUrl = `https://api.fontshare.com/v2/css?f[]=${slug}@${weight}${styleSuffix}&display=swap`;\n const cssRes = await fetch(cssUrl);\n if (!cssRes.ok) {\n if (cssRes.status === 400 || cssRes.status === 404) fontshareNotFound.add(notFoundKey);\n return null;\n }\n const css = await cssRes.text();\n const ttMatch = css.match(/url\\(([^)]+)\\)\\s+format\\(['\"]?truetype['\"]?\\)/i);\n if (!ttMatch) {\n fontshareNotFound.add(notFoundKey);\n return null;\n }\n let ttfUrl = ttMatch[1].replace(/['\"]/g, '').trim();\n if (ttfUrl.startsWith('//')) ttfUrl = `https:${ttfUrl}`;\n const ttfRes = await fetch(ttfUrl);\n if (!ttfRes.ok) return null;\n const buf = await ttfRes.arrayBuffer();\n const bytes = new Uint8Array(buf);\n if (!isJsPdfEmbeddableTrueType(bytes)) return null;\n const b64 = bytesToBase64(bytes);\n ttfCache.set(cacheKey, b64);\n return b64;\n } catch (err) {\n console.warn(`[pdf-fonts] fetchFontshareTTF failed for ${fontFamily} (${weight}):`, err);\n return null;\n }\n}\n\nfunction registerJsPdfFont(\n pdf: jsPDF,\n fontName: string,\n resolvedWeight: number,\n isItalic: boolean,\n base64: string,\n): boolean {\n const label = FONT_WEIGHT_LABELS[resolvedWeight];\n const italicSuffix = isItalic ? 'Italic' : '';\n const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, resolvedWeight, isItalic);\n const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;\n try {\n registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(base64ToBytes(base64)));\n pdf.addFileToVFS(fileName, base64);\n pdf.addFont(fileName, jsPdfFontName, 'normal');\n if (fontName !== jsPdfFontName) {\n try { pdf.addFont(fileName, fontName, 'normal'); } catch { /* duplicate alias */ }\n }\n registeredFamilies.add(fontName);\n registeredVariants.add(variantKey(fontName, resolvedWeight, isItalic));\n return true;\n } catch (err) {\n console.warn(`[pdf-fonts] registerJsPdfFont failed for ${fontName}:`, err);\n return false;\n }\n}\n\n/**\n * Embed a font into jsPDF — tries local TTF, then Fontshare, then Google Fonts.\n * Mirrors `embedFontWithGoogleFallback` in the main app's pdfFonts.ts.\n */\nexport async function embedFontWithGoogleFallback(\n pdf: jsPDF,\n fontName: string,\n weight: number = 400,\n fontBaseUrl: string,\n isItalic = false,\n): Promise<boolean> {\n // 1. Local first\n if (FONT_FILES[fontName]) {\n const ok = await embedFont(pdf, fontName, weight, fontBaseUrl, isItalic);\n if (ok) return true;\n }\n const resolved = resolveFontWeight(weight);\n\n // Weight-ladder fallback (parity with client `src/lib/pdfFonts.ts`).\n // Single-weight decorative families (Pacifico, Frijole, Stardom, etc.) only\n // ship 400. When the requested weight is unavailable, walk the ladder so\n // the family still embeds with its real glyphs. We register under the\n // ACTUAL fetched weight so the SVG rewriter's `needsSyntheticBold` check\n // fires and applies stroke-based synthetic bold — matching what <canvas>\n // does in the browser preview.\n const weightLadder: number[] = [resolved];\n for (const w of [400, 500, 700, 600, 300]) {\n if (!weightLadder.includes(w)) weightLadder.push(w);\n }\n\n const tryFetch = async (w: number, italic: boolean): Promise<string | null> => {\n const fs = await fetchFontshareTTF(fontName, w, italic);\n if (fs) return fs;\n const g = await fetchGoogleFontTTF(fontName, w, italic);\n return g;\n };\n\n let b64: string | null = null;\n let usedItalic = isItalic;\n let usedWeight = resolved;\n for (const w of weightLadder) {\n b64 = await tryFetch(w, isItalic);\n if (b64) { usedWeight = w; break; }\n }\n if (!b64 && isItalic) {\n for (const w of weightLadder) {\n b64 = await tryFetch(w, false);\n if (b64) { usedItalic = false; usedWeight = w; break; }\n }\n }\n if (!b64) return false;\n return registerJsPdfFont(pdf, fontName, usedWeight, usedItalic, b64);\n}\n\n// ─── Config-based font discovery and embedding (matches client embedFontsForConfig) ───\n\n/**\n * Walk a template config to discover all font families/weights,\n * then embed each one into jsPDF. Also embeds symbol + devanagari fallbacks.\n */\nexport async function embedFontsForConfig(\n pdf: jsPDF,\n config: any,\n fontBaseUrl: string,\n): Promise<Set<string>> {\n const fontKeys = new Set<string>();\n const SEP = '\\u001F';\n\n // Normalize Fabric fontWeight (number OR string like \"bold\"/\"normal\"/\"600\")\n // to {300,400,500,600,700}. resolveFontWeight() alone returns 700 for any\n // non-numeric string (NaN comparisons), causing the embedded jsPDF font name\n // to mismatch the SVG-rewritten font name → svg2pdf falls back to Helvetica\n // in selectable-text mode.\n const normalizeWeight = (raw: any): number => {\n if (raw == null) return 400;\n if (typeof raw === 'number' && Number.isFinite(raw)) return resolveFontWeight(raw);\n const str = String(raw).trim().toLowerCase();\n const parsed = Number.parseInt(str, 10);\n if (Number.isFinite(parsed)) return resolveFontWeight(parsed);\n if (str === 'bold' || str === 'bolder') return 700;\n if (str === 'semibold' || str === 'demibold') return 600;\n if (str === 'medium') return 500;\n if (str === 'light' || str === 'lighter' || str === 'thin') return 300;\n return 400;\n };\n\n const walkElements = (elements: any[]) => {\n for (const el of elements) {\n const addFontVariant = (family: string, weight: number, italic: boolean) => {\n fontKeys.add(`${family}${SEP}${weight}${SEP}${italic ? 'italic' : 'normal'}`);\n };\n\n if (el.fontFamily) {\n const w = normalizeWeight(el.fontWeight);\n addFontVariant(el.fontFamily, w, /italic|oblique/i.test(String(el.fontStyle ?? '')));\n // NOTE: previously we speculatively pre-embedded {700,n}, {400,i}, {700,i}\n // for every text family \"just in case\". That ballooned PDF size by\n // ~25KB on average vs the server pipeline (which never speculates) —\n // decorative single-weight fonts (Alex Brush, Pacifico, Abril Fatface,\n // …) ended up shipping fake bold/italic subsets that no glyph actually\n // uses. Variants that are *actually* referenced by markdown / styles\n // are still added below; anything the SVG rewriter emits later is\n // caught by `embedFontVariantsFromSvg`. This restores 1:1 file-size\n // parity with the server export.\n // ── PARITY: inline markdown formatting (formattingEnabled) ──\n // The saved config has `text: \"**bold**\"` but no `el.styles` map —\n // those styles are computed from markdown at render time. Without\n // walking the parser output we miss the bold/italic font variants\n // and svg2pdf falls back to Helvetica for those tspans.\n if (el.formattingEnabled === true && typeof el.text === 'string') {\n try {\n const parsed = parseTextMarkdown(el.text);\n for (const lineStyles of Object.values(parsed.styles || {})) {\n if (!lineStyles || typeof lineStyles !== 'object') continue;\n for (const s of Object.values(lineStyles as Record<string, any>)) {\n if (!s) continue;\n const family = s.fontFamily || el.fontFamily;\n if (!family) continue;\n const ww = normalizeWeight(s.fontWeight ?? el.fontWeight);\n const it = /italic|oblique/i.test(String(s.fontStyle ?? el.fontStyle ?? ''));\n addFontVariant(family, ww, it);\n }\n }\n } catch {/* parser is best-effort */}\n }\n }\n // Check Fabric v6 object-keyed styles\n if (el.styles && typeof el.styles === 'object') {\n for (const lineKey of Object.keys(el.styles)) {\n const lineStyles = el.styles[lineKey];\n if (lineStyles && typeof lineStyles === 'object') {\n for (const charKey of Object.keys(lineStyles)) {\n const s = lineStyles[charKey];\n const styledFamily = s?.fontFamily || el.fontFamily;\n if (styledFamily) {\n const w = normalizeWeight(s.fontWeight ?? el.fontWeight);\n addFontVariant(styledFamily, w, /italic|oblique/i.test(String(s.fontStyle ?? el.fontStyle ?? '')));\n }\n }\n }\n }\n }\n if (el.children) walkElements(el.children);\n if (el.objects) walkElements(el.objects);\n }\n };\n\n for (const page of (config?.pages || [])) {\n if (page.children) walkElements(page.children);\n if (page.elements) walkElements(page.elements);\n }\n\n // Always embed symbol + devanagari fallbacks\n fontKeys.add(`${FONT_FALLBACK_SYMBOLS}${SEP}400${SEP}normal`);\n fontKeys.add(`${FONT_FALLBACK_MATH}${SEP}400${SEP}normal`);\n for (const w of [300, 400, 500, 600, 700]) {\n fontKeys.add(`${FONT_FALLBACK_DEVANAGARI}${SEP}${w}${SEP}normal`);\n }\n\n const embedded = new Set<string>();\n const tasks: Promise<void>[] = [];\n\n for (const key of fontKeys) {\n const sep = key.indexOf(SEP);\n const secondSep = key.indexOf(SEP, sep + 1);\n const fontName = key.slice(0, sep);\n const weight = parseInt(key.slice(sep + 1, secondSep), 10);\n const italic = key.slice(secondSep + 1) === 'italic';\n if (!isFontAvailable(fontName)) continue;\n\n tasks.push(\n embedFont(pdf, fontName, weight, fontBaseUrl, italic).then((ok) => {\n if (ok) embedded.add(key);\n }),\n );\n }\n\n await Promise.all(tasks);\n console.log(`[pdf-fonts] Embedded ${embedded.size} font variants from config`);\n return embedded;\n}\n\n// ─── Devanagari detection ───\n\n/** True if the character is in the Devanagari Unicode block (Hindi, Marathi, Sanskrit, etc.) */\nfunction isDevanagari(char: string): boolean {\n const c = char.codePointAt(0) ?? 0;\n return (c >= 0x0900 && c <= 0x097F) || (c >= 0xA8E0 && c <= 0xA8FF) || (c >= 0x1CD0 && c <= 0x1CFF);\n}\n\nfunction containsDevanagari(text: string): boolean {\n if (!text) return false;\n for (const char of text) {\n if (isDevanagari(char)) return true;\n }\n return false;\n}\n\n/** Check if a string contains any \"symbol\" characters that need the symbol-fallback font.\n * A symbol char here = anything outside Basic Latin/Latin-1 and outside Devanagari\n * (e.g. ₹ ₿ € ™ ★ arrows, etc.). The active font often lacks these glyphs, so we\n * must split them into a separate <tspan> using Noto Sans. */\nfunction containsSymbol(text: string, mainSupportsChar?: (char: string) => boolean): boolean {\n if (!text) return false;\n for (const char of text) {\n if (classifyChar(char, mainSupportsChar) !== 'main') return true;\n }\n return false;\n}\n\n/** True if the character is in Basic Latin or Latin-1 */\nfunction isBasicLatinOrLatin1(char: string): boolean {\n const c = char.codePointAt(0) ?? 0;\n return c <= 0x024F;\n}\n\n/**\n * Common typographic punctuation that virtually every modern Latin font\n * (Google Fonts, Fontshare, etc.) includes. We must NOT route these to the\n * symbol-fallback font (Noto Sans) because that makes them visually mismatch\n * the live canvas — e.g. an em-dash (U+2014) routed through a fallback can\n * appear as a thin \"artificial line\" instead of the active font's actual\n * dash glyph. This whitelist mirrors the client-side vectorPdfExport rules\n * so client and package PDF exports agree pixel-for-pixel.\n */\nfunction isCommonLatinPunctuation(char: string): boolean {\n const c = char.codePointAt(0) ?? 0;\n if (c >= 0x2010 && c <= 0x2049) return true; // dashes, quotes, ellipsis, bullet, primes...\n if (c === 0x2113 || c === 0x2122) return true; // ℓ, ™\n return false;\n}\n\nfunction isMathOperator(char: string): boolean {\n const c = char.codePointAt(0) ?? 0;\n return (c >= 0x2190 && c <= 0x22FF) || (c >= 0x2300 && c <= 0x23FF) || (c >= 0x27C0 && c <= 0x2AFF) || (c >= 0x2B00 && c <= 0x2B59);\n}\n\ntype RunType = 'main' | 'devanagari' | 'math' | 'symbol';\nfunction classifyChar(char: string, mainSupportsChar?: (char: string) => boolean): RunType {\n if (isBasicLatinOrLatin1(char)) return 'main';\n if (isCommonLatinPunctuation(char)) return 'main';\n if (!isDevanagari(char) && mainSupportsChar?.(char)) return 'main';\n if (isDevanagari(char)) return 'devanagari';\n if (isMathOperator(char)) return 'math';\n return 'symbol';\n}\n\n/** Split text into contiguous runs of same script type */\nfunction splitIntoRuns(text: string, mainSupportsChar?: (char: string) => boolean): { text: string; runType: RunType }[] {\n if (!text) return [];\n const runs: { text: string; runType: RunType }[] = [];\n let currentType: RunType | null = null;\n let currentText = '';\n for (const char of text) {\n const type = classifyChar(char, mainSupportsChar);\n if (type !== currentType && currentText) {\n runs.push({ text: currentText, runType: currentType! });\n currentText = '';\n }\n currentType = type;\n currentText += char;\n }\n if (currentText && currentType) {\n runs.push({ text: currentText, runType: currentType });\n }\n return runs;\n}\n\n// ─── SVG font-family rewriting (matches client rewriteSvgFontsForJsPDF) ───\n\n/**\n * Rewrite font-family attributes in SVG <text>/<tspan> to match jsPDF embedded font names.\n * CRITICAL: Also sets font-weight to \"normal\" because the weight is already baked into\n * the jsPDF font name (e.g. JosefinSans-SemiBold). Without this, svg2pdf combines\n * font-weight + font-style into \"600normal\" which won't match fonts registered with style \"normal\".\n *\n * For Devanagari text: splits <tspan> elements containing mixed scripts into separate\n * <tspan> children — Latin runs use the original font, Devanagari runs use FONT_FALLBACK_DEVANAGARI.\n */\nexport function rewriteSvgFontsForJsPDF(svgStr: string): string {\n const parser = new DOMParser();\n const doc = parser.parseFromString(svgStr, 'image/svg+xml');\n const allTextEls = Array.from(doc.querySelectorAll('text, tspan, textPath'));\n\n const readStyleToken = (style: string, prop: string): string | null => {\n const match = style.match(new RegExp(`${prop}\\\\s*:\\\\s*([^;]+)`, 'i'));\n return match?.[1]?.trim() || null;\n };\n\n const resolveInheritedValue = (el: Element, attr: string, styleProp = attr): string | null => {\n let current: Element | null = el;\n while (current) {\n const attrVal = current.getAttribute(attr)?.trim();\n if (attrVal) return attrVal;\n const styleVal = readStyleToken(current.getAttribute('style') || '', styleProp);\n if (styleVal) return styleVal;\n current = current.parentElement;\n }\n return null;\n };\n\n const resolveWeightNum = (weightRaw: string): number => {\n const parsedWeight = Number.parseInt(weightRaw, 10);\n return Number.isFinite(parsedWeight)\n ? parsedWeight\n : /bold/i.test(weightRaw)\n ? 700\n : /medium/i.test(weightRaw)\n ? 500\n : /semi/i.test(weightRaw)\n ? 600\n : /light/i.test(weightRaw)\n ? 300\n : 400;\n };\n\n const buildStyleString = (existingStyle: string, fontName: string): string => {\n const stylePairs = existingStyle\n .split(';')\n .map((part) => part.trim())\n .filter(Boolean)\n .filter((part) => !/^font-family\\s*:/i.test(part) && !/^font-weight\\s*:/i.test(part) && !/^font-style\\s*:/i.test(part));\n stylePairs.push(`font-family: ${fontName}`);\n stylePairs.push(`font-weight: normal`);\n stylePairs.push(`font-style: normal`);\n return stylePairs.join('; ');\n };\n\n const applySyntheticItalicTransform = (el: Element): void => {\n const x = Number.parseFloat(resolveInheritedValue(el, 'x') || '0') || 0;\n const y = Number.parseFloat(resolveInheritedValue(el, 'y') || '0') || 0;\n const existing = el.getAttribute('transform') || '';\n const synth = `translate(${x} ${y}) skewX(-12) translate(${-x} ${-y})`;\n el.setAttribute('transform', existing ? `${existing} ${synth}` : synth);\n };\n\n const getDepth = (el: Element): number => {\n let depth = 0;\n let current = el.parentElement;\n while (current) { depth++; current = current.parentElement; }\n return depth;\n };\n\n const sourceMeta = new Map<Element, {\n clean: string;\n requested: number;\n resolved: number;\n isItalic: boolean;\n actualItalic: boolean;\n jsPdfName: string;\n inlineStyle: string;\n weight: number;\n }>();\n\n for (const el of allTextEls) {\n const inlineStyle = el.getAttribute('style') || '';\n const rawFf = resolveInheritedValue(el, 'font-family');\n if (!rawFf) continue;\n const clean = rawFf\n .split(',')[0]\n ?.replace(/['\"]/g, '')\n .trim();\n // Accept either local TTFs OR runtime-embedded Google/Fontshare families\n if (!isFontAvailable(clean) && !isFamilyEmbedded(clean)) continue;\n\n const weightRaw = resolveInheritedValue(el, 'font-weight') || '400';\n const styleRaw = resolveInheritedValue(el, 'font-style') || 'normal';\n const weight = resolveWeightNum(weightRaw);\n const requested = resolveFontWeight(weight);\n const requestedItalic = /italic|oblique/i.test(styleRaw);\n const best = resolveBestRegisteredVariant(clean, requested, requestedItalic);\n if (!best) continue;\n const jsPdfName = getEmbeddedJsPDFFontName(clean, best.weight, best.italic);\n sourceMeta.set(el, { clean, requested, resolved: best.weight, isItalic: requestedItalic, actualItalic: best.italic, jsPdfName, inlineStyle, weight });\n }\n\n // Process deepest children first so tspans with real text are split before\n // their parent <text> gets rewritten to a jsPDF-only font name.\n const textEls = allTextEls.sort((a, b) => getDepth(b) - getDepth(a));\n\n for (const el of textEls) {\n if (!el.isConnected) continue;\n const meta = sourceMeta.get(el);\n if (!meta) continue;\n const { clean, requested, resolved, isItalic, actualItalic, jsPdfName, inlineStyle, weight } = meta;\n\n // Preserve original font metadata so downstream measurement (e.g. underline\n // width) can restore real fonts on a live clone. Without these data-source\n // attributes, getComputedTextLength/getStartPositionOfChar would measure\n // against the jsPDF-only font name (which the browser doesn't know) and\n // fall back to a default font, producing shortened underlines.\n el.setAttribute('data-source-font-family', clean);\n el.setAttribute('data-source-font-weight', String(requested));\n el.setAttribute('data-source-font-style', isItalic ? 'italic' : 'normal');\n if (requested >= 600 && resolved < 600) {\n const fill = resolveInheritedValue(el, 'fill') || readStyleToken(inlineStyle, 'fill') || '#000000';\n el.setAttribute('stroke', fill);\n el.setAttribute('stroke-width', String(requested === 700 ? 0.7 : 0.5));\n el.setAttribute('stroke-linejoin', 'round');\n }\n // Apply synthetic italic skew whenever the source asked for italic but\n // no italic font variant was embedded. We previously gated this on the\n // tspan having its OWN font-style:italic, but Fabric inherits italic\n // from the parent <text> for per-character styled runs and may not\n // re-emit `font-style: italic` on each tspan. Relaxing the gate lets\n // the synthetic skew apply to per-character italic runs too. The\n // tspan→<text> promotion post-pass (below) makes the skew actually\n // visible since SVG ignores `transform` on <tspan>.\n if (isItalic && !actualItalic) {\n applySyntheticItalicTransform(el);\n try {\n // eslint-disable-next-line no-console\n console.log('[Vector PDF][synthetic-italic]', {\n tag: el.tagName,\n family: clean,\n weight: requested,\n textPreview: (el.textContent || '').slice(0, 40),\n });\n } catch {}\n }\n\n // Check if this element's direct text content contains Devanagari\n const directText = Array.from(el.childNodes)\n .filter((n) => n.nodeType === 3) // text nodes only\n .map((n) => n.textContent || '')\n .join('');\n\n const hasDevanagari = containsDevanagari(directText);\n const mainSupportsChar = (char: string) => doesVariantSupportChar(clean, resolved, actualItalic, char);\n const hasSymbol = containsSymbol(directText, mainSupportsChar);\n\n if ((hasDevanagari || hasSymbol) && directText.length > 0) {\n // Split text nodes into script runs with appropriate fonts.\n // Triggers for Devanagari (Hindi etc.) AND for any non-Latin symbol\n // glyph (₹, €, ™, ★, arrows…) so we can swap to Noto Sans for chars\n // the active font doesn't include.\n const devanagariWeight = resolveFontWeight(weight);\n const devanagariJsPdfName = getEmbeddedJsPDFFontName(FONT_FALLBACK_DEVANAGARI, devanagariWeight);\n const symbolJsPdfName = isFontAvailable(FONT_FALLBACK_SYMBOLS)\n ? getEmbeddedJsPDFFontName(FONT_FALLBACK_SYMBOLS, 400)\n : jsPdfName;\n const mathJsPdfName = isFontAvailable(FONT_FALLBACK_MATH)\n ? getEmbeddedJsPDFFontName(FONT_FALLBACK_MATH, 400)\n : symbolJsPdfName;\n\n // Replace text nodes with tspan elements for each run\n const childNodes = Array.from(el.childNodes);\n for (const node of childNodes) {\n if (node.nodeType !== 3 || !node.textContent) continue;\n const runs = splitIntoRuns(node.textContent, mainSupportsChar);\n // Skip only when the single run is plain 'main' (Latin) — anything else\n // (symbol or devanagari) needs the fallback font swap.\n if (runs.length <= 1 && runs[0]?.runType === 'main') continue;\n\n const fragment = doc.createDocumentFragment();\n for (const run of runs) {\n const tspan = doc.createElementNS('http://www.w3.org/2000/svg', 'tspan');\n let runFont: string;\n if (run.runType === 'devanagari') {\n runFont = devanagariJsPdfName;\n } else if (run.runType === 'symbol') {\n runFont = symbolJsPdfName;\n } else if (run.runType === 'math') {\n runFont = mathJsPdfName;\n } else {\n runFont = jsPdfName;\n }\n tspan.setAttribute('font-family', runFont);\n tspan.setAttribute('font-weight', 'normal');\n tspan.setAttribute('font-style', 'normal');\n tspan.textContent = run.text;\n fragment.appendChild(tspan);\n }\n el.replaceChild(fragment, node);\n }\n\n // Set parent element font to main (for any inherited defaults)\n el.setAttribute('font-family', jsPdfName);\n el.setAttribute('font-weight', 'normal');\n el.setAttribute('font-style', 'normal');\n el.setAttribute('style', buildStyleString(inlineStyle, jsPdfName));\n } else {\n // No Devanagari — simple rewrite as before\n el.setAttribute('font-family', jsPdfName);\n el.setAttribute('font-weight', 'normal');\n el.setAttribute('font-style', 'normal');\n el.setAttribute('style', buildStyleString(inlineStyle, jsPdfName));\n }\n }\n\n // ── Rich-text positioned run post-pass ──\n // Fabric emits formatted text as many absolute-positioned <tspan x y> runs\n // inside one <text>. Browser/canvas preview honors those run positions, but\n // svg2pdf can still build a single text chunk and over-apply advances between\n // tspans, which shows up as the EC2-only \"gaps\" after rich-text segments.\n // Promote every explicitly positioned run to its own sibling <text> while\n // preserving the original parent transform. Text remains selectable, and PDF\n // placement is now driven by Fabric's exact x/y for each run.\n const SVG_NS = 'http://www.w3.org/2000/svg';\n const promotedPositionedRuns: Element[] = [];\n const positionedRunParents = Array.from(doc.querySelectorAll('text')).filter((textEl) => {\n const directTspans = Array.from(textEl.children).filter((child) => child.tagName.toLowerCase() === 'tspan');\n if (directTspans.length === 0) return false;\n const directText = Array.from(textEl.childNodes)\n .filter((node) => node.nodeType === 3)\n .map((node) => node.textContent || '')\n .join('');\n if (directText.trim()) return false;\n const hasTransformedRun = directTspans.some((tspan) => /skewX/i.test(tspan.getAttribute('transform') || ''));\n const allPositioned = directTspans.every((tspan) => tspan.hasAttribute('x') || tspan.hasAttribute('y'));\n return hasTransformedRun || (directTspans.length > 1 && allPositioned);\n });\n\n for (const parentText of positionedRunParents) {\n if (!parentText.parentNode) continue;\n const directTspans = Array.from(parentText.children).filter((child) => child.tagName.toLowerCase() === 'tspan');\n let parentTransform = '';\n const parentAttrs = Array.from(parentText.attributes).filter((attr) => {\n if (attr.name === 'transform') { parentTransform = attr.value; return false; }\n return true;\n });\n\n for (const tspan of directTspans) {\n const wrapper = doc.createElementNS(SVG_NS, 'text');\n for (const attr of parentAttrs) wrapper.setAttribute(attr.name, attr.value);\n const runTransform = tspan.getAttribute('transform') || '';\n const combined = [parentTransform, runTransform].filter(Boolean).join(' ');\n if (combined) wrapper.setAttribute('transform', combined);\n tspan.removeAttribute('transform');\n wrapper.appendChild(tspan);\n promotedPositionedRuns.push(wrapper);\n parentText.parentNode.insertBefore(wrapper, parentText);\n }\n\n parentText.parentNode.removeChild(parentText);\n }\n\n // svg2pdf.js still occasionally treats child <tspan x/y> as text-flow\n // continuations even after the parent <text> split, then adds its own glyph\n // advance on top of Fabric's absolute x/y. For promoted one-run text nodes,\n // move the run's absolute coordinates to the <text> itself and leave the\n // child <tspan> unpositioned. This is semantically identical in SVG, but it\n // forces svg2pdf to use Fabric's exact run anchor instead of reflowing gaps.\n for (const textEl of promotedPositionedRuns) {\n const onlyChild = Array.from(textEl.children).filter((child) => child.tagName.toLowerCase() === 'tspan');\n if (onlyChild.length !== 1) continue;\n const tspan = onlyChild[0];\n for (const attr of ['x', 'y', 'dx', 'dy']) {\n const value = tspan.getAttribute(attr);\n if (value == null) continue;\n textEl.setAttribute(attr, value);\n tspan.removeAttribute(attr);\n }\n }\n\n return new XMLSerializer().serializeToString(doc.documentElement);\n}\n\n// ─── Legacy API (kept for backward compat but no longer the primary path) ───\n\n/**\n * Extract all unique font-family values from SVG strings.\n */\nexport function extractFontFamiliesFromSvgs(svgs: string[]): Set<string> {\n const families = new Set<string>();\n const regex = /font-family[=:]\\s*[\"']?([^\"';},]+)/gi;\n for (const svg of svgs) {\n let m: RegExpExecArray | null;\n while ((m = regex.exec(svg)) !== null) {\n const raw = m[1].trim().split(',')[0].trim().replace(/^['\"]|['\"]$/g, '');\n if (raw && raw !== 'serif' && raw !== 'sans-serif' && raw !== 'monospace') {\n families.add(raw);\n }\n }\n }\n return families;\n}\n\n/**\n * Scan a LIVE SVG for every (family, weight, italic) tuple referenced by\n * <text>/<tspan> elements and embed any variant not already registered in\n * the active jsPDF instance via `embedFontWithGoogleFallback` (local TTF →\n * Fontshare → Google Fonts). Always pre-embeds Symbols / Math / Devanagari\n * fallbacks so per-character glyph fallback can resolve in svg2pdf.\n *\n * Mirrors `embedFontsForSvg` in src/pages/UsePackage.tsx (host vector PDF\n * pipeline). Without this pass, rich-text spans that introduce a new\n * (weight, italic) tuple — e.g. an inline bold/italic markdown run — never\n * get a registered jsPDF font and svg2pdf silently falls back to Helvetica,\n * producing the visible word-spacing gaps and \"wrong font on one element\"\n * symptoms we see on the EC2 server PDF.\n */\nexport async function embedFontVariantsFromSvg(\n pdf: jsPDF,\n svgStr: string,\n fontBaseUrl: string,\n): Promise<number> {\n const parser = new DOMParser();\n const doc = parser.parseFromString(svgStr, 'image/svg+xml');\n const textEls = Array.from(doc.querySelectorAll('text, tspan, textPath'));\n\n const readStyleToken = (style: string, prop: string): string | null => {\n const m = style.match(new RegExp(`${prop}\\\\s*:\\\\s*([^;]+)`, 'i'));\n return m?.[1]?.trim() || null;\n };\n const resolveInherited = (el: Element, attr: string, styleProp = attr): string | null => {\n let cur: Element | null = el;\n while (cur) {\n const a = cur.getAttribute(attr)?.trim();\n if (a) return a;\n const s = readStyleToken(cur.getAttribute('style') || '', styleProp);\n if (s) return s;\n cur = cur.parentElement;\n }\n return null;\n };\n const parseWeight = (raw: string): number => {\n const n = Number.parseInt(raw, 10);\n if (Number.isFinite(n)) return n;\n const s = raw.toLowerCase();\n if (/bold/.test(s)) return 700;\n if (/semi|demi/.test(s)) return 600;\n if (/medium/.test(s)) return 500;\n if (/light|thin/.test(s)) return 300;\n return 400;\n };\n\n const needed = new Map<string, { family: string; weight: number; italic: boolean }>();\n for (const el of textEls) {\n const rawFf = resolveInherited(el, 'font-family');\n if (!rawFf) continue;\n const family = rawFf.split(',')[0]?.replace(/['\"]/g, '').trim();\n if (!family) continue;\n const weight = resolveFontWeight(parseWeight(resolveInherited(el, 'font-weight') || '400'));\n const italic = /italic|oblique/i.test(resolveInherited(el, 'font-style') || 'normal');\n const key = `${family}\\u001F${weight}\\u001F${italic ? 'i' : 'n'}`;\n if (!needed.has(key)) needed.set(key, { family, weight, italic });\n }\n\n let embedded = 0;\n for (const { family, weight, italic } of needed.values()) {\n if (isVariantEmbedded(family, weight, italic)) continue;\n await embedFontWithGoogleFallback(pdf, family, weight, fontBaseUrl, italic);\n if (isVariantEmbedded(family, weight, italic)) embedded++;\n }\n\n // Pre-embed per-character fallback fonts (Symbols / Math / Devanagari).\n // The downstream `rewriteSvgFontsForJsPDF` splits text into tspans and\n // assigns these fallback families to runs containing glyphs the main font\n // lacks (≠ ≤ ≥ ≈ ∞ → ₹ €, Devanagari, etc.). If those fonts were never\n // registered into THIS jsPDF instance, svg2pdf falls back silently.\n const fallbacks: Array<{ family: string; weight: number }> = [\n { family: FONT_FALLBACK_SYMBOLS, weight: 400 },\n { family: FONT_FALLBACK_MATH, weight: 400 },\n ];\n for (const w of [300, 400, 500, 600, 700]) {\n fallbacks.push({ family: FONT_FALLBACK_DEVANAGARI, weight: w });\n }\n for (const { family, weight } of fallbacks) {\n if (isVariantEmbedded(family, weight, false)) continue;\n await embedFontWithGoogleFallback(pdf, family, weight, fontBaseUrl, false);\n if (isVariantEmbedded(family, weight, false)) embedded++;\n }\n\n // Italic + heavy-weight fallback: many families lack a real bold-italic\n // file. Pre-embed regular-weight italic so the rewriter can downgrade\n // weight (keeping italic glyphs) and apply synthetic bold via stroke.\n for (const { family, weight, italic } of needed.values()) {\n if (!italic) continue;\n if (!isVariantEmbedded(family, weight, false)) {\n await embedFontWithGoogleFallback(pdf, family, weight, fontBaseUrl, false);\n if (isVariantEmbedded(family, weight, false)) embedded++;\n }\n if (!isVariantEmbedded(family, 400, false)) {\n await embedFontWithGoogleFallback(pdf, family, 400, fontBaseUrl, false);\n if (isVariantEmbedded(family, 400, false)) embedded++;\n }\n if (weight <= 400) continue;\n if (isVariantEmbedded(family, 400, true)) continue;\n await embedFontWithGoogleFallback(pdf, family, 400, fontBaseUrl, true);\n if (isVariantEmbedded(family, 400, true)) embedded++;\n }\n\n console.log('[pdf-fonts] embedFontVariantsFromSvg', {\n requested: needed.size,\n newlyEmbedded: embedded,\n });\n return embedded;\n}\n\n/**\n * @deprecated Use embedFontsForConfig + rewriteSvgFontsForJsPDF instead.\n * Embed all required fonts into a jsPDF instance using the old approach.\n */\nexport async function embedFontsInPdf(\n pdf: jsPDF,\n fontFamilies: Set<string>,\n fontBaseUrl: string,\n): Promise<Set<string>> {\n const embedded = new Set<string>();\n const weights = [300, 400, 500, 600, 700] as const;\n const tasks: Promise<void>[] = [];\n\n // Always register fallback fonts used by rewriteSvgFontsForJsPDF for glyphs\n // that the selected font may not contain (₹, €, ™, arrows, Devanagari, etc.).\n fontFamilies.add(FONT_FALLBACK_SYMBOLS);\n fontFamilies.add(FONT_FALLBACK_DEVANAGARI);\n\n for (const family of fontFamilies) {\n if (isFontAvailable(family)) {\n for (const w of weights) {\n tasks.push(\n embedFont(pdf, family, w, fontBaseUrl).then((ok) => {\n if (ok) embedded.add(`${family}\\u001F${w}`);\n }),\n );\n tasks.push(\n embedFont(pdf, family, w, fontBaseUrl, true).then((ok) => {\n if (ok) embedded.add(`${family}\\u001F${w}i`);\n }),\n );\n }\n } else {\n // Try Google Fonts / Fontshare fallback so families like \"Rubik Maze\",\n // \"Satoshi\", \"Clash Display\" etc. still render in the vector PDF.\n // Embed regular + bold + italic + bold-italic so inline styling\n // (selectable-mode PDF) renders bold/italic/underline correctly.\n // Each fallback fetch is independent and tolerates missing variants.\n const variants: Array<{ w: number; italic: boolean }> = [\n { w: 400, italic: false },\n { w: 700, italic: false },\n { w: 400, italic: true },\n { w: 700, italic: true },\n ];\n for (const v of variants) {\n tasks.push(\n embedFontWithGoogleFallback(pdf, family, v.w, fontBaseUrl, v.italic).then((ok) => {\n if (ok) embedded.add(`${family}\\u001F${v.w}${v.italic ? 'i' : ''}`);\n else if (v.w === 400 && !v.italic) {\n console.warn(`[pdf-fonts] No TTF (local/Google/Fontshare) for \"${family}\" — will use Helvetica fallback`);\n }\n }),\n );\n }\n }\n }\n\n await Promise.all(tasks);\n console.log(`[pdf-fonts] Embedded ${embedded.size} font variants for ${fontFamilies.size} families`);\n return embedded;\n}\n","/**\n * Font Loader — Loads Google Fonts via CSS injection.\n * Framework-agnostic, works in any browser environment.\n */\n\nimport type { TemplateConfig } from './types';\nimport { parseTextMarkdown } from '@/lib/textMarkdown';\nimport { FONT_FILES, type FontWeightFiles } from './pdf-fonts';\n// Use the HOST app's unified font loader so the package preview (use-page)\n// has identical font coverage to the builder. The host loader handles:\n// - Local @font-face fonts (LOCAL_FONTS)\n// - Fontshare via EXTENDED_FONT_LIST (Satoshi, Clash Display, …)\n// - Google Fonts with progressive URL fallback (display/script families\n// like \"Frijole\" that 404 on multi-weight queries)\n// - Italic + multi-weight loading via `ital,wght@…` CSS2 syntax\n// Without this delegation the package was using a thinner CSS1 path that\n// silently skipped many display fonts on the use-page preview.\nimport { loadFont as hostLoadFont, LOCAL_FONTS as HOST_LOCAL_FONTS } from '@/lib/googleFonts';\n\n/**\n * Fontshare slug map — must mirror EXTENDED_FONT_LIST entries with source: 'fontshare'\n * in src/lib/googleFonts.ts. When a font name appears here we load via Fontshare's\n * CSS API instead of Google Fonts.\n */\nconst FONTSHARE_SLUGS: Record<string, string> = {\n 'Satoshi': 'satoshi',\n 'Cabinet Grotesk': 'cabinet-grotesk',\n 'Clash Display': 'clash-display',\n 'Clash Grotesk': 'clash-grotesk',\n 'General Sans': 'general-sans',\n 'Switzer': 'switzer',\n 'Supreme': 'supreme',\n 'Author': 'author',\n 'Boska': 'boska',\n 'Excon': 'excon',\n 'Khand': 'khand',\n 'Sentient': 'sentient',\n 'Synonym': 'synonym',\n 'Erode': 'erode',\n 'Ranade': 'ranade',\n 'Tanker': 'tanker',\n 'Zodiak': 'zodiak',\n 'Gambarino': 'gambarino',\n 'Melodrama': 'melodrama',\n 'Bespoke Serif': 'bespoke-serif',\n 'Bespoke Stencil': 'bespoke-stencil',\n 'Panchang': 'panchang',\n 'Quincy CF': 'quincy-cf',\n 'Pally': 'pally',\n 'Tabular': 'tabular',\n 'Sharpie': 'sharpie',\n 'Stardom': 'stardom',\n 'Rebond Grotesque': 'rebond-grotesque',\n 'Telma': 'telma',\n 'Nippo': 'nippo',\n};\n\n/**\n * Normalize a CSS font-family stack to the first Google-compatible family name.\n * e.g. `\"Roboto, sans-serif\"` → `\"Roboto\"`, `\"'Open Sans', Arial\"` → `\"Open Sans\"`\n */\nexport function normalizeFontFamily(fontStack: string): string {\n const first = fontStack.split(',')[0].trim();\n return first.replace(/^['\"]|['\"]$/g, '');\n}\n\nfunction appendStylesheet(url: string, rejectOnError = true): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = url;\n link.crossOrigin = 'anonymous';\n link.onload = () => resolve();\n link.onerror = () => rejectOnError ? reject(new Error(`Failed to load stylesheet: ${url}`)) : resolve();\n document.head.appendChild(link);\n });\n}\n\n/** Fonts already loaded in this session */\nconst loadedFonts = new Set<string>();\n/** Loading promises to deduplicate concurrent requests */\nconst loadingPromises = new Map<string, Promise<void>>();\nconst registeredLocalFontFaces = new Set<string>();\nconst registeredRemoteFontFaces = new Set<string>();\nconst remoteFontDataUriPromises = new Map<string, Promise<string | null>>();\n\n/**\n * Same-origin <style> tag mirroring every locally-registered @font-face rule.\n *\n * Why: when the EC2 harness (or any standalone consumer of this package) loads\n * fonts via `new FontFace(...)` + `document.fonts.add(...)`, those faces are\n * usable for live canvas/SVG measurement, but they DO NOT appear in\n * `document.styleSheets[*].cssRules`.\n *\n * The PDF shadow rasterizer (`pdf-export.ts > collectDocumentFontFaceCss`)\n * walks `document.styleSheets` to collect the `@font-face` rules, inlines the\n * `url(...)` payloads as base64 data URIs, and embeds them into the offscreen\n * blob: SVG used to rasterize text shadows. If the rules aren't visible there,\n * the offscreen renderer falls back to a system font and the shadow silhouette\n * drifts vs the foreground text. By mirroring every `new FontFace` we register\n * into a real same-origin `<style>` block, cssRules picks them up and the\n * shadow raster ends up using the same font metrics as the live canvas above\n * it — eliminating the client/server visual disparity.\n */\nlet localFontFaceStyleEl: HTMLStyleElement | null = null;\nfunction ensureLocalFontFaceStyle(): HTMLStyleElement | null {\n if (typeof document === 'undefined') return null;\n if (localFontFaceStyleEl && localFontFaceStyleEl.isConnected) return localFontFaceStyleEl;\n try {\n localFontFaceStyleEl = document.createElement('style');\n localFontFaceStyleEl.setAttribute('data-pixldocs-local-fontfaces', '1');\n document.head.appendChild(localFontFaceStyleEl);\n return localFontFaceStyleEl;\n } catch {\n return null;\n }\n}\nfunction appendLocalFontFaceRule(family: string, weight: number, style: 'normal' | 'italic', file: string): void {\n const styleEl = ensureLocalFontFaceStyle();\n if (!styleEl) return;\n const cssText =\n `@font-face{font-family:\"${family}\";` +\n `src:url(\"/fonts/${file}\");` +\n `font-weight:${weight};font-style:${style};font-display:swap;}\\n`;\n // Plain textContent append — same-origin, always parseable via cssRules.\n styleEl.appendChild(document.createTextNode(cssText));\n}\n\nfunction appendDataUriFontFaceRule(family: string, weight: number, style: 'normal' | 'italic', dataUri: string): void {\n const styleEl = ensureLocalFontFaceStyle();\n if (!styleEl) return;\n const cssText =\n `@font-face{font-family:\"${family}\";` +\n `src:url(\"${dataUri}\") format(\"truetype\");` +\n `font-weight:${weight};font-style:${style};font-display:swap;}\\n`;\n styleEl.appendChild(document.createTextNode(cssText));\n}\n\nfunction resolveHarnessFontProxyUrl(): string {\n try {\n const runtimeBase =\n (typeof window !== 'undefined' && ((window as any).__PIXLDOCS_SUPABASE_URL || (window as any).__CONFIG__?.supabaseUrl)) ||\n (typeof globalThis !== 'undefined' && ((globalThis as any).__PIXLDOCS_SUPABASE_URL || (globalThis as any).__CONFIG__?.supabaseUrl)) ||\n '';\n const base = String(runtimeBase || '').replace(/\\/$/, '');\n return base ? `${base}/functions/v1/font-proxy` : '';\n } catch {\n return '';\n }\n}\n\nfunction isEmbeddableTrueType(bytes: Uint8Array): boolean {\n if (bytes.length < 12) return false;\n const signature = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3]);\n return signature === '\\x00\\x01\\x00\\x00' || signature === 'true';\n}\n\nasync function arrayBufferToDataUri(buf: ArrayBuffer): Promise<string> {\n const blob = new Blob([buf], { type: 'font/ttf' });\n return await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(String(reader.result));\n reader.onerror = () => reject(reader.error || new Error('Failed to read font bytes'));\n reader.readAsDataURL(blob);\n });\n}\n\nasync function fetchFontProxyDataUri(\n family: string,\n weight: number,\n style: 'normal' | 'italic',\n source: 'google' | 'fontshare',\n): Promise<string | null> {\n const proxyUrl = resolveHarnessFontProxyUrl();\n if (!proxyUrl) return null;\n const key = `${source}|${family}|${weight}|${style}`;\n const existing = remoteFontDataUriPromises.get(key);\n if (existing) return existing;\n const promise = (async () => {\n try {\n const url = `${proxyUrl}?family=${encodeURIComponent(family)}&weight=${weight}&italic=${style === 'italic' ? 1 : 0}&source=${source}`;\n const res = await fetch(url, { credentials: 'omit' });\n if (!res.ok) return null;\n const contentType = res.headers.get('content-type') || '';\n if (/application\\/json/i.test(contentType)) return null;\n const buf = await res.arrayBuffer();\n const bytes = new Uint8Array(buf);\n if (!isEmbeddableTrueType(bytes)) return null;\n return await arrayBufferToDataUri(buf);\n } catch {\n return null;\n }\n })();\n remoteFontDataUriPromises.set(key, promise);\n return promise;\n}\n\nasync function registerRemoteFontFaceViaProxy(\n family: string,\n requestedWeight: number | string,\n styleRaw: string,\n): Promise<boolean> {\n if (typeof document === 'undefined' || typeof FontFace === 'undefined' || !document.fonts) return false;\n if (!resolveHarnessFontProxyUrl()) return false;\n const style: 'normal' | 'italic' = /italic|oblique/i.test(styleRaw || '') ? 'italic' : 'normal';\n const parsed = typeof requestedWeight === 'number' ? requestedWeight : Number.parseInt(String(requestedWeight || '400'), 10);\n const resolved = Number.isFinite(parsed)\n ? parsed <= 350 ? 300 : parsed <= 450 ? 400 : parsed <= 550 ? 500 : parsed <= 650 ? 600 : 700\n : 400;\n const weightLadder: number[] = [resolved];\n for (const w of [400, 500, 700, 600, 300]) if (!weightLadder.includes(w)) weightLadder.push(w);\n const sourceOrder: Array<'google' | 'fontshare'> = FONTSHARE_SLUGS[family]\n ? ['fontshare', 'google']\n : ['google', 'fontshare'];\n\n for (const actualWeight of weightLadder) {\n for (const source of sourceOrder) {\n const faceKey = `${family}|${actualWeight}|${style}|${source}`;\n if (registeredRemoteFontFaces.has(faceKey)) return true;\n const dataUri = await fetchFontProxyDataUri(family, actualWeight, style, source);\n if (!dataUri) continue;\n try {\n // Register only the real upstream weight. If a single-weight display\n // font (e.g. Frijole) is requested as 700 but only ships 400, the host\n // browser uses synthetic bold from the 400 face. Registering the same\n // regular bytes as an explicit 700 face disables that synthesis on EC2,\n // producing narrower lineWidths and center-anchor drift.\n const weightsToRegister = new Set<number>([actualWeight]);\n const requestedNum = Number.isFinite(parsed) ? Math.max(100, Math.min(900, parsed)) : 400;\n if (requestedNum === actualWeight) weightsToRegister.add(requestedNum);\n for (const w of weightsToRegister) {\n const aliasKey = `${family}|${w}|${style}|${source}`;\n if (registeredRemoteFontFaces.has(aliasKey)) continue;\n try {\n const face = new FontFace(family, `url(\"${dataUri}\")`, {\n weight: String(w),\n style,\n });\n await face.load();\n document.fonts.add(face);\n appendDataUriFontFaceRule(family, w, style, dataUri);\n registeredRemoteFontFaces.add(aliasKey);\n } catch {\n // Per-weight failure shouldn't block the others.\n }\n }\n return true;\n } catch {\n // Try the next source/weight; a failed FontFace should not block render.\n }\n }\n }\n return false;\n}\n\nconst LOCAL_FONT_FACE_VARIANTS: Array<{ key: keyof FontWeightFiles; weight: number; style: 'normal' | 'italic' }> = [\n { key: 'regular', weight: 400, style: 'normal' },\n { key: 'bold', weight: 700, style: 'normal' },\n { key: 'light', weight: 300, style: 'normal' },\n { key: 'medium', weight: 500, style: 'normal' },\n { key: 'semibold', weight: 600, style: 'normal' },\n { key: 'italic', weight: 400, style: 'italic' },\n { key: 'boldItalic', weight: 700, style: 'italic' },\n { key: 'lightItalic', weight: 300, style: 'italic' },\n { key: 'mediumItalic', weight: 500, style: 'italic' },\n { key: 'semiboldItalic', weight: 600, style: 'italic' },\n];\n\nasync function registerLocalFontFaces(fontFamily: string): Promise<void> {\n if (typeof document === 'undefined' || typeof FontFace === 'undefined' || !document.fonts) return;\n const files = FONT_FILES[fontFamily];\n if (!files) return;\n\n const loads: Promise<unknown>[] = [];\n for (const variant of LOCAL_FONT_FACE_VARIANTS) {\n const file = files[variant.key];\n if (!file) continue;\n const faceKey = `${fontFamily}|${variant.weight}|${variant.style}|${file}`;\n if (registeredLocalFontFaces.has(faceKey)) continue;\n registeredLocalFontFaces.add(faceKey);\n try {\n const face = new FontFace(fontFamily, `url(\"/fonts/${file}\")`, {\n weight: String(variant.weight),\n style: variant.style,\n });\n document.fonts.add(face);\n // Mirror this face into a real same-origin <style> so the PDF shadow\n // rasterizer (which scans document.styleSheets) can see the @font-face\n // and inline the payload as a data URI. Without this, the offscreen\n // shadow raster falls back to a system font on EC2 → silhouette drift.\n appendLocalFontFaceRule(fontFamily, variant.weight, variant.style, file);\n loads.push(face.load().catch(() => undefined));\n } catch {\n // If FontFace construction fails, leave the browser fallback in place.\n }\n }\n if (loads.length > 0) await Promise.race([\n Promise.all(loads).then(() => undefined),\n new Promise<void>((resolve) => setTimeout(resolve, 2500)),\n ]);\n}\n\nfunction withTimeout<T>(promise: Promise<T>, timeoutMs = 4000): Promise<T | void> {\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n return Promise.race([\n promise,\n new Promise<void>((resolve) => {\n timeoutId = setTimeout(resolve, timeoutMs);\n }),\n ]).finally(() => {\n if (timeoutId) clearTimeout(timeoutId);\n });\n}\n\n/**\n * Load a Google Font by injecting a <link> stylesheet.\n * Resolves when the font is ready for use.\n */\nexport async function loadGoogleFontCSS(rawFontFamily: string): Promise<void> {\n if (!rawFontFamily || typeof document === 'undefined') return;\n // Normalize font stacks like \"Roboto, sans-serif\" → \"Roboto\"\n const fontFamily = normalizeFontFamily(rawFontFamily);\n if (!fontFamily) return;\n if (loadedFonts.has(fontFamily)) return;\n\n const existing = loadingPromises.get(fontFamily);\n if (existing) return existing;\n\n const promise = (async () => {\n try {\n // Local fonts are already registered via @font-face in the host's\n // CSS bundle in the app, but the standalone EC2 harness loads only the\n // package browser bundle. Register the same local TTF faces here too so\n // Fabric measures with the real font instead of a system fallback.\n if (HOST_LOCAL_FONTS.has(fontFamily)) {\n await registerLocalFontFaces(fontFamily);\n loadedFonts.add(fontFamily);\n return;\n }\n // Delegate to the host loader. It internally dispatches to:\n // - Fontshare via EXTENDED_FONT_LIST (covers Satoshi, Excon, …)\n // - Google Fonts with progressive URL fallback (display fonts)\n // and loads italic variants via the combined `ital,wght@…` URL.\n await withTimeout(hostLoadFont(fontFamily), 4000);\n loadedFonts.add(fontFamily);\n } catch (e) {\n console.warn(`[@pixldocs/canvas-renderer] Font load failed: ${fontFamily}`, e);\n // Don't throw — missing font shouldn't break rendering\n }\n })();\n\n loadingPromises.set(fontFamily, promise);\n await promise;\n loadingPromises.delete(fontFamily);\n}\n\n/**\n * Collect all font families used in a template config.\n */\nexport function collectFontsFromConfig(config: TemplateConfig): Set<string> {\n const fonts = new Set<string>();\n fonts.add('Open Sans'); // Default fallback\n fonts.add('Hind'); // Devanagari fallback — matches server\n\n function walk(nodes: any[]) {\n if (!nodes) return;\n for (const node of nodes) {\n if (node.fontFamily) fonts.add(normalizeFontFamily(node.fontFamily));\n if (node.smartProps?.fontFamily) fonts.add(normalizeFontFamily(node.smartProps.fontFamily));\n // Collect from text styles array (Fabric textbox per-character styles)\n if (node.styles && Array.isArray(node.styles)) {\n for (const lineStyle of node.styles) {\n if (lineStyle && typeof lineStyle === 'object') {\n for (const charStyle of Object.values(lineStyle as Record<string, any>)) {\n if (charStyle?.fontFamily) fonts.add(normalizeFontFamily(charStyle.fontFamily));\n }\n }\n }\n }\n if (node.children) walk(node.children);\n }\n }\n\n for (const page of config.pages || []) {\n walk(page.children || []);\n }\n\n // Also collect fonts referenced in theme variables (e.g. fontFamily overrides)\n if (config.themeConfig?.variables) {\n for (const def of Object.values(config.themeConfig.variables)) {\n // Theme variables that look like font names (contain letters, no # prefix for colors)\n if (def.value && typeof def.value === 'string' && !def.value.startsWith('#') && !def.value.startsWith('rgb')) {\n // Check if label hints at font\n if (def.label && /font/i.test(def.label)) {\n fonts.add(normalizeFontFamily(def.value));\n }\n }\n }\n }\n\n return fonts;\n}\n\n/**\n * Walk a fully-resolved TemplateConfig and collect every unique\n * { fontFamily, fontWeight, fontStyle } tuple from all text nodes\n * (including clones, repeatable children, and per-character Fabric styles).\n */\nexport interface FontDescriptor {\n family: string;\n weight: number | string;\n style: string; // 'normal' | 'italic'\n}\n\nexport function collectFontDescriptorsFromConfig(\n config: TemplateConfig,\n includeCommonTextVariants = true,\n): FontDescriptor[] {\n const seen = new Set<string>();\n const descriptors: FontDescriptor[] = [];\n\n function add(family: string, weight?: number | string, style?: string) {\n const f = normalizeFontFamily(family);\n if (!f) return;\n const w = weight ?? 400;\n const s = style ?? 'normal';\n const key = `${f}|${w}|${s}`;\n if (seen.has(key)) return;\n seen.add(key);\n descriptors.push({ family: f, weight: w, style: s });\n }\n\n function walk(nodes: any[]) {\n if (!nodes) return;\n for (const node of nodes) {\n if (node.fontFamily) {\n add(node.fontFamily, node.fontWeight, node.fontStyle);\n // Also add common normal + italic variants for text nodes so the\n // package has the same coverage as server/PDF export. Inline markdown\n // may introduce `fontStyle: italic` and/or `fontWeight: 700` even when\n // the saved element itself is regular.\n if (includeCommonTextVariants && node.type === 'text') {\n for (const w of [300, 400, 500, 600, 700]) {\n add(node.fontFamily, w, node.fontStyle);\n add(node.fontFamily, w, 'italic');\n }\n }\n }\n if (node.formattingEnabled === true && node.fontFamily) {\n const parsed = parseTextMarkdown(String(node.text ?? ''));\n const parsedStyleEntries = Object.values(parsed.styles || {});\n for (const lineStyle of parsedStyleEntries) {\n if (lineStyle && typeof lineStyle === 'object') {\n for (const charStyle of Object.values(lineStyle as Record<string, any>)) {\n if (!charStyle || typeof charStyle !== 'object') continue;\n add(\n charStyle.fontFamily || node.fontFamily,\n charStyle.fontWeight ?? node.fontWeight,\n charStyle.fontStyle ?? node.fontStyle,\n );\n }\n }\n }\n }\n if (node.smartProps?.fontFamily) {\n add(node.smartProps.fontFamily, node.smartProps.fontWeight, node.smartProps.fontStyle);\n }\n // Per-character Fabric styles\n if (node.styles) {\n // Fabric v6 uses object-keyed styles { lineIndex: { charIndex: style } }\n // but some serialized configs use arrays. Handle both.\n const styleEntries: any[] = Array.isArray(node.styles)\n ? node.styles\n : Object.values(node.styles);\n for (const lineStyle of styleEntries) {\n if (lineStyle && typeof lineStyle === 'object') {\n for (const charStyle of Object.values(lineStyle as Record<string, any>)) {\n if (charStyle?.fontFamily) {\n add(charStyle.fontFamily, charStyle.fontWeight, charStyle.fontStyle);\n }\n }\n }\n }\n }\n if (node.children) walk(node.children);\n }\n }\n\n // Always include default\n add('Open Sans', 400, 'normal');\n // Always include Devanagari fallback — server always embeds Hind\n add('Hind', 400, 'normal');\n add('Hind', 700, 'normal');\n\n for (const page of config.pages || []) {\n walk(page.children || []);\n }\n\n // Theme font variables\n if (config.themeConfig?.variables) {\n for (const def of Object.values(config.themeConfig.variables)) {\n if (def.value && typeof def.value === 'string' && !def.value.startsWith('#') && !def.value.startsWith('rgb')) {\n if (def.label && /font/i.test(def.label)) {\n add(def.value);\n }\n }\n }\n }\n\n return descriptors;\n}\n\n/**\n * Start loading all fonts required by a fully-resolved TemplateConfig.\n *\n * This is the **single API** consumers (and the renderer internally) should\n * call to guarantee font parity with EC2 `/render-from-form`.\n *\n * It:\n * 1. Walks ALL text nodes (including clones/repeatables) collecting\n * fontFamily + fontWeight + fontStyle.\n * 2. Loads each unique family via Google Fonts CSS v1 (idempotent).\n * 3. Kicks off each weight+style combo via `document.fonts.load()` without\n * blocking render completion; late font load reflow handles final metrics.\n *\n * Idempotent — safe to call multiple times for the same config.\n */\nexport async function ensureFontsForResolvedConfig(config: TemplateConfig): Promise<void> {\n if (typeof document === 'undefined') return;\n\n const descriptors = collectFontDescriptorsFromConfig(config, false);\n // Unique families for stylesheet injection\n const families = new Set(descriptors.map(d => d.family));\n\n // 1. EC2/parity path: stylesheet <link> loading can be blocked by ORB/CORS in\n // headless Chrome for some remote display fonts (notably single-weight\n // Google/Fontshare families). When that happens, the visible Fabric canvas\n // may still look close, but SVG center-anchor baking and shadow rasterization\n // measure with fallback metrics. Register data-URI FontFace rules via the\n // font proxy so server measurement/raster sees the same real font family.\n const proxyOutcomes = await withTimeout(Promise.all(\n descriptors.map(async (d) => ({ family: d.family, ok: await registerRemoteFontFaceViaProxy(d.family, d.weight, d.style) })),\n ), 9000) as Array<{ family: string; ok: boolean }> | void;\n const proxyLoadedFamilies = new Set((proxyOutcomes || []).filter((r) => r.ok).map((r) => r.family));\n\n // 2. Inject local font faces and only fall back to external stylesheets for\n // remote families that the proxy could not register. This avoids CORS/ORB\n // races becoming the first measurement source on the server path.\n await withTimeout(Promise.all([...families].map((f) => {\n if (proxyLoadedFamilies.has(f)) {\n loadedFonts.add(f);\n return Promise.resolve();\n }\n return loadGoogleFontCSS(f);\n })), 3500);\n\n // 3. Nudge the browser to fetch each weight/style combo without waiting.\n if (document.fonts) {\n descriptors.forEach(d => {\n const stylePrefix = d.style === 'italic' ? 'italic ' : '';\n const weightStr = String(d.weight);\n const spec = `${stylePrefix}${weightStr} 16px \"${d.family}\"`;\n document.fonts.load(spec).catch(() => {\n // Swallow — font may not have this exact weight/style; browser will use closest match\n });\n });\n }\n}\n\n/**\n * Returns true when any text node in `config` uses\n * `overflowPolicy: 'auto-shrink'`. The synchronous shrink loop in\n * `createText` measures with whatever font Fabric can resolve at mount\n * time, so for these configs the consumer MUST block on real font load\n * before mounting (otherwise it shrinks against fallback metrics and\n * overflows once the real font swaps in).\n */\nexport function configHasAutoShrinkText(config: TemplateConfig | null | undefined): boolean {\n if (!config?.pages?.length) return false;\n const walk = (nodes: any[]): boolean => {\n for (const node of nodes || []) {\n if (!node) continue;\n if (node.type === 'text' && node.overflowPolicy === 'auto-shrink') return true;\n if (Array.isArray(node.children) && node.children.length && walk(node.children)) return true;\n }\n return false;\n };\n for (const page of config.pages) {\n if (walk(page.children || [])) return true;\n }\n return false;\n}\n\n/**\n * Block until the webfonts referenced by `config` have actually loaded\n * (or `maxWaitMs` elapses). Stronger than `ensureFontsForResolvedConfig`\n * which only fire-and-forget queues `document.fonts.load()`.\n *\n * Use this BEFORE mounting `PreviewCanvas` so the synchronous\n * `createText` auto-shrink loop measures against real font metrics\n * instead of system fallback ones (which are typically narrower → loop\n * decides \"fits, no shrink needed\" → text overflows once the real font\n * swaps in).\n */\nexport async function awaitFontsForConfig(\n config: TemplateConfig,\n maxWaitMs: number,\n): Promise<void> {\n if (typeof document === 'undefined' || !document.fonts) return;\n\n // Register CSS @font-face rules first, then wait for descriptor loads.\n await ensureFontsForResolvedConfig(config);\n\n const descriptors = collectFontDescriptorsFromConfig(config, false);\n if (descriptors.length === 0) return;\n\n // ── PARITY (v0.5.74) ──\n // The host app pre-warms fonts via `preloadAllFonts` long before any\n // canvas mounts, so its first paint always measures against real font\n // metrics. The package consumer (use-package page) only has THIS wait\n // — so we must give it enough time for the actual woff2 binary fetch\n // to complete, otherwise Fabric's synchronous Textbox `initDimensions`\n // measures with a system fallback (typically narrower for display\n // serifs like Ewert/Playfair → text fits on 1 line at the saved size)\n // and then the real font swaps in wider → overflow / 1-line layout\n // where the builder showed 2 lines.\n //\n // Strategy: actually AWAIT every (family, weight) descriptor's binary\n // load (no per-call race), capped by a generous overall budget. The\n // `document.fonts.load()` promise only resolves after the .woff2 has\n // been downloaded AND registered, so once these settle the next\n // synchronous Fabric measurement is guaranteed to use the real font.\n const overallBudget = Math.max(maxWaitMs, 5000);\n\n const loads = Promise.all(\n descriptors.map((d) => {\n const stylePrefix = d.style === 'italic' ? 'italic ' : '';\n const spec = `${stylePrefix}${d.weight} 16px \"${d.family}\"`;\n return document.fonts!.load(spec).catch(() => []);\n }),\n ).then(() => undefined);\n\n await Promise.race([\n loads,\n new Promise<void>((resolve) => setTimeout(resolve, overallBudget)),\n ]);\n\n // After per-descriptor loads, await `document.fonts.ready` to catch\n // any sibling FontFaces (e.g. late italic variants) the browser\n // started fetching as a side-effect of the descriptor loads above.\n await Promise.race([\n document.fonts.ready.catch(() => undefined).then(() => undefined),\n new Promise<void>((r) => setTimeout(r, 1500)),\n ]);\n\n // ── PARITY (v0.5.73) ──\n // `document.fonts.load(spec)` can resolve as soon as a matching FontFace\n // is *registered* — not necessarily when the binary .woff2 has been\n // fetched and parsed. On the local-package and EC2 paths this is\n // exactly the race that breaks textbox widths: the auto-shrink loop\n // in `createText` runs synchronously at mount time, measures with a\n // system fallback (e.g. Verdana Bold for Josefin Sans 700 → ~5–8%\n // wider glyphs), picks a font size, and locks in a maxLineWidth that\n // doesn't match the host (which has fonts already loaded via\n // `preloadAllFonts`).\n //\n // Fix: actively poll `document.fonts.check()` for every descriptor\n // until it returns true (binary actually applied) or budget runs out.\n // This brings the package + EC2 path into parity with the host's\n // pre-warmed font state.\n const checkSpecs: string[] = [];\n for (const d of descriptors) {\n const stylePrefix = d.style === 'italic' ? 'italic ' : '';\n checkSpecs.push(`${stylePrefix}${d.weight} 16px \"${d.family}\"`);\n }\n\n const startedAt = Date.now();\n const pollBudget = 2500;\n const allReady = () => {\n for (const spec of checkSpecs) {\n try {\n if (!document.fonts!.check(spec)) return false;\n } catch {\n // Some browsers throw on malformed specs — treat as ready so we\n // don't hang forever.\n }\n }\n return true;\n };\n\n while (!allReady() && Date.now() - startedAt < pollBudget) {\n await new Promise<void>((resolve) => setTimeout(resolve, 50));\n }\n\n // Two RAFs to flush any layout work the browser queued in response to\n // the newly loaded fonts before the consumer mounts the canvas.\n await new Promise<void>((resolve) =>\n requestAnimationFrame(() => requestAnimationFrame(() => resolve())),\n );\n}\n","/**\n * Data Resolver — Fetches template + form schema from database and applies\n * V2 sectionState to produce a fully resolved TemplateConfig ready for rendering.\n *\n * This mirrors the server's /render-from-form pipeline so external consumers\n * can pass the same minimal payload: { templateId, formSchemaId, sectionState }.\n */\n\nimport type { TemplateConfig, DynamicField } from './types';\nimport { applyThemeToConfig } from './theme';\nimport type { FormTemplateMappingEntry } from '@/lib/api';\nimport type { InferredSection, SectionFormState } from '@/lib/inferFormSchemaFromTemplate';\nimport type { FormConfig } from '@/lib/formsApi';\nimport {\n inferFormSchemaFromTemplate,\n formDefSectionsToInferred,\n flattenSectionStateToFormData,\n isDefaultDataV2,\n} from '@/lib/inferFormSchemaFromTemplate';\nimport { defaultSectionState } from '@/lib/inferFormSchemaFromTemplate';\nimport { applyFormDataToConfig } from '@/lib/applyFormDataToConfig';\nimport { ENTRY_ID_KEY, ENTRY_NAME_KEY } from '@/lib/repeatableEntryIds';\nimport { applyContentBoundsPagination } from '@/lib/layoutWithContentBounds';\nimport { baseId } from '@/lib/formSchema';\nimport { isGroup, isVerticalStackLayoutMode } from '@/types/editor';\nimport { awaitFontsForConfig, configHasAutoShrinkText } from './font-loader';\n\ntype FormDefField = {\n id: string;\n label: string;\n key: string;\n type: 'text' | 'textarea' | 'email' | 'tel' | 'url' | 'date' | 'number' | 'image' | 'color' | 'select' | 'toggle' | 'currency' | 'rating';\n placeholder?: string;\n options?: { value: string; label: string }[];\n order: number;\n width?: 'full' | 'half' | 'third';\n description?: string;\n};\n\ntype FormDefSection = {\n id: string;\n label: string;\n description?: string;\n order: number;\n fields: FormDefField[];\n repeatable?: boolean;\n minEntries?: number;\n maxEntries?: number;\n templateKeyPrefix?: string;\n children?: FormDefSection[];\n};\n\ntype FormDefRepeatablePage = {\n id: string;\n label: string;\n description?: string;\n order: number;\n templateKeyPrefix: string;\n fields: FormDefField[];\n minEntries?: number;\n maxEntries?: number;\n children?: FormDefSection[];\n};\n\ntype FormDefSchema = {\n sections: FormDefSection[];\n repeatablePages?: FormDefRepeatablePage[];\n formRenderPreset?: 'default' | 'compact' | 'cards' | 'minimal' | 'biodata';\n};\n\nasync function awaitFontsBeforeTextReflow(config: TemplateConfig): Promise<void> {\n if (typeof document === 'undefined' || !configHasAutoShrinkText(config)) return;\n try {\n await awaitFontsForConfig(config, 4000);\n } catch (error) {\n console.warn('[@pixldocs/canvas-renderer] Font wait before text reflow failed:', error);\n }\n}\n\n// ─── Public types ────────────────────────────────────────────────\n\nexport interface ResolveOptions {\n /** Template UUID */\n templateId: string;\n /** Optional flat formData (legacy, simple fields only) */\n formData?: Record<string, any>;\n /** Supabase project URL */\n supabaseUrl?: string;\n /** Supabase anon key */\n supabaseAnonKey?: string;\n /**\n * Optional prefetched template row from a trusted server. When provided\n * the resolver skips the REST fetch — useful for the EC2 v2 pipeline where\n * the server already has the row in memory.\n */\n prefetched?: {\n templateRow?: {\n id?: string;\n name?: string;\n price?: number;\n config: TemplateConfig;\n form_schema?: unknown;\n default_data?: unknown;\n };\n };\n}\n\n/** V2 resolution options — matches the server API payload */\nexport interface ResolveFromFormOptions {\n /** Template UUID */\n templateId: string;\n /**\n * Form schema UUID. Optional — omit for templates with manual `dynamicFields`\n * that are not bound to a saved form schema.\n */\n formSchemaId?: string;\n /**\n * V2 section state (same shape sent to /render-from-form). Optional when\n * `flatFormData` is provided (manual-fields path).\n */\n sectionState?: SectionFormState;\n /**\n * Flat key/value map of dynamic-field values, keyed by `dynamicField.id`.\n * Use this for manual-fields templates with no `formSchemaId` — values\n * are applied directly through `applyFormDataToConfig` without going\n * through the section-state flatten step.\n */\n flatFormData?: Record<string, unknown>;\n /** Optional theme variant ID (default: 'default') */\n themeId?: string;\n /** Supabase project URL */\n supabaseUrl?: string;\n /** Supabase anon key */\n supabaseAnonKey?: string;\n /** Optional prefetched rows from a trusted server so browser-side package resolution can skip REST fetches entirely. */\n prefetched?: {\n templateRow?: {\n id?: string;\n name?: string;\n price?: number;\n config: TemplateConfig;\n form_schema?: {\n repeatableSections?: { nodeId: string; label: string; minEntries?: number; maxEntries?: number; entryFilter?: { mode: 'all' | 'range'; range?: string } }[];\n repeatablePages?: unknown[];\n dynamicFields?: DynamicField[];\n fieldGroups?: any[];\n } | null;\n default_data?: unknown;\n };\n formSchemaRow?: {\n id?: string;\n schema: FormDefSchema;\n } | null;\n defaultForm?: {\n config: FormConfig;\n values: Record<string, any>;\n saved_data: Record<string, any>;\n } | null;\n };\n}\n\nexport interface ResolvedTemplate {\n config: TemplateConfig;\n templateName: string;\n templateId: string;\n /** Template price — 0 = free, >0 = paid (watermark applies) */\n price: number;\n}\n\nfunction repeatablePageToSection(page: FormDefRepeatablePage): FormDefSection {\n return {\n id: page.id,\n label: page.label,\n description: page.description,\n order: typeof page.order === 'number' ? page.order + 10000 : 10000,\n fields: page.fields,\n repeatable: true,\n minEntries: page.minEntries,\n maxEntries: page.maxEntries,\n templateKeyPrefix: page.templateKeyPrefix,\n children: page.children,\n };\n}\n\nfunction getRenderableFormSections(schema: FormDefSchema | null | undefined): FormDefSection[] {\n if (!schema) return [];\n const base = schema.sections ?? [];\n const pages = schema.repeatablePages ?? [];\n if (!pages.length) return base;\n return [...base, ...pages.map(repeatablePageToSection)];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction getRepeatableEntryMeta(entry: Record<string, unknown>, section: InferredSection): { id?: string; name?: string } {\n const entryNameKey = (section as { entryNameFieldKey?: string }).entryNameFieldKey;\n const nameCandidate =\n entry[ENTRY_NAME_KEY]\n ?? (entryNameKey ? entry[entryNameKey] : undefined)\n ?? entry.section_title\n ?? entry.label\n ?? entry.name;\n\n return {\n id: typeof entry[ENTRY_ID_KEY] === 'string' ? entry[ENTRY_ID_KEY] : undefined,\n name: typeof nameCandidate === 'string' ? nameCandidate : undefined,\n };\n}\n\nfunction extractSectionStateCandidate(values: unknown, sections: InferredSection[]): SectionFormState | null {\n if (!isRecord(values)) return null;\n const raw = isDefaultDataV2(values) && isRecord(values.sectionState) ? values.sectionState : values;\n const sectionIds = new Set(sections.map((section) => section.id));\n const looksLikeSectionState = Object.keys(raw).some((key) => sectionIds.has(key) || key.startsWith('section_'));\n return looksLikeSectionState ? (raw as SectionFormState) : null;\n}\n\nfunction mergeRepeatableEntryMeta(\n target: SectionFormState,\n metaSource: SectionFormState | null | undefined,\n sections: InferredSection[],\n): SectionFormState {\n if (!metaSource) return target;\n\n let changed = false;\n const next: SectionFormState = { ...target };\n const repeatableIds = new Set(sections.filter((section) => section.type === 'repeatable').map((section) => section.id));\n const isRepeatableStateKey = (key: string) => repeatableIds.has(key) || Array.from(repeatableIds).some((id) => key.endsWith(`_${id}`));\n\n for (const [key, targetEntries] of Object.entries(target)) {\n if (!isRepeatableStateKey(key) || !Array.isArray(targetEntries)) continue;\n const sourceEntries = metaSource[key];\n if (!Array.isArray(sourceEntries)) continue;\n\n const mergedEntries = targetEntries.map((entry, index) => {\n if (!isRecord(entry)) return entry;\n const sourceEntry = sourceEntries[index];\n if (!isRecord(sourceEntry)) return entry;\n\n const id = sourceEntry[ENTRY_ID_KEY];\n const name = sourceEntry[ENTRY_NAME_KEY];\n const additions: Record<string, string> = {};\n if (typeof id === 'string' && id.trim() && typeof entry[ENTRY_ID_KEY] !== 'string') additions[ENTRY_ID_KEY] = id;\n if (typeof name === 'string' && name.trim() && typeof entry[ENTRY_NAME_KEY] !== 'string') additions[ENTRY_NAME_KEY] = name;\n if (!Object.keys(additions).length) return entry;\n changed = true;\n return { ...entry, ...additions };\n });\n next[key] = mergedEntries as SectionFormState[string];\n }\n\n return changed ? next : target;\n}\n\nfunction buildRepeatablePagesInputForApply(\n schema: FormDefSchema | null | undefined,\n sectionState: Record<string, unknown> | null | undefined,\n): Array<{ pageId: string; templateKeyPrefix: string; entryCount?: number }> {\n if (!schema?.repeatablePages?.length) return [];\n const normalizeTemplateKeyPrefix = (prefix?: string): string => {\n if (!prefix || typeof prefix !== 'string') return '';\n return prefix.replace(/^field_/, '');\n };\n return schema.repeatablePages.map((page) => {\n const entries = sectionState?.[page.id];\n const minEntries = page.minEntries != null ? Math.max(0, page.minEntries) : 1;\n let entryCount: number | undefined;\n if (Array.isArray(entries)) {\n entryCount = minEntries === 0 ? entries.length : Math.max(1, entries.length);\n }\n return {\n pageId: page.id,\n templateKeyPrefix: normalizeTemplateKeyPrefix(page.templateKeyPrefix),\n entryCount,\n };\n });\n}\n\n// ─── Internal helpers ────────────────────────────────────────────\n\n/** Fetch a single row from a Supabase table via REST */\nasync function fetchRow(\n supabaseUrl: string,\n anonKey: string,\n table: string,\n id: string,\n): Promise<any> {\n const url = `${supabaseUrl}/rest/v1/${table}?id=eq.${id}&select=*`;\n const res = await fetch(url, {\n headers: {\n apikey: anonKey,\n Authorization: `Bearer ${anonKey}`,\n Accept: 'application/json',\n },\n });\n if (!res.ok) throw new Error(`Failed to fetch ${table}/${id}: ${res.status}`);\n const rows = await res.json();\n if (!rows.length) throw new Error(`${table}/${id} not found`);\n return rows[0];\n}\n\n/** Fetch default form for a form schema */\nasync function fetchDefaultForm(\n supabaseUrl: string,\n anonKey: string,\n formSchemaId: string,\n): Promise<{ config: FormConfig; values: Record<string, any>; saved_data: Record<string, any> } | null> {\n const url = `${supabaseUrl}/rest/v1/forms?form_schema_id=eq.${formSchemaId}&is_default=eq.true&select=config,values,saved_data&limit=1`;\n const res = await fetch(url, {\n headers: {\n apikey: anonKey,\n Authorization: `Bearer ${anonKey}`,\n Accept: 'application/json',\n },\n });\n if (!res.ok) return null;\n const rows = await res.json();\n return rows.length ? rows[0] : null;\n}\n\n// (Legacy `applyFormDataSimple` removed — `resolveTemplateData` now uses the\n// full `applyFormDataToConfig` pipeline so repeatable PAGES and SECTIONS clone\n// identically across editor, package, and EC2 server.)\n\n// ─── Legacy: fetch + flat apply with FULL repeatable support ─────\n//\n// Uses the same `applyFormDataToConfig` pipeline as the editor, so\n// repeatable PAGES (TemplateConfigPage.boundRepeatablePageId) and repeatable\n// SECTIONS (CanvasNode.repeatableSection) are cloned exactly the same way.\n//\n// We derive the inputs directly from the template (no separate FormSchema row\n// is required), supporting two layouts:\n// 1. `template.form_schema` JSONB embedded on the template row (legacy /\n// single-template authoring), or\n// 2. Plain template with `dynamicFields` + pages — we infer repeatable\n// pages by inspecting which field-id prefixes (`field_<prefix>_N_*`)\n// map to elements that live inside a `boundRepeatablePageId` page.\n\n/**\n * Build the `repeatablePagesFromSchema` input for `applyFormDataToConfig`\n * from a template config alone (no separate FormSchema row needed).\n *\n * For every page with `boundRepeatablePageId`, find the templateKeyPrefix:\n * - Prefer a match from `template.form_schema.repeatablePages[]`.\n * - Fallback: scan `dynamicFields` for ids matching `field_<prefix>_N_<rest>`\n * whose mappings target an element id that lives inside this page —\n * then `<prefix>` is our templateKeyPrefix.\n */\nfunction deriveRepeatablePagesFromTemplate(\n config: TemplateConfig,\n inlineFormSchema: any,\n formData?: Record<string, any>,\n): Array<{ pageId: string; templateKeyPrefix: string; entryCount?: number }> {\n if (!Array.isArray(config?.pages) || config.pages.length === 0) return [];\n\n const schemaPages: Array<{ id: string; templateKeyPrefix?: string; minEntries?: number }> | undefined =\n inlineFormSchema?.repeatablePages;\n\n const normalizeTemplateKeyPrefix = (prefix?: string): string | undefined => {\n if (!prefix || typeof prefix !== 'string') return undefined;\n return prefix.replace(/^field_/, '');\n };\n\n const inferEntryCount = (prefix: string, minEntries?: number): number | undefined => {\n const normalizedPrefix = normalizeTemplateKeyPrefix(prefix);\n if (!normalizedPrefix) return minEntries === 0 ? 0 : undefined;\n let maxIndex = 0;\n const keyPrefix = `field_${normalizedPrefix}_`;\n for (const key of Object.keys(formData ?? {})) {\n if (!key.startsWith(keyPrefix)) continue;\n const rest = key.slice(keyPrefix.length);\n const match = /^(\\d+)_/.exec(rest);\n if (match) maxIndex = Math.max(maxIndex, parseInt(match[1], 10));\n }\n if (maxIndex > 0) return maxIndex;\n return minEntries === 0 ? 0 : undefined;\n };\n\n // Collect element ids per page for prefix-inference fallback.\n const collectIds = (nodes: any[], out: Set<string>) => {\n for (const n of nodes ?? []) {\n if (n?.id) out.add(n.id);\n if (Array.isArray(n?.children)) collectIds(n.children, out);\n }\n };\n\n const dynamicFields = (config as any).dynamicFields as DynamicField[] | undefined;\n\n const out: Array<{ pageId: string; templateKeyPrefix: string; entryCount?: number }> = [];\n\n for (const page of config.pages as any[]) {\n const boundId: string | undefined = page?.boundRepeatablePageId;\n if (!boundId) continue;\n\n let templateKeyPrefix: string | undefined;\n\n // 1. Schema lookup\n let entryCount: number | undefined;\n\n if (Array.isArray(schemaPages)) {\n const found = schemaPages.find((rp) => rp?.id === boundId || rp?.id === page.id);\n templateKeyPrefix = normalizeTemplateKeyPrefix(found?.templateKeyPrefix);\n entryCount = inferEntryCount(templateKeyPrefix ?? found?.templateKeyPrefix ?? '', found?.minEntries);\n }\n\n // 2. Inference fallback from dynamicFields\n if (!templateKeyPrefix && Array.isArray(dynamicFields) && dynamicFields.length > 0) {\n const idsOnThisPage = new Set<string>();\n collectIds(page.children || [], idsOnThisPage);\n\n const prefixCounts = new Map<string, number>();\n for (const f of dynamicFields) {\n const m = /^field_(.+)_N_/.exec(f.id);\n if (!m) continue;\n const prefix = m[1];\n for (const map of f.mappings || []) {\n if (idsOnThisPage.has(map.elementId)) {\n prefixCounts.set(prefix, (prefixCounts.get(prefix) || 0) + 1);\n break;\n }\n }\n }\n // Pick the prefix with the most matches (handles overlapping cases gracefully).\n let best: string | undefined;\n let bestCount = 0;\n for (const [prefix, count] of prefixCounts) {\n if (count > bestCount) { best = prefix; bestCount = count; }\n }\n if (best) templateKeyPrefix = normalizeTemplateKeyPrefix(best);\n }\n\n if (templateKeyPrefix) {\n out.push({\n pageId: boundId,\n templateKeyPrefix,\n entryCount: entryCount ?? inferEntryCount(templateKeyPrefix),\n });\n }\n }\n\n return out;\n}\n\nexport async function resolveTemplateData(options: ResolveOptions): Promise<ResolvedTemplate> {\n const { templateId, formData, supabaseUrl, supabaseAnonKey, prefetched } = options;\n const template = prefetched?.templateRow\n ? prefetched.templateRow\n : await fetchRow(supabaseUrl as string, supabaseAnonKey as string, 'templates', templateId);\n let config = template.config as TemplateConfig;\n const inlineFormSchema = template.form_schema as any;\n const defaultData = template.default_data as Record<string, any> | null;\n\n // ── Enrich config the same way the V2 path does ──────────────────\n // 1. Copy dynamicFields / fieldGroups from form_schema when config has none\n if (inlineFormSchema && typeof inlineFormSchema === 'object') {\n if (!Array.isArray((config as any).dynamicFields) && Array.isArray(inlineFormSchema.dynamicFields)) {\n (config as any).dynamicFields = inlineFormSchema.dynamicFields;\n }\n if (!Array.isArray((config as any).fieldGroups) && Array.isArray(inlineFormSchema.fieldGroups)) {\n (config as any).fieldGroups = inlineFormSchema.fieldGroups;\n }\n }\n // 2. Normalize layout aliases ('stack' → 'vertical-stack')\n normalizeLayoutModes(config);\n // 3. Paint repeatableSection flags onto tree nodes from inline schema\n const repeatableSectionsInput: { nodeId: string; label: string; minEntries?: number; maxEntries?: number; entryFilter?: { mode: 'all' | 'range'; range?: string } }[] = [];\n if (Array.isArray(inlineFormSchema?.repeatableSections)) {\n for (const r of inlineFormSchema.repeatableSections) {\n if (r?.nodeId && r?.label) {\n repeatableSectionsInput.push({\n nodeId: r.nodeId,\n label: r.label,\n minEntries: r.minEntries,\n maxEntries: r.maxEntries,\n entryFilter: r.entryFilter,\n });\n }\n }\n if (repeatableSectionsInput.length > 0) {\n paintRepeatableSections(config, repeatableSectionsInput);\n }\n }\n\n // ── Merge defaultData into formData (formData wins on conflicts) ──\n const mergedFormData: Record<string, any> = {\n ...(defaultData && typeof defaultData === 'object' && !Array.isArray(defaultData) ? defaultData : {}),\n ...(formData ?? {}),\n };\n\n const dynamicFields = (config as any).dynamicFields as DynamicField[] | undefined;\n\n // If there are no dynamicFields at all, nothing to apply — return as-is.\n if (!Array.isArray(dynamicFields) || dynamicFields.length === 0) {\n return { config, templateName: template.name || 'Untitled', templateId, price: template.price ?? 0 };\n }\n\n // Build mappings array from dynamicFields[].mappings\n const mappings: FormTemplateMappingEntry[] = [];\n for (const f of dynamicFields) {\n for (const m of f.mappings || []) {\n mappings.push({\n field_key: f.id,\n element_id: m.elementId,\n target_property: (m as any).targetProperty || 'text',\n });\n }\n }\n\n // Derive repeatable pages from config + inline schema (with smart fallback)\n const repeatablePagesInput = deriveRepeatablePagesFromTemplate(config, inlineFormSchema, mergedFormData);\n\n await awaitFontsBeforeTextReflow(config);\n\n // Apply with FULL repeatable support (sections AND pages — same code path\n // the editor and PreviewCanvas use, so client-side preview, PNG and PDF\n // outputs all stay in 1:1 visual parity).\n const resolvedConfig = applyFormDataToConfig(\n config as any,\n mappings,\n mergedFormData,\n repeatableSectionsInput,\n undefined,\n undefined,\n undefined,\n repeatablePagesInput.length > 0 ? repeatablePagesInput : undefined,\n ) as unknown as TemplateConfig;\n\n return {\n config: resolvedConfig,\n templateName: template.name || 'Untitled',\n templateId,\n price: template.price ?? 0,\n };\n}\n\n// ─── V2 resolution: sectionState → fully resolved config ────────\n\n/**\n * Resolve a template using the V2 sectionState format.\n * This is the primary API for external consumers and matches the server's /render-from-form pipeline.\n */\nexport async function resolveFromForm(options: ResolveFromFormOptions): Promise<ResolvedTemplate> {\n const { templateId, formSchemaId, sectionState, flatFormData: directFlatFormData, themeId, supabaseUrl, supabaseAnonKey, prefetched } = options;\n\n // Manual-fields path: no formSchemaId means the template has manual `dynamicFields`\n // not bound to a saved form schema. Resolve directly through the legacy\n // `resolveTemplateData` pipeline, which calls `applyFormDataToConfig` with the\n // flat key/value map. This matches what the editor and PreviewCanvas do for\n // manual templates and ensures the EC2 v2 pipeline reflects user input.\n if (!formSchemaId) {\n return resolveTemplateData({\n templateId,\n formData: (directFlatFormData ?? (sectionState as Record<string, unknown> | undefined) ?? {}) as Record<string, any>,\n supabaseUrl: supabaseUrl as string,\n supabaseAnonKey: supabaseAnonKey as string,\n prefetched: prefetched?.templateRow ? { templateRow: prefetched.templateRow } : undefined,\n });\n }\n\n // Fetch only missing rows; trusted servers can provide prefetched rows so the\n // package remains the source of truth for resolution without needing browser REST auth.\n const [templateRow, formSchemaRow, defaultForm] = await Promise.all([\n prefetched?.templateRow\n ? Promise.resolve(prefetched.templateRow)\n : fetchRow(supabaseUrl, supabaseAnonKey, 'templates', templateId),\n prefetched?.formSchemaRow !== undefined\n ? Promise.resolve(prefetched.formSchemaRow)\n : fetchRow(supabaseUrl, supabaseAnonKey, 'form_schemas', formSchemaId),\n prefetched?.defaultForm !== undefined\n ? Promise.resolve(prefetched.defaultForm)\n : fetchDefaultForm(supabaseUrl, supabaseAnonKey, formSchemaId),\n ]);\n\n const templateConfig = templateRow.config as TemplateConfig;\n const templateFormSchema = templateRow.form_schema as {\n repeatableSections?: { nodeId: string; label: string; minEntries?: number; maxEntries?: number; entryFilter?: { mode: 'all' | 'range'; range?: string } }[];\n repeatablePages?: unknown[];\n dynamicFields?: DynamicField[];\n fieldGroups?: any[];\n } | null;\n const formSchema = formSchemaRow.schema as FormDefSchema | undefined;\n\n // ── Enrich config (mirrors rfEnrichTemplateConfigForServer on EC2) ──\n // 1. Copy dynamicFields / fieldGroups from form_schema when config has none\n if (templateFormSchema) {\n if (!Array.isArray(templateConfig.dynamicFields) && Array.isArray(templateFormSchema.dynamicFields)) {\n (templateConfig as any).dynamicFields = templateFormSchema.dynamicFields;\n }\n if (!Array.isArray(templateConfig.fieldGroups) && Array.isArray(templateFormSchema.fieldGroups)) {\n (templateConfig as any).fieldGroups = templateFormSchema.fieldGroups;\n }\n }\n // 2. Normalize layout mode aliases ('stack'/'stacked' → 'vertical-stack')\n normalizeLayoutModes(templateConfig);\n // 3. Paint repeatableSection flags onto tree nodes (mirrors rfPaintRepeatableSectionsIntoConfig)\n const repeatableFromSchema = templateFormSchema?.repeatableSections;\n if (repeatableFromSchema?.length && templateConfig.pages) {\n paintRepeatableSections(templateConfig, repeatableFromSchema);\n }\n\n // Build form schema sections → InferredSection[]\n const schemaSections = getRenderableFormSections(formSchema) as FormDefSection[];\n const repeatableNodeMap = new Map<string, string>();\n if (repeatableFromSchema) {\n for (const r of repeatableFromSchema) {\n // Match the client resolver: duplicate labels can exist for repeated\n // canvas occurrences, and the first occurrence is the filtered/bound one.\n // Overwriting here made EC2 resolve nested form keys against the later\n // unfiltered duplicate node, so #id-filtered children rendered empty.\n if (!repeatableNodeMap.has(r.label)) repeatableNodeMap.set(r.label, r.nodeId);\n const labelKey = r.label.trim().toLowerCase();\n if (!repeatableNodeMap.has(labelKey)) repeatableNodeMap.set(labelKey, r.nodeId);\n }\n }\n\n let inferredSections: InferredSection[];\n if (schemaSections?.length) {\n inferredSections = formDefSectionsToInferred(schemaSections, repeatableNodeMap);\n } else if (templateConfig.dynamicFields?.length) {\n const groups = templateConfig.fieldGroups || [];\n inferredSections = inferFormSchemaFromTemplate(\n templateConfig.dynamicFields as any[],\n groups as any[],\n templateConfig.pages?.length ? { pages: templateConfig.pages as any[] } : undefined,\n );\n } else {\n inferredSections = [];\n }\n\n const defaultFormMetaSectionState = extractSectionStateCandidate(defaultForm?.values, inferredSections)\n ?? extractSectionStateCandidate(defaultForm?.saved_data, inferredSections);\n\n // Apply default data first (from template default_data V2 or default form values)\n let mergedSectionState = { ...sectionState };\n const templateDefaultData = templateRow.default_data;\n if (templateDefaultData && isDefaultDataV2(templateDefaultData)) {\n // Merge: user sectionState overrides defaults\n const defaults = templateDefaultData.sectionState as SectionFormState;\n for (const key of Object.keys(defaults)) {\n if (!(key in mergedSectionState)) {\n mergedSectionState[key] = defaults[key];\n }\n }\n }\n // Client previews often pass template default_data as the visible values while\n // the saved default form carries the stable __entryId metadata. Borrow that\n // metadata so nested #id filters resolve in package preview exactly like the\n // in-app preview and PDF paths.\n mergedSectionState = mergeRepeatableEntryMeta(mergedSectionState, defaultFormMetaSectionState, inferredSections);\n\n // Flatten sectionState → flat formData\n const flatFormData = flattenSectionStateToFormData(mergedSectionState, inferredSections);\n\n // Build mappings array from dynamicFields (already enriched onto config above)\n const dynamicFields = (templateConfig.dynamicFields as DynamicField[] | undefined) || [];\n const mappings: FormTemplateMappingEntry[] = [];\n for (const field of dynamicFields) {\n if (field.mappings) {\n for (const m of field.mappings) {\n mappings.push({\n field_key: field.id,\n element_id: m.elementId,\n target_property: m.targetProperty,\n });\n }\n }\n }\n\n // Build repeatable section info\n const repeatableFromSchemaByBase = new Map(\n (repeatableFromSchema ?? []).map((r) => [baseId(r.nodeId), r])\n );\n const topLevelRepeatables = inferredSections\n .filter((s): s is Extract<typeof s, { type: 'repeatable' }> => s.type === 'repeatable' && !(s as any).parentId)\n .map((s) => {\n const entries = (mergedSectionState[s.id] ?? []) as Array<Record<string, string | string[]>>;\n const nodeId = (s as any).treeNodeId ?? s.id;\n const schemaRepeatable = repeatableFromSchemaByBase.get(baseId(nodeId));\n const entryMeta = entries.map((e) => getRepeatableEntryMeta(e as Record<string, unknown>, s));\n return { nodeId, label: s.label, entryCount: Math.max(1, entries.length), entryFilter: schemaRepeatable?.entryFilter, entryMeta };\n });\n const nestedRepeatables = inferredSections\n .filter((s): s is Extract<typeof s, { type: 'repeatable' }> => s.type === 'repeatable' && (s as any).parentId != null)\n .map((s) => {\n const nodeId = (s as any).treeNodeId ?? s.id;\n const schemaRepeatable = repeatableFromSchemaByBase.get(baseId(nodeId));\n // Build per-parent-index entry meta (required for #token matching of nested\n // repeatables — applyFormDataToConfig looks it up by `${parentBaseId}_${pi+1}_${childBaseId}`).\n const parentId = (s as any).parentId as string;\n const parentSection = inferredSections.find((ps) => ps.id === parentId);\n const parentNodeId = parentSection ? ((parentSection as any).treeNodeId ?? parentSection.id) : parentId;\n const parentEntries = (mergedSectionState[parentId] ?? []) as any[];\n const nestedEntryMeta: Record<string, Array<{ id?: string; name?: string }>> = {};\n const merged: Array<{ id?: string; name?: string }> = [];\n for (let pi = 0; pi < parentEntries.length; pi++) {\n const childEntries = (mergedSectionState[`${parentId}_${pi}_${s.id}`] ?? []) as any[];\n const meta = childEntries.map((e: any) => getRepeatableEntryMeta(e as Record<string, unknown>, s));\n nestedEntryMeta[`${baseId(parentNodeId)}_${pi + 1}_${baseId(nodeId)}`] = meta;\n merged.push(...meta);\n }\n return { nodeId, label: s.label, entryFilter: schemaRepeatable?.entryFilter, entryMeta: merged, nestedEntryMeta } as any;\n });\n const inferredRepeatableList = [...topLevelRepeatables, ...nestedRepeatables];\n const entryCountForLabel = (label: string): number | undefined => {\n const normalized = label.trim().toLowerCase();\n for (const item of inferredRepeatableList) {\n if (item.label.trim().toLowerCase() !== normalized) continue;\n const count = (item as { entryCount?: number }).entryCount;\n if (typeof count === 'number') return count;\n }\n return undefined;\n };\n const fallbackRepeatableList = (repeatableFromSchema ?? []).map((r) => ({\n nodeId: r.nodeId,\n label: r.label,\n entryFilter: r.entryFilter,\n entryCount: entryCountForLabel(r.label),\n }));\n const repeatableList = inferredRepeatableList.length > 0\n ? [\n ...inferredRepeatableList,\n ...fallbackRepeatableList.filter((fallback) =>\n !inferredRepeatableList.some((r) => baseId(r.nodeId) === baseId(fallback.nodeId))\n ),\n ]\n : fallbackRepeatableList;\n\n // Build nested entry counts\n const repeatableNestedEntryCounts: Record<string, number> = {};\n for (const s of inferredSections) {\n if (s.type !== 'repeatable') continue;\n const parentId = (s as any).parentId;\n if (parentId == null) continue;\n const parentEntries = (mergedSectionState[parentId] ?? []) as any[];\n const parentSection = inferredSections.find((ps) => ps.id === parentId);\n const parentTreeNodeId = parentSection ? ((parentSection as any).treeNodeId ?? parentSection.id) : parentId;\n const childTreeNodeId = (s as any).treeNodeId ?? s.id;\n for (let pi = 0; pi < parentEntries.length; pi++) {\n const compositeKey = `${parentId}_${pi}_${s.id}`;\n const entries = (mergedSectionState[compositeKey] ?? []) as any[];\n const nestedKey = `${baseId(parentTreeNodeId)}_${pi + 1}_${baseId(childTreeNodeId)}`;\n repeatableNestedEntryCounts[nestedKey] = Math.max(1, entries.length);\n }\n }\n\n // Build display format map from form config\n const displayFormatMap = new Map<string, string>();\n const formConfig = defaultForm?.config as FormConfig | undefined;\n if (formConfig?.sections) {\n const collectFormats = (sections: FormConfig['sections']) => {\n for (const s of sections) {\n if (s.fields) {\n for (const f of s.fields) {\n if (f.inputDisplay && f.inputDisplay !== 'text') {\n displayFormatMap.set(f.key, f.inputDisplay);\n }\n }\n }\n if (s.entryFieldConfigs) {\n for (const configs of Object.values(s.entryFieldConfigs)) {\n for (const f of configs) {\n if (f.inputDisplay && f.inputDisplay !== 'text') {\n displayFormatMap.set(f.key, f.inputDisplay);\n }\n }\n }\n }\n if (s.children) collectFormats(s.children);\n }\n };\n collectFormats(formConfig.sections);\n }\n\n await awaitFontsBeforeTextReflow(templateConfig);\n\n // Apply form data to config (handles repeatable sections, cloning, reflowing)\n let resolvedConfig = applyFormDataToConfig(\n templateConfig as any,\n mappings,\n flatFormData,\n repeatableList.length > 0 ? repeatableList : (repeatableFromSchema ?? []),\n undefined,\n Object.keys(repeatableNestedEntryCounts).length > 0 ? repeatableNestedEntryCounts : undefined,\n displayFormatMap.size > 0 ? displayFormatMap : undefined,\n buildRepeatablePagesInputForApply(formSchema, mergedSectionState as Record<string, unknown>),\n ) as unknown as TemplateConfig;\n\n // ── Apply theme ──────────────────────────────────────────────────\n // 1. Apply themeBindings (base theme variables → node properties).\n // Must run AFTER cloning so cloned repeatable nodes also get theme colors/fonts.\n if (resolvedConfig.themeConfig?.variables) {\n const baseOverrides: Record<string, string> = {};\n for (const [key, def] of Object.entries(resolvedConfig.themeConfig.variables)) {\n baseOverrides[key] = def.value;\n }\n resolvedConfig = applyThemeToConfig(resolvedConfig, baseOverrides);\n }\n\n // 2. Apply theme variant overrides (mirrors applyThemeToConfigServer on EC2)\n resolvedConfig = applyThemeVariantToConfig(resolvedConfig, templateConfig.themeConfig as any, themeId);\n\n // 3. Normalize config for EC2 parity (stackSpacing defaults, text height, overflowPolicy)\n normalizeConfigForEC2Parity(resolvedConfig);\n\n // Apply content bounds pagination (auto-paginate)\n resolvedConfig = applyContentBoundsPagination(resolvedConfig as any) as unknown as TemplateConfig;\n\n return {\n config: resolvedConfig,\n templateName: templateRow.name || 'Untitled',\n templateId,\n price: templateRow.price ?? 0,\n };\n}\n\n/** Flatten all nodes in a tree */\nfunction flattenAll(nodes: any[]): any[] {\n const result: any[] = [];\n for (const node of nodes) {\n result.push(node);\n if (node.children) result.push(...flattenAll(node.children));\n }\n return result;\n}\n\n// ─── Server-parity helpers ──────────────────────────────────────\n\n/**\n * Strip clone suffixes from an element ID for theme matching.\n * Mirrors themeBaseId on EC2 — more thorough than formSchema.baseId.\n */\nfunction themeBaseId(id: string | undefined): string {\n if (!id) return id ?? '';\n let out = id;\n out = out.replace(/_inner\\d+_\\d+_/g, '');\n out = out.replace(/_clone\\d+_/g, '');\n out = out.replace(/_clone_\\d+/g, '');\n while (/_\\d+$/.test(out)) out = out.replace(/_\\d+$/, '');\n return out;\n}\n\n/**\n * Apply theme variant values to a resolved config.\n * Mirrors applyThemeToConfigServer on EC2 — handles cloned elements via\n * __sourceId, __baseNodeId, __cloneIdMap, and themeBaseId matching.\n */\nfunction applyThemeVariantToConfig(\n config: TemplateConfig,\n themeConfig: any | undefined,\n themeId: string | undefined,\n): TemplateConfig {\n if (!themeConfig) return config;\n\n // For non-default variants, use variant values; for default, use property defaults for clones\n const variant = (themeId && themeId !== 'default')\n ? themeConfig.variants?.find((v: any) => v.id === themeId)\n : null;\n const shouldApplyDefaults = !variant && themeConfig.properties?.length;\n\n if (!variant && !shouldApplyDefaults) return config;\n if (!themeConfig.properties?.length) return config;\n\n const result = JSON.parse(JSON.stringify(config)) as any;\n const cloneIdMap = (config as any).__cloneIdMap || {};\n\n const pageElements = result.pages.map((page: any) => flattenAll(page.children || []));\n\n for (const prop of themeConfig.properties) {\n const lookupId = prop.linkedTo || prop.id;\n const value = variant ? variant.values?.[lookupId] : prop.defaultValue;\n if (value === undefined) continue;\n\n // Page background color\n if (prop.targetProperty === 'backgroundColor' && prop.elementId === '__pageBackground__') {\n result.pages.forEach((p: any) => { p.settings.backgroundColor = value; });\n continue;\n }\n\n // Page background gradient stops\n if (prop.targetProperty === 'backgroundGradient' && prop.elementId === '__pageBackground__' && prop.svgColorKey) {\n const stopMatch = prop.svgColorKey.match(/^stop:(\\d+)$/);\n if (stopMatch) {\n const stopIndex = parseInt(stopMatch[1], 10);\n result.pages.forEach((p: any) => {\n if (p.settings.backgroundGradient?.stops?.[stopIndex]) {\n p.settings.backgroundGradient = {\n ...p.settings.backgroundGradient,\n stops: p.settings.backgroundGradient.stops.map((s: any, i: number) =>\n i === stopIndex ? { ...s, color: value } : s\n ),\n };\n }\n });\n }\n continue;\n }\n\n // Build set of target element IDs (original + all clones) — mirrors server logic\n const propBase = themeBaseId(prop.elementId);\n const targetIds = new Set([prop.elementId, propBase]);\n\n // Add cloned element IDs from the clone map\n for (const [mapKey, mappedId] of Object.entries(cloneIdMap)) {\n if (mapKey.endsWith(`_${prop.elementId}`) || mapKey.endsWith(`_${propBase}`)) {\n targetIds.add(mappedId as string);\n }\n }\n\n // Element properties — match by id, themeBaseId, __sourceId, or __baseNodeId\n for (const els of pageElements) {\n for (const el of (els as any[])) {\n const elBase = themeBaseId(el.id);\n const sourceId = el.__sourceId;\n const sourceBase = sourceId ? themeBaseId(sourceId) : undefined;\n const cloneBase = el.__baseNodeId;\n const cloneBaseNorm = cloneBase ? themeBaseId(cloneBase) : undefined;\n\n const match =\n targetIds.has(el.id) ||\n targetIds.has(elBase) ||\n (sourceId ? targetIds.has(sourceId) : false) ||\n (sourceBase ? targetIds.has(sourceBase) : false) ||\n (cloneBase ? targetIds.has(cloneBase) : false) ||\n (cloneBaseNorm ? targetIds.has(cloneBaseNorm) : false);\n\n if (!match) continue;\n\n if (prop.svgColorKey && el.svgColorMap) {\n el.svgColorMap = { ...el.svgColorMap, [prop.svgColorKey]: value };\n } else {\n el[prop.targetProperty] = value;\n }\n }\n }\n }\n\n return result;\n}\n\n/**\n * Normalize config for EC2 rendering parity.\n * Mirrors rfNormalizeConfigForEC2Parity on EC2.\n */\nfunction normalizeConfigForEC2Parity(config: TemplateConfig): void {\n function walk(node: any) {\n if (node.layoutMode === 'stack' || node.layoutMode === 'stacked') {\n node.layoutMode = 'vertical-stack';\n }\n const layoutMode = String(node.layoutMode ?? '');\n const isStack = isVerticalStackLayoutMode(layoutMode as any) ||\n layoutMode === 'horizontal-stack' || layoutMode === 'horizontal-fill';\n if (isStack && node.stackSpacing == null) node.stackSpacing = 8;\n\n if (node.type === 'text') {\n const overflowPolicy = String(node.overflowPolicy ?? 'grow-and-push');\n // PARITY FIX (v2): mirror EC2 form-api setInTree — drop stale measured\n // height on bound text so vertical-stack reflow re-measures and siblings\n // shift correctly. Auto-shrink keeps explicit height as its ceiling.\n if (overflowPolicy !== 'auto-shrink') {\n delete node.height;\n }\n }\n\n if (Array.isArray(node.children)) {\n delete node.height;\n for (const child of node.children) walk(child);\n }\n }\n\n for (const page of (config as any).pages ?? []) {\n for (const child of page.children ?? []) walk(child);\n }\n}\n\n// ─── Server-parity helpers (mirror rfEnrichTemplateConfigForServer / rfNormalizeLayoutModes / rfPaintRepeatableSectionsIntoConfig) ──\n\n/**\n * Normalize legacy layout mode aliases to canonical 'vertical-stack'.\n * Mirrors rfNormalizeLayoutModes on the EC2 server.\n */\nfunction normalizeLayoutModes(config: TemplateConfig): void {\n function walk(node: any) {\n if (node.layoutMode === 'stack' || node.layoutMode === 'stacked') {\n node.layoutMode = 'vertical-stack';\n }\n if (Array.isArray(node.children)) {\n for (const child of node.children) walk(child);\n }\n }\n for (const page of config.pages ?? []) {\n if (page.children) {\n for (const child of page.children) walk(child);\n }\n }\n}\n\n/**\n * Paint repeatableSection flags onto tree nodes matching repeatable section nodeIds.\n * Mirrors rfPaintRepeatableSectionsIntoConfig on the EC2 server.\n * This is essential for applyFormDataToConfig to find and clone repeatable blocks.\n */\nfunction paintRepeatableSections(\n config: TemplateConfig,\n repeatableSections: Array<{ nodeId: string; label: string; minEntries?: number; maxEntries?: number; entryFilter?: { mode: 'all' | 'range'; range?: string } }>,\n): void {\n const pages = config.pages ?? [];\n\n // First strip any existing repeatableSection flags to avoid stale data\n function stripFlags(nodes: any[]) {\n for (const node of nodes) {\n delete node.repeatableSection;\n if (Array.isArray(node.children)) stripFlags(node.children);\n }\n }\n for (const page of pages) {\n if (page.children) stripFlags(page.children);\n }\n\n // Then paint fresh flags\n function setRepeatable(\n nodes: any[],\n nodeId: string,\n payload: { label: string; minEntries?: number; maxEntries?: number },\n ): boolean {\n for (const node of nodes) {\n const id = node.id as string | undefined;\n if (id && (id === nodeId || baseId(id) === baseId(nodeId))) {\n node.repeatableSection = payload;\n return true;\n }\n if (Array.isArray(node.children) && setRepeatable(node.children, nodeId, payload)) {\n return true;\n }\n }\n return false;\n }\n\n for (const section of repeatableSections) {\n const payload: any = { label: section.label };\n if (section.minEntries !== undefined) payload.minEntries = section.minEntries;\n if (section.maxEntries !== undefined) payload.maxEntries = section.maxEntries;\n if (section.entryFilter !== undefined) payload.entryFilter = section.entryFilter;\n for (const page of pages) {\n if (setRepeatable(page.children ?? [], section.nodeId, payload)) break;\n }\n }\n}\n\n// ─── Public API: getTemplateForm ─────────────────────────────────\n//\n// Returns the editable form (sections + initial values) attached to a\n// template — works for BOTH manual `dynamicFields` templates and templates\n// bound to a saved `form_schemas` row.\n//\n// External apps (e.g. PixlPost Creator) use this to build \"Edit template\"\n// UIs without re-implementing the schema-inference pipeline. Feed the\n// returned `initialSectionState` into your form, then pass the edited\n// state straight back to `renderer.renderFromForm({ templateId, formSchemaId,\n// sectionState })` for rendering.\n\nexport interface GetTemplateFormOptions {\n templateId: string;\n /** Optional — when omitted we read the template row and auto-detect from `template.form_schema_id`. */\n formSchemaId?: string;\n supabaseUrl: string;\n supabaseAnonKey: string;\n}\n\nexport interface TemplateForm {\n templateId: string;\n templateName: string;\n /** 0 = free, >0 = paid (watermark applies on rendered output). */\n price: number;\n /**\n * The bound form_schema id, if any. Pass this back as `formSchemaId` when\n * rendering. `null` indicates a manual-fields template — pass the\n * sectionState as-is to `renderFromForm` (without `formSchemaId`).\n */\n formSchemaId: string | null;\n /** Inferred section/field structure — drives the edit UI. */\n sections: InferredSection[];\n /**\n * Pre-seeded section state: defaults from the template's `default_data`\n * (V2) or saved default form values, falling back to empty values. Use\n * this as the initial value of your form state.\n */\n initialSectionState: SectionFormState;\n}\n\nexport async function getTemplateForm(options: GetTemplateFormOptions): Promise<TemplateForm> {\n const { templateId, supabaseUrl, supabaseAnonKey } = options;\n if (!supabaseUrl || !supabaseAnonKey) {\n throw new Error('[getTemplateForm] supabaseUrl and supabaseAnonKey are required');\n }\n\n const templateRow = await fetchRow(supabaseUrl, supabaseAnonKey, 'templates', templateId);\n const templateConfig = templateRow.config as TemplateConfig;\n const templateFormSchema = templateRow.form_schema as {\n repeatableSections?: { nodeId: string; label: string; minEntries?: number; maxEntries?: number }[];\n repeatablePages?: unknown[];\n dynamicFields?: DynamicField[];\n fieldGroups?: any[];\n } | null;\n\n // Auto-detect bound formSchemaId when not supplied.\n const boundFormSchemaId: string | null =\n options.formSchemaId\n ?? (typeof templateRow.form_schema_id === 'string' ? templateRow.form_schema_id : null);\n\n // Enrich config so dynamicFields are visible even when stored on form_schema JSONB.\n if (templateFormSchema) {\n if (!Array.isArray(templateConfig.dynamicFields) && Array.isArray(templateFormSchema.dynamicFields)) {\n (templateConfig as any).dynamicFields = templateFormSchema.dynamicFields;\n }\n if (!Array.isArray(templateConfig.fieldGroups) && Array.isArray(templateFormSchema.fieldGroups)) {\n (templateConfig as any).fieldGroups = templateFormSchema.fieldGroups;\n }\n }\n\n // Build inferred sections — schema-bound path first, manual fallback after.\n let formSchema: FormDefSchema | undefined;\n let defaultForm: { config: FormConfig; values: Record<string, any>; saved_data: Record<string, any> } | null = null;\n if (boundFormSchemaId) {\n const [schemaRow, defForm] = await Promise.all([\n fetchRow(supabaseUrl, supabaseAnonKey, 'form_schemas', boundFormSchemaId).catch(() => null),\n fetchDefaultForm(supabaseUrl, supabaseAnonKey, boundFormSchemaId),\n ]);\n formSchema = schemaRow?.schema as FormDefSchema | undefined;\n defaultForm = defForm;\n }\n\n const repeatableNodeMap = new Map<string, string>();\n const repeatableFromSchema = templateFormSchema?.repeatableSections;\n if (repeatableFromSchema) {\n for (const r of repeatableFromSchema) {\n if (!repeatableNodeMap.has(r.label)) repeatableNodeMap.set(r.label, r.nodeId);\n const labelKey = r.label.trim().toLowerCase();\n if (!repeatableNodeMap.has(labelKey)) repeatableNodeMap.set(labelKey, r.nodeId);\n }\n }\n\n const schemaSections = getRenderableFormSections(formSchema) as FormDefSection[];\n let sections: InferredSection[];\n if (schemaSections?.length) {\n sections = formDefSectionsToInferred(schemaSections, repeatableNodeMap);\n } else if (templateConfig.dynamicFields?.length) {\n sections = inferFormSchemaFromTemplate(\n templateConfig.dynamicFields as any[],\n (templateConfig.fieldGroups || []) as any[],\n templateConfig.pages?.length ? { pages: templateConfig.pages as any[] } : undefined,\n );\n } else {\n sections = [];\n }\n\n // Seed initial section state — empty defaults, then overlay default_data (V2)\n // or saved default form values so the edit form opens with real content.\n const seeded = defaultSectionState(sections);\n const templateDefaultData = templateRow.default_data;\n let overlay: SectionFormState | null = null;\n if (templateDefaultData && isDefaultDataV2(templateDefaultData)) {\n overlay = templateDefaultData.sectionState as SectionFormState;\n } else {\n overlay =\n extractSectionStateCandidate(defaultForm?.values, sections)\n ?? extractSectionStateCandidate(defaultForm?.saved_data, sections)\n ?? null;\n }\n const initialSectionState: SectionFormState = overlay\n ? { ...seeded, ...overlay }\n : seeded;\n\n return {\n templateId,\n templateName: templateRow.name || 'Untitled',\n price: templateRow.price ?? 0,\n formSchemaId: boundFormSchemaId,\n sections,\n initialSectionState,\n };\n}\n","/**\n * PixldocsPreview — React component for rendering Pixldocs templates with full parity.\n *\n * Supports two modes:\n * 1. Pass a pre-resolved `config` directly\n * 2. Pass `templateId` + `formSchemaId` + `sectionState` to auto-resolve from database\n */\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport type { TemplateConfig } from './types';\nimport type { SectionFormState } from '@/lib/inferFormSchemaFromTemplate';\nimport { setPackageApiUrl } from './shims/app-api';\nimport { PreviewCanvas as AppPreviewCanvas } from '../../../src/components/PreviewCanvas';\nimport { resolveFromForm } from './data-resolver';\nimport {\n awaitFontsForConfig,\n configHasAutoShrinkText,\n} from './font-loader';\n\nconst PREVIEW_DEBUG_PREFIX = '[canvas-renderer][preview-debug]';\n\n/**\n * Build a stable signature of every font family referenced in the config.\n * If this signature is unchanged between renders, no new @font-face needs to\n * load and we can keep the live canvas mounted (PageCanvas will diff text /\n * color / image / etc. in-place via its updateFabricObject path).\n *\n * This is what makes form-driven edits on /use-package \"preserve the canvas\":\n * only meaningful changes (new font family added) trigger the loading curtain.\n */\nfunction computeFontSignature(config: TemplateConfig | null | undefined): string {\n if (!config?.pages?.length) return '';\n const fams = new Set<string>();\n const walk = (nodes: any[]) => {\n for (const node of nodes || []) {\n if (node?.fontFamily) fams.add(String(node.fontFamily));\n if (node?.children?.length) walk(node.children);\n }\n };\n for (const page of config.pages) walk(page.children || []);\n return Array.from(fams).sort().join('|');\n}\n\nfunction countUnderlinedNodes(config: TemplateConfig | null | undefined): number {\n if (!config?.pages?.length) return 0;\n let count = 0;\n const walk = (nodes: any[]) => {\n for (const node of nodes || []) {\n if (node?.underline) count += 1;\n if (node?.children?.length) walk(node.children);\n }\n };\n for (const page of config.pages) walk(page.children || []);\n return count;\n}\n\nexport interface PixldocsPreviewBaseProps {\n /** Page index to render (default: 0) */\n pageIndex?: number;\n /** Zoom / scale factor (default: 1) */\n zoom?: number;\n /** When true, zoom is used as-is without auto-fit calculation */\n absoluteZoom?: boolean;\n /** Image proxy URL for CORS-safe external image loading */\n imageProxyUrl?: string;\n /** CSS class name for the outer container */\n className?: string;\n /** Inline styles for the outer container */\n style?: Record<string, string | number>;\n /** Optional dynamic field click callback */\n onDynamicFieldClick?: (elementId: string, fieldId: string) => void;\n /** Called when the canvas has fully loaded fonts and is ready to display */\n onReady?: () => void;\n /** Called when resolution or rendering fails */\n onError?: (error: Error) => void;\n /** Allow package previews to skip the blocking font-ready wait used by app preview */\n skipFontReadyWait?: boolean;\n}\n\n/** Mode 1: Pre-resolved config */\nexport interface PixldocsPreviewConfigProps extends PixldocsPreviewBaseProps {\n /** Template configuration object (pre-resolved) */\n config: TemplateConfig;\n templateId?: never;\n formSchemaId?: never;\n sectionState?: never;\n themeId?: never;\n supabaseUrl?: never;\n supabaseAnonKey?: never;\n}\n\n/** Mode 2: Auto-resolve from database */\nexport interface PixldocsPreviewResolveProps extends PixldocsPreviewBaseProps {\n config?: never;\n /** Template UUID to fetch and resolve */\n templateId: string;\n /** Form schema UUID */\n formSchemaId: string;\n /** V2 section state data */\n sectionState: SectionFormState;\n /** Optional theme variant ID */\n themeId?: string;\n /** Supabase project URL */\n supabaseUrl: string;\n /** Supabase anon key */\n supabaseAnonKey: string;\n}\n\nexport type PixldocsPreviewProps = PixldocsPreviewConfigProps | PixldocsPreviewResolveProps;\n\nexport function PixldocsPreview(props: PixldocsPreviewProps) {\n const {\n pageIndex = 0,\n zoom = 1,\n absoluteZoom = false,\n imageProxyUrl,\n className,\n style,\n onDynamicFieldClick,\n onReady,\n onError,\n // Default `false` so PageCanvas blocks textbox creation until the host\n // browser actually has the @font-face rules registered. This matters for\n // `overflowPolicy: 'auto-shrink'` text — `createText` runs the shrink\n // loop synchronously at mount time using whatever font metrics Fabric\n // can measure right then. If the real font hasn't loaded yet, Fabric\n // falls back to the system font (typically narrower), the shrink loop\n // decides \"fits, no shrink needed\", and when the real font finally\n // loads the text overflows the box.\n //\n // The renderer's imperative PNG/PDF paths (`renderPageViaPreviewCanvas`,\n // `captureSvgViaPreviewCanvas`) already pass `skipFontReadyWait: false`\n // for this exact reason — that's why the downloaded PDF was correct\n // while the on-screen preview wasn't.\n skipFontReadyWait = false,\n } = props;\n\n // Set image proxy URL\n useEffect(() => {\n setPackageApiUrl(imageProxyUrl);\n }, [imageProxyUrl]);\n\n // Handle auto-resolution mode\n const [resolvedConfig, setResolvedConfig] = useState<TemplateConfig | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [fontsReady, setFontsReady] = useState(false);\n const [canvasSettled, setCanvasSettled] = useState(false);\n // (stabilizationPass removed — see PARITY (v0.5.75) below)\n\n const isResolveMode = !('config' in props && props.config);\n\n useEffect(() => {\n if (!isResolveMode) {\n setResolvedConfig(null);\n setCanvasSettled(false);\n console.log(PREVIEW_DEBUG_PREFIX, 'config-mode active');\n return;\n }\n\n const p = props as PixldocsPreviewResolveProps;\n if (!p.templateId || !p.formSchemaId || !p.supabaseUrl || !p.supabaseAnonKey) return;\n\n let cancelled = false;\n setIsLoading(true);\n setFontsReady(false);\n setCanvasSettled(false);\n console.log(PREVIEW_DEBUG_PREFIX, 'resolve-start', {\n templateId: p.templateId,\n formSchemaId: p.formSchemaId,\n themeId: p.themeId ?? null,\n pageIndex,\n });\n\n resolveFromForm({\n templateId: p.templateId,\n formSchemaId: p.formSchemaId,\n sectionState: p.sectionState,\n themeId: p.themeId,\n supabaseUrl: p.supabaseUrl,\n supabaseAnonKey: p.supabaseAnonKey,\n })\n .then((resolved) => {\n if (!cancelled) {\n console.log(PREVIEW_DEBUG_PREFIX, 'resolve-done', {\n pages: resolved.config?.pages?.length ?? 0,\n underlinedNodes: countUnderlinedNodes(resolved.config),\n });\n setResolvedConfig(resolved.config);\n // Block on real font load before allowing first mount. Critical\n // for `overflowPolicy: 'auto-shrink'` text — see notes on\n // `awaitFontsForConfig`. Locally-installed builds were racing\n // here: the previous fire-and-forget `ensureFontsForResolvedConfig`\n // returned immediately, the canvas mounted with fallback metrics,\n // and the auto-shrink loop locked in a too-large font size.\n const hasAutoShrink = configHasAutoShrinkText(resolved.config);\n const waitMs = hasAutoShrink ? 4000 : 1800;\n awaitFontsForConfig(resolved.config, waitMs)\n .then(() => {\n if (!cancelled) {\n console.log(PREVIEW_DEBUG_PREFIX, 'resolve-mode fonts settled', { hasAutoShrink, waitMs });\n setFontsReady(true);\n setIsLoading(false);\n }\n })\n .catch((err) => {\n if (!cancelled) {\n console.warn(PREVIEW_DEBUG_PREFIX, 'resolve-mode font wait failed', err);\n setFontsReady(true);\n setIsLoading(false);\n }\n });\n }\n })\n .catch((err) => {\n if (!cancelled) {\n setIsLoading(false);\n console.warn(PREVIEW_DEBUG_PREFIX, 'resolve-error', err);\n onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n });\n\n return () => { cancelled = true; };\n }, [\n isResolveMode,\n // For resolve mode, re-resolve when these change\n isResolveMode ? (props as PixldocsPreviewResolveProps).templateId : undefined,\n isResolveMode ? (props as PixldocsPreviewResolveProps).formSchemaId : undefined,\n isResolveMode ? JSON.stringify((props as PixldocsPreviewResolveProps).sectionState) : undefined,\n isResolveMode ? (props as PixldocsPreviewResolveProps).themeId : undefined,\n ]);\n\n const config = isResolveMode ? resolvedConfig : (props as PixldocsPreviewConfigProps).config;\n\n // ── PARITY (v0.5.75) ──\n // Mount PreviewCanvas EXACTLY ONCE per pageIndex — matching the host's\n // direct <PreviewCanvas> path on /templates, /builder, and TemplateCard\n // (which all mount once and wrap correctly). The previous\n // `stabilizationPass` logic forced an unmount/remount on the first\n // canvas-ready event; that second mount re-ran the synchronous\n // `createText` textbox-width measurement against half-cleared Fabric\n // char-width caches and locked in a too-wide textbox (e.g. \"Deekshant\n // Malvi\" rendered on one line and overflowed off the canvas), while the\n // mount-once host paths produced the correct two-line wrap.\n // `awaitFontsForConfig` below already gates the first mount on real\n // font loads, so the remount was unnecessary AND the source of the\n // /use-package vs. /templates disparity.\n const previewKey = useMemo(() => `${pageIndex}`, [pageIndex]);\n\n // Font signature drives the \"should we show the loading curtain\" decision.\n // Pure data edits (text/color/image src) leave this string unchanged, so\n // the canvas stays mounted and PageCanvas patches Fabric objects in-place.\n const fontSignature = useMemo(() => computeFontSignature(config), [config]);\n\n // For pre-resolved config mode, load fonts when config changes\n useEffect(() => {\n if (isResolveMode) return;\n if (!config) {\n setFontsReady(false);\n setCanvasSettled(false);\n return;\n }\n // Surgical-update path: this effect only re-runs when `fontSignature`\n // changes (see deps below), so for pure data edits (text / color /\n // image src) we never get here — the canvas stays mounted and\n // PageCanvas's internal diff (updateFabricObject) patches Fabric\n // objects in-place. Only when a NEW font family appears do we hide\n // the canvas and wait for @font-face to load.\n setFontsReady(false);\n setCanvasSettled(false);\n let cancelled = false;\n const hasAutoShrink = configHasAutoShrinkText(config);\n const waitMs = hasAutoShrink ? 4000 : 1800;\n awaitFontsForConfig(config, waitMs)\n .then(() => {\n if (cancelled) return;\n console.log(PREVIEW_DEBUG_PREFIX, 'config-mode fonts settled', {\n pageIndex,\n hasAutoShrink,\n waitMs,\n underlinedNodes: countUnderlinedNodes(config),\n });\n setFontsReady(true);\n })\n .catch((err) => {\n if (cancelled) return;\n console.warn(PREVIEW_DEBUG_PREFIX, 'config-mode font wait failed', err);\n setFontsReady(true);\n });\n return () => { cancelled = true; };\n // We intentionally key off fontSignature (not the whole config object)\n // so that data-only edits do NOT re-await fonts or hide the canvas.\n }, [isResolveMode, fontSignature]);\n\n const handleCanvasReady = useCallback(() => {\n console.log(PREVIEW_DEBUG_PREFIX, 'canvas-ready', { pageIndex, action: 'settled' });\n setCanvasSettled(true);\n onReady?.();\n }, [onReady, pageIndex]);\n\n if (isLoading) {\n return (\n <div className={className} style={{ ...style as any, display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: 200 }}>\n <div style={{ color: '#888', fontSize: 14 }}>Loading preview...</div>\n </div>\n );\n }\n\n if (!config) return null;\n\n if (!fontsReady) {\n return (\n <div className={className} style={{ ...style as any, display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: 200 }}>\n <div style={{ color: '#888', fontSize: 14 }}>Loading preview...</div>\n </div>\n );\n }\n\n return (\n <div className={className} style={{ ...(style as any), position: 'relative' }}>\n <div style={{ visibility: canvasSettled ? 'visible' : 'hidden' }}>\n <AppPreviewCanvas\n key={previewKey}\n config={config as any}\n pageIndex={pageIndex}\n zoom={zoom}\n absoluteZoom={absoluteZoom}\n skipFontReadyWait={skipFontReadyWait}\n onDynamicFieldClick={onDynamicFieldClick}\n onReady={handleCanvasReady}\n />\n </div>\n {!canvasSettled && (\n <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: 200 }}>\n <div style={{ color: '#888', fontSize: 14 }}>Loading preview...</div>\n </div>\n )}\n </div>\n );\n}\n","/**\n * Shared \"Fabric canvas → SVG\" capture used by BOTH:\n * - the canvas-renderer package's `renderPageSvg` (client UsePackage path)\n * - the unified `exportMultiPagePdf` live-canvas branch (server EC2 path)\n *\n * Single source of truth so that bug-fixes (e.g. edge-fade bake, retina\n * neutralization, svg dimension normalization) automatically apply to both\n * client and server PDF exports — preserving 1:1 visual parity.\n */\nimport * as fabric from 'fabric';\n\nfunction normalizeSvgDimensions(svg: string, targetWidth: number, targetHeight: number): string {\n let normalized = svg;\n if (/\\bwidth=\"[^\"]*\"/i.test(normalized)) {\n normalized = normalized.replace(/(<svg[^>]*\\b)width=\"[^\"]*\"/i, `$1width=\"${targetWidth}\"`);\n } else {\n normalized = normalized.replace(/<svg\\b/i, `<svg width=\"${targetWidth}\"`);\n }\n if (/\\bheight=\"[^\"]*\"/i.test(normalized)) {\n normalized = normalized.replace(/(<svg[^>]*\\b)height=\"[^\"]*\"/i, `$1height=\"${targetHeight}\"`);\n } else {\n normalized = normalized.replace(/<svg\\b/i, `<svg height=\"${targetHeight}\"`);\n }\n const viewBox = `0 0 ${targetWidth} ${targetHeight}`;\n if (/\\bviewBox=\"[^\"]*\"/i.test(normalized)) {\n normalized = normalized.replace(/viewBox=\"[^\"]*\"/i, `viewBox=\"${viewBox}\"`);\n } else {\n normalized = normalized.replace(/<svg\\b/i, `<svg viewBox=\"${viewBox}\"`);\n }\n normalized = normalized.replace(/=\"undefined\"/g, '=\"0\"');\n normalized = normalized.replace(/=\"NaN\"/g, '=\"0\"');\n if (/\\bx=\"[^\"]*\"/i.test(normalized)) {\n normalized = normalized.replace(/(<svg[^>]*\\b)x=\"[^\"]*\"/i, '$1x=\"0\"');\n } else {\n normalized = normalized.replace(/<svg\\b/i, '<svg x=\"0\"');\n }\n if (/\\by=\"[^\"]*\"/i.test(normalized)) {\n normalized = normalized.replace(/(<svg[^>]*\\b)y=\"[^\"]*\"/i, '$1y=\"0\"');\n } else {\n normalized = normalized.replace(/<svg\\b/i, '<svg y=\"0\"');\n }\n normalized = normalized.replace(/\\bpreserveAspectRatio=\"[^\"]*\"/i, 'preserveAspectRatio=\"none\"');\n if (!/\\bpreserveAspectRatio=\"[^\"]*\"/i.test(normalized)) {\n normalized = normalized.replace(/<svg\\b/i, '<svg preserveAspectRatio=\"none\"');\n }\n return normalized;\n}\n\nfunction isTextboxLike(obj: any): boolean {\n return !!obj && (\n obj instanceof (fabric as any).Textbox ||\n obj.type === 'textbox' ||\n (Array.isArray(obj?._textLines) && typeof obj.getLineWidth === 'function')\n );\n}\n\nfunction stampFabricLineMetricsOnTextSvg(svg: string, obj: any): string {\n const lines = Array.isArray(obj?._textLines) ? obj._textLines : [];\n if (!lines.length || typeof obj?.getLineWidth !== 'function') return svg;\n const boxWidth = Number(obj.width ?? 0) || 0;\n let lineIndex = 0;\n return svg.replace(/<tspan\\b([^>]*)>/gi, (match, attrs: string) => {\n // Fabric emits one y-positioned <tspan> per visual textbox line. Rich-text\n // styling may add nested tspans; leave those alone so we don't corrupt spans.\n if (lineIndex >= lines.length || !/\\sy\\s*=/.test(attrs)) return match;\n let lineWidth = 0;\n let lineLeft = 0;\n try { lineWidth = Number(obj.getLineWidth(lineIndex) || 0); } catch { lineWidth = 0; }\n try { lineLeft = Number(obj._getLineLeftOffset?.(lineIndex) ?? 0); } catch { lineLeft = 0; }\n const lineStart = -boxWidth / 2 + lineLeft;\n lineIndex++;\n if (!Number.isFinite(lineWidth) || lineWidth <= 0 || !Number.isFinite(lineStart)) return match;\n const cleaned = attrs\n .replace(/\\sdata-pd-line-width=\"[^\"]*\"/gi, '')\n .replace(/\\sdata-pd-line-start=\"[^\"]*\"/gi, '');\n return `<tspan${cleaned} data-pd-line-width=\"${Number(lineWidth.toFixed(3))}\" data-pd-line-start=\"${Number(lineStart.toFixed(3))}\">`;\n });\n}\n\n/**\n * Capture `fabricInstance` as a clean SVG string suitable for svg2pdf.\n *\n * Steps performed (must stay identical for client/server parity):\n * 1. Snapshot canvas state (VPT, svgViewportTransformation, retina, dims).\n * 2. Reset VPT to identity, disable svgViewportTransformation + retina,\n * and force logical page dimensions.\n * 3. Bake edge-fade groups (`__edgeFadeRenderConfig`, etc.) into flat\n * FabricImage replacements via `toCanvasElement` so the fade gradient\n * ends up as pixels in the SVG instead of being lost (Fabric's toSVG\n * never invokes the `drawObject` override that paints the fade).\n * 4. Call `fabricInstance.toSVG()`.\n * 5. Normalize the root <svg> attributes (width/height/viewBox/x/y/par).\n * 6. Restore originals and snapshot.\n */\nexport function captureFabricCanvasSvgForPdf(\n fabricInstance: any,\n canvasWidth: number,\n canvasHeight: number,\n): string {\n const prevVPT = fabricInstance.viewportTransform ? [...fabricInstance.viewportTransform] : undefined;\n const prevSvgVPT = fabricInstance.svgViewportTransformation;\n const prevRetina = fabricInstance.enableRetinaScaling;\n const prevWidth = fabricInstance.width;\n const prevHeight = fabricInstance.height;\n\n fabricInstance.viewportTransform = [1, 0, 0, 1, 0, 0];\n fabricInstance.svgViewportTransformation = false;\n fabricInstance.enableRetinaScaling = false;\n try {\n fabricInstance.setDimensions(\n { width: canvasWidth, height: canvasHeight },\n { cssOnly: false, backstoreOnly: false },\n );\n } catch {}\n\n const textSvgPatchRecords: Array<{ obj: any; originalToSVG: any }> = [];\n try {\n const visit = (obj: any) => {\n if (!obj) return;\n if (isTextboxLike(obj) && typeof obj.toSVG === 'function') {\n const originalToSVG = obj.toSVG.bind(obj);\n obj.toSVG = (reviver?: (markup: string) => string) =>\n stampFabricLineMetricsOnTextSvg(originalToSVG(reviver), obj);\n textSvgPatchRecords.push({ obj, originalToSVG });\n }\n const children = Array.isArray(obj?._objects) ? obj._objects : [];\n for (const child of children) visit(child);\n };\n for (const obj of fabricInstance.getObjects().slice()) visit(obj);\n } catch (e) {\n console.warn('[canvas-svg-capture][textMetrics] patch pass error:', e);\n }\n\n const fadeBakeRecords: Array<{\n original: any;\n replacement: any;\n prevExclude: boolean | undefined;\n insertIndex: number;\n }> = [];\n\n try {\n const objs = fabricInstance.getObjects().slice();\n for (const obj of objs) {\n // Cross-realm safe group check: the canvas-renderer package and the host\n // app may bundle separate fabric copies, so `instanceof fabric.Group`\n // can return false for real groups. Use property-shape detection.\n const isGroupLike =\n obj instanceof (fabric as any).Group ||\n obj?.type === 'group' ||\n Array.isArray(obj?._objects);\n const isFadedCropGroup =\n isGroupLike &&\n (Boolean(obj.__edgeFadeRenderConfig) ||\n Boolean(obj.__edgeFadeKey) ||\n Boolean(obj.__edgeFadeInputKey));\n if (!isFadedCropGroup) continue;\n try {\n const baked: HTMLCanvasElement = obj.toCanvasElement({\n multiplier: 2,\n enableRetinaScaling: false,\n });\n const rect = obj.getBoundingRect();\n const replacement = new (fabric as any).FabricImage(baked, {\n left: rect.left,\n top: rect.top,\n originX: 'left',\n originY: 'top',\n scaleX: rect.width / baked.width,\n scaleY: rect.height / baked.height,\n selectable: false,\n evented: false,\n objectCaching: false,\n });\n const insertIndex = fabricInstance._objects.indexOf(obj);\n const prevExclude = obj.excludeFromExport;\n obj.excludeFromExport = true;\n if (insertIndex >= 0) {\n fabricInstance.insertAt(insertIndex + 1, replacement);\n } else {\n fabricInstance.add(replacement);\n }\n fadeBakeRecords.push({ original: obj, replacement, prevExclude, insertIndex });\n } catch (bakeErr) {\n console.warn('[canvas-svg-capture][edgeFade] bake failed:', bakeErr);\n }\n }\n if (fadeBakeRecords.length) {\n fabricInstance.renderAll();\n console.log(`[canvas-svg-capture][edgeFade] baked ${fadeBakeRecords.length} faded object(s)`);\n }\n } catch (e) {\n console.warn('[canvas-svg-capture][edgeFade] bake pass error:', e);\n }\n\n let svgString = '';\n try {\n const raw = fabricInstance.toSVG();\n svgString = normalizeSvgDimensions(raw, canvasWidth, canvasHeight);\n } finally {\n // Restore baked replacements\n for (const rec of fadeBakeRecords) {\n try {\n fabricInstance.remove(rec.replacement);\n rec.original.excludeFromExport = rec.prevExclude;\n } catch {}\n }\n for (const rec of textSvgPatchRecords) {\n try { rec.obj.toSVG = rec.originalToSVG; } catch {}\n }\n // Restore canvas state\n try {\n fabricInstance.enableRetinaScaling = prevRetina;\n fabricInstance.setDimensions(\n { width: prevWidth, height: prevHeight },\n { cssOnly: false, backstoreOnly: false },\n );\n } catch {}\n if (prevVPT) fabricInstance.viewportTransform = prevVPT;\n fabricInstance.svgViewportTransformation = prevSvgVPT;\n }\n return svgString;\n}","/**\n * Core Renderer — Uses the full PageCanvas/PreviewCanvas engine for 1:1 parity rendering.\n * Also provides a lightweight renderNodes fallback for simple templates.\n */\n\nimport { createRoot } from 'react-dom/client';\nimport { createElement } from 'react';\nimport * as fabric from 'fabric';\nimport type { TemplateConfig, CanvasNode } from './types';\nimport type { SectionFormState } from '@/lib/inferFormSchemaFromTemplate';\nimport { collectFontDescriptorsFromConfig, ensureFontsForResolvedConfig } from './font-loader';\nimport { resolveFromForm, resolveTemplateData } from './data-resolver';\nimport type { ResolveFromFormOptions } from './data-resolver';\nimport { clearMeasurementCache, getCanvasMeasuredTextboxLineWidths } from '@/lib/textMeasurement';\nimport { clearFabricCharCache } from '@/lib/fontLoader';\nimport { getObjectId } from '@/lib/fabricUtils';\nimport { captureFabricCanvasSvgForPdf } from '@/lib/canvasSvgCapture';\n\ndeclare const __PIXLDOCS_CANVAS_RENDERER_VERSION__: string | undefined;\ndeclare const __PIXLDOCS_CANVAS_RENDERER_DEPLOYMENT_MARKER__: string | undefined;\n\n/**\n * Package version banner. Bump alongside package.json so we can confirm\n * (via browser:log) that the deployed bundle matches the expected build.\n */\nconst resolvedPackageVersion = typeof __PIXLDOCS_CANVAS_RENDERER_VERSION__ !== 'undefined'\n ? __PIXLDOCS_CANVAS_RENDERER_VERSION__\n : '0.5.178';\n\nexport const PACKAGE_VERSION = resolvedPackageVersion;\nexport const DEPLOYMENT_VERSION_MARKER = typeof __PIXLDOCS_CANVAS_RENDERER_DEPLOYMENT_MARKER__ !== 'undefined'\n ? __PIXLDOCS_CANVAS_RENDERER_DEPLOYMENT_MARKER__\n : `__PIXLDOCS_CANVAS_RENDERER_VERSION__:${resolvedPackageVersion}`;\n\nconst roundParityValue = (value: unknown): unknown => {\n if (typeof value !== 'number') return value;\n return Number.isFinite(value) ? Number(value.toFixed(3)) : value;\n};\n\nfunction isolatePageForCapture(config: TemplateConfig, pageIndex: number): { config: TemplateConfig; pageId: string } {\n const capturePageId = `__pixldocs_capture_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}_${pageIndex}`;\n const cloned = JSON.parse(JSON.stringify(config)) as TemplateConfig;\n if (cloned.pages?.[pageIndex]) {\n cloned.pages[pageIndex].id = capturePageId;\n }\n return { config: cloned, pageId: capturePageId };\n}\n\nfunction logJsonLine(tag: string, payload: Record<string, unknown>): void {\n try {\n console.log(`${tag} ${JSON.stringify(payload, (_key, value) => roundParityValue(value))}`);\n } catch {\n console.log(tag, payload);\n }\n}\n\nfunction isFabricTextboxLike(obj: any): obj is fabric.Textbox {\n return !!obj && (\n obj instanceof fabric.Textbox ||\n obj.type === 'textbox' ||\n obj.type === 'text' ||\n (typeof obj.getLineWidth === 'function' && Array.isArray(obj._textLines))\n );\n}\n\nfunction isFabricGroupLike(obj: any): obj is fabric.Group {\n return !!obj && (\n obj instanceof fabric.Group ||\n obj.type === 'group' ||\n (Array.isArray(obj._objects) && typeof obj.getObjects === 'function')\n );\n}\n\n/**\n * Underline-fix monkey patch — installed once per process.\n *\n * Root cause (validated via browser:log on EC2):\n * For grouped Textbox objects whose container `width` (e.g. 317px) is wider\n * than the actual text content (`maxLineWidth` ~152px), Fabric's\n * `_renderTextDecoration` walks `__charBounds[i][j]` and accumulates\n * `kernedWidth`. If `__charBounds` was populated against a STALE text/style\n * state (or against the container width as a layout hint rather than the\n * measured glyphs), the per-char `kernedWidth` values sum to ~containerWidth\n * instead of ~textWidth — producing an underline that spans the full\n * textbox box.\n *\n * Fix (v0.5.40): Completely replace `_renderTextDecoration` with a\n * reimplementation that measures each rendered line from the actual canvas\n * font metrics (`measureText`) plus Fabric charSpacing. In practice this is\n * more reliable than Fabric's line-width/cache path for our off-screen PNG\n * capture flow, where textbox width is intentionally preserved for layout but\n * the underline must match only the visible glyph run.\n *\n * This patch is idempotent and safe — `getLineWidth` is what Fabric itself\n * calls when building `__lineWidths`, and the SVG path (PDF) already uses the\n * same measurements which is why PDF was correct.\n */\nlet __underlineFixInstalled = false;\nfunction installUnderlineFix(fab: typeof fabric) {\n if (__underlineFixInstalled) return;\n const TextProto: any = (fab as any).Text?.prototype;\n if (!TextProto || typeof TextProto._renderTextDecoration !== 'function') return;\n const original = TextProto._renderTextDecoration;\n const measureLineTextWidth = (obj: any, ctx: CanvasRenderingContext2D, lineIndex: number) => {\n const rawLine = obj._textLines?.[lineIndex];\n const lineText = Array.isArray(rawLine) ? rawLine.join('') : String(rawLine ?? '');\n if (!lineText) return 0;\n\n const fontSize = Number(obj.getValueOfPropertyAt?.(lineIndex, 0, 'fontSize') ?? obj.fontSize ?? 0);\n const fontStyle = String(obj.getValueOfPropertyAt?.(lineIndex, 0, 'fontStyle') ?? obj.fontStyle ?? 'normal');\n const fontWeight = String(obj.getValueOfPropertyAt?.(lineIndex, 0, 'fontWeight') ?? obj.fontWeight ?? '400');\n const fontFamily = String(obj.getValueOfPropertyAt?.(lineIndex, 0, 'fontFamily') ?? obj.fontFamily ?? 'sans-serif');\n const charSpacing = Number(obj.getValueOfPropertyAt?.(lineIndex, 0, 'charSpacing') ?? obj.charSpacing ?? 0);\n\n ctx.save();\n ctx.font = `${fontStyle} normal ${fontWeight} ${fontSize}px ${fontFamily}`;\n const measured = ctx.measureText(lineText).width;\n ctx.restore();\n\n const graphemeCount = Array.from(lineText).length;\n const spacingWidth = graphemeCount > 1 ? ((charSpacing / 1000) * fontSize) * (graphemeCount - 1) : 0;\n return Math.max(0, measured + spacingWidth);\n };\n\n TextProto._renderTextDecoration = function patchedRenderTextDecoration(ctx: any, type: string) {\n try {\n // Skip work if this object has no decoration of this kind anywhere.\n const hasOwn = !!this[type];\n const hasStyled = typeof this.styleHas === 'function' && this.styleHas(type);\n if (!hasOwn && !hasStyled) return;\n\n // IMPORTANT: this patch is global once the package renderer is initialized.\n // For markdown / rich text, underline and strike may be applied only to a\n // styled substring inside a Fabric Textbox. Fabric's native renderer handles\n // those per-character ranges correctly; our measured-line workaround is only\n // safe for object-level decorations. If we handle styled-only ranges here,\n // the visible Use Package preview changes from \"word underlined\" to\n // \"whole line underlined\" immediately after clicking Capture → Vector PDF.\n if (!hasOwn && hasStyled) {\n return original.call(this, ctx, type);\n }\n\n const lines = this._textLines;\n const offsets = this.offsets;\n if (!Array.isArray(lines) || !offsets) {\n return original.call(this, ctx, type);\n }\n\n const offsetY = offsets[type];\n const offsetAligner = type === 'linethrough' ? 0.5 : type === 'overline' ? 1 : 0;\n const leftOffset = this._getLeftOffset();\n let topOffset = this._getTopOffset();\n\n for (let i = 0, len = lines.length; i < len; i++) {\n const heightOfLine = this.getHeightOfLine(i);\n // Object-level decoration means every rendered line gets the decoration.\n // Styled-only partial ranges are delegated to Fabric above.\n const lineHas = !!this[type];\n if (!lineHas) {\n topOffset += heightOfLine;\n continue;\n }\n\n const fillStyle = this.getValueOfPropertyAt(i, 0, 'fill');\n const thickness = this.getValueOfPropertyAt(i, 0, 'textDecorationThickness');\n const charSize = this.getHeightOfChar(i, 0);\n const dy = this.getValueOfPropertyAt(i, 0, 'deltaY') || 0;\n const finalThickness = (this.fontSize * (thickness || 0)) / 1000;\n\n if (!fillStyle || !finalThickness) {\n topOffset += heightOfLine;\n continue;\n }\n\n const lineWidth = measureLineTextWidth(this, ctx, i);\n if (!lineWidth) {\n topOffset += heightOfLine;\n continue;\n }\n\n const availableWidth = Number(this.width ?? lineWidth);\n let lineLeftOffset = 0;\n const align = String(this.textAlign ?? 'left');\n if (align === 'center') lineLeftOffset = (availableWidth - lineWidth) / 2;\n else if (align === 'right' || align === 'end') lineLeftOffset = availableWidth - lineWidth;\n\n let drawStart = leftOffset + lineLeftOffset;\n if (this.direction === 'rtl') {\n drawStart = this.width - drawStart - lineWidth;\n }\n\n const maxHeight = heightOfLine / this.lineHeight;\n const top = topOffset + maxHeight * (1 - this._fontSizeFraction);\n\n ctx.fillStyle = fillStyle;\n ctx.fillRect(\n drawStart,\n top + offsetY * charSize + dy - offsetAligner * finalThickness,\n lineWidth,\n finalThickness\n );\n\n topOffset += heightOfLine;\n }\n\n // Match Fabric's behavior of clearing shadow after decoration.\n if (typeof this._removeShadow === 'function') {\n try { this._removeShadow(ctx); } catch { /* ignore */ }\n }\n } catch {\n // If anything goes sideways, fall back to Fabric's default impl\n // so we never break rendering entirely.\n try { return original.call(this, ctx, type); } catch { /* swallow */ }\n }\n };\n __underlineFixInstalled = true;\n // eslint-disable-next-line no-console\n console.log(`[canvas-renderer] underline-fix monkey patch installed (v${PACKAGE_VERSION})`);\n}\n\n/**\n * Apply Pixldocs Textbox prototype extensions for `minBoxHeight` and\n * `verticalAlign` so canvas-renderer (Use page / external embedders / PDF\n * export) renders text boxes with the same height + vertical alignment as\n * the editor preview. Mirrors src/lib/fabricTextboxExtensions.ts. Idempotent.\n */\nlet __textboxBoxExtensionsInstalled = false;\nfunction installTextboxBoxExtensions(fab: typeof fabric) {\n if (__textboxBoxExtensionsInstalled) return;\n const TextboxProto: any = (fab as any).Textbox?.prototype;\n if (!TextboxProto) return;\n if (TextboxProto.__pixldocsTextboxExtended) {\n __textboxBoxExtensionsInstalled = true;\n return;\n }\n if (typeof TextboxProto.calcTextHeight === 'function') {\n const origCalc = TextboxProto.calcTextHeight;\n TextboxProto.__pixldocsOrigCalcTextHeight = origCalc;\n TextboxProto.calcTextHeight = function (this: any) {\n const orig = origCalc.call(this);\n this._contentHeight = orig;\n const min = this.minBoxHeight || 0;\n return min > orig ? min : orig;\n };\n }\n if (typeof TextboxProto._getTopOffset === 'function') {\n const origTop = TextboxProto._getTopOffset;\n TextboxProto.__pixldocsOrigGetTopOffset = origTop;\n TextboxProto._getTopOffset = function (this: any) {\n const baseOffset = origTop.call(this);\n const valign = this.verticalAlign || 'top';\n if (valign === 'top') return baseOffset;\n const content = typeof this._contentHeight === 'number'\n ? this._contentHeight\n : (TextboxProto.__pixldocsOrigCalcTextHeight\n ? TextboxProto.__pixldocsOrigCalcTextHeight.call(this)\n : 0);\n const padding = (this.height || 0) - content;\n if (padding <= 0) return baseOffset;\n if (valign === 'middle') return baseOffset + padding / 2;\n if (valign === 'bottom') return baseOffset + padding;\n return baseOffset;\n };\n }\n // Override `_getSVGLeftTopOffsets` so Fabric's toSVG() (consumed by\n // svg2pdf for client-side PDF export) honors `verticalAlign`. Stock\n // Fabric hard-codes textTop = -height/2 here, bypassing _getTopOffset.\n if (typeof TextboxProto._getSVGLeftTopOffsets === 'function') {\n const origSvgOffsets = TextboxProto._getSVGLeftTopOffsets;\n TextboxProto.__pixldocsOrigGetSVGLeftTopOffsets = origSvgOffsets;\n TextboxProto._getSVGLeftTopOffsets = function (this: any) {\n const base = origSvgOffsets.call(this);\n const valign = this.verticalAlign || 'top';\n if (valign === 'top') return base;\n const content = typeof this._contentHeight === 'number'\n ? this._contentHeight\n : (TextboxProto.__pixldocsOrigCalcTextHeight\n ? TextboxProto.__pixldocsOrigCalcTextHeight.call(this)\n : 0);\n const padding = (this.height || 0) - content;\n if (padding <= 0) return base;\n const extra = valign === 'middle' ? padding / 2 : padding;\n return { ...base, textTop: base.textTop + extra };\n };\n }\n const stateProps: string[] | undefined = TextboxProto.stateProperties;\n if (Array.isArray(stateProps)) {\n if (!stateProps.includes('minBoxHeight')) stateProps.push('minBoxHeight');\n if (!stateProps.includes('verticalAlign')) stateProps.push('verticalAlign');\n }\n const cacheProps: string[] | undefined = TextboxProto.cacheProperties;\n if (Array.isArray(cacheProps)) {\n if (!cacheProps.includes('minBoxHeight')) cacheProps.push('minBoxHeight');\n if (!cacheProps.includes('verticalAlign')) cacheProps.push('verticalAlign');\n }\n TextboxProto.__pixldocsTextboxExtended = true;\n __textboxBoxExtensionsInstalled = true;\n}\n\n/**\n * Walk the resolved config and return true if ANY text node uses\n * `overflowPolicy: 'auto-shrink'`. Used to decide whether the headless\n * capture path should pay the extra cost of a stricter font-ready wait\n * (correctness > latency) and a post-mount remount-on-font-settle pass.\n */\nfunction configHasAutoShrinkText(config: TemplateConfig): boolean {\n if (!config?.pages?.length) return false;\n const walk = (nodes: any[]): boolean => {\n for (const node of nodes || []) {\n if (!node) continue;\n if (node.type === 'text' && node.overflowPolicy === 'auto-shrink') return true;\n if (Array.isArray(node.children) && node.children.length && walk(node.children)) return true;\n }\n return false;\n };\n for (const page of config.pages) {\n if (walk(page.children || [])) return true;\n }\n return false;\n}\n\nexport interface RendererConfig {\n /** Supabase project URL for fetching templates */\n supabaseUrl: string;\n /** Supabase anon key */\n supabaseAnonKey: string;\n /** Optional: image proxy URL for CORS-safe image loading */\n imageProxyUrl?: string;\n /** Optional: pixel ratio for high-DPI rendering (default: 2) */\n pixelRatio?: number;\n /**\n * Maximum time (ms) to wait for canvas image assets before bailing out.\n * Default: 15000. Lower this (e.g. 3000) for thumbnail/preview use-cases.\n */\n assetWaitTimeoutMs?: number;\n /**\n * Once the scene is settled (fabric+dom+canvas ready) and no new asset\n * progress has been seen for this many ms, resolve early even if the\n * expected counter hasn't matched. Default: 1500.\n */\n assetWaitEarlyExitMs?: number;\n /** Verbose asset-wait diagnostics. Default: false. */\n debug?: boolean;\n}\n\nexport interface RenderOptions {\n /** Page index to render (default: 0) */\n pageIndex?: number;\n /** Output format (default: 'png') */\n format?: 'png' | 'jpeg' | 'webp';\n /** Quality for jpeg/webp (0-1, default: 0.92) */\n quality?: number;\n /** Scale multiplier (default: 1) */\n scale?: number;\n /** Custom pixel ratio override */\n pixelRatio?: number;\n /**\n * If true, skip the blocking font-ready wait before mounting the headless\n * PreviewCanvas. Default: `false`. Setting this to `true` makes capture\n * faster but can cause `overflowPolicy: 'auto-shrink'` text to overflow\n * when the real webfont loads after auto-shrink has already measured\n * against fallback metrics.\n */\n skipFontReadyWait?: boolean;\n /**\n * Maximum time (ms) to wait for `document.fonts.load()` per descriptor\n * before mounting PreviewCanvas. Default: `4000` for configs that contain\n * any `auto-shrink` text (correctness matters), `1800` otherwise. Only\n * applies when `skipFontReadyWait` is false.\n */\n waitForFontsMs?: number;\n}\n\nexport interface RenderResult {\n /** Data URL of the rendered image */\n dataUrl: string;\n /** Width of the rendered image in CSS pixels */\n width: number;\n /** Height of the rendered image in CSS pixels */\n height: number;\n /** Actual pixel width (width * pixelRatio) */\n pixelWidth: number;\n /** Actual pixel height (height * pixelRatio) */\n pixelHeight: number;\n}\n\nexport interface SvgRenderResult {\n /** Raw SVG string from Fabric's toSVG() — clean, no viewport transforms */\n svg: string;\n /** Page width in CSS pixels */\n width: number;\n /** Page height in CSS pixels */\n height: number;\n /** Background color of the page */\n backgroundColor: string;\n /** Background gradient (if any) */\n backgroundGradient?: any;\n}\n\n/** Watermark appearance overrides (mirrors src/lib/canvasWatermark WatermarkOptions). */\nexport interface WatermarkOptions {\n text?: string;\n opacity?: number;\n fontSize?: number;\n angle?: number;\n}\n\n/** Options for renderFromForm — matches the server API payload */\nexport interface RenderFromFormOptions extends Omit<RenderOptions, 'pageIndex'> {\n templateId: string;\n formSchemaId: string;\n sectionState: SectionFormState;\n themeId?: string;\n /** Whether to inject watermark on preview. Default: auto (true for paid templates, false for free). */\n watermark?: boolean;\n /** Customize watermark text/opacity/fontSize/angle. Defaults preserve current behavior. */\n watermarkOptions?: WatermarkOptions;\n /** Optional prefetched rows from a trusted server to skip browser-side REST fetching. */\n prefetched?: ResolveFromFormOptions['prefetched'];\n}\n\n/** Options for PDF rendering */\nexport interface PdfFromFormOptions {\n templateId: string;\n formSchemaId: string;\n sectionState: SectionFormState;\n themeId?: string;\n /** Whether to inject watermark. Default: auto (true for paid templates, false for free). */\n watermark?: boolean;\n /** Customize watermark text/opacity/fontSize/angle. Defaults preserve current behavior. */\n watermarkOptions?: WatermarkOptions;\n /** Optional prefetched rows from a trusted server to skip browser-side REST fetching. */\n prefetched?: ResolveFromFormOptions['prefetched'];\n /** PDF document title */\n title?: string;\n /** Base URL for TTF font files for PDF font embedding */\n fontBaseUrl?: string;\n /** PDF text rendering mode. Default: selectable text for client vector-PDF parity. */\n textMode?: 'auto' | 'selectable' | 'pixel-perfect';\n}\n\nexport class PixldocsRenderer {\n private config: RendererConfig;\n\n constructor(config: RendererConfig) {\n this.config = config;\n this.installRuntimeGlobals();\n installUnderlineFix(fabric);\n installTextboxBoxExtensions(fabric);\n try {\n // eslint-disable-next-line no-console\n console.log(`[canvas-renderer] PixldocsRenderer v${PACKAGE_VERSION} initialized`);\n } catch {}\n }\n\n private installRuntimeGlobals(): void {\n try {\n if (typeof window !== 'undefined') {\n (window as any).__PIXLDOCS_SUPABASE_URL = this.config.supabaseUrl;\n (window as any).__PIXLDOCS_SUPABASE_ANON_KEY = this.config.supabaseAnonKey;\n }\n } catch {}\n }\n\n /**\n * Render a pre-resolved template config to an image using the full PageCanvas engine.\n * Mounts a hidden PreviewCanvas component and captures the Fabric canvas output.\n */\n async render(templateConfig: TemplateConfig, options: RenderOptions = {}): Promise<RenderResult> {\n const pageIndex = options.pageIndex ?? 0;\n const format = options.format ?? 'png';\n const quality = options.quality ?? 0.92;\n const pixelRatio = options.pixelRatio ?? this.config.pixelRatio ?? 2;\n\n const canvasWidth = templateConfig.canvas.width;\n const canvasHeight = templateConfig.canvas.height;\n\n const page = templateConfig.pages[pageIndex];\n if (!page) {\n throw new Error(`Page index ${pageIndex} not found (template has ${templateConfig.pages.length} pages)`);\n }\n\n // Load fonts first\n await ensureFontsForResolvedConfig(templateConfig);\n\n // ── PARITY FIX (v0.5.57) ──\n // `ensureFontsForResolvedConfig` only *queues* font loads (fire-and-forget).\n // The headless capture path mounts `PreviewCanvas` exactly once, and\n // `createText`'s `overflowPolicy: 'auto-shrink'` loop runs synchronously\n // at mount time using whatever metrics Fabric can measure right then.\n // If the real webfont hasn't actually loaded yet, the loop measures\n // against a fallback face (typically narrower) → \"fits, no shrink\" →\n // text overflows the box once the real font finally loads.\n //\n // The mounted `PixldocsPreview` component avoided this by remounting\n // PreviewCanvas with a fresh `key` after `document.fonts.ready`. The\n // headless path didn't, so PNG/PDF capture from `renderFromForm` could\n // diverge from the on-screen preview for templates with auto-shrink text.\n //\n // Fix: actually *await* the font loads (with a sane timeout) BEFORE we\n // mount PreviewCanvas, so the very first `createText` call measures\n // against final metrics.\n if (!options.skipFontReadyWait) {\n const hasAutoShrink = configHasAutoShrinkText(templateConfig);\n const defaultWait = hasAutoShrink ? 4000 : 1800;\n await this.awaitFontsForConfig(templateConfig, options.waitForFontsMs ?? defaultWait);\n }\n\n // Set up image proxy URL for the preview\n const { setPackageApiUrl } = await import('./shims/app-api');\n setPackageApiUrl(this.config.imageProxyUrl);\n\n // Mount a hidden PreviewCanvas and capture\n const dataUrl = await this.renderPageViaPreviewCanvas(\n templateConfig,\n pageIndex,\n pixelRatio,\n format,\n quality,\n { skipFontReadyWait: options.skipFontReadyWait, waitForFontsMs: options.waitForFontsMs },\n );\n\n return {\n dataUrl,\n width: canvasWidth,\n height: canvasHeight,\n pixelWidth: canvasWidth * pixelRatio,\n pixelHeight: canvasHeight * pixelRatio,\n };\n }\n\n /**\n * Render all pages and return array of results.\n */\n async renderAllPages(\n templateConfig: TemplateConfig,\n options: Omit<RenderOptions, 'pageIndex'> = {},\n ): Promise<RenderResult[]> {\n // Pre-await fonts ONCE for the whole config (the per-page render() also\n // does this, but doing it here avoids re-awaiting per page).\n if (!options.skipFontReadyWait) {\n const hasAutoShrink = configHasAutoShrinkText(templateConfig);\n const defaultWait = hasAutoShrink ? 4000 : 1800;\n await this.awaitFontsForConfig(templateConfig, options.waitForFontsMs ?? defaultWait);\n }\n const results: RenderResult[] = [];\n for (let i = 0; i < templateConfig.pages.length; i++) {\n // Skip the per-page font wait — we already did it above.\n results.push(await this.render(templateConfig, { ...options, pageIndex: i, skipFontReadyWait: true }));\n }\n return results;\n }\n\n /**\n * Resolve from V2 sectionState (like the server API) and render all pages.\n * This is the primary external API for the package.\n */\n async renderFromForm(options: RenderFromFormOptions): Promise<RenderResult[]> {\n const { templateId, formSchemaId, sectionState, themeId, watermark, watermarkOptions, prefetched, ...renderOpts } = options;\n\n const resolved = await resolveFromForm({\n templateId,\n formSchemaId,\n sectionState,\n themeId,\n supabaseUrl: this.config.supabaseUrl,\n supabaseAnonKey: this.config.supabaseAnonKey,\n prefetched,\n });\n\n // Inject watermark for paid templates (matches server render-from-form behavior)\n const shouldWatermark = watermark ?? (resolved.price > 0);\n let configToRender = resolved.config;\n if (shouldWatermark) {\n const { injectWatermark } = await import('@/lib/canvasWatermark');\n configToRender = injectWatermark(configToRender as any, watermarkOptions) as unknown as TemplateConfig;\n const { injectPreviewBlur } = await import('@/lib/previewBlur');\n configToRender = injectPreviewBlur(configToRender as any) as unknown as TemplateConfig;\n }\n\n return this.renderAllPages(configToRender, renderOpts);\n }\n\n /**\n * Render a page and capture the Fabric canvas SVG output (vector, not raster).\n * This is the key building block for client-side vector PDF export.\n */\n async renderPageSvg(templateConfig: TemplateConfig, pageIndex = 0): Promise<SvgRenderResult> {\n const page = templateConfig.pages[pageIndex];\n if (!page) {\n throw new Error(`Page index ${pageIndex} not found (template has ${templateConfig.pages.length} pages)`);\n }\n\n // Load fonts and BLOCK on the loads so the headless `createText`\n // auto-shrink loop measures against final webfont metrics. Without\n // this, SVG/PDF capture can pick up fallback metrics → overflow.\n await ensureFontsForResolvedConfig(templateConfig);\n const hasAutoShrinkSvg = configHasAutoShrinkText(templateConfig);\n await this.awaitFontsForConfig(templateConfig, hasAutoShrinkSvg ? 4000 : 1800);\n\n // Set up image proxy URL\n const { setPackageApiUrl } = await import('./shims/app-api');\n setPackageApiUrl(this.config.imageProxyUrl);\n\n const canvasWidth = templateConfig.canvas.width;\n const canvasHeight = templateConfig.canvas.height;\n\n return this.captureSvgViaPreviewCanvas(templateConfig, pageIndex, canvasWidth, canvasHeight);\n }\n\n /**\n * Render all pages and return SVG strings for each.\n */\n async renderAllPageSvgs(templateConfig: TemplateConfig): Promise<SvgRenderResult[]> {\n // Load fonts once upfront, and BLOCK on them (see renderPageSvg comment).\n await ensureFontsForResolvedConfig(templateConfig);\n const hasAutoShrinkSvg = configHasAutoShrinkText(templateConfig);\n await this.awaitFontsForConfig(templateConfig, hasAutoShrinkSvg ? 4000 : 1800);\n const { setPackageApiUrl } = await import('./shims/app-api');\n setPackageApiUrl(this.config.imageProxyUrl);\n\n const results: SvgRenderResult[] = [];\n for (let i = 0; i < templateConfig.pages.length; i++) {\n const canvasWidth = templateConfig.canvas.width;\n const canvasHeight = templateConfig.canvas.height;\n results.push(await this.captureSvgViaPreviewCanvas(templateConfig, i, canvasWidth, canvasHeight));\n }\n return results;\n }\n\n /**\n * Resolve from V2 sectionState and return SVGs for all pages (for server vector PDF).\n */\n async renderSvgsFromForm(options: Omit<RenderFromFormOptions, 'format' | 'quality' | 'scale' | 'pixelRatio'>): Promise<SvgRenderResult[]> {\n const { templateId, formSchemaId, sectionState, themeId, watermark, watermarkOptions, prefetched } = options;\n\n const resolved = await resolveFromForm({\n templateId,\n formSchemaId,\n sectionState,\n themeId,\n supabaseUrl: this.config.supabaseUrl,\n supabaseAnonKey: this.config.supabaseAnonKey,\n prefetched,\n });\n\n const shouldWatermark = watermark ?? (resolved.price > 0);\n let configToRender = resolved.config;\n if (shouldWatermark) {\n const { injectWatermark } = await import('@/lib/canvasWatermark');\n configToRender = injectWatermark(configToRender as any, watermarkOptions) as unknown as TemplateConfig;\n const { injectPreviewBlur } = await import('@/lib/previewBlur');\n configToRender = injectPreviewBlur(configToRender as any) as unknown as TemplateConfig;\n }\n\n return this.renderAllPageSvgs(configToRender);\n }\n\n /**\n * Render a pre-resolved template config to a vector PDF.\n * Returns a Blob and ArrayBuffer.\n *\n * Unified path (v0.5.118+): delegates to the EXACT same\n * `exportMultiPagePdf` pipeline used by the client-side editor / UseForm\n * download buttons. This guarantees byte-identical output between the\n * browser-side download and the server-side EC2 render — no separate SVG\n * stitching path, no svg2pdf-only fallback. The only requirement is that\n * each page is mounted as a real Fabric canvas (via `PreviewCanvas`) and\n * registered in `fabricCanvasRegistry` before we hand off to the client\n * exporter, which is what `renderPdfViaClientExport` does below.\n */\n async renderPdf(\n templateConfig: TemplateConfig,\n options?: { title?: string; fontBaseUrl?: string; textMode?: 'auto' | 'selectable' | 'pixel-perfect' },\n ): Promise<import('./pdf-export').PdfRenderResult> {\n return this.renderPdfViaClientExport(templateConfig, {\n title: options?.title,\n textMode: options?.textMode,\n });\n }\n\n /**\n * Resolve from V2 sectionState and render a vector PDF.\n * This is the primary PDF export API — mirrors renderFromForm() but returns a PDF.\n */\n async renderPdfFromForm(\n options: PdfFromFormOptions,\n ): Promise<import('./pdf-export').PdfRenderResult> {\n const { templateId, formSchemaId, sectionState, themeId, watermark, watermarkOptions, prefetched, title, fontBaseUrl, textMode } = options;\n\n const resolved = await resolveFromForm({\n templateId,\n formSchemaId,\n sectionState,\n themeId,\n supabaseUrl: this.config.supabaseUrl,\n supabaseAnonKey: this.config.supabaseAnonKey,\n prefetched,\n });\n\n const shouldWatermark = watermark ?? (resolved.price > 0);\n let configToRender = resolved.config;\n if (shouldWatermark) {\n const { injectWatermark } = await import('@/lib/canvasWatermark');\n configToRender = injectWatermark(configToRender as any, watermarkOptions) as unknown as TemplateConfig;\n const { injectPreviewBlur } = await import('@/lib/previewBlur');\n configToRender = injectPreviewBlur(configToRender as any) as unknown as TemplateConfig;\n }\n\n return this.renderPdfViaClientExport(configToRender, {\n title: title ?? resolved.config.name,\n watermark: shouldWatermark,\n textMode,\n });\n }\n async renderById(\n templateId: string,\n formData?: Record<string, any>,\n options?: RenderOptions,\n ): Promise<RenderResult> {\n const resolved = await resolveTemplateData({\n templateId,\n formData,\n supabaseUrl: this.config.supabaseUrl,\n supabaseAnonKey: this.config.supabaseAnonKey,\n });\n return this.render(resolved.config, options);\n }\n\n /**\n * Convenience: fetch by ID with flat data and render ALL pages.\n */\n async renderAllById(\n templateId: string,\n formData?: Record<string, any>,\n options?: Omit<RenderOptions, 'pageIndex'>,\n ): Promise<RenderResult[]> {\n const resolved = await resolveTemplateData({\n templateId,\n formData,\n supabaseUrl: this.config.supabaseUrl,\n supabaseAnonKey: this.config.supabaseAnonKey,\n });\n return this.renderAllPages(resolved.config, options);\n }\n\n // ─── Internal: render a page using the full PreviewCanvas engine ───\n\n /**\n * Mount every page of `templateConfig` as a real `PreviewCanvas` (so each\n * `PageCanvas` registers its Fabric instance into `fabricCanvasRegistry`),\n * then hand the prepared draw list off to the SAME `exportMultiPagePdf`\n * function the client-side download buttons use. This guarantees 1:1\n * parity between the browser-side PDF and the server-side EC2 PDF —\n * same fonts, same gradients, same draw order, same selectable text.\n */\n private async renderPdfViaClientExport(\n templateConfig: TemplateConfig,\n options: { title?: string; watermark?: boolean; textMode?: 'auto' | 'selectable' | 'pixel-perfect' } = {},\n ): Promise<import('./pdf-export').PdfRenderResult> {\n // 1. Make sure web fonts are available before any Fabric measurement.\n await ensureFontsForResolvedConfig(templateConfig);\n const hasAutoShrink = configHasAutoShrinkText(templateConfig);\n await this.awaitFontsForConfig(templateConfig, hasAutoShrink ? 4000 : 1800);\n\n // 2. Wire image proxy URL into the package shim so PreviewCanvas can\n // fetch user-media via the same proxy as the editor.\n const { setPackageApiUrl } = await import('./shims/app-api');\n setPackageApiUrl(this.config.imageProxyUrl);\n\n // 3. Clone the config and stamp unique pageIds so multiple harness\n // invocations never collide in the global Fabric registry.\n const cloned: TemplateConfig = JSON.parse(JSON.stringify(templateConfig));\n const stampPrefix = `__pixldocs_pdf_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;\n const pageIds: string[] = cloned.pages.map((p, i) => {\n const id = `${stampPrefix}_p${i}`;\n p.id = id;\n return id;\n });\n\n // 4. Mount one PreviewCanvas per page in hidden containers so every page\n // Fabric canvas is alive simultaneously when `exportMultiPagePdf`\n // iterates `getCanvasForPage(pageId)`.\n const { PreviewCanvas } = await import('../../../src/components/PreviewCanvas');\n const containers: HTMLDivElement[] = [];\n const roots: ReturnType<typeof createRoot>[] = [];\n const canvasWidth = cloned.canvas.width;\n const canvasHeight = cloned.canvas.height;\n\n const cleanup = () => {\n for (const r of roots) { try { r.unmount(); } catch {} }\n for (const c of containers) { try { c.remove(); } catch {} }\n };\n\n try {\n for (let i = 0; i < cloned.pages.length; i++) {\n const container = document.createElement('div');\n container.style.cssText = `position: fixed; left: -99999px; top: -99999px; width: ${canvasWidth}px; height: ${canvasHeight}px; overflow: hidden; pointer-events: none; opacity: 0;`;\n document.body.appendChild(container);\n containers.push(container);\n\n const root = createRoot(container);\n roots.push(root);\n\n await new Promise<void>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`PreviewCanvas onReady timeout for page ${i}`)), 30000);\n root.render(\n createElement(PreviewCanvas as any, {\n key: `pdf-export-page-${i}`,\n config: cloned,\n pageIndex: i,\n pageIdOverride: pageIds[i],\n zoom: 1,\n absoluteZoom: true,\n skipFontReadyWait: false,\n preserveGlobalFontCache: true,\n onReady: () => { clearTimeout(timer); resolve(); },\n }),\n );\n });\n\n // Wait for assets/text/scene to settle for THIS page before moving on.\n await this.waitForCanvasScene(container, cloned, i);\n const expected = this.getExpectedImageCount(cloned, i);\n await this.waitForCanvasImages(container, expected);\n // PDF export runs alongside the live `/use` preview — never clear\n // Fabric's global char-width cache, that would silently reflow the\n // visible auto-shrunk textboxes from auto-shrink → grow-and-push.\n await this.waitForStableTextMetrics(container, cloned, { clearGlobalCharCache: false });\n await this.waitForCanvasScene(container, cloned, i);\n }\n\n console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);\n\n // 5. Use the exact same client export pipeline.\n const { exportMultiPagePdf, preparePagesForExport } = await import('@/lib/vectorPdfExport');\n const prepared = preparePagesForExport(\n cloned.pages as any,\n canvasWidth,\n canvasHeight,\n );\n\n const result = await exportMultiPagePdf(prepared, {\n title: options.title,\n watermark: !!options.watermark,\n returnBlob: true,\n pdfTextMode:\n options.textMode ??\n ((cloned as any)?.pdfTextMode as 'auto' | 'selectable' | 'pixel-perfect' | undefined) ??\n ((cloned.canvas as any)?.n as 'auto' | 'selectable' | 'pixel-perfect' | undefined) ??\n 'auto',\n });\n\n if (!result || typeof result === 'undefined') {\n throw new Error('exportMultiPagePdf returned no blob (returnBlob path failed)');\n }\n\n return result as import('./pdf-export').PdfRenderResult;\n } finally {\n cleanup();\n }\n }\n\n private getExpectedImageCount(config: TemplateConfig, pageIndex: number): number {\n return this.getExpectedImageIds(config, pageIndex).length;\n }\n\n /**\n * Collects ids of nodes that the renderer expects to produce a renderable\n * fabric image. Excludes SVG sources because those are loaded as Groups,\n * not HTMLImageElement-backed Images, and would otherwise inflate the\n * `expected` counter forever.\n */\n private getExpectedImageIds(config: TemplateConfig, pageIndex: number): string[] {\n const page = config.pages[pageIndex];\n if (!page?.children) return [];\n const ids: string[] = [];\n const isSvgUrl = (u: string) => /\\.svg(\\?|#|$)/i.test(u) || u.startsWith('data:image/svg');\n const walk = (nodes: CanvasNode[]) => {\n for (const node of nodes) {\n if (!node || node.visible === false) continue;\n const src = typeof node.src === 'string' ? node.src.trim() : '';\n const imageUrl = typeof node.imageUrl === 'string' ? node.imageUrl.trim() : '';\n const url = src || imageUrl;\n if (node.type === 'image' && url && !isSvgUrl(url) && node.id) {\n ids.push(String(node.id));\n }\n if (Array.isArray(node.children) && node.children.length > 0) {\n walk(node.children);\n }\n }\n };\n walk(page.children as CanvasNode[]);\n return ids;\n }\n\n private waitForCanvasImages(\n container: HTMLElement,\n expectedImageCount: number,\n maxWaitMs?: number,\n pollMs = 120,\n ): Promise<void> {\n const timeout = Math.max(500, maxWaitMs ?? this.config.assetWaitTimeoutMs ?? 15000);\n const earlyExitMs = Math.max(250, this.config.assetWaitEarlyExitMs ?? 1500);\n const debug = !!this.config.debug;\n return new Promise<void>((resolve) => {\n const start = Date.now();\n let stableFrames = 0;\n let lastSummary = '';\n let lastActual = -1;\n let lastProgressAt = Date.now();\n\n const isRenderableImage = (value: unknown): value is HTMLImageElement =>\n value instanceof HTMLImageElement && value.complete && value.naturalWidth > 0 && value.naturalHeight > 0;\n\n const collectRenderableImages = (obj: any, seen: Set<HTMLImageElement>) => {\n if (!obj || typeof obj !== 'object') return;\n\n const candidates = [obj._element, obj._originalElement, obj._filteredEl, obj._cacheCanvasEl];\n for (const candidate of candidates) {\n if (isRenderableImage(candidate)) {\n seen.add(candidate);\n } else if (candidate instanceof HTMLImageElement) {\n return false;\n }\n }\n\n const nested = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];\n for (const child of nested) {\n if (collectRenderableImages(child, seen) === false) return false;\n }\n\n return true;\n };\n\n const getFabricCanvas = () => {\n const registry = (window as any).__fabricCanvasRegistry;\n if (registry instanceof Map) {\n for (const entry of registry.values()) {\n const canvas = entry?.canvas;\n const el = canvas?.lowerCanvasEl || canvas?.upperCanvasEl;\n if (el && container.contains(el)) return canvas;\n }\n }\n return null;\n };\n\n const settle = () => requestAnimationFrame(() => requestAnimationFrame(() => resolve()));\n\n const getImageDebugInfo = (obj: any, bucket: Array<Record<string, unknown>>) => {\n if (!obj || typeof obj !== 'object') return;\n\n const candidates = [obj._element, obj._originalElement, obj._filteredEl, obj._cacheCanvasEl];\n for (const candidate of candidates) {\n if (candidate instanceof HTMLImageElement) {\n bucket.push({\n id: obj.__docuforgeId || obj.id || 'unknown',\n src: (candidate.currentSrc || candidate.src || '').slice(0, 240),\n complete: candidate.complete,\n naturalWidth: candidate.naturalWidth,\n naturalHeight: candidate.naturalHeight,\n });\n }\n }\n\n const nested = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];\n for (const child of nested) {\n getImageDebugInfo(child, bucket);\n }\n };\n\n const check = () => {\n const elapsed = Date.now() - start;\n const domImages = Array.from(container.querySelectorAll('img')) as HTMLImageElement[];\n const allDomLoaded = domImages.every((img) => img.complete && img.naturalWidth > 0 && img.naturalHeight > 0);\n\n const fabricCanvas = getFabricCanvas();\n const fabricObjects = fabricCanvas && typeof fabricCanvas.getObjects === 'function'\n ? fabricCanvas.getObjects()\n : [];\n const renderableImages = new Set<HTMLImageElement>();\n const fabricReady = fabricObjects.every((obj: any) => collectRenderableImages(obj, renderableImages) !== false);\n const actualImageCount = Math.max(domImages.length, renderableImages.size);\n const canvasReady = !!fabricCanvas && !!(fabricCanvas.lowerCanvasEl || fabricCanvas.upperCanvasEl);\n const hasExpectedAssets = expectedImageCount === 0 ? true : actualImageCount >= expectedImageCount;\n const ready = allDomLoaded && fabricReady && hasExpectedAssets;\n const summary = `expected=${expectedImageCount} actual=${actualImageCount} dom=${domImages.length} fabricReady=${fabricReady} domReady=${allDomLoaded} canvasReady=${canvasReady}`;\n\n if (summary !== lastSummary) {\n lastSummary = summary;\n if (debug) console.log(`[canvas-renderer][asset-wait] ${summary}`);\n }\n\n if (actualImageCount !== lastActual) {\n lastActual = actualImageCount;\n lastProgressAt = Date.now();\n }\n\n if (ready) {\n stableFrames += 1;\n if (stableFrames >= 2) {\n if (debug) console.log(`[canvas-renderer][asset-wait] ready after ${elapsed}ms (${summary})`);\n settle();\n return;\n }\n } else {\n stableFrames = 0;\n }\n\n // Early-exit: scene fully settled, no asset progress for a while.\n // Handles cases where `expected` is non-zero but the corresponding\n // fabric objects don't materialize as HTMLImageElements (e.g. SVG\n // sources loaded as Groups, missing/blocked URLs, mask-only assets).\n const sceneSettled =\n fabricReady && allDomLoaded && canvasReady && fabricObjects.length > 0;\n const idleFor = Date.now() - lastProgressAt;\n if (sceneSettled && actualImageCount < expectedImageCount && idleFor >= earlyExitMs) {\n if (debug) {\n console.log(\n `[canvas-renderer][asset-wait] early-exit after ${elapsed}ms (idle=${idleFor}ms, ${summary})`,\n );\n }\n settle();\n return;\n }\n\n if (elapsed >= timeout) {\n const fabricImageDebug: Array<Record<string, unknown>> = [];\n for (const obj of fabricObjects as any[]) {\n getImageDebugInfo(obj, fabricImageDebug);\n }\n const domImageDebug = domImages.map((img, index) => ({\n index,\n src: (img.currentSrc || img.src || '').slice(0, 240),\n complete: img.complete,\n naturalWidth: img.naturalWidth,\n naturalHeight: img.naturalHeight,\n }));\n console.warn(`[canvas-renderer][asset-wait-timeout] elapsed=${elapsed}ms ${summary}`);\n console.warn('[canvas-renderer][asset-wait-timeout][dom-images]', domImageDebug);\n console.warn('[canvas-renderer][asset-wait-timeout][fabric-images]', fabricImageDebug);\n settle();\n return;\n }\n\n setTimeout(check, pollMs);\n };\n\n setTimeout(check, 0);\n });\n }\n\n private waitForCanvasScene(\n container: HTMLElement,\n config: TemplateConfig,\n pageIndex: number,\n maxWaitMs = 8000,\n pollMs = 50,\n ): Promise<void> {\n return new Promise<void>((resolve) => {\n const start = Date.now();\n const pageHasContent = (config.pages[pageIndex]?.children?.length ?? 0) > 0;\n const settle = () => requestAnimationFrame(() => requestAnimationFrame(() => resolve()));\n\n const check = () => {\n const fabricCanvas = this.getFabricCanvasFromContainer(container);\n const lowerCanvas = fabricCanvas?.lowerCanvasEl || container.querySelector('canvas.lower-canvas, canvas');\n const objectCount = typeof fabricCanvas?.getObjects === 'function' ? fabricCanvas.getObjects().length : 0;\n const ready = !!lowerCanvas && (!pageHasContent || objectCount > 0);\n\n if (ready) {\n console.log(`[canvas-renderer][scene-wait] ready after ${Date.now() - start}ms (objects=${objectCount})`);\n settle();\n return;\n }\n\n if (Date.now() - start >= maxWaitMs) {\n console.warn(`[canvas-renderer][scene-wait-timeout] elapsed=${Date.now() - start}ms objects=${objectCount} pageHasContent=${pageHasContent}`);\n settle();\n return;\n }\n\n setTimeout(check, pollMs);\n };\n\n setTimeout(check, 0);\n });\n }\n\n private async waitForRelevantFonts(config: TemplateConfig, maxWaitMs = 1800): Promise<void> {\n if (typeof document === 'undefined' || !document.fonts) return;\n\n const descriptors = collectFontDescriptorsFromConfig(config);\n if (descriptors.length === 0) return;\n\n const loads = Promise.all(\n descriptors.map((descriptor) => {\n const stylePrefix = descriptor.style === 'italic' ? 'italic ' : '';\n const spec = `${stylePrefix}${descriptor.weight} 16px \"${descriptor.family}\"`;\n return document.fonts!.load(spec).catch(() => []);\n }),\n ).then(() => undefined);\n\n await Promise.race([\n loads,\n new Promise<void>((resolve) => setTimeout(resolve, maxWaitMs)),\n ]);\n\n await new Promise<void>((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));\n }\n\n /**\n * Block until the webfonts referenced by `config` have actually loaded\n * (or `maxWaitMs` elapses). Used by the headless capture path BEFORE\n * mounting `PreviewCanvas`, so the synchronous `createText` auto-shrink\n * loop measures against final font metrics instead of fallback ones.\n *\n * Stronger than `ensureFontsForResolvedConfig` (which is fire-and-forget)\n * — this awaits each `document.fonts.load(spec)` AND `document.fonts.ready`,\n * racing the whole thing against `maxWaitMs` so a slow CDN can't hang the\n * renderer.\n */\n private async awaitFontsForConfig(config: TemplateConfig, maxWaitMs: number): Promise<void> {\n if (typeof document === 'undefined' || !document.fonts) return;\n // Register CSS @font-face rules before descriptor loads. If this is only\n // fire-and-forget, the auto-shrink loop can still mount against fallback\n // fonts on EC2/local package cold starts.\n await ensureFontsForResolvedConfig(config);\n // Wait for the descriptors to actually shape (with timeout).\n await this.waitForRelevantFonts(config, maxWaitMs);\n // Then race `document.fonts.ready` against the remaining budget.\n await Promise.race([\n document.fonts.ready.catch(() => undefined).then(() => undefined),\n new Promise<void>((r) => setTimeout(r, Math.min(500, maxWaitMs))),\n ]);\n }\n\n private getNormalizedGradientStops(gradient: any): Array<{ offset: number; color: string }> {\n const stops = Array.isArray(gradient?.stops)\n ? gradient.stops\n .map((stop: any) => ({\n offset: Math.max(0, Math.min(1, Number(stop?.offset ?? 0))),\n color: String(stop?.color ?? '#ffffff'),\n }))\n .filter((stop: { offset: number; color: string }) => Number.isFinite(stop.offset))\n .sort((a, b) => a.offset - b.offset)\n : [];\n\n if (stops.length === 0) return [];\n const normalized = [...stops];\n if (normalized[0].offset > 0) {\n normalized.unshift({ offset: 0, color: normalized[0].color });\n }\n if (normalized[normalized.length - 1].offset < 1) {\n normalized.push({ offset: 1, color: normalized[normalized.length - 1].color });\n }\n return normalized;\n }\n\n private paintPageBackground(\n ctx: CanvasRenderingContext2D,\n page: TemplateConfig['pages'][number] | undefined,\n width: number,\n height: number,\n ) {\n const backgroundColor = page?.settings?.backgroundColor || '#ffffff';\n const gradient = page?.settings?.backgroundGradient;\n\n ctx.clearRect(0, 0, width, height);\n ctx.fillStyle = backgroundColor;\n ctx.fillRect(0, 0, width, height);\n\n const stops = this.getNormalizedGradientStops(gradient);\n if (stops.length < 2) return;\n\n try {\n let canvasGradient: CanvasGradient | null = null;\n\n if (gradient?.type === 'radial') {\n const cx = Number.isFinite(gradient?.cx) ? gradient.cx : 0.5;\n const cy = Number.isFinite(gradient?.cy) ? gradient.cy : 0.5;\n const centerX = width * cx;\n const centerY = height * cy;\n const radius = Math.max(\n Math.hypot(centerX, centerY),\n Math.hypot(width - centerX, centerY),\n Math.hypot(centerX, height - centerY),\n Math.hypot(width - centerX, height - centerY),\n );\n canvasGradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, radius);\n } else if (gradient?.type === 'conic' && typeof (ctx as any).createConicGradient === 'function') {\n const cx = Number.isFinite(gradient?.cx) ? gradient.cx : 0.5;\n const cy = Number.isFinite(gradient?.cy) ? gradient.cy : 0.5;\n const startAngle = (((gradient?.angle ?? 0) - 90) * Math.PI) / 180;\n canvasGradient = (ctx as any).createConicGradient(startAngle, width * cx, height * cy);\n } else {\n const angleDeg = gradient?.angle ?? 90;\n const angleRad = (angleDeg * Math.PI) / 180;\n const sinA = Math.sin(angleRad);\n const cosA = Math.cos(angleRad);\n const midX = width / 2;\n const midY = height / 2;\n const corners = [\n [0, 0],\n [width, 0],\n [width, height],\n [0, height],\n ];\n const projections = corners.map(([x, y]) => x * sinA - y * cosA);\n const minProjection = Math.min(...projections);\n const maxProjection = Math.max(...projections);\n canvasGradient = ctx.createLinearGradient(\n midX + minProjection * sinA,\n midY - minProjection * cosA,\n midX + maxProjection * sinA,\n midY - maxProjection * cosA,\n );\n }\n\n if (!canvasGradient) return;\n\n stops.forEach((stop) => canvasGradient!.addColorStop(stop.offset, stop.color));\n ctx.fillStyle = canvasGradient;\n ctx.fillRect(0, 0, width, height);\n } catch {\n // Fall back to solid backgroundColor only.\n }\n }\n\n private async renderPageViaPreviewCanvas(\n config: TemplateConfig,\n pageIndex: number,\n pixelRatio: number,\n format: string,\n quality: number,\n options: { skipFontReadyWait?: boolean; waitForFontsMs?: number } = {},\n ): Promise<string> {\n // Dynamically import PreviewCanvas to avoid circular deps at module load\n const { PreviewCanvas } = await import('../../../src/components/PreviewCanvas');\n const capture = isolatePageForCapture(config, pageIndex);\n const renderConfig = capture.config;\n\n const canvasWidth = renderConfig.canvas.width;\n const canvasHeight = renderConfig.canvas.height;\n const hasAutoShrink = configHasAutoShrinkText(renderConfig);\n // Track whether `document.fonts.ready` resolved AFTER the first PreviewCanvas\n // mount completed — if so, the synchronous auto-shrink loop in `createText`\n // ran against fallback metrics and we MUST remount with cleared caches\n // (mirroring what `PixldocsPreview` does via its `fontsReadyVersion` key).\n let firstMountSettled = false;\n let lateFontSettleDetected = false;\n if (typeof document !== 'undefined' && document.fonts && hasAutoShrink) {\n document.fonts.ready\n .then(() => {\n if (firstMountSettled) lateFontSettleDetected = true;\n })\n .catch(() => {});\n }\n\n return new Promise<string>((resolve, reject) => {\n // Create a hidden container\n const container = document.createElement('div');\n container.style.cssText = `\n position: fixed; left: -99999px; top: -99999px;\n width: ${canvasWidth}px; height: ${canvasHeight}px;\n overflow: hidden; pointer-events: none; opacity: 0;\n `;\n document.body.appendChild(container);\n\n const timeout = setTimeout(() => {\n cleanup();\n reject(new Error('Render timeout (30s)'));\n }, 30000);\n\n let root: ReturnType<typeof createRoot>;\n let mountKey = 0;\n\n const cleanup = () => {\n clearTimeout(timeout);\n try {\n root.unmount();\n } catch {}\n container.remove();\n };\n\n const remountWithFreshKey = async (): Promise<void> => {\n mountKey += 1;\n // Clear measurement caches so `createText`'s auto-shrink loop\n // re-measures against the freshly-loaded webfont metrics.\n try { clearMeasurementCache(); } catch {}\n try { clearFabricCharCache(); } catch {}\n try { root.unmount(); } catch {}\n // Recreate root on the same container — React doesn't allow reusing\n // an unmounted root.\n root = createRoot(container);\n await new Promise<void>((settle) => {\n // Wire up a one-shot onReady for the remount.\n const onReadyOnce = () => {\n // Re-run the same scene/asset/text stabilization passes.\n this.waitForCanvasScene(container, renderConfig, pageIndex)\n .then(async () => {\n const fabricInstance = this.getFabricCanvasFromContainer(container);\n const expectedImageCount = this.getExpectedImageCount(renderConfig, pageIndex);\n await this.waitForCanvasImages(container, expectedImageCount);\n await this.waitForStableTextMetrics(container, renderConfig);\n await this.waitForCanvasScene(container, renderConfig, pageIndex);\n if (!fabricInstance) return settle();\n settle();\n })\n .catch(() => settle());\n };\n root.render(\n createElement(PreviewCanvas, {\n key: `remount-${mountKey}`,\n config: renderConfig as any,\n pageIndex,\n pageIdOverride: capture.pageId,\n zoom: pixelRatio,\n absoluteZoom: true,\n skipFontReadyWait: false,\n preserveGlobalFontCache: true,\n onReady: onReadyOnce,\n }),\n );\n });\n };\n\n const onReady = () => {\n this.waitForCanvasScene(container, renderConfig, pageIndex).then(async () => {\n try {\n const fabricInstance = this.getFabricCanvasFromContainer(container);\n const expectedImageCount = this.getExpectedImageCount(renderConfig, pageIndex);\n await this.waitForCanvasImages(container, expectedImageCount);\n await this.waitForStableTextMetrics(container, renderConfig);\n await this.waitForCanvasScene(container, renderConfig, pageIndex);\n firstMountSettled = true;\n\n // ── PARITY REMOUNT ──\n // If the config has auto-shrink text and `document.fonts.ready`\n // resolved AFTER our first mount completed (i.e. fonts were still\n // loading when `createText` ran the shrink loop), the chosen\n // fontSize was based on fallback metrics and is now wrong.\n // Remount with a fresh key + cleared caches so the shrink loop\n // re-runs against final metrics. This mirrors `PixldocsPreview`'s\n // `fontsReadyVersion` bump.\n if (hasAutoShrink && lateFontSettleDetected) {\n console.log('[canvas-renderer][parity] late font-settle detected — remounting for auto-shrink reflow');\n await remountWithFreshKey();\n }\n\n const fabricCanvas = container.querySelector('canvas.upper-canvas, canvas') as HTMLCanvasElement;\n const sourceCanvas = fabricInstance?.lowerCanvasEl || container.querySelector('canvas.lower-canvas') as HTMLCanvasElement || fabricCanvas;\n // Re-resolve fabricInstance after potential remount.\n const fabricInstanceAfter = this.getFabricCanvasFromContainer(container) || fabricInstance;\n const sourceCanvasAfter = fabricInstanceAfter?.lowerCanvasEl\n || container.querySelector('canvas.lower-canvas') as HTMLCanvasElement\n || sourceCanvas;\n if (!sourceCanvas) {\n cleanup();\n reject(new Error('No canvas element found after render'));\n return;\n }\n const exportCanvas = document.createElement('canvas');\n exportCanvas.width = sourceCanvasAfter.width;\n exportCanvas.height = sourceCanvasAfter.height;\n const exportCtx = exportCanvas.getContext('2d');\n if (!exportCtx) {\n cleanup();\n reject(new Error('Failed to create export canvas'));\n return;\n }\n\n exportCtx.save();\n exportCtx.scale(sourceCanvasAfter.width / canvasWidth, sourceCanvasAfter.height / canvasHeight);\n this.paintPageBackground(exportCtx, renderConfig.pages[pageIndex], canvasWidth, canvasHeight);\n exportCtx.restore();\n exportCtx.drawImage(sourceCanvasAfter, 0, 0);\n\n const mimeType =\n format === 'jpeg' ? 'image/jpeg' : format === 'webp' ? 'image/webp' : 'image/png';\n const dataUrl = exportCanvas.toDataURL(mimeType, quality);\n cleanup();\n resolve(dataUrl);\n } catch (err) {\n cleanup();\n reject(err);\n }\n });\n };\n\n root = createRoot(container);\n root.render(\n createElement(PreviewCanvas, {\n config: renderConfig as any,\n pageIndex,\n pageIdOverride: capture.pageId,\n zoom: pixelRatio,\n absoluteZoom: true,\n skipFontReadyWait: false,\n preserveGlobalFontCache: true,\n onReady,\n }),\n );\n });\n }\n\n // ─── Internal: capture SVG from a rendered Fabric canvas ───\n //\n // APPROACH: Use the SAME PreviewCanvas that renders perfect PNGs, then call\n // Fabric's toSVG() on that canvas. This guarantees 100% layout parity —\n // the SVG is a vector snapshot of exactly what's on screen.\n //\n // The trick: before calling toSVG(), we temporarily neutralize the viewport\n // transform and retina scaling so Fabric emits coordinates in logical\n // document space (e.g. 612x792) instead of inflated pixel space.\n\n private captureSvgViaPreviewCanvas(\n config: TemplateConfig,\n pageIndex: number,\n canvasWidth: number,\n canvasHeight: number,\n ): Promise<SvgRenderResult> {\n return new Promise<SvgRenderResult>(async (resolve, reject) => {\n const { PreviewCanvas } = await import('../../../src/components/PreviewCanvas');\n const capture = isolatePageForCapture(config, pageIndex);\n const renderConfig = capture.config;\n const container = document.createElement('div');\n container.style.cssText = `\n position: fixed; left: -99999px; top: -99999px;\n width: ${canvasWidth}px; height: ${canvasHeight}px;\n overflow: hidden; pointer-events: none; opacity: 0;\n `;\n document.body.appendChild(container);\n\n const timeout = setTimeout(() => {\n cleanup();\n reject(new Error('SVG render timeout (30s)'));\n }, 30000);\n\n let root: ReturnType<typeof createRoot> | null = null;\n const mountKey = 0;\n\n const cleanup = () => {\n clearTimeout(timeout);\n try {\n root?.unmount();\n } catch {}\n container.remove();\n };\n\n const mountPreview = (readyHandler: () => void) => {\n root = createRoot(container);\n root.render(\n createElement(PreviewCanvas, {\n key: `svg-capture-${mountKey}`,\n config: renderConfig as any,\n pageIndex,\n pageIdOverride: capture.pageId,\n zoom: 1,\n absoluteZoom: true,\n skipFontReadyWait: false,\n preserveGlobalFontCache: true,\n onReady: readyHandler,\n }),\n );\n };\n\n const onReady = () => {\n this.waitForCanvasScene(container, renderConfig, pageIndex).then(async () => {\n try {\n const expectedImageCount = this.getExpectedImageCount(renderConfig, pageIndex);\n await this.waitForCanvasImages(container, expectedImageCount);\n await this.waitForStableTextMetrics(container, renderConfig);\n await this.waitForCanvasScene(container, renderConfig, pageIndex);\n\n const fabricInstance = this.getFabricCanvasFromContainer(container);\n if (!fabricInstance) {\n cleanup();\n reject(new Error('No Fabric canvas instance found for SVG capture'));\n return;\n }\n\n // SHARED CAPTURE — same helper used by `exportMultiPagePdf` so the\n // server (EC2) and client (UsePackage) produce byte-comparable SVGs.\n const svgString = captureFabricCanvasSvgForPdf(\n fabricInstance,\n canvasWidth,\n canvasHeight,\n );\n\n const page = renderConfig.pages[pageIndex];\n const backgroundColor = page?.settings?.backgroundColor || '#ffffff';\n const backgroundGradient = page?.settings?.backgroundGradient;\n\n cleanup();\n resolve({\n svg: svgString,\n width: canvasWidth,\n height: canvasHeight,\n backgroundColor,\n backgroundGradient,\n });\n } catch (err) {\n cleanup();\n reject(err);\n }\n });\n };\n\n mountPreview(onReady);\n });\n }\n\n /**\n * Normalize the SVG's width/height/viewBox to match the logical page dimensions.\n * Fabric's toSVG() may output dimensions scaled by the canvas element's actual\n * pixel size (e.g., 2x due to devicePixelRatio), causing svg2pdf to render\n * content at the wrong scale. This rewrites the root <svg> attributes to ensure\n * the SVG coordinate system matches the intended page size exactly.\n */\n private normalizeSvgDimensions(svg: string, targetWidth: number, targetHeight: number): string {\n // Extract the actual width/height from the SVG root element\n const widthMatch = svg.match(/<svg[^>]*\\bwidth=\"([^\"]+)\"/i);\n const heightMatch = svg.match(/<svg[^>]*\\bheight=\"([^\"]+)\"/i);\n\n const svgWidth = widthMatch ? parseFloat(widthMatch[1]) : targetWidth;\n const svgHeight = heightMatch ? parseFloat(heightMatch[1]) : targetHeight;\n\n console.log(\n `[canvas-renderer][svg-normalize] root ${svgWidth}x${svgHeight} → page ${targetWidth}x${targetHeight}`,\n );\n\n let normalized = svg;\n\n if (/\\bwidth=\"[^\"]*\"/i.test(normalized)) {\n normalized = normalized.replace(/(<svg[^>]*\\b)width=\"[^\"]*\"/i, `$1width=\"${targetWidth}\"`);\n } else {\n normalized = normalized.replace(/<svg\\b/i, `<svg width=\"${targetWidth}\"`);\n }\n\n if (/\\bheight=\"[^\"]*\"/i.test(normalized)) {\n normalized = normalized.replace(/(<svg[^>]*\\b)height=\"[^\"]*\"/i, `$1height=\"${targetHeight}\"`);\n } else {\n normalized = normalized.replace(/<svg\\b/i, `<svg height=\"${targetHeight}\"`);\n }\n\n // Force logical page coordinates as the root coordinate system.\n // This avoids svg2pdf honoring an inflated backing-store size or stale canvas offset.\n const viewBox = `0 0 ${targetWidth} ${targetHeight}`;\n if (/\\bviewBox=\"[^\"]*\"/i.test(normalized)) {\n normalized = normalized.replace(/viewBox=\"[^\"]*\"/i, `viewBox=\"${viewBox}\"`);\n } else {\n normalized = normalized.replace(/<svg\\b/i, `<svg viewBox=\"${viewBox}\"`);\n }\n\n // Sanitize undefined/NaN attribute values that Fabric.js may emit\n // which cause svg2pdf.js to throw \"Invalid argument passed to jsPDF.scale\"\n normalized = normalized.replace(/=\"undefined\"/g, '=\"0\"');\n normalized = normalized.replace(/=\"NaN\"/g, '=\"0\"');\n\n if (/\\bx=\"[^\"]*\"/i.test(normalized)) {\n normalized = normalized.replace(/(<svg[^>]*\\b)x=\"[^\"]*\"/i, '$1x=\"0\"');\n } else {\n normalized = normalized.replace(/<svg\\b/i, '<svg x=\"0\"');\n }\n\n if (/\\by=\"[^\"]*\"/i.test(normalized)) {\n normalized = normalized.replace(/(<svg[^>]*\\b)y=\"[^\"]*\"/i, '$1y=\"0\"');\n } else {\n normalized = normalized.replace(/<svg\\b/i, '<svg y=\"0\"');\n }\n\n normalized = normalized\n .replace(/\\bpreserveAspectRatio=\"[^\"]*\"/i, 'preserveAspectRatio=\"none\"');\n\n if (!/\\bpreserveAspectRatio=\"[^\"]*\"/i.test(normalized)) {\n normalized = normalized.replace(/<svg\\b/i, '<svg preserveAspectRatio=\"none\"');\n }\n\n return normalized;\n }\n\n /**\n * Find the Fabric.Canvas instance that belongs to a given container element,\n * using the global __fabricCanvasRegistry (set by PageCanvas).\n */\n private getFabricCanvasFromContainer(container: HTMLElement): any | null {\n const registry = (window as any).__fabricCanvasRegistry;\n if (registry instanceof Map) {\n for (const entry of registry.values()) {\n const canvas = entry?.canvas || entry;\n if (!canvas || typeof canvas.toSVG !== 'function') continue;\n const el = canvas.lowerCanvasEl || canvas.upperCanvasEl;\n if (el && container.contains(el)) return canvas;\n }\n }\n return null;\n }\n\n private logFabricTextParitySnapshot(stage: string, fabricInstance: any): void {\n if (typeof window === 'undefined' || (window as any).__pixldocsDebugAutoShrink !== true) return;\n const sample: Array<Record<string, unknown>> = [];\n const visit = (obj: any, groupPath = '') => {\n if (!obj) return;\n if (isFabricTextboxLike(obj)) {\n const lineWidths = getCanvasMeasuredTextboxLineWidths(obj);\n sample.push({\n id: getObjectId(obj),\n groupPath,\n text: String(obj.text ?? '').slice(0, 180),\n left: obj.left,\n top: obj.top,\n width: obj.width,\n height: obj.height,\n scaleX: obj.scaleX,\n scaleY: obj.scaleY,\n fontSize: obj.fontSize,\n fontFamily: obj.fontFamily,\n fontWeight: obj.fontWeight,\n lineCount: obj.textLines?.length || 0,\n lines: (obj.textLines || []).map((line: unknown) => Array.isArray(line) ? line.join('') : String(line ?? '')),\n lineWidths,\n maxLineWidth: lineWidths.length ? Math.max(...lineWidths) : 0,\n });\n }\n if (isFabricGroupLike(obj)) {\n const nextPath = [groupPath, getObjectId(obj) || obj.type || 'group'].filter(Boolean).join('/');\n obj.getObjects().forEach((child: unknown) => visit(child, nextPath));\n }\n };\n fabricInstance?.getObjects?.().forEach((obj: unknown) => visit(obj));\n logJsonLine('[canvas-renderer][fabric-text-parity]', { stage, textboxes: sample.length, sample });\n }\n\n private async waitForStableTextMetrics(\n container: HTMLElement,\n config: TemplateConfig,\n options: { clearGlobalCharCache?: boolean } = {},\n ): Promise<void> {\n if (typeof document !== 'undefined') {\n void ensureFontsForResolvedConfig(config);\n await this.waitForRelevantFonts(config);\n }\n\n const fabricInstance = this.getFabricCanvasFromContainer(container);\n if (!fabricInstance?.getObjects) return;\n\n this.logFabricTextParitySnapshot('before-stable-text-metrics', fabricInstance);\n\n const waitForPaint = () => new Promise<void>((r) => requestAnimationFrame(() => requestAnimationFrame(() => r())));\n\n // Underline-fix: never call `initDimensions()` on textboxes in the package\n // capture path. `initDimensions` calls `_clearCache` which wipes\n // `__charBounds` AND `__lineWidths`. Fabric then repopulates\n // `__lineWidths` immediately but **`__charBounds` only fills lazily on the\n // next paint**. The PNG path in `renderPageViaPreviewCanvas` copies\n // `lowerCanvasEl` to an export canvas right after this — if the next\n // Fabric render hasn't actually flushed by then, `_renderTextDecoration`\n // ends up drawing the underline from a stale/empty charBounds and falls\n // back to spanning the full textbox width. The PDF path goes through\n // `toSVG()` which serializes from `__lineWidths` directly, so it stays\n // correct — that's why PDF was right but PNG was wrong.\n //\n // Fix: don't re-measure. Just (a) prime `__charBounds` for every textbox\n // by calling `getLineWidth` on each line (idempotent, populates the cache\n // in-place without touching width/scale), (b) mark everything dirty so\n // Fabric repaints with the now-loaded fonts, then (c) force a\n // SYNCHRONOUS `renderAll()` BEFORE the caller copies the canvas — so the\n // underline is painted from the freshly-primed charBounds.\n const primeCharBounds = (obj: unknown) => {\n if (isFabricTextboxLike(obj)) {\n // CENTER-ALIGN PARITY FIX: Invalidate stale per-line measurements so\n // Fabric re-measures using the now-loaded webfont metrics. Without\n // this, `__lineWidths` (and `__charBounds`) may have been populated\n // earlier against a fallback font — fabric's `toSVG()` then centers\n // each line based on those stale widths, which visibly drifts only\n // centered/right-aligned text while left-aligned text looks correct.\n //\n // We deliberately do NOT call `initDimensions()` here — that would\n // also re-flow word-wrap and change `width`, breaking underline\n // baking. Clearing only the line/char caches forces a re-measure\n // through the standard `getLineWidth()` path WITHOUT touching the\n // textbox dimensions.\n try {\n (obj as any).__lineWidths = [];\n (obj as any).__lineHeights = [];\n (obj as any).__charBounds = [];\n } catch {\n // ignore — fall back to existing cache\n }\n const lines = (obj as any)._textLines as unknown[] | undefined;\n if (Array.isArray(lines)) {\n for (let i = 0; i < lines.length; i++) {\n try {\n (obj as any).getLineWidth(i);\n } catch {\n // ignore — Fabric will recompute on next paint\n }\n }\n }\n obj.dirty = true;\n return;\n }\n if (isFabricGroupLike(obj)) {\n obj.getObjects().forEach(primeCharBounds);\n obj.dirty = true;\n }\n };\n\n // Critical: object-level cache invalidation is NOT enough. Fabric also has\n // a process-global character-width cache keyed by font declaration. If any\n // textbox measured before webfonts finished loading, clearing only\n // `__lineWidths` just repopulates them from fallback values in that global\n // cache. Flush it immediately before priming char bounds so center/right\n // offsets are recomputed from the real loaded font metrics.\n // GLITCH FIX: `clearFabricCharCache()` is process-global. Calling it from\n // the PDF-export path (which runs while the live preview canvas is still\n // mounted on /use/:id) wipes the char-width cache that the visible\n // canvas's already-rendered textboxes rely on. The next time the visible\n // canvas repaints, Fabric re-measures with the (now-empty) cache and the\n // auto-shrunk textbox reflows back to its natural grow-and-push height —\n // pushing siblings down. Only clear when the caller explicitly opts in\n // (PNG export path, where no live preview is mounted simultaneously).\n if (options.clearGlobalCharCache !== false) {\n try { clearFabricCharCache(); } catch {}\n }\n fabricInstance.getObjects().forEach(primeCharBounds);\n fabricInstance.calcOffset?.();\n // Synchronous render — guarantees `_renderTextDecoration` runs against\n // the freshly-primed `__charBounds` before the PNG capture reads\n // `lowerCanvasEl`.\n fabricInstance.renderAll?.();\n await waitForPaint();\n // Second sync render after rAF — covers any late font-load reflow that\n // re-marks objects dirty between the first render and the capture.\n fabricInstance.renderAll?.();\n await waitForPaint();\n this.logFabricTextParitySnapshot('after-stable-text-metrics', fabricInstance);\n }\n}\n","/**\n * PDF Export Module for @pixldocs/canvas-renderer\n * \n * Assembles vector PDFs from SVG render results using jsPDF + svg2pdf.js.\n * Extracted from the main app's vectorPdfExport.ts — contains only the\n * SVG processing pipeline (no app-specific dependencies).\n */\n\nimport { jsPDF, ShadingPattern } from 'jspdf';\nimport { svg2pdf } from 'svg2pdf.js';\nimport type { SvgRenderResult } from './renderer';\nimport { PACKAGE_VERSION } from './renderer';\nimport { embedFontsInPdf, rewriteSvgFontsForJsPDF } from './pdf-fonts';\n\n// ─── Types ───\n\nexport interface PdfRenderResult {\n /** PDF as a Blob */\n blob: Blob;\n /** PDF as ArrayBuffer */\n arrayBuffer: ArrayBuffer;\n /** Total number of pages */\n totalPages: number;\n /** Page dimensions (CSS pixels) */\n pages: Array<{ width: number; height: number }>;\n}\n\nexport interface PdfAssemblyOptions {\n /** PDF document title */\n title?: string;\n /** Output filename hint */\n filename?: string;\n /** Whether to strip page background from SVG (drawn separately for gradient support) */\n stripPageBackground?: boolean;\n /** Base URL for TTF font files (e.g. 'https://pixldocs.com/fonts/' or '/fonts/'). Required for correct font rendering. */\n fontBaseUrl?: string;\n /** Convert SVG text to paths before svg2pdf. Default: false — keep live Fabric SVG text for preview/PDF metric parity. */\n outlineText?: boolean;\n /**\n * Per-template text rendering mode.\n * - 'auto' : outline gradient-filled text only; other text remains selectable.\n * - 'selectable' : keep text live; gradient text falls back to first gradient stop.\n * - 'pixel-perfect' : outline every <text> for 100% visual parity.\n * When omitted, falls back to `outlineText` (legacy boolean) for backwards compatibility.\n */\n textMode?: 'auto' | 'selectable' | 'pixel-perfect';\n}\n\n// ─── Constants ───\n\n// ─── Parity diagnostics helper ───\n// Walks an SVG string and logs textbox-relevant info so we can compare the\n// in-package PDF pipeline against the working UsePackage client vector path.\n// The host page should call dumpSvgTextDiagnosticsExternal at the same stages.\nfunction logParityJson(tag: string, stage: string, payload: Record<string, unknown>): void {\n try {\n console.log(`${tag} ${stage} ${JSON.stringify(payload, (_key, value) => {\n if (typeof value !== 'number') return value;\n return Number.isFinite(value) ? Number(value.toFixed(3)) : value;\n })}`);\n } catch {\n console.log(`${tag} ${stage}`, payload);\n }\n}\n\nexport function dumpSvgTextDiagnostics(\n svgStr: string,\n pageIndex: number,\n tag: string,\n stage: string,\n maxItems = 30,\n): void {\n try {\n if (typeof DOMParser === 'undefined') return;\n const doc = new DOMParser().parseFromString(svgStr, 'image/svg+xml');\n if (doc.querySelector('parsererror')) {\n console.warn(`${tag} page=${pageIndex} stage=${stage} parse-error`);\n return;\n }\n const root = doc.documentElement;\n const svgWidth = root?.getAttribute('width');\n const svgHeight = root?.getAttribute('height');\n const svgViewBox = root?.getAttribute('viewBox');\n\n const texts = Array.from(doc.querySelectorAll('text'));\n const summary = {\n page: pageIndex,\n stage,\n svgLen: svgStr.length,\n svgWidth,\n svgHeight,\n svgViewBox,\n textCount: texts.length,\n };\n logParityJson(tag, stage, { kind: 'summary', ...summary });\n\n const sample = texts.slice(0, maxItems).map((t, idx) => {\n const tspans = Array.from(t.querySelectorAll('tspan'));\n const tspanInfo = tspans.slice(0, 8).map((s) => ({\n x: s.getAttribute('x'),\n y: s.getAttribute('y'),\n fs: s.getAttribute('font-style'),\n fw: s.getAttribute('font-weight'),\n ff: s.getAttribute('font-family'),\n td: s.getAttribute('text-decoration'),\n style: (s.getAttribute('style') || '').slice(0, 120),\n text: (s.textContent || '').slice(0, 40),\n }));\n // Walk up to find any width attribute on ancestors (textbox container)\n let containerWidth: string | null = null;\n let cursor: Element | null = t.parentElement;\n while (cursor && !containerWidth) {\n containerWidth = cursor.getAttribute?.('width');\n cursor = cursor.parentElement;\n if (cursor && cursor.tagName?.toLowerCase() === 'svg') break;\n }\n return {\n idx,\n x: t.getAttribute('x'),\n y: t.getAttribute('y'),\n fontSize: t.getAttribute('font-size'),\n fontFamily: t.getAttribute('font-family'),\n fontWeight: t.getAttribute('font-weight'),\n textAnchor: t.getAttribute('text-anchor'),\n transform: t.getAttribute('transform'),\n style: (t.getAttribute('style') || '').slice(0, 120),\n ancestorWidth: containerWidth,\n textContent: (t.textContent || '').slice(0, 60),\n tspanCount: tspans.length,\n tspanSample: tspanInfo,\n };\n });\n logParityJson(tag, stage, { kind: 'text-sample', page: pageIndex, count: sample.length, total: texts.length, sample });\n } catch (err) {\n console.warn(`${tag} ${stage} page=${pageIndex} dump threw`, err);\n }\n}\n\n\nconst SVG_DRAWABLE_TAGS = new Set([\n 'path', 'rect', 'circle', 'ellipse', 'polygon', 'polyline', 'line', 'text', 'tspan',\n]);\n\nconst SVG_DEFINITION_CONTAINER_TAGS = new Set([\n 'defs', 'clippath', 'mask', 'pattern', 'marker', 'symbol', 'filter',\n 'lineargradient', 'radialgradient',\n]);\n\nconst SVG_STYLE_PROPS = new Set([\n 'fill', 'stroke', 'color', 'opacity', 'fill-opacity', 'stroke-opacity',\n 'fill-rule', 'stroke-width', 'stroke-linecap', 'stroke-linejoin',\n 'stroke-miterlimit', 'stroke-dasharray', 'stroke-dashoffset', 'display',\n 'visibility', 'stop-color', 'stop-opacity', 'clip-rule', 'clip-path',\n 'mask', 'filter',\n]);\n\nconst GRADIENT_ATTRS_LINEAR = ['x1', 'y1', 'x2', 'y2', 'gradientUnits', 'gradientTransform', 'spreadMethod'];\nconst GRADIENT_ATTRS_RADIAL = ['cx', 'cy', 'r', 'fx', 'fy', 'gradientUnits', 'gradientTransform', 'spreadMethod'];\n\nconst URL_GRADIENT_RE = /^\\s*url\\s*\\(\\s*(['\"]?)([^)]+?)\\1\\s*\\)/i;\n\n/** Browser SVG-filter rasterization renders soft shadows a little denser than Canvas2D. */\nconst SHADOW_RASTER_ALPHA_COMPENSATION = 0.84;\n\n/**\n * Scan an SVG markup fragment for every distinct font-family / font-weight /\n * font-style combination used by `<text>` / `<tspan>` elements. Returns a\n * list of CSS `font-shorthand` specs suitable for `document.fonts.load(spec)`.\n * Used by the shadow rasterizer to deterministically wait for every font\n * needed inside the offscreen SVG-in-img render — without this the shadow\n * silhouette occasionally paints with a fallback font and visibly drifts\n * from the real text above it.\n */\nfunction collectFontSpecsFromMarkup(markup: string): string[] {\n const specs = new Set<string>();\n const re = /<(?:text|tspan)\\b[^>]*>/gi;\n let match: RegExpExecArray | null;\n while ((match = re.exec(markup)) !== null) {\n const tag = match[0];\n const get = (attr: string): string | null => {\n const m = tag.match(new RegExp(`\\\\s${attr}\\\\s*=\\\\s*\"([^\"]*)\"`, 'i'));\n if (m) return m[1];\n const styleM = tag.match(/\\sstyle\\s*=\\s*\"([^\"]*)\"/i);\n if (styleM) {\n const sm = styleM[1].match(new RegExp(`${attr}\\\\s*:\\\\s*([^;]+)`, 'i'));\n if (sm) return sm[1].trim();\n }\n return null;\n };\n const family = (get('font-family') || '').split(',')[0].replace(/['\"]/g, '').trim();\n if (!family) continue;\n const weight = get('font-weight') || '400';\n const style = get('font-style') || 'normal';\n const size = get('font-size') || '16px';\n const sizePx = /[a-z%]/i.test(size) ? size : `${size}px`;\n // Quote families with spaces.\n const famSpec = /\\s/.test(family) ? `\"${family}\"` : family;\n specs.add(`${style} ${weight} ${sizePx} ${famSpec}`);\n }\n return Array.from(specs);\n}\n\n// ─── Color Parsing ───\n\nfunction parseColor(color: string | undefined): { r: number; g: number; b: number } | null {\n if (!color) return null;\n const raw = color.trim().toLowerCase();\n if (!raw || raw === 'transparent' || raw === 'none') return null;\n\n const clamp = (value: number) => Math.max(0, Math.min(255, Math.round(value)));\n const parseNumeric = (token: string) => {\n const value = parseFloat(token);\n return Number.isFinite(value) ? value : NaN;\n };\n const parseRgbComponent = (token: string) => {\n const value = parseNumeric(token);\n if (!Number.isFinite(value)) return NaN;\n return token.endsWith('%') ? (value / 100) * 255 : value;\n };\n const parseAlpha = (token: string | undefined): number => {\n if (!token) return 1;\n const value = parseNumeric(token);\n if (!Number.isFinite(value)) return 1;\n return token.endsWith('%') ? value / 100 : value;\n };\n\n const toRgbFromHsl = (h: number, s: number, l: number) => {\n const hue = ((h % 360) + 360) % 360;\n const sat = Math.max(0, Math.min(1, s));\n const light = Math.max(0, Math.min(1, l));\n if (sat === 0) {\n const gray = clamp(light * 255);\n return { r: gray, g: gray, b: gray };\n }\n const q = light < 0.5 ? light * (1 + sat) : light + sat - light * sat;\n const p = 2 * light - q;\n const hueToRgb = (t: number) => {\n let tt = t;\n if (tt < 0) tt += 1;\n if (tt > 1) tt -= 1;\n if (tt < 1 / 6) return p + (q - p) * 6 * tt;\n if (tt < 1 / 2) return q;\n if (tt < 2 / 3) return p + (q - p) * (2 / 3 - tt) * 6;\n return p;\n };\n return {\n r: clamp(hueToRgb(hue / 360 + 1 / 3) * 255),\n g: clamp(hueToRgb(hue / 360) * 255),\n b: clamp(hueToRgb(hue / 360 - 1 / 3) * 255),\n };\n };\n\n if (raw.startsWith('#')) {\n const hex = raw.slice(1);\n const expanded = hex.length === 3 || hex.length === 4\n ? hex.split('').map((char) => char + char).join('')\n : hex;\n if (expanded.length !== 6 && expanded.length !== 8) return null;\n const intValue = parseInt(expanded.slice(0, 6), 16);\n if (!Number.isFinite(intValue)) return null;\n if (expanded.length === 8) {\n const alphaHex = parseInt(expanded.slice(6, 8), 16);\n if (Number.isFinite(alphaHex) && alphaHex <= 0) return null;\n }\n return { r: (intValue >> 16) & 255, g: (intValue >> 8) & 255, b: intValue & 255 };\n }\n\n const rgbMatch = raw.match(/^rgba?\\((.+)\\)$/);\n if (rgbMatch) {\n const normalized = rgbMatch[1].replace(/\\//g, ' ').replace(/,/g, ' ');\n const parts = normalized.split(/\\s+/).filter(Boolean);\n if (parts.length >= 3) {\n const alpha = parseAlpha(parts[3]);\n if (alpha <= 0) return null;\n const r = parseRgbComponent(parts[0]);\n const g = parseRgbComponent(parts[1]);\n const b = parseRgbComponent(parts[2]);\n if (Number.isFinite(r) && Number.isFinite(g) && Number.isFinite(b)) {\n return { r: clamp(r), g: clamp(g), b: clamp(b) };\n }\n }\n }\n\n const hslMatch = raw.match(/^hsla?\\((.+)\\)$/);\n if (hslMatch) {\n const normalized = hslMatch[1].replace(/\\//g, ' ').replace(/,/g, ' ');\n const parts = normalized.split(/\\s+/).filter(Boolean);\n if (parts.length >= 3) {\n const alpha = parseAlpha(parts[3]);\n if (alpha <= 0) return null;\n const h = parseNumeric(parts[0].replace(/deg$/, ''));\n const sRaw = parseNumeric(parts[1].replace(/%$/, ''));\n const lRaw = parseNumeric(parts[2].replace(/%$/, ''));\n if (Number.isFinite(h) && Number.isFinite(sRaw) && Number.isFinite(lRaw)) {\n return toRgbFromHsl(h, sRaw / 100, lRaw / 100);\n }\n }\n }\n\n return null;\n}\n\nfunction rgbToHex(r: number, g: number, b: number): string {\n return '#' + [r, g, b].map((x) => Math.max(0, Math.min(255, Math.round(x))).toString(16).padStart(2, '0')).join('');\n}\n\nfunction cssColorToHex(css: string): string | null {\n const s = css.trim();\n if (/^#[0-9a-f]{3}$/i.test(s)) {\n const r = s[1] + s[1], g = s[2] + s[2], b = s[3] + s[3];\n return '#' + r + g + b;\n }\n if (/^#[0-9a-f]{6}$/i.test(s)) return s;\n if (/^#[0-9a-f]{8}$/i.test(s)) return '#' + s.slice(1, 7);\n const rgb = s.match(/^rgba?\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/i);\n if (rgb) {\n const r = Number(rgb[1]).toString(16).padStart(2, '0');\n const g = Number(rgb[2]).toString(16).padStart(2, '0');\n const b = Number(rgb[3]).toString(16).padStart(2, '0');\n return '#' + r + g + b;\n }\n if (typeof document === 'undefined') return null;\n const div = document.createElement('div');\n div.style.color = s;\n const computed = document.defaultView?.getComputedStyle(div).color;\n if (!computed || !computed.startsWith('rgb')) return null;\n const m = computed.match(/\\d+/g);\n if (!m || m.length < 3) return null;\n return '#' + [m[0], m[1], m[2]].map(v => Number(v).toString(16).padStart(2, '0')).join('');\n}\n\n// ─── SVG Helpers ───\n\nfunction isInSvgDefinitionSubtree(el: Element): boolean {\n let current: Element | null = el;\n while (current) {\n if (SVG_DEFINITION_CONTAINER_TAGS.has(current.tagName?.toLowerCase() ?? '')) return true;\n current = current.parentElement;\n }\n return false;\n}\n\nfunction parseInlineSvgStyleDeclarations(styleText: string): Array<{ key: string; value: string }> {\n return styleText\n .split(';')\n .map((part) => part.trim())\n .filter(Boolean)\n .map((part) => {\n const idx = part.indexOf(':');\n if (idx <= 0) return null;\n return { key: part.slice(0, idx).trim().toLowerCase(), value: part.slice(idx + 1).trim() };\n })\n .filter((x): x is { key: string; value: string } => !!x);\n}\n\nfunction extractGradientIdFromPaint(value: string | null): string | null {\n if (!value) return null;\n const match = value.trim().match(URL_GRADIENT_RE);\n if (!match) return null;\n const rawRef = (match[2] || '').trim();\n if (!rawRef) return null;\n const hashIdx = rawRef.lastIndexOf('#');\n if (hashIdx < 0 || hashIdx === rawRef.length - 1) return null;\n const id = rawRef.slice(hashIdx + 1).trim();\n if (!id) return null;\n return id.replace(/[\\s\"')].*$/, '');\n}\n\nfunction normalizeGradientPaintRef(value: string): string {\n const id = extractGradientIdFromPaint(value);\n return id ? `url(#${id})` : value;\n}\n\nfunction findGradientInTree(svgRoot: Element, gradientId: string): Element | null {\n for (const el of svgRoot.querySelectorAll('[id]')) {\n if (el.getAttribute('id') === gradientId) return el;\n }\n return null;\n}\n\nfunction getInlineStyleValue(el: Element, key: string): string | null {\n const style = el.getAttribute('style') || '';\n if (!style) return null;\n const hit = parseInlineSvgStyleDeclarations(style).find((decl) => decl.key === key);\n return hit?.value ?? null;\n}\n\nfunction isTransparentColorToken(value: string | null): boolean {\n if (!value) return false;\n const s = value.trim().toLowerCase();\n if (!s || s === 'none' || s === 'transparent') return true;\n if (/^#[0-9a-f]{8}$/i.test(s)) {\n return Number.parseInt(s.slice(7, 9), 16) === 0;\n }\n const rgba = s.match(/^rgba\\s*\\(([^)]+)\\)$/i);\n if (rgba) {\n const parts = rgba[1].split(',').map((part) => part.trim());\n if (parts.length >= 4) {\n const alpha = parseSvgOpacity(parts[3]);\n return alpha != null && alpha <= 0.0001;\n }\n }\n return false;\n}\n\nfunction parseSvgOpacity(value: string | null): number | null {\n if (!value) return null;\n const raw = value.trim();\n if (!raw) return null;\n if (raw.endsWith('%')) {\n const pct = Number.parseFloat(raw.slice(0, -1));\n if (!Number.isFinite(pct)) return null;\n return Math.max(0, Math.min(1, pct / 100));\n }\n const n = Number.parseFloat(raw);\n if (!Number.isFinite(n)) return null;\n return Math.max(0, Math.min(1, n));\n}\n\nfunction formatSvgOpacity(value: number): string {\n return Number(Math.max(0, Math.min(1, value)).toFixed(4)).toString();\n}\n\nfunction multiplySvgOpacityAttr(\n el: Element,\n attr: 'opacity' | 'fill-opacity' | 'stroke-opacity' | 'stop-opacity',\n factor: number,\n): void {\n const existing = parseSvgOpacity(el.getAttribute(attr));\n el.setAttribute(attr, formatSvgOpacity((existing ?? 1) * factor));\n}\n\n// ─── SVG Style Inlining ───\n\nfunction inlineSvgStyleBlockDeclarations(svg: Element): void {\n const styleNodes = Array.from(svg.querySelectorAll('style'));\n if (styleNodes.length === 0) return;\n\n const cssText = styleNodes.map((node) => node.textContent || '').join('\\n').replace(/\\/\\*[\\s\\S]*?\\*\\//g, ' ');\n if (!cssText.trim()) return;\n\n const allElements = [svg, ...Array.from(svg.querySelectorAll('*'))];\n const classIndex = new Map<string, Element[]>();\n allElements.forEach((el) => {\n (el.getAttribute('class') || '').split(/\\s+/).map((t) => t.trim()).filter(Boolean).forEach((token) => {\n const list = classIndex.get(token) ?? [];\n list.push(el);\n classIndex.set(token, list);\n });\n });\n\n const normalizePresentationValue = (key: string, value: string): string => {\n // Strip !important — valid in CSS but invalid in SVG presentation attributes\n const cleaned = value.replace(/\\s*!important\\s*$/i, '').trim();\n if (['fill', 'stroke', 'clip-path', 'mask', 'filter'].includes(key)) return normalizeGradientPaintRef(cleaned);\n return cleaned;\n };\n\n const applyDeclarations = (elements: Iterable<Element>, declarations: Array<{ key: string; value: string }>) => {\n for (const el of elements) {\n const inlineDeclMap = new Map(\n parseInlineSvgStyleDeclarations(el.getAttribute('style') || '').map(({ key, value }) => [key, value]),\n );\n for (const { key, value } of declarations) {\n if (!value || inlineDeclMap.has(key)) continue;\n el.setAttribute(key, normalizePresentationValue(key, value));\n }\n }\n };\n\n const ruleRegex = /([^{}]+)\\{([^}]*)\\}/g;\n let ruleMatch: RegExpExecArray | null;\n while ((ruleMatch = ruleRegex.exec(cssText))) {\n const selectors = ruleMatch[1].split(',').map((s) => s.trim()).filter(Boolean);\n const declarations = parseInlineSvgStyleDeclarations(ruleMatch[2]).filter((d) => SVG_STYLE_PROPS.has(d.key));\n if (selectors.length === 0 || declarations.length === 0) continue;\n for (const selector of selectors) {\n if (!selector || selector.startsWith('@')) continue;\n const classOnlyMatch = selector.match(/^\\.([A-Za-z_][\\w-]*)$/);\n if (classOnlyMatch) {\n applyDeclarations(classIndex.get(classOnlyMatch[1]) ?? [], declarations);\n continue;\n }\n try { applyDeclarations(svg.querySelectorAll(selector), declarations); } catch {\n const classMatch = selector.match(/\\.([A-Za-z0-9_-]+)/);\n if (classMatch) applyDeclarations(classIndex.get(classMatch[1]) ?? [], declarations);\n }\n }\n }\n\n for (const el of allElements) {\n const style = el.getAttribute('style');\n if (!style) continue;\n const keptDecls: string[] = [];\n let changed = false;\n for (const { key, value } of parseInlineSvgStyleDeclarations(style)) {\n if (SVG_STYLE_PROPS.has(key)) {\n el.setAttribute(key, normalizePresentationValue(key, value));\n changed = true;\n } else {\n keptDecls.push(`${key}: ${value}`);\n }\n }\n if (changed) {\n if (keptDecls.length > 0) el.setAttribute('style', keptDecls.join('; '));\n else el.removeAttribute('style');\n }\n }\n\n for (const styleNode of styleNodes) {\n const css = styleNode.textContent || '';\n let cleaned = css;\n for (const prop of SVG_STYLE_PROPS) {\n const regex = new RegExp(`${prop.replace(/[-/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&')}\\\\s*:\\\\s*[^;}{]+;?`, 'gi');\n cleaned = cleaned.replace(regex, '');\n }\n styleNode.textContent = cleaned\n .replace(/;\\s*;/g, ';').replace(/\\{\\s*;/g, '{').replace(/;\\s*}/g, '}').replace(/\\{\\s*}/g, '{}');\n }\n}\n\n// ─── SVG Color Normalization ───\n\nfunction normalizeSvgExplicitColors(svg: Element): Element {\n const clone = svg.cloneNode(true) as Element;\n inlineSvgStyleBlockDeclarations(clone);\n\n const getAttr = (el: Element, attr: 'fill' | 'stroke' | 'color'): string | null => {\n const v = el.getAttribute(attr) ?? (el as SVGElement).style?.getPropertyValue(attr);\n if (!v) return null;\n const s = v.trim().toLowerCase();\n if (!s || s === 'none' || s === 'transparent' || s === 'currentcolor') return null;\n return normalizeGradientPaintRef(v);\n };\n\n const hasExplicitNonePaint = (el: Element, attr: 'fill' | 'stroke'): boolean => {\n const raw = (el.getAttribute(attr) ?? (el as SVGElement).style?.getPropertyValue(attr) ?? '').trim().toLowerCase();\n if (raw === 'none' || raw === 'transparent') return true;\n const rawOpacity = (el.getAttribute(`${attr}-opacity`) ?? (el as SVGElement).style?.getPropertyValue(`${attr}-opacity`) ?? '').trim().toLowerCase();\n return rawOpacity === '0' || rawOpacity === '0%' || rawOpacity === '0.0';\n };\n\n function walk(el: Element, parentFill: string | null, parentStroke: string | null, parentColor: string | null) {\n if (isInSvgDefinitionSubtree(el)) {\n for (let i = 0; i < el.children.length; i++) walk(el.children[i], null, null, null);\n return;\n }\n const tag = el.tagName?.toLowerCase() ?? '';\n const isDrawable = SVG_DRAWABLE_TAGS.has(tag);\n let fill = getAttr(el, 'fill');\n let stroke = getAttr(el, 'stroke');\n const color = getAttr(el, 'color') ?? parentColor;\n const fillNone = hasExplicitNonePaint(el, 'fill');\n const strokeNone = hasExplicitNonePaint(el, 'stroke');\n const inheritedFill = parentFill === 'none' ? null : parentFill;\n const inheritedStroke = parentStroke === 'none' ? null : parentStroke;\n\n if (isDrawable) {\n if (fillNone) { el.setAttribute('fill', 'none'); fill = null; }\n else {\n const resolved = fill ?? color ?? inheritedFill;\n if (resolved) { el.setAttribute('fill', resolved); fill = resolved; }\n else if (tag !== 'text' && tag !== 'tspan') { el.setAttribute('fill', 'none'); fill = null; }\n }\n }\n if (isDrawable) {\n if (strokeNone) { el.setAttribute('stroke', 'none'); stroke = null; }\n else if (stroke != null || color != null || inheritedStroke != null) {\n const resolved = stroke ?? color ?? inheritedStroke;\n if (resolved) { el.setAttribute('stroke', resolved); stroke = resolved; }\n }\n }\n\n const nextColor = color ?? parentColor;\n const nextFill = fillNone ? 'none' : (fill ?? inheritedFill);\n const nextStroke = strokeNone ? 'none' : (stroke ?? inheritedStroke);\n for (let i = 0; i < el.children.length; i++) walk(el.children[i], nextFill, nextStroke, nextColor);\n }\n\n const rootColor = getAttr(clone, 'color') ?? (clone.getAttribute('color') || null);\n const rootFill = getAttr(clone, 'fill') ?? rootColor;\n const rootStroke = getAttr(clone, 'stroke') ?? rootColor;\n const rootFillNone = hasExplicitNonePaint(clone, 'fill');\n const rootStrokeNone = hasExplicitNonePaint(clone, 'stroke');\n\n if (rootFillNone) clone.setAttribute('fill', 'none');\n else if (rootFill) clone.setAttribute('fill', rootFill);\n if (rootStrokeNone) clone.setAttribute('stroke', 'none');\n else if (rootStroke) clone.setAttribute('stroke', rootStroke);\n\n for (let i = 0; i < clone.children.length; i++) {\n walk(clone.children[i], rootFillNone ? 'none' : (rootFill ?? null), rootStrokeNone ? 'none' : (rootStroke ?? null), rootColor);\n }\n\n return clone;\n}\n\n// ─── SVG Opacity ───\n\nfunction bakeGroupOpacityIntoChildren(svg: Element): void {\n const DRAWABLE = new Set(['path', 'rect', 'circle', 'ellipse', 'polygon', 'polyline', 'line', 'text', 'tspan']);\n function walkAndBake(el: Element, inheritedOpacity: number): void {\n if (isInSvgDefinitionSubtree(el)) {\n for (let i = 0; i < el.children.length; i++) walkAndBake(el.children[i], 1);\n return;\n }\n const tag = el.tagName?.toLowerCase() ?? '';\n const opacityAttr = parseSvgOpacity(el.getAttribute('opacity'));\n const styleOpacity = parseSvgOpacity((el as SVGElement).style?.getPropertyValue('opacity') || null);\n const ownOpacity = opacityAttr ?? styleOpacity ?? 1;\n const combinedOpacity = inheritedOpacity * ownOpacity;\n // PARITY with src/lib/vectorPdfExport.ts — preserve <image> opacity since\n // svg2pdf has no fill-opacity channel for raster <image> elements.\n if (ownOpacity < 0.999 && tag !== 'image') {\n el.removeAttribute('opacity');\n if ((el as SVGElement).style?.opacity) (el as SVGElement).style.removeProperty('opacity');\n }\n if (DRAWABLE.has(tag) && combinedOpacity < 0.999) {\n multiplySvgOpacityAttr(el, 'fill-opacity', combinedOpacity);\n multiplySvgOpacityAttr(el, 'stroke-opacity', combinedOpacity);\n }\n if (tag === 'image' && combinedOpacity < 0.999) {\n el.setAttribute('opacity', String(Number(combinedOpacity.toFixed(4))));\n if ((el as SVGElement).style?.opacity) (el as SVGElement).style.removeProperty('opacity');\n }\n if (tag === 'stop' && ownOpacity < 0.999) {\n multiplySvgOpacityAttr(el, 'stop-opacity', ownOpacity);\n }\n for (let i = 0; i < el.children.length; i++) walkAndBake(el.children[i], combinedOpacity);\n }\n walkAndBake(svg, 1);\n}\n\n// ─── SVG Sanitization ───\n\nfunction hasInvalidSvgNumericToken(value: string | null | undefined): value is string {\n return typeof value === 'string' && /\\b(?:NaN|-?Infinity|undefined|null)\\b/.test(value);\n}\n\nfunction sanitizeSvgNumericTokens(value: string): string {\n return value\n .replace(/\\bNaN\\b/g, '0')\n .replace(/\\b-?Infinity\\b/g, '0')\n .replace(/\\bundefined\\b/g, '0')\n .replace(/\\bnull\\b/g, '0');\n}\n\nfunction sanitizeSvgTreeForPdf(svg: Element): void {\n const attrsToSanitize = [\n 'd', 'points', 'transform', 'gradientTransform', 'patternTransform', 'viewBox',\n 'x', 'y', 'x1', 'y1', 'x2', 'y2', 'cx', 'cy', 'r', 'rx', 'ry', 'width', 'height',\n 'dx', 'dy', 'opacity', 'fill-opacity', 'stroke-opacity', 'stroke-width',\n 'stroke-dashoffset', 'font-size', 'letter-spacing', 'word-spacing',\n ];\n const nodes = [svg, ...Array.from(svg.querySelectorAll('*'))];\n for (const node of nodes) {\n for (const attr of attrsToSanitize) {\n const value = node.getAttribute(attr);\n if (!hasInvalidSvgNumericToken(value)) continue;\n node.setAttribute(attr, sanitizeSvgNumericTokens(value));\n }\n }\n}\n\n// ─── SVG Gradient Processing ───\n\nfunction normalizeSvgGradientStopOffsets(svg: Element): void {\n for (const stop of svg.querySelectorAll('linearGradient stop, radialGradient stop')) {\n const offset = stop.getAttribute('offset');\n if (!offset) continue;\n const trimmed = offset.trim();\n if (trimmed.endsWith('%')) {\n const num = parseFloat(trimmed.slice(0, -1)) / 100;\n if (Number.isFinite(num)) stop.setAttribute('offset', String(Math.max(0, Math.min(1, num))));\n }\n }\n}\n\nfunction copyGradientAttrsFromRef(gradient: Element, ref: Element): void {\n const tag = gradient.tagName?.toLowerCase();\n const attrs = tag === 'radialgradient' ? GRADIENT_ATTRS_RADIAL : GRADIENT_ATTRS_LINEAR;\n for (const name of attrs) {\n if (!gradient.hasAttribute(name) && ref.hasAttribute(name)) {\n gradient.setAttribute(name, ref.getAttribute(name)!);\n }\n }\n}\n\nfunction expandSvgGradientHrefs(svg: Element): void {\n const visited = new Set<string>();\n function expand(gradient: Element): void {\n const id = gradient.getAttribute('id');\n if (!id || visited.has(id)) return;\n visited.add(id);\n if (gradient.querySelectorAll('stop').length > 0) return;\n const href = (gradient.getAttribute('href') || gradient.getAttribute('xlink:href') || '').trim();\n if (!href.startsWith('#')) return;\n const ref = findGradientInTree(svg, href.slice(1));\n if (!ref) return;\n expand(ref);\n copyGradientAttrsFromRef(gradient, ref);\n for (const stop of ref.querySelectorAll('stop')) gradient.appendChild(stop.cloneNode(true));\n gradient.removeAttribute('href');\n gradient.removeAttribute('xlink:href');\n }\n for (const g of svg.querySelectorAll('linearGradient, radialGradient')) expand(g);\n}\n\n// ─── SVG <use> Expansion ───\n\nfunction expandSvgUseElements(svg: Element): void {\n const doc = svg.ownerDocument;\n for (const use of Array.from(svg.querySelectorAll('use'))) {\n const ref = (use.getAttribute('href') || use.getAttribute('xlink:href') || '').trim();\n if (!ref.startsWith('#')) continue;\n const target = doc.getElementById(ref.slice(1));\n if (!target) continue;\n const x = parseFloat(use.getAttribute('x') || '0') || 0;\n const y = parseFloat(use.getAttribute('y') || '0') || 0;\n const w = parseFloat(use.getAttribute('width') || '0') || 0;\n const h = parseFloat(use.getAttribute('height') || '0') || 0;\n const g = doc.createElementNS('http://www.w3.org/2000/svg', 'g');\n if (target.tagName?.toLowerCase() === 'symbol') {\n const viewBox = target.getAttribute('viewBox');\n for (let i = 0; i < target.children.length; i++) g.appendChild(target.children[i].cloneNode(true));\n if (viewBox && w && h) {\n const parts = viewBox.split(/\\s+/).map(Number);\n const vbW = parts[2]; const vbH = parts[3];\n if (vbW && vbH) g.setAttribute('transform', `translate(${x},${y}) scale(${w / vbW},${h / vbH})`);\n else g.setAttribute('transform', `translate(${x},${y})`);\n } else if (x || y) g.setAttribute('transform', `translate(${x},${y})`);\n } else {\n const clone = target.cloneNode(true) as Element;\n if (x || y) g.setAttribute('transform', `translate(${x},${y})`);\n g.appendChild(clone);\n }\n if (use.parentNode) use.parentNode.replaceChild(g, use);\n }\n}\n\n// ─── SVG ViewBox Normalization ───\n\nfunction normalizeSvgViewBoxOrigin(svg: Element): void {\n const viewBox = svg.getAttribute('viewBox');\n if (!viewBox) return;\n const parts = viewBox.split(/[\\s,]+/).map(Number.parseFloat).filter(Number.isFinite);\n if (parts.length !== 4) return;\n const [vx, vy, vw, vh] = parts;\n if (vw <= 0 || vh <= 0) return;\n if (Math.abs(vx) < 0.001 && Math.abs(vy) < 0.001) return;\n\n const doc = svg.ownerDocument;\n if (!doc) return;\n const keepAtRoot = new Set(['defs', 'style', 'title', 'desc', 'metadata']);\n const translatableChildren = Array.from(svg.children).filter((c) => !keepAtRoot.has(c.tagName.toLowerCase()));\n if (translatableChildren.length === 0) { svg.setAttribute('viewBox', `0 0 ${vw} ${vh}`); return; }\n\n const wrapper = doc.createElementNS('http://www.w3.org/2000/svg', 'g');\n wrapper.setAttribute('transform', `translate(${-vx} ${-vy})`);\n for (const child of translatableChildren) wrapper.appendChild(child);\n svg.appendChild(wrapper);\n svg.setAttribute('viewBox', `0 0 ${vw} ${vh}`);\n}\n\n// ─── SVG Background Stripping ───\n\nfunction stripRootPageBackgroundFromSvg(svg: Element): void {\n for (const child of Array.from(svg.children)) {\n const tag = child.tagName.toLowerCase();\n if (tag !== 'rect' && tag !== 'path') continue;\n const x = Number.parseFloat(child.getAttribute('x') || '0');\n const y = Number.parseFloat(child.getAttribute('y') || '0');\n const width = Number.parseFloat(child.getAttribute('width') || '0');\n const height = Number.parseFloat(child.getAttribute('height') || '0');\n const fill = child.getAttribute('fill') || getInlineStyleValue(child, 'fill');\n const stroke = child.getAttribute('stroke') || getInlineStyleValue(child, 'stroke');\n const opacity = parseSvgOpacity(child.getAttribute('opacity')) ?? 1;\n const isFullPageRect = tag === 'rect' && Math.abs(x) < 0.01 && Math.abs(y) < 0.01 &&\n Math.abs(width - Number.parseFloat(svg.getAttribute('width') || '0')) < 0.5 &&\n Math.abs(height - Number.parseFloat(svg.getAttribute('height') || '0')) < 0.5;\n const isVisiblePaint = opacity > 0.0001 && !isTransparentColorToken(fill) && (!stroke || isTransparentColorToken(stroke));\n if (isFullPageRect && isVisiblePaint) { child.remove(); return; }\n }\n}\n\nfunction stripSuspiciousFullPageOverlayNodes(svg: Element): void {\n const pageWidth = Number.parseFloat(svg.getAttribute('width') || '0');\n const pageHeight = Number.parseFloat(svg.getAttribute('height') || '0');\n if (!(pageWidth > 0 && pageHeight > 0)) return;\n\n const isNear = (a: number, b: number, tolerance = 0.75) => Math.abs(a - b) <= tolerance;\n const isDarkPaint = (value: string | null) => {\n const rgb = value ? parseColor(value) : null;\n return rgb ? rgb.r <= 32 && rgb.g <= 32 && rgb.b <= 32 : false;\n };\n\n const removeIfSuspicious = (el: Element) => {\n const opacity = parseSvgOpacity(el.getAttribute('opacity')) ?? parseSvgOpacity(getInlineStyleValue(el, 'opacity')) ?? 1;\n if (opacity <= 0.001) return;\n const fill = el.getAttribute('fill') || getInlineStyleValue(el, 'fill');\n const stroke = el.getAttribute('stroke') || getInlineStyleValue(el, 'stroke');\n if (!isDarkPaint(fill) && !isDarkPaint(stroke)) return;\n const w = Number.parseFloat(el.getAttribute('width') || '0');\n const h = Number.parseFloat(el.getAttribute('height') || '0');\n const x = Number.parseFloat(el.getAttribute('x') || '0');\n const y = Number.parseFloat(el.getAttribute('y') || '0');\n const isRectLike = el.tagName.toLowerCase() === 'rect' && isNear(x, 0) && isNear(y, 0) && isNear(w, pageWidth, 1.5) && isNear(h, pageHeight, 1.5);\n if (isRectLike) el.remove();\n };\n\n for (const child of Array.from(svg.children)) {\n const tag = child.tagName.toLowerCase();\n if (['defs', 'style', 'title', 'desc', 'metadata'].includes(tag)) continue;\n if (tag === 'g') { for (const gc of Array.from(child.children)) removeIfSuspicious(gc); }\n removeIfSuspicious(child);\n }\n}\n\n// ─── Inline SVG Data URIs ───\n\nfunction decodeSvgDataUri(href: string): string | null {\n if (!href.startsWith('data:image/svg+xml')) return null;\n const commaIdx = href.indexOf(',');\n if (commaIdx < 0) return null;\n const meta = href.slice(0, commaIdx).toLowerCase();\n const payload = href.slice(commaIdx + 1);\n try {\n if (meta.includes(';base64')) {\n const binary = atob(payload);\n const bytes = Uint8Array.from(binary, (char) => char.charCodeAt(0));\n return new TextDecoder('utf-8').decode(bytes);\n }\n return decodeURIComponent(payload);\n } catch {\n try { return atob(payload); } catch { return null; }\n }\n}\n\nfunction inlineNestedSvgImageDataUris(svgString: string, domParser = new DOMParser()): string {\n try {\n const doc = domParser.parseFromString(svgString, 'image/svg+xml');\n if (doc.querySelector('parsererror')) return svgString;\n const root = doc.documentElement;\n if (!root || root.tagName.toLowerCase() !== 'svg') return svgString;\n\n let changed = false;\n for (const img of Array.from(doc.querySelectorAll('image'))) {\n const href = img.getAttribute('href') || img.getAttributeNS('http://www.w3.org/1999/xlink', 'href');\n if (!href || !href.startsWith('data:image/svg+xml')) continue;\n try {\n const svgContent = decodeSvgDataUri(href);\n if (!svgContent || !/<svg[\\s>]/i.test(svgContent)) continue;\n const innerDoc = domParser.parseFromString(svgContent, 'image/svg+xml');\n if (innerDoc.querySelector('parsererror')) continue;\n const innerSvg = innerDoc.documentElement;\n if (!innerSvg || innerSvg.tagName.toLowerCase() !== 'svg') continue;\n const ix = parseFloat(img.getAttribute('x') || '0') || 0;\n const iy = parseFloat(img.getAttribute('y') || '0') || 0;\n const iw = parseFloat(img.getAttribute('width') || '0');\n const ih = parseFloat(img.getAttribute('height') || '0');\n if (!(iw > 0 && ih > 0)) continue;\n\n const nestedSvg = doc.importNode(innerSvg, true) as unknown as SVGElement;\n if (!nestedSvg.getAttribute('viewBox')) nestedSvg.setAttribute('viewBox', `0 0 ${iw} ${ih}`);\n nestedSvg.setAttribute('x', '0'); nestedSvg.setAttribute('y', '0');\n nestedSvg.setAttribute('width', String(iw)); nestedSvg.setAttribute('height', String(ih));\n nestedSvg.setAttribute('preserveAspectRatio', img.getAttribute('preserveAspectRatio') || nestedSvg.getAttribute('preserveAspectRatio') || 'xMidYMid meet');\n\n const g = doc.createElementNS('http://www.w3.org/2000/svg', 'g');\n const existingTransform = img.getAttribute('transform') || '';\n g.setAttribute('transform', `${existingTransform}${existingTransform ? ' ' : ''}translate(${ix},${iy})`);\n for (const attr of Array.from(img.attributes)) {\n if (['id', 'class', 'style', 'opacity', 'display', 'visibility', 'clip-path', 'mask', 'filter', 'pointer-events'].includes(attr.name)) {\n g.setAttribute(attr.name, attr.value);\n }\n }\n g.appendChild(nestedSvg);\n img.parentNode?.replaceChild(g, img);\n changed = true;\n } catch { /* skip */ }\n }\n return changed ? new XMLSerializer().serializeToString(doc.documentElement) : svgString;\n } catch { return svgString; }\n}\n\n// ─── Computed Style Inlining ───\n\nfunction inlineComputedStyles(svg: Element): void {\n if (typeof document === 'undefined') return;\n const wrap = document.createElement('div');\n wrap.style.cssText = 'position:fixed;left:-9999px;top:0;width:400px;height:400px;overflow:hidden;pointer-events:none';\n const root = svg as SVGElement;\n if (!root.hasAttribute('width')) root.setAttribute('width', '400');\n if (!root.hasAttribute('height')) root.setAttribute('height', '400');\n wrap.appendChild(root);\n document.body.appendChild(wrap);\n try {\n const drawableTags = ['path', 'rect', 'circle', 'ellipse', 'polygon', 'polyline', 'line', 'text', 'tspan'];\n function walk(el: Element) {\n const tag = el.tagName?.toLowerCase();\n if (drawableTags.includes(tag)) {\n const cs = window.getComputedStyle(el as SVGElement);\n const fill = cs.fill;\n const stroke = cs.stroke;\n if (fill && fill !== 'none' && fill !== 'rgba(0, 0, 0, 0)') {\n const parsed = parseColor(fill);\n if (parsed) el.setAttribute('fill', rgbToHex(parsed.r, parsed.g, parsed.b));\n } else if (fill === 'rgba(0, 0, 0, 0)' || fill === 'transparent') {\n el.setAttribute('fill', 'none');\n }\n if (stroke && stroke !== 'none' && stroke !== 'rgba(0, 0, 0, 0)') {\n const parsed = parseColor(stroke);\n if (parsed) el.setAttribute('stroke', rgbToHex(parsed.r, parsed.g, parsed.b));\n }\n }\n for (let i = 0; i < el.children.length; i++) walk(el.children[i]);\n }\n walk(root);\n root.remove();\n } finally {\n if (wrap.parentNode) document.body.removeChild(wrap);\n }\n}\n\n// ─── Nested SVG ID Disambiguation (prevent collisions between SVG images on same page) ───\n\nfunction disambiguateNestedSvgIds(rootSvg: Element): void {\n const nestedSvgs = Array.from(rootSvg.querySelectorAll('svg'));\n // Skip the root itself — only process nested <svg> elements (embedded images)\n const toProcess = nestedSvgs.filter((s) => s !== rootSvg);\n if (toProcess.length < 2) return; // No collision possible with 0–1 nested SVGs\n\n toProcess.forEach((nested, idx) => {\n prefixSvgIds(nested, `n${idx}`);\n });\n}\n\n// ─── SVG ID Prefixing (prevent gradient ID collisions between pages) ───\n\nfunction prefixSvgIds(svg: Element, prefix: string): void {\n const safePrefix = String(prefix).replace(/[^a-zA-Z0-9-]/g, '_');\n const idMap = new Map<string, string>();\n svg.querySelectorAll('[id]').forEach((el) => {\n const id = el.getAttribute('id');\n if (id) idMap.set(id, `${safePrefix}_${id}`);\n });\n if (idMap.size === 0) return;\n\n idMap.forEach((newId, oldId) => {\n svg.querySelectorAll(`[id=\"${oldId}\"]`).forEach((el) => el.setAttribute('id', newId));\n });\n\n const replaceUrlRefs = (value: string): string => {\n return value.replace(/url\\(\\s*(['\"]?)([^)]+?)\\1\\s*\\)/gi, (full, quoteRaw, refRaw) => {\n const ref = String(refRaw || '').trim();\n const hashIdx = ref.lastIndexOf('#');\n if (hashIdx < 0 || hashIdx === ref.length - 1) return full;\n const base = ref.slice(0, hashIdx + 1);\n const oldId = ref.slice(hashIdx + 1).trim().replace(/[\\s\"')].*$/, '');\n const mapped = idMap.get(oldId);\n if (!mapped) return full;\n const quote = String(quoteRaw || '');\n return `url(${quote}${base}${mapped}${quote})`;\n });\n };\n\n const replaceHrefRef = (value: string): string => {\n const trimmed = value.trim();\n if (trimmed.startsWith('#')) {\n const mapped = idMap.get(trimmed.slice(1));\n return mapped ? `#${mapped}` : value;\n }\n return replaceUrlRefs(value);\n };\n\n const refAttrs = ['fill', 'stroke', 'clip-path', 'mask', 'filter', 'href', 'xlink:href', 'marker-start', 'marker-mid', 'marker-end'];\n svg.querySelectorAll('*').forEach((el) => {\n refAttrs.forEach((attr) => {\n const val = el.getAttribute(attr);\n if (!val) return;\n const next = attr === 'href' || attr === 'xlink:href' ? replaceHrefRef(val) : replaceUrlRefs(val);\n if (next !== val) el.setAttribute(attr, next);\n });\n const style = el.getAttribute('style');\n if (style) {\n const nextStyle = replaceUrlRefs(style);\n if (nextStyle !== style) el.setAttribute('style', nextStyle);\n }\n });\n svg.querySelectorAll('style').forEach((styleNode) => {\n const text = styleNode.textContent || '';\n const next = replaceUrlRefs(text);\n if (next !== text) styleNode.textContent = next;\n });\n}\n\n// ─── SVG Color State Management ───\n\nfunction getFirstExplicitColorFromSvg(svg: Element): { fill: string | null; stroke: string | null } {\n let fill: string | null = null;\n let stroke: string | null = null;\n const isRealColor = (v: string | null): boolean => {\n if (!v || v === 'none') return false;\n const s = v.trim().toLowerCase();\n return s !== 'currentcolor' && s !== 'inherit' && (s.startsWith('#') || s.startsWith('rgb'));\n };\n const resolveUrl = (v: string | null): string | null => {\n if (!v || v === 'none') return null;\n const gradientId = extractGradientIdFromPaint(v);\n if (!gradientId) return null;\n return getGradientStopColorAsHex(svg, gradientId);\n };\n function walk(el: Element) {\n if (fill && stroke) return;\n const f = el.getAttribute('fill') ?? (el as SVGElement).style?.getPropertyValue('fill');\n const s = el.getAttribute('stroke') ?? (el as SVGElement).style?.getPropertyValue('stroke');\n if (!fill) {\n if (isRealColor(f)) fill = f;\n else if (f) { const resolved = resolveUrl(f); if (resolved) fill = resolved; }\n }\n if (!stroke) {\n if (isRealColor(s)) stroke = s;\n else if (s) { const resolved = resolveUrl(s); if (resolved) stroke = resolved; }\n }\n for (let i = 0; i < el.children.length; i++) walk(el.children[i]);\n }\n walk(svg);\n return { fill, stroke };\n}\n\nfunction isNearWhite(hex: string): boolean {\n if (!/^#[0-9a-f]{6}$/i.test(hex)) return false;\n const r = parseInt(hex.slice(1, 3), 16);\n const g = parseInt(hex.slice(3, 5), 16);\n const b = parseInt(hex.slice(5, 7), 16);\n return r >= 250 && g >= 250 && b >= 250;\n}\n\nfunction getStopColorRaw(stop: Element): string | null {\n return stop.getAttribute('stop-color') ?? (stop as SVGElement).style?.getPropertyValue('stop-color')?.trim() ?? getInlineStyleValue(stop, 'stop-color');\n}\n\nfunction getGradientStopColorAsHex(svgRoot: Element, gradientId: string, visited = new Set<string>()): string | null {\n if (visited.has(gradientId)) return null;\n visited.add(gradientId);\n const gradient = findGradientInTree(svgRoot, gradientId);\n if (!gradient) return null;\n const tag = gradient.tagName?.toLowerCase();\n if (tag !== 'lineargradient' && tag !== 'radialgradient') return null;\n const stops = Array.from(gradient.querySelectorAll('stop'));\n if (stops.length > 0) {\n const first = getStopColorRaw(stops[0]);\n const last = getStopColorRaw(stops[stops.length - 1]);\n const firstHex = first ? cssColorToHex(first) : null;\n const lastHex = last ? cssColorToHex(last) : null;\n if (firstHex && !isNearWhite(firstHex)) return firstHex;\n if (lastHex && !isNearWhite(lastHex)) return lastHex;\n return firstHex ?? lastHex;\n }\n const href = (gradient.getAttribute('href') || gradient.getAttribute('xlink:href') || '').trim();\n if (href.startsWith('#')) return getGradientStopColorAsHex(svgRoot, href.slice(1), visited);\n return null;\n}\n\nfunction setPdfColorFromSvg(pdf: jsPDF, svg: Element, _elementId?: string) {\n const { fill, stroke } = getFirstExplicitColorFromSvg(svg);\n const setColor = (hex: string | null, setter: 'setFillColor' | 'setDrawColor') => {\n if (!hex) return;\n const c = parseColor(hex);\n if (c) (pdf as any)[setter](c.r, c.g, c.b);\n };\n setColor(fill, 'setFillColor');\n setColor(stroke ?? fill, 'setDrawColor');\n}\n\n// ─── Core: SVG Preparation ───\n\nfunction svg2pdfOpts(x: number, y: number, width: number, height: number) {\n const sanitize = (value: number, fallback: number): number => Number.isFinite(value) ? Number(value.toFixed(3)) : fallback;\n const w = Math.max(0.001, sanitize(width, 1));\n const h = Math.max(0.001, sanitize(height, 1));\n return { x: sanitize(x, 0), y: sanitize(y, 0), width: w, height: h };\n}\n\nasync function svg2pdfWithDomMount(svg: Element, pdf: jsPDF, opts: ReturnType<typeof svg2pdfOpts>): Promise<void> {\n const wrap = document.createElement('div');\n wrap.style.cssText = 'position:fixed;left:-9999px;top:0;width:0;height:0;overflow:hidden;pointer-events:none;opacity:0';\n wrap.appendChild(svg);\n document.body.appendChild(wrap);\n try {\n await svg2pdf(svg, pdf, opts);\n } finally {\n svg.remove();\n if (wrap.parentNode) document.body.removeChild(wrap);\n }\n}\n\n// ─── Text Decoration → Explicit Lines ───\n// svg2pdf.js does NOT support text-decoration on <tspan>/<text> elements.\n// Fabric.js toSVG() outputs text-decoration=\"underline\" on tspans.\n// This function converts those decorations into explicit <line> elements\n// that svg2pdf can render.\n\nasync function convertTextDecorationsToLines(svg: Element): Promise<void> {\n const doc = svg.ownerDocument;\n if (!doc) return;\n\n const stripTextDecoration = (el: Element): void => {\n el.removeAttribute('text-decoration');\n const style = el.getAttribute('style') || '';\n if (!style) return;\n const kept = style\n .split(';')\n .map((part) => part.trim())\n .filter(Boolean)\n .filter((part) => !/^text-decoration\\s*:/i.test(part));\n if (kept.length > 0) el.setAttribute('style', kept.join('; '));\n else el.removeAttribute('style');\n };\n\n const resolveInheritedSvgValue = (el: Element, attr: string, styleProp = attr): string | null => {\n let current: Element | null = el;\n while (current) {\n const attrValue = current.getAttribute(attr)?.trim();\n if (attrValue) return attrValue;\n const styleValue = getInlineStyleValue(current, styleProp)?.trim();\n if (styleValue) return styleValue;\n current = current.parentElement;\n }\n return null;\n };\n\n if (typeof document !== 'undefined' && document.fonts) {\n const fontFamilies = new Set<string>();\n for (const textEl of svg.querySelectorAll('text')) {\n const ff = textEl.getAttribute('data-source-font-family') || textEl.getAttribute('font-family');\n if (ff) fontFamilies.add(ff.replace(/'/g, ''));\n for (const tspan of textEl.querySelectorAll('tspan')) {\n const tff = tspan.getAttribute('data-source-font-family') || tspan.getAttribute('font-family');\n if (tff) fontFamilies.add(tff.replace(/'/g, ''));\n }\n }\n\n await Promise.all(Array.from(fontFamilies).flatMap((ff) => [\n document.fonts.load(`16px \"${ff}\"`).then(() => {}).catch(() => {}),\n document.fonts.load(`bold 16px \"${ff}\"`).then(() => {}).catch(() => {}),\n ]));\n await document.fonts.ready;\n }\n\n let tempContainer: HTMLDivElement | null = null;\n let liveSvg: Element | null = null;\n try {\n if (typeof document !== 'undefined') {\n tempContainer = document.createElement('div');\n tempContainer.style.cssText = 'position:fixed;left:-9999px;top:-9999px;visibility:hidden;pointer-events:none;';\n document.body.appendChild(tempContainer);\n const clone = svg.cloneNode(true) as Element;\n // If the SVG has been rewritten with jsPDF font names, restore the\n // original font metadata on the live clone so the browser measures\n // against real fonts instead of the unknown jsPDF name (which would\n // fall back to a default font and shorten the underline).\n for (const textNode of clone.querySelectorAll('text, tspan, textPath')) {\n const sourceFamily = textNode.getAttribute('data-source-font-family');\n const sourceWeight = textNode.getAttribute('data-source-font-weight');\n const sourceStyle = textNode.getAttribute('data-source-font-style');\n if (sourceFamily) textNode.setAttribute('font-family', sourceFamily);\n if (sourceWeight) textNode.setAttribute('font-weight', sourceWeight);\n if (sourceStyle) textNode.setAttribute('font-style', sourceStyle);\n\n const inlineStyle = textNode.getAttribute('style') || '';\n const stylePairs = inlineStyle\n .split(';')\n .map((part) => part.trim())\n .filter(Boolean)\n .filter((part) => !/^font-family\\s*:/i.test(part) && !/^font-weight\\s*:/i.test(part) && !/^font-style\\s*:/i.test(part));\n if (sourceFamily) stylePairs.push(`font-family: ${sourceFamily}`);\n if (sourceWeight) stylePairs.push(`font-weight: ${sourceWeight}`);\n if (sourceStyle) stylePairs.push(`font-style: ${sourceStyle}`);\n if (stylePairs.length > 0) textNode.setAttribute('style', stylePairs.join('; '));\n }\n tempContainer.appendChild(clone);\n liveSvg = clone;\n }\n } catch { /* noop */ }\n\n let ctx: CanvasRenderingContext2D | null = null;\n try {\n const realDoc = typeof document !== 'undefined' ? document : doc;\n const measureCanvas = realDoc.createElement('canvas') as HTMLCanvasElement;\n ctx = measureCanvas.getContext('2d');\n } catch { /* noop */ }\n\n const textEls = Array.from(svg.querySelectorAll('text'));\n const liveTextEls = liveSvg ? Array.from(liveSvg.querySelectorAll('text')) : null;\n\n for (let ti = 0; ti < textEls.length; ti++) {\n const textEl = textEls[ti];\n const liveTextEl = liveTextEls?.[ti] as SVGTextElement | undefined;\n const tspans = Array.from(textEl.querySelectorAll('tspan'));\n if (tspans.length === 0) continue;\n const liveTspans = liveTextEl ? Array.from(liveTextEl.querySelectorAll('tspan')) as SVGTSpanElement[] : null;\n\n // Check if the whole <text> has underline\n const textDecOnText = (textEl.getAttribute('text-decoration') || '').toLowerCase();\n const textStyleDec = (getInlineStyleValue(textEl, 'text-decoration') || '').toLowerCase();\n const textHasUnderline = textDecOnText.includes('underline') || textStyleDec.includes('underline');\n const textHasLinethrough = textDecOnText.includes('line-through') || textStyleDec.includes('line-through');\n\n for (let si = 0; si < tspans.length; si++) {\n const tspan = tspans[si];\n const liveTspan = liveTspans?.[si];\n const tspanDec = (tspan.getAttribute('text-decoration') || '').toLowerCase();\n const tspanStyleDec = (getInlineStyleValue(tspan, 'text-decoration') || '').toLowerCase();\n const hasUnderline = tspanDec.includes('underline') || tspanStyleDec.includes('underline') || textHasUnderline;\n const hasLinethrough = tspanDec.includes('line-through') || tspanStyleDec.includes('line-through') || textHasLinethrough;\n\n if (!hasUnderline && !hasLinethrough) continue;\n\n const content = tspan.textContent || '';\n if (!content.trim()) continue;\n\n // Get position — tspan x/y, fall back to parent text\n const xAttr = tspan.getAttribute('x') ?? textEl.getAttribute('x') ?? '0';\n const yAttr = tspan.getAttribute('y') ?? textEl.getAttribute('y') ?? '0';\n const x = parseFloat(xAttr) || 0;\n const y = parseFloat(yAttr) || 0;\n\n // Get font properties\n const fontSize = parseFloat(\n tspan.getAttribute('font-size') || textEl.getAttribute('font-size') || '16'\n );\n const fontFamily =\n tspan.getAttribute('data-source-font-family') ||\n textEl.getAttribute('data-source-font-family') ||\n resolveInheritedSvgValue(tspan, 'font-family') ||\n 'sans-serif';\n const fontWeight =\n tspan.getAttribute('data-source-font-weight') ||\n textEl.getAttribute('data-source-font-weight') ||\n resolveInheritedSvgValue(tspan, 'font-weight') ||\n 'normal';\n const fontStyle =\n tspan.getAttribute('data-source-font-style') ||\n textEl.getAttribute('data-source-font-style') ||\n resolveInheritedSvgValue(tspan, 'font-style') ||\n 'normal';\n\n // Get fill color for the underline stroke.\n // Fabric.js typically writes fill via inline `style=\"fill: rgb(...)\"` on\n // <text> (not as a `fill=` attribute), and tspans inherit it. Older\n // SVGs may also place it on an ancestor <g>. Walk the inheritance\n // chain via attribute AND inline style so the underline color matches\n // the actual rendered glyph color instead of defaulting to black.\n const resolvedFill =\n tspan.getAttribute('fill') ||\n getInlineStyleValue(tspan, 'fill') ||\n resolveInheritedSvgValue(tspan, 'fill') ||\n textEl.getAttribute('fill') ||\n getInlineStyleValue(textEl, 'fill') ||\n '#000000';\n const fill = resolvedFill;\n const fillOpacity =\n tspan.getAttribute('fill-opacity') ||\n getInlineStyleValue(tspan, 'fill-opacity') ||\n resolveInheritedSvgValue(tspan, 'fill-opacity') ||\n textEl.getAttribute('fill-opacity') ||\n getInlineStyleValue(textEl, 'fill-opacity') ||\n null;\n\n // Measure text width\n let textWidth = content.length * fontSize * 0.6;\n if (ctx) {\n ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily.replace(/'/g, '')}`;\n textWidth = ctx.measureText(content).width;\n }\n\n const textAnchorRaw = (resolveInheritedSvgValue(tspan, 'text-anchor') || 'start').toLowerCase();\n const textAnchor = textAnchorRaw === 'middle' || textAnchorRaw === 'end' ? textAnchorRaw : 'start';\n let lineStartX = x - (textAnchor === 'middle' ? textWidth / 2 : textAnchor === 'end' ? textWidth : 0);\n let lineEndX = lineStartX + textWidth;\n let baselineY = y;\n\n if (liveTspan) {\n try {\n const liveCharCount = liveTspan.getNumberOfChars();\n // Source of truth: the live SVG's per-glyph positions. This matches\n // exactly what Fabric's canvas `_renderTextDecoration` draws (which\n // uses __charBounds covering ONLY the glyph run, NOT the trailing\n // whitespace or italic overhang). Using getBBox or canvas-measure\n // Math.max'd over this would over-extend the underline past the\n // actual glyph endpoints — the bug the user reported.\n if (liveCharCount > 0) {\n const start = liveTspan.getStartPositionOfChar(0);\n const end = liveTspan.getEndPositionOfChar(liveCharCount - 1);\n if (Number.isFinite(start.x)) lineStartX = start.x;\n if (Number.isFinite(start.y)) baselineY = start.y;\n if (Number.isFinite(end.x)) lineEndX = end.x;\n if (Number.isFinite(end.y) && !Number.isFinite(baselineY)) baselineY = end.y;\n } else {\n const svgWidth = liveTspan.getComputedTextLength();\n if (Number.isFinite(svgWidth) && svgWidth > 0) {\n textWidth = svgWidth;\n lineEndX = lineStartX + textWidth;\n }\n }\n } catch { /* use canvas width */ }\n }\n\n if (!(lineEndX > lineStartX)) {\n lineStartX = x - (textAnchor === 'middle' ? textWidth / 2 : textAnchor === 'end' ? textWidth : 0);\n lineEndX = lineStartX + textWidth;\n }\n\n // Calculate decoration positions and thickness\n const thickness = Math.max(0.5, fontSize * 0.066667);\n const makeLine = (yPos: number) => {\n const line = doc.createElementNS('http://www.w3.org/2000/svg', 'line');\n line.setAttribute('x1', String(lineStartX));\n line.setAttribute('y1', String(yPos));\n line.setAttribute('x2', String(lineEndX));\n line.setAttribute('y2', String(yPos));\n line.setAttribute('stroke', fill.startsWith('url(') ? '#000000' : fill);\n line.setAttribute('stroke-width', String(thickness));\n line.setAttribute('stroke-linecap', 'butt');\n line.setAttribute('fill', 'none');\n if (fillOpacity) line.setAttribute('stroke-opacity', fillOpacity);\n if (textEl.parentElement) {\n textEl.parentElement.insertBefore(line, textEl.nextSibling);\n }\n };\n\n if (hasUnderline) makeLine(baselineY + fontSize * 0.15);\n if (hasLinethrough) makeLine(baselineY - fontSize * 0.3);\n\n // Prevent duplicate decorations if a later pass rewrites/serializes the\n // remaining <text>. The explicit SVG line is now the decoration source.\n stripTextDecoration(tspan);\n if (textHasUnderline || textHasLinethrough) stripTextDecoration(textEl);\n }\n }\n\n if (tempContainer) {\n try { document.body.removeChild(tempContainer); } catch { /* noop */ }\n }\n}\n\n// ─── String wrapper for the underline conversion ───\n// Parses the SVG string, runs `convertTextDecorationsToLines` on the live\n// document, and serializes back. Used to insert explicit <line> underlines\n// BEFORE text-to-path outlining destroys text metadata.\nasync function convertSvgTextDecorationsToLinesString(svgStr: string): Promise<string> {\n if (typeof DOMParser === 'undefined' || typeof XMLSerializer === 'undefined') {\n return svgStr;\n }\n // Quick early-out: nothing to do if no decoration is present at all.\n if (!/text-decoration/i.test(svgStr) && !/underline/i.test(svgStr) && !/line-through/i.test(svgStr)) {\n return svgStr;\n }\n try {\n const parser = new DOMParser();\n const docEl = parser.parseFromString(svgStr, 'image/svg+xml');\n const rootSvg = docEl.documentElement;\n if (!rootSvg) return svgStr;\n await convertTextDecorationsToLines(rootSvg as unknown as Element);\n const serializer = new XMLSerializer();\n return serializer.serializeToString(rootSvg);\n } catch {\n return svgStr;\n }\n}\n\n// ─── Shadow Marker Rasterization ───\n//\n// Replaces every `<g class=\"__pdShadowRaster\">` placeholder produced by\n// `src/lib/textBackgroundRenderer.ts` with a smooth, blurred PNG `<image>`.\n//\n// Why: svg2pdf.js has zero support for SVG <filter> / feGaussianBlur, so a\n// vector-only shadow can only be approximated by stacking many offset/opaque\n// duplicates of the shape. That produces visibly harsh, banded shadows in the\n// final PDF. Rasterizing each marker through a real Gaussian filter inside\n// an offscreen browser <img> gives us pixel-perfect parity with the canvas\n// preview, while keeping every other element in the page strictly vector.\nasync function rasterizeShadowMarkers(svg: SVGElement): Promise<void> {\n if (typeof window === 'undefined' || typeof document === 'undefined') return;\n const markers = Array.from(svg.querySelectorAll('g.__pdShadowRaster')) as SVGGElement[];\n if (markers.length === 0) return;\n\n const SVG_NS = 'http://www.w3.org/2000/svg';\n const XLINK_NS = 'http://www.w3.org/1999/xlink';\n\n // Best-effort: ensure document fonts are settled so glyph silhouettes match\n // the canvas preview when the offscreen <img> renderer falls back to them.\n try { if ((document as any).fonts?.ready) await (document as any).fonts.ready; } catch { /* noop */ }\n\n // Collect @font-face rules and inline url() payloads as data: URIs so the\n // offscreen blob: SVG can actually resolve the same fonts the live canvas\n // uses. Without inlining, the blob context can't fetch the woff2 reliably\n // (CORS + timing) and falls back to sans-serif → shadow drifts vs text.\n // PARITY with `src/lib/vectorPdfExport.ts`.\n const fontFaceCss = await collectInlinedFontFaceCss();\n\n for (const marker of markers) {\n try {\n const blur = parseFloat(marker.getAttribute('data-blur') || '0');\n const ox = parseFloat(marker.getAttribute('data-ox') || '0');\n const oy = parseFloat(marker.getAttribute('data-oy') || '0');\n const bx = parseFloat(marker.getAttribute('data-bx') || '0');\n const by = parseFloat(marker.getAttribute('data-by') || '0');\n const bw = parseFloat(marker.getAttribute('data-bw') || '0');\n const bh = parseFloat(marker.getAttribute('data-bh') || '0');\n if (!Number.isFinite(bw) || !Number.isFinite(bh) || bw <= 0 || bh <= 0) {\n marker.parentNode?.removeChild(marker);\n continue;\n }\n\n // Serialize marker children into a standalone SVG with a real Gaussian\n // filter applied. The viewBox is in object-local coordinates so the\n // resulting bitmap maps 1:1 onto the marker's location.\n // PARITY: restore `data-source-font-*` back onto the text nodes so the\n // offscreen rasterizer uses the document's @font-face entries, not the\n // jsPDF font names produced by the SVG rewriter (which the document has\n // no @font-face for → fallback → silhouette drift).\n const innerXml = restoreSourceFontsForShadowRaster(\n Array.from(marker.childNodes)\n .map((n) => (n instanceof Element ? new XMLSerializer().serializeToString(n) : ''))\n .join(''),\n );\n\n // ── Race-condition guard: explicitly load every font referenced inside\n // this marker BEFORE rasterizing. Without this, the offscreen <img>\n // sometimes paints the shadow silhouette with a fallback font (wrong\n // metrics → shadow doesn't align with the real text glyphs above it).\n // `document.fonts.load(spec)` triggers the network fetch and resolves\n // when the family is fully usable in the document — which the SVG-in-img\n // renderer inherits via @font-face cssText we inline below.\n try {\n const fontSpecs = collectFontSpecsFromMarkup(innerXml);\n if (fontSpecs.length > 0 && (document as any).fonts?.load) {\n await Promise.all(\n fontSpecs.map((spec) =>\n (document as any).fonts.load(spec).catch(() => undefined),\n ),\n );\n }\n } catch { /* noop */ }\n\n // Render at 2x device pixels for crisp scaling. Cap to keep memory sane.\n const scale = 2;\n const pxW = Math.min(4096, Math.max(8, Math.ceil(bw * scale)));\n const pxH = Math.min(4096, Math.max(8, Math.ceil(bh * scale)));\n\n // Canvas2D `shadowBlur` is roughly 2× SVG `feGaussianBlur stdDeviation`\n // (Canvas spec uses a Gaussian where the blur radius ≈ 2σ). Without\n // this conversion the rasterized PDF shadow spreads ~2× wider than the\n // canvas preview at the same blur value.\n const stdDev = Math.max(0, blur / 2);\n const filterId = `pdShadowBlur_${Math.random().toString(36).slice(2, 9)}`;\n const styleBlock = fontFaceCss ? `<style>${fontFaceCss}</style>` : '';\n const miniSvg =\n `<svg xmlns=\"${SVG_NS}\" xmlns:xlink=\"${XLINK_NS}\" width=\"${pxW}\" height=\"${pxH}\" viewBox=\"${bx} ${by} ${bw} ${bh}\">` +\n `${styleBlock}<defs><filter id=\"${filterId}\" filterUnits=\"userSpaceOnUse\" x=\"${bx}\" y=\"${by}\" width=\"${bw}\" height=\"${bh}\" color-interpolation-filters=\"sRGB\">` +\n `<feOffset dx=\"${ox}\" dy=\"${oy}\" result=\"offsetShadow\" />` +\n `<feGaussianBlur in=\"offsetShadow\" stdDeviation=\"${stdDev}\" />` +\n `</filter></defs>` +\n `<g filter=\"url(#${filterId})\">${innerXml}</g>` +\n `</svg>`;\n\n const dataUrl = await rasterSvgToPngDataUrl(miniSvg, pxW, pxH);\n if (!dataUrl) {\n // Couldn't rasterize — drop the marker entirely rather than showing\n // unblurred silhouettes that look worse than no shadow at all.\n marker.parentNode?.removeChild(marker);\n continue;\n }\n\n const img = svg.ownerDocument!.createElementNS(SVG_NS, 'image') as SVGImageElement;\n img.setAttribute('x', String(bx));\n img.setAttribute('y', String(by));\n img.setAttribute('width', String(bw));\n img.setAttribute('height', String(bh));\n img.setAttribute('opacity', String(SHADOW_RASTER_ALPHA_COMPENSATION));\n img.setAttribute('preserveAspectRatio', 'none');\n img.setAttributeNS(XLINK_NS, 'xlink:href', dataUrl);\n img.setAttribute('href', dataUrl);\n marker.parentNode?.replaceChild(img, marker);\n } catch (e) {\n console.warn('[pdf-export] rasterizeShadowMarkers failed for one marker:', e);\n try { marker.parentNode?.removeChild(marker); } catch { /* noop */ }\n }\n }\n}\n\n/** Render an SVG markup string into a PNG data URL via an offscreen <img>. */\nfunction rasterSvgToPngDataUrl(svgMarkup: string, pxW: number, pxH: number): Promise<string | null> {\n return new Promise((resolve) => {\n try {\n const blob = new Blob([svgMarkup], { type: 'image/svg+xml;charset=utf-8' });\n const url = URL.createObjectURL(blob);\n const img = new Image();\n // PARITY: do NOT set `crossOrigin = 'anonymous'` here. The client\n // export (`src/lib/vectorPdfExport.ts > rasterSvgToPngDataUrl`) does\n // not set it, and setting it on an <img> with a blob: src forces a\n // CORS-mode resource fetch for the inlined sub-resources (fonts,\n // images) inside the SVG. On the EC2 harness that flips just enough\n // browser internals to break @font-face lookup → shadow silhouette\n // renders with a fallback font and visibly drifts vs the live text.\n const cleanup = () => { try { URL.revokeObjectURL(url); } catch { /* noop */ } };\n img.onload = () => {\n try {\n const canvas = document.createElement('canvas');\n canvas.width = pxW;\n canvas.height = pxH;\n const ctx = canvas.getContext('2d');\n if (!ctx) { cleanup(); resolve(null); return; }\n // PARITY: explicit clearRect — matches the client implementation\n // and avoids any pre-existing canvas content leaking into the PNG\n // when the browser allocates a non-zeroed backing store.\n ctx.clearRect(0, 0, pxW, pxH);\n ctx.drawImage(img, 0, 0, pxW, pxH);\n const dataUrl = canvas.toDataURL('image/png');\n cleanup();\n resolve(dataUrl);\n } catch (e) {\n cleanup();\n resolve(null);\n }\n };\n img.onerror = () => { cleanup(); resolve(null); };\n img.src = url;\n } catch {\n resolve(null);\n }\n });\n}\n\n/**\n * Walk every same-origin stylesheet in the live document and collect\n * `@font-face` rules so the offscreen SVG-in-img renderer can resolve the\n * same font families used on the live canvas. We can't simply reference the\n * families by name — SVG images are loaded in an isolated context that does\n * not inherit document fonts.\n */\nlet cachedFontFaceCss: string | null = null;\nfunction collectDocumentFontFaceCss(): string {\n if (cachedFontFaceCss !== null) return cachedFontFaceCss;\n const out: string[] = [];\n try {\n for (const sheet of Array.from(document.styleSheets)) {\n let rules: CSSRuleList | null = null;\n try { rules = sheet.cssRules; } catch { rules = null; /* CORS */ }\n if (!rules) continue;\n for (const rule of Array.from(rules)) {\n // CSSFontFaceRule has type === 5; check by type to avoid lib issues.\n const r = rule as CSSRule & { cssText?: string };\n if (r && (r.type === 5 || /@font-face/i.test(r.cssText || ''))) {\n if (r.cssText) out.push(r.cssText);\n }\n }\n }\n } catch { /* noop */ }\n cachedFontFaceCss = out.join('\\n');\n return cachedFontFaceCss;\n}\n\n// ─── Font inlining for shadow rasterization ────────────────────────────────\n// PARITY with `src/lib/vectorPdfExport.ts`: browsers won't reliably load\n// fonts via @font-face URL() inside a blob: SVG loaded via <img>. Inlining\n// the font payload as a data: URI works in every browser, so the shadow\n// silhouette renders with the SAME font as the live canvas above it instead\n// of a fallback (which would visibly drift).\nlet cachedInlinedFontFaceCss: string | null = null;\nconst fontUrlDataCache = new Map<string, string | null>();\n\nasync function fetchFontAsDataUri(url: string): Promise<string | null> {\n if (fontUrlDataCache.has(url)) return fontUrlDataCache.get(url) ?? null;\n try {\n const resp = await fetch(url, { mode: 'cors', credentials: 'omit' });\n if (!resp.ok) { fontUrlDataCache.set(url, null); return null; }\n const blob = await resp.blob();\n const dataUri: string = await new Promise((resolve, reject) => {\n const fr = new FileReader();\n fr.onload = () => resolve(String(fr.result));\n fr.onerror = () => reject(fr.error);\n fr.readAsDataURL(blob);\n });\n fontUrlDataCache.set(url, dataUri);\n return dataUri;\n } catch {\n fontUrlDataCache.set(url, null);\n return null;\n }\n}\n\nasync function inlineUrlsInCss(css: string): Promise<string> {\n const urlRe = /url\\((['\"]?)([^'\")]+)\\1\\)/gi;\n const matches: { full: string; url: string }[] = [];\n let m: RegExpExecArray | null;\n while ((m = urlRe.exec(css)) !== null) {\n const raw = m[2].trim();\n if (raw.startsWith('data:')) continue;\n let abs = raw;\n try { abs = new URL(raw, document.baseURI).toString(); } catch { /* keep raw */ }\n matches.push({ full: m[0], url: abs });\n }\n if (matches.length === 0) return css;\n const unique = Array.from(new Set(matches.map((mm) => mm.url)));\n const results = await Promise.all(unique.map((u) => fetchFontAsDataUri(u)));\n const map = new Map<string, string | null>();\n unique.forEach((u, i) => map.set(u, results[i]));\n let out = css;\n for (const { full, url } of matches) {\n const data = map.get(url);\n if (!data) continue;\n const safeFull = full.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n out = out.replace(new RegExp(safeFull, 'g'), `url(\"${data}\")`);\n }\n return out;\n}\n\nasync function collectInlinedFontFaceCss(): Promise<string> {\n if (cachedInlinedFontFaceCss !== null) return cachedInlinedFontFaceCss;\n const raw = collectDocumentFontFaceCss();\n if (!raw) { cachedInlinedFontFaceCss = ''; return ''; }\n try {\n cachedInlinedFontFaceCss = await inlineUrlsInCss(raw);\n } catch {\n cachedInlinedFontFaceCss = raw;\n }\n return cachedInlinedFontFaceCss;\n}\n\n// PARITY: after the SVG rewriter renames `font-family` to jsPDF font names\n// (e.g. \"Stardom-Regular\"), the offscreen <img> shadow rasterizer cannot\n// resolve those names — it has no @font-face for them. Restore the original\n// `data-source-font-*` attributes onto a clone of the markup so the shadow\n// silhouette uses the SAME font as the live canvas.\nfunction restoreSourceFontsForShadowRaster(markup: string): string {\n try {\n const parser = new DOMParser();\n const doc = parser.parseFromString(`<svg xmlns=\"http://www.w3.org/2000/svg\">${markup}</svg>`, 'image/svg+xml');\n if (doc.querySelector('parsererror')) return markup;\n for (const node of Array.from(doc.querySelectorAll('text, tspan, textPath'))) {\n const family = node.getAttribute('data-source-font-family');\n const weight = node.getAttribute('data-source-font-weight');\n const style = node.getAttribute('data-source-font-style');\n if (!family && !weight && !style) continue;\n const stylePairs = (node.getAttribute('style') || '')\n .split(';')\n .map((part) => part.trim())\n .filter(Boolean)\n .filter((part) => !/^font-family\\s*:/i.test(part) && !/^font-weight\\s*:/i.test(part) && !/^font-style\\s*:/i.test(part));\n if (family) { node.setAttribute('font-family', family); stylePairs.push(`font-family: ${family}`); }\n if (weight) { node.setAttribute('font-weight', weight); stylePairs.push(`font-weight: ${weight}`); }\n if (style) { node.setAttribute('font-style', style); stylePairs.push(`font-style: ${style}`); }\n if (stylePairs.length > 0) node.setAttribute('style', stylePairs.join('; '));\n }\n const root = doc.documentElement;\n return Array.from(root.childNodes)\n .map((n) => (n instanceof Element ? new XMLSerializer().serializeToString(n) : ''))\n .join('');\n } catch {\n return markup;\n }\n}\n\nasync function prepareLiveCanvasSvgForPdf(\n rawSvg: string,\n pageWidth: number,\n pageHeight: number,\n pageKey: string,\n options?: { stripPageBackground?: boolean },\n): Promise<Element | null> {\n try {\n const parser = new DOMParser();\n const processedSvg = inlineNestedSvgImageDataUris(rawSvg, parser);\n const doc = parser.parseFromString(processedSvg, 'image/svg+xml');\n if (doc.querySelector('parsererror')) return null;\n\n const svg = doc.documentElement;\n if (!svg || svg.tagName.toLowerCase() !== 'svg') return null;\n\n svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');\n if (/xlink:href/i.test(processedSvg) && !svg.getAttribute('xmlns:xlink')) {\n svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');\n }\n svg.setAttribute('width', String(pageWidth));\n svg.setAttribute('height', String(pageHeight));\n svg.setAttribute('viewBox', `0 0 ${pageWidth} ${pageHeight}`);\n\n sanitizeSvgTreeForPdf(svg);\n normalizeSvgViewBoxOrigin(svg);\n disambiguateNestedSvgIds(svg);\n expandSvgUseElements(svg);\n const svgToDraw = normalizeSvgExplicitColors(svg);\n inlineComputedStyles(svgToDraw);\n sanitizeSvgTreeForPdf(svgToDraw);\n normalizeSvgGradientStopOffsets(svgToDraw);\n expandSvgGradientHrefs(svgToDraw);\n prefixSvgIds(svgToDraw, pageKey);\n bakeGroupOpacityIntoChildren(svgToDraw);\n stripSuspiciousFullPageOverlayNodes(svgToDraw);\n if (options?.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);\n sanitizeSvgTreeForPdf(svgToDraw);\n // ─── v0.5.131 PARITY: bake text-anchor → start using live canvas\n // measurement, BEFORE shadow rasterization or any svg2pdf width math.\n // Source-of-truth implementation lives in `@/lib/vectorPdfExport` so\n // both the host (`UsePackage`) and the package paths share it.\n try {\n const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await import('@/lib/vectorPdfExport');\n try { await logTextMeasurementDiagnostic(svgToDraw); } catch {}\n await bakeTextAnchorPositionsFromLiveSvg(svgToDraw);\n } catch (e) {\n console.warn('[canvas-renderer][pdf-export] anchor-bake pass failed (continuing):', e);\n }\n // Replace text-shadow markers with rasterized blurred PNG <image> elements.\n // This is what gives us the SMOOTH Gaussian blur in the vector PDF —\n // svg2pdf has no <filter> support, so stacked offset duplicates would\n // look harsh. Rasterizing the marker with a real feGaussianBlur produces\n // pixel-perfect parity with the canvas preview.\n await rasterizeShadowMarkers(svgToDraw as SVGElement);\n\n return svgToDraw;\n } catch { return null; }\n}\n\n// ─── Background Drawing ───\n\nfunction drawPageBackground(\n pdf: jsPDF,\n pageIndex: number,\n pageWidth: number,\n pageHeight: number,\n backgroundColor: string,\n backgroundGradient?: any,\n): void {\n if (backgroundGradient && backgroundGradient.stops?.length >= 2) {\n const grad = backgroundGradient;\n const colorStops = grad.stops\n .map((s: any) => {\n const c = parseColor(s.color);\n return {\n offset: Math.max(0, Math.min(1, Number(s.offset))),\n color: c ? [c.r, c.g, c.b] as [number, number, number] : [0, 0, 0] as [number, number, number],\n };\n })\n .filter((s: any) => Number.isFinite(s.offset))\n .sort((a: any, b: any) => a.offset - b.offset);\n\n const normalizedStops = [...colorStops];\n if (normalizedStops.length > 0) {\n if (normalizedStops[0].offset > 0) normalizedStops.unshift({ offset: 0, color: normalizedStops[0].color });\n if (normalizedStops[normalizedStops.length - 1].offset < 1) normalizedStops.push({ offset: 1, color: normalizedStops[normalizedStops.length - 1].color });\n }\n\n const shadingColors = normalizedStops.map((s: any) => ({ offset: s.offset, color: s.color }));\n const patternKey = `bg-grad-${pageIndex}`;\n\n try {\n pdf.advancedAPI((doc: any) => {\n const isLinear = grad.type === 'linear';\n const isConic = grad.type === 'conic';\n\n if (isLinear || isConic) {\n const angleDeg = grad.angle ?? (isConic ? 0 : 90);\n const angleRad = (angleDeg * Math.PI) / 180;\n const sinA = Math.sin(angleRad);\n const cosA = Math.cos(angleRad);\n const corners = [[0, 0], [pageWidth, 0], [pageWidth, pageHeight], [0, pageHeight]];\n const projs = corners.map(([x, y]) => x * sinA - y * cosA);\n const minP = Math.min(...projs);\n const maxP = Math.max(...projs);\n const halfLen = (maxP - minP) / 2;\n const midX = pageWidth / 2;\n const midY = pageHeight / 2;\n\n let finalStops = shadingColors;\n if (isConic && shadingColors.length >= 2) {\n const reversed = [...shadingColors].reverse().map((s: any) => ({ offset: 0.5 + (1 - s.offset) * 0.5, color: s.color }));\n const firstHalf = shadingColors.map((s: any) => ({ offset: s.offset * 0.5, color: s.color }));\n finalStops = [...firstHalf, ...reversed.slice(1)];\n }\n\n doc.addShadingPattern(patternKey, new ShadingPattern('axial', [\n midX - sinA * halfLen, midY + cosA * halfLen,\n midX + sinA * halfLen, midY - cosA * halfLen,\n ], finalStops));\n } else {\n const cx = (grad.cx ?? 0.5) * pageWidth;\n const cy = (grad.cy ?? 0.5) * pageHeight;\n const maxR = (grad.r ?? 0.5) * Math.max(pageWidth, pageHeight);\n doc.addShadingPattern(patternKey, new ShadingPattern('radial', [cx, cy, 0, cx, cy, maxR], shadingColors));\n }\n\n doc.rect(0, 0, pageWidth, pageHeight);\n doc.fill({ key: patternKey, matrix: doc.Matrix(1, 0, 0, 1, 0, 0) });\n });\n } catch {\n const fallback = colorStops[0]?.color || [255, 255, 255];\n pdf.setFillColor(fallback[0], fallback[1], fallback[2]);\n pdf.rect(0, 0, pageWidth, pageHeight, 'F');\n }\n } else {\n const bgColor = parseColor(backgroundColor && backgroundColor !== 'transparent' ? backgroundColor : '#ffffff');\n if (bgColor) {\n pdf.setFillColor(bgColor.r, bgColor.g, bgColor.b);\n pdf.rect(0, 0, pageWidth, pageHeight, 'F');\n }\n }\n}\n\n// ─── Public API ───\n\n/**\n * Assemble a vector PDF from SVG render results.\n * This is the core function that converts canvas SVGs into a multi-page PDF document.\n */\nexport async function assemblePdfFromSvgs(\n svgResults: SvgRenderResult[],\n options: PdfAssemblyOptions = {},\n): Promise<PdfRenderResult> {\n if (svgResults.length === 0) throw new Error('No pages to export');\n\n const { title, stripPageBackground } = options;\n const firstPage = svgResults[0];\n const orientation = firstPage.width > firstPage.height ? 'landscape' : 'portrait';\n\n // ─── Parity diagnostics: dump textbox metrics from the captured SVG ───\n // Use the SAME log tag in the host UsePackage client vector path so the two\n // can be diff'd line-by-line. Look for [parity-diag] in both consoles.\n const PARITY_TAG = '[canvas-renderer][parity-diag][pkg-pdf]';\n console.log(`${PARITY_TAG} pkg-version=${PACKAGE_VERSION} pages=${svgResults.length}`);\n try {\n for (let pi = 0; pi < svgResults.length; pi++) {\n dumpSvgTextDiagnostics(svgResults[pi].svg, pi, PARITY_TAG, 'STAGE-1-raw-toSVG');\n }\n } catch (e) {\n console.warn(`${PARITY_TAG} dump failed`, e);\n }\n\n const pdf = new jsPDF({\n orientation,\n unit: 'px',\n format: [firstPage.width, firstPage.height],\n hotfixes: ['px_scaling'],\n compress: true,\n });\n\n if (title) pdf.setProperties({ title, creator: 'Pixldocs' });\n\n // ── Embed fonts: discover from SVG + embed each weight as separate jsPDF font ──\n const fontBaseUrl = options.fontBaseUrl ?? (typeof window !== 'undefined' ? window.location.origin + '/fonts/' : '/fonts/');\n // Use the legacy SVG-scanning approach to find all font families, then embed all weights\n const { extractFontFamiliesFromSvgs } = await import('./pdf-fonts');\n const fontFamilies = extractFontFamiliesFromSvgs(svgResults.map(s => s.svg));\n if (fontFamilies.size > 0) {\n await embedFontsInPdf(pdf, fontFamilies, fontBaseUrl);\n }\n\n for (let i = 0; i < svgResults.length; i++) {\n const page = svgResults[i];\n\n if (i > 0) {\n const pageOrientation = page.width > page.height ? 'landscape' : 'portrait';\n pdf.addPage([page.width, page.height], pageOrientation);\n }\n\n // Draw background (gradient or solid) directly via jsPDF\n const hasGradient = !!page.backgroundGradient?.stops?.length;\n drawPageBackground(pdf, i, page.width, page.height, page.backgroundColor, page.backgroundGradient);\n\n // Process and draw the SVG content. Text mode is intentionally delegated to\n // the shared host helper so the app and published package follow the exact\n // same gradient/selectable/pixel-perfect branch.\n const shouldStripBg = stripPageBackground ?? hasGradient;\n const textMode: 'auto' | 'selectable' | 'pixel-perfect' =\n options.textMode\n ?? (options.outlineText === true ? 'pixel-perfect' : 'selectable');\n\n // ─── v0.5.74 PARITY FIX ───\n // The working UsePackage client vector PDF (src/pages/UsePackage.tsx)\n // outlines text on the *raw Fabric SVG string* BEFORE any other DOM\n // mutation. The previous order in this package ran\n // `prepareLiveCanvasSvgForPdf` first — that helper invokes\n // `inlineComputedStyles`, `normalizeSvgExplicitColors`, etc., which\n // mutate text font-size / font-family attributes and re-parse the\n // tree. Outlining AFTER those mutations produced different glyph\n // metrics and dropped some dynamic text entirely on staging.\n //\n // We now mirror UsePackage exactly: outline first on the raw string,\n // then run the prepare/sanitise pipeline on the already-outlined SVG.\n let pageSvg = page.svg;\n // ─── v0.5.79 UNDERLINE FIX ───\n // svg2pdf.js drops `text-decoration` on <text>/<tspan>, AND our\n // text-to-path outliner replaces those nodes with <path>s — destroying\n // any decoration metadata. Convert underlines to explicit <line>\n // elements on the RAW SVG (still has live <text>) BEFORE outlining.\n try {\n pageSvg = await convertSvgTextDecorationsToLinesString(pageSvg);\n } catch (underlineErr) {\n console.warn(\n '[canvas-renderer][pdf] underline-to-line conversion failed (raw stage):',\n underlineErr,\n );\n }\n try {\n const { prepareSvgTextForPdfMode } = await import('@/lib/svgTextToPath');\n pageSvg = await prepareSvgTextForPdfMode(pageSvg, textMode, fontBaseUrl);\n try { dumpSvgTextDiagnostics(pageSvg, i, PARITY_TAG, 'STAGE-1b-after-shared-text-prep'); } catch {}\n } catch (textPrepErr) {\n console.warn('[canvas-renderer][pdf] shared text prep failed:', textPrepErr);\n }\n\n let processedSvg = await prepareLiveCanvasSvgForPdf(pageSvg, page.width, page.height, `page-${i + 1}`, {\n stripPageBackground: shouldStripBg,\n });\n\n if (processedSvg) {\n try {\n dumpSvgTextDiagnostics(\n new XMLSerializer().serializeToString(processedSvg),\n i,\n PARITY_TAG,\n 'STAGE-2-after-prepareLiveCanvasSvgForPdf',\n );\n } catch {}\n // Convert underlines to explicit vector lines before outlining text.\n // Once <text> becomes <path>, text-decoration metadata is gone.\n // NOTE (v0.5.79): the primary underline conversion now runs on the\n // raw SVG above. This second call is a safety net for any <text>\n // nodes that the outliner skipped (e.g. missing font-family).\n // It is a no-op when no <text> with text-decoration remains.\n await convertTextDecorationsToLines(processedSvg as unknown as Element);\n\n // Text was already outlined on the raw SVG above (v0.5.74) — any\n // remaining <text> nodes here are ones the outliner skipped (e.g.\n // empty strings, missing font-family). Leave them as-is for svg2pdf.\n\n // Rewrite any remaining SVG text font-family attributes to match jsPDF font names.\n // ─── PARITY FIX (v0.5.114) ───\n // Just-in-time scan the LIVE SVG for every (family, weight, italic)\n // tuple actually present (rich-text spans, inline markdown bold/italic,\n // etc.) and embed any variant not already registered in this jsPDF\n // instance via local TTF → Fontshare → Google Fonts. Without this,\n // tspans introducing a new (weight, italic) tuple silently fall back\n // to Helvetica in svg2pdf — which is what produced the visible\n // word-spacing gap (\"Revenue grew by 45% in Q3— down up\n // from\") and the wrong-font Recipe span on the EC2 server PDF.\n // Mirrors `embedFontsForSvg` in the host UsePackage vector PDF flow.\n const liveSvgStr = new XMLSerializer().serializeToString(processedSvg);\n try {\n const { embedFontVariantsFromSvg } = await import('./pdf-fonts');\n await embedFontVariantsFromSvg(pdf, liveSvgStr, fontBaseUrl);\n } catch (embedErr) {\n console.warn(\n '[canvas-renderer][pdf] embedFontVariantsFromSvg failed (page ' +\n (i + 1) + '):',\n embedErr,\n );\n }\n const rewrittenSvg = rewriteSvgFontsForJsPDF(liveSvgStr);\n const reParser = new DOMParser();\n const reDoc = reParser.parseFromString(rewrittenSvg, 'image/svg+xml');\n processedSvg = reDoc.documentElement as unknown as SVGElement;\n try {\n dumpSvgTextDiagnostics(\n rewrittenSvg,\n i,\n PARITY_TAG,\n 'STAGE-3-after-rewriteSvgFontsForJsPDF',\n );\n } catch {}\n }\n\n if (processedSvg) {\n pdf.setFillColor(0, 0, 0);\n pdf.setDrawColor(0, 0, 0);\n pdf.saveGraphicsState();\n setPdfColorFromSvg(pdf, processedSvg, `page-${i + 1}`);\n await svg2pdfWithDomMount(processedSvg, pdf, svg2pdfOpts(0, 0, page.width, page.height));\n pdf.restoreGraphicsState();\n pdf.setFillColor(0, 0, 0);\n pdf.setDrawColor(0, 0, 0);\n }\n }\n\n const arrayBuffer = pdf.output('arraybuffer');\n const blob = new Blob([arrayBuffer], { type: 'application/pdf' });\n\n return {\n blob,\n arrayBuffer,\n totalPages: svgResults.length,\n pages: svgResults.map((p) => ({ width: p.width, height: p.height })),\n };\n}\n","/**\n * Templates Catalog API — list published templates by workspace.\n *\n * Uses the public RLS policy on `templates` (status='published') so this\n * works with the anon key, no auth required.\n */\n\nexport interface PublishedTemplate {\n id: string;\n name: string;\n description: string | null;\n category: string;\n thumbnail_url: string | null;\n preview_images: unknown | null;\n price: number;\n download_count: number;\n workspace_id: string | null;\n sort_order: number;\n created_at: string;\n updated_at: string;\n}\n\nexport interface ListPublishedTemplatesOptions {\n /** Workspace UUID — fetches every published template owned by this workspace. */\n workspaceId: string;\n /** Supabase project URL */\n supabaseUrl: string;\n /** Supabase anon (publishable) key */\n supabaseAnonKey: string;\n /** Optional category filter (e.g. 'social-media', 'invitation') */\n category?: string;\n /** Limit (default: 200, max enforced by PostgREST) */\n limit?: number;\n /** Offset for pagination (default: 0) */\n offset?: number;\n}\n\nconst SELECT_COLUMNS =\n 'id,name,description,category,thumbnail_url,preview_images,price,download_count,workspace_id,sort_order,created_at,updated_at';\n\n/**\n * List all published templates for a workspace.\n *\n * ```ts\n * const templates = await listPublishedTemplates({\n * workspaceId: 'your-workspace-uuid',\n * supabaseUrl: 'https://xxx.supabase.co',\n * supabaseAnonKey: 'eyJ...',\n * });\n * ```\n */\nexport async function listPublishedTemplates(\n options: ListPublishedTemplatesOptions,\n): Promise<PublishedTemplate[]> {\n const { workspaceId, supabaseUrl, supabaseAnonKey, category, limit = 200, offset = 0 } = options;\n\n if (!workspaceId) throw new Error('listPublishedTemplates: workspaceId is required');\n if (!supabaseUrl || !supabaseAnonKey) {\n throw new Error('listPublishedTemplates: supabaseUrl and supabaseAnonKey are required');\n }\n\n const params = new URLSearchParams({\n select: SELECT_COLUMNS,\n workspace_id: `eq.${workspaceId}`,\n status: 'eq.published',\n order: 'sort_order.asc,updated_at.desc',\n limit: String(limit),\n offset: String(offset),\n });\n if (category) params.set('category', `eq.${category}`);\n\n const url = `${supabaseUrl.replace(/\\/$/, '')}/rest/v1/templates?${params.toString()}`;\n const res = await fetch(url, {\n headers: {\n apikey: supabaseAnonKey,\n Authorization: `Bearer ${supabaseAnonKey}`,\n Accept: 'application/json',\n },\n });\n if (!res.ok) {\n const text = await res.text().catch(() => '');\n throw new Error(`listPublishedTemplates failed: ${res.status} ${text}`);\n }\n return (await res.json()) as PublishedTemplate[];\n}\n\n/** Fetch a single published template by ID (anon-readable). */\nexport async function getPublishedTemplate(options: {\n templateId: string;\n supabaseUrl: string;\n supabaseAnonKey: string;\n}): Promise<PublishedTemplate | null> {\n const { templateId, supabaseUrl, supabaseAnonKey } = options;\n const params = new URLSearchParams({\n select: SELECT_COLUMNS,\n id: `eq.${templateId}`,\n status: 'eq.published',\n limit: '1',\n });\n const url = `${supabaseUrl.replace(/\\/$/, '')}/rest/v1/templates?${params.toString()}`;\n const res = await fetch(url, {\n headers: {\n apikey: supabaseAnonKey,\n Authorization: `Bearer ${supabaseAnonKey}`,\n Accept: 'application/json',\n },\n });\n if (!res.ok) return null;\n const rows = (await res.json()) as PublishedTemplate[];\n return rows[0] ?? null;\n}","/**\n * Preview Warm-up API — Prefetch fonts and image assets for a resolved template\n * so that subsequent `render` / `renderAllPages` / `renderFromForm` calls resolve\n * faster from browser caches.\n *\n * Intended for **idle / background** use on the host (e.g. on route mount).\n * **Idempotent** — safe to call multiple times for the same config.\n * Does **not** require mounting a canvas or React tree.\n */\n\nimport type { TemplateConfig, CanvasNode } from './types';\nimport { ensureFontsForResolvedConfig } from './font-loader';\nimport { resolveFromForm } from './data-resolver';\nimport type { ResolveFromFormOptions } from './data-resolver';\nimport { API_URL } from './shims/app-api';\n\n// ─── Shared image URL collector (single source of truth) ───────────────\n\n/**\n * Collect all image asset URLs from a TemplateConfig that the Fabric canvas\n * will request during rendering. This is the canonical list — the same logic\n * that `getExpectedImageCount` uses, but returning URLs instead of a count.\n *\n * Walks **all pages** and recurses into children / groups.\n */\nexport function collectImageUrls(config: TemplateConfig): string[] {\n const urls: string[] = [];\n\n const walk = (nodes: CanvasNode[]) => {\n for (const node of nodes) {\n if (!node || node.visible === false) continue;\n const src = typeof node.src === 'string' ? node.src.trim() : '';\n const imageUrl = typeof node.imageUrl === 'string' ? node.imageUrl.trim() : '';\n if (node.type === 'image') {\n const url = src || imageUrl;\n if (url) urls.push(url);\n }\n if (Array.isArray(node.children) && node.children.length > 0) {\n walk(node.children as CanvasNode[]);\n }\n }\n };\n\n for (const page of config.pages || []) {\n walk((page.children || []) as CanvasNode[]);\n }\n\n return urls;\n}\n\n/**\n * Apply the same proxy / public-URL normalization that the render path uses\n * so the browser cache key matches what Fabric will request.\n */\nfunction normalizeAssetUrl(rawUrl: string, imageProxyUrl?: string): string | null {\n if (!rawUrl) return null;\n if (rawUrl.startsWith('data:') || rawUrl.startsWith('blob:')) return null; // already local\n\n // Same-origin bundled static assets (relative or absolute): prefetch directly.\n if (rawUrl.startsWith('/') && !rawUrl.startsWith('//')) {\n if (typeof window !== 'undefined') return new URL(rawUrl, window.location.origin).toString();\n return null;\n }\n\n // Private / localhost URLs can't be fetched\n try {\n const h = new URL(rawUrl).hostname.toLowerCase();\n if (h === 'localhost' || h === '127.0.0.1' || h === '0.0.0.0' || h.endsWith('.local') || /^(10\\.|192\\.168\\.|169\\.254\\.)/.test(h)) {\n // Same-origin bundled assets are still prefetchable\n if (typeof window !== 'undefined' && new URL(rawUrl).origin === window.location.origin) {\n return rawUrl;\n }\n return null;\n }\n } catch {\n return null;\n }\n\n // Supabase storage signed URLs → public\n const supabaseUrl = typeof (globalThis as any).__VITE_SUPABASE_URL === 'string'\n ? (globalThis as any).__VITE_SUPABASE_URL\n : '';\n if (supabaseUrl && rawUrl.includes(supabaseUrl)) {\n const signedMatch = rawUrl.match(/\\/storage\\/v1\\/object\\/sign\\/([^?]+)/);\n if (signedMatch) return `${supabaseUrl}/storage/v1/object/public/${signedMatch[1]}`;\n if (rawUrl.includes('/storage/v1/object/public/')) return rawUrl;\n }\n\n // Use the proxy URL configured via setPackageApiUrl / imageProxyUrl option\n const proxyBase = imageProxyUrl\n ? imageProxyUrl.replace(/\\/image-proxy(?:\\?.*)?$/, '')\n : API_URL;\n\n if (proxyBase) {\n return `${proxyBase}/image-proxy?url=${encodeURIComponent(rawUrl)}`;\n }\n\n // No proxy — try the raw URL directly (may fail CORS but warms the CDN)\n return rawUrl;\n}\n\n// ─── Prefetch engine ────────────────────────────────────────────────────\n\nconst CONCURRENCY = 6;\n\nasync function prefetchUrls(\n urls: string[],\n signal?: AbortSignal,\n): Promise<void> {\n const unique = [...new Set(urls)];\n if (unique.length === 0) return;\n\n let i = 0;\n const next = async (): Promise<void> => {\n while (i < unique.length) {\n if (signal?.aborted) return;\n const url = unique[i++];\n try {\n await fetch(url, { signal, mode: 'cors', credentials: 'omit' });\n } catch {\n // Swallow per-URL failures — warming is best-effort\n }\n }\n };\n\n const workers = Array.from({ length: Math.min(CONCURRENCY, unique.length) }, () => next());\n await Promise.all(workers);\n}\n\n// ─── Public API ─────────────────────────────────────────────────────────\n\nexport interface WarmOptions {\n /** AbortSignal to cancel in-flight prefetches (e.g. on route change). */\n signal?: AbortSignal;\n /** Image proxy base URL. Falls back to the value set via `setPackageApiUrl`. */\n imageProxyUrl?: string;\n}\n\n/**\n * Warm fonts **and** image assets for a fully-resolved `TemplateConfig`.\n *\n * Call this on idle / in the background before rendering so that `render()`\n * resolves from browser caches instead of hitting the network.\n *\n * **Idempotent** — repeated calls for the same config are near-instant\n * (fonts deduplicate internally; `fetch` hits HTTP cache).\n *\n * Does **not** mount a canvas or require React.\n *\n * @example\n * ```ts\n * import { warmResolvedTemplateForPreview } from '@pixldocs/canvas-renderer';\n *\n * const controller = new AbortController();\n * await warmResolvedTemplateForPreview(resolvedConfig, { signal: controller.signal });\n * // Later: renderer.render(resolvedConfig) — fonts & images are cached\n * ```\n */\nexport async function warmResolvedTemplateForPreview(\n config: TemplateConfig,\n options?: WarmOptions,\n): Promise<void> {\n const { signal, imageProxyUrl } = options ?? {};\n\n // 1. Fonts (reuses the existing idempotent loader)\n await ensureFontsForResolvedConfig(config);\n\n if (signal?.aborted) return;\n\n // 2. Collect & normalize image URLs using the same rules as the render path\n const rawUrls = collectImageUrls(config);\n const resolvedUrls = rawUrls\n .map((u) => normalizeAssetUrl(u, imageProxyUrl))\n .filter((u): u is string => u !== null);\n\n // 3. Prefetch with bounded concurrency\n await prefetchUrls(resolvedUrls, signal);\n}\n\n/**\n * Convenience: resolve a template from the database **and** warm its assets\n * in a single call. Combines `resolveFromForm` + `warmResolvedTemplateForPreview`.\n *\n * @example\n * ```ts\n * import { warmTemplateFromForm } from '@pixldocs/canvas-renderer';\n *\n * await warmTemplateFromForm({\n * templateId: 'dc3fbb17-...',\n * formSchemaId: 'b04cd362-...',\n * sectionState: { ... },\n * supabaseUrl: '...',\n * supabaseAnonKey: '...',\n * signal: controller.signal,\n * });\n * ```\n */\nexport async function warmTemplateFromForm(\n options: ResolveFromFormOptions & WarmOptions,\n): Promise<void> {\n const { signal, imageProxyUrl, ...resolveOpts } = options;\n\n const resolved = await resolveFromForm(resolveOpts);\n\n if (signal?.aborted) return;\n\n await warmResolvedTemplateForPreview(resolved.config, { signal, imageProxyUrl });\n}\n","/**\n * @pixldocs/canvas-renderer\n * \n * Client-side template renderer for Pixldocs — React component + imperative API.\n * Renders templates to canvas with 1:1 parity with the Pixldocs editor.\n * \n * React Component (recommended):\n * import { PixldocsPreview } from '@pixldocs/canvas-renderer';\n * \n * // Mode 1: Pre-resolved config\n * <PixldocsPreview config={templateConfig} pageIndex={0} />\n * \n * // Mode 2: Auto-resolve from database (like the server API)\n * <PixldocsPreview\n * templateId=\"dc3fbb17-...\"\n * formSchemaId=\"b04cd362-...\"\n * sectionState={sectionState}\n * supabaseUrl=\"https://xxx.supabase.co\"\n * supabaseAnonKey=\"eyJ...\"\n * />\n * \n * Imperative API:\n * import { PixldocsRenderer } from '@pixldocs/canvas-renderer';\n * \n * const renderer = new PixldocsRenderer({ supabaseUrl, supabaseAnonKey });\n * \n * // Render from V2 sectionState (same as server API)\n * const results = await renderer.renderFromForm({\n * templateId: 'dc3fbb17-...',\n * formSchemaId: 'b04cd362-...',\n * sectionState: { ... },\n * });\n * \n * // Or render a pre-resolved config\n * const { dataUrl } = await renderer.render(templateConfig);\n */\n\n// React component\nexport { PixldocsPreview } from './PixldocsPreview';\nexport type { PixldocsPreviewProps, PixldocsPreviewConfigProps, PixldocsPreviewResolveProps } from './PixldocsPreview';\n\n// Imperative renderer\nexport { PixldocsRenderer } from './renderer';\nexport { PACKAGE_VERSION, DEPLOYMENT_VERSION_MARKER } from './renderer';\nexport type { RendererConfig, RenderOptions, RenderResult, RenderFromFormOptions, PdfFromFormOptions, SvgRenderResult } from './renderer';\n\n// PDF export\nexport { assemblePdfFromSvgs } from './pdf-export';\nexport type { PdfRenderResult, PdfAssemblyOptions } from './pdf-export';\nexport { dumpSvgTextDiagnostics } from './pdf-export';\n\n// Data resolution\nexport { resolveTemplateData, resolveFromForm, getTemplateForm } from './data-resolver';\nexport type { ResolveOptions, ResolveFromFormOptions, ResolvedTemplate, GetTemplateFormOptions, TemplateForm } from './data-resolver';\n\n// Templates catalog (list/fetch published templates by workspace)\nexport { listPublishedTemplates, getPublishedTemplate } from './templates-api';\nexport type { PublishedTemplate, ListPublishedTemplatesOptions } from './templates-api';\n\n// Utilities\nexport { loadGoogleFontCSS, collectFontsFromConfig, normalizeFontFamily } from './font-loader';\nexport {\n ensureFontsForResolvedConfig,\n collectFontDescriptorsFromConfig,\n awaitFontsForConfig,\n configHasAutoShrinkText,\n} from './font-loader';\nexport type { FontDescriptor } from './font-loader';\nexport { applyThemeToConfig } from './theme';\nexport type { ThemeVariables } from './theme';\n\n// PDF font embedding\nexport { extractFontFamiliesFromSvgs, embedFontsInPdf, embedFont, embedFontsForConfig, rewriteSvgFontsForJsPDF, getEmbeddedJsPDFFontName, isFontAvailable, resolveFontWeight, FONT_FILES, FONT_FALLBACK_SYMBOLS, FONT_FALLBACK_DEVANAGARI, FONT_FALLBACK_MATH } from './pdf-fonts';\n\n// Warm-up / prefetch API\nexport { warmResolvedTemplateForPreview, warmTemplateFromForm, collectImageUrls } from './warm';\nexport type { WarmOptions } from './warm';\n\n// Bundled-asset support — let host apps register same-origin static prefixes\n// (e.g. `/pixldocs-bundled-assets/`) that should bypass the Supabase image-proxy.\nexport { setBundledAssetPrefixes, isBundledAssetUrl, getProxiedImageUrl, isPrivateUrl } from '@/lib/canvasImageLoader';\n\n// Diagnostics\n/**\n * Enable verbose console logs for the auto-shrink loop in the live preview.\n * Logs target width, measured line widths, font availability, and the chosen\n * fontSize for each text element with `overflowPolicy: 'auto-shrink'`.\n * Disabled by default — call once from the host app when debugging.\n */\nexport function setAutoShrinkDebug(enabled: boolean): void {\n if (typeof window !== 'undefined') {\n (window as any).__pixldocsDebugAutoShrink = !!enabled;\n }\n}\n\n// Types\nexport type { TemplateConfig, CanvasNode, TemplateConfigPage, DynamicField, ThemeConfig, PageSettings, CanvasSize } from './types';\nexport type { SectionFormState, InferredSection } from '@/lib/inferFormSchemaFromTemplate';\n\n// Re-export shared types for consumer convenience\nexport type { SmartElementType, SmartElementProps } from '@shared/smart-elements/types';\n"],"names":["API_URL","fabric","newId","cloneNodeWithNewIds","create","id","expandedIds","_a","loadingPromises","loadFontUnified","url","imageFit","elementWidth","elementHeight","img","clamp","minDim","ct","buildRoundedRectPath","startX","startY","buildCanonicalRoundedRectPath","forwardRef","useRef","useState","useMemo","useEffect","useCallback","useImperativeHandle","canvas","zoom","scaledWidth","scaledHeight","elements","selectedGroup","flushSync","currentPage","isCropGroup","transform","corner","updateElement","_b","_c","modifiedTarget","pageChildren","e","toast","commitHistory","shouldSkipUpdates","isTransforming","loadImageAsync","applyMaskToCropGroup","fc","isDynamicField","canBeEvented","baseScaleX","baseScaleY","needCropGroup","jsxs","jsx","isActive","Fragment","fields","idPrefix","m","direct","canonicalSuffix","nestedMatch","match","cloned","baseId","nestedStayCloned","stayVersion","overflowEntryClone","overflowVersion","HOST_LOCAL_FONTS","hostLoadFont","configHasAutoShrinkText","out","AppPreviewCanvas","TextboxProto","stateProps","cacheProps","setPackageApiUrl","PreviewCanvas","createRoot","createElement","registry","svg2pdf","measureCanvas","ShadingPattern","jsPDF","extractFontFamiliesFromSvgs","embedFontVariantsFromSvg"],"mappings":"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"}
|