Explorar o código

docs: api docs

xiamidaxia hai 10 meses
pai
achega
d328ffaa6d
Modificáronse 27 ficheiros con 798 adicións e 2 borrados
  1. 11 1
      apps/demo-fixed-layout-simple/src/components/base-node.tsx
  2. 10 0
      apps/demo-fixed-layout/src/components/base-node/index.tsx
  3. 15 0
      apps/docs/src/zh/api/components/editor-renderer.mdx
  4. 21 0
      apps/docs/src/zh/api/components/fixed-layout-editor-provider.mdx
  5. 20 0
      apps/docs/src/zh/api/components/fixed-layout-editor.mdx
  6. 21 0
      apps/docs/src/zh/api/components/free-layout-editor-provider.mdx
  7. 18 0
      apps/docs/src/zh/api/components/free-layout-editor.mdx
  8. 28 0
      apps/docs/src/zh/api/components/workflow-node-renderer.mdx
  9. 32 1
      apps/docs/src/zh/api/core/flow-node-entity.mdx
  10. 98 0
      apps/docs/src/zh/api/core/playground.mdx
  11. 5 0
      apps/docs/src/zh/api/core/workflow-line-entity.mdx
  12. 28 0
      apps/docs/src/zh/api/core/workflow-lines-manager.mdx
  13. 20 0
      apps/docs/src/zh/api/hooks/use-client-context.mdx
  14. 66 0
      apps/docs/src/zh/api/hooks/use-node-render.mdx
  15. 69 0
      apps/docs/src/zh/api/hooks/use-playground-tools.mdx
  16. 28 0
      apps/docs/src/zh/api/hooks/use-refresh.mdx
  17. 56 0
      apps/docs/src/zh/api/hooks/use-service.mdx
  18. 5 0
      apps/docs/src/zh/api/services/clipboard-service.mdx
  19. 11 0
      apps/docs/src/zh/api/services/command-service.mdx
  20. 5 0
      apps/docs/src/zh/api/services/flow-operation-service.mdx
  21. 49 0
      apps/docs/src/zh/api/services/history-service.mdx
  22. 13 0
      apps/docs/src/zh/api/services/selection-service.mdx
  23. 33 0
      apps/docs/src/zh/api/utils/disposable-collection.mdx
  24. 20 0
      apps/docs/src/zh/api/utils/disposable.mdx
  25. 41 0
      apps/docs/src/zh/api/utils/emitter.mdx
  26. 72 0
      apps/docs/src/zh/api/utils/get-node-form.mdx
  27. 3 0
      apps/docs/src/zh/guide/advanced/interactive/shortcuts.mdx

+ 11 - 1
apps/demo-fixed-layout-simple/src/components/base-node.tsx

@@ -15,14 +15,24 @@ export const BaseNode = ({ node }: { node: FlowNodeEntity }) => {
   return (
   return (
     <div
     <div
       className="demo-fixed-node"
       className="demo-fixed-node"
+      /*
+       * onMouseEnter is added to a fixed layout node primarily to listen for hover highlighting of branch lines
+       * onMouseEnter 加到固定布局节点主要是为了监听 分支线条的 hover 高亮
+       **/
       onMouseEnter={nodeRender.onMouseEnter}
       onMouseEnter={nodeRender.onMouseEnter}
       onMouseLeave={nodeRender.onMouseLeave}
       onMouseLeave={nodeRender.onMouseLeave}
-      onMouseDown={e => {
+      onMouseDown={(e) => {
         // trigger drag node
         // trigger drag node
         nodeRender.startDrag(e);
         nodeRender.startDrag(e);
         e.stopPropagation();
         e.stopPropagation();
       }}
       }}
       style={{
       style={{
+        /**
+         * Lets you precisely control the style of branch nodes
+         * 用于精确控制分支节点的样式
+         * isBlockIcon: 整个 condition 分支的 头部节点
+         * isBlockOrderIcon: 分支的第一个节点
+         */
         ...(nodeRender.isBlockOrderIcon || nodeRender.isBlockIcon ? { width: 260 } : {}),
         ...(nodeRender.isBlockOrderIcon || nodeRender.isBlockIcon ? { width: 260 } : {}),
       }}
       }}
     >
     >

+ 10 - 0
apps/demo-fixed-layout/src/components/base-node/index.tsx

@@ -28,9 +28,19 @@ export const BaseNode = ({ node }: { node: FlowNodeEntity }) => {
     <ConfigProvider getPopupContainer={getPopupContainer}>
     <ConfigProvider getPopupContainer={getPopupContainer}>
       {form?.state.invalid && <ErrorIcon />}
       {form?.state.invalid && <ErrorIcon />}
       <BaseNodeStyle
       <BaseNodeStyle
+        /*
+         * onMouseEnter is added to a fixed layout node primarily to listen for hover highlighting of branch lines
+         * onMouseEnter 加到固定布局节点主要是为了监听 分支线条的 hover 高亮
+         **/
         onMouseEnter={nodeRender.onMouseEnter}
         onMouseEnter={nodeRender.onMouseEnter}
         onMouseLeave={nodeRender.onMouseLeave}
         onMouseLeave={nodeRender.onMouseLeave}
         style={{
         style={{
+          /**
+           * Lets you precisely control the style of branch nodes
+           * 用于精确控制分支节点的样式
+           * isBlockIcon: 整个 condition 分支的 头部节点
+           * isBlockOrderIcon: 分支的第一个节点
+           */
           ...(nodeRender.isBlockOrderIcon || nodeRender.isBlockIcon ? { width: 260 } : {}),
           ...(nodeRender.isBlockOrderIcon || nodeRender.isBlockIcon ? { width: 260 } : {}),
           outline: form?.state.invalid ? '1px solid red' : 'none',
           outline: form?.state.invalid ? '1px solid red' : 'none',
         }}
         }}

+ 15 - 0
apps/docs/src/zh/api/components/editor-renderer.mdx

@@ -0,0 +1,15 @@
+# EditorRenderer
+
+画布渲染组件,需要 配合 `FixedLayoutEditorProvider` 或 `FreeLayoutEditorProvider` 使用
+
+```tsx pure
+function App() {
+  return (
+    <FixedLayoutEditorProvider {...editorProps}>
+      <EditorRenderer className="demo-editor" style={{ /* style */}}>
+        {/* 如果提供 children,该内容会放到 画布 div 下边 */}
+      </EditorRenderer>
+    </FixedLayoutEditorProvider>
+  )
+}
+```

+ 21 - 0
apps/docs/src/zh/api/components/fixed-layout-editor-provider.mdx

@@ -0,0 +1,21 @@
+# FixedLayoutEditorProvider
+
+固定布局画布配置器,支持 ref
+
+```tsx pure
+import { FixedLayoutEditorProvider, FixedLayoutPluginContext, EditorRenderer } from '@flowgram.ai/fixed-layout-editor'
+
+function App() {
+  const ref = useRef<FixedLayoutPluginContext | undefined>();
+
+  useEffect(() => {
+    console.log(ref.current.document.toJSON())
+  }, [])
+  return (
+    <FixedLayoutEditorProvider {...editorProps} ref={ref}>
+      <EditorRenderer className="demo-editor" />
+    </FixedLayoutEditorProvider>
+  )
+}
+
+```

+ 20 - 0
apps/docs/src/zh/api/components/fixed-layout-editor.mdx

@@ -0,0 +1,20 @@
+# FixedLayoutEditor
+
+
+固定布局画布, 等价于 `FixedLayoutEditorProvider` 和 `EditorRenderer` 的组合
+
+```tsx pure
+import { FixedLayoutEditor, FixedLayoutPluginContext } from '@flowgram.ai/fixed-layout-editor'
+
+function App() {
+  const ref = useRef<FixedLayoutPluginContext | undefined>();
+
+  useEffect(() => {
+    console.log(ref.current.document.toJSON())
+  }, [])
+
+  return (
+    <FixedLayoutEditor className="demo-editor" {...editorProps} ref={ref} />
+  )
+}
+```

+ 21 - 0
apps/docs/src/zh/api/components/free-layout-editor-provider.mdx

@@ -0,0 +1,21 @@
+# FreeLayoutEditorProvider
+
+自由布局画布配置器,支持 ref
+
+```tsx pure
+import { FreeLayoutEditorProvider, FreeLayoutPluginContext, EditorRenderer } from '@flowgram.ai/free-layout-editor'
+
+function App() {
+  const ref = useRef<FreeLayoutPluginContext | undefined>();
+
+  useEffect(() => {
+    console.log(ref.current.document.toJSON())
+  }, [])
+  return (
+    <FreeLayoutEditorProvider {...editorProps} ref={ref}>
+      <EditorRenderer className="demo-editor" />
+    </FreeLayoutEditorProvider>
+  )
+}
+
+```

+ 18 - 0
apps/docs/src/zh/api/components/free-layout-editor.mdx

@@ -0,0 +1,18 @@
+# FreeLayoutEditor
+
+自由布局画布, 等价于 `FreeLayoutEditorProvider` 和 `EditorRenderer` 的组合
+
+```tsx pure
+import { FreeLayoutEditor, FreeLayoutPluginContext } from '@flowgram.ai/free-layout-editor'
+
+function App() {
+  const ref = useRef<FreeLayoutPluginContext | undefined>();
+
+  useEffect(() => {
+    console.log(ref.current.document.toJSON())
+  }, [])
+  return (
+    <FreeLayoutEditor className="demo-editor" {...editorProps} ref={ref} />
+  )
+}
+```

+ 28 - 0
apps/docs/src/zh/api/components/workflow-node-renderer.mdx

@@ -0,0 +1,28 @@
+# WorkflowNodeRenderer(free)
+
+自由布局节点容器
+
+## Usage
+
+```tsx pure
+import { useNodeRender, WorkflowNodeRenderer } from '@flowgram.ai/free-layout-editor';
+
+export const BaseNode = () => {
+  /**
+   * 提供节点渲染相关的方法
+   */
+  const { form } = useNodeRender()
+  /**
+   * WorkflowNodeRenderer 会添加节点拖拽事件及 端口渲染,如果要深度定制,可以看该组件源代码:
+   * https://github.com/coze-dev/flowgram.ai/blob/main/packages/client/free-layout-editor/src/components/workflow-node-renderer.tsx
+   */
+  return (
+    <WorkflowNodeRenderer className="demo-free-node" node={props.node}>
+      {
+        // 表单渲染通过 formMeta 生成
+        form?.render()
+      }
+    </WorkflowNodeRenderer>
+  )
+};
+```

+ 32 - 1
apps/docs/src/zh/api/core/flow-node-entity.mdx

@@ -1,6 +1,6 @@
 # FlowNodeEntity/WorkflowNodeEntity
 # FlowNodeEntity/WorkflowNodeEntity
 
 
-节点实体,`WorkflowNodeEntity` 为节点别名用于自由布局节点, 节点实体采用 [ECS](/flowgram.ai/guide/concepts/ECS.html) 架构
+节点实体,`WorkflowNodeEntity` 为节点别名用于自由布局节点, 节点实体采用 [ECS](/flowgram.ai/guide/concepts/ECS.html) 架构, 为 `Entity`
 
 
 [> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/document/classes/FlowNodeEntity-1.html)
 [> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/document/classes/FlowNodeEntity-1.html)
 
 
@@ -56,8 +56,39 @@ const nodeRegistry = node.getNodeRegistry<FlowNodeRegistry>()
 
 
 ### getData
 ### getData
 
 
+等价于 [ECS](/flowgram.ai/guide/concepts/ECS.html) 架构 里获取 Entity 的 Component,目前内置两个核心 Component
+
+```ts pure
+node.getData(FlowNodeTransformData) // transform 矩阵数据, 包含节点的 x,y,width,height 等信息
+node.getData(FlowNodeRenderData) // 节点的渲染数据, 包含渲染状态等数据
+
+```
+
 ### addData
 ### addData
 
 
+等价于 [ECS](/flowgram.ai/guide/concepts/ECS.html) 架构 里添加 Entity 的 Component
+
+```ts pure
+
+// 自定义 EntityData
+class CustomEntityData extends EntityData<{ key0: string }> {
+  static type = 'CustomEntityData';
+  getDefaultData() {
+    return {
+      key0: 'test'
+    }
+  }
+}
+
+// 添加 Enitty Component
+node.addData(CustomEntityData)
+
+
+// 更新 Entity Component 数据
+node.getData(CustomEntityData).update({ key0: 'new value' })
+
+```
+
 ### getService
 ### getService
 
 
 节点访问 [IOC](/flowgram.ai/guide/concepts/IOC.html) 服务
 节点访问 [IOC](/flowgram.ai/guide/concepts/IOC.html) 服务

+ 98 - 0
apps/docs/src/zh/api/core/playground.mdx

@@ -1 +1,99 @@
 # Playground
 # Playground
+
+画布实例
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/core/classes/Playground.html)
+
+```ts pure
+const ctx = useClientContext()
+
+console.log(ctx.playground)
+
+```
+## config
+
+画布配置, 提供 zoom、scroll 等状态
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/core/classes/PlaygroundConfigEntity.html)
+
+### Properties
+- zoom `number` 当前缩放比例
+- scrollData `{ scrollX: number, scrollY: number }` 当前滚动位置
+- readonlyOrDisabled 画布是否为 readonly 或 disabled 状态
+- readonly
+- disabled
+
+
+### fitView
+
+节点适应画布窗口, 需要传入节点的 bounds
+
+```ts pure
+/**
+ * 适应大小
+ * @param bounds {Rectangle} 目标大小
+ * @param easing {number} 是否开启动画,默认开启
+ * @param padding {number} 边界空白
+ */
+ctx.playground.config.fitView(ctx.document.root.bounds, true, 10)
+```
+
+### scrollToView
+
+指定节点位置并滚动到画布可见区域, 如果位置已经在可见区域则不会滚动,除非加上 `scrollToCenter` 强制滚动
+
+```ts pure
+
+/**
+ * 详细参数说明
+ * @param opts {PlaygroundConfigRevealOpts}
+**/
+interface PlaygroundConfigRevealOpts {
+  entities?: Entity[]
+  position?: PositionSchema // 滚动到指定位置,并居中
+  bounds?: Rectangle // 滚动的 bounds
+  scrollDelta?: PositionSchema
+  zoom?: number // 需要缩放的比例
+  easing?: boolean // 是否开启缓动,默认开启
+  easingDuration?: number // 默认 500 ms
+  scrollToCenter?: boolean // 是否强制滚动到中心
+}
+
+ctx.playground.config.scrollToView({
+  bounds: ctx.document.getNode('start').bounds,
+})
+```
+
+### zoomin
+
+放大画布
+
+### zoomout
+
+缩小画布
+
+### getPoseFromMouseEvent
+
+将浏览器鼠标位置转成画布坐标系
+
+```ts pure
+
+const pos: { x: number, y: number } = ctx.playground.config.getPoseFromMouseEvent(domMouseEvent)
+
+```
+
+### scroll
+
+滚动画布, 需要传入滚动位置, 以及是否平滑滚动, 滚动时间
+
+```ts pure
+ctx.playground.config.scroll({ scrollX: 100, scrollY: 100 }, true, 300)
+```
+
+### getViewport
+
+获取当前画布的视窗大小
+
+```ts pure
+const viewport = ctx.playground.config.getViewport()
+```

+ 5 - 0
apps/docs/src/zh/api/core/workflow-line-entity.mdx

@@ -1 +1,6 @@
 # WorkflowLineEntity (free)
 # WorkflowLineEntity (free)
+
+自由布局线条实体
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/free-layout-core/classes/WorkflowLineEntity.html)
+

+ 28 - 0
apps/docs/src/zh/api/core/workflow-lines-manager.mdx

@@ -1 +1,29 @@
 # WorkflowLinesManager (free)
 # WorkflowLinesManager (free)
+
+自由布局线条管理, 目前挂在自由布局 document 下边
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/free-layout-core/classes/WorkflowLinesManager.html)
+
+```
+import { useClientContext } from '@flowgram.ai/free-layout-editor'
+
+const ctx = useClientContext();
+console.log(ctx.document.linesManager)
+```
+
+## getAllLines
+
+获取所有线条的实体
+
+```ts pure
+const allLines = ctx.document.linesManager.getAllLines()
+
+```
+
+## toJSON
+
+导出线条数据
+
+```ts pure
+const json = ctx.document.linesManager.toJSON()
+```

+ 20 - 0
apps/docs/src/zh/api/hooks/use-client-context.mdx

@@ -1 +1,21 @@
 # useClientContext
 # useClientContext
+
+提供在 react 内部访问画布的上下文, 目前固定布局和 自由布局有一定区别
+
+## 固定布局
+
+- Return: [FixedLayoutPluginContext](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-layout-editor/interfaces/FixedLayoutPluginContext.html)
+
+```ts pure
+import { useClientContext } from '@flowgram.ai/fixed-layout-editor'
+const ctx = useClientContext()
+```
+
+## 自由布局
+
+- Return: [FreeLayoutPluginContext](https://coze-dev.github.io/flowgram.ai/auto-docs/free-layout-editor/interfaces/FreeLayoutPluginContext.html)
+
+```ts pure
+import { useClientContext } from '@flowgram.ai/free-layout-editor'
+const ctx = useClientContext()
+```

+ 66 - 0
apps/docs/src/zh/api/hooks/use-node-render.mdx

@@ -1 +1,67 @@
 # useNodeRender
 # useNodeRender
+
+提供节点渲染相关的方法, 返回结果的 form 等价于 [getNodeForm](/api/utils/get-node-form.html)
+
+## 固定布局
+
+- Return: [NodeRenderReturnType](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-layout-editor/interfaces/NodeRenderReturnType.html)
+
+```tsx pure
+
+import { FlowNodeEntity, useNodeRender } from '@flowgram.ai/fixed-layout-editor';
+
+export const BaseNode = ({ node }: { node: FlowNodeEntity }) => {
+  /**
+   * 提供节点渲染相关的方法
+   */
+  const nodeRender = useNodeRender();
+  /**
+   * 只有在节点引擎开启时候才能使用表单
+   */
+  const form = nodeRender.form;
+
+  return (
+    <div
+      className="demo-fixed-node"
+      /*
+       * onMouseEnter 加到固定布局节点主要是为了监听 分支线条的 hover 高亮
+       **/
+      onMouseEnter={nodeRender.onMouseEnter}
+      onMouseLeave={nodeRender.onMouseLeave}
+      onMouseDown={e => {
+        // trigger drag node
+        nodeRender.startDrag(e);
+        e.stopPropagation();
+      }}
+      style={{
+        /**
+         * 用于精确控制分支节点的样式
+         * isBlockIcon: 整个 condition 分支的 头部节点
+         * isBlockOrderIcon: 分支的第一个节点
+         */
+        ...(nodeRender.isBlockOrderIcon || nodeRender.isBlockIcon ? { width: 260 } : {}),
+      }}
+    >
+      {form?.render()}
+    </div>
+  );
+};
+
+```
+
+## 自由布局
+
+- Return: [NodeRenderReturnType](https://coze-dev.github.io/flowgram.ai/auto-docs/free-layout-core/interfaces/NodeRenderReturnType.html)
+
+```tsx pure
+import { WorkflowNodeRenderer, useNodeRender } from '@flowgram.ai/free-layout-editor';
+export const BaseNode = () => {
+  const { form, node } = useNodeRender()
+  return (
+    <WorkflowNodeRenderer className="demo-free-node" node={node}>
+      {form?.render()}
+    </WorkflowNodeRenderer>
+  )
+}
+
+```

+ 69 - 0
apps/docs/src/zh/api/hooks/use-playground-tools.mdx

@@ -1 +1,70 @@
 # usePlaygroundTools
 # usePlaygroundTools
+
+画布工具方法
+
+## 固定布局
+
+- Return: [PlaygroundTools](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-layout-editor/interfaces/PlaygroundTools.html)
+```tsx pure
+import { useEffect, useState } from 'react'
+import { usePlaygroundTools, useClientContext } from '@flowgram.ai/fixed-layout-editor';
+
+export function Tools() {
+  const { history } = useClientContext();
+  const tools = usePlaygroundTools();
+  const [canUndo, setCanUndo] = useState(false);
+  const [canRedo, setCanRedo] = useState(false);
+
+  useEffect(() => {
+    const disposable = history.undoRedoService.onChange(() => {
+      setCanUndo(history.canUndo());
+      setCanRedo(history.canRedo());
+    });
+    return () => disposable.dispose();
+  }, [history]);
+
+  return <div style={{ position: 'absolute', zIndex: 10, bottom: 16, left: 16, display: 'flex', gap: 8 }}>
+    <button onClick={() => tools.zoomin()}>ZoomIn</button>
+    <button onClick={() => tools.zoomout()}>ZoomOut</button>
+    <button onClick={() => tools.fitView()}>Fitview</button>
+    <button onClick={() => tools.changeLayout()}>ChangeLayout</button>
+    <button onClick={() => history.undo()} disabled={!canUndo}>Undo</button>
+    <button onClick={() => history.redo()} disabled={!canRedo}>Redo</button>
+    <span>{Math.floor(tools.zoom * 100)}%</span>
+  </div>
+}
+```
+
+
+## 自由布局
+
+- Return: [PlaygroundTools](https://coze-dev.github.io/flowgram.ai/auto-docs/free-layout-editor/interfaces/PlaygroundTools.html)
+
+```tsx pure
+import { usePlaygroundTools, useClientContext } from '@flowgram.ai/free-layout-editor';
+
+export function Tools() {
+  const { history } = useClientContext();
+  const tools = usePlaygroundTools();
+  const [canUndo, setCanUndo] = useState(false);
+  const [canRedo, setCanRedo] = useState(false);
+
+  useEffect(() => {
+    const disposable = history.undoRedoService.onChange(() => {
+      setCanUndo(history.canUndo());
+      setCanRedo(history.canRedo());
+    });
+    return () => disposable.dispose();
+  }, [history]);
+
+  return <div style={{ position: 'absolute', zIndex: 10, bottom: 16, left: 226, display: 'flex', gap: 8 }}>
+    <button onClick={() => tools.zoomin()}>ZoomIn</button>
+    <button onClick={() => tools.zoomout()}>ZoomOut</button>
+    <button onClick={() => tools.fitView()}>Fitview</button>
+    <button onClick={() => tools.autoLayout()}>AutoLayout</button>
+    <button onClick={() => history.undo()} disabled={!canUndo}>Undo</button>
+    <button onClick={() => history.redo()} disabled={!canRedo}>Redo</button>
+    <span>{Math.floor(tools.zoom * 100)}%</span>
+  </div>
+}
+```

+ 28 - 0
apps/docs/src/zh/api/hooks/use-refresh.mdx

@@ -1 +1,29 @@
 # useRefresh
 # useRefresh
+
+## Source Code
+
+```ts
+import { useCallback, useState } from 'react';
+
+export function useRefresh(defaultValue?: any): (v?: any) => void {
+  const [, update] = useState<any>(defaultValue);
+  return useCallback((v?: any) => update(v !== undefined ? v : {}), []);
+}
+```
+
+## Usage
+
+```tsx pure
+import { useRefresh } from '@flowgram.ai/fixed-layout-editor';
+
+function Demo() {
+  const refresh = useRefresh();
+  return (
+    <div>
+      <button onClick={() => refresh()}>Refresh</button>
+    </div>
+  )
+}
+
+```
+

+ 56 - 0
apps/docs/src/zh/api/hooks/use-service.mdx

@@ -1 +1,57 @@
 # useService
 # useService
+
+获取底层 [IOC](/flowgram.ai/guide/concepts/IOC.html) 的所有单例模块
+
+```ts pure
+
+const playground = useService<Playground>(Playground)
+const flowDocument = useService<FlowDocument>(FlowDocument)
+const historyService = useService<HistoryService>(HistoryService)
+
+// 等价
+const playground1 = useClientContext().playground
+
+// 等价
+const playground3 = useClientContext().get<Playground>(Playground)
+
+```
+
+
+
+## 自定义 Service
+
+```tsx pure
+/**
+ *  inversify: https://github.com/inversify/InversifyJS
+ */
+import { injectable } from 'inversify'
+
+@injectable()
+class MyService {
+  // ...
+}
+
+import { useMemo } from 'react';
+import { type FixedLayoutProps } from '@flowgram.ai/fixed-layout-editor';
+
+function BaseNode() {
+  const mySerivce = useService<MyService>(MyService)
+}
+
+export function useEditorProps(
+): FixedLayoutProps {
+  return useMemo<FixedLayoutProps>(
+    () => ({
+      // ....other props
+      onBind: ({ bind }) => {
+        bind(MyService).toSelf().inSingletonScope()
+      },
+      materials: {
+        renderDefaultNode: BaseNode
+      }
+    }),
+    [],
+  );
+}
+
+```

+ 5 - 0
apps/docs/src/zh/api/services/clipboard-service.mdx

@@ -0,0 +1,5 @@
+# ClipboardService
+
+剪贴板服务
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/core/interfaces/ClipboardService.html)

+ 11 - 0
apps/docs/src/zh/api/services/command-service.mdx

@@ -0,0 +1,11 @@
+# CommandService
+
+指令服务,需要和 [Shortcuts](/flowgram.ai/guide/advanced/interactive/shortcuts.html) 一起使用
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/command/interfaces/CommandService.html)
+
+
+```Usage
+
+ctx.get(CommandService).execCommand('selectAll')
+```

+ 5 - 0
apps/docs/src/zh/api/services/flow-operation-service.mdx

@@ -5,9 +5,14 @@
 [> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-layout-editor/interfaces/FlowOperationService.html)
 [> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-layout-editor/interfaces/FlowOperationService.html)
 
 
 ```typescript pure
 ```typescript pure
+const operationService = useService<FlowOperationService>(FlowOperationService)
+operationService.addNode({ id: 'xxx', type: 'custom', data: {} })
+
+// or
 const ctx = useClientContext();
 const ctx = useClientContext();
 ctx.operation.addNode({ id: 'xxx', type: 'custom', data: {} })
 ctx.operation.addNode({ id: 'xxx', type: 'custom', data: {} })
 
 
+
 ```
 ```
 
 
 ## Interface
 ## Interface

+ 49 - 0
apps/docs/src/zh/api/services/history-service.mdx

@@ -0,0 +1,49 @@
+## HistoryService
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/fixed-history-plugin/classes/HistoryService.html)
+
+## Redo/Undo
+
+```tsx pure
+import { useEffect, useState } from 'react'
+import { useClientContext } from '@flowgram.ai/fixed-layout-editor';
+
+export function Tools() {
+  const { history } = useClientContext();
+  const [canUndo, setCanUndo] = useState(false);
+  const [canRedo, setCanRedo] = useState(false);
+
+  useEffect(() => {
+    const disposable = history.undoRedoService.onChange(() => {
+      setCanUndo(history.canUndo());
+      setCanRedo(history.canRedo());
+    });
+    return () => disposable.dispose();
+  }, [history]);
+
+  return <div>
+    <button onClick={() => history.undo()} disabled={!canUndo}>Undo</button>
+    <button onClick={() => history.redo()} disabled={!canRedo}>Redo</button>
+  </div>
+}
+```
+
+## 渲染历史记录
+
+```tsx pure
+import { useEffect } from 'react'
+import { useRefresh, useClientContext } from '@flowgram.ai/fixed-layout-editor'
+
+function HistoryListRender() {
+  const refresh = useRefresh()
+  const ctx = useClientContext()
+  useEffect(() => {
+    ctx.history.onApply(() => refresh())
+  }, [ctx])
+  return (
+    <div>
+      {ctx.history.historyManager.historyStack.items.map((record) => <HistoryOperations key={record.id} operations={record.operations} />)}
+    </div>
+  )
+}
+```

+ 13 - 0
apps/docs/src/zh/api/services/selection-service.mdx

@@ -1 +1,14 @@
 # SelectionService
 # SelectionService
+
+用于控制选择的节点
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/core/classes/SelectionService.html)
+
+## Usage
+```tsx pure
+// Listen Selection Change
+ctx.selection.onSelectionChanged((nodes) => {
+})
+// Select All Nodes
+ctx.selection.selection = ctx.document.getAllNodes()
+```

+ 33 - 0
apps/docs/src/zh/api/utils/disposable-collection.mdx

@@ -0,0 +1,33 @@
+# DisposableCollection
+
+## Usage
+
+
+```ts pure
+
+import { DisposableCollection, Disposable } from '@flowgram.ai/utils'
+const disposable1: Disposable = {
+  dispose() {
+    console.log(1)
+  },
+};
+const disposable2: Disposable = {
+  dispose() {
+    console.log(2)
+  },
+};
+const dc = new DisposableCollection();
+dc.onDispose(() => {
+  console.log('end')
+});
+
+dc.pushAll([disposable1, disposable2]);
+dc.dispose(); // Log: 1, 2, dispose end
+
+```
+
+## Source Code
+
+https://github.com/coze-dev/flowgram.ai/blob/main/packages/common/utils/src/disposable.ts
+
+

+ 20 - 0
apps/docs/src/zh/api/utils/disposable.mdx

@@ -1 +1,21 @@
 # Disposable
 # Disposable
+
+## Interface
+
+```ts
+/**
+ * An object that performs a cleanup operation when `.dispose()` is called.
+ *
+ * Some examples of how disposables are used:
+ *
+ * - An event listener that removes itself when `.dispose()` is called.
+ * - The return value from registering a provider. When `.dispose()` is called, the provider is unregistered.
+ */
+export interface Disposable {
+  dispose(): void;
+}
+```
+
+## Source Code
+
+https://github.com/coze-dev/flowgram.ai/blob/main/packages/common/utils/src/disposable.ts

+ 41 - 0
apps/docs/src/zh/api/utils/emitter.mdx

@@ -1 +1,42 @@
 # Emitter
 # Emitter
+
+事件模块
+
+
+## Usage
+
+```tsx pure
+import { Emitter } from '@flowgram.ai/utils'
+
+class Doc {
+  private _content = ''
+  private _onContentChangeEmitter = new Emitter<string>()
+  readonly onContentChange = this._onContentChangeEmitter.event
+  setContent(content: string) {
+    this._content = content
+    this._onContentChangeEmitter.fire(content)
+  }
+  get content() {
+    return this._content
+  }
+}
+
+function App() {
+  const doc1 = useMemo(() => new Doc(), [])
+  const [content, updateContent] = useState(doc1.content)
+  useEffect(() => {
+    const toDispose = doc1.onContentChange((content) => {
+      updateContent(content)
+    })
+    return () => toDispose.dispose()
+  }, [doc1])
+  return <div>{content}</div>
+}
+
+
+```
+
+## Source Code
+
+https://github.com/coze-dev/flowgram.ai/blob/main/packages/common/utils/src/event.ts
+

+ 72 - 0
apps/docs/src/zh/api/utils/get-node-form.mdx

@@ -1 +1,73 @@
 # getNodeForm
 # getNodeForm
+
+获取节点的表单能力,需要开启 节点引擎才能使用
+
+[> API Detail](https://coze-dev.github.io/flowgram.ai/auto-docs/editor/functions/getNodeForm.html)
+
+
+## Usage
+
+```tsx pure
+
+function BaseNode({ node }) {
+  const form = getNodeForm(node);
+  console.log(form.getValueIn('title'))
+  return <div>{form?.render()}</div>
+}
+```
+
+## Return Inteface
+
+```ts pure
+
+export interface NodeFormProps<TValues> {
+  /**
+   * The initialValues of the form.
+   */
+  initialValues: TValues;
+  /**
+   * Form values. Returns a deep copy of the data in the store.
+   */
+  values: TValues;
+  /**
+   * Form state
+   */
+  state: FormState;
+  /**
+   * Get value in certain path
+   * @param name path
+   */
+  getValueIn<TValue = FieldValue>(name: FieldName): TValue;
+
+  /**
+   * Set value in certain path.
+   * It will trigger the re-rendering of the Field Component if a Field is related to this path
+   * @param name path
+   */
+  setValueIn<TValue>(name: FieldName, value: TValue): void;
+  /**
+   * Render form
+   */
+  render: () => React.ReactNode;
+  /**
+   * Form value change event
+   */
+  onFormValuesChange: Event<OnFormValuesChangePayload>;
+  /**
+   * Trigger form validate
+   */
+  validate: () => Promise<boolean>;
+  /**
+   * Form validate event
+   */
+  onValidate: Event<FormState>;
+  /**
+   * Form field value change event
+   */
+  onFormValueChangeIn<TValue = FieldValue, TFormValue = FieldValue>(
+    name: FieldName,
+    callback: (payload: onFormValueChangeInPayload<TValue, TFormValue>) => void
+  ): void;
+}
+```
+

+ 3 - 0
apps/docs/src/zh/guide/advanced/interactive/shortcuts.mdx

@@ -29,4 +29,7 @@ const commandService = useService(CommandService)
  * 调用命令服务, args 参数会透传给 execute 和 isEnabled
  * 调用命令服务, args 参数会透传给 execute 和 isEnabled
  */
  */
 commandService.executeCommand('selectAll', ...args)
 commandService.executeCommand('selectAll', ...args)
+
+// OR
+ctx.get(CommandService).executeCommand('selectAll', ...args)
 ```
 ```