Merge branch 'develop' into 4459-remove-beta-suffix

This commit is contained in:
darshanr0107
2025-07-01 12:34:33 +05:30
committed by GitHub
73 changed files with 3312 additions and 980 deletions

View File

@@ -1,5 +0,0 @@
---
'mermaid': minor
---
feat: Add Vertical Line To Gantt Plot At Specified Time

View File

@@ -0,0 +1,6 @@
---
'mermaid': minor
'@mermaid-js/parser': minor
---
Adding support for the new diagram type nested treemap

View File

@@ -1,5 +0,0 @@
---
'@mermaid-js/layout-elk': patch
---
Make elk respect the order of nodes based from the code

View File

@@ -1,5 +0,0 @@
---
'@mermaid-js/mermaid-zenuml': major
---
Upgraded the dependency @zenuml/core

View File

@@ -1,5 +0,0 @@
---
'mermaid': patch
---
Fix stroke styles for ER diagram to correctly apply path and row-specific styles

View File

@@ -1,5 +0,0 @@
---
'mermaid': patch
---
chore: Convert StateDB into TypeScript

View File

@@ -1,5 +0,0 @@
---
'mermaid': patch
---
fix: Remove incorrect `style="undefined;"` attributes in some Mermaid diagrams

View File

@@ -1,7 +0,0 @@
---
'@mermaid-js/mermaid-zenuml': patch
---
chore: bump minimum ZenUML version to 3.23.28
commit: 9d06d8f31e7f12af9e9e092214f907f2dc93ad75

View File

@@ -1,5 +0,0 @@
---
'mermaid': minor
---
feat: Add support for styling Journey Diagram title (color, font-family, and font-size)

View File

@@ -1,5 +0,0 @@
---
'mermaid': patch
---
FontAwesome icons can now be embedded as SVGs in flowcharts if they are registered via `mermaid.registerIconPacks`.

View File

@@ -1,5 +0,0 @@
---
'mermaid': minor
---
Added support for the click directive in stateDiagram syntax

View File

@@ -1,6 +0,0 @@
---
'mermaid': minor
'@mermaid-js/parser': minor
---
feat: Add shorter `+<count>: Label` syntax in packet diagram

View File

@@ -1,6 +0,0 @@
---
'mermaid': patch
'@mermaid-js/parser': patch
---
Refactor grammar so that title don't break Architecture Diagrams

View File

@@ -1,5 +0,0 @@
---
'mermaid': major
---
fix: allow sequence diagram arrows with a trailing colon but no message

View File

@@ -1,5 +0,0 @@
---
'mermaid': minor
---
feat: Dynamically Render Data Labels Within Bar Charts

View File

@@ -1,5 +0,0 @@
---
'mermaid': patch
---
fix: allow colons in events

View File

@@ -1,7 +0,0 @@
---
'mermaid': patch
---
fix(timeline): ensure consistent vertical line lengths with visible arrowheads
Fixed timeline diagrams where vertical dashed lines from tasks had inconsistent lengths. All vertical lines now extend to the same depth regardless of the number of events in each column, with sufficient padding to clearly display both the dashed line pattern and complete arrowheads.

View File

@@ -1,7 +0,0 @@
---
'@mermaid-js/mermaid-zenuml': patch
---
fix(zenuml): limit `peerDependencies` to Mermaid v10 and v11
commit: 0ad44c12feead9d20c6a870a49327ada58d6e657

View File

@@ -1,5 +0,0 @@
---
'mermaid': patch
---
fix: Fix incomplete string escaping in URL manipulation logic when `arrowMarkerAbsolute: true` by ensuring all unsafe characters are escaped.

View File

@@ -88,6 +88,7 @@ NODIR
NSTR
outdir
Qcontrolx
QSTR
reinit
rels
reqs

View File

@@ -1,5 +1,5 @@
import { build } from 'esbuild';
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
import { cp, mkdir, readFile, rename, writeFile } from 'node:fs/promises';
import { packageOptions } from '../.build/common.js';
import { generateLangium } from '../.build/generateLangium.js';
import type { MermaidBuildOptions } from './util.js';
@@ -90,6 +90,7 @@ const buildTinyMermaid = async () => {
tinyPkg.version = mermaidPkg.version;
await writeFile('./packages/tiny/package.json', JSON.stringify(tinyPkg, null, 2) + '\n');
await cp('./packages/mermaid/CHANGELOG.md', './packages/tiny/CHANGELOG.md');
};
const main = async () => {

3
.github/lychee.toml vendored
View File

@@ -52,7 +52,8 @@ exclude = [
# Timeout
"https://huehive.co",
"https://foswiki.org",
"https://www.gnu.org"
"https://www.gnu.org",
"https://mermaid-preview.com"
]
# Exclude all private IPs from checking.

70
.github/workflows/validate-lockfile.yml vendored Normal file
View File

@@ -0,0 +1,70 @@
name: Validate pnpm-lock.yaml
on:
pull_request:
paths:
- 'pnpm-lock.yaml'
- '**/package.json'
- '.github/workflows/validate-lockfile.yml'
jobs:
validate-lockfile:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0
- name: Validate pnpm-lock.yaml entries
id: validate # give this step an ID so we can reference its outputs
run: |
issues=()
# 1) No tarball references
if grep -qF 'tarball:' pnpm-lock.yaml; then
issues+=("• Tarball references found (forbidden)")
fi
# 2) No unwanted vitepress paths
if grep -qF 'packages/mermaid/src/vitepress' pnpm-lock.yaml; then
issues+=("• Disallowed path 'packages/mermaid/src/vitepress' present. Run `rm -rf packages/mermaid/src/vitepress && pnpm install` to regenerate.")
fi
# 3) Lockfile only changes when package.json changes
git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }} > changed.txt
if grep -q '^pnpm-lock.yaml$' changed.txt && ! grep -q 'package.json' changed.txt; then
issues+=("• pnpm-lock.yaml changed without any package.json modification")
fi
# If any issues, output them and fail
if [ ${#issues[@]} -gt 0 ]; then
# Use the new GITHUB_OUTPUT approach to set a multiline output
{
echo "errors<<EOF"
printf '%s\n' "${issues[@]}"
echo "EOF"
} >> $GITHUB_OUTPUT
exit 1
fi
- name: Comment on PR if validation failed
if: failure()
uses: peter-evans/create-or-update-comment@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.pull_request.number }}
body: |
The following issue(s) were detected:
${{ steps.validate.outputs.errors }}
Please address these and push an update.
_Posted automatically by GitHub Actions_

View File

@@ -95,10 +95,6 @@ In our release process we rely heavily on visual regression tests using [applito
<!-- </Main description> -->
## Mermaid AI Bot
[Mermaid](https://codeparrot.ai/oracle?owner=mermaid-js&repo=mermaid) Bot will help you understand this repository better. You can ask for code examples, installation guide, debugging help and much more.
## Examples
**The following are some examples of the diagrams, charts and graphs that can be made using Mermaid. Click here to jump into the [text syntax](https://mermaid.js.org/intro/syntax-reference.html).**

View File

@@ -0,0 +1,382 @@
import { imgSnapshotTest } from '../../helpers/util.ts';
describe('Treemap Diagram', () => {
it('1: should render a basic treemap', () => {
imgSnapshotTest(
`treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
`,
{}
);
});
it('2: should render a hierarchical treemap', () => {
imgSnapshotTest(
`treemap-beta
"Products"
"Electronics"
"Phones": 50
"Computers": 30
"Accessories": 20
"Clothing"
"Men's"
"Shirts": 10
"Pants": 15
"Women's"
"Dresses": 20
"Skirts": 10
`,
{}
);
});
it('3: should render a treemap with styling using classDef', () => {
imgSnapshotTest(
`treemap-beta
"Section 1"
"Leaf 1.1": 12
"Section 1.2":::class1
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20:::class1
"Leaf 2.2": 25
"Leaf 2.3": 12
classDef class1 fill:red,color:blue,stroke:#FFD600;
`,
{}
);
});
it('4: should handle long text that wraps', () => {
imgSnapshotTest(
`treemap-beta
"Main Category"
"This is a very long item name that should wrap to the next line when rendered in the treemap diagram": 50
"Short item": 20
`,
{}
);
});
it('5: should render with a forest theme', () => {
imgSnapshotTest(
`---
config:
theme: forest
---
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
`,
{}
);
});
it('6: should handle multiple levels of nesting', () => {
imgSnapshotTest(
`treemap-beta
"Level 1"
"Level 2A"
"Level 3A": 10
"Level 3B": 15
"Level 2B"
"Level 3C": 20
"Level 3D"
"Level 4A": 5
"Level 4B": 5
`,
{}
);
});
it('7: should handle classDef with multiple styles', () => {
imgSnapshotTest(
`treemap-beta
"Main"
"A": 20
"B":::important
"B1": 10
"B2": 15
"C": 5:::secondary
classDef important fill:#f96,stroke:#333,stroke-width:2px;
classDef secondary fill:#6cf,stroke:#333,stroke-dasharray:5 5;
`,
{}
);
});
it('8: should handle dollar value formatting with thousands separator', () => {
imgSnapshotTest(
`---
config:
treemap:
valueFormat: "$0,0"
---
treemap
"Budget"
"Operations"
"Salaries": 700000
"Equipment": 200000
"Supplies": 100000
"Marketing"
"Advertising": 400000
"Events": 100000
`,
{}
);
});
it('8a: should handle percentage formatting', () => {
imgSnapshotTest(
`---
config:
treemap:
valueFormat: ".1%"
---
treemap-beta
"Market Share"
"Company A": 0.35
"Company B": 0.25
"Company C": 0.15
"Others": 0.25
`,
{}
);
});
it('8b: should handle decimal formatting', () => {
imgSnapshotTest(
`---
config:
treemap:
valueFormat: ".2f"
---
treemap-beta
"Metrics"
"Conversion Rate": 0.0567
"Bounce Rate": 0.6723
"Click-through Rate": 0.1289
"Engagement": 0.4521
`,
{}
);
});
it('8c: should handle dollar sign with decimal places', () => {
imgSnapshotTest(
`---
config:
treemap:
valueFormat: "$.2f"
---
treemap-beta
"Product Prices"
"Basic": 19.99
"Standard": 49.99
"Premium": 99.99
"Enterprise": 199.99
`,
{}
);
});
it('8d: should handle dollar sign with thousands separator and decimal places', () => {
imgSnapshotTest(
`---
config:
treemap:
valueFormat: "$,.2f"
---
treemap-beta
"Revenue"
"Q1": 1250345.75
"Q2": 1645789.25
"Q3": 1845123.50
"Q4": 2145678.75
`,
{}
);
});
it('8e: should handle simple thousands separator', () => {
imgSnapshotTest(
`---
config:
treemap:
valueFormat: ","
---
treemap-beta
"User Counts"
"Active Users": 1250345
"New Signups": 45789
"Churned": 12350
"Converted": 78975
`,
{}
);
});
it('8f: should handle valueFormat set via directive with dollar and thousands separator', () => {
imgSnapshotTest(
`---
config:
treemap:
valueFormat: "$,.0f"
---
treemap-beta
"Sales by Region"
"North": 1234567
"South": 7654321
"East": 4567890
"West": 9876543
`,
{}
);
});
it('8g: should handle scientific notation format', () => {
imgSnapshotTest(
`---
config:
treemap:
valueFormat: ".2e"
---
treemap-beta
"Scientific Values"
"Value 1": 1234567
"Value 2": 0.0000123
"Value 3": 1000000000
`,
{}
);
});
it('9: should handle a complex example with multiple features', () => {
imgSnapshotTest(
`---
config:
theme: dark
treemap:
valueFormat: "$0,0"
---
treemap-beta
"Company Budget"
"Engineering":::engineering
"Frontend": 300000
"Backend": 400000
"DevOps": 200000
"Marketing":::marketing
"Digital": 250000
"Print": 100000
"Events": 150000
"Sales":::sales
"Direct": 500000
"Channel": 300000
classDef engineering fill:#6b9bc3,stroke:#333;
classDef marketing fill:#c36b9b,stroke:#333;
classDef sales fill:#c3a66b,stroke:#333;
`,
{}
);
});
it('10: should render the example from documentation', () => {
imgSnapshotTest(
`
treemap-beta
"Section 1"
"Leaf 1.1": 12
"Section 1.2":::class1
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20:::class1
"Leaf 2.2": 25
"Leaf 2.3": 12
classDef class1 fill:red,color:blue,stroke:#FFD600;
`,
{}
);
});
it('11: should handle comments', () => {
imgSnapshotTest(
`
treemap-beta
%% This is a comment
"Category A"
"Item A1": 10
"Item A2": 20
%% Another comment
"Category B"
"Item B1": 15
"Item B2": 25
`,
{}
);
});
/*
it.skip('12: should render a treemap with title', () => {
imgSnapshotTest(
`
treemap-beta
title Treemap with Title
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
`,
{}
);
});
it.skip('13: should render a treemap with accessibility attributes', () => {
imgSnapshotTest(
`
treemap-beta
accTitle: Accessible Treemap Title
accDescr: This is a description of the treemap for accessibility purposes
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
`,
{}
);
});
it.skip('14: should render a treemap with title and accessibility attributes', () => {
imgSnapshotTest(
`
treemap
title Treemap with Title and Accessibility
accTitle: Accessible Treemap Title
accDescr: This is a description of the treemap for accessibility purposes
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
`,
{}
);
});
*/
});

View File

@@ -32,8 +32,26 @@
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
rel="stylesheet"
/>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Recursive:wght@300..1000&display=swap"
rel="stylesheet"
/>
<style>
.recursive-mermaid {
font-family: 'Recursive', sans-serif;
font-optical-sizing: auto;
font-weight: 500;
font-style: normal;
font-variation-settings:
'slnt' 0,
'CASL' 0,
'CRSV' 0.5,
'MONO' 0;
}
body {
/* background: rgb(221, 208, 208); */
/* background: #333; */
@@ -45,7 +63,9 @@
h1 {
color: grey;
}
.mermaid {
border: 1px solid red;
}
.mermaid2 {
display: none;
}
@@ -83,6 +103,11 @@
width: 100%;
}
.class2 {
fill: red;
fill-opacity: 1;
}
/* tspan {
font-size: 6px !important;
} */
@@ -106,19 +131,63 @@
<body>
<pre id="diagram4" class="mermaid">
treemap
"Section 1"
"Leaf 1.1": 12
"Section 1.2":::class1
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20:::class1
"Leaf 2.2": 25
"Leaf 2.3": 12
classDef class1 fill:red,color:blue,stroke:#FFD600;
</pre
>
<pre id="diagram4" class="mermaid2">
---
config:
treemap:
valueFormat: '$0,0'
---
treemap
"Budget"
"Operations"
"Salaries": 7000
"Equipment": 2000
"Supplies": 1000
"Marketing"
"Advertising": 4000
"Events": 1000
</pre
>
<pre id="diagram4" class="mermaid">
treemap
title Accessible Treemap Title
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
</pre>
<pre id="diagram4" class="mermaid2">
flowchart LR
AB["apa@apa@"] --> B(("`apa@apa`"))
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart
D(("for D"))
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
A e1@==> B
e1@{ animate: true}
</pre>
<pre id="diagram4" class="mermaid">
<pre id="diagram4" class="mermaid2">
flowchart LR
A e1@--> B
classDef animate stroke-width:2,stroke-dasharray:10\,8,stroke-dashoffset:-180,animation: edge-animation-frame 6s linear infinite, stroke-linecap: round
@@ -438,7 +507,7 @@ kanban
alert('It worked');
}
await mermaid.initialize({
// theme: 'base',
// theme: 'forest',
// theme: 'default',
// theme: 'forest',
// handDrawnSeed: 12,
@@ -449,11 +518,7 @@ kanban
// layout: 'fixed',
// htmlLabels: false,
flowchart: { titleTopMargin: 10 },
// fontFamily: 'Caveat',
// fontFamily: 'Kalam',
// fontFamily: 'courier',
fontFamily: 'arial',
fontFamily: "'Recursive', sans-serif",
sequence: {
actorFontFamily: 'courier',
noteFontFamily: 'courier',

75
demos/treemap.html Normal file
View File

@@ -0,0 +1,75 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Mermaid Treemap Diagram Demo</title>
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
<style>
body {
font-family: 'Montserrat', sans-serif;
margin: 0 auto;
max-width: 900px;
padding: 20px;
}
.mermaid {
margin: 30px 0;
}
h1,
h2 {
color: #333;
}
pre {
background-color: #f5f5f5;
padding: 15px;
border-radius: 5px;
}
</style>
</head>
<body>
<h1>Treemap Diagram Demo</h1>
<p>This is a demo of the new treemap diagram type in Mermaid.</p>
<h2>Basic Treemap Example</h2>
<pre class="mermaid">
treemap
"Root"
"Branch 1"
"Leaf 1.1": 10
"Leaf 1.2": 15
"Branch 2"
"Branch 2.1"
"Leaf 2.1.1": 20
"Leaf 2.1.2": 25
"Leaf 2.2": 25
"Leaf 2.3": 30
</pre>
<h2>Technology Stack Treemap Example</h2>
<pre class="mermaid">
treemap
"Technology Stack"
"Frontend"
"React": 35
"CSS": 15
"HTML": 10
"Backend"
"Node.js": 25
"Express": 10
"MongoDB": 15
"DevOps"
"Docker": 10
"Kubernetes": 15
"CI/CD": 5
</pre>
<script type="module">
import mermaid from './mermaid.esm.mjs';
mermaid.initialize({
theme: 'forest',
logLevel: 1,
securityLevel: 'loose',
});
</script>
</body>
</html>

View File

@@ -12,4 +12,4 @@
> `const` **configKeys**: `Set`<`string`>
Defined in: [packages/mermaid/src/defaultConfig.ts:278](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L278)
Defined in: [packages/mermaid/src/defaultConfig.ts:290](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L290)

View File

@@ -245,7 +245,7 @@ Communication tools and platforms
| GitHub + Mermaid | - | [🦊🔗](https://addons.mozilla.org/firefox/addon/github-mermaid/) | - | - | [🐙🔗](https://github.com/BackMarket/github-mermaid-extension) |
| Asciidoctor Live Preview | [🎡🔗](https://chromewebstore.google.com/detail/asciidoctorjs-live-previe/iaalpfgpbocpdfblpnhhgllgbdbchmia) | - | - | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/asciidoctorjs-live-previ/pefkelkanablhjdekgdahplkccnbdggd?hl=en-US) | - |
| Diagram Tab | - | - | - | - | [🐙🔗](https://github.com/khafast/diagramtab) |
| Markdown Diagrams | [🎡🔗](https://chromewebstore.google.com/detail/markdown-diagrams/pmoglnmodacnbbofbgcagndelmgaclel) | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-diagrams/) | [🔴🔗](https://addons.opera.com/en/extensions/details/markdown-diagrams/) | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/markdown-diagrams/hceenoomhhdkjjijnmlclkpenkapfihe) | [🐙🔗](https://github.com/marcozaccari/markdown-diagrams-browser-extension/tree/master/doc/examples) |
| Markdown Diagrams | [🎡🔗](https://chromewebstore.google.com/detail/markdown-diagrams/pmoglnmodacnbbofbgcagndelmgaclel) | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-diagrams/) | - | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/markdown-diagrams/hceenoomhhdkjjijnmlclkpenkapfihe) | [🐙🔗](https://github.com/marcozaccari/markdown-diagrams-browser-extension/tree/master/doc/examples) |
| Markdown Viewer | - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | - | - | [🐙🔗](https://github.com/simov/markdown-viewer) |
| Extensions for Mermaid | - | - | [🔴🔗](https://addons.opera.com/en/extensions/details/extensions-for-mermaid/) | - | [🐙🔗](https://github.com/Stefan-S/mermaid-extension) |
| Chrome Diagrammer | [🎡🔗](https://chromewebstore.google.com/detail/chrome-diagrammer/bkpbgjmkomfoakfklcjeoegkklgjnnpk) | - | - | - | - |
@@ -270,5 +270,6 @@ Communication tools and platforms
- [reveal.js-mermaid-plugin](https://github.com/ludwick/reveal.js-mermaid-plugin)
- [Reveal CK](https://github.com/jedcn/reveal-ck)
- [reveal-ck-mermaid-plugin](https://github.com/tmtm/reveal-ck-mermaid-plugin)
- [Vitepress Plugin](https://github.com/sametcn99/vitepress-mermaid-renderer)
<!--- cspell:ignore Blazorade HueHive --->

View File

@@ -30,7 +30,7 @@ Try the Ultimate AI, Mermaid, and Visual Diagramming Suite by creating an accoun
Official Mermaid Chart plugins:
- [Mermaid Chart GPT](https://chat.openai.com/g/g-1IRFKwq4G-mermaid-chart)
- [Mermaid Chart GPT](https://chatgpt.com/g/g-684cc36f30208191b21383b88650a45d-mermaid-chart-diagrams-and-charts)
- [Confluence](https://marketplace.atlassian.com/apps/1234056/mermaid-chart-for-confluence?hosting=cloud&tab=overview)
- [Jira](https://marketplace.atlassian.com/apps/1234810/mermaid-chart-for-jira?tab=overview&hosting=cloud)
- [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=MermaidChart.vscode-mermaid-chart)

View File

@@ -1949,7 +1949,7 @@ flowchart TD
There are two ways to display these FontAwesome icons:
### Register FontAwesome icon packs (v\<MERMAID_RELEASE_VERSION>+)
### Register FontAwesome icon packs (v11.7.0+)
You can register your own FontAwesome icon pack following the ["Registering icon packs" instructions](../config/icons.md).

View File

@@ -23,7 +23,7 @@ start-end: "Block name" %% Multi-bit blocks
... More Fields ...
```
### Bits Syntax (v\<MERMAID_RELEASE_VERSION>+)
### Bits Syntax (v11.7.0+)
Using start and end bit counts can be difficult, especially when modifying a design. For this we add a bit count field, which starts from the end of the previous field automagically. Use `+<count>` to set the number of bits, thus:

353
docs/syntax/treemap.md Normal file
View File

@@ -0,0 +1,353 @@
> **Warning**
>
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
>
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/syntax/treemap.md](../../packages/mermaid/src/docs/syntax/treemap.md).
# Treemap Diagram
> A treemap diagram displays hierarchical data as a set of nested rectangles. Each branch of the tree is represented by a rectangle, which is then tiled with smaller rectangles representing sub-branches.
> **Warning**
> This is a new diagram type in Mermaid. Its syntax may evolve in future versions.
## Introduction
Treemap diagrams are an effective way to visualize hierarchical data and show proportions between categories and subcategories. The size of each rectangle is proportional to the value it represents, making it easy to compare different parts of a hierarchy.
Treemap diagrams are particularly useful for:
- Visualizing hierarchical data structures
- Comparing proportions between categories
- Displaying large amounts of hierarchical data in a limited space
- Identifying patterns and outliers in hierarchical data
## Syntax
```
treemap-beta
"Section 1"
"Leaf 1.1": 12
"Section 1.2"
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20
"Leaf 2.2": 25
```
### Node Definition
Nodes in a treemap are defined using the following syntax:
- **Section/Parent nodes**: Defined with quoted text `"Section Name"`
- **Leaf nodes with values**: Defined with quoted text followed by a colon and value `"Leaf Name": value`
- **Hierarchy**: Created using indentation (spaces or tabs)
- **Styling**: Nodes can be styled using the `:::class` syntax
## Examples
### Basic Treemap
```mermaid-example
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
```
```mermaid
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
```
### Hierarchical Treemap
```mermaid-example
treemap-beta
"Products"
"Electronics"
"Phones": 50
"Computers": 30
"Accessories": 20
"Clothing"
"Men's": 40
"Women's": 40
```
```mermaid
treemap-beta
"Products"
"Electronics"
"Phones": 50
"Computers": 30
"Accessories": 20
"Clothing"
"Men's": 40
"Women's": 40
```
### Treemap with Styling
```mermaid-example
treemap-beta
"Section 1"
"Leaf 1.1": 12
"Section 1.2":::class1
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20:::class1
"Leaf 2.2": 25
"Leaf 2.3": 12
classDef class1 fill:red,color:blue,stroke:#FFD600;
```
```mermaid
treemap-beta
"Section 1"
"Leaf 1.1": 12
"Section 1.2":::class1
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20:::class1
"Leaf 2.2": 25
"Leaf 2.3": 12
classDef class1 fill:red,color:blue,stroke:#FFD600;
```
## Styling and Configuration
Treemap diagrams can be customized using Mermaid's styling and configuration options.
### Using classDef for Styling
You can define custom styles for nodes using the `classDef` syntax, which is a standard feature across many Mermaid diagram types:
```mermaid-example
treemap-beta
"Main"
"A": 20
"B":::important
"B1": 10
"B2": 15
"C": 5
classDef important fill:#f96,stroke:#333,stroke-width:2px;
```
```mermaid
treemap-beta
"Main"
"A": 20
"B":::important
"B1": 10
"B2": 15
"C": 5
classDef important fill:#f96,stroke:#333,stroke-width:2px;
```
### Theme Configuration
You can customize the colors of your treemap using the theme configuration:
```mermaid-example
---
config:
theme: 'forest'
---
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
```
```mermaid
---
config:
theme: 'forest'
---
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
```
### Diagram Padding
You can adjust the padding around the treemap diagram using the `diagramPadding` configuration option:
```mermaid-example
---
config:
treemap:
diagramPadding: 200
---
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
```
```mermaid
---
config:
treemap:
diagramPadding: 200
---
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
```
## Configuration Options
The treemap diagram supports the following configuration options:
| Option | Description | Default |
| -------------- | --------------------------------------------------------------------------- | ------- |
| useMaxWidth | When true, the diagram width is set to 100% and scales with available space | true |
| padding | Internal padding between nodes | 10 |
| diagramPadding | Padding around the entire diagram | 8 |
| showValues | Whether to show values in the treemap | true |
| nodeWidth | Width of nodes | 100 |
| nodeHeight | Height of nodes | 40 |
| borderWidth | Width of borders | 1 |
| valueFontSize | Font size for values | 12 |
| labelFontSize | Font size for labels | 14 |
| valueFormat | Format for values (see Value Formatting section) | ',' |
## Advanced Features
### Value Formatting
Values in treemap diagrams can be formatted to display in different ways using the `valueFormat` configuration option. This option primarily uses [D3's format specifiers](https://github.com/d3/d3-format#locale_format) to control how numbers are displayed, with some additional special cases for common formats.
Some common format patterns:
- `,` - Thousands separator (default)
- `$` - Add dollar sign
- `.1f` - Show one decimal place
- `.1%` - Show as percentage with one decimal place
- `$0,0` - Dollar sign with thousands separator
- `$.2f` - Dollar sign with 2 decimal places
- `$,.2f` - Dollar sign with thousands separator and 2 decimal places
The treemap diagram supports both standard D3 format specifiers and some common currency formats that combine the dollar sign with other formatting options.
Example with currency formatting:
```mermaid-example
---
config:
treemap:
valueFormat: '$0,0'
---
treemap-beta
"Budget"
"Operations"
"Salaries": 700000
"Equipment": 200000
"Supplies": 100000
"Marketing"
"Advertising": 400000
"Events": 100000
```
```mermaid
---
config:
treemap:
valueFormat: '$0,0'
---
treemap-beta
"Budget"
"Operations"
"Salaries": 700000
"Equipment": 200000
"Supplies": 100000
"Marketing"
"Advertising": 400000
"Events": 100000
```
Example with percentage formatting:
```mermaid-example
---
config:
treemap:
valueFormat: '$.1%'
---
treemap-beta
"Market Share"
"Company A": 0.35
"Company B": 0.25
"Company C": 0.15
"Others": 0.25
```
```mermaid
---
config:
treemap:
valueFormat: '$.1%'
---
treemap-beta
"Market Share"
"Company A": 0.35
"Company B": 0.25
"Company C": 0.15
"Others": 0.25
```
## Common Use Cases
Treemap diagrams are commonly used for:
1. **Financial Data**: Visualizing budget allocations, market shares, or portfolio compositions
2. **File System Analysis**: Showing disk space usage by folders and files
3. **Population Demographics**: Displaying population distribution across regions and subregions
4. **Product Hierarchies**: Visualizing product categories and their sales volumes
5. **Organizational Structures**: Representing departments and team sizes in a company
## Limitations
- Treemap diagrams work best when the data has a natural hierarchy
- Very small values may be difficult to see or label in a treemap diagram
- Deep hierarchies (many levels) can be challenging to represent clearly
- Treemap diagrams are not well suited for representing data with negative values
## Related Diagrams
If treemap diagrams don't suit your needs, consider these alternatives:
- [**Pie Charts**](./pie.md): For simple proportion comparisons without hierarchy
- **Sunburst Diagrams**: For hierarchical data with a radial layout (yet to be released in Mermaid).
- [**Sankey Diagrams**](./sankey.md): For flow-based hierarchical data
## Notes
The treemap diagram implementation in Mermaid is designed to be simple to use while providing powerful visualization capabilities. As this is a newer diagram type, feedback and feature requests are welcome through the Mermaid GitHub repository.

View File

@@ -83,7 +83,7 @@
"@vitest/spy": "^3.0.6",
"@vitest/ui": "^3.0.6",
"ajv": "^8.17.1",
"chokidar": "^4.0.3",
"chokidar": "3.6.0",
"concurrently": "^9.1.2",
"cors": "^2.8.5",
"cpy-cli": "^5.0.0",

View File

@@ -1,5 +1,14 @@
# @mermaid-js/layout-elk
## 0.1.8
### Patch Changes
- [#6648](https://github.com/mermaid-js/mermaid/pull/6648) [`85c5b9b`](https://github.com/mermaid-js/mermaid/commit/85c5b9b4c064e2edabf21757c8215a1018d4d288) Thanks [@knsv](https://github.com/knsv)! - Make elk respect the order of nodes based from the code
- Updated dependencies [[`97b79c3`](https://github.com/mermaid-js/mermaid/commit/97b79c3578a2004c63fa32f6d5e17bd8a536e13a), [`b1cf291`](https://github.com/mermaid-js/mermaid/commit/b1cf29127348602137552405e3300dee1697f0de), [`a4754ad`](https://github.com/mermaid-js/mermaid/commit/a4754ad195e70d52fbd46ef44f40797d2d215e41), [`2b05d7e`](https://github.com/mermaid-js/mermaid/commit/2b05d7e1edef635e6c80cb383b10ea0a89279f41), [`41e84b7`](https://github.com/mermaid-js/mermaid/commit/41e84b726a1f2df002b77c4b0071e2c15e47838e), [`d63d3bf`](https://github.com/mermaid-js/mermaid/commit/d63d3bf1e7596ac7eeb24ba06cbc7a70f9c8b070), [`aa6cb86`](https://github.com/mermaid-js/mermaid/commit/aa6cb86899968c65561eebfc1d54dd086b1518a2), [`df9df9d`](https://github.com/mermaid-js/mermaid/commit/df9df9dc32b80a8c320cc0efd5483b9485f15bde), [`cdbd3e5`](https://github.com/mermaid-js/mermaid/commit/cdbd3e58a3a35d63a79258115dedca4a535c1038), [`c17277e`](https://github.com/mermaid-js/mermaid/commit/c17277e743b1c12e4134fba44c62a7d5885f2574), [`a1ba65c`](https://github.com/mermaid-js/mermaid/commit/a1ba65c0c08432ec36e772570c3a5899cb57c102), [`1ddaf10`](https://github.com/mermaid-js/mermaid/commit/1ddaf10b89d8c7311c5e10d466b42fa36b61210b), [`ca80f71`](https://github.com/mermaid-js/mermaid/commit/ca80f719eac86cf4c31392105d5d896f39b84bbc), [`bca6ed6`](https://github.com/mermaid-js/mermaid/commit/bca6ed67c3e0db910bf498fdd0fc0346c02d392b)]:
- mermaid@11.7.0
## 0.1.7
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@mermaid-js/layout-elk",
"version": "0.1.7",
"version": "0.1.8",
"description": "ELK layout engine for mermaid",
"module": "dist/mermaid-layout-elk.core.mjs",
"types": "dist/layouts.d.ts",

View File

@@ -0,0 +1,14 @@
# @mermaid-js/mermaid-zenuml
## 0.2.1
### Patch Changes
- [#6581](https://github.com/mermaid-js/mermaid/pull/6581) [`941bc69`](https://github.com/mermaid-js/mermaid/commit/941bc698350bd103b2a431ed8fed0c7b0d92fff0) Thanks [@MrCoder](https://github.com/MrCoder)! - Upgraded the dependency @zenuml/core
- [#6319](https://github.com/mermaid-js/mermaid/pull/6319) [`9d06d8f`](https://github.com/mermaid-js/mermaid/commit/9d06d8f31e7f12af9e9e092214f907f2dc93ad75) Thanks [@renovate](https://github.com/apps/renovate)! - chore: bump minimum ZenUML version to 3.23.28
- [#5737](https://github.com/mermaid-js/mermaid/pull/5737) [`0ad44c1`](https://github.com/mermaid-js/mermaid/commit/0ad44c12feead9d20c6a870a49327ada58d6e657) Thanks [@sidharthv96](https://github.com/sidharthv96)! - fix(zenuml): limit `peerDependencies` to Mermaid v10 and v11
- Updated dependencies [[`97b79c3`](https://github.com/mermaid-js/mermaid/commit/97b79c3578a2004c63fa32f6d5e17bd8a536e13a), [`b1cf291`](https://github.com/mermaid-js/mermaid/commit/b1cf29127348602137552405e3300dee1697f0de), [`a4754ad`](https://github.com/mermaid-js/mermaid/commit/a4754ad195e70d52fbd46ef44f40797d2d215e41), [`2b05d7e`](https://github.com/mermaid-js/mermaid/commit/2b05d7e1edef635e6c80cb383b10ea0a89279f41), [`41e84b7`](https://github.com/mermaid-js/mermaid/commit/41e84b726a1f2df002b77c4b0071e2c15e47838e), [`d63d3bf`](https://github.com/mermaid-js/mermaid/commit/d63d3bf1e7596ac7eeb24ba06cbc7a70f9c8b070), [`aa6cb86`](https://github.com/mermaid-js/mermaid/commit/aa6cb86899968c65561eebfc1d54dd086b1518a2), [`df9df9d`](https://github.com/mermaid-js/mermaid/commit/df9df9dc32b80a8c320cc0efd5483b9485f15bde), [`cdbd3e5`](https://github.com/mermaid-js/mermaid/commit/cdbd3e58a3a35d63a79258115dedca4a535c1038), [`c17277e`](https://github.com/mermaid-js/mermaid/commit/c17277e743b1c12e4134fba44c62a7d5885f2574), [`a1ba65c`](https://github.com/mermaid-js/mermaid/commit/a1ba65c0c08432ec36e772570c3a5899cb57c102), [`1ddaf10`](https://github.com/mermaid-js/mermaid/commit/1ddaf10b89d8c7311c5e10d466b42fa36b61210b), [`ca80f71`](https://github.com/mermaid-js/mermaid/commit/ca80f719eac86cf4c31392105d5d896f39b84bbc), [`bca6ed6`](https://github.com/mermaid-js/mermaid/commit/bca6ed67c3e0db910bf498fdd0fc0346c02d392b)]:
- mermaid@11.7.0

View File

@@ -1,6 +1,6 @@
{
"name": "@mermaid-js/mermaid-zenuml",
"version": "0.3.0",
"version": "0.2.1",
"description": "MermaidJS plugin for ZenUML integration",
"module": "dist/mermaid-zenuml.core.mjs",
"types": "dist/detector.d.ts",

View File

@@ -1,5 +1,44 @@
# mermaid
## 11.7.0
### Minor Changes
- [#6479](https://github.com/mermaid-js/mermaid/pull/6479) [`97b79c3`](https://github.com/mermaid-js/mermaid/commit/97b79c3578a2004c63fa32f6d5e17bd8a536e13a) Thanks [@monicanguyen25](https://github.com/monicanguyen25)! - feat: Add Vertical Line To Gantt Plot At Specified Time
- [#6225](https://github.com/mermaid-js/mermaid/pull/6225) [`41e84b7`](https://github.com/mermaid-js/mermaid/commit/41e84b726a1f2df002b77c4b0071e2c15e47838e) Thanks [@Shahir-47](https://github.com/Shahir-47)! - feat: Add support for styling Journey Diagram title (color, font-family, and font-size)
- [#6423](https://github.com/mermaid-js/mermaid/pull/6423) [`aa6cb86`](https://github.com/mermaid-js/mermaid/commit/aa6cb86899968c65561eebfc1d54dd086b1518a2) Thanks [@BambioGaming](https://github.com/BambioGaming)! - Added support for the click directive in stateDiagram syntax
- [#5980](https://github.com/mermaid-js/mermaid/pull/5980) [`df9df9d`](https://github.com/mermaid-js/mermaid/commit/df9df9dc32b80a8c320cc0efd5483b9485f15bde) Thanks [@BryanCrotazGivEnergy](https://github.com/BryanCrotazGivEnergy)! - feat: Add shorter `+<count>: Label` syntax in packet diagram
- [#6523](https://github.com/mermaid-js/mermaid/pull/6523) [`c17277e`](https://github.com/mermaid-js/mermaid/commit/c17277e743b1c12e4134fba44c62a7d5885f2574) Thanks [@NourBenz](https://github.com/NourBenz)! - fix: allow sequence diagram arrows with a trailing colon but no message
- [#6475](https://github.com/mermaid-js/mermaid/pull/6475) [`a1ba65c`](https://github.com/mermaid-js/mermaid/commit/a1ba65c0c08432ec36e772570c3a5899cb57c102) Thanks [@Shahir-47](https://github.com/Shahir-47)! - feat: Dynamically Render Data Labels Within Bar Charts
### Patch Changes
- [#6588](https://github.com/mermaid-js/mermaid/pull/6588) [`b1cf291`](https://github.com/mermaid-js/mermaid/commit/b1cf29127348602137552405e3300dee1697f0de) Thanks [@omkarht](https://github.com/omkarht)! - Fix stroke styles for ER diagram to correctly apply path and row-specific styles
- [#6296](https://github.com/mermaid-js/mermaid/pull/6296) [`a4754ad`](https://github.com/mermaid-js/mermaid/commit/a4754ad195e70d52fbd46ef44f40797d2d215e41) Thanks [@sidharthv96](https://github.com/sidharthv96)! - chore: Convert StateDB into TypeScript
- [#6463](https://github.com/mermaid-js/mermaid/pull/6463) [`2b05d7e`](https://github.com/mermaid-js/mermaid/commit/2b05d7e1edef635e6c80cb383b10ea0a89279f41) Thanks [@AaronMoat](https://github.com/AaronMoat)! - fix: Remove incorrect `style="undefined;"` attributes in some Mermaid diagrams
- [#6282](https://github.com/mermaid-js/mermaid/pull/6282) [`d63d3bf`](https://github.com/mermaid-js/mermaid/commit/d63d3bf1e7596ac7eeb24ba06cbc7a70f9c8b070) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - FontAwesome icons can now be embedded as SVGs in flowcharts if they are registered via `mermaid.registerIconPacks`.
- [#6407](https://github.com/mermaid-js/mermaid/pull/6407) [`cdbd3e5`](https://github.com/mermaid-js/mermaid/commit/cdbd3e58a3a35d63a79258115dedca4a535c1038) Thanks [@thomascizeron](https://github.com/thomascizeron)! - Refactor grammar so that title don't break Architecture Diagrams
- [#6343](https://github.com/mermaid-js/mermaid/pull/6343) [`1ddaf10`](https://github.com/mermaid-js/mermaid/commit/1ddaf10b89d8c7311c5e10d466b42fa36b61210b) Thanks [@jeswr](https://github.com/jeswr)! - fix: allow colons in events
- [#6616](https://github.com/mermaid-js/mermaid/pull/6616) [`ca80f71`](https://github.com/mermaid-js/mermaid/commit/ca80f719eac86cf4c31392105d5d896f39b84bbc) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(timeline): ensure consistent vertical line lengths with visible arrowheads
Fixed timeline diagrams where vertical dashed lines from tasks had inconsistent lengths. All vertical lines now extend to the same depth regardless of the number of events in each column, with sufficient padding to clearly display both the dashed line pattern and complete arrowheads.
- [#6566](https://github.com/mermaid-js/mermaid/pull/6566) [`bca6ed6`](https://github.com/mermaid-js/mermaid/commit/bca6ed67c3e0db910bf498fdd0fc0346c02d392b) Thanks [@arpitjain099](https://github.com/arpitjain099)! - fix: Fix incomplete string escaping in URL manipulation logic when `arrowMarkerAbsolute: true` by ensuring all unsafe characters are escaped.
- Updated dependencies [[`df9df9d`](https://github.com/mermaid-js/mermaid/commit/df9df9dc32b80a8c320cc0efd5483b9485f15bde), [`cdbd3e5`](https://github.com/mermaid-js/mermaid/commit/cdbd3e58a3a35d63a79258115dedca4a535c1038)]:
- @mermaid-js/parser@0.5.0
## 11.6.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "mermaid",
"version": "11.6.0",
"version": "11.7.0",
"description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
"type": "module",
"module": "./dist/mermaid.core.mjs",
@@ -105,7 +105,7 @@
"@types/stylis": "^4.2.7",
"@types/uuid": "^10.0.0",
"ajv": "^8.17.1",
"chokidar": "^4.0.3",
"chokidar": "3.6.0",
"concurrently": "^9.1.2",
"csstree-validator": "^4.0.1",
"globby": "^14.0.2",

View File

@@ -262,6 +262,18 @@ const config: RequiredDeep<MermaidConfig> = {
radar: {
...defaultConfigJson.radar,
},
treemap: {
useMaxWidth: true,
padding: 10,
diagramPadding: 8,
showValues: true,
nodeWidth: 100,
nodeHeight: 40,
borderWidth: 1,
valueFontSize: 12,
labelFontSize: 14,
valueFormat: ',',
},
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any

View File

@@ -27,6 +27,7 @@ import block from '../diagrams/block/blockDetector.js';
import architecture from '../diagrams/architecture/architectureDetector.js';
import { registerLazyLoadedDiagrams } from './detectType.js';
import { registerDiagram } from './diagramAPI.js';
import { treemap } from '../diagrams/treemap/detector.js';
import '../type.d.ts';
let hasLoadedDiagrams = false;
@@ -99,6 +100,7 @@ export const addDiagrams = () => {
packet,
xychart,
block,
radar
radar,
treemap
);
};

View File

@@ -0,0 +1,112 @@
import { getConfig as commonGetConfig } from '../../config.js';
import DEFAULT_CONFIG from '../../defaultConfig.js';
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
import { isLabelStyle } from '../../rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import { cleanAndMerge } from '../../utils.js';
import { ImperativeState } from '../../utils/imperativeState.js';
import {
clear as commonClear,
getAccDescription,
getAccTitle,
getDiagramTitle,
setAccDescription,
setAccTitle,
setDiagramTitle,
} from '../common/commonDb.js';
import type { TreemapDB, TreemapData, TreemapDiagramConfig, TreemapNode } from './types.js';
const defaultTreemapData: TreemapData = {
nodes: [],
levels: new Map(),
outerNodes: [],
classes: new Map(),
};
const state = new ImperativeState<TreemapData>(() => structuredClone(defaultTreemapData));
const getConfig = (): Required<TreemapDiagramConfig> => {
// Use type assertion with unknown as intermediate step
const defaultConfig = DEFAULT_CONFIG as unknown as { treemap: Required<TreemapDiagramConfig> };
const userConfig = commonGetConfig() as unknown as { treemap?: Partial<TreemapDiagramConfig> };
return cleanAndMerge({
...defaultConfig.treemap,
...(userConfig.treemap ?? {}),
}) as Required<TreemapDiagramConfig>;
};
const getNodes = (): TreemapNode[] => state.records.nodes;
const addNode = (node: TreemapNode, level: number) => {
const data = state.records;
data.nodes.push(node);
data.levels.set(node, level);
if (level === 0) {
data.outerNodes.push(node);
}
// Set the root node if this is a level 0 node and we don't have a root yet
if (level === 0 && !data.root) {
data.root = node;
}
};
const getRoot = (): TreemapNode | undefined => ({ name: '', children: state.records.outerNodes });
const addClass = (id: string, _style: string) => {
const classes = state.records.classes;
const styleClass = classes.get(id) ?? { id, styles: [], textStyles: [] };
classes.set(id, styleClass);
const styles = _style.replace(/\\,/g, '§§§').replace(/,/g, ';').replace(/§§§/g, ',').split(';');
if (styles) {
styles.forEach((s) => {
if (isLabelStyle(s)) {
if (styleClass?.textStyles) {
styleClass.textStyles.push(s);
} else {
styleClass.textStyles = [s];
}
}
if (styleClass?.styles) {
styleClass.styles.push(s);
} else {
styleClass.styles = [s];
}
});
}
classes.set(id, styleClass);
};
const getClasses = (): Map<string, DiagramStyleClassDef> => {
return state.records.classes;
};
const getStylesForClass = (classSelector: string): string[] => {
return state.records.classes.get(classSelector)?.styles ?? [];
};
const clear = () => {
commonClear();
state.reset();
};
export const db: TreemapDB = {
getNodes,
addNode,
getRoot,
getConfig,
clear,
setAccTitle,
getAccTitle,
setDiagramTitle,
getDiagramTitle,
getAccDescription,
setAccDescription,
addClass,
getClasses,
getStylesForClass,
};

View File

@@ -0,0 +1,22 @@
import type {
DiagramDetector,
DiagramLoader,
ExternalDiagramDefinition,
} from '../../diagram-api/types.js';
const id = 'treemap';
const detector: DiagramDetector = (txt) => {
return /^\s*treemap/.test(txt);
};
const loader: DiagramLoader = async () => {
const { diagram } = await import('./diagram.js');
return { id, diagram };
};
export const treemap: ExternalDiagramDefinition = {
id,
detector,
loader,
};

View File

@@ -0,0 +1,12 @@
import type { DiagramDefinition } from '../../diagram-api/types.js';
import { db } from './db.js';
import { parser } from './parser.js';
import { renderer } from './renderer.js';
import styles from './styles.js';
export const diagram: DiagramDefinition = {
parser,
db,
renderer,
styles,
};

View File

@@ -0,0 +1,100 @@
import { parse } from '@mermaid-js/parser';
import type { ParserDefinition } from '../../diagram-api/types.js';
import { log } from '../../logger.js';
import { populateCommonDb } from '../common/populateCommonDb.js';
import { db } from './db.js';
import type { TreemapNode, TreemapAst } from './types.js';
import { buildHierarchy } from './utils.js';
/**
* Populates the database with data from the Treemap AST
* @param ast - The Treemap AST
*/
const populate = (ast: TreemapAst) => {
// We need to bypass the type checking for populateCommonDb
// eslint-disable-next-line @typescript-eslint/no-explicit-any
populateCommonDb(ast as any, db);
const items: {
level: number;
name: string;
type: string;
value?: number;
classSelector?: string;
cssCompiledStyles?: string;
}[] = [];
// Extract classes and styles from the treemap
for (const row of ast.TreemapRows ?? []) {
if (row.$type === 'ClassDefStatement') {
db.addClass(row.className ?? '', row.styleText ?? '');
}
}
// Extract data from each row in the treemap
for (const row of ast.TreemapRows ?? []) {
const item = row.item;
if (!item) {
continue;
}
const level = row.indent ? parseInt(row.indent) : 0;
const name = getItemName(item);
// Get styles as a string if they exist
const styles = item.classSelector ? db.getStylesForClass(item.classSelector) : [];
const cssCompiledStyles = styles.length > 0 ? styles.join(';') : undefined;
const itemData = {
level,
name,
type: item.$type,
value: item.value,
classSelector: item.classSelector,
cssCompiledStyles,
};
items.push(itemData);
}
// Convert flat structure to hierarchical
const hierarchyNodes = buildHierarchy(items);
// Add all nodes to the database
const addNodesRecursively = (nodes: TreemapNode[], level: number) => {
for (const node of nodes) {
db.addNode(node, level);
if (node.children && node.children.length > 0) {
addNodesRecursively(node.children, level + 1);
}
}
};
addNodesRecursively(hierarchyNodes, 0);
};
/**
* Gets the name of a treemap item
* @param item - The treemap item
* @returns The name of the item
*/
const getItemName = (item: { name?: string | number }): string => {
return item.name ? String(item.name) : '';
};
export const parser: ParserDefinition = {
parse: async (text: string): Promise<void> => {
try {
// Use a generic parse that accepts any diagram type
const parseFunc = parse as (diagramType: string, text: string) => Promise<TreemapAst>;
const ast = await parseFunc('treemap', text);
log.debug('Treemap AST:', ast);
populate(ast);
} catch (error) {
log.error('Error parsing treemap:', error);
throw error;
}
},
};

View File

@@ -0,0 +1,526 @@
import type { Diagram } from '../../Diagram.js';
import type {
DiagramRenderer,
DiagramStyleClassDef,
DrawDefinition,
} from '../../diagram-api/types.js';
import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js';
import { configureSvgSize } from '../../setupGraphViewbox.js';
import type { TreemapDB, TreemapNode } from './types.js';
import { scaleOrdinal, treemap, hierarchy, format, select } from 'd3';
import { styles2String } from '../../rendering-util/rendering-elements/shapes/handDrawnShapeStyles.js';
import { getConfig } from '../../config.js';
import { log } from '../../logger.js';
import type { Node } from '../../rendering-util/types.js';
const DEFAULT_INNER_PADDING = 10; // Default for inner padding between cells/sections
const SECTION_INNER_PADDING = 10; // Default for inner padding between cells/sections
const SECTION_HEADER_HEIGHT = 25;
/**
* Draws the treemap diagram
*/
const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
const treemapDb = diagram.db as TreemapDB;
const config = treemapDb.getConfig();
const treemapInnerPadding = config.padding ?? DEFAULT_INNER_PADDING;
const title = treemapDb.getDiagramTitle();
const root = treemapDb.getRoot();
const { themeVariables } = getConfig();
if (!root) {
return;
}
// Define dimensions
const titleHeight = title ? 30 : 0;
const svg = selectSvgElement(id);
// Use config dimensions or defaults
const width = config.nodeWidth ? config.nodeWidth * SECTION_INNER_PADDING : 960;
const height = config.nodeHeight ? config.nodeHeight * SECTION_INNER_PADDING : 500;
const svgWidth = width;
const svgHeight = height + titleHeight;
// Set the SVG size
svg.attr('viewBox', `0 0 ${svgWidth} ${svgHeight}`);
configureSvgSize(svg, svgHeight, svgWidth, config.useMaxWidth);
// Format for displaying values
let valueFormat;
try {
// Handle special format patterns
const formatStr = config.valueFormat || ',';
// Handle special cases that aren't directly supported by D3 format
if (formatStr === '$0,0') {
// Currency with thousands separator
valueFormat = (value: number) => '$' + format(',')(value);
} else if (formatStr.startsWith('$') && formatStr.includes(',')) {
// Other dollar formats with commas
const precision = /\.\d+/.exec(formatStr);
const precisionStr = precision ? precision[0] : '';
valueFormat = (value: number) => '$' + format(',' + precisionStr)(value);
} else if (formatStr.startsWith('$')) {
// Simple dollar sign prefix
const restOfFormat = formatStr.substring(1);
valueFormat = (value: number) => '$' + format(restOfFormat || '')(value);
} else {
// Standard D3 format
valueFormat = format(formatStr);
}
} catch (error) {
log.error('Error creating format function:', error);
// Fallback to default format
valueFormat = format(',');
}
// Create color scale
const colorScale = scaleOrdinal<string>().range([
'transparent',
themeVariables.cScale0,
themeVariables.cScale1,
themeVariables.cScale2,
themeVariables.cScale3,
themeVariables.cScale4,
themeVariables.cScale5,
themeVariables.cScale6,
themeVariables.cScale7,
themeVariables.cScale8,
themeVariables.cScale9,
themeVariables.cScale10,
themeVariables.cScale11,
]);
const colorScalePeer = scaleOrdinal<string>().range([
'transparent',
themeVariables.cScalePeer0,
themeVariables.cScalePeer1,
themeVariables.cScalePeer2,
themeVariables.cScalePeer3,
themeVariables.cScalePeer4,
themeVariables.cScalePeer5,
themeVariables.cScalePeer6,
themeVariables.cScalePeer7,
themeVariables.cScalePeer8,
themeVariables.cScalePeer9,
themeVariables.cScalePeer10,
themeVariables.cScalePeer11,
]);
const colorScaleLabel = scaleOrdinal<string>().range([
themeVariables.cScaleLabel0,
themeVariables.cScaleLabel1,
themeVariables.cScaleLabel2,
themeVariables.cScaleLabel3,
themeVariables.cScaleLabel4,
themeVariables.cScaleLabel5,
themeVariables.cScaleLabel6,
themeVariables.cScaleLabel7,
themeVariables.cScaleLabel8,
themeVariables.cScaleLabel9,
themeVariables.cScaleLabel10,
themeVariables.cScaleLabel11,
]);
// Draw the title if it exists
if (title) {
svg
.append('text')
.attr('x', svgWidth / 2)
.attr('y', titleHeight / 2)
.attr('class', 'treemapTitle')
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'middle')
.text(title);
}
// Create a main container for the treemap, translated below the title
const g = svg
.append('g')
.attr('transform', `translate(0, ${titleHeight})`)
.attr('class', 'treemapContainer');
// Create the hierarchical structure
const hierarchyRoot = hierarchy<TreemapNode>(root)
.sum((d) => d.value ?? 0)
.sort((a, b) => (b.value ?? 0) - (a.value ?? 0));
// Create treemap layout
const treemapLayout = treemap<TreemapNode>()
.size([width, height])
.paddingTop((d) =>
d.children && d.children.length > 0 ? SECTION_HEADER_HEIGHT + SECTION_INNER_PADDING : 0
)
.paddingInner(treemapInnerPadding)
.paddingLeft((d) => (d.children && d.children.length > 0 ? SECTION_INNER_PADDING : 0))
.paddingRight((d) => (d.children && d.children.length > 0 ? SECTION_INNER_PADDING : 0))
.paddingBottom((d) => (d.children && d.children.length > 0 ? SECTION_INNER_PADDING : 0))
.round(true);
// Apply the treemap layout to the hierarchy
const treemapData = treemapLayout(hierarchyRoot);
// Draw section nodes (branches - nodes with children)
const branchNodes = treemapData.descendants().filter((d) => d.children && d.children.length > 0);
const sections = g
.selectAll('.treemapSection')
.data(branchNodes)
.enter()
.append('g')
.attr('class', 'treemapSection')
.attr('transform', (d) => `translate(${d.x0},${d.y0})`);
// Add section header background
sections
.append('rect')
.attr('width', (d) => d.x1 - d.x0)
.attr('height', SECTION_HEADER_HEIGHT)
.attr('class', 'treemapSectionHeader')
.attr('fill', 'none')
.attr('fill-opacity', 0.6)
.attr('stroke-width', 0.6)
.attr('style', (d) => {
// Hide the label for the root section
if (d.depth === 0) {
return 'display: none;';
}
return '';
});
// Add clip paths for section headers to prevent text overflow
sections
.append('clipPath')
.attr('id', (_d, i) => `clip-section-${id}-${i}`)
.append('rect')
.attr('width', (d) => Math.max(0, d.x1 - d.x0 - 12)) // 6px padding on each side
.attr('height', SECTION_HEADER_HEIGHT);
sections
.append('rect')
.attr('width', (d) => d.x1 - d.x0)
.attr('height', (d) => d.y1 - d.y0)
.attr('class', (_d, i) => {
return `treemapSection section${i}`;
})
.attr('fill', (d) => colorScale(d.data.name))
.attr('fill-opacity', 0.6)
.attr('stroke', (d) => colorScalePeer(d.data.name))
.attr('stroke-width', 2.0)
.attr('stroke-opacity', 0.4)
.attr('style', (d) => {
// Hide the label for the root section
if (d.depth === 0) {
return 'display: none;';
}
const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles } as Node);
return styles.nodeStyles + ';' + styles.borderStyles.join(';');
});
// Add section labels
sections
.append('text')
.attr('class', 'treemapSectionLabel')
.attr('x', 6) // Keep original left padding
.attr('y', SECTION_HEADER_HEIGHT / 2)
.attr('dominant-baseline', 'middle')
.text((d) => (d.depth === 0 ? '' : d.data.name)) // Skip label for root section
.attr('font-weight', 'bold')
.attr('style', (d) => {
// Hide the label for the root section
if (d.depth === 0) {
return 'display: none;';
}
const labelStyles =
'dominant-baseline: middle; font-size: 12px; fill:' +
colorScaleLabel(d.data.name) +
'; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;';
const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles } as Node);
return labelStyles + styles.labelStyles.replace('color:', 'fill:');
})
.each(function (d) {
// Skip processing for root section
if (d.depth === 0) {
return;
}
const self = select(this);
const originalText = d.data.name;
self.text(originalText);
const totalHeaderWidth = d.x1 - d.x0;
const labelXPosition = 6;
let spaceForTextContent;
if (config.showValues !== false && d.value) {
const valueEndsAtXRelative = totalHeaderWidth - 10;
const estimatedValueTextActualWidth = 30;
const gapBetweenLabelAndValue = 10;
const labelMustEndBeforeX =
valueEndsAtXRelative - estimatedValueTextActualWidth - gapBetweenLabelAndValue;
spaceForTextContent = labelMustEndBeforeX - labelXPosition;
} else {
const labelOwnRightPadding = 6;
spaceForTextContent = totalHeaderWidth - labelXPosition - labelOwnRightPadding;
}
const minimumWidthToDisplay = 15;
const actualAvailableWidth = Math.max(minimumWidthToDisplay, spaceForTextContent);
const textNode = self.node()!;
const currentTextContentLength = textNode.getComputedTextLength();
if (currentTextContentLength > actualAvailableWidth) {
const ellipsis = '...';
let currentTruncatedText = originalText;
while (currentTruncatedText.length > 0) {
currentTruncatedText = originalText.substring(0, currentTruncatedText.length - 1);
if (currentTruncatedText.length === 0) {
self.text(ellipsis);
if (textNode.getComputedTextLength() > actualAvailableWidth) {
self.text('');
}
break;
}
self.text(currentTruncatedText + ellipsis);
if (textNode.getComputedTextLength() <= actualAvailableWidth) {
break;
}
}
}
});
// Add section values if enabled
if (config.showValues !== false) {
sections
.append('text')
.attr('class', 'treemapSectionValue')
.attr('x', (d) => d.x1 - d.x0 - 10)
.attr('y', SECTION_HEADER_HEIGHT / 2)
.attr('text-anchor', 'end')
.attr('dominant-baseline', 'middle')
.text((d) => (d.value ? valueFormat(d.value) : ''))
.attr('font-style', 'italic')
.attr('style', (d) => {
// Hide the value for the root section
if (d.depth === 0) {
return 'display: none;';
}
const labelStyles =
'text-anchor: end; dominant-baseline: middle; font-size: 10px; fill:' +
colorScaleLabel(d.data.name) +
'; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;';
const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles } as Node);
return labelStyles + styles.labelStyles.replace('color:', 'fill:');
});
}
// Draw the leaf nodes
const leafNodes = treemapData.leaves();
const cell = g
.selectAll('.treemapLeafGroup')
.data(leafNodes)
.enter()
.append('g')
.attr('class', (d, i) => {
return `treemapNode treemapLeafGroup leaf${i}${d.data.classSelector ? ` ${d.data.classSelector}` : ''}x`;
})
.attr('transform', (d) => `translate(${d.x0},${d.y0})`);
// Add rectangle for each leaf node
cell
.append('rect')
.attr('width', (d) => d.x1 - d.x0)
.attr('height', (d) => d.y1 - d.y0)
.attr('class', 'treemapLeaf')
.attr('fill', (d) => {
// Leaves inherit color from their immediate parent section's name.
// If a leaf is the root itself (no parent), it uses its own name.
return d.parent ? colorScale(d.parent.data.name) : colorScale(d.data.name);
})
.attr('style', (d) => {
const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles } as Node);
return styles.nodeStyles;
})
.attr('fill-opacity', 0.3)
.attr('stroke', (d) => {
// Leaves inherit color from their immediate parent section's name.
// If a leaf is the root itself (no parent), it uses its own name.
return d.parent ? colorScale(d.parent.data.name) : colorScale(d.data.name);
})
.attr('stroke-width', 3.0);
// Add clip paths to prevent text from extending outside nodes
cell
.append('clipPath')
.attr('id', (_d, i) => `clip-${id}-${i}`)
.append('rect')
.attr('width', (d) => Math.max(0, d.x1 - d.x0 - 4))
.attr('height', (d) => Math.max(0, d.y1 - d.y0 - 4));
// Add node labels with clipping
const leafLabels = cell
.append('text')
.attr('class', 'treemapLabel')
.attr('x', (d) => (d.x1 - d.x0) / 2)
.attr('y', (d) => (d.y1 - d.y0) / 2)
// .style('fill', (d) => colorScaleLabel(d.data.name))
.attr('style', (d) => {
const labelStyles =
'text-anchor: middle; dominant-baseline: middle; font-size: 38px;fill:' +
colorScaleLabel(d.data.name) +
';';
const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles } as Node);
return labelStyles + styles.labelStyles.replace('color:', 'fill:');
})
.attr('clip-path', (_d, i) => `url(#clip-${id}-${i})`)
.text((d) => d.data.name);
leafLabels.each(function (d) {
const self = select(this);
const nodeWidth = d.x1 - d.x0;
const nodeHeight = d.y1 - d.y0;
const textNode = self.node()!;
const padding = 4;
const availableWidth = nodeWidth - 2 * padding;
const availableHeight = nodeHeight - 2 * padding;
if (availableWidth < 10 || availableHeight < 10) {
self.style('display', 'none');
return;
}
let currentLabelFontSize = parseInt(self.style('font-size'), 10);
const minLabelFontSize = 8;
const originalValueRelFontSize = 28; // Original font size of value, for max cap
const valueScaleFactor = 0.6; // Value font size as a factor of label font size
const minValueFontSize = 6;
const spacingBetweenLabelAndValue = 2;
// 1. Adjust label font size to fit width
while (
textNode.getComputedTextLength() > availableWidth &&
currentLabelFontSize > minLabelFontSize
) {
currentLabelFontSize--;
self.style('font-size', `${currentLabelFontSize}px`);
}
// 2. Adjust both label and prospective value font size to fit combined height
let prospectiveValueFontSize = Math.max(
minValueFontSize,
Math.min(originalValueRelFontSize, Math.round(currentLabelFontSize * valueScaleFactor))
);
let combinedHeight =
currentLabelFontSize + spacingBetweenLabelAndValue + prospectiveValueFontSize;
while (combinedHeight > availableHeight && currentLabelFontSize > minLabelFontSize) {
currentLabelFontSize--;
prospectiveValueFontSize = Math.max(
minValueFontSize,
Math.min(originalValueRelFontSize, Math.round(currentLabelFontSize * valueScaleFactor))
);
if (
prospectiveValueFontSize < minValueFontSize &&
currentLabelFontSize === minLabelFontSize
) {
break;
} // Avoid shrinking label if value is already at min
self.style('font-size', `${currentLabelFontSize}px`);
combinedHeight =
currentLabelFontSize + spacingBetweenLabelAndValue + prospectiveValueFontSize;
if (prospectiveValueFontSize <= minValueFontSize && combinedHeight > availableHeight) {
// If value is at min and still doesn't fit, label might need to shrink more alone
// This might lead to label being too small for its own text, checked next
}
}
// Update label font size based on height adjustment
self.style('font-size', `${currentLabelFontSize}px`);
// 3. Final visibility check for the label
if (
textNode.getComputedTextLength() > availableWidth ||
currentLabelFontSize < minLabelFontSize ||
availableHeight < currentLabelFontSize
) {
self.style('display', 'none');
// If label is hidden, value will be hidden by its own .each() loop
}
});
// Add node values with clipping
if (config.showValues !== false) {
const leafValues = cell
.append('text')
.attr('class', 'treemapValue')
.attr('x', (d) => (d.x1 - d.x0) / 2)
.attr('y', function (d) {
// Y position calculated dynamically in leafValues.each based on final label metrics
return (d.y1 - d.y0) / 2; // Placeholder, will be overwritten
})
.attr('style', (d) => {
const labelStyles =
'text-anchor: middle; dominant-baseline: hanging; font-size: 28px;fill:' +
colorScaleLabel(d.data.name) +
';';
const styles = styles2String({ cssCompiledStyles: d.data.cssCompiledStyles } as Node);
return labelStyles + styles.labelStyles.replace('color:', 'fill:');
})
.attr('clip-path', (_d, i) => `url(#clip-${id}-${i})`)
.text((d) => (d.value ? valueFormat(d.value) : ''));
leafValues.each(function (d) {
const valueTextElement = select(this);
const parentCellNode = this.parentNode as SVGGElement | null;
if (!parentCellNode) {
valueTextElement.style('display', 'none');
return;
}
const labelElement = select(parentCellNode).select<SVGTextElement>('.treemapLabel');
if (labelElement.empty() || labelElement.style('display') === 'none') {
valueTextElement.style('display', 'none');
return;
}
const finalLabelFontSize = parseFloat(labelElement.style('font-size'));
const originalValueFontSize = 28; // From initial style setting
const valueScaleFactor = 0.6;
const minValueFontSize = 6;
const spacingBetweenLabelAndValue = 2;
const actualValueFontSize = Math.max(
minValueFontSize,
Math.min(originalValueFontSize, Math.round(finalLabelFontSize * valueScaleFactor))
);
valueTextElement.style('font-size', `${actualValueFontSize}px`);
const labelCenterY = (d.y1 - d.y0) / 2;
const valueTopActualY = labelCenterY + finalLabelFontSize / 2 + spacingBetweenLabelAndValue;
valueTextElement.attr('y', valueTopActualY);
const nodeWidth = d.x1 - d.x0;
const nodeTotalHeight = d.y1 - d.y0;
const cellBottomPadding = 4;
const maxValueBottomY = nodeTotalHeight - cellBottomPadding;
const availableWidthForValue = nodeWidth - 2 * 4; // padding for value text
if (
valueTextElement.node()!.getComputedTextLength() > availableWidthForValue ||
valueTopActualY + actualValueFontSize > maxValueBottomY ||
actualValueFontSize < minValueFontSize
) {
valueTextElement.style('display', 'none');
} else {
valueTextElement.style('display', null);
}
});
}
const diagramPadding = config.diagramPadding ?? 8;
setupViewPortForSVG(svg, diagramPadding, 'flowchart', config?.useMaxWidth || false);
};
const getClasses = function (
_text: string,
diagramObj: Pick<Diagram, 'db'>
): Map<string, DiagramStyleClassDef> {
return (diagramObj.db as TreemapDB).getClasses();
};
export const renderer: DiagramRenderer = { draw, getClasses };

View File

@@ -0,0 +1,51 @@
import type { DiagramStylesProvider } from '../../diagram-api/types.js';
import { cleanAndMerge } from '../../utils.js';
import type { TreemapStyleOptions } from './types.js';
const defaultTreemapStyleOptions: TreemapStyleOptions = {
sectionStrokeColor: 'black',
sectionStrokeWidth: '1',
sectionFillColor: '#efefef',
leafStrokeColor: 'black',
leafStrokeWidth: '1',
leafFillColor: '#efefef',
labelColor: 'black',
labelFontSize: '12px',
valueFontSize: '10px',
valueColor: 'black',
titleColor: 'black',
titleFontSize: '14px',
};
export const getStyles: DiagramStylesProvider = ({
treemap,
}: { treemap?: TreemapStyleOptions } = {}) => {
const options = cleanAndMerge(defaultTreemapStyleOptions, treemap);
return `
.treemapNode.section {
stroke: ${options.sectionStrokeColor};
stroke-width: ${options.sectionStrokeWidth};
fill: ${options.sectionFillColor};
}
.treemapNode.leaf {
stroke: ${options.leafStrokeColor};
stroke-width: ${options.leafStrokeWidth};
fill: ${options.leafFillColor};
}
.treemapLabel {
fill: ${options.labelColor};
font-size: ${options.labelFontSize};
}
.treemapValue {
fill: ${options.valueColor};
font-size: ${options.valueFontSize};
}
.treemapTitle {
fill: ${options.titleColor};
font-size: ${options.titleFontSize};
}
`;
};
export default getStyles;

View File

@@ -0,0 +1,80 @@
import type { DiagramDBBase, DiagramStyleClassDef } from '../../diagram-api/types.js';
import type { BaseDiagramConfig } from '../../config.type.js';
export interface TreemapNode {
name: string;
children?: TreemapNode[];
value?: number;
parent?: TreemapNode;
classSelector?: string;
cssCompiledStyles?: string[];
}
export interface TreemapDB extends DiagramDBBase<TreemapDiagramConfig> {
getNodes: () => TreemapNode[];
addNode: (node: TreemapNode, level: number) => void;
getRoot: () => TreemapNode | undefined;
getClasses: () => Map<string, DiagramStyleClassDef>;
addClass: (className: string, style: string) => void;
getStylesForClass: (classSelector: string) => string[];
}
export interface TreemapStyleOptions {
sectionStrokeColor?: string;
sectionStrokeWidth?: string;
sectionFillColor?: string;
leafStrokeColor?: string;
leafStrokeWidth?: string;
leafFillColor?: string;
labelColor?: string;
labelFontSize?: string;
valueFontSize?: string;
valueColor?: string;
titleColor?: string;
titleFontSize?: string;
}
export interface TreemapData {
nodes: TreemapNode[];
levels: Map<TreemapNode, number>;
root?: TreemapNode;
outerNodes: TreemapNode[];
classes: Map<string, DiagramStyleClassDef>;
}
export interface TreemapItem {
$type: string;
name: string;
value?: number;
classSelector?: string;
}
export interface TreemapRow {
$type: string;
indent?: string;
item?: TreemapItem;
className?: string;
styleText?: string;
}
export interface TreemapAst {
TreemapRows?: TreemapRow[];
title?: string;
description?: string;
accDescription?: string;
accTitle?: string;
diagramTitle?: string;
}
// Define the TreemapDiagramConfig interface
export interface TreemapDiagramConfig extends BaseDiagramConfig {
padding?: number;
diagramPadding?: number;
showValues?: boolean;
nodeWidth?: number;
nodeHeight?: number;
borderWidth?: number;
valueFontSize?: number;
labelFontSize?: number;
valueFormat?: string;
}

View File

@@ -0,0 +1,100 @@
import { describe, it, expect } from 'vitest';
import { buildHierarchy } from './utils.js';
import type { TreemapNode } from './types.js';
describe('treemap utilities', () => {
describe('buildHierarchy', () => {
it('should convert a flat array into a hierarchical structure', () => {
// Input flat structure
const flatItems = [
{ level: 0, name: 'Root', type: 'Section' },
{ level: 4, name: 'Branch 1', type: 'Section' },
{ level: 8, name: 'Leaf 1.1', type: 'Leaf', value: 10 },
{ level: 8, name: 'Leaf 1.2', type: 'Leaf', value: 15 },
{ level: 4, name: 'Branch 2', type: 'Section' },
{ level: 8, name: 'Leaf 2.1', type: 'Leaf', value: 20 },
{ level: 8, name: 'Leaf 2.2', type: 'Leaf', value: 25 },
{ level: 8, name: 'Leaf 2.3', type: 'Leaf', value: 30 },
];
// Expected hierarchical structure
const expectedHierarchy: TreemapNode[] = [
{
name: 'Root',
children: [
{
name: 'Branch 1',
children: [
{ name: 'Leaf 1.1', value: 10 },
{ name: 'Leaf 1.2', value: 15 },
],
},
{
name: 'Branch 2',
children: [
{ name: 'Leaf 2.1', value: 20 },
{ name: 'Leaf 2.2', value: 25 },
{ name: 'Leaf 2.3', value: 30 },
],
},
],
},
];
const result = buildHierarchy(flatItems);
expect(result).toEqual(expectedHierarchy);
});
it('should handle empty input', () => {
expect(buildHierarchy([])).toEqual([]);
});
it('should handle only root nodes', () => {
const flatItems = [
{ level: 0, name: 'Root 1', type: 'Section' },
{ level: 0, name: 'Root 2', type: 'Section' },
];
const expected = [
{ name: 'Root 1', children: [] },
{ name: 'Root 2', children: [] },
];
expect(buildHierarchy(flatItems)).toEqual(expected);
});
it('should handle complex nesting levels', () => {
const flatItems = [
{ level: 0, name: 'Root', type: 'Section' },
{ level: 2, name: 'Level 1', type: 'Section' },
{ level: 4, name: 'Level 2', type: 'Section' },
{ level: 6, name: 'Leaf 1', type: 'Leaf', value: 10 },
{ level: 4, name: 'Level 2 again', type: 'Section' },
{ level: 6, name: 'Leaf 2', type: 'Leaf', value: 20 },
];
const expected = [
{
name: 'Root',
children: [
{
name: 'Level 1',
children: [
{
name: 'Level 2',
children: [{ name: 'Leaf 1', value: 10 }],
},
{
name: 'Level 2 again',
children: [{ name: 'Leaf 2', value: 20 }],
},
],
},
],
},
];
expect(buildHierarchy(flatItems)).toEqual(expected);
});
});
});

View File

@@ -0,0 +1,64 @@
import type { TreemapNode } from './types.js';
/**
* Converts a flat array of treemap items into a hierarchical structure
* @param items - Array of flat treemap items with level, name, type, and optional value
* @returns A hierarchical tree structure
*/
export function buildHierarchy(
items: {
level: number;
name: string;
type: string;
value?: number;
classSelector?: string;
cssCompiledStyles?: string;
}[]
): TreemapNode[] {
if (!items.length) {
return [];
}
const root: TreemapNode[] = [];
const stack: { node: TreemapNode; level: number }[] = [];
items.forEach((item) => {
const node: TreemapNode = {
name: item.name,
children: item.type === 'Leaf' ? undefined : [],
};
node.classSelector = item?.classSelector;
if (item?.cssCompiledStyles) {
node.cssCompiledStyles = [item.cssCompiledStyles];
}
if (item.type === 'Leaf' && item.value !== undefined) {
node.value = item.value;
}
// Find the right parent for this node
while (stack.length > 0 && stack[stack.length - 1].level >= item.level) {
stack.pop();
}
if (stack.length === 0) {
// This is a root node
root.push(node);
} else {
// Add as child to the parent
const parent = stack[stack.length - 1].node;
if (parent.children) {
parent.children.push(node);
} else {
parent.children = [node];
}
}
// Only add to stack if it can have children
if (item.type !== 'Leaf') {
stack.push({ node, level: item.level });
}
});
return root;
}

View File

@@ -179,6 +179,7 @@ function sidebarSyntax() {
{ text: 'Kanban 🔥', link: '/syntax/kanban' },
{ text: 'Architecture 🔥', link: '/syntax/architecture' },
{ text: 'Radar 🔥', link: '/syntax/radar' },
{ text: 'Treemap 🔥', link: '/syntax/treemap' },
{ text: 'Other Examples', link: '/syntax/examples' },
],
},

View File

@@ -240,7 +240,7 @@ Communication tools and platforms
| GitHub + Mermaid | - | [🦊🔗](https://addons.mozilla.org/firefox/addon/github-mermaid/) | - | - | [🐙🔗](https://github.com/BackMarket/github-mermaid-extension) |
| Asciidoctor Live Preview | [🎡🔗](https://chromewebstore.google.com/detail/asciidoctorjs-live-previe/iaalpfgpbocpdfblpnhhgllgbdbchmia) | - | - | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/asciidoctorjs-live-previ/pefkelkanablhjdekgdahplkccnbdggd?hl=en-US) | - |
| Diagram Tab | - | - | - | - | [🐙🔗](https://github.com/khafast/diagramtab) |
| Markdown Diagrams | [🎡🔗](https://chromewebstore.google.com/detail/markdown-diagrams/pmoglnmodacnbbofbgcagndelmgaclel) | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-diagrams/) | [🔴🔗](https://addons.opera.com/en/extensions/details/markdown-diagrams/) | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/markdown-diagrams/hceenoomhhdkjjijnmlclkpenkapfihe) | [🐙🔗](https://github.com/marcozaccari/markdown-diagrams-browser-extension/tree/master/doc/examples) |
| Markdown Diagrams | [🎡🔗](https://chromewebstore.google.com/detail/markdown-diagrams/pmoglnmodacnbbofbgcagndelmgaclel) | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-diagrams/) | - | [🌀🔗](https://microsoftedge.microsoft.com/addons/detail/markdown-diagrams/hceenoomhhdkjjijnmlclkpenkapfihe) | [🐙🔗](https://github.com/marcozaccari/markdown-diagrams-browser-extension/tree/master/doc/examples) |
| Markdown Viewer | - | [🦊🔗](https://addons.mozilla.org/en-US/firefox/addon/markdown-viewer-chrome/) | - | - | [🐙🔗](https://github.com/simov/markdown-viewer) |
| Extensions for Mermaid | - | - | [🔴🔗](https://addons.opera.com/en/extensions/details/extensions-for-mermaid/) | - | [🐙🔗](https://github.com/Stefan-S/mermaid-extension) |
| Chrome Diagrammer | [🎡🔗](https://chromewebstore.google.com/detail/chrome-diagrammer/bkpbgjmkomfoakfklcjeoegkklgjnnpk) | - | - | - | - |
@@ -265,5 +265,6 @@ Communication tools and platforms
- [reveal.js-mermaid-plugin](https://github.com/ludwick/reveal.js-mermaid-plugin)
- [Reveal CK](https://github.com/jedcn/reveal-ck)
- [reveal-ck-mermaid-plugin](https://github.com/tmtm/reveal-ck-mermaid-plugin)
- [Vitepress Plugin](https://github.com/sametcn99/vitepress-mermaid-renderer)
<!--- cspell:ignore Blazorade HueHive --->

View File

@@ -24,7 +24,7 @@ Try the Ultimate AI, Mermaid, and Visual Diagramming Suite by creating an accoun
Official Mermaid Chart plugins:
- [Mermaid Chart GPT](https://chat.openai.com/g/g-1IRFKwq4G-mermaid-chart)
- [Mermaid Chart GPT](https://chatgpt.com/g/g-684cc36f30208191b21383b88650a45d-mermaid-chart-diagrams-and-charts)
- [Confluence](https://marketplace.atlassian.com/apps/1234056/mermaid-chart-for-confluence?hosting=cloud&tab=overview)
- [Jira](https://marketplace.atlassian.com/apps/1234810/mermaid-chart-for-jira?tab=overview&hosting=cloud)
- [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=MermaidChart.vscode-mermaid-chart)

View File

@@ -1253,7 +1253,7 @@ flowchart TD
There are two ways to display these FontAwesome icons:
### Register FontAwesome icon packs (v<MERMAID_RELEASE_VERSION>+)
### Register FontAwesome icon packs (v11.7.0+)
You can register your own FontAwesome icon pack following the ["Registering icon packs" instructions](../config/icons.md).

View File

@@ -17,7 +17,7 @@ start-end: "Block name" %% Multi-bit blocks
... More Fields ...
```
### Bits Syntax (v<MERMAID_RELEASE_VERSION>+)
### Bits Syntax (v11.7.0+)
Using start and end bit counts can be difficult, especially when modifying a design. For this we add a bit count field, which starts from the end of the previous field automagically. Use `+<count>` to set the number of bits, thus:

View File

@@ -0,0 +1,245 @@
---
title: Treemap Diagram Syntax
outline: 'deep' # shows all h3 headings in outline in Vitepress
---
# Treemap Diagram
> A treemap diagram displays hierarchical data as a set of nested rectangles. Each branch of the tree is represented by a rectangle, which is then tiled with smaller rectangles representing sub-branches.
```warning
This is a new diagram type in Mermaid. Its syntax may evolve in future versions.
```
## Introduction
Treemap diagrams are an effective way to visualize hierarchical data and show proportions between categories and subcategories. The size of each rectangle is proportional to the value it represents, making it easy to compare different parts of a hierarchy.
Treemap diagrams are particularly useful for:
- Visualizing hierarchical data structures
- Comparing proportions between categories
- Displaying large amounts of hierarchical data in a limited space
- Identifying patterns and outliers in hierarchical data
## Syntax
```
treemap-beta
"Section 1"
"Leaf 1.1": 12
"Section 1.2"
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20
"Leaf 2.2": 25
```
### Node Definition
Nodes in a treemap are defined using the following syntax:
- **Section/Parent nodes**: Defined with quoted text `"Section Name"`
- **Leaf nodes with values**: Defined with quoted text followed by a colon and value `"Leaf Name": value`
- **Hierarchy**: Created using indentation (spaces or tabs)
- **Styling**: Nodes can be styled using the `:::class` syntax
## Examples
### Basic Treemap
```mermaid-example
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
```
### Hierarchical Treemap
```mermaid-example
treemap-beta
"Products"
"Electronics"
"Phones": 50
"Computers": 30
"Accessories": 20
"Clothing"
"Men's": 40
"Women's": 40
```
### Treemap with Styling
```mermaid-example
treemap-beta
"Section 1"
"Leaf 1.1": 12
"Section 1.2":::class1
"Leaf 1.2.1": 12
"Section 2"
"Leaf 2.1": 20:::class1
"Leaf 2.2": 25
"Leaf 2.3": 12
classDef class1 fill:red,color:blue,stroke:#FFD600;
```
## Styling and Configuration
Treemap diagrams can be customized using Mermaid's styling and configuration options.
### Using classDef for Styling
You can define custom styles for nodes using the `classDef` syntax, which is a standard feature across many Mermaid diagram types:
```mermaid-example
treemap-beta
"Main"
"A": 20
"B":::important
"B1": 10
"B2": 15
"C": 5
classDef important fill:#f96,stroke:#333,stroke-width:2px;
```
### Theme Configuration
You can customize the colors of your treemap using the theme configuration:
```mermaid-example
---
config:
theme: 'forest'
---
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
```
### Diagram Padding
You can adjust the padding around the treemap diagram using the `diagramPadding` configuration option:
```mermaid-example
---
config:
treemap:
diagramPadding: 200
---
treemap-beta
"Category A"
"Item A1": 10
"Item A2": 20
"Category B"
"Item B1": 15
"Item B2": 25
```
## Configuration Options
The treemap diagram supports the following configuration options:
| Option | Description | Default |
| -------------- | --------------------------------------------------------------------------- | ------- |
| useMaxWidth | When true, the diagram width is set to 100% and scales with available space | true |
| padding | Internal padding between nodes | 10 |
| diagramPadding | Padding around the entire diagram | 8 |
| showValues | Whether to show values in the treemap | true |
| nodeWidth | Width of nodes | 100 |
| nodeHeight | Height of nodes | 40 |
| borderWidth | Width of borders | 1 |
| valueFontSize | Font size for values | 12 |
| labelFontSize | Font size for labels | 14 |
| valueFormat | Format for values (see Value Formatting section) | ',' |
## Advanced Features
### Value Formatting
Values in treemap diagrams can be formatted to display in different ways using the `valueFormat` configuration option. This option primarily uses [D3's format specifiers](https://github.com/d3/d3-format#locale_format) to control how numbers are displayed, with some additional special cases for common formats.
Some common format patterns:
- `,` - Thousands separator (default)
- `$` - Add dollar sign
- `.1f` - Show one decimal place
- `.1%` - Show as percentage with one decimal place
- `$0,0` - Dollar sign with thousands separator
- `$.2f` - Dollar sign with 2 decimal places
- `$,.2f` - Dollar sign with thousands separator and 2 decimal places
The treemap diagram supports both standard D3 format specifiers and some common currency formats that combine the dollar sign with other formatting options.
Example with currency formatting:
```mermaid-example
---
config:
treemap:
valueFormat: '$0,0'
---
treemap-beta
"Budget"
"Operations"
"Salaries": 700000
"Equipment": 200000
"Supplies": 100000
"Marketing"
"Advertising": 400000
"Events": 100000
```
Example with percentage formatting:
```mermaid-example
---
config:
treemap:
valueFormat: '$.1%'
---
treemap-beta
"Market Share"
"Company A": 0.35
"Company B": 0.25
"Company C": 0.15
"Others": 0.25
```
## Common Use Cases
Treemap diagrams are commonly used for:
1. **Financial Data**: Visualizing budget allocations, market shares, or portfolio compositions
2. **File System Analysis**: Showing disk space usage by folders and files
3. **Population Demographics**: Displaying population distribution across regions and subregions
4. **Product Hierarchies**: Visualizing product categories and their sales volumes
5. **Organizational Structures**: Representing departments and team sizes in a company
## Limitations
- Treemap diagrams work best when the data has a natural hierarchy
- Very small values may be difficult to see or label in a treemap diagram
- Deep hierarchies (many levels) can be challenging to represent clearly
- Treemap diagrams are not well suited for representing data with negative values
## Related Diagrams
If treemap diagrams don't suit your needs, consider these alternatives:
- [**Pie Charts**](./pie.md): For simple proportion comparisons without hierarchy
- **Sunburst Diagrams**: For hierarchical data with a radial layout (yet to be released in Mermaid).
- [**Sankey Diagrams**](./sankey.md): For flow-based hierarchical data
## Notes
The treemap diagram implementation in Mermaid is designed to be simple to use while providing powerful visualization capabilities. As this is a newer diagram type, feedback and feature requests are welcome through the Mermaid GitHub repository.

View File

@@ -1,5 +1,15 @@
# @mermaid-js/parser
## 0.5.0
### Minor Changes
- [#5980](https://github.com/mermaid-js/mermaid/pull/5980) [`df9df9d`](https://github.com/mermaid-js/mermaid/commit/df9df9dc32b80a8c320cc0efd5483b9485f15bde) Thanks [@BryanCrotazGivEnergy](https://github.com/BryanCrotazGivEnergy)! - feat: Add shorter `+<count>: Label` syntax in packet diagram
### Patch Changes
- [#6407](https://github.com/mermaid-js/mermaid/pull/6407) [`cdbd3e5`](https://github.com/mermaid-js/mermaid/commit/cdbd3e58a3a35d63a79258115dedca4a535c1038) Thanks [@thomascizeron](https://github.com/thomascizeron)! - Refactor grammar so that title don't break Architecture Diagrams
## 0.4.0
### Minor Changes

View File

@@ -30,6 +30,11 @@
"id": "radar",
"grammar": "src/language/radar/radar.langium",
"fileExtensions": [".mmd", ".mermaid"]
},
{
"id": "treemap",
"grammar": "src/language/treemap/treemap.langium",
"fileExtensions": [".mmd", ".mermaid"]
}
],
"mode": "production",

View File

@@ -1,6 +1,6 @@
{
"name": "@mermaid-js/parser",
"version": "0.4.0",
"version": "0.5.0",
"description": "MermaidJS parser",
"author": "Yokozuna59",
"contributors": [

View File

@@ -8,6 +8,7 @@ export {
Architecture,
GitGraph,
Radar,
TreemapDoc,
Branch,
Commit,
Merge,
@@ -19,6 +20,7 @@ export {
isPieSection,
isArchitecture,
isGitGraph,
isTreemapDoc,
isBranch,
isCommit,
isMerge,
@@ -32,6 +34,7 @@ export {
ArchitectureGeneratedModule,
GitGraphGeneratedModule,
RadarGeneratedModule,
TreemapGeneratedModule,
} from './generated/module.js';
export * from './gitGraph/index.js';
@@ -41,3 +44,4 @@ export * from './packet/index.js';
export * from './pie/index.js';
export * from './architecture/index.js';
export * from './radar/index.js';
export * from './treemap/index.js';

View File

@@ -0,0 +1 @@
export * from './module.js';

View File

@@ -0,0 +1,88 @@
import type {
DefaultSharedCoreModuleContext,
LangiumCoreServices,
LangiumSharedCoreServices,
Module,
PartialLangiumCoreServices,
} from 'langium';
import {
EmptyFileSystem,
createDefaultCoreModule,
createDefaultSharedCoreModule,
inject,
} from 'langium';
import { MermaidGeneratedSharedModule, TreemapGeneratedModule } from '../generated/module.js';
import { TreemapTokenBuilder } from './tokenBuilder.js';
import { TreemapValueConverter } from './valueConverter.js';
import { TreemapValidator, registerValidationChecks } from './treemap-validator.js';
/**
* Declaration of `Treemap` services.
*/
interface TreemapAddedServices {
parser: {
TokenBuilder: TreemapTokenBuilder;
ValueConverter: TreemapValueConverter;
};
validation: {
TreemapValidator: TreemapValidator;
};
}
/**
* Union of Langium default services and `Treemap` services.
*/
export type TreemapServices = LangiumCoreServices & TreemapAddedServices;
/**
* Dependency injection module that overrides Langium default services and
* contributes the declared `Treemap` services.
*/
export const TreemapModule: Module<
TreemapServices,
PartialLangiumCoreServices & TreemapAddedServices
> = {
parser: {
TokenBuilder: () => new TreemapTokenBuilder(),
ValueConverter: () => new TreemapValueConverter(),
},
validation: {
TreemapValidator: () => new TreemapValidator(),
},
};
/**
* Create the full set of services required by Langium.
*
* First inject the shared services by merging two modules:
* - Langium default shared services
* - Services generated by langium-cli
*
* Then inject the language-specific services by merging three modules:
* - Langium default language-specific services
* - Services generated by langium-cli
* - Services specified in this file
* @param context - Optional module context with the LSP connection
* @returns An object wrapping the shared services and the language-specific services
*/
export function createTreemapServices(context: DefaultSharedCoreModuleContext = EmptyFileSystem): {
shared: LangiumSharedCoreServices;
Treemap: TreemapServices;
} {
const shared: LangiumSharedCoreServices = inject(
createDefaultSharedCoreModule(context),
MermaidGeneratedSharedModule
);
const Treemap: TreemapServices = inject(
createDefaultCoreModule({ shared }),
TreemapGeneratedModule,
TreemapModule
);
shared.ServiceRegistry.register(Treemap);
// Register validation checks
registerValidationChecks(Treemap);
return { shared, Treemap };
}

View File

@@ -0,0 +1,7 @@
import { AbstractMermaidTokenBuilder } from '../common/index.js';
export class TreemapTokenBuilder extends AbstractMermaidTokenBuilder {
public constructor() {
super(['treemap']);
}
}

View File

@@ -0,0 +1,61 @@
import type { ValidationAcceptor, ValidationChecks } from 'langium';
import type { MermaidAstType, TreemapDoc } from '../generated/ast.js';
import type { TreemapServices } from './module.js';
/**
* Register custom validation checks.
*/
export function registerValidationChecks(services: TreemapServices) {
const validator = services.validation.TreemapValidator;
const registry = services.validation.ValidationRegistry;
if (registry) {
// Use any to bypass type checking since we know TreemapDoc is part of the AST
// but the type system is having trouble with it
const checks: ValidationChecks<MermaidAstType> = {
TreemapDoc: validator.checkSingleRoot.bind(validator),
// Remove unused validation for TreemapRow
};
registry.register(checks, validator);
}
}
/**
* Implementation of custom validations.
*/
export class TreemapValidator {
/**
* Validates that a treemap has only one root node.
* A root node is defined as a node that has no indentation.
*/
checkSingleRoot(doc: TreemapDoc, accept: ValidationAcceptor): void {
let rootNodeIndentation;
for (const row of doc.TreemapRows) {
// Skip non-node items or items without a type
if (!row.item) {
continue;
}
if (
rootNodeIndentation === undefined && // Check if this is a root node (no indentation)
row.indent === undefined
) {
rootNodeIndentation = 0;
} else if (row.indent === undefined) {
// If we've already found a root node, report an error
accept('error', 'Multiple root nodes are not allowed in a treemap.', {
node: row,
property: 'item',
});
} else if (
rootNodeIndentation !== undefined &&
rootNodeIndentation >= parseInt(row.indent, 10)
) {
accept('error', 'Multiple root nodes are not allowed in a treemap.', {
node: row,
property: 'item',
});
}
}
}
}

View File

@@ -0,0 +1,90 @@
/**
* Treemap grammar for Langium
* Converted from mindmap grammar
*
* The ML_COMMENT and NL hidden terminals handle whitespace, comments, and newlines
* before the treemap keyword, allowing for empty lines and comments before the
* treemap declaration.
*/
grammar Treemap
fragment TitleAndAccessibilities:
((accDescr=ACC_DESCR | accTitle=ACC_TITLE | title=TITLE))+
;
terminal BOOLEAN returns boolean: 'true' | 'false';
terminal ACC_DESCR: /[\t ]*accDescr(?:[\t ]*:([^\n\r]*?(?=%%)|[^\n\r]*)|\s*{([^}]*)})/;
terminal ACC_TITLE: /[\t ]*accTitle[\t ]*:(?:[^\n\r]*?(?=%%)|[^\n\r]*)/;
terminal TITLE: /[\t ]*title(?:[\t ][^\n\r]*?(?=%%)|[\t ][^\n\r]*|)/;
// Interface declarations for data types
interface Item {
name: string
classSelector?: string // For ::: class
}
interface Section extends Item {
}
interface Leaf extends Item {
value: number
}
interface ClassDefStatement {
className: string
styleText: string // Optional style text
}
interface TreemapDoc {
TreemapRows: TreemapRow[]
title?: string
accTitle?: string
accDescr?: string
}
entry TreemapDoc returns TreemapDoc:
TREEMAP_KEYWORD
(
TitleAndAccessibilities
| TreemapRows+=TreemapRow
)*;
terminal TREEMAP_KEYWORD: 'treemap-beta' | 'treemap';
terminal CLASS_DEF: /classDef\s+([a-zA-Z_][a-zA-Z0-9_]+)(?:\s+([^;\r\n]*))?(?:;)?/;
terminal STYLE_SEPARATOR: ':::';
terminal SEPARATOR: ':';
terminal COMMA: ',';
hidden terminal WS: /[ \t]+/; // One or more spaces or tabs for hidden whitespace
hidden terminal ML_COMMENT: /\%\%[^\n]*/;
hidden terminal NL: /\r?\n/;
TreemapRow:
indent=INDENTATION? (item=Item | ClassDef);
// Class definition statement handled by the value converter
ClassDef returns string:
CLASS_DEF;
Item returns Item:
Leaf | Section;
// Use a special rule order to handle the parsing precedence
Section returns Section:
name=STRING2 (STYLE_SEPARATOR classSelector=ID2)?;
Leaf returns Leaf:
name=STRING2 INDENTATION? (SEPARATOR | COMMA) INDENTATION? value=MyNumber (STYLE_SEPARATOR classSelector=ID2)?;
// This should be processed before whitespace is ignored
terminal INDENTATION: /[ \t]{1,}/; // One or more spaces/tabs for indentation
// Keywords with fixed text patterns
terminal ID2: /[a-zA-Z_][a-zA-Z0-9_]*/;
// Define as a terminal rule
terminal NUMBER2: /[0-9_\.\,]+/;
// Then create a data type rule that uses it
MyNumber returns number: NUMBER2;
terminal STRING2: /"[^"]*"|'[^']*'/;
// Modified indentation rule to have higher priority than WS

View File

@@ -0,0 +1,44 @@
import type { CstNode, GrammarAST, ValueType } from 'langium';
import { AbstractMermaidValueConverter } from '../common/index.js';
// Regular expression to extract className and styleText from a classDef terminal
const classDefRegex = /classDef\s+([A-Z_a-z]\w+)(?:\s+([^\n\r;]*))?;?/;
export class TreemapValueConverter extends AbstractMermaidValueConverter {
protected runCustomConverter(
rule: GrammarAST.AbstractRule,
input: string,
_cstNode: CstNode
): ValueType | undefined {
if (rule.name === 'NUMBER2') {
// Convert to a number by removing any commas and converting to float
return parseFloat(input.replace(/,/g, ''));
} else if (rule.name === 'SEPARATOR') {
// Remove quotes
return input.substring(1, input.length - 1);
} else if (rule.name === 'STRING2') {
// Remove quotes
return input.substring(1, input.length - 1);
} else if (rule.name === 'INDENTATION') {
return input.length;
} else if (rule.name === 'ClassDef') {
// Handle both CLASS_DEF terminal and ClassDef rule
if (typeof input !== 'string') {
// If we're dealing with an already processed object, return it as is
return input;
}
// Extract className and styleText from classDef statement
const match = classDefRegex.exec(input);
if (match) {
// Use any type to avoid type issues
return {
$type: 'ClassDefStatement',
className: match[1],
styleText: match[2] || undefined,
} as any;
}
}
return undefined;
}
}

View File

@@ -1,6 +1,6 @@
import type { LangiumParser, ParseResult } from 'langium';
import type { Info, Packet, Pie, Architecture, GitGraph, Radar } from './index.js';
import type { Info, Packet, Pie, Architecture, GitGraph, Radar, Treemap } from './index.js';
export type DiagramAST = Info | Packet | Pie | Architecture | GitGraph | Radar;
@@ -36,6 +36,11 @@ const initializers = {
const parser = createRadarServices().Radar.parser.LangiumParser;
parsers.radar = parser;
},
treemap: async () => {
const { createTreemapServices } = await import('./language/treemap/index.js');
const parser = createTreemapServices().Treemap.parser.LangiumParser;
parsers.treemap = parser;
},
} as const;
export async function parse(diagramType: 'info', text: string): Promise<Info>;
@@ -44,6 +49,7 @@ export async function parse(diagramType: 'pie', text: string): Promise<Pie>;
export async function parse(diagramType: 'architecture', text: string): Promise<Architecture>;
export async function parse(diagramType: 'gitGraph', text: string): Promise<GitGraph>;
export async function parse(diagramType: 'radar', text: string): Promise<Radar>;
export async function parse(diagramType: 'treemap', text: string): Promise<Treemap>;
export async function parse<T extends DiagramAST>(
diagramType: keyof typeof initializers,

View File

@@ -32,6 +32,12 @@ const consoleMock = vi.spyOn(console, 'log').mockImplementation(() => undefined)
* @param result - the result `parse` function.
*/
export function expectNoErrorsOrAlternatives(result: ParseResult) {
if (result.lexerErrors.length > 0) {
// console.debug(result.lexerErrors);
}
if (result.parserErrors.length > 0) {
// console.debug(result.parserErrors);
}
expect(result.lexerErrors).toHaveLength(0);
expect(result.parserErrors).toHaveLength(0);

View File

@@ -0,0 +1,238 @@
import { describe, expect, it } from 'vitest';
import { expectNoErrorsOrAlternatives } from './test-util.js';
import type { TreemapDoc, Section, Leaf, TreemapRow } from '../src/language/generated/ast.js';
import type { LangiumParser } from 'langium';
import { createTreemapServices } from '../src/language/treemap/module.js';
describe('Treemap Parser', () => {
const services = createTreemapServices().Treemap;
const parser: LangiumParser = services.parser.LangiumParser;
const parse = (input: string) => {
return parser.parse<TreemapDoc>(input);
};
describe('Basic Parsing', () => {
it('should parse empty treemap', () => {
const result = parse('treemap');
expectNoErrorsOrAlternatives(result);
expect(result.value.$type).toBe('TreemapDoc');
expect(result.value.TreemapRows).toHaveLength(0);
});
it('should parse a section node', () => {
const result = parse('treemap\n"Root"');
expectNoErrorsOrAlternatives(result);
expect(result.value.$type).toBe('TreemapDoc');
expect(result.value.TreemapRows).toHaveLength(1);
if (result.value.TreemapRows[0].item) {
expect(result.value.TreemapRows[0].item.$type).toBe('Section');
const section = result.value.TreemapRows[0].item as Section;
expect(section.name).toBe('Root');
}
});
it('should parse a section with leaf nodes', () => {
const result = parse(`treemap
"Root"
"Child1" , 100
"Child2" : 200
`);
expectNoErrorsOrAlternatives(result);
expect(result.value.$type).toBe('TreemapDoc');
expect(result.value.TreemapRows).toHaveLength(3);
if (result.value.TreemapRows[0].item) {
expect(result.value.TreemapRows[0].item.$type).toBe('Section');
const section = result.value.TreemapRows[0].item as Section;
expect(section.name).toBe('Root');
}
if (result.value.TreemapRows[1].item) {
expect(result.value.TreemapRows[1].item.$type).toBe('Leaf');
const leaf = result.value.TreemapRows[1].item as Leaf;
expect(leaf.name).toBe('Child1');
expect(leaf.value).toBe(100);
}
if (result.value.TreemapRows[2].item) {
expect(result.value.TreemapRows[2].item.$type).toBe('Leaf');
const leaf = result.value.TreemapRows[2].item as Leaf;
expect(leaf.name).toBe('Child2');
expect(leaf.value).toBe(200);
}
});
});
describe('Data Types', () => {
it('should correctly parse string values', () => {
const result = parse('treemap\n"My Section"');
expectNoErrorsOrAlternatives(result);
if (result.value.TreemapRows[0].item) {
expect(result.value.TreemapRows[0].item.$type).toBe('Section');
const section = result.value.TreemapRows[0].item as Section;
expect(section.name).toBe('My Section');
}
});
it('should correctly parse number values', () => {
const result = parse('treemap\n"Item" : 123.45');
expectNoErrorsOrAlternatives(result);
if (result.value.TreemapRows[0].item) {
expect(result.value.TreemapRows[0].item.$type).toBe('Leaf');
const leaf = result.value.TreemapRows[0].item as Leaf;
expect(leaf.name).toBe('Item');
expect(typeof leaf.value).toBe('number');
expect(leaf.value).toBe(123.45);
}
});
});
describe('Validation', () => {
it('should parse multiple root nodes', () => {
const result = parse('treemap\n"Root1"\n"Root2"');
expect(result.parserErrors).toHaveLength(0);
// We're only checking that the multiple root nodes parse successfully
// The validation errors would be reported by the validator during validation
expect(result.value.$type).toBe('TreemapDoc');
expect(result.value.TreemapRows).toHaveLength(2);
});
});
describe('Title and Accessibilities', () => {
it('should parse a treemap with title', () => {
const result = parse('treemap\ntitle My Treemap Diagram\n"Root"\n "Child": 100');
expectNoErrorsOrAlternatives(result);
expect(result.value.$type).toBe('TreemapDoc');
// We can't directly test the title property due to how Langium processes TitleAndAccessibilities
// but we can verify the TreemapRows are parsed correctly
expect(result.value.TreemapRows).toHaveLength(2);
});
it('should parse a treemap with accTitle', () => {
const result = parse('treemap\naccTitle: Accessible Title\n"Root"\n "Child": 100');
expectNoErrorsOrAlternatives(result);
expect(result.value.$type).toBe('TreemapDoc');
// We can't directly test the accTitle property due to how Langium processes TitleAndAccessibilities
expect(result.value.TreemapRows).toHaveLength(2);
});
it('should parse a treemap with accDescr', () => {
const result = parse(
'treemap\naccDescr: This is an accessible description\n"Root"\n "Child": 100'
);
expectNoErrorsOrAlternatives(result);
expect(result.value.$type).toBe('TreemapDoc');
// We can't directly test the accDescr property due to how Langium processes TitleAndAccessibilities
expect(result.value.TreemapRows).toHaveLength(2);
});
it('should parse a treemap with multiple accessibility attributes', () => {
const result = parse(`treemap
title My Treemap Diagram
accTitle: Accessible Title
accDescr: This is an accessible description
"Root"
"Child": 100`);
expectNoErrorsOrAlternatives(result);
expect(result.value.$type).toBe('TreemapDoc');
// We can't directly test these properties due to how Langium processes TitleAndAccessibilities
expect(result.value.TreemapRows).toHaveLength(2);
});
});
describe('ClassDef and Class Statements', () => {
it('should parse a classDef statement', () => {
const result = parse('treemap\nclassDef myClass fill:red;');
// We know there are parser errors with styleText as the Langium grammar can't handle it perfectly
// Check that we at least got the right type and className
expect(result.value.TreemapRows).toHaveLength(1);
const classDefElement = result.value.TreemapRows[0];
expect(classDefElement.$type).toBe('ClassDefStatement');
// We can't directly test the ClassDefStatement properties due to type issues
// but we can verify the basic structure is correct
});
it('should parse a classDef statement without semicolon', () => {
const result = parse('treemap\nclassDef myClass fill:red');
// Skip error assertion
const classDefElement = result.value.TreemapRows[0];
expect(classDefElement.$type).toBe('ClassDefStatement');
// We can't directly test the ClassDefStatement properties due to type issues
// but we can verify the basic structure is correct
});
it('should parse a classDef statement with multiple style properties', () => {
const result = parse(
'treemap\nclassDef complexClass fill:blue stroke:#ff0000 stroke-width:2px'
);
// Skip error assertion
const classDefElement = result.value.TreemapRows[0];
expect(classDefElement.$type).toBe('ClassDefStatement');
// We can't directly test the ClassDefStatement properties due to type issues
// but we can verify the basic structure is correct
});
it('should parse a class assignment statement', () => {
const result = parse('treemap\nclass myNode myClass');
// Skip error check since parsing is not fully implemented yet
// expectNoErrorsOrAlternatives(result);
// For now, just expect that something is returned, even if it's empty
expect(result.value).toBeDefined();
});
it('should parse a class assignment statement with semicolon', () => {
const result = parse('treemap\nclass myNode myClass;');
// Skip error check since parsing is not fully implemented yet
// expectNoErrorsOrAlternatives(result);
// For now, just expect that something is returned, even if it's empty
expect(result.value).toBeDefined();
});
it('should parse a section with inline class style using :::', () => {
const result = parse('treemap\n"My Section":::sectionClass');
expectNoErrorsOrAlternatives(result);
const row = result.value.TreemapRows.find(
(element): element is TreemapRow => element.$type === 'TreemapRow'
);
expect(row).toBeDefined();
if (row?.item) {
expect(row.item.$type).toBe('Section');
const section = row.item as Section;
expect(section.name).toBe('My Section');
expect(section.classSelector).toBe('sectionClass');
}
});
it('should parse a leaf with inline class style using :::', () => {
const result = parse('treemap\n"My Leaf" : 100:::leafClass');
expectNoErrorsOrAlternatives(result);
const row = result.value.TreemapRows.find(
(element): element is TreemapRow => element.$type === 'TreemapRow'
);
expect(row).toBeDefined();
if (row?.item) {
expect(row.item.$type).toBe('Leaf');
const leaf = row.item as Leaf;
expect(leaf.name).toBe('My Leaf');
expect(leaf.value).toBe(100);
expect(leaf.classSelector).toBe('leafClass');
}
});
});
});

240
packages/tiny/CHANGELOG.md Normal file
View File

@@ -0,0 +1,240 @@
# mermaid
## 11.7.0
### Minor Changes
- [#6479](https://github.com/mermaid-js/mermaid/pull/6479) [`97b79c3`](https://github.com/mermaid-js/mermaid/commit/97b79c3578a2004c63fa32f6d5e17bd8a536e13a) Thanks [@monicanguyen25](https://github.com/monicanguyen25)! - feat: Add Vertical Line To Gantt Plot At Specified Time
- [#6225](https://github.com/mermaid-js/mermaid/pull/6225) [`41e84b7`](https://github.com/mermaid-js/mermaid/commit/41e84b726a1f2df002b77c4b0071e2c15e47838e) Thanks [@Shahir-47](https://github.com/Shahir-47)! - feat: Add support for styling Journey Diagram title (color, font-family, and font-size)
- [#6423](https://github.com/mermaid-js/mermaid/pull/6423) [`aa6cb86`](https://github.com/mermaid-js/mermaid/commit/aa6cb86899968c65561eebfc1d54dd086b1518a2) Thanks [@BambioGaming](https://github.com/BambioGaming)! - Added support for the click directive in stateDiagram syntax
- [#5980](https://github.com/mermaid-js/mermaid/pull/5980) [`df9df9d`](https://github.com/mermaid-js/mermaid/commit/df9df9dc32b80a8c320cc0efd5483b9485f15bde) Thanks [@BryanCrotazGivEnergy](https://github.com/BryanCrotazGivEnergy)! - feat: Add shorter `+<count>: Label` syntax in packet diagram
- [#6523](https://github.com/mermaid-js/mermaid/pull/6523) [`c17277e`](https://github.com/mermaid-js/mermaid/commit/c17277e743b1c12e4134fba44c62a7d5885f2574) Thanks [@NourBenz](https://github.com/NourBenz)! - fix: allow sequence diagram arrows with a trailing colon but no message
- [#6475](https://github.com/mermaid-js/mermaid/pull/6475) [`a1ba65c`](https://github.com/mermaid-js/mermaid/commit/a1ba65c0c08432ec36e772570c3a5899cb57c102) Thanks [@Shahir-47](https://github.com/Shahir-47)! - feat: Dynamically Render Data Labels Within Bar Charts
### Patch Changes
- [#6588](https://github.com/mermaid-js/mermaid/pull/6588) [`b1cf291`](https://github.com/mermaid-js/mermaid/commit/b1cf29127348602137552405e3300dee1697f0de) Thanks [@omkarht](https://github.com/omkarht)! - Fix stroke styles for ER diagram to correctly apply path and row-specific styles
- [#6296](https://github.com/mermaid-js/mermaid/pull/6296) [`a4754ad`](https://github.com/mermaid-js/mermaid/commit/a4754ad195e70d52fbd46ef44f40797d2d215e41) Thanks [@sidharthv96](https://github.com/sidharthv96)! - chore: Convert StateDB into TypeScript
- [#6463](https://github.com/mermaid-js/mermaid/pull/6463) [`2b05d7e`](https://github.com/mermaid-js/mermaid/commit/2b05d7e1edef635e6c80cb383b10ea0a89279f41) Thanks [@AaronMoat](https://github.com/AaronMoat)! - fix: Remove incorrect `style="undefined;"` attributes in some Mermaid diagrams
- [#6282](https://github.com/mermaid-js/mermaid/pull/6282) [`d63d3bf`](https://github.com/mermaid-js/mermaid/commit/d63d3bf1e7596ac7eeb24ba06cbc7a70f9c8b070) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - FontAwesome icons can now be embedded as SVGs in flowcharts if they are registered via `mermaid.registerIconPacks`.
- [#6407](https://github.com/mermaid-js/mermaid/pull/6407) [`cdbd3e5`](https://github.com/mermaid-js/mermaid/commit/cdbd3e58a3a35d63a79258115dedca4a535c1038) Thanks [@thomascizeron](https://github.com/thomascizeron)! - Refactor grammar so that title don't break Architecture Diagrams
- [#6343](https://github.com/mermaid-js/mermaid/pull/6343) [`1ddaf10`](https://github.com/mermaid-js/mermaid/commit/1ddaf10b89d8c7311c5e10d466b42fa36b61210b) Thanks [@jeswr](https://github.com/jeswr)! - fix: allow colons in events
- [#6616](https://github.com/mermaid-js/mermaid/pull/6616) [`ca80f71`](https://github.com/mermaid-js/mermaid/commit/ca80f719eac86cf4c31392105d5d896f39b84bbc) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix(timeline): ensure consistent vertical line lengths with visible arrowheads
Fixed timeline diagrams where vertical dashed lines from tasks had inconsistent lengths. All vertical lines now extend to the same depth regardless of the number of events in each column, with sufficient padding to clearly display both the dashed line pattern and complete arrowheads.
- [#6566](https://github.com/mermaid-js/mermaid/pull/6566) [`bca6ed6`](https://github.com/mermaid-js/mermaid/commit/bca6ed67c3e0db910bf498fdd0fc0346c02d392b) Thanks [@arpitjain099](https://github.com/arpitjain099)! - fix: Fix incomplete string escaping in URL manipulation logic when `arrowMarkerAbsolute: true` by ensuring all unsafe characters are escaped.
- Updated dependencies [[`df9df9d`](https://github.com/mermaid-js/mermaid/commit/df9df9dc32b80a8c320cc0efd5483b9485f15bde), [`cdbd3e5`](https://github.com/mermaid-js/mermaid/commit/cdbd3e58a3a35d63a79258115dedca4a535c1038)]:
- @mermaid-js/parser@0.5.0
## 11.6.0
### Minor Changes
- [#6408](https://github.com/mermaid-js/mermaid/pull/6408) [`ad65313`](https://github.com/mermaid-js/mermaid/commit/ad653138e16765d095613a6e5de86dc5e52ac8f0) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - fix: restore curve type configuration functionality for flowcharts. This fixes the issue where curve type settings were not being applied when configured through any of the following methods:
- Config
- Init directive (%%{ init: { 'flowchart': { 'curve': '...' } } }%%)
- LinkStyle command (linkStyle default interpolate ...)
- [#6381](https://github.com/mermaid-js/mermaid/pull/6381) [`95d73bc`](https://github.com/mermaid-js/mermaid/commit/95d73bc3f064dbf261a06483f94a7ef4d0bb52eb) Thanks [@thomascizeron](https://github.com/thomascizeron)! - Add Radar Chart
### Patch Changes
- [#2](https://github.com/calvinvette/mermaid/pull/2) [`16d9b63`](https://github.com/mermaid-js/mermaid/commit/16d9b6345749ab5f24d5b8433efc3635d4913863) Thanks [@calvinvette](https://github.com/calvinvette)! - - [#6388](https://github.com/mermaid-js/mermaid/pull/6386)
Thanks [@bollwyvl](https://github.com/bollwyvl) - Fix requirement diagram containment arrow
- Updated dependencies [[`95d73bc`](https://github.com/mermaid-js/mermaid/commit/95d73bc3f064dbf261a06483f94a7ef4d0bb52eb)]:
- @mermaid-js/parser@0.4.0
## 11.5.0
### Minor Changes
- [#6187](https://github.com/mermaid-js/mermaid/pull/6187) [`7809b5a`](https://github.com/mermaid-js/mermaid/commit/7809b5a93fae127f45727071f5ff14325222c518) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - Flowchart new syntax for node metadata bugs
- Incorrect label mapping for nodes when using `&`
- Syntax error when `}` with trailing spaces before new line
- [#6136](https://github.com/mermaid-js/mermaid/pull/6136) [`ec0d9c3`](https://github.com/mermaid-js/mermaid/commit/ec0d9c389aa6018043187654044c1e0b5aa4f600) Thanks [@knsv](https://github.com/knsv)! - Adding support for animation of flowchart edges
- [#6373](https://github.com/mermaid-js/mermaid/pull/6373) [`05bdf0e`](https://github.com/mermaid-js/mermaid/commit/05bdf0e20e2629fe77513218fbd4e28e65f75882) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - Upgrade Requirement and ER diagram to use the common renderer flow
- Added support for directions
- Added support for hand drawn look
- [#6371](https://github.com/mermaid-js/mermaid/pull/6371) [`4d25cab`](https://github.com/mermaid-js/mermaid/commit/4d25caba8e65df078966a283e7e0ae1200bef595) Thanks [@knsv](https://github.com/knsv)! - The arrowhead color should match the color of the edge. Creates a unique clone of the arrow marker with the appropriate color.
### Patch Changes
- [#6064](https://github.com/mermaid-js/mermaid/pull/6064) [`2a91849`](https://github.com/mermaid-js/mermaid/commit/2a91849a38641e97ed6b20cb60aa4506d1b63177) Thanks [@NicolasNewman](https://github.com/NicolasNewman)! - fix: architecture diagrams no longer grow to extreme heights due to conflicting alignments
- [#6198](https://github.com/mermaid-js/mermaid/pull/6198) [`963efa6`](https://github.com/mermaid-js/mermaid/commit/963efa64c794466dcd0f06bad6de6ba554d05a54) Thanks [@ferozmht](https://github.com/ferozmht)! - Fixes for consistent edge id creation & handling edge cases for animate edge feature
- [#6196](https://github.com/mermaid-js/mermaid/pull/6196) [`127bac1`](https://github.com/mermaid-js/mermaid/commit/127bac1147034d8a8588cc8f7870abe92ebc945e) Thanks [@knsv](https://github.com/knsv)! - Fix for issue #6195 - allowing @ signs inside node labels
- [#6212](https://github.com/mermaid-js/mermaid/pull/6212) [`90bbf90`](https://github.com/mermaid-js/mermaid/commit/90bbf90a83bf5da53fc8030cf1370bc8238fa4aa) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - fix: `mermaidAPI.getDiagramFromText()` now returns a new different db for each class diagram
- [#6218](https://github.com/mermaid-js/mermaid/pull/6218) [`232e60c`](https://github.com/mermaid-js/mermaid/commit/232e60c8cbaea804e6d98aa90f90d1ce76730e17) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - fix: revert state db to resolve getData returning empty nodes and edges
- [#6250](https://github.com/mermaid-js/mermaid/pull/6250) [`9cad3c7`](https://github.com/mermaid-js/mermaid/commit/9cad3c7aea3bbbc61495b23225ccff76d312783f) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - `mermaidAPI.getDiagramFromText()` now returns a new db instance on each call for state diagrams
- [#6293](https://github.com/mermaid-js/mermaid/pull/6293) [`cfd84e5`](https://github.com/mermaid-js/mermaid/commit/cfd84e54d502f4d36a35b50478121558cfbef2c4) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - Added versioning to StateDB and updated tests and diagrams to use it.
- [#6161](https://github.com/mermaid-js/mermaid/pull/6161) [`6cc31b7`](https://github.com/mermaid-js/mermaid/commit/6cc31b74530baa6d0f527346ab1395b0896bb3c2) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - fix: `mermaidAPI.getDiagramFromText()` now returns a new different db for each flowchart
- [#6272](https://github.com/mermaid-js/mermaid/pull/6272) [`ffa7804`](https://github.com/mermaid-js/mermaid/commit/ffa7804af0701b3d044d6794e36bd9132d6c7e8d) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - fix: `mermaidAPI.getDiagramFromText()` now returns a new different db for each sequence diagram. Added unique IDs for messages.
- [#6205](https://github.com/mermaid-js/mermaid/pull/6205) [`32a68d4`](https://github.com/mermaid-js/mermaid/commit/32a68d489ed83a5b79f516d6b2fb3a7505c5eb24) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - fix: Gantt, Sankey and User Journey diagram are now able to pick font-family from mermaid config.
- [#6295](https://github.com/mermaid-js/mermaid/pull/6295) [`da6361f`](https://github.com/mermaid-js/mermaid/commit/da6361f6527918b4b6a9c07cc9558cf2e2c709d2) Thanks [@omkarht](https://github.com/omkarht)! - fix: `getDirection` and `setDirection` in `stateDb` refactored to return and set actual direction
- [#6185](https://github.com/mermaid-js/mermaid/pull/6185) [`3e32332`](https://github.com/mermaid-js/mermaid/commit/3e32332814c659e7ed1bb73d4a26ed4e61b77d59) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - `mermaidAPI.getDiagramFromText()` now returns a new different db for each state diagram
## 11.4.1
### Patch Changes
- [#6059](https://github.com/mermaid-js/mermaid/pull/6059) [`01b5079`](https://github.com/mermaid-js/mermaid/commit/01b5079562ec8d34ce9964910f168873843c68f8) Thanks [@knsv](https://github.com/knsv)! - fix: Kanban diagrams will not render when adding a number as ticket id or assigned for a task
- [#6038](https://github.com/mermaid-js/mermaid/pull/6038) [`1388662`](https://github.com/mermaid-js/mermaid/commit/1388662132cc829f9820c2e9970ae04e2dd90588) Thanks [@knsv](https://github.com/knsv)! - fix: Intersection calculations for tilted cylinder/DAS when using handdrawn look. Some random seeds could cause the calculations to break.
- [#6079](https://github.com/mermaid-js/mermaid/pull/6079) [`fe3cffb`](https://github.com/mermaid-js/mermaid/commit/fe3cffbb673a25b81989aacb06e5d0eda35326db) Thanks [@aloisklink](https://github.com/aloisklink)! - Bump dompurify to `^3.2.1`. This removes the need for `@types/dompurify`.
## 11.4.0
### Minor Changes
- [#5999](https://github.com/mermaid-js/mermaid/pull/5999) [`742ad7c`](https://github.com/mermaid-js/mermaid/commit/742ad7c130964df1fb5544e909d9556081285f68) Thanks [@knsv](https://github.com/knsv)! - Adding Kanban board, a new diagram type
- [#5880](https://github.com/mermaid-js/mermaid/pull/5880) [`bdf145f`](https://github.com/mermaid-js/mermaid/commit/bdf145ffe362462176d9c1e68d5f3ff5c9d962b0) Thanks [@yari-dewalt](https://github.com/yari-dewalt)! - Class diagram changes:
- Updates the class diagram to the new unified way of rendering.
- Includes a new "classBox" shape to be used in diagrams
- Other updates such as:
- the option to hide the empty members box in class diagrams,
- support for handDrawn look,
- the introduction of the classDef statement into class diagrams,
- support for styling the default class,
- support lollipop interfaces.
- Includes fixes / additions for #5562 #3139 and #4037
### Patch Changes
- [#5937](https://github.com/mermaid-js/mermaid/pull/5937) [`17b7831`](https://github.com/mermaid-js/mermaid/commit/17b783135f9b2b7748b620dbf81d0f56ab4755f1) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - fix: Jagged edge fix for icon shape
- [#5933](https://github.com/mermaid-js/mermaid/pull/5933) [`72d60d2`](https://github.com/mermaid-js/mermaid/commit/72d60d2633584eb59bccdb6cf30b9522db645db2) Thanks [@remcohaszing](https://github.com/remcohaszing)! - Add missing TypeScript dependencies
- [#5937](https://github.com/mermaid-js/mermaid/pull/5937) [`17b7831`](https://github.com/mermaid-js/mermaid/commit/17b783135f9b2b7748b620dbf81d0f56ab4755f1) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - fix: Icon color fix for colored icons.
- [#6002](https://github.com/mermaid-js/mermaid/pull/6002) [`5fabd41`](https://github.com/mermaid-js/mermaid/commit/5fabd414fbee01e43bf6c900907ffc1511ca7440) Thanks [@aloisklink](https://github.com/aloisklink)! - fix: error `mermaid.parse` on an invalid shape, so that it matches the errors thrown by `mermaid.render`
## 11.3.0
### Minor Changes
- [#5825](https://github.com/mermaid-js/mermaid/pull/5825) [`9e3aa70`](https://github.com/mermaid-js/mermaid/commit/9e3aa705ae21fd4898504ab22d775a9e437b898e) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - New Flowchart Shapes (with new syntax)
### Patch Changes
- [#5849](https://github.com/mermaid-js/mermaid/pull/5849) [`6c5b7ce`](https://github.com/mermaid-js/mermaid/commit/6c5b7ce9f41c0fbd59fe03dbefc8418d97697f0a) Thanks [@ReneLombard](https://github.com/ReneLombard)! - Fixed an issue when the mermaid classdiagram crashes when adding a . to the namespace.
For example
```mermaid
classDiagram
namespace Company.Project.Module {
class GenericClass~T~ {
+addItem(item: T)
+getItem() T
}
}
```
- [#5914](https://github.com/mermaid-js/mermaid/pull/5914) [`de2c05c`](https://github.com/mermaid-js/mermaid/commit/de2c05cd5463af68d19dd7b6b3f1303d69ddb2dd) Thanks [@aloisklink](https://github.com/aloisklink)! - Ban DOMPurify v3.1.7 as a dependency
## 11.2.1
### Patch Changes
- [#5856](https://github.com/mermaid-js/mermaid/pull/5856) [`bfd8c63`](https://github.com/mermaid-js/mermaid/commit/bfd8c63daaa8420e57da9953922b9f0c94123064) Thanks [@knsv](https://github.com/knsv)! - Fix for issue with calculation of label width when using in firefox
## 11.2.0
### Minor Changes
- [#5831](https://github.com/mermaid-js/mermaid/pull/5831) [`64abf29`](https://github.com/mermaid-js/mermaid/commit/64abf29ea870eaa47148197f95ce714f85bd7eea) Thanks [@sidharthv96](https://github.com/sidharthv96)! - feat: Return parsed config from mermaid.parse
### Patch Changes
- [#5838](https://github.com/mermaid-js/mermaid/pull/5838) [`5e75320`](https://github.com/mermaid-js/mermaid/commit/5e75320d49eab65aca630dcc3c04c8d620a8bbf7) Thanks [@bollwyvl](https://github.com/bollwyvl)! - fix: Replace $root with relative paths
## 11.1.1
### Patch Changes
- [#5828](https://github.com/mermaid-js/mermaid/pull/5828) [`4c43d21`](https://github.com/mermaid-js/mermaid/commit/4c43d21196f784b6f483ae635fc462329f3d176f) Thanks [@knsv](https://github.com/knsv)! - fix: Fix for issue where self-loops in the root of diagrams break the rendering
## 11.1.0
### Minor Changes
- [#5793](https://github.com/mermaid-js/mermaid/pull/5793) [`6ecdf7b`](https://github.com/mermaid-js/mermaid/commit/6ecdf7be688efdc53c52fea3ba891327242bc890) Thanks [@sidharthv96](https://github.com/sidharthv96)! - feat: Add support for iconify icons
- [#5711](https://github.com/mermaid-js/mermaid/pull/5711) [`8e640da`](https://github.com/mermaid-js/mermaid/commit/8e640da5436e8ae013b11b1c1821a9afcc15d0d3) Thanks [@NicolasNewman](https://github.com/NicolasNewman)! - feat(er): allow multi-line relationship labels
- [#5452](https://github.com/mermaid-js/mermaid/pull/5452) [`256a148`](https://github.com/mermaid-js/mermaid/commit/256a148bbf484fc7db6c19f94dd69d5d268ee048) Thanks [@NicolasNewman](https://github.com/NicolasNewman)! - New Diagram: Architecture
Adds architecture diagrams which allows users to show relations between services.
### Patch Changes
- [#5810](https://github.com/mermaid-js/mermaid/pull/5810) [`28bd07f`](https://github.com/mermaid-js/mermaid/commit/28bd07fdeb4fc981107d21317ec6160b31f80116) Thanks [@knsv](https://github.com/knsv)! - Fix for self loops in cluster
Supporting legacy defaultRenderer directive
- [#5789](https://github.com/mermaid-js/mermaid/pull/5789) [`16faef4`](https://github.com/mermaid-js/mermaid/commit/16faef4613b91a7d3a98a1563c25b57f9238acc7) Thanks [@sidharthv96](https://github.com/sidharthv96)! - chore: Move icons to architecture, remove full icon sets to reduce bundle size
- Updated dependencies [[`256a148`](https://github.com/mermaid-js/mermaid/commit/256a148bbf484fc7db6c19f94dd69d5d268ee048), [`7d8143b`](https://github.com/mermaid-js/mermaid/commit/7d8143b917ee3562149a0e0a821ed2d6f29cc05d)]:
- @mermaid-js/parser@0.3.0
## 11.0.2
### Patch Changes
- [#5664](https://github.com/mermaid-js/mermaid/pull/5664) [`5deaef4`](https://github.com/mermaid-js/mermaid/commit/5deaef456e74d796866431c26f69360e4e74dbff) Thanks [@Austin-Fulbright](https://github.com/Austin-Fulbright)! - chore: Migrate git graph to langium, use typescript for internals
- Updated dependencies [[`5deaef4`](https://github.com/mermaid-js/mermaid/commit/5deaef456e74d796866431c26f69360e4e74dbff)]:
- @mermaid-js/parser@0.2.0
## 11.0.1
### Patch Changes
- [#2](https://github.com/calvinvette/mermaid/pull/2) [`bf05d87`](https://github.com/mermaid-js/mermaid/commit/bf05d8781edacb580fdb053da167e968b7570117) Thanks [@calvinvette](https://github.com/calvinvette)! - test changeset
## 11.0.2
### Patch Changes
- Updated dependencies [[`83926c9`](https://github.com/mermaid-js/mermaid/commit/83926c9707b09c34e300888186250191ee8ae30a)]:
- @mermaid-js/parser@0.1.1
## 11.0.1
### Patch Changes
- [#5744](https://github.com/mermaid-js/mermaid/pull/5744) [`5013484`](https://github.com/mermaid-js/mermaid/commit/50134849246141ec400e33e08c12c10539b84de9) Thanks [@sidharthv96](https://github.com/sidharthv96)! - Release parser, test changesets
- Updated dependencies [[`5013484`](https://github.com/mermaid-js/mermaid/commit/50134849246141ec400e33e08c12c10539b84de9)]:
- @mermaid-js/parser@0.1.0

View File

@@ -1,6 +1,6 @@
{
"name": "@mermaid-js/tiny",
"version": "11.6.0",
"version": "11.7.0",
"description": "Tiny version of mermaid",
"type": "commonjs",
"main": "./dist/mermaid.tiny.js",

985
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff