tiptap-markdown-react 0.11.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -4
- package/dist/{ReportContent-By-tSiNn.js → ReportContent-CfvE4CYH.js} +6 -6
- package/dist/{ReportContent-By-tSiNn.js.map → ReportContent-CfvE4CYH.js.map} +1 -1
- package/dist/components/FindReplaceBar.d.ts +4 -2
- package/dist/components/MarkdownWysiwygEditor.d.ts +35 -6
- package/dist/{extractToc-CB4RYsMJ.js → extractToc-BT3OquOq.js} +2 -2
- package/dist/{extractToc-CB4RYsMJ.js.map → extractToc-BT3OquOq.js.map} +1 -1
- package/dist/icons/index.d.ts +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +178 -121
- package/dist/index.js.map +1 -1
- package/dist/reader.js +2 -2
- package/dist/{scrollToTocHeading-EkePiWil.js → scrollToTocHeading-DVdii3VR.js} +2 -2
- package/dist/{scrollToTocHeading-EkePiWil.js.map → scrollToTocHeading-DVdii3VR.js.map} +1 -1
- package/dist/server.js +4 -4
- package/dist/style.css +109 -87
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/components/CitationRefView.tsx","../src/createCitationRef.ts","../src/commentAnchor/commentAnchorPlugin.ts","../src/commentAnchor/commentAnchorController.ts","../src/findReplace.ts","../src/icons/index.tsx","../src/labels.ts","../src/components/FindReplaceBar.tsx","../src/importPlaceholder.ts","../src/markdownFileDrop.ts","../src/pendingAnchor.ts","../src/selectionKind.ts","../src/markdownPaste.ts","../src/components/ChartView.tsx","../src/chart/createChart.ts","../src/components/CodeBlockView.tsx","../src/components/MarkdownWysiwygEditor.tsx","../src/components/MarkdownPreview.tsx","../src/importMenu.ts","../src/insertMarkdown.ts","../src/tableSelection.ts","../src/components/ColorPalette.tsx","../src/components/MathEditorPopover.tsx","../src/components/EditorToolbar.tsx","../src/hooks/useIsMobile.ts","../src/components/TocPanel.tsx","../src/commentAnchor/CommentPopover.tsx","../src/anchorRange.ts","../src/markdownRange.ts","../src/normalizeMarkdown.ts","../src/replaceRange.ts"],"sourcesContent":["'use client';\n\nimport {\n NodeViewWrapper,\n type NodeViewProps,\n} from '@tiptap/react';\nimport type { RenderCitation } from '../citationTypes';\n\n/**\n * 脚注圆标 React NodeView。\n * 无 `renderCitation` 时渲默认 pill(有 url 则可点);有插槽时把 defaultDom 交给消费方。\n */\nexport function CitationRefView({ node, extension }: NodeViewProps) {\n const index = String(node.attrs.index ?? '');\n const url = (node.attrs.url as string | null) || null;\n const title = (node.attrs.title as string | null) || '';\n const renderCitation = extension.options.renderCitation as\n | RenderCitation\n | undefined;\n\n const pill = (\n <span\n className=\"citation-ref\"\n data-index={index}\n {...(url ? { 'data-url': url } : {})}\n {...(title ? { 'data-title': title } : {})}\n >\n {!renderCitation && url ? (\n <a\n href={url}\n title={title}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {index}\n </a>\n ) : (\n index\n )}\n </span>\n );\n\n const content = renderCitation\n ? renderCitation({\n index,\n attrs: { index, url, title: title || null },\n defaultDom: pill,\n })\n : pill;\n\n return (\n <NodeViewWrapper\n as=\"span\"\n data-citation-ref=\"\"\n style={{ display: 'inline' }}\n >\n {content}\n </NodeViewWrapper>\n );\n}\n","'use client';\n\nimport { ReactNodeViewRenderer } from '@tiptap/react';\nimport { CitationRef, type CitationRefOptions } from './CitationRef';\nimport type { RenderCitation } from './citationTypes';\nimport { CitationRefView } from './components/CitationRefView';\n\nexport type CitationRefViewOptions = CitationRefOptions & {\n renderCitation?: RenderCitation;\n};\n\n/**\n * 客户端增强版 CitationRef:挂 React NodeView,支持 `renderCitation` 插槽。\n * server / SSR 请继续用纯 {@link CitationRef}(无 React)。\n */\nexport function createCitationRef(\n options: { renderCitation?: RenderCitation } = {},\n) {\n return CitationRef.extend<CitationRefViewOptions>({\n addOptions() {\n return {\n HTMLAttributes: {},\n ...this.parent?.(),\n renderCitation: options.renderCitation,\n };\n },\n addNodeView() {\n return ReactNodeViewRenderer(CitationRefView);\n },\n }).configure({\n renderCitation: options.renderCitation,\n });\n}\n","/**\n * 评论锚定客户端插件:\n * - 装饰:block 左缘 gutter 气泡(showGutter)、active 评论的 mark/block 高亮;\n * - 交互:点击 mark / gutter 通过 transaction meta 上报(宿主经 editor.on('transaction')\n * 接收,规避扩展创建时闭包 stale 的问题);\n * - 守卫:粘贴 / 拖拽的 slice 剥离 commentAnchor mark,防止幽灵高亮。\n *\n * 只读态(MarkdownPreview)不注入本插件、不接评论 —— 评论是编辑会话专属。\n */\n\nimport {\n Fragment,\n Slice,\n type MarkType,\n type Node as PMNode,\n} from '@tiptap/pm/model';\nimport { Extension } from '@tiptap/core';\nimport {\n Plugin,\n PluginKey,\n type EditorState,\n} from '@tiptap/pm/state';\nimport {\n Decoration,\n DecorationSet,\n type EditorView,\n} from '@tiptap/pm/view';\nimport type { CommentClickPayload } from './commentTypes';\n\nexport const COMMENT_ACTIVE_META = 'tmr:comment:active';\nexport const COMMENT_CLICK_META = 'tmr:comment:click';\nexport const COMMENT_GUTTER_META = 'tmr:comment:gutter';\n\nexport interface CommentGutterPayload {\n commentIds: string[];\n pos: number;\n}\n\nexport interface CommentAnchorPluginOptions {\n /** 是否在 block 左缘渲染评论 gutter 气泡,默认 true。 */\n showGutter?: boolean;\n /**\n * 编辑器内点 mark 是否参与交互(默认 true:设 active + 上报 click meta)。\n * 设 false 后点击 mark 完全惰性(不设 active、不上报),适合「只靠侧栏单项\n * 驱动滚动定位」的宿主。\n */\n interactive?: boolean;\n}\n\nexport interface CommentAnchorPluginState {\n activeCommentId: string | null;\n}\n\nexport const commentAnchorPluginKey = new PluginKey<CommentAnchorPluginState>(\n 'tmrCommentAnchor',\n);\n\n/** 从 Slice 中剔除 commentAnchor mark(粘贴/拖拽守卫)。 */\nexport function stripCommentAnchorMarks(\n slice: Slice,\n markType: MarkType,\n): Slice {\n const strip = (fragment: Fragment): Fragment => {\n const children: PMNode[] = [];\n fragment.forEach((child) => {\n if (child.isText && child.marks.some((m) => m.type === markType)) {\n children.push(\n child.mark(child.marks.filter((m) => m.type !== markType)),\n );\n } else if (child.content.size > 0) {\n children.push(child.copy(strip(child.content)));\n } else {\n children.push(child);\n }\n });\n return Fragment.fromArray(children);\n };\n return new Slice(strip(slice.content), slice.openStart, slice.openEnd);\n}\n\nfunction sliceHasCommentMarks(slice: Slice, markType: MarkType): boolean {\n let found = false;\n slice.content.descendants((node) => {\n if (node.isText && node.marks.some((m) => m.type === markType)) {\n found = true;\n return false;\n }\n return true;\n });\n return found;\n}\n\n/** 顶层 block 边界。 */\nfunction blockBounds(doc: PMNode): Array<{ start: number; end: number }> {\n const bounds: Array<{ start: number; end: number }> = [];\n doc.forEach((child, offset) => {\n bounds.push({ start: offset, end: offset + child.nodeSize });\n });\n return bounds;\n}\n\n/** commentId → 文本区间(从 doc 内 commentAnchor mark 收集)。 */\nfunction collectCommentRanges(\n doc: PMNode,\n): Map<string, Array<{ from: number; to: number }>> {\n const byId = new Map<string, Array<{ from: number; to: number }>>();\n doc.descendants((node, pos) => {\n if (!node.isText) return true;\n for (const m of node.marks) {\n if (m.type.name !== 'commentAnchor') continue;\n const ids = (m.attrs.commentIds as string[]) ?? [];\n for (const id of ids) {\n const arr = byId.get(id) ?? [];\n arr.push({ from: pos, to: pos + node.nodeSize });\n byId.set(id, arr);\n }\n }\n return true;\n });\n return byId;\n}\n\nfunction rangesIntersectBlock(\n ranges: Array<{ from: number; to: number }>,\n start: number,\n end: number,\n): boolean {\n return ranges.some((r) => r.from < end && r.to > start);\n}\n\nfunction gutterDom(\n commentIds: string[],\n view: EditorView,\n blockPos: number,\n): HTMLElement {\n const el = document.createElement('span');\n el.className = 'tmr-comment-gutter';\n el.setAttribute('data-comment-ids', commentIds.join(' '));\n el.textContent = String(commentIds.length);\n el.title = `${commentIds.length}`;\n // 不抢编辑器焦点/选区\n el.addEventListener('mousedown', (e) => {\n e.preventDefault();\n e.stopPropagation();\n });\n el.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n view.dispatch(\n view.state.tr\n .setMeta(COMMENT_ACTIVE_META, commentIds[0] ?? null)\n .setMeta(COMMENT_GUTTER_META, {\n commentIds,\n pos: blockPos,\n } satisfies CommentGutterPayload),\n );\n });\n return el;\n}\n\nexport function commentAnchorPlugin(\n options: CommentAnchorPluginOptions = {},\n): Plugin<CommentAnchorPluginState> {\n const showGutter = options.showGutter !== false;\n const interactive = options.interactive !== false;\n\n return new Plugin<CommentAnchorPluginState>({\n key: commentAnchorPluginKey,\n state: {\n init: () => ({ activeCommentId: null }),\n apply: (tr, value) => {\n const active = tr.getMeta(COMMENT_ACTIVE_META);\n return active !== undefined\n ? { activeCommentId: active as string | null }\n : value;\n },\n },\n props: {\n decorations(state: EditorState) {\n const byId = collectCommentRanges(state.doc);\n if (byId.size === 0) return DecorationSet.empty;\n\n const decos: Decoration[] = [];\n const bounds = blockBounds(state.doc);\n\n if (showGutter) {\n for (const b of bounds) {\n const idsInBlock: string[] = [];\n for (const [id, ranges] of byId) {\n if (rangesIntersectBlock(ranges, b.start, b.end)) {\n idsInBlock.push(id);\n }\n }\n if (idsInBlock.length > 0) {\n decos.push(\n Decoration.widget(\n b.start,\n (view) => gutterDom(idsInBlock, view, b.start),\n { side: -1, key: `tmr-gutter:${b.start}` },\n ),\n );\n }\n }\n }\n\n const activeId =\n commentAnchorPluginKey.getState(state)?.activeCommentId ?? null;\n if (activeId) {\n const ranges = byId.get(activeId) ?? [];\n for (const r of ranges) {\n decos.push(\n Decoration.inline(r.from, r.to, { class: 'tmr-comment-active' }),\n );\n }\n for (const b of bounds) {\n if (rangesIntersectBlock(ranges, b.start, b.end)) {\n decos.push(\n Decoration.node(b.start, b.end, {\n class: 'tmr-comment-block-active',\n }),\n );\n }\n }\n }\n\n return DecorationSet.create(state.doc, decos);\n },\n\n handleClick(view: EditorView, pos: number, event: MouseEvent) {\n // 惰性模式:编辑器内点击 mark 不产生任何交互(侧栏单项驱动)。\n if (!interactive) return false;\n const target = event.target as Element | null;\n const el = target?.closest?.(\n 'mark.tmr-comment[data-comment-ids]',\n ) as HTMLElement | null;\n if (!el) return false;\n const commentIds = (el.getAttribute('data-comment-ids') ?? '')\n .split(' ')\n .filter(Boolean);\n if (commentIds.length === 0) return false;\n view.dispatch(\n view.state.tr\n .setMeta(COMMENT_ACTIVE_META, commentIds[0] ?? null)\n .setMeta(COMMENT_CLICK_META, {\n commentIds,\n anchorEl: el,\n pos,\n } satisfies CommentClickPayload),\n );\n return true;\n },\n\n // 粘贴 / 拖拽 / 编辑器内拖动的 slice 统一走这里:剥离评论 mark,\n // 防止复制粘贴产生幽灵高亮。正文内容不变,只是丢掉会话级元数据。\n transformPasted(slice: Slice, view: EditorView) {\n const markType = view.state.schema.marks.commentAnchor;\n if (!markType || !sliceHasCommentMarks(slice, markType)) return slice;\n return stripCommentAnchorMarks(slice, markType);\n },\n },\n });\n}\n\n/**\n * Tiptap Extension 包装:把评论锚定 Plugin 挂进 useEditor / Editor 的 extensions。\n * 只读态(MarkdownPreview)不要注入本扩展 —— 评论是编辑会话专属。\n */\nexport function commentAnchorExtension(\n options: CommentAnchorPluginOptions = {},\n) {\n return Extension.create({\n name: 'tmrCommentAnchor',\n addProseMirrorPlugins() {\n return [commentAnchorPlugin(options)];\n },\n });\n}\n","/**\n * 编辑会话内的评论锚定控制器(纯函数,供宿主 / 组件 handle 复用)。\n *\n * 职责:\n * - applyCommentAnchorsToEditor:comments 装载时把 segments 映射成 mark 铺入 doc;\n * - focusComment / nextComment:active 状态 + 滚动 + 选区;\n * - collectCommentIds / commentRangesById:供宿主查询。\n */\n\nimport type { Editor } from '@tiptap/core';\nimport {\n COMMENT_ACTIVE_META,\n commentAnchorPluginKey,\n} from './commentAnchorPlugin';\nimport {\n mapCommentAnchors,\n mergeCommentIntervals,\n type CommentRange,\n} from './commentMapper';\nimport type { CommentRef } from './commentTypes';\n\n/** 先清后铺,幂等;无评论时清空全部 mark。 */\nexport function applyCommentAnchorsToEditor(\n editor: Editor,\n comments: CommentRef[],\n): void {\n // 只读态不接评论(库契约:评论锚定 = 编辑会话专属)。\n if (!editor.isEditable) return;\n const intervals =\n comments.length > 0\n ? mergeCommentIntervals(\n mapCommentAnchors(\n editor.state.doc,\n comments.map((c) => ({ commentId: c.commentId, segments: c.segments })),\n ).map((r) => ({ commentId: r.commentId, ranges: r.ranges })),\n )\n : [];\n const chain = editor.chain().clearCommentAnchors();\n if (intervals.length > 0) chain.applyCommentAnchors(intervals);\n chain.run();\n}\n\n/** 文档顺序去重的 commentId 列表(gutter / 导航顺序)。 */\nexport function collectCommentIds(editor: Editor): string[] {\n const ids: string[] = [];\n editor.state.doc.descendants((node) => {\n if (!node.isText) return true;\n for (const m of node.marks) {\n if (m.type.name !== 'commentAnchor') continue;\n for (const id of (m.attrs.commentIds as string[]) ?? []) {\n if (!ids.includes(id)) ids.push(id);\n }\n }\n return true;\n });\n return ids;\n}\n\nexport function commentRangesById(\n editor: Editor,\n commentId: string,\n): CommentRange[] {\n const ranges: CommentRange[] = [];\n editor.state.doc.descendants((node, pos) => {\n if (!node.isText) return true;\n for (const m of node.marks) {\n if (m.type.name !== 'commentAnchor') continue;\n const ids = (m.attrs.commentIds as string[]) ?? [];\n if (ids.includes(commentId)) {\n ranges.push({ from: pos, to: pos + node.nodeSize });\n }\n }\n return true;\n });\n return ranges;\n}\n\nfunction setActive(editor: Editor, commentId: string | null): void {\n editor.view.dispatch(\n editor.state.tr.setMeta(COMMENT_ACTIVE_META, commentId),\n );\n}\n\nfunction getActive(editor: Editor): string | null {\n return commentAnchorPluginKey.getState(editor.state)?.activeCommentId ?? null;\n}\n\n/**\n * 聚焦某条评论:设置 active(mark/block 高亮)+ 滚动到第一个 mark + 光标落到\n * 区间起点。找不到(outdated)时清空 active 并返回 false。\n */\nexport function focusComment(editor: Editor, commentId: string): boolean {\n const ranges = commentRangesById(editor, commentId);\n if (ranges.length === 0) {\n setActive(editor, null);\n return false;\n }\n setActive(editor, commentId);\n const markEl = editor.view.dom.querySelector<HTMLElement>(\n `mark.tmr-comment[data-comment-ids~=\"${CSS.escape(commentId)}\"]`,\n );\n markEl?.scrollIntoView?.({ block: 'center', behavior: 'smooth' });\n editor.chain().setTextSelection(ranges[0].from).run();\n return true;\n}\n\n/** 按文档顺序在评论间循环跳转(dir: next / prev)。 */\nexport function nextComment(\n editor: Editor,\n dir: 'next' | 'prev' = 'next',\n): string | null {\n const ids = collectCommentIds(editor);\n if (ids.length === 0) return null;\n const active = getActive(editor);\n const current = active ? ids.indexOf(active) : -1;\n const nextIdx =\n dir === 'next'\n ? (current + 1) % ids.length\n : (current - 1 + ids.length) % ids.length;\n const target = ids[nextIdx];\n focusComment(editor, target);\n return target;\n}\n","/**\n * 查找替换的适配层。\n *\n * 匹配 / 高亮 / 替换全部由官方 `@tiptap/extension-find-and-replace` 承担(命令 + storage +\n * decoration),宿主与 AI 侧可以直接用 `editor.commands.setSearchTerm / replaceAll …`。\n * 这个文件只收拾 Tiptap 3.31.3 上的一个坑,以及库内的默认防抖。\n */\n\n/**\n * 输入防抖(毫秒)。\n *\n * 注意:注册扩展时必须把官方选项 `searchDebounceMs` 设为 **0**。官方防抖走 `setTimeout`,\n * 真正的 dispatch 发生在异步回调里,下面 `runFindCommand` 的守卫就兜不住那次抛错。\n * 防抖改由调用方(浮动条)自己做,语义一样但全程同步。\n */\nexport const FIND_DEBOUNCE_MS = 120;\n\nconst MISMATCH_RE = /Applying a mismatched transaction/;\n\n/**\n * 跑一条官方查找替换命令,兜掉 Tiptap 3.31.3 的一处事务错配。\n *\n * 成因:官方扩展的 `setSearchTerm` 不走 CommandManager 给的 dispatch,而是自己\n * `editor.state.tr` + `view.dispatch`(见扩展 dist 的 `applySearchTerm`)。CommandManager\n * 在命令结束后仍会派发它「命令开始时创建」的那个 tr。若这次派发触发了 TrailingNode 的\n * appendTransaction(**文末是代码块 / 表格 / 图表**时它会补一个空段落,starter-kit 自带),\n * doc 已经前进,那个旧 tr 的 `before` 就对不上当前 doc → `RangeError: Applying a mismatched\n * transaction`。\n *\n * 此时查询其实已经生效(扩展自己那次 dispatch 成功了、尾段落也补上了),只是紧随其后的\n * 第二次派发炸掉。所以捕获这一种错并重试一次即可收敛——重试时文末空段落已在,TrailingNode\n * 不再插手。其它错误照抛,不吞。\n */\nexport function runFindCommand(run: () => void): void {\n try {\n run();\n } catch (error) {\n if (error instanceof RangeError && MISMATCH_RE.test(error.message)) {\n run();\n return;\n }\n throw error;\n }\n}\n","import type { SVGProps } from 'react';\n\n/**\n * 内联 SVG 图标集(0 运行时依赖)。stroke 走 currentColor,尺寸默认 1em 跟随字号,\n * 故颜色/大小随文本与主题自动变化。\n *\n * 通用图标(粗体/斜体/下划线/列表/撤销/查找等,本文件表格图标之前的部分)的 path 取自\n * Lucide,其许可证为 ISC,其中部分图形源自 Feather 的 MIT——完整版权声明见\n * 仓库根目录 THIRD_PARTY_LICENSES.md。表格行列操作图标(Column / Row / TableDelete 系列)为自绘。\n */\nexport interface IconProps extends SVGProps<SVGSVGElement> {\n size?: number | string;\n}\n\nfunction Svg({ size = '1em', children, ...rest }: IconProps & { children: React.ReactNode }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n {...rest}\n >\n {children}\n </svg>\n );\n}\n\nexport const BoldIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\" />\n <path d=\"M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\" />\n </Svg>\n);\n\nexport const ItalicIcon = (p: IconProps) => (\n <Svg {...p}>\n <line x1=\"19\" x2=\"10\" y1=\"4\" y2=\"4\" />\n <line x1=\"14\" x2=\"5\" y1=\"20\" y2=\"20\" />\n <line x1=\"15\" x2=\"9\" y1=\"4\" y2=\"20\" />\n </Svg>\n);\n\nexport const UnderlineIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M6 4v6a6 6 0 0 0 12 0V4\" />\n <line x1=\"4\" x2=\"20\" y1=\"20\" y2=\"20\" />\n </Svg>\n);\n\nexport const StrikethroughIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M16 4H9a3 3 0 0 0-2.83 4\" />\n <path d=\"M14 12a4 4 0 0 1 0 8H6\" />\n <line x1=\"4\" x2=\"20\" y1=\"12\" y2=\"12\" />\n </Svg>\n);\n\nexport const CodeIcon = (p: IconProps) => (\n <Svg {...p}>\n <polyline points=\"16 18 22 12 16 6\" />\n <polyline points=\"8 6 2 12 8 18\" />\n </Svg>\n);\n\nexport const LinkIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\" />\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\" />\n </Svg>\n);\n\nexport const ImageIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" ry=\"2\" />\n <circle cx=\"9\" cy=\"9\" r=\"2\" />\n <path d=\"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21\" />\n </Svg>\n);\n\nexport const ImportIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M12 3v12\" />\n <path d=\"m8 11 4 4 4-4\" />\n <path d=\"M8 5H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-4\" />\n </Svg>\n);\n\nexport const ListUnorderedIcon = (p: IconProps) => (\n <Svg {...p}>\n <line x1=\"8\" x2=\"21\" y1=\"6\" y2=\"6\" />\n <line x1=\"8\" x2=\"21\" y1=\"12\" y2=\"12\" />\n <line x1=\"8\" x2=\"21\" y1=\"18\" y2=\"18\" />\n <line x1=\"3\" x2=\"3.01\" y1=\"6\" y2=\"6\" />\n <line x1=\"3\" x2=\"3.01\" y1=\"12\" y2=\"12\" />\n <line x1=\"3\" x2=\"3.01\" y1=\"18\" y2=\"18\" />\n </Svg>\n);\n\nexport const ListOrderedIcon = (p: IconProps) => (\n <Svg {...p}>\n <line x1=\"10\" x2=\"21\" y1=\"6\" y2=\"6\" />\n <line x1=\"10\" x2=\"21\" y1=\"12\" y2=\"12\" />\n <line x1=\"10\" x2=\"21\" y1=\"18\" y2=\"18\" />\n <path d=\"M4 6h1v4\" />\n <path d=\"M4 10h2\" />\n <path d=\"M6 18H4c0-1 2-2 2-3s-1-1.5-2-1\" />\n </Svg>\n);\n\nexport const ListChecksIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m3 17 2 2 4-4\" />\n <path d=\"m3 7 2 2 4-4\" />\n <path d=\"M13 6h8\" />\n <path d=\"M13 12h8\" />\n <path d=\"M13 18h8\" />\n </Svg>\n);\n\nexport const UndoIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M9 14 4 9l5-5\" />\n <path d=\"M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5 5.5 5.5 0 0 1-5.5 5.5H11\" />\n </Svg>\n);\n\nexport const RedoIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m15 14 5-5-5-5\" />\n <path d=\"M20 9H9.5A5.5 5.5 0 0 0 4 14.5 5.5 5.5 0 0 0 9.5 20H13\" />\n </Svg>\n);\n\nexport const ChevronDownIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m6 9 6 6 6-6\" />\n </Svg>\n);\n\nexport const CheckIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M20 6 9 17l-5-5\" />\n </Svg>\n);\n\nexport const TrashIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M3 6h18\" />\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\" />\n <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n <line x1=\"10\" x2=\"10\" y1=\"11\" y2=\"17\" />\n <line x1=\"14\" x2=\"14\" y1=\"11\" y2=\"17\" />\n </Svg>\n);\n\nexport const LockIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </Svg>\n);\n\nexport const MenuIcon = (p: IconProps) => (\n <Svg {...p}>\n <line x1=\"4\" x2=\"20\" y1=\"12\" y2=\"12\" />\n <line x1=\"4\" x2=\"20\" y1=\"6\" y2=\"6\" />\n <line x1=\"4\" x2=\"20\" y1=\"18\" y2=\"18\" />\n </Svg>\n);\n\nexport const SearchIcon = (p: IconProps) => (\n <Svg {...p}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </Svg>\n);\n\nexport const XIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </Svg>\n);\n\nexport const ChevronUpIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m18 15-6-6-6 6\" />\n </Svg>\n);\n\n/* ── 表格行列操作图标(自绘:表格轮廓 + 目标边高亮 + 加号/叉号)── */\n\nexport const ColumnBeforeIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"10\" y=\"4\" width=\"11\" height=\"16\" rx=\"1\" />\n <path d=\"M14 4v16\" />\n <path d=\"M5 9v6\" />\n <path d=\"M2 12h6\" />\n </Svg>\n);\n\nexport const ColumnAfterIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"3\" y=\"4\" width=\"11\" height=\"16\" rx=\"1\" />\n <path d=\"M10 4v16\" />\n <path d=\"M19 9v6\" />\n <path d=\"M16 12h6\" />\n </Svg>\n);\n\nexport const ColumnDeleteIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"1\" />\n <path d=\"M12 4v16\" />\n <path d=\"m8 9 8 6\" />\n <path d=\"m16 9-8 6\" />\n </Svg>\n);\n\nexport const RowBeforeIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"4\" y=\"10\" width=\"16\" height=\"11\" rx=\"1\" />\n <path d=\"M4 14h16\" />\n <path d=\"M9 5h6\" />\n <path d=\"M12 2v6\" />\n </Svg>\n);\n\nexport const RowAfterIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"4\" y=\"3\" width=\"16\" height=\"11\" rx=\"1\" />\n <path d=\"M4 10h16\" />\n <path d=\"M9 19h6\" />\n <path d=\"M12 16v6\" />\n </Svg>\n);\n\nexport const RowDeleteIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"1\" />\n <path d=\"M4 12h16\" />\n <path d=\"m9 8 6 8\" />\n <path d=\"m15 8-6 8\" />\n </Svg>\n);\n\nexport const TableDeleteIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"1\" />\n <path d=\"M3 9h18\" />\n <path d=\"M9 5v14\" />\n <path d=\"M15 5v14\" />\n <path d=\"m7 2 10 20\" />\n </Svg>\n);\n","/**\n * UI 文案(i18n 注入点)。各组件接收 `labels?: Partial<...>`,与内置英文默认合并。\n * 消费方(如中文项目)可传入本地化文案。\n */\n\nexport interface ToolbarLabels {\n undo: string;\n redo: string;\n style: string;\n normalText: string;\n /** 传入层级,返回如 \"Heading 2\"。 */\n headingLabel: (level: number) => string;\n fontSize: string;\n fontSizeDefault: string;\n bold: string;\n italic: string;\n underline: string;\n strike: string;\n code: string;\n textColor: string;\n highlight: string;\n colorNone: string;\n colorTheme: string;\n scriptMenu: string;\n scriptNormal: string;\n superscript: string;\n subscript: string;\n link: string;\n linkPrompt: string;\n image: string;\n imageUploadFailed: string;\n /** Markdown 文件导入失败(与图片上传共用 onError 回调时,便于宿主区分文案)。 */\n importMarkdownFailed: string;\n /** 主栏导入下拉触发器上的短文案(对齐 style / fontSize)。 */\n importDocument: string;\n /** 导入触发器 title / aria-label。 */\n importDocumentHint: string;\n /** 未传 importMenuItems、但传了 onImportDocument + importAccept 时的第二项。 */\n importDocumentOther: string;\n /** 导入进行中的按钮 title。 */\n importDocumentBusy: string;\n /** 光标占位:上传阶段,传入 0–100。 */\n importDocumentUploading: (percent: number) => string;\n /** 光标占位:转换阶段,不要百分比。 */\n importDocumentConverting: string;\n /** 非 Markdown 文件导入失败(onError 的 source === 'import')。 */\n importDocumentFailed: string;\n blockquote: string;\n bulletList: string;\n orderedList: string;\n taskList: string;\n more: string;\n codeBlock: string;\n hr: string;\n /** 导入下拉里的 Markdown 项。 */\n importMarkdown: string;\n tableInsert: string;\n /** 网格选择器底部尺寸文案,如 \"3 × 4\"。参数顺序:列、行。 */\n tableSizeSelected: (cols: number, rows: number) => string;\n tableAddColumnBefore: string;\n tableAddColumnAfter: string;\n tableDeleteColumn: string;\n tableAddRowBefore: string;\n tableAddRowAfter: string;\n tableDeleteRow: string;\n /** 多格选区:在左侧插入 N 列。 */\n tableAddColumnBeforeN: (n: number) => string;\n /** 多格选区:在右侧插入 N 列。 */\n tableAddColumnAfterN: (n: number) => string;\n /** 多格选区:删除 N 列。 */\n tableDeleteColumnN: (n: number) => string;\n /** 多格选区:在上方插入 N 行。 */\n tableAddRowBeforeN: (n: number) => string;\n /** 多格选区:在下方插入 N 行。 */\n tableAddRowAfterN: (n: number) => string;\n /** 多格选区:删除 N 行。 */\n tableDeleteRowN: (n: number) => string;\n tableDeleteTable: string;\n inlineMath: string;\n blockMath: string;\n mathPlaceholder: string;\n mathDone: string;\n mathCancel: string;\n mathNewInline: string;\n mathNewBlock: string;\n}\n\nexport interface ChartLabels {\n /** Tab label when config has no title. */\n tabLabel: (chartType: string, index: number) => string;\n done: string;\n cancel: string;\n configLabel: string;\n tableLabel: string;\n /** Modal dialog title. */\n editTitle: string;\n}\n\nexport const defaultChartLabels: ChartLabels = {\n tabLabel: (chartType, index) => `${chartType} ${index + 1}`,\n done: 'Done',\n cancel: 'Cancel',\n configLabel: 'Chart config (JSON)',\n tableLabel: 'Data table (Markdown)',\n editTitle: 'Edit chart',\n};\n\nexport const defaultToolbarLabels: ToolbarLabels = {\n undo: 'Undo',\n redo: 'Redo',\n style: 'Style',\n normalText: 'Normal text',\n headingLabel: (level) => `Heading ${level}`,\n fontSize: 'Font size',\n fontSizeDefault: 'Default',\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n strike: 'Strikethrough',\n code: 'Inline code',\n textColor: 'Text color',\n highlight: 'Highlight',\n colorNone: 'None',\n colorTheme: 'THEME',\n scriptMenu: 'Superscript / Subscript',\n scriptNormal: 'Normal',\n superscript: 'Superscript',\n subscript: 'Subscript',\n link: 'Link',\n linkPrompt: 'Enter URL',\n image: 'Image',\n imageUploadFailed: 'Image upload failed',\n importMarkdownFailed: 'Markdown import failed',\n importDocument: 'Import',\n importDocumentHint: 'Import a file',\n importDocumentOther: 'Document',\n importDocumentBusy: 'Importing…',\n importDocumentUploading: (percent) => `Uploading ${percent}%`,\n importDocumentConverting: 'Converting…',\n importDocumentFailed: 'Import failed',\n blockquote: 'Blockquote',\n bulletList: 'Bullet list',\n orderedList: 'Ordered list',\n taskList: 'Task list',\n more: 'More',\n codeBlock: 'Code block',\n hr: 'Divider',\n importMarkdown: 'Markdown',\n tableInsert: 'Insert table',\n tableSizeSelected: (cols, rows) => `${cols} × ${rows}`,\n tableAddColumnBefore: 'Add column before',\n tableAddColumnAfter: 'Add column after',\n tableDeleteColumn: 'Delete column',\n tableAddRowBefore: 'Add row before',\n tableAddRowAfter: 'Add row after',\n tableDeleteRow: 'Delete row',\n tableAddColumnBeforeN: (n) => `Add ${n} columns before`,\n tableAddColumnAfterN: (n) => `Add ${n} columns after`,\n tableDeleteColumnN: (n) => `Delete ${n} columns`,\n tableAddRowBeforeN: (n) => `Add ${n} rows before`,\n tableAddRowAfterN: (n) => `Add ${n} rows after`,\n tableDeleteRowN: (n) => `Delete ${n} rows`,\n tableDeleteTable: 'Delete table',\n inlineMath: 'Inline equation',\n blockMath: 'Block equation',\n mathPlaceholder: 'E = mc^2',\n mathDone: 'Done',\n mathCancel: 'Cancel',\n mathNewInline: 'New equation',\n mathNewBlock: 'Add a TeX equation',\n};\n\nexport interface ColorPaletteLabels {\n none: string;\n theme: string;\n}\n\nexport const defaultColorPaletteLabels: ColorPaletteLabels = {\n none: 'None',\n theme: 'THEME',\n};\n\nexport interface TocLabels {\n title: string;\n expand: string;\n collapse: string;\n}\n\nexport const defaultTocLabels: TocLabels = {\n title: 'Contents',\n expand: 'Expand',\n collapse: 'Collapse',\n};\n\nexport interface CodeBlockLabels {\n autoDetect: string;\n delete: string;\n}\n\nexport const defaultCodeBlockLabels: CodeBlockLabels = {\n autoDetect: 'Auto-detect',\n delete: 'Delete code block',\n};\n\nexport interface CommentLabels {\n open: string;\n resolved: string;\n dismissed: string;\n outdated: string;\n ambiguous: string;\n partial: string;\n gutterTitle: string;\n}\n\nexport const defaultCommentLabels: CommentLabels = {\n open: 'Open',\n resolved: 'Resolved',\n dismissed: 'Dismissed',\n outdated: 'Outdated',\n ambiguous: 'Ambiguous',\n partial: 'Partially matched',\n gutterTitle: 'Comment',\n};\n\nexport interface FindLabels {\n /** 查找输入框的占位与无障碍名,也用作浮动条的 aria-label。 */\n find: string;\n /** 替换输入框的占位与无障碍名。 */\n replace: string;\n next: string;\n previous: string;\n replaceOne: string;\n replaceAll: string;\n close: string;\n caseSensitive: string;\n wholeWord: string;\n useRegex: string;\n /** 计数文案。无结果时 current 传 0。 */\n counter: (current: number, total: number) => string;\n /** 正则模式下模式非法(RE2 不支持 lookaround / backreference 等,见官方扩展)。 */\n invalidRegex: string;\n /** 只读态提示:可查不可换。 */\n readOnly: string;\n}\n\nexport const defaultFindLabels: FindLabels = {\n find: 'Find',\n replace: 'Replace with',\n next: 'Next match',\n previous: 'Previous match',\n replaceOne: 'Replace',\n replaceAll: 'Replace all',\n close: 'Close',\n caseSensitive: 'Match case',\n wholeWord: 'Whole word',\n useRegex: 'Use regular expression',\n counter: (current, total) => `${current} / ${total}`,\n invalidRegex: 'Invalid pattern',\n readOnly: 'Read-only',\n};\n","'use client';\n\nimport {\n createSearchRegex,\n FindAndReplacePluginKey,\n} from '@tiptap/extension-find-and-replace';\nimport { useEditorState, type Editor } from '@tiptap/react';\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type KeyboardEvent as ReactKeyboardEvent,\n type MouseEvent as ReactMouseEvent,\n type RefObject,\n} from 'react';\nimport { FIND_DEBOUNCE_MS, runFindCommand } from '../findReplace';\nimport { ChevronDownIcon, ChevronUpIcon, SearchIcon, XIcon } from '../icons';\nimport { defaultFindLabels, type FindLabels } from '../labels';\nimport styles from '../styles/findBar.module.css';\n\nexport interface FindReplaceBarProps {\n /** 编辑器实例(由 `<MarkdownWysiwygEditor>` 提供,浮动条不自行创建编辑器)。 */\n editor: Editor;\n /** 关闭(Esc / ×):宿主负责收起浮动条并把焦点还给编辑器。 */\n onClose: () => void;\n labels?: Partial<FindLabels>;\n /**\n * 查找输入框 ref。宿主拿它实现「再按一次 Mod+F 聚焦并全选当前查询」。\n * 也用于浮动条打开时自动聚焦。\n */\n inputRef?: RefObject<HTMLInputElement | null>;\n /** 定位 / 层级 class,由宿主给(浮动条自身只负责内部布局)。 */\n className?: string;\n}\n\n/**\n * 查找替换浮动条。匹配、高亮、替换全部由官方\n * `@tiptap/extension-find-and-replace` 承担(含 RE2 安全正则、跨标记匹配、单事务全部替换),\n * 这里只做输入、计数、开关与键位。\n *\n * 打开即把查询推给编辑器,关闭时 `clearSearch()`——高亮是会话级的,不留残影。\n */\nexport function FindReplaceBar({\n editor,\n onClose,\n labels,\n inputRef,\n className,\n}: FindReplaceBarProps) {\n const t: FindLabels = { ...defaultFindLabels, ...labels };\n const [term, setTerm] = useState('');\n const [replaceTerm, setReplaceTerm] = useState('');\n\n const state = useEditorState({\n editor,\n selector: ({ editor: instance }) => {\n const plugin = FindAndReplacePluginKey.getState(instance.state);\n return {\n currentIndex: plugin?.currentIndex ?? null,\n total: plugin?.results.length ?? 0,\n caseSensitive: plugin?.caseSensitive ?? false,\n wholeWord: plugin?.wholeWord ?? false,\n useRegex: plugin?.useRegex ?? false,\n };\n },\n });\n\n // 查询词防抖由这里做(扩展注册时 searchDebounceMs: 0,原因见 findReplace.ts):\n // 输入时延迟推给编辑器,回车 / 替换等动作前先 flush,否则会拿着旧查询执行。\n const appliedTermRef = useRef<string | null>(null);\n const pushTerm = useCallback(\n (value: string) => {\n appliedTermRef.current = value;\n runFindCommand(() => editor.commands.setSearchTerm(value));\n },\n [editor],\n );\n const flushTerm = useCallback(() => {\n if (appliedTermRef.current !== term) pushTerm(term);\n }, [pushTerm, term]);\n\n useEffect(() => {\n if (appliedTermRef.current === term) return;\n const timer = setTimeout(() => pushTerm(term), FIND_DEBOUNCE_MS);\n return () => clearTimeout(timer);\n }, [term, pushTerm]);\n\n useEffect(() => {\n runFindCommand(() => editor.commands.setReplaceTerm(replaceTerm));\n }, [editor, replaceTerm]);\n\n // 关闭 / 卸载时清空查询与高亮。\n useEffect(() => {\n return () => {\n if (!editor.isDestroyed) editor.commands.clearSearch();\n };\n }, [editor]);\n\n /** 动作类命令(导航 / 替换):先落定查询词,再执行。 */\n const runAction = useCallback(\n (action: () => void) => {\n flushTerm();\n runFindCommand(action);\n },\n [flushTerm],\n );\n\n // RE2 模式非法(lookaround / backreference 等):官方返回零结果不报错,这里给个提示,\n // 否则「输入了正则却一直 0 / 0」没有解释。\n const invalidPattern = useMemo(\n () =>\n term !== '' &&\n state.useRegex &&\n createSearchRegex(term, {\n caseSensitive: state.caseSensitive,\n useRegex: true,\n wholeWord: false,\n }) === null,\n [term, state.useRegex, state.caseSensitive],\n );\n\n const counter = t.counter(\n state.total === 0 ? 0 : (state.currentIndex ?? 0) + 1,\n state.total,\n );\n\n const keepFocus = (e: ReactMouseEvent) => e.preventDefault();\n\n const onFindKeyDown = (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n runAction(() => {\n if (e.shiftKey) editor.commands.goToPreviousResult();\n else editor.commands.goToNextResult();\n });\n }\n };\n\n const onReplaceKeyDown = (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n runAction(() => editor.commands.replace());\n }\n };\n\n const toggle = (\n key: 'caseSensitive' | 'wholeWord' | 'useRegex',\n value: boolean,\n ) => {\n runFindCommand(() => {\n if (key === 'caseSensitive') editor.commands.setCaseSensitive(value);\n else if (key === 'wholeWord') editor.commands.setWholeWord(value);\n else editor.commands.setUseRegex(value);\n });\n };\n\n const toggleClass = (on: boolean) =>\n `${styles.btn} ${styles.toggle}${on ? ` ${styles.toggleOn}` : ''}`;\n\n return (\n <div\n className={className ? `${styles.bar} ${className}` : styles.bar}\n role=\"dialog\"\n aria-label={t.find}\n onKeyDown={(e) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose();\n }\n }}\n >\n <div className={styles.row}>\n <span className={styles.field}>\n <SearchIcon size={14} className={styles.fieldIcon} />\n <input\n ref={inputRef}\n className={styles.input}\n value={term}\n onChange={(e) => setTerm(e.target.value)}\n onKeyDown={onFindKeyDown}\n placeholder={t.find}\n aria-label={t.find}\n autoFocus\n spellCheck={false}\n />\n </span>\n <span\n className={`${styles.counter}${invalidPattern ? ` ${styles.counterInvalid}` : ''}`}\n aria-live=\"polite\"\n title={invalidPattern ? t.invalidRegex : undefined}\n >\n {invalidPattern ? t.invalidRegex : counter}\n </span>\n <button\n type=\"button\"\n className={styles.btn}\n title={t.previous}\n aria-label={t.previous}\n disabled={state.total === 0}\n onMouseDown={keepFocus}\n onClick={() => runAction(() => editor.commands.goToPreviousResult())}\n >\n <ChevronUpIcon size={16} />\n </button>\n <button\n type=\"button\"\n className={styles.btn}\n title={t.next}\n aria-label={t.next}\n disabled={state.total === 0}\n onMouseDown={keepFocus}\n onClick={() => runAction(() => editor.commands.goToNextResult())}\n >\n <ChevronDownIcon size={16} />\n </button>\n <button\n type=\"button\"\n className={styles.btn}\n title={t.close}\n aria-label={t.close}\n onClick={onClose}\n >\n <XIcon size={16} />\n </button>\n </div>\n\n {editor.isEditable ? (\n <div className={styles.row}>\n <span className={styles.field}>\n <input\n className={styles.input}\n value={replaceTerm}\n onChange={(e) => setReplaceTerm(e.target.value)}\n onKeyDown={onReplaceKeyDown}\n placeholder={t.replace}\n aria-label={t.replace}\n spellCheck={false}\n />\n </span>\n <button\n type=\"button\"\n className={toggleClass(state.caseSensitive)}\n title={t.caseSensitive}\n aria-label={t.caseSensitive}\n aria-pressed={state.caseSensitive}\n onMouseDown={keepFocus}\n onClick={() => toggle('caseSensitive', !state.caseSensitive)}\n >\n Aa\n </button>\n <button\n type=\"button\"\n className={toggleClass(state.wholeWord)}\n title={t.wholeWord}\n aria-label={t.wholeWord}\n aria-pressed={state.wholeWord}\n onMouseDown={keepFocus}\n onClick={() => toggle('wholeWord', !state.wholeWord)}\n >\n ab\n </button>\n <button\n type=\"button\"\n className={toggleClass(state.useRegex)}\n title={t.useRegex}\n aria-label={t.useRegex}\n aria-pressed={state.useRegex}\n onMouseDown={keepFocus}\n onClick={() => toggle('useRegex', !state.useRegex)}\n >\n .*\n </button>\n <span className={styles.spacer} />\n <button\n type=\"button\"\n className={`${styles.btn} ${styles.textBtn}`}\n disabled={state.total === 0}\n onMouseDown={keepFocus}\n onClick={() => runAction(() => editor.commands.replace())}\n >\n {t.replaceOne}\n </button>\n <button\n type=\"button\"\n className={`${styles.btn} ${styles.textBtn}`}\n disabled={state.total === 0}\n onMouseDown={keepFocus}\n onClick={() => runAction(() => editor.commands.replaceAll())}\n >\n {t.replaceAll}\n </button>\n </div>\n ) : (\n <div className={styles.row}>\n <span className={styles.readOnly}>{t.readOnly}</span>\n </div>\n )}\n </div>\n );\n}\n","import { Node } from '@tiptap/core';\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n importPlaceholder: {\n insertImportPlaceholder: (label: string) => ReturnType;\n updateImportPlaceholder: (label: string) => ReturnType;\n removeImportPlaceholder: () => ReturnType;\n };\n }\n}\n\nfunction findPlaceholderPos(doc: {\n descendants: (\n f: (node: { type: { name: string } }, pos: number) => boolean | void,\n ) => void;\n}): number | null {\n let found: number | null = null;\n doc.descendants((node, pos) => {\n if (node.type.name === 'importPlaceholder') {\n found = pos;\n return false;\n }\n });\n return found;\n}\n\n/** 导入进行中插在光标处的占位块。不进 Markdown,autosave 不会把进度文案落库。 */\nexport const ImportPlaceholder = Node.create({\n name: 'importPlaceholder',\n group: 'block',\n atom: true,\n selectable: false,\n draggable: false,\n\n addAttributes() {\n return {\n label: {\n default: '',\n parseHTML: (el) => el.getAttribute('data-label') ?? '',\n renderHTML: (attrs) =>\n attrs.label ? { 'data-label': attrs.label } : {},\n },\n };\n },\n\n parseHTML() {\n return [{ tag: 'div[data-type=\"import-placeholder\"]' }];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const label = String(node.attrs.label ?? '');\n return [\n 'div',\n {\n ...HTMLAttributes,\n 'data-type': 'import-placeholder',\n class: 'tmr-import-placeholder',\n contenteditable: 'false',\n 'aria-live': 'polite',\n 'aria-busy': 'true',\n },\n ['span', { class: 'tmr-import-placeholder-spin', 'aria-hidden': 'true' }],\n ['span', { class: 'tmr-import-placeholder-label' }, label],\n ];\n },\n\n renderMarkdown() {\n return '';\n },\n\n addCommands() {\n return {\n insertImportPlaceholder:\n (label) =>\n ({ chain }) =>\n chain()\n .focus()\n .insertContent({\n type: this.name,\n attrs: { label },\n })\n .command(({ tr }) => {\n tr.setMeta('addToHistory', false);\n tr.setMeta('preventUpdate', true);\n return true;\n })\n .run(),\n updateImportPlaceholder:\n (label) =>\n ({ tr, dispatch, state }) => {\n const pos = findPlaceholderPos(state.doc);\n if (pos == null) return false;\n if (dispatch) {\n dispatch(\n tr\n .setNodeMarkup(pos, undefined, { label })\n .setMeta('addToHistory', false)\n .setMeta('preventUpdate', true),\n );\n }\n return true;\n },\n removeImportPlaceholder:\n () =>\n ({ tr, dispatch, state }) => {\n const pos = findPlaceholderPos(state.doc);\n if (pos == null) return false;\n const node = state.doc.nodeAt(pos);\n if (!node) return false;\n if (dispatch) {\n dispatch(\n tr\n .delete(pos, pos + node.nodeSize)\n .setMeta('addToHistory', false)\n .setMeta('preventUpdate', true),\n );\n }\n return true;\n },\n };\n },\n});\n","// 副作用:增强 Editor.markdown(MarkdownManager)的类型。\nimport '@tiptap/markdown';\nimport { Extension, type Editor } from '@tiptap/core';\nimport { FileHandlePlugin } from '@tiptap/extension-file-handler';\nimport { PluginKey } from '@tiptap/pm/state';\n\n/** .md / .markdown 扩展名(不区分大小写)。 */\nconst MD_FILE_RE = /\\.(md|markdown)$/i;\n\n/**\n * .md 的 MIME 类型在各平台不稳定(text/markdown / text/x-markdown / 空串),\n * 而 FileHandlePlugin 的 allowedMimeTypes 是严格 `includes(file.type)` 匹配\n * (源码确认,不支持扩展名)。故列表包含空串兜住「系统未注册 MIME」的 .md,\n * 真正的判定在回调里按文件名做。副作用:拖入其它空 MIME 文件会被吞成 no-op\n * ——好过浏览器默认导航打开该文件。\n */\nconst MD_MIME_TYPES = ['text/markdown', 'text/x-markdown', ''];\n\n/** 读 .md 文件文本 → markdown.parse → 插入(drop 时插到落点,paste 时插到光标)。 */\nasync function insertMarkdownFiles(\n editor: Editor,\n files: File[],\n pos?: number,\n): Promise<void> {\n const mdFiles = files.filter((f) => MD_FILE_RE.test(f.name));\n if (mdFiles.length === 0) return;\n // markdown manager 仅在注册了 @tiptap/markdown 扩展后存在\n const markdown = editor.markdown;\n if (!markdown) return;\n const texts = await Promise.all(mdFiles.map((f) => f.text()));\n const json = markdown.parse(texts.join('\\n\\n'));\n if (pos != null) {\n editor.chain().focus().insertContentAt(pos, json).run();\n } else {\n editor.chain().focus().insertContent(json).run();\n }\n}\n\n/**\n * 把 .md / .markdown 文件拖拽或粘贴进编辑器,解析后插入内容。\n * 复用官方 @tiptap/extension-file-handler 的底层 FileHandlePlugin,但注册在\n * 自有 PluginKey 下——宿主仍可通过 extraExtensions 注入自己的 FileHandler\n * (如图片上传)而不撞 key。\n */\nexport const MarkdownFileDrop = Extension.create({\n name: 'markdownFileDrop',\n\n addProseMirrorPlugins() {\n const { editor } = this;\n return [\n FileHandlePlugin({\n key: new PluginKey('markdownFileDrop'),\n editor,\n allowedMimeTypes: MD_MIME_TYPES,\n onDrop: (ed, files, pos) => {\n insertMarkdownFiles(ed, files, pos).catch((err) => {\n console.error('markdown file drop failed:', err);\n });\n },\n onPaste: (ed, files) => {\n insertMarkdownFiles(ed, files).catch((err) => {\n console.error('markdown file paste failed:', err);\n });\n },\n }),\n ];\n },\n});\n","import { Extension } from '@tiptap/core';\nimport { skipTrailingNodeMeta } from '@tiptap/extensions';\nimport type { Node } from '@tiptap/pm/model';\nimport { Plugin, PluginKey, type EditorState } from '@tiptap/pm/state';\nimport { Decoration, DecorationSet } from '@tiptap/pm/view';\nimport type { Editor } from '@tiptap/react';\n\n/**\n * 「这段正在被 AI 改写」的高亮。\n *\n * 用 **decoration** 而不是 mark:两者都不会漏进 markdown,都能盖住表格,但 decoration\n * 不需要往 schema 里加标记、也不参与 undo 历史,而且**原子节点(图表 / 图片)也能盖**\n * ——mark 只作用于行内内容,盖不住 `atom: true` 的块级节点。\n *\n * 状态由宿主通过 `pendingAnchors` 推入(提交圈选改写时给上,回填或冲突时清空)。\n * 文档被编辑时装饰会跟着映射(在原文中间插字,高亮跟着变长;在前面插,整体后移)。\n */\nexport interface PendingAnchor {\n /** 宿主自己的标识(例如一次圈选请求的 request_id)。 */\n id: string;\n /** doc 坐标区间;通常是与选区相交的顶层块的首尾(见 getMarkdownForRange)。 */\n ranges: Array<{ from: number; to: number }>;\n}\n\nexport interface PendingAnchorState {\n decorations: DecorationSet;\n}\n\n/** 用 transaction meta 推入锚点:`tr.setMeta(PENDING_ANCHOR_META, anchors)`。 */\nexport const PENDING_ANCHOR_META = 'tmr:pendingAnchor';\n\nexport const pendingAnchorPluginKey = new PluginKey<PendingAnchorState>(\n 'tmrPendingAnchor',\n);\n\n/** 装饰上的 class;点击命中时宿主用 `[data-pending-id]` 取回 id。 */\nexport const PENDING_ANCHOR_CLASS = 'tmr-pending-anchor';\n\nexport const pendingAnchorExtension = Extension.create({\n name: 'pendingAnchor',\n\n addProseMirrorPlugins() {\n return [\n new Plugin<PendingAnchorState>({\n key: pendingAnchorPluginKey,\n state: {\n init: () => ({ decorations: DecorationSet.empty }),\n apply(tr, value) {\n const next = tr.getMeta(PENDING_ANCHOR_META) as\n | PendingAnchor[]\n | undefined;\n if (next) return { decorations: buildDecorations(tr.doc, next) };\n if (tr.docChanged) {\n return { decorations: value.decorations.map(tr.mapping, tr.doc) };\n }\n return value;\n },\n },\n props: {\n decorations(state: EditorState) {\n return pendingAnchorPluginKey.getState(state)?.decorations ?? null;\n },\n },\n }),\n ];\n },\n});\n\n/** 更新待改写高亮(传空数组即清空)。不进 undo 历史。 */\nexport function setPendingAnchors(editor: Editor, anchors: PendingAnchor[]): void {\n editor.view.dispatch(\n editor.state.tr\n .setMeta(PENDING_ANCHOR_META, anchors)\n // Tiptap 的 TrailingNode(StarterKit 自带)会在「第一个 transaction」时给文档末尾补一个\n // 空段落——只要文末是图表 / 表格 / 代码块这类节点。那是它本来的行为,但**不该由一次\n // 「加个高亮」触发**:那等于用户什么都没干、正文却多了个空段落(落库就变成结尾的 \\n\\n)。\n // 用官方 meta 跳过本次。\n .setMeta(skipTrailingNodeMeta, true)\n .setMeta('addToHistory', false),\n );\n}\n\nfunction buildDecorations(doc: Node, anchors: PendingAnchor[]): DecorationSet {\n const bounds: Array<{ from: number; to: number }> = [];\n doc.forEach((child, offset) => {\n bounds.push({ from: offset, to: offset + child.nodeSize });\n });\n\n const decorations: Decoration[] = [];\n for (const anchor of anchors) {\n for (const range of anchor.ranges) {\n const from = Math.max(0, Math.min(range.from, range.to));\n const to = Math.min(doc.content.size, Math.max(range.from, range.to));\n if (from >= to) continue;\n\n for (const bound of bounds) {\n if (bound.to <= from || bound.from >= to) continue;\n const attrs = {\n class: PENDING_ANCHOR_CLASS,\n 'data-pending-id': anchor.id,\n };\n if (from <= bound.from && to >= bound.to) {\n // 整块:用 node 装饰,表格 / 图表这类块级节点才盖得住\n decorations.push(Decoration.node(bound.from, bound.to, attrs));\n } else {\n // 块内的一部分(未扩块的选区):行内高亮\n decorations.push(\n Decoration.inline(Math.max(from, bound.from), Math.min(to, bound.to), attrs),\n );\n }\n }\n }\n }\n\n return decorations.length ? DecorationSet.create(doc, decorations) : DecorationSet.empty;\n}\n","import type { Selection } from '@tiptap/pm/state';\nimport { NodeSelection, TextSelection } from '@tiptap/pm/state';\nimport { CellSelection } from '@tiptap/pm/tables';\n\n/**\n * 选区类型——给宿主判断「用户选的是什么」用。\n *\n * - `text`:普通文字选区(含 AllSelection)\n * - `cell`:表格里的单元格选区(`CellSelection`,拖过表格时就是它)\n * - `node`:整节点选区(`NodeSelection`)。图表 / 图片 / 代码块这类 `atom` 节点只能这样被选中\n * ——它们在编辑器里渲染成图或块,用户没法用拖选文字的方式选中\n */\nexport type SelectionKind = 'text' | 'cell' | 'node';\n\nexport function selectionKind(selection: Selection): SelectionKind {\n if (selection instanceof CellSelection) return 'cell';\n if (selection instanceof NodeSelection) return 'node';\n if (selection instanceof TextSelection) return 'text';\n return 'text';\n}\n","// 副作用:增强 Editor.markdown(MarkdownManager)的类型。\nimport '@tiptap/markdown';\nimport { Extension } from '@tiptap/core';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport { prepareChartMarkdown } from './chart/prepareChartMarkdown';\n\n/**\n * 启发式判断一段纯文本是否「像 markdown」。\n * 只要命中任一块级/行内特征即认为是——宁可偶尔把带星号的普通文本转掉,\n * 也不漏掉真 markdown(用户可用 Shift+粘贴逃生)。\n */\nexport function looksLikeMarkdown(text: string): boolean {\n return (\n /^#{1,6}\\s/m.test(text) || // 标题\n /\\*\\*[^*\\n]+\\*\\*/.test(text) || // 加粗\n /(^|[^!])\\[[^\\]\\n]+\\]\\([^)\\n]+\\)/.test(text) || // 链接\n /!\\[[^\\]\\n]*\\]\\([^)\\n]+\\)/.test(text) || // 图片\n /^[-*+]\\s+\\S/m.test(text) || // 无序列表\n /^\\d+\\.\\s+\\S/m.test(text) || // 有序列表\n /^>\\s/m.test(text) || // 引用\n /^```/m.test(text) || // 代码围栏\n /^\\|.+\\|\\s*$/m.test(text) || // 表格行\n /^(-{3,}|\\*{3,})\\s*$/m.test(text) || // 分割线\n /<!--\\s*[\\[{][\\s\\S]*?\"chartType\"[\\s\\S]*?-->/.test(text) // 图表注释\n );\n}\n\n/**\n * 粘贴 markdown 纯文本自动转富文本(官方 @tiptap/markdown 不内置此能力,\n * 实现方式取自官方文档 \"Paste Markdown Detection\" 配方并调整边界)。\n *\n * 判定只看 text/plain 的内容,不看剪贴板是否带 text/html——很多来源\n * (Xcode/VS Code 等编辑器经 RTF/语法高亮 HTML)复制 markdown 源码时会\n * 附带一份仅是\"字面文本+样式\"的 HTML,按 HTML 标签判定来源不可枚举。\n * 而真富文本(Word/网页文章)的 text/plain 降级不含 markdown 符号,\n * 启发式天然不命中,仍走默认富文本粘贴。\n *\n * 放行(不转换)的边界:\n * - Shift+粘贴(粘贴为纯文本)→ 保留逃生通道\n * - 光标在代码块内 → markdown 源码原样贴入\n * - looksLikeMarkdown 未命中 → 默认粘贴\n */\nexport const MarkdownPaste = Extension.create({\n name: 'markdownPaste',\n\n addProseMirrorPlugins() {\n const { editor } = this;\n return [\n new Plugin({\n key: new PluginKey('markdownPaste'),\n props: {\n handlePaste(view, event) {\n const clipboard = event.clipboardData;\n if (!clipboard) return false;\n const text = clipboard.getData('text/plain');\n if (!text) return false;\n // Shift+粘贴 = 用户显式要纯文本(shiftKey 是 prosemirror-view\n // 内部状态,无公开 API,容错访问;拿不到则照常转换)\n const input = (view as unknown as { input?: { shiftKey?: boolean } })\n .input;\n if (input?.shiftKey) return false;\n // 代码块内粘贴 markdown 源码是常见操作,不转换\n if (view.state.selection.$from.parent.type.spec.code) return false;\n if (!looksLikeMarkdown(text)) return false;\n // markdown manager 仅在注册了 @tiptap/markdown 扩展后存在\n const markdown = editor.markdown;\n if (!markdown) return false;\n try {\n // 与 insertMarkdown / 初始 content 一致:先把\n // `<!-- chartType -->` + GFM 表收成 ```tmr-chart,否则\n // TipTap 会丢掉 HTML 注释,只剩普通表格。\n const json = markdown.parse(prepareChartMarkdown(text));\n editor.commands.insertContent(json);\n return true;\n } catch (err) {\n console.error('markdown paste parse failed:', err);\n return false; // 解析失败回退默认纯文本粘贴\n }\n },\n },\n }),\n ];\n },\n});\n","'use client';\n\nimport type { Chart as ChartJs } from 'chart.js';\nimport {\n NodeViewWrapper,\n type NodeViewProps,\n} from '@tiptap/react';\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n type MouseEvent,\n} from 'react';\nimport { destroyChart, renderOrUpdateChart } from '../chart/renderChart';\nimport type { ChartPayload, ChartTheme } from '../chart/types';\nimport { defaultChartLabels } from '../labels';\nimport '../styles/chart.css';\n\nfunction tabLabel(\n chartType: string,\n title: string | undefined,\n index: number,\n fallback: (type: string, i: number) => string,\n): string {\n if (title?.trim()) return title;\n return fallback(chartType, index);\n}\n\n/**\n * Chart NodeView: render + NodeSelection (like Image).\n * Config editing is intentionally disabled for now (no modal).\n */\nexport function ChartView({\n node,\n editor,\n extension,\n selected,\n getPos,\n}: NodeViewProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const chartRef = useRef<ChartJs | null>(null);\n const [active, setActive] = useState(0);\n\n const payload: ChartPayload = useMemo(\n () => ({\n config: (node.attrs.config ?? []) as ChartPayload['config'],\n columns: (node.attrs.columns ?? []) as ChartPayload['columns'],\n dataSource: (node.attrs.dataSource ??\n []) as ChartPayload['dataSource'],\n }),\n [node.attrs.config, node.attrs.columns, node.attrs.dataSource],\n );\n\n const theme = (extension.options.chartTheme ?? null) as ChartTheme | null;\n const configs = payload.config;\n const safeIndex = Math.min(active, Math.max(0, configs.length - 1));\n const config = configs[safeIndex];\n const height = config?.height ?? 320;\n const canSelect = Boolean(editor?.isEditable);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas || !config) return;\n chartRef.current = renderOrUpdateChart({\n canvas,\n config,\n payload,\n theme,\n chart: chartRef.current,\n });\n }, [config, payload, theme]);\n\n useEffect(() => {\n return () => {\n destroyChart(chartRef.current);\n chartRef.current = null;\n };\n }, []);\n\n // When active tab changes, recreate chart (type may differ)\n useEffect(() => {\n destroyChart(chartRef.current);\n chartRef.current = null;\n const canvas = canvasRef.current;\n if (!canvas || !config) return;\n chartRef.current = renderOrUpdateChart({\n canvas,\n config,\n payload,\n theme,\n chart: null,\n });\n }, [safeIndex]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const labels = {\n ...defaultChartLabels,\n ...(extension.options.chartLabels as\n | Partial<typeof defaultChartLabels>\n | undefined),\n };\n\n const selectChart = () => {\n if (!editor || !canSelect) return;\n const pos = getPos();\n if (typeof pos !== 'number') return;\n editor.commands.setNodeSelection(pos);\n };\n\n return (\n <NodeViewWrapper\n as=\"div\"\n className={`tmr-chart${canSelect ? ' tmr-chart--interactive' : ''}${\n selected ? ' ProseMirror-selectednode' : ''\n }`}\n data-type=\"chart\"\n data-selected={selected ? 'true' : undefined}\n contentEditable={false}\n onMouseDown={(e: MouseEvent) => {\n if ((e.target as HTMLElement).closest('button')) return;\n if (e.button !== 0) return;\n // Select node but do not preventDefault — Chart.js needs hover/click.\n selectChart();\n }}\n >\n {config?.title ? (\n <div className=\"tmr-chart-title\">{config.title}</div>\n ) : null}\n {config?.dataTime ? (\n <div className=\"tmr-chart-time\">{config.dataTime}</div>\n ) : null}\n {configs.length > 1 ? (\n <div className=\"tmr-chart-tabs\" role=\"tablist\">\n {configs.map((c, i) => (\n <button\n key={`${c.chartType}-${i}`}\n type=\"button\"\n role=\"tab\"\n className=\"tmr-chart-tab\"\n data-active={i === safeIndex ? 'true' : 'false'}\n aria-selected={i === safeIndex}\n onMouseDown={(e) => e.stopPropagation()}\n onClick={(e) => {\n e.stopPropagation();\n setActive(i);\n }}\n >\n {tabLabel(c.chartType, c.title, i, labels.tabLabel)}\n </button>\n ))}\n </div>\n ) : null}\n <div className=\"tmr-chart-canvas-host\" style={{ height }}>\n <canvas ref={canvasRef} />\n </div>\n </NodeViewWrapper>\n );\n}\n","import { ReactNodeViewRenderer } from '@tiptap/react';\nimport { reportChart, type ReportChartOptions } from './ChartExtension';\nimport { ChartView } from '../components/ChartView';\nimport type { ChartTheme } from './types';\nimport type { ChartLabels } from '../labels';\n\nexport interface CreateChartOptions {\n /** When true, reserved for future in-place chart editing. Currently unused (no edit UI). Default false. */\n editable?: boolean;\n chartTheme?: ChartTheme | null;\n chartLabels?: Partial<ChartLabels>;\n}\n\nexport interface InteractiveChartOptions extends ReportChartOptions {\n chartEditable: boolean;\n chartTheme: ChartTheme | null;\n chartLabels?: Partial<ChartLabels>;\n}\n\n/**\n * Client chart extension with React NodeView.\n * Server / pure HTML paths should use {@link reportChart} / {@link pureChart}.\n */\nexport function createChart(options: CreateChartOptions = {}) {\n // Chart config editing (modal) is disabled for now; keep option for later.\n const { editable = false, chartTheme = null, chartLabels } = options;\n return reportChart.extend<InteractiveChartOptions>({\n addOptions() {\n return {\n HTMLAttributes: {},\n chartEditable: editable,\n chartTheme,\n chartLabels,\n };\n },\n addNodeView() {\n return ReactNodeViewRenderer(ChartView);\n },\n });\n}\n","'use client';\n\nimport * as DropdownMenu from '@radix-ui/react-dropdown-menu';\nimport {\n NodeViewContent,\n NodeViewWrapper,\n type NodeViewProps,\n} from '@tiptap/react';\nimport { CheckIcon, ChevronDownIcon, TrashIcon } from '../icons';\nimport { defaultCodeBlockLabels, type CodeBlockLabels } from '../labels';\nimport styles from '../styles/codeBlock.module.css';\n\n// 语言选择可选项。空 value = Auto-detect(交给 lowlight 自动识别)\nconst LANGUAGES: { value: string; label: string }[] = [\n { value: '', label: 'Auto-detect' },\n { value: 'javascript', label: 'JavaScript' },\n { value: 'typescript', label: 'TypeScript' },\n { value: 'python', label: 'Python' },\n { value: 'java', label: 'Java' },\n { value: 'go', label: 'Go' },\n { value: 'rust', label: 'Rust' },\n { value: 'c', label: 'C' },\n { value: 'cpp', label: 'C++' },\n { value: 'csharp', label: 'C#' },\n { value: 'sql', label: 'SQL' },\n { value: 'json', label: 'JSON' },\n { value: 'yaml', label: 'YAML' },\n { value: 'bash', label: 'Bash' },\n { value: 'shell', label: 'Shell' },\n { value: 'html', label: 'HTML' },\n { value: 'css', label: 'CSS' },\n { value: 'markdown', label: 'Markdown' },\n];\n\n/**\n * 代码块自定义 NodeView:右上角语言选择器(Radix DropdownMenu,支持方向键导航)+ 删除。\n * 文案(Auto-detect / 删除标题)从扩展 options.codeBlockLabels 读取,缺省用英文默认。\n */\nexport function CodeBlockView({\n node,\n updateAttributes,\n deleteNode,\n extension,\n editor,\n}: NodeViewProps) {\n const labels: CodeBlockLabels = {\n ...defaultCodeBlockLabels,\n ...((extension?.options as { codeBlockLabels?: Partial<CodeBlockLabels> })\n ?.codeBlockLabels ?? {}),\n };\n const language = (node.attrs.language as string) || '';\n const current = LANGUAGES.find((l) => l.value === language);\n const currentLabel = current\n ? current.value === ''\n ? labels.autoDetect\n : current.label\n : labels.autoDetect;\n const editable = editor.isEditable;\n\n return (\n <NodeViewWrapper className={styles.wrapper}>\n {editable ? (\n <div className={styles.header} contentEditable={false}>\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={styles.langTrigger}\n aria-label=\"Code language\"\n >\n <span>{currentLabel}</span>\n <ChevronDownIcon size={14} className={styles.langChevron} />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className={styles.langMenu}\n sideOffset={4}\n align=\"end\"\n >\n {LANGUAGES.map((l) => {\n const optionLabel =\n l.value === '' ? labels.autoDetect : l.label;\n const selected = l.value === language;\n return (\n <DropdownMenu.Item\n key={l.value}\n className={`${styles.langItem}${selected ? ` ${styles.langItemSelected}` : ''}`}\n onSelect={() => updateAttributes({ language: l.value })}\n >\n <span className={styles.langItemCheck}>\n {selected ? <CheckIcon size={14} /> : null}\n </span>\n {optionLabel}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n <button\n type=\"button\"\n className={styles.deleteBtn}\n title={labels.delete}\n aria-label={labels.delete}\n onClick={() => deleteNode()}\n >\n <TrashIcon />\n </button>\n </div>\n ) : (\n // 只读:只展示语言标签,无下拉 / 删除等交互件\n <div className={styles.langBadge} contentEditable={false}>\n {currentLabel}\n </div>\n )}\n <pre className={styles.pre}>\n {/* code 标签是代码块标准内容容器;v3 类型未含 'code',运行时有效,故断言 */}\n <NodeViewContent as={'code' as 'div'} />\n </pre>\n </NodeViewWrapper>\n );\n}\n","'use client';\n\nimport CodeBlockLowlight, {\n type CodeBlockLowlightOptions,\n} from '@tiptap/extension-code-block-lowlight';\nimport FindAndReplace from '@tiptap/extension-find-and-replace';\nimport Image from '@tiptap/extension-image';\nimport { TableOfContents } from '@tiptap/extension-table-of-contents';\nimport { Markdown } from '@tiptap/markdown';\nimport {\n EditorContent,\n ReactNodeViewRenderer,\n useEditor,\n type AnyExtension,\n type Editor,\n} from '@tiptap/react';\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n} from 'react';\nimport {\n enrichMarkdownCitations,\n type SourceRef,\n} from '../citationUtils';\nimport type { RenderCitation } from '../citationTypes';\nimport { createCitationRef } from '../createCitationRef';\nimport { CommentMark } from '../commentAnchor/CommentMark';\nimport {\n COMMENT_ACTIVE_META,\n COMMENT_CLICK_META,\n COMMENT_GUTTER_META,\n commentAnchorExtension,\n} from '../commentAnchor/commentAnchorPlugin';\nimport {\n applyCommentAnchorsToEditor,\n collectCommentIds,\n focusComment,\n nextComment,\n} from '../commentAnchor/commentAnchorController';\nimport type {\n CommentClickPayload,\n CommentRef,\n} from '../commentAnchor/commentTypes';\nimport { baseExtensions, lowlight } from '../extensions';\nimport { FindReplaceBar } from './FindReplaceBar';\nimport { ImportPlaceholder } from '../importPlaceholder';\nimport type { CodeBlockLabels, FindLabels } from '../labels';\nimport { MarkdownFileDrop } from '../markdownFileDrop';\nimport {\n pendingAnchorExtension,\n setPendingAnchors,\n type PendingAnchor,\n} from '../pendingAnchor';\nimport { selectionKind, type SelectionKind } from '../selectionKind';\nimport { MarkdownPaste } from '../markdownPaste';\nimport { parseCodeTokenAsChartOrCodeBlock } from '../chart/codeBlockChartParse';\nimport { createChart } from '../chart/createChart';\nimport { prepareChartMarkdown } from '../chart/prepareChartMarkdown';\nimport '../styles/chart.css';\nimport '../styles/pending.css';\nimport '../styles/find.css';\nimport styles from '../styles/content.module.css';\nimport type { TocItem } from '../toc/extractToc';\nimport { makeTocGetId } from '../toc/tocSlug';\nimport { CodeBlockView } from './CodeBlockView';\n\n// 带语言选择器的代码块(自定义 React NodeView)。base 不含代码块,此增强版由编辑器注入。\n// addOptions 追加 codeBlockLabels,供 CodeBlockView 读取以本地化文案。\ntype CodeBlockOptions = CodeBlockLowlightOptions & {\n codeBlockLabels?: Partial<CodeBlockLabels>;\n};\n\nconst CodeBlock = CodeBlockLowlight.extend<CodeBlockOptions>({\n addOptions() {\n return {\n ...this.parent?.(),\n codeBlockLabels: undefined,\n } as CodeBlockOptions;\n },\n // Built-in `code` tokens often win over chart's custom fence tokenizer;\n // upgrade ```tmr-chart here so the mid-column card editor renders ChartView.\n parseMarkdown: (token, helpers) =>\n parseCodeTokenAsChartOrCodeBlock(token, helpers, 'codeBlock'),\n addNodeView() {\n return ReactNodeViewRenderer(CodeBlockView);\n },\n addKeyboardShortcuts() {\n return {\n Backspace: () => {\n const { state } = this.editor;\n const { selection } = state;\n const { empty, $anchor } = selection;\n\n // 1) 光标在「非空代码块」内容最前面:拦截,防止拆块漏文字(空块放行可删)\n if (\n empty &&\n $anchor.parent.type.name === this.name &&\n $anchor.parentOffset === 0 &&\n $anchor.parent.content.size > 0\n ) {\n return true;\n }\n\n // 2) 光标在「代码块后方块」的开头:先选中整个代码块(二次确认),不直接删\n if (empty && $anchor.parentOffset === 0) {\n const before = $anchor.before($anchor.depth);\n const prevNode = state.doc.resolve(before).nodeBefore;\n if (prevNode?.type.name === this.name) {\n const codeBlockPos = before - prevNode.nodeSize;\n this.editor.chain().setNodeSelection(codeBlockPos).run();\n return true;\n }\n }\n\n return false;\n },\n };\n },\n});\n\n// 块级图片:Backspace 二次确认删除(与代码块一致)。\nconst ImageWithConfirmDelete = Image.extend({\n addKeyboardShortcuts() {\n return {\n Backspace: () => {\n const { state } = this.editor;\n const { selection } = state;\n const { empty, $anchor } = selection;\n if (empty) {\n const nodeBefore = $anchor.nodeBefore;\n if (nodeBefore?.type.name === this.name) {\n const imagePos = $anchor.pos - nodeBefore.nodeSize;\n this.editor.chain().setNodeSelection(imagePos).run();\n return true;\n }\n }\n return false;\n },\n };\n },\n});\n\nexport interface MarkdownWysiwygEditorHandle {\n /** 取当前正文的 markdown 字符串。 */\n getMarkdown: () => string;\n /** 取当前正文的 HTML 字符串。 */\n getHTML: () => string;\n /** 取当前正文的 Tiptap JSON。 */\n getJSON: () => Record<string, unknown>;\n /** 底层 Tiptap Editor 实例(可能为 null,未就绪时)。 */\n getEditor: () => Editor | null;\n /** 聚焦评论:设 active + 滚动 + 光标落到区间起点。找不到返回 false。 */\n focusComment: (commentId: string) => boolean;\n /** 按文档顺序跳转评论(next / prev),返回目标 commentId。 */\n nextComment: (dir?: 'next' | 'prev') => string | null;\n /** 当前 doc 内已锚定的去重 commentId 列表(文档顺序)。 */\n getCommentIds: () => string[];\n /** 打开查找替换浮动条(宿主自己绑快捷键/按钮时用)。 */\n openFind: () => void;\n /** 收起查找替换浮动条,清空高亮并把焦点还给编辑器。 */\n closeFind: () => void;\n}\n\nexport interface MarkdownWysiwygEditorProps {\n /** 初始 markdown 内容。 */\n initialMarkdown?: string;\n /**\n * 是否可编辑,默认 true。false = 只读渲染,与编辑态同源同路径:\n * 同一套扩展 / NodeView / 样式,交互件(代码块语言选择、删除等)自动收起。\n * 只读态不应用评论锚定(comments 被忽略),与 MarkdownPreview 语义一致。\n */\n editable?: boolean;\n /**\n * 初始脚注来源:按 index 对齐 `[^n]`,写入 citationRef 的 url/title。\n * 仅影响初始 content;后续插入请用 `insertMarkdown(editor, md, sources)`。\n */\n sources?: SourceRef[];\n /**\n * 脚注圆标 NodeView 插槽。消费方用 Popover 包住 `defaultDom`,\n * 用 `index` 查自己的数据源。仅初始化时生效。\n */\n renderCitation?: RenderCitation;\n placeholder?: string;\n /** editor 实例就绪 / 销毁时回调,供外部工具栏使用。 */\n onEditorReady?: (editor: Editor | null) => void;\n /** 目录变化回调(正文标题增删改时),供侧边目录实时展示。 */\n onTocChange?: (items: TocItem[]) => void;\n /**\n * 粘贴纯文本时启发式检测 markdown 并自动转富文本(Shift+粘贴保持纯文本)。\n * 默认 true。仅初始化时生效。\n */\n markdownPaste?: boolean;\n /**\n * 支持把 .md / .markdown 文件拖拽或粘贴进编辑器,解析后插入到落点/光标处。\n * 默认 true。仅初始化时生效。\n */\n markdownFileDrop?: boolean;\n /** 追加的 Tiptap 扩展(在内置扩展之后注册)。 */\n extraExtensions?: AnyExtension[];\n /** 代码块 NodeView 的本地化文案。 */\n codeBlockLabels?: Partial<CodeBlockLabels>;\n /**\n * 「这段正在被 AI 改写」的高亮:宿主在提交请求时给上、回填或冲突时传空数组清空。\n * 走 decoration,**不进 markdown、不进 undo 历史**,能盖住表格与图表这类块级节点。\n */\n pendingAnchors?: PendingAnchor[];\n /** 点击待改写高亮区域时回调,给出锚点 id(宿主可用来跳回/取消)。 */\n onAnchorClick?: (id: string) => void;\n /**\n * 选区变化。宿主用它做「选中即出现引用」——塌缩成光标也会报(`empty: true`),\n * 好让引用跟着消失;`kind` 区分普通文字 / 表格单元格 / 整节点(图表)。\n */\n onSelectionChange?: (selection: {\n from: number;\n to: number;\n empty: boolean;\n kind: SelectionKind;\n }) => void;\n /** 附加到滚动容器的 class。 */\n className?: string;\n /**\n * 编辑态评论锚定:评论列表(含已解码 segments)。装载时映射为 commentAnchor\n * mark 并高亮;markdown 导出自动剥离,只读态(MarkdownPreview)不渲染评论。\n * 注意:数组引用变化会触发重新铺 mark,宿主应 memo 该数组。\n */\n comments?: CommentRef[];\n /** 受控 active 评论 id(sidebar 联动)。null = 无 active。 */\n activeCommentId?: string | null;\n /** 编辑器内点击 mark / gutter 时回调。 */\n onCommentClick?: (payload: CommentClickPayload) => void;\n /** active 变化回调(点击 mark / gutter / nextComment 时)。 */\n onActiveCommentChange?: (commentId: string | null) => void;\n /** 是否在 block 左缘渲染评论 gutter 气泡,默认 true。 */\n showCommentGutter?: boolean;\n /**\n * 编辑器内点评论 mark 是否可交互(设 active / 上报 click),默认 true。\n * 只靠侧栏单项驱动滚动定位时传 false。\n */\n commentInteractive?: boolean;\n /**\n * 启用查找替换(默认 true):注册官方 `@tiptap/extension-find-and-replace`\n * (自带命令 `setSearchTerm / replace / replaceAll / goToNextResult …` 与\n * `editor.storage.findAndReplace`),并按 {@link findShortcut} 打开浮动条。\n */\n findReplace?: boolean;\n /**\n * 焦点在编辑器内时接管 Cmd/Ctrl+F 打开查找条(默认 true)。传 false 则只保留\n * `handle.openFind()`——例如宿主想保留浏览器原生查找,或自己摆入口。\n * 焦点不在编辑器内时不接管,同页多编辑器不会互相抢。\n */\n findShortcut?: boolean;\n /** 查找替换浮动条的本地化文案。 */\n findLabels?: Partial<FindLabels>;\n}\n\n/**\n * 所见即所得 Markdown 编辑器(基于 Tiptap v3 + 官方 @tiptap/markdown)。\n * 内容进出均为 markdown 字符串。工具栏由外部渲染——通过 onEditorReady 拿到 editor 实例。\n */\nexport const MarkdownWysiwygEditor = forwardRef<\n MarkdownWysiwygEditorHandle,\n MarkdownWysiwygEditorProps\n>(function MarkdownWysiwygEditor(\n {\n initialMarkdown = '',\n editable = true,\n sources,\n renderCitation,\n placeholder,\n onEditorReady,\n onTocChange,\n markdownPaste = true,\n markdownFileDrop = true,\n extraExtensions,\n codeBlockLabels,\n className,\n comments,\n activeCommentId,\n onCommentClick,\n onActiveCommentChange,\n showCommentGutter = true,\n commentInteractive = true,\n pendingAnchors,\n onAnchorClick,\n onSelectionChange,\n findReplace = true,\n findShortcut = true,\n findLabels,\n },\n ref,\n) {\n const preparedInitial = prepareChartMarkdown(\n enrichMarkdownCitations(initialMarkdown, sources ?? []),\n );\n\n const [findOpen, setFindOpen] = useState(false);\n const findInputRef = useRef<HTMLInputElement | null>(null);\n\n const editor = useEditor({\n extensions: [\n ...baseExtensions,\n CodeBlock.configure({ lowlight, codeBlockLabels }),\n ImageWithConfirmDelete.configure({ inline: false }),\n ImportPlaceholder,\n createChart({ editable: false }),\n createCitationRef({ renderCitation }),\n CommentMark,\n commentAnchorExtension({\n showGutter: showCommentGutter,\n interactive: commentInteractive,\n }),\n Markdown,\n pendingAnchorExtension,\n // 官方查找替换:只出命令 / storage / 装饰,UI 自绘(见 FindReplaceBar)。\n // - injectCSS 关掉:它默认会往页面插一个 <style>,绕开宿主的 --tmr-* 主题与 style.css,\n // 命中样式改由 src/styles/find.css 承担。\n // - searchDebounceMs 关掉:官方防抖走 setTimeout,抛错会落在异步回调里兜不住;\n // 防抖改由浮动条自己做(见 findReplace.ts)。\n ...(findReplace\n ? [FindAndReplace.configure({ injectCSS: false, searchDebounceMs: 0 })]\n : []),\n TableOfContents.configure({\n getId: makeTocGetId(),\n onUpdate: (anchors) => {\n onTocChange?.(\n anchors\n .filter((a) => a.level <= 6)\n .map((a) => ({ id: a.id, level: a.level, text: a.textContent })),\n );\n },\n }),\n ...(markdownPaste ? [MarkdownPaste] : []),\n ...(markdownFileDrop ? [MarkdownFileDrop] : []),\n ...(extraExtensions ?? []),\n ],\n content: preparedInitial,\n contentType: 'markdown',\n editable,\n // Next.js SSR:服务端不立即渲染,避免 hydration 不一致\n immediatelyRender: false,\n editorProps: {\n attributes: {\n class: styles.editorContent,\n 'data-placeholder': placeholder ?? '',\n },\n },\n });\n\n useEffect(() => {\n onEditorReady?.(editor);\n return () => onEditorReady?.(null);\n }, [editor, onEditorReady]);\n\n // 运行时切换编辑/只读(同一实例,NodeView 交互件随 editor.isEditable 收起)。\n useEffect(() => {\n editor?.setEditable(editable);\n }, [editor, editable]);\n\n const closeFind = useCallback(() => {\n setFindOpen(false);\n // 焦点归还:Tiptap 的 focus 命令内部就是 requestAnimationFrame 延后执行的\n // (`delayedFocus`),正好落在 React 卸载浮动条之后——否则被卸载的输入框会把焦点丢给 body。\n editor?.commands.focus();\n }, [editor]);\n\n // Cmd/Ctrl+F → 打开查找条。接管条件必须收得比「焦点在编辑器内」松、比「谁都能接管」紧:\n // - 焦点在本编辑器内:接管 ✓\n // - 焦点不在任何输入控件里(body)且页面上只有本编辑器:接管 ✓(单编辑器页面点完工具栏按钮能直接按)\n // - 其余情况一律不接管:同页多编辑器时不会一起弹条(文档站就是这样),宿主的其它输入框\n // 也不会被夺走原生查找。多编辑器页面上宿主可自己调 handle.openFind()。\n useEffect(() => {\n if (!editor || !findReplace || !findShortcut) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (!(event.metaKey || event.ctrlKey) || event.altKey || event.shiftKey) {\n return;\n }\n if (event.key !== 'f' && event.key !== 'F') return;\n const active = document.activeElement;\n const inEditor = !!active && editor.view.dom.contains(active);\n const nothingFocused = active === null || active === document.body;\n const soleEditor = document.querySelectorAll('.ProseMirror').length <= 1;\n if (!inEditor && !editor.isFocused && !(nothingFocused && soleEditor)) {\n return;\n }\n event.preventDefault();\n setFindOpen(true);\n // 已打开时再按一次:聚焦并全选当前查询(首次打开由浮动条的 autoFocus 负责)\n requestAnimationFrame(() => findInputRef.current?.select());\n };\n document.addEventListener('keydown', onKeyDown, true);\n return () => document.removeEventListener('keydown', onKeyDown, true);\n }, [editor, findReplace, findShortcut]);\n\n // 评论列表 → 铺 mark。用 commentId 签名做防抖:宿主每次渲染传新数组引用时\n // 不会反复清/铺(清空再重铺会丢掉 mark 随编辑移动后的位置)。\n const commentsSignatureRef = useRef<string>('');\n useEffect(() => {\n // 只读态不接评论(与库的「评论锚定 = 编辑会话专属」契约一致)。\n if (!editor || !editable) return;\n const signature = (comments ?? [])\n .map((c) => `${c.commentId}:${c.segments.length}`)\n .join('|');\n if (signature === commentsSignatureRef.current) return;\n commentsSignatureRef.current = signature;\n applyCommentAnchorsToEditor(editor, comments ?? []);\n }, [editor, editable, comments]);\n\n // active 同步到插件(mark/block 高亮装饰);滚动定位走 handle.focusComment。\n useEffect(() => {\n if (!editor) return;\n editor.view.dispatch(\n editor.state.tr.setMeta(\n COMMENT_ACTIVE_META,\n activeCommentId ?? null,\n ),\n );\n }, [editor, activeCommentId]);\n\n // 待改写高亮:会话级装饰,不进 markdown / 不进 undo(宿主推入,回填或冲突时清空)。\n useEffect(() => {\n if (!editor) return;\n setPendingAnchors(editor, pendingAnchors ?? []);\n }, [editor, pendingAnchors]);\n\n // 点击待改写高亮 → 上报锚点 id。走 DOM 监听而不是插件 meta:这里只要「点了哪一段」。\n const onAnchorClickRef = useRef(onAnchorClick);\n useEffect(() => {\n onAnchorClickRef.current = onAnchorClick;\n }, [onAnchorClick]);\n useEffect(() => {\n if (!editor) return;\n const dom = editor.view.dom;\n const onClick = (event: MouseEvent) => {\n const target = event.target as HTMLElement | null;\n const id = target?.closest?.('[data-pending-id]')?.getAttribute('data-pending-id');\n if (id) onAnchorClickRef.current?.(id);\n };\n dom.addEventListener('click', onClick);\n return () => dom.removeEventListener('click', onClick);\n }, [editor]);\n\n // 选区变化:宿主据此做「选中即出现引用 / 引用跟着选区走」。\n const onSelectionChangeRef = useRef(onSelectionChange);\n useEffect(() => {\n onSelectionChangeRef.current = onSelectionChange;\n }, [onSelectionChange]);\n useEffect(() => {\n if (!editor) return;\n const onSelectionUpdate = () => {\n const { from, to, empty } = editor.state.selection;\n onSelectionChangeRef.current?.({\n from,\n to,\n empty,\n kind: selectionKind(editor.state.selection),\n });\n };\n editor.on('selectionUpdate', onSelectionUpdate);\n return () => {\n editor.off('selectionUpdate', onSelectionUpdate);\n };\n }, [editor]);\n\n // mark / gutter 点击 → 通过 transaction meta 上报宿主(回调走 ref 防 stale)。\n const onCommentClickRef = useRef(onCommentClick);\n const onActiveCommentChangeRef = useRef(onActiveCommentChange);\n onCommentClickRef.current = onCommentClick;\n onActiveCommentChangeRef.current = onActiveCommentChange;\n useEffect(() => {\n if (!editor) return;\n const onTransaction = ({\n transaction,\n }: {\n transaction: { getMeta: (key: string) => unknown };\n }) => {\n const click = transaction.getMeta(COMMENT_CLICK_META) as\n | CommentClickPayload\n | undefined;\n if (click) {\n onCommentClickRef.current?.(click);\n onActiveCommentChangeRef.current?.(click.commentIds[0] ?? null);\n }\n const gutter = transaction.getMeta(COMMENT_GUTTER_META) as\n | { commentIds: string[]; pos: number }\n | undefined;\n if (gutter) {\n onCommentClickRef.current?.({\n commentIds: gutter.commentIds,\n anchorEl: null,\n pos: gutter.pos,\n });\n onActiveCommentChangeRef.current?.(gutter.commentIds[0] ?? null);\n }\n };\n editor.on('transaction', onTransaction);\n return () => {\n editor.off('transaction', onTransaction);\n };\n }, [editor]);\n\n useImperativeHandle(\n ref,\n () => ({\n getMarkdown: () => editor?.getMarkdown?.() ?? '',\n getHTML: () => editor?.getHTML?.() ?? '',\n getJSON: () => (editor?.getJSON?.() as Record<string, unknown>) ?? {},\n getEditor: () => editor ?? null,\n focusComment: (commentId: string) =>\n editor ? focusComment(editor, commentId) : false,\n nextComment: (dir?: 'next' | 'prev') =>\n editor ? nextComment(editor, dir ?? 'next') : null,\n getCommentIds: () => (editor ? collectCommentIds(editor) : []),\n openFind: () => setFindOpen(true),\n closeFind,\n }),\n [editor, closeFind],\n );\n\n return (\n <div className={styles.editorHost}>\n {/* 粘性锚点排在正文之前:浮动条跟着最近的滚动容器走,正文滚动时不会被卷上去 */}\n {editor && findReplace && findOpen ? (\n <div className={styles.findBarAnchor}>\n <FindReplaceBar\n editor={editor}\n labels={findLabels}\n onClose={closeFind}\n inputRef={findInputRef}\n className={styles.findBar}\n />\n </div>\n ) : null}\n <EditorContent\n editor={editor}\n className={\n className ? `${styles.editorScroll} ${className}` : styles.editorScroll\n }\n />\n </div>\n );\n});\n","'use client';\n\nimport { Markdown } from '@tiptap/markdown';\nimport { EditorContent, useEditor } from '@tiptap/react';\nimport { useEffect, useMemo } from 'react';\nimport { createChart } from '../chart/createChart';\nimport { prepareChartMarkdown } from '../chart/prepareChartMarkdown';\nimport {\n enrichMarkdownCitations,\n type SourceRef,\n} from '../citationUtils';\nimport type { RenderCitation } from '../citationTypes';\nimport { createCitationRef } from '../createCitationRef';\nimport { baseExtensions, pureCodeBlock, pureImage } from '../extensions';\nimport '../styles/chart.css';\nimport styles from '../styles/content.module.css';\n\nexport interface MarkdownPreviewProps {\n /** 要预览的 markdown 字符串。 */\n markdown: string;\n /**\n * 脚注来源列表:按 `index` 与正文 `[^n]` 对齐,写入节点的 url/title。\n * 业务数据与 Popover 仍由消费方通过 {@link renderCitation} 完成。\n */\n sources?: SourceRef[];\n /**\n * 脚注圆标 NodeView 插槽。用 Popover 等包住 `defaultDom`;\n * 用 `index` / `attrs` 查消费方自己的数据源。\n */\n renderCitation?: RenderCitation;\n className?: string;\n}\n\n/**\n * 轻量只读 markdown 预览(Tiptap + 官方 @tiptap/markdown,editable:false)。\n * 与 MarkdownWysiwygEditor 共用同一套 base 扩展与正文样式类,渲染同源——\n * 预览所见即编辑/插入后所得。用纯版 CodeBlock/Image(无 React 视图 / 删除快捷键);\n * 图表用只读 NodeView(可渲染,不可编辑弹层)。\n *\n * 这是「客户端只读预览」;若需 SEO / 无 JS 静态渲染,请改用 server 入口的\n * renderReportHtml + ReportContent / ReportContentWithCharts。\n */\nexport function MarkdownPreview({\n markdown,\n sources,\n renderCitation,\n className,\n}: MarkdownPreviewProps) {\n const prepared = useMemo(\n () =>\n prepareChartMarkdown(\n enrichMarkdownCitations(markdown, sources ?? []),\n ),\n [markdown, sources],\n );\n\n const extensions = useMemo(\n () => [\n ...baseExtensions,\n pureCodeBlock,\n pureImage,\n createChart({ editable: false }),\n createCitationRef({ renderCitation }),\n Markdown,\n ],\n [renderCitation],\n );\n\n const editor = useEditor(\n {\n extensions,\n content: prepared,\n contentType: 'markdown',\n editable: false,\n immediatelyRender: false,\n editorProps: {\n attributes: { class: styles.editorContent },\n },\n },\n [extensions],\n );\n\n useEffect(() => {\n if (!editor) return;\n editor.commands.setContent(prepared, { contentType: 'markdown' });\n }, [editor, prepared]);\n\n return (\n <EditorContent\n editor={editor}\n className={className ?? styles.editorScroll}\n />\n );\n}\n","import type { ToolbarLabels } from './labels';\n\n/** 包内唯一识别的扩展名:命中即本地读文本,其余一律交给宿主回调。 */\nexport const MD_FILE_RE = /\\.(md|markdown)$/i;\nexport const MD_ACCEPT = '.md,.markdown,text/markdown';\n\n/** 主栏导入下拉里的一项。`accept` 写到隐藏 file input。 */\nexport interface ImportMenuItem {\n key: string;\n label: string;\n accept: string;\n}\n\nexport function resolveImportMenuItems({\n labels,\n onImportDocument,\n importAccept,\n importMenuItems,\n}: {\n labels: ToolbarLabels;\n onImportDocument?: unknown;\n importAccept?: string;\n importMenuItems?: ImportMenuItem[];\n}): ImportMenuItem[] {\n if (importMenuItems?.length) return importMenuItems;\n const markdown: ImportMenuItem = {\n key: 'markdown',\n label: labels.importMarkdown,\n accept: MD_ACCEPT,\n };\n if (onImportDocument && importAccept) {\n return [\n markdown,\n {\n key: 'document',\n label: labels.importDocumentOther,\n accept: importAccept,\n },\n ];\n }\n return [markdown];\n}\n","import '@tiptap/markdown';\nimport type { Editor } from '@tiptap/react';\nimport { prepareChartMarkdown } from './chart/prepareChartMarkdown';\nimport {\n enrichMarkdownCitations,\n type SourceRef,\n} from './citationUtils';\n\n/**\n * 在光标处插入 markdown 片段(封装 contentType: 'markdown')。\n * 传入 `sources` 时会先 enrich `[^n]` → 带 url 的 citation-ref,再插入。\n *\n * 整段过不了 schema(嵌套 bold、块级图进 listItem 等)时按块重试,\n * 单块仍挂则剥标记当段落。某一处脏输出不至于整次插入失败。\n */\nexport function insertMarkdown(\n editor: Editor,\n markdown: string,\n sources: SourceRef[] = [],\n): void {\n const prepared = prepareChartMarkdown(\n enrichMarkdownCitations(markdown, sources),\n );\n if (!prepared) return;\n if (tryInsertMarkdown(editor, prepared)) return;\n for (const block of splitTopLevelBlocks(prepared)) {\n if (tryInsertMarkdown(editor, block)) continue;\n insertPlainParagraph(editor, stripToPlainText(block));\n }\n}\n\nfunction tryInsertMarkdown(editor: Editor, markdown: string): boolean {\n try {\n return editor\n .chain()\n .focus()\n .insertContent(markdown, { contentType: 'markdown' })\n .run();\n } catch {\n return false;\n }\n}\n\nfunction insertPlainParagraph(editor: Editor, text: string): void {\n if (!text) return;\n editor\n .chain()\n .focus()\n .insertContent({\n type: 'paragraph',\n content: [{ type: 'text', text }],\n })\n .run();\n}\n\n/** 围栏代码整块留下,其余按空行切。 */\nexport function splitTopLevelBlocks(markdown: string): string[] {\n const out: string[] = [];\n for (const [i, part] of markdown.split(/(```[\\s\\S]*?```)/).entries()) {\n if (!part) continue;\n if (i % 2 === 1) {\n out.push(part);\n continue;\n }\n for (const block of part.split(/\\n{2,}/)) {\n if (block.trim()) out.push(block);\n }\n }\n return out;\n}\n\nexport function stripToPlainText(markdown: string): string {\n return markdown\n .replace(/!\\[[^\\]]*\\]\\([^)]+\\)/g, '')\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, '$1')\n .replace(/^#{1,6}\\s+/gm, '')\n .replace(/^[ \\t]*[-*+]\\s+/gm, '')\n .replace(/^[ \\t]*\\d+\\.\\s+/gm, '')\n .replace(/[*_~`]+/g, '')\n .replace(/<[^>]+>/g, '')\n .replace(/\\|/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n","import type { Editor } from '@tiptap/core';\nimport type { EditorState } from '@tiptap/pm/state';\nimport {\n CellSelection,\n isInTable,\n rowIsHeader,\n selectedRect,\n} from '@tiptap/pm/tables';\n\nexport interface TableSelectionInfo {\n rowCount: number;\n colCount: number;\n /** 选区跨越多行或多列时为 true(用于带 N 的文案)。 */\n isMultiCell: boolean;\n includesHeaderRow: boolean;\n coversAllRows: boolean;\n coversAllCols: boolean;\n}\n\n/** 当前若不在表格内返回 null。 */\nexport function getTableSelectionInfo(\n state: EditorState,\n): TableSelectionInfo | null {\n if (!isInTable(state)) return null;\n\n const rect = selectedRect(state);\n const rowCount = Math.max(1, rect.bottom - rect.top);\n const colCount = Math.max(1, rect.right - rect.left);\n\n let includesHeaderRow = false;\n for (let row = rect.top; row < rect.bottom; row++) {\n if (rowIsHeader(rect.map, rect.table, row)) {\n includesHeaderRow = true;\n break;\n }\n }\n\n return {\n rowCount,\n colCount,\n isMultiCell: rowCount > 1 || colCount > 1,\n includesHeaderRow,\n coversAllRows: rect.top === 0 && rect.bottom === rect.map.height,\n coversAllCols: rect.left === 0 && rect.right === rect.map.width,\n };\n}\n\n/** 文档坐标是否落在 CellSelection 覆盖的某个单元格内(含单元格节点本身)。 */\nexport function isPosInCellSelection(\n selection: CellSelection,\n pos: number,\n): boolean {\n let found = false;\n selection.forEachCell((node, cellPos) => {\n if (pos >= cellPos && pos <= cellPos + node.nodeSize) {\n found = true;\n }\n });\n return found;\n}\n\n/**\n * 表内右键:若点击落在已有多格选区内则保留选区;\n * 否则把光标落到点击位置(单格操作)。\n */\nexport function preserveTableSelectionOnContextMenu(\n editor: Editor,\n pos: number,\n): void {\n const { selection } = editor.state;\n if (\n selection instanceof CellSelection &&\n isPosInCellSelection(selection, pos)\n ) {\n editor.view.focus();\n return;\n }\n editor.chain().focus().setTextSelection(pos).run();\n}\n\nexport function addRowsBefore(editor: Editor, count: number): boolean {\n const n = Math.max(1, count);\n for (let i = 0; i < n; i++) {\n if (!editor.commands.addRowBefore()) return false;\n }\n return true;\n}\n\nexport function addRowsAfter(editor: Editor, count: number): boolean {\n const n = Math.max(1, count);\n for (let i = 0; i < n; i++) {\n if (!editor.commands.addRowAfter()) return false;\n }\n return true;\n}\n\nexport function addColumnsBefore(editor: Editor, count: number): boolean {\n const n = Math.max(1, count);\n for (let i = 0; i < n; i++) {\n if (!editor.commands.addColumnBefore()) return false;\n }\n return true;\n}\n\nexport function addColumnsAfter(editor: Editor, count: number): boolean {\n const n = Math.max(1, count);\n for (let i = 0; i < n; i++) {\n if (!editor.commands.addColumnAfter()) return false;\n }\n return true;\n}\n\n/** 删行:全表行被选中时改为删整表;含表头时调用方应先禁用。 */\nexport function deleteSelectedRows(editor: Editor): boolean {\n const info = getTableSelectionInfo(editor.state);\n if (!info) return false;\n if (info.coversAllRows) return editor.commands.deleteTable();\n return editor.commands.deleteRow();\n}\n\n/** 删列:选区覆盖全部列且同时覆盖全部行时删整表;仅覆盖全部列时失败(由 UI 禁用)。 */\nexport function deleteSelectedColumns(editor: Editor): boolean {\n const info = getTableSelectionInfo(editor.state);\n if (!info) return false;\n if (info.coversAllCols) {\n if (info.coversAllRows) return editor.commands.deleteTable();\n return false;\n }\n return editor.commands.deleteColumn();\n}\n","'use client';\n\nimport { defaultColorPaletteLabels, type ColorPaletteLabels } from '../labels';\nimport styles from '../styles/colorPalette.module.css';\n\n/**\n * 色板矩阵:10 个色相 × 6 个明度。\n * 第 1 行为纯色(最饱和),下方 5 行为同色相的明→暗变体。\n */\nconst PALETTE: string[][] = [\n ['#8b0000', '#ff0000', '#ff9100', '#ffeb00', '#00e000', '#00e5ff', '#4a86e8', '#0000ff', '#9900ff', '#ff00ff'],\n ['#dba0a0', '#e8b4c0', '#f5d9b8', '#f7f0c0', '#cfe8c4', '#bcd9d4', '#c4d4ec', '#cdd4e8', '#d6c4e0', '#e8c4dc'],\n ['#d28a8a', '#dd8c9c', '#eec49a', '#f0e29c', '#a9d4a0', '#94c0bc', '#a0bce4', '#a4b0d8', '#bca0d0', '#d49cc0'],\n ['#cc4444', '#d4506c', '#e89a5c', '#e8d05c', '#7cc06c', '#5ca09c', '#5c90e0', '#6478c8', '#9460c0', '#c45c98'],\n ['#a02020', '#b01030', '#c87410', '#c8a810', '#449030', '#2c706c', '#3060c0', '#1850a0', '#6428a0', '#a02868'],\n ['#5c1010', '#700818', '#7c4808', '#7c6808', '#205818', '#10403c', '#183c78', '#0c3060', '#3c1460', '#601838'],\n];\n\n// THEME 品牌色\nconst THEME_COLORS = ['#ff6719', '#ff5500'];\n\nexport interface ColorPaletteProps {\n /** 当前已应用的颜色(用于打勾),无则不选中。 */\n value?: string;\n /** 点击某色块。null 表示「None」(清除)。 */\n onPick: (color: string | null) => void;\n labels?: Partial<ColorPaletteLabels>;\n}\n\n/** 颜色面板:None 清除行 + 色板网格 + THEME 品牌色。 */\nexport function ColorPalette({ value, onPick, labels }: ColorPaletteProps) {\n const t = { ...defaultColorPaletteLabels, ...labels };\n const current = value?.toLowerCase();\n\n return (\n <div className={styles.palette}>\n <button\n type=\"button\"\n className={styles.noneRow}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onPick(null)}\n >\n <span className={styles.noneIcon} aria-hidden />\n <span className={styles.noneLabel}>{t.none}</span>\n </button>\n\n <div className={styles.grid}>\n {PALETTE.flat().map((c) => (\n <button\n key={c}\n type=\"button\"\n className={`${styles.swatch} ${\n current === c.toLowerCase() ? styles.swatchActive : ''\n }`}\n style={{ background: c }}\n title={c}\n aria-label={c}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onPick(c)}\n />\n ))}\n </div>\n\n <div className={styles.themeLabel}>{t.theme}</div>\n <div className={styles.themeRow}>\n {THEME_COLORS.map((c) => (\n <button\n key={c}\n type=\"button\"\n className={`${styles.swatch} ${\n current === c.toLowerCase() ? styles.swatchActive : ''\n }`}\n style={{ background: c }}\n title={c}\n aria-label={c}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onPick(c)}\n />\n ))}\n </div>\n </div>\n );\n}\n","'use client';\n\nimport type { Editor } from '@tiptap/react';\nimport {\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type RefObject,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { renderMathInto, type MathKind } from '../math';\nimport styles from '../styles/toolbar.module.css';\n\nexport interface MathEditorPopoverProps {\n editor: Editor;\n kind: MathKind;\n mode: 'insert' | 'edit';\n pos?: number;\n latex: string;\n /** 工具栏新插入:取消时删掉占位节点 */\n isNew?: boolean;\n newLabel: string;\n placeholder: string;\n doneLabel: string;\n onConfirm: (latex: string) => void;\n onCancel: () => void;\n}\n\nfunction resolveNodeEl(editor: Editor, pos: number): HTMLElement | null {\n const dom = editor.view.nodeDOM(pos);\n if (dom instanceof HTMLElement) return dom;\n if (dom instanceof Node) return dom.parentElement;\n return null;\n}\n\nfunction mathRenderTarget(el: HTMLElement, isBlock: boolean): HTMLElement {\n if (!isBlock) return el;\n return (el.querySelector('.block-math-inner') as HTMLElement | null) ?? el;\n}\n\nfunction getMathLayerStyle(\n editor: Editor,\n kind: MathKind,\n pos?: number,\n): CSSProperties {\n const host = editor.view.dom.parentElement;\n if (!host) return {};\n const hostRect = host.getBoundingClientRect();\n const editorRect = editor.view.dom.getBoundingClientRect();\n const gap = 6;\n const blockWidth = editor.view.dom.clientWidth;\n\n if (pos != null) {\n const el = resolveNodeEl(editor, pos);\n if (el) {\n const r = el.getBoundingClientRect();\n const top = r.bottom - hostRect.top + gap;\n if (kind === 'block') {\n return {\n left: editorRect.left - hostRect.left,\n top,\n width: blockWidth,\n };\n }\n return {\n left: r.left - hostRect.left,\n top,\n };\n }\n }\n\n const coords = editor.view.coordsAtPos(editor.state.selection.from);\n if (kind === 'block') {\n return {\n left: editorRect.left - hostRect.left,\n top: coords.bottom - hostRect.top + gap,\n width: blockWidth,\n };\n }\n return {\n left: coords.left - hostRect.left,\n top: coords.bottom - hostRect.top + gap,\n };\n}\n\nexport function MathEditorPopover({\n editor,\n kind,\n mode,\n pos,\n latex,\n isNew = false,\n newLabel,\n placeholder,\n doneLabel,\n onConfirm,\n onCancel,\n}: MathEditorPopoverProps) {\n const [draft, setDraft] = useState(latex);\n const [layerStyle, setLayerStyle] = useState<CSSProperties>(() =>\n getMathLayerStyle(editor, kind, pos),\n );\n const titleId = useId();\n const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement>(null);\n const rootRef = useRef<HTMLDivElement>(null);\n const isBlock = kind === 'block';\n const host = editor.view.dom.parentElement;\n\n useEffect(() => {\n setDraft(latex);\n }, [latex]);\n\n useEffect(() => {\n const update = () => setLayerStyle(getMathLayerStyle(editor, kind, pos));\n update();\n window.addEventListener('resize', update);\n return () => window.removeEventListener('resize', update);\n }, [editor, kind, pos, draft]);\n\n useEffect(() => {\n inputRef.current?.focus();\n }, []);\n\n useEffect(() => {\n if (pos == null) return;\n const el = resolveNodeEl(editor, pos);\n if (!el) return;\n el.classList.add('tmr-math-editing');\n return () => {\n el.classList.remove('tmr-math-editing');\n };\n }, [editor, pos]);\n\n useEffect(() => {\n if (pos == null) return;\n const el = resolveNodeEl(editor, pos);\n if (!el) return;\n const target = mathRenderTarget(el, isBlock);\n const src = draft.trim();\n if (src) renderMathInto(target, src, isBlock);\n else target.textContent = '';\n }, [draft, pos, editor, isBlock]);\n\n useEffect(() => {\n if (pos == null || isNew) return;\n const el = resolveNodeEl(editor, pos);\n if (!el) return;\n const target = mathRenderTarget(el, isBlock);\n return () => {\n const restore = latex.trim();\n if (restore) renderMathInto(target, restore, isBlock);\n else target.textContent = '';\n };\n }, [pos, editor, isBlock, latex, isNew]);\n\n useEffect(() => {\n const onPtr = (e: PointerEvent) => {\n const target = e.target;\n if (!(target instanceof Node)) return;\n if (rootRef.current?.contains(target)) return;\n if (pos != null) {\n const el = resolveNodeEl(editor, pos);\n if (el?.contains(target)) return;\n }\n onCancel();\n };\n document.addEventListener('pointerdown', onPtr);\n return () => document.removeEventListener('pointerdown', onPtr);\n }, [onCancel, editor, pos]);\n\n const canSubmit = draft.trim().length > 0;\n const showHint = !canSubmit && (mode === 'insert' || isNew);\n\n const submit = () => {\n if (!canSubmit) return;\n onConfirm(draft.trim());\n };\n\n const onKeyDown = (\n e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>,\n ) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onCancel();\n return;\n }\n if (e.key !== 'Enter') return;\n if (isBlock && !(e.metaKey || e.ctrlKey)) return;\n e.preventDefault();\n submit();\n };\n\n const field = isBlock ? (\n <textarea\n ref={inputRef as RefObject<HTMLTextAreaElement>}\n className={styles.mathInput}\n value={draft}\n placeholder={placeholder}\n rows={Math.max(3, draft.split('\\n').length)}\n aria-labelledby={titleId}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={onKeyDown}\n />\n ) : (\n <input\n ref={inputRef as RefObject<HTMLInputElement>}\n className={styles.mathInput}\n value={draft}\n placeholder={placeholder}\n aria-labelledby={titleId}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={onKeyDown}\n />\n );\n\n if (!host) return null;\n\n return createPortal(\n <div\n ref={rootRef}\n className={styles.mathLayer}\n style={layerStyle}\n role=\"dialog\"\n aria-modal=\"false\"\n aria-labelledby={titleId}\n >\n <div\n className={\n isBlock\n ? `${styles.mathStack} ${styles.mathStackBlock}`\n : styles.mathStack\n }\n >\n {showHint ? (\n <div\n id={titleId}\n className={\n isBlock\n ? `${styles.mathHint} ${styles.mathHintBlock}`\n : styles.mathHint\n }\n >\n <span className={styles.mathHintIcon} aria-hidden>\n {isBlock ? 'TeX' : '√x'}\n </span>\n {newLabel}\n </div>\n ) : null}\n <div\n id={showHint ? undefined : titleId}\n className={\n isBlock\n ? `${styles.mathField} ${styles.mathFieldBlock}`\n : styles.mathField\n }\n >\n {field}\n <button\n type=\"button\"\n className={styles.mathDone}\n disabled={!canSubmit}\n title={\n isBlock ? `${doneLabel} (⌘/Ctrl+Enter)` : `${doneLabel} (Enter)`\n }\n onClick={submit}\n >\n {doneLabel}\n <span className={styles.mathDoneKbd} aria-hidden>\n ↵\n </span>\n </button>\n </div>\n </div>\n </div>,\n host,\n );\n}\n","'use client';\n\nimport * as Popover from '@radix-ui/react-popover';\nimport { useEditorState, type Editor } from '@tiptap/react';\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n BoldIcon,\n ChevronDownIcon,\n CodeIcon,\n ColumnAfterIcon,\n ColumnBeforeIcon,\n ColumnDeleteIcon,\n ImageIcon,\n ItalicIcon,\n LinkIcon,\n ListChecksIcon,\n ListOrderedIcon,\n ListUnorderedIcon,\n RedoIcon,\n RowAfterIcon,\n RowBeforeIcon,\n RowDeleteIcon,\n StrikethroughIcon,\n TableDeleteIcon,\n UnderlineIcon,\n UndoIcon,\n} from '../icons';\nimport { defaultToolbarLabels, type ToolbarLabels } from '../labels';\nimport {\n MD_FILE_RE,\n resolveImportMenuItems,\n type ImportMenuItem,\n} from '../importMenu';\nimport type { SourceRef } from '../citationUtils';\nimport { insertMarkdown } from '../insertMarkdown';\nimport { subscribeMathClick, type MathKind } from '../math';\nimport {\n addColumnsAfter,\n addColumnsBefore,\n addRowsAfter,\n addRowsBefore,\n deleteSelectedColumns,\n deleteSelectedRows,\n getTableSelectionInfo,\n preserveTableSelectionOnContextMenu,\n} from '../tableSelection';\nimport styles from '../styles/toolbar.module.css';\nimport { ColorPalette } from './ColorPalette';\nimport { MathEditorPopover } from './MathEditorPopover';\n\n/** `onImportDocument` 的成功返回。给字符串等价于 `{ markdown }`。 */\nexport interface ImportDocumentResult {\n markdown: string;\n sources?: SourceRef[];\n}\n\n/** 导入进度。包用来更新光标占位文案并禁用导入按钮。 */\nexport interface ImportDocumentProgress {\n /** 0–1。通常只有上传阶段可测;转换阶段可省略。 */\n ratio?: number;\n phase: 'upload' | 'convert';\n}\n\nexport interface ImportDocumentContext {\n /** 用户点取消或组件卸载时 abort,宿主据此中断请求。 */\n signal: AbortSignal;\n onProgress?: (p: ImportDocumentProgress) => void;\n}\n\n/** More 菜单里注入的自定义项(宿主用它扩展工具栏,如「导入项目报告」)。 */\nexport interface ExtraToolbarItem {\n key: string;\n /** 左侧图标插槽(可选,文字或 SVG 皆可)。 */\n icon?: ReactNode;\n label: string;\n disabled?: boolean;\n /** 点击回调,拿到 editor 实例自行操作(如 insertContent)。 */\n onSelect: (editor: Editor) => void;\n}\n\nexport interface EditorToolbarProps {\n editor: Editor;\n /**\n * 图片上传回调:收到文件,返回可访问的图片 URL。未提供则不显示图片按钮。\n * 抛错会转交 onError(..., 'image')。\n */\n onImageUpload?: (file: File) => Promise<string>;\n /**\n * 副作用错误回调(图片上传 / Markdown 导入失败),供宿主弹自己的提示。\n * `source` 区分来源,避免一律显示「图片上传失败」。\n */\n onError?: (err: unknown, source?: 'image' | 'markdown' | 'import') => void;\n /**\n * 非 Markdown 文件的转换:收到文件,返回可插入的 Markdown。未提供则导入只吃 .md。\n * 包内不校验扩展名——格式白名单由宿主的 `importAccept` 与本回调自己负责。\n * 抛错转交 onError(..., 'import');`AbortError` 视为用户取消,不报错。\n */\n onImportDocument?: (\n file: File,\n ctx: ImportDocumentContext,\n ) => Promise<ImportDocumentResult | string>;\n /**\n * 追加到导入 input 的 accept(默认已含 `.md,.markdown,text/markdown`)。\n * 例:`.doc,.docx,.csv,.pdf`。未传 `importMenuItems` 且传了 `onImportDocument` 时,\n * 下拉会多一项「Document」。\n */\n importAccept?: string;\n /**\n * 主栏导入下拉的选项。不传则 Markdown;再加 `onImportDocument` + `importAccept`\n * 时多一项 Document。宿主要拆成 Word / PDF 时自己传入。\n */\n importMenuItems?: ImportMenuItem[];\n /** 是否显示导入下拉,默认 `true`。卡片等场景可关掉。 */\n showImport?: boolean;\n labels?: Partial<ToolbarLabels>;\n /** 追加到 More 菜单末尾的自定义项。 */\n extraToolbarItems?: ExtraToolbarItem[];\n className?: string;\n}\n\nexport type { ImportMenuItem };\n\n/** 单个工具栏按钮:激活态高亮,disabled 时灰显。 */\nfunction ToolbarButton({\n title,\n active,\n disabled,\n busy,\n onClick,\n children,\n}: {\n title: string;\n active?: boolean;\n disabled?: boolean;\n busy?: boolean;\n onClick: () => void;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n title={title}\n aria-label={title}\n aria-pressed={active}\n aria-busy={busy}\n disabled={disabled}\n className={`${styles.btn} ${active ? styles.btnActive : ''}`}\n // mousedown + preventDefault 防止点击工具栏时编辑器失焦丢选区\n onMouseDown={(e) => e.preventDefault()}\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n\nfunction Divider() {\n return <span className={styles.divider} aria-hidden />;\n}\n\nfunction TableMenuItem({\n label,\n disabled,\n onClick,\n children,\n}: {\n label: string;\n disabled?: boolean;\n onClick: () => void;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n disabled={disabled}\n className={styles.tableMenuItem}\n onMouseDown={(e) => e.preventDefault()}\n onClick={onClick}\n >\n <span className={styles.tableMenuItemIcon} aria-hidden>\n {children}\n </span>\n <span className={styles.tableMenuItemLabel}>{label}</span>\n </button>\n );\n}\n\nfunction TableMenuDivider() {\n return <div className={styles.tableMenuDivider} aria-hidden />;\n}\n\n// 关闭当前菜单的回调(由 MenuPopover 注入,MenuItem 选中后调用以收起)。\nconst MenuCloseCtx = createContext<() => void>(() => {});\n\n/**\n * 菜单气泡:用 Radix Popover 而非 DropdownMenu——后者会强制抢焦点(menu 语义),\n * 打开即让编辑器 blur、丢选区;Popover 可 onOpenAutoFocus preventDefault 保持编辑器焦点。\n * 菜单项为普通 button(onMouseDown preventDefault 不夺焦),行为与原 antd 一致。\n */\nfunction MenuPopover({\n trigger,\n children,\n}: {\n trigger: ReactNode;\n children: ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n const close = useCallback(() => setOpen(false), []);\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger asChild>{trigger}</Popover.Trigger>\n <Popover.Portal>\n <Popover.Content\n className={styles.menu}\n sideOffset={4}\n align=\"start\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n >\n <MenuCloseCtx.Provider value={close}>\n {children}\n </MenuCloseCtx.Provider>\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\nfunction MenuItem({\n selected,\n disabled,\n onSelect,\n children,\n}: {\n selected?: boolean;\n disabled?: boolean;\n onSelect: () => void;\n children: ReactNode;\n}) {\n const close = useContext(MenuCloseCtx);\n return (\n <button\n type=\"button\"\n disabled={disabled}\n className={`${styles.menuItem} ${selected ? styles.menuItemSelected : ''}`}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => {\n onSelect();\n close();\n }}\n >\n {children}\n </button>\n );\n}\n\nconst TABLE_PICKER_COLS = 10;\nconst TABLE_PICKER_ROWS = 8;\n\n/**\n * More 菜单里的「插入表格」:二级面板用网格悬停选行列,点击插入。\n * 保持 Popover(不夺编辑器焦点),与 MenuItem 一致。\n */\nfunction TableInsertItem({\n disabled,\n labels,\n onInsert,\n}: {\n disabled?: boolean;\n labels: Pick<ToolbarLabels, 'tableInsert' | 'tableSizeSelected'>;\n onInsert: (rows: number, cols: number) => void;\n}) {\n const closeMenu = useContext(MenuCloseCtx);\n const [open, setOpen] = useState(false);\n const [hover, setHover] = useState({ cols: 0, rows: 0 });\n\n const resetHover = useCallback(() => setHover({ cols: 0, rows: 0 }), []);\n\n return (\n <Popover.Root\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) resetHover();\n }}\n >\n <Popover.Trigger asChild>\n <button\n type=\"button\"\n disabled={disabled}\n className={`${styles.menuItem} ${open ? styles.menuItemSelected : ''}`}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>⊞</span>\n {labels.tableInsert}\n </span>\n <ChevronDownIcon size={12} className={styles.tableInsertCaret} />\n </button>\n </Popover.Trigger>\n <Popover.Portal>\n <Popover.Content\n className={styles.tableSizePicker}\n side=\"right\"\n align=\"start\"\n sideOffset={6}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n >\n <div\n className={styles.tableSizeGrid}\n style={{\n gridTemplateColumns: `repeat(${TABLE_PICKER_COLS}, 1fr)`,\n }}\n onMouseLeave={resetHover}\n >\n {Array.from({ length: TABLE_PICKER_ROWS * TABLE_PICKER_COLS }, (_, i) => {\n const col = (i % TABLE_PICKER_COLS) + 1;\n const row = Math.floor(i / TABLE_PICKER_COLS) + 1;\n const active = hover.cols > 0 && col <= hover.cols && row <= hover.rows;\n return (\n <button\n key={i}\n type=\"button\"\n aria-label={labels.tableSizeSelected(col, row)}\n className={`${styles.tableSizeCell} ${active ? styles.tableSizeCellActive : ''}`}\n onMouseDown={(e) => e.preventDefault()}\n onMouseEnter={() => setHover({ cols: col, rows: row })}\n onClick={() => {\n onInsert(row, col);\n setOpen(false);\n resetHover();\n closeMenu();\n }}\n />\n );\n })}\n </div>\n <div className={styles.tableSizeLabel}>\n {hover.cols > 0\n ? labels.tableSizeSelected(hover.cols, hover.rows)\n : labels.tableInsert}\n </div>\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\n/** 颜色气泡:点色块即应用并关闭。 */\nfunction ColorPopover({\n title,\n glyph,\n bar,\n value,\n onPick,\n paletteLabels,\n}: {\n title: string;\n glyph: string;\n bar: string;\n value?: string;\n onPick: (color: string | null) => void;\n paletteLabels: { none: string; theme: string };\n}) {\n const [open, setOpen] = useState(false);\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger asChild>\n <button\n type=\"button\"\n className={styles.btn}\n title={title}\n aria-label={title}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.colorIcon}>\n <span className={styles.colorIconGlyph}>{glyph}</span>\n <span className={styles.colorIconBar} style={{ background: bar }} />\n </span>\n </button>\n </Popover.Trigger>\n <Popover.Portal>\n <Popover.Content\n className={styles.popoverContent}\n sideOffset={4}\n align=\"start\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n >\n <ColorPalette\n value={value}\n onPick={(c) => {\n onPick(c);\n setOpen(false);\n }}\n labels={paletteLabels}\n />\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\nconst HEADING_LEVELS = [1, 2, 3, 4, 5, 6] as const;\nconst FONT_SIZES = ['12px', '14px', '16px', '18px', '20px', '24px', '30px'] as const;\n\n/**\n * 顶部操作栏(antd-free,Radix Popover 菜单 + 内联 SVG 图标)。位置由父级控制,\n * 这里只渲染按钮 + 反映 editor 激活态。不含业务耦合,扩展项经 extraToolbarItems 注入。\n */\nexport function EditorToolbar({\n editor,\n onImageUpload,\n onError,\n onImportDocument,\n importAccept,\n importMenuItems,\n showImport = true,\n labels,\n extraToolbarItems,\n className,\n}: EditorToolbarProps) {\n const t: ToolbarLabels = { ...defaultToolbarLabels, ...labels };\n\n const state = useEditorState({\n editor,\n selector: ({ editor: e }) => ({\n bold: e.isActive('bold'),\n italic: e.isActive('italic'),\n underline: e.isActive('underline'),\n strike: e.isActive('strike'),\n code: e.isActive('code'),\n link: e.isActive('link'),\n taskList: e.isActive('taskList'),\n headingLevel: ([1, 2, 3, 4, 5, 6] as const).find((lv) =>\n e.isActive('heading', { level: lv }),\n ),\n fontSize: (e.getAttributes('textStyle').fontSize as string) || undefined,\n isParagraph: e.isActive('paragraph'),\n bulletList: e.isActive('bulletList'),\n orderedList: e.isActive('orderedList'),\n blockquote: e.isActive('blockquote'),\n textColor: (e.getAttributes('textStyle').color as string) || undefined,\n highlightColor:\n (e.getAttributes('highlight').color as string) || undefined,\n superscript: e.isActive('superscript'),\n subscript: e.isActive('subscript'),\n inTable: e.isActive('table'),\n canUndo: e.can().undo(),\n canRedo: e.can().redo(),\n }),\n });\n\n // 编辑器是否聚焦:仅正文聚焦时才允许调字号。Popover 菜单开/关已阻止抢焦点,\n // 故打开下拉不会误触 blur。\n const [editorFocused, setEditorFocused] = useState(() => editor.isFocused);\n useEffect(() => {\n const onFocus = () => setEditorFocused(true);\n const onBlur = () => setEditorFocused(false);\n editor.on('focus', onFocus);\n editor.on('blur', onBlur);\n return () => {\n editor.off('focus', onFocus);\n editor.off('blur', onBlur);\n };\n }, [editor]);\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n const chain = () => editor.chain().focus();\n\n // ── 表格工具条(右键召唤):右键单元格时在鼠标处弹出,点别处/Esc 隐藏 ──\n const [tableMenu, setTableMenu] = useState<{ x: number; y: number } | null>(\n null,\n );\n const closeTableMenu = useCallback(() => setTableMenu(null), []);\n\n useEffect(() => {\n const dom = editor.view.dom;\n const onContextMenu = (e: MouseEvent) => {\n const coords = editor.view.posAtCoords({\n left: e.clientX,\n top: e.clientY,\n });\n if (!coords) return;\n const $pos = editor.state.doc.resolve(coords.pos);\n let inTable = false;\n for (let d = $pos.depth; d > 0; d--) {\n if ($pos.node(d).type.name === 'table') {\n inTable = true;\n break;\n }\n }\n if (!inTable) return;\n e.preventDefault();\n // 多格选区内右键:保留 CellSelection;选区外才落到点击位\n preserveTableSelectionOnContextMenu(editor, coords.pos);\n setTableMenu({ x: e.clientX, y: e.clientY });\n };\n dom.addEventListener('contextmenu', onContextMenu);\n return () => dom.removeEventListener('contextmenu', onContextMenu);\n }, [editor]);\n\n useEffect(() => {\n if (!tableMenu) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') closeTableMenu();\n };\n document.addEventListener('mousedown', closeTableMenu);\n document.addEventListener('keydown', onKey, true);\n return () => {\n document.removeEventListener('mousedown', closeTableMenu);\n document.removeEventListener('keydown', onKey, true);\n };\n }, [tableMenu, closeTableMenu]);\n\n const runTable = useCallback(\n (fn: () => void) => {\n fn();\n closeTableMenu();\n },\n [closeTableMenu],\n );\n\n const tableSel = tableMenu ? getTableSelectionInfo(editor.state) : null;\n const tableRowN = tableSel?.rowCount ?? 1;\n const tableColN = tableSel?.colCount ?? 1;\n const tableMulti = tableSel?.isMultiCell ?? false;\n const disableAddRowBefore = !!tableSel?.includesHeaderRow;\n const disableDeleteRow = !!tableSel?.includesHeaderRow;\n const disableDeleteColumn =\n !!tableSel?.coversAllCols && !tableSel?.coversAllRows;\n\n // ── 图片:选图 → onImageUpload → 插入返回的 URL ──\n const handlePickImage = () => fileInputRef.current?.click();\n const handleImageChange = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (!file || !onImageUpload) return;\n try {\n const url = await onImageUpload(file);\n if (!url) throw new Error('empty url');\n chain().setImage({ src: url }).run();\n } catch (err) {\n console.error('image upload failed:', err);\n onError?.(err, 'image');\n }\n };\n\n // ── 导入:.md 包内读文本插入;其余原样交给宿主 onImportDocument ──\n const importInputRef = useRef<HTMLInputElement>(null);\n const [importing, setImporting] = useState<ImportDocumentProgress | null>(\n null,\n );\n const importAbortRef = useRef<AbortController | null>(null);\n\n // 卸载(如切路由)中断在飞的导入,避免请求泄漏与卸载后 setState\n useEffect(() => () => importAbortRef.current?.abort(), []);\n\n const handleImportChange = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (!file) return;\n\n if (MD_FILE_RE.test(file.name)) {\n try {\n insertMarkdown(editor, await file.text());\n } catch (err) {\n console.error('markdown import failed:', err);\n onError?.(err, 'markdown');\n }\n return;\n }\n\n if (!onImportDocument) {\n onError?.(new Error(`unsupported file: ${file.name}`), 'import');\n return;\n }\n\n const ctrl = new AbortController();\n importAbortRef.current = ctrl;\n setImporting({ phase: 'upload', ratio: 0 });\n const labelOf = (p: ImportDocumentProgress) =>\n p.phase === 'convert'\n ? t.importDocumentConverting\n : t.importDocumentUploading(Math.round((p.ratio ?? 0) * 100));\n editor.commands.insertImportPlaceholder(labelOf({ phase: 'upload', ratio: 0 }));\n try {\n const raw = await onImportDocument(file, {\n signal: ctrl.signal,\n onProgress: (p) => {\n if (ctrl.signal.aborted) return;\n setImporting(p);\n editor.commands.updateImportPlaceholder(labelOf(p));\n },\n });\n editor.commands.removeImportPlaceholder();\n const md = typeof raw === 'string' ? raw : raw.markdown;\n const sources = typeof raw === 'string' ? [] : raw.sources ?? [];\n insertMarkdown(editor, md, sources);\n } catch (err) {\n editor.commands.removeImportPlaceholder();\n // 卸载 abort 不算错误\n if (!ctrl.signal.aborted) {\n console.error('document import failed:', err);\n onError?.(err, 'import');\n }\n } finally {\n if (importAbortRef.current === ctrl) importAbortRef.current = null;\n setImporting(null);\n }\n };\n\n const importItems = resolveImportMenuItems({\n labels: t,\n onImportDocument,\n importAccept,\n importMenuItems,\n });\n\n const pickImport = (accept: string) => {\n const input = importInputRef.current;\n if (!input) return;\n input.accept = accept;\n input.value = '';\n input.click();\n };\n\n // 进度写在光标占位上;按钮只区分空闲 / 忙碌。\n const importTitle = importing ? t.importDocumentBusy : t.importDocumentHint;\n\n const applyTextColor = (color: string | null) => {\n if (color) chain().setColor(color).run();\n else chain().unsetColor().run();\n };\n const applyHighlight = (color: string | null) => {\n if (color) chain().setHighlight({ color }).run();\n else chain().unsetHighlight().run();\n };\n\n const toggleLink = () => {\n if (state.link) {\n chain().unsetLink().run();\n return;\n }\n const url = window.prompt(t.linkPrompt);\n if (url) chain().setLink({ href: url }).run();\n };\n\n const setBlockStyle = (level: number) => {\n if (level === 0) chain().setParagraph().run();\n else\n chain()\n .toggleHeading({ level: level as 1 | 2 | 3 | 4 | 5 | 6 })\n .run();\n };\n\n const applyFontSize = (size: string) => {\n if (size) chain().setFontSize(size).run();\n else chain().unsetFontSize().run();\n };\n const canEditFontSize = editorFocused && state.isParagraph;\n\n const [mathEdit, setMathEdit] = useState<{\n kind: MathKind;\n mode: 'insert' | 'edit';\n pos?: number;\n latex: string;\n isNew?: boolean;\n } | null>(null);\n\n useEffect(() => subscribeMathClick((payload) => {\n setMathEdit({\n kind: payload.kind,\n mode: 'edit',\n pos: payload.pos,\n latex: payload.latex,\n });\n }), []);\n\n const openInsertMath = (kind: MathKind) => {\n const { from, to } = editor.state.selection;\n const selected =\n from === to ? '' : editor.state.doc.textBetween(from, to, ' ');\n const type = kind === 'inline' ? 'inlineMath' : 'blockMath';\n const searchFrom = from;\n chain().insertContent({ type, attrs: { latex: selected } }).run();\n let pos: number | null = null;\n editor.state.doc.nodesBetween(\n searchFrom,\n editor.state.doc.content.size,\n (node, nodePos) => {\n if (pos != null) return false;\n if (\n node.type.name === type &&\n String(node.attrs.latex ?? '') === selected\n ) {\n pos = nodePos;\n return false;\n }\n },\n );\n if (pos == null) {\n setMathEdit({ kind, mode: 'insert', latex: selected, isNew: true });\n return;\n }\n setMathEdit({\n kind,\n mode: 'edit',\n pos,\n latex: selected,\n isNew: true,\n });\n };\n\n const applyMath = (latex: string) => {\n if (!mathEdit) return;\n const { kind, mode, pos } = mathEdit;\n setMathEdit(null);\n if (mode === 'edit' && pos != null) {\n if (kind === 'inline') {\n chain().updateInlineMath({ latex, pos }).run();\n } else {\n chain().updateBlockMath({ latex, pos }).run();\n }\n return;\n }\n if (kind === 'inline') {\n chain().insertContent({ type: 'inlineMath', attrs: { latex } }).run();\n } else {\n chain().insertContent({ type: 'blockMath', attrs: { latex } }).run();\n }\n };\n\n const cancelMath = () => {\n if (!mathEdit) return;\n const { isNew, pos } = mathEdit;\n if (isNew && pos != null) {\n const node = editor.state.doc.nodeAt(pos);\n if (\n node &&\n (node.type.name === 'inlineMath' || node.type.name === 'blockMath')\n ) {\n editor\n .chain()\n .focus()\n .deleteRange({ from: pos, to: pos + node.nodeSize })\n .run();\n }\n }\n setMathEdit(null);\n };\n\n const scriptActive = state.superscript\n ? 'superscript'\n : state.subscript\n ? 'subscript'\n : 'normal';\n\n return (\n <>\n <div\n className={\n className ? `${styles.toolbar} ${className}` : styles.toolbar\n }\n >\n <div className={styles.inner}>\n {/* 撤销 / 重做 */}\n <ToolbarButton\n title={t.undo}\n disabled={!state.canUndo}\n onClick={() => chain().undo().run()}\n >\n <UndoIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.redo}\n disabled={!state.canRedo}\n onClick={() => chain().redo().run()}\n >\n <RedoIcon />\n </ToolbarButton>\n\n <Divider />\n\n {/* 段落样式下拉(正文 / 标题 1~6) */}\n <MenuPopover\n trigger={\n <button\n type=\"button\"\n className={styles.styleTrigger}\n title={t.style}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.styleTriggerLabel}>{t.style}</span>\n <ChevronDownIcon size={12} className={styles.styleTriggerCaret} />\n </button>\n }\n >\n <MenuItem\n selected={(state.headingLevel ?? 0) === 0}\n onSelect={() => setBlockStyle(0)}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>¶</span>\n {t.normalText}\n </span>\n </MenuItem>\n {HEADING_LEVELS.map((lv) => (\n <MenuItem\n key={lv}\n selected={state.headingLevel === lv}\n onSelect={() => setBlockStyle(lv)}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>{`H${lv}`}</span>\n {t.headingLabel(lv)}\n </span>\n </MenuItem>\n ))}\n </MenuPopover>\n\n {/* 正文字号下拉:仅正文可调 */}\n <MenuPopover\n trigger={\n <button\n type=\"button\"\n className={styles.styleTrigger}\n title={t.fontSize}\n aria-label={t.fontSize}\n disabled={!canEditFontSize}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.styleTriggerLabel}>\n {state.fontSize || t.fontSize}\n </span>\n <ChevronDownIcon size={12} className={styles.styleTriggerCaret} />\n </button>\n }\n >\n <MenuItem\n selected={!state.fontSize}\n onSelect={() => applyFontSize('')}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>A</span>\n {t.fontSizeDefault}\n </span>\n </MenuItem>\n {FONT_SIZES.map((size) => (\n <MenuItem\n key={size}\n selected={state.fontSize === size}\n onSelect={() => applyFontSize(size)}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>{parseInt(size, 10)}</span>\n {size}\n </span>\n </MenuItem>\n ))}\n </MenuPopover>\n\n <Divider />\n\n {/* 文字格式 */}\n <ToolbarButton\n title={t.bold}\n active={state.bold}\n onClick={() => chain().toggleBold().run()}\n >\n <BoldIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.italic}\n active={state.italic}\n onClick={() => chain().toggleItalic().run()}\n >\n <ItalicIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.underline}\n active={state.underline}\n onClick={() => chain().toggleUnderline().run()}\n >\n <UnderlineIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.strike}\n active={state.strike}\n onClick={() => chain().toggleStrike().run()}\n >\n <StrikethroughIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.code}\n active={state.code}\n onClick={() => chain().toggleCode().run()}\n >\n <CodeIcon />\n </ToolbarButton>\n\n {/* 文字颜色 */}\n <ColorPopover\n title={t.textColor}\n glyph=\"T\"\n bar={state.textColor || '#ff3b30'}\n value={state.textColor}\n onPick={applyTextColor}\n paletteLabels={{ none: t.colorNone, theme: t.colorTheme }}\n />\n {/* 文字高亮 */}\n <ColorPopover\n title={t.highlight}\n glyph=\"✎\"\n bar={state.highlightColor || '#ffd83d'}\n value={state.highlightColor}\n onPick={applyHighlight}\n paletteLabels={{ none: t.colorNone, theme: t.colorTheme }}\n />\n\n {/* 上标 / 下标下拉(A▾) */}\n <MenuPopover\n trigger={\n <button\n type=\"button\"\n className={`${styles.scriptTrigger} ${\n scriptActive !== 'normal' ? styles.btnActive : ''\n }`}\n title={t.scriptMenu}\n aria-label={t.scriptMenu}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.scriptTriggerGlyph}>A</span>\n <ChevronDownIcon size={12} className={styles.styleTriggerCaret} />\n </button>\n }\n >\n <MenuItem\n selected={scriptActive === 'normal'}\n onSelect={() => chain().unsetSuperscript().unsetSubscript().run()}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>A</span>\n {t.scriptNormal}\n </span>\n </MenuItem>\n <MenuItem\n selected={scriptActive === 'superscript'}\n onSelect={() => chain().unsetSubscript().toggleSuperscript().run()}\n >\n <span className={styles.styleItem}>\n <span className={`${styles.styleIcon} ${styles.scriptGlyph}`}>\n x<sup>2</sup>\n </span>\n {t.superscript}\n </span>\n </MenuItem>\n <MenuItem\n selected={scriptActive === 'subscript'}\n onSelect={() => chain().unsetSuperscript().toggleSubscript().run()}\n >\n <span className={styles.styleItem}>\n <span className={`${styles.styleIcon} ${styles.scriptGlyph}`}>\n x<sub>2</sub>\n </span>\n {t.subscript}\n </span>\n </MenuItem>\n </MenuPopover>\n\n <Divider />\n\n {/* 插入媒体 */}\n <ToolbarButton title={t.link} active={state.link} onClick={toggleLink}>\n <LinkIcon />\n </ToolbarButton>\n {onImageUpload ? (\n <>\n <ToolbarButton title={t.image} onClick={handlePickImage}>\n <ImageIcon />\n </ToolbarButton>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n hidden\n onChange={handleImageChange}\n />\n </>\n ) : null}\n {showImport ? (\n <MenuPopover\n trigger={\n <button\n type=\"button\"\n className={styles.styleTrigger}\n title={importTitle}\n aria-label={importTitle}\n aria-busy={!!importing}\n disabled={!!importing}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.styleTriggerLabel}>\n {t.importDocument}\n </span>\n <ChevronDownIcon\n size={12}\n className={styles.styleTriggerCaret}\n />\n </button>\n }\n >\n {importItems.map((item) => (\n <MenuItem\n key={item.key}\n onSelect={() => pickImport(item.accept)}\n >\n {item.label}\n </MenuItem>\n ))}\n </MenuPopover>\n ) : null}\n <ToolbarButton\n title={t.blockquote}\n active={state.blockquote}\n onClick={() => chain().toggleBlockquote().run()}\n >\n <span className={styles.txtIcon}>❝</span>\n </ToolbarButton>\n\n <Divider />\n\n {/* 列表 */}\n <ToolbarButton\n title={t.bulletList}\n active={state.bulletList}\n onClick={() => chain().toggleBulletList().run()}\n >\n <ListUnorderedIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.orderedList}\n active={state.orderedList}\n onClick={() => chain().toggleOrderedList().run()}\n >\n <ListOrderedIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.taskList}\n active={state.taskList}\n onClick={() => chain().toggleTaskList().run()}\n >\n <ListChecksIcon />\n </ToolbarButton>\n\n <Divider />\n\n {/* More 下拉(代码块、分割线、表格 + 宿主注入项) */}\n <MenuPopover\n trigger={\n <button\n type=\"button\"\n className={styles.styleTrigger}\n title={t.more}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.styleTriggerLabel}>{t.more}</span>\n <ChevronDownIcon size={12} className={styles.styleTriggerCaret} />\n </button>\n }\n >\n <MenuItem onSelect={() => chain().toggleCodeBlock().run()}>\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>{'{ }'}</span>\n {t.codeBlock}\n </span>\n </MenuItem>\n <MenuItem onSelect={() => openInsertMath('inline')}>\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>√x</span>\n {t.inlineMath}\n </span>\n </MenuItem>\n <MenuItem onSelect={() => openInsertMath('block')}>\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>∑</span>\n {t.blockMath}\n </span>\n </MenuItem>\n <MenuItem onSelect={() => chain().setHorizontalRule().run()}>\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>—</span>\n {t.hr}\n </span>\n </MenuItem>\n <TableInsertItem\n disabled={state.inTable}\n labels={t}\n onInsert={(rows, cols) =>\n chain()\n .insertTable({ rows, cols, withHeaderRow: true })\n .run()\n }\n />\n {extraToolbarItems?.map((item) => (\n <MenuItem\n key={item.key}\n disabled={item.disabled}\n onSelect={() => item.onSelect(editor)}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>{item.icon}</span>\n {item.label}\n </span>\n </MenuItem>\n ))}\n </MenuPopover>\n </div>\n </div>\n\n {/* 导入的隐藏文件选择器:accept 由下拉选项写入 */}\n {showImport ? (\n <input\n ref={importInputRef}\n type=\"file\"\n hidden\n onChange={handleImportChange}\n />\n ) : null}\n\n {mathEdit ? (\n <MathEditorPopover\n editor={editor}\n kind={mathEdit.kind}\n mode={mathEdit.mode}\n pos={mathEdit.pos}\n latex={mathEdit.latex}\n isNew={mathEdit.isNew}\n newLabel={\n mathEdit.kind === 'inline' ? t.mathNewInline : t.mathNewBlock\n }\n placeholder={t.mathPlaceholder}\n doneLabel={t.mathDone}\n onConfirm={applyMath}\n onCancel={cancelMath}\n />\n ) : null}\n\n {/* 表格右键菜单:纵向,图标 + 文案,分组分隔 */}\n {tableMenu &&\n createPortal(\n <div\n className={styles.tableBubble}\n style={{ position: 'fixed', left: tableMenu.x, top: tableMenu.y }}\n role=\"menu\"\n onMouseDown={(e) => e.stopPropagation()}\n onContextMenu={(e) => e.preventDefault()}\n >\n <TableMenuItem\n label={\n tableMulti\n ? t.tableAddColumnBeforeN(tableColN)\n : t.tableAddColumnBefore\n }\n onClick={() =>\n runTable(() => addColumnsBefore(editor, tableColN))\n }\n >\n <ColumnBeforeIcon />\n </TableMenuItem>\n <TableMenuItem\n label={\n tableMulti\n ? t.tableAddColumnAfterN(tableColN)\n : t.tableAddColumnAfter\n }\n onClick={() =>\n runTable(() => addColumnsAfter(editor, tableColN))\n }\n >\n <ColumnAfterIcon />\n </TableMenuItem>\n <TableMenuItem\n label={\n tableMulti\n ? t.tableDeleteColumnN(tableColN)\n : t.tableDeleteColumn\n }\n disabled={disableDeleteColumn}\n onClick={() =>\n runTable(() => {\n deleteSelectedColumns(editor);\n })\n }\n >\n <ColumnDeleteIcon />\n </TableMenuItem>\n <TableMenuDivider />\n <TableMenuItem\n label={\n tableMulti\n ? t.tableAddRowBeforeN(tableRowN)\n : t.tableAddRowBefore\n }\n disabled={disableAddRowBefore}\n onClick={() =>\n runTable(() => addRowsBefore(editor, tableRowN))\n }\n >\n <RowBeforeIcon />\n </TableMenuItem>\n <TableMenuItem\n label={\n tableMulti ? t.tableAddRowAfterN(tableRowN) : t.tableAddRowAfter\n }\n onClick={() => runTable(() => addRowsAfter(editor, tableRowN))}\n >\n <RowAfterIcon />\n </TableMenuItem>\n <TableMenuItem\n label={\n tableMulti ? t.tableDeleteRowN(tableRowN) : t.tableDeleteRow\n }\n disabled={disableDeleteRow}\n onClick={() =>\n runTable(() => {\n deleteSelectedRows(editor);\n })\n }\n >\n <RowDeleteIcon />\n </TableMenuItem>\n <TableMenuDivider />\n <TableMenuItem\n label={t.tableDeleteTable}\n onClick={() =>\n runTable(() => {\n editor.commands.deleteTable();\n })\n }\n >\n <TableDeleteIcon />\n </TableMenuItem>\n </div>,\n document.body,\n )}\n </>\n );\n}\n","import { useEffect, useState } from 'react';\n\n/**\n * 是否窄屏(默认 <768px)。取代原项目的 useDevice,内联为纯 matchMedia,\n * 无第三方依赖。SSR 首帧返回 false,挂载后按实际视口更新。\n */\nexport function useIsMobile(breakpoint = 768): boolean {\n const [isMobile, setIsMobile] = useState(false);\n\n useEffect(() => {\n const mq = window.matchMedia(`(max-width: ${breakpoint - 1}px)`);\n const update = () => setIsMobile(mq.matches);\n update();\n mq.addEventListener('change', update);\n return () => mq.removeEventListener('change', update);\n }, [breakpoint]);\n\n return isMobile;\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { useIsMobile } from '../hooks/useIsMobile';\nimport { ChevronDownIcon, ListUnorderedIcon, LockIcon, MenuIcon } from '../icons';\nimport { defaultTocLabels, type TocLabels } from '../labels';\nimport styles from '../styles/tocPanel.module.css';\nimport type { TocItem } from '../toc/extractToc';\n\nexport interface TocPanelProps {\n items: TocItem[];\n /** 当前高亮的锚点 id(阅读页由 IntersectionObserver 算、编辑页由光标章节算)。 */\n activeId?: string;\n /** 点击目录项。锁住项不触发。默认行为由调用方决定(滚动 / 跳转)。 */\n onItemClick?: (item: TocItem) => void;\n labels?: Partial<TocLabels>;\n}\n\n/**\n * 目录面板(阅读页 + 编辑页共用)。\n *\n * - 桌面:左侧粘性栏,可收起(«/»)。\n * - 移动:顶部可折叠「目录」条,选中后自动收起。\n * - 层级用左缩进;active accent 左边框 + 加粗;locked 置灰 + 锁图标不可点。\n *\n * 纯展示:滚动 / active 计算交给调用方,本组件只渲染 + 派发点击。\n */\nexport function TocPanel({ items, activeId, onItemClick, labels }: TocPanelProps) {\n const t = { ...defaultTocLabels, ...labels };\n const isMobile = useIsMobile();\n\n const [collapsed, setCollapsed] = useState(false);\n const [mobileOpen, setMobileOpen] = useState(false);\n\n const desktopNavRef = useRef<HTMLElement>(null);\n const mobilePanelRef = useRef<HTMLDivElement>(null);\n\n // activeId 变化时把当前高亮项滚入 TOC 可视区(仅在不可见时)。\n useEffect(() => {\n if (!activeId) return;\n const reduce = window.matchMedia(\n '(prefers-reduced-motion: reduce)',\n ).matches;\n const container = desktopNavRef.current || mobilePanelRef.current;\n if (!container) return;\n const el = container.querySelector(`a[href=\"#${CSS.escape(activeId)}\"]`);\n if (!el) return;\n el.scrollIntoView({\n block: 'nearest',\n behavior: reduce ? 'auto' : 'smooth',\n });\n }, [activeId]);\n\n if (!items.length) return null;\n\n const minLevel = Math.min(...items.map((i) => i.level));\n\n const handleClick = (item: TocItem) => {\n if (item.locked) return;\n onItemClick?.(item);\n if (isMobile) setMobileOpen(false);\n };\n\n const list = (\n <ul className={styles.list}>\n {items.map((item) => (\n <li key={item.id}>\n <a\n href={item.locked ? undefined : `#${item.id}`}\n className={`${styles.item} ${\n item.id === activeId ? styles.active : ''\n } ${item.locked ? styles.locked : ''}`}\n style={{ paddingLeft: `${(item.level - minLevel) * 12 + 12}px` }}\n aria-current={item.id === activeId ? 'true' : undefined}\n aria-disabled={item.locked ? 'true' : undefined}\n onClick={(e) => {\n e.preventDefault();\n handleClick(item);\n }}\n >\n <span className={styles.itemText}>{item.text}</span>\n {item.locked ? (\n <LockIcon className={styles.lockIcon} aria-hidden />\n ) : null}\n </a>\n </li>\n ))}\n </ul>\n );\n\n // ── 移动端:顶部可折叠条 ──\n if (isMobile) {\n return (\n <nav className={styles.mobile} aria-label={t.title}>\n <button\n type=\"button\"\n className={styles.mobileBar}\n aria-expanded={mobileOpen}\n onClick={() => setMobileOpen((v) => !v)}\n >\n <MenuIcon className={styles.mobileBarIcon} aria-hidden />\n <span>{t.title}</span>\n <span\n className={`${styles.chevron} ${\n mobileOpen ? styles.chevronUp : ''\n }`}\n aria-hidden\n >\n <ChevronDownIcon size={16} />\n </span>\n </button>\n <div\n ref={mobilePanelRef}\n className={`${styles.mobilePanel} ${\n mobileOpen ? styles.mobilePanelOpen : ''\n }`}\n >\n {list}\n </div>\n </nav>\n );\n }\n\n // ── 桌面:左侧粘性栏(可收起)──\n if (collapsed) {\n return (\n <button\n type=\"button\"\n className={styles.collapsedRail}\n aria-label={t.expand}\n title={t.expand}\n onClick={() => setCollapsed(false)}\n >\n <ListUnorderedIcon />\n </button>\n );\n }\n\n return (\n <nav className={styles.desktop} aria-label={t.title} ref={desktopNavRef}>\n <div className={styles.header}>\n <span className={styles.headerTitle}>{t.title}</span>\n <button\n type=\"button\"\n className={styles.collapseBtn}\n aria-label={t.collapse}\n title={t.collapse}\n onClick={() => setCollapsed(true)}\n >\n «\n </button>\n </div>\n {list}\n </nav>\n );\n}\n","'use client';\n\nimport * as Popover from '@radix-ui/react-popover';\nimport type { ReactNode } from 'react';\nimport styles from '../styles/comment.module.css';\n\nexport interface CommentPopoverProps {\n open: boolean;\n onOpenChange?: (open: boolean) => void;\n /** 被点击的 mark 元素(from onCommentClick 的 anchorEl)。 */\n anchorEl: HTMLElement | null;\n children: ReactNode;\n side?: 'top' | 'bottom' | 'left' | 'right';\n align?: 'start' | 'center' | 'end';\n sideOffset?: number;\n}\n\n/**\n * 评论浮层(Radix)。库只负责锚定与外观,内容由宿主通过 children 提供\n * (典型:评论正文 + Resolve/Dismiss/Reopen 操作)。\n * 锚点是点击 mark 的动态元素:渲染一个 fixed 1x1 span 挂在 anchorEl 的\n * getBoundingClientRect 位置,Radix 以它为锚。\n */\nexport function CommentPopover({\n open,\n onOpenChange,\n anchorEl,\n children,\n side = 'top',\n align = 'start',\n sideOffset = 6,\n}: CommentPopoverProps) {\n const rect = open && anchorEl ? anchorEl.getBoundingClientRect() : null;\n return (\n <Popover.Root open={open} onOpenChange={onOpenChange}>\n {rect && (\n <Popover.Anchor asChild>\n <span\n className={styles.popoverAnchor}\n style={{ left: rect.left, top: rect.top }}\n />\n </Popover.Anchor>\n )}\n <Popover.Portal>\n <Popover.Content\n className={styles.popoverContent}\n side={side}\n align={align}\n sideOffset={sideOffset}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n >\n {children}\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n","import type { Editor } from '@tiptap/react';\nimport {\n mapCommentAnchors,\n type CommentAnchorStatus,\n type CommentSegment,\n} from './commentAnchor/commentMapper';\n\n/**\n * 内容锚点 → 当前文档里的区间。\n *\n * 用途:宿主在提交一次「圈选改写」时记下选区的内容锚点(`prefix` / `exact` / `suffix`,\n * `blockHash` 可选),等 AI 改完、推送回来时再用它把那段区间找回来——**不能用位置**,\n * 因为编辑器在这期间可能整体重建过(保存、切卡、SWR 刷新都会重挂),位置活不过重建。\n *\n * 锚点类型直接复用评论锚定那套(`commentMapper`),匹配走同一条 fallback 链:\n * `blockHash` → 前后文 → `exact` → 前缀降级(前 20 字)。**这条链是会降级的**,所以:\n *\n * > 调用方必须自己比对返回的 `text` 是否仍等于提交时那一段。本函数只回答「在哪」,\n * > 不回答「还算不算同一段」——后者决定了是原地回填还是弹冲突。\n */\nexport interface AnchorRange {\n /** doc 坐标 */\n from: number;\n to: number;\n /**\n * 区间当前的纯文本。**按匹配器的口径**给出:`commentMapper` 把区间内的 text 节点\n * 直接拼起来(块之间**没有分隔符**),所以这里也是 `textBetween(from, to)`(不传\n * blockSeparator)。调用方拿它跟「建锚点时用的那段文本」比对——两边必须同一口径,\n * 否则多块区间(表格 / 列表)会永远对不上。\n */\n text: string;\n status: CommentAnchorStatus;\n}\n\n/** 探针 id:借 commentMapper 的匹配链路,但我们只要区间,不要评论语义。 */\nconst PROBE_ID = '__anchor-range-probe__';\n\nexport function findRangeByAnchor(\n editor: Editor,\n anchor: CommentSegment | null | undefined,\n): AnchorRange | null {\n if (!anchor || !anchor.exact) return null;\n\n const [result] = mapCommentAnchors(editor.state.doc, [\n { commentId: PROBE_ID, segments: [anchor] },\n ]);\n const range = result?.ranges[0];\n if (!range) return null;\n\n return {\n from: range.from,\n to: range.to,\n // 无 blockSeparator:与 commentMapper 的 `collectText`(text 节点直接拼接)同一口径\n text: editor.state.doc.textBetween(range.from, range.to),\n status: result.status,\n };\n}\n","import '@tiptap/markdown';\nimport type { JSONContent } from '@tiptap/core';\nimport type { Editor } from '@tiptap/react';\n\n/**\n * 取区间对应的 markdown,并给出它在 `editor.getMarkdown()` 输出里的精确偏移。\n *\n * 为什么需要它:后端改卡走的是「在正文里逐字找到这段,替换」(`replace_in_text` +\n * `count=1`),所以发过去的那段必须是**存库正文的逐字子串**;调用方还要知道它在整篇里\n * 的偏移,才能从存库正文取前后文(`ref`)并界定「这次改了哪一段」。官方 OSS 只有整篇\n * `Editor.getMarkdown()`;官方 Pro 的 `getMarkdownRange` 只返回字符串、不给偏移,也不做\n * 块扩展。\n *\n * **默认扩块**(`expandToBlocks: true`):把区间扩展到与它相交的顶层块的首尾。一是序列化\n * 稳定(半句话里跨着加粗,片段序列化会在断口插入多余的 `**`),二是**只有块对齐时偏移才是\n * 算出来的,而不是猜出来的**。\n *\n * 偏移怎么来的:把 doc 的顶层块逐个序列化、用 `\\n\\n` 拼起来,等于整篇序列化(有测试钉住\n * 这条不变量),于是「前 i 块拼接的长度」就是第 i 块的起点偏移。这条不变量若在某篇文档上\n * 不成立,退回按内容在整篇里定位;定位不到或出现多处就返回 `null`——宁可让调用方知道\n * 拿不到偏移,也不要给一个错的。\n */\nexport interface MarkdownRange {\n /** 区间对应的 markdown 片段(扩块后)。 */\n markdown: string;\n /** 片段在 `editor.getMarkdown()` 输出里的起始偏移。 */\n from: number;\n /** 结束偏移(不含)。恒有 `to - from === markdown.length`。 */\n to: number;\n /**\n * **同一段**在 doc 坐标里的范围(扩块之后)。\n *\n * 宿主需要它把「读」和「写」对齐:`from/to` 是 markdown 偏移,而编辑器里的替换要按\n * doc 坐标做。少了它,宿主只能自己拿原始选区去定位,于是「用来定位的那段」和\n * 「按 markdown 偏移算出来的那段」不是同一段——把 A 段写进 B 区间,内容就会重复。\n */\n docFrom: number;\n docTo: number;\n}\n\nexport interface GetMarkdownForRangeOptions {\n /**\n * 是否把区间扩展到与它相交的顶层块(段落 / 表格 / 列表 / 图表 …)的首尾。\n * 默认 `true`:调用方要「存库正文的逐字子串 + 精确偏移」时应该保持默认。\n * 设 `false` 按原区间取,此时偏移依赖内容定位,可能返回 `null`。\n */\n expandToBlocks?: boolean;\n}\n\n/** 顶层块之间的分隔符——与 MarkdownManager 的 doc 级拼接一致。 */\nconst BLOCK_SEPARATOR = '\\n\\n';\n\ninterface TopLevelBlock {\n json: JSONContent;\n /** doc 坐标 */\n from: number;\n to: number;\n}\n\nfunction topLevelBlocks(editor: Editor): TopLevelBlock[] {\n const blocks: TopLevelBlock[] = [];\n editor.state.doc.forEach((node, offset) => {\n blocks.push({\n json: node.toJSON() as JSONContent,\n from: offset,\n to: offset + node.nodeSize,\n });\n });\n return blocks;\n}\n\nexport function getMarkdownForRange(\n editor: Editor,\n from: number,\n to: number,\n options: GetMarkdownForRangeOptions = {},\n): MarkdownRange | null {\n const manager = editor.markdown;\n if (!manager) return null;\n\n const size = editor.state.doc.content.size;\n let start = Math.max(0, Math.min(from, to));\n let end = Math.min(size, Math.max(from, to));\n if (start >= end) return null;\n\n const blocks = topLevelBlocks(editor);\n if (blocks.length === 0) return null;\n\n const expand = options.expandToBlocks !== false;\n\n // 与 [start, end) 相交的顶层块:第一个末端越过 start 的、到最后一个起点早于 end 的。\n // 单元格内、列表项内的选区都会扩到它们所属的顶层块(表格 / 列表整体)。\n let first = 0;\n let last = blocks.length - 1;\n if (expand) {\n first = blocks.findIndex((b) => b.to > start);\n if (first < 0) return null;\n for (let i = blocks.length - 1; i >= first; i -= 1) {\n if (blocks[i].from < end) {\n last = i;\n break;\n }\n }\n start = blocks[first].from;\n end = blocks[last].to;\n }\n\n const parts = blocks.map((b) => manager.serialize({ type: 'doc', content: [b.json] }));\n const full = editor.getMarkdown();\n\n if (expand && parts.join(BLOCK_SEPARATOR) === full) {\n const markdown = parts.slice(first, last + 1).join(BLOCK_SEPARATOR);\n // 空段落拼出来是空串:语义上等于「这段没内容」,交给调用方去判空不如这里就返回 null\n if (!markdown) return null;\n const at =\n first === 0\n ? 0\n : parts.slice(0, first).join(BLOCK_SEPARATOR).length + BLOCK_SEPARATOR.length;\n return { markdown, from: at, to: at + markdown.length, docFrom: start, docTo: end };\n }\n\n // 非块对齐,或整篇拼接与 getMarkdown() 不一致:只能按内容定位,且必须唯一\n const markdown = manager.serialize(\n editor.state.doc.cut(start, end).toJSON() as JSONContent,\n );\n if (!markdown) return null;\n const at = full.indexOf(markdown);\n if (at < 0 || full.indexOf(markdown, at + 1) >= 0) return null;\n return { markdown, from: at, to: at + markdown.length, docFrom: start, docTo: end };\n}\n","import { MarkdownManager } from '@tiptap/markdown';\nimport { CitationRef } from './CitationRef';\nimport { prepareChartMarkdown } from './chart/prepareChartMarkdown';\nimport { baseExtensions, pureChart, pureCodeBlock, pureImage } from './extensions';\n\n/**\n * 把一段正文规范成「编辑器读进来再吐出去」的那种写法。\n *\n * **为什么需要它**:编辑器加载 markdown 时要先解析成文档结构,而 markdown 里有些东西是\n * 排版装饰、解析时就丢了(表格列宽的空格、注释 JSON 里的空格、数值尾零 …)。所以\n * 「存库正文」和「编辑器序列化结果」常常**逐字不同**——这与用户改没改无关,加载那一刻就\n * 发生了。而后端改卡走的是「在正文里逐字找到这段再替换」,两边写法不一致就会搜不到。\n * 宿主在要动正文之前(例如圈选改写提交前)先用本函数比对/对齐一次即可。\n *\n * **已知会被规范化的结构**(都是排版层面,内容语义不变):\n *\n * | 结构 | 存库可能是 | 规范化后 |\n * |------|-----------|---------|\n * | GFM 表格 | `\\| 收入 \\| 100 \\|` | 按列内容宽度重排对齐(多/少空格) |\n * | 图表注释 JSON | `<!-- {\"chartType\": \"column\"} -->` | `<!-- {\"chartType\":\"column\"} -->`(去空格,键序按解析结果) |\n * | **图表区**的数值 | `132.0` | `132`(图表把表解析成 payload,数值走 number 再写回) |\n * | 纯空白的正文 | `\" \\n \"` | `\"\"` |\n *\n * 注意第三行**只作用于图表区**:普通 GFM 表格走 marked 的表格解析,单元格是文本,\n * `1,234.50` 这种写法会原样保留(有测试钉住)。\n *\n * 反过来,这些**不该**被改动,同样有测试钉住:标题/段落/加粗斜体/列表/引用、代码块、\n * 公式、图片、脚注 `[^n]`、图表仍是「注释 + 表」的作者形态(不会变成 ```tmr-chart 围栏)。\n *\n * 注意它**不使用** `enrichMarkdownCitations`:脚注的 `[^n]` 由 CitationRef 自带的\n * tokenizer 解析,url/title 只存在于节点属性里、不进 markdown,所以规范化不需要 sources。\n */\nexport function normalizeMarkdown(markdown: string): string {\n if (!markdown) return markdown;\n const manager = getManager();\n return manager.serialize(manager.parse(prepareChartMarkdown(markdown)));\n}\n\n// [perf] 与 renderReportHtml 同样的理由:每次 new MarkdownManager 都会让底层 marked 全局\n// 累积 tokenizer,parse 逐次变慢。这里只做「解析 → 序列化」,无状态,模块级复用即可。\nlet sharedManager: MarkdownManager | null = null;\n\nfunction getManager(): MarkdownManager {\n sharedManager ??= new MarkdownManager({\n extensions: [...baseExtensions, pureCodeBlock, pureImage, pureChart, CitationRef],\n });\n return sharedManager;\n}\n","import '@tiptap/markdown';\nimport type { Editor } from '@tiptap/react';\nimport { prepareChartMarkdown } from './chart/prepareChartMarkdown';\nimport { enrichMarkdownCitations, type SourceRef } from './citationUtils';\nimport { splitTopLevelBlocks, stripToPlainText } from './insertMarkdown';\n\nexport interface ReplaceRangeOptions {\n /** 脚注来源:把 `[^n]` enrich 成带 url/title 的 citation-ref(与 `insertMarkdown` 同一套)。 */\n sources?: SourceRef[];\n}\n\n/**\n * 用一段 markdown **替换**一个区间。给「后台回填」用——AI 在别处改完,把结果写回编辑器。\n *\n * 与 `insertMarkdown` 的三处刻意差异(都在注释里点明,改的时候别抹平):\n *\n * 1. **不抢焦点**。`insertMarkdown` 是「用户主动插入」,链式带了 `.focus()`;后台回填时\n * 用户可能正在别处打字,抢焦点等于打断他。所以这里直接调 `insertContentAt`。\n * 2. **按区间替换**,不是往光标处插(`insertContentAt` 收 `{from,to}` 时后者即替换)。\n * 3. **进 undo 历史**。`insertContentAt` 本身是一个 transaction,撤销一步就回去;\n * 与评论锚定的 `addToHistory: false` 相反——正文改动必须能撤。\n *\n * 解析失败(AI 的脏输出过不了 schema:嵌套 bold、块级图进 listItem …)时按块降级,\n * 与 `insertMarkdown` 同一套策略。注意降级路径是**逐块多次 transaction**,撤销要多按几下;\n * 只在整段失败时才走。\n *\n * @returns 是否改动了文档。空 markdown 返回 `false`(不静默删掉用户的内容)。\n */\nexport function replaceRangeWithMarkdown(\n editor: Editor,\n range: { from: number; to: number },\n markdown: string,\n options: ReplaceRangeOptions = {},\n): boolean {\n const prepared = prepareChartMarkdown(\n enrichMarkdownCitations(markdown ?? '', options.sources ?? []),\n );\n if (!prepared.trim()) return false;\n\n let from = Math.max(0, Math.min(range.from, range.to));\n let to = Math.max(range.from, range.to);\n if (from === to) return false;\n\n // ① 整段替换:一个 transaction,撤销一步到位\n if (tryInsertMarkdownAt(editor, from, to, prepared)) return true;\n\n // ② 降级:逐块替换。块插完要往后挪插入点,否则每块都往同一个区间插、只剩最后一块\n for (const block of splitTopLevelBlocks(prepared)) {\n const before = editor.state.doc.content.size;\n const changed =\n tryInsertMarkdownAt(editor, from, to, block) ||\n insertPlainParagraphAt(editor, from, to, stripToPlainText(block));\n if (!changed) continue;\n // 插入内容的 doc 尺寸 = 文档增量 + 被替换掉的宽度\n const inserted = editor.state.doc.content.size - before + (to - from);\n from += inserted;\n to = from;\n }\n return true;\n}\n\n/** 注意:不带 `.focus()`——后台回填不能抢用户的焦点。 */\nfunction tryInsertMarkdownAt(\n editor: Editor,\n from: number,\n to: number,\n markdown: string,\n): boolean {\n try {\n return editor\n .chain()\n .insertContentAt({ from, to }, markdown, { contentType: 'markdown' })\n .run();\n } catch {\n return false;\n }\n}\n\nfunction insertPlainParagraphAt(\n editor: Editor,\n from: number,\n to: number,\n text: string,\n): boolean {\n try {\n return editor\n .chain()\n .insertContentAt(\n { from, to },\n { type: 'paragraph', content: text ? [{ type: 'text', text }] : [] },\n )\n .run();\n } catch {\n return false;\n }\n}\n"],"names":["m","r","e","active","b","counter","toggle","styles","Node","MD_FILE_RE","f","input","setActive","MarkdownWysiwygEditor","a","row","field","bar","Fragment","item","list","markdown","at"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAYO,SAAS,gBAAgB,EAAE,MAAM,aAA4B;AAClE,QAAM,QAAQ,OAAO,KAAK,MAAM,SAAS,EAAE;AAC3C,QAAM,MAAO,KAAK,MAAM,OAAyB;AACjD,QAAM,QAAS,KAAK,MAAM,SAA2B;AACrD,QAAM,iBAAiB,UAAU,QAAQ;AAIzC,QAAM,OACJ;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAU;AAAA,MACV,cAAY;AAAA,MACX,GAAI,MAAM,EAAE,YAAY,IAAA,IAAQ,CAAA;AAAA,MAChC,GAAI,QAAQ,EAAE,cAAc,MAAA,IAAU,CAAA;AAAA,MAEtC,UAAA,CAAC,kBAAkB,MAClB;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAM;AAAA,UACN;AAAA,UACA,QAAO;AAAA,UACP,KAAI;AAAA,UAEH,UAAA;AAAA,QAAA;AAAA,MAAA,IAGH;AAAA,IAAA;AAAA,EAAA;AAKN,QAAM,UAAU,iBACZ,eAAe;AAAA,IACb;AAAA,IACA,OAAO,EAAE,OAAO,KAAK,OAAO,SAAS,KAAA;AAAA,IACrC,YAAY;AAAA,EAAA,CACb,IACD;AAEJ,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,IAAG;AAAA,MACH,qBAAkB;AAAA,MAClB,OAAO,EAAE,SAAS,SAAA;AAAA,MAEjB,UAAA;AAAA,IAAA;AAAA,EAAA;AAGP;AC5CO,SAAS,kBACd,UAA+C,IAC/C;AACA,SAAO,YAAY,OAA+B;AAAA,IAChD,aAAa;;AACX,aAAO;AAAA,QACL,gBAAgB,CAAA;AAAA,QAChB,IAAG,UAAK,WAAL;AAAA,QACH,gBAAgB,QAAQ;AAAA,MAAA;AAAA,IAE5B;AAAA,IACA,cAAc;AACZ,aAAO,sBAAsB,eAAe;AAAA,IAC9C;AAAA,EAAA,CACD,EAAE,UAAU;AAAA,IACX,gBAAgB,QAAQ;AAAA,EAAA,CACzB;AACH;ACHO,MAAM,sBAAsB;AAC5B,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAsB5B,MAAM,yBAAyB,IAAI;AAAA,EACxC;AACF;AAGO,SAAS,wBACd,OACA,UACO;AACP,QAAM,QAAQ,CAAC,aAAiC;AAC9C,UAAM,WAAqB,CAAA;AAC3B,aAAS,QAAQ,CAAC,UAAU;AAC1B,UAAI,MAAM,UAAU,MAAM,MAAM,KAAK,CAACA,OAAMA,GAAE,SAAS,QAAQ,GAAG;AAChE,iBAAS;AAAA,UACP,MAAM,KAAK,MAAM,MAAM,OAAO,CAACA,OAAMA,GAAE,SAAS,QAAQ,CAAC;AAAA,QAAA;AAAA,MAE7D,WAAW,MAAM,QAAQ,OAAO,GAAG;AACjC,iBAAS,KAAK,MAAM,KAAK,MAAM,MAAM,OAAO,CAAC,CAAC;AAAA,MAChD,OAAO;AACL,iBAAS,KAAK,KAAK;AAAA,MACrB;AAAA,IACF,CAAC;AACD,WAAO,SAAS,UAAU,QAAQ;AAAA,EACpC;AACA,SAAO,IAAI,MAAM,MAAM,MAAM,OAAO,GAAG,MAAM,WAAW,MAAM,OAAO;AACvE;AAEA,SAAS,qBAAqB,OAAc,UAA6B;AACvE,MAAI,QAAQ;AACZ,QAAM,QAAQ,YAAY,CAAC,SAAS;AAClC,QAAI,KAAK,UAAU,KAAK,MAAM,KAAK,CAACA,OAAMA,GAAE,SAAS,QAAQ,GAAG;AAC9D,cAAQ;AACR,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,CAAC;AACD,SAAO;AACT;AAGA,SAAS,YAAY,KAAoD;AACvE,QAAM,SAAgD,CAAA;AACtD,MAAI,QAAQ,CAAC,OAAO,WAAW;AAC7B,WAAO,KAAK,EAAE,OAAO,QAAQ,KAAK,SAAS,MAAM,UAAU;AAAA,EAC7D,CAAC;AACD,SAAO;AACT;AAGA,SAAS,qBACP,KACkD;AAClD,QAAM,2BAAW,IAAA;AACjB,MAAI,YAAY,CAAC,MAAM,QAAQ;AAC7B,QAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,eAAWA,MAAK,KAAK,OAAO;AAC1B,UAAIA,GAAE,KAAK,SAAS,gBAAiB;AACrC,YAAM,MAAOA,GAAE,MAAM,cAA2B,CAAA;AAChD,iBAAW,MAAM,KAAK;AACpB,cAAM,MAAM,KAAK,IAAI,EAAE,KAAK,CAAA;AAC5B,YAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,KAAK,UAAU;AAC/C,aAAK,IAAI,IAAI,GAAG;AAAA,MAClB;AAAA,IACF;AACA,WAAO;AAAA,EACT,CAAC;AACD,SAAO;AACT;AAEA,SAAS,qBACP,QACA,OACA,KACS;AACT,SAAO,OAAO,KAAK,CAACC,OAAMA,GAAE,OAAO,OAAOA,GAAE,KAAK,KAAK;AACxD;AAEA,SAAS,UACP,YACA,MACA,UACa;AACb,QAAM,KAAK,SAAS,cAAc,MAAM;AACxC,KAAG,YAAY;AACf,KAAG,aAAa,oBAAoB,WAAW,KAAK,GAAG,CAAC;AACxD,KAAG,cAAc,OAAO,WAAW,MAAM;AACzC,KAAG,QAAQ,GAAG,WAAW,MAAM;AAE/B,KAAG,iBAAiB,aAAa,CAACC,OAAM;AACtC,IAAAA,GAAE,eAAA;AACF,IAAAA,GAAE,gBAAA;AAAA,EACJ,CAAC;AACD,KAAG,iBAAiB,SAAS,CAACA,OAAM;AAClC,IAAAA,GAAE,eAAA;AACF,IAAAA,GAAE,gBAAA;AACF,SAAK;AAAA,MACH,KAAK,MAAM,GACR,QAAQ,qBAAqB,WAAW,CAAC,KAAK,IAAI,EAClD,QAAQ,qBAAqB;AAAA,QAC5B;AAAA,QACA,KAAK;AAAA,MAAA,CACyB;AAAA,IAAA;AAAA,EAEtC,CAAC;AACD,SAAO;AACT;AAEO,SAAS,oBACd,UAAsC,IACJ;AAClC,QAAM,aAAa,QAAQ,eAAe;AAC1C,QAAM,cAAc,QAAQ,gBAAgB;AAE5C,SAAO,IAAI,OAAiC;AAAA,IAC1C,KAAK;AAAA,IACL,OAAO;AAAA,MACL,MAAM,OAAO,EAAE,iBAAiB;MAChC,OAAO,CAAC,IAAI,UAAU;AACpB,cAAMC,UAAS,GAAG,QAAQ,mBAAmB;AAC7C,eAAOA,YAAW,SACd,EAAE,iBAAiBA,YACnB;AAAA,MACN;AAAA,IAAA;AAAA,IAEF,OAAO;AAAA,MACL,YAAY,OAAoB;;AAC9B,cAAM,OAAO,qBAAqB,MAAM,GAAG;AAC3C,YAAI,KAAK,SAAS,EAAG,QAAO,cAAc;AAE1C,cAAM,QAAsB,CAAA;AAC5B,cAAM,SAAS,YAAY,MAAM,GAAG;AAEpC,YAAI,YAAY;AACd,qBAAWC,MAAK,QAAQ;AACtB,kBAAM,aAAuB,CAAA;AAC7B,uBAAW,CAAC,IAAI,MAAM,KAAK,MAAM;AAC/B,kBAAI,qBAAqB,QAAQA,GAAE,OAAOA,GAAE,GAAG,GAAG;AAChD,2BAAW,KAAK,EAAE;AAAA,cACpB;AAAA,YACF;AACA,gBAAI,WAAW,SAAS,GAAG;AACzB,oBAAM;AAAA,gBACJ,WAAW;AAAA,kBACTA,GAAE;AAAA,kBACF,CAAC,SAAS,UAAU,YAAY,MAAMA,GAAE,KAAK;AAAA,kBAC7C,EAAE,MAAM,IAAI,KAAK,cAAcA,GAAE,KAAK,GAAA;AAAA,gBAAG;AAAA,cAC3C;AAAA,YAEJ;AAAA,UACF;AAAA,QACF;AAEA,cAAM,aACJ,4BAAuB,SAAS,KAAK,MAArC,mBAAwC,oBAAmB;AAC7D,YAAI,UAAU;AACZ,gBAAM,SAAS,KAAK,IAAI,QAAQ,KAAK,CAAA;AACrC,qBAAWH,MAAK,QAAQ;AACtB,kBAAM;AAAA,cACJ,WAAW,OAAOA,GAAE,MAAMA,GAAE,IAAI,EAAE,OAAO,qBAAA,CAAsB;AAAA,YAAA;AAAA,UAEnE;AACA,qBAAWG,MAAK,QAAQ;AACtB,gBAAI,qBAAqB,QAAQA,GAAE,OAAOA,GAAE,GAAG,GAAG;AAChD,oBAAM;AAAA,gBACJ,WAAW,KAAKA,GAAE,OAAOA,GAAE,KAAK;AAAA,kBAC9B,OAAO;AAAA,gBAAA,CACR;AAAA,cAAA;AAAA,YAEL;AAAA,UACF;AAAA,QACF;AAEA,eAAO,cAAc,OAAO,MAAM,KAAK,KAAK;AAAA,MAC9C;AAAA,MAEA,YAAY,MAAkB,KAAa,OAAmB;;AAE5D,YAAI,CAAC,YAAa,QAAO;AACzB,cAAM,SAAS,MAAM;AACrB,cAAM,MAAK,sCAAQ,YAAR;AAAA;AAAA,UACT;AAAA;AAEF,YAAI,CAAC,GAAI,QAAO;AAChB,cAAM,cAAc,GAAG,aAAa,kBAAkB,KAAK,IACxD,MAAM,GAAG,EACT,OAAO,OAAO;AACjB,YAAI,WAAW,WAAW,EAAG,QAAO;AACpC,aAAK;AAAA,UACH,KAAK,MAAM,GACR,QAAQ,qBAAqB,WAAW,CAAC,KAAK,IAAI,EAClD,QAAQ,oBAAoB;AAAA,YAC3B;AAAA,YACA,UAAU;AAAA,YACV;AAAA,UAAA,CAC6B;AAAA,QAAA;AAEnC,eAAO;AAAA,MACT;AAAA;AAAA;AAAA,MAIA,gBAAgB,OAAc,MAAkB;AAC9C,cAAM,WAAW,KAAK,MAAM,OAAO,MAAM;AACzC,YAAI,CAAC,YAAY,CAAC,qBAAqB,OAAO,QAAQ,EAAG,QAAO;AAChE,eAAO,wBAAwB,OAAO,QAAQ;AAAA,MAChD;AAAA,IAAA;AAAA,EACF,CACD;AACH;AAMO,SAAS,uBACd,UAAsC,IACtC;AACA,SAAO,UAAU,OAAO;AAAA,IACtB,MAAM;AAAA,IACN,wBAAwB;AACtB,aAAO,CAAC,oBAAoB,OAAO,CAAC;AAAA,IACtC;AAAA,EAAA,CACD;AACH;AC9PO,SAAS,4BACd,QACA,UACM;AAEN,MAAI,CAAC,OAAO,WAAY;AACxB,QAAM,YACJ,SAAS,SAAS,IACd;AAAA,IACE;AAAA,MACE,OAAO,MAAM;AAAA,MACb,SAAS,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,WAAW,UAAU,EAAE,WAAW;AAAA,IAAA,EACtE,IAAI,CAACH,QAAO,EAAE,WAAWA,GAAE,WAAW,QAAQA,GAAE,SAAS;AAAA,EAAA,IAE7D,CAAA;AACN,QAAM,QAAQ,OAAO,MAAA,EAAQ,oBAAA;AAC7B,MAAI,UAAU,SAAS,EAAG,OAAM,oBAAoB,SAAS;AAC7D,QAAM,IAAA;AACR;AAGO,SAAS,kBAAkB,QAA0B;AAC1D,QAAM,MAAgB,CAAA;AACtB,SAAO,MAAM,IAAI,YAAY,CAAC,SAAS;AACrC,QAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,eAAWD,MAAK,KAAK,OAAO;AAC1B,UAAIA,GAAE,KAAK,SAAS,gBAAiB;AACrC,iBAAW,MAAOA,GAAE,MAAM,cAA2B,CAAA,GAAI;AACvD,YAAI,CAAC,IAAI,SAAS,EAAE,EAAG,KAAI,KAAK,EAAE;AAAA,MACpC;AAAA,IACF;AACA,WAAO;AAAA,EACT,CAAC;AACD,SAAO;AACT;AAEO,SAAS,kBACd,QACA,WACgB;AAChB,QAAM,SAAyB,CAAA;AAC/B,SAAO,MAAM,IAAI,YAAY,CAAC,MAAM,QAAQ;AAC1C,QAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,eAAWA,MAAK,KAAK,OAAO;AAC1B,UAAIA,GAAE,KAAK,SAAS,gBAAiB;AACrC,YAAM,MAAOA,GAAE,MAAM,cAA2B,CAAA;AAChD,UAAI,IAAI,SAAS,SAAS,GAAG;AAC3B,eAAO,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,KAAK,UAAU;AAAA,MACpD;AAAA,IACF;AACA,WAAO;AAAA,EACT,CAAC;AACD,SAAO;AACT;AAEA,SAAS,UAAU,QAAgB,WAAgC;AACjE,SAAO,KAAK;AAAA,IACV,OAAO,MAAM,GAAG,QAAQ,qBAAqB,SAAS;AAAA,EAAA;AAE1D;AAEA,SAAS,UAAU,QAA+B;;AAChD,WAAO,4BAAuB,SAAS,OAAO,KAAK,MAA5C,mBAA+C,oBAAmB;AAC3E;AAMO,SAAS,aAAa,QAAgB,WAA4B;;AACvE,QAAM,SAAS,kBAAkB,QAAQ,SAAS;AAClD,MAAI,OAAO,WAAW,GAAG;AACvB,cAAU,QAAQ,IAAI;AACtB,WAAO;AAAA,EACT;AACA,YAAU,QAAQ,SAAS;AAC3B,QAAM,SAAS,OAAO,KAAK,IAAI;AAAA,IAC7B,uCAAuC,IAAI,OAAO,SAAS,CAAC;AAAA,EAAA;AAE9D,yCAAQ,mBAAR,gCAAyB,EAAE,OAAO,UAAU,UAAU;AACtD,SAAO,MAAA,EAAQ,iBAAiB,OAAO,CAAC,EAAE,IAAI,EAAE,IAAA;AAChD,SAAO;AACT;AAGO,SAAS,YACd,QACA,MAAuB,QACR;AACf,QAAM,MAAM,kBAAkB,MAAM;AACpC,MAAI,IAAI,WAAW,EAAG,QAAO;AAC7B,QAAMG,UAAS,UAAU,MAAM;AAC/B,QAAM,UAAUA,UAAS,IAAI,QAAQA,OAAM,IAAI;AAC/C,QAAM,UACJ,QAAQ,UACH,UAAU,KAAK,IAAI,UACnB,UAAU,IAAI,IAAI,UAAU,IAAI;AACvC,QAAM,SAAS,IAAI,OAAO;AAC1B,eAAa,QAAQ,MAAM;AAC3B,SAAO;AACT;AC3GO,MAAM,mBAAmB;AAEhC,MAAM,cAAc;AAgBb,SAAS,eAAe,KAAuB;AACpD,MAAI;AACF,QAAA;AAAA,EACF,SAAS,OAAO;AACd,QAAI,iBAAiB,cAAc,YAAY,KAAK,MAAM,OAAO,GAAG;AAClE,UAAA;AACA;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;AC7BA,SAAS,IAAI,EAAE,OAAO,OAAO,UAAU,GAAG,QAAmD;AAC3F,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAa;AAAA,MACb,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MACZ,WAAU;AAAA,MACT,GAAG;AAAA,MAEH;AAAA,IAAA;AAAA,EAAA;AAGP;AAEO,MAAM,WAAW,CAAC,MACvB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,wCAAA,CAAwC;AAAA,EAChD,oBAAC,QAAA,EAAK,GAAE,yCAAA,CAAyC;AAAA,EAAA,CACnD;AAGK,MAAM,aAAa,CAAC,MACzB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,IAAA,CAAI;AAAA,EACpC,oBAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EACrC,oBAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,KAAA,CAAK;AAAA,EAAA,CACtC;AAGK,MAAM,gBAAgB,CAAC,MAC5B,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,0BAAA,CAA0B;AAAA,EAClC,oBAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EAAA,CACvC;AAGK,MAAM,oBAAoB,CAAC,MAChC,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,2BAAA,CAA2B;AAAA,EACnC,oBAAC,QAAA,EAAK,GAAE,yBAAA,CAAyB;AAAA,EACjC,oBAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EAAA,CACvC;AAGK,MAAM,WAAW,CAAC,MACvB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,YAAA,EAAS,QAAO,mBAAA,CAAmB;AAAA,EACpC,oBAAC,YAAA,EAAS,QAAO,gBAAA,CAAgB;AAAA,EAAA,CACnC;AAGK,MAAM,WAAW,CAAC,MACvB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,8DAAA,CAA8D;AAAA,EACtE,oBAAC,QAAA,EAAK,GAAE,+DAAA,CAA+D;AAAA,EAAA,CACzE;AAGK,MAAM,YAAY,CAAC,MACxB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,OAAM,MAAK,QAAO,MAAK,GAAE,KAAI,GAAE,KAAI,IAAG,KAAI,IAAG,KAAI;AAAA,sBACtD,UAAA,EAAO,IAAG,KAAI,IAAG,KAAI,GAAE,KAAI;AAAA,EAC5B,oBAAC,QAAA,EAAK,GAAE,4CAAA,CAA4C;AAAA,EAAA,CACtD;AAGK,MAAM,aAAa,CAAC,MACzB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EACnB,oBAAC,QAAA,EAAK,GAAE,gBAAA,CAAgB;AAAA,EACxB,oBAAC,QAAA,EAAK,GAAE,4EAAA,CAA4E;AAAA,EAAA,CACtF;AAGK,MAAM,oBAAoB,CAAC,MAChC,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,IAAG,KAAI,IAAG,MAAK,IAAG,KAAI,IAAG,IAAA,CAAI;AAAA,EACnC,oBAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EACrC,oBAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EACrC,oBAAC,UAAK,IAAG,KAAI,IAAG,QAAO,IAAG,KAAI,IAAG,IAAA,CAAI;AAAA,EACrC,oBAAC,UAAK,IAAG,KAAI,IAAG,QAAO,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EACvC,oBAAC,UAAK,IAAG,KAAI,IAAG,QAAO,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EAAA,CACzC;AAGK,MAAM,kBAAkB,CAAC,MAC9B,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,IAAA,CAAI;AAAA,EACpC,oBAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EACtC,oBAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EACtC,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EACnB,oBAAC,QAAA,EAAK,GAAE,UAAA,CAAU;AAAA,EAClB,oBAAC,QAAA,EAAK,GAAE,iCAAA,CAAiC;AAAA,EAAA,CAC3C;AAGK,MAAM,iBAAiB,CAAC,MAC7B,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,gBAAA,CAAgB;AAAA,EACxB,oBAAC,QAAA,EAAK,GAAE,eAAA,CAAe;AAAA,EACvB,oBAAC,QAAA,EAAK,GAAE,UAAA,CAAU;AAAA,EAClB,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EACnB,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EAAA,CACrB;AAGK,MAAM,WAAW,CAAC,MACvB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,gBAAA,CAAgB;AAAA,EACxB,oBAAC,QAAA,EAAK,GAAE,2DAAA,CAA2D;AAAA,EAAA,CACrE;AAGK,MAAM,WAAW,CAAC,MACvB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,iBAAA,CAAiB;AAAA,EACzB,oBAAC,QAAA,EAAK,GAAE,yDAAA,CAAyD;AAAA,EAAA,CACnE;AAGK,MAAM,kBAAkB,CAAC,MAC9B,oBAAC,KAAA,EAAK,GAAG,GACP,UAAA,oBAAC,QAAA,EAAK,GAAE,eAAA,CAAe,EAAA,CACzB;AAGK,MAAM,YAAY,CAAC,MACxB,oBAAC,KAAA,EAAK,GAAG,GACP,UAAA,oBAAC,QAAA,EAAK,GAAE,kBAAA,CAAkB,EAAA,CAC5B;AAGK,MAAM,YAAY,CAAC,MACxB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,UAAA,CAAU;AAAA,EAClB,oBAAC,QAAA,EAAK,GAAE,2CAAA,CAA2C;AAAA,EACnD,oBAAC,QAAA,EAAK,GAAE,yCAAA,CAAyC;AAAA,EACjD,oBAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EACtC,oBAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EAAA,CACxC;AAGK,MAAM,WAAW,CAAC,MACvB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,OAAM,MAAK,QAAO,MAAK,GAAE,KAAI,GAAE,MAAK,IAAG,KAAI,IAAG,KAAI;AAAA,EACxD,oBAAC,QAAA,EAAK,GAAE,2BAAA,CAA2B;AAAA,EAAA,CACrC;AAGK,MAAM,WAAW,CAAC,MACvB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EACrC,oBAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,KAAI,IAAG,IAAA,CAAI;AAAA,EACnC,oBAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,KAAA,CAAK;AAAA,EAAA,CACvC;AAGK,MAAM,aAAa,CAAC,MACzB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,EAC9B,oBAAC,QAAA,EAAK,GAAE,iBAAA,CAAiB;AAAA,EAAA,CAC3B;AAGK,MAAM,QAAQ,CAAC,MACpB,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,aAAA,CAAa;AAAA,EACrB,oBAAC,QAAA,EAAK,GAAE,aAAA,CAAa;AAAA,EAAA,CACvB;AAGK,MAAM,gBAAgB,CAAC,MAC5B,oBAAC,KAAA,EAAK,GAAG,GACP,UAAA,oBAAC,QAAA,EAAK,GAAE,iBAAA,CAAiB,EAAA,CAC3B;AAKK,MAAM,mBAAmB,CAAC,MAC/B,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,MAAK,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,IAAA,CAAI;AAAA,EACjD,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EACnB,oBAAC,QAAA,EAAK,GAAE,SAAA,CAAS;AAAA,EACjB,oBAAC,QAAA,EAAK,GAAE,UAAA,CAAU;AAAA,EAAA,CACpB;AAGK,MAAM,kBAAkB,CAAC,MAC9B,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,IAAA,CAAI;AAAA,EAChD,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EACnB,oBAAC,QAAA,EAAK,GAAE,UAAA,CAAU;AAAA,EAClB,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EAAA,CACrB;AAGK,MAAM,mBAAmB,CAAC,MAC/B,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,IAAA,CAAI;AAAA,EAChD,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EACnB,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EACnB,oBAAC,QAAA,EAAK,GAAE,YAAA,CAAY;AAAA,EAAA,CACtB;AAGK,MAAM,gBAAgB,CAAC,MAC5B,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,KAAI,GAAE,MAAK,OAAM,MAAK,QAAO,MAAK,IAAG,IAAA,CAAI;AAAA,EACjD,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EACnB,oBAAC,QAAA,EAAK,GAAE,SAAA,CAAS;AAAA,EACjB,oBAAC,QAAA,EAAK,GAAE,UAAA,CAAU;AAAA,EAAA,CACpB;AAGK,MAAM,eAAe,CAAC,MAC3B,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,IAAA,CAAI;AAAA,EAChD,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EACnB,oBAAC,QAAA,EAAK,GAAE,UAAA,CAAU;AAAA,EAClB,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EAAA,CACrB;AAGK,MAAM,gBAAgB,CAAC,MAC5B,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,IAAA,CAAI;AAAA,EAChD,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EACnB,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EACnB,oBAAC,QAAA,EAAK,GAAE,YAAA,CAAY;AAAA,EAAA,CACtB;AAGK,MAAM,kBAAkB,CAAC,MAC9B,qBAAC,KAAA,EAAK,GAAG,GACP,UAAA;AAAA,EAAA,oBAAC,QAAA,EAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,IAAA,CAAI;AAAA,EAChD,oBAAC,QAAA,EAAK,GAAE,UAAA,CAAU;AAAA,EAClB,oBAAC,QAAA,EAAK,GAAE,UAAA,CAAU;AAAA,EAClB,oBAAC,QAAA,EAAK,GAAE,WAAA,CAAW;AAAA,EACnB,oBAAC,QAAA,EAAK,GAAE,aAAA,CAAa;AAAA,EAAA,CACvB;ACnKK,MAAM,qBAAkC;AAAA,EAC7C,UAAU,CAAC,WAAW,UAAU,GAAG,SAAS,IAAI,QAAQ,CAAC;AAAA,EACzD,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,WAAW;AACb;AAEO,MAAM,uBAAsC;AAAA,EACjD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,cAAc,CAAC,UAAU,WAAW,KAAK;AAAA,EACzC,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,WAAW;AAAA,EACX,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,aAAa;AAAA,EACb,WAAW;AAAA,EACX,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,mBAAmB;AAAA,EACnB,sBAAsB;AAAA,EACtB,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,yBAAyB,CAAC,YAAY,aAAa,OAAO;AAAA,EAC1D,0BAA0B;AAAA,EAC1B,sBAAsB;AAAA,EACtB,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM;AAAA,EACN,WAAW;AAAA,EACX,IAAI;AAAA,EACJ,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,mBAAmB,CAAC,MAAM,SAAS,GAAG,IAAI,MAAM,IAAI;AAAA,EACpD,sBAAsB;AAAA,EACtB,qBAAqB;AAAA,EACrB,mBAAmB;AAAA,EACnB,mBAAmB;AAAA,EACnB,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,uBAAuB,CAAC,MAAM,OAAO,CAAC;AAAA,EACtC,sBAAsB,CAAC,MAAM,OAAO,CAAC;AAAA,EACrC,oBAAoB,CAAC,MAAM,UAAU,CAAC;AAAA,EACtC,oBAAoB,CAAC,MAAM,OAAO,CAAC;AAAA,EACnC,mBAAmB,CAAC,MAAM,OAAO,CAAC;AAAA,EAClC,iBAAiB,CAAC,MAAM,UAAU,CAAC;AAAA,EACnC,kBAAkB;AAAA,EAClB,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,cAAc;AAChB;AAOO,MAAM,4BAAgD;AAAA,EAC3D,MAAM;AAAA,EACN,OAAO;AACT;AAQO,MAAM,mBAA8B;AAAA,EACzC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,UAAU;AACZ;AAOO,MAAM,yBAA0C;AAAA,EACrD,YAAY;AAAA,EACZ,QAAQ;AACV;AAYO,MAAM,uBAAsC;AAAA,EACjD,MAAM;AAAA,EACN,UAAU;AAAA,EACV,WAAW;AAAA,EACX,UAAU;AAAA,EACV,WAAW;AAAA,EACX,SAAS;AAAA,EACT,aAAa;AACf;AAuBO,MAAM,oBAAgC;AAAA,EAC3C,MAAM;AAAA,EACN,SAAS;AAAA,EACT,MAAM;AAAA,EACN,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,eAAe;AAAA,EACf,WAAW;AAAA,EACX,UAAU;AAAA,EACV,SAAS,CAAC,SAAS,UAAU,GAAG,OAAO,MAAM,KAAK;AAAA,EAClD,cAAc;AAAA,EACd,UAAU;AACZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvNO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,QAAM,IAAgB,EAAE,GAAG,mBAAmB,GAAG,OAAA;AACjD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,EAAE;AACnC,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,EAAE;AAEjD,QAAM,QAAQ,eAAe;AAAA,IAC3B;AAAA,IACA,UAAU,CAAC,EAAE,QAAQ,eAAe;AAClC,YAAM,SAAS,wBAAwB,SAAS,SAAS,KAAK;AAC9D,aAAO;AAAA,QACL,eAAc,iCAAQ,iBAAgB;AAAA,QACtC,QAAO,iCAAQ,QAAQ,WAAU;AAAA,QACjC,gBAAe,iCAAQ,kBAAiB;AAAA,QACxC,YAAW,iCAAQ,cAAa;AAAA,QAChC,WAAU,iCAAQ,aAAY;AAAA,MAAA;AAAA,IAElC;AAAA,EAAA,CACD;AAID,QAAM,iBAAiB,OAAsB,IAAI;AACjD,QAAM,WAAW;AAAA,IACf,CAAC,UAAkB;AACjB,qBAAe,UAAU;AACzB,qBAAe,MAAM,OAAO,SAAS,cAAc,KAAK,CAAC;AAAA,IAC3D;AAAA,IACA,CAAC,MAAM;AAAA,EAAA;AAET,QAAM,YAAY,YAAY,MAAM;AAClC,QAAI,eAAe,YAAY,KAAM,UAAS,IAAI;AAAA,EACpD,GAAG,CAAC,UAAU,IAAI,CAAC;AAEnB,YAAU,MAAM;AACd,QAAI,eAAe,YAAY,KAAM;AACrC,UAAM,QAAQ,WAAW,MAAM,SAAS,IAAI,GAAG,gBAAgB;AAC/D,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG,CAAC,MAAM,QAAQ,CAAC;AAEnB,YAAU,MAAM;AACd,mBAAe,MAAM,OAAO,SAAS,eAAe,WAAW,CAAC;AAAA,EAClE,GAAG,CAAC,QAAQ,WAAW,CAAC;AAGxB,YAAU,MAAM;AACd,WAAO,MAAM;AACX,UAAI,CAAC,OAAO,YAAa,QAAO,SAAS,YAAA;AAAA,IAC3C;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAGX,QAAM,YAAY;AAAA,IAChB,CAAC,WAAuB;AACtB,gBAAA;AACA,qBAAe,MAAM;AAAA,IACvB;AAAA,IACA,CAAC,SAAS;AAAA,EAAA;AAKZ,QAAM,iBAAiB;AAAA,IACrB,MACE,SAAS,MACT,MAAM,YACN,kBAAkB,MAAM;AAAA,MACtB,eAAe,MAAM;AAAA,MACrB,UAAU;AAAA,MACV,WAAW;AAAA,IAAA,CACZ,MAAM;AAAA,IACT,CAAC,MAAM,MAAM,UAAU,MAAM,aAAa;AAAA,EAAA;AAG5C,QAAME,WAAU,EAAE;AAAA,IAChB,MAAM,UAAU,IAAI,KAAK,MAAM,gBAAgB,KAAK;AAAA,IACpD,MAAM;AAAA,EAAA;AAGR,QAAM,YAAY,CAACH,OAAuBA,GAAE,eAAA;AAE5C,QAAM,gBAAgB,CAACA,OAA4C;AACjE,QAAIA,GAAE,QAAQ,SAAS;AACrB,MAAAA,GAAE,eAAA;AACF,gBAAU,MAAM;AACd,YAAIA,GAAE,SAAU,QAAO,SAAS,mBAAA;AAAA,YAC3B,QAAO,SAAS,eAAA;AAAA,MACvB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,mBAAmB,CAACA,OAA4C;AACpE,QAAIA,GAAE,QAAQ,SAAS;AACrB,MAAAA,GAAE,eAAA;AACF,gBAAU,MAAM,OAAO,SAAS,QAAA,CAAS;AAAA,IAC3C;AAAA,EACF;AAEA,QAAMI,UAAS,CACb,KACA,UACG;AACH,mBAAe,MAAM;AACnB,UAAI,QAAQ,gBAAiB,QAAO,SAAS,iBAAiB,KAAK;AAAA,eAC1D,QAAQ,YAAa,QAAO,SAAS,aAAa,KAAK;AAAA,UAC3D,QAAO,SAAS,YAAY,KAAK;AAAA,IACxC,CAAC;AAAA,EACH;AAEA,QAAM,cAAc,CAAC,OACnB,GAAGC,SAAO,GAAG,IAAIA,SAAO,MAAM,GAAG,KAAK,IAAIA,SAAO,QAAQ,KAAK,EAAE;AAElE,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,YAAY,GAAGA,SAAO,GAAG,IAAI,SAAS,KAAKA,SAAO;AAAA,MAC7D,MAAK;AAAA,MACL,cAAY,EAAE;AAAA,MACd,WAAW,CAACL,OAAM;AAChB,YAAIA,GAAE,QAAQ,UAAU;AACtB,UAAAA,GAAE,eAAA;AACF,kBAAA;AAAA,QACF;AAAA,MACF;AAAA,MAEA,UAAA;AAAA,QAAA,qBAAC,OAAA,EAAI,WAAWK,SAAO,KACrB,UAAA;AAAA,UAAA,qBAAC,QAAA,EAAK,WAAWA,SAAO,OACtB,UAAA;AAAA,YAAA,oBAAC,YAAA,EAAW,MAAM,IAAI,WAAWA,SAAO,WAAW;AAAA,YACnD;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,KAAK;AAAA,gBACL,WAAWA,SAAO;AAAA,gBAClB,OAAO;AAAA,gBACP,UAAU,CAACL,OAAM,QAAQA,GAAE,OAAO,KAAK;AAAA,gBACvC,WAAW;AAAA,gBACX,aAAa,EAAE;AAAA,gBACf,cAAY,EAAE;AAAA,gBACd,WAAS;AAAA,gBACT,YAAY;AAAA,cAAA;AAAA,YAAA;AAAA,UACd,GACF;AAAA,UACA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAW,GAAGK,SAAO,OAAO,GAAG,iBAAiB,IAAIA,SAAO,cAAc,KAAK,EAAE;AAAA,cAChF,aAAU;AAAA,cACV,OAAO,iBAAiB,EAAE,eAAe;AAAA,cAExC,UAAA,iBAAiB,EAAE,eAAeF;AAAA,YAAA;AAAA,UAAA;AAAA,UAErC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAWE,SAAO;AAAA,cAClB,OAAO,EAAE;AAAA,cACT,cAAY,EAAE;AAAA,cACd,UAAU,MAAM,UAAU;AAAA,cAC1B,aAAa;AAAA,cACb,SAAS,MAAM,UAAU,MAAM,OAAO,SAAS,oBAAoB;AAAA,cAEnE,UAAA,oBAAC,eAAA,EAAc,MAAM,GAAA,CAAI;AAAA,YAAA;AAAA,UAAA;AAAA,UAE3B;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAWA,SAAO;AAAA,cAClB,OAAO,EAAE;AAAA,cACT,cAAY,EAAE;AAAA,cACd,UAAU,MAAM,UAAU;AAAA,cAC1B,aAAa;AAAA,cACb,SAAS,MAAM,UAAU,MAAM,OAAO,SAAS,gBAAgB;AAAA,cAE/D,UAAA,oBAAC,iBAAA,EAAgB,MAAM,GAAA,CAAI;AAAA,YAAA;AAAA,UAAA;AAAA,UAE7B;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAWA,SAAO;AAAA,cAClB,OAAO,EAAE;AAAA,cACT,cAAY,EAAE;AAAA,cACd,SAAS;AAAA,cAET,UAAA,oBAAC,OAAA,EAAM,MAAM,GAAA,CAAI;AAAA,YAAA;AAAA,UAAA;AAAA,QACnB,GACF;AAAA,QAEC,OAAO,aACN,qBAAC,OAAA,EAAI,WAAWA,SAAO,KACrB,UAAA;AAAA,UAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,OACtB,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAWA,SAAO;AAAA,cAClB,OAAO;AAAA,cACP,UAAU,CAACL,OAAM,eAAeA,GAAE,OAAO,KAAK;AAAA,cAC9C,WAAW;AAAA,cACX,aAAa,EAAE;AAAA,cACf,cAAY,EAAE;AAAA,cACd,YAAY;AAAA,YAAA;AAAA,UAAA,GAEhB;AAAA,UACA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAW,YAAY,MAAM,aAAa;AAAA,cAC1C,OAAO,EAAE;AAAA,cACT,cAAY,EAAE;AAAA,cACd,gBAAc,MAAM;AAAA,cACpB,aAAa;AAAA,cACb,SAAS,MAAMI,QAAO,iBAAiB,CAAC,MAAM,aAAa;AAAA,cAC5D,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAGD;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAW,YAAY,MAAM,SAAS;AAAA,cACtC,OAAO,EAAE;AAAA,cACT,cAAY,EAAE;AAAA,cACd,gBAAc,MAAM;AAAA,cACpB,aAAa;AAAA,cACb,SAAS,MAAMA,QAAO,aAAa,CAAC,MAAM,SAAS;AAAA,cACpD,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAGD;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAW,YAAY,MAAM,QAAQ;AAAA,cACrC,OAAO,EAAE;AAAA,cACT,cAAY,EAAE;AAAA,cACd,gBAAc,MAAM;AAAA,cACpB,aAAa;AAAA,cACb,SAAS,MAAMA,QAAO,YAAY,CAAC,MAAM,QAAQ;AAAA,cAClD,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAGD,oBAAC,QAAA,EAAK,WAAWC,SAAO,OAAA,CAAQ;AAAA,UAChC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAW,GAAGA,SAAO,GAAG,IAAIA,SAAO,OAAO;AAAA,cAC1C,UAAU,MAAM,UAAU;AAAA,cAC1B,aAAa;AAAA,cACb,SAAS,MAAM,UAAU,MAAM,OAAO,SAAS,SAAS;AAAA,cAEvD,UAAA,EAAE;AAAA,YAAA;AAAA,UAAA;AAAA,UAEL;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAW,GAAGA,SAAO,GAAG,IAAIA,SAAO,OAAO;AAAA,cAC1C,UAAU,MAAM,UAAU;AAAA,cAC1B,aAAa;AAAA,cACb,SAAS,MAAM,UAAU,MAAM,OAAO,SAAS,YAAY;AAAA,cAE1D,UAAA,EAAE;AAAA,YAAA;AAAA,UAAA;AAAA,QACL,EAAA,CACF,IAEA,oBAAC,OAAA,EAAI,WAAWA,SAAO,KACrB,UAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,UAAW,UAAA,EAAE,UAAS,EAAA,CAChD;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAIR;ACjSA,SAAS,mBAAmB,KAIV;AAChB,MAAI,QAAuB;AAC3B,MAAI,YAAY,CAAC,MAAM,QAAQ;AAC7B,QAAI,KAAK,KAAK,SAAS,qBAAqB;AAC1C,cAAQ;AACR,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAGO,MAAM,oBAAoBC,OAAK,OAAO;AAAA,EAC3C,MAAM;AAAA,EACN,OAAO;AAAA,EACP,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,WAAW;AAAA,EAEX,gBAAgB;AACd,WAAO;AAAA,MACL,OAAO;AAAA,QACL,SAAS;AAAA,QACT,WAAW,CAAC,OAAO,GAAG,aAAa,YAAY,KAAK;AAAA,QACpD,YAAY,CAAC,UACX,MAAM,QAAQ,EAAE,cAAc,MAAM,UAAU,CAAA;AAAA,MAAC;AAAA,IACnD;AAAA,EAEJ;AAAA,EAEA,YAAY;AACV,WAAO,CAAC,EAAE,KAAK,uCAAuC;AAAA,EACxD;AAAA,EAEA,WAAW,EAAE,MAAM,kBAAkB;AACnC,UAAM,QAAQ,OAAO,KAAK,MAAM,SAAS,EAAE;AAC3C,WAAO;AAAA,MACL;AAAA,MACA;AAAA,QACE,GAAG;AAAA,QACH,aAAa;AAAA,QACb,OAAO;AAAA,QACP,iBAAiB;AAAA,QACjB,aAAa;AAAA,QACb,aAAa;AAAA,MAAA;AAAA,MAEf,CAAC,QAAQ,EAAE,OAAO,+BAA+B,eAAe,QAAQ;AAAA,MACxE,CAAC,QAAQ,EAAE,OAAO,+BAAA,GAAkC,KAAK;AAAA,IAAA;AAAA,EAE7D;AAAA,EAEA,iBAAiB;AACf,WAAO;AAAA,EACT;AAAA,EAEA,cAAc;AACZ,WAAO;AAAA,MACL,yBACE,CAAC,UACD,CAAC,EAAE,MAAA,MACD,MAAA,EACG,MAAA,EACA,cAAc;AAAA,QACb,MAAM,KAAK;AAAA,QACX,OAAO,EAAE,MAAA;AAAA,MAAM,CAChB,EACA,QAAQ,CAAC,EAAE,SAAS;AACnB,WAAG,QAAQ,gBAAgB,KAAK;AAChC,WAAG,QAAQ,iBAAiB,IAAI;AAChC,eAAO;AAAA,MACT,CAAC,EACA,IAAA;AAAA,MACP,yBACE,CAAC,UACD,CAAC,EAAE,IAAI,UAAU,YAAY;AAC3B,cAAM,MAAM,mBAAmB,MAAM,GAAG;AACxC,YAAI,OAAO,KAAM,QAAO;AACxB,YAAI,UAAU;AACZ;AAAA,YACE,GACG,cAAc,KAAK,QAAW,EAAE,MAAA,CAAO,EACvC,QAAQ,gBAAgB,KAAK,EAC7B,QAAQ,iBAAiB,IAAI;AAAA,UAAA;AAAA,QAEpC;AACA,eAAO;AAAA,MACT;AAAA,MACF,yBACE,MACA,CAAC,EAAE,IAAI,UAAU,YAAY;AAC3B,cAAM,MAAM,mBAAmB,MAAM,GAAG;AACxC,YAAI,OAAO,KAAM,QAAO;AACxB,cAAM,OAAO,MAAM,IAAI,OAAO,GAAG;AACjC,YAAI,CAAC,KAAM,QAAO;AAClB,YAAI,UAAU;AACZ;AAAA,YACE,GACG,OAAO,KAAK,MAAM,KAAK,QAAQ,EAC/B,QAAQ,gBAAgB,KAAK,EAC7B,QAAQ,iBAAiB,IAAI;AAAA,UAAA;AAAA,QAEpC;AACA,eAAO;AAAA,MACT;AAAA,IAAA;AAAA,EAEN;AACF,CAAC;ACnHD,MAAMC,eAAa;AASnB,MAAM,gBAAgB,CAAC,iBAAiB,mBAAmB,EAAE;AAG7D,eAAe,oBACb,QACA,OACA,KACe;AACf,QAAM,UAAU,MAAM,OAAO,CAACC,OAAMD,aAAW,KAAKC,GAAE,IAAI,CAAC;AAC3D,MAAI,QAAQ,WAAW,EAAG;AAE1B,QAAM,WAAW,OAAO;AACxB,MAAI,CAAC,SAAU;AACf,QAAM,QAAQ,MAAM,QAAQ,IAAI,QAAQ,IAAI,CAACA,OAAMA,GAAE,KAAA,CAAM,CAAC;AAC5D,QAAM,OAAO,SAAS,MAAM,MAAM,KAAK,MAAM,CAAC;AAC9C,MAAI,OAAO,MAAM;AACf,WAAO,MAAA,EAAQ,MAAA,EAAQ,gBAAgB,KAAK,IAAI,EAAE,IAAA;AAAA,EACpD,OAAO;AACL,WAAO,QAAQ,MAAA,EAAQ,cAAc,IAAI,EAAE,IAAA;AAAA,EAC7C;AACF;AAQO,MAAM,mBAAmB,UAAU,OAAO;AAAA,EAC/C,MAAM;AAAA,EAEN,wBAAwB;AACtB,UAAM,EAAE,WAAW;AACnB,WAAO;AAAA,MACL,iBAAiB;AAAA,QACf,KAAK,IAAI,UAAU,kBAAkB;AAAA,QACrC;AAAA,QACA,kBAAkB;AAAA,QAClB,QAAQ,CAAC,IAAI,OAAO,QAAQ;AAC1B,8BAAoB,IAAI,OAAO,GAAG,EAAE,MAAM,CAAC,QAAQ;AACjD,oBAAQ,MAAM,8BAA8B,GAAG;AAAA,UACjD,CAAC;AAAA,QACH;AAAA,QACA,SAAS,CAAC,IAAI,UAAU;AACtB,8BAAoB,IAAI,KAAK,EAAE,MAAM,CAAC,QAAQ;AAC5C,oBAAQ,MAAM,+BAA+B,GAAG;AAAA,UAClD,CAAC;AAAA,QACH;AAAA,MAAA,CACD;AAAA,IAAA;AAAA,EAEL;AACF,CAAC;ACtCM,MAAM,sBAAsB;AAE5B,MAAM,yBAAyB,IAAI;AAAA,EACxC;AACF;AAGO,MAAM,uBAAuB;AAE7B,MAAM,yBAAyB,UAAU,OAAO;AAAA,EACrD,MAAM;AAAA,EAEN,wBAAwB;AACtB,WAAO;AAAA,MACL,IAAI,OAA2B;AAAA,QAC7B,KAAK;AAAA,QACL,OAAO;AAAA,UACL,MAAM,OAAO,EAAE,aAAa,cAAc,MAAA;AAAA,UAC1C,MAAM,IAAI,OAAO;AACf,kBAAM,OAAO,GAAG,QAAQ,mBAAmB;AAG3C,gBAAI,aAAa,EAAE,aAAa,iBAAiB,GAAG,KAAK,IAAI,EAAA;AAC7D,gBAAI,GAAG,YAAY;AACjB,qBAAO,EAAE,aAAa,MAAM,YAAY,IAAI,GAAG,SAAS,GAAG,GAAG,EAAA;AAAA,YAChE;AACA,mBAAO;AAAA,UACT;AAAA,QAAA;AAAA,QAEF,OAAO;AAAA,UACL,YAAY,OAAoB;;AAC9B,qBAAO,4BAAuB,SAAS,KAAK,MAArC,mBAAwC,gBAAe;AAAA,UAChE;AAAA,QAAA;AAAA,MACF,CACD;AAAA,IAAA;AAAA,EAEL;AACF,CAAC;AAGM,SAAS,kBAAkB,QAAgB,SAAgC;AAChF,SAAO,KAAK;AAAA,IACV,OAAO,MAAM,GACV,QAAQ,qBAAqB,OAAO,EAKpC,QAAQ,sBAAsB,IAAI,EAClC,QAAQ,gBAAgB,KAAK;AAAA,EAAA;AAEpC;AAEA,SAAS,iBAAiB,KAAW,SAAyC;AAC5E,QAAM,SAA8C,CAAA;AACpD,MAAI,QAAQ,CAAC,OAAO,WAAW;AAC7B,WAAO,KAAK,EAAE,MAAM,QAAQ,IAAI,SAAS,MAAM,UAAU;AAAA,EAC3D,CAAC;AAED,QAAM,cAA4B,CAAA;AAClC,aAAW,UAAU,SAAS;AAC5B,eAAW,SAAS,OAAO,QAAQ;AACjC,YAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,MAAM,MAAM,EAAE,CAAC;AACvD,YAAM,KAAK,KAAK,IAAI,IAAI,QAAQ,MAAM,KAAK,IAAI,MAAM,MAAM,MAAM,EAAE,CAAC;AACpE,UAAI,QAAQ,GAAI;AAEhB,iBAAW,SAAS,QAAQ;AAC1B,YAAI,MAAM,MAAM,QAAQ,MAAM,QAAQ,GAAI;AAC1C,cAAM,QAAQ;AAAA,UACZ,OAAO;AAAA,UACP,mBAAmB,OAAO;AAAA,QAAA;AAE5B,YAAI,QAAQ,MAAM,QAAQ,MAAM,MAAM,IAAI;AAExC,sBAAY,KAAK,WAAW,KAAK,MAAM,MAAM,MAAM,IAAI,KAAK,CAAC;AAAA,QAC/D,OAAO;AAEL,sBAAY;AAAA,YACV,WAAW,OAAO,KAAK,IAAI,MAAM,MAAM,IAAI,GAAG,KAAK,IAAI,IAAI,MAAM,EAAE,GAAG,KAAK;AAAA,UAAA;AAAA,QAE/E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,YAAY,SAAS,cAAc,OAAO,KAAK,WAAW,IAAI,cAAc;AACrF;ACrGO,SAAS,cAAc,WAAqC;AACjE,MAAI,qBAAqB,cAAe,QAAO;AAC/C,MAAI,qBAAqB,cAAe,QAAO;AAC/C,MAAI,qBAAqB,cAAe,QAAO;AAC/C,SAAO;AACT;ACRO,SAAS,kBAAkB,MAAuB;AACvD,SACE,aAAa,KAAK,IAAI;AAAA,EACtB,kBAAkB,KAAK,IAAI;AAAA,EAC3B,kCAAkC,KAAK,IAAI;AAAA,EAC3C,2BAA2B,KAAK,IAAI;AAAA,EACpC,eAAe,KAAK,IAAI;AAAA,EACxB,eAAe,KAAK,IAAI;AAAA,EACxB,QAAQ,KAAK,IAAI;AAAA,EACjB,QAAQ,KAAK,IAAI;AAAA,EACjB,eAAe,KAAK,IAAI;AAAA,EACxB,uBAAuB,KAAK,IAAI;AAAA,EAChC,6CAA6C,KAAK,IAAI;AAE1D;AAiBO,MAAM,gBAAgB,UAAU,OAAO;AAAA,EAC5C,MAAM;AAAA,EAEN,wBAAwB;AACtB,UAAM,EAAE,WAAW;AACnB,WAAO;AAAA,MACL,IAAI,OAAO;AAAA,QACT,KAAK,IAAI,UAAU,eAAe;AAAA,QAClC,OAAO;AAAA,UACL,YAAY,MAAM,OAAO;AACvB,kBAAM,YAAY,MAAM;AACxB,gBAAI,CAAC,UAAW,QAAO;AACvB,kBAAM,OAAO,UAAU,QAAQ,YAAY;AAC3C,gBAAI,CAAC,KAAM,QAAO;AAGlB,kBAAMC,SAAS,KACZ;AACH,gBAAIA,UAAA,gBAAAA,OAAO,SAAU,QAAO;AAE5B,gBAAI,KAAK,MAAM,UAAU,MAAM,OAAO,KAAK,KAAK,KAAM,QAAO;AAC7D,gBAAI,CAAC,kBAAkB,IAAI,EAAG,QAAO;AAErC,kBAAM,WAAW,OAAO;AACxB,gBAAI,CAAC,SAAU,QAAO;AACtB,gBAAI;AAIF,oBAAM,OAAO,SAAS,MAAM,qBAAqB,IAAI,CAAC;AACtD,qBAAO,SAAS,cAAc,IAAI;AAClC,qBAAO;AAAA,YACT,SAAS,KAAK;AACZ,sBAAQ,MAAM,gCAAgC,GAAG;AACjD,qBAAO;AAAA,YACT;AAAA,UACF;AAAA,QAAA;AAAA,MACF,CACD;AAAA,IAAA;AAAA,EAEL;AACF,CAAC;AChED,SAAS,SACP,WACA,OACA,OACA,UACQ;AACR,MAAI,+BAAO,OAAQ,QAAO;AAC1B,SAAO,SAAS,WAAW,KAAK;AAClC;AAMO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkB;AAChB,QAAM,YAAY,OAA0B,IAAI;AAChD,QAAM,WAAW,OAAuB,IAAI;AAC5C,QAAM,CAACR,SAAQS,UAAS,IAAI,SAAS,CAAC;AAEtC,QAAM,UAAwB;AAAA,IAC5B,OAAO;AAAA,MACL,QAAS,KAAK,MAAM,UAAU,CAAA;AAAA,MAC9B,SAAU,KAAK,MAAM,WAAW,CAAA;AAAA,MAChC,YAAa,KAAK,MAAM,cACtB,CAAA;AAAA,IAAC;AAAA,IAEL,CAAC,KAAK,MAAM,QAAQ,KAAK,MAAM,SAAS,KAAK,MAAM,UAAU;AAAA,EAAA;AAG/D,QAAM,QAAS,UAAU,QAAQ,cAAc;AAC/C,QAAM,UAAU,QAAQ;AACxB,QAAM,YAAY,KAAK,IAAIT,SAAQ,KAAK,IAAI,GAAG,QAAQ,SAAS,CAAC,CAAC;AAClE,QAAM,SAAS,QAAQ,SAAS;AAChC,QAAM,UAAS,iCAAQ,WAAU;AACjC,QAAM,YAAY,QAAQ,iCAAQ,UAAU;AAE5C,YAAU,MAAM;AACd,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,UAAU,CAAC,OAAQ;AACxB,aAAS,UAAU,oBAAoB;AAAA,MACrC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,SAAS;AAAA,IAAA,CACjB;AAAA,EACH,GAAG,CAAC,QAAQ,SAAS,KAAK,CAAC;AAE3B,YAAU,MAAM;AACd,WAAO,MAAM;AACX,mBAAa,SAAS,OAAO;AAC7B,eAAS,UAAU;AAAA,IACrB;AAAA,EACF,GAAG,CAAA,CAAE;AAGL,YAAU,MAAM;AACd,iBAAa,SAAS,OAAO;AAC7B,aAAS,UAAU;AACnB,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,UAAU,CAAC,OAAQ;AACxB,aAAS,UAAU,oBAAoB;AAAA,MACrC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IAAA,CACR;AAAA,EACH,GAAG,CAAC,SAAS,CAAC;AAEd,QAAM,SAAS;AAAA,IACb,GAAG;AAAA,IACH,GAAI,UAAU,QAAQ;AAAA,EAAA;AAKxB,QAAM,cAAc,MAAM;AACxB,QAAI,CAAC,UAAU,CAAC,UAAW;AAC3B,UAAM,MAAM,OAAA;AACZ,QAAI,OAAO,QAAQ,SAAU;AAC7B,WAAO,SAAS,iBAAiB,GAAG;AAAA,EACtC;AAEA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,IAAG;AAAA,MACH,WAAW,YAAY,YAAY,4BAA4B,EAAE,GAC/D,WAAW,8BAA8B,EAC3C;AAAA,MACA,aAAU;AAAA,MACV,iBAAe,WAAW,SAAS;AAAA,MACnC,iBAAiB;AAAA,MACjB,aAAa,CAACD,OAAkB;AAC9B,YAAKA,GAAE,OAAuB,QAAQ,QAAQ,EAAG;AACjD,YAAIA,GAAE,WAAW,EAAG;AAEpB,oBAAA;AAAA,MACF;AAAA,MAEC,UAAA;AAAA,SAAA,iCAAQ,SACP,oBAAC,OAAA,EAAI,WAAU,mBAAmB,UAAA,OAAO,OAAM,IAC7C;AAAA,SACH,iCAAQ,YACP,oBAAC,OAAA,EAAI,WAAU,kBAAkB,UAAA,OAAO,UAAS,IAC/C;AAAA,QACH,QAAQ,SAAS,IAChB,oBAAC,OAAA,EAAI,WAAU,kBAAiB,MAAK,WAClC,UAAA,QAAQ,IAAI,CAAC,GAAG,MACf;AAAA,UAAC;AAAA,UAAA;AAAA,YAEC,MAAK;AAAA,YACL,MAAK;AAAA,YACL,WAAU;AAAA,YACV,eAAa,MAAM,YAAY,SAAS;AAAA,YACxC,iBAAe,MAAM;AAAA,YACrB,aAAa,CAACA,OAAMA,GAAE,gBAAA;AAAA,YACtB,SAAS,CAACA,OAAM;AACd,cAAAA,GAAE,gBAAA;AACF,cAAAU,WAAU,CAAC;AAAA,YACb;AAAA,YAEC,mBAAS,EAAE,WAAW,EAAE,OAAO,GAAG,OAAO,QAAQ;AAAA,UAAA;AAAA,UAZ7C,GAAG,EAAE,SAAS,IAAI,CAAC;AAAA,QAAA,CAc3B,GACH,IACE;AAAA,QACJ,oBAAC,OAAA,EAAI,WAAU,yBAAwB,OAAO,EAAE,OAAA,GAC9C,UAAA,oBAAC,UAAA,EAAO,KAAK,UAAA,CAAW,EAAA,CAC1B;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN;ACtIO,SAAS,YAAY,UAA8B,IAAI;AAE5D,QAAM,EAAE,WAAW,OAAO,aAAa,MAAM,gBAAgB;AAC7D,SAAO,YAAY,OAAgC;AAAA,IACjD,aAAa;AACX,aAAO;AAAA,QACL,gBAAgB,CAAA;AAAA,QAChB,eAAe;AAAA,QACf;AAAA,QACA;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,cAAc;AACZ,aAAO,sBAAsB,SAAS;AAAA,IACxC;AAAA,EAAA,CACD;AACH;;;;;;;;;;;;;;;;;;;;;;;;;AC1BA,MAAM,YAAgD;AAAA,EACpD,EAAE,OAAO,IAAI,OAAO,cAAA;AAAA,EACpB,EAAE,OAAO,cAAc,OAAO,aAAA;AAAA,EAC9B,EAAE,OAAO,cAAc,OAAO,aAAA;AAAA,EAC9B,EAAE,OAAO,UAAU,OAAO,SAAA;AAAA,EAC1B,EAAE,OAAO,QAAQ,OAAO,OAAA;AAAA,EACxB,EAAE,OAAO,MAAM,OAAO,KAAA;AAAA,EACtB,EAAE,OAAO,QAAQ,OAAO,OAAA;AAAA,EACxB,EAAE,OAAO,KAAK,OAAO,IAAA;AAAA,EACrB,EAAE,OAAO,OAAO,OAAO,MAAA;AAAA,EACvB,EAAE,OAAO,UAAU,OAAO,KAAA;AAAA,EAC1B,EAAE,OAAO,OAAO,OAAO,MAAA;AAAA,EACvB,EAAE,OAAO,QAAQ,OAAO,OAAA;AAAA,EACxB,EAAE,OAAO,QAAQ,OAAO,OAAA;AAAA,EACxB,EAAE,OAAO,QAAQ,OAAO,OAAA;AAAA,EACxB,EAAE,OAAO,SAAS,OAAO,QAAA;AAAA,EACzB,EAAE,OAAO,QAAQ,OAAO,OAAA;AAAA,EACxB,EAAE,OAAO,OAAO,OAAO,MAAA;AAAA,EACvB,EAAE,OAAO,YAAY,OAAO,WAAA;AAC9B;AAMO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAkB;;AAChB,QAAM,SAA0B;AAAA,IAC9B,GAAG;AAAA,IACH,KAAK,4CAAW,YAAX,mBACD,oBAAmB,CAAA;AAAA,EAAC;AAE1B,QAAM,WAAY,KAAK,MAAM,YAAuB;AACpD,QAAM,UAAU,UAAU,KAAK,CAAC,MAAM,EAAE,UAAU,QAAQ;AAC1D,QAAM,eAAe,UACjB,QAAQ,UAAU,KAChB,OAAO,aACP,QAAQ,QACR,OAAO;AACb,QAAM,WAAW,OAAO;AAExB,SACE,qBAAC,iBAAA,EAAgB,WAAWL,SAAO,SAChC,UAAA;AAAA,IAAA,gCACE,OAAA,EAAI,WAAWA,SAAO,QAAQ,iBAAiB,OAC9C,UAAA;AAAA,MAAA,qBAAC,aAAa,MAAb,EACC,UAAA;AAAA,QAAA,oBAAC,aAAa,SAAb,EAAqB,SAAO,MAC3B,UAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAWA,SAAO;AAAA,YAClB,cAAW;AAAA,YAEX,UAAA;AAAA,cAAA,oBAAC,UAAM,UAAA,aAAA,CAAa;AAAA,kCACnB,iBAAA,EAAgB,MAAM,IAAI,WAAWA,SAAO,YAAA,CAAa;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA,GAE9D;AAAA,QACA,oBAAC,aAAa,QAAb,EACC,UAAA;AAAA,UAAC,aAAa;AAAA,UAAb;AAAA,YACC,WAAWA,SAAO;AAAA,YAClB,YAAY;AAAA,YACZ,OAAM;AAAA,YAEL,UAAA,UAAU,IAAI,CAAC,MAAM;AACpB,oBAAM,cACJ,EAAE,UAAU,KAAK,OAAO,aAAa,EAAE;AACzC,oBAAM,WAAW,EAAE,UAAU;AAC7B,qBACE;AAAA,gBAAC,aAAa;AAAA,gBAAb;AAAA,kBAEC,WAAW,GAAGA,SAAO,QAAQ,GAAG,WAAW,IAAIA,SAAO,gBAAgB,KAAK,EAAE;AAAA,kBAC7E,UAAU,MAAM,iBAAiB,EAAE,UAAU,EAAE,OAAO;AAAA,kBAEtD,UAAA;AAAA,oBAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,eACrB,UAAA,+BAAY,WAAA,EAAU,MAAM,GAAA,CAAI,IAAK,KAAA,CACxC;AAAA,oBACC;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAPI,EAAE;AAAA,cAAA;AAAA,YAUb,CAAC;AAAA,UAAA;AAAA,QAAA,EACH,CACF;AAAA,MAAA,GACF;AAAA,MACA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAWA,SAAO;AAAA,UAClB,OAAO,OAAO;AAAA,UACd,cAAY,OAAO;AAAA,UACnB,SAAS,MAAM,WAAA;AAAA,UAEf,8BAAC,WAAA,CAAA,CAAU;AAAA,QAAA;AAAA,MAAA;AAAA,IACb,GACF;AAAA;AAAA,0BAGC,OAAA,EAAI,WAAWA,SAAO,WAAW,iBAAiB,OAChD,UAAA,aAAA,CACH;AAAA;AAAA,IAEF,oBAAC,SAAI,WAAWA,SAAO,KAErB,UAAA,oBAAC,iBAAA,EAAgB,IAAI,OAAA,CAAiB,EAAA,CACxC;AAAA,EAAA,GACF;AAEJ;AC9CA,MAAM,YAAY,kBAAkB,OAAyB;AAAA,EAC3D,aAAa;;AACX,WAAO;AAAA,MACL,IAAG,UAAK,WAAL;AAAA,MACH,iBAAiB;AAAA,IAAA;AAAA,EAErB;AAAA;AAAA;AAAA,EAGA,eAAe,CAAC,OAAO,YACrB,iCAAiC,OAAO,SAAS,WAAW;AAAA,EAC9D,cAAc;AACZ,WAAO,sBAAsB,aAAa;AAAA,EAC5C;AAAA,EACA,uBAAuB;AACrB,WAAO;AAAA,MACL,WAAW,MAAM;AACf,cAAM,EAAE,UAAU,KAAK;AACvB,cAAM,EAAE,cAAc;AACtB,cAAM,EAAE,OAAO,QAAA,IAAY;AAG3B,YACE,SACA,QAAQ,OAAO,KAAK,SAAS,KAAK,QAClC,QAAQ,iBAAiB,KACzB,QAAQ,OAAO,QAAQ,OAAO,GAC9B;AACA,iBAAO;AAAA,QACT;AAGA,YAAI,SAAS,QAAQ,iBAAiB,GAAG;AACvC,gBAAM,SAAS,QAAQ,OAAO,QAAQ,KAAK;AAC3C,gBAAM,WAAW,MAAM,IAAI,QAAQ,MAAM,EAAE;AAC3C,eAAI,qCAAU,KAAK,UAAS,KAAK,MAAM;AACrC,kBAAM,eAAe,SAAS,SAAS;AACvC,iBAAK,OAAO,MAAA,EAAQ,iBAAiB,YAAY,EAAE,IAAA;AACnD,mBAAO;AAAA,UACT;AAAA,QACF;AAEA,eAAO;AAAA,MACT;AAAA,IAAA;AAAA,EAEJ;AACF,CAAC;AAGD,MAAM,yBAAyB,MAAM,OAAO;AAAA,EAC1C,uBAAuB;AACrB,WAAO;AAAA,MACL,WAAW,MAAM;AACf,cAAM,EAAE,UAAU,KAAK;AACvB,cAAM,EAAE,cAAc;AACtB,cAAM,EAAE,OAAO,QAAA,IAAY;AAC3B,YAAI,OAAO;AACT,gBAAM,aAAa,QAAQ;AAC3B,eAAI,yCAAY,KAAK,UAAS,KAAK,MAAM;AACvC,kBAAM,WAAW,QAAQ,MAAM,WAAW;AAC1C,iBAAK,OAAO,MAAA,EAAQ,iBAAiB,QAAQ,EAAE,IAAA;AAC/C,mBAAO;AAAA,UACT;AAAA,QACF;AACA,eAAO;AAAA,MACT;AAAA,IAAA;AAAA,EAEJ;AACF,CAAC;AAuHM,MAAM,wBAAwB,WAGnC,SAASM,uBACT;AAAA,EACE,kBAAkB;AAAA,EAClB,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB,qBAAqB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,eAAe;AAAA,EACf;AACF,GACA,KACA;AACA,QAAM,kBAAkB;AAAA,IACtB,wBAAwB,iBAAiB,WAAW,CAAA,CAAE;AAAA,EAAA;AAGxD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAC9C,QAAM,eAAe,OAAgC,IAAI;AAEzD,QAAM,SAAS,UAAU;AAAA,IACvB,YAAY;AAAA,MACV,GAAG;AAAA,MACH,UAAU,UAAU,EAAE,UAAU,iBAAiB;AAAA,MACjD,uBAAuB,UAAU,EAAE,QAAQ,OAAO;AAAA,MAClD;AAAA,MACA,YAAY,EAAE,UAAU,OAAO;AAAA,MAC/B,kBAAkB,EAAE,gBAAgB;AAAA,MACpC;AAAA,MACA,uBAAuB;AAAA,QACrB,YAAY;AAAA,QACZ,aAAa;AAAA,MAAA,CACd;AAAA,MACD;AAAA,MACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,GAAI,cACA,CAAC,eAAe,UAAU,EAAE,WAAW,OAAO,kBAAkB,GAAG,CAAC,IACpE,CAAA;AAAA,MACJ,gBAAgB,UAAU;AAAA,QACxB,OAAO,aAAA;AAAA,QACP,UAAU,CAAC,YAAY;AACrB;AAAA,YACE,QACG,OAAO,CAACC,OAAMA,GAAE,SAAS,CAAC,EAC1B,IAAI,CAACA,QAAO,EAAE,IAAIA,GAAE,IAAI,OAAOA,GAAE,OAAO,MAAMA,GAAE,cAAc;AAAA;AAAA,QAErE;AAAA,MAAA,CACD;AAAA,MACD,GAAI,gBAAgB,CAAC,aAAa,IAAI,CAAA;AAAA,MACtC,GAAI,mBAAmB,CAAC,gBAAgB,IAAI,CAAA;AAAA,MAC5C,GAAI,mBAAmB,CAAA;AAAA,IAAC;AAAA,IAE1B,SAAS;AAAA,IACT,aAAa;AAAA,IACb;AAAA;AAAA,IAEA,mBAAmB;AAAA,IACnB,aAAa;AAAA,MACX,YAAY;AAAA,QACV,OAAOP,SAAO;AAAA,QACd,oBAAoB,eAAe;AAAA,MAAA;AAAA,IACrC;AAAA,EACF,CACD;AAED,YAAU,MAAM;AACd,mDAAgB;AAChB,WAAO,MAAM,+CAAgB;AAAA,EAC/B,GAAG,CAAC,QAAQ,aAAa,CAAC;AAG1B,YAAU,MAAM;AACd,qCAAQ,YAAY;AAAA,EACtB,GAAG,CAAC,QAAQ,QAAQ,CAAC;AAErB,QAAM,YAAY,YAAY,MAAM;AAClC,gBAAY,KAAK;AAGjB,qCAAQ,SAAS;AAAA,EACnB,GAAG,CAAC,MAAM,CAAC;AAOX,YAAU,MAAM;AACd,QAAI,CAAC,UAAU,CAAC,eAAe,CAAC,aAAc;AAC9C,UAAM,YAAY,CAAC,UAAyB;AAC1C,UAAI,EAAE,MAAM,WAAW,MAAM,YAAY,MAAM,UAAU,MAAM,UAAU;AACvE;AAAA,MACF;AACA,UAAI,MAAM,QAAQ,OAAO,MAAM,QAAQ,IAAK;AAC5C,YAAMJ,UAAS,SAAS;AACxB,YAAM,WAAW,CAAC,CAACA,WAAU,OAAO,KAAK,IAAI,SAASA,OAAM;AAC5D,YAAM,iBAAiBA,YAAW,QAAQA,YAAW,SAAS;AAC9D,YAAM,aAAa,SAAS,iBAAiB,cAAc,EAAE,UAAU;AACvE,UAAI,CAAC,YAAY,CAAC,OAAO,aAAa,EAAE,kBAAkB,aAAa;AACrE;AAAA,MACF;AACA,YAAM,eAAA;AACN,kBAAY,IAAI;AAEhB,4BAAsB,MAAA;;AAAM,kCAAa,YAAb,mBAAsB;AAAA,OAAQ;AAAA,IAC5D;AACA,aAAS,iBAAiB,WAAW,WAAW,IAAI;AACpD,WAAO,MAAM,SAAS,oBAAoB,WAAW,WAAW,IAAI;AAAA,EACtE,GAAG,CAAC,QAAQ,aAAa,YAAY,CAAC;AAItC,QAAM,uBAAuB,OAAe,EAAE;AAC9C,YAAU,MAAM;AAEd,QAAI,CAAC,UAAU,CAAC,SAAU;AAC1B,UAAM,aAAa,YAAY,CAAA,GAC5B,IAAI,CAAC,MAAM,GAAG,EAAE,SAAS,IAAI,EAAE,SAAS,MAAM,EAAE,EAChD,KAAK,GAAG;AACX,QAAI,cAAc,qBAAqB,QAAS;AAChD,yBAAqB,UAAU;AAC/B,gCAA4B,QAAQ,YAAY,EAAE;AAAA,EACpD,GAAG,CAAC,QAAQ,UAAU,QAAQ,CAAC;AAG/B,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,WAAO,KAAK;AAAA,MACV,OAAO,MAAM,GAAG;AAAA,QACd;AAAA,QACA,mBAAmB;AAAA,MAAA;AAAA,IACrB;AAAA,EAEJ,GAAG,CAAC,QAAQ,eAAe,CAAC;AAG5B,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,sBAAkB,QAAQ,kBAAkB,EAAE;AAAA,EAChD,GAAG,CAAC,QAAQ,cAAc,CAAC;AAG3B,QAAM,mBAAmB,OAAO,aAAa;AAC7C,YAAU,MAAM;AACd,qBAAiB,UAAU;AAAA,EAC7B,GAAG,CAAC,aAAa,CAAC;AAClB,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,MAAM,OAAO,KAAK;AACxB,UAAM,UAAU,CAAC,UAAsB;;AACrC,YAAM,SAAS,MAAM;AACrB,YAAM,MAAK,4CAAQ,YAAR,gCAAkB,yBAAlB,mBAAwC,aAAa;AAChE,UAAI,GAAI,wBAAiB,YAAjB,0CAA2B;AAAA,IACrC;AACA,QAAI,iBAAiB,SAAS,OAAO;AACrC,WAAO,MAAM,IAAI,oBAAoB,SAAS,OAAO;AAAA,EACvD,GAAG,CAAC,MAAM,CAAC;AAGX,QAAM,uBAAuB,OAAO,iBAAiB;AACrD,YAAU,MAAM;AACd,yBAAqB,UAAU;AAAA,EACjC,GAAG,CAAC,iBAAiB,CAAC;AACtB,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,oBAAoB,MAAM;;AAC9B,YAAM,EAAE,MAAM,IAAI,MAAA,IAAU,OAAO,MAAM;AACzC,iCAAqB,YAArB,8CAA+B;AAAA,QAC7B;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM,cAAc,OAAO,MAAM,SAAS;AAAA,MAAA;AAAA,IAE9C;AACA,WAAO,GAAG,mBAAmB,iBAAiB;AAC9C,WAAO,MAAM;AACX,aAAO,IAAI,mBAAmB,iBAAiB;AAAA,IACjD;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAGX,QAAM,oBAAoB,OAAO,cAAc;AAC/C,QAAM,2BAA2B,OAAO,qBAAqB;AAC7D,oBAAkB,UAAU;AAC5B,2BAAyB,UAAU;AACnC,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,UAAM,gBAAgB,CAAC;AAAA,MACrB;AAAA,IAAA,MAGI;;AACJ,YAAM,QAAQ,YAAY,QAAQ,kBAAkB;AAGpD,UAAI,OAAO;AACT,gCAAkB,YAAlB,2CAA4B;AAC5B,uCAAyB,YAAzB,kDAAmC,MAAM,WAAW,CAAC,KAAK;AAAA,MAC5D;AACA,YAAM,SAAS,YAAY,QAAQ,mBAAmB;AAGtD,UAAI,QAAQ;AACV,gCAAkB,YAAlB,2CAA4B;AAAA,UAC1B,YAAY,OAAO;AAAA,UACnB,UAAU;AAAA,UACV,KAAK,OAAO;AAAA,QAAA;AAEd,uCAAyB,YAAzB,kDAAmC,OAAO,WAAW,CAAC,KAAK;AAAA,MAC7D;AAAA,IACF;AACA,WAAO,GAAG,eAAe,aAAa;AACtC,WAAO,MAAM;AACX,aAAO,IAAI,eAAe,aAAa;AAAA,IACzC;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX;AAAA,IACE;AAAA,IACA,OAAO;AAAA,MACL,aAAa,MAAA;;AAAM,uDAAQ,gBAAR,oCAA2B;AAAA;AAAA,MAC9C,SAAS,MAAA;;AAAM,uDAAQ,YAAR,oCAAuB;AAAA;AAAA,MACtC,SAAS,MAAA;;AAAO,uDAAQ,YAAR,oCAAmD,CAAA;AAAA;AAAA,MACnE,WAAW,MAAM,UAAU;AAAA,MAC3B,cAAc,CAAC,cACb,SAAS,aAAa,QAAQ,SAAS,IAAI;AAAA,MAC7C,aAAa,CAAC,QACZ,SAAS,YAAY,QAAQ,OAAO,MAAM,IAAI;AAAA,MAChD,eAAe,MAAO,SAAS,kBAAkB,MAAM,IAAI,CAAA;AAAA,MAC3D,UAAU,MAAM,YAAY,IAAI;AAAA,MAChC;AAAA,IAAA;AAAA,IAEF,CAAC,QAAQ,SAAS;AAAA,EAAA;AAGpB,SACE,qBAAC,OAAA,EAAI,WAAWI,SAAO,YAEpB,UAAA;AAAA,IAAA,UAAU,eAAe,WACxB,oBAAC,OAAA,EAAI,WAAWA,SAAO,eACrB,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAWA,SAAO;AAAA,MAAA;AAAA,IAAA,GAEtB,IACE;AAAA,IACJ;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,WACE,YAAY,GAAGA,SAAO,YAAY,IAAI,SAAS,KAAKA,SAAO;AAAA,MAAA;AAAA,IAAA;AAAA,EAE/D,GACF;AAEJ,CAAC;ACtfM,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAyB;AACvB,QAAM,WAAW;AAAA,IACf,MACE;AAAA,MACE,wBAAwB,UAAU,WAAW,CAAA,CAAE;AAAA,IAAA;AAAA,IAEnD,CAAC,UAAU,OAAO;AAAA,EAAA;AAGpB,QAAM,aAAa;AAAA,IACjB,MAAM;AAAA,MACJ,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA,YAAY,EAAE,UAAU,OAAO;AAAA,MAC/B,kBAAkB,EAAE,gBAAgB;AAAA,MACpC;AAAA,IAAA;AAAA,IAEF,CAAC,cAAc;AAAA,EAAA;AAGjB,QAAM,SAAS;AAAA,IACb;AAAA,MACE;AAAA,MACA,SAAS;AAAA,MACT,aAAa;AAAA,MACb,UAAU;AAAA,MACV,mBAAmB;AAAA,MACnB,aAAa;AAAA,QACX,YAAY,EAAE,OAAOA,SAAO,cAAA;AAAA,MAAc;AAAA,IAC5C;AAAA,IAEF,CAAC,UAAU;AAAA,EAAA;AAGb,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AACb,WAAO,SAAS,WAAW,UAAU,EAAE,aAAa,YAAY;AAAA,EAClE,GAAG,CAAC,QAAQ,QAAQ,CAAC;AAErB,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC;AAAA,MACA,WAAW,aAAaA,SAAO;AAAA,IAAA;AAAA,EAAA;AAGrC;AC1FO,MAAM,aAAa;AACnB,MAAM,YAAY;AASlB,SAAS,uBAAuB;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKqB;AACnB,MAAI,mDAAiB,OAAQ,QAAO;AACpC,QAAM,WAA2B;AAAA,IAC/B,KAAK;AAAA,IACL,OAAO,OAAO;AAAA,IACd,QAAQ;AAAA,EAAA;AAEV,MAAI,oBAAoB,cAAc;AACpC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO,OAAO;AAAA,QACd,QAAQ;AAAA,MAAA;AAAA,IACV;AAAA,EAEJ;AACA,SAAO,CAAC,QAAQ;AAClB;AC1BO,SAAS,eACd,QACA,UACA,UAAuB,CAAA,GACjB;AACN,QAAM,WAAW;AAAA,IACf,wBAAwB,UAAU,OAAO;AAAA,EAAA;AAE3C,MAAI,CAAC,SAAU;AACf,MAAI,kBAAkB,QAAQ,QAAQ,EAAG;AACzC,aAAW,SAAS,oBAAoB,QAAQ,GAAG;AACjD,QAAI,kBAAkB,QAAQ,KAAK,EAAG;AACtC,yBAAqB,QAAQ,iBAAiB,KAAK,CAAC;AAAA,EACtD;AACF;AAEA,SAAS,kBAAkB,QAAgB,UAA2B;AACpE,MAAI;AACF,WAAO,OACJ,QACA,QACA,cAAc,UAAU,EAAE,aAAa,WAAA,CAAY,EACnD,IAAA;AAAA,EACL,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,qBAAqB,QAAgB,MAAoB;AAChE,MAAI,CAAC,KAAM;AACX,SACG,MAAA,EACA,MAAA,EACA,cAAc;AAAA,IACb,MAAM;AAAA,IACN,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM;AAAA,EAAA,CACjC,EACA,IAAA;AACL;AAGO,SAAS,oBAAoB,UAA4B;AAC9D,QAAM,MAAgB,CAAA;AACtB,aAAW,CAAC,GAAG,IAAI,KAAK,SAAS,MAAM,kBAAkB,EAAE,WAAW;AACpE,QAAI,CAAC,KAAM;AACX,QAAI,IAAI,MAAM,GAAG;AACf,UAAI,KAAK,IAAI;AACb;AAAA,IACF;AACA,eAAW,SAAS,KAAK,MAAM,QAAQ,GAAG;AACxC,UAAI,MAAM,KAAA,EAAQ,KAAI,KAAK,KAAK;AAAA,IAClC;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,iBAAiB,UAA0B;AACzD,SAAO,SACJ,QAAQ,yBAAyB,EAAE,EACnC,QAAQ,0BAA0B,IAAI,EACtC,QAAQ,gBAAgB,EAAE,EAC1B,QAAQ,qBAAqB,EAAE,EAC/B,QAAQ,qBAAqB,EAAE,EAC/B,QAAQ,YAAY,EAAE,EACtB,QAAQ,YAAY,EAAE,EACtB,QAAQ,OAAO,GAAG,EAClB,QAAQ,QAAQ,GAAG,EACnB,KAAA;AACL;AC/DO,SAAS,sBACd,OAC2B;AAC3B,MAAI,CAAC,UAAU,KAAK,EAAG,QAAO;AAE9B,QAAM,OAAO,aAAa,KAAK;AAC/B,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,SAAS,KAAK,GAAG;AACnD,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,QAAQ,KAAK,IAAI;AAEnD,MAAI,oBAAoB;AACxB,WAASQ,OAAM,KAAK,KAAKA,OAAM,KAAK,QAAQA,QAAO;AACjD,QAAI,YAAY,KAAK,KAAK,KAAK,OAAOA,IAAG,GAAG;AAC1C,0BAAoB;AACpB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,aAAa,WAAW,KAAK,WAAW;AAAA,IACxC;AAAA,IACA,eAAe,KAAK,QAAQ,KAAK,KAAK,WAAW,KAAK,IAAI;AAAA,IAC1D,eAAe,KAAK,SAAS,KAAK,KAAK,UAAU,KAAK,IAAI;AAAA,EAAA;AAE9D;AAGO,SAAS,qBACd,WACA,KACS;AACT,MAAI,QAAQ;AACZ,YAAU,YAAY,CAAC,MAAM,YAAY;AACvC,QAAI,OAAO,WAAW,OAAO,UAAU,KAAK,UAAU;AACpD,cAAQ;AAAA,IACV;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAMO,SAAS,oCACd,QACA,KACM;AACN,QAAM,EAAE,cAAc,OAAO;AAC7B,MACE,qBAAqB,iBACrB,qBAAqB,WAAW,GAAG,GACnC;AACA,WAAO,KAAK,MAAA;AACZ;AAAA,EACF;AACA,SAAO,QAAQ,MAAA,EAAQ,iBAAiB,GAAG,EAAE,IAAA;AAC/C;AAEO,SAAS,cAAc,QAAgB,OAAwB;AACpE,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK;AAC3B,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI,CAAC,OAAO,SAAS,aAAA,EAAgB,QAAO;AAAA,EAC9C;AACA,SAAO;AACT;AAEO,SAAS,aAAa,QAAgB,OAAwB;AACnE,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK;AAC3B,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI,CAAC,OAAO,SAAS,YAAA,EAAe,QAAO;AAAA,EAC7C;AACA,SAAO;AACT;AAEO,SAAS,iBAAiB,QAAgB,OAAwB;AACvE,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK;AAC3B,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI,CAAC,OAAO,SAAS,gBAAA,EAAmB,QAAO;AAAA,EACjD;AACA,SAAO;AACT;AAEO,SAAS,gBAAgB,QAAgB,OAAwB;AACtE,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK;AAC3B,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI,CAAC,OAAO,SAAS,eAAA,EAAkB,QAAO;AAAA,EAChD;AACA,SAAO;AACT;AAGO,SAAS,mBAAmB,QAAyB;AAC1D,QAAM,OAAO,sBAAsB,OAAO,KAAK;AAC/C,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,KAAK,cAAe,QAAO,OAAO,SAAS,YAAA;AAC/C,SAAO,OAAO,SAAS,UAAA;AACzB;AAGO,SAAS,sBAAsB,QAAyB;AAC7D,QAAM,OAAO,sBAAsB,OAAO,KAAK;AAC/C,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,KAAK,eAAe;AACtB,QAAI,KAAK,cAAe,QAAO,OAAO,SAAS,YAAA;AAC/C,WAAO;AAAA,EACT;AACA,SAAO,OAAO,SAAS,aAAA;AACzB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxHA,MAAM,UAAsB;AAAA,EAC1B,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,EAC7G,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,EAC7G,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,EAC7G,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,EAC7G,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAAA,EAC7G,CAAC,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,WAAW,SAAS;AAC/G;AAGA,MAAM,eAAe,CAAC,WAAW,SAAS;AAWnC,SAAS,aAAa,EAAE,OAAO,QAAQ,UAA6B;AACzE,QAAM,IAAI,EAAE,GAAG,2BAA2B,GAAG,OAAA;AAC7C,QAAM,UAAU,+BAAO;AAEvB,SACE,qBAAC,OAAA,EAAI,WAAWR,SAAO,SACrB,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAWA,SAAO;AAAA,QAClB,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,QACtB,SAAS,MAAM,OAAO,IAAI;AAAA,QAE1B,UAAA;AAAA,UAAA,oBAAC,QAAA,EAAK,WAAWK,SAAO,UAAU,eAAW,MAAC;AAAA,8BAC7C,QAAA,EAAK,WAAWA,SAAO,WAAY,YAAE,KAAA,CAAK;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAG7C,oBAAC,OAAA,EAAI,WAAWA,SAAO,MACpB,kBAAQ,KAAA,EAAO,IAAI,CAAC,MACnB;AAAA,MAAC;AAAA,MAAA;AAAA,QAEC,MAAK;AAAA,QACL,WAAW,GAAGA,SAAO,MAAM,IACzB,YAAY,EAAE,YAAA,IAAgBA,SAAO,eAAe,EACtD;AAAA,QACA,OAAO,EAAE,YAAY,EAAA;AAAA,QACrB,OAAO;AAAA,QACP,cAAY;AAAA,QACZ,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,QACtB,SAAS,MAAM,OAAO,CAAC;AAAA,MAAA;AAAA,MATlB;AAAA,IAAA,CAWR,GACH;AAAA,wBAEC,OAAA,EAAI,WAAWK,SAAO,YAAa,YAAE,OAAM;AAAA,IAC5C,oBAAC,SAAI,WAAWA,SAAO,UACpB,UAAA,aAAa,IAAI,CAAC,MACjB;AAAA,MAAC;AAAA,MAAA;AAAA,QAEC,MAAK;AAAA,QACL,WAAW,GAAGA,SAAO,MAAM,IACzB,YAAY,EAAE,YAAA,IAAgBA,SAAO,eAAe,EACtD;AAAA,QACA,OAAO,EAAE,YAAY,EAAA;AAAA,QACrB,OAAO;AAAA,QACP,cAAY;AAAA,QACZ,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,QACtB,SAAS,MAAM,OAAO,CAAC;AAAA,MAAA;AAAA,MATlB;AAAA,IAAA,CAWR,EAAA,CACH;AAAA,EAAA,GACF;AAEJ;ACnDA,SAAS,cAAc,QAAgB,KAAiC;AACtE,QAAM,MAAM,OAAO,KAAK,QAAQ,GAAG;AACnC,MAAI,eAAe,YAAa,QAAO;AACvC,MAAI,eAAe,KAAM,QAAO,IAAI;AACpC,SAAO;AACT;AAEA,SAAS,iBAAiB,IAAiB,SAA+B;AACxE,MAAI,CAAC,QAAS,QAAO;AACrB,SAAQ,GAAG,cAAc,mBAAmB,KAA4B;AAC1E;AAEA,SAAS,kBACP,QACA,MACA,KACe;AACf,QAAM,OAAO,OAAO,KAAK,IAAI;AAC7B,MAAI,CAAC,KAAM,QAAO,CAAA;AAClB,QAAM,WAAW,KAAK,sBAAA;AACtB,QAAM,aAAa,OAAO,KAAK,IAAI,sBAAA;AACnC,QAAM,MAAM;AACZ,QAAM,aAAa,OAAO,KAAK,IAAI;AAEnC,MAAI,OAAO,MAAM;AACf,UAAM,KAAK,cAAc,QAAQ,GAAG;AACpC,QAAI,IAAI;AACN,YAAMD,KAAI,GAAG,sBAAA;AACb,YAAM,MAAMA,GAAE,SAAS,SAAS,MAAM;AACtC,UAAI,SAAS,SAAS;AACpB,eAAO;AAAA,UACL,MAAM,WAAW,OAAO,SAAS;AAAA,UACjC;AAAA,UACA,OAAO;AAAA,QAAA;AAAA,MAEX;AACA,aAAO;AAAA,QACL,MAAMA,GAAE,OAAO,SAAS;AAAA,QACxB;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AAEA,QAAM,SAAS,OAAO,KAAK,YAAY,OAAO,MAAM,UAAU,IAAI;AAClE,MAAI,SAAS,SAAS;AACpB,WAAO;AAAA,MACL,MAAM,WAAW,OAAO,SAAS;AAAA,MACjC,KAAK,OAAO,SAAS,SAAS,MAAM;AAAA,MACpC,OAAO;AAAA,IAAA;AAAA,EAEX;AACA,SAAO;AAAA,IACL,MAAM,OAAO,OAAO,SAAS;AAAA,IAC7B,KAAK,OAAO,SAAS,SAAS,MAAM;AAAA,EAAA;AAExC;AAEO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA2B;AACzB,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,KAAK;AACxC,QAAM,CAAC,YAAY,aAAa,IAAI;AAAA,IAAwB,MAC1D,kBAAkB,QAAQ,MAAM,GAAG;AAAA,EAAA;AAErC,QAAM,UAAU,MAAA;AAChB,QAAM,WAAW,OAA+C,IAAI;AACpE,QAAM,UAAU,OAAuB,IAAI;AAC3C,QAAM,UAAU,SAAS;AACzB,QAAM,OAAO,OAAO,KAAK,IAAI;AAE7B,YAAU,MAAM;AACd,aAAS,KAAK;AAAA,EAChB,GAAG,CAAC,KAAK,CAAC;AAEV,YAAU,MAAM;AACd,UAAM,SAAS,MAAM,cAAc,kBAAkB,QAAQ,MAAM,GAAG,CAAC;AACvE,WAAA;AACA,WAAO,iBAAiB,UAAU,MAAM;AACxC,WAAO,MAAM,OAAO,oBAAoB,UAAU,MAAM;AAAA,EAC1D,GAAG,CAAC,QAAQ,MAAM,KAAK,KAAK,CAAC;AAE7B,YAAU,MAAM;;AACd,mBAAS,YAAT,mBAAkB;AAAA,EACpB,GAAG,CAAA,CAAE;AAEL,YAAU,MAAM;AACd,QAAI,OAAO,KAAM;AACjB,UAAM,KAAK,cAAc,QAAQ,GAAG;AACpC,QAAI,CAAC,GAAI;AACT,OAAG,UAAU,IAAI,kBAAkB;AACnC,WAAO,MAAM;AACX,SAAG,UAAU,OAAO,kBAAkB;AAAA,IACxC;AAAA,EACF,GAAG,CAAC,QAAQ,GAAG,CAAC;AAEhB,YAAU,MAAM;AACd,QAAI,OAAO,KAAM;AACjB,UAAM,KAAK,cAAc,QAAQ,GAAG;AACpC,QAAI,CAAC,GAAI;AACT,UAAM,SAAS,iBAAiB,IAAI,OAAO;AAC3C,UAAM,MAAM,MAAM,KAAA;AAClB,QAAI,IAAK,gBAAe,QAAQ,KAAK,OAAO;AAAA,gBAChC,cAAc;AAAA,EAC5B,GAAG,CAAC,OAAO,KAAK,QAAQ,OAAO,CAAC;AAEhC,YAAU,MAAM;AACd,QAAI,OAAO,QAAQ,MAAO;AAC1B,UAAM,KAAK,cAAc,QAAQ,GAAG;AACpC,QAAI,CAAC,GAAI;AACT,UAAM,SAAS,iBAAiB,IAAI,OAAO;AAC3C,WAAO,MAAM;AACX,YAAM,UAAU,MAAM,KAAA;AACtB,UAAI,QAAS,gBAAe,QAAQ,SAAS,OAAO;AAAA,kBACxC,cAAc;AAAA,IAC5B;AAAA,EACF,GAAG,CAAC,KAAK,QAAQ,SAAS,OAAO,KAAK,CAAC;AAEvC,YAAU,MAAM;AACd,UAAM,QAAQ,CAACC,OAAoB;;AACjC,YAAM,SAASA,GAAE;AACjB,UAAI,EAAE,kBAAkB,MAAO;AAC/B,WAAI,aAAQ,YAAR,mBAAiB,SAAS,QAAS;AACvC,UAAI,OAAO,MAAM;AACf,cAAM,KAAK,cAAc,QAAQ,GAAG;AACpC,YAAI,yBAAI,SAAS,QAAS;AAAA,MAC5B;AACA,eAAA;AAAA,IACF;AACA,aAAS,iBAAiB,eAAe,KAAK;AAC9C,WAAO,MAAM,SAAS,oBAAoB,eAAe,KAAK;AAAA,EAChE,GAAG,CAAC,UAAU,QAAQ,GAAG,CAAC;AAE1B,QAAM,YAAY,MAAM,KAAA,EAAO,SAAS;AACxC,QAAM,WAAW,CAAC,cAAc,SAAS,YAAY;AAErD,QAAM,SAAS,MAAM;AACnB,QAAI,CAAC,UAAW;AAChB,cAAU,MAAM,MAAM;AAAA,EACxB;AAEA,QAAM,YAAY,CAChBA,OACG;AACH,QAAIA,GAAE,QAAQ,UAAU;AACtB,MAAAA,GAAE,eAAA;AACF,eAAA;AACA;AAAA,IACF;AACA,QAAIA,GAAE,QAAQ,QAAS;AACvB,QAAI,WAAW,EAAEA,GAAE,WAAWA,GAAE,SAAU;AAC1C,IAAAA,GAAE,eAAA;AACF,WAAA;AAAA,EACF;AAEA,QAAMc,SAAQ,UACZ;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAWT,SAAO;AAAA,MAClB,OAAO;AAAA,MACP;AAAA,MACA,MAAM,KAAK,IAAI,GAAG,MAAM,MAAM,IAAI,EAAE,MAAM;AAAA,MAC1C,mBAAiB;AAAA,MACjB,UAAU,CAACL,OAAM,SAASA,GAAE,OAAO,KAAK;AAAA,MACxC;AAAA,IAAA;AAAA,EAAA,IAGF;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAK;AAAA,MACL,WAAWK,SAAO;AAAA,MAClB,OAAO;AAAA,MACP;AAAA,MACA,mBAAiB;AAAA,MACjB,UAAU,CAACL,OAAM,SAASA,GAAE,OAAO,KAAK;AAAA,MACxC;AAAA,IAAA;AAAA,EAAA;AAIJ,MAAI,CAAC,KAAM,QAAO;AAElB,SAAO;AAAA,IACL;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK;AAAA,QACL,WAAWK,SAAO;AAAA,QAClB,OAAO;AAAA,QACP,MAAK;AAAA,QACL,cAAW;AAAA,QACX,mBAAiB;AAAA,QAEjB,UAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WACE,UACI,GAAGA,SAAO,SAAS,IAAIA,SAAO,cAAc,KAC5CA,SAAO;AAAA,YAGZ,UAAA;AAAA,cAAA,WACC;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,IAAI;AAAA,kBACJ,WACE,UACI,GAAGA,SAAO,QAAQ,IAAIA,SAAO,aAAa,KAC1CA,SAAO;AAAA,kBAGb,UAAA;AAAA,oBAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,cAAc,eAAW,MAC9C,UAAA,UAAU,QAAQ,KAAA,CACrB;AAAA,oBACC;AAAA,kBAAA;AAAA,gBAAA;AAAA,cAAA,IAED;AAAA,cACJ;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,IAAI,WAAW,SAAY;AAAA,kBAC3B,WACE,UACI,GAAGA,SAAO,SAAS,IAAIA,SAAO,cAAc,KAC5CA,SAAO;AAAA,kBAGZ,UAAA;AAAA,oBAAAS;AAAA,oBACD;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBACC,MAAK;AAAA,wBACL,WAAWT,SAAO;AAAA,wBAClB,UAAU,CAAC;AAAA,wBACX,OACE,UAAU,GAAG,SAAS,oBAAoB,GAAG,SAAS;AAAA,wBAExD,SAAS;AAAA,wBAER,UAAA;AAAA,0BAAA;AAAA,8CACA,QAAA,EAAK,WAAWA,SAAO,aAAa,eAAW,MAAC,UAAA,IAAA,CAEjD;AAAA,wBAAA;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBACF;AAAA,gBAAA;AAAA,cAAA;AAAA,YACF;AAAA,UAAA;AAAA,QAAA;AAAA,MACF;AAAA,IAAA;AAAA,IAEF;AAAA,EAAA;AAEJ;ACnJA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA,QAAAJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOG;AACD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,cAAY;AAAA,MACZ,gBAAcA;AAAA,MACd,aAAW;AAAA,MACX;AAAA,MACA,WAAW,GAAGI,SAAO,GAAG,IAAIJ,UAASI,SAAO,YAAY,EAAE;AAAA,MAE1D,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,MACtB;AAAA,MAEC;AAAA,IAAA;AAAA,EAAA;AAGP;AAEA,SAAS,UAAU;AACjB,6BAAQ,QAAA,EAAK,WAAWK,SAAO,SAAS,eAAW,MAAC;AACtD;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,WAAWA,SAAO;AAAA,MAClB,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,MACtB;AAAA,MAEA,UAAA;AAAA,QAAA,oBAAC,UAAK,WAAWK,SAAO,mBAAmB,eAAW,MACnD,UACH;AAAA,QACA,oBAAC,QAAA,EAAK,WAAWA,SAAO,oBAAqB,UAAA,MAAA,CAAM;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGzD;AAEA,SAAS,mBAAmB;AAC1B,6BAAQ,OAAA,EAAI,WAAWA,SAAO,kBAAkB,eAAW,MAAC;AAC9D;AAGA,MAAM,eAAe,cAA0B,MAAM;AAAC,CAAC;AAOvD,SAAS,YAAY;AAAA,EACnB;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,QAAQ,YAAY,MAAM,QAAQ,KAAK,GAAG,CAAA,CAAE;AAClD,8BACG,QAAQ,MAAR,EAAa,MAAY,cAAc,SACtC,UAAA;AAAA,IAAA,oBAAC,QAAQ,SAAR,EAAgB,SAAO,MAAE,UAAA,SAAQ;AAAA,IAClC,oBAAC,QAAQ,QAAR,EACC,UAAA;AAAA,MAAC,QAAQ;AAAA,MAAR;AAAA,QACC,WAAWA,SAAO;AAAA,QAClB,YAAY;AAAA,QACZ,OAAM;AAAA,QACN,iBAAiB,CAACL,OAAMA,GAAE,eAAA;AAAA,QAC1B,kBAAkB,CAACA,OAAMA,GAAE,eAAA;AAAA,QAE3B,8BAAC,aAAa,UAAb,EAAsB,OAAO,OAC3B,SAAA,CACH;AAAA,MAAA;AAAA,IAAA,EACF,CACF;AAAA,EAAA,GACF;AAEJ;AAEA,SAAS,SAAS;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAQ,WAAW,YAAY;AACrC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,WAAW,GAAGK,SAAO,QAAQ,IAAI,WAAWA,SAAO,mBAAmB,EAAE;AAAA,MACxE,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,MACtB,SAAS,MAAM;AACb,iBAAA;AACA,cAAA;AAAA,MACF;AAAA,MAEC;AAAA,IAAA;AAAA,EAAA;AAGP;AAEA,MAAM,oBAAoB;AAC1B,MAAM,oBAAoB;AAM1B,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,YAAY,WAAW,YAAY;AACzC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG;AAEvD,QAAM,aAAa,YAAY,MAAM,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,GAAG,EAAE;AAEvE,SACE;AAAA,IAAC,QAAQ;AAAA,IAAR;AAAA,MACC;AAAA,MACA,cAAc,CAAC,SAAS;AACtB,gBAAQ,IAAI;AACZ,YAAI,CAAC,KAAM,YAAA;AAAA,MACb;AAAA,MAEA,UAAA;AAAA,QAAA,oBAAC,QAAQ,SAAR,EAAgB,SAAO,MACtB,UAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL;AAAA,YACA,WAAW,GAAGK,SAAO,QAAQ,IAAI,OAAOA,SAAO,mBAAmB,EAAE;AAAA,YACpE,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,YAEtB,UAAA;AAAA,cAAA,qBAAC,QAAA,EAAK,WAAWK,SAAO,WACtB,UAAA;AAAA,gBAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,WAAW,UAAA,KAAC;AAAA,gBACnC,OAAO;AAAA,cAAA,GACV;AAAA,kCACC,iBAAA,EAAgB,MAAM,IAAI,WAAWA,SAAO,iBAAA,CAAkB;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA,GAEnE;AAAA,QACA,oBAAC,QAAQ,QAAR,EACC,UAAA;AAAA,UAAC,QAAQ;AAAA,UAAR;AAAA,YACC,WAAWA,SAAO;AAAA,YAClB,MAAK;AAAA,YACL,OAAM;AAAA,YACN,YAAY;AAAA,YACZ,iBAAiB,CAACL,OAAMA,GAAE,eAAA;AAAA,YAC1B,kBAAkB,CAACA,OAAMA,GAAE,eAAA;AAAA,YAE3B,UAAA;AAAA,cAAA;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,WAAWK,SAAO;AAAA,kBAClB,OAAO;AAAA,oBACL,qBAAqB,UAAU,iBAAiB;AAAA,kBAAA;AAAA,kBAElD,cAAc;AAAA,kBAEb,UAAA,MAAM,KAAK,EAAE,QAAQ,oBAAoB,kBAAA,GAAqB,CAAC,GAAG,MAAM;AACvE,0BAAM,MAAO,IAAI,oBAAqB;AACtC,0BAAMQ,OAAM,KAAK,MAAM,IAAI,iBAAiB,IAAI;AAChD,0BAAMZ,UAAS,MAAM,OAAO,KAAK,OAAO,MAAM,QAAQY,QAAO,MAAM;AACnE,2BACE;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBAEC,MAAK;AAAA,wBACL,cAAY,OAAO,kBAAkB,KAAKA,IAAG;AAAA,wBAC7C,WAAW,GAAGR,SAAO,aAAa,IAAIJ,UAASI,SAAO,sBAAsB,EAAE;AAAA,wBAC9E,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,wBACtB,cAAc,MAAM,SAAS,EAAE,MAAM,KAAK,MAAMa,MAAK;AAAA,wBACrD,SAAS,MAAM;AACb,mCAASA,MAAK,GAAG;AACjB,kCAAQ,KAAK;AACb,qCAAA;AACA,oCAAA;AAAA,wBACF;AAAA,sBAAA;AAAA,sBAXK;AAAA,oBAAA;AAAA,kBAcX,CAAC;AAAA,gBAAA;AAAA,cAAA;AAAA,kCAEF,OAAA,EAAI,WAAWR,SAAO,gBACpB,gBAAM,OAAO,IACV,OAAO,kBAAkB,MAAM,MAAM,MAAM,IAAI,IAC/C,OAAO,YAAA,CACb;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA,EACF,CACF;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN;AAGA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA,KAAAU;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOG;AACD,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,8BACG,QAAQ,MAAR,EAAa,MAAY,cAAc,SACtC,UAAA;AAAA,IAAA,oBAAC,QAAQ,SAAR,EAAgB,SAAO,MACtB,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAWV,SAAO;AAAA,QAClB;AAAA,QACA,cAAY;AAAA,QACZ,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,QAEtB,UAAA,qBAAC,QAAA,EAAK,WAAWK,SAAO,WACtB,UAAA;AAAA,UAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,gBAAiB,UAAA,OAAM;AAAA,UAC/C,oBAAC,UAAK,WAAWA,SAAO,cAAc,OAAO,EAAE,YAAYU,OAAI,CAAG;AAAA,QAAA,EAAA,CACpE;AAAA,MAAA;AAAA,IAAA,GAEJ;AAAA,IACA,oBAAC,QAAQ,QAAR,EACC,UAAA;AAAA,MAAC,QAAQ;AAAA,MAAR;AAAA,QACC,WAAWV,SAAO;AAAA,QAClB,YAAY;AAAA,QACZ,OAAM;AAAA,QACN,iBAAiB,CAACL,OAAMA,GAAE,eAAA;AAAA,QAC1B,kBAAkB,CAACA,OAAMA,GAAE,eAAA;AAAA,QAE3B,UAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC;AAAA,YACA,QAAQ,CAAC,MAAM;AACb,qBAAO,CAAC;AACR,sBAAQ,KAAK;AAAA,YACf;AAAA,YACA,QAAQ;AAAA,UAAA;AAAA,QAAA;AAAA,MACV;AAAA,IAAA,EACF,CACF;AAAA,EAAA,GACF;AAEJ;AAEA,MAAM,iBAAiB,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AACxC,MAAM,aAAa,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,MAAM;AAMnE,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AACF,GAAuB;AACrB,QAAM,IAAmB,EAAE,GAAG,sBAAsB,GAAG,OAAA;AAEvD,QAAM,QAAQ,eAAe;AAAA,IAC3B;AAAA,IACA,UAAU,CAAC,EAAE,QAAQA,UAAS;AAAA,MAC5B,MAAMA,GAAE,SAAS,MAAM;AAAA,MACvB,QAAQA,GAAE,SAAS,QAAQ;AAAA,MAC3B,WAAWA,GAAE,SAAS,WAAW;AAAA,MACjC,QAAQA,GAAE,SAAS,QAAQ;AAAA,MAC3B,MAAMA,GAAE,SAAS,MAAM;AAAA,MACvB,MAAMA,GAAE,SAAS,MAAM;AAAA,MACvB,UAAUA,GAAE,SAAS,UAAU;AAAA,MAC/B,cAAe,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,EAAY;AAAA,QAAK,CAAC,OAChDA,GAAE,SAAS,WAAW,EAAE,OAAO,IAAI;AAAA,MAAA;AAAA,MAErC,UAAWA,GAAE,cAAc,WAAW,EAAE,YAAuB;AAAA,MAC/D,aAAaA,GAAE,SAAS,WAAW;AAAA,MACnC,YAAYA,GAAE,SAAS,YAAY;AAAA,MACnC,aAAaA,GAAE,SAAS,aAAa;AAAA,MACrC,YAAYA,GAAE,SAAS,YAAY;AAAA,MACnC,WAAYA,GAAE,cAAc,WAAW,EAAE,SAAoB;AAAA,MAC7D,gBACGA,GAAE,cAAc,WAAW,EAAE,SAAoB;AAAA,MACpD,aAAaA,GAAE,SAAS,aAAa;AAAA,MACrC,WAAWA,GAAE,SAAS,WAAW;AAAA,MACjC,SAASA,GAAE,SAAS,OAAO;AAAA,MAC3B,SAASA,GAAE,IAAA,EAAM,KAAA;AAAA,MACjB,SAASA,GAAE,IAAA,EAAM,KAAA;AAAA,IAAK;AAAA,EACxB,CACD;AAID,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAS,MAAM,OAAO,SAAS;AACzE,YAAU,MAAM;AACd,UAAM,UAAU,MAAM,iBAAiB,IAAI;AAC3C,UAAM,SAAS,MAAM,iBAAiB,KAAK;AAC3C,WAAO,GAAG,SAAS,OAAO;AAC1B,WAAO,GAAG,QAAQ,MAAM;AACxB,WAAO,MAAM;AACX,aAAO,IAAI,SAAS,OAAO;AAC3B,aAAO,IAAI,QAAQ,MAAM;AAAA,IAC3B;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,eAAe,OAAyB,IAAI;AAClD,QAAM,QAAQ,MAAM,OAAO,MAAA,EAAQ,MAAA;AAGnC,QAAM,CAAC,WAAW,YAAY,IAAI;AAAA,IAChC;AAAA,EAAA;AAEF,QAAM,iBAAiB,YAAY,MAAM,aAAa,IAAI,GAAG,CAAA,CAAE;AAE/D,YAAU,MAAM;AACd,UAAM,MAAM,OAAO,KAAK;AACxB,UAAM,gBAAgB,CAACA,OAAkB;AACvC,YAAM,SAAS,OAAO,KAAK,YAAY;AAAA,QACrC,MAAMA,GAAE;AAAA,QACR,KAAKA,GAAE;AAAA,MAAA,CACR;AACD,UAAI,CAAC,OAAQ;AACb,YAAM,OAAO,OAAO,MAAM,IAAI,QAAQ,OAAO,GAAG;AAChD,UAAI,UAAU;AACd,eAAS,IAAI,KAAK,OAAO,IAAI,GAAG,KAAK;AACnC,YAAI,KAAK,KAAK,CAAC,EAAE,KAAK,SAAS,SAAS;AACtC,oBAAU;AACV;AAAA,QACF;AAAA,MACF;AACA,UAAI,CAAC,QAAS;AACd,MAAAA,GAAE,eAAA;AAEF,0CAAoC,QAAQ,OAAO,GAAG;AACtD,mBAAa,EAAE,GAAGA,GAAE,SAAS,GAAGA,GAAE,SAAS;AAAA,IAC7C;AACA,QAAI,iBAAiB,eAAe,aAAa;AACjD,WAAO,MAAM,IAAI,oBAAoB,eAAe,aAAa;AAAA,EACnE,GAAG,CAAC,MAAM,CAAC;AAEX,YAAU,MAAM;AACd,QAAI,CAAC,UAAW;AAChB,UAAM,QAAQ,CAACA,OAAqB;AAClC,UAAIA,GAAE,QAAQ,SAAU,gBAAA;AAAA,IAC1B;AACA,aAAS,iBAAiB,aAAa,cAAc;AACrD,aAAS,iBAAiB,WAAW,OAAO,IAAI;AAChD,WAAO,MAAM;AACX,eAAS,oBAAoB,aAAa,cAAc;AACxD,eAAS,oBAAoB,WAAW,OAAO,IAAI;AAAA,IACrD;AAAA,EACF,GAAG,CAAC,WAAW,cAAc,CAAC;AAE9B,QAAM,WAAW;AAAA,IACf,CAAC,OAAmB;AAClB,SAAA;AACA,qBAAA;AAAA,IACF;AAAA,IACA,CAAC,cAAc;AAAA,EAAA;AAGjB,QAAM,WAAW,YAAY,sBAAsB,OAAO,KAAK,IAAI;AACnE,QAAM,aAAY,qCAAU,aAAY;AACxC,QAAM,aAAY,qCAAU,aAAY;AACxC,QAAM,cAAa,qCAAU,gBAAe;AAC5C,QAAM,sBAAsB,CAAC,EAAC,qCAAU;AACxC,QAAM,mBAAmB,CAAC,EAAC,qCAAU;AACrC,QAAM,sBACJ,CAAC,EAAC,qCAAU,kBAAiB,EAAC,qCAAU;AAG1C,QAAM,kBAAkB,MAAA;;AAAM,8BAAa,YAAb,mBAAsB;AAAA;AACpD,QAAM,oBAAoB,OAAOA,OAA2C;;AAC1E,UAAM,QAAO,KAAAA,GAAE,OAAO,UAAT,mBAAiB;AAC9B,IAAAA,GAAE,OAAO,QAAQ;AACjB,QAAI,CAAC,QAAQ,CAAC,cAAe;AAC7B,QAAI;AACF,YAAM,MAAM,MAAM,cAAc,IAAI;AACpC,UAAI,CAAC,IAAK,OAAM,IAAI,MAAM,WAAW;AACrC,YAAA,EAAQ,SAAS,EAAE,KAAK,IAAA,CAAK,EAAE,IAAA;AAAA,IACjC,SAAS,KAAK;AACZ,cAAQ,MAAM,wBAAwB,GAAG;AACzC,yCAAU,KAAK;AAAA,IACjB;AAAA,EACF;AAGA,QAAM,iBAAiB,OAAyB,IAAI;AACpD,QAAM,CAAC,WAAW,YAAY,IAAI;AAAA,IAChC;AAAA,EAAA;AAEF,QAAM,iBAAiB,OAA+B,IAAI;AAG1D,YAAU,MAAM,MAAA;;AAAM,gCAAe,YAAf,mBAAwB;AAAA,KAAS,CAAA,CAAE;AAEzD,QAAM,qBAAqB,OAAOA,OAA2C;;AAC3E,UAAM,QAAO,KAAAA,GAAE,OAAO,UAAT,mBAAiB;AAC9B,IAAAA,GAAE,OAAO,QAAQ;AACjB,QAAI,CAAC,KAAM;AAEX,QAAI,WAAW,KAAK,KAAK,IAAI,GAAG;AAC9B,UAAI;AACF,uBAAe,QAAQ,MAAM,KAAK,KAAA,CAAM;AAAA,MAC1C,SAAS,KAAK;AACZ,gBAAQ,MAAM,2BAA2B,GAAG;AAC5C,2CAAU,KAAK;AAAA,MACjB;AACA;AAAA,IACF;AAEA,QAAI,CAAC,kBAAkB;AACrB,yCAAU,IAAI,MAAM,qBAAqB,KAAK,IAAI,EAAE,GAAG;AACvD;AAAA,IACF;AAEA,UAAM,OAAO,IAAI,gBAAA;AACjB,mBAAe,UAAU;AACzB,iBAAa,EAAE,OAAO,UAAU,OAAO,GAAG;AAC1C,UAAM,UAAU,CAAC,MACf,EAAE,UAAU,YACR,EAAE,2BACF,EAAE,wBAAwB,KAAK,OAAO,EAAE,SAAS,KAAK,GAAG,CAAC;AAChE,WAAO,SAAS,wBAAwB,QAAQ,EAAE,OAAO,UAAU,OAAO,EAAA,CAAG,CAAC;AAC9E,QAAI;AACF,YAAM,MAAM,MAAM,iBAAiB,MAAM;AAAA,QACvC,QAAQ,KAAK;AAAA,QACb,YAAY,CAAC,MAAM;AACjB,cAAI,KAAK,OAAO,QAAS;AACzB,uBAAa,CAAC;AACd,iBAAO,SAAS,wBAAwB,QAAQ,CAAC,CAAC;AAAA,QACpD;AAAA,MAAA,CACD;AACD,aAAO,SAAS,wBAAA;AAChB,YAAM,KAAK,OAAO,QAAQ,WAAW,MAAM,IAAI;AAC/C,YAAM,UAAU,OAAO,QAAQ,WAAW,CAAA,IAAK,IAAI,WAAW,CAAA;AAC9D,qBAAe,QAAQ,IAAI,OAAO;AAAA,IACpC,SAAS,KAAK;AACZ,aAAO,SAAS,wBAAA;AAEhB,UAAI,CAAC,KAAK,OAAO,SAAS;AACxB,gBAAQ,MAAM,2BAA2B,GAAG;AAC5C,2CAAU,KAAK;AAAA,MACjB;AAAA,IACF,UAAA;AACE,UAAI,eAAe,YAAY,KAAM,gBAAe,UAAU;AAC9D,mBAAa,IAAI;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,cAAc,uBAAuB;AAAA,IACzC,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AAED,QAAM,aAAa,CAAC,WAAmB;AACrC,UAAMS,SAAQ,eAAe;AAC7B,QAAI,CAACA,OAAO;AACZ,IAAAA,OAAM,SAAS;AACf,IAAAA,OAAM,QAAQ;AACd,IAAAA,OAAM,MAAA;AAAA,EACR;AAGA,QAAM,cAAc,YAAY,EAAE,qBAAqB,EAAE;AAEzD,QAAM,iBAAiB,CAAC,UAAyB;AAC/C,QAAI,MAAO,OAAA,EAAQ,SAAS,KAAK,EAAE,IAAA;AAAA,QAC9B,OAAA,EAAQ,WAAA,EAAa,IAAA;AAAA,EAC5B;AACA,QAAM,iBAAiB,CAAC,UAAyB;AAC/C,QAAI,eAAe,aAAa,EAAE,MAAA,CAAO,EAAE,IAAA;AAAA,QACtC,OAAA,EAAQ,eAAA,EAAiB,IAAA;AAAA,EAChC;AAEA,QAAM,aAAa,MAAM;AACvB,QAAI,MAAM,MAAM;AACd,YAAA,EAAQ,UAAA,EAAY,IAAA;AACpB;AAAA,IACF;AACA,UAAM,MAAM,OAAO,OAAO,EAAE,UAAU;AACtC,QAAI,aAAa,QAAQ,EAAE,MAAM,IAAA,CAAK,EAAE,IAAA;AAAA,EAC1C;AAEA,QAAM,gBAAgB,CAAC,UAAkB;AACvC,QAAI,UAAU,EAAG,OAAA,EAAQ,aAAA,EAAe,IAAA;AAAA;AAEtC,YAAA,EACG,cAAc,EAAE,MAAA,CAAuC,EACvD,IAAA;AAAA,EACP;AAEA,QAAM,gBAAgB,CAAC,SAAiB;AACtC,QAAI,KAAM,OAAA,EAAQ,YAAY,IAAI,EAAE,IAAA;AAAA,QAC/B,OAAA,EAAQ,cAAA,EAAgB,IAAA;AAAA,EAC/B;AACA,QAAM,kBAAkB,iBAAiB,MAAM;AAE/C,QAAM,CAAC,UAAU,WAAW,IAAI,SAMtB,IAAI;AAEd,YAAU,MAAM,mBAAmB,CAAC,YAAY;AAC9C,gBAAY;AAAA,MACV,MAAM,QAAQ;AAAA,MACd,MAAM;AAAA,MACN,KAAK,QAAQ;AAAA,MACb,OAAO,QAAQ;AAAA,IAAA,CAChB;AAAA,EACH,CAAC,GAAG,CAAA,CAAE;AAEN,QAAM,iBAAiB,CAAC,SAAmB;AACzC,UAAM,EAAE,MAAM,GAAA,IAAO,OAAO,MAAM;AAClC,UAAM,WACJ,SAAS,KAAK,KAAK,OAAO,MAAM,IAAI,YAAY,MAAM,IAAI,GAAG;AAC/D,UAAM,OAAO,SAAS,WAAW,eAAe;AAChD,UAAM,aAAa;AACnB,UAAA,EAAQ,cAAc,EAAE,MAAM,OAAO,EAAE,OAAO,SAAA,GAAY,EAAE,IAAA;AAC5D,QAAI,MAAqB;AACzB,WAAO,MAAM,IAAI;AAAA,MACf;AAAA,MACA,OAAO,MAAM,IAAI,QAAQ;AAAA,MACzB,CAAC,MAAM,YAAY;AACjB,YAAI,OAAO,KAAM,QAAO;AACxB,YACE,KAAK,KAAK,SAAS,QACnB,OAAO,KAAK,MAAM,SAAS,EAAE,MAAM,UACnC;AACA,gBAAM;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IAAA;AAEF,QAAI,OAAO,MAAM;AACf,kBAAY,EAAE,MAAM,MAAM,UAAU,OAAO,UAAU,OAAO,MAAM;AAClE;AAAA,IACF;AACA,gBAAY;AAAA,MACV;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,OAAO;AAAA,MACP,OAAO;AAAA,IAAA,CACR;AAAA,EACH;AAEA,QAAM,YAAY,CAAC,UAAkB;AACnC,QAAI,CAAC,SAAU;AACf,UAAM,EAAE,MAAM,MAAM,IAAA,IAAQ;AAC5B,gBAAY,IAAI;AAChB,QAAI,SAAS,UAAU,OAAO,MAAM;AAClC,UAAI,SAAS,UAAU;AACrB,cAAA,EAAQ,iBAAiB,EAAE,OAAO,IAAA,CAAK,EAAE,IAAA;AAAA,MAC3C,OAAO;AACL,cAAA,EAAQ,gBAAgB,EAAE,OAAO,IAAA,CAAK,EAAE,IAAA;AAAA,MAC1C;AACA;AAAA,IACF;AACA,QAAI,SAAS,UAAU;AACrB,YAAA,EAAQ,cAAc,EAAE,MAAM,cAAc,OAAO,EAAE,MAAA,GAAS,EAAE,IAAA;AAAA,IAClE,OAAO;AACL,YAAA,EAAQ,cAAc,EAAE,MAAM,aAAa,OAAO,EAAE,MAAA,GAAS,EAAE,IAAA;AAAA,IACjE;AAAA,EACF;AAEA,QAAM,aAAa,MAAM;AACvB,QAAI,CAAC,SAAU;AACf,UAAM,EAAE,OAAO,IAAA,IAAQ;AACvB,QAAI,SAAS,OAAO,MAAM;AACxB,YAAM,OAAO,OAAO,MAAM,IAAI,OAAO,GAAG;AACxC,UACE,SACC,KAAK,KAAK,SAAS,gBAAgB,KAAK,KAAK,SAAS,cACvD;AACA,eACG,MAAA,EACA,MAAA,EACA,YAAY,EAAE,MAAM,KAAK,IAAI,MAAM,KAAK,SAAA,CAAU,EAClD,IAAA;AAAA,MACL;AAAA,IACF;AACA,gBAAY,IAAI;AAAA,EAClB;AAEA,QAAM,eAAe,MAAM,cACvB,gBACA,MAAM,YACJ,cACA;AAEN,SACE,qBAAAO,YAAA,EACE,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WACE,YAAY,GAAGX,SAAO,OAAO,IAAI,SAAS,KAAKA,SAAO;AAAA,QAGxD,UAAA,qBAAC,OAAA,EAAI,WAAWA,SAAO,OAErB,UAAA;AAAA,UAAA;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,UAAU,CAAC,MAAM;AAAA,cACjB,SAAS,MAAM,MAAA,EAAQ,KAAA,EAAO,IAAA;AAAA,cAE9B,8BAAC,UAAA,CAAA,CAAS;AAAA,YAAA;AAAA,UAAA;AAAA,UAEZ;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,UAAU,CAAC,MAAM;AAAA,cACjB,SAAS,MAAM,MAAA,EAAQ,KAAA,EAAO,IAAA;AAAA,cAE9B,8BAAC,UAAA,CAAA,CAAS;AAAA,YAAA;AAAA,UAAA;AAAA,8BAGX,SAAA,EAAQ;AAAA,UAGT;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,SACE;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,WAAWA,SAAO;AAAA,kBAClB,OAAO,EAAE;AAAA,kBACT,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,kBAEtB,UAAA;AAAA,oBAAA,oBAAC,QAAA,EAAK,WAAWK,SAAO,mBAAoB,YAAE,OAAM;AAAA,wCACnD,iBAAA,EAAgB,MAAM,IAAI,WAAWA,SAAO,kBAAA,CAAmB;AAAA,kBAAA;AAAA,gBAAA;AAAA,cAAA;AAAA,cAIpE,UAAA;AAAA,gBAAA;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,WAAW,MAAM,gBAAgB,OAAO;AAAA,oBACxC,UAAU,MAAM,cAAc,CAAC;AAAA,oBAE/B,UAAA,qBAAC,QAAA,EAAK,WAAWA,SAAO,WACtB,UAAA;AAAA,sBAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,WAAW,UAAA,KAAC;AAAA,sBACnC,EAAE;AAAA,oBAAA,EAAA,CACL;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAED,eAAe,IAAI,CAAC,OACnB;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBAEC,UAAU,MAAM,iBAAiB;AAAA,oBACjC,UAAU,MAAM,cAAc,EAAE;AAAA,oBAEhC,UAAA,qBAAC,QAAA,EAAK,WAAWA,SAAO,WACtB,UAAA;AAAA,sBAAA,oBAAC,UAAK,WAAWA,SAAO,WAAY,UAAA,IAAI,EAAE,IAAG;AAAA,sBAC5C,EAAE,aAAa,EAAE;AAAA,oBAAA,EAAA,CACpB;AAAA,kBAAA;AAAA,kBAPK;AAAA,gBAAA,CASR;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAIH;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,SACE;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,WAAWA,SAAO;AAAA,kBAClB,OAAO,EAAE;AAAA,kBACT,cAAY,EAAE;AAAA,kBACd,UAAU,CAAC;AAAA,kBACX,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,kBAEtB,UAAA;AAAA,oBAAA,oBAAC,UAAK,WAAWK,SAAO,mBACrB,UAAA,MAAM,YAAY,EAAE,SAAA,CACvB;AAAA,wCACC,iBAAA,EAAgB,MAAM,IAAI,WAAWA,SAAO,kBAAA,CAAmB;AAAA,kBAAA;AAAA,gBAAA;AAAA,cAAA;AAAA,cAIpE,UAAA;AAAA,gBAAA;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,UAAU,CAAC,MAAM;AAAA,oBACjB,UAAU,MAAM,cAAc,EAAE;AAAA,oBAEhC,UAAA,qBAAC,QAAA,EAAK,WAAWA,SAAO,WACtB,UAAA;AAAA,sBAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,WAAW,UAAA,KAAC;AAAA,sBACnC,EAAE;AAAA,oBAAA,EAAA,CACL;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAED,WAAW,IAAI,CAAC,SACf;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBAEC,UAAU,MAAM,aAAa;AAAA,oBAC7B,UAAU,MAAM,cAAc,IAAI;AAAA,oBAElC,UAAA,qBAAC,QAAA,EAAK,WAAWA,SAAO,WACtB,UAAA;AAAA,sBAAA,oBAAC,UAAK,WAAWA,SAAO,WAAY,UAAA,SAAS,MAAM,EAAE,GAAE;AAAA,sBACtD;AAAA,oBAAA,EAAA,CACH;AAAA,kBAAA;AAAA,kBAPK;AAAA,gBAAA,CASR;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,8BAGF,SAAA,EAAQ;AAAA,UAGT;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,QAAQ,MAAM;AAAA,cACd,SAAS,MAAM,MAAA,EAAQ,WAAA,EAAa,IAAA;AAAA,cAEpC,8BAAC,UAAA,CAAA,CAAS;AAAA,YAAA;AAAA,UAAA;AAAA,UAEZ;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,QAAQ,MAAM;AAAA,cACd,SAAS,MAAM,MAAA,EAAQ,aAAA,EAAe,IAAA;AAAA,cAEtC,8BAAC,YAAA,CAAA,CAAW;AAAA,YAAA;AAAA,UAAA;AAAA,UAEd;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,QAAQ,MAAM;AAAA,cACd,SAAS,MAAM,MAAA,EAAQ,gBAAA,EAAkB,IAAA;AAAA,cAEzC,8BAAC,eAAA,CAAA,CAAc;AAAA,YAAA;AAAA,UAAA;AAAA,UAEjB;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,QAAQ,MAAM;AAAA,cACd,SAAS,MAAM,MAAA,EAAQ,aAAA,EAAe,IAAA;AAAA,cAEtC,8BAAC,mBAAA,CAAA,CAAkB;AAAA,YAAA;AAAA,UAAA;AAAA,UAErB;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,QAAQ,MAAM;AAAA,cACd,SAAS,MAAM,MAAA,EAAQ,WAAA,EAAa,IAAA;AAAA,cAEpC,8BAAC,UAAA,CAAA,CAAS;AAAA,YAAA;AAAA,UAAA;AAAA,UAIZ;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,OAAM;AAAA,cACN,KAAK,MAAM,aAAa;AAAA,cACxB,OAAO,MAAM;AAAA,cACb,QAAQ;AAAA,cACR,eAAe,EAAE,MAAM,EAAE,WAAW,OAAO,EAAE,WAAA;AAAA,YAAW;AAAA,UAAA;AAAA,UAG1D;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,OAAM;AAAA,cACN,KAAK,MAAM,kBAAkB;AAAA,cAC7B,OAAO,MAAM;AAAA,cACb,QAAQ;AAAA,cACR,eAAe,EAAE,MAAM,EAAE,WAAW,OAAO,EAAE,WAAA;AAAA,YAAW;AAAA,UAAA;AAAA,UAI1D;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,SACE;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,WAAW,GAAGA,SAAO,aAAa,IAChC,iBAAiB,WAAWA,SAAO,YAAY,EACjD;AAAA,kBACA,OAAO,EAAE;AAAA,kBACT,cAAY,EAAE;AAAA,kBACd,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,kBAEtB,UAAA;AAAA,oBAAA,oBAAC,QAAA,EAAK,WAAWK,SAAO,oBAAoB,UAAA,KAAC;AAAA,wCAC5C,iBAAA,EAAgB,MAAM,IAAI,WAAWA,SAAO,kBAAA,CAAmB;AAAA,kBAAA;AAAA,gBAAA;AAAA,cAAA;AAAA,cAIpE,UAAA;AAAA,gBAAA;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,UAAU,iBAAiB;AAAA,oBAC3B,UAAU,MAAM,MAAA,EAAQ,mBAAmB,eAAA,EAAiB,IAAA;AAAA,oBAE5D,UAAA,qBAAC,QAAA,EAAK,WAAWA,SAAO,WACtB,UAAA;AAAA,sBAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,WAAW,UAAA,KAAC;AAAA,sBACnC,EAAE;AAAA,oBAAA,EAAA,CACL;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAEF;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,UAAU,iBAAiB;AAAA,oBAC3B,UAAU,MAAM,MAAA,EAAQ,iBAAiB,kBAAA,EAAoB,IAAA;AAAA,oBAE7D,UAAA,qBAAC,QAAA,EAAK,WAAWA,SAAO,WACtB,UAAA;AAAA,sBAAA,qBAAC,QAAA,EAAK,WAAW,GAAGA,SAAO,SAAS,IAAIA,SAAO,WAAW,IAAI,UAAA;AAAA,wBAAA;AAAA,wBAC3D,oBAAC,SAAI,UAAA,IAAA,CAAC;AAAA,sBAAA,GACT;AAAA,sBACC,EAAE;AAAA,oBAAA,EAAA,CACL;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAEF;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,UAAU,iBAAiB;AAAA,oBAC3B,UAAU,MAAM,MAAA,EAAQ,mBAAmB,gBAAA,EAAkB,IAAA;AAAA,oBAE7D,UAAA,qBAAC,QAAA,EAAK,WAAWA,SAAO,WACtB,UAAA;AAAA,sBAAA,qBAAC,QAAA,EAAK,WAAW,GAAGA,SAAO,SAAS,IAAIA,SAAO,WAAW,IAAI,UAAA;AAAA,wBAAA;AAAA,wBAC3D,oBAAC,SAAI,UAAA,IAAA,CAAC;AAAA,sBAAA,GACT;AAAA,sBACC,EAAE;AAAA,oBAAA,EAAA,CACL;AAAA,kBAAA;AAAA,gBAAA;AAAA,cACF;AAAA,YAAA;AAAA,UAAA;AAAA,8BAGD,SAAA,EAAQ;AAAA,UAGT,oBAAC,eAAA,EAAc,OAAO,EAAE,MAAM,QAAQ,MAAM,MAAM,SAAS,YACzD,UAAA,oBAAC,UAAA,CAAA,CAAS,GACZ;AAAA,UACC,gBACC,qBAAAW,YAAA,EACE,UAAA;AAAA,YAAA,oBAAC,eAAA,EAAc,OAAO,EAAE,OAAO,SAAS,iBACtC,UAAA,oBAAC,aAAU,EAAA,CACb;AAAA,YACA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,KAAK;AAAA,gBACL,MAAK;AAAA,gBACL,QAAO;AAAA,gBACP,QAAM;AAAA,gBACN,UAAU;AAAA,cAAA;AAAA,YAAA;AAAA,UACZ,EAAA,CACF,IACE;AAAA,UACH,aACC;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,SACE;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,WAAWX,SAAO;AAAA,kBAClB,OAAO;AAAA,kBACP,cAAY;AAAA,kBACZ,aAAW,CAAC,CAAC;AAAA,kBACb,UAAU,CAAC,CAAC;AAAA,kBACZ,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,kBAEtB,UAAA;AAAA,oBAAA,oBAAC,QAAA,EAAK,WAAWK,SAAO,mBACrB,YAAE,gBACL;AAAA,oBACA;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBACC,MAAM;AAAA,wBACN,WAAWA,SAAO;AAAA,sBAAA;AAAA,oBAAA;AAAA,kBACpB;AAAA,gBAAA;AAAA,cAAA;AAAA,cAIH,UAAA,YAAY,IAAI,CAACY,UAChB;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBAEC,UAAU,MAAM,WAAWA,MAAK,MAAM;AAAA,kBAErC,UAAAA,MAAK;AAAA,gBAAA;AAAA,gBAHDA,MAAK;AAAA,cAAA,CAKb;AAAA,YAAA;AAAA,UAAA,IAED;AAAA,UACJ;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,QAAQ,MAAM;AAAA,cACd,SAAS,MAAM,MAAA,EAAQ,iBAAA,EAAmB,IAAA;AAAA,cAE1C,UAAA,oBAAC,QAAA,EAAK,WAAWZ,SAAO,SAAS,UAAA,IAAA,CAAC;AAAA,YAAA;AAAA,UAAA;AAAA,8BAGnC,SAAA,EAAQ;AAAA,UAGT;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,QAAQ,MAAM;AAAA,cACd,SAAS,MAAM,MAAA,EAAQ,iBAAA,EAAmB,IAAA;AAAA,cAE1C,8BAAC,mBAAA,CAAA,CAAkB;AAAA,YAAA;AAAA,UAAA;AAAA,UAErB;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,QAAQ,MAAM;AAAA,cACd,SAAS,MAAM,MAAA,EAAQ,kBAAA,EAAoB,IAAA;AAAA,cAE3C,8BAAC,iBAAA,CAAA,CAAgB;AAAA,YAAA;AAAA,UAAA;AAAA,UAEnB;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,OAAO,EAAE;AAAA,cACT,QAAQ,MAAM;AAAA,cACd,SAAS,MAAM,MAAA,EAAQ,eAAA,EAAiB,IAAA;AAAA,cAExC,8BAAC,gBAAA,CAAA,CAAe;AAAA,YAAA;AAAA,UAAA;AAAA,8BAGjB,SAAA,EAAQ;AAAA,UAGT;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,SACE;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,WAAWA,SAAO;AAAA,kBAClB,OAAO,EAAE;AAAA,kBACT,aAAa,CAACL,OAAMA,GAAE,eAAA;AAAA,kBAEtB,UAAA;AAAA,oBAAA,oBAAC,QAAA,EAAK,WAAWK,SAAO,mBAAoB,YAAE,MAAK;AAAA,wCAClD,iBAAA,EAAgB,MAAM,IAAI,WAAWA,SAAO,kBAAA,CAAmB;AAAA,kBAAA;AAAA,gBAAA;AAAA,cAAA;AAAA,cAIpE,UAAA;AAAA,gBAAA,oBAAC,UAAA,EAAS,UAAU,MAAM,MAAA,EAAQ,kBAAkB,IAAA,GAClD,UAAA,qBAAC,QAAA,EAAK,WAAWA,SAAO,WACtB,UAAA;AAAA,kBAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,WAAY,UAAA,OAAM;AAAA,kBACzC,EAAE;AAAA,gBAAA,EAAA,CACL,EAAA,CACF;AAAA,gBACA,oBAAC,UAAA,EAAS,UAAU,MAAM,eAAe,QAAQ,GAC/C,UAAA,qBAAC,QAAA,EAAK,WAAWA,SAAO,WACtB,UAAA;AAAA,kBAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,WAAW,UAAA,MAAE;AAAA,kBACpC,EAAE;AAAA,gBAAA,EAAA,CACL,EAAA,CACF;AAAA,gBACA,oBAAC,UAAA,EAAS,UAAU,MAAM,eAAe,OAAO,GAC9C,UAAA,qBAAC,QAAA,EAAK,WAAWA,SAAO,WACtB,UAAA;AAAA,kBAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,WAAW,UAAA,KAAC;AAAA,kBACnC,EAAE;AAAA,gBAAA,EAAA,CACL,EAAA,CACF;AAAA,gBACA,oBAAC,UAAA,EAAS,UAAU,MAAM,QAAQ,oBAAoB,IAAA,GACpD,UAAA,qBAAC,QAAA,EAAK,WAAWA,SAAO,WACtB,UAAA;AAAA,kBAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,WAAW,UAAA,KAAC;AAAA,kBACnC,EAAE;AAAA,gBAAA,EAAA,CACL,EAAA,CACF;AAAA,gBACA;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,UAAU,MAAM;AAAA,oBAChB,QAAQ;AAAA,oBACR,UAAU,CAAC,MAAM,SACf,QACG,YAAY,EAAE,MAAM,MAAM,eAAe,KAAA,CAAM,EAC/C,IAAA;AAAA,kBAAI;AAAA,gBAAA;AAAA,gBAGV,uDAAmB,IAAI,CAACY,UACvB;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBAEC,UAAUA,MAAK;AAAA,oBACf,UAAU,MAAMA,MAAK,SAAS,MAAM;AAAA,oBAEpC,UAAA,qBAAC,QAAA,EAAK,WAAWZ,SAAO,WACtB,UAAA;AAAA,sBAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,WAAY,gBAAK,MAAK;AAAA,sBAC7CY,MAAK;AAAA,oBAAA,EAAA,CACR;AAAA,kBAAA;AAAA,kBAPKA,MAAK;AAAA,gBAAA;AAAA,cASb;AAAA,YAAA;AAAA,UAAA;AAAA,QACH,EAAA,CACF;AAAA,MAAA;AAAA,IAAA;AAAA,IAID,aACC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL,QAAM;AAAA,QACN,UAAU;AAAA,MAAA;AAAA,IAAA,IAEV;AAAA,IAEH,WACC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC;AAAA,QACA,MAAM,SAAS;AAAA,QACf,MAAM,SAAS;AAAA,QACf,KAAK,SAAS;AAAA,QACd,OAAO,SAAS;AAAA,QAChB,OAAO,SAAS;AAAA,QAChB,UACE,SAAS,SAAS,WAAW,EAAE,gBAAgB,EAAE;AAAA,QAEnD,aAAa,EAAE;AAAA,QACf,WAAW,EAAE;AAAA,QACb,WAAW;AAAA,QACX,UAAU;AAAA,MAAA;AAAA,IAAA,IAEV;AAAA,IAGH,aACC;AAAA,MACE;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAWZ,SAAO;AAAA,UAClB,OAAO,EAAE,UAAU,SAAS,MAAM,UAAU,GAAG,KAAK,UAAU,EAAA;AAAA,UAC9D,MAAK;AAAA,UACL,aAAa,CAACL,OAAMA,GAAE,gBAAA;AAAA,UACtB,eAAe,CAACA,OAAMA,GAAE,eAAA;AAAA,UAExB,UAAA;AAAA,YAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,OACE,aACI,EAAE,sBAAsB,SAAS,IACjC,EAAE;AAAA,gBAER,SAAS,MACP,SAAS,MAAM,iBAAiB,QAAQ,SAAS,CAAC;AAAA,gBAGpD,8BAAC,kBAAA,CAAA,CAAiB;AAAA,cAAA;AAAA,YAAA;AAAA,YAEpB;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,OACE,aACI,EAAE,qBAAqB,SAAS,IAChC,EAAE;AAAA,gBAER,SAAS,MACP,SAAS,MAAM,gBAAgB,QAAQ,SAAS,CAAC;AAAA,gBAGnD,8BAAC,iBAAA,CAAA,CAAgB;AAAA,cAAA;AAAA,YAAA;AAAA,YAEnB;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,OACE,aACI,EAAE,mBAAmB,SAAS,IAC9B,EAAE;AAAA,gBAER,UAAU;AAAA,gBACV,SAAS,MACP,SAAS,MAAM;AACb,wCAAsB,MAAM;AAAA,gBAC9B,CAAC;AAAA,gBAGH,8BAAC,kBAAA,CAAA,CAAiB;AAAA,cAAA;AAAA,YAAA;AAAA,gCAEnB,kBAAA,EAAiB;AAAA,YAClB;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,OACE,aACI,EAAE,mBAAmB,SAAS,IAC9B,EAAE;AAAA,gBAER,UAAU;AAAA,gBACV,SAAS,MACP,SAAS,MAAM,cAAc,QAAQ,SAAS,CAAC;AAAA,gBAGjD,8BAAC,eAAA,CAAA,CAAc;AAAA,cAAA;AAAA,YAAA;AAAA,YAEjB;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,OACE,aAAa,EAAE,kBAAkB,SAAS,IAAI,EAAE;AAAA,gBAElD,SAAS,MAAM,SAAS,MAAM,aAAa,QAAQ,SAAS,CAAC;AAAA,gBAE7D,8BAAC,cAAA,CAAA,CAAa;AAAA,cAAA;AAAA,YAAA;AAAA,YAEhB;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,OACE,aAAa,EAAE,gBAAgB,SAAS,IAAI,EAAE;AAAA,gBAEhD,UAAU;AAAA,gBACV,SAAS,MACP,SAAS,MAAM;AACb,qCAAmB,MAAM;AAAA,gBAC3B,CAAC;AAAA,gBAGH,8BAAC,eAAA,CAAA,CAAc;AAAA,cAAA;AAAA,YAAA;AAAA,gCAEhB,kBAAA,EAAiB;AAAA,YAClB;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,OAAO,EAAE;AAAA,gBACT,SAAS,MACP,SAAS,MAAM;AACb,yBAAO,SAAS,YAAA;AAAA,gBAClB,CAAC;AAAA,gBAGH,8BAAC,iBAAA,CAAA,CAAgB;AAAA,cAAA;AAAA,YAAA;AAAA,UACnB;AAAA,QAAA;AAAA,MAAA;AAAA,MAEF,SAAS;AAAA,IAAA;AAAA,EACX,GACJ;AAEJ;ACpuCO,SAAS,YAAY,aAAa,KAAc;AACrD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAE9C,YAAU,MAAM;AACd,UAAM,KAAK,OAAO,WAAW,eAAe,aAAa,CAAC,KAAK;AAC/D,UAAM,SAAS,MAAM,YAAY,GAAG,OAAO;AAC3C,WAAA;AACA,OAAG,iBAAiB,UAAU,MAAM;AACpC,WAAO,MAAM,GAAG,oBAAoB,UAAU,MAAM;AAAA,EACtD,GAAG,CAAC,UAAU,CAAC;AAEf,SAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACSO,SAAS,SAAS,EAAE,OAAO,UAAU,aAAa,UAAyB;AAChF,QAAM,IAAI,EAAE,GAAG,kBAAkB,GAAG,OAAA;AACpC,QAAM,WAAW,YAAA;AAEjB,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAChD,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAElD,QAAM,gBAAgB,OAAoB,IAAI;AAC9C,QAAM,iBAAiB,OAAuB,IAAI;AAGlD,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AACf,UAAM,SAAS,OAAO;AAAA,MACpB;AAAA,IAAA,EACA;AACF,UAAM,YAAY,cAAc,WAAW,eAAe;AAC1D,QAAI,CAAC,UAAW;AAChB,UAAM,KAAK,UAAU,cAAc,YAAY,IAAI,OAAO,QAAQ,CAAC,IAAI;AACvE,QAAI,CAAC,GAAI;AACT,OAAG,eAAe;AAAA,MAChB,OAAO;AAAA,MACP,UAAU,SAAS,SAAS;AAAA,IAAA,CAC7B;AAAA,EACH,GAAG,CAAC,QAAQ,CAAC;AAEb,MAAI,CAAC,MAAM,OAAQ,QAAO;AAE1B,QAAM,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC;AAEtD,QAAM,cAAc,CAACiB,UAAkB;AACrC,QAAIA,MAAK,OAAQ;AACjB,+CAAcA;AACd,QAAI,wBAAwB,KAAK;AAAA,EACnC;AAEA,QAAMC,QACJ,oBAAC,MAAA,EAAG,WAAWb,SAAO,MACnB,UAAA,MAAM,IAAI,CAACY,UACV,oBAAC,MAAA,EACC,UAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAMA,MAAK,SAAS,SAAY,IAAIA,MAAK,EAAE;AAAA,MAC3C,WAAW,GAAGZ,SAAO,IAAI,IACvBY,MAAK,OAAO,WAAWZ,SAAO,SAAS,EACzC,IAAIY,MAAK,SAASZ,SAAO,SAAS,EAAE;AAAA,MACpC,OAAO,EAAE,aAAa,IAAIY,MAAK,QAAQ,YAAY,KAAK,EAAE,KAAA;AAAA,MAC1D,gBAAcA,MAAK,OAAO,WAAW,SAAS;AAAA,MAC9C,iBAAeA,MAAK,SAAS,SAAS;AAAA,MACtC,SAAS,CAACjB,OAAM;AACd,QAAAA,GAAE,eAAA;AACF,oBAAYiB,KAAI;AAAA,MAClB;AAAA,MAEA,UAAA;AAAA,QAAA,oBAAC,QAAA,EAAK,WAAWZ,SAAO,UAAW,gBAAK,MAAK;AAAA,QAC5CY,MAAK,SACJ,oBAAC,UAAA,EAAS,WAAWZ,SAAO,UAAU,eAAW,KAAA,CAAC,IAChD;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA,EACN,GAlBOY,MAAK,EAmBd,CACD,GACH;AAIF,MAAI,UAAU;AACZ,gCACG,OAAA,EAAI,WAAWZ,SAAO,QAAQ,cAAY,EAAE,OAC3C,UAAA;AAAA,MAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAWA,SAAO;AAAA,UAClB,iBAAe;AAAA,UACf,SAAS,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;AAAA,UAEtC,UAAA;AAAA,YAAA,oBAAC,UAAA,EAAS,WAAWA,SAAO,eAAe,eAAW,MAAC;AAAA,YACvD,oBAAC,QAAA,EAAM,UAAA,EAAE,MAAA,CAAM;AAAA,YACf;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,WAAW,GAAGA,SAAO,OAAO,IAC1B,aAAaA,SAAO,YAAY,EAClC;AAAA,gBACA,eAAW;AAAA,gBAEX,UAAA,oBAAC,iBAAA,EAAgB,MAAM,GAAA,CAAI;AAAA,cAAA;AAAA,YAAA;AAAA,UAC7B;AAAA,QAAA;AAAA,MAAA;AAAA,MAEF;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,KAAK;AAAA,UACL,WAAW,GAAGA,SAAO,WAAW,IAC9B,aAAaA,SAAO,kBAAkB,EACxC;AAAA,UAEC,UAAAa;AAAA,QAAA;AAAA,MAAA;AAAA,IACH,GACF;AAAA,EAEJ;AAGA,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAWb,SAAO;AAAA,QAClB,cAAY,EAAE;AAAA,QACd,OAAO,EAAE;AAAA,QACT,SAAS,MAAM,aAAa,KAAK;AAAA,QAEjC,8BAAC,mBAAA,CAAA,CAAkB;AAAA,MAAA;AAAA,IAAA;AAAA,EAGzB;AAEA,SACE,qBAAC,SAAI,WAAWA,SAAO,SAAS,cAAY,EAAE,OAAO,KAAK,eACxD,UAAA;AAAA,IAAA,qBAAC,OAAA,EAAI,WAAWA,SAAO,QACrB,UAAA;AAAA,MAAA,oBAAC,QAAA,EAAK,WAAWA,SAAO,aAAc,YAAE,OAAM;AAAA,MAC9C;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAWA,SAAO;AAAA,UAClB,cAAY,EAAE;AAAA,UACd,OAAO,EAAE;AAAA,UACT,SAAS,MAAM,aAAa,IAAI;AAAA,UACjC,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAED,GACF;AAAA,IACCa;AAAA,EAAA,GACH;AAEJ;;;;;;;ACpIO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,aAAa;AACf,GAAwB;AACtB,QAAM,OAAO,QAAQ,WAAW,SAAS,0BAA0B;AACnE,SACE,qBAAC,QAAQ,MAAR,EAAa,MAAY,cACvB,UAAA;AAAA,IAAA,QACC,oBAAC,QAAQ,QAAR,EAAe,SAAO,MACrB,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW,OAAO;AAAA,QAClB,OAAO,EAAE,MAAM,KAAK,MAAM,KAAK,KAAK,IAAA;AAAA,MAAI;AAAA,IAAA,GAE5C;AAAA,IAEF,oBAAC,QAAQ,QAAR,EACC,UAAA;AAAA,MAAC,QAAQ;AAAA,MAAR;AAAA,QACC,WAAW,OAAO;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,QACA,iBAAiB,CAAClB,OAAMA,GAAE,eAAA;AAAA,QAC1B,kBAAkB,CAACA,OAAMA,GAAE,eAAA;AAAA,QAE1B;AAAA,MAAA;AAAA,IAAA,EACH,CACF;AAAA,EAAA,GACF;AAEJ;ACtBA,MAAM,WAAW;AAEV,SAAS,kBACd,QACA,QACoB;AACpB,MAAI,CAAC,UAAU,CAAC,OAAO,MAAO,QAAO;AAErC,QAAM,CAAC,MAAM,IAAI,kBAAkB,OAAO,MAAM,KAAK;AAAA,IACnD,EAAE,WAAW,UAAU,UAAU,CAAC,MAAM,EAAA;AAAA,EAAE,CAC3C;AACD,QAAM,QAAQ,iCAAQ,OAAO;AAC7B,MAAI,CAAC,MAAO,QAAO;AAEnB,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,IAAI,MAAM;AAAA;AAAA,IAEV,MAAM,OAAO,MAAM,IAAI,YAAY,MAAM,MAAM,MAAM,EAAE;AAAA,IACvD,QAAQ,OAAO;AAAA,EAAA;AAEnB;ACNA,MAAM,kBAAkB;AASxB,SAAS,eAAe,QAAiC;AACvD,QAAM,SAA0B,CAAA;AAChC,SAAO,MAAM,IAAI,QAAQ,CAAC,MAAM,WAAW;AACzC,WAAO,KAAK;AAAA,MACV,MAAM,KAAK,OAAA;AAAA,MACX,MAAM;AAAA,MACN,IAAI,SAAS,KAAK;AAAA,IAAA,CACnB;AAAA,EACH,CAAC;AACD,SAAO;AACT;AAEO,SAAS,oBACd,QACA,MACA,IACA,UAAsC,CAAA,GAChB;AACtB,QAAM,UAAU,OAAO;AACvB,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,OAAO,OAAO,MAAM,IAAI,QAAQ;AACtC,MAAI,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,EAAE,CAAC;AAC1C,MAAI,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;AAC3C,MAAI,SAAS,IAAK,QAAO;AAEzB,QAAM,SAAS,eAAe,MAAM;AACpC,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,QAAM,SAAS,QAAQ,mBAAmB;AAI1C,MAAI,QAAQ;AACZ,MAAI,OAAO,OAAO,SAAS;AAC3B,MAAI,QAAQ;AACV,YAAQ,OAAO,UAAU,CAACE,OAAMA,GAAE,KAAK,KAAK;AAC5C,QAAI,QAAQ,EAAG,QAAO;AACtB,aAAS,IAAI,OAAO,SAAS,GAAG,KAAK,OAAO,KAAK,GAAG;AAClD,UAAI,OAAO,CAAC,EAAE,OAAO,KAAK;AACxB,eAAO;AACP;AAAA,MACF;AAAA,IACF;AACA,YAAQ,OAAO,KAAK,EAAE;AACtB,UAAM,OAAO,IAAI,EAAE;AAAA,EACrB;AAEA,QAAM,QAAQ,OAAO,IAAI,CAACA,OAAM,QAAQ,UAAU,EAAE,MAAM,OAAO,SAAS,CAACA,GAAE,IAAI,EAAA,CAAG,CAAC;AACrF,QAAM,OAAO,OAAO,YAAA;AAEpB,MAAI,UAAU,MAAM,KAAK,eAAe,MAAM,MAAM;AAClD,UAAMiB,YAAW,MAAM,MAAM,OAAO,OAAO,CAAC,EAAE,KAAK,eAAe;AAElE,QAAI,CAACA,UAAU,QAAO;AACtB,UAAMC,MACJ,UAAU,IACN,IACA,MAAM,MAAM,GAAG,KAAK,EAAE,KAAK,eAAe,EAAE,SAAS,gBAAgB;AAC3E,WAAO,EAAE,UAAAD,WAAU,MAAMC,KAAI,IAAIA,MAAKD,UAAS,QAAQ,SAAS,OAAO,OAAO,IAAA;AAAA,EAChF;AAGA,QAAM,WAAW,QAAQ;AAAA,IACvB,OAAO,MAAM,IAAI,IAAI,OAAO,GAAG,EAAE,OAAA;AAAA,EAAO;AAE1C,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,KAAK,KAAK,QAAQ,QAAQ;AAChC,MAAI,KAAK,KAAK,KAAK,QAAQ,UAAU,KAAK,CAAC,KAAK,EAAG,QAAO;AAC1D,SAAO,EAAE,UAAU,MAAM,IAAI,IAAI,KAAK,SAAS,QAAQ,SAAS,OAAO,OAAO,IAAA;AAChF;ACjGO,SAAS,kBAAkB,UAA0B;AAC1D,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,UAAU,WAAA;AAChB,SAAO,QAAQ,UAAU,QAAQ,MAAM,qBAAqB,QAAQ,CAAC,CAAC;AACxE;AAIA,IAAI,gBAAwC;AAE5C,SAAS,aAA8B;AACrC,oCAAkB,IAAI,gBAAgB;AAAA,IACpC,YAAY,CAAC,GAAG,gBAAgB,eAAe,WAAW,WAAW,WAAW;AAAA,EAAA,CACjF;AACD,SAAO;AACT;ACnBO,SAAS,yBACd,QACA,OACA,UACA,UAA+B,CAAA,GACtB;AACT,QAAM,WAAW;AAAA,IACf,wBAAwB,YAAY,IAAI,QAAQ,WAAW,CAAA,CAAE;AAAA,EAAA;AAE/D,MAAI,CAAC,SAAS,KAAA,EAAQ,QAAO;AAE7B,MAAI,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,MAAM,MAAM,EAAE,CAAC;AACrD,MAAI,KAAK,KAAK,IAAI,MAAM,MAAM,MAAM,EAAE;AACtC,MAAI,SAAS,GAAI,QAAO;AAGxB,MAAI,oBAAoB,QAAQ,MAAM,IAAI,QAAQ,EAAG,QAAO;AAG5D,aAAW,SAAS,oBAAoB,QAAQ,GAAG;AACjD,UAAM,SAAS,OAAO,MAAM,IAAI,QAAQ;AACxC,UAAM,UACJ,oBAAoB,QAAQ,MAAM,IAAI,KAAK,KAC3C,uBAAuB,QAAQ,MAAM,IAAI,iBAAiB,KAAK,CAAC;AAClE,QAAI,CAAC,QAAS;AAEd,UAAM,WAAW,OAAO,MAAM,IAAI,QAAQ,OAAO,UAAU,KAAK;AAChE,YAAQ;AACR,SAAK;AAAA,EACP;AACA,SAAO;AACT;AAGA,SAAS,oBACP,QACA,MACA,IACA,UACS;AACT,MAAI;AACF,WAAO,OACJ,MAAA,EACA,gBAAgB,EAAE,MAAM,MAAM,UAAU,EAAE,aAAa,WAAA,CAAY,EACnE,IAAA;AAAA,EACL,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,uBACP,QACA,MACA,IACA,MACS;AACT,MAAI;AACF,WAAO,OACJ,QACA;AAAA,MACC,EAAE,MAAM,GAAA;AAAA,MACR,EAAE,MAAM,aAAa,SAAS,OAAO,CAAC,EAAE,MAAM,QAAQ,KAAA,CAAM,IAAI,CAAA,EAAC;AAAA,IAAE,EAEpE,IAAA;AAAA,EACL,QAAQ;AACN,WAAO;AAAA,EACT;AACF;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/components/CitationRefView.tsx","../src/createCitationRef.ts","../src/commentAnchor/commentAnchorPlugin.ts","../src/commentAnchor/commentAnchorController.ts","../src/findReplace.ts","../src/icons/index.tsx","../src/labels.ts","../src/components/FindReplaceBar.tsx","../src/importPlaceholder.ts","../src/markdownFileDrop.ts","../src/pendingAnchor.ts","../src/selectionKind.ts","../src/markdownPaste.ts","../src/components/ChartView.tsx","../src/chart/createChart.ts","../src/components/CodeBlockView.tsx","../src/components/MarkdownWysiwygEditor.tsx","../src/components/MarkdownPreview.tsx","../src/importMenu.ts","../src/insertMarkdown.ts","../src/tableSelection.ts","../src/components/ColorPalette.tsx","../src/components/MathEditorPopover.tsx","../src/components/EditorToolbar.tsx","../src/hooks/useIsMobile.ts","../src/components/TocPanel.tsx","../src/commentAnchor/CommentPopover.tsx","../src/anchorRange.ts","../src/markdownRange.ts","../src/normalizeMarkdown.ts","../src/replaceRange.ts"],"sourcesContent":["'use client';\n\nimport {\n NodeViewWrapper,\n type NodeViewProps,\n} from '@tiptap/react';\nimport type { RenderCitation } from '../citationTypes';\n\n/**\n * 脚注圆标 React NodeView。\n * 无 `renderCitation` 时渲默认 pill(有 url 则可点);有插槽时把 defaultDom 交给消费方。\n */\nexport function CitationRefView({ node, extension }: NodeViewProps) {\n const index = String(node.attrs.index ?? '');\n const url = (node.attrs.url as string | null) || null;\n const title = (node.attrs.title as string | null) || '';\n const renderCitation = extension.options.renderCitation as\n | RenderCitation\n | undefined;\n\n const pill = (\n <span\n className=\"citation-ref\"\n data-index={index}\n {...(url ? { 'data-url': url } : {})}\n {...(title ? { 'data-title': title } : {})}\n >\n {!renderCitation && url ? (\n <a\n href={url}\n title={title}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {index}\n </a>\n ) : (\n index\n )}\n </span>\n );\n\n const content = renderCitation\n ? renderCitation({\n index,\n attrs: { index, url, title: title || null },\n defaultDom: pill,\n })\n : pill;\n\n return (\n <NodeViewWrapper\n as=\"span\"\n data-citation-ref=\"\"\n style={{ display: 'inline' }}\n >\n {content}\n </NodeViewWrapper>\n );\n}\n","'use client';\n\nimport { ReactNodeViewRenderer } from '@tiptap/react';\nimport { CitationRef, type CitationRefOptions } from './CitationRef';\nimport type { RenderCitation } from './citationTypes';\nimport { CitationRefView } from './components/CitationRefView';\n\nexport type CitationRefViewOptions = CitationRefOptions & {\n renderCitation?: RenderCitation;\n};\n\n/**\n * 客户端增强版 CitationRef:挂 React NodeView,支持 `renderCitation` 插槽。\n * server / SSR 请继续用纯 {@link CitationRef}(无 React)。\n */\nexport function createCitationRef(\n options: { renderCitation?: RenderCitation } = {},\n) {\n return CitationRef.extend<CitationRefViewOptions>({\n addOptions() {\n return {\n HTMLAttributes: {},\n ...this.parent?.(),\n renderCitation: options.renderCitation,\n };\n },\n addNodeView() {\n return ReactNodeViewRenderer(CitationRefView);\n },\n }).configure({\n renderCitation: options.renderCitation,\n });\n}\n","/**\n * 评论锚定客户端插件:\n * - 装饰:block 左缘 gutter 气泡(showGutter)、active 评论的 mark/block 高亮;\n * - 交互:点击 mark / gutter 通过 transaction meta 上报(宿主经 editor.on('transaction')\n * 接收,规避扩展创建时闭包 stale 的问题);\n * - 守卫:粘贴 / 拖拽的 slice 剥离 commentAnchor mark,防止幽灵高亮。\n *\n * 只读态(MarkdownPreview)不注入本插件、不接评论 —— 评论是编辑会话专属。\n */\n\nimport {\n Fragment,\n Slice,\n type MarkType,\n type Node as PMNode,\n} from '@tiptap/pm/model';\nimport { Extension } from '@tiptap/core';\nimport {\n Plugin,\n PluginKey,\n type EditorState,\n} from '@tiptap/pm/state';\nimport {\n Decoration,\n DecorationSet,\n type EditorView,\n} from '@tiptap/pm/view';\nimport type { CommentClickPayload } from './commentTypes';\n\nexport const COMMENT_ACTIVE_META = 'tmr:comment:active';\nexport const COMMENT_CLICK_META = 'tmr:comment:click';\nexport const COMMENT_GUTTER_META = 'tmr:comment:gutter';\n\nexport interface CommentGutterPayload {\n commentIds: string[];\n pos: number;\n}\n\nexport interface CommentAnchorPluginOptions {\n /** 是否在 block 左缘渲染评论 gutter 气泡,默认 true。 */\n showGutter?: boolean;\n /**\n * 编辑器内点 mark 是否参与交互(默认 true:设 active + 上报 click meta)。\n * 设 false 后点击 mark 完全惰性(不设 active、不上报),适合「只靠侧栏单项\n * 驱动滚动定位」的宿主。\n */\n interactive?: boolean;\n}\n\nexport interface CommentAnchorPluginState {\n activeCommentId: string | null;\n}\n\nexport const commentAnchorPluginKey = new PluginKey<CommentAnchorPluginState>(\n 'tmrCommentAnchor',\n);\n\n/** 从 Slice 中剔除 commentAnchor mark(粘贴/拖拽守卫)。 */\nexport function stripCommentAnchorMarks(\n slice: Slice,\n markType: MarkType,\n): Slice {\n const strip = (fragment: Fragment): Fragment => {\n const children: PMNode[] = [];\n fragment.forEach((child) => {\n if (child.isText && child.marks.some((m) => m.type === markType)) {\n children.push(\n child.mark(child.marks.filter((m) => m.type !== markType)),\n );\n } else if (child.content.size > 0) {\n children.push(child.copy(strip(child.content)));\n } else {\n children.push(child);\n }\n });\n return Fragment.fromArray(children);\n };\n return new Slice(strip(slice.content), slice.openStart, slice.openEnd);\n}\n\nfunction sliceHasCommentMarks(slice: Slice, markType: MarkType): boolean {\n let found = false;\n slice.content.descendants((node) => {\n if (node.isText && node.marks.some((m) => m.type === markType)) {\n found = true;\n return false;\n }\n return true;\n });\n return found;\n}\n\n/** 顶层 block 边界。 */\nfunction blockBounds(doc: PMNode): Array<{ start: number; end: number }> {\n const bounds: Array<{ start: number; end: number }> = [];\n doc.forEach((child, offset) => {\n bounds.push({ start: offset, end: offset + child.nodeSize });\n });\n return bounds;\n}\n\n/** commentId → 文本区间(从 doc 内 commentAnchor mark 收集)。 */\nfunction collectCommentRanges(\n doc: PMNode,\n): Map<string, Array<{ from: number; to: number }>> {\n const byId = new Map<string, Array<{ from: number; to: number }>>();\n doc.descendants((node, pos) => {\n if (!node.isText) return true;\n for (const m of node.marks) {\n if (m.type.name !== 'commentAnchor') continue;\n const ids = (m.attrs.commentIds as string[]) ?? [];\n for (const id of ids) {\n const arr = byId.get(id) ?? [];\n arr.push({ from: pos, to: pos + node.nodeSize });\n byId.set(id, arr);\n }\n }\n return true;\n });\n return byId;\n}\n\nfunction rangesIntersectBlock(\n ranges: Array<{ from: number; to: number }>,\n start: number,\n end: number,\n): boolean {\n return ranges.some((r) => r.from < end && r.to > start);\n}\n\nfunction gutterDom(\n commentIds: string[],\n view: EditorView,\n blockPos: number,\n): HTMLElement {\n const el = document.createElement('span');\n el.className = 'tmr-comment-gutter';\n el.setAttribute('data-comment-ids', commentIds.join(' '));\n el.textContent = String(commentIds.length);\n el.title = `${commentIds.length}`;\n // 不抢编辑器焦点/选区\n el.addEventListener('mousedown', (e) => {\n e.preventDefault();\n e.stopPropagation();\n });\n el.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n view.dispatch(\n view.state.tr\n .setMeta(COMMENT_ACTIVE_META, commentIds[0] ?? null)\n .setMeta(COMMENT_GUTTER_META, {\n commentIds,\n pos: blockPos,\n } satisfies CommentGutterPayload),\n );\n });\n return el;\n}\n\nexport function commentAnchorPlugin(\n options: CommentAnchorPluginOptions = {},\n): Plugin<CommentAnchorPluginState> {\n const showGutter = options.showGutter !== false;\n const interactive = options.interactive !== false;\n\n return new Plugin<CommentAnchorPluginState>({\n key: commentAnchorPluginKey,\n state: {\n init: () => ({ activeCommentId: null }),\n apply: (tr, value) => {\n const active = tr.getMeta(COMMENT_ACTIVE_META);\n return active !== undefined\n ? { activeCommentId: active as string | null }\n : value;\n },\n },\n props: {\n decorations(state: EditorState) {\n const byId = collectCommentRanges(state.doc);\n if (byId.size === 0) return DecorationSet.empty;\n\n const decos: Decoration[] = [];\n const bounds = blockBounds(state.doc);\n\n if (showGutter) {\n for (const b of bounds) {\n const idsInBlock: string[] = [];\n for (const [id, ranges] of byId) {\n if (rangesIntersectBlock(ranges, b.start, b.end)) {\n idsInBlock.push(id);\n }\n }\n if (idsInBlock.length > 0) {\n decos.push(\n Decoration.widget(\n b.start,\n (view) => gutterDom(idsInBlock, view, b.start),\n { side: -1, key: `tmr-gutter:${b.start}` },\n ),\n );\n }\n }\n }\n\n const activeId =\n commentAnchorPluginKey.getState(state)?.activeCommentId ?? null;\n if (activeId) {\n const ranges = byId.get(activeId) ?? [];\n for (const r of ranges) {\n decos.push(\n Decoration.inline(r.from, r.to, { class: 'tmr-comment-active' }),\n );\n }\n for (const b of bounds) {\n if (rangesIntersectBlock(ranges, b.start, b.end)) {\n decos.push(\n Decoration.node(b.start, b.end, {\n class: 'tmr-comment-block-active',\n }),\n );\n }\n }\n }\n\n return DecorationSet.create(state.doc, decos);\n },\n\n handleClick(view: EditorView, pos: number, event: MouseEvent) {\n // 惰性模式:编辑器内点击 mark 不产生任何交互(侧栏单项驱动)。\n if (!interactive) return false;\n const target = event.target as Element | null;\n const el = target?.closest?.(\n 'mark.tmr-comment[data-comment-ids]',\n ) as HTMLElement | null;\n if (!el) return false;\n const commentIds = (el.getAttribute('data-comment-ids') ?? '')\n .split(' ')\n .filter(Boolean);\n if (commentIds.length === 0) return false;\n view.dispatch(\n view.state.tr\n .setMeta(COMMENT_ACTIVE_META, commentIds[0] ?? null)\n .setMeta(COMMENT_CLICK_META, {\n commentIds,\n anchorEl: el,\n pos,\n } satisfies CommentClickPayload),\n );\n return true;\n },\n\n // 粘贴 / 拖拽 / 编辑器内拖动的 slice 统一走这里:剥离评论 mark,\n // 防止复制粘贴产生幽灵高亮。正文内容不变,只是丢掉会话级元数据。\n transformPasted(slice: Slice, view: EditorView) {\n const markType = view.state.schema.marks.commentAnchor;\n if (!markType || !sliceHasCommentMarks(slice, markType)) return slice;\n return stripCommentAnchorMarks(slice, markType);\n },\n },\n });\n}\n\n/**\n * Tiptap Extension 包装:把评论锚定 Plugin 挂进 useEditor / Editor 的 extensions。\n * 只读态(MarkdownPreview)不要注入本扩展 —— 评论是编辑会话专属。\n */\nexport function commentAnchorExtension(\n options: CommentAnchorPluginOptions = {},\n) {\n return Extension.create({\n name: 'tmrCommentAnchor',\n addProseMirrorPlugins() {\n return [commentAnchorPlugin(options)];\n },\n });\n}\n","/**\n * 编辑会话内的评论锚定控制器(纯函数,供宿主 / 组件 handle 复用)。\n *\n * 职责:\n * - applyCommentAnchorsToEditor:comments 装载时把 segments 映射成 mark 铺入 doc;\n * - focusComment / nextComment:active 状态 + 滚动 + 选区;\n * - collectCommentIds / commentRangesById:供宿主查询。\n */\n\nimport type { Editor } from '@tiptap/core';\nimport {\n COMMENT_ACTIVE_META,\n commentAnchorPluginKey,\n} from './commentAnchorPlugin';\nimport {\n mapCommentAnchors,\n mergeCommentIntervals,\n type CommentRange,\n} from './commentMapper';\nimport type { CommentRef } from './commentTypes';\n\n/** 先清后铺,幂等;无评论时清空全部 mark。 */\nexport function applyCommentAnchorsToEditor(\n editor: Editor,\n comments: CommentRef[],\n): void {\n // 只读态不接评论(库契约:评论锚定 = 编辑会话专属)。\n if (!editor.isEditable) return;\n const intervals =\n comments.length > 0\n ? mergeCommentIntervals(\n mapCommentAnchors(\n editor.state.doc,\n comments.map((c) => ({ commentId: c.commentId, segments: c.segments })),\n ).map((r) => ({ commentId: r.commentId, ranges: r.ranges })),\n )\n : [];\n const chain = editor.chain().clearCommentAnchors();\n if (intervals.length > 0) chain.applyCommentAnchors(intervals);\n chain.run();\n}\n\n/** 文档顺序去重的 commentId 列表(gutter / 导航顺序)。 */\nexport function collectCommentIds(editor: Editor): string[] {\n const ids: string[] = [];\n editor.state.doc.descendants((node) => {\n if (!node.isText) return true;\n for (const m of node.marks) {\n if (m.type.name !== 'commentAnchor') continue;\n for (const id of (m.attrs.commentIds as string[]) ?? []) {\n if (!ids.includes(id)) ids.push(id);\n }\n }\n return true;\n });\n return ids;\n}\n\nexport function commentRangesById(\n editor: Editor,\n commentId: string,\n): CommentRange[] {\n const ranges: CommentRange[] = [];\n editor.state.doc.descendants((node, pos) => {\n if (!node.isText) return true;\n for (const m of node.marks) {\n if (m.type.name !== 'commentAnchor') continue;\n const ids = (m.attrs.commentIds as string[]) ?? [];\n if (ids.includes(commentId)) {\n ranges.push({ from: pos, to: pos + node.nodeSize });\n }\n }\n return true;\n });\n return ranges;\n}\n\nfunction setActive(editor: Editor, commentId: string | null): void {\n editor.view.dispatch(\n editor.state.tr.setMeta(COMMENT_ACTIVE_META, commentId),\n );\n}\n\nfunction getActive(editor: Editor): string | null {\n return commentAnchorPluginKey.getState(editor.state)?.activeCommentId ?? null;\n}\n\n/**\n * 聚焦某条评论:设置 active(mark/block 高亮)+ 滚动到第一个 mark + 光标落到\n * 区间起点。找不到(outdated)时清空 active 并返回 false。\n */\nexport function focusComment(editor: Editor, commentId: string): boolean {\n const ranges = commentRangesById(editor, commentId);\n if (ranges.length === 0) {\n setActive(editor, null);\n return false;\n }\n setActive(editor, commentId);\n const markEl = editor.view.dom.querySelector<HTMLElement>(\n `mark.tmr-comment[data-comment-ids~=\"${CSS.escape(commentId)}\"]`,\n );\n markEl?.scrollIntoView?.({ block: 'center', behavior: 'smooth' });\n editor.chain().setTextSelection(ranges[0].from).run();\n return true;\n}\n\n/** 按文档顺序在评论间循环跳转(dir: next / prev)。 */\nexport function nextComment(\n editor: Editor,\n dir: 'next' | 'prev' = 'next',\n): string | null {\n const ids = collectCommentIds(editor);\n if (ids.length === 0) return null;\n const active = getActive(editor);\n const current = active ? ids.indexOf(active) : -1;\n const nextIdx =\n dir === 'next'\n ? (current + 1) % ids.length\n : (current - 1 + ids.length) % ids.length;\n const target = ids[nextIdx];\n focusComment(editor, target);\n return target;\n}\n","/**\n * 查找替换的适配层。\n *\n * 匹配 / 高亮 / 替换全部由官方 `@tiptap/extension-find-and-replace` 承担(命令 + storage +\n * decoration),宿主与 AI 侧可以直接用 `editor.commands.setSearchTerm / replaceAll …`。\n * 这个文件只收拾 Tiptap 3.31.3 上的一个坑,以及库内的默认防抖。\n */\n\n/**\n * 输入防抖(毫秒)。\n *\n * 注意:注册扩展时必须把官方选项 `searchDebounceMs` 设为 **0**。官方防抖走 `setTimeout`,\n * 真正的 dispatch 发生在异步回调里,下面 `runFindCommand` 的守卫就兜不住那次抛错。\n * 防抖改由调用方(浮动条)自己做,语义一样但全程同步。\n */\nexport const FIND_DEBOUNCE_MS = 120;\n\nconst MISMATCH_RE = /Applying a mismatched transaction/;\n\n/**\n * 跑一条官方查找替换命令,兜掉 Tiptap 3.31.3 的一处事务错配。\n *\n * 成因:官方扩展的 `setSearchTerm` 不走 CommandManager 给的 dispatch,而是自己\n * `editor.state.tr` + `view.dispatch`(见扩展 dist 的 `applySearchTerm`)。CommandManager\n * 在命令结束后仍会派发它「命令开始时创建」的那个 tr。若这次派发触发了 TrailingNode 的\n * appendTransaction(**文末是代码块 / 表格 / 图表**时它会补一个空段落,starter-kit 自带),\n * doc 已经前进,那个旧 tr 的 `before` 就对不上当前 doc → `RangeError: Applying a mismatched\n * transaction`。\n *\n * 此时查询其实已经生效(扩展自己那次 dispatch 成功了、尾段落也补上了),只是紧随其后的\n * 第二次派发炸掉。所以捕获这一种错并重试一次即可收敛——重试时文末空段落已在,TrailingNode\n * 不再插手。其它错误照抛,不吞。\n */\nexport function runFindCommand(run: () => void): void {\n try {\n run();\n } catch (error) {\n if (error instanceof RangeError && MISMATCH_RE.test(error.message)) {\n run();\n return;\n }\n throw error;\n }\n}\n","import type { SVGProps } from 'react';\n\n/**\n * 内联 SVG 图标集(0 运行时依赖)。stroke 走 currentColor,尺寸默认 1em 跟随字号,\n * 故颜色/大小随文本与主题自动变化。\n *\n * 通用图标(粗体/斜体/下划线/列表/撤销/查找等,本文件表格图标之前的部分)的 path 取自\n * Lucide,其许可证为 ISC,其中部分图形源自 Feather 的 MIT——完整版权声明见\n * 仓库根目录 THIRD_PARTY_LICENSES.md。表格行列操作图标(Column / Row / TableDelete 系列)为自绘。\n */\nexport interface IconProps extends SVGProps<SVGSVGElement> {\n size?: number | string;\n}\n\nfunction Svg({ size = '1em', children, ...rest }: IconProps & { children: React.ReactNode }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n {...rest}\n >\n {children}\n </svg>\n );\n}\n\nexport const BoldIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\" />\n <path d=\"M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z\" />\n </Svg>\n);\n\nexport const ItalicIcon = (p: IconProps) => (\n <Svg {...p}>\n <line x1=\"19\" x2=\"10\" y1=\"4\" y2=\"4\" />\n <line x1=\"14\" x2=\"5\" y1=\"20\" y2=\"20\" />\n <line x1=\"15\" x2=\"9\" y1=\"4\" y2=\"20\" />\n </Svg>\n);\n\nexport const UnderlineIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M6 4v6a6 6 0 0 0 12 0V4\" />\n <line x1=\"4\" x2=\"20\" y1=\"20\" y2=\"20\" />\n </Svg>\n);\n\nexport const StrikethroughIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M16 4H9a3 3 0 0 0-2.83 4\" />\n <path d=\"M14 12a4 4 0 0 1 0 8H6\" />\n <line x1=\"4\" x2=\"20\" y1=\"12\" y2=\"12\" />\n </Svg>\n);\n\nexport const CodeIcon = (p: IconProps) => (\n <Svg {...p}>\n <polyline points=\"16 18 22 12 16 6\" />\n <polyline points=\"8 6 2 12 8 18\" />\n </Svg>\n);\n\nexport const LinkIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71\" />\n <path d=\"M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71\" />\n </Svg>\n);\n\nexport const ImageIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" ry=\"2\" />\n <circle cx=\"9\" cy=\"9\" r=\"2\" />\n <path d=\"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21\" />\n </Svg>\n);\n\nexport const ImportIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M12 3v12\" />\n <path d=\"m8 11 4 4 4-4\" />\n <path d=\"M8 5H4a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-4\" />\n </Svg>\n);\n\nexport const ListUnorderedIcon = (p: IconProps) => (\n <Svg {...p}>\n <line x1=\"8\" x2=\"21\" y1=\"6\" y2=\"6\" />\n <line x1=\"8\" x2=\"21\" y1=\"12\" y2=\"12\" />\n <line x1=\"8\" x2=\"21\" y1=\"18\" y2=\"18\" />\n <line x1=\"3\" x2=\"3.01\" y1=\"6\" y2=\"6\" />\n <line x1=\"3\" x2=\"3.01\" y1=\"12\" y2=\"12\" />\n <line x1=\"3\" x2=\"3.01\" y1=\"18\" y2=\"18\" />\n </Svg>\n);\n\nexport const ListOrderedIcon = (p: IconProps) => (\n <Svg {...p}>\n <line x1=\"10\" x2=\"21\" y1=\"6\" y2=\"6\" />\n <line x1=\"10\" x2=\"21\" y1=\"12\" y2=\"12\" />\n <line x1=\"10\" x2=\"21\" y1=\"18\" y2=\"18\" />\n <path d=\"M4 6h1v4\" />\n <path d=\"M4 10h2\" />\n <path d=\"M6 18H4c0-1 2-2 2-3s-1-1.5-2-1\" />\n </Svg>\n);\n\nexport const ListChecksIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m3 17 2 2 4-4\" />\n <path d=\"m3 7 2 2 4-4\" />\n <path d=\"M13 6h8\" />\n <path d=\"M13 12h8\" />\n <path d=\"M13 18h8\" />\n </Svg>\n);\n\nexport const UndoIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M9 14 4 9l5-5\" />\n <path d=\"M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5 5.5 5.5 0 0 1-5.5 5.5H11\" />\n </Svg>\n);\n\nexport const RedoIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m15 14 5-5-5-5\" />\n <path d=\"M20 9H9.5A5.5 5.5 0 0 0 4 14.5 5.5 5.5 0 0 0 9.5 20H13\" />\n </Svg>\n);\n\nexport const ChevronDownIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m6 9 6 6 6-6\" />\n </Svg>\n);\n\nexport const CheckIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M20 6 9 17l-5-5\" />\n </Svg>\n);\n\nexport const TrashIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M3 6h18\" />\n <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\" />\n <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" />\n <line x1=\"10\" x2=\"10\" y1=\"11\" y2=\"17\" />\n <line x1=\"14\" x2=\"14\" y1=\"11\" y2=\"17\" />\n </Svg>\n);\n\nexport const LockIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 11V7a5 5 0 0 1 10 0v4\" />\n </Svg>\n);\n\nexport const MenuIcon = (p: IconProps) => (\n <Svg {...p}>\n <line x1=\"4\" x2=\"20\" y1=\"12\" y2=\"12\" />\n <line x1=\"4\" x2=\"20\" y1=\"6\" y2=\"6\" />\n <line x1=\"4\" x2=\"20\" y1=\"18\" y2=\"18\" />\n </Svg>\n);\n\nexport const SearchIcon = (p: IconProps) => (\n <Svg {...p}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </Svg>\n);\n\nexport const XIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </Svg>\n);\n\nexport const ChevronUpIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m18 15-6-6-6 6\" />\n </Svg>\n);\n\nexport const ReplaceIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M14 4a1 1 0 0 1 1-1\" />\n <path d=\"M15 10a1 1 0 0 1-1-1\" />\n <path d=\"M21 4a1 1 0 0 0-1-1\" />\n <path d=\"M21 9a1 1 0 0 1-1 1\" />\n <path d=\"m3 7 3 3 3-3\" />\n <path d=\"M6 10V5a2 2 0 0 1 2-2h2\" />\n <rect x=\"3\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\" />\n </Svg>\n);\n\nexport const ReplaceAllIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M14 14a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1\" />\n <path d=\"M14 4a1 1 0 0 1 1-1\" />\n <path d=\"M15 10a1 1 0 0 1-1-1\" />\n <path d=\"M19 14a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1\" />\n <path d=\"M21 4a1 1 0 0 0-1-1\" />\n <path d=\"M21 9a1 1 0 0 1-1 1\" />\n <path d=\"m3 7 3 3 3-3\" />\n <path d=\"M6 10V5a2 2 0 0 1 2-2h2\" />\n <rect x=\"3\" y=\"14\" width=\"7\" height=\"7\" rx=\"1\" />\n </Svg>\n);\n\n/* ── 表格行列操作图标(自绘:表格轮廓 + 目标边高亮 + 加号/叉号)── */\n\nexport const ColumnBeforeIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"10\" y=\"4\" width=\"11\" height=\"16\" rx=\"1\" />\n <path d=\"M14 4v16\" />\n <path d=\"M5 9v6\" />\n <path d=\"M2 12h6\" />\n </Svg>\n);\n\nexport const ColumnAfterIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"3\" y=\"4\" width=\"11\" height=\"16\" rx=\"1\" />\n <path d=\"M10 4v16\" />\n <path d=\"M19 9v6\" />\n <path d=\"M16 12h6\" />\n </Svg>\n);\n\nexport const ColumnDeleteIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"1\" />\n <path d=\"M12 4v16\" />\n <path d=\"m8 9 8 6\" />\n <path d=\"m16 9-8 6\" />\n </Svg>\n);\n\nexport const RowBeforeIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"4\" y=\"10\" width=\"16\" height=\"11\" rx=\"1\" />\n <path d=\"M4 14h16\" />\n <path d=\"M9 5h6\" />\n <path d=\"M12 2v6\" />\n </Svg>\n);\n\nexport const RowAfterIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"4\" y=\"3\" width=\"16\" height=\"11\" rx=\"1\" />\n <path d=\"M4 10h16\" />\n <path d=\"M9 19h6\" />\n <path d=\"M12 16v6\" />\n </Svg>\n);\n\nexport const RowDeleteIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"1\" />\n <path d=\"M4 12h16\" />\n <path d=\"m9 8 6 8\" />\n <path d=\"m15 8-6 8\" />\n </Svg>\n);\n\nexport const TableDeleteIcon = (p: IconProps) => (\n <Svg {...p}>\n <rect x=\"3\" y=\"5\" width=\"18\" height=\"14\" rx=\"1\" />\n <path d=\"M3 9h18\" />\n <path d=\"M9 5v14\" />\n <path d=\"M15 5v14\" />\n <path d=\"m7 2 10 20\" />\n </Svg>\n);\n","/**\n * UI 文案(i18n 注入点)。各组件接收 `labels?: Partial<...>`,与内置英文默认合并。\n * 消费方(如中文项目)可传入本地化文案。\n */\n\nexport interface ToolbarLabels {\n undo: string;\n redo: string;\n style: string;\n normalText: string;\n /** 传入层级,返回如 \"Heading 2\"。 */\n headingLabel: (level: number) => string;\n fontSize: string;\n fontSizeDefault: string;\n bold: string;\n italic: string;\n underline: string;\n strike: string;\n code: string;\n textColor: string;\n highlight: string;\n colorNone: string;\n colorTheme: string;\n scriptMenu: string;\n scriptNormal: string;\n superscript: string;\n subscript: string;\n link: string;\n linkPrompt: string;\n image: string;\n imageUploadFailed: string;\n /** Markdown 文件导入失败(与图片上传共用 onError 回调时,便于宿主区分文案)。 */\n importMarkdownFailed: string;\n /** 主栏导入下拉触发器上的短文案(对齐 style / fontSize)。 */\n importDocument: string;\n /** 导入触发器 title / aria-label。 */\n importDocumentHint: string;\n /** 未传 importMenuItems、但传了 onImportDocument + importAccept 时的第二项。 */\n importDocumentOther: string;\n /** 导入进行中的按钮 title。 */\n importDocumentBusy: string;\n /** 光标占位:上传阶段,传入 0–100。 */\n importDocumentUploading: (percent: number) => string;\n /** 光标占位:转换阶段,不要百分比。 */\n importDocumentConverting: string;\n /** 非 Markdown 文件导入失败(onError 的 source === 'import')。 */\n importDocumentFailed: string;\n blockquote: string;\n bulletList: string;\n orderedList: string;\n taskList: string;\n more: string;\n codeBlock: string;\n hr: string;\n /** 导入下拉里的 Markdown 项。 */\n importMarkdown: string;\n tableInsert: string;\n /** 网格选择器底部尺寸文案,如 \"3 × 4\"。参数顺序:列、行。 */\n tableSizeSelected: (cols: number, rows: number) => string;\n tableAddColumnBefore: string;\n tableAddColumnAfter: string;\n tableDeleteColumn: string;\n tableAddRowBefore: string;\n tableAddRowAfter: string;\n tableDeleteRow: string;\n /** 多格选区:在左侧插入 N 列。 */\n tableAddColumnBeforeN: (n: number) => string;\n /** 多格选区:在右侧插入 N 列。 */\n tableAddColumnAfterN: (n: number) => string;\n /** 多格选区:删除 N 列。 */\n tableDeleteColumnN: (n: number) => string;\n /** 多格选区:在上方插入 N 行。 */\n tableAddRowBeforeN: (n: number) => string;\n /** 多格选区:在下方插入 N 行。 */\n tableAddRowAfterN: (n: number) => string;\n /** 多格选区:删除 N 行。 */\n tableDeleteRowN: (n: number) => string;\n tableDeleteTable: string;\n inlineMath: string;\n blockMath: string;\n mathPlaceholder: string;\n mathDone: string;\n mathCancel: string;\n mathNewInline: string;\n mathNewBlock: string;\n}\n\nexport interface ChartLabels {\n /** Tab label when config has no title. */\n tabLabel: (chartType: string, index: number) => string;\n done: string;\n cancel: string;\n configLabel: string;\n tableLabel: string;\n /** Modal dialog title. */\n editTitle: string;\n}\n\nexport const defaultChartLabels: ChartLabels = {\n tabLabel: (chartType, index) => `${chartType} ${index + 1}`,\n done: 'Done',\n cancel: 'Cancel',\n configLabel: 'Chart config (JSON)',\n tableLabel: 'Data table (Markdown)',\n editTitle: 'Edit chart',\n};\n\nexport const defaultToolbarLabels: ToolbarLabels = {\n undo: 'Undo',\n redo: 'Redo',\n style: 'Style',\n normalText: 'Normal text',\n headingLabel: (level) => `Heading ${level}`,\n fontSize: 'Font size',\n fontSizeDefault: 'Default',\n bold: 'Bold',\n italic: 'Italic',\n underline: 'Underline',\n strike: 'Strikethrough',\n code: 'Inline code',\n textColor: 'Text color',\n highlight: 'Highlight',\n colorNone: 'None',\n colorTheme: 'THEME',\n scriptMenu: 'Superscript / Subscript',\n scriptNormal: 'Normal',\n superscript: 'Superscript',\n subscript: 'Subscript',\n link: 'Link',\n linkPrompt: 'Enter URL',\n image: 'Image',\n imageUploadFailed: 'Image upload failed',\n importMarkdownFailed: 'Markdown import failed',\n importDocument: 'Import',\n importDocumentHint: 'Import a file',\n importDocumentOther: 'Document',\n importDocumentBusy: 'Importing…',\n importDocumentUploading: (percent) => `Uploading ${percent}%`,\n importDocumentConverting: 'Converting…',\n importDocumentFailed: 'Import failed',\n blockquote: 'Blockquote',\n bulletList: 'Bullet list',\n orderedList: 'Ordered list',\n taskList: 'Task list',\n more: 'More',\n codeBlock: 'Code block',\n hr: 'Divider',\n importMarkdown: 'Markdown',\n tableInsert: 'Insert table',\n tableSizeSelected: (cols, rows) => `${cols} × ${rows}`,\n tableAddColumnBefore: 'Add column before',\n tableAddColumnAfter: 'Add column after',\n tableDeleteColumn: 'Delete column',\n tableAddRowBefore: 'Add row before',\n tableAddRowAfter: 'Add row after',\n tableDeleteRow: 'Delete row',\n tableAddColumnBeforeN: (n) => `Add ${n} columns before`,\n tableAddColumnAfterN: (n) => `Add ${n} columns after`,\n tableDeleteColumnN: (n) => `Delete ${n} columns`,\n tableAddRowBeforeN: (n) => `Add ${n} rows before`,\n tableAddRowAfterN: (n) => `Add ${n} rows after`,\n tableDeleteRowN: (n) => `Delete ${n} rows`,\n tableDeleteTable: 'Delete table',\n inlineMath: 'Inline equation',\n blockMath: 'Block equation',\n mathPlaceholder: 'E = mc^2',\n mathDone: 'Done',\n mathCancel: 'Cancel',\n mathNewInline: 'New equation',\n mathNewBlock: 'Add a TeX equation',\n};\n\nexport interface ColorPaletteLabels {\n none: string;\n theme: string;\n}\n\nexport const defaultColorPaletteLabels: ColorPaletteLabels = {\n none: 'None',\n theme: 'THEME',\n};\n\nexport interface TocLabels {\n title: string;\n expand: string;\n collapse: string;\n}\n\nexport const defaultTocLabels: TocLabels = {\n title: 'Contents',\n expand: 'Expand',\n collapse: 'Collapse',\n};\n\nexport interface CodeBlockLabels {\n autoDetect: string;\n delete: string;\n}\n\nexport const defaultCodeBlockLabels: CodeBlockLabels = {\n autoDetect: 'Auto-detect',\n delete: 'Delete code block',\n};\n\nexport interface CommentLabels {\n open: string;\n resolved: string;\n dismissed: string;\n outdated: string;\n ambiguous: string;\n partial: string;\n gutterTitle: string;\n}\n\nexport const defaultCommentLabels: CommentLabels = {\n open: 'Open',\n resolved: 'Resolved',\n dismissed: 'Dismissed',\n outdated: 'Outdated',\n ambiguous: 'Ambiguous',\n partial: 'Partially matched',\n gutterTitle: 'Comment',\n};\n\nexport interface FindLabels {\n /** 查找输入框的占位与无障碍名,也用作浮动条的 aria-label。 */\n find: string;\n /** 替换输入框的占位与无障碍名。 */\n replace: string;\n next: string;\n previous: string;\n replaceOne: string;\n replaceAll: string;\n close: string;\n caseSensitive: string;\n wholeWord: string;\n useRegex: string;\n /** 计数文案。无结果时 current 传 0。 */\n counter: (current: number, total: number) => string;\n /** 正则模式下模式非法(RE2 不支持 lookaround / backreference 等,见官方扩展)。 */\n invalidRegex: string;\n /** 只读态提示:可查不可换。 */\n readOnly: string;\n}\n\nexport const defaultFindLabels: FindLabels = {\n find: 'Find',\n replace: 'Replace with',\n next: 'Next match',\n previous: 'Previous match',\n replaceOne: 'Replace',\n replaceAll: 'Replace all',\n close: 'Close',\n caseSensitive: 'Match case',\n wholeWord: 'Whole word',\n useRegex: 'Use regular expression',\n counter: (current, total) => `${current} / ${total}`,\n invalidRegex: 'Invalid pattern',\n readOnly: 'Read-only',\n};\n","'use client';\n\nimport {\n createSearchRegex,\n FindAndReplacePluginKey,\n} from '@tiptap/extension-find-and-replace';\nimport { useEditorState, type Editor } from '@tiptap/react';\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent as ReactKeyboardEvent,\n type MouseEvent as ReactMouseEvent,\n type RefObject,\n} from 'react';\nimport { FIND_DEBOUNCE_MS, runFindCommand } from '../findReplace';\nimport {\n ChevronDownIcon,\n ChevronUpIcon,\n ReplaceAllIcon,\n ReplaceIcon,\n SearchIcon,\n XIcon,\n} from '../icons';\nimport { defaultFindLabels, type FindLabels } from '../labels';\nimport styles from '../styles/findBar.module.css';\n\nexport interface FindReplaceBarProps {\n /** 编辑器实例(由 `<MarkdownWysiwygEditor>` 提供,浮动条不自行创建编辑器)。 */\n editor: Editor;\n /** 关闭(Esc / ×):宿主负责收起浮动条并把焦点还给编辑器。 */\n onClose: () => void;\n labels?: Partial<FindLabels>;\n /**\n * 查找输入框 ref。宿主拿它实现「再按一次 Mod+F 聚焦并全选当前查询」。\n * 也用于浮动条打开时自动聚焦。\n */\n inputRef?: RefObject<HTMLInputElement | null>;\n /** 定位 / 层级 class,由宿主给(浮动条自身只负责内部布局)。 */\n className?: string;\n /** 根节点内联样式(编辑器用它落 findBarOffset;宿主自绘时也可用)。 */\n style?: CSSProperties;\n}\n\n/**\n * 查找替换浮动条。匹配、高亮、替换全部由官方\n * `@tiptap/extension-find-and-replace` 承担(含 RE2 安全正则、跨标记匹配、单事务全部替换),\n * 这里只做输入、计数、开关与键位。\n *\n * 打开即把查询推给编辑器,关闭时 `clearSearch()`——高亮是会话级的,不留残影。\n */\nexport function FindReplaceBar({\n editor,\n onClose,\n labels,\n inputRef,\n className,\n style,\n}: FindReplaceBarProps) {\n const t: FindLabels = { ...defaultFindLabels, ...labels };\n const [term, setTerm] = useState('');\n const [replaceTerm, setReplaceTerm] = useState('');\n\n // 宿主自己摆条子时可能把 findReplace 关了——那时扩展没注册,命令与插件 state 都不存在。\n // 不拦住的话下面每个 effect 都会 TypeError 把宿主的树带崩;这里退化为不渲染并留一句提示。\n const hasExtension = typeof editor.commands.setSearchTerm === 'function';\n useEffect(() => {\n if (!hasExtension) {\n console.warn(\n '[tiptap-markdown-react] FindReplaceBar 需要官方 find 扩展:' +\n '请让 <MarkdownWysiwygEditor findReplace> 保持开启(默认 true),' +\n '否则 setSearchTerm / replaceAll 等命令不存在。',\n );\n }\n }, [hasExtension]);\n\n const state = useEditorState({\n editor,\n selector: ({ editor: instance }) => {\n const plugin = FindAndReplacePluginKey.getState(instance.state);\n return {\n currentIndex: plugin?.currentIndex ?? null,\n total: plugin?.results.length ?? 0,\n caseSensitive: plugin?.caseSensitive ?? false,\n wholeWord: plugin?.wholeWord ?? false,\n useRegex: plugin?.useRegex ?? false,\n };\n },\n });\n\n /** 所有命令都从这里走:扩展缺席时直接跳过(见上面 hasExtension)。 */\n const runCommand = useCallback(\n (run: () => void) => {\n if (!hasExtension) return;\n runFindCommand(run);\n },\n [hasExtension],\n );\n\n // 查询词防抖由这里做(扩展注册时 searchDebounceMs: 0,原因见 findReplace.ts):\n // 输入时延迟推给编辑器,回车 / 替换等动作前先 flush,否则会拿着旧查询执行。\n const appliedTermRef = useRef<string | null>(null);\n const pushTerm = useCallback(\n (value: string) => {\n appliedTermRef.current = value;\n runCommand(() => editor.commands.setSearchTerm(value));\n },\n [editor, runCommand],\n );\n const flushTerm = useCallback(() => {\n if (appliedTermRef.current !== term) pushTerm(term);\n }, [pushTerm, term]);\n\n useEffect(() => {\n if (appliedTermRef.current === term) return;\n const timer = setTimeout(() => pushTerm(term), FIND_DEBOUNCE_MS);\n return () => clearTimeout(timer);\n }, [term, pushTerm]);\n\n useEffect(() => {\n runCommand(() => editor.commands.setReplaceTerm(replaceTerm));\n }, [editor, replaceTerm, runCommand]);\n\n // 关闭 / 卸载时清空查询与高亮。\n useEffect(() => {\n return () => {\n if (!editor.isDestroyed) runCommand(() => editor.commands.clearSearch());\n };\n }, [editor, runCommand]);\n\n /** 动作类命令(导航 / 替换):先落定查询词,再执行。 */\n const runAction = useCallback(\n (action: () => void) => {\n flushTerm();\n runCommand(action);\n },\n [flushTerm, runCommand],\n );\n\n // RE2 模式非法(lookaround / backreference 等):官方返回零结果不报错,这里给个提示,\n // 否则「输入了正则却一直 0 / 0」没有解释。\n const invalidPattern = useMemo(\n () =>\n term !== '' &&\n state.useRegex &&\n createSearchRegex(term, {\n caseSensitive: state.caseSensitive,\n useRegex: true,\n wholeWord: false,\n }) === null,\n [term, state.useRegex, state.caseSensitive],\n );\n\n const counter = t.counter(\n state.total === 0 ? 0 : (state.currentIndex ?? 0) + 1,\n state.total,\n );\n\n const keepFocus = (e: ReactMouseEvent) => e.preventDefault();\n\n const onFindKeyDown = (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n runAction(() => {\n if (e.shiftKey) editor.commands.goToPreviousResult();\n else editor.commands.goToNextResult();\n });\n }\n };\n\n const onReplaceKeyDown = (e: ReactKeyboardEvent<HTMLInputElement>) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n runAction(() => editor.commands.replace());\n }\n };\n\n const toggle = (key: 'caseSensitive' | 'wholeWord', value: boolean) => {\n runCommand(() => {\n if (key === 'caseSensitive') editor.commands.setCaseSensitive(value);\n else editor.commands.setWholeWord(value);\n });\n };\n\n if (!hasExtension) return null;\n\n const toggleClass = (on: boolean) =>\n `${styles.btn} ${styles.toggle}${on ? ` ${styles.toggleOn}` : ''}`;\n\n return (\n <div\n className={className ? `${styles.bar} ${className}` : styles.bar}\n style={style}\n role=\"dialog\"\n aria-label={t.find}\n onKeyDown={(e) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose();\n }\n }}\n >\n <div className={styles.row}>\n <span className={styles.field}>\n <SearchIcon size={14} className={styles.fieldIcon} />\n <input\n ref={inputRef}\n className={styles.input}\n value={term}\n onChange={(e) => setTerm(e.target.value)}\n onKeyDown={onFindKeyDown}\n placeholder={t.find}\n aria-label={t.find}\n autoFocus\n spellCheck={false}\n />\n <span\n className={`${styles.counter}${invalidPattern ? ` ${styles.counterInvalid}` : ''}`}\n aria-live=\"polite\"\n title={invalidPattern ? t.invalidRegex : undefined}\n >\n {invalidPattern ? t.invalidRegex : counter}\n </span>\n </span>\n <button\n type=\"button\"\n className={toggleClass(state.caseSensitive)}\n title={t.caseSensitive}\n aria-label={t.caseSensitive}\n aria-pressed={state.caseSensitive}\n onMouseDown={keepFocus}\n onClick={() => toggle('caseSensitive', !state.caseSensitive)}\n >\n Aa\n </button>\n <button\n type=\"button\"\n className={toggleClass(state.wholeWord)}\n title={t.wholeWord}\n aria-label={t.wholeWord}\n aria-pressed={state.wholeWord}\n onMouseDown={keepFocus}\n onClick={() => toggle('wholeWord', !state.wholeWord)}\n >\n ab\n </button>\n\n <span className={styles.spacer} />\n <span className={styles.iconGroup}>\n <button\n type=\"button\"\n className={styles.btn}\n title={t.previous}\n aria-label={t.previous}\n disabled={state.total === 0}\n onMouseDown={keepFocus}\n onClick={() => runAction(() => editor.commands.goToPreviousResult())}\n >\n <ChevronUpIcon size={16} />\n </button>\n <button\n type=\"button\"\n className={styles.btn}\n title={t.next}\n aria-label={t.next}\n disabled={state.total === 0}\n onMouseDown={keepFocus}\n onClick={() => runAction(() => editor.commands.goToNextResult())}\n >\n <ChevronDownIcon size={16} />\n </button>\n <button\n type=\"button\"\n className={styles.btn}\n title={t.close}\n aria-label={t.close}\n onClick={onClose}\n >\n <XIcon size={16} />\n </button>\n </span>\n </div>\n\n {editor.isEditable ? (\n <div className={styles.row}>\n <span className={styles.field}>\n <input\n className={styles.input}\n value={replaceTerm}\n onChange={(e) => setReplaceTerm(e.target.value)}\n onKeyDown={onReplaceKeyDown}\n placeholder={t.replace}\n aria-label={t.replace}\n spellCheck={false}\n />\n </span>\n <span className={styles.spacer} />\n <button\n type=\"button\"\n className={styles.btn}\n title={t.replaceOne}\n aria-label={t.replaceOne}\n disabled={state.total === 0}\n onMouseDown={keepFocus}\n onClick={() => runAction(() => editor.commands.replace())}\n >\n <ReplaceIcon size={16} />\n </button>\n <button\n type=\"button\"\n className={styles.btn}\n title={t.replaceAll}\n aria-label={t.replaceAll}\n disabled={state.total === 0}\n onMouseDown={keepFocus}\n onClick={() => runAction(() => editor.commands.replaceAll())}\n >\n <ReplaceAllIcon size={16} />\n </button>\n </div>\n ) : (\n <div className={styles.row}>\n <span className={styles.readOnly}>{t.readOnly}</span>\n </div>\n )}\n </div>\n );\n}\n","import { Node } from '@tiptap/core';\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n importPlaceholder: {\n insertImportPlaceholder: (label: string) => ReturnType;\n updateImportPlaceholder: (label: string) => ReturnType;\n removeImportPlaceholder: () => ReturnType;\n };\n }\n}\n\nfunction findPlaceholderPos(doc: {\n descendants: (\n f: (node: { type: { name: string } }, pos: number) => boolean | void,\n ) => void;\n}): number | null {\n let found: number | null = null;\n doc.descendants((node, pos) => {\n if (node.type.name === 'importPlaceholder') {\n found = pos;\n return false;\n }\n });\n return found;\n}\n\n/** 导入进行中插在光标处的占位块。不进 Markdown,autosave 不会把进度文案落库。 */\nexport const ImportPlaceholder = Node.create({\n name: 'importPlaceholder',\n group: 'block',\n atom: true,\n selectable: false,\n draggable: false,\n\n addAttributes() {\n return {\n label: {\n default: '',\n parseHTML: (el) => el.getAttribute('data-label') ?? '',\n renderHTML: (attrs) =>\n attrs.label ? { 'data-label': attrs.label } : {},\n },\n };\n },\n\n parseHTML() {\n return [{ tag: 'div[data-type=\"import-placeholder\"]' }];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const label = String(node.attrs.label ?? '');\n return [\n 'div',\n {\n ...HTMLAttributes,\n 'data-type': 'import-placeholder',\n class: 'tmr-import-placeholder',\n contenteditable: 'false',\n 'aria-live': 'polite',\n 'aria-busy': 'true',\n },\n ['span', { class: 'tmr-import-placeholder-spin', 'aria-hidden': 'true' }],\n ['span', { class: 'tmr-import-placeholder-label' }, label],\n ];\n },\n\n renderMarkdown() {\n return '';\n },\n\n addCommands() {\n return {\n insertImportPlaceholder:\n (label) =>\n ({ chain }) =>\n chain()\n .focus()\n .insertContent({\n type: this.name,\n attrs: { label },\n })\n .command(({ tr }) => {\n tr.setMeta('addToHistory', false);\n tr.setMeta('preventUpdate', true);\n return true;\n })\n .run(),\n updateImportPlaceholder:\n (label) =>\n ({ tr, dispatch, state }) => {\n const pos = findPlaceholderPos(state.doc);\n if (pos == null) return false;\n if (dispatch) {\n dispatch(\n tr\n .setNodeMarkup(pos, undefined, { label })\n .setMeta('addToHistory', false)\n .setMeta('preventUpdate', true),\n );\n }\n return true;\n },\n removeImportPlaceholder:\n () =>\n ({ tr, dispatch, state }) => {\n const pos = findPlaceholderPos(state.doc);\n if (pos == null) return false;\n const node = state.doc.nodeAt(pos);\n if (!node) return false;\n if (dispatch) {\n dispatch(\n tr\n .delete(pos, pos + node.nodeSize)\n .setMeta('addToHistory', false)\n .setMeta('preventUpdate', true),\n );\n }\n return true;\n },\n };\n },\n});\n","// 副作用:增强 Editor.markdown(MarkdownManager)的类型。\nimport '@tiptap/markdown';\nimport { Extension, type Editor } from '@tiptap/core';\nimport { FileHandlePlugin } from '@tiptap/extension-file-handler';\nimport { PluginKey } from '@tiptap/pm/state';\n\n/** .md / .markdown 扩展名(不区分大小写)。 */\nconst MD_FILE_RE = /\\.(md|markdown)$/i;\n\n/**\n * .md 的 MIME 类型在各平台不稳定(text/markdown / text/x-markdown / 空串),\n * 而 FileHandlePlugin 的 allowedMimeTypes 是严格 `includes(file.type)` 匹配\n * (源码确认,不支持扩展名)。故列表包含空串兜住「系统未注册 MIME」的 .md,\n * 真正的判定在回调里按文件名做。副作用:拖入其它空 MIME 文件会被吞成 no-op\n * ——好过浏览器默认导航打开该文件。\n */\nconst MD_MIME_TYPES = ['text/markdown', 'text/x-markdown', ''];\n\n/** 读 .md 文件文本 → markdown.parse → 插入(drop 时插到落点,paste 时插到光标)。 */\nasync function insertMarkdownFiles(\n editor: Editor,\n files: File[],\n pos?: number,\n): Promise<void> {\n const mdFiles = files.filter((f) => MD_FILE_RE.test(f.name));\n if (mdFiles.length === 0) return;\n // markdown manager 仅在注册了 @tiptap/markdown 扩展后存在\n const markdown = editor.markdown;\n if (!markdown) return;\n const texts = await Promise.all(mdFiles.map((f) => f.text()));\n const json = markdown.parse(texts.join('\\n\\n'));\n if (pos != null) {\n editor.chain().focus().insertContentAt(pos, json).run();\n } else {\n editor.chain().focus().insertContent(json).run();\n }\n}\n\n/**\n * 把 .md / .markdown 文件拖拽或粘贴进编辑器,解析后插入内容。\n * 复用官方 @tiptap/extension-file-handler 的底层 FileHandlePlugin,但注册在\n * 自有 PluginKey 下——宿主仍可通过 extraExtensions 注入自己的 FileHandler\n * (如图片上传)而不撞 key。\n */\nexport const MarkdownFileDrop = Extension.create({\n name: 'markdownFileDrop',\n\n addProseMirrorPlugins() {\n const { editor } = this;\n return [\n FileHandlePlugin({\n key: new PluginKey('markdownFileDrop'),\n editor,\n allowedMimeTypes: MD_MIME_TYPES,\n onDrop: (ed, files, pos) => {\n insertMarkdownFiles(ed, files, pos).catch((err) => {\n console.error('markdown file drop failed:', err);\n });\n },\n onPaste: (ed, files) => {\n insertMarkdownFiles(ed, files).catch((err) => {\n console.error('markdown file paste failed:', err);\n });\n },\n }),\n ];\n },\n});\n","import { Extension } from '@tiptap/core';\nimport { skipTrailingNodeMeta } from '@tiptap/extensions';\nimport type { Node } from '@tiptap/pm/model';\nimport { Plugin, PluginKey, type EditorState } from '@tiptap/pm/state';\nimport { Decoration, DecorationSet } from '@tiptap/pm/view';\nimport type { Editor } from '@tiptap/react';\n\n/**\n * 「这段正在被 AI 改写」的高亮。\n *\n * 用 **decoration** 而不是 mark:两者都不会漏进 markdown,都能盖住表格,但 decoration\n * 不需要往 schema 里加标记、也不参与 undo 历史,而且**原子节点(图表 / 图片)也能盖**\n * ——mark 只作用于行内内容,盖不住 `atom: true` 的块级节点。\n *\n * 状态由宿主通过 `pendingAnchors` 推入(提交圈选改写时给上,回填或冲突时清空)。\n * 文档被编辑时装饰会跟着映射(在原文中间插字,高亮跟着变长;在前面插,整体后移)。\n */\nexport interface PendingAnchor {\n /** 宿主自己的标识(例如一次圈选请求的 request_id)。 */\n id: string;\n /** doc 坐标区间;通常是与选区相交的顶层块的首尾(见 getMarkdownForRange)。 */\n ranges: Array<{ from: number; to: number }>;\n}\n\nexport interface PendingAnchorState {\n decorations: DecorationSet;\n}\n\n/** 用 transaction meta 推入锚点:`tr.setMeta(PENDING_ANCHOR_META, anchors)`。 */\nexport const PENDING_ANCHOR_META = 'tmr:pendingAnchor';\n\nexport const pendingAnchorPluginKey = new PluginKey<PendingAnchorState>(\n 'tmrPendingAnchor',\n);\n\n/** 装饰上的 class;点击命中时宿主用 `[data-pending-id]` 取回 id。 */\nexport const PENDING_ANCHOR_CLASS = 'tmr-pending-anchor';\n\nexport const pendingAnchorExtension = Extension.create({\n name: 'pendingAnchor',\n\n addProseMirrorPlugins() {\n return [\n new Plugin<PendingAnchorState>({\n key: pendingAnchorPluginKey,\n state: {\n init: () => ({ decorations: DecorationSet.empty }),\n apply(tr, value) {\n const next = tr.getMeta(PENDING_ANCHOR_META) as\n | PendingAnchor[]\n | undefined;\n if (next) return { decorations: buildDecorations(tr.doc, next) };\n if (tr.docChanged) {\n return { decorations: value.decorations.map(tr.mapping, tr.doc) };\n }\n return value;\n },\n },\n props: {\n decorations(state: EditorState) {\n return pendingAnchorPluginKey.getState(state)?.decorations ?? null;\n },\n },\n }),\n ];\n },\n});\n\n/** 更新待改写高亮(传空数组即清空)。不进 undo 历史。 */\nexport function setPendingAnchors(editor: Editor, anchors: PendingAnchor[]): void {\n editor.view.dispatch(\n editor.state.tr\n .setMeta(PENDING_ANCHOR_META, anchors)\n // Tiptap 的 TrailingNode(StarterKit 自带)会在「第一个 transaction」时给文档末尾补一个\n // 空段落——只要文末是图表 / 表格 / 代码块这类节点。那是它本来的行为,但**不该由一次\n // 「加个高亮」触发**:那等于用户什么都没干、正文却多了个空段落(落库就变成结尾的 \\n\\n)。\n // 用官方 meta 跳过本次。\n .setMeta(skipTrailingNodeMeta, true)\n .setMeta('addToHistory', false),\n );\n}\n\nfunction buildDecorations(doc: Node, anchors: PendingAnchor[]): DecorationSet {\n const bounds: Array<{ from: number; to: number }> = [];\n doc.forEach((child, offset) => {\n bounds.push({ from: offset, to: offset + child.nodeSize });\n });\n\n const decorations: Decoration[] = [];\n for (const anchor of anchors) {\n for (const range of anchor.ranges) {\n const from = Math.max(0, Math.min(range.from, range.to));\n const to = Math.min(doc.content.size, Math.max(range.from, range.to));\n if (from >= to) continue;\n\n for (const bound of bounds) {\n if (bound.to <= from || bound.from >= to) continue;\n const attrs = {\n class: PENDING_ANCHOR_CLASS,\n 'data-pending-id': anchor.id,\n };\n if (from <= bound.from && to >= bound.to) {\n // 整块:用 node 装饰,表格 / 图表这类块级节点才盖得住\n decorations.push(Decoration.node(bound.from, bound.to, attrs));\n } else {\n // 块内的一部分(未扩块的选区):行内高亮\n decorations.push(\n Decoration.inline(Math.max(from, bound.from), Math.min(to, bound.to), attrs),\n );\n }\n }\n }\n }\n\n return decorations.length ? DecorationSet.create(doc, decorations) : DecorationSet.empty;\n}\n","import type { Selection } from '@tiptap/pm/state';\nimport { NodeSelection, TextSelection } from '@tiptap/pm/state';\nimport { CellSelection } from '@tiptap/pm/tables';\n\n/**\n * 选区类型——给宿主判断「用户选的是什么」用。\n *\n * - `text`:普通文字选区(含 AllSelection)\n * - `cell`:表格里的单元格选区(`CellSelection`,拖过表格时就是它)\n * - `node`:整节点选区(`NodeSelection`)。图表 / 图片 / 代码块这类 `atom` 节点只能这样被选中\n * ——它们在编辑器里渲染成图或块,用户没法用拖选文字的方式选中\n */\nexport type SelectionKind = 'text' | 'cell' | 'node';\n\nexport function selectionKind(selection: Selection): SelectionKind {\n if (selection instanceof CellSelection) return 'cell';\n if (selection instanceof NodeSelection) return 'node';\n if (selection instanceof TextSelection) return 'text';\n return 'text';\n}\n","// 副作用:增强 Editor.markdown(MarkdownManager)的类型。\nimport '@tiptap/markdown';\nimport { Extension } from '@tiptap/core';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport { prepareChartMarkdown } from './chart/prepareChartMarkdown';\n\n/**\n * 启发式判断一段纯文本是否「像 markdown」。\n * 只要命中任一块级/行内特征即认为是——宁可偶尔把带星号的普通文本转掉,\n * 也不漏掉真 markdown(用户可用 Shift+粘贴逃生)。\n */\nexport function looksLikeMarkdown(text: string): boolean {\n return (\n /^#{1,6}\\s/m.test(text) || // 标题\n /\\*\\*[^*\\n]+\\*\\*/.test(text) || // 加粗\n /(^|[^!])\\[[^\\]\\n]+\\]\\([^)\\n]+\\)/.test(text) || // 链接\n /!\\[[^\\]\\n]*\\]\\([^)\\n]+\\)/.test(text) || // 图片\n /^[-*+]\\s+\\S/m.test(text) || // 无序列表\n /^\\d+\\.\\s+\\S/m.test(text) || // 有序列表\n /^>\\s/m.test(text) || // 引用\n /^```/m.test(text) || // 代码围栏\n /^\\|.+\\|\\s*$/m.test(text) || // 表格行\n /^(-{3,}|\\*{3,})\\s*$/m.test(text) || // 分割线\n /<!--\\s*[\\[{][\\s\\S]*?\"chartType\"[\\s\\S]*?-->/.test(text) // 图表注释\n );\n}\n\n/**\n * 粘贴 markdown 纯文本自动转富文本(官方 @tiptap/markdown 不内置此能力,\n * 实现方式取自官方文档 \"Paste Markdown Detection\" 配方并调整边界)。\n *\n * 判定只看 text/plain 的内容,不看剪贴板是否带 text/html——很多来源\n * (Xcode/VS Code 等编辑器经 RTF/语法高亮 HTML)复制 markdown 源码时会\n * 附带一份仅是\"字面文本+样式\"的 HTML,按 HTML 标签判定来源不可枚举。\n * 而真富文本(Word/网页文章)的 text/plain 降级不含 markdown 符号,\n * 启发式天然不命中,仍走默认富文本粘贴。\n *\n * 放行(不转换)的边界:\n * - Shift+粘贴(粘贴为纯文本)→ 保留逃生通道\n * - 光标在代码块内 → markdown 源码原样贴入\n * - looksLikeMarkdown 未命中 → 默认粘贴\n */\nexport const MarkdownPaste = Extension.create({\n name: 'markdownPaste',\n\n addProseMirrorPlugins() {\n const { editor } = this;\n return [\n new Plugin({\n key: new PluginKey('markdownPaste'),\n props: {\n handlePaste(view, event) {\n const clipboard = event.clipboardData;\n if (!clipboard) return false;\n const text = clipboard.getData('text/plain');\n if (!text) return false;\n // Shift+粘贴 = 用户显式要纯文本(shiftKey 是 prosemirror-view\n // 内部状态,无公开 API,容错访问;拿不到则照常转换)\n const input = (view as unknown as { input?: { shiftKey?: boolean } })\n .input;\n if (input?.shiftKey) return false;\n // 代码块内粘贴 markdown 源码是常见操作,不转换\n if (view.state.selection.$from.parent.type.spec.code) return false;\n if (!looksLikeMarkdown(text)) return false;\n // markdown manager 仅在注册了 @tiptap/markdown 扩展后存在\n const markdown = editor.markdown;\n if (!markdown) return false;\n try {\n // 与 insertMarkdown / 初始 content 一致:先把\n // `<!-- chartType -->` + GFM 表收成 ```tmr-chart,否则\n // TipTap 会丢掉 HTML 注释,只剩普通表格。\n const json = markdown.parse(prepareChartMarkdown(text));\n editor.commands.insertContent(json);\n return true;\n } catch (err) {\n console.error('markdown paste parse failed:', err);\n return false; // 解析失败回退默认纯文本粘贴\n }\n },\n },\n }),\n ];\n },\n});\n","'use client';\n\nimport type { Chart as ChartJs } from 'chart.js';\nimport {\n NodeViewWrapper,\n type NodeViewProps,\n} from '@tiptap/react';\nimport {\n useEffect,\n useMemo,\n useRef,\n useState,\n type MouseEvent,\n} from 'react';\nimport { destroyChart, renderOrUpdateChart } from '../chart/renderChart';\nimport type { ChartPayload, ChartTheme } from '../chart/types';\nimport { defaultChartLabels } from '../labels';\nimport '../styles/chart.css';\n\nfunction tabLabel(\n chartType: string,\n title: string | undefined,\n index: number,\n fallback: (type: string, i: number) => string,\n): string {\n if (title?.trim()) return title;\n return fallback(chartType, index);\n}\n\n/**\n * Chart NodeView: render + NodeSelection (like Image).\n * Config editing is intentionally disabled for now (no modal).\n */\nexport function ChartView({\n node,\n editor,\n extension,\n selected,\n getPos,\n}: NodeViewProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const chartRef = useRef<ChartJs | null>(null);\n const [active, setActive] = useState(0);\n\n const payload: ChartPayload = useMemo(\n () => ({\n config: (node.attrs.config ?? []) as ChartPayload['config'],\n columns: (node.attrs.columns ?? []) as ChartPayload['columns'],\n dataSource: (node.attrs.dataSource ??\n []) as ChartPayload['dataSource'],\n }),\n [node.attrs.config, node.attrs.columns, node.attrs.dataSource],\n );\n\n const theme = (extension.options.chartTheme ?? null) as ChartTheme | null;\n const configs = payload.config;\n const safeIndex = Math.min(active, Math.max(0, configs.length - 1));\n const config = configs[safeIndex];\n const height = config?.height ?? 320;\n const canSelect = Boolean(editor?.isEditable);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas || !config) return;\n chartRef.current = renderOrUpdateChart({\n canvas,\n config,\n payload,\n theme,\n chart: chartRef.current,\n });\n }, [config, payload, theme]);\n\n useEffect(() => {\n return () => {\n destroyChart(chartRef.current);\n chartRef.current = null;\n };\n }, []);\n\n // When active tab changes, recreate chart (type may differ)\n useEffect(() => {\n destroyChart(chartRef.current);\n chartRef.current = null;\n const canvas = canvasRef.current;\n if (!canvas || !config) return;\n chartRef.current = renderOrUpdateChart({\n canvas,\n config,\n payload,\n theme,\n chart: null,\n });\n }, [safeIndex]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const labels = {\n ...defaultChartLabels,\n ...(extension.options.chartLabels as\n | Partial<typeof defaultChartLabels>\n | undefined),\n };\n\n const selectChart = () => {\n if (!editor || !canSelect) return;\n const pos = getPos();\n if (typeof pos !== 'number') return;\n editor.commands.setNodeSelection(pos);\n };\n\n return (\n <NodeViewWrapper\n as=\"div\"\n className={`tmr-chart${canSelect ? ' tmr-chart--interactive' : ''}${\n selected ? ' ProseMirror-selectednode' : ''\n }`}\n data-type=\"chart\"\n data-selected={selected ? 'true' : undefined}\n contentEditable={false}\n onMouseDown={(e: MouseEvent) => {\n if ((e.target as HTMLElement).closest('button')) return;\n if (e.button !== 0) return;\n // Select node but do not preventDefault — Chart.js needs hover/click.\n selectChart();\n }}\n >\n {config?.title ? (\n <div className=\"tmr-chart-title\">{config.title}</div>\n ) : null}\n {config?.dataTime ? (\n <div className=\"tmr-chart-time\">{config.dataTime}</div>\n ) : null}\n {configs.length > 1 ? (\n <div className=\"tmr-chart-tabs\" role=\"tablist\">\n {configs.map((c, i) => (\n <button\n key={`${c.chartType}-${i}`}\n type=\"button\"\n role=\"tab\"\n className=\"tmr-chart-tab\"\n data-active={i === safeIndex ? 'true' : 'false'}\n aria-selected={i === safeIndex}\n onMouseDown={(e) => e.stopPropagation()}\n onClick={(e) => {\n e.stopPropagation();\n setActive(i);\n }}\n >\n {tabLabel(c.chartType, c.title, i, labels.tabLabel)}\n </button>\n ))}\n </div>\n ) : null}\n <div className=\"tmr-chart-canvas-host\" style={{ height }}>\n <canvas ref={canvasRef} />\n </div>\n </NodeViewWrapper>\n );\n}\n","import { ReactNodeViewRenderer } from '@tiptap/react';\nimport { reportChart, type ReportChartOptions } from './ChartExtension';\nimport { ChartView } from '../components/ChartView';\nimport type { ChartTheme } from './types';\nimport type { ChartLabels } from '../labels';\n\nexport interface CreateChartOptions {\n /** When true, reserved for future in-place chart editing. Currently unused (no edit UI). Default false. */\n editable?: boolean;\n chartTheme?: ChartTheme | null;\n chartLabels?: Partial<ChartLabels>;\n}\n\nexport interface InteractiveChartOptions extends ReportChartOptions {\n chartEditable: boolean;\n chartTheme: ChartTheme | null;\n chartLabels?: Partial<ChartLabels>;\n}\n\n/**\n * Client chart extension with React NodeView.\n * Server / pure HTML paths should use {@link reportChart} / {@link pureChart}.\n */\nexport function createChart(options: CreateChartOptions = {}) {\n // Chart config editing (modal) is disabled for now; keep option for later.\n const { editable = false, chartTheme = null, chartLabels } = options;\n return reportChart.extend<InteractiveChartOptions>({\n addOptions() {\n return {\n HTMLAttributes: {},\n chartEditable: editable,\n chartTheme,\n chartLabels,\n };\n },\n addNodeView() {\n return ReactNodeViewRenderer(ChartView);\n },\n });\n}\n","'use client';\n\nimport * as DropdownMenu from '@radix-ui/react-dropdown-menu';\nimport {\n NodeViewContent,\n NodeViewWrapper,\n type NodeViewProps,\n} from '@tiptap/react';\nimport { CheckIcon, ChevronDownIcon, TrashIcon } from '../icons';\nimport { defaultCodeBlockLabels, type CodeBlockLabels } from '../labels';\nimport styles from '../styles/codeBlock.module.css';\n\n// 语言选择可选项。空 value = Auto-detect(交给 lowlight 自动识别)\nconst LANGUAGES: { value: string; label: string }[] = [\n { value: '', label: 'Auto-detect' },\n { value: 'javascript', label: 'JavaScript' },\n { value: 'typescript', label: 'TypeScript' },\n { value: 'python', label: 'Python' },\n { value: 'java', label: 'Java' },\n { value: 'go', label: 'Go' },\n { value: 'rust', label: 'Rust' },\n { value: 'c', label: 'C' },\n { value: 'cpp', label: 'C++' },\n { value: 'csharp', label: 'C#' },\n { value: 'sql', label: 'SQL' },\n { value: 'json', label: 'JSON' },\n { value: 'yaml', label: 'YAML' },\n { value: 'bash', label: 'Bash' },\n { value: 'shell', label: 'Shell' },\n { value: 'html', label: 'HTML' },\n { value: 'css', label: 'CSS' },\n { value: 'markdown', label: 'Markdown' },\n];\n\n/**\n * 代码块自定义 NodeView:右上角语言选择器(Radix DropdownMenu,支持方向键导航)+ 删除。\n * 文案(Auto-detect / 删除标题)从扩展 options.codeBlockLabels 读取,缺省用英文默认。\n */\nexport function CodeBlockView({\n node,\n updateAttributes,\n deleteNode,\n extension,\n editor,\n}: NodeViewProps) {\n const labels: CodeBlockLabels = {\n ...defaultCodeBlockLabels,\n ...((extension?.options as { codeBlockLabels?: Partial<CodeBlockLabels> })\n ?.codeBlockLabels ?? {}),\n };\n const language = (node.attrs.language as string) || '';\n const current = LANGUAGES.find((l) => l.value === language);\n const currentLabel = current\n ? current.value === ''\n ? labels.autoDetect\n : current.label\n : labels.autoDetect;\n const editable = editor.isEditable;\n\n return (\n <NodeViewWrapper className={styles.wrapper}>\n {editable ? (\n <div className={styles.header} contentEditable={false}>\n <DropdownMenu.Root>\n <DropdownMenu.Trigger asChild>\n <button\n type=\"button\"\n className={styles.langTrigger}\n aria-label=\"Code language\"\n >\n <span>{currentLabel}</span>\n <ChevronDownIcon size={14} className={styles.langChevron} />\n </button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Portal>\n <DropdownMenu.Content\n className={styles.langMenu}\n sideOffset={4}\n align=\"end\"\n >\n {LANGUAGES.map((l) => {\n const optionLabel =\n l.value === '' ? labels.autoDetect : l.label;\n const selected = l.value === language;\n return (\n <DropdownMenu.Item\n key={l.value}\n className={`${styles.langItem}${selected ? ` ${styles.langItemSelected}` : ''}`}\n onSelect={() => updateAttributes({ language: l.value })}\n >\n <span className={styles.langItemCheck}>\n {selected ? <CheckIcon size={14} /> : null}\n </span>\n {optionLabel}\n </DropdownMenu.Item>\n );\n })}\n </DropdownMenu.Content>\n </DropdownMenu.Portal>\n </DropdownMenu.Root>\n <button\n type=\"button\"\n className={styles.deleteBtn}\n title={labels.delete}\n aria-label={labels.delete}\n onClick={() => deleteNode()}\n >\n <TrashIcon />\n </button>\n </div>\n ) : (\n // 只读:只展示语言标签,无下拉 / 删除等交互件\n <div className={styles.langBadge} contentEditable={false}>\n {currentLabel}\n </div>\n )}\n <pre className={styles.pre}>\n {/* code 标签是代码块标准内容容器;v3 类型未含 'code',运行时有效,故断言 */}\n <NodeViewContent as={'code' as 'div'} />\n </pre>\n </NodeViewWrapper>\n );\n}\n","'use client';\n\nimport CodeBlockLowlight, {\n type CodeBlockLowlightOptions,\n} from '@tiptap/extension-code-block-lowlight';\nimport FindAndReplace from '@tiptap/extension-find-and-replace';\nimport Image from '@tiptap/extension-image';\nimport { TableOfContents } from '@tiptap/extension-table-of-contents';\nimport { Markdown } from '@tiptap/markdown';\nimport {\n EditorContent,\n ReactNodeViewRenderer,\n useEditor,\n type AnyExtension,\n type Editor,\n} from '@tiptap/react';\nimport { createPortal } from 'react-dom';\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n} from 'react';\nimport {\n enrichMarkdownCitations,\n type SourceRef,\n} from '../citationUtils';\nimport type { RenderCitation } from '../citationTypes';\nimport { createCitationRef } from '../createCitationRef';\nimport { CommentMark } from '../commentAnchor/CommentMark';\nimport {\n COMMENT_ACTIVE_META,\n COMMENT_CLICK_META,\n COMMENT_GUTTER_META,\n commentAnchorExtension,\n} from '../commentAnchor/commentAnchorPlugin';\nimport {\n applyCommentAnchorsToEditor,\n collectCommentIds,\n focusComment,\n nextComment,\n} from '../commentAnchor/commentAnchorController';\nimport type {\n CommentClickPayload,\n CommentRef,\n} from '../commentAnchor/commentTypes';\nimport { baseExtensions, lowlight } from '../extensions';\nimport { FindReplaceBar } from './FindReplaceBar';\nimport { ImportPlaceholder } from '../importPlaceholder';\nimport type { CodeBlockLabels, FindLabels } from '../labels';\nimport { MarkdownFileDrop } from '../markdownFileDrop';\nimport {\n pendingAnchorExtension,\n setPendingAnchors,\n type PendingAnchor,\n} from '../pendingAnchor';\nimport { selectionKind, type SelectionKind } from '../selectionKind';\nimport { MarkdownPaste } from '../markdownPaste';\nimport { parseCodeTokenAsChartOrCodeBlock } from '../chart/codeBlockChartParse';\nimport { createChart } from '../chart/createChart';\nimport { prepareChartMarkdown } from '../chart/prepareChartMarkdown';\nimport '../styles/chart.css';\nimport '../styles/pending.css';\nimport '../styles/find.css';\nimport styles from '../styles/content.module.css';\nimport type { TocItem } from '../toc/extractToc';\nimport { makeTocGetId } from '../toc/tocSlug';\nimport { CodeBlockView } from './CodeBlockView';\n\n// 带语言选择器的代码块(自定义 React NodeView)。base 不含代码块,此增强版由编辑器注入。\n// addOptions 追加 codeBlockLabels,供 CodeBlockView 读取以本地化文案。\ntype CodeBlockOptions = CodeBlockLowlightOptions & {\n codeBlockLabels?: Partial<CodeBlockLabels>;\n};\n\nconst CodeBlock = CodeBlockLowlight.extend<CodeBlockOptions>({\n addOptions() {\n return {\n ...this.parent?.(),\n codeBlockLabels: undefined,\n } as CodeBlockOptions;\n },\n // Built-in `code` tokens often win over chart's custom fence tokenizer;\n // upgrade ```tmr-chart here so the mid-column card editor renders ChartView.\n parseMarkdown: (token, helpers) =>\n parseCodeTokenAsChartOrCodeBlock(token, helpers, 'codeBlock'),\n addNodeView() {\n return ReactNodeViewRenderer(CodeBlockView);\n },\n addKeyboardShortcuts() {\n return {\n Backspace: () => {\n const { state } = this.editor;\n const { selection } = state;\n const { empty, $anchor } = selection;\n\n // 1) 光标在「非空代码块」内容最前面:拦截,防止拆块漏文字(空块放行可删)\n if (\n empty &&\n $anchor.parent.type.name === this.name &&\n $anchor.parentOffset === 0 &&\n $anchor.parent.content.size > 0\n ) {\n return true;\n }\n\n // 2) 光标在「代码块后方块」的开头:先选中整个代码块(二次确认),不直接删\n if (empty && $anchor.parentOffset === 0) {\n const before = $anchor.before($anchor.depth);\n const prevNode = state.doc.resolve(before).nodeBefore;\n if (prevNode?.type.name === this.name) {\n const codeBlockPos = before - prevNode.nodeSize;\n this.editor.chain().setNodeSelection(codeBlockPos).run();\n return true;\n }\n }\n\n return false;\n },\n };\n },\n});\n\n// 块级图片:Backspace 二次确认删除(与代码块一致)。\nconst ImageWithConfirmDelete = Image.extend({\n addKeyboardShortcuts() {\n return {\n Backspace: () => {\n const { state } = this.editor;\n const { selection } = state;\n const { empty, $anchor } = selection;\n if (empty) {\n const nodeBefore = $anchor.nodeBefore;\n if (nodeBefore?.type.name === this.name) {\n const imagePos = $anchor.pos - nodeBefore.nodeSize;\n this.editor.chain().setNodeSelection(imagePos).run();\n return true;\n }\n }\n return false;\n },\n };\n },\n});\n\n/** 浮动条相对其定位上下文的偏移(数字按 px)。内部路径的上下文是编辑器,portal 路径是宿主容器。 */\nexport interface FindBarOffset {\n top?: number | string;\n right?: number | string;\n bottom?: number | string;\n left?: number | string;\n}\n\nconst DEFAULT_FIND_BAR_OFFSET: FindBarOffset = { top: 4, right: 4 };\n\nfunction findBarOffsetStyle(offset: FindBarOffset): CSSProperties {\n const px = (v: number | string | undefined) =>\n typeof v === 'number' ? `${v}px` : v;\n return {\n position: 'absolute',\n top: px(offset.top),\n right: px(offset.right),\n bottom: px(offset.bottom),\n left: px(offset.left),\n };\n}\n\nexport interface MarkdownWysiwygEditorHandle {\n /** 取当前正文的 markdown 字符串。 */\n getMarkdown: () => string;\n /** 取当前正文的 HTML 字符串。 */\n getHTML: () => string;\n /** 取当前正文的 Tiptap JSON。 */\n getJSON: () => Record<string, unknown>;\n /** 底层 Tiptap Editor 实例(可能为 null,未就绪时)。 */\n getEditor: () => Editor | null;\n /** 聚焦评论:设 active + 滚动 + 光标落到区间起点。找不到返回 false。 */\n focusComment: (commentId: string) => boolean;\n /** 按文档顺序跳转评论(next / prev),返回目标 commentId。 */\n nextComment: (dir?: 'next' | 'prev') => string | null;\n /** 当前 doc 内已锚定的去重 commentId 列表(文档顺序)。 */\n getCommentIds: () => string[];\n /** 打开编辑器自带的查找浮动条(宿主自己绑快捷键/按钮时用)。findBar={false} 时不生效。 */\n openFind: () => void;\n /** 收起自带浮动条,清空高亮并把焦点还给编辑器。findBar={false} 时不生效。 */\n closeFind: () => void;\n}\n\nexport interface MarkdownWysiwygEditorProps {\n /** 初始 markdown 内容。 */\n initialMarkdown?: string;\n /**\n * 是否可编辑,默认 true。false = 只读渲染,与编辑态同源同路径:\n * 同一套扩展 / NodeView / 样式,交互件(代码块语言选择、删除等)自动收起。\n * 只读态不应用评论锚定(comments 被忽略),与 MarkdownPreview 语义一致。\n */\n editable?: boolean;\n /**\n * 初始脚注来源:按 index 对齐 `[^n]`,写入 citationRef 的 url/title。\n * 仅影响初始 content;后续插入请用 `insertMarkdown(editor, md, sources)`。\n */\n sources?: SourceRef[];\n /**\n * 脚注圆标 NodeView 插槽。消费方用 Popover 包住 `defaultDom`,\n * 用 `index` 查自己的数据源。仅初始化时生效。\n */\n renderCitation?: RenderCitation;\n placeholder?: string;\n /** editor 实例就绪 / 销毁时回调,供外部工具栏使用。 */\n onEditorReady?: (editor: Editor | null) => void;\n /** 目录变化回调(正文标题增删改时),供侧边目录实时展示。 */\n onTocChange?: (items: TocItem[]) => void;\n /**\n * 粘贴纯文本时启发式检测 markdown 并自动转富文本(Shift+粘贴保持纯文本)。\n * 默认 true。仅初始化时生效。\n */\n markdownPaste?: boolean;\n /**\n * 支持把 .md / .markdown 文件拖拽或粘贴进编辑器,解析后插入到落点/光标处。\n * 默认 true。仅初始化时生效。\n */\n markdownFileDrop?: boolean;\n /** 追加的 Tiptap 扩展(在内置扩展之后注册)。 */\n extraExtensions?: AnyExtension[];\n /** 代码块 NodeView 的本地化文案。 */\n codeBlockLabels?: Partial<CodeBlockLabels>;\n /**\n * 「这段正在被 AI 改写」的高亮:宿主在提交请求时给上、回填或冲突时传空数组清空。\n * 走 decoration,**不进 markdown、不进 undo 历史**,能盖住表格与图表这类块级节点。\n */\n pendingAnchors?: PendingAnchor[];\n /** 点击待改写高亮区域时回调,给出锚点 id(宿主可用来跳回/取消)。 */\n onAnchorClick?: (id: string) => void;\n /**\n * 选区变化。宿主用它做「选中即出现引用」——塌缩成光标也会报(`empty: true`),\n * 好让引用跟着消失;`kind` 区分普通文字 / 表格单元格 / 整节点(图表)。\n */\n onSelectionChange?: (selection: {\n from: number;\n to: number;\n empty: boolean;\n kind: SelectionKind;\n }) => void;\n /** 附加到滚动容器的 class。 */\n className?: string;\n /**\n * 编辑态评论锚定:评论列表(含已解码 segments)。装载时映射为 commentAnchor\n * mark 并高亮;markdown 导出自动剥离,只读态(MarkdownPreview)不渲染评论。\n * 注意:数组引用变化会触发重新铺 mark,宿主应 memo 该数组。\n */\n comments?: CommentRef[];\n /** 受控 active 评论 id(sidebar 联动)。null = 无 active。 */\n activeCommentId?: string | null;\n /** 编辑器内点击 mark / gutter 时回调。 */\n onCommentClick?: (payload: CommentClickPayload) => void;\n /** active 变化回调(点击 mark / gutter / nextComment 时)。 */\n onActiveCommentChange?: (commentId: string | null) => void;\n /** 是否在 block 左缘渲染评论 gutter 气泡,默认 true。 */\n showCommentGutter?: boolean;\n /**\n * 编辑器内点评论 mark 是否可交互(设 active / 上报 click),默认 true。\n * 只靠侧栏单项驱动滚动定位时传 false。\n */\n commentInteractive?: boolean;\n /**\n * 启用查找替换(默认 true):注册官方 `@tiptap/extension-find-and-replace`\n * (自带命令 `setSearchTerm / replace / replaceAll / goToNextResult …` 与\n * `editor.storage.findAndReplace`)。传 false 则连扩展一起不注册——此时命令与 storage 都不存在,\n * 宿主的自绘面板也无从驱动。\n */\n findReplace?: boolean;\n /**\n * 是否由编辑器渲染浮动条(默认跟随 {@link findReplace})。传 false = **定位交给宿主**:\n * 扩展照旧注册,但编辑器不出条子,宿主自己在任意位置渲染 `<FindReplaceBar editor={…} />`\n * (与工具栏同一套分工——组件归库,摆位归宿主)。此时 {@link findShortcut} 与\n * `handle.openFind/closeFind` 一并失效,因为内部没有条子可开。\n */\n findBar?: boolean;\n /**\n * 把自带的浮动条挂到宿主的容器里(antd `getPopupContainer` 那一套):给元素或返回元素的函数\n * 即可,开合状态与 Cmd/Ctrl+F 仍归库——只换挂载点。适合条子被 `overflow: hidden` 祖先裁掉、\n * 或想让它落在自己的头部 / 侧栏里。挂进去后**定位由宿主负责**(库不再加绝对定位),\n * 且容器若在主题子树之外,记得把 `--tmr-*` 变量也带到那里。\n * 返回 null / 不传时回落到编辑器内自带的浮动条。\n */\n findBarContainer?: HTMLElement | null | (() => HTMLElement | null);\n /**\n * 浮动条相对其定位上下文的偏移,默认 `{ top: 4, right: 4 }`(右上角)。数字按 px,也收 CSS 字符串。\n * 内部路径的上下文是编辑器(粘在滚动容器顶部的那层锚点),`findBarContainer` 路径的上下文是那个容器\n * ——那条路径下库会保证容器是定位上下文(computed position 为 static 时补 `position: relative`)。\n */\n findBarOffset?: FindBarOffset;\n /**\n * 焦点在编辑器内时接管 Cmd/Ctrl+F 打开**编辑器自带的**浮动条(默认 true;`findBar={false}`\n * 时不接管,免得抢了键却不弹东西)。传 false 则只保留 `handle.openFind()`——例如宿主想\n * 保留浏览器原生查找,或自己摆入口。焦点不在编辑器内时不接管,同页多编辑器不会互相抢。\n */\n findShortcut?: boolean;\n /** 查找替换浮动条的本地化文案。 */\n findLabels?: Partial<FindLabels>;\n}\n\n/**\n * 所见即所得 Markdown 编辑器(基于 Tiptap v3 + 官方 @tiptap/markdown)。\n * 内容进出均为 markdown 字符串。工具栏由外部渲染——通过 onEditorReady 拿到 editor 实例。\n */\nexport const MarkdownWysiwygEditor = forwardRef<\n MarkdownWysiwygEditorHandle,\n MarkdownWysiwygEditorProps\n>(function MarkdownWysiwygEditor(\n {\n initialMarkdown = '',\n editable = true,\n sources,\n renderCitation,\n placeholder,\n onEditorReady,\n onTocChange,\n markdownPaste = true,\n markdownFileDrop = true,\n extraExtensions,\n codeBlockLabels,\n className,\n comments,\n activeCommentId,\n onCommentClick,\n onActiveCommentChange,\n showCommentGutter = true,\n commentInteractive = true,\n pendingAnchors,\n onAnchorClick,\n onSelectionChange,\n findReplace = true,\n findBar = findReplace,\n findBarContainer,\n findBarOffset = DEFAULT_FIND_BAR_OFFSET,\n findShortcut = true,\n findLabels,\n },\n ref,\n) {\n const preparedInitial = prepareChartMarkdown(\n enrichMarkdownCitations(initialMarkdown, sources ?? []),\n );\n\n const [findOpen, setFindOpen] = useState(false);\n const findInputRef = useRef<HTMLInputElement | null>(null);\n\n const editor = useEditor({\n extensions: [\n ...baseExtensions,\n CodeBlock.configure({ lowlight, codeBlockLabels }),\n ImageWithConfirmDelete.configure({ inline: false }),\n ImportPlaceholder,\n createChart({ editable: false }),\n createCitationRef({ renderCitation }),\n CommentMark,\n commentAnchorExtension({\n showGutter: showCommentGutter,\n interactive: commentInteractive,\n }),\n Markdown,\n pendingAnchorExtension,\n // 官方查找替换:只出命令 / storage / 装饰,UI 自绘(见 FindReplaceBar)。\n // - injectCSS 关掉:它默认会往页面插一个 <style>,绕开宿主的 --tmr-* 主题与 style.css,\n // 命中样式改由 src/styles/find.css 承担。\n // - searchDebounceMs 关掉:官方防抖走 setTimeout,抛错会落在异步回调里兜不住;\n // 防抖改由浮动条自己做(见 findReplace.ts)。\n ...(findReplace\n ? [FindAndReplace.configure({ injectCSS: false, searchDebounceMs: 0 })]\n : []),\n TableOfContents.configure({\n getId: makeTocGetId(),\n onUpdate: (anchors) => {\n onTocChange?.(\n anchors\n .filter((a) => a.level <= 6)\n .map((a) => ({ id: a.id, level: a.level, text: a.textContent })),\n );\n },\n }),\n ...(markdownPaste ? [MarkdownPaste] : []),\n ...(markdownFileDrop ? [MarkdownFileDrop] : []),\n ...(extraExtensions ?? []),\n ],\n content: preparedInitial,\n contentType: 'markdown',\n editable,\n // Next.js SSR:服务端不立即渲染,避免 hydration 不一致\n immediatelyRender: false,\n editorProps: {\n attributes: {\n class: styles.editorContent,\n 'data-placeholder': placeholder ?? '',\n },\n },\n });\n\n useEffect(() => {\n onEditorReady?.(editor);\n return () => onEditorReady?.(null);\n }, [editor, onEditorReady]);\n\n // 运行时切换编辑/只读(同一实例,NodeView 交互件随 editor.isEditable 收起)。\n useEffect(() => {\n editor?.setEditable(editable);\n }, [editor, editable]);\n\n const closeFind = useCallback(() => {\n setFindOpen(false);\n // 焦点归还:Tiptap 的 focus 命令内部就是 requestAnimationFrame 延后执行的\n // (`delayedFocus`),正好落在 React 卸载浮动条之后——否则被卸载的输入框会把焦点丢给 body。\n editor?.commands.focus();\n }, [editor]);\n\n // Cmd/Ctrl+F → 打开查找条。接管条件必须收得比「焦点在编辑器内」松、比「谁都能接管」紧:\n // - 焦点在本编辑器内:接管 ✓\n // - 焦点不在任何输入控件里(body)且页面上只有本编辑器:接管 ✓(单编辑器页面点完工具栏按钮能直接按)\n // - 其余情况一律不接管:同页多编辑器时不会一起弹条(文档站就是这样),宿主的其它输入框\n // 也不会被夺走原生查找。多编辑器页面上宿主可自己调 handle.openFind()。\n // 只有容器里真有那条浮动条(findBar)时才绑:否则会白抢浏览器原生查找,却什么都不弹。\n useEffect(() => {\n if (!editor || !findReplace || !findBar || !findShortcut) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (!(event.metaKey || event.ctrlKey) || event.altKey || event.shiftKey) {\n return;\n }\n if (event.key !== 'f' && event.key !== 'F') return;\n const active = document.activeElement;\n const inEditor = !!active && editor.view.dom.contains(active);\n const nothingFocused = active === null || active === document.body;\n const soleEditor = document.querySelectorAll('.ProseMirror').length <= 1;\n if (!inEditor && !editor.isFocused && !(nothingFocused && soleEditor)) {\n return;\n }\n event.preventDefault();\n setFindOpen(true);\n // 已打开时再按一次:聚焦并全选当前查询(首次打开由浮动条的 autoFocus 负责)\n requestAnimationFrame(() => findInputRef.current?.select());\n };\n document.addEventListener('keydown', onKeyDown, true);\n return () => document.removeEventListener('keydown', onKeyDown, true);\n }, [editor, findReplace, findBar, findShortcut]);\n\n // 评论列表 → 铺 mark。用 commentId 签名做防抖:宿主每次渲染传新数组引用时\n // 不会反复清/铺(清空再重铺会丢掉 mark 随编辑移动后的位置)。\n const commentsSignatureRef = useRef<string>('');\n useEffect(() => {\n // 只读态不接评论(与库的「评论锚定 = 编辑会话专属」契约一致)。\n if (!editor || !editable) return;\n const signature = (comments ?? [])\n .map((c) => `${c.commentId}:${c.segments.length}`)\n .join('|');\n if (signature === commentsSignatureRef.current) return;\n commentsSignatureRef.current = signature;\n applyCommentAnchorsToEditor(editor, comments ?? []);\n }, [editor, editable, comments]);\n\n // active 同步到插件(mark/block 高亮装饰);滚动定位走 handle.focusComment。\n useEffect(() => {\n if (!editor) return;\n editor.view.dispatch(\n editor.state.tr.setMeta(\n COMMENT_ACTIVE_META,\n activeCommentId ?? null,\n ),\n );\n }, [editor, activeCommentId]);\n\n // 待改写高亮:会话级装饰,不进 markdown / 不进 undo(宿主推入,回填或冲突时清空)。\n useEffect(() => {\n if (!editor) return;\n setPendingAnchors(editor, pendingAnchors ?? []);\n }, [editor, pendingAnchors]);\n\n // 点击待改写高亮 → 上报锚点 id。走 DOM 监听而不是插件 meta:这里只要「点了哪一段」。\n const onAnchorClickRef = useRef(onAnchorClick);\n useEffect(() => {\n onAnchorClickRef.current = onAnchorClick;\n }, [onAnchorClick]);\n useEffect(() => {\n if (!editor) return;\n const dom = editor.view.dom;\n const onClick = (event: MouseEvent) => {\n const target = event.target as HTMLElement | null;\n const id = target?.closest?.('[data-pending-id]')?.getAttribute('data-pending-id');\n if (id) onAnchorClickRef.current?.(id);\n };\n dom.addEventListener('click', onClick);\n return () => dom.removeEventListener('click', onClick);\n }, [editor]);\n\n // 选区变化:宿主据此做「选中即出现引用 / 引用跟着选区走」。\n const onSelectionChangeRef = useRef(onSelectionChange);\n useEffect(() => {\n onSelectionChangeRef.current = onSelectionChange;\n }, [onSelectionChange]);\n useEffect(() => {\n if (!editor) return;\n const onSelectionUpdate = () => {\n const { from, to, empty } = editor.state.selection;\n onSelectionChangeRef.current?.({\n from,\n to,\n empty,\n kind: selectionKind(editor.state.selection),\n });\n };\n editor.on('selectionUpdate', onSelectionUpdate);\n return () => {\n editor.off('selectionUpdate', onSelectionUpdate);\n };\n }, [editor]);\n\n // mark / gutter 点击 → 通过 transaction meta 上报宿主(回调走 ref 防 stale)。\n const onCommentClickRef = useRef(onCommentClick);\n const onActiveCommentChangeRef = useRef(onActiveCommentChange);\n onCommentClickRef.current = onCommentClick;\n onActiveCommentChangeRef.current = onActiveCommentChange;\n useEffect(() => {\n if (!editor) return;\n const onTransaction = ({\n transaction,\n }: {\n transaction: { getMeta: (key: string) => unknown };\n }) => {\n const click = transaction.getMeta(COMMENT_CLICK_META) as\n | CommentClickPayload\n | undefined;\n if (click) {\n onCommentClickRef.current?.(click);\n onActiveCommentChangeRef.current?.(click.commentIds[0] ?? null);\n }\n const gutter = transaction.getMeta(COMMENT_GUTTER_META) as\n | { commentIds: string[]; pos: number }\n | undefined;\n if (gutter) {\n onCommentClickRef.current?.({\n commentIds: gutter.commentIds,\n anchorEl: null,\n pos: gutter.pos,\n });\n onActiveCommentChangeRef.current?.(gutter.commentIds[0] ?? null);\n }\n };\n editor.on('transaction', onTransaction);\n return () => {\n editor.off('transaction', onTransaction);\n };\n }, [editor]);\n\n useImperativeHandle(\n ref,\n () => ({\n getMarkdown: () => editor?.getMarkdown?.() ?? '',\n getHTML: () => editor?.getHTML?.() ?? '',\n getJSON: () => (editor?.getJSON?.() as Record<string, unknown>) ?? {},\n getEditor: () => editor ?? null,\n focusComment: (commentId: string) =>\n editor ? focusComment(editor, commentId) : false,\n nextComment: (dir?: 'next' | 'prev') =>\n editor ? nextComment(editor, dir ?? 'next') : null,\n getCommentIds: () => (editor ? collectCommentIds(editor) : []),\n openFind: () => setFindOpen(true),\n closeFind,\n }),\n [editor, closeFind],\n );\n\n // 宿主指定了容器就把条子 portal 进去;解析不到则回落到编辑器内的粘性锚点。\n const findBarTarget =\n typeof findBarContainer === 'function'\n ? findBarContainer()\n : (findBarContainer ?? null);\n\n // 条子是绝对定位的:容器得先是定位上下文。宿主容器是 static 时补一个 relative——\n // 不补的话条子会以「最近的定位祖先」为基准(可能是页面),位置会莫名其妙。\n useEffect(() => {\n if (!findBarTarget) return;\n if (getComputedStyle(findBarTarget).position === 'static') {\n findBarTarget.style.position = 'relative';\n }\n }, [findBarTarget]);\n\n const findBarNode =\n editor && findBar && findOpen ? (\n <FindReplaceBar\n editor={editor}\n labels={findLabels}\n onClose={closeFind}\n inputRef={findInputRef}\n className={styles.findBar}\n style={findBarOffsetStyle(findBarOffset)}\n />\n ) : null;\n\n return (\n <div className={styles.editorHost}>\n {/* 粘性锚点排在正文之前:浮动条跟着最近的滚动容器走,正文滚动时不会被卷上去 */}\n {findBarNode && !findBarTarget ? (\n <div className={styles.findBarAnchor}>{findBarNode}</div>\n ) : null}\n {findBarNode && findBarTarget\n ? createPortal(findBarNode, findBarTarget)\n : null}\n <EditorContent\n editor={editor}\n className={\n className ? `${styles.editorScroll} ${className}` : styles.editorScroll\n }\n />\n </div>\n );\n});\n","'use client';\n\nimport { Markdown } from '@tiptap/markdown';\nimport { EditorContent, useEditor } from '@tiptap/react';\nimport { useEffect, useMemo } from 'react';\nimport { createChart } from '../chart/createChart';\nimport { prepareChartMarkdown } from '../chart/prepareChartMarkdown';\nimport {\n enrichMarkdownCitations,\n type SourceRef,\n} from '../citationUtils';\nimport type { RenderCitation } from '../citationTypes';\nimport { createCitationRef } from '../createCitationRef';\nimport { baseExtensions, pureCodeBlock, pureImage } from '../extensions';\nimport '../styles/chart.css';\nimport styles from '../styles/content.module.css';\n\nexport interface MarkdownPreviewProps {\n /** 要预览的 markdown 字符串。 */\n markdown: string;\n /**\n * 脚注来源列表:按 `index` 与正文 `[^n]` 对齐,写入节点的 url/title。\n * 业务数据与 Popover 仍由消费方通过 {@link renderCitation} 完成。\n */\n sources?: SourceRef[];\n /**\n * 脚注圆标 NodeView 插槽。用 Popover 等包住 `defaultDom`;\n * 用 `index` / `attrs` 查消费方自己的数据源。\n */\n renderCitation?: RenderCitation;\n className?: string;\n}\n\n/**\n * 轻量只读 markdown 预览(Tiptap + 官方 @tiptap/markdown,editable:false)。\n * 与 MarkdownWysiwygEditor 共用同一套 base 扩展与正文样式类,渲染同源——\n * 预览所见即编辑/插入后所得。用纯版 CodeBlock/Image(无 React 视图 / 删除快捷键);\n * 图表用只读 NodeView(可渲染,不可编辑弹层)。\n *\n * 这是「客户端只读预览」;若需 SEO / 无 JS 静态渲染,请改用 server 入口的\n * renderReportHtml + ReportContent / ReportContentWithCharts。\n */\nexport function MarkdownPreview({\n markdown,\n sources,\n renderCitation,\n className,\n}: MarkdownPreviewProps) {\n const prepared = useMemo(\n () =>\n prepareChartMarkdown(\n enrichMarkdownCitations(markdown, sources ?? []),\n ),\n [markdown, sources],\n );\n\n const extensions = useMemo(\n () => [\n ...baseExtensions,\n pureCodeBlock,\n pureImage,\n createChart({ editable: false }),\n createCitationRef({ renderCitation }),\n Markdown,\n ],\n [renderCitation],\n );\n\n const editor = useEditor(\n {\n extensions,\n content: prepared,\n contentType: 'markdown',\n editable: false,\n immediatelyRender: false,\n editorProps: {\n attributes: { class: styles.editorContent },\n },\n },\n [extensions],\n );\n\n useEffect(() => {\n if (!editor) return;\n editor.commands.setContent(prepared, { contentType: 'markdown' });\n }, [editor, prepared]);\n\n return (\n <EditorContent\n editor={editor}\n className={className ?? styles.editorScroll}\n />\n );\n}\n","import type { ToolbarLabels } from './labels';\n\n/** 包内唯一识别的扩展名:命中即本地读文本,其余一律交给宿主回调。 */\nexport const MD_FILE_RE = /\\.(md|markdown)$/i;\nexport const MD_ACCEPT = '.md,.markdown,text/markdown';\n\n/** 主栏导入下拉里的一项。`accept` 写到隐藏 file input。 */\nexport interface ImportMenuItem {\n key: string;\n label: string;\n accept: string;\n}\n\nexport function resolveImportMenuItems({\n labels,\n onImportDocument,\n importAccept,\n importMenuItems,\n}: {\n labels: ToolbarLabels;\n onImportDocument?: unknown;\n importAccept?: string;\n importMenuItems?: ImportMenuItem[];\n}): ImportMenuItem[] {\n if (importMenuItems?.length) return importMenuItems;\n const markdown: ImportMenuItem = {\n key: 'markdown',\n label: labels.importMarkdown,\n accept: MD_ACCEPT,\n };\n if (onImportDocument && importAccept) {\n return [\n markdown,\n {\n key: 'document',\n label: labels.importDocumentOther,\n accept: importAccept,\n },\n ];\n }\n return [markdown];\n}\n","import '@tiptap/markdown';\nimport type { Editor } from '@tiptap/react';\nimport { prepareChartMarkdown } from './chart/prepareChartMarkdown';\nimport {\n enrichMarkdownCitations,\n type SourceRef,\n} from './citationUtils';\n\n/**\n * 在光标处插入 markdown 片段(封装 contentType: 'markdown')。\n * 传入 `sources` 时会先 enrich `[^n]` → 带 url 的 citation-ref,再插入。\n *\n * 整段过不了 schema(嵌套 bold、块级图进 listItem 等)时按块重试,\n * 单块仍挂则剥标记当段落。某一处脏输出不至于整次插入失败。\n */\nexport function insertMarkdown(\n editor: Editor,\n markdown: string,\n sources: SourceRef[] = [],\n): void {\n const prepared = prepareChartMarkdown(\n enrichMarkdownCitations(markdown, sources),\n );\n if (!prepared) return;\n if (tryInsertMarkdown(editor, prepared)) return;\n for (const block of splitTopLevelBlocks(prepared)) {\n if (tryInsertMarkdown(editor, block)) continue;\n insertPlainParagraph(editor, stripToPlainText(block));\n }\n}\n\nfunction tryInsertMarkdown(editor: Editor, markdown: string): boolean {\n try {\n return editor\n .chain()\n .focus()\n .insertContent(markdown, { contentType: 'markdown' })\n .run();\n } catch {\n return false;\n }\n}\n\nfunction insertPlainParagraph(editor: Editor, text: string): void {\n if (!text) return;\n editor\n .chain()\n .focus()\n .insertContent({\n type: 'paragraph',\n content: [{ type: 'text', text }],\n })\n .run();\n}\n\n/** 围栏代码整块留下,其余按空行切。 */\nexport function splitTopLevelBlocks(markdown: string): string[] {\n const out: string[] = [];\n for (const [i, part] of markdown.split(/(```[\\s\\S]*?```)/).entries()) {\n if (!part) continue;\n if (i % 2 === 1) {\n out.push(part);\n continue;\n }\n for (const block of part.split(/\\n{2,}/)) {\n if (block.trim()) out.push(block);\n }\n }\n return out;\n}\n\nexport function stripToPlainText(markdown: string): string {\n return markdown\n .replace(/!\\[[^\\]]*\\]\\([^)]+\\)/g, '')\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, '$1')\n .replace(/^#{1,6}\\s+/gm, '')\n .replace(/^[ \\t]*[-*+]\\s+/gm, '')\n .replace(/^[ \\t]*\\d+\\.\\s+/gm, '')\n .replace(/[*_~`]+/g, '')\n .replace(/<[^>]+>/g, '')\n .replace(/\\|/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n","import type { Editor } from '@tiptap/core';\nimport type { EditorState } from '@tiptap/pm/state';\nimport {\n CellSelection,\n isInTable,\n rowIsHeader,\n selectedRect,\n} from '@tiptap/pm/tables';\n\nexport interface TableSelectionInfo {\n rowCount: number;\n colCount: number;\n /** 选区跨越多行或多列时为 true(用于带 N 的文案)。 */\n isMultiCell: boolean;\n includesHeaderRow: boolean;\n coversAllRows: boolean;\n coversAllCols: boolean;\n}\n\n/** 当前若不在表格内返回 null。 */\nexport function getTableSelectionInfo(\n state: EditorState,\n): TableSelectionInfo | null {\n if (!isInTable(state)) return null;\n\n const rect = selectedRect(state);\n const rowCount = Math.max(1, rect.bottom - rect.top);\n const colCount = Math.max(1, rect.right - rect.left);\n\n let includesHeaderRow = false;\n for (let row = rect.top; row < rect.bottom; row++) {\n if (rowIsHeader(rect.map, rect.table, row)) {\n includesHeaderRow = true;\n break;\n }\n }\n\n return {\n rowCount,\n colCount,\n isMultiCell: rowCount > 1 || colCount > 1,\n includesHeaderRow,\n coversAllRows: rect.top === 0 && rect.bottom === rect.map.height,\n coversAllCols: rect.left === 0 && rect.right === rect.map.width,\n };\n}\n\n/** 文档坐标是否落在 CellSelection 覆盖的某个单元格内(含单元格节点本身)。 */\nexport function isPosInCellSelection(\n selection: CellSelection,\n pos: number,\n): boolean {\n let found = false;\n selection.forEachCell((node, cellPos) => {\n if (pos >= cellPos && pos <= cellPos + node.nodeSize) {\n found = true;\n }\n });\n return found;\n}\n\n/**\n * 表内右键:若点击落在已有多格选区内则保留选区;\n * 否则把光标落到点击位置(单格操作)。\n */\nexport function preserveTableSelectionOnContextMenu(\n editor: Editor,\n pos: number,\n): void {\n const { selection } = editor.state;\n if (\n selection instanceof CellSelection &&\n isPosInCellSelection(selection, pos)\n ) {\n editor.view.focus();\n return;\n }\n editor.chain().focus().setTextSelection(pos).run();\n}\n\nexport function addRowsBefore(editor: Editor, count: number): boolean {\n const n = Math.max(1, count);\n for (let i = 0; i < n; i++) {\n if (!editor.commands.addRowBefore()) return false;\n }\n return true;\n}\n\nexport function addRowsAfter(editor: Editor, count: number): boolean {\n const n = Math.max(1, count);\n for (let i = 0; i < n; i++) {\n if (!editor.commands.addRowAfter()) return false;\n }\n return true;\n}\n\nexport function addColumnsBefore(editor: Editor, count: number): boolean {\n const n = Math.max(1, count);\n for (let i = 0; i < n; i++) {\n if (!editor.commands.addColumnBefore()) return false;\n }\n return true;\n}\n\nexport function addColumnsAfter(editor: Editor, count: number): boolean {\n const n = Math.max(1, count);\n for (let i = 0; i < n; i++) {\n if (!editor.commands.addColumnAfter()) return false;\n }\n return true;\n}\n\n/** 删行:全表行被选中时改为删整表;含表头时调用方应先禁用。 */\nexport function deleteSelectedRows(editor: Editor): boolean {\n const info = getTableSelectionInfo(editor.state);\n if (!info) return false;\n if (info.coversAllRows) return editor.commands.deleteTable();\n return editor.commands.deleteRow();\n}\n\n/** 删列:选区覆盖全部列且同时覆盖全部行时删整表;仅覆盖全部列时失败(由 UI 禁用)。 */\nexport function deleteSelectedColumns(editor: Editor): boolean {\n const info = getTableSelectionInfo(editor.state);\n if (!info) return false;\n if (info.coversAllCols) {\n if (info.coversAllRows) return editor.commands.deleteTable();\n return false;\n }\n return editor.commands.deleteColumn();\n}\n","'use client';\n\nimport { defaultColorPaletteLabels, type ColorPaletteLabels } from '../labels';\nimport styles from '../styles/colorPalette.module.css';\n\n/**\n * 色板矩阵:10 个色相 × 6 个明度。\n * 第 1 行为纯色(最饱和),下方 5 行为同色相的明→暗变体。\n */\nconst PALETTE: string[][] = [\n ['#8b0000', '#ff0000', '#ff9100', '#ffeb00', '#00e000', '#00e5ff', '#4a86e8', '#0000ff', '#9900ff', '#ff00ff'],\n ['#dba0a0', '#e8b4c0', '#f5d9b8', '#f7f0c0', '#cfe8c4', '#bcd9d4', '#c4d4ec', '#cdd4e8', '#d6c4e0', '#e8c4dc'],\n ['#d28a8a', '#dd8c9c', '#eec49a', '#f0e29c', '#a9d4a0', '#94c0bc', '#a0bce4', '#a4b0d8', '#bca0d0', '#d49cc0'],\n ['#cc4444', '#d4506c', '#e89a5c', '#e8d05c', '#7cc06c', '#5ca09c', '#5c90e0', '#6478c8', '#9460c0', '#c45c98'],\n ['#a02020', '#b01030', '#c87410', '#c8a810', '#449030', '#2c706c', '#3060c0', '#1850a0', '#6428a0', '#a02868'],\n ['#5c1010', '#700818', '#7c4808', '#7c6808', '#205818', '#10403c', '#183c78', '#0c3060', '#3c1460', '#601838'],\n];\n\n// THEME 品牌色\nconst THEME_COLORS = ['#ff6719', '#ff5500'];\n\nexport interface ColorPaletteProps {\n /** 当前已应用的颜色(用于打勾),无则不选中。 */\n value?: string;\n /** 点击某色块。null 表示「None」(清除)。 */\n onPick: (color: string | null) => void;\n labels?: Partial<ColorPaletteLabels>;\n}\n\n/** 颜色面板:None 清除行 + 色板网格 + THEME 品牌色。 */\nexport function ColorPalette({ value, onPick, labels }: ColorPaletteProps) {\n const t = { ...defaultColorPaletteLabels, ...labels };\n const current = value?.toLowerCase();\n\n return (\n <div className={styles.palette}>\n <button\n type=\"button\"\n className={styles.noneRow}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onPick(null)}\n >\n <span className={styles.noneIcon} aria-hidden />\n <span className={styles.noneLabel}>{t.none}</span>\n </button>\n\n <div className={styles.grid}>\n {PALETTE.flat().map((c) => (\n <button\n key={c}\n type=\"button\"\n className={`${styles.swatch} ${\n current === c.toLowerCase() ? styles.swatchActive : ''\n }`}\n style={{ background: c }}\n title={c}\n aria-label={c}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onPick(c)}\n />\n ))}\n </div>\n\n <div className={styles.themeLabel}>{t.theme}</div>\n <div className={styles.themeRow}>\n {THEME_COLORS.map((c) => (\n <button\n key={c}\n type=\"button\"\n className={`${styles.swatch} ${\n current === c.toLowerCase() ? styles.swatchActive : ''\n }`}\n style={{ background: c }}\n title={c}\n aria-label={c}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => onPick(c)}\n />\n ))}\n </div>\n </div>\n );\n}\n","'use client';\n\nimport type { Editor } from '@tiptap/react';\nimport {\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type RefObject,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport { renderMathInto, type MathKind } from '../math';\nimport styles from '../styles/toolbar.module.css';\n\nexport interface MathEditorPopoverProps {\n editor: Editor;\n kind: MathKind;\n mode: 'insert' | 'edit';\n pos?: number;\n latex: string;\n /** 工具栏新插入:取消时删掉占位节点 */\n isNew?: boolean;\n newLabel: string;\n placeholder: string;\n doneLabel: string;\n onConfirm: (latex: string) => void;\n onCancel: () => void;\n}\n\nfunction resolveNodeEl(editor: Editor, pos: number): HTMLElement | null {\n const dom = editor.view.nodeDOM(pos);\n if (dom instanceof HTMLElement) return dom;\n if (dom instanceof Node) return dom.parentElement;\n return null;\n}\n\nfunction mathRenderTarget(el: HTMLElement, isBlock: boolean): HTMLElement {\n if (!isBlock) return el;\n return (el.querySelector('.block-math-inner') as HTMLElement | null) ?? el;\n}\n\nfunction getMathLayerStyle(\n editor: Editor,\n kind: MathKind,\n pos?: number,\n): CSSProperties {\n const host = editor.view.dom.parentElement;\n if (!host) return {};\n const hostRect = host.getBoundingClientRect();\n const editorRect = editor.view.dom.getBoundingClientRect();\n const gap = 6;\n const blockWidth = editor.view.dom.clientWidth;\n\n if (pos != null) {\n const el = resolveNodeEl(editor, pos);\n if (el) {\n const r = el.getBoundingClientRect();\n const top = r.bottom - hostRect.top + gap;\n if (kind === 'block') {\n return {\n left: editorRect.left - hostRect.left,\n top,\n width: blockWidth,\n };\n }\n return {\n left: r.left - hostRect.left,\n top,\n };\n }\n }\n\n const coords = editor.view.coordsAtPos(editor.state.selection.from);\n if (kind === 'block') {\n return {\n left: editorRect.left - hostRect.left,\n top: coords.bottom - hostRect.top + gap,\n width: blockWidth,\n };\n }\n return {\n left: coords.left - hostRect.left,\n top: coords.bottom - hostRect.top + gap,\n };\n}\n\nexport function MathEditorPopover({\n editor,\n kind,\n mode,\n pos,\n latex,\n isNew = false,\n newLabel,\n placeholder,\n doneLabel,\n onConfirm,\n onCancel,\n}: MathEditorPopoverProps) {\n const [draft, setDraft] = useState(latex);\n const [layerStyle, setLayerStyle] = useState<CSSProperties>(() =>\n getMathLayerStyle(editor, kind, pos),\n );\n const titleId = useId();\n const inputRef = useRef<HTMLInputElement | HTMLTextAreaElement>(null);\n const rootRef = useRef<HTMLDivElement>(null);\n const isBlock = kind === 'block';\n const host = editor.view.dom.parentElement;\n\n useEffect(() => {\n setDraft(latex);\n }, [latex]);\n\n useEffect(() => {\n const update = () => setLayerStyle(getMathLayerStyle(editor, kind, pos));\n update();\n window.addEventListener('resize', update);\n return () => window.removeEventListener('resize', update);\n }, [editor, kind, pos, draft]);\n\n useEffect(() => {\n inputRef.current?.focus();\n }, []);\n\n useEffect(() => {\n if (pos == null) return;\n const el = resolveNodeEl(editor, pos);\n if (!el) return;\n el.classList.add('tmr-math-editing');\n return () => {\n el.classList.remove('tmr-math-editing');\n };\n }, [editor, pos]);\n\n useEffect(() => {\n if (pos == null) return;\n const el = resolveNodeEl(editor, pos);\n if (!el) return;\n const target = mathRenderTarget(el, isBlock);\n const src = draft.trim();\n if (src) renderMathInto(target, src, isBlock);\n else target.textContent = '';\n }, [draft, pos, editor, isBlock]);\n\n useEffect(() => {\n if (pos == null || isNew) return;\n const el = resolveNodeEl(editor, pos);\n if (!el) return;\n const target = mathRenderTarget(el, isBlock);\n return () => {\n const restore = latex.trim();\n if (restore) renderMathInto(target, restore, isBlock);\n else target.textContent = '';\n };\n }, [pos, editor, isBlock, latex, isNew]);\n\n useEffect(() => {\n const onPtr = (e: PointerEvent) => {\n const target = e.target;\n if (!(target instanceof Node)) return;\n if (rootRef.current?.contains(target)) return;\n if (pos != null) {\n const el = resolveNodeEl(editor, pos);\n if (el?.contains(target)) return;\n }\n onCancel();\n };\n document.addEventListener('pointerdown', onPtr);\n return () => document.removeEventListener('pointerdown', onPtr);\n }, [onCancel, editor, pos]);\n\n const canSubmit = draft.trim().length > 0;\n const showHint = !canSubmit && (mode === 'insert' || isNew);\n\n const submit = () => {\n if (!canSubmit) return;\n onConfirm(draft.trim());\n };\n\n const onKeyDown = (\n e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>,\n ) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onCancel();\n return;\n }\n if (e.key !== 'Enter') return;\n if (isBlock && !(e.metaKey || e.ctrlKey)) return;\n e.preventDefault();\n submit();\n };\n\n const field = isBlock ? (\n <textarea\n ref={inputRef as RefObject<HTMLTextAreaElement>}\n className={styles.mathInput}\n value={draft}\n placeholder={placeholder}\n rows={Math.max(3, draft.split('\\n').length)}\n aria-labelledby={titleId}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={onKeyDown}\n />\n ) : (\n <input\n ref={inputRef as RefObject<HTMLInputElement>}\n className={styles.mathInput}\n value={draft}\n placeholder={placeholder}\n aria-labelledby={titleId}\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={onKeyDown}\n />\n );\n\n if (!host) return null;\n\n return createPortal(\n <div\n ref={rootRef}\n className={styles.mathLayer}\n style={layerStyle}\n role=\"dialog\"\n aria-modal=\"false\"\n aria-labelledby={titleId}\n >\n <div\n className={\n isBlock\n ? `${styles.mathStack} ${styles.mathStackBlock}`\n : styles.mathStack\n }\n >\n {showHint ? (\n <div\n id={titleId}\n className={\n isBlock\n ? `${styles.mathHint} ${styles.mathHintBlock}`\n : styles.mathHint\n }\n >\n <span className={styles.mathHintIcon} aria-hidden>\n {isBlock ? 'TeX' : '√x'}\n </span>\n {newLabel}\n </div>\n ) : null}\n <div\n id={showHint ? undefined : titleId}\n className={\n isBlock\n ? `${styles.mathField} ${styles.mathFieldBlock}`\n : styles.mathField\n }\n >\n {field}\n <button\n type=\"button\"\n className={styles.mathDone}\n disabled={!canSubmit}\n title={\n isBlock ? `${doneLabel} (⌘/Ctrl+Enter)` : `${doneLabel} (Enter)`\n }\n onClick={submit}\n >\n {doneLabel}\n <span className={styles.mathDoneKbd} aria-hidden>\n ↵\n </span>\n </button>\n </div>\n </div>\n </div>,\n host,\n );\n}\n","'use client';\n\nimport * as Popover from '@radix-ui/react-popover';\nimport { useEditorState, type Editor } from '@tiptap/react';\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n BoldIcon,\n ChevronDownIcon,\n CodeIcon,\n ColumnAfterIcon,\n ColumnBeforeIcon,\n ColumnDeleteIcon,\n ImageIcon,\n ItalicIcon,\n LinkIcon,\n ListChecksIcon,\n ListOrderedIcon,\n ListUnorderedIcon,\n RedoIcon,\n RowAfterIcon,\n RowBeforeIcon,\n RowDeleteIcon,\n StrikethroughIcon,\n TableDeleteIcon,\n UnderlineIcon,\n UndoIcon,\n} from '../icons';\nimport { defaultToolbarLabels, type ToolbarLabels } from '../labels';\nimport {\n MD_FILE_RE,\n resolveImportMenuItems,\n type ImportMenuItem,\n} from '../importMenu';\nimport type { SourceRef } from '../citationUtils';\nimport { insertMarkdown } from '../insertMarkdown';\nimport { subscribeMathClick, type MathKind } from '../math';\nimport {\n addColumnsAfter,\n addColumnsBefore,\n addRowsAfter,\n addRowsBefore,\n deleteSelectedColumns,\n deleteSelectedRows,\n getTableSelectionInfo,\n preserveTableSelectionOnContextMenu,\n} from '../tableSelection';\nimport styles from '../styles/toolbar.module.css';\nimport { ColorPalette } from './ColorPalette';\nimport { MathEditorPopover } from './MathEditorPopover';\n\n/** `onImportDocument` 的成功返回。给字符串等价于 `{ markdown }`。 */\nexport interface ImportDocumentResult {\n markdown: string;\n sources?: SourceRef[];\n}\n\n/** 导入进度。包用来更新光标占位文案并禁用导入按钮。 */\nexport interface ImportDocumentProgress {\n /** 0–1。通常只有上传阶段可测;转换阶段可省略。 */\n ratio?: number;\n phase: 'upload' | 'convert';\n}\n\nexport interface ImportDocumentContext {\n /** 用户点取消或组件卸载时 abort,宿主据此中断请求。 */\n signal: AbortSignal;\n onProgress?: (p: ImportDocumentProgress) => void;\n}\n\n/** More 菜单里注入的自定义项(宿主用它扩展工具栏,如「导入项目报告」)。 */\nexport interface ExtraToolbarItem {\n key: string;\n /** 左侧图标插槽(可选,文字或 SVG 皆可)。 */\n icon?: ReactNode;\n label: string;\n disabled?: boolean;\n /** 点击回调,拿到 editor 实例自行操作(如 insertContent)。 */\n onSelect: (editor: Editor) => void;\n}\n\nexport interface EditorToolbarProps {\n editor: Editor;\n /**\n * 图片上传回调:收到文件,返回可访问的图片 URL。未提供则不显示图片按钮。\n * 抛错会转交 onError(..., 'image')。\n */\n onImageUpload?: (file: File) => Promise<string>;\n /**\n * 副作用错误回调(图片上传 / Markdown 导入失败),供宿主弹自己的提示。\n * `source` 区分来源,避免一律显示「图片上传失败」。\n */\n onError?: (err: unknown, source?: 'image' | 'markdown' | 'import') => void;\n /**\n * 非 Markdown 文件的转换:收到文件,返回可插入的 Markdown。未提供则导入只吃 .md。\n * 包内不校验扩展名——格式白名单由宿主的 `importAccept` 与本回调自己负责。\n * 抛错转交 onError(..., 'import');`AbortError` 视为用户取消,不报错。\n */\n onImportDocument?: (\n file: File,\n ctx: ImportDocumentContext,\n ) => Promise<ImportDocumentResult | string>;\n /**\n * 追加到导入 input 的 accept(默认已含 `.md,.markdown,text/markdown`)。\n * 例:`.doc,.docx,.csv,.pdf`。未传 `importMenuItems` 且传了 `onImportDocument` 时,\n * 下拉会多一项「Document」。\n */\n importAccept?: string;\n /**\n * 主栏导入下拉的选项。不传则 Markdown;再加 `onImportDocument` + `importAccept`\n * 时多一项 Document。宿主要拆成 Word / PDF 时自己传入。\n */\n importMenuItems?: ImportMenuItem[];\n /** 是否显示导入下拉,默认 `true`。卡片等场景可关掉。 */\n showImport?: boolean;\n labels?: Partial<ToolbarLabels>;\n /** 追加到 More 菜单末尾的自定义项。 */\n extraToolbarItems?: ExtraToolbarItem[];\n className?: string;\n}\n\nexport type { ImportMenuItem };\n\n/** 单个工具栏按钮:激活态高亮,disabled 时灰显。 */\nfunction ToolbarButton({\n title,\n active,\n disabled,\n busy,\n onClick,\n children,\n}: {\n title: string;\n active?: boolean;\n disabled?: boolean;\n busy?: boolean;\n onClick: () => void;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n title={title}\n aria-label={title}\n aria-pressed={active}\n aria-busy={busy}\n disabled={disabled}\n className={`${styles.btn} ${active ? styles.btnActive : ''}`}\n // mousedown + preventDefault 防止点击工具栏时编辑器失焦丢选区\n onMouseDown={(e) => e.preventDefault()}\n onClick={onClick}\n >\n {children}\n </button>\n );\n}\n\nfunction Divider() {\n return <span className={styles.divider} aria-hidden />;\n}\n\nfunction TableMenuItem({\n label,\n disabled,\n onClick,\n children,\n}: {\n label: string;\n disabled?: boolean;\n onClick: () => void;\n children: ReactNode;\n}) {\n return (\n <button\n type=\"button\"\n disabled={disabled}\n className={styles.tableMenuItem}\n onMouseDown={(e) => e.preventDefault()}\n onClick={onClick}\n >\n <span className={styles.tableMenuItemIcon} aria-hidden>\n {children}\n </span>\n <span className={styles.tableMenuItemLabel}>{label}</span>\n </button>\n );\n}\n\nfunction TableMenuDivider() {\n return <div className={styles.tableMenuDivider} aria-hidden />;\n}\n\n// 关闭当前菜单的回调(由 MenuPopover 注入,MenuItem 选中后调用以收起)。\nconst MenuCloseCtx = createContext<() => void>(() => {});\n\n/**\n * 菜单气泡:用 Radix Popover 而非 DropdownMenu——后者会强制抢焦点(menu 语义),\n * 打开即让编辑器 blur、丢选区;Popover 可 onOpenAutoFocus preventDefault 保持编辑器焦点。\n * 菜单项为普通 button(onMouseDown preventDefault 不夺焦),行为与原 antd 一致。\n */\nfunction MenuPopover({\n trigger,\n children,\n}: {\n trigger: ReactNode;\n children: ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n const close = useCallback(() => setOpen(false), []);\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger asChild>{trigger}</Popover.Trigger>\n <Popover.Portal>\n <Popover.Content\n className={styles.menu}\n sideOffset={4}\n align=\"start\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n >\n <MenuCloseCtx.Provider value={close}>\n {children}\n </MenuCloseCtx.Provider>\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\nfunction MenuItem({\n selected,\n disabled,\n onSelect,\n children,\n}: {\n selected?: boolean;\n disabled?: boolean;\n onSelect: () => void;\n children: ReactNode;\n}) {\n const close = useContext(MenuCloseCtx);\n return (\n <button\n type=\"button\"\n disabled={disabled}\n className={`${styles.menuItem} ${selected ? styles.menuItemSelected : ''}`}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => {\n onSelect();\n close();\n }}\n >\n {children}\n </button>\n );\n}\n\nconst TABLE_PICKER_COLS = 10;\nconst TABLE_PICKER_ROWS = 8;\n\n/**\n * More 菜单里的「插入表格」:二级面板用网格悬停选行列,点击插入。\n * 保持 Popover(不夺编辑器焦点),与 MenuItem 一致。\n */\nfunction TableInsertItem({\n disabled,\n labels,\n onInsert,\n}: {\n disabled?: boolean;\n labels: Pick<ToolbarLabels, 'tableInsert' | 'tableSizeSelected'>;\n onInsert: (rows: number, cols: number) => void;\n}) {\n const closeMenu = useContext(MenuCloseCtx);\n const [open, setOpen] = useState(false);\n const [hover, setHover] = useState({ cols: 0, rows: 0 });\n\n const resetHover = useCallback(() => setHover({ cols: 0, rows: 0 }), []);\n\n return (\n <Popover.Root\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) resetHover();\n }}\n >\n <Popover.Trigger asChild>\n <button\n type=\"button\"\n disabled={disabled}\n className={`${styles.menuItem} ${open ? styles.menuItemSelected : ''}`}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>⊞</span>\n {labels.tableInsert}\n </span>\n <ChevronDownIcon size={12} className={styles.tableInsertCaret} />\n </button>\n </Popover.Trigger>\n <Popover.Portal>\n <Popover.Content\n className={styles.tableSizePicker}\n side=\"right\"\n align=\"start\"\n sideOffset={6}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n >\n <div\n className={styles.tableSizeGrid}\n style={{\n gridTemplateColumns: `repeat(${TABLE_PICKER_COLS}, 1fr)`,\n }}\n onMouseLeave={resetHover}\n >\n {Array.from({ length: TABLE_PICKER_ROWS * TABLE_PICKER_COLS }, (_, i) => {\n const col = (i % TABLE_PICKER_COLS) + 1;\n const row = Math.floor(i / TABLE_PICKER_COLS) + 1;\n const active = hover.cols > 0 && col <= hover.cols && row <= hover.rows;\n return (\n <button\n key={i}\n type=\"button\"\n aria-label={labels.tableSizeSelected(col, row)}\n className={`${styles.tableSizeCell} ${active ? styles.tableSizeCellActive : ''}`}\n onMouseDown={(e) => e.preventDefault()}\n onMouseEnter={() => setHover({ cols: col, rows: row })}\n onClick={() => {\n onInsert(row, col);\n setOpen(false);\n resetHover();\n closeMenu();\n }}\n />\n );\n })}\n </div>\n <div className={styles.tableSizeLabel}>\n {hover.cols > 0\n ? labels.tableSizeSelected(hover.cols, hover.rows)\n : labels.tableInsert}\n </div>\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\n/** 颜色气泡:点色块即应用并关闭。 */\nfunction ColorPopover({\n title,\n glyph,\n bar,\n value,\n onPick,\n paletteLabels,\n}: {\n title: string;\n glyph: string;\n bar: string;\n value?: string;\n onPick: (color: string | null) => void;\n paletteLabels: { none: string; theme: string };\n}) {\n const [open, setOpen] = useState(false);\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n <Popover.Trigger asChild>\n <button\n type=\"button\"\n className={styles.btn}\n title={title}\n aria-label={title}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.colorIcon}>\n <span className={styles.colorIconGlyph}>{glyph}</span>\n <span className={styles.colorIconBar} style={{ background: bar }} />\n </span>\n </button>\n </Popover.Trigger>\n <Popover.Portal>\n <Popover.Content\n className={styles.popoverContent}\n sideOffset={4}\n align=\"start\"\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n >\n <ColorPalette\n value={value}\n onPick={(c) => {\n onPick(c);\n setOpen(false);\n }}\n labels={paletteLabels}\n />\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n\nconst HEADING_LEVELS = [1, 2, 3, 4, 5, 6] as const;\nconst FONT_SIZES = ['12px', '14px', '16px', '18px', '20px', '24px', '30px'] as const;\n\n/**\n * 顶部操作栏(antd-free,Radix Popover 菜单 + 内联 SVG 图标)。位置由父级控制,\n * 这里只渲染按钮 + 反映 editor 激活态。不含业务耦合,扩展项经 extraToolbarItems 注入。\n */\nexport function EditorToolbar({\n editor,\n onImageUpload,\n onError,\n onImportDocument,\n importAccept,\n importMenuItems,\n showImport = true,\n labels,\n extraToolbarItems,\n className,\n}: EditorToolbarProps) {\n const t: ToolbarLabels = { ...defaultToolbarLabels, ...labels };\n\n const state = useEditorState({\n editor,\n selector: ({ editor: e }) => ({\n bold: e.isActive('bold'),\n italic: e.isActive('italic'),\n underline: e.isActive('underline'),\n strike: e.isActive('strike'),\n code: e.isActive('code'),\n link: e.isActive('link'),\n taskList: e.isActive('taskList'),\n headingLevel: ([1, 2, 3, 4, 5, 6] as const).find((lv) =>\n e.isActive('heading', { level: lv }),\n ),\n fontSize: (e.getAttributes('textStyle').fontSize as string) || undefined,\n isParagraph: e.isActive('paragraph'),\n bulletList: e.isActive('bulletList'),\n orderedList: e.isActive('orderedList'),\n blockquote: e.isActive('blockquote'),\n textColor: (e.getAttributes('textStyle').color as string) || undefined,\n highlightColor:\n (e.getAttributes('highlight').color as string) || undefined,\n superscript: e.isActive('superscript'),\n subscript: e.isActive('subscript'),\n inTable: e.isActive('table'),\n canUndo: e.can().undo(),\n canRedo: e.can().redo(),\n }),\n });\n\n // 编辑器是否聚焦:仅正文聚焦时才允许调字号。Popover 菜单开/关已阻止抢焦点,\n // 故打开下拉不会误触 blur。\n const [editorFocused, setEditorFocused] = useState(() => editor.isFocused);\n useEffect(() => {\n const onFocus = () => setEditorFocused(true);\n const onBlur = () => setEditorFocused(false);\n editor.on('focus', onFocus);\n editor.on('blur', onBlur);\n return () => {\n editor.off('focus', onFocus);\n editor.off('blur', onBlur);\n };\n }, [editor]);\n\n const fileInputRef = useRef<HTMLInputElement>(null);\n const chain = () => editor.chain().focus();\n\n // ── 表格工具条(右键召唤):右键单元格时在鼠标处弹出,点别处/Esc 隐藏 ──\n const [tableMenu, setTableMenu] = useState<{ x: number; y: number } | null>(\n null,\n );\n const closeTableMenu = useCallback(() => setTableMenu(null), []);\n\n useEffect(() => {\n const dom = editor.view.dom;\n const onContextMenu = (e: MouseEvent) => {\n const coords = editor.view.posAtCoords({\n left: e.clientX,\n top: e.clientY,\n });\n if (!coords) return;\n const $pos = editor.state.doc.resolve(coords.pos);\n let inTable = false;\n for (let d = $pos.depth; d > 0; d--) {\n if ($pos.node(d).type.name === 'table') {\n inTable = true;\n break;\n }\n }\n if (!inTable) return;\n e.preventDefault();\n // 多格选区内右键:保留 CellSelection;选区外才落到点击位\n preserveTableSelectionOnContextMenu(editor, coords.pos);\n setTableMenu({ x: e.clientX, y: e.clientY });\n };\n dom.addEventListener('contextmenu', onContextMenu);\n return () => dom.removeEventListener('contextmenu', onContextMenu);\n }, [editor]);\n\n useEffect(() => {\n if (!tableMenu) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') closeTableMenu();\n };\n document.addEventListener('mousedown', closeTableMenu);\n document.addEventListener('keydown', onKey, true);\n return () => {\n document.removeEventListener('mousedown', closeTableMenu);\n document.removeEventListener('keydown', onKey, true);\n };\n }, [tableMenu, closeTableMenu]);\n\n const runTable = useCallback(\n (fn: () => void) => {\n fn();\n closeTableMenu();\n },\n [closeTableMenu],\n );\n\n const tableSel = tableMenu ? getTableSelectionInfo(editor.state) : null;\n const tableRowN = tableSel?.rowCount ?? 1;\n const tableColN = tableSel?.colCount ?? 1;\n const tableMulti = tableSel?.isMultiCell ?? false;\n const disableAddRowBefore = !!tableSel?.includesHeaderRow;\n const disableDeleteRow = !!tableSel?.includesHeaderRow;\n const disableDeleteColumn =\n !!tableSel?.coversAllCols && !tableSel?.coversAllRows;\n\n // ── 图片:选图 → onImageUpload → 插入返回的 URL ──\n const handlePickImage = () => fileInputRef.current?.click();\n const handleImageChange = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (!file || !onImageUpload) return;\n try {\n const url = await onImageUpload(file);\n if (!url) throw new Error('empty url');\n chain().setImage({ src: url }).run();\n } catch (err) {\n console.error('image upload failed:', err);\n onError?.(err, 'image');\n }\n };\n\n // ── 导入:.md 包内读文本插入;其余原样交给宿主 onImportDocument ──\n const importInputRef = useRef<HTMLInputElement>(null);\n const [importing, setImporting] = useState<ImportDocumentProgress | null>(\n null,\n );\n const importAbortRef = useRef<AbortController | null>(null);\n\n // 卸载(如切路由)中断在飞的导入,避免请求泄漏与卸载后 setState\n useEffect(() => () => importAbortRef.current?.abort(), []);\n\n const handleImportChange = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n e.target.value = '';\n if (!file) return;\n\n if (MD_FILE_RE.test(file.name)) {\n try {\n insertMarkdown(editor, await file.text());\n } catch (err) {\n console.error('markdown import failed:', err);\n onError?.(err, 'markdown');\n }\n return;\n }\n\n if (!onImportDocument) {\n onError?.(new Error(`unsupported file: ${file.name}`), 'import');\n return;\n }\n\n const ctrl = new AbortController();\n importAbortRef.current = ctrl;\n setImporting({ phase: 'upload', ratio: 0 });\n const labelOf = (p: ImportDocumentProgress) =>\n p.phase === 'convert'\n ? t.importDocumentConverting\n : t.importDocumentUploading(Math.round((p.ratio ?? 0) * 100));\n editor.commands.insertImportPlaceholder(labelOf({ phase: 'upload', ratio: 0 }));\n try {\n const raw = await onImportDocument(file, {\n signal: ctrl.signal,\n onProgress: (p) => {\n if (ctrl.signal.aborted) return;\n setImporting(p);\n editor.commands.updateImportPlaceholder(labelOf(p));\n },\n });\n editor.commands.removeImportPlaceholder();\n const md = typeof raw === 'string' ? raw : raw.markdown;\n const sources = typeof raw === 'string' ? [] : raw.sources ?? [];\n insertMarkdown(editor, md, sources);\n } catch (err) {\n editor.commands.removeImportPlaceholder();\n // 卸载 abort 不算错误\n if (!ctrl.signal.aborted) {\n console.error('document import failed:', err);\n onError?.(err, 'import');\n }\n } finally {\n if (importAbortRef.current === ctrl) importAbortRef.current = null;\n setImporting(null);\n }\n };\n\n const importItems = resolveImportMenuItems({\n labels: t,\n onImportDocument,\n importAccept,\n importMenuItems,\n });\n\n const pickImport = (accept: string) => {\n const input = importInputRef.current;\n if (!input) return;\n input.accept = accept;\n input.value = '';\n input.click();\n };\n\n // 进度写在光标占位上;按钮只区分空闲 / 忙碌。\n const importTitle = importing ? t.importDocumentBusy : t.importDocumentHint;\n\n const applyTextColor = (color: string | null) => {\n if (color) chain().setColor(color).run();\n else chain().unsetColor().run();\n };\n const applyHighlight = (color: string | null) => {\n if (color) chain().setHighlight({ color }).run();\n else chain().unsetHighlight().run();\n };\n\n const toggleLink = () => {\n if (state.link) {\n chain().unsetLink().run();\n return;\n }\n const url = window.prompt(t.linkPrompt);\n if (url) chain().setLink({ href: url }).run();\n };\n\n const setBlockStyle = (level: number) => {\n if (level === 0) chain().setParagraph().run();\n else\n chain()\n .toggleHeading({ level: level as 1 | 2 | 3 | 4 | 5 | 6 })\n .run();\n };\n\n const applyFontSize = (size: string) => {\n if (size) chain().setFontSize(size).run();\n else chain().unsetFontSize().run();\n };\n const canEditFontSize = editorFocused && state.isParagraph;\n\n const [mathEdit, setMathEdit] = useState<{\n kind: MathKind;\n mode: 'insert' | 'edit';\n pos?: number;\n latex: string;\n isNew?: boolean;\n } | null>(null);\n\n useEffect(() => subscribeMathClick((payload) => {\n setMathEdit({\n kind: payload.kind,\n mode: 'edit',\n pos: payload.pos,\n latex: payload.latex,\n });\n }), []);\n\n const openInsertMath = (kind: MathKind) => {\n const { from, to } = editor.state.selection;\n const selected =\n from === to ? '' : editor.state.doc.textBetween(from, to, ' ');\n const type = kind === 'inline' ? 'inlineMath' : 'blockMath';\n const searchFrom = from;\n chain().insertContent({ type, attrs: { latex: selected } }).run();\n let pos: number | null = null;\n editor.state.doc.nodesBetween(\n searchFrom,\n editor.state.doc.content.size,\n (node, nodePos) => {\n if (pos != null) return false;\n if (\n node.type.name === type &&\n String(node.attrs.latex ?? '') === selected\n ) {\n pos = nodePos;\n return false;\n }\n },\n );\n if (pos == null) {\n setMathEdit({ kind, mode: 'insert', latex: selected, isNew: true });\n return;\n }\n setMathEdit({\n kind,\n mode: 'edit',\n pos,\n latex: selected,\n isNew: true,\n });\n };\n\n const applyMath = (latex: string) => {\n if (!mathEdit) return;\n const { kind, mode, pos } = mathEdit;\n setMathEdit(null);\n if (mode === 'edit' && pos != null) {\n if (kind === 'inline') {\n chain().updateInlineMath({ latex, pos }).run();\n } else {\n chain().updateBlockMath({ latex, pos }).run();\n }\n return;\n }\n if (kind === 'inline') {\n chain().insertContent({ type: 'inlineMath', attrs: { latex } }).run();\n } else {\n chain().insertContent({ type: 'blockMath', attrs: { latex } }).run();\n }\n };\n\n const cancelMath = () => {\n if (!mathEdit) return;\n const { isNew, pos } = mathEdit;\n if (isNew && pos != null) {\n const node = editor.state.doc.nodeAt(pos);\n if (\n node &&\n (node.type.name === 'inlineMath' || node.type.name === 'blockMath')\n ) {\n editor\n .chain()\n .focus()\n .deleteRange({ from: pos, to: pos + node.nodeSize })\n .run();\n }\n }\n setMathEdit(null);\n };\n\n const scriptActive = state.superscript\n ? 'superscript'\n : state.subscript\n ? 'subscript'\n : 'normal';\n\n return (\n <>\n <div\n className={\n className ? `${styles.toolbar} ${className}` : styles.toolbar\n }\n >\n <div className={styles.inner}>\n {/* 撤销 / 重做 */}\n <ToolbarButton\n title={t.undo}\n disabled={!state.canUndo}\n onClick={() => chain().undo().run()}\n >\n <UndoIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.redo}\n disabled={!state.canRedo}\n onClick={() => chain().redo().run()}\n >\n <RedoIcon />\n </ToolbarButton>\n\n <Divider />\n\n {/* 段落样式下拉(正文 / 标题 1~6) */}\n <MenuPopover\n trigger={\n <button\n type=\"button\"\n className={styles.styleTrigger}\n title={t.style}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.styleTriggerLabel}>{t.style}</span>\n <ChevronDownIcon size={12} className={styles.styleTriggerCaret} />\n </button>\n }\n >\n <MenuItem\n selected={(state.headingLevel ?? 0) === 0}\n onSelect={() => setBlockStyle(0)}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>¶</span>\n {t.normalText}\n </span>\n </MenuItem>\n {HEADING_LEVELS.map((lv) => (\n <MenuItem\n key={lv}\n selected={state.headingLevel === lv}\n onSelect={() => setBlockStyle(lv)}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>{`H${lv}`}</span>\n {t.headingLabel(lv)}\n </span>\n </MenuItem>\n ))}\n </MenuPopover>\n\n {/* 正文字号下拉:仅正文可调 */}\n <MenuPopover\n trigger={\n <button\n type=\"button\"\n className={styles.styleTrigger}\n title={t.fontSize}\n aria-label={t.fontSize}\n disabled={!canEditFontSize}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.styleTriggerLabel}>\n {state.fontSize || t.fontSize}\n </span>\n <ChevronDownIcon size={12} className={styles.styleTriggerCaret} />\n </button>\n }\n >\n <MenuItem\n selected={!state.fontSize}\n onSelect={() => applyFontSize('')}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>A</span>\n {t.fontSizeDefault}\n </span>\n </MenuItem>\n {FONT_SIZES.map((size) => (\n <MenuItem\n key={size}\n selected={state.fontSize === size}\n onSelect={() => applyFontSize(size)}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>{parseInt(size, 10)}</span>\n {size}\n </span>\n </MenuItem>\n ))}\n </MenuPopover>\n\n <Divider />\n\n {/* 文字格式 */}\n <ToolbarButton\n title={t.bold}\n active={state.bold}\n onClick={() => chain().toggleBold().run()}\n >\n <BoldIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.italic}\n active={state.italic}\n onClick={() => chain().toggleItalic().run()}\n >\n <ItalicIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.underline}\n active={state.underline}\n onClick={() => chain().toggleUnderline().run()}\n >\n <UnderlineIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.strike}\n active={state.strike}\n onClick={() => chain().toggleStrike().run()}\n >\n <StrikethroughIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.code}\n active={state.code}\n onClick={() => chain().toggleCode().run()}\n >\n <CodeIcon />\n </ToolbarButton>\n\n {/* 文字颜色 */}\n <ColorPopover\n title={t.textColor}\n glyph=\"T\"\n bar={state.textColor || '#ff3b30'}\n value={state.textColor}\n onPick={applyTextColor}\n paletteLabels={{ none: t.colorNone, theme: t.colorTheme }}\n />\n {/* 文字高亮 */}\n <ColorPopover\n title={t.highlight}\n glyph=\"✎\"\n bar={state.highlightColor || '#ffd83d'}\n value={state.highlightColor}\n onPick={applyHighlight}\n paletteLabels={{ none: t.colorNone, theme: t.colorTheme }}\n />\n\n {/* 上标 / 下标下拉(A▾) */}\n <MenuPopover\n trigger={\n <button\n type=\"button\"\n className={`${styles.scriptTrigger} ${\n scriptActive !== 'normal' ? styles.btnActive : ''\n }`}\n title={t.scriptMenu}\n aria-label={t.scriptMenu}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.scriptTriggerGlyph}>A</span>\n <ChevronDownIcon size={12} className={styles.styleTriggerCaret} />\n </button>\n }\n >\n <MenuItem\n selected={scriptActive === 'normal'}\n onSelect={() => chain().unsetSuperscript().unsetSubscript().run()}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>A</span>\n {t.scriptNormal}\n </span>\n </MenuItem>\n <MenuItem\n selected={scriptActive === 'superscript'}\n onSelect={() => chain().unsetSubscript().toggleSuperscript().run()}\n >\n <span className={styles.styleItem}>\n <span className={`${styles.styleIcon} ${styles.scriptGlyph}`}>\n x<sup>2</sup>\n </span>\n {t.superscript}\n </span>\n </MenuItem>\n <MenuItem\n selected={scriptActive === 'subscript'}\n onSelect={() => chain().unsetSuperscript().toggleSubscript().run()}\n >\n <span className={styles.styleItem}>\n <span className={`${styles.styleIcon} ${styles.scriptGlyph}`}>\n x<sub>2</sub>\n </span>\n {t.subscript}\n </span>\n </MenuItem>\n </MenuPopover>\n\n <Divider />\n\n {/* 插入媒体 */}\n <ToolbarButton title={t.link} active={state.link} onClick={toggleLink}>\n <LinkIcon />\n </ToolbarButton>\n {onImageUpload ? (\n <>\n <ToolbarButton title={t.image} onClick={handlePickImage}>\n <ImageIcon />\n </ToolbarButton>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n hidden\n onChange={handleImageChange}\n />\n </>\n ) : null}\n {showImport ? (\n <MenuPopover\n trigger={\n <button\n type=\"button\"\n className={styles.styleTrigger}\n title={importTitle}\n aria-label={importTitle}\n aria-busy={!!importing}\n disabled={!!importing}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.styleTriggerLabel}>\n {t.importDocument}\n </span>\n <ChevronDownIcon\n size={12}\n className={styles.styleTriggerCaret}\n />\n </button>\n }\n >\n {importItems.map((item) => (\n <MenuItem\n key={item.key}\n onSelect={() => pickImport(item.accept)}\n >\n {item.label}\n </MenuItem>\n ))}\n </MenuPopover>\n ) : null}\n <ToolbarButton\n title={t.blockquote}\n active={state.blockquote}\n onClick={() => chain().toggleBlockquote().run()}\n >\n <span className={styles.txtIcon}>❝</span>\n </ToolbarButton>\n\n <Divider />\n\n {/* 列表 */}\n <ToolbarButton\n title={t.bulletList}\n active={state.bulletList}\n onClick={() => chain().toggleBulletList().run()}\n >\n <ListUnorderedIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.orderedList}\n active={state.orderedList}\n onClick={() => chain().toggleOrderedList().run()}\n >\n <ListOrderedIcon />\n </ToolbarButton>\n <ToolbarButton\n title={t.taskList}\n active={state.taskList}\n onClick={() => chain().toggleTaskList().run()}\n >\n <ListChecksIcon />\n </ToolbarButton>\n\n <Divider />\n\n {/* More 下拉(代码块、分割线、表格 + 宿主注入项) */}\n <MenuPopover\n trigger={\n <button\n type=\"button\"\n className={styles.styleTrigger}\n title={t.more}\n onMouseDown={(e) => e.preventDefault()}\n >\n <span className={styles.styleTriggerLabel}>{t.more}</span>\n <ChevronDownIcon size={12} className={styles.styleTriggerCaret} />\n </button>\n }\n >\n <MenuItem onSelect={() => chain().toggleCodeBlock().run()}>\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>{'{ }'}</span>\n {t.codeBlock}\n </span>\n </MenuItem>\n <MenuItem onSelect={() => openInsertMath('inline')}>\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>√x</span>\n {t.inlineMath}\n </span>\n </MenuItem>\n <MenuItem onSelect={() => openInsertMath('block')}>\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>∑</span>\n {t.blockMath}\n </span>\n </MenuItem>\n <MenuItem onSelect={() => chain().setHorizontalRule().run()}>\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>—</span>\n {t.hr}\n </span>\n </MenuItem>\n <TableInsertItem\n disabled={state.inTable}\n labels={t}\n onInsert={(rows, cols) =>\n chain()\n .insertTable({ rows, cols, withHeaderRow: true })\n .run()\n }\n />\n {extraToolbarItems?.map((item) => (\n <MenuItem\n key={item.key}\n disabled={item.disabled}\n onSelect={() => item.onSelect(editor)}\n >\n <span className={styles.styleItem}>\n <span className={styles.styleIcon}>{item.icon}</span>\n {item.label}\n </span>\n </MenuItem>\n ))}\n </MenuPopover>\n </div>\n </div>\n\n {/* 导入的隐藏文件选择器:accept 由下拉选项写入 */}\n {showImport ? (\n <input\n ref={importInputRef}\n type=\"file\"\n hidden\n onChange={handleImportChange}\n />\n ) : null}\n\n {mathEdit ? (\n <MathEditorPopover\n editor={editor}\n kind={mathEdit.kind}\n mode={mathEdit.mode}\n pos={mathEdit.pos}\n latex={mathEdit.latex}\n isNew={mathEdit.isNew}\n newLabel={\n mathEdit.kind === 'inline' ? t.mathNewInline : t.mathNewBlock\n }\n placeholder={t.mathPlaceholder}\n doneLabel={t.mathDone}\n onConfirm={applyMath}\n onCancel={cancelMath}\n />\n ) : null}\n\n {/* 表格右键菜单:纵向,图标 + 文案,分组分隔 */}\n {tableMenu &&\n createPortal(\n <div\n className={styles.tableBubble}\n style={{ position: 'fixed', left: tableMenu.x, top: tableMenu.y }}\n role=\"menu\"\n onMouseDown={(e) => e.stopPropagation()}\n onContextMenu={(e) => e.preventDefault()}\n >\n <TableMenuItem\n label={\n tableMulti\n ? t.tableAddColumnBeforeN(tableColN)\n : t.tableAddColumnBefore\n }\n onClick={() =>\n runTable(() => addColumnsBefore(editor, tableColN))\n }\n >\n <ColumnBeforeIcon />\n </TableMenuItem>\n <TableMenuItem\n label={\n tableMulti\n ? t.tableAddColumnAfterN(tableColN)\n : t.tableAddColumnAfter\n }\n onClick={() =>\n runTable(() => addColumnsAfter(editor, tableColN))\n }\n >\n <ColumnAfterIcon />\n </TableMenuItem>\n <TableMenuItem\n label={\n tableMulti\n ? t.tableDeleteColumnN(tableColN)\n : t.tableDeleteColumn\n }\n disabled={disableDeleteColumn}\n onClick={() =>\n runTable(() => {\n deleteSelectedColumns(editor);\n })\n }\n >\n <ColumnDeleteIcon />\n </TableMenuItem>\n <TableMenuDivider />\n <TableMenuItem\n label={\n tableMulti\n ? t.tableAddRowBeforeN(tableRowN)\n : t.tableAddRowBefore\n }\n disabled={disableAddRowBefore}\n onClick={() =>\n runTable(() => addRowsBefore(editor, tableRowN))\n }\n >\n <RowBeforeIcon />\n </TableMenuItem>\n <TableMenuItem\n label={\n tableMulti ? t.tableAddRowAfterN(tableRowN) : t.tableAddRowAfter\n }\n onClick={() => runTable(() => addRowsAfter(editor, tableRowN))}\n >\n <RowAfterIcon />\n </TableMenuItem>\n <TableMenuItem\n label={\n tableMulti ? t.tableDeleteRowN(tableRowN) : t.tableDeleteRow\n }\n disabled={disableDeleteRow}\n onClick={() =>\n runTable(() => {\n deleteSelectedRows(editor);\n })\n }\n >\n <RowDeleteIcon />\n </TableMenuItem>\n <TableMenuDivider />\n <TableMenuItem\n label={t.tableDeleteTable}\n onClick={() =>\n runTable(() => {\n editor.commands.deleteTable();\n })\n }\n >\n <TableDeleteIcon />\n </TableMenuItem>\n </div>,\n document.body,\n )}\n </>\n );\n}\n","import { useEffect, useState } from 'react';\n\n/**\n * 是否窄屏(默认 <768px)。取代原项目的 useDevice,内联为纯 matchMedia,\n * 无第三方依赖。SSR 首帧返回 false,挂载后按实际视口更新。\n */\nexport function useIsMobile(breakpoint = 768): boolean {\n const [isMobile, setIsMobile] = useState(false);\n\n useEffect(() => {\n const mq = window.matchMedia(`(max-width: ${breakpoint - 1}px)`);\n const update = () => setIsMobile(mq.matches);\n update();\n mq.addEventListener('change', update);\n return () => mq.removeEventListener('change', update);\n }, [breakpoint]);\n\n return isMobile;\n}\n","'use client';\n\nimport { useEffect, useRef, useState } from 'react';\nimport { useIsMobile } from '../hooks/useIsMobile';\nimport { ChevronDownIcon, ListUnorderedIcon, LockIcon, MenuIcon } from '../icons';\nimport { defaultTocLabels, type TocLabels } from '../labels';\nimport styles from '../styles/tocPanel.module.css';\nimport type { TocItem } from '../toc/extractToc';\n\nexport interface TocPanelProps {\n items: TocItem[];\n /** 当前高亮的锚点 id(阅读页由 IntersectionObserver 算、编辑页由光标章节算)。 */\n activeId?: string;\n /** 点击目录项。锁住项不触发。默认行为由调用方决定(滚动 / 跳转)。 */\n onItemClick?: (item: TocItem) => void;\n labels?: Partial<TocLabels>;\n}\n\n/**\n * 目录面板(阅读页 + 编辑页共用)。\n *\n * - 桌面:左侧粘性栏,可收起(«/»)。\n * - 移动:顶部可折叠「目录」条,选中后自动收起。\n * - 层级用左缩进;active accent 左边框 + 加粗;locked 置灰 + 锁图标不可点。\n *\n * 纯展示:滚动 / active 计算交给调用方,本组件只渲染 + 派发点击。\n */\nexport function TocPanel({ items, activeId, onItemClick, labels }: TocPanelProps) {\n const t = { ...defaultTocLabels, ...labels };\n const isMobile = useIsMobile();\n\n const [collapsed, setCollapsed] = useState(false);\n const [mobileOpen, setMobileOpen] = useState(false);\n\n const desktopNavRef = useRef<HTMLElement>(null);\n const mobilePanelRef = useRef<HTMLDivElement>(null);\n\n // activeId 变化时把当前高亮项滚入 TOC 可视区(仅在不可见时)。\n useEffect(() => {\n if (!activeId) return;\n const reduce = window.matchMedia(\n '(prefers-reduced-motion: reduce)',\n ).matches;\n const container = desktopNavRef.current || mobilePanelRef.current;\n if (!container) return;\n const el = container.querySelector(`a[href=\"#${CSS.escape(activeId)}\"]`);\n if (!el) return;\n el.scrollIntoView({\n block: 'nearest',\n behavior: reduce ? 'auto' : 'smooth',\n });\n }, [activeId]);\n\n if (!items.length) return null;\n\n const minLevel = Math.min(...items.map((i) => i.level));\n\n const handleClick = (item: TocItem) => {\n if (item.locked) return;\n onItemClick?.(item);\n if (isMobile) setMobileOpen(false);\n };\n\n const list = (\n <ul className={styles.list}>\n {items.map((item) => (\n <li key={item.id}>\n <a\n href={item.locked ? undefined : `#${item.id}`}\n className={`${styles.item} ${\n item.id === activeId ? styles.active : ''\n } ${item.locked ? styles.locked : ''}`}\n style={{ paddingLeft: `${(item.level - minLevel) * 12 + 12}px` }}\n aria-current={item.id === activeId ? 'true' : undefined}\n aria-disabled={item.locked ? 'true' : undefined}\n onClick={(e) => {\n e.preventDefault();\n handleClick(item);\n }}\n >\n <span className={styles.itemText}>{item.text}</span>\n {item.locked ? (\n <LockIcon className={styles.lockIcon} aria-hidden />\n ) : null}\n </a>\n </li>\n ))}\n </ul>\n );\n\n // ── 移动端:顶部可折叠条 ──\n if (isMobile) {\n return (\n <nav className={styles.mobile} aria-label={t.title}>\n <button\n type=\"button\"\n className={styles.mobileBar}\n aria-expanded={mobileOpen}\n onClick={() => setMobileOpen((v) => !v)}\n >\n <MenuIcon className={styles.mobileBarIcon} aria-hidden />\n <span>{t.title}</span>\n <span\n className={`${styles.chevron} ${\n mobileOpen ? styles.chevronUp : ''\n }`}\n aria-hidden\n >\n <ChevronDownIcon size={16} />\n </span>\n </button>\n <div\n ref={mobilePanelRef}\n className={`${styles.mobilePanel} ${\n mobileOpen ? styles.mobilePanelOpen : ''\n }`}\n >\n {list}\n </div>\n </nav>\n );\n }\n\n // ── 桌面:左侧粘性栏(可收起)──\n if (collapsed) {\n return (\n <button\n type=\"button\"\n className={styles.collapsedRail}\n aria-label={t.expand}\n title={t.expand}\n onClick={() => setCollapsed(false)}\n >\n <ListUnorderedIcon />\n </button>\n );\n }\n\n return (\n <nav className={styles.desktop} aria-label={t.title} ref={desktopNavRef}>\n <div className={styles.header}>\n <span className={styles.headerTitle}>{t.title}</span>\n <button\n type=\"button\"\n className={styles.collapseBtn}\n aria-label={t.collapse}\n title={t.collapse}\n onClick={() => setCollapsed(true)}\n >\n «\n </button>\n </div>\n {list}\n </nav>\n );\n}\n","'use client';\n\nimport * as Popover from '@radix-ui/react-popover';\nimport type { ReactNode } from 'react';\nimport styles from '../styles/comment.module.css';\n\nexport interface CommentPopoverProps {\n open: boolean;\n onOpenChange?: (open: boolean) => void;\n /** 被点击的 mark 元素(from onCommentClick 的 anchorEl)。 */\n anchorEl: HTMLElement | null;\n children: ReactNode;\n side?: 'top' | 'bottom' | 'left' | 'right';\n align?: 'start' | 'center' | 'end';\n sideOffset?: number;\n}\n\n/**\n * 评论浮层(Radix)。库只负责锚定与外观,内容由宿主通过 children 提供\n * (典型:评论正文 + Resolve/Dismiss/Reopen 操作)。\n * 锚点是点击 mark 的动态元素:渲染一个 fixed 1x1 span 挂在 anchorEl 的\n * getBoundingClientRect 位置,Radix 以它为锚。\n */\nexport function CommentPopover({\n open,\n onOpenChange,\n anchorEl,\n children,\n side = 'top',\n align = 'start',\n sideOffset = 6,\n}: CommentPopoverProps) {\n const rect = open && anchorEl ? anchorEl.getBoundingClientRect() : null;\n return (\n <Popover.Root open={open} onOpenChange={onOpenChange}>\n {rect && (\n <Popover.Anchor asChild>\n <span\n className={styles.popoverAnchor}\n style={{ left: rect.left, top: rect.top }}\n />\n </Popover.Anchor>\n )}\n <Popover.Portal>\n <Popover.Content\n className={styles.popoverContent}\n side={side}\n align={align}\n sideOffset={sideOffset}\n onOpenAutoFocus={(e) => e.preventDefault()}\n onCloseAutoFocus={(e) => e.preventDefault()}\n >\n {children}\n </Popover.Content>\n </Popover.Portal>\n </Popover.Root>\n );\n}\n","import type { Editor } from '@tiptap/react';\nimport {\n mapCommentAnchors,\n type CommentAnchorStatus,\n type CommentSegment,\n} from './commentAnchor/commentMapper';\n\n/**\n * 内容锚点 → 当前文档里的区间。\n *\n * 用途:宿主在提交一次「圈选改写」时记下选区的内容锚点(`prefix` / `exact` / `suffix`,\n * `blockHash` 可选),等 AI 改完、推送回来时再用它把那段区间找回来——**不能用位置**,\n * 因为编辑器在这期间可能整体重建过(保存、切卡、SWR 刷新都会重挂),位置活不过重建。\n *\n * 锚点类型直接复用评论锚定那套(`commentMapper`),匹配走同一条 fallback 链:\n * `blockHash` → 前后文 → `exact` → 前缀降级(前 20 字)。**这条链是会降级的**,所以:\n *\n * > 调用方必须自己比对返回的 `text` 是否仍等于提交时那一段。本函数只回答「在哪」,\n * > 不回答「还算不算同一段」——后者决定了是原地回填还是弹冲突。\n */\nexport interface AnchorRange {\n /** doc 坐标 */\n from: number;\n to: number;\n /**\n * 区间当前的纯文本。**按匹配器的口径**给出:`commentMapper` 把区间内的 text 节点\n * 直接拼起来(块之间**没有分隔符**),所以这里也是 `textBetween(from, to)`(不传\n * blockSeparator)。调用方拿它跟「建锚点时用的那段文本」比对——两边必须同一口径,\n * 否则多块区间(表格 / 列表)会永远对不上。\n */\n text: string;\n status: CommentAnchorStatus;\n}\n\n/** 探针 id:借 commentMapper 的匹配链路,但我们只要区间,不要评论语义。 */\nconst PROBE_ID = '__anchor-range-probe__';\n\nexport function findRangeByAnchor(\n editor: Editor,\n anchor: CommentSegment | null | undefined,\n): AnchorRange | null {\n if (!anchor || !anchor.exact) return null;\n\n const [result] = mapCommentAnchors(editor.state.doc, [\n { commentId: PROBE_ID, segments: [anchor] },\n ]);\n const range = result?.ranges[0];\n if (!range) return null;\n\n return {\n from: range.from,\n to: range.to,\n // 无 blockSeparator:与 commentMapper 的 `collectText`(text 节点直接拼接)同一口径\n text: editor.state.doc.textBetween(range.from, range.to),\n status: result.status,\n };\n}\n","import '@tiptap/markdown';\nimport type { JSONContent } from '@tiptap/core';\nimport type { Editor } from '@tiptap/react';\n\n/**\n * 取区间对应的 markdown,并给出它在 `editor.getMarkdown()` 输出里的精确偏移。\n *\n * 为什么需要它:后端改卡走的是「在正文里逐字找到这段,替换」(`replace_in_text` +\n * `count=1`),所以发过去的那段必须是**存库正文的逐字子串**;调用方还要知道它在整篇里\n * 的偏移,才能从存库正文取前后文(`ref`)并界定「这次改了哪一段」。官方 OSS 只有整篇\n * `Editor.getMarkdown()`;官方 Pro 的 `getMarkdownRange` 只返回字符串、不给偏移,也不做\n * 块扩展。\n *\n * **默认扩块**(`expandToBlocks: true`):把区间扩展到与它相交的顶层块的首尾。一是序列化\n * 稳定(半句话里跨着加粗,片段序列化会在断口插入多余的 `**`),二是**只有块对齐时偏移才是\n * 算出来的,而不是猜出来的**。\n *\n * 偏移怎么来的:把 doc 的顶层块逐个序列化、用 `\\n\\n` 拼起来,等于整篇序列化(有测试钉住\n * 这条不变量),于是「前 i 块拼接的长度」就是第 i 块的起点偏移。这条不变量若在某篇文档上\n * 不成立,退回按内容在整篇里定位;定位不到或出现多处就返回 `null`——宁可让调用方知道\n * 拿不到偏移,也不要给一个错的。\n */\nexport interface MarkdownRange {\n /** 区间对应的 markdown 片段(扩块后)。 */\n markdown: string;\n /** 片段在 `editor.getMarkdown()` 输出里的起始偏移。 */\n from: number;\n /** 结束偏移(不含)。恒有 `to - from === markdown.length`。 */\n to: number;\n /**\n * **同一段**在 doc 坐标里的范围(扩块之后)。\n *\n * 宿主需要它把「读」和「写」对齐:`from/to` 是 markdown 偏移,而编辑器里的替换要按\n * doc 坐标做。少了它,宿主只能自己拿原始选区去定位,于是「用来定位的那段」和\n * 「按 markdown 偏移算出来的那段」不是同一段——把 A 段写进 B 区间,内容就会重复。\n */\n docFrom: number;\n docTo: number;\n}\n\nexport interface GetMarkdownForRangeOptions {\n /**\n * 是否把区间扩展到与它相交的顶层块(段落 / 表格 / 列表 / 图表 …)的首尾。\n * 默认 `true`:调用方要「存库正文的逐字子串 + 精确偏移」时应该保持默认。\n * 设 `false` 按原区间取,此时偏移依赖内容定位,可能返回 `null`。\n */\n expandToBlocks?: boolean;\n}\n\n/** 顶层块之间的分隔符——与 MarkdownManager 的 doc 级拼接一致。 */\nconst BLOCK_SEPARATOR = '\\n\\n';\n\ninterface TopLevelBlock {\n json: JSONContent;\n /** doc 坐标 */\n from: number;\n to: number;\n}\n\nfunction topLevelBlocks(editor: Editor): TopLevelBlock[] {\n const blocks: TopLevelBlock[] = [];\n editor.state.doc.forEach((node, offset) => {\n blocks.push({\n json: node.toJSON() as JSONContent,\n from: offset,\n to: offset + node.nodeSize,\n });\n });\n return blocks;\n}\n\nexport function getMarkdownForRange(\n editor: Editor,\n from: number,\n to: number,\n options: GetMarkdownForRangeOptions = {},\n): MarkdownRange | null {\n const manager = editor.markdown;\n if (!manager) return null;\n\n const size = editor.state.doc.content.size;\n let start = Math.max(0, Math.min(from, to));\n let end = Math.min(size, Math.max(from, to));\n if (start >= end) return null;\n\n const blocks = topLevelBlocks(editor);\n if (blocks.length === 0) return null;\n\n const expand = options.expandToBlocks !== false;\n\n // 与 [start, end) 相交的顶层块:第一个末端越过 start 的、到最后一个起点早于 end 的。\n // 单元格内、列表项内的选区都会扩到它们所属的顶层块(表格 / 列表整体)。\n let first = 0;\n let last = blocks.length - 1;\n if (expand) {\n first = blocks.findIndex((b) => b.to > start);\n if (first < 0) return null;\n for (let i = blocks.length - 1; i >= first; i -= 1) {\n if (blocks[i].from < end) {\n last = i;\n break;\n }\n }\n start = blocks[first].from;\n end = blocks[last].to;\n }\n\n const parts = blocks.map((b) => manager.serialize({ type: 'doc', content: [b.json] }));\n const full = editor.getMarkdown();\n\n if (expand && parts.join(BLOCK_SEPARATOR) === full) {\n const markdown = parts.slice(first, last + 1).join(BLOCK_SEPARATOR);\n // 空段落拼出来是空串:语义上等于「这段没内容」,交给调用方去判空不如这里就返回 null\n if (!markdown) return null;\n const at =\n first === 0\n ? 0\n : parts.slice(0, first).join(BLOCK_SEPARATOR).length + BLOCK_SEPARATOR.length;\n return { markdown, from: at, to: at + markdown.length, docFrom: start, docTo: end };\n }\n\n // 非块对齐,或整篇拼接与 getMarkdown() 不一致:只能按内容定位,且必须唯一\n const markdown = manager.serialize(\n editor.state.doc.cut(start, end).toJSON() as JSONContent,\n );\n if (!markdown) return null;\n const at = full.indexOf(markdown);\n if (at < 0 || full.indexOf(markdown, at + 1) >= 0) return null;\n return { markdown, from: at, to: at + markdown.length, docFrom: start, docTo: end };\n}\n","import { MarkdownManager } from '@tiptap/markdown';\nimport { CitationRef } from './CitationRef';\nimport { prepareChartMarkdown } from './chart/prepareChartMarkdown';\nimport { baseExtensions, pureChart, pureCodeBlock, pureImage } from './extensions';\n\n/**\n * 把一段正文规范成「编辑器读进来再吐出去」的那种写法。\n *\n * **为什么需要它**:编辑器加载 markdown 时要先解析成文档结构,而 markdown 里有些东西是\n * 排版装饰、解析时就丢了(表格列宽的空格、注释 JSON 里的空格、数值尾零 …)。所以\n * 「存库正文」和「编辑器序列化结果」常常**逐字不同**——这与用户改没改无关,加载那一刻就\n * 发生了。而后端改卡走的是「在正文里逐字找到这段再替换」,两边写法不一致就会搜不到。\n * 宿主在要动正文之前(例如圈选改写提交前)先用本函数比对/对齐一次即可。\n *\n * **已知会被规范化的结构**(都是排版层面,内容语义不变):\n *\n * | 结构 | 存库可能是 | 规范化后 |\n * |------|-----------|---------|\n * | GFM 表格 | `\\| 收入 \\| 100 \\|` | 按列内容宽度重排对齐(多/少空格) |\n * | 图表注释 JSON | `<!-- {\"chartType\": \"column\"} -->` | `<!-- {\"chartType\":\"column\"} -->`(去空格,键序按解析结果) |\n * | **图表区**的数值 | `132.0` | `132`(图表把表解析成 payload,数值走 number 再写回) |\n * | 纯空白的正文 | `\" \\n \"` | `\"\"` |\n *\n * 注意第三行**只作用于图表区**:普通 GFM 表格走 marked 的表格解析,单元格是文本,\n * `1,234.50` 这种写法会原样保留(有测试钉住)。\n *\n * 反过来,这些**不该**被改动,同样有测试钉住:标题/段落/加粗斜体/列表/引用、代码块、\n * 公式、图片、脚注 `[^n]`、图表仍是「注释 + 表」的作者形态(不会变成 ```tmr-chart 围栏)。\n *\n * 注意它**不使用** `enrichMarkdownCitations`:脚注的 `[^n]` 由 CitationRef 自带的\n * tokenizer 解析,url/title 只存在于节点属性里、不进 markdown,所以规范化不需要 sources。\n */\nexport function normalizeMarkdown(markdown: string): string {\n if (!markdown) return markdown;\n const manager = getManager();\n return manager.serialize(manager.parse(prepareChartMarkdown(markdown)));\n}\n\n// [perf] 与 renderReportHtml 同样的理由:每次 new MarkdownManager 都会让底层 marked 全局\n// 累积 tokenizer,parse 逐次变慢。这里只做「解析 → 序列化」,无状态,模块级复用即可。\nlet sharedManager: MarkdownManager | null = null;\n\nfunction getManager(): MarkdownManager {\n sharedManager ??= new MarkdownManager({\n extensions: [...baseExtensions, pureCodeBlock, pureImage, pureChart, CitationRef],\n });\n return sharedManager;\n}\n","import '@tiptap/markdown';\nimport type { Editor } from '@tiptap/react';\nimport { prepareChartMarkdown } from './chart/prepareChartMarkdown';\nimport { enrichMarkdownCitations, type SourceRef } from './citationUtils';\nimport { splitTopLevelBlocks, stripToPlainText } from './insertMarkdown';\n\nexport interface ReplaceRangeOptions {\n /** 脚注来源:把 `[^n]` enrich 成带 url/title 的 citation-ref(与 `insertMarkdown` 同一套)。 */\n sources?: SourceRef[];\n}\n\n/**\n * 用一段 markdown **替换**一个区间。给「后台回填」用——AI 在别处改完,把结果写回编辑器。\n *\n * 与 `insertMarkdown` 的三处刻意差异(都在注释里点明,改的时候别抹平):\n *\n * 1. **不抢焦点**。`insertMarkdown` 是「用户主动插入」,链式带了 `.focus()`;后台回填时\n * 用户可能正在别处打字,抢焦点等于打断他。所以这里直接调 `insertContentAt`。\n * 2. **按区间替换**,不是往光标处插(`insertContentAt` 收 `{from,to}` 时后者即替换)。\n * 3. **进 undo 历史**。`insertContentAt` 本身是一个 transaction,撤销一步就回去;\n * 与评论锚定的 `addToHistory: false` 相反——正文改动必须能撤。\n *\n * 解析失败(AI 的脏输出过不了 schema:嵌套 bold、块级图进 listItem …)时按块降级,\n * 与 `insertMarkdown` 同一套策略。注意降级路径是**逐块多次 transaction**,撤销要多按几下;\n * 只在整段失败时才走。\n *\n * @returns 是否改动了文档。空 markdown 返回 `false`(不静默删掉用户的内容)。\n */\nexport function replaceRangeWithMarkdown(\n editor: Editor,\n range: { from: number; to: number },\n markdown: string,\n options: ReplaceRangeOptions = {},\n): boolean {\n const prepared = prepareChartMarkdown(\n enrichMarkdownCitations(markdown ?? '', options.sources ?? []),\n );\n if (!prepared.trim()) return false;\n\n let from = Math.max(0, Math.min(range.from, range.to));\n let to = Math.max(range.from, range.to);\n if (from === to) return false;\n\n // ① 整段替换:一个 transaction,撤销一步到位\n if (tryInsertMarkdownAt(editor, from, to, prepared)) return true;\n\n // ② 降级:逐块替换。块插完要往后挪插入点,否则每块都往同一个区间插、只剩最后一块\n for (const block of splitTopLevelBlocks(prepared)) {\n const before = editor.state.doc.content.size;\n const changed =\n tryInsertMarkdownAt(editor, from, to, block) ||\n insertPlainParagraphAt(editor, from, to, stripToPlainText(block));\n if (!changed) continue;\n // 插入内容的 doc 尺寸 = 文档增量 + 被替换掉的宽度\n const inserted = editor.state.doc.content.size - before + (to - from);\n from += inserted;\n to = from;\n }\n return true;\n}\n\n/** 注意:不带 `.focus()`——后台回填不能抢用户的焦点。 */\nfunction tryInsertMarkdownAt(\n editor: Editor,\n from: number,\n to: number,\n markdown: string,\n): boolean {\n try {\n return editor\n .chain()\n .insertContentAt({ from, to }, markdown, { contentType: 'markdown' })\n .run();\n } catch {\n return false;\n }\n}\n\nfunction insertPlainParagraphAt(\n editor: Editor,\n from: number,\n to: number,\n text: string,\n): boolean {\n try {\n return editor\n .chain()\n .insertContentAt(\n { from, to },\n { type: 'paragraph', content: text ? [{ type: 'text', text }] : [] },\n )\n .run();\n } catch {\n return false;\n }\n}\n"],"names":["m","r","e","active","b","counter","toggle","styles","Node","MD_FILE_RE","f","input","setActive","MarkdownWysiwygEditor","a","row","field","bar","Fragment","item","list","markdown","at"],"mappings":"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"}
|