MoonshotAI / MoonshotAI/kimi-code

web: Long mermaid labels overflow their node boxes and overlap

Open
#2,577 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
7.5k
Forks
1.2k
Avg merge
11h 53m
Merged PRs (30d)
350

Description

Problem

In the web UI, mermaid diagrams with long labels (very common with CJK text, ~12+ Chinese characters) render with the label text overflowing its node box on both sides, and adjacent nodes' labels overlap each other:

The node rect is sized for the wrapped label, but the text renders as one long single line centered on the node.

Root cause

  1. mermaid (11.15, securityLevel: loose → htmlLabels on) wraps long labels via CSS soft wrap inside a <foreignObject> (max-width: 200px, no <br> in the DOM) and sizes the node rect from the wrapped measurement (~200px + padding).
  2. Before inserting the SVG, markstream-vue runs it through stream-markdown-parser's toSafeSvgElement, whose replaceForeignObjectLabels replaces every <foreignObject> with a single-line SVG <text> — it only splits lines on literal <br>, so the CSS soft-wrap structure is lost.
  3. The full-width single-line text is then rendered centered (text-anchor="middle") on a rect sized for 200px → symmetric overflow on both sides; dagre laid the nodes out for the small measured width, so neighbors' labels overlap.

Measured with the same dependency versions (mermaid 11.15.0 + stream-markdown-parser 1.1.7): a 35-char CJK label yields a 260px node rect but 576px of rendered text (~158px overflow per side).

Notes

  • App-side CSS is not the cause: after sanitization there is no foreignObject left in the DOM for any selector to reach, and mermaid injects its own font styles into the SVG before measuring.
  • A fix PR is on the way: it injects %%{init: {"htmlLabels": false}}%% into mermaid fences so mermaid lays out native SVG text with real width-based line breaking, leaving the sanitizer nothing to flatten. (flowchart.htmlLabels is deprecated and silently shadowed by the global default in mermaid 11.15 — only the global key actually takes effect.)

Environment

  • kimi-web (web UI) with markstream-vue 1.0.9-beta.1, stream-markdown-parser 1.1.7, mermaid 11.15.0
  • Reproduces in Chrome; mechanism is platform-independent.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the issue in the web UI with mermaid 11.15.0 and a long CJK label, then trace the mermaid fence through markstream-vue and stream-markdown-parser 1.1.7, especially foreignObject label sanitization. Done means long labels wrap within their node boxes and adjacent node labels no longer overlap, with the behavior verified in Chrome.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend, web-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.