- add document evidence parsing/search/open routes, Hermes tool wiring, local index settings/status, and the document-evidence skill plus design notes - fix PDF resource tabs by rendering PDFs inline with pdf.js canvases instead of iframe preview pages, release PDF documents on close, and document the fourth-PDF stall bug - keep PDF preview at 2x rendering while removing the previous lazy-load/placeholder direction, and make dev:hot bind loopback defaults externally reachable Verification: - node --check rust/crates/mnote-web/browser/document-resource-tab-runtime.js - node scripts/task-dev-hot-plan-test.js - cargo test -p mnote-web --manifest-path rust/Cargo.toml pdf_preview_page_does_not_render_visible_toolbar - cargo test -p mnote-web --manifest-path rust/Cargo.toml document_shell_returns_page_aggregate_snapshot - cargo build -p mnote-web --manifest-path rust/Cargo.toml - browser smoke: sequentially opened the four tea_seed_oil_cosmetic PDFs; fourth PDF rendered 15/15 canvases, iframeCount=0, browser errors=0
8123 leptos-tiptap runtime bridge
这是 rust/spikes/leptos-tiptap-spike 的宿主桥接说明,面向前端 host / QA。
runtime 识别
宿主可用下面特征识别这套 runtime:
data-mnote-runtime="8123-leptos-tiptap-runtime"data-mnote-runtime-bridge="true"data-testid="mnote-leptos-tiptap-host"
稳定锚点:
- root:
data-testid="mnote-leptos-tiptap-host" - stage:
#editor-stage/data-testid="mnote-leptos-tiptap-editor-stage" - editor root:
.editor-surface .ProseMirror/data-testid="mnote-leptos-tiptap-editor-root" - toolbar:
data-testid="mnote-leptos-tiptap-toolbar" - slash menu:
data-testid="mnote-leptos-tiptap-slash-menu" - handle:
data-testid="mnote-leptos-tiptap-handle"
事件协议
所有事件都走同一 envelope:
{
"protocol": "mnote.leptos_tiptap.bridge.v1",
"runtime": "8123-leptos-tiptap-runtime",
"version": "1.0.0",
"source": "mnote:leptos-tiptap-spike",
"payload": {}
}
mnote:leptos-tiptap-spike:ready
首次挂载完成时发送,告诉 host 这套 runtime 可以被嵌入。
payload 里至少包含:
runtime_nameselectorssupported_commandssupports_embedded_mode
mnote:leptos-tiptap-spike:state
发送当前最小可观测状态。
payload 字段:
document_idtitledirty_countselected_block_indexeditor_focusedslash_opentoolbar_open
mnote:leptos-tiptap-spike:change
内容变化时发送结构化文档快照。
payload 结构:
title: 文档标题content: 当前文档 JSONmeta: 附加运行态信息(如 dirty_count / selection / focus)
mnote:leptos-tiptap-spike:save-request
保存路径或 host 明确要求落盘时发送,payload 与 change 一致,但语义是“请宿主处理保存”。
mnote:leptos-tiptap-spike:command
预留宿主到 runtime 的命令通道。当前 spike 只声明了最小命令集合,还没有把完整命令分发做成正式 host API。
选择器清单
建议 host/QA 只依赖这些稳定选择器:
- root:
[data-testid="mnote-leptos-tiptap-host"] - stage:
#editor-stage或[data-testid="mnote-leptos-tiptap-editor-stage"] - editor:
.editor-surface .ProseMirror或[data-testid="mnote-leptos-tiptap-editor-root"] - toolbar:
[data-testid="mnote-leptos-tiptap-toolbar"] - slash menu:
[data-testid="mnote-leptos-tiptap-slash-menu"] - handle:
[data-testid="mnote-leptos-tiptap-handle"]
推荐嵌入方式
推荐把这套 runtime 作为 iframe 或独立容器挂载,然后由 host 监听 document 上的 CustomEvent:
- 先等待
ready。 - 从
ready.payload.selectors取稳定锚点。 - 监听
change/state/save-request。 - 需要操作时再发
command。
最小监听示例:
const onReady = (event: Event) => {
const detail = (event as CustomEvent).detail;
// detail.protocol / detail.payload.selectors
};
document.addEventListener('mnote:leptos-tiptap-spike:ready', onReady as EventListener);
document.addEventListener('mnote:leptos-tiptap-spike:change', onReady as EventListener);
document.addEventListener('mnote:leptos-tiptap-spike:state', onReady as EventListener);
document.addEventListener('mnote:leptos-tiptap-spike:save-request', onReady as EventListener);
已知限制
- 这仍是 8123 spike,不是正式主编辑器切流完成态。
- 目前桥接只保证稳定事件与稳定 selector,不保证 host 命令已经全量实现。
- 仍保留独立运行能力,host 不应依赖 debug 文案。
- 保存仍以 spike 本地草稿逻辑为主,真正主链保存合同还没迁移完。