基础交互 API
本页记录@skynote/plugins-basic中供宿主主动调用的接口。交互效果与快捷键见基础交互手册,常用节点、视口和历史命令优先使用Editor API。
先选择装配入口
使用SkyNoteEditor时直接访问editor.textEditor及Editor方法,不要为了接工具栏再安装一套文字、选择或连线插件。相同插件ID会替换已装配实例;Editor持有的实例与宿主新建实例不是同一个对象。
直接使用Core时自行组合插件,保存需要主动调用的实例。下例只完成平台中立引擎装配;字体度量、渲染器挂载、宿主输入桥接和最终engine.destroy()仍由宿主负责,不是完整浏览器启动例子。
/** 仅直接使用Core时自行装配;SkyNoteEditor已默认安装这些能力。 */
export function createBasicEngine(fonts: FontMeasurer): SkyNoteEngine {
return new SkyNoteEngine({ fonts })
.use(new BasicNodesPlugin())
.use(new BranchConnectorsPlugin())
.use(new ViewportNavigationPlugin())
.use(new SelectionPlugin())
.use(new SelectionOutlinePlugin())
.use(new EditingShortcutsPlugin())
.use(new TransformPlugin())
.use(new ClipboardPlugin())
.use(new ConnectorToolPlugin({ connectorType: 'orthogonal', style: { endArrow: true } }))
.use(new ConnectorEditPlugin())
.use(new TextEditPlugin());
}除ConnectorToolPlugin(options?)外,下表中的插件均使用无参数构造函数。小地图也是无参数构造,需单独安装和启用,见小地图API。
| 类 | 作用 | 宿主主动入口 |
|---|---|---|
BasicNodesPlugin | 注册六类基础节点和堆叠布局 | 通过Editor创建节点;类型与参数见基础插件 |
BranchConnectorsPlugin | 派生布局分支线及写入样式覆盖 | setBranchStyle、clearBranchStyle、clearLineStyle |
ViewportNavigationPlugin | 平移、缩放与导航快捷键 | 使用Editor的视口方法 |
SelectionPlugin | 选择、框选与移动 | 使用Editor的选择方法 |
SelectionOutlinePlugin | 选区与控制柄显示 | 由引擎会话和指针输入驱动 |
EditingShortcutsPlugin | 撤销、组合、删除等快捷键 | 使用Editor的对应命令 |
TransformPlugin | 缩放与旋转手势 | 使用Editor的尺寸与旋转方法 |
ClipboardPlugin | 结构化复制、剪切与粘贴 | copy、cut、paste |
ConnectorToolPlugin | 连线创建与空白处落点通知 | 配置、onDropOnBlank、connectNewNode |
ConnectorEditPlugin | 端点与路由手势编辑 | 使用Editor的连线方法 |
TextEditPlugin | 节点与连线的文字编辑 | 状态查询、格式命令、onChange、exit |
install(ctx)、unmount()以及各类onPointer*是引擎调用的生命周期与输入钩子。宿主不要自行调用这些方法来模拟点击、卸载或文字输入;走输入桥接、InputScope与插件管理协议。
TextEditPlugin
Editor默认实例为editor.textEditor。以下查询与命令在插件安装后使用;销毁Editor后不再调用。
| 成员 / 签名 | 说明 |
|---|---|
snapshot: TextEditSnapshot | null | 当前文字编辑态,未编辑为null;包含kind(node或connector)、实体id、blockId和文字范围start/end |
formatState: TextFormatState | null | 当前格式目标,没有可设置格式的文字时为null;未处于编辑态也可能返回选中节点整块文字的格式 |
editingBounds: RectBounds | null | 编辑中文字的世界外框,未编辑时为null;宿主通过Editor换算屏幕位置 |
onChange(listener: () => void): () => void | 订阅编辑态、文字选区及格式目标变化,返回解绑函数;不代替视口订阅 |
applyStyle(patch: RichTextStylePatch): void | 设置格式;编辑中为空文字选区时修改接下来输入的样式 |
toggleFormat(format: TextFormat): void | 切换bold/italic/underline/strikethrough;目标全部具备该格式时取消,否则统一启用 |
clearFormat(): void | 清除行内格式,保留段落对齐 |
setAlign(align: TextAlign): void | 设置段落对齐;编辑时作用于文字选区覆盖的段落,未编辑时作用于整块文字 |
setVerticalAlign(verticalAlign: VerticalAlign): void | 设置固定高度文字块的垂直对齐;先查询verticalAlignable |
exit(): void | 结束当前文字编辑并清理编辑态;保留选择,可能按节点规则移除空内容;不销毁插件 |
TextFormatState.style只返回目标共有的生效样式,不能把某个键缺失理解成它一定关闭。align或verticalAlign为undefined可表示混合值;verticalAlignable表示存在可设置垂直对齐的固定高度文字块。
TextAlign取值为left/center/right/justify,VerticalAlign为top/middle/bottom。snapshot的start/end为文字范围,不能作为节点或页面的坐标使用。
/** 在工具栏挂载时订阅,关闭或卸载工具栏时调用返回的解绑函数。 */
export function observeTextFormat(
editor: SkyNoteEditor<HTMLElement>,
render: (state: TextFormatState | null) => void
): () => void {
const update = (): void => render(editor.textEditor.formatState);
const unsubscribe = editor.textEditor.onChange(update);
update();
return unsubscribe;
}
export function applyTextAppearance(editor: SkyNoteEditor<HTMLElement>): void {
editor.textEditor.applyStyle({ fontSize: 18, color: '$blue' });
editor.textEditor.setAlign('center');
if (editor.textEditor.formatState?.verticalAlignable) editor.textEditor.setVerticalAlign('middle');
}颜色、背景色和字号等同类连续调整由插件合并编辑历史;格式开关与打字段落的历史分组不同。写入仍受只读、锁定与事务约束,void返回值不表示一定产生了补丁。按钮和面板需要正确保留或切换画布焦点,输入法组合过程交给宿主输入桥接。
ConnectorToolPlugin
直接使用Core时可传ConnectorToolOptions;通过Editor接入时优先使用startConnectorTool、onConnectorDropOnBlank和connectNewNode。
| 配置 / 成员 | 类型与默认值 | 说明 |
|---|---|---|
connectorType | string,默认orthogonal | 新连线的路由器ID;基础线型为straight、orthogonal、curved |
style | ConnectorStyle,默认{ endArrow: true } | 新连线样式;主动更新时整体替换对象,避免就地修改 |
onDropOnBlank(listener) | (event: ConnectorDropEvent) => void,返回() => void | 已绘制的连线留下自由端时通知,返回解绑函数 |
connectNewNode(connectorId, request) | ConnectNodeRequest → string | null | 在自由端创建并连接节点,一步撤销,成功选中新节点;连线不存在、无自由端或创建失败时为null |
ConnectorDropEvent包含connectorId与自由端的世界坐标point。ConnectNodeRequest基于节点创建请求移除x/y/origin/parentId,位置由自由端决定;宿主应在用户选定节点类型后调用,不再单独创建第二条连线。
ClipboardPlugin
| 方法 | 返回与行为 |
|---|---|
copy(): ClipboardData | null | 序列化当前选区,没有可复制内容时为null;不会自动写系统剪贴板 |
cut(): ClipboardData | null | 序列化并删除可剪切实体;只读时为null,锁定实体会过滤;宿主负责系统写入及失败策略 |
paste(data: ClipboardData, files?: readonly unknown[]): boolean | 返回是否消费输入;true不保证资产已加载或文档已写入成功 |
ClipboardData是按MIME类型组织的字符串数据。解析内部节点格式失败时也可能返回true并报告资产错误;图片粘贴会启动异步资产任务。宿主通过资产任务事件展示结果,不把boolean当作异步任务成功信号。文本编辑中的复制粘贴应由引擎注册的剪贴板处理链分发,避免绕过当前文字选区。
只调用copy()或paste()不会自动获得浏览器剪贴板权限。不要复制assetId字符串来代替媒体二进制与资产作用域处理,见文档与媒体。
BranchConnectorsPlugin
分支线由布局派生,通常不是单独持久化的普通连线。以下方法的memberIds为布局成员节点ID,不能换成普通连线ID;未安装相关布局时也不会凭空生成一棵结构树。
| 方法 | 说明 |
|---|---|
setBranchStyle(memberIds: Iterable<string>, patch: ConnectorStyle & { router?: string }, options?: CommandOptions): void | 设置通向父成员的线并沿子树继承;清除当前线同名的单线覆盖,保留后代单独覆盖;显式undefined用于清除对应设置 |
clearBranchStyle(memberIds: Iterable<string>, keys?: readonly (keyof ConnectorStyle)[], options?: CommandOptions): void | 不传keys时清除整枝及单线样式和线型;传keys时仅清除指定样式项;保留文字及连接点 |
clearLineStyle(memberIds: Iterable<string>, options?: CommandOptions): void | 仅清除单线样式与线型,保留整枝继承、文字及连接点 |
操作通过事务提交,支持CommandOptions中的label/groupId;无实际变化时不产生补丁。节点特有状态由插件公开协议管理,不直接改写文档中的布局字段。
释放与替换
所有事件注册返回的解绑函数由创建它的宿主调用。引擎管理插件生命周期和受管注册,销毁引擎时释放;不要在仍被引擎持有时直接调用实例unmount。需要替换插件时走引擎插件管理,并确认宿主保存的实例引用也同步更新。