Slate v2 核心编辑器方法硬切方案解读从 99 个静态方法到state/tx分组 API【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate本篇技术指南以仓库内决策文档 docs/plans/2026-05-03-slate-v2-core-editor-method-hard-cut-ralplan.md 为核心系统讲解 Slate v2 对公共Editor.*静态方法命名空间的一次硬切hard cut架构决策如何将旧的扁平静态工具方法收拢为极小的实例生命周期read/update/subscribe/extend加按领域分组的state.*读与tx.*写API并给出完整的方法去向矩阵、异议台账与分阶段实施路径。读完本文你将掌握 Slate v2 公共 API 的目标形态、方法迁移规则、回归证明策略以及该决策对 Plate、slate-yjs 和 React 渲染层的具体影响。一、问题背景99 个公共静态方法为何是架构债务在旧版 Slate 的公共 API 形态中Editor.*是一个同时混入了读方法、写方法、运行时内部机制、扩展注册入口和遗留辅助策略的静态命名空间。决策文档记录了对当时EditorStaticApi的评估它仍然暴露 99 个方法把读取与写入、公共作者 API与运行时实现细节混在同一个表形状的对象上。决策文档的结论很直接保留全部 99 个公共静态方法是架构债务。它一方面让老 Slate 用户感到熟悉另一方面却原样保留了read/update state/tx本应取代的那种对象形状的杂物抽屉junk drawer。与此同时现场源码已经具备了正确的底层基质BaseEditor已经很小只含read、subscribe、update、extend四个实例方法EditorCoreStateView与EditorCoreUpdateTransaction已经以分组形式暴露了state/tx读写 APIEditorStaticApi仍然暴露 99 个方法混合读取、写入、运行时内部、扩展注册和遗留辅助策略。在当前仓库的packages/slate中也能看到这条演进线的痕迹packages/slate/src/interfaces/editor/editor-api.ts 中的EditorApi类型已经按fragment、getDirtyPaths、isElementReadOnly、after、string、pathRef、rangeRefs等语义分组组织packages/slate/src/create-editor.ts 通过bindFirst把packages/slate/src/internal/editor/*下的内部实现逐一绑定到编辑器实例上。而.tmp/slate-v2决策文档中描述的独立 slate-v2 工作区则在此基础上进一步完成了公共根的硬切。二、意图与边界本次硬切做什么、不做什么决策文档首先界定了意图与边界记录Intent / boundary record意图审查每一个现存的核心编辑器方法决定它在干净的 Slate v2 架构中是否应该存活从公共 API 思维中移除elementReadOnly、shouldMergeNodesRemovePrevNode这类遗留残留对照 Lexical、ProseMirror、Tiptap 比较目标形态但不把 Slate 变成它们中的任何一个。期望产出一份可以驱动后续实现的硬切计划对每个现存EditorStaticApi方法给出 keep / move / internalize / cut 四类决策之一公共编写示例收敛到editor.read((state) ...)与editor.update((tx) ...)。范围内In scopepackages/slate/src/interfaces/editor.ts核心方法表面BaseEditor、EditorStateView、EditorUpdateTransaction、EditorTransformApi、EditorStaticApi扩展注册表面与命令残留Schema/谓词辅助方法isVoid、isInline、isSelectable、isElementReadOnlyOperation、dirty-path、runtime-id、ref、snapshot 访问器Plate 与 slate-yjs 的迁移骨干。非目标Non-goals本次不做任何实现编辑不做当前版本 Plate 的兼容包装不做 slate-yjs 适配器实现不把公共命令目录作为 raw Slate 的常规变更 API除非明确发布门禁要求否则不做兼容别名计划。决策边界若某个方法除了老 Slate 就这么干之外没有公共作者用例默认是cut而不是保留若某个方法被 core/runtime/tests 需要那是内部化的理由不是公共 API 的理由。三、决策简报为什么选 Option B硬切决策文档列出了三条设计原则作为底层约束公共 Slate 应当小而内聚且保持Slate 味写入必须经过单一事务生命周期读取必须与已提交状态或事务局部草稿状态保持一致运行时策略不得以一次性公共辅助方法的形式泄漏Plate 和 slate-yjs 需要的是骨干backbone而不是兼容性杂物抽屉。三个可比方案选项内容优点缺点Option A保留Editor.*作为兼容表面同时教学state/tx迁移容易每件核心事都有两种公共写法自动补全变差架构信号弱Option B硬切Editor.*保留实例editor.read/update/subscribe/extend暴露具名纯辅助与state/tx分组架构干净迁移更大Option CTiptap 风格editor.commands/editor.chain()作为主 API工具栏 DX 友好对 raw Slate 而言过于产品化选定方案Option B。被拒绝的替代方案及其理由保留全部静态辅助会延续方法蔓延命令作为核心editor.update才是写生命周期命令目录应位于 core 之上ProseMirror 整数位置模型Slate 继续使用 path、runtime id、operations 与 JSON 节点Lexical$辅助风格与类节点Slate 保持纯数据与直接回调参数。后果示例/文档/测试必须从Editor.foo(editor, ...)迁移到state/tx分组或具名导出部分测试设置辅助需要内部导入插件作者得到更干净的扩展命名空间但失去旧的扁平方法增长路径。四、方法普查用数据证明静态命名空间不是作者依赖在 2026-05-03 的 method census 通过中执行了全量普查命令形态如下rg --files packages site docs exclude: site/out, site/.next, CHANGELOG.md, docs/general/changelog.md count: /\bEditor\.([A-Za-z_$][\w$]*)\b/普查结果扫描了 1590 个源码/文档/示例文件共出现 2284 处Editor.*涉及 93 个唯一方法名公共文档仅 2 处遗留式Editor.*字符串且都没有教学当前编写 API站点源码1 处Editor.getSnapshot运行时源码371 处涉及 52 个方法测试1910 处涉及 80 个方法。当前Editor.*压力最大的方法方法数量含义replace488大多是测试夹具种子数据属于内部/测试辅助与tx.value.replacegetSnapshot396大多是测试/快照契约公共文档示例只应在确有全量快照意图时使用state.runtime.snapshotgetChildren84大多是测试/内部公共读取路径是state.value.get()after70查询测试/内部公共读取路径是state.points.afterstring65查询测试/内部公共读取路径是state.text.stringisBlock58查询测试/内部公共读取路径是state.schema.isBlockregisterCommand18仅测试确认命令辅助是内部契约/测试基质而非公共编写 APIpathRef/pointRef/rangeRef36合计运行时/浏览器内部与 ref 测试支持把 ref 集合内部化同时保留 bookmark/runtime-id 公共锚点叙事敏感方法家族普查方法/家族数量公共文档/站点运行时测试决策elementReadOnly/isElementReadOnly6060cut/rename运行时成为isReadOnly策略shouldMergeNodesRemovePrevNode1010仅内部合并策略ref 创建/集合440377内部运行时/测试表面公共持久锚点是 bookmarks/runtime ids规范化开关7070仅内部公共控制是tx.withoutNormalizing命令注册/定义190019仅内部/测试raw Slate 无公共命令目录扩展注册表/能力/normalizer/commit 监听220121仅内部扩展运行时replace/reset48903486replace保持内部/测试reset删除静态read/update2002切掉静态包装实例方法保留结论公共教学表面已经基本是最终态的editor.read/update静态命名空间不是作者依赖而是运行时/测试依赖。实现应当切掉公共静态暴露并把测试迁移到slate/internal或测试辅助而不是为应用作者保留Editor.*。同时该通过关闭了公共Editor值的分期问题公共Editor值随方法切一并消亡。五、目标公共形态editor.readeditor.update双生命周期决策文档给出的目标公共形状north stareditor.read((state) { state.selection.get(); state.nodes.above(); state.schema.isVoid(element); }); editor.update((tx) { tx.nodes.set({ type: heading }); tx.selection.collapse({ edge: end }); tx.value.replace({ children, selection: null }); });保留Keepeditor.read、editor.update、editor.subscribe、editor.extend四个实例方法具名纯数据辅助Node、Path、Point、Range、Element、Text若需要公共运行时检查保留具名谓词isEditor(value)具名defineEditorExtension(...)。从公共作者 API 中切掉Cut公共Editor.*静态方法命名空间tx之外的公共原始写辅助公共命令注册辅助公共 ref 集合访问器公共合并策略辅助与state/tx重复的公共快捷辅助。这里有一条硬规则值得一提如果一个辅助方法需要编辑器实例、并且能观察或变更编辑器状态它就不应该属于公共静态命名空间。If a helper needs an editor instance and can observe or mutate editor state, it does not belong in a public static namespace.六、方法去向全表每个静态方法的归宿决策文档提供了覆盖全部现存EditorStaticApi方法的完整方法覆盖表这是迁移时最重要的参照决策方法保留实例方法切静态包装read、update、subscribe、extend保留具名导出切静态包装isEditor、defineEditorExtension移到state.nodesabove、first、getChildren、hasBlocks、hasInlines、hasPath、hasTexts、isEmpty、last、leaf、levels、next、parent、path、positions、previous、void移到state.pointsafter、before、point、isEdge、isEnd、isStart移到state.rangesbookmark、edges、range、projectRange、unhangRange移到state.fragmentfragment、getFragment移到state.textstring移到state.valuegetOperations、getLastCommit移到state.runtimegetPathByRuntimeId、getRuntimeId、getSelection、getSnapshot移到state.schemaisBlock、isElementReadOnly→isReadOnly、isInline、isSelectable、isVoid移到tx.marksaddMark、removeMark、toggleMark移到tx.textdelete、deleteBackward、deleteForward、insertText移到tx.fragmentdeleteFragment、insertFragment移到tx.breakinsertBreak、insertSoftBreak移到tx.selectioncollapse、deselect、move、select、setPoint、setSelection移到tx.nodesinsertNode、insertNodes、liftNodes、mergeNodes、moveNodes、removeNodes、setNodes、splitNodes、unsetNodes、unwrapNodes、wrapNodes移到tx.valuereplace、reset移到tx控制normalize、withoutNormalizing内部运行时getOperationDirtiness、getDirtyPaths、getExtensionRegistry、pathRef、pathRefs、pointRef、pointRefs、rangeRef、rangeRefs、defineCommand、registerCommand、registerCapability、registerNormalizer、registerCommitListener、subscribeSource、isNormalizing、setNormalizing、shouldMergeNodesRemovePrevNode彻底切掉elementReadOnly七、读分组state.*与写分组tx.*详解7.1 读方法迁到state.*读方法统一迁入按领域分组的state视图目标形态editor.read((state) { state.nodes.above(); state.points.after(at); state.ranges.get(at); state.fragment.get({ at }); state.text.string(at); state.value.operations(); state.value.lastCommit(); state.runtime.idAt(path); state.runtime.pathOf(runtimeId); state.runtime.snapshot(); state.schema.isVoid(element); });7.2 写方法迁到tx.*写方法统一迁入事务分组的tx视图目标形态editor.update((tx) { tx.marks.add(bold, true); tx.text.insert(hello); tx.fragment.insert(fragment); tx.break.insert(); tx.selection.set(target); tx.nodes.insert(node); tx.value.replace({ children, marks: null, selection: null }); tx.normalize(); tx.withoutNormalizing(() {}); });7.3 硬切中的几个细化决定合并insertNode/insertNodes丢弃公共insertNode/insertNodes的拆分只保留一个tx.nodes.insert(nodes, options)丢弃tx.nodes.insertManylive 代码中insert与insertMany都接受T | T[]保留两者只是 API 噪音丢弃reset改用tx.value.replace丢弃公共withoutNormalizing(editor, fn)只保留tx内部的版本。7.4 schema 谓词的修订决策中明确了两处修订state.schema.isElementReadOnly(element)改为state.schema.isReadOnly(element)。理由是该 API 已经活在state.schema之下那里的每个谓词都是关于元素行为的重复Element只是噪音行为谓词移到state.schema结构性谓词保留在state.nodes下state.nodes.void()保留命名空间已经足够表意voidElement只是冗长而没有更强的收益。八、内部运行时目标EditorTransformApi不是公共架构决策文档明确EditorTransformApi保持内部并给出硬规则EditorTransformApi is runtime-owned implementation, not public architecture.目标包内部 transform 注册表需要裸运行时辅助的测试从内部测试辅助导入公共文档永不直接教学 transform 注册表方法。各内部化家族在公共侧的替代形状内部化家族公共替代Operation 脏度commit 元数据与内部运行时 APIDirty pathscommit/runtime 证明辅助而非公共工具扩展注册表defineEditorExtensioneditor.extend命令注册内部桥或产品层命令目录Ref API持久公共锚点优先用 bookmarks 与 runtime ids规范化开关仅tx.withoutNormalizing合并策略若有真实公共用例走 schema/spec 或 transform 中间件否则仅内部elementReadOnly的切掉与替代elementReadOnly被彻底 cut替代写法editor.read((state) { state.nodes.above({ match: (node) Element.isElement(node) state.schema.isReadOnly(node), }); });理由它是披着核心 API 外衣的遗留便捷搜索辅助它只是nodes.above加 schema 行为的重复名字别扭且产品化。九、Hook/组件/渲染 DX 目标计划虽然是 core API 优先但 React 涟漪很重要React 代码订阅EditorCommit脏度而不是宽泛的Editor.*快照辅助Hook 暴露基于 commit/runtime 状态的窄选择器示例使用editor.read/editor.update运行时内部可以使用内部方法但不教学应用作者照做。性能视角的三条约束重复的编辑器单元不应在渲染中调用宽泛静态辅助React 渲染中的读取应选择器背书或快照背书而不是任意运行时拉取变更处理器应调用editor.update而不是直接调静态包装。十、Plate 与 slate-yjs 迁移骨干Plate 应迁移到editor.extend(...)或构造时扩展注册state.plugin读命名空间tx.plugin写命名空间位于 raw Slate 之上的产品命令目录而不是 raw Slate 内部schema/spec 元素行为而非谓词覆盖。Plate不应通过为每个被删静态方法包一个 Plate 兼容 shim 来迁移——那会在上一层重建杂物抽屉。slate-yjs 协作需要tx.operations.replay下的操作重放本地/远端来源的 commit 元数据确定性快照与 runtime idsbookmarks/runtime ids 作为持久锚点不以公共可变 ref 集合作为协作用锚点。计划必须证明三点远端操作应用不需要公共Editor.apply远端选择/bookmark 映射不需要公共PathRef/PointRef集合协作元数据可以放进 update tags/metadata而不是临时命令载荷。十一、遗留回归证明矩阵风险所需证明切后静态 API 泄漏公共导出契约拒绝EditorStaticApi值导出文档继续教学旧 API文档对Editor.写辅助的 grep 在迁移/内部说明之外为空示例回归站点示例编译并通过editor.read/update浏览器冒烟transforms 丢行为mark/text/fragment/selection/node transform 经tx.*的单元测试replace/reset 破坏夹具公共夹具用tx.value.replace内部夹具用测试辅助schema 谓词漂移schema.isVoid、schema.isInline、schema.isSelectable、schema.isReadOnly的测试合并策略隐藏破坏merge-nodes 测试覆盖无公共辅助下的前节点移除refs 切掉破坏锚点bookmark/runtime-id 测试覆盖经操作后的持久锚点协作重放破坏带 commit 元数据经tx.operations.replay重放操作扩展迁移失败state.name与tx.name的扩展命名空间测试十二、维护者异议台账objection ledger决策文档为每个有争议的切法记录了谁痛、反对意见、钢人反题、权衡张力、为什么不是为变而变、被拒替代、迁移答案、文档/示例答案、回归证明、生态答案、裁决。12.1 切掉公共Editor.*反对意见这让 Slate v2 不那么像 Slate。钢人反题旧Editor.nodes(editor, ...)风格熟悉且易 grep。被拒替代保留静态包装作为别名——别名会保留两套公共 API。迁移答案Editor.foo(editor, ...)映射到state.*或tx.*。回归证明导出契约 文档 grep tx/state 对等测试。裁决keep维持切法。12.2 彻底切掉公共Editor值反对意见你可以删方法而不删命名空间。关键证据公共表面契约已断言Editor in Slate为 false剩余Editor.*使用是内部/测试为主。被拒替代保留Editor.isEditor和少量受祝福静态——会保留命名空间歧义。迁移答案应用作者用createEditor、实例read/update与具名纯辅助运行时/测试从slate/internal导入Editor。裁决keep。公开的空/僵尸Editor命名空间比干脆的断舍离 DX 更差。12.3 切掉elementReadOnly与内部化shouldMergeNodesRemovePrevNodeelementReadOnly只是nodes.above加 schema 谓词名字糟糕改用state.nodes.abovestate.schema.isReadOnlyshouldMergeNodesRemovePrevNode是实现条件而非 API属于 transform 策略除非真实用例证明需要 schema 或 transform-middleware hook否则不提供公共迁移。12.4 内部化 ref 集合反对意见Refs 是 Slate 追踪移动位置的方式。关键证据公共示例已在用state.ranges.bookmark运行时 ref 用在 transforms、DOM/浏览器 handler、Android 输入、选择协调器与内部测试。被拒替代永远保留公共 refs——ProseMirror bookmarks 与 Slate v2 runtime ids 是更干净的持久锚点。迁移答案持久锚点用 bookmarks/runtime ids内部 refs 保留给 transform 实现。裁决keep。12.5 内部化命令辅助反对意见raw Slate 需要命令 API 来做快捷键和工具栏动作。关键证据当前Editor.registerCommand与Editor.defineCommand命中全在测试slate/internal已导出命令注册表辅助。被拒替代发布editor.commands或Editor.registerCommand——那会制造第二个变更生命周期。迁移答案产品层可定义调用editor.update的命令目录raw 扩展运行时可保留内部中间件。裁决keep。12.6 重命名只读 schema 谓词反对意见长名字更明确。权衡张力isReadOnly丢了Element一词。被拒替代保留isElementReadOnly——被视为遗留措辞。迁移答案state.schema.isElementReadOnly(element)→state.schema.isReadOnly(element)。裁决keep。十三、实施阶段、门禁与执行记录13.1 六个实施阶段阶段内容状态Phase 0导入与使用普查对公共文档、示例、测试、包导出与包内部做Editor.*grep逐条对照本计划分类暂不切代码规划完成Phase 1关闭分数与导出表面红契约断言EditorStaticApi值方法非公共最终 API公共Editor值不从slate泄漏isEditor与defineEditorExtension保持具名导出内部辅助保持在内部入口下nextPhase 2文档/示例迁移到state/tx先示例后文档行为不变-Phase 3tx/state 对等测试每个读/写家族一个行为测试不允许只断言被删 API 不存在的测试-Phase 4按家族硬切方法按家族移除公共静态包装内部化运行时/注册表/ref 辅助切elementReadOnly内部化shouldMergeNodesRemovePrevNode-Phase 5生态证明Plate 风格扩展命名空间示例slate-yjs 操作重放/骨干证明bookmark/runtime-id 持久锚点证明-Phase 6关闭清扫文档 grep、公共导出契约、包 typecheck、selection/paste/void/read-only 路径浏览器冒烟-13.2 快速驱动门禁fast driver gatesrg -n Editor\. .tmp/slate-v2/docs .tmp/slate-v2/site .tmp/slate-v2/packages在文档迁移后只能出现内部/测试允许的行关闭前在.tmp/slate-v2跑bun check若实现批次移动了这些方法跑 read-only/void/selection/paste 聚焦浏览器测试导出表面契约在EditorStaticApi再次泄漏时必须失败。13.3 2026-05-04 Lexical 一致性附录Editor.replace不是特例该附录的触发点是用户问Editor.replace是否应该硬切因为 Lexical 不暴露Editor.*命名空间随后澄清该通过必须覆盖每一个类似 API而不只是 replacement。补充的 live 源码证据公共slate根导出createEditor、顶层isEditor、type-only 的Editor与 type-only 的 state/tx 分组不导出公共Editor值DOMEditor/ReactEditor值不是正常公共根 APIslate-dom以类型导出DOMEditor并暴露withDOMslate-react以类型导出ReactEditor与withReactDOM 适配器已有更好的公共形态editor.dom.*但其能力仍通过内部静态DOMEditor.*表委托实现Lexical 暴露LexicalEditor.update作为唯一安全变更回调setEditorState作为显式整态 setter不暴露 Slate 风格的Editor.replace(editor, ...)命名空间。附录的决策与硬规则保持一致保留纯数据命名空间Node、Path、Point、Range、Operation、Element、Text、Scrubber只保留编辑器实例生命周期editor.read、editor.update、editor.subscribe、editor.extend只保留非有状态编辑器命名空间重复的公共具名根函数createEditor、defineEditorExtension、isEditor、elementPropertytx.value.replace(...)是唯一公共整文档替换入口切掉公共Editor.replace与Editor.reset只保留内部replaceSnapshot(editor, input)原语与测试辅助切掉静态生命周期重复、静态写/transform 重复、静态读/查询重复、静态快照/runtime 重复、公共可变 ref API、公共扩展/命令注册辅助、策略残留适配器静态保持 internal/friend公共应用代码应在withDOM/withReact之后使用editor.dom.*。结论Editor.replace并不特殊。它只是不应成为公共 API 的那一类有状态静态编辑器辅助中的一员。 Lexical 一致性裁决是Slate 不复制 Lexical 的类节点、$辅助或命令总线作为公共编写 API但应复制其清晰度——一个编辑器实例生命周期、一个写边界、编辑器之外的纯辅助、没有混合静态状态命名空间。13.4 Ralph 执行记录与验证门禁2026-05-04 的执行通过Status:done覆盖为slate-dom增加公共表面覆盖使包根拒绝运行时DOMEditor值而保留withDOM收紧slate-react表面覆盖拒绝运行时ReactEditor/DOMEditor值而保留withReact替换剩余的非测试运行时Editor.replace(...)快捷调用React provider 初始化现在通过editor.update((tx) tx.value.replace(...))播种initialValuetransform 内部的全文档文本与片段替换改用内部replaceSnapshot(...)原语新增replaceEditorValue(editor, input)测试辅助经editor.update((tx) tx.value.replace(input))实现公共 state/read-update 契约测试迁移掉Editor.replace(...)播种样板移除直接调用点的源码级静态策略残留Editor.elementReadOnly(...)、Editor.shouldMergeNodesRemovePrevNode(...)、Editor.isNormalizing(...)、Editor.setNormalizing(...)移除热路径相邻 React provider 与 trace 代码中的静态生命周期/读重复Editor.isEditor(...)、Editor.subscribe(...)、Editor.getOperations(...)。执行后源码清单验证rg对 slate/slate-dom/slate-react 三个 src 目录rg \bEditor\.(read|update|subscribe|extend|replace|reset|getOperations|elementReadOnly|shouldMergeNodesRemovePrevNode|setNormalizing|isNormalizing)\( .tmp/slate-v2/packages/slate/src .tmp/slate-v2/packages/slate-dom/src .tmp/slate-v2/packages/slate-react/src 0 matches全量门禁结果bun check biome check: pass packages typecheck: 6 successful site/root typecheck: pass bun test: 1007 pass, 95 skip, 0 fail slate-react vitest: 20 files passed, 147 tests passed浏览器证明在http://localhost:3102/examples/mentions上完成应用内 Browser 设置浏览器冒烟因 Browser Use 拒绝以data:URL 安全拦截重载当前页而未能完成未使用替代浏览器方案。十四、风险预演与评分卡14.1 高风险刻意模式预演pre-mortem触发条件公共 API 硬切、扩展基质、操作/协作路径、文档/示例。爆炸半径packages/slate、packages/slate-react、packages/slate-dom、站点示例、文档、测试、下游 Plate 迁移、slate-yjs/协作基质。三个失败场景API 切在类型上成功但示例/文档仍在教学过时的静态辅助内部化 refs 破坏了浏览器路径中微妙的 selection/anchor 映射命令辅助切得太狠让扩展失去键盘或产品命令的良好迁移路线。证明扩展单元层做 tx/state 对等集成层做扩展命名空间与操作重放契约浏览器层做 selection、IME 相邻输入、粘贴、void/read-only 导航迁移层做 Plate 风格扩展示例与协作重放示例文档层只展示最终态 API性能层做 selector/read 热路径基准。裁决保持方向把执行拆成批次。14.2 置信度评分卡维度分数证据React 19.2 运行时性能0.86方法普查显示 docs/site 源码已用editor.read/update热渲染路径不应依赖公共静态方法Slate 味无观点 DX0.91liveBaseEditor只有read、subscribe、update、extenddocs/examples 已教学state/txstate.nodes.void保持 Slate 熟悉感Plate 与 slate-yjs 迁移骨干0.87live 扩展命名空间、tx.operations.replay、commit 元数据、bookmarks、runtime ids、slate/internal导入覆盖骨干无需公共命令命名空间回归证明测试策略0.85已识别现有公共表面、state/tx、写边界、扩展、bookmark、命令/internal、迁移契约最终实现仍需每批次红契约编辑研究证据完整性0.90live 源码/测试普查支撑 Lexical read/update、ProseMirror 事务所有权、Tiptap 扩展 DX 对比shadcn 风格可组合性/极简0.88公共 API 变为小实例生命周期加分组 state/tx API产品命令保持在 raw Slate 之上关闭门禁要求分数 0.92、无维度低于0.85、每个方法家族有证明行、Plate/slate-yjs 迁移骨干行被接受、实现阶段可被ralph分批、最终关闭通过记录实现就绪或精确剩余证明缺口、active goal state指向下一个评审/实现通过。十五、总结一次为瘦身而做的硬切这份 ralplan 的价值不在于删了多少个方法而在于确立了 Slate v2 公共 API 的形态纪律写入只有一条路editor.update((tx) ...)读取与已提交状态或草稿状态一致editor.read((state) ...)实例生命周期极小read / update / subscribe / extend纯数据命名空间留在编辑器之外Node、Path、Point、Range、Operation、Element、Text运行时策略不再以一次性公共辅助泄漏dirty paths、refs、命令注册、规范化开关全部内部化生态不靠兼容 shim 迁移Plate 走扩展命名空间slate-yjs 走tx.operations.replay与 commit 元数据。对准备跟进该架构的开发者建议按本文第六节的方法去向全表逐家族核对现有代码先跑一次rg普查确认自己的Editor.*使用分布再按 Phase 2 → Phase 3 → Phase 4 的顺序先示例后文档、先对等测试后切代码平滑迁移最终态下公共文档中不应再出现任何Editor.静态写/读辅助的教学用法。进一步阅读决策文档原文 docs/plans/2026-05-03-slate-v2-core-editor-method-hard-cut-ralplan.md当前仓库的编辑器 API 类型定义 packages/slate/src/interfaces/editor/editor-api.ts实例装配入口 packages/slate/src/create-editor.ts内部实现目录 packages/slate/src/internal/editor公共导出根 packages/slate/src/index.ts。【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考