# `@workspace/lexical` 基于 Lexical 的声明式富文本编辑器。编辑器能力由 `` 中出现的 action 组件决定;action 同时声明自己依赖的 node、plugin 和 embed,`` 会在创建 Composer 前自动收集并去重。 ## 使用预设 `useDefaults` 提供 `minimal` 和 `full` 两套预设。使用预设时不再接收 `children`,避免默认 action 与手动 action 的优先级不明确。 ```tsx import { LexicalActions, LexicalBubbleToolbar, LexicalContent, LexicalFixedToolbar, LexicalFooter, LexicalRoot, } from "@workspace/lexical" export function Editor() { return ( console.log(html)}> ) } ``` `LexicalFixedToolbar`、`LexicalBubbleToolbar` 和 `LexicalFooter` 都是可选的。 当对应区域没有 action,也没有自定义 children 时,组件不会产生 DOM。 action、node 与 plugin 会在编辑器首次挂载时确定;需要切换整套能力时,应为 `LexicalRoot` 提供新的 `key` 以重新创建编辑器。 ## 国际化 内置控件会使用 `@workspace/i18n` 的当前语言;包提供英文与简体中文 catalog。 应用应将对应 locale source 加入自己的 `i18n.config.json`: ```json { "catalogSources": ["@workspace/lexical/locales/{locale}"] } ``` 未置于 `I18nProvider` 内时,编辑器会回退到英文。外部 action 的 `label` 仍可直接传字符串,也可以传 `{ id, message }` 消息描述符。 ## 自定义 action 布局 action 默认显示在固定工具栏。通过 `in` 可以指定单个区域或多个区域; `ActionGroup` 可以只做普通组合,也可以渲染成下拉菜单。 ```tsx import { ActionGroup, Bold, BulletList, CheckList, ClearFormatting, Date, Heading, LexicalActions, NormalText, OrderedList, Quote, Redo, Undo, } from "@workspace/lexical" ; ``` ## 定义扩展 action 外部 action 把行为和 Composer 依赖放在同一份定义中,不需要额外注册 feature。只要 action 出现在 `LexicalActions` 中,它声明的 node 和 plugin 就会自动启用。 ```tsx import { defineLexicalAction, type LexicalActionDefinition, } from "@workspace/lexical" const mentionAction: LexicalActionDefinition = { name: "mention", label: "插入提及", nodes: [MentionNode], plugins: [MentionPopoverPlugin], execute: ({ editor }) => openMentionPicker(editor), } export const Mention = defineLexicalAction(mentionAction) ``` action 组件可以用 render function 替换默认控件,但依赖收集仍由同一个 action 完成: ```tsx {({ disabled, execute }) => ( execute(mention)} /> )} ``` render context 中的 `execute(value?)` 会调用该 action,并保留 value 类型。 `onClick` 是 `execute()` 的无参快捷方式,适合普通按钮。 图片和视频 action 在不传 value 时继续使用内置输入弹窗;自定义上传器可以 在上传结束后直接把结果交给 `execute`,不需要操作 Lexical editor: ```tsx {({ execute }) => ( execute({ src, alt, caption }) } /> )} ``` ## 粘贴图片 `full` 预设已包含 ``:直接粘贴截图或拖入图片文件时, 会立即插入本地预览;默认完成后把图片编码成可序列化的 `data:` URL。 生产环境通常更适合传入 `resolveImage`,先把图片上传到对象存储,再返回 持久 URL。上传期间可通过 `reportProgress` 汇报 `0` 到 `1` 的进度;不汇报 时编辑器会显示不确定进度: ```tsx import { ClipboardImages, LexicalActions } from "@workspace/lexical" ; {/* 其他 action */} { const uploaded = await uploadImage(file, { signal, onProgress: reportProgress, }) return { alt: file.name, src: uploaded.url, } }} onError={(error, file) => reportUploadError(error, file)} /> ``` 非图片文件不会被编辑器接管,粘贴仍由浏览器处理。图片被选中后可以通过 控制点缩放、添加或修改说明、切换左/中/右对齐,也可以使用可见删除按钮、 Delete 或 Backspace 删除。该能力同时复用 Lexical 的文件拖放命令,因此 相同 resolver 也适用于拖入编辑器的图片。 没有可见控件、只提供编辑行为的能力也可以声明为 `hidden` action。包内的 `` 就使用这种方式,因此它会启用拖拽 plugin,但不会占据 任何工具栏位置。