Skip to content

Fix 5706 Block Positioning when nesting and blocks span columns - #6119

Merged
knsv merged 11 commits into
mermaid-js:developfrom
NealGooch:bug/5706_block_positioning_issues_when_nesting
Mar 1, 2026
Merged

knsv merged 11 commits into
mermaid-js:developfrom
NealGooch:bug/5706_block_positioning_issues_when_nesting

Conversation

@NealGooch

@NealGooch NealGooch commented Dec 8, 2024 •

Copy link
Copy Markdown
Contributor

📑 Summary

Block diagrams positioning goes wrong when nesting blocks and blocks span columns

Resolves #5706

📏 Design Decisions

Fix

📋 Tasks

Make sure you

  • 📖 have read the contribution guidelines
  • 💻 have added necessary unit/e2e tests.
  • 📓 have added documentation. Make sure MERMAID_RELEASE_VERSION is used for all new features.
  • 🦋 If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

@changeset-bot

changeset-bot Bot commented Dec 8, 2024 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8eb324e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
mermaid Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions github-actions Bot added the Type: Bug / Error Something isn't working or is incorrect label Dec 8, 2024
@netlify

netlify Bot commented Dec 8, 2024 •

Copy link
Copy Markdown

✅ Deploy Preview for mermaid-js ready!

Name Link
🔨 Latest commit 8778cc8
🔍 Latest deploy log https://app.netlify.com/sites/mermaid-js/deploys/67e1b5e7ae4600000830efd9
😎 Deploy Preview https://deploy-preview-6119--mermaid-js.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@pkg-pr-new

pkg-pr-new Bot commented Dec 8, 2024 •

Copy link
Copy Markdown

Open in StackBlitz

@mermaid-js/examples

npm i https://pkg.pr.new/@mermaid-js/examples@6119

mermaid

npm i https://pkg.pr.new/mermaid@6119

@mermaid-js/layout-elk

npm i https://pkg.pr.new/@mermaid-js/layout-elk@6119

@mermaid-js/layout-tidy-tree

npm i https://pkg.pr.new/@mermaid-js/layout-tidy-tree@6119

@mermaid-js/mermaid-zenuml

npm i https://pkg.pr.new/@mermaid-js/mermaid-zenuml@6119

@mermaid-js/parser

npm i https://pkg.pr.new/@mermaid-js/parser@6119

@mermaid-js/tiny

npm i https://pkg.pr.new/@mermaid-js/tiny@6119

commit: 0cbbda7

@codecov

codecov Bot commented Dec 8, 2024 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 32 lines in your changes missing coverage. Please review.
✅ Project coverage is 3.55%. Comparing base (4306d6d) to head (8eb324e).
⚠️ Report is 12 commits behind head on develop.

Files with missing lines Patch % Lines
packages/mermaid/src/diagrams/block/layout.ts 0.00% 32 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           develop   #6119      +/-   ##
==========================================
- Coverage     3.55%   3.55%   -0.01%     
==========================================
  Files          489     489              
  Lines        48744   48774      +30     
  Branches       765     765              
==========================================
  Hits          1734    1734              
- Misses       47010   47040      +30     
Flag Coverage Δ
unit 3.55% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/mermaid/src/diagrams/block/layout.ts 0.34% <0.00%> (-0.05%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@argos-ci

argos-ci Bot commented Dec 8, 2024 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Argos notifications ↗︎

Build Status Details Updated (UTC)
default (Inspect) 👍 Changes approved 4 changed, 2 added Mar 1, 2026, 2:27 PM

@netlify

netlify Bot commented May 8, 2025 •

Copy link
Copy Markdown

✅ Deploy Preview for mermaid-js ready!

Name Link
🔨 Latest commit 8eb324e
🔍 Latest deploy log https://app.netlify.com/projects/mermaid-js/deploys/69a44ab5b8b51f00087a51c0
😎 Deploy Preview https://deploy-preview-6119--mermaid-js.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@knsv knsv left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @NealGooch — first of all, sorry for the long wait on this review. This PR has been sitting for over a year and that's not the experience we want for contributors. Let's get this across the finish line.

What's working well

🎉 [praise] Great bug catch! The fix is surgically precise — block.widthInColumns → child.widthInColumns on line 64 of layout.ts is clearly correct. When normalizing a child's rendered width to find the per-column unit width, you need to divide by that child's column span, not the parent's. Using the parent's span was causing completely wrong size calculations for nested blocks with multi-column children, which explains the overlapping and mispositioned elements in issue #5706.

🎉 [praise] One-line fix, right at the root cause. This is the kind of change that's easy to get right and hard to argue with.

Things to address

🟡 [important] Missing E2E visual regression test. Block diagram layout changes must have a Cypress snapshot test to prevent future regressions. Please add a test case in cypress/integration/rendering/block.spec.js (or similar) using imgSnapshotTest() with the reproduction case from issue #5706:

block-beta
    columns 4

    block:0_0:4
        columns 6
            Example:2
        space:2
        ExampleOther:2
        ExampleOther:1
        block:0_0_0:6
            a b c d e f g h
        end
    end

This is especially important because this is shared layout code — a future refactor could easily re-introduce the same bug without visual coverage.

🟡 [important] Missing unit test. It would be great to add a unit test for getMaxChildSize() that covers multi-column children. The existing test file (layout.spec.ts) only tests calculateBlockPosition. A test that constructs a mock Block with children having different widthInColumns values and verifies the returned max width would nail this down. This provides faster feedback than E2E alone.

🟡 [important] Missing changeset. Since this is a bug fix, please generate one:

pnpm changeset

Select packages/mermaid, patch bump, and prefix the description with fix: (e.g., fix: correct block positioning when nested blocks span multiple columns).

Self-check

  • At least one 🎉 praise item
  • No duplicate comments
  • Severity tally: 0 🔴 / 3 🟡 / 0 🟢 / 0 💡 / 2 🎉
  • Verdict: Approved
  • Tone check: collaborative and appreciative

Thanks for the contribution — the fix itself is spot-on. Once the test and changeset are added, this should be ready to go. Let me know if you need any help with the Cypress test setup!

knsv and others added 2 commits March 1, 2026 13:28

@knsv knsv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argos spotted some regression issues in the PR which I can confirm:

This diagram

block
  columns 3
  a:3
  block:group1:2
    columns 2
    h i j k
  end
  g
  block:group2:3
    %% columns auto (default)
    l m n o p q r
  end
Loading

Looks like this with the change:

Image

@knsv

knsv commented Mar 1, 2026

Copy link
Copy Markdown
Collaborator

Here's why that breaks with the PR fix:

  1. Height divergence after resizing. In setBlockSizes, step 3 (lines 110–112) initially makes all root children the same height (maxHeight). But step 4 (lines 121–123) calls
    setBlockSizes recursively again, and at line 186–191, each block's height gets rewritten to match its internal layout:
  • group1 (2 columns, 4 children → 2 rows internally) → tall
  • group2 (auto columns, 7 children → 1 row internally) → short
  1. The y-position formula breaks. When positioning group2 at py=2:

group2.y = parent.y - parent.h/2 + 2 * (group2.height + padding) + group2.height/2 + padding

It computes the offset for rows 0 and 1 using group2.height — but row 1 actually contains group1, which is taller than group2. The formula underestimates the space taken by row
1, so group2 gets placed too high, overlapping group1.

  1. Why wasn't this visible before the fix? With the original code (block.widthInColumns — the parent's span), getMaxChildSize returns an inflated maxWidth. This causes the "too
    small sibling" branch (line 142–163) to trigger more aggressively during the second setBlockSizes pass, forcing:

height = siblingHeight; // line 147 — forces uniform height

This masks the y-positioning bug by keeping all children at the same height. The PR fix produces correct per-column widths, so children keep their natural heights — and the
pre-existing row-height bug surfaces.

In short: the fix is correct for width calculation, but it exposes a latent bug in layoutBlocks where the y-positioning formula assumes uniform row heights. The real fix needs
to also track per-row max heights and use cumulative row offsets instead of py * (child.height + padding).

knsv and others added 2 commits March 1, 2026 14:22
The y-position formula in layoutBlocks assumed all rows have the same
height (the current child's height). When nested blocks have different
internal layouts (e.g. group1 with 2 rows vs group2 with 1 row), this
caused later rows to overlap earlier taller rows.

Fix: pre-compute per-row max heights and use cumulative row offsets
instead of py * (child.height + padding).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ights

BL32: reproduces issue mermaid-js#5706 — nested blocks spanning multiple columns
BL33: verifies rows with different heights don't overlap

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Mar 1, 2026 •

Copy link
Copy Markdown
Contributor

❌ Lockfile Validation Failed

The following issue(s) were detected:
• Disallowed path 'packages/mermaid/src/vitepress' present. Run rm -rf packages/mermaid/src/vitepress && pnpm install to regenerate.

Please address these and push an update.

Posted automatically by GitHub Actions

knsv and others added 2 commits March 1, 2026 14:56
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@knsv knsv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ready to approve this one now!

@knsv
knsv added this pull request to the merge queue Mar 1, 2026
Merged via the queue into mermaid-js:develop with commit 3b5f67d Mar 1, 2026
22 checks passed
@mermaid-bot

mermaid-bot Bot commented Mar 1, 2026

Copy link
Copy Markdown

@NealGooch, Thank you for the contribution!
You are now eligible for a year of Premium account on MermaidChart.
Sign up with your GitHub account to activate.

@github-actions github-actions Bot mentioned this pull request Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Type: Bug / Error Something isn't working or is incorrect

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Positioning is broken

2 participants