@blueking/flow-canvas 0.0.1-beta.1 → 0.0.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,17 +24,59 @@ npm install @antv/x6-plugin-dnd # 拖拽建节点(DND)功能需要
24
24
 
25
25
  ## 快速开始
26
26
 
27
+ ### 零配置启动
28
+
29
+ 使用 `createDefaultSchema` 可零配置启动一个可拖拽、可连线的画布:
30
+
31
+ ```vue
32
+ <template>
33
+ <CanvasLayout :editor="editor" :palette-items="paletteItems">
34
+ <CanvasRuntime :editor="editor" @ui-event="handleUiEvent" />
35
+ <CanvasToolbar :editor="editor" />
36
+ </CanvasLayout>
37
+ </template>
38
+
39
+ <script setup lang="ts">
40
+ import {
41
+ useCanvasEditor,
42
+ CanvasRuntime,
43
+ CanvasLayout,
44
+ CanvasToolbar,
45
+ createDefaultSchema,
46
+ createEmptyFlowModel,
47
+ selectionPlugin,
48
+ snaplinePlugin,
49
+ type CanvasUiEvent,
50
+ } from '@blueking/flow-canvas';
51
+ import '@blueking/flow-canvas/style';
52
+
53
+ const { schema, paletteItems } = createDefaultSchema();
54
+
55
+ const editor = useCanvasEditor({
56
+ initialFlowModel: createEmptyFlowModel(),
57
+ schema,
58
+ plugins: [selectionPlugin(), snaplinePlugin()],
59
+ });
60
+
61
+ function handleUiEvent(event: CanvasUiEvent) {
62
+ console.log('UI 事件:', event.type);
63
+ }
64
+ </script>
65
+ ```
66
+
67
+ 传入 `editor` prop 后,`CanvasLayout` 会自动在侧边栏渲染内置节点面板 `CanvasNodePalette`,用户可直接拖拽节点到画布。
68
+
69
+ ### 自定义 Schema
70
+
71
+ 如需完全控制节点/边类型,可手动定义 `CanvasSchema`:
72
+
27
73
  ```vue
28
74
  <template>
29
75
  <CanvasLayout>
30
76
  <template #sidebar>
31
- <!-- 自定义侧边栏 -->
77
+ <MySidebar :editor="editor" />
32
78
  </template>
33
- <CanvasRuntime :editor="editor" @ui-event="handleUiEvent">
34
- <template #node-overlay="{ node, screenAnchors, api }">
35
- <!-- 节点悬浮操作按钮 -->
36
- </template>
37
- </CanvasRuntime>
79
+ <CanvasRuntime :editor="editor" @ui-event="handleUiEvent" />
38
80
  <CanvasToolbar :editor="editor" />
39
81
  </CanvasLayout>
40
82
  </template>
@@ -157,7 +199,7 @@ npm install @antv/x6-plugin-dnd # 拖拽建节点(DND)功能需要
157
199
 
158
200
  ```typescript
159
201
  interface FlowModel {
160
- version: '1.0';
202
+ version?: '1.0'; // 数据模型版本标识,可选,未传时引擎自动补全为 '1.0'
161
203
  nodes: Record<string, FlowNodeModel>; // 节点字典,key = nodeId
162
204
  edges: Record<string, FlowEdgeModel>; // 边字典,key = edgeId
163
205
  meta?: Record<string, unknown>; // 全局元数据
@@ -197,7 +239,6 @@ interface CanvasNodeDefinition {
197
239
  getSize: (node) => { width; height };
198
240
  getPorts?: (node) => FlowPortModel[];
199
241
  getBehavior?: (node, ctx) => NodeBehaviorConfig;
200
- getOverlayAnchors?: (node) => NodeOverlayAnchors;
201
242
  x6CellConfig?: Record<string, unknown>; // 透传给 X6 的额外配置
202
243
  }
203
244
  ```
@@ -223,7 +264,137 @@ interface CanvasEdgeDefinition {
223
264
 
224
265
  > **注意:** `labelRenderer` 字段在类型定义中存在但标记为 `@experimental`,当前版本尚未完整实现。如需自定义边标签样式,建议通过 `x6EdgeConfig.defaultLabel` 配置 X6 原生标签 markup。
225
266
 
226
- > **注意:** `labelRenderer` 字段在类型定义中存在但标记为 `@experimental`,当前版本尚未完整实现。如需自定义边标签样式,建议通过 `x6EdgeConfig.defaultLabel` 配置 X6 原生标签 markup。
267
+ ---
268
+
269
+ ## createDefaultSchema — 开箱即用的 Schema 工厂
270
+
271
+ `createDefaultSchema` 提供内置的节点类型和边类型定义,可零配置快速启动画布。
272
+
273
+ ```typescript
274
+ import { createDefaultSchema } from '@blueking/flow-canvas';
275
+
276
+ const { schema, paletteItems } = createDefaultSchema(options?);
277
+ ```
278
+
279
+ ### DefaultSchemaOptions
280
+
281
+ | 参数 | 类型 | 默认 | 说明 |
282
+ | --------------- | ----------------------------------------- | ------------- | --------------------------------------------- |
283
+ | nodeTypes | `Record<string, DefaultNodeTypeConfig>` | 7 种内置类型 | 自定义节点类型列表,传入后替换内置类型 |
284
+ | defaultEdgeType | `string` | `'manhattan'` | 默认连线类型,内置 `'manhattan'` 和 `'bezier'` |
285
+ | edgeTypes | `Record<string, CanvasEdgeDefinition>` | - | 额外/覆盖的边类型定义,会与内置类型合并 |
286
+
287
+ ### 返回值
288
+
289
+ | 属性 | 类型 | 说明 |
290
+ | ------------ | ------------------- | -------------------------------------------- |
291
+ | schema | `CanvasSchema` | 可直接传给 `useCanvasEditor` 的 Schema 定义 |
292
+ | paletteItems | `NodePaletteItem[]` | 可传给 `CanvasLayout` 的 `paletteItems` prop |
293
+
294
+ ### 内置节点类型
295
+
296
+ 不传 `nodeTypes` 参数时,默认包含 7 种节点:
297
+
298
+ | 类型 | 标签 | 尺寸 |
299
+ | ---------------------------- | ------------ | --------- |
300
+ | `start` | 开始 | 88 × 40 |
301
+ | `end` | 结束 | 88 × 40 |
302
+ | `empty` | 空节点 | 240 × 48 |
303
+ | `parallel-gateway` | 并行网关 | 64 × 64 |
304
+ | `branch-gateway` | 分支网关 | 64 × 64 |
305
+ | `converge-gateway` | 汇聚网关 | 64 × 64 |
306
+ | `conditional-parallel-gateway` | 条件并行网关 | 64 × 64 |
307
+
308
+ 每种节点均使用内置 `DefaultNode` 组件渲染,自带上/右/下/左四个连接端口。
309
+
310
+ 自定义节点类型列表:
311
+
312
+ ```typescript
313
+ const { schema, paletteItems } = createDefaultSchema({
314
+ nodeTypes: {
315
+ task: { label: '任务节点', width: 180, height: 60 },
316
+ approval: { label: '审批节点', icon: 'my-icon-class', width: 200, height: 60 },
317
+ notification: { label: '通知节点', width: 160, height: 50 },
318
+ },
319
+ });
320
+ ```
321
+
322
+ ### 连线类型配置
323
+
324
+ `createDefaultSchema` 内置两种连线类型:
325
+
326
+ | 类型 | 路由 | 连接器 | 说明 |
327
+ | ----------------------- | ----------- | ---------------------- | -------------------- |
328
+ | `manhattan`(默认) | `manhattan` | `rounded`(radius: 8)| 直角折线,圆角转弯 |
329
+ | `bezier` | 无 | `smooth` | 贝塞尔曲线,平滑 S 形 |
330
+
331
+ **切换为贝塞尔曲线连线:**
332
+
333
+ ```typescript
334
+ const { schema, paletteItems } = createDefaultSchema({
335
+ defaultEdgeType: 'bezier',
336
+ });
337
+ ```
338
+
339
+ **使用自定义边类型:**
340
+
341
+ ```typescript
342
+ const { schema, paletteItems } = createDefaultSchema({
343
+ defaultEdgeType: 'myEdge',
344
+ edgeTypes: {
345
+ myEdge: {
346
+ connector: 'normal',
347
+ style: (_edge, state) => ({
348
+ stroke: state.hovered ? 'red' : 'gray',
349
+ strokeWidth: 2,
350
+ }),
351
+ },
352
+ },
353
+ });
354
+ ```
355
+
356
+ **手动定义边类型(不使用 `createDefaultSchema`):**
357
+
358
+ 在手动编写 `CanvasSchema` 时,同样可以通过 `edgeTypes` 和 `defaultEdgeType` 配置连线样式:
359
+
360
+ ```typescript
361
+ const schema: CanvasSchema = {
362
+ nodeTypes: { /* ... */ },
363
+ edgeTypes: {
364
+ bezier: {
365
+ connector: { name: 'smooth' },
366
+ style: (_edge, state) => ({
367
+ stroke: state.hovered ? '#3a84ff' : '#abb5cc',
368
+ strokeWidth: 2,
369
+ }),
370
+ x6EdgeConfig: {
371
+ attrs: {
372
+ line: {
373
+ stroke: '#abb5cc',
374
+ strokeWidth: 2,
375
+ targetMarker: { name: 'block', width: 8, height: 8 },
376
+ },
377
+ },
378
+ },
379
+ },
380
+ manhattan: {
381
+ router: { name: 'manhattan', args: { padding: 10, maxDirectionChange: 90 } },
382
+ connector: { name: 'rounded', args: { radius: 8 } },
383
+ style: (_edge, state) => ({
384
+ stroke: state.hovered ? '#3a84ff' : '#abb5cc',
385
+ strokeWidth: 2,
386
+ }),
387
+ },
388
+ },
389
+ defaultEdgeType: 'bezier',
390
+ };
391
+ ```
392
+
393
+ ### 默认连线与端口样式
394
+
395
+ - **端口**:半径 6px,背景 `#3a84ff`,1px 白色描边。默认隐藏(`visibility: hidden`),hover 节点时显示;拖拽连线时自动显示所有节点端口。
396
+ - **连线**:宽度 2px,颜色 `#abb5cc`,hover 变 `#3a84ff`,平角箭头(`block` marker)。`zIndex: -1` 确保在节点下方,不阻挡端口交互。
397
+ - **连接点**:`connectionPoint: 'anchor'` + `anchor: 'center'`,连线直达端口中心,紧贴节点。
227
398
 
228
399
  ---
229
400
 
@@ -291,7 +462,6 @@ editor.executeCommand({
291
462
 
292
463
  | Slot | Props | 说明 |
293
464
  | --------------- | ------------------------------------------------ | ----------------------------------------------------------- |
294
- | node-overlay | `{ node, screenAnchors, api }` | 节点悬浮层,鼠标移入节点时显示 |
295
465
  | quick-add-panel | `{ node, api, insertNodeToRight, closePopover }` | 快捷添加弹层内容,点击右侧"+"按钮时显示(默认显示提示文字) |
296
466
 
297
467
  #### 节点快捷操作工具栏
@@ -329,13 +499,14 @@ editor.executeCommand({
329
499
  | `copyInsertDisabled` | `true` → 复制并插入按钮置灰 |
330
500
  | `disconnectDisabled` | `true` → 断开连线按钮置灰 |
331
501
  | `debugDisabled` | `true` → 调试按钮置灰 |
502
+ | `actionsOffset` | `{ x?: number; y?: number }` — 工具栏位置偏移(px),相对于默认位置(节点右下角) |
332
503
 
333
504
  按钮有效可见性 = 全局 `show*` AND 逐节点 `*able !== false`;
334
505
  按钮禁用状态 = 逐节点 `*Disabled === true`。
335
506
 
336
507
  操作触发后通过 `@ui-event` 发出对应事件:`node.action.delete` / `node.action.copy` / `node.action.copy-insert` / `node.action.disconnect` / `node.action.debug`。
337
508
 
338
- #### 节点快捷添加按钮
509
+ #### 节点快捷添加按钮(Quick Add)
339
510
 
340
511
  hover 节点时,右侧端口显示为"+"按钮,支持点击弹出面板和拖拽发起连线。通过 `quickAdd` prop 进行全局配置:
341
512
 
@@ -373,22 +544,226 @@ hover 节点时,右侧端口显示为"+"按钮,支持点击弹出面板和
373
544
 
374
545
  操作触发后通过 `@ui-event` 发出对应事件:`node.quick-add`(弹层打开时)/ `node.action.quick-insert`(插入成功时)。
375
546
 
547
+ **完整的 quick-add-panel 使用示例:**
548
+
549
+ ```vue
550
+ <template>
551
+ <CanvasLayout :editor="editor" :palette-items="paletteItems">
552
+ <CanvasRuntime :editor="editor" :quick-add="{ enabled: true }" @ui-event="handleUiEvent">
553
+ <template #quick-add-panel="{ node, insertNodeToRight, closePopover }">
554
+ <div class="quick-add-menu">
555
+ <div class="quick-add-menu__title">选择节点类型</div>
556
+ <div
557
+ v-for="item in quickAddNodeList"
558
+ :key="item.type"
559
+ class="quick-add-menu__item"
560
+ @click="handleQuickAdd(item, insertNodeToRight, closePopover)">
561
+ <i :class="item.icon" />
562
+ <span>{{ item.label }}</span>
563
+ </div>
564
+ </div>
565
+ </template>
566
+ </CanvasRuntime>
567
+ <CanvasToolbar :editor="editor" />
568
+ </CanvasLayout>
569
+ </template>
570
+
571
+ <script setup lang="ts">
572
+ import {
573
+ useCanvasEditor,
574
+ CanvasRuntime,
575
+ CanvasLayout,
576
+ CanvasToolbar,
577
+ createDefaultSchema,
578
+ createEmptyFlowModel,
579
+ generateId,
580
+ type FlowNodeModel,
581
+ } from '@blueking/flow-canvas';
582
+ import '@blueking/flow-canvas/style';
583
+
584
+ const { schema, paletteItems } = createDefaultSchema();
585
+ const editor = useCanvasEditor({ initialFlowModel: createEmptyFlowModel(), schema });
586
+
587
+ const quickAddNodeList = [
588
+ { type: 'empty', label: '空节点', icon: 'flow-canvas-icon canvas-jiedi' },
589
+ { type: 'parallel-gateway', label: '并行网关', icon: 'flow-canvas-icon canvas-bingxingwangguan' },
590
+ ];
591
+
592
+ function handleQuickAdd(
593
+ item: { type: string; label: string },
594
+ insertNodeToRight: (node: Omit<FlowNodeModel, 'position'>) => void,
595
+ closePopover: () => void,
596
+ ) {
597
+ insertNodeToRight({
598
+ id: generateId(),
599
+ type: item.type,
600
+ label: item.label,
601
+ });
602
+ closePopover();
603
+ }
604
+ </script>
605
+ ```
606
+
607
+ 通过 `getBehavior` 可动态控制哪些节点显示"+"按钮:
608
+
609
+ ```typescript
610
+ const schema: CanvasSchema = {
611
+ nodeTypes: {
612
+ end: {
613
+ component: EndNode,
614
+ getSize: () => ({ width: 88, height: 40 }),
615
+ getBehavior: () => ({
616
+ quickAddEnabled: false, // 结束节点不显示"+"按钮
617
+ deletable: false,
618
+ }),
619
+ },
620
+ task: {
621
+ component: TaskNode,
622
+ getSize: () => ({ width: 180, height: 60 }),
623
+ getBehavior: (node, ctx) => {
624
+ const hasOutEdge = Object.values(ctx.flowModel.edges)
625
+ .some(e => e.source.nodeId === node.id);
626
+ return {
627
+ quickAddEnabled: !hasOutEdge, // 已有出边时隐藏"+"按钮
628
+ };
629
+ },
630
+ },
631
+ },
632
+ };
633
+ ```
634
+
376
635
  ### CanvasLayout
377
636
 
378
- 可选的布局骨架组件。
637
+ 可选的布局骨架组件,提供侧边栏 + 主画布 + 底栏的三栏布局。
638
+
639
+ | Prop | 类型 | 默认 | 说明 |
640
+ | ---------------- | --------------------- | ----------- | ---------------------------------------------------- |
641
+ | sidebarCollapsed | `boolean` | `false` | 侧边栏是否收起 |
642
+ | sidebarWidth | `number` | `260` | 侧边栏宽度(px) |
643
+ | hideSidebar | `boolean` | `false` | 是否隐藏侧边栏 |
644
+ | hideFooter | `boolean` | `false` | 是否隐藏底部栏 |
645
+ | editor | `CanvasEditorContext` | `undefined` | 编辑器实例,传入后自动渲染内置 `CanvasNodePalette` |
646
+ | paletteItems | `NodePaletteItem[]` | `undefined` | 节点面板项列表,配合 `editor` 使用自定义面板节点列表 |
647
+
648
+ | Emit | 参数 | 说明 |
649
+ | ----------------------- | --------- | ---------------- |
650
+ | update:sidebarCollapsed | `boolean` | 侧边栏收起状态变更 |
651
+
652
+ | Slot | 说明 |
653
+ | ------- | ------------------------------------------------------------- |
654
+ | sidebar | 侧边栏内容(传入后覆盖内置 `CanvasNodePalette` 默认面板) |
655
+ | default | 主画布区域(放置 `CanvasRuntime` + `CanvasToolbar`) |
656
+ | footer | 底部栏 |
657
+
658
+ #### 侧边栏的三种使用方式
659
+
660
+ **方式一:自动渲染内置节点面板**
661
+
662
+ 传入 `editor` prop 且不提供 `sidebar` slot,`CanvasLayout` 自动在侧边栏渲染 `CanvasNodePalette`,用户可从面板拖拽节点到画布:
663
+
664
+ ```vue
665
+ <CanvasLayout :editor="editor" :palette-items="paletteItems">
666
+ <CanvasRuntime :editor="editor" />
667
+ </CanvasLayout>
668
+ ```
669
+
670
+ 通过 `paletteItems` prop 自定义面板中显示的节点类型列表:
671
+
672
+ ```vue
673
+ <script setup lang="ts">
674
+ import { createDefaultSchema, useCanvasEditor, createEmptyFlowModel } from '@blueking/flow-canvas';
675
+
676
+ const { schema, paletteItems } = createDefaultSchema();
677
+ const editor = useCanvasEditor({ initialFlowModel: createEmptyFlowModel(), schema });
678
+
679
+ // 也可以手动指定面板项,只展示部分节点类型
680
+ const customPaletteItems = [
681
+ { type: 'start', label: '开始节点', icon: 'flow-canvas-icon canvas-kaishi' },
682
+ { type: 'end', label: '结束节点', icon: 'flow-canvas-icon canvas-stop' },
683
+ { type: 'empty', label: '空节点', icon: 'flow-canvas-icon canvas-jiedi' },
684
+ ];
685
+ </script>
686
+
687
+ <template>
688
+ <CanvasLayout :editor="editor" :palette-items="customPaletteItems">
689
+ <CanvasRuntime :editor="editor" />
690
+ </CanvasLayout>
691
+ </template>
692
+ ```
693
+
694
+ **方式二:通过 sidebar slot 完全自定义侧边栏**
379
695
 
380
- | Prop | 类型 | 默认 | 说明 |
381
- | ---------------- | --------- | ------- | -------------- |
382
- | sidebarCollapsed | `boolean` | `false` | 侧边栏是否收起 |
383
- | sidebarWidth | `number` | `260` | 侧边栏宽度 |
384
- | hideSidebar | `boolean` | `false` | 是否隐藏侧边栏 |
385
- | hideFooter | `boolean` | `false` | 是否隐藏底部栏 |
696
+ ```vue
697
+ <template>
698
+ <CanvasLayout>
699
+ <template #sidebar>
700
+ <div class="my-sidebar">
701
+ <h3>节点库</h3>
702
+ <div
703
+ v-for="item in nodeItems"
704
+ :key="item.type"
705
+ ref="dndRefs"
706
+ class="my-sidebar__item"
707
+ :data-type="item.type">
708
+ {{ item.label }}
709
+ </div>
710
+ </div>
711
+ </template>
712
+ <CanvasRuntime :editor="editor" />
713
+ </CanvasLayout>
714
+ </template>
715
+
716
+ <script setup lang="ts">
717
+ import { ref, watch } from 'vue';
718
+ import { useCanvasEditor, CanvasRuntime, CanvasLayout, generateId } from '@blueking/flow-canvas';
719
+
720
+ const nodeItems = [
721
+ { type: 'task', label: '任务' },
722
+ { type: 'approval', label: '审批' },
723
+ ];
724
+
725
+ // 通过 api.registerDndSource 注册拖拽源
726
+ watch(() => editor.api.value, (api) => {
727
+ if (!api) return;
728
+ for (const item of nodeItems) {
729
+ const el = document.querySelector(`[data-type="${item.type}"]`);
730
+ if (el) {
731
+ api.registerDndSource(el as HTMLElement, () => ({
732
+ id: generateId(),
733
+ type: item.type,
734
+ label: item.label,
735
+ position: { x: 0, y: 0 },
736
+ }));
737
+ }
738
+ }
739
+ });
740
+ </script>
741
+ ```
386
742
 
387
- | Slot | 说明 |
388
- | ------- | ------------------------------------------------ |
389
- | sidebar | 侧边栏内容 |
390
- | default | 主画布区域(放置 CanvasRuntime + CanvasToolbar) |
391
- | footer | 底部栏 |
743
+ **方式三:隐藏侧边栏**
744
+
745
+ ```vue
746
+ <CanvasLayout hide-sidebar>
747
+ <CanvasRuntime :editor="editor" />
748
+ </CanvasLayout>
749
+ ```
750
+
751
+ ### CanvasNodePalette
752
+
753
+ 内置的节点面板组件,支持拖拽节点到画布(DnD)。通常由 `CanvasLayout` 自动渲染,也可以单独使用。
754
+
755
+ | Prop | 类型 | 必填 | 说明 |
756
+ | ------ | --------------------- | ---- | ---------------------------------------- |
757
+ | editor | `CanvasEditorContext` | 是 | 编辑器实例 |
758
+ | items | `NodePaletteItem[]` | 否 | 节点列表,不传时从 schema.nodeTypes 生成 |
759
+
760
+ ```typescript
761
+ interface NodePaletteItem {
762
+ type: string; // 节点类型,对应 schema.nodeTypes 的 key
763
+ label: string; // 显示名称
764
+ icon?: string; // CSS 图标类名
765
+ }
766
+ ```
392
767
 
393
768
  ### CanvasToolbar
394
769
 
@@ -404,12 +779,20 @@ hover 节点时,右侧端口显示为"+"按钮,支持点击弹出面板和
404
779
 
405
780
  工厂函数,用于获取默认工具栏项列表,便于自定义组合。
406
781
 
782
+ 撤销/重做(`undo` / `redo`)默认隐藏,可通过 `include` 恢复显示。
783
+
407
784
  ```typescript
408
785
  import { createDefaultToolbarItems } from '@blueking/flow-canvas';
409
786
 
410
- // 排除搜索,追加自定义项
411
- const items = [
412
- ...createDefaultToolbarItems({ exclude: ['search'] }),
787
+ // 默认不含撤销/重做
788
+ const items = createDefaultToolbarItems();
789
+
790
+ // 恢复显示撤销/重做
791
+ const itemsWithHistory = createDefaultToolbarItems({ include: ['undo', 'redo'] });
792
+
793
+ // 恢复撤销/重做,同时排除搜索,追加自定义项
794
+ const customItems = [
795
+ ...createDefaultToolbarItems({ include: ['undo', 'redo'], exclude: ['search'] }),
413
796
  { id: 'my-tool', type: 'custom', icon: 'my-icon-class', onClick: handleClick },
414
797
  ];
415
798
  ```
@@ -428,6 +811,114 @@ const items = [
428
811
 
429
812
  ---
430
813
 
814
+ ## 自定义节点组件
815
+
816
+ 节点的渲染由 `CanvasNodeDefinition.component` 指定的 Vue 组件控制。组件内可通过 `inject('getNode')` 获取 X6 Node 实例,读取 FlowNodeModel 数据。
817
+
818
+ ### 基础节点组件
819
+
820
+ ```vue
821
+ <!-- my-task-node.vue -->
822
+ <template>
823
+ <div class="my-task-node" :class="{ 'is-selected': selected }">
824
+ <i v-if="icon" :class="icon" class="my-task-node__icon" />
825
+ <span class="my-task-node__label">{{ label }}</span>
826
+ </div>
827
+ </template>
828
+
829
+ <script setup lang="ts">
830
+ import { inject, ref, onMounted, onBeforeUnmount, computed } from 'vue';
831
+ import type { FlowNodeModel } from '@blueking/flow-canvas';
832
+
833
+ const getNode = inject<() => any>('getNode')!;
834
+
835
+ const nodeModel = ref<FlowNodeModel>();
836
+ const selected = ref(false);
837
+
838
+ const label = computed(() => nodeModel.value?.label ?? '');
839
+ const icon = computed(() => (nodeModel.value?.extensions as any)?.icon ?? '');
840
+
841
+ onMounted(() => {
842
+ const node = getNode();
843
+ nodeModel.value = node.getData() as FlowNodeModel;
844
+
845
+ node.on('change:data', ({ current }: { current: FlowNodeModel }) => {
846
+ nodeModel.value = current;
847
+ });
848
+ });
849
+ </script>
850
+
851
+ <style scoped>
852
+ .my-task-node {
853
+ display: flex;
854
+ align-items: center;
855
+ gap: 8px;
856
+ width: 100%;
857
+ height: 100%;
858
+ padding: 0 16px;
859
+ background: #fff;
860
+ border: 1px solid #dcdee5;
861
+ border-radius: 4px;
862
+ box-sizing: border-box;
863
+ cursor: pointer;
864
+ }
865
+ .my-task-node.is-selected {
866
+ border-color: #3a84ff;
867
+ }
868
+ </style>
869
+ ```
870
+
871
+ ### 在 Schema 中注册节点组件
872
+
873
+ ```typescript
874
+ import MyTaskNode from './components/my-task-node.vue';
875
+ import MyGatewayNode from './components/my-gateway-node.vue';
876
+
877
+ const schema: CanvasSchema = {
878
+ nodeTypes: {
879
+ task: {
880
+ component: MyTaskNode,
881
+ getSize: () => ({ width: 180, height: 60 }),
882
+ getPorts: () => [
883
+ { id: 'left', group: 'left' },
884
+ { id: 'right', group: 'right' },
885
+ ],
886
+ getBehavior: (node, ctx) => ({
887
+ deletable: true,
888
+ copyable: true,
889
+ quickAddEnabled: true,
890
+ }),
891
+ },
892
+ gateway: {
893
+ component: MyGatewayNode,
894
+ getSize: () => ({ width: 64, height: 64 }),
895
+ getPorts: () => [
896
+ { id: 'top', group: 'top' },
897
+ { id: 'right', group: 'right' },
898
+ { id: 'bottom', group: 'bottom' },
899
+ { id: 'left', group: 'left' },
900
+ ],
901
+ getBehavior: () => ({
902
+ copyable: false,
903
+ showActions: true,
904
+ }),
905
+ },
906
+ },
907
+ edgeTypes: {
908
+ default: {
909
+ connector: { name: 'smooth' },
910
+ style: (_edge, state) => ({
911
+ stroke: state.hovered ? '#3a84ff' : '#abb5cc',
912
+ strokeWidth: 2,
913
+ }),
914
+ },
915
+ },
916
+ defaultEdgeType: 'default',
917
+ };
918
+ ```
919
+
920
+ ---
921
+
431
922
  ## CanvasApi
432
923
 
433
924
  `editor.api.value` 在 `CanvasRuntime` 挂载后可用,之前为 `null`。
@@ -649,7 +1140,7 @@ editor.history.clear();
649
1140
  | 类型 | 说明 |
650
1141
  | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
651
1142
  | `CanvasSchema` | 画布配置(nodeTypes / edgeTypes) |
652
- | `CanvasNodeDefinition` | 节点类型定义(component / getSize / getPorts / getBehavior / getOverlayAnchors |
1143
+ | `CanvasNodeDefinition` | 节点类型定义(component / getSize / getPorts / getBehavior) |
653
1144
  | `CanvasEdgeDefinition` | 边类型定义(router / connector / style / labelDraggable)。`labelRenderer` 字段为 `@experimental`,当前未实现 |
654
1145
  | `CanvasCallbackContext` | 运行时上下文(api / flowModel / history / mode) |
655
1146
  | `CanvasMode` | 模式:`'edit'` / `'readonly'` / `'thumbnail'` |
@@ -698,6 +1189,16 @@ editor.history.clear();
698
1189
  | `ConnectionValidator` | 连接校验函数类型 |
699
1190
  | `ConnectionValidateContext` | 连接校验上下文 |
700
1191
  | `ConnectionValidateResult` | 连接校验结果 |
1192
+ | `NodePaletteItem` | 节点面板项(type / label / icon) |
1193
+
1194
+ ### 默认 Schema
1195
+
1196
+ | 类型 | 说明 |
1197
+ | ------------------------- | ------------------------------------- |
1198
+ | `DefaultNodeTypeConfig` | `createDefaultSchema` 的节点配置项 |
1199
+ | `DefaultSchemaOptions` | `createDefaultSchema` 的选项 |
1200
+ | `DefaultSchemaResult` | `createDefaultSchema` 的返回值 |
1201
+ | `DefaultToolbarItemsOptions` | `createDefaultToolbarItems` 的选项 |
701
1202
 
702
1203
  ### 历史与 Overlay
703
1204
 
@@ -706,8 +1207,6 @@ editor.history.clear();
706
1207
  | `CanvasHistory` | 历史管理器接口 |
707
1208
  | `CanvasHistoryOptions` | 历史配置(maxHistorySize) |
708
1209
  | `OverlayManager` | Overlay 管理器接口 |
709
- | `NodeOverlayAnchors` | 节点 Overlay 锚点定义 |
710
- | `OverlayAnchor` | 单个锚点坐标 |
711
1210
 
712
1211
  ### 编辑器
713
1212