| 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) |
|
|