remark-dgmo 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -153,6 +153,13 @@ remarkDgmo({
153
153
  // astro-dgmo v0.3.0 to keep the legacy `astro-dgmo*` class names for one
154
154
  // minor cycle of backward compat.
155
155
  legacyClassNames: [],
156
+
157
+ // Emit MDX-compatible output. Default: false (raw `html` mdast node).
158
+ // Set to true when the host pipeline routes files through @mdx-js/mdx —
159
+ // Docusaurus with `markdown.format: 'mdx'`, Astro `.mdx`, Fumadocs, etc.
160
+ // The plugin then emits an `mdxJsxFlowElement` instead of an `html` node,
161
+ // so MDX accepts the output without "Cannot handle unknown node `raw`".
162
+ mdx: false,
156
163
  });
157
164
  ```
158
165
 
@@ -178,6 +185,21 @@ A -> B
178
185
  | `copy` / `noCopy` | Force copy button on/off |
179
186
  | `openInEditor` / `noOpenInEditor` | Force editor link on/off |
180
187
 
188
+ ## Working reference site
189
+
190
+ For an end-to-end example of `remark-dgmo` running inside a real
191
+ framework, see [`docusaurus-plugin-dgmo`'s `tests/fixture/`](https://github.com/diagrammo/docusaurus-plugin-dgmo/tree/main/tests/fixture)
192
+ — a minimal Docusaurus 3 site that wires this plugin into every preset
193
+ slot and exercises plain, tagged, showcase, and per-block-override
194
+ blocks. The `astro-dgmo` repo has an equivalent Astro 6 fixture at
195
+ [`tests/fixture/`](https://github.com/diagrammo/astro-dgmo/tree/main/tests/fixture).
196
+
197
+ Both fixtures pin to `link:../..` against the wrapper plugin's source,
198
+ so they're the canonical reference for the smallest correct config —
199
+ including the non-obvious gotchas (Docusaurus's async-function default
200
+ export + `markdown: { format: 'md' }`, Astro's manual `import
201
+ 'remark-dgmo/client.css'`).
202
+
181
203
  ## Custom color-mode selector
182
204
 
183
205
  The shipped `client.css` keys on `[data-theme="dark"]` — the convention used by Docusaurus and Starlight. For Tailwind-style sites that signal dark mode via a `.dark` class on `<html>` (or any other selector), don't import `client.css`. Inline these three rules in your own CSS instead, swapping the selector:
@@ -24,7 +24,8 @@ function resolveOptions(opts = {}) {
24
24
  editorBaseUrl: opts.editorBaseUrl ?? "https://online.diagrammo.app",
25
25
  wrapper: opts.wrapper ?? "figure",
26
26
  className: opts.className ?? "dgmo",
27
- legacyClassNames: opts.legacyClassNames ?? []
27
+ legacyClassNames: opts.legacyClassNames ?? [],
28
+ mdx: opts.mdx ?? false
28
29
  };
29
30
  }
30
31
 
@@ -365,30 +366,18 @@ function renderShowcase(source, svg, editorUrl, opts, title) {
365
366
  const wrapperClass = buildWrapperClasses(opts, "showcase");
366
367
  const cardClass = buildInnerClasses(opts, "dgmo-card");
367
368
  const captionHtml = title ? Wrapper === "figure" ? `<figcaption class="dgmo-caption">${escapeHtml(title)}</figcaption>` : `<div class="dgmo-caption">${escapeHtml(title)}</div>` : "";
368
- const sourceHtml = opts.showSource ? renderSource(source) : "";
369
- const openButton = opts.showOpenInEditor && editorUrl ? `<a href="${escapeAttr(editorUrl)}" target="_blank" rel="noopener noreferrer" class="dgmo-toolbar-btn dgmo-open" aria-label="Open in online editor" title="Open in online editor">
370
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
371
- <path d="M9.5 2.5h4v4"/>
372
- <path d="M13.5 2.5 7 9"/>
373
- <path d="M12.5 9.5v3a1 1 0 0 1-1 1h-8a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1h3"/>
374
- </svg>
375
- </a>` : "";
376
- const copyButton = opts.showCopy ? `<button type="button" class="dgmo-toolbar-btn dgmo-copy" aria-label="Copy to clipboard" title="Copy to clipboard" data-dgmo-source="${escapeAttr(source)}">
377
- <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
378
- <rect x="5.5" y="5.5" width="8" height="8" rx="1.5"/>
379
- <path d="M10.5 5.5V3a1.5 1.5 0 0 0-1.5-1.5H3A1.5 1.5 0 0 0 1.5 3v6A1.5 1.5 0 0 0 3 10.5h2.5"/>
380
- </svg>
381
- </button>` : "";
382
- const toolbarActions = openButton || copyButton ? `<div class="dgmo-toolbar-actions">${openButton}${copyButton}</div>` : "";
383
- const toolbar = opts.showSource ? `<div class="dgmo-toolbar"><span class="dgmo-toolbar-label">dgmo</span>${toolbarActions}</div>` : "";
384
- return `<${Wrapper} class="${escapeAttr(wrapperClass)}">` + captionHtml + `<div class="${escapeAttr(cardClass)}">` + (opts.showSource ? `<div class="dgmo-source-wrap">${toolbar}<div class="dgmo-source-inner">${sourceHtml}</div></div>` : "") + `<div class="${escapeAttr(buildInnerClasses(opts, "dgmo-svg"))}">${svg}</div></div></${Wrapper}>`;
369
+ return `<${Wrapper} class="${escapeAttr(wrapperClass)}">` + captionHtml + `<div class="${escapeAttr(cardClass)}"><div class="${escapeAttr(buildInnerClasses(opts, "dgmo-svg"))}">${svg}</div>` + renderSourceDisclosure(source, editorUrl, opts) + `</div></${Wrapper}>`;
385
370
  }
386
371
  function renderShowcaseDual(source, lightSvg, darkSvg, editorUrl, opts, title) {
387
372
  const Wrapper = opts.wrapper;
388
373
  const wrapperClass = buildWrapperClasses(opts, "showcase");
389
374
  const cardClass = buildInnerClasses(opts, "dgmo-card");
390
375
  const captionHtml = title ? Wrapper === "figure" ? `<figcaption class="dgmo-caption">${escapeHtml(title)}</figcaption>` : `<div class="dgmo-caption">${escapeHtml(title)}</div>` : "";
391
- const sourceHtml = opts.showSource ? renderSource(source) : "";
376
+ return `<${Wrapper} class="${escapeAttr(wrapperClass)}">` + captionHtml + `<div class="${escapeAttr(cardClass)}"><div class="${escapeAttr(buildInnerClasses(opts, "dgmo-light"))}">${lightSvg}</div><div class="${escapeAttr(buildInnerClasses(opts, "dgmo-dark"))}">${darkSvg}</div>` + renderSourceDisclosure(source, editorUrl, opts) + `</div></${Wrapper}>`;
377
+ }
378
+ function renderSourceDisclosure(source, editorUrl, opts) {
379
+ if (!opts.showSource) return "";
380
+ const sourceHtml = renderSource(source);
392
381
  const openButton = opts.showOpenInEditor && editorUrl ? `<a href="${escapeAttr(editorUrl)}" target="_blank" rel="noopener noreferrer" class="dgmo-toolbar-btn dgmo-open" aria-label="Open in online editor" title="Open in online editor">
393
382
  <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
394
383
  <path d="M9.5 2.5h4v4"/>
@@ -403,8 +392,8 @@ function renderShowcaseDual(source, lightSvg, darkSvg, editorUrl, opts, title) {
403
392
  </svg>
404
393
  </button>` : "";
405
394
  const toolbarActions = openButton || copyButton ? `<div class="dgmo-toolbar-actions">${openButton}${copyButton}</div>` : "";
406
- const toolbar = opts.showSource ? `<div class="dgmo-toolbar"><span class="dgmo-toolbar-label">dgmo</span>${toolbarActions}</div>` : "";
407
- return `<${Wrapper} class="${escapeAttr(wrapperClass)}">` + captionHtml + `<div class="${escapeAttr(cardClass)}">` + (opts.showSource ? `<div class="dgmo-source-wrap">${toolbar}<div class="dgmo-source-inner">${sourceHtml}</div></div>` : "") + `<div class="${escapeAttr(buildInnerClasses(opts, "dgmo-light"))}">${lightSvg}</div><div class="${escapeAttr(buildInnerClasses(opts, "dgmo-dark"))}">${darkSvg}</div></div></${Wrapper}>`;
395
+ const chevron = `<svg class="dgmo-chevron" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 4 4 4-4 4"/></svg>`;
396
+ return `<details class="dgmo-source-wrap"><summary class="dgmo-toolbar"><span class="dgmo-toolbar-label">${chevron}<span>source</span></span>${toolbarActions}</summary><div class="dgmo-source-inner">${sourceHtml}</div></details>`;
408
397
  }
409
398
  function renderSource(source) {
410
399
  const tokens = highlightDgmo(source);
@@ -420,6 +409,40 @@ function renderSource(source) {
420
409
  return `<pre class="dgmo-pre"><span class="dgmo-code">${inner}</span></pre>`;
421
410
  }
422
411
 
412
+ // src/mdx-node.ts
413
+ import { valueToEstree } from "estree-util-value-to-estree";
414
+ function htmlToMdxJsxNode(html) {
415
+ const objectExpression = valueToEstree({ __html: html });
416
+ const program = {
417
+ type: "Program",
418
+ body: [
419
+ {
420
+ type: "ExpressionStatement",
421
+ expression: objectExpression
422
+ }
423
+ ],
424
+ sourceType: "module"
425
+ };
426
+ return {
427
+ type: "mdxJsxFlowElement",
428
+ name: "div",
429
+ attributes: [
430
+ {
431
+ type: "mdxJsxAttribute",
432
+ name: "dangerouslySetInnerHTML",
433
+ value: {
434
+ type: "mdxJsxAttributeValueExpression",
435
+ // String form is what `mdast-util-mdx-jsx` uses if it re-parses; we
436
+ // also ship the estree on `data` for compilers that prefer it.
437
+ value: `{__html: ${JSON.stringify(html)}}`,
438
+ data: { estree: program }
439
+ }
440
+ }
441
+ ],
442
+ children: []
443
+ };
444
+ }
445
+
423
446
  // src/remark-plugin.ts
424
447
  function remarkDgmo(options = {}) {
425
448
  return async function transformer(tree, file) {
@@ -453,8 +476,8 @@ function remarkDgmo(options = {}) {
453
476
  );
454
477
  for (let i = targets.length - 1; i >= 0; i--) {
455
478
  const t = targets[i];
456
- const html = { type: "html", value: rendered[i].html };
457
- t.parent.children[t.index] = html;
479
+ const replacement = options.mdx ? htmlToMdxJsxNode(rendered[i].html) : { type: "html", value: rendered[i].html };
480
+ t.parent.children[t.index] = replacement;
458
481
  }
459
482
  };
460
483
  }
@@ -481,4 +504,4 @@ export {
481
504
  renderDgmoBlock,
482
505
  remarkDgmo
483
506
  };
484
- //# sourceMappingURL=chunk-E5QL6KCZ.js.map
507
+ //# sourceMappingURL=chunk-LUCV265X.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/remark-plugin.ts","../src/render-block.ts","../src/options.ts","../src/fence-meta.ts","../src/svg-normalize.ts","../src/escape.ts","../src/mdx-node.ts"],"sourcesContent":["import { visit } from 'unist-util-visit';\nimport type { Root, Code, Html, Parent } from 'mdast';\nimport { renderDgmoBlock, type BlockLocation } from './render-block.js';\nimport type { DgmoOptions } from './options.js';\nimport { htmlToMdxJsxNode } from './mdx-node.js';\n\nexport type RemarkDgmoOptions = DgmoOptions;\n\ninterface FencePayload {\n source: string;\n meta: string | null;\n location: BlockLocation;\n}\n\ninterface Target {\n parent: Parent;\n index: number;\n payload: FencePayload;\n}\n\n/**\n * Remark plugin that finds ```dgmo fenced code blocks and replaces them with\n * an HTML node containing the rendered SVG (and optional showcase chrome).\n *\n * The `lang` field on the code node is the fence language (the word after the\n * backticks). The `meta` field is everything that follows on the same line,\n * which we use to allow per-block options like ```dgmo showcase palette=catppuccin.\n *\n * Replaces the code node entirely (parent.children[index] = newNode) rather\n * than mutating it in place — otherwise downstream rehype/Shiki plugins still\n * see the lingering `lang: 'dgmo'` and `value: '...source...'` properties and\n * may re-process the block as a plaintext code listing, clobbering our\n * syntax-highlighted output.\n *\n * Async-safe: replacement is collected first, applied after parsing finishes.\n */\nexport default function remarkDgmo(options: RemarkDgmoOptions = {}) {\n return async function transformer(\n tree: Root,\n file?: { path?: string }\n ): Promise<void> {\n const targets: Target[] = [];\n visit(tree, 'code', (node: Code, index, parent) => {\n if (node.lang !== 'dgmo') return;\n if (!parent || index === undefined) return;\n const loc: BlockLocation = {};\n if (file?.path) loc.path = file.path;\n const line = node.position?.start.line;\n if (typeof line === 'number') loc.line = line;\n targets.push({\n parent: parent as Parent,\n index,\n payload: { source: node.value, meta: node.meta ?? null, location: loc },\n });\n });\n if (targets.length === 0) return;\n\n const rendered = await Promise.all(\n targets.map(t =>\n renderDgmoBlock(\n t.payload.source,\n t.payload.meta,\n options,\n t.payload.location\n ).catch(err => ({\n html: errorHtml(err, t.payload.source, options),\n diagnostics: [],\n }))\n )\n );\n\n // Replace in reverse index order per parent so earlier replacements don't\n // shift indices of later targets in the same parent. (Visit walks in tree\n // order, so within a single parent's children targets are also ordered;\n // reversing is sufficient.)\n for (let i = targets.length - 1; i >= 0; i--) {\n const t = targets[i];\n // MDX rejects raw `html` nodes (\"Cannot handle unknown node `raw`\"),\n // so under `mdx: true` we emit an `mdxJsxFlowElement` (a\n // `<div dangerouslySetInnerHTML={{__html: …}} />` JSX wrapper) which\n // the MDX → React compiler accepts. Default stays raw HTML to keep\n // every existing wrapper (astro, plain remark, remark-html) untouched.\n const replacement = options.mdx\n ? htmlToMdxJsxNode(rendered[i].html)\n : ({ type: 'html', value: rendered[i].html } as Html);\n t.parent.children[t.index] = replacement as unknown as Html;\n }\n };\n}\n\nfunction errorHtml(\n err: unknown,\n source: string,\n options: RemarkDgmoOptions\n): string {\n const msg =\n err instanceof Error ? err.message : 'Failed to render dgmo block.';\n const safeMsg = msg.replace(/[<>&]/g, ch =>\n ch === '<' ? '&lt;' : ch === '>' ? '&gt;' : '&amp;'\n );\n const safeSrc = source.replace(/[<>&]/g, ch =>\n ch === '<' ? '&lt;' : ch === '>' ? '&gt;' : '&amp;'\n );\n const baseClass = options.className ?? 'dgmo';\n const legacy = (options.legacyClassNames ?? []).join(' ');\n const cls = legacy\n ? `${baseClass} ${legacy} ${baseClass}--error`\n : `${baseClass} ${baseClass}--error`;\n return (\n `<div class=\"${cls}\" role=\"alert\">` +\n `<strong>dgmo render error:</strong> ${safeMsg}` +\n `<pre>${safeSrc}</pre></div>`\n );\n}\n","import {\n render,\n encodeDiagramUrl,\n palettes,\n type PaletteConfig,\n} from '@diagrammo/dgmo';\nimport { highlightDgmo, NORD_ROLE_STYLES } from '@diagrammo/dgmo/highlight';\nimport {\n resolveOptions,\n type DgmoOptions,\n type ResolvedOptions,\n type Theme,\n} from './options.js';\nimport { parseFenceMeta } from './fence-meta.js';\nimport { normalizeSvg } from './svg-normalize.js';\nimport { escapeHtml, escapeAttr } from './escape.js';\n\nexport interface RenderBlockResult {\n html: string;\n diagnostics: Array<{ message: string; line?: number; severity?: string }>;\n}\n\n/**\n * Optional source-location hint, passed through from the remark transformer so\n * palette-fallback warnings can point at the offending block.\n */\nexport interface BlockLocation {\n path?: string;\n line?: number;\n}\n\n/**\n * Render a single ```dgmo block to inline HTML. Pure function: takes source +\n * options and returns the HTML string and any diagnostics from the parser.\n *\n * The remark plugin calls this for every matched code node.\n */\nexport async function renderDgmoBlock(\n source: string,\n meta: string | null | undefined,\n integrationOptions: DgmoOptions = {},\n location?: BlockLocation\n): Promise<RenderBlockResult> {\n const block = parseFenceMeta(meta);\n const base = resolveOptions(integrationOptions);\n const effectiveMode = block.mode ?? base.mode;\n const showcase = effectiveMode === 'showcase';\n const opts: ResolvedOptions = {\n ...base,\n mode: effectiveMode,\n palette: block.palette ?? base.palette,\n theme: block.theme ?? base.theme,\n colorMode: block.colorMode ?? base.colorMode,\n showSource:\n block.showSource ?? (block.mode ? showcase : base.showSource),\n showCopy: block.showCopy ?? (block.mode ? showcase : base.showCopy),\n showOpenInEditor:\n block.showOpenInEditor ?? (block.mode ? showcase : base.showOpenInEditor),\n };\n\n const trimmed = source.trim();\n const palette = resolvePaletteWithWarning(opts.palette, location);\n\n // collect diagnostics from however many render passes we end up doing\n const allDiagnostics: RenderBlockResult['diagnostics'] = [];\n\n if (opts.colorMode === 'auto') {\n const [lightSvgRaw, darkSvgRaw] = await Promise.all([\n renderForTheme(trimmed, palette, 'light', opts.palette, location),\n renderForTheme(trimmed, palette, 'dark', opts.palette, location),\n ]);\n allDiagnostics.push(...lightSvgRaw.diagnostics, ...darkSvgRaw.diagnostics);\n\n const lightSvg = normalizeSvg(lightSvgRaw.svg);\n const darkSvg = normalizeSvg(darkSvgRaw.svg);\n\n let editorUrl: string | undefined;\n if (opts.showOpenInEditor) {\n const url = encodeDiagramUrl(trimmed, { baseUrl: opts.editorBaseUrl });\n editorUrl = url ?? opts.editorBaseUrl;\n }\n\n const html =\n opts.mode === 'showcase'\n ? renderShowcaseDual(trimmed, lightSvg, darkSvg, editorUrl, opts, block.title)\n : renderSimpleDual(lightSvg, darkSvg, opts, block.title);\n\n return { html, diagnostics: allDiagnostics };\n }\n\n // Single-render path. colorMode is narrowed to 'light' | 'dark' here since\n // 'auto' is handled above. The dgmo render() also accepts 'transparent', but\n // we don't surface that via colorMode — it's reachable via `theme`.\n const themeForRender: Theme = opts.colorMode === 'light' ? 'light' : 'dark';\n const { svg: rawSvg, diagnostics } = await render(trimmed, {\n palette,\n theme: themeForRender,\n });\n allDiagnostics.push(...diagnostics);\n const svg = normalizeSvg(rawSvg);\n\n let editorUrl: string | undefined;\n if (opts.showOpenInEditor) {\n const url = encodeDiagramUrl(trimmed, { baseUrl: opts.editorBaseUrl });\n editorUrl = url ?? opts.editorBaseUrl;\n }\n\n const html =\n opts.mode === 'showcase'\n ? renderShowcase(trimmed, svg, editorUrl, opts, block.title)\n : renderSimple(svg, opts, block.title);\n\n return { html, diagnostics: allDiagnostics };\n}\n\nfunction locationSuffix(location: BlockLocation | undefined): string {\n if (!location) return '';\n if (location.path && location.line) return ` at ${location.path}:${location.line}`;\n if (location.line) return ` at line ${location.line}`;\n return '';\n}\n\nfunction resolvePaletteWithWarning(\n name: string,\n location: BlockLocation | undefined\n): PaletteConfig {\n const found = Object.values(palettes).find(p => p.id === name);\n if (!found) {\n // eslint-disable-next-line no-console\n console.warn(\n `[remark-dgmo] palette \"${name}\" not registered, falling back to \"nord\"${locationSuffix(location)}`\n );\n return palettes.nord;\n }\n return found;\n}\n\n/**\n * Render one theme. If `colorMode: 'auto'` is requested but the palette is\n * missing the requested mode, fall back to nord's mode and emit a warning.\n *\n * Today this is defensive: dgmo's palette registry validates both modes at\n * registration time, so every registered palette has both pairs by\n * construction. User-supplied palettes via `registerPalette()` that slip past\n * validation would hit this path; tests exercise it via mocking.\n */\nasync function renderForTheme(\n source: string,\n palette: PaletteConfig,\n theme: 'light' | 'dark',\n requestedName: string,\n location: BlockLocation | undefined\n): Promise<{ svg: string; diagnostics: RenderBlockResult['diagnostics'] }> {\n if (!palette[theme]) {\n // eslint-disable-next-line no-console\n console.warn(\n `[remark-dgmo] palette \"${requestedName}\" has no ${theme} mode; using nord ${theme} for the missing pair${locationSuffix(location)}`\n );\n // Build a synthetic palette where the missing mode is borrowed from nord.\n const filled: PaletteConfig = {\n ...palette,\n [theme]: palettes.nord[theme],\n } as PaletteConfig;\n return render(source, { palette: filled, theme });\n }\n return render(source, { palette, theme });\n}\n\nfunction buildWrapperClasses(\n resolved: Pick<ResolvedOptions, 'className' | 'legacyClassNames'>,\n variant: 'diagram' | 'showcase' | 'error'\n): string {\n const base = `${resolved.className} ${resolved.className}--${variant}`;\n const legacy = resolved.legacyClassNames.join(' ');\n return legacy ? `${base} ${legacy}` : base;\n}\n\nfunction buildInnerClasses(\n resolved: Pick<ResolvedOptions, 'legacyClassNames'>,\n primary: string\n): string {\n const legacy = resolved.legacyClassNames.join(' ');\n return legacy ? `${primary} ${legacy}` : primary;\n}\n\nfunction renderSimple(\n svg: string,\n opts: ResolvedOptions,\n title?: string\n): string {\n const Wrapper = opts.wrapper;\n const wrapperClass = buildWrapperClasses(opts, 'diagram');\n const captionHtml = title\n ? `<figcaption class=\"dgmo-caption\">${escapeHtml(title)}</figcaption>`\n : '';\n const captionFallback =\n title && Wrapper !== 'figure'\n ? `<div class=\"dgmo-caption\">${escapeHtml(title)}</div>`\n : '';\n return (\n `<${Wrapper} class=\"${escapeAttr(wrapperClass)}\">` +\n (Wrapper === 'figure' ? captionHtml : captionFallback) +\n `<div class=\"${escapeAttr(buildInnerClasses(opts, 'dgmo-svg'))}\">${svg}</div>` +\n `</${Wrapper}>`\n );\n}\n\nfunction renderSimpleDual(\n lightSvg: string,\n darkSvg: string,\n opts: ResolvedOptions,\n title?: string\n): string {\n const Wrapper = opts.wrapper;\n const wrapperClass = buildWrapperClasses(opts, 'diagram');\n const captionHtml = title\n ? `<figcaption class=\"dgmo-caption\">${escapeHtml(title)}</figcaption>`\n : '';\n const captionFallback =\n title && Wrapper !== 'figure'\n ? `<div class=\"dgmo-caption\">${escapeHtml(title)}</div>`\n : '';\n return (\n `<${Wrapper} class=\"${escapeAttr(wrapperClass)}\">` +\n (Wrapper === 'figure' ? captionHtml : captionFallback) +\n `<div class=\"${escapeAttr(buildInnerClasses(opts, 'dgmo-light'))}\">${lightSvg}</div>` +\n `<div class=\"${escapeAttr(buildInnerClasses(opts, 'dgmo-dark'))}\">${darkSvg}</div>` +\n `</${Wrapper}>`\n );\n}\n\nfunction renderShowcase(\n source: string,\n svg: string,\n editorUrl: string | undefined,\n opts: ResolvedOptions,\n title?: string\n): string {\n const Wrapper = opts.wrapper;\n const wrapperClass = buildWrapperClasses(opts, 'showcase');\n const cardClass = buildInnerClasses(opts, 'dgmo-card');\n\n const captionHtml = title\n ? Wrapper === 'figure'\n ? `<figcaption class=\"dgmo-caption\">${escapeHtml(title)}</figcaption>`\n : `<div class=\"dgmo-caption\">${escapeHtml(title)}</div>`\n : '';\n\n return (\n `<${Wrapper} class=\"${escapeAttr(wrapperClass)}\">` +\n captionHtml +\n `<div class=\"${escapeAttr(cardClass)}\">` +\n `<div class=\"${escapeAttr(buildInnerClasses(opts, 'dgmo-svg'))}\">${svg}</div>` +\n renderSourceDisclosure(source, editorUrl, opts) +\n `</div>` +\n `</${Wrapper}>`\n );\n}\n\nfunction renderShowcaseDual(\n source: string,\n lightSvg: string,\n darkSvg: string,\n editorUrl: string | undefined,\n opts: ResolvedOptions,\n title?: string\n): string {\n const Wrapper = opts.wrapper;\n const wrapperClass = buildWrapperClasses(opts, 'showcase');\n const cardClass = buildInnerClasses(opts, 'dgmo-card');\n\n const captionHtml = title\n ? Wrapper === 'figure'\n ? `<figcaption class=\"dgmo-caption\">${escapeHtml(title)}</figcaption>`\n : `<div class=\"dgmo-caption\">${escapeHtml(title)}</div>`\n : '';\n\n return (\n `<${Wrapper} class=\"${escapeAttr(wrapperClass)}\">` +\n captionHtml +\n `<div class=\"${escapeAttr(cardClass)}\">` +\n `<div class=\"${escapeAttr(buildInnerClasses(opts, 'dgmo-light'))}\">${lightSvg}</div>` +\n `<div class=\"${escapeAttr(buildInnerClasses(opts, 'dgmo-dark'))}\">${darkSvg}</div>` +\n renderSourceDisclosure(source, editorUrl, opts) +\n `</div>` +\n `</${Wrapper}>`\n );\n}\n\n/**\n * Source listing wrapped in a native <details>/<summary> disclosure, collapsed\n * by default. The summary doubles as the toolbar row (label + chevron + copy /\n * open-in-editor buttons). Clicks on the toolbar buttons are stopped from\n * propagating to the summary in `client.ts`, so they don't also toggle the\n * disclosure.\n *\n * Returns '' when `showSource` is false (matches the prior noSource behavior).\n */\nfunction renderSourceDisclosure(\n source: string,\n editorUrl: string | undefined,\n opts: ResolvedOptions\n): string {\n if (!opts.showSource) return '';\n\n const sourceHtml = renderSource(source);\n\n const openButton =\n opts.showOpenInEditor && editorUrl\n ? `<a href=\"${escapeAttr(editorUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"dgmo-toolbar-btn dgmo-open\" aria-label=\"Open in online editor\" title=\"Open in online editor\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M9.5 2.5h4v4\"/>\n <path d=\"M13.5 2.5 7 9\"/>\n <path d=\"M12.5 9.5v3a1 1 0 0 1-1 1h-8a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1h3\"/>\n </svg>\n </a>`\n : '';\n\n const copyButton = opts.showCopy\n ? `<button type=\"button\" class=\"dgmo-toolbar-btn dgmo-copy\" aria-label=\"Copy to clipboard\" title=\"Copy to clipboard\" data-dgmo-source=\"${escapeAttr(source)}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8\" rx=\"1.5\"/>\n <path d=\"M10.5 5.5V3a1.5 1.5 0 0 0-1.5-1.5H3A1.5 1.5 0 0 0 1.5 3v6A1.5 1.5 0 0 0 3 10.5h2.5\"/>\n </svg>\n </button>`\n : '';\n\n const toolbarActions =\n openButton || copyButton\n ? `<div class=\"dgmo-toolbar-actions\">${openButton}${copyButton}</div>`\n : '';\n\n const chevron = `<svg class=\"dgmo-chevron\" width=\"12\" height=\"12\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"m6 4 4 4-4 4\"/></svg>`;\n\n return (\n `<details class=\"dgmo-source-wrap\">` +\n `<summary class=\"dgmo-toolbar\"><span class=\"dgmo-toolbar-label\">${chevron}<span>source</span></span>${toolbarActions}</summary>` +\n `<div class=\"dgmo-source-inner\">${sourceHtml}</div>` +\n `</details>`\n );\n}\n\nfunction renderSource(source: string): string {\n const tokens = highlightDgmo(source);\n const inner = tokens\n .map(t => {\n const styles = NORD_ROLE_STYLES[t.role];\n const text = escapeHtml(t.text);\n if (!styles || Object.keys(styles).length === 0) return text;\n const styleStr = Object.entries(styles)\n .map(\n ([k, v]) => `${k.replace(/[A-Z]/g, m => '-' + m.toLowerCase())}:${v}`\n )\n .join(';');\n return `<span style=\"${escapeAttr(styleStr)}\">${text}</span>`;\n })\n .join('');\n // NOTE: We deliberately use <pre><span> rather than <pre><code> here. Astro's\n // Shiki rehype plugin (and Docusaurus's MDX pipeline) walk the hast and\n // post-process any <pre><code> pair (even ones we emit from a remark plugin\n // via raw HTML), which clobbers our pre-rendered highlight spans with a\n // plaintext listing. Using a <span> as the inner element bypasses the\n // matcher while preserving preformatted-text semantics on the outer <pre>.\n return `<pre class=\"dgmo-pre\"><span class=\"dgmo-code\">${inner}</span></pre>`;\n}\n","export type Mode = 'diagram' | 'showcase';\n\nexport type Theme = 'light' | 'dark' | 'transparent';\n\n/**\n * Framework-agnostic options for `remarkDgmo` / `renderDgmoBlock`.\n *\n * Wrapper packages (`astro-dgmo`, `docusaurus-plugin-dgmo`) re-export this\n * shape under their own conventional names (`DgmoIntegrationOptions`,\n * `DocusaurusDgmoOptions`).\n */\nexport interface DgmoOptions {\n /**\n * Output mode for `dgmo` fenced blocks.\n * - `diagram` (default): render the SVG only, in a `<figure>`.\n * - `showcase`: render syntax-highlighted source + SVG + copy + open-in-editor.\n *\n * Override per-block via the fence info string: ```dgmo showcase\n */\n mode?: Mode;\n\n /** Default palette name. Default: `nord`. */\n palette?: string;\n\n /**\n * Default theme (`light` | `dark` | `transparent`). Default: `dark`.\n *\n * NOTE: under the default `colorMode: 'auto'`, this option is unreachable —\n * dual-render emits both light and dark SVGs regardless. `theme` is consulted\n * only when `colorMode` is explicitly set to `'light'` or `'dark'`.\n */\n theme?: Theme;\n\n /**\n * Color-mode strategy for emitted SVG(s). Default: `auto`.\n *\n * - `auto` — render every block twice (light + dark palettes) and wrap each\n * SVG in a `<div class=\"dgmo-light\">` / `<div class=\"dgmo-dark\">` so the\n * shipped CSS can flip visibility based on the host site's color-mode\n * signal (`[data-theme=\"dark\"]` by default).\n * - `light` / `dark` — single-render with the matching theme. Halves the\n * emitted SVG bytes; recommended only for single-mode sites.\n */\n colorMode?: 'auto' | 'light' | 'dark';\n\n /**\n * Show source code above the diagram. Defaults to `true` in showcase mode,\n * `false` in diagram mode.\n */\n showSource?: boolean;\n\n /**\n * Show a copy-to-clipboard button. Defaults to `true` in showcase mode,\n * `false` in diagram mode.\n */\n showCopy?: boolean;\n\n /**\n * Show an \"Open in online editor\" link. Defaults to `true` in showcase mode,\n * `false` in diagram mode.\n */\n showOpenInEditor?: boolean;\n\n /**\n * Base URL for the \"Open in editor\" link. Default: `https://online.diagrammo.app`.\n * The plugin appends `?dgmo=...` (compressed source) to the base.\n */\n editorBaseUrl?: string;\n\n /**\n * Wrapper element. Default: `figure`.\n */\n wrapper?: 'figure' | 'div';\n\n /**\n * Class added to the outer wrapper. Defaults to `dgmo`.\n * Useful as a styling hook.\n */\n className?: string;\n\n /**\n * Additional class names appended to every emitted wrapper's `class`\n * attribute. Used by `astro-dgmo` v0.3.0 to emit both the new `dgmo-*` class\n * names and the legacy `astro-dgmo-*` ones for one minor cycle of backward\n * compatibility. Default: `[]`.\n */\n legacyClassNames?: string[];\n\n /**\n * Emit MDX-compatible output. Default: `false` (raw `html` mdast node).\n *\n * When `true`, every replaced ```dgmo block becomes an `mdxJsxFlowElement`\n * (`<div dangerouslySetInnerHTML={{__html: …}} />`) so MDX-format files\n * accept the output. Use this when the host pipeline routes files through\n * `@mdx-js/mdx` — Docusaurus with `markdown.format: 'mdx'`, Astro `.mdx`\n * files, Fumadocs, etc. MDX rejects raw `html` nodes with\n * `Cannot handle unknown node \"raw\"`; this option is the fix.\n */\n mdx?: boolean;\n}\n\nexport type ResolvedOptions = Required<\n Omit<DgmoOptions, 'showSource' | 'showCopy' | 'showOpenInEditor' | 'mdx'>\n> & {\n showSource: boolean;\n showCopy: boolean;\n showOpenInEditor: boolean;\n mdx: boolean;\n};\n\n/**\n * Apply defaults, including mode-dependent defaults for showSource/showCopy/showOpenInEditor.\n */\nexport function resolveOptions(opts: DgmoOptions = {}): ResolvedOptions {\n const mode: Mode = opts.mode ?? 'diagram';\n const showcase = mode === 'showcase';\n return {\n mode,\n palette: opts.palette ?? 'nord',\n theme: opts.theme ?? 'dark',\n colorMode: opts.colorMode ?? 'auto',\n showSource: opts.showSource ?? showcase,\n showCopy: opts.showCopy ?? showcase,\n showOpenInEditor: opts.showOpenInEditor ?? showcase,\n editorBaseUrl: opts.editorBaseUrl ?? 'https://online.diagrammo.app',\n wrapper: opts.wrapper ?? 'figure',\n className: opts.className ?? 'dgmo',\n legacyClassNames: opts.legacyClassNames ?? [],\n mdx: opts.mdx ?? false,\n };\n}\n","import type { Mode, Theme } from './options.js';\n\n/**\n * Per-block options that can be set via the fence info string, e.g.\n *\n * ```dgmo showcase palette=catppuccin theme=light title=\"Login flow\"\n *\n * Tokens are space-separated. Boolean tokens are bare words (`showcase`,\n * `diagram`, `noSource`). Key=value pairs use `=`; values may be quoted with\n * double quotes to include spaces.\n */\nexport interface BlockOptions {\n mode?: Mode;\n palette?: string;\n theme?: Theme;\n colorMode?: 'auto' | 'light' | 'dark';\n showSource?: boolean;\n showCopy?: boolean;\n showOpenInEditor?: boolean;\n title?: string;\n}\n\nconst BARE_FLAGS: Record<string, Partial<BlockOptions>> = {\n diagram: { mode: 'diagram' },\n showcase: { mode: 'showcase' },\n noSource: { showSource: false },\n source: { showSource: true },\n noCopy: { showCopy: false },\n copy: { showCopy: true },\n noOpenInEditor: { showOpenInEditor: false },\n openInEditor: { showOpenInEditor: true },\n};\n\nconst VALID_THEMES = new Set<Theme>(['light', 'dark', 'transparent']);\nconst VALID_COLOR_MODES = new Set<'auto' | 'light' | 'dark'>([\n 'auto',\n 'light',\n 'dark',\n]);\n\n/**\n * Parse the meta string that follows ```dgmo on the fence line.\n * Robust to: empty, missing, malformed input.\n */\nexport function parseFenceMeta(meta: string | null | undefined): BlockOptions {\n if (!meta) return {};\n const out: BlockOptions = {};\n const tokens = tokenize(meta);\n for (const tok of tokens) {\n if (BARE_FLAGS[tok]) {\n Object.assign(out, BARE_FLAGS[tok]);\n continue;\n }\n const eq = tok.indexOf('=');\n if (eq < 0) continue;\n const key = tok.slice(0, eq).trim();\n const rawVal = tok.slice(eq + 1).trim();\n const val = unquote(rawVal);\n switch (key) {\n case 'palette':\n if (val) out.palette = val;\n break;\n case 'theme':\n if (VALID_THEMES.has(val as Theme)) out.theme = val as Theme;\n break;\n case 'colorMode':\n if (VALID_COLOR_MODES.has(val as 'auto' | 'light' | 'dark')) {\n out.colorMode = val as 'auto' | 'light' | 'dark';\n }\n break;\n case 'mode':\n if (val === 'diagram' || val === 'showcase') out.mode = val;\n break;\n case 'showSource':\n out.showSource = parseBool(val);\n break;\n case 'showCopy':\n out.showCopy = parseBool(val);\n break;\n case 'showOpenInEditor':\n out.showOpenInEditor = parseBool(val);\n break;\n case 'title':\n if (val) out.title = val;\n break;\n }\n }\n return out;\n}\n\nfunction parseBool(s: string): boolean {\n return s === 'true' || s === '1' || s === 'yes';\n}\n\nfunction unquote(s: string): string {\n if (s.length >= 2 && s.startsWith('\"') && s.endsWith('\"')) {\n return s.slice(1, -1);\n }\n return s;\n}\n\n/**\n * Split on whitespace, respecting double-quoted segments so a value like\n * `title=\"Login flow\"` survives intact.\n */\nfunction tokenize(input: string): string[] {\n const out: string[] = [];\n let buf = '';\n let inQuotes = false;\n for (let i = 0; i < input.length; i++) {\n const ch = input[i];\n if (ch === '\"') {\n inQuotes = !inQuotes;\n buf += ch;\n continue;\n }\n if (!inQuotes && /\\s/.test(ch)) {\n if (buf) {\n out.push(buf);\n buf = '';\n }\n continue;\n }\n buf += ch;\n }\n if (buf) out.push(buf);\n return out;\n}\n","/**\n * Normalize an SVG produced by `@diagrammo/dgmo` for inline embedding:\n *\n * - Compute a tight content bounding box from element coordinates and\n * set the root `viewBox` to bbox+padding. Replaces the JS-side\n * `getBBox()` step that can't measure dual-rendered SVGs hidden by\n * color-mode CSS.\n * - Ensure the root `<svg>` has a `viewBox` so it scales responsively.\n * - Strip fixed `width=\"N\"` / `height=\"N\"` so CSS controls sizing.\n * - Remove any inline `background:` from the root style so the page\n * background shows through.\n */\nexport function normalizeSvg(input: string): string {\n let svg = input;\n const rootMatch = svg.match(/<svg[^>]*>/);\n const rootTag = rootMatch?.[0] ?? '';\n if (rootTag && !rootTag.includes('viewBox')) {\n const wh = rootTag.match(/width=\"(\\d+)\"[^>]*height=\"(\\d+)\"/);\n if (wh) {\n svg = svg.replace(/<svg/, `<svg viewBox=\"0 0 ${wh[1]} ${wh[2]}\"`);\n }\n }\n\n // Tighten viewBox to the content bbox. dgmo emits diagrams within a\n // fixed-size canvas (e.g. viewBox=\"0 0 1200 250\"), with content often\n // occupying only a fraction of that canvas. Tightening here means\n // dual-rendered SVGs render at the same scale whether visible or not.\n const tight = computeBBox(svg);\n if (tight && tight.width > 0 && tight.height > 0) {\n const pad = 16;\n const vb = `${tight.x - pad} ${tight.y - pad} ${tight.width + pad * 2} ${tight.height + pad * 2}`;\n svg = svg.replace(/(<svg[^>]*?)viewBox=\"[^\"]*\"/, `$1viewBox=\"${vb}\"`);\n }\n\n svg = svg.replace(/(<svg[^>]*?) width=\"[^\"]*\"/g, '$1');\n svg = svg.replace(/(<svg[^>]*?) height=\"[^\"]*\"/g, '$1');\n svg = svg.replace(/(<svg[^>]*?style=\"[^\"]*?)background:[^;\"]*;?\\s*/g, '$1');\n svg = svg.replace(/<svg\\s{2,}/g, '<svg ');\n return svg;\n}\n\n/**\n * Compute an approximate content bounding box from raw element coordinates.\n *\n * This is a regex walk, not a real SVG layout — it ignores `transform`\n * attributes and uses a heuristic for text widths. dgmo's renderer mostly\n * uses absolute coordinates within its viewBox, so the approximation is\n * close enough that the rendered output reliably fills the visible area.\n */\nfunction computeBBox(\n svg: string\n): { x: number; y: number; width: number; height: number } | null {\n const xs: number[] = [];\n const ys: number[] = [];\n\n function push(x: number, y: number): void {\n if (Number.isFinite(x) && Number.isFinite(y)) {\n xs.push(x);\n ys.push(y);\n }\n }\n\n function attr(tag: string, name: string): number | null {\n const m = tag.match(new RegExp(`\\\\b${name}=\"([^\"]*)\"`));\n if (!m) return null;\n const n = parseFloat(m[1]);\n return Number.isFinite(n) ? n : null;\n }\n\n // <rect x y width height>\n for (const m of svg.matchAll(/<rect\\b[^>]*?\\/?>/g)) {\n const tag = m[0];\n const x = attr(tag, 'x');\n const y = attr(tag, 'y');\n const w = attr(tag, 'width');\n const h = attr(tag, 'height');\n if (x !== null && y !== null && w !== null && h !== null) {\n push(x, y);\n push(x + w, y + h);\n }\n }\n\n // <line x1 y1 x2 y2>\n for (const m of svg.matchAll(/<line\\b[^>]*?\\/?>/g)) {\n const tag = m[0];\n const x1 = attr(tag, 'x1');\n const y1 = attr(tag, 'y1');\n const x2 = attr(tag, 'x2');\n const y2 = attr(tag, 'y2');\n if (x1 !== null && y1 !== null && x2 !== null && y2 !== null) {\n push(x1, y1);\n push(x2, y2);\n }\n }\n\n // <circle cx cy r>\n for (const m of svg.matchAll(/<circle\\b[^>]*?\\/?>/g)) {\n const tag = m[0];\n const cx = attr(tag, 'cx');\n const cy = attr(tag, 'cy');\n const r = attr(tag, 'r');\n if (cx !== null && cy !== null && r !== null) {\n push(cx - r, cy - r);\n push(cx + r, cy + r);\n }\n }\n\n // <ellipse cx cy rx ry>\n for (const m of svg.matchAll(/<ellipse\\b[^>]*?\\/?>/g)) {\n const tag = m[0];\n const cx = attr(tag, 'cx');\n const cy = attr(tag, 'cy');\n const rx = attr(tag, 'rx');\n const ry = attr(tag, 'ry');\n if (cx !== null && cy !== null && rx !== null && ry !== null) {\n push(cx - rx, cy - ry);\n push(cx + rx, cy + ry);\n }\n }\n\n // <text x y>some content</text>\n // Approximate width: text content length × an empirical font width factor.\n // dgmo uses Inter ~14px by default; ~7-8px per character is a usable\n // rough estimate that won't drastically under- or over-count.\n for (const m of svg.matchAll(/<text\\b([^>]*?)>([\\s\\S]*?)<\\/text>/g)) {\n const tag = `<text${m[1]}>`;\n const text = m[2].replace(/<[^>]+>/g, ''); // strip inner tags (tspan, etc.)\n const x = attr(tag, 'x');\n const y = attr(tag, 'y');\n if (x !== null && y !== null) {\n const w = text.length * 7;\n // text-anchor may be start/middle/end; assume worst case (middle) for span\n push(x - w / 2, y - 14);\n push(x + w / 2, y + 4);\n }\n }\n\n // <path d=\"...\"> — pull every coordinate pair out of the d attribute.\n for (const m of svg.matchAll(/<path\\b[^>]*?\\bd=\"([^\"]+)\"/g)) {\n const d = m[1];\n const nums = d.match(/-?\\d+(?:\\.\\d+)?/g);\n if (!nums) continue;\n for (let i = 0; i + 1 < nums.length; i += 2) {\n push(parseFloat(nums[i]), parseFloat(nums[i + 1]));\n }\n }\n\n // <polygon points=\"x,y x,y ...\"> and <polyline>\n for (const m of svg.matchAll(/<(?:polygon|polyline)\\b[^>]*?\\bpoints=\"([^\"]+)\"/g)) {\n const nums = m[1].match(/-?\\d+(?:\\.\\d+)?/g);\n if (!nums) continue;\n for (let i = 0; i + 1 < nums.length; i += 2) {\n push(parseFloat(nums[i]), parseFloat(nums[i + 1]));\n }\n }\n\n if (xs.length === 0 || ys.length === 0) return null;\n\n const minX = Math.min(...xs);\n const maxX = Math.max(...xs);\n const minY = Math.min(...ys);\n const maxY = Math.max(...ys);\n\n return {\n x: minX,\n y: minY,\n width: maxX - minX,\n height: maxY - minY,\n };\n}\n","const HTML_ENTITIES: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;',\n};\n\nexport function escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, ch => HTML_ENTITIES[ch]);\n}\n\nexport function escapeAttr(s: string): string {\n return s.replace(/[&<>\"']/g, ch => HTML_ENTITIES[ch]);\n}\n","/**\n * Build an mdast node that an MDX pipeline accepts in place of a raw `html`\n * node. The output corresponds to authoring this in MDX:\n *\n * <div dangerouslySetInnerHTML={{ __html: \"…html…\" }} />\n *\n * MDX rejects mdast `html` nodes (\"Cannot handle unknown node `raw`\"), so when\n * the host pipeline is MDX-format (Docusaurus with `markdown.format: 'mdx'`,\n * Astro `.mdx`, Fumadocs, etc.) the plugin emits this node instead.\n *\n * The `data.estree` field is what survives MDX → React compilation —\n * `@mdx-js/mdx` reads attribute values from the estree, not the string-form\n * `value`. Without it, the expression silently evaluates to `undefined` and\n * the diagram disappears.\n */\n\nimport { valueToEstree } from 'estree-util-value-to-estree';\nimport type { ObjectExpression, Program } from 'estree';\n\ninterface MdxJsxAttributeValueExpression {\n type: 'mdxJsxAttributeValueExpression';\n value: string;\n data: { estree: Program };\n}\n\ninterface MdxJsxAttribute {\n type: 'mdxJsxAttribute';\n name: string;\n value: MdxJsxAttributeValueExpression;\n}\n\nexport interface MdxJsxFlowElement {\n type: 'mdxJsxFlowElement';\n name: string;\n attributes: MdxJsxAttribute[];\n children: [];\n}\n\nexport function htmlToMdxJsxNode(html: string): MdxJsxFlowElement {\n const objectExpression = valueToEstree({ __html: html }) as ObjectExpression;\n // valueToEstree emits ObjectExpression with `Property` entries — exactly the\n // shape MDX expects, so we use it verbatim and just wrap in a Program.\n const program: Program = {\n type: 'Program',\n body: [\n {\n type: 'ExpressionStatement',\n expression: objectExpression,\n },\n ],\n sourceType: 'module',\n };\n\n return {\n type: 'mdxJsxFlowElement',\n name: 'div',\n attributes: [\n {\n type: 'mdxJsxAttribute',\n name: 'dangerouslySetInnerHTML',\n value: {\n type: 'mdxJsxAttributeValueExpression',\n // String form is what `mdast-util-mdx-jsx` uses if it re-parses; we\n // also ship the estree on `data` for compilers that prefer it.\n value: `{__html: ${JSON.stringify(html)}}`,\n data: { estree: program },\n },\n },\n ],\n children: [],\n };\n}\n\n"],"mappings":"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","names":["editorUrl","html"]}
package/dist/client.css CHANGED
@@ -39,15 +39,20 @@
39
39
  }
40
40
  .dgmo-code { display: block; }
41
41
 
42
- /* === Showcase mode: card + toolbar === */
42
+ /* === Showcase mode: card + toolbar ===
43
+ * Showcase order is diagram-then-source. The source is wrapped in a
44
+ * <details> disclosure that's collapsed by default — the <summary>
45
+ * doubles as the toolbar row at the bottom of the card. */
43
46
  .dgmo-card {
44
47
  border: 1px solid rgba(127, 127, 127, 0.2);
45
48
  border-radius: 0.5em;
46
49
  overflow: hidden;
47
50
  }
48
51
  .dgmo-source-wrap {
49
- border-bottom: 1px solid rgba(127, 127, 127, 0.2);
52
+ border-top: 1px solid rgba(127, 127, 127, 0.2);
50
53
  }
54
+ /* Summary is the clickable toolbar. Hide the native disclosure marker
55
+ * (both spec and webkit pseudo) so our own chevron is the only indicator. */
51
56
  .dgmo-toolbar {
52
57
  display: flex;
53
58
  align-items: center;
@@ -57,7 +62,21 @@
57
62
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
58
63
  font-size: 0.75em;
59
64
  color: rgba(127, 127, 127, 0.95);
65
+ cursor: pointer;
66
+ list-style: none;
67
+ user-select: none;
68
+ }
69
+ .dgmo-toolbar::-webkit-details-marker { display: none; }
70
+ .dgmo-toolbar-label {
71
+ display: inline-flex;
72
+ align-items: center;
73
+ gap: 0.4em;
74
+ }
75
+ .dgmo-chevron {
76
+ transition: transform 0.15s ease;
77
+ flex-shrink: 0;
60
78
  }
79
+ details[open] > .dgmo-toolbar .dgmo-chevron { transform: rotate(90deg); }
61
80
  .dgmo-toolbar-actions {
62
81
  display: flex;
63
82
  gap: 0.4em;
package/dist/client.d.ts CHANGED
@@ -2,8 +2,13 @@
2
2
  * Framework-neutral client-side enhancement for diagrams emitted by
3
3
  * `remark-dgmo`:
4
4
  *
5
- * - Bind a delegated click handler for `button.dgmo-copy` to copy the
6
- * source string in `data-dgmo-source` to the clipboard.
5
+ * - Bind a delegated click handler for the showcase toolbar buttons:
6
+ * `.dgmo-copy` copies the source string in `data-dgmo-source` to the
7
+ * clipboard. `.dgmo-open` is an `<a href>` whose default-action
8
+ * navigation is preserved — except when it lives inside a `<summary>`
9
+ * (the collapsible toolbar case), where we have to manually navigate
10
+ * because the same click's `preventDefault()` cancels both the
11
+ * summary's toggle AND the anchor's nav.
7
12
  * - Tighten each diagram's `viewBox` to its actual content bounds via
8
13
  * `SVGGraphicsElement.getBBox()`, since SVG-export from the renderer
9
14
  * embeds a generous bounding box.
package/dist/client.js CHANGED
@@ -4,7 +4,7 @@ var themeObserverBound = false;
4
4
  function bindDgmo() {
5
5
  if (typeof window === "undefined" || typeof document === "undefined") return;
6
6
  if (!clickHandlerBound) {
7
- document.addEventListener("click", handleCopyClick);
7
+ document.addEventListener("click", handleToolbarBtnClick);
8
8
  clickHandlerBound = true;
9
9
  }
10
10
  tightenViewBoxes();
@@ -20,19 +20,30 @@ function bindDgmo() {
20
20
  themeObserverBound = true;
21
21
  }
22
22
  }
23
- async function handleCopyClick(e) {
23
+ async function handleToolbarBtnClick(e) {
24
24
  const target = e.target;
25
25
  if (!target || typeof target.closest !== "function") return;
26
- const btn = target.closest("button.dgmo-copy");
26
+ const btn = target.closest(".dgmo-toolbar-btn");
27
27
  if (!btn) return;
28
- const src = btn.dataset.dgmoSource ?? "";
29
- try {
30
- await navigator.clipboard.writeText(src);
31
- } catch {
28
+ const insideSummary = !!btn.closest("summary");
29
+ if (insideSummary) e.preventDefault();
30
+ if (btn.matches("button.dgmo-copy")) {
31
+ const src = btn.dataset.dgmoSource ?? "";
32
+ try {
33
+ await navigator.clipboard.writeText(src);
34
+ } catch {
35
+ return;
36
+ }
37
+ btn.classList.add("dgmo-copy--success");
38
+ setTimeout(() => btn.classList.remove("dgmo-copy--success"), 1500);
32
39
  return;
33
40
  }
34
- btn.classList.add("dgmo-copy--success");
35
- setTimeout(() => btn.classList.remove("dgmo-copy--success"), 1500);
41
+ if (insideSummary && btn.matches("a.dgmo-open")) {
42
+ const anchor = btn;
43
+ if (anchor.href) {
44
+ window.open(anchor.href, anchor.target || "_blank", "noopener,noreferrer");
45
+ }
46
+ }
36
47
  }
37
48
  function tightenViewBoxes() {
38
49
  const WRAPPER_SELECTORS = ".dgmo-light, .dgmo-dark, .dgmo-svg";
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"sourcesContent":["/**\n * Framework-neutral client-side enhancement for diagrams emitted by\n * `remark-dgmo`:\n *\n * - Bind a delegated click handler for `button.dgmo-copy` to copy the\n * source string in `data-dgmo-source` to the clipboard.\n * - Tighten each diagram's `viewBox` to its actual content bounds via\n * `SVGGraphicsElement.getBBox()`, since SVG-export from the renderer\n * embeds a generous bounding box.\n *\n * `bindDgmo()` is safe to call multiple times: the click handler is bound\n * once-and-only-once (idempotent), and viewBox tightening is run every\n * invocation so SPA-style frameworks (Docusaurus) can re-run it after\n * route changes.\n *\n * In a non-browser environment (Node SSR), `bindDgmo()` is a no-op.\n */\n\nlet clickHandlerBound = false;\nlet themeObserverBound = false;\n\nexport function bindDgmo(): void {\n if (typeof window === 'undefined' || typeof document === 'undefined') return;\n\n if (!clickHandlerBound) {\n document.addEventListener('click', handleCopyClick);\n clickHandlerBound = true;\n }\n tightenViewBoxes();\n\n // Color-mode toggles flip which dual-render wrapper is `display: none`.\n // The wrapper that was hidden at load couldn't be measured (getBBox\n // returns 0 on display:none subtrees), so its SVG keeps the full\n // un-tightened viewBox and looks tiny when it becomes visible. Watch\n // for the host's color-mode signal flipping and re-tighten then.\n //\n // Double-rAF defers the measurement until AFTER the browser has\n // finished the layout pass that the display-change triggered. Without\n // it, MutationObserver fires synchronously before layout and getBBox\n // still returns 0 on the freshly-visible element.\n if (!themeObserverBound) {\n const html = document.documentElement;\n const reTighten = () => {\n requestAnimationFrame(() => requestAnimationFrame(tightenViewBoxes));\n };\n new MutationObserver(reTighten).observe(html, {\n attributes: true,\n attributeFilter: ['data-theme', 'class'],\n });\n themeObserverBound = true;\n }\n}\n\nasync function handleCopyClick(e: Event): Promise<void> {\n const target = e.target as Element | null;\n if (!target || typeof target.closest !== 'function') return;\n const btn = target.closest('button.dgmo-copy') as HTMLElement | null;\n if (!btn) return;\n const src = btn.dataset.dgmoSource ?? '';\n try {\n await navigator.clipboard.writeText(src);\n } catch {\n return;\n }\n btn.classList.add('dgmo-copy--success');\n setTimeout(() => btn.classList.remove('dgmo-copy--success'), 1500);\n}\n\nfunction tightenViewBoxes(): void {\n const WRAPPER_SELECTORS = '.dgmo-light, .dgmo-dark, .dgmo-svg';\n document.querySelectorAll(WRAPPER_SELECTORS).forEach(node => {\n const wrapper = node as HTMLElement;\n const svg = wrapper.querySelector('svg') as SVGSVGElement | null;\n if (!svg) return;\n\n // `getBBox()` returns 0,0,0,0 on elements whose ancestor is `display: none`.\n // Under dual-render the inactive color-mode wrapper IS display:none at load,\n // so its SVG would stay un-tightened — and then look small after the user\n // toggles into it. Set the wrapper to inline-style `display: block`\n // synchronously, read getBBox, then restore. Modern browsers don't paint\n // between these synchronous DOM writes, so there's no visible flicker.\n const computed = window.getComputedStyle(wrapper);\n const wasHidden = computed.display === 'none';\n const savedInlineDisplay = wrapper.style.display;\n if (wasHidden) {\n wrapper.style.display = 'block';\n // Force a synchronous layout pass before getBBox so the freshly-\n // shown element actually has bounds. Without this, some browsers\n // still report 0,0,0,0 because they batch the display change for\n // the next frame.\n void wrapper.offsetHeight;\n }\n\n try {\n const bbox = (svg as unknown as SVGGraphicsElement).getBBox();\n if (bbox.width > 0 && bbox.height > 0) {\n const pad = 16;\n svg.setAttribute(\n 'viewBox',\n `${bbox.x - pad} ${bbox.y - pad} ${bbox.width + pad * 2} ${\n bbox.height + pad * 2\n }`\n );\n }\n } catch {\n // ignore: SVG not yet in the DOM, or getBBox unsupported\n }\n\n if (wasHidden) wrapper.style.display = savedInlineDisplay;\n });\n}\n\n// Auto-init on initial load. Docusaurus-style SPA wrappers also re-call\n// bindDgmo on route changes; that's safe (the click handler is bound once,\n// viewBox tightening runs every time).\nif (typeof window !== 'undefined' && typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', bindDgmo);\n } else {\n bindDgmo();\n }\n}\n"],"mappings":";AAkBA,IAAI,oBAAoB;AACxB,IAAI,qBAAqB;AAElB,SAAS,WAAiB;AAC/B,MAAI,OAAO,WAAW,eAAe,OAAO,aAAa,YAAa;AAEtE,MAAI,CAAC,mBAAmB;AACtB,aAAS,iBAAiB,SAAS,eAAe;AAClD,wBAAoB;AAAA,EACtB;AACA,mBAAiB;AAYjB,MAAI,CAAC,oBAAoB;AACvB,UAAM,OAAO,SAAS;AACtB,UAAM,YAAY,MAAM;AACtB,4BAAsB,MAAM,sBAAsB,gBAAgB,CAAC;AAAA,IACrE;AACA,QAAI,iBAAiB,SAAS,EAAE,QAAQ,MAAM;AAAA,MAC5C,YAAY;AAAA,MACZ,iBAAiB,CAAC,cAAc,OAAO;AAAA,IACzC,CAAC;AACD,yBAAqB;AAAA,EACvB;AACF;AAEA,eAAe,gBAAgB,GAAyB;AACtD,QAAM,SAAS,EAAE;AACjB,MAAI,CAAC,UAAU,OAAO,OAAO,YAAY,WAAY;AACrD,QAAM,MAAM,OAAO,QAAQ,kBAAkB;AAC7C,MAAI,CAAC,IAAK;AACV,QAAM,MAAM,IAAI,QAAQ,cAAc;AACtC,MAAI;AACF,UAAM,UAAU,UAAU,UAAU,GAAG;AAAA,EACzC,QAAQ;AACN;AAAA,EACF;AACA,MAAI,UAAU,IAAI,oBAAoB;AACtC,aAAW,MAAM,IAAI,UAAU,OAAO,oBAAoB,GAAG,IAAI;AACnE;AAEA,SAAS,mBAAyB;AAChC,QAAM,oBAAoB;AAC1B,WAAS,iBAAiB,iBAAiB,EAAE,QAAQ,UAAQ;AAC3D,UAAM,UAAU;AAChB,UAAM,MAAM,QAAQ,cAAc,KAAK;AACvC,QAAI,CAAC,IAAK;AAQV,UAAM,WAAW,OAAO,iBAAiB,OAAO;AAChD,UAAM,YAAY,SAAS,YAAY;AACvC,UAAM,qBAAqB,QAAQ,MAAM;AACzC,QAAI,WAAW;AACb,cAAQ,MAAM,UAAU;AAKxB,WAAK,QAAQ;AAAA,IACf;AAEA,QAAI;AACF,YAAM,OAAQ,IAAsC,QAAQ;AAC5D,UAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,GAAG;AACrC,cAAM,MAAM;AACZ,YAAI;AAAA,UACF;AAAA,UACA,GAAG,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,KAAK,QAAQ,MAAM,CAAC,IACrD,KAAK,SAAS,MAAM,CACtB;AAAA,QACF;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,QAAI,UAAW,SAAQ,MAAM,UAAU;AAAA,EACzC,CAAC;AACH;AAKA,IAAI,OAAO,WAAW,eAAe,OAAO,aAAa,aAAa;AACpE,MAAI,SAAS,eAAe,WAAW;AACrC,aAAS,iBAAiB,oBAAoB,QAAQ;AAAA,EACxD,OAAO;AACL,aAAS;AAAA,EACX;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/client.ts"],"sourcesContent":["/**\n * Framework-neutral client-side enhancement for diagrams emitted by\n * `remark-dgmo`:\n *\n * - Bind a delegated click handler for the showcase toolbar buttons:\n * `.dgmo-copy` copies the source string in `data-dgmo-source` to the\n * clipboard. `.dgmo-open` is an `<a href>` whose default-action\n * navigation is preserved — except when it lives inside a `<summary>`\n * (the collapsible toolbar case), where we have to manually navigate\n * because the same click's `preventDefault()` cancels both the\n * summary's toggle AND the anchor's nav.\n * - Tighten each diagram's `viewBox` to its actual content bounds via\n * `SVGGraphicsElement.getBBox()`, since SVG-export from the renderer\n * embeds a generous bounding box.\n *\n * `bindDgmo()` is safe to call multiple times: the click handler is bound\n * once-and-only-once (idempotent), and viewBox tightening is run every\n * invocation so SPA-style frameworks (Docusaurus) can re-run it after\n * route changes.\n *\n * In a non-browser environment (Node SSR), `bindDgmo()` is a no-op.\n */\n\nlet clickHandlerBound = false;\nlet themeObserverBound = false;\n\nexport function bindDgmo(): void {\n if (typeof window === 'undefined' || typeof document === 'undefined') return;\n\n if (!clickHandlerBound) {\n document.addEventListener('click', handleToolbarBtnClick);\n clickHandlerBound = true;\n }\n tightenViewBoxes();\n\n // Color-mode toggles flip which dual-render wrapper is `display: none`.\n // The wrapper that was hidden at load couldn't be measured (getBBox\n // returns 0 on display:none subtrees), so its SVG keeps the full\n // un-tightened viewBox and looks tiny when it becomes visible. Watch\n // for the host's color-mode signal flipping and re-tighten then.\n //\n // Double-rAF defers the measurement until AFTER the browser has\n // finished the layout pass that the display-change triggered. Without\n // it, MutationObserver fires synchronously before layout and getBBox\n // still returns 0 on the freshly-visible element.\n if (!themeObserverBound) {\n const html = document.documentElement;\n const reTighten = () => {\n requestAnimationFrame(() => requestAnimationFrame(tightenViewBoxes));\n };\n new MutationObserver(reTighten).observe(html, {\n attributes: true,\n attributeFilter: ['data-theme', 'class'],\n });\n themeObserverBound = true;\n }\n}\n\nasync function handleToolbarBtnClick(e: Event): Promise<void> {\n const target = e.target as Element | null;\n if (!target || typeof target.closest !== 'function') return;\n const btn = target.closest('.dgmo-toolbar-btn') as HTMLElement | null;\n if (!btn) return;\n\n // The showcase toolbar IS the <summary> of a <details> disclosure, so a\n // click on any descendant would also toggle the disclosure unless we\n // cancel the default action. preventDefault here cancels the summary's\n // toggle — but it also cancels an anchor's navigation, so we have to\n // manually re-open the link below when the open-in-editor button is\n // nested inside a summary.\n const insideSummary = !!btn.closest('summary');\n if (insideSummary) e.preventDefault();\n\n if (btn.matches('button.dgmo-copy')) {\n const src = btn.dataset.dgmoSource ?? '';\n try {\n await navigator.clipboard.writeText(src);\n } catch {\n return;\n }\n btn.classList.add('dgmo-copy--success');\n setTimeout(() => btn.classList.remove('dgmo-copy--success'), 1500);\n return;\n }\n\n if (insideSummary && btn.matches('a.dgmo-open')) {\n const anchor = btn as HTMLAnchorElement;\n if (anchor.href) {\n window.open(anchor.href, anchor.target || '_blank', 'noopener,noreferrer');\n }\n }\n}\n\nfunction tightenViewBoxes(): void {\n const WRAPPER_SELECTORS = '.dgmo-light, .dgmo-dark, .dgmo-svg';\n document.querySelectorAll(WRAPPER_SELECTORS).forEach(node => {\n const wrapper = node as HTMLElement;\n const svg = wrapper.querySelector('svg') as SVGSVGElement | null;\n if (!svg) return;\n\n // `getBBox()` returns 0,0,0,0 on elements whose ancestor is `display: none`.\n // Under dual-render the inactive color-mode wrapper IS display:none at load,\n // so its SVG would stay un-tightened — and then look small after the user\n // toggles into it. Set the wrapper to inline-style `display: block`\n // synchronously, read getBBox, then restore. Modern browsers don't paint\n // between these synchronous DOM writes, so there's no visible flicker.\n const computed = window.getComputedStyle(wrapper);\n const wasHidden = computed.display === 'none';\n const savedInlineDisplay = wrapper.style.display;\n if (wasHidden) {\n wrapper.style.display = 'block';\n // Force a synchronous layout pass before getBBox so the freshly-\n // shown element actually has bounds. Without this, some browsers\n // still report 0,0,0,0 because they batch the display change for\n // the next frame.\n void wrapper.offsetHeight;\n }\n\n try {\n const bbox = (svg as unknown as SVGGraphicsElement).getBBox();\n if (bbox.width > 0 && bbox.height > 0) {\n const pad = 16;\n svg.setAttribute(\n 'viewBox',\n `${bbox.x - pad} ${bbox.y - pad} ${bbox.width + pad * 2} ${\n bbox.height + pad * 2\n }`\n );\n }\n } catch {\n // ignore: SVG not yet in the DOM, or getBBox unsupported\n }\n\n if (wasHidden) wrapper.style.display = savedInlineDisplay;\n });\n}\n\n// Auto-init on initial load. Docusaurus-style SPA wrappers also re-call\n// bindDgmo on route changes; that's safe (the click handler is bound once,\n// viewBox tightening runs every time).\nif (typeof window !== 'undefined' && typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', bindDgmo);\n } else {\n bindDgmo();\n }\n}\n"],"mappings":";AAuBA,IAAI,oBAAoB;AACxB,IAAI,qBAAqB;AAElB,SAAS,WAAiB;AAC/B,MAAI,OAAO,WAAW,eAAe,OAAO,aAAa,YAAa;AAEtE,MAAI,CAAC,mBAAmB;AACtB,aAAS,iBAAiB,SAAS,qBAAqB;AACxD,wBAAoB;AAAA,EACtB;AACA,mBAAiB;AAYjB,MAAI,CAAC,oBAAoB;AACvB,UAAM,OAAO,SAAS;AACtB,UAAM,YAAY,MAAM;AACtB,4BAAsB,MAAM,sBAAsB,gBAAgB,CAAC;AAAA,IACrE;AACA,QAAI,iBAAiB,SAAS,EAAE,QAAQ,MAAM;AAAA,MAC5C,YAAY;AAAA,MACZ,iBAAiB,CAAC,cAAc,OAAO;AAAA,IACzC,CAAC;AACD,yBAAqB;AAAA,EACvB;AACF;AAEA,eAAe,sBAAsB,GAAyB;AAC5D,QAAM,SAAS,EAAE;AACjB,MAAI,CAAC,UAAU,OAAO,OAAO,YAAY,WAAY;AACrD,QAAM,MAAM,OAAO,QAAQ,mBAAmB;AAC9C,MAAI,CAAC,IAAK;AAQV,QAAM,gBAAgB,CAAC,CAAC,IAAI,QAAQ,SAAS;AAC7C,MAAI,cAAe,GAAE,eAAe;AAEpC,MAAI,IAAI,QAAQ,kBAAkB,GAAG;AACnC,UAAM,MAAM,IAAI,QAAQ,cAAc;AACtC,QAAI;AACF,YAAM,UAAU,UAAU,UAAU,GAAG;AAAA,IACzC,QAAQ;AACN;AAAA,IACF;AACA,QAAI,UAAU,IAAI,oBAAoB;AACtC,eAAW,MAAM,IAAI,UAAU,OAAO,oBAAoB,GAAG,IAAI;AACjE;AAAA,EACF;AAEA,MAAI,iBAAiB,IAAI,QAAQ,aAAa,GAAG;AAC/C,UAAM,SAAS;AACf,QAAI,OAAO,MAAM;AACf,aAAO,KAAK,OAAO,MAAM,OAAO,UAAU,UAAU,qBAAqB;AAAA,IAC3E;AAAA,EACF;AACF;AAEA,SAAS,mBAAyB;AAChC,QAAM,oBAAoB;AAC1B,WAAS,iBAAiB,iBAAiB,EAAE,QAAQ,UAAQ;AAC3D,UAAM,UAAU;AAChB,UAAM,MAAM,QAAQ,cAAc,KAAK;AACvC,QAAI,CAAC,IAAK;AAQV,UAAM,WAAW,OAAO,iBAAiB,OAAO;AAChD,UAAM,YAAY,SAAS,YAAY;AACvC,UAAM,qBAAqB,QAAQ,MAAM;AACzC,QAAI,WAAW;AACb,cAAQ,MAAM,UAAU;AAKxB,WAAK,QAAQ;AAAA,IACf;AAEA,QAAI;AACF,YAAM,OAAQ,IAAsC,QAAQ;AAC5D,UAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,GAAG;AACrC,cAAM,MAAM;AACZ,YAAI;AAAA,UACF;AAAA,UACA,GAAG,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,KAAK,QAAQ,MAAM,CAAC,IACrD,KAAK,SAAS,MAAM,CACtB;AAAA,QACF;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,QAAI,UAAW,SAAQ,MAAM,UAAU;AAAA,EACzC,CAAC;AACH;AAKA,IAAI,OAAO,WAAW,eAAe,OAAO,aAAa,aAAa;AACpE,MAAI,SAAS,eAAe,WAAW;AACrC,aAAS,iBAAiB,oBAAoB,QAAQ;AAAA,EACxD,OAAO;AACL,aAAS;AAAA,EACX;AACF;","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { D as DgmoOptions, M as Mode, T as Theme } from './remark-plugin-CNBL_aZc.js';
2
- export { R as RemarkDgmoOptions, a as ResolvedOptions, r as default, r as remarkDgmo, b as resolveOptions } from './remark-plugin-CNBL_aZc.js';
1
+ import { D as DgmoOptions, M as Mode, T as Theme } from './remark-plugin-Cs_wkViF.js';
2
+ export { R as RemarkDgmoOptions, a as ResolvedOptions, r as default, r as remarkDgmo, b as resolveOptions } from './remark-plugin-Cs_wkViF.js';
3
3
  import 'mdast';
4
4
 
5
5
  interface RenderBlockResult {
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  remarkDgmo,
5
5
  renderDgmoBlock,
6
6
  resolveOptions
7
- } from "./chunk-E5QL6KCZ.js";
7
+ } from "./chunk-LUCV265X.js";
8
8
  export {
9
9
  remarkDgmo as default,
10
10
  normalizeSvg,
@@ -75,11 +75,23 @@ interface DgmoOptions {
75
75
  * compatibility. Default: `[]`.
76
76
  */
77
77
  legacyClassNames?: string[];
78
+ /**
79
+ * Emit MDX-compatible output. Default: `false` (raw `html` mdast node).
80
+ *
81
+ * When `true`, every replaced ```dgmo block becomes an `mdxJsxFlowElement`
82
+ * (`<div dangerouslySetInnerHTML={{__html: …}} />`) so MDX-format files
83
+ * accept the output. Use this when the host pipeline routes files through
84
+ * `@mdx-js/mdx` — Docusaurus with `markdown.format: 'mdx'`, Astro `.mdx`
85
+ * files, Fumadocs, etc. MDX rejects raw `html` nodes with
86
+ * `Cannot handle unknown node "raw"`; this option is the fix.
87
+ */
88
+ mdx?: boolean;
78
89
  }
79
- type ResolvedOptions = Required<Omit<DgmoOptions, 'showSource' | 'showCopy' | 'showOpenInEditor'>> & {
90
+ type ResolvedOptions = Required<Omit<DgmoOptions, 'showSource' | 'showCopy' | 'showOpenInEditor' | 'mdx'>> & {
80
91
  showSource: boolean;
81
92
  showCopy: boolean;
82
93
  showOpenInEditor: boolean;
94
+ mdx: boolean;
83
95
  };
84
96
  /**
85
97
  * Apply defaults, including mode-dependent defaults for showSource/showCopy/showOpenInEditor.
@@ -1,2 +1,2 @@
1
1
  import 'mdast';
2
- export { R as RemarkDgmoOptions, r as default } from './remark-plugin-CNBL_aZc.js';
2
+ export { R as RemarkDgmoOptions, r as default } from './remark-plugin-Cs_wkViF.js';
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  remarkDgmo
3
- } from "./chunk-E5QL6KCZ.js";
3
+ } from "./chunk-LUCV265X.js";
4
4
  export {
5
5
  remarkDgmo as default
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remark-dgmo",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Remark plugin to render DGMO diagrams from fenced code blocks at build time. Framework-agnostic core shared by astro-dgmo, docusaurus-plugin-dgmo, and any unified pipeline.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -70,10 +70,13 @@
70
70
  "@lezer/common": "^1.5.1",
71
71
  "@lezer/highlight": "^1.2.3",
72
72
  "@lezer/lr": "^1.4.8",
73
+ "estree-util-value-to-estree": "^3.5.0",
73
74
  "unist-util-visit": "^5.0.0"
74
75
  },
75
76
  "devDependencies": {
76
77
  "@diagrammo/dgmo": "^0.15.0",
78
+ "@mdx-js/mdx": "^3.1.0",
79
+ "@types/estree": "^1.0.8",
77
80
  "@types/mdast": "^4.0.4",
78
81
  "@types/node": "^22.10.0",
79
82
  "postcss": "^8.4.49",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/remark-plugin.ts","../src/render-block.ts","../src/options.ts","../src/fence-meta.ts","../src/svg-normalize.ts","../src/escape.ts"],"sourcesContent":["import { visit } from 'unist-util-visit';\nimport type { Root, Code, Html, Parent } from 'mdast';\nimport { renderDgmoBlock, type BlockLocation } from './render-block.js';\nimport type { DgmoOptions } from './options.js';\n\nexport type RemarkDgmoOptions = DgmoOptions;\n\ninterface FencePayload {\n source: string;\n meta: string | null;\n location: BlockLocation;\n}\n\ninterface Target {\n parent: Parent;\n index: number;\n payload: FencePayload;\n}\n\n/**\n * Remark plugin that finds ```dgmo fenced code blocks and replaces them with\n * an HTML node containing the rendered SVG (and optional showcase chrome).\n *\n * The `lang` field on the code node is the fence language (the word after the\n * backticks). The `meta` field is everything that follows on the same line,\n * which we use to allow per-block options like ```dgmo showcase palette=catppuccin.\n *\n * Replaces the code node entirely (parent.children[index] = newNode) rather\n * than mutating it in place — otherwise downstream rehype/Shiki plugins still\n * see the lingering `lang: 'dgmo'` and `value: '...source...'` properties and\n * may re-process the block as a plaintext code listing, clobbering our\n * syntax-highlighted output.\n *\n * Async-safe: replacement is collected first, applied after parsing finishes.\n */\nexport default function remarkDgmo(options: RemarkDgmoOptions = {}) {\n return async function transformer(\n tree: Root,\n file?: { path?: string }\n ): Promise<void> {\n const targets: Target[] = [];\n visit(tree, 'code', (node: Code, index, parent) => {\n if (node.lang !== 'dgmo') return;\n if (!parent || index === undefined) return;\n const loc: BlockLocation = {};\n if (file?.path) loc.path = file.path;\n const line = node.position?.start.line;\n if (typeof line === 'number') loc.line = line;\n targets.push({\n parent: parent as Parent,\n index,\n payload: { source: node.value, meta: node.meta ?? null, location: loc },\n });\n });\n if (targets.length === 0) return;\n\n const rendered = await Promise.all(\n targets.map(t =>\n renderDgmoBlock(\n t.payload.source,\n t.payload.meta,\n options,\n t.payload.location\n ).catch(err => ({\n html: errorHtml(err, t.payload.source, options),\n diagnostics: [],\n }))\n )\n );\n\n // Replace in reverse index order per parent so earlier replacements don't\n // shift indices of later targets in the same parent. (Visit walks in tree\n // order, so within a single parent's children targets are also ordered;\n // reversing is sufficient.)\n for (let i = targets.length - 1; i >= 0; i--) {\n const t = targets[i];\n const html: Html = { type: 'html', value: rendered[i].html };\n t.parent.children[t.index] = html;\n }\n };\n}\n\nfunction errorHtml(\n err: unknown,\n source: string,\n options: RemarkDgmoOptions\n): string {\n const msg =\n err instanceof Error ? err.message : 'Failed to render dgmo block.';\n const safeMsg = msg.replace(/[<>&]/g, ch =>\n ch === '<' ? '&lt;' : ch === '>' ? '&gt;' : '&amp;'\n );\n const safeSrc = source.replace(/[<>&]/g, ch =>\n ch === '<' ? '&lt;' : ch === '>' ? '&gt;' : '&amp;'\n );\n const baseClass = options.className ?? 'dgmo';\n const legacy = (options.legacyClassNames ?? []).join(' ');\n const cls = legacy\n ? `${baseClass} ${legacy} ${baseClass}--error`\n : `${baseClass} ${baseClass}--error`;\n return (\n `<div class=\"${cls}\" role=\"alert\">` +\n `<strong>dgmo render error:</strong> ${safeMsg}` +\n `<pre>${safeSrc}</pre></div>`\n );\n}\n","import {\n render,\n encodeDiagramUrl,\n palettes,\n type PaletteConfig,\n} from '@diagrammo/dgmo';\nimport { highlightDgmo, NORD_ROLE_STYLES } from '@diagrammo/dgmo/highlight';\nimport {\n resolveOptions,\n type DgmoOptions,\n type ResolvedOptions,\n type Theme,\n} from './options.js';\nimport { parseFenceMeta } from './fence-meta.js';\nimport { normalizeSvg } from './svg-normalize.js';\nimport { escapeHtml, escapeAttr } from './escape.js';\n\nexport interface RenderBlockResult {\n html: string;\n diagnostics: Array<{ message: string; line?: number; severity?: string }>;\n}\n\n/**\n * Optional source-location hint, passed through from the remark transformer so\n * palette-fallback warnings can point at the offending block.\n */\nexport interface BlockLocation {\n path?: string;\n line?: number;\n}\n\n/**\n * Render a single ```dgmo block to inline HTML. Pure function: takes source +\n * options and returns the HTML string and any diagnostics from the parser.\n *\n * The remark plugin calls this for every matched code node.\n */\nexport async function renderDgmoBlock(\n source: string,\n meta: string | null | undefined,\n integrationOptions: DgmoOptions = {},\n location?: BlockLocation\n): Promise<RenderBlockResult> {\n const block = parseFenceMeta(meta);\n const base = resolveOptions(integrationOptions);\n const effectiveMode = block.mode ?? base.mode;\n const showcase = effectiveMode === 'showcase';\n const opts: ResolvedOptions = {\n ...base,\n mode: effectiveMode,\n palette: block.palette ?? base.palette,\n theme: block.theme ?? base.theme,\n colorMode: block.colorMode ?? base.colorMode,\n showSource:\n block.showSource ?? (block.mode ? showcase : base.showSource),\n showCopy: block.showCopy ?? (block.mode ? showcase : base.showCopy),\n showOpenInEditor:\n block.showOpenInEditor ?? (block.mode ? showcase : base.showOpenInEditor),\n };\n\n const trimmed = source.trim();\n const palette = resolvePaletteWithWarning(opts.palette, location);\n\n // collect diagnostics from however many render passes we end up doing\n const allDiagnostics: RenderBlockResult['diagnostics'] = [];\n\n if (opts.colorMode === 'auto') {\n const [lightSvgRaw, darkSvgRaw] = await Promise.all([\n renderForTheme(trimmed, palette, 'light', opts.palette, location),\n renderForTheme(trimmed, palette, 'dark', opts.palette, location),\n ]);\n allDiagnostics.push(...lightSvgRaw.diagnostics, ...darkSvgRaw.diagnostics);\n\n const lightSvg = normalizeSvg(lightSvgRaw.svg);\n const darkSvg = normalizeSvg(darkSvgRaw.svg);\n\n let editorUrl: string | undefined;\n if (opts.showOpenInEditor) {\n const url = encodeDiagramUrl(trimmed, { baseUrl: opts.editorBaseUrl });\n editorUrl = url ?? opts.editorBaseUrl;\n }\n\n const html =\n opts.mode === 'showcase'\n ? renderShowcaseDual(trimmed, lightSvg, darkSvg, editorUrl, opts, block.title)\n : renderSimpleDual(lightSvg, darkSvg, opts, block.title);\n\n return { html, diagnostics: allDiagnostics };\n }\n\n // Single-render path. colorMode is narrowed to 'light' | 'dark' here since\n // 'auto' is handled above. The dgmo render() also accepts 'transparent', but\n // we don't surface that via colorMode — it's reachable via `theme`.\n const themeForRender: Theme = opts.colorMode === 'light' ? 'light' : 'dark';\n const { svg: rawSvg, diagnostics } = await render(trimmed, {\n palette,\n theme: themeForRender,\n });\n allDiagnostics.push(...diagnostics);\n const svg = normalizeSvg(rawSvg);\n\n let editorUrl: string | undefined;\n if (opts.showOpenInEditor) {\n const url = encodeDiagramUrl(trimmed, { baseUrl: opts.editorBaseUrl });\n editorUrl = url ?? opts.editorBaseUrl;\n }\n\n const html =\n opts.mode === 'showcase'\n ? renderShowcase(trimmed, svg, editorUrl, opts, block.title)\n : renderSimple(svg, opts, block.title);\n\n return { html, diagnostics: allDiagnostics };\n}\n\nfunction locationSuffix(location: BlockLocation | undefined): string {\n if (!location) return '';\n if (location.path && location.line) return ` at ${location.path}:${location.line}`;\n if (location.line) return ` at line ${location.line}`;\n return '';\n}\n\nfunction resolvePaletteWithWarning(\n name: string,\n location: BlockLocation | undefined\n): PaletteConfig {\n const found = Object.values(palettes).find(p => p.id === name);\n if (!found) {\n // eslint-disable-next-line no-console\n console.warn(\n `[remark-dgmo] palette \"${name}\" not registered, falling back to \"nord\"${locationSuffix(location)}`\n );\n return palettes.nord;\n }\n return found;\n}\n\n/**\n * Render one theme. If `colorMode: 'auto'` is requested but the palette is\n * missing the requested mode, fall back to nord's mode and emit a warning.\n *\n * Today this is defensive: dgmo's palette registry validates both modes at\n * registration time, so every registered palette has both pairs by\n * construction. User-supplied palettes via `registerPalette()` that slip past\n * validation would hit this path; tests exercise it via mocking.\n */\nasync function renderForTheme(\n source: string,\n palette: PaletteConfig,\n theme: 'light' | 'dark',\n requestedName: string,\n location: BlockLocation | undefined\n): Promise<{ svg: string; diagnostics: RenderBlockResult['diagnostics'] }> {\n if (!palette[theme]) {\n // eslint-disable-next-line no-console\n console.warn(\n `[remark-dgmo] palette \"${requestedName}\" has no ${theme} mode; using nord ${theme} for the missing pair${locationSuffix(location)}`\n );\n // Build a synthetic palette where the missing mode is borrowed from nord.\n const filled: PaletteConfig = {\n ...palette,\n [theme]: palettes.nord[theme],\n } as PaletteConfig;\n return render(source, { palette: filled, theme });\n }\n return render(source, { palette, theme });\n}\n\nfunction buildWrapperClasses(\n resolved: Pick<ResolvedOptions, 'className' | 'legacyClassNames'>,\n variant: 'diagram' | 'showcase' | 'error'\n): string {\n const base = `${resolved.className} ${resolved.className}--${variant}`;\n const legacy = resolved.legacyClassNames.join(' ');\n return legacy ? `${base} ${legacy}` : base;\n}\n\nfunction buildInnerClasses(\n resolved: Pick<ResolvedOptions, 'legacyClassNames'>,\n primary: string\n): string {\n const legacy = resolved.legacyClassNames.join(' ');\n return legacy ? `${primary} ${legacy}` : primary;\n}\n\nfunction renderSimple(\n svg: string,\n opts: ResolvedOptions,\n title?: string\n): string {\n const Wrapper = opts.wrapper;\n const wrapperClass = buildWrapperClasses(opts, 'diagram');\n const captionHtml = title\n ? `<figcaption class=\"dgmo-caption\">${escapeHtml(title)}</figcaption>`\n : '';\n const captionFallback =\n title && Wrapper !== 'figure'\n ? `<div class=\"dgmo-caption\">${escapeHtml(title)}</div>`\n : '';\n return (\n `<${Wrapper} class=\"${escapeAttr(wrapperClass)}\">` +\n (Wrapper === 'figure' ? captionHtml : captionFallback) +\n `<div class=\"${escapeAttr(buildInnerClasses(opts, 'dgmo-svg'))}\">${svg}</div>` +\n `</${Wrapper}>`\n );\n}\n\nfunction renderSimpleDual(\n lightSvg: string,\n darkSvg: string,\n opts: ResolvedOptions,\n title?: string\n): string {\n const Wrapper = opts.wrapper;\n const wrapperClass = buildWrapperClasses(opts, 'diagram');\n const captionHtml = title\n ? `<figcaption class=\"dgmo-caption\">${escapeHtml(title)}</figcaption>`\n : '';\n const captionFallback =\n title && Wrapper !== 'figure'\n ? `<div class=\"dgmo-caption\">${escapeHtml(title)}</div>`\n : '';\n return (\n `<${Wrapper} class=\"${escapeAttr(wrapperClass)}\">` +\n (Wrapper === 'figure' ? captionHtml : captionFallback) +\n `<div class=\"${escapeAttr(buildInnerClasses(opts, 'dgmo-light'))}\">${lightSvg}</div>` +\n `<div class=\"${escapeAttr(buildInnerClasses(opts, 'dgmo-dark'))}\">${darkSvg}</div>` +\n `</${Wrapper}>`\n );\n}\n\nfunction renderShowcase(\n source: string,\n svg: string,\n editorUrl: string | undefined,\n opts: ResolvedOptions,\n title?: string\n): string {\n const Wrapper = opts.wrapper;\n const wrapperClass = buildWrapperClasses(opts, 'showcase');\n const cardClass = buildInnerClasses(opts, 'dgmo-card');\n\n const captionHtml = title\n ? Wrapper === 'figure'\n ? `<figcaption class=\"dgmo-caption\">${escapeHtml(title)}</figcaption>`\n : `<div class=\"dgmo-caption\">${escapeHtml(title)}</div>`\n : '';\n\n const sourceHtml = opts.showSource ? renderSource(source) : '';\n\n const openButton =\n opts.showOpenInEditor && editorUrl\n ? `<a href=\"${escapeAttr(editorUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"dgmo-toolbar-btn dgmo-open\" aria-label=\"Open in online editor\" title=\"Open in online editor\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M9.5 2.5h4v4\"/>\n <path d=\"M13.5 2.5 7 9\"/>\n <path d=\"M12.5 9.5v3a1 1 0 0 1-1 1h-8a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1h3\"/>\n </svg>\n </a>`\n : '';\n\n const copyButton = opts.showCopy\n ? `<button type=\"button\" class=\"dgmo-toolbar-btn dgmo-copy\" aria-label=\"Copy to clipboard\" title=\"Copy to clipboard\" data-dgmo-source=\"${escapeAttr(source)}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8\" rx=\"1.5\"/>\n <path d=\"M10.5 5.5V3a1.5 1.5 0 0 0-1.5-1.5H3A1.5 1.5 0 0 0 1.5 3v6A1.5 1.5 0 0 0 3 10.5h2.5\"/>\n </svg>\n </button>`\n : '';\n\n const toolbarActions =\n openButton || copyButton\n ? `<div class=\"dgmo-toolbar-actions\">${openButton}${copyButton}</div>`\n : '';\n\n const toolbar = opts.showSource\n ? `<div class=\"dgmo-toolbar\"><span class=\"dgmo-toolbar-label\">dgmo</span>${toolbarActions}</div>`\n : '';\n\n return (\n `<${Wrapper} class=\"${escapeAttr(wrapperClass)}\">` +\n captionHtml +\n `<div class=\"${escapeAttr(cardClass)}\">` +\n (opts.showSource\n ? `<div class=\"dgmo-source-wrap\">${toolbar}<div class=\"dgmo-source-inner\">${sourceHtml}</div></div>`\n : '') +\n `<div class=\"${escapeAttr(buildInnerClasses(opts, 'dgmo-svg'))}\">${svg}</div>` +\n `</div>` +\n `</${Wrapper}>`\n );\n}\n\nfunction renderShowcaseDual(\n source: string,\n lightSvg: string,\n darkSvg: string,\n editorUrl: string | undefined,\n opts: ResolvedOptions,\n title?: string\n): string {\n const Wrapper = opts.wrapper;\n const wrapperClass = buildWrapperClasses(opts, 'showcase');\n const cardClass = buildInnerClasses(opts, 'dgmo-card');\n\n const captionHtml = title\n ? Wrapper === 'figure'\n ? `<figcaption class=\"dgmo-caption\">${escapeHtml(title)}</figcaption>`\n : `<div class=\"dgmo-caption\">${escapeHtml(title)}</div>`\n : '';\n\n const sourceHtml = opts.showSource ? renderSource(source) : '';\n\n const openButton =\n opts.showOpenInEditor && editorUrl\n ? `<a href=\"${escapeAttr(editorUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"dgmo-toolbar-btn dgmo-open\" aria-label=\"Open in online editor\" title=\"Open in online editor\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M9.5 2.5h4v4\"/>\n <path d=\"M13.5 2.5 7 9\"/>\n <path d=\"M12.5 9.5v3a1 1 0 0 1-1 1h-8a1 1 0 0 1-1-1v-8a1 1 0 0 1 1-1h3\"/>\n </svg>\n </a>`\n : '';\n\n const copyButton = opts.showCopy\n ? `<button type=\"button\" class=\"dgmo-toolbar-btn dgmo-copy\" aria-label=\"Copy to clipboard\" title=\"Copy to clipboard\" data-dgmo-source=\"${escapeAttr(source)}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8\" rx=\"1.5\"/>\n <path d=\"M10.5 5.5V3a1.5 1.5 0 0 0-1.5-1.5H3A1.5 1.5 0 0 0 1.5 3v6A1.5 1.5 0 0 0 3 10.5h2.5\"/>\n </svg>\n </button>`\n : '';\n\n const toolbarActions =\n openButton || copyButton\n ? `<div class=\"dgmo-toolbar-actions\">${openButton}${copyButton}</div>`\n : '';\n\n const toolbar = opts.showSource\n ? `<div class=\"dgmo-toolbar\"><span class=\"dgmo-toolbar-label\">dgmo</span>${toolbarActions}</div>`\n : '';\n\n return (\n `<${Wrapper} class=\"${escapeAttr(wrapperClass)}\">` +\n captionHtml +\n `<div class=\"${escapeAttr(cardClass)}\">` +\n (opts.showSource\n ? `<div class=\"dgmo-source-wrap\">${toolbar}<div class=\"dgmo-source-inner\">${sourceHtml}</div></div>`\n : '') +\n `<div class=\"${escapeAttr(buildInnerClasses(opts, 'dgmo-light'))}\">${lightSvg}</div>` +\n `<div class=\"${escapeAttr(buildInnerClasses(opts, 'dgmo-dark'))}\">${darkSvg}</div>` +\n `</div>` +\n `</${Wrapper}>`\n );\n}\n\nfunction renderSource(source: string): string {\n const tokens = highlightDgmo(source);\n const inner = tokens\n .map(t => {\n const styles = NORD_ROLE_STYLES[t.role];\n const text = escapeHtml(t.text);\n if (!styles || Object.keys(styles).length === 0) return text;\n const styleStr = Object.entries(styles)\n .map(\n ([k, v]) => `${k.replace(/[A-Z]/g, m => '-' + m.toLowerCase())}:${v}`\n )\n .join(';');\n return `<span style=\"${escapeAttr(styleStr)}\">${text}</span>`;\n })\n .join('');\n // NOTE: We deliberately use <pre><span> rather than <pre><code> here. Astro's\n // Shiki rehype plugin (and Docusaurus's MDX pipeline) walk the hast and\n // post-process any <pre><code> pair (even ones we emit from a remark plugin\n // via raw HTML), which clobbers our pre-rendered highlight spans with a\n // plaintext listing. Using a <span> as the inner element bypasses the\n // matcher while preserving preformatted-text semantics on the outer <pre>.\n return `<pre class=\"dgmo-pre\"><span class=\"dgmo-code\">${inner}</span></pre>`;\n}\n","export type Mode = 'diagram' | 'showcase';\n\nexport type Theme = 'light' | 'dark' | 'transparent';\n\n/**\n * Framework-agnostic options for `remarkDgmo` / `renderDgmoBlock`.\n *\n * Wrapper packages (`astro-dgmo`, `docusaurus-plugin-dgmo`) re-export this\n * shape under their own conventional names (`DgmoIntegrationOptions`,\n * `DocusaurusDgmoOptions`).\n */\nexport interface DgmoOptions {\n /**\n * Output mode for `dgmo` fenced blocks.\n * - `diagram` (default): render the SVG only, in a `<figure>`.\n * - `showcase`: render syntax-highlighted source + SVG + copy + open-in-editor.\n *\n * Override per-block via the fence info string: ```dgmo showcase\n */\n mode?: Mode;\n\n /** Default palette name. Default: `nord`. */\n palette?: string;\n\n /**\n * Default theme (`light` | `dark` | `transparent`). Default: `dark`.\n *\n * NOTE: under the default `colorMode: 'auto'`, this option is unreachable —\n * dual-render emits both light and dark SVGs regardless. `theme` is consulted\n * only when `colorMode` is explicitly set to `'light'` or `'dark'`.\n */\n theme?: Theme;\n\n /**\n * Color-mode strategy for emitted SVG(s). Default: `auto`.\n *\n * - `auto` — render every block twice (light + dark palettes) and wrap each\n * SVG in a `<div class=\"dgmo-light\">` / `<div class=\"dgmo-dark\">` so the\n * shipped CSS can flip visibility based on the host site's color-mode\n * signal (`[data-theme=\"dark\"]` by default).\n * - `light` / `dark` — single-render with the matching theme. Halves the\n * emitted SVG bytes; recommended only for single-mode sites.\n */\n colorMode?: 'auto' | 'light' | 'dark';\n\n /**\n * Show source code above the diagram. Defaults to `true` in showcase mode,\n * `false` in diagram mode.\n */\n showSource?: boolean;\n\n /**\n * Show a copy-to-clipboard button. Defaults to `true` in showcase mode,\n * `false` in diagram mode.\n */\n showCopy?: boolean;\n\n /**\n * Show an \"Open in online editor\" link. Defaults to `true` in showcase mode,\n * `false` in diagram mode.\n */\n showOpenInEditor?: boolean;\n\n /**\n * Base URL for the \"Open in editor\" link. Default: `https://online.diagrammo.app`.\n * The plugin appends `?dgmo=...` (compressed source) to the base.\n */\n editorBaseUrl?: string;\n\n /**\n * Wrapper element. Default: `figure`.\n */\n wrapper?: 'figure' | 'div';\n\n /**\n * Class added to the outer wrapper. Defaults to `dgmo`.\n * Useful as a styling hook.\n */\n className?: string;\n\n /**\n * Additional class names appended to every emitted wrapper's `class`\n * attribute. Used by `astro-dgmo` v0.3.0 to emit both the new `dgmo-*` class\n * names and the legacy `astro-dgmo-*` ones for one minor cycle of backward\n * compatibility. Default: `[]`.\n */\n legacyClassNames?: string[];\n}\n\nexport type ResolvedOptions = Required<\n Omit<DgmoOptions, 'showSource' | 'showCopy' | 'showOpenInEditor'>\n> & {\n showSource: boolean;\n showCopy: boolean;\n showOpenInEditor: boolean;\n};\n\n/**\n * Apply defaults, including mode-dependent defaults for showSource/showCopy/showOpenInEditor.\n */\nexport function resolveOptions(opts: DgmoOptions = {}): ResolvedOptions {\n const mode: Mode = opts.mode ?? 'diagram';\n const showcase = mode === 'showcase';\n return {\n mode,\n palette: opts.palette ?? 'nord',\n theme: opts.theme ?? 'dark',\n colorMode: opts.colorMode ?? 'auto',\n showSource: opts.showSource ?? showcase,\n showCopy: opts.showCopy ?? showcase,\n showOpenInEditor: opts.showOpenInEditor ?? showcase,\n editorBaseUrl: opts.editorBaseUrl ?? 'https://online.diagrammo.app',\n wrapper: opts.wrapper ?? 'figure',\n className: opts.className ?? 'dgmo',\n legacyClassNames: opts.legacyClassNames ?? [],\n };\n}\n","import type { Mode, Theme } from './options.js';\n\n/**\n * Per-block options that can be set via the fence info string, e.g.\n *\n * ```dgmo showcase palette=catppuccin theme=light title=\"Login flow\"\n *\n * Tokens are space-separated. Boolean tokens are bare words (`showcase`,\n * `diagram`, `noSource`). Key=value pairs use `=`; values may be quoted with\n * double quotes to include spaces.\n */\nexport interface BlockOptions {\n mode?: Mode;\n palette?: string;\n theme?: Theme;\n colorMode?: 'auto' | 'light' | 'dark';\n showSource?: boolean;\n showCopy?: boolean;\n showOpenInEditor?: boolean;\n title?: string;\n}\n\nconst BARE_FLAGS: Record<string, Partial<BlockOptions>> = {\n diagram: { mode: 'diagram' },\n showcase: { mode: 'showcase' },\n noSource: { showSource: false },\n source: { showSource: true },\n noCopy: { showCopy: false },\n copy: { showCopy: true },\n noOpenInEditor: { showOpenInEditor: false },\n openInEditor: { showOpenInEditor: true },\n};\n\nconst VALID_THEMES = new Set<Theme>(['light', 'dark', 'transparent']);\nconst VALID_COLOR_MODES = new Set<'auto' | 'light' | 'dark'>([\n 'auto',\n 'light',\n 'dark',\n]);\n\n/**\n * Parse the meta string that follows ```dgmo on the fence line.\n * Robust to: empty, missing, malformed input.\n */\nexport function parseFenceMeta(meta: string | null | undefined): BlockOptions {\n if (!meta) return {};\n const out: BlockOptions = {};\n const tokens = tokenize(meta);\n for (const tok of tokens) {\n if (BARE_FLAGS[tok]) {\n Object.assign(out, BARE_FLAGS[tok]);\n continue;\n }\n const eq = tok.indexOf('=');\n if (eq < 0) continue;\n const key = tok.slice(0, eq).trim();\n const rawVal = tok.slice(eq + 1).trim();\n const val = unquote(rawVal);\n switch (key) {\n case 'palette':\n if (val) out.palette = val;\n break;\n case 'theme':\n if (VALID_THEMES.has(val as Theme)) out.theme = val as Theme;\n break;\n case 'colorMode':\n if (VALID_COLOR_MODES.has(val as 'auto' | 'light' | 'dark')) {\n out.colorMode = val as 'auto' | 'light' | 'dark';\n }\n break;\n case 'mode':\n if (val === 'diagram' || val === 'showcase') out.mode = val;\n break;\n case 'showSource':\n out.showSource = parseBool(val);\n break;\n case 'showCopy':\n out.showCopy = parseBool(val);\n break;\n case 'showOpenInEditor':\n out.showOpenInEditor = parseBool(val);\n break;\n case 'title':\n if (val) out.title = val;\n break;\n }\n }\n return out;\n}\n\nfunction parseBool(s: string): boolean {\n return s === 'true' || s === '1' || s === 'yes';\n}\n\nfunction unquote(s: string): string {\n if (s.length >= 2 && s.startsWith('\"') && s.endsWith('\"')) {\n return s.slice(1, -1);\n }\n return s;\n}\n\n/**\n * Split on whitespace, respecting double-quoted segments so a value like\n * `title=\"Login flow\"` survives intact.\n */\nfunction tokenize(input: string): string[] {\n const out: string[] = [];\n let buf = '';\n let inQuotes = false;\n for (let i = 0; i < input.length; i++) {\n const ch = input[i];\n if (ch === '\"') {\n inQuotes = !inQuotes;\n buf += ch;\n continue;\n }\n if (!inQuotes && /\\s/.test(ch)) {\n if (buf) {\n out.push(buf);\n buf = '';\n }\n continue;\n }\n buf += ch;\n }\n if (buf) out.push(buf);\n return out;\n}\n","/**\n * Normalize an SVG produced by `@diagrammo/dgmo` for inline embedding:\n *\n * - Compute a tight content bounding box from element coordinates and\n * set the root `viewBox` to bbox+padding. Replaces the JS-side\n * `getBBox()` step that can't measure dual-rendered SVGs hidden by\n * color-mode CSS.\n * - Ensure the root `<svg>` has a `viewBox` so it scales responsively.\n * - Strip fixed `width=\"N\"` / `height=\"N\"` so CSS controls sizing.\n * - Remove any inline `background:` from the root style so the page\n * background shows through.\n */\nexport function normalizeSvg(input: string): string {\n let svg = input;\n const rootMatch = svg.match(/<svg[^>]*>/);\n const rootTag = rootMatch?.[0] ?? '';\n if (rootTag && !rootTag.includes('viewBox')) {\n const wh = rootTag.match(/width=\"(\\d+)\"[^>]*height=\"(\\d+)\"/);\n if (wh) {\n svg = svg.replace(/<svg/, `<svg viewBox=\"0 0 ${wh[1]} ${wh[2]}\"`);\n }\n }\n\n // Tighten viewBox to the content bbox. dgmo emits diagrams within a\n // fixed-size canvas (e.g. viewBox=\"0 0 1200 250\"), with content often\n // occupying only a fraction of that canvas. Tightening here means\n // dual-rendered SVGs render at the same scale whether visible or not.\n const tight = computeBBox(svg);\n if (tight && tight.width > 0 && tight.height > 0) {\n const pad = 16;\n const vb = `${tight.x - pad} ${tight.y - pad} ${tight.width + pad * 2} ${tight.height + pad * 2}`;\n svg = svg.replace(/(<svg[^>]*?)viewBox=\"[^\"]*\"/, `$1viewBox=\"${vb}\"`);\n }\n\n svg = svg.replace(/(<svg[^>]*?) width=\"[^\"]*\"/g, '$1');\n svg = svg.replace(/(<svg[^>]*?) height=\"[^\"]*\"/g, '$1');\n svg = svg.replace(/(<svg[^>]*?style=\"[^\"]*?)background:[^;\"]*;?\\s*/g, '$1');\n svg = svg.replace(/<svg\\s{2,}/g, '<svg ');\n return svg;\n}\n\n/**\n * Compute an approximate content bounding box from raw element coordinates.\n *\n * This is a regex walk, not a real SVG layout — it ignores `transform`\n * attributes and uses a heuristic for text widths. dgmo's renderer mostly\n * uses absolute coordinates within its viewBox, so the approximation is\n * close enough that the rendered output reliably fills the visible area.\n */\nfunction computeBBox(\n svg: string\n): { x: number; y: number; width: number; height: number } | null {\n const xs: number[] = [];\n const ys: number[] = [];\n\n function push(x: number, y: number): void {\n if (Number.isFinite(x) && Number.isFinite(y)) {\n xs.push(x);\n ys.push(y);\n }\n }\n\n function attr(tag: string, name: string): number | null {\n const m = tag.match(new RegExp(`\\\\b${name}=\"([^\"]*)\"`));\n if (!m) return null;\n const n = parseFloat(m[1]);\n return Number.isFinite(n) ? n : null;\n }\n\n // <rect x y width height>\n for (const m of svg.matchAll(/<rect\\b[^>]*?\\/?>/g)) {\n const tag = m[0];\n const x = attr(tag, 'x');\n const y = attr(tag, 'y');\n const w = attr(tag, 'width');\n const h = attr(tag, 'height');\n if (x !== null && y !== null && w !== null && h !== null) {\n push(x, y);\n push(x + w, y + h);\n }\n }\n\n // <line x1 y1 x2 y2>\n for (const m of svg.matchAll(/<line\\b[^>]*?\\/?>/g)) {\n const tag = m[0];\n const x1 = attr(tag, 'x1');\n const y1 = attr(tag, 'y1');\n const x2 = attr(tag, 'x2');\n const y2 = attr(tag, 'y2');\n if (x1 !== null && y1 !== null && x2 !== null && y2 !== null) {\n push(x1, y1);\n push(x2, y2);\n }\n }\n\n // <circle cx cy r>\n for (const m of svg.matchAll(/<circle\\b[^>]*?\\/?>/g)) {\n const tag = m[0];\n const cx = attr(tag, 'cx');\n const cy = attr(tag, 'cy');\n const r = attr(tag, 'r');\n if (cx !== null && cy !== null && r !== null) {\n push(cx - r, cy - r);\n push(cx + r, cy + r);\n }\n }\n\n // <ellipse cx cy rx ry>\n for (const m of svg.matchAll(/<ellipse\\b[^>]*?\\/?>/g)) {\n const tag = m[0];\n const cx = attr(tag, 'cx');\n const cy = attr(tag, 'cy');\n const rx = attr(tag, 'rx');\n const ry = attr(tag, 'ry');\n if (cx !== null && cy !== null && rx !== null && ry !== null) {\n push(cx - rx, cy - ry);\n push(cx + rx, cy + ry);\n }\n }\n\n // <text x y>some content</text>\n // Approximate width: text content length × an empirical font width factor.\n // dgmo uses Inter ~14px by default; ~7-8px per character is a usable\n // rough estimate that won't drastically under- or over-count.\n for (const m of svg.matchAll(/<text\\b([^>]*?)>([\\s\\S]*?)<\\/text>/g)) {\n const tag = `<text${m[1]}>`;\n const text = m[2].replace(/<[^>]+>/g, ''); // strip inner tags (tspan, etc.)\n const x = attr(tag, 'x');\n const y = attr(tag, 'y');\n if (x !== null && y !== null) {\n const w = text.length * 7;\n // text-anchor may be start/middle/end; assume worst case (middle) for span\n push(x - w / 2, y - 14);\n push(x + w / 2, y + 4);\n }\n }\n\n // <path d=\"...\"> — pull every coordinate pair out of the d attribute.\n for (const m of svg.matchAll(/<path\\b[^>]*?\\bd=\"([^\"]+)\"/g)) {\n const d = m[1];\n const nums = d.match(/-?\\d+(?:\\.\\d+)?/g);\n if (!nums) continue;\n for (let i = 0; i + 1 < nums.length; i += 2) {\n push(parseFloat(nums[i]), parseFloat(nums[i + 1]));\n }\n }\n\n // <polygon points=\"x,y x,y ...\"> and <polyline>\n for (const m of svg.matchAll(/<(?:polygon|polyline)\\b[^>]*?\\bpoints=\"([^\"]+)\"/g)) {\n const nums = m[1].match(/-?\\d+(?:\\.\\d+)?/g);\n if (!nums) continue;\n for (let i = 0; i + 1 < nums.length; i += 2) {\n push(parseFloat(nums[i]), parseFloat(nums[i + 1]));\n }\n }\n\n if (xs.length === 0 || ys.length === 0) return null;\n\n const minX = Math.min(...xs);\n const maxX = Math.max(...xs);\n const minY = Math.min(...ys);\n const maxY = Math.max(...ys);\n\n return {\n x: minX,\n y: minY,\n width: maxX - minX,\n height: maxY - minY,\n };\n}\n","const HTML_ENTITIES: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;',\n};\n\nexport function escapeHtml(s: string): string {\n return s.replace(/[&<>\"']/g, ch => HTML_ENTITIES[ch]);\n}\n\nexport function escapeAttr(s: string): string {\n return s.replace(/[&<>\"']/g, ch => HTML_ENTITIES[ch]);\n}\n"],"mappings":"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","names":["editorUrl","html"]}