@blaaiz/docs-core 0.1.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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +103 -0
  3. package/dist/chunk-3ZX4WIE3.js +2984 -0
  4. package/dist/chunk-3ZX4WIE3.js.map +1 -0
  5. package/dist/chunk-JCYR6RPE.js +31 -0
  6. package/dist/chunk-JCYR6RPE.js.map +1 -0
  7. package/dist/chunk-ZKOOKLZ3.js +124 -0
  8. package/dist/chunk-ZKOOKLZ3.js.map +1 -0
  9. package/dist/cli.js +534 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/generator.cjs +508 -0
  12. package/dist/generator.cjs.map +1 -0
  13. package/dist/generator.d.cts +122 -0
  14. package/dist/generator.d.ts +122 -0
  15. package/dist/generator.js +177 -0
  16. package/dist/generator.js.map +1 -0
  17. package/dist/index.cjs +3024 -0
  18. package/dist/index.cjs.map +1 -0
  19. package/dist/index.d.cts +1182 -0
  20. package/dist/index.d.ts +1182 -0
  21. package/dist/index.js +3 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/navigation-CGqFIPlP.d.cts +498 -0
  24. package/dist/navigation-CGqFIPlP.d.ts +498 -0
  25. package/dist/openapi-types-CJ6p5Cux.d.cts +78 -0
  26. package/dist/openapi-types-CJ6p5Cux.d.ts +78 -0
  27. package/dist/ui/api-try-it.cjs +654 -0
  28. package/dist/ui/api-try-it.cjs.map +1 -0
  29. package/dist/ui/api-try-it.d.cts +78 -0
  30. package/dist/ui/api-try-it.d.ts +78 -0
  31. package/dist/ui/api-try-it.js +509 -0
  32. package/dist/ui/api-try-it.js.map +1 -0
  33. package/dist/ui/ask-ai.cjs +810 -0
  34. package/dist/ui/ask-ai.cjs.map +1 -0
  35. package/dist/ui/ask-ai.d.cts +57 -0
  36. package/dist/ui/ask-ai.d.ts +57 -0
  37. package/dist/ui/ask-ai.js +808 -0
  38. package/dist/ui/ask-ai.js.map +1 -0
  39. package/dist/ui/copy-page.cjs +312 -0
  40. package/dist/ui/copy-page.cjs.map +1 -0
  41. package/dist/ui/copy-page.d.cts +33 -0
  42. package/dist/ui/copy-page.d.ts +33 -0
  43. package/dist/ui/copy-page.js +183 -0
  44. package/dist/ui/copy-page.js.map +1 -0
  45. package/dist/ui/mermaid.cjs +363 -0
  46. package/dist/ui/mermaid.cjs.map +1 -0
  47. package/dist/ui/mermaid.d.cts +13 -0
  48. package/dist/ui/mermaid.d.ts +13 -0
  49. package/dist/ui/mermaid.js +361 -0
  50. package/dist/ui/mermaid.js.map +1 -0
  51. package/dist/ui.cjs +661 -0
  52. package/dist/ui.cjs.map +1 -0
  53. package/dist/ui.d.cts +428 -0
  54. package/dist/ui.d.ts +428 -0
  55. package/dist/ui.js +537 -0
  56. package/dist/ui.js.map +1 -0
  57. package/package.json +145 -0
  58. package/patches/fumadocs-openapi.patch +173 -0
  59. package/skills/AGENTS-section.md +36 -0
  60. package/skills/SKILL.md +363 -0
  61. package/styles/api-reference.css +1417 -0
  62. package/styles/ask-ai.css +563 -0
  63. package/styles/auth.css +462 -0
  64. package/styles/docs.css +247 -0
  65. package/styles/home.css +376 -0
  66. package/templates/init/content/docs/index.mdx.tmpl +52 -0
  67. package/templates/init/content/docs/meta.json.tmpl +3 -0
  68. package/templates/init/content/docs.json.tmpl +12 -0
  69. package/templates/init/content/nav.json.tmpl +7 -0
  70. package/templates/init/docs.config.ts.tmpl +36 -0
  71. package/templates/init/env.example.tmpl +15 -0
@@ -0,0 +1,183 @@
1
+ 'use client';
2
+ import { copyToClipboard } from '../chunk-JCYR6RPE.js';
3
+ import { strokeIcon } from '../chunk-ZKOOKLZ3.js';
4
+ import { useState, useRef, useEffect } from 'react';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ function Icon({ name, size = 15 }) {
8
+ return strokeIcon(name, { size, strokeWidth: name === "check" ? 2.5 : 1.9, rounded: true });
9
+ }
10
+ var styles = {
11
+ root: { position: "relative", flexShrink: 0, fontSize: 13, lineHeight: 1.2 },
12
+ split: {
13
+ display: "inline-flex",
14
+ alignItems: "stretch",
15
+ border: "1px solid var(--color-fd-border)",
16
+ borderRadius: 8,
17
+ background: "var(--color-fd-card)",
18
+ overflow: "hidden"
19
+ },
20
+ main: {
21
+ display: "inline-flex",
22
+ alignItems: "center",
23
+ gap: 8,
24
+ padding: "9px 15px",
25
+ background: "transparent",
26
+ color: "var(--color-fd-foreground)",
27
+ font: "inherit",
28
+ fontWeight: 500,
29
+ cursor: "pointer",
30
+ border: "none"
31
+ },
32
+ caret: {
33
+ display: "inline-flex",
34
+ alignItems: "center",
35
+ padding: "9px 11px",
36
+ background: "transparent",
37
+ color: "var(--color-fd-muted-foreground)",
38
+ borderLeft: "1px solid var(--color-fd-border)",
39
+ cursor: "pointer"
40
+ },
41
+ menu: {
42
+ position: "absolute",
43
+ top: "calc(100% + 6px)",
44
+ right: 0,
45
+ zIndex: 40,
46
+ width: 268,
47
+ padding: 6,
48
+ border: "1px solid var(--color-fd-border)",
49
+ borderRadius: 12,
50
+ background: "var(--color-fd-popover, var(--color-fd-card))",
51
+ boxShadow: "0 4px 6px -2px rgba(0,0,0,0.05), 0 12px 28px -6px rgba(0,0,0,0.18)"
52
+ },
53
+ item: {
54
+ display: "flex",
55
+ alignItems: "flex-start",
56
+ gap: 10,
57
+ width: "100%",
58
+ padding: "9px 10px",
59
+ borderRadius: 8,
60
+ background: "transparent",
61
+ border: "none",
62
+ textAlign: "left",
63
+ textDecoration: "none",
64
+ color: "var(--color-fd-foreground)",
65
+ font: "inherit",
66
+ cursor: "pointer"
67
+ },
68
+ muted: { color: "var(--color-fd-muted-foreground)" },
69
+ itemText: { display: "flex", flexDirection: "column", gap: 2, minWidth: 0 },
70
+ itemSub: { fontSize: 12, color: "var(--color-fd-muted-foreground)" }
71
+ };
72
+ var HOVER_BG = "color-mix(in oklab, var(--color-fd-primary) 9%, transparent)";
73
+ function hoverProps(base) {
74
+ return {
75
+ onMouseEnter: (event) => {
76
+ event.currentTarget.style.background = HOVER_BG;
77
+ },
78
+ onMouseLeave: (event) => {
79
+ event.currentTarget.style.background = base.background ?? "transparent";
80
+ }
81
+ };
82
+ }
83
+ function CopyPageButton({ markdown, viewUrl }) {
84
+ const [open, setOpen] = useState(false);
85
+ const [copied, setCopied] = useState(false);
86
+ const ref = useRef(null);
87
+ useEffect(() => {
88
+ if (!open) {
89
+ return;
90
+ }
91
+ const onPointerDown = (event) => {
92
+ if (ref.current && !ref.current.contains(event.target)) {
93
+ setOpen(false);
94
+ }
95
+ };
96
+ document.addEventListener("mousedown", onPointerDown);
97
+ return () => {
98
+ document.removeEventListener("mousedown", onPointerDown);
99
+ };
100
+ }, [open]);
101
+ const copy = async () => {
102
+ if (await copyToClipboard(markdown)) {
103
+ setCopied(true);
104
+ setTimeout(() => {
105
+ setCopied(false);
106
+ }, 1600);
107
+ }
108
+ setOpen(false);
109
+ };
110
+ return /* @__PURE__ */ jsxs("div", { ref, style: styles.root, children: [
111
+ /* @__PURE__ */ jsxs("div", { style: styles.split, children: [
112
+ /* @__PURE__ */ jsxs(
113
+ "button",
114
+ {
115
+ type: "button",
116
+ style: styles.main,
117
+ onClick: () => void copy(),
118
+ ...hoverProps(styles.main),
119
+ children: [
120
+ /* @__PURE__ */ jsx("span", { style: styles.muted, children: /* @__PURE__ */ jsx(Icon, { name: copied ? "check" : "copy" }) }),
121
+ copied ? "Copied" : "Copy page"
122
+ ]
123
+ }
124
+ ),
125
+ /* @__PURE__ */ jsx(
126
+ "button",
127
+ {
128
+ type: "button",
129
+ style: styles.caret,
130
+ "aria-label": "More options",
131
+ "aria-expanded": open,
132
+ onClick: () => {
133
+ setOpen((value) => !value);
134
+ },
135
+ ...hoverProps(styles.caret),
136
+ children: /* @__PURE__ */ jsx(Icon, { name: "chevronDown", size: 14 })
137
+ }
138
+ )
139
+ ] }),
140
+ open ? /* @__PURE__ */ jsxs("div", { style: styles.menu, role: "menu", children: [
141
+ /* @__PURE__ */ jsxs(
142
+ "button",
143
+ {
144
+ type: "button",
145
+ style: styles.item,
146
+ onClick: () => void copy(),
147
+ ...hoverProps(styles.item),
148
+ children: [
149
+ /* @__PURE__ */ jsx("span", { style: { ...styles.muted, marginTop: 1 }, children: /* @__PURE__ */ jsx(Icon, { name: "copy", size: 16 }) }),
150
+ /* @__PURE__ */ jsxs("span", { style: styles.itemText, children: [
151
+ /* @__PURE__ */ jsx("b", { style: { fontWeight: 600 }, children: "Copy page" }),
152
+ /* @__PURE__ */ jsx("small", { style: styles.itemSub, children: "Copy page as Markdown for LLMs" })
153
+ ] })
154
+ ]
155
+ }
156
+ ),
157
+ /* @__PURE__ */ jsxs(
158
+ "a",
159
+ {
160
+ style: styles.item,
161
+ href: viewUrl,
162
+ target: "_blank",
163
+ rel: "noreferrer",
164
+ onClick: () => {
165
+ setOpen(false);
166
+ },
167
+ ...hoverProps(styles.item),
168
+ children: [
169
+ /* @__PURE__ */ jsx("span", { style: { ...styles.muted, marginTop: 1 }, children: /* @__PURE__ */ jsx(Icon, { name: "markdown", size: 16 }) }),
170
+ /* @__PURE__ */ jsxs("span", { style: styles.itemText, children: [
171
+ /* @__PURE__ */ jsx("b", { style: { fontWeight: 600 }, children: "View as Markdown \u2197" }),
172
+ /* @__PURE__ */ jsx("small", { style: styles.itemSub, children: "View this page as plain text" })
173
+ ] })
174
+ ]
175
+ }
176
+ )
177
+ ] }) : null
178
+ ] });
179
+ }
180
+
181
+ export { CopyPageButton };
182
+ //# sourceMappingURL=copy-page.js.map
183
+ //# sourceMappingURL=copy-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ui/copy-page.tsx"],"names":[],"mappings":"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","file":"copy-page.js","sourcesContent":["'use client';\n\nimport { useEffect, useRef, useState, type CSSProperties } from 'react';\n\nimport { copyToClipboard } from './clipboard.js';\nimport { strokeIcon } from './icons.js';\n\n/**\n * The \"Copy page\" control — a split button with a dropdown, matching Mintlify's\n * LLM-friendly page action. The primary button copies the page's Markdown to\n * the clipboard; the dropdown adds a \"View as Markdown\" link.\n *\n * Self-contained: it styles itself with inline styles keyed to the framework's\n * `--color-fd-*` theme variables, so it inherits the site's palette with no\n * extra stylesheet. This is the framework's one client component.\n *\n * @packageDocumentation\n */\n\n/**\n * Props for {@link CopyPageButton}.\n *\n * @public\n */\nexport interface CopyPageButtonProps {\n /** The page rendered as Markdown, copied to the clipboard on click. */\n readonly markdown: string;\n /** URL that serves the same page as plain Markdown (opened in a new tab). */\n readonly viewUrl: string;\n}\n\n/** The four glyphs this control draws, from the framework's shared set. */\ntype IconName = 'copy' | 'check' | 'chevronDown' | 'markdown';\n\nfunction Icon({ name, size = 15 }: { name: IconName; size?: number }) {\n // The check mark is drawn heavier so it reads at 15px.\n return strokeIcon(name, { size, strokeWidth: name === 'check' ? 2.5 : 1.9, rounded: true });\n}\n\nconst styles = {\n root: { position: 'relative', flexShrink: 0, fontSize: 13, lineHeight: 1.2 } as CSSProperties,\n split: {\n display: 'inline-flex',\n alignItems: 'stretch',\n border: '1px solid var(--color-fd-border)',\n borderRadius: 8,\n background: 'var(--color-fd-card)',\n overflow: 'hidden',\n } as CSSProperties,\n main: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 8,\n padding: '9px 15px',\n background: 'transparent',\n color: 'var(--color-fd-foreground)',\n font: 'inherit',\n fontWeight: 500,\n cursor: 'pointer',\n border: 'none',\n } as CSSProperties,\n caret: {\n display: 'inline-flex',\n alignItems: 'center',\n padding: '9px 11px',\n background: 'transparent',\n color: 'var(--color-fd-muted-foreground)',\n borderLeft: '1px solid var(--color-fd-border)',\n cursor: 'pointer',\n } as CSSProperties,\n menu: {\n position: 'absolute',\n top: 'calc(100% + 6px)',\n right: 0,\n zIndex: 40,\n width: 268,\n padding: 6,\n border: '1px solid var(--color-fd-border)',\n borderRadius: 12,\n background: 'var(--color-fd-popover, var(--color-fd-card))',\n boxShadow: '0 4px 6px -2px rgba(0,0,0,0.05), 0 12px 28px -6px rgba(0,0,0,0.18)',\n } as CSSProperties,\n item: {\n display: 'flex',\n alignItems: 'flex-start',\n gap: 10,\n width: '100%',\n padding: '9px 10px',\n borderRadius: 8,\n background: 'transparent',\n border: 'none',\n textAlign: 'left',\n textDecoration: 'none',\n color: 'var(--color-fd-foreground)',\n font: 'inherit',\n cursor: 'pointer',\n } as CSSProperties,\n muted: { color: 'var(--color-fd-muted-foreground)' } as CSSProperties,\n itemText: { display: 'flex', flexDirection: 'column', gap: 2, minWidth: 0 } as CSSProperties,\n itemSub: { fontSize: 12, color: 'var(--color-fd-muted-foreground)' } as CSSProperties,\n};\n\nconst HOVER_BG = 'color-mix(in oklab, var(--color-fd-primary) 9%, transparent)';\n\nfunction hoverProps(base: CSSProperties) {\n return {\n onMouseEnter: (event: { currentTarget: HTMLElement }) => {\n event.currentTarget.style.background = HOVER_BG;\n },\n onMouseLeave: (event: { currentTarget: HTMLElement }) => {\n event.currentTarget.style.background = (base.background as string) ?? 'transparent';\n },\n };\n}\n\n/**\n * The split \"Copy page\" button. Renders nothing structural of its own beyond a\n * relatively-positioned wrapper, so a site drops it beside the page title.\n *\n * @public\n */\nexport function CopyPageButton({ markdown, viewUrl }: CopyPageButtonProps) {\n const [open, setOpen] = useState(false);\n const [copied, setCopied] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!open) {\n return;\n }\n const onPointerDown = (event: MouseEvent) => {\n if (ref.current && !ref.current.contains(event.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener('mousedown', onPointerDown);\n return () => {\n document.removeEventListener('mousedown', onPointerDown);\n };\n }, [open]);\n\n const copy = async () => {\n // A refused clipboard leaves the label unchanged: no error, no false claim.\n if (await copyToClipboard(markdown)) {\n setCopied(true);\n setTimeout(() => {\n setCopied(false);\n }, 1600);\n }\n setOpen(false);\n };\n\n return (\n <div ref={ref} style={styles.root}>\n <div style={styles.split}>\n <button\n type=\"button\"\n style={styles.main}\n onClick={() => void copy()}\n {...hoverProps(styles.main)}\n >\n <span style={styles.muted}>\n <Icon name={copied ? 'check' : 'copy'} />\n </span>\n {copied ? 'Copied' : 'Copy page'}\n </button>\n <button\n type=\"button\"\n style={styles.caret}\n aria-label=\"More options\"\n aria-expanded={open}\n onClick={() => {\n setOpen((value) => !value);\n }}\n {...hoverProps(styles.caret)}\n >\n <Icon name=\"chevronDown\" size={14} />\n </button>\n </div>\n {open ? (\n <div style={styles.menu} role=\"menu\">\n <button\n type=\"button\"\n style={styles.item}\n onClick={() => void copy()}\n {...hoverProps(styles.item)}\n >\n <span style={{ ...styles.muted, marginTop: 1 }}>\n <Icon name=\"copy\" size={16} />\n </span>\n <span style={styles.itemText}>\n <b style={{ fontWeight: 600 }}>Copy page</b>\n <small style={styles.itemSub}>Copy page as Markdown for LLMs</small>\n </span>\n </button>\n <a\n style={styles.item}\n href={viewUrl}\n target=\"_blank\"\n rel=\"noreferrer\"\n onClick={() => {\n setOpen(false);\n }}\n {...hoverProps(styles.item)}\n >\n <span style={{ ...styles.muted, marginTop: 1 }}>\n <Icon name=\"markdown\" size={16} />\n </span>\n <span style={styles.itemText}>\n <b style={{ fontWeight: 600 }}>View as Markdown ↗</b>\n <small style={styles.itemSub}>View this page as plain text</small>\n </span>\n </a>\n </div>\n ) : null}\n </div>\n );\n}\n"]}
@@ -0,0 +1,363 @@
1
+ 'use client';
2
+ 'use strict';
3
+
4
+ var react = require('react');
5
+ var reactDom = require('react-dom');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ var MIN_SCALE = 0.4;
9
+ var MAX_SCALE = 8;
10
+ var MAX_FIT_SCALE = 2.5;
11
+ var FIT_PADDING = 0.9;
12
+ var IDENTITY = { scale: 1, x: 0, y: 0 };
13
+ function clamp(value, min, max) {
14
+ return Math.min(max, Math.max(min, value));
15
+ }
16
+ function isDarkTheme() {
17
+ return document.documentElement.classList.contains("dark");
18
+ }
19
+ function useMermaidSvg(chart) {
20
+ const rawId = react.useId().replace(/[^a-zA-Z0-9]/g, "");
21
+ const [svg, setSvg] = react.useState("");
22
+ const [dark, setDark] = react.useState(false);
23
+ react.useEffect(() => {
24
+ setDark(isDarkTheme());
25
+ const observer = new MutationObserver(() => {
26
+ setDark(isDarkTheme());
27
+ });
28
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ["class"] });
29
+ return () => {
30
+ observer.disconnect();
31
+ };
32
+ }, []);
33
+ react.useEffect(() => {
34
+ let active = true;
35
+ void (async () => {
36
+ const mermaid = (await import('mermaid')).default;
37
+ mermaid.initialize({
38
+ startOnLoad: false,
39
+ theme: dark ? "dark" : "neutral",
40
+ securityLevel: "loose",
41
+ fontFamily: "inherit",
42
+ themeVariables: { fontSize: "14px" }
43
+ });
44
+ try {
45
+ const result = await mermaid.render(`mmd-${rawId}`, chart);
46
+ if (active) {
47
+ setSvg(result.svg);
48
+ }
49
+ } catch {
50
+ if (active) {
51
+ setSvg("");
52
+ }
53
+ }
54
+ })();
55
+ return () => {
56
+ active = false;
57
+ };
58
+ }, [chart, dark, rawId]);
59
+ return svg;
60
+ }
61
+ var ICONS = {
62
+ zoomIn: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M11 8v6M8 11h6M21 21l-4.35-4.35M11 18a7 7 0 1 0 0-14 7 7 0 0 0 0 14Z" }),
63
+ zoomOut: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 11h6M21 21l-4.35-4.35M11 18a7 7 0 1 0 0-14 7 7 0 0 0 0 14Z" }),
64
+ reset: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 12a9 9 0 1 0 3-6.7L3 8m0-5v5h5" }),
65
+ expand: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3M3 16v3a2 2 0 0 0 2 2h3m8 0h3a2 2 0 0 0 2-2v-3" }),
66
+ close: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" })
67
+ };
68
+ function ControlButton({
69
+ label,
70
+ onClick,
71
+ children
72
+ }) {
73
+ return /* @__PURE__ */ jsxRuntime.jsx(
74
+ "button",
75
+ {
76
+ type: "button",
77
+ "aria-label": label,
78
+ onClick,
79
+ style: {
80
+ display: "inline-flex",
81
+ alignItems: "center",
82
+ justifyContent: "center",
83
+ width: 32,
84
+ height: 32,
85
+ padding: 0,
86
+ border: "1px solid var(--color-fd-border)",
87
+ borderRadius: 8,
88
+ background: "var(--color-fd-card)",
89
+ color: "var(--color-fd-muted-foreground)",
90
+ cursor: "pointer"
91
+ },
92
+ onMouseEnter: (event) => {
93
+ event.currentTarget.style.color = "var(--color-fd-foreground)";
94
+ event.currentTarget.style.background = "color-mix(in oklab, var(--color-fd-primary) 10%, var(--color-fd-card))";
95
+ },
96
+ onMouseLeave: (event) => {
97
+ event.currentTarget.style.color = "var(--color-fd-muted-foreground)";
98
+ event.currentTarget.style.background = "var(--color-fd-card)";
99
+ },
100
+ children: /* @__PURE__ */ jsxRuntime.jsx(
101
+ "svg",
102
+ {
103
+ width: 16,
104
+ height: 16,
105
+ viewBox: "0 0 24 24",
106
+ fill: "none",
107
+ stroke: "currentColor",
108
+ strokeWidth: 1.8,
109
+ strokeLinecap: "round",
110
+ strokeLinejoin: "round",
111
+ "aria-hidden": "true",
112
+ children
113
+ }
114
+ )
115
+ }
116
+ );
117
+ }
118
+ function Viewer({ svg, fullscreen, onToggleFullscreen }) {
119
+ const stageRef = react.useRef(null);
120
+ const contentRef = react.useRef(null);
121
+ const [view, setView] = react.useState(IDENTITY);
122
+ const drag = react.useRef(null);
123
+ const zoomAt = react.useCallback((clientX, clientY, factor) => {
124
+ const stage = stageRef.current;
125
+ if (!stage) {
126
+ return;
127
+ }
128
+ const rect = stage.getBoundingClientRect();
129
+ const px = clientX - rect.left;
130
+ const py = clientY - rect.top;
131
+ setView((current) => {
132
+ const scale = clamp(current.scale * factor, MIN_SCALE, MAX_SCALE);
133
+ const ratio = scale / current.scale;
134
+ return { scale, x: px - (px - current.x) * ratio, y: py - (py - current.y) * ratio };
135
+ });
136
+ }, []);
137
+ const zoomFromCenter = react.useCallback(
138
+ (factor) => {
139
+ const stage = stageRef.current;
140
+ if (!stage) {
141
+ return;
142
+ }
143
+ const rect = stage.getBoundingClientRect();
144
+ zoomAt(rect.left + rect.width / 2, rect.top + rect.height / 2, factor);
145
+ },
146
+ [zoomAt]
147
+ );
148
+ const fit = react.useCallback(() => {
149
+ const stage = stageRef.current;
150
+ const content = contentRef.current;
151
+ if (!stage || !content) {
152
+ return;
153
+ }
154
+ const w = content.offsetWidth;
155
+ const h = content.offsetHeight;
156
+ if (w === 0 || h === 0) {
157
+ return;
158
+ }
159
+ const sw = stage.clientWidth;
160
+ const sh = stage.clientHeight;
161
+ const scale = clamp(Math.min(sw / w, sh / h) * FIT_PADDING, MIN_SCALE, MAX_FIT_SCALE);
162
+ setView({ scale, x: (sw - w * scale) / 2, y: (sh - h * scale) / 2 });
163
+ }, []);
164
+ react.useEffect(() => {
165
+ const stage = stageRef.current;
166
+ if (!stage) {
167
+ return;
168
+ }
169
+ const onWheel = (event) => {
170
+ event.preventDefault();
171
+ zoomAt(event.clientX, event.clientY, event.deltaY < 0 ? 1.12 : 1 / 1.12);
172
+ };
173
+ stage.addEventListener("wheel", onWheel, { passive: false });
174
+ return () => {
175
+ stage.removeEventListener("wheel", onWheel);
176
+ };
177
+ }, [zoomAt]);
178
+ react.useEffect(() => {
179
+ fit();
180
+ }, [svg, fullscreen, fit]);
181
+ const onPointerDown = (event) => {
182
+ drag.current = { x: event.clientX, y: event.clientY };
183
+ event.currentTarget.setPointerCapture(event.pointerId);
184
+ };
185
+ const onPointerMove = (event) => {
186
+ if (!drag.current) {
187
+ return;
188
+ }
189
+ const dx = event.clientX - drag.current.x;
190
+ const dy = event.clientY - drag.current.y;
191
+ drag.current = { x: event.clientX, y: event.clientY };
192
+ setView((current) => ({ ...current, x: current.x + dx, y: current.y + dy }));
193
+ };
194
+ const onPointerUp = (event) => {
195
+ drag.current = null;
196
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) {
197
+ event.currentTarget.releasePointerCapture(event.pointerId);
198
+ }
199
+ };
200
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", width: "100%", height: fullscreen ? "100%" : 420 }, children: [
201
+ /* @__PURE__ */ jsxRuntime.jsx(
202
+ "div",
203
+ {
204
+ ref: stageRef,
205
+ onPointerDown,
206
+ onPointerMove,
207
+ onPointerUp,
208
+ onPointerLeave: onPointerUp,
209
+ style: {
210
+ position: "absolute",
211
+ inset: 0,
212
+ overflow: "hidden",
213
+ cursor: "grab",
214
+ touchAction: "none"
215
+ },
216
+ children: /* @__PURE__ */ jsxRuntime.jsx(
217
+ "div",
218
+ {
219
+ ref: contentRef,
220
+ style: {
221
+ transform: `translate(${String(view.x)}px, ${String(view.y)}px) scale(${String(view.scale)})`,
222
+ transformOrigin: "0 0",
223
+ display: "inline-block",
224
+ willChange: "transform"
225
+ },
226
+ dangerouslySetInnerHTML: { __html: svg }
227
+ }
228
+ )
229
+ }
230
+ ),
231
+ /* @__PURE__ */ jsxRuntime.jsxs(
232
+ "div",
233
+ {
234
+ style: {
235
+ position: "absolute",
236
+ bottom: 12,
237
+ right: 12,
238
+ display: "flex",
239
+ flexDirection: "column",
240
+ gap: 6
241
+ },
242
+ children: [
243
+ /* @__PURE__ */ jsxRuntime.jsx(
244
+ ControlButton,
245
+ {
246
+ label: fullscreen ? "Exit full screen" : "Full screen",
247
+ onClick: onToggleFullscreen,
248
+ children: fullscreen ? ICONS.close : ICONS.expand
249
+ }
250
+ ),
251
+ /* @__PURE__ */ jsxRuntime.jsx(
252
+ ControlButton,
253
+ {
254
+ label: "Zoom in",
255
+ onClick: () => {
256
+ zoomFromCenter(1.3);
257
+ },
258
+ children: ICONS.zoomIn
259
+ }
260
+ ),
261
+ /* @__PURE__ */ jsxRuntime.jsx(
262
+ ControlButton,
263
+ {
264
+ label: "Zoom out",
265
+ onClick: () => {
266
+ zoomFromCenter(1 / 1.3);
267
+ },
268
+ children: ICONS.zoomOut
269
+ }
270
+ ),
271
+ /* @__PURE__ */ jsxRuntime.jsx(ControlButton, { label: "Reset view", onClick: fit, children: ICONS.reset })
272
+ ]
273
+ }
274
+ )
275
+ ] });
276
+ }
277
+ function Mermaid({ chart }) {
278
+ const svg = useMermaidSvg(chart);
279
+ const [full, setFull] = react.useState(false);
280
+ const [mounted, setMounted] = react.useState(false);
281
+ react.useEffect(() => {
282
+ setMounted(true);
283
+ }, []);
284
+ react.useEffect(() => {
285
+ if (!full) {
286
+ return;
287
+ }
288
+ const onKey = (event) => {
289
+ if (event.key === "Escape") {
290
+ setFull(false);
291
+ }
292
+ };
293
+ document.addEventListener("keydown", onKey);
294
+ return () => {
295
+ document.removeEventListener("keydown", onKey);
296
+ };
297
+ }, [full]);
298
+ if (svg === "") {
299
+ return null;
300
+ }
301
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { margin: "1.5rem 0", borderRadius: 12, overflow: "hidden" }, children: [
302
+ /* @__PURE__ */ jsxRuntime.jsx(
303
+ Viewer,
304
+ {
305
+ svg,
306
+ fullscreen: false,
307
+ onToggleFullscreen: () => {
308
+ setFull(true);
309
+ }
310
+ }
311
+ ),
312
+ mounted && full ? reactDom.createPortal(
313
+ /* @__PURE__ */ jsxRuntime.jsx(
314
+ "div",
315
+ {
316
+ onClick: (event) => {
317
+ if (event.target === event.currentTarget) {
318
+ setFull(false);
319
+ }
320
+ },
321
+ style: {
322
+ position: "fixed",
323
+ inset: 0,
324
+ zIndex: 9999,
325
+ background: "color-mix(in oklab, black 55%, transparent)",
326
+ backdropFilter: "blur(2px)"
327
+ },
328
+ children: /* @__PURE__ */ jsxRuntime.jsx(
329
+ "div",
330
+ {
331
+ style: {
332
+ position: "absolute",
333
+ inset: "clamp(20px, 3.5vw, 48px)",
334
+ borderRadius: 16,
335
+ border: "1px solid var(--color-fd-border)",
336
+ overflow: "hidden",
337
+ background: "var(--color-fd-background, #0a0a0b)",
338
+ backgroundImage: "radial-gradient(circle, color-mix(in oklab, var(--color-fd-muted-foreground) 22%, transparent) 1px, transparent 1px)",
339
+ backgroundSize: "22px 22px",
340
+ boxShadow: "0 24px 70px -12px rgba(0, 0, 0, 0.5)"
341
+ },
342
+ children: /* @__PURE__ */ jsxRuntime.jsx(
343
+ Viewer,
344
+ {
345
+ svg,
346
+ fullscreen: true,
347
+ onToggleFullscreen: () => {
348
+ setFull(false);
349
+ }
350
+ }
351
+ )
352
+ }
353
+ )
354
+ }
355
+ ),
356
+ document.body
357
+ ) : null
358
+ ] });
359
+ }
360
+
361
+ exports.Mermaid = Mermaid;
362
+ //# sourceMappingURL=mermaid.cjs.map
363
+ //# sourceMappingURL=mermaid.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ui/mermaid.tsx"],"names":["useId","useState","useEffect","jsx","useRef","useCallback","jsxs","createPortal"],"mappings":";;;;;;AA4BA,IAAM,SAAA,GAAY,GAAA;AAClB,IAAM,SAAA,GAAY,CAAA;AAClB,IAAM,aAAA,GAAgB,GAAA;AACtB,IAAM,WAAA,GAAc,GAAA;AAQpB,IAAM,WAAiB,EAAE,KAAA,EAAO,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAE9C,SAAS,KAAA,CAAM,KAAA,EAAe,GAAA,EAAa,GAAA,EAAqB;AAC9D,EAAA,OAAO,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,CAAC,CAAA;AAC3C;AAEA,SAAS,WAAA,GAAuB;AAC9B,EAAA,OAAO,QAAA,CAAS,eAAA,CAAgB,SAAA,CAAU,QAAA,CAAS,MAAM,CAAA;AAC3D;AAMA,SAAS,cAAc,KAAA,EAAuB;AAC5C,EAAA,MAAM,KAAA,GAAQA,WAAA,EAAM,CAAE,OAAA,CAAQ,iBAAiB,EAAE,CAAA;AACjD,EAAA,MAAM,CAAC,GAAA,EAAK,MAAM,CAAA,GAAIC,eAAS,EAAE,CAAA;AACjC,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIA,eAAS,KAAK,CAAA;AAEtC,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,OAAA,CAAQ,aAAa,CAAA;AACrB,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,MAAM;AAC1C,MAAA,OAAA,CAAQ,aAAa,CAAA;AAAA,IACvB,CAAC,CAAA;AACD,IAAA,QAAA,CAAS,OAAA,CAAQ,QAAA,CAAS,eAAA,EAAiB,EAAE,UAAA,EAAY,MAAM,eAAA,EAAiB,CAAC,OAAO,CAAA,EAAG,CAAA;AAC3F,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,UAAA,EAAW;AAAA,IACtB,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,MAAA,GAAS,IAAA;AACb,IAAA,KAAA,CAAM,YAAY;AAChB,MAAA,MAAM,OAAA,GAAA,CAAW,MAAM,OAAO,SAAS,CAAA,EAAG,OAAA;AAC1C,MAAA,OAAA,CAAQ,UAAA,CAAW;AAAA,QACjB,WAAA,EAAa,KAAA;AAAA,QACb,KAAA,EAAO,OAAO,MAAA,GAAS,SAAA;AAAA,QACvB,aAAA,EAAe,OAAA;AAAA,QACf,UAAA,EAAY,SAAA;AAAA,QACZ,cAAA,EAAgB,EAAE,QAAA,EAAU,MAAA;AAAO,OACpC,CAAA;AACD,MAAA,IAAI;AACF,QAAA,MAAM,SAAS,MAAM,OAAA,CAAQ,OAAO,CAAA,IAAA,EAAO,KAAK,IAAI,KAAK,CAAA;AACzD,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,MAAA,CAAO,OAAO,GAAG,CAAA;AAAA,QACnB;AAAA,MACF,CAAA,CAAA,MAAQ;AACN,QAAA,IAAI,MAAA,EAAQ;AACV,UAAA,MAAA,CAAO,EAAE,CAAA;AAAA,QACX;AAAA,MACF;AAAA,IACF,CAAA,GAAG;AACH,IAAA,OAAO,MAAM;AACX,MAAA,MAAA,GAAS,KAAA;AAAA,IACX,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,KAAA,EAAO,IAAA,EAAM,KAAK,CAAC,CAAA;AAEvB,EAAA,OAAO,GAAA;AACT;AAEA,IAAM,KAAA,GAAQ;AAAA,EACZ,MAAA,kBAAQC,cAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,sEAAA,EAAuE,CAAA;AAAA,EACvF,OAAA,kBAASA,cAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,+DAAA,EAAgE,CAAA;AAAA,EACjF,KAAA,kBAAOA,cAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,mCAAA,EAAoC,CAAA;AAAA,EACnD,MAAA,kBACEA,cAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,8FAAA,EAA+F,CAAA;AAAA,EAEzG,KAAA,kBAAOA,cAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,sBAAA,EAAuB;AACxC,CAAA;AAEA,SAAS,aAAA,CAAc;AAAA,EACrB,KAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,uBACEA,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,YAAA,EAAY,KAAA;AAAA,MACZ,OAAA;AAAA,MACA,KAAA,EAAO;AAAA,QACL,OAAA,EAAS,aAAA;AAAA,QACT,UAAA,EAAY,QAAA;AAAA,QACZ,cAAA,EAAgB,QAAA;AAAA,QAChB,KAAA,EAAO,EAAA;AAAA,QACP,MAAA,EAAQ,EAAA;AAAA,QACR,OAAA,EAAS,CAAA;AAAA,QACT,MAAA,EAAQ,kCAAA;AAAA,QACR,YAAA,EAAc,CAAA;AAAA,QACd,UAAA,EAAY,sBAAA;AAAA,QACZ,KAAA,EAAO,kCAAA;AAAA,QACP,MAAA,EAAQ;AAAA,OACV;AAAA,MACA,YAAA,EAAc,CAAC,KAAA,KAAU;AACvB,QAAA,KAAA,CAAM,aAAA,CAAc,MAAM,KAAA,GAAQ,4BAAA;AAClC,QAAA,KAAA,CAAM,aAAA,CAAc,MAAM,UAAA,GACxB,wEAAA;AAAA,MACJ,CAAA;AAAA,MACA,YAAA,EAAc,CAAC,KAAA,KAAU;AACvB,QAAA,KAAA,CAAM,aAAA,CAAc,MAAM,KAAA,GAAQ,kCAAA;AAClC,QAAA,KAAA,CAAM,aAAA,CAAc,MAAM,UAAA,GAAa,sBAAA;AAAA,MACzC,CAAA;AAAA,MAEA,QAAA,kBAAAA,cAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAO,EAAA;AAAA,UACP,MAAA,EAAQ,EAAA;AAAA,UACR,OAAA,EAAQ,WAAA;AAAA,UACR,IAAA,EAAK,MAAA;AAAA,UACL,MAAA,EAAO,cAAA;AAAA,UACP,WAAA,EAAa,GAAA;AAAA,UACb,aAAA,EAAc,OAAA;AAAA,UACd,cAAA,EAAe,OAAA;AAAA,UACf,aAAA,EAAY,MAAA;AAAA,UAEX;AAAA;AAAA;AACH;AAAA,GACF;AAEJ;AAcA,SAAS,MAAA,CAAO,EAAE,GAAA,EAAK,UAAA,EAAY,oBAAmB,EAAgB;AACpE,EAAA,MAAM,QAAA,GAAWC,aAAuB,IAAI,CAAA;AAC5C,EAAA,MAAM,UAAA,GAAaA,aAAuB,IAAI,CAAA;AAC9C,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIH,eAAe,QAAQ,CAAA;AAC/C,EAAA,MAAM,IAAA,GAAOG,aAAwC,IAAI,CAAA;AAEzD,EAAA,MAAM,MAAA,GAASC,iBAAA,CAAY,CAAC,OAAA,EAAiB,SAAiB,MAAA,KAAmB;AAC/E,IAAA,MAAM,QAAQ,QAAA,CAAS,OAAA;AACvB,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA;AAAA,IACF;AACA,IAAA,MAAM,IAAA,GAAO,MAAM,qBAAA,EAAsB;AACzC,IAAA,MAAM,EAAA,GAAK,UAAU,IAAA,CAAK,IAAA;AAC1B,IAAA,MAAM,EAAA,GAAK,UAAU,IAAA,CAAK,GAAA;AAC1B,IAAA,OAAA,CAAQ,CAAC,OAAA,KAAY;AACnB,MAAA,MAAM,QAAQ,KAAA,CAAM,OAAA,CAAQ,KAAA,GAAQ,MAAA,EAAQ,WAAW,SAAS,CAAA;AAChE,MAAA,MAAM,KAAA,GAAQ,QAAQ,OAAA,CAAQ,KAAA;AAC9B,MAAA,OAAO,EAAE,KAAA,EAAO,CAAA,EAAG,EAAA,GAAA,CAAM,EAAA,GAAK,OAAA,CAAQ,CAAA,IAAK,KAAA,EAAO,CAAA,EAAG,EAAA,GAAA,CAAM,EAAA,GAAK,OAAA,CAAQ,KAAK,KAAA,EAAM;AAAA,IACrF,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,cAAA,GAAiBA,iBAAA;AAAA,IACrB,CAAC,MAAA,KAAmB;AAClB,MAAA,MAAM,QAAQ,QAAA,CAAS,OAAA;AACvB,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA;AAAA,MACF;AACA,MAAA,MAAM,IAAA,GAAO,MAAM,qBAAA,EAAsB;AACzC,MAAA,MAAA,CAAO,IAAA,CAAK,IAAA,GAAO,IAAA,CAAK,KAAA,GAAQ,CAAA,EAAG,KAAK,GAAA,GAAM,IAAA,CAAK,MAAA,GAAS,CAAA,EAAG,MAAM,CAAA;AAAA,IACvE,CAAA;AAAA,IACA,CAAC,MAAM;AAAA,GACT;AAIA,EAAA,MAAM,GAAA,GAAMA,kBAAY,MAAM;AAC5B,IAAA,MAAM,QAAQ,QAAA,CAAS,OAAA;AACvB,IAAA,MAAM,UAAU,UAAA,CAAW,OAAA;AAC3B,IAAA,IAAI,CAAC,KAAA,IAAS,CAAC,OAAA,EAAS;AACtB,MAAA;AAAA,IACF;AACA,IAAA,MAAM,IAAI,OAAA,CAAQ,WAAA;AAClB,IAAA,MAAM,IAAI,OAAA,CAAQ,YAAA;AAClB,IAAA,IAAI,CAAA,KAAM,CAAA,IAAK,CAAA,KAAM,CAAA,EAAG;AACtB,MAAA;AAAA,IACF;AACA,IAAA,MAAM,KAAK,KAAA,CAAM,WAAA;AACjB,IAAA,MAAM,KAAK,KAAA,CAAM,YAAA;AACjB,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,IAAA,CAAK,GAAA,CAAI,EAAA,GAAK,CAAA,EAAG,EAAA,GAAK,CAAC,CAAA,GAAI,WAAA,EAAa,SAAA,EAAW,aAAa,CAAA;AACpF,IAAA,OAAA,CAAQ,EAAE,KAAA,EAAO,CAAA,EAAA,CAAI,EAAA,GAAK,CAAA,GAAI,KAAA,IAAS,CAAA,EAAG,CAAA,EAAA,CAAI,EAAA,GAAK,CAAA,GAAI,KAAA,IAAS,CAAA,EAAG,CAAA;AAAA,EACrE,CAAA,EAAG,EAAE,CAAA;AAIL,EAAAH,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,QAAQ,QAAA,CAAS,OAAA;AACvB,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA;AAAA,IACF;AACA,IAAA,MAAM,OAAA,GAAU,CAAC,KAAA,KAAsB;AACrC,MAAA,KAAA,CAAM,cAAA,EAAe;AACrB,MAAA,MAAA,CAAO,KAAA,CAAM,SAAS,KAAA,CAAM,OAAA,EAAS,MAAM,MAAA,GAAS,CAAA,GAAI,IAAA,GAAO,CAAA,GAAI,IAAI,CAAA;AAAA,IACzE,CAAA;AACA,IAAA,KAAA,CAAM,iBAAiB,OAAA,EAAS,OAAA,EAAS,EAAE,OAAA,EAAS,OAAO,CAAA;AAC3D,IAAA,OAAO,MAAM;AACX,MAAA,KAAA,CAAM,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAAA,IAC5C,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAGX,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,GAAA,EAAI;AAAA,EACN,CAAA,EAAG,CAAC,GAAA,EAAK,UAAA,EAAY,GAAG,CAAC,CAAA;AAEzB,EAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAA6C;AAClE,IAAA,IAAA,CAAK,UAAU,EAAE,CAAA,EAAG,MAAM,OAAA,EAAS,CAAA,EAAG,MAAM,OAAA,EAAQ;AACpD,IAAA,KAAA,CAAM,aAAA,CAAc,iBAAA,CAAkB,KAAA,CAAM,SAAS,CAAA;AAAA,EACvD,CAAA;AAEA,EAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAA6C;AAClE,IAAA,IAAI,CAAC,KAAK,OAAA,EAAS;AACjB,MAAA;AAAA,IACF;AACA,IAAA,MAAM,EAAA,GAAK,KAAA,CAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,CAAA;AACxC,IAAA,MAAM,EAAA,GAAK,KAAA,CAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,CAAA;AACxC,IAAA,IAAA,CAAK,UAAU,EAAE,CAAA,EAAG,MAAM,OAAA,EAAS,CAAA,EAAG,MAAM,OAAA,EAAQ;AACpD,IAAA,OAAA,CAAQ,CAAC,OAAA,MAAa,EAAE,GAAG,OAAA,EAAS,CAAA,EAAG,OAAA,CAAQ,CAAA,GAAI,EAAA,EAAI,CAAA,EAAG,OAAA,CAAQ,CAAA,GAAI,IAAG,CAAE,CAAA;AAAA,EAC7E,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAAC,KAAA,KAA6C;AAChE,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,IAAA,IAAI,KAAA,CAAM,aAAA,CAAc,iBAAA,CAAkB,KAAA,CAAM,SAAS,CAAA,EAAG;AAC1D,MAAA,KAAA,CAAM,aAAA,CAAc,qBAAA,CAAsB,KAAA,CAAM,SAAS,CAAA;AAAA,IAC3D;AAAA,EACF,CAAA;AAEA,EAAA,uBACEI,eAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,QAAA,EAAU,UAAA,EAAY,KAAA,EAAO,MAAA,EAAQ,MAAA,EAAQ,UAAA,GAAa,MAAA,GAAS,GAAA,EAAI,EACnF,QAAA,EAAA;AAAA,oBAAAH,cAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,QAAA;AAAA,QACL,aAAA;AAAA,QACA,aAAA;AAAA,QACA,WAAA;AAAA,QACA,cAAA,EAAgB,WAAA;AAAA,QAChB,KAAA,EAAO;AAAA,UACL,QAAA,EAAU,UAAA;AAAA,UACV,KAAA,EAAO,CAAA;AAAA,UACP,QAAA,EAAU,QAAA;AAAA,UACV,MAAA,EAAQ,MAAA;AAAA,UACR,WAAA,EAAa;AAAA,SACf;AAAA,QAEA,QAAA,kBAAAA,cAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,GAAA,EAAK,UAAA;AAAA,YACL,KAAA,EAAO;AAAA,cACL,SAAA,EAAW,CAAA,UAAA,EAAa,MAAA,CAAO,IAAA,CAAK,CAAC,CAAC,CAAA,IAAA,EAAO,MAAA,CAAO,IAAA,CAAK,CAAC,CAAC,CAAA,UAAA,EAAa,MAAA,CAAO,IAAA,CAAK,KAAK,CAAC,CAAA,CAAA,CAAA;AAAA,cAC1F,eAAA,EAAiB,KAAA;AAAA,cACjB,OAAA,EAAS,cAAA;AAAA,cACT,UAAA,EAAY;AAAA,aACd;AAAA,YACA,uBAAA,EAAyB,EAAE,MAAA,EAAQ,GAAA;AAAI;AAAA;AACzC;AAAA,KACF;AAAA,oBACAG,eAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO;AAAA,UACL,QAAA,EAAU,UAAA;AAAA,UACV,MAAA,EAAQ,EAAA;AAAA,UACR,KAAA,EAAO,EAAA;AAAA,UACP,OAAA,EAAS,MAAA;AAAA,UACT,aAAA,EAAe,QAAA;AAAA,UACf,GAAA,EAAK;AAAA,SACP;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAAH,cAAA;AAAA,YAAC,aAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAO,aAAa,kBAAA,GAAqB,aAAA;AAAA,cACzC,OAAA,EAAS,kBAAA;AAAA,cAER,QAAA,EAAA,UAAA,GAAa,KAAA,CAAM,KAAA,GAAQ,KAAA,CAAM;AAAA;AAAA,WACpC;AAAA,0BACAA,cAAA;AAAA,YAAC,aAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAM,SAAA;AAAA,cACN,SAAS,MAAM;AACb,gBAAA,cAAA,CAAe,GAAG,CAAA;AAAA,cACpB,CAAA;AAAA,cAEC,QAAA,EAAA,KAAA,CAAM;AAAA;AAAA,WACT;AAAA,0BACAA,cAAA;AAAA,YAAC,aAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAM,UAAA;AAAA,cACN,SAAS,MAAM;AACb,gBAAA,cAAA,CAAe,IAAI,GAAG,CAAA;AAAA,cACxB,CAAA;AAAA,cAEC,QAAA,EAAA,KAAA,CAAM;AAAA;AAAA,WACT;AAAA,yCACC,aAAA,EAAA,EAAc,KAAA,EAAM,cAAa,OAAA,EAAS,GAAA,EACxC,gBAAM,KAAA,EACT;AAAA;AAAA;AAAA;AACF,GAAA,EACF,CAAA;AAEJ;AAQO,SAAS,OAAA,CAAQ,EAAE,KAAA,EAAM,EAAsB;AACpD,EAAA,MAAM,GAAA,GAAM,cAAc,KAAK,CAAA;AAC/B,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIF,eAAS,KAAK,CAAA;AACtC,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,eAAS,KAAK,CAAA;AAE5C,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,UAAA,CAAW,IAAI,CAAA;AAAA,EACjB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA;AAAA,IACF;AACA,IAAA,MAAM,KAAA,GAAQ,CAAC,KAAA,KAAyB;AACtC,MAAA,IAAI,KAAA,CAAM,QAAQ,QAAA,EAAU;AAC1B,QAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,MACf;AAAA,IACF,CAAA;AACA,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,KAAK,CAAA;AAC1C,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,WAAW,KAAK,CAAA;AAAA,IAC/C,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,IAAI,QAAQ,EAAA,EAAI;AACd,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,uBACEI,eAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,MAAA,EAAQ,YAAY,YAAA,EAAc,EAAA,EAAI,QAAA,EAAU,QAAA,EAAS,EACrE,QAAA,EAAA;AAAA,oBAAAH,cAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,UAAA,EAAY,KAAA;AAAA,QACZ,oBAAoB,MAAM;AACxB,UAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,QACd;AAAA;AAAA,KACF;AAAA,IACC,WAAW,IAAA,GACRI,qBAAA;AAAA,sBACEJ,cAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,OAAA,EAAS,CAAC,KAAA,KAAU;AAElB,YAAA,IAAI,KAAA,CAAM,MAAA,KAAW,KAAA,CAAM,aAAA,EAAe;AACxC,cAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,YACf;AAAA,UACF,CAAA;AAAA,UACA,KAAA,EAAO;AAAA,YACL,QAAA,EAAU,OAAA;AAAA,YACV,KAAA,EAAO,CAAA;AAAA,YACP,MAAA,EAAQ,IAAA;AAAA,YACR,UAAA,EAAY,6CAAA;AAAA,YACZ,cAAA,EAAgB;AAAA,WAClB;AAAA,UAEA,QAAA,kBAAAA,cAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,KAAA,EAAO;AAAA,gBACL,QAAA,EAAU,UAAA;AAAA,gBACV,KAAA,EAAO,0BAAA;AAAA,gBACP,YAAA,EAAc,EAAA;AAAA,gBACd,MAAA,EAAQ,kCAAA;AAAA,gBACR,QAAA,EAAU,QAAA;AAAA,gBACV,UAAA,EAAY,qCAAA;AAAA,gBACZ,eAAA,EACE,sHAAA;AAAA,gBACF,cAAA,EAAgB,WAAA;AAAA,gBAChB,SAAA,EAAW;AAAA,eACb;AAAA,cAEA,QAAA,kBAAAA,cAAA;AAAA,gBAAC,MAAA;AAAA,gBAAA;AAAA,kBACC,GAAA;AAAA,kBACA,UAAA,EAAU,IAAA;AAAA,kBACV,oBAAoB,MAAM;AACxB,oBAAA,OAAA,CAAQ,KAAK,CAAA;AAAA,kBACf;AAAA;AAAA;AACF;AAAA;AACF;AAAA,OACF;AAAA,MACA,QAAA,CAAS;AAAA,KACX,GACA;AAAA,GAAA,EACN,CAAA;AAEJ","file":"mermaid.cjs","sourcesContent":["'use client';\n\nimport {\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n type PointerEvent as ReactPointerEvent,\n type ReactNode,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\n/**\n * The Mermaid diagram viewer — renders a chart to SVG and wraps it in an\n * interactive stage: wheel to zoom, drag to pan, a control cluster, and a\n * full-screen lightbox on a dot-grid backdrop. Matches the premium viewer a\n * reader expects from a modern docs site.\n *\n * Client-only and self-contained: it dynamically imports `mermaid` (an optional\n * peer dependency), styles itself with inline styles keyed to the framework's\n * `--color-fd-*` theme variables, and re-renders when the site toggles dark\n * mode. It lives on its own entry (`@blaaiz/docs-core/ui/mermaid`) so the heavy\n * `mermaid` import never reaches the server-compatible `ui` barrel.\n *\n * @packageDocumentation\n */\n\nconst MIN_SCALE = 0.4;\nconst MAX_SCALE = 8;\nconst MAX_FIT_SCALE = 2.5;\nconst FIT_PADDING = 0.9;\n\ninterface View {\n readonly scale: number;\n readonly x: number;\n readonly y: number;\n}\n\nconst IDENTITY: View = { scale: 1, x: 0, y: 0 };\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nfunction isDarkTheme(): boolean {\n return document.documentElement.classList.contains('dark');\n}\n\n/**\n * Render a Mermaid chart to an SVG string, re-rendering when the chart changes\n * or the site switches between light and dark themes.\n */\nfunction useMermaidSvg(chart: string): string {\n const rawId = useId().replace(/[^a-zA-Z0-9]/g, '');\n const [svg, setSvg] = useState('');\n const [dark, setDark] = useState(false);\n\n useEffect(() => {\n setDark(isDarkTheme());\n const observer = new MutationObserver(() => {\n setDark(isDarkTheme());\n });\n observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });\n return () => {\n observer.disconnect();\n };\n }, []);\n\n useEffect(() => {\n let active = true;\n void (async () => {\n const mermaid = (await import('mermaid')).default;\n mermaid.initialize({\n startOnLoad: false,\n theme: dark ? 'dark' : 'neutral',\n securityLevel: 'loose',\n fontFamily: 'inherit',\n themeVariables: { fontSize: '14px' },\n });\n try {\n const result = await mermaid.render(`mmd-${rawId}`, chart);\n if (active) {\n setSvg(result.svg);\n }\n } catch {\n if (active) {\n setSvg('');\n }\n }\n })();\n return () => {\n active = false;\n };\n }, [chart, dark, rawId]);\n\n return svg;\n}\n\nconst ICONS = {\n zoomIn: <path d=\"M11 8v6M8 11h6M21 21l-4.35-4.35M11 18a7 7 0 1 0 0-14 7 7 0 0 0 0 14Z\" />,\n zoomOut: <path d=\"M8 11h6M21 21l-4.35-4.35M11 18a7 7 0 1 0 0-14 7 7 0 0 0 0 14Z\" />,\n reset: <path d=\"M3 12a9 9 0 1 0 3-6.7L3 8m0-5v5h5\" />,\n expand: (\n <path d=\"M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3M3 16v3a2 2 0 0 0 2 2h3m8 0h3a2 2 0 0 0 2-2v-3\" />\n ),\n close: <path d=\"M18 6 6 18M6 6l12 12\" />,\n};\n\nfunction ControlButton({\n label,\n onClick,\n children,\n}: {\n label: string;\n onClick: () => void;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n aria-label={label}\n onClick={onClick}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 32,\n height: 32,\n padding: 0,\n border: '1px solid var(--color-fd-border)',\n borderRadius: 8,\n background: 'var(--color-fd-card)',\n color: 'var(--color-fd-muted-foreground)',\n cursor: 'pointer',\n }}\n onMouseEnter={(event) => {\n event.currentTarget.style.color = 'var(--color-fd-foreground)';\n event.currentTarget.style.background =\n 'color-mix(in oklab, var(--color-fd-primary) 10%, var(--color-fd-card))';\n }}\n onMouseLeave={(event) => {\n event.currentTarget.style.color = 'var(--color-fd-muted-foreground)';\n event.currentTarget.style.background = 'var(--color-fd-card)';\n }}\n >\n <svg\n width={16}\n height={16}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.8}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n {children}\n </svg>\n </button>\n );\n}\n\ninterface ViewerProps {\n readonly svg: string;\n readonly fullscreen: boolean;\n readonly onToggleFullscreen: () => void;\n}\n\n/**\n * The interactive diagram surface: the transformed SVG plus its control cluster.\n * The controls sit as a sibling of the draggable stage (not a child), so a click\n * on a control never triggers the stage's pan/pointer-capture. Reused for both\n * the inline card and the full-screen lightbox.\n */\nfunction Viewer({ svg, fullscreen, onToggleFullscreen }: ViewerProps) {\n const stageRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const [view, setView] = useState<View>(IDENTITY);\n const drag = useRef<{ x: number; y: number } | null>(null);\n\n const zoomAt = useCallback((clientX: number, clientY: number, factor: number) => {\n const stage = stageRef.current;\n if (!stage) {\n return;\n }\n const rect = stage.getBoundingClientRect();\n const px = clientX - rect.left;\n const py = clientY - rect.top;\n setView((current) => {\n const scale = clamp(current.scale * factor, MIN_SCALE, MAX_SCALE);\n const ratio = scale / current.scale;\n return { scale, x: px - (px - current.x) * ratio, y: py - (py - current.y) * ratio };\n });\n }, []);\n\n const zoomFromCenter = useCallback(\n (factor: number) => {\n const stage = stageRef.current;\n if (!stage) {\n return;\n }\n const rect = stage.getBoundingClientRect();\n zoomAt(rect.left + rect.width / 2, rect.top + rect.height / 2, factor);\n },\n [zoomAt],\n );\n\n // Scale the diagram to fit the stage and centre it. `offsetWidth/Height` are\n // the untransformed layout size, so this is independent of the current zoom.\n const fit = useCallback(() => {\n const stage = stageRef.current;\n const content = contentRef.current;\n if (!stage || !content) {\n return;\n }\n const w = content.offsetWidth;\n const h = content.offsetHeight;\n if (w === 0 || h === 0) {\n return;\n }\n const sw = stage.clientWidth;\n const sh = stage.clientHeight;\n const scale = clamp(Math.min(sw / w, sh / h) * FIT_PADDING, MIN_SCALE, MAX_FIT_SCALE);\n setView({ scale, x: (sw - w * scale) / 2, y: (sh - h * scale) / 2 });\n }, []);\n\n // Wheel-zoom needs a non-passive listener; React attaches `onWheel` as passive\n // and would warn when we call preventDefault.\n useEffect(() => {\n const stage = stageRef.current;\n if (!stage) {\n return;\n }\n const onWheel = (event: WheelEvent) => {\n event.preventDefault();\n zoomAt(event.clientX, event.clientY, event.deltaY < 0 ? 1.12 : 1 / 1.12);\n };\n stage.addEventListener('wheel', onWheel, { passive: false });\n return () => {\n stage.removeEventListener('wheel', onWheel);\n };\n }, [zoomAt]);\n\n // Fit whenever the diagram or the surface size changes.\n useEffect(() => {\n fit();\n }, [svg, fullscreen, fit]);\n\n const onPointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n drag.current = { x: event.clientX, y: event.clientY };\n event.currentTarget.setPointerCapture(event.pointerId);\n };\n\n const onPointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (!drag.current) {\n return;\n }\n const dx = event.clientX - drag.current.x;\n const dy = event.clientY - drag.current.y;\n drag.current = { x: event.clientX, y: event.clientY };\n setView((current) => ({ ...current, x: current.x + dx, y: current.y + dy }));\n };\n\n const onPointerUp = (event: ReactPointerEvent<HTMLDivElement>) => {\n drag.current = null;\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n };\n\n return (\n <div style={{ position: 'relative', width: '100%', height: fullscreen ? '100%' : 420 }}>\n <div\n ref={stageRef}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onPointerLeave={onPointerUp}\n style={{\n position: 'absolute',\n inset: 0,\n overflow: 'hidden',\n cursor: 'grab',\n touchAction: 'none',\n }}\n >\n <div\n ref={contentRef}\n style={{\n transform: `translate(${String(view.x)}px, ${String(view.y)}px) scale(${String(view.scale)})`,\n transformOrigin: '0 0',\n display: 'inline-block',\n willChange: 'transform',\n }}\n dangerouslySetInnerHTML={{ __html: svg }}\n />\n </div>\n <div\n style={{\n position: 'absolute',\n bottom: 12,\n right: 12,\n display: 'flex',\n flexDirection: 'column',\n gap: 6,\n }}\n >\n <ControlButton\n label={fullscreen ? 'Exit full screen' : 'Full screen'}\n onClick={onToggleFullscreen}\n >\n {fullscreen ? ICONS.close : ICONS.expand}\n </ControlButton>\n <ControlButton\n label=\"Zoom in\"\n onClick={() => {\n zoomFromCenter(1.3);\n }}\n >\n {ICONS.zoomIn}\n </ControlButton>\n <ControlButton\n label=\"Zoom out\"\n onClick={() => {\n zoomFromCenter(1 / 1.3);\n }}\n >\n {ICONS.zoomOut}\n </ControlButton>\n <ControlButton label=\"Reset view\" onClick={fit}>\n {ICONS.reset}\n </ControlButton>\n </div>\n </div>\n );\n}\n\n/**\n * Render a Mermaid chart in an interactive, zoomable viewer.\n *\n * @param props - the Mermaid source in `chart`\n * @public\n */\nexport function Mermaid({ chart }: { chart: string }) {\n const svg = useMermaidSvg(chart);\n const [full, setFull] = useState(false);\n const [mounted, setMounted] = useState(false);\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (!full) {\n return;\n }\n const onKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setFull(false);\n }\n };\n document.addEventListener('keydown', onKey);\n return () => {\n document.removeEventListener('keydown', onKey);\n };\n }, [full]);\n\n if (svg === '') {\n return null;\n }\n\n return (\n <div style={{ margin: '1.5rem 0', borderRadius: 12, overflow: 'hidden' }}>\n <Viewer\n svg={svg}\n fullscreen={false}\n onToggleFullscreen={() => {\n setFull(true);\n }}\n />\n {mounted && full\n ? createPortal(\n <div\n onClick={(event) => {\n // Click the dimmed gap around the panel to close.\n if (event.target === event.currentTarget) {\n setFull(false);\n }\n }}\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 9999,\n background: 'color-mix(in oklab, black 55%, transparent)',\n backdropFilter: 'blur(2px)',\n }}\n >\n <div\n style={{\n position: 'absolute',\n inset: 'clamp(20px, 3.5vw, 48px)',\n borderRadius: 16,\n border: '1px solid var(--color-fd-border)',\n overflow: 'hidden',\n background: 'var(--color-fd-background, #0a0a0b)',\n backgroundImage:\n 'radial-gradient(circle, color-mix(in oklab, var(--color-fd-muted-foreground) 22%, transparent) 1px, transparent 1px)',\n backgroundSize: '22px 22px',\n boxShadow: '0 24px 70px -12px rgba(0, 0, 0, 0.5)',\n }}\n >\n <Viewer\n svg={svg}\n fullscreen\n onToggleFullscreen={() => {\n setFull(false);\n }}\n />\n </div>\n </div>,\n document.body,\n )\n : null}\n </div>\n );\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import * as react from 'react';
2
+
3
+ /**
4
+ * Render a Mermaid chart in an interactive, zoomable viewer.
5
+ *
6
+ * @param props - the Mermaid source in `chart`
7
+ * @public
8
+ */
9
+ declare function Mermaid({ chart }: {
10
+ chart: string;
11
+ }): react.JSX.Element | null;
12
+
13
+ export { Mermaid };
@@ -0,0 +1,13 @@
1
+ import * as react from 'react';
2
+
3
+ /**
4
+ * Render a Mermaid chart in an interactive, zoomable viewer.
5
+ *
6
+ * @param props - the Mermaid source in `chart`
7
+ * @public
8
+ */
9
+ declare function Mermaid({ chart }: {
10
+ chart: string;
11
+ }): react.JSX.Element | null;
12
+
13
+ export { Mermaid };