bridgerte 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +830 -0
- package/dist/bridge.cjs +2 -0
- package/dist/bridge.cjs.map +1 -0
- package/dist/bridge.d.ts +1070 -0
- package/dist/bridge.js +37 -0
- package/dist/bridge.js.map +1 -0
- package/dist/core.cjs +2 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.ts +899 -0
- package/dist/core.js +58 -0
- package/dist/core.js.map +1 -0
- package/dist/dom.cjs +2 -0
- package/dist/dom.cjs.map +1 -0
- package/dist/dom.d.ts +955 -0
- package/dist/dom.js +8 -0
- package/dist/dom.js.map +1 -0
- package/dist/index-BDgKCpty.cjs +3 -0
- package/dist/index-BDgKCpty.cjs.map +1 -0
- package/dist/index-C7IVE5Bd.js +4515 -0
- package/dist/index-C7IVE5Bd.js.map +1 -0
- package/dist/index-CuNKUHed.js +7 -0
- package/dist/index-CuNKUHed.js.map +1 -0
- package/dist/index-GaS65GL0.cjs +2 -0
- package/dist/index-GaS65GL0.cjs.map +1 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +1233 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/native-spec.cjs +2 -0
- package/dist/native-spec.cjs.map +1 -0
- package/dist/native-spec.d.ts +953 -0
- package/dist/native-spec.js +594 -0
- package/dist/native-spec.js.map +1 -0
- package/dist/style.css +1 -0
- package/dist/webview.cjs +2 -0
- package/dist/webview.cjs.map +1 -0
- package/dist/webview.d.ts +1107 -0
- package/dist/webview.js +5 -0
- package/dist/webview.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-BDgKCpty.cjs","sources":["../../dom/src/mediaNode/index.ts","../../dom/src/contentModel/index.ts","../../dom/src/dividerNode/index.ts","../../dom/src/mentionNode/index.ts","../../dom/src/placeholder/index.ts","../../dom/src/menuIcon/defaultIcons.ts","../../dom/src/menuIcon/index.ts","../../dom/src/interactionState/index.ts","../../dom/src/menuRuntime/index.ts","../../dom/src/richTextToolbar/index.ts","../../dom/src/commandState/index.ts","../../dom/src/richTextEditor/errorReporter.ts","../../dom/src/richTextEditor/commandStateRuntime.ts","../../dom/src/richTextEditor/mediaUpload.ts","../../dom/src/codeBlock/index.ts","../../dom/src/richTextEditor/lexicalTheme.ts","../../dom/src/richTextEditor/commandExecutor/block.ts","../../dom/src/richTextEditor/commandExecutor/link.ts","../../dom/src/richTextEditor/commandExecutor/media.ts","../../dom/src/richTextEditor/commandExecutor/mention.ts","../../dom/src/richTextEditor/commandExecutor/style.ts","../../dom/src/richTextEditor/tableCommands.ts","../../dom/src/richTextEditor/commandExecutor/table.ts","../../dom/src/richTextEditor/commandExecutor.ts","../../dom/src/richTextEditor/constants.ts","../../dom/src/maxLength/index.ts","../../dom/src/richTextEditor/contentSync.ts","../../dom/src/codeHighlight/language.ts","../../dom/src/codeHighlight/html.ts","../../dom/src/dialog/index.ts","../../dom/src/domScheduler/index.ts","../../dom/src/codeHighlight/controller.ts","../../dom/src/mediaControls/menu.ts","../../dom/src/mediaControls/index.ts","../../dom/src/payloadPanel/command.ts","../../dom/src/payloadPanel/color.ts","../../dom/src/payloadPanel/fieldRenderer.ts","../../dom/src/payloadPanel/layout.ts","../../dom/src/payloadPanel/tableGrid.ts","../../dom/src/payloadPanel/index.ts","../../dom/src/tableHeader/index.ts","../../dom/src/richTextEditor/controllers.ts","../../dom/src/richTextEditor/dom.ts","../../dom/src/richTextEditor/payloadPanelSelection.ts","../../dom/src/autoLink/index.ts","../../dom/src/clipboard/index.ts","../../dom/src/floatingLayer/index.ts","../../dom/src/selectionGeometry/index.ts","../../dom/src/hoverbar/index.ts","../../dom/src/keyboardShortcuts/index.ts","../../dom/src/floatingMenu/index.ts","../../dom/src/floatingPicker/index.ts","../../dom/src/mention/config.ts","../../dom/src/mention/deleteMention.ts","../../dom/src/mention/index.ts","../../dom/src/paste/htmlCleanup.ts","../../dom/src/paste/index.ts","../../dom/src/slashCommand/config.ts","../../dom/src/slashCommand/index.ts","../../dom/src/todoList/index.ts","../../dom/src/richTextEditor/plugins.ts","../../dom/src/richTextEditor/index.ts","../../dom/src/bridgeRuntime/index.ts"],"sourcesContent":["import type {\n DOMConversionMap,\n DOMConversionOutput,\n DOMExportOutput,\n EditorConfig,\n LexicalEditor,\n LexicalNode,\n NodeKey\n} from 'lexical';\nimport { $applyNodeReplacement, DecoratorNode } from 'lexical';\nimport { $getRoot, $isElementNode } from 'lexical';\nimport type {\n EditorAsset,\n ImageInsertPayload,\n MediaAlign,\n MediaDisplayWidthPercent,\n VideoInsertPayload\n} from '@bridgerte/core';\nimport type {\n BridgeMediaPayload,\n BridgeMediaType,\n SerializedBridgeMediaNode\n} from './type';\n\nexport type * from './type';\n\nconst mediaNodeType = 'bridgerte-media';\n\nconst createAssetId = (mediaType: BridgeMediaType, url: string) => (\n `${mediaType}:${url}`\n);\n\nconst toPositiveNumber = (value: number | undefined) => (\n typeof value === 'number' && Number.isFinite(value) && value > 0\n ? Math.floor(value)\n : undefined\n);\n\nconst clampProgress = (value: number | undefined) => (\n typeof value === 'number' && Number.isFinite(value)\n ? Math.min(Math.max(value, 0), 100)\n : undefined\n);\n\nconst isMediaDisplayWidthPercent = (\n value: number | undefined\n): value is MediaDisplayWidthPercent => value === 20 || value === 50 || value === 100;\n\nconst normalizeDisplayWidthPercent = (value: number | undefined) => (\n isMediaDisplayWidthPercent(value) ? value : undefined\n);\n\nconst normalizeMediaAlign = (value: MediaAlign | undefined) => (\n value === 'center' || value === 'right' ? value : undefined\n);\n\nconst setOptionalStringAttribute = (\n element: HTMLElement,\n name: string,\n value: string | undefined\n) => {\n if (value) element.setAttribute(name, value);\n};\n\nconst setOptionalNumberAttribute = (\n element: HTMLElement,\n name: string,\n value: number | undefined\n) => {\n if (value !== undefined) element.setAttribute(name, String(value));\n};\n\n/**\n * BridgeRTE 媒体节点。\n *\n * 第一版只承载 URL 插入的图片/视频和稳定尺寸元信息;上传中、失败态和重试会在同一节点上扩展,\n * 避免第 7 期后续上传能力再引入第二套媒体内容协议。\n */\nexport class BridgeMediaNode extends DecoratorNode<null> {\n __payload: BridgeMediaPayload;\n\n static override getType(): string {\n return mediaNodeType;\n }\n\n static override clone(node: BridgeMediaNode): BridgeMediaNode {\n return new BridgeMediaNode(node.__payload, node.__key);\n }\n\n constructor(payload: BridgeMediaPayload, key?: NodeKey) {\n super(key);\n this.__payload = {\n ...payload,\n assetId: payload.assetId ?? createAssetId(payload.mediaType, payload.url),\n width: toPositiveNumber(payload.width),\n height: toPositiveNumber(payload.height),\n duration: toPositiveNumber(payload.duration),\n progress: clampProgress(payload.progress),\n displayWidthPercent: normalizeDisplayWidthPercent(payload.displayWidthPercent),\n align: normalizeMediaAlign(payload.align)\n };\n if (this.__payload.displayWidthPercent === undefined) {\n delete this.__payload.displayWidthPercent;\n }\n if (this.__payload.align === undefined) {\n delete this.__payload.align;\n }\n }\n\n override createDOM(_config: EditorConfig): HTMLElement {\n return this.createMediaElement();\n }\n\n override updateDOM(previousNode: BridgeMediaNode, dom: HTMLElement): boolean {\n if (previousNode.__payload === this.__payload) return false;\n\n const nextElement = this.createMediaElement();\n\n dom.replaceWith(nextElement);\n\n return true;\n }\n\n override exportDOM(_editor: LexicalEditor): DOMExportOutput {\n return { element: this.createMediaElement() };\n }\n\n static override importDOM(): DOMConversionMap | null {\n return {\n img: () => ({\n conversion: $convertImageElement,\n priority: 1\n }),\n video: () => ({\n conversion: $convertVideoElement,\n priority: 1\n })\n };\n }\n\n static override importJSON(serializedNode: SerializedBridgeMediaNode): BridgeMediaNode {\n return $createBridgeMediaNode(serializedNode).updateFromJSON(serializedNode);\n }\n\n override exportJSON(): SerializedBridgeMediaNode {\n return {\n ...super.exportJSON(),\n ...this.__payload,\n type: mediaNodeType\n };\n }\n\n override getTextContent(): string {\n return this.__payload.title ?? this.__payload.alt ?? this.__payload.url;\n }\n\n override isInline(): false {\n return false;\n }\n\n getAsset(): EditorAsset {\n const payload = this.__payload;\n\n const asset: EditorAsset = {\n id: payload.assetId ?? createAssetId(payload.mediaType, payload.url),\n type: payload.mediaType,\n url: payload.url,\n status: payload.status,\n progress: payload.progress,\n poster: payload.poster,\n width: payload.width,\n height: payload.height,\n duration: payload.duration,\n mimeType: payload.mimeType,\n size: payload.size,\n errorMessage: payload.errorMessage,\n external: true\n };\n\n if (payload.displayWidthPercent !== undefined) {\n asset.displayWidthPercent = payload.displayWidthPercent;\n }\n if (payload.align !== undefined) {\n asset.align = payload.align;\n }\n\n return asset;\n }\n\n updatePayload(nextPayload: Partial<BridgeMediaPayload>): void {\n const writable = this.getWritable();\n\n writable.__payload = {\n ...writable.__payload,\n ...nextPayload,\n width: toPositiveNumber(nextPayload.width ?? writable.__payload.width),\n height: toPositiveNumber(nextPayload.height ?? writable.__payload.height),\n duration: toPositiveNumber(nextPayload.duration ?? writable.__payload.duration),\n progress: clampProgress(nextPayload.progress ?? writable.__payload.progress),\n displayWidthPercent: Object.prototype.hasOwnProperty.call(\n nextPayload,\n 'displayWidthPercent'\n )\n ? normalizeDisplayWidthPercent(nextPayload.displayWidthPercent)\n : writable.__payload.displayWidthPercent,\n align: Object.prototype.hasOwnProperty.call(nextPayload, 'align')\n ? normalizeMediaAlign(nextPayload.align)\n : writable.__payload.align\n };\n if (writable.__payload.displayWidthPercent === undefined) {\n delete writable.__payload.displayWidthPercent;\n }\n if (writable.__payload.align === undefined) {\n delete writable.__payload.align;\n }\n }\n\n private createMediaElement(): HTMLElement {\n const payload = this.__payload;\n const figure = document.createElement('figure');\n const mediaElement = payload.mediaType === 'image'\n ? document.createElement('img')\n : document.createElement('video');\n\n figure.className = `bridgerte__media bridgerte__media--${payload.mediaType}`;\n figure.contentEditable = 'false';\n figure.dataset.assetId = payload.assetId;\n figure.dataset.mediaType = payload.mediaType;\n figure.dataset.status = payload.status ?? 'success';\n if (payload.progress !== undefined) figure.dataset.progress = String(payload.progress);\n if (payload.align !== undefined) figure.dataset.align = payload.align;\n if (payload.displayWidthPercent !== undefined) {\n figure.dataset.displayWidthPercent = String(payload.displayWidthPercent);\n figure.style.setProperty(\n '--bridgerte-media-display-width',\n `${payload.displayWidthPercent}%`\n );\n }\n mediaElement.className = 'bridgerte__media-element';\n if (payload.mediaType === 'image') {\n mediaElement.setAttribute('src', payload.url);\n mediaElement.setAttribute('loading', 'lazy');\n setOptionalStringAttribute(mediaElement, 'alt', payload.alt ?? payload.title);\n } else {\n mediaElement.setAttribute('src', payload.url);\n mediaElement.setAttribute('controls', 'true');\n mediaElement.setAttribute('preload', 'metadata');\n setOptionalStringAttribute(mediaElement, 'poster', payload.poster);\n }\n setOptionalStringAttribute(mediaElement, 'title', payload.title);\n setOptionalNumberAttribute(mediaElement, 'width', payload.width);\n setOptionalNumberAttribute(mediaElement, 'height', payload.height);\n figure.append(mediaElement);\n if (payload.status === 'uploading' || payload.status === 'error') {\n const statusElement = document.createElement('figcaption');\n\n statusElement.className = 'bridgerte__media-status';\n statusElement.textContent = payload.status === 'error'\n ? payload.errorMessage ?? '上传失败'\n : `上传中 ${payload.progress ?? 0}%`;\n figure.append(statusElement);\n }\n\n return figure;\n }\n}\n\nconst $convertImageElement = (node: Node): DOMConversionOutput => {\n const element = node instanceof HTMLImageElement ? node : null;\n\n return {\n node: element?.src ? $createBridgeMediaNode({\n mediaType: 'image',\n url: element.src,\n alt: element.alt,\n title: element.title,\n width: element.width,\n height: element.height,\n status: 'success'\n }) : null\n };\n};\n\nconst $convertVideoElement = (node: Node): DOMConversionOutput => {\n const element = node instanceof HTMLVideoElement ? node : null;\n\n return {\n node: element?.src ? $createBridgeMediaNode({\n mediaType: 'video',\n url: element.src,\n poster: element.poster,\n title: element.title,\n width: element.videoWidth || element.width,\n height: element.videoHeight || element.height,\n status: 'success'\n }) : null\n };\n};\n\nexport const $createBridgeMediaNode = (payload: BridgeMediaPayload): BridgeMediaNode => (\n $applyNodeReplacement(new BridgeMediaNode(payload))\n);\n\nexport const $createBridgeImageNode = (payload: ImageInsertPayload): BridgeMediaNode => (\n $createBridgeMediaNode({\n mediaType: 'image',\n url: payload.url,\n alt: payload.alt,\n title: payload.title,\n width: payload.width,\n height: payload.height,\n displayWidthPercent: payload.displayWidthPercent,\n align: payload.align,\n assetId: payload.assetId,\n status: 'success'\n })\n);\n\nexport const $createBridgeVideoNode = (payload: VideoInsertPayload): BridgeMediaNode => (\n $createBridgeMediaNode({\n mediaType: 'video',\n url: payload.url,\n poster: payload.poster,\n title: payload.title,\n width: payload.width,\n height: payload.height,\n displayWidthPercent: payload.displayWidthPercent,\n align: payload.align,\n assetId: payload.assetId,\n status: 'success'\n })\n);\n\nexport const $isBridgeMediaNode = (\n node: LexicalNode | null | undefined\n): node is BridgeMediaNode => node instanceof BridgeMediaNode;\n\n/**\n * 按 assetId 查找媒体节点。\n *\n * 上传回调可能晚于用户继续编辑,不能缓存 DOM 节点或 LexicalNode 实例;每次回写都在当前\n * editorState 中按稳定 assetId 查找,删除后的节点会自然找不到并忽略异步结果。\n */\nexport const $findBridgeMediaNodeByAssetId = (assetId: string): BridgeMediaNode | null => {\n const visitNode = (node: LexicalNode): BridgeMediaNode | null => {\n if ($isBridgeMediaNode(node) && node.getAsset().id === assetId) return node;\n if (!$isElementNode(node)) return null;\n\n for (const childNode of node.getChildren()) {\n const matchedNode = visitNode(childNode);\n\n if (matchedNode) return matchedNode;\n }\n\n return null;\n };\n\n return visitNode($getRoot());\n};\n","import {\n $createParagraphNode,\n $getRoot,\n $isElementNode,\n type EditorState,\n type LexicalNode\n} from 'lexical';\nimport type { SerializedEditorState, SerializedLexicalNode } from 'lexical';\nimport { $generateHtmlFromNodes, $generateNodesFromDOM } from '@lexical/html';\nimport {\n BRIDGERTE_CONTENT_VERSION,\n type EditorContent,\n type EditorContentJson\n} from '@bridgerte/core';\nimport { $isBridgeMediaNode } from '../mediaNode';\nimport type { LexicalEditor } from './type';\n\nexport type * from './type';\n\nexport const emptyContentJson: EditorContentJson = {\n root: {\n type: 'root',\n version: 1,\n children: []\n }\n};\n\n/**\n * 标准化外部传入的部分内容。\n *\n * 这样 `getContent()` 始终返回完整结构,宿主不需要处理缺省字段。\n */\nexport function createEmptyContent(value: Partial<EditorContent> = {}): EditorContent {\n return {\n html: value.html ?? '',\n json: value.json ?? emptyContentJson,\n plainText: value.plainText ?? '',\n assets: value.assets ?? [],\n version: value.version ?? BRIDGERTE_CONTENT_VERSION\n };\n}\n\nconst getContentJson = (editorState: EditorState): EditorContentJson => (\n editorState.toJSON() as EditorContentJson\n);\n\nconst isEmptyContentJson = (json: EditorContentJson): boolean => (\n json.root.children?.length === 0\n);\n\nconst collectEditorAssets = (editorState: EditorState): EditorContent['assets'] => (\n editorState.read(() => {\n const assets = new Map<string, EditorContent['assets'][number]>();\n\n /*\n * 媒体节点是 assets 的权威来源。删除节点后下一次序列化自然移除 asset,\n * 不需要额外维护一份容易过期的外部列表。\n */\n const collectNodeAssets = (node: LexicalNode) => {\n if (!$isElementNode(node)) return;\n\n node.getChildren().forEach((childNode) => {\n if ($isBridgeMediaNode(childNode)) {\n const asset = childNode.getAsset();\n\n assets.set(asset.id, asset);\n return;\n }\n\n if ($isElementNode(childNode)) {\n collectNodeAssets(childNode);\n }\n });\n };\n\n collectNodeAssets($getRoot());\n\n return [...assets.values()];\n })\n);\n\n/**\n * 把 Lexical 当前状态序列化成 BridgeRTE 内容协议。\n *\n * html 是编辑区片段,json 是 BridgeRTE v1 内容结构承载的 Lexical editorState;\n * assets 只从当前媒体节点实时收集,删除节点后不会被旧内容快照重新带回来。\n */\nexport const serializeContent = (\n editorState: EditorState,\n editor: LexicalEditor\n): EditorContent => {\n const html = editor.read(() => $generateHtmlFromNodes(editor));\n const plainText = editorState.read(() => $getRoot().getTextContent());\n const assets = collectEditorAssets(editorState);\n\n return {\n html,\n json: getContentJson(editorState),\n plainText,\n assets,\n version: BRIDGERTE_CONTENT_VERSION\n };\n};\n\n/**\n * 初始化内容时先写入编辑器,再回读成完整内容,保证缺省字段和实际 DOM 状态一致。\n */\nexport const normalizeInitialContent = (\n editor: LexicalEditor,\n value?: Partial<EditorContent>\n): EditorContent => {\n const content = createEmptyContent(value);\n\n applyContentToEditor(editor, content);\n\n return serializeContent(editor.getEditorState(), editor);\n};\n\n/**\n * 将 BridgeRTE 内容协议写回 Lexical。\n *\n * 优先使用 json,空内容会显式创建一个空段落,避免编辑器处于不可输入的空 root 状态。\n */\nexport const applyContentToEditor = (\n editor: LexicalEditor,\n nextContent: EditorContent\n) => {\n if (nextContent.json !== emptyContentJson && !isEmptyContentJson(nextContent.json)) {\n const editorStateJson = nextContent.json as SerializedEditorState<SerializedLexicalNode>;\n\n editor.setEditorState(editor.parseEditorState(editorStateJson));\n return;\n }\n\n if (!nextContent.html) {\n editor.update(\n () => {\n const root = $getRoot();\n\n root.clear();\n root.append($createParagraphNode());\n },\n { discrete: true }\n );\n return;\n }\n\n const parser = new DOMParser();\n const dom = parser.parseFromString(nextContent.html, 'text/html');\n\n editor.update(\n () => {\n const root = $getRoot();\n const nodes = $generateNodesFromDOM(editor, dom);\n\n root.clear();\n root.append(...nodes);\n },\n { discrete: true }\n );\n};\n","import type {\n DOMConversionMap,\n DOMConversionOutput,\n DOMExportOutput,\n EditorConfig,\n LexicalEditor,\n LexicalNode,\n NodeKey\n} from 'lexical';\nimport { $applyNodeReplacement, DecoratorNode } from 'lexical';\nimport type { SerializedDividerNode } from './type';\n\nexport type * from './type';\n\n/**\n * BridgeRTE 分割线节点。\n *\n * 分割线是块级不可编辑节点,使用 Lexical DecoratorNode 保持 selection 边界稳定;\n * DOM 输出固定为 hr,方便 Web/H5 和保存 HTML 都得到一致结构。\n */\nexport class DividerNode extends DecoratorNode<null> {\n static override getType(): string {\n return 'bridgerte-divider';\n }\n\n static override clone(node: DividerNode): DividerNode {\n return new DividerNode(node.__key);\n }\n\n constructor(key?: NodeKey) {\n super(key);\n }\n\n override createDOM(_config: EditorConfig): HTMLElement {\n const element = document.createElement('hr');\n\n element.className = 'bridgerte__divider';\n\n return element;\n }\n\n override updateDOM(): false {\n return false;\n }\n\n override exportDOM(_editor: LexicalEditor): DOMExportOutput {\n const element = document.createElement('hr');\n\n element.className = 'bridgerte__divider';\n\n return { element };\n }\n\n static override importDOM(): DOMConversionMap | null {\n return {\n hr: () => ({\n conversion: $convertDividerElement,\n priority: 0\n })\n };\n }\n\n static override importJSON(serializedNode: SerializedDividerNode): DividerNode {\n return $createDividerNode().updateFromJSON(serializedNode);\n }\n\n override exportJSON(): SerializedDividerNode {\n return {\n ...super.exportJSON(),\n type: DividerNode.getType()\n };\n }\n\n override getTextContent(): string {\n return '\\n';\n }\n\n override isInline(): false {\n return false;\n }\n}\n\nconst $convertDividerElement = (_node: Node): DOMConversionOutput => ({\n node: $createDividerNode()\n});\n\nexport const $createDividerNode = (): DividerNode => (\n $applyNodeReplacement(new DividerNode())\n);\n\nexport const $isDividerNode = (\n node: LexicalNode | null | undefined\n): node is DividerNode => node instanceof DividerNode;\n","import type {\n DOMConversionMap,\n DOMConversionOutput,\n DOMExportOutput,\n EditorConfig,\n LexicalEditor,\n LexicalNode,\n NodeKey\n} from 'lexical';\nimport { $applyNodeReplacement, TextNode } from 'lexical';\nimport type { MentionItem } from '@bridgerte/core';\nimport type { SerializedMentionNode } from './type';\n\nexport type * from './type';\n\nconst mentionNodeType = 'bridgerte-mention';\nconst mentionDatasetType = 'mention';\n\nconst normalizeMentionText = (item: MentionItem) => (\n item.label.startsWith('@') ? item.label : `@${item.label}`\n);\n\nconst createMentionElement = (item: MentionItem) => {\n const element = document.createElement('span');\n\n element.className = 'bridgerte__mention';\n element.dataset.type = mentionDatasetType;\n element.dataset.id = item.id;\n element.dataset.value = item.value;\n element.contentEditable = 'false';\n element.textContent = normalizeMentionText(item);\n if (item.description) {\n element.dataset.description = item.description;\n }\n\n return element;\n};\n\n/**\n * BridgeRTE mention 节点。\n *\n * mention 是行内文本实体,用 TextNode token 模式接入文本流:plainText 仍输出 `@label`,\n * 但删除和光标移动会把它当成一个整体,避免 DecoratorNode 把普通输入体验割裂开。\n */\nexport class MentionNode extends TextNode {\n __item: MentionItem;\n\n static override getType(): string {\n return mentionNodeType;\n }\n\n static override clone(node: MentionNode): MentionNode {\n return new MentionNode(node.__item, node.__text, node.__key);\n }\n\n constructor(item: MentionItem, text = normalizeMentionText(item), key?: NodeKey) {\n super(text, key);\n this.__item = item;\n }\n\n override createDOM(config: EditorConfig): HTMLElement {\n const element = super.createDOM(config);\n\n element.className = 'bridgerte__mention';\n element.dataset.type = mentionDatasetType;\n element.dataset.id = this.__item.id;\n element.dataset.value = this.__item.value;\n element.contentEditable = 'false';\n if (this.__item.description) {\n element.dataset.description = this.__item.description;\n }\n\n return element;\n }\n\n override updateDOM(previousNode: this, dom: HTMLElement, config: EditorConfig): boolean {\n const shouldReplace = super.updateDOM(previousNode, dom, config);\n\n if (shouldReplace) return true;\n\n dom.dataset.id = this.__item.id;\n dom.dataset.value = this.__item.value;\n if (this.__item.description) {\n dom.dataset.description = this.__item.description;\n } else {\n delete dom.dataset.description;\n }\n\n return false;\n }\n\n override exportDOM(_editor: LexicalEditor): DOMExportOutput {\n return { element: createMentionElement(this.__item) };\n }\n\n static override importDOM(): DOMConversionMap | null {\n return {\n span: () => ({\n conversion: $convertMentionElement,\n priority: 2\n })\n };\n }\n\n static override importJSON(serializedNode: SerializedMentionNode): MentionNode {\n return $createMentionNode(serializedNode).updateFromJSON(serializedNode);\n }\n\n override exportJSON(): SerializedMentionNode {\n return {\n ...super.exportJSON(),\n ...this.__item,\n type: mentionNodeType\n };\n }\n\n override isTextEntity(): true {\n return true;\n }\n\n override isToken(): true {\n return true;\n }\n\n getMentionItem(): MentionItem {\n return this.__item;\n }\n}\n\nconst $convertMentionElement = (node: Node): DOMConversionOutput => {\n const element = node instanceof HTMLElement ? node : null;\n\n if (!element || element.dataset.type !== mentionDatasetType) {\n return { node: null };\n }\n\n const label = element.textContent?.replace(/^@/, '') || element.dataset.value || '';\n const id = element.dataset.id || element.dataset.value || label;\n const value = element.dataset.value || id;\n\n if (!label || !id || !value) return { node: null };\n\n return {\n node: $createMentionNode({\n id,\n label,\n value,\n description: element.dataset.description\n })\n };\n};\n\nexport const $createMentionNode = (item: MentionItem): MentionNode => (\n $applyNodeReplacement(new MentionNode(item).setMode('token') as MentionNode)\n);\n\nexport const $isMentionNode = (\n node: LexicalNode | null | undefined\n): node is MentionNode => node instanceof MentionNode;\n","import { $getRoot, $isParagraphNode } from 'lexical';\nimport type { PlaceholderFocusOptions, PlaceholderStateOptions } from './type';\n\nexport type * from './type';\n\n/**\n * DOM SDK 的默认占位文案。\n *\n * 业务传入 `placeholder` 时会覆盖它;保留默认值是为了让最小初始化也有可见空态。\n */\nexport const defaultPlaceholder = '请输入内容';\n\nconst isRootEmptyPlaceholderTarget = (): boolean => {\n const root = $getRoot();\n const children = root.getChildren();\n\n if (children.length === 0) return true;\n if (children.length > 1) return false;\n\n const onlyChild = children[0];\n\n /*\n * placeholder 只覆盖编辑器初始化或清空后的默认空段落。\n * 空 todo、表格、代码块、媒体等结构节点即使没有文本,也已经是用户内容,不能继续露出空态文案。\n */\n return $isParagraphNode(onlyChild) && onlyChild.getChildrenSize() === 0;\n};\n\n/**\n * 根据当前 editorState 更新 placeholder 的显隐。\n *\n * 这里只读 root 的直接结构,不做 HTML/JSON 序列化,避免空态判断把内容同步\n * 变成高频重活;空编辑器通常也会保留一个空段落,所以要区分默认空段落和空结构节点。\n */\nexport const syncPlaceholderState = ({\n editor,\n contentElement\n}: PlaceholderStateOptions): void => {\n const isEmpty = editor.getEditorState().read(isRootEmptyPlaceholderTarget);\n\n contentElement.dataset.empty = String(isEmpty);\n};\n\n/**\n * 注册空态 placeholder 的聚焦兜底。\n *\n * placeholder 是 CSS 伪元素,不是 contenteditable 里的真实文本节点;点击伪元素或空白区时,\n * 浏览器不一定能像 textarea 一样生成可输入光标,所以空态点击时主动聚焦并选到 root 开头。\n */\nexport const registerPlaceholderFocus = ({\n editor,\n contentElement,\n isReadonly\n}: PlaceholderFocusOptions): (() => void) => {\n const handlePointerDown = (event: PointerEvent) => {\n if (isReadonly() || contentElement.dataset.empty !== 'true') return;\n if (event.button !== 0) return;\n\n event.preventDefault();\n editor.focus(() => {\n editor.update(() => {\n $getRoot().selectStart();\n });\n });\n };\n\n contentElement.addEventListener('pointerdown', handlePointerDown);\n\n return () => {\n contentElement.removeEventListener('pointerdown', handlePointerDown);\n };\n};\n","/**\n * DOM 默认菜单 SVG icon 表。\n *\n * 这个表只覆盖 `defaultMenuSchema` 和表格上下文菜单实际声明过的 `MenuItem.icon` key,\n * 分类依据是跨端协议里的稳定 icon key,而不是 DOM 的菜单 id 或 lucide 文件名。\n *\n * 集中维护的原因有三点:\n * - schema 继续保持 SVG-free,RN/Flutter/WebView 只读取 icon key 后自绘;\n * - DOM 渲染层只做字符串查表,不在按钮分支里写一堆 icon 特判;\n * - 业务传入的 `icons` map 永远优先,缺失 key 再落到这里,最后才回退 label 文本。\n *\n * 后续新增默认菜单时,先在 native-spec 的 schema 里确定 icon key,再补这个表和\n * `richTextToolbar` 对齐测试;业务私有菜单不要加到这里,直接通过 `icons` option 传入。\n * 图标源文件来自 ignored 的 `artifacts/icons/*.svg` 素材池,接入时统一为 18px、\n * `aria-hidden=\"true\"` 和 `currentColor`,保证按钮无障碍名称仍来自 `MenuItem.label`。\n * 这个常量没有运行时副作用,只服务 DOM toolbar/tabbar/hoverbar 的默认视觉兜底。\n */\nexport const defaultMenuIcons: Record<string, string> = {\n // 居中对齐菜单使用,和 align 命令的 center value 对应。\n 'align-center': '<svg aria-hidden=\"true\" class=\"lucide lucide-align-center\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M21 5H3\" /> <path d=\"M17 12H7\" /> <path d=\"M19 19H5\" /> </svg>',\n // 两端对齐菜单使用,保留段落排版语义,不和普通居中/左右对齐混用。\n 'align-justify': '<svg aria-hidden=\"true\" class=\"lucide lucide-align-justify\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M3 5h18\" /> <path d=\"M3 12h18\" /> <path d=\"M3 19h18\" /> </svg>',\n // 左对齐菜单使用,是段落默认对齐方向的显式入口。\n 'align-left': '<svg aria-hidden=\"true\" class=\"lucide lucide-align-left\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M21 5H3\" /> <path d=\"M15 12H3\" /> <path d=\"M17 19H3\" /> </svg>',\n // 右对齐菜单使用,和 align 命令的 right value 对应。\n 'align-right': '<svg aria-hidden=\"true\" class=\"lucide lucide-align-right\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M21 5H3\" /> <path d=\"M21 12H9\" /> <path d=\"M21 19H7\" /> </svg>',\n // @ mention 插入入口使用,后续 mention 候选菜单仍复用同一语义 key。\n 'at-sign': '<svg aria-hidden=\"true\" class=\"lucide lucide-at-sign\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <circle cx=\"12\" cy=\"12\" r=\"4\" /> <path d=\"M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8\" /> </svg>',\n // 加粗菜单和 hoverbar 加粗按钮共用,表示 format.bold。\n bold: '<svg aria-hidden=\"true\" class=\"lucide lucide-bold\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8\" /> </svg>',\n // 字号菜单使用,表达大小写/字形敏感的文本尺寸设置。\n 'case-sensitive': '<svg aria-hidden=\"true\" class=\"lucide lucide-case-sensitive\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"m2 16 4.039-9.69a.5.5 0 0 1 .923 0L11 16\" /> <path d=\"M22 9v7\" /> <path d=\"M3.304 13h6.392\" /> <circle cx=\"18.5\" cy=\"12.5\" r=\"3.5\" /> </svg>',\n // 行内代码菜单和 hoverbar 行内代码按钮共用,表示 format.inlineCode。\n code: '<svg aria-hidden=\"true\" class=\"lucide lucide-code\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"m16 18 6-6-6-6\" /> <path d=\"m8 6-6 6 6 6\" /> </svg>',\n // 表格删除列入口使用,图形保持列方向,和 rows-minus 区分。\n 'columns-minus': '<svg aria-hidden=\"true\" class=\"lucide lucide-between-vertical-end\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <rect width=\"7\" height=\"13\" x=\"3\" y=\"3\" rx=\"1\" /> <path d=\"m9 22 3-3 3 3\" /> <rect width=\"7\" height=\"13\" x=\"14\" y=\"3\" rx=\"1\" /> </svg>',\n // 表格插入列入口使用,图形保持列方向,和 rows-plus 区分。\n 'columns-plus': '<svg aria-hidden=\"true\" class=\"lucide lucide-between-vertical-start\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <rect width=\"7\" height=\"13\" x=\"3\" y=\"8\" rx=\"1\" /> <path d=\"m15 2-3 3-3-3\" /> <rect width=\"7\" height=\"13\" x=\"14\" y=\"8\" rx=\"1\" /> </svg>',\n // 一级标题菜单使用,和 block.heading level 1 对应。\n 'heading-1': '<svg aria-hidden=\"true\" class=\"lucide lucide-heading-1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M4 12h8\" /> <path d=\"M4 18V6\" /> <path d=\"M12 18V6\" /> <path d=\"m17 12 3-2v8\" /> </svg>',\n // 二级标题菜单使用,和 block.heading level 2 对应。\n 'heading-2': '<svg aria-hidden=\"true\" class=\"lucide lucide-heading-2\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M4 12h8\" /> <path d=\"M4 18V6\" /> <path d=\"M12 18V6\" /> <path d=\"M21 18h-4c0-4 4-3 4-6 0-1.5-2-2.5-4-1\" /> </svg>',\n // 三级标题菜单使用,和 block.heading level 3 对应。\n 'heading-3': '<svg aria-hidden=\"true\" class=\"lucide lucide-heading-3\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M4 12h8\" /> <path d=\"M4 18V6\" /> <path d=\"M12 18V6\" /> <path d=\"M17.5 10.5c1.7-1 3.5 0 3.5 1.5a2 2 0 0 1-2 2\" /> <path d=\"M17 17.5c2 1.5 4 .3 4-1.5a2 2 0 0 0-2-2\" /> </svg>',\n // 四级标题菜单使用,和 block.heading level 4 对应。\n 'heading-4': '<svg aria-hidden=\"true\" class=\"lucide lucide-heading-4\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M12 18V6\" /> <path d=\"M17 10v3a1 1 0 0 0 1 1h3\" /> <path d=\"M21 10v8\" /> <path d=\"M4 12h8\" /> <path d=\"M4 18V6\" /> </svg>',\n // 五级标题菜单使用,和 block.heading level 5 对应。\n 'heading-5': '<svg aria-hidden=\"true\" class=\"lucide lucide-heading-5\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M4 12h8\" /> <path d=\"M4 18V6\" /> <path d=\"M12 18V6\" /> <path d=\"M17 13v-3h4\" /> <path d=\"M17 17.7c.4.2.8.3 1.3.3 1.5 0 2.7-1.1 2.7-2.5S19.8 13 18.3 13H17\" /> </svg>',\n // 六级标题菜单使用,和 block.heading level 6 对应。\n 'heading-6': '<svg aria-hidden=\"true\" class=\"lucide lucide-heading-6\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M4 12h8\" /> <path d=\"M4 18V6\" /> <path d=\"M12 18V6\" /> <circle cx=\"19\" cy=\"16\" r=\"2\" /> <path d=\"M20 10c-2 2-3 3.5-3 6\" /> </svg>',\n // 减少缩进菜单使用,和 indent.decrease 命令对应。\n 'indent-decrease': '<svg aria-hidden=\"true\" class=\"lucide lucide-indent-decrease\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M21 5H11\" /> <path d=\"M21 12H11\" /> <path d=\"M21 19H11\" /> <path d=\"m7 8-4 4 4 4\" /> </svg>',\n // 增加缩进菜单使用,和 indent.increase 命令对应。\n 'indent-increase': '<svg aria-hidden=\"true\" class=\"lucide lucide-indent-increase\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M21 5H11\" /> <path d=\"M21 12H11\" /> <path d=\"M21 19H11\" /> <path d=\"m3 8 4 4-4 4\" /> </svg>',\n // 斜体菜单和 hoverbar 斜体按钮共用,表示 format.italic。\n italic: '<svg aria-hidden=\"true\" class=\"lucide lucide-italic\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <line x1=\"19\" x2=\"10\" y1=\"4\" y2=\"4\" /> <line x1=\"14\" x2=\"5\" y1=\"20\" y2=\"20\" /> <line x1=\"15\" x2=\"9\" y1=\"4\" y2=\"20\" /> </svg>',\n // 有序列表菜单使用,表示 list.ordered。\n 'list-ordered': '<svg aria-hidden=\"true\" class=\"lucide lucide-list-ordered\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M11 5h10\" /> <path d=\"M11 12h10\" /> <path d=\"M11 19h10\" /> <path d=\"M4 4h1v5\" /> <path d=\"M4 9h2\" /> <path d=\"M6.5 20H3.4c0-1 2.6-1.925 2.6-3.5a1.5 1.5 0 0 0-2.6-1.02\" /> </svg>',\n // slash command 入口使用,表示打开候选命令列表。\n 'list-plus': '<svg aria-hidden=\"true\" class=\"lucide lucide-list-plus\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M16 5H3\" /> <path d=\"M11 12H3\" /> <path d=\"M16 19H3\" /> <path d=\"M18 9v6\" /> <path d=\"M21 12h-6\" /> </svg>',\n // 待办列表菜单使用,表示 list.todo。\n 'list-todo': '<svg aria-hidden=\"true\" class=\"lucide lucide-list-todo\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M13 5h8\" /> <path d=\"M13 12h8\" /> <path d=\"M13 19h8\" /> <path d=\"m3 17 2 2 4-4\" /> <rect x=\"3\" y=\"4\" width=\"6\" height=\"6\" rx=\"1\" /> </svg>',\n // 无序列表菜单使用,表示 list.unordered。\n list: '<svg aria-hidden=\"true\" class=\"lucide lucide-list\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M3 5h.01\" /> <path d=\"M3 12h.01\" /> <path d=\"M3 19h.01\" /> <path d=\"M8 5h13\" /> <path d=\"M8 12h13\" /> <path d=\"M8 19h13\" /> </svg>',\n // 全屏切换菜单使用,表示 fullscreen.toggle。\n maximize: '<svg aria-hidden=\"true\" class=\"lucide lucide-maximize\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M8 3H5a2 2 0 0 0-2 2v3\" /> <path d=\"M21 8V5a2 2 0 0 0-2-2h-3\" /> <path d=\"M3 16v3a2 2 0 0 0 2 2h3\" /> <path d=\"M16 21h3a2 2 0 0 0 2-2v-3\" /> </svg>',\n // 分割线菜单使用,表示 block.divider。\n minus: '<svg aria-hidden=\"true\" class=\"lucide lucide-minus\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M5 12h14\" /> </svg>',\n // 背景色菜单使用,表示 format.backgroundColor。\n 'paint-bucket': '<svg aria-hidden=\"true\" class=\"lucide lucide-paint-bucket\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M11 7 6 2\" /> <path d=\"M18.992 12H2.041\" /> <path d=\"M21.145 18.38A3.34 3.34 0 0 1 20 16.5a3.3 3.3 0 0 1-1.145 1.88c-.575.46-.855 1.02-.855 1.595A2 2 0 0 0 20 22a2 2 0 0 0 2-2.025c0-.58-.285-1.13-.855-1.595\" /> <path d=\"m8.5 4.5 2.148-2.148a1.205 1.205 0 0 1 1.704 0l7.296 7.296a1.205 1.205 0 0 1 0 1.704l-7.592 7.592a3.615 3.615 0 0 1-5.112 0l-3.888-3.888a3.615 3.615 0 0 1 0-5.112L5.67 7.33\" /> </svg>',\n // 文字颜色菜单使用,表示 format.color。\n palette: '<svg aria-hidden=\"true\" class=\"lucide lucide-palette\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z\" /> <circle cx=\"13.5\" cy=\"6.5\" r=\".5\" fill=\"currentColor\" /> <circle cx=\"17.5\" cy=\"10.5\" r=\".5\" fill=\"currentColor\" /> <circle cx=\"6.5\" cy=\"12.5\" r=\".5\" fill=\"currentColor\" /> <circle cx=\"8.5\" cy=\"7.5\" r=\".5\" fill=\"currentColor\" /> </svg>',\n // 正文段落菜单使用,表示 block.paragraph。\n pilcrow: '<svg aria-hidden=\"true\" class=\"lucide lucide-pilcrow\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M13 4v16\" /> <path d=\"M17 4v16\" /> <path d=\"M19 4H9.5a4.5 4.5 0 0 0 0 9H13\" /> </svg>',\n // 引用块菜单使用,表示 block.quote。\n quote: '<svg aria-hidden=\"true\" class=\"lucide lucide-quote\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M16 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z\" /> <path d=\"M5 3a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2 1 1 0 0 1 1 1v1a2 2 0 0 1-2 2 1 1 0 0 0-1 1v2a1 1 0 0 0 1 1 6 6 0 0 0 6-6V5a2 2 0 0 0-2-2z\" /> </svg>',\n // 重做菜单使用,表示 history.redo。\n redo: '<svg aria-hidden=\"true\" class=\"lucide lucide-redo\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M21 7v6h-6\" /> <path d=\"M3 17a9 9 0 0 1 9-9 9 9 0 0 1 6 2.3l3 2.7\" /> </svg>',\n // 清除样式菜单和 hoverbar 清除样式按钮共用,表示 format.clear。\n 'remove-formatting': '<svg aria-hidden=\"true\" class=\"lucide lucide-remove-formatting\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M4 7V4h16v3\" /> <path d=\"M5 20h6\" /> <path d=\"M13 4 8 20\" /> <path d=\"m15 15 5 5\" /> <path d=\"m20 15-5 5\" /> </svg>',\n // 表格删除行入口使用,图形保持行方向,和 columns-minus 区分。\n 'rows-minus': '<svg aria-hidden=\"true\" class=\"lucide lucide-between-horizontal-end\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <rect width=\"13\" height=\"7\" x=\"3\" y=\"3\" rx=\"1\" /> <path d=\"m22 15-3-3 3-3\" /> <rect width=\"13\" height=\"7\" x=\"3\" y=\"14\" rx=\"1\" /> </svg>',\n // 表格插入行入口使用,图形保持行方向,和 columns-plus 区分。\n 'rows-plus': '<svg aria-hidden=\"true\" class=\"lucide lucide-between-horizontal-start\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <rect width=\"13\" height=\"7\" x=\"8\" y=\"3\" rx=\"1\" /> <path d=\"m2 9 3 3-3 3\" /> <rect width=\"13\" height=\"7\" x=\"8\" y=\"14\" rx=\"1\" /> </svg>',\n // 代码块菜单使用,和行内代码的 code icon 区分为块级入口。\n 'square-code': '<svg aria-hidden=\"true\" class=\"lucide lucide-square-code\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"m10 9-3 3 3 3\" /> <path d=\"m14 15 3-3-3-3\" /> <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" /> </svg>',\n // 删除线菜单和 hoverbar 删除线按钮共用,表示 format.strike。\n strikethrough: '<svg aria-hidden=\"true\" class=\"lucide lucide-strikethrough\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M16 4H9a3 3 0 0 0-2.83 4\" /> <path d=\"M14 12a4 4 0 0 1 0 8H6\" /> <line x1=\"4\" x2=\"20\" y1=\"12\" y2=\"12\" /> </svg>',\n // 下标菜单使用,表示 format.subscript。\n subscript: '<svg aria-hidden=\"true\" class=\"lucide lucide-subscript\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"m4 5 8 8\" /> <path d=\"m12 5-8 8\" /> <path d=\"M20 19h-4c0-1.5.44-2 1.5-2.5S20 15.33 20 14c0-.47-.17-.93-.48-1.29a2.11 2.11 0 0 0-2.62-.44c-.42.24-.74.62-.9 1.07\" /> </svg>',\n // 上标菜单使用,表示 format.superscript。\n superscript: '<svg aria-hidden=\"true\" class=\"lucide lucide-superscript\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"m4 19 8-8\" /> <path d=\"m12 19-8-8\" /> <path d=\"M20 12h-4c0-1.5.442-2 1.5-2.5S20 8.334 20 7.002c0-.472-.17-.93-.484-1.29a2.105 2.105 0 0 0-2.617-.436c-.42.239-.738.614-.899 1.06\" /> </svg>',\n // 删除整张表格入口使用,沿用 table 轮廓保持表格上下文语义。\n 'table-delete': '<svg aria-hidden=\"true\" class=\"lucide lucide-table\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M12 3v18\" /> <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" /> <path d=\"M3 9h18\" /> <path d=\"M3 15h18\" /> </svg>',\n // 插入表格菜单使用,表示 table.insert。\n table: '<svg aria-hidden=\"true\" class=\"lucide lucide-table\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M12 3v18\" /> <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" /> <path d=\"M3 9h18\" /> <path d=\"M3 15h18\" /> </svg>',\n // 清空内容菜单使用,表示 content.clear,危险操作保持清理语义。\n 'trash-2': '<svg aria-hidden=\"true\" class=\"lucide lucide-trash-2\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M10 11v6\" /> <path d=\"M14 11v6\" /> <path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6\" /> <path d=\"M3 6h18\" /> <path d=\"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\" /> </svg>',\n // 字体菜单使用,表示 format.fontFamily。\n type: '<svg aria-hidden=\"true\" class=\"lucide lucide-type\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M12 4v16\" /> <path d=\"M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2\" /> <path d=\"M9 20h6\" /> </svg>',\n // 下划线菜单和 hoverbar 下划线按钮共用,表示 format.underline。\n underline: '<svg aria-hidden=\"true\" class=\"lucide lucide-underline\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M6 4v6a6 6 0 0 0 12 0V4\" /> <line x1=\"4\" x2=\"20\" y1=\"20\" y2=\"20\" /> </svg>',\n // 撤销菜单使用,表示 history.undo。\n undo: '<svg aria-hidden=\"true\" class=\"lucide lucide-undo\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M3 7v6h6\" /> <path d=\"M21 17a9 9 0 0 0-9-9 9 9 0 0 0-6 2.3L3 13\" /> </svg>',\n // 上传图片菜单使用,和 upload-video 分开,避免媒体类型在原生侧混淆。\n 'upload-image': '<svg aria-hidden=\"true\" class=\"lucide lucide-image\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" ry=\"2\" /> <circle cx=\"9\" cy=\"9\" r=\"2\" /> <path d=\"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21\" /> </svg>',\n // 上传视频菜单使用,和 upload-image 分开,避免媒体类型在原生侧混淆。\n 'upload-video': '<svg aria-hidden=\"true\" class=\"lucide lucide-video\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5\" /> <rect x=\"2\" y=\"6\" width=\"14\" height=\"12\" rx=\"2\" /> </svg>',\n // 行高菜单使用,表示 format.lineHeight。\n 'wrap-text': '<svg aria-hidden=\"true\" class=\"lucide lucide-wrap-text\" xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"m16 16-3 3 3 3\" /> <path d=\"M3 12h14.5a1 1 0 0 1 0 7H13\" /> <path d=\"M3 19h6\" /> <path d=\"M3 5h18\" /> </svg>'\n};\n","/**\n * 菜单文本兜底是 DOM 默认 icon 的最后一层保护。\n *\n * 内置菜单应优先使用 `defaultMenuIcons` 的 SVG;只有业务自定义菜单没有传 SVG,\n * 或 schema 新增 key 但默认 icon 还没补齐时,才显示 `MenuItem.label`,避免空按钮。\n * 这里不再维护按 id 缩写的字符图标表,防止内置菜单退回旧的 B/I/Img 字符视觉。\n */\nexport const createMenuTextIconElement = (text: string) => {\n const iconElement = document.createElement('span');\n\n iconElement.className = 'bridgerte__menu-icon-text';\n iconElement.textContent = text;\n\n return iconElement;\n};\n\n/**\n * 把菜单 icon 写入按钮或菜单项容器。\n *\n * 调用方先决定 iconSvg 的来源和优先级,例如 toolbar 需要先合并业务覆盖再落默认 SVG;\n * 这里只负责 DOM 写入和最终 label 文本兜底,不理解 `MenuItem`、hoverbar 或 toolbar 的命令语义。\n */\nexport const appendMenuIcon = (\n container: HTMLElement,\n iconSvg: string | undefined,\n fallbackText: string\n) => {\n if (iconSvg) {\n container.innerHTML = iconSvg;\n return;\n }\n\n container.append(createMenuTextIconElement(fallbackText));\n};\n\nexport { defaultMenuIcons } from './defaultIcons';\n","import type {\n ClearInteractionPressedState,\n InteractionPressedStateOptions\n} from './type';\n\nexport type * from './type';\n\n/**\n * 给触屏交互补一个稳定的按压态标记。\n *\n * H5 上浏览器的 `:active` 并不总是可靠,尤其在祖先节点调用 `preventDefault()`、\n * 触摸拖动或某些 WebView 环境里,伪类可能一闪而过甚至根本不出现。这里用\n * `data-pressed=\"true\"` 兜底,样式层再把它和 `:active` 绑定到同一套状态色。\n */\nexport const bindTouchPressedState = (\n element: HTMLElement,\n options: InteractionPressedStateOptions = {}\n): ClearInteractionPressedState => {\n let pressedElement: HTMLElement | null = null;\n\n const setPressed = (pressed: boolean) => {\n const target = pressedElement ?? element;\n\n if (!pressed && !pressedElement) return;\n\n if (pressed) {\n target.dataset.pressed = 'true';\n return;\n }\n\n delete target.dataset.pressed;\n pressedElement = null;\n };\n\n const handlePointerDown = (event: PointerEvent) => {\n if (event.pointerType === 'mouse') return;\n\n const target = event.target;\n\n pressedElement = target instanceof HTMLElement && options.targetSelector\n ? target.closest<HTMLElement>(options.targetSelector)\n : element;\n if (!pressedElement) return;\n\n setPressed(true);\n };\n\n const clearPressed = () => {\n setPressed(false);\n };\n\n element.addEventListener('pointerdown', handlePointerDown);\n element.addEventListener('pointerup', clearPressed);\n element.addEventListener('pointercancel', clearPressed);\n element.addEventListener('lostpointercapture', clearPressed);\n\n return () => {\n clearPressed();\n element.removeEventListener('pointerdown', handlePointerDown);\n element.removeEventListener('pointerup', clearPressed);\n element.removeEventListener('pointercancel', clearPressed);\n element.removeEventListener('lostpointercapture', clearPressed);\n };\n};\n","import type {\n CommandState,\n MenuItem,\n MenuLabelOverrides,\n PayloadPanelConfig,\n PayloadPanelValues\n} from '@bridgerte/core';\nimport { resolvePayloadPanelSchema } from '@bridgerte/core';\nimport { isCommandStateForCommand } from '@bridgerte/native-spec';\n\n/**\n * 应用菜单展示覆盖。\n *\n * label override 只改变 DOM 菜单的展示、tooltip 和无障碍名称;\n * command、payloadPanel、icon key 和 schema id 保持原样,避免业务配置误改执行语义。\n */\nexport const resolveMenuSchemaForDom = (\n menuSchema: MenuItem[],\n options: {\n menuLabels?: MenuLabelOverrides;\n payloadPanelConfig?: PayloadPanelConfig;\n } = {}\n) => menuSchema.map((item) => {\n const label = options.menuLabels?.[item.id];\n const payloadPanel = item.payloadPanel\n ? resolvePayloadPanelSchema(item.payloadPanel, options.payloadPanelConfig)\n : undefined;\n\n return {\n ...item,\n ...(label === undefined ? {} : { label }),\n ...(payloadPanel === undefined ? {} : { payloadPanel })\n };\n});\n\n/**\n * 从 CommandState 回填参数面板当前值。\n *\n * toolbar 和 hoverbar 都只知道 `CommandState.value` 这一个稳定状态出口;\n * 具体字段如何渲染仍交给同一份 payloadPanel schema 或业务自绘层处理。\n */\nexport const getPayloadPanelCurrentValues = (\n item: MenuItem,\n commandStates: CommandState[]\n): PayloadPanelValues | undefined => {\n const state = commandStates.find((commandState) => (\n commandState.command === item.command.type\n ));\n\n return state?.value === undefined\n ? undefined\n : { value: String(state.value) };\n};\n\n/**\n * 把完整菜单命令映射到当前 CommandState。\n *\n * 同类命令需要同时比较 `CommandState.value`,例如 heading level、align value 和未来媒体尺寸;\n * 带 payloadPanel 的菜单只使用同 command type 的 disabled 状态,避免空 payload command\n * 和当前真实值不一致时错误禁用按钮。\n */\nexport const getMenuStateForItem = (\n item: MenuItem,\n commandStates: CommandState[]\n) => {\n const exactState = commandStates.find((state) => isCommandStateForCommand(item.command, state));\n const commandTypeState = commandStates.find((state) => state.command === item.command.type);\n\n return {\n active: exactState?.active === true,\n disabled: item.payloadPanel\n ? commandTypeState?.disabled === true\n : exactState?.disabled === true || commandTypeState?.disabled === true\n };\n};\n","import type { CommandState } from '@bridgerte/core';\nimport {\n defaultMenuSchema,\n resolveToolbarMenu,\n type MenuItem,\n type ResolvedToolbarItem\n} from '@bridgerte/native-spec';\nimport {\n appendMenuIcon,\n defaultMenuIcons\n} from './icons';\nimport { bindTouchPressedState } from '../interactionState';\nimport {\n getMenuStateForItem,\n getPayloadPanelCurrentValues,\n resolveMenuSchemaForDom\n} from '../menuRuntime';\nimport type {\n RichTextToolbarAPI,\n RichTextToolbarIcons,\n RichTextToolbarOptions,\n ToolbarDragState\n} from './type';\n\nconst toolbarDragClickThresholdPx = 4;\nconst toolbarTooltipOffsetPx = 8;\nconst toolbarButtonSelector = 'button[data-bridgerte-toolbar-item-id]';\n\nexport type * from './type';\n\nconst canUseHoverTooltip = () => (\n typeof window !== 'undefined'\n && window.matchMedia?.('(hover: hover) and (pointer: fine)').matches === true\n);\n\nconst getToolbarButtonFromTarget = (target: EventTarget | null) => {\n /*\n * 图标覆盖常用 SVG,H5 pointer 事件可能落在 svg/path 上。\n * 这里用 Element 而不是 HTMLElement,保证触屏兜底和 click 都能向上命中真实按钮。\n */\n const button = target instanceof Element\n ? target.closest<HTMLButtonElement>(toolbarButtonSelector)\n : null;\n\n return button instanceof HTMLButtonElement ? button : null;\n};\n\nconst renderToolbarButton = (\n groupElement: HTMLElement,\n item: MenuItem,\n commandStates: CommandState[],\n icons: RichTextToolbarIcons,\n enableTooltip: boolean\n) => {\n const state = getMenuStateForItem(item, commandStates);\n const button = document.createElement('button');\n // icon 兜底顺序固定为:业务覆盖 > DOM 默认 SVG > label 文本。\n const iconSvg = icons[item.icon] ?? defaultMenuIcons[item.icon];\n\n button.type = 'button';\n button.className = 'bridgerte__toolbar-button';\n button.disabled = state.disabled;\n button.dataset.active = String(state.active);\n button.dataset.bridgerteToolbarItemId = item.id;\n button.setAttribute('aria-label', item.label);\n button.setAttribute('aria-pressed', String(state.active));\n if (enableTooltip) button.dataset.tooltip = item.label;\n\n appendMenuIcon(button, iconSvg, item.label);\n\n groupElement.append(button);\n};\n\nconst renderToolbar = (\n toolbarElement: HTMLElement,\n toolbarItems: ResolvedToolbarItem[],\n commandStates: CommandState[],\n icons: RichTextToolbarIcons,\n enableTooltip: boolean\n) => {\n toolbarElement.textContent = '';\n\n let currentGroup = '';\n let groupElement: HTMLDivElement | null = null;\n\n toolbarItems.forEach((toolbarItem) => {\n if (toolbarItem.type === 'separator') {\n currentGroup = '';\n groupElement = null;\n\n const separatorElement = document.createElement('span');\n\n separatorElement.className = 'bridgerte__toolbar-separator';\n separatorElement.dataset.separatorId = toolbarItem.key;\n separatorElement.setAttribute('aria-hidden', 'true');\n toolbarElement.append(separatorElement);\n return;\n }\n\n const nextGroup = toolbarItem.type === 'button' ? toolbarItem.item.group : toolbarItem.key;\n\n if (!groupElement || currentGroup !== nextGroup) {\n currentGroup = nextGroup;\n groupElement = document.createElement('div');\n groupElement.className = 'bridgerte__toolbar-group';\n groupElement.dataset.group = nextGroup;\n if (toolbarItem.type === 'group') {\n groupElement.setAttribute('aria-label', toolbarItem.title);\n }\n toolbarElement.append(groupElement);\n }\n\n const activeGroupElement = groupElement;\n\n if (toolbarItem.type === 'button') {\n renderToolbarButton(\n activeGroupElement,\n toolbarItem.item,\n commandStates,\n icons,\n enableTooltip\n );\n return;\n }\n\n toolbarItem.items.forEach((item) => {\n renderToolbarButton(\n activeGroupElement,\n item,\n commandStates,\n icons,\n enableTooltip\n );\n });\n });\n};\n\n/**\n * 创建独立菜单实例。\n *\n * toolbar/tabbar 只订阅 EditorAPI 状态并派发命令,不接触编辑器内部 DOM 或 Lexical 实例。\n */\nexport function createRichTextToolbar(\n container: HTMLElement,\n options: RichTextToolbarOptions\n): RichTextToolbarAPI {\n const placement = options.placement ?? 'top';\n const menuSchema = resolveMenuSchemaForDom(options.menuSchema ?? defaultMenuSchema, {\n menuLabels: options.menuLabels,\n payloadPanelConfig: options.payloadPanelConfig\n });\n const toolbarItems = resolveToolbarMenu(options.toolbarConfig, menuSchema);\n /*\n * click 事件只需要能执行命令的菜单项。分割线和 group 容器是渲染结构,\n * 先在这里摊平,后续点击时就不用理解 toolbarConfig 的展示层级。\n */\n const executableMenuItems = toolbarItems.flatMap((toolbarItem) => (\n toolbarItem.type === 'button' ? [toolbarItem.item]\n : toolbarItem.type === 'group' ? toolbarItem.items\n : []\n ));\n const icons = options.icons ?? {};\n /*\n * tooltip 只属于 PC 精细指针体验。H5 上即使没有原生 title,部分浏览器也会把 hover/mouseover\n * 模拟成首触摸状态,导致第一次点像是只唤醒提示;所以触屏端不写 tooltip 数据也不挂监听。\n */\n const enableTooltip = canUseHoverTooltip();\n const tooltipElement = document.createElement('div');\n const overlayHost = container.closest('.bridgerte') ?? container;\n let destroyed = false;\n let dragState: ToolbarDragState | null = null;\n let shouldSuppressNextClick = false;\n const clearToolbarPressedState = bindTouchPressedState(container, {\n targetSelector: 'button[data-bridgerte-toolbar-item-id]'\n });\n\n const mountToolbarOverlays = () => {\n // 独立 toolbar 可能不在 `.bridgerte` 内,渲染按钮会清空 container,需要把浮层重新挂回去。\n overlayHost.append(tooltipElement);\n };\n\n const renderStates = (states: CommandState[]) => {\n if (destroyed) return;\n\n renderToolbar(container, toolbarItems, states, icons, enableTooltip);\n mountToolbarOverlays();\n };\n\n const update = () => {\n if (destroyed) return;\n\n renderStates(options.editor.getCommandStates());\n };\n\n const hideTooltip = () => {\n tooltipElement.dataset.visible = 'false';\n tooltipElement.textContent = '';\n };\n\n const showTooltip = (button: HTMLButtonElement) => {\n const tooltipText = button.dataset.tooltip;\n\n if (!enableTooltip || !tooltipText || dragState) return;\n\n const buttonRect = button.getBoundingClientRect();\n\n tooltipElement.textContent = tooltipText;\n tooltipElement.dataset.visible = 'true';\n tooltipElement.style.left = `${buttonRect.left + buttonRect.width / 2}px`;\n tooltipElement.style.top = `${buttonRect.top - toolbarTooltipOffsetPx}px`;\n };\n\n const handleTooltipTarget = (event: Event) => {\n const button = getToolbarButtonFromTarget(event.target);\n\n if (button) {\n showTooltip(button);\n }\n };\n\n const handleTooltipLeave = (event: MouseEvent) => {\n const relatedTarget = event.relatedTarget;\n const button = getToolbarButtonFromTarget(event.target);\n\n if (\n button\n && relatedTarget instanceof Node\n && button.contains(relatedTarget)\n ) return;\n\n hideTooltip();\n };\n\n const stopToolbarDrag = () => {\n dragState = null;\n\n delete container.dataset.dragging;\n // 拖动过程中监听挂在 document 上,松手或 destroy 必须统一清掉,避免离开 toolbar 后残留滚动状态。\n document.removeEventListener('pointermove', handlePointerMove);\n document.removeEventListener('pointerup', handlePointerUp);\n document.removeEventListener('pointercancel', handlePointerUp);\n };\n\n const handlePointerMove = (event: PointerEvent) => {\n if (!dragState) return;\n\n const deltaX = dragState.startClientX - event.clientX;\n\n if (Math.abs(deltaX) > toolbarDragClickThresholdPx) {\n dragState.hasDragged = true;\n shouldSuppressNextClick = true;\n hideTooltip();\n }\n\n container.scrollLeft = dragState.startScrollLeft + deltaX;\n };\n\n const handlePointerUp = (event: PointerEvent) => {\n const currentDragState = dragState;\n\n stopToolbarDrag();\n if (\n currentDragState\n && event.type !== 'pointercancel'\n && currentDragState.pointerType !== 'mouse'\n && !currentDragState.hasDragged\n && currentDragState.startButton\n ) {\n executeToolbarButton(currentDragState.startButton);\n shouldSuppressNextClick = true;\n }\n };\n\n const handlePointerDown = (event: PointerEvent) => {\n if (event.pointerType === 'mouse' && event.button !== 0) return;\n\n const startButton = getToolbarButtonFromTarget(event.target);\n\n // 点击和拖动 toolbar 都要保留编辑区 selection,命令才能继续作用在原选区。\n event.preventDefault();\n dragState = {\n startClientX: event.clientX,\n startScrollLeft: container.scrollLeft,\n pointerType: event.pointerType,\n hasDragged: false,\n startButton: startButton ?? undefined\n };\n container.dataset.dragging = 'true';\n hideTooltip();\n // pointermove 放到 document,保证用户按住 X 轴拖出 toolbar 后仍能完成滚动和释放。\n document.addEventListener('pointermove', handlePointerMove);\n document.addEventListener('pointerup', handlePointerUp);\n document.addEventListener('pointercancel', handlePointerUp);\n };\n\n const executeToolbarButton = (button: HTMLButtonElement) => {\n if (!(button instanceof HTMLButtonElement) || button.disabled) return;\n\n const menuItem = executableMenuItems.find((item) => (\n item.id === button.dataset.bridgerteToolbarItemId\n ));\n\n if (!menuItem) return;\n\n options.editor.focus();\n if (menuItem.payloadPanel) {\n const buttonRect = button.getBoundingClientRect();\n\n /*\n * 带 payloadPanel 的菜单不直接执行基础 command,而是发起参数请求。\n * DOM 内置面板和业务/RN/Flutter 自绘都走同一个 request,避免后续颜色、\n * 字体、链接等参数菜单各自发明一套协议。\n */\n options.editor.requestPayloadPanel({\n menuId: menuItem.id,\n command: menuItem.command,\n panel: menuItem.payloadPanel,\n currentValues: getPayloadPanelCurrentValues(menuItem, options.editor.getCommandStates()),\n anchorRect: {\n x: buttonRect.left,\n y: buttonRect.top,\n width: buttonRect.width,\n height: buttonRect.height\n }\n });\n return;\n }\n\n options.editor.executeCommand(menuItem.command);\n };\n\n const handleClick = (event: MouseEvent) => {\n if (shouldSuppressNextClick) {\n shouldSuppressNextClick = false;\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n const button = getToolbarButtonFromTarget(event.target);\n if (!button) return;\n\n executeToolbarButton(button);\n };\n\n container.classList.add('bridgerte__toolbar');\n tooltipElement.className = 'bridgerte__toolbar-tooltip';\n tooltipElement.dataset.visible = 'false';\n container.dataset.placement = placement;\n container.setAttribute('role', 'toolbar');\n container.setAttribute(\n 'aria-label',\n placement === 'bottom' ? 'BridgeRTE tabbar' : 'BridgeRTE toolbar'\n );\n container.addEventListener('pointerdown', handlePointerDown, true);\n container.addEventListener('click', handleClick);\n if (enableTooltip) {\n container.addEventListener('mouseover', handleTooltipTarget);\n container.addEventListener('mouseout', handleTooltipLeave);\n }\n container.addEventListener('focusout', hideTooltip);\n // 浮层挂在最近的编辑器根容器下,既能继承变量,也不会操作编辑内容 DOM。\n mountToolbarOverlays();\n\n // 独立 toolbar 只订阅 public API 状态,不依赖 DOM 编辑器内部实现。\n const unsubscribe = options.editor.subscribeCommandStateChange(renderStates);\n\n return {\n update,\n destroy() {\n if (destroyed) return;\n\n destroyed = true;\n stopToolbarDrag();\n unsubscribe();\n container.removeEventListener('pointerdown', handlePointerDown, true);\n container.removeEventListener('click', handleClick);\n if (enableTooltip) {\n container.removeEventListener('mouseover', handleTooltipTarget);\n container.removeEventListener('mouseout', handleTooltipLeave);\n }\n clearToolbarPressedState();\n container.removeEventListener('focusout', hideTooltip);\n tooltipElement.remove();\n container.classList.remove('bridgerte__toolbar');\n delete container.dataset.placement;\n container.textContent = '';\n container.removeAttribute('role');\n container.removeAttribute('aria-label');\n }\n };\n}\n","import { $getSelection, $isRangeSelection } from 'lexical';\nimport type { CommandState } from '@bridgerte/core';\nimport { $isCodeNode } from '@lexical/code';\nimport { $isHeadingNode, $isQuoteNode } from '@lexical/rich-text';\nimport { $isListNode, ListNode } from '@lexical/list';\nimport { $getSelectionStyleValueForProperty } from '@lexical/selection';\nimport { $getNearestNodeOfType } from '@lexical/utils';\nimport { $isLinkNode } from '@lexical/link';\nimport type { SelectionCommandStateOptions } from './type';\n\nexport type * from './type';\n\nconst inlineFormatSpecs = [\n { command: 'format.bold', format: 'bold' },\n { command: 'format.italic', format: 'italic' },\n { command: 'format.underline', format: 'underline' },\n { command: 'format.strike', format: 'strikethrough' },\n { command: 'format.inlineCode', format: 'code' },\n { command: 'format.superscript', format: 'superscript' },\n { command: 'format.subscript', format: 'subscript' }\n] as const;\n\nconst inlineStyleSpecs = [\n { command: 'format.color', property: 'color' },\n { command: 'format.backgroundColor', property: 'background-color' },\n { command: 'format.fontSize', property: 'font-size' },\n { command: 'format.fontFamily', property: 'font-family' },\n { command: 'format.lineHeight', property: 'line-height' }\n] as const;\n\nconst listStateSpecs = [\n { command: 'list.ordered', listType: 'ordered' },\n { command: 'list.unordered', listType: 'unordered' },\n { command: 'list.todo', listType: 'todo' }\n] as const;\n\nconst uploadCommandSpecs = [\n 'media.pickImage',\n 'media.pickVideo'\n] as const;\n\nconst getSelectionBlock = () => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) return null;\n\n const node = selection.anchor.getNode();\n\n return node.getKey() === 'root' ? node : node.getTopLevelElementOrThrow();\n};\n\nconst getSelectionBlockState = (): Pick<CommandState, 'command' | 'value'> | null => {\n const block = getSelectionBlock();\n\n if (!block) return null;\n\n if ($isHeadingNode(block)) {\n const level = Number(block.getTag().replace('h', ''));\n\n return {\n command: 'block.heading',\n value: Number.isNaN(level) ? undefined : level\n };\n }\n\n if ($isQuoteNode(block)) {\n return {\n command: 'block.quote'\n };\n }\n\n if ($isCodeNode(block)) {\n const latestBlock = block.getLatest();\n\n return {\n command: 'block.code',\n value: $isCodeNode(latestBlock) ? latestBlock.getLanguage() ?? '' : ''\n };\n }\n\n return {\n command: 'block.paragraph'\n };\n};\n\nconst getSelectionAlignValue = (): string | undefined => {\n const block = getSelectionBlock();\n\n if (!block || !('getFormatType' in block)) return undefined;\n\n const formatType = block.getFormatType();\n\n return formatType === '' ? undefined : formatType;\n};\n\nconst getSelectionListType = (): 'ordered' | 'unordered' | 'todo' | null => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) return null;\n\n const node = selection.anchor.getNode();\n const listNode = $isListNode(node) ? node : $getNearestNodeOfType(node, ListNode);\n\n if (!listNode) return null;\n\n if (listNode.getListType() === 'check') return 'todo';\n\n return listNode.getTag() === 'ol' ? 'ordered' : 'unordered';\n};\n\nconst getSelectionStyleValue = (property: string): string | undefined => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) return undefined;\n\n const value = $getSelectionStyleValueForProperty(selection, property);\n\n return value === '' ? undefined : value;\n};\n\nconst isSelectionInsideLink = (): boolean => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) return false;\n\n const node = selection.anchor.getNode();\n const parent = node.getParent();\n\n return $isLinkNode(node) || $isLinkNode(parent);\n};\n\n/**\n * 从当前选区推导 toolbar/native 菜单所需的最小状态。\n *\n * 这里不能扫描全文,后续 10w 内容下 selection 高频变化也只读取当前位置。\n */\nexport const getSelectionCommandStates = (\n options: SelectionCommandStateOptions\n): CommandState[] => {\n const selection = $getSelection();\n const isRangeSelection = $isRangeSelection(selection);\n const blockState = getSelectionBlockState();\n const listType = getSelectionListType();\n const alignValue = getSelectionAlignValue();\n /*\n * inline style 状态只读取 selection 中 TextNode 的 style 值,不扫描全文。\n * 如果选区内值不一致,Lexical 返回空字符串,这里转成 undefined 给菜单显示混合态。\n */\n const isInsideLink = isSelectionInsideLink();\n const rangeDisabled = options.readonly || !isRangeSelection;\n /*\n * inline format/style/list 的状态模式完全一致,集中成 specs 生成,避免新增同类命令时\n * 在长数组里复制对象字面量;块、链接、历史等有额外业务条件的状态仍保留显式对象。\n */\n const inlineFormatStates: CommandState[] = inlineFormatSpecs.map((spec) => ({\n command: spec.command,\n active: isRangeSelection && selection.hasFormat(spec.format),\n disabled: rangeDisabled\n }));\n const inlineStyleStates: CommandState[] = inlineStyleSpecs.map((spec) => {\n const value = getSelectionStyleValue(spec.property);\n\n return {\n command: spec.command,\n active: value !== undefined,\n disabled: rangeDisabled,\n value\n };\n });\n const listStates: CommandState[] = listStateSpecs.map((spec) => ({\n command: spec.command,\n active: listType === spec.listType,\n disabled: rangeDisabled\n }));\n const uploadStates: CommandState[] = uploadCommandSpecs.map((command) => ({\n command,\n active: false,\n disabled: options.readonly || !options.canUploadMedia\n }));\n\n return [\n ...inlineFormatStates,\n {\n command: 'format.clear',\n active: false,\n disabled: rangeDisabled\n },\n ...inlineStyleStates,\n {\n command: 'block.heading',\n active: blockState?.command === 'block.heading',\n disabled: rangeDisabled,\n value: blockState?.command === 'block.heading' ? blockState.value : undefined\n },\n {\n command: 'block.paragraph',\n active: blockState?.command === 'block.paragraph',\n disabled: rangeDisabled\n },\n {\n command: 'block.quote',\n active: blockState?.command === 'block.quote',\n disabled: rangeDisabled\n },\n {\n command: 'block.divider',\n active: false,\n disabled: options.readonly\n },\n {\n command: 'block.code',\n active: blockState?.command === 'block.code',\n disabled: options.readonly,\n value: blockState?.command === 'block.code' ? blockState.value : undefined\n },\n ...listStates,\n {\n command: 'align',\n active: alignValue !== undefined,\n disabled: rangeDisabled,\n value: alignValue\n },\n {\n command: 'link.set',\n active: isInsideLink,\n disabled: rangeDisabled\n },\n {\n command: 'link.unset',\n active: false,\n disabled: rangeDisabled || !isInsideLink\n },\n {\n command: 'link.open',\n active: false,\n disabled: options.readonly || !isInsideLink\n },\n {\n command: 'indent.increase',\n active: false,\n disabled: rangeDisabled\n },\n {\n command: 'indent.decrease',\n active: false,\n disabled: rangeDisabled\n },\n {\n command: 'history.undo',\n active: false,\n disabled: options.readonly || !options.canUndo\n },\n {\n command: 'history.redo',\n active: false,\n disabled: options.readonly || !options.canRedo\n },\n {\n command: 'content.clear',\n active: false,\n disabled: options.readonly\n },\n ...uploadStates,\n {\n command: 'table.insert',\n active: false,\n disabled: options.readonly\n },\n {\n command: 'fullscreen.toggle',\n active: false,\n disabled: false\n }\n ];\n};\n\n/**\n * 判断两批命令状态是否有业务变化,避免 selection/update 高频事件重复通知宿主。\n */\nexport const areCommandStatesEqual = (\n left: CommandState[],\n right: CommandState[]\n): boolean => (\n left.length === right.length\n && left.every((state, index) => {\n const nextState = right[index];\n\n return nextState !== undefined\n && state.command === nextState.command\n && state.active === nextState.active\n && state.disabled === nextState.disabled\n && state.value === nextState.value;\n })\n);\n","import type {\n CommandState,\n EditorAPI,\n EditorContent,\n EditorContentChange,\n RichTextEditorOptions\n} from '@bridgerte/core';\n\n/**\n * 统一上报 DOM SDK 内部错误。\n *\n * 回调自身抛错时只打印到控制台,避免用户回调异常再次打断编辑器生命周期。\n */\nexport const reportEditorError = (\n options: RichTextEditorOptions,\n code: string,\n message: string,\n cause: unknown\n) => {\n try {\n options.onError?.({ code, message, cause });\n } catch (error) {\n console.error('[BridgeRTE] onError callback failed.', error);\n }\n};\n\n/**\n * 包装 onChange,保证业务回调异常会进入 onError,而不是中断 Lexical update listener。\n */\nexport const notifyChange = (options: RichTextEditorOptions, content: EditorContent) => {\n try {\n options.onChange?.(content);\n } catch (error) {\n reportEditorError(options, 'callback.onChange', 'onChange callback failed.', error);\n }\n};\n\n/**\n * 包装轻量内容变更回调。\n *\n * 这个回调位于高频输入链路,只传摘要信息;业务如果需要完整 html/json/plainText,\n * 应在保存或主动读取时调用 `getContent()`。\n */\nexport const notifyContentChange = (\n options: RichTextEditorOptions,\n change: EditorContentChange\n) => {\n try {\n options.onContentChange?.(change);\n } catch (error) {\n reportEditorError(\n options,\n 'callback.onContentChange',\n 'onContentChange callback failed.',\n error\n );\n }\n};\n\n/**\n * 复制一份 CommandState 再通知业务,避免外部误改 editor 内部状态数组。\n */\nexport const notifyCommandStateChange = (\n options: RichTextEditorOptions,\n commandStates: CommandState[]\n) => {\n try {\n options.onCommandStateChange?.([...commandStates]);\n } catch (error) {\n reportEditorError(\n options,\n 'callback.onCommandStateChange',\n 'onCommandStateChange callback failed.',\n error\n );\n }\n};\n\nexport const notifyFocus = (options: RichTextEditorOptions) => {\n try {\n options.onFocus?.();\n } catch (error) {\n reportEditorError(options, 'callback.onFocus', 'onFocus callback failed.', error);\n }\n};\n\nexport const notifyBlur = (options: RichTextEditorOptions) => {\n try {\n options.onBlur?.();\n } catch (error) {\n reportEditorError(options, 'callback.onBlur', 'onBlur callback failed.', error);\n }\n};\n\nexport const notifyReady = (options: RichTextEditorOptions, api: EditorAPI) => {\n try {\n options.onReady?.(api);\n } catch (error) {\n reportEditorError(options, 'callback.onReady', 'onReady callback failed.', error);\n }\n};\n","import type { CommandState } from '@bridgerte/core';\nimport { areCommandStatesEqual, getSelectionCommandStates } from '../commandState';\nimport {\n notifyCommandStateChange,\n reportEditorError\n} from './errorReporter';\nimport type {\n RichTextEditorCommandStateRuntime,\n RichTextEditorCommandStateRuntimeOptions\n} from './type';\n\n/**\n * 创建命令状态 runtime。\n *\n * toolbar/tabbar 通过这里订阅 CommandState,runtime 只读取当前 selection 和 undo/redo\n * 状态,不做全文扫描,避免 selection 高频变化时拖慢大文档输入。\n */\nexport const createRichTextEditorCommandStateRuntime = ({\n lexicalEditor,\n options,\n isDestroyed,\n canUploadMedia,\n isReadonly\n}: RichTextEditorCommandStateRuntimeOptions): RichTextEditorCommandStateRuntime => {\n let canUndo = false;\n let canRedo = false;\n let commandStates: CommandState[] = [];\n // 独立 toolbar/tabbar 通过这组监听器订阅状态,避免直接触碰 Lexical 或 DOM 内容。\n const commandStateListeners = new Set<(states: CommandState[]) => void>();\n\n const notifyCommandStateListeners = () => {\n const nextStates = [...commandStates];\n\n commandStateListeners.forEach((listener) => {\n try {\n listener(nextStates);\n } catch (error) {\n reportEditorError(\n options,\n 'callback.commandStateSubscriber',\n 'Command state subscriber failed.',\n error\n );\n }\n });\n };\n\n const refreshCommandStates = (shouldNotify = true) => {\n if (isDestroyed()) return;\n\n const previousStates = commandStates;\n\n // CommandState 只从当前 selection 和 undo/redo 能力推导,不能为了 toolbar 状态扫描全文。\n lexicalEditor.getEditorState().read(() => {\n commandStates = getSelectionCommandStates({\n canUndo,\n canRedo,\n readonly: isReadonly(),\n canUploadMedia: canUploadMedia()\n });\n });\n\n if (shouldNotify && !areCommandStatesEqual(previousStates, commandStates)) {\n notifyCommandStateChange(options, commandStates);\n notifyCommandStateListeners();\n }\n };\n\n return {\n refreshCommandStates,\n getCommandStates() {\n refreshCommandStates(false);\n\n return [...commandStates];\n },\n subscribeCommandStateChange(listener) {\n if (isDestroyed()) return () => {};\n\n commandStateListeners.add(listener);\n listener([...commandStates]);\n\n return () => {\n commandStateListeners.delete(listener);\n };\n },\n setCanUndo(value) {\n canUndo = value;\n refreshCommandStates();\n },\n setCanRedo(value) {\n canRedo = value;\n refreshCommandStates();\n },\n setHistoryAvailability(nextCanUndo, nextCanRedo) {\n canUndo = nextCanUndo;\n canRedo = nextCanRedo;\n refreshCommandStates();\n },\n destroy() {\n commandStateListeners.clear();\n }\n };\n};\n","import {\n $createParagraphNode,\n $getRoot,\n $getSelection,\n $insertNodes\n} from 'lexical';\nimport type { UploadFileLike, UploadResult } from '@bridgerte/core';\nimport {\n $createBridgeMediaNode,\n $findBridgeMediaNodeByAssetId,\n type BridgeMediaPayload,\n type BridgeMediaType\n} from '../mediaNode';\nimport type {\n RichTextEditorMediaUploader,\n RichTextEditorMediaUploadOptions,\n RichTextEditorMediaUploadTask\n} from './type';\n\nconst createUploadAssetId = (type: BridgeMediaType) => (\n `upload:${type}:${Date.now()}:${Math.random().toString(36).slice(2)}`\n);\n\nconst getFilePreviewUrl = (file: File) => (\n typeof URL.createObjectURL === 'function' ? URL.createObjectURL(file) : file.name\n);\n\nconst revokeFilePreviewUrl = (url: string) => {\n if (typeof URL.revokeObjectURL === 'function' && url.startsWith('blob:')) {\n URL.revokeObjectURL(url);\n }\n};\n\nconst toUploadFileLike = (file: File): UploadFileLike => ({\n name: file.name,\n mimeType: file.type || undefined,\n size: file.size,\n data: file\n});\n\nconst isAbortError = (error: unknown) => (\n typeof DOMException !== 'undefined' && error instanceof DOMException && error.name === 'AbortError'\n);\n\n/**\n * 创建 DOM 媒体上传控制器。\n *\n * commandExecutor 只负责分发命令,上传控制器负责文件选择、上传中占位、进度回写和成功/失败\n * 状态更新。异步回写始终按 assetId 查找当前节点,用户删除节点后不会误改其它内容。\n */\nexport const createRichTextEditorMediaUploader = ({\n container,\n lexicalEditor,\n options,\n isDestroyed\n}: RichTextEditorMediaUploadOptions): RichTextEditorMediaUploader => {\n /*\n * 上传任务只保存运行时资源:原始 File、object URL 和 AbortController。\n * 内容协议仍以媒体节点为准,避免把浏览器 File 这类不可跨端数据写入 JSON。\n */\n const uploadTasks = new Map<string, RichTextEditorMediaUploadTask>();\n let nextRunId = 0;\n\n const updateMediaNode = (\n assetId: string,\n payload: Partial<BridgeMediaPayload>\n ) => {\n lexicalEditor.update(() => {\n $findBridgeMediaNodeByAssetId(assetId)?.updatePayload(payload);\n });\n };\n\n const removeMediaNode = (assetId: string): BridgeMediaPayload | null => {\n let removedPayload: BridgeMediaPayload | null = null;\n\n lexicalEditor.update(() => {\n const mediaNode = $findBridgeMediaNodeByAssetId(assetId);\n\n if (!mediaNode) return;\n\n const asset = mediaNode.getAsset();\n\n removedPayload = {\n mediaType: asset.type,\n url: asset.url,\n assetId: asset.id,\n status: asset.status,\n progress: asset.progress,\n poster: asset.poster,\n width: asset.width,\n height: asset.height,\n duration: asset.duration,\n mimeType: asset.mimeType,\n size: asset.size,\n displayWidthPercent: asset.displayWidthPercent,\n align: asset.align,\n errorMessage: asset.errorMessage\n };\n mediaNode.remove();\n });\n\n return removedPayload;\n };\n\n const isCurrentRun = (assetId: string, runId: number) => {\n const task = uploadTasks.get(assetId);\n\n return task?.runId === runId;\n };\n\n const abortTask = (task: RichTextEditorMediaUploadTask) => {\n task.abortController?.abort();\n };\n\n const clearTask = (assetId: string, shouldAbort: boolean) => {\n const task = uploadTasks.get(assetId);\n\n if (!task) return false;\n\n if (shouldAbort) abortTask(task);\n revokeFilePreviewUrl(task.previewUrl);\n uploadTasks.delete(assetId);\n\n return true;\n };\n\n const insertUploadingMedia = (\n type: BridgeMediaType,\n file: File,\n assetId: string,\n previewUrl: string\n ) => {\n lexicalEditor.update(\n () => {\n const mediaNode = $createBridgeMediaNode({\n mediaType: type,\n url: previewUrl,\n assetId,\n status: 'uploading',\n progress: 0,\n title: file.name,\n mimeType: file.type || undefined,\n size: file.size\n });\n const paragraphNode = $createParagraphNode();\n\n /*\n * 上传先落一个稳定媒体节点,再异步替换最终 URL。\n * paste/drop 可能发生在没有 Lexical selection 的空编辑器里;这时先把选区落到\n * root 末尾。discrete update 保证占位节点先入树,再启动可能立即返回的 adapter。\n */\n if (!$getSelection()) {\n $getRoot().selectEnd();\n }\n $insertNodes([mediaNode, paragraphNode]);\n paragraphNode.selectStart();\n },\n { discrete: true }\n );\n };\n\n const applyUploadResult = (\n type: BridgeMediaType,\n assetId: string,\n previewUrl: string,\n result: UploadResult\n ) => {\n updateMediaNode(assetId, {\n mediaType: type,\n url: result.url,\n poster: result.poster,\n width: result.width,\n height: result.height,\n duration: result.duration,\n mimeType: result.mimeType,\n size: result.size,\n status: 'success',\n progress: 100,\n errorMessage: undefined\n });\n revokeFilePreviewUrl(previewUrl);\n };\n\n const handleUploadError = (\n type: BridgeMediaType,\n assetId: string,\n error: unknown\n ) => {\n if (isAbortError(error)) return;\n\n updateMediaNode(assetId, {\n mediaType: type,\n status: 'error',\n errorMessage: '上传失败'\n });\n options.onUploadError?.({\n assetId,\n type,\n cause: error\n });\n };\n\n const runUploadTask = (task: RichTextEditorMediaUploadTask) => {\n const uploadAdapter = options.uploadAdapter;\n\n if (!uploadAdapter) return;\n\n const abortController = typeof AbortController === 'function' ? new AbortController() : null;\n const runId = nextRunId + 1;\n\n nextRunId = runId;\n task.runId = runId;\n task.abortController = abortController;\n uploadTasks.set(task.assetId, task);\n const uploadContext = {\n assetId: task.assetId,\n signal: abortController?.signal,\n onProgress: (progress: number) => {\n if (!isCurrentRun(task.assetId, runId) || isDestroyed()) return;\n\n updateMediaNode(task.assetId, {\n mediaType: task.type,\n status: 'uploading',\n progress\n });\n }\n };\n let uploadPromise: Promise<UploadResult>;\n\n try {\n uploadPromise = task.type === 'image'\n ? uploadAdapter.uploadImage(toUploadFileLike(task.file), uploadContext)\n : uploadAdapter.uploadVideo(toUploadFileLike(task.file), uploadContext);\n } catch (error: unknown) {\n if (isCurrentRun(task.assetId, runId)) {\n handleUploadError(task.type, task.assetId, error);\n }\n return;\n }\n\n uploadPromise\n .then((result) => {\n if (isDestroyed() || !isCurrentRun(task.assetId, runId)) return;\n\n applyUploadResult(task.type, task.assetId, task.previewUrl, result);\n uploadTasks.delete(task.assetId);\n })\n .catch((error: unknown) => {\n if (isDestroyed() || !isCurrentRun(task.assetId, runId)) return;\n\n handleUploadError(task.type, task.assetId, error);\n });\n };\n\n const uploadMediaFile = (type: BridgeMediaType, file: File) => {\n if (!options.uploadAdapter) return;\n\n const assetId = createUploadAssetId(type);\n const previewUrl = getFilePreviewUrl(file);\n const task: RichTextEditorMediaUploadTask = {\n assetId,\n type,\n file,\n previewUrl,\n runId: 0,\n abortController: null\n };\n\n insertUploadingMedia(type, file, assetId, previewUrl);\n runUploadTask(task);\n };\n\n const pickMediaFile = (type: BridgeMediaType) => {\n if (!options.uploadAdapter) return;\n\n const input = container.ownerDocument.createElement('input');\n\n input.type = 'file';\n input.accept = type === 'image' ? 'image/*' : 'video/*';\n input.style.display = 'none';\n input.addEventListener('change', () => {\n const file = input.files?.[0];\n\n input.remove();\n if (!file) return;\n\n uploadMediaFile(type, file);\n }, { once: true });\n container.append(input);\n input.click();\n };\n\n return {\n pickMediaFile,\n uploadMediaFile,\n removeMedia(assetId) {\n const removedPayload = removeMediaNode(assetId);\n const didClearTask = clearTask(assetId, true);\n\n if (!didClearTask && removedPayload?.url.startsWith('blob:')) {\n revokeFilePreviewUrl(removedPayload.url);\n }\n },\n retryMedia(assetId) {\n const task = uploadTasks.get(assetId);\n\n if (!task || !options.uploadAdapter) return;\n\n /*\n * 重试复用原始 File 和同一个 assetId,让 assets 输出、失败态 UI 和后续选中菜单\n * 都能稳定定位同一媒体块。旧 run 会被 runId 检查自然忽略。\n */\n abortTask(task);\n updateMediaNode(assetId, {\n mediaType: task.type,\n url: task.previewUrl,\n status: 'uploading',\n progress: 0,\n errorMessage: undefined\n });\n runUploadTask(task);\n },\n destroy() {\n uploadTasks.forEach((task) => {\n abortTask(task);\n revokeFilePreviewUrl(task.previewUrl);\n });\n uploadTasks.clear();\n }\n };\n};\n","import { $createCodeNode } from '@lexical/code';\nimport type { CodeNode } from '@lexical/code';\n\nexport type * from '../codeHighlight/type';\n\n/**\n * 创建 BridgeRTE 基础代码块节点。\n *\n * 对齐 wangEditor 的分层:codeBlock 只负责内容节点,语言菜单和高亮解析放在\n * codeHighlight 领域,避免基础节点入口继续堆 DOM header、dialog 和粘贴解析。\n */\nexport const $createBridgeCodeNode = (language?: string | null | undefined): CodeNode => (\n $createCodeNode(language)\n);\n","import type { EditorThemeClasses } from 'lexical';\nimport type { HeadingTagType } from '@lexical/rich-text';\n\nexport const headingTagByLevel: Record<1 | 2 | 3 | 4 | 5 | 6, HeadingTagType> = {\n 1: 'h1',\n 2: 'h2',\n 3: 'h3',\n 4: 'h4',\n 5: 'h5',\n 6: 'h6'\n};\n\n/**\n * Lexical 节点到 BridgeRTE public BEM class 的稳定映射。\n *\n * 这些 class 是业务主题覆盖和 playground 验收的公共样式契约,不能随内部节点实现随意变化。\n */\nexport const lexicalTheme: EditorThemeClasses = {\n code: 'bridgerte__code-block',\n codeHighlight: {\n attr: 'bridgerte__code-token bridgerte__code-token--attr',\n 'attr-name': 'bridgerte__code-token bridgerte__code-token--attr-name',\n 'attr-value': 'bridgerte__code-token bridgerte__code-token--attr-value',\n boolean: 'bridgerte__code-token bridgerte__code-token--boolean',\n builtin: 'bridgerte__code-token bridgerte__code-token--builtin',\n 'class-name': 'bridgerte__code-token bridgerte__code-token--class-name',\n comment: 'bridgerte__code-token bridgerte__code-token--comment',\n constant: 'bridgerte__code-token bridgerte__code-token--constant',\n deleted: 'bridgerte__code-token bridgerte__code-token--deleted',\n function: 'bridgerte__code-token bridgerte__code-token--function',\n inserted: 'bridgerte__code-token bridgerte__code-token--inserted',\n keyword: 'bridgerte__code-token bridgerte__code-token--keyword',\n namespace: 'bridgerte__code-token bridgerte__code-token--namespace',\n number: 'bridgerte__code-token bridgerte__code-token--number',\n operator: 'bridgerte__code-token bridgerte__code-token--operator',\n prefix: 'bridgerte__code-token bridgerte__code-token--prefix',\n property: 'bridgerte__code-token bridgerte__code-token--property',\n punctuation: 'bridgerte__code-token bridgerte__code-token--punctuation',\n regex: 'bridgerte__code-token bridgerte__code-token--regex',\n selector: 'bridgerte__code-token bridgerte__code-token--selector',\n string: 'bridgerte__code-token bridgerte__code-token--string',\n tag: 'bridgerte__code-token bridgerte__code-token--tag',\n unchanged: 'bridgerte__code-token bridgerte__code-token--unchanged',\n url: 'bridgerte__code-token bridgerte__code-token--url',\n variable: 'bridgerte__code-token bridgerte__code-token--variable'\n },\n heading: {\n h1: 'bridgerte__heading bridgerte__heading--h1',\n h2: 'bridgerte__heading bridgerte__heading--h2',\n h3: 'bridgerte__heading bridgerte__heading--h3',\n h4: 'bridgerte__heading bridgerte__heading--h4',\n h5: 'bridgerte__heading bridgerte__heading--h5',\n h6: 'bridgerte__heading bridgerte__heading--h6'\n },\n list: {\n checklist: 'bridgerte__list bridgerte__list--todo',\n ol: 'bridgerte__list',\n ul: 'bridgerte__list',\n listitem: 'bridgerte__list-item',\n listitemChecked: 'bridgerte__list-item bridgerte__list-item--checked',\n listitemUnchecked: 'bridgerte__list-item bridgerte__list-item--unchecked'\n },\n paragraph: 'bridgerte__paragraph',\n quote: 'bridgerte__quote',\n root: 'bridgerte__content-root',\n text: {\n bold: 'bridgerte__text--bold',\n code: 'bridgerte__code',\n italic: 'bridgerte__text--italic',\n strikethrough: 'bridgerte__text--strike',\n underline: 'bridgerte__text--underline',\n underlineStrikethrough: 'bridgerte__text--underline-strike'\n },\n table: 'bridgerte__table',\n tableCell: 'bridgerte__table-cell',\n tableCellHeader: 'bridgerte__table-cell bridgerte__table-cell--header',\n tableRow: 'bridgerte__table-row',\n tableScrollableWrapper: 'bridgerte__table-wrapper'\n};\n","import {\n $createParagraphNode,\n $getRoot,\n $getSelection,\n $insertNodes,\n $isRangeSelection,\n FORMAT_ELEMENT_COMMAND\n} from 'lexical';\nimport { $createHeadingNode, $createQuoteNode } from '@lexical/rich-text';\nimport { $isCodeNode } from '@lexical/code';\nimport { $setBlocksType } from '@lexical/selection';\nimport type { EditorCommand } from '@bridgerte/core';\nimport type { LexicalEditor } from 'lexical';\nimport { $createBridgeCodeNode } from '../../codeBlock';\nimport { $createDividerNode } from '../../dividerNode';\nimport { headingTagByLevel } from '../lexicalTheme';\n\n/**\n * 创建块级命令处理器。\n *\n * 这里处理段落、标题、引用、分割线、代码块和整体清空;这些命令都围绕当前 block\n * 或 root 结构工作,和 inline style、link、media 的节点 payload 更新分开维护。\n */\nexport const createBlockCommandHandlers = (lexicalEditor: LexicalEditor) => {\n const setBlockHeading = (level: 1 | 2 | 3 | 4 | 5 | 6) => {\n lexicalEditor.update(() => {\n const selection = $getSelection();\n\n if ($isRangeSelection(selection)) {\n $setBlocksType(selection, () => $createHeadingNode(headingTagByLevel[level]));\n }\n });\n };\n\n const setParagraphBlock = () => {\n lexicalEditor.update(() => {\n const selection = $getSelection();\n\n if ($isRangeSelection(selection)) {\n $setBlocksType(selection, () => $createParagraphNode());\n }\n });\n };\n\n const setQuoteBlock = () => {\n lexicalEditor.update(() => {\n const selection = $getSelection();\n\n if ($isRangeSelection(selection)) {\n $setBlocksType(selection, () => $createQuoteNode());\n }\n });\n };\n\n const insertDividerBlock = () => {\n lexicalEditor.update(() => {\n const paragraphNode = $createParagraphNode();\n\n $insertNodes([$createDividerNode(), paragraphNode]);\n paragraphNode.selectStart();\n });\n };\n\n const insertCodeBlock = (language?: string) => {\n lexicalEditor.update(() => {\n const codeNode = $createBridgeCodeNode(language);\n const paragraphNode = $createParagraphNode();\n\n $insertNodes([codeNode, paragraphNode]);\n codeNode.selectEnd();\n });\n };\n\n const setSelectedCodeBlockLanguage = (language: string) => {\n lexicalEditor.update(() => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) return;\n\n const node = selection.anchor.getNode();\n const block = node.getKey() === 'root' ? node : node.getTopLevelElementOrThrow();\n\n if ($isCodeNode(block)) {\n block.setLanguage(language);\n }\n });\n };\n\n const clearContent = () => {\n lexicalEditor.update(() => {\n const root = $getRoot();\n\n root.clear();\n root.append($createParagraphNode());\n });\n };\n\n const formatAlign = (value: Extract<EditorCommand, { type: 'align' }>['value']) => {\n lexicalEditor.dispatchCommand(FORMAT_ELEMENT_COMMAND, value);\n };\n\n return {\n setBlockHeading,\n setParagraphBlock,\n setQuoteBlock,\n insertDividerBlock,\n insertCodeBlock,\n setSelectedCodeBlockLanguage,\n clearContent,\n formatAlign\n };\n};\n","import {\n $createTextNode,\n $getSelection,\n $insertNodes,\n $isRangeSelection\n} from 'lexical';\nimport { $createLinkNode, $isLinkNode, $toggleLink, formatUrl } from '@lexical/link';\nimport { $findMatchingParent } from '@lexical/utils';\nimport type { LexicalEditor } from 'lexical';\n\n/**\n * 创建链接命令处理器。\n *\n * 链接需要读取当前 selection 和浏览器 window.open,保留在 DOM 命令层;\n * toolbar/paste/payload panel 只传 link command,不直接触碰 Lexical LinkNode。\n */\nexport const createLinkCommandHandlers = (lexicalEditor: LexicalEditor) => {\n const setLink = (href: string, text?: string) => {\n lexicalEditor.update(() => {\n const selection = $getSelection();\n const formattedHref = formatUrl(href);\n const fallbackText = text?.trim() || href.trim();\n\n if (!$isRangeSelection(selection) || !href.trim()) return;\n\n if (selection.isCollapsed()) {\n const linkNode = $createLinkNode(formattedHref, {\n rel: 'noreferrer noopener',\n target: '_blank'\n });\n\n linkNode.append($createTextNode(fallbackText));\n $insertNodes([linkNode]);\n return;\n }\n\n $toggleLink(formattedHref, {\n rel: 'noreferrer noopener',\n target: '_blank'\n });\n });\n };\n\n const unsetLink = () => {\n lexicalEditor.update(() => {\n $toggleLink(null);\n });\n };\n\n const openSelectedLink = () => {\n if (typeof window === 'undefined') return;\n\n const linkTarget = lexicalEditor.getEditorState().read(() => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) return null;\n\n const anchorNode = selection.anchor.getNode();\n const linkNode = $isLinkNode(anchorNode)\n ? anchorNode\n : $findMatchingParent(anchorNode, $isLinkNode);\n\n if (!linkNode) return null;\n\n return {\n target: linkNode.getTarget() ?? '_blank',\n url: linkNode.sanitizeUrl(linkNode.getURL())\n };\n });\n\n if (!linkTarget) return;\n\n window.open(linkTarget.url, linkTarget.target, 'noopener,noreferrer');\n };\n\n return {\n setLink,\n unsetLink,\n openSelectedLink\n };\n};\n","import { $createParagraphNode, $insertNodes } from 'lexical';\nimport type { EditorCommand } from '@bridgerte/core';\nimport type { LexicalEditor } from 'lexical';\nimport {\n $createBridgeImageNode,\n $createBridgeVideoNode,\n $findBridgeMediaNodeByAssetId\n} from '../../mediaNode';\n\n/**\n * 创建媒体命令处理器。\n *\n * 媒体节点自己的尺寸、对齐和资源 payload 都在这里更新;上传文件选择仍由\n * mediaUpload runtime 管理,避免节点写入和上传生命周期互相混在一个文件里。\n */\nexport const createMediaCommandHandlers = (lexicalEditor: LexicalEditor) => {\n const insertImage = (command: Extract<EditorCommand, { type: 'media.insertImage' }>) => {\n if (!command.url.trim()) return;\n\n lexicalEditor.update(() => {\n const paragraphNode = $createParagraphNode();\n\n /*\n * URL 图片和上传图片共用同一份媒体节点 payload。宽高和加载元信息都保留在 payload 上,\n * 方便后续懒加载占位复用。\n */\n $insertNodes([$createBridgeImageNode(command), paragraphNode]);\n paragraphNode.selectStart();\n });\n };\n\n const insertVideo = (command: Extract<EditorCommand, { type: 'media.insertVideo' }>) => {\n if (!command.url.trim()) return;\n\n lexicalEditor.update(() => {\n const paragraphNode = $createParagraphNode();\n\n /*\n * 视频遵循和图片一致的块级媒体契约;poster、duration 和后续上传态都应该扩展节点\n * payload,而不是另开一条 UI 路径。\n */\n $insertNodes([$createBridgeVideoNode(command), paragraphNode]);\n paragraphNode.selectStart();\n });\n };\n\n const resizeMedia = (command: Extract<EditorCommand, { type: 'media.resize' }>) => {\n lexicalEditor.update(() => {\n /*\n * 调整大小只改变展示百分比。天然尺寸保持不变,用于导出、上传回写和后续懒加载占位测量。\n */\n $findBridgeMediaNodeByAssetId(command.assetId)?.updatePayload({\n displayWidthPercent: command.widthPercent\n });\n });\n };\n\n const resetMediaSize = (assetId: string) => {\n lexicalEditor.update(() => {\n /*\n * 清掉 displayWidthPercent 会回到开发者配置的默认宽度,不能顺手擦掉媒体真实尺寸。\n */\n $findBridgeMediaNodeByAssetId(assetId)?.updatePayload({\n displayWidthPercent: undefined\n });\n });\n };\n\n const alignMedia = (command: Extract<EditorCommand, { type: 'media.align' }>) => {\n lexicalEditor.update(() => {\n /*\n * 媒体对齐写在媒体节点上,不写段落对齐;相邻文本块保留自己的布局,\n * 被选中的图片/视频块可以独立移动。\n */\n $findBridgeMediaNodeByAssetId(command.assetId)?.updatePayload({\n align: command.value === 'left' ? undefined : command.value\n });\n });\n };\n\n return {\n insertImage,\n insertVideo,\n resizeMedia,\n resetMediaSize,\n alignMedia\n };\n};\n","import {\n $createTextNode,\n $getSelection,\n $insertNodes,\n $isRangeSelection,\n type LexicalEditor\n} from 'lexical';\nimport type { MentionItem } from '@bridgerte/core';\nimport { $createMentionNode } from '../../mentionNode';\n\n/**\n * 创建 mention 命令处理器。\n *\n * mention 插入只负责当前 selection 位置的节点写入,不读取 provider、不打开菜单;\n * trigger 插件和业务自绘都通过同一个 `mention.insert` 命令复用这里的内容协议。\n */\nexport const createMentionCommandHandlers = (lexicalEditor: LexicalEditor) => {\n const insertMention = (item: MentionItem) => {\n lexicalEditor.update(() => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection)) return;\n\n $insertNodes([\n $createMentionNode(item),\n $createTextNode(' ')\n ]);\n });\n };\n\n return {\n insertMention\n };\n};\n","import {\n $getSelection,\n $isRangeSelection,\n type LexicalEditor\n} from 'lexical';\nimport { $patchStyleText } from '@lexical/selection';\n\n/**\n * 创建 inline style 命令处理器。\n *\n * TextFormat bit 和 CSS inline style 是 Lexical 两条不同通道;清除格式必须同时处理,\n * 单项清除则只 patch 对应 CSS 属性,避免误清用户其它文字样式。\n */\nexport const createStyleCommandHandlers = (lexicalEditor: LexicalEditor) => {\n const clearSelectionFormat = () => {\n lexicalEditor.update(() => {\n const selection = $getSelection();\n\n if ($isRangeSelection(selection)) {\n selection.setFormat(0);\n $patchStyleText(selection, {\n color: null,\n 'background-color': null,\n 'font-size': null,\n 'font-family': null,\n 'line-height': null\n });\n }\n });\n };\n\n const setSelectionStyle = (styleProperty: string, value: string) => {\n lexicalEditor.update(() => {\n const selection = $getSelection();\n\n if ($isRangeSelection(selection)) {\n $patchStyleText(selection, {\n [styleProperty]: value === '' ? null : value\n });\n }\n });\n };\n\n return {\n clearSelectionFormat,\n setSelectionStyle\n };\n};\n","import {\n $createParagraphNode,\n $getSelection,\n $isRangeSelection,\n type LexicalEditor\n} from 'lexical';\nimport {\n $deleteTableColumnAtSelection,\n $deleteTableRowAtSelection,\n $findCellNode,\n $findTableNode,\n $insertTableColumnAtSelection,\n $insertTableRowAtSelection,\n $isTableSelection,\n INSERT_TABLE_COMMAND\n} from '@lexical/table';\nimport {\n BRIDGERTE_TABLE_INSERT_MAX_COLS,\n BRIDGERTE_TABLE_INSERT_MAX_ROWS,\n type EditorCommand\n} from '@bridgerte/core';\n\n/*\n * 行列增删的 count 是 public command 输入,需要在执行层做最终保护。\n * 这里限制单次命令最多变更 20 行/列,避免误传超大 count 直接卡住 DOM。\n */\nconst tableMutationMaxCount = 20;\n\nconst clampTableInsertSize = (value: number, maxValue: number) => (\n Number.isFinite(value) && value > 0\n ? Math.min(Math.floor(value), maxValue)\n : 1\n);\n\nconst normalizeTableMutationCount = (count: number | undefined) => (\n Number.isFinite(count) && (count ?? 0) > 0\n ? Math.min(Math.floor(count ?? 1), tableMutationMaxCount)\n : 1\n);\n\nconst isSelectionInsideTable = () => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection) && !$isTableSelection(selection)) return false;\n\n return $findCellNode(selection.anchor.getNode()) !== null;\n};\n\n/**\n * 创建表格命令执行器。\n *\n * 表格命令依赖 Lexical 当前 selection,后续表格 controls 或浮动菜单只需要先把 selection 放到目标\n * 单元格,再调用同一组命令,避免 UI 层直接操作 Lexical table 节点。\n */\nexport const createTableCommandHandlers = (lexicalEditor: LexicalEditor) => {\n const insertTable = (rows: number, cols: number) => {\n const safeRows = clampTableInsertSize(rows, BRIDGERTE_TABLE_INSERT_MAX_ROWS);\n const safeCols = clampTableInsertSize(cols, BRIDGERTE_TABLE_INSERT_MAX_COLS);\n\n lexicalEditor.dispatchCommand(INSERT_TABLE_COMMAND, {\n rows: String(safeRows),\n columns: String(safeCols),\n /*\n * BridgeRTE 默认表格更贴近文档编辑场景:首行作为表头,首列保持普通单元格。\n * 后续表格菜单补齐后,再把首行/首列表头切换做成显式行为。\n */\n includeHeaders: {\n rows: true,\n columns: false\n }\n });\n };\n\n const insertTableRow = (command: Extract<EditorCommand, { type: 'table.insertRow' }>) => {\n lexicalEditor.update(() => {\n if (!isSelectionInsideTable()) return;\n\n const count = normalizeTableMutationCount(command.count);\n\n for (let index = 0; index < count; index += 1) {\n $insertTableRowAtSelection(command.direction !== 'before');\n }\n });\n };\n\n const insertTableColumn = (command: Extract<EditorCommand, { type: 'table.insertColumn' }>) => {\n lexicalEditor.update(() => {\n if (!isSelectionInsideTable()) return;\n\n const count = normalizeTableMutationCount(command.count);\n\n for (let index = 0; index < count; index += 1) {\n $insertTableColumnAtSelection(command.direction !== 'before');\n }\n });\n };\n\n const deleteTableRow = (command: Extract<EditorCommand, { type: 'table.deleteRow' }>) => {\n lexicalEditor.update(() => {\n const count = normalizeTableMutationCount(command.count);\n\n for (let index = 0; index < count; index += 1) {\n if (!isSelectionInsideTable()) return;\n\n $deleteTableRowAtSelection();\n }\n });\n };\n\n const deleteTableColumn = (command: Extract<EditorCommand, { type: 'table.deleteColumn' }>) => {\n lexicalEditor.update(() => {\n const count = normalizeTableMutationCount(command.count);\n\n for (let index = 0; index < count; index += 1) {\n if (!isSelectionInsideTable()) return;\n\n $deleteTableColumnAtSelection();\n }\n });\n };\n\n const deleteTable = () => {\n lexicalEditor.update(() => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection) && !$isTableSelection(selection)) return;\n\n const tableNode = $findTableNode(selection.anchor.getNode());\n\n if (!tableNode) return;\n\n const paragraphNode = $createParagraphNode();\n\n /*\n * 删除整表后补一个段落承接光标,避免表格是唯一内容时 root 变成不可输入的空状态。\n */\n tableNode.insertAfter(paragraphNode);\n tableNode.remove();\n paragraphNode.selectStart();\n });\n };\n\n return {\n insertTable,\n insertTableRow,\n insertTableColumn,\n deleteTableRow,\n deleteTableColumn,\n deleteTable\n };\n};\n","import type { EditorCommand } from '@bridgerte/core';\nimport type { LexicalEditor } from 'lexical';\nimport { createTableCommandHandlers } from '../tableCommands';\n\n/**\n * 创建表格命令处理器。\n *\n * tableCommands 已经封装了 Lexical TableSelection 细节;这里只把 discriminated command\n * 翻译成对应方法,保持主 executor 的 switch 不再关心表格内部实现。\n */\nexport const createTableCommandRuntime = (lexicalEditor: LexicalEditor) => {\n const tableCommandHandlers = createTableCommandHandlers(lexicalEditor);\n\n return {\n insertTable: (command: Extract<EditorCommand, { type: 'table.insert' }>) => {\n tableCommandHandlers.insertTable(command.rows, command.cols);\n },\n insertTableRow: (command: Extract<EditorCommand, { type: 'table.insertRow' }>) => {\n tableCommandHandlers.insertTableRow(command);\n },\n insertTableColumn: (command: Extract<EditorCommand, { type: 'table.insertColumn' }>) => {\n tableCommandHandlers.insertTableColumn(command);\n },\n deleteTableRow: (command: Extract<EditorCommand, { type: 'table.deleteRow' }>) => {\n tableCommandHandlers.deleteTableRow(command);\n },\n deleteTableColumn: (command: Extract<EditorCommand, { type: 'table.deleteColumn' }>) => {\n tableCommandHandlers.deleteTableColumn(command);\n },\n deleteTable: () => {\n tableCommandHandlers.deleteTable();\n }\n };\n};\n","import {\n FORMAT_TEXT_COMMAND,\n INDENT_CONTENT_COMMAND,\n OUTDENT_CONTENT_COMMAND,\n REDO_COMMAND,\n type LexicalCommand,\n type TextFormatType,\n UNDO_COMMAND\n} from 'lexical';\nimport {\n INSERT_CHECK_LIST_COMMAND,\n INSERT_ORDERED_LIST_COMMAND,\n INSERT_UNORDERED_LIST_COMMAND\n} from '@lexical/list';\nimport type { EditorCommand } from '@bridgerte/core';\nimport { createRichTextEditorMediaUploader } from './mediaUpload';\nimport { createBlockCommandHandlers } from './commandExecutor/block';\nimport { createLinkCommandHandlers } from './commandExecutor/link';\nimport { createMediaCommandHandlers } from './commandExecutor/media';\nimport { createMentionCommandHandlers } from './commandExecutor/mention';\nimport { createStyleCommandHandlers } from './commandExecutor/style';\nimport { createTableCommandRuntime } from './commandExecutor/table';\nimport type {\n RichTextEditorCommandExecutor,\n RichTextEditorCommandExecutorOptions\n} from './type';\n\n/*\n * 简单无 payload 命令集中放在 map,新增同类命令时优先补这里;带 payload 或有多步骤\n * 副作用的命令保留在 switch 中,利用 TypeScript discriminated union 做参数收窄。\n */\nconst textFormatByCommandType: Partial<Record<EditorCommand['type'], TextFormatType>> = {\n 'format.bold': 'bold',\n 'format.italic': 'italic',\n 'format.underline': 'underline',\n 'format.strike': 'strikethrough',\n 'format.inlineCode': 'code',\n 'format.superscript': 'superscript',\n 'format.subscript': 'subscript'\n};\n\nconst listCommandByCommandType: Partial<Record<EditorCommand['type'], LexicalCommand<void>>> = {\n 'list.ordered': INSERT_ORDERED_LIST_COMMAND,\n 'list.unordered': INSERT_UNORDERED_LIST_COMMAND,\n 'list.todo': INSERT_CHECK_LIST_COMMAND\n};\n\nconst editorCommandByCommandType: Partial<Record<EditorCommand['type'], LexicalCommand<void>>> = {\n 'indent.increase': INDENT_CONTENT_COMMAND,\n 'indent.decrease': OUTDENT_CONTENT_COMMAND,\n 'history.undo': UNDO_COMMAND,\n 'history.redo': REDO_COMMAND\n};\n\n/*\n * 文本 style 命令都落到 Lexical TextNode 的 inline style。\n * 后续参数面板只负责收集 value,真正写入仍统一经过这里,避免 UI 层碰 Lexical。\n */\nconst textStylePropertyByCommandType: Partial<Record<EditorCommand['type'], string>> = {\n 'format.color': 'color',\n 'format.backgroundColor': 'background-color',\n 'format.fontSize': 'font-size',\n 'format.fontFamily': 'font-family',\n 'format.lineHeight': 'line-height'\n};\n\n/**\n * 创建 BridgeRTE 命令到 Lexical 命令的适配器。\n *\n * 主分发只保留命令路由。link/block/style/media/table 的具体 DOM/Lexical 写入逻辑\n * 下沉到同名子模块,后续新增命令时优先放进对应领域,避免 executor 再次变成大文件。\n */\nexport const createRichTextEditorCommandExecutor = ({\n container,\n lexicalEditor,\n options,\n isDestroyed,\n isReadonly,\n reportError\n}: RichTextEditorCommandExecutorOptions): RichTextEditorCommandExecutor => {\n const mediaUploader = createRichTextEditorMediaUploader({\n container,\n lexicalEditor,\n options,\n isDestroyed\n });\n const blockCommands = createBlockCommandHandlers(lexicalEditor);\n const linkCommands = createLinkCommandHandlers(lexicalEditor);\n const mediaCommands = createMediaCommandHandlers(lexicalEditor);\n const mentionCommands = createMentionCommandHandlers(lexicalEditor);\n const styleCommands = createStyleCommandHandlers(lexicalEditor);\n const tableCommands = createTableCommandRuntime(lexicalEditor);\n\n const toggleFullscreen = () => {\n const fullscreenElement = document.fullscreenElement;\n\n if (fullscreenElement) {\n document.exitFullscreen?.().catch((error: unknown) => {\n reportError(options, 'fullscreen.exit', 'Exit fullscreen failed.', error);\n });\n return;\n }\n\n container.requestFullscreen?.().catch((error: unknown) => {\n reportError(options, 'fullscreen.enter', 'Enter fullscreen failed.', error);\n });\n };\n\n /*\n * executor 对外仍是一个可调用函数,便于 toolbar、paste、快捷键模块直接复用;\n * destroy 只暴露给 editor 生命周期,用来清理命令分发内部持有的运行时资源。\n */\n const executeCommand = ((command: EditorCommand) => {\n if (isDestroyed() || isReadonly()) return;\n\n const textFormat = textFormatByCommandType[command.type];\n if (textFormat) {\n lexicalEditor.dispatchCommand(FORMAT_TEXT_COMMAND, textFormat);\n return;\n }\n\n const listCommand = listCommandByCommandType[command.type];\n if (listCommand) {\n lexicalEditor.dispatchCommand(listCommand, undefined);\n return;\n }\n\n const editorCommand = editorCommandByCommandType[command.type];\n if (editorCommand) {\n lexicalEditor.dispatchCommand(editorCommand, undefined);\n return;\n }\n\n const styleProperty = textStylePropertyByCommandType[command.type];\n if (styleProperty && 'value' in command) {\n styleCommands.setSelectionStyle(styleProperty, command.value);\n return;\n }\n\n switch (command.type) {\n case 'format.clear':\n styleCommands.clearSelectionFormat();\n return;\n case 'block.heading':\n blockCommands.setBlockHeading(command.level);\n return;\n case 'block.paragraph':\n blockCommands.setParagraphBlock();\n return;\n case 'block.quote':\n blockCommands.setQuoteBlock();\n return;\n case 'block.divider':\n blockCommands.insertDividerBlock();\n return;\n case 'block.code':\n blockCommands.insertCodeBlock(command.language);\n return;\n case 'block.setCodeLanguage':\n blockCommands.setSelectedCodeBlockLanguage(command.language);\n return;\n case 'align':\n blockCommands.formatAlign(command.value);\n return;\n case 'link.set':\n linkCommands.setLink(command.href, command.text);\n return;\n case 'link.unset':\n linkCommands.unsetLink();\n return;\n case 'link.open':\n linkCommands.openSelectedLink();\n return;\n case 'mention.insert':\n mentionCommands.insertMention(command.item);\n return;\n case 'content.clear':\n blockCommands.clearContent();\n return;\n case 'table.insert':\n tableCommands.insertTable(command);\n return;\n case 'table.insertRow':\n tableCommands.insertTableRow(command);\n return;\n case 'table.insertColumn':\n tableCommands.insertTableColumn(command);\n return;\n case 'table.deleteRow':\n tableCommands.deleteTableRow(command);\n return;\n case 'table.deleteColumn':\n tableCommands.deleteTableColumn(command);\n return;\n case 'table.delete':\n tableCommands.deleteTable();\n return;\n case 'media.insertImage':\n mediaCommands.insertImage(command);\n return;\n case 'media.insertVideo':\n mediaCommands.insertVideo(command);\n return;\n case 'media.pickImage':\n mediaUploader.pickMediaFile('image');\n return;\n case 'media.pickVideo':\n mediaUploader.pickMediaFile('video');\n return;\n case 'media.retry':\n mediaUploader.retryMedia(command.assetId);\n return;\n case 'media.remove':\n mediaUploader.removeMedia(command.assetId);\n return;\n case 'media.resize':\n mediaCommands.resizeMedia(command);\n return;\n case 'media.align':\n mediaCommands.alignMedia(command);\n return;\n case 'media.resetSize':\n mediaCommands.resetMediaSize(command.assetId);\n return;\n case 'fullscreen.toggle':\n toggleFullscreen();\n return;\n default:\n /*\n * public command 协议会先于 DOM 行为实现存在。slash.open 和后续媒体选中菜单\n * 需要等对应 panel/handler 落地后再接入,这里保持 no-op 以避免阶段性破坏。\n */\n }\n }) as RichTextEditorCommandExecutor;\n\n executeCommand.uploadMediaFile = mediaUploader.uploadMediaFile;\n\n executeCommand.destroy = () => {\n mediaUploader.destroy();\n };\n\n return executeCommand;\n};\n","/**\n * Lexical history 合并窗口。\n *\n * 这个值只影响 DOM 内核的撤销栈合并策略,不属于跨端 public API。\n */\nexport const LEXICAL_HISTORY_MERGE_DELAY_MS = 300;\n\n/**\n * Lexical 内部命名空间。\n *\n * 仅用于隔离 Lexical editor 实例和调试信息,不暴露给业务方作为协议字段。\n */\nexport const LEXICAL_EDITOR_NAMESPACE = 'BridgeRTE';\n","import {\n $getRoot,\n $getSelection,\n $isRangeSelection\n} from 'lexical';\nimport { $trimTextContentFromAnchor } from '@lexical/selection';\nimport type { EnforceMaxLengthOptions } from './type';\n\nexport type * from './type';\n\n/**\n * 在 Lexical update 写阶段执行 `maxLength` 裁剪。\n *\n * overflowLength 由 update listener 的只读阶段计算;这里只负责从当前 anchor 回裁多余\n * 字符,避免把读长度和写节点混在同一个 Lexical read 回调里。\n */\nexport const enforceMaxLength = ({\n editor,\n overflowLength\n}: EnforceMaxLengthOptions): boolean => {\n if (overflowLength <= 0) return false;\n\n const selection = $getSelection();\n\n if ($isRangeSelection(selection)) {\n $trimTextContentFromAnchor(editor, selection.anchor, overflowLength);\n return true;\n }\n\n /*\n * setContent 或初始化写入时可能没有真实 selection。此时从 root 末尾回裁,\n * 保留前面的内容,避免宿主写入超长内容绕过 maxLength。\n */\n $getRoot().selectEnd();\n const fallbackSelection = $getSelection();\n\n if (!$isRangeSelection(fallbackSelection)) return false;\n\n $trimTextContentFromAnchor(editor, fallbackSelection.anchor, overflowLength);\n return true;\n};\n","import { $getRoot } from 'lexical';\nimport { BRIDGE_CONTENT_CHANGE_DEBOUNCE_MS } from '@bridgerte/bridge';\nimport { BRIDGERTE_CONTENT_VERSION } from '@bridgerte/core';\nimport { serializeContent } from '../contentModel';\nimport { enforceMaxLength } from '../maxLength';\nimport { notifyChange, notifyContentChange } from './errorReporter';\nimport type {\n RichTextEditorContentSyncOptions,\n RichTextEditorContentSyncRuntime\n} from './type';\n\n/**\n * 创建内容同步 runtime。\n *\n * 这个模块集中处理“何时序列化内容”和“何时裁剪 maxLength”。调用方只负责接入\n * Lexical update listener,避免主 editor 文件继续混入防抖、占位和长度限制细节。\n */\nexport const createRichTextEditorContentSync = ({\n lexicalEditor,\n options,\n isDestroyed,\n setContent,\n syncPlaceholder\n}: RichTextEditorContentSyncOptions): RichTextEditorContentSyncRuntime => {\n /*\n * setContent / 初始内容写入会触发 Lexical update listener,但这不是用户输入。\n * 用计数而不是 boolean,是为了连续程序化写入时能逐次抵消对应的变更通知。\n */\n let suppressNextChangeCount = 0;\n // 变更通知统一防抖,避免 10w 内容下输入每个字符都完整序列化并回调宿主。\n let contentChangeTimer: ReturnType<typeof setTimeout> | null = null;\n\n const clearContentChangeTimer = () => {\n if (!contentChangeTimer) return;\n\n clearTimeout(contentChangeTimer);\n contentChangeTimer = null;\n };\n\n const syncContent = (shouldNotify: boolean) => {\n if (isDestroyed()) return;\n\n // 完整内容序列化成本高,只有在主动读取或防抖后的变更通知中执行。\n const content = serializeContent(lexicalEditor.getEditorState(), lexicalEditor);\n\n setContent(content);\n if (shouldNotify) {\n notifyChange(options, content);\n }\n };\n\n const createContentChangeSummary = (plainTextLength: number) => {\n const maxLength = options.maxLength !== undefined && options.maxLength >= 0\n ? options.maxLength\n : undefined;\n\n return {\n dirty: true,\n plainTextLength,\n version: BRIDGERTE_CONTENT_VERSION,\n maxLength,\n isOverMaxLength: maxLength === undefined ? false : plainTextLength > maxLength\n };\n };\n\n const notifyLightweightContentChange = (plainTextLength: number) => {\n /*\n * 高频输入先发摘要,避免为了 dirty/字数这类状态生成完整 HTML 和 JSON。\n * 旧 onChange 兼容路径如果存在,会在 debounce 后额外生成完整内容快照。\n */\n notifyContentChange(options, createContentChangeSummary(plainTextLength));\n };\n\n const scheduleFullContentChange = () => {\n if (!options.onChange) return;\n\n clearContentChangeTimer();\n /*\n * onChange 是历史 API,需要给业务完整内容快照,但不能和 Lexical 每次 reconcile 同频。\n * 新业务应优先使用 onContentChange 摘要,并在保存时主动调用 getContent()。\n */\n contentChangeTimer = setTimeout(() => {\n syncContent(true);\n }, BRIDGE_CONTENT_CHANGE_DEBOUNCE_MS);\n };\n\n const scheduleContentChange = (plainTextLength: number) => {\n if (suppressNextChangeCount > 0) {\n suppressNextChangeCount -= 1;\n return;\n }\n\n notifyLightweightContentChange(plainTextLength);\n scheduleFullContentChange();\n };\n\n const getPlainTextLength = () => (\n lexicalEditor.getEditorState().read(() => (\n $getRoot().getTextContent().length\n ))\n );\n\n const getMaxLengthOverflow = (plainTextLength: number) => {\n if (options.maxLength === undefined || options.maxLength < 0) return 0;\n\n return plainTextLength - options.maxLength;\n };\n\n const trimMaxLengthOverflow = (overflowLength: number) => {\n if (overflowLength <= 0) return false;\n\n /*\n * maxLength 裁剪会触发第二次 Lexical update。下一次 update listener 只会看到\n * 已经合规的长度,所以不会形成循环;同时也不会为长度限制生成 HTML/JSON。\n */\n lexicalEditor.update(() => {\n enforceMaxLength({ editor: lexicalEditor, overflowLength });\n }, { discrete: true });\n\n return true;\n };\n\n const enforceCurrentMaxLength = () => {\n if (options.maxLength === undefined || options.maxLength < 0) return;\n\n lexicalEditor.update(() => {\n const overflowLength = $getRoot().getTextContent().length - (options.maxLength ?? 0);\n\n enforceMaxLength({ editor: lexicalEditor, overflowLength });\n }, { discrete: true });\n };\n\n return {\n clearContentChangeTimer,\n enforceCurrentMaxLength,\n syncContent,\n suppressNextChange() {\n suppressNextChangeCount += 1;\n },\n syncAfterEditorUpdate() {\n const plainTextLength = getPlainTextLength();\n const wasTrimmedByMaxLength = trimMaxLengthOverflow(getMaxLengthOverflow(plainTextLength));\n\n if (wasTrimmedByMaxLength) {\n syncPlaceholder();\n return;\n }\n\n syncPlaceholder();\n scheduleContentChange(plainTextLength);\n }\n };\n};\n","import { getCodeLanguageOptions } from '@lexical/code';\nimport { codeBlockLanguagePanel } from '@bridgerte/native-spec';\nimport type { PayloadPanelField } from '@bridgerte/core';\nimport type { CodeBlockLanguageOption } from './type';\n\nexport const codeLanguageAttributeName = 'data-language';\n\nconst defaultCodeBlockLanguageLabel = '纯文本';\nconst codeBlockLanguageFieldName = 'language';\nconst plainTextPrismLanguages = new Set(['plain', 'plaintext', 'text', 'txt']);\nconst codeLanguageAttributeNames = [\n codeLanguageAttributeName,\n 'data-lang',\n 'data-code-language',\n 'data-highlight-language',\n 'lang',\n 'language'\n];\nconst codeLanguageRegExp = /^[a-z][a-z0-9_+#.-]{0,31}$/i;\nconst codeLanguageClassRegExp = /^(?:language|lang)-([a-z][a-z0-9_+#.-]{0,31})$/i;\nconst codeLanguageBrushClassRegExp = /^brush:\\s*([a-z][a-z0-9_+#.-]{0,31})$/i;\nconst canonicalCodeLanguageValueMap = new Map([\n ['js', 'javascript'],\n ['jsx', 'javascript'],\n ['py', 'python'],\n ['rs', 'rust'],\n ['ts', 'typescript'],\n ['tsx', 'typescript']\n]);\n\nconst isSelectField = (\n field: PayloadPanelField\n): field is Extract<PayloadPanelField, { type: 'select' }> => field.type === 'select';\n\nconst findLanguageField = (\n fields: PayloadPanelField[]\n): Extract<PayloadPanelField, { type: 'select' }> | undefined => (\n fields.find((field): field is Extract<PayloadPanelField, { type: 'select' }> => (\n field.name === codeBlockLanguageFieldName && isSelectField(field)\n ))\n);\n\nexport const normalizeCodeLanguageValue = (language: string | null | undefined) => {\n const normalizedValue = language?.trim().toLowerCase();\n\n if (!normalizedValue || !codeLanguageRegExp.test(normalizedValue)) return null;\n\n return canonicalCodeLanguageValueMap.get(normalizedValue) ?? normalizedValue;\n};\n\nexport const getCodeLanguageFromAttributes = (element: Element) => {\n for (const attributeName of codeLanguageAttributeNames) {\n const normalizedLanguage = normalizeCodeLanguageValue(element.getAttribute(attributeName));\n\n if (normalizedLanguage) return normalizedLanguage;\n }\n\n return null;\n};\n\nexport const getCodeLanguageFromClassName = (className: string) => {\n const [, brushLanguage] = className.match(codeLanguageBrushClassRegExp) ?? [];\n const normalizedBrushLanguage = normalizeCodeLanguageValue(brushLanguage);\n\n if (normalizedBrushLanguage) return normalizedBrushLanguage;\n\n for (const classText of className.split(/\\s+/)) {\n const [, language] = classText.match(codeLanguageClassRegExp) ?? [];\n const normalizedLanguage = normalizeCodeLanguageValue(language);\n\n if (normalizedLanguage) return normalizedLanguage;\n }\n\n return null;\n};\n\n/*\n * DOM 默认菜单只展示 Prism 标准语言名,不展开 alias。这里相当于 wangEditor 的\n * `codeLangs` 配置默认值,业务仍可通过 codeBlockLanguagePanel 覆盖候选项。\n */\nconst createDefaultCodeLanguageOptions = (): CodeBlockLanguageOption[] => {\n const prismLanguageOptions = getCodeLanguageOptions()\n .filter(([language]) => !plainTextPrismLanguages.has(language))\n .map(([language, label]) => ({\n label,\n value: normalizeCodeLanguageValue(language) ?? language\n }));\n\n return [\n { label: defaultCodeBlockLanguageLabel, value: '' },\n ...prismLanguageOptions\n ];\n};\n\nconst defaultPrismLanguageOptions = createDefaultCodeLanguageOptions();\n\n/**\n * 代码块语言只消费 select 字段。\n *\n * 和 wangEditor 的 select-lang 菜单一样,语言候选来自配置;业务传错字段时回退默认语言表。\n */\nexport const getLanguageOptionsFromPanel = (\n panel = codeBlockLanguagePanel\n): CodeBlockLanguageOption[] => (\n panel === codeBlockLanguagePanel\n ? defaultPrismLanguageOptions\n : findLanguageField(panel.fields)?.options\n ?? defaultPrismLanguageOptions\n);\n\nexport const getCodeBlockLabel = (\n languageOptions: CodeBlockLanguageOption[],\n language: string | null | undefined\n) => (\n languageOptions.find((option) => option.value === language)?.label\n ?? languageOptions.find((option) => (\n normalizeCodeLanguageValue(option.value) === normalizeCodeLanguageValue(language)\n ))?.label\n ?? languageOptions[0]?.label\n ?? defaultCodeBlockLanguageLabel\n);\n\nexport const codeBlockLanguageOptions = getLanguageOptionsFromPanel();\n","import type { LexicalNode } from 'lexical';\nimport { $isCodeNode } from '@lexical/code';\nimport {\n codeLanguageAttributeName,\n getCodeLanguageFromAttributes,\n getCodeLanguageFromClassName\n} from './language';\n\n/**\n * 把外部代码块语言归一到 `<pre data-language>`。\n *\n * 这一层对齐 wangEditor 的 parse-style-html:只解析显式 `language-*`、`data-language`\n * 等剪贴板元信息,不根据正文猜语言,避免普通文章片段被误判成代码。\n */\nexport const normalizeCodeBlockLanguages = (root: ParentNode) => {\n [...root.querySelectorAll('pre,code')].forEach((element) => {\n const language = getCodeLanguageFromAttributes(element)\n ?? getCodeLanguageFromClassName(element.className);\n const preElement = element.tagName === 'PRE' ? element : element.closest('pre');\n\n if (preElement && language) {\n preElement.setAttribute(codeLanguageAttributeName, language);\n }\n });\n};\nexport const unwrapPreCodeChildren = (root: ParentNode) => {\n root.querySelectorAll('pre').forEach((preElement) => {\n const childElements = [...preElement.children];\n\n /*\n * 外部 HTML 常见结构是 `<pre data-language><code class=\"language-*\">...</code></pre>`。\n * Lexical 会把 pre 和多行 code 都识别成 CodeNode,形成双层代码块;导入前只剥掉\n * pre 里的 code 包装,保留文本、br 和 pre[data-language] 交给 CodeNode 处理。\n */\n childElements.forEach((childElement) => {\n if (childElement.tagName === 'CODE') {\n childElement.replaceWith(...childElement.childNodes);\n }\n });\n });\n};\n\nexport const applyCodeNodeLanguagesFromDom = (\n nodes: LexicalNode[],\n root: ParentNode\n) => {\n const codeElements = [...root.querySelectorAll<HTMLElement>('pre[data-language]')];\n let codeElementIndex = 0;\n\n /*\n * Lexical 旧 DOM conversion 只从命中的元素读取 data-language;外部 HTML 如果是\n * `<pre data-language><code>...</code></pre>`,内部 code 可能以更高优先级先生成 CodeNode。\n * 这里按粘贴片段里的 pre 顺序兜底写回语言,避免清洗阶段识别成功但导入后变成纯文本。\n */\n nodes.forEach((node) => {\n if (!$isCodeNode(node)) return;\n\n const codeElement = codeElements[codeElementIndex];\n\n codeElementIndex += 1;\n if (!codeElement) return;\n\n const language = codeElement.getAttribute(codeLanguageAttributeName);\n\n if (language && !node.getLanguage()) {\n node.setLanguage(language);\n }\n });\n};\n","import type {\n RichTextDialog,\n RichTextDialogAnchorRect,\n RichTextDialogOptions\n} from './type';\n\nexport type * from './type';\n\nconst dialogViewportPadding = 12;\nconst dialogAnchorOffset = 6;\n\nconst clampDialogCoordinate = (value: number, min: number, max: number) => (\n Math.min(Math.max(value, min), Math.max(min, max))\n);\n\nconst getVisibleViewportRect = () => {\n const visualViewport = window.visualViewport;\n\n /*\n * H5 键盘弹起时 `window.innerHeight` 往往仍是布局视口高度,弹窗会被键盘盖住。\n * visualViewport 描述的是用户当前真正看得到的区域;不支持时再回退到传统视口。\n */\n return {\n left: visualViewport?.offsetLeft ?? 0,\n top: visualViewport?.offsetTop ?? 0,\n width: visualViewport?.width ?? window.innerWidth,\n height: visualViewport?.height ?? window.innerHeight\n };\n};\n\nconst measureDialogRect = (dialogElement: HTMLElement) => {\n const previousVisibility = dialogElement.style.visibility;\n const previousPointerEvents = dialogElement.style.pointerEvents;\n const previousDisplay = dialogElement.style.display;\n\n /*\n * dialog 默认是 opacity 0 且 pointer-events none,但仍可能在刚创建或被业务 class\n * 影响时测不到稳定尺寸。打开前短暂进入可测量状态,避免靠 0 尺寸定位后溢出视口。\n */\n dialogElement.style.visibility = 'hidden';\n dialogElement.style.pointerEvents = 'none';\n dialogElement.style.display = 'grid';\n\n const rect = dialogElement.getBoundingClientRect();\n\n dialogElement.style.visibility = previousVisibility;\n dialogElement.style.pointerEvents = previousPointerEvents;\n dialogElement.style.display = previousDisplay;\n\n return rect;\n};\n\nconst getDialogPosition = (\n dialogElement: HTMLElement,\n rootElement: HTMLElement,\n anchorRect?: RichTextDialogAnchorRect\n) => {\n const dialogRect = measureDialogRect(dialogElement);\n const viewportRect = getVisibleViewportRect();\n const rootRect = rootElement.getBoundingClientRect();\n const fallbackLeft = rootRect.left + dialogViewportPadding;\n const fallbackTop = rootRect.top + dialogViewportPadding;\n const nextLeft = anchorRect ? anchorRect.x : fallbackLeft;\n const nextTop = anchorRect ? anchorRect.y + anchorRect.height + dialogAnchorOffset : fallbackTop;\n const fallbackAboveTop = anchorRect\n ? anchorRect.y - dialogRect.height - dialogAnchorOffset\n : nextTop;\n const minLeft = viewportRect.left + dialogViewportPadding;\n const minTop = viewportRect.top + dialogViewportPadding;\n const maxLeft = viewportRect.left + viewportRect.width - dialogRect.width - dialogViewportPadding;\n const maxTop = viewportRect.top + viewportRect.height - dialogRect.height - dialogViewportPadding;\n const visibleTop = nextTop > maxTop ? fallbackAboveTop : nextTop;\n\n return {\n left: clampDialogCoordinate(nextLeft, minLeft, maxLeft),\n top: clampDialogCoordinate(visibleTop, minTop, maxTop),\n viewportHeight: viewportRect.height\n };\n};\n\n/**\n * 创建 DOM 通用轻弹窗壳。\n *\n * 这个模块只负责透明蒙层、定位、打开关闭和销毁;具体内容由 payloadPanel、\n * colorPanel、tablePanel、mediaPanel 等业务模块填充,避免后续每种参数面板重复写浮层生命周期。\n */\nexport const createRichTextDialog = (options: RichTextDialogOptions): RichTextDialog => {\n const backdropElement = document.createElement('div');\n const dialogElement = document.createElement('div');\n const contentElement = document.createElement('div');\n let activeAnchorRect: RichTextDialogAnchorRect | undefined;\n\n const close = () => {\n backdropElement.dataset.visible = 'false';\n dialogElement.dataset.visible = 'false';\n activeAnchorRect = undefined;\n };\n\n const syncPosition = () => {\n const position = getDialogPosition(dialogElement, options.root, activeAnchorRect);\n\n dialogElement.style.left = `${position.left}px`;\n dialogElement.style.top = `${position.top}px`;\n /*\n * CSS 的 100vh 在 H5 键盘弹起时常等于布局视口,不是可见视口。\n * 这里把 visualViewport 高度透给 CSS,让弹层内容高度也跟着键盘避让。\n */\n dialogElement.style.setProperty(\n '--bridgerte-dialog-visible-height',\n `${position.viewportHeight}px`\n );\n };\n\n const open = (anchorRect?: RichTextDialogAnchorRect) => {\n activeAnchorRect = anchorRect;\n if (anchorRect) {\n dialogElement.style.setProperty('--bridgerte-dialog-anchor-width', `${anchorRect.width}px`);\n } else {\n dialogElement.style.removeProperty('--bridgerte-dialog-anchor-width');\n }\n syncPosition();\n backdropElement.dataset.visible = 'true';\n dialogElement.dataset.visible = 'true';\n };\n\n backdropElement.className = 'bridgerte__dialog-backdrop';\n backdropElement.dataset.visible = 'false';\n dialogElement.className = `bridgerte__dialog ${options.className}`;\n dialogElement.dataset.visible = 'false';\n contentElement.className = 'bridgerte__dialog-content';\n dialogElement.append(contentElement);\n options.root.append(backdropElement, dialogElement);\n\n backdropElement.addEventListener('click', () => {\n options.onBackdropClick?.();\n close();\n });\n window.visualViewport?.addEventListener('resize', syncPosition);\n window.visualViewport?.addEventListener('scroll', syncPosition);\n window.addEventListener('resize', syncPosition);\n\n return {\n element: dialogElement,\n content: contentElement,\n open,\n close,\n destroy() {\n close();\n window.visualViewport?.removeEventListener('resize', syncPosition);\n window.visualViewport?.removeEventListener('scroll', syncPosition);\n window.removeEventListener('resize', syncPosition);\n backdropElement.remove();\n dialogElement.remove();\n }\n };\n};\n","/**\n * DOM 领域统一的下一帧调度。\n *\n * 代码块语言菜单、媒体 controls 和未来其他位置同步都需要“优先使用 rAF,回退到\n * setTimeout”的同一行为。抽出来后可以避免各模块分别维护降级分支。\n */\nexport const scheduleFrame = (callback: () => void) => (\n typeof requestAnimationFrame === 'function'\n ? requestAnimationFrame(callback)\n : window.setTimeout(callback, 0)\n);\n\nexport const cancelFrame = (frameId: number) => {\n if (typeof cancelAnimationFrame === 'function') {\n cancelAnimationFrame(frameId);\n return;\n }\n\n window.clearTimeout(frameId);\n};\n","import { $getNodeByKey, type NodeKey } from 'lexical';\nimport { $isCodeNode, CodeNode } from '@lexical/code';\nimport { codeBlockLanguagePanel } from '@bridgerte/native-spec';\nimport { resolvePayloadPanelSchema } from '@bridgerte/core';\nimport { createRichTextDialog, type RichTextDialog } from '../dialog';\nimport {\n cancelFrame,\n scheduleFrame\n} from '../domScheduler';\nimport { bindTouchPressedState } from '../interactionState';\nimport type { ClearInteractionPressedState } from '../interactionState';\nimport {\n getCodeBlockLabel,\n getLanguageOptionsFromPanel\n} from './language';\nimport type {\n CodeBlockLanguageController,\n CodeBlockLanguageControllerOptions,\n CodeBlockLanguageOption\n} from './type';\n\nconst codeBlockLanguageFieldName = 'language';\nconst codeBlockLanguageRequestIdPrefix = 'bridgerte-code-block-language';\nconst codeBlockControlOffset = 8;\nlet codeBlockLanguageRequestIdSeed = 0;\n\nconst createCodeBlockLanguageRequestId = () => {\n codeBlockLanguageRequestIdSeed += 1;\n\n return `${codeBlockLanguageRequestIdPrefix}-${codeBlockLanguageRequestIdSeed}`;\n};\n\nconst setCodeBlockControlLabel = (\n control: HTMLElement,\n languageOptions: CodeBlockLanguageOption[],\n language: string | null | undefined\n) => {\n const label = control.querySelector<HTMLElement>('.bridgerte__code-block-control-label');\n\n control.dataset.language = language ?? '';\n if (label) {\n label.textContent = getCodeBlockLabel(languageOptions, language);\n }\n};\n\nconst createCodeBlockControl = (\n languageOptions: CodeBlockLanguageOption[],\n language: string | null | undefined\n) => {\n const control = document.createElement('button');\n const label = document.createElement('span');\n const arrow = document.createElement('span');\n\n control.type = 'button';\n control.className = 'bridgerte__code-block-control';\n control.contentEditable = 'false';\n control.dataset.language = language ?? '';\n control.setAttribute('aria-label', '选择代码块语言');\n label.className = 'bridgerte__code-block-control-label';\n label.textContent = getCodeBlockLabel(languageOptions, language);\n arrow.className = 'bridgerte__code-block-control-arrow';\n control.append(label, arrow);\n\n return control;\n};\n\nconst getCodeBlockScrollContainer = (root: HTMLElement) => (\n root.querySelector<HTMLElement>('.bridgerte__content') ?? root\n);\n\n/**\n * 绑定代码块 header 的语言选择行为。\n *\n * 对齐 wangEditor 的 code-highlight 模块分层:CodeNode 只保存语言和文本,这里作为\n * 独立 DOM 内置组件负责 header、语言候选和自绘接管,不进入 codeBlock 基础节点。\n */\nexport const createCodeBlockLanguageController = (\n options: CodeBlockLanguageControllerOptions\n): CodeBlockLanguageController => {\n const layer = document.createElement('div');\n const scrollContainer = getCodeBlockScrollContainer(options.root);\n const languagePanel = resolvePayloadPanelSchema(\n options.languagePanel ?? codeBlockLanguagePanel,\n options.payloadPanelConfig\n );\n const languageOptions = getLanguageOptionsFromPanel(languagePanel);\n let dialog: RichTextDialog | null = null;\n let syncFrame: number | null = null;\n const controls = new Map<NodeKey, HTMLElement>();\n const clearPressedStates = new Map<HTMLElement, ClearInteractionPressedState>();\n\n const closeDialog = () => {\n dialog?.close();\n };\n\n const setLanguage = (nodeKey: NodeKey, language: string) => {\n if (options.isReadonly()) return;\n\n options.editor.update(() => {\n const node = $getNodeByKey(nodeKey);\n\n if ($isCodeNode(node)) {\n node.setLanguage(language);\n }\n });\n };\n\n const scheduleSetLanguage = (nodeKey: NodeKey, language: string) => {\n /*\n * Prism 对长代码块会同步重算 token。语言选择先关闭弹窗,再把高亮更新放到下一帧,\n * 避免用户点击后看到弹窗卡在屏幕上,后续如仍需优化再接入分片高亮策略。\n */\n scheduleFrame(() => {\n setLanguage(nodeKey, language);\n });\n };\n\n const requestHostLanguagePanel = (\n nodeKey: NodeKey,\n anchorRect: DOMRect,\n language: string\n ) => options.onRequest?.({\n id: createCodeBlockLanguageRequestId(),\n readonly: options.isReadonly(),\n menuId: 'code-block-language',\n command: { type: 'block.setCodeLanguage', language },\n panel: languagePanel,\n anchorRect: {\n x: anchorRect.left,\n y: anchorRect.top,\n width: anchorRect.width,\n height: anchorRect.height\n },\n currentValues: {\n [codeBlockLanguageFieldName]: language\n },\n submit: (values) => {\n closeDialog();\n scheduleSetLanguage(nodeKey, values[codeBlockLanguageFieldName] ?? '');\n },\n cancel: closeDialog\n }) === true;\n\n const positionControl = (control: HTMLElement, codeElement: HTMLElement) => {\n const rootRect = options.root.getBoundingClientRect();\n const codeRect = codeElement.getBoundingClientRect();\n const isOutsideRoot = codeRect.bottom < rootRect.top || codeRect.top > rootRect.bottom;\n\n control.hidden = isOutsideRoot;\n control.style.transform = `translate(${\n codeRect.left - rootRect.left + codeBlockControlOffset\n }px, ${codeRect.top - rootRect.top + codeBlockControlOffset}px)`;\n };\n\n const syncControl = (nodeKey: NodeKey) => {\n const codeElement = options.editor.getElementByKey(nodeKey);\n\n if (!codeElement) {\n controls.get(nodeKey)?.remove();\n controls.delete(nodeKey);\n return;\n }\n\n codeElement.dataset.lexicalKey = nodeKey;\n const language = codeElement.getAttribute('data-language');\n\n const existingControl = controls.get(nodeKey);\n if (existingControl) {\n setCodeBlockControlLabel(existingControl, languageOptions, language);\n positionControl(existingControl, codeElement);\n return;\n }\n\n const control = createCodeBlockControl(languageOptions, language);\n const clearPressedState = bindTouchPressedState(control);\n\n control.dataset.lexicalKey = nodeKey;\n controls.set(nodeKey, control);\n clearPressedStates.set(control, clearPressedState);\n layer.append(control);\n positionControl(control, codeElement);\n };\n\n const syncAllControls = () => {\n syncFrame = null;\n controls.forEach((_, nodeKey) => {\n syncControl(nodeKey);\n });\n };\n\n const scheduleSyncAllControls = () => {\n if (syncFrame !== null) return;\n\n // 位置同步只读 DOM rect 并写 transform,放到下一帧能避开 Lexical 本轮 DOM reconcile。\n syncFrame = scheduleFrame(syncAllControls);\n };\n\n const openLanguageDialog = (control: HTMLElement, nodeKey: NodeKey) => {\n const anchorRect = control.getBoundingClientRect();\n const currentLanguageValue = control.dataset.language ?? '';\n\n // 宿主接管时不创建内置 dialog,避免 DOM 默认 UI 和业务自绘同时出现。\n if (requestHostLanguagePanel(nodeKey, anchorRect, currentLanguageValue)) return;\n\n /*\n * readonly 下仍允许宿主收到 request 展示只读态;没有宿主接管时默认 DOM 菜单不打开,\n * 且真正写入语言的 `setLanguage` 也会再次检查 readonly,防住异步 submit。\n */\n if (options.isReadonly()) {\n closeDialog();\n return;\n }\n\n if (!dialog) {\n dialog = createRichTextDialog({\n root: options.root,\n className: 'bridgerte__code-block-menu',\n onBackdropClick: closeDialog\n });\n }\n\n const list = document.createElement('div');\n\n dialog.content.replaceChildren();\n dialog.element.style.minWidth = '180px';\n list.className = 'bridgerte__code-block-menu-list';\n languageOptions.forEach((option) => {\n const button = document.createElement('button');\n\n button.type = 'button';\n button.className = 'bridgerte__code-block-menu-item';\n button.textContent = option.label;\n bindTouchPressedState(button);\n button.addEventListener('click', () => {\n closeDialog();\n scheduleSetLanguage(nodeKey, option.value);\n });\n list.append(button);\n });\n dialog.content.append(list);\n dialog.open({\n x: anchorRect.left,\n y: anchorRect.top,\n width: 180,\n height: anchorRect.height\n });\n };\n\n layer.className = 'bridgerte__code-block-controls-layer';\n options.root.append(layer);\n\n const unregisterMutationListener = options.editor.registerMutationListener(\n CodeNode,\n (mutations) => {\n mutations.forEach((mutation, nodeKey) => {\n if (mutation === 'destroyed') {\n const control = controls.get(nodeKey);\n\n if (control) {\n const clearPressedState = clearPressedStates.get(control);\n\n clearPressedState?.();\n clearPressedStates.delete(control);\n control.remove();\n }\n controls.delete(nodeKey);\n return;\n }\n\n syncControl(nodeKey);\n });\n }\n );\n const unregisterUpdateListener = options.editor.registerUpdateListener(scheduleSyncAllControls);\n\n const handleClick = (event: MouseEvent) => {\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) return;\n\n const control = target.closest('.bridgerte__code-block-control');\n if (!(control instanceof HTMLElement)) return;\n\n const nodeKey = control.dataset.lexicalKey;\n\n if (!nodeKey) return;\n\n event.preventDefault();\n event.stopPropagation();\n openLanguageDialog(control, nodeKey);\n };\n\n const handlePointerDown = (event: PointerEvent) => {\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) return;\n\n if (target.closest('.bridgerte__code-block-control')) {\n event.preventDefault();\n }\n };\n\n const handleRootPointerDown = (event: PointerEvent) => {\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) return;\n\n if (!target.closest('.bridgerte__code-block')) {\n closeDialog();\n return;\n }\n\n const codeElement = target.closest<HTMLElement>('.bridgerte__code-block');\n\n if (!codeElement || codeElement.textContent) return;\n\n const nodeKey = codeElement.dataset.lexicalKey;\n\n if (!nodeKey) return;\n\n /*\n * 空代码块里没有真实文本节点可供浏览器命中,点击 padding 区域时部分环境不会把\n * caret 放回 Lexical。这里只在空代码块兜底选到 CodeNode 末尾,不覆盖有内容时\n * 浏览器/Lexical 自己计算出来的精确光标位置。\n */\n options.editor.update(() => {\n const node = $getNodeByKey(nodeKey);\n\n if ($isCodeNode(node)) {\n node.selectEnd();\n }\n });\n options.editor.focus();\n };\n\n layer.addEventListener('pointerdown', handlePointerDown);\n layer.addEventListener('click', handleClick);\n scrollContainer.addEventListener('pointerdown', handleRootPointerDown);\n scrollContainer.addEventListener('scroll', scheduleSyncAllControls, { passive: true });\n window.addEventListener('resize', scheduleSyncAllControls);\n\n return {\n destroy() {\n unregisterMutationListener();\n unregisterUpdateListener();\n if (syncFrame !== null) {\n cancelFrame(syncFrame);\n syncFrame = null;\n }\n layer.removeEventListener('pointerdown', handlePointerDown);\n layer.removeEventListener('click', handleClick);\n scrollContainer.removeEventListener('pointerdown', handleRootPointerDown);\n scrollContainer.removeEventListener('scroll', scheduleSyncAllControls);\n window.removeEventListener('resize', scheduleSyncAllControls);\n controls.forEach((control) => {\n clearPressedStates.get(control)?.();\n control.remove();\n });\n controls.clear();\n clearPressedStates.clear();\n layer.remove();\n dialog?.destroy();\n dialog = null;\n }\n };\n};\n","import type {\n MediaAlign,\n MediaDisplayWidthPercent,\n MenuItem,\n RichTextEditorOptions,\n ToolbarConfig,\n ToolbarKey\n} from '@bridgerte/core';\nimport { resolveToolbarMenu } from '@bridgerte/native-spec';\nimport { resolveMenuSchemaForDom } from '../menuRuntime';\n\nexport const mediaControlsResizeIds = [\n 'media-resize-20',\n 'media-resize-50',\n 'media-resize-100'\n] as const;\n\nconst mediaControlsDefaultKeys: ToolbarKey[] = [\n 'media-align-left',\n 'media-align-center',\n 'media-align-right',\n '|',\n ...mediaControlsResizeIds,\n '|',\n 'media-remove'\n];\n\nconst mediaControlsErrorKeys: ToolbarKey[] = [\n 'media-retry',\n '|',\n 'media-remove'\n];\n\nconst mediaControlSchema: MenuItem[] = [\n {\n id: 'media-align-left',\n command: { type: 'media.align', assetId: '', value: 'left' },\n label: '左',\n icon: 'align-left',\n group: 'media'\n },\n {\n id: 'media-align-center',\n command: { type: 'media.align', assetId: '', value: 'center' },\n label: '中',\n icon: 'align-center',\n group: 'media'\n },\n {\n id: 'media-align-right',\n command: { type: 'media.align', assetId: '', value: 'right' },\n label: '右',\n icon: 'align-right',\n group: 'media'\n },\n {\n id: 'media-resize-20',\n command: { type: 'media.resize', assetId: '', widthPercent: 20 },\n label: '20%',\n icon: 'media-resize-20',\n group: 'media'\n },\n {\n id: 'media-resize-50',\n command: { type: 'media.resize', assetId: '', widthPercent: 50 },\n label: '50%',\n icon: 'media-resize-50',\n group: 'media'\n },\n {\n id: 'media-resize-100',\n command: { type: 'media.resize', assetId: '', widthPercent: 100 },\n label: '100%',\n icon: 'media-resize-100',\n group: 'media'\n },\n {\n id: 'media-retry',\n command: { type: 'media.retry', assetId: '' },\n label: '重试',\n icon: 'refresh-cw',\n group: 'media'\n },\n {\n id: 'media-remove',\n command: { type: 'media.remove', assetId: '' },\n label: '删除',\n icon: 'trash-2',\n group: 'media'\n }\n];\n\nconst isResizeId = (key: string): key is typeof mediaControlsResizeIds[number] => (\n mediaControlsResizeIds.includes(key as typeof mediaControlsResizeIds[number])\n);\n\nconst isToolbarGroupConfig = (\n key: ToolbarKey\n): key is Extract<ToolbarKey, { menuKeys: string[] }> => (\n typeof key === 'object' && Array.isArray(key.menuKeys)\n);\n\nconst collectToolbarKeyIds = (keys: ToolbarKey[]) => new Set(keys.flatMap((key) => {\n if (key === '|') return [];\n if (typeof key === 'string') return [key];\n if (isToolbarGroupConfig(key)) return [key.key, ...key.menuKeys];\n\n return [];\n}));\n\nconst appendMissingResizeKeys = (keys: ToolbarKey[]) => {\n const existingKeys = collectToolbarKeyIds(keys);\n const missingResizeKeys = mediaControlsResizeIds.filter((key) => !existingKeys.has(key));\n\n if (missingResizeKeys.length === 0) return keys;\n\n /*\n * 尺寸控制是媒体节点基础可用性,不允许业务 config 删除。\n * 业务完整重排或 excludeKeys 误删时,解析层在末尾补回缺失尺寸入口,并用分割线隔开。\n */\n return [\n ...keys,\n '|',\n ...missingResizeKeys\n ];\n};\n\nconst normalizeSuccessConfig = (\n config: ToolbarConfig | undefined\n): ToolbarConfig => {\n const baseKeys = config?.toolbarKeys ?? mediaControlsDefaultKeys;\n const safeConfig = {\n ...config,\n toolbarKeys: appendMissingResizeKeys(baseKeys),\n excludeKeys: config?.excludeKeys?.filter((key) => !isResizeId(key))\n };\n\n return safeConfig;\n};\n\nexport const createMediaControlCommand = (\n item: MenuItem,\n assetId: string\n) => {\n switch (item.command.type) {\n case 'media.retry':\n return { ...item.command, assetId };\n case 'media.remove':\n return { ...item.command, assetId };\n case 'media.resize':\n return { ...item.command, assetId };\n case 'media.align':\n return { ...item.command, assetId };\n default:\n /*\n * media controls schema 只接收媒体命令。业务误塞非媒体命令时保持 no-op,\n * 避免 overlay controls 意外执行文档级操作。\n */\n return null;\n }\n};\n\nexport const isMediaControlActive = (\n item: MenuItem,\n currentWidthPercent: MediaDisplayWidthPercent,\n currentAlign: MediaAlign\n) => {\n if (item.command.type === 'media.resize') {\n return item.command.widthPercent === currentWidthPercent;\n }\n\n return item.command.type === 'media.align' && item.command.value === currentAlign;\n};\n\n/**\n * 解析媒体 overlay controls 菜单。\n *\n * 成功态允许业务删减、排序、插入和替换 label/icon,但尺寸三项会强制保留;\n * 失败态固定只暴露重试和删除,避免展示对失败资源无效的尺寸或对齐操作。\n */\nexport const resolveMediaControlsMenu = (\n status: string | undefined,\n options: {\n config?: RichTextEditorOptions['mediaControlsConfig'];\n menuLabels?: RichTextEditorOptions['menuLabels'];\n } = {}\n) => {\n const menuSchema = resolveMenuSchemaForDom(mediaControlSchema, {\n menuLabels: options.menuLabels\n });\n const config = status === 'error'\n ? { toolbarKeys: mediaControlsErrorKeys }\n : normalizeSuccessConfig(options.config);\n\n return resolveToolbarMenu(config, menuSchema);\n};\n","import { type NodeKey } from 'lexical';\nimport type {\n MediaAlign,\n MediaDisplayWidthPercent,\n MenuItem\n} from '@bridgerte/core';\nimport type { ResolvedToolbarItem } from '@bridgerte/native-spec';\nimport { BridgeMediaNode } from '../mediaNode';\nimport {\n cancelFrame,\n scheduleFrame\n} from '../domScheduler';\nimport { bindTouchPressedState } from '../interactionState';\nimport type { ClearInteractionPressedState } from '../interactionState';\nimport {\n createMediaControlCommand,\n isMediaControlActive,\n resolveMediaControlsMenu\n} from './menu';\nimport type {\n MediaControlsController,\n MediaControlsControllerOptions\n} from './type';\n\nexport type * from './type';\n\nconst mediaControlsOffset = 8;\nconst mediaControlsButtonClassName = 'bridgerte__media-controls-button';\n\nconst getMediaScrollContainer = (root: HTMLElement) => (\n root.querySelector<HTMLElement>('.bridgerte__content') ?? root\n);\n\nconst getMediaElementFromTarget = (target: EventTarget | null) => (\n target instanceof Element ? target.closest<HTMLElement>('.bridgerte__media') : null\n);\n\nconst createMediaControlsButton = (\n item: MenuItem,\n active = false\n) => {\n const button = document.createElement('button');\n\n button.type = 'button';\n button.className = mediaControlsButtonClassName;\n button.textContent = item.label;\n button.dataset.menuItemId = item.id;\n button.dataset.action = item.id.replace(/^media-/, '');\n if (active) button.dataset.active = 'true';\n button.setAttribute('aria-label', item.label);\n\n return button;\n};\n\nconst flattenMediaControlsItems = (items: ResolvedToolbarItem[]) => items.flatMap((item) => (\n item.type === 'button' ? [item.item]\n : item.type === 'group' ? item.items\n : []\n));\n\nconst appendMediaControlItem = (\n controls: HTMLElement,\n item: ResolvedToolbarItem,\n currentWidthPercent: MediaDisplayWidthPercent,\n currentAlign: MediaAlign\n) => {\n if (item.type === 'separator') {\n const separator = document.createElement('span');\n\n separator.className = 'bridgerte__media-controls-separator';\n separator.dataset.separatorId = item.key;\n separator.setAttribute('aria-hidden', 'true');\n controls.append(separator);\n return;\n }\n\n const menuItems = item.type === 'button' ? [item.item] : item.items;\n\n menuItems.forEach((menuItem) => {\n controls.append(createMediaControlsButton(\n menuItem,\n isMediaControlActive(menuItem, currentWidthPercent, currentAlign)\n ));\n });\n};\n\nconst createMediaControls = (\n mediaElement: HTMLElement,\n defaultWidthPercent: MediaDisplayWidthPercent,\n options: MediaControlsControllerOptions\n) => {\n const controls = document.createElement('div');\n const status = mediaElement.dataset.status;\n const activeWidthPercent = Number(\n mediaElement.dataset.displayWidthPercent ?? defaultWidthPercent\n ) as MediaDisplayWidthPercent;\n const activeAlign = (mediaElement.dataset.align ?? 'left') as MediaAlign;\n const controlItems = resolveMediaControlsMenu(status, {\n config: options.mediaControlsConfig,\n menuLabels: options.menuLabels\n });\n\n controls.className = 'bridgerte__media-controls';\n controls.contentEditable = 'false';\n controls.setAttribute('aria-label', '媒体操作');\n controls.dataset.status = status ?? 'success';\n controls.dataset.displayWidthPercent = mediaElement.dataset.displayWidthPercent ?? '';\n controls.dataset.align = mediaElement.dataset.align ?? '';\n controls.dataset.menuItemIds = flattenMediaControlsItems(controlItems)\n .map((item) => item.id)\n .join('|');\n controlItems.forEach((item) => {\n appendMediaControlItem(controls, item, activeWidthPercent, activeAlign);\n });\n\n return controls;\n};\n\n/**\n * 创建媒体选中/操作控制层。\n *\n * 媒体节点仍只负责内容 DOM 和序列化;控制层作为 overlay sibling 挂在编辑器根容器上,\n * 根据媒体节点的 `assetId/status` 触发 `media.retry` 或 `media.remove`,不把按钮写进内容。\n */\nexport const createMediaControlsController = (\n options: MediaControlsControllerOptions\n): MediaControlsController => {\n const layer = document.createElement('div');\n const scrollContainer = getMediaScrollContainer(options.root);\n const controls = new Map<NodeKey, HTMLElement>();\n const clearPressedStates = new Map<HTMLElement, ClearInteractionPressedState>();\n const mediaElementKeys = new Map<HTMLElement, NodeKey>();\n let syncFrame: number | null = null;\n let touchStartButton: HTMLButtonElement | null = null;\n let shouldSuppressNextClick = false;\n let activeMediaKey: NodeKey | null = null;\n\n const removeControls = (nodeKey: NodeKey) => {\n const control = controls.get(nodeKey);\n\n if (!control) return;\n\n clearPressedStates.get(control)?.();\n clearPressedStates.delete(control);\n control.remove();\n controls.delete(nodeKey);\n if (activeMediaKey === nodeKey) activeMediaKey = null;\n };\n\n const shouldShowControls = (nodeKey: NodeKey, mediaElement: HTMLElement) => (\n mediaElement.dataset.status === 'error' || activeMediaKey === nodeKey\n );\n\n const positionControls = (control: HTMLElement, mediaElement: HTMLElement) => {\n const rootRect = options.root.getBoundingClientRect();\n const mediaRect = mediaElement.getBoundingClientRect();\n const isOutsideRoot = mediaRect.bottom < rootRect.top || mediaRect.top > rootRect.bottom;\n const maxX = Math.max(\n mediaControlsOffset,\n rootRect.width - control.offsetWidth - mediaControlsOffset\n );\n const nextX = Math.min(\n Math.max(mediaRect.left - rootRect.left + mediaControlsOffset, mediaControlsOffset),\n maxX\n );\n const nextY = Math.max(\n mediaControlsOffset,\n mediaRect.top - rootRect.top - control.offsetHeight - mediaControlsOffset\n );\n\n control.hidden = isOutsideRoot;\n /*\n * 控制条优先贴在媒体块上方并做水平夹紧,避免尺寸按钮遮住图片/视频内容;\n * 顶部空间不足时落在容器可视范围内,保证 H5 小屏也能点到。\n */\n control.style.transform = `translate(${nextX}px, ${nextY}px)`;\n };\n\n const syncControls = (nodeKey: NodeKey) => {\n const mediaElement = options.editor.getElementByKey(nodeKey);\n\n if (!mediaElement) {\n removeControls(nodeKey);\n return;\n }\n\n mediaElement.dataset.lexicalKey = nodeKey;\n mediaElementKeys.set(mediaElement, nodeKey);\n const existingControls = controls.get(nodeKey);\n\n if (!shouldShowControls(nodeKey, mediaElement)) {\n removeControls(nodeKey);\n return;\n }\n\n if (existingControls) {\n const shouldHaveRetry = mediaElement.dataset.status === 'error';\n const hasRetry = existingControls.querySelector('[data-action=\"retry\"]') !== null;\n const displayWidthPercent = mediaElement.dataset.displayWidthPercent ?? '';\n const align = mediaElement.dataset.align ?? '';\n\n if (\n shouldHaveRetry === hasRetry\n && existingControls.dataset.displayWidthPercent === displayWidthPercent\n && existingControls.dataset.align === align\n ) {\n positionControls(existingControls, mediaElement);\n return;\n }\n\n removeControls(nodeKey);\n }\n\n const control = createMediaControls(mediaElement, options.defaultWidthPercent, options);\n const clearPressedState = bindTouchPressedState(control, {\n targetSelector: `.${mediaControlsButtonClassName}`\n });\n\n control.dataset.lexicalKey = nodeKey;\n control.dataset.assetId = mediaElement.dataset.assetId;\n controls.set(nodeKey, control);\n clearPressedStates.set(control, clearPressedState);\n layer.append(control);\n positionControls(control, mediaElement);\n };\n\n const syncAllControls = () => {\n syncFrame = null;\n mediaElementKeys.forEach((nodeKey, mediaElement) => {\n if (!options.root.contains(mediaElement)) {\n mediaElementKeys.delete(mediaElement);\n removeControls(nodeKey);\n }\n });\n options.root.querySelectorAll<HTMLElement>('.bridgerte__media').forEach((mediaElement) => {\n const nodeKey = mediaElement.dataset.lexicalKey as NodeKey | undefined;\n\n if (nodeKey) {\n mediaElementKeys.set(mediaElement, nodeKey);\n syncControls(nodeKey);\n }\n });\n controls.forEach((_, nodeKey) => {\n syncControls(nodeKey);\n });\n if (activeMediaKey !== null) {\n syncControls(activeMediaKey);\n }\n };\n\n const scheduleSyncAllControls = () => {\n if (syncFrame !== null) return;\n\n // 媒体 controls 和内容节点分离,位置同步只在下一帧读写 rect,避免和 Lexical reconcile 抢时机。\n syncFrame = scheduleFrame(syncAllControls);\n };\n\n const executeButton = (button: HTMLButtonElement, control: HTMLElement) => {\n const assetId = control.dataset.assetId;\n const menuItem = flattenMediaControlsItems(resolveMediaControlsMenu(control.dataset.status, {\n config: options.mediaControlsConfig,\n menuLabels: options.menuLabels\n })).find((item) => item.id === button.dataset.menuItemId);\n\n if (!assetId || !menuItem) return;\n\n const command = createMediaControlCommand(menuItem, assetId);\n\n if (command) options.executeCommand(command);\n };\n\n const activateMediaElement = (mediaElement: HTMLElement | null) => {\n if (!mediaElement) {\n const previousActiveKey = activeMediaKey;\n\n activeMediaKey = null;\n if (previousActiveKey !== null) syncControls(previousActiveKey);\n return;\n }\n\n const nextActiveKey = mediaElement.dataset.lexicalKey\n ? (mediaElement.dataset.lexicalKey as NodeKey)\n : mediaElementKeys.get(mediaElement) ?? null;\n\n if (!nextActiveKey || activeMediaKey === nextActiveKey) return;\n\n const previousActiveKey = activeMediaKey;\n\n activeMediaKey = nextActiveKey;\n if (previousActiveKey !== null) syncControls(previousActiveKey);\n syncControls(nextActiveKey);\n };\n\n const handleContentPointerDown = (event: PointerEvent) => {\n const mediaElement = getMediaElementFromTarget(event.target);\n\n /*\n * 成功态 controls 只跟随用户当前操作的媒体块,避免大文档每个媒体都常驻按钮。\n * 失败态由 syncControls 按 status 保持常驻,方便用户直接重试或删除。\n */\n activateMediaElement(mediaElement);\n };\n\n const handleContentFocusIn = (event: FocusEvent) => {\n activateMediaElement(getMediaElementFromTarget(event.target));\n };\n\n const handlePointerDown = (event: PointerEvent) => {\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) return;\n\n const button = target.closest<HTMLButtonElement>(`.${mediaControlsButtonClassName}`);\n\n if (!button) return;\n\n event.preventDefault();\n touchStartButton = event.pointerType === 'mouse' ? null : button;\n };\n\n const handlePointerUp = (event: PointerEvent) => {\n if (event.pointerType === 'mouse' || !touchStartButton) return;\n\n const target = event.target;\n const control = target instanceof HTMLElement\n ? target.closest<HTMLElement>('.bridgerte__media-controls')\n : null;\n const button = target instanceof HTMLElement\n ? target.closest<HTMLButtonElement>(`.${mediaControlsButtonClassName}`)\n : null;\n\n if (button === touchStartButton && control) {\n event.preventDefault();\n event.stopPropagation();\n executeButton(button, control);\n shouldSuppressNextClick = true;\n }\n touchStartButton = null;\n };\n\n const clearTouchStartButton = () => {\n touchStartButton = null;\n };\n\n const handleClick = (event: MouseEvent) => {\n if (shouldSuppressNextClick) {\n shouldSuppressNextClick = false;\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) return;\n\n const button = target.closest<HTMLButtonElement>(`.${mediaControlsButtonClassName}`);\n const control = target.closest<HTMLElement>('.bridgerte__media-controls');\n\n if (!button || !control) return;\n\n event.preventDefault();\n event.stopPropagation();\n executeButton(button, control);\n };\n\n layer.className = 'bridgerte__media-controls-layer';\n options.root.append(layer);\n\n const unregisterMutationListener = options.editor.registerMutationListener(\n BridgeMediaNode,\n (mutations) => {\n mutations.forEach((mutation, nodeKey) => {\n if (mutation === 'destroyed') {\n removeControls(nodeKey);\n return;\n }\n\n syncControls(nodeKey);\n });\n }\n );\n const unregisterUpdateListener = options.editor.registerUpdateListener(scheduleSyncAllControls);\n\n layer.addEventListener('pointerdown', handlePointerDown);\n layer.addEventListener('pointerup', handlePointerUp);\n layer.addEventListener('pointercancel', clearTouchStartButton);\n layer.addEventListener('click', handleClick);\n scrollContainer.addEventListener('pointerdown', handleContentPointerDown);\n scrollContainer.addEventListener('focusin', handleContentFocusIn);\n scrollContainer.addEventListener('scroll', scheduleSyncAllControls, { passive: true });\n window.addEventListener('resize', scheduleSyncAllControls);\n\n return {\n destroy() {\n unregisterMutationListener();\n unregisterUpdateListener();\n if (syncFrame !== null) {\n cancelFrame(syncFrame);\n syncFrame = null;\n }\n layer.removeEventListener('pointerdown', handlePointerDown);\n layer.removeEventListener('pointerup', handlePointerUp);\n layer.removeEventListener('pointercancel', clearTouchStartButton);\n layer.removeEventListener('click', handleClick);\n scrollContainer.removeEventListener('pointerdown', handleContentPointerDown);\n scrollContainer.removeEventListener('focusin', handleContentFocusIn);\n scrollContainer.removeEventListener('scroll', scheduleSyncAllControls);\n window.removeEventListener('resize', scheduleSyncAllControls);\n controls.forEach((control) => {\n clearPressedStates.get(control)?.();\n control.remove();\n });\n controls.clear();\n clearPressedStates.clear();\n mediaElementKeys.clear();\n layer.remove();\n }\n };\n};\n","import type { EditorCommand, PayloadPanelValues } from '@bridgerte/core';\n\nconst optionalNumberPayloadKeys = ['width', 'height'] as const;\n\nconst getStringValue = (values: PayloadPanelValues, key: string) => {\n const value = values[key]?.trim();\n\n return value ? value : undefined;\n};\n\nconst getPositiveIntegerValue = (values: PayloadPanelValues, key: string) => {\n const value = Number.parseInt(values[key] ?? '', 10);\n\n return Number.isFinite(value) && value > 0 ? value : undefined;\n};\n\nconst mergeOptionalNumberPayload = <TCommand extends EditorCommand>(\n command: TCommand,\n values: PayloadPanelValues\n) => optionalNumberPayloadKeys.reduce<TCommand>((nextCommand, key) => {\n const value = getPositiveIntegerValue(values, key);\n\n return value === undefined ? nextCommand : { ...nextCommand, [key]: value };\n}, command);\n\n/**\n * 把参数面板收集到的字段值合成真正可执行的命令。\n *\n * 面板字段值统一是 string,命令层在这里做最小类型转换;新增参数命令时优先扩展这个\n * 分发表,避免 DOM 字段渲染器知道编辑器业务语义。\n */\nexport const mergePayloadValuesIntoCommand = (\n command: EditorCommand,\n values: PayloadPanelValues\n): EditorCommand | null => {\n if (\n command.type === 'format.color'\n || command.type === 'format.backgroundColor'\n || command.type === 'format.fontSize'\n || command.type === 'format.fontFamily'\n || command.type === 'format.lineHeight'\n ) {\n return values.value !== undefined ? { ...command, value: values.value } : command;\n }\n\n if (command.type === 'link.set') {\n const href = getStringValue(values, 'href');\n const text = getStringValue(values, 'text');\n\n return href ? { ...command, href, text } : null;\n }\n\n if (command.type === 'block.code') {\n return values.language ? { type: 'block.code', language: values.language } : command;\n }\n\n if (command.type === 'block.setCodeLanguage') {\n return values.language !== undefined ? { ...command, language: values.language } : command;\n }\n\n if (command.type === 'table.insert') {\n const rows = getPositiveIntegerValue(values, 'rows');\n const cols = getPositiveIntegerValue(values, 'cols');\n\n return rows && cols ? { type: 'table.insert', rows, cols } : null;\n }\n\n if (command.type === 'media.insertImage') {\n const url = getStringValue(values, 'url');\n\n if (!url) return null;\n\n return mergeOptionalNumberPayload({\n ...command,\n url,\n alt: getStringValue(values, 'alt'),\n title: getStringValue(values, 'title')\n }, values);\n }\n\n if (command.type === 'media.insertVideo') {\n const url = getStringValue(values, 'url');\n\n if (!url) return null;\n\n return mergeOptionalNumberPayload({\n ...command,\n url,\n poster: getStringValue(values, 'poster'),\n title: getStringValue(values, 'title')\n }, values);\n }\n\n return command;\n};\n","import type { HsvColor, RgbColor } from './type';\n\n/**\n * color 字段的纯转换工具。\n *\n * DOM 默认面板用 HSV 做圆盘交互,用 hex 写回命令;这些函数不触碰 DOM,后续如果 H5\n * 或 WebView 想复用同样算法,可以迁到更公共的位置。\n */\nexport const clampRgbValue = (value: number) => Math.min(Math.max(Math.round(value), 0), 255);\n\nexport const formatHexColor = ({ r, g, b }: RgbColor) => (\n `#${\n [r, g, b]\n .map((channel) => clampRgbValue(channel).toString(16).padStart(2, '0'))\n .join('')\n }`\n);\n\nexport const parseHexColor = (value: string): RgbColor | null => {\n const normalizedValue = value.trim();\n const match = normalizedValue.match(/^#([0-9a-f]{6})$/i);\n\n if (!match) return null;\n\n const hexValue = match[1] ?? '';\n\n return {\n r: Number.parseInt(hexValue.slice(0, 2), 16),\n g: Number.parseInt(hexValue.slice(2, 4), 16),\n b: Number.parseInt(hexValue.slice(4, 6), 16)\n };\n};\n\nexport const parseRgbColor = (value: string): RgbColor | null => {\n const match = value\n .trim()\n .match(/^rgb\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*\\)$/i);\n\n if (!match) return null;\n\n return {\n r: clampRgbValue(Number(match[1])),\n g: clampRgbValue(Number(match[2])),\n b: clampRgbValue(Number(match[3]))\n };\n};\n\nexport const normalizeColorValue = (value: string): string | null => {\n const parsedValue = parseHexColor(value) ?? parseRgbColor(value);\n\n return parsedValue ? formatHexColor(parsedValue) : null;\n};\n\nexport const clampUnitValue = (value: number) => Math.min(Math.max(value, 0), 1);\n\nexport const rgbToHsv = ({ r, g, b }: RgbColor): HsvColor => {\n const red = clampRgbValue(r) / 255;\n const green = clampRgbValue(g) / 255;\n const blue = clampRgbValue(b) / 255;\n const max = Math.max(red, green, blue);\n const min = Math.min(red, green, blue);\n const delta = max - min;\n let h = 0;\n\n if (delta !== 0) {\n if (max === red) {\n h = 60 * (((green - blue) / delta) % 6);\n } else if (max === green) {\n h = 60 * ((blue - red) / delta + 2);\n } else {\n h = 60 * ((red - green) / delta + 4);\n }\n }\n\n return {\n h: h < 0 ? h + 360 : h,\n s: max === 0 ? 0 : delta / max,\n v: max\n };\n};\n\nexport const hsvToRgb = ({\n h,\n s,\n v\n}: HsvColor): RgbColor => {\n const chroma = v * s;\n const x = chroma * (1 - Math.abs(((h / 60) % 2) - 1));\n const m = v - chroma;\n let red = 0;\n let green = 0;\n let blue = 0;\n\n if (h < 60) {\n red = chroma;\n green = x;\n } else if (h < 120) {\n red = x;\n green = chroma;\n } else if (h < 180) {\n green = chroma;\n blue = x;\n } else if (h < 240) {\n green = x;\n blue = chroma;\n } else if (h < 300) {\n red = x;\n blue = chroma;\n } else {\n red = chroma;\n blue = x;\n }\n\n return {\n r: (red + m) * 255,\n g: (green + m) * 255,\n b: (blue + m) * 255\n };\n};\n\nexport const getWheelPointerPosition = ({ h, s }: Pick<HsvColor, 'h' | 's'>) => {\n const angle = (h * Math.PI) / 180;\n const radius = clampUnitValue(s) * 50;\n\n return {\n x: 50 + Math.cos(angle) * radius,\n y: 50 + Math.sin(angle) * radius\n };\n};\n\nexport const getHsvFromPointer = (event: PointerEvent, wheelElement: HTMLElement): HsvColor => {\n const rect = wheelElement.getBoundingClientRect();\n const centerX = rect.left + rect.width / 2;\n const centerY = rect.top + rect.height / 2;\n const dx = event.clientX - centerX;\n const dy = event.clientY - centerY;\n const distance = Math.min(Math.sqrt(dx * dx + dy * dy), rect.width / 2);\n const angle = Math.atan2(dy, dx) * 180 / Math.PI;\n\n return {\n h: angle < 0 ? angle + 360 : angle,\n s: clampUnitValue(distance / (rect.width / 2)),\n v: 1\n };\n};\n","import type { PayloadPanelField, PayloadPanelValues } from '@bridgerte/core';\nimport { bindTouchPressedState } from '../interactionState';\nimport {\n formatHexColor,\n getHsvFromPointer,\n getWheelPointerPosition,\n hsvToRgb,\n normalizeColorValue,\n parseHexColor,\n rgbToHsv\n} from './color';\nimport type { HsvColor, PayloadPanelFieldRendererOptions } from './type';\n\n/*\n * 内置色盘的无配置兜底保留黑白极值;业务品牌色通过 color field options 注入。\n * 透明度、渐变或复杂色板仍应通过 onPayloadPanelRequest 自绘接管。\n */\nconst defaultColorSwatchValues = [\n '#000000',\n '#ffffff'\n];\n\nconst getColorSwatchOptions = (field: Extract<PayloadPanelField, { type: 'color' }>) => (\n field.options?.length\n ? field.options\n : defaultColorSwatchValues.map((value) => ({ label: value, value }))\n);\n\nconst createFieldContainer = () => {\n const fieldElement = document.createElement('section');\n\n fieldElement.className = 'bridgerte__payload-panel-field';\n\n return fieldElement;\n};\n\n/**\n * 渲染 select 字段为按钮列表。\n *\n * DOM 默认面板采用“点击选项即确认”的交互,不再提供底部动作按钮;关闭语义交给透明蒙层。\n */\nconst renderSelectField = (\n field: Extract<PayloadPanelField, { type: 'select' }>,\n values: PayloadPanelValues,\n onSubmit: (values: PayloadPanelValues) => void\n) => {\n const fieldElement = createFieldContainer();\n const listElement = document.createElement('div');\n\n listElement.className = 'bridgerte__payload-panel-option-list';\n field.options.forEach((option) => {\n const optionButton = document.createElement('button');\n\n optionButton.type = 'button';\n optionButton.className = 'bridgerte__payload-panel-option';\n optionButton.textContent = option.label;\n optionButton.dataset.bridgertePayloadOption = option.value;\n optionButton.dataset.active = values[field.name] === option.value ? 'true' : 'false';\n bindTouchPressedState(optionButton);\n optionButton.addEventListener('pointerdown', (event) => {\n // select 选项和 toolbar 一样要保留原选区,点击后命令才能作用在用户选中的文本上。\n event.preventDefault();\n });\n optionButton.addEventListener('click', () => {\n onSubmit({\n ...values,\n [field.name]: option.value\n });\n });\n listElement.append(optionButton);\n });\n fieldElement.append(listElement);\n\n return fieldElement;\n};\n\n/**\n * 渲染 color 字段为 BridgeRTE 内置圆盘选择器。\n *\n * 圆盘负责大范围取色,底部黑白按钮补齐极值。默认不高亮任何颜色,\n * 只有用户明确点击或拖动后才把当前值写回表单。\n */\nconst renderColorField = (\n field: Extract<PayloadPanelField, { type: 'color' }>,\n values: PayloadPanelValues,\n onSubmit: (values: PayloadPanelValues) => void\n) => {\n const fieldElement = createFieldContainer();\n const colorWheelElement = document.createElement('div');\n const colorWheelHandleElement = document.createElement('span');\n const colorActionsElement = document.createElement('div');\n const colorPreviewElement = document.createElement('div');\n let currentHsv: HsvColor = { h: 0, s: 0, v: 1 };\n let activePointerId: number | null = null;\n\n const updateColorPreview = (nextValue: string) => {\n const normalizedValue = normalizeColorValue(nextValue);\n\n if (!normalizedValue) return;\n\n values[field.name] = normalizedValue;\n colorPreviewElement.style.background = normalizedValue;\n currentHsv = rgbToHsv(parseHexColor(normalizedValue) ?? { r: 255, g: 255, b: 255 });\n const pointerPosition = getWheelPointerPosition(currentHsv);\n\n colorWheelElement.dataset.active = 'true';\n colorPreviewElement.dataset.empty = 'false';\n colorWheelHandleElement.style.left = `${pointerPosition.x}%`;\n colorWheelHandleElement.style.top = `${pointerPosition.y}%`;\n };\n const submitColorValue = () => {\n const colorValue = values[field.name];\n\n if (!colorValue) return;\n\n onSubmit({\n ...values,\n [field.name]: colorValue\n });\n };\n\n fieldElement.className = 'bridgerte__payload-panel-field';\n colorWheelElement.className = 'bridgerte__payload-panel-color-wheel';\n /*\n * 色盘是 pointer-first 的二维选择区域,不声明 slider。\n * slider 语义需要完整键盘数值模型和 aria-valuenow;这里保守暴露为带说明的自定义区域,\n * 黑白快捷色仍使用真实 button,复杂可访问色板交给业务自绘接管。\n */\n colorWheelElement.setAttribute('aria-label', `${field.label}选择区域`);\n colorWheelHandleElement.className = 'bridgerte__payload-panel-color-wheel-handle';\n colorActionsElement.className = 'bridgerte__payload-panel-color-actions';\n colorPreviewElement.className = 'bridgerte__payload-panel-color-preview';\n colorPreviewElement.dataset.empty = 'true';\n colorWheelElement.append(colorWheelHandleElement);\n getColorSwatchOptions(field).forEach((option) => {\n const swatchButton = document.createElement('button');\n const colorValue = option.value;\n\n swatchButton.type = 'button';\n swatchButton.className = 'bridgerte__payload-panel-color-swatch';\n swatchButton.dataset.value = colorValue;\n swatchButton.style.background = colorValue;\n swatchButton.setAttribute('aria-label', `选择颜色 ${option.label}`);\n bindTouchPressedState(swatchButton);\n swatchButton.addEventListener('pointerdown', (event) => {\n event.preventDefault();\n });\n swatchButton.addEventListener('click', () => {\n updateColorPreview(colorValue);\n submitColorValue();\n });\n colorActionsElement.append(swatchButton);\n });\n colorWheelElement.addEventListener('pointerdown', (event) => {\n activePointerId = event.pointerId;\n colorWheelElement.setPointerCapture(event.pointerId);\n currentHsv = getHsvFromPointer(event, colorWheelElement);\n updateColorPreview(formatHexColor(hsvToRgb(currentHsv)));\n event.preventDefault();\n });\n colorWheelElement.addEventListener('pointermove', (event) => {\n if (activePointerId !== event.pointerId) return;\n\n currentHsv = getHsvFromPointer(event, colorWheelElement);\n updateColorPreview(formatHexColor(hsvToRgb(currentHsv)));\n });\n colorWheelElement.addEventListener('pointerup', (event) => {\n if (activePointerId !== event.pointerId) return;\n\n activePointerId = null;\n colorWheelElement.releasePointerCapture(event.pointerId);\n submitColorValue();\n });\n colorWheelElement.addEventListener('pointercancel', (event) => {\n if (activePointerId !== event.pointerId) return;\n\n activePointerId = null;\n colorWheelElement.releasePointerCapture(event.pointerId);\n });\n const initialValue = values[field.name];\n\n if (initialValue) {\n updateColorPreview(initialValue);\n }\n fieldElement.append(colorWheelElement, colorPreviewElement, colorActionsElement);\n\n return fieldElement;\n};\n\n/**\n * 渲染自由文本字段,用于链接 URL、媒体 URL、说明文本等真实业务输入。\n *\n * 输入字段需要获得焦点,所以这里不阻止 pointerdown;提交前 controller 会恢复编辑器 selection。\n */\nconst renderTextField = (\n field: Extract<PayloadPanelField, { type: 'text' }>,\n values: PayloadPanelValues,\n onSubmit: (values: PayloadPanelValues) => void\n) => {\n const fieldElement = document.createElement('label');\n const textInput = document.createElement('input');\n\n fieldElement.className = 'bridgerte__payload-panel-text-field';\n fieldElement.textContent = field.label;\n textInput.type = field.name === 'href' || field.name === 'url' ? 'url' : 'text';\n textInput.className = 'bridgerte__payload-panel-text-input';\n textInput.value = values[field.name] ?? '';\n textInput.placeholder = field.placeholder ?? '';\n textInput.spellcheck = false;\n textInput.addEventListener('input', () => {\n values[field.name] = textInput.value;\n });\n textInput.addEventListener('keydown', (event) => {\n if (event.key !== 'Enter') return;\n\n event.preventDefault();\n onSubmit(values);\n });\n fieldElement.append(textInput);\n\n return fieldElement;\n};\n\n/**\n * 渲染 number 字段,用于表格行列、媒体尺寸等需要数值但最终仍以字符串提交的参数。\n */\nconst renderNumberField = (\n field: Extract<PayloadPanelField, { type: 'number' }>,\n values: PayloadPanelValues,\n onSubmit: (values: PayloadPanelValues) => void\n) => {\n const fieldElement = document.createElement('label');\n const numberInput = document.createElement('input');\n\n fieldElement.className = 'bridgerte__payload-panel-text-field';\n fieldElement.textContent = field.label;\n numberInput.type = 'number';\n numberInput.className = 'bridgerte__payload-panel-text-input';\n numberInput.value = values[field.name] ?? '';\n numberInput.placeholder = field.placeholder ?? '';\n if (field.min !== undefined) numberInput.min = String(field.min);\n if (field.max !== undefined) numberInput.max = String(field.max);\n if (field.step !== undefined) numberInput.step = String(field.step);\n numberInput.addEventListener('input', () => {\n values[field.name] = numberInput.value;\n });\n numberInput.addEventListener('keydown', (event) => {\n if (event.key !== 'Enter') return;\n\n event.preventDefault();\n onSubmit(values);\n });\n fieldElement.append(numberInput);\n\n return fieldElement;\n};\n\nexport const renderPayloadPanelField = ({\n field,\n values,\n onSubmit\n}: PayloadPanelFieldRendererOptions) => {\n if (field.type === 'color') {\n return renderColorField(field, values, onSubmit);\n }\n if (field.type === 'text') return renderTextField(field, values, onSubmit);\n if (field.type === 'number') return renderNumberField(field, values, onSubmit);\n\n return renderSelectField(field, values, onSubmit);\n};\n","import type { EditorCommand, PayloadPanelField, PayloadPanelOpenRequest } from '@bridgerte/core';\nimport { bindTouchPressedState } from '../interactionState';\nimport type { PayloadPanelControllerOptions } from './type';\n\nexport const getDefaultFieldValue = (field: PayloadPanelField) => (\n field.defaultValue\n ?? (field.type === 'select' ? field.options[0]?.value : undefined)\n ?? (field.type === 'color' ? field.options?.[0]?.value : undefined)\n ?? ''\n);\n\nexport const getInitialFieldValue = (\n field: PayloadPanelField,\n currentValues: Record<string, string> | undefined\n) => (\n currentValues?.[field.name]\n ?? (field.type === 'color' ? '' : getDefaultFieldValue(field))\n);\n\nexport const hasManualSubmitField = (fields: PayloadPanelField[]) => (\n fields.some((field) => field.type === 'text' || field.type === 'number')\n);\n\nexport const focusFirstEditableInput = (container: HTMLElement) => {\n const input = container.querySelector<HTMLInputElement>(\n '.bridgerte__payload-panel-text-input'\n );\n\n /*\n * 输入型面板打开后直接聚焦第一个输入框。controller 在提交前会恢复编辑器 selection,\n * 所以这里可以服务 URL、表格行列、媒体尺寸等真正需要键盘输入的面板。\n */\n queueMicrotask(() => {\n input?.focus();\n input?.select();\n });\n};\n\nexport const createPanelTitleElement = (\n request: PayloadPanelOpenRequest,\n onClear: (command: EditorCommand) => void,\n getClearCommand?: PayloadPanelControllerOptions['getClearCommand']\n) => {\n const titleElement = document.createElement('div');\n const titleTextElement = document.createElement('span');\n const clearCommand = getClearCommand?.(request) ?? null;\n\n titleElement.className = 'bridgerte__payload-panel-title';\n titleTextElement.textContent = request.panel.title;\n titleElement.append(titleTextElement);\n\n if (clearCommand) {\n const clearButton = document.createElement('button');\n\n clearButton.type = 'button';\n clearButton.className = 'bridgerte__payload-panel-clear';\n clearButton.textContent = '清除';\n clearButton.setAttribute('aria-label', `清除${request.panel.title}`);\n bindTouchPressedState(clearButton);\n clearButton.addEventListener('pointerdown', (event) => {\n // 参数面板按钮不能抢走编辑区 selection,否则清除命令会找不到原选区。\n event.preventDefault();\n });\n clearButton.addEventListener('click', () => {\n onClear(clearCommand);\n });\n titleElement.append(clearButton);\n }\n\n return titleElement;\n};\n\nexport const getDialogWidth = (panelId: string) => (\n /*\n * 字体类面板只需要紧凑候选列表,颜色面板需要保留一点横向空间给圆盘和黑白按钮。\n * 输入型面板保留默认宽度;table-insert 会按 schema 网格列数单独计算。\n */\n panelId === 'font-size'\n || panelId === 'font-family'\n || panelId === 'line-height'\n ? '180px'\n : '220px'\n);\n","import {\n BRIDGERTE_TABLE_INSERT_MAX_COLS,\n BRIDGERTE_TABLE_INSERT_MAX_ROWS,\n type PayloadPanelField\n} from '@bridgerte/core';\nimport { bindTouchPressedState } from '../interactionState';\nimport type {\n PayloadPanelNumberField,\n TableGridDimension,\n TableGridDimensions,\n TableGridRendererOptions\n} from './type';\n\nconst tableGridDefaultRows = 3;\nconst tableGridDefaultCols = 3;\nconst tableGridDefaultVisibleRows = 10;\nconst tableGridDefaultVisibleCols = 10;\nconst tableGridCellSize = 16;\nconst tableGridCellGap = 2;\nconst tableGridPanelChromeWidth = 24;\n\nconst canUseHoverPreview = () => (\n typeof window !== 'undefined'\n && window.matchMedia?.('(hover: hover) and (pointer: fine)').matches === true\n);\n\nconst clampIntegerValue = (\n value: string | undefined,\n dimension: TableGridDimension\n) => {\n const nextValue = Number.parseInt(value ?? '', 10);\n\n if (!Number.isFinite(nextValue)) return dimension.defaultValue;\n\n return Math.min(Math.max(nextValue, dimension.min), dimension.max);\n};\n\nconst isTableGridNumberField = (\n field: PayloadPanelField,\n name: 'rows' | 'cols'\n): field is PayloadPanelNumberField => field.type === 'number' && field.name === name;\n\nconst getPositiveIntegerLimit = (\n value: number | undefined,\n fallbackValue: number\n) => (\n typeof value === 'number' && Number.isFinite(value) && value > 0\n ? Math.floor(value)\n : fallbackValue\n);\n\nconst getTableGridDimension = (\n fields: PayloadPanelField[],\n name: 'rows' | 'cols',\n fallbackMax: number,\n fallbackDefault: number\n): TableGridDimension => {\n const field = fields.find((item) => isTableGridNumberField(item, name));\n const min = getPositiveIntegerLimit(field?.min, 1);\n const maxFromSchema = getPositiveIntegerLimit(field?.max, fallbackMax);\n const max = Math.max(min, maxFromSchema);\n const fallbackDefaultInRange = Math.min(Math.max(fallbackDefault, min), max);\n const defaultValue = clampIntegerValue(field?.defaultValue, {\n min,\n max,\n defaultValue: fallbackDefaultInRange\n });\n\n return {\n min,\n max,\n defaultValue\n };\n};\n\n/**\n * 从 table-insert 面板的 rows/cols number 字段推导默认 DOM 网格尺寸。\n *\n * public schema 是跨端能力来源,DOM 网格只在字段缺失或 schema 写错时使用内置值兜底;\n * 这样不会把默认 UI 固定死,也不会静默吞掉 native-spec 已声明的更大行列上限。\n */\nexport const resolveTableGridDimensions = (\n fields: PayloadPanelField[]\n): TableGridDimensions => ({\n rows: getTableGridDimension(\n fields,\n 'rows',\n BRIDGERTE_TABLE_INSERT_MAX_ROWS,\n tableGridDefaultRows\n ),\n cols: getTableGridDimension(\n fields,\n 'cols',\n BRIDGERTE_TABLE_INSERT_MAX_COLS,\n tableGridDefaultCols\n )\n});\n\n/**\n * 根据网格列数给 table-insert 面板计算紧凑宽度。\n *\n * 默认 DOM UI 只提供首屏紧凑选择;可见网格尺寸由本模块 UI 常量控制。\n */\nexport const getTableGridDialogWidth = (dimensions: TableGridDimensions) => {\n const visibleCols = Math.min(dimensions.cols.max, tableGridDefaultVisibleCols);\n const gridWidth = visibleCols * tableGridCellSize\n + Math.max(visibleCols - 1, 0) * tableGridCellGap;\n\n return `${gridWidth + tableGridPanelChromeWidth}px`;\n};\n\n/**\n * 渲染表格插入网格。\n *\n * table-insert 的 public schema 仍保留 rows/cols number 字段,方便业务自绘和原生侧复用;\n * DOM 默认 UI 只展示紧凑网格,不再提供内置展开入口,避免弹窗重新变重。\n */\nexport const renderTableGridField = ({\n fields,\n values,\n onSubmit\n}: TableGridRendererOptions) => {\n const dimensions = resolveTableGridDimensions(fields);\n const fieldElement = document.createElement('section');\n const gridElement = document.createElement('div');\n const statusElement = document.createElement('div');\n const gridButtons: HTMLButtonElement[] = [];\n const shouldUseHoverPreview = canUseHoverPreview();\n const visibleRows = Math.min(dimensions.rows.max, tableGridDefaultVisibleRows);\n const visibleCols = Math.min(dimensions.cols.max, tableGridDefaultVisibleCols);\n const visibleRowsDimension = {\n ...dimensions.rows,\n max: visibleRows,\n defaultValue: Math.min(dimensions.rows.defaultValue, visibleRows)\n };\n const visibleColsDimension = {\n ...dimensions.cols,\n max: visibleCols,\n defaultValue: Math.min(dimensions.cols.defaultValue, visibleCols)\n };\n let selectedRows = clampIntegerValue(\n values.rows,\n visibleRowsDimension\n );\n let selectedCols = clampIntegerValue(\n values.cols,\n visibleColsDimension\n );\n let pendingCellClickButton: HTMLButtonElement | null = null;\n\n const syncSelection = (rows: number, cols: number) => {\n selectedRows = rows;\n selectedCols = cols;\n values.rows = String(rows);\n values.cols = String(cols);\n statusElement.textContent = `${rows} x ${cols}`;\n gridButtons.forEach((button) => {\n const buttonRows = Number.parseInt(button.dataset.rows ?? '0', 10);\n const buttonCols = Number.parseInt(button.dataset.cols ?? '0', 10);\n\n button.dataset.active = String(buttonRows <= rows && buttonCols <= cols);\n });\n };\n const getGridButtonFromPoint = (event: PointerEvent) => (\n document.elementFromPoint(event.clientX, event.clientY)\n ?.closest<HTMLButtonElement>('.bridgerte__payload-panel-table-cell') ?? null\n );\n const syncSelectionFromButton = (button: HTMLButtonElement | null) => {\n if (!button) return;\n\n const rows = clampIntegerValue(\n button.dataset.rows,\n visibleRowsDimension\n );\n const cols = clampIntegerValue(\n button.dataset.cols,\n visibleColsDimension\n );\n\n syncSelection(rows, cols);\n };\n const submitSelection = () => {\n onSubmit({\n ...values,\n rows: String(selectedRows),\n cols: String(selectedCols)\n });\n };\n const clearPendingCellClickButton = () => {\n pendingCellClickButton = null;\n };\n const clearPendingCellClickButtonSoon = () => {\n window.setTimeout(clearPendingCellClickButton, 0);\n };\n const handleCellClick = (\n event: MouseEvent,\n cellButton: HTMLButtonElement\n ) => {\n /*\n * H5 toolbar 会在 pointerup 打开面板,浏览器随后可能补发一次 click,\n * 目标会重新命中新出现的网格。表格网格必须确认 click 来自 cell 自己的\n * pointerdown;键盘和测试里的 detail 0 click 仍保留原生 button 语义。\n */\n if (event.detail > 0 && pendingCellClickButton !== cellButton) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n clearPendingCellClickButton();\n syncSelectionFromButton(cellButton);\n submitSelection();\n };\n for (let rowIndex = 1; rowIndex <= visibleRows; rowIndex += 1) {\n for (let colIndex = 1; colIndex <= visibleCols; colIndex += 1) {\n const cellButton = document.createElement('button');\n\n cellButton.type = 'button';\n cellButton.className = 'bridgerte__payload-panel-table-cell';\n cellButton.dataset.rows = String(rowIndex);\n cellButton.dataset.cols = String(colIndex);\n cellButton.setAttribute('aria-label', `插入 ${rowIndex} 行 ${colIndex} 列表格`);\n bindTouchPressedState(cellButton);\n cellButton.addEventListener('pointerdown', (event) => {\n pendingCellClickButton = cellButton;\n syncSelectionFromButton(cellButton);\n event.preventDefault();\n });\n cellButton.addEventListener('pointerup', clearPendingCellClickButtonSoon);\n cellButton.addEventListener('pointercancel', clearPendingCellClickButton);\n cellButton.addEventListener('click', (event) => {\n handleCellClick(event, cellButton);\n });\n if (shouldUseHoverPreview) {\n cellButton.addEventListener('pointerenter', () => {\n syncSelectionFromButton(cellButton);\n });\n }\n gridButtons.push(cellButton);\n gridElement.append(cellButton);\n }\n }\n\n fieldElement.className = 'bridgerte__payload-panel-field';\n gridElement.className = 'bridgerte__payload-panel-table-grid';\n gridElement.setAttribute('aria-label', '选择表格行列');\n gridElement.style.setProperty(\n '--bridgerte-payload-panel-table-cols',\n String(visibleCols)\n );\n statusElement.className = 'bridgerte__payload-panel-table-status';\n statusElement.setAttribute('aria-live', 'polite');\n\n gridElement.addEventListener('pointermove', (event) => {\n if (shouldUseHoverPreview) return;\n\n syncSelectionFromButton(getGridButtonFromPoint(event));\n });\n syncSelection(selectedRows, selectedCols);\n fieldElement.append(gridElement, statusElement);\n\n return fieldElement;\n};\n","import type {\n EditorCommand,\n PayloadPanelOpenRequest,\n PayloadPanelRequest,\n PayloadPanelValues\n} from '@bridgerte/core';\nimport { createRichTextDialog } from '../dialog';\nimport { bindTouchPressedState } from '../interactionState';\nimport { mergePayloadValuesIntoCommand } from './command';\nimport { renderPayloadPanelField } from './fieldRenderer';\nimport {\n createPanelTitleElement,\n focusFirstEditableInput,\n getDialogWidth,\n getInitialFieldValue,\n hasManualSubmitField\n} from './layout';\nimport {\n getTableGridDialogWidth,\n renderTableGridField,\n resolveTableGridDimensions\n} from './tableGrid';\nimport type {\n PayloadPanelController,\n PayloadPanelControllerOptions\n} from './type';\n\nexport type * from './type';\n\nconst payloadPanelIdPrefix = 'bridgerte-payload-panel';\nlet payloadPanelIdSeed = 0;\n\nconst createRequestId = () => {\n payloadPanelIdSeed += 1;\n\n return `${payloadPanelIdPrefix}-${payloadPanelIdSeed}`;\n};\n\nconst isTableInsertPanel = (request: PayloadPanelOpenRequest) => request.panel.id === 'table-insert';\n\nconst createPanelSubmitButton = (\n values: PayloadPanelValues,\n onSubmit: (values: PayloadPanelValues) => void\n) => {\n const submitButton = document.createElement('button');\n\n submitButton.type = 'button';\n submitButton.className = 'bridgerte__payload-panel-submit';\n submitButton.textContent = '应用';\n bindTouchPressedState(submitButton);\n submitButton.addEventListener('pointerdown', (event) => {\n // 应用按钮不能抢走编辑区 selection;controller 会在真正执行命令前恢复焦点。\n event.preventDefault();\n });\n submitButton.addEventListener('click', () => {\n onSubmit(values);\n });\n\n return submitButton;\n};\n\n/**\n * 创建 DOM 默认参数面板控制器。\n *\n * 控制器只负责 request 生命周期:把 schema 渲染成默认 DOM 表单,或把 request 交给\n * 业务自绘层;字段渲染和命令合成分别由同领域小模块处理,避免参数面板继续长成大文件。\n */\nexport const createPayloadPanelController = (\n options: PayloadPanelControllerOptions\n): PayloadPanelController => {\n let activeRequest: PayloadPanelRequest | null = null;\n let values: PayloadPanelValues = {};\n\n const dialog = createRichTextDialog({\n root: options.editorRoot,\n className: 'bridgerte__payload-panel',\n onBackdropClick: () => {\n close();\n }\n });\n\n function close() {\n activeRequest = null;\n values = {};\n dialog.close();\n dialog.content.replaceChildren();\n }\n\n const submit = (nextValues: PayloadPanelValues) => {\n /*\n * readonly 是 request 创建时传给宿主的协议快照。即使宿主稍后才调用 submit,\n * 只要当时或当前处于 readonly,都不能把参数合成为真实编辑命令。\n */\n if (!activeRequest || activeRequest.readonly || options.isReadonly()) return;\n\n const command = mergePayloadValuesIntoCommand(activeRequest.command, nextValues);\n\n if (!command) return;\n\n options.restoreEditorFocus?.(() => {\n close();\n /*\n * text/number 输入框会临时拿走焦点。Lexical 的 focus/selection 恢复不是同步完成,\n * 所以命令必须在 focus 回调里执行,避免表格、链接、媒体等需要当前 selection 的命令变成 no-op。\n */\n if (!options.isReadonly()) {\n options.executeCommand(command);\n }\n });\n };\n\n const clear = (command: EditorCommand) => {\n if (!activeRequest || activeRequest.readonly || options.isReadonly()) return;\n\n options.restoreEditorFocus?.(() => {\n close();\n if (!options.isReadonly()) {\n options.executeCommand(command);\n }\n });\n };\n\n const mountDefaultPanel = (request: PayloadPanelOpenRequest) => {\n values = request.panel.fields.reduce<PayloadPanelValues>((nextValues, field) => {\n nextValues[field.name] = getInitialFieldValue(field, request.currentValues);\n\n return nextValues;\n }, {});\n\n /*\n * table-insert 默认网格尺寸来自 rows/cols schema,需要在渲染前同步用于 dialog 宽度;\n * 其他面板继续使用固定宽度表,保持已有输入型和候选型面板的兼容布局。\n */\n const dialogWidth = isTableInsertPanel(request)\n ? getTableGridDialogWidth(resolveTableGridDimensions(request.panel.fields))\n : getDialogWidth(request.panel.id);\n\n dialog.element.style.width = `min(${dialogWidth}, calc(100vw - 24px))`;\n dialog.content.append(createPanelTitleElement(request, clear, options.getClearCommand));\n /*\n * 表格插入仍复用 rows/cols number schema 给自绘和原生端读取;DOM 默认 UI 使用网格选择,\n * 避免库内置高频结构操作出现数字输入框,后续其他面板仍按字段类型兼容渲染。\n */\n if (isTableInsertPanel(request)) {\n dialog.content.append(renderTableGridField({\n fields: request.panel.fields,\n values,\n onSubmit: submit\n }));\n } else {\n request.panel.fields.forEach((field) => {\n dialog.content.append(renderPayloadPanelField({\n field,\n values,\n onSubmit: submit\n }));\n });\n }\n if (!isTableInsertPanel(request) && hasManualSubmitField(request.panel.fields)) {\n dialog.content.append(createPanelSubmitButton(values, submit));\n }\n dialog.open(request.anchorRect);\n if (!isTableInsertPanel(request) && hasManualSubmitField(request.panel.fields)) {\n focusFirstEditableInput(dialog.content);\n }\n };\n\n const open = (request: PayloadPanelOpenRequest) => {\n close();\n\n const nextRequest: PayloadPanelRequest = {\n ...request,\n id: createRequestId(),\n readonly: options.isReadonly(),\n submit,\n cancel: close\n };\n activeRequest = nextRequest;\n const isHandledByHost = options.onRequest?.(nextRequest) === true;\n\n // 宿主接管时不挂载默认 DOM 面板,避免内置 UI 和业务自绘同时出现。\n if (isHandledByHost) return;\n\n /*\n * readonly 下仍然把 request 发给业务/RN/Flutter/WebView,方便宿主展示只读态面板;\n * 但 DOM 默认面板不打开,且 submit/clear 会被上面的 readonly 防线拦截。\n */\n if (nextRequest.readonly) {\n close();\n return;\n }\n\n mountDefaultPanel(request);\n };\n\n return {\n open,\n close,\n destroy() {\n close();\n dialog.destroy();\n }\n };\n};\n","import { $getNodeByKey, type NodeKey } from 'lexical';\nimport {\n $isTableCellNode,\n $isTableRowNode,\n TableNode,\n type TableCellNode\n} from '@lexical/table';\nimport {\n defaultMenuSchema,\n tableHeaderMenuItems\n} from '@bridgerte/native-spec';\nimport type { MenuItem } from '@bridgerte/native-spec';\nimport type { EditorCommand } from '@bridgerte/core';\nimport {\n cancelFrame,\n scheduleFrame\n} from '../domScheduler';\nimport { bindTouchPressedState } from '../interactionState';\nimport type { ClearInteractionPressedState } from '../interactionState';\nimport type { TableHeaderController, TableHeaderControllerOptions } from './type';\n\nexport type * from './type';\n\nconst tableControlsButtonClassName = 'bridgerte__table-controls-button';\n\nconst tableControlsMenuItemIds = [\n 'table-insert-row-after',\n 'table-delete-row',\n 'table-insert-column-after',\n 'table-delete-column',\n 'table-delete'\n] as const;\n\nconst createTableControlsMenuItems = () => {\n const schemaItemById = new Map(defaultMenuSchema.map((item) => [item.id, item]));\n\n /*\n * 表格 controls 的默认按钮来自 native-spec 菜单全集,避免控制层私有化 command/label。\n * 如果业务后续改菜单文案或图标,只要保留 id,就能继续复用同一份协议。\n */\n return tableControlsMenuItemIds\n .map((id) => tableHeaderMenuItems.find((item) => item.id === id) ?? schemaItemById.get(id))\n .filter((item): item is NonNullable<typeof item> => item !== undefined);\n};\n\nconst tableControlsActions = createTableControlsMenuItems();\nconst tableControlsActionById = new Map<string, MenuItem>(\n /*\n * Controls 按钮用 MenuItem.id 查完整 command,同类命令的不同 payload 不能用 command.type 合并。\n * 后续加入插入前/后、合并/拆分等表格菜单时,只要 id 稳定,就不会互相覆盖。\n */\n tableControlsActions.map((item) => [item.id, item])\n);\n\nconst getTableElementFromNodeElement = (nodeElement: HTMLElement) => (\n nodeElement.matches('.bridgerte__table')\n ? nodeElement\n : nodeElement.querySelector<HTMLElement>('.bridgerte__table') ?? nodeElement\n);\n\nconst getTableWrapperElement = (nodeElement: HTMLElement, tableElement: HTMLElement) => {\n if (nodeElement.classList.contains('bridgerte__table-wrapper')) return nodeElement;\n if (tableElement.parentElement instanceof HTMLElement) return tableElement.parentElement;\n\n return tableElement;\n};\n\nconst getTableScrollContainer = (root: HTMLElement) => (\n root.querySelector<HTMLElement>('.bridgerte__content') ?? root\n);\n\nconst getTableElementFromTarget = (target: EventTarget | null) => (\n target instanceof Element ? target.closest<HTMLElement>('.bridgerte__table-wrapper') : null\n);\n\nconst findFirstTableCell = (tableNode: TableNode): TableCellNode | null => {\n const firstRow = tableNode.getFirstChild();\n if (!$isTableRowNode(firstRow)) return null;\n\n const firstCell = firstRow.getFirstChild();\n\n return $isTableCellNode(firstCell) ? firstCell : null;\n};\n\nconst createTableControlsButton = (item: MenuItem) => {\n const button = document.createElement('button');\n\n button.type = 'button';\n button.className = tableControlsButtonClassName;\n button.textContent = item.label;\n button.dataset.menuItemId = item.id;\n button.setAttribute('aria-label', item.label);\n\n return button;\n};\n\nconst createTableControls = () => {\n const control = document.createElement('div');\n\n control.className = 'bridgerte__table-controls';\n control.contentEditable = 'false';\n control.setAttribute('aria-label', '表格操作');\n\n tableControlsActions.forEach((item) => {\n control.append(createTableControlsButton(item));\n });\n\n return control;\n};\n\n/**\n * 创建表格选中控制层。\n *\n * Controls 放在编辑器 root overlay layer 中,不进入 Lexical table DOM 和 contenteditable\n * 正文树;只有当前点中或聚焦的表格显示浮条。点击操作前先把 selection 放回目标表格\n * 首个单元格,再复用 `EditorCommand` 执行器,保证表格菜单行为和 toolbar/API 保持同源。\n */\nexport const createTableHeaderController = (\n options: TableHeaderControllerOptions\n): TableHeaderController => {\n const layer = document.createElement('div');\n const scrollContainer = getTableScrollContainer(options.root);\n const controls = new Map<NodeKey, HTMLElement>();\n const clearPressedStates = new Map<HTMLElement, ClearInteractionPressedState>();\n const tableElementKeys = new Map<HTMLElement, NodeKey>();\n let syncFrame: number | null = null;\n let touchStartButton: HTMLButtonElement | null = null;\n let shouldSuppressNextClick = false;\n let activeTableKey: NodeKey | null = null;\n\n const positionControl = (\n control: HTMLElement,\n tableWrapperElement: HTMLElement\n ) => {\n const rootRect = options.root.getBoundingClientRect();\n const wrapperRect = tableWrapperElement.getBoundingClientRect();\n const isOutsideRoot = wrapperRect.bottom < rootRect.top || wrapperRect.top > rootRect.bottom;\n const maxX = Math.max(\n 8,\n rootRect.width - control.offsetWidth - 8\n );\n const nextX = Math.min(\n Math.max(wrapperRect.left - rootRect.left + 8, 8),\n maxX\n );\n const nextY = Math.max(8, wrapperRect.top - rootRect.top - control.offsetHeight - 8);\n\n control.hidden = isOutsideRoot;\n control.style.transform = `translate(${nextX}px, ${nextY}px)`;\n };\n\n const shouldShowControl = (nodeKey: NodeKey) => activeTableKey === nodeKey;\n\n const syncControl = (nodeKey: NodeKey) => {\n const nodeElement = options.editor.getElementByKey(nodeKey);\n\n if (!nodeElement) {\n removeControl(nodeKey);\n return;\n }\n\n nodeElement.dataset.lexicalKey = nodeKey;\n const tableElement = getTableElementFromNodeElement(nodeElement);\n const tableWrapperElement = getTableWrapperElement(nodeElement, tableElement);\n tableElementKeys.set(tableWrapperElement, nodeKey);\n const existingControl = controls.get(nodeKey);\n\n if (!shouldShowControl(nodeKey)) {\n removeControl(nodeKey);\n return;\n }\n\n if (existingControl) {\n positionControl(existingControl, tableWrapperElement);\n return;\n }\n\n const control = createTableControls();\n const clearPressedState = bindTouchPressedState(control, {\n targetSelector: `.${tableControlsButtonClassName}`\n });\n\n control.dataset.lexicalKey = nodeKey;\n controls.set(nodeKey, control);\n clearPressedStates.set(control, clearPressedState);\n layer.append(control);\n positionControl(control, tableWrapperElement);\n };\n\n const removeControl = (nodeKey: NodeKey) => {\n const control = controls.get(nodeKey);\n\n if (!control) return;\n\n clearPressedStates.get(control)?.();\n clearPressedStates.delete(control);\n control.remove();\n controls.delete(nodeKey);\n if (activeTableKey === nodeKey) activeTableKey = null;\n };\n\n const syncAllControls = () => {\n syncFrame = null;\n tableElementKeys.forEach((nodeKey, tableWrapperElement) => {\n if (!options.root.contains(tableWrapperElement)) {\n tableElementKeys.delete(tableWrapperElement);\n removeControl(nodeKey);\n }\n });\n options.root.querySelectorAll<HTMLElement>('.bridgerte__table-wrapper').forEach((element) => {\n const nodeKey = element.dataset.lexicalKey as NodeKey | undefined;\n\n if (nodeKey) {\n tableElementKeys.set(element, nodeKey);\n syncControl(nodeKey);\n }\n });\n controls.forEach((_, nodeKey) => {\n syncControl(nodeKey);\n });\n if (activeTableKey !== null) syncControl(activeTableKey);\n };\n\n const scheduleSyncAllControls = () => {\n if (syncFrame !== null) return;\n\n // 位置同步只读 table wrapper rect 并写 transform,放到下一帧避免和 Lexical reconcile 抢布局。\n syncFrame = scheduleFrame(syncAllControls);\n };\n\n const selectTableFirstCell = (nodeKey: NodeKey) => {\n options.editor.update(() => {\n const node = $getNodeByKey(nodeKey);\n\n if (!(node instanceof TableNode)) return;\n\n findFirstTableCell(node)?.selectStart();\n });\n options.editor.focus();\n };\n\n const executeTableCommand = (nodeKey: NodeKey, command: EditorCommand) => {\n selectTableFirstCell(nodeKey);\n options.executeCommand(command);\n };\n\n const executeButton = (button: HTMLButtonElement, control: HTMLElement) => {\n const nodeKey = control.dataset.lexicalKey;\n const itemId = button.dataset.menuItemId;\n const item = itemId ? tableControlsActionById.get(itemId) : undefined;\n\n if (!nodeKey || !item) return;\n\n executeTableCommand(nodeKey, item.command);\n };\n\n const activateTableElement = (tableElement: HTMLElement | null) => {\n if (!tableElement) {\n const previousActiveKey = activeTableKey;\n\n activeTableKey = null;\n if (previousActiveKey !== null) syncControl(previousActiveKey);\n return;\n }\n\n const nextActiveKey = tableElement.dataset.lexicalKey\n ? (tableElement.dataset.lexicalKey as NodeKey)\n : tableElementKeys.get(tableElement) ?? null;\n\n if (!nextActiveKey || activeTableKey === nextActiveKey) return;\n\n const previousActiveKey = activeTableKey;\n\n activeTableKey = nextActiveKey;\n if (previousActiveKey !== null) syncControl(previousActiveKey);\n syncControl(nextActiveKey);\n };\n\n const handleContentPointerDown = (event: PointerEvent) => {\n /*\n * 表格 controls 和媒体 controls 保持同一交互:只跟随当前操作的块级节点。\n * 这样大文档不会常驻大量按钮,H5 也不依赖 hover 才能唤出操作入口。\n */\n activateTableElement(getTableElementFromTarget(event.target));\n };\n\n const handleContentFocusIn = (event: FocusEvent) => {\n activateTableElement(getTableElementFromTarget(event.target));\n };\n\n const handlePointerDown = (event: PointerEvent) => {\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) return;\n\n const button = target.closest<HTMLButtonElement>(`.${tableControlsButtonClassName}`);\n\n if (!button) return;\n\n event.preventDefault();\n touchStartButton = event.pointerType === 'mouse' ? null : button;\n };\n\n const handlePointerUp = (event: PointerEvent) => {\n if (event.pointerType === 'mouse' || !touchStartButton) return;\n\n const target = event.target;\n const control = target instanceof HTMLElement\n ? target.closest<HTMLElement>('.bridgerte__table-controls')\n : null;\n const button = target instanceof HTMLElement\n ? target.closest<HTMLButtonElement>(`.${tableControlsButtonClassName}`)\n : null;\n\n if (button === touchStartButton && control) {\n event.preventDefault();\n event.stopPropagation();\n executeButton(button, control);\n shouldSuppressNextClick = true;\n }\n touchStartButton = null;\n };\n\n const clearTouchStartButton = () => {\n touchStartButton = null;\n };\n\n const handleClick = (event: MouseEvent) => {\n if (shouldSuppressNextClick) {\n shouldSuppressNextClick = false;\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n const target = event.target;\n\n if (!(target instanceof HTMLElement)) return;\n\n const button = target.closest<HTMLButtonElement>(`.${tableControlsButtonClassName}`);\n const control = target.closest<HTMLElement>('.bridgerte__table-controls');\n\n if (!button || !control) return;\n\n event.preventDefault();\n event.stopPropagation();\n executeButton(button, control);\n };\n\n const unregisterMutationListener = options.editor.registerMutationListener(\n TableNode,\n (mutations) => {\n mutations.forEach((mutation, nodeKey) => {\n if (mutation === 'destroyed') {\n removeControl(nodeKey);\n return;\n }\n\n syncControl(nodeKey);\n });\n }\n );\n\n const unregisterUpdateListener = options.editor.registerUpdateListener(scheduleSyncAllControls);\n\n layer.className = 'bridgerte__table-controls-layer';\n options.root.append(layer);\n layer.addEventListener('pointerdown', handlePointerDown);\n layer.addEventListener('pointerup', handlePointerUp);\n layer.addEventListener('pointercancel', clearTouchStartButton);\n layer.addEventListener('click', handleClick);\n scrollContainer.addEventListener('pointerdown', handleContentPointerDown);\n scrollContainer.addEventListener('focusin', handleContentFocusIn);\n scrollContainer.addEventListener('scroll', scheduleSyncAllControls, { passive: true });\n window.addEventListener('resize', scheduleSyncAllControls);\n\n return {\n destroy() {\n unregisterMutationListener();\n unregisterUpdateListener();\n if (syncFrame !== null) {\n cancelFrame(syncFrame);\n syncFrame = null;\n }\n layer.removeEventListener('pointerdown', handlePointerDown);\n layer.removeEventListener('pointerup', handlePointerUp);\n layer.removeEventListener('pointercancel', clearTouchStartButton);\n layer.removeEventListener('click', handleClick);\n scrollContainer.removeEventListener('pointerdown', handleContentPointerDown);\n scrollContainer.removeEventListener('focusin', handleContentFocusIn);\n scrollContainer.removeEventListener('scroll', scheduleSyncAllControls);\n window.removeEventListener('resize', scheduleSyncAllControls);\n controls.forEach((control) => {\n clearPressedStates.get(control)?.();\n control.remove();\n });\n controls.clear();\n clearPressedStates.clear();\n tableElementKeys.clear();\n layer.remove();\n }\n };\n};\n","import type {\n RichTextEditorControllerOptions,\n RichTextEditorControllerRuntime,\n RichTextEditorControllers\n} from './type';\nimport { createCodeBlockLanguageController } from '../codeHighlight';\nimport { createMediaControlsController } from '../mediaControls';\nimport { createPayloadPanelController } from '../payloadPanel';\nimport { createTableHeaderController } from '../tableHeader';\n\n/**\n * 创建编辑器内置控制器。\n *\n * payloadPanel、code block 语言 header、表格 header 和媒体控制按钮都属于同一层 DOM\n * 内置能力,统一从这里创建和销毁,避免主文件继续累积“工具栏之外的 UI 编排”。\n */\nexport const createRichTextEditorControllers = (\n options: RichTextEditorControllerOptions\n): RichTextEditorControllerRuntime & RichTextEditorControllers => {\n const payloadPanelController = createPayloadPanelController({\n editorRoot: options.editorRoot,\n isReadonly: options.isReadonly,\n restoreEditorFocus: options.restoreEditorFocus,\n executeCommand: options.executeCommand,\n getClearCommand: options.getClearCommand,\n onRequest: options.onRequest\n });\n const codeBlockController = createCodeBlockLanguageController({\n editor: options.lexicalEditor,\n root: options.editorRoot,\n isReadonly: options.isReadonly,\n languagePanel: options.codeBlockLanguagePanel,\n payloadPanelConfig: options.payloadPanelConfig,\n onRequest: options.onRequest\n });\n const tableHeaderController = createTableHeaderController({\n editor: options.lexicalEditor,\n root: options.editorRoot,\n executeCommand: options.executeCommand\n });\n const mediaControlsController = createMediaControlsController({\n editor: options.lexicalEditor,\n root: options.editorRoot,\n defaultWidthPercent: options.defaultMediaWidthPercent,\n executeCommand: options.executeCommand,\n mediaControlsConfig: options.mediaControlsConfig,\n menuLabels: options.menuLabels\n });\n\n return {\n payloadPanelController,\n codeBlockController,\n tableHeaderController,\n mediaControlsController,\n destroy() {\n payloadPanelController.destroy();\n codeBlockController.destroy();\n tableHeaderController.destroy();\n mediaControlsController.destroy();\n }\n };\n};\n","import type { RichTextEditorDomElements, RichTextEditorDomOptions } from './type';\n\n/**\n * 创建并挂载编辑器根 DOM。\n *\n * 这个模块只负责静态容器结构,不碰 Lexical 和命令逻辑;把 DOM 初始化从主编辑器\n * 文件拆出来后,`index.ts` 只保留生命周期编排和业务接线。\n */\nexport const createRichTextEditorDom = (\n container: HTMLElement,\n options: RichTextEditorDomOptions\n): RichTextEditorDomElements => {\n const rootElement = document.createElement('div');\n const editorElement = document.createElement('div');\n const toolbarElement = document.createElement('div');\n const contentElement = document.createElement('div');\n\n container.classList.add('bridgerte');\n container.textContent = '';\n rootElement.className = 'bridgerte__editor';\n contentElement.className = 'bridgerte__content';\n contentElement.dataset.placeholder = options.placeholder;\n contentElement.setAttribute('role', 'textbox');\n contentElement.setAttribute('aria-multiline', 'true');\n editorElement.append(contentElement);\n if (options.shouldRenderToolbar && options.toolbarPlacement === 'top') {\n rootElement.append(toolbarElement);\n }\n rootElement.append(editorElement);\n if (options.shouldRenderToolbar && options.toolbarPlacement === 'bottom') {\n rootElement.append(toolbarElement);\n }\n container.append(rootElement);\n\n return {\n rootElement,\n editorElement,\n toolbarElement,\n contentElement\n };\n};\n","import {\n $getSelection,\n $setSelection\n} from 'lexical';\nimport type {\n PayloadPanelSelectionStore,\n PayloadPanelSelectionStoreOptions,\n StoredPayloadPanelSelection\n} from './type';\n\n/**\n * 保存参数面板打开前的 Lexical selection。\n *\n * text/number 输入型面板会把浏览器焦点移到 input 上,如果提交时只调用 editor.focus(),\n * 表格、链接、媒体这类依赖 selection 的命令可能找不到原位置。这里把 selection 克隆出来,\n * 提交前再恢复,payloadPanel 自身不需要理解 Lexical 内核。\n */\nexport const createPayloadPanelSelectionStore = ({\n editor\n}: PayloadPanelSelectionStoreOptions): PayloadPanelSelectionStore => {\n let selection: StoredPayloadPanelSelection = null;\n\n return {\n capture() {\n editor.getEditorState().read(() => {\n selection = $getSelection()?.clone() ?? null;\n });\n },\n restore() {\n if (!selection) return;\n\n editor.update(() => {\n $setSelection(selection?.clone() ?? null);\n });\n },\n clear() {\n selection = null;\n }\n };\n};\n","import { createLinkMatcherWithRegExp, registerAutoLink } from '@lexical/link';\nimport type { BridgeAutoLinkConfig, RegisterBridgeAutoLinkOptions } from './type';\n\nexport type * from './type';\n\nconst urlMatchRegExp = /((https?:\\/\\/|www\\.)[^\\s<>()]+[^\\s<>().,;:!?])/i;\nconst emailMatchRegExp = /([A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,})/i;\n\n/*\n * 自动链接只做高置信度识别:显式协议、www 前缀和邮箱。\n * 更激进的裸域名识别容易把普通文本、文件名和命令参数误包成链接,后续可通过配置扩展。\n */\nexport const bridgeAutoLinkConfig: BridgeAutoLinkConfig = {\n changeHandlers: [],\n excludeParents: [],\n matchers: [\n createLinkMatcherWithRegExp(urlMatchRegExp, (text) => (\n text.startsWith('http://') || text.startsWith('https://')\n ? text\n : `https://${text}`\n )),\n createLinkMatcherWithRegExp(emailMatchRegExp, (text) => `mailto:${text}`)\n ]\n};\n\n/**\n * 注册 BridgeRTE 默认自动识别链接能力。\n *\n * DOM 内核只注册 matcher,不改变手动 link.set 的优先级;Lexical 会跳过已经处在\n * LinkNode/AutoLinkNode 内的文本,避免重复包裹。\n */\nexport const registerBridgeAutoLink = ({\n editor\n}: RegisterBridgeAutoLinkOptions): (() => void) => (\n registerAutoLink(editor, bridgeAutoLinkConfig)\n);\n","import type { ClipboardCopyOptions } from './type';\n\nexport type * from './type';\n\nconst internalClipboardSelector = [\n '.bridgerte__code-header',\n '.bridgerte__code-block-control',\n '.bridgerte__code-block-controls-layer',\n '.bridgerte__code-block-menu',\n '.bridgerte__table-controls-layer',\n '.bridgerte__table-controls',\n '.bridgerte__media-controls-layer',\n '.bridgerte__media-controls',\n '.bridgerte__dialog-backdrop',\n '.bridgerte__dialog',\n '.bridgerte__payload-panel'\n].join(',');\n\nconst isSelectionInsideTarget = (selection: Selection, target: HTMLElement) => {\n const anchorNode = selection.anchorNode;\n const focusNode = selection.focusNode;\n\n return anchorNode !== null\n && focusNode !== null\n && target.contains(anchorNode)\n && target.contains(focusNode);\n};\n\nconst removeInternalClipboardNodes = (root: DocumentFragment | HTMLElement) => {\n root.querySelectorAll(internalClipboardSelector).forEach((element) => {\n element.remove();\n });\n root.querySelectorAll('[contenteditable=\"false\"]').forEach((element) => {\n if (element.classList.contains('bridgerte__media')) return;\n\n element.remove();\n });\n};\n\nconst getClipboardHtmlAndText = (target: HTMLElement) => {\n const selection = target.ownerDocument.getSelection();\n\n if (!selection || selection.rangeCount === 0 || !isSelectionInsideTarget(selection, target)) {\n return null;\n }\n\n const fragment = selection.getRangeAt(0).cloneContents();\n\n /*\n * 复制输出只保留真实内容节点。代码块 header、表格 controls、媒体 controls 和 dialog\n * 都是 DOM 内置控制层,不能出现在用户复制给外部应用的 HTML 或 plainText 里。\n */\n removeInternalClipboardNodes(fragment);\n const wrapper = target.ownerDocument.createElement('div');\n\n wrapper.append(fragment);\n\n return {\n html: wrapper.innerHTML,\n text: wrapper.textContent ?? ''\n };\n};\n\n/**\n * 注册 BridgeRTE 复制输出稳定器。\n *\n * 浏览器原生 copy 会把当前选区 DOM 直接写入剪贴板;BridgeRTE 需要先剥离内部 controls,\n * 再同时写入 text/html 和 text/plain,保证复制到外部应用时只包含编辑内容。\n */\nexport const registerClipboardCopy = ({\n target,\n isReadonly\n}: ClipboardCopyOptions): (() => void) => {\n const handleCopy = (event: ClipboardEvent) => {\n const clipboardContent = getClipboardHtmlAndText(target);\n\n if (!clipboardContent || !event.clipboardData) return;\n\n event.clipboardData.setData('text/html', clipboardContent.html);\n event.clipboardData.setData('text/plain', clipboardContent.text);\n event.preventDefault();\n event.stopImmediatePropagation();\n };\n\n const handleCut = (event: ClipboardEvent) => {\n if (isReadonly()) {\n handleCopy(event);\n return;\n }\n\n handleCopy(event);\n };\n\n target.addEventListener('copy', handleCopy, { capture: true });\n target.addEventListener('cut', handleCut, { capture: true });\n\n return () => {\n target.removeEventListener('copy', handleCopy, { capture: true });\n target.removeEventListener('cut', handleCut, { capture: true });\n };\n};\n","import {\n autoUpdate,\n computePosition,\n flip,\n offset,\n platform,\n shift,\n type Placement,\n type Strategy\n} from '@floating-ui/dom';\nimport type { RichTextFloatingLayer, RichTextFloatingLayerOptions } from './type';\n\nexport type * from './type';\n\nconst floatingViewportPadding = 8;\n\nconst getVisibleViewportRect = () => {\n const visualViewport = window.visualViewport;\n\n /*\n * H5 键盘弹起时布局视口和可见视口会分离。浮层最终位置要按 visualViewport\n * 再夹一次,避免候选菜单被键盘盖住;不支持 visualViewport 时回退传统视口。\n */\n return {\n left: visualViewport?.offsetLeft ?? 0,\n top: visualViewport?.offsetTop ?? 0,\n width: visualViewport?.width ?? window.innerWidth,\n height: visualViewport?.height ?? window.innerHeight\n };\n};\n\nconst clampCoordinate = (value: number, min: number, max: number) => (\n Math.min(Math.max(value, min), Math.max(min, max))\n);\n\n/**\n * 统一浮层定位能力。\n *\n * hoverbar、mention 和 slash menu 都从这里复用定位、翻转、键盘可视区和边界避让逻辑。\n */\nexport function createFloatingLayer(\n reference: HTMLElement,\n floating: HTMLElement,\n options: RichTextFloatingLayerOptions = {}\n): RichTextFloatingLayer {\n const placement = options.placement ?? 'bottom-start';\n const offsetValue = options.offset ?? 8;\n const shiftPadding = options.shiftPadding ?? 8;\n const strategy = options.strategy ?? 'absolute';\n let cleanupAutoUpdate: (() => void) | null = null;\n let open = false;\n\n const prepareFloatingElement = () => {\n /*\n * 打开浮层前必须先脱离文档流。否则 `hidden=false` 到 async 定位完成之间,\n * 菜单会短暂按普通 div 参与布局,把富文本内容向下顶一下。\n */\n floating.style.position = strategy;\n floating.style.left = '0px';\n floating.style.top = '0px';\n floating.style.opacity = '0';\n floating.style.pointerEvents = 'none';\n };\n\n const applyPosition = (x: number, y: number) => {\n const viewportRect = getVisibleViewportRect();\n const floatingRect = floating.getBoundingClientRect();\n const minLeft = viewportRect.left + floatingViewportPadding;\n const minTop = viewportRect.top + floatingViewportPadding;\n const maxLeft = viewportRect.left + viewportRect.width\n - floatingRect.width - floatingViewportPadding;\n const maxTop = viewportRect.top + viewportRect.height\n - floatingRect.height - floatingViewportPadding;\n\n floating.style.left = `${clampCoordinate(x, minLeft, maxLeft)}px`;\n floating.style.top = `${clampCoordinate(y, minTop, maxTop)}px`;\n floating.style.opacity = '';\n floating.style.pointerEvents = '';\n };\n\n const update = async () => {\n /*\n * 所有轻浮层统一经过 floating-ui 计算初始位置;随后按 visualViewport 再做一次\n * clamp,覆盖 H5 键盘弹起后 floating-ui 仍可能按布局视口计算的场景。\n */\n const position = await computePosition(reference, floating, {\n placement: placement as Placement,\n strategy: strategy as Strategy,\n platform,\n middleware: [\n offset(offsetValue),\n flip(),\n shift({ padding: shiftPadding })\n ]\n });\n\n applyPosition(position.x, position.y);\n };\n\n const stopAutoUpdate = () => {\n cleanupAutoUpdate?.();\n cleanupAutoUpdate = null;\n };\n\n const setOpen = (nextOpen: boolean) => {\n if (open === nextOpen) return;\n\n open = nextOpen;\n stopAutoUpdate();\n\n if (open) {\n prepareFloatingElement();\n floating.hidden = false;\n // 只有打开时才启动 autoUpdate,避免隐藏浮层继续注册 resize/scroll/observer 影响输入性能。\n cleanupAutoUpdate = autoUpdate(reference, floating, update);\n void update();\n return;\n }\n\n floating.hidden = true;\n floating.style.opacity = '';\n floating.style.pointerEvents = '';\n };\n\n prepareFloatingElement();\n floating.hidden = true;\n\n return {\n update,\n setOpen,\n destroy() {\n stopAutoUpdate();\n floating.hidden = true;\n }\n };\n}\n","/**\n * 读取浏览器当前 selection 的可视 rect。\n *\n * hoverbar、slash、mention 和未来其他 selection 锚点浮层都需要这个结果;独立成模块后,\n * 不用在每个领域里重复处理“没有 range”或“零尺寸 rect”的边界。\n */\nexport const getBrowserSelectionRect = (): DOMRect | null => {\n const selection = window.getSelection();\n const range = selection?.rangeCount ? selection.getRangeAt(0) : null;\n const rect = range?.getBoundingClientRect();\n\n if (!rect || (rect.width === 0 && rect.height === 0)) return null;\n\n return rect;\n};\n","import {\n defaultMenuSchema,\n resolveToolbarMenu,\n type MenuItem,\n type ResolvedToolbarItem\n} from '@bridgerte/native-spec';\nimport type {\n CommandState,\n ToolbarConfig\n} from '@bridgerte/core';\nimport {\n $getSelection,\n $isRangeSelection,\n COMMAND_PRIORITY_LOW,\n KEY_ESCAPE_COMMAND,\n SELECTION_CHANGE_COMMAND\n} from 'lexical';\nimport { createFloatingLayer, type RichTextFloatingLayer } from '../floatingLayer';\nimport { bindTouchPressedState } from '../interactionState';\nimport {\n appendMenuIcon,\n defaultMenuIcons\n} from '../menuIcon';\nimport {\n getMenuStateForItem,\n getPayloadPanelCurrentValues,\n resolveMenuSchemaForDom\n} from '../menuRuntime';\nimport { getBrowserSelectionRect } from '../selectionGeometry';\nimport type { HoverbarControllerOptions } from './type';\n\nexport type * from './type';\n\nconst hoverbarOpenDelayMs = 160;\nconst defaultHoverbarConfig: ToolbarConfig = {\n toolbarKeys: [\n 'bold',\n 'italic',\n 'underline',\n 'strike',\n 'inline-code',\n 'clear-style',\n '|',\n 'color',\n 'background-color',\n 'font-size',\n 'font-family',\n 'line-height'\n ]\n};\n\nconst hasExpandedEditorSelection = () => {\n const selection = $getSelection();\n\n return $isRangeSelection(selection) && !selection.isCollapsed();\n};\n\nconst isEventInside = (event: Event, element: HTMLElement) => (\n event.target instanceof Node && element.contains(event.target)\n);\n\nconst getHoverbarButton = (target: EventTarget | null) => (\n target instanceof Element\n ? target.closest<HTMLButtonElement>('.bridgerte__hoverbar-button')\n : null\n);\n\nconst flattenHoverbarItems = (items: ResolvedToolbarItem[]) => items.flatMap((item) => (\n item.type === 'button' ? [item.item]\n : item.type === 'group' ? item.items\n : []\n));\n\nconst renderHoverbarSeparator = (separator: Extract<ResolvedToolbarItem, { type: 'separator' }>) => {\n const element = document.createElement('span');\n\n element.className = 'bridgerte__hoverbar-separator';\n element.dataset.separatorId = separator.key;\n element.setAttribute('aria-hidden', 'true');\n\n return element;\n};\n\nconst renderHoverbarButton = (\n item: MenuItem,\n commandStates: CommandState[],\n icons: NonNullable<HoverbarControllerOptions['icons']>\n) => {\n const state = getMenuStateForItem(item, commandStates);\n const button = document.createElement('button');\n\n button.type = 'button';\n button.className = 'bridgerte__hoverbar-button';\n button.dataset.hoverbarItemId = item.id;\n button.dataset.active = String(state.active);\n button.disabled = state.disabled;\n button.setAttribute('aria-label', item.label);\n button.setAttribute('aria-pressed', String(state.active));\n appendMenuIcon(button, icons[item.icon] ?? defaultMenuIcons[item.icon], item.label);\n\n return button;\n};\n\n/**\n * 注册选中文本 hoverbar。\n *\n * hoverbar 菜单同样走 schema/config/payloadPanel:默认 DOM 只负责浮层和按钮渲染,\n * 具体菜单全集、显示顺序和参数面板都复用 toolbar/native-spec 的稳定协议。\n */\nexport const registerHoverbar = ({\n editorRoot,\n contentElement,\n editor,\n isReadonly,\n executeCommand,\n requestPayloadPanel,\n getCommandStates,\n menuSchema: rawMenuSchema,\n hoverbarConfig,\n menuLabels,\n payloadPanelConfig,\n icons = {}\n}: HoverbarControllerOptions): (() => void) => {\n const menuSchema = resolveMenuSchemaForDom(rawMenuSchema ?? defaultMenuSchema, {\n menuLabels,\n payloadPanelConfig\n });\n const hoverbarItems = resolveToolbarMenu(hoverbarConfig ?? defaultHoverbarConfig, menuSchema);\n const executableMenuItems = flattenHoverbarItems(hoverbarItems);\n const anchor = document.createElement('span');\n const bar = document.createElement('div');\n let floatingLayer: RichTextFloatingLayer | null = null;\n let open = false;\n let openTimer: number | null = null;\n const clearPressedState = bindTouchPressedState(bar, {\n targetSelector: '.bridgerte__hoverbar-button'\n });\n\n anchor.className = 'bridgerte__hoverbar-anchor';\n anchor.setAttribute('aria-hidden', 'true');\n bar.className = 'bridgerte__floating-menu bridgerte__hoverbar';\n bar.setAttribute('role', 'toolbar');\n bar.setAttribute('aria-label', 'BridgeRTE hoverbar');\n editorRoot.append(anchor, bar);\n floatingLayer = createFloatingLayer(anchor, bar, {\n placement: 'top',\n offset: 8,\n strategy: 'fixed'\n });\n\n const clearOpenTimer = () => {\n if (!openTimer) return;\n\n window.clearTimeout(openTimer);\n openTimer = null;\n };\n\n const close = () => {\n clearOpenTimer();\n open = false;\n bar.replaceChildren();\n bar.dataset.visible = 'false';\n floatingLayer?.setOpen(false);\n };\n\n const syncAnchorPosition = () => {\n const rect = getBrowserSelectionRect();\n const fallbackRect = contentElement.getBoundingClientRect();\n\n /*\n * hoverbar 以浏览器真实选区 rect 为锚点;测试环境或 WebView 拿不到 rect 时退回\n * 编辑区顶部,保证命令按钮仍可测、可用,不阻塞后续真实浏览器验收。\n */\n anchor.style.left = `${rect?.left ?? fallbackRect.left}px`;\n anchor.style.top = `${rect?.top ?? fallbackRect.top}px`;\n anchor.style.width = `${rect?.width || 1}px`;\n anchor.style.height = `${rect?.height || 1}px`;\n };\n\n const render = () => {\n const commandStates = getCommandStates();\n\n bar.replaceChildren(...hoverbarItems.flatMap((item) => {\n if (item.type === 'separator') return [renderHoverbarSeparator(item)];\n\n const items = item.type === 'button' ? [item.item] : item.items;\n\n return items.map((menuItem) => renderHoverbarButton(menuItem, commandStates, icons));\n }));\n syncAnchorPosition();\n open = true;\n bar.dataset.visible = 'true';\n floatingLayer?.setOpen(true);\n void floatingLayer?.update();\n };\n\n const canOpenHoverbar = () => {\n if (isReadonly()) {\n return false;\n }\n\n return editor.getEditorState().read(hasExpandedEditorSelection);\n };\n\n const syncSelection = (openImmediately = false) => {\n clearOpenTimer();\n\n if (!canOpenHoverbar()) {\n close();\n return;\n }\n\n /*\n * 用户拖选文本时 selection 会连续变化,hoverbar 立即出现会挡住拖选路径。\n * 默认等 selection 稳定一小段时间再显示;命令执行后的状态刷新可以显式立即渲染。\n */\n if (openImmediately) {\n render();\n return;\n }\n\n if (open) close();\n openTimer = window.setTimeout(() => {\n openTimer = null;\n if (canOpenHoverbar()) render();\n }, hoverbarOpenDelayMs);\n };\n\n const executeHoverbarButton = (button: HTMLButtonElement) => {\n const item = executableMenuItems.find((hoverbarItem) => (\n hoverbarItem.id === button.dataset.hoverbarItemId\n ));\n\n if (!item || button.disabled) return;\n\n if (item.payloadPanel) {\n const buttonRect = button.getBoundingClientRect();\n\n /*\n * hoverbar 的参数菜单和 toolbar 使用同一个 request。这里传按钮 rect 作为锚点,\n * payloadPanel 控制器仍负责自绘接管、readonly 和默认 DOM 面板。\n */\n requestPayloadPanel({\n menuId: item.id,\n command: item.command,\n panel: item.payloadPanel,\n currentValues: getPayloadPanelCurrentValues(item, getCommandStates()),\n anchorRect: {\n x: buttonRect.left,\n y: buttonRect.top,\n width: buttonRect.width,\n height: buttonRect.height\n }\n });\n syncSelection(true);\n return;\n }\n\n executeCommand(item.command);\n syncSelection(true);\n };\n\n const handlePointerDown = (event: PointerEvent) => {\n const button = getHoverbarButton(event.target);\n\n if (!button) return;\n\n /*\n * hoverbar 按钮必须保留当前选区,命令才能作用在刚刚选中的文本;pointerdown 阻止\n * 默认聚焦,避免真实浏览器先把 selection 收掉。\n */\n event.preventDefault();\n };\n\n const handleClick = (event: MouseEvent) => {\n const button = getHoverbarButton(event.target);\n\n if (!button) return;\n\n event.preventDefault();\n executeHoverbarButton(button);\n };\n\n const handleDocumentPointerDown = (event: PointerEvent) => {\n if (!open || isEventInside(event, bar) || isEventInside(event, contentElement)) return;\n\n close();\n };\n\n const unregisterSelection = editor.registerCommand(\n SELECTION_CHANGE_COMMAND,\n () => {\n syncSelection();\n return false;\n },\n COMMAND_PRIORITY_LOW\n );\n const unregisterUpdate = editor.registerUpdateListener(() => {\n syncSelection();\n });\n const unregisterEscape = editor.registerCommand(\n KEY_ESCAPE_COMMAND,\n (event) => {\n if (!open) return false;\n\n event?.preventDefault();\n close();\n return true;\n },\n COMMAND_PRIORITY_LOW\n );\n\n bar.addEventListener('pointerdown', handlePointerDown);\n bar.addEventListener('click', handleClick);\n document.addEventListener('pointerdown', handleDocumentPointerDown, true);\n\n return () => {\n clearOpenTimer();\n unregisterSelection();\n unregisterUpdate();\n unregisterEscape();\n bar.removeEventListener('pointerdown', handlePointerDown);\n bar.removeEventListener('click', handleClick);\n document.removeEventListener('pointerdown', handleDocumentPointerDown, true);\n clearPressedState();\n floatingLayer?.destroy();\n anchor.remove();\n bar.remove();\n };\n};\n","import type { EditorCommand } from '@bridgerte/core';\nimport type { KeyboardShortcutOptions, KeyboardShortcutResolver } from './type';\n\nexport type * from './type';\n\nconst isPrimaryModifier = (event: KeyboardEvent) => event.metaKey || event.ctrlKey;\n\n/*\n * 快捷键只映射到无需额外 payload 的命令;需要参数面板、上传、slash 触发器\n * 或破坏系统默认行为的能力不放进这里,避免绕过统一 panel/request 体系。\n */\nconst primaryOnlyCommandByKey: Partial<Record<string, EditorCommand>> = {\n b: { type: 'format.bold' },\n i: { type: 'format.italic' },\n u: { type: 'format.underline' },\n '\\\\': { type: 'format.clear' }\n};\nconst primaryShiftCommandByKey: Partial<Record<string, EditorCommand>> = {\n x: { type: 'format.strike' },\n l: { type: 'align', value: 'left' },\n e: { type: 'align', value: 'center' },\n r: { type: 'align', value: 'right' },\n j: { type: 'align', value: 'justify' }\n};\nconst primaryAltCommandByDigit: Partial<Record<string, EditorCommand>> = {\n '0': { type: 'block.paragraph' },\n '1': { type: 'block.heading', level: 1 },\n '2': { type: 'block.heading', level: 2 },\n '3': { type: 'block.heading', level: 3 },\n '4': { type: 'block.heading', level: 4 },\n '5': { type: 'block.heading', level: 5 },\n '6': { type: 'block.heading', level: 6 }\n};\n\nexport const resolveBasicKeyboardShortcut: KeyboardShortcutResolver = (event) => {\n const key = event.key.toLowerCase();\n const code = event.code;\n\n if (!event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey) return null;\n\n if (!isPrimaryModifier(event)) return null;\n\n if (event.altKey) {\n if (event.shiftKey) return null;\n if (key === 'c' || code === 'KeyC') return { type: 'block.code' };\n\n const digit = code.startsWith('Digit') ? code.slice('Digit'.length) : key;\n\n return primaryAltCommandByDigit[digit] ?? null;\n }\n\n if (event.shiftKey) {\n if (key === 'z') return { type: 'history.redo' };\n if (key === '.' || key === '>' || code === 'Period') return { type: 'block.quote' };\n if (key === '7' || key === '&' || code === 'Digit7') return { type: 'list.ordered' };\n if (key === '8' || key === '*' || code === 'Digit8') return { type: 'list.unordered' };\n if (key === '9' || key === '(' || code === 'Digit9') return { type: 'list.todo' };\n if (key === '-' || key === '_' || code === 'Minus') return { type: 'block.divider' };\n\n return primaryShiftCommandByKey[key] ?? null;\n }\n\n if (key === 'z') return { type: 'history.undo' };\n if (key === 'y' && event.ctrlKey && !event.metaKey) return { type: 'history.redo' };\n if (key === '`' || key === '~' || code === 'Backquote') return { type: 'format.inlineCode' };\n\n return primaryOnlyCommandByKey[key] ?? null;\n};\n\n/**\n * 在编辑区上注册基础快捷键。\n *\n * 监听挂在 contenteditable 容器上,最终仍调用 `EditorAPI.executeCommand()` 对应的内部执行器;\n * readonly 时直接跳过,避免浏览器快捷键被无意义拦截。\n */\nexport const registerKeyboardShortcuts = ({\n target,\n isReadonly,\n executeCommand\n}: KeyboardShortcutOptions): (() => void) => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (isReadonly()) return;\n\n const command = resolveBasicKeyboardShortcut(event);\n\n if (!command) return;\n\n event.preventDefault();\n executeCommand(command);\n };\n\n target.addEventListener('keydown', handleKeyDown);\n\n return () => {\n target.removeEventListener('keydown', handleKeyDown);\n };\n};\n","/**\n * 浮层菜单内部滚动工具。\n *\n * 原生 `element.scrollIntoView()` 可能向上滚动页面或外层编辑器容器,H5 键盘弹起时还可能\n * 触发浏览器重新聚焦/收键盘。菜单候选只需要滚动自己的浮层容器,所以这里手动计算\n * active item 相对菜单的可见范围,避免影响正文布局和页面滚动。\n */\nexport const scrollFloatingMenuItemIntoView = (\n menu: HTMLElement,\n activeItem: HTMLElement\n) => {\n const itemOffsetTop = activeItem.offsetTop;\n const itemBottom = itemOffsetTop + activeItem.offsetHeight;\n const visibleTop = menu.scrollTop;\n const visibleBottom = visibleTop + menu.clientHeight;\n\n if (itemOffsetTop < visibleTop) {\n menu.scrollTop = itemOffsetTop;\n return;\n }\n\n if (itemBottom > visibleBottom) {\n menu.scrollTop = itemBottom - menu.clientHeight;\n }\n};\n","import {\n COMMAND_PRIORITY_LOW,\n KEY_ARROW_DOWN_COMMAND,\n KEY_ARROW_UP_COMMAND,\n KEY_ENTER_COMMAND,\n KEY_ESCAPE_COMMAND\n} from 'lexical';\nimport { createFloatingLayer } from '../floatingLayer';\nimport { scrollFloatingMenuItemIntoView } from '../floatingMenu';\nimport { bindTouchPressedState } from '../interactionState';\nimport { getBrowserSelectionRect } from '../selectionGeometry';\nimport type {\n FloatingPickerOptions,\n FloatingPickerRuntime,\n FloatingPickerRuntimeState\n} from './type';\n\nexport type * from './type';\n\n/**\n * 在 Lexical TextNode 对应 DOM 中查找覆盖指定 offset 的真实 Text 节点。\n *\n * Lexical 在不同浏览器和编辑状态下可能给 TextNode 包多层 span;递归查找能让 slash/mention\n * 菜单锚点继续对齐触发符,而不是退回编辑区左上角。\n */\nexport const findTextNodeWithOffset = (node: Node | null, offset: number): Text | null => {\n if (node instanceof Text && offset <= (node.textContent?.length ?? 0)) return node;\n\n for (const child of Array.from(node?.childNodes ?? [])) {\n const textNode = findTextNodeWithOffset(child, offset);\n\n if (textNode) return textNode;\n }\n\n return null;\n};\n\n/**\n * 创建 DOM 默认触发符候选浮层。\n *\n * slash command 和 mention 都是“触发符检测 -> 异步候选 -> 键盘/点击选择”的同一状态机。\n * 这里统一处理浮层、requestId 竞态、H5 软关闭和销毁;具体候选数据、DOM item 和选中命令\n * 仍由各领域注入,避免公共组件理解 slash 或 mention 的业务语义。\n */\nexport const registerFloatingPicker = <TItem>({\n editorRoot,\n contentElement,\n editor,\n isReadonly,\n menu,\n anchor,\n itemSelector,\n getCurrentTrigger,\n getTriggerRect,\n resolveItems,\n renderItem,\n renderStatus,\n onStateChange,\n onSelect\n}: FloatingPickerOptions<TItem>): FloatingPickerRuntime => {\n let state: FloatingPickerRuntimeState<TItem> | null = null;\n let requestId = 0;\n const clearPressedState = bindTouchPressedState(menu, {\n targetSelector: itemSelector\n });\n const floatingLayer = createFloatingLayer(anchor, menu, {\n placement: 'bottom-start',\n offset: 2,\n strategy: 'fixed'\n });\n\n editorRoot.append(anchor, menu);\n\n const getAnchorRect = () => {\n const rect = state\n ? getTriggerRect(state.trigger) ?? getBrowserSelectionRect()\n : getBrowserSelectionRect();\n const fallbackRect = contentElement.getBoundingClientRect();\n\n return rect ?? fallbackRect;\n };\n\n const syncAnchorPosition = () => {\n const rect = getAnchorRect();\n\n /*\n * 触发符菜单优先跟随 `/` 或 `@` 本身;测试环境和部分 WebView 可能拿不到 range rect。\n * 拿不到时退回当前 selection 或编辑区位置,保证键盘选择链路仍然可用。\n */\n anchor.style.left = `${rect.left}px`;\n anchor.style.top = `${rect.top}px`;\n anchor.style.height = `${rect.height || 1}px`;\n };\n\n const close = (shouldClearItems = true) => {\n state = null;\n menu.dataset.visible = 'false';\n if (shouldClearItems) menu.replaceChildren();\n floatingLayer.setOpen(false);\n };\n\n const scrollActiveItemIntoView = () => {\n const activeItem = menu.querySelector<HTMLElement>(`${itemSelector}[data-active=\"true\"]`);\n\n if (!activeItem) return;\n\n scrollFloatingMenuItemIntoView(menu, activeItem);\n };\n\n const selectItem = (\n item: TItem,\n stateSnapshot: FloatingPickerRuntimeState<TItem>\n ) => {\n /*\n * 自绘层可能在异步请求返回后仍持有旧 request。只允许当前 requestId 提交,\n * 避免旧 query 的候选插入到新光标触发点。\n */\n if (!state || state.requestId !== stateSnapshot.requestId) return;\n\n close();\n onSelect(item, stateSnapshot.trigger);\n };\n\n const render = () => {\n if (!state) {\n close();\n return;\n }\n\n const stateSnapshot = state;\n const anchorRect = getAnchorRect();\n const shouldUseCustomRenderer = onStateChange?.(stateSnapshot, {\n anchorRect,\n close,\n selectItem: (item) => selectItem(item, stateSnapshot)\n }) === true;\n\n if (shouldUseCustomRenderer) {\n menu.replaceChildren();\n menu.dataset.visible = 'false';\n floatingLayer.setOpen(false);\n return;\n }\n\n if (stateSnapshot.status === 'success') {\n menu.replaceChildren(\n ...stateSnapshot.items.map((item, index) => (\n renderItem(item, index, index === stateSnapshot.activeIndex)\n ))\n );\n } else {\n const statusElement = renderStatus?.(\n stateSnapshot.status,\n stateSnapshot.trigger.query,\n stateSnapshot.error\n );\n\n menu.replaceChildren(...(statusElement ? [statusElement] : []));\n }\n\n const hasVisibleContent = menu.children.length > 0;\n\n menu.dataset.visible = String(hasVisibleContent);\n syncAnchorPosition();\n floatingLayer.setOpen(hasVisibleContent);\n scrollActiveItemIntoView();\n void floatingLayer.update();\n };\n\n const resolveCurrentItems = async (query: string, nextRequestId: number) => {\n let items: TItem[];\n\n try {\n items = await Promise.resolve(resolveItems(query));\n } catch (error) {\n /*\n * provider 通常由业务接远程数据源。失败时保留当前请求并进入 error 状态;\n * 过期请求失败说明用户已经继续输入,不能覆盖新状态。\n */\n if (state?.requestId === nextRequestId) {\n state = {\n ...state,\n items: [],\n activeIndex: 0,\n status: 'error',\n error\n };\n render();\n }\n return;\n }\n\n if (!state || nextRequestId !== state.requestId) return;\n\n state = {\n ...state,\n items,\n activeIndex: Math.min(state.activeIndex, Math.max(items.length - 1, 0)),\n status: items.length > 0 ? 'success' : 'empty',\n error: undefined\n };\n render();\n };\n\n const syncTrigger = () => {\n if (isReadonly()) {\n close();\n return;\n }\n\n const trigger = editor.getEditorState().read(getCurrentTrigger);\n\n if (!trigger) {\n /*\n * H5 软键盘删除 trigger query 时应该只收起候选层,不能因为清空菜单 DOM 触发\n * contenteditable 附近的大规模重排,否则部分 WebView 会顺手收起软键盘。\n */\n close(false);\n return;\n }\n\n requestId += 1;\n state = {\n trigger,\n items: [],\n activeIndex: 0,\n requestId,\n status: 'loading',\n error: undefined\n };\n render();\n void resolveCurrentItems(trigger.query, requestId);\n };\n\n const selectActiveItem = () => {\n if (!state || state.status !== 'success') return false;\n\n const item = state.items[state.activeIndex];\n const trigger = state.trigger;\n\n if (!item) return false;\n\n close();\n onSelect(item, trigger);\n\n return true;\n };\n\n const moveActiveIndex = (offset: number) => {\n if (!state || state.status !== 'success' || state.items.length === 0) return false;\n\n state = {\n ...state,\n activeIndex: (state.activeIndex + offset + state.items.length) % state.items.length\n };\n render();\n\n return true;\n };\n\n const handleClick = (event: MouseEvent) => {\n const target = event.target;\n const button = target instanceof HTMLElement\n ? target.closest<HTMLButtonElement>(itemSelector)\n : null;\n const index = button?.dataset.index ? Number.parseInt(button.dataset.index, 10) : Number.NaN;\n\n if (!state || state.status !== 'success' || Number.isNaN(index)) return;\n\n state = { ...state, activeIndex: index };\n event.preventDefault();\n selectActiveItem();\n };\n\n const handlePointerDown = (event: PointerEvent) => {\n const target = event.target;\n const button = target instanceof HTMLElement\n ? target.closest<HTMLButtonElement>(itemSelector)\n : null;\n\n if (!button) return;\n\n /*\n * pointerdown 阶段阻止按钮抢焦点,避免真实浏览器点击候选时 Lexical selection\n * 先丢失,导致无法删除当前 query 或插入点漂移。\n */\n event.preventDefault();\n };\n\n const unregisterUpdate = editor.registerUpdateListener(() => {\n syncTrigger();\n });\n const unregisterArrowDown = editor.registerCommand(\n KEY_ARROW_DOWN_COMMAND,\n (event) => {\n if (!moveActiveIndex(1)) return false;\n\n event?.preventDefault();\n return true;\n },\n COMMAND_PRIORITY_LOW\n );\n const unregisterArrowUp = editor.registerCommand(\n KEY_ARROW_UP_COMMAND,\n (event) => {\n if (!moveActiveIndex(-1)) return false;\n\n event?.preventDefault();\n return true;\n },\n COMMAND_PRIORITY_LOW\n );\n const unregisterEnter = editor.registerCommand(\n KEY_ENTER_COMMAND,\n (event) => {\n if (!selectActiveItem()) return false;\n\n event?.preventDefault();\n return true;\n },\n COMMAND_PRIORITY_LOW\n );\n const unregisterEscape = editor.registerCommand(\n KEY_ESCAPE_COMMAND,\n (event) => {\n if (!state) return false;\n\n event?.preventDefault();\n close();\n return true;\n },\n COMMAND_PRIORITY_LOW\n );\n\n menu.addEventListener('click', handleClick);\n menu.addEventListener('pointerdown', handlePointerDown);\n\n return {\n close,\n destroy() {\n unregisterUpdate();\n unregisterArrowDown();\n unregisterArrowUp();\n unregisterEnter();\n unregisterEscape();\n menu.removeEventListener('click', handleClick);\n menu.removeEventListener('pointerdown', handlePointerDown);\n clearPressedState();\n floatingLayer.destroy();\n anchor.remove();\n menu.remove();\n }\n };\n};\n","import type {\n MentionItem,\n MentionMenuConfig,\n MentionMenuDisplayItem,\n MentionMenuFieldPath\n} from '@bridgerte/core';\n\nexport const defaultMentionMenuConfig: Required<MentionMenuConfig> = {\n labelField: 'label',\n descriptionField: 'description',\n avatarField: 'avatar',\n iconField: 'data.icon',\n showAvatar: true,\n showIcon: true,\n showDescription: true,\n loadingText: '加载中',\n emptyText: '没有匹配的提及',\n errorText: '提及加载失败'\n};\n\nexport const resolveMentionMenuConfig = (\n config?: MentionMenuConfig\n): Required<MentionMenuConfig> => ({\n ...defaultMentionMenuConfig,\n ...config\n});\n\nconst readDataField = (\n item: MentionItem,\n path: string\n) => {\n const dataKey = path.slice('data.'.length);\n const value = item.data?.[dataKey];\n\n return typeof value === 'string' && value ? value : undefined;\n};\n\nconst readMentionField = (\n item: MentionItem,\n path: MentionMenuFieldPath\n) => {\n if (path.startsWith('data.')) return readDataField(item, path);\n\n const value = path === 'id'\n ? item.id\n : path === 'label'\n ? item.label\n : path === 'value'\n ? item.value\n : path === 'avatar'\n ? item.avatar\n : item.description;\n\n return typeof value === 'string' && value ? value : undefined;\n};\n\nconst normalizeMentionLabel = (value: string) => (\n value.startsWith('@') ? value : `@${value}`\n);\n\n/**\n * 把 provider 返回的 MentionItem 解析成展示模型。\n *\n * provider 继续只负责数据;字段映射、空值兜底和 avatar/icon 优先级集中在这里,\n * DOM 默认菜单和业务自绘 request 读取同一份结果,避免出现两套展示规则。\n */\nexport const resolveMentionDisplayItem = (\n item: MentionItem,\n config: Required<MentionMenuConfig>\n): MentionMenuDisplayItem => {\n const label = readMentionField(item, config.labelField)\n ?? item.label\n ?? item.value\n ?? item.id;\n const description = config.showDescription\n ? readMentionField(item, config.descriptionField) ?? item.description\n : undefined;\n const avatar = config.showAvatar\n ? readMentionField(item, config.avatarField) ?? item.avatar\n : undefined;\n const icon = config.showIcon && !avatar\n ? readMentionField(item, config.iconField)\n : undefined;\n\n return {\n item,\n label: normalizeMentionLabel(label),\n ...(description ? { description } : {}),\n ...(avatar ? { avatar } : {}),\n ...(icon ? { icon } : {})\n };\n};\n\nexport const resolveMentionDisplayItems = (\n items: MentionItem[],\n config: Required<MentionMenuConfig>\n) => items.map((item) => resolveMentionDisplayItem(item, config));\n","import {\n $getSelection,\n $isRangeSelection,\n COMMAND_PRIORITY_HIGH,\n DELETE_CHARACTER_COMMAND,\n KEY_BACKSPACE_COMMAND,\n KEY_DELETE_COMMAND,\n TextNode,\n type LexicalEditor\n} from 'lexical';\nimport { $isMentionNode, type MentionNode } from '../mentionNode';\n\nconst hasLeadingSpace = (node: unknown): node is TextNode => (\n node instanceof TextNode && node.getTextContent().startsWith(' ')\n);\n\nconst removeLeadingAutoSpace = (node: TextNode) => {\n const text = node.getTextContent();\n const nextText = text.slice(1);\n\n if (!nextText) {\n node.remove();\n return;\n }\n\n node.setTextContent(nextText);\n};\n\nconst removeMentionAndAutoSpace = (\n mentionNode: MentionNode,\n isBackward: boolean\n) => {\n const previousSibling = mentionNode.getPreviousSibling();\n const nextSibling = mentionNode.getNextSibling();\n const siblingAfterAutoSpace = hasLeadingSpace(nextSibling)\n ? nextSibling.getNextSibling()\n : nextSibling;\n\n /*\n * `mention.insert` 会在 mention 后补一个空格,移动端删除时经常先删空格再删 mention。\n * 这里把自动空格和 mention 作为一个编辑单元处理,保证 Backspace/Delete 一次完成。\n */\n if (hasLeadingSpace(nextSibling)) {\n removeLeadingAutoSpace(nextSibling);\n }\n\n mentionNode.remove();\n\n if (isBackward) {\n previousSibling?.selectEnd();\n return;\n }\n\n siblingAfterAutoSpace?.selectStart();\n};\n\nconst getMentionNodeForDeletion = (isBackward: boolean): MentionNode | null => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection) || !selection.isCollapsed()) return null;\n\n const anchor = selection.anchor;\n const anchorNode = anchor.getNode();\n\n if ($isMentionNode(anchorNode)) return anchorNode;\n\n if (!(anchorNode instanceof TextNode)) return null;\n\n const textLength = anchorNode.getTextContentSize();\n const previousSibling = anchorNode.getPreviousSibling();\n const nextSibling = anchorNode.getNextSibling();\n const isAfterLeadingAutoSpace = hasLeadingSpace(anchorNode) && anchor.offset === 1;\n const targetNode = isBackward\n ? anchor.offset === 0 || isAfterLeadingAutoSpace\n ? previousSibling\n : null\n : anchor.offset === textLength\n ? nextSibling\n : null;\n\n return $isMentionNode(targetNode) ? targetNode : null;\n};\n\n/**\n * 注册 mention 原子删除兜底。\n *\n * Lexical token TextNode 理论上会整体删除,但 H5 contenteditable 和软键盘边界上可能先删空格、\n * 先选中 token 或触发候选菜单。这里用高优先级删除命令只接管 mention 边界,普通文本继续走\n * Lexical 默认删除链路。\n */\nexport const registerMentionDeletion = (\n editor: LexicalEditor,\n isReadonly: () => boolean,\n onDeleteMention: () => void\n) => {\n const deleteMention = (isBackward: boolean) => {\n if (isReadonly()) return false;\n\n const mentionNode = getMentionNodeForDeletion(isBackward);\n\n if (!mentionNode) return false;\n\n removeMentionAndAutoSpace(mentionNode, isBackward);\n onDeleteMention();\n\n return true;\n };\n const handleKeyboardDelete = (\n event: KeyboardEvent,\n isBackward: boolean\n ) => {\n const didDelete = deleteMention(isBackward);\n\n if (didDelete) event.preventDefault();\n\n return didDelete;\n };\n\n return [\n editor.registerCommand(\n KEY_BACKSPACE_COMMAND,\n (event) => handleKeyboardDelete(event, true),\n COMMAND_PRIORITY_HIGH\n ),\n editor.registerCommand(\n KEY_DELETE_COMMAND,\n (event) => handleKeyboardDelete(event, false),\n COMMAND_PRIORITY_HIGH\n ),\n editor.registerCommand(\n DELETE_CHARACTER_COMMAND,\n (isBackward) => deleteMention(isBackward),\n COMMAND_PRIORITY_HIGH\n )\n ];\n};\n","import {\n $getNodeByKey,\n $getSelection,\n $isRangeSelection,\n mergeRegister,\n TextNode\n} from 'lexical';\nimport type {\n MentionItem,\n MentionMenuAnchorRect,\n MentionMenuDisplayItem,\n MentionMenuStatus\n} from '@bridgerte/core';\nimport {\n findTextNodeWithOffset,\n registerFloatingPicker\n} from '../floatingPicker';\nimport type { FloatingPickerTrigger } from '../floatingPicker';\nimport {\n resolveMentionDisplayItem,\n resolveMentionDisplayItems,\n resolveMentionMenuConfig\n} from './config';\nimport { registerMentionDeletion } from './deleteMention';\nimport type {\n MentionControllerOptions\n} from './type';\n\nexport type * from './type';\n\nconst mentionQueryRegExp = /(?:^|\\s)@([\\p{L}\\p{N}_-]*)$/u;\n\nconst defaultMentionItems: MentionItem[] = [\n { id: 'bridgerte-team', label: 'BridgeRTE Team', value: 'bridgerte-team' },\n { id: 'frontend', label: 'Frontend', value: 'frontend' },\n { id: 'designer', label: 'Designer', value: 'designer' }\n];\n\nconst normalizeSearchText = (value: string) => value.trim().toLowerCase();\n\nconst getMentionSearchText = (item: MentionItem) => (\n [item.label, item.value, item.description]\n .filter(Boolean)\n .join(' ')\n .toLowerCase()\n);\n\nconst getDefaultMentionItems = (query: string) => {\n const normalizedQuery = normalizeSearchText(query);\n\n if (!normalizedQuery) return defaultMentionItems;\n\n return defaultMentionItems.filter((item) => (\n getMentionSearchText(item).includes(normalizedQuery)\n ));\n};\n\nconst getCurrentMentionTrigger = (): FloatingPickerTrigger | null => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection) || !selection.isCollapsed()) return null;\n\n const anchor = selection.anchor;\n const anchorNode = anchor.getNode();\n\n if (!(anchorNode instanceof TextNode)) return null;\n\n const textBeforeCursor = anchorNode.getTextContent().slice(0, anchor.offset);\n const match = textBeforeCursor.match(mentionQueryRegExp);\n\n if (!match) return null;\n\n const query = match[1] ?? '';\n const matchText = match[0] ?? '';\n const leadingWhitespace = matchText.startsWith('@') ? 0 : 1;\n const startOffset = anchor.offset - matchText.length + leadingWhitespace;\n\n return {\n query,\n nodeKey: anchorNode.getKey(),\n startOffset,\n endOffset: anchor.offset\n };\n};\n\nconst createMentionMenuElement = () => {\n const menu = document.createElement('div');\n\n menu.className = 'bridgerte__floating-menu bridgerte__mention-menu';\n menu.dataset.visible = 'false';\n\n return menu;\n};\n\nconst createMentionAnchorElement = () => {\n const anchor = document.createElement('span');\n\n anchor.className = 'bridgerte__mention-anchor';\n anchor.setAttribute('aria-hidden', 'true');\n\n return anchor;\n};\n\nconst getMentionTriggerRect = (\n editor: MentionControllerOptions['editor'],\n trigger: FloatingPickerTrigger\n) => {\n const element = editor.getElementByKey(trigger.nodeKey);\n /*\n * Lexical TextNode 的 DOM 在不同编辑状态下可能不是 element.firstChild。\n * 递归找能覆盖 trigger offset 的真实 Text,避免失败后退回编辑区底部导致菜单离光标很远。\n */\n const textNode = findTextNodeWithOffset(element, trigger.startOffset + 1);\n\n if (!(textNode instanceof Text)) return null;\n\n const range = document.createRange();\n const triggerEndOffset = Math.min(trigger.startOffset + 1, textNode.textContent?.length ?? 0);\n\n if (triggerEndOffset <= trigger.startOffset) return null;\n\n /*\n * mention 浮层应固定在 `@` 触发符下方,而不是随着 query 越输越往右漂。\n * 用触发字符自身的 DOM Range 作为锚点,输入 `@bo` 时菜单仍然对齐 `@`。\n */\n range.setStart(textNode, trigger.startOffset);\n range.setEnd(textNode, triggerEndOffset);\n\n return range.getBoundingClientRect();\n};\n\nconst createMentionItemElement = (\n displayItem: MentionMenuDisplayItem,\n index: number,\n active: boolean\n) => {\n const button = document.createElement('button');\n const title = document.createElement('span');\n\n button.type = 'button';\n button.className = 'bridgerte__menu-item bridgerte__mention-item';\n button.dataset.mentionId = displayItem.item.id;\n button.dataset.index = String(index);\n button.dataset.active = String(active);\n\n if (displayItem.avatar) {\n const avatar = document.createElement('img');\n\n avatar.className = 'bridgerte__mention-item-avatar';\n avatar.src = displayItem.avatar;\n avatar.alt = '';\n avatar.setAttribute('aria-hidden', 'true');\n button.append(avatar);\n } else if (displayItem.icon) {\n const icon = document.createElement('span');\n\n icon.className = 'bridgerte__mention-item-icon';\n icon.setAttribute('aria-hidden', 'true');\n icon.textContent = displayItem.icon;\n button.append(icon);\n }\n\n title.className = 'bridgerte__mention-item-title';\n title.textContent = displayItem.label;\n button.append(title);\n\n if (displayItem.description) {\n const description = document.createElement('span');\n\n description.className = 'bridgerte__mention-item-description';\n description.textContent = displayItem.description;\n button.append(description);\n }\n\n return button;\n};\n\nconst createMentionStatusElement = (\n status: Exclude<MentionMenuStatus, 'success'>,\n text: string\n) => {\n const element = document.createElement('div');\n\n element.className = 'bridgerte__mention-status';\n element.dataset.status = status;\n element.textContent = text;\n\n return element;\n};\n\nconst getMentionStatusText = (\n status: Exclude<MentionMenuStatus, 'success'>,\n config: ReturnType<typeof resolveMentionMenuConfig>\n) => {\n switch (status) {\n case 'loading':\n return config.loadingText;\n case 'empty':\n return config.emptyText;\n case 'error':\n return config.errorText;\n }\n};\n\nconst serializeMentionAnchorRect = (\n rect?: DOMRect\n): MentionMenuAnchorRect | undefined => (\n rect\n ? {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height\n }\n : undefined\n);\n\n/**\n * 注册 DOM 默认 mention trigger。\n *\n * 触发检测只读取当前 TextNode 光标前的短文本;provider 只负责候选数据,\n * 展示字段和自绘 request 统一走 mentionMenuConfig,避免 DOM 默认 UI 与业务自绘协议分叉。\n */\nexport const registerMention = ({\n editorRoot,\n contentElement,\n editor,\n isReadonly,\n executeCommand,\n mentionProvider,\n mentionMenuConfig,\n onMentionMenuRequest\n}: MentionControllerOptions): (() => void) => {\n const menu = createMentionMenuElement();\n const anchor = createMentionAnchorElement();\n const resolvedMentionMenuConfig = resolveMentionMenuConfig(mentionMenuConfig);\n\n const selectItem = (item: MentionItem, trigger: FloatingPickerTrigger) => {\n editor.update(() => {\n /*\n * 点击候选会让 button 参与事件流。这里用捕获到的 trigger nodeKey 删除 `@query`,\n * 不再依赖当前 selection 仍停在原位置,避免 PC/H5 点击候选时插入点漂移。\n */\n const triggerNode = $getNodeByKey(trigger.nodeKey);\n\n if (!(triggerNode instanceof TextNode)) return;\n\n triggerNode.spliceText(trigger.startOffset, trigger.endOffset - trigger.startOffset, '');\n triggerNode.select(trigger.startOffset, trigger.startOffset);\n });\n executeCommand({ type: 'mention.insert', item });\n };\n\n const picker = registerFloatingPicker({\n editorRoot,\n contentElement,\n editor,\n isReadonly,\n menu,\n anchor,\n itemSelector: '.bridgerte__mention-item',\n getCurrentTrigger: getCurrentMentionTrigger,\n getTriggerRect: (trigger) => getMentionTriggerRect(editor, trigger),\n resolveItems: async (query) => {\n const items = await Promise.resolve(\n mentionProvider ? mentionProvider(query) : getDefaultMentionItems(query)\n );\n\n return resolveMentionDisplayItems(items, resolvedMentionMenuConfig);\n },\n renderItem: createMentionItemElement,\n renderStatus: (status) => createMentionStatusElement(\n status,\n getMentionStatusText(status, resolvedMentionMenuConfig)\n ),\n onStateChange: onMentionMenuRequest\n ? (state, helpers) => onMentionMenuRequest({\n id: `bridgerte-mention-menu-${state.requestId}`,\n query: state.trigger.query,\n status: state.status,\n items: state.items,\n config: resolvedMentionMenuConfig,\n readonly: isReadonly(),\n anchorRect: serializeMentionAnchorRect(helpers.anchorRect),\n ...(state.error ? { error: state.error } : {}),\n submit: (item) => helpers.selectItem(\n resolveMentionDisplayItem(item, resolvedMentionMenuConfig)\n ),\n cancel: helpers.close\n })\n : undefined,\n onSelect: (displayItem, trigger) => selectItem(displayItem.item, trigger)\n });\n const unregisterMentionDeletion = mergeRegister(\n ...registerMentionDeletion(editor, isReadonly, () => picker.close(false))\n );\n\n return () => {\n unregisterMentionDeletion();\n picker.destroy();\n };\n};\n","import {\n codeLanguageAttributeName,\n normalizeCodeBlockLanguages,\n normalizeCodeLanguageValue\n} from '../codeHighlight';\n\nconst removableHtmlSelector = [\n 'script',\n 'style',\n 'iframe',\n 'object',\n 'embed',\n 'meta',\n 'link',\n 'xml',\n 'svg',\n 'math',\n 'canvas',\n 'form',\n 'input',\n 'button',\n 'select',\n 'textarea'\n].join(',');\nconst removableClipboardUiSelector = [\n '.bridgerte__code-header',\n '.bridgerte__code-block-control',\n '.bridgerte__code-block-controls-layer',\n '.bridgerte__code-block-menu',\n '.bridgerte__table-controls-layer',\n '.bridgerte__table-controls',\n '.bridgerte__media-controls-layer',\n '.bridgerte__media-controls',\n '.bridgerte__dialog-backdrop',\n '.bridgerte__dialog',\n '.bridgerte__payload-panel',\n '[data-bridgerte-clipboard-ui=\"true\"]'\n].join(',');\nconst allowedHtmlTags = new Set([\n 'A',\n 'B',\n 'BLOCKQUOTE',\n 'BR',\n 'CODE',\n 'DEL',\n 'DIV',\n 'EM',\n 'H1',\n 'H2',\n 'H3',\n 'H4',\n 'H5',\n 'H6',\n 'FONT',\n 'I',\n 'LI',\n 'OL',\n 'P',\n 'PRE',\n 'S',\n 'SPAN',\n 'STRIKE',\n 'STRONG',\n 'SUB',\n 'SUP',\n 'TABLE',\n 'TBODY',\n 'TFOOT',\n 'TD',\n 'TH',\n 'THEAD',\n 'TR',\n 'TT',\n 'U',\n 'UL'\n]);\nconst allowedLinkProtocols = new Set(['http:', 'https:', 'mailto:']);\nconst htmlBlockElementSelector = 'p,div,blockquote,pre,h1,h2,h3,h4,h5,h6,ul,ol,table';\nconst nestedBlockElementSelector = 'p,blockquote,pre,h1,h2,h3,h4,h5,h6,ul,ol,table';\nconst tableSpanAttributeNames = new Set(['colspan', 'rowspan']);\nconst tableCellTagNames = new Set(['TD', 'TH']);\nconst officeNamespacePrefixes = new Set(['M', 'O', 'V', 'W']);\nconst controlledStyleTagNames = new Set(['SPAN']);\nconst controlledInlineStyleProperties = new Set(['color', 'background-color']);\nconst hexColorRegExp = /^#([\\da-f]{3}|[\\da-f]{6}|[\\da-f]{8})$/i;\n/*\n * HTML 语义归一化只处理浏览器、办公软件和 Android 原生富文本复制时最常见的短标签。\n * 这里集中成表,后续扩展时优先判断是否是稳定语义标签,再加入清洗层,避免把样式还原逻辑塞进 paste。\n */\nconst semanticHtmlTagMap = new Map([\n ['B', 'strong'],\n ['DEL', 's'],\n ['I', 'em'],\n ['STRIKE', 's'],\n ['TT', 'code']\n]);\n\nconst isSafeUrl = (value: string) => {\n try {\n const url = new URL(value, window.location.href);\n\n return allowedLinkProtocols.has(url.protocol);\n } catch {\n return false;\n }\n};\n\nconst unwrapDisallowedElement = (element: Element) => {\n element.replaceWith(...element.childNodes);\n};\n\nconst replaceElementTag = (element: Element, tagName: string) => {\n const replacement = element.ownerDocument.createElement(tagName);\n\n replacement.append(...element.childNodes);\n element.replaceWith(replacement);\n\n return replacement;\n};\n\nconst isOfficeNamespaceElement = (element: Element) => {\n const prefix = element.tagName.split(':')[0] ?? '';\n\n return element.tagName.includes(':') && officeNamespacePrefixes.has(prefix);\n};\n\nconst removeCommentNodes = (node: Node) => {\n [...node.childNodes].forEach((childNode) => {\n if (childNode.nodeType === Node.COMMENT_NODE) {\n childNode.remove();\n return;\n }\n\n removeCommentNodes(childNode);\n });\n};\n\nconst normalizeTextNodes = (node: Node) => {\n [...node.childNodes].forEach((childNode) => {\n if (childNode.nodeType === Node.TEXT_NODE) {\n const parentElement = childNode.parentElement;\n const preserveWhitespace = Boolean(parentElement?.closest('pre,code,textarea'));\n const textContent = (childNode.textContent ?? '')\n .replace(/[\\u200B-\\u200D\\uFEFF]/g, '')\n .replace(/\\u00A0/g, preserveWhitespace ? '\\u00A0' : ' ');\n\n if (preserveWhitespace) {\n childNode.textContent = textContent;\n return;\n }\n\n let normalizedText = textContent.replace(/\\s+/g, ' ');\n\n if (!childNode.previousSibling) normalizedText = normalizedText.trimStart();\n if (!childNode.nextSibling) normalizedText = normalizedText.trimEnd();\n\n childNode.textContent = normalizedText;\n return;\n }\n\n normalizeTextNodes(childNode);\n });\n};\n\nconst isPositiveIntegerText = (value: string) => /^[1-9]\\d*$/.test(value.trim());\n\nconst normalizeHexColor = (value: string) => {\n const normalizedValue = value.trim().toLowerCase();\n const [, hexValue] = normalizedValue.match(hexColorRegExp) ?? [];\n\n if (!hexValue) return null;\n if (hexValue.length === 8) return `#${hexValue.slice(2)}`;\n\n return normalizedValue;\n};\n\nconst normalizeControlledInlineStyle = (tagName: string, styleText: string) => {\n if (!controlledStyleTagNames.has(tagName)) return null;\n\n const styleEntries = styleText.split(';').flatMap((entry) => {\n const [rawProperty, ...rawValueParts] = entry.split(':');\n const property = rawProperty?.trim().toLowerCase();\n const value = normalizeHexColor(rawValueParts.join(':'));\n\n if (!property || !value || !controlledInlineStyleProperties.has(property)) return [];\n\n return [`${property}: ${value}`];\n });\n\n return styleEntries.length > 0 ? `${styleEntries.join('; ')};` : null;\n};\n\nconst sanitizeElement = (element: Element) => {\n if (isOfficeNamespaceElement(element)) {\n element.remove();\n return;\n }\n\n if (!allowedHtmlTags.has(element.tagName)) {\n unwrapDisallowedElement(element);\n return;\n }\n\n [...element.attributes].forEach((attribute) => {\n const attributeName = attribute.name.toLowerCase();\n\n if (attributeName.startsWith('on')) {\n element.removeAttribute(attribute.name);\n return;\n }\n\n if (attributeName === 'style') {\n const normalizedStyle = normalizeControlledInlineStyle(element.tagName, attribute.value);\n\n /*\n * Android 原生富文本复制可能用 span style 承载前景/背景色。这里仅保留可验证的\n * hex 色值,布局、字体、危险表达式和网页里的任意 CSS 都继续作为不受控样式移除。\n */\n if (normalizedStyle) {\n element.setAttribute(attribute.name, normalizedStyle);\n return;\n }\n\n element.removeAttribute(attribute.name);\n return;\n }\n\n if (element.tagName === 'A' && attributeName === 'href') {\n if (isSafeUrl(attribute.value)) return;\n\n element.removeAttribute(attribute.name);\n return;\n }\n\n if (element.tagName === 'A' && ['target', 'rel', 'title'].includes(attributeName)) return;\n if (element.tagName === 'PRE' && attributeName === codeLanguageAttributeName) {\n const normalizedLanguage = normalizeCodeLanguageValue(attribute.value);\n\n if (normalizedLanguage) {\n element.setAttribute(attribute.name, normalizedLanguage);\n return;\n }\n\n element.removeAttribute(attribute.name);\n return;\n }\n if (element.tagName === 'FONT' && attributeName === 'color') {\n if (normalizeHexColor(attribute.value)) return;\n\n element.removeAttribute(attribute.name);\n return;\n }\n if (\n tableCellTagNames.has(element.tagName)\n && tableSpanAttributeNames.has(attributeName)\n && isPositiveIntegerText(attribute.value)\n ) {\n return;\n }\n\n element.removeAttribute(attribute.name);\n });\n};\n\nconst normalizeFontElements = (root: ParentNode) => {\n [...root.querySelectorAll('font')].forEach((element) => {\n const colorValue = element.getAttribute('color');\n const normalizedColor = colorValue ? normalizeHexColor(colorValue) : null;\n const replacement = replaceElementTag(element, 'span');\n\n /*\n * Android TextView/Spannable 常用 font[color] 表达前景色。这里只把可验证的 hex 色值\n * 转成 BridgeRTE/Lexical 可识别的受控 inline style,其它 font 属性继续丢弃。\n */\n if (normalizedColor) replacement.setAttribute('style', `color: ${normalizedColor};`);\n });\n};\n\nconst normalizeSemanticElements = (root: ParentNode) => {\n [...root.querySelectorAll([...semanticHtmlTagMap.keys()].join(','))].forEach((element) => {\n const tagName = semanticHtmlTagMap.get(element.tagName);\n\n if (tagName) replaceElementTag(element, tagName);\n });\n};\n\nconst normalizeDivElements = (root: ParentNode) => {\n [...root.querySelectorAll('div')].reverse().forEach((element) => {\n if (element.querySelector(nestedBlockElementSelector)) {\n unwrapDisallowedElement(element);\n return;\n }\n\n replaceElementTag(element, 'p');\n });\n};\n\nconst unwrapNeutralSpans = (root: ParentNode) => {\n [...root.querySelectorAll('span')].forEach((element) => {\n if (element.attributes.length === 0) unwrapDisallowedElement(element);\n });\n};\n\nconst isEmptyCleanupElement = (element: Element) => {\n if (!['P', 'DIV', 'SPAN'].includes(element.tagName)) return false;\n if (element.querySelector('br,table,ul,ol')) return false;\n\n return !(element.textContent ?? '').trim();\n};\n\nconst removeEmptyCleanupElements = (root: ParentNode) => {\n [...root.querySelectorAll('p,div,span')].reverse().forEach((element) => {\n if (isEmptyCleanupElement(element)) element.remove();\n });\n};\n\nconst isInlineTopLevelNode = (node: Node) => {\n if (node.nodeType === Node.TEXT_NODE) return Boolean(node.textContent?.trim());\n if (node.nodeType !== Node.ELEMENT_NODE) return false;\n\n return !(node as Element).matches(htmlBlockElementSelector);\n};\n\nconst normalizeTopLevelInlineRuns = (wrapper: HTMLElement) => {\n let inlineNodes: Node[] = [];\n\n const flushInlineNodes = () => {\n if (inlineNodes.length === 0) return;\n\n const paragraph = wrapper.ownerDocument.createElement('p');\n const firstInlineNode = inlineNodes[0];\n\n if (!firstInlineNode) return;\n\n wrapper.insertBefore(paragraph, firstInlineNode);\n inlineNodes.forEach((node) => {\n paragraph.append(node);\n });\n inlineNodes = [];\n };\n\n [...wrapper.childNodes].forEach((node) => {\n if (node.nodeType === Node.TEXT_NODE && !node.textContent?.trim()) {\n node.remove();\n return;\n }\n\n if (isInlineTopLevelNode(node)) {\n inlineNodes.push(node);\n return;\n }\n\n flushInlineNodes();\n });\n\n flushInlineNodes();\n};\n\n/**\n * 清洗外部 HTML 粘贴片段。\n *\n * 这里保留基础富文本结构,主动移除脚本、事件属性、style、Office 条件注释和网页包装噪音;\n * 顶层裸 inline 会被收束进 paragraph,避免 Word、飞书或网页片段生成不可预期的 root 子节点。\n */\nexport const sanitizePastedHtml = (html: string): string => {\n const template = document.createElement('template');\n\n template.innerHTML = html;\n template.content.querySelectorAll(removableHtmlSelector).forEach((node) => {\n node.remove();\n });\n template.content.querySelectorAll(removableClipboardUiSelector).forEach((node) => {\n node.remove();\n });\n removeCommentNodes(template.content);\n normalizeCodeBlockLanguages(template.content);\n [...template.content.querySelectorAll('*')].forEach(sanitizeElement);\n normalizeTextNodes(template.content);\n normalizeFontElements(template.content);\n normalizeSemanticElements(template.content);\n normalizeDivElements(template.content);\n unwrapNeutralSpans(template.content);\n removeEmptyCleanupElements(template.content);\n\n const wrapper = document.createElement('div');\n\n wrapper.append(template.content.cloneNode(true));\n normalizeTopLevelInlineRuns(wrapper);\n removeEmptyCleanupElements(wrapper);\n\n return wrapper.innerHTML;\n};\n","import {\n $createTextNode,\n $createParagraphNode,\n $getRoot,\n $getSelection,\n $insertNodes\n} from 'lexical';\nimport { $isCodeNode, type CodeNode } from '@lexical/code';\nimport { $generateNodesFromDOM } from '@lexical/html';\nimport { $insertNodeToNearestRoot } from '@lexical/utils';\nimport {\n applyCodeNodeLanguagesFromDom,\n unwrapPreCodeChildren\n} from '../codeHighlight';\nimport type { BridgeMediaType } from '../mediaNode';\nimport { sanitizePastedHtml } from './htmlCleanup';\nimport type {\n CustomPasteHookOptions,\n PasteHtmlCleanupOptions,\n PasteInput,\n PasteLinkOptions,\n PasteMediaOptions\n} from './type';\n\nexport type * from './type';\nexport { sanitizePastedHtml } from './htmlCleanup';\n\nconst explicitUrlRegExp = /^https?:\\/\\/[^\\s<>\"']+\\.[^\\s<>\"']+$/i;\nconst wwwUrlRegExp = /^www\\.[^\\s<>\"']+\\.[^\\s<>\"']+$/i;\nconst nakedDomainRegExp = new RegExp(\n '^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?'\n + '(?:\\\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+'\n + '(?:/[^\\\\s<>\"\\']*)?$',\n 'i'\n);\nconst emailRegExp = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/i;\nconst fencedCodeBlockRegExp = /^\\s*```([a-z0-9_+#.-]+)?\\s*$/i;\nconst probableCodeLineRegExp = /[{}()[\\];<>:=/\\\\]|<!DOCTYPE|<\\/?[a-z][\\w:-]*\\b/i;\nconst probableCodeFirstLineRegExp = /^[a-z][a-z0-9_+#.-]{0,31}$/i;\n\nconst getMediaTypeFromFile = (file: File): BridgeMediaType | null => {\n if (file.type.startsWith('image/')) return 'image';\n if (file.type.startsWith('video/')) return 'video';\n\n return null;\n};\n\nconst getMediaFiles = (fileList: FileList | File[] | null | undefined) => {\n if (!fileList) return [];\n\n return [...fileList].flatMap((file) => {\n const type = getMediaTypeFromFile(file);\n\n return type ? [{ type, file }] : [];\n });\n};\n\nconst getClipboardPasteInput = (clipboardData: DataTransfer | null): PasteInput => ({\n text: clipboardData?.getData('text/plain') ?? '',\n html: clipboardData?.getData('text/html') ?? '',\n files: clipboardData?.files ? [...clipboardData.files] : []\n});\n\nconst toUploadFileLike = (file: File) => ({\n name: file.name,\n mimeType: file.type || undefined,\n size: file.size,\n data: file\n});\n\nconst isPlainTextCodeSnippet = (value: string): boolean => {\n const lines = value.replace(/\\r\\n/g, '\\n').trim().split('\\n');\n\n if (lines.length < 2) return false;\n\n const firstLine = lines[0]?.trim() ?? '';\n if (!probableCodeFirstLineRegExp.test(firstLine)) return false;\n\n const lastLine = lines[lines.length - 1]?.trim() ?? '';\n if (fencedCodeBlockRegExp.test(firstLine)) return true;\n if (!probableCodeLineRegExp.test(lines.slice(1).join('\\n'))) return false;\n if (lastLine === '```') return true;\n\n return lines.slice(1).some((line) => probableCodeLineRegExp.test(line));\n};\n\n/**\n * 判断纯文本粘贴内容是否可以被 BridgeRTE 直接当作 URL 链接处理。\n *\n * paste 是用户明确输入 URL 的高意图场景,所以这里比 autoLink 多支持裸域名;但仍拒绝\n * 邮箱、HTML 片段、空白字符和危险协议,避免接管普通文本或把脚本 URL 写入链接命令。\n */\nexport const isPlainUrlText = (value: string): boolean => {\n const text = value.trim();\n\n if (!text || /\\s/.test(text)) return false;\n if (text.includes('<') || text.includes('>')) return false;\n if (/^[a-z][a-z0-9+.-]*:/i.test(text) && !/^https?:\\/\\//i.test(text)) return false;\n if (emailRegExp.test(text)) return false;\n\n return explicitUrlRegExp.test(text)\n || wwwUrlRegExp.test(text)\n || nakedDomainRegExp.test(text);\n};\n\nconst handlePasteLinkInput = (\n input: PasteInput,\n {\n isReadonly,\n executeCommand\n }: Omit<PasteLinkOptions, 'target'>\n) => {\n if (isReadonly()) return false;\n if (!isPlainUrlText(input.text)) return false;\n\n executeCommand({\n type: 'link.set',\n href: input.text.trim()\n });\n\n return true;\n};\n\nconst handlePasteMediaInput = (\n input: PasteInput,\n {\n isReadonly,\n canUploadMedia,\n uploadMediaFile\n }: Omit<PasteMediaOptions, 'target'>\n) => {\n if (isReadonly() || !canUploadMedia()) return false;\n\n const mediaFiles = getMediaFiles(input.files);\n\n if (mediaFiles.length === 0) return false;\n\n mediaFiles.forEach(({ type, file }) => {\n uploadMediaFile(type, file);\n });\n\n return true;\n};\n\nconst generateNodesFromSanitizedHtml = (editor: PasteHtmlCleanupOptions['editor'], html: string) => {\n const parser = new DOMParser();\n const dom = parser.parseFromString(html, 'text/html');\n\n /*\n * 清洗层已经把 code.language-* 归一到 pre[data-language],这里回到 Lexical 原生\n * HTML 导入,保留 H/P/List 的连续结构;后续只兜底修正 CodeNode 语言和空后续段落。\n */\n unwrapPreCodeChildren(dom.body);\n\n const nodes = $generateNodesFromDOM(editor, dom);\n\n applyCodeNodeLanguagesFromDom(nodes, dom.body);\n\n return nodes;\n};\n\nconst insertSanitizedHtmlNodes = (\n editor: PasteHtmlCleanupOptions['editor'],\n sanitizedHtml: string\n) => {\n const nodes = generateNodesFromSanitizedHtml(editor, sanitizedHtml);\n\n if (nodes.length === 0) return false;\n if (!$getSelection()) {\n $getRoot().selectEnd();\n }\n\n if (nodes.some($isCodeNode)) {\n /*\n * 混排块级 HTML 粘贴不能直接 `$insertNodes(nodes)` 到当前段落尾部,否则首个 H/P\n * 会和已有文本合并。这里统一插到最近 root 边界,保持外部文档的块级结构。\n */\n nodes.forEach((node) => {\n $insertNodeToNearestRoot(node);\n });\n const lastInsertedNode = nodes[nodes.length - 1] as CodeNode | undefined;\n\n if (lastInsertedNode && $isCodeNode(lastInsertedNode)) {\n $insertNodes([$createParagraphNode()]);\n }\n\n return true;\n }\n\n $insertNodes(nodes);\n return true;\n};\n\nconst handlePasteRichTextInput = (\n input: PasteInput,\n {\n editor,\n isReadonly\n }: Omit<PasteHtmlCleanupOptions, 'target'>\n) => {\n if (isReadonly()) return false;\n if (!input.html.trim()) return handlePastePlainTextInput(input, { editor, isReadonly });\n\n const sanitizedHtml = sanitizePastedHtml(input.html);\n\n if (!sanitizedHtml.trim()) return false;\n\n editor.update(() => {\n insertSanitizedHtmlNodes(editor, sanitizedHtml);\n });\n\n return true;\n};\n\nconst handlePastePlainTextInput = (\n input: PasteInput,\n {\n editor,\n isReadonly\n }: Omit<PasteHtmlCleanupOptions, 'target'>\n) => {\n if (isReadonly()) return false;\n if (input.html.trim()) return false;\n if (!input.text) return false;\n\n /*\n * happy-dom 和部分 WebView 不会在自定义 paste 事件里帮 contenteditable 插入纯文本。\n * 内置链路显式插入 TextNode,保留换行给 Lexical/RichText 插件拆成可编辑文本。\n */\n editor.update(() => {\n if (!$getSelection()) $getRoot().selectEnd();\n $insertNodes([$createTextNode(input.text)]);\n });\n\n return true;\n};\n\nconst preventNativePaste = (event: ClipboardEvent | DragEvent) => {\n event.preventDefault();\n /*\n * paste/drop 接管后同一个 contentElement 上的后续监听不能继续消费原始剪贴板。\n * stopPropagation 只能阻止冒泡,不能阻止同一 target、同一阶段后注册的 listener。\n */\n event.stopImmediatePropagation();\n};\n\n/**\n * 按 BridgeRTE 内置顺序处理 paste 摘要。\n *\n * 顺序固定为媒体文件、纯 URL、HTML 清洗、普通纯文本;自定义 paste hook 返回替换内容后\n * 也复用这条链路,避免业务接管和内置处理出现两套语义。\n */\nexport const handleBuiltInPasteInput = (\n input: PasteInput,\n options: Omit<PasteMediaOptions, 'target'> & Omit<PasteLinkOptions, 'target'>\n & Omit<PasteHtmlCleanupOptions, 'target'>\n) => (\n handlePasteMediaInput(input, options)\n || handlePasteLinkInput(input, options)\n || handlePasteRichTextInput(input, options)\n);\n\n/**\n * 纯文本代码片段只做高置信识别。\n *\n * 这条路径只接管明显像代码的纯文本,避免普通文章被误判成代码块;真正的高亮和语言\n * 还原仍交给 CodeNode + codeHighlight 管线。\n */\nexport const handlePlainTextCodeSnippetInput = (\n input: PasteInput,\n options: Omit<PasteHtmlCleanupOptions, 'target'>\n) => {\n if (options.isReadonly()) return false;\n if (!input.text.trim()) return false;\n if (!isPlainTextCodeSnippet(input.text)) return false;\n\n const language = input.text.trim().startsWith('<!DOCTYPE') || /<\\/?[a-z][\\w:-]*\\b/i.test(input.text)\n ? 'html'\n : 'text';\n\n options.editor.update(() => {\n const parser = new DOMParser();\n const dom = parser.parseFromString(\n `<pre data-language=\"${language}\"><code>${input.text\n .trim()\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')}</code></pre>`,\n 'text/html'\n );\n\n unwrapPreCodeChildren(dom.body);\n\n const nodes = $generateNodesFromDOM(options.editor, dom);\n\n if (nodes.length === 0) return;\n\n if (!$getSelection()) $getRoot().selectEnd();\n nodes.forEach((node) => {\n $insertNodeToNearestRoot(node);\n });\n if (nodes.some($isCodeNode)) {\n $insertNodes([$createParagraphNode()]);\n }\n });\n\n return true;\n};\n\n/**\n * 注册链接粘贴优先体验。\n *\n * 这里只处理“剪贴板纯文本是 URL”的窄场景:非 URL、HTML 粘贴、图片粘贴和完整清洗策略\n * 继续交给 Lexical/浏览器默认链路或第 8 期 paste cleanup,不在这个模块里提前吞掉事件。\n */\nexport const registerPasteLink = (options: PasteLinkOptions): (() => void) => {\n const handlePaste = (event: ClipboardEvent) => {\n if (event.defaultPrevented) return;\n if (!handlePasteLinkInput(getClipboardPasteInput(event.clipboardData), options)) return;\n\n preventNativePaste(event);\n };\n\n options.target.addEventListener('paste', handlePaste, { capture: true });\n\n return () => {\n options.target.removeEventListener('paste', handlePaste, { capture: true });\n };\n};\n\n/**\n * 注册第 8 期媒体输入管线的第一条路径:剪贴板和拖拽里的本地媒体文件。\n *\n * 这里只识别文件并交给第 7 期上传控制器;上传占位、进度、失败重试和删除仍由同一套\n * mediaUploader 承担,避免 paste/drop 重新实现一份上传状态机。\n */\nexport const registerPasteMedia = (options: PasteMediaOptions): (() => void) => {\n const handlePaste = (event: ClipboardEvent) => {\n if (event.defaultPrevented) return;\n if (!handlePasteMediaInput(getClipboardPasteInput(event.clipboardData), options)) return;\n\n preventNativePaste(event);\n };\n\n const handleDragOver = (event: DragEvent) => {\n if (options.isReadonly() || !options.canUploadMedia()) return;\n const files = event.dataTransfer?.files ? [...event.dataTransfer.files] : [];\n\n if (getMediaFiles(files).length === 0) {\n return;\n }\n\n event.preventDefault();\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'copy';\n };\n\n const handleDrop = (event: DragEvent) => {\n const input = {\n text: '',\n html: '',\n files: event.dataTransfer?.files ? [...event.dataTransfer.files] : []\n };\n\n if (!handlePasteMediaInput(input, options)) return;\n\n preventNativePaste(event);\n };\n\n options.target.addEventListener('paste', handlePaste, { capture: true });\n options.target.addEventListener('dragover', handleDragOver);\n options.target.addEventListener('drop', handleDrop);\n\n return () => {\n options.target.removeEventListener('paste', handlePaste, { capture: true });\n options.target.removeEventListener('dragover', handleDragOver);\n options.target.removeEventListener('drop', handleDrop);\n };\n};\n\n/**\n * 注册 HTML 粘贴清洗。\n *\n * 媒体文件和纯文本 URL 由更早注册的处理器先接管;走到这里的 HTML 会转换为安全基础节点,\n * 普通纯文本由同一条链路做兜底插入,覆盖 happy-dom 和部分 WebView 不触发原生插入的情况。\n */\nexport const registerPasteHtmlCleanup = (options: PasteHtmlCleanupOptions): (() => void) => {\n const handlePaste = (event: ClipboardEvent) => {\n if (\n event.defaultPrevented\n || !handlePasteRichTextInput(getClipboardPasteInput(event.clipboardData), options)\n ) {\n return;\n }\n\n preventNativePaste(event);\n };\n\n options.target.addEventListener('paste', handlePaste, { capture: true });\n\n return () => {\n options.target.removeEventListener('paste', handlePaste, { capture: true });\n };\n};\n\n/**\n * 注册业务自定义 paste hook。\n *\n * 返回 true 表示业务完全接管;返回 text/html 则把替换后的摘要继续交给 BridgeRTE 内置\n * URL、媒体和 HTML 清洗处理器。Promise 结果只用于异步接管,不会阻塞浏览器默认 paste。\n */\nexport const registerCustomPasteHook = ({\n target,\n isReadonly,\n onPaste,\n canUploadMedia,\n uploadMediaFile,\n executeCommand,\n editor\n}: CustomPasteHookOptions): (() => void) => {\n const handleReplacement = (input: PasteInput, result: { text?: string; html?: string }) => (\n handleBuiltInPasteInput({\n text: result.text ?? input.text,\n html: result.html ?? input.html,\n files: input.files\n }, {\n isReadonly,\n canUploadMedia,\n uploadMediaFile,\n executeCommand,\n editor\n })\n );\n\n const handlePaste = (event: ClipboardEvent) => {\n if (isReadonly() || !onPaste) return;\n\n const input = getClipboardPasteInput(event.clipboardData);\n const hookResult = onPaste({\n text: input.text,\n html: input.html,\n files: input.files.map(toUploadFileLike)\n });\n\n if (hookResult instanceof Promise) {\n preventNativePaste(event);\n hookResult.then((result) => {\n if (result === true) return;\n if (!result) return;\n\n handleReplacement(input, result);\n });\n return;\n }\n\n if (hookResult === true) {\n preventNativePaste(event);\n return;\n }\n\n if (!hookResult) return;\n\n preventNativePaste(event);\n handleReplacement(input, hookResult);\n };\n\n target.addEventListener('paste', handlePaste, { capture: true });\n\n return () => {\n target.removeEventListener('paste', handlePaste, { capture: true });\n };\n};\n","import type {\n MenuItem,\n SlashCommandDisplayItem,\n SlashCommandItem,\n SlashCommandMenuConfig,\n ToolbarConfig\n} from '@bridgerte/core';\nimport { resolveToolbarMenu } from '@bridgerte/native-spec';\n\nexport const defaultSlashCommandKeys = [\n 'paragraph',\n 'heading-1',\n 'heading-2',\n 'heading-3',\n 'quote',\n 'code-block',\n 'ordered-list',\n 'unordered-list',\n 'todo-list',\n 'divider',\n 'upload-image',\n 'upload-video',\n 'table'\n];\n\nexport const defaultSlashCommandConfig: Required<SlashCommandMenuConfig> = {\n loadingText: '加载中',\n emptyText: '没有匹配的命令',\n errorText: '命令加载失败'\n};\n\nexport const resolveSlashCommandMenuConfig = (\n config?: SlashCommandMenuConfig\n): Required<SlashCommandMenuConfig> => ({\n ...defaultSlashCommandConfig,\n ...config\n});\n\nconst flattenMenuItems = (items: ReturnType<typeof resolveToolbarMenu>) => items.flatMap((item) => (\n item.type === 'button' ? [item.item]\n : item.type === 'group' ? item.items\n : []\n));\n\nconst createSlashCommandConfig = (\n config?: ToolbarConfig\n): ToolbarConfig => ({\n ...config,\n toolbarKeys: config?.toolbarKeys ?? defaultSlashCommandKeys\n});\n\nconst toSlashCommandItem = (\n item: MenuItem\n): SlashCommandDisplayItem => ({\n id: item.id,\n label: item.label,\n command: item.command,\n icon: item.icon,\n requiresPayload: item.requiresPayload,\n payloadPanel: item.payloadPanel,\n group: item.group,\n source: 'schema'\n});\n\n/**\n * 把 schema/config 解析成 slash command 静态候选。\n *\n * slash command 只消费稳定 `MenuItem` 协议:命令、payloadPanel、icon 和 label 仍由\n * schema/config 决定;DOM 默认菜单和业务自绘 request 共享这里的结果。\n */\nexport const resolveStaticSlashCommandItems = (\n menuSchema: MenuItem[],\n config?: ToolbarConfig\n) => flattenMenuItems(resolveToolbarMenu(\n createSlashCommandConfig(config),\n menuSchema\n)).map(toSlashCommandItem);\n\nexport const toProviderSlashCommandItem = (\n item: SlashCommandItem\n): SlashCommandDisplayItem => ({\n ...item,\n source: 'provider'\n});\n","import {\n $getNodeByKey,\n $getSelection,\n $isRangeSelection,\n TextNode\n} from 'lexical';\nimport {\n defaultMenuSchema\n} from '@bridgerte/native-spec';\nimport type {\n SlashCommandDisplayItem,\n SlashCommandItem,\n SlashCommandMenuAnchorRect,\n SlashCommandStatus\n} from '@bridgerte/core';\nimport {\n findTextNodeWithOffset,\n registerFloatingPicker\n} from '../floatingPicker';\nimport type { FloatingPickerTrigger } from '../floatingPicker';\nimport {\n appendMenuIcon,\n defaultMenuIcons\n} from '../menuIcon';\nimport { resolveMenuSchemaForDom } from '../menuRuntime';\nimport {\n resolveSlashCommandMenuConfig,\n resolveStaticSlashCommandItems,\n toProviderSlashCommandItem\n} from './config';\nimport type {\n SlashCommandControllerOptions\n} from './type';\n\nexport type * from './type';\n\nconst slashQueryRegExp = /(?:^|\\s)\\/([\\p{L}\\p{N}_-]*)$/u;\n\nconst normalizeSearchText = (value: string) => value.trim().toLowerCase();\n\nconst getCommandSearchText = (item: SlashCommandItem) => (\n [item.label, item.id, item.description, item.group, ...(item.keywords ?? [])]\n .filter(Boolean)\n .join(' ')\n .toLowerCase()\n);\n\nconst filterSlashCommandItems = (\n items: SlashCommandDisplayItem[],\n query: string\n) => {\n const normalizedQuery = normalizeSearchText(query);\n\n if (!normalizedQuery) return items;\n\n return items.filter((item) => getCommandSearchText(item).includes(normalizedQuery));\n};\n\nconst getProviderItems = async (\n query: string,\n slashCommandProvider: SlashCommandControllerOptions['slashCommandProvider']\n) => {\n const items = await Promise.resolve(slashCommandProvider?.(query) ?? []);\n\n return items.map(toProviderSlashCommandItem);\n};\n\nconst normalizeSubmittedSlashCommandItem = (\n item: SlashCommandDisplayItem | SlashCommandItem\n) => (\n 'source' in item ? item : toProviderSlashCommandItem(item)\n);\n\nconst hasConfiguredStaticSlashCommands = ({\n menuSchema,\n slashCommandConfig\n}: Pick<SlashCommandControllerOptions, 'menuSchema' | 'slashCommandConfig'>) => (\n menuSchema !== undefined || slashCommandConfig !== undefined\n);\n\nconst getCurrentSlashTrigger = (): FloatingPickerTrigger | null => {\n const selection = $getSelection();\n\n if (!$isRangeSelection(selection) || !selection.isCollapsed()) return null;\n\n const anchor = selection.anchor;\n const anchorNode = anchor.getNode();\n\n if (!(anchorNode instanceof TextNode)) return null;\n\n const textBeforeCursor = anchorNode.getTextContent().slice(0, anchor.offset);\n const match = textBeforeCursor.match(slashQueryRegExp);\n\n if (!match) return null;\n\n const query = match[1] ?? '';\n const matchText = match[0] ?? '';\n const leadingWhitespace = matchText.startsWith('/') ? 0 : 1;\n const startOffset = anchor.offset - matchText.length + leadingWhitespace;\n\n return {\n query,\n nodeKey: anchorNode.getKey(),\n startOffset,\n endOffset: anchor.offset\n };\n};\n\nconst createSlashMenuElement = () => {\n const menu = document.createElement('div');\n\n menu.className = 'bridgerte__floating-menu bridgerte__slash-command-menu';\n menu.dataset.visible = 'false';\n\n return menu;\n};\n\nconst createSlashAnchorElement = () => {\n const anchor = document.createElement('span');\n\n anchor.className = 'bridgerte__slash-command-anchor';\n anchor.setAttribute('aria-hidden', 'true');\n\n return anchor;\n};\n\nconst getSlashTriggerRect = (\n editor: SlashCommandControllerOptions['editor'],\n trigger: FloatingPickerTrigger\n) => {\n const element = editor.getElementByKey(trigger.nodeKey);\n /*\n * Lexical TextNode 的 DOM 在不同编辑状态下可能不是 element.firstChild。\n * 递归找能覆盖 trigger offset 的真实 Text,避免失败后退回编辑区底部导致菜单离光标很远。\n */\n const textNode = findTextNodeWithOffset(element, trigger.startOffset + 1);\n\n if (!(textNode instanceof Text)) return null;\n\n const range = document.createRange();\n const triggerEndOffset = Math.min(trigger.startOffset + 1, textNode.textContent?.length ?? 0);\n\n if (triggerEndOffset <= trigger.startOffset) return null;\n\n /*\n * slash menu 的视觉锚点是 `/` 触发符,不是 query 末尾光标。\n * 否则输入 `/引用` 时菜单会跟着文字宽度右移,看起来像位置漂移。\n */\n range.setStart(textNode, trigger.startOffset);\n range.setEnd(textNode, triggerEndOffset);\n\n return range.getBoundingClientRect();\n};\n\nconst createSlashMenuItemElement = (\n item: SlashCommandDisplayItem,\n index: number,\n active: boolean,\n icons: NonNullable<SlashCommandControllerOptions['icons']>\n) => {\n const button = document.createElement('button');\n const title = document.createElement('span');\n\n button.type = 'button';\n button.className = 'bridgerte__menu-item bridgerte__slash-command-item';\n button.dataset.commandId = item.id;\n button.dataset.index = String(index);\n button.dataset.active = String(active);\n\n if (item.icon) {\n const icon = document.createElement('span');\n\n icon.className = 'bridgerte__slash-command-item-icon';\n icon.setAttribute('aria-hidden', 'true');\n appendMenuIcon(icon, icons[item.icon] ?? defaultMenuIcons[item.icon], item.label);\n button.append(icon);\n }\n\n title.className = 'bridgerte__slash-command-item-title';\n title.textContent = item.label;\n button.append(title);\n\n if (item.description) {\n const description = document.createElement('span');\n\n description.className = 'bridgerte__slash-command-item-description';\n description.textContent = item.description;\n button.append(description);\n }\n\n return button;\n};\n\nconst createSlashStatusElement = (\n status: Exclude<SlashCommandStatus, 'success'>,\n text: string\n) => {\n const element = document.createElement('div');\n\n element.className = 'bridgerte__slash-command-status';\n element.dataset.status = status;\n element.textContent = text;\n\n return element;\n};\n\nconst getSlashStatusText = (\n status: Exclude<SlashCommandStatus, 'success'>,\n config: ReturnType<typeof resolveSlashCommandMenuConfig>\n) => {\n switch (status) {\n case 'loading':\n return config.loadingText;\n case 'empty':\n return config.emptyText;\n case 'error':\n return config.errorText;\n }\n};\n\nconst serializeSlashAnchorRect = (\n rect?: DOMRect\n): SlashCommandMenuAnchorRect | undefined => (\n rect\n ? {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height\n }\n : undefined\n);\n\n/**\n * 注册 DOM 默认 slash command。\n *\n * 默认候选来自 `menuSchema + slashCommandConfig`;旧 `slashCommandProvider` 单独使用时继续\n * 替换候选源,配置化开启后 provider 作为动态追加项合并,避免破坏已有业务。\n */\nexport const registerSlashCommand = ({\n editorRoot,\n contentElement,\n editor,\n isReadonly,\n executeCommand,\n requestPayloadPanel,\n menuSchema: rawMenuSchema,\n slashCommandConfig,\n icons = {},\n menuLabels,\n payloadPanelConfig,\n slashCommandMenuConfig,\n onSlashCommandMenuRequest,\n slashCommandProvider\n}: SlashCommandControllerOptions): (() => void) => {\n const menu = createSlashMenuElement();\n const anchor = createSlashAnchorElement();\n const resolvedSlashCommandMenuConfig = resolveSlashCommandMenuConfig(slashCommandMenuConfig);\n const menuSchema = resolveMenuSchemaForDom(rawMenuSchema ?? defaultMenuSchema, {\n menuLabels,\n payloadPanelConfig\n });\n const staticItems = resolveStaticSlashCommandItems(menuSchema, slashCommandConfig);\n const staticItemMap = new Map(menuSchema.map((item) => [item.id, item]));\n const shouldMergeProviderItems = hasConfiguredStaticSlashCommands({\n menuSchema: rawMenuSchema,\n slashCommandConfig\n });\n\n const removeTriggerText = (trigger: FloatingPickerTrigger) => {\n editor.update(() => {\n /*\n * 真实浏览器里点击/回车执行菜单时,button 聚焦、IME 或 Lexical update listener 都可能\n * 让当前 selection 短暂漂移。trigger 记录原 TextNode key,执行时回到原节点删除 `/query`。\n */\n const triggerNode = $getNodeByKey(trigger.nodeKey);\n\n if (!(triggerNode instanceof TextNode)) return;\n\n triggerNode.spliceText(trigger.startOffset, trigger.endOffset - trigger.startOffset, '');\n triggerNode.select(trigger.startOffset, trigger.startOffset);\n });\n };\n\n const selectItem = (item: SlashCommandDisplayItem, trigger: FloatingPickerTrigger) => {\n removeTriggerText(trigger);\n\n const schemaItem = item.source === 'schema' ? staticItemMap.get(item.id) : undefined;\n\n if (schemaItem?.payloadPanel) {\n const anchorRect = getSlashTriggerRect(editor, trigger);\n\n /*\n * 带 payloadPanel 的 slash command 只负责删除触发文本和发起统一参数请求。\n * 具体默认 DOM 面板、业务自绘、readonly 和命令合成仍交给 payloadPanel 控制器。\n */\n requestPayloadPanel({\n menuId: schemaItem.id,\n command: schemaItem.command,\n panel: schemaItem.payloadPanel,\n anchorRect: serializeSlashAnchorRect(anchorRect ?? undefined)\n });\n return;\n }\n\n executeCommand(item.command);\n };\n\n const resolveItems = async (query: string) => {\n const baseItems = shouldMergeProviderItems || !slashCommandProvider\n ? filterSlashCommandItems(staticItems, query)\n : [];\n\n try {\n const providerItems = await getProviderItems(query, slashCommandProvider);\n\n return [...baseItems, ...providerItems];\n } catch (error) {\n /*\n * schema/config 静态命令是 slash command 的基础能力,provider 只是动态追加。\n * provider 失败时如果静态命令已能响应当前 query,就继续展示静态项;只有完全依赖\n * provider 或静态项无命中时,才把错误交给 floatingPicker 渲染 error 状态。\n */\n if (baseItems.length > 0) return baseItems;\n\n throw error;\n }\n };\n\n const picker = registerFloatingPicker({\n editorRoot,\n contentElement,\n editor,\n isReadonly,\n menu,\n anchor,\n itemSelector: '.bridgerte__slash-command-item',\n getCurrentTrigger: getCurrentSlashTrigger,\n getTriggerRect: (trigger) => getSlashTriggerRect(editor, trigger),\n resolveItems,\n renderItem: (item, index, active) => createSlashMenuItemElement(\n item,\n index,\n active,\n icons\n ),\n renderStatus: (status) => createSlashStatusElement(\n status,\n getSlashStatusText(status, resolvedSlashCommandMenuConfig)\n ),\n onStateChange: onSlashCommandMenuRequest\n ? (state, helpers) => onSlashCommandMenuRequest({\n id: `bridgerte-slash-command-menu-${state.requestId}`,\n query: state.trigger.query,\n status: state.status,\n items: state.items,\n config: resolvedSlashCommandMenuConfig,\n readonly: isReadonly(),\n anchorRect: serializeSlashAnchorRect(helpers.anchorRect),\n ...(state.error ? { error: state.error } : {}),\n submit: (item) => helpers.selectItem(normalizeSubmittedSlashCommandItem(item)),\n cancel: helpers.close\n })\n : undefined,\n onSelect: selectItem\n });\n\n return picker.destroy;\n};\n","import { $isListItemNode } from '@lexical/list';\nimport { $getNearestNodeFromDOMNode } from 'lexical';\nimport type { TodoListMarkerOptions } from './type';\n\nexport type * from './type';\n\nconst todoListMarkerHitWidth = 32;\n\nconst isTodoListItemElement = (target: EventTarget | null): target is HTMLElement => (\n target instanceof HTMLElement\n && target.getAttribute('role') === 'checkbox'\n && target.parentElement?.classList.contains('bridgerte__list--todo') === true\n);\n\nconst getTodoListItemElement = (target: EventTarget | null): HTMLElement | null => (\n target instanceof HTMLElement ? target.closest<HTMLElement>('[role=\"checkbox\"]') : null\n);\n\nconst getTodoListItemNode = (target: HTMLElement) => $getNearestNodeFromDOMNode(target);\n\nconst isPrimaryMouseEvent = (event: MouseEvent | PointerEvent) => event.button === 0;\n\nconst isInsideTodoMarkerArea = (event: MouseEvent | PointerEvent, target: HTMLElement) => {\n const rect = target.getBoundingClientRect();\n\n return target.dir === 'rtl'\n ? event.clientX >= rect.right - todoListMarkerHitWidth && event.clientX <= rect.right\n : event.clientX >= rect.left && event.clientX <= rect.left + todoListMarkerHitWidth;\n};\n\nconst stopTodoListNativeEvent = (event: Event) => {\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n};\n\n/**\n * 接管待办列表 marker 点击。\n *\n * Lexical 默认 checklist 使用 16px `::before` 命中区,并带 500ms 去重窗口,PC 快速\n * 连点会被吞。这里只接管左侧 marker 区域,仍调用 ListItemNode.toggleChecked(),\n * 不直接改 DOM class,确保 undo、序列化和 command state 继续由 Lexical 管理。\n */\nexport const registerTodoListMarker = ({\n contentElement,\n editor,\n isReadonly\n}: TodoListMarkerOptions): (() => void) => {\n let lastTouchToggleTime = 0;\n\n const handlePointerDown = (event: PointerEvent) => {\n if (isReadonly() || !isPrimaryMouseEvent(event)) return;\n\n const itemElement = getTodoListItemElement(event.target);\n\n if (!itemElement || !isTodoListItemElement(itemElement)) return;\n if (!isInsideTodoMarkerArea(event, itemElement)) return;\n\n // 只阻止 Lexical 原生 checklist 的 focus/去重链路,真正切换放在 click/pointerup。\n stopTodoListNativeEvent(event);\n };\n\n const toggleItem = (event: MouseEvent | PointerEvent, itemElement: HTMLElement) => {\n stopTodoListNativeEvent(event);\n editor.update(() => {\n const itemNode = getTodoListItemNode(itemElement);\n\n if ($isListItemNode(itemNode)) {\n itemNode.toggleChecked();\n }\n });\n };\n\n const handleClick = (event: MouseEvent) => {\n if (isReadonly() || !isPrimaryMouseEvent(event)) return;\n if (Date.now() - lastTouchToggleTime < 700) return;\n\n const itemElement = getTodoListItemElement(event.target);\n\n if (!itemElement || !isTodoListItemElement(itemElement)) return;\n if (!isInsideTodoMarkerArea(event, itemElement)) return;\n\n toggleItem(event, itemElement);\n };\n\n const handlePointerUp = (event: PointerEvent) => {\n if (isReadonly() || event.pointerType !== 'touch') return;\n\n const itemElement = getTodoListItemElement(event.target);\n\n if (!itemElement || !isTodoListItemElement(itemElement)) return;\n if (!isInsideTodoMarkerArea(event, itemElement)) return;\n\n lastTouchToggleTime = Date.now();\n toggleItem(event, itemElement);\n };\n\n contentElement.addEventListener('pointerdown', handlePointerDown, true);\n contentElement.addEventListener('pointerup', handlePointerUp, true);\n contentElement.addEventListener('click', handleClick, true);\n\n return () => {\n contentElement.removeEventListener('pointerdown', handlePointerDown, true);\n contentElement.removeEventListener('pointerup', handlePointerUp, true);\n contentElement.removeEventListener('click', handleClick, true);\n };\n};\n","import {\n CAN_REDO_COMMAND,\n CAN_UNDO_COMMAND,\n COMMAND_PRIORITY_LOW,\n SELECTION_CHANGE_COMMAND,\n mergeRegister\n} from 'lexical';\nimport {\n PrismTokenizer,\n registerCodeHighlighting\n} from '@lexical/code';\nimport { registerRichText } from '@lexical/rich-text';\nimport { registerHistory } from '@lexical/history';\nimport {\n registerCheckList,\n registerList\n} from '@lexical/list';\nimport { registerTablePlugin } from '@lexical/table';\nimport { registerBridgeAutoLink } from '../autoLink';\nimport { registerClipboardCopy } from '../clipboard';\nimport { registerHoverbar } from '../hoverbar';\nimport { registerKeyboardShortcuts } from '../keyboardShortcuts';\nimport { registerMention } from '../mention';\nimport {\n registerCustomPasteHook,\n registerPasteHtmlCleanup,\n registerPasteLink,\n registerPasteMedia\n} from '../paste';\nimport { registerPlaceholderFocus } from '../placeholder';\nimport { registerSlashCommand } from '../slashCommand';\nimport { registerTodoListMarker } from '../todoList';\nimport { LEXICAL_HISTORY_MERGE_DELAY_MS } from './constants';\nimport type {\n RichTextEditorPluginOptions,\n RichTextEditorPluginRuntime\n} from './type';\n\n/*\n * BridgeRTE 的默认代码块仍然是“纯文本”。Lexical/Prism 默认会给无语言代码块补\n * javascript,这会让 header、payload currentValues 和导出语义都偏离旧行为;\n * 只把 fallback 关掉,具体 tokenize 仍完全委托给官方 Prism tokenizer。\n */\nconst bridgerteCodeTokenizer: typeof PrismTokenizer = {\n ...PrismTokenizer,\n defaultLanguage: null\n};\n\nconst isFloatingMenuEnabled = (\n options: RichTextEditorPluginOptions['options'],\n key: 'mention' | 'slash' | 'hoverbar'\n) => options.floatingMenus?.[key] !== false;\n\n/**\n * 注册 DOM 编辑器的 Lexical 插件和命令监听。\n *\n * 这个模块只负责挂载/卸载监听,不拥有 editor public API。新增插件时优先放进这里,\n * 让 `richTextEditor/index.ts` 保持实例编排,不继续堆注册细节。\n */\nexport const registerRichTextEditorPlugins = ({\n options,\n lexicalEditor,\n editorRoot,\n contentElement,\n historyState,\n isReadonly,\n executeCommand,\n requestPayloadPanel,\n uploadMediaFile,\n canUploadMedia,\n syncAfterEditorUpdate,\n refreshCommandStates,\n getCommandStates,\n setCanUndo,\n setCanRedo,\n enableKeyboardShortcuts\n}: RichTextEditorPluginOptions): RichTextEditorPluginRuntime => {\n const enableMention = isFloatingMenuEnabled(options, 'mention');\n const enableSlash = isFloatingMenuEnabled(options, 'slash');\n const enableHoverbar = isFloatingMenuEnabled(options, 'hoverbar');\n\n /*\n * floatingMenus 是 DOM 默认浮层菜单的统一开关。默认保持开箱可用;业务在 H5/WebView\n * 自绘或软键盘敏感场景下显式关闭时,只跳过对应插件注册,不影响底层 command API。\n */\n /*\n * Lexical 插件、命令监听和 selection 监听统一交给 mergeRegister 管理。\n * destroy 时只调用一次 unregister,避免新增插件后遗漏单独清理逻辑。\n */\n const unregister = mergeRegister(\n /*\n * 业务自定义 paste hook 最先看到原始剪贴板摘要;返回 undefined 时完全不拦截,\n * 继续走 BridgeRTE 内置媒体、URL 和 HTML 清洗链路。\n */\n registerCustomPasteHook({\n target: contentElement,\n isReadonly,\n onPaste: options.onPaste,\n canUploadMedia,\n uploadMediaFile,\n executeCommand,\n editor: lexicalEditor\n }),\n /*\n * 媒体文件粘贴/拖拽优先于 URL 粘贴快速路径;剪贴板里有文件时直接进入上传管线,\n * 没有文件再交给纯文本 URL 链接处理或 Lexical 默认粘贴。\n */\n registerPasteMedia({\n target: contentElement,\n isReadonly,\n canUploadMedia,\n uploadMediaFile\n }),\n /*\n * URL 粘贴是 BridgeRTE 的高意图快捷路径,必须先于 Lexical 默认 paste 监听注册。\n * 否则 Lexical 会先把 URL 当普通文本插入,后续就失去“选区变链接”的语义。\n */\n registerPasteLink({\n target: contentElement,\n isReadonly,\n executeCommand\n }),\n /*\n * HTML 清洗放在媒体和纯文本 URL 之后、Lexical 默认 rich text paste 之前。\n * 这样外部网页/办公软件片段会先进入 BridgeRTE 白名单清洗,再转成 Lexical 节点。\n */\n registerPasteHtmlCleanup({\n target: contentElement,\n editor: lexicalEditor,\n isReadonly\n }),\n registerClipboardCopy({\n target: contentElement,\n isReadonly\n }),\n registerRichText(lexicalEditor),\n /*\n * 代码块高亮使用 Lexical 官方 Prism 管线。CodeNode 只保存语言和文本,真正的 token\n * 拆分、Tab/缩进处理和 data-highlight-language 都由这里注册;无语言时保持纯文本。\n */\n registerCodeHighlighting(lexicalEditor, bridgerteCodeTokenizer),\n registerHistory(lexicalEditor, historyState, LEXICAL_HISTORY_MERGE_DELAY_MS),\n registerList(lexicalEditor),\n registerCheckList(lexicalEditor),\n registerTodoListMarker({\n contentElement,\n editor: lexicalEditor,\n isReadonly\n }),\n enableMention\n ? registerMention({\n editorRoot,\n contentElement,\n editor: lexicalEditor,\n isReadonly,\n executeCommand,\n mentionProvider: options.mentionProvider,\n mentionMenuConfig: options.mentionMenuConfig,\n onMentionMenuRequest: options.onMentionMenuRequest\n })\n : () => undefined,\n enableHoverbar\n ? registerHoverbar({\n editorRoot,\n contentElement,\n editor: lexicalEditor,\n isReadonly,\n executeCommand,\n requestPayloadPanel,\n getCommandStates,\n menuSchema: options.menuSchema,\n hoverbarConfig: options.hoverbarConfig,\n icons: options.icons,\n menuLabels: options.menuLabels,\n payloadPanelConfig: options.payloadPanelConfig\n })\n : () => undefined,\n registerTablePlugin(lexicalEditor),\n registerBridgeAutoLink({ editor: lexicalEditor }),\n enableSlash\n ? registerSlashCommand({\n editorRoot,\n contentElement,\n editor: lexicalEditor,\n isReadonly,\n executeCommand,\n requestPayloadPanel,\n menuSchema: options.menuSchema,\n slashCommandConfig: options.slashCommandConfig,\n icons: options.icons,\n menuLabels: options.menuLabels,\n payloadPanelConfig: options.payloadPanelConfig,\n slashCommandMenuConfig: options.slashCommandMenuConfig,\n onSlashCommandMenuRequest: options.onSlashCommandMenuRequest,\n slashCommandProvider: options.slashCommandProvider\n })\n : () => undefined,\n registerPlaceholderFocus({\n editor: lexicalEditor,\n contentElement,\n isReadonly\n }),\n enableKeyboardShortcuts\n ? registerKeyboardShortcuts({\n target: contentElement,\n isReadonly,\n executeCommand\n })\n : () => undefined,\n lexicalEditor.registerUpdateListener(() => {\n syncAfterEditorUpdate();\n refreshCommandStates();\n }),\n lexicalEditor.registerCommand(\n SELECTION_CHANGE_COMMAND,\n () => {\n refreshCommandStates();\n return false;\n },\n COMMAND_PRIORITY_LOW\n ),\n lexicalEditor.registerCommand(\n CAN_UNDO_COMMAND,\n (payload) => {\n setCanUndo(payload);\n return false;\n },\n COMMAND_PRIORITY_LOW\n ),\n lexicalEditor.registerCommand(\n CAN_REDO_COMMAND,\n (payload) => {\n setCanRedo(payload);\n return false;\n },\n COMMAND_PRIORITY_LOW\n )\n );\n\n return {\n destroy() {\n unregister();\n }\n };\n};\n","import {\n CLEAR_HISTORY_COMMAND,\n createEditor\n} from 'lexical';\nimport {\n HeadingNode,\n QuoteNode\n} from '@lexical/rich-text';\nimport { CodeHighlightNode, CodeNode } from '@lexical/code';\nimport {\n ListItemNode,\n ListNode\n} from '@lexical/list';\nimport {\n TableCellNode,\n TableNode,\n TableRowNode,\n setScrollableTablesActive\n} from '@lexical/table';\nimport { AutoLinkNode, LinkNode } from '@lexical/link';\nimport { createEmptyHistoryState } from '@lexical/history';\nimport {\n type EditorAPI,\n type EditorCommand,\n type MediaDisplayWidthPercent,\n type PayloadPanelOpenRequest,\n type RichTextEditorOptions\n} from '@bridgerte/core';\nimport {\n applyContentToEditor,\n createEmptyContent,\n normalizeInitialContent\n} from '../contentModel';\nimport { DividerNode } from '../dividerNode';\nimport { BridgeMediaNode } from '../mediaNode';\nimport { MentionNode } from '../mentionNode';\nimport { defaultPlaceholder, syncPlaceholderState } from '../placeholder';\nimport {\n createRichTextToolbar,\n type RichTextToolbarAPI,\n type RichTextToolbarPlacement\n} from '../richTextToolbar';\nimport { createRichTextEditorCommandStateRuntime } from './commandStateRuntime';\nimport { createRichTextEditorCommandExecutor } from './commandExecutor';\nimport { LEXICAL_EDITOR_NAMESPACE } from './constants';\nimport { createRichTextEditorContentSync } from './contentSync';\nimport { createRichTextEditorControllers } from './controllers';\nimport { createRichTextEditorDom } from './dom';\nimport {\n notifyBlur,\n notifyFocus,\n notifyReady,\n reportEditorError\n} from './errorReporter';\nimport { lexicalTheme } from './lexicalTheme';\nimport { createPayloadPanelSelectionStore } from './payloadPanelSelection';\nimport { registerRichTextEditorPlugins } from './plugins';\n\n/**\n * 创建浏览器 DOM 编辑器实例。\n * Lexical 只作为内部编辑器内核,public API 继续保持 BridgeRTE 的跨端契约。\n */\nexport function createRichTextEditor(\n container: HTMLElement,\n options: RichTextEditorOptions = {}\n): EditorAPI {\n const historyState = createEmptyHistoryState();\n const toolbarMode = options.toolbarMode ?? 'top';\n const mediaDefaultWidthPercent: MediaDisplayWidthPercent = options.mediaDefaultWidthPercent ?? 50;\n const shouldRenderToolbar = toolbarMode === 'top' || toolbarMode === 'bottom';\n const toolbarPlacement: RichTextToolbarPlacement = toolbarMode === 'bottom' ? 'bottom' : 'top';\n const {\n toolbarElement,\n contentElement\n } = createRichTextEditorDom(container, {\n placeholder: options.placeholder ?? defaultPlaceholder,\n shouldRenderToolbar,\n toolbarPlacement\n });\n // 快捷键是 DOM 端可选增强,默认不注册,避免 H5/WebView 或宿主项目快捷键被意外拦截。\n const enableKeyboardShortcuts = options.keyboardShortcuts === true;\n let readonly = options.readonly ?? false;\n let destroyed = false;\n let builtinToolbar: RichTextToolbarAPI | null = null;\n let content = createEmptyContent(options.value);\n\n const lexicalEditor = createEditor({\n namespace: LEXICAL_EDITOR_NAMESPACE,\n editable: !readonly,\n nodes: [\n HeadingNode,\n QuoteNode,\n CodeNode,\n CodeHighlightNode,\n ListNode,\n ListItemNode,\n TableNode,\n TableRowNode,\n TableCellNode,\n LinkNode,\n AutoLinkNode,\n DividerNode,\n BridgeMediaNode,\n MentionNode\n ],\n theme: lexicalTheme,\n onError: (error) => {\n reportEditorError(options, 'lexical.runtime', 'Lexical runtime error.', error);\n }\n });\n setScrollableTablesActive(lexicalEditor, true);\n\n const isDestroyed = () => destroyed;\n const isReadonly = () => readonly;\n const syncPlaceholder = () => {\n if (isDestroyed()) return;\n\n /*\n * placeholder 只展示“当前是否真的空”,不参与内容协议和 HTML 序列化。\n * 这样输入、清空、setContent 之后都能复用同一套轻量状态判断。\n */\n syncPlaceholderState({ editor: lexicalEditor, contentElement });\n };\n const payloadPanelSelectionStore = createPayloadPanelSelectionStore({ editor: lexicalEditor });\n const contentSync = createRichTextEditorContentSync({\n lexicalEditor,\n options,\n isDestroyed,\n setContent: (nextContent) => {\n content = nextContent;\n },\n syncPlaceholder\n });\n const commandStateRuntime = createRichTextEditorCommandStateRuntime({\n lexicalEditor,\n options,\n isDestroyed,\n canUploadMedia: () => options.uploadAdapter !== undefined,\n isReadonly\n });\n const executeEditorCommand = createRichTextEditorCommandExecutor({\n container,\n lexicalEditor,\n options,\n isDestroyed,\n isReadonly,\n reportError: reportEditorError\n });\n const syncEditableState = () => {\n contentElement.contentEditable = String(!readonly);\n lexicalEditor.setEditable(!readonly);\n };\n const getPayloadPanelClearCommand = (\n request: PayloadPanelOpenRequest\n ): EditorCommand | null => {\n /*\n * 清除按钮只负责清掉当前参数面板管理的 payload,不等同于 format.clear。\n * 这样用户打开文字颜色、背景色、字体、字号或行高时,可以只恢复这一项样式。\n */\n switch (request.command.type) {\n case 'format.color':\n case 'format.backgroundColor':\n case 'format.fontSize':\n case 'format.fontFamily':\n case 'format.lineHeight':\n return { ...request.command, value: '' };\n default:\n return null;\n }\n };\n const controllers = createRichTextEditorControllers({\n editorRoot: container,\n lexicalEditor,\n isReadonly,\n restoreEditorFocus: (callback) => {\n payloadPanelSelectionStore.restore();\n lexicalEditor.focus(callback);\n },\n executeCommand: executeEditorCommand,\n getClearCommand: getPayloadPanelClearCommand,\n codeBlockLanguagePanel: options.codeBlockLanguagePanel,\n payloadPanelConfig: options.payloadPanelConfig,\n mediaControlsConfig: options.mediaControlsConfig,\n menuLabels: options.menuLabels,\n onRequest: options.onPayloadPanelRequest,\n defaultMediaWidthPercent: mediaDefaultWidthPercent\n });\n const handleFocus = () => notifyFocus(options);\n const handleBlur = () => notifyBlur(options);\n const requestPayloadPanel: EditorAPI['requestPayloadPanel'] = (request) => {\n if (isDestroyed()) return;\n\n payloadPanelSelectionStore.capture();\n controllers.payloadPanelController.open(request);\n };\n\n container.dataset.readonly = String(readonly);\n container.addEventListener('focusin', handleFocus);\n container.addEventListener('focusout', handleBlur);\n /*\n * 未单独设置尺寸的媒体节点默认按 50% 展示;业务可通过 public option 改默认值。\n * 单个媒体点击 20/50/100 后会在节点内写入同名 CSS 变量,优先级高于容器默认值。\n */\n container.style.setProperty(\n '--bridgerte-media-display-width',\n `${mediaDefaultWidthPercent}%`\n );\n\n const plugins = registerRichTextEditorPlugins({\n options,\n lexicalEditor,\n editorRoot: container,\n contentElement,\n historyState,\n isReadonly,\n executeCommand: executeEditorCommand,\n requestPayloadPanel,\n uploadMediaFile: executeEditorCommand.uploadMediaFile,\n canUploadMedia: () => options.uploadAdapter !== undefined,\n syncAfterEditorUpdate: contentSync.syncAfterEditorUpdate,\n refreshCommandStates: commandStateRuntime.refreshCommandStates,\n getCommandStates: commandStateRuntime.getCommandStates,\n setCanUndo: commandStateRuntime.setCanUndo,\n setCanRedo: commandStateRuntime.setCanRedo,\n enableKeyboardShortcuts\n });\n\n lexicalEditor.setRootElement(contentElement);\n contentSync.suppressNextChange();\n content = normalizeInitialContent(lexicalEditor, options.value);\n syncEditableState();\n\n const api: EditorAPI = {\n getContent() {\n if (isDestroyed()) return content;\n\n // 主动读取时立即清掉待触发的变更通知,保证返回值代表最新 editorState。\n contentSync.clearContentChangeTimer();\n contentSync.syncContent(false);\n\n return content;\n },\n setContent(nextContent) {\n if (isDestroyed()) return;\n\n contentSync.clearContentChangeTimer();\n content = createEmptyContent(nextContent);\n // setContent 是宿主主动写入,不应该再被 Lexical update listener 当成一次用户输入。\n contentSync.suppressNextChange();\n applyContentToEditor(lexicalEditor, content);\n contentSync.enforceCurrentMaxLength();\n syncPlaceholder();\n lexicalEditor.dispatchCommand(CLEAR_HISTORY_COMMAND, undefined);\n commandStateRuntime.setHistoryAvailability(false, false);\n contentSync.syncContent(true);\n },\n executeCommand(command: EditorCommand) {\n executeEditorCommand(command);\n },\n requestPayloadPanel,\n getCommandStates: commandStateRuntime.getCommandStates,\n subscribeCommandStateChange: commandStateRuntime.subscribeCommandStateChange,\n setReadonly(nextReadonly) {\n if (isDestroyed()) return;\n\n readonly = nextReadonly;\n container.dataset.readonly = String(readonly);\n syncEditableState();\n commandStateRuntime.refreshCommandStates();\n },\n focus() {\n if (isDestroyed()) return;\n\n lexicalEditor.focus();\n },\n blur() {\n if (isDestroyed()) return;\n\n contentElement.blur();\n },\n destroy() {\n if (isDestroyed()) return;\n\n destroyed = true;\n contentSync.clearContentChangeTimer();\n // 自动创建的 toolbar 由 editor 管理;业务独立创建的 toolbar 需要业务自己 destroy。\n builtinToolbar?.destroy();\n builtinToolbar = null;\n controllers.destroy();\n executeEditorCommand.destroy();\n commandStateRuntime.destroy();\n payloadPanelSelectionStore.clear();\n plugins.destroy();\n lexicalEditor.setRootElement(null);\n container.removeEventListener('focusin', handleFocus);\n container.removeEventListener('focusout', handleBlur);\n container.classList.remove('bridgerte');\n container.textContent = '';\n delete container.dataset.readonly;\n }\n };\n\n contentSync.syncContent(false);\n syncPlaceholder();\n commandStateRuntime.refreshCommandStates();\n\n if (shouldRenderToolbar) {\n builtinToolbar = createRichTextToolbar(toolbarElement, {\n editor: api,\n menuSchema: options.menuSchema,\n placement: toolbarPlacement,\n toolbarConfig: options.toolbarConfig,\n icons: options.icons,\n menuLabels: options.menuLabels,\n payloadPanelConfig: options.payloadPanelConfig\n });\n }\n\n notifyReady(options, api);\n\n return api;\n}\n","import {\n BRIDGE_HEIGHT_CHANGE_THROTTLE_MS,\n defaultBridgeEventTiming,\n isBridgeMessage,\n type EditorInitOptions,\n type EditorToNativeMessage,\n type NativeToEditorMessage\n} from '@bridgerte/bridge';\nimport {\n BRIDGERTE_CONTENT_VERSION,\n type EditorAPI,\n type EditorCommand,\n type UploadResult\n} from '@bridgerte/core';\nimport { defaultMenuSchema } from '@bridgerte/native-spec';\nimport { createRichTextEditor } from '../richTextEditor';\nimport type {\n PendingNativeUpload,\n PendingNativePayloadPanelRequest,\n WebViewBridgeRuntime,\n WebViewBridgeRuntimeOptions\n} from './type';\n\nexport type * from './type';\n\nconst isNativeToEditorMessage = (message: unknown): message is NativeToEditorMessage => {\n if (!isBridgeMessage(message) || !('id' in message)) return false;\n\n return message.type === 'editor.init'\n || message.type === 'editor.executeCommand'\n || message.type === 'editor.setContent'\n || message.type === 'editor.setReadonly'\n || message.type === 'editor.requestContent'\n || message.type === 'editor.payloadPanelResolved'\n || message.type === 'editor.payloadPanelCanceled'\n || message.type === 'editor.uploadResolved'\n || message.type === 'editor.uploadRejected';\n};\n\nconst createReadyMessage = (id: string | undefined): EditorToNativeMessage => ({\n id,\n type: 'editor.ready',\n payload: {\n menuSchema: defaultMenuSchema,\n eventTiming: defaultBridgeEventTiming,\n version: BRIDGERTE_CONTENT_VERSION\n }\n});\n\nconst createNativeUploadAssetId = (type: PendingNativeUpload['type']) => (\n `native-upload:${type}:${Date.now()}:${Math.random().toString(36).slice(2)}`\n);\n\n/**\n * 创建 WebView bridge runtime。\n *\n * Runtime 只做协议适配:native 消息进来后调用 EditorAPI,编辑器事件再转成\n * EditorToNativeMessage。它不暴露 Lexical、DOM 节点或上传文件对象,确保 RN/Flutter\n * 只依赖稳定 bridge 协议。\n */\nexport const createWebViewBridgeRuntime = ({\n container,\n transport\n}: WebViewBridgeRuntimeOptions): WebViewBridgeRuntime => {\n let editor: EditorAPI | null = null;\n let destroyed = false;\n let unsubscribeCommandState: (() => void) | null = null;\n let unsubscribeTransport: (() => void) | null = null;\n let heightChangeTimer: ReturnType<typeof setTimeout> | null = null;\n let lastHeight = 0;\n const pendingNativeUploads = new Map<string, PendingNativeUpload>();\n const pendingPayloadPanelRequests = new Map<string, PendingNativePayloadPanelRequest>();\n\n const postMessage = (message: EditorToNativeMessage) => {\n if (destroyed) return;\n\n transport.postMessage(message);\n };\n\n const clearHeightTimer = () => {\n if (!heightChangeTimer) return;\n\n clearTimeout(heightChangeTimer);\n heightChangeTimer = null;\n };\n\n const scheduleHeightChange = () => {\n clearHeightTimer();\n heightChangeTimer = setTimeout(() => {\n if (destroyed) return;\n\n const height = Math.ceil(container.getBoundingClientRect().height);\n\n if (height === lastHeight) return;\n\n lastHeight = height;\n postMessage({\n type: 'editor.heightChange',\n payload: { height }\n });\n }, BRIDGE_HEIGHT_CHANGE_THROTTLE_MS);\n };\n\n const postContent = (id: string | undefined) => {\n if (!editor) return;\n\n /*\n * requestContent 是主动低频读取,可以返回完整内容。这里同时发送新协议\n * editor.content 和旧协议 editor.contentChange,避免老 RN/Flutter 宿主只监听\n * contentChange 时拿不到响应;自动输入仍只走轻量 contentChange 摘要。\n */\n const content = editor.getContent();\n\n postMessage({\n id,\n type: 'editor.content',\n payload: content\n });\n postMessage({\n id,\n type: 'editor.contentChange',\n payload: content\n });\n };\n\n const resolvePendingNativeUploadResolved = (\n message: Extract<NativeToEditorMessage, { type: 'editor.uploadResolved' }>\n ) => {\n const payload = message.payload;\n const pendingUpload = pendingNativeUploads.get(payload.assetId);\n\n if (!pendingUpload) return;\n\n pendingNativeUploads.delete(payload.assetId);\n\n if (pendingUpload.source === 'uploadAdapter') {\n pendingUpload.resolve(payload.result);\n return;\n }\n\n editor?.executeCommand({\n type: pendingUpload.type === 'image' ? 'media.insertImage' : 'media.insertVideo',\n url: payload.result.url,\n poster: payload.result.poster,\n width: payload.result.width,\n height: payload.result.height,\n displayWidthPercent: 50,\n assetId: payload.assetId\n });\n };\n\n const resolvePendingNativeUploadRejected = (\n message: Extract<NativeToEditorMessage, { type: 'editor.uploadRejected' }>\n ) => {\n const payload = message.payload;\n const pendingUpload = pendingNativeUploads.get(payload.assetId);\n\n if (!pendingUpload) return;\n\n pendingNativeUploads.delete(payload.assetId);\n if (pendingUpload.source === 'uploadAdapter') {\n pendingUpload.reject(new Error(payload.message));\n return;\n }\n\n postMessage({\n id: message.id,\n type: 'editor.error',\n payload: {\n code: 'bridge.uploadRejected',\n message: payload.message\n }\n });\n };\n\n const requestNativeUpload = (type: PendingNativeUpload['type'], assetId: string) => (\n new Promise<UploadResult>((resolve, reject) => {\n pendingNativeUploads.set(assetId, {\n type,\n assetId,\n source: 'uploadAdapter',\n resolve,\n reject\n });\n /*\n * WebView native 上传由原生侧选择文件并上传,bridge 只传 assetId 和 accept。\n * 这里禁止把 File/base64 塞进消息,避免大文件拖垮 WebView 通信通道。\n */\n postMessage({\n type: 'editor.uploadRequest',\n payload: {\n assetId,\n type,\n accept: type === 'image' ? 'image/*' : 'video/*'\n }\n });\n })\n );\n\n const requestNativePickerUpload = (type: PendingNativeUpload['type']) => {\n const assetId = createNativeUploadAssetId(type);\n\n pendingNativeUploads.set(assetId, {\n type,\n assetId,\n source: 'nativePicker'\n });\n /*\n * 原生 toolbar 触发上传时不能打开 DOM hidden input;native 负责选择和上传文件,\n * WebView 只接收最终 URL/尺寸等轻量结果。\n */\n postMessage({\n type: 'editor.uploadRequest',\n payload: {\n assetId,\n type,\n accept: type === 'image' ? 'image/*' : 'video/*'\n }\n });\n };\n\n const resolvePayloadPanel = (\n message: Extract<NativeToEditorMessage, { type: 'editor.payloadPanelResolved' }>\n ) => {\n const pendingRequest = pendingPayloadPanelRequests.get(message.payload.requestId);\n\n if (!pendingRequest) return;\n\n pendingPayloadPanelRequests.delete(message.payload.requestId);\n pendingRequest.request.submit(message.payload.values);\n };\n\n const cancelPayloadPanel = (\n message: Extract<NativeToEditorMessage, { type: 'editor.payloadPanelCanceled' }>\n ) => {\n const pendingRequest = pendingPayloadPanelRequests.get(message.payload.requestId);\n\n if (!pendingRequest) return;\n\n pendingPayloadPanelRequests.delete(message.payload.requestId);\n pendingRequest.request.cancel();\n };\n\n const createEditor = (id: string, options: EditorInitOptions) => {\n editor?.destroy();\n unsubscribeCommandState?.();\n pendingNativeUploads.clear();\n pendingPayloadPanelRequests.clear();\n\n editor = createRichTextEditor(container, {\n ...options,\n toolbarMode: 'native',\n platform: 'webview',\n uploadAdapter: {\n uploadImage(_file, context) {\n return requestNativeUpload('image', context.assetId);\n },\n uploadVideo(_file, context) {\n return requestNativeUpload('video', context.assetId);\n }\n },\n onContentChange: (change) => {\n postMessage({\n type: 'editor.contentChange',\n payload: change\n });\n scheduleHeightChange();\n },\n onCommandStateChange: (states) => {\n postMessage({\n type: 'editor.commandStateChange',\n payload: states\n });\n },\n onPayloadPanelRequest: (request) => {\n pendingPayloadPanelRequests.set(request.id, { request });\n postMessage({\n type: 'editor.payloadPanelRequest',\n payload: {\n menuId: request.menuId,\n command: request.command,\n panel: request.panel,\n anchorRect: request.anchorRect,\n currentValues: request.currentValues,\n id: request.id,\n readonly: request.readonly\n }\n });\n\n return true;\n },\n onError: (error) => {\n postMessage({\n type: 'editor.error',\n payload: error\n });\n }\n });\n unsubscribeCommandState = editor.subscribeCommandStateChange((states) => {\n postMessage({\n type: 'editor.commandStateChange',\n payload: states\n });\n });\n postMessage(createReadyMessage(id));\n scheduleHeightChange();\n };\n\n const executeNativeCommand = (command: EditorCommand) => {\n if (command.type === 'media.pickImage') {\n requestNativePickerUpload('image');\n return;\n }\n if (command.type === 'media.pickVideo') {\n requestNativePickerUpload('video');\n return;\n }\n\n editor?.executeCommand(command);\n };\n\n const handleMessage = (message: NativeToEditorMessage | unknown) => {\n if (destroyed || !isNativeToEditorMessage(message)) return;\n\n switch (message.type) {\n case 'editor.init':\n createEditor(message.id, message.payload);\n return;\n case 'editor.executeCommand':\n executeNativeCommand(message.payload);\n return;\n case 'editor.setContent':\n editor?.setContent(message.payload);\n return;\n case 'editor.setReadonly':\n editor?.setReadonly(message.payload.readonly);\n return;\n case 'editor.requestContent':\n postContent(message.id);\n return;\n case 'editor.payloadPanelResolved':\n resolvePayloadPanel(message);\n return;\n case 'editor.payloadPanelCanceled':\n cancelPayloadPanel(message);\n return;\n case 'editor.uploadResolved':\n resolvePendingNativeUploadResolved(message);\n return;\n case 'editor.uploadRejected':\n resolvePendingNativeUploadRejected(message);\n return;\n default:\n /*\n * bridge 协议可能先于 DOM runtime 能力扩展。未知但已过类型守卫的消息保持 no-op,\n * 避免旧 WebView 页面因为新协议字段崩溃。\n */\n }\n };\n\n unsubscribeTransport = transport.addMessageListener?.(handleMessage) ?? null;\n\n return {\n receive: handleMessage,\n destroy() {\n if (destroyed) return;\n\n destroyed = true;\n clearHeightTimer();\n unsubscribeTransport?.();\n unsubscribeCommandState?.();\n pendingNativeUploads.clear();\n pendingPayloadPanelRequests.clear();\n editor?.destroy();\n editor = null;\n }\n };\n};\n"],"names":["mediaNodeType","createAssetId","mediaType","url","toPositiveNumber","value","clampProgress","isMediaDisplayWidthPercent","normalizeDisplayWidthPercent","normalizeMediaAlign","setOptionalStringAttribute","element","name","setOptionalNumberAttribute","BridgeMediaNode","DecoratorNode","payload","key","__publicField","node","_config","previousNode","dom","nextElement","_editor","$convertImageElement","$convertVideoElement","serializedNode","$createBridgeMediaNode","asset","nextPayload","writable","figure","mediaElement","statusElement","$applyNodeReplacement","$createBridgeImageNode","$createBridgeVideoNode","$isBridgeMediaNode","$findBridgeMediaNodeByAssetId","assetId","visitNode","$isElementNode","childNode","matchedNode","$getRoot","emptyContentJson","createEmptyContent","BRIDGERTE_CONTENT_VERSION","getContentJson","editorState","isEmptyContentJson","json","_a","collectEditorAssets","assets","collectNodeAssets","serializeContent","editor","html","$generateHtmlFromNodes","plainText","normalizeInitialContent","content","applyContentToEditor","nextContent","editorStateJson","root","$createParagraphNode","nodes","$generateNodesFromDOM","DividerNode","$convertDividerElement","$createDividerNode","_node","mentionNodeType","mentionDatasetType","normalizeMentionText","item","createMentionElement","MentionNode","TextNode","text","config","$convertMentionElement","$createMentionNode","label","id","$isMentionNode","defaultPlaceholder","isRootEmptyPlaceholderTarget","children","onlyChild","$isParagraphNode","syncPlaceholderState","contentElement","isEmpty","registerPlaceholderFocus","isReadonly","handlePointerDown","event","defaultMenuIcons","createMenuTextIconElement","iconElement","appendMenuIcon","container","iconSvg","fallbackText","bindTouchPressedState","options","pressedElement","setPressed","pressed","target","clearPressed","resolveMenuSchemaForDom","menuSchema","payloadPanel","resolvePayloadPanelSchema","getPayloadPanelCurrentValues","commandStates","state","commandState","getMenuStateForItem","exactState","isCommandStateForCommand","commandTypeState","toolbarDragClickThresholdPx","toolbarTooltipOffsetPx","toolbarButtonSelector","canUseHoverTooltip","getToolbarButtonFromTarget","button","renderToolbarButton","groupElement","icons","enableTooltip","renderToolbar","toolbarElement","toolbarItems","currentGroup","toolbarItem","separatorElement","nextGroup","activeGroupElement","createRichTextToolbar","placement","defaultMenuSchema","resolveToolbarMenu","executableMenuItems","tooltipElement","overlayHost","destroyed","dragState","shouldSuppressNextClick","clearToolbarPressedState","mountToolbarOverlays","renderStates","states","update","hideTooltip","showTooltip","tooltipText","buttonRect","handleTooltipTarget","handleTooltipLeave","relatedTarget","stopToolbarDrag","handlePointerMove","handlePointerUp","deltaX","currentDragState","executeToolbarButton","startButton","menuItem","handleClick","unsubscribe","inlineFormatSpecs","inlineStyleSpecs","listStateSpecs","uploadCommandSpecs","getSelectionBlock","selection","$getSelection","$isRangeSelection","getSelectionBlockState","block","$isHeadingNode","level","$isQuoteNode","$isCodeNode","latestBlock","getSelectionAlignValue","formatType","getSelectionListType","listNode","$isListNode","$getNearestNodeOfType","ListNode","getSelectionStyleValue","property","$getSelectionStyleValueForProperty","isSelectionInsideLink","parent","$isLinkNode","getSelectionCommandStates","isRangeSelection","blockState","listType","alignValue","isInsideLink","rangeDisabled","inlineFormatStates","spec","inlineStyleStates","listStates","uploadStates","command","areCommandStatesEqual","left","right","index","nextState","reportEditorError","code","message","cause","error","notifyChange","notifyContentChange","change","notifyCommandStateChange","notifyFocus","notifyBlur","notifyReady","api","createRichTextEditorCommandStateRuntime","lexicalEditor","isDestroyed","canUploadMedia","canUndo","canRedo","commandStateListeners","notifyCommandStateListeners","nextStates","listener","refreshCommandStates","shouldNotify","previousStates","nextCanUndo","nextCanRedo","createUploadAssetId","type","getFilePreviewUrl","file","revokeFilePreviewUrl","toUploadFileLike","isAbortError","createRichTextEditorMediaUploader","uploadTasks","nextRunId","updateMediaNode","removeMediaNode","removedPayload","mediaNode","isCurrentRun","runId","task","abortTask","clearTask","shouldAbort","insertUploadingMedia","previewUrl","paragraphNode","$insertNodes","applyUploadResult","result","handleUploadError","runUploadTask","uploadAdapter","abortController","uploadContext","progress","uploadPromise","uploadMediaFile","input","$createBridgeCodeNode","language","$createCodeNode","headingTagByLevel","lexicalTheme","createBlockCommandHandlers","$setBlocksType","$createHeadingNode","$createQuoteNode","codeNode","FORMAT_ELEMENT_COMMAND","createLinkCommandHandlers","href","formattedHref","formatUrl","linkNode","$createLinkNode","$createTextNode","$toggleLink","linkTarget","anchorNode","$findMatchingParent","createMediaCommandHandlers","createMentionCommandHandlers","createStyleCommandHandlers","$patchStyleText","styleProperty","tableMutationMaxCount","clampTableInsertSize","maxValue","normalizeTableMutationCount","count","isSelectionInsideTable","$isTableSelection","$findCellNode","createTableCommandHandlers","rows","cols","safeRows","BRIDGERTE_TABLE_INSERT_MAX_ROWS","safeCols","BRIDGERTE_TABLE_INSERT_MAX_COLS","INSERT_TABLE_COMMAND","$insertTableRowAtSelection","$insertTableColumnAtSelection","$deleteTableRowAtSelection","$deleteTableColumnAtSelection","tableNode","$findTableNode","createTableCommandRuntime","tableCommandHandlers","textFormatByCommandType","listCommandByCommandType","INSERT_ORDERED_LIST_COMMAND","INSERT_UNORDERED_LIST_COMMAND","INSERT_CHECK_LIST_COMMAND","editorCommandByCommandType","INDENT_CONTENT_COMMAND","OUTDENT_CONTENT_COMMAND","UNDO_COMMAND","REDO_COMMAND","textStylePropertyByCommandType","createRichTextEditorCommandExecutor","reportError","mediaUploader","blockCommands","linkCommands","mediaCommands","mentionCommands","styleCommands","tableCommands","toggleFullscreen","_b","executeCommand","textFormat","FORMAT_TEXT_COMMAND","listCommand","editorCommand","LEXICAL_HISTORY_MERGE_DELAY_MS","LEXICAL_EDITOR_NAMESPACE","enforceMaxLength","overflowLength","$trimTextContentFromAnchor","fallbackSelection","createRichTextEditorContentSync","setContent","syncPlaceholder","suppressNextChangeCount","contentChangeTimer","clearContentChangeTimer","syncContent","createContentChangeSummary","plainTextLength","maxLength","notifyLightweightContentChange","scheduleFullContentChange","BRIDGE_CONTENT_CHANGE_DEBOUNCE_MS","scheduleContentChange","getPlainTextLength","getMaxLengthOverflow","trimMaxLengthOverflow","codeLanguageAttributeName","defaultCodeBlockLanguageLabel","codeBlockLanguageFieldName","plainTextPrismLanguages","codeLanguageAttributeNames","codeLanguageRegExp","codeLanguageClassRegExp","codeLanguageBrushClassRegExp","canonicalCodeLanguageValueMap","isSelectField","field","findLanguageField","fields","normalizeCodeLanguageValue","normalizedValue","getCodeLanguageFromAttributes","attributeName","normalizedLanguage","getCodeLanguageFromClassName","className","brushLanguage","normalizedBrushLanguage","classText","createDefaultCodeLanguageOptions","prismLanguageOptions","getCodeLanguageOptions","defaultPrismLanguageOptions","getLanguageOptionsFromPanel","panel","codeBlockLanguagePanel","getCodeBlockLabel","languageOptions","option","_c","normalizeCodeBlockLanguages","preElement","unwrapPreCodeChildren","childElement","applyCodeNodeLanguagesFromDom","codeElements","codeElementIndex","codeElement","dialogViewportPadding","dialogAnchorOffset","clampDialogCoordinate","min","max","getVisibleViewportRect","visualViewport","measureDialogRect","dialogElement","previousVisibility","previousPointerEvents","previousDisplay","rect","getDialogPosition","rootElement","anchorRect","dialogRect","viewportRect","rootRect","fallbackLeft","fallbackTop","nextLeft","nextTop","fallbackAboveTop","minLeft","minTop","maxLeft","maxTop","visibleTop","createRichTextDialog","backdropElement","activeAnchorRect","close","syncPosition","position","open","scheduleFrame","callback","cancelFrame","frameId","codeBlockLanguageRequestIdPrefix","codeBlockControlOffset","codeBlockLanguageRequestIdSeed","createCodeBlockLanguageRequestId","setCodeBlockControlLabel","control","createCodeBlockControl","arrow","getCodeBlockScrollContainer","createCodeBlockLanguageController","layer","scrollContainer","languagePanel","dialog","syncFrame","controls","clearPressedStates","closeDialog","setLanguage","nodeKey","$getNodeByKey","scheduleSetLanguage","requestHostLanguagePanel","values","positionControl","codeRect","isOutsideRoot","syncControl","existingControl","clearPressedState","syncAllControls","_","scheduleSyncAllControls","openLanguageDialog","currentLanguageValue","list","unregisterMutationListener","CodeNode","mutations","mutation","unregisterUpdateListener","handleRootPointerDown","mediaControlsResizeIds","mediaControlsDefaultKeys","mediaControlsErrorKeys","mediaControlSchema","isResizeId","isToolbarGroupConfig","collectToolbarKeyIds","keys","appendMissingResizeKeys","existingKeys","missingResizeKeys","normalizeSuccessConfig","baseKeys","createMediaControlCommand","isMediaControlActive","currentWidthPercent","currentAlign","resolveMediaControlsMenu","status","mediaControlsOffset","mediaControlsButtonClassName","getMediaScrollContainer","getMediaElementFromTarget","createMediaControlsButton","active","flattenMediaControlsItems","items","appendMediaControlItem","separator","createMediaControls","defaultWidthPercent","activeWidthPercent","activeAlign","controlItems","createMediaControlsController","mediaElementKeys","touchStartButton","activeMediaKey","removeControls","shouldShowControls","positionControls","mediaRect","maxX","nextX","nextY","syncControls","existingControls","shouldHaveRetry","hasRetry","displayWidthPercent","align","executeButton","activateMediaElement","previousActiveKey","nextActiveKey","handleContentPointerDown","handleContentFocusIn","clearTouchStartButton","optionalNumberPayloadKeys","getStringValue","getPositiveIntegerValue","mergeOptionalNumberPayload","nextCommand","mergePayloadValuesIntoCommand","clampRgbValue","formatHexColor","r","g","b","channel","parseHexColor","match","hexValue","parseRgbColor","normalizeColorValue","parsedValue","clampUnitValue","rgbToHsv","red","green","blue","delta","h","hsvToRgb","s","v","chroma","x","m","getWheelPointerPosition","angle","radius","getHsvFromPointer","wheelElement","centerX","centerY","dx","dy","distance","defaultColorSwatchValues","getColorSwatchOptions","createFieldContainer","fieldElement","renderSelectField","onSubmit","listElement","optionButton","renderColorField","colorWheelElement","colorWheelHandleElement","colorActionsElement","colorPreviewElement","currentHsv","activePointerId","updateColorPreview","nextValue","pointerPosition","submitColorValue","colorValue","swatchButton","initialValue","renderTextField","textInput","renderNumberField","numberInput","renderPayloadPanelField","getDefaultFieldValue","getInitialFieldValue","currentValues","hasManualSubmitField","focusFirstEditableInput","createPanelTitleElement","request","onClear","getClearCommand","titleElement","titleTextElement","clearCommand","clearButton","getDialogWidth","panelId","tableGridDefaultRows","tableGridDefaultCols","tableGridDefaultVisibleRows","tableGridDefaultVisibleCols","tableGridCellSize","tableGridCellGap","tableGridPanelChromeWidth","canUseHoverPreview","clampIntegerValue","dimension","isTableGridNumberField","getPositiveIntegerLimit","fallbackValue","getTableGridDimension","fallbackMax","fallbackDefault","maxFromSchema","fallbackDefaultInRange","defaultValue","resolveTableGridDimensions","getTableGridDialogWidth","dimensions","visibleCols","renderTableGridField","gridElement","gridButtons","shouldUseHoverPreview","visibleRows","visibleRowsDimension","visibleColsDimension","selectedRows","selectedCols","pendingCellClickButton","syncSelection","buttonRows","buttonCols","getGridButtonFromPoint","syncSelectionFromButton","submitSelection","clearPendingCellClickButton","clearPendingCellClickButtonSoon","handleCellClick","cellButton","rowIndex","colIndex","payloadPanelIdPrefix","payloadPanelIdSeed","createRequestId","isTableInsertPanel","createPanelSubmitButton","submitButton","createPayloadPanelController","activeRequest","submit","nextValues","clear","mountDefaultPanel","dialogWidth","nextRequest","tableControlsButtonClassName","tableControlsMenuItemIds","createTableControlsMenuItems","schemaItemById","tableHeaderMenuItems","tableControlsActions","tableControlsActionById","getTableElementFromNodeElement","nodeElement","getTableWrapperElement","tableElement","getTableScrollContainer","getTableElementFromTarget","findFirstTableCell","firstRow","$isTableRowNode","firstCell","$isTableCellNode","createTableControlsButton","createTableControls","createTableHeaderController","tableElementKeys","activeTableKey","tableWrapperElement","wrapperRect","shouldShowControl","removeControl","selectTableFirstCell","TableNode","executeTableCommand","itemId","activateTableElement","createRichTextEditorControllers","payloadPanelController","codeBlockController","tableHeaderController","mediaControlsController","createRichTextEditorDom","editorElement","createPayloadPanelSelectionStore","$setSelection","urlMatchRegExp","emailMatchRegExp","bridgeAutoLinkConfig","createLinkMatcherWithRegExp","registerBridgeAutoLink","registerAutoLink","internalClipboardSelector","isSelectionInsideTarget","focusNode","removeInternalClipboardNodes","getClipboardHtmlAndText","fragment","wrapper","registerClipboardCopy","handleCopy","clipboardContent","handleCut","floatingViewportPadding","clampCoordinate","createFloatingLayer","reference","floating","offsetValue","shiftPadding","strategy","cleanupAutoUpdate","prepareFloatingElement","applyPosition","y","floatingRect","computePosition","platform","offset","flip","shift","stopAutoUpdate","setOpen","nextOpen","autoUpdate","getBrowserSelectionRect","range","hoverbarOpenDelayMs","defaultHoverbarConfig","hasExpandedEditorSelection","isEventInside","getHoverbarButton","flattenHoverbarItems","renderHoverbarSeparator","renderHoverbarButton","registerHoverbar","editorRoot","requestPayloadPanel","getCommandStates","rawMenuSchema","hoverbarConfig","menuLabels","payloadPanelConfig","hoverbarItems","anchor","bar","floatingLayer","openTimer","clearOpenTimer","syncAnchorPosition","fallbackRect","render","canOpenHoverbar","openImmediately","executeHoverbarButton","hoverbarItem","handleDocumentPointerDown","unregisterSelection","SELECTION_CHANGE_COMMAND","COMMAND_PRIORITY_LOW","unregisterUpdate","unregisterEscape","KEY_ESCAPE_COMMAND","isPrimaryModifier","primaryOnlyCommandByKey","primaryShiftCommandByKey","primaryAltCommandByDigit","resolveBasicKeyboardShortcut","digit","registerKeyboardShortcuts","handleKeyDown","scrollFloatingMenuItemIntoView","menu","activeItem","itemOffsetTop","itemBottom","visibleBottom","findTextNodeWithOffset","child","textNode","registerFloatingPicker","itemSelector","getCurrentTrigger","getTriggerRect","resolveItems","renderItem","renderStatus","onStateChange","onSelect","requestId","getAnchorRect","shouldClearItems","scrollActiveItemIntoView","selectItem","stateSnapshot","hasVisibleContent","resolveCurrentItems","query","nextRequestId","syncTrigger","trigger","selectActiveItem","moveActiveIndex","unregisterArrowDown","KEY_ARROW_DOWN_COMMAND","unregisterArrowUp","KEY_ARROW_UP_COMMAND","unregisterEnter","KEY_ENTER_COMMAND","defaultMentionMenuConfig","resolveMentionMenuConfig","readDataField","path","dataKey","readMentionField","normalizeMentionLabel","resolveMentionDisplayItem","description","avatar","icon","resolveMentionDisplayItems","hasLeadingSpace","removeLeadingAutoSpace","nextText","removeMentionAndAutoSpace","mentionNode","isBackward","previousSibling","nextSibling","siblingAfterAutoSpace","getMentionNodeForDeletion","textLength","isAfterLeadingAutoSpace","targetNode","registerMentionDeletion","onDeleteMention","deleteMention","handleKeyboardDelete","didDelete","KEY_BACKSPACE_COMMAND","COMMAND_PRIORITY_HIGH","KEY_DELETE_COMMAND","DELETE_CHARACTER_COMMAND","mentionQueryRegExp","defaultMentionItems","normalizeSearchText","getMentionSearchText","getDefaultMentionItems","normalizedQuery","getCurrentMentionTrigger","matchText","leadingWhitespace","startOffset","createMentionMenuElement","createMentionAnchorElement","getMentionTriggerRect","triggerEndOffset","createMentionItemElement","displayItem","title","createMentionStatusElement","getMentionStatusText","serializeMentionAnchorRect","registerMention","mentionProvider","mentionMenuConfig","onMentionMenuRequest","resolvedMentionMenuConfig","triggerNode","picker","helpers","unregisterMentionDeletion","mergeRegister","removableHtmlSelector","removableClipboardUiSelector","allowedHtmlTags","allowedLinkProtocols","htmlBlockElementSelector","nestedBlockElementSelector","tableSpanAttributeNames","tableCellTagNames","officeNamespacePrefixes","controlledStyleTagNames","controlledInlineStyleProperties","hexColorRegExp","semanticHtmlTagMap","isSafeUrl","unwrapDisallowedElement","replaceElementTag","tagName","replacement","isOfficeNamespaceElement","prefix","removeCommentNodes","normalizeTextNodes","parentElement","preserveWhitespace","textContent","normalizedText","isPositiveIntegerText","normalizeHexColor","normalizeControlledInlineStyle","styleText","styleEntries","entry","rawProperty","rawValueParts","sanitizeElement","attribute","normalizedStyle","normalizeFontElements","normalizedColor","normalizeSemanticElements","normalizeDivElements","unwrapNeutralSpans","isEmptyCleanupElement","removeEmptyCleanupElements","isInlineTopLevelNode","normalizeTopLevelInlineRuns","inlineNodes","flushInlineNodes","paragraph","firstInlineNode","sanitizePastedHtml","template","explicitUrlRegExp","wwwUrlRegExp","nakedDomainRegExp","emailRegExp","getMediaTypeFromFile","getMediaFiles","fileList","getClipboardPasteInput","clipboardData","isPlainUrlText","handlePasteLinkInput","handlePasteMediaInput","mediaFiles","generateNodesFromSanitizedHtml","insertSanitizedHtmlNodes","sanitizedHtml","$insertNodeToNearestRoot","lastInsertedNode","handlePasteRichTextInput","handlePastePlainTextInput","preventNativePaste","handleBuiltInPasteInput","registerPasteLink","handlePaste","registerPasteMedia","handleDragOver","files","handleDrop","registerPasteHtmlCleanup","registerCustomPasteHook","onPaste","handleReplacement","hookResult","defaultSlashCommandKeys","defaultSlashCommandConfig","resolveSlashCommandMenuConfig","flattenMenuItems","createSlashCommandConfig","toSlashCommandItem","resolveStaticSlashCommandItems","toProviderSlashCommandItem","slashQueryRegExp","getCommandSearchText","filterSlashCommandItems","getProviderItems","slashCommandProvider","normalizeSubmittedSlashCommandItem","hasConfiguredStaticSlashCommands","slashCommandConfig","getCurrentSlashTrigger","createSlashMenuElement","createSlashAnchorElement","getSlashTriggerRect","createSlashMenuItemElement","createSlashStatusElement","getSlashStatusText","serializeSlashAnchorRect","registerSlashCommand","slashCommandMenuConfig","onSlashCommandMenuRequest","resolvedSlashCommandMenuConfig","staticItems","staticItemMap","shouldMergeProviderItems","removeTriggerText","baseItems","providerItems","schemaItem","todoListMarkerHitWidth","isTodoListItemElement","getTodoListItemElement","getTodoListItemNode","$getNearestNodeFromDOMNode","isPrimaryMouseEvent","isInsideTodoMarkerArea","stopTodoListNativeEvent","registerTodoListMarker","lastTouchToggleTime","itemElement","toggleItem","itemNode","$isListItemNode","bridgerteCodeTokenizer","PrismTokenizer","isFloatingMenuEnabled","registerRichTextEditorPlugins","historyState","syncAfterEditorUpdate","setCanUndo","setCanRedo","enableKeyboardShortcuts","enableMention","enableSlash","enableHoverbar","unregister","registerRichText","registerCodeHighlighting","registerHistory","registerList","registerCheckList","registerTablePlugin","CAN_UNDO_COMMAND","CAN_REDO_COMMAND","createRichTextEditor","createEmptyHistoryState","toolbarMode","mediaDefaultWidthPercent","shouldRenderToolbar","toolbarPlacement","readonly","builtinToolbar","createEditor","HeadingNode","QuoteNode","CodeHighlightNode","ListItemNode","TableRowNode","TableCellNode","LinkNode","AutoLinkNode","setScrollableTablesActive","payloadPanelSelectionStore","contentSync","commandStateRuntime","executeEditorCommand","syncEditableState","controllers","handleFocus","handleBlur","plugins","CLEAR_HISTORY_COMMAND","nextReadonly","isNativeToEditorMessage","isBridgeMessage","createReadyMessage","defaultBridgeEventTiming","createNativeUploadAssetId","createWebViewBridgeRuntime","transport","unsubscribeCommandState","unsubscribeTransport","heightChangeTimer","lastHeight","pendingNativeUploads","pendingPayloadPanelRequests","postMessage","clearHeightTimer","scheduleHeightChange","height","BRIDGE_HEIGHT_CHANGE_THROTTLE_MS","postContent","resolvePendingNativeUploadResolved","pendingUpload","resolvePendingNativeUploadRejected","requestNativeUpload","resolve","reject","requestNativePickerUpload","resolvePayloadPanel","pendingRequest","cancelPayloadPanel","_file","context","executeNativeCommand","handleMessage"],"mappings":"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"}
|