Appearance
Workflow 服务 API
Workflow family 用来接入宿主和外部世界:上传、布局、持久化、分享、剪贴板、导入导出都属于这一层。
ts
import type { WorkflowServicePlugin } from '@shangchien/molio'WorkflowServicePlugin
ts
interface WorkflowServicePlugin {
manifest: PluginManifest
importers?: readonly DescriptorImporter[]
exporters?: readonly DescriptorExporter[]
clipboard?: ClipboardService
layout?: readonly LayoutService[]
persistence?: PersistenceService
share?: ShareService
upload?: UploadService
activate?: (ctx: PluginActivateContext) => void | Promise<void>
}宿主通常通过 optionalPlugins 注入 workflow:
vue
<MolEditor :optional-plugins="[hostWorkflowPlugin]" />UploadService
图片或大文件上传应由宿主接管。返回值必须包含最终可访问 URL。
ts
export const uploadWorkflow: WorkflowServicePlugin = {
manifest: { id: 'host:workflow.upload', name: 'Host Upload', version: '1.0.0' },
upload: {
id: 'host:upload',
accept: ['image/*'],
async upload(file) {
const formData = new FormData()
formData.append('file', file, 'image.png')
const res = await fetch('/api/upload', { method: 'POST', body: formData })
const data = await res.json()
return { url: data.url }
},
},
}PersistenceService
持久化服务负责保存和读取整篇文档。
ts
export const persistenceWorkflow: WorkflowServicePlugin = {
manifest: { id: 'host:workflow.persistence', name: 'Host Persistence', version: '1.0.0' },
persistence: {
id: 'host:persistence',
async save(ctx) {
const snapshot = ctx.store.snapshot()
return new Blob([JSON.stringify(snapshot)], { type: 'application/json' })
},
async load(ctx, source) {
const snapshot = JSON.parse(await source.text())
return snapshot.nodes
},
},
}组件 ref 上的 saveDocumentWithWorkflow() 和 loadDocumentWithWorkflow(file) 会读取当前激活的 persistence service。没有注册 persistence 时返回 null。
ShareService
分享服务负责生成 URL、二维码数据或可上传的 Blob。
ts
export const shareWorkflow: WorkflowServicePlugin = {
manifest: { id: 'host:workflow.share', name: 'Host Share', version: '1.0.0' },
share: {
id: 'host:share',
async share(ctx, nodeIds) {
const snapshot = ctx.store.snapshot()
const res = await fetch('/api/share', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ snapshot, nodeIds }),
})
const data = await res.json()
return { url: data.url }
},
},
}组件 ref 上的 shareDocumentWithWorkflow(nodeIds?) 返回 { url?: string, blob?: Blob } | null。
LayoutService
布局服务用于分子或对象的自动排布、美化、避让等场景。
ts
const layoutWorkflow: WorkflowServicePlugin = {
manifest: { id: 'host:workflow.layout', name: 'Host Layout', version: '1.0.0' },
layout: [
{
id: 'host:layout.compact',
async apply(ctx, nodeIds, options) {
console.log('layout target', nodeIds, options)
},
},
],
}组件 ref 上的 runWorkflowLayout(nodeIds?) 会调用 workflow registry 中的 layout 服务。
ClipboardService
Clipboard service 用于跨应用 rich-clip 或业务格式剪贴板。
ts
const clipboardWorkflow: WorkflowServicePlugin = {
manifest: { id: 'host:workflow.clipboard', name: 'Host Clipboard', version: '1.0.0' },
clipboard: {
id: 'host:clipboard',
async write(ctx, nodes) {
await navigator.clipboard.writeText(JSON.stringify(nodes))
},
async read() {
const text = await navigator.clipboard.readText()
return JSON.parse(text)
},
},
}Importers 和 exporters
importers 与 exporters 让宿主注册自定义格式。它们通过 descriptor/workflow registry 查询进入 shell 或 helper,而不是把格式逻辑写进 core。
设计边界
- 上传、保存、分享、业务格式转换属于宿主 workflow。
- 编辑器 core 只提供稳定的文档、selection、command、scene 和 transaction 入口。
- workflow helper 是 nullable:父组件必须处理返回
null的情况。