@ai-matrx/rich-content 0.2.4 → 0.2.6

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.
Files changed (381) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/code-block/CodeBlock.d.ts +44 -0
  3. package/dist/code-block/CodeBlock.js +449 -0
  4. package/dist/code-block/CodeBlockHeader.d.ts +63 -0
  5. package/dist/code-block/CodeBlockHeader.js +472 -0
  6. package/dist/code-block/CodeEditorLoading.d.ts +3 -0
  7. package/dist/code-block/CodeEditorLoading.js +34 -0
  8. package/dist/code-block/LanguageDisplay.d.ts +28 -0
  9. package/dist/code-block/LanguageDisplay.js +279 -0
  10. package/dist/code-block/SmallCodeEditor.d.ts +30 -0
  11. package/dist/code-block/SmallCodeEditor.js +22 -0
  12. package/dist/code-block/StickyButtons.d.ts +35 -0
  13. package/dist/code-block/StickyButtons.js +88 -0
  14. package/dist/code-block/highlight/ShikiCodeView.d.ts +26 -0
  15. package/dist/code-block/highlight/ShikiCodeView.js +134 -0
  16. package/dist/code-block/highlight/shiki-highlighter.d.ts +14 -0
  17. package/dist/code-block/highlight/shiki-highlighter.js +126 -0
  18. package/dist/code-block/highlight/useHighlightedLines.d.ts +18 -0
  19. package/dist/code-block/highlight/useHighlightedLines.js +142 -0
  20. package/dist/code-block/sticky-inset.d.ts +6 -0
  21. package/dist/code-block/sticky-inset.js +10 -0
  22. package/dist/display/block-interaction.d.ts +33 -0
  23. package/dist/display/block-interaction.js +13 -0
  24. package/dist/display/blocks/ChatCollapsibleWrapper.d.ts +13 -0
  25. package/dist/display/blocks/ChatCollapsibleWrapper.js +56 -0
  26. package/dist/display/blocks/buildMediaSource.d.ts +25 -0
  27. package/dist/display/blocks/buildMediaSource.js +43 -0
  28. package/dist/display/blocks/canvas-adaptive.d.ts +118 -0
  29. package/dist/display/blocks/canvas-adaptive.js +127 -0
  30. package/dist/display/blocks/canvas-fit.d.ts +24 -0
  31. package/dist/display/blocks/canvas-fit.js +19 -0
  32. package/dist/display/blocks/chart/ChartBlock.d.ts +8 -0
  33. package/dist/display/blocks/chart/ChartBlock.js +125 -0
  34. package/dist/display/blocks/chart/ChartCanvas.d.ts +18 -0
  35. package/dist/display/blocks/chart/ChartCanvas.js +159 -0
  36. package/dist/display/blocks/chart/TableChart.d.ts +25 -0
  37. package/dist/display/blocks/chart/TableChart.js +97 -0
  38. package/dist/display/blocks/chart/chart-spec.d.ts +39 -0
  39. package/dist/display/blocks/chart/chart-spec.js +128 -0
  40. package/dist/display/blocks/chart/labels.d.ts +20 -0
  41. package/dist/display/blocks/chart/labels.js +7 -0
  42. package/dist/display/blocks/chart/table-chart.d.ts +37 -0
  43. package/dist/display/blocks/chart/table-chart.js +231 -0
  44. package/dist/display/blocks/common/BlockHeaderWrapper.d.ts +56 -0
  45. package/dist/display/blocks/common/BlockHeaderWrapper.js +310 -0
  46. package/dist/display/blocks/common/ContentBlockWrapper.d.ts +40 -0
  47. package/dist/display/blocks/common/ContentBlockWrapper.js +214 -0
  48. package/dist/display/blocks/common/SandboxedHtml.d.ts +27 -0
  49. package/dist/display/blocks/common/SandboxedHtml.js +26 -0
  50. package/dist/display/blocks/diagram/DiagramLoadingVisualization.d.ts +6 -0
  51. package/dist/display/blocks/diagram/DiagramLoadingVisualization.js +190 -0
  52. package/dist/display/blocks/diagram/InteractiveDiagramBlock.d.ts +51 -0
  53. package/dist/display/blocks/diagram/InteractiveDiagramBlock.js +2415 -0
  54. package/dist/display/blocks/diagram/diagram-printer.d.ts +16 -0
  55. package/dist/display/blocks/diagram/diagram-printer.js +294 -0
  56. package/dist/display/blocks/diagram/diagram-visual-defaults.d.ts +116 -0
  57. package/dist/display/blocks/diagram/diagram-visual-defaults.js +400 -0
  58. package/dist/display/blocks/diagram/layout-utils.d.ts +90 -0
  59. package/dist/display/blocks/diagram/layout-utils.js +347 -0
  60. package/dist/display/blocks/diagram/parseDiagramJSON.d.ts +105 -0
  61. package/dist/display/blocks/diagram/parseDiagramJSON.js +296 -0
  62. package/dist/display/blocks/diagram/presentation-direction.d.ts +29 -0
  63. package/dist/display/blocks/diagram/presentation-direction.js +19 -0
  64. package/dist/display/blocks/diagram/ui-utils.d.ts +1 -0
  65. package/dist/display/blocks/diagram/ui-utils.js +18 -0
  66. package/dist/display/blocks/diff/DiffBlock.d.ts +10 -0
  67. package/dist/display/blocks/diff/DiffBlock.js +119 -0
  68. package/dist/display/blocks/diff/DiffCanvas.d.ts +15 -0
  69. package/dist/display/blocks/diff/DiffCanvas.js +20 -0
  70. package/dist/display/blocks/generic/GenericStructuredBlock.d.ts +24 -0
  71. package/dist/display/blocks/generic/GenericStructuredBlock.js +53 -0
  72. package/dist/display/blocks/generic/StructuredValueTabs.d.ts +21 -0
  73. package/dist/display/blocks/generic/StructuredValueTabs.js +124 -0
  74. package/dist/display/blocks/generic/tile-actions-slot.d.ts +39 -0
  75. package/dist/display/blocks/generic/tile-actions-slot.js +33 -0
  76. package/dist/display/blocks/images/ImageBlock.d.ts +8 -0
  77. package/dist/display/blocks/images/ImageBlock.js +265 -0
  78. package/dist/display/blocks/json/JsonBlock.d.ts +34 -0
  79. package/dist/display/blocks/json/JsonBlock.js +562 -0
  80. package/dist/display/blocks/json/JsonTableView.d.ts +10 -0
  81. package/dist/display/blocks/json/JsonTableView.js +173 -0
  82. package/dist/display/blocks/json/json-compact-stringify.d.ts +25 -0
  83. package/dist/display/blocks/json/json-compact-stringify.js +52 -0
  84. package/dist/display/blocks/json/json-tabular-utils.d.ts +65 -0
  85. package/dist/display/blocks/json/json-tabular-utils.js +121 -0
  86. package/dist/display/blocks/links/LinkComponent.d.ts +6 -0
  87. package/dist/display/blocks/links/LinkComponent.js +373 -0
  88. package/dist/display/blocks/links/LinkComponentWithFetch.d.ts +1 -0
  89. package/dist/display/blocks/links/LinkComponentWithFetch.js +0 -0
  90. package/dist/display/blocks/markdown/MarkdownKindBlock.d.ts +48 -0
  91. package/dist/display/blocks/markdown/MarkdownKindBlock.js +52 -0
  92. package/dist/display/blocks/markdown-preview/MarkdownPreviewBlock.d.ts +17 -0
  93. package/dist/display/blocks/markdown-preview/MarkdownPreviewBlock.js +70 -0
  94. package/dist/display/blocks/mermaid/MermaidBlock.d.ts +19 -0
  95. package/dist/display/blocks/mermaid/MermaidBlock.js +386 -0
  96. package/dist/display/blocks/search-replace/SearchReplaceBlock.d.ts +50 -0
  97. package/dist/display/blocks/search-replace/SearchReplaceBlock.js +71 -0
  98. package/dist/display/blocks/svg/SvgBlock.d.ts +8 -0
  99. package/dist/display/blocks/svg/SvgBlock.js +126 -0
  100. package/dist/display/blocks/table/StreamingTableRenderer.d.ts +53 -0
  101. package/dist/display/blocks/table/StreamingTableRenderer.js +907 -0
  102. package/dist/display/blocks/table/TableRenderPathDiagnostic.d.ts +21 -0
  103. package/dist/display/blocks/table/TableRenderPathDiagnostic.js +79 -0
  104. package/dist/display/blocks/thinking-reasoning/ConsolidatedReasoningVisualization.d.ts +14 -0
  105. package/dist/display/blocks/thinking-reasoning/ConsolidatedReasoningVisualization.js +15 -0
  106. package/dist/display/blocks/thinking-reasoning/ReasoningVisualization.d.ts +13 -0
  107. package/dist/display/blocks/thinking-reasoning/ReasoningVisualization.js +19 -0
  108. package/dist/display/blocks/thinking-reasoning/ThinkingTrace.d.ts +30 -0
  109. package/dist/display/blocks/thinking-reasoning/ThinkingTrace.js +75 -0
  110. package/dist/display/blocks/thinking-reasoning/ThinkingTraceMarkdown.d.ts +13 -0
  111. package/dist/display/blocks/thinking-reasoning/ThinkingTraceMarkdown.js +48 -0
  112. package/dist/display/blocks/thinking-reasoning/ThinkingVisualization.d.ts +12 -0
  113. package/dist/display/blocks/thinking-reasoning/ThinkingVisualization.js +19 -0
  114. package/dist/display/blocks/toml/TomlBlock.d.ts +7 -0
  115. package/dist/display/blocks/toml/TomlBlock.js +167 -0
  116. package/dist/display/blocks/tree/TreeBlock.d.ts +7 -0
  117. package/dist/display/blocks/tree/TreeBlock.js +163 -0
  118. package/dist/display/blocks/xml/XmlBlock.d.ts +23 -0
  119. package/dist/display/blocks/xml/XmlBlock.js +197 -0
  120. package/dist/display/blocks/xml/readXmlTag.d.ts +1 -0
  121. package/dist/display/blocks/xml/readXmlTag.js +1 -0
  122. package/dist/display/blocks/xml/xml-tokenize.d.ts +13 -0
  123. package/dist/display/blocks/xml/xml-tokenize.js +169 -0
  124. package/dist/display/blocks/yaml/YamlBlock.d.ts +7 -0
  125. package/dist/display/blocks/yaml/YamlBlock.js +191 -0
  126. package/dist/display/chat-markdown/BasicMarkdownContent.d.ts +29 -0
  127. package/dist/display/chat-markdown/BasicMarkdownContent.js +122 -0
  128. package/dist/display/chat-markdown/BlockRenderingContext.d.ts +23 -0
  129. package/dist/display/chat-markdown/BlockRenderingContext.js +17 -0
  130. package/dist/display/chat-markdown/ConfigurableMarkdownContent.d.ts +172 -0
  131. package/dist/display/chat-markdown/ConfigurableMarkdownContent.js +649 -0
  132. package/dist/display/chat-markdown/InlineCodeSnippet.d.ts +19 -0
  133. package/dist/display/chat-markdown/InlineCodeSnippet.js +146 -0
  134. package/dist/display/chat-markdown/InlineCodeSnippetKindGate.d.ts +11 -0
  135. package/dist/display/chat-markdown/InlineCodeSnippetKindGate.js +9 -0
  136. package/dist/display/chat-markdown/KindTextGate.d.ts +31 -0
  137. package/dist/display/chat-markdown/KindTextGate.js +60 -0
  138. package/dist/display/chat-markdown/QuestionnaireLoadingVisualization.d.ts +6 -0
  139. package/dist/display/chat-markdown/QuestionnaireLoadingVisualization.js +92 -0
  140. package/dist/display/chat-markdown/block-registry/BlockComponentRegistry.d.ts +72 -0
  141. package/dist/display/chat-markdown/block-registry/BlockComponentRegistry.js +94 -0
  142. package/dist/display/chat-markdown/block-registry/BlockRenderer.d.ts +126 -0
  143. package/dist/display/chat-markdown/block-registry/BlockRenderer.js +473 -0
  144. package/dist/display/chat-markdown/block-registry/block-dispatch.d.ts +410 -0
  145. package/dist/display/chat-markdown/block-registry/block-dispatch.js +495 -0
  146. package/dist/display/chat-markdown/block-registry/json-parse-utils.d.ts +13 -0
  147. package/dist/display/chat-markdown/block-registry/json-parse-utils.js +236 -0
  148. package/dist/display/chat-markdown/constants.d.ts +14 -0
  149. package/dist/display/chat-markdown/constants.js +317 -0
  150. package/dist/display/chat-markdown/diff-blocks/DiffCollapsible.d.ts +31 -0
  151. package/dist/display/chat-markdown/diff-blocks/DiffCollapsible.js +62 -0
  152. package/dist/display/chat-markdown/diff-blocks/DiffLoadingIndicator.d.ts +12 -0
  153. package/dist/display/chat-markdown/diff-blocks/DiffLoadingIndicator.js +18 -0
  154. package/dist/display/chat-markdown/diff-blocks/StreamingDiffBlock.d.ts +22 -0
  155. package/dist/display/chat-markdown/diff-blocks/StreamingDiffBlock.js +130 -0
  156. package/dist/display/chat-markdown/diff-blocks/diff-style-registry.d.ts +21 -0
  157. package/dist/display/chat-markdown/diff-blocks/diff-style-registry.js +91 -0
  158. package/dist/display/chat-markdown/diff-blocks/renderers/SearchReplaceDiffRenderer.d.ts +26 -0
  159. package/dist/display/chat-markdown/diff-blocks/renderers/SearchReplaceDiffRenderer.js +186 -0
  160. package/dist/display/chat-markdown/diff-blocks/types.d.ts +56 -0
  161. package/dist/display/chat-markdown/diff-blocks/types.js +0 -0
  162. package/dist/display/chat-markdown/internal-handlers/BlockFallback.d.ts +20 -0
  163. package/dist/display/chat-markdown/internal-handlers/BlockFallback.js +83 -0
  164. package/dist/display/chat-markdown/internal-handlers/InlineStatusIndicator.d.ts +4 -0
  165. package/dist/display/chat-markdown/internal-handlers/InlineStatusIndicator.js +16 -0
  166. package/dist/display/chat-markdown/internal-handlers/MarkdownErrorBoundary.d.ts +17 -0
  167. package/dist/display/chat-markdown/internal-handlers/MarkdownErrorBoundary.js +40 -0
  168. package/dist/display/chat-markdown/internal-handlers/PlainTextFallback.d.ts +8 -0
  169. package/dist/display/chat-markdown/internal-handlers/PlainTextFallback.js +91 -0
  170. package/dist/display/chat-markdown/internal-handlers/SafeBlockRenderer.d.ts +20 -0
  171. package/dist/display/chat-markdown/internal-handlers/SafeBlockRenderer.js +72 -0
  172. package/dist/display/chat-markdown/kind-source-view.d.ts +14 -0
  173. package/dist/display/chat-markdown/kind-source-view.js +14 -0
  174. package/dist/display/chat-markdown/matrx-variables/MatrxVariableInline.d.ts +28 -0
  175. package/dist/display/chat-markdown/matrx-variables/MatrxVariableInline.js +65 -0
  176. package/dist/display/chat-markdown/progressive-mount.d.ts +18 -0
  177. package/dist/display/chat-markdown/progressive-mount.js +90 -0
  178. package/dist/display/chat-markdown/render-block-to-content-block.d.ts +31 -0
  179. package/dist/display/chat-markdown/render-block-to-content-block.js +32 -0
  180. package/dist/display/chat-markdown/settle-stream-blocks.d.ts +50 -0
  181. package/dist/display/chat-markdown/settle-stream-blocks.js +26 -0
  182. package/dist/display/chat-markdown/stable-blocks.d.ts +15 -0
  183. package/dist/display/chat-markdown/stable-blocks.js +54 -0
  184. package/dist/display/chat-markdown/types.d.ts +11 -0
  185. package/dist/display/chat-markdown/types.js +26 -0
  186. package/dist/display/specimen/SpecimenContext.d.ts +26 -0
  187. package/dist/display/specimen/SpecimenContext.js +64 -0
  188. package/dist/display/tables/MarkdownTable.d.ts +23 -0
  189. package/dist/display/tables/MarkdownTable.js +769 -0
  190. package/dist/display/tables/MarkdownTableScrollArea.d.ts +12 -0
  191. package/dist/display/tables/MarkdownTableScrollArea.js +92 -0
  192. package/dist/display/tables/SendToGoogleSheetButton.d.ts +19 -0
  193. package/dist/display/tables/SendToGoogleSheetButton.js +93 -0
  194. package/dist/display/tables/SendToWorkbookButton.d.ts +24 -0
  195. package/dist/display/tables/SendToWorkbookButton.js +93 -0
  196. package/dist/display/tables/TableSaveToMenu.d.ts +16 -0
  197. package/dist/display/tables/TableSaveToMenu.js +98 -0
  198. package/dist/display/tables/TableWithSeparatedControls.d.ts +22 -0
  199. package/dist/display/tables/TableWithSeparatedControls.js +574 -0
  200. package/dist/display/tables/ViewTableModal.d.ts +14 -0
  201. package/dist/display/tables/ViewTableModal.js +67 -0
  202. package/dist/display/tables/editing/ColumnActionsMenu.d.ts +16 -0
  203. package/dist/display/tables/editing/ColumnActionsMenu.js +80 -0
  204. package/dist/display/tables/editing/RowActionsMenu.d.ts +16 -0
  205. package/dist/display/tables/editing/RowActionsMenu.js +80 -0
  206. package/dist/display/tables/editing/TableEditToolbar.d.ts +15 -0
  207. package/dist/display/tables/editing/TableEditToolbar.js +63 -0
  208. package/dist/display/tables/editing/tableMutations.d.ts +50 -0
  209. package/dist/display/tables/editing/tableMutations.js +148 -0
  210. package/dist/display/tables/editing/useDoubleClickEdit.d.ts +43 -0
  211. package/dist/display/tables/editing/useDoubleClickEdit.js +51 -0
  212. package/dist/display/tables/editing/useTableUndo.d.ts +25 -0
  213. package/dist/display/tables/editing/useTableUndo.js +17 -0
  214. package/dist/display/tables/table-action-row.d.ts +8 -0
  215. package/dist/display/tables/table-action-row.js +31 -0
  216. package/dist/display/tables/table-viewer.d.ts +13 -0
  217. package/dist/display/tables/table-viewer.js +18 -0
  218. package/dist/host/ErrorActions.d.ts +1 -1
  219. package/dist/host/ErrorNotice.d.ts +10 -0
  220. package/dist/host/ErrorNotice.js +19 -0
  221. package/dist/host/app-bindings.d.ts +155 -0
  222. package/dist/host/app-bindings.js +160 -0
  223. package/dist/host/diagnostics.d.ts +2 -2
  224. package/dist/host/diagnostics.js +2 -1
  225. package/dist/host/tables.d.ts +1 -6
  226. package/dist/host/types.d.ts +14 -7
  227. package/dist/levels/RichContent.d.ts +3 -0
  228. package/dist/levels/RichContent.js +102 -0
  229. package/dist/levels/RichContentInline.d.ts +28 -0
  230. package/dist/levels/RichContentInline.js +61 -0
  231. package/dist/levels/RichContentPreview.d.ts +12 -0
  232. package/dist/levels/RichContentPreview.js +39 -0
  233. package/dist/levels/RichContentStandardImpl.d.ts +12 -0
  234. package/dist/levels/RichContentStandardImpl.js +27 -0
  235. package/dist/levels/RichContentStaticProse.d.ts +46 -0
  236. package/dist/levels/RichContentStaticProse.js +100 -0
  237. package/dist/levels/depth.d.ts +18 -0
  238. package/dist/levels/depth.js +32 -0
  239. package/dist/levels/prose/inline-level-elements.d.ts +19 -0
  240. package/dist/levels/prose/inline-level-elements.js +103 -0
  241. package/dist/levels/prose/prose-block-elements.d.ts +25 -0
  242. package/dist/levels/prose/prose-block-elements.js +313 -0
  243. package/dist/levels/prose/prose-inline-elements.d.ts +13 -0
  244. package/dist/levels/prose/prose-inline-elements.js +143 -0
  245. package/dist/levels/prose/prose-prepare.d.ts +50 -0
  246. package/dist/levels/prose/prose-prepare.js +246 -0
  247. package/dist/levels/prose/remote-image-policy.d.ts +34 -0
  248. package/dist/levels/prose/remote-image-policy.js +153 -0
  249. package/dist/levels/prose/variant-root.d.ts +9 -0
  250. package/dist/levels/prose/variant-root.js +34 -0
  251. package/dist/levels/rich-content-types.d.ts +93 -0
  252. package/dist/levels/rich-content-types.js +4 -0
  253. package/dist/levels/server/DelimiterViolationReport.d.ts +7 -0
  254. package/dist/levels/server/DelimiterViolationReport.js +24 -0
  255. package/dist/levels/server/RichContentServer.d.ts +27 -0
  256. package/dist/levels/server/RichContentServer.js +97 -0
  257. package/dist/levels/standard/NestedRichContent.d.ts +7 -0
  258. package/dist/levels/standard/NestedRichContent.js +70 -0
  259. package/dist/levels/standard/StandardBlocks.d.ts +13 -0
  260. package/dist/levels/standard/StandardBlocks.js +239 -0
  261. package/dist/levels/standard/StandardKindRegion.d.ts +14 -0
  262. package/dist/levels/standard/StandardKindRegion.js +69 -0
  263. package/dist/levels/standard/standard-kind-region.d.ts +19 -0
  264. package/dist/levels/standard/standard-kind-region.js +21 -0
  265. package/dist/levels/standard/static-standard.d.ts +23 -0
  266. package/dist/levels/standard/static-standard.js +187 -0
  267. package/dist/levels/standard/stream-holdback.d.ts +2 -0
  268. package/dist/levels/standard/stream-holdback.js +77 -0
  269. package/dist/mermaid/MermaidFullscreen.d.ts +17 -0
  270. package/dist/mermaid/MermaidFullscreen.js +71 -0
  271. package/dist/mermaid/MermaidRenderer.d.ts +20 -0
  272. package/dist/mermaid/MermaidRenderer.js +267 -0
  273. package/dist/mermaid/MermaidView.d.ts +27 -0
  274. package/dist/mermaid/MermaidView.js +68 -0
  275. package/dist/mermaid/MermaidViewport.d.ts +75 -0
  276. package/dist/mermaid/MermaidViewport.js +286 -0
  277. package/dist/mermaid/adapters/er.d.ts +10 -0
  278. package/dist/mermaid/adapters/er.js +205 -0
  279. package/dist/mermaid/adapters/flowchart.d.ts +17 -0
  280. package/dist/mermaid/adapters/flowchart.js +634 -0
  281. package/dist/mermaid/adapters/journey.d.ts +9 -0
  282. package/dist/mermaid/adapters/journey.js +207 -0
  283. package/dist/mermaid/adapters/mindmap.d.ts +12 -0
  284. package/dist/mermaid/adapters/mindmap.js +252 -0
  285. package/dist/mermaid/adapters/pie.d.ts +7 -0
  286. package/dist/mermaid/adapters/pie.js +172 -0
  287. package/dist/mermaid/adapters/quadrant.d.ts +8 -0
  288. package/dist/mermaid/adapters/quadrant.js +231 -0
  289. package/dist/mermaid/adapters/register.d.ts +7 -0
  290. package/dist/mermaid/adapters/register.js +19 -0
  291. package/dist/mermaid/adapters/sequence.d.ts +8 -0
  292. package/dist/mermaid/adapters/sequence.js +251 -0
  293. package/dist/mermaid/adapters/state.d.ts +12 -0
  294. package/dist/mermaid/adapters/state.js +245 -0
  295. package/dist/mermaid/adapters/timeline.d.ts +8 -0
  296. package/dist/mermaid/adapters/timeline.js +245 -0
  297. package/dist/mermaid/catalog.d.ts +33 -0
  298. package/dist/mermaid/catalog.js +202 -0
  299. package/dist/mermaid/diagram-type.d.ts +39 -0
  300. package/dist/mermaid/diagram-type.js +89 -0
  301. package/dist/mermaid/export.d.ts +21 -0
  302. package/dist/mermaid/export.js +112 -0
  303. package/dist/mermaid/extract-fence.d.ts +15 -0
  304. package/dist/mermaid/extract-fence.js +22 -0
  305. package/dist/mermaid/lazy-draw.d.ts +40 -0
  306. package/dist/mermaid/lazy-draw.js +168 -0
  307. package/dist/mermaid/model/adapter.d.ts +28 -0
  308. package/dist/mermaid/model/adapter.js +16 -0
  309. package/dist/mermaid/model/ops.d.ts +282 -0
  310. package/dist/mermaid/model/ops.js +9 -0
  311. package/dist/mermaid/model/round-trip.d.ts +22 -0
  312. package/dist/mermaid/model/round-trip.js +45 -0
  313. package/dist/mermaid/model/types.d.ts +271 -0
  314. package/dist/mermaid/model/types.js +0 -0
  315. package/dist/mermaid/print-render.d.ts +9 -0
  316. package/dist/mermaid/print-render.js +39 -0
  317. package/dist/mermaid/runtime.d.ts +25 -0
  318. package/dist/mermaid/runtime.js +183 -0
  319. package/dist/mermaid/sanitize.d.ts +46 -0
  320. package/dist/mermaid/sanitize.js +234 -0
  321. package/dist/mermaid/types.d.ts +43 -0
  322. package/dist/mermaid/types.js +21 -0
  323. package/dist/mermaid/view/ViewModePane.d.ts +24 -0
  324. package/dist/mermaid/view/ViewModePane.js +9 -0
  325. package/dist/utils/client-lazy.d.ts +1 -1
  326. package/dist/utils/client-lazy.js +4 -1
  327. package/dist/utils/lifted/DiffView.d.ts +10 -0
  328. package/dist/utils/lifted/DiffView.js +26 -0
  329. package/dist/utils/lifted/IconButton.d.ts +24 -0
  330. package/dist/utils/lifted/IconButton.js +43 -0
  331. package/dist/utils/lifted/MatrxMiniLoader.d.ts +1 -0
  332. package/dist/utils/lifted/MatrxMiniLoader.js +8 -0
  333. package/dist/utils/lifted/ShimmerText.d.ts +5 -0
  334. package/dist/utils/lifted/ShimmerText.js +21 -0
  335. package/dist/utils/lifted/SuspenseLoader.d.ts +16 -0
  336. package/dist/utils/lifted/SuspenseLoader.js +42 -0
  337. package/dist/utils/lifted/Tooltip.d.ts +20 -0
  338. package/dist/utils/lifted/Tooltip.js +52 -0
  339. package/dist/utils/lifted/artifactId.d.ts +34 -0
  340. package/dist/utils/lifted/artifactId.js +15 -0
  341. package/dist/utils/lifted/canvasContent.d.ts +63 -0
  342. package/dist/utils/lifted/canvasContent.js +98 -0
  343. package/dist/utils/lifted/captureReactError.d.ts +24 -0
  344. package/dist/utils/lifted/captureReactError.js +28 -0
  345. package/dist/utils/lifted/chunk-load-recovery.d.ts +25 -0
  346. package/dist/utils/lifted/chunk-load-recovery.js +36 -0
  347. package/dist/utils/lifted/code-editor-agent-types.d.ts +6 -0
  348. package/dist/utils/lifted/code-editor-agent-types.js +0 -0
  349. package/dist/utils/lifted/code-editor-agents.d.ts +39 -0
  350. package/dist/utils/lifted/code-editor-agents.js +52 -0
  351. package/dist/utils/lifted/code-language-extension.d.ts +1 -0
  352. package/dist/utils/lifted/code-language-extension.js +60 -0
  353. package/dist/utils/lifted/custom-icons.d.ts +16 -0
  354. package/dist/utils/lifted/custom-icons.js +47 -0
  355. package/dist/utils/lifted/durability.d.ts +16 -0
  356. package/dist/utils/lifted/durability.js +45 -0
  357. package/dist/utils/lifted/errors.d.ts +30 -0
  358. package/dist/utils/lifted/errors.js +29 -0
  359. package/dist/utils/lifted/html-document.d.ts +1 -0
  360. package/dist/utils/lifted/html-document.js +12 -0
  361. package/dist/utils/lifted/languageOptions.d.ts +9 -0
  362. package/dist/utils/lifted/languageOptions.js +52 -0
  363. package/dist/utils/lifted/languages.d.ts +34 -0
  364. package/dist/utils/lifted/languages.js +175 -0
  365. package/dist/utils/lifted/loading-spinner.d.ts +18 -0
  366. package/dist/utils/lifted/loading-spinner.js +200 -0
  367. package/dist/utils/lifted/media-refs.d.ts +13 -0
  368. package/dist/utils/lifted/media-refs.js +27 -0
  369. package/dist/utils/lifted/scroll-root.d.ts +1 -0
  370. package/dist/utils/lifted/scroll-root.js +25 -0
  371. package/dist/utils/lifted/syntax-themes.d.ts +32 -0
  372. package/dist/utils/lifted/syntax-themes.js +100 -0
  373. package/dist/utils/lifted/url-utm.d.ts +24 -0
  374. package/dist/utils/lifted/url-utm.js +66 -0
  375. package/dist/utils/lifted/use-is-mounted.d.ts +24 -0
  376. package/dist/utils/lifted/use-is-mounted.js +21 -0
  377. package/dist/utils/lifted/useToastManager.d.ts +1 -0
  378. package/dist/utils/lifted/useToastManager.js +7 -0
  379. package/dist/utils/report-kind-at-raw-renderer.d.ts +19 -0
  380. package/dist/utils/report-kind-at-raw-renderer.js +32 -0
  381. package/package.json +32 -3
@@ -0,0 +1,2415 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { Button, Chip } from "@ai-matrx/design-system/controls";
4
+ import {
5
+ useState,
6
+ useCallback,
7
+ useMemo,
8
+ useEffect,
9
+ useRef,
10
+ useId
11
+ } from "react";
12
+ import {
13
+ ReactFlow,
14
+ Controls,
15
+ Background,
16
+ useNodesState,
17
+ useEdgesState,
18
+ addEdge,
19
+ MarkerType,
20
+ BackgroundVariant,
21
+ Panel,
22
+ MiniMap,
23
+ ReactFlowProvider,
24
+ Handle,
25
+ Position,
26
+ useReactFlow,
27
+ useNodesInitialized,
28
+ useStore,
29
+ getViewportForBounds,
30
+ NodeResizer,
31
+ applyNodeChanges,
32
+ reconnectEdge
33
+ } from "@xyflow/react";
34
+ import "@xyflow/react/dist/style.css";
35
+ import {
36
+ Network,
37
+ Maximize2,
38
+ Minimize2,
39
+ Download,
40
+ Layers,
41
+ Settings,
42
+ CheckCircle2,
43
+ XCircle,
44
+ GitBranch,
45
+ Users,
46
+ Database,
47
+ Server,
48
+ Globe,
49
+ Cpu,
50
+ HardDrive,
51
+ RotateCcw,
52
+ Square,
53
+ Circle,
54
+ Rainbow,
55
+ Shuffle,
56
+ Camera,
57
+ ExternalLink,
58
+ Printer,
59
+ Clock,
60
+ Table,
61
+ ArrowRight,
62
+ ArrowDown,
63
+ ArrowLeft,
64
+ ArrowUp,
65
+ Plus,
66
+ Trash2,
67
+ Pencil,
68
+ Check,
69
+ Boxes,
70
+ Magnet,
71
+ LayoutGrid,
72
+ ChevronDown
73
+ } from "lucide-react";
74
+ import { useCanvas } from "../../../host/app-bindings.js";
75
+ import { useOpenArtifactInCanvas } from "../../../host/app-bindings.js";
76
+ import { isMaterializedArtifactId } from "../../../utils/lifted/artifactId.js";
77
+ import { getArtifactDef } from "../../../host/app-bindings.js";
78
+ import IconButton from "../../../utils/lifted/IconButton.js";
79
+ import { IconResolver } from "@ai-matrx/icons";
80
+ import { IconInputWithValidation } from "../../../host/app-bindings.js";
81
+ import {
82
+ getLayoutedElements,
83
+ getLayoutOptionsForDiagramType,
84
+ getGridLayout,
85
+ getRadialLayout,
86
+ getOrgChartLayout,
87
+ getPedigreeLayout
88
+ } from "./layout-utils.js";
89
+ import { formatDiagramType } from "./ui-utils.js";
90
+ import {
91
+ diagramDirectionForFlow,
92
+ shouldRelayoutOnFlowChange
93
+ } from "./presentation-direction.js";
94
+ import { preferredFlowDirection } from "@ai-matrx/canvas";
95
+ import { useCanvasPresentation } from "@ai-matrx/canvas/react";
96
+ import {
97
+ diagramScrollPans,
98
+ firstRankBounds,
99
+ portraitWidthFitViewport
100
+ } from "../canvas-adaptive.js";
101
+ import {
102
+ materializeDiagramDefaults
103
+ } from "./parseDiagramJSON.js";
104
+ import {
105
+ DIAGRAM_COLOR_PRESETS,
106
+ getDiagramColorHex,
107
+ getDiagramNodeColorClass,
108
+ isCustomDiagramColor,
109
+ normalizeDiagramIconName
110
+ } from "./diagram-visual-defaults.js";
111
+ import {
112
+ PrintOptionsDialog,
113
+ usePrintOptions
114
+ } from "@ai-matrx/print/react";
115
+ import { createDiagramPrinter } from "./diagram-printer.js";
116
+ import {
117
+ DropdownMenu,
118
+ DropdownMenuContent,
119
+ DropdownMenuItem,
120
+ DropdownMenuLabel,
121
+ DropdownMenuSeparator,
122
+ DropdownMenuTrigger
123
+ } from "@ai-matrx/design-system";
124
+ const UNSAFE_COLOR_RE = /\b(oklch|oklab|lab|lch|color)\s*\(/i;
125
+ function backgroundVariantFromDiagram(diagram) {
126
+ if (diagram.renderHints?.background === "lines")
127
+ return BackgroundVariant.Lines;
128
+ if (diagram.renderHints?.background === "cross")
129
+ return BackgroundVariant.Cross;
130
+ return BackgroundVariant.Dots;
131
+ }
132
+ function safenColor(value, prop, isDark) {
133
+ if (!UNSAFE_COLOR_RE.test(value)) return value;
134
+ const lp = prop.toLowerCase();
135
+ if (lp.includes("background")) return isDark ? "#1f2937" : "#ffffff";
136
+ if (lp === "color") return isDark ? "#f3f4f6" : "#111827";
137
+ if (lp.includes("border") || lp.includes("outline"))
138
+ return isDark ? "#4b5563" : "#d1d5db";
139
+ if (lp === "fill" || lp === "stroke") return isDark ? "#9ca3af" : "#374151";
140
+ return isDark ? "#6b7280" : "#6b7280";
141
+ }
142
+ function patchComputedStyleForCapture(isDark) {
143
+ const original = window.getComputedStyle.bind(window);
144
+ window.getComputedStyle = function(elt, pseudo) {
145
+ const computed = original(elt, pseudo);
146
+ return new Proxy(computed, {
147
+ get(target, prop) {
148
+ const value = target[prop];
149
+ if (typeof prop === "string" && typeof value === "string" && value && UNSAFE_COLOR_RE.test(value)) {
150
+ return safenColor(value, prop, isDark);
151
+ }
152
+ if (prop === "getPropertyValue") {
153
+ return (p) => {
154
+ const raw = target.getPropertyValue(p);
155
+ return raw && UNSAFE_COLOR_RE.test(raw) ? safenColor(raw, p, isDark) : raw;
156
+ };
157
+ }
158
+ if (typeof value === "function")
159
+ return value.bind(target);
160
+ return value;
161
+ }
162
+ });
163
+ };
164
+ return () => {
165
+ window.getComputedStyle = original;
166
+ };
167
+ }
168
+ const PedigreeNode = ({
169
+ data,
170
+ selected
171
+ }) => {
172
+ const gender = data.gender;
173
+ const affected = data.affected;
174
+ const deceased = data.deceased;
175
+ const proband = data.proband;
176
+ const birthYear = data.birthYear;
177
+ const deathYear = data.deathYear;
178
+ const description = typeof data.description === "string" ? data.description : void 0;
179
+ const isCircle = gender === "female";
180
+ const isUnknown = !gender || gender === "unknown";
181
+ const shapeBase = "relative flex items-center justify-center transition-all";
182
+ const size = "w-20 h-20";
183
+ const fillColor = affected ? "bg-gray-800 dark:bg-gray-200 text-white dark:text-gray-900" : "bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100";
184
+ const borderColor = proband ? "border-4 border-blue-500" : selected ? "border-4 border-blue-400" : "border-2 border-gray-600 dark:border-gray-400";
185
+ const shapeClass = isCircle ? `rounded-full ${shapeBase} ${size} ${fillColor} ${borderColor}` : isUnknown ? `rotate-45 ${shapeBase} ${size} ${fillColor} border-2 border-gray-600 dark:border-gray-400` : `${shapeBase} ${size} ${fillColor} ${borderColor}`;
186
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-1 p-1", children: [
187
+ /* @__PURE__ */ jsx(
188
+ Handle,
189
+ {
190
+ type: "target",
191
+ position: Position.Top,
192
+ id: "input",
193
+ className: "w-2 h-2 border border-gray-400 dark:border-gray-500 bg-white dark:bg-gray-700"
194
+ }
195
+ ),
196
+ /* @__PURE__ */ jsxs("div", { className: shapeClass, title: data.label, children: [
197
+ deceased && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsx("div", { className: "absolute w-full h-px bg-gray-600 dark:bg-gray-400 rotate-45 origin-center" }) }),
198
+ proband && /* @__PURE__ */ jsx("div", { className: "absolute -bottom-1 -left-3 text-blue-500 text-xs font-bold", children: "\u2197" }),
199
+ isUnknown && /* @__PURE__ */ jsx("div", { className: "-rotate-45 text-xs font-semibold text-center leading-tight px-1", children: data.label }),
200
+ !isUnknown && /* @__PURE__ */ jsx("div", { className: "text-xs font-semibold text-center leading-tight px-1 break-words max-w-full", children: data.label })
201
+ ] }),
202
+ (description || birthYear) && /* @__PURE__ */ jsxs("div", { className: "text-center max-w-[120px]", children: [
203
+ description && /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-700 dark:text-gray-300 font-medium truncate", children: description }),
204
+ (birthYear || deathYear) && /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500 dark:text-gray-400", children: birthYear && deathYear ? `${birthYear}\u2013${deathYear}` : birthYear ? `b. ${birthYear}` : deathYear ? `d. ${deathYear}` : null })
205
+ ] }),
206
+ /* @__PURE__ */ jsx(
207
+ Handle,
208
+ {
209
+ type: "source",
210
+ position: Position.Bottom,
211
+ id: "output",
212
+ className: "w-2 h-2 border border-gray-400 dark:border-gray-500 bg-white dark:bg-gray-700"
213
+ }
214
+ )
215
+ ] });
216
+ };
217
+ const TimelineNode = ({
218
+ data,
219
+ selected
220
+ }) => {
221
+ const details = typeof data.details === "string" ? data.details : void 0;
222
+ const description = typeof data.description === "string" ? data.description : void 0;
223
+ return /* @__PURE__ */ jsxs(
224
+ "div",
225
+ {
226
+ className: `px-4 py-3 min-w-[140px] max-w-[200px] rounded-xl border-2 shadow-md transition-all bg-blue-50 dark:bg-blue-950/30 border-blue-400 dark:border-blue-600 text-blue-900 dark:text-blue-100 ${selected ? "shadow-xl scale-105 ring-2 ring-blue-400" : "hover:shadow-md"}`,
227
+ children: [
228
+ /* @__PURE__ */ jsx(
229
+ Handle,
230
+ {
231
+ type: "target",
232
+ position: Position.Left,
233
+ id: "input",
234
+ className: "w-2 h-2 border border-blue-400 bg-white dark:bg-gray-800"
235
+ }
236
+ ),
237
+ details && /* @__PURE__ */ jsx("div", { className: "text-xs font-bold text-blue-500 dark:text-blue-400 mb-1", children: details }),
238
+ /* @__PURE__ */ jsx("div", { className: "font-semibold text-sm", children: data.label }),
239
+ description && /* @__PURE__ */ jsx("div", { className: "text-xs opacity-75 mt-1", children: description }),
240
+ /* @__PURE__ */ jsx(
241
+ Handle,
242
+ {
243
+ type: "source",
244
+ position: Position.Right,
245
+ id: "output",
246
+ className: "w-2 h-2 border border-blue-400 bg-white dark:bg-gray-800"
247
+ }
248
+ )
249
+ ]
250
+ }
251
+ );
252
+ };
253
+ const ERDNode = ({
254
+ data,
255
+ selected
256
+ }) => {
257
+ const attributes = data.attributes;
258
+ return /* @__PURE__ */ jsxs(
259
+ "div",
260
+ {
261
+ className: `min-w-[160px] rounded-lg border-2 shadow-md overflow-hidden transition-all bg-white dark:bg-gray-800 border-purple-400 dark:border-purple-600 ${selected ? "shadow-xl scale-105 ring-2 ring-purple-400" : "hover:shadow-md"}`,
262
+ children: [
263
+ /* @__PURE__ */ jsx(
264
+ Handle,
265
+ {
266
+ type: "target",
267
+ position: Position.Left,
268
+ id: "input",
269
+ className: "w-2 h-2 border border-purple-400 bg-white dark:bg-gray-800"
270
+ }
271
+ ),
272
+ /* @__PURE__ */ jsx("div", { className: "bg-purple-500 dark:bg-purple-700 px-3 py-2 text-white font-bold text-sm text-center", children: data.label }),
273
+ attributes && attributes.length > 0 && /* @__PURE__ */ jsx("div", { className: "divide-y divide-gray-100 dark:divide-gray-700", children: attributes.map((attr, i) => /* @__PURE__ */ jsx(
274
+ "div",
275
+ {
276
+ className: "px-3 py-1 text-xs text-gray-700 dark:text-gray-300 font-mono",
277
+ children: attr
278
+ },
279
+ i
280
+ )) }),
281
+ /* @__PURE__ */ jsx(
282
+ Handle,
283
+ {
284
+ type: "source",
285
+ position: Position.Right,
286
+ id: "output",
287
+ className: "w-2 h-2 border border-purple-400 bg-white dark:bg-gray-800"
288
+ }
289
+ )
290
+ ]
291
+ }
292
+ );
293
+ };
294
+ const CustomNode = ({
295
+ data,
296
+ selected
297
+ }) => {
298
+ const description = typeof data.description === "string" ? data.description : void 0;
299
+ const details = typeof data.details === "string" ? data.details : void 0;
300
+ const getNodeIcon = () => {
301
+ const iconName = normalizeDiagramIconName(
302
+ typeof data.icon === "string" ? data.icon : "Square"
303
+ );
304
+ if (iconName === "none") return null;
305
+ return /* @__PURE__ */ jsx(
306
+ IconResolver,
307
+ {
308
+ iconName,
309
+ fallbackIcon: "Square",
310
+ className: "h-4 w-4 shrink-0"
311
+ }
312
+ );
313
+ };
314
+ const getNodeColor = () => {
315
+ const explicit = getDiagramNodeColorClass(data.color);
316
+ if (explicit) return explicit;
317
+ if (data.color) return "";
318
+ switch (data.nodeType) {
319
+ case "start":
320
+ return "bg-green-100 dark:bg-green-950/30 border-green-500 text-green-700 dark:text-green-300";
321
+ case "end":
322
+ return "bg-red-100 dark:bg-red-950/30 border-red-500 text-red-700 dark:text-red-300";
323
+ case "decision":
324
+ return "bg-orange-100 dark:bg-orange-950/30 border-orange-500 text-orange-700 dark:text-orange-300";
325
+ case "process":
326
+ return "bg-blue-100 dark:bg-blue-950/30 border-blue-500 text-blue-700 dark:text-blue-300";
327
+ case "data":
328
+ return "bg-purple-100 dark:bg-purple-950/30 border-purple-500 text-purple-700 dark:text-purple-300";
329
+ case "user":
330
+ return "bg-indigo-100 dark:bg-indigo-950/30 border-indigo-500 text-indigo-700 dark:text-indigo-300";
331
+ case "system":
332
+ return "bg-gray-100 dark:bg-gray-800 border-gray-500 text-gray-700 dark:text-gray-300";
333
+ case "api":
334
+ return "bg-teal-100 dark:bg-teal-950/30 border-teal-500 text-teal-700 dark:text-teal-300";
335
+ case "compute":
336
+ return "bg-yellow-100 dark:bg-yellow-950/30 border-yellow-500 text-yellow-700 dark:text-yellow-300";
337
+ case "storage":
338
+ return "bg-pink-100 dark:bg-pink-950/30 border-pink-500 text-pink-700 dark:text-pink-300";
339
+ case "event":
340
+ return "bg-cyan-100 dark:bg-cyan-950/30 border-cyan-500 text-cyan-700 dark:text-cyan-300";
341
+ case "entity":
342
+ return "bg-violet-100 dark:bg-violet-950/30 border-violet-500 text-violet-700 dark:text-violet-300";
343
+ case "gateway":
344
+ return "bg-amber-100 dark:bg-amber-950/30 border-amber-500 text-amber-700 dark:text-amber-300";
345
+ default:
346
+ return "bg-textured border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300";
347
+ }
348
+ };
349
+ const isOrgChart = data.diagramType === "orgchart";
350
+ const colorClass = getNodeColor();
351
+ const inlineStyle = isCustomDiagramColor(data.color) ? {
352
+ backgroundColor: `${getDiagramColorHex(data.color)}20`,
353
+ borderColor: getDiagramColorHex(data.color),
354
+ color: getDiagramColorHex(data.color)
355
+ } : void 0;
356
+ const shape = data.shape === "rectangle" || data.shape === "pill" || data.shape === "circle" || data.shape === "diamond" || data.shape === "hexagon" ? data.shape : "rounded";
357
+ const shapeClass = shape === "rectangle" ? "rounded-none" : shape === "pill" ? "rounded-full" : shape === "circle" ? "aspect-square rounded-full" : shape === "rounded" ? "rounded-lg" : "rounded-none";
358
+ const clipPath = shape === "diamond" ? "polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)" : shape === "hexagon" ? "polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%)" : void 0;
359
+ const borderStyle = data.borderStyle === "dashed" ? "border-dashed" : data.borderStyle === "dotted" ? "border-dotted" : "border-solid";
360
+ const centered = data.textAlign === "center";
361
+ const hasExplicitWidth = data.hasExplicitWidth === true;
362
+ const shapeSizeClass = shape === "circle" ? "aspect-square w-[200px] min-w-[160px]" : shape === "diamond" ? "min-h-[180px] w-[240px] min-w-[200px]" : shape === "hexagon" ? "min-h-[140px] w-[260px] min-w-[220px]" : isOrgChart ? `min-w-[200px] ${hasExplicitWidth ? "" : "max-w-[280px]"}` : `min-w-[120px] ${hasExplicitWidth ? "" : "max-w-[280px]"}`;
363
+ const shapePaddingClass = shape === "diamond" ? "px-12 py-10" : shape === "hexagon" ? "px-10 py-6" : isOrgChart ? "px-6 py-4" : "px-4 py-3";
364
+ return /* @__PURE__ */ jsxs("div", { className: `${shapeSizeClass} relative h-full overflow-visible`, children: [
365
+ /* @__PURE__ */ jsx(
366
+ NodeResizer,
367
+ {
368
+ isVisible: selected && data.editing === true,
369
+ minWidth: shape === "circle" ? 120 : 140,
370
+ minHeight: shape === "circle" ? 120 : 64,
371
+ keepAspectRatio: shape === "circle",
372
+ lineClassName: "!border-primary",
373
+ handleClassName: "!h-2.5 !w-2.5 !border-primary !bg-background"
374
+ }
375
+ ),
376
+ /* @__PURE__ */ jsx(
377
+ Handle,
378
+ {
379
+ type: "target",
380
+ position: isOrgChart ? Position.Top : Position.Left,
381
+ id: "input",
382
+ style: isOrgChart ? { left: "50%", transform: "translateX(-50%)", top: "-6px" } : {},
383
+ className: "w-3 h-3 border-2 border-gray-400 dark:border-gray-500 bg-textured hover:bg-blue-200 dark:hover:bg-blue-700 transition-colors"
384
+ }
385
+ ),
386
+ /* @__PURE__ */ jsx(
387
+ "div",
388
+ {
389
+ className: `${shapePaddingClass} relative flex h-full w-full items-center border-2 shadow-lg transition-all ${shapeClass} ${borderStyle} ${colorClass} ${selected ? "shadow-xl ring-2 ring-blue-400 dark:ring-blue-500" : "hover:shadow-md"}`,
390
+ style: { ...inlineStyle, clipPath },
391
+ children: isOrgChart ? /* @__PURE__ */ jsxs("div", { className: "w-full min-w-0 text-center", children: [
392
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-2 mb-2", children: [
393
+ getNodeIcon(),
394
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 break-words text-base font-bold [overflow-wrap:anywhere]", children: data.label })
395
+ ] }),
396
+ description && /* @__PURE__ */ jsx("div", { className: "mb-1 break-words text-sm font-medium opacity-90 [overflow-wrap:anywhere]", children: description }),
397
+ details && /* @__PURE__ */ jsx("div", { className: "break-words text-xs italic opacity-70 [overflow-wrap:anywhere]", children: details })
398
+ ] }) : /* @__PURE__ */ jsxs(
399
+ "div",
400
+ {
401
+ className: `w-full min-w-0 ${centered ? "text-center" : "text-left"}`,
402
+ children: [
403
+ /* @__PURE__ */ jsxs(
404
+ "div",
405
+ {
406
+ className: `mb-1 flex items-center gap-2 ${centered ? "justify-center" : ""}`,
407
+ children: [
408
+ getNodeIcon(),
409
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 break-words text-sm font-semibold [overflow-wrap:anywhere]", children: data.label })
410
+ ]
411
+ }
412
+ ),
413
+ description && /* @__PURE__ */ jsx("div", { className: "mt-1 break-words text-xs opacity-80 [overflow-wrap:anywhere]", children: description }),
414
+ details && /* @__PURE__ */ jsx("div", { className: "mt-1 break-words text-xs italic opacity-70 [overflow-wrap:anywhere]", children: details })
415
+ ]
416
+ }
417
+ )
418
+ }
419
+ ),
420
+ /* @__PURE__ */ jsx(
421
+ Handle,
422
+ {
423
+ type: "source",
424
+ position: isOrgChart ? Position.Bottom : Position.Right,
425
+ id: "output",
426
+ style: isOrgChart ? { left: "50%", transform: "translateX(-50%)", bottom: "-6px" } : {},
427
+ className: "w-3 h-3 border-2 border-gray-400 dark:border-gray-500 bg-textured hover:bg-blue-200 dark:hover:bg-blue-700 transition-colors"
428
+ }
429
+ )
430
+ ] });
431
+ };
432
+ const GroupNode = ({
433
+ data,
434
+ selected
435
+ }) => {
436
+ const style = data.groupStyle === "solid" ? "border-solid" : data.groupStyle === "dotted" ? "border-dotted" : "border-dashed";
437
+ const color = typeof data.color === "string" && data.color !== "auto" ? data.color : void 0;
438
+ return /* @__PURE__ */ jsxs(
439
+ "div",
440
+ {
441
+ className: `h-full w-full rounded-2xl border-2 ${style} bg-background/35 shadow-sm backdrop-blur-[1px] transition-colors ${selected ? "border-primary ring-2 ring-primary/20" : "border-border/80"}`,
442
+ style: color ? {
443
+ borderColor: getDiagramColorHex(color),
444
+ backgroundColor: `${getDiagramColorHex(color)}0d`
445
+ } : void 0,
446
+ children: [
447
+ /* @__PURE__ */ jsx(
448
+ NodeResizer,
449
+ {
450
+ isVisible: selected && data.editing === true,
451
+ minWidth: 260,
452
+ minHeight: 180,
453
+ lineClassName: "!border-primary",
454
+ handleClassName: "!h-2.5 !w-2.5 !border-primary !bg-background"
455
+ }
456
+ ),
457
+ /* @__PURE__ */ jsxs("div", { className: "pointer-events-none absolute left-3 top-2 flex max-w-[calc(100%-1.5rem)] items-center gap-1.5 rounded-md bg-background/90 px-2 py-1 text-xs font-semibold text-foreground shadow-sm ring-1 ring-border/70", children: [
458
+ /* @__PURE__ */ jsx(Boxes, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
459
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: String(data.label ?? "Section") })
460
+ ] })
461
+ ]
462
+ }
463
+ );
464
+ };
465
+ const nodeTypes = {
466
+ custom: CustomNode,
467
+ pedigree: PedigreeNode,
468
+ timeline: TimelineNode,
469
+ erd: ERDNode,
470
+ group: GroupNode
471
+ };
472
+ function getReactFlowNodeType(diagramType, nodeData) {
473
+ if (nodeData.isGroup) return "group";
474
+ if (diagramType === "pedigree") return "pedigree";
475
+ if (diagramType === "timeline") return "timeline";
476
+ if (diagramType === "erd") return "erd";
477
+ return "custom";
478
+ }
479
+ function buildReactFlowNodes(diagram, editing = false) {
480
+ const ordered = [...diagram.nodes].sort(
481
+ (a, b) => Number(Boolean(b.isGroup)) - Number(Boolean(a.isGroup))
482
+ );
483
+ return ordered.map((node, index) => ({
484
+ id: node.id,
485
+ type: getReactFlowNodeType(diagram.type, node),
486
+ position: node.position || {
487
+ x: index % 3 * 200 + 100,
488
+ y: Math.floor(index / 3) * 150 + 100
489
+ },
490
+ data: {
491
+ label: node.label,
492
+ isGroup: node.isGroup === true,
493
+ groupStyle: node.groupStyle ?? "dashed",
494
+ editing,
495
+ nodeType: node.nodeType || node.type || "default",
496
+ description: node.description,
497
+ details: node.details,
498
+ diagramType: diagram.type,
499
+ // Pedigree fields
500
+ gender: node.gender,
501
+ affected: node.affected,
502
+ deceased: node.deceased,
503
+ proband: node.proband,
504
+ birthYear: node.birthYear,
505
+ deathYear: node.deathYear,
506
+ generation: node.generation,
507
+ // Extras
508
+ color: node.color,
509
+ icon: node.icon,
510
+ shape: node.shape,
511
+ borderStyle: node.borderStyle,
512
+ textAlign: node.textAlign,
513
+ attributes: node.metadata?.attributes,
514
+ hasExplicitWidth: node.width !== void 0
515
+ },
516
+ parentId: node.parentId,
517
+ extent: node.parentId ? "parent" : void 0,
518
+ expandParent: Boolean(node.parentId),
519
+ style: node.width !== void 0 || node.height !== void 0 || node.isGroup ? {
520
+ width: node.width ?? (node.isGroup ? 420 : void 0),
521
+ height: node.height ?? (node.isGroup ? 260 : void 0)
522
+ } : void 0
523
+ }));
524
+ }
525
+ function buildReactFlowEdges(diagram) {
526
+ const nodeIds = new Set(diagram.nodes.map((n) => n.id));
527
+ const isPedigree = diagram.type === "pedigree";
528
+ const hideArrows = diagram.renderHints?.hideArrows;
529
+ const showLabels = diagram.renderHints?.showEdgeLabels !== false;
530
+ const seenEdgeIds = /* @__PURE__ */ new Map();
531
+ const uniqueEdgeId = (rawId) => {
532
+ const priorCount = seenEdgeIds.get(rawId) ?? 0;
533
+ seenEdgeIds.set(rawId, priorCount + 1);
534
+ if (priorCount === 0) return rawId;
535
+ const deduped = `${rawId}__dup${priorCount}`;
536
+ console.warn(
537
+ `Diagram edge id "${rawId}" is duplicated in this diagram's data; rendering it as "${deduped}" so both edges stay visible.`
538
+ );
539
+ return deduped;
540
+ };
541
+ return diagram.edges.filter((edge) => {
542
+ if (!nodeIds.has(edge.source) || !nodeIds.has(edge.target)) {
543
+ console.warn(`Diagram edge ${edge.id} references missing nodes`, edge);
544
+ return false;
545
+ }
546
+ return true;
547
+ }).map((edge) => {
548
+ const isMarriage = edge.relationship === "marriage" || edge.relationship === "divorced";
549
+ const isDivorced = edge.relationship === "divorced";
550
+ const isConsanguineous = edge.relationship === "consanguineous";
551
+ const edgeColor = getDiagramColorHex(
552
+ edge.color || (isMarriage ? "#374151" : "gray")
553
+ );
554
+ const edgeStyle = {
555
+ stroke: edgeColor,
556
+ strokeWidth: isMarriage ? 3 : edge.strokeWidth || 2,
557
+ strokeDasharray: isDivorced ? "6,3" : isConsanguineous ? "2,2" : edge.lineStyle === "dotted" ? "2,5" : edge.lineStyle === "dashed" || edge.dashed ? "7,5" : "none"
558
+ };
559
+ const marker = edge.marker ?? (edge.arrow === false || isMarriage ? "none" : "end");
560
+ const showStartMarker = !hideArrows && marker !== "none" && (marker === "start" || marker === "both");
561
+ const showEndMarker = !hideArrows && marker !== "none" && (marker === "end" || marker === "both");
562
+ const markerDefinition = {
563
+ type: MarkerType.ArrowClosed,
564
+ width: isPedigree ? 14 : 20,
565
+ height: isPedigree ? 14 : 20,
566
+ color: edgeColor
567
+ };
568
+ return {
569
+ id: uniqueEdgeId(edge.id),
570
+ source: edge.source,
571
+ target: edge.target,
572
+ sourceHandle: "output",
573
+ targetHandle: "input",
574
+ type: isPedigree && isMarriage ? "straight" : edge.type === "straight" || edge.type === "step" || edge.type === "smoothstep" ? edge.type : "default",
575
+ animated: edge.animated || false,
576
+ markerStart: showStartMarker ? markerDefinition : void 0,
577
+ markerEnd: showEndMarker ? markerDefinition : void 0,
578
+ style: edgeStyle,
579
+ label: showLabels && !isPedigree ? edge.label : void 0,
580
+ labelStyle: {
581
+ fontSize: 12,
582
+ fontWeight: 500,
583
+ fill: edgeColor
584
+ },
585
+ labelBgStyle: { fill: "#ffffff", fillOpacity: 0.8, rx: 4, ry: 4 },
586
+ data: {
587
+ lineStyle: edge.lineStyle ?? (edge.dashed ? "dashed" : "solid"),
588
+ color: edge.color ?? "gray",
589
+ strokeWidth: edge.strokeWidth ?? 2,
590
+ marker,
591
+ arrow: marker !== "none",
592
+ edgeType: edge.type ?? "bezier"
593
+ }
594
+ };
595
+ });
596
+ }
597
+ const DiagramFlow = ({
598
+ diagram,
599
+ workspace = false,
600
+ showMiniMap,
601
+ setShowMiniMap,
602
+ backgroundVariant,
603
+ setBackgroundVariant,
604
+ onExportImage,
605
+ onNodeClick,
606
+ onSelectionChange,
607
+ editing = false,
608
+ onDiagramChange
609
+ }) => {
610
+ const {
611
+ setViewport,
612
+ getNodes,
613
+ getEdges,
614
+ getNodesBounds,
615
+ screenToFlowPosition
616
+ } = useReactFlow();
617
+ const nodesInitialized = useNodesInitialized();
618
+ const hasAutoLayoutApplied = useRef(false);
619
+ const autoLayoutFrameRef = useRef(null);
620
+ const canvasPresentation = useCanvasPresentation();
621
+ const canvasFlow = canvasPresentation ? preferredFlowDirection(canvasPresentation) : null;
622
+ const personArranged = useRef(false);
623
+ const lastCanvasFlow = useRef(canvasFlow);
624
+ const initialNodes = useMemo(
625
+ () => buildReactFlowNodes(diagram, editing),
626
+ [diagram, editing]
627
+ );
628
+ const initialEdges = useMemo(() => buildReactFlowEdges(diagram), [diagram]);
629
+ const [nodes, setNodes] = useNodesState(initialNodes);
630
+ const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
631
+ useEffect(() => {
632
+ setNodes(buildReactFlowNodes(diagram, editing));
633
+ setEdges(buildReactFlowEdges(diagram));
634
+ }, [diagram, editing, setNodes, setEdges]);
635
+ const [selectedNodeId, setSelectedNodeId] = useState(null);
636
+ const [selectedEdgeId, setSelectedEdgeId] = useState(null);
637
+ const commit = useCallback(
638
+ (rfNodes, rfEdges, layoutOverride) => {
639
+ if (!onDiagramChange) return;
640
+ const priorNodes = new Map(diagram.nodes.map((n) => [n.id, n]));
641
+ const priorEdges = new Map(diagram.edges.map((e) => [e.id, e]));
642
+ const nodes2 = rfNodes.map((rf) => {
643
+ const data = rf.data;
644
+ const isGroup = data.isGroup === true;
645
+ return {
646
+ ...priorNodes.get(rf.id) ?? { id: rf.id, label: rf.id },
647
+ id: rf.id,
648
+ label: typeof data.label === "string" ? data.label : rf.id,
649
+ description: typeof data.description === "string" && data.description !== "" ? data.description : void 0,
650
+ nodeType: typeof data.nodeType === "string" ? data.nodeType : void 0,
651
+ color: typeof data.color === "string" ? data.color : void 0,
652
+ icon: typeof data.icon === "string" ? data.icon : void 0,
653
+ shape: data.shape === "rectangle" || data.shape === "pill" || data.shape === "circle" || data.shape === "diamond" || data.shape === "hexagon" ? data.shape : "rounded",
654
+ borderStyle: data.borderStyle === "dashed" || data.borderStyle === "dotted" ? data.borderStyle : "solid",
655
+ textAlign: data.textAlign === "center" ? "center" : "left",
656
+ isGroup,
657
+ parentId: rf.parentId,
658
+ width: isGroup ? rf.measured?.width ?? rf.width ?? 420 : rf.width ?? priorNodes.get(rf.id)?.width,
659
+ height: isGroup ? rf.measured?.height ?? rf.height ?? 260 : rf.height ?? priorNodes.get(rf.id)?.height,
660
+ groupStyle: data.groupStyle === "solid" || data.groupStyle === "dashed" || data.groupStyle === "dotted" ? data.groupStyle : void 0,
661
+ position: { x: rf.position.x, y: rf.position.y }
662
+ };
663
+ });
664
+ const edges2 = rfEdges.map((rf) => {
665
+ const data = rf.data;
666
+ return {
667
+ ...priorEdges.get(rf.id) ?? {
668
+ id: rf.id,
669
+ source: rf.source,
670
+ target: rf.target
671
+ },
672
+ id: rf.id,
673
+ source: rf.source,
674
+ target: rf.target,
675
+ label: typeof rf.label === "string" && rf.label !== "" ? rf.label : void 0,
676
+ type: data?.edgeType === "straight" || data?.edgeType === "step" || data?.edgeType === "smoothstep" ? data.edgeType : "bezier",
677
+ lineStyle: data?.lineStyle === "dashed" || data?.lineStyle === "dotted" ? data.lineStyle : "solid",
678
+ dashed: data?.lineStyle === "dashed",
679
+ animated: rf.animated === true,
680
+ color: typeof data?.color === "string" ? data.color : "gray",
681
+ strokeWidth: typeof data?.strokeWidth === "number" ? data.strokeWidth : 2,
682
+ marker: data?.marker === "none" || data?.marker === "start" || data?.marker === "both" ? data.marker : "end",
683
+ arrow: data?.marker !== "none" && data?.arrow !== false
684
+ };
685
+ });
686
+ onDiagramChange(
687
+ materializeDiagramDefaults({
688
+ ...diagram,
689
+ nodes: nodes2,
690
+ edges: edges2,
691
+ layout: layoutOverride ? { ...diagram.layout, ...layoutOverride } : diagram.layout
692
+ })
693
+ );
694
+ },
695
+ [diagram, onDiagramChange]
696
+ );
697
+ const onConnect = useCallback(
698
+ (params) => {
699
+ const next = addEdge(
700
+ {
701
+ ...params,
702
+ id: `e-${crypto.randomUUID().slice(0, 8)}`,
703
+ type: "default",
704
+ markerEnd: {
705
+ type: MarkerType.ArrowClosed,
706
+ color: getDiagramColorHex("gray")
707
+ },
708
+ style: { stroke: getDiagramColorHex("gray"), strokeWidth: 2 },
709
+ data: {
710
+ lineStyle: "solid",
711
+ marker: "end",
712
+ color: "gray",
713
+ strokeWidth: 2,
714
+ edgeType: "bezier"
715
+ }
716
+ },
717
+ getEdges()
718
+ );
719
+ setEdges(next);
720
+ commit(getNodes(), next);
721
+ },
722
+ [setEdges, commit, getNodes, getEdges]
723
+ );
724
+ const onReconnect = useCallback(
725
+ (oldEdge, connection) => {
726
+ const next = reconnectEdge(oldEdge, connection, getEdges());
727
+ setEdges(next);
728
+ commit(getNodes(), next);
729
+ },
730
+ [commit, getEdges, getNodes, setEdges]
731
+ );
732
+ const addBox = useCallback(() => {
733
+ const id = `n-${crypto.randomUUID().slice(0, 8)}`;
734
+ const existing = getNodes();
735
+ const selectedGroup = existing.find(
736
+ (node) => node.id === selectedNodeId && node.data.isGroup === true
737
+ );
738
+ const viewportCenter = screenToFlowPosition({
739
+ x: window.innerWidth * 0.58,
740
+ y: window.innerHeight * 0.42
741
+ });
742
+ const newNode = {
743
+ id,
744
+ type: getReactFlowNodeType(diagram.type, { id, label: "New box" }),
745
+ position: selectedGroup ? { x: 28, y: 72 } : viewportCenter,
746
+ data: { label: "New box", diagramType: diagram.type },
747
+ parentId: selectedGroup?.id,
748
+ extent: selectedGroup ? "parent" : void 0,
749
+ expandParent: Boolean(selectedGroup)
750
+ };
751
+ const next = [...existing, newNode];
752
+ setNodes(next);
753
+ commit(next, getEdges());
754
+ setSelectedNodeId(id);
755
+ setSelectedEdgeId(null);
756
+ onSelectionChange?.({ kind: "box", id });
757
+ }, [
758
+ getNodes,
759
+ getEdges,
760
+ setNodes,
761
+ commit,
762
+ diagram.type,
763
+ selectedNodeId,
764
+ onSelectionChange,
765
+ screenToFlowPosition
766
+ ]);
767
+ const addSection = useCallback(() => {
768
+ const id = `g-${crypto.randomUUID().slice(0, 8)}`;
769
+ const existing = getNodes();
770
+ const viewportCenter = screenToFlowPosition({
771
+ x: window.innerWidth * 0.55,
772
+ y: window.innerHeight * 0.38
773
+ });
774
+ const section = {
775
+ id,
776
+ type: "group",
777
+ position: viewportCenter,
778
+ data: {
779
+ label: "New section",
780
+ isGroup: true,
781
+ groupStyle: "dashed",
782
+ editing: true
783
+ },
784
+ style: { width: 420, height: 260 }
785
+ };
786
+ const next = [section, ...existing];
787
+ setNodes(next);
788
+ commit(next, getEdges());
789
+ setSelectedNodeId(id);
790
+ setSelectedEdgeId(null);
791
+ onSelectionChange?.({ kind: "section", id });
792
+ }, [
793
+ getNodes,
794
+ getEdges,
795
+ setNodes,
796
+ commit,
797
+ onSelectionChange,
798
+ screenToFlowPosition
799
+ ]);
800
+ const patchSelectedNode = useCallback(
801
+ (patch) => {
802
+ if (!selectedNodeId) return;
803
+ const next = getNodes().map(
804
+ (node) => node.id === selectedNodeId ? { ...node, data: { ...node.data, ...patch } } : node
805
+ );
806
+ setNodes(next);
807
+ commit(next, getEdges());
808
+ },
809
+ [selectedNodeId, setNodes, getNodes, getEdges, commit]
810
+ );
811
+ const deleteSelectedNode = useCallback(() => {
812
+ if (!selectedNodeId) return;
813
+ const currentNodes = getNodes();
814
+ const selected = currentNodes.find((node) => node.id === selectedNodeId);
815
+ const selectedIsGroup = selected?.data.isGroup === true;
816
+ const nextNodes = currentNodes.filter((node) => node.id !== selectedNodeId).map((node) => {
817
+ if (!selectedIsGroup || node.parentId !== selectedNodeId || !selected)
818
+ return node;
819
+ return {
820
+ ...node,
821
+ parentId: void 0,
822
+ extent: void 0,
823
+ expandParent: false,
824
+ position: {
825
+ x: selected.position.x + node.position.x,
826
+ y: selected.position.y + node.position.y
827
+ }
828
+ };
829
+ });
830
+ const nextEdges = selectedIsGroup ? getEdges() : getEdges().filter(
831
+ (edge) => edge.source !== selectedNodeId && edge.target !== selectedNodeId
832
+ );
833
+ setNodes(nextNodes);
834
+ setEdges(nextEdges);
835
+ setSelectedNodeId(null);
836
+ commit(nextNodes, nextEdges);
837
+ onSelectionChange?.({ kind: null, id: null });
838
+ }, [
839
+ selectedNodeId,
840
+ getNodes,
841
+ getEdges,
842
+ setNodes,
843
+ setEdges,
844
+ commit,
845
+ onSelectionChange
846
+ ]);
847
+ const moveSelectedBoxToSection = useCallback(
848
+ (parentId) => {
849
+ if (!selectedNodeId) return;
850
+ const current = getNodes();
851
+ const selected = current.find((node) => node.id === selectedNodeId);
852
+ if (!selected || selected.data.isGroup === true) return;
853
+ const oldParent = selected.parentId ? current.find((node) => node.id === selected.parentId) : void 0;
854
+ const newParent = parentId ? current.find(
855
+ (node) => node.id === parentId && node.data.isGroup === true
856
+ ) : void 0;
857
+ if (parentId && !newParent)
858
+ throw new Error(`Section ${parentId} is not on this map.`);
859
+ const absolute = oldParent ? {
860
+ x: oldParent.position.x + selected.position.x,
861
+ y: oldParent.position.y + selected.position.y
862
+ } : selected.position;
863
+ const position = newParent ? {
864
+ x: Math.max(24, absolute.x - newParent.position.x),
865
+ y: Math.max(64, absolute.y - newParent.position.y)
866
+ } : absolute;
867
+ const next = current.map(
868
+ (node) => node.id === selectedNodeId ? {
869
+ ...node,
870
+ parentId: newParent?.id,
871
+ extent: newParent ? "parent" : void 0,
872
+ expandParent: Boolean(newParent),
873
+ position
874
+ } : node
875
+ );
876
+ setNodes(next);
877
+ commit(next, getEdges());
878
+ },
879
+ [selectedNodeId, setNodes, getNodes, getEdges, commit]
880
+ );
881
+ const patchSelectedEdge = useCallback(
882
+ (patch) => {
883
+ if (!selectedEdgeId) return;
884
+ const next = getEdges().map((edge) => {
885
+ if (edge.id !== selectedEdgeId) return edge;
886
+ const data = {
887
+ ...edge.data,
888
+ ...patch.lineStyle ? { lineStyle: patch.lineStyle } : {},
889
+ ...patch.edgeType ? { edgeType: patch.edgeType } : {},
890
+ ...patch.color ? { color: patch.color } : {},
891
+ ...patch.strokeWidth !== void 0 ? { strokeWidth: patch.strokeWidth } : {},
892
+ ...patch.marker ? { marker: patch.marker } : {}
893
+ };
894
+ const lineStyle = data.lineStyle === "dashed" || data.lineStyle === "dotted" ? data.lineStyle : "solid";
895
+ const marker = data.marker === "none" || data.marker === "start" || data.marker === "both" ? data.marker : "end";
896
+ const color = getDiagramColorHex(data.color);
897
+ const markerDefinition = {
898
+ type: MarkerType.ArrowClosed,
899
+ color
900
+ };
901
+ return {
902
+ ...edge,
903
+ ...patch.label !== void 0 ? { label: patch.label } : {},
904
+ ...patch.edgeType ? {
905
+ type: patch.edgeType === "bezier" ? "default" : patch.edgeType
906
+ } : {},
907
+ ...patch.animated !== void 0 ? { animated: patch.animated } : {},
908
+ data,
909
+ markerStart: marker === "start" || marker === "both" ? markerDefinition : void 0,
910
+ markerEnd: marker === "end" || marker === "both" ? markerDefinition : void 0,
911
+ style: {
912
+ ...edge.style,
913
+ stroke: color,
914
+ strokeWidth: typeof data.strokeWidth === "number" ? data.strokeWidth : 2,
915
+ strokeDasharray: lineStyle === "dotted" ? "2,5" : lineStyle === "dashed" ? "7,5" : "none"
916
+ }
917
+ };
918
+ });
919
+ setEdges(next);
920
+ commit(getNodes(), next);
921
+ },
922
+ [selectedEdgeId, setEdges, getNodes, getEdges, commit]
923
+ );
924
+ const deleteSelectedEdge = useCallback(() => {
925
+ if (!selectedEdgeId) return;
926
+ const nextEdges = getEdges().filter((e) => e.id !== selectedEdgeId);
927
+ setEdges(nextEdges);
928
+ setSelectedEdgeId(null);
929
+ commit(getNodes(), nextEdges);
930
+ onSelectionChange?.({ kind: null, id: null });
931
+ }, [selectedEdgeId, getEdges, setEdges, getNodes, commit, onSelectionChange]);
932
+ const handleEditNodeClick = useCallback(
933
+ (_e, node) => {
934
+ setSelectedEdgeId(null);
935
+ setSelectedNodeId(node.id);
936
+ onSelectionChange?.({
937
+ kind: node.data.isGroup === true ? "section" : "box",
938
+ id: node.id
939
+ });
940
+ },
941
+ [onSelectionChange]
942
+ );
943
+ const handleEditNodeContextMenu = useCallback(
944
+ (_e, node) => {
945
+ setSelectedEdgeId(null);
946
+ setSelectedNodeId(node.id);
947
+ onSelectionChange?.({
948
+ kind: node.data.isGroup === true ? "section" : "box",
949
+ id: node.id
950
+ });
951
+ },
952
+ [onSelectionChange]
953
+ );
954
+ const handleEditEdgeClick = useCallback(
955
+ (_e, edge) => {
956
+ setSelectedNodeId(null);
957
+ setSelectedEdgeId(edge.id);
958
+ onSelectionChange?.({ kind: "arrow", id: edge.id });
959
+ },
960
+ [onSelectionChange]
961
+ );
962
+ const handlePaneClick = useCallback(() => {
963
+ setSelectedNodeId(null);
964
+ setSelectedEdgeId(null);
965
+ onSelectionChange?.({ kind: null, id: null });
966
+ }, [onSelectionChange]);
967
+ const handleNodeDragStop = useCallback(() => {
968
+ commit(getNodes(), getEdges());
969
+ }, [commit, getNodes, getEdges]);
970
+ const selectedNode = editing ? nodes.find((n) => n.id === selectedNodeId) : void 0;
971
+ const selectedEdge = editing ? edges.find((e) => e.id === selectedEdgeId) : void 0;
972
+ const selectedIsSection = selectedNode?.data.isGroup === true;
973
+ const selectedIconName = normalizeDiagramIconName(
974
+ typeof selectedNode?.data.icon === "string" ? selectedNode.data.icon : "none"
975
+ );
976
+ const sections = editing ? nodes.filter((node) => node.data.isGroup === true) : [];
977
+ const patchRenderHints = useCallback(
978
+ (patch) => {
979
+ if (!onDiagramChange) return;
980
+ onDiagramChange(
981
+ materializeDiagramDefaults({
982
+ ...diagram,
983
+ renderHints: { ...diagram.renderHints, ...patch }
984
+ })
985
+ );
986
+ },
987
+ [diagram, onDiagramChange]
988
+ );
989
+ const patchLayout = useCallback(
990
+ (patch) => {
991
+ if (!onDiagramChange) return;
992
+ onDiagramChange(
993
+ materializeDiagramDefaults({
994
+ ...diagram,
995
+ layout: { ...diagram.layout, ...patch }
996
+ })
997
+ );
998
+ },
999
+ [diagram, onDiagramChange]
1000
+ );
1001
+ const chooseBackground = useCallback(
1002
+ (variant) => {
1003
+ setBackgroundVariant(variant);
1004
+ patchRenderHints({
1005
+ background: variant === BackgroundVariant.Lines ? "lines" : variant === BackgroundVariant.Cross ? "cross" : "dots"
1006
+ });
1007
+ },
1008
+ [patchRenderHints, setBackgroundVariant]
1009
+ );
1010
+ const chooseMiniMap = useCallback(
1011
+ (visible) => {
1012
+ setShowMiniMap(visible);
1013
+ patchRenderHints({ showMiniMap: visible });
1014
+ },
1015
+ [patchRenderHints, setShowMiniMap]
1016
+ );
1017
+ useEffect(() => {
1018
+ setNodes(
1019
+ (current) => current.map(
1020
+ (node) => node.data.isGroup === true ? { ...node, data: { ...node.data, editing } } : node
1021
+ )
1022
+ );
1023
+ }, [editing, setNodes]);
1024
+ const handleNodesChange = useCallback(
1025
+ (changes) => {
1026
+ const next = applyNodeChanges(changes, getNodes());
1027
+ setNodes(next);
1028
+ if (editing && changes.some(
1029
+ (change) => change.type === "dimensions" && change.resizing === false
1030
+ )) {
1031
+ commit(next, getEdges());
1032
+ }
1033
+ },
1034
+ [setNodes, editing, commit, getNodes, getEdges]
1035
+ );
1036
+ const handleNodeClick = useCallback(
1037
+ (_e, rfNode) => {
1038
+ if (!onNodeClick) return;
1039
+ const original = diagram.nodes.find((n) => n.id === rfNode.id);
1040
+ if (original) onNodeClick(original);
1041
+ },
1042
+ [onNodeClick, diagram.nodes]
1043
+ );
1044
+ const exportImage = useCallback(() => {
1045
+ const currentNodes = getNodes();
1046
+ if (!currentNodes.length) {
1047
+ onExportImage();
1048
+ return;
1049
+ }
1050
+ const nodesBounds = getNodesBounds(currentNodes);
1051
+ const imageWidth = 1200;
1052
+ const imageHeight = 800;
1053
+ const viewport = getViewportForBounds(
1054
+ nodesBounds,
1055
+ imageWidth,
1056
+ imageHeight,
1057
+ 0.1,
1058
+ 2,
1059
+ 0.1
1060
+ );
1061
+ const reactFlowEl = document.querySelector(
1062
+ ".react-flow"
1063
+ );
1064
+ if (!reactFlowEl) {
1065
+ onExportImage();
1066
+ return;
1067
+ }
1068
+ const isDark = document.documentElement.classList.contains("dark") || window.matchMedia("(prefers-color-scheme: dark)").matches;
1069
+ const bgColor = isDark ? "#111827" : "#ffffff";
1070
+ const exportContainer = document.createElement("div");
1071
+ exportContainer.style.cssText = `position:absolute;top:-9999px;left:-9999px;width:${imageWidth}px;height:${imageHeight}px;background:${bgColor}`;
1072
+ if (isDark) exportContainer.classList.add("dark");
1073
+ const cloned = reactFlowEl.cloneNode(true);
1074
+ if (isDark) cloned.classList.add("dark");
1075
+ cloned.style.cssText = `width:${imageWidth}px;height:${imageHeight}px;position:relative;overflow:hidden`;
1076
+ const clonedViewport = cloned.querySelector(
1077
+ ".react-flow__viewport"
1078
+ );
1079
+ if (clonedViewport) {
1080
+ clonedViewport.style.transform = `translate(${viewport.x}px, ${viewport.y}px) scale(${viewport.zoom})`;
1081
+ }
1082
+ exportContainer.appendChild(cloned);
1083
+ document.body.appendChild(exportContainer);
1084
+ import("html2canvas").then((mod) => {
1085
+ const restore = patchComputedStyleForCapture(isDark);
1086
+ return mod.default(exportContainer, {
1087
+ backgroundColor: bgColor,
1088
+ scale: 2,
1089
+ useCORS: true,
1090
+ allowTaint: true,
1091
+ width: imageWidth,
1092
+ height: imageHeight,
1093
+ ignoreElements: (el) => el.classList.contains("react-flow__controls") || el.classList.contains("react-flow__minimap") || el.classList.contains("react-flow__panel")
1094
+ }).finally(restore);
1095
+ }).then((canvas) => {
1096
+ const a = document.createElement("a");
1097
+ a.download = `${diagram.title.replace(/[^a-z0-9]/gi, "_").toLowerCase()}_diagram${isDark ? "_dark" : "_light"}.png`;
1098
+ a.href = canvas.toDataURL("image/png");
1099
+ a.click();
1100
+ }).catch((err) => console.warn("Diagram export failed:", err)).finally(() => document.body.removeChild(exportContainer));
1101
+ }, [getNodes, diagram.title, onExportImage]);
1102
+ const measuredWidth = useStore((s) => s.width);
1103
+ const measuredHeight = useStore((s) => s.height);
1104
+ const fitPadding = workspace ? 0.12 : 0.2;
1105
+ const fitMinZoom = workspace ? 0.05 : 0.5;
1106
+ const lastFitKey = useRef(null);
1107
+ const fitViewAfterLayout = useCallback(() => {
1108
+ lastFitKey.current = null;
1109
+ }, []);
1110
+ useEffect(() => {
1111
+ if (editing) return void 0;
1112
+ if (!nodesInitialized || !measuredWidth || !measuredHeight) return void 0;
1113
+ const laidOut = getNodes();
1114
+ if (!laidOut.length) return void 0;
1115
+ const bounds = getNodesBounds(laidOut);
1116
+ if (bounds.width <= 0 || bounds.height <= 0) return void 0;
1117
+ const key = [
1118
+ Math.round(measuredWidth),
1119
+ Math.round(measuredHeight),
1120
+ Math.round(bounds.x),
1121
+ Math.round(bounds.y),
1122
+ Math.round(bounds.width),
1123
+ Math.round(bounds.height)
1124
+ ].join(":");
1125
+ if (lastFitKey.current === key) return void 0;
1126
+ lastFitKey.current = key;
1127
+ const frame = requestAnimationFrame(() => {
1128
+ const contained = getViewportForBounds(
1129
+ bounds,
1130
+ measuredWidth,
1131
+ measuredHeight,
1132
+ fitMinZoom,
1133
+ 2,
1134
+ fitPadding
1135
+ );
1136
+ let viewport = contained;
1137
+ const firstRank = firstRankBounds(
1138
+ laidOut.flatMap((n) => {
1139
+ const w = n.measured?.width;
1140
+ const h = n.measured?.height;
1141
+ return !n.parentId && w && h ? [{ x: n.position.x, y: n.position.y, width: w, height: h }] : [];
1142
+ })
1143
+ );
1144
+ const portraitFit = portraitWidthFitViewport({
1145
+ presentation: canvasPresentation,
1146
+ bounds,
1147
+ firstRank,
1148
+ width: measuredWidth,
1149
+ height: measuredHeight,
1150
+ minZoom: fitMinZoom,
1151
+ maxZoom: 2,
1152
+ padding: fitPadding,
1153
+ containedZoom: contained.zoom
1154
+ });
1155
+ const isNarrowPhoneViewport = measuredWidth > 0 && measuredWidth < 640;
1156
+ if (portraitFit) {
1157
+ viewport = portraitFit;
1158
+ } else if (isNarrowPhoneViewport && !diagramScrollPans(canvasPresentation)) {
1159
+ const heightZoom = Math.min(
1160
+ 2,
1161
+ Math.max(
1162
+ fitMinZoom,
1163
+ measuredHeight * (1 - fitPadding * 2) / bounds.height
1164
+ )
1165
+ );
1166
+ if (heightZoom > contained.zoom) {
1167
+ const zoom = Math.min(heightZoom, contained.zoom * 4, 2);
1168
+ viewport = {
1169
+ zoom,
1170
+ x: measuredWidth / 2 - (bounds.x + bounds.width / 2) * zoom,
1171
+ y: measuredHeight / 2 - (bounds.y + bounds.height / 2) * zoom
1172
+ };
1173
+ }
1174
+ }
1175
+ setViewport(viewport, { duration: 300 });
1176
+ });
1177
+ return () => cancelAnimationFrame(frame);
1178
+ }, [
1179
+ editing,
1180
+ nodesInitialized,
1181
+ measuredWidth,
1182
+ measuredHeight,
1183
+ fitMinZoom,
1184
+ fitPadding,
1185
+ nodes,
1186
+ getNodes,
1187
+ setViewport,
1188
+ canvasPresentation
1189
+ ]);
1190
+ const applyDirectedLayout = useCallback(
1191
+ (direction) => {
1192
+ const currentNodes = getNodes();
1193
+ const currentEdges = getEdges();
1194
+ if (currentNodes.length === 0) return;
1195
+ let result;
1196
+ if (diagram.type === "pedigree" && direction === "TB") {
1197
+ result = getPedigreeLayout(currentNodes, currentEdges);
1198
+ } else if (diagram.type === "orgchart") {
1199
+ const opts = getLayoutOptionsForDiagramType(
1200
+ diagram.type,
1201
+ diagram.nodes.length,
1202
+ direction
1203
+ );
1204
+ result = getOrgChartLayout(currentNodes, currentEdges, opts);
1205
+ if (result.edges) setEdges(result.edges);
1206
+ } else {
1207
+ const opts = getLayoutOptionsForDiagramType(
1208
+ diagram.type,
1209
+ diagram.nodes.length,
1210
+ direction
1211
+ );
1212
+ result = getLayoutedElements(currentNodes, currentEdges, opts);
1213
+ }
1214
+ setNodes(result.nodes);
1215
+ commit(result.nodes, result.edges ?? currentEdges, {
1216
+ algorithm: diagram.type === "pedigree" && direction === "TB" ? "pedigree" : "dagre",
1217
+ direction
1218
+ });
1219
+ fitViewAfterLayout();
1220
+ hasAutoLayoutApplied.current = true;
1221
+ },
1222
+ [
1223
+ commit,
1224
+ getNodes,
1225
+ getEdges,
1226
+ diagram.type,
1227
+ diagram.nodes.length,
1228
+ setNodes,
1229
+ setEdges,
1230
+ fitViewAfterLayout
1231
+ ]
1232
+ );
1233
+ const applyGridLayout = useCallback(() => {
1234
+ const currentEdges = getEdges();
1235
+ const { nodes: laid } = getGridLayout(getNodes(), currentEdges);
1236
+ setNodes(laid);
1237
+ commit(laid, currentEdges, { algorithm: "grid" });
1238
+ fitViewAfterLayout();
1239
+ hasAutoLayoutApplied.current = true;
1240
+ }, [getNodes, getEdges, setNodes, commit, fitViewAfterLayout]);
1241
+ const applyRadialLayout = useCallback(() => {
1242
+ const { nodes: laid } = getRadialLayout(getNodes(), getEdges());
1243
+ setNodes(laid);
1244
+ commit(laid, getEdges(), { algorithm: "radial" });
1245
+ fitViewAfterLayout();
1246
+ hasAutoLayoutApplied.current = true;
1247
+ }, [getNodes, getEdges, setNodes, commit, fitViewAfterLayout]);
1248
+ const applyAutoLayout = useCallback(() => {
1249
+ if (diagram.layout?.algorithm === "radial") {
1250
+ applyRadialLayout();
1251
+ return;
1252
+ }
1253
+ if (diagram.layout?.algorithm === "grid") {
1254
+ applyGridLayout();
1255
+ return;
1256
+ }
1257
+ applyDirectedLayout(
1258
+ diagramDirectionForFlow(canvasFlow, diagram.layout?.direction, diagram.type)
1259
+ );
1260
+ }, [
1261
+ applyDirectedLayout,
1262
+ applyGridLayout,
1263
+ applyRadialLayout,
1264
+ diagram.layout?.algorithm,
1265
+ diagram.layout?.direction,
1266
+ diagram.type,
1267
+ canvasFlow
1268
+ ]);
1269
+ const arrangeByPerson = useCallback((arrange) => {
1270
+ personArranged.current = true;
1271
+ arrange();
1272
+ }, []);
1273
+ useEffect(() => {
1274
+ const previousFlow = lastCanvasFlow.current;
1275
+ lastCanvasFlow.current = canvasFlow;
1276
+ if (!shouldRelayoutOnFlowChange({
1277
+ previousFlow,
1278
+ flow: canvasFlow,
1279
+ autoLaidOut: hasAutoLayoutApplied.current,
1280
+ personArranged: personArranged.current,
1281
+ authoring: Boolean(onDiagramChange)
1282
+ })) {
1283
+ return;
1284
+ }
1285
+ applyAutoLayout();
1286
+ }, [canvasFlow, applyAutoLayout, onDiagramChange]);
1287
+ const resetLayout = useCallback(() => {
1288
+ setNodes(buildReactFlowNodes(diagram, editing));
1289
+ setEdges(buildReactFlowEdges(diagram));
1290
+ fitViewAfterLayout();
1291
+ hasAutoLayoutApplied.current = true;
1292
+ }, [diagram, editing, setNodes, setEdges, fitViewAfterLayout]);
1293
+ useEffect(() => {
1294
+ if (onDiagramChange) return;
1295
+ hasAutoLayoutApplied.current = false;
1296
+ }, [diagram, onDiagramChange]);
1297
+ useEffect(() => {
1298
+ if (!nodesInitialized || hasAutoLayoutApplied.current) return void 0;
1299
+ if (getNodes().length <= 1) return void 0;
1300
+ if (onDiagramChange && diagram.nodes.length > 0 && diagram.nodes.every((n) => n.position)) {
1301
+ hasAutoLayoutApplied.current = true;
1302
+ fitViewAfterLayout();
1303
+ return () => {
1304
+ if (autoLayoutFrameRef.current !== null) {
1305
+ cancelAnimationFrame(autoLayoutFrameRef.current);
1306
+ autoLayoutFrameRef.current = null;
1307
+ }
1308
+ };
1309
+ }
1310
+ autoLayoutFrameRef.current = requestAnimationFrame(() => {
1311
+ autoLayoutFrameRef.current = requestAnimationFrame(() => {
1312
+ if (hasAutoLayoutApplied.current) return;
1313
+ applyAutoLayout();
1314
+ });
1315
+ });
1316
+ return () => {
1317
+ if (autoLayoutFrameRef.current !== null) {
1318
+ cancelAnimationFrame(autoLayoutFrameRef.current);
1319
+ autoLayoutFrameRef.current = null;
1320
+ }
1321
+ };
1322
+ }, [
1323
+ nodesInitialized,
1324
+ applyAutoLayout,
1325
+ fitViewAfterLayout,
1326
+ getNodes,
1327
+ diagram,
1328
+ onDiagramChange
1329
+ ]);
1330
+ return /* @__PURE__ */ jsxs(
1331
+ ReactFlow,
1332
+ {
1333
+ nodes,
1334
+ edges,
1335
+ onNodesChange: handleNodesChange,
1336
+ onEdgesChange,
1337
+ onConnect,
1338
+ onReconnect,
1339
+ onNodeClick: editing ? handleEditNodeClick : onNodeClick ? handleNodeClick : void 0,
1340
+ onNodeContextMenu: editing ? handleEditNodeContextMenu : void 0,
1341
+ onEdgeClick: editing ? handleEditEdgeClick : void 0,
1342
+ onPaneClick: editing ? handlePaneClick : void 0,
1343
+ onNodeDragStop: editing ? handleNodeDragStop : void 0,
1344
+ nodeTypes,
1345
+ nodesDraggable: editing,
1346
+ nodesConnectable: editing,
1347
+ edgesReconnectable: editing,
1348
+ snapToGrid: diagram.renderHints?.snapToGrid === true,
1349
+ snapGrid: [20, 20],
1350
+ elementsSelectable: editing || Boolean(onNodeClick),
1351
+ deleteKeyCode: null,
1352
+ minZoom: workspace ? 0.05 : 0.5,
1353
+ maxZoom: 2,
1354
+ fitView: false,
1355
+ panOnScroll: !editing && diagramScrollPans(canvasPresentation),
1356
+ proOptions: { hideAttribution: true },
1357
+ className: `bg-gray-50 dark:bg-gray-900 ${workspace && editing ? "!w-[calc(100%-min(320px,48vw))] !overflow-visible" : ""} ${onNodeClick || editing ? "[&_.react-flow__node]:cursor-pointer" : ""}`,
1358
+ children: [
1359
+ /* @__PURE__ */ jsx(
1360
+ Background,
1361
+ {
1362
+ variant: backgroundVariant,
1363
+ gap: 20,
1364
+ size: 1,
1365
+ className: "bg-gray-50 dark:bg-gray-900"
1366
+ }
1367
+ ),
1368
+ diagram.renderHints?.showControls !== false && /* @__PURE__ */ jsx(
1369
+ Controls,
1370
+ {
1371
+ className: "bg-textured border-border rounded-lg shadow-lg",
1372
+ showInteractive: false
1373
+ }
1374
+ ),
1375
+ showMiniMap && /* @__PURE__ */ jsx(
1376
+ MiniMap,
1377
+ {
1378
+ className: "bg-textured border-border rounded-lg shadow-lg",
1379
+ nodeColor: (node) => {
1380
+ if (typeof node.data.color === "string" && node.data.color !== "auto") {
1381
+ return getDiagramColorHex(node.data.color);
1382
+ }
1383
+ switch (node.data.nodeType) {
1384
+ case "start":
1385
+ return "#10b981";
1386
+ case "end":
1387
+ return "#ef4444";
1388
+ case "decision":
1389
+ return "#f59e0b";
1390
+ case "process":
1391
+ return "#3b82f6";
1392
+ case "data":
1393
+ return "#8b5cf6";
1394
+ default:
1395
+ return "#6b7280";
1396
+ }
1397
+ },
1398
+ maskColor: "rgba(0,0,0,0.1)"
1399
+ }
1400
+ ),
1401
+ editing && /* @__PURE__ */ jsxs(
1402
+ Panel,
1403
+ {
1404
+ position: workspace ? "top-right" : "top-left",
1405
+ className: workspace ? "!m-0 h-full w-[min(320px,48vw)] translate-x-full overflow-y-auto rounded-none border-l border-border/80 bg-card/95 p-4 shadow-[-8px_0_24px_-18px_rgba(15,23,42,0.45)] backdrop-blur-xl" : "max-h-[calc(100%-24px)] w-[286px] overflow-y-auto rounded-xl border border-border/80 bg-card/95 p-3 shadow-xl backdrop-blur",
1406
+ children: [
1407
+ /* @__PURE__ */ jsxs("div", { className: "mb-3 flex items-center gap-2.5", children: [
1408
+ /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-primary/10 p-2 text-primary-ink", children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" }) }),
1409
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
1410
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-foreground", children: "Build your map" }),
1411
+ /* @__PURE__ */ jsxs("div", { className: "mt-0.5 flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [
1412
+ /* @__PURE__ */ jsxs("span", { children: [
1413
+ nodes.filter((node) => node.data.isGroup !== true).length,
1414
+ " ",
1415
+ "boxes"
1416
+ ] }),
1417
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xB7" }),
1418
+ /* @__PURE__ */ jsxs("span", { children: [
1419
+ sections.length,
1420
+ " sections"
1421
+ ] }),
1422
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: "\xB7" }),
1423
+ /* @__PURE__ */ jsxs("span", { children: [
1424
+ edges.length,
1425
+ " arrows"
1426
+ ] })
1427
+ ] })
1428
+ ] })
1429
+ ] }),
1430
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-1.5", children: [
1431
+ /* @__PURE__ */ jsx(Button, { variant: "primary", icon: /* @__PURE__ */ jsx(Plus, {}), onClick: addBox, "aria-label": "Add box", children: "Add box" }),
1432
+ /* @__PURE__ */ jsx(Button, { variant: "outline", icon: /* @__PURE__ */ jsx(Boxes, {}), onClick: addSection, "aria-label": "Add section", children: "Add section" })
1433
+ ] }),
1434
+ !selectedNode && !selectedEdge && /* @__PURE__ */ jsx("p", { className: "mt-2 text-[11px] leading-snug text-muted-foreground", children: "Click anything to shape it. Drag boxes to move them. Draw an arrow by dragging from the small dot on one box to another." }),
1435
+ selectedNode && /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2.5 border-t border-border/70 pt-3", children: [
1436
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground", children: selectedIsSection ? "Section" : "Box" }),
1437
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1438
+ "Name",
1439
+ /* @__PURE__ */ jsx(
1440
+ "input",
1441
+ {
1442
+ value: typeof selectedNode.data.label === "string" ? selectedNode.data.label : "",
1443
+ onChange: (e) => patchSelectedNode({ label: e.target.value }),
1444
+ className: "mt-1 w-full rounded border border-border bg-background px-2 py-1 text-xs text-foreground outline-none focus:border-primary",
1445
+ placeholder: "What is this step?"
1446
+ }
1447
+ )
1448
+ ] }),
1449
+ selectedIsSection ? /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1450
+ "Border",
1451
+ /* @__PURE__ */ jsxs(
1452
+ "select",
1453
+ {
1454
+ value: selectedNode.data.groupStyle === "solid" || selectedNode.data.groupStyle === "dotted" ? selectedNode.data.groupStyle : "dashed",
1455
+ onChange: (event) => patchSelectedNode({
1456
+ groupStyle: event.target.value
1457
+ }),
1458
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1459
+ children: [
1460
+ /* @__PURE__ */ jsx("option", { value: "dashed", children: "Dashed" }),
1461
+ /* @__PURE__ */ jsx("option", { value: "dotted", children: "Dotted" }),
1462
+ /* @__PURE__ */ jsx("option", { value: "solid", children: "Solid" })
1463
+ ]
1464
+ }
1465
+ )
1466
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1467
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1468
+ "Notes",
1469
+ " ",
1470
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "(optional)" }),
1471
+ /* @__PURE__ */ jsx(
1472
+ "textarea",
1473
+ {
1474
+ value: typeof selectedNode.data.description === "string" ? selectedNode.data.description : "",
1475
+ onChange: (event) => patchSelectedNode({ description: event.target.value }),
1476
+ rows: 2,
1477
+ className: "mt-1 w-full resize-none rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1478
+ placeholder: "A short line of detail"
1479
+ }
1480
+ )
1481
+ ] }),
1482
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
1483
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1484
+ "Style",
1485
+ /* @__PURE__ */ jsxs(
1486
+ "select",
1487
+ {
1488
+ value: typeof selectedNode.data.nodeType === "string" ? selectedNode.data.nodeType : "default",
1489
+ onChange: (event) => patchSelectedNode({ nodeType: event.target.value }),
1490
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1491
+ children: [
1492
+ /* @__PURE__ */ jsx("option", { value: "default", children: "Plain" }),
1493
+ /* @__PURE__ */ jsx("option", { value: "start", children: "Start" }),
1494
+ /* @__PURE__ */ jsx("option", { value: "process", children: "Step" }),
1495
+ /* @__PURE__ */ jsx("option", { value: "decision", children: "Decision" }),
1496
+ /* @__PURE__ */ jsx("option", { value: "data", children: "Information" }),
1497
+ /* @__PURE__ */ jsx("option", { value: "end", children: "Finish" })
1498
+ ]
1499
+ }
1500
+ )
1501
+ ] }),
1502
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1503
+ "Section",
1504
+ /* @__PURE__ */ jsxs(
1505
+ "select",
1506
+ {
1507
+ value: selectedNode.parentId ?? "none",
1508
+ onChange: (event) => moveSelectedBoxToSection(
1509
+ event.target.value === "none" ? null : event.target.value
1510
+ ),
1511
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1512
+ children: [
1513
+ /* @__PURE__ */ jsx("option", { value: "none", children: "No section" }),
1514
+ sections.map((section) => /* @__PURE__ */ jsx("option", { value: section.id, children: String(section.data.label ?? "Section") }, section.id))
1515
+ ]
1516
+ }
1517
+ )
1518
+ ] })
1519
+ ] })
1520
+ ] }),
1521
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1522
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-foreground", children: "Color" }),
1523
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
1524
+ DIAGRAM_COLOR_PRESETS.map((preset) => /* @__PURE__ */ jsx(
1525
+ "button",
1526
+ {
1527
+ type: "button",
1528
+ onClick: () => patchSelectedNode({ color: preset.value }),
1529
+ "aria-label": `Use ${preset.label.toLowerCase()}`,
1530
+ "aria-pressed": selectedNode.data.color === preset.value,
1531
+ className: `h-5 w-5 rounded-full border-2 transition-transform hover:scale-110 ${selectedNode.data.color === preset.value ? "border-primary ring-1 ring-primary" : "border-border"}`,
1532
+ style: { backgroundColor: preset.hex }
1533
+ },
1534
+ preset.value
1535
+ )),
1536
+ /* @__PURE__ */ jsxs(
1537
+ "label",
1538
+ {
1539
+ className: "relative h-5 w-5 overflow-hidden rounded-full border border-border",
1540
+ title: "Custom color",
1541
+ children: [
1542
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Custom color" }),
1543
+ /* @__PURE__ */ jsx(
1544
+ "input",
1545
+ {
1546
+ type: "color",
1547
+ "aria-label": "Choose a custom color",
1548
+ value: getDiagramColorHex(selectedNode.data.color),
1549
+ onChange: (event) => patchSelectedNode({ color: event.target.value }),
1550
+ className: "absolute -inset-2 h-9 w-9 cursor-pointer"
1551
+ }
1552
+ )
1553
+ ]
1554
+ }
1555
+ )
1556
+ ] })
1557
+ ] }),
1558
+ !selectedIsSection && /* @__PURE__ */ jsxs(Fragment, { children: [
1559
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1560
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-foreground", children: "Icon" }),
1561
+ /* @__PURE__ */ jsx(
1562
+ IconInputWithValidation,
1563
+ {
1564
+ value: selectedIconName === "none" ? "" : selectedIconName,
1565
+ onChange: (iconName) => patchSelectedNode({
1566
+ icon: iconName.trim() || "none"
1567
+ }),
1568
+ placeholder: "Search or enter an icon",
1569
+ className: "h-8"
1570
+ }
1571
+ )
1572
+ ] }),
1573
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
1574
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1575
+ "Shape",
1576
+ /* @__PURE__ */ jsxs(
1577
+ "select",
1578
+ {
1579
+ value: String(selectedNode.data.shape ?? "rounded"),
1580
+ onChange: (event) => patchSelectedNode({
1581
+ shape: event.target.value
1582
+ }),
1583
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1584
+ children: [
1585
+ /* @__PURE__ */ jsx("option", { value: "rounded", children: "Rounded" }),
1586
+ /* @__PURE__ */ jsx("option", { value: "rectangle", children: "Rectangle" }),
1587
+ /* @__PURE__ */ jsx("option", { value: "pill", children: "Pill" }),
1588
+ /* @__PURE__ */ jsx("option", { value: "circle", children: "Circle" }),
1589
+ /* @__PURE__ */ jsx("option", { value: "diamond", children: "Diamond" }),
1590
+ /* @__PURE__ */ jsx("option", { value: "hexagon", children: "Hexagon" })
1591
+ ]
1592
+ }
1593
+ )
1594
+ ] }),
1595
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1596
+ "Border",
1597
+ /* @__PURE__ */ jsxs(
1598
+ "select",
1599
+ {
1600
+ value: String(selectedNode.data.borderStyle ?? "solid"),
1601
+ onChange: (event) => patchSelectedNode({
1602
+ borderStyle: event.target.value
1603
+ }),
1604
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1605
+ children: [
1606
+ /* @__PURE__ */ jsx("option", { value: "solid", children: "Solid" }),
1607
+ /* @__PURE__ */ jsx("option", { value: "dashed", children: "Dashed" }),
1608
+ /* @__PURE__ */ jsx("option", { value: "dotted", children: "Dotted" })
1609
+ ]
1610
+ }
1611
+ )
1612
+ ] })
1613
+ ] }),
1614
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1615
+ "Text",
1616
+ /* @__PURE__ */ jsxs(
1617
+ "select",
1618
+ {
1619
+ value: String(selectedNode.data.textAlign ?? "left"),
1620
+ onChange: (event) => patchSelectedNode({
1621
+ textAlign: event.target.value
1622
+ }),
1623
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1624
+ children: [
1625
+ /* @__PURE__ */ jsx("option", { value: "left", children: "Left" }),
1626
+ /* @__PURE__ */ jsx("option", { value: "center", children: "Centered" })
1627
+ ]
1628
+ }
1629
+ )
1630
+ ] }),
1631
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: "Drag the selection handles to set an exact box size." })
1632
+ ] }),
1633
+ /* @__PURE__ */ jsx(Button, { variant: "outline", icon: /* @__PURE__ */ jsx(Trash2, {}), onClick: deleteSelectedNode, "aria-label": selectedIsSection ? "Remove section and keep its boxes" : "Remove box", className: "w-full", children: selectedIsSection ? "Remove section (keep boxes)" : "Remove box" })
1634
+ ] }),
1635
+ selectedEdge && /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2.5 border-t border-border/70 pt-3", children: [
1636
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground", children: "Arrow" }),
1637
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1638
+ "Arrow label",
1639
+ /* @__PURE__ */ jsx(
1640
+ "input",
1641
+ {
1642
+ value: typeof selectedEdge.label === "string" ? selectedEdge.label : "",
1643
+ onChange: (event) => patchSelectedEdge({ label: event.target.value }),
1644
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1645
+ placeholder: "e.g. sends to"
1646
+ }
1647
+ )
1648
+ ] }),
1649
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
1650
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1651
+ "Path",
1652
+ /* @__PURE__ */ jsxs(
1653
+ "select",
1654
+ {
1655
+ value: selectedEdge.data?.edgeType === "smoothstep" || selectedEdge.data?.edgeType === "step" || selectedEdge.data?.edgeType === "straight" ? selectedEdge.data.edgeType : "bezier",
1656
+ onChange: (event) => patchSelectedEdge({
1657
+ edgeType: event.target.value
1658
+ }),
1659
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1660
+ children: [
1661
+ /* @__PURE__ */ jsx("option", { value: "bezier", children: "Curved" }),
1662
+ /* @__PURE__ */ jsx("option", { value: "smoothstep", children: "Rounded" }),
1663
+ /* @__PURE__ */ jsx("option", { value: "step", children: "Stepped" }),
1664
+ /* @__PURE__ */ jsx("option", { value: "straight", children: "Straight" })
1665
+ ]
1666
+ }
1667
+ )
1668
+ ] }),
1669
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1670
+ "Line",
1671
+ /* @__PURE__ */ jsxs(
1672
+ "select",
1673
+ {
1674
+ value: selectedEdge.data?.lineStyle === "dashed" || selectedEdge.data?.lineStyle === "dotted" ? selectedEdge.data.lineStyle : "solid",
1675
+ onChange: (event) => patchSelectedEdge({
1676
+ lineStyle: event.target.value
1677
+ }),
1678
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1679
+ children: [
1680
+ /* @__PURE__ */ jsx("option", { value: "solid", children: "Solid" }),
1681
+ /* @__PURE__ */ jsx("option", { value: "dashed", children: "Dashed" }),
1682
+ /* @__PURE__ */ jsx("option", { value: "dotted", children: "Dotted" })
1683
+ ]
1684
+ }
1685
+ )
1686
+ ] })
1687
+ ] }),
1688
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
1689
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1690
+ "Direction",
1691
+ /* @__PURE__ */ jsxs(
1692
+ "select",
1693
+ {
1694
+ value: String(selectedEdge.data?.marker ?? "end"),
1695
+ onChange: (event) => patchSelectedEdge({
1696
+ marker: event.target.value
1697
+ }),
1698
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1699
+ children: [
1700
+ /* @__PURE__ */ jsx("option", { value: "end", children: "Forward" }),
1701
+ /* @__PURE__ */ jsx("option", { value: "start", children: "Backward" }),
1702
+ /* @__PURE__ */ jsx("option", { value: "both", children: "Both ends" }),
1703
+ /* @__PURE__ */ jsx("option", { value: "none", children: "No arrowheads" })
1704
+ ]
1705
+ }
1706
+ )
1707
+ ] }),
1708
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1709
+ "Weight",
1710
+ /* @__PURE__ */ jsxs(
1711
+ "select",
1712
+ {
1713
+ value: String(selectedEdge.data?.strokeWidth ?? 2),
1714
+ onChange: (event) => patchSelectedEdge({
1715
+ strokeWidth: Number(event.target.value)
1716
+ }),
1717
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1718
+ children: [
1719
+ /* @__PURE__ */ jsx("option", { value: "1", children: "Fine" }),
1720
+ /* @__PURE__ */ jsx("option", { value: "2", children: "Regular" }),
1721
+ /* @__PURE__ */ jsx("option", { value: "3", children: "Bold" }),
1722
+ /* @__PURE__ */ jsx("option", { value: "4", children: "Heavy" })
1723
+ ]
1724
+ }
1725
+ )
1726
+ ] })
1727
+ ] }),
1728
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1729
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-medium text-foreground", children: "Color" }),
1730
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
1731
+ DIAGRAM_COLOR_PRESETS.map((preset) => /* @__PURE__ */ jsx(
1732
+ "button",
1733
+ {
1734
+ type: "button",
1735
+ onClick: () => patchSelectedEdge({ color: preset.value }),
1736
+ "aria-label": `Use ${preset.label.toLowerCase()}`,
1737
+ "aria-pressed": selectedEdge.data?.color === preset.value,
1738
+ className: `h-5 w-5 rounded-full border-2 transition-transform hover:scale-110 ${selectedEdge.data?.color === preset.value ? "border-primary ring-1 ring-primary" : "border-border"}`,
1739
+ style: { backgroundColor: preset.hex }
1740
+ },
1741
+ preset.value
1742
+ )),
1743
+ /* @__PURE__ */ jsxs(
1744
+ "label",
1745
+ {
1746
+ className: "relative h-5 w-5 overflow-hidden rounded-full border border-border",
1747
+ title: "Custom color",
1748
+ children: [
1749
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Custom color" }),
1750
+ /* @__PURE__ */ jsx(
1751
+ "input",
1752
+ {
1753
+ type: "color",
1754
+ "aria-label": "Choose a custom arrow color",
1755
+ value: getDiagramColorHex(selectedEdge.data?.color),
1756
+ onChange: (event) => patchSelectedEdge({ color: event.target.value }),
1757
+ className: "absolute -inset-2 h-9 w-9 cursor-pointer"
1758
+ }
1759
+ )
1760
+ ]
1761
+ }
1762
+ )
1763
+ ] })
1764
+ ] }),
1765
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-1.5", children: /* @__PURE__ */ jsx(Button, { variant: "outline", pressed: selectedEdge.animated, onClick: () => patchSelectedEdge({ animated: !selectedEdge.animated }), children: selectedEdge.animated ? "Motion on" : "Motion off" }) }),
1766
+ /* @__PURE__ */ jsx(Button, { variant: "outline", icon: /* @__PURE__ */ jsx(Trash2, {}), onClick: deleteSelectedEdge, "aria-label": "Remove arrow", className: "w-full", children: "Remove arrow" })
1767
+ ] }),
1768
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 space-y-2.5 border-t border-border/70 pt-3", children: [
1769
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground", children: "Map appearance" }),
1770
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
1771
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1772
+ "Background",
1773
+ /* @__PURE__ */ jsxs(
1774
+ "select",
1775
+ {
1776
+ value: diagram.renderHints?.background ?? "dots",
1777
+ onChange: (event) => chooseBackground(
1778
+ event.target.value === "lines" ? BackgroundVariant.Lines : event.target.value === "cross" ? BackgroundVariant.Cross : BackgroundVariant.Dots
1779
+ ),
1780
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1781
+ children: [
1782
+ /* @__PURE__ */ jsx("option", { value: "dots", children: "Dots" }),
1783
+ /* @__PURE__ */ jsx("option", { value: "lines", children: "Lines" }),
1784
+ /* @__PURE__ */ jsx("option", { value: "cross", children: "Crosses" })
1785
+ ]
1786
+ }
1787
+ )
1788
+ ] }),
1789
+ /* @__PURE__ */ jsxs("label", { className: "block text-[11px] font-medium text-foreground", children: [
1790
+ "Flow",
1791
+ /* @__PURE__ */ jsxs(
1792
+ "select",
1793
+ {
1794
+ value: diagram.layout?.direction ?? "TB",
1795
+ onChange: (event) => patchLayout({
1796
+ direction: event.target.value
1797
+ }),
1798
+ className: "mt-1 w-full rounded-md border border-border bg-background px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary",
1799
+ children: [
1800
+ /* @__PURE__ */ jsx("option", { value: "TB", children: "Top to bottom" }),
1801
+ /* @__PURE__ */ jsx("option", { value: "LR", children: "Left to right" }),
1802
+ /* @__PURE__ */ jsx("option", { value: "BT", children: "Bottom to top" }),
1803
+ /* @__PURE__ */ jsx("option", { value: "RL", children: "Right to left" })
1804
+ ]
1805
+ }
1806
+ )
1807
+ ] })
1808
+ ] }),
1809
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-1.5", children: [
1810
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", pressed: showMiniMap, onClick: () => chooseMiniMap(!showMiniMap), children: [
1811
+ "Mini map ",
1812
+ showMiniMap ? "on" : "off"
1813
+ ] }),
1814
+ /* @__PURE__ */ jsxs(
1815
+ "button",
1816
+ {
1817
+ type: "button",
1818
+ onClick: () => patchRenderHints({
1819
+ snapToGrid: diagram.renderHints?.snapToGrid !== true
1820
+ }),
1821
+ "aria-pressed": diagram.renderHints?.snapToGrid === true,
1822
+ className: `rounded-md border px-2 py-1.5 text-[11px] font-medium ${diagram.renderHints?.snapToGrid ? "border-primary/40 bg-primary/10 text-primary-ink" : "border-border text-muted-foreground"}`,
1823
+ children: [
1824
+ "Snap ",
1825
+ diagram.renderHints?.snapToGrid ? "on" : "off"
1826
+ ]
1827
+ }
1828
+ ),
1829
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", pressed: diagram.renderHints?.showEdgeLabels !== false, onClick: () => patchRenderHints({
1830
+ showEdgeLabels: diagram.renderHints?.showEdgeLabels === false
1831
+ }), children: [
1832
+ "Labels",
1833
+ " ",
1834
+ diagram.renderHints?.showEdgeLabels !== false ? "on" : "off"
1835
+ ] }),
1836
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", pressed: diagram.renderHints?.showLegend !== false, onClick: () => patchRenderHints({
1837
+ showLegend: diagram.renderHints?.showLegend === false
1838
+ }), children: [
1839
+ "Legend",
1840
+ " ",
1841
+ diagram.renderHints?.showLegend !== false ? "on" : "off"
1842
+ ] })
1843
+ ] }),
1844
+ /* @__PURE__ */ jsx("p", { className: "text-[10px] leading-snug text-muted-foreground", children: "Flow direction is used the next time you choose a directional layout." })
1845
+ ] })
1846
+ ]
1847
+ }
1848
+ ),
1849
+ /* @__PURE__ */ jsx(
1850
+ Panel,
1851
+ {
1852
+ position: "top-right",
1853
+ className: `${workspace ? "!top-32 !right-3 sm:!top-3" : ""} rounded-xl border border-border/70 bg-card/90 p-1.5 shadow-lg backdrop-blur-xl`,
1854
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
1855
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
1856
+ /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
1857
+ "button",
1858
+ {
1859
+ type: "button",
1860
+ "aria-label": "Arrange map",
1861
+ className: "flex items-center gap-1 rounded-lg border border-blue-200 bg-blue-50 p-2 text-blue-600 transition-colors hover:bg-blue-100 dark:border-blue-800 dark:bg-blue-950/20 dark:text-blue-400 dark:hover:bg-blue-900/30",
1862
+ title: "Arrange map",
1863
+ children: [
1864
+ /* @__PURE__ */ jsx(Shuffle, { className: "h-4 w-4" }),
1865
+ /* @__PURE__ */ jsx(ChevronDown, { className: "h-3 w-3" })
1866
+ ]
1867
+ }
1868
+ ) }),
1869
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "start", className: "w-52", children: [
1870
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { children: "Arrange map" }),
1871
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => arrangeByPerson(() => applyDirectedLayout("TB")), children: [
1872
+ /* @__PURE__ */ jsx(ArrowDown, { className: "mr-2 h-4 w-4" }),
1873
+ "Top to bottom"
1874
+ ] }),
1875
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => arrangeByPerson(() => applyDirectedLayout("LR")), children: [
1876
+ /* @__PURE__ */ jsx(ArrowRight, { className: "mr-2 h-4 w-4" }),
1877
+ "Left to right"
1878
+ ] }),
1879
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => arrangeByPerson(() => applyDirectedLayout("BT")), children: [
1880
+ /* @__PURE__ */ jsx(ArrowUp, { className: "mr-2 h-4 w-4" }),
1881
+ "Bottom to top"
1882
+ ] }),
1883
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => arrangeByPerson(() => applyDirectedLayout("RL")), children: [
1884
+ /* @__PURE__ */ jsx(ArrowLeft, { className: "mr-2 h-4 w-4" }),
1885
+ "Right to left"
1886
+ ] }),
1887
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
1888
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => arrangeByPerson(applyGridLayout), children: [
1889
+ /* @__PURE__ */ jsx(LayoutGrid, { className: "mr-2 h-4 w-4" }),
1890
+ "Balanced grid"
1891
+ ] }),
1892
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onSelect: () => arrangeByPerson(applyRadialLayout), children: [
1893
+ /* @__PURE__ */ jsx(Circle, { className: "mr-2 h-4 w-4" }),
1894
+ "Around a center"
1895
+ ] })
1896
+ ] })
1897
+ ] }),
1898
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
1899
+ /* @__PURE__ */ jsx(Button, { variant: "quiet", icon: /* @__PURE__ */ jsx(RotateCcw, {}), onClick: () => arrangeByPerson(resetLayout), "aria-label": "Restore saved layout", title: "Reset Layout" }),
1900
+ /* @__PURE__ */ jsx(Button, { variant: "quiet", icon: /* @__PURE__ */ jsx(Square, {}), onClick: () => chooseBackground(
1901
+ backgroundVariant === BackgroundVariant.Dots ? BackgroundVariant.Lines : BackgroundVariant.Dots
1902
+ ), "aria-label": backgroundVariant === BackgroundVariant.Dots ? "Use lined background" : "Use dotted background", title: "Toggle Background" })
1903
+ ] }),
1904
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2 justify-center", children: [
1905
+ /* @__PURE__ */ jsx(Button, { variant: "quiet", pressed: showMiniMap, icon: /* @__PURE__ */ jsx(Layers, {}), onClick: () => chooseMiniMap(!showMiniMap), "aria-label": showMiniMap ? "Hide mini map" : "Show mini map", title: "Toggle Mini Map" }),
1906
+ editing && /* @__PURE__ */ jsx(
1907
+ "button",
1908
+ {
1909
+ type: "button",
1910
+ onClick: () => patchRenderHints({
1911
+ snapToGrid: diagram.renderHints?.snapToGrid !== true
1912
+ }),
1913
+ "aria-label": diagram.renderHints?.snapToGrid ? "Turn off grid snapping" : "Turn on grid snapping",
1914
+ "aria-pressed": diagram.renderHints?.snapToGrid === true,
1915
+ className: `rounded-lg p-2 transition-colors ${diagram.renderHints?.snapToGrid ? "bg-blue-100 text-blue-700 dark:bg-blue-950/30 dark:text-blue-300" : "text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"}`,
1916
+ title: "Toggle snapping",
1917
+ children: /* @__PURE__ */ jsx(Magnet, { className: "h-4 w-4" })
1918
+ }
1919
+ ),
1920
+ /* @__PURE__ */ jsx(Button, { variant: "outline", icon: /* @__PURE__ */ jsx(Camera, {}), glyphTone: "success", onClick: exportImage, "aria-label": "Export map as image", title: "Export as Image" })
1921
+ ] })
1922
+ ] })
1923
+ }
1924
+ )
1925
+ ]
1926
+ }
1927
+ );
1928
+ };
1929
+ const ALL_LEGEND_ITEMS = [
1930
+ {
1931
+ type: "start",
1932
+ label: "Start",
1933
+ color: "bg-green-100 dark:bg-green-950/30 text-green-700 dark:text-green-300 border border-green-200 dark:border-green-800",
1934
+ icon: CheckCircle2
1935
+ },
1936
+ {
1937
+ type: "process",
1938
+ label: "Process",
1939
+ color: "bg-blue-100 dark:bg-blue-950/30 text-blue-700 dark:text-blue-300 border border-blue-200 dark:border-blue-800",
1940
+ icon: Settings
1941
+ },
1942
+ {
1943
+ type: "decision",
1944
+ label: "Decision",
1945
+ color: "bg-orange-100 dark:bg-orange-950/30 text-orange-700 dark:text-orange-300 border border-orange-200 dark:border-orange-800",
1946
+ icon: GitBranch
1947
+ },
1948
+ {
1949
+ type: "data",
1950
+ label: "Data",
1951
+ color: "bg-purple-100 dark:bg-purple-950/30 text-purple-700 dark:text-purple-300 border border-purple-200 dark:border-purple-800",
1952
+ icon: Database
1953
+ },
1954
+ {
1955
+ type: "end",
1956
+ label: "End",
1957
+ color: "bg-red-100 dark:bg-red-950/30 text-red-700 dark:text-red-300 border border-red-200 dark:border-red-800",
1958
+ icon: XCircle
1959
+ },
1960
+ {
1961
+ type: "user",
1962
+ label: "User",
1963
+ color: "bg-indigo-100 dark:bg-indigo-950/30 text-indigo-700 dark:text-indigo-300 border border-indigo-200 dark:border-indigo-800",
1964
+ icon: Users
1965
+ },
1966
+ {
1967
+ type: "system",
1968
+ label: "System",
1969
+ color: "bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-200 dark:border-gray-800",
1970
+ icon: Server
1971
+ },
1972
+ {
1973
+ type: "api",
1974
+ label: "API",
1975
+ color: "bg-teal-100 dark:bg-teal-950/30 text-teal-700 dark:text-teal-300 border border-teal-200 dark:border-teal-800",
1976
+ icon: Globe
1977
+ },
1978
+ {
1979
+ type: "compute",
1980
+ label: "Compute",
1981
+ color: "bg-yellow-100 dark:bg-yellow-950/30 text-yellow-700 dark:text-yellow-300 border border-yellow-200 dark:border-yellow-800",
1982
+ icon: Cpu
1983
+ },
1984
+ {
1985
+ type: "storage",
1986
+ label: "Storage",
1987
+ color: "bg-pink-100 dark:bg-pink-950/30 text-pink-700 dark:text-pink-300 border border-pink-200 dark:border-pink-800",
1988
+ icon: HardDrive
1989
+ },
1990
+ {
1991
+ type: "event",
1992
+ label: "Event",
1993
+ color: "bg-cyan-100 dark:bg-cyan-950/30 text-cyan-700 dark:text-cyan-300 border border-cyan-200 dark:border-cyan-800",
1994
+ icon: Clock
1995
+ },
1996
+ {
1997
+ type: "entity",
1998
+ label: "Entity",
1999
+ color: "bg-violet-100 dark:bg-violet-950/30 text-violet-700 dark:text-violet-300 border border-violet-200 dark:border-violet-800",
2000
+ icon: Table
2001
+ },
2002
+ {
2003
+ type: "gateway",
2004
+ label: "Gateway",
2005
+ color: "bg-amber-100 dark:bg-amber-950/30 text-amber-700 dark:text-amber-300 border border-amber-200 dark:border-amber-800",
2006
+ icon: ArrowRight
2007
+ },
2008
+ {
2009
+ type: "default",
2010
+ label: "Node",
2011
+ color: "bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 border border-gray-200 dark:border-gray-800",
2012
+ icon: Square
2013
+ }
2014
+ ];
2015
+ const PedigreeLegend = () => /* @__PURE__ */ jsx("div", { className: "bg-textured rounded-xl p-3 border-border shadow-sm", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-3", children: [
2016
+ [
2017
+ {
2018
+ label: "Male",
2019
+ shape: "w-6 h-6 border-2 border-gray-600 bg-white dark:bg-gray-800"
2020
+ },
2021
+ {
2022
+ label: "Female",
2023
+ shape: "w-6 h-6 rounded-full border-2 border-gray-600 bg-white dark:bg-gray-800"
2024
+ },
2025
+ {
2026
+ label: "Affected",
2027
+ shape: "w-6 h-6 border-2 border-gray-600 bg-gray-800 dark:bg-gray-200"
2028
+ },
2029
+ {
2030
+ label: "Deceased",
2031
+ shape: "w-6 h-6 border-2 border-gray-600 bg-white dark:bg-gray-800 relative overflow-hidden"
2032
+ },
2033
+ {
2034
+ label: "Proband \u2192",
2035
+ shape: "w-6 h-6 border-4 border-blue-500 bg-white dark:bg-gray-800"
2036
+ }
2037
+ ].map(({ label, shape }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2038
+ /* @__PURE__ */ jsx("div", { className: shape }),
2039
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-600 dark:text-gray-400", children: label })
2040
+ ] }, label)),
2041
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2042
+ /* @__PURE__ */ jsx("div", { className: "w-8 h-px border-t-2 border-dashed border-gray-500" }),
2043
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-gray-600 dark:text-gray-400", children: "Divorced" })
2044
+ ] })
2045
+ ] }) });
2046
+ function getDiagramIcon(type) {
2047
+ switch (type) {
2048
+ case "flowchart":
2049
+ return /* @__PURE__ */ jsx(GitBranch, { className: "h-4 w-4" });
2050
+ case "mindmap":
2051
+ return /* @__PURE__ */ jsx(Rainbow, { className: "h-4 w-4" });
2052
+ case "orgchart":
2053
+ return /* @__PURE__ */ jsx(Users, { className: "h-4 w-4" });
2054
+ case "network":
2055
+ return /* @__PURE__ */ jsx(Network, { className: "h-4 w-4" });
2056
+ case "system":
2057
+ return /* @__PURE__ */ jsx(Server, { className: "h-4 w-4" });
2058
+ case "process":
2059
+ return /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" });
2060
+ case "pedigree":
2061
+ return /* @__PURE__ */ jsx(Users, { className: "h-4 w-4" });
2062
+ case "timeline":
2063
+ return /* @__PURE__ */ jsx(Clock, { className: "h-4 w-4" });
2064
+ case "erd":
2065
+ return /* @__PURE__ */ jsx(Table, { className: "h-4 w-4" });
2066
+ case "sequence":
2067
+ return /* @__PURE__ */ jsx(ArrowRight, { className: "h-4 w-4" });
2068
+ default:
2069
+ return /* @__PURE__ */ jsx(Network, { className: "h-4 w-4" });
2070
+ }
2071
+ }
2072
+ const InteractiveDiagramBlock = ({
2073
+ diagram,
2074
+ taskId,
2075
+ messageId,
2076
+ conversationId,
2077
+ artifactId,
2078
+ blockIndex,
2079
+ presentation = "card",
2080
+ onNodeClick,
2081
+ defaultEditing = false,
2082
+ onSelectionChange,
2083
+ onDiagramChange
2084
+ }) => {
2085
+ const isWorkspace = presentation === "workspace";
2086
+ const [isFullScreen, setIsFullScreen] = useState(false);
2087
+ const [editing, setEditing] = useState(defaultEditing);
2088
+ const canEdit = Boolean(onDiagramChange);
2089
+ const [cardShowMiniMap, setCardShowMiniMap] = useState(false);
2090
+ const [cardBackgroundVariant, setCardBackgroundVariant] = useState(BackgroundVariant.Dots);
2091
+ const showMiniMap = editing ? diagram.renderHints?.showMiniMap === true : cardShowMiniMap;
2092
+ const backgroundVariant = editing ? backgroundVariantFromDiagram(diagram) : cardBackgroundVariant;
2093
+ const { open: openCanvas } = useCanvas();
2094
+ const { openArtifact } = useOpenArtifactInCanvas();
2095
+ const handleOpenCanvas = () => {
2096
+ const def = getArtifactDef("diagram");
2097
+ if (def?.materializable && isMaterializedArtifactId(artifactId)) {
2098
+ void openArtifact({
2099
+ canvasType: "diagram",
2100
+ title: diagram.title,
2101
+ content: JSON.stringify(diagram),
2102
+ conversationId,
2103
+ messageId,
2104
+ artifactId,
2105
+ artifactIndex: blockIndex && blockIndex > 0 ? blockIndex : 1
2106
+ });
2107
+ return;
2108
+ }
2109
+ openCanvas({
2110
+ type: "diagram",
2111
+ data: diagram,
2112
+ metadata: {
2113
+ title: diagram.title,
2114
+ sourceTaskId: taskId,
2115
+ sourceMessageId: messageId,
2116
+ conversationId,
2117
+ canvasItemId: artifactId
2118
+ }
2119
+ });
2120
+ };
2121
+ const diagramContainerId = useId();
2122
+ const getDiagramElement = useCallback(
2123
+ () => document.getElementById(diagramContainerId),
2124
+ [diagramContainerId]
2125
+ );
2126
+ const diagramPrinter = useMemo(
2127
+ () => createDiagramPrinter(getDiagramElement, diagram),
2128
+ [getDiagramElement, diagram]
2129
+ );
2130
+ const {
2131
+ open: printDialogOpen,
2132
+ setOpen: setPrintDialogOpen,
2133
+ triggerPrint
2134
+ } = usePrintOptions(diagramPrinter, diagram);
2135
+ const exportDiagramJSON = useCallback(() => {
2136
+ const blob = new Blob([JSON.stringify({ diagram }, null, 2)], {
2137
+ type: "application/json"
2138
+ });
2139
+ const url = URL.createObjectURL(blob);
2140
+ const a = document.createElement("a");
2141
+ a.href = url;
2142
+ a.download = `${diagram.title.replace(/[^a-z0-9]/gi, "_").toLowerCase()}.json`;
2143
+ a.click();
2144
+ URL.revokeObjectURL(url);
2145
+ }, [diagram]);
2146
+ const toggleEditing = () => {
2147
+ const next = !editing;
2148
+ setEditing(next);
2149
+ if (!next) onSelectionChange?.({ kind: null, id: null });
2150
+ };
2151
+ const handleExportImage = useCallback(() => {
2152
+ const viewport = document.querySelector(
2153
+ ".react-flow__viewport"
2154
+ );
2155
+ if (!viewport) return;
2156
+ const isDark = document.documentElement.classList.contains("dark") || window.matchMedia("(prefers-color-scheme: dark)").matches;
2157
+ import("html2canvas").then((mod) => {
2158
+ const restore = patchComputedStyleForCapture(isDark);
2159
+ return mod.default(viewport, {
2160
+ backgroundColor: isDark ? "#111827" : "#ffffff",
2161
+ scale: 2,
2162
+ useCORS: true
2163
+ }).finally(restore);
2164
+ }).then((canvas) => {
2165
+ const a = document.createElement("a");
2166
+ a.download = `${diagram.title.replace(/[^a-z0-9]/gi, "_").toLowerCase()}_diagram.png`;
2167
+ a.href = canvas.toDataURL("image/png");
2168
+ a.click();
2169
+ }).catch((err) => console.warn("Image export failed:", err));
2170
+ }, [diagram.title]);
2171
+ const renderLegend = () => {
2172
+ if (diagram.type === "orgchart") return null;
2173
+ if (diagram.type === "pedigree") return /* @__PURE__ */ jsx(PedigreeLegend, {});
2174
+ if (diagram.renderHints?.showLegend === false) return null;
2175
+ const usedTypes = new Set(
2176
+ diagram.nodes.map((n) => n.nodeType || n.type || "default")
2177
+ );
2178
+ const items = ALL_LEGEND_ITEMS.filter((item) => usedTypes.has(item.type));
2179
+ if (items.length === 0 || items.length === 1 && items[0].type === "default")
2180
+ return null;
2181
+ return /* @__PURE__ */ jsx("div", { className: "bg-textured rounded-xl p-3 border-border shadow-sm", children: /* @__PURE__ */ jsx(
2182
+ "div",
2183
+ {
2184
+ className: `grid gap-3 ${items.length <= 2 ? "grid-cols-2" : items.length <= 3 ? "grid-cols-3" : "grid-cols-2 md:grid-cols-5"}`,
2185
+ children: items.map(({ type, label, color, icon: Icon }) => /* @__PURE__ */ jsxs(
2186
+ "div",
2187
+ {
2188
+ className: `flex items-center gap-1 p-1 rounded-lg ${color} text-xs font-medium`,
2189
+ children: [
2190
+ /* @__PURE__ */ jsx(Icon, { className: "h-3 w-3" }),
2191
+ /* @__PURE__ */ jsx("span", { children: label })
2192
+ ]
2193
+ },
2194
+ type
2195
+ ))
2196
+ }
2197
+ ) });
2198
+ };
2199
+ const legend = renderLegend();
2200
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2201
+ !isWorkspace && isFullScreen && /* @__PURE__ */ jsx(
2202
+ "div",
2203
+ {
2204
+ className: "fixed inset-0 z-40 bg-black/60 backdrop-blur-sm",
2205
+ onClick: () => setIsFullScreen(false)
2206
+ }
2207
+ ),
2208
+ /* @__PURE__ */ jsx(
2209
+ "div",
2210
+ {
2211
+ className: (
2212
+ // matrx-touch-targets floors every button/menu-item under it to a
2213
+ // 44px hit area on touch/narrow viewports only (app/globals.css) —
2214
+ // desktop density is untouched. Needed here because React Flow's
2215
+ // own <Controls/> (Zoom in/out, Fit view) and the hand-rolled
2216
+ // Arrange-map/Restore-layout/background/minimap/export buttons
2217
+ // below all render at 26-34px, well under the iOS floor.
2218
+ isWorkspace ? "relative h-full min-h-0 w-full overflow-hidden bg-background matrx-touch-targets" : `w-full rounded-xl border border-border matrx-touch-targets ${isFullScreen ? "fixed inset-0 z-50 flex items-center justify-center p-2" : "py-2"}`
2219
+ ),
2220
+ children: /* @__PURE__ */ jsxs(
2221
+ "div",
2222
+ {
2223
+ className: isWorkspace ? "h-full min-h-0 w-full overflow-hidden" : `mx-auto w-full max-w-6xl ${isFullScreen ? "bg-textured flex h-full max-h-[95dvh] flex-col overflow-hidden rounded-xl border border-border shadow-2xl" : ""}`,
2224
+ children: [
2225
+ !isWorkspace && isFullScreen && /* @__PURE__ */ jsxs("div", { className: "flex-shrink-0 px-3 py-2 border-b border-border flex items-center justify-between bg-gradient-to-r from-blue-50 to-indigo-50 dark:from-blue-950/30 dark:to-indigo-950/30", children: [
2226
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
2227
+ /* @__PURE__ */ jsx("div", { className: "text-blue-600 dark:text-blue-400 flex-shrink-0 [&_svg]:h-4 [&_svg]:w-4", children: getDiagramIcon(diagram.type) }),
2228
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-foreground truncate", children: diagram.title })
2229
+ ] }),
2230
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
2231
+ canEdit && /* @__PURE__ */ jsx(
2232
+ IconButton,
2233
+ {
2234
+ icon: editing ? Check : Pencil,
2235
+ tooltip: editing ? "Done editing" : "Edit this map",
2236
+ "aria-label": editing ? "Done editing" : "Edit this map",
2237
+ onClick: toggleEditing,
2238
+ className: editing ? "bg-emerald-500 dark:bg-emerald-600 text-white hover:bg-emerald-600 dark:hover:bg-emerald-700" : void 0,
2239
+ variant: editing ? void 0 : "outline"
2240
+ }
2241
+ ),
2242
+ /* @__PURE__ */ jsx(
2243
+ IconButton,
2244
+ {
2245
+ icon: Printer,
2246
+ tooltip: "Print / Save as PDF",
2247
+ "aria-label": "Print or save as PDF",
2248
+ onClick: triggerPrint
2249
+ }
2250
+ ),
2251
+ /* @__PURE__ */ jsx(
2252
+ IconButton,
2253
+ {
2254
+ icon: Download,
2255
+ tooltip: "Export as JSON",
2256
+ "aria-label": "Export map as JSON",
2257
+ onClick: exportDiagramJSON,
2258
+ variant: "outline"
2259
+ }
2260
+ ),
2261
+ /* @__PURE__ */ jsx(
2262
+ IconButton,
2263
+ {
2264
+ icon: Minimize2,
2265
+ tooltip: "Exit full screen",
2266
+ "aria-label": "Exit full screen",
2267
+ onClick: () => setIsFullScreen(false),
2268
+ variant: "outline"
2269
+ }
2270
+ )
2271
+ ] })
2272
+ ] }),
2273
+ /* @__PURE__ */ jsxs(
2274
+ "div",
2275
+ {
2276
+ className: isWorkspace ? "relative flex h-full min-h-0 flex-col overflow-hidden" : isFullScreen ? "flex min-h-0 flex-1 flex-col overflow-hidden p-2" : "p-2",
2277
+ children: [
2278
+ !isWorkspace && !isFullScreen && /* @__PURE__ */ jsx("div", { className: "bg-gradient-to-br from-blue-100 via-indigo-50 to-purple-100 dark:from-blue-950/40 dark:via-indigo-950/30 dark:to-purple-950/40 rounded-xl p-2 border border-blue-200 dark:border-blue-800/50 mb-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-2", children: [
2279
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 flex-1 min-w-0", children: [
2280
+ /* @__PURE__ */ jsx("div", { className: "p-2 bg-blue-500 dark:bg-blue-600 rounded-lg flex-shrink-0 text-white [&_svg]:h-4 [&_svg]:w-4", children: getDiagramIcon(diagram.type) }),
2281
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
2282
+ /* @__PURE__ */ jsx("h1", { className: "text-sm font-bold text-foreground leading-tight line-clamp-2", children: diagram.title }),
2283
+ diagram.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mt-0.5 line-clamp-2", children: diagram.description }),
2284
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 flex-wrap mt-1", children: [
2285
+ /* @__PURE__ */ jsx(Chip, { tone: "blue", label: formatDiagramType(diagram.type) }),
2286
+ diagram.layout?.direction && /* @__PURE__ */ jsx("span", { className: "px-1.5 py-0.5 bg-muted text-muted-foreground rounded-full text-[10px]", children: diagram.layout.direction })
2287
+ ] })
2288
+ ] })
2289
+ ] }),
2290
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [
2291
+ canEdit && /* @__PURE__ */ jsx(
2292
+ IconButton,
2293
+ {
2294
+ icon: editing ? Check : Pencil,
2295
+ tooltip: editing ? "Done editing" : "Edit this map",
2296
+ "aria-label": editing ? "Done editing" : "Edit this map",
2297
+ onClick: toggleEditing,
2298
+ className: editing ? "bg-emerald-500 dark:bg-emerald-600 text-white hover:bg-emerald-600 dark:hover:bg-emerald-700" : void 0,
2299
+ variant: editing ? void 0 : "outline"
2300
+ }
2301
+ ),
2302
+ /* @__PURE__ */ jsx(
2303
+ IconButton,
2304
+ {
2305
+ icon: Printer,
2306
+ tooltip: "Print / Save as PDF",
2307
+ "aria-label": "Print or save as PDF",
2308
+ onClick: triggerPrint
2309
+ }
2310
+ ),
2311
+ /* @__PURE__ */ jsx(
2312
+ IconButton,
2313
+ {
2314
+ icon: ExternalLink,
2315
+ tooltip: "Open Canvas",
2316
+ "aria-label": "Open in Canvas",
2317
+ onClick: handleOpenCanvas
2318
+ }
2319
+ ),
2320
+ /* @__PURE__ */ jsx(
2321
+ IconButton,
2322
+ {
2323
+ icon: Maximize2,
2324
+ tooltip: "Expand to full screen",
2325
+ "aria-label": "Expand to full screen",
2326
+ onClick: () => setIsFullScreen(true)
2327
+ }
2328
+ ),
2329
+ /* @__PURE__ */ jsx(
2330
+ IconButton,
2331
+ {
2332
+ icon: Download,
2333
+ tooltip: "Export as JSON",
2334
+ "aria-label": "Export map as JSON",
2335
+ onClick: exportDiagramJSON,
2336
+ variant: "outline"
2337
+ }
2338
+ )
2339
+ ] })
2340
+ ] }) }),
2341
+ isWorkspace && /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute bottom-3 left-1/2 z-20 -translate-x-1/2", children: /* @__PURE__ */ jsxs("div", { className: "pointer-events-auto flex items-center gap-1 rounded-xl border border-border/70 bg-card/90 p-1 shadow-lg backdrop-blur-xl", children: [
2342
+ /* @__PURE__ */ jsx(
2343
+ IconButton,
2344
+ {
2345
+ icon: Printer,
2346
+ tooltip: "Print or save as PDF",
2347
+ "aria-label": "Print or save as PDF",
2348
+ onClick: triggerPrint,
2349
+ variant: "ghost"
2350
+ }
2351
+ ),
2352
+ /* @__PURE__ */ jsx(
2353
+ IconButton,
2354
+ {
2355
+ icon: Download,
2356
+ tooltip: "Export map as JSON",
2357
+ "aria-label": "Export map as JSON",
2358
+ onClick: exportDiagramJSON,
2359
+ variant: "ghost"
2360
+ }
2361
+ )
2362
+ ] }) }),
2363
+ /* @__PURE__ */ jsx(
2364
+ "div",
2365
+ {
2366
+ id: diagramContainerId,
2367
+ className: isWorkspace ? "min-h-0 flex-1 overflow-hidden bg-textured" : `${isFullScreen ? "min-h-0 flex-1" : "h-[600px]"} overflow-hidden rounded-xl border border-border bg-textured`,
2368
+ children: /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsx(
2369
+ DiagramFlow,
2370
+ {
2371
+ diagram,
2372
+ workspace: isWorkspace,
2373
+ showMiniMap,
2374
+ setShowMiniMap: setCardShowMiniMap,
2375
+ backgroundVariant,
2376
+ setBackgroundVariant: setCardBackgroundVariant,
2377
+ onExportImage: handleExportImage,
2378
+ onNodeClick,
2379
+ onSelectionChange,
2380
+ editing: canEdit && editing,
2381
+ onDiagramChange
2382
+ }
2383
+ ) })
2384
+ }
2385
+ ),
2386
+ !isWorkspace && legend && /* @__PURE__ */ jsx(
2387
+ "div",
2388
+ {
2389
+ className: isFullScreen ? "flex-shrink-0 px-4 py-3 border-t border-border" : "mt-4",
2390
+ children: legend
2391
+ }
2392
+ )
2393
+ ]
2394
+ }
2395
+ )
2396
+ ]
2397
+ }
2398
+ )
2399
+ }
2400
+ ),
2401
+ /* @__PURE__ */ jsx(
2402
+ PrintOptionsDialog,
2403
+ {
2404
+ printer: diagramPrinter,
2405
+ data: diagram,
2406
+ open: printDialogOpen,
2407
+ onOpenChange: setPrintDialogOpen
2408
+ }
2409
+ )
2410
+ ] });
2411
+ };
2412
+ var InteractiveDiagramBlock_default = InteractiveDiagramBlock;
2413
+ export {
2414
+ InteractiveDiagramBlock_default as default
2415
+ };