| import { |
| memo, |
| useCallback, |
| useState, |
| } from 'react' |
| import { intersection } from 'lodash-es' |
| import type { EdgeProps } from 'reactflow' |
| import { |
| BaseEdge, |
| EdgeLabelRenderer, |
| Position, |
| getBezierPath, |
| } from 'reactflow' |
| import { |
| useAvailableBlocks, |
| useNodesInteractions, |
| } from './hooks' |
| import BlockSelector from './block-selector' |
| import type { |
| Edge, |
| OnSelectBlock, |
| } from './types' |
| import { ITERATION_CHILDREN_Z_INDEX } from './constants' |
| import cn from '@/utils/classnames' |
|
|
| const CustomEdge = ({ |
| id, |
| data, |
| source, |
| sourceHandleId, |
| target, |
| targetHandleId, |
| sourceX, |
| sourceY, |
| targetX, |
| targetY, |
| selected, |
| }: EdgeProps) => { |
| const [ |
| edgePath, |
| labelX, |
| labelY, |
| ] = getBezierPath({ |
| sourceX: sourceX - 8, |
| sourceY, |
| sourcePosition: Position.Right, |
| targetX: targetX + 8, |
| targetY, |
| targetPosition: Position.Left, |
| curvature: 0.16, |
| }) |
| const [open, setOpen] = useState(false) |
| const { handleNodeAdd } = useNodesInteractions() |
| const { availablePrevBlocks } = useAvailableBlocks((data as Edge['data'])!.targetType, (data as Edge['data'])?.isInIteration) |
| const { availableNextBlocks } = useAvailableBlocks((data as Edge['data'])!.sourceType, (data as Edge['data'])?.isInIteration) |
|
|
| const handleOpenChange = useCallback((v: boolean) => { |
| setOpen(v) |
| }, []) |
|
|
| const handleInsert = useCallback<OnSelectBlock>((nodeType, toolDefaultValue) => { |
| handleNodeAdd( |
| { |
| nodeType, |
| toolDefaultValue, |
| }, |
| { |
| prevNodeId: source, |
| prevNodeSourceHandle: sourceHandleId || 'source', |
| nextNodeId: target, |
| nextNodeTargetHandle: targetHandleId || 'target', |
| }, |
| ) |
| }, [handleNodeAdd, source, sourceHandleId, target, targetHandleId]) |
|
|
| return ( |
| <> |
| <BaseEdge |
| id={id} |
| path={edgePath} |
| style={{ |
| stroke: (selected || data?._connectedNodeIsHovering || data?._run) ? '#2970FF' : '#D0D5DD', |
| strokeWidth: 2, |
| }} |
| /> |
| <EdgeLabelRenderer> |
| <div |
| className={cn( |
| 'nopan nodrag hover:scale-125', |
| data?._hovering ? 'block' : 'hidden', |
| open && '!block', |
| data.isInIteration && `z-[${ITERATION_CHILDREN_Z_INDEX}]`, |
| )} |
| style={{ |
| position: 'absolute', |
| transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`, |
| pointerEvents: 'all', |
| }} |
| > |
| <BlockSelector |
| open={open} |
| onOpenChange={handleOpenChange} |
| asChild |
| onSelect={handleInsert} |
| availableBlocksTypes={intersection(availablePrevBlocks, availableNextBlocks)} |
| triggerClassName={() => 'hover:scale-150 transition-all'} |
| /> |
| </div> |
| </EdgeLabelRenderer> |
| </> |
| ) |
| } |
|
|
| export default memo(CustomEdge) |
|
|