candidate-node.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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 { WorkflowHistoryEvent, useNodesInteractions, useWorkflowHistory } 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. const { saveStateToHistory } = useWorkflowHistory()
  29. useEventListener('click', (e) => {
  30. const { candidateNode, mousePosition } = workflowStore.getState()
  31. if (candidateNode) {
  32. e.preventDefault()
  33. const {
  34. getNodes,
  35. setNodes,
  36. } = store.getState()
  37. const { screenToFlowPosition } = reactflow
  38. const nodes = getNodes()
  39. const { x, y } = screenToFlowPosition({ x: mousePosition.pageX, y: mousePosition.pageY })
  40. const newNodes = produce(nodes, (draft) => {
  41. draft.push({
  42. ...candidateNode,
  43. data: {
  44. ...candidateNode.data,
  45. _isCandidate: false,
  46. },
  47. position: {
  48. x,
  49. y,
  50. },
  51. })
  52. })
  53. setNodes(newNodes)
  54. if (candidateNode.type === CUSTOM_NOTE_NODE)
  55. saveStateToHistory(WorkflowHistoryEvent.NoteAdd)
  56. else
  57. saveStateToHistory(WorkflowHistoryEvent.NodeAdd)
  58. workflowStore.setState({ candidateNode: undefined })
  59. if (candidateNode.type === CUSTOM_NOTE_NODE)
  60. handleNodeSelect(candidateNode.id)
  61. }
  62. })
  63. useEventListener('contextmenu', (e) => {
  64. const { candidateNode } = workflowStore.getState()
  65. if (candidateNode) {
  66. e.preventDefault()
  67. workflowStore.setState({ candidateNode: undefined })
  68. }
  69. })
  70. if (!candidateNode)
  71. return null
  72. return (
  73. <div
  74. className='absolute z-10'
  75. style={{
  76. left: mousePosition.elementX,
  77. top: mousePosition.elementY,
  78. transform: `scale(${zoom})`,
  79. transformOrigin: '0 0',
  80. }}
  81. >
  82. {
  83. candidateNode.type === CUSTOM_NODE && (
  84. <CustomNode {...candidateNode as any} />
  85. )
  86. }
  87. {
  88. candidateNode.type === CUSTOM_NOTE_NODE && (
  89. <CustomNoteNode {...candidateNode as any} />
  90. )
  91. }
  92. </div>
  93. )
  94. }
  95. export default memo(CandidateNode)