feat(ui): @plannotator/ui 0.40.0 — Mermaid 12.0.0 (ELK by default), loaded lazily - #1557
Merged
Merged
Conversation
Bump @plannotator/ui's mermaid dependency from ^11.17.2 to an exact 12.0.0 and regenerate bun.lock. Mermaid 12 lays flowchart, state, class, ER and requirement diagrams out with ELK by default (elkjs is now bundled in mermaid itself), targets Safari 17.4+ / ES2024, and drops the legacy flowchart/class/state diagram ids. We take 12's defaults rather than pinning the 11 ones. No API or type changes were needed: MERMAID_CONFIG (securityLevel 'strict') and the theme mapping apply unchanged, every generated SVG id keeps its 11.x shape, and the katex import Mermaid makes for $$ labels is the same call (the math-slot bridge is untouched). The visual-explainer skill's render gate now expects Mermaid 12.
Drop the eager registration import (@plannotator/ui/utils/mermaid-eager)
from the plan editor entry. Since Mermaid 12 the runtime plus ELK is about
1.8 MB larger, so a plan with no diagram must not pay for it: the block now
resolves the runtime through utils/mermaid's own import('mermaid') on the
first MermaidBlock render. In the chunked share-portal build that moves
mermaid.core (~640 KB) out of the entry chunk; the single-file builds still
inline it through inlineDynamicImports, so nothing changes there except
Mermaid 12's own size.
MermaidBlock shows the source fence under a role=status "Rendering
diagram" line until the first render lands, never the error panel, and
applyMermaidTheme is keyed on the runtime object so the lazily loaded
runtime is themed on its first render like an eagerly registered one.
mermaid-eager stays exported for hosts that want startup registration.
tests/entry-assets.test.ts now asserts the eager Mermaid marker is absent
from both app bundles; DiagramBlock.lazyRetry.test.tsx pins the pending
state.
Add the "Mermaid 12 (0.40.0)" section hosts need to adopt the bump: ELK layout by default and the other 12 changes we take, the concrete SVG id patterns (unchanged 11 -> 12, per family), the g.edgePaths declaration-order change and the select-by-id rule, the Safari 17.4+ / ES2024 floor, the lazy-load contract (the plan editor no longer imports mermaid-eager; how a host keeps startup registration; the pending state; measured chunk and single-file sizes), the theming contract with and without tokens, the 0.40 contrast re-sweep (104 combinations, 0 failures), and the publish order core 0.25.3 -> ui 0.40.0. Retitle the theme and element-context sections to 0.40.0, fold the two unreleased publishing bullets into the current pair, and update the 0.32.0 lazy-renderer text, README and AGENTS for the new policy.
Carries the #1549 html-anchor element-context exports (parseHtmlElementContext, MAX_ELEMENT_CONTEXT_BYTES, MAX_PAGE_URL_LENGTH) that @plannotator/ui 0.40.0 imports. Publish this before ui 0.40.0.
Mermaid 12 pulls chevrotain 11.1.2 (via langium), which pins lodash-es exactly 4.17.23 (CVE-2026-4800 high, CVE-2026-2950 medium), so the workspace resolved a second, vulnerable copy beside the 4.18.1 that dagre-d3-es already resolves. A root "overrides" entry forces every lodash-es range to 4.18.1 (published 2026-04-01, past the 7-day gate); bun.lock now records a single lodash-es@4.18.1. chevrotain still parses every diagram grammar under it: all 15 eval diagrams render with zero errors in the built plan editor, typecheck, the ui utils and MermaidBlock tests, and the package smoke pass, and the built bundles are byte-for-byte the same size.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
@plannotator/ui0.40.0 on@plannotator/core0.25.3: Mermaid 11.17.2 → 12.0.0 (exact pin), loaded lazily in the plan editor, on top of the theme-aware Mermaid work from #1556.mermaid12.0.0, exact. We take 12's defaults (owner ruling): ELK is the default layout for flowchart / state / class / ER / requirement (elkjs is bundled in mermaid itself now), the legacyflowchart/class/statediagram ids are gone, and the build targets Safari 17.4+ / ES2024. No API or type break:bun run typecheckis clean,MERMAID_CONFIG(securityLevel: 'strict', still pinned by test) and the 0.39 theme mapping apply unchanged, every rendered SVG id keeps its 11.x shape ({renderId}-flowchart-{node}-{n},{renderId}-L_{from}_{to}_{n},{renderId}-state-…,{renderId}-edge{n},{renderId}-classId-…,{renderId}-entity-…, globalactor{n}/root-{n}in sequence), and the only DOM-order change is thatg.edgePathschildren are now in declaration order. TheminimumReleaseAgegate was respected: 12.0.0 was published 2026-09-10T07:43Z and the install ran after 2026-09-17T07:43Z; nothing was added tominimumReleaseAgeExcludes.packages/editor/App.tsxno longer imports@plannotator/ui/utils/mermaid-eager; the runtime resolves throughutils/mermaid's existingimport('mermaid')on the firstMermaidBlockrender.MermaidBlockshows the source fence under arole="status""Rendering diagram…" line until the first SVG lands (never the error panel as a placeholder), andapplyMermaidThemeis keyed on the runtime object so the lazily loaded runtime is themed on its first render.mermaid-eagerstays exported for hosts that want startup registration.tests/entry-assets.test.tsnow asserts the eager marker is absent from both bundles;DiagramBlock.lazyRetry.test.tsxpins the pending state.edgePathsorder change and what a host should do, the Safari 17.4+ floor, the lazy-load contract, the theming contract with and without tokens, the publish order); README and AGENTS updated; the visual-explainer skill's render gate expects Mermaid 12.a42aefc8, so core 0.25.3 carriesparseHtmlElementContext/MAX_ELEMENT_CONTEXT_BYTES/MAX_PAGE_URL_LENGTHon@plannotator/core/html-anchorand the element-context round trip. That is also why the ui pin moves to 0.25.3.Bundle sizes (gzip level 9; main =
a42aefc8)apps/hook/dist/index.htmlapps/hook/dist/review.htmlindex-*.jsmermaid.core-*.js(lazy, first diagram)elk-*.js(Mermaid's own import, first ELK layout)Honest reading: the single-file builds (hook, review, opencode, the compiled binary) inline every dynamic import through
inlineDynamicImports, so the lazy import saves nothing there — the +1.85 MB onindex.htmlis Mermaid 12's own runtime plus ELK, and it would be the same with the eager import kept (the earlier eval measured a 61-byte difference). The lazy import only moves bytes on a chunked build: the share portal's entry chunk drops by 660 KB, andmermaid.core(plus ELK, which Mermaid fetches itself either way) is downloaded only when a document actually has a diagram.Browser floor
Mermaid 12 is built for Safari 17.4+ and ES2024 (upstream release note; Node 22.12+ for anything importing it server-side). A host that must render diagrams on an older Safari stays on ui 0.39.x. Nothing else in
@plannotator/uimoved its floor.Publishing (by hand, in this order — CI never publishes these packages)
--provenancedoes not work from a local publish (no OIDC);--tag nextfirst andnpm dist-tag add … latestafter the consumer preflight is the established pattern.Security
Mermaid 12 brings chevrotain 11.1.2 (via langium), which pins
lodash-esexactly 4.17.23 (CVE-2026-4800 high, CVE-2026-2950 medium) beside the 4.18.1 main already resolves through dagre-d3-es; a root"overrides": { "lodash-es": "4.18.1" }forces the single 4.18.1 copy (grep -o '"lodash-es@[0-9.]*"' bun.lock | sort -u→ only4.18.1), and chevrotain still parses every grammar under it: all 15 eval diagrams render with zero errors in the built plan editor, typecheck / ui utils tests / MermaidBlock DOM tests /smoke:packagepass, and the rebuilt bundles are byte-identical in size to the table above.Verification
bun run typecheckclean;bun test packages/ui/utils packages/core packages/shared(1930 pass);DOM_TESTS=1 bun test packages/ui/components/MermaidBlock* packages/ui/components/Viewer* DiagramBlock.lazyRetry(92 pass);bun test scripts/dom-test-allowlist.test.ts tests/entry-assets.test.ts apps/skills/extra/plannotator-visual-explainer/SKILL.test.ts(33 pass, including the built-HTML marker checks against the freshdist/).bun run --cwd packages/ui smoke:package: passes ("Verified @plannotator/ui@0.40.0 packs, resolves AnnotationPanel/Viewer/StickyHeaderLane/parser, and installs externally with @plannotator/core@0.25.3").bun run --cwd apps/guides-show check:manifest: in sync (the viewer bundle carries no Mermaid).bun run --cwd apps/review build && bun run build:hook && bun run build:opencode && bun run build:portal./private/tmp/claude-501/-Users-ramos-plannotator-plannotator/34d56d5a-33a8-4878-92b2-3f4318214ae2/scratchpad/mermaid12-v040/index.html— every palette × mode on 11 vs 12 with the contrast numbers, side-by-side before/after for six palettes, and the size table.