candidate-node.tsx 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import {
  2. memo,
  3. } from 'react'
  4. import produce from 'immer'
  5. import {
  6. useReactFlow,
  7. useStoreApi,
  8. useViewport,
  9. } from 'reactflow'
  10. import { useEventListener } from 'ahooks'
  11. import {
  12. useStore,
  13. useWorkflowStore,
  14. } from './store'
  15. import CustomNode from './nodes'
  16. const CandidateNode = () => {
  17. const store = useStoreApi()
  18. const reactflow = useReactFlow()
  19. const workflowStore = useWorkflowStore()
  20. const candidateNode = useStore(s => s.candidateNode)
  21. const mousePosition = useStore(s => s.mousePosition)
  22. const { zoom } = useViewport()
  23. useEventListener('click', (e) => {
  24. const { candidateNode, mousePosition } = workflowStore.getState()
  25. if (candidateNode) {
  26. e.preventDefault()
  27. const {
  28. getNodes,
  29. setNodes,
  30. } = store.getState()
  31. const { screenToFlowPosition } = reactflow
  32. const nodes = getNodes()
  33. const { x, y } = screenToFlowPosition({ x: mousePosition.pageX, y: mousePosition.pageY })
  34. const newNodes = produce(nodes, (draft) => {
  35. draft.push({
  36. ...candidateNode,
  37. data: {
  38. ...candidateNode.data,
  39. _isCandidate: false,
  40. },
  41. position: {
  42. x,
  43. y,
  44. },
  45. })
  46. })
  47. setNodes(newNodes)
  48. workflowStore.setState({ candidateNode: undefined })
  49. }
  50. })
  51. useEventListener('contextmenu', (e) => {
  52. const { candidateNode } = workflowStore.getState()
  53. if (candidateNode) {
  54. e.preventDefault()
  55. workflowStore.setState({ candidateNode: undefined })
  56. }
  57. })
  58. if (!candidateNode)
  59. return null
  60. return (
  61. <div
  62. className='absolute z-10'
  63. style={{
  64. left: mousePosition.elementX,
  65. top: mousePosition.elementY,
  66. transform: `scale(${zoom})`,
  67. transformOrigin: '0 0',
  68. }}
  69. >
  70. <CustomNode {...candidateNode as any} />
  71. </div>
  72. )
  73. }
  74. export default memo(CandidateNode)