candidate-node.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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 { useNodesInteractions } from './hooks'
  16. import { CUSTOM_NODE } from './constants'
  17. import CustomNode from './nodes'
  18. import CustomNoteNode from './note-node'
  19. import { CUSTOM_NOTE_NODE } from './note-node/constants'
  20. const CandidateNode = () => {
  21. const store = useStoreApi()
  22. const reactflow = useReactFlow()
  23. const workflowStore = useWorkflowStore()
  24. const candidateNode = useStore(s => s.candidateNode)
  25. const mousePosition = useStore(s => s.mousePosition)
  26. const { zoom } = useViewport()
  27. const { handleNodeSelect } = useNodesInteractions()
  28. useEventListener('click', (e) => {
  29. const { candidateNode, mousePosition } = workflowStore.getState()
  30. if (candidateNode) {
  31. e.preventDefault()
  32. const {
  33. getNodes,
  34. setNodes,
  35. } = store.getState()
  36. const { screenToFlowPosition } = reactflow
  37. const nodes = getNodes()
  38. const { x, y } = screenToFlowPosition({ x: mousePosition.pageX, y: mousePosition.pageY })
  39. const newNodes = produce(nodes, (draft) => {
  40. draft.push({
  41. ...candidateNode,
  42. data: {
  43. ...candidateNode.data,
  44. _isCandidate: false,
  45. },
  46. position: {
  47. x,
  48. y,
  49. },
  50. })
  51. })
  52. setNodes(newNodes)
  53. workflowStore.setState({ candidateNode: undefined })
  54. if (candidateNode.type === CUSTOM_NOTE_NODE)
  55. handleNodeSelect(candidateNode.id)
  56. }
  57. })
  58. useEventListener('contextmenu', (e) => {
  59. const { candidateNode } = workflowStore.getState()
  60. if (candidateNode) {
  61. e.preventDefault()
  62. workflowStore.setState({ candidateNode: undefined })
  63. }
  64. })
  65. if (!candidateNode)
  66. return null
  67. return (
  68. <div
  69. className='absolute z-10'
  70. style={{
  71. left: mousePosition.elementX,
  72. top: mousePosition.elementY,
  73. transform: `scale(${zoom})`,
  74. transformOrigin: '0 0',
  75. }}
  76. >
  77. {
  78. candidateNode.type === CUSTOM_NODE && (
  79. <CustomNode {...candidateNode as any} />
  80. )
  81. }
  82. {
  83. candidateNode.type === CUSTOM_NOTE_NODE && (
  84. <CustomNoteNode {...candidateNode as any} />
  85. )
  86. }
  87. </div>
  88. )
  89. }
  90. export default memo(CandidateNode)