agentic-mermaid 0.1.1 → 0.2.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 (340) hide show
  1. package/AGENT_NATIVE.md +155 -91
  2. package/CHANGELOG.md +163 -4
  3. package/Instructions_for_agents.md +10 -10
  4. package/LICENSES/Apache-2.0.txt +202 -0
  5. package/README.md +31 -38
  6. package/THIRD_PARTY_NOTICES.md +29 -0
  7. package/assets/hero.png +0 -0
  8. package/dist/agent-core.d.ts +463 -0
  9. package/dist/agent-core.js +397 -0
  10. package/dist/agent.d.ts +73 -1868
  11. package/dist/agent.js +336 -37325
  12. package/dist/agentic-mermaid-mcp.js +7 -38399
  13. package/dist/am.js +33626 -40446
  14. package/dist/chunk-2P5FKUQC.js +3485 -0
  15. package/dist/chunk-2S3VSS6I.js +149 -0
  16. package/dist/chunk-2SILJDW2.js +37 -0
  17. package/dist/chunk-BJYMBT4I.js +61963 -0
  18. package/dist/chunk-FDM43XU7.js +615 -0
  19. package/dist/chunk-MYPDVZCO.js +4702 -0
  20. package/dist/index-DWPa2MJs.d.ts +6780 -0
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +310 -33014
  23. package/dist/mcp-cli-5J47WEY3.js +17 -0
  24. package/docs/README.md +39 -31
  25. package/docs/agent-api-cookbook.md +44 -35
  26. package/docs/agent-mutation-policy.md +1 -1
  27. package/docs/agent-workflow-examples.md +2 -2
  28. package/docs/api.md +284 -77
  29. package/docs/ascii.md +26 -16
  30. package/docs/code-mode-impact.md +214 -0
  31. package/docs/comparison.md +23 -11
  32. package/docs/computational-aesthetics-prototype-plan.md +252 -0
  33. package/docs/config.md +26 -10
  34. package/docs/custom-fonts.md +265 -0
  35. package/docs/custom-style-cookbook.md +130 -9
  36. package/docs/diagram-families.md +48 -23
  37. package/docs/features.md +59 -52
  38. package/docs/fork-differences.md +6 -3
  39. package/docs/getting-started.md +23 -16
  40. package/docs/issue-derived-test-cases.md +29 -22
  41. package/docs/mcp-code-mode-rationale.md +13 -6
  42. package/docs/mcp-http-transport.md +20 -13
  43. package/docs/mermaid-layout-complaints.md +66 -52
  44. package/docs/mutation-testing.md +145 -66
  45. package/docs/quality.md +23 -14
  46. package/docs/react.md +2 -2
  47. package/docs/schemas/style-spec.schema.json +1221 -30
  48. package/docs/style-authoring.md +241 -38
  49. package/docs/svg-semantic-contract.md +49 -0
  50. package/docs/testing-strategy.md +166 -58
  51. package/docs/theming.md +19 -32
  52. package/examples/styles/catalog.json +54 -0
  53. package/examples/styles/cloudflare-workers-inspired-prototype.mmd +9 -0
  54. package/examples/styles/cloudflare-workers-inspired-prototype.style.json +110 -0
  55. package/examples/styles/cupertino-prototype.mmd +10 -0
  56. package/examples/styles/cupertino-prototype.style.json +63 -0
  57. package/examples/styles/mid-century-report.style.json +2 -2
  58. package/examples/styles/star-chart-atlas.style.json +2 -1
  59. package/examples/styles/transit-route-map.style.json +2 -2
  60. package/examples/styles/vercel-inspired-prototype.mmd +6 -0
  61. package/examples/styles/vercel-inspired-prototype.style.json +87 -0
  62. package/package.json +85 -45
  63. package/server.json +2 -2
  64. package/skills/agentic-mermaid-diagram-workflow/SKILL.md +17 -36
  65. package/skills/agentic-mermaid-diagram-workflow/references/cli.md +4 -5
  66. package/skills/agentic-mermaid-diagram-workflow/references/code-mode.md +15 -31
  67. package/skills/agentic-mermaid-diagram-workflow/references/sequence.md +10 -14
  68. package/skills/agentic-mermaid-live-editor/SKILL.md +100 -206
  69. package/TODO.md +0 -684
  70. package/dist/index-wjRjbsP-.d.ts +0 -1102
  71. package/docs/assets/improvements/box-start-connector.png +0 -0
  72. package/docs/assets/improvements/comment-dropped-lint.png +0 -0
  73. package/docs/assets/improvements/er-content-loss.png +0 -0
  74. package/docs/assets/improvements/fan-in-trunks.png +0 -0
  75. package/docs/assets/improvements/gantt-family.png +0 -0
  76. package/docs/assets/improvements/gantt-milestone-clamp.png +0 -0
  77. package/docs/assets/improvements/gantt-verify-seam.png +0 -0
  78. package/docs/assets/improvements/subgraph-container-edges.png +0 -0
  79. package/docs/assets/improvements/wrapper-frontmatter.png +0 -0
  80. package/docs/assets/improvements/wrapper-init-directive.png +0 -0
  81. package/docs/assets/improvements/wrapper-leading-comment.png +0 -0
  82. package/docs/assets/style-cookbook/mid-century-report.png +0 -0
  83. package/docs/assets/style-cookbook/star-chart-atlas.png +0 -0
  84. package/docs/assets/style-cookbook/transit-route-map.png +0 -0
  85. package/docs/contributing/adding-diagram-types.md +0 -144
  86. package/docs/contributing/diagram-family-citizenship.matrix.json +0 -2127
  87. package/docs/contributing/diagram-family-citizenship.md +0 -82
  88. package/docs/contributing/harvesting-upstream-tests.md +0 -126
  89. package/docs/contributing/lessons-learned.md +0 -276
  90. package/docs/contributing/releasing.md +0 -82
  91. package/docs/contributing/visual-review-evidence.md +0 -53
  92. package/docs/design/families/README.md +0 -26
  93. package/docs/design/families/architecture-beta.md +0 -48
  94. package/docs/design/families/flowchart-parser-conformance.md +0 -22
  95. package/docs/design/families/gantt-research.md +0 -137
  96. package/docs/design/families/gantt.md +0 -329
  97. package/docs/design/families/journey-agentic-cards-before.png +0 -0
  98. package/docs/design/families/journey-experience-curve-implementation.png +0 -0
  99. package/docs/design/families/journey-mermaid-classic-implementation.png +0 -0
  100. package/docs/design/families/journey-mermaid-classic-prototype.png +0 -0
  101. package/docs/design/families/journey-mermaid-classic-prototype.svg +0 -163
  102. package/docs/design/families/journey-mermaid-classic-prototype.svg.png +0 -0
  103. package/docs/design/families/journey-migration-parity.md +0 -439
  104. package/docs/design/families/journey-section-overlap-after.png +0 -0
  105. package/docs/design/families/journey-section-overlap-before.png +0 -0
  106. package/docs/design/families/journey-usage-research.md +0 -423
  107. package/docs/design/families/journey.md +0 -153
  108. package/docs/design/families/xychart.md +0 -85
  109. package/docs/design/system/README.md +0 -45
  110. package/docs/design/system/abstraction-audit.md +0 -224
  111. package/docs/design/system/abstraction-recommendations.md +0 -655
  112. package/docs/design/system/architecture.mmd +0 -29
  113. package/docs/design/system/architecture.svg +0 -137
  114. package/docs/design/system/layout-guarantees-and-robustness.md +0 -351
  115. package/docs/design/system/layout-rubric.md +0 -138
  116. package/docs/design/system/route-contracts.md +0 -848
  117. package/docs/design/system/source-preservation-ladder.md +0 -52
  118. package/docs/design/system/styles-rollout.md +0 -216
  119. package/docs/design/system/ugly-layouts.md +0 -119
  120. package/docs/layout-characterization/README.md +0 -245
  121. package/docs/layout-characterization/contact-sheet-families.md +0 -498
  122. package/docs/layout-characterization/contact-sheet.md +0 -638
  123. package/docs/layout-characterization/properties.md +0 -281
  124. package/docs/layout-characterization/visual-quality.md +0 -160
  125. package/docs/layout-characterization/visual-snapshots/architecture.svg +0 -79
  126. package/docs/layout-characterization/visual-snapshots/class.svg +0 -60
  127. package/docs/layout-characterization/visual-snapshots/er.svg +0 -61
  128. package/docs/layout-characterization/visual-snapshots/flowchart.svg +0 -58
  129. package/docs/layout-characterization/visual-snapshots/gantt.svg +0 -52
  130. package/docs/layout-characterization/visual-snapshots/journey.svg +0 -98
  131. package/docs/layout-characterization/visual-snapshots/pie.svg +0 -36
  132. package/docs/layout-characterization/visual-snapshots/quadrant.svg +0 -47
  133. package/docs/layout-characterization/visual-snapshots/sequence.svg +0 -59
  134. package/docs/layout-characterization/visual-snapshots/state.svg +0 -52
  135. package/docs/layout-characterization/visual-snapshots/timeline.svg +0 -64
  136. package/docs/layout-characterization/visual-snapshots/xychart.svg +0 -97
  137. package/docs/project/divergences.md +0 -98
  138. package/docs/project/dogfooding-docs-strategy.md +0 -66
  139. package/docs/project/hosted-mcp-cloudflare-plan.md +0 -338
  140. package/docs/project/lessons-learned.md +0 -1019
  141. package/docs/project/remove-role-styling-plan.md +0 -176
  142. package/examples/agent-improve-auth-flow.ts +0 -206
  143. package/examples/agent-loop.ts +0 -53
  144. package/examples/mcp-vs-cli-complex-diagrams.ts +0 -133
  145. package/llms.txt +0 -104
  146. package/skill-evals/README.md +0 -77
  147. package/skill-evals/fixtures/architecture-cache/input.mmd +0 -5
  148. package/skill-evals/fixtures/class-payment/input.mmd +0 -4
  149. package/skill-evals/fixtures/er-orders/input.mmd +0 -10
  150. package/skill-evals/fixtures/flowchart-cache/input.mmd +0 -3
  151. package/skill-evals/fixtures/gantt-release/input.mmd +0 -7
  152. package/skill-evals/fixtures/journey-checkout/input.mmd +0 -6
  153. package/skill-evals/fixtures/pie-exports/input.mmd +0 -5
  154. package/skill-evals/fixtures/quadrant-priorities/input.mmd +0 -11
  155. package/skill-evals/fixtures/sequence-retry/input.mmd +0 -8
  156. package/skill-evals/fixtures/state-lifecycle/input.mmd +0 -5
  157. package/skill-evals/fixtures/timeline-release/input.mmd +0 -6
  158. package/skill-evals/fixtures/xychart-growth/input.mmd +0 -5
  159. package/skill-evals/shared-benchmark.json +0 -510
  160. package/src/agent/analyze.ts +0 -157
  161. package/src/agent/apply.ts +0 -146
  162. package/src/agent/architecture-body.ts +0 -458
  163. package/src/agent/certificates.ts +0 -110
  164. package/src/agent/class-body.ts +0 -319
  165. package/src/agent/core.ts +0 -207
  166. package/src/agent/create.ts +0 -106
  167. package/src/agent/describe.ts +0 -368
  168. package/src/agent/er-body.ts +0 -224
  169. package/src/agent/facts.ts +0 -360
  170. package/src/agent/families-builtin.ts +0 -920
  171. package/src/agent/families.ts +0 -232
  172. package/src/agent/family-layouts.ts +0 -832
  173. package/src/agent/flowchart-body.ts +0 -372
  174. package/src/agent/flowchart-unsupported.ts +0 -243
  175. package/src/agent/font-coverage.ts +0 -288
  176. package/src/agent/gantt-body.ts +0 -495
  177. package/src/agent/index.ts +0 -10
  178. package/src/agent/journey-body.ts +0 -374
  179. package/src/agent/label-metrics.ts +0 -28
  180. package/src/agent/layout-to-rendered.ts +0 -63
  181. package/src/agent/mutate.ts +0 -97
  182. package/src/agent/mutation-ops.ts +0 -51
  183. package/src/agent/op-schema.ts +0 -443
  184. package/src/agent/parse.ts +0 -223
  185. package/src/agent/pie-body.ts +0 -270
  186. package/src/agent/png.ts +0 -171
  187. package/src/agent/quadrant-body.ts +0 -336
  188. package/src/agent/quality.ts +0 -363
  189. package/src/agent/readability-audit.ts +0 -92
  190. package/src/agent/rendered-route-audit.ts +0 -61
  191. package/src/agent/sequence-body.ts +0 -345
  192. package/src/agent/serialize.ts +0 -214
  193. package/src/agent/state-body.ts +0 -589
  194. package/src/agent/structural-count.ts +0 -150
  195. package/src/agent/timeline-body.ts +0 -280
  196. package/src/agent/trace-log.ts +0 -43
  197. package/src/agent/types.ts +0 -995
  198. package/src/agent/verify.ts +0 -603
  199. package/src/agent/xychart-body.ts +0 -472
  200. package/src/architecture/config.ts +0 -282
  201. package/src/architecture/layout.ts +0 -496
  202. package/src/architecture/parser.ts +0 -375
  203. package/src/architecture/renderer.ts +0 -611
  204. package/src/architecture/types.ts +0 -113
  205. package/src/ascii/ansi.ts +0 -423
  206. package/src/ascii/architecture.ts +0 -210
  207. package/src/ascii/canvas.ts +0 -443
  208. package/src/ascii/class-diagram.ts +0 -697
  209. package/src/ascii/converter.ts +0 -475
  210. package/src/ascii/draw.ts +0 -1693
  211. package/src/ascii/edge-bundling.ts +0 -328
  212. package/src/ascii/edge-routing.ts +0 -330
  213. package/src/ascii/er-diagram.ts +0 -439
  214. package/src/ascii/gantt.ts +0 -276
  215. package/src/ascii/grid.ts +0 -747
  216. package/src/ascii/index.ts +0 -196
  217. package/src/ascii/journey.ts +0 -169
  218. package/src/ascii/meta.ts +0 -244
  219. package/src/ascii/multiline-utils.ts +0 -80
  220. package/src/ascii/pathfinder.ts +0 -301
  221. package/src/ascii/pie.ts +0 -67
  222. package/src/ascii/quadrant.ts +0 -158
  223. package/src/ascii/reverse.ts +0 -216
  224. package/src/ascii/sequence.ts +0 -499
  225. package/src/ascii/shapes/circle.ts +0 -27
  226. package/src/ascii/shapes/corners.ts +0 -143
  227. package/src/ascii/shapes/diamond.ts +0 -27
  228. package/src/ascii/shapes/hexagon.ts +0 -27
  229. package/src/ascii/shapes/index.ts +0 -106
  230. package/src/ascii/shapes/rectangle.ts +0 -168
  231. package/src/ascii/shapes/rounded.ts +0 -27
  232. package/src/ascii/shapes/special.ts +0 -332
  233. package/src/ascii/shapes/stadium.ts +0 -110
  234. package/src/ascii/shapes/state.ts +0 -192
  235. package/src/ascii/shapes/types.ts +0 -73
  236. package/src/ascii/timeline.ts +0 -141
  237. package/src/ascii/types.ts +0 -312
  238. package/src/ascii/validate.ts +0 -120
  239. package/src/ascii/width.ts +0 -81
  240. package/src/ascii/wrap.ts +0 -131
  241. package/src/ascii/xychart.ts +0 -919
  242. package/src/browser.ts +0 -29
  243. package/src/class/layout.ts +0 -240
  244. package/src/class/parser.ts +0 -332
  245. package/src/class/renderer.ts +0 -638
  246. package/src/class/types.ts +0 -129
  247. package/src/cli/agent-instructions.ts +0 -1
  248. package/src/cli/am-bin.ts +0 -6
  249. package/src/cli/exit-codes.ts +0 -18
  250. package/src/cli/index.ts +0 -1132
  251. package/src/cli/init-agent.ts +0 -147
  252. package/src/cli/run-entrypoint.ts +0 -10
  253. package/src/color-resolver.ts +0 -152
  254. package/src/elk-instance.ts +0 -114
  255. package/src/er/layout.ts +0 -187
  256. package/src/er/parser.ts +0 -226
  257. package/src/er/renderer.ts +0 -792
  258. package/src/er/types.ts +0 -99
  259. package/src/family-rubric.ts +0 -425
  260. package/src/font-manifest.ts +0 -31
  261. package/src/gantt/layout.ts +0 -365
  262. package/src/gantt/parser.ts +0 -282
  263. package/src/gantt/pipeline.ts +0 -27
  264. package/src/gantt/renderer.ts +0 -414
  265. package/src/gantt/schedule.ts +0 -513
  266. package/src/gantt/types.ts +0 -255
  267. package/src/index.ts +0 -368
  268. package/src/journey/layout.ts +0 -554
  269. package/src/journey/parse-core.ts +0 -251
  270. package/src/journey/parser.ts +0 -101
  271. package/src/journey/renderer.ts +0 -917
  272. package/src/journey/types.ts +0 -144
  273. package/src/layout/geometry.ts +0 -182
  274. package/src/layout/pass.ts +0 -142
  275. package/src/layout/passes/index.ts +0 -3916
  276. package/src/layout-engine.ts +0 -1565
  277. package/src/layout-rubric.ts +0 -659
  278. package/src/mcp/artifacts.ts +0 -137
  279. package/src/mcp/dynamic-harness.ts +0 -31
  280. package/src/mcp/dynamic-modules.d.ts +0 -7
  281. package/src/mcp/facade.ts +0 -608
  282. package/src/mcp/harness-runtime.ts +0 -203
  283. package/src/mcp/hosted-server.ts +0 -468
  284. package/src/mcp/mcp-bin.ts +0 -3
  285. package/src/mcp/mcp-cli.ts +0 -82
  286. package/src/mcp/protocol.ts +0 -13
  287. package/src/mcp/sandbox.ts +0 -195
  288. package/src/mcp/sdk-decl.ts +0 -391
  289. package/src/mcp/server.ts +0 -362
  290. package/src/mcp/tool-surface.ts +0 -146
  291. package/src/mermaid-source.ts +0 -655
  292. package/src/multiline-utils.ts +0 -228
  293. package/src/parser.ts +0 -1031
  294. package/src/pie/layout.ts +0 -168
  295. package/src/pie/parser.ts +0 -136
  296. package/src/pie/renderer.ts +0 -234
  297. package/src/pie/types.ts +0 -82
  298. package/src/quadrant/layout.ts +0 -191
  299. package/src/quadrant/parser.ts +0 -183
  300. package/src/quadrant/renderer.ts +0 -322
  301. package/src/quadrant/types.ts +0 -113
  302. package/src/render-family-hooks.ts +0 -244
  303. package/src/renderer.ts +0 -1099
  304. package/src/route-contracts.ts +0 -2723
  305. package/src/scene/backend.ts +0 -76
  306. package/src/scene/fidelity.ts +0 -183
  307. package/src/scene/hybrid-backend.ts +0 -174
  308. package/src/scene/ir.ts +0 -181
  309. package/src/scene/marks.ts +0 -127
  310. package/src/scene/rough-backend.ts +0 -378
  311. package/src/scene/seed.ts +0 -46
  312. package/src/scene/style-registry.ts +0 -556
  313. package/src/sequence/layout.ts +0 -456
  314. package/src/sequence/parser.ts +0 -255
  315. package/src/sequence/renderer.ts +0 -604
  316. package/src/sequence/types.ts +0 -154
  317. package/src/shape-clipping.ts +0 -351
  318. package/src/shared/accessibility-directives.ts +0 -22
  319. package/src/shared/batched.ts +0 -61
  320. package/src/shared/color-math.ts +0 -93
  321. package/src/shared/svg-a11y.ts +0 -29
  322. package/src/shared/syntax-error.ts +0 -17
  323. package/src/shared/unicode-ranges.ts +0 -135
  324. package/src/styles.ts +0 -318
  325. package/src/svg-paths.ts +0 -28
  326. package/src/text-metrics.ts +0 -248
  327. package/src/theme.ts +0 -710
  328. package/src/timeline/layout.ts +0 -381
  329. package/src/timeline/parser.ts +0 -215
  330. package/src/timeline/renderer.ts +0 -538
  331. package/src/timeline/types.ts +0 -105
  332. package/src/types.ts +0 -462
  333. package/src/website-worker-modules.d.ts +0 -18
  334. package/src/xychart/axis-utils.ts +0 -109
  335. package/src/xychart/colors.ts +0 -124
  336. package/src/xychart/config.ts +0 -88
  337. package/src/xychart/layout.ts +0 -656
  338. package/src/xychart/parser.ts +0 -504
  339. package/src/xychart/renderer.ts +0 -640
  340. package/src/xychart/types.ts +0 -282
@@ -1,29 +0,0 @@
1
- /**
2
- * Shared SVG accessibility root attributes.
3
- *
4
- * One implementation of the contract every family renderer that threads
5
- * accessibility itself must follow: `role="img"` on the root,
6
- * `aria-labelledby` referencing the `<title id>` and `aria-describedby`
7
- * referencing the `<desc id>`. Renderers that do not thread accessibility get
8
- * the same contract from the injectAccessibility post-pass in index.ts —
9
- * which detects these root attributes to know when to leave output alone.
10
- * (Conformance-gated across all families by svg-a11y-conformance.test.ts.)
11
- */
12
- export function buildAccessibilityAttrs(
13
- title: string | undefined,
14
- description: string | undefined,
15
- titleId: string,
16
- descId: string,
17
- roledescription?: string,
18
- ): Record<string, string> {
19
- const attrs: Record<string, string> = {}
20
- if (roledescription) {
21
- attrs['role'] = 'img'
22
- attrs['aria-roledescription'] = roledescription
23
- } else if (title || description) {
24
- attrs['role'] = 'img'
25
- }
26
- if (title) attrs['aria-labelledby'] = titleId
27
- if (description) attrs['aria-describedby'] = descId
28
- return attrs
29
- }
@@ -1,17 +0,0 @@
1
- // A prescriptive syntax error: say WHAT is wrong AND how to fix it — the
2
- // expected form plus a copyable example (and, when known, the valid identifiers
3
- // in scope) — so a caller, especially a smaller model driving the hosted MCP,
4
- // can correct from the message alone instead of trial-and-error. The render-path
5
- // parsers throw plain Errors that `verifyMermaid` flattens into the RENDER_FAILED
6
- // warning's `reason` string, so the prescriptive text rides straight through to
7
- // the agent. Message shape mirrors the architecture edge errors:
8
- // `<what> — expected <expectedForm>, e.g. <example>[ (known: a, b, c)]`
9
- export function syntaxError(detail: {
10
- what: string
11
- expectedForm: string
12
- example: string
13
- known?: readonly string[]
14
- }): Error {
15
- const known = detail.known && detail.known.length > 0 ? ` (known: ${detail.known.join(', ')})` : ''
16
- return new Error(`${detail.what} — expected ${detail.expectedForm}, e.g. ${detail.example}${known}`)
17
- }
@@ -1,135 +0,0 @@
1
- // ============================================================================
2
- // Shared Unicode range tables.
3
- //
4
- // Both the ASCII renderer (src/ascii/width.ts) and the SVG text-metrics
5
- // module (src/text-metrics.ts) need to know which codepoints are wide
6
- // (CJK), which are emoji, and which are zero-width (combining marks,
7
- // ZWJ, variation selectors). Cross-importing between ascii/ and core
8
- // would violate the substrate lint (ascii should not pull core; core
9
- // should not pull ascii). This neutral module is the shared substrate.
10
- //
11
- // Conventions:
12
- // - Ranges are inclusive [start, end] pairs of codepoints.
13
- // - Helpers operate on codepoint integers, not string chars, so callers
14
- // can iterate via `for ... of` (which yields codepoints, not UTF-16
15
- // code units) and pass the result of `String.prototype.codePointAt`.
16
- // ============================================================================
17
-
18
- export type CodepointRange = readonly [number, number]
19
-
20
- // ----------------------------------------------------------------------------
21
- // CJK + Hangul ranges — fullwidth in terminals and 2x width in proportional
22
- // fonts. Sourced from Unicode East Asian Width Wide/Fullwidth ranges plus
23
- // CJK Unified Ideographs and related supplements.
24
- // ----------------------------------------------------------------------------
25
- export const CJK_RANGES: readonly CodepointRange[] = [
26
- [0x2e80, 0x2eff], // CJK Radicals Supplement
27
- [0x2f00, 0x2fdf], // Kangxi Radicals
28
- [0x3000, 0x303f], // CJK Symbols and Punctuation
29
- [0x3040, 0x309f], // Hiragana
30
- [0x30a0, 0x30ff], // Katakana
31
- [0x3100, 0x312f], // Bopomofo
32
- [0x3190, 0x31ff], // Kanbun + extensions
33
- [0x3200, 0x33ff], // Enclosed CJK + Compatibility
34
- [0x3400, 0x4dbf], // CJK Extension A
35
- [0x4e00, 0x9fff], // CJK Unified Ideographs
36
- [0xf900, 0xfaff], // CJK Compatibility Ideographs
37
- [0x20000, 0x2ffff], // CJK Extension B and beyond
38
- ]
39
-
40
- // ----------------------------------------------------------------------------
41
- // Hangul ranges — Korean syllabic block. Separate from CJK_RANGES so callers
42
- // can distinguish Korean from Han characters when needed (e.g., font shaping).
43
- // ----------------------------------------------------------------------------
44
- export const HANGUL_RANGES: readonly CodepointRange[] = [
45
- [0x1100, 0x115f], // Hangul Jamo (leading)
46
- [0x3130, 0x318f], // Hangul Compatibility Jamo
47
- [0xac00, 0xd7af], // Hangul Syllables
48
- ]
49
-
50
- // ----------------------------------------------------------------------------
51
- // Fullwidth ASCII and symbol ranges — the U+FF00 block plus angle brackets
52
- // and a few other "halfwidth-and-fullwidth forms" that render as 2 cells.
53
- // ----------------------------------------------------------------------------
54
- export const FULLWIDTH_RANGES: readonly CodepointRange[] = [
55
- [0x2329, 0x232a], // Angle brackets
56
- [0xfe10, 0xfe19], // Vertical forms
57
- [0xfe30, 0xfe6f], // CJK Compatibility Forms + Small Form Variants
58
- [0xff00, 0xff60], // Fullwidth ASCII
59
- [0xffe0, 0xffe6], // Fullwidth symbols
60
- ]
61
-
62
- // ----------------------------------------------------------------------------
63
- // Emoji presentation ranges — the SMP planes where emoji live by default.
64
- // The Unicode regex `\p{Emoji_Presentation}|\p{Extended_Pictographic}` is a
65
- // more precise check for individual characters; these ranges are useful for
66
- // fast codepoint-integer checks and for callers that cannot afford a regex.
67
- // ----------------------------------------------------------------------------
68
- export const EMOJI_RANGES: readonly CodepointRange[] = [
69
- [0x1f300, 0x1faff], // Misc Symbols & Pictographs through Symbols & Pictographs Extended-A
70
- ]
71
-
72
- // ----------------------------------------------------------------------------
73
- // Combining-mark and zero-width ranges. Iterating codepoints and treating
74
- // these as width 0 keeps display-width math correct for accented Latin and
75
- // Devanagari/Arabic shaping marks.
76
- // ----------------------------------------------------------------------------
77
- export const COMBINING_RANGES: readonly CodepointRange[] = [
78
- [0x0300, 0x036f], // Combining Diacritical Marks
79
- [0x1ab0, 0x1aff], // Combining Diacritical Marks Extended
80
- [0x1dc0, 0x1dff], // Combining Diacritical Marks Supplement
81
- [0x20d0, 0x20ff], // Combining Diacritical Marks for Symbols
82
- [0xfe20, 0xfe2f], // Combining Half Marks
83
- ]
84
-
85
- // ----------------------------------------------------------------------------
86
- // Special zero-width codepoints. Separate from COMBINING_RANGES because they
87
- // have semantic meaning beyond "no advance":
88
- // - U+200B ZERO WIDTH SPACE
89
- // - U+200C ZERO WIDTH NON-JOINER
90
- // - U+200D ZERO WIDTH JOINER (binds emoji into sequences)
91
- // - U+FEFF ZERO WIDTH NO-BREAK SPACE / BOM
92
- // ----------------------------------------------------------------------------
93
- export const ZERO_WIDTH_CODEPOINTS: ReadonlySet<number> = new Set([
94
- 0x200b, 0x200c, 0x200d, 0xfeff,
95
- ])
96
-
97
- // ----------------------------------------------------------------------------
98
- // Variation selectors — modify the preceding base codepoint:
99
- // - U+FE0E Text-presentation selector (force width 1)
100
- // - U+FE0F Emoji-presentation selector (force width 2)
101
- // ----------------------------------------------------------------------------
102
- export const VS_TEXT = 0xfe0e
103
- export const VS_EMOJI = 0xfe0f
104
- export const ZWJ = 0x200d
105
-
106
- // ----------------------------------------------------------------------------
107
- // Range-membership helpers.
108
- // ----------------------------------------------------------------------------
109
-
110
- function inRanges(cp: number, ranges: readonly CodepointRange[]): boolean {
111
- for (const [lo, hi] of ranges) if (cp >= lo && cp <= hi) return true
112
- return false
113
- }
114
-
115
- /**
116
- * Is the codepoint wide (CJK / Hangul / Fullwidth / Emoji)?
117
- *
118
- * Note: emoji ZWJ sequences and variation selectors are NOT handled here —
119
- * the caller (visualWidth) must apply them on top of this base check.
120
- */
121
- export function isWideRange(cp: number): boolean {
122
- return (
123
- inRanges(cp, CJK_RANGES) ||
124
- inRanges(cp, HANGUL_RANGES) ||
125
- inRanges(cp, FULLWIDTH_RANGES) ||
126
- inRanges(cp, EMOJI_RANGES)
127
- )
128
- }
129
-
130
- /**
131
- * Is the codepoint zero-width (combining mark or a special ZWS/ZWJ/BOM)?
132
- */
133
- export function isZeroWidth(cp: number): boolean {
134
- return inRanges(cp, COMBINING_RANGES) || ZERO_WIDTH_CODEPOINTS.has(cp)
135
- }
package/src/styles.ts DELETED
@@ -1,318 +0,0 @@
1
- // ============================================================================
2
- // Font metrics — character width estimates for Inter at different sizes.
3
- // Used to approximate text bounding boxes without DOM measurement.
4
- // These are calibrated for Inter's typical glyph widths.
5
- //
6
- // NOTE: Theme/color system has moved to src/theme.ts. This file only
7
- // contains font metrics, spacing constants, and stroke widths.
8
- // ============================================================================
9
-
10
- import { measureTextWidth } from './text-metrics'
11
- import { styleFaceOf } from './scene/style-registry.ts'
12
- import type { InternalStyleFace, StyleInput } from './scene/style-registry.ts'
13
- import type { TextTransform } from './types.ts'
14
-
15
- /** Average character width in px at the given font size and weight (proportional font) */
16
- export function estimateTextWidth(text: string, fontSize: number, fontWeight: number): number {
17
- // Delegate to variable-width character measurement for better accuracy
18
- // with mixed character sets (Latin narrow/wide, CJK, emoji, etc.)
19
- return measureTextWidth(text, fontSize, fontWeight)
20
- }
21
-
22
- /** Average character width in px for monospace fonts (uniform glyph width) */
23
- export function estimateMonoTextWidth(text: string, fontSize: number): number {
24
- // Monospace fonts have uniform character width — 0.6 of fontSize matches actual
25
- // glyph widths for JetBrains Mono / SF Mono / Fira Code at small sizes (11px).
26
- // Previous value of 0.55 underestimated widths, causing class member labels to
27
- // extend beyond their box boundaries.
28
- return text.length * fontSize * 0.6
29
- }
30
-
31
- /** Monospace font family used for code-like text (class members, types) */
32
- export const MONO_FONT = "'JetBrains Mono'" as const
33
-
34
- /** Full CSS fallback chain for monospace text */
35
- export const MONO_FONT_STACK = `${MONO_FONT}, 'SF Mono', 'Fira Code', ui-monospace, monospace` as const
36
-
37
- /** Fixed font sizes used in the renderer (in px) */
38
- export const FONT_SIZES = {
39
- /** Node label text */
40
- nodeLabel: 13,
41
- /** Edge label text */
42
- edgeLabel: 11,
43
- /** Subgraph header text */
44
- groupHeader: 12,
45
- } as const
46
-
47
- /** Font weights used per element type */
48
- export const FONT_WEIGHTS = {
49
- nodeLabel: 500,
50
- edgeLabel: 400,
51
- groupHeader: 600,
52
- } as const
53
-
54
- // ============================================================================
55
- // Spacing & sizing constants
56
- // ============================================================================
57
-
58
- /** Vertical gap between a subgraph header band and the content area below it (px).
59
- * Without this, nested subgraph headers sit flush against their parent's header band.
60
- * Increased from 8 to 12 to provide more clearance for edges routing near headers. */
61
- export const GROUP_HEADER_CONTENT_PAD = 12
62
-
63
- /** Padding inside node shapes */
64
- export const NODE_PADDING = {
65
- /** Horizontal padding inside rectangles/rounded/stadium (increased from 16 for better label fit) */
66
- horizontal: 20,
67
- /** Vertical padding inside rectangles/rounded/stadium */
68
- vertical: 10,
69
- /** Extra padding for diamond shapes (they need more space due to rotation) */
70
- diamondExtra: 24,
71
- } as const
72
-
73
- /** Stroke widths per element type (in px) */
74
- export const STROKE_WIDTHS = {
75
- outerBox: 1,
76
- innerBox: 0.75,
77
- /** Edge connector stroke (increased from 0.75 for better visibility) */
78
- connector: 1,
79
- } as const
80
-
81
- /**
82
- * Vertical shift applied to all text elements for font-agnostic centering.
83
- *
84
- * Instead of relying on `dominant-baseline="central"` (which each font interprets
85
- * differently based on its own ascent/descent metrics), we use the default alphabetic
86
- * baseline and shift down by 0.35em. This places the optical center of text at the
87
- * y coordinate, regardless of font family (Inter, JetBrains Mono, system fallbacks).
88
- *
89
- * The 0.35em value approximates the distance from alphabetic baseline to visual
90
- * center of Latin text. Using `em` units ensures it scales with font size.
91
- */
92
- export const TEXT_BASELINE_SHIFT = '0.35em' as const
93
-
94
- /** Arrow head dimensions — matches spec: 8px wide × ~5px tall */
95
- export const ARROW_HEAD = {
96
- width: 8,
97
- height: 5,
98
- } as const
99
-
100
- /** Flowchart dotted-edge stroke pattern; renderer emits stroke-dasharray="4 4". */
101
- export const FLOWCHART_DOTTED_DASH = {
102
- dash: 4,
103
- gap: 4,
104
- } as const
105
-
106
- // ============================================================================
107
- // Render style option resolution
108
- // ============================================================================
109
-
110
- export interface RenderStyleOptions {
111
- /** A style input (name | spec | stack); built-in style faces are read here. */
112
- style?: StyleInput | StyleInput[]
113
- /** @internal Projected families can pass precomputed face metrics without exposing them as public style JSON. */
114
- styleFace?: InternalStyleFace
115
- }
116
-
117
- export interface RenderStyleDefaults {
118
- nodeLabelFontSize: number
119
- edgeLabelFontSize: number
120
- groupHeaderFontSize: number
121
- nodeLabelFontWeight: number
122
- edgeLabelFontWeight: number
123
- groupHeaderFontWeight: number
124
- nodeTextTransform?: TextTransform
125
- edgeTextTransform?: TextTransform
126
- nodeLetterSpacing?: number
127
- edgeLetterSpacing?: number
128
- groupLetterSpacing?: number
129
- nodePaddingX: number
130
- nodePaddingY: number
131
- diamondExtraPadding?: number
132
- nodeCornerRadius?: number
133
- nodeLineWidth?: number
134
- nodeFillColor?: string
135
- nodeBorderColor?: string
136
- nodeTextColor?: string
137
- edgeLineWidth: number
138
- edgeBendRadius?: number
139
- edgeStrokeColor?: string
140
- edgeTextColor?: string
141
- groupFont?: string
142
- groupTextTransform?: TextTransform
143
- groupCornerRadius: number
144
- groupBorderColor?: string
145
- groupFillColor?: string
146
- groupHeaderFillColor?: string
147
- groupTextColor?: string
148
- groupPaddingX: number
149
- groupPaddingY: number
150
- groupLabelPaddingX?: number
151
- groupLineWidth?: number
152
- }
153
-
154
- export interface ResolvedRenderStyle {
155
- nodeLabelFontSize: number
156
- edgeLabelFontSize: number
157
- groupHeaderFontSize: number
158
- nodeLabelFontWeight: number
159
- edgeLabelFontWeight: number
160
- groupHeaderFontWeight: number
161
- nodeTextTransform?: TextTransform
162
- edgeTextTransform?: TextTransform
163
- nodeLetterSpacing: number
164
- edgeLetterSpacing: number
165
- groupLetterSpacing: number
166
- nodePaddingX: number
167
- nodePaddingY: number
168
- diamondExtraPadding: number
169
- cornerRadius?: number
170
- nodeLineWidth: number
171
- nodeFillColor?: string
172
- nodeBorderColor?: string
173
- nodeTextColor?: string
174
- lineWidth: number
175
- edgeBendRadius: number
176
- edgeStrokeColor?: string
177
- edgeTextColor?: string
178
- groupFont?: string
179
- groupTextTransform?: TextTransform
180
- groupCornerRadius: number
181
- groupBorderColor?: string
182
- groupFillColor?: string
183
- groupHeaderFillColor?: string
184
- groupTextColor?: string
185
- groupPaddingX: number
186
- groupPaddingY: number
187
- groupLabelPaddingX: number
188
- groupLineWidth: number
189
- }
190
-
191
- export const FLOWCHART_STYLE_DEFAULTS: RenderStyleDefaults = {
192
- nodeLabelFontSize: FONT_SIZES.nodeLabel,
193
- edgeLabelFontSize: FONT_SIZES.edgeLabel,
194
- groupHeaderFontSize: FONT_SIZES.groupHeader,
195
- nodeLabelFontWeight: FONT_WEIGHTS.nodeLabel,
196
- edgeLabelFontWeight: FONT_WEIGHTS.edgeLabel,
197
- groupHeaderFontWeight: FONT_WEIGHTS.groupHeader,
198
- nodePaddingX: NODE_PADDING.horizontal,
199
- nodePaddingY: NODE_PADDING.vertical,
200
- diamondExtraPadding: NODE_PADDING.diamondExtra,
201
- edgeLineWidth: STROKE_WIDTHS.connector,
202
- groupCornerRadius: 0,
203
- groupPaddingX: 16,
204
- groupPaddingY: 16,
205
- groupLabelPaddingX: 12,
206
- groupLineWidth: STROKE_WIDTHS.outerBox,
207
- }
208
-
209
- function finiteNumber(value: number | undefined): number | undefined {
210
- return typeof value === 'number' && Number.isFinite(value) ? value : undefined
211
- }
212
-
213
- function positiveNumber(fallback: number, ...values: Array<number | undefined>): number {
214
- for (const value of values) {
215
- const finite = finiteNumber(value)
216
- if (finite != null && finite > 0) return finite
217
- }
218
- return fallback
219
- }
220
-
221
- function nonNegativeNumber(fallback: number, ...values: Array<number | undefined>): number
222
- function nonNegativeNumber(fallback: undefined, ...values: Array<number | undefined>): number | undefined
223
- function nonNegativeNumber(fallback: number | undefined, ...values: Array<number | undefined>): number | undefined {
224
- for (const value of values) {
225
- const finite = finiteNumber(value)
226
- if (finite != null && finite >= 0) return finite
227
- }
228
- return fallback
229
- }
230
-
231
- function finiteString(...values: Array<string | undefined>): string | undefined {
232
- for (const value of values) {
233
- if (typeof value === 'string' && value.trim().length > 0) return value
234
- }
235
- return undefined
236
- }
237
-
238
- function textTransform(...values: Array<string | undefined>): TextTransform | undefined {
239
- for (const value of values) {
240
- const normalized = finiteString(value)?.toLowerCase()
241
- if (normalized === 'uppercase' || normalized === 'lowercase' || normalized === 'capitalize') {
242
- return normalized
243
- }
244
- }
245
- return undefined
246
- }
247
-
248
- const INLINE_FORMAT_TAG = /(<\/?(?:b|strong|i|em|u|s|del)\s*>)/gi
249
-
250
- export function applyTextTransform(text: string, transform: TextTransform | undefined): string {
251
- if (!transform) return text
252
- const transformPlain = (chunk: string): string => {
253
- switch (transform) {
254
- case 'uppercase':
255
- return chunk.toUpperCase()
256
- case 'lowercase':
257
- return chunk.toLowerCase()
258
- case 'capitalize':
259
- return chunk.replace(/\b\p{L}/gu, ch => ch.toUpperCase())
260
- }
261
- }
262
- return text
263
- .split(INLINE_FORMAT_TAG)
264
- .map(part => /^<\/?(?:b|strong|i|em|u|s|del)\s*>$/i.test(part) ? part : transformPlain(part))
265
- .join('')
266
- }
267
-
268
- export function resolveRenderStyle(
269
- options: RenderStyleOptions = {},
270
- defaults: RenderStyleDefaults = FLOWCHART_STYLE_DEFAULTS,
271
- ): ResolvedRenderStyle {
272
- const face = options.styleFace ?? styleFaceOf(options.style)
273
- const text = face?.text
274
- const node = face?.node
275
- const edge = face?.edge
276
- const group = face?.group
277
- const explicitGroupPaddingX = nonNegativeNumber(undefined, group?.paddingX)
278
- const cornerRadius = defaults.nodeCornerRadius == null
279
- ? nonNegativeNumber(undefined, node?.cornerRadius)
280
- : nonNegativeNumber(defaults.nodeCornerRadius, node?.cornerRadius)
281
-
282
- return {
283
- nodeLabelFontSize: positiveNumber(defaults.nodeLabelFontSize, node?.fontSize, text?.fontSize),
284
- edgeLabelFontSize: positiveNumber(defaults.edgeLabelFontSize, edge?.fontSize, text?.fontSize),
285
- groupHeaderFontSize: positiveNumber(defaults.groupHeaderFontSize, group?.fontSize, text?.fontSize),
286
- nodeLabelFontWeight: positiveNumber(defaults.nodeLabelFontWeight, node?.fontWeight, text?.fontWeight),
287
- edgeLabelFontWeight: positiveNumber(defaults.edgeLabelFontWeight, edge?.fontWeight, text?.fontWeight),
288
- groupHeaderFontWeight: positiveNumber(defaults.groupHeaderFontWeight, group?.fontWeight, text?.fontWeight),
289
- nodeTextTransform: textTransform(node?.textTransform, text?.textTransform, defaults.nodeTextTransform),
290
- edgeTextTransform: textTransform(edge?.textTransform, text?.textTransform, defaults.edgeTextTransform),
291
- nodeLetterSpacing: finiteNumber(node?.letterSpacing) ?? finiteNumber(text?.letterSpacing) ?? defaults.nodeLetterSpacing ?? 0,
292
- edgeLetterSpacing: finiteNumber(edge?.letterSpacing) ?? finiteNumber(text?.letterSpacing) ?? defaults.edgeLetterSpacing ?? 0,
293
- groupLetterSpacing: finiteNumber(group?.letterSpacing) ?? finiteNumber(text?.letterSpacing) ?? defaults.groupLetterSpacing ?? 0,
294
- nodePaddingX: nonNegativeNumber(defaults.nodePaddingX, node?.paddingX),
295
- nodePaddingY: nonNegativeNumber(defaults.nodePaddingY, node?.paddingY),
296
- diamondExtraPadding: defaults.diamondExtraPadding ?? NODE_PADDING.diamondExtra,
297
- cornerRadius,
298
- nodeLineWidth: positiveNumber(defaults.nodeLineWidth ?? STROKE_WIDTHS.innerBox, node?.lineWidth),
299
- nodeFillColor: finiteString(node?.fillColor, defaults.nodeFillColor),
300
- nodeBorderColor: finiteString(node?.borderColor, defaults.nodeBorderColor),
301
- nodeTextColor: finiteString(node?.textColor, text?.textColor, defaults.nodeTextColor),
302
- lineWidth: positiveNumber(defaults.edgeLineWidth, edge?.lineWidth),
303
- edgeBendRadius: nonNegativeNumber(defaults.edgeBendRadius ?? 0, edge?.bendRadius),
304
- edgeStrokeColor: finiteString(edge?.strokeColor, defaults.edgeStrokeColor),
305
- edgeTextColor: finiteString(edge?.textColor, text?.textColor, defaults.edgeTextColor),
306
- groupFont: finiteString(group?.fontFamily, defaults.groupFont),
307
- groupTextTransform: textTransform(group?.textTransform, text?.textTransform, defaults.groupTextTransform),
308
- groupCornerRadius: nonNegativeNumber(defaults.groupCornerRadius, group?.cornerRadius),
309
- groupBorderColor: finiteString(group?.borderColor, defaults.groupBorderColor),
310
- groupFillColor: finiteString(group?.fillColor, defaults.groupFillColor),
311
- groupHeaderFillColor: finiteString(group?.headerFillColor, defaults.groupHeaderFillColor),
312
- groupTextColor: finiteString(group?.textColor, text?.textColor, defaults.groupTextColor),
313
- groupPaddingX: explicitGroupPaddingX ?? defaults.groupPaddingX,
314
- groupPaddingY: nonNegativeNumber(defaults.groupPaddingY, group?.paddingY),
315
- groupLabelPaddingX: explicitGroupPaddingX ?? defaults.groupLabelPaddingX ?? defaults.groupPaddingX,
316
- groupLineWidth: positiveNumber(defaults.groupLineWidth ?? STROKE_WIDTHS.outerBox, group?.lineWidth),
317
- }
318
- }
package/src/svg-paths.ts DELETED
@@ -1,28 +0,0 @@
1
- // ============================================================================
2
- // SVG path helpers for partial fills inside rounded boxes.
3
- //
4
- // Use this instead of rounded <rect> elements for header bands: a full rounded
5
- // rect gives partial-height fills their own rounded bottom corners, which creates
6
- // visual seams and pill/crescent artifacts.
7
- // ============================================================================
8
-
9
- export function topRoundedRectPath(x: number, y: number, width: number, height: number, radius: number): string {
10
- const r = clampRadius(radius, width / 2, height)
11
- if (r === 0) return `M${x},${y} H${x + width} V${y + height} H${x} Z`
12
-
13
- return [
14
- `M${x + r},${y}`,
15
- `H${x + width - r}`,
16
- `A${r},${r} 0 0 1 ${x + width},${y + r}`,
17
- `V${y + height}`,
18
- `H${x}`,
19
- `V${y + r}`,
20
- `A${r},${r} 0 0 1 ${x + r},${y}`,
21
- 'Z',
22
- ].join(' ')
23
- }
24
-
25
-
26
- function clampRadius(radius: number, maxX: number, maxY: number): number {
27
- return Math.max(0, Math.min(radius, maxX, maxY))
28
- }