@diagrammo/dgmo 0.48.2 → 0.49.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 (216) hide show
  1. package/.cursorrules +8 -3
  2. package/.github/copilot-instructions.md +8 -3
  3. package/.windsurfrules +8 -3
  4. package/SKILL.md +8 -3
  5. package/dist/advanced.d.ts +444 -1
  6. package/dist/advanced.js +208 -146
  7. package/dist/auto.css +63 -0
  8. package/dist/auto.js +202 -102
  9. package/dist/auto.mjs +6849 -824
  10. package/dist/block.css +63 -0
  11. package/dist/block.d.ts +13 -5
  12. package/dist/block.js +137 -57
  13. package/dist/{charts-d3-QOZHKTCT.js → charts-d3-EW3YQTEA.js} +9 -8
  14. package/dist/chunk-26RVGM44.js +331 -0
  15. package/dist/{chunk-44CM72SQ.js → chunk-2WMBWZY2.js} +3 -3
  16. package/dist/{chunk-L66GEFB6.js → chunk-35BBZDFE.js} +4 -4
  17. package/dist/{chunk-4GRI7MEB.js → chunk-3BIAFYD2.js} +6 -6
  18. package/dist/chunk-3NFJWFNP.js +1474 -0
  19. package/dist/{chunk-76OWZ3BA.js → chunk-4BD7EVPK.js} +2 -2
  20. package/dist/{chunk-MITI6NOL.js → chunk-4FIV4K4Z.js} +9 -9
  21. package/dist/chunk-4HVNZ7WF.js +574 -0
  22. package/dist/{chunk-X5LCYCL5.js → chunk-4NQ3IKUM.js} +2 -2
  23. package/dist/{chunk-PWIHZ6NJ.js → chunk-4UDKKGHH.js} +4 -4
  24. package/dist/{chunk-6NYWYNBI.js → chunk-4XK3FLFB.js} +3 -3
  25. package/dist/chunk-4YNP6O47.js +607 -0
  26. package/dist/{chunk-3MQQNXPD.js → chunk-5FGDJIJX.js} +3 -3
  27. package/dist/{chunk-WCT3NYCV.js → chunk-5LWQH6QV.js} +1 -1
  28. package/dist/chunk-5XCM7UUW.js +261 -0
  29. package/dist/{chunk-RYEGFMUO.js → chunk-5ZZLLBFK.js} +2 -2
  30. package/dist/{chunk-EB6FPQUP.js → chunk-65RTDUZH.js} +3 -3
  31. package/dist/chunk-6CLKNXVP.js +664 -0
  32. package/dist/{chunk-H6PI3KJT.js → chunk-6IUAK7RZ.js} +2 -2
  33. package/dist/{chunk-ZGR7ULFJ.js → chunk-6SA7FJE4.js} +31 -19
  34. package/dist/{chunk-LIOHW36Z.js → chunk-6VE3VLWM.js} +3 -3
  35. package/dist/{chunk-AN2MOO5T.js → chunk-7OVSJI2V.js} +3 -3
  36. package/dist/{chunk-YAA6IID3.js → chunk-7UEMZREK.js} +2 -2
  37. package/dist/{chunk-FCIIHT24.js → chunk-7VLUGEMJ.js} +7 -7
  38. package/dist/{chunk-VOKGH627.js → chunk-AHGF2YYA.js} +13 -3
  39. package/dist/{chunk-3R5POCTZ.js → chunk-AJ2PEY7J.js} +6 -6
  40. package/dist/{chunk-PBHE5UG6.js → chunk-ALRHIR6I.js} +46 -12
  41. package/dist/{chunk-7JEGTRLD.js → chunk-B57V3DWN.js} +3 -3
  42. package/dist/{chunk-ILKORZ3H.js → chunk-BCT5G2VN.js} +7 -7
  43. package/dist/{chunk-TYS6CSS5.js → chunk-BCYVE3N5.js} +2 -2
  44. package/dist/{chunk-ZBWMSD5N.js → chunk-BGJV5ATD.js} +4 -4
  45. package/dist/{chunk-G2H74XJZ.js → chunk-BPIJLRYE.js} +8 -8
  46. package/dist/{chunk-YGJTDXVR.js → chunk-C4GQDB5L.js} +2 -2
  47. package/dist/{chunk-Y2ZE3MSG.js → chunk-C63UWAKM.js} +2 -2
  48. package/dist/{chunk-QEBUY5NY.js → chunk-CEHZOPGM.js} +4 -4
  49. package/dist/{chunk-725LDASD.js → chunk-CLD2OKV7.js} +2 -2
  50. package/dist/{chunk-5QXL4NYS.js → chunk-CLR4A2N2.js} +10 -5
  51. package/dist/{chunk-WBRZJOEC.js → chunk-CMCR5WBW.js} +3 -3
  52. package/dist/{chunk-SML67VPV.js → chunk-D5AVQCDN.js} +3 -3
  53. package/dist/{chunk-2LACINWN.js → chunk-DDTJ5N7Q.js} +9 -9
  54. package/dist/{chunk-FITOLXSX.js → chunk-EOFPYPAU.js} +26 -2
  55. package/dist/{chunk-B65G5DNL.js → chunk-EYN7VFKL.js} +3 -3
  56. package/dist/{chunk-4OHACBGX.js → chunk-F2L5GCQ4.js} +2 -2
  57. package/dist/{chunk-RVMRZAPB.js → chunk-F743CM2N.js} +3 -3
  58. package/dist/{chunk-3JLKYGBQ.js → chunk-F7BFXWNQ.js} +2 -2
  59. package/dist/{chunk-WCSOJFU3.js → chunk-FMKTYMP4.js} +3 -3
  60. package/dist/{chunk-RTLBSQ3G.js → chunk-FUCAB3KQ.js} +3 -3
  61. package/dist/{chunk-SGZYXELT.js → chunk-GB3YZTAM.js} +9 -6
  62. package/dist/{chunk-QLCCJEJI.js → chunk-HBVD67XG.js} +2 -2
  63. package/dist/{chunk-PBAHEPLQ.js → chunk-HGN652MU.js} +7 -6
  64. package/dist/{chunk-3SMGIJDD.js → chunk-HHXOONLX.js} +13 -1
  65. package/dist/{chunk-QOOUC2J5.js → chunk-HQCHYB5F.js} +2 -2
  66. package/dist/chunk-IAEC4KLA.js +492 -0
  67. package/dist/{chunk-J5FIXQRT.js → chunk-IBC35BTK.js} +4 -4
  68. package/dist/{chunk-NURGB5Z4.js → chunk-IFK3GIUW.js} +2 -2
  69. package/dist/{chunk-FANX6UJR.js → chunk-IHLSHCPZ.js} +11 -11
  70. package/dist/{chunk-GMR5MFHJ.js → chunk-IUK7AGD4.js} +2 -2
  71. package/dist/chunk-IVKC4GID.js +32 -0
  72. package/dist/{chunk-OJR3MQYV.js → chunk-JFPY3UJ7.js} +296 -57
  73. package/dist/{chunk-5MLYVTYM.js → chunk-K6HNAY5V.js} +2 -2
  74. package/dist/{chunk-P235SVAH.js → chunk-KQAEKMIX.js} +2 -2
  75. package/dist/{chunk-7DTWEFUE.js → chunk-KUBBJ2CD.js} +10 -10
  76. package/dist/{chunk-BUVJFRPY.js → chunk-KV6Y2HE6.js} +4 -4
  77. package/dist/{chunk-OURHMODR.js → chunk-LG4TWW4U.js} +13 -13
  78. package/dist/{chunk-XAKEUMEJ.js → chunk-LVHPTBO3.js} +3 -3
  79. package/dist/{chunk-ERLBPDGU.js → chunk-MJCG5K2O.js} +2 -2
  80. package/dist/{chunk-THXCFRTU.js → chunk-N4J5KGWG.js} +12 -12
  81. package/dist/{chunk-MZSBFAPJ.js → chunk-NVT6C2VE.js} +9 -9
  82. package/dist/{chunk-AELOBFW5.js → chunk-O5MQPK7E.js} +3 -3
  83. package/dist/{chunk-JM4LEPY3.js → chunk-O7NUCTFU.js} +2 -2
  84. package/dist/{chunk-JED6ZDEE.js → chunk-O7WP4ZD4.js} +2 -2
  85. package/dist/{chunk-ZO27FGJS.js → chunk-PH5X4GIP.js} +2 -2
  86. package/dist/{chunk-B7JUCQUA.js → chunk-PU3AUQPA.js} +4 -4
  87. package/dist/{chunk-YGJZWZTY.js → chunk-PZFVK3IH.js} +2 -2
  88. package/dist/chunk-QQJUTGQH.js +135 -0
  89. package/dist/{chunk-HSH73DP6.js → chunk-RI4NIMFP.js} +99 -39
  90. package/dist/{chunk-33LCUH4H.js → chunk-RTERS6S5.js} +3 -3
  91. package/dist/{chunk-T3UBLACL.js → chunk-SCQ5VPUF.js} +19 -5
  92. package/dist/chunk-SGHSY3LU.js +377 -0
  93. package/dist/{chunk-SRTU6HMQ.js → chunk-SJEGO2QL.js} +8 -8
  94. package/dist/chunk-SQDFK5ZQ.js +273 -0
  95. package/dist/{chunk-PZMETGLY.js → chunk-SVDWQGX2.js} +296 -121
  96. package/dist/{chunk-Z5CGSFJB.js → chunk-T7IKPCMI.js} +4 -4
  97. package/dist/chunk-TC3YWBFO.js +233 -0
  98. package/dist/{chunk-EVCVDTXE.js → chunk-TLKMTQYL.js} +3 -3
  99. package/dist/{chunk-IJZFN3HM.js → chunk-TWQUYVP3.js} +4 -4
  100. package/dist/{chunk-IZMRON6C.js → chunk-UVCXZEGU.js} +2 -2
  101. package/dist/{chunk-CKNVO24D.js → chunk-UWDO3O52.js} +2 -2
  102. package/dist/{chunk-RJE5JTVK.js → chunk-VC3TR4NL.js} +7 -7
  103. package/dist/{chunk-CI2G3OEB.js → chunk-X2CH42BN.js} +9 -9
  104. package/dist/{chunk-6HO5ZTXK.js → chunk-XCC2RENT.js} +2 -2
  105. package/dist/chunk-XHVV4NVW.js +51 -0
  106. package/dist/{chunk-ZJEL4H2R.js → chunk-XJ7J6WOO.js} +9 -9
  107. package/dist/{chunk-ULOEATBZ.js → chunk-XKTN7CZF.js} +106 -29
  108. package/dist/{chunk-IPWPWM6R.js → chunk-YM2BSPYW.js} +111 -10
  109. package/dist/{chunk-BUPDIHML.js → chunk-YRVLP7UU.js} +3 -3
  110. package/dist/{chunk-T2OE3YQB.js → chunk-YTN572Q2.js} +3 -3
  111. package/dist/{chunk-WVAJFAIA.js → chunk-YYX3SU6H.js} +3 -3
  112. package/dist/{chunk-MO5YHHMQ.js → chunk-ZDUQGL3N.js} +2 -2
  113. package/dist/{chunk-Y3J7VR52.js → chunk-ZNQX6QWH.js} +30 -2
  114. package/dist/{chunk-UWN33VNX.js → chunk-ZREZOIGS.js} +8 -8
  115. package/dist/{chunk-6SM5NJQH.js → chunk-ZTLWVRNS.js} +4 -4
  116. package/dist/{chunk-RUNNI6VE.js → chunk-ZXL6MB4R.js} +3 -3
  117. package/dist/cli.cjs +159 -122
  118. package/dist/dgmo-router-ODKPEJ3P.js +79 -0
  119. package/dist/dimensions-WSIJXT5Q.js +22 -0
  120. package/dist/editor.js +4 -1
  121. package/dist/element.js +203 -103
  122. package/dist/element.mjs +6849 -824
  123. package/dist/{flowchart-parser-ZNSKIBVR.js → flowchart-parser-IVZN7CQN.js} +4 -4
  124. package/dist/{flowchart-renderer-SNDSII4D.js → flowchart-renderer-GMI2U3DD.js} +9 -9
  125. package/dist/highlight.js +7 -1
  126. package/dist/index.d.ts +5 -1
  127. package/dist/index.js +193 -232
  128. package/dist/{layout-HRBZPFCN.js → layout-34CLNICW.js} +5 -5
  129. package/dist/{layout-5RA6QWR6.js → layout-4Z5JM7PT.js} +6 -6
  130. package/dist/layout-6RDJHS6E.js +9 -0
  131. package/dist/{layout-7QXCNOVS.js → layout-7H4H46CS.js} +3 -3
  132. package/dist/{layout-46N4JJYK.js → layout-7SKMFYHL.js} +5 -5
  133. package/dist/{layout-HWDSRX5E.js → layout-D42XE4RE.js} +6 -6
  134. package/dist/{layout-EE6GE46Y.js → layout-DC4TVXER.js} +5 -5
  135. package/dist/layout-FGQWRYYW.js +14 -0
  136. package/dist/layout-GZ2CWONU.js +14 -0
  137. package/dist/layout-HQMBPJVS.js +10 -0
  138. package/dist/{layout-UM5F4DJB.js → layout-K2ZN3Q42.js} +5 -5
  139. package/dist/{layout-S2QBYSK2.js → layout-NXG63LWH.js} +3 -3
  140. package/dist/{layout-N76NR4ZO.js → layout-PUQCB6AN.js} +7 -7
  141. package/dist/{layout-HYZPWAK5.js → layout-QNUQLEHU.js} +3 -3
  142. package/dist/layout-S3EK4IYO.js +14 -0
  143. package/dist/{layout-search-OYV77HHS.js → layout-search-QS44PI5R.js} +6 -6
  144. package/dist/{parser-KNSQSKQO.js → parser-4BKIFG2C.js} +5 -5
  145. package/dist/{parser-OV7NOBW6.js → parser-4ROBKVUR.js} +4 -4
  146. package/dist/parser-667RGSUW.js +13 -0
  147. package/dist/{parser-IXSZZQHY.js → parser-BL7Z72EY.js} +4 -4
  148. package/dist/{parser-AQETEVRW.js → parser-CLMFZWCC.js} +4 -4
  149. package/dist/{parser-XKRP7QKP.js → parser-D6ONJQFR.js} +3 -3
  150. package/dist/{parser-2EWECDSA.js → parser-DERPY5KC.js} +4 -4
  151. package/dist/{parser-4OGOBJJ4.js → parser-GFSOPDB7.js} +4 -4
  152. package/dist/{parser-2MFP2H2E.js → parser-HVJFTOXL.js} +3 -3
  153. package/dist/{parser-VQP2UJ6W.js → parser-IKZFTLOJ.js} +3 -3
  154. package/dist/parser-J3P2D6IP.js +13 -0
  155. package/dist/{parser-PQ3POX45.js → parser-JD7OQ2E6.js} +4 -4
  156. package/dist/{parser-O5J4VBII.js → parser-K647FRI4.js} +3 -3
  157. package/dist/{parser-NGU3ETO6.js → parser-KPMN5KKE.js} +4 -4
  158. package/dist/{parser-4FL2CMDG.js → parser-MBJSBTL5.js} +4 -4
  159. package/dist/{parser-TFZFBVWN.js → parser-MCJWF5G3.js} +3 -3
  160. package/dist/{parser-NRAI6O25.js → parser-MRBPXXIV.js} +4 -4
  161. package/dist/{parser-6BTRLKRZ.js → parser-OBQG655V.js} +4 -4
  162. package/dist/{parser-3STE62GB.js → parser-QJYS7KQQ.js} +4 -4
  163. package/dist/{parser-XDVELHRK.js → parser-SMBJO3XN.js} +4 -4
  164. package/dist/{parser-TRTHDFPP.js → parser-TITK4YW6.js} +5 -5
  165. package/dist/{parser-I6KXEYFK.js → parser-TNYX5S7E.js} +4 -4
  166. package/dist/{parser-Y6WTBU76.js → parser-UBGPTIZD.js} +3 -3
  167. package/dist/parser-UGA23PYK.js +14 -0
  168. package/dist/{parser-N5O4IHUN.js → parser-WISPH7LW.js} +4 -4
  169. package/dist/{parser-CFZD5IBL.js → parser-XWUDFJ7P.js} +4 -4
  170. package/dist/parser-ZKF5K2H2.js +15 -0
  171. package/dist/{parser-ZSDPZYQP.js → parser-ZYC3XGNS.js} +4 -4
  172. package/dist/{renderer-AWWAF6XD.js → renderer-4IUPINAE.js} +10 -10
  173. package/dist/renderer-6L3NBEY5.js +24 -0
  174. package/dist/{renderer-ZRNG54CW.js → renderer-6T3KK4S3.js} +11 -11
  175. package/dist/{renderer-KQB7UGDS.js → renderer-7RH2SI3B.js} +3 -3
  176. package/dist/{renderer-6EEZHMH4.js → renderer-A5VFZQQK.js} +9 -9
  177. package/dist/{renderer-5MYBMBYO.js → renderer-BB5PREMY.js} +5 -5
  178. package/dist/{renderer-BYCNMBF7.js → renderer-CGW7QPNA.js} +10 -10
  179. package/dist/{renderer-QIWVHWZO.js → renderer-DAXMXIKD.js} +3 -3
  180. package/dist/{renderer-7MVLWWQD.js → renderer-DKESNMU5.js} +9 -9
  181. package/dist/{renderer-UV6MI64M.js → renderer-HVCU2C3Z.js} +3 -3
  182. package/dist/{renderer-VACVQYML.js → renderer-LWGJFT3D.js} +8 -8
  183. package/dist/{renderer-PGX2TKVS.js → renderer-MFJ7HY2H.js} +8 -8
  184. package/dist/{renderer-B2OMQIQG.js → renderer-MJDDU27W.js} +15 -15
  185. package/dist/{renderer-4JHRUBE6.js → renderer-QL5KO6SK.js} +10 -10
  186. package/dist/{renderer-W4M6QLIJ.js → renderer-QNHUXCRL.js} +14 -14
  187. package/dist/{renderer-ZGNTUWC4.js → renderer-ROV756WT.js} +8 -8
  188. package/dist/{renderer-YY2OSF6E.js → renderer-SQ3JUAI7.js} +9 -9
  189. package/dist/renderer-THD6V5TL.js +22 -0
  190. package/dist/{renderer-5NDVNDAZ.js → renderer-TPIBXNOS.js} +9 -9
  191. package/dist/{renderer-RPOA5YPZ.js → renderer-TYXRHMRI.js} +13 -13
  192. package/dist/{renderer-N43WR5GV.js → renderer-UZF3JROD.js} +11 -11
  193. package/dist/{renderer-6W5462RB.js → renderer-V3JEMWMM.js} +9 -9
  194. package/dist/{renderer-JGBKUCZD.js → renderer-VFUVRNLK.js} +4 -4
  195. package/dist/{renderer-Z7I3W2PP.js → renderer-VICQ4WNY.js} +8 -8
  196. package/dist/renderer-W5RMOURB.js +21 -0
  197. package/dist/renderer-XEKIRPI6.js +23 -0
  198. package/dist/{renderer-CLJHQPBJ.js → renderer-YHXPN3GF.js} +12 -12
  199. package/dist/renderer-radial-MHO2VDXN.js +21 -0
  200. package/dist/{resolver-NOAA7ID7.js → resolver-FHBCO3PL.js} +3 -3
  201. package/dist/{state-parser-Z2V23ATR.js → state-parser-RX3GXOIB.js} +4 -4
  202. package/dist/{state-renderer-B4DQBM6M.js → state-renderer-AJUKGNWU.js} +9 -9
  203. package/docs/ai-integration.md +8 -3
  204. package/docs/language-reference.md +179 -5
  205. package/gallery/fixtures/family.dgmo +23 -0
  206. package/gallery/fixtures/sketch.dgmo +22 -0
  207. package/package.json +1 -1
  208. package/dist/chunk-ODZVHU3R.js +0 -153
  209. package/dist/dgmo-router-X35VLZLM.js +0 -73
  210. package/dist/dimensions-J3FHIMJ6.js +0 -22
  211. package/dist/layout-5T6RH5M6.js +0 -14
  212. package/dist/layout-G23F7LDH.js +0 -9
  213. package/dist/layout-OB3RI63S.js +0 -14
  214. package/dist/parser-JAL2HD4I.js +0 -13
  215. package/dist/renderer-SMIBCRVB.js +0 -24
  216. package/dist/renderer-radial-C32GPJQ7.js +0 -21
@@ -0,0 +1,377 @@
1
+ import {
2
+ SKETCH_DIAGNOSTIC_CODES
3
+ } from "./chunk-XHVV4NVW.js";
4
+ import {
5
+ makeDgmoError
6
+ } from "./chunk-CXK4DZH3.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: 26,
13
+ /** universal footprint width, in grid cells */
14
+ footprintCellsW: 8,
15
+ /** mandatory gap between footprints, in cells */
16
+ gapCellsX: 4,
17
+ gapCellsY: 4,
18
+ /** box reserved top band, px (spec decision 12) */
19
+ bandPx: 44,
20
+ /** box frame padding around the children bbox, px */
21
+ boxPadPx: 26,
22
+ /** edge-ring (connect hook) width as a fraction of footprint height */
23
+ ringFrac: 0.22
24
+ };
25
+ var SKETCH_FOOT_W = SKETCH_GEOMETRY.footprintCellsW * SKETCH_GEOMETRY.cellPx;
26
+ var SKETCH_FOOT_H = Math.round(SKETCH_FOOT_W / SKETCH_PHI);
27
+ var SKETCH_HALF_SLOT_X = (SKETCH_FOOT_W + SKETCH_GEOMETRY.gapCellsX * SKETCH_GEOMETRY.cellPx) / 2;
28
+ var SKETCH_HALF_SLOT_Y = (SKETCH_FOOT_H + SKETCH_GEOMETRY.gapCellsY * SKETCH_GEOMETRY.cellPx) / 2;
29
+ var SKETCH_SEP = 2;
30
+ function sketchSlotToPx(c, r) {
31
+ return { x: c * SKETCH_HALF_SLOT_X, y: r * SKETCH_HALF_SLOT_Y };
32
+ }
33
+
34
+ // src/sketch/collapse.ts
35
+ function collapseSketch(parsed, collapsedLabels) {
36
+ const collapsed = collapsedLabels ?? new Set(parsed.boxes.filter((b) => b.collapsed).map((b) => b.label));
37
+ if (collapsed.size === 0) {
38
+ return {
39
+ nodes: parsed.nodes,
40
+ boxes: parsed.boxes,
41
+ virtualBoxes: [],
42
+ edges: parsed.edges,
43
+ collapsedChildCounts: /* @__PURE__ */ new Map()
44
+ };
45
+ }
46
+ const virtualBoxes = parsed.boxes.filter((b) => collapsed.has(b.label));
47
+ const boxes = parsed.boxes.filter((b) => !collapsed.has(b.label));
48
+ const nodeToVirtual = /* @__PURE__ */ new Map();
49
+ const collapsedChildCounts = /* @__PURE__ */ new Map();
50
+ for (const box of virtualBoxes) {
51
+ collapsedChildCounts.set(box.label, box.children.length);
52
+ for (const childId of box.children) nodeToVirtual.set(childId, box.id);
53
+ }
54
+ const nodes = parsed.nodes.filter((n) => !nodeToVirtual.has(n.id));
55
+ const edges = [];
56
+ const seen = /* @__PURE__ */ new Set();
57
+ for (const edge of parsed.edges) {
58
+ const sourceId = nodeToVirtual.get(edge.sourceId) ?? edge.sourceId;
59
+ const targetId = nodeToVirtual.get(edge.targetId) ?? edge.targetId;
60
+ if (sourceId === targetId) continue;
61
+ const key = `${sourceId}|${targetId}|${edge.label ?? ""}|${edge.heads}|${edge.dashed}`;
62
+ if (seen.has(key)) continue;
63
+ seen.add(key);
64
+ edges.push({ ...edge, sourceId, targetId });
65
+ }
66
+ return { nodes, boxes, virtualBoxes, edges, collapsedChildCounts };
67
+ }
68
+
69
+ // src/sketch/layout.ts
70
+ function unitRect(c, r) {
71
+ return { c, r, w: SKETCH_SEP, h: SKETCH_SEP };
72
+ }
73
+ function rectsOverlap(a, b) {
74
+ 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;
75
+ }
76
+ function collidesAny(rect, occupied) {
77
+ for (const o of occupied) if (rectsOverlap(rect, o)) return true;
78
+ return false;
79
+ }
80
+ function nearestFree(base, occupied) {
81
+ if (!collidesAny(base, occupied)) return { c: base.c, r: base.r };
82
+ for (let d = 1; d <= 200; d++) {
83
+ const candidates = [];
84
+ for (let dc = -d; dc <= d; dc++) {
85
+ const dr = d - Math.abs(dc);
86
+ candidates.push({ c: base.c + dc, r: base.r + dr });
87
+ if (dr !== 0) candidates.push({ c: base.c + dc, r: base.r - dr });
88
+ }
89
+ candidates.sort((a, b) => {
90
+ const costA = (a.r < base.r ? 2 : 0) + (a.c < base.c ? 1 : 0);
91
+ const costB = (b.r < base.r ? 2 : 0) + (b.c < base.c ? 1 : 0);
92
+ return costA - costB || a.r - b.r || a.c - b.c;
93
+ });
94
+ for (const cand of candidates) {
95
+ if (!collidesAny({ ...base, c: cand.c, r: cand.r }, occupied)) {
96
+ return cand;
97
+ }
98
+ }
99
+ }
100
+ return { c: base.c, r: base.r };
101
+ }
102
+ function layoutChildren(box, nodesById, warn) {
103
+ const occupied = [];
104
+ const children = [];
105
+ const pending = [];
106
+ for (const id of box.children) {
107
+ const node = nodesById.get(id);
108
+ if (!node) continue;
109
+ if (node.at === null) {
110
+ pending.push(node);
111
+ continue;
112
+ }
113
+ const target = unitRect(node.at.c, node.at.r);
114
+ const spot = nearestFree(target, occupied);
115
+ if (spot.c !== node.at.c || spot.r !== node.at.r) {
116
+ warn(node.lineNumber, node.label);
117
+ }
118
+ occupied.push(unitRect(spot.c, spot.r));
119
+ children.push({ node, c: spot.c, r: spot.r });
120
+ }
121
+ let flowRow = occupied.length > 0 ? Math.max(...occupied.map((o) => o.r)) + SKETCH_SEP : 0;
122
+ let flowCol = 0;
123
+ const wrapAt = Math.max(
124
+ SKETCH_SEP * 3,
125
+ occupied.length > 0 ? Math.max(...occupied.map((o) => o.c)) + SKETCH_SEP : SKETCH_SEP * 3
126
+ );
127
+ for (const node of pending) {
128
+ let placed = false;
129
+ while (!placed) {
130
+ const rect = unitRect(flowCol, flowRow);
131
+ if (!collidesAny(rect, occupied)) {
132
+ occupied.push(rect);
133
+ children.push({ node, c: flowCol, r: flowRow });
134
+ placed = true;
135
+ }
136
+ flowCol += SKETCH_SEP;
137
+ if (flowCol > wrapAt) {
138
+ flowCol = 0;
139
+ flowRow += SKETCH_SEP;
140
+ }
141
+ }
142
+ }
143
+ let extent;
144
+ if (occupied.length === 0) {
145
+ extent = { c: 0, r: 0, w: SKETCH_SEP, h: SKETCH_SEP };
146
+ } else {
147
+ const cMin = Math.min(...occupied.map((o) => o.c));
148
+ const rMin = Math.min(...occupied.map((o) => o.r));
149
+ const cMax = Math.max(...occupied.map((o) => o.c + o.w));
150
+ const rMax = Math.max(...occupied.map((o) => o.r + o.h));
151
+ extent = { c: cMin, r: rMin, w: cMax - cMin, h: rMax - rMin };
152
+ }
153
+ return { children, extent };
154
+ }
155
+ function layoutSketch(parsed, options = {}) {
156
+ const diagnostics = [];
157
+ const overlapWarn = (line, label) => {
158
+ diagnostics.push(
159
+ makeDgmoError(
160
+ line,
161
+ `Shape "${label}" overlapped another at its authored position \u2014 moved to the nearest free slot`,
162
+ "warning",
163
+ SKETCH_DIAGNOSTIC_CODES.OVERLAP_RESOLVED
164
+ )
165
+ );
166
+ };
167
+ const collapsed = collapseSketch(parsed, options.collapsedBoxes);
168
+ const nodesById = new Map(collapsed.nodes.map((n) => [n.id, n]));
169
+ const padHsX = SKETCH_GEOMETRY.boxPadPx / SKETCH_HALF_SLOT_X;
170
+ const padHsY = SKETCH_GEOMETRY.boxPadPx / SKETCH_HALF_SLOT_Y;
171
+ const bandHs = SKETCH_GEOMETRY.bandPx / SKETCH_HALF_SLOT_Y;
172
+ const boxLocal = /* @__PURE__ */ new Map();
173
+ const inExpandedBox = /* @__PURE__ */ new Set();
174
+ for (const box of collapsed.boxes) {
175
+ const local = layoutChildren(box, nodesById, overlapWarn);
176
+ boxLocal.set(box.id, local);
177
+ for (const child of local.children) inExpandedBox.add(child.node.id);
178
+ }
179
+ const rootUnits = [];
180
+ for (const node of collapsed.nodes) {
181
+ if (!inExpandedBox.has(node.id)) rootUnits.push({ kind: "shape", node });
182
+ }
183
+ for (const box of collapsed.virtualBoxes) {
184
+ rootUnits.push({ kind: "virtual", box });
185
+ }
186
+ for (const box of collapsed.boxes) {
187
+ rootUnits.push({ kind: "box", box });
188
+ }
189
+ rootUnits.sort((a, b) => {
190
+ const la = a.kind === "shape" ? a.node.lineNumber : a.box.lineNumber;
191
+ const lb = b.kind === "shape" ? b.node.lineNumber : b.box.lineNumber;
192
+ return la - lb;
193
+ });
194
+ const rectFor = (unit, c, r) => {
195
+ if (unit.kind === "box") {
196
+ const local = boxLocal.get(unit.box.id);
197
+ return {
198
+ c: c + local.extent.c - padHsX,
199
+ r: r + local.extent.r - bandHs,
200
+ w: local.extent.w + 2 * padHsX,
201
+ h: local.extent.h + bandHs + padHsY
202
+ };
203
+ }
204
+ return unitRect(c, r);
205
+ };
206
+ const occupied = [];
207
+ const placedAt = /* @__PURE__ */ new Map();
208
+ const pending = [];
209
+ for (const unit of rootUnits) {
210
+ const at = unit.kind === "shape" ? unit.node.at : unit.box.at;
211
+ if (at === null) {
212
+ pending.push(unit);
213
+ continue;
214
+ }
215
+ const base = rectFor(unit, at.c, at.r);
216
+ let spot = { c: at.c, r: at.r };
217
+ if (collidesAny(base, occupied)) {
218
+ const freed = nearestFree(base, occupied);
219
+ spot = {
220
+ c: at.c + (freed.c - base.c),
221
+ r: at.r + (freed.r - base.r)
222
+ };
223
+ const line = unit.kind === "shape" ? unit.node.lineNumber : unit.box.lineNumber;
224
+ const label = unit.kind === "shape" ? unit.node.label : unit.box.label;
225
+ overlapWarn(line, label);
226
+ }
227
+ occupied.push(rectFor(unit, spot.c, spot.r));
228
+ placedAt.set(unit, spot);
229
+ }
230
+ let flowRow = occupied.length > 0 ? Math.ceil(Math.max(...occupied.map((o) => o.r + o.h))) : 0;
231
+ let flowCol = 0;
232
+ const wrapAt = Math.max(
233
+ SKETCH_SEP * 4,
234
+ occupied.length > 0 ? Math.ceil(Math.max(...occupied.map((o) => o.c + o.w))) : SKETCH_SEP * 4
235
+ );
236
+ for (const unit of pending) {
237
+ let placed = false;
238
+ while (!placed) {
239
+ const rect = rectFor(unit, flowCol, flowRow);
240
+ if (!collidesAny(rect, occupied)) {
241
+ occupied.push(rect);
242
+ placedAt.set(unit, { c: flowCol, r: flowRow });
243
+ placed = true;
244
+ }
245
+ flowCol += SKETCH_SEP;
246
+ if (flowCol > wrapAt) {
247
+ flowCol = 0;
248
+ flowRow += SKETCH_SEP;
249
+ }
250
+ }
251
+ }
252
+ const allRects = rootUnits.map((u) => {
253
+ const spot = placedAt.get(u);
254
+ return rectFor(u, spot.c, spot.r);
255
+ });
256
+ const cMin = allRects.length > 0 ? Math.min(...allRects.map((r) => r.c)) : 0;
257
+ const rMin = allRects.length > 0 ? Math.min(...allRects.map((r) => r.r)) : 0;
258
+ const toPx = (c, r) => ({
259
+ x: (c - cMin) * SKETCH_HALF_SLOT_X,
260
+ y: (r - rMin) * SKETCH_HALF_SLOT_Y
261
+ });
262
+ const nodes = [];
263
+ const boxes = [];
264
+ for (const unit of rootUnits) {
265
+ const spot = placedAt.get(unit);
266
+ if (unit.kind === "shape") {
267
+ const { x, y } = toPx(spot.c, spot.r);
268
+ nodes.push({
269
+ id: unit.node.id,
270
+ label: unit.node.label,
271
+ shape: unit.node.shape,
272
+ metadata: unit.node.metadata,
273
+ ...unit.node.description && { description: unit.node.description },
274
+ lineNumber: unit.node.lineNumber,
275
+ slot: spot,
276
+ x,
277
+ y,
278
+ w: SKETCH_FOOT_W,
279
+ h: SKETCH_FOOT_H
280
+ });
281
+ } else if (unit.kind === "virtual") {
282
+ const { x, y } = toPx(spot.c, spot.r);
283
+ nodes.push({
284
+ id: unit.box.id,
285
+ label: unit.box.label,
286
+ shape: "rectangle",
287
+ metadata: unit.box.metadata,
288
+ lineNumber: unit.box.lineNumber,
289
+ slot: spot,
290
+ x,
291
+ y,
292
+ w: SKETCH_FOOT_W,
293
+ h: SKETCH_FOOT_H,
294
+ isCollapsedBox: true,
295
+ childCount: collapsed.collapsedChildCounts.get(unit.box.label) ?? 0
296
+ });
297
+ } else {
298
+ const local = boxLocal.get(unit.box.id);
299
+ let minX = Infinity;
300
+ let minY = Infinity;
301
+ let maxX = -Infinity;
302
+ let maxY = -Infinity;
303
+ for (const child of local.children) {
304
+ const abs = toPx(spot.c + child.c, spot.r + child.r);
305
+ nodes.push({
306
+ id: child.node.id,
307
+ label: child.node.label,
308
+ shape: child.node.shape,
309
+ metadata: child.node.metadata,
310
+ ...child.node.description && {
311
+ description: child.node.description
312
+ },
313
+ boxLabel: unit.box.label,
314
+ lineNumber: child.node.lineNumber,
315
+ slot: { c: spot.c + child.c, r: spot.r + child.r },
316
+ x: abs.x,
317
+ y: abs.y,
318
+ w: SKETCH_FOOT_W,
319
+ h: SKETCH_FOOT_H
320
+ });
321
+ minX = Math.min(minX, abs.x);
322
+ minY = Math.min(minY, abs.y);
323
+ maxX = Math.max(maxX, abs.x + SKETCH_FOOT_W);
324
+ maxY = Math.max(maxY, abs.y + SKETCH_FOOT_H);
325
+ }
326
+ if (minX === Infinity) {
327
+ const origin = toPx(spot.c, spot.r);
328
+ minX = origin.x;
329
+ minY = origin.y + SKETCH_GEOMETRY.bandPx;
330
+ maxX = origin.x + SKETCH_FOOT_W;
331
+ maxY = minY;
332
+ }
333
+ boxes.push({
334
+ id: unit.box.id,
335
+ label: unit.box.label,
336
+ metadata: unit.box.metadata,
337
+ lineNumber: unit.box.lineNumber,
338
+ x: minX - SKETCH_GEOMETRY.boxPadPx,
339
+ y: minY - SKETCH_GEOMETRY.bandPx,
340
+ w: maxX - minX + 2 * SKETCH_GEOMETRY.boxPadPx,
341
+ h: maxY - minY + SKETCH_GEOMETRY.bandPx + SKETCH_GEOMETRY.boxPadPx,
342
+ bandH: SKETCH_GEOMETRY.bandPx
343
+ });
344
+ }
345
+ }
346
+ let width = 0;
347
+ let height = 0;
348
+ for (const n of nodes) {
349
+ width = Math.max(width, n.x + n.w);
350
+ height = Math.max(height, n.y + n.h);
351
+ }
352
+ for (const b of boxes) {
353
+ width = Math.max(width, b.x + b.w);
354
+ height = Math.max(height, b.y + b.h);
355
+ }
356
+ return {
357
+ nodes,
358
+ boxes,
359
+ edges: collapsed.edges,
360
+ width,
361
+ height,
362
+ diagnostics
363
+ };
364
+ }
365
+
366
+ export {
367
+ SKETCH_GEOMETRY,
368
+ SKETCH_FOOT_W,
369
+ SKETCH_FOOT_H,
370
+ SKETCH_HALF_SLOT_X,
371
+ SKETCH_HALF_SLOT_Y,
372
+ SKETCH_SEP,
373
+ sketchSlotToPx,
374
+ collapseSketch,
375
+ layoutSketch
376
+ };
377
+ //# sourceMappingURL=chunk-SGHSY3LU.js.map
@@ -4,15 +4,15 @@ import {
4
4
  import {
5
5
  wrapDescriptionLines
6
6
  } from "./chunk-BMR4CIEO.js";
7
- import {
8
- renderIntegratedLegend
9
- } from "./chunk-PWIHZ6NJ.js";
10
7
  import {
11
8
  ScaleContext
12
9
  } from "./chunk-YYVTBZZC.js";
10
+ import {
11
+ renderIntegratedLegend
12
+ } from "./chunk-4UDKKGHH.js";
13
13
  import {
14
14
  getMaxLegendReservedHeight
15
- } from "./chunk-YAA6IID3.js";
15
+ } from "./chunk-7UEMZREK.js";
16
16
  import {
17
17
  TITLE_FONT_SIZE,
18
18
  TITLE_FONT_WEIGHT,
@@ -24,7 +24,7 @@ import {
24
24
  import {
25
25
  measureText,
26
26
  truncateText
27
- } from "./chunk-WCT3NYCV.js";
27
+ } from "./chunk-5LWQH6QV.js";
28
28
  import {
29
29
  contrastText,
30
30
  mix,
@@ -35,11 +35,11 @@ import {
35
35
  isSequenceBlock,
36
36
  isSequenceNote,
37
37
  isSequenceSection
38
- } from "./chunk-SML67VPV.js";
38
+ } from "./chunk-D5AVQCDN.js";
39
39
  import {
40
40
  resolveActiveTagGroup,
41
41
  tagAttrKey
42
- } from "./chunk-QLCCJEJI.js";
42
+ } from "./chunk-HBVD67XG.js";
43
43
 
44
44
  // src/sequence/renderer.ts
45
45
  import * as d3Selection from "d3-selection";
@@ -1848,4 +1848,4 @@ export {
1848
1848
  renderSequenceDiagram,
1849
1849
  buildNoteMessageMap
1850
1850
  };
1851
- //# sourceMappingURL=chunk-SRTU6HMQ.js.map
1851
+ //# sourceMappingURL=chunk-SJEGO2QL.js.map
@@ -0,0 +1,273 @@
1
+ import {
2
+ familyCardRows,
3
+ familyDisplayLabel
4
+ } from "./chunk-IVKC4GID.js";
5
+ import {
6
+ CARD_RADIUS,
7
+ EDGE_STROKE_WIDTH,
8
+ HEADER_HEIGHT,
9
+ LABEL_FONT_SIZE,
10
+ META_FONT_SIZE,
11
+ META_LINE_HEIGHT,
12
+ NODE_STROKE_WIDTH,
13
+ SEPARATOR_GAP
14
+ } from "./chunk-3CIOJ5YJ.js";
15
+ import {
16
+ renderIntegratedLegend
17
+ } from "./chunk-4UDKKGHH.js";
18
+ import {
19
+ getMaxLegendReservedHeight
20
+ } from "./chunk-7UEMZREK.js";
21
+ import {
22
+ TITLE_FONT_SIZE,
23
+ TITLE_FONT_WEIGHT,
24
+ TITLE_Y
25
+ } from "./chunk-A4GOY3PE.js";
26
+ import {
27
+ FONT_FAMILY
28
+ } from "./chunk-6KFWC4CO.js";
29
+ import {
30
+ LEGEND_GROUP_GAP
31
+ } from "./chunk-HQCHYB5F.js";
32
+ import {
33
+ measureText
34
+ } from "./chunk-5LWQH6QV.js";
35
+ import {
36
+ contrastText,
37
+ mix,
38
+ shapeFill,
39
+ themeBaseBg
40
+ } from "./chunk-P6T66CCZ.js";
41
+ import {
42
+ resolveTagColor,
43
+ tagAttrKey
44
+ } from "./chunk-HBVD67XG.js";
45
+ import {
46
+ resolveColor
47
+ } from "./chunk-TLVIHFRO.js";
48
+
49
+ // src/family/renderer.ts
50
+ import * as d3Selection from "d3-selection";
51
+ var KEY_X = 10;
52
+ var KEY_VALUE_GAP = 6;
53
+ var BAR_DOT_R = 3.5;
54
+ var TITLE_RESERVE = 40;
55
+ var DIM_OPACITY = 0.28;
56
+ var ROMAN = [
57
+ [10, "X"],
58
+ [9, "IX"],
59
+ [5, "V"],
60
+ [4, "IV"],
61
+ [1, "I"]
62
+ ];
63
+ function toRoman(n) {
64
+ let out = "";
65
+ let v = n;
66
+ for (const [val, sym] of ROMAN)
67
+ while (v >= val) {
68
+ out += sym;
69
+ v -= val;
70
+ }
71
+ return out;
72
+ }
73
+ function baseColor(node, parsed, palette, activeTagGroup) {
74
+ if (node.color) {
75
+ const c = resolveColor(node.color, palette);
76
+ if (c) return c;
77
+ }
78
+ if (activeTagGroup) {
79
+ const c = resolveTagColor(
80
+ node.tagMetadata,
81
+ [...parsed.tagGroups],
82
+ activeTagGroup
83
+ );
84
+ if (c && c !== "#999999") return c;
85
+ }
86
+ return palette.primary;
87
+ }
88
+ function renderFamilyForExport(container, parsed, layout, palette, isDark, opts = {}) {
89
+ d3Selection.select(container).selectAll(":not([data-d3-tooltip])").remove();
90
+ const activeTagGroup = opts.activeTagGroup ?? null;
91
+ const solid = parsed.options["solid-fill"] === "on";
92
+ const noDaggers = parsed.options["no-daggers"] === "true";
93
+ const baseBg = themeBaseBg(palette, isDark);
94
+ const PAD = 20;
95
+ const MAX_SCALE = 1.5;
96
+ const titleReserve = parsed.title ? TITLE_RESERVE : 0;
97
+ const legendGroups = parsed.tagGroups.filter((g) => g.entries.length > 0).map((g) => ({
98
+ name: g.name,
99
+ entries: g.entries.map((e) => ({ value: e.value, color: e.color }))
100
+ }));
101
+ const hasLegend = legendGroups.length > 0;
102
+ const legendConfig = {
103
+ groups: legendGroups,
104
+ position: { placement: "top-center", titleRelation: "below-title" },
105
+ mode: opts.exportMode ? "export" : "preview",
106
+ showInactivePills: true
107
+ };
108
+ const contentW = layout.width;
109
+ const contentH = layout.height;
110
+ const W = opts.fit?.width ?? opts.exportDims?.width ?? contentW + PAD * 2;
111
+ const legendReserve = hasLegend ? getMaxLegendReservedHeight(legendConfig, W) + LEGEND_GROUP_GAP : 0;
112
+ const chrome = titleReserve + legendReserve;
113
+ let scale = 1;
114
+ let H;
115
+ if (opts.fit) {
116
+ H = opts.fit.height;
117
+ const availW = Math.max(1, W - PAD * 2);
118
+ const availH = Math.max(1, H - chrome - PAD * 2);
119
+ scale = Math.min(MAX_SCALE, availW / contentW, availH / contentH);
120
+ if (!Number.isFinite(scale) || scale <= 0) scale = 1;
121
+ } else {
122
+ H = contentH + chrome + PAD * 2;
123
+ }
124
+ const svg = d3Selection.select(container).append("svg").attr("xmlns", "http://www.w3.org/2000/svg").attr("width", W).attr("height", H).attr("viewBox", `0 0 ${W} ${H}`).attr("preserveAspectRatio", "xMidYMin meet").attr("data-fit-scale", scale.toFixed(3)).style("font-family", FONT_FAMILY);
125
+ svg.append("style").text(
126
+ ".family-focus-icon{opacity:0;transition:opacity .15s ease;pointer-events:none}.family-card:hover .family-focus-icon{opacity:.6;pointer-events:all}.family-focus-icon:hover{opacity:1}"
127
+ );
128
+ if (parsed.title) {
129
+ svg.append("text").attr("x", W / 2).attr("y", TITLE_Y).attr("text-anchor", "middle").attr("font-size", TITLE_FONT_SIZE).attr("font-weight", TITLE_FONT_WEIGHT).attr("fill", palette.text).text(parsed.title);
130
+ }
131
+ if (hasLegend) {
132
+ const legendParent = svg.append("g").attr("transform", `translate(0, ${titleReserve})`);
133
+ renderIntegratedLegend(legendParent, {
134
+ ...legendConfig,
135
+ palette,
136
+ isDark,
137
+ width: W,
138
+ activeGroup: activeTagGroup
139
+ });
140
+ legendParent.selectAll("[data-legend-group]").classed("family-legend-group", true);
141
+ }
142
+ const contentX = (W - contentW * scale) / 2;
143
+ const root = svg.append("g").attr(
144
+ "transform",
145
+ `translate(${contentX}, ${chrome + PAD}) scale(${scale})`
146
+ );
147
+ if (parsed.options["generations"] === "true" && layout.rows.length > 0) {
148
+ const bandG = root.append("g").attr("class", "family-generation-bands");
149
+ const toneA = mix(palette.textMuted, baseBg, 7);
150
+ const toneB = mix(palette.textMuted, baseBg, 2);
151
+ const BAND_VPAD = 12;
152
+ const BAND_INSET = 2;
153
+ for (let i = 0; i < layout.rows.length; i++) {
154
+ const r = layout.rows[i];
155
+ bandG.append("rect").attr("x", BAND_INSET).attr("y", r.y - BAND_VPAD).attr("width", Math.max(0, contentW - BAND_INSET * 2)).attr("height", r.height + BAND_VPAD * 2).attr("rx", CARD_RADIUS).attr("fill", i % 2 === 0 ? toneA : toneB);
156
+ }
157
+ }
158
+ const edgeG = root.append("g").attr("class", "family-edges");
159
+ const pathD = (pts) => pts.map((p, i) => `${i ? "L" : "M"}${p.x} ${p.y}`).join(" ");
160
+ const line = (pts, dashed, dimmed) => {
161
+ edgeG.append("path").attr("d", pathD(pts)).attr("fill", "none").attr("stroke", palette.textMuted).attr("stroke-width", EDGE_STROKE_WIDTH).attr("stroke-dasharray", dashed ? "6 3" : null).attr("stroke-opacity", dimmed ? DIM_OPACITY : null);
162
+ };
163
+ const byUnion = /* @__PURE__ */ new Map();
164
+ for (const e of layout.edges) {
165
+ (byUnion.get(e.unionId) ?? byUnion.set(e.unionId, []).get(e.unionId)).push(
166
+ e
167
+ );
168
+ }
169
+ for (const group of byUnion.values()) {
170
+ const first = group[0];
171
+ const allAdopted = group.every((e) => e.adopted);
172
+ const trunkDimmed = group.every((e) => e.dimmed);
173
+ if (first.points.length > 2) {
174
+ line(first.points.slice(0, 2), allAdopted, trunkDimmed);
175
+ for (const e of group) line(e.points.slice(1), e.adopted, !!e.dimmed);
176
+ } else {
177
+ for (const e of group) line(e.points, e.adopted, !!e.dimmed);
178
+ }
179
+ for (const e of group) {
180
+ if (!e.adopted) continue;
181
+ const last = e.points[e.points.length - 1];
182
+ const prev = e.points[e.points.length - 2] ?? last;
183
+ edgeG.append("text").attr("x", last.x + 5).attr("y", (last.y + prev.y) / 2).attr("font-size", META_FONT_SIZE).attr("font-style", "italic").attr("fill", palette.textMuted).attr("fill-opacity", e.dimmed ? DIM_OPACITY : null).text("adopted");
184
+ }
185
+ }
186
+ const barG = root.append("g").attr("class", "family-bars");
187
+ for (const bar of layout.bars) {
188
+ const bg = barG.append("g");
189
+ if (bar.dimmed) bg.attr("opacity", DIM_OPACITY);
190
+ bg.append("line").attr("x1", bar.x1).attr("y1", bar.y).attr("x2", bar.x2).attr("y2", bar.y).attr("stroke", palette.textMuted).attr("stroke-width", EDGE_STROKE_WIDTH).attr("stroke-dasharray", bar.divorced ? "6 3" : null).attr("class", "family-marriage-bar").attr("data-line-number", String(bar.lineNumber));
191
+ bg.append("circle").attr("cx", bar.midX).attr("cy", bar.y).attr("r", BAR_DOT_R).attr("fill", palette.textMuted);
192
+ if (bar.year) {
193
+ bg.append("text").attr("x", bar.labelX).attr("y", bar.y - BAR_DOT_R - 3).attr("text-anchor", "middle").attr("font-size", META_FONT_SIZE).attr("fill", palette.textMuted).attr("stroke", baseBg).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("paint-order", "stroke").text(`m. ${bar.year}`);
194
+ }
195
+ }
196
+ const occludeG = root.append("g").attr("class", "family-dim-occluders");
197
+ for (const node of layout.nodes) {
198
+ if (!node.dimmed) continue;
199
+ occludeG.append("rect").attr("x", node.x).attr("y", node.y).attr("width", node.width).attr("height", node.height).attr("rx", CARD_RADIUS).attr("fill", baseBg);
200
+ }
201
+ const cardsG = root.append("g").attr("class", "family-cards");
202
+ for (const node of layout.nodes) {
203
+ const isPh = !!node.placeholder;
204
+ const base = baseColor(node, parsed, palette, activeTagGroup);
205
+ const fill = isPh ? mix(palette.textMuted, baseBg, 6) : shapeFill(palette, base, isDark, { solid });
206
+ const stroke = isPh ? palette.textMuted : base;
207
+ const labelColor = isPh ? palette.textMuted : contrastText(fill, palette.textOnFillLight, palette.textOnFillDark);
208
+ const g = cardsG.append("g").attr("class", "family-card").attr("transform", `translate(${node.x}, ${node.y})`).attr("data-line-number", String(node.lineNumber)).attr("data-person-id", node.id);
209
+ if (node.dimmed) g.attr("opacity", DIM_OPACITY);
210
+ if (activeTagGroup) {
211
+ const key = tagAttrKey(activeTagGroup);
212
+ const v = node.tagMetadata[key];
213
+ if (v) g.attr(`data-tag-${key}`, v.toLowerCase());
214
+ }
215
+ g.append("rect").attr("x", 0).attr("y", 0).attr("width", node.width).attr("height", node.height).attr("rx", CARD_RADIUS).attr("fill", fill).attr("stroke", stroke).attr("stroke-width", NODE_STROKE_WIDTH);
216
+ g.append("text").attr("x", node.width / 2).attr("y", HEADER_HEIGHT / 2 + LABEL_FONT_SIZE / 2 - 2).attr("text-anchor", "middle").attr("fill", labelColor).attr("font-size", LABEL_FONT_SIZE).attr("font-weight", "bold").text(noDaggers ? node.label : familyDisplayLabel(node));
217
+ if (isPh) continue;
218
+ const fx = node.width - 13;
219
+ const fy = 9;
220
+ const focusG = g.append("g").attr("class", "family-focus-icon").attr("data-focus-person", node.id).attr("data-export-ignore", "true").style("cursor", "pointer");
221
+ focusG.append("rect").attr("x", fx - 6).attr("y", fy - 6).attr("width", 16).attr("height", 16).attr("fill", "transparent");
222
+ focusG.append("circle").attr("cx", fx).attr("cy", fy).attr("r", 5).attr("fill", "none").attr("stroke", labelColor).attr("stroke-width", 1.4);
223
+ focusG.append("circle").attr("cx", fx).attr("cy", fy).attr("r", 1.6).attr("fill", labelColor);
224
+ const rows = familyCardRows(node);
225
+ if (rows.length === 0) continue;
226
+ g.append("line").attr("x1", 0).attr("y1", HEADER_HEIGHT).attr("x2", node.width).attr("y2", HEADER_HEIGHT).attr("stroke", solid ? labelColor : stroke).attr("stroke-opacity", 0.3).attr("stroke-width", 1);
227
+ const maxKeyWidth = Math.max(
228
+ 0,
229
+ ...rows.filter((r) => !r.year).map((r) => measureText(`${r.key}: `, META_FONT_SIZE))
230
+ );
231
+ const valueX = KEY_X + maxKeyWidth + KEY_VALUE_GAP;
232
+ const startY = HEADER_HEIGHT + SEPARATOR_GAP + META_FONT_SIZE;
233
+ rows.forEach((r, i) => {
234
+ const rowY = startY + i * META_LINE_HEIGHT;
235
+ if (r.year) {
236
+ g.append("text").attr("x", KEY_X).attr("y", rowY).attr("fill", labelColor).attr("fill-opacity", 0.7).attr("font-size", META_FONT_SIZE).text(r.value);
237
+ } else {
238
+ g.append("text").attr("x", KEY_X).attr("y", rowY).attr("fill", labelColor).attr("font-size", META_FONT_SIZE).text(`${r.key}: `);
239
+ g.append("text").attr("x", valueX).attr("y", rowY).attr("fill", labelColor).attr("font-size", META_FONT_SIZE).text(r.value);
240
+ }
241
+ });
242
+ }
243
+ if (parsed.options["generations"] === "true") {
244
+ const genG = root.append("g").attr("class", "family-generations");
245
+ for (const rw of layout.rows) {
246
+ genG.append("text").attr("x", 6).attr("y", rw.y + rw.height / 2).attr("dominant-baseline", "middle").attr("font-size", META_FONT_SIZE).attr("font-weight", "bold").attr("fill", palette.textMuted).text(`Gen ${toRoman(rw.row + 1)}`);
247
+ }
248
+ }
249
+ if (layout.ancestors.length > 0 && layout.focusAnchor) {
250
+ const aG = root.append("g").attr("class", "family-ancestors");
251
+ const anchor = layout.focusAnchor;
252
+ const dotY = layout.ancestors[0].y;
253
+ aG.append("line").attr("x1", anchor.x).attr("y1", dotY).attr("x2", anchor.x).attr("y2", anchor.y).attr("stroke", palette.textMuted).attr("stroke-width", EDGE_STROKE_WIDTH).attr("stroke-opacity", 0.5);
254
+ for (const a of layout.ancestors) {
255
+ const hue = (a.color ? resolveColor(a.color, palette) : null) ?? resolveColor(
256
+ a.sex === "m" ? "blue" : a.sex === "f" ? "purple" : "gray",
257
+ palette
258
+ ) ?? palette.textMuted;
259
+ const dot = aG.append("g").attr("data-ancestor", a.label).attr("data-focus-person", a.id).style("cursor", "pointer");
260
+ dot.append("circle").attr("cx", a.x).attr("cy", a.y).attr("r", 6).attr("fill", mix(hue, baseBg, 40)).attr("stroke", hue).attr("stroke-width", 1.5);
261
+ dot.append("text").attr("x", a.x + 10).attr("y", a.y).attr("dominant-baseline", "middle").attr("font-size", META_FONT_SIZE).attr("fill", palette.textMuted).attr("stroke", baseBg).attr("stroke-width", 3).attr("stroke-linejoin", "round").attr("paint-order", "stroke").text(a.label);
262
+ }
263
+ }
264
+ }
265
+ function renderFamily(container, parsed, layout, palette, isDark, opts = {}) {
266
+ renderFamilyForExport(container, parsed, layout, palette, isDark, opts);
267
+ }
268
+
269
+ export {
270
+ renderFamilyForExport,
271
+ renderFamily
272
+ };
273
+ //# sourceMappingURL=chunk-SQDFK5ZQ.js.map