自动缩放 prosemiror 绑定
合作编写紧随 丰富的文本计划 使用ProseMirror. (英语).
状态
这个插件是β质量软件. API可能会在稳定放出之前稍有改变,并且存在bugs,但也有合理的效果.
怎样玩
此寄存器中有一个功能完备的编辑器, 您可以通过运行来播放 npm run playground 然后访问 http://localhost:5173。 。 。 .
示例
这个库提供了一个插件,用于映射Autommerge文档和ProseMirror文档之间. 这个插件依赖于两件事:第一,你使用的图案是ProseMiror schema的一个非常具体的子集,它被映射到Automerce丰富的文本图案(更多关于这个)上;第二,你从Automerce文档中初始化了ProseMiror文档. 因此,我们提供一个简单的切入点,为你们做所有这些事情:
import { init } from "@automerge/prosemirror"
// Obtain a DocHandle somehow
const handle = repo.find("some-doc-url")
// wait for the handle to be ready before continuing
await handle.whenReady()
// This is the important part, we initialize the plugin with the handle and the path to the text field in the document
// and we get back a schema, a ProseMirror document, and a plugin
const { schema, pmDoc, plugin } = init(handle, ["text"])
// Create your prosemirror state with the schema, plugin, and document
let editorConfig = {
schema,
plugins: [
keymap({
...baseKeymap,
"Mod-b": toggleBold,
"Mod-i": toggleItalic,
"Mod-z": undo,
"Mod-y": redo,
"Mod-Shift-z": redo,
}),
plugin,
],
doc: pmDoc
}
let state = EditorState.create(editorConfig)
const view = new EditorView(<whatever DOM element you are rendering to>, {
state
})
见 playground/src/Editor.tsx 用于完整显示的示例.
Schema 绘图
ProseMirror 文档有一个计划,它决定文档中允许的节点和标记的种类. 要在自动化文档和ProseMirror文档中的块标记和标记之间映射,您必须创建 SchemaAdapter。对 SchemaAdapter 和那个一样 {nodes, marks} 对象,用于创建 ProseMirror 计划,但是 nodes 财务报告和审定财务报表 marks 对象有一个额外的可选密钥,名为 automerge,它配置自动化文档如何映射到ProseMirror文档.
举例来说,这里有一个片段,它描绘了 paragraph 节点到 paragraph 块类型 :
import {SchemaAdapter} from "@automerge/prosemirror"
const adapter = new SchemaAdapter({
nodes: {
... // other nodes
/// A plain paragraph textblock. Represented in the DOM
/// as a `<p>` element.
paragraph: {
// ---------------------------------------
// This is the automerge configuration
// ---------------------------------------
automerge: {
block: "paragraph",
},
// ---------------------------------------
content: "inline*",
group: "block",
parseDOM: [{ tag: "p" }],
toDOM() {
return pDOM
},
} as NodeSpec,
}
})
此策略适配器可以传递给 init 作为一种选项:
const { pmDoc, schema, plugin } = init(handle, ["text"], {
schemaAdapter: adapter,
})
表格中有许多键可用 automerge 测绘. 要了解它们都意味着什么 你需要了解计划绘图的目标:
- 在自动合并块和ProseMirror节点之间转换
- 在自动合并标记和ProseMiror标记之间转换
- 在ProseMirror 文档中代表未知的块和标记,这样编辑一个带有未知标记或块的文档不会导致它们丢失
将块转换为节点
简单块 <- > 节点映射
将块转换为节点的简单案例是当从块类型到节点类型的一对一映射,而节点没有任何额外的属性. 与上段标记的情况一样,这通常看起来像:
nodes: {
<node name>: {
// rest of the node spec
automerge: {
block: <block name>
}
}
}
依靠父母绘制地图
一个更复杂的案例是当块的类型取决于周围的内容. 例如,a <li> proseMirror中的节点可以是 ordered-list-item 或一个 unordered-list-item 在丰富的文本中, 在这种情况下,你可以使用 within 键 :
nodes: {
list_item: {
// rest of the node spec
automerge: {
// Here the keys of the map are other nodes in the schema
within: {
ordered_list: "ordered-list-item",
bullet_list: "unordered-list-item"
}
}
}
}
具有额外属性的映射
许多节点和块标记比仅仅一种类型名称更为复杂. 它们也带有属性. 在这种情况下,你使用 attrParsers 会 议 日 程 和 议 程 automerge 键。 例如 heading 块标记 level 属性,用于确定标题的级别。 这就是你如何将它映射到ProseMirror节点:
nodes: {
heading {
// rest of the node spec
automerge: {
block: "heading",
attrParsers: {
fromAutomerge: block => ({ level: block.attrs.level }),
fromProsemirror: node => ({ level: node.attrs.level }),
},
},
}
}
这个 fromAutomerge 函数将会被传递到块标记,并且应该返回一组节点属性,同时 fromProsemirror 函数将传递一个节点,并返回块属性地图.
嵌入区块
一些块类型并不代表分级内容,而是代表嵌入内容,这些内容不会改变文本继而起的结构作用。 例如,一个图像块标记只是表示一个图像应该出现在块标记的位置上. 对于这些街区,你可以设置 isEmbed 键到 true数字 :
nodes: {
image: {
// the rest of the node spec
automerge: {
block: "image",
isEmbed: true,
attrParsers: { .. },
}
}
}
将标记转换为标记
标记比块简单一点 这个 automerge 在标记 spec上键可以包含 markName 键,该键指定自动合并文档中的标记与ProseMirror文档中的标记相对应.
例如,a strong 标记可能是这样绘制的:
marks: {
strong: {
// rest of the mark spec
automerge: {
markName: "strong",
},
},
}
与块一样,一些标记也具有需要转换的属性。 这事是用 attrParsers 键。 与块标记不同的是,块标记不能将复杂内容存储在自动化的标记值上,因此在解析器中,我们通常会转换成或从JSON编码的字符串,比如:
marks: {
link: {
automerge: {
markName: "link",
parsers: {
fromAutomerge: (mark: am.MarkValue) => {
if (typeof mark === "string") {
try {
const value = JSON.parse(mark)
return {
href: value.href || "",
title: value.title || "",
}
} catch (e) {
console.warn("failed to parse link mark as JSON")
}
}
return {
href: "",
title: "",
}
},
fromProsemirror: (mark: Mark) =>
JSON.stringify({
href: mark.attrs.href,
title: mark.attrs.title,
}),
},
},
}
}
未知块
每个变相器都必须提供某种方式来代表未知的块. 这使得应用程序可以使用不同的方案在同一个文本文档上合作. 未知块将代表我的 node 拥有 automerge.unknownBlock 键集为正则,其中可以包含计划中的任何其他节点.
一个简单的方法是:
nodes: {
unknownBlock: {
automerge: {
unknownBlock: true,
},
group: "block",
content: "block+", // Allow any block content
parseDOM: [{ tag: "div", attrs: { "data-unknown-block": "true" } }],
toDOM() {
return ["div", { "data-unknown-block": "true" }, 0]
},
},
}
API 密码
SchemaAdapter
A 类 SchemaAdapter 提供ProseMirror Schema和您在自动合并文档中使用的块标记之间的映射。 这个API要理解的部分是您传递给 SchemaAdapter 建筑师.
一个schema适配器规格是ProseMiror schema的延伸. 它代表着一个物体 nodes 键和 a marks 键,每个键都类似于它们在 ProseMirror schema 中的等同键,但带有几个额外的键.
这个 nodes 值必须是ProseMirror NodeSpec 附加对象 automerge 键,类型如下:
type AutomergeNodeSpec = {
unknownBlock?: boolean
block?: BlockMappingSpec
isEmbed?: boolean
attrParsers?: {
fromProsemirror: (node: Node) => { [key: string]: am.MaterializeValue }
fromAutomerge: (block: BlockMarker) => Attrs
}
}
type BlockMappingSpec = string | { within: { [key: string]: string } }
type BlockMarker = {
type: automerge.ImmutableString
parents: automerge.ImmutableString[]
attrs: { [key: string]: any }
isEmbed?: boolean
}
这个 marks 值必须是ProseMirror MarkSpec 附加对象 automerge 键,类型如下:
automerge?: {
markName: string
parsers?: {
fromAutomerge: (value: automerge.MarkValue) => Attrs
fromProsemirror: (mark: Mark) => automerge.MarkValue
}
}