Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

use-selection-interactions.ts 4.1KB

3 месяцев назад
3 месяцев назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import type { MouseEvent } from 'react'
  2. import {
  3. useCallback,
  4. } from 'react'
  5. import produce from 'immer'
  6. import type {
  7. OnSelectionChangeFunc,
  8. } from 'reactflow'
  9. import { useStoreApi } from 'reactflow'
  10. import { useWorkflowStore } from '../store'
  11. import type { Node } from '../types'
  12. export const useSelectionInteractions = () => {
  13. const store = useStoreApi()
  14. const workflowStore = useWorkflowStore()
  15. const handleSelectionStart = useCallback(() => {
  16. const {
  17. getNodes,
  18. setNodes,
  19. edges,
  20. setEdges,
  21. userSelectionRect,
  22. } = store.getState()
  23. if (!userSelectionRect?.width || !userSelectionRect?.height) {
  24. const nodes = getNodes()
  25. const newNodes = produce(nodes, (draft) => {
  26. draft.forEach((node) => {
  27. if (node.data._isBundled)
  28. node.data._isBundled = false
  29. })
  30. })
  31. setNodes(newNodes)
  32. const newEdges = produce(edges, (draft) => {
  33. draft.forEach((edge) => {
  34. if (edge.data._isBundled)
  35. edge.data._isBundled = false
  36. })
  37. })
  38. setEdges(newEdges)
  39. }
  40. }, [store])
  41. const handleSelectionChange = useCallback<OnSelectionChangeFunc>(({ nodes: nodesInSelection, edges: edgesInSelection }) => {
  42. const {
  43. getNodes,
  44. setNodes,
  45. edges,
  46. setEdges,
  47. userSelectionRect,
  48. } = store.getState()
  49. const nodes = getNodes()
  50. if (!userSelectionRect?.width || !userSelectionRect?.height)
  51. return
  52. const newNodes = produce(nodes, (draft) => {
  53. draft.forEach((node) => {
  54. const nodeInSelection = nodesInSelection.find(n => n.id === node.id)
  55. if (nodeInSelection)
  56. node.data._isBundled = true
  57. else
  58. node.data._isBundled = false
  59. })
  60. })
  61. setNodes(newNodes)
  62. const newEdges = produce(edges, (draft) => {
  63. draft.forEach((edge) => {
  64. const edgeInSelection = edgesInSelection.find(e => e.id === edge.id)
  65. if (edgeInSelection)
  66. edge.data._isBundled = true
  67. else
  68. edge.data._isBundled = false
  69. })
  70. })
  71. setEdges(newEdges)
  72. }, [store])
  73. const handleSelectionDrag = useCallback((_: MouseEvent, nodesWithDrag: Node[]) => {
  74. const {
  75. getNodes,
  76. setNodes,
  77. } = store.getState()
  78. workflowStore.setState({
  79. nodeAnimation: false,
  80. })
  81. const nodes = getNodes()
  82. const newNodes = produce(nodes, (draft) => {
  83. draft.forEach((node) => {
  84. const dragNode = nodesWithDrag.find(n => n.id === node.id)
  85. if (dragNode)
  86. node.position = dragNode.position
  87. })
  88. })
  89. setNodes(newNodes)
  90. }, [store, workflowStore])
  91. const handleSelectionCancel = useCallback(() => {
  92. const {
  93. getNodes,
  94. setNodes,
  95. edges,
  96. setEdges,
  97. } = store.getState()
  98. store.setState({
  99. userSelectionRect: null,
  100. userSelectionActive: true,
  101. })
  102. const nodes = getNodes()
  103. const newNodes = produce(nodes, (draft) => {
  104. draft.forEach((node) => {
  105. if (node.data._isBundled)
  106. node.data._isBundled = false
  107. })
  108. })
  109. setNodes(newNodes)
  110. const newEdges = produce(edges, (draft) => {
  111. draft.forEach((edge) => {
  112. if (edge.data._isBundled)
  113. edge.data._isBundled = false
  114. })
  115. })
  116. setEdges(newEdges)
  117. }, [store])
  118. const handleSelectionContextMenu = useCallback((e: MouseEvent) => {
  119. const target = e.target as HTMLElement
  120. if (!target.classList.contains('react-flow__nodesselection-rect'))
  121. return
  122. e.preventDefault()
  123. const container = document.querySelector('#workflow-container')
  124. const { x, y } = container!.getBoundingClientRect()
  125. workflowStore.setState({
  126. selectionMenu: {
  127. top: e.clientY - y,
  128. left: e.clientX - x,
  129. },
  130. })
  131. }, [workflowStore])
  132. const handleSelectionContextmenuCancel = useCallback(() => {
  133. workflowStore.setState({
  134. selectionMenu: undefined,
  135. })
  136. }, [workflowStore])
  137. return {
  138. handleSelectionStart,
  139. handleSelectionChange,
  140. handleSelectionDrag,
  141. handleSelectionCancel,
  142. handleSelectionContextMenu,
  143. handleSelectionContextmenuCancel,
  144. }
  145. }