@diagrammo/dgmo 0.95.0 → 0.96.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 (215) hide show
  1. package/README.md +1 -1
  2. package/dist/advanced.d.ts +27 -569
  3. package/dist/advanced.js +157 -350
  4. package/dist/block.js +54 -55
  5. package/dist/{calculator-BNH3GSJE.js → calculator-GIB7POFX.js} +2 -2
  6. package/dist/{chart-meta-BbjsRY7o.d.ts → chart-meta-uImk4eTn.d.ts} +1 -1
  7. package/dist/chart-meta.d.ts +2 -2
  8. package/dist/chart-meta.js +15 -15
  9. package/dist/{chart-types-Cppnp31G.d.ts → chart-types-CBVYiLqy.d.ts} +1 -5
  10. package/dist/{charts-d3-SZV2SFTM.js → charts-d3-IRP5VANE.js} +5 -5
  11. package/dist/{chunk-MLY5ALOV.js → chunk-2BYFNZVM.js} +2 -2
  12. package/dist/{chunk-OSSTOSXU.js → chunk-2M3K6GD2.js} +3 -6
  13. package/dist/{chunk-CDM6XMOT.js → chunk-34JOHSVE.js} +2 -2
  14. package/dist/chunk-35A3J4Z5.js +14 -0
  15. package/dist/{chunk-7IALGIOI.js → chunk-3W73ZP6W.js} +9 -4
  16. package/dist/{chunk-IHN6WDEY.js → chunk-4B45SNZH.js} +5 -5
  17. package/dist/{chunk-AULZD45V.js → chunk-5ARANBIE.js} +2 -2
  18. package/dist/{chunk-L5S32VZJ.js → chunk-5BG4OSWJ.js} +5 -5
  19. package/dist/{chunk-VB4VMB2I.js → chunk-5G4DOOX2.js} +1 -1
  20. package/dist/{chunk-EXHXTMVR.js → chunk-5GU6C5WB.js} +2 -2
  21. package/dist/{chunk-EBIDNRSR.js → chunk-5H7SA5ZD.js} +1 -1
  22. package/dist/{chunk-CN4RDJDV.js → chunk-5LG526X7.js} +1 -1
  23. package/dist/{chunk-VF7IKIRS.js → chunk-67RKJEKF.js} +5 -5
  24. package/dist/{chunk-D3K4U3ZM.js → chunk-6K2W3FH7.js} +8 -5
  25. package/dist/{chunk-C6G36F5S.js → chunk-7UWVHNPM.js} +4 -4
  26. package/dist/{chunk-FWVE373X.js → chunk-AQRSEQZV.js} +1 -1
  27. package/dist/{chunk-BQO24BDM.js → chunk-AUXUNV73.js} +1 -1
  28. package/dist/{chunk-3PP746YM.js → chunk-B2YVZ3QU.js} +1 -1
  29. package/dist/{chunk-QPQWY5RU.js → chunk-B5CEV7IR.js} +3 -3
  30. package/dist/{chunk-J7Q4AB23.js → chunk-B7BSRVNC.js} +2 -2
  31. package/dist/{chunk-IXHWS2HI.js → chunk-BD4O4D2A.js} +2 -2
  32. package/dist/{chunk-RQTDUZUH.js → chunk-BUVLLK3D.js} +6 -6
  33. package/dist/{chunk-JJ7RGTAU.js → chunk-CD7VQCDL.js} +6 -6
  34. package/dist/{chunk-6EFCOES2.js → chunk-CP73WWLN.js} +5 -5
  35. package/dist/{chunk-GI5R5B3S.js → chunk-D7DGLJ7N.js} +2 -2
  36. package/dist/{chunk-XOMIYMQ3.js → chunk-DKCVAQU3.js} +6 -6
  37. package/dist/{chunk-KBDMEOLI.js → chunk-DPNSDCR3.js} +1 -1
  38. package/dist/{chunk-BRGRIZQB.js → chunk-DWMQ24JR.js} +2 -2
  39. package/dist/{chunk-4XYZJTFO.js → chunk-EM5SA7NC.js} +11 -3
  40. package/dist/{chunk-AM42TLSZ.js → chunk-EMGNCG5C.js} +1 -1
  41. package/dist/{chunk-3KVUFHUJ.js → chunk-EPB3UEMD.js} +2 -2
  42. package/dist/{chunk-NXU4N5WT.js → chunk-EZ6BI5LL.js} +1 -1
  43. package/dist/{chunk-2ZW4NBYX.js → chunk-FBK32S4D.js} +1 -1
  44. package/dist/{chunk-2I4UQG7W.js → chunk-FHX373L5.js} +1 -1
  45. package/dist/{chunk-AQQUJEDN.js → chunk-FKJWZWNU.js} +1 -1
  46. package/dist/{chunk-TIIZIAGS.js → chunk-FUYEXLAN.js} +6 -13
  47. package/dist/{chunk-TASRGDYP.js → chunk-GEHK4UD5.js} +3 -3
  48. package/dist/{chunk-ZD3QCNB7.js → chunk-GLL237AP.js} +2 -2
  49. package/dist/{chunk-PGSGJLUR.js → chunk-GM2SLMQW.js} +2 -2
  50. package/dist/{chunk-V5D6GDNK.js → chunk-H7JVKUA5.js} +4 -4
  51. package/dist/{chunk-IY62DXT2.js → chunk-H7RQG4PH.js} +2 -2
  52. package/dist/{chunk-KLBTJEIK.js → chunk-HH3DHNQA.js} +1 -1
  53. package/dist/{chunk-GWQRTA5W.js → chunk-HZX4QZGR.js} +1 -1
  54. package/dist/{chunk-KBEWVCK3.js → chunk-I2I2FKAK.js} +1 -1
  55. package/dist/{chunk-BTP2BMWN.js → chunk-I3ZRIMR7.js} +10 -10
  56. package/dist/{chunk-IQN2NGEU.js → chunk-IKXQ6NVR.js} +6 -6
  57. package/dist/{chunk-XJQ6Z3FO.js → chunk-IQZSKWE5.js} +3 -3
  58. package/dist/{chunk-3GUEYQGL.js → chunk-ITDF3MWD.js} +3 -3
  59. package/dist/{chunk-JXGSTBW6.js → chunk-IU7XKZA6.js} +2 -2
  60. package/dist/{chunk-RITTLIDJ.js → chunk-IZFJZCF6.js} +4 -4
  61. package/dist/{chunk-PGBTUGDB.js → chunk-JBAFAKGX.js} +5 -5
  62. package/dist/{chunk-VSAKEMDD.js → chunk-JCC3B2GS.js} +8 -2
  63. package/dist/{chunk-66JTY4AN.js → chunk-JRN2CRXJ.js} +1 -1
  64. package/dist/{chunk-USZLHYEQ.js → chunk-K2SFH3GJ.js} +2 -2
  65. package/dist/{chunk-NM5V5EKY.js → chunk-K2WXMXI2.js} +1 -1
  66. package/dist/{chunk-62GLKE6Q.js → chunk-KDWEOT54.js} +21 -9
  67. package/dist/{chunk-PVWIBKV2.js → chunk-KQAPFIYF.js} +2 -2
  68. package/dist/{chunk-4SACN2C5.js → chunk-LGUFJ7Y2.js} +1 -1
  69. package/dist/{chunk-LAXMUSGW.js → chunk-LRHPBWOY.js} +4 -4
  70. package/dist/{chunk-5XBYLYYI.js → chunk-M4ZUIW3J.js} +3 -3
  71. package/dist/{chunk-S4SJ4LLY.js → chunk-MAYTYF5S.js} +3 -3
  72. package/dist/{chunk-P5XA627W.js → chunk-MVUNMJKO.js} +46 -52
  73. package/dist/{chunk-E7F76M3U.js → chunk-MYHR3PMH.js} +57 -5
  74. package/dist/{chunk-NBAAIRFP.js → chunk-NI4L6HEU.js} +4 -1
  75. package/dist/{chunk-A2A2I4Z4.js → chunk-O2HNVNKO.js} +2 -2
  76. package/dist/{chunk-4UVCTLRH.js → chunk-OAZ6BIIB.js} +3 -3
  77. package/dist/{chunk-IZHGT5HD.js → chunk-OO4GUE4E.js} +3 -3
  78. package/dist/{chunk-KSZB7TIY.js → chunk-OYGJZA24.js} +8 -8
  79. package/dist/{chunk-H6BT45SN.js → chunk-P2GNNEMN.js} +1 -1
  80. package/dist/{chunk-U6VS3T2M.js → chunk-P3PSLC2K.js} +4 -4
  81. package/dist/{chunk-HHVIE45A.js → chunk-P6LKX3IQ.js} +4 -4
  82. package/dist/{chunk-NMS5XSLX.js → chunk-PGD6CNWO.js} +1 -1
  83. package/dist/{chunk-NVZ7R4EK.js → chunk-PWZEJNO6.js} +3 -3
  84. package/dist/{chunk-NPDVWFAQ.js → chunk-QEU6VM4O.js} +1 -1
  85. package/dist/{chunk-UIEKW4SG.js → chunk-R5L5E3TC.js} +0 -1
  86. package/dist/{chunk-2WQ3YZMN.js → chunk-RGFVHYDP.js} +2 -2
  87. package/dist/{chunk-YQMIKX54.js → chunk-RIK6WUMO.js} +62 -29
  88. package/dist/{chunk-BH2SF4TT.js → chunk-RTRORHSP.js} +1 -1
  89. package/dist/{chunk-USE6HIOZ.js → chunk-RVOSA4RR.js} +845 -193
  90. package/dist/{chunk-LKZCUFOW.js → chunk-SCYVGPLI.js} +2 -2
  91. package/dist/{chunk-XIUGSUE4.js → chunk-SIABEREK.js} +6 -2
  92. package/dist/{chunk-R46N5KR4.js → chunk-SQBCNEJB.js} +2 -1
  93. package/dist/{chunk-VTESGA5F.js → chunk-THTYCJGF.js} +2 -2
  94. package/dist/{chunk-4EX4OKGZ.js → chunk-TIPNNOZC.js} +5 -5
  95. package/dist/{chunk-UZ7EZW3B.js → chunk-TO53KK2P.js} +6 -1
  96. package/dist/{chunk-LJGE43SG.js → chunk-TPCP2UOI.js} +3 -3
  97. package/dist/{chunk-Y3SIQN4J.js → chunk-TUOZ6AXC.js} +2 -2
  98. package/dist/{chunk-KRPLP5LP.js → chunk-U6N547QA.js} +1 -1
  99. package/dist/{chunk-BCV2VJTM.js → chunk-VJ7NLYFE.js} +2 -2
  100. package/dist/{chunk-UXNA2H2V.js → chunk-VLI6AWS3.js} +2 -2
  101. package/dist/{chunk-2J2CWWWK.js → chunk-VNAPEZX2.js} +1 -1
  102. package/dist/{chunk-EBVVMUAA.js → chunk-VVTCUIPN.js} +1 -1
  103. package/dist/{chunk-FVTYJUXR.js → chunk-W5MMPPGX.js} +2 -2
  104. package/dist/{chunk-BQMHJ6OW.js → chunk-WGNP5ND2.js} +20 -12
  105. package/dist/{chunk-5OTA2PUH.js → chunk-WLGOIMTI.js} +2 -2
  106. package/dist/{chunk-IGJEKO2P.js → chunk-WTPS73RM.js} +4 -4
  107. package/dist/{chunk-R6EGUTIV.js → chunk-YFIUABSF.js} +2 -2
  108. package/dist/{chunk-7PJBJ2DU.js → chunk-YSGOXZBB.js} +1 -1
  109. package/dist/{chunk-ZECJ7Q6C.js → chunk-YVIPJGFG.js} +2 -2
  110. package/dist/{chunk-5KKZXA44.js → chunk-ZBOIYC2G.js} +4 -2
  111. package/dist/{chunk-RBVFNUAL.js → chunk-ZOKD5F7M.js} +2 -2
  112. package/dist/{collapse-BSPH3BFM.js → collapse-6X5S2S3G.js} +2 -1
  113. package/dist/completion-registry.js +4 -38
  114. package/dist/countdown.js +1 -1
  115. package/dist/{dgmo-router-6YLKM6WU.js → dgmo-router-EPBQKQW2.js} +44 -45
  116. package/dist/{dimensions-DS6FWLRY.js → dimensions-DBCRBZIU.js} +4 -4
  117. package/dist/editor.js +2 -7
  118. package/dist/{flowchart-parser-J3VWIFWB.js → flowchart-parser-SM5LHF2D.js} +3 -3
  119. package/dist/{flowchart-renderer-FECH5KK5.js → flowchart-renderer-PPS2GTTD.js} +9 -9
  120. package/dist/highlight.js +3 -8
  121. package/dist/index.d.ts +42 -6
  122. package/dist/index.js +61 -56
  123. package/dist/{layout-MXHR3P35.js → layout-3J72UULM.js} +3 -3
  124. package/dist/{layout-TIBRMWHL.js → layout-AF4KA5B2.js} +3 -3
  125. package/dist/{layout-5SZ5A64I.js → layout-FCFUVCRI.js} +6 -6
  126. package/dist/{layout-KV27UW25.js → layout-H2KP5A6M.js} +1 -1
  127. package/dist/{layout-ND26WVX2.js → layout-IXQNVRBE.js} +3 -3
  128. package/dist/{layout-YBMT74MG.js → layout-KELSNWBD.js} +6 -6
  129. package/dist/{layout-JTIRCKAW.js → layout-LNVIH45F.js} +3 -3
  130. package/dist/{layout-EWXHEXNS.js → layout-MPSH3YWE.js} +6 -6
  131. package/dist/{layout-HFBK5UEG.js → layout-PPIVGJXD.js} +2 -2
  132. package/dist/{layout-RH3N46HP.js → layout-R6G4MEO3.js} +4 -3
  133. package/dist/{layout-search-AWPJWBKT.js → layout-search-C2TYUH4L.js} +4 -4
  134. package/dist/{parser-BT4NI6JY.js → parser-2AXU2MHJ.js} +3 -3
  135. package/dist/{parser-3QIFY5IN.js → parser-4BOP77CD.js} +2 -2
  136. package/dist/{parser-MA7L3XND.js → parser-4GHAYZKZ.js} +4 -4
  137. package/dist/{parser-LTRQASGB.js → parser-5HQPPVHJ.js} +3 -3
  138. package/dist/{parser-EAQPZX2B.js → parser-5RUD4A3X.js} +3 -3
  139. package/dist/{parser-BJ7RJNUM.js → parser-6WURFLOB.js} +3 -3
  140. package/dist/{parser-AR2GON37.js → parser-722KLLAQ.js} +4 -4
  141. package/dist/{parser-KMKVFET2.js → parser-B7SCN7FG.js} +2 -2
  142. package/dist/{parser-TUAEX6ML.js → parser-BNRX35NT.js} +3 -3
  143. package/dist/{parser-NL73FSFI.js → parser-BPYHIG24.js} +3 -3
  144. package/dist/{parser-3LT3ZUUC.js → parser-CRJYLOHA.js} +2 -2
  145. package/dist/{parser-NUU3DVW4.js → parser-DGLKH4NT.js} +2 -2
  146. package/dist/{parser-5UZV32ZI.js → parser-DRUGM3R6.js} +2 -2
  147. package/dist/{parser-KLCSFQ3J.js → parser-DWV2CYBS.js} +3 -3
  148. package/dist/{parser-2IKPQVKX.js → parser-F3JJNIFC.js} +3 -3
  149. package/dist/{parser-EFF22GYO.js → parser-F75WNYMK.js} +3 -3
  150. package/dist/{parser-RTWPFKXG.js → parser-GBQY3WOZ.js} +3 -3
  151. package/dist/{parser-F7NDRPMA.js → parser-GM5B2EPW.js} +3 -3
  152. package/dist/{parser-K2DI26SC.js → parser-H6HT2WFQ.js} +2 -2
  153. package/dist/{parser-PEZ7RN43.js → parser-HM6FEX5K.js} +3 -3
  154. package/dist/{parser-YG625J5H.js → parser-L7SI3PW4.js} +4 -4
  155. package/dist/{parser-GMQJISZ6.js → parser-LUJX7AXO.js} +2 -2
  156. package/dist/{parser-A3AN76RQ.js → parser-MWINQNQW.js} +3 -3
  157. package/dist/{parser-KJPPUN4D.js → parser-OHBBDCG4.js} +2 -2
  158. package/dist/{parser-BTSTKY5G.js → parser-QWTECQEC.js} +4 -4
  159. package/dist/{parser-4TBSWULQ.js → parser-TTGZYLYD.js} +3 -3
  160. package/dist/{parser-6TDWUKM5.js → parser-UHKROC7Z.js} +3 -3
  161. package/dist/{parser-H5OODY5N.js → parser-W6NX3AIV.js} +3 -3
  162. package/dist/{parser-GDLKUBTO.js → parser-WIKXZP4X.js} +2 -2
  163. package/dist/{parser-4Y6PODW6.js → parser-XEJP37GQ.js} +3 -3
  164. package/dist/{parser-RCIEKN7Y.js → parser-Y7QXD2UR.js} +2 -2
  165. package/dist/{parser-ZRIZFDZY.js → parser-ZV756RMP.js} +4 -4
  166. package/dist/{parser-KKF6Y5MM.js → parser-ZWWQZ4XZ.js} +4 -3
  167. package/dist/{redraw-AHW7EUUF.js → redraw-BZ4GI6IC.js} +6 -4
  168. package/dist/{redraw-STZ4WJAI.js → redraw-LEOXS7C6.js} +3 -3
  169. package/dist/{renderer-4VGO27EE.js → renderer-2MCV75JQ.js} +11 -11
  170. package/dist/{renderer-TINHO2IO.js → renderer-2V2XY2V7.js} +4 -4
  171. package/dist/{renderer-XDX6S7OV.js → renderer-5AEDVLAA.js} +8 -7
  172. package/dist/{renderer-W4MUMXJE.js → renderer-5GP7YUS4.js} +3 -3
  173. package/dist/{renderer-ACQQ2JXA.js → renderer-66NCRXSC.js} +6 -6
  174. package/dist/{renderer-AM7P4LN7.js → renderer-6HU44IGJ.js} +4 -4
  175. package/dist/{renderer-6BDK47V6.js → renderer-7C76HP5W.js} +6 -6
  176. package/dist/{renderer-O6RP52CQ.js → renderer-7RAMBMTH.js} +6 -6
  177. package/dist/{renderer-IGSHD3OT.js → renderer-BYLQ37T2.js} +8 -8
  178. package/dist/{renderer-7OGGV327.js → renderer-CVCCW7UT.js} +4 -4
  179. package/dist/{renderer-QTPWRRJ7.js → renderer-D6EH5UQ6.js} +6 -6
  180. package/dist/renderer-E3334XLT.js +84 -0
  181. package/dist/{renderer-IXBOT6DU.js → renderer-F7YGMEGQ.js} +2 -2
  182. package/dist/{renderer-XCLARXCK.js → renderer-GKY55M4Z.js} +5 -5
  183. package/dist/{renderer-KJ3V5BYP.js → renderer-LFZKG2GR.js} +5 -5
  184. package/dist/{renderer-2LYX6NHN.js → renderer-LJPUCG3U.js} +5 -5
  185. package/dist/{renderer-DAZWHNLI.js → renderer-MGF2NNGG.js} +3 -3
  186. package/dist/{renderer-HX6ICPDX.js → renderer-MVBAQP3M.js} +4 -4
  187. package/dist/{renderer-UGW4N2W5.js → renderer-MZIWP55B.js} +5 -5
  188. package/dist/{renderer-MWZC7TMD.js → renderer-N6PM5CSG.js} +7 -7
  189. package/dist/{renderer-ISQJ2ELA.js → renderer-N75E3UVY.js} +5 -5
  190. package/dist/{renderer-IVHD7ENY.js → renderer-ONENGXFQ.js} +6 -6
  191. package/dist/{renderer-RUSQJFFC.js → renderer-PEJF6R2I.js} +2 -2
  192. package/dist/{renderer-36446HSH.js → renderer-QZJZIAT3.js} +2 -2
  193. package/dist/{renderer-UTEEJDGB.js → renderer-SYRH3B62.js} +6 -6
  194. package/dist/{renderer-2QPHDBZY.js → renderer-TS5NHOQD.js} +5 -5
  195. package/dist/{renderer-Y47EM337.js → renderer-VNJOZPSH.js} +7 -7
  196. package/dist/{renderer-P3WR7TKD.js → renderer-VNUDN6F5.js} +11 -11
  197. package/dist/{renderer-JYHA6R2D.js → renderer-VUXAAGUG.js} +5 -5
  198. package/dist/{renderer-BXD5KVSR.js → renderer-YJVQT7QG.js} +6 -6
  199. package/dist/{renderer-radial-WFUX3Z3C.js → renderer-radial-4R7AKETK.js} +5 -5
  200. package/dist/{state-parser-PMNHLHLE.js → state-parser-EQBBEKHR.js} +4 -4
  201. package/dist/{state-renderer-JQ5DS66J.js → state-renderer-SOGZ2CNN.js} +11 -11
  202. package/dist/{themes-DzIH3Hjv.d.ts → themes-CbJL3w8L.d.ts} +1 -1
  203. package/docs/ai-integration.md +5 -6
  204. package/docs/language-reference.md +68 -104
  205. package/gallery/fixtures/whiteboard.dgmo +1 -0
  206. package/package.json +1 -1
  207. package/dist/chunk-6BQSDF77.js +0 -734
  208. package/dist/chunk-NWSPPGIE.js +0 -60
  209. package/dist/chunk-VBMRZCMQ.js +0 -1465
  210. package/dist/chunk-WZBZXZ6T.js +0 -636
  211. package/dist/layout-D4L44NRG.js +0 -11
  212. package/dist/parser-YHDGKPZI.js +0 -14
  213. package/dist/renderer-WPN2SXGT.js +0 -29
  214. package/dist/renderer-ZV6KCLCL.js +0 -85
  215. package/gallery/fixtures/sketch.dgmo +0 -22
@@ -1,734 +0,0 @@
1
- import {
2
- SKETCH_DIAGNOSTIC_CODES
3
- } from "./chunk-NWSPPGIE.js";
4
- import {
5
- makeDgmoError
6
- } from "./chunk-BYU54C3S.js";
7
-
8
- // src/sketch/geometry.ts
9
- var SKETCH_PHI = (1 + Math.sqrt(5)) / 2;
10
- var SKETCH_GEOMETRY = {
11
- /** px per grid cell (the dot-grid pitch) */
12
- cellPx: 16,
13
- /** universal footprint width, in grid cells */
14
- footprintCellsW: 8,
15
- /**
16
- * Legacy — the gap is now a derived half-unit (footprint/2 per axis), not
17
- * these cell counts. Kept only so the shape of SKETCH_GEOMETRY is stable.
18
- */
19
- gapCellsX: 4,
20
- gapCellsY: 4,
21
- /** box reserved top band, px (spec decision 12) */
22
- bandPx: 28,
23
- /** box frame padding around the children bbox, px */
24
- boxPadPx: 16,
25
- /** edge-ring (connect hook) width as a fraction of footprint height */
26
- ringFrac: 0.22
27
- };
28
- var SKETCH_FOOT_W = SKETCH_GEOMETRY.footprintCellsW * SKETCH_GEOMETRY.cellPx;
29
- var SKETCH_FOOT_H = 2 * Math.round(SKETCH_FOOT_W / SKETCH_PHI / 2);
30
- var SKETCH_HALF_SLOT_X = SKETCH_FOOT_W / 2;
31
- var SKETCH_HALF_SLOT_Y = SKETCH_FOOT_H / 2;
32
- var SKETCH_SEP = 3;
33
- var SKETCH_SLOT_X = SKETCH_HALF_SLOT_X * SKETCH_SEP;
34
- var SKETCH_SLOT_Y = SKETCH_HALF_SLOT_Y * SKETCH_SEP;
35
- function sketchSlotToPx(c, r) {
36
- return { x: c * SKETCH_HALF_SLOT_X, y: r * SKETCH_HALF_SLOT_Y };
37
- }
38
-
39
- // src/sketch/collapse.ts
40
- function collapseSketch(parsed, collapsedLabels) {
41
- const collapsed = collapsedLabels ?? new Set(parsed.boxes.filter((b) => b.collapsed).map((b) => b.label));
42
- if (collapsed.size === 0) {
43
- return {
44
- nodes: parsed.nodes,
45
- boxes: parsed.boxes,
46
- virtualBoxes: [],
47
- edges: parsed.edges,
48
- collapsedChildCounts: /* @__PURE__ */ new Map()
49
- };
50
- }
51
- const virtualBoxes = parsed.boxes.filter((b) => collapsed.has(b.label));
52
- const boxes = parsed.boxes.filter((b) => !collapsed.has(b.label));
53
- const nodeToVirtual = /* @__PURE__ */ new Map();
54
- const collapsedChildCounts = /* @__PURE__ */ new Map();
55
- for (const box of virtualBoxes) {
56
- collapsedChildCounts.set(box.label, box.children.length);
57
- for (const childId of box.children) nodeToVirtual.set(childId, box.id);
58
- }
59
- const nodes = parsed.nodes.filter((n) => !nodeToVirtual.has(n.id));
60
- const edges = [];
61
- const seen = /* @__PURE__ */ new Set();
62
- for (const edge of parsed.edges) {
63
- const sourceId = nodeToVirtual.get(edge.sourceId) ?? edge.sourceId;
64
- const targetId = nodeToVirtual.get(edge.targetId) ?? edge.targetId;
65
- if (sourceId === targetId) continue;
66
- const key = `${sourceId}|${targetId}|${edge.label ?? ""}|${edge.heads}|${edge.dashed}`;
67
- if (seen.has(key)) continue;
68
- seen.add(key);
69
- edges.push({ ...edge, sourceId, targetId });
70
- }
71
- return { nodes, boxes, virtualBoxes, edges, collapsedChildCounts };
72
- }
73
-
74
- // src/sketch/layout.ts
75
- var SKETCH_AUTO_LAYOUT_DEFAULTS = {
76
- normalizeOrigin: false,
77
- sortRootsBySource: false,
78
- resolveOverlap: true,
79
- groupCollisionAsRect: true,
80
- flowPlaceUnpositioned: true,
81
- avoidEdges: true
82
- };
83
- function resolveAutoFlags(f = {}) {
84
- const d = SKETCH_AUTO_LAYOUT_DEFAULTS;
85
- return {
86
- normalizeOrigin: f.normalizeOrigin ?? d.normalizeOrigin,
87
- sortRootsBySource: f.sortRootsBySource ?? d.sortRootsBySource,
88
- resolveOverlap: f.resolveOverlap ?? d.resolveOverlap,
89
- groupCollisionAsRect: f.groupCollisionAsRect ?? d.groupCollisionAsRect,
90
- flowPlaceUnpositioned: f.flowPlaceUnpositioned ?? d.flowPlaceUnpositioned,
91
- avoidEdges: f.avoidEdges ?? d.avoidEdges
92
- };
93
- }
94
- function unitRect(c, r) {
95
- return { c, r, w: SKETCH_SEP, h: SKETCH_SEP };
96
- }
97
- var childBoxAt = /* @__PURE__ */ new Map();
98
- function firstFreeOnRing(base, occupied, d) {
99
- for (let quadrant = 0; quadrant < 4; quadrant++) {
100
- for (let dr = -d; dr <= d; dr++) {
101
- const r = base.r + dr;
102
- const spread = d - Math.abs(dr);
103
- for (const c of spread === 0 ? [base.c] : [base.c - spread, base.c + spread]) {
104
- const cost = (r < base.r ? 2 : 0) + (c < base.c ? 1 : 0);
105
- if (cost !== quadrant) continue;
106
- if (!occupied.hits({ ...base, c, r })) return { c, r };
107
- }
108
- }
109
- }
110
- return null;
111
- }
112
- function nearestFreeRect(base, occupied) {
113
- if (!occupied.hits(base)) return { c: base.c, r: base.r };
114
- const key = `${base.c},${base.r},${base.w},${base.h}`;
115
- for (let d = occupied.ringStart.get(key) ?? 1; d <= 200; d++) {
116
- const found = firstFreeOnRing(base, occupied, d);
117
- if (found) {
118
- occupied.ringStart.set(key, d);
119
- return found;
120
- }
121
- }
122
- return { c: base.c, r: base.r };
123
- }
124
- function rectsOverlap(a, b) {
125
- return a.c < b.c + b.w && b.c < a.c + a.w && a.r < b.r + b.h && b.r < a.r + a.h;
126
- }
127
- var CELL = SKETCH_SEP;
128
- var OVERSIZED_CELLS = 64;
129
- function cellRange(rect) {
130
- return [
131
- Math.floor(rect.c / CELL),
132
- Math.floor(rect.r / CELL),
133
- Math.floor((rect.c + rect.w) / CELL),
134
- Math.floor((rect.r + rect.h) / CELL)
135
- ];
136
- }
137
- function cellSpan(range) {
138
- return (range[2] - range[0] + 1) * (range[3] - range[1] + 1);
139
- }
140
- var Occupancy = class {
141
- grid = /* @__PURE__ */ new Map();
142
- oversized = [];
143
- /** Every rect, in insertion order — the extent and flow-origin maths want it. */
144
- rects = [];
145
- /**
146
- * The ring a search from a given base last had to reach, keyed by that base.
147
- *
148
- * Slots are only ever taken here, never given back, so a ring that was full
149
- * once is full for the rest of the layout. The next unit authored at the
150
- * same slot can therefore start where the last one finished instead of
151
- * re-walking every ring inside it — which is what made a stack of shapes on
152
- * one coordinate cost more than linear even with the collision index in
153
- * place (#484). Skipping proven-full rings cannot change where a unit lands.
154
- */
155
- ringStart = /* @__PURE__ */ new Map();
156
- add(rect) {
157
- this.rects.push(rect);
158
- const range = cellRange(rect);
159
- if (cellSpan(range) > OVERSIZED_CELLS) {
160
- this.oversized.push(rect);
161
- return;
162
- }
163
- const [c0, r0, c1, r1] = range;
164
- for (let c = c0; c <= c1; c++) {
165
- for (let r = r0; r <= r1; r++) {
166
- const key = `${c},${r}`;
167
- const bucket = this.grid.get(key);
168
- if (bucket) bucket.push(rect);
169
- else this.grid.set(key, [rect]);
170
- }
171
- }
172
- }
173
- hits(rect) {
174
- for (const o of this.oversized) if (rectsOverlap(rect, o)) return true;
175
- const range = cellRange(rect);
176
- if (cellSpan(range) > OVERSIZED_CELLS) {
177
- for (const o of this.rects) if (rectsOverlap(rect, o)) return true;
178
- return false;
179
- }
180
- const [c0, r0, c1, r1] = range;
181
- for (let c = c0; c <= c1; c++) {
182
- for (let r = r0; r <= r1; r++) {
183
- const bucket = this.grid.get(`${c},${r}`);
184
- if (!bucket) continue;
185
- for (const o of bucket) if (rectsOverlap(rect, o)) return true;
186
- }
187
- }
188
- return false;
189
- }
190
- };
191
- function nearestFree(base, occupied) {
192
- if (!occupied.hits(base)) return { c: base.c, r: base.r };
193
- const key = `${base.c},${base.r},${base.w},${base.h}`;
194
- for (let d = occupied.ringStart.get(key) ?? 1; d <= 200; d++) {
195
- const found = firstFreeOnRing(base, occupied, d);
196
- if (found) {
197
- occupied.ringStart.set(key, d);
198
- return found;
199
- }
200
- }
201
- return { c: base.c, r: base.r };
202
- }
203
- function layoutChildren(box, nodesById, warn, flags, childBoxRects = /* @__PURE__ */ new Map()) {
204
- const occupied = new Occupancy();
205
- const children = [];
206
- const localBoxes = [];
207
- const pending = [];
208
- for (const boxId of box.childBoxes) {
209
- const rect = childBoxRects.get(boxId);
210
- if (!rect) continue;
211
- const at = childBoxAt.get(boxId) ?? null;
212
- const base = at ?? { c: 0, r: 0 };
213
- const want = { ...rect, c: base.c, r: base.r };
214
- const spot = flags.resolveOverlap ? nearestFreeRect(want, occupied) : { c: want.c, r: want.r };
215
- occupied.add({ ...rect, c: spot.c, r: spot.r });
216
- localBoxes.push({ boxId, c: spot.c, r: spot.r, rect });
217
- }
218
- for (const id of box.children) {
219
- const node = nodesById.get(id);
220
- if (!node) continue;
221
- if (node.at === null) {
222
- pending.push(node);
223
- continue;
224
- }
225
- const target = unitRect(node.at.c, node.at.r);
226
- const spot = flags.resolveOverlap ? nearestFree(target, occupied) : { c: node.at.c, r: node.at.r };
227
- if (spot.c !== node.at.c || spot.r !== node.at.r) {
228
- warn(node.lineNumber, node.label);
229
- }
230
- occupied.add(unitRect(spot.c, spot.r));
231
- children.push({ node, c: spot.c, r: spot.r });
232
- }
233
- if (!flags.flowPlaceUnpositioned) {
234
- for (const node of pending) children.push({ node, c: 0, r: 0 });
235
- pending.length = 0;
236
- }
237
- let flowRow = occupied.rects.length > 0 ? Math.max(...occupied.rects.map((o) => o.r)) + SKETCH_SEP : 0;
238
- let flowCol = 0;
239
- const wrapAt = Math.max(
240
- SKETCH_SEP * 3,
241
- occupied.rects.length > 0 ? Math.max(...occupied.rects.map((o) => o.c)) + SKETCH_SEP : SKETCH_SEP * 3
242
- );
243
- for (const node of pending) {
244
- let placed = false;
245
- while (!placed) {
246
- const rect = unitRect(flowCol, flowRow);
247
- if (!occupied.hits(rect)) {
248
- occupied.add(rect);
249
- children.push({ node, c: flowCol, r: flowRow });
250
- placed = true;
251
- }
252
- flowCol += SKETCH_SEP;
253
- if (flowCol > wrapAt) {
254
- flowCol = 0;
255
- flowRow += SKETCH_SEP;
256
- }
257
- }
258
- }
259
- const footWs = SKETCH_FOOT_W / SKETCH_HALF_SLOT_X;
260
- const footHs = SKETCH_FOOT_H / SKETCH_HALF_SLOT_Y;
261
- const drawn = [
262
- ...children.map((k) => ({ c: k.c, r: k.r, w: footWs, h: footHs })),
263
- ...localBoxes.map((b) => ({ c: b.c, r: b.r, w: b.rect.w, h: b.rect.h }))
264
- ];
265
- let extent;
266
- if (drawn.length === 0) {
267
- extent = { c: 0, r: 0, w: footWs, h: footHs };
268
- } else {
269
- const cMin = Math.min(...drawn.map((o) => o.c));
270
- const rMin = Math.min(...drawn.map((o) => o.r));
271
- const cMax = Math.max(...drawn.map((o) => o.c + o.w));
272
- const rMax = Math.max(...drawn.map((o) => o.r + o.h));
273
- extent = { c: cMin, r: rMin, w: cMax - cMin, h: rMax - rMin };
274
- }
275
- return { children, boxes: localBoxes, extent };
276
- }
277
- function layoutSketch(parsed, options = {}) {
278
- const diagnostics = [];
279
- const overlapWarn = (line, label) => {
280
- diagnostics.push(
281
- makeDgmoError(
282
- line,
283
- `Shape "${label}" overlapped another at its authored position \u2014 moved to the nearest free slot`,
284
- "warning",
285
- SKETCH_DIAGNOSTIC_CODES.OVERLAP_RESOLVED
286
- )
287
- );
288
- };
289
- const flags = resolveAutoFlags(options.autoLayout);
290
- const collapsed = collapseSketch(parsed, options.collapsedBoxes);
291
- const nodesById = new Map(collapsed.nodes.map((n) => [n.id, n]));
292
- const padHsX = SKETCH_GEOMETRY.boxPadPx / SKETCH_HALF_SLOT_X;
293
- const padHsY = SKETCH_GEOMETRY.boxPadPx / SKETCH_HALF_SLOT_Y;
294
- const bandHs = SKETCH_GEOMETRY.bandPx / SKETCH_HALF_SLOT_Y;
295
- const boxLocal = /* @__PURE__ */ new Map();
296
- const inExpandedBox = /* @__PURE__ */ new Set();
297
- const boxById = new Map(collapsed.boxes.map((b) => [b.id, b]));
298
- const nestedBoxIds = new Set(
299
- collapsed.boxes.filter((b) => b.parentBoxId !== null).map((b) => b.id)
300
- );
301
- childBoxAt.clear();
302
- for (const box of collapsed.boxes) {
303
- if (!nestedBoxIds.has(box.id)) continue;
304
- childBoxAt.set(box.id, box.at);
305
- const local = layoutChildren(box, nodesById, overlapWarn, flags);
306
- boxLocal.set(box.id, local);
307
- for (const child of local.children) inExpandedBox.add(child.node.id);
308
- }
309
- const childBoxRects = /* @__PURE__ */ new Map();
310
- for (const box of collapsed.boxes) {
311
- if (!nestedBoxIds.has(box.id)) continue;
312
- const local = boxLocal.get(box.id);
313
- childBoxRects.set(box.id, {
314
- c: 0,
315
- r: 0,
316
- w: local.extent.w + 2 * padHsX,
317
- h: local.extent.h + bandHs + padHsY
318
- });
319
- }
320
- for (const box of collapsed.boxes) {
321
- if (nestedBoxIds.has(box.id)) continue;
322
- const local = layoutChildren(
323
- box,
324
- nodesById,
325
- overlapWarn,
326
- flags,
327
- childBoxRects
328
- );
329
- boxLocal.set(box.id, local);
330
- for (const child of local.children) inExpandedBox.add(child.node.id);
331
- }
332
- const allNodesById = new Map(parsed.nodes.map((n) => [n.id, n]));
333
- const noWarn = () => {
334
- };
335
- const virtualLocal = /* @__PURE__ */ new Map();
336
- for (const box of collapsed.virtualBoxes) {
337
- virtualLocal.set(box.id, layoutChildren(box, allNodesById, noWarn, flags));
338
- }
339
- const footWs = SKETCH_FOOT_W / SKETCH_HALF_SLOT_X;
340
- const footHs = SKETCH_FOOT_H / SKETCH_HALF_SLOT_Y;
341
- const virtualCardSpot = (boxId, spot) => {
342
- const local = virtualLocal.get(boxId);
343
- if (local.children.length === 0) return { c: spot.c, r: spot.r };
344
- let minC = Infinity;
345
- let minR = Infinity;
346
- let maxC = -Infinity;
347
- let maxR = -Infinity;
348
- for (const ch of local.children) {
349
- minC = Math.min(minC, ch.c);
350
- minR = Math.min(minR, ch.r);
351
- maxC = Math.max(maxC, ch.c + footWs);
352
- maxR = Math.max(maxR, ch.r + footHs);
353
- }
354
- const cx = spot.c + (minC + maxC) / 2;
355
- const cy = spot.r + (minR + maxR) / 2 + (padHsY - bandHs) / 2;
356
- return {
357
- c: Math.round(cx - footWs / 2),
358
- r: Math.round(cy - footHs / 2)
359
- };
360
- };
361
- const rootUnits = [];
362
- for (const node of collapsed.nodes) {
363
- if (!inExpandedBox.has(node.id)) rootUnits.push({ kind: "shape", node });
364
- }
365
- for (const box of collapsed.virtualBoxes) {
366
- rootUnits.push({ kind: "virtual", box });
367
- }
368
- for (const box of collapsed.boxes) {
369
- if (nestedBoxIds.has(box.id)) continue;
370
- rootUnits.push({ kind: "box", box });
371
- }
372
- const lineOf = (u) => u.kind === "shape" ? u.node.lineNumber : u.box.lineNumber;
373
- const atOf = (u) => u.kind === "shape" ? u.node.at : u.box.at;
374
- if (flags.sortRootsBySource) {
375
- rootUnits.sort((a, b) => lineOf(a) - lineOf(b));
376
- } else {
377
- rootUnits.sort((a, b) => {
378
- const aa = atOf(a);
379
- const ba = atOf(b);
380
- if (aa && ba) {
381
- return aa.r - ba.r || aa.c - ba.c || lineOf(a) - lineOf(b);
382
- }
383
- if (aa) return -1;
384
- if (ba) return 1;
385
- return lineOf(a) - lineOf(b);
386
- });
387
- }
388
- const rectFor = (unit, c, r) => {
389
- if (unit.kind !== "shape" && flags.groupCollisionAsRect) {
390
- const local = (unit.kind === "box" ? boxLocal : virtualLocal).get(
391
- unit.box.id
392
- );
393
- return {
394
- c: c + local.extent.c - padHsX,
395
- r: r + local.extent.r - bandHs,
396
- w: local.extent.w + 2 * padHsX,
397
- h: local.extent.h + bandHs + padHsY
398
- };
399
- }
400
- return unitRect(c, r);
401
- };
402
- const occupied = new Occupancy();
403
- const placedAt = /* @__PURE__ */ new Map();
404
- const pending = [];
405
- for (const unit of rootUnits) {
406
- const at = atOf(unit);
407
- if (at === null) {
408
- pending.push(unit);
409
- continue;
410
- }
411
- const base = rectFor(unit, at.c, at.r);
412
- let spot = { c: at.c, r: at.r };
413
- if (flags.resolveOverlap && unit.kind === "shape" && occupied.hits(base)) {
414
- const freed = nearestFree(base, occupied);
415
- spot = {
416
- c: at.c + (freed.c - base.c),
417
- r: at.r + (freed.r - base.r)
418
- };
419
- overlapWarn(unit.node.lineNumber, unit.node.label);
420
- }
421
- occupied.add(rectFor(unit, spot.c, spot.r));
422
- placedAt.set(unit, spot);
423
- }
424
- if (!flags.flowPlaceUnpositioned) {
425
- for (const unit of pending) {
426
- occupied.add(rectFor(unit, 0, 0));
427
- placedAt.set(unit, { c: 0, r: 0 });
428
- }
429
- pending.length = 0;
430
- }
431
- let flowRow = occupied.rects.length > 0 ? Math.ceil(Math.max(...occupied.rects.map((o) => o.r + o.h))) : 0;
432
- let flowCol = 0;
433
- const wrapAt = Math.max(
434
- SKETCH_SEP * 4,
435
- occupied.rects.length > 0 ? Math.ceil(Math.max(...occupied.rects.map((o) => o.c + o.w))) : SKETCH_SEP * 4
436
- );
437
- for (const unit of pending) {
438
- let placed = false;
439
- while (!placed) {
440
- const rect = rectFor(unit, flowCol, flowRow);
441
- if (!occupied.hits(rect)) {
442
- occupied.add(rect);
443
- placedAt.set(unit, { c: flowCol, r: flowRow });
444
- placed = true;
445
- }
446
- flowCol += SKETCH_SEP;
447
- if (flowCol > wrapAt) {
448
- flowCol = 0;
449
- flowRow += SKETCH_SEP;
450
- }
451
- }
452
- }
453
- const allRects = rootUnits.map((u) => {
454
- const spot = placedAt.get(u);
455
- return rectFor(u, spot.c, spot.r);
456
- });
457
- const liveCMin = allRects.length > 0 ? Math.min(...allRects.map((r) => r.c)) : 0;
458
- const liveRMin = allRects.length > 0 ? Math.min(...allRects.map((r) => r.r)) : 0;
459
- const cMin = flags.normalizeOrigin ? liveCMin : Math.min(options.frozenOrigin?.c ?? liveCMin, liveCMin);
460
- const rMin = flags.normalizeOrigin ? liveRMin : Math.min(options.frozenOrigin?.r ?? liveRMin, liveRMin);
461
- const toPx = (c, r) => ({
462
- x: (c - cMin) * SKETCH_HALF_SLOT_X,
463
- y: (r - rMin) * SKETCH_HALF_SLOT_Y
464
- });
465
- const nodes = [];
466
- const boxes = [];
467
- for (const unit of rootUnits) {
468
- const spot = placedAt.get(unit);
469
- if (unit.kind === "shape") {
470
- const { x, y } = toPx(spot.c, spot.r);
471
- nodes.push({
472
- id: unit.node.id,
473
- label: unit.node.label,
474
- metadata: unit.node.metadata,
475
- ...unit.node.description && { description: unit.node.description },
476
- lineNumber: unit.node.lineNumber,
477
- slot: spot,
478
- x,
479
- y,
480
- w: SKETCH_FOOT_W,
481
- h: SKETCH_FOOT_H
482
- });
483
- } else if (unit.kind === "virtual") {
484
- const cardSpot = virtualCardSpot(unit.box.id, spot);
485
- const { x, y } = toPx(cardSpot.c, cardSpot.r);
486
- nodes.push({
487
- id: unit.box.id,
488
- label: unit.box.label,
489
- metadata: unit.box.metadata,
490
- lineNumber: unit.box.lineNumber,
491
- slot: cardSpot,
492
- x,
493
- y,
494
- w: SKETCH_FOOT_W,
495
- h: SKETCH_FOOT_H,
496
- isCollapsedBox: true,
497
- childCount: collapsed.collapsedChildCounts.get(unit.box.label) ?? 0
498
- });
499
- } else {
500
- const local = boxLocal.get(unit.box.id);
501
- let minX = Infinity;
502
- let minY = Infinity;
503
- let maxX = -Infinity;
504
- let maxY = -Infinity;
505
- for (const child of local.children) {
506
- const abs = toPx(spot.c + child.c, spot.r + child.r);
507
- nodes.push({
508
- id: child.node.id,
509
- label: child.node.label,
510
- metadata: child.node.metadata,
511
- ...child.node.description && {
512
- description: child.node.description
513
- },
514
- boxLabel: unit.box.label,
515
- lineNumber: child.node.lineNumber,
516
- slot: { c: spot.c + child.c, r: spot.r + child.r },
517
- x: abs.x,
518
- y: abs.y,
519
- w: SKETCH_FOOT_W,
520
- h: SKETCH_FOOT_H
521
- });
522
- minX = Math.min(minX, abs.x);
523
- minY = Math.min(minY, abs.y);
524
- maxX = Math.max(maxX, abs.x + SKETCH_FOOT_W);
525
- maxY = Math.max(maxY, abs.y + SKETCH_FOOT_H);
526
- }
527
- if (minX === Infinity) {
528
- const origin = toPx(spot.c, spot.r);
529
- minX = origin.x;
530
- minY = origin.y + SKETCH_GEOMETRY.bandPx;
531
- maxX = origin.x + SKETCH_FOOT_W;
532
- maxY = minY;
533
- }
534
- for (const inner of local.boxes) {
535
- const innerBox = boxById.get(inner.boxId);
536
- const innerLocal = boxLocal.get(inner.boxId);
537
- if (!innerBox || !innerLocal) continue;
538
- const innerRectOrigin = toPx(spot.c + inner.c, spot.r + inner.r);
539
- const innerContentX = innerRectOrigin.x + SKETCH_GEOMETRY.boxPadPx - innerLocal.extent.c * SKETCH_HALF_SLOT_X;
540
- const innerContentY = innerRectOrigin.y + SKETCH_GEOMETRY.bandPx - innerLocal.extent.r * SKETCH_HALF_SLOT_Y;
541
- let iMinX = Infinity;
542
- let iMinY = Infinity;
543
- let iMaxX = -Infinity;
544
- let iMaxY = -Infinity;
545
- for (const gc of innerLocal.children) {
546
- const gx = innerContentX + gc.c * SKETCH_HALF_SLOT_X;
547
- const gy = innerContentY + gc.r * SKETCH_HALF_SLOT_Y;
548
- nodes.push({
549
- id: gc.node.id,
550
- label: gc.node.label,
551
- metadata: gc.node.metadata,
552
- ...gc.node.description && { description: gc.node.description },
553
- boxLabel: innerBox.label,
554
- lineNumber: gc.node.lineNumber,
555
- // 🔴 The child's OWN offset, or every child of an inner box
556
- // reports its box's corner and they all read as one stack.
557
- // `x`/`y` two lines down have always added `gc`; the slot did not,
558
- // so two shapes 192px apart on screen both answered `5,-9` — and
559
- // anything reading slots rather than pixels (the desktop canvas
560
- // does, to adopt resolved positions on load) drew them on top of
561
- // each other, then wrote that stack back to the file. The frame
562
- // margins are the sub-unit difference between this and `gx`; the
563
- // lattice owns the answer, so they round away, exactly as the
564
- // depth-1 path above already assumes (#597).
565
- slot: {
566
- c: Math.round(
567
- spot.c + inner.c + padHsX - innerLocal.extent.c + gc.c
568
- ),
569
- r: Math.round(
570
- spot.r + inner.r + bandHs - innerLocal.extent.r + gc.r
571
- )
572
- },
573
- x: gx,
574
- y: gy,
575
- w: SKETCH_FOOT_W,
576
- h: SKETCH_FOOT_H
577
- });
578
- iMinX = Math.min(iMinX, gx);
579
- iMinY = Math.min(iMinY, gy);
580
- iMaxX = Math.max(iMaxX, gx + SKETCH_FOOT_W);
581
- iMaxY = Math.max(iMaxY, gy + SKETCH_FOOT_H);
582
- }
583
- if (iMinX === Infinity) {
584
- iMinX = innerContentX;
585
- iMinY = innerContentY + SKETCH_GEOMETRY.bandPx;
586
- iMaxX = innerContentX + SKETCH_FOOT_W;
587
- iMaxY = iMinY;
588
- }
589
- const iFrame = {
590
- x: iMinX - SKETCH_GEOMETRY.boxPadPx,
591
- y: iMinY - SKETCH_GEOMETRY.bandPx,
592
- w: iMaxX - iMinX + 2 * SKETCH_GEOMETRY.boxPadPx,
593
- h: iMaxY - iMinY + SKETCH_GEOMETRY.bandPx + SKETCH_GEOMETRY.boxPadPx
594
- };
595
- boxes.push({
596
- id: innerBox.id,
597
- label: innerBox.label,
598
- metadata: innerBox.metadata,
599
- lineNumber: innerBox.lineNumber,
600
- ...iFrame,
601
- bandH: SKETCH_GEOMETRY.bandPx
602
- });
603
- minX = Math.min(minX, iFrame.x);
604
- minY = Math.min(minY, iFrame.y);
605
- maxX = Math.max(maxX, iFrame.x + iFrame.w);
606
- maxY = Math.max(maxY, iFrame.y + iFrame.h);
607
- }
608
- boxes.push({
609
- id: unit.box.id,
610
- label: unit.box.label,
611
- metadata: unit.box.metadata,
612
- lineNumber: unit.box.lineNumber,
613
- x: minX - SKETCH_GEOMETRY.boxPadPx,
614
- y: minY - SKETCH_GEOMETRY.bandPx,
615
- w: maxX - minX + 2 * SKETCH_GEOMETRY.boxPadPx,
616
- h: maxY - minY + SKETCH_GEOMETRY.bandPx + SKETCH_GEOMETRY.boxPadPx,
617
- bandH: SKETCH_GEOMETRY.bandPx
618
- });
619
- }
620
- }
621
- if (flags.avoidEdges) {
622
- const authored = /* @__PURE__ */ new Set();
623
- for (const unit of rootUnits) {
624
- if (atOf(unit) !== null) {
625
- authored.add(unit.kind === "shape" ? unit.node.id : unit.box.id);
626
- }
627
- }
628
- const centerOf = (id) => {
629
- const n = nodes.find((nd) => nd.id === id);
630
- if (n) return { x: n.x + n.w / 2, y: n.y + n.h / 2 };
631
- const b = boxes.find((bx) => bx.id === id);
632
- if (b) return { x: b.x + b.w / 2, y: b.y + b.h / 2 };
633
- return null;
634
- };
635
- const segHitsRect = (ax, ay, bx, by, rx0, ry0, rx1, ry1) => {
636
- let t0 = 0;
637
- let t1 = 1;
638
- const p = [-(bx - ax), bx - ax, -(by - ay), by - ay];
639
- const q = [ax - rx0, rx1 - ax, ay - ry0, ry1 - ay];
640
- for (let i = 0; i < 4; i++) {
641
- if (p[i] === 0) {
642
- if (q[i] < 0) return false;
643
- } else {
644
- const t = q[i] / p[i];
645
- if (p[i] < 0) {
646
- if (t > t1) return false;
647
- if (t > t0) t0 = t;
648
- } else {
649
- if (t < t0) return false;
650
- if (t < t1) t1 = t;
651
- }
652
- }
653
- }
654
- return t0 <= t1;
655
- };
656
- const warned = /* @__PURE__ */ new Set();
657
- for (let pass = 0; pass < 4; pass++) {
658
- let moved = false;
659
- for (const n of nodes) {
660
- if (n.boxLabel) continue;
661
- if (authored.has(n.id)) continue;
662
- for (const e of collapsed.edges) {
663
- if (e.sourceId === n.id || e.targetId === n.id) continue;
664
- const a = centerOf(e.sourceId);
665
- const b = centerOf(e.targetId);
666
- if (!a || !b) continue;
667
- if (!segHitsRect(a.x, a.y, b.x, b.y, n.x, n.y, n.x + n.w, n.y + n.h))
668
- continue;
669
- const ncx = n.x + n.w / 2;
670
- const ncy = n.y + n.h / 2;
671
- const m = n;
672
- if (Math.abs(b.x - a.x) >= Math.abs(b.y - a.y)) {
673
- const lineY = a.y + (b.y - a.y) * (ncx - a.x) / (b.x - a.x || 1);
674
- let dir = ncy >= lineY ? 1 : -1;
675
- if (n.slot.r + dir * SKETCH_SEP < 0) dir = 1;
676
- m.y += dir * SKETCH_SLOT_Y;
677
- m.slot = { c: n.slot.c, r: n.slot.r + dir * SKETCH_SEP };
678
- } else {
679
- const lineX = a.x + (b.x - a.x) * (ncy - a.y) / (b.y - a.y || 1);
680
- let dir = ncx >= lineX ? 1 : -1;
681
- if (n.slot.c + dir * SKETCH_SEP < 0) dir = 1;
682
- m.x += dir * SKETCH_SLOT_X;
683
- m.slot = { c: n.slot.c + dir * SKETCH_SEP, r: n.slot.r };
684
- }
685
- if (!warned.has(n.id)) {
686
- overlapWarn(n.lineNumber, n.label);
687
- warned.add(n.id);
688
- }
689
- moved = true;
690
- break;
691
- }
692
- }
693
- if (!moved) break;
694
- }
695
- }
696
- let width = 0;
697
- let height = 0;
698
- for (const n of nodes) {
699
- width = Math.max(width, n.x + n.w);
700
- height = Math.max(height, n.y + n.h);
701
- }
702
- for (const b of boxes) {
703
- width = Math.max(width, b.x + b.w);
704
- height = Math.max(height, b.y + b.h);
705
- }
706
- const orderedBoxes = [
707
- ...boxes.filter((b) => !nestedBoxIds.has(b.id)),
708
- ...boxes.filter((b) => nestedBoxIds.has(b.id))
709
- ];
710
- return {
711
- nodes,
712
- boxes: orderedBoxes,
713
- edges: collapsed.edges,
714
- width,
715
- height,
716
- diagnostics,
717
- origin: { c: cMin, r: rMin }
718
- };
719
- }
720
-
721
- export {
722
- SKETCH_GEOMETRY,
723
- SKETCH_FOOT_W,
724
- SKETCH_FOOT_H,
725
- SKETCH_HALF_SLOT_X,
726
- SKETCH_HALF_SLOT_Y,
727
- SKETCH_SEP,
728
- SKETCH_SLOT_X,
729
- SKETCH_SLOT_Y,
730
- sketchSlotToPx,
731
- collapseSketch,
732
- SKETCH_AUTO_LAYOUT_DEFAULTS,
733
- layoutSketch
734
- };