| import { | |
| memo, | |
| } from 'react' | |
| import produce from 'immer' | |
| import { | |
| useReactFlow, | |
| useStoreApi, | |
| useViewport, | |
| } from 'reactflow' | |
| import { useEventListener } from 'ahooks' | |
| import { | |
| useStore, | |
| useWorkflowStore, | |
| } from './store' | |
| import { WorkflowHistoryEvent, useNodesInteractions, useWorkflowHistory } from './hooks' | |
| import { CUSTOM_NODE } from './constants' | |
| import { getIterationStartNode } from './utils' | |
| import CustomNode from './nodes' | |
| import CustomNoteNode from './note-node' | |
| import { CUSTOM_NOTE_NODE } from './note-node/constants' | |
| import { BlockEnum } from './types' | |
| const CandidateNode = () => { | |
| const store = useStoreApi() | |
| const reactflow = useReactFlow() | |
| const workflowStore = useWorkflowStore() | |
| const candidateNode = useStore(s => s.candidateNode) | |
| const mousePosition = useStore(s => s.mousePosition) | |
| const { zoom } = useViewport() | |
| const { handleNodeSelect } = useNodesInteractions() | |
| const { saveStateToHistory } = useWorkflowHistory() | |
| useEventListener('click', (e) => { | |
| const { candidateNode, mousePosition } = workflowStore.getState() | |
| if (candidateNode) { | |
| e.preventDefault() | |
| const { | |
| getNodes, | |
| setNodes, | |
| } = store.getState() | |
| const { screenToFlowPosition } = reactflow | |
| const nodes = getNodes() | |
| const { x, y } = screenToFlowPosition({ x: mousePosition.pageX, y: mousePosition.pageY }) | |
| const newNodes = produce(nodes, (draft) => { | |
| draft.push({ | |
| ...candidateNode, | |
| data: { | |
| ...candidateNode.data, | |
| _isCandidate: false, | |
| }, | |
| position: { | |
| x, | |
| y, | |
| }, | |
| }) | |
| if (candidateNode.data.type === BlockEnum.Iteration) | |
| draft.push(getIterationStartNode(candidateNode.id)) | |
| }) | |
| setNodes(newNodes) | |
| if (candidateNode.type === CUSTOM_NOTE_NODE) | |
| saveStateToHistory(WorkflowHistoryEvent.NoteAdd) | |
| else | |
| saveStateToHistory(WorkflowHistoryEvent.NodeAdd) | |
| workflowStore.setState({ candidateNode: undefined }) | |
| if (candidateNode.type === CUSTOM_NOTE_NODE) | |
| handleNodeSelect(candidateNode.id) | |
| } | |
| }) | |
| useEventListener('contextmenu', (e) => { | |
| const { candidateNode } = workflowStore.getState() | |
| if (candidateNode) { | |
| e.preventDefault() | |
| workflowStore.setState({ candidateNode: undefined }) | |
| } | |
| }) | |
| if (!candidateNode) | |
| return null | |
| return ( | |
| <div | |
| className='absolute z-10' | |
| style={{ | |
| left: mousePosition.elementX, | |
| top: mousePosition.elementY, | |
| transform: `scale(${zoom})`, | |
| transformOrigin: '0 0', | |
| }} | |
| > | |
| { | |
| candidateNode.type === CUSTOM_NODE && ( | |
| <CustomNode {...candidateNode as any} /> | |
| ) | |
| } | |
| { | |
| candidateNode.type === CUSTOM_NOTE_NODE && ( | |
| <CustomNoteNode {...candidateNode as any} /> | |
| ) | |
| } | |
| </div> | |
| ) | |
| } | |
| export default memo(CandidateNode) | |
