@elixpo/lixsketch 5.4.7 → 5.5.1
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/dist/react/AIRenderer-M4LMJ66J.js +1105 -0
- package/dist/react/AIRenderer-M4LMJ66J.js.map +7 -0
- package/dist/react/Arrow-BJDAXPMH.js +8 -0
- package/dist/react/Arrow-BJDAXPMH.js.map +7 -0
- package/dist/react/Circle-KPG7TKIX.js +8 -0
- package/dist/react/Circle-KPG7TKIX.js.map +7 -0
- package/dist/react/CodeShape-K4DIZAIV.js +8 -0
- package/dist/react/CodeShape-K4DIZAIV.js.map +7 -0
- package/dist/react/CopyPaste-4CKJRHJ3.js +569 -0
- package/dist/react/CopyPaste-4CKJRHJ3.js.map +7 -0
- package/dist/react/EraserTrail-PA6IQLQN.js +20 -0
- package/dist/react/EraserTrail-PA6IQLQN.js.map +7 -0
- package/dist/react/EventDispatcher-SRFH6LQZ.js +463 -0
- package/dist/react/EventDispatcher-SRFH6LQZ.js.map +7 -0
- package/dist/react/Frame-6UR5XPAX.js +10 -0
- package/dist/react/Frame-6UR5XPAX.js.map +7 -0
- package/dist/react/FreehandStroke-CK24NUT3.js +8 -0
- package/dist/react/FreehandStroke-CK24NUT3.js.map +7 -0
- package/dist/react/GraphEngine-QE5B2PMR.js +340 -0
- package/dist/react/GraphEngine-QE5B2PMR.js.map +7 -0
- package/dist/react/GraphMathParser-2WMTY4IE.js +10 -0
- package/dist/react/GraphMathParser-2WMTY4IE.js.map +7 -0
- package/dist/react/IconShape-KMIA6T2H.js +10 -0
- package/dist/react/IconShape-KMIA6T2H.js.map +7 -0
- package/dist/react/ImageShape-CHHGBXUQ.js +10 -0
- package/dist/react/ImageShape-CHHGBXUQ.js.map +7 -0
- package/dist/react/LayerOrder-XCHF4MSS.js +66 -0
- package/dist/react/LayerOrder-XCHF4MSS.js.map +7 -0
- package/dist/react/Line-2KOQEEGA.js +10 -0
- package/dist/react/Line-2KOQEEGA.js.map +7 -0
- package/dist/react/LixScriptParser-JYWJX375.js +1033 -0
- package/dist/react/LixScriptParser-JYWJX375.js.map +7 -0
- package/dist/react/MermaidFlowchartRenderer-4QBAZ5MB.js +412 -0
- package/dist/react/MermaidFlowchartRenderer-4QBAZ5MB.js.map +7 -0
- package/dist/react/MermaidSequenceParser-UKG2NSZY.js +8 -0
- package/dist/react/MermaidSequenceParser-UKG2NSZY.js.map +7 -0
- package/dist/react/MermaidSequenceRenderer-HPLHY5II.js +387 -0
- package/dist/react/MermaidSequenceRenderer-HPLHY5II.js.map +7 -0
- package/dist/react/Rectangle-6FE7RN6W.js +8 -0
- package/dist/react/Rectangle-6FE7RN6W.js.map +7 -0
- package/dist/react/ResizeCode-WAMDTKSW.js +2 -0
- package/dist/react/ResizeCode-WAMDTKSW.js.map +7 -0
- package/dist/react/ResizeShapes-LKEQTITP.js +250 -0
- package/dist/react/ResizeShapes-LKEQTITP.js.map +7 -0
- package/dist/react/SceneSerializer-4U4B24JM.js +739 -0
- package/dist/react/SceneSerializer-4U4B24JM.js.map +7 -0
- package/dist/react/Selection-VVUHY5YJ.js +34 -0
- package/dist/react/Selection-VVUHY5YJ.js.map +7 -0
- package/dist/react/SketchEngine-YA4RG3KX.js +413 -0
- package/dist/react/SketchEngine-YA4RG3KX.js.map +7 -0
- package/dist/react/TextShape-54ZJ66E3.js +8 -0
- package/dist/react/TextShape-54ZJ66E3.js.map +7 -0
- package/dist/react/UndoRedo-M2JZUBKN.js +30 -0
- package/dist/react/UndoRedo-M2JZUBKN.js.map +7 -0
- package/dist/react/ZoomPan-U3TXC5AJ.js +186 -0
- package/dist/react/ZoomPan-U3TXC5AJ.js.map +7 -0
- package/dist/react/arrowTool-CWEMIRXK.js +17 -0
- package/dist/react/arrowTool-CWEMIRXK.js.map +7 -0
- package/dist/react/boxicons-5JNJQPUP.woff +0 -0
- package/dist/react/boxicons-6NVWQSCQ.eot +0 -0
- package/dist/react/boxicons-AQ5N6WP7.woff2 +0 -0
- package/dist/react/boxicons-GDR4JU3X.ttf +0 -0
- package/dist/react/boxicons-NNFHLMOR.svg +1660 -0
- package/dist/react/chunk-2OQXI7QB.js +564 -0
- package/dist/react/chunk-2OQXI7QB.js.map +7 -0
- package/dist/react/chunk-5OUBTHHO.js +187 -0
- package/dist/react/chunk-5OUBTHHO.js.map +7 -0
- package/dist/react/chunk-6PFXZKL2.js +628 -0
- package/dist/react/chunk-6PFXZKL2.js.map +7 -0
- package/dist/react/chunk-6SFNWGGZ.js +453 -0
- package/dist/react/chunk-6SFNWGGZ.js.map +7 -0
- package/dist/react/chunk-7TZSIR6V.js +210 -0
- package/dist/react/chunk-7TZSIR6V.js.map +7 -0
- package/dist/react/chunk-AJAZC37E.js +662 -0
- package/dist/react/chunk-AJAZC37E.js.map +7 -0
- package/dist/react/chunk-BU4D2WYQ.js +1213 -0
- package/dist/react/chunk-BU4D2WYQ.js.map +7 -0
- package/dist/react/chunk-BZE4CEBG.js +747 -0
- package/dist/react/chunk-BZE4CEBG.js.map +7 -0
- package/dist/react/chunk-CB2RANCB.js +212 -0
- package/dist/react/chunk-CB2RANCB.js.map +7 -0
- package/dist/react/chunk-DNAG7ML6.js +128 -0
- package/dist/react/chunk-DNAG7ML6.js.map +7 -0
- package/dist/react/chunk-HZWLPXFN.js +198 -0
- package/dist/react/chunk-HZWLPXFN.js.map +7 -0
- package/dist/react/chunk-I6HCCIXB.js +572 -0
- package/dist/react/chunk-I6HCCIXB.js.map +7 -0
- package/dist/react/chunk-IZ5OGWGW.js +235 -0
- package/dist/react/chunk-IZ5OGWGW.js.map +7 -0
- package/dist/react/chunk-JJCJNLNN.js +1490 -0
- package/dist/react/chunk-JJCJNLNN.js.map +7 -0
- package/dist/react/chunk-JQ3IRFDP.js +222 -0
- package/dist/react/chunk-JQ3IRFDP.js.map +7 -0
- package/dist/react/chunk-L5OARZJ7.js +1134 -0
- package/dist/react/chunk-L5OARZJ7.js.map +7 -0
- package/dist/react/chunk-LHRTXNVE.js +1600 -0
- package/dist/react/chunk-LHRTXNVE.js.map +7 -0
- package/dist/react/chunk-Q2GA4MBZ.js +1653 -0
- package/dist/react/chunk-Q2GA4MBZ.js.map +7 -0
- package/dist/react/chunk-QNSE5BAY.js +519 -0
- package/dist/react/chunk-QNSE5BAY.js.map +7 -0
- package/dist/react/chunk-QXFBG7OM.js +191 -0
- package/dist/react/chunk-QXFBG7OM.js.map +7 -0
- package/dist/react/chunk-T6ZVV5ZO.js +714 -0
- package/dist/react/chunk-T6ZVV5ZO.js.map +7 -0
- package/dist/react/chunk-URB6MY46.js +974 -0
- package/dist/react/chunk-URB6MY46.js.map +7 -0
- package/dist/react/chunk-VN62KLOC.js +931 -0
- package/dist/react/chunk-VN62KLOC.js.map +7 -0
- package/dist/react/chunk-VQVEPJSA.js +158 -0
- package/dist/react/chunk-VQVEPJSA.js.map +7 -0
- package/dist/react/chunk-XISEAGBV.js +1632 -0
- package/dist/react/chunk-XISEAGBV.js.map +7 -0
- package/dist/react/chunk-YKJUBFHE.js +575 -0
- package/dist/react/chunk-YKJUBFHE.js.map +7 -0
- package/dist/react/circleTool-NUATSEI2.js +14 -0
- package/dist/react/circleTool-NUATSEI2.js.map +7 -0
- package/dist/react/codeTool-MHCB2FNB.js +38 -0
- package/dist/react/codeTool-MHCB2FNB.js.map +7 -0
- package/dist/react/eraserTool-2GS2LQCS.js +103 -0
- package/dist/react/eraserTool-2GS2LQCS.js.map +7 -0
- package/dist/react/frameTool-PWVKKXSP.js +14 -0
- package/dist/react/frameTool-PWVKKXSP.js.map +7 -0
- package/dist/react/freehandTool-SLYGASVP.js +14 -0
- package/dist/react/freehandTool-SLYGASVP.js.map +7 -0
- package/dist/react/iconTool-GPZ7O7NH.js +18 -0
- package/dist/react/iconTool-GPZ7O7NH.js.map +7 -0
- package/dist/react/imageTool-D5R4XGEU.js +15 -0
- package/dist/react/imageTool-D5R4XGEU.js.map +7 -0
- package/dist/react/index.js +5349 -0
- package/dist/react/index.js.map +7 -0
- package/dist/react/laserTool-XVMV63AV.js +239 -0
- package/dist/react/laserTool-XVMV63AV.js.map +7 -0
- package/dist/react/lineTool-WNI5EMZ5.js +14 -0
- package/dist/react/lineTool-WNI5EMZ5.js.map +7 -0
- package/dist/react/lixCode-OJMVUXXI.ttf +0 -0
- package/dist/react/lixDefault-JEAPAUJL.ttf +0 -0
- package/dist/react/lixFancy-BPXYM5CQ.ttf +0 -0
- package/dist/react/lixFont-CPKEUDVM.woff2 +0 -0
- package/dist/react/rectangleTool-U7DZ6ZTA.js +14 -0
- package/dist/react/rectangleTool-U7DZ6ZTA.js.map +7 -0
- package/dist/react/styles.css +6627 -0
- package/dist/react/textTool-M7S6F3VC.js +21 -0
- package/dist/react/textTool-M7S6F3VC.js.map +7 -0
- package/package.json +39 -5
- package/src/EngineShortcuts.js +83 -27
- package/src/core/AIRenderer.js +30 -18
- package/src/core/GraphEngine.js +64 -41
- package/src/core/MermaidFlowchartRenderer.js +153 -88
- package/src/core/MermaidSequenceRenderer.js +168 -93
- package/src/core/SceneSerializer.js +86 -2
- package/src/core/Selection.js +119 -19
- package/src/core/UndoRedo.js +82 -15
- package/src/core/ZoomPan.js +15 -5
- package/src/index.js +14 -1
- package/src/react/LixSketchCanvas.jsx +347 -0
- package/src/react/components/AppMenu.jsx +482 -0
- package/src/react/components/Footer.jsx +85 -0
- package/src/react/components/Toolbar.jsx +140 -0
- package/src/react/components/canvas/CanvasLoadingOverlay.jsx +76 -0
- package/src/react/components/canvas/ContextMenu.jsx +466 -0
- package/src/react/components/canvas/FindBar.jsx +177 -0
- package/src/react/components/canvas/ImageSourcePicker.jsx +133 -0
- package/src/react/components/canvas/MultiSelectActions.jsx +120 -0
- package/src/react/components/canvas/SVGCanvas.jsx +145 -0
- package/src/react/components/canvas/SaveStatusIndicator.jsx +29 -0
- package/src/react/components/modals/CanvasPropertiesModal.jsx +358 -0
- package/src/react/components/modals/CommandPalette.jsx +307 -0
- package/src/react/components/modals/ExportImageModal.jsx +287 -0
- package/src/react/components/modals/GraphModal.jsx +174 -0
- package/src/react/components/modals/HelpModal.jsx +208 -0
- package/src/react/components/modals/LixScriptModal.jsx +130 -0
- package/src/react/components/modals/ShortcutsModal.jsx +125 -0
- package/src/react/components/sidebars/ArrowSidebar.jsx +173 -0
- package/src/react/components/sidebars/CircleSidebar.jsx +134 -0
- package/src/react/components/sidebars/FrameSidebar.jsx +263 -0
- package/src/react/components/sidebars/IconSidebar.jsx +279 -0
- package/src/react/components/sidebars/ImageSidebar.jsx +69 -0
- package/src/react/components/sidebars/LineSidebar.jsx +109 -0
- package/src/react/components/sidebars/PaintbrushSidebar.jsx +119 -0
- package/src/react/components/sidebars/RectangleSidebar.jsx +165 -0
- package/src/react/components/sidebars/ShapeSidebar.jsx +130 -0
- package/src/react/components/sidebars/TextSidebar.jsx +174 -0
- package/src/react/hooks/inertStores.js +58 -0
- package/src/react/hooks/useSketchEngine.js +76 -0
- package/src/react/hooks/useTranslation.js +92 -0
- package/src/react/index.js +41 -0
- package/src/react/store/useSketchStore.js +234 -0
- package/src/react/store/useUIStore.js +196 -0
- package/src/react/styles/arrowSidebar.css +263 -0
- package/src/react/styles/canvasStroke.css +47 -0
- package/src/react/styles/canvasTools.css +769 -0
- package/src/react/styles/circleSidebar.css +206 -0
- package/src/react/styles/fonts/fonts.css +29 -0
- package/src/react/styles/fonts/lixCode.ttf +0 -0
- package/src/react/styles/fonts/lixDefault.ttf +0 -0
- package/src/react/styles/fonts/lixDocs.ttf +0 -0
- package/src/react/styles/fonts/lixFancy.ttf +0 -0
- package/src/react/styles/fonts/lixFont.woff2 +0 -0
- package/src/react/styles/lineSidebar.css +207 -0
- package/src/react/styles/paintbrushSidebar.css +247 -0
- package/src/react/styles/squareSidebar.css +206 -0
- package/src/react/styles/writeText.css +149 -0
- package/src/react/styles.css +175 -0
- package/src/react/toolsEnum.js +20 -0
- package/src/react/utils/toast.js +18 -0
- package/src/shapes/Frame.js +7 -1
- package/src/shapes/Line.js +11 -5
- package/src/tools/arrowTool.js +30 -4
- package/src/tools/circleTool.js +33 -9
- package/src/tools/codeTool.js +5 -3
- package/src/tools/frameTool.js +47 -7
- package/src/tools/freehandTool.js +12 -4
- package/src/tools/iconTool.js +7 -1
- package/src/tools/imageTool.js +7 -1
- package/src/tools/lineTool.js +27 -3
- package/src/tools/rectangleTool.js +45 -8
- package/src/tools/textTool.js +23 -6
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/core/LixScriptParser.js"],
|
|
4
|
+
"sourcesContent": ["/* eslint-disable */\n/**\n * LixScript \u2014 Programmatic diagram DSL for LixSketch\n *\n * Parses a text-based language into canvas shapes with full control over\n * properties, positions, connections, and grouping.\n *\n * Usage:\n * const result = parseLixScript(source)\n * if (result.errors.length) { ... }\n * renderLixScript(result)\n */\n\nconst NS = 'http://www.w3.org/2000/svg'\n\n// ============================================================\n// TOKENIZER\n// ============================================================\n\n/**\n * Tokenize a LixScript source string into a flat list of tokens.\n * Each token: { type, value, line }\n */\nfunction tokenize(source) {\n const tokens = []\n const lines = source.split('\\n')\n\n for (let i = 0; i < lines.length; i++) {\n const raw = lines[i]\n const lineNum = i + 1\n\n // Strip comments\n const commentIdx = raw.indexOf('//')\n const line = commentIdx !== -1 ? raw.slice(0, commentIdx) : raw\n const trimmed = line.trim()\n if (!trimmed) continue\n\n tokens.push({ type: 'LINE', value: trimmed, line: lineNum })\n }\n\n return tokens\n}\n\n// ============================================================\n// PARSER\n// ============================================================\n\n/**\n * Parse LixScript source into an AST.\n * Returns { variables, shapes, errors }\n */\nexport function parseLixScript(source) {\n const tokens = tokenize(source)\n const variables = {}\n const shapes = []\n const errors = []\n\n let i = 0\n\n while (i < tokens.length) {\n const token = tokens[i]\n const line = token.value\n const lineNum = token.line\n\n try {\n // Variable assignment: $name = value\n if (line.startsWith('$')) {\n const match = line.match(/^\\$(\\w+)\\s*=\\s*(.+)$/)\n if (match) {\n variables[match[1]] = match[2].trim()\n } else {\n errors.push({ line: lineNum, message: `Invalid variable syntax: ${line}` })\n }\n i++\n continue\n }\n\n // Shape declarations\n const shapeMatch = line.match(/^(rect|circle|ellipse|arrow|line|text|frame|freehand|image|icon)\\s+(\\w+)\\s+(.+)$/)\n if (shapeMatch) {\n const [, type, id, rest] = shapeMatch\n const shape = parseShapeDeclaration(type, id, rest, lineNum, errors, variables)\n\n // Check for property block { ... }\n if (rest.includes('{') && !rest.includes('}')) {\n // Multi-line property block \u2014 consume lines until closing }\n i++\n const props = []\n while (i < tokens.length && !tokens[i].value.startsWith('}')) {\n props.push(tokens[i].value)\n i++\n }\n if (i < tokens.length) i++ // skip closing }\n parseProperties(shape, props, variables, errors)\n } else if (rest.includes('{') && rest.includes('}')) {\n // Inline property block\n const blockMatch = rest.match(/\\{([^}]*)\\}/)\n if (blockMatch) {\n const props = blockMatch[1].split(/[,;]/).map(s => s.trim()).filter(Boolean)\n parseProperties(shape, props, variables, errors)\n }\n i++ // advance past this single line\n } else {\n // No property block\n i++\n }\n\n shapes.push(shape)\n continue\n }\n\n errors.push({ line: lineNum, message: `Unrecognized syntax: ${line}` })\n i++\n } catch (err) {\n errors.push({ line: lineNum, message: err.message })\n i++\n }\n }\n\n return { variables, shapes, errors }\n}\n\n/**\n * Parse the declaration part (after type and id) of a shape.\n */\nfunction parseShapeDeclaration(type, id, rest, lineNum, errors, variables) {\n const shape = { type, id, line: lineNum, props: {} }\n\n // Extract position: at X, Y or from ... to ...\n if (type === 'arrow' || type === 'line') {\n // from source[.side] to target[.side]\n // from X, Y to X, Y\n const connMatch = rest.match(/from\\s+(.+?)\\s+to\\s+(.+?)(?:\\s*\\{|$)/)\n if (connMatch) {\n shape.from = parsePointOrRef(connMatch[1].trim(), variables)\n shape.to = parsePointOrRef(connMatch[2].trim(), variables)\n } else {\n errors.push({ line: lineNum, message: `${type} requires 'from ... to ...' syntax` })\n }\n } else {\n // at X, Y\n const atMatch = rest.match(/at\\s+([\\w$.+\\-*\\s]+?),\\s*([\\w$.+\\-*\\s]+?)(?:\\s+size|\\s*\\{|$)/)\n if (atMatch) {\n shape.x = parseExpr(atMatch[1].trim(), variables)\n shape.y = parseExpr(atMatch[2].trim(), variables)\n } else if (type !== 'frame') {\n errors.push({ line: lineNum, message: `${type} requires 'at X, Y' syntax` })\n }\n\n // size WxH\n const sizeMatch = rest.match(/size\\s+([\\w$.+\\-*]+)\\s*x\\s*([\\w$.+\\-*]+)/)\n if (sizeMatch) {\n shape.width = parseExpr(sizeMatch[1].trim(), variables)\n shape.height = parseExpr(sizeMatch[2].trim(), variables)\n }\n }\n\n return shape\n}\n\n/**\n * Parse a point reference \u2014 either a coordinate pair \"X, Y\" or\n * a shape reference \"shapeId.side\" or \"shapeId.side + offset\"\n */\nfunction parsePointOrRef(str, variables) {\n // shapeId.side [+/- offset]\n const refMatch = str.match(/^(\\w+)\\.(\\w+)(?:\\s*([+-])\\s*([\\d.]+))?$/)\n if (refMatch) {\n return {\n ref: refMatch[1],\n side: refMatch[2],\n offset: refMatch[3] ? parseFloat((refMatch[3] === '-' ? '-' : '') + refMatch[4]) : 0,\n }\n }\n\n // X, Y coordinate pair\n const coordMatch = str.match(/^([\\d.]+)\\s*,?\\s*([\\d.]+)$/)\n if (coordMatch) {\n return { x: parseFloat(coordMatch[1]), y: parseFloat(coordMatch[2]) }\n }\n\n // Just a shape reference (center)\n if (/^\\w+$/.test(str)) {\n return { ref: str, side: 'center', offset: 0 }\n }\n\n return { x: 0, y: 0 }\n}\n\n/**\n * Parse a numeric expression, resolving variables.\n * Supports: numbers, $var, shapeId.prop, simple +/- arithmetic\n */\nfunction parseExpr(str, variables) {\n // Replace $variables\n let resolved = str.replace(/\\$(\\w+)/g, (_, name) => {\n return variables[name] !== undefined ? variables[name] : '0'\n })\n\n // If it's a simple number, return it\n const num = parseFloat(resolved)\n if (!isNaN(num) && String(num) === resolved.trim()) {\n return num\n }\n\n // If it contains a shape reference like shapeId.prop, return as deferred\n if (/\\w+\\.\\w+/.test(resolved)) {\n return { expr: resolved }\n }\n\n // Try simple arithmetic (A + B, A - B)\n const arithMatch = resolved.match(/^([\\d.]+)\\s*([+-])\\s*([\\d.]+)$/)\n if (arithMatch) {\n const a = parseFloat(arithMatch[1])\n const b = parseFloat(arithMatch[3])\n return arithMatch[2] === '+' ? a + b : a - b\n }\n\n return isNaN(num) ? 0 : num\n}\n\n/**\n * Parse property lines into shape.props\n */\nfunction parseProperties(shape, lines, variables, errors) {\n for (const line of lines) {\n const propMatch = line.match(/^(\\w+)\\s*:\\s*(.+)$/)\n if (!propMatch) continue\n\n let [, key, value] = propMatch\n value = value.trim()\n\n // Strip quotes from string values\n if ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1)\n }\n\n // Resolve variables\n value = value.replace(/\\$(\\w+)/g, (_, name) => {\n return variables[name] !== undefined ? variables[name] : value\n })\n\n // Parse numeric values\n const num = parseFloat(value)\n if (!isNaN(num) && String(num) === value) {\n shape.props[key] = num\n } else if (value === 'true') {\n shape.props[key] = true\n } else if (value === 'false') {\n shape.props[key] = false\n } else {\n shape.props[key] = value\n }\n }\n}\n\n// ============================================================\n// RESOLVER \u2014 resolve deferred expressions & shape references\n// ============================================================\n\nexport function resolveShapeRefs(shapes) {\n const shapeMap = new Map()\n\n // Iteratively resolve deferred expressions until no more progress\n // This handles chained references like: A(absolute) \u2192 B(refs A) \u2192 C(refs B) \u2192 D(refs C)\n const MAX_PASSES = 10\n for (let pass = 0; pass < MAX_PASSES; pass++) {\n let progress = false\n\n // Collect all shapes with known (numeric) positions\n for (const s of shapes) {\n if (typeof s.x === 'number' && typeof s.y === 'number' && !shapeMap.has(s.id)) {\n shapeMap.set(s.id, s)\n progress = true\n }\n }\n\n // Try to resolve any remaining deferred expressions\n let anyUnresolved = false\n for (const s of shapes) {\n if (s.x && typeof s.x === 'object' && s.x.expr) {\n const resolved = resolveExpr(s.x.expr, shapeMap)\n if (typeof resolved === 'number' && !isNaN(resolved)) {\n s.x = resolved\n progress = true\n } else {\n anyUnresolved = true\n }\n }\n if (s.y && typeof s.y === 'object' && s.y.expr) {\n const resolved = resolveExpr(s.y.expr, shapeMap)\n if (typeof resolved === 'number' && !isNaN(resolved)) {\n s.y = resolved\n progress = true\n } else {\n anyUnresolved = true\n }\n }\n }\n\n if (!anyUnresolved || !progress) break\n }\n\n // Final fallback: force-resolve any remaining deferred expressions to 0\n for (const s of shapes) {\n if (s.x && typeof s.x === 'object' && s.x.expr) s.x = 0\n if (s.y && typeof s.y === 'object' && s.y.expr) s.y = 0\n }\n}\n\nfunction resolveExpr(expr, shapeMap) {\n // Match: shapeId.prop [+/- offset]\n const m = expr.match(/^(\\w+)\\.(\\w+)(?:\\s*([+-])\\s*([\\d.]+))?$/)\n if (!m) return NaN\n\n const [, ref, prop, op, offsetStr] = m\n const shape = shapeMap.get(ref)\n if (!shape) return NaN\n\n let val = 0\n switch (prop) {\n case 'x': val = shape.x || 0; break\n case 'y': val = shape.y || 0; break\n case 'right': val = (shape.x || 0) + (shape.width || 0); break\n case 'left': val = shape.x || 0; break\n case 'top': val = shape.y || 0; break\n case 'bottom': val = (shape.y || 0) + (shape.height || 0); break\n case 'centerX': val = (shape.x || 0) + (shape.width || 0) / 2; break\n case 'centerY': val = (shape.y || 0) + (shape.height || 0) / 2; break\n case 'width': val = shape.width || 0; break\n case 'height': val = shape.height || 0; break\n default: val = 0\n }\n\n const offset = offsetStr ? parseFloat(offsetStr) : 0\n return op === '-' ? val - offset : val + offset\n}\n\n// ============================================================\n// RENDERER \u2014 create actual canvas shapes from parsed AST\n// ============================================================\n\n/**\n * Render a parsed LixScript AST onto the canvas.\n * Returns { success, shapesCreated, errors }\n */\nexport function renderLixScript(parsed) {\n const { shapes: shapeDefs, errors } = parsed\n if (errors.length > 0) {\n return { success: false, shapesCreated: 0, errors }\n }\n\n // Resolve relative references\n resolveShapeRefs(shapeDefs)\n\n const svg = window.svg\n if (!svg) {\n return { success: false, shapesCreated: 0, errors: [{ line: 0, message: 'Canvas not initialized' }] }\n }\n\n const createdShapes = new Map() // id -> { instance, def }\n const renderErrors = []\n\n // Check if user defined a frame \u2014 if not, we auto-create one\n const userFrameDef = shapeDefs.find(s => s.type === 'frame')\n let frame = null\n let frameDef = userFrameDef\n\n if (userFrameDef) {\n // User-defined frame\n frame = createFrame(userFrameDef, renderErrors)\n if (frame) {\n createdShapes.set(userFrameDef.id, { instance: frame, def: userFrameDef })\n }\n }\n\n // Create non-connection shapes first (rect, circle, text)\n for (const def of shapeDefs) {\n if (def.type === 'frame') continue // already created\n if (def.type === 'arrow' || def.type === 'line') continue // deferred\n\n const instance = createShape(def, renderErrors)\n if (instance) {\n createdShapes.set(def.id, { instance, def })\n }\n }\n\n // Create connections (arrows, lines) \u2014 now that source/target shapes exist\n for (const def of shapeDefs) {\n if (def.type !== 'arrow' && def.type !== 'line') continue\n\n const instance = createConnection(def, createdShapes, renderErrors)\n if (instance) {\n createdShapes.set(def.id, { instance, def })\n }\n }\n\n // Auto-create wrapping frame if user didn't define one\n if (!frame && createdShapes.size > 0) {\n // Calculate bounds from all created shapes\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity\n\n for (const [, { instance, def }] of createdShapes) {\n if (def.type === 'arrow' || def.type === 'line') {\n // Use the actual instance start/end coordinates\n const from = resolveConnectionPoint(def.from, createdShapes)\n const to = resolveConnectionPoint(def.to, createdShapes)\n if (from) { minX = Math.min(minX, from.x); minY = Math.min(minY, from.y); maxX = Math.max(maxX, from.x); maxY = Math.max(maxY, from.y) }\n if (to) { minX = Math.min(minX, to.x); minY = Math.min(minY, to.y); maxX = Math.max(maxX, to.x); maxY = Math.max(maxY, to.y) }\n } else if (def.type !== 'frame') {\n const x = def.x || 0\n const y = def.y || 0\n const w = def.width || 160\n const h = def.height || 60\n minX = Math.min(minX, x)\n minY = Math.min(minY, y)\n maxX = Math.max(maxX, x + w)\n maxY = Math.max(maxY, y + h)\n }\n }\n\n if (isFinite(minX)) {\n const pad = 40\n const autoFrameDef = {\n type: 'frame',\n id: '_lixscript_auto_frame',\n line: 0,\n x: minX - pad,\n y: minY - pad,\n width: (maxX - minX) + pad * 2,\n height: (maxY - minY) + pad * 2,\n props: { name: 'LixScript' }\n }\n frameDef = autoFrameDef\n frame = createFrame(autoFrameDef, renderErrors)\n if (frame) {\n createdShapes.set(autoFrameDef.id, { instance: frame, def: autoFrameDef })\n }\n }\n }\n\n // Add all shapes to frame\n if (frame) {\n for (const [id, { instance, def }] of createdShapes) {\n if (def.type === 'frame') continue // don't add frame to itself\n if (shouldAddToFrame(def, frameDef)) {\n frame.addShapeToFrame(instance)\n }\n }\n }\n\n return {\n success: renderErrors.length === 0,\n shapesCreated: createdShapes.size,\n errors: renderErrors,\n }\n}\n\n/**\n * Check if a shape should be added to the frame based on 'contains' prop.\n */\nfunction shouldAddToFrame(shapeDef, frameDef) {\n if (!frameDef || !frameDef.props.contains) return true // add all by default\n const ids = frameDef.props.contains.split(',').map(s => s.trim())\n return ids.includes(shapeDef.id)\n}\n\n/**\n * Create a Frame instance.\n */\nfunction createFrame(def, errors) {\n const Frame = window.Frame\n if (!Frame) {\n errors.push({ line: def.line, message: 'Frame class not available' })\n return null\n }\n\n try {\n const x = def.x || 0\n const y = def.y || 0\n const w = def.width || 600\n const h = def.height || 400\n\n const frame = new Frame(x, y, w, h, {\n frameName: def.props.frameName || def.props.name || def.id,\n stroke: def.props.stroke || '#555',\n strokeWidth: def.props.strokeWidth || 1,\n fill: def.props.fill || 'transparent',\n fillStyle: def.props.fillStyle || 'transparent',\n fillColor: def.props.fillColor || '#1e1e28',\n opacity: def.props.opacity || 1,\n rotation: def.props.rotation || 0,\n })\n\n window.shapes.push(frame)\n if (window.pushCreateAction) window.pushCreateAction(frame)\n\n // Tag as scripted\n frame._frameType = 'lixscript'\n frame._lixscriptSource = true\n\n // Set image from URL if provided\n if (def.props.imageURL && typeof frame.setImageFromURL === 'function') {\n frame.setImageFromURL(def.props.imageURL, def.props.imageFit || 'cover')\n }\n\n return frame\n } catch (err) {\n errors.push({ line: def.line, message: `Frame creation failed: ${err.message}` })\n return null\n }\n}\n\n/**\n * Create a shape instance from a definition.\n */\nfunction createShape(def, errors) {\n try {\n switch (def.type) {\n case 'rect': return createRect(def, errors)\n case 'circle':\n case 'ellipse': return createCircle(def, errors)\n case 'text': return createText(def, errors)\n case 'freehand': return createFreehand(def, errors)\n case 'image': return createImage(def, errors)\n case 'icon': return createIcon(def, errors)\n default:\n errors.push({ line: def.line, message: `Unknown shape type: ${def.type}` })\n return null\n }\n } catch (err) {\n errors.push({ line: def.line, message: `Shape '${def.id}' failed: ${err.message}` })\n return null\n }\n}\n\n/**\n * Create an image shape from a LixScript definition.\n * Usage: image myImg at 100, 200 size 300x200 { src: \"https://...\" }\n */\nfunction createImage(def, errors) {\n const ImageShape = window.ImageShape\n if (!ImageShape) {\n errors.push({ line: def.line, message: 'ImageShape class not available' })\n return null\n }\n\n const src = def.props.src || def.props.href || def.props.url || ''\n if (!src) {\n errors.push({ line: def.line, message: `Image '${def.id}' requires a src property` })\n return null\n }\n\n const svgEl = document.getElementById('freehand-canvas')\n if (!svgEl) return null\n\n const x = def.x || 0\n const y = def.y || 0\n const w = def.width || 200\n const h = def.height || 200\n\n const imgEl = document.createElementNS('http://www.w3.org/2000/svg', 'image')\n imgEl.setAttribute('href', src)\n imgEl.setAttribute('x', x)\n imgEl.setAttribute('y', y)\n imgEl.setAttribute('width', w)\n imgEl.setAttribute('height', h)\n imgEl.setAttribute('data-shape-x', x)\n imgEl.setAttribute('data-shape-y', y)\n imgEl.setAttribute('data-shape-width', w)\n imgEl.setAttribute('data-shape-height', h)\n imgEl.setAttribute('type', 'image')\n imgEl.setAttribute('preserveAspectRatio', def.props.fit === 'contain' ? 'xMidYMid meet' : def.props.fit === 'cover' ? 'xMidYMid slice' : 'xMidYMid meet')\n\n svgEl.appendChild(imgEl)\n const shape = new ImageShape(imgEl)\n if (def.props.rotation) shape.rotation = parseFloat(def.props.rotation)\n shape.shapeID = def.id || shape.shapeID\n\n window.shapes.push(shape)\n if (window.pushCreateAction) window.pushCreateAction(shape)\n\n return shape\n}\n\n/**\n * Create an icon shape from a LixScript definition.\n * Usage: icon myIcon at 100, 200 size 48x48 { name: \"AWS_Lambda_64\" }\n * or: icon myIcon at 100, 200 size 48x48 { svg: \"<path d='...' />\" }\n */\nfunction createIcon(def, errors) {\n const IconShape = window.IconShape\n if (!IconShape) {\n errors.push({ line: def.line, message: 'IconShape class not available' })\n return null\n }\n\n const svgEl = document.getElementById('freehand-canvas')\n if (!svgEl) return null\n\n const x = def.x || 0\n const y = def.y || 0\n const size = def.width || 48\n const color = def.props.color || def.props.fill || '#ffffff'\n\n // Build the inner SVG content\n let innerSVG = ''\n if (def.props.svg) {\n // Inline SVG path(s)\n innerSVG = def.props.svg\n } else if (def.props.name) {\n // Named icon \u2014 use a simple placeholder circle+text until loaded\n // The AI should provide inline SVG paths for reliability\n innerSVG = `<circle cx=\"12\" cy=\"12\" r=\"10\" fill=\"none\" stroke=\"${color}\" stroke-width=\"1.5\"/><text x=\"12\" y=\"16\" text-anchor=\"middle\" fill=\"${color}\" font-size=\"10\" font-family=\"sans-serif\">${(def.props.name || '?').charAt(0)}</text>`\n } else {\n errors.push({ line: def.line, message: `Icon '${def.id}' requires a name or svg property` })\n return null\n }\n\n const vbWidth = parseFloat(def.props.viewBoxWidth) || 24\n const vbHeight = parseFloat(def.props.viewBoxHeight) || 24\n const scale = size / Math.max(vbWidth, vbHeight)\n const localCenterX = size / 2 / scale\n const localCenterY = size / 2 / scale\n const rotation = def.props.rotation || 0\n\n const iconGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g')\n iconGroup.setAttribute('transform', `translate(${x}, ${y}) scale(${scale}) rotate(${rotation}, ${localCenterX}, ${localCenterY})`)\n iconGroup.setAttribute('data-viewbox-width', vbWidth)\n iconGroup.setAttribute('data-viewbox-height', vbHeight)\n iconGroup.setAttribute('x', x)\n iconGroup.setAttribute('y', y)\n iconGroup.setAttribute('width', size)\n iconGroup.setAttribute('height', size)\n iconGroup.setAttribute('type', 'icon')\n iconGroup.setAttribute('data-shape-x', x)\n iconGroup.setAttribute('data-shape-y', y)\n iconGroup.setAttribute('data-shape-width', size)\n iconGroup.setAttribute('data-shape-height', size)\n iconGroup.setAttribute('data-shape-rotation', rotation)\n iconGroup.setAttribute('style', 'cursor: pointer; pointer-events: all;')\n\n // Transparent hit area\n const bgRect = document.createElementNS('http://www.w3.org/2000/svg', 'rect')\n bgRect.setAttribute('x', 0)\n bgRect.setAttribute('y', 0)\n bgRect.setAttribute('width', vbWidth)\n bgRect.setAttribute('height', vbHeight)\n bgRect.setAttribute('fill', 'transparent')\n bgRect.setAttribute('stroke', 'none')\n bgRect.setAttribute('style', 'pointer-events: all;')\n iconGroup.appendChild(bgRect)\n\n // Parse and insert SVG content\n const tempSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n tempSvg.innerHTML = innerSVG\n while (tempSvg.firstChild) {\n const child = tempSvg.firstChild\n // Apply color to paths/circles/etc\n if (child.nodeType === 1) {\n const fill = child.getAttribute('fill')\n const stroke = child.getAttribute('stroke')\n if (!fill || fill === 'currentColor' || fill === '#000' || fill === '#000000' || fill === 'black') {\n child.setAttribute('fill', color)\n }\n if (stroke === 'currentColor' || stroke === '#000' || stroke === '#000000' || stroke === 'black') {\n child.setAttribute('stroke', color)\n }\n }\n iconGroup.appendChild(child)\n }\n\n svgEl.appendChild(iconGroup)\n const shape = new IconShape(iconGroup)\n shape.shapeID = def.id || shape.shapeID\n\n window.shapes.push(shape)\n if (window.pushCreateAction) window.pushCreateAction(shape)\n\n return shape\n}\n\nfunction createRect(def, errors) {\n const Rectangle = window.Rectangle\n if (!Rectangle) {\n errors.push({ line: def.line, message: 'Rectangle class not available' })\n return null\n }\n\n const x = def.x || 0\n const y = def.y || 0\n const w = def.width || 160\n const h = def.height || 60\n\n const rect = new Rectangle(x, y, w, h, {\n stroke: def.props.stroke || '#fff',\n strokeWidth: def.props.strokeWidth || 2,\n fill: def.props.fill || 'transparent',\n fillStyle: def.props.fillStyle || 'none',\n roughness: def.props.roughness !== undefined ? def.props.roughness : 1.5,\n strokeDasharray: resolveStrokeStyle(def.props.style),\n shadeColor: def.props.shadeColor || null,\n shadeOpacity: def.props.shadeOpacity !== undefined ? parseFloat(def.props.shadeOpacity) : 0.15,\n shadeDirection: def.props.shadeDirection || 'bottom',\n })\n\n if (def.props.rotation) rect.rotation = def.props.rotation\n if (def.props.label) {\n rect.setLabel(\n def.props.label,\n def.props.labelColor || '#e0e0e0',\n def.props.labelFontSize || 14\n )\n }\n\n window.shapes.push(rect)\n if (window.pushCreateAction) window.pushCreateAction(rect)\n return rect\n}\n\nfunction createCircle(def, errors) {\n const Circle = window.Circle\n if (!Circle) {\n errors.push({ line: def.line, message: 'Circle class not available' })\n return null\n }\n\n const x = def.x || 0\n const y = def.y || 0\n const w = def.width || 80\n const h = def.height || 80\n\n // Circle constructor uses (x, y, rx, ry) \u2014 center and radii\n const rx = w / 2\n const ry = h / 2\n\n const circle = new Circle(x + rx, y + ry, rx, ry, {\n stroke: def.props.stroke || '#fff',\n strokeWidth: def.props.strokeWidth || 2,\n fill: def.props.fill || 'transparent',\n fillStyle: def.props.fillStyle || 'none',\n roughness: def.props.roughness !== undefined ? def.props.roughness : 1.5,\n strokeDasharray: resolveStrokeStyle(def.props.style),\n shadeColor: def.props.shadeColor || null,\n shadeOpacity: def.props.shadeOpacity !== undefined ? parseFloat(def.props.shadeOpacity) : 0.15,\n shadeDirection: def.props.shadeDirection || 'bottom',\n })\n\n if (def.props.rotation) circle.rotation = def.props.rotation\n if (def.props.label) {\n circle.setLabel(\n def.props.label,\n def.props.labelColor || '#e0e0e0',\n def.props.labelFontSize || 14\n )\n }\n\n window.shapes.push(circle)\n if (window.pushCreateAction) window.pushCreateAction(circle)\n return circle\n}\n\nfunction createText(def, errors) {\n const TextShape = window.TextShape\n const svgEl = window.svg\n if (!TextShape || !svgEl) {\n errors.push({ line: def.line, message: 'TextShape class not available' })\n return null\n }\n\n const x = def.x || 0\n const y = def.y || 0\n const content = def.props.content || def.props.text || 'Text'\n const color = def.props.color || def.props.fill || '#fff'\n const fontSize = def.props.fontSize || 16\n\n const g = document.createElementNS(NS, 'g')\n g.setAttribute('data-type', 'text-group')\n g.setAttribute('transform', `translate(${x}, ${y})`)\n g.setAttribute('data-x', x)\n g.setAttribute('data-y', y)\n\n const t = document.createElementNS(NS, 'text')\n t.setAttribute('x', 0)\n t.setAttribute('y', 0)\n t.setAttribute('text-anchor', def.props.anchor || 'middle')\n t.setAttribute('dominant-baseline', 'central')\n t.setAttribute('fill', color)\n t.setAttribute('font-size', fontSize)\n t.setAttribute('font-family', def.props.fontFamily || 'lixFont, sans-serif')\n t.setAttribute('data-initial-font', def.props.fontFamily || 'lixFont')\n t.setAttribute('data-initial-color', color)\n t.setAttribute('data-initial-size', fontSize + 'px')\n t.textContent = content\n\n g.appendChild(t)\n svgEl.appendChild(g)\n\n const shape = new TextShape(g)\n window.shapes.push(shape)\n if (window.pushCreateAction) window.pushCreateAction(shape)\n return shape\n}\n\nfunction createFreehand(def, errors) {\n const FreehandStroke = window.FreehandStroke\n if (!FreehandStroke) {\n errors.push({ line: def.line, message: 'FreehandStroke class not available' })\n return null\n }\n\n // Points should be provided as a property: points: \"x1,y1;x2,y2;...\"\n const pointsStr = def.props.points || ''\n const points = pointsStr.split(';').map(p => {\n const [x, y, pressure] = p.split(',').map(Number)\n return [x || 0, y || 0, pressure || 0.5]\n }).filter(p => !isNaN(p[0]))\n\n if (points.length < 2) {\n errors.push({ line: def.line, message: 'Freehand requires at least 2 points' })\n return null\n }\n\n const stroke = new FreehandStroke(points, {\n stroke: def.props.stroke || def.props.color || '#fff',\n strokeWidth: def.props.strokeWidth || 3,\n thinning: def.props.thinning || 0.5,\n roughness: def.props.roughness || 'smooth',\n strokeStyle: def.props.style || 'solid',\n })\n\n window.shapes.push(stroke)\n if (window.pushCreateAction) window.pushCreateAction(stroke)\n return stroke\n}\n\n/**\n * Create a connection (arrow or line) between two points or shape references.\n */\nfunction createConnection(def, createdShapes, errors) {\n const from = resolveConnectionPoint(def.from, createdShapes)\n const to = resolveConnectionPoint(def.to, createdShapes)\n\n if (!from || !to) {\n errors.push({ line: def.line, message: `Cannot resolve connection endpoints for '${def.id}'` })\n return null\n }\n\n if (def.type === 'arrow') {\n return createArrow(def, from, to, createdShapes, errors)\n } else {\n return createLine(def, from, to, errors)\n }\n}\n\nfunction createArrow(def, from, to, createdShapes, errors) {\n const Arrow = window.Arrow\n if (!Arrow) {\n errors.push({ line: def.line, message: 'Arrow class not available' })\n return null\n }\n\n const curveMode = def.props.curve || 'straight'\n\n const arrow = new Arrow(\n { x: from.x, y: from.y },\n { x: to.x, y: to.y },\n {\n stroke: def.props.stroke || '#fff',\n strokeWidth: def.props.strokeWidth || 2,\n arrowOutlineStyle: def.props.style || 'solid',\n arrowHeadStyle: def.props.head || 'default',\n arrowHeadLength: def.props.headLength || 15,\n arrowCurved: curveMode,\n arrowCurveAmount: def.props.curveAmount || 50,\n }\n )\n\n if (def.props.label) {\n arrow.setLabel(\n def.props.label,\n def.props.labelColor || '#e0e0e0',\n def.props.labelFontSize || 12\n )\n }\n\n // Auto-attach to source/target shapes\n if (def.from && def.from.ref) {\n const sourceEntry = createdShapes.get(def.from.ref)\n if (sourceEntry) {\n autoAttach(arrow, sourceEntry.instance, true, from)\n }\n }\n if (def.to && def.to.ref) {\n const targetEntry = createdShapes.get(def.to.ref)\n if (targetEntry) {\n autoAttach(arrow, targetEntry.instance, false, to)\n }\n }\n\n window.shapes.push(arrow)\n if (window.pushCreateAction) window.pushCreateAction(arrow)\n return arrow\n}\n\nfunction createLine(def, from, to, errors) {\n const Line = window.Line\n if (!Line) {\n errors.push({ line: def.line, message: 'Line class not available' })\n return null\n }\n\n const line = new Line(\n { x: from.x, y: from.y },\n { x: to.x, y: to.y },\n {\n stroke: def.props.stroke || '#fff',\n strokeWidth: def.props.strokeWidth || 2,\n strokeDasharray: resolveStrokeStyle(def.props.style),\n }\n )\n\n if (def.props.curve === 'true' || def.props.curve === true) {\n line.isCurved = true\n line.initializeCurveControlPoint?.()\n line.draw()\n }\n\n if (def.props.label) {\n line.setLabel(\n def.props.label,\n def.props.labelColor || '#e0e0e0',\n def.props.labelFontSize || 12\n )\n }\n\n window.shapes.push(line)\n if (window.pushCreateAction) window.pushCreateAction(line)\n return line\n}\n\n// ============================================================\n// CONNECTION POINT RESOLUTION\n// ============================================================\n\n/**\n * Resolve a connection endpoint \u2014 either absolute coords or a shape reference.\n */\nfunction resolveConnectionPoint(pointDef, createdShapes) {\n if (!pointDef) return null\n\n // Absolute coordinates\n if (pointDef.x !== undefined && pointDef.y !== undefined) {\n return { x: pointDef.x, y: pointDef.y }\n }\n\n // Shape reference\n if (pointDef.ref) {\n const entry = createdShapes.get(pointDef.ref)\n if (!entry) return null\n\n const shape = entry.instance\n const def = entry.def\n const side = pointDef.side || 'center'\n const offset = pointDef.offset || 0\n\n // Get shape bounds\n const sx = shape.x !== undefined ? shape.x : (def.x || 0)\n const sy = shape.y !== undefined ? shape.y : (def.y || 0)\n const sw = shape.width || def.width || 0\n const sh = shape.height || def.height || 0\n\n // For circles, x/y is the center\n let cx, cy\n if (shape.shapeName === 'circle') {\n cx = sx\n cy = sy\n const rx = shape.rx || sw / 2\n const ry = shape.ry || sh / 2\n\n switch (side) {\n case 'top': return { x: cx + offset, y: cy - ry }\n case 'bottom': return { x: cx + offset, y: cy + ry }\n case 'left': return { x: cx - rx, y: cy + offset }\n case 'right': return { x: cx + rx, y: cy + offset }\n case 'center': return { x: cx + offset, y: cy }\n default: return { x: cx, y: cy }\n }\n }\n\n // For rectangles and other box shapes\n cx = sx + sw / 2\n cy = sy + sh / 2\n\n switch (side) {\n case 'top': return { x: cx + offset, y: sy }\n case 'bottom': return { x: cx + offset, y: sy + sh }\n case 'left': return { x: sx, y: cy + offset }\n case 'right': return { x: sx + sw, y: cy + offset }\n case 'center': return { x: cx + offset, y: cy }\n default: return { x: cx, y: cy }\n }\n }\n\n return null\n}\n\n/**\n * Auto-attach an arrow to a shape (sets attachedToStart or attachedToEnd).\n */\nfunction autoAttach(arrow, shape, isStart, connectionPoint) {\n if (!shape || !connectionPoint) return\n\n const sx = shape.x || 0\n const sy = shape.y || 0\n const sw = shape.width || 0\n const sh = shape.height || 0\n\n let cx, cy\n if (shape.shapeName === 'circle') {\n cx = sx\n cy = sy\n } else {\n cx = sx + sw / 2\n cy = sy + sh / 2\n }\n\n // Determine which side the connection point is on\n const dx = connectionPoint.x - cx\n const dy = connectionPoint.y - cy\n let side = 'bottom'\n\n if (Math.abs(dx) > Math.abs(dy)) {\n side = dx > 0 ? 'right' : 'left'\n } else {\n side = dy > 0 ? 'bottom' : 'top'\n }\n\n const attachment = { shape, side, offset: { x: 0, y: 0 } }\n\n if (isStart) {\n arrow.attachedToStart = attachment\n } else {\n arrow.attachedToEnd = attachment\n }\n}\n\n// ============================================================\n// PREVIEW \u2014 generate SVG preview without touching the canvas\n// ============================================================\n\n/**\n * Generate a preview SVG string from parsed LixScript.\n */\nexport function previewLixScript(parsed) {\n const { shapes: defs, errors } = parsed\n if (errors.length > 0) return ''\n\n resolveShapeRefs(defs)\n\n // Build a shape map for resolving arrow references in preview\n const shapeMap = new Map()\n for (const def of defs) {\n if (def.type !== 'arrow' && def.type !== 'line') {\n shapeMap.set(def.id, def)\n }\n }\n\n // Resolve arrow/line endpoints to coordinates for preview\n function resolvePreviewPoint(pointDef) {\n if (!pointDef) return { x: 0, y: 0 }\n if (pointDef.x !== undefined && pointDef.y !== undefined) return pointDef\n\n if (pointDef.ref) {\n const target = shapeMap.get(pointDef.ref)\n if (!target) return { x: 0, y: 0 }\n\n const side = pointDef.side || 'center'\n const offset = pointDef.offset || 0\n const tx = target.x || 0\n const ty = target.y || 0\n const tw = target.width || 160\n const th = target.height || 60\n\n // For circle, x/y is top-left of bounding box in our DSL\n const cx = tx + tw / 2\n const cy = ty + th / 2\n\n switch (side) {\n case 'top': return { x: cx + offset, y: ty }\n case 'bottom': return { x: cx + offset, y: ty + th }\n case 'left': return { x: tx, y: cy + offset }\n case 'right': return { x: tx + tw, y: cy + offset }\n case 'center': return { x: cx + offset, y: cy }\n default: return { x: cx, y: cy }\n }\n }\n return { x: 0, y: 0 }\n }\n\n // Calculate bounds\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity\n\n for (const def of defs) {\n if (def.type === 'arrow' || def.type === 'line') {\n const from = resolvePreviewPoint(def.from)\n const to = resolvePreviewPoint(def.to)\n minX = Math.min(minX, from.x, to.x)\n minY = Math.min(minY, from.y, to.y)\n maxX = Math.max(maxX, from.x, to.x)\n maxY = Math.max(maxY, from.y, to.y)\n } else if (def.type !== 'frame') {\n const x = def.x || 0\n const y = def.y || 0\n const w = def.width || 160\n const h = def.height || 60\n minX = Math.min(minX, x)\n minY = Math.min(minY, y)\n maxX = Math.max(maxX, x + w)\n maxY = Math.max(maxY, y + h)\n }\n }\n\n if (!isFinite(minX)) { minX = 0; minY = 0; maxX = 400; maxY = 300 }\n\n const pad = 40\n const vw = maxX - minX + pad * 2\n const vh = maxY - minY + pad * 2\n\n let svgContent = ''\n\n // Render each shape as simple SVG\n for (const def of defs) {\n const props = def.props || {}\n\n switch (def.type) {\n case 'rect':\n svgContent += `<rect x=\"${def.x || 0}\" y=\"${def.y || 0}\" width=\"${def.width || 160}\" height=\"${def.height || 60}\" stroke=\"${props.stroke || '#fff'}\" stroke-width=\"${props.strokeWidth || 2}\" fill=\"${props.fill || 'transparent'}\" rx=\"4\" />`\n if (props.label) {\n const cx = (def.x || 0) + (def.width || 160) / 2\n const cy = (def.y || 0) + (def.height || 60) / 2\n svgContent += `<text x=\"${cx}\" y=\"${cy}\" text-anchor=\"middle\" dominant-baseline=\"central\" fill=\"${props.labelColor || '#e0e0e0'}\" font-size=\"${props.labelFontSize || 14}\" font-family=\"sans-serif\">${escapeXml(props.label)}</text>`\n }\n break\n\n case 'circle':\n case 'ellipse': {\n const rx = (def.width || 80) / 2\n const ry = (def.height || 80) / 2\n const cx = (def.x || 0) + rx\n const cy = (def.y || 0) + ry\n svgContent += `<ellipse cx=\"${cx}\" cy=\"${cy}\" rx=\"${rx}\" ry=\"${ry}\" stroke=\"${props.stroke || '#fff'}\" stroke-width=\"${props.strokeWidth || 2}\" fill=\"${props.fill || 'transparent'}\" />`\n if (props.label) {\n svgContent += `<text x=\"${cx}\" y=\"${cy}\" text-anchor=\"middle\" dominant-baseline=\"central\" fill=\"${props.labelColor || '#e0e0e0'}\" font-size=\"${props.labelFontSize || 14}\" font-family=\"sans-serif\">${escapeXml(props.label)}</text>`\n }\n break\n }\n\n case 'text': {\n const content = props.content || props.text || 'Text'\n svgContent += `<text x=\"${def.x || 0}\" y=\"${def.y || 0}\" fill=\"${props.color || props.fill || '#fff'}\" font-size=\"${props.fontSize || 16}\" font-family=\"sans-serif\">${escapeXml(content)}</text>`\n break\n }\n\n case 'arrow': {\n const fromOrig = resolvePreviewPoint(def.from)\n const toOrig = resolvePreviewPoint(def.to)\n const stroke = props.stroke || '#fff'\n const sw = props.strokeWidth || 2\n const dash = props.style === 'dashed' ? ' stroke-dasharray=\"10,10\"' : props.style === 'dotted' ? ' stroke-dasharray=\"2,8\"' : ''\n const curve = props.curve || 'straight'\n const markerId = `ah-${def.id}`\n const headLen = 10 // arrowhead marker size\n\n // Pull back arrow endpoint so the tip lands at the shape edge, not inside it\n const to = shortenEndpoint(fromOrig, toOrig, headLen)\n const from = fromOrig\n\n // Per-arrow colored arrowhead marker \u2014 refX=0 so tip is at the shortened line end\n svgContent += `<defs><marker id=\"${markerId}\" markerWidth=\"10\" markerHeight=\"7\" refX=\"0\" refY=\"3.5\" orient=\"auto\"><polygon points=\"0 0, 10 3.5, 0 7\" fill=\"${stroke}\" /></marker></defs>`\n\n if (curve === 'curved') {\n // Compute a quadratic bezier control point perpendicular to the line\n const mx = (from.x + toOrig.x) / 2\n const my = (from.y + toOrig.y) / 2\n const dx = toOrig.x - from.x\n const dy = toOrig.y - from.y\n const dist = Math.sqrt(dx * dx + dy * dy) || 1\n const amt = props.curveAmount || Math.min(dist * 0.3, 80)\n // Perpendicular offset (always curve to the same side)\n const cpx = mx + (dy / dist) * amt\n const cpy = my - (dx / dist) * amt\n // Shorten the bezier endpoint\n const toShort = shortenEndpoint({ x: cpx, y: cpy }, toOrig, headLen)\n svgContent += `<path d=\"M${from.x},${from.y} Q${cpx},${cpy} ${toShort.x},${toShort.y}\" stroke=\"${stroke}\" stroke-width=\"${sw}\" fill=\"none\"${dash} marker-end=\"url(#${markerId})\" />`\n if (props.label) {\n // Label at the curve midpoint (t=0.5 on quadratic bezier)\n const lx = 0.25 * from.x + 0.5 * cpx + 0.25 * toOrig.x\n const ly = 0.25 * from.y + 0.5 * cpy + 0.25 * toOrig.y - 8\n svgContent += `<text x=\"${lx}\" y=\"${ly}\" text-anchor=\"middle\" fill=\"${props.labelColor || '#a0a0b0'}\" font-size=\"11\" font-family=\"sans-serif\">${escapeXml(props.label)}</text>`\n }\n } else if (curve === 'elbow') {\n // Simple elbow: go vertical then horizontal (or vice versa)\n const midY = from.y + (toOrig.y - from.y) / 2\n // Shorten the last segment endpoint\n const lastFrom = { x: toOrig.x, y: midY }\n const toShort = shortenEndpoint(lastFrom, toOrig, headLen)\n svgContent += `<path d=\"M${from.x},${from.y} L${from.x},${midY} L${toOrig.x},${midY} L${toShort.x},${toShort.y}\" stroke=\"${stroke}\" stroke-width=\"${sw}\" fill=\"none\"${dash} marker-end=\"url(#${markerId})\" />`\n if (props.label) {\n const lx = (from.x + toOrig.x) / 2\n const ly = midY - 8\n svgContent += `<text x=\"${lx}\" y=\"${ly}\" text-anchor=\"middle\" fill=\"${props.labelColor || '#a0a0b0'}\" font-size=\"11\" font-family=\"sans-serif\">${escapeXml(props.label)}</text>`\n }\n } else {\n svgContent += `<line x1=\"${from.x}\" y1=\"${from.y}\" x2=\"${to.x}\" y2=\"${to.y}\" stroke=\"${stroke}\" stroke-width=\"${sw}\"${dash} marker-end=\"url(#${markerId})\" />`\n if (props.label) {\n const lx = (from.x + toOrig.x) / 2\n const ly = (from.y + toOrig.y) / 2 - 10\n svgContent += `<text x=\"${lx}\" y=\"${ly}\" text-anchor=\"middle\" fill=\"${props.labelColor || '#a0a0b0'}\" font-size=\"11\" font-family=\"sans-serif\">${escapeXml(props.label)}</text>`\n }\n }\n break\n }\n\n case 'line': {\n const from = resolvePreviewPoint(def.from)\n const to = resolvePreviewPoint(def.to)\n const dash = props.style === 'dashed' ? ' stroke-dasharray=\"10,10\"' : props.style === 'dotted' ? ' stroke-dasharray=\"2,8\"' : ''\n svgContent += `<line x1=\"${from.x}\" y1=\"${from.y}\" x2=\"${to.x}\" y2=\"${to.y}\" stroke=\"${props.stroke || '#fff'}\" stroke-width=\"${props.strokeWidth || 2}\"${dash} />`\n break\n }\n\n case 'frame': {\n const frameName = props.name || def.id\n svgContent += `<rect x=\"${def.x || 0}\" y=\"${def.y || 0}\" width=\"${def.width || 600}\" height=\"${def.height || 400}\" stroke=\"${props.stroke || '#555'}\" stroke-width=\"1\" fill=\"transparent\" stroke-dasharray=\"8,4\" rx=\"8\" />`\n svgContent += `<text x=\"${(def.x || 0) + 10}\" y=\"${(def.y || 0) - 8}\" fill=\"#888\" font-size=\"12\" font-family=\"sans-serif\">${escapeXml(frameName)}</text>`\n break\n }\n }\n }\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"${minX - pad} ${minY - pad} ${vw} ${vh}\" width=\"100%\" height=\"100%\" style=\"background: transparent;\">\n ${svgContent}\n </svg>`\n}\n\n/**\n * Pull back an arrow endpoint so the arrowhead tip lands at the target edge,\n * rather than the line extending into the shape.\n */\nfunction shortenEndpoint(from, to, amount) {\n const dx = to.x - from.x\n const dy = to.y - from.y\n const dist = Math.sqrt(dx * dx + dy * dy)\n if (dist < amount * 2) return to // too short to shorten\n return {\n x: to.x - (dx / dist) * amount,\n y: to.y - (dy / dist) * amount,\n }\n}\n\nfunction escapeXml(str) {\n return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"')\n}\n\n// ============================================================\n// STROKE STYLE HELPERS\n// ============================================================\n\nfunction resolveStrokeStyle(style) {\n if (!style) return ''\n switch (style) {\n case 'dashed': return '10,10'\n case 'dotted': return '2,8'\n case 'solid':\n default: return ''\n }\n}\n\n// ============================================================\n// WINDOW BRIDGE \u2014 expose to canvas engine\n// ============================================================\n\nexport function initLixScriptBridge() {\n window.__lixscriptParse = parseLixScript\n window.__lixscriptRender = renderLixScript\n window.__lixscriptPreview = (source) => {\n const parsed = parseLixScript(source)\n return previewLixScript(parsed)\n }\n window.__lixscriptExecute = (source) => {\n const parsed = parseLixScript(source)\n if (parsed.errors.length > 0) {\n return { success: false, errors: parsed.errors, shapesCreated: 0 }\n }\n return renderLixScript(parsed)\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/core/MermaidFlowchartRenderer.js
|
|
4
|
+
var NODE_W = 150;
|
|
5
|
+
var NODE_H = 50;
|
|
6
|
+
var SIDE_MARGIN = 50;
|
|
7
|
+
var TOP_MARGIN = 40;
|
|
8
|
+
var FONT_FAMILY = "lixFont, sans-serif";
|
|
9
|
+
var THEME = {
|
|
10
|
+
bg: "#1e1e28",
|
|
11
|
+
nodeBg: "transparent",
|
|
12
|
+
nodeStroke: "#9090c0",
|
|
13
|
+
nodeText: "#e0e0e0",
|
|
14
|
+
edgeStroke: "#888",
|
|
15
|
+
edgeText: "#a0a0b0",
|
|
16
|
+
subgraphBg: "rgba(80,80,120,0.08)",
|
|
17
|
+
subgraphBorder: "#555",
|
|
18
|
+
subgraphLabel: "#888"
|
|
19
|
+
};
|
|
20
|
+
function escapeXml(str) {
|
|
21
|
+
return String(str).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
22
|
+
}
|
|
23
|
+
function measureText(text, fontSize) {
|
|
24
|
+
return text.length * fontSize * 0.55;
|
|
25
|
+
}
|
|
26
|
+
function renderFlowchartSVG(diagram, opts = {}) {
|
|
27
|
+
if (!diagram || !diagram.nodes || diagram.nodes.length === 0) return "";
|
|
28
|
+
const nodes = diagram.nodes;
|
|
29
|
+
const edges = diagram.edges || [];
|
|
30
|
+
const subgraphs = diagram.subgraphs || [];
|
|
31
|
+
const direction = diagram.direction || "TD";
|
|
32
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
33
|
+
nodes.forEach((n) => {
|
|
34
|
+
const nw = n.width || NODE_W;
|
|
35
|
+
const nh = n.height || NODE_H;
|
|
36
|
+
minX = Math.min(minX, n.x);
|
|
37
|
+
minY = Math.min(minY, n.y);
|
|
38
|
+
maxX = Math.max(maxX, n.x + nw);
|
|
39
|
+
maxY = Math.max(maxY, n.y + nh);
|
|
40
|
+
});
|
|
41
|
+
const dw = maxX - minX || 1;
|
|
42
|
+
const dh = maxY - minY || 1;
|
|
43
|
+
const targetW = opts.width || dw + SIDE_MARGIN * 2;
|
|
44
|
+
const targetH = opts.height || dh + TOP_MARGIN * 2;
|
|
45
|
+
let scale, offX, offY;
|
|
46
|
+
if (opts.width || opts.height) {
|
|
47
|
+
const pad = 40;
|
|
48
|
+
scale = Math.min(
|
|
49
|
+
(targetW - pad * 2) / dw,
|
|
50
|
+
(targetH - pad * 2) / dh,
|
|
51
|
+
1.8
|
|
52
|
+
);
|
|
53
|
+
offX = (targetW - dw * scale) / 2 - minX * scale;
|
|
54
|
+
offY = (targetH - dh * scale) / 2 - minY * scale;
|
|
55
|
+
} else {
|
|
56
|
+
scale = 1;
|
|
57
|
+
offX = SIDE_MARGIN - minX;
|
|
58
|
+
offY = TOP_MARGIN - minY;
|
|
59
|
+
}
|
|
60
|
+
const totalWidth = opts.width || Math.round(dw * scale + SIDE_MARGIN * 2);
|
|
61
|
+
const totalHeight = opts.height || Math.round(dh * scale + TOP_MARGIN * 2);
|
|
62
|
+
const nodeById = /* @__PURE__ */ new Map();
|
|
63
|
+
nodes.forEach((n) => {
|
|
64
|
+
const nw = (n.width || NODE_W) * scale;
|
|
65
|
+
const nh = (n.height || NODE_H) * scale;
|
|
66
|
+
const nx = n.x * scale + offX;
|
|
67
|
+
const ny = n.y * scale + offY;
|
|
68
|
+
nodeById.set(n.id, {
|
|
69
|
+
x: nx,
|
|
70
|
+
y: ny,
|
|
71
|
+
w: nw,
|
|
72
|
+
h: nh,
|
|
73
|
+
cx: nx + nw / 2,
|
|
74
|
+
cy: ny + nh / 2,
|
|
75
|
+
type: n.type,
|
|
76
|
+
label: n.label,
|
|
77
|
+
fill: n.fill,
|
|
78
|
+
stroke: n.stroke,
|
|
79
|
+
strokeWidth: n.strokeWidth
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
let svg = "";
|
|
83
|
+
const defs = [];
|
|
84
|
+
defs.push(`<marker id="fc-arrow" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
85
|
+
<path d="M1,1 L9,3.5 L1,6" fill="none" stroke="${THEME.edgeStroke}" stroke-width="1.5" stroke-linejoin="round" />
|
|
86
|
+
</marker>`);
|
|
87
|
+
defs.push(`<marker id="fc-arrow-thick" markerWidth="12" markerHeight="9" refX="11" refY="4.5" orient="auto">
|
|
88
|
+
<path d="M1,1 L11,4.5 L1,8" fill="none" stroke="${THEME.edgeStroke}" stroke-width="2" stroke-linejoin="round" />
|
|
89
|
+
</marker>`);
|
|
90
|
+
svg += `<rect x="0" y="0" width="${totalWidth}" height="${totalHeight}" fill="${THEME.bg}" rx="8" />`;
|
|
91
|
+
for (const sg of subgraphs) {
|
|
92
|
+
if (!sg.nodes || sg.nodes.length === 0) continue;
|
|
93
|
+
let sgMinX = Infinity, sgMinY = Infinity, sgMaxX = -Infinity, sgMaxY = -Infinity;
|
|
94
|
+
let hasNodes = false;
|
|
95
|
+
for (const nid of sg.nodes) {
|
|
96
|
+
const nd = nodeById.get(nid);
|
|
97
|
+
if (!nd) continue;
|
|
98
|
+
hasNodes = true;
|
|
99
|
+
sgMinX = Math.min(sgMinX, nd.x);
|
|
100
|
+
sgMinY = Math.min(sgMinY, nd.y);
|
|
101
|
+
sgMaxX = Math.max(sgMaxX, nd.x + nd.w);
|
|
102
|
+
sgMaxY = Math.max(sgMaxY, nd.y + nd.h);
|
|
103
|
+
}
|
|
104
|
+
if (!hasNodes) continue;
|
|
105
|
+
const sgPad = 20 * scale;
|
|
106
|
+
const sgX = sgMinX - sgPad;
|
|
107
|
+
const sgY = sgMinY - sgPad - 16 * scale;
|
|
108
|
+
const sgW = sgMaxX - sgMinX + sgPad * 2;
|
|
109
|
+
const sgH = sgMaxY - sgMinY + sgPad * 2 + 16 * scale;
|
|
110
|
+
svg += `<g data-fc-type="subgraph" data-fc-id="${escapeXml(sg.id)}">`;
|
|
111
|
+
svg += `<rect x="${sgX}" y="${sgY}" width="${sgW}" height="${sgH}" rx="6" fill="${THEME.subgraphBg}" stroke="${THEME.subgraphBorder}" stroke-width="1" stroke-dasharray="4 2" />`;
|
|
112
|
+
if (sg.label) {
|
|
113
|
+
svg += `<text x="${sgX + 8}" y="${sgY + 14}" fill="${THEME.subgraphLabel}" font-size="${Math.max(9, 11 * scale)}" font-family="${FONT_FAMILY}">${escapeXml(sg.label)}</text>`;
|
|
114
|
+
}
|
|
115
|
+
svg += `</g>`;
|
|
116
|
+
}
|
|
117
|
+
edges.forEach((e) => {
|
|
118
|
+
const f = nodeById.get(e.from);
|
|
119
|
+
const t = nodeById.get(e.to);
|
|
120
|
+
if (!f || !t) return;
|
|
121
|
+
const directed = e.directed !== false;
|
|
122
|
+
const edgeStyle = e.style || "normal";
|
|
123
|
+
let strokeW, dashArr, markerRef;
|
|
124
|
+
if (edgeStyle === "thick") {
|
|
125
|
+
strokeW = 3;
|
|
126
|
+
dashArr = "";
|
|
127
|
+
markerRef = directed ? ' marker-end="url(#fc-arrow-thick)"' : "";
|
|
128
|
+
} else if (edgeStyle === "dotted") {
|
|
129
|
+
strokeW = 1.5;
|
|
130
|
+
dashArr = ' stroke-dasharray="5 3"';
|
|
131
|
+
markerRef = directed ? ' marker-end="url(#fc-arrow)"' : "";
|
|
132
|
+
} else {
|
|
133
|
+
strokeW = 1.5;
|
|
134
|
+
dashArr = "";
|
|
135
|
+
markerRef = directed ? ' marker-end="url(#fc-arrow)"' : "";
|
|
136
|
+
}
|
|
137
|
+
const eStroke = e.stroke || THEME.edgeStroke;
|
|
138
|
+
const sp = getEdgePoint(f, t);
|
|
139
|
+
const ep = getEdgePoint(t, f);
|
|
140
|
+
const dx = t.cx - f.cx;
|
|
141
|
+
const dy = t.cy - f.cy;
|
|
142
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
143
|
+
let mx = (sp.x + ep.x) / 2;
|
|
144
|
+
let my = (sp.y + ep.y) / 2;
|
|
145
|
+
svg += `<g data-fc-type="edge" data-fc-from="${escapeXml(e.from)}" data-fc-to="${escapeXml(e.to)}">`;
|
|
146
|
+
if (dist > 0 && Math.abs(dy) > 15 && Math.abs(dx) > 15) {
|
|
147
|
+
const perpX = -dy / dist;
|
|
148
|
+
const perpY = dx / dist;
|
|
149
|
+
const curveAmt = dist * 0.12;
|
|
150
|
+
const cpx = mx + perpX * curveAmt;
|
|
151
|
+
const cpy = my + perpY * curveAmt;
|
|
152
|
+
mx = 0.25 * sp.x + 0.5 * cpx + 0.25 * ep.x;
|
|
153
|
+
my = 0.25 * sp.y + 0.5 * cpy + 0.25 * ep.y;
|
|
154
|
+
svg += `<path d="M ${sp.x} ${sp.y} Q ${cpx} ${cpy} ${ep.x} ${ep.y}" fill="none" stroke="${eStroke}" stroke-width="${strokeW}"${dashArr}${markerRef} />`;
|
|
155
|
+
} else {
|
|
156
|
+
svg += `<line x1="${sp.x}" y1="${sp.y}" x2="${ep.x}" y2="${ep.y}" stroke="${eStroke}" stroke-width="${strokeW}"${dashArr}${markerRef} />`;
|
|
157
|
+
}
|
|
158
|
+
if (e.label) {
|
|
159
|
+
const labelFontSize = Math.max(8, 10 * scale);
|
|
160
|
+
const labelLines = e.label.split("\n");
|
|
161
|
+
const maxLineW = Math.max(...labelLines.map((l) => measureText(l, labelFontSize)));
|
|
162
|
+
const labelW = maxLineW + 12;
|
|
163
|
+
const labelH = labelLines.length * (labelFontSize + 3) + 6;
|
|
164
|
+
svg += `<rect x="${mx - labelW / 2}" y="${my - labelH / 2}" width="${labelW}" height="${labelH}" rx="3" fill="${THEME.bg}" opacity="0.85" />`;
|
|
165
|
+
if (labelLines.length === 1) {
|
|
166
|
+
svg += `<text x="${mx}" y="${my + 1}" text-anchor="middle" dominant-baseline="central" fill="${THEME.edgeText}" font-size="${labelFontSize}" font-family="${FONT_FAMILY}">${escapeXml(e.label)}</text>`;
|
|
167
|
+
} else {
|
|
168
|
+
const startY = my - (labelLines.length - 1) * (labelFontSize + 3) / 2;
|
|
169
|
+
svg += `<text x="${mx}" text-anchor="middle" fill="${THEME.edgeText}" font-size="${labelFontSize}" font-family="${FONT_FAMILY}">`;
|
|
170
|
+
labelLines.forEach((ln, idx) => {
|
|
171
|
+
svg += `<tspan x="${mx}" dy="${idx === 0 ? 0 : labelFontSize + 3}" y="${idx === 0 ? startY : ""}">${escapeXml(ln)}</tspan>`;
|
|
172
|
+
});
|
|
173
|
+
svg += `</text>`;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
svg += `</g>`;
|
|
177
|
+
});
|
|
178
|
+
nodes.forEach((n) => {
|
|
179
|
+
const d = nodeById.get(n.id);
|
|
180
|
+
if (!d) return;
|
|
181
|
+
const nStroke = n.stroke || THEME.nodeStroke;
|
|
182
|
+
const nFill = n.fill || THEME.nodeBg;
|
|
183
|
+
const nStrokeWidth = n.strokeWidth || 1.8;
|
|
184
|
+
const fontSize = Math.max(9, Math.min(13, 12 * scale));
|
|
185
|
+
svg += `<g data-fc-type="node" data-fc-id="${escapeXml(n.id)}">`;
|
|
186
|
+
if (n.type === "circle") {
|
|
187
|
+
const r = Math.min(d.w, d.h) / 2;
|
|
188
|
+
svg += `<circle cx="${d.cx}" cy="${d.cy}" r="${r}" fill="${nFill}" stroke="${nStroke}" stroke-width="${nStrokeWidth}" />`;
|
|
189
|
+
} else if (n.type === "diamond") {
|
|
190
|
+
const hw = d.w / 2 * 0.85;
|
|
191
|
+
const hh = d.h / 2 * 0.85;
|
|
192
|
+
svg += `<polygon points="${d.cx},${d.cy - hh} ${d.cx + hw},${d.cy} ${d.cx},${d.cy + hh} ${d.cx - hw},${d.cy}" fill="${nFill}" stroke="${nStroke}" stroke-width="${nStrokeWidth}" />`;
|
|
193
|
+
} else if (n.type === "asymmetric") {
|
|
194
|
+
const notchX = d.x + 15 * scale;
|
|
195
|
+
svg += `<polygon points="${d.x},${d.y} ${d.x + d.w},${d.y} ${d.x + d.w},${d.y + d.h} ${d.x},${d.y + d.h} ${notchX},${d.cy}" fill="${nFill}" stroke="${nStroke}" stroke-width="${nStrokeWidth}" />`;
|
|
196
|
+
} else if (n.type === "roundrect") {
|
|
197
|
+
svg += `<rect x="${d.x}" y="${d.y}" width="${d.w}" height="${d.h}" rx="${12 * scale}" fill="${nFill}" stroke="${nStroke}" stroke-width="${nStrokeWidth}" />`;
|
|
198
|
+
} else {
|
|
199
|
+
svg += `<rect x="${d.x}" y="${d.y}" width="${d.w}" height="${d.h}" rx="${3 * scale}" fill="${nFill}" stroke="${nStroke}" stroke-width="${nStrokeWidth}" />`;
|
|
200
|
+
}
|
|
201
|
+
if (n.label) {
|
|
202
|
+
let labelFill = nFill && nFill !== "transparent" && nFill !== THEME.nodeBg ? getContrastColor(nFill) : nStroke;
|
|
203
|
+
if (isColorTooDark(labelFill)) labelFill = "#d0d0d0";
|
|
204
|
+
const labelLines = n.label.split("\n");
|
|
205
|
+
if (labelLines.length === 1) {
|
|
206
|
+
svg += `<text x="${d.cx}" y="${d.cy}" text-anchor="middle" dominant-baseline="central" fill="${labelFill}" font-size="${fontSize}" font-family="${FONT_FAMILY}" font-weight="500">${escapeXml(n.label)}</text>`;
|
|
207
|
+
} else {
|
|
208
|
+
const lineH = fontSize + 3;
|
|
209
|
+
const startY = d.cy - (labelLines.length - 1) * lineH / 2;
|
|
210
|
+
svg += `<text text-anchor="middle" fill="${labelFill}" font-size="${fontSize}" font-family="${FONT_FAMILY}" font-weight="500">`;
|
|
211
|
+
labelLines.forEach((ln, idx) => {
|
|
212
|
+
svg += `<tspan x="${d.cx}" y="${startY + idx * lineH}">${escapeXml(ln)}</tspan>`;
|
|
213
|
+
});
|
|
214
|
+
svg += `</text>`;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
svg += `</g>`;
|
|
218
|
+
});
|
|
219
|
+
const defsStr = defs.length > 0 ? `<defs>${defs.join("")}</defs>` : "";
|
|
220
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${totalWidth}" height="${totalHeight}" viewBox="0 0 ${totalWidth} ${totalHeight}">${defsStr}${svg}</svg>`;
|
|
221
|
+
}
|
|
222
|
+
function getEdgePoint(node, target) {
|
|
223
|
+
const dx = target.cx - node.cx;
|
|
224
|
+
const dy = target.cy - node.cy;
|
|
225
|
+
if (node.type === "circle") {
|
|
226
|
+
const r = Math.min(node.w, node.h) / 2;
|
|
227
|
+
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
228
|
+
return { x: node.cx + dx / dist * r, y: node.cy + dy / dist * r };
|
|
229
|
+
}
|
|
230
|
+
if (node.type === "diamond") {
|
|
231
|
+
const hw2 = node.w / 2 * 0.85;
|
|
232
|
+
const hh2 = node.h / 2 * 0.85;
|
|
233
|
+
const adx = Math.abs(dx) || 1e-3;
|
|
234
|
+
const ady = Math.abs(dy) || 1e-3;
|
|
235
|
+
const t = Math.min(hw2 / adx, hh2 / ady);
|
|
236
|
+
return { x: node.cx + dx * t * 0.95, y: node.cy + dy * t * 0.95 };
|
|
237
|
+
}
|
|
238
|
+
const hw = node.w / 2;
|
|
239
|
+
const hh = node.h / 2;
|
|
240
|
+
if (Math.abs(dx) < 1e-3 || Math.abs(dy) * hw > Math.abs(dx) * hh) {
|
|
241
|
+
if (dy > 0) return { x: node.cx, y: node.y + node.h };
|
|
242
|
+
return { x: node.cx, y: node.y };
|
|
243
|
+
}
|
|
244
|
+
if (dx > 0) return { x: node.x + node.w, y: node.cy };
|
|
245
|
+
return { x: node.x, y: node.cy };
|
|
246
|
+
}
|
|
247
|
+
function isColorTooDark(hex) {
|
|
248
|
+
if (!hex || hex === "transparent" || hex === "none") return false;
|
|
249
|
+
const rgb = parseColor(hex);
|
|
250
|
+
if (!rgb) return false;
|
|
251
|
+
return 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b < 80;
|
|
252
|
+
}
|
|
253
|
+
function parseColor(hex) {
|
|
254
|
+
if (!hex || hex === "transparent" || hex === "none") return null;
|
|
255
|
+
let c = hex.replace("#", "");
|
|
256
|
+
if (c.length === 3) c = c[0] + c[0] + c[1] + c[1] + c[2] + c[2];
|
|
257
|
+
if (c.length < 6) return null;
|
|
258
|
+
return {
|
|
259
|
+
r: parseInt(c.substring(0, 2), 16),
|
|
260
|
+
g: parseInt(c.substring(2, 4), 16),
|
|
261
|
+
b: parseInt(c.substring(4, 6), 16)
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function getLuminance(hex) {
|
|
265
|
+
const rgb = parseColor(hex);
|
|
266
|
+
if (!rgb) return 0;
|
|
267
|
+
return 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b;
|
|
268
|
+
}
|
|
269
|
+
function getContrastColor(bgHex) {
|
|
270
|
+
return getLuminance(bgHex) > 140 ? "#1a1a2e" : "#f0f0f0";
|
|
271
|
+
}
|
|
272
|
+
function renderFlowchartPreviewSVG(diagram) {
|
|
273
|
+
return renderFlowchartSVG(diagram, { width: 600, height: 450 });
|
|
274
|
+
}
|
|
275
|
+
function renderFlowchartOnCanvas(diagram) {
|
|
276
|
+
if (!diagram || !diagram.nodes || diagram.nodes.length === 0) return false;
|
|
277
|
+
if (!window.svg || !window.Rectangle || !window.Frame) {
|
|
278
|
+
console.error("[FlowchartRenderer] Engine not initialized");
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
const nodes = diagram.nodes;
|
|
282
|
+
const edges = diagram.edges || [];
|
|
283
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
284
|
+
nodes.forEach((n) => {
|
|
285
|
+
const nw = n.width || 140;
|
|
286
|
+
const nh = n.height || 60;
|
|
287
|
+
minX = Math.min(minX, n.x);
|
|
288
|
+
minY = Math.min(minY, n.y);
|
|
289
|
+
maxX = Math.max(maxX, n.x + nw);
|
|
290
|
+
maxY = Math.max(maxY, n.y + nh);
|
|
291
|
+
});
|
|
292
|
+
const dw = maxX - minX || 1;
|
|
293
|
+
const dh = maxY - minY || 1;
|
|
294
|
+
const vb = window.currentViewBox || { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight };
|
|
295
|
+
const vcx = vb.x + vb.width / 2;
|
|
296
|
+
const vcy = vb.y + vb.height / 2;
|
|
297
|
+
const ox = vcx - dw / 2 - minX;
|
|
298
|
+
const oy = vcy - dh / 2 - minY;
|
|
299
|
+
const PADDING = 40;
|
|
300
|
+
const frameTitle = diagram.title || "Mermaid diagram";
|
|
301
|
+
const frame = new window.Frame(
|
|
302
|
+
vcx - dw / 2 - PADDING,
|
|
303
|
+
vcy - dh / 2 - PADDING,
|
|
304
|
+
dw + PADDING * 2,
|
|
305
|
+
dh + PADDING * 2,
|
|
306
|
+
{
|
|
307
|
+
stroke: "#888",
|
|
308
|
+
strokeWidth: 1,
|
|
309
|
+
fill: "transparent",
|
|
310
|
+
opacity: 0.7,
|
|
311
|
+
frameName: frameTitle
|
|
312
|
+
}
|
|
313
|
+
);
|
|
314
|
+
frame._diagramType = "mermaid-flowchart";
|
|
315
|
+
window.shapes.push(frame);
|
|
316
|
+
if (window.pushCreateAction) window.pushCreateAction(frame);
|
|
317
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
318
|
+
for (const n of nodes) {
|
|
319
|
+
const nw = n.width || 140;
|
|
320
|
+
const nh = n.height || 60;
|
|
321
|
+
const nx = n.x + ox;
|
|
322
|
+
const ny = n.y + oy;
|
|
323
|
+
const cx = nx + nw / 2;
|
|
324
|
+
const cy = ny + nh / 2;
|
|
325
|
+
const opts = {
|
|
326
|
+
stroke: n.stroke || "#fff",
|
|
327
|
+
strokeWidth: n.strokeWidth ?? 1.5,
|
|
328
|
+
fill: n.fill || "transparent",
|
|
329
|
+
fillStyle: n.fill && n.fill !== "transparent" ? "solid" : "none",
|
|
330
|
+
roughness: 1,
|
|
331
|
+
label: n.label || ""
|
|
332
|
+
};
|
|
333
|
+
let shape = null;
|
|
334
|
+
try {
|
|
335
|
+
if (n.type === "circle" && window.Circle) {
|
|
336
|
+
shape = new window.Circle(cx, cy, nw / 2, nh / 2, opts);
|
|
337
|
+
} else if (n.type === "diamond") {
|
|
338
|
+
const sz = Math.max(nw, nh) * 0.75;
|
|
339
|
+
shape = new window.Rectangle(cx - sz / 2, cy - sz / 2, sz, sz, opts);
|
|
340
|
+
shape.rotation = 45;
|
|
341
|
+
if (typeof shape.draw === "function") shape.draw();
|
|
342
|
+
} else if (n.type === "roundrect") {
|
|
343
|
+
shape = new window.Rectangle(nx, ny, nw, nh, { ...opts, cornerRadius: Math.min(nw, nh) * 0.2 });
|
|
344
|
+
} else {
|
|
345
|
+
shape = new window.Rectangle(nx, ny, nw, nh, opts);
|
|
346
|
+
}
|
|
347
|
+
} catch (err) {
|
|
348
|
+
console.warn("[FlowchartRenderer] Node creation failed:", n.id, err);
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (!shape) continue;
|
|
352
|
+
window.shapes.push(shape);
|
|
353
|
+
if (window.pushCreateAction) window.pushCreateAction(shape);
|
|
354
|
+
frame.addShapeToFrame(shape);
|
|
355
|
+
nodeMap.set(n.id, { shape, x: nx, y: ny, width: nw, height: nh, centerX: cx, centerY: cy });
|
|
356
|
+
}
|
|
357
|
+
for (const e of edges) {
|
|
358
|
+
const fromNode = nodeMap.get(e.from);
|
|
359
|
+
const toNode = nodeMap.get(e.to);
|
|
360
|
+
if (!fromNode || !toNode) continue;
|
|
361
|
+
const sp = { x: fromNode.centerX, y: fromNode.centerY };
|
|
362
|
+
const ep = { x: toNode.centerX, y: toNode.centerY };
|
|
363
|
+
const directed = e.directed !== false;
|
|
364
|
+
const style = e.style || "normal";
|
|
365
|
+
const isThick = style === "thick";
|
|
366
|
+
const isDotted = style === "dotted";
|
|
367
|
+
const opts = {
|
|
368
|
+
stroke: e.stroke || "#fff",
|
|
369
|
+
strokeWidth: isThick ? 3 : 1.5,
|
|
370
|
+
roughness: 1,
|
|
371
|
+
strokeDasharray: isDotted ? "5 3" : "",
|
|
372
|
+
label: e.label || ""
|
|
373
|
+
};
|
|
374
|
+
let connector = null;
|
|
375
|
+
try {
|
|
376
|
+
if (directed && window.Arrow) {
|
|
377
|
+
connector = new window.Arrow(sp, ep, opts);
|
|
378
|
+
} else if (window.Line) {
|
|
379
|
+
connector = new window.Line(sp, ep, opts);
|
|
380
|
+
} else if (window.Arrow) {
|
|
381
|
+
connector = new window.Arrow(sp, ep, opts);
|
|
382
|
+
}
|
|
383
|
+
} catch (err) {
|
|
384
|
+
console.warn("[FlowchartRenderer] Edge creation failed:", e, err);
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
if (!connector) continue;
|
|
388
|
+
window.shapes.push(connector);
|
|
389
|
+
if (window.pushCreateAction) window.pushCreateAction(connector);
|
|
390
|
+
frame.addShapeToFrame(connector);
|
|
391
|
+
if (directed && connector.shapeName === "arrow" && typeof window.__autoAttach === "function") {
|
|
392
|
+
try {
|
|
393
|
+
window.__autoAttach(connector, fromNode.shape, true, sp);
|
|
394
|
+
window.__autoAttach(connector, toNode.shape, false, ep);
|
|
395
|
+
} catch (err) {
|
|
396
|
+
console.warn("[FlowchartRenderer] autoAttach failed:", err);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
const first = nodeMap.values().next().value;
|
|
401
|
+
if (first) {
|
|
402
|
+
window.currentShape = first.shape;
|
|
403
|
+
if (typeof first.shape.selectShape === "function") first.shape.selectShape();
|
|
404
|
+
}
|
|
405
|
+
return true;
|
|
406
|
+
}
|
|
407
|
+
export {
|
|
408
|
+
renderFlowchartOnCanvas,
|
|
409
|
+
renderFlowchartPreviewSVG,
|
|
410
|
+
renderFlowchartSVG
|
|
411
|
+
};
|
|
412
|
+
//# sourceMappingURL=MermaidFlowchartRenderer-4QBAZ5MB.js.map
|