From 65acba0b61a716b3b3019495f0f3b1ed12ae4b7b Mon Sep 17 00:00:00 2001 From: Peter White <1788320+peterwhite@users.noreply.github.com> Date: Wed, 14 Oct 2026 11:26:28 +0200 Subject: [PATCH] Fix Mermaid block diagrams and clipped labels on published sites (#4687) --- .changeset/mermaid-block-diagrams.md | 5 ++++ .changeset/mermaid-clipped-labels.md | 5 ++++ bun.lock | 1 + package.json | 3 ++- .../scripts/generate-mermaid-runtime.ts | 15 ++++++++--- .../CodeBlock/mermaid-runtime-path.ts | 2 +- patches/mermaid@11.14.0.patch | 26 +++++++++++++++++++ 7 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 .changeset/mermaid-block-diagrams.md create mode 100644 .changeset/mermaid-clipped-labels.md create mode 100644 patches/mermaid@11.14.0.patch diff --git a/.changeset/mermaid-block-diagrams.md b/.changeset/mermaid-block-diagrams.md new file mode 100644 index 000000000..4a086982a --- /dev/null +++ b/.changeset/mermaid-block-diagrams.md @@ -0,0 +1,5 @@ +--- +"gitbook": patch +--- + +Fix Mermaid block diagrams falling back to a code block on published sites. diff --git a/.changeset/mermaid-clipped-labels.md b/.changeset/mermaid-clipped-labels.md new file mode 100644 index 000000000..4d917cf70 --- /dev/null +++ b/.changeset/mermaid-clipped-labels.md @@ -0,0 +1,5 @@ +--- +"gitbook": patch +--- + +Fix long Mermaid labels being clipped instead of wrapping at some browser zoom levels. diff --git a/bun.lock b/bun.lock index 8221d4f3a..65d35ebce 100644 --- a/bun.lock +++ b/bun.lock @@ -343,6 +343,7 @@ "patchedDependencies": { "decode-named-character-reference@1.0.2": "patches/decode-named-character-reference@1.0.2.patch", "next@16.3.8": "patches/next@16.3.8.patch", + "mermaid@11.14.0": "patches/mermaid@11.14.0.patch", }, "overrides": { "@codemirror/state": "6.4.1", diff --git a/package.json b/package.json index 5e4dd90d3..1df37c57e 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "patchedDependencies": { "decode-named-character-reference@1.0.2": "patches/decode-named-character-reference@1.0.2.patch", "@vercel/next@4.4.2": "patches/@vercel%2Fnext@4.4.2.patch", - "next@16.3.8": "patches/next@16.3.8.patch" + "next@16.3.8": "patches/next@16.3.8.patch", + "mermaid@11.14.0": "patches/mermaid@11.14.0.patch" } } diff --git a/packages/gitbook/scripts/generate-mermaid-runtime.ts b/packages/gitbook/scripts/generate-mermaid-runtime.ts index f7dd914cb..4ae1788be 100644 --- a/packages/gitbook/scripts/generate-mermaid-runtime.ts +++ b/packages/gitbook/scripts/generate-mermaid-runtime.ts @@ -1,5 +1,6 @@ import { build } from 'bun'; -import { mkdir, rename, rm } from 'node:fs/promises'; +import { createHash } from 'node:crypto'; +import { mkdir, readFile, rename, rm } from 'node:fs/promises'; import { createRequire } from 'node:module'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -12,14 +13,20 @@ const temporaryDir = join(outputDir, '.build'); const require = createRequire(import.meta.url); const mermaidPackage = require('mermaid/package.json') as { version: string }; const zenumlPackage = require('@mermaid-js/mermaid-zenuml/package.json') as { version: string }; +const mermaidPatch = await readFile( + join(scriptDir, `../../../patches/mermaid@${mermaidPackage.version}.patch`) +).catch(() => null); +const mermaidPatchSuffix = mermaidPatch + ? `-patch.${createHash('sha256').update(mermaidPatch).digest('hex').slice(0, 8)}` + : ''; -// The runtime URL is served as immutable, it has to change whenever the bundled versions change. +// The runtime URL is served as immutable, it has to change whenever the bundled versions or patch change. if ( MERMAID_RUNTIME_PATH !== - `mermaid/mermaid@${mermaidPackage.version}-zenuml@${zenumlPackage.version}.mjs` + `mermaid/mermaid@${mermaidPackage.version}${mermaidPatchSuffix}-zenuml@${zenumlPackage.version}.mjs` ) { throw new Error( - 'Update MERMAID_RUNTIME_PATH for the installed mermaid and @mermaid-js/mermaid-zenuml versions' + 'Update MERMAID_RUNTIME_PATH for the installed mermaid and @mermaid-js/mermaid-zenuml versions and the mermaid patch' ); } diff --git a/packages/gitbook/src/components/DocumentView/CodeBlock/mermaid-runtime-path.ts b/packages/gitbook/src/components/DocumentView/CodeBlock/mermaid-runtime-path.ts index 8a70fa08d..ede08b53c 100644 --- a/packages/gitbook/src/components/DocumentView/CodeBlock/mermaid-runtime-path.ts +++ b/packages/gitbook/src/components/DocumentView/CodeBlock/mermaid-runtime-path.ts @@ -1 +1 @@ -export const MERMAID_RUNTIME_PATH = 'mermaid/mermaid@11.14.0-zenuml@0.2.2.mjs'; +export const MERMAID_RUNTIME_PATH = 'mermaid/mermaid@11.14.0-patch.caefc3e9-zenuml@0.2.2.mjs'; diff --git a/patches/mermaid@11.14.0.patch b/patches/mermaid@11.14.0.patch new file mode 100644 index 000000000..006ea4112 --- /dev/null +++ b/patches/mermaid@11.14.0.patch @@ -0,0 +1,26 @@ +diff --git a/dist/chunks/mermaid.core/blockDiagram-DXYQGD6D.mjs b/dist/chunks/mermaid.core/blockDiagram-DXYQGD6D.mjs +index f37722f2f65d3c49904ec704998a9a0ce6f01d21..0b97ddef583d120235530222990f08db3de83e5d 100644 +--- a/dist/chunks/mermaid.core/blockDiagram-DXYQGD6D.mjs ++++ b/dist/chunks/mermaid.core/blockDiagram-DXYQGD6D.mjs +@@ -3658,7 +3658,7 @@ async function calculateBlockSize(elem, block, db2) { + const nodeEl = await insertNode(elem, node, { config: config2 }); + const boundingBox = nodeEl.node().getBBox(); + const obj = db2.getBlock(node.id); +- obj.size = { width: boundingBox.width, height: boundingBox.height, x: 0, y: 0, node: nodeEl }; ++ obj.size = { width: boundingBox.width, height: boundingBox.height, x: 0, y: 0 }; + db2.setBlock(obj); + nodeEl.remove(); + } +diff --git a/dist/chunks/mermaid.core/chunk-U2HBQHQK.mjs b/dist/chunks/mermaid.core/chunk-U2HBQHQK.mjs +index 6f5ff605824cec370f0ff1077fe3005823fa59f5..1468e9b37b3c1ef3449774b816202e3143174476 100644 +--- a/dist/chunks/mermaid.core/chunk-U2HBQHQK.mjs ++++ b/dist/chunks/mermaid.core/chunk-U2HBQHQK.mjs +@@ -308,7 +308,7 @@ async function addHtmlSpan(element, node, width, classes, addBackground = false, + div.attr("class", "labelBkg"); + } + let bbox = div.node().getBoundingClientRect(); +- if (bbox.width === width) { ++ if (Math.round(bbox.width) === width) { + div.style("display", "table"); + div.style("white-space", "break-spaces"); + div.style("width", width + "px");