From 6904b5bd49a011cacb362046153498cfc99efb61 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 10 Jul 2024 11:58:49 +0200 Subject: [PATCH] refactor(useConnection): return internal node, add node generic --- examples/react/src/examples/Figma/index.tsx | 14 ++++++++++++- .../FloatingEdges/FloatingConnectionLine.tsx | 4 ++-- .../react/src/examples/FloatingEdges/utils.ts | 20 +++++++++++-------- .../src/examples/UseConnection/index.tsx | 4 ++-- packages/react/src/hooks/useConnection.ts | 12 +++++------ packages/react/src/types/edges.ts | 12 ++++++----- packages/system/src/types/general.ts | 16 ++++++--------- packages/system/src/xyhandle/XYHandle.ts | 4 ++-- 8 files changed, 50 insertions(+), 36 deletions(-) diff --git a/examples/react/src/examples/Figma/index.tsx b/examples/react/src/examples/Figma/index.tsx index 6780b6cb..f51219df 100644 --- a/examples/react/src/examples/Figma/index.tsx +++ b/examples/react/src/examples/Figma/index.tsx @@ -3,7 +3,19 @@ import { ReactFlow, Background, BackgroundVariant, Node, Edge, SelectionMode, Co const MULTI_SELECT_KEY = ['Meta', 'Shift']; const initialNodes: Node[] = [ - { id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, className: 'light' }, + { + id: '1', + type: 'input', + data: { + label: ( + <> + + + ), + }, + position: { x: 250, y: 5 }, + className: 'light', + }, { id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, className: 'light' }, { id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, className: 'light' }, { id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, className: 'light' }, diff --git a/examples/react/src/examples/FloatingEdges/FloatingConnectionLine.tsx b/examples/react/src/examples/FloatingEdges/FloatingConnectionLine.tsx index 3bac9d41..a3039123 100644 --- a/examples/react/src/examples/FloatingEdges/FloatingConnectionLine.tsx +++ b/examples/react/src/examples/FloatingEdges/FloatingConnectionLine.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { getBezierPath, ConnectionLineComponentProps, Node } from '@xyflow/react'; +import { getBezierPath, ConnectionLineComponentProps, Node, InternalNode } from '@xyflow/react'; import { getEdgeParams } from './utils'; @@ -13,7 +13,7 @@ const FloatingConnectionLine: FC = ({ toX, toY, fr width: 1, height: 1, position: { x: toX, y: toY }, - } as Node; + } as InternalNode; const { sx, sy } = getEdgeParams(fromNode, targetNode); diff --git a/examples/react/src/examples/FloatingEdges/utils.ts b/examples/react/src/examples/FloatingEdges/utils.ts index 08593c5c..39f0fad0 100644 --- a/examples/react/src/examples/FloatingEdges/utils.ts +++ b/examples/react/src/examples/FloatingEdges/utils.ts @@ -2,21 +2,19 @@ import { Position, XYPosition, Node, Edge, InternalNode } from '@xyflow/react'; // this helper function returns the intersection point // of the line between the center of the intersectionNode and the target node -function getNodeIntersection(intersectionNode: Node, targetNode: Node): XYPosition { - // https://math.stackexchange.com/questions/1724792/an-algorithm-for-finding-the-intersection-point-between-a-center-of-vision-and-a - - const { position: intersectionNodePosition } = intersectionNode; +function getNodeIntersection(intersectionNode: InternalNode, targetNode: InternalNode): XYPosition { + const { internals: intersectionInternals } = intersectionNode; const { width: intersectionNodeWidth, height: intersectionNodeHeight } = intersectionNode.measured ?? { width: 0, height: 0, }; - const targetPosition = targetNode.position; + const targetPosition = targetNode.internals.positionAbsolute; const w = (intersectionNodeWidth ?? 0) / 2; const h = (intersectionNodeHeight ?? 0) / 2; - const x2 = intersectionNodePosition.x + w; - const y2 = intersectionNodePosition.y + h; + const x2 = intersectionInternals.positionAbsolute.x + w; + const y2 = intersectionInternals.positionAbsolute.y + h; const x1 = targetPosition.x + w; const y1 = targetPosition.y + h; @@ -92,7 +90,13 @@ export function createElements(): NodesAndEdges { const x = 250 * Math.cos(radians) + center.x; const y = 250 * Math.sin(radians) + center.y; - nodes.push({ id: `${i}`, data: { label: 'Source' }, position: { x, y } }); + const isChild = i === 1; + nodes.push({ + id: `${i}`, + data: { label: 'Source' }, + position: isChild ? { x: 0, y: 0 } : { x, y }, + parentId: isChild ? '0' : undefined, + }); edges.push({ id: `edge-${i}`, diff --git a/examples/react/src/examples/UseConnection/index.tsx b/examples/react/src/examples/UseConnection/index.tsx index cc90f11f..38109b45 100644 --- a/examples/react/src/examples/UseConnection/index.tsx +++ b/examples/react/src/examples/UseConnection/index.tsx @@ -40,7 +40,7 @@ const initialEdges: Edge[] = [ { id: 'e1-3', source: '1', target: '3' }, ]; -const UseZoomPanHelperFlow = () => { +const UseConnectionFlow = () => { const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); @@ -68,7 +68,7 @@ const UseZoomPanHelperFlow = () => { const WrappedFlow = () => ( - + ); diff --git a/packages/react/src/hooks/useConnection.ts b/packages/react/src/hooks/useConnection.ts index 8a4b377b..46784c4f 100644 --- a/packages/react/src/hooks/useConnection.ts +++ b/packages/react/src/hooks/useConnection.ts @@ -1,10 +1,10 @@ import { shallow } from 'zustand/shallow'; - -import { useStore } from './useStore'; -import type { ReactFlowStore } from '../types/store'; import { ConnectionState, pointToRendererPoint } from '@xyflow/system'; -const selector = (s: ReactFlowStore): ConnectionState => { +import { useStore } from './useStore'; +import type { InternalNode, Node, ReactFlowStore } from '../types'; + +const selector = (s: ReactFlowStore) => { return s.connection.inProgress ? { ...s.connection, to: pointToRendererPoint(s.connection.to, s.transform) } : { ...s.connection }; @@ -15,6 +15,6 @@ const selector = (s: ReactFlowStore): ConnectionState => { * @public * @returns ConnectionState */ -export function useConnection(): ConnectionState { - return useStore(selector, shallow); +export function useConnection(): ConnectionState> { + return useStore(selector, shallow) as ConnectionState>; } diff --git a/packages/react/src/types/edges.ts b/packages/react/src/types/edges.ts index 640366d7..e765b389 100644 --- a/packages/react/src/types/edges.ts +++ b/packages/react/src/types/edges.ts @@ -16,7 +16,7 @@ import type { OnError, } from '@xyflow/system'; -import { EdgeTypes, Node } from '.'; +import { EdgeTypes, InternalNode, Node } from '.'; export type EdgeLabelOptions = { label?: string | ReactNode; @@ -190,10 +190,10 @@ export type SimpleBezierEdgeProps = EdgeComponentProps; export type OnReconnect = (oldEdge: EdgeType, newConnection: Connection) => void; -export type ConnectionLineComponentProps = { +export type ConnectionLineComponentProps = { connectionLineStyle?: CSSProperties; connectionLineType: ConnectionLineType; - fromNode: Node; + fromNode: InternalNode; fromHandle: Handle; fromX: number; fromY: number; @@ -202,8 +202,10 @@ export type ConnectionLineComponentProps = { fromPosition: Position; toPosition: Position; connectionStatus: 'valid' | 'invalid' | null; - toNode: Node | null; + toNode: InternalNode | null; toHandle: Handle | null; }; -export type ConnectionLineComponent = ComponentType; +export type ConnectionLineComponent = ComponentType< + ConnectionLineComponentProps +>; diff --git a/packages/system/src/types/general.ts b/packages/system/src/types/general.ts index f712e1ea..becbe4af 100644 --- a/packages/system/src/types/general.ts +++ b/packages/system/src/types/general.ts @@ -148,34 +148,30 @@ export const initialConnection: NoConnection = { export type NoConnection = { inProgress: false; isValid: null; - from: null; fromHandle: null; fromPosition: null; fromNode: null; - to: null; toHandle: null; toPosition: null; toNode: null; }; - -export type ConnectionInProgress = { +export type ConnectionInProgress = { inProgress: true; isValid: boolean | null; - from: XYPosition; fromHandle: Handle; fromPosition: Position; - fromNode: NodeBase; - + fromNode: NodeType; to: XYPosition; toHandle: Handle | null; toPosition: Position; - toNode: NodeBase | null; + toNode: NodeType | null; }; - -export type ConnectionState = ConnectionInProgress | NoConnection; +export type ConnectionState = + | ConnectionInProgress + | NoConnection; export type UpdateConnection = (params: ConnectionState) => void; diff --git a/packages/system/src/xyhandle/XYHandle.ts b/packages/system/src/xyhandle/XYHandle.ts index 13f627fa..77b6da50 100644 --- a/packages/system/src/xyhandle/XYHandle.ts +++ b/packages/system/src/xyhandle/XYHandle.ts @@ -104,7 +104,7 @@ function onPointerDown( from, fromHandle, fromPosition: fromHandle.position, - fromNode: fromNodeInternal.internals.userNode, + fromNode: fromNodeInternal, to: position, toHandle: null, @@ -163,7 +163,7 @@ function onPointerDown( : position, toHandle: result.toHandle, toPosition: isValid && result.toHandle ? result.toHandle.position : oppositePosition[fromHandle.position], - toNode: result.toHandle ? nodeLookup.get(result.toHandle.nodeId)!.internals.userNode : null, + toNode: result.toHandle ? nodeLookup.get(result.toHandle.nodeId)! : null, }; // we don't want to trigger an update when the connection