@diagrammo/dgmo 0.47.0 → 0.48.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. package/dist/advanced.js +11 -11
  2. package/dist/auto.js +16 -16
  3. package/dist/auto.mjs +41 -12
  4. package/dist/block.js +4 -4
  5. package/dist/{chunk-FNB3PNGF.js → chunk-7DTWEFUE.js} +3 -3
  6. package/dist/{chunk-2DXMZRWJ.js → chunk-B65G5DNL.js} +8 -1
  7. package/dist/{chunk-RZCF2VVM.js → chunk-B7JUCQUA.js} +3 -1
  8. package/dist/{chunk-DU7W62N5.js → chunk-FANX6UJR.js} +3 -3
  9. package/dist/{chunk-6FZYCKXB.js → chunk-HSH73DP6.js} +2 -2
  10. package/dist/{chunk-P4RH4OSP.js → chunk-ILKORZ3H.js} +2 -2
  11. package/dist/{chunk-Y5QGVTVC.js → chunk-JTSMEYIZ.js} +7 -3
  12. package/dist/{chunk-RCERWOJR.js → chunk-ODZVHU3R.js} +1 -2
  13. package/dist/{chunk-DZAQBW35.js → chunk-SGZYXELT.js} +3 -7
  14. package/dist/{chunk-CUVHQHZ7.js → chunk-THXCFRTU.js} +3 -3
  15. package/dist/{chunk-IH6ZMVQ5.js → chunk-UC7TFHUM.js} +29 -11
  16. package/dist/{chunk-EMS2SK26.js → chunk-ZBWMSD5N.js} +3 -1
  17. package/dist/cli.cjs +15 -15
  18. package/dist/{dgmo-router-DZCIDUO5.js → dgmo-router-X35VLZLM.js} +3 -3
  19. package/dist/element.js +16 -16
  20. package/dist/element.mjs +41 -12
  21. package/dist/{flowchart-renderer-ZAEOL4DX.js → flowchart-renderer-SNDSII4D.js} +2 -2
  22. package/dist/index.d.ts +4 -2
  23. package/dist/index.js +4 -4
  24. package/dist/{parser-FUSKFGZN.js → parser-2EWECDSA.js} +2 -2
  25. package/dist/{renderer-UWA5XS74.js → renderer-4JHRUBE6.js} +3 -3
  26. package/dist/{renderer-WZRREQ2P.js → renderer-5MYBMBYO.js} +2 -2
  27. package/dist/{renderer-TOCOVLHS.js → renderer-B2OMQIQG.js} +3 -3
  28. package/dist/{renderer-2XQQQ6QR.js → renderer-N43WR5GV.js} +3 -3
  29. package/dist/{renderer-T7YKC5VP.js → renderer-ZRNG54CW.js} +3 -3
  30. package/dist/{state-renderer-RFYHSP4K.js → state-renderer-B4DQBM6M.js} +2 -2
  31. package/package.json +23 -71
  32. package/dist/advanced.cjs +0 -71648
  33. package/dist/advanced.d.cts +0 -5719
  34. package/dist/auto.cjs +0 -70648
  35. package/dist/auto.d.cts +0 -54
  36. package/dist/block.cjs +0 -70208
  37. package/dist/block.d.cts +0 -115
  38. package/dist/editor.cjs +0 -526
  39. package/dist/editor.d.cts +0 -26
  40. package/dist/element.cjs +0 -70530
  41. package/dist/element.d.cts +0 -62
  42. package/dist/highlight.cjs +0 -852
  43. package/dist/highlight.d.cts +0 -49
  44. package/dist/index.cjs +0 -70491
  45. package/dist/index.d.cts +0 -160
  46. package/dist/pert.cjs +0 -325
  47. package/dist/pert.d.cts +0 -559
  48. package/dist/themes-1-CuKpeH.d.cts +0 -908
  49. package/src/advanced.ts +0 -873
  50. package/src/arc/parser.ts +0 -15
  51. package/src/arc/renderer.ts +0 -633
  52. package/src/auto/index.ts +0 -621
  53. package/src/auto/shared.ts +0 -370
  54. package/src/auto/styles.ts +0 -73
  55. package/src/block/layout.ts +0 -198
  56. package/src/block/parser.ts +0 -427
  57. package/src/block/renderer.ts +0 -484
  58. package/src/block/types.ts +0 -67
  59. package/src/boxes-and-lines/collapse.ts +0 -96
  60. package/src/boxes-and-lines/focus.ts +0 -257
  61. package/src/boxes-and-lines/label-placement.ts +0 -339
  62. package/src/boxes-and-lines/layout-grouped.ts +0 -912
  63. package/src/boxes-and-lines/layout-layered.ts +0 -722
  64. package/src/boxes-and-lines/layout-search.ts +0 -1678
  65. package/src/boxes-and-lines/layout.ts +0 -398
  66. package/src/boxes-and-lines/parser.ts +0 -1181
  67. package/src/boxes-and-lines/renderer.ts +0 -1465
  68. package/src/boxes-and-lines/types.ts +0 -66
  69. package/src/c4/layout.ts +0 -2441
  70. package/src/c4/parser.ts +0 -1158
  71. package/src/c4/renderer.ts +0 -2008
  72. package/src/c4/types.ts +0 -89
  73. package/src/chart-type-registry.ts +0 -529
  74. package/src/chart-types.ts +0 -225
  75. package/src/chart.ts +0 -685
  76. package/src/charts-d3/bar.ts +0 -338
  77. package/src/charts-d3/chord.ts +0 -140
  78. package/src/charts-d3/function.ts +0 -147
  79. package/src/charts-d3/funnel.ts +0 -104
  80. package/src/charts-d3/heatmap.ts +0 -145
  81. package/src/charts-d3/index.ts +0 -337
  82. package/src/charts-d3/interactions.ts +0 -477
  83. package/src/charts-d3/line.ts +0 -344
  84. package/src/charts-d3/mount.ts +0 -151
  85. package/src/charts-d3/pie.ts +0 -117
  86. package/src/charts-d3/polar.ts +0 -89
  87. package/src/charts-d3/radar.ts +0 -0
  88. package/src/charts-d3/sankey.ts +0 -0
  89. package/src/charts-d3/scatter.ts +0 -185
  90. package/src/charts-d3/shared.ts +0 -208
  91. package/src/class/layout.ts +0 -326
  92. package/src/class/parser.ts +0 -635
  93. package/src/class/renderer.ts +0 -793
  94. package/src/class/types.ts +0 -58
  95. package/src/cli-banner.ts +0 -106
  96. package/src/cli.ts +0 -1080
  97. package/src/colors-diagnostics.ts +0 -35
  98. package/src/colors.ts +0 -379
  99. package/src/completion-types.ts +0 -27
  100. package/src/completion.ts +0 -2668
  101. package/src/cycle/layout.ts +0 -1026
  102. package/src/cycle/parser.ts +0 -387
  103. package/src/cycle/renderer.ts +0 -653
  104. package/src/cycle/types.ts +0 -101
  105. package/src/d3.ts +0 -1434
  106. package/src/data-chart-parser.ts +0 -1007
  107. package/src/dgmo-router.ts +0 -296
  108. package/src/diagnostics-registry.ts +0 -108
  109. package/src/diagnostics.ts +0 -0
  110. package/src/dimensions.ts +0 -20
  111. package/src/directives-registry.ts +0 -396
  112. package/src/editor/dgmo.grammar +0 -76
  113. package/src/editor/dgmo.grammar.d.ts +0 -2
  114. package/src/editor/dgmo.grammar.js +0 -18
  115. package/src/editor/dgmo.grammar.terms.d.ts +0 -5
  116. package/src/editor/dgmo.grammar.terms.js +0 -35
  117. package/src/editor/highlight-api.ts +0 -596
  118. package/src/editor/highlight.ts +0 -36
  119. package/src/editor/index.ts +0 -27
  120. package/src/editor/keywords.ts +0 -128
  121. package/src/editor/tokens.ts +0 -30
  122. package/src/element/index.ts +0 -432
  123. package/src/embed/css.ts +0 -312
  124. package/src/embed/escape.ts +0 -15
  125. package/src/embed/index.ts +0 -280
  126. package/src/er/classify.ts +0 -228
  127. package/src/er/layout.ts +0 -530
  128. package/src/er/parser.ts +0 -750
  129. package/src/er/renderer.ts +0 -725
  130. package/src/er/types.ts +0 -52
  131. package/src/error-card.ts +0 -269
  132. package/src/event-line/diagnostics.ts +0 -117
  133. package/src/event-line/parser.ts +0 -643
  134. package/src/event-line/renderer.ts +0 -1742
  135. package/src/event-line/types.ts +0 -74
  136. package/src/fonts.ts +0 -3
  137. package/src/gantt/calculator.ts +0 -979
  138. package/src/gantt/parser.ts +0 -1641
  139. package/src/gantt/renderer.ts +0 -3787
  140. package/src/gantt/resolver.ts +0 -172
  141. package/src/gantt/types.ts +0 -206
  142. package/src/graph/diagnostics.ts +0 -64
  143. package/src/graph/edge-spline.ts +0 -29
  144. package/src/graph/flowchart-parser.ts +0 -759
  145. package/src/graph/flowchart-renderer.ts +0 -817
  146. package/src/graph/layout.ts +0 -472
  147. package/src/graph/notes.ts +0 -21
  148. package/src/graph/state-collapse.ts +0 -78
  149. package/src/graph/state-parser.ts +0 -574
  150. package/src/graph/state-renderer.ts +0 -653
  151. package/src/graph/types.ts +0 -65
  152. package/src/index.ts +0 -261
  153. package/src/infra/compute.ts +0 -1385
  154. package/src/infra/layout.ts +0 -888
  155. package/src/infra/parser.ts +0 -1234
  156. package/src/infra/renderer.ts +0 -2534
  157. package/src/infra/roles.ts +0 -75
  158. package/src/infra/types.ts +0 -216
  159. package/src/infra/validation.ts +0 -201
  160. package/src/journey-map/layout.ts +0 -490
  161. package/src/journey-map/parser.ts +0 -557
  162. package/src/journey-map/renderer.ts +0 -1580
  163. package/src/journey-map/types.ts +0 -47
  164. package/src/kanban/mutations.ts +0 -175
  165. package/src/kanban/parser.ts +0 -509
  166. package/src/kanban/renderer.ts +0 -1449
  167. package/src/kanban/types.ts +0 -39
  168. package/src/label-layout.ts +0 -368
  169. package/src/map/colorize.ts +0 -54
  170. package/src/map/completion.ts +0 -316
  171. package/src/map/context-labels.ts +0 -609
  172. package/src/map/data/PROVENANCE.json +0 -1
  173. package/src/map/data/README.md +0 -40
  174. package/src/map/data/airport-collisions.json +0 -1
  175. package/src/map/data/airports.json +0 -1
  176. package/src/map/data/gazetteer.json +0 -1
  177. package/src/map/data/lakes.json +0 -1
  178. package/src/map/data/mountain-ranges.json +0 -1
  179. package/src/map/data/na-lakes.json +0 -1
  180. package/src/map/data/na-land.json +0 -1
  181. package/src/map/data/region-names.json +0 -1
  182. package/src/map/data/rivers.json +0 -1
  183. package/src/map/data/types.ts +0 -121
  184. package/src/map/data/us-states.json +0 -1
  185. package/src/map/data/water-bodies.json +0 -1
  186. package/src/map/data/world-coarse.json +0 -1
  187. package/src/map/data/world-detail.json +0 -1
  188. package/src/map/diagnostics.ts +0 -134
  189. package/src/map/dimensions.ts +0 -150
  190. package/src/map/geo-query.ts +0 -295
  191. package/src/map/geo.ts +0 -438
  192. package/src/map/invert.ts +0 -111
  193. package/src/map/layout.ts +0 -5069
  194. package/src/map/legend-band.ts +0 -127
  195. package/src/map/load-data.ts +0 -186
  196. package/src/map/parser.ts +0 -783
  197. package/src/map/renderer.ts +0 -1445
  198. package/src/map/resolved-types.ts +0 -160
  199. package/src/map/resolver.ts +0 -1146
  200. package/src/map/types.ts +0 -194
  201. package/src/mindmap/collapse.ts +0 -67
  202. package/src/mindmap/layout.ts +0 -649
  203. package/src/mindmap/parser.ts +0 -430
  204. package/src/mindmap/renderer.ts +0 -637
  205. package/src/mindmap/text-wrap.ts +0 -218
  206. package/src/mindmap/types.ts +0 -56
  207. package/src/org/collapse.ts +0 -151
  208. package/src/org/layout.ts +0 -1262
  209. package/src/org/parser.ts +0 -519
  210. package/src/org/renderer.ts +0 -866
  211. package/src/org/resolver.ts +0 -636
  212. package/src/palettes/atlas.ts +0 -77
  213. package/src/palettes/blueprint.ts +0 -73
  214. package/src/palettes/catppuccin.ts +0 -84
  215. package/src/palettes/color-utils.ts +0 -443
  216. package/src/palettes/index.ts +0 -67
  217. package/src/palettes/nord.ts +0 -67
  218. package/src/palettes/registry.ts +0 -114
  219. package/src/palettes/slate.ts +0 -73
  220. package/src/palettes/tidewater.ts +0 -73
  221. package/src/palettes/tokyo-night.ts +0 -86
  222. package/src/palettes/types.ts +0 -88
  223. package/src/pert/analyzer.ts +0 -1183
  224. package/src/pert/diagnostics.ts +0 -110
  225. package/src/pert/index.ts +0 -43
  226. package/src/pert/internal.ts +0 -252
  227. package/src/pert/layout.ts +0 -971
  228. package/src/pert/monte-carlo.ts +0 -446
  229. package/src/pert/parser.ts +0 -1606
  230. package/src/pert/renderer.ts +0 -4009
  231. package/src/pert/share-normalize.ts +0 -62
  232. package/src/pert/types.ts +0 -604
  233. package/src/pyramid/parser.ts +0 -185
  234. package/src/pyramid/renderer.ts +0 -768
  235. package/src/pyramid/types.ts +0 -28
  236. package/src/quadrant/parser.ts +0 -18
  237. package/src/quadrant/renderer.ts +0 -638
  238. package/src/raci/diagnostics.ts +0 -213
  239. package/src/raci/index.ts +0 -23
  240. package/src/raci/mutations.ts +0 -321
  241. package/src/raci/parser.ts +0 -699
  242. package/src/raci/renderer.ts +0 -1627
  243. package/src/raci/types.ts +0 -82
  244. package/src/raci/variants.ts +0 -320
  245. package/src/render.ts +0 -268
  246. package/src/ring/parser.ts +0 -212
  247. package/src/ring/renderer.ts +0 -490
  248. package/src/ring/types.ts +0 -27
  249. package/src/sequence/collapse.ts +0 -174
  250. package/src/sequence/parser.ts +0 -1596
  251. package/src/sequence/participant-inference.ts +0 -152
  252. package/src/sequence/renderer.ts +0 -3168
  253. package/src/sequence/tag-resolution.ts +0 -164
  254. package/src/sharing.ts +0 -211
  255. package/src/sitemap/collapse.ts +0 -100
  256. package/src/sitemap/layout.ts +0 -925
  257. package/src/sitemap/parser.ts +0 -755
  258. package/src/sitemap/renderer.ts +0 -828
  259. package/src/sitemap/types.ts +0 -42
  260. package/src/slope/parser.ts +0 -18
  261. package/src/slope/renderer.ts +0 -378
  262. package/src/swimlane/diagnostics.ts +0 -94
  263. package/src/swimlane/layout.ts +0 -597
  264. package/src/swimlane/parser.ts +0 -613
  265. package/src/swimlane/renderer.ts +0 -681
  266. package/src/swimlane/types.ts +0 -151
  267. package/src/tech-radar/interactive.ts +0 -1129
  268. package/src/tech-radar/layout.ts +0 -197
  269. package/src/tech-radar/parser.ts +0 -436
  270. package/src/tech-radar/renderer.ts +0 -1239
  271. package/src/tech-radar/shared.ts +0 -151
  272. package/src/tech-radar/types.ts +0 -86
  273. package/src/themes.ts +0 -22
  274. package/src/timeline/parser.ts +0 -472
  275. package/src/timeline/renderer.ts +0 -3024
  276. package/src/timeline/types.ts +0 -33
  277. package/src/timeline/viz-parser.ts +0 -21
  278. package/src/treemap/diagnostics.ts +0 -62
  279. package/src/treemap/layout-radial.ts +0 -233
  280. package/src/treemap/layout.ts +0 -189
  281. package/src/treemap/parser.ts +0 -463
  282. package/src/treemap/renderer-radial.ts +0 -438
  283. package/src/treemap/renderer.ts +0 -572
  284. package/src/treemap/treemap-shared.ts +0 -309
  285. package/src/treemap/types.ts +0 -60
  286. package/src/utils/arrow-markers.ts +0 -51
  287. package/src/utils/arrows-diagnostics.ts +0 -62
  288. package/src/utils/arrows.ts +0 -227
  289. package/src/utils/brand.ts +0 -61
  290. package/src/utils/card.ts +0 -183
  291. package/src/utils/collapse-engine/tree-edges.ts +0 -115
  292. package/src/utils/collapse-engine/tree.ts +0 -117
  293. package/src/utils/d3-helpers.ts +0 -219
  294. package/src/utils/d3-types.ts +0 -9
  295. package/src/utils/description-helpers.ts +0 -38
  296. package/src/utils/duration.ts +0 -312
  297. package/src/utils/export-container.ts +0 -41
  298. package/src/utils/expr-eval.ts +0 -27
  299. package/src/utils/fit-canvas.ts +0 -64
  300. package/src/utils/hover-styles.ts +0 -673
  301. package/src/utils/inline-markdown.ts +0 -96
  302. package/src/utils/legend-constants.ts +0 -48
  303. package/src/utils/legend-d3.ts +0 -618
  304. package/src/utils/legend-integration.ts +0 -107
  305. package/src/utils/legend-layout.ts +0 -776
  306. package/src/utils/legend-svg.ts +0 -214
  307. package/src/utils/legend-types.ts +0 -272
  308. package/src/utils/name-normalize.ts +0 -163
  309. package/src/utils/note-box/constants.ts +0 -25
  310. package/src/utils/note-box/index.ts +0 -11
  311. package/src/utils/note-box/metrics.ts +0 -90
  312. package/src/utils/note-box/svg.ts +0 -331
  313. package/src/utils/notes/bounds.ts +0 -30
  314. package/src/utils/notes/build.ts +0 -131
  315. package/src/utils/notes/index.ts +0 -18
  316. package/src/utils/notes/model.ts +0 -19
  317. package/src/utils/notes/parse.ts +0 -131
  318. package/src/utils/notes/place.ts +0 -177
  319. package/src/utils/notes/resolve.ts +0 -88
  320. package/src/utils/number-format.ts +0 -36
  321. package/src/utils/parsing.ts +0 -953
  322. package/src/utils/reserved-key-registry.ts +0 -239
  323. package/src/utils/safe-href.ts +0 -38
  324. package/src/utils/scaling.ts +0 -97
  325. package/src/utils/svg-embed.ts +0 -251
  326. package/src/utils/tag-groups.ts +0 -607
  327. package/src/utils/text-measure.ts +0 -122
  328. package/src/utils/time-ticks.ts +0 -253
  329. package/src/utils/title-constants.ts +0 -24
  330. package/src/utils/visual-conventions.ts +0 -61
  331. package/src/utils/wrapped-desc.ts +0 -87
  332. package/src/venn/parser.ts +0 -18
  333. package/src/venn/renderer.ts +0 -1047
  334. package/src/version-control/diagnostics.ts +0 -67
  335. package/src/version-control/parser.ts +0 -544
  336. package/src/version-control/renderer.ts +0 -724
  337. package/src/version-control/types.ts +0 -100
  338. package/src/visualizations/parse.ts +0 -1560
  339. package/src/visualizations/types.ts +0 -262
  340. package/src/wireframe/layout.ts +0 -479
  341. package/src/wireframe/parser.ts +0 -1114
  342. package/src/wireframe/renderer.ts +0 -1318
  343. package/src/wireframe/types.ts +0 -110
  344. package/src/wordcloud/parser.ts +0 -18
  345. package/src/wordcloud/renderer.ts +0 -357
@@ -1,122 +0,0 @@
1
- // ============================================================
2
- // Shared text measurement
3
- // ============================================================
4
- // One source of truth for "how wide is this string?" Before this
5
- // module, ~30 renderers/layouts each carried their own char-width
6
- // estimate (7.5px, 7px, 0.6·fontSize, 0.58, 0.55 …). The drift meant
7
- // the same label measured differently per chart type — a label could
8
- // fit inside an org node but overflow an infra node. All sizing,
9
- // wrapping, and truncation now route through the per-glyph table here.
10
-
11
- // Helvetica character width ratios (fraction of fontSize). Replaces the
12
- // naive `chars * 0.6 * fontSize` estimate with per-character widths.
13
- // prettier-ignore
14
- const CHAR_W: Record<string, number> = {
15
- ' ':.28,'!': .28,'"': .36,'#': .56,'$': .56,'%': .89,'&': .67,"'":.19,
16
- '(':.33,')':.33,'*': .39,'+':.58,',':.28,'-':.33,'.':.28,'/':.28,
17
- '0':.56,'1':.56,'2':.56,'3':.56,'4':.56,'5':.56,'6':.56,'7':.56,'8':.56,'9':.56,
18
- ':':.28,';':.28,'<':.58,'=':.58,'>':.58,'?':.56,'@':1.02,
19
- A:.67,B:.67,C:.72,D:.72,E:.67,F:.61,G:.78,H:.72,I:.28,J:.50,K:.67,L:.56,M:.83,
20
- N:.72,O:.78,P:.67,Q:.78,R:.72,S:.67,T:.61,U:.72,V:.67,W:.94,X:.67,Y:.67,Z:.61,
21
- a:.56,b:.56,c:.50,d:.56,e:.56,f:.28,g:.56,h:.56,i:.22,j:.22,k:.50,l:.22,m:.83,
22
- n:.56,o:.56,p:.56,q:.56,r:.33,s:.50,t:.28,u:.56,v:.50,w:.72,x:.50,y:.50,z:.50,
23
- };
24
- const DEFAULT_W = 0.56;
25
-
26
- /**
27
- * Average glyph-width ratio (fraction of fontSize). Only for the rare
28
- * call site that needs a single scalar (e.g. estimating a max char count
29
- * up front). Prefer {@link measureText} / {@link wrapTextToWidth} —
30
- * they account for actual glyph widths.
31
- */
32
- export const CHAR_WIDTH_RATIO = DEFAULT_W;
33
-
34
- /** Estimate rendered text width using Helvetica proportional character widths. */
35
- export function measureText(text: string, fontSize: number): number {
36
- let w = 0;
37
- for (let i = 0; i < text.length; i++) {
38
- // charAt returns '' for out-of-bounds, never undefined.
39
- w += (CHAR_W[text.charAt(i)] ?? DEFAULT_W) * fontSize;
40
- }
41
- return w;
42
- }
43
-
44
- /**
45
- * Truncate text with a trailing ellipsis to fit within maxWidth.
46
- * Returns the original text if it already fits, or '' if even the
47
- * ellipsis alone won't fit.
48
- */
49
- export function truncateText(
50
- text: string,
51
- fontSize: number,
52
- maxWidth: number
53
- ): string {
54
- if (measureText(text, fontSize) <= maxWidth) return text;
55
- const ellipsis = '…';
56
- const ellipsisW = measureText(ellipsis, fontSize);
57
- if (ellipsisW > maxWidth) return '';
58
- let lo = 0;
59
- let hi = text.length;
60
- while (lo < hi) {
61
- const mid = Math.ceil((lo + hi) / 2);
62
- if (measureText(text.slice(0, mid), fontSize) + ellipsisW <= maxWidth) {
63
- lo = mid;
64
- } else {
65
- hi = mid - 1;
66
- }
67
- }
68
- return lo === 0 ? ellipsis : text.slice(0, lo) + ellipsis;
69
- }
70
-
71
- /**
72
- * Greedy word-wrap to a pixel width using accurate glyph measurement.
73
- *
74
- * - Splits on whitespace; a word that alone exceeds `maxWidth` is kept
75
- * whole unless `hardBreak` is set, in which case it is broken at the
76
- * character boundary that fits.
77
- * - Returns at least one line (`['']` for empty input).
78
- */
79
- export function wrapTextToWidth(
80
- text: string,
81
- fontSize: number,
82
- maxWidth: number,
83
- opts?: { hardBreak?: boolean }
84
- ): string[] {
85
- const words = text.split(/\s+/).filter((w) => w.length > 0);
86
- if (words.length === 0) return [''];
87
- const hardBreak = opts?.hardBreak ?? false;
88
- const lines: string[] = [];
89
- let current = '';
90
- const pushWord = (word: string) => {
91
- const test = current ? `${current} ${word}` : word;
92
- if (measureText(test, fontSize) <= maxWidth || !current) {
93
- current = test;
94
- } else {
95
- lines.push(current);
96
- current = word;
97
- }
98
- };
99
- for (const word of words) {
100
- if (hardBreak && measureText(word, fontSize) > maxWidth) {
101
- // Break the over-long word into width-fitting chunks.
102
- if (current) {
103
- lines.push(current);
104
- current = '';
105
- }
106
- let chunk = '';
107
- for (const ch of word) {
108
- if (chunk && measureText(chunk + ch, fontSize) > maxWidth) {
109
- lines.push(chunk);
110
- chunk = ch;
111
- } else {
112
- chunk += ch;
113
- }
114
- }
115
- current = chunk;
116
- continue;
117
- }
118
- pushWord(word);
119
- }
120
- if (current) lines.push(current);
121
- return lines.length > 0 ? lines : [''];
122
- }
@@ -1,253 +0,0 @@
1
- // ============================================================
2
- // Time axis tick computation — shared by d3.ts and gantt/renderer.ts
3
- // ============================================================
4
-
5
- import type * as d3Scale from 'd3-scale';
6
-
7
- export const MONTH_ABBR = [
8
- 'Jan',
9
- 'Feb',
10
- 'Mar',
11
- 'Apr',
12
- 'May',
13
- 'Jun',
14
- 'Jul',
15
- 'Aug',
16
- 'Sep',
17
- 'Oct',
18
- 'Nov',
19
- 'Dec',
20
- ];
21
-
22
- function fractionalYearToDate(frac: number): Date {
23
- const year = Math.floor(frac);
24
- const remainder = frac - year;
25
- // Inverse of: (month-1)/12 + (day-1)/365 + hour/8760 + minute/525600 + second/31536000
26
- const monthFrac = remainder * 12;
27
- const month = Math.floor(monthFrac); // 0-based
28
- const monthRemainder = remainder - month / 12;
29
- const dayFrac = monthRemainder * 365; // fractional day-of-year offset
30
- const day = Math.floor(dayFrac) + 1;
31
- const dayRemainder = dayFrac - Math.floor(dayFrac);
32
- const hourFrac = dayRemainder * 24;
33
- const hour = Math.floor(hourFrac);
34
- const minuteFrac = (hourFrac - hour) * 60;
35
- const minute = Math.floor(minuteFrac);
36
- const second = Math.round((minuteFrac - minute) * 60);
37
- return new Date(year, month, day, hour, minute, second);
38
- }
39
-
40
- /** Convert a Date to a fractional year number. */
41
- function dateToFractionalYear(d: Date): number {
42
- return (
43
- d.getFullYear() +
44
- d.getMonth() / 12 +
45
- (d.getDate() - 1) / 365 +
46
- d.getHours() / 8760 +
47
- d.getMinutes() / 525600 +
48
- d.getSeconds() / 31536000
49
- );
50
- }
51
-
52
- /** Year axis label: negative years render as `N BCE`. */
53
- function formatYearTick(y: number): string {
54
- return y < 0 ? `${-y} BCE` : String(y);
55
- }
56
-
57
- /**
58
- * Generates adaptive tick marks along a time axis.
59
- * Picks the right granularity (years, months, weeks, days, hours, minutes)
60
- * based on the domain span.
61
- *
62
- * Optional boundary parameters add ticks at exact data start/end:
63
- * - boundaryStart/boundaryEnd: numeric date values
64
- * - boundaryStartLabel/boundaryEndLabel: formatted labels for those dates
65
- */
66
- export function computeTimeTicks(
67
- domainMin: number,
68
- domainMax: number,
69
- scale: d3Scale.ScaleLinear<number, number>,
70
- boundaryStart?: number,
71
- boundaryEnd?: number,
72
- boundaryStartLabel?: string,
73
- boundaryEndLabel?: string
74
- ): { pos: number; label: string }[] {
75
- const minYear = Math.floor(domainMin);
76
- const maxYear = Math.floor(domainMax);
77
- const span = domainMax - domainMin;
78
-
79
- let ticks: { pos: number; label: string }[] = [];
80
-
81
- // Year ticks for multi-year spans (need at least 2 boundaries)
82
- const firstYear = Math.ceil(domainMin);
83
- const lastYear = Math.floor(domainMax);
84
- if (lastYear >= firstYear + 1) {
85
- // Decimate ticks for long spans so labels don't overlap. The ladder runs
86
- // up to century/bicentury steps so millennium-scale spans (and BCE labels,
87
- // which are ~2× wider) stay legible.
88
- const yearSpan = lastYear - firstYear;
89
- let step = 1;
90
- if (yearSpan > 800) step = 200;
91
- else if (yearSpan > 400) step = 100;
92
- else if (yearSpan > 160) step = 50;
93
- else if (yearSpan > 80) step = 20;
94
- else if (yearSpan > 40) step = 10;
95
- else if (yearSpan > 20) step = 5;
96
- else if (yearSpan > 10) step = 2;
97
-
98
- // Align to step boundary so ticks land on round years (1700, 1710, …)
99
- const alignedFirst = Math.ceil(firstYear / step) * step;
100
- for (let y = alignedFirst; y <= lastYear; y += step) {
101
- ticks.push({ pos: scale(y), label: formatYearTick(y) });
102
- }
103
- } else if (span > 0.25) {
104
- // Month ticks for spans > ~3 months
105
- const crossesYear = maxYear > minYear;
106
- for (let y = minYear; y <= maxYear + 1; y++) {
107
- for (let m = 1; m <= 12; m++) {
108
- const val = y + (m - 1) / 12;
109
- if (val > domainMax) break;
110
- if (val >= domainMin) {
111
- // m is 1..12, so MONTH_ABBR[m-1] is always defined.
112
- const abbr = MONTH_ABBR[m - 1]!;
113
- ticks.push({
114
- pos: scale(val),
115
- label: crossesYear ? `${abbr} '${String(y).slice(-2)}` : abbr,
116
- });
117
- }
118
- }
119
- }
120
- } else if (span <= 0.0000114) {
121
- // Second ticks for spans ≤ ~6 minutes
122
- // Adaptive step: >3min → 30s, >1min → 15s, >30s → 10s, else 5s
123
- let stepSec = 5;
124
- const spanSec = span * 31536000;
125
- if (spanSec > 180) stepSec = 30;
126
- else if (spanSec > 60) stepSec = 15;
127
- else if (spanSec > 30) stepSec = 10;
128
-
129
- const startDate = fractionalYearToDate(domainMin);
130
- // Round down to nearest step boundary
131
- startDate.setSeconds(
132
- Math.floor(startDate.getSeconds() / stepSec) * stepSec,
133
- 0
134
- );
135
-
136
- while (true) {
137
- const val = dateToFractionalYear(startDate);
138
- if (val > domainMax) break;
139
- if (val >= domainMin) {
140
- const hh = String(startDate.getHours()).padStart(2, '0');
141
- const mm = String(startDate.getMinutes()).padStart(2, '0');
142
- const ss = String(startDate.getSeconds()).padStart(2, '0');
143
- ticks.push({ pos: scale(val), label: `${hh}:${mm}:${ss}` });
144
- }
145
- startDate.setSeconds(startDate.getSeconds() + stepSec);
146
- }
147
- } else if (span <= 0.000685) {
148
- // Minute ticks for spans ≤ ~6 hours
149
- // Adaptive step: >3h → 30min, >1h → 15min, >30min → 10min, else 5min
150
- let stepMin = 5;
151
- const spanHours = span * 8760;
152
- if (spanHours > 3) stepMin = 30;
153
- else if (spanHours > 1) stepMin = 15;
154
- else if (spanHours > 0.5) stepMin = 10;
155
-
156
- // Iterate from the start hour boundary
157
- const startDate = fractionalYearToDate(domainMin);
158
- // Round down to nearest step boundary
159
- startDate.setMinutes(
160
- Math.floor(startDate.getMinutes() / stepMin) * stepMin,
161
- 0,
162
- 0
163
- );
164
-
165
- while (true) {
166
- const val = dateToFractionalYear(startDate);
167
- if (val > domainMax) break;
168
- if (val >= domainMin) {
169
- const hh = String(startDate.getHours()).padStart(2, '0');
170
- const mm = String(startDate.getMinutes()).padStart(2, '0');
171
- ticks.push({ pos: scale(val), label: `${hh}:${mm}` });
172
- }
173
- startDate.setMinutes(startDate.getMinutes() + stepMin);
174
- }
175
- } else if (span <= 0.00822) {
176
- // Hour ticks for spans ≤ ~3 days
177
- // Adaptive step: >2d → 6h, >1d → 3h, >12h → 2h, else 1h
178
- let stepHour = 1;
179
- const spanHours = span * 8760;
180
- if (spanHours > 48) stepHour = 6;
181
- else if (spanHours > 24) stepHour = 3;
182
- else if (spanHours > 12) stepHour = 2;
183
-
184
- // For single-day spans, just show HH:MM without the date prefix
185
- const singleDay = spanHours <= 24;
186
-
187
- const startDate = fractionalYearToDate(domainMin);
188
- // Round down to nearest step boundary
189
- startDate.setHours(
190
- Math.floor(startDate.getHours() / stepHour) * stepHour,
191
- 0,
192
- 0,
193
- 0
194
- );
195
-
196
- while (true) {
197
- const val = dateToFractionalYear(startDate);
198
- if (val > domainMax) break;
199
- if (val >= domainMin) {
200
- const hh = String(startDate.getHours()).padStart(2, '0');
201
- const mm = String(startDate.getMinutes()).padStart(2, '0');
202
- if (singleDay) {
203
- ticks.push({ pos: scale(val), label: `${hh}:${mm}` });
204
- } else {
205
- const mon = MONTH_ABBR[startDate.getMonth()];
206
- const d = startDate.getDate();
207
- ticks.push({ pos: scale(val), label: `${mon} ${d} ${hh}:${mm}` });
208
- }
209
- }
210
- startDate.setHours(startDate.getHours() + stepHour);
211
- }
212
- } else {
213
- // Week ticks for spans ≤ ~3 months (1st, 8th, 15th, 22nd of each month)
214
- for (let y = minYear; y <= maxYear + 1; y++) {
215
- for (let m = 1; m <= 12; m++) {
216
- for (const d of [1, 8, 15, 22]) {
217
- const val = y + (m - 1) / 12 + (d - 1) / 365;
218
- if (val > domainMax) break;
219
- if (val >= domainMin) {
220
- ticks.push({
221
- pos: scale(val),
222
- label: `${MONTH_ABBR[m - 1]} ${d}`,
223
- });
224
- }
225
- }
226
- }
227
- }
228
- }
229
-
230
- // Add boundary ticks at exact data start/end if provided
231
- // When a boundary tick collides with a standard tick, replace the standard tick
232
- const collisionThreshold = 40; // pixels
233
-
234
- if (boundaryStart !== undefined && boundaryStartLabel) {
235
- const boundaryPos = scale(boundaryStart);
236
- // Remove any standard ticks that would collide with the start boundary
237
- ticks = ticks.filter(
238
- (t) => Math.abs(t.pos - boundaryPos) >= collisionThreshold
239
- );
240
- ticks.unshift({ pos: boundaryPos, label: boundaryStartLabel });
241
- }
242
-
243
- if (boundaryEnd !== undefined && boundaryEndLabel) {
244
- const boundaryPos = scale(boundaryEnd);
245
- // Remove any standard ticks that would collide with the end boundary
246
- ticks = ticks.filter(
247
- (t) => Math.abs(t.pos - boundaryPos) >= collisionThreshold
248
- );
249
- ticks.push({ pos: boundaryPos, label: boundaryEndLabel });
250
- }
251
-
252
- return ticks;
253
- }
@@ -1,24 +0,0 @@
1
- // ============================================================
2
- // Shared chart title constants
3
- // All renderers import from here to stay in sync.
4
- // ============================================================
5
-
6
- export const TITLE_FONT_SIZE = 20;
7
- export const TITLE_FONT_WEIGHT = '700';
8
- export const TITLE_Y = 30;
9
- export const TITLE_OFFSET = 40;
10
-
11
- // Caption — supplementary banner text. The pert renderer wraps caption
12
- // content in a node-styled rectangle below the diagram body; backward-
13
- // anchor annotations still render as a free-floating italic line below
14
- // the title. Pixel `dy` (not `'1.2em'`) so layout math and rendered text
15
- // never drift between JSDOM and resvg.
16
- export const CAPTION_FONT_SIZE = 13;
17
- export const CAPTION_FONT_WEIGHT = '400';
18
- export const CAPTION_LINE_HEIGHT = 18;
19
- export const CAPTION_TOP_GAP = 12;
20
- // Inner padding for the caption rectangle. X = horizontal inset from
21
- // rect edge to bullet glyph; Y = vertical inset from rect top to first
22
- // baseline.
23
- export const CAPTION_BOX_PADDING_X = 16;
24
- export const CAPTION_BOX_PADDING_Y = 12;
@@ -1,61 +0,0 @@
1
- // ============================================================
2
- // Visual conventions — shared card/group/collapse constants (Story 111.1)
3
- // ============================================================
4
- //
5
- // Single source of truth for the structured-diagram visual constants described
6
- // in docs/architecture/diagram-visual-conventions.md. Before this module these
7
- // values were re-declared in every renderer (NODE_STROKE_WIDTH in 13 files,
8
- // HEADER_HEIGHT in 12, ...), so a convention change meant editing N files and
9
- // hoping the snapshots agreed.
10
- //
11
- // Two tiers, because the renderers do NOT all agree:
12
- //
13
- // 1. UNIVERSAL — identical at every call site. Import these everywhere; never
14
- // re-declare. Changing one of these is a deliberate cross-chart change.
15
- //
16
- // 2. CONVENTION DEFAULTS — the org/sitemap baseline from the convention. Most
17
- // card-shaped renderers match these and should import them. A few have a
18
- // DOCUMENTED intentional deviation and keep a local override (with a
19
- // comment saying why):
20
- // - infra: META_FONT_SIZE 10 / META_LINE_HEIGHT 14 (denser meta rows)
21
- // - boxes-and-lines: COLLAPSE_BAR_HEIGHT 4 / SEPARATOR_GAP 4
22
- // - cycle, raci: HEADER_HEIGHT 36 (not label+meta cards)
23
- // Those overrides are the exception that proves the rule — they stay local
24
- // and visible, not hidden inside a re-declared full constant set.
25
-
26
- // ── Universal (same value at every site) ──
27
-
28
- /** Node card + group border stroke width. */
29
- export const NODE_STROKE_WIDTH = 1.5;
30
- /** Edge / connector stroke width. */
31
- export const EDGE_STROKE_WIDTH = 1.5;
32
- /** Node card corner radius. */
33
- export const CARD_RADIUS = 6;
34
- /** Group / container corner radius. */
35
- export const CONTAINER_RADIUS = 8;
36
- /** Collapse accent bar horizontal inset from the card edges. */
37
- export const COLLAPSE_BAR_INSET = 0;
38
-
39
- // ── Convention defaults (org/sitemap baseline; see deviations above) ──
40
-
41
- /** Node card header band height. */
42
- export const HEADER_HEIGHT = 28;
43
- /** Node card label font size. */
44
- export const LABEL_FONT_SIZE = 13;
45
- /** Node card metadata-row font size. */
46
- export const META_FONT_SIZE = 11;
47
- /** Node card metadata-row line height. */
48
- export const META_LINE_HEIGHT = 16;
49
- /** Gap between the header separator and the first metadata row. */
50
- export const SEPARATOR_GAP = 6;
51
- /** Collapse accent bar height. */
52
- export const COLLAPSE_BAR_HEIGHT = 6;
53
-
54
- /** Group / container reserved header band height. */
55
- export const CONTAINER_HEADER_HEIGHT = 28;
56
- /** Group / container label font size. */
57
- export const CONTAINER_LABEL_FONT_SIZE = 13;
58
- /** Group / container metadata-row font size. */
59
- export const CONTAINER_META_FONT_SIZE = 11;
60
- /** Group / container metadata-row line height. */
61
- export const CONTAINER_META_LINE_HEIGHT = 16;
@@ -1,87 +0,0 @@
1
- // ============================================================
2
- // Wrapped Description — shared bullet-aware text wrapping
3
- // ============================================================
4
-
5
- /**
6
- * One rendered description line. `kind` controls horizontal placement and
7
- * whether the renderer draws a bullet glyph:
8
- * - `plain` — flush left at the description's left edge
9
- * - `bullet-first` — "•" drawn at the left edge, body text at the bullet column
10
- * - `bullet-cont` — body continuation at the bullet column (no glyph)
11
- *
12
- * Splitting first-line bullet rendering into separate text elements lets
13
- * continuation lines align exactly under the first word past the bullet,
14
- * regardless of font-width estimation drift.
15
- */
16
- export interface WrappedDescLine {
17
- text: string;
18
- kind: 'plain' | 'bullet-first' | 'bullet-cont';
19
- }
20
-
21
- /** Bullet prefix that triggers split-rendering with a hanging body column. */
22
- export const BULLET_PREFIX = '• ';
23
- /** Equivalent body-column width in characters (subtracted from wrap width). */
24
- export const BULLET_INDENT_CHARS = 2;
25
-
26
- /**
27
- * Optional measurer — returns the *display* length of a string in characters.
28
- * Defaults to `s.length`. Pass a markdown-aware function (stripping link
29
- * targets, emphasis markers, etc.) when wrapping rich text so the wrap
30
- * boundary matches what the user will actually see.
31
- */
32
- export type LengthFn = (s: string) => number;
33
-
34
- /**
35
- * Word-wrap description lines. Bullet lines (starting with "• ") are split
36
- * so the renderer can place the "•" glyph at the description's left edge and
37
- * the body text at a fixed bullet-body column — continuation lines align
38
- * exactly under the first word past the bullet without depending on
39
- * font-width estimation.
40
- */
41
- export function wrapDescriptionLines(
42
- lines: string[],
43
- charsPerLine: number,
44
- lengthFn: LengthFn = (s) => s.length
45
- ): WrappedDescLine[] {
46
- const result: WrappedDescLine[] = [];
47
- for (const line of lines) {
48
- if (!line.startsWith(BULLET_PREFIX)) {
49
- const wrapped = wrapPlainLine(line, charsPerLine, lengthFn);
50
- for (const w of wrapped) result.push({ text: w, kind: 'plain' });
51
- continue;
52
- }
53
- // Strip "• " — the renderer draws the bullet glyph; we only wrap the body.
54
- const body = line.slice(BULLET_PREFIX.length);
55
- const bodyLimit = Math.max(8, charsPerLine - BULLET_INDENT_CHARS);
56
- const wrapped = wrapPlainLine(body, bodyLimit, lengthFn);
57
- wrapped.forEach((w, i) => {
58
- result.push({ text: w, kind: i === 0 ? 'bullet-first' : 'bullet-cont' });
59
- });
60
- }
61
- return result;
62
- }
63
-
64
- /**
65
- * Greedy word-wrap of a single string at the given character limit.
66
- * Long words are kept whole even if they exceed the limit (no mid-word break).
67
- */
68
- function wrapPlainLine(
69
- line: string,
70
- charsPerLine: number,
71
- lengthFn: LengthFn
72
- ): string[] {
73
- const words = line.split(/\s+/);
74
- const result: string[] = [];
75
- let current = '';
76
- for (const word of words) {
77
- const test = current ? `${current} ${word}` : word;
78
- if (lengthFn(test) > charsPerLine && current) {
79
- result.push(current);
80
- current = word;
81
- } else {
82
- current = test;
83
- }
84
- }
85
- if (current) result.push(current);
86
- return result;
87
- }
@@ -1,18 +0,0 @@
1
- // ============================================================
2
- // venn parser door — Story 109.2 (arch-review).
3
- //
4
- // The six visualizations share one parse state machine (visualizations/parse.ts);
5
- // this is venn's typed entry point into it, returning the narrowed
6
- // ParsedVenn shape. The registry binds the 'venn' chart type to this door.
7
- // ============================================================
8
-
9
- import type { PaletteColors } from '../palettes';
10
- import { parseVisualization } from '../visualizations/parse';
11
- import type { ParsedVenn } from '../visualizations/types';
12
-
13
- export function parseVenn(
14
- content: string,
15
- palette?: PaletteColors
16
- ): ParsedVenn {
17
- return parseVisualization(content, palette) as ParsedVenn;
18
- }