Skip to content

Add Mermaid Local Editor (Custom Template)#7626

Merged
knsv merged 29 commits intomermaid-js:developfrom
Dvurechensky-Tools:develop
May 6, 2026
Merged

Add Mermaid Local Editor (Custom Template)#7626
knsv merged 29 commits intomermaid-js:developfrom
Dvurechensky-Tools:develop

Conversation

@Dvurechensky
Copy link
Copy Markdown
Contributor

@Dvurechensky Dvurechensky commented Apr 15, 2026

Mermaid Local Editor (Custom Template)

Overview

This contribution introduces a lightweight local editor for Mermaid diagrams, implemented as a static HTML interface on top of the existing build output.

The editor is designed to run directly from the compiled dist directory without requiring any additional tooling, frameworks, or runtime dependencies.


Functionality

The template provides the following capabilities:

  • Live diagram editing with immediate rendering
  • Multiple diagram management using localStorage
  • Automatic persistence of diagram content and view state
  • Zoom and pan controls (mouse-based interaction)
  • Keyboard navigation between nodes
  • Node highlighting (hover and selection)
  • View state restoration (per diagram)
  • SVG export of the current diagram
  • Toolbar visibility toggle

The implementation is intentionally minimal and relies only on the Mermaid runtime (mermaid.min.js).


Architecture

The editor operates as a static layer:

  • mermaid.min.js is produced by the existing build pipeline
  • index.html provides the UI and interaction logic
  • A simple static server is used for local execution

No changes are made to Mermaid’s internal rendering logic.


Build Integration

Additional scripts were introduced to integrate the editor into the existing workflow.

clean

rimraf packages/mermaid/dist

Removes the existing build output.


copy:index

cpy templates/index.html packages/mermaid/dist/ --flat

Copies the editor template into the dist directory.

The --flat option ensures that the file is placed directly at:

packages/mermaid/dist/index.html

serve:dist

cd packages/mermaid/dist && python -m http.server 8080

Starts a static HTTP server serving the compiled output.


build:mermaid:full

pnpm clean && pnpm build:mermaid && pnpm copy:index && pnpm serve:dist

Executes the full pipeline:

  1. Cleans the build directory
  2. Builds the Mermaid bundle
  3. Copies the editor template
  4. Starts a local server

Result

After running the full build:

packages/mermaid/dist/
 ├── mermaid.min.js
 ├── index.html

Opening the served directory provides a functional local editor for Mermaid diagrams.


Scope

  • The implementation does not modify Mermaid core
  • It is fully isolated at the build/output level
  • It can be used as a development utility or demonstration interface

Notes

This approach enables a simple way to work with Mermaid locally without relying on external playgrounds or integrations.

Screenshots

  • image

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 15, 2026

🦋 Changeset detected

Latest commit: 9f7ea0f

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

This PR includes changesets to release 1 package
Name Type
@mermaid-js/mermaid-local-editor Patch

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

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

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 15, 2026

Deploy Preview for mermaid-js ready!

Name Link
🔨 Latest commit 9f7ea0f
🔍 Latest deploy log https://app.netlify.com/projects/mermaid-js/deploys/69fa15719e2c2400081f8442
😎 Deploy Preview https://deploy-preview-7626--mermaid-js.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

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

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 15, 2026

Open in StackBlitz

@mermaid-js/examples

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

mermaid

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

@mermaid-js/layout-elk

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

@mermaid-js/layout-tidy-tree

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

@mermaid-js/mermaid-zenuml

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

@mermaid-js/parser

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

@mermaid-js/tiny

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

commit: 9f7ea0f

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 15, 2026

Codecov Report

❌ Patch coverage is 0% with 435 lines in your changes missing coverage. Please review.
✅ Project coverage is 3.29%. Comparing base (71f9731) to head (9f7ea0f).

Files with missing lines Patch % Lines
...ackages/mermaid-local-editor/static/js/renderer.js 0.00% 129 Missing ⚠️
packages/mermaid-local-editor/static/js/ui.js 0.00% 97 Missing ⚠️
...kages/mermaid-local-editor/static/js/navigation.js 0.00% 79 Missing ⚠️
packages/mermaid-local-editor/static/app.js 0.00% 66 Missing ⚠️
packages/mermaid-local-editor/static/js/storage.js 0.00% 43 Missing ⚠️
packages/mermaid-local-editor/static/js/config.js 0.00% 21 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           develop   #7626      +/-   ##
==========================================
- Coverage     3.31%   3.29%   -0.03%     
==========================================
  Files          543     549       +6     
  Lines        57217   57652     +435     
  Branches       840     846       +6     
==========================================
  Hits          1898    1898              
- Misses       55319   55754     +435     
Flag Coverage Δ
unit 3.29% <0.00%> (-0.03%) ⬇️

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

Files with missing lines Coverage Δ
packages/mermaid-local-editor/static/js/config.js 0.00% <0.00%> (ø)
packages/mermaid-local-editor/static/js/storage.js 0.00% <0.00%> (ø)
packages/mermaid-local-editor/static/app.js 0.00% <0.00%> (ø)
...kages/mermaid-local-editor/static/js/navigation.js 0.00% <0.00%> (ø)
packages/mermaid-local-editor/static/js/ui.js 0.00% <0.00%> (ø)
...ackages/mermaid-local-editor/static/js/renderer.js 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@argos-ci
Copy link
Copy Markdown

argos-ci Bot commented Apr 15, 2026

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

Build Status Details Updated (UTC)
default (Inspect) 👍 Changes approved 1 changed May 5, 2026, 4:19 PM

Comment thread templates/index.html Fixed
Comment thread templates/index.html Fixed
Comment thread templates/index.html Fixed
Comment thread templates/index.html Fixed
Comment thread templates/index.html Fixed
Comment thread templates/index.html Fixed
Comment thread templates/index.html Fixed
Comment thread templates/index.html Fixed
Comment thread templates/index.html Fixed
Comment thread templates/index.html Fixed
Comment thread templates/index.html Fixed
Comment thread templates/index.html Fixed
Comment thread templates/index.html Fixed
@Dvurechensky
Copy link
Copy Markdown
Contributor Author

This PR only adds a new template file and does not modify any existing rendering logic.

The Argos visual diff appears to be unrelated to this change.

Please confirm if new HTML templates are expected to be excluded from visual tests.

Copy link
Copy Markdown
Collaborator

@knsv-bot knsv-bot left a comment

Choose a reason for hiding this comment

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

[sisyphus-bot]

Thanks for putting this together, @Dvurechensky — there's a clear amount of effort here, and I can see the appeal of having a zero-tooling local editor that just works against dist/. Before we get into the line-level feedback, there's a scope question that should probably be answered first, because a lot of the other items depend on it.

🎉 What's working well

  • Defense-in-depth on the render path is genuinely well thought out: DOMPurify sanitization, followed by a second manual attribute strip, inserted into an iframe with sandbox="allow-same-origin" (notably without allow-scripts). Even if sanitization were bypassed, the sandbox blocks script execution. That's the right instinct.
  • deterministicIds: true + the IS_E2E branch shows you thought about testability, which is nice to see in a standalone tool.
  • The localStorage-backed multi-diagram management is a neat UX touch.

The scope question (please read first)

This PR overlaps substantially with infrastructure the project already has:

  • demos/ — a directory of ~25 pre-built HTML demo pages that already run against the dev build.
  • pnpm dev — esbuild-based dev server on http://localhost:9000/ with live reload (see .esbuild/server.ts). This is the canonical way to work with Mermaid locally.
  • mermaid.live — the official, community-maintained live editor.

Adding a second, parallel editor surface (with its own Python server, its own template directory, and its own root-level npm scripts) inside the core library repo is a significant expansion of what the repo is responsible for. The maintainers are best placed to decide whether that's desirable — but it's probably worth getting a 👍 from them on the direction before iterating on the code itself. I'd suggest:

  1. Opening a discussion or issue referencing this work and asking whether a local editor belongs in mermaid-js/mermaid core, or whether it should live as a separate project (a common pattern for companion tools).
  2. If maintainers are interested, consider whether the existing demos/ or dev/example.html pages could host this instead of a new templates/ top-level directory.

Everything below assumes a positive answer to the above — but if this ends up living elsewhere, most of these items won't apply.


Things to address (if this goes ahead in-repo)

🔴 [blocking] External CDN load with no SRI — templates/index.html:6

<script src="https://unpkg.com/dompurify@3.0.6/dist/purify.min.js"></script>

This fetches DOMPurify from unpkg over the network on every page load, with no integrity="sha384-..." hash. Two problems: (a) breaks the "run from dist/ with no tooling" promise the moment you're offline, and (b) supply-chain risk — if unpkg serves a modified file, the sandbox doesn't help because DOMPurify is what's doing the sanitizing. Mermaid already depends on DOMPurify internally; please either bundle it with the editor or install it as a dev dep and copy the file alongside mermaid.min.js in copy:index.

🔴 [blocking] Non-English content throughout — templates/index.html

  • <html lang="ru"> on line 2
  • UI strings: 'Показать панель' / 'Скрыть панель' (line ~396)
  • Code comments: Подсветка прямоугольников нод (line ~53), // FIX: вернуть namespace (иначе текст пропадает) (line ~196), // вставка в iframe (line ~218), // убирает inline-центрирование / // убирает авто-отступы / // якорь трансформаций (lines ~104-107)

Mermaid is an English-first project and the rest of the codebase is consistently English. Please translate lang, UI strings, and inline comments to English.

🔴 [blocking] Python runtime dependency — package.json:"serve:dist"

"serve:dist": "cd packages/mermaid/dist && python -m http.server 8080"

This introduces Python as a build-pipeline dependency in an otherwise Node-only monorepo. Not every contributor has python on PATH, and behavior differs between Python 2/3 and Windows vs Unix. Please switch to a Node-based static server — the project already uses start-server-and-test; http-server, serve, or sirv-cli would all fit the existing toolchain.

🟡 [important] No changeset or linked issue

For a user-facing addition that ships via dist/, a changeset is expected (see CONTRIBUTING.md and the existing .changeset/ flow). The PR also doesn't reference an issue where this was scoped/agreed. Linking one (or adding a short rationale to the PR description) will help a human reviewer assess fit.

🟡 [important] href stripped from all elements — templates/index.html:~210

svgEl.querySelectorAll('*').forEach((el) => {
  [...el.attributes].forEach((attr) => {
    if (attr.name.startsWith('on') || attr.name === 'href' || attr.name === 'xlink:href') {
      el.removeAttribute(attr.name);
    }
  });
});

Stripping every href and xlink:href breaks legitimate links Mermaid generates for click directives, and also strips xlink:href on <use> elements that reference in-document symbols (used by some shape sets). DOMPurify already blocks javascript: URLs — this extra pass is both redundant for security and destructive for functionality. Either drop it, or scope it to only strip values starting with javascript: / data: with non-SVG media types.

🟡 [important] Centering math appears off — templates/index.html:~460

const nodeCenterY = nodeRect.top + nodeRect.height / 6;
const contCenterY = contRect.top + contRect.height / 6;
// same pattern for X, using width / 6

Dividing by 6 places the "center" one-sixth of the way down/across the node and container — should be / 2 for a true midpoint. Worth double-checking against the behavior you intended.

🟡 [important] Dead / duplicate code

  • Outer-scope let isPanning = false; let startX = 0, startY = 0; (~line 152) are shadowed by isPanningLocal / startXLocal / startYLocal inside render() and never used.
  • const _render = render; (~line 522) — assigned and never read.
  • function getRootGroup() (~line 342) — defined and never called.
  • Two src.addEventListener('input', ...) listeners are registered separately (one renders, one debounces save). A single debounced listener is cleaner and avoids running the render pipeline twice per keystroke.
  • Two #preview svg { ... } CSS rule blocks (~lines 90 and 96) that overlap — fold into one.

🟡 [important] build:mermaid:full has redundant + inconsistent steps

  • pnpm clean is redundant with build:esbuild, which already runs pnpm run -r clean.
  • Port is hardcoded to 8080, while pnpm dev uses MERMAID_PORT. If the editor is going to live alongside the dev server, sharing the port convention would be less surprising.

🟢 [nit] diagrams[name] = diagrams[name] || {} in the save handler preserves an object whose src and view are overwritten immediately after. The fallback isn't doing work.

💡 [suggestion] If this stays in the repo, moving the inline <style> and <script> blocks into templates/editor.css and templates/editor.js would let ESLint, CSpell, and Prettier cover them — right now a 500-line script is opaque to the usual quality gates.


Security summary

No confirmed XSS vectors in the rendering pipeline — the DOMPurify + sandboxed iframe combination is sound. The main security issue is the unpinned external CDN fetch (above). ADD_TAGS: ['foreignObject'] is acceptable here because DOMPurify still sanitizes the contents, and the iframe blocks script execution regardless.


Verdict

Requesting changes, but the primary ask is really the scope discussion with maintainers — let's land that first and then iterate on the technical items. Thanks again for the contribution; the render-path thinking in particular is solid. 🙂

@Dvurechensky
Copy link
Copy Markdown
Contributor Author

@knsv-bot

Thanks for the detailed review — really appreciate the depth here.

You're absolutely right that the biggest question is whether this belongs inside the core repo or should live as a separate companion tool.

My initial intention was to provide a zero-tooling, fully offline editor that works directly against dist/, especially for cases where pnpm dev or mermaid.live are not ideal (e.g. isolated environments, quick prototyping, reverse/debug scenarios).

That said, I agree this introduces a parallel surface and expands the repo scope.

Before iterating further on the implementation, I’ll open a discussion with maintainers to clarify whether:

  1. This should live inside the core repo (possibly integrated into demos/)
  2. Or be split into a separate project

Once direction is clear, I’ll address the technical points accordingly.

Thanks again — especially for the security feedback, that was very useful.

@knsv
Copy link
Copy Markdown
Collaborator

knsv commented Apr 17, 2026

Hi @Dvurechensky — thanks for the ping.

My take: I think this can live in this repo. We're a monorepo, and a standalone editor under packages/ (e.g. packages/mermaid-local-editor or similar) slots in naturally alongside the other packages. So the scope concern from the bot isn't a blocker for me — it's a positioning question, and I'm fine with it being here.

That said, the blockers the bot flagged are real and need fixing before this goes further:

  • Drop the Python dependency. This is a Node-only monorepo; serve:dist has to be a Node-based static server (serve, http-server, sirv-cli — whatever fits). Python on PATH isn't a fair assumption for contributors.
  • Bundle DOMPurify instead of fetching from unpkg with no SRI. Loading a sanitizer from a CDN without an integrity hash undercuts the whole security story, and it breaks the "runs offline from dist/" promise anyway. Mermaid already depends on DOMPurify — reuse it.
  • Translate the UI strings, lang="ru", and code comments to English. We want the whole codebase consistently English-first.

If you take care of those three, plus move the template out of a new top-level templates/ into a proper package directory, I think this is genuinely nifty — the localStorage-based multi-diagram UX and the sandboxed-iframe render path are both nice touches. Happy to look again once those are addressed.

@autofix-ci
Copy link
Copy Markdown
Contributor

autofix-ci Bot commented Apr 17, 2026

Hi! I'm autofix logoautofix.ci, a bot that automatically fixes trivial issues such as code formatting in pull requests.

I would like to apply some automated changes to this pull request, but it looks like I don't have the necessary permissions to do so. To get this pull request into a mergeable state, please do one of the following two things:

  1. Allow edits by maintainers for your pull request, and then re-trigger CI (for example by pushing a new commit).
  2. Manually fix the issues identified for your pull request (see the GitHub Actions output for details on what I would like to change).

# Mermaid Local Editor (Custom Template)

## Overview

This contribution introduces a lightweight local editor for Mermaid diagrams, implemented as a static HTML interface on top of the existing build output.

The editor is designed to run directly from the compiled `dist` directory without requiring any additional tooling, frameworks, or runtime dependencies.

---

## Functionality

The template provides the following capabilities:

* **Live diagram editing** with immediate rendering
* **Multiple diagram management** using `localStorage`
* **Automatic persistence** of diagram content and view state
* **Zoom and pan controls** (mouse-based interaction)
* **Keyboard navigation** between nodes
* **Node highlighting** (hover and selection)
* **View state restoration** (per diagram)
* **SVG export** of the current diagram
* **Toolbar visibility toggle**

The implementation is intentionally minimal and relies only on the Mermaid runtime (`mermaid.min.js`).

---

## Architecture

The editor operates as a static layer:

* `mermaid.min.js` is produced by the existing build pipeline
* `index.html` provides the UI and interaction logic
* A simple static server is used for local execution

No changes are made to Mermaid’s internal rendering logic.

---

## Build Integration

Additional scripts were introduced to integrate the editor into the existing workflow.

### `clean`

```bash
rimraf packages/mermaid/dist
```

Removes the existing build output.

---

### `copy:index`

```bash
cpy templates/index.html packages/mermaid/dist/ --flat
```

Copies the editor template into the `dist` directory.

The `--flat` option ensures that the file is placed directly at:

```
packages/mermaid/dist/index.html
```

---

### `serve:dist`

```bash
cd packages/mermaid/dist && python -m http.server 8080
```

Starts a static HTTP server serving the compiled output.

---

### `build:mermaid:full`

```bash
pnpm clean && pnpm build:mermaid && pnpm copy:index && pnpm serve:dist
```

Executes the full pipeline:

1. Cleans the build directory
2. Builds the Mermaid bundle
3. Copies the editor template
4. Starts a local server

---

## Result

After running the full build:

```
packages/mermaid/dist/
 ├── mermaid.min.js
 ├── index.html
```

Opening the served directory provides a functional local editor for Mermaid diagrams.

---

## Scope

* The implementation does not modify Mermaid core
* It is fully isolated at the build/output level
* It can be used as a development utility or demonstration interface

---

## Notes

This approach enables a simple way to work with Mermaid locally without relying on external playgrounds or integrations.
…moved). This is a controlled local editor environment, risk is mitigated.
@Dvurechensky
Copy link
Copy Markdown
Contributor Author

CI is failing due to:
fatal: bad object

The validate-lockfile step uses git diff between commits
that are not available because checkout uses shallow clone (fetch-depth: 1).

Fix:
actions/checkout@v4 with fetch-depth: 0

@Dvurechensky
Copy link
Copy Markdown
Contributor Author

@knsv Hi — thanks for the detailed review.

I've addressed the points raised:

  • Removed the Python dependency
    The editor is now served via a Node-based static server (sirv).
    It runs entirely within the existing monorepo tooling and does not require Python on PATH.

  • Bundled DOMPurify locally
    DOMPurify is no longer fetched from a CDN.
    It is copied from node_modules into the local vendor/ directory as part of the build pipeline, ensuring:

    • offline support
    • no runtime network dependency
    • no integrity concerns
  • Ensured English-first consistency
    All UI strings, comments, and markup have been translated to English, and lang="en" is set in the HTML.

  • Moved the editor into a proper package structure
    The editor now lives under:

    packages/mermaid-local-editor
    

    and is integrated into the existing build pipeline.
    A minimal package.json is included to align with workspace expectations.


Additional improvements

Beyond the requested changes, I also refactored the original single-file implementation:

  • Split the editor into modular components:

    • storage (localStorage handling)
    • renderer (Mermaid rendering + sandboxed iframe)
    • ui (UI bindings and interactions)
    • navigation (keyboard navigation and node focus)
  • Introduced a clearer separation of concerns in the runtime flow

  • Kept the sandboxed iframe rendering model, with DOMPurify sanitization applied before insertion, preserving the defense-in-depth approach

  • Ensured the editor runs fully from dist/ with no external dependencies


If this structure looks good to you, I can follow up with further refinements if needed.

@Dvurechensky
Copy link
Copy Markdown
Contributor Author

I don't understand the reason for the Argos error.

@knsv
Copy link
Copy Markdown
Collaborator

knsv commented Apr 21, 2026

I don't understand the reason for the Argos error.

It is a flaky test, we are about to fix it.

Will rerun the review to look at your new changes🤞

Copy link
Copy Markdown
Collaborator

@knsv-bot knsv-bot left a comment

Choose a reason for hiding this comment

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

[sisyphus-bot]

Thanks @Dvurechensky — really significant progress since the last round. The restructure into packages/mermaid-local-editor/ plus the modular JS split is a big improvement, and the CDN / Python-server / language fixes all landed cleanly. Nice work. 🎉

🎉 What's working well now (up from round 1)

  • DOMPurify is now bundled locally via copy:dompurify from node_modules — the supply-chain and offline-capability concerns are both resolved.
  • sirv instead of python -m http.server — good Node-native choice, fits the rest of the toolchain.
  • <html lang="en"> and the toolbar labels are all English now.
  • Monorepo package layout (packages/mermaid-local-editor/) plus the config.js/storage.js/renderer.js/ui.js/navigation.js split makes the code dramatically more readable and answers the earlier scope-creep question in a much better way.

🔴 [blocking] — eslint.config.js:28 blanket-ignores the whole new package

'packages/mermaid-local-editor/**',

This excludes the entire new package — ~500 lines of JS, CSS, and HTML — from ESLint, Prettier, and CSpell. Other packages in this monorepo are fully covered. A new package shouldn't get a free pass, and in practice this is what lets the items below slip through (the Russian CSS comments would have been caught by CSpell; the duplicate CSS rule by the formatter; the dead variables by no-unused-vars; etc.).

Please remove the blanket ignore. If there's a narrow carve-out that's genuinely needed (for example the copied third-party files under static/vendor/), limit the entry to that:

'packages/mermaid-local-editor/dist/',          // if there's a build output
'packages/mermaid/dist/mermaid-local-editor/',  // the served output

…and fix whatever the first lint pass flags.

🟡 [important] — Russian CSS comments remain in static/styles.css

  • lines ~54: /* фон */, /* свечение */
  • lines ~101–103: /* убирает inline-центрирование */, /* убирает авто-отступы */, /* якорь трансформаций */

Once the ESLint ignore is dropped, CSpell will highlight these. Worth doing a pass across all the new files to make sure no other non-English comments snuck in.

🟡 [important] — href / xlink:href / on* stripping still hurts functionality — static/js/renderer.js:42–48

svgEl.querySelectorAll('*').forEach((el) => {
  [...el.attributes].forEach((attr) => {
    if (attr.name.startsWith('on') || attr.name === 'href' || attr.name === 'xlink:href') {
      el.removeAttribute(attr.name);
    }
  });
});

DOMPurify already blocks javascript: / data: URLs, so this pass is redundant for security. What it does still do, however, is break legitimate hrefs that Mermaid emits for click directives, and strip xlink:href from <use> elements (which some shape sets use to reference in-document symbols). Suggestions:

  • Drop the pass entirely and rely on DOMPurify, or
  • Keep it protocol-scoped: only strip when attr.value.startsWith('javascript:') || attr.value.startsWith('data:').

A quick smoke test against a flowchart with click A "https://example.com" in demos/flowchart.html will show the issue.

🟡 [important] — Centering still uses / 6static/js/navigation.js:39–45

const nodeCenterY = nodeRect.top + nodeRect.height / 6;
const contCenterY = contRect.top + contRect.height / 6;
// ...same pattern for X with width / 6

Mid-point of a rectangle is / 2. If / 6 is intentional (e.g., to keep the selected node biased toward the upper-left so it's always in view), a one-line comment explaining that would help. Otherwise this likely wants to be / 2.

🟡 [important] — Duplicate CSS rule — static/styles.css:92 and :98

#preview svg {
  width: 100%;
  height: auto;
  padding: 12px;
  position: relative;
  overflow: visible;
}
#preview svg {
  display: block;
  margin: 0;
  transform-origin: 0 0;
}

Same selector, non-overlapping properties — fold into one block.

🟡 [important] — No changeset

Adding a new monorepo package and four root-level npm scripts is user-facing. Please run pnpm changeset (or add the file manually) with a chore: or feat: prefix describing the addition. A patch bump is probably fine since nothing user-visible in the core mermaid package itself changes.

🟢 [nit] — Misleading variable name — static/js/ui.js:89

const toolbar = document.getElementById('src');
// ...
toolbar.classList.toggle('collapsed', toolbarCollapsed);

The variable is named toolbar but it holds the source textarea (#src). Combined with the button labeled "toggle toolbar," what actually collapses on click is the source panel, not the toolbar (which is #toolbar). Either rename to srcPanel and adjust the button's label, or retarget #toolbar if the intent was the real toolbar.

💡 [suggestion] — setTimeout(…, 0)requestAnimationFramestatic/js/renderer.js:56

Already using requestAnimationFrame a few lines below — using it here too for the rebuildNavNodes() call keeps it consistent and avoids the setTimeout(…, 0) footgun with microtask ordering.

💡 [suggestion] — Try a click-directive diagram end-to-end

Loading demos/flowchart.html-style content in the new editor and clicking a node would confirm (or rule out) the href-stripping regression flagged above.


Scope (context, not a finding)

The round-1 question about whether this belongs in the core mermaid-js/mermaid repo vs. as a separate project is better answered by the new packages/mermaid-local-editor/ layout — it's now genuinely isolated, which is much nicer. Still worth a 👍 from @knsv / maintainers on direction before spending a lot more polishing time on it, just so nobody is surprised.

Security summary

No new XSS vectors. The iframe sandbox (sandbox="allow-same-origin" with no allow-scripts) plus DOMPurify is sound. The remaining href issue is a functionality concern, not a security one.


Verdict: REQUEST_CHANGES (1 🔴, 5 🟡). Much narrower list than round 1, and most items are mechanical — I think we can get this across the finish line quickly once the ESLint ignore is lifted.

Heads-up on protocol: our automated review escalates to a human reviewer after two rounds of requested changes, so the next round (if needed) would route this to a maintainer rather than another bot pass.

@knsv
Copy link
Copy Markdown
Collaborator

knsv commented Apr 21, 2026

Good progress @Dvurechensky !! Only mechanical changes left!

Verdict: REQUEST_CHANGES (1 🔴, 5 🟡). Much narrower list than round 1, and most items are mechanical — I think we can get this across the finish line quickly once the ESLint ignore is lifted.

@Dvurechensky
Copy link
Copy Markdown
Contributor Author

@knsv @knsv-bot

  1. [🔴 [blocking] — eslint.config.js:28 blanket-ignores the whole new package]

    • Ok
  2. [🟡 [important] — Russian CSS comments remain in static/styles.css]

    • Ok
  3. [🟡 [important] — href / xlink:href / on* stripping still hurts functionality — static/js/renderer.js:42–48]

    • Ok
  4. [🟡 [important] — Centering still uses / 6 — static/js/navigation.js:39–45]

    The /6 offset is intentional rather than midpoint centering.

    This editor is optimized for navigation through directional diagrams
    (LR / TD), so selected nodes are biased toward the upper-left area,
    leaving more forward canvas visible.

    Added inline comments to clarify the behavior.

  5. [🟡 [important] — Duplicate CSS rule — static/styles.css:92 and :98]

    • Ok
  6. [🟡 [important] — No changeset]

    • Ok

Other:

  • Integrated packages/mermaid-local-editor into the monorepo typed ESLint / TypeScript config instead of relying on ignore rules.
  • Declared mermaid and DOMPurify as browser globals in renderer.js since they are intentionally loaded via script tags.
  • Cleaned formatting and passed local pre-commit checks (lint-staged, ESLint, formatting).

@Dvurechensky
Copy link
Copy Markdown
Contributor Author

@knsv @knsv-bot

And also corrected
7. 🟢 [nit] — Misleading variable name — static/js/ui.js:89

  • Ок

@Dvurechensky
Copy link
Copy Markdown
Contributor Author

@knsv-bot @knsv
Fine, Argos still 😴

@pbrolin47
Copy link
Copy Markdown
Collaborator

Hi @Dvurechensky,
The failing Argos-test is not related to this PR, so I approved the test. Note: There is a PR published intended to resolve the flakiness of that test, #7644

@Dvurechensky
Copy link
Copy Markdown
Contributor Author

E2E bad 😑

@ashishjain0512
Copy link
Copy Markdown
Collaborator

@Dvurechensky The argos quota limit is now reset, please take the latest pull from develop, and the test cases should go properly. We'll be happy to merge this PR once it is green

@Dvurechensky
Copy link
Copy Markdown
Contributor Author

@ashishjain0512 It seems like everything went well 🎈

@knsv knsv added this pull request to the merge queue May 6, 2026
@knsv
Copy link
Copy Markdown
Collaborator

knsv commented May 6, 2026

Merging 🥳

Merged via the queue into mermaid-js:develop with commit 2b31756 May 6, 2026
25 checks passed
@mermaid-bot
Copy link
Copy Markdown

mermaid-bot Bot commented May 6, 2026

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants