瀏覽代碼

feat(docs): add plugin docs (#819)

July 4 月之前
父節點
當前提交
a1f166f0e8

+ 6 - 0
apps/demo-free-layout/src/components/problem-panel/index.ts

@@ -0,0 +1,6 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+export { PROBLEM_PANEL, problemPanelFactory, ProblemButton } from './problem-panel';

+ 53 - 0
apps/demo-free-layout/src/components/problem-panel/problem-panel.tsx

@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
+ * SPDX-License-Identifier: MIT
+ */
+
+import { PanelFactory, usePanelManager } from '@flowgram.ai/panel-manager-plugin';
+import { IconButton } from '@douyinfe/semi-ui';
+import { IconUploadError, IconClose } from '@douyinfe/semi-icons';
+export const PROBLEM_PANEL = 'problem-panel';
+
+export const ProblemPanel = () => {
+  const panelManager = usePanelManager();
+
+  return (
+    <div
+      style={{
+        width: '100%',
+        height: '200px',
+        borderRadius: '8px',
+        background: 'rgb(251, 251, 251)',
+        border: '1px solid rgba(82,100,154, 0.13)',
+      }}
+    >
+      <div style={{ display: 'flex', height: '50px', alignItems: 'center', justifyContent: 'end' }}>
+        <IconButton
+          type="tertiary"
+          theme="borderless"
+          icon={<IconClose />}
+          onClick={() => panelManager.close(PROBLEM_PANEL, 'bottom')}
+        />
+      </div>
+      <div>problem panel</div>
+    </div>
+  );
+};
+
+export const problemPanelFactory: PanelFactory<void> = {
+  key: PROBLEM_PANEL,
+  render: () => <ProblemPanel />,
+};
+
+export const ProblemButton = () => {
+  const panelManager = usePanelManager();
+
+  return (
+    <IconButton
+      type="tertiary"
+      theme="borderless"
+      icon={<IconUploadError />}
+      onClick={() => panelManager.open(PROBLEM_PANEL, 'bottom')}
+    />
+  );
+};

+ 2 - 0
apps/demo-free-layout/src/components/tools/index.tsx

@@ -22,6 +22,7 @@ import { Interactive } from './interactive';
 import { FitView } from './fit-view';
 import { Comment } from './comment';
 import { AutoLayout } from './auto-layout';
+import { ProblemButton } from '../problem-panel';
 
 export const DemoTools = () => {
   const { history, playground } = useClientContext();
@@ -72,6 +73,7 @@ export const DemoTools = () => {
             onClick={() => history.redo()}
           />
         </Tooltip>
+        <ProblemButton />
         <Divider layout="vertical" style={{ height: '16px' }} margin={3} />
         <AddNode disabled={playground.config.readonly} />
         <Divider layout="vertical" style={{ height: '16px' }} margin={3} />

+ 2 - 1
apps/demo-free-layout/src/hooks/use-editor-props.tsx

@@ -37,6 +37,7 @@ import { WorkflowNodeType } from '../nodes';
 import { testRunPanelFactory } from '../components/testrun/testrun-panel';
 import { nodeFormPanelFactory } from '../components/sidebar';
 import { SelectorBoxPopover } from '../components/selector-box-popover';
+import { problemPanelFactory } from '../components/problem-panel';
 import { BaseNode, CommentRender, GroupNodeRender, LineAddButton, NodePanel } from '../components';
 
 export function useEditorProps(
@@ -384,7 +385,7 @@ export function useEditorProps(
         }),
         /** Float layout plugin */
         createPanelManagerPlugin({
-          factories: [nodeFormPanelFactory, testRunPanelFactory],
+          factories: [nodeFormPanelFactory, testRunPanelFactory, problemPanelFactory],
         }),
       ],
     }),

+ 6 - 1
apps/docs/src/en/guide/advanced/_meta.json

@@ -23,7 +23,12 @@
   "history",
   "shortcuts",
   "minimap",
-  "custom-plugin",
+  {
+    "type": "dir",
+    "name": "plugin",
+    "label": "Plugin",
+    "collapsed": true
+  },
   "custom-service",
   "custom-layer",
   "form-materials",

+ 4 - 0
apps/docs/src/en/guide/advanced/plugin/_meta.json

@@ -0,0 +1,4 @@
+[
+  "custom-plugin",
+  "panel-manager-plugin"
+]

+ 0 - 0
apps/docs/src/en/guide/advanced/custom-plugin.mdx → apps/docs/src/en/guide/advanced/plugin/custom-plugin.mdx


+ 100 - 0
apps/docs/src/en/guide/advanced/plugin/panel-manager-plugin.mdx

@@ -0,0 +1,100 @@
+import { PackageManagerTabs } from '@theme';
+
+# Panel Manager Plugin
+
+A plugin for managing different types of panels.
+
+## Features
+
+- Easily integrate custom panels on the right or bottom of the canvas as React components with minimal setup.
+
+- No need for complex style adaptations—the plugin automatically calculates panel boundaries and layout.
+
+- Automatically manages the entry and exit of the panel queue.
+
+![Preview](@/public/plugin/panel-manager-1.png)
+
+## Quick Start
+
+1. Installation
+
+<PackageManagerTabs command="install @flowgram.ai/panel-manager-plugin" />
+
+2. Register the plugin
+
+The registration process is basically the same as other Flowgram plugins. Just make sure you don’t create duplicates and eventually pass it into the corresponding `LayoutEditorProvider`.
+
+```tsx
+import { createPanelManagerPlugin } from '@flowgram.ai/panel-manager-plugin';
+
+const editorProps = useMemo(() => ({
+  plugins: () => [createPanelManagerPlugin({})]
+}), []);
+
+return (
+  <FreeLayoutEditorProvider {...editorProps}>
+    <EditorRenderer />
+  </FreeLayoutEditorProvider>
+)
+```
+
+3. Register panel components
+
+A panel registration requires a unique key and a render function render that returns a ReactNode.
+
+For example, here’s a node form panel:
+
+```tsx
+import { type PanelFactory } from '@flowgram.ai/panel-manager-plugin';
+
+export const NODE_FORM_PANEL = 'node-form-panel';
+export const nodeFormPanelFactory: PanelFactory<NodeFormPanelProps> = {
+  key: NODE_FORM_PANEL,
+  render: (props: NodeFormPanelProps) => <NodeFormPanel {...props} />
+}
+```
+
+Pass the defined object into the plugin:
+
+```ts
+createPanelManagerPlugin({
+  factories: [nodeFormPanelFactory]
+})
+```
+
+4. Open/close panels
+
+Opening and closing panels is handled through an instance of PanelManager:
+
+```ts
+import { PanelManager } from '@flowgram.ai/panel-manager-plugin';
+
+class NodeFormService {
+  @inject(PanelManager): panelManager: PanelManager;
+
+  openPanel(nodeId: string) {
+    this.panelManager.open(NODE_FORM_PANEL, 'right', {
+      props: {
+        nodeId
+      }
+    })
+  }
+  closePanel() {
+    this.panelManager.close(NODE_FORM_PANEL, 'right')
+  }
+}
+```
+
+Alternatively, you can also access the instance in a React component via a hook:
+
+```tsx
+import { usePanelManager } from '@flowgram.ai/panel-manager-plugin';
+
+const panelManager = usePanelManager();
+
+<button
+  onClick={() => panelManager.open(TEST_RUN_FORM_PANEL, 'right')}
+>
+  Test Run
+</button>
+```

二進制
apps/docs/src/public/plugin/panel-manager-1.png


+ 6 - 1
apps/docs/src/zh/guide/advanced/_meta.json

@@ -23,7 +23,12 @@
   "history",
   "shortcuts",
   "minimap",
-  "custom-plugin",
+  {
+    "type": "dir",
+    "name": "plugin",
+    "label": "插件",
+    "collapsed": true
+  },
   "custom-service",
   "custom-layer",
   "form-materials",

+ 4 - 0
apps/docs/src/zh/guide/advanced/plugin/_meta.json

@@ -0,0 +1,4 @@
+[
+  "custom-plugin",
+  "panel-manager-plugin"
+]

+ 0 - 0
apps/docs/src/zh/guide/advanced/custom-plugin.mdx → apps/docs/src/zh/guide/advanced/plugin/custom-plugin.mdx


+ 100 - 0
apps/docs/src/zh/guide/advanced/plugin/panel-manager-plugin.mdx

@@ -0,0 +1,100 @@
+import { PackageManagerTabs } from '@theme';
+
+# Panel Manager 插件
+
+管理各类面板的插件。
+
+## 功能
+
+- 基于该插件可以低成本的在画布的右侧和底部以 React 组件形式接入自定义面板
+
+- 无需复杂的样式适配,底层自动计算面板的限位和布局
+
+- 自动管理面板队列的出入
+
+![Preview](@/public/plugin/panel-manager-1.png)
+
+## 快速开始
+
+1. 安装
+
+<PackageManagerTabs command="install @flowgram.ai/panel-manager-plugin" />
+
+2. 注册插件
+
+插件的注册方法和 flowgram 的其他插件基本相同,只需要保证不要重复创建以及最终传入到对应的 LayoutEditorProvider 即可
+
+```tsx
+import { createPanelManagerPlugin } from '@flowgram.ai/panel-manager-plugin';
+
+const editorProps = useMemo(() => ({
+  plugins: () => [createPanelManagerPlugin({})]
+}), []);
+
+return (
+  <FreeLayoutEditorProvider {...editorProps}>
+    <EditorRenderer />
+  </FreeLayoutEditorProvider>
+)
+```
+
+3. 注册面板组件
+
+面板的注册需要唯一的 `key` 以及返回 ReactNode 的渲染函数 `render`
+
+这里以节点表单面板为例:
+
+```tsx
+import { type PanelFactory } from '@flowgram.ai/panel-manager-plugin';
+
+export const NODE_FORM_PANEL = 'node-form-panel';
+export const nodeFormPanelFactory: PanelFactory<NodeFormPanelProps> = {
+  key: NODE_FORM_PANEL,
+  render: (props: NodeFormPanelProps) => <NodeFormPanel {...props} />
+}
+```
+
+将定义好的对象传入插件中:
+
+```ts
+createPanelManagerPlugin({
+  factories: [nodeFormPanelFactory]
+})
+```
+
+4. 打开/关闭面板
+
+面板的打开关闭通过 PanelManager 的实例控制:
+
+```ts
+import { PanelManager } from '@flowgram.ai/panel-manager-plugin';
+
+class NodeFormService {
+  @inject(PanelManager): panelManager: PanelManager;
+
+  openPanel(nodeId: string) {
+    this.panelManager.open(NODE_FORM_PANEL, 'right', {
+      props: {
+        nodeId
+      }
+    })
+  }
+  closePanel() {
+    this.panelManager.close(NODE_FORM_PANEL, 'right')
+  }
+}
+```
+
+除此之外也可以在 react 组件中以 hook 的方式获取实例:
+
+```tsx
+import { usePanelManager } from '@flowgram.ai/panel-manager-plugin';
+
+const panelManager = usePanelManager();
+
+<button
+  onClick={() => panelManager.open(TEST_RUN_FORM_PANEL, 'right')}
+>
+  试运行
+</button>
+```

+ 10 - 2
packages/plugins/panel-manager-plugin/src/components/panel-layer/css.ts

@@ -10,6 +10,7 @@ export const panelLayer: React.CSSProperties = {
   left: 0,
 
   display: 'flex',
+  columnGap: '4px',
   width: '100%',
   height: '100%',
   padding: '4px',
@@ -21,6 +22,10 @@ export const leftArea: React.CSSProperties = {
   minWidth: 0,
   flexGrow: 0,
   flexShrink: 1,
+
+  display: 'flex',
+  flexDirection: 'column',
+  rowGap: '4px',
 };
 
 export const rightArea: React.CSSProperties = {
@@ -36,14 +41,17 @@ export const rightArea: React.CSSProperties = {
 export const mainArea: React.CSSProperties = {
   position: 'relative',
   overflow: 'hidden',
-  flex: '0 1 0',
+  flexGrow: 0,
+  flexShrink: 1,
   width: '100%',
   height: '100%',
 };
 
 export const bottomArea: React.CSSProperties = {
-  flex: '1 0 0',
+  flexGrow: 1,
+  flexShrink: 0,
   width: '100%',
+  minHeight: 0,
 };
 
 export const floatPanelWrap: React.CSSProperties = {