Repository navigation
[v12] chore!: require ES2024, Node.js 22.12, and Safari 17.4 - #8213
Conversation
🦋 Changeset detectedLatest commit: 9ea73f4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 7 packages
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 |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Mermaid now requires browsers that support ES2024.
We're targeting browser support for Safari 17.4, since Safari is the
main browser that tends to be out-of-date, due to iOS/MacOS devices not
being to upgrade to new iOS/MacOS versions.
Chromium v121 and Firefox 123 have also been added as targets, since
they're on the `baseline-widely-available` right now (just like Safari
17.4 in a few days), but we're not commited to supporting them, as it's
unlikely people are stuck on those browsers.
We're also officially declaring a Node.JS v22.12+ requirement for users
that install mermaid for build tools. This is mainly to avoid `npm
install` errors for our users, as we're a browser-based library and we
don't actually support running mermaid in Node.JS.
- esbuild now targets ES2024 and Safari 17.4
- TypeScript targets ES2024 with ES2024 lib; class-field semantics are pinned to
the legacy behaviour so object shapes do not change in this PR
- root and published package.json files declare engines.node >= 22.12.0
- fix an invalid `a?.b = c` assignment in architecture.spec.ts that the old ES2018
lowering used to hide
BREAKING CHANGE: Mermaid now requires ES2024 and Safari 17.4 or later.
Although Mermaid is a browser library, Mermaid also
declares a Node.JS v22.12+ requirement so it can update
using dependencies that also require Node.JS v22.12+,
without causing `npm install` errors for users.
…ri.17.4 Conflicts: packages/mermaid-layout-elk/package.json
82c3b79 to
c6cf520
Compare
…ri.17.4 Fixes a merge conflict in `package.json` that GitHub seems to see, but git CLI can solve without conflicts.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## release/12.0.0 #8213 +/- ##
==================================================
- Coverage 80.16% 80.16% -0.01%
==================================================
Files 624 624
Lines 85411 85416 +5
Branches 16216 18544 +2328
==================================================
+ Hits 68471 68472 +1
- Misses 15906 15910 +4
Partials 1034 1034
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
The latest updates on your projects. Learn more about Argos notifications ↗︎
|
ashishjain0512
left a comment
There was a problem hiding this comment.
[sisyphus-bot]
This is a clean piece of work for a breaking change — the kind where most of the risk is in the bits that are easy to forget, and those are all handled. I checked out the head (38256bb) and verified the mechanics rather than only reading the diff.
Heads-up on ordering: this is stacked on build/add-eslint-plugin-compat (#8212), and the browserslist edit here edits a field that PR introduces — so it needs to land after it.
What's working well
🎉 Changeset coverage is exactly right. I enumerated every manifest under packages/: seven publishable packages (mermaid, @mermaid-js/parser, @mermaid-js/tiny, @mermaid-js/examples, @mermaid-js/layout-elk, @mermaid-js/layout-tidy-tree, @mermaid-js/mermaid-zenuml) and two private ones (@mermaid-js/mermaid-example-diagram, @mermaid-js/mermaid-local-editor). All seven publishable ones get engines and a major entry in .changeset/bitter-jeans-worry.md; the two private ones correctly get neither. That's the easiest thing in the world to get 6/7 right on.
🎉 useDefineForClassFields: false is the right call, and it actually reaches the bundles. TypeScript and esbuild both flip that default to true at target >= ES2022, so without the explicit pin at tsconfig.json:27-29 this PR would have quietly changed class-field semantics (define-vs-set, accessor shadowing, own-property shape) across the whole codebase. Pinning it keeps the change shape-neutral, and because .esbuild/util.ts builds with tsconfig: 'tsconfig.json', esbuild honours the pin for shipped output rather than just for tsc. The TODO framing is right too — that flip deserves its own PR.
🎉 The architecture.spec.ts fix is a real improvement, not just syntax appeasement. parser.parser?.yy = db isn't valid JS; the old ES2018 lowering emitted roughly (_a = parser.parser) == null ? void 0 : _a.yy = db, which silently skipped the assignment if parser.parser was nullish — so a beforeEach that failed to wire up the db would have left tests running against whatever yy was previously. assert(parser.parser) turns that into a loud failure and lets the @ts-expect-error go. A grep for optional-chain assignment (?.x =, ?.x ??=, ?.[…] =, and friends) across the repo finds exactly this one occurrence, so there's no second landmine waiting.
🎉 No stale version pins left behind. .node-version is already 24.16.0 and the Dockerfile already pins node:22.12.0-alpine, so the new floor doesn't contradict anything in CI or tooling — and both docs copies (packages/mermaid/src/docs/** source and the generated docs/** mirror) were updated together.
🎉 Centralising the target in .build/common.ts fixes a pre-existing mismatch as a side effect. Before this PR the production bundles had no target at all (esbuild default esnext) while the dev server hardcoded es2020 — dev and prod were compiled to different floors, in the direction that hides problems. Both now read buildTarget.
🎉 All 8 e2e shards, unit-test (which runs pnpm test:check:tsc, so scripts/tsc-check.ts is covered) and build-docs are green, so the target bump builds and renders. Worth noting for anyone eyeing the red argos: it reports the same 176 changed screenshots on #8212, which touches nothing in the bundles — so that's release-branch baseline drift, not output shifted by the new esbuild target.
Things to address
🟡 [important] iOS Safari isn't actually in the lint's target list — and it's the platform the changeset names as the whole reason for 17.4. browserslist treats ios_saf as a family separate from safari, so safari >= 17.4 doesn't imply it. Resolved from packages/mermaid/src/mermaid.ts on this head:
families: chrome, firefox, node, safari
floors : chrome 121 | firefox 123 | node 22.12.0 | safari 17.4
ios_saf present? false edge present? false
Meanwhile buildTarget (.build/common.ts) does list ios17.4 and edge121. So the esbuild target and the lint target disagree on exactly the two entries, and the missing one is the one that motivated the PR. iOS Safari's API surface does trail desktop Safari at the same version number in places, so this isn't purely cosmetic. ios_saf >= 17.4 and edge >= 121 in browserslist would close it.
In fairness: I tried to demonstrate an API this actually lets through and couldn't get compat/compat to flag one either way, which is consistent with the detection-coverage limitation I raised on #8212 (ast-metadata-inferer@0.8.1 derives its metadata from @mdn/browser-compat-data@5.7.6). So treat this as "the declared floor should match the intended floor" rather than a bug you'd see today.
🟢 [nit] e2e/tsconfig.json silently flips useDefineForClassFields the other way. It's the one standalone tsconfig in the repo — everything under packages/ extends the root — and moving it to target/lib es2024 (e2e/tsconfig.json:3-4) takes its useDefineForClassFields default from false (the es2020 default) to true, directly opposite the root's deliberate pin. It's noEmit and the e2e specs have no classes, so nothing breaks; it just means the two files now disagree about a decision this PR is explicitly making. Adding the pin there (or having it extends: '../tsconfig.json') keeps them from drifting.
🟢 [nit] The node entries are inert in both lists. node >= 22.12 in browserslist doesn't produce findings in practice — lint is green across source that's full of document/window, which have no Node support data at all — and node22.12 in buildTarget can't constrain a platform: 'browser' bundle further, since Node 22.12 supports all of ES2024. Harmless, but engines already states the Node floor, so this is a fourth copy of the same number to keep in sync. Dropping them (or a one-line comment saying they're declarative) would make the intent clearer.
🟢 [nit] The new docs section has no version qualifier. "Mermaid's published bundles target ES2024 and are aimed to support Safari 17.4 or later" (packages/mermaid/src/docs/config/usage.md) is unconditionally true only from v12. Since the docs are built from the source tree, a v11 reader could take it as current. MERMAID_RELEASE_VERSION exists for exactly this, and the same applies to the Node.js >= 22.12.0 line under Requirements.
Suggestions
💡 The floor now lives in five places, held together by a comment. browserslist (root package.json), buildTarget (.build/common.ts), target/lib (tsconfig.json, e2e/tsconfig.json, scripts/tsc-check.ts), engines, and the docs prose. The doc comment on buildTarget acknowledges the duty — and the ios_saf/edge divergence above is that duty already being missed on day one, before anyone has had a chance to forget. A few lines in .esbuild/util.spec.ts asserting buildTarget agrees with the resolved browserslist (or generating one from the other — browserslist-to-esbuild does this) would turn a convention into a check. Not this PR's job, but it's the natural follow-up.
💡 Worth being explicit in the changelog that pnpm makes this a hard failure. npm only warns on an engines mismatch unless engine-strict=true, but pnpm errors by default (ERR_PNPM_UNSUPPORTED_ENGINE). So for pnpm users on Node < 22.12 — a docs site or app that merely bundles mermaid and never runs it in Node — this is an install failure rather than a warning. That reads as intended given the rationale, but "you may be unable to install" lands differently from "you may see a warning", and it's the one consequence users will actually hit.
Security
No XSS or injection issues identified. No shipped runtime source changes at all — the only packages/*/src file touched is a spec. I did check the two paths where a language-level change could matter: the DOMPurify boundary in mermaidAPI.ts (sanitize on the serialized output, after draw(), for every non-loose/non-sandbox path) and the sanitizeText/removeScript hooks in diagrams/common/common.ts are untouched; no regex in packages/*/src uses the v flag or unicode property escapes, so the new target can't shift sanitizer regex semantics; and nothing was added to esbuild's define/banner/inject — buildTarget is a compiler flag, not injected content. The error path in mermaidAPI.ts rethrows rather than returning partially-built SVG, so even a mid-render TypeError from a newly-lib-allowed API can't bypass sanitization.
Verdict: comment only, nothing blocking. The 🟡 and the first two nits are one-liners; the rest is changelog wording and a follow-up idea.
Use a `v<MERMAID_RELEASE_VERSION>+` tag to specify that the ES2024 support will only happen in the next version. I've also added `ios_saf` and `edge` to our `browserlist`, even though they're identical to `safari` and `chrome`, so it matches our ESBuild `target`.
Updated in 9ea73f4
This is fine, it's only for E2E tests.
This is also fine, it's better to document them than not to document them. And just because they are inert now, they might not be inert in the future.
Updated in 9ea73f4
I don't think this is too big of a deal, since we're very very unlikely to change this for a long time.
I think the |
Upstream release: https://github.com/mermaid-js/mermaid/releases/tag/mermaid%4012.0.0 Release notes: **Mermaid 12.0.0** ships ELK as the bundled default layout engine, a new `redux-color` / `neo` default appearance, and two new diagram types: [UML use case diagrams](https://mermaid.ai/open-source/syntax/usecase.html). This is a breaking release (ES2024, Safari 17.4+, Node 22.12+). Existing flowcharts, state and class diagrams will re-lay out and recolour; add `layout: dagre`, `theme: default` and `look: classic` to your config to keep the old look. Full changelog below. ### Major Changes - [#8213](mermaid-js/mermaid#8213) [`33442fd`](mermaid-js/mermaid@33442fd) Thanks [@aloisklink](https://github.com/aloisklink)! - chore!: require ES2024, Safari 17.4+, Node.JS v22.12+ Mermaid is now built to target Safari 17.4+ and ES2024. If you need to support older browsers, you may need to polyfill or transpile mermaid. Safari 17.4+ has been chosen as the floor, as unlike Firefox/Chrome, older iOS devices don't get major Safari updates. Node.JS v22.12+ is also declared as requirement in our `package.json` files, but as mermaid requires a browser, this is mainly so we can use dependencies that also declare a Node.JS v22.12+ requirement, without causing issues for users when running `npm install`. - [#8155](mermaid-js/mermaid#8155) [`810893c`](mermaid-js/mermaid@810893c) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat!: **ELK is now bundled with mermaid and is the default layout algorithm.** ELK previously shipped as a separate `@mermaid-js/layout-elk` package that sites had to install and register. It is now part of mermaid itself and registered automatically, so `layout: elk` — and the `elk.stress`, `elk.force`, `elk.mrtree`, `elk.sporeOverlap`, `elk.box` and `elk.rectpacking` variants — work with no setup. **This changes how existing diagrams look.** Flowchart, state, class, entity-relationship, requirement, use-case diagrams that do not specify a `layout` are now laid out by ELK instead of dagre. To keep the previous layout, set dagre explicitly: ```yaml --- config: layout: dagre --- ``` or globally, `mermaid.initialize({ layout: 'dagre' })`. Mindmap is unchanged: it keeps laying out with cose-bilkent unless a layout is explicitly requested (in the tiny build, which ships neither ELK nor cose-bilkent, it falls back to dagre). Other notes: - ELK is loaded as a separate chunk in the ESM builds, so it is only fetched when a diagram actually uses it. The single-file IIFE build (`mermaid.min.js`) inlines it and grows by roughly 500 kB gzipped. - The **tiny** build deliberately omits ELK to stay small, and falls back to dagre for diagrams that ask for an ELK layout. Its size is unchanged. - `@mermaid-js/layout-elk` is no longer needed on normal builds — existing `mermaid.registerLayoutLoaders(elkLayouts)` calls keep working and can be removed. It is still published, and remains the way to add ELK to the tiny build. - `dist/mermaid.esm.min.mjs` now contains syntax that `es-module-lexer` (used by Vite) rejects with `content contains invalid JS syntax`. Bundler users are unaffected as long as they import the `mermaid` package specifier, which resolves to the core build; only builds that point Vite directly at that dist file need to switch to the package specifier or the core build. - State diagrams now resolve their layout through the same registration check as every other diagram, so an unavailable layout falls back instead of failing to render. An unrecognised `theme` name now resolves to the default theme in name as well as in variables; previously the invalid name stayed in place while the default's variables were loaded, and every palette-aware stylesheet gates on the name. `theme: 'null'`, the documented way to disable the pre-defined themes, is unaffected. Note that `neo` paints node strokes with a gradient when the theme sets `useGradient`, which `base` does; setting a custom `nodeBorder` on `base` turns the gradient off. - [#8211](mermaid-js/mermaid#8211) [`a19bd08`](mermaid-js/mermaid@a19bd08) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - **Removed: the `defaultRenderer` option of the `flowchart`, `class` and `state` config sections.** Use the top-level `layout` option instead: ```yaml --- config: layout: dagre # or elk --- ``` ### Why `defaultRenderer` named a rendering engine back when there was more than one. There is not. All of its accepted values — `dagre`, `dagre-wrapper`, `dagre-d3` — had come to select the same unified renderer, and its `elk` value did nothing but set `layout: elk` on your behalf. The option's documented purpose no longer existed. What it still did was stranger than doing nothing. The detectors branched on whether the value was _recognised_, so a **valid** value routed a diagram to the modern renderer and an **invalid** one silently routed it to the legacy renderer. Since the default was always a valid value, the legacy `class` and `state` renderers were unreachable except by misconfiguring the option. ### What changes for you - `layout` selects the layout algorithm, as it already did. Nothing else does. - `graph`, `classDiagram` and `stateDiagram` always render with the unified diagram. This was already true for every valid configuration. - The legacy `flowchart`, `class` and `state` diagram ids are gone. `flowchart-v2`, `classDiagram` and `stateDiagram` are what `detectType` now returns for that syntax. - `flowchart-elk` as an explicit diagram keyword still works. Configuration that still sets `defaultRenderer` is ignored rather than rejected, so nothing throws — but it no longer has any effect, and diagrams that relied on `flowchart: { defaultRenderer: 'elk' }` to get an ELK layout should set `layout: elk`. - [#8223](mermaid-js/mermaid#8223) [`6df1149`](mermaid-js/mermaid@6df1149) Thanks [@aloisklink](https://github.com/aloisklink)! - refactor!: remove layout internal exports Remove the `clearLayoutRenderState`, `createCommonLayoutRenderer`, `defaultMeasureLayout`, `paintLayoutData` functions, and the `CommonLayout*` types from Mermaid's public API. These functions were only used by the `@mermaid-js/layout-elk` package, which now bundles them. Removing them makes it easier to avoid major versions of mermaid. ### Minor Changes - [#8048](mermaid-js/mermaid#8048) [`7a3c1a8`](mermaid-js/mermaid@7a3c1a8) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat: add UML use case diagrams with actors, use cases, system boundaries, relationships, stereotypes, notes, JSON tables, class and style support, accessibility metadata, and business variants. - [#8073](mermaid-js/mermaid#8073) [`cd48a64`](mermaid-js/mermaid@cd48a64) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat: `defaultMeasureLayout` accepts a `unwrapGroupLabels` option so a layout engine can ask for cluster labels to be measured at their natural width instead of the `flowchart.wrappingWidth` fallback. `insertCluster` paints a plain cluster label with an infinite width while the measurement pass wrapped it at 200px, so a layout that sizes compound nodes from the measured label sized them too narrow. Layouts now opt in explicitly; core no longer inspects the layout's name. Markdown cluster labels stay wrapped, since those are painted wrapped. The bundled ELK layout opts in, which changes the size of labelled subgraphs in ELK-laid-out diagrams. Diagrams laid out with dagre are unaffected. - [#8073](mermaid-js/mermaid#8073) [`0cf3797`](mermaid-js/mermaid@0cf3797) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat: let a container pick its own ELK algorithm with `@{ algorithm: … }`, and add `elk.box` and `elk.rectpacking` to the selectable `layout` values. A subgraph carrying `@{ algorithm: elk.box }` is laid out with that algorithm in its own coordinate system instead of inheriting the diagram's. Supported values are `elk.layered`, `elk.box`, `elk.rectpacking`, `elk.stress`, `elk.force`, `elk.mrtree`, `elk.radial`, and `elk.sporeOverlap`; anything else is ignored with a warning rather than handed to ELK, where an unknown id would abort the layout. Containers with edges crossing their boundary fall back to the inherited algorithm, since isolated layout and cross-boundary edges are incompatible. Also in this release: - ELK cluster labels are measured unwrapped, so a compound node is sized to fit its label instead of to a 200px wrapping width. **This changes the size — and therefore the layout — of existing ELK diagrams that have labelled subgraphs.** - `elk.box` and `elk.rectpacking` place nodes but never route edges. Edges they leave unrouted now fall back to a straight line between the two node centres instead of failing the render. - `keepEntryNodeOnTop` pins a cycle's true entry rather than the first-declared node when a back-edge feeds the entry, so recursive flows read from where they actually start. - [#8193](mermaid-js/mermaid#8193) [`813c766`](mermaid-js/mermaid@813c766) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - **`theme`, `look` and `layout` can now be set per diagram type**, in each diagram's config section — `mermaid.initialize({ look: 'classic', flowchart: { look: 'handDrawn' } })`, or the same under `config` in front matter. The schema uses the same mechanism to give a diagram type its own default. Resolution, highest first: front matter or directive, `initialize()`, the diagram type's default, the global default; a diagram-scoped value beats a global one set in the same layer. Swimlanes take `layout: swimlane` from that schema default instead of having it forced by their `init` hook, so `swimlane: { layout: ... }` and a `layout` in front matter are now honoured. An unregistered layout also always falls back to `dagre` with a warning rather than throwing — state diagrams skipped that fallback, and mindmaps threw when `cose-bilkent` was absent, as it is in `@mermaid-js/tiny`. - [#8147](mermaid-js/mermaid#8147) [`43d9fbc`](mermaid-js/mermaid@43d9fbc) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat(themes): class boxes and flowchart subgraph containers now take a per-item colour under the `redux-color` and `redux-dark-color` themes, cycling every 12 as ER entities already do. Collapsed subgraphs keep the slot they would have had expanded; nodes inside a subgraph stay uniform, and explicit `classDef` or `style` still wins over the palette. - [#8191](mermaid-js/mermaid#8191) [`2878cf3`](mermaid-js/mermaid@2878cf3) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat(themes): composite states now take a per-container colour under the `redux-color` and `redux-dark-color` themes, as flowchart subgraphs already do. Each composite gets the palette's border colour on its outline and its background tint behind the title strip; nested composites each take the next colour, so depth stays readable. The body keeps the theme's own `compositeBackground`. `redux-dark-color` colours the outlines only, matching how it treats ER, requirement and sequence. The concurrency regions produced by a `--` divider share the colour of the composite they split, rather than taking one of their own — the author wrote a single composite, so it is drawn as one thing in parts. Adding a `--` therefore leaves every other composite's colour untouched. Under the `handDrawn` look, concurrency regions are now filled solid rather than hatched, so that they can carry the palette tint the same way every other look does. States inside a composite stay uniform. A composite carrying its own `classDef` or `style` keeps those colours and takes no palette slot, and neither do its concurrency regions; the slot is still spent, so styling one composite does not shift the colours of the ones after it. Note that this opt-out is all-or-nothing: a `classDef` that sets only text properties, such as `font-weight`, still takes that composite out of the palette. - [#8176](mermaid-js/mermaid#8176) [`16b9a7d`](mermaid-js/mermaid@16b9a7d) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat(themes): swimlane lanes take a per-lane colour under the `redux-color` and `redux-dark-color` themes, cycling every 12 as flowchart subgraphs do. The lane holding ungrouped nodes takes its own slot and now follows the diagram's `look`. - [#8178](mermaid-js/mermaid#8178) [`75e6c30`](mermaid-js/mermaid@75e6c30) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat(usecase): use case diagrams now take colour by role — actors, use cases and system boundaries each get their own colour from the new `usecaseActorBkg`/`usecaseActorBorder`, `usecaseBkg`/`usecaseBorder` and `usecaseBoundaryBkg`/`usecaseBoundaryBorder` theme variables, with `usecaseIncludeLine`/`usecaseExtendLine` separating the two dashed relationship kinds by hue. `redux-color` and `redux-dark-color` set them; every other theme is unchanged. Colour is keyed to the kind of element, so editing a diagram never recolours the elements around the edit. Set `usecase.colorScheme: 'rotate'` for the per-element palette cycle instead, and `classDef`/`style` still wins over both. ### Patch Changes - [#8211](mermaid-js/mermaid#8211) [`dc2e453`](mermaid-js/mermaid@dc2e453) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(block): restore node borders under looks that use a gradient stroke. A block diagram rendered with `look: neo` lost its node borders entirely. The look-specific rules set `stroke: url(#<svgId>-gradient)`, and those definitions were appended by `rendering-util/render.ts` — which block does not use, since it runs its own render loop. An `url(#…)` paint that resolves to nothing is painted as **none**, not as a fallback colour, so the border disappeared rather than degrading to a plain stroke. The definitions now live in `rendering-util/insertLookDefs.ts` and both render paths call it, so the two cannot drift into producing different gradients. This only became visible recently: block did not previously pass `look` to its nodes, so none of the look-specific rules applied to it and the missing definitions went unnoticed. - [#8181](mermaid-js/mermaid#8181) [`ce0302d`](mermaid-js/mermaid@ce0302d) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(block): apply the redux colour palette to composite blocks. Composites now take a per-container colour under `redux-color` and `redux-dark-color`, matching how flowchart subgraphs are coloured — one counter over containers, in declaration order, with the plain shapes left on the flat theme colour. The palette is opt-in: block does not default to `redux-color` the way flowchart and several other diagram types do, so set `theme: redux-color` (or `redux-dark-color`) explicitly to see it. `classDef`/`style` still win. - [#8211](mermaid-js/mermaid#8211) [`ad98070`](mermaid-js/mermaid@ad98070) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(block): take the node border width from the theme, as every other diagram does. `block/styles.ts` pinned `stroke-width: 1px` on node shapes while the flowchart, class and state stylesheets all read `strokeWidth` from the theme. Under a theme that asks for more — `neo` asks for 2 — a block rendered a visibly thinner border than an identical flowchart node, and nothing downstream corrected it: the `neo` rules in the shared stylesheet set `stroke` and `filter`, never `stroke-width`. The gap was invisible until block began propagating `look` to its nodes, because until then none of the look-specific rules applied to block at all. Affects only themes whose `strokeWidth` is not 1. `neo` is 2; `neo-dark`, `base` and the rest are unchanged. - [#8231](mermaid-js/mermaid#8231) [`e2aab3f`](mermaid-js/mermaid@e2aab3f) Thanks [@knsv-bot](https://github.com/knsv-bot)! - Use balanced Brandes-Koepf placement for the default ELK preset to improve alignment of branches and composite-state entries. Preserve named non-default presets and explicit placement/alignment options, including `NONE`. Some diagrams may become wider or taller; `depthFirst` retains the previous default layout. - [#7874](mermaid-js/mermaid#7874) [`6b79518`](mermaid-js/mermaid@6b79518) Thanks [@filipsajdak](https://github.com/filipsajdak)! - fix(c4): allow boundaries as relationship endpoints A `Rel` (or `BiRel`/`Rel_*`) that referenced a boundary alias threw `references an unknown shape`, because endpoint lookup only searched shapes and not boundaries. Boundary aliases now resolve as relationship endpoints. Fixes #4864. - [#8100](mermaid-js/mermaid#8100) [`30325d4`](mermaid-js/mermaid@30325d4) Thanks [@filipsajdak](https://github.com/filipsajdak)! - fix(c4): stop wrapping non-text named attributes that land in a text slot A named attribute such as `$tags` or `$sprite` can arrive in the positional slot of a text field when the argument before it is omitted. It was then stored as `{ text: value }` rather than a string, so `$tags` given without a description crashed rendering. - [#8148](mermaid-js/mermaid#8148) [`c3ee3c7`](mermaid-js/mermaid@c3ee3c7) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(themes): `redux-dark`, `redux-dark-color` and `neo-dark` shipped `secondBkg` as the literal string `calculated`, so railroad rendered the invalid `fill: calculated`; it is now computed as `theme-dark` does. The same three themes had gantt done-task labels at 1.07:1 contrast — a light fill under their light task ink — now 5.7:1 or better. The ER and requirement stylesheets also validate `look` before interpolating it into a CSS selector. - [#8222](mermaid-js/mermaid#8222) [`1ee934d`](mermaid-js/mermaid@1ee934d) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: stop ELK-laid-out diagrams logging `Unknown arrow type: arrow_open` once per edge. ELK's arrow table put the edge _type_ `arrow_open` — which means "no arrowheads" — into the arrow-type slot, where `none` is the value that marks a deliberate absence. Anything else is reported as an unknown marker name. Diagrams whose db sets `arrowTypeStart` itself, such as flowcharts, never reached that fallback; state diagrams, which leave it unset, warned on every edge. Rendering is unchanged: both spellings produced no start marker and the same geometry, since neither has a marker offset. Only the log noise goes away. - [#8204](mermaid-js/mermaid#8204) [`a7831c5`](mermaid-js/mermaid@a7831c5) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: keep ELK subgraph frames out to the border anchor of edges that terminate on the group, so transitions to composite states no longer run along the cluster border - [#8155](mermaid-js/mermaid#8155) [`0320406`](mermaid-js/mermaid@0320406) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(elk): a composite state or subgraph containing a loop now opens on its own start node. Cycle breaking was resolved for the root graph but never passed to containers, so a container laid out on its own fell back to ELK's default, `GREEDY`, while the root ran whatever `elk.preset` asked for. The two then reversed different edges of the same cycle. In a composite state that loops, greedy reverses the edge that turns an ordinary state into a source, and sources sit on the first layer — so the diagram opened on that state alongside its start circle instead of on the start circle alone. Dagre reverses the other edge, which is why the two layout engines disagreed on the same diagram. Containers now resolve cycle breaking from the preset exactly as the root does. Only containers that actually contain a cycle change; an acyclic subgraph gives a cycle-breaking strategy nothing to do. `preset: legacy` still reaches containers with `GREEDY`, so it keeps reproducing the earlier rendering inside frames as well as outside them. - [#8228](mermaid-js/mermaid#8228) [`e36b883`](mermaid-js/mermaid@e36b883) Thanks [@knsv-bot](https://github.com/knsv-bot)! - Reserve subgraph title padding before ELK routes edges so attachments stay on the painted frame. Clip stale interior endpoints along the incoming segment, avoiding edges that run along the subgraph border. - [#8199](mermaid-js/mermaid#8199) [`b993915`](mermaid-js/mermaid@b993915) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: keep ELK edges vertical at small nodes — the node now moves onto the routed line instead of the edge bending toward the node's off-centre position - [#8155](mermaid-js/mermaid#8155) [`4e00c5c`](mermaid-js/mermaid@4e00c5c) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: render ER relationship edges above subgraph backgrounds under the ELK layout instead of hiding them behind the cluster rect - [#8156](mermaid-js/mermaid#8156) [`3f05015`](mermaid-js/mermaid@3f05015) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(er, requirement, timeline): stop the ER, requirement and timeline stylesheets emitting CSS the browser discards for the colour themes. All three generate one rule per palette slot. ER and requirement looped to `THEME_COLOR_LIMIT` and indexed the palette by the loop counter, which goes wrong in both directions: a palette shorter than the limit emitted `stroke: undefined` for the overflow slots, and a palette _longer_ than it left entities stamped with a slot that had no rule at all, rendering unstyled beside coloured neighbours. Both now take the loop bound from the palette itself, which is the same length the boxes stamp with — so the rules emitted and the slots stamped cannot disagree. Both also bail before the loop for an empty palette, since wrapping alone is not enough there: `i % 0` is `NaN` and `[][NaN]` is `undefined`. Timeline keeps looping to `THEME_COLOR_LIMIT` and wrapping, because it numbers `.section-N` classes rather than palette slots — nothing stamps those, so the palette cycles across however many sections exist. `requirement` also emitted `fill: ;` — a property with no value, which is invalid — whenever there was no background palette. That is the live case for `redux-dark-color`, which ships a border palette and no background palette so that it colours outlines only. The declaration is now omitted instead. None of these raises an error: the browser discards the invalid declaration, so the only symptom is a shape rendering unstyled. - [#8149](mermaid-js/mermaid#8149) [`d57ed55`](mermaid-js/mermaid@d57ed55) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(docs): stop `docs:build` deleting the committed `docs/` directory when a later step fails. - [#7906](mermaid-js/mermaid#7906) [`1fc5bb3`](mermaid-js/mermaid@1fc5bb3) Thanks [@knsv-bot](https://github.com/knsv-bot)! - perf: avoid quadratic parse cost on deeply-indented diagrams (~1.4 s → ~30 ms on a pathological fixture) - [#8211](mermaid-js/mermaid#8211) [`b979eb4`](mermaid-js/mermaid@b979eb4) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(handdrawn): tighten the hachure fill so shapes read as filled rather than striped. The hand-drawn fill drew 4px-wide strokes 5.2px apart, which left visible diagonal banding across every shape — legible as a texture up close, but at normal diagram size it read as stripes rather than a fill. Strokes are now 1.5px at 1.5px spacing, so the fill reads as an even tint while keeping the drawn edge quality. The striped fill behind state-diagram start, end and fork markers moves the same way, so those come out close to solid — which is what the UML convention asks for anyway. Swimlane lane titles previously pinned their own stroke weight and so ignored the shared value; they now follow it like every other shape. - [#8152](mermaid-js/mermaid#8152) [`7ee4c3f`](mermaid-js/mermaid@7ee4c3f) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: edges attach to non-rectangular shapes on the outline instead of half a pixel off it. **This is not ELK-specific.** `intersectPolygon` is how every non-rectangular shape finds its edge attachment — diamond, stadium, hexagon, trapezoid, subroutine — in every layout, so a dagre-rendered flowchart with a decision diamond is affected exactly as much as an ELK one. `intersectLine` comes from Graphics Gems, where the coordinates were integers and the numerator was nudged half a denominator away from zero so the integer division rounded instead of truncating. JavaScript division does neither, so the nudge stopped being a correction and became the whole error: every result came back displaced by `0.5 * sign(num) * sign(denom)`. The magnitude is always exactly half a unit, but the sign is per axis, because the numerator is computed separately for x and y while the denominator is shared — so the two axes could move the same way or opposite ways depending on the geometry, which is why it never looked like a constant offset anyone could spot by eye. That was enough to give an otherwise orthogonal edge a tiny diagonal opening segment, and to put an attachment just inside the node it was meant to touch. `question.ts` had been subtracting a flat 0.5 from both axes to compensate for diamonds. That only cancelled the bias when both signs came out positive, and doubled the error to a full unit when they did not — so the compensation goes along with the cause. **Rendered output moves by up to a pixel wherever a polygon shape terminates an edge.** - [#8048](mermaid-js/mermaid#8048) [`a6ec7ff`](mermaid-js/mermaid@a6ec7ff) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: treat `</br>` as a line break in labels `lineBreakRegex` only matched `<br>`, `<br/>` and `<br />`, so the malformed-but-common `</br>` survived as literal text wherever labels render as plain SVG text. HTML parsers already treat `</br>` as a `<br>`, so the tag appeared to work in HTML-label mode and failed everywhere else. It is now accepted on both paths. Also fixes `hasBreaks()` returning alternating results for the same input: it called `.test()` on a global regex, which advances `lastIndex` between calls. `wrapLabel()` used the same stateful check and could therefore re-wrap labels that already contained breaks. - [#8152](mermaid-js/mermaid#8152) [`1246a55`](mermaid-js/mermaid@1246a55) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: don't draw a line hop that has no room next to a bend. A crossing close to a corner used to get a hop squeezed into whatever space was left — as little as 2.9px against a requested 6px, opening exactly on the corner's tangent point. At that size the arc no longer clears the line it is meant to hop, so the two strokes still touch and the corner's curve runs straight into the arc's. It reads as a rendering fault rather than as a crossing. Hops now keep a straight run clear of the bend, and one that would still have to shrink below 60% of the requested radius is dropped instead of drawn. An undrawn hop is an ordinary crossing, which is a much better failure than a broken-looking one. **This changes swimlane diagrams as well as ELK ones.** Swimlanes are the existing consumer of line hops and have them on today, so a swimlane with a crossing near a bend will render differently even for someone not using ELK at all. It shows up wherever a layout stacks edges in narrow lanes: ELK routes subgraph-internal edges 10px apart, and 10px does not hold a 7.07px corner cut plus a 6px hop. A crossing is also ignored now when it lands inside the stretch where either edge is rounding a bend. Crossings are found on polylines, but a rounded edge is not drawn as its polyline — it leaves the line up to 7.07px before each bend and rejoins it that far after. A crossing found inside that stretch is somewhere the stroke never goes, so the hop was arching over blank paper while the two lines carried on touching beside it. - [#8146](mermaid-js/mermaid#8146) [`def4c81`](mermaid-js/mermaid@def4c81) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(themes): `redux-color` and `redux-dark-color` now define every variable their base themes define, instead of silently falling back to untuned values for `primaryBorderColor`, `clusterBkg`, `clusterBorder`, `altBackground`, `compositeTitleBackground` and the state and requirement edge-label backgrounds. Pie, gantt and user-journey also read the theme palette rather than a single pale tint, so pie slices are distinguishable and gantt sections are visibly banded. - [#8189](mermaid-js/mermaid#8189) [`3802472`](mermaid-js/mermaid@3802472) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(themes): venn circles follow the `redux-color` and `redux-dark-color` palettes. Neither theme defined any `venn*` variable, so every circle rendered in one flat colour. - [#8185](mermaid-js/mermaid#8185) [`f5af413`](mermaid-js/mermaid@f5af413) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: sequence diagram actors under the `neo` look and `redux` themes. Notes no longer render bold, a `rect` section band is no longer drawn white on white, and participants follow one vertical model: every lifeline starts and ends on a shared line, all participant glyphs are one size with their feet on a common edge, single-line labels share one baseline in the header and in the mirrored footer, and a multiline label grows away from the lifeline instead of moving it. The `classic` look is unchanged. - [#8157](mermaid-js/mermaid#8157) [`a3a92ba`](mermaid-js/mermaid@a3a92ba) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(sequence): index each actor colour palette by its own length. Every actor-drawing call site read `bkgColorArray[actorCount % borderColorArray.length]` — one palette indexed by the other's length. Under `redux-color` both palettes have twelve entries, so the wrong length happens to give the right answer and nothing is visibly broken today. It goes wrong as soon as the two differ in length: the overflow actors resolve to `undefined`, and d3 then strips the inline fill for some actors and not others. Both palettes now cycle within their own length, via a shared helper. An absent or empty palette still yields `undefined` rather than a substitute colour, which is what `redux-dark-color` relies on: it ships a border palette and an empty background palette so actors are outlined but not filled. - [#8232](mermaid-js/mermaid#8232) [`e691042`](mermaid-js/mermaid@e691042) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - Circle, double circle, Delay and Display nodes size themselves from the label's height as well as its width, so a wrapped label stays inside the outline. Each was sized from the width alone and clipped any label taller than it was wide, which `flowchart.wrappingWidth: 120` made common. This replaces the wrapping exemption those shapes carried along with stadium and diamond: it stopped them wrapping at all, so a long label produced a single-line node hundreds of pixels wide. Stadium needs no exemption — its `w >= 1.5h` floor already keeps a wrapped label from closing the caps into a circle — and diamond never needed one. Stacked (`docs`) and lined (`lin-doc`) document nodes lift their label clear of the wavy bottom edge by the wave's full depth rather than half of it, so the last line is no longer clipped by the trough. Plain `doc` already did this; the two variants had copied it with the offset halved. Node dimensions are unchanged. - [#8154](mermaid-js/mermaid#8154) [`ba0deed`](mermaid-js/mermaid@ba0deed) Thanks [@aloisklink](https://github.com/aloisklink)! - fix: bundle `fastdom` to fix issues with global `define` - [#8227](mermaid-js/mermaid#8227) [`b05824a`](mermaid-js/mermaid@b05824a) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(flowchart): stop stadium labels from wrapping into a circle and exempt selected shapes from automatic label wrapping. Long stadium labels wrapped to `flowchart.wrappingWidth`, grew taller without growing wider, and turned the stadium into a circle. Stadium now keeps its semicircular caps with an outer width of at least 1.5 times its height and enough clearance that the label stays inside the arcs. Stadium (`terminal`, `pill`), circle (`circ`), diamond (`diam`, `decision`, `question`), double circle (`dbl-circ`, `double-circle`), Display (`curv-trap`, `curved-trapezoid`, `display`) and Delay (`delay`, `half-rounded-rectangle`) no longer wrap their labels at `flowchart.wrappingWidth`. Explicit line breaks are kept, and an explicit node width still takes precedence. - [#8192](mermaid-js/mermaid#8192) [`0ec29e9`](mermaid-js/mermaid@0ec29e9) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(state): draw the edge between a state and its note dashed under the `neo` look. It was rendering solid. The dashes were expressed only as CSS — `.note-edge { stroke-dasharray: 5 }` — which is enough under `classic` but not under `neo`, where `insertEdge` writes an inline `stroke-dasharray` on every edge, computed from the path length so the arrow markers keep their gaps. An inline style outranks a stylesheet rule, so the note edge took the solid pattern and the `.note-edge` rule simply lost. The note edge now declares `pattern: 'dashed'`, which is what `insertEdge` reads to choose its dash generator. `classic` is unchanged. - [#8225](mermaid-js/mermaid#8225) [`0d77926`](mermaid-js/mermaid@0d77926) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(swimlane): seed cycle removal from source nodes so feedback edges are reversed instead of forward flow edges. A cycle like `task --> decision --> fix --> task` no longer places `fix` in the middle of the `start --> task` flow line. - [#8211](mermaid-js/mermaid#8211) [`93edd72`](mermaid-js/mermaid@93edd72) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: keep association markers apart on use-case ovals under ELK. Ovals get the same vertical padding as horizontal, edge attachment points on them are spread across the side, and the ELK renderer now accounts for every end-marker offset (extension, circle, cross, …) so a short entry stub can no longer flip a marker around. - Updated dependencies \[[`33442fd`](mermaid-js/mermaid@33442fd)]: - @mermaid-js/parser@2.0.0 ### Keeping the previous defaults in your integration Mermaid 12 changes what unconfigured diagrams look like: ELK replaces dagre as the default layout, and `redux-color` / `neo` replace `default` / `classic` as theme and look for flowchart, class, state, ER, requirement, sequence, use case, swimlane, Venn and agentflow. If you embed Mermaid and want your users' existing diagrams to render as before, set all three explicitly at initialisation: ```js mermaid.initialize({ layout: 'dagre', theme: 'default', look: 'classic' }); ``` Diagram authors can do the same per diagram in front matter, and a value there always wins over `initialize()`. - [Layouts: how `layout` is resolved, ELK variants, and the tiny build](https://mermaid.ai/open-source/config/layouts.html) - [Flowchart: default theme, look and layout in v12](https://mermaid.ai/open-source/syntax/flowchart.html#default-theme-look-and-layout-v-mermaid-release-version) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: give me a 98K <240642031+inhuman-0@users.noreply.github.com>
Upstream release: https://github.com/mermaid-js/mermaid/releases/tag/mermaid%4012.0.0 Release notes: **Mermaid 12.0.0** ships ELK as the bundled default layout engine, a new `redux-color` / `neo` default appearance, and two new diagram types: [UML use case diagrams](https://mermaid.ai/open-source/syntax/usecase.html). This is a breaking release (ES2024, Safari 17.4+, Node 22.12+). Existing flowcharts, state and class diagrams will re-lay out and recolour; add `layout: dagre`, `theme: default` and `look: classic` to your config to keep the old look. Full changelog below. ### Major Changes - [#8213](mermaid-js/mermaid#8213) [`33442fd`](mermaid-js/mermaid@33442fd) Thanks [@aloisklink](https://github.com/aloisklink)! - chore!: require ES2024, Safari 17.4+, Node.JS v22.12+ Mermaid is now built to target Safari 17.4+ and ES2024. If you need to support older browsers, you may need to polyfill or transpile mermaid. Safari 17.4+ has been chosen as the floor, as unlike Firefox/Chrome, older iOS devices don't get major Safari updates. Node.JS v22.12+ is also declared as requirement in our `package.json` files, but as mermaid requires a browser, this is mainly so we can use dependencies that also declare a Node.JS v22.12+ requirement, without causing issues for users when running `npm install`. - [#8155](mermaid-js/mermaid#8155) [`810893c`](mermaid-js/mermaid@810893c) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat!: **ELK is now bundled with mermaid and is the default layout algorithm.** ELK previously shipped as a separate `@mermaid-js/layout-elk` package that sites had to install and register. It is now part of mermaid itself and registered automatically, so `layout: elk` — and the `elk.stress`, `elk.force`, `elk.mrtree`, `elk.sporeOverlap`, `elk.box` and `elk.rectpacking` variants — work with no setup. **This changes how existing diagrams look.** Flowchart, state, class, entity-relationship, requirement, use-case diagrams that do not specify a `layout` are now laid out by ELK instead of dagre. To keep the previous layout, set dagre explicitly: ```yaml --- config: layout: dagre --- ``` or globally, `mermaid.initialize({ layout: 'dagre' })`. Mindmap is unchanged: it keeps laying out with cose-bilkent unless a layout is explicitly requested (in the tiny build, which ships neither ELK nor cose-bilkent, it falls back to dagre). Other notes: - ELK is loaded as a separate chunk in the ESM builds, so it is only fetched when a diagram actually uses it. The single-file IIFE build (`mermaid.min.js`) inlines it and grows by roughly 500 kB gzipped. - The **tiny** build deliberately omits ELK to stay small, and falls back to dagre for diagrams that ask for an ELK layout. Its size is unchanged. - `@mermaid-js/layout-elk` is no longer needed on normal builds — existing `mermaid.registerLayoutLoaders(elkLayouts)` calls keep working and can be removed. It is still published, and remains the way to add ELK to the tiny build. - `dist/mermaid.esm.min.mjs` now contains syntax that `es-module-lexer` (used by Vite) rejects with `content contains invalid JS syntax`. Bundler users are unaffected as long as they import the `mermaid` package specifier, which resolves to the core build; only builds that point Vite directly at that dist file need to switch to the package specifier or the core build. - State diagrams now resolve their layout through the same registration check as every other diagram, so an unavailable layout falls back instead of failing to render. An unrecognised `theme` name now resolves to the default theme in name as well as in variables; previously the invalid name stayed in place while the default's variables were loaded, and every palette-aware stylesheet gates on the name. `theme: 'null'`, the documented way to disable the pre-defined themes, is unaffected. Note that `neo` paints node strokes with a gradient when the theme sets `useGradient`, which `base` does; setting a custom `nodeBorder` on `base` turns the gradient off. - [#8211](mermaid-js/mermaid#8211) [`a19bd08`](mermaid-js/mermaid@a19bd08) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - **Removed: the `defaultRenderer` option of the `flowchart`, `class` and `state` config sections.** Use the top-level `layout` option instead: ```yaml --- config: layout: dagre # or elk --- ``` ### Why `defaultRenderer` named a rendering engine back when there was more than one. There is not. All of its accepted values — `dagre`, `dagre-wrapper`, `dagre-d3` — had come to select the same unified renderer, and its `elk` value did nothing but set `layout: elk` on your behalf. The option's documented purpose no longer existed. What it still did was stranger than doing nothing. The detectors branched on whether the value was _recognised_, so a **valid** value routed a diagram to the modern renderer and an **invalid** one silently routed it to the legacy renderer. Since the default was always a valid value, the legacy `class` and `state` renderers were unreachable except by misconfiguring the option. ### What changes for you - `layout` selects the layout algorithm, as it already did. Nothing else does. - `graph`, `classDiagram` and `stateDiagram` always render with the unified diagram. This was already true for every valid configuration. - The legacy `flowchart`, `class` and `state` diagram ids are gone. `flowchart-v2`, `classDiagram` and `stateDiagram` are what `detectType` now returns for that syntax. - `flowchart-elk` as an explicit diagram keyword still works. Configuration that still sets `defaultRenderer` is ignored rather than rejected, so nothing throws — but it no longer has any effect, and diagrams that relied on `flowchart: { defaultRenderer: 'elk' }` to get an ELK layout should set `layout: elk`. - [#8223](mermaid-js/mermaid#8223) [`6df1149`](mermaid-js/mermaid@6df1149) Thanks [@aloisklink](https://github.com/aloisklink)! - refactor!: remove layout internal exports Remove the `clearLayoutRenderState`, `createCommonLayoutRenderer`, `defaultMeasureLayout`, `paintLayoutData` functions, and the `CommonLayout*` types from Mermaid's public API. These functions were only used by the `@mermaid-js/layout-elk` package, which now bundles them. Removing them makes it easier to avoid major versions of mermaid. ### Minor Changes - [#8048](mermaid-js/mermaid#8048) [`7a3c1a8`](mermaid-js/mermaid@7a3c1a8) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat: add UML use case diagrams with actors, use cases, system boundaries, relationships, stereotypes, notes, JSON tables, class and style support, accessibility metadata, and business variants. - [#8073](mermaid-js/mermaid#8073) [`cd48a64`](mermaid-js/mermaid@cd48a64) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat: `defaultMeasureLayout` accepts a `unwrapGroupLabels` option so a layout engine can ask for cluster labels to be measured at their natural width instead of the `flowchart.wrappingWidth` fallback. `insertCluster` paints a plain cluster label with an infinite width while the measurement pass wrapped it at 200px, so a layout that sizes compound nodes from the measured label sized them too narrow. Layouts now opt in explicitly; core no longer inspects the layout's name. Markdown cluster labels stay wrapped, since those are painted wrapped. The bundled ELK layout opts in, which changes the size of labelled subgraphs in ELK-laid-out diagrams. Diagrams laid out with dagre are unaffected. - [#8073](mermaid-js/mermaid#8073) [`0cf3797`](mermaid-js/mermaid@0cf3797) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat: let a container pick its own ELK algorithm with `@{ algorithm: … }`, and add `elk.box` and `elk.rectpacking` to the selectable `layout` values. A subgraph carrying `@{ algorithm: elk.box }` is laid out with that algorithm in its own coordinate system instead of inheriting the diagram's. Supported values are `elk.layered`, `elk.box`, `elk.rectpacking`, `elk.stress`, `elk.force`, `elk.mrtree`, `elk.radial`, and `elk.sporeOverlap`; anything else is ignored with a warning rather than handed to ELK, where an unknown id would abort the layout. Containers with edges crossing their boundary fall back to the inherited algorithm, since isolated layout and cross-boundary edges are incompatible. Also in this release: - ELK cluster labels are measured unwrapped, so a compound node is sized to fit its label instead of to a 200px wrapping width. **This changes the size — and therefore the layout — of existing ELK diagrams that have labelled subgraphs.** - `elk.box` and `elk.rectpacking` place nodes but never route edges. Edges they leave unrouted now fall back to a straight line between the two node centres instead of failing the render. - `keepEntryNodeOnTop` pins a cycle's true entry rather than the first-declared node when a back-edge feeds the entry, so recursive flows read from where they actually start. - [#8193](mermaid-js/mermaid#8193) [`813c766`](mermaid-js/mermaid@813c766) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - **`theme`, `look` and `layout` can now be set per diagram type**, in each diagram's config section — `mermaid.initialize({ look: 'classic', flowchart: { look: 'handDrawn' } })`, or the same under `config` in front matter. The schema uses the same mechanism to give a diagram type its own default. Resolution, highest first: front matter or directive, `initialize()`, the diagram type's default, the global default; a diagram-scoped value beats a global one set in the same layer. Swimlanes take `layout: swimlane` from that schema default instead of having it forced by their `init` hook, so `swimlane: { layout: ... }` and a `layout` in front matter are now honoured. An unregistered layout also always falls back to `dagre` with a warning rather than throwing — state diagrams skipped that fallback, and mindmaps threw when `cose-bilkent` was absent, as it is in `@mermaid-js/tiny`. - [#8147](mermaid-js/mermaid#8147) [`43d9fbc`](mermaid-js/mermaid@43d9fbc) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat(themes): class boxes and flowchart subgraph containers now take a per-item colour under the `redux-color` and `redux-dark-color` themes, cycling every 12 as ER entities already do. Collapsed subgraphs keep the slot they would have had expanded; nodes inside a subgraph stay uniform, and explicit `classDef` or `style` still wins over the palette. - [#8191](mermaid-js/mermaid#8191) [`2878cf3`](mermaid-js/mermaid@2878cf3) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat(themes): composite states now take a per-container colour under the `redux-color` and `redux-dark-color` themes, as flowchart subgraphs already do. Each composite gets the palette's border colour on its outline and its background tint behind the title strip; nested composites each take the next colour, so depth stays readable. The body keeps the theme's own `compositeBackground`. `redux-dark-color` colours the outlines only, matching how it treats ER, requirement and sequence. The concurrency regions produced by a `--` divider share the colour of the composite they split, rather than taking one of their own — the author wrote a single composite, so it is drawn as one thing in parts. Adding a `--` therefore leaves every other composite's colour untouched. Under the `handDrawn` look, concurrency regions are now filled solid rather than hatched, so that they can carry the palette tint the same way every other look does. States inside a composite stay uniform. A composite carrying its own `classDef` or `style` keeps those colours and takes no palette slot, and neither do its concurrency regions; the slot is still spent, so styling one composite does not shift the colours of the ones after it. Note that this opt-out is all-or-nothing: a `classDef` that sets only text properties, such as `font-weight`, still takes that composite out of the palette. - [#8176](mermaid-js/mermaid#8176) [`16b9a7d`](mermaid-js/mermaid@16b9a7d) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat(themes): swimlane lanes take a per-lane colour under the `redux-color` and `redux-dark-color` themes, cycling every 12 as flowchart subgraphs do. The lane holding ungrouped nodes takes its own slot and now follows the diagram's `look`. - [#8178](mermaid-js/mermaid#8178) [`75e6c30`](mermaid-js/mermaid@75e6c30) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat(usecase): use case diagrams now take colour by role — actors, use cases and system boundaries each get their own colour from the new `usecaseActorBkg`/`usecaseActorBorder`, `usecaseBkg`/`usecaseBorder` and `usecaseBoundaryBkg`/`usecaseBoundaryBorder` theme variables, with `usecaseIncludeLine`/`usecaseExtendLine` separating the two dashed relationship kinds by hue. `redux-color` and `redux-dark-color` set them; every other theme is unchanged. Colour is keyed to the kind of element, so editing a diagram never recolours the elements around the edit. Set `usecase.colorScheme: 'rotate'` for the per-element palette cycle instead, and `classDef`/`style` still wins over both. ### Patch Changes - [#8211](mermaid-js/mermaid#8211) [`dc2e453`](mermaid-js/mermaid@dc2e453) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(block): restore node borders under looks that use a gradient stroke. A block diagram rendered with `look: neo` lost its node borders entirely. The look-specific rules set `stroke: url(#<svgId>-gradient)`, and those definitions were appended by `rendering-util/render.ts` — which block does not use, since it runs its own render loop. An `url(#…)` paint that resolves to nothing is painted as **none**, not as a fallback colour, so the border disappeared rather than degrading to a plain stroke. The definitions now live in `rendering-util/insertLookDefs.ts` and both render paths call it, so the two cannot drift into producing different gradients. This only became visible recently: block did not previously pass `look` to its nodes, so none of the look-specific rules applied to it and the missing definitions went unnoticed. - [#8181](mermaid-js/mermaid#8181) [`ce0302d`](mermaid-js/mermaid@ce0302d) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(block): apply the redux colour palette to composite blocks. Composites now take a per-container colour under `redux-color` and `redux-dark-color`, matching how flowchart subgraphs are coloured — one counter over containers, in declaration order, with the plain shapes left on the flat theme colour. The palette is opt-in: block does not default to `redux-color` the way flowchart and several other diagram types do, so set `theme: redux-color` (or `redux-dark-color`) explicitly to see it. `classDef`/`style` still win. - [#8211](mermaid-js/mermaid#8211) [`ad98070`](mermaid-js/mermaid@ad98070) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(block): take the node border width from the theme, as every other diagram does. `block/styles.ts` pinned `stroke-width: 1px` on node shapes while the flowchart, class and state stylesheets all read `strokeWidth` from the theme. Under a theme that asks for more — `neo` asks for 2 — a block rendered a visibly thinner border than an identical flowchart node, and nothing downstream corrected it: the `neo` rules in the shared stylesheet set `stroke` and `filter`, never `stroke-width`. The gap was invisible until block began propagating `look` to its nodes, because until then none of the look-specific rules applied to block at all. Affects only themes whose `strokeWidth` is not 1. `neo` is 2; `neo-dark`, `base` and the rest are unchanged. - [#8231](mermaid-js/mermaid#8231) [`e2aab3f`](mermaid-js/mermaid@e2aab3f) Thanks [@knsv-bot](https://github.com/knsv-bot)! - Use balanced Brandes-Koepf placement for the default ELK preset to improve alignment of branches and composite-state entries. Preserve named non-default presets and explicit placement/alignment options, including `NONE`. Some diagrams may become wider or taller; `depthFirst` retains the previous default layout. - [#7874](mermaid-js/mermaid#7874) [`6b79518`](mermaid-js/mermaid@6b79518) Thanks [@filipsajdak](https://github.com/filipsajdak)! - fix(c4): allow boundaries as relationship endpoints A `Rel` (or `BiRel`/`Rel_*`) that referenced a boundary alias threw `references an unknown shape`, because endpoint lookup only searched shapes and not boundaries. Boundary aliases now resolve as relationship endpoints. Fixes #4864. - [#8100](mermaid-js/mermaid#8100) [`30325d4`](mermaid-js/mermaid@30325d4) Thanks [@filipsajdak](https://github.com/filipsajdak)! - fix(c4): stop wrapping non-text named attributes that land in a text slot A named attribute such as `$tags` or `$sprite` can arrive in the positional slot of a text field when the argument before it is omitted. It was then stored as `{ text: value }` rather than a string, so `$tags` given without a description crashed rendering. - [#8148](mermaid-js/mermaid#8148) [`c3ee3c7`](mermaid-js/mermaid@c3ee3c7) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(themes): `redux-dark`, `redux-dark-color` and `neo-dark` shipped `secondBkg` as the literal string `calculated`, so railroad rendered the invalid `fill: calculated`; it is now computed as `theme-dark` does. The same three themes had gantt done-task labels at 1.07:1 contrast — a light fill under their light task ink — now 5.7:1 or better. The ER and requirement stylesheets also validate `look` before interpolating it into a CSS selector. - [#8222](mermaid-js/mermaid#8222) [`1ee934d`](mermaid-js/mermaid@1ee934d) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: stop ELK-laid-out diagrams logging `Unknown arrow type: arrow_open` once per edge. ELK's arrow table put the edge _type_ `arrow_open` — which means "no arrowheads" — into the arrow-type slot, where `none` is the value that marks a deliberate absence. Anything else is reported as an unknown marker name. Diagrams whose db sets `arrowTypeStart` itself, such as flowcharts, never reached that fallback; state diagrams, which leave it unset, warned on every edge. Rendering is unchanged: both spellings produced no start marker and the same geometry, since neither has a marker offset. Only the log noise goes away. - [#8204](mermaid-js/mermaid#8204) [`a7831c5`](mermaid-js/mermaid@a7831c5) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: keep ELK subgraph frames out to the border anchor of edges that terminate on the group, so transitions to composite states no longer run along the cluster border - [#8155](mermaid-js/mermaid#8155) [`0320406`](mermaid-js/mermaid@0320406) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(elk): a composite state or subgraph containing a loop now opens on its own start node. Cycle breaking was resolved for the root graph but never passed to containers, so a container laid out on its own fell back to ELK's default, `GREEDY`, while the root ran whatever `elk.preset` asked for. The two then reversed different edges of the same cycle. In a composite state that loops, greedy reverses the edge that turns an ordinary state into a source, and sources sit on the first layer — so the diagram opened on that state alongside its start circle instead of on the start circle alone. Dagre reverses the other edge, which is why the two layout engines disagreed on the same diagram. Containers now resolve cycle breaking from the preset exactly as the root does. Only containers that actually contain a cycle change; an acyclic subgraph gives a cycle-breaking strategy nothing to do. `preset: legacy` still reaches containers with `GREEDY`, so it keeps reproducing the earlier rendering inside frames as well as outside them. - [#8228](mermaid-js/mermaid#8228) [`e36b883`](mermaid-js/mermaid@e36b883) Thanks [@knsv-bot](https://github.com/knsv-bot)! - Reserve subgraph title padding before ELK routes edges so attachments stay on the painted frame. Clip stale interior endpoints along the incoming segment, avoiding edges that run along the subgraph border. - [#8199](mermaid-js/mermaid#8199) [`b993915`](mermaid-js/mermaid@b993915) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: keep ELK edges vertical at small nodes — the node now moves onto the routed line instead of the edge bending toward the node's off-centre position - [#8155](mermaid-js/mermaid#8155) [`4e00c5c`](mermaid-js/mermaid@4e00c5c) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: render ER relationship edges above subgraph backgrounds under the ELK layout instead of hiding them behind the cluster rect - [#8156](mermaid-js/mermaid#8156) [`3f05015`](mermaid-js/mermaid@3f05015) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(er, requirement, timeline): stop the ER, requirement and timeline stylesheets emitting CSS the browser discards for the colour themes. All three generate one rule per palette slot. ER and requirement looped to `THEME_COLOR_LIMIT` and indexed the palette by the loop counter, which goes wrong in both directions: a palette shorter than the limit emitted `stroke: undefined` for the overflow slots, and a palette _longer_ than it left entities stamped with a slot that had no rule at all, rendering unstyled beside coloured neighbours. Both now take the loop bound from the palette itself, which is the same length the boxes stamp with — so the rules emitted and the slots stamped cannot disagree. Both also bail before the loop for an empty palette, since wrapping alone is not enough there: `i % 0` is `NaN` and `[][NaN]` is `undefined`. Timeline keeps looping to `THEME_COLOR_LIMIT` and wrapping, because it numbers `.section-N` classes rather than palette slots — nothing stamps those, so the palette cycles across however many sections exist. `requirement` also emitted `fill: ;` — a property with no value, which is invalid — whenever there was no background palette. That is the live case for `redux-dark-color`, which ships a border palette and no background palette so that it colours outlines only. The declaration is now omitted instead. None of these raises an error: the browser discards the invalid declaration, so the only symptom is a shape rendering unstyled. - [#8149](mermaid-js/mermaid#8149) [`d57ed55`](mermaid-js/mermaid@d57ed55) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(docs): stop `docs:build` deleting the committed `docs/` directory when a later step fails. - [#7906](mermaid-js/mermaid#7906) [`1fc5bb3`](mermaid-js/mermaid@1fc5bb3) Thanks [@knsv-bot](https://github.com/knsv-bot)! - perf: avoid quadratic parse cost on deeply-indented diagrams (~1.4 s → ~30 ms on a pathological fixture) - [#8211](mermaid-js/mermaid#8211) [`b979eb4`](mermaid-js/mermaid@b979eb4) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(handdrawn): tighten the hachure fill so shapes read as filled rather than striped. The hand-drawn fill drew 4px-wide strokes 5.2px apart, which left visible diagonal banding across every shape — legible as a texture up close, but at normal diagram size it read as stripes rather than a fill. Strokes are now 1.5px at 1.5px spacing, so the fill reads as an even tint while keeping the drawn edge quality. The striped fill behind state-diagram start, end and fork markers moves the same way, so those come out close to solid — which is what the UML convention asks for anyway. Swimlane lane titles previously pinned their own stroke weight and so ignored the shared value; they now follow it like every other shape. - [#8152](mermaid-js/mermaid#8152) [`7ee4c3f`](mermaid-js/mermaid@7ee4c3f) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: edges attach to non-rectangular shapes on the outline instead of half a pixel off it. **This is not ELK-specific.** `intersectPolygon` is how every non-rectangular shape finds its edge attachment — diamond, stadium, hexagon, trapezoid, subroutine — in every layout, so a dagre-rendered flowchart with a decision diamond is affected exactly as much as an ELK one. `intersectLine` comes from Graphics Gems, where the coordinates were integers and the numerator was nudged half a denominator away from zero so the integer division rounded instead of truncating. JavaScript division does neither, so the nudge stopped being a correction and became the whole error: every result came back displaced by `0.5 * sign(num) * sign(denom)`. The magnitude is always exactly half a unit, but the sign is per axis, because the numerator is computed separately for x and y while the denominator is shared — so the two axes could move the same way or opposite ways depending on the geometry, which is why it never looked like a constant offset anyone could spot by eye. That was enough to give an otherwise orthogonal edge a tiny diagonal opening segment, and to put an attachment just inside the node it was meant to touch. `question.ts` had been subtracting a flat 0.5 from both axes to compensate for diamonds. That only cancelled the bias when both signs came out positive, and doubled the error to a full unit when they did not — so the compensation goes along with the cause. **Rendered output moves by up to a pixel wherever a polygon shape terminates an edge.** - [#8048](mermaid-js/mermaid#8048) [`a6ec7ff`](mermaid-js/mermaid@a6ec7ff) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: treat `</br>` as a line break in labels `lineBreakRegex` only matched `<br>`, `<br/>` and `<br />`, so the malformed-but-common `</br>` survived as literal text wherever labels render as plain SVG text. HTML parsers already treat `</br>` as a `<br>`, so the tag appeared to work in HTML-label mode and failed everywhere else. It is now accepted on both paths. Also fixes `hasBreaks()` returning alternating results for the same input: it called `.test()` on a global regex, which advances `lastIndex` between calls. `wrapLabel()` used the same stateful check and could therefore re-wrap labels that already contained breaks. - [#8152](mermaid-js/mermaid#8152) [`1246a55`](mermaid-js/mermaid@1246a55) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: don't draw a line hop that has no room next to a bend. A crossing close to a corner used to get a hop squeezed into whatever space was left — as little as 2.9px against a requested 6px, opening exactly on the corner's tangent point. At that size the arc no longer clears the line it is meant to hop, so the two strokes still touch and the corner's curve runs straight into the arc's. It reads as a rendering fault rather than as a crossing. Hops now keep a straight run clear of the bend, and one that would still have to shrink below 60% of the requested radius is dropped instead of drawn. An undrawn hop is an ordinary crossing, which is a much better failure than a broken-looking one. **This changes swimlane diagrams as well as ELK ones.** Swimlanes are the existing consumer of line hops and have them on today, so a swimlane with a crossing near a bend will render differently even for someone not using ELK at all. It shows up wherever a layout stacks edges in narrow lanes: ELK routes subgraph-internal edges 10px apart, and 10px does not hold a 7.07px corner cut plus a 6px hop. A crossing is also ignored now when it lands inside the stretch where either edge is rounding a bend. Crossings are found on polylines, but a rounded edge is not drawn as its polyline — it leaves the line up to 7.07px before each bend and rejoins it that far after. A crossing found inside that stretch is somewhere the stroke never goes, so the hop was arching over blank paper while the two lines carried on touching beside it. - [#8146](mermaid-js/mermaid#8146) [`def4c81`](mermaid-js/mermaid@def4c81) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(themes): `redux-color` and `redux-dark-color` now define every variable their base themes define, instead of silently falling back to untuned values for `primaryBorderColor`, `clusterBkg`, `clusterBorder`, `altBackground`, `compositeTitleBackground` and the state and requirement edge-label backgrounds. Pie, gantt and user-journey also read the theme palette rather than a single pale tint, so pie slices are distinguishable and gantt sections are visibly banded. - [#8189](mermaid-js/mermaid#8189) [`3802472`](mermaid-js/mermaid@3802472) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(themes): venn circles follow the `redux-color` and `redux-dark-color` palettes. Neither theme defined any `venn*` variable, so every circle rendered in one flat colour. - [#8185](mermaid-js/mermaid#8185) [`f5af413`](mermaid-js/mermaid@f5af413) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: sequence diagram actors under the `neo` look and `redux` themes. Notes no longer render bold, a `rect` section band is no longer drawn white on white, and participants follow one vertical model: every lifeline starts and ends on a shared line, all participant glyphs are one size with their feet on a common edge, single-line labels share one baseline in the header and in the mirrored footer, and a multiline label grows away from the lifeline instead of moving it. The `classic` look is unchanged. - [#8157](mermaid-js/mermaid#8157) [`a3a92ba`](mermaid-js/mermaid@a3a92ba) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(sequence): index each actor colour palette by its own length. Every actor-drawing call site read `bkgColorArray[actorCount % borderColorArray.length]` — one palette indexed by the other's length. Under `redux-color` both palettes have twelve entries, so the wrong length happens to give the right answer and nothing is visibly broken today. It goes wrong as soon as the two differ in length: the overflow actors resolve to `undefined`, and d3 then strips the inline fill for some actors and not others. Both palettes now cycle within their own length, via a shared helper. An absent or empty palette still yields `undefined` rather than a substitute colour, which is what `redux-dark-color` relies on: it ships a border palette and an empty background palette so actors are outlined but not filled. - [#8232](mermaid-js/mermaid#8232) [`e691042`](mermaid-js/mermaid@e691042) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - Circle, double circle, Delay and Display nodes size themselves from the label's height as well as its width, so a wrapped label stays inside the outline. Each was sized from the width alone and clipped any label taller than it was wide, which `flowchart.wrappingWidth: 120` made common. This replaces the wrapping exemption those shapes carried along with stadium and diamond: it stopped them wrapping at all, so a long label produced a single-line node hundreds of pixels wide. Stadium needs no exemption — its `w >= 1.5h` floor already keeps a wrapped label from closing the caps into a circle — and diamond never needed one. Stacked (`docs`) and lined (`lin-doc`) document nodes lift their label clear of the wavy bottom edge by the wave's full depth rather than half of it, so the last line is no longer clipped by the trough. Plain `doc` already did this; the two variants had copied it with the offset halved. Node dimensions are unchanged. - [#8154](mermaid-js/mermaid#8154) [`ba0deed`](mermaid-js/mermaid@ba0deed) Thanks [@aloisklink](https://github.com/aloisklink)! - fix: bundle `fastdom` to fix issues with global `define` - [#8227](mermaid-js/mermaid#8227) [`b05824a`](mermaid-js/mermaid@b05824a) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(flowchart): stop stadium labels from wrapping into a circle and exempt selected shapes from automatic label wrapping. Long stadium labels wrapped to `flowchart.wrappingWidth`, grew taller without growing wider, and turned the stadium into a circle. Stadium now keeps its semicircular caps with an outer width of at least 1.5 times its height and enough clearance that the label stays inside the arcs. Stadium (`terminal`, `pill`), circle (`circ`), diamond (`diam`, `decision`, `question`), double circle (`dbl-circ`, `double-circle`), Display (`curv-trap`, `curved-trapezoid`, `display`) and Delay (`delay`, `half-rounded-rectangle`) no longer wrap their labels at `flowchart.wrappingWidth`. Explicit line breaks are kept, and an explicit node width still takes precedence. - [#8192](mermaid-js/mermaid#8192) [`0ec29e9`](mermaid-js/mermaid@0ec29e9) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(state): draw the edge between a state and its note dashed under the `neo` look. It was rendering solid. The dashes were expressed only as CSS — `.note-edge { stroke-dasharray: 5 }` — which is enough under `classic` but not under `neo`, where `insertEdge` writes an inline `stroke-dasharray` on every edge, computed from the path length so the arrow markers keep their gaps. An inline style outranks a stylesheet rule, so the note edge took the solid pattern and the `.note-edge` rule simply lost. The note edge now declares `pattern: 'dashed'`, which is what `insertEdge` reads to choose its dash generator. `classic` is unchanged. - [#8225](mermaid-js/mermaid#8225) [`0d77926`](mermaid-js/mermaid@0d77926) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(swimlane): seed cycle removal from source nodes so feedback edges are reversed instead of forward flow edges. A cycle like `task --> decision --> fix --> task` no longer places `fix` in the middle of the `start --> task` flow line. - [#8211](mermaid-js/mermaid#8211) [`93edd72`](mermaid-js/mermaid@93edd72) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: keep association markers apart on use-case ovals under ELK. Ovals get the same vertical padding as horizontal, edge attachment points on them are spread across the side, and the ELK renderer now accounts for every end-marker offset (extension, circle, cross, …) so a short entry stub can no longer flip a marker around. - Updated dependencies \[[`33442fd`](mermaid-js/mermaid@33442fd)]: - @mermaid-js/parser@2.0.0 ### Keeping the previous defaults in your integration Mermaid 12 changes what unconfigured diagrams look like: ELK replaces dagre as the default layout, and `redux-color` / `neo` replace `default` / `classic` as theme and look for flowchart, class, state, ER, requirement, sequence, use case, swimlane, Venn and agentflow. If you embed Mermaid and want your users' existing diagrams to render as before, set all three explicitly at initialisation: ```js mermaid.initialize({ layout: 'dagre', theme: 'default', look: 'classic' }); ``` Diagram authors can do the same per diagram in front matter, and a value there always wins over `initialize()`. - [Layouts: how `layout` is resolved, ELK variants, and the tiny build](https://mermaid.ai/open-source/config/layouts.html) - [Flowchart: default theme, look and layout in v12](https://mermaid.ai/open-source/syntax/flowchart.html#default-theme-look-and-layout-v-mermaid-release-version) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: give me a 98K <240642031+inhuman-0@users.noreply.github.com>
Upstream release: https://github.com/mermaid-js/mermaid/releases/tag/mermaid%4012.0.0 Release notes: **Mermaid 12.0.0** ships ELK as the bundled default layout engine, a new `redux-color` / `neo` default appearance, and two new diagram types: [UML use case diagrams](https://mermaid.ai/open-source/syntax/usecase.html). This is a breaking release (ES2024, Safari 17.4+, Node 22.12+). Existing flowcharts, state and class diagrams will re-lay out and recolour; add `layout: dagre`, `theme: default` and `look: classic` to your config to keep the old look. Full changelog below. ### Major Changes - [#8213](mermaid-js/mermaid#8213) [`33442fd`](mermaid-js/mermaid@33442fd) Thanks [@aloisklink](https://github.com/aloisklink)! - chore!: require ES2024, Safari 17.4+, Node.JS v22.12+ Mermaid is now built to target Safari 17.4+ and ES2024. If you need to support older browsers, you may need to polyfill or transpile mermaid. Safari 17.4+ has been chosen as the floor, as unlike Firefox/Chrome, older iOS devices don't get major Safari updates. Node.JS v22.12+ is also declared as requirement in our `package.json` files, but as mermaid requires a browser, this is mainly so we can use dependencies that also declare a Node.JS v22.12+ requirement, without causing issues for users when running `npm install`. - [#8155](mermaid-js/mermaid#8155) [`810893c`](mermaid-js/mermaid@810893c) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat!: **ELK is now bundled with mermaid and is the default layout algorithm.** ELK previously shipped as a separate `@mermaid-js/layout-elk` package that sites had to install and register. It is now part of mermaid itself and registered automatically, so `layout: elk` — and the `elk.stress`, `elk.force`, `elk.mrtree`, `elk.sporeOverlap`, `elk.box` and `elk.rectpacking` variants — work with no setup. **This changes how existing diagrams look.** Flowchart, state, class, entity-relationship, requirement, use-case diagrams that do not specify a `layout` are now laid out by ELK instead of dagre. To keep the previous layout, set dagre explicitly: ```yaml --- config: layout: dagre --- ``` or globally, `mermaid.initialize({ layout: 'dagre' })`. Mindmap is unchanged: it keeps laying out with cose-bilkent unless a layout is explicitly requested (in the tiny build, which ships neither ELK nor cose-bilkent, it falls back to dagre). Other notes: - ELK is loaded as a separate chunk in the ESM builds, so it is only fetched when a diagram actually uses it. The single-file IIFE build (`mermaid.min.js`) inlines it and grows by roughly 500 kB gzipped. - The **tiny** build deliberately omits ELK to stay small, and falls back to dagre for diagrams that ask for an ELK layout. Its size is unchanged. - `@mermaid-js/layout-elk` is no longer needed on normal builds — existing `mermaid.registerLayoutLoaders(elkLayouts)` calls keep working and can be removed. It is still published, and remains the way to add ELK to the tiny build. - `dist/mermaid.esm.min.mjs` now contains syntax that `es-module-lexer` (used by Vite) rejects with `content contains invalid JS syntax`. Bundler users are unaffected as long as they import the `mermaid` package specifier, which resolves to the core build; only builds that point Vite directly at that dist file need to switch to the package specifier or the core build. - State diagrams now resolve their layout through the same registration check as every other diagram, so an unavailable layout falls back instead of failing to render. An unrecognised `theme` name now resolves to the default theme in name as well as in variables; previously the invalid name stayed in place while the default's variables were loaded, and every palette-aware stylesheet gates on the name. `theme: 'null'`, the documented way to disable the pre-defined themes, is unaffected. Note that `neo` paints node strokes with a gradient when the theme sets `useGradient`, which `base` does; setting a custom `nodeBorder` on `base` turns the gradient off. - [#8211](mermaid-js/mermaid#8211) [`a19bd08`](mermaid-js/mermaid@a19bd08) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - **Removed: the `defaultRenderer` option of the `flowchart`, `class` and `state` config sections.** Use the top-level `layout` option instead: ```yaml --- config: layout: dagre # or elk --- ``` ### Why `defaultRenderer` named a rendering engine back when there was more than one. There is not. All of its accepted values — `dagre`, `dagre-wrapper`, `dagre-d3` — had come to select the same unified renderer, and its `elk` value did nothing but set `layout: elk` on your behalf. The option's documented purpose no longer existed. What it still did was stranger than doing nothing. The detectors branched on whether the value was _recognised_, so a **valid** value routed a diagram to the modern renderer and an **invalid** one silently routed it to the legacy renderer. Since the default was always a valid value, the legacy `class` and `state` renderers were unreachable except by misconfiguring the option. ### What changes for you - `layout` selects the layout algorithm, as it already did. Nothing else does. - `graph`, `classDiagram` and `stateDiagram` always render with the unified diagram. This was already true for every valid configuration. - The legacy `flowchart`, `class` and `state` diagram ids are gone. `flowchart-v2`, `classDiagram` and `stateDiagram` are what `detectType` now returns for that syntax. - `flowchart-elk` as an explicit diagram keyword still works. Configuration that still sets `defaultRenderer` is ignored rather than rejected, so nothing throws — but it no longer has any effect, and diagrams that relied on `flowchart: { defaultRenderer: 'elk' }` to get an ELK layout should set `layout: elk`. - [#8223](mermaid-js/mermaid#8223) [`6df1149`](mermaid-js/mermaid@6df1149) Thanks [@aloisklink](https://github.com/aloisklink)! - refactor!: remove layout internal exports Remove the `clearLayoutRenderState`, `createCommonLayoutRenderer`, `defaultMeasureLayout`, `paintLayoutData` functions, and the `CommonLayout*` types from Mermaid's public API. These functions were only used by the `@mermaid-js/layout-elk` package, which now bundles them. Removing them makes it easier to avoid major versions of mermaid. ### Minor Changes - [#8048](mermaid-js/mermaid#8048) [`7a3c1a8`](mermaid-js/mermaid@7a3c1a8) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat: add UML use case diagrams with actors, use cases, system boundaries, relationships, stereotypes, notes, JSON tables, class and style support, accessibility metadata, and business variants. - [#8073](mermaid-js/mermaid#8073) [`cd48a64`](mermaid-js/mermaid@cd48a64) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat: `defaultMeasureLayout` accepts a `unwrapGroupLabels` option so a layout engine can ask for cluster labels to be measured at their natural width instead of the `flowchart.wrappingWidth` fallback. `insertCluster` paints a plain cluster label with an infinite width while the measurement pass wrapped it at 200px, so a layout that sizes compound nodes from the measured label sized them too narrow. Layouts now opt in explicitly; core no longer inspects the layout's name. Markdown cluster labels stay wrapped, since those are painted wrapped. The bundled ELK layout opts in, which changes the size of labelled subgraphs in ELK-laid-out diagrams. Diagrams laid out with dagre are unaffected. - [#8073](mermaid-js/mermaid#8073) [`0cf3797`](mermaid-js/mermaid@0cf3797) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat: let a container pick its own ELK algorithm with `@{ algorithm: … }`, and add `elk.box` and `elk.rectpacking` to the selectable `layout` values. A subgraph carrying `@{ algorithm: elk.box }` is laid out with that algorithm in its own coordinate system instead of inheriting the diagram's. Supported values are `elk.layered`, `elk.box`, `elk.rectpacking`, `elk.stress`, `elk.force`, `elk.mrtree`, `elk.radial`, and `elk.sporeOverlap`; anything else is ignored with a warning rather than handed to ELK, where an unknown id would abort the layout. Containers with edges crossing their boundary fall back to the inherited algorithm, since isolated layout and cross-boundary edges are incompatible. Also in this release: - ELK cluster labels are measured unwrapped, so a compound node is sized to fit its label instead of to a 200px wrapping width. **This changes the size — and therefore the layout — of existing ELK diagrams that have labelled subgraphs.** - `elk.box` and `elk.rectpacking` place nodes but never route edges. Edges they leave unrouted now fall back to a straight line between the two node centres instead of failing the render. - `keepEntryNodeOnTop` pins a cycle's true entry rather than the first-declared node when a back-edge feeds the entry, so recursive flows read from where they actually start. - [#8193](mermaid-js/mermaid#8193) [`813c766`](mermaid-js/mermaid@813c766) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - **`theme`, `look` and `layout` can now be set per diagram type**, in each diagram's config section — `mermaid.initialize({ look: 'classic', flowchart: { look: 'handDrawn' } })`, or the same under `config` in front matter. The schema uses the same mechanism to give a diagram type its own default. Resolution, highest first: front matter or directive, `initialize()`, the diagram type's default, the global default; a diagram-scoped value beats a global one set in the same layer. Swimlanes take `layout: swimlane` from that schema default instead of having it forced by their `init` hook, so `swimlane: { layout: ... }` and a `layout` in front matter are now honoured. An unregistered layout also always falls back to `dagre` with a warning rather than throwing — state diagrams skipped that fallback, and mindmaps threw when `cose-bilkent` was absent, as it is in `@mermaid-js/tiny`. - [#8147](mermaid-js/mermaid#8147) [`43d9fbc`](mermaid-js/mermaid@43d9fbc) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat(themes): class boxes and flowchart subgraph containers now take a per-item colour under the `redux-color` and `redux-dark-color` themes, cycling every 12 as ER entities already do. Collapsed subgraphs keep the slot they would have had expanded; nodes inside a subgraph stay uniform, and explicit `classDef` or `style` still wins over the palette. - [#8191](mermaid-js/mermaid#8191) [`2878cf3`](mermaid-js/mermaid@2878cf3) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat(themes): composite states now take a per-container colour under the `redux-color` and `redux-dark-color` themes, as flowchart subgraphs already do. Each composite gets the palette's border colour on its outline and its background tint behind the title strip; nested composites each take the next colour, so depth stays readable. The body keeps the theme's own `compositeBackground`. `redux-dark-color` colours the outlines only, matching how it treats ER, requirement and sequence. The concurrency regions produced by a `--` divider share the colour of the composite they split, rather than taking one of their own — the author wrote a single composite, so it is drawn as one thing in parts. Adding a `--` therefore leaves every other composite's colour untouched. Under the `handDrawn` look, concurrency regions are now filled solid rather than hatched, so that they can carry the palette tint the same way every other look does. States inside a composite stay uniform. A composite carrying its own `classDef` or `style` keeps those colours and takes no palette slot, and neither do its concurrency regions; the slot is still spent, so styling one composite does not shift the colours of the ones after it. Note that this opt-out is all-or-nothing: a `classDef` that sets only text properties, such as `font-weight`, still takes that composite out of the palette. - [#8176](mermaid-js/mermaid#8176) [`16b9a7d`](mermaid-js/mermaid@16b9a7d) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat(themes): swimlane lanes take a per-lane colour under the `redux-color` and `redux-dark-color` themes, cycling every 12 as flowchart subgraphs do. The lane holding ungrouped nodes takes its own slot and now follows the diagram's `look`. - [#8178](mermaid-js/mermaid#8178) [`75e6c30`](mermaid-js/mermaid@75e6c30) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat(usecase): use case diagrams now take colour by role — actors, use cases and system boundaries each get their own colour from the new `usecaseActorBkg`/`usecaseActorBorder`, `usecaseBkg`/`usecaseBorder` and `usecaseBoundaryBkg`/`usecaseBoundaryBorder` theme variables, with `usecaseIncludeLine`/`usecaseExtendLine` separating the two dashed relationship kinds by hue. `redux-color` and `redux-dark-color` set them; every other theme is unchanged. Colour is keyed to the kind of element, so editing a diagram never recolours the elements around the edit. Set `usecase.colorScheme: 'rotate'` for the per-element palette cycle instead, and `classDef`/`style` still wins over both. ### Patch Changes - [#8211](mermaid-js/mermaid#8211) [`dc2e453`](mermaid-js/mermaid@dc2e453) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(block): restore node borders under looks that use a gradient stroke. A block diagram rendered with `look: neo` lost its node borders entirely. The look-specific rules set `stroke: url(#<svgId>-gradient)`, and those definitions were appended by `rendering-util/render.ts` — which block does not use, since it runs its own render loop. An `url(#…)` paint that resolves to nothing is painted as **none**, not as a fallback colour, so the border disappeared rather than degrading to a plain stroke. The definitions now live in `rendering-util/insertLookDefs.ts` and both render paths call it, so the two cannot drift into producing different gradients. This only became visible recently: block did not previously pass `look` to its nodes, so none of the look-specific rules applied to it and the missing definitions went unnoticed. - [#8181](mermaid-js/mermaid#8181) [`ce0302d`](mermaid-js/mermaid@ce0302d) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(block): apply the redux colour palette to composite blocks. Composites now take a per-container colour under `redux-color` and `redux-dark-color`, matching how flowchart subgraphs are coloured — one counter over containers, in declaration order, with the plain shapes left on the flat theme colour. The palette is opt-in: block does not default to `redux-color` the way flowchart and several other diagram types do, so set `theme: redux-color` (or `redux-dark-color`) explicitly to see it. `classDef`/`style` still win. - [#8211](mermaid-js/mermaid#8211) [`ad98070`](mermaid-js/mermaid@ad98070) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(block): take the node border width from the theme, as every other diagram does. `block/styles.ts` pinned `stroke-width: 1px` on node shapes while the flowchart, class and state stylesheets all read `strokeWidth` from the theme. Under a theme that asks for more — `neo` asks for 2 — a block rendered a visibly thinner border than an identical flowchart node, and nothing downstream corrected it: the `neo` rules in the shared stylesheet set `stroke` and `filter`, never `stroke-width`. The gap was invisible until block began propagating `look` to its nodes, because until then none of the look-specific rules applied to block at all. Affects only themes whose `strokeWidth` is not 1. `neo` is 2; `neo-dark`, `base` and the rest are unchanged. - [#8231](mermaid-js/mermaid#8231) [`e2aab3f`](mermaid-js/mermaid@e2aab3f) Thanks [@knsv-bot](https://github.com/knsv-bot)! - Use balanced Brandes-Koepf placement for the default ELK preset to improve alignment of branches and composite-state entries. Preserve named non-default presets and explicit placement/alignment options, including `NONE`. Some diagrams may become wider or taller; `depthFirst` retains the previous default layout. - [#7874](mermaid-js/mermaid#7874) [`6b79518`](mermaid-js/mermaid@6b79518) Thanks [@filipsajdak](https://github.com/filipsajdak)! - fix(c4): allow boundaries as relationship endpoints A `Rel` (or `BiRel`/`Rel_*`) that referenced a boundary alias threw `references an unknown shape`, because endpoint lookup only searched shapes and not boundaries. Boundary aliases now resolve as relationship endpoints. Fixes #4864. - [#8100](mermaid-js/mermaid#8100) [`30325d4`](mermaid-js/mermaid@30325d4) Thanks [@filipsajdak](https://github.com/filipsajdak)! - fix(c4): stop wrapping non-text named attributes that land in a text slot A named attribute such as `$tags` or `$sprite` can arrive in the positional slot of a text field when the argument before it is omitted. It was then stored as `{ text: value }` rather than a string, so `$tags` given without a description crashed rendering. - [#8148](mermaid-js/mermaid#8148) [`c3ee3c7`](mermaid-js/mermaid@c3ee3c7) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(themes): `redux-dark`, `redux-dark-color` and `neo-dark` shipped `secondBkg` as the literal string `calculated`, so railroad rendered the invalid `fill: calculated`; it is now computed as `theme-dark` does. The same three themes had gantt done-task labels at 1.07:1 contrast — a light fill under their light task ink — now 5.7:1 or better. The ER and requirement stylesheets also validate `look` before interpolating it into a CSS selector. - [#8222](mermaid-js/mermaid#8222) [`1ee934d`](mermaid-js/mermaid@1ee934d) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: stop ELK-laid-out diagrams logging `Unknown arrow type: arrow_open` once per edge. ELK's arrow table put the edge _type_ `arrow_open` — which means "no arrowheads" — into the arrow-type slot, where `none` is the value that marks a deliberate absence. Anything else is reported as an unknown marker name. Diagrams whose db sets `arrowTypeStart` itself, such as flowcharts, never reached that fallback; state diagrams, which leave it unset, warned on every edge. Rendering is unchanged: both spellings produced no start marker and the same geometry, since neither has a marker offset. Only the log noise goes away. - [#8204](mermaid-js/mermaid#8204) [`a7831c5`](mermaid-js/mermaid@a7831c5) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: keep ELK subgraph frames out to the border anchor of edges that terminate on the group, so transitions to composite states no longer run along the cluster border - [#8155](mermaid-js/mermaid#8155) [`0320406`](mermaid-js/mermaid@0320406) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(elk): a composite state or subgraph containing a loop now opens on its own start node. Cycle breaking was resolved for the root graph but never passed to containers, so a container laid out on its own fell back to ELK's default, `GREEDY`, while the root ran whatever `elk.preset` asked for. The two then reversed different edges of the same cycle. In a composite state that loops, greedy reverses the edge that turns an ordinary state into a source, and sources sit on the first layer — so the diagram opened on that state alongside its start circle instead of on the start circle alone. Dagre reverses the other edge, which is why the two layout engines disagreed on the same diagram. Containers now resolve cycle breaking from the preset exactly as the root does. Only containers that actually contain a cycle change; an acyclic subgraph gives a cycle-breaking strategy nothing to do. `preset: legacy` still reaches containers with `GREEDY`, so it keeps reproducing the earlier rendering inside frames as well as outside them. - [#8228](mermaid-js/mermaid#8228) [`e36b883`](mermaid-js/mermaid@e36b883) Thanks [@knsv-bot](https://github.com/knsv-bot)! - Reserve subgraph title padding before ELK routes edges so attachments stay on the painted frame. Clip stale interior endpoints along the incoming segment, avoiding edges that run along the subgraph border. - [#8199](mermaid-js/mermaid#8199) [`b993915`](mermaid-js/mermaid@b993915) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: keep ELK edges vertical at small nodes — the node now moves onto the routed line instead of the edge bending toward the node's off-centre position - [#8155](mermaid-js/mermaid#8155) [`4e00c5c`](mermaid-js/mermaid@4e00c5c) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: render ER relationship edges above subgraph backgrounds under the ELK layout instead of hiding them behind the cluster rect - [#8156](mermaid-js/mermaid#8156) [`3f05015`](mermaid-js/mermaid@3f05015) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(er, requirement, timeline): stop the ER, requirement and timeline stylesheets emitting CSS the browser discards for the colour themes. All three generate one rule per palette slot. ER and requirement looped to `THEME_COLOR_LIMIT` and indexed the palette by the loop counter, which goes wrong in both directions: a palette shorter than the limit emitted `stroke: undefined` for the overflow slots, and a palette _longer_ than it left entities stamped with a slot that had no rule at all, rendering unstyled beside coloured neighbours. Both now take the loop bound from the palette itself, which is the same length the boxes stamp with — so the rules emitted and the slots stamped cannot disagree. Both also bail before the loop for an empty palette, since wrapping alone is not enough there: `i % 0` is `NaN` and `[][NaN]` is `undefined`. Timeline keeps looping to `THEME_COLOR_LIMIT` and wrapping, because it numbers `.section-N` classes rather than palette slots — nothing stamps those, so the palette cycles across however many sections exist. `requirement` also emitted `fill: ;` — a property with no value, which is invalid — whenever there was no background palette. That is the live case for `redux-dark-color`, which ships a border palette and no background palette so that it colours outlines only. The declaration is now omitted instead. None of these raises an error: the browser discards the invalid declaration, so the only symptom is a shape rendering unstyled. - [#8149](mermaid-js/mermaid#8149) [`d57ed55`](mermaid-js/mermaid@d57ed55) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(docs): stop `docs:build` deleting the committed `docs/` directory when a later step fails. - [#7906](mermaid-js/mermaid#7906) [`1fc5bb3`](mermaid-js/mermaid@1fc5bb3) Thanks [@knsv-bot](https://github.com/knsv-bot)! - perf: avoid quadratic parse cost on deeply-indented diagrams (~1.4 s → ~30 ms on a pathological fixture) - [#8211](mermaid-js/mermaid#8211) [`b979eb4`](mermaid-js/mermaid@b979eb4) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(handdrawn): tighten the hachure fill so shapes read as filled rather than striped. The hand-drawn fill drew 4px-wide strokes 5.2px apart, which left visible diagonal banding across every shape — legible as a texture up close, but at normal diagram size it read as stripes rather than a fill. Strokes are now 1.5px at 1.5px spacing, so the fill reads as an even tint while keeping the drawn edge quality. The striped fill behind state-diagram start, end and fork markers moves the same way, so those come out close to solid — which is what the UML convention asks for anyway. Swimlane lane titles previously pinned their own stroke weight and so ignored the shared value; they now follow it like every other shape. - [#8152](mermaid-js/mermaid#8152) [`7ee4c3f`](mermaid-js/mermaid@7ee4c3f) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: edges attach to non-rectangular shapes on the outline instead of half a pixel off it. **This is not ELK-specific.** `intersectPolygon` is how every non-rectangular shape finds its edge attachment — diamond, stadium, hexagon, trapezoid, subroutine — in every layout, so a dagre-rendered flowchart with a decision diamond is affected exactly as much as an ELK one. `intersectLine` comes from Graphics Gems, where the coordinates were integers and the numerator was nudged half a denominator away from zero so the integer division rounded instead of truncating. JavaScript division does neither, so the nudge stopped being a correction and became the whole error: every result came back displaced by `0.5 * sign(num) * sign(denom)`. The magnitude is always exactly half a unit, but the sign is per axis, because the numerator is computed separately for x and y while the denominator is shared — so the two axes could move the same way or opposite ways depending on the geometry, which is why it never looked like a constant offset anyone could spot by eye. That was enough to give an otherwise orthogonal edge a tiny diagonal opening segment, and to put an attachment just inside the node it was meant to touch. `question.ts` had been subtracting a flat 0.5 from both axes to compensate for diamonds. That only cancelled the bias when both signs came out positive, and doubled the error to a full unit when they did not — so the compensation goes along with the cause. **Rendered output moves by up to a pixel wherever a polygon shape terminates an edge.** - [#8048](mermaid-js/mermaid#8048) [`a6ec7ff`](mermaid-js/mermaid@a6ec7ff) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: treat `</br>` as a line break in labels `lineBreakRegex` only matched `<br>`, `<br/>` and `<br />`, so the malformed-but-common `</br>` survived as literal text wherever labels render as plain SVG text. HTML parsers already treat `</br>` as a `<br>`, so the tag appeared to work in HTML-label mode and failed everywhere else. It is now accepted on both paths. Also fixes `hasBreaks()` returning alternating results for the same input: it called `.test()` on a global regex, which advances `lastIndex` between calls. `wrapLabel()` used the same stateful check and could therefore re-wrap labels that already contained breaks. - [#8152](mermaid-js/mermaid#8152) [`1246a55`](mermaid-js/mermaid@1246a55) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: don't draw a line hop that has no room next to a bend. A crossing close to a corner used to get a hop squeezed into whatever space was left — as little as 2.9px against a requested 6px, opening exactly on the corner's tangent point. At that size the arc no longer clears the line it is meant to hop, so the two strokes still touch and the corner's curve runs straight into the arc's. It reads as a rendering fault rather than as a crossing. Hops now keep a straight run clear of the bend, and one that would still have to shrink below 60% of the requested radius is dropped instead of drawn. An undrawn hop is an ordinary crossing, which is a much better failure than a broken-looking one. **This changes swimlane diagrams as well as ELK ones.** Swimlanes are the existing consumer of line hops and have them on today, so a swimlane with a crossing near a bend will render differently even for someone not using ELK at all. It shows up wherever a layout stacks edges in narrow lanes: ELK routes subgraph-internal edges 10px apart, and 10px does not hold a 7.07px corner cut plus a 6px hop. A crossing is also ignored now when it lands inside the stretch where either edge is rounding a bend. Crossings are found on polylines, but a rounded edge is not drawn as its polyline — it leaves the line up to 7.07px before each bend and rejoins it that far after. A crossing found inside that stretch is somewhere the stroke never goes, so the hop was arching over blank paper while the two lines carried on touching beside it. - [#8146](mermaid-js/mermaid#8146) [`def4c81`](mermaid-js/mermaid@def4c81) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(themes): `redux-color` and `redux-dark-color` now define every variable their base themes define, instead of silently falling back to untuned values for `primaryBorderColor`, `clusterBkg`, `clusterBorder`, `altBackground`, `compositeTitleBackground` and the state and requirement edge-label backgrounds. Pie, gantt and user-journey also read the theme palette rather than a single pale tint, so pie slices are distinguishable and gantt sections are visibly banded. - [#8189](mermaid-js/mermaid#8189) [`3802472`](mermaid-js/mermaid@3802472) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(themes): venn circles follow the `redux-color` and `redux-dark-color` palettes. Neither theme defined any `venn*` variable, so every circle rendered in one flat colour. - [#8185](mermaid-js/mermaid#8185) [`f5af413`](mermaid-js/mermaid@f5af413) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: sequence diagram actors under the `neo` look and `redux` themes. Notes no longer render bold, a `rect` section band is no longer drawn white on white, and participants follow one vertical model: every lifeline starts and ends on a shared line, all participant glyphs are one size with their feet on a common edge, single-line labels share one baseline in the header and in the mirrored footer, and a multiline label grows away from the lifeline instead of moving it. The `classic` look is unchanged. - [#8157](mermaid-js/mermaid#8157) [`a3a92ba`](mermaid-js/mermaid@a3a92ba) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(sequence): index each actor colour palette by its own length. Every actor-drawing call site read `bkgColorArray[actorCount % borderColorArray.length]` — one palette indexed by the other's length. Under `redux-color` both palettes have twelve entries, so the wrong length happens to give the right answer and nothing is visibly broken today. It goes wrong as soon as the two differ in length: the overflow actors resolve to `undefined`, and d3 then strips the inline fill for some actors and not others. Both palettes now cycle within their own length, via a shared helper. An absent or empty palette still yields `undefined` rather than a substitute colour, which is what `redux-dark-color` relies on: it ships a border palette and an empty background palette so actors are outlined but not filled. - [#8232](mermaid-js/mermaid#8232) [`e691042`](mermaid-js/mermaid@e691042) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - Circle, double circle, Delay and Display nodes size themselves from the label's height as well as its width, so a wrapped label stays inside the outline. Each was sized from the width alone and clipped any label taller than it was wide, which `flowchart.wrappingWidth: 120` made common. This replaces the wrapping exemption those shapes carried along with stadium and diamond: it stopped them wrapping at all, so a long label produced a single-line node hundreds of pixels wide. Stadium needs no exemption — its `w >= 1.5h` floor already keeps a wrapped label from closing the caps into a circle — and diamond never needed one. Stacked (`docs`) and lined (`lin-doc`) document nodes lift their label clear of the wavy bottom edge by the wave's full depth rather than half of it, so the last line is no longer clipped by the trough. Plain `doc` already did this; the two variants had copied it with the offset halved. Node dimensions are unchanged. - [#8154](mermaid-js/mermaid#8154) [`ba0deed`](mermaid-js/mermaid@ba0deed) Thanks [@aloisklink](https://github.com/aloisklink)! - fix: bundle `fastdom` to fix issues with global `define` - [#8227](mermaid-js/mermaid#8227) [`b05824a`](mermaid-js/mermaid@b05824a) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(flowchart): stop stadium labels from wrapping into a circle and exempt selected shapes from automatic label wrapping. Long stadium labels wrapped to `flowchart.wrappingWidth`, grew taller without growing wider, and turned the stadium into a circle. Stadium now keeps its semicircular caps with an outer width of at least 1.5 times its height and enough clearance that the label stays inside the arcs. Stadium (`terminal`, `pill`), circle (`circ`), diamond (`diam`, `decision`, `question`), double circle (`dbl-circ`, `double-circle`), Display (`curv-trap`, `curved-trapezoid`, `display`) and Delay (`delay`, `half-rounded-rectangle`) no longer wrap their labels at `flowchart.wrappingWidth`. Explicit line breaks are kept, and an explicit node width still takes precedence. - [#8192](mermaid-js/mermaid#8192) [`0ec29e9`](mermaid-js/mermaid@0ec29e9) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(state): draw the edge between a state and its note dashed under the `neo` look. It was rendering solid. The dashes were expressed only as CSS — `.note-edge { stroke-dasharray: 5 }` — which is enough under `classic` but not under `neo`, where `insertEdge` writes an inline `stroke-dasharray` on every edge, computed from the path length so the arrow markers keep their gaps. An inline style outranks a stylesheet rule, so the note edge took the solid pattern and the `.note-edge` rule simply lost. The note edge now declares `pattern: 'dashed'`, which is what `insertEdge` reads to choose its dash generator. `classic` is unchanged. - [#8225](mermaid-js/mermaid#8225) [`0d77926`](mermaid-js/mermaid@0d77926) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(swimlane): seed cycle removal from source nodes so feedback edges are reversed instead of forward flow edges. A cycle like `task --> decision --> fix --> task` no longer places `fix` in the middle of the `start --> task` flow line. - [#8211](mermaid-js/mermaid#8211) [`93edd72`](mermaid-js/mermaid@93edd72) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: keep association markers apart on use-case ovals under ELK. Ovals get the same vertical padding as horizontal, edge attachment points on them are spread across the side, and the ELK renderer now accounts for every end-marker offset (extension, circle, cross, …) so a short entry stub can no longer flip a marker around. - Updated dependencies \[[`33442fd`](mermaid-js/mermaid@33442fd)]: - @mermaid-js/parser@2.0.0 ### Keeping the previous defaults in your integration Mermaid 12 changes what unconfigured diagrams look like: ELK replaces dagre as the default layout, and `redux-color` / `neo` replace `default` / `classic` as theme and look for flowchart, class, state, ER, requirement, sequence, use case, swimlane, Venn and agentflow. If you embed Mermaid and want your users' existing diagrams to render as before, set all three explicitly at initialisation: ```js mermaid.initialize({ layout: 'dagre', theme: 'default', look: 'classic' }); ``` Diagram authors can do the same per diagram in front matter, and a value there always wins over `initialize()`. - [Layouts: how `layout` is resolved, ELK variants, and the tiny build](https://mermaid.ai/open-source/config/layouts.html) - [Flowchart: default theme, look and layout in v12](https://mermaid.ai/open-source/syntax/flowchart.html#default-theme-look-and-layout-v-mermaid-release-version) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: give me a 98K <240642031+inhuman-0@users.noreply.github.com>
* chore: sync Mermaid runtime to 12.0.0 Upstream release: https://github.com/mermaid-js/mermaid/releases/tag/mermaid%4012.0.0 Release notes: **Mermaid 12.0.0** ships ELK as the bundled default layout engine, a new `redux-color` / `neo` default appearance, and two new diagram types: [UML use case diagrams](https://mermaid.ai/open-source/syntax/usecase.html). This is a breaking release (ES2024, Safari 17.4+, Node 22.12+). Existing flowcharts, state and class diagrams will re-lay out and recolour; add `layout: dagre`, `theme: default` and `look: classic` to your config to keep the old look. Full changelog below. ### Major Changes - [#8213](mermaid-js/mermaid#8213) [`33442fd`](mermaid-js/mermaid@33442fd) Thanks [@aloisklink](https://github.com/aloisklink)! - chore!: require ES2024, Safari 17.4+, Node.JS v22.12+ Mermaid is now built to target Safari 17.4+ and ES2024. If you need to support older browsers, you may need to polyfill or transpile mermaid. Safari 17.4+ has been chosen as the floor, as unlike Firefox/Chrome, older iOS devices don't get major Safari updates. Node.JS v22.12+ is also declared as requirement in our `package.json` files, but as mermaid requires a browser, this is mainly so we can use dependencies that also declare a Node.JS v22.12+ requirement, without causing issues for users when running `npm install`. - [#8155](mermaid-js/mermaid#8155) [`810893c`](mermaid-js/mermaid@810893c) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat!: **ELK is now bundled with mermaid and is the default layout algorithm.** ELK previously shipped as a separate `@mermaid-js/layout-elk` package that sites had to install and register. It is now part of mermaid itself and registered automatically, so `layout: elk` — and the `elk.stress`, `elk.force`, `elk.mrtree`, `elk.sporeOverlap`, `elk.box` and `elk.rectpacking` variants — work with no setup. **This changes how existing diagrams look.** Flowchart, state, class, entity-relationship, requirement, use-case diagrams that do not specify a `layout` are now laid out by ELK instead of dagre. To keep the previous layout, set dagre explicitly: ```yaml --- config: layout: dagre --- ``` or globally, `mermaid.initialize({ layout: 'dagre' })`. Mindmap is unchanged: it keeps laying out with cose-bilkent unless a layout is explicitly requested (in the tiny build, which ships neither ELK nor cose-bilkent, it falls back to dagre). Other notes: - ELK is loaded as a separate chunk in the ESM builds, so it is only fetched when a diagram actually uses it. The single-file IIFE build (`mermaid.min.js`) inlines it and grows by roughly 500 kB gzipped. - The **tiny** build deliberately omits ELK to stay small, and falls back to dagre for diagrams that ask for an ELK layout. Its size is unchanged. - `@mermaid-js/layout-elk` is no longer needed on normal builds — existing `mermaid.registerLayoutLoaders(elkLayouts)` calls keep working and can be removed. It is still published, and remains the way to add ELK to the tiny build. - `dist/mermaid.esm.min.mjs` now contains syntax that `es-module-lexer` (used by Vite) rejects with `content contains invalid JS syntax`. Bundler users are unaffected as long as they import the `mermaid` package specifier, which resolves to the core build; only builds that point Vite directly at that dist file need to switch to the package specifier or the core build. - State diagrams now resolve their layout through the same registration check as every other diagram, so an unavailable layout falls back instead of failing to render. An unrecognised `theme` name now resolves to the default theme in name as well as in variables; previously the invalid name stayed in place while the default's variables were loaded, and every palette-aware stylesheet gates on the name. `theme: 'null'`, the documented way to disable the pre-defined themes, is unaffected. Note that `neo` paints node strokes with a gradient when the theme sets `useGradient`, which `base` does; setting a custom `nodeBorder` on `base` turns the gradient off. - [#8211](mermaid-js/mermaid#8211) [`a19bd08`](mermaid-js/mermaid@a19bd08) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - **Removed: the `defaultRenderer` option of the `flowchart`, `class` and `state` config sections.** Use the top-level `layout` option instead: ```yaml --- config: layout: dagre # or elk --- ``` ### Why `defaultRenderer` named a rendering engine back when there was more than one. There is not. All of its accepted values — `dagre`, `dagre-wrapper`, `dagre-d3` — had come to select the same unified renderer, and its `elk` value did nothing but set `layout: elk` on your behalf. The option's documented purpose no longer existed. What it still did was stranger than doing nothing. The detectors branched on whether the value was _recognised_, so a **valid** value routed a diagram to the modern renderer and an **invalid** one silently routed it to the legacy renderer. Since the default was always a valid value, the legacy `class` and `state` renderers were unreachable except by misconfiguring the option. ### What changes for you - `layout` selects the layout algorithm, as it already did. Nothing else does. - `graph`, `classDiagram` and `stateDiagram` always render with the unified diagram. This was already true for every valid configuration. - The legacy `flowchart`, `class` and `state` diagram ids are gone. `flowchart-v2`, `classDiagram` and `stateDiagram` are what `detectType` now returns for that syntax. - `flowchart-elk` as an explicit diagram keyword still works. Configuration that still sets `defaultRenderer` is ignored rather than rejected, so nothing throws — but it no longer has any effect, and diagrams that relied on `flowchart: { defaultRenderer: 'elk' }` to get an ELK layout should set `layout: elk`. - [#8223](mermaid-js/mermaid#8223) [`6df1149`](mermaid-js/mermaid@6df1149) Thanks [@aloisklink](https://github.com/aloisklink)! - refactor!: remove layout internal exports Remove the `clearLayoutRenderState`, `createCommonLayoutRenderer`, `defaultMeasureLayout`, `paintLayoutData` functions, and the `CommonLayout*` types from Mermaid's public API. These functions were only used by the `@mermaid-js/layout-elk` package, which now bundles them. Removing them makes it easier to avoid major versions of mermaid. ### Minor Changes - [#8048](mermaid-js/mermaid#8048) [`7a3c1a8`](mermaid-js/mermaid@7a3c1a8) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat: add UML use case diagrams with actors, use cases, system boundaries, relationships, stereotypes, notes, JSON tables, class and style support, accessibility metadata, and business variants. - [#8073](mermaid-js/mermaid#8073) [`cd48a64`](mermaid-js/mermaid@cd48a64) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat: `defaultMeasureLayout` accepts a `unwrapGroupLabels` option so a layout engine can ask for cluster labels to be measured at their natural width instead of the `flowchart.wrappingWidth` fallback. `insertCluster` paints a plain cluster label with an infinite width while the measurement pass wrapped it at 200px, so a layout that sizes compound nodes from the measured label sized them too narrow. Layouts now opt in explicitly; core no longer inspects the layout's name. Markdown cluster labels stay wrapped, since those are painted wrapped. The bundled ELK layout opts in, which changes the size of labelled subgraphs in ELK-laid-out diagrams. Diagrams laid out with dagre are unaffected. - [#8073](mermaid-js/mermaid#8073) [`0cf3797`](mermaid-js/mermaid@0cf3797) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat: let a container pick its own ELK algorithm with `@{ algorithm: … }`, and add `elk.box` and `elk.rectpacking` to the selectable `layout` values. A subgraph carrying `@{ algorithm: elk.box }` is laid out with that algorithm in its own coordinate system instead of inheriting the diagram's. Supported values are `elk.layered`, `elk.box`, `elk.rectpacking`, `elk.stress`, `elk.force`, `elk.mrtree`, `elk.radial`, and `elk.sporeOverlap`; anything else is ignored with a warning rather than handed to ELK, where an unknown id would abort the layout. Containers with edges crossing their boundary fall back to the inherited algorithm, since isolated layout and cross-boundary edges are incompatible. Also in this release: - ELK cluster labels are measured unwrapped, so a compound node is sized to fit its label instead of to a 200px wrapping width. **This changes the size — and therefore the layout — of existing ELK diagrams that have labelled subgraphs.** - `elk.box` and `elk.rectpacking` place nodes but never route edges. Edges they leave unrouted now fall back to a straight line between the two node centres instead of failing the render. - `keepEntryNodeOnTop` pins a cycle's true entry rather than the first-declared node when a back-edge feeds the entry, so recursive flows read from where they actually start. - [#8193](mermaid-js/mermaid#8193) [`813c766`](mermaid-js/mermaid@813c766) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - **`theme`, `look` and `layout` can now be set per diagram type**, in each diagram's config section — `mermaid.initialize({ look: 'classic', flowchart: { look: 'handDrawn' } })`, or the same under `config` in front matter. The schema uses the same mechanism to give a diagram type its own default. Resolution, highest first: front matter or directive, `initialize()`, the diagram type's default, the global default; a diagram-scoped value beats a global one set in the same layer. Swimlanes take `layout: swimlane` from that schema default instead of having it forced by their `init` hook, so `swimlane: { layout: ... }` and a `layout` in front matter are now honoured. An unregistered layout also always falls back to `dagre` with a warning rather than throwing — state diagrams skipped that fallback, and mindmaps threw when `cose-bilkent` was absent, as it is in `@mermaid-js/tiny`. - [#8147](mermaid-js/mermaid#8147) [`43d9fbc`](mermaid-js/mermaid@43d9fbc) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat(themes): class boxes and flowchart subgraph containers now take a per-item colour under the `redux-color` and `redux-dark-color` themes, cycling every 12 as ER entities already do. Collapsed subgraphs keep the slot they would have had expanded; nodes inside a subgraph stay uniform, and explicit `classDef` or `style` still wins over the palette. - [#8191](mermaid-js/mermaid#8191) [`2878cf3`](mermaid-js/mermaid@2878cf3) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat(themes): composite states now take a per-container colour under the `redux-color` and `redux-dark-color` themes, as flowchart subgraphs already do. Each composite gets the palette's border colour on its outline and its background tint behind the title strip; nested composites each take the next colour, so depth stays readable. The body keeps the theme's own `compositeBackground`. `redux-dark-color` colours the outlines only, matching how it treats ER, requirement and sequence. The concurrency regions produced by a `--` divider share the colour of the composite they split, rather than taking one of their own — the author wrote a single composite, so it is drawn as one thing in parts. Adding a `--` therefore leaves every other composite's colour untouched. Under the `handDrawn` look, concurrency regions are now filled solid rather than hatched, so that they can carry the palette tint the same way every other look does. States inside a composite stay uniform. A composite carrying its own `classDef` or `style` keeps those colours and takes no palette slot, and neither do its concurrency regions; the slot is still spent, so styling one composite does not shift the colours of the ones after it. Note that this opt-out is all-or-nothing: a `classDef` that sets only text properties, such as `font-weight`, still takes that composite out of the palette. - [#8176](mermaid-js/mermaid#8176) [`16b9a7d`](mermaid-js/mermaid@16b9a7d) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - feat(themes): swimlane lanes take a per-lane colour under the `redux-color` and `redux-dark-color` themes, cycling every 12 as flowchart subgraphs do. The lane holding ungrouped nodes takes its own slot and now follows the diagram's `look`. - [#8178](mermaid-js/mermaid#8178) [`75e6c30`](mermaid-js/mermaid@75e6c30) Thanks [@knsv-bot](https://github.com/knsv-bot)! - feat(usecase): use case diagrams now take colour by role — actors, use cases and system boundaries each get their own colour from the new `usecaseActorBkg`/`usecaseActorBorder`, `usecaseBkg`/`usecaseBorder` and `usecaseBoundaryBkg`/`usecaseBoundaryBorder` theme variables, with `usecaseIncludeLine`/`usecaseExtendLine` separating the two dashed relationship kinds by hue. `redux-color` and `redux-dark-color` set them; every other theme is unchanged. Colour is keyed to the kind of element, so editing a diagram never recolours the elements around the edit. Set `usecase.colorScheme: 'rotate'` for the per-element palette cycle instead, and `classDef`/`style` still wins over both. ### Patch Changes - [#8211](mermaid-js/mermaid#8211) [`dc2e453`](mermaid-js/mermaid@dc2e453) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(block): restore node borders under looks that use a gradient stroke. A block diagram rendered with `look: neo` lost its node borders entirely. The look-specific rules set `stroke: url(#<svgId>-gradient)`, and those definitions were appended by `rendering-util/render.ts` — which block does not use, since it runs its own render loop. An `url(#…)` paint that resolves to nothing is painted as **none**, not as a fallback colour, so the border disappeared rather than degrading to a plain stroke. The definitions now live in `rendering-util/insertLookDefs.ts` and both render paths call it, so the two cannot drift into producing different gradients. This only became visible recently: block did not previously pass `look` to its nodes, so none of the look-specific rules applied to it and the missing definitions went unnoticed. - [#8181](mermaid-js/mermaid#8181) [`ce0302d`](mermaid-js/mermaid@ce0302d) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(block): apply the redux colour palette to composite blocks. Composites now take a per-container colour under `redux-color` and `redux-dark-color`, matching how flowchart subgraphs are coloured — one counter over containers, in declaration order, with the plain shapes left on the flat theme colour. The palette is opt-in: block does not default to `redux-color` the way flowchart and several other diagram types do, so set `theme: redux-color` (or `redux-dark-color`) explicitly to see it. `classDef`/`style` still win. - [#8211](mermaid-js/mermaid#8211) [`ad98070`](mermaid-js/mermaid@ad98070) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(block): take the node border width from the theme, as every other diagram does. `block/styles.ts` pinned `stroke-width: 1px` on node shapes while the flowchart, class and state stylesheets all read `strokeWidth` from the theme. Under a theme that asks for more — `neo` asks for 2 — a block rendered a visibly thinner border than an identical flowchart node, and nothing downstream corrected it: the `neo` rules in the shared stylesheet set `stroke` and `filter`, never `stroke-width`. The gap was invisible until block began propagating `look` to its nodes, because until then none of the look-specific rules applied to block at all. Affects only themes whose `strokeWidth` is not 1. `neo` is 2; `neo-dark`, `base` and the rest are unchanged. - [#8231](mermaid-js/mermaid#8231) [`e2aab3f`](mermaid-js/mermaid@e2aab3f) Thanks [@knsv-bot](https://github.com/knsv-bot)! - Use balanced Brandes-Koepf placement for the default ELK preset to improve alignment of branches and composite-state entries. Preserve named non-default presets and explicit placement/alignment options, including `NONE`. Some diagrams may become wider or taller; `depthFirst` retains the previous default layout. - [#7874](mermaid-js/mermaid#7874) [`6b79518`](mermaid-js/mermaid@6b79518) Thanks [@filipsajdak](https://github.com/filipsajdak)! - fix(c4): allow boundaries as relationship endpoints A `Rel` (or `BiRel`/`Rel_*`) that referenced a boundary alias threw `references an unknown shape`, because endpoint lookup only searched shapes and not boundaries. Boundary aliases now resolve as relationship endpoints. Fixes #4864. - [#8100](mermaid-js/mermaid#8100) [`30325d4`](mermaid-js/mermaid@30325d4) Thanks [@filipsajdak](https://github.com/filipsajdak)! - fix(c4): stop wrapping non-text named attributes that land in a text slot A named attribute such as `$tags` or `$sprite` can arrive in the positional slot of a text field when the argument before it is omitted. It was then stored as `{ text: value }` rather than a string, so `$tags` given without a description crashed rendering. - [#8148](mermaid-js/mermaid#8148) [`c3ee3c7`](mermaid-js/mermaid@c3ee3c7) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(themes): `redux-dark`, `redux-dark-color` and `neo-dark` shipped `secondBkg` as the literal string `calculated`, so railroad rendered the invalid `fill: calculated`; it is now computed as `theme-dark` does. The same three themes had gantt done-task labels at 1.07:1 contrast — a light fill under their light task ink — now 5.7:1 or better. The ER and requirement stylesheets also validate `look` before interpolating it into a CSS selector. - [#8222](mermaid-js/mermaid#8222) [`1ee934d`](mermaid-js/mermaid@1ee934d) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: stop ELK-laid-out diagrams logging `Unknown arrow type: arrow_open` once per edge. ELK's arrow table put the edge _type_ `arrow_open` — which means "no arrowheads" — into the arrow-type slot, where `none` is the value that marks a deliberate absence. Anything else is reported as an unknown marker name. Diagrams whose db sets `arrowTypeStart` itself, such as flowcharts, never reached that fallback; state diagrams, which leave it unset, warned on every edge. Rendering is unchanged: both spellings produced no start marker and the same geometry, since neither has a marker offset. Only the log noise goes away. - [#8204](mermaid-js/mermaid#8204) [`a7831c5`](mermaid-js/mermaid@a7831c5) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: keep ELK subgraph frames out to the border anchor of edges that terminate on the group, so transitions to composite states no longer run along the cluster border - [#8155](mermaid-js/mermaid#8155) [`0320406`](mermaid-js/mermaid@0320406) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(elk): a composite state or subgraph containing a loop now opens on its own start node. Cycle breaking was resolved for the root graph but never passed to containers, so a container laid out on its own fell back to ELK's default, `GREEDY`, while the root ran whatever `elk.preset` asked for. The two then reversed different edges of the same cycle. In a composite state that loops, greedy reverses the edge that turns an ordinary state into a source, and sources sit on the first layer — so the diagram opened on that state alongside its start circle instead of on the start circle alone. Dagre reverses the other edge, which is why the two layout engines disagreed on the same diagram. Containers now resolve cycle breaking from the preset exactly as the root does. Only containers that actually contain a cycle change; an acyclic subgraph gives a cycle-breaking strategy nothing to do. `preset: legacy` still reaches containers with `GREEDY`, so it keeps reproducing the earlier rendering inside frames as well as outside them. - [#8228](mermaid-js/mermaid#8228) [`e36b883`](mermaid-js/mermaid@e36b883) Thanks [@knsv-bot](https://github.com/knsv-bot)! - Reserve subgraph title padding before ELK routes edges so attachments stay on the painted frame. Clip stale interior endpoints along the incoming segment, avoiding edges that run along the subgraph border. - [#8199](mermaid-js/mermaid#8199) [`b993915`](mermaid-js/mermaid@b993915) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: keep ELK edges vertical at small nodes — the node now moves onto the routed line instead of the edge bending toward the node's off-centre position - [#8155](mermaid-js/mermaid#8155) [`4e00c5c`](mermaid-js/mermaid@4e00c5c) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: render ER relationship edges above subgraph backgrounds under the ELK layout instead of hiding them behind the cluster rect - [#8156](mermaid-js/mermaid#8156) [`3f05015`](mermaid-js/mermaid@3f05015) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(er, requirement, timeline): stop the ER, requirement and timeline stylesheets emitting CSS the browser discards for the colour themes. All three generate one rule per palette slot. ER and requirement looped to `THEME_COLOR_LIMIT` and indexed the palette by the loop counter, which goes wrong in both directions: a palette shorter than the limit emitted `stroke: undefined` for the overflow slots, and a palette _longer_ than it left entities stamped with a slot that had no rule at all, rendering unstyled beside coloured neighbours. Both now take the loop bound from the palette itself, which is the same length the boxes stamp with — so the rules emitted and the slots stamped cannot disagree. Both also bail before the loop for an empty palette, since wrapping alone is not enough there: `i % 0` is `NaN` and `[][NaN]` is `undefined`. Timeline keeps looping to `THEME_COLOR_LIMIT` and wrapping, because it numbers `.section-N` classes rather than palette slots — nothing stamps those, so the palette cycles across however many sections exist. `requirement` also emitted `fill: ;` — a property with no value, which is invalid — whenever there was no background palette. That is the live case for `redux-dark-color`, which ships a border palette and no background palette so that it colours outlines only. The declaration is now omitted instead. None of these raises an error: the browser discards the invalid declaration, so the only symptom is a shape rendering unstyled. - [#8149](mermaid-js/mermaid#8149) [`d57ed55`](mermaid-js/mermaid@d57ed55) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(docs): stop `docs:build` deleting the committed `docs/` directory when a later step fails. - [#7906](mermaid-js/mermaid#7906) [`1fc5bb3`](mermaid-js/mermaid@1fc5bb3) Thanks [@knsv-bot](https://github.com/knsv-bot)! - perf: avoid quadratic parse cost on deeply-indented diagrams (~1.4 s → ~30 ms on a pathological fixture) - [#8211](mermaid-js/mermaid#8211) [`b979eb4`](mermaid-js/mermaid@b979eb4) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(handdrawn): tighten the hachure fill so shapes read as filled rather than striped. The hand-drawn fill drew 4px-wide strokes 5.2px apart, which left visible diagonal banding across every shape — legible as a texture up close, but at normal diagram size it read as stripes rather than a fill. Strokes are now 1.5px at 1.5px spacing, so the fill reads as an even tint while keeping the drawn edge quality. The striped fill behind state-diagram start, end and fork markers moves the same way, so those come out close to solid — which is what the UML convention asks for anyway. Swimlane lane titles previously pinned their own stroke weight and so ignored the shared value; they now follow it like every other shape. - [#8152](mermaid-js/mermaid#8152) [`7ee4c3f`](mermaid-js/mermaid@7ee4c3f) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: edges attach to non-rectangular shapes on the outline instead of half a pixel off it. **This is not ELK-specific.** `intersectPolygon` is how every non-rectangular shape finds its edge attachment — diamond, stadium, hexagon, trapezoid, subroutine — in every layout, so a dagre-rendered flowchart with a decision diamond is affected exactly as much as an ELK one. `intersectLine` comes from Graphics Gems, where the coordinates were integers and the numerator was nudged half a denominator away from zero so the integer division rounded instead of truncating. JavaScript division does neither, so the nudge stopped being a correction and became the whole error: every result came back displaced by `0.5 * sign(num) * sign(denom)`. The magnitude is always exactly half a unit, but the sign is per axis, because the numerator is computed separately for x and y while the denominator is shared — so the two axes could move the same way or opposite ways depending on the geometry, which is why it never looked like a constant offset anyone could spot by eye. That was enough to give an otherwise orthogonal edge a tiny diagonal opening segment, and to put an attachment just inside the node it was meant to touch. `question.ts` had been subtracting a flat 0.5 from both axes to compensate for diamonds. That only cancelled the bias when both signs came out positive, and doubled the error to a full unit when they did not — so the compensation goes along with the cause. **Rendered output moves by up to a pixel wherever a polygon shape terminates an edge.** - [#8048](mermaid-js/mermaid#8048) [`a6ec7ff`](mermaid-js/mermaid@a6ec7ff) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: treat `</br>` as a line break in labels `lineBreakRegex` only matched `<br>`, `<br/>` and `<br />`, so the malformed-but-common `</br>` survived as literal text wherever labels render as plain SVG text. HTML parsers already treat `</br>` as a `<br>`, so the tag appeared to work in HTML-label mode and failed everywhere else. It is now accepted on both paths. Also fixes `hasBreaks()` returning alternating results for the same input: it called `.test()` on a global regex, which advances `lastIndex` between calls. `wrapLabel()` used the same stateful check and could therefore re-wrap labels that already contained breaks. - [#8152](mermaid-js/mermaid#8152) [`1246a55`](mermaid-js/mermaid@1246a55) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: don't draw a line hop that has no room next to a bend. A crossing close to a corner used to get a hop squeezed into whatever space was left — as little as 2.9px against a requested 6px, opening exactly on the corner's tangent point. At that size the arc no longer clears the line it is meant to hop, so the two strokes still touch and the corner's curve runs straight into the arc's. It reads as a rendering fault rather than as a crossing. Hops now keep a straight run clear of the bend, and one that would still have to shrink below 60% of the requested radius is dropped instead of drawn. An undrawn hop is an ordinary crossing, which is a much better failure than a broken-looking one. **This changes swimlane diagrams as well as ELK ones.** Swimlanes are the existing consumer of line hops and have them on today, so a swimlane with a crossing near a bend will render differently even for someone not using ELK at all. It shows up wherever a layout stacks edges in narrow lanes: ELK routes subgraph-internal edges 10px apart, and 10px does not hold a 7.07px corner cut plus a 6px hop. A crossing is also ignored now when it lands inside the stretch where either edge is rounding a bend. Crossings are found on polylines, but a rounded edge is not drawn as its polyline — it leaves the line up to 7.07px before each bend and rejoins it that far after. A crossing found inside that stretch is somewhere the stroke never goes, so the hop was arching over blank paper while the two lines carried on touching beside it. - [#8146](mermaid-js/mermaid#8146) [`def4c81`](mermaid-js/mermaid@def4c81) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(themes): `redux-color` and `redux-dark-color` now define every variable their base themes define, instead of silently falling back to untuned values for `primaryBorderColor`, `clusterBkg`, `clusterBorder`, `altBackground`, `compositeTitleBackground` and the state and requirement edge-label backgrounds. Pie, gantt and user-journey also read the theme palette rather than a single pale tint, so pie slices are distinguishable and gantt sections are visibly banded. - [#8189](mermaid-js/mermaid#8189) [`3802472`](mermaid-js/mermaid@3802472) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(themes): venn circles follow the `redux-color` and `redux-dark-color` palettes. Neither theme defined any `venn*` variable, so every circle rendered in one flat colour. - [#8185](mermaid-js/mermaid#8185) [`f5af413`](mermaid-js/mermaid@f5af413) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix: sequence diagram actors under the `neo` look and `redux` themes. Notes no longer render bold, a `rect` section band is no longer drawn white on white, and participants follow one vertical model: every lifeline starts and ends on a shared line, all participant glyphs are one size with their feet on a common edge, single-line labels share one baseline in the header and in the mirrored footer, and a multiline label grows away from the lifeline instead of moving it. The `classic` look is unchanged. - [#8157](mermaid-js/mermaid#8157) [`a3a92ba`](mermaid-js/mermaid@a3a92ba) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(sequence): index each actor colour palette by its own length. Every actor-drawing call site read `bkgColorArray[actorCount % borderColorArray.length]` — one palette indexed by the other's length. Under `redux-color` both palettes have twelve entries, so the wrong length happens to give the right answer and nothing is visibly broken today. It goes wrong as soon as the two differ in length: the overflow actors resolve to `undefined`, and d3 then strips the inline fill for some actors and not others. Both palettes now cycle within their own length, via a shared helper. An absent or empty palette still yields `undefined` rather than a substitute colour, which is what `redux-dark-color` relies on: it ships a border palette and an empty background palette so actors are outlined but not filled. - [#8232](mermaid-js/mermaid#8232) [`e691042`](mermaid-js/mermaid@e691042) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - Circle, double circle, Delay and Display nodes size themselves from the label's height as well as its width, so a wrapped label stays inside the outline. Each was sized from the width alone and clipped any label taller than it was wide, which `flowchart.wrappingWidth: 120` made common. This replaces the wrapping exemption those shapes carried along with stadium and diamond: it stopped them wrapping at all, so a long label produced a single-line node hundreds of pixels wide. Stadium needs no exemption — its `w >= 1.5h` floor already keeps a wrapped label from closing the caps into a circle — and diamond never needed one. Stacked (`docs`) and lined (`lin-doc`) document nodes lift their label clear of the wavy bottom edge by the wave's full depth rather than half of it, so the last line is no longer clipped by the trough. Plain `doc` already did this; the two variants had copied it with the offset halved. Node dimensions are unchanged. - [#8154](mermaid-js/mermaid#8154) [`ba0deed`](mermaid-js/mermaid@ba0deed) Thanks [@aloisklink](https://github.com/aloisklink)! - fix: bundle `fastdom` to fix issues with global `define` - [#8227](mermaid-js/mermaid#8227) [`b05824a`](mermaid-js/mermaid@b05824a) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(flowchart): stop stadium labels from wrapping into a circle and exempt selected shapes from automatic label wrapping. Long stadium labels wrapped to `flowchart.wrappingWidth`, grew taller without growing wider, and turned the stadium into a circle. Stadium now keeps its semicircular caps with an outer width of at least 1.5 times its height and enough clearance that the label stays inside the arcs. Stadium (`terminal`, `pill`), circle (`circ`), diamond (`diam`, `decision`, `question`), double circle (`dbl-circ`, `double-circle`), Display (`curv-trap`, `curved-trapezoid`, `display`) and Delay (`delay`, `half-rounded-rectangle`) no longer wrap their labels at `flowchart.wrappingWidth`. Explicit line breaks are kept, and an explicit node width still takes precedence. - [#8192](mermaid-js/mermaid#8192) [`0ec29e9`](mermaid-js/mermaid@0ec29e9) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(state): draw the edge between a state and its note dashed under the `neo` look. It was rendering solid. The dashes were expressed only as CSS — `.note-edge { stroke-dasharray: 5 }` — which is enough under `classic` but not under `neo`, where `insertEdge` writes an inline `stroke-dasharray` on every edge, computed from the path length so the arrow markers keep their gaps. An inline style outranks a stylesheet rule, so the note edge took the solid pattern and the `.note-edge` rule simply lost. The note edge now declares `pattern: 'dashed'`, which is what `insertEdge` reads to choose its dash generator. `classic` is unchanged. - [#8225](mermaid-js/mermaid#8225) [`0d77926`](mermaid-js/mermaid@0d77926) Thanks [@knsv-bot](https://github.com/knsv-bot)! - fix(swimlane): seed cycle removal from source nodes so feedback edges are reversed instead of forward flow edges. A cycle like `task --> decision --> fix --> task` no longer places `fix` in the middle of the `start --> task` flow line. - [#8211](mermaid-js/mermaid#8211) [`93edd72`](mermaid-js/mermaid@93edd72) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: keep association markers apart on use-case ovals under ELK. Ovals get the same vertical padding as horizontal, edge attachment points on them are spread across the side, and the ELK renderer now accounts for every end-marker offset (extension, circle, cross, …) so a short entry stub can no longer flip a marker around. - Updated dependencies \[[`33442fd`](mermaid-js/mermaid@33442fd)]: - @mermaid-js/parser@2.0.0 ### Keeping the previous defaults in your integration Mermaid 12 changes what unconfigured diagrams look like: ELK replaces dagre as the default layout, and `redux-color` / `neo` replace `default` / `classic` as theme and look for flowchart, class, state, ER, requirement, sequence, use case, swimlane, Venn and agentflow. If you embed Mermaid and want your users' existing diagrams to render as before, set all three explicitly at initialisation: ```js mermaid.initialize({ layout: 'dagre', theme: 'default', look: 'classic' }); ``` Diagram authors can do the same per diagram in front matter, and a value there always wins over `initialize()`. - [Layouts: how `layout` is resolved, ELK variants, and the tiny build](https://mermaid.ai/open-source/config/layouts.html) - [Flowchart: default theme, look and layout in v12](https://mermaid.ai/open-source/syntax/flowchart.html#default-theme-look-and-layout-v-mermaid-release-version) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: give me a 98K <240642031+inhuman-0@users.noreply.github.com> * fix: serialize asynchronous Mermaid preview rendering --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: give me a 98K <240642031+inhuman-0@users.noreply.github.com>
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [@mermaid-js/layout-elk](https://github.com/mermaid-js/mermaid) | [`^0.1.9` → `^1.0.0`](https://renovatebot.com/diffs/npm/@mermaid-js%2flayout-elk/0.1.9/1.0.1) |  |  | --- ### Release Notes <details> <summary>mermaid-js/mermaid (@​mermaid-js/layout-elk)</summary> ### [`v1.0.1`](https://github.com/mermaid-js/mermaid/releases/tag/%40mermaid-js/layout-elk%401.0.1) [Compare Source](https://github.com/mermaid-js/mermaid/compare/@mermaid-js/layout-elk@1.0.0...@mermaid-js/layout-elk@1.0.1) ##### Patch Changes - [#​8334](mermaid-js/mermaid#8334) [`d67331d`](mermaid-js/mermaid@d67331d) Thanks [@​ashishjain0512](https://github.com/ashishjain0512)! - fix(class): place cardinality labels beside their relation ends on dagre's sides with ELK, centre dagre's end labels, and stop clipping their text - Updated dependencies \[[`50c9e55`](mermaid-js/mermaid@50c9e55), [`4c90f5c`](mermaid-js/mermaid@4c90f5c), [`c7fa1a5`](mermaid-js/mermaid@c7fa1a5), [`d67331d`](mermaid-js/mermaid@d67331d), [`99a050b`](mermaid-js/mermaid@99a050b), [`9140716`](mermaid-js/mermaid@9140716), [`3101c7d`](mermaid-js/mermaid@3101c7d), [`aa29345`](mermaid-js/mermaid@aa29345), [`967bbde`](mermaid-js/mermaid@967bbde), [`147f343`](mermaid-js/mermaid@147f343), [`40ef7b4`](mermaid-js/mermaid@40ef7b4), [`351d7d2`](mermaid-js/mermaid@351d7d2), [`b657a2c`](mermaid-js/mermaid@b657a2c), [`c38a565`](mermaid-js/mermaid@c38a565), [`fd4f5f2`](mermaid-js/mermaid@fd4f5f2), [`8afd83c`](mermaid-js/mermaid@8afd83c), [`859f1f8`](mermaid-js/mermaid@859f1f8), [`b6d952d`](mermaid-js/mermaid@b6d952d), [`7917c1a`](mermaid-js/mermaid@7917c1a), [`4a722fb`](mermaid-js/mermaid@4a722fb)]: - mermaid\@​12.1.0 ### [`v1.0.0`](https://github.com/mermaid-js/mermaid/releases/tag/%40mermaid-js/layout-elk%401.0.0) [Compare Source](https://github.com/mermaid-js/mermaid/compare/@mermaid-js/layout-elk@0.2.3...@mermaid-js/layout-elk@1.0.0) ##### Major Changes - [#​8213](mermaid-js/mermaid#8213) [`33442fd`](mermaid-js/mermaid@33442fd) Thanks [@​aloisklink](https://github.com/aloisklink)! - chore!: require ES2024, Safari 17.4+, Node.JS v22.12+ Mermaid is now built to target Safari 17.4+ and ES2024. If you need to support older browsers, you may need to polyfill or transpile mermaid. Safari 17.4+ has been chosen as the floor, as unlike Firefox/Chrome, older iOS devices don't get major Safari updates. Node.JS v22.12+ is also declared as requirement in our `package.json` files, but as mermaid requires a browser, this is mainly so we can use dependencies that also declare a Node.JS v22.12+ requirement, without causing issues for users when running `npm install`. ##### Minor Changes - [#​8152](mermaid-js/mermaid#8152) [`d4bea0d`](mermaid-js/mermaid@d4bea0d) Thanks [@​knsv-bot](https://github.com/knsv-bot)! - feat: `elk.preset` picks a named combination of the options that decide where nodes end up. Three options settle node positions, and they sit in different phases of the layout: which layer a node lands in, where it goes within that layer, and which edges get reversed to make the graph acyclic. Choosing them well means knowing all three interact; `preset` names the combinations worth using. - `default` — network simplex layering, balanced Brandes-Koepf placement at the top level and inside subgraphs, and depth-first cycle breaking. Balanced placement centres branches and composite-state entries; depth-first breaking gives shorter back edges on graphs that loop. - `legacy` — reproduces what earlier versions actually rendered: Brandes-Koepf placement with ELK's own greedy cycle breaking. - `modelOrder` — as `depthFirst`, but breaks cycles by greedy model order, which disturbs declaration order least at the cost of longer back edges. - `depthFirst` — the previous default: network simplex layering and top-level placement, Brandes-Koepf placement inside subgraphs, `NONE` alignment, and depth-first cycle breaking. ```yaml --- config: layout: elk elk: preset: legacy --- ``` Setting `layeringStrategy`, `nodePlacementStrategy`, `nodePlacementAlignment` or `cycleBreakingStrategy` explicitly overrides the preset for that one option and leaves the rest in place, so a preset is a starting point rather than a lock. **Node placement keeps `BRANDES_KOEPF`, but its alignment changes from `NONE` to `BALANCED` and cycle breaking from `GREEDY` to `DEPTH_FIRST`, so existing ELK diagrams will lay out differently.** `preset: legacy` restores the previous behaviour, and is the single switch for it — this is the net change against the last release, measured from what shipped rather than from any intermediate state. Subgraph contents use `BRANDES_KOEPF` under every preset. For `modelOrder` and `depthFirst` that is deliberately not the root's strategy: network simplex inside a frame produced routes that left the subgraph on its bounding-box corner. The two sides are tuned independently, so `nodePlacementStrategy` set explicitly still applies to both. Note that `legacy` uses `GREEDY` cycle breaking rather than the `GREEDY_MODEL_ORDER` the schema previously advertised. That default was declared in the schema but never listed in the shipped defaults, so it reached ELK as undefined and ELK's own default applied — `legacy` reproduces what was rendered, not what was documented. - [#​8152](mermaid-js/mermaid#8152) [`1246a55`](mermaid-js/mermaid@1246a55) Thanks [@​knsv-bot](https://github.com/knsv-bot)! - feat: draw line hops where ELK edges cross, controlled by `elk.lineHops`. Where two edges cross, the one that gives way is drawn with a small arc (or a visible gap) so it is clear which line passes over which. On by default; set `elk.lineHops: false` to draw plain crossings, or `'gap'` to use gaps instead of arcs. ```yaml --- config: layout: elk elk: lineHops: gap --- ``` The crossing detection and both styles already existed and were used by swimlanes — this registers the `afterPaint` hook that lets ELK use them. An edge that takes a hop loses its corner rounding on that segment, which is the trade for a readable crossing; curved edges are skipped rather than rewritten, to avoid corrupting their geometry. **Existing ELK diagrams with crossing edges will render differently.** - [#​8155](mermaid-js/mermaid#8155) [`810893c`](mermaid-js/mermaid@810893c) Thanks [@​ashishjain0512](https://github.com/ashishjain0512)! - feat: this package is now built from mermaid's own ELK implementation instead of carrying its own copy, and is only needed for Mermaid builds that ship without ELK. `mermaid` bundles ELK and registers it automatically, so most projects can drop the dependency and the `registerLayoutLoaders` call. The package remains published and fully functional for the **tiny** build (`mermaid.tiny.js`), which omits ELK to stay small and where registering this is the only way to get an ELK layout. Because it is compiled from mermaid's ELK source rather than importing the whole `mermaid` entry point, the published bundle no longer drags in every diagram type, parser and KaTeX: the minified ESM payload drops from roughly **1.58 MB to 728 kB gzipped**. It stays self-contained, so it still loads from a CDN next to any Mermaid build with no import map. The rendering utilities the ELK source reaches (`dompurify`, `katex`, `dayjs`, `dagre-d3-es`) are now declared in the package's `dependencies`, so the npm build (`.core.mjs`) resolves them through your package manager — they dedupe against the host's copies and show up in audits — instead of carrying invisible inlined copies. > **Maintainers:** `peerDependencies.mermaid` still reads `^11.0.2`. It should be raised to the major that bundles ELK as part of the release. ##### Patch Changes - [#​8152](mermaid-js/mermaid#8152) [`785ca77`](mermaid-js/mermaid@785ca77) Thanks [@​knsv-bot](https://github.com/knsv-bot)! - fix: draw ELK subgraph frames an even distance from their contents. A subgraph could sit 76px from its nodes on one side and 24px on the other, with nothing visible in the gap. ELK sizes a container around everything it put inside, edges included, and an edge that runs against the flow of the layout is routed back around the outside — so a group holding one grew on whichever side that edge left by, and a group without one did not. The lane is real and the edge still needs it, so the space is not reclaimed. What changes is that the frame is no longer drawn around it: the frame is pulled in to an even distance from the group's own children, and the edge keeps its lane just outside, which is what an edge routed around a group should look like anyway. The top is left as ELK set it, since it carries the subgraph's title strip and there is no way to tell how much of that padding is the title and how much is spare. A frame still holds the lanes that genuinely belong to it. An edge with both endpoints inside a group never leaves it, so its lane is part of that group's interior and the frame stays drawn around it — which matters for nested groups, where a lane routed around an inner group sits inside the outer one. **Subgraphs render tighter, and groups that used to be visibly lopsided are now even.** - [#​8228](mermaid-js/mermaid#8228) [`e36b883`](mermaid-js/mermaid@e36b883) Thanks [@​knsv-bot](https://github.com/knsv-bot)! - Reserve subgraph title padding before ELK routes edges so attachments stay on the painted frame. Clip stale interior endpoints along the incoming segment, avoiding edges that run along the subgraph border. - [#​8152](mermaid-js/mermaid#8152) [`1befa91`](mermaid-js/mermaid@1befa91) Thanks [@​knsv-bot](https://github.com/knsv-bot)! - fix: edges leave diamonds, stadiums and other non-rectangular shapes without kinking. ELK routes to ports on a node's bounding box and always leaves one perpendicular to the side it sits on. For a rectangle that port is the attachment point; for anything else the outline is inside the box, so the attachment has to move inwards — and the direction it moves in decides whether the edge stays orthogonal. It used to move along the ray from the node's centre, which lands on the outline at a different offset along the side than the port ELK chose, so the opening segment came out diagonal. The attachment now walks the outline along the edge's own departure axis, staying collinear with ELK's stub: the edge leaves the outline, crosses the box, and carries on in one straight line. Rectangular nodes are unaffected. - [#​8152](mermaid-js/mermaid#8152) [`1348b4f`](mermaid-js/mermaid@1348b4f) Thanks [@​knsv-bot](https://github.com/knsv-bot)! - fix: an edge no longer leaves a subgraph from the frame's corner. `elk.spacing.portsSurrounding` was left at ELK's default of `0`, which permits a port to sit exactly on a node's corner. A corner is the one boundary point with no side to leave from, so the edge came out of the vertex and then ran ALONG the frame's own edge before turning away from it. Subgraphs showed it first, because an edge that crosses a subgraph boundary attaches to the frame rather than to a node inside it, and a frame is large enough for the result to be obvious. A margin is now reserved at the ends of every side, so ELK keeps ports off the corners itself rather than the renderer correcting them afterwards. Over the `elk-edge-cases` corpus this takes the fixtures with a corner endpoint from 8 of 30 down to 3. The value is 12, chosen by measurement: it is the smallest that clears the corner on that corpus. It is not a free parameter — 30 was tried and reorders layers. - [#​8194](mermaid-js/mermaid#8194) [`012e1f7`](mermaid-js/mermaid@012e1f7) Thanks [@​knsv-bot](https://github.com/knsv-bot)! - fix: center edges attached to small nodes such as start/end state circles. ELK's ports-surrounding margin exceeded the side length of nodes narrower than 24px, parking the edge anchor off-center; such anchors are now discarded so the edge aims at the node center. - [#​8152](mermaid-js/mermaid#8152) [`1befa91`](mermaid-js/mermaid@1befa91) Thanks [@​knsv-bot](https://github.com/knsv-bot)! - fix: an edge no longer leaves a node with a tiny kink. ELK spreads an edge's port evenly along a node's side, then routes the edge down a channel whose row rarely lines up with that port exactly. The leftover is a staircase of a few pixels right at the border: leave the port, run a short distance, step perpendicular onto the channel, carry on. With rounded corners the two micro-bends sit on top of each other and read as a glitch — one edge in the sample corpus stepped 3.25px and rendered as two quadratic curves with a zero-length segment between them. The step is now removed by moving the channel onto the port's row, so the edge draws as one straight line and **both ports stay exactly where the layout put them** — sliding an attachment along a node's border leaves a node whose other edges are still evenly spread looking lopsided. Only a step next to a node is touched, and only when it is small and the edge continues the same way afterwards, so a real turn is never collapsed. An edge is left alone entirely when moving its run would drag the far port, or would buy a crossing. Set `elk.straightenEdges: false` to keep the previous behaviour. - [#​8152](mermaid-js/mermaid#8152) [`3b09225`](mermaid-js/mermaid@3b09225) Thanks [@​knsv-bot](https://github.com/knsv-bot)! - fix: stop ELK subgraphs padding one side more than the other. A subgraph could end up with far more space on one side than the other for no reason a reader could see — 74px on the right of one group against 24px everywhere else. The extra space was a routing lane held open for an edge that runs against the flow of the layout and has to be routed back around, and its width came from `spacing.baseValue`. That base value was doing two jobs at once. Every unset ELK spacing derives from it, so it had to stay large enough that an edge got a straight run before the node it enters — below about 40 the approach came out shorter than the arrowhead and the turn read as happening underneath it. But an edge routed down the inside of a frame claims a lane the same width, so paying for the approach out of the base value also pushed groups clear of their own borders. The two are now bought separately. The base value drops to 24, and the approach run, node separation and edge separation are set explicitly, so edges keep the run they had without the frame paying for it. `elk.layered.spacing.edgeNodeBetweenLayers` is the key that buys the approach. An earlier attempt used `elk.layered.spacing.edgeEdgeBetweenLayers`, which is edge-to-edge and a different quantity, and a note in the source concluded from it that ELK ignored edge-node spacing "in every key form". It does not; that note was wrong and is corrected. Subgraph contents also gain `PORT_POSITION` node flexibility, which lets a node shift so an edge can leave straight rather than bending off the port. (Their placement strategy is covered in the `elk.preset` note.) **Existing diagrams with subgraphs will render differently** — groups get tighter and more even. - [#​8129](mermaid-js/mermaid#8129) [`83f5c47`](mermaid-js/mermaid@83f5c47) Thanks [@​ashishjain0512](https://github.com/ashishjain0512)! - fix(build): externalize `peerDependencies` in core builds so the layout plugins no longer inline a second copy of mermaid `getBuildConfig` only externalized `dependencies`, so a runtime (non-type) import of the peer-depended mermaid resolved through `exports` to `dist/mermaid.core.mjs` and esbuild inlined the whole bundle. `@mermaid-js/layout-elk`'s core entry had grown to 106 files / 6.6 MB, carrying its own mermaid with separate module-level singletons — so mermaid rendering fixes did not reach the ELK layout path until the plugin itself was republished. The core entry is back to 3 files / \~41 KB and now defers to the host's mermaid. The self-contained `esm` entry is unchanged. - Updated dependencies \[[`7a3c1a8`](mermaid-js/mermaid@7a3c1a8), [`0cf3797`](mermaid-js/mermaid@0cf3797), [`846fd65`](mermaid-js/mermaid@846fd65), [`33442fd`](mermaid-js/mermaid@33442fd), [`dc2e453`](mermaid-js/mermaid@dc2e453), [`ce0302d`](mermaid-js/mermaid@ce0302d), [`ad98070`](mermaid-js/mermaid@ad98070), [`e2aab3f`](mermaid-js/mermaid@e2aab3f), [`6b79518`](mermaid-js/mermaid@6b79518), [`30325d4`](mermaid-js/mermaid@30325d4), [`cd48a64`](mermaid-js/mermaid@cd48a64), [`c3ee3c7`](mermaid-js/mermaid@c3ee3c7), [`1ee934d`](mermaid-js/mermaid@1ee934d), [`a7831c5`](mermaid-js/mermaid@a7831c5), [`0cf3797`](mermaid-js/mermaid@0cf3797), [`0320406`](mermaid-js/mermaid@0320406), [`810893c`](mermaid-js/mermaid@810893c), [`e36b883`](mermaid-js/mermaid@e36b883), [`b993915`](mermaid-js/mermaid@b993915), [`4e00c5c`](mermaid-js/mermaid@4e00c5c), [`3f05015`](mermaid-js/mermaid@3f05015), [`d57ed55`](mermaid-js/mermaid@d57ed55), [`1fc5bb3`](mermaid-js/mermaid@1fc5bb3), [`b979eb4`](mermaid-js/mermaid@b979eb4), [`7ee4c3f`](mermaid-js/mermaid@7ee4c3f), [`a6ec7ff`](mermaid-js/mermaid@a6ec7ff), [`1246a55`](mermaid-js/mermaid@1246a55), [`813c766`](mermaid-js/mermaid@813c766), [`8603bdd`](mermaid-js/mermaid@8603bdd), [`43d9fbc`](mermaid-js/mermaid@43d9fbc), [`2878cf3`](mermaid-js/mermaid@2878cf3), [`16b9a7d`](mermaid-js/mermaid@16b9a7d), [`def4c81`](mermaid-js/mermaid@def4c81), [`3802472`](mermaid-js/mermaid@3802472), [`a19bd08`](mermaid-js/mermaid@a19bd08), [`f5af413`](mermaid-js/mermaid@f5af413), [`a3a92ba`](mermaid-js/mermaid@a3a92ba), [`e691042`](mermaid-js/mermaid@e691042), [`ba0deed`](mermaid-js/mermaid@ba0deed), [`b05824a`](mermaid-js/mermaid@b05824a), [`0ec29e9`](mermaid-js/mermaid@0ec29e9), [`0d77926`](mermaid-js/mermaid@0d77926), [`93edd72`](mermaid-js/mermaid@93edd72), [`75e6c30`](mermaid-js/mermaid@75e6c30), [`6df1149`](mermaid-js/mermaid@6df1149), [`a31ecb7`](mermaid-js/mermaid@a31ecb7)]: - mermaid\@​12.0.0 ### [`v0.2.3`](https://github.com/mermaid-js/mermaid/releases/tag/%40mermaid-js/layout-elk%400.2.3) [Compare Source](https://github.com/mermaid-js/mermaid/compare/@mermaid-js/layout-elk@0.2.2...@mermaid-js/layout-elk@0.2.3) ##### Patch Changes - [#​7828](mermaid-js/mermaid#7828) [`8eb3afc`](mermaid-js/mermaid@8eb3afc) Thanks [@​knsv-bot](https://github.com/knsv-bot)! - feat(elk): add `elk.keepEntryNodeOnTop` config option to keep a recursive flow's entry node on top - [#​7803](mermaid-js/mermaid#7803) [`74e44eb`](mermaid-js/mermaid@74e44eb) Thanks [@​knsv-bot](https://github.com/knsv-bot)! - feat(elk): add `elk.nodePlacementAlignment` config option - Updated dependencies \[[`215fe89`](mermaid-js/mermaid@215fe89), [`3670b4e`](mermaid-js/mermaid@3670b4e), [`cdfc0ea`](mermaid-js/mermaid@cdfc0ea), [`c45cde9`](mermaid-js/mermaid@c45cde9), [`8d874c4`](mermaid-js/mermaid@8d874c4), [`8eb3afc`](mermaid-js/mermaid@8eb3afc), [`74e44eb`](mermaid-js/mermaid@74e44eb), [`ea55b31`](mermaid-js/mermaid@ea55b31), [`b3d1f63`](mermaid-js/mermaid@b3d1f63), [`71b8843`](mermaid-js/mermaid@71b8843), [`9cbef5d`](mermaid-js/mermaid@9cbef5d), [`a2c0fb6`](mermaid-js/mermaid@a2c0fb6), [`a34cbf0`](mermaid-js/mermaid@a34cbf0), [`f9cbe1e`](mermaid-js/mermaid@f9cbe1e), [`ae3e115`](mermaid-js/mermaid@ae3e115), [`90eeece`](mermaid-js/mermaid@90eeece), [`afa2f80`](mermaid-js/mermaid@afa2f80), [`0fd7a9f`](mermaid-js/mermaid@0fd7a9f)]: - mermaid\@​11.17.0 ### [`v0.2.2`](https://github.com/mermaid-js/mermaid/releases/tag/%40mermaid-js/layout-elk%400.2.2) [Compare Source](https://github.com/mermaid-js/mermaid/compare/@mermaid-js/layout-elk@0.2.1...@mermaid-js/layout-elk@0.2.2) ##### Patch Changes - [#​7712](mermaid-js/mermaid#7712) [`e2e518a`](mermaid-js/mermaid@e2e518a) Thanks [@​knsv-bot](https://github.com/knsv-bot)! - fix(elk): propagate `elk.mergeEdges` config to subgraphs in ELK layout — previously edges defined inside a subgraph were not merged even when `elk.mergeEdges: true` was set - Updated dependencies \[[`ea1c48f`](mermaid-js/mermaid@ea1c48f), [`f45cc2c`](mermaid-js/mermaid@f45cc2c), [`f1f4d45`](mermaid-js/mermaid@f1f4d45), [`633c261`](mermaid-js/mermaid@633c261), [`c8ba156`](mermaid-js/mermaid@c8ba156), [`4e4e6c4`](mermaid-js/mermaid@4e4e6c4), [`cfd2391`](mermaid-js/mermaid@cfd2391), [`c1f116d`](mermaid-js/mermaid@c1f116d), [`b4d0442`](mermaid-js/mermaid@b4d0442), [`72fbab1`](mermaid-js/mermaid@72fbab1), [`a6f097d`](mermaid-js/mermaid@a6f097d), [`37f2e36`](mermaid-js/mermaid@37f2e36), [`4e63e9d`](mermaid-js/mermaid@4e63e9d), [`4887e97`](mermaid-js/mermaid@4887e97), [`a4c1e50`](mermaid-js/mermaid@a4c1e50), [`cc75089`](mermaid-js/mermaid@cc75089), [`be2e282`](mermaid-js/mermaid@be2e282), [`d945968`](mermaid-js/mermaid@d945968), [`2f5e9e8`](mermaid-js/mermaid@2f5e9e8), [`8dcdce4`](mermaid-js/mermaid@8dcdce4), [`1bbc189`](mermaid-js/mermaid@1bbc189), [`05223be`](mermaid-js/mermaid@05223be), [`365c1b1`](mermaid-js/mermaid@365c1b1), [`06a32b7`](mermaid-js/mermaid@06a32b7), [`afaf306`](mermaid-js/mermaid@afaf306), [`216e4e9`](mermaid-js/mermaid@216e4e9), [`79e97cd`](mermaid-js/mermaid@79e97cd), [`e5c75e6`](mermaid-js/mermaid@e5c75e6), [`974fa7b`](mermaid-js/mermaid@974fa7b), [`c2305df`](mermaid-js/mermaid@c2305df), [`a4a250b`](mermaid-js/mermaid@a4a250b)]: - mermaid\@​11.16.0 ### [`v0.2.1`](https://github.com/mermaid-js/mermaid/releases/tag/%40mermaid-js/layout-elk%400.2.1) [Compare Source](https://github.com/mermaid-js/mermaid/compare/@mermaid-js/layout-elk@0.2.0...@mermaid-js/layout-elk@0.2.1) ##### Patch Changes - [#​7425](mermaid-js/mermaid#7425) [`f16bfbb`](mermaid-js/mermaid@f16bfbb) Thanks [@​knsv](https://github.com/knsv)! - fix: use rounded right-angle edges for ELK layout ELK layout edges now default to `rounded` curve (right-angle segments with rounded corners) instead of inheriting the global `basis` default. This fixes ELK edges that were curving instead of routing at right angles ([#​7213](mermaid-js/mermaid#7213)). Non-ELK layouts are unaffected and keep their existing `basis` default. - Updated dependencies \[[`96a766d`](mermaid-js/mermaid@96a766d), [`32723b2`](mermaid-js/mermaid@32723b2), [`a60e615`](mermaid-js/mermaid@a60e615), [`1a9d45a`](mermaid-js/mermaid@1a9d45a), [`96ca7c0`](mermaid-js/mermaid@96ca7c0), [`60f6331`](mermaid-js/mermaid@60f6331), [`fa15ce8`](mermaid-js/mermaid@fa15ce8), [`33c7c72`](mermaid-js/mermaid@33c7c72), [`3c069b5`](mermaid-js/mermaid@3c069b5), [`9745f32`](mermaid-js/mermaid@9745f32), [`d6db0b0`](mermaid-js/mermaid@d6db0b0), [`cdacb0b`](mermaid-js/mermaid@cdacb0b), [`a408b55`](mermaid-js/mermaid@a408b55), [`712c1ec`](mermaid-js/mermaid@712c1ec), [`981a62e`](mermaid-js/mermaid@981a62e), [`a4bb0b5`](mermaid-js/mermaid@a4bb0b5), [`b0f9d5b`](mermaid-js/mermaid@b0f9d5b), [`981fbb8`](mermaid-js/mermaid@981fbb8), [`93aa657`](mermaid-js/mermaid@93aa657), [`6bc6617`](mermaid-js/mermaid@6bc6617), [`73e9849`](mermaid-js/mermaid@73e9849), [`9d0669a`](mermaid-js/mermaid@9d0669a), [`acce4db`](mermaid-js/mermaid@acce4db), [`7eed6a1`](mermaid-js/mermaid@7eed6a1), [`2000680`](mermaid-js/mermaid@2000680), [`b7c66a2`](mermaid-js/mermaid@b7c66a2), [`f16bfbb`](mermaid-js/mermaid@f16bfbb), [`aac86f7`](mermaid-js/mermaid@aac86f7), [`9745f32`](mermaid-js/mermaid@9745f32), [`2dd29be`](mermaid-js/mermaid@2dd29be), [`ace0367`](mermaid-js/mermaid@ace0367), [`09b74f1`](mermaid-js/mermaid@09b74f1), [`33c7c72`](mermaid-js/mermaid@33c7c72), [`835de00`](mermaid-js/mermaid@835de00), [`a9e4c72`](mermaid-js/mermaid@a9e4c72), [`ff15e51`](mermaid-js/mermaid@ff15e51), [`8bfd477`](mermaid-js/mermaid@8bfd477), [`b136acd`](mermaid-js/mermaid@b136acd), [`e0317ac`](mermaid-js/mermaid@e0317ac)]: - mermaid\@​11.13.0 ### [`v0.2.0`](https://github.com/mermaid-js/mermaid/releases/tag/%40mermaid-js/layout-elk%400.2.0) [Compare Source](https://github.com/mermaid-js/mermaid/compare/@mermaid-js/layout-elk@0.1.9...@mermaid-js/layout-elk@0.2.0) ##### Minor Changes - [#​6802](mermaid-js/mermaid#6802) [`c8e5027`](mermaid-js/mermaid@c8e5027) Thanks [@​darshanr0107](https://github.com/darshanr0107)! - feat: Update mindmap rendering to support multiple layouts, improved edge intersections, and new shapes ##### Patch Changes - Updated dependencies \[[`33bc4a0`](mermaid-js/mermaid@33bc4a0), [`e0b45c2`](mermaid-js/mermaid@e0b45c2), [`012530e`](mermaid-js/mermaid@012530e), [`c8e5027`](mermaid-js/mermaid@c8e5027)]: - mermaid\@​11.11.0 </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - "before 9am on tuesday" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xMzMuMCIsInVwZGF0ZWRJblZlciI6IjQ0LjEzMy4wIiwidGFyZ2V0QnJhbmNoIjoiZGV2ZWxvcCIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiLCJyZW5vdmF0ZSJdfQ==--> Reviewed-on: https://code.futo.org/harbor/harbor/pulls/1843 Reviewed-by: Mark Harding <mark@futo.org>
📑 Summary
Mermaid now requires browsers that support ES2024.
We're targeting browser support for Safari 17.4, since Safari is the main browser that tends to be out-of-date, due to iOS/MacOS devices not being to upgrade to new iOS/MacOS versions.
Chromium v121 and Firefox 123 have also been added as targets, since they're on the
baseline-widely-availableright now (just like Safari 17.4 in a few days), but we're not commited to supporting them, as it's unlikely people are stuck on those browsers.We're also officially declaring a Node.JS v22.12+ requirement for users that install mermaid for build tools. This is mainly to avoid
npm installerrors for our users, as we're a browser-based library and we don't actually support running mermaid in Node.JS.a?.b = cassignment in architecture.spec.ts that the old ES2018 lowering used to hideBREAKING CHANGE:
Mermaid now requires ES2024 and Safari 17.4 or later.
Although Mermaid is a browser library, Mermaid also declares a Node.JS v22.12+ requirement so it can update using dependencies that also require Node.JS v22.12+, without causing
npm installerrors for users.📏 Design Decisions
Describe the way your implementation works or what design decisions you made if applicable.
📋 Tasks
Make sure you
MERMAID_RELEASE_VERSIONis used for all new features.pnpm changesetand following the prompts. Changesets that add features should beminorand those that fix bugs should bepatch. Please prefix changeset messages withfeat:,fix:, orchore:.