From 2858780e476ae954aa2e175bd23bb32ea56eafca Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 17 Jun 2026 00:44:17 +0000 Subject: [PATCH 1/3] feat(surfaces): add mermaid diagram parts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a `mermaid` surface part across all three tiers: agents hand over diagram source (flowchart, sequence, ERD, gantt, state, …) and the trusted viewer renders it natively to a themed SVG via the mermaid library — no sandboxed iframe. - types/validation: MermaidPart in the data model, strict (REST) and loose (MCP, drops blank) schemas, and the shared MCP spec (JSON schema enum, zod, descriptions). - viewer: MermaidPart.tsx lazy-loads mermaid, renders with securityLevel 'strict' (DOMPurify-sanitized SVG, no scripts/HTML labels) and suppressErrorRendering, re-renders on light/dark flips, and shows the source in an error fallback on a parse failure. - CLI: `sideshow mermaid ` and `--mermaid` on `sideshow publish`. - docs/tests: design guide, changelog, API round-trip + MCP drop-empty tests, and an e2e spec (render + error fallback). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01Gx95NNUML7pUjJAQUuNaKt --- bin/sideshow.js | 23 ++++++++++++ e2e/mermaid.spec.ts | 48 ++++++++++++++++++++++++ guide/DESIGN_GUIDE.md | 12 +++++- package.json | 1 + server/mcpSpec.ts | 30 ++++++++++----- server/surfaceParts.ts | 14 +++++++ server/types.ts | 35 +++++++++++++++-- test/api.test.ts | 41 ++++++++++++++++++++ viewer/src/Card.tsx | 5 +++ viewer/src/MermaidPart.tsx | 77 ++++++++++++++++++++++++++++++++++++++ viewer/src/api.ts | 2 + viewer/src/styles.css | 27 +++++++++++++ 12 files changed, 299 insertions(+), 16 deletions(-) create mode 100644 e2e/mermaid.spec.ts create mode 100644 viewer/src/MermaidPart.tsx diff --git a/bin/sideshow.js b/bin/sideshow.js index 8fe59f7..95aee5e 100755 --- a/bin/sideshow.js +++ b/bin/sideshow.js @@ -18,6 +18,7 @@ usage: sideshow publish [options] publish an HTML surface (one html part) --title surface title --md add a markdown part (prose) — combine with html + --mermaid add a mermaid part (diagram source → SVG) — combine with html --diff add a diff part from a unified/git patch (combine with html) --terminal add a terminal part from monospace/ANSI output --image upload an image and append it as an image part @@ -48,6 +49,9 @@ usage: --term-title label shown in the terminal window chrome --cols render width hint, in columns (also: --session, --session-title, --agent, --new-session) + sideshow mermaid [options] publish a mermaid surface (diagram → SVG) + --title surface title + (also: --session, --session-title, --agent, --new-session) sideshow update revise a surface (new version, same card) --title replace title sideshow wait [options] block until the user comments (long-poll) @@ -410,6 +414,7 @@ const commands = { options: { title: { type: "string" }, md: { type: "string" }, + mermaid: { type: "string" }, diff: { type: "string" }, image: { type: "string" }, terminal: { type: "string" }, @@ -424,6 +429,9 @@ const commands = { if (flags.md !== undefined) { parts.push({ kind: "markdown", markdown: readContent(flags.md || "-") }); } + if (flags.mermaid !== undefined) { + parts.push({ kind: "mermaid", mermaid: readContent(flags.mermaid || "-") }); + } if (flags.diff !== undefined) { parts.push({ kind: "diff", @@ -577,6 +585,21 @@ const commands = { out({ ...surface, url: `${BASE}/s/${surface.id}` }); }, + async mermaid() { + const { values: flags, positionals } = parse({ + allowPositionals: true, + options: { + title: { type: "string" }, + session: { type: "string" }, + "session-title": { type: "string" }, + agent: { type: "string" }, + "new-session": { type: "boolean" }, + }, + }); + const parts = [{ kind: "mermaid", mermaid: readContent(positionals[0]) }]; + outSurface(await publishSurface(parts, flags)); + }, + async update() { const { values: flags, positionals } = parse({ allowPositionals: true, diff --git a/e2e/mermaid.spec.ts b/e2e/mermaid.spec.ts new file mode 100644 index 0000000..3623966 --- /dev/null +++ b/e2e/mermaid.spec.ts @@ -0,0 +1,48 @@ +import { expect, publishParts, test } from "./fixtures.ts"; + +const DIAGRAM = [ + "graph TD", + " A[Start] --> B{Choice}", + " B -->|yes| C[Do it]", + " B -->|no| D[Skip]", +].join("\n"); + +test("a mermaid part renders a diagram as inline SVG in the viewer", async ({ page, server }) => { + await publishParts(server.url, { + title: "Flow", + agent: "e2e", + parts: [{ kind: "mermaid", mermaid: DIAGRAM }], + }); + + await page.goto(server.url); + const card = page.locator(".card:not(#sessionThread)"); + const mermaid = card.locator(".mermaidpart"); + + // rendered natively in the viewer document (no sandboxed iframe), as an SVG + const svg = mermaid.locator("svg"); + await expect(svg).toBeVisible(); + // the node labels made it into the rendered graph + await expect(mermaid).toContainText("Start"); + await expect(mermaid).toContainText("Choice"); + // it's structured SVG, not an error fallback + await expect(mermaid.locator(".mermaid-error")).toHaveCount(0); +}); + +test("an invalid mermaid part shows the source in an error fallback, not a crash", async ({ + page, + server, +}) => { + await publishParts(server.url, { + title: "Broken", + agent: "e2e", + // no diagram-type keyword → mermaid can't even pick a parser, so it throws + parts: [{ kind: "mermaid", mermaid: "this is definitely not a valid diagram" }], + }); + + await page.goto(server.url); + const card = page.locator(".card:not(#sessionThread)"); + const err = card.locator(".mermaidpart .mermaid-error"); + await expect(err).toBeVisible(); + // the original source is echoed so the agent can see what failed + await expect(err.locator("pre")).toContainText("not a valid diagram"); +}); diff --git a/guide/DESIGN_GUIDE.md b/guide/DESIGN_GUIDE.md index 447b5b4..62afaf1 100644 --- a/guide/DESIGN_GUIDE.md +++ b/guide/DESIGN_GUIDE.md @@ -21,6 +21,12 @@ a `kind`: interleave prose, tables, code, and pictures. Only raw _HTML_ in the source is escaped, not rendered — reach for an `html` part when you need live markup (interactivity, vector graphics, custom layout), not just to show a picture. +- **`mermaid`** — diagram source you hand over as _text_; the viewer renders it + to an SVG with mermaid (flowcharts, sequence diagrams, ERDs, gantt, state, …). + Reach for it when the shape of a system is the point — a flow, a state + machine, a schema — and you'd rather describe it than draw SVG by hand. Like + markdown it renders as data, not sandboxed markup (securityLevel `strict`); for + bespoke vector art hand-write inline `` in an `html` part instead. - **`diff`** — a patch you hand over as _data_; the trusted viewer renders it natively as a syntax-highlighted code review (split or unified). Reach for it to show a changeset or review code, not to draw. @@ -39,14 +45,15 @@ a `kind`: A surface can combine parts, e.g. `[html, diff]` is a diagram with its code review in one card, and `[markdown, diff]` is a written rationale above its changeset. Trust differs: html parts are sandboxed because you author the -markup; markdown/diff/image/trace/terminal parts are rendered by the viewer -from data — send data, never markup. +markup; markdown/mermaid/diff/image/trace/terminal parts are rendered by the +viewer from data — send data, never markup. A **`SurfacePart`** is one of: ``` { "kind": "html", "html": "

...

" } { "kind": "markdown", "markdown": "## Plan\n\n1. ...\n2. ..." } +{ "kind": "mermaid", "mermaid": "graph TD; A[Start] --> B{Ok?}; B -->|yes| C; B -->|no| D" } { "kind": "diff", "patch": "" } # preferred — compact { "kind": "diff", "files": [{ "filename": "a.ts", "before": "...", "after": "...", "language": "ts" }] } # fallback { "kind": "image", "assetId": "", "alt": "...", "caption": "..." } @@ -137,6 +144,7 @@ CLI equivalents: ``` sideshow publish sketch.html --title "Cache layout" # html surface sideshow markdown plan.md --title "Migration plan" # standalone markdown surface +sideshow mermaid flow.mmd --title "Request flow" # standalone mermaid surface sideshow diff change.patch --title "Add retry" --layout split # standalone diff surface sideshow publish sketch.html --diff change.patch --title "Retry flow" # combined [html, diff] ``` diff --git a/package.json b/package.json index 287600f..fa1faac 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "@types/node": "^25.9.3", "lint-staged": "^17.0.7", "markdown-it": "^14.2.0", + "mermaid": "^11.15.0", "oxfmt": "^0.54.0", "oxlint": "^1.69.0", "shiki": "^4.2.0", diff --git a/server/mcpSpec.ts b/server/mcpSpec.ts index 332b509..2f3d043 100644 --- a/server/mcpSpec.ts +++ b/server/mcpSpec.ts @@ -6,7 +6,8 @@ export const MCP_INSTRUCTIONS = "sideshow is a live visual surface the user watches in a browser. Publish surfaces to illustrate " + "concepts, sketch UI ideas, visualize data, or show a code review while you work. A surface is an " + "ordered list of parts: an `html` part is markup you write (a body fragment), a `markdown` part is " + - "prose the viewer renders with consistent typography, a `diff` part is a patch the viewer renders as " + + "prose the viewer renders with consistent typography, a `mermaid` part is diagram source the viewer " + + "renders to an SVG (flowchart, sequence, ERD, …), a `diff` part is a patch the viewer renders as " + "a syntax-highlighted split/unified diff. Combine them — e.g. a markdown rationale above a diff part — " + "in one card. publish_surface is the general tool; publish_snippet is " + "sugar for a single html part. Call get_design_guide once before your first publish. On your first " + @@ -36,6 +37,8 @@ const d = { assetSession: "Session id to attach the asset to", partHtml: "html part: body fragment (no doctype/html/head/body)", partMarkdown: "markdown part: prose (headings, lists, tables, code, links); raw HTML is escaped", + partMermaid: + "mermaid part: diagram source (flowchart, sequence, ERD, gantt, …), rendered to SVG by the viewer", partPatch: "diff part: a unified/git diff string — the preferred, compact form", partFiles: "diff part: before/after pairs — heavier (full contents); prefer patch", partAssetId: "image/trace part: id returned by upload_asset", @@ -54,7 +57,9 @@ const d = { const MCP_PARTS_DESCRIPTION = "Ordered parts. html: {kind:'html', html:''}. markdown: {kind:'markdown', " + "markdown:'## prose'} — for explanations, plans, tradeoff write-ups (styled text, not sandboxed; " + - "embedded raw HTML is escaped — use an html part for live markup). diff: {kind:'diff', " + + "embedded raw HTML is escaped — use an html part for live markup). mermaid: {kind:'mermaid', " + + "mermaid:'graph TD; A-->B'} — diagram source rendered to SVG (flowchart, sequence, ERD, gantt, …). " + + "diff: {kind:'diff', " + "patch:''} (preferred, compact) or {kind:'diff', files:[{filename, before, " + "after}]} (heavier). image: {kind:'image', assetId:'', alt?, caption?} — " + "renders an uploaded image; you can also embed the asset URL in an html part instead. trace: " + @@ -67,9 +72,13 @@ const MCP_PARTS_DESCRIPTION = const MCP_PART_JSON_SCHEMA = { type: "object", properties: { - kind: { type: "string", enum: ["html", "markdown", "diff", "image", "trace", "terminal"] }, + kind: { + type: "string", + enum: ["html", "markdown", "mermaid", "diff", "image", "trace", "terminal"], + }, html: { type: "string", description: d.partHtml }, markdown: { type: "string", description: d.partMarkdown }, + mermaid: { type: "string", description: d.partMermaid }, patch: { type: "string", description: d.partPatch }, files: { type: "array", @@ -118,9 +127,9 @@ const MCP_PARTS_JSON_SCHEMA = { export const MCP_TOOL_DESCRIPTIONS = { publishSurfaceHttp: - "Publish a surface to the user's sideshow board. A surface is an ordered list of parts (html, markdown, diff, image, and/or trace). Returns the surface id, view URL, and sessionId — pass sessionId as `session` on later calls. On your first publish, pass sessionTitle naming the task. If the result includes userFeedback, those are new comments from the user. Call get_design_guide first if you have not this session.", + "Publish a surface to the user's sideshow board. A surface is an ordered list of parts (html, markdown, mermaid, diff, image, and/or trace). Returns the surface id, view URL, and sessionId — pass sessionId as `session` on later calls. On your first publish, pass sessionTitle naming the task. If the result includes userFeedback, those are new comments from the user. Call get_design_guide first if you have not this session.", publishSurfaceStdio: - "Publish a surface to the user's sideshow board. A surface is an ordered list of parts (html, markdown, diff, image, and/or trace). Returns the surface id and view URL. On your first publish, pass sessionTitle naming the task. If the result includes userFeedback, those are new comments from the user. Call get_design_guide first if you have not this session.", + "Publish a surface to the user's sideshow board. A surface is an ordered list of parts (html, markdown, mermaid, diff, image, and/or trace). Returns the surface id and view URL. On your first publish, pass sessionTitle naming the task. If the result includes userFeedback, those are new comments from the user. Call get_design_guide first if you have not this session.", updateSurface: "Revise a surface in place (same card, new version). Prefer this over publishing a near-duplicate. Pass the full replacement parts array. If the result includes userFeedback, read it.", publishSnippet: @@ -271,9 +280,10 @@ const traceStepSchema = z.object({ const mcpPartSchema = z .object({ - kind: z.enum(["html", "markdown", "diff", "image", "trace", "terminal"]), + kind: z.enum(["html", "markdown", "mermaid", "diff", "image", "trace", "terminal"]), html: z.string().optional().describe(d.partHtml), markdown: z.string().optional().describe(d.partMarkdown), + mermaid: z.string().optional().describe(d.partMermaid), patch: z.string().optional().describe(d.partPatch), files: z.array(diffFileSchema).optional().describe(d.partFiles), layout: z.enum(["unified", "split"]).optional(), @@ -286,10 +296,10 @@ const mcpPartSchema = z cols: z.number().optional().describe(d.terminalCols), }) .describe( - "A surface part: html {kind:'html',html}; markdown {kind:'markdown',markdown} (prose); diff " + - "{kind:'diff',patch}; image {kind:'image',assetId} (from upload_asset); trace {kind:'trace',steps} " + - "and/or {kind:'trace',assetId}; terminal {kind:'terminal',text} (monospace output; ANSI SGR " + - "colors rendered)", + "A surface part: html {kind:'html',html}; markdown {kind:'markdown',markdown} (prose); mermaid " + + "{kind:'mermaid',mermaid} (diagram source → SVG); diff {kind:'diff',patch}; image " + + "{kind:'image',assetId} (from upload_asset); trace {kind:'trace',steps} and/or {kind:'trace',assetId}; " + + "terminal {kind:'terminal',text} (monospace output; ANSI SGR colors rendered)", ); export const STDIO_MCP_INPUT_SCHEMAS = { diff --git a/server/surfaceParts.ts b/server/surfaceParts.ts index 1c03eeb..95b2779 100644 --- a/server/surfaceParts.ts +++ b/server/surfaceParts.ts @@ -87,6 +87,17 @@ const looseMarkdownPart = z message: 'markdown part requires non-empty "markdown"', }); +const strictMermaidPart = z.object({ + kind: z.literal("mermaid"), + mermaid: requiredString("mermaid"), +}); +// Loose mode drops a blank mermaid part rather than publishing an empty card. +const looseMermaidPart = z + .object({ kind: z.literal("mermaid"), mermaid: z.string() }) + .refine((p) => p.mermaid.trim().length > 0, { + message: 'mermaid part requires non-empty "mermaid"', + }); + const strictDiffPart = z .object({ kind: z.literal("diff"), @@ -158,6 +169,7 @@ const looseTerminalPart = z.object({ const looseSurfacePart = z.union([ looseHtmlPart, looseMarkdownPart, + looseMermaidPart, looseDiffPart, looseImagePart, looseTracePart, @@ -219,6 +231,8 @@ function schemaForKind(kind: unknown): z.ZodType | null { return strictHtmlPart; case "markdown": return strictMarkdownPart; + case "mermaid": + return strictMermaidPart; case "diff": return strictDiffPart; case "image": diff --git a/server/types.ts b/server/types.ts index a9505a7..5a0a8b4 100644 --- a/server/types.ts +++ b/server/types.ts @@ -15,10 +15,17 @@ export interface Session { // A surface is an ordered list of parts. Each part declares its own kind; // the surface itself is kind-agnostic. An `html` part is arbitrary agent // markup (rendered sandboxed in an iframe); `diff`, `image`, `trace`, -// `markdown`, and `terminal` parts are structured data rendered by the trusted -// viewer. A snippet is just a surface with one html part; a +// `markdown`, `terminal`, and `mermaid` parts are structured data rendered by +// the trusted viewer. A snippet is just a surface with one html part; a // diagram-with-its-diff is `[html, diff]`. -export type SurfacePartKind = "html" | "diff" | "image" | "trace" | "markdown" | "terminal"; +export type SurfacePartKind = + | "html" + | "diff" + | "image" + | "trace" + | "markdown" + | "terminal" + | "mermaid"; export interface HtmlPart { kind: "html"; @@ -35,6 +42,17 @@ export interface MarkdownPart { markdown: string; } +// A mermaid part is diagram source (flowchart, sequence, ERD, gantt, …) the +// trusted viewer renders to SVG with the mermaid library. Like markdown it is +// NOT sandboxed: mermaid renders in the viewer's own origin with +// securityLevel 'strict', sanitizing the SVG and disabling scripts/HTML labels +// (see MermaidPart.tsx). Agents wanting hand-drawn vector art use an html part +// with inline instead. +export interface MermaidPart { + kind: "mermaid"; + mermaid: string; +} + export interface DiffFile { filename: string; before: string; @@ -96,7 +114,14 @@ export interface TerminalPart { title?: string; } -export type SurfacePart = HtmlPart | DiffPart | ImagePart | TracePart | MarkdownPart | TerminalPart; +export type SurfacePart = + | HtmlPart + | DiffPart + | ImagePart + | TracePart + | MarkdownPart + | TerminalPart + | MermaidPart; export interface SurfaceVersion { version: number; @@ -259,6 +284,8 @@ export function partsByteLength(parts: SurfacePart[]): number { n += p.markdown.length; } else if (p.kind === "terminal") { n += p.text.length + (p.title?.length ?? 0); + } else if (p.kind === "mermaid") { + n += p.mermaid.length; } else { n += (p.assetId?.length ?? 0) + (p.title?.length ?? 0); for (const s of p.steps ?? []) { diff --git a/test/api.test.ts b/test/api.test.ts index d56d1c5..225177d 100644 --- a/test/api.test.ts +++ b/test/api.test.ts @@ -240,6 +240,47 @@ test("publish_surface MCP tool round-trips a terminal part", async () => { assert.equal((await app.request(`/s/${payload.id}?part=0`)).status, 404); }); +test("publishes a mermaid part; /s has no html doc for it", async () => { + const app = makeApp(); + const res = await app.request( + "/api/surfaces", + json({ title: "Flow", parts: [{ kind: "mermaid", mermaid: "graph TD; A-->B" }] }), + ); + assert.equal(res.status, 201); + const surface = (await res.json()) as any; + assert.deepEqual(surface.kinds, ["mermaid"]); + + const full = (await (await app.request(`/api/surfaces/${surface.id}`)).json()) as any; + assert.equal(full.parts[0].kind, "mermaid"); + assert.equal(full.parts[0].mermaid, "graph TD; A-->B"); + // mermaid is viewer-rendered data, not a sandboxed html doc + assert.equal((await app.request(`/s/${surface.id}?part=0`)).status, 404); +}); + +test("publish_surface MCP tool keeps mermaid parts and drops empty ones", async () => { + const app = makeApp(); + const published = (await ( + await app.request( + "/mcp", + mcpCall(2, "tools/call", { + name: "publish_surface", + arguments: { + title: "Diagram", + parts: [ + { kind: "mermaid", mermaid: " " }, + { kind: "mermaid", mermaid: "graph TD; A-->B" }, + ], + }, + }), + ) + ).json()) as any; + const payload = JSON.parse(published.result.content[0].text); + const full = (await (await app.request(`/api/surfaces/${payload.id}`)).json()) as any; + assert.equal(full.parts.length, 1); + assert.equal(full.parts[0].kind, "mermaid"); + assert.equal(full.parts[0].mermaid, "graph TD; A-->B"); +}); + test("update bumps version and keeps history; old version renderable", async () => { const app = makeApp(); const s = (await ( diff --git a/viewer/src/Card.tsx b/viewer/src/Card.tsx index b635cd7..db5f435 100644 --- a/viewer/src/Card.tsx +++ b/viewer/src/Card.tsx @@ -16,6 +16,7 @@ import { type DiffPart as DiffPartData, type ImagePart as ImagePartData, type MarkdownPart as MarkdownPartData, + type MermaidPart as MermaidPartData, type Surface, type TerminalPart as TerminalPartData, type TracePart as TracePartData, @@ -24,6 +25,7 @@ import { DiffPart } from "./DiffPart.tsx"; import { CommentIcon, LinkIcon, OpenIcon, TrashIcon } from "./icons.tsx"; import { ImagePart } from "./ImagePart.tsx"; import { MarkdownPart } from "./MarkdownPart.tsx"; +import { MermaidPart } from "./MermaidPart.tsx"; import { TerminalPart } from "./TerminalPart.tsx"; import { TracePart } from "./TracePart.tsx"; import { @@ -143,6 +145,9 @@ export function Card(props: { surface: Surface }) { + + + diff --git a/viewer/src/MermaidPart.tsx b/viewer/src/MermaidPart.tsx new file mode 100644 index 0000000..d21cc4b --- /dev/null +++ b/viewer/src/MermaidPart.tsx @@ -0,0 +1,77 @@ +import { createEffect, createSignal, onCleanup, onMount } from "solid-js"; +import type { MermaidPart as MermaidPartData } from "./api.ts"; + +// Mermaid bakes theme colors into the SVG at render time (unlike shiki's +// dual-theme output, which a CSS rule can flip), so the diagram must be +// re-rendered when the OS color scheme changes. Reuse the same +// prefers-color-scheme signal pattern DiffPart uses. +const darkQuery = window.matchMedia("(prefers-color-scheme: dark)"); +const [isDark, setIsDark] = createSignal(darkQuery.matches); +darkQuery.addEventListener("change", (e) => setIsDark(e.matches)); + +// mermaid.render namespaces the SVG's internal ids with this; it must be unique +// per render across the whole document, so a module-level counter, not a uuid. +let seq = 0; + +export function MermaidPart(props: { part: MermaidPartData }) { + const [svg, setSvg] = createSignal(""); + const [error, setError] = createSignal(null); + + onMount(() => { + let disposed = false; + onCleanup(() => (disposed = true)); + + const render = async () => { + const src = props.part.mermaid ?? ""; + try { + // Lazy-load mermaid (a heavy dep) only when a mermaid part actually + // mounts. mermaid is the default export. + const mermaid = (await import("mermaid")).default; + // securityLevel 'strict' makes mermaid sanitize the generated SVG with + // its bundled DOMPurify and disables inline HTML labels and click + // handlers — this part renders in the trusted viewer origin (no + // sandbox), so never relax it. suppressErrorRendering keeps a parse + // failure from injecting mermaid's "bomb" graphic into document.body; + // we render our own error fallback instead. + mermaid.initialize({ + startOnLoad: false, + securityLevel: "strict", + suppressErrorRendering: true, + theme: isDark() ? "dark" : "default", + }); + const { svg: out } = await mermaid.render(`mmd-${seq++}`, src); + if (!disposed) { + setError(null); + setSvg(out); + } + } catch (e) { + if (!disposed) { + setSvg(""); + setError(e instanceof Error ? e.message : "Could not render diagram."); + } + } + }; + + // Initial paint, plus a re-render whenever the color scheme flips: the + // effect reads isDark() synchronously (so it's tracked), then renders with + // the matching mermaid theme. The first run does the initial paint. + createEffect(() => { + isDark(); + void render(); + }); + }); + + return ( +
+ {error() ? ( +
+ Couldn’t render diagram — {error()} +
{props.part.mermaid}
+
+ ) : ( + // eslint-disable-next-line solid/no-innerhtml -- sanitized: mermaid securityLevel 'strict' (DOMPurify) +
+ )} +
+ ); +} diff --git a/viewer/src/api.ts b/viewer/src/api.ts index fffe178..d0f3a4a 100644 --- a/viewer/src/api.ts +++ b/viewer/src/api.ts @@ -5,6 +5,7 @@ import type { HtmlPart, ImagePart, MarkdownPart, + MermaidPart, Session, Surface, SurfacePart, @@ -19,6 +20,7 @@ export type { HtmlPart, ImagePart, MarkdownPart, + MermaidPart, Session, Surface, SurfacePart, diff --git a/viewer/src/styles.css b/viewer/src/styles.css index 33fc2cf..ba39d33 100644 --- a/viewer/src/styles.css +++ b/viewer/src/styles.css @@ -589,6 +589,33 @@ iframe { border-top: 0.5px solid var(--border); margin: 1em 0; } +.mermaidpart { + border-top: 0.5px solid var(--border); + padding: 14px 16px; + /* center the diagram; mermaid sizes the SVG to its content */ + text-align: center; + overflow: auto; +} +.mermaid-svg svg { + max-width: 100%; + height: auto; +} +.mermaid-error { + padding: 10px 14px; + font-size: 12px; + color: var(--faint); + text-align: left; +} +.mermaid-error pre { + margin: 6px 0 0; + padding: 8px 10px; + background: var(--panel); + border: 0.5px solid var(--border); + border-radius: 8px; + overflow: auto; + font: 12px var(--font-mono, ui-monospace, monospace); + color: var(--text); +} .tracepart { border-top: 0.5px solid var(--border); padding: 10px 14px 12px; From 9de6b0c0c18f32f2cddde953189de9663f158ce2 Mon Sep 17 00:00:00 2001 From: Ben Vinegar <2153+benvinegar@users.noreply.github.com> Date: Wed, 17 Jun 2026 15:54:17 -0400 Subject: [PATCH 2/3] feat(viewer): theme mermaid diagrams in the sideshow palette Drive mermaid's `base` theme from the viewer's live CSS custom properties instead of its stock dark/default themes, so diagrams match the design language (panel fills, hairline borders, muted lines, the viewer's font) in both light and dark. Add agent-facing accent classes wired to `--accent`: tag a flowchart node with `:::accent` / `class A accent`, or an edge with `accentLine`. Documented in the design guide. Co-Authored-By: Claude Opus 4.8 (1M context) --- guide/DESIGN_GUIDE.md | 8 +++- viewer/src/MermaidPart.tsx | 80 +++++++++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/guide/DESIGN_GUIDE.md b/guide/DESIGN_GUIDE.md index 62afaf1..911dbc4 100644 --- a/guide/DESIGN_GUIDE.md +++ b/guide/DESIGN_GUIDE.md @@ -26,7 +26,13 @@ a `kind`: Reach for it when the shape of a system is the point — a flow, a state machine, a schema — and you'd rather describe it than draw SVG by hand. Like markdown it renders as data, not sandboxed markup (securityLevel `strict`); for - bespoke vector art hand-write inline `` in an `html` part instead. + bespoke vector art hand-write inline `` in an `html` part instead. The + viewer themes the diagram in the sideshow palette and font automatically (light + and dark) — don't set your own colors. To highlight, two classes are + pre-wired to the accent color: in a flowchart, tag nodes with `:::accent` + (e.g. `B[Live render]:::accent`) or `class A,B accent`, and recolor an edge by + giving it `accentLine` (pair with `linkStyle`). Accents apply to flowcharts; + sequence diagrams style actors globally only. - **`diff`** — a patch you hand over as _data_; the trusted viewer renders it natively as a syntax-highlighted code review (split or unified). Reach for it to show a changeset or review code, not to draw. diff --git a/viewer/src/MermaidPart.tsx b/viewer/src/MermaidPart.tsx index d21cc4b..2f9afb3 100644 --- a/viewer/src/MermaidPart.tsx +++ b/viewer/src/MermaidPart.tsx @@ -13,6 +13,81 @@ darkQuery.addEventListener("change", (e) => setIsDark(e.matches)); // per render across the whole document, so a module-level counter, not a uuid. let seq = 0; +// Mermaid's stock themes ignore our design tokens, so the diagram reads as +// generic mermaid. Instead drive its `base` theme from the viewer's own CSS +// custom properties (read live — this part renders in the trusted origin, so +// getComputedStyle is fine). The vars already flip light/dark, so re-rendering +// on a scheme change (below) is all that's needed to stay in sync. Returns the +// `themeVariables` + `themeCSS` mermaid needs to match sideshow's look. +function sideshowTheme() { + const css = getComputedStyle(document.documentElement); + const v = (name: string, fallback: string) => css.getPropertyValue(name).trim() || fallback; + + const text = v("--text", "#1a1915"); + const muted = v("--muted", "#5f5e56"); + const border = v("--border-2", "rgba(20,20,10,0.25)"); + const panel = v("--panel", "#f3f2ec"); + const surface = v("--surface", "#ffffff"); + const bg = v("--bg", "#faf9f5"); + const accent = v("--accent", "#185fa5"); + const accentBg = v("--accent-bg", "#e6f1fb"); + // The viewer has no font token — its system stack lives on `body` — so match + // the diagram font to whatever the rest of the viewer is actually rendering. + const font = getComputedStyle(document.body).fontFamily || "ui-sans-serif, system-ui, sans-serif"; + + return { + themeVariables: { + fontFamily: font, + fontSize: "14px", + // shared / flowchart + primaryColor: panel, + primaryBorderColor: border, + primaryTextColor: text, + secondaryColor: surface, + tertiaryColor: bg, + mainBkg: panel, + nodeBorder: border, + lineColor: muted, + textColor: text, + clusterBkg: bg, + clusterBorder: border, + edgeLabelBackground: bg, + // sequence diagrams have their own palette + actorBkg: panel, + actorBorder: border, + actorTextColor: text, + actorLineColor: muted, + signalColor: muted, + signalTextColor: text, + labelBoxBkgColor: surface, + labelBoxBorderColor: border, + labelTextColor: text, + loopTextColor: text, + noteBkgColor: accentBg, + noteBorderColor: border, + noteTextColor: text, + sequenceNumberColor: surface, + }, + // Flat-and-clean to match the design language: rounded rects, hairline + // strokes, no heavy borders. Plus agent-facing accent classes (see below). + themeCSS: ` + .node rect, .node polygon, rect.actor, .labelBox { rx: 8px; ry: 8px; } + .node rect, rect.actor { stroke-width: 1px; } + .edgePath .path, .flowchart-link, .actor-line, + .messageLine0, .messageLine1 { stroke-width: 1px; } + + /* Agent-applied highlight classes, colored from --accent. Apply in a + flowchart with A:::accent (a node) or 'class A,B accent'. 'accent' + fills a node with the brand color; 'accentLine' recolors an edge + (pair with linkStyle to target a specific link). */ + .node.accent > rect, .node.accent > polygon, .node.accent > circle, + .node.accent > path { fill: ${accentBg}; stroke: ${accent}; } + .node.accent .nodeLabel, .node.accent span, .node.accent text { fill: ${accent}; color: ${accent}; } + .flowchart-link.accentLine, .edgePath.accentLine > .path { stroke: ${accent}; } + `, + }; +} + export function MermaidPart(props: { part: MermaidPartData }) { const [svg, setSvg] = createSignal(""); const [error, setError] = createSignal(null); @@ -33,11 +108,14 @@ export function MermaidPart(props: { part: MermaidPartData }) { // sandbox), so never relax it. suppressErrorRendering keeps a parse // failure from injecting mermaid's "bomb" graphic into document.body; // we render our own error fallback instead. + const { themeVariables, themeCSS } = sideshowTheme(); mermaid.initialize({ startOnLoad: false, securityLevel: "strict", suppressErrorRendering: true, - theme: isDark() ? "dark" : "default", + theme: "base", + themeVariables, + themeCSS, }); const { svg: out } = await mermaid.render(`mmd-${seq++}`, src); if (!disposed) { From 1f823f06f55af09970bbcbeee9f62057f10da2b8 Mon Sep 17 00:00:00 2001 From: Ben Vinegar <2153+benvinegar@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:36:37 -0400 Subject: [PATCH 3/3] docs: add mermaid to the surface gallery + changeset Add a mermaid cell to the README "Surface kinds" gallery (filling the empty slot), register the example in scripts/shoot-surfaces.mjs with scripts/surface-examples/loop.mmd, and add a changeset for the feature. Relock for the mermaid dependency. Co-Authored-By: Claude Opus 4.8 (1M context) --- .changeset/mermaid-surface-parts.md | 5 + README.md | 7 +- docs/surfaces/07-mermaid.png | Bin 0 -> 44331 bytes .../{07-combined.png => 08-combined.png} | Bin package-lock.json | 1284 ++++++++++++++++- scripts/shoot-surfaces.mjs | 5 + scripts/surface-examples/loop.mmd | 5 + 7 files changed, 1256 insertions(+), 50 deletions(-) create mode 100644 .changeset/mermaid-surface-parts.md create mode 100644 docs/surfaces/07-mermaid.png rename docs/surfaces/{07-combined.png => 08-combined.png} (100%) create mode 100644 scripts/surface-examples/loop.mmd diff --git a/.changeset/mermaid-surface-parts.md b/.changeset/mermaid-surface-parts.md new file mode 100644 index 0000000..fa0bcd6 --- /dev/null +++ b/.changeset/mermaid-surface-parts.md @@ -0,0 +1,5 @@ +--- +"sideshow": minor +--- + +Add a `mermaid` surface part. Agents hand over diagram source (flowchart, sequence, ERD, gantt, state, …) and the viewer renders it natively to an SVG — themed in the sideshow palette and font (light and dark), with flowchart nodes/edges that can opt into the accent color via `:::accent` / `accentLine`. Available on all three tiers: a `mermaid` part over MCP and `POST /api/surfaces`, plus the CLI (`sideshow mermaid`, and `--mermaid` on `sideshow publish`). Rendered as data, not sandboxed markup — mermaid runs with securityLevel `strict`, and an invalid diagram shows its source in an error fallback instead of breaking the card. diff --git a/README.md b/README.md index ac6b3dd..1c2919b 100644 --- a/README.md +++ b/README.md @@ -150,10 +150,13 @@ from the viewer. Regenerate them with `node scripts/shoot-surfaces.mjs`.
-
markdown + diff — two parts composed in one card + mermaid part — a flowchart rendered from a few lines of text +

mermaid — a few lines of diagram source, rendered to an SVG in the sideshow palette. Tag nodes with :::accent to highlight them.

+ + + markdown + diff — two parts composed in one card

Parts compose. One card can carry several — here a markdown rationale stacked above its diff, so a single surface holds the why and the what.

- diff --git a/docs/surfaces/07-mermaid.png b/docs/surfaces/07-mermaid.png new file mode 100644 index 0000000000000000000000000000000000000000..047cce216b744750e772cc516019aea0a1862252 GIT binary patch literal 44331 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.18" } }, + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@antfu/install-pkg/node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -349,6 +371,13 @@ "node": ">=6.9.0" } }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "dev": true, + "license": "MIT" + }, "node_modules/@changesets/apply-release-plan": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-7.1.1.tgz", @@ -591,6 +620,13 @@ "prettier": "^2.7.1" } }, + "node_modules/@chevrotain/types": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/@cloudflare/kv-asset-handler": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.5.0.tgz", @@ -1210,6 +1246,25 @@ "hono": "^4" } }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@iconify/utils": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.3.tgz", + "integrity": "sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "import-meta-resolve": "^4.2.0" + } + }, "node_modules/@img/colour": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", @@ -1866,6 +1921,16 @@ "node": ">=6 <7 || >=8" } }, + "node_modules/@mermaid-js/parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.1.tgz", + "integrity": "sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@chevrotain/types": "~11.1.1" + } + }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", @@ -3186,6 +3251,297 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -3239,6 +3595,14 @@ "undici-types": ">=7.24.0 <7.24.7" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -3251,6 +3615,17 @@ "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", "license": "ISC" }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -3667,6 +4042,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, "node_modules/content-disposition": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", @@ -3731,6 +4116,16 @@ "url": "https://opencollective.com/express" } }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "dev": true, + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3752,72 +4147,643 @@ "dev": true, "license": "MIT" }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/cytoscape": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.0.tgz", + "integrity": "sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==", + "dev": true, "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=0.10" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.8" + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=6" + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" } }, - "node_modules/detect-indent": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", - "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", "dev": true, "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "layout-base": "^2.0.0" } }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "license": "MIT", + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "dev": true, + "license": "ISC", "dependencies": { - "dequal": "^2.0.0" + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dev": true, + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dev": true, + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "dev": true, + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, + "node_modules/dayjs": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/diff": { @@ -3842,6 +4808,16 @@ "node": ">=8" } }, + "node_modules/dompurify": { + "version": "3.4.11", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.11.tgz", + "integrity": "sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==", + "dev": true, + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -3988,6 +4964,17 @@ "node": ">= 0.4" } }, + "node_modules/es-toolkit": { + "version": "1.47.1", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.47.1.tgz", + "integrity": "sha512-5RAqEwf4P4E17p+W75KLOWw/nOvKZzSQpxM32IpI2KZLaVonjTrZ0Ai5ghMaVI9eKC2p8eoQgcBdkEDgzFk6+Q==", + "dev": true, + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/esbuild": { "version": "0.27.3", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", @@ -4450,6 +5437,13 @@ "dev": true, "license": "ISC" }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "dev": true, + "license": "MIT" + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -4592,12 +5586,33 @@ "node": ">= 4" } }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/ip-address": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", @@ -4800,6 +5815,39 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", + "dev": true + }, "node_modules/kleur": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", @@ -4810,6 +5858,13 @@ "node": ">=6" } }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "dev": true, + "license": "MIT" + }, "node_modules/lightningcss": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", @@ -5146,6 +6201,13 @@ "node": ">=8" } }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.startcase": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", @@ -5283,6 +6345,19 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -5367,6 +6442,36 @@ "node": ">= 8" } }, + "node_modules/mermaid": { + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.15.0.tgz", + "integrity": "sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.1.1", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.1.1", + "@types/d3": "^7.4.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.1", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.19", + "dompurify": "^3.3.1", + "es-toolkit": "^1.45.1", + "katex": "^0.16.25", + "khroma": "^2.1.0", + "marked": "^16.3.0", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" + } + }, "node_modules/micromark-util-character": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", @@ -5873,6 +6978,13 @@ "node": ">= 0.8" } }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "dev": true, + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -6005,6 +7117,24 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "dev": true, + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, "node_modules/postcss": { "version": "8.5.15", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", @@ -6301,6 +7431,13 @@ "dev": true, "license": "MIT" }, + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "dev": true, + "license": "Unlicense" + }, "node_modules/rolldown": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", @@ -6335,6 +7472,19 @@ "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -6375,6 +7525,13 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -6824,6 +7981,13 @@ "node": ">=4" } }, + "node_modules/stylis": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", + "dev": true, + "license": "MIT" + }, "node_modules/supports-color": { "version": "10.2.2", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", @@ -6919,6 +8083,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-dedent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", + "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -7124,6 +8298,20 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uuid": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/scripts/shoot-surfaces.mjs b/scripts/shoot-surfaces.mjs index ca55db1..6aa3107 100644 --- a/scripts/shoot-surfaces.mjs +++ b/scripts/shoot-surfaces.mjs @@ -158,6 +158,11 @@ const cards = [ }, ], }, + { + file: "mermaid", + title: "mermaid part — a diagram from a few lines of text", + parts: [{ kind: "mermaid", mermaid: read("loop.mmd") }], + }, { file: "combined", title: "markdown + diff — two parts composed in one card", diff --git a/scripts/surface-examples/loop.mmd b/scripts/surface-examples/loop.mmd new file mode 100644 index 0000000..fe60ee7 --- /dev/null +++ b/scripts/surface-examples/loop.mmd @@ -0,0 +1,5 @@ +flowchart LR + A[Agent publishes snippet] --> B[Live render in browser]:::accent + B --> C[User comments] + C --> D[Agent revises and replies]:::accent + D --> B