| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 | import { useCallback } from 'react'import produce from 'immer'import { useTranslation } from 'react-i18next'import { useStoreApi } from 'reactflow'import type {  BlockEnum,  Node,} from '../../types'import { generateNewNode } from '../../utils'import {  LOOP_PADDING,  NODES_INITIAL_DATA,} from '../../constants'import { CUSTOM_LOOP_START_NODE } from '../loop-start/constants'export const useNodeLoopInteractions = () => {  const { t } = useTranslation()  const store = useStoreApi()  const handleNodeLoopRerender = useCallback((nodeId: string) => {    const {      getNodes,      setNodes,    } = store.getState()    const nodes = getNodes()    const currentNode = nodes.find(n => n.id === nodeId)!    const childrenNodes = nodes.filter(n => n.parentId === nodeId)    let rightNode: Node    let bottomNode: Node    childrenNodes.forEach((n) => {      if (rightNode) {        if (n.position.x + n.width! > rightNode.position.x + rightNode.width!)          rightNode = n      }      else {        rightNode = n      }      if (bottomNode) {        if (n.position.y + n.height! > bottomNode.position.y + bottomNode.height!)          bottomNode = n      }      else {        bottomNode = n      }    })    const widthShouldExtend = rightNode! && currentNode.width! < rightNode.position.x + rightNode.width!    const heightShouldExtend = bottomNode! && currentNode.height! < bottomNode.position.y + bottomNode.height!    if (widthShouldExtend || heightShouldExtend) {      const newNodes = produce(nodes, (draft) => {        draft.forEach((n) => {          if (n.id === nodeId) {            if (widthShouldExtend) {              n.data.width = rightNode.position.x + rightNode.width! + LOOP_PADDING.right              n.width = rightNode.position.x + rightNode.width! + LOOP_PADDING.right            }            if (heightShouldExtend) {              n.data.height = bottomNode.position.y + bottomNode.height! + LOOP_PADDING.bottom              n.height = bottomNode.position.y + bottomNode.height! + LOOP_PADDING.bottom            }          }        })      })      setNodes(newNodes)    }  }, [store])  const handleNodeLoopChildDrag = useCallback((node: Node) => {    const { getNodes } = store.getState()    const nodes = getNodes()    const restrictPosition: { x?: number; y?: number } = { x: undefined, y: undefined }    if (node.data.isInLoop) {      const parentNode = nodes.find(n => n.id === node.parentId)      if (parentNode) {        if (node.position.y < LOOP_PADDING.top)          restrictPosition.y = LOOP_PADDING.top        if (node.position.x < LOOP_PADDING.left)          restrictPosition.x = LOOP_PADDING.left        if (node.position.x + node.width! > parentNode!.width! - LOOP_PADDING.right)          restrictPosition.x = parentNode!.width! - LOOP_PADDING.right - node.width!        if (node.position.y + node.height! > parentNode!.height! - LOOP_PADDING.bottom)          restrictPosition.y = parentNode!.height! - LOOP_PADDING.bottom - node.height!      }    }    return {      restrictPosition,    }  }, [store])  const handleNodeLoopChildSizeChange = useCallback((nodeId: string) => {    const { getNodes } = store.getState()    const nodes = getNodes()    const currentNode = nodes.find(n => n.id === nodeId)!    const parentId = currentNode.parentId    if (parentId)      handleNodeLoopRerender(parentId)  }, [store, handleNodeLoopRerender])  const handleNodeLoopChildrenCopy = useCallback((nodeId: string, newNodeId: string) => {    const { getNodes } = store.getState()    const nodes = getNodes()    const childrenNodes = nodes.filter(n => n.parentId === nodeId && n.type !== CUSTOM_LOOP_START_NODE)    return childrenNodes.map((child, index) => {      const childNodeType = child.data.type as BlockEnum      const nodesWithSameType = nodes.filter(node => node.data.type === childNodeType)      const { newNode } = generateNewNode({        data: {          ...NODES_INITIAL_DATA[childNodeType],          ...child.data,          selected: false,          _isBundled: false,          _connectedSourceHandleIds: [],          _connectedTargetHandleIds: [],          title: nodesWithSameType.length > 0 ? `${t(`workflow.blocks.${childNodeType}`)} ${nodesWithSameType.length + 1}` : t(`workflow.blocks.${childNodeType}`),          loop_id: newNodeId,        },        position: child.position,        positionAbsolute: child.positionAbsolute,        parentId: newNodeId,        extent: child.extent,        zIndex: child.zIndex,      })      newNode.id = `${newNodeId}${newNode.id + index}`      return newNode    })  }, [store, t])  return {    handleNodeLoopRerender,    handleNodeLoopChildDrag,    handleNodeLoopChildSizeChange,    handleNodeLoopChildrenCopy,  }}
 |