@diagrammo/dgmo 0.48.2 → 0.50.0

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 (244) hide show
  1. package/.cursorrules +12 -3
  2. package/.github/copilot-instructions.md +12 -3
  3. package/.windsurfrules +12 -3
  4. package/SKILL.md +12 -3
  5. package/dist/advanced.d.ts +851 -1
  6. package/dist/advanced.js +601 -177
  7. package/dist/auto.css +63 -0
  8. package/dist/auto.js +220 -110
  9. package/dist/auto.mjs +45920 -33167
  10. package/dist/block.css +63 -0
  11. package/dist/block.d.ts +13 -5
  12. package/dist/block.js +239 -62
  13. package/dist/{charts-d3-QOZHKTCT.js → charts-d3-DKUD7MQE.js} +9 -8
  14. package/dist/{chunk-3MQQNXPD.js → chunk-2C56LEML.js} +3 -3
  15. package/dist/{chunk-L66GEFB6.js → chunk-2JJ2KNPI.js} +4 -4
  16. package/dist/{chunk-6SM5NJQH.js → chunk-2QYTMIRR.js} +4 -4
  17. package/dist/{chunk-RJE5JTVK.js → chunk-3G6TMNVF.js} +7 -7
  18. package/dist/{chunk-MO5YHHMQ.js → chunk-3LKM6FMW.js} +2 -2
  19. package/dist/{chunk-76OWZ3BA.js → chunk-3P2DKJCG.js} +2 -2
  20. package/dist/chunk-3TDRHT4J.js +1043 -0
  21. package/dist/chunk-3XPUDB7B.js +420 -0
  22. package/dist/{chunk-2LACINWN.js → chunk-3ZPC476N.js} +7 -7
  23. package/dist/{chunk-G2H74XJZ.js → chunk-4BMJQFNK.js} +8 -8
  24. package/dist/{chunk-THXCFRTU.js → chunk-4S723I74.js} +9 -9
  25. package/dist/{chunk-6NYWYNBI.js → chunk-4XK3FLFB.js} +3 -3
  26. package/dist/chunk-5JSWBPZZ.js +607 -0
  27. package/dist/{chunk-WCT3NYCV.js → chunk-5LWQH6QV.js} +1 -1
  28. package/dist/{chunk-7DTWEFUE.js → chunk-5Z736BSU.js} +8 -8
  29. package/dist/{chunk-ERLBPDGU.js → chunk-6BFZKBGD.js} +2 -2
  30. package/dist/{chunk-6HO5ZTXK.js → chunk-6IAA2QQ2.js} +2 -2
  31. package/dist/{chunk-H6PI3KJT.js → chunk-6IUAK7RZ.js} +2 -2
  32. package/dist/{chunk-RTLBSQ3G.js → chunk-6M5PJFQG.js} +3 -3
  33. package/dist/{chunk-Z5CGSFJB.js → chunk-6X4AKWLF.js} +4 -4
  34. package/dist/{chunk-OJR3MQYV.js → chunk-6ZT4U37Q.js} +291 -52
  35. package/dist/{chunk-5QXL4NYS.js → chunk-7G2ER4CY.js} +10 -5
  36. package/dist/chunk-7PQYTZMA.js +681 -0
  37. package/dist/{chunk-OURHMODR.js → chunk-7RB5Q6MB.js} +11 -11
  38. package/dist/{chunk-YAA6IID3.js → chunk-7UEMZREK.js} +2 -2
  39. package/dist/{chunk-AN2MOO5T.js → chunk-A3WQVFBS.js} +3 -3
  40. package/dist/{chunk-VOKGH627.js → chunk-AHGF2YYA.js} +13 -3
  41. package/dist/{chunk-CI2G3OEB.js → chunk-ASS5YYIZ.js} +12 -12
  42. package/dist/{chunk-TYS6CSS5.js → chunk-BCYVE3N5.js} +2 -2
  43. package/dist/chunk-BDXC7MDK.js +2395 -0
  44. package/dist/chunk-BTUTZMPT.js +482 -0
  45. package/dist/{chunk-YGJTDXVR.js → chunk-C4GQDB5L.js} +2 -2
  46. package/dist/{chunk-Y2ZE3MSG.js → chunk-C63UWAKM.js} +2 -2
  47. package/dist/{chunk-725LDASD.js → chunk-CLD2OKV7.js} +2 -2
  48. package/dist/{chunk-WBRZJOEC.js → chunk-CMCR5WBW.js} +3 -3
  49. package/dist/{chunk-IZMRON6C.js → chunk-CVV36CWI.js} +2 -2
  50. package/dist/chunk-DMJJ3CEQ.js +254 -0
  51. package/dist/{chunk-MZSBFAPJ.js → chunk-EJTKV7CY.js} +9 -9
  52. package/dist/{chunk-FITOLXSX.js → chunk-EOFPYPAU.js} +26 -2
  53. package/dist/{chunk-X5LCYCL5.js → chunk-ER5SCQWQ.js} +5 -5
  54. package/dist/{chunk-4OHACBGX.js → chunk-F2L5GCQ4.js} +2 -2
  55. package/dist/{chunk-FCIIHT24.js → chunk-F5UDBSJY.js} +7 -7
  56. package/dist/{chunk-3JLKYGBQ.js → chunk-F7BFXWNQ.js} +2 -2
  57. package/dist/{chunk-FANX6UJR.js → chunk-FAL7NOK3.js} +11 -11
  58. package/dist/{chunk-BUPDIHML.js → chunk-FB2WHOEQ.js} +4 -4
  59. package/dist/chunk-FL4IOQ37.js +379 -0
  60. package/dist/{chunk-LIOHW36Z.js → chunk-GBE54KY6.js} +6 -5
  61. package/dist/{chunk-RUNNI6VE.js → chunk-GL5UZ6NY.js} +3 -3
  62. package/dist/{chunk-4GRI7MEB.js → chunk-GPWHQ5FJ.js} +6 -6
  63. package/dist/chunk-GROQGHCT.js +960 -0
  64. package/dist/{chunk-SGZYXELT.js → chunk-H73FP42Q.js} +9 -6
  65. package/dist/{chunk-PBAHEPLQ.js → chunk-HGN652MU.js} +7 -6
  66. package/dist/{chunk-3SMGIJDD.js → chunk-HHXOONLX.js} +13 -1
  67. package/dist/{chunk-QOOUC2J5.js → chunk-HQCHYB5F.js} +2 -2
  68. package/dist/{chunk-AELOBFW5.js → chunk-I4IFRCUB.js} +3 -3
  69. package/dist/{chunk-GMR5MFHJ.js → chunk-I7F2A35O.js} +2 -2
  70. package/dist/{chunk-T2OE3YQB.js → chunk-IA3FJYWR.js} +3 -3
  71. package/dist/chunk-IAEC4KLA.js +492 -0
  72. package/dist/chunk-IVKC4GID.js +32 -0
  73. package/dist/{chunk-HSH73DP6.js → chunk-JFYIP7XU.js} +139 -39
  74. package/dist/{chunk-CKNVO24D.js → chunk-JZNMXEIV.js} +2 -2
  75. package/dist/chunk-KJXIHOVL.js +940 -0
  76. package/dist/chunk-L2ZTFHAY.js +331 -0
  77. package/dist/{chunk-B7JUCQUA.js → chunk-M5RXSRO2.js} +4 -4
  78. package/dist/{chunk-ULOEATBZ.js → chunk-NFFIKVNO.js} +106 -29
  79. package/dist/{chunk-PZMETGLY.js → chunk-NISQC5KW.js} +358 -122
  80. package/dist/chunk-O4VUFXIH.js +574 -0
  81. package/dist/{chunk-RVMRZAPB.js → chunk-O76UD6VJ.js} +3 -3
  82. package/dist/{chunk-JM4LEPY3.js → chunk-O7NUCTFU.js} +2 -2
  83. package/dist/{chunk-JED6ZDEE.js → chunk-O7WP4ZD4.js} +2 -2
  84. package/dist/{chunk-EVCVDTXE.js → chunk-OHQEMBLI.js} +3 -3
  85. package/dist/{chunk-ZBWMSD5N.js → chunk-ONA5KPV3.js} +4 -4
  86. package/dist/{chunk-Y3J7VR52.js → chunk-OTAL43EH.js} +34 -2
  87. package/dist/{chunk-WCSOJFU3.js → chunk-OTP5KVLO.js} +3 -3
  88. package/dist/{chunk-RYEGFMUO.js → chunk-PGEGPSCZ.js} +2 -2
  89. package/dist/{chunk-ZO27FGJS.js → chunk-PH5X4GIP.js} +2 -2
  90. package/dist/{chunk-ZJEL4H2R.js → chunk-PJUGRJHJ.js} +9 -9
  91. package/dist/{chunk-ZGR7ULFJ.js → chunk-PLZI6KPM.js} +26 -14
  92. package/dist/{chunk-3R5POCTZ.js → chunk-PMN3Q7RJ.js} +6 -6
  93. package/dist/{chunk-YGJZWZTY.js → chunk-PZFVK3IH.js} +2 -2
  94. package/dist/chunk-Q4V4XQWV.js +158 -0
  95. package/dist/chunk-QDFNCATJ.js +325 -0
  96. package/dist/{chunk-QEBUY5NY.js → chunk-QFQ35BTO.js} +4 -4
  97. package/dist/chunk-QQJUTGQH.js +135 -0
  98. package/dist/{chunk-PWIHZ6NJ.js → chunk-QUJGFNFN.js} +4 -4
  99. package/dist/{chunk-J5FIXQRT.js → chunk-R56LASIN.js} +4 -4
  100. package/dist/{chunk-SRTU6HMQ.js → chunk-RV26LTUU.js} +8 -8
  101. package/dist/chunk-RV6A2B5S.js +354 -0
  102. package/dist/{chunk-EB6FPQUP.js → chunk-S5GRONXL.js} +3 -3
  103. package/dist/{chunk-5MLYVTYM.js → chunk-SCHXJTZL.js} +2 -2
  104. package/dist/{chunk-T3UBLACL.js → chunk-SCQ5VPUF.js} +19 -5
  105. package/dist/{chunk-PBHE5UG6.js → chunk-SGFZZAUO.js} +46 -12
  106. package/dist/{chunk-BUVJFRPY.js → chunk-SU2VBK4L.js} +4 -4
  107. package/dist/{chunk-SML67VPV.js → chunk-T4BRO3Z6.js} +3 -3
  108. package/dist/{chunk-NURGB5Z4.js → chunk-TSA237IM.js} +2 -2
  109. package/dist/chunk-TWCLK2GA.js +273 -0
  110. package/dist/{chunk-IJZFN3HM.js → chunk-TWQUYVP3.js} +4 -4
  111. package/dist/{chunk-DKEPS5LH.js → chunk-U2HGPLZS.js} +36 -2
  112. package/dist/{chunk-B65G5DNL.js → chunk-URSQLCTR.js} +3 -3
  113. package/dist/{chunk-ILKORZ3H.js → chunk-UUS2GIJZ.js} +7 -7
  114. package/dist/{chunk-XAKEUMEJ.js → chunk-UXOSVCLJ.js} +4 -4
  115. package/dist/{chunk-QLCCJEJI.js → chunk-WCUHAQKB.js} +2 -2
  116. package/dist/{chunk-WVAJFAIA.js → chunk-WWN566I7.js} +257 -101
  117. package/dist/{chunk-IPWPWM6R.js → chunk-X2NMFTG3.js} +111 -10
  118. package/dist/{chunk-UWN33VNX.js → chunk-XCLHOZAM.js} +10 -10
  119. package/dist/{chunk-P235SVAH.js → chunk-XDXNDSKO.js} +2 -2
  120. package/dist/chunk-XHVV4NVW.js +51 -0
  121. package/dist/{chunk-33LCUH4H.js → chunk-XMVQ5F4M.js} +4 -4
  122. package/dist/{chunk-MITI6NOL.js → chunk-YA7D2N2O.js} +11 -11
  123. package/dist/{chunk-7JEGTRLD.js → chunk-YB3FW24O.js} +3 -3
  124. package/dist/chunk-YNRDWYZP.js +295 -0
  125. package/dist/{chunk-44CM72SQ.js → chunk-YZLMKW4T.js} +3 -3
  126. package/dist/chunk-Z6XJQ6KO.js +452 -0
  127. package/dist/cli.cjs +179 -133
  128. package/dist/clock.d.ts +10 -0
  129. package/dist/clock.js +235 -0
  130. package/dist/countdown.d.ts +12 -0
  131. package/dist/countdown.js +450 -0
  132. package/dist/dgmo-router-QOMFCOOV.js +84 -0
  133. package/dist/dimensions-P5FSX2QN.js +22 -0
  134. package/dist/editor.js +43 -2
  135. package/dist/element.js +220 -110
  136. package/dist/element.mjs +45920 -33167
  137. package/dist/{flowchart-parser-ZNSKIBVR.js → flowchart-parser-OE4WHLTF.js} +4 -4
  138. package/dist/{flowchart-renderer-SNDSII4D.js → flowchart-renderer-GPCSMTOR.js} +8 -8
  139. package/dist/highlight.d.ts +17 -1
  140. package/dist/highlight.js +163 -6
  141. package/dist/index.d.ts +5 -1
  142. package/dist/index.js +199 -233
  143. package/dist/{layout-HRBZPFCN.js → layout-34CLNICW.js} +5 -5
  144. package/dist/layout-46366KBT.js +10 -0
  145. package/dist/{layout-HWDSRX5E.js → layout-5BG6DFCU.js} +6 -6
  146. package/dist/layout-6RDJHS6E.js +9 -0
  147. package/dist/{layout-7QXCNOVS.js → layout-7H4H46CS.js} +3 -3
  148. package/dist/{layout-46N4JJYK.js → layout-7SKMFYHL.js} +5 -5
  149. package/dist/{layout-EE6GE46Y.js → layout-DC4TVXER.js} +5 -5
  150. package/dist/layout-FGQWRYYW.js +14 -0
  151. package/dist/{layout-S2QBYSK2.js → layout-NXG63LWH.js} +3 -3
  152. package/dist/{layout-N76NR4ZO.js → layout-PUQCB6AN.js} +7 -7
  153. package/dist/{layout-HYZPWAK5.js → layout-QNUQLEHU.js} +3 -3
  154. package/dist/{layout-UM5F4DJB.js → layout-T3OZU5QW.js} +5 -5
  155. package/dist/layout-TJIWF7EM.js +14 -0
  156. package/dist/layout-VYELEAW7.js +14 -0
  157. package/dist/{layout-5RA6QWR6.js → layout-WZHNDT2O.js} +6 -6
  158. package/dist/{layout-search-OYV77HHS.js → layout-search-QS44PI5R.js} +6 -6
  159. package/dist/{parser-6BTRLKRZ.js → parser-45DENHFZ.js} +4 -4
  160. package/dist/{parser-TFZFBVWN.js → parser-4AI5ZN5F.js} +3 -3
  161. package/dist/{parser-XDVELHRK.js → parser-4P36TUVD.js} +4 -4
  162. package/dist/{parser-ZSDPZYQP.js → parser-5AURY4A6.js} +4 -4
  163. package/dist/{parser-N5O4IHUN.js → parser-A2BEFMGK.js} +4 -4
  164. package/dist/parser-B5FVS7O6.js +11 -0
  165. package/dist/{parser-NGU3ETO6.js → parser-C2HF2C2E.js} +4 -4
  166. package/dist/parser-CSFUN3CT.js +14 -0
  167. package/dist/{parser-TRTHDFPP.js → parser-D3QT6GWN.js} +5 -5
  168. package/dist/parser-D5637H5H.js +15 -0
  169. package/dist/{parser-VQP2UJ6W.js → parser-DFFEDKHH.js} +3 -3
  170. package/dist/parser-DOKMZXVZ.js +13 -0
  171. package/dist/parser-FMPCVFRK.js +15 -0
  172. package/dist/{parser-Y6WTBU76.js → parser-HYRTF3DO.js} +3 -3
  173. package/dist/{parser-I6KXEYFK.js → parser-I2UIJKVQ.js} +4 -4
  174. package/dist/{parser-O5J4VBII.js → parser-IBWNAPY4.js} +3 -3
  175. package/dist/{parser-PQ3POX45.js → parser-KUQWRPIT.js} +4 -4
  176. package/dist/{parser-2MFP2H2E.js → parser-LWKKBNSA.js} +3 -3
  177. package/dist/{parser-OV7NOBW6.js → parser-O4QFCUW7.js} +5 -5
  178. package/dist/{parser-IXSZZQHY.js → parser-PGMQDD4G.js} +4 -4
  179. package/dist/{parser-3STE62GB.js → parser-Q4QKCIWQ.js} +4 -4
  180. package/dist/parser-QTOB4KFL.js +14 -0
  181. package/dist/{parser-2EWECDSA.js → parser-QYYM4QVW.js} +4 -4
  182. package/dist/{parser-4OGOBJJ4.js → parser-RZMQP7MM.js} +4 -4
  183. package/dist/parser-RZPVAQVX.js +11 -0
  184. package/dist/parser-SOUJOEYI.js +13 -0
  185. package/dist/{parser-4FL2CMDG.js → parser-UQE5OWZI.js} +5 -5
  186. package/dist/{parser-NRAI6O25.js → parser-WAV5JRPT.js} +4 -4
  187. package/dist/{parser-KNSQSKQO.js → parser-YLKYBRIT.js} +5 -5
  188. package/dist/{parser-XKRP7QKP.js → parser-YS7TOS2K.js} +3 -3
  189. package/dist/{parser-AQETEVRW.js → parser-ZSOWUBML.js} +5 -5
  190. package/dist/{parser-CFZD5IBL.js → parser-ZTBATMLX.js} +4 -4
  191. package/dist/{renderer-VACVQYML.js → renderer-35HSIDMZ.js} +8 -8
  192. package/dist/{renderer-5MYBMBYO.js → renderer-4ITCHBT7.js} +5 -5
  193. package/dist/{renderer-CLJHQPBJ.js → renderer-67NPCBIS.js} +11 -11
  194. package/dist/{renderer-5NDVNDAZ.js → renderer-6GHYK7DX.js} +9 -9
  195. package/dist/{renderer-Z7I3W2PP.js → renderer-6RNGHC5Z.js} +8 -8
  196. package/dist/renderer-72LGR2YF.js +14 -0
  197. package/dist/{renderer-KQB7UGDS.js → renderer-7RH2SI3B.js} +3 -3
  198. package/dist/renderer-7SWMIFMM.js +21 -0
  199. package/dist/renderer-BBCEFILK.js +24 -0
  200. package/dist/{renderer-JGBKUCZD.js → renderer-BSW7SRIZ.js} +4 -4
  201. package/dist/{renderer-BYCNMBF7.js → renderer-BY533UWU.js} +11 -11
  202. package/dist/{renderer-6W5462RB.js → renderer-BZSBPTZJ.js} +9 -9
  203. package/dist/{renderer-7MVLWWQD.js → renderer-CXUC4KAD.js} +9 -9
  204. package/dist/{renderer-QIWVHWZO.js → renderer-DAXMXIKD.js} +3 -3
  205. package/dist/renderer-FZUKFUNZ.js +23 -0
  206. package/dist/renderer-G2NLGNKF.js +17 -0
  207. package/dist/renderer-GO3FE3RA.js +24 -0
  208. package/dist/{renderer-ZGNTUWC4.js → renderer-HPGR6USK.js} +8 -8
  209. package/dist/{renderer-UV6MI64M.js → renderer-HVCU2C3Z.js} +3 -3
  210. package/dist/renderer-ICJN2SA2.js +24 -0
  211. package/dist/{renderer-AWWAF6XD.js → renderer-INEXO7B6.js} +10 -10
  212. package/dist/{renderer-YY2OSF6E.js → renderer-KDYCFRBX.js} +8 -8
  213. package/dist/renderer-KY4KQBTF.js +19 -0
  214. package/dist/{renderer-B2OMQIQG.js → renderer-LBN65V45.js} +13 -13
  215. package/dist/{renderer-N43WR5GV.js → renderer-MGBWOCXG.js} +10 -10
  216. package/dist/{renderer-PGX2TKVS.js → renderer-O4JKUGKO.js} +8 -8
  217. package/dist/{renderer-4JHRUBE6.js → renderer-OOGFODWP.js} +10 -10
  218. package/dist/{renderer-6EEZHMH4.js → renderer-Q6ZKPLS6.js} +9 -9
  219. package/dist/{renderer-RPOA5YPZ.js → renderer-SZQ326M5.js} +12 -12
  220. package/dist/{renderer-ZRNG54CW.js → renderer-TKG6LS4U.js} +11 -11
  221. package/dist/{renderer-W4M6QLIJ.js → renderer-TQMZGDAX.js} +13 -13
  222. package/dist/renderer-radial-JELMHQ24.js +21 -0
  223. package/dist/{resolver-NOAA7ID7.js → resolver-FHBCO3PL.js} +3 -3
  224. package/dist/{state-parser-Z2V23ATR.js → state-parser-3REXRK3R.js} +4 -4
  225. package/dist/{state-renderer-B4DQBM6M.js → state-renderer-XYLNRWXR.js} +8 -8
  226. package/docs/ai-integration.md +12 -3
  227. package/docs/language-reference.md +429 -24
  228. package/gallery/fixtures/body.dgmo +17 -0
  229. package/gallery/fixtures/bracket.dgmo +30 -0
  230. package/gallery/fixtures/clock.dgmo +8 -0
  231. package/gallery/fixtures/countdown.dgmo +3 -0
  232. package/gallery/fixtures/family.dgmo +23 -0
  233. package/gallery/fixtures/goal.dgmo +4 -0
  234. package/gallery/fixtures/sketch.dgmo +22 -0
  235. package/package.json +12 -4
  236. package/dist/chunk-ODZVHU3R.js +0 -153
  237. package/dist/dgmo-router-X35VLZLM.js +0 -73
  238. package/dist/dimensions-J3FHIMJ6.js +0 -22
  239. package/dist/layout-5T6RH5M6.js +0 -14
  240. package/dist/layout-G23F7LDH.js +0 -9
  241. package/dist/layout-OB3RI63S.js +0 -14
  242. package/dist/parser-JAL2HD4I.js +0 -13
  243. package/dist/renderer-SMIBCRVB.js +0 -24
  244. package/dist/renderer-radial-C32GPJQ7.js +0 -21
@@ -0,0 +1,1043 @@
1
+ import {
2
+ renderCollapseBar,
3
+ renderNodeCard
4
+ } from "./chunk-AHGF2YYA.js";
5
+ import {
6
+ CARD_RADIUS,
7
+ CONTAINER_RADIUS
8
+ } from "./chunk-3CIOJ5YJ.js";
9
+ import {
10
+ renderIntegratedLegend
11
+ } from "./chunk-QUJGFNFN.js";
12
+ import {
13
+ getMaxLegendReservedHeight
14
+ } from "./chunk-7UEMZREK.js";
15
+ import {
16
+ FONT_FAMILY
17
+ } from "./chunk-6KFWC4CO.js";
18
+ import {
19
+ measureText,
20
+ wrapTextToWidth
21
+ } from "./chunk-5LWQH6QV.js";
22
+ import {
23
+ contrastText,
24
+ mix,
25
+ shapeFill
26
+ } from "./chunk-P6T66CCZ.js";
27
+ import {
28
+ resolveActiveTagGroup,
29
+ resolveTagColor,
30
+ tagAttrKey
31
+ } from "./chunk-WCUHAQKB.js";
32
+
33
+ // src/sketch/renderer.ts
34
+ import * as d3 from "d3-selection";
35
+
36
+ // src/sketch/markdown-card.ts
37
+ var BOLD_WIDTH_FACTOR = 1.06;
38
+ var INDENT_PX = 12;
39
+ var BULLET_HANG_PX = 12;
40
+ var ELLIPSIS = "\u2026";
41
+ var BULLET = "\u2022";
42
+ function segWidth(seg, fontSize) {
43
+ const w = measureText(seg.text, fontSize);
44
+ return seg.bold ? w * BOLD_WIDTH_FACTOR : w;
45
+ }
46
+ function parseInline(text) {
47
+ const segments = [];
48
+ const regex = /\*\*(.+?)\*\*|\[([^\]]*)\]\(([^)]*)\)|((?:(?!\*\*|\[).)+)/gs;
49
+ let m;
50
+ while ((m = regex.exec(text)) !== null) {
51
+ if (m[1] !== void 0) {
52
+ segments.push({ text: m[1], bold: true });
53
+ } else if (m[2] !== void 0) {
54
+ segments.push({ text: m[2], bold: false, ...m[3] && { href: m[3] } });
55
+ } else if (m[4] !== void 0) {
56
+ segments.push({ text: m[4], bold: false });
57
+ }
58
+ }
59
+ return segments;
60
+ }
61
+ function segmentsToWords(segments) {
62
+ const words = [];
63
+ let current = [];
64
+ for (const seg of segments) {
65
+ const parts = seg.text.split(/(\s+)/);
66
+ for (const part of parts) {
67
+ if (part === "") continue;
68
+ if (/^\s+$/.test(part)) {
69
+ if (current.length > 0) {
70
+ words.push(current);
71
+ current = [];
72
+ }
73
+ } else {
74
+ current.push({
75
+ text: part,
76
+ bold: seg.bold,
77
+ ...seg.href !== void 0 && { href: seg.href }
78
+ });
79
+ }
80
+ }
81
+ }
82
+ if (current.length > 0) words.push(current);
83
+ return words;
84
+ }
85
+ function wordWidth(word, fontSize) {
86
+ let w = 0;
87
+ for (const piece of word) w += segWidth(piece, fontSize);
88
+ return w;
89
+ }
90
+ function coalesce(pieces) {
91
+ const out = [];
92
+ for (const p of pieces) {
93
+ const last = out[out.length - 1];
94
+ if (last?.bold === p.bold && last.href === p.href) {
95
+ last.text += p.text;
96
+ } else {
97
+ out.push({
98
+ text: p.text,
99
+ bold: p.bold,
100
+ ...p.href !== void 0 && { href: p.href }
101
+ });
102
+ }
103
+ }
104
+ return out;
105
+ }
106
+ function wrapSegments(segments, fontSize, avail, textX, bulletX) {
107
+ const words = segmentsToWords(segments);
108
+ if (words.length === 0) {
109
+ return [
110
+ { segments: [], x: textX, ...bulletX !== void 0 && { bulletX } }
111
+ ];
112
+ }
113
+ const spaceW = measureText(" ", fontSize);
114
+ const lines = [];
115
+ let currentPieces = [];
116
+ let currentW = 0;
117
+ let first = true;
118
+ const flush = () => {
119
+ lines.push({
120
+ segments: coalesce(currentPieces),
121
+ x: textX,
122
+ // only the FIRST visual line of a bullet carries the marker
123
+ ...first && bulletX !== void 0 && { bulletX }
124
+ });
125
+ first = false;
126
+ currentPieces = [];
127
+ currentW = 0;
128
+ };
129
+ for (const word of words) {
130
+ const ww = wordWidth(word, fontSize);
131
+ const addW = currentPieces.length === 0 ? ww : spaceW + ww;
132
+ if (currentPieces.length > 0 && currentW + addW > avail) {
133
+ flush();
134
+ currentPieces.push(...word);
135
+ currentW = ww;
136
+ } else {
137
+ if (currentPieces.length > 0) {
138
+ currentPieces.push({ text: " ", bold: false });
139
+ currentW += spaceW;
140
+ }
141
+ currentPieces.push(...word);
142
+ currentW += ww;
143
+ }
144
+ }
145
+ flush();
146
+ return lines;
147
+ }
148
+ function parseLogicalLine(raw) {
149
+ let i = 0;
150
+ let level = 0;
151
+ let spaceRun = 0;
152
+ while (i < raw.length) {
153
+ const ch = raw[i];
154
+ if (ch === " ") {
155
+ level += 1;
156
+ i += 1;
157
+ spaceRun = 0;
158
+ } else if (ch === " ") {
159
+ spaceRun += 1;
160
+ i += 1;
161
+ if (spaceRun === 2) {
162
+ level += 1;
163
+ spaceRun = 0;
164
+ }
165
+ } else {
166
+ break;
167
+ }
168
+ }
169
+ let content = raw.slice(i);
170
+ let bullet = false;
171
+ if (content.startsWith("- ") || content.startsWith("* ")) {
172
+ bullet = true;
173
+ content = content.slice(2);
174
+ }
175
+ return { level, bullet, content };
176
+ }
177
+ function drawMarkdownBlock(container, text, opts) {
178
+ const { width, fontSize, lineHeight, color, linkColor, maxLines } = opts;
179
+ const visualLines = [];
180
+ for (const raw of text.split("\n")) {
181
+ const { level, bullet, content } = parseLogicalLine(raw);
182
+ const indentX = level * INDENT_PX;
183
+ const textX = bullet ? indentX + BULLET_HANG_PX : indentX;
184
+ const avail = Math.max(1, width - textX);
185
+ const segments = parseInline(content);
186
+ const wrapped = wrapSegments(
187
+ segments,
188
+ fontSize,
189
+ avail,
190
+ textX,
191
+ bullet ? indentX : void 0
192
+ );
193
+ visualLines.push(...wrapped);
194
+ }
195
+ let shown = visualLines;
196
+ let clamped = false;
197
+ if (maxLines !== void 0 && visualLines.length > maxLines) {
198
+ shown = visualLines.slice(0, maxLines);
199
+ clamped = true;
200
+ }
201
+ for (let li = 0; li < shown.length; li++) {
202
+ const line = shown[li];
203
+ const y = fontSize + li * lineHeight;
204
+ const isLast = li === shown.length - 1;
205
+ if (line.bulletX !== void 0) {
206
+ container.append("text").attr("x", line.bulletX).attr("y", y).attr("fill", color).attr("font-size", fontSize).text(BULLET);
207
+ }
208
+ const textEl = container.append("text").attr("x", line.x).attr("y", y).attr("font-size", fontSize);
209
+ let cursorX = line.x;
210
+ const segs = line.segments.slice();
211
+ if (clamped && isLast) {
212
+ segs.push({ text: ELLIPSIS, bold: false });
213
+ }
214
+ for (const seg of segs) {
215
+ const tspan = textEl.append("tspan").attr("x", cursorX).attr("fill", seg.href !== void 0 ? linkColor : color).text(seg.text);
216
+ if (seg.bold) tspan.attr("font-weight", "bold");
217
+ const w = segWidth(seg, fontSize);
218
+ if (seg.href !== void 0) {
219
+ tspan.attr("data-href", seg.href);
220
+ container.append("line").attr("x1", cursorX).attr("y1", y + 1.5).attr("x2", cursorX + w).attr("y2", y + 1.5).attr("stroke", linkColor).attr("stroke-width", 1);
221
+ }
222
+ cursorX += w;
223
+ }
224
+ }
225
+ return shown.length * lineHeight;
226
+ }
227
+
228
+ // src/sketch/renderer.ts
229
+ var DIAGRAM_PADDING = 20;
230
+ var TITLE_Y = 32;
231
+ var TITLE_FONT_SIZE = 18;
232
+ var NODE_STROKE_WIDTH = 2;
233
+ var EDGE_STROKE_WIDTH = 2;
234
+ var EDGE_HIT_WIDTH = 18;
235
+ var ARROWHEAD_W = 12;
236
+ var ARROWHEAD_H = 8;
237
+ var DASH = "6 3";
238
+ var BAND_LABEL_FONT_SIZE = 19;
239
+ var BAND_LABEL_OPACITY = 0.55;
240
+ var NOTE_FONT_SIZE = 11;
241
+ var COLLAPSE_BAR_HEIGHT = 4;
242
+ var EDGE_LABEL_FONT_SIZE = 12;
243
+ var CURVE_HANDLE_MIN = 24;
244
+ var CURVE_HANDLE_MAX = 90;
245
+ function drawNoteBody(g, w, h, colors) {
246
+ const f = 14;
247
+ g.append("path").attr(
248
+ "d",
249
+ `M0 2 a2 2 0 0 1 2 -2 h${w - f - 2} l${f} ${f} v${h - f - 2} a2 2 0 0 1 -2 2 h-${w - 4} a2 2 0 0 1 -2 -2 Z`
250
+ ).attr("fill", colors.fill).attr("stroke", colors.stroke).attr("stroke-width", NODE_STROKE_WIDTH);
251
+ g.append("path").attr("d", `M${w - f} 0 v${f} h${f}`).attr("fill", "none").attr("stroke", colors.stroke).attr("stroke-width", 1.2);
252
+ }
253
+ function drawTypeBadge(g, kind, color, bx, by) {
254
+ const b = g.append("g").attr("transform", `translate(${bx},${by})`).attr("fill", "none").attr("stroke", color).attr("stroke-width", 1.3).attr("stroke-linejoin", "round").attr("stroke-linecap", "round");
255
+ switch (kind) {
256
+ case "database":
257
+ b.append("ellipse").attr("cx", 8).attr("cy", 3).attr("rx", 6).attr("ry", 2.4);
258
+ b.append("path").attr("d", "M2 3 v10 a6 2.4 0 0 0 12 0 v-10");
259
+ return;
260
+ case "queue":
261
+ b.append("path").attr("d", "M3 1 h8 a3 6.5 0 0 1 0 13 h-8 Z");
262
+ b.append("ellipse").attr("cx", 3).attr("cy", 7.5).attr("rx", 3).attr("ry", 6.5);
263
+ return;
264
+ case "document":
265
+ b.append("path").attr("d", "M2 1 h9 v11 q-4.5 2 -9 0 q0 0 0 0 Z");
266
+ return;
267
+ case "person":
268
+ b.append("circle").attr("cx", 8).attr("cy", 5).attr("r", 3);
269
+ b.append("path").attr("d", "M2 15 a6 5 0 0 1 12 0");
270
+ return;
271
+ default:
272
+ return;
273
+ }
274
+ }
275
+ function metaRows(metadata, tagGroups) {
276
+ const rows = [];
277
+ for (const grp of tagGroups) {
278
+ const v = metadata[tagAttrKey(grp.name)];
279
+ if (v !== void 0) rows.push([grp.name, v]);
280
+ }
281
+ return rows;
282
+ }
283
+ var CARD_HEADER_H = 34;
284
+ var CARD_LABEL_MAX = 15;
285
+ var CARD_LABEL_MIN = 11;
286
+ var CARD_META_FONT = 12;
287
+ var CARD_TITLE_MAX = 30;
288
+ function fitWrapped(label, maxWidth, maxFont = CARD_LABEL_MAX, minFont = CARD_LABEL_MIN, maxLines = 2) {
289
+ for (let fs = maxFont; fs >= minFont; fs--) {
290
+ const lines2 = wrapTextToWidth(label, fs, maxWidth, { hardBreak: true });
291
+ if (lines2.length <= maxLines) return { lines: lines2, fontSize: fs };
292
+ }
293
+ const lines = wrapTextToWidth(label, minFont, maxWidth, { hardBreak: true });
294
+ if (lines.length <= maxLines) return { lines, fontSize: minFont };
295
+ const kept = lines.slice(0, maxLines);
296
+ let last = kept[maxLines - 1];
297
+ while (last.length > 1 && measureText(`${last}\u2026`, minFont) > maxWidth)
298
+ last = last.slice(0, -1);
299
+ kept[maxLines - 1] = `${last}\u2026`;
300
+ return { lines: kept, fontSize: minFont };
301
+ }
302
+ function renderSketch(container, parsed, layout, palette, isDark, options = {}) {
303
+ const {
304
+ activeTagGroup,
305
+ exportMode = false,
306
+ hideDescriptions = false
307
+ } = options;
308
+ const hideDesc = hideDescriptions || parsed.options.noDescriptions;
309
+ const neutralFill = mix(palette.textMuted, palette.bg, 12);
310
+ const tagGroups = [...parsed.tagGroups];
311
+ const activeName = resolveActiveTagGroup(
312
+ tagGroups,
313
+ void 0,
314
+ activeTagGroup
315
+ );
316
+ const activeKey = activeName === null ? null : tagAttrKey(activeName);
317
+ const colorsFor = (metadata, isContainer = false) => {
318
+ const tagged = activeKey !== null && metadata[activeKey] !== void 0;
319
+ const tagColor = tagged ? resolveTagColor(metadata, tagGroups, activeName, isContainer) : void 0;
320
+ if (!tagColor) {
321
+ return {
322
+ fill: neutralFill,
323
+ stroke: palette.textMuted,
324
+ text: palette.text
325
+ };
326
+ }
327
+ const fill = shapeFill(palette, tagColor, isDark, {
328
+ solid: parsed.options.solidFill
329
+ });
330
+ return {
331
+ fill,
332
+ stroke: tagColor,
333
+ // Label text takes the shape's own (tag) color — but for solid fills the
334
+ // tag color would vanish into the fill, so keep a contrast color there.
335
+ text: parsed.options.solidFill ? contrastText(fill, palette.textOnFillLight, palette.textOnFillDark) : tagColor
336
+ };
337
+ };
338
+ const showTitle = !!parsed.title;
339
+ const titleOffset = showTitle ? 40 : 0;
340
+ const legendGroups = parsed.options.noLegend ? [] : tagGroups;
341
+ const edgeGeom = sketchEdgeGeometry(layout);
342
+ let minX = 0;
343
+ let minY = 0;
344
+ let maxX = layout.width;
345
+ let maxY = layout.height;
346
+ for (let i = 0; i < edgeGeom.length; i++) {
347
+ const g = edgeGeom[i];
348
+ if (!g) continue;
349
+ const nums = (g.d.match(/-?[\d.]+/g) ?? []).map(Number);
350
+ for (let k = 0; k + 1 < nums.length; k += 2) {
351
+ minX = Math.min(minX, nums[k]);
352
+ maxX = Math.max(maxX, nums[k]);
353
+ minY = Math.min(minY, nums[k + 1]);
354
+ maxY = Math.max(maxY, nums[k + 1]);
355
+ }
356
+ const label = layout.edges[i]?.label;
357
+ if (label) {
358
+ const hw = measureText(label, EDGE_LABEL_FONT_SIZE) / 2 + 6;
359
+ const hh = EDGE_LABEL_FONT_SIZE / 2 + 4;
360
+ minX = Math.min(minX, g.mid.x - hw);
361
+ maxX = Math.max(maxX, g.mid.x + hw);
362
+ minY = Math.min(minY, g.mid.y - hh);
363
+ maxY = Math.max(maxY, g.mid.y + hh);
364
+ }
365
+ }
366
+ const extraLeft = Math.max(0, -minX);
367
+ const extraTop = Math.max(0, -minY);
368
+ const boundW = maxX + extraLeft;
369
+ const contentWidth = boundW + 2 * DIAGRAM_PADDING;
370
+ const width = Math.max(contentWidth, options.exportDims?.width ?? 0);
371
+ const legendHeight = legendGroups.length > 0 ? getMaxLegendReservedHeight(
372
+ {
373
+ groups: legendGroups,
374
+ position: { placement: "top-center", titleRelation: "below-title" },
375
+ mode: exportMode ? "export" : "preview"
376
+ },
377
+ width
378
+ ) : 0;
379
+ const contentTop = titleOffset + legendHeight + DIAGRAM_PADDING + extraTop;
380
+ const height = Math.max(
381
+ contentTop + maxY + DIAGRAM_PADDING,
382
+ options.exportDims?.height ?? 0
383
+ );
384
+ d3.select(container).selectAll("*").remove();
385
+ const svg = d3.select(container).append("svg").attr("width", width).attr("height", height).attr("viewBox", `0 0 ${width} ${height}`).style("font-family", FONT_FAMILY);
386
+ const defs = svg.append("defs");
387
+ const edgeColorFor = (metadata) => {
388
+ if (activeKey !== null && metadata[activeKey] !== void 0) {
389
+ const c = resolveTagColor(metadata, tagGroups, activeName);
390
+ if (c && c !== "#999999") return c;
391
+ }
392
+ return palette.textMuted;
393
+ };
394
+ const flowColor = (edge) => edgeColorFor(edge.metadata);
395
+ const edgeColors = new Set(layout.edges.map((e) => flowColor(e)));
396
+ for (const color of edgeColors) {
397
+ const hex = color.replace("#", "");
398
+ defs.append("marker").attr("id", `sk-arrow-${hex}`).attr("viewBox", `0 0 ${ARROWHEAD_W} ${ARROWHEAD_H}`).attr("refX", ARROWHEAD_W).attr("refY", ARROWHEAD_H / 2).attr("markerWidth", ARROWHEAD_W).attr("markerHeight", ARROWHEAD_H).attr("markerUnits", "userSpaceOnUse").attr("orient", "auto").append("polygon").attr("points", `0,0 ${ARROWHEAD_W},${ARROWHEAD_H / 2} 0,${ARROWHEAD_H}`).attr("fill", color);
399
+ defs.append("marker").attr("id", `sk-arrow-rev-${hex}`).attr("viewBox", `0 0 ${ARROWHEAD_W} ${ARROWHEAD_H}`).attr("refX", 0).attr("refY", ARROWHEAD_H / 2).attr("markerWidth", ARROWHEAD_W).attr("markerHeight", ARROWHEAD_H).attr("markerUnits", "userSpaceOnUse").attr("orient", "auto").append("polygon").attr(
400
+ "points",
401
+ `${ARROWHEAD_W},0 0,${ARROWHEAD_H / 2} ${ARROWHEAD_W},${ARROWHEAD_H}`
402
+ ).attr("fill", color);
403
+ }
404
+ if (showTitle) {
405
+ svg.append("text").attr("x", width / 2).attr("y", TITLE_Y).attr("text-anchor", "middle").attr("font-size", TITLE_FONT_SIZE).attr("font-weight", 700).attr("fill", palette.text).text(parsed.title);
406
+ }
407
+ if (legendGroups.length > 0) {
408
+ const legendG = svg.append("g").attr("transform", `translate(0,${titleOffset + 4})`);
409
+ renderIntegratedLegend(legendG, {
410
+ groups: legendGroups,
411
+ ...activeName !== null && { activeGroup: activeName },
412
+ mode: exportMode ? "export" : "preview",
413
+ showInactivePills: true,
414
+ palette,
415
+ isDark,
416
+ width
417
+ });
418
+ legendG.selectAll("[data-legend-group]").classed("sk-legend-group", true);
419
+ }
420
+ const contentX = DIAGRAM_PADDING + extraLeft + Math.max(0, (width - contentWidth) / 2);
421
+ const root = svg.append("g").attr("class", "sk-root").attr("transform", `translate(${contentX},${contentTop})`);
422
+ const boxLayer = root.append("g").attr("class", "sk-boxes");
423
+ for (const box of layout.boxes) {
424
+ drawBoxFrame(boxLayer, box, colorsFor(box.metadata, true), palette);
425
+ }
426
+ const edgeLayer = root.append("g").attr("class", "sk-edges");
427
+ const labelLayerData = [];
428
+ for (let ei = 0; ei < layout.edges.length; ei++) {
429
+ const edge = layout.edges[ei];
430
+ const geo = edgeGeom[ei];
431
+ if (!geo) continue;
432
+ const color = flowColor(edge);
433
+ const hex = color.replace("#", "");
434
+ const { d, mid } = geo;
435
+ const g = edgeLayer.append("g").attr("class", "sk-edge-group").attr("data-from", edge.sourceId).attr("data-to", edge.targetId).attr("data-line-number", edge.lineNumber);
436
+ const path = g.append("path").attr("d", geo.dRender ?? d).attr("fill", "none").attr("stroke", color).attr("stroke-width", EDGE_STROKE_WIDTH);
437
+ if (edge.dashed) path.attr("stroke-dasharray", DASH);
438
+ if (edge.heads === "one" || edge.heads === "both") {
439
+ path.attr("marker-end", `url(#sk-arrow-${hex})`);
440
+ }
441
+ if (edge.heads === "both") {
442
+ path.attr("marker-start", `url(#sk-arrow-rev-${hex})`);
443
+ }
444
+ g.append("path").attr("class", "sk-edge-hit").attr("d", d).attr("fill", "none").attr("stroke", "transparent").attr("stroke-width", EDGE_HIT_WIDTH).attr("stroke-linecap", "round").attr("pointer-events", "stroke");
445
+ if (edge.label) {
446
+ labelLayerData.push({
447
+ x: mid.x,
448
+ y: mid.y,
449
+ text: edge.label,
450
+ color,
451
+ from: edge.sourceId,
452
+ to: edge.targetId,
453
+ ei,
454
+ cp: (d.match(/-?[\d.]+/g) ?? []).map(Number)
455
+ });
456
+ }
457
+ }
458
+ {
459
+ const labelW = (t) => t.length * EDGE_LABEL_FONT_SIZE * 0.56;
460
+ const halfH = EDGE_LABEL_FONT_SIZE / 2 + 3;
461
+ const GAP = 4;
462
+ const shapeRects = [
463
+ ...layout.nodes.map((n) => ({ x: n.x, y: n.y, w: n.w, h: n.h })),
464
+ ...layout.boxes.map((b) => ({ x: b.x, y: b.y, w: b.w, h: b.h }))
465
+ ];
466
+ const cubicPt = (cp, t) => {
467
+ const u = 1 - t;
468
+ const a = u * u * u;
469
+ const b = 3 * u * u * t;
470
+ const c = 3 * u * t * t;
471
+ const dd = t * t * t;
472
+ return {
473
+ x: a * cp[0] + b * cp[2] + c * cp[4] + dd * cp[6],
474
+ y: a * cp[1] + b * cp[3] + c * cp[5] + dd * cp[7]
475
+ };
476
+ };
477
+ const allPolys = edgeGeom.map((g) => {
478
+ if (!g) return null;
479
+ const cp = (g.d.match(/-?[\d.]+/g) ?? []).map(Number);
480
+ if (cp.length < 8) return null;
481
+ const pts = [];
482
+ for (let s = 0; s <= 32; s++) pts.push(cubicPt(cp, s / 32));
483
+ return pts;
484
+ });
485
+ const covers = (cx, cy, hw, ox, oy, ohw, ohh) => Math.abs(cx - ox) < hw + ohw + GAP && Math.abs(cy - oy) < halfH + ohh + GAP;
486
+ const placed = [];
487
+ const TS = [0.5, 0.4, 0.6, 0.32, 0.68, 0.25, 0.75, 0.18, 0.82];
488
+ for (const l of labelLayerData) {
489
+ const hw = labelW(l.text) / 2 + 3;
490
+ let bestT = 0.5;
491
+ let bestScore = Infinity;
492
+ for (const t of TS) {
493
+ const p2 = cubicPt(l.cp, t);
494
+ let labelHits = 0;
495
+ for (const q of placed)
496
+ if (covers(p2.x, p2.y, hw, q.x, q.y, q.hw, halfH)) labelHits++;
497
+ let shapeHits = 0;
498
+ for (const r of shapeRects)
499
+ if (covers(p2.x, p2.y, hw, r.x + r.w / 2, r.y + r.h / 2, r.w / 2, r.h / 2))
500
+ shapeHits++;
501
+ let lineHits = 0;
502
+ for (let k = 0; k < allPolys.length; k++) {
503
+ if (k === l.ei) continue;
504
+ const poly = allPolys[k];
505
+ if (poly?.some((pt) => covers(p2.x, p2.y, hw, pt.x, pt.y, 0, 0)))
506
+ lineHits++;
507
+ }
508
+ if (labelHits === 0 && shapeHits === 0 && lineHits === 0) {
509
+ bestT = t;
510
+ break;
511
+ }
512
+ const score = labelHits * 10 + shapeHits * 6 + lineHits * 4 + Math.abs(t - 0.5);
513
+ if (score < bestScore) {
514
+ bestScore = score;
515
+ bestT = t;
516
+ }
517
+ }
518
+ const p = cubicPt(l.cp, bestT);
519
+ l.x = p.x;
520
+ l.y = p.y;
521
+ placed.push({ x: p.x, y: p.y, hw });
522
+ }
523
+ }
524
+ const nodeLayer = root.append("g").attr("class", "sk-nodes");
525
+ for (const node of layout.nodes) {
526
+ let n = node;
527
+ if (hideDesc && node.description) {
528
+ n = { ...node };
529
+ delete n.description;
530
+ }
531
+ drawNode(
532
+ nodeLayer,
533
+ n,
534
+ colorsFor(node.metadata),
535
+ palette,
536
+ isDark,
537
+ hideDesc ? [] : tagGroups
538
+ );
539
+ }
540
+ const labelLayer = root.append("g").attr("class", "sk-edge-labels");
541
+ for (const l of labelLayerData) {
542
+ const g = labelLayer.append("g").attr("class", "sk-edge-label").attr("data-from", l.from).attr("data-to", l.to);
543
+ g.append("text").attr("x", l.x).attr("y", l.y).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", EDGE_LABEL_FONT_SIZE).attr("fill", l.color).attr("stroke", palette.bg).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("paint-order", "stroke").text(l.text);
544
+ }
545
+ if (options.onClickItem) {
546
+ const handler = options.onClickItem;
547
+ svg.selectAll("[data-line-number]").on("click", function() {
548
+ const ln = Number(this.getAttribute("data-line-number"));
549
+ if (Number.isFinite(ln) && ln > 0) handler(ln);
550
+ });
551
+ }
552
+ }
553
+ function drawBoxFrame(layer, box, colors, palette) {
554
+ const g = layer.append("g").attr("class", "sk-box").attr("data-node-id", box.id).attr("data-group-toggle", box.label).attr("data-line-number", box.lineNumber);
555
+ g.append("rect").attr("x", box.x).attr("y", box.y).attr("width", box.w).attr("height", box.h).attr("rx", CONTAINER_RADIUS).attr("fill", colors.fill).attr("fill-opacity", 0.4).attr("stroke", colors.stroke).attr("stroke-opacity", 0.7).attr("stroke-width", NODE_STROKE_WIDTH);
556
+ const fit = fitWrapped(box.label, box.w - 16, BAND_LABEL_FONT_SIZE, 12, 2);
557
+ const lineH = fit.fontSize * 1.2;
558
+ const bandMid = box.y + box.bandH / 2;
559
+ const startY = bandMid - (fit.lines.length - 1) * lineH / 2;
560
+ for (let li = 0; li < fit.lines.length; li++) {
561
+ g.append("text").attr("x", box.x + box.w / 2).attr("y", startY + li * lineH).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", fit.fontSize).attr("font-weight", 800).attr("fill", palette.text).attr("opacity", BAND_LABEL_OPACITY).text(fit.lines[li]);
562
+ }
563
+ }
564
+ function drawNode(layer, node, colors, palette, isDark, tagGroups) {
565
+ void isDark;
566
+ const g = layer.append("g").attr("class", node.isCollapsedBox ? "sk-node sk-box-collapsed" : "sk-node").attr("transform", `translate(${node.x},${node.y})`).attr("data-node-id", node.id).attr("data-line-number", node.lineNumber);
567
+ for (const [k, v] of Object.entries(node.metadata)) {
568
+ g.attr(`data-tag-${k}`, v);
569
+ }
570
+ if (node.isCollapsedBox) {
571
+ g.attr("data-group-toggle", node.label);
572
+ }
573
+ if (node.shape === "note") {
574
+ drawNoteBody(g, node.w, node.h, colors);
575
+ const lines = wrapTextToWidth(node.label, NOTE_FONT_SIZE, node.w - 34);
576
+ const lineHeight = NOTE_FONT_SIZE + 4;
577
+ lines.slice(0, 5).forEach((line, i) => {
578
+ g.append("text").attr("x", 10).attr("y", 20 + i * lineHeight).attr("font-size", NOTE_FONT_SIZE).attr("fill", colors.text).text(line);
579
+ });
580
+ } else {
581
+ const rows = node.isCollapsedBox ? [] : metaRows(node.metadata, tagGroups);
582
+ const badge = node.shape !== "rectangle";
583
+ const labelInset = badge ? 22 : 0;
584
+ const solid = colors.stroke === colors.fill;
585
+ const ruleColor = solid ? colors.text : colors.stroke;
586
+ if (node.description && !node.isCollapsedBox) {
587
+ const fitH = fitWrapped(
588
+ node.label,
589
+ node.w - 24 - labelInset,
590
+ CARD_LABEL_MAX,
591
+ CARD_LABEL_MIN,
592
+ 1
593
+ );
594
+ renderNodeCard(g, {
595
+ width: node.w,
596
+ height: node.h,
597
+ rx: CARD_RADIUS,
598
+ fill: colors.fill,
599
+ stroke: colors.stroke,
600
+ strokeWidth: NODE_STROKE_WIDTH,
601
+ label: fitH.lines[0] ?? node.label,
602
+ labelColor: colors.text,
603
+ labelFontSize: fitH.fontSize,
604
+ headerHeight: CARD_HEADER_H
605
+ });
606
+ g.append("line").attr("x1", 0).attr("y1", CARD_HEADER_H).attr("x2", node.w).attr("y2", CARD_HEADER_H).attr("stroke", ruleColor).attr("stroke-opacity", 0.3).attr("stroke-width", 1);
607
+ const inset = 12;
608
+ const bodyGap = 8;
609
+ const lh = CARD_META_FONT + 4;
610
+ const avail = node.h - CARD_HEADER_H - bodyGap - 8;
611
+ const body = g.append("g").attr("class", "sk-desc").attr("transform", `translate(${inset} ${CARD_HEADER_H + bodyGap})`);
612
+ drawMarkdownBlock(body, node.description, {
613
+ width: node.w - inset * 2,
614
+ fontSize: CARD_META_FONT,
615
+ lineHeight: lh,
616
+ color: colors.text,
617
+ // match the header label (contrast-aware in solid)
618
+ linkColor: colors.text,
619
+ maxLines: Math.max(1, Math.floor(avail / lh))
620
+ });
621
+ if (badge) {
622
+ drawTypeBadge(g, node.shape, colors.text, 10, (CARD_HEADER_H - 16) / 2);
623
+ }
624
+ return;
625
+ }
626
+ const headerH = rows.length ? CARD_HEADER_H : node.h;
627
+ const fillTitle = rows.length === 0;
628
+ const fit = fitWrapped(
629
+ node.label,
630
+ node.w - 24 - labelInset,
631
+ fillTitle ? CARD_TITLE_MAX : CARD_LABEL_MAX,
632
+ CARD_LABEL_MIN,
633
+ fillTitle ? 3 : 2
634
+ );
635
+ renderNodeCard(g, {
636
+ width: node.w,
637
+ height: node.h,
638
+ rx: CARD_RADIUS,
639
+ fill: colors.fill,
640
+ stroke: colors.stroke,
641
+ strokeWidth: NODE_STROKE_WIDTH,
642
+ label: fit.lines.join(" "),
643
+ labelLines: fit.lines,
644
+ labelColor: colors.text,
645
+ labelFontSize: fit.fontSize,
646
+ headerHeight: headerH,
647
+ ...rows.length ? {
648
+ meta: {
649
+ rows,
650
+ fontSize: CARD_META_FONT,
651
+ lineHeight: CARD_META_FONT + 5,
652
+ separatorGap: 8,
653
+ separatorColor: ruleColor,
654
+ textColor: solid ? colors.text : palette.text,
655
+ keyX: 12
656
+ }
657
+ } : {}
658
+ });
659
+ if (badge) {
660
+ drawTypeBadge(g, node.shape, colors.text, 10, (CARD_HEADER_H - 16) / 2);
661
+ }
662
+ }
663
+ if (node.isCollapsedBox) {
664
+ renderCollapseBar(g, {
665
+ width: node.w,
666
+ height: node.h,
667
+ barHeight: COLLAPSE_BAR_HEIGHT,
668
+ inset: 0,
669
+ rx: CARD_RADIUS,
670
+ fill: colors.stroke === palette.textMuted ? palette.textMuted : colors.stroke,
671
+ clipId: `sk-clip-${node.id.replace(/[^a-zA-Z0-9_-]/g, "")}-${node.lineNumber}`,
672
+ className: "sk-collapse-bar"
673
+ });
674
+ }
675
+ }
676
+ function assignEdgeSides(edges, rectById) {
677
+ const cx = (r) => r.x + r.w / 2;
678
+ const cy = (r) => r.y + r.h / 2;
679
+ const facing = (dx, dy) => Math.abs(dx) >= Math.abs(dy) ? dx >= 0 ? "R" : "L" : dy >= 0 ? "B" : "T";
680
+ return edges.map((e) => {
681
+ const s = rectById.get(e.sourceId);
682
+ const t = rectById.get(e.targetId);
683
+ if (!s || !t) return null;
684
+ const dx = cx(t) - cx(s);
685
+ const dy = cy(t) - cy(s);
686
+ const xOverlap = Math.min(s.x + s.w, t.x + t.w) - Math.max(s.x, t.x);
687
+ const yOverlap = Math.min(s.y + s.h, t.y + t.h) - Math.max(s.y, t.y);
688
+ if (xOverlap >= 0 && xOverlap >= yOverlap) {
689
+ const below = dy >= 0;
690
+ return { s: below ? "B" : "T", t: below ? "T" : "B" };
691
+ }
692
+ if (yOverlap >= 0 && yOverlap >= xOverlap) {
693
+ const right = dx >= 0;
694
+ return { s: right ? "R" : "L", t: right ? "L" : "R" };
695
+ }
696
+ return { s: facing(dx, dy), t: facing(-dx, -dy) };
697
+ });
698
+ }
699
+ function edgePath(source, target, sSide, tSide, sourcePorts, targetPorts) {
700
+ const acx = source.x + source.w / 2;
701
+ const acy = source.y + source.h / 2;
702
+ const bcx = target.x + target.w / 2;
703
+ const bcy = target.y + target.h / 2;
704
+ const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
705
+ const nearest = (arr, v) => arr.reduce((a, b) => Math.abs(b - v) < Math.abs(a - v) ? b : a, arr[0]);
706
+ const attach = (side, rect, ports, toward) => {
707
+ if (side === "L" || side === "R") {
708
+ const x2 = side === "L" ? rect.x : rect.x + rect.w;
709
+ const y2 = ports ? clamp(nearest(ports.ys, toward.y), rect.y, rect.y + rect.h) : rect.y + rect.h / 2;
710
+ return { x: x2, y: y2 };
711
+ }
712
+ const y = side === "T" ? rect.y : rect.y + rect.h;
713
+ const x = ports ? clamp(nearest(ports.xs, toward.x), rect.x, rect.x + rect.w) : rect.x + rect.w / 2;
714
+ return { x, y };
715
+ };
716
+ const normal = (side) => side === "L" ? { x: -1, y: 0 } : side === "R" ? { x: 1, y: 0 } : side === "T" ? { x: 0, y: -1 } : { x: 0, y: 1 };
717
+ const p0 = attach(sSide, source, sourcePorts, { x: bcx, y: bcy });
718
+ const p1 = attach(tSide, target, targetPorts, { x: acx, y: acy });
719
+ const n0 = normal(sSide);
720
+ const n1 = normal(tSide);
721
+ const k = Math.max(
722
+ CURVE_HANDLE_MIN,
723
+ Math.min(CURVE_HANDLE_MAX, Math.hypot(p1.x - p0.x, p1.y - p0.y) / 2)
724
+ );
725
+ const h0 = { x: p0.x + n0.x * k, y: p0.y + n0.y * k };
726
+ const h1 = { x: p1.x + n1.x * k, y: p1.y + n1.y * k };
727
+ return {
728
+ d: `M ${p0.x} ${p0.y} C ${h0.x} ${h0.y}, ${h1.x} ${h1.y}, ${p1.x} ${p1.y}`,
729
+ // Centered ON the line at its ARC midpoint (t=0.5 on the cubic), not the
730
+ // endpoint average: for a straight edge the two coincide, but for a curve
731
+ // that bulges out to route around a shape the arc midpoint sits at the
732
+ // bulge apex — in open space — while the endpoint average would land on the
733
+ // very shape the edge detoured past. The opaque halo masks the line behind.
734
+ mid: {
735
+ x: 0.125 * p0.x + 0.375 * h0.x + 0.375 * h1.x + 0.125 * p1.x,
736
+ y: 0.125 * p0.y + 0.375 * h0.y + 0.375 * h1.y + 0.125 * p1.y
737
+ },
738
+ p0,
739
+ h0,
740
+ h1,
741
+ p1
742
+ };
743
+ }
744
+ var SIDES = ["T", "B", "L", "R"];
745
+ function cubicAt(g, t) {
746
+ const u = 1 - t;
747
+ const a = u * u * u;
748
+ const b = 3 * u * u * t;
749
+ const c = 3 * u * t * t;
750
+ const dd = t * t * t;
751
+ return {
752
+ x: a * g.p0.x + b * g.h0.x + c * g.h1.x + dd * g.p1.x,
753
+ y: a * g.p0.y + b * g.h0.y + c * g.h1.y + dd * g.p1.y
754
+ };
755
+ }
756
+ var EDGE_OBSTACLE_INSET = 6;
757
+ var EDGE_SAMPLES = 24;
758
+ var POLY_SAMPLES = 19;
759
+ function polyline(g) {
760
+ const pts = [];
761
+ for (let i = 0; i <= POLY_SAMPLES; i++)
762
+ pts.push(cubicAt(g, i / POLY_SAMPLES));
763
+ return pts;
764
+ }
765
+ function segmentsCross(p, p2, q, q2) {
766
+ const o = (a, b, c) => (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
767
+ const d1 = o(p, p2, q);
768
+ const d2 = o(p, p2, q2);
769
+ const d32 = o(q, q2, p);
770
+ const d4 = o(q, q2, p2);
771
+ return (d1 > 0 && d2 < 0 || d1 < 0 && d2 > 0) && (d32 > 0 && d4 < 0 || d32 < 0 && d4 > 0);
772
+ }
773
+ function polyCrossings(a, b) {
774
+ let n = 0;
775
+ for (let i = 0; i + 1 < a.length; i++)
776
+ for (let j = 0; j + 1 < b.length; j++)
777
+ if (segmentsCross(a[i], a[i + 1], b[j], b[j + 1])) n++;
778
+ return n;
779
+ }
780
+ function polyIntersection(a, b) {
781
+ for (let i = 0; i + 1 < a.length; i++) {
782
+ const p = a[i];
783
+ const p2 = a[i + 1];
784
+ for (let j = 0; j + 1 < b.length; j++) {
785
+ const q = b[j];
786
+ const q2 = b[j + 1];
787
+ if (!segmentsCross(p, p2, q, q2)) continue;
788
+ const rx = p2.x - p.x;
789
+ const ry = p2.y - p.y;
790
+ const sx = q2.x - q.x;
791
+ const sy = q2.y - q.y;
792
+ const denom = rx * sy - ry * sx;
793
+ if (denom === 0) continue;
794
+ const t = ((q.x - p.x) * sy - (q.y - p.y) * sx) / denom;
795
+ return { x: p.x + t * rx, y: p.y + t * ry };
796
+ }
797
+ }
798
+ return null;
799
+ }
800
+ var HOP_R = 7;
801
+ function hoppedPath(g, hops) {
802
+ if (hops.length === 0) return null;
803
+ const N = 49;
804
+ const pts = [];
805
+ for (let s = 0; s <= N; s++) pts.push(cubicAt(g, s / N));
806
+ const onSeg = /* @__PURE__ */ new Map();
807
+ for (const hp of hops) {
808
+ let bestSeg = -1;
809
+ let bestD = Infinity;
810
+ let bestPt = null;
811
+ for (let k = 1; k <= N; k++) {
812
+ const a = pts[k - 1];
813
+ const b = pts[k];
814
+ const dx = b.x - a.x;
815
+ const dy = b.y - a.y;
816
+ const len2 = dx * dx + dy * dy || 1;
817
+ let f = ((hp.x - a.x) * dx + (hp.y - a.y) * dy) / len2;
818
+ f = Math.max(0, Math.min(1, f));
819
+ const px = a.x + f * dx;
820
+ const py = a.y + f * dy;
821
+ const d2 = Math.hypot(hp.x - px, hp.y - py);
822
+ if (d2 < bestD) {
823
+ bestD = d2;
824
+ bestSeg = k;
825
+ bestPt = { x: px, y: py };
826
+ }
827
+ }
828
+ if (bestSeg >= 3 && bestSeg <= N - 3 && bestPt && !onSeg.has(bestSeg))
829
+ onSeg.set(bestSeg, bestPt);
830
+ }
831
+ if (onSeg.size === 0) return null;
832
+ let d = `M ${pts[0].x} ${pts[0].y}`;
833
+ for (let k = 1; k <= N; k++) {
834
+ const a = pts[k - 1];
835
+ const b = pts[k];
836
+ const hp = onSeg.get(k);
837
+ if (hp) {
838
+ const segLen = Math.hypot(b.x - a.x, b.y - a.y) || 1;
839
+ const dir = { x: (b.x - a.x) / segLen, y: (b.y - a.y) / segLen };
840
+ let perp = { x: dir.y, y: -dir.x };
841
+ if (perp.y > 0) perp = { x: -perp.x, y: -perp.y };
842
+ const A = { x: hp.x - dir.x * HOP_R, y: hp.y - dir.y * HOP_R };
843
+ const B = { x: hp.x + dir.x * HOP_R, y: hp.y + dir.y * HOP_R };
844
+ const k1 = {
845
+ x: A.x + perp.x * HOP_R * 1.33,
846
+ y: A.y + perp.y * HOP_R * 1.33
847
+ };
848
+ const k2 = {
849
+ x: B.x + perp.x * HOP_R * 1.33,
850
+ y: B.y + perp.y * HOP_R * 1.33
851
+ };
852
+ d += ` L ${A.x} ${A.y} C ${k1.x} ${k1.y}, ${k2.x} ${k2.y}, ${B.x} ${B.y} L ${b.x} ${b.y}`;
853
+ } else {
854
+ d += ` L ${b.x} ${b.y}`;
855
+ }
856
+ }
857
+ return d;
858
+ }
859
+ function pathCrossings(g, obstacles) {
860
+ if (obstacles.length === 0) return 0;
861
+ let hits = 0;
862
+ for (let i = 1; i < EDGE_SAMPLES; i++) {
863
+ const p = cubicAt(g, i / EDGE_SAMPLES);
864
+ for (const r of obstacles) {
865
+ const x0 = r.x + EDGE_OBSTACLE_INSET;
866
+ const y0 = r.y + EDGE_OBSTACLE_INSET;
867
+ const x1 = r.x + r.w - EDGE_OBSTACLE_INSET;
868
+ const y1 = r.y + r.h - EDGE_OBSTACLE_INSET;
869
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1) {
870
+ hits++;
871
+ break;
872
+ }
873
+ }
874
+ }
875
+ return hits;
876
+ }
877
+ function sketchEdgeGeometry(layout, offsets) {
878
+ const off = (id) => offsets?.get(id) ?? { dx: 0, dy: 0 };
879
+ const rectById = /* @__PURE__ */ new Map();
880
+ for (const n of layout.nodes) {
881
+ const o = off(n.id);
882
+ rectById.set(n.id, { x: n.x + o.dx, y: n.y + o.dy, w: n.w, h: n.h });
883
+ }
884
+ for (const b of layout.boxes) {
885
+ const o = off(b.id);
886
+ rectById.set(b.id, { x: b.x + o.dx, y: b.y + o.dy, w: b.w, h: b.h });
887
+ }
888
+ const portsById = /* @__PURE__ */ new Map();
889
+ for (const box of layout.boxes) {
890
+ const o = off(box.id);
891
+ const kids = layout.nodes.filter((n) => n.boxLabel === box.label);
892
+ const ys = kids.map((k) => k.y + off(k.id).dy + k.h / 2);
893
+ const xs = kids.map((k) => k.x + off(k.id).dx + k.w / 2);
894
+ ys.push(box.y + o.dy + box.h / 2);
895
+ xs.push(box.x + o.dx + box.w / 2);
896
+ portsById.set(box.id, { ys, xs });
897
+ }
898
+ const sides = assignEdgeSides(layout.edges, rectById);
899
+ const boxIdByLabel = /* @__PURE__ */ new Map();
900
+ for (const b of layout.boxes) boxIdByLabel.set(b.label, b.id);
901
+ const boxOf = (id) => {
902
+ const n = layout.nodes.find((m) => m.id === id);
903
+ return n?.boxLabel ? boxIdByLabel.get(n.boxLabel) : void 0;
904
+ };
905
+ const obstacles = [];
906
+ for (const [id, rect] of rectById) obstacles.push({ id, rect });
907
+ const normalOf = (s) => s === "L" ? { x: -1, y: 0 } : s === "R" ? { x: 1, y: 0 } : s === "T" ? { x: 0, y: -1 } : { x: 0, y: 1 };
908
+ const facingCost = (from, to, side) => {
909
+ const dx = to.x + to.w / 2 - (from.x + from.w / 2);
910
+ const dy = to.y + to.h / 2 - (from.y + from.h / 2);
911
+ const len = Math.hypot(dx, dy) || 1;
912
+ const n = normalOf(side);
913
+ return 1 - (n.x * dx + n.y * dy) / len;
914
+ };
915
+ const ctx = layout.edges.map((edge) => {
916
+ const source = rectById.get(edge.sourceId);
917
+ const target = rectById.get(edge.targetId);
918
+ if (!source || !target) return null;
919
+ const exclude = new Set(
920
+ [
921
+ edge.sourceId,
922
+ edge.targetId,
923
+ boxOf(edge.sourceId),
924
+ boxOf(edge.targetId)
925
+ ].filter((x) => x !== void 0)
926
+ );
927
+ return {
928
+ source,
929
+ target,
930
+ sPorts: portsById.get(edge.sourceId),
931
+ tPorts: portsById.get(edge.targetId),
932
+ obstacleRects: obstacles.filter((o) => !exclude.has(o.id)).map((o) => o.rect),
933
+ adjacent: /* @__PURE__ */ new Set()
934
+ };
935
+ });
936
+ for (let a = 0; a < layout.edges.length; a++) {
937
+ for (let b = a + 1; b < layout.edges.length; b++) {
938
+ const ea = layout.edges[a];
939
+ const eb = layout.edges[b];
940
+ if (ea.sourceId === eb.sourceId || ea.sourceId === eb.targetId || ea.targetId === eb.sourceId || ea.targetId === eb.targetId) {
941
+ ctx[a]?.adjacent.add(b);
942
+ ctx[b]?.adjacent.add(a);
943
+ }
944
+ }
945
+ }
946
+ const W_NODE = 100;
947
+ const W_EDGE = 8;
948
+ const scoreOf = (c, g, poly, self, polys2, s, t) => {
949
+ let edgeCross = 0;
950
+ for (let j = 0; j < polys2.length; j++) {
951
+ if (j === self || c.adjacent.has(j)) continue;
952
+ const pj = polys2[j];
953
+ if (pj) edgeCross += polyCrossings(poly, pj);
954
+ }
955
+ return pathCrossings(g, c.obstacleRects) * W_NODE + edgeCross * W_EDGE + facingCost(c.source, c.target, s) + facingCost(c.target, c.source, t);
956
+ };
957
+ const chosen = layout.edges.map(
958
+ (_, i) => sides[i] ?? { s: "R", t: "L" }
959
+ );
960
+ const geoms = ctx.map(
961
+ (c, i) => c ? edgePath(
962
+ c.source,
963
+ c.target,
964
+ chosen[i].s,
965
+ chosen[i].t,
966
+ c.sPorts,
967
+ c.tPorts
968
+ ) : null
969
+ );
970
+ const polys = geoms.map((g) => g ? polyline(g) : null);
971
+ for (let pass = 0; pass < 3; pass++) {
972
+ let changed = false;
973
+ for (let i = 0; i < ctx.length; i++) {
974
+ const c = ctx[i];
975
+ const g = geoms[i];
976
+ const p = polys[i];
977
+ if (!c || !g || !p) continue;
978
+ const cur = chosen[i];
979
+ const curScore = scoreOf(c, g, p, i, polys, cur.s, cur.t);
980
+ if (curScore < W_EDGE) continue;
981
+ let bestScore = curScore;
982
+ let bestG = g;
983
+ let bestP = p;
984
+ let bestSide = cur;
985
+ for (const s of SIDES) {
986
+ for (const t of SIDES) {
987
+ const cg = edgePath(c.source, c.target, s, t, c.sPorts, c.tPorts);
988
+ const cp = polyline(cg);
989
+ const sc = scoreOf(c, cg, cp, i, polys, s, t);
990
+ if (sc < bestScore) {
991
+ bestScore = sc;
992
+ bestG = cg;
993
+ bestP = cp;
994
+ bestSide = { s, t };
995
+ }
996
+ }
997
+ }
998
+ if (bestSide !== cur) {
999
+ chosen[i] = bestSide;
1000
+ geoms[i] = bestG;
1001
+ polys[i] = bestP;
1002
+ changed = true;
1003
+ }
1004
+ }
1005
+ if (!changed) break;
1006
+ }
1007
+ const hopsFor = layout.edges.map(() => []);
1008
+ for (let i = 0; i < polys.length; i++) {
1009
+ for (let j = i + 1; j < polys.length; j++) {
1010
+ if (ctx[i]?.adjacent.has(j)) continue;
1011
+ const a = polys[i];
1012
+ const b = polys[j];
1013
+ if (!a || !b) continue;
1014
+ const pt = polyIntersection(a, b);
1015
+ if (pt) hopsFor[j].push(pt);
1016
+ }
1017
+ }
1018
+ return layout.edges.map((edge, i) => {
1019
+ const g = geoms[i];
1020
+ if (!g) return null;
1021
+ const dRender = hoppedPath(g, hopsFor[i]);
1022
+ return {
1023
+ sourceId: edge.sourceId,
1024
+ targetId: edge.targetId,
1025
+ d: g.d,
1026
+ mid: g.mid,
1027
+ ...dRender && { dRender }
1028
+ };
1029
+ });
1030
+ }
1031
+ function renderSketchForExport(container, parsed, layout, palette, isDark, options = {}) {
1032
+ renderSketch(container, parsed, layout, palette, isDark, {
1033
+ ...options,
1034
+ exportMode: options.exportMode ?? true
1035
+ });
1036
+ }
1037
+
1038
+ export {
1039
+ renderSketch,
1040
+ sketchEdgeGeometry,
1041
+ renderSketchForExport
1042
+ };
1043
+ //# sourceMappingURL=chunk-3TDRHT4J.js.map