Kaynağa Gözat

refactor(free-demo): add node button access node panel

liuyangxing 10 ay önce
ebeveyn
işleme
f716fceed5

+ 12 - 24
apps/demo-free-layout/src/components/add-node/index.tsx

@@ -1,34 +1,22 @@
-import { useState } from 'react';
-
 import { Button } from '@douyinfe/semi-ui';
-import { Popover } from '@douyinfe/semi-ui';
 import { IconPlus } from '@douyinfe/semi-icons';
 
-import { NodeList } from './node-list';
+import { useAddNode } from './use-add-node';
 
 export const AddNode = (props: { disabled: boolean }) => {
-  const [visible, setVisible] = useState(false);
-
+  const addNode = useAddNode();
   return (
-    <Popover
-      visible={visible}
-      onVisibleChange={props.disabled ? () => {} : setVisible}
-      content={!props.disabled && <NodeList />}
-      placement="right"
-      trigger="click"
-      popupAlign={{ offset: [30, 0] }}
-      overlayStyle={{
-        padding: 0,
+    <Button
+      icon={<IconPlus />}
+      color="highlight"
+      style={{ backgroundColor: 'rgba(171,181,255,0.3)', borderRadius: '8px' }}
+      disabled={props.disabled}
+      onClick={(e) => {
+        const rect = e.currentTarget.getBoundingClientRect();
+        addNode(rect);
       }}
     >
-      <Button
-        icon={<IconPlus />}
-        color="highlight"
-        style={{ backgroundColor: 'rgba(171,181,255,0.3)', borderRadius: '8px' }}
-        disabled={props.disabled}
-      >
-        Add Node
-      </Button>
-    </Popover>
+      Add Node
+    </Button>
   );
 };

+ 0 - 71
apps/demo-free-layout/src/components/add-node/node-list.tsx

@@ -1,71 +0,0 @@
-import styled from 'styled-components';
-import { useClientContext } from '@flowgram.ai/free-layout-editor';
-
-import { FlowNodeRegistry } from '../../typings';
-import { nodeRegistries } from '../../nodes';
-
-const NodeWrap = styled.div`
-  width: 100%;
-  height: 32px;
-  border-radius: 5px;
-  display: flex;
-  align-items: center;
-  cursor: pointer;
-  font-size: 19px;
-  padding: 0 15px;
-  &:hover {
-    background-color: hsl(252deg 62% 55% / 9%);
-    color: hsl(252 62% 54.9%);
-  },
-`;
-
-const NodeLabel = styled.div`
-  font-size: 12px;
-  margin-left: 10px;
-`;
-
-function Node(props: { label: string; icon: JSX.Element; onClick: () => void; disabled: boolean }) {
-  return (
-    <NodeWrap
-      onClick={props.disabled ? undefined : props.onClick}
-      style={props.disabled ? { opacity: 0.3 } : {}}
-    >
-      <div style={{ fontSize: 14 }}>{props.icon}</div>
-      <NodeLabel>{props.label}</NodeLabel>
-    </NodeWrap>
-  );
-}
-
-const NodesWrap = styled.div`
-  max-height: 500px;
-  overflow: auto;
-  &::-webkit-scrollbar {
-    display: none;
-  }
-`;
-
-export function NodeList() {
-  const context = useClientContext();
-  const clientContext = useClientContext();
-  const handleClick = (registry: FlowNodeRegistry) => {
-    const nodeJSON = registry.onAdd?.(context);
-    if (nodeJSON) {
-      const node = clientContext.document.createWorkflowNode(nodeJSON);
-      // Select New Node
-      clientContext.selection.selection = [node];
-    }
-  };
-  return (
-    <NodesWrap style={{ width: 80 * 2 + 20 }}>
-      {nodeRegistries.map((registry) => (
-        <Node
-          key={registry.type}
-          disabled={!(registry.canAdd?.(context) ?? true)}
-          icon={<img style={{ width: 10, height: 10, borderRadius: 4 }} src={registry.info.icon} />}
-          label={registry.type as string}
-          onClick={() => handleClick(registry)}
-        />
-      ))}
-    </NodesWrap>
-  );
-}

+ 72 - 0
apps/demo-free-layout/src/components/add-node/use-add-node.ts

@@ -0,0 +1,72 @@
+import { useCallback } from 'react';
+
+import { WorkflowNodePanelService } from '@flowgram.ai/free-node-panel-plugin';
+import {
+  useService,
+  WorkflowDocument,
+  usePlayground,
+  getAntiOverlapPosition,
+  PositionSchema,
+  WorkflowNodeEntity,
+  WorkflowSelectService,
+} from '@flowgram.ai/free-layout-editor';
+
+const useGetPanelPosition = () => {
+  const playground = usePlayground();
+
+  return useCallback(
+    (targetBoundingRect: DOMRect): PositionSchema =>
+      playground.config.getPosFromMouseEvent({
+        clientX: targetBoundingRect.left + 64,
+        clientY: targetBoundingRect.top - 7,
+      }),
+    [playground]
+  );
+};
+
+const useSelectNode = () => {
+  const selectService = useService(WorkflowSelectService);
+  return useCallback(
+    (node?: WorkflowNodeEntity) => {
+      if (!node) {
+        return;
+      }
+      selectService.selectNode(node);
+    },
+    [selectService]
+  );
+};
+
+export const useAddNode = () => {
+  const workflowDocument = useService(WorkflowDocument);
+  const nodePanelService = useService<WorkflowNodePanelService>(WorkflowNodePanelService);
+  const playground = usePlayground();
+  const getPanelPosition = useGetPanelPosition();
+  const select = useSelectNode();
+
+  return useCallback(
+    async (targetBoundingRect: DOMRect): Promise<void> => {
+      const panelPosition = getPanelPosition(targetBoundingRect);
+      await nodePanelService.call({
+        panelPosition,
+        customPosition: ({ selectPosition }) => {
+          const nodeWidth = 360;
+          const nodePanelOffset = 150 / playground.config.zoom;
+          const customPositionX = panelPosition.x + nodeWidth / 2 + nodePanelOffset;
+          const customNodePosition = getAntiOverlapPosition(workflowDocument, {
+            x: customPositionX,
+            y: selectPosition.y,
+          });
+          return {
+            x: customNodePosition.x,
+            y: customNodePosition.y,
+          };
+        },
+        enableSelectPosition: true,
+        enableMultiAdd: true,
+        afterAddNode: select,
+      });
+    },
+    [getPanelPosition, nodePanelService, playground.config.zoom, workflowDocument, select]
+  );
+};