Skip to content

基础交互 API ​

本页记录@skynote/plugins-basic中供宿主主动调用的接口。交互效果与快捷键见基础交互手册,常用节点、视口和历史命令优先使用Editor API。

先选择装配入口 ​

使用SkyNoteEditor时直接访问editor.textEditor及Editor方法,不要为了接工具栏再安装一套文字、选择或连线插件。相同插件ID会替换已装配实例;Editor持有的实例与宿主新建实例不是同一个对象。

直接使用Core时自行组合插件,保存需要主动调用的实例。下例只完成平台中立引擎装配;字体度量、渲染器挂载、宿主输入桥接和最终engine.destroy()仍由宿主负责,不是完整浏览器启动例子。

ts
/** 仅直接使用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为文字范围,不能作为节点或页面的坐标使用。

ts
/** 在工具栏挂载时订阅,关闭或卸载工具栏时调用返回的解绑函数。 */
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。

配置 / 成员类型与默认值说明
connectorTypestring,默认orthogonal新连线的路由器ID;基础线型为straight、orthogonal、curved
styleConnectorStyle,默认{ 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。需要替换插件时走引擎插件管理,并确认宿主保存的实例引用也同步更新。

可组合的画布能力,从一个想法开始。