@ai-markdown/core 3.2.1 → 3.3.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/LICENSE +72 -0
- package/components/package.json +8 -0
- package/dist/components/index.cjs +555 -0
- package/dist/components/index.cjs.map +1 -0
- package/dist/components/index.d.cts +233 -0
- package/dist/components/index.d.ts +233 -0
- package/dist/components/index.js +528 -0
- package/dist/components/index.js.map +1 -0
- package/dist/index.cjs +932 -979
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +260 -326
- package/dist/index.d.ts +260 -326
- package/dist/index.dev.cjs +929 -979
- package/dist/index.dev.cjs.map +1 -1
- package/dist/index.dev.js +907 -944
- package/dist/index.dev.js.map +1 -1
- package/dist/index.js +910 -944
- package/dist/index.js.map +1 -1
- package/package.json +21 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/components/nodes.ts","../../src/components/codeFrame.ts","../../src/components/formatJson.ts","../../src/components/jsonCompleteness.ts","../../src/components/renderQueue.ts","../../src/components/mermaid.ts","../../src/components/diagram.ts","../../src/components/scroll.ts","../../src/components/image.ts","../../src/components/imageTransform.ts"],"sourcesContent":["import type { Element, RootContent } from 'hast';\n\nexport interface CodeSource {\n code: string;\n language: string;\n}\n/** Enhance only ordinary fenced code; preserve all other pre overrides. */\nexport function extractCode(node?: Element): CodeSource | null {\n if (node?.tagName !== 'pre' || node.children.length !== 1 || Object.keys(node.properties).length) return null;\n const child = node.children[0];\n if (\n child.type !== 'element' ||\n child.tagName !== 'code' ||\n child.children.some((n) => n.type !== 'text') ||\n Object.keys(child.properties).some((k) => k !== 'className')\n )\n return null;\n const classes = child.properties.className ?? [];\n const names = (Array.isArray(classes) ? classes : String(classes).split(/\\s+/)).map(String).filter(Boolean);\n if (names.some((n) => !n.startsWith('language-'))) return null;\n const languages = [...new Set(names.map((n) => n.slice(9).trim().toLowerCase()))];\n if (languages.length > 1) return null;\n return { code: child.children.map((n) => (n.type === 'text' ? n.value : '')).join(''), language: languages[0] ?? '' };\n}\nexport function normalizeRenderers<T>(renderers: Readonly<Record<string, T>>): Readonly<Record<string, T>> {\n const result: Record<string, T> = Object.create(null);\n for (const [language, renderer] of Object.entries(renderers)) {\n const key = language.trim().toLowerCase();\n if (!key) throw new Error('Code renderer language must not be empty');\n if (Object.hasOwn(result, key)) throw new Error(`Duplicate code renderer: ${key}`);\n result[key] = renderer;\n }\n return Object.freeze(result);\n}\nfunction annotation(node: RootContent): Element | undefined {\n if (node.type !== 'element') return;\n if (node.tagName === 'annotation' && node.properties.encoding === 'application/x-tex') return node;\n for (const child of node.children) {\n const found = annotation(child);\n if (found) return found;\n }\n}\nfunction text(node: RootContent): string {\n if (node.type === 'text') return node.value;\n if (node.type !== 'element') return '';\n if (node.tagName === 'table') throw new Error('Nested tables cannot be exported');\n if (Array.isArray(node.properties.className) && node.properties.className.includes('katex')) {\n const tex = annotation(node);\n if (!tex) throw new Error('Math is missing its text annotation');\n return tex.children.map(text).join('');\n }\n if (node.tagName === 'br') return '\\n';\n if (node.tagName === 'img' || node.tagName === 'cross-chunk-image') return String(node.properties.alt ?? '');\n return node.children.map(text).join('');\n}\nexport type TableProjection = { rows: string[][]; reason?: undefined } | { rows?: undefined; reason: string };\n/** Project sanitized HAST semantics, never custom cell UI or raw Markdown. */\nexport function projectTable(node?: Element): TableProjection {\n try {\n if (node?.tagName !== 'table') throw new Error('Table source is unavailable');\n const rows: string[][] = [];\n const walk = (parent: Element) => {\n for (const child of parent.children) {\n if (child.type === 'text' && !child.value.trim()) continue;\n if (child.type !== 'element') throw new Error('Unsupported table content');\n if (child.tagName === 'tr') {\n const cells: string[] = [];\n for (const cell of child.children) {\n if (cell.type === 'text' && !cell.value.trim()) continue;\n if (\n cell.type !== 'element' ||\n !['th', 'td'].includes(cell.tagName) ||\n Number(cell.properties.colSpan ?? 1) !== 1 ||\n Number(cell.properties.rowSpan ?? 1) !== 1\n )\n throw new Error('Only tables without merged cells can be exported');\n cells.push(text(cell));\n }\n rows.push(cells);\n } else if (['thead', 'tbody', 'tfoot'].includes(child.tagName) && parent === node) walk(child);\n else throw new Error('Unsupported table structure');\n }\n };\n walk(node);\n if (!rows.length || !rows[0].length || rows.some((r) => r.length !== rows[0].length))\n throw new Error('Only rectangular tables can be exported');\n return { rows };\n } catch (error) {\n return { reason: error instanceof Error ? error.message : 'Table cannot be exported' };\n }\n}\n/** Spreadsheet text policy is independent of delimiter quoting. Negative\n * numbers stay numeric; formulas/control-prefixed text stay literal. */\n// Control-prefixed formulas must stay literal when pasted into a spreadsheet.\n// eslint-disable-next-line no-control-regex\nconst formulaPrefix = /^[\\s\\u0000-\\u001f]*[=+@-]/;\nexport function serializeTable(rows: readonly (readonly string[])[], delimiter: ',' | '\\t' = ','): string {\n return rows\n .map((row) =>\n row\n .map((value) => {\n if (\n (formulaPrefix.test(value) && !/^\\s*-?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?\\s*$/i.test(value)) ||\n /^[\\t\\r\\n]/.test(value)\n )\n value = `'${value}`;\n return /[\"\\r\\n\\t,]/.test(value) ? `\"${value.replaceAll('\"', '\"\"')}\"` : value;\n })\n .join(delimiter)\n )\n .join('\\r\\n');\n}\n","export interface CodeFrame {\n code: string;\n language: string;\n}\n\n/** A trailing throttle: append bursts replace one pending frame without\n * moving its deadline. Replacements and completion bypass the timer. */\nexport function createCodeFrame(initial: CodeFrame, publish: (frame: CodeFrame) => void) {\n let shown = initial;\n let latest = initial;\n let delay = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const cancel = () => {\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n };\n const flush = () => {\n cancel();\n if (shown.code === latest.code && shown.language === latest.language) return;\n shown = latest;\n publish(shown);\n };\n return {\n update(next: CodeFrame, streaming: boolean, interval: number) {\n const replaced = next.language !== latest.language || !next.code.startsWith(latest.code);\n latest = next;\n if (delay !== interval) cancel();\n delay = interval;\n if (!streaming || interval === 0 || replaced) return flush();\n if (shown.code === next.code && shown.language === next.language) return cancel();\n timer ??= setTimeout(flush, interval);\n },\n // Cancellation is reversible: Strict Mode replays the update effect.\n dispose: cancel,\n };\n}\n","/** Validate with the native parser, but format lexical tokens so numbers,\n * duplicate keys and key order never pass through JavaScript's value model.\n * Nested JSON expansion is optional and only applies to string values. */\nexport function prettyPrintJson(text: string, expandNested = true): string {\n try {\n return format(text, expandNested, 0);\n } catch {\n return text;\n }\n}\n\nfunction format(text: string, expandNested: boolean, baseIndent: number): string {\n JSON.parse(text);\n const tokens =\n text.match(/\"(?:\\\\[\\s\\S]|[^\"\\\\])*\"|-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?|true|false|null|[{}[\\],:]/g) ?? [];\n const out: string[] = [];\n let indent = baseIndent;\n const newline = () => out.push('\\n', ' '.repeat(indent));\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n if (token === '{' || token === '[') {\n out.push(token);\n if (tokens[i + 1] !== (token === '{' ? '}' : ']')) {\n indent++;\n newline();\n }\n } else if (token === '}' || token === ']') {\n if (tokens[i - 1] !== (token === '}' ? '{' : '[')) {\n indent--;\n newline();\n }\n out.push(token);\n } else if (token === ',') {\n out.push(',');\n newline();\n } else if (token === ':') {\n out.push(': ');\n } else if (token.startsWith('\"')) {\n const value = JSON.parse(token) as string;\n const trimmed = value.trim();\n if (expandNested && tokens[i + 1] !== ':' && /^[{[]/.test(trimmed) && indent < 100) {\n try {\n out.push(format(trimmed, true, indent));\n continue;\n } catch {\n /* Keep non-JSON strings. */\n }\n }\n out.push(JSON.stringify(value));\n } else {\n out.push(token);\n }\n }\n return out.join('');\n}\n","/** Bracket-balance gate, not a JSON validator. Retain quote/escape state\n * across append seams so growing JSON does not rescan its whole body when\n * each nested object closes. Replacements start a fresh lineage. */\nexport function createJsonCompletenessScanner() {\n let previous = '';\n let depth = 0;\n let quoted = false;\n let escaped = false;\n let invalid = false;\n let last = '';\n return (text: string): boolean => {\n let from = previous.length;\n if (!text.startsWith(previous)) {\n from = 0;\n depth = 0;\n quoted = escaped = invalid = false;\n last = '';\n }\n previous = text;\n for (let i = from; i < text.length; i++) {\n const c = text[i];\n if (!/\\s/.test(c)) last = c;\n if (quoted) {\n if (escaped) escaped = false;\n else if (c === '\\\\') escaped = true;\n else if (c === '\"') quoted = false;\n } else if (c === '\"') quoted = true;\n else if (c === '{' || c === '[') depth++;\n else if (c === '}' || c === ']') {\n depth--;\n if (depth < 0) invalid = true;\n }\n }\n return !invalid && !quoted && depth === 0 && (last === '}' || last === ']');\n };\n}\n\nexport function jsonLooksComplete(text: string): boolean {\n return createJsonCompletenessScanner()(text);\n}\n","/** Mermaid owns global configuration and a global renderer. Keep initialize,\n * parse and render in one serialized task. Each mounted diagram retains at\n * most one pending task; superseded frames never enter Mermaid. */\nexport function createRenderQueue() {\n type Job = { run: () => Promise<void>; resolve: () => void; reject: (error: unknown) => void };\n const pending = new Map<object, Job>();\n let running = false;\n async function drain() {\n if (running) return;\n running = true;\n try {\n while (pending.size) {\n const [owner, job] = pending.entries().next().value!;\n pending.delete(owner);\n try {\n await job.run();\n job.resolve();\n } catch (error) {\n job.reject(error);\n }\n }\n } finally {\n running = false;\n }\n }\n return {\n enqueue(owner: object, run: () => Promise<void>): Promise<void> {\n pending.get(owner)?.resolve();\n const promise = new Promise<void>((resolve, reject) => pending.set(owner, { run, resolve, reject }));\n void drain();\n return promise;\n },\n cancel(owner: object) {\n pending.get(owner)?.resolve();\n pending.delete(owner);\n },\n };\n}\n\nexport const mermaidRenderQueue = createRenderQueue();\n","type MermaidConfig = {\n theme?: string;\n securityLevel?: string;\n darkMode?: boolean;\n suppressErrorRendering?: boolean;\n maxTextSize?: number;\n themeVariables?: unknown;\n};\n\n/** The part of the mermaid module this file touches. Structural so tests can\n * pass a stub; `mermaidAPI` is deprecated in mermaid's types but present at\n * runtime in mermaid 11, and it is the only place `getSiteConfig` /\n * `getConfig` live (the default export has neither). */\nexport type MermaidInitTarget = {\n initialize(config: MermaidConfig): void;\n mermaidAPI?: {\n getSiteConfig?: () => MermaidConfig;\n getConfig?: () => MermaidConfig;\n };\n};\n\n/**\n * `securityLevel` values under which mermaid still sanitizes what it emits.\n * `sandbox` is stricter than `strict` (the diagram renders inside a sandboxed\n * iframe), so a host that chose it must not be downgraded. `loose` and\n * `antiscript` skip DOMPurify and are upgraded to `strict`; so is an unset\n * value, which mermaid treats as `strict` but which we pin explicitly so the\n * guard below has something to compare against.\n */\nconst SAFE_SECURITY_LEVELS: ReadonlySet<string | undefined> = new Set(['strict', 'sandbox']);\n\n/** Theme we last wrote. mermaid's config is a module-level singleton, so this\n * is module-level too: instances under providers with DIFFERENT color\n * schemes each re-assert before their own render, and the check runs per\n * attempt (each streamed chunk re-runs the effect) rather than once per\n * instance. It also tells a theme WE wrote apart from one the host wrote —\n * the host's choice is left alone; ours follows the color scheme. */\nlet ownedThemes = new WeakMap<object, 'dark' | 'base'>();\n\n/** Test hook: forget the theme cache so each test starts from a cold module. */\nexport const resetMermaidInitializationForTests = () => {\n ownedThemes = new WeakMap();\n};\n\n/**\n * Read the config `mermaid.initialize` would replace. `getSiteConfig` is the\n * site config (what the host passed to `initialize`, merged over mermaid's\n * defaults); `getConfig` is the per-render config with `%%{init}%%`\n * directives merged in and is only a fallback for builds without the former.\n */\nconst readSiteConfig = (mermaid: MermaidInitTarget): MermaidConfig => {\n const api = mermaid.mermaidAPI;\n return api?.getSiteConfig?.() ?? api?.getConfig?.() ?? {};\n};\n\n/** mermaid's own default for `maxTextSize` (`MAX_TEXTLENGTH` in mermaidAPI). */\nexport const MERMAID_DEFAULT_MAX_TEXT_SIZE = 50_000;\n\n/**\n * The effective `maxTextSize`. `mermaid.render` does not reject oversized\n * input: it swaps in a placeholder diagram (\"Maximum text size in diagram\n * exceeded\") and resolves normally, and `mermaid.parse` has no size gate at\n * all, so the whole text is parsed first. The renderer checks this before\n * parsing and reports the size as an error instead. The key is in mermaid's\n * `secure` list, so a `%%{init}%%` directive cannot raise it and the site\n * config is the value that applies.\n */\nexport const getMermaidMaxTextSize = (mermaid: MermaidInitTarget): number => {\n const configured = readSiteConfig(mermaid).maxTextSize;\n return typeof configured === 'number' && Number.isFinite(configured) && configured >= 0\n ? configured\n : MERMAID_DEFAULT_MAX_TEXT_SIZE;\n};\n\n/**\n * mermaid's config is a module-level singleton shared with the host\n * application when the bundler dedupes the package, and a host that enables\n * `click` interactions calls `mermaid.initialize({ securityLevel: 'loose' })`\n * — the officially documented way. Under `loose` mermaid skips DOMPurify\n * and its output goes into this component's `innerHTML` verbatim: an\n * LLM-authored diagram string could then run script in the page origin.\n * So a theme cache alone is not enough of a guard: before every render the\n * current `securityLevel` is read back (a config copy, still far cheaper\n * than `initialize`'s merge + theme variables + diagram registration) and an\n * unsafe value forces a re-initialize\n * (2026-08-19 review r2 P2-11; the v2.4.2 \"documented premise\" made this\n * the host's problem — it is ours, the innerHTML is ours).\n *\n * In mermaid 11 `initialize` goes through `setSiteConfig`, which REPLACES\n * the site config with defaults + the keys passed in. Calling it with only\n * our keys wiped the host's `theme`, `fontFamily`, `flowchart` options and\n * so on, and turned a host `sandbox` into `strict` (3.0.2 review). So:\n * - the current site config is read back and passed through with our\n * overrides on top, so host keys survive;\n * - `sandbox` is accepted as is; only `loose` / `antiscript` / unset become\n * `strict`;\n * - a theme the host chose is kept (with its `themeVariables`); the color\n * scheme switch only applies to the theme when the host has not chosen\n * one, or when the current theme is one we wrote;\n * - when nothing needs to change, `initialize` is not called at all, so a\n * host on `strict`/`sandbox` and this component stop overwriting each\n * other on every render.\n */\nexport const ensureMermaidInitialized = (mermaid: MermaidInitTarget, isDark: boolean) => {\n const site = readSiteConfig(mermaid);\n const ownedTheme = ownedThemes.get(mermaid);\n const wantedTheme = isDark ? 'dark' : 'base';\n\n // `default` is mermaid's own initial value, so it does not count as a host\n // choice. A theme equal to the one we last wrote is ours to switch.\n const hostOwnsTheme = site.theme !== undefined && site.theme !== 'default' && site.theme !== ownedTheme;\n\n const levelOk = SAFE_SECURITY_LEVELS.has(site.securityLevel);\n const themeOk = hostOwnsTheme || (site.theme === wantedTheme && Boolean(site.darkMode) === isDark);\n const suppressOk = site.suppressErrorRendering === true;\n if (levelOk && themeOk && suppressOk) return;\n\n const next: MermaidConfig = {\n ...site,\n // Without this, a draw-phase throw (an error that got past\n // mermaid.parse) leaves mermaid's temp element orphaned in document.body\n // — its error path only cleans up when this flag is set. We render our\n // own error tab anyway, so mermaid's built-in error diagram is dead\n // weight here regardless.\n suppressErrorRendering: true,\n };\n if (!levelOk) {\n next.securityLevel = 'strict';\n }\n if (!hostOwnsTheme) {\n next.theme = wantedTheme;\n next.darkMode = isDark;\n // The site config carries the PREVIOUS theme's fully computed\n // `themeVariables`. `initialize` feeds `themeVariables` into the new\n // theme as overrides for every key present, so passing them back would\n // make the new theme look exactly like the old one. Drop them and keep\n // only `fontFamily`: `default`, `base` and `dark` share the same font\n // default, so a value that differs is the host's and survives the switch\n // (a top-level `fontFamily` survives through the spread above either way).\n // Mermaid's dark edge labels use #ccc text on #585858 (4.43:1).\n // Give our default palette enough contrast; host-owned themes stay intact.\n const fontFamily: unknown = (site.themeVariables as { fontFamily?: unknown } | undefined)?.fontFamily;\n if (typeof fontFamily === 'string') {\n next.themeVariables = { fontFamily, ...(isDark ? { edgeLabelBackground: '#444444' } : {}) };\n } else if (isDark) {\n next.themeVariables = { edgeLabelBackground: '#444444' };\n } else {\n delete next.themeVariables;\n }\n ownedThemes.set(mermaid, wantedTheme);\n }\n mermaid.initialize(next);\n};\n","import { mermaidRenderQueue } from './renderQueue';\nimport { ensureMermaidInitialized, getMermaidMaxTextSize, type MermaidInitTarget } from './mermaid';\n\nexport interface DiagramEngine extends MermaidInitTarget {\n parse(code: string, options: { suppressErrors: true }): Promise<unknown>;\n render(id: string, code: string): Promise<{ svg: string; bindFunctions?(element: object): void }>;\n}\nexport type DiagramState = {\n status: 'loading' | 'ready' | 'error';\n svg: string;\n error?: string;\n bind?: (element: object) => void;\n};\nexport interface DiagramRequest {\n code: string;\n dark: boolean;\n streaming: boolean;\n active: boolean;\n resetKey: string;\n interval: number;\n}\nlet nextId = 0;\n/** Owns cancellation and retries across both UI adapters. In-flight Mermaid\n * cannot be aborted, but obsolete work never publishes or starts a render. */\nexport function createDiagramController(load: () => Promise<DiagramEngine>, publish: (state: DiagramState) => void) {\n const owner = {};\n let epoch = 0;\n let previous: DiagramRequest | undefined;\n let svg = '';\n let bind: DiagramState['bind'];\n let timer: ReturnType<typeof setTimeout> | undefined;\n const cancel = () => {\n epoch++;\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n mermaidRenderQueue.cancel(owner);\n };\n return {\n update(request: DiagramRequest) {\n const replaced =\n !previous ||\n previous.resetKey !== request.resetKey ||\n previous.dark !== request.dark ||\n !request.code.startsWith(previous.code);\n const pending = timer !== undefined;\n // Append bursts retain their deadline; every request invalidates work\n // already running, including completion-only and active-only changes.\n epoch++;\n mermaidRenderQueue.cancel(owner);\n if (replaced) {\n svg = '';\n bind = undefined;\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n }\n previous = request;\n if (!request.active) {\n cancel();\n return;\n }\n publish({ status: 'loading', svg, bind });\n const attempt = () => {\n timer = undefined;\n const current = previous!;\n const generation = epoch;\n const valid = () => generation === epoch;\n let phase: 'load' | 'render' = 'load';\n void load()\n .then((engine) => {\n phase = 'render';\n if (!valid()) return;\n return mermaidRenderQueue.enqueue(owner, async () => {\n if (!valid()) return;\n ensureMermaidInitialized(engine, current.dark);\n if (current.code.length > getMermaidMaxTextSize(engine))\n throw new Error('Diagram exceeds Mermaid’s maximum text size');\n const parsed = await engine.parse(current.code, { suppressErrors: true });\n if (!valid()) return;\n if (parsed === false) throw new Error('Diagram syntax is incomplete or invalid');\n const result = await engine.render(`aimd-diagram-${++nextId}`, current.code);\n if (!valid()) return;\n svg = result.svg;\n bind = result.bindFunctions;\n publish({ status: 'ready', svg, bind });\n });\n })\n .catch((error) => {\n if (valid())\n publish({\n status: current.streaming && phase === 'render' ? 'loading' : 'error',\n svg,\n bind,\n error:\n (phase === 'load' ? 'Diagram engine could not load: ' : '') +\n (error instanceof Error ? error.message : String(error)).slice(0, 500),\n });\n });\n };\n if (!request.streaming || request.interval <= 0) {\n if (timer !== undefined) clearTimeout(timer);\n attempt();\n } else if (!pending || replaced) timer = setTimeout(attempt, request.interval);\n },\n dispose: cancel,\n };\n}\n","/** Structural browser target keeps the shared core independent of DOM libs.\n * Several React/Vue dialogs can coexist; the last owner restores scrolling. */\nconst locks = new WeakMap<object, { count: number; overflow: string }>();\nexport function lockImagePreviewScroll(target: { style: { overflow: string } }): () => void {\n let lock = locks.get(target);\n if (!lock) {\n lock = { count: 0, overflow: target.style.overflow };\n locks.set(target, lock);\n }\n lock.count++;\n target.style.overflow = 'hidden';\n let released = false;\n return () => {\n if (released) return;\n released = true;\n if (--lock.count === 0) {\n if (target.style.overflow === 'hidden') target.style.overflow = lock.overflow;\n locks.delete(target);\n }\n };\n}\n","/** Shared image semantics; no DOM or framework dependency. */\nexport type ImageActionIconName =\n 'rotateLeft' | 'rotateRight' | 'zoomIn' | 'zoomOut' | 'close' | 'prev' | 'next' | 'flipX' | 'flipY';\nexport type ImageIconName = 'placeholder' | 'error' | 'preview' | 'gallery' | ImageActionIconName;\nexport type ImageLoadStatus = 'loading' | 'ready' | 'error';\n/** Lucide paths supplied for the Markdown image skin (ISC license). */\nexport const imageIconPaths: Record<ImageIconName, readonly string[]> = {\n rotateLeft: ['M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8', 'M3 3v5h5'],\n rotateRight: ['M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8', 'M21 3v5h-5'],\n zoomIn: ['M19 11a8 8 0 1 1 -16 0a8 8 0 1 1 16 0', 'M21 21L16.65 16.65', 'M11 8L11 14', 'M8 11L14 11'],\n zoomOut: ['M19 11a8 8 0 1 1 -16 0a8 8 0 1 1 16 0', 'M21 21L16.65 16.65', 'M8 11L14 11'],\n close: ['M18 6 6 18', 'm6 6 12 12'],\n prev: ['m15 18-6-6 6-6'],\n next: ['m9 18 6-6-6-6'],\n flipX: [\n 'M8 3H5a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h3',\n 'M16 3h3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-3',\n 'M12 20v2',\n 'M12 14v2',\n 'M12 8v2',\n 'M12 2v2',\n ],\n flipY: [\n 'M21 8V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v3',\n 'M21 16v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-3',\n 'M4 12H2',\n 'M10 12H8',\n 'M16 12h-2',\n 'M22 12h-2',\n ],\n placeholder: [\n 'M5 3h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z',\n 'M11 9a2 2 0 1 1-4 0 2 2 0 0 1 4 0',\n 'm21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21',\n ],\n error: [\n 'm2 2 20 20M10.41 10.41a2 2 0 1 1-2.83-2.83m5.92 5.92L6 21m12-9 3 3',\n 'M3.59 3.59A2 2 0 0 0 3 5v14a2 2 0 0 0 2 2h14c.55 0 1.052-.22 1.41-.59M21 15V5a2 2 0 0 0-2-2H9',\n ],\n gallery: ['M5 3h14a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z', 'M4 21h1m4 0h1m4 0h1m4 0h1'],\n preview: [\n 'M15 15.003a1 1 0 0 1 1.517-.859l4.997 2.997a1 1 0 0 1 0 1.718l-4.997 2.997a1 1 0 0 1-1.517-.86z',\n 'M21 12.17V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h6m-5 0 5-5',\n 'M11 9a2 2 0 1 1-4 0 2 2 0 0 1 4 0',\n ],\n};\nexport const imageGroupSelector = '[data-aimd-image-scope], .aim-typography-root, .aimd-vue, .mantine-Typography-root';\nexport interface ImageGalleryItem {\n id: object;\n src: string;\n alt: string;\n /** DOM adapters provide document ordering without leaking DOM types. */\n precedes: (other: object) => boolean;\n}\nexport interface ImageGallery {\n items: () => readonly ImageGalleryItem[];\n subscribe: (listener: () => void) => () => void;\n set: (item: ImageGalleryItem) => void;\n remove: (id: object) => void;\n}\nconst galleries = new WeakMap<object, ImageGallery>();\n/** Scope is an adapter-owned object, never a global document id. */\nexport function getImageGallery(scope: object): ImageGallery {\n const existing = galleries.get(scope);\n if (existing) return existing;\n const entries = new Map<object, ImageGalleryItem>();\n const listeners = new Set<() => void>();\n const notify = () => listeners.forEach((listener) => listener());\n const gallery: ImageGallery = {\n items: () => [...entries.values()].sort((a, b) => (a.precedes(b.id) ? -1 : b.precedes(a.id) ? 1 : 0)),\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n set(item) {\n const old = entries.get(item.id);\n if (old?.src === item.src && old?.alt === item.alt) return;\n entries.set(item.id, item);\n notify();\n },\n remove(id) {\n if (entries.delete(id)) notify();\n },\n };\n galleries.set(scope, gallery);\n return gallery;\n}\n\nexport const imageActionLabels: Record<ImageActionIconName, string> = {\n close: 'Close preview',\n prev: 'Previous image',\n next: 'Next image',\n rotateLeft: 'Rotate left',\n rotateRight: 'Rotate right',\n zoomIn: 'Zoom in',\n zoomOut: 'Zoom out',\n flipX: 'Flip horizontally',\n flipY: 'Flip vertically',\n};\n","/** Transform rules adapted from @rc-component/image 1.10.0 (MIT).\n * Keep the Vue adapter's gestures aligned with the upstream React engine. */\nexport interface ImageTransform {\n x: number;\n y: number;\n rotate: number;\n scale: number;\n flipX: boolean;\n flipY: boolean;\n}\nexport interface ImageGeometry {\n width: number;\n height: number;\n left: number;\n top: number;\n viewportWidth: number;\n viewportHeight: number;\n}\nexport const initialImageTransform = (): ImageTransform => ({\n x: 0,\n y: 0,\n rotate: 0,\n scale: 1,\n flipX: false,\n flipY: false,\n});\nexport function imageTransformStyle(transform: ImageTransform): string {\n const { x, y, scale, rotate, flipX, flipY } = transform;\n return `translate3d(${x}px, ${y}px, 0) scale3d(${flipX ? '-' : ''}${scale}, ${flipY ? '-' : ''}${scale}, 1) rotate(${rotate}deg)`;\n}\nexport function zoomImage(\n transform: ImageTransform,\n ratio: number,\n geometry: ImageGeometry,\n centerX = geometry.viewportWidth / 2,\n centerY = geometry.viewportHeight / 2,\n touch = false\n): ImageTransform {\n if (!Number.isFinite(ratio) || ratio <= 0) return transform;\n const scale = Math.min(50, touch ? Math.max(0.01, transform.scale * ratio) : Math.max(1, transform.scale * ratio));\n const difference = scale / transform.scale - 1;\n let x = transform.x - difference * (centerX - transform.x - geometry.left - geometry.width / 2);\n let y = transform.y - difference * (centerY - transform.y - geometry.top - geometry.height / 2);\n if (\n ratio < 1 &&\n scale === 1 &&\n geometry.width <= geometry.viewportWidth &&\n geometry.height <= geometry.viewportHeight\n )\n x = y = 0;\n return { ...transform, x, y, scale };\n}\nexport function imageWheelRatio(delta: number): number {\n const ratio = 1 + Math.min(Math.abs(delta / 100), 1) * 0.5;\n return delta > 0 ? 1 / ratio : ratio;\n}\n/** Snap a moved image back inside the viewport, taking quarter turns into account. */\nexport function reboundImage(\n transform: ImageTransform,\n geometry: ImageGeometry,\n bounds: { left: number; top: number }\n): ImageTransform {\n if (transform.scale < 1) return { ...transform, x: 0, y: 0, scale: 1 };\n const rotated = transform.rotate % 180 !== 0;\n const width = (rotated ? geometry.height : geometry.width) * transform.scale;\n const height = (rotated ? geometry.width : geometry.height) * transform.scale;\n if (width <= geometry.viewportWidth && height <= geometry.viewportHeight) return { ...transform, x: 0, y: 0 };\n const fix = (position: number, start: number, size: number, viewport: number) => {\n const offset = (size - viewport) / 2;\n if (size > viewport) {\n if (start > 0) return offset;\n if (start < 0 && start + size < viewport) return -offset;\n } else if (start < 0 || start + size > viewport) return start < 0 ? offset : -offset;\n return position;\n };\n return {\n ...transform,\n x: fix(transform.x, bounds.left, width, geometry.viewportWidth),\n y: fix(transform.y, bounds.top, height, geometry.viewportHeight),\n };\n}\n/** Upstream pinch center weights each finger by how far it moved. */\nexport function imagePinchCenter(\n oldA: { x: number; y: number },\n oldB: { x: number; y: number },\n a: { x: number; y: number },\n b: { x: number; y: number }\n): { x: number; y: number } {\n const distanceA = Math.hypot(a.x - oldA.x, a.y - oldA.y),\n distanceB = Math.hypot(b.x - oldB.x, b.y - oldB.y);\n const ratio = distanceA + distanceB ? distanceA / (distanceA + distanceB) : 0;\n return { x: oldA.x + ratio * (oldB.x - oldA.x), y: oldA.y + ratio * (oldB.y - oldA.y) };\n}\n"],"mappings":";;AAOA,SAAgB,YAAY,MAAmC;CAC7D,IAAI,MAAM,YAAY,SAAS,KAAK,SAAS,WAAW,KAAK,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,QAAQ,OAAO;CACzG,MAAM,QAAQ,KAAK,SAAS;CAC5B,IACE,MAAM,SAAS,aACf,MAAM,YAAY,UAClB,MAAM,SAAS,MAAM,MAAM,EAAE,SAAS,MAAM,KAC5C,OAAO,KAAK,MAAM,UAAU,CAAC,CAAC,MAAM,MAAM,MAAM,WAAW,GAE3D,OAAO;CACT,MAAM,UAAU,MAAM,WAAW,aAAa,CAAC;CAC/C,MAAM,SAAS,MAAM,QAAQ,OAAO,IAAI,UAAU,OAAO,OAAO,CAAC,CAAC,MAAM,KAAK,EAAA,CAAG,IAAI,MAAM,CAAC,CAAC,OAAO,OAAO;CAC1G,IAAI,MAAM,MAAM,MAAM,CAAC,EAAE,WAAW,WAAW,CAAC,GAAG,OAAO;CAC1D,MAAM,YAAY,CAAC,GAAG,IAAI,IAAI,MAAM,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;CAChF,IAAI,UAAU,SAAS,GAAG,OAAO;CACjC,OAAO;EAAE,MAAM,MAAM,SAAS,KAAK,MAAO,EAAE,SAAS,SAAS,EAAE,QAAQ,EAAG,CAAC,CAAC,KAAK,EAAE;EAAG,UAAU,UAAU,MAAM;CAAG;AACtH;AACA,SAAgB,mBAAsB,WAAqE;CACzG,MAAM,SAA4B,OAAO,OAAO,IAAI;CACpD,KAAK,MAAM,CAAC,UAAU,aAAa,OAAO,QAAQ,SAAS,GAAG;EAC5D,MAAM,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY;EACxC,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,0CAA0C;EACpE,IAAI,OAAO,OAAO,QAAQ,GAAG,GAAG,MAAM,IAAI,MAAM,4BAA4B,KAAK;EACjF,OAAO,OAAO;CAChB;CACA,OAAO,OAAO,OAAO,MAAM;AAC7B;AACA,SAAS,WAAW,MAAwC;CAC1D,IAAI,KAAK,SAAS,WAAW;CAC7B,IAAI,KAAK,YAAY,gBAAgB,KAAK,WAAW,aAAa,qBAAqB,OAAO;CAC9F,KAAK,MAAM,SAAS,KAAK,UAAU;EACjC,MAAM,QAAQ,WAAW,KAAK;EAC9B,IAAI,OAAO,OAAO;CACpB;AACF;AACA,SAAS,KAAK,MAA2B;CACvC,IAAI,KAAK,SAAS,QAAQ,OAAO,KAAK;CACtC,IAAI,KAAK,SAAS,WAAW,OAAO;CACpC,IAAI,KAAK,YAAY,SAAS,MAAM,IAAI,MAAM,kCAAkC;CAChF,IAAI,MAAM,QAAQ,KAAK,WAAW,SAAS,KAAK,KAAK,WAAW,UAAU,SAAS,OAAO,GAAG;EAC3F,MAAM,MAAM,WAAW,IAAI;EAC3B,IAAI,CAAC,KAAK,MAAM,IAAI,MAAM,qCAAqC;EAC/D,OAAO,IAAI,SAAS,IAAI,IAAI,CAAC,CAAC,KAAK,EAAE;CACvC;CACA,IAAI,KAAK,YAAY,MAAM,OAAO;CAClC,IAAI,KAAK,YAAY,SAAS,KAAK,YAAY,qBAAqB,OAAO,OAAO,KAAK,WAAW,OAAO,EAAE;CAC3G,OAAO,KAAK,SAAS,IAAI,IAAI,CAAC,CAAC,KAAK,EAAE;AACxC;AAGA,SAAgB,aAAa,MAAiC;CAC5D,IAAI;EACF,IAAI,MAAM,YAAY,SAAS,MAAM,IAAI,MAAM,6BAA6B;EAC5E,MAAM,OAAmB,CAAC;EAC1B,MAAM,QAAQ,WAAoB;GAChC,KAAK,MAAM,SAAS,OAAO,UAAU;IACnC,IAAI,MAAM,SAAS,UAAU,CAAC,MAAM,MAAM,KAAK,GAAG;IAClD,IAAI,MAAM,SAAS,WAAW,MAAM,IAAI,MAAM,2BAA2B;IACzE,IAAI,MAAM,YAAY,MAAM;KAC1B,MAAM,QAAkB,CAAC;KACzB,KAAK,MAAM,QAAQ,MAAM,UAAU;MACjC,IAAI,KAAK,SAAS,UAAU,CAAC,KAAK,MAAM,KAAK,GAAG;MAChD,IACE,KAAK,SAAS,aACd,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,SAAS,KAAK,OAAO,KACnC,OAAO,KAAK,WAAW,WAAW,CAAC,MAAM,KACzC,OAAO,KAAK,WAAW,WAAW,CAAC,MAAM,GAEzC,MAAM,IAAI,MAAM,kDAAkD;MACpE,MAAM,KAAK,KAAK,IAAI,CAAC;KACvB;KACA,KAAK,KAAK,KAAK;IACjB,OAAO,IAAI;KAAC;KAAS;KAAS;IAAO,CAAC,CAAC,SAAS,MAAM,OAAO,KAAK,WAAW,MAAM,KAAK,KAAK;SACxF,MAAM,IAAI,MAAM,6BAA6B;GACpD;EACF;EACA,KAAK,IAAI;EACT,IAAI,CAAC,KAAK,UAAU,CAAC,KAAK,EAAE,CAAC,UAAU,KAAK,MAAM,MAAM,EAAE,WAAW,KAAK,EAAE,CAAC,MAAM,GACjF,MAAM,IAAI,MAAM,yCAAyC;EAC3D,OAAO,EAAE,KAAK;CAChB,SAAS,OAAO;EACd,OAAO,EAAE,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,2BAA2B;CACvF;AACF;AAKA,MAAM,gBAAgB;AACtB,SAAgB,eAAe,MAAsC,YAAwB,KAAa;CACxG,OAAO,KACJ,KAAK,QACJ,IACG,KAAK,UAAU;EACd,IACG,cAAc,KAAK,KAAK,KAAK,CAAC,mDAAmD,KAAK,KAAK,KAC5F,YAAY,KAAK,KAAK,GAEtB,QAAQ,IAAI;EACd,OAAO,aAAa,KAAK,KAAK,IAAI,IAAI,MAAM,WAAW,MAAK,MAAI,EAAE,KAAK;CACzE,CAAC,CAAC,CACD,KAAK,SAAS,CACnB,CAAC,CACA,KAAK,MAAM;AAChB;ACxGA,SAAgB,gBAAgB,SAAoB,SAAqC;CACvF,IAAI,QAAQ;CACZ,IAAI,SAAS;CACb,IAAI,QAAQ;CACZ,IAAI;CACJ,MAAM,eAAe;EACnB,IAAI,UAAU,KAAA,GAAW,aAAa,KAAK;EAC3C,QAAQ,KAAA;CACV;CACA,MAAM,cAAc;EAClB,OAAO;EACP,IAAI,MAAM,SAAS,OAAO,QAAQ,MAAM,aAAa,OAAO,UAAU;EACtE,QAAQ;EACR,QAAQ,KAAK;CACf;CACA,OAAO;EACL,OAAO,MAAiB,WAAoB,UAAkB;GAC5D,MAAM,WAAW,KAAK,aAAa,OAAO,YAAY,CAAC,KAAK,KAAK,WAAW,OAAO,IAAI;GACvF,SAAS;GACT,IAAI,UAAU,UAAU,OAAO;GAC/B,QAAQ;GACR,IAAI,CAAC,aAAa,aAAa,KAAK,UAAU,OAAO,MAAM;GAC3D,IAAI,MAAM,SAAS,KAAK,QAAQ,MAAM,aAAa,KAAK,UAAU,OAAO,OAAO;GAChF,UAAU,WAAW,OAAO,QAAQ;EACtC;EAEA,SAAS;CACX;AACF;AChCA,SAAgB,gBAAgB,MAAc,eAAe,MAAc;CACzE,IAAI;EACF,OAAO,OAAO,MAAM,cAAc,CAAC;CACrC,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,OAAO,MAAc,cAAuB,YAA4B;CAC/E,KAAK,MAAM,IAAI;CACf,MAAM,SACJ,KAAK,MAAM,+FAA+F,KAAK,CAAC;CAClH,MAAM,MAAgB,CAAC;CACvB,IAAI,SAAS;CACb,MAAM,gBAAgB,IAAI,KAAK,MAAM,KAAK,OAAO,MAAM,CAAC;CACxD,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,QAAQ,OAAO;EACrB,IAAI,UAAU,OAAO,UAAU,KAAK;GAClC,IAAI,KAAK,KAAK;GACd,IAAI,OAAO,IAAI,QAAQ,UAAU,MAAM,MAAM,MAAM;IACjD;IACA,QAAQ;GACV;EACF,OAAO,IAAI,UAAU,OAAO,UAAU,KAAK;GACzC,IAAI,OAAO,IAAI,QAAQ,UAAU,MAAM,MAAM,MAAM;IACjD;IACA,QAAQ;GACV;GACA,IAAI,KAAK,KAAK;EAChB,OAAO,IAAI,UAAU,KAAK;GACxB,IAAI,KAAK,GAAG;GACZ,QAAQ;EACV,OAAO,IAAI,UAAU,KACnB,IAAI,KAAK,IAAI;OACR,IAAI,MAAM,WAAW,IAAG,GAAG;GAChC,MAAM,QAAQ,KAAK,MAAM,KAAK;GAC9B,MAAM,UAAU,MAAM,KAAK;GAC3B,IAAI,gBAAgB,OAAO,IAAI,OAAO,OAAO,QAAQ,KAAK,OAAO,KAAK,SAAS,KAC7E,IAAI;IACF,IAAI,KAAK,OAAO,SAAS,MAAM,MAAM,CAAC;IACtC;GACF,QAAQ,CAER;GAEF,IAAI,KAAK,KAAK,UAAU,KAAK,CAAC;EAChC,OACE,IAAI,KAAK,KAAK;CAElB;CACA,OAAO,IAAI,KAAK,EAAE;AACpB;ACnDA,SAAgB,gCAAgC;CAC9C,IAAI,WAAW;CACf,IAAI,QAAQ;CACZ,IAAI,SAAS;CACb,IAAI,UAAU;CACd,IAAI,UAAU;CACd,IAAI,OAAO;CACX,QAAQ,SAA0B;EAChC,IAAI,OAAO,SAAS;EACpB,IAAI,CAAC,KAAK,WAAW,QAAQ,GAAG;GAC9B,OAAO;GACP,QAAQ;GACR,SAAS,UAAU,UAAU;GAC7B,OAAO;EACT;EACA,WAAW;EACX,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,QAAQ,KAAK;GACvC,MAAM,IAAI,KAAK;GACf,IAAI,CAAC,KAAK,KAAK,CAAC,GAAG,OAAO;GAC1B,IAAI,QAAQ;IACV,IAAI,SAAS,UAAU;SAClB,IAAI,MAAM,MAAM,UAAU;SAC1B,IAAI,MAAM,MAAK,SAAS;GAC/B,OAAO,IAAI,MAAM,MAAK,SAAS;QAC1B,IAAI,MAAM,OAAO,MAAM,KAAK;QAC5B,IAAI,MAAM,OAAO,MAAM,KAAK;IAC/B;IACA,IAAI,QAAQ,GAAG,UAAU;GAC3B;EACF;EACA,OAAO,CAAC,WAAW,CAAC,UAAU,UAAU,MAAM,SAAS,OAAO,SAAS;CACzE;AACF;AAEA,SAAgB,kBAAkB,MAAuB;CACvD,OAAO,8BAA8B,CAAC,CAAC,IAAI;AAC7C;ACpCA,SAAgB,oBAAoB;CAElC,MAAM,0BAAU,IAAI,IAAiB;CACrC,IAAI,UAAU;CACd,eAAe,QAAQ;EACrB,IAAI,SAAS;EACb,UAAU;EACV,IAAI;GACF,OAAO,QAAQ,MAAM;IACnB,MAAM,CAAC,OAAO,OAAO,QAAQ,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC;IAC9C,QAAQ,OAAO,KAAK;IACpB,IAAI;KACF,MAAM,IAAI,IAAI;KACd,IAAI,QAAQ;IACd,SAAS,OAAO;KACd,IAAI,OAAO,KAAK;IAClB;GACF;EACF,UAAU;GACR,UAAU;EACZ;CACF;CACA,OAAO;EACL,QAAQ,OAAe,KAAyC;GAC9D,QAAQ,IAAI,KAAK,CAAC,EAAE,QAAQ;GAC5B,MAAM,UAAU,IAAI,SAAe,SAAS,WAAW,QAAQ,IAAI,OAAO;IAAE;IAAK;IAAS;GAAO,CAAC,CAAC;GACnG,MAAW;GACX,OAAO;EACT;EACA,OAAO,OAAe;GACpB,QAAQ,IAAI,KAAK,CAAC,EAAE,QAAQ;GAC5B,QAAQ,OAAO,KAAK;EACtB;CACF;AACF;AAEA,MAAa,qBAAqB,kBAAkB;ACVpD,MAAM,uCAAwD,IAAI,IAAI,CAAC,UAAU,SAAS,CAAC;AAQ3F,IAAI,8BAAc,IAAI,QAAiC;AAGvD,MAAa,2CAA2C;CACtD,8BAAc,IAAI,QAAQ;AAC5B;AAQA,MAAM,kBAAkB,YAA8C;CACpE,MAAM,MAAM,QAAQ;CACpB,OAAO,KAAK,gBAAgB,KAAK,KAAK,YAAY,KAAK,CAAC;AAC1D;AAGA,MAAa,gCAAgC;AAW7C,MAAa,yBAAyB,YAAuC;CAC3E,MAAM,aAAa,eAAe,OAAO,CAAC,CAAC;CAC3C,OAAO,OAAO,eAAe,YAAY,OAAO,SAAS,UAAU,KAAK,cAAc,IAClF,aACA;AACN;AA+BA,MAAa,4BAA4B,SAA4B,WAAoB;CACvF,MAAM,OAAO,eAAe,OAAO;CACnC,MAAM,aAAa,YAAY,IAAI,OAAO;CAC1C,MAAM,cAAc,SAAS,SAAS;CAItC,MAAM,gBAAgB,KAAK,UAAU,KAAA,KAAa,KAAK,UAAU,aAAa,KAAK,UAAU;CAE7F,MAAM,UAAU,qBAAqB,IAAI,KAAK,aAAa;CAC3D,MAAM,UAAU,iBAAkB,KAAK,UAAU,eAAe,QAAQ,KAAK,QAAQ,MAAM;CAC3F,MAAM,aAAa,KAAK,2BAA2B;CACnD,IAAI,WAAW,WAAW,YAAY;CAEtC,MAAM,OAAsB;EAC1B,GAAG;EAMH,wBAAwB;CAC1B;CACA,IAAI,CAAC,SACH,KAAK,gBAAgB;CAEvB,IAAI,CAAC,eAAe;EAClB,KAAK,QAAQ;EACb,KAAK,WAAW;EAUhB,MAAM,aAAuB,KAAK,gBAAyD;EAC3F,IAAI,OAAO,eAAe,UACxB,KAAK,iBAAiB;GAAE;GAAY,GAAI,SAAS,EAAE,qBAAqB,UAAU,IAAI,CAAC;EAAG;OACrF,IAAI,QACT,KAAK,iBAAiB,EAAE,qBAAqB,UAAU;OAEvD,OAAO,KAAK;EAEd,YAAY,IAAI,SAAS,WAAW;CACtC;CACA,QAAQ,WAAW,IAAI;AACzB;ACnIA,IAAI,SAAS;AAGb,SAAgB,wBAAwB,MAAoC,SAAwC;CAClH,MAAM,QAAQ,CAAC;CACf,IAAI,QAAQ;CACZ,IAAI;CACJ,IAAI,MAAM;CACV,IAAI;CACJ,IAAI;CACJ,MAAM,eAAe;EACnB;EACA,IAAI,UAAU,KAAA,GAAW,aAAa,KAAK;EAC3C,QAAQ,KAAA;EACR,mBAAmB,OAAO,KAAK;CACjC;CACA,OAAO;EACL,OAAO,SAAyB;GAC9B,MAAM,WACJ,CAAC,YACD,SAAS,aAAa,QAAQ,YAC9B,SAAS,SAAS,QAAQ,QAC1B,CAAC,QAAQ,KAAK,WAAW,SAAS,IAAI;GACxC,MAAM,UAAU,UAAU,KAAA;GAG1B;GACA,mBAAmB,OAAO,KAAK;GAC/B,IAAI,UAAU;IACZ,MAAM;IACN,OAAO,KAAA;IACP,IAAI,UAAU,KAAA,GAAW,aAAa,KAAK;IAC3C,QAAQ,KAAA;GACV;GACA,WAAW;GACX,IAAI,CAAC,QAAQ,QAAQ;IACnB,OAAO;IACP;GACF;GACA,QAAQ;IAAE,QAAQ;IAAW;IAAK;GAAK,CAAC;GACxC,MAAM,gBAAgB;IACpB,QAAQ,KAAA;IACR,MAAM,UAAU;IAChB,MAAM,aAAa;IACnB,MAAM,cAAc,eAAe;IACnC,IAAI,QAA2B;IAC/B,KAAU,CAAC,CACR,MAAM,WAAW;KAChB,QAAQ;KACR,IAAI,CAAC,MAAM,GAAG;KACd,OAAO,mBAAmB,QAAQ,OAAO,YAAY;MACnD,IAAI,CAAC,MAAM,GAAG;MACd,yBAAyB,QAAQ,QAAQ,IAAI;MAC7C,IAAI,QAAQ,KAAK,SAAS,sBAAsB,MAAM,GACpD,MAAM,IAAI,MAAM,6CAA6C;MAC/D,MAAM,SAAS,MAAM,OAAO,MAAM,QAAQ,MAAM,EAAE,gBAAgB,KAAK,CAAC;MACxE,IAAI,CAAC,MAAM,GAAG;MACd,IAAI,WAAW,OAAO,MAAM,IAAI,MAAM,yCAAyC;MAC/E,MAAM,SAAS,MAAM,OAAO,OAAO,gBAAgB,EAAE,UAAU,QAAQ,IAAI;MAC3E,IAAI,CAAC,MAAM,GAAG;MACd,MAAM,OAAO;MACb,OAAO,OAAO;MACd,QAAQ;OAAE,QAAQ;OAAS;OAAK;MAAK,CAAC;KACxC,CAAC;IACH,CAAC,CAAC,CACD,OAAO,UAAU;KAChB,IAAI,MAAM,GACR,QAAQ;MACN,QAAQ,QAAQ,aAAa,UAAU,WAAW,YAAY;MAC9D;MACA;MACA,QACG,UAAU,SAAS,oCAAoC,OACvD,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAA,CAAG,MAAM,GAAG,GAAG;KACzE,CAAC;IACL,CAAC;GACL;GACA,IAAI,CAAC,QAAQ,aAAa,QAAQ,YAAY,GAAG;IAC/C,IAAI,UAAU,KAAA,GAAW,aAAa,KAAK;IAC3C,QAAQ;GACV,OAAO,IAAI,CAAC,WAAW,UAAU,QAAQ,WAAW,SAAS,QAAQ,QAAQ;EAC/E;EACA,SAAS;CACX;AACF;ACvGA,MAAM,wBAAQ,IAAI,QAAqD;AACvE,SAAgB,uBAAuB,QAAqD;CAC1F,IAAI,OAAO,MAAM,IAAI,MAAM;CAC3B,IAAI,CAAC,MAAM;EACT,OAAO;GAAE,OAAO;GAAG,UAAU,OAAO,MAAM;EAAS;EACnD,MAAM,IAAI,QAAQ,IAAI;CACxB;CACA,KAAK;CACL,OAAO,MAAM,WAAW;CACxB,IAAI,WAAW;CACf,aAAa;EACX,IAAI,UAAU;EACd,WAAW;EACX,IAAI,EAAE,KAAK,UAAU,GAAG;GACtB,IAAI,OAAO,MAAM,aAAa,UAAU,OAAO,MAAM,WAAW,KAAK;GACrE,MAAM,OAAO,MAAM;EACrB;CACF;AACF;ACdA,MAAa,iBAA2D;CACtE,YAAY,CAAC,qDAAqD,UAAU;CAC5E,aAAa,CAAC,qDAAqD,YAAY;CAC/E,QAAQ;EAAC;EAAyC;EAAsB;EAAe;CAAa;CACpG,SAAS;EAAC;EAAyC;EAAsB;CAAa;CACtF,OAAO,CAAC,cAAc,YAAY;CAClC,MAAM,CAAC,gBAAgB;CACvB,MAAM,CAAC,eAAe;CACtB,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;CACF;CACA,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;CACF;CACA,aAAa;EACX;EACA;EACA;CACF;CACA,OAAO,CACL,sEACA,+FACF;CACA,SAAS,CAAC,2EAA2E,2BAA2B;CAChH,SAAS;EACP;EACA;EACA;CACF;AACF;AACA,MAAa,qBAAqB;AAclC,MAAM,4BAAY,IAAI,QAA8B;AAEpD,SAAgB,gBAAgB,OAA6B;CAC3D,MAAM,WAAW,UAAU,IAAI,KAAK;CACpC,IAAI,UAAU,OAAO;CACrB,MAAM,0BAAU,IAAI,IAA8B;CAClD,MAAM,4BAAY,IAAI,IAAgB;CACtC,MAAM,eAAe,UAAU,SAAS,aAAa,SAAS,CAAC;CAC/D,MAAM,UAAwB;EAC5B,aAAa,CAAC,GAAG,QAAQ,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,MAAO,EAAE,SAAS,EAAE,EAAE,IAAI,KAAK,EAAE,SAAS,EAAE,EAAE,IAAI,IAAI,CAAE;EACpG,UAAU,UAAU;GAClB,UAAU,IAAI,QAAQ;GACtB,aAAa;IACX,UAAU,OAAO,QAAQ;GAC3B;EACF;EACA,IAAI,MAAM;GACR,MAAM,MAAM,QAAQ,IAAI,KAAK,EAAE;GAC/B,IAAI,KAAK,QAAQ,KAAK,OAAO,KAAK,QAAQ,KAAK,KAAK;GACpD,QAAQ,IAAI,KAAK,IAAI,IAAI;GACzB,OAAO;EACT;EACA,OAAO,IAAI;GACT,IAAI,QAAQ,OAAO,EAAE,GAAG,OAAO;EACjC;CACF;CACA,UAAU,IAAI,OAAO,OAAO;CAC5B,OAAO;AACT;AAEA,MAAa,oBAAyD;CACpE,OAAO;CACP,MAAM;CACN,MAAM;CACN,YAAY;CACZ,aAAa;CACb,QAAQ;CACR,SAAS;CACT,OAAO;CACP,OAAO;AACT;AClFA,MAAa,+BAA+C;CAC1D,GAAG;CACH,GAAG;CACH,QAAQ;CACR,OAAO;CACP,OAAO;CACP,OAAO;AACT;AACA,SAAgB,oBAAoB,WAAmC;CACrE,MAAM,EAAE,GAAG,GAAG,OAAO,QAAQ,OAAO,UAAU;CAC9C,OAAO,eAAe,EAAE,MAAM,EAAE,iBAAiB,QAAQ,MAAM,KAAK,MAAM,IAAI,QAAQ,MAAM,KAAK,MAAM,cAAc,OAAO;AAC9H;AACA,SAAgB,UACd,WACA,OACA,UACA,UAAU,SAAS,gBAAgB,GACnC,UAAU,SAAS,iBAAiB,GACpC,QAAQ,OACQ;CAChB,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG,OAAO;CAClD,MAAM,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI,KAAM,UAAU,QAAQ,KAAK,IAAI,KAAK,IAAI,GAAG,UAAU,QAAQ,KAAK,CAAC;CACjH,MAAM,aAAa,QAAQ,UAAU,QAAQ;CAC7C,IAAI,IAAI,UAAU,IAAI,cAAc,UAAU,UAAU,IAAI,SAAS,OAAO,SAAS,QAAQ;CAC7F,IAAI,IAAI,UAAU,IAAI,cAAc,UAAU,UAAU,IAAI,SAAS,MAAM,SAAS,SAAS;CAC7F,IACE,QAAQ,KACR,UAAU,KACV,SAAS,SAAS,SAAS,iBAC3B,SAAS,UAAU,SAAS,gBAE5B,IAAI,IAAI;CACV,OAAO;EAAE,GAAG;EAAW;EAAG;EAAG;CAAM;AACrC;AACA,SAAgB,gBAAgB,OAAuB;CACrD,MAAM,QAAQ,IAAI,KAAK,IAAI,KAAK,IAAI,QAAQ,GAAG,GAAG,CAAC,IAAI;CACvD,OAAO,QAAQ,IAAI,IAAI,QAAQ;AACjC;AAEA,SAAgB,aACd,WACA,UACA,QACgB;CAChB,IAAI,UAAU,QAAQ,GAAG,OAAO;EAAE,GAAG;EAAW,GAAG;EAAG,GAAG;EAAG,OAAO;CAAE;CACrE,MAAM,UAAU,UAAU,SAAS,QAAQ;CAC3C,MAAM,SAAS,UAAU,SAAS,SAAS,SAAS,SAAS,UAAU;CACvE,MAAM,UAAU,UAAU,SAAS,QAAQ,SAAS,UAAU,UAAU;CACxE,IAAI,SAAS,SAAS,iBAAiB,UAAU,SAAS,gBAAgB,OAAO;EAAE,GAAG;EAAW,GAAG;EAAG,GAAG;CAAE;CAC5G,MAAM,OAAO,UAAkB,OAAe,MAAc,aAAqB;EAC/E,MAAM,UAAU,OAAO,YAAY;EACnC,IAAI,OAAO,UAAU;GACnB,IAAI,QAAQ,GAAG,OAAO;GACtB,IAAI,QAAQ,KAAK,QAAQ,OAAO,UAAU,OAAO,CAAC;EACpD,OAAO,IAAI,QAAQ,KAAK,QAAQ,OAAO,UAAU,OAAO,QAAQ,IAAI,SAAS,CAAC;EAC9E,OAAO;CACT;CACA,OAAO;EACL,GAAG;EACH,GAAG,IAAI,UAAU,GAAG,OAAO,MAAM,OAAO,SAAS,aAAa;EAC9D,GAAG,IAAI,UAAU,GAAG,OAAO,KAAK,QAAQ,SAAS,cAAc;CACjE;AACF;AAEA,SAAgB,iBACd,MACA,MACA,GACA,GAC0B;CAC1B,MAAM,YAAY,KAAK,MAAM,EAAE,IAAI,KAAK,GAAG,EAAE,IAAI,KAAK,CAAC,GACrD,YAAY,KAAK,MAAM,EAAE,IAAI,KAAK,GAAG,EAAE,IAAI,KAAK,CAAC;CACnD,MAAM,QAAQ,YAAY,YAAY,aAAa,YAAY,aAAa;CAC5E,OAAO;EAAE,GAAG,KAAK,IAAI,SAAS,KAAK,IAAI,KAAK;EAAI,GAAG,KAAK,IAAI,SAAS,KAAK,IAAI,KAAK;CAAG;AACxF"}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { Element } from "hast";
|
|
2
|
+
interface CodeSource {
|
|
3
|
+
code: string;
|
|
4
|
+
language: string;
|
|
5
|
+
}
|
|
6
|
+
/** Enhance only ordinary fenced code; preserve all other pre overrides. */
|
|
7
|
+
export declare function extractCode(node?: Element): CodeSource | null;
|
|
8
|
+
export declare function normalizeRenderers<T>(renderers: Readonly<Record<string, T>>): Readonly<Record<string, T>>;
|
|
9
|
+
type TableProjection = {
|
|
10
|
+
rows: string[][];
|
|
11
|
+
reason?: undefined;
|
|
12
|
+
} | {
|
|
13
|
+
rows?: undefined;
|
|
14
|
+
reason: string;
|
|
15
|
+
};
|
|
16
|
+
/** Project sanitized HAST semantics, never custom cell UI or raw Markdown. */
|
|
17
|
+
export declare function projectTable(node?: Element): TableProjection;
|
|
18
|
+
export declare function serializeTable(rows: readonly (readonly string[])[], delimiter?: ',' | '\t'): string;
|
|
19
|
+
interface CodeFrame {
|
|
20
|
+
code: string;
|
|
21
|
+
language: string;
|
|
22
|
+
}
|
|
23
|
+
/** A trailing throttle: append bursts replace one pending frame without
|
|
24
|
+
* moving its deadline. Replacements and completion bypass the timer. */
|
|
25
|
+
export declare function createCodeFrame(initial: CodeFrame, publish: (frame: CodeFrame) => void): {
|
|
26
|
+
update(next: CodeFrame, streaming: boolean, interval: number): void;
|
|
27
|
+
dispose: () => void;
|
|
28
|
+
};
|
|
29
|
+
/** Validate with the native parser, but format lexical tokens so numbers,
|
|
30
|
+
* duplicate keys and key order never pass through JavaScript's value model.
|
|
31
|
+
* Nested JSON expansion is optional and only applies to string values. */
|
|
32
|
+
export declare function prettyPrintJson(text: string, expandNested?: boolean): string;
|
|
33
|
+
/** Bracket-balance gate, not a JSON validator. Retain quote/escape state
|
|
34
|
+
* across append seams so growing JSON does not rescan its whole body when
|
|
35
|
+
* each nested object closes. Replacements start a fresh lineage. */
|
|
36
|
+
export declare function createJsonCompletenessScanner(): (text: string) => boolean;
|
|
37
|
+
export declare function jsonLooksComplete(text: string): boolean;
|
|
38
|
+
/** Mermaid owns global configuration and a global renderer. Keep initialize,
|
|
39
|
+
* parse and render in one serialized task. Each mounted diagram retains at
|
|
40
|
+
* most one pending task; superseded frames never enter Mermaid. */
|
|
41
|
+
export declare function createRenderQueue(): {
|
|
42
|
+
enqueue(owner: object, run: () => Promise<void>): Promise<void>;
|
|
43
|
+
cancel(owner: object): void;
|
|
44
|
+
};
|
|
45
|
+
export declare const mermaidRenderQueue: {
|
|
46
|
+
enqueue(owner: object, run: () => Promise<void>): Promise<void>;
|
|
47
|
+
cancel(owner: object): void;
|
|
48
|
+
};
|
|
49
|
+
type MermaidConfig = {
|
|
50
|
+
theme?: string;
|
|
51
|
+
securityLevel?: string;
|
|
52
|
+
darkMode?: boolean;
|
|
53
|
+
suppressErrorRendering?: boolean;
|
|
54
|
+
maxTextSize?: number;
|
|
55
|
+
themeVariables?: unknown;
|
|
56
|
+
};
|
|
57
|
+
/** The part of the mermaid module this file touches. Structural so tests can
|
|
58
|
+
* pass a stub; `mermaidAPI` is deprecated in mermaid's types but present at
|
|
59
|
+
* runtime in mermaid 11, and it is the only place `getSiteConfig` /
|
|
60
|
+
* `getConfig` live (the default export has neither). */
|
|
61
|
+
type MermaidInitTarget = {
|
|
62
|
+
initialize(config: MermaidConfig): void;
|
|
63
|
+
mermaidAPI?: {
|
|
64
|
+
getSiteConfig?: () => MermaidConfig;
|
|
65
|
+
getConfig?: () => MermaidConfig;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
/** Test hook: forget the theme cache so each test starts from a cold module. */
|
|
69
|
+
export declare const resetMermaidInitializationForTests: () => void;
|
|
70
|
+
/** mermaid's own default for `maxTextSize` (`MAX_TEXTLENGTH` in mermaidAPI). */
|
|
71
|
+
export declare const MERMAID_DEFAULT_MAX_TEXT_SIZE = 50000;
|
|
72
|
+
/**
|
|
73
|
+
* The effective `maxTextSize`. `mermaid.render` does not reject oversized
|
|
74
|
+
* input: it swaps in a placeholder diagram ("Maximum text size in diagram
|
|
75
|
+
* exceeded") and resolves normally, and `mermaid.parse` has no size gate at
|
|
76
|
+
* all, so the whole text is parsed first. The renderer checks this before
|
|
77
|
+
* parsing and reports the size as an error instead. The key is in mermaid's
|
|
78
|
+
* `secure` list, so a `%%{init}%%` directive cannot raise it and the site
|
|
79
|
+
* config is the value that applies.
|
|
80
|
+
*/
|
|
81
|
+
export declare const getMermaidMaxTextSize: (mermaid: MermaidInitTarget) => number;
|
|
82
|
+
/**
|
|
83
|
+
* mermaid's config is a module-level singleton shared with the host
|
|
84
|
+
* application when the bundler dedupes the package, and a host that enables
|
|
85
|
+
* `click` interactions calls `mermaid.initialize({ securityLevel: 'loose' })`
|
|
86
|
+
* — the officially documented way. Under `loose` mermaid skips DOMPurify
|
|
87
|
+
* and its output goes into this component's `innerHTML` verbatim: an
|
|
88
|
+
* LLM-authored diagram string could then run script in the page origin.
|
|
89
|
+
* So a theme cache alone is not enough of a guard: before every render the
|
|
90
|
+
* current `securityLevel` is read back (a config copy, still far cheaper
|
|
91
|
+
* than `initialize`'s merge + theme variables + diagram registration) and an
|
|
92
|
+
* unsafe value forces a re-initialize
|
|
93
|
+
* (2026-08-19 review r2 P2-11; the v2.4.2 "documented premise" made this
|
|
94
|
+
* the host's problem — it is ours, the innerHTML is ours).
|
|
95
|
+
*
|
|
96
|
+
* In mermaid 11 `initialize` goes through `setSiteConfig`, which REPLACES
|
|
97
|
+
* the site config with defaults + the keys passed in. Calling it with only
|
|
98
|
+
* our keys wiped the host's `theme`, `fontFamily`, `flowchart` options and
|
|
99
|
+
* so on, and turned a host `sandbox` into `strict` (3.0.2 review). So:
|
|
100
|
+
* - the current site config is read back and passed through with our
|
|
101
|
+
* overrides on top, so host keys survive;
|
|
102
|
+
* - `sandbox` is accepted as is; only `loose` / `antiscript` / unset become
|
|
103
|
+
* `strict`;
|
|
104
|
+
* - a theme the host chose is kept (with its `themeVariables`); the color
|
|
105
|
+
* scheme switch only applies to the theme when the host has not chosen
|
|
106
|
+
* one, or when the current theme is one we wrote;
|
|
107
|
+
* - when nothing needs to change, `initialize` is not called at all, so a
|
|
108
|
+
* host on `strict`/`sandbox` and this component stop overwriting each
|
|
109
|
+
* other on every render.
|
|
110
|
+
*/
|
|
111
|
+
export declare const ensureMermaidInitialized: (mermaid: MermaidInitTarget, isDark: boolean) => void;
|
|
112
|
+
interface DiagramEngine extends MermaidInitTarget {
|
|
113
|
+
parse(code: string, options: {
|
|
114
|
+
suppressErrors: true;
|
|
115
|
+
}): Promise<unknown>;
|
|
116
|
+
render(id: string, code: string): Promise<{
|
|
117
|
+
svg: string;
|
|
118
|
+
bindFunctions?(element: object): void;
|
|
119
|
+
}>;
|
|
120
|
+
}
|
|
121
|
+
type DiagramState = {
|
|
122
|
+
status: 'loading' | 'ready' | 'error';
|
|
123
|
+
svg: string;
|
|
124
|
+
error?: string;
|
|
125
|
+
bind?: (element: object) => void;
|
|
126
|
+
};
|
|
127
|
+
interface DiagramRequest {
|
|
128
|
+
code: string;
|
|
129
|
+
dark: boolean;
|
|
130
|
+
streaming: boolean;
|
|
131
|
+
active: boolean;
|
|
132
|
+
resetKey: string;
|
|
133
|
+
interval: number;
|
|
134
|
+
}
|
|
135
|
+
/** Owns cancellation and retries across both UI adapters. In-flight Mermaid
|
|
136
|
+
* cannot be aborted, but obsolete work never publishes or starts a render. */
|
|
137
|
+
export declare function createDiagramController(load: () => Promise<DiagramEngine>, publish: (state: DiagramState) => void): {
|
|
138
|
+
update(request: DiagramRequest): void;
|
|
139
|
+
dispose: () => void;
|
|
140
|
+
};
|
|
141
|
+
export declare function lockImagePreviewScroll(target: {
|
|
142
|
+
style: {
|
|
143
|
+
overflow: string;
|
|
144
|
+
};
|
|
145
|
+
}): () => void;
|
|
146
|
+
/** Shared image semantics; no DOM or framework dependency. */
|
|
147
|
+
type ImageActionIconName = 'rotateLeft' | 'rotateRight' | 'zoomIn' | 'zoomOut' | 'close' | 'prev' | 'next' | 'flipX' | 'flipY';
|
|
148
|
+
type ImageIconName = 'placeholder' | 'error' | 'preview' | 'gallery' | ImageActionIconName;
|
|
149
|
+
type ImageLoadStatus = 'loading' | 'ready' | 'error';
|
|
150
|
+
/** Lucide paths supplied for the Markdown image skin (ISC license). */
|
|
151
|
+
export declare const imageIconPaths: Record<ImageIconName, readonly string[]>;
|
|
152
|
+
export declare const imageGroupSelector = "[data-aimd-image-scope], .aim-typography-root, .aimd-vue, .mantine-Typography-root";
|
|
153
|
+
interface ImageGalleryItem {
|
|
154
|
+
id: object;
|
|
155
|
+
src: string;
|
|
156
|
+
alt: string;
|
|
157
|
+
/** DOM adapters provide document ordering without leaking DOM types. */
|
|
158
|
+
precedes: (other: object) => boolean;
|
|
159
|
+
}
|
|
160
|
+
interface ImageGallery {
|
|
161
|
+
items: () => readonly ImageGalleryItem[];
|
|
162
|
+
subscribe: (listener: () => void) => () => void;
|
|
163
|
+
set: (item: ImageGalleryItem) => void;
|
|
164
|
+
remove: (id: object) => void;
|
|
165
|
+
}
|
|
166
|
+
/** Scope is an adapter-owned object, never a global document id. */
|
|
167
|
+
export declare function getImageGallery(scope: object): ImageGallery;
|
|
168
|
+
export declare const imageActionLabels: Record<ImageActionIconName, string>;
|
|
169
|
+
/** Transform rules adapted from @rc-component/image 1.10.0 (MIT).
|
|
170
|
+
* Keep the Vue adapter's gestures aligned with the upstream React engine. */
|
|
171
|
+
interface ImageTransform {
|
|
172
|
+
x: number;
|
|
173
|
+
y: number;
|
|
174
|
+
rotate: number;
|
|
175
|
+
scale: number;
|
|
176
|
+
flipX: boolean;
|
|
177
|
+
flipY: boolean;
|
|
178
|
+
}
|
|
179
|
+
interface ImageGeometry {
|
|
180
|
+
width: number;
|
|
181
|
+
height: number;
|
|
182
|
+
left: number;
|
|
183
|
+
top: number;
|
|
184
|
+
viewportWidth: number;
|
|
185
|
+
viewportHeight: number;
|
|
186
|
+
}
|
|
187
|
+
export declare const initialImageTransform: () => ImageTransform;
|
|
188
|
+
export declare function imageTransformStyle(transform: ImageTransform): string;
|
|
189
|
+
export declare function zoomImage(transform: ImageTransform, ratio: number, geometry: ImageGeometry, centerX?: number, centerY?: number, touch?: boolean): ImageTransform;
|
|
190
|
+
export declare function imageWheelRatio(delta: number): number;
|
|
191
|
+
/** Snap a moved image back inside the viewport, taking quarter turns into account. */
|
|
192
|
+
export declare function reboundImage(transform: ImageTransform, geometry: ImageGeometry, bounds: {
|
|
193
|
+
left: number;
|
|
194
|
+
top: number;
|
|
195
|
+
}): ImageTransform;
|
|
196
|
+
/** Upstream pinch center weights each finger by how far it moved. */
|
|
197
|
+
export declare function imagePinchCenter(oldA: {
|
|
198
|
+
x: number;
|
|
199
|
+
y: number;
|
|
200
|
+
}, oldB: {
|
|
201
|
+
x: number;
|
|
202
|
+
y: number;
|
|
203
|
+
}, a: {
|
|
204
|
+
x: number;
|
|
205
|
+
y: number;
|
|
206
|
+
}, b: {
|
|
207
|
+
x: number;
|
|
208
|
+
y: number;
|
|
209
|
+
}): {
|
|
210
|
+
x: number;
|
|
211
|
+
y: number;
|
|
212
|
+
};
|
|
213
|
+
export interface CodeRendererInput {
|
|
214
|
+
/** Raw accumulated source, including its trailing newline. */
|
|
215
|
+
code: string;
|
|
216
|
+
/** Explicit normalized fence language; detection never selects a renderer. */
|
|
217
|
+
language: string;
|
|
218
|
+
/** Document streaming state, not an inferred fence-completion flag. */
|
|
219
|
+
streaming: boolean;
|
|
220
|
+
colorScheme: 'light' | 'dark';
|
|
221
|
+
active: boolean;
|
|
222
|
+
/** Changes on source replacement or identity change; append preserves it. */
|
|
223
|
+
resetKey: string;
|
|
224
|
+
}
|
|
225
|
+
export interface CodeBlockOptions {
|
|
226
|
+
defaultExpanded?: boolean;
|
|
227
|
+
autoDetectUnknownLanguage?: boolean;
|
|
228
|
+
formatJson?: boolean;
|
|
229
|
+
expandNestedJson?: boolean;
|
|
230
|
+
highlightIntervalMs?: number;
|
|
231
|
+
mermaidIntervalMs?: number;
|
|
232
|
+
}
|
|
233
|
+
export type { CodeFrame, CodeSource, DiagramEngine, DiagramRequest, DiagramState, ImageActionIconName, ImageGallery, ImageGalleryItem, ImageGeometry, ImageIconName, ImageLoadStatus, ImageTransform, MermaidInitTarget, TableProjection };
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { Element } from "hast";
|
|
2
|
+
interface CodeSource {
|
|
3
|
+
code: string;
|
|
4
|
+
language: string;
|
|
5
|
+
}
|
|
6
|
+
/** Enhance only ordinary fenced code; preserve all other pre overrides. */
|
|
7
|
+
export declare function extractCode(node?: Element): CodeSource | null;
|
|
8
|
+
export declare function normalizeRenderers<T>(renderers: Readonly<Record<string, T>>): Readonly<Record<string, T>>;
|
|
9
|
+
type TableProjection = {
|
|
10
|
+
rows: string[][];
|
|
11
|
+
reason?: undefined;
|
|
12
|
+
} | {
|
|
13
|
+
rows?: undefined;
|
|
14
|
+
reason: string;
|
|
15
|
+
};
|
|
16
|
+
/** Project sanitized HAST semantics, never custom cell UI or raw Markdown. */
|
|
17
|
+
export declare function projectTable(node?: Element): TableProjection;
|
|
18
|
+
export declare function serializeTable(rows: readonly (readonly string[])[], delimiter?: ',' | '\t'): string;
|
|
19
|
+
interface CodeFrame {
|
|
20
|
+
code: string;
|
|
21
|
+
language: string;
|
|
22
|
+
}
|
|
23
|
+
/** A trailing throttle: append bursts replace one pending frame without
|
|
24
|
+
* moving its deadline. Replacements and completion bypass the timer. */
|
|
25
|
+
export declare function createCodeFrame(initial: CodeFrame, publish: (frame: CodeFrame) => void): {
|
|
26
|
+
update(next: CodeFrame, streaming: boolean, interval: number): void;
|
|
27
|
+
dispose: () => void;
|
|
28
|
+
};
|
|
29
|
+
/** Validate with the native parser, but format lexical tokens so numbers,
|
|
30
|
+
* duplicate keys and key order never pass through JavaScript's value model.
|
|
31
|
+
* Nested JSON expansion is optional and only applies to string values. */
|
|
32
|
+
export declare function prettyPrintJson(text: string, expandNested?: boolean): string;
|
|
33
|
+
/** Bracket-balance gate, not a JSON validator. Retain quote/escape state
|
|
34
|
+
* across append seams so growing JSON does not rescan its whole body when
|
|
35
|
+
* each nested object closes. Replacements start a fresh lineage. */
|
|
36
|
+
export declare function createJsonCompletenessScanner(): (text: string) => boolean;
|
|
37
|
+
export declare function jsonLooksComplete(text: string): boolean;
|
|
38
|
+
/** Mermaid owns global configuration and a global renderer. Keep initialize,
|
|
39
|
+
* parse and render in one serialized task. Each mounted diagram retains at
|
|
40
|
+
* most one pending task; superseded frames never enter Mermaid. */
|
|
41
|
+
export declare function createRenderQueue(): {
|
|
42
|
+
enqueue(owner: object, run: () => Promise<void>): Promise<void>;
|
|
43
|
+
cancel(owner: object): void;
|
|
44
|
+
};
|
|
45
|
+
export declare const mermaidRenderQueue: {
|
|
46
|
+
enqueue(owner: object, run: () => Promise<void>): Promise<void>;
|
|
47
|
+
cancel(owner: object): void;
|
|
48
|
+
};
|
|
49
|
+
type MermaidConfig = {
|
|
50
|
+
theme?: string;
|
|
51
|
+
securityLevel?: string;
|
|
52
|
+
darkMode?: boolean;
|
|
53
|
+
suppressErrorRendering?: boolean;
|
|
54
|
+
maxTextSize?: number;
|
|
55
|
+
themeVariables?: unknown;
|
|
56
|
+
};
|
|
57
|
+
/** The part of the mermaid module this file touches. Structural so tests can
|
|
58
|
+
* pass a stub; `mermaidAPI` is deprecated in mermaid's types but present at
|
|
59
|
+
* runtime in mermaid 11, and it is the only place `getSiteConfig` /
|
|
60
|
+
* `getConfig` live (the default export has neither). */
|
|
61
|
+
type MermaidInitTarget = {
|
|
62
|
+
initialize(config: MermaidConfig): void;
|
|
63
|
+
mermaidAPI?: {
|
|
64
|
+
getSiteConfig?: () => MermaidConfig;
|
|
65
|
+
getConfig?: () => MermaidConfig;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
/** Test hook: forget the theme cache so each test starts from a cold module. */
|
|
69
|
+
export declare const resetMermaidInitializationForTests: () => void;
|
|
70
|
+
/** mermaid's own default for `maxTextSize` (`MAX_TEXTLENGTH` in mermaidAPI). */
|
|
71
|
+
export declare const MERMAID_DEFAULT_MAX_TEXT_SIZE = 50000;
|
|
72
|
+
/**
|
|
73
|
+
* The effective `maxTextSize`. `mermaid.render` does not reject oversized
|
|
74
|
+
* input: it swaps in a placeholder diagram ("Maximum text size in diagram
|
|
75
|
+
* exceeded") and resolves normally, and `mermaid.parse` has no size gate at
|
|
76
|
+
* all, so the whole text is parsed first. The renderer checks this before
|
|
77
|
+
* parsing and reports the size as an error instead. The key is in mermaid's
|
|
78
|
+
* `secure` list, so a `%%{init}%%` directive cannot raise it and the site
|
|
79
|
+
* config is the value that applies.
|
|
80
|
+
*/
|
|
81
|
+
export declare const getMermaidMaxTextSize: (mermaid: MermaidInitTarget) => number;
|
|
82
|
+
/**
|
|
83
|
+
* mermaid's config is a module-level singleton shared with the host
|
|
84
|
+
* application when the bundler dedupes the package, and a host that enables
|
|
85
|
+
* `click` interactions calls `mermaid.initialize({ securityLevel: 'loose' })`
|
|
86
|
+
* — the officially documented way. Under `loose` mermaid skips DOMPurify
|
|
87
|
+
* and its output goes into this component's `innerHTML` verbatim: an
|
|
88
|
+
* LLM-authored diagram string could then run script in the page origin.
|
|
89
|
+
* So a theme cache alone is not enough of a guard: before every render the
|
|
90
|
+
* current `securityLevel` is read back (a config copy, still far cheaper
|
|
91
|
+
* than `initialize`'s merge + theme variables + diagram registration) and an
|
|
92
|
+
* unsafe value forces a re-initialize
|
|
93
|
+
* (2026-08-19 review r2 P2-11; the v2.4.2 "documented premise" made this
|
|
94
|
+
* the host's problem — it is ours, the innerHTML is ours).
|
|
95
|
+
*
|
|
96
|
+
* In mermaid 11 `initialize` goes through `setSiteConfig`, which REPLACES
|
|
97
|
+
* the site config with defaults + the keys passed in. Calling it with only
|
|
98
|
+
* our keys wiped the host's `theme`, `fontFamily`, `flowchart` options and
|
|
99
|
+
* so on, and turned a host `sandbox` into `strict` (3.0.2 review). So:
|
|
100
|
+
* - the current site config is read back and passed through with our
|
|
101
|
+
* overrides on top, so host keys survive;
|
|
102
|
+
* - `sandbox` is accepted as is; only `loose` / `antiscript` / unset become
|
|
103
|
+
* `strict`;
|
|
104
|
+
* - a theme the host chose is kept (with its `themeVariables`); the color
|
|
105
|
+
* scheme switch only applies to the theme when the host has not chosen
|
|
106
|
+
* one, or when the current theme is one we wrote;
|
|
107
|
+
* - when nothing needs to change, `initialize` is not called at all, so a
|
|
108
|
+
* host on `strict`/`sandbox` and this component stop overwriting each
|
|
109
|
+
* other on every render.
|
|
110
|
+
*/
|
|
111
|
+
export declare const ensureMermaidInitialized: (mermaid: MermaidInitTarget, isDark: boolean) => void;
|
|
112
|
+
interface DiagramEngine extends MermaidInitTarget {
|
|
113
|
+
parse(code: string, options: {
|
|
114
|
+
suppressErrors: true;
|
|
115
|
+
}): Promise<unknown>;
|
|
116
|
+
render(id: string, code: string): Promise<{
|
|
117
|
+
svg: string;
|
|
118
|
+
bindFunctions?(element: object): void;
|
|
119
|
+
}>;
|
|
120
|
+
}
|
|
121
|
+
type DiagramState = {
|
|
122
|
+
status: 'loading' | 'ready' | 'error';
|
|
123
|
+
svg: string;
|
|
124
|
+
error?: string;
|
|
125
|
+
bind?: (element: object) => void;
|
|
126
|
+
};
|
|
127
|
+
interface DiagramRequest {
|
|
128
|
+
code: string;
|
|
129
|
+
dark: boolean;
|
|
130
|
+
streaming: boolean;
|
|
131
|
+
active: boolean;
|
|
132
|
+
resetKey: string;
|
|
133
|
+
interval: number;
|
|
134
|
+
}
|
|
135
|
+
/** Owns cancellation and retries across both UI adapters. In-flight Mermaid
|
|
136
|
+
* cannot be aborted, but obsolete work never publishes or starts a render. */
|
|
137
|
+
export declare function createDiagramController(load: () => Promise<DiagramEngine>, publish: (state: DiagramState) => void): {
|
|
138
|
+
update(request: DiagramRequest): void;
|
|
139
|
+
dispose: () => void;
|
|
140
|
+
};
|
|
141
|
+
export declare function lockImagePreviewScroll(target: {
|
|
142
|
+
style: {
|
|
143
|
+
overflow: string;
|
|
144
|
+
};
|
|
145
|
+
}): () => void;
|
|
146
|
+
/** Shared image semantics; no DOM or framework dependency. */
|
|
147
|
+
type ImageActionIconName = 'rotateLeft' | 'rotateRight' | 'zoomIn' | 'zoomOut' | 'close' | 'prev' | 'next' | 'flipX' | 'flipY';
|
|
148
|
+
type ImageIconName = 'placeholder' | 'error' | 'preview' | 'gallery' | ImageActionIconName;
|
|
149
|
+
type ImageLoadStatus = 'loading' | 'ready' | 'error';
|
|
150
|
+
/** Lucide paths supplied for the Markdown image skin (ISC license). */
|
|
151
|
+
export declare const imageIconPaths: Record<ImageIconName, readonly string[]>;
|
|
152
|
+
export declare const imageGroupSelector = "[data-aimd-image-scope], .aim-typography-root, .aimd-vue, .mantine-Typography-root";
|
|
153
|
+
interface ImageGalleryItem {
|
|
154
|
+
id: object;
|
|
155
|
+
src: string;
|
|
156
|
+
alt: string;
|
|
157
|
+
/** DOM adapters provide document ordering without leaking DOM types. */
|
|
158
|
+
precedes: (other: object) => boolean;
|
|
159
|
+
}
|
|
160
|
+
interface ImageGallery {
|
|
161
|
+
items: () => readonly ImageGalleryItem[];
|
|
162
|
+
subscribe: (listener: () => void) => () => void;
|
|
163
|
+
set: (item: ImageGalleryItem) => void;
|
|
164
|
+
remove: (id: object) => void;
|
|
165
|
+
}
|
|
166
|
+
/** Scope is an adapter-owned object, never a global document id. */
|
|
167
|
+
export declare function getImageGallery(scope: object): ImageGallery;
|
|
168
|
+
export declare const imageActionLabels: Record<ImageActionIconName, string>;
|
|
169
|
+
/** Transform rules adapted from @rc-component/image 1.10.0 (MIT).
|
|
170
|
+
* Keep the Vue adapter's gestures aligned with the upstream React engine. */
|
|
171
|
+
interface ImageTransform {
|
|
172
|
+
x: number;
|
|
173
|
+
y: number;
|
|
174
|
+
rotate: number;
|
|
175
|
+
scale: number;
|
|
176
|
+
flipX: boolean;
|
|
177
|
+
flipY: boolean;
|
|
178
|
+
}
|
|
179
|
+
interface ImageGeometry {
|
|
180
|
+
width: number;
|
|
181
|
+
height: number;
|
|
182
|
+
left: number;
|
|
183
|
+
top: number;
|
|
184
|
+
viewportWidth: number;
|
|
185
|
+
viewportHeight: number;
|
|
186
|
+
}
|
|
187
|
+
export declare const initialImageTransform: () => ImageTransform;
|
|
188
|
+
export declare function imageTransformStyle(transform: ImageTransform): string;
|
|
189
|
+
export declare function zoomImage(transform: ImageTransform, ratio: number, geometry: ImageGeometry, centerX?: number, centerY?: number, touch?: boolean): ImageTransform;
|
|
190
|
+
export declare function imageWheelRatio(delta: number): number;
|
|
191
|
+
/** Snap a moved image back inside the viewport, taking quarter turns into account. */
|
|
192
|
+
export declare function reboundImage(transform: ImageTransform, geometry: ImageGeometry, bounds: {
|
|
193
|
+
left: number;
|
|
194
|
+
top: number;
|
|
195
|
+
}): ImageTransform;
|
|
196
|
+
/** Upstream pinch center weights each finger by how far it moved. */
|
|
197
|
+
export declare function imagePinchCenter(oldA: {
|
|
198
|
+
x: number;
|
|
199
|
+
y: number;
|
|
200
|
+
}, oldB: {
|
|
201
|
+
x: number;
|
|
202
|
+
y: number;
|
|
203
|
+
}, a: {
|
|
204
|
+
x: number;
|
|
205
|
+
y: number;
|
|
206
|
+
}, b: {
|
|
207
|
+
x: number;
|
|
208
|
+
y: number;
|
|
209
|
+
}): {
|
|
210
|
+
x: number;
|
|
211
|
+
y: number;
|
|
212
|
+
};
|
|
213
|
+
export interface CodeRendererInput {
|
|
214
|
+
/** Raw accumulated source, including its trailing newline. */
|
|
215
|
+
code: string;
|
|
216
|
+
/** Explicit normalized fence language; detection never selects a renderer. */
|
|
217
|
+
language: string;
|
|
218
|
+
/** Document streaming state, not an inferred fence-completion flag. */
|
|
219
|
+
streaming: boolean;
|
|
220
|
+
colorScheme: 'light' | 'dark';
|
|
221
|
+
active: boolean;
|
|
222
|
+
/** Changes on source replacement or identity change; append preserves it. */
|
|
223
|
+
resetKey: string;
|
|
224
|
+
}
|
|
225
|
+
export interface CodeBlockOptions {
|
|
226
|
+
defaultExpanded?: boolean;
|
|
227
|
+
autoDetectUnknownLanguage?: boolean;
|
|
228
|
+
formatJson?: boolean;
|
|
229
|
+
expandNestedJson?: boolean;
|
|
230
|
+
highlightIntervalMs?: number;
|
|
231
|
+
mermaidIntervalMs?: number;
|
|
232
|
+
}
|
|
233
|
+
export type { CodeFrame, CodeSource, DiagramEngine, DiagramRequest, DiagramState, ImageActionIconName, ImageGallery, ImageGalleryItem, ImageGeometry, ImageIconName, ImageLoadStatus, ImageTransform, MermaidInitTarget, TableProjection };
|