// import { CSSProperties, useCallback } from 'react'; // import { shallow } from 'zustand/shallow'; import cc from 'classcat'; import { Position, ConnectionLineType, ConnectionMode, getBezierPath, getSmoothStepPath, type ConnectionStatus, type HandleType, } from '@xyflow/system'; import { useStore } from '../../hooks/useStore'; import { getSimpleBezierPath } from '../Edges/SimpleBezierEdge'; import type { ConnectionLineComponent, SolidFlowState, SolidFlowStore } from '../../types'; import { Show, mergeProps, JSX } from 'solid-js'; type ConnectionLineProps = { nodeId: string; handleType: HandleType; type: ConnectionLineType; style?: JSX.CSSProperties; CustomComponent?: ConnectionLineComponent; connectionStatus: ConnectionStatus | null; }; const oppositePosition = { [Position.Left]: Position.Right, [Position.Right]: Position.Left, [Position.Top]: Position.Bottom, [Position.Bottom]: Position.Top, }; const ConnectionLine = (_p: ConnectionLineProps) => { // nodeId, // handleType, // style, // type = ConnectionLineType.Bezier, // CustomComponent, // connectionStatus, // }: ConnectionLineProps) => { const p = mergeProps({ type: ConnectionLineType.Bezier }, _p); const { fromNode, handleId, toX, toY, connectionMode } = useStore((s: SolidFlowStore) => ({ fromNode: s.nodeLookup.get(p.nodeId), handleId: s.connectionStartHandle.get()?.handleId, toX: () => (s.connectionPosition.get().x - s.transform.get()[0]) / s.transform.get()[2], toY: () => (s.connectionPosition.get().y - s.transform.get()[1]) / s.transform.get()[2], connectionMode: s.connectionMode, })); // p.shallow const fromHandleBounds = () => fromNode?.internals.handleBounds; const handleBounds = () => { const x = fromHandleBounds()?.[p.handleType]; if (connectionMode.get() === ConnectionMode.Loose) { return x ? x : fromHandleBounds()?.[p.handleType === 'source' ? 'target' : 'source']; } else { return x; } }; // if (connectionMode === ConnectionMode.Loose) { // handleBounds = handleBounds() ? handleBounds : fromHandleBounds?.[handleType === 'source' ? 'target' : 'source']; // } // if (!fromNode || !handleBounds) { // return null; // } const fromHandle = () => (handleId ? handleBounds()?.find((d) => d.id === handleId) : handleBounds()?.[0]); const fromHandleX = () => { const handle = fromHandle(); if (handle) { return handle.x + handle.width / 2; } else { return fromNode?.measured.width ?? 0 / 2; } }; const fromHandleY = () => { const handle = fromHandle(); if (handle) { return handle.y + handle.height / 2; } else { return fromNode?.measured.height ?? 0 / 2; } }; const fromX = () => fromNode?.internals?.positionAbsolute?.x || 0 + fromHandleX(); const fromY = () => fromNode?.internals?.positionAbsolute?.y || 0 + fromHandleY(); const fromPosition = () => fromHandle()?.position; const toPosition = () => (fromPosition() ? oppositePosition[fromPosition()!] : null); const DefaultComponent = () => { const makeDAttr = () => { let dAttr = ''; const pathParams = { sourceX: fromX(), sourceY: fromY(), sourcePosition: fromPosition()!, targetX: toX(), targetY: toY(), targetPosition: toPosition()!, }; if (p.type === ConnectionLineType.Bezier) { // we assume the destination position is opposite to the source position [dAttr] = getBezierPath(pathParams); } else if (p.type === ConnectionLineType.Step) { [dAttr] = getSmoothStepPath({ ...pathParams, borderRadius: 0, }); } else if (p.type === ConnectionLineType.SmoothStep) { [dAttr] = getSmoothStepPath(pathParams); } else if (p.type === ConnectionLineType.SimpleBezier) { [dAttr] = getSimpleBezierPath(pathParams); } else { dAttr = `M${fromX()},${fromY()} ${toX},${toY}`; } return dAttr; }; return ; }; return ( }> {(Comp) => { return ( ); }} ); // if (CustomComponent) { // return ( // // ); // } }; ConnectionLine.displayName = 'ConnectionLine'; type ConnectionLineWrapperProps = { type: ConnectionLineType; component?: ConnectionLineComponent; containerStyle?: JSX.CSSProperties; style?: JSX.CSSProperties; }; const selector = (s: SolidFlowState) => ({ nodeId: () => s.connectionStartHandle.get()?.nodeId, handleType: () => s.connectionStartHandle.get()?.type, nodesConnectable: () => s.nodesConnectable.get(), connectionStatus: () => s.connectionStatus.get(), width: s.width, height: s.height, }); export function ConnectionLineWrapper(p: ConnectionLineWrapperProps) { // { containerStyle, style, type, component }: ConnectionLineWrapperProps) { const { nodeId, handleType, nodesConnectable, width, height, connectionStatus } = useStore(selector); const innerProps = () => { const nId = nodeId(); const hType = handleType(); const isValid = !!(nId && hType && width.get() && nodesConnectable()); if (!isValid) { return null; } return { nodeId: nId, handleType: hType, type: p.type, style: p.style, CustomComponent: p.component, connectionStatus: connectionStatus(), }; }; return ( {(props) => { return ( ); }} ); }