From 8a2ac1e31e2a6c4afbb3aa08deb1ab2d16cffae4 Mon Sep 17 00:00:00 2001 From: moklick Date: Tue, 9 Nov 2021 14:52:39 +0100 Subject: [PATCH] refactor(types): cleanup --- src/additional-components/MiniMap/index.tsx | 2 +- src/components/ConnectionLine/index.tsx | 7 +- src/components/Handle/handler.ts | 27 +- src/components/Handle/index.tsx | 4 +- src/components/Nodes/wrapNode.tsx | 4 +- src/components/StoreUpdater/index.tsx | 16 +- src/container/EdgeRenderer/utils.ts | 4 +- src/container/NodeRenderer/index.tsx | 2 +- src/container/NodeRenderer/utils.ts | 20 +- src/container/ReactFlow/index.tsx | 20 +- src/contexts/NodeIdContext.ts | 4 +- src/hooks/useOnLoadHandler.ts | 4 +- src/hooks/useUpdateNodeInternals.ts | 4 +- src/hooks/useZoomPanHelper.ts | 2 +- src/store/index.ts | 48 +- src/store/utils.ts | 13 +- src/types/changes.ts | 28 + src/types/edges.ts | 158 ++++++ src/types/general.ts | 217 ++++++++ src/types/handles.ts | 18 + src/types/index.ts | 571 +------------------- src/types/nodes.ts | 116 ++++ src/types/utils.ts | 29 + src/utils/graph.ts | 4 +- 24 files changed, 655 insertions(+), 667 deletions(-) create mode 100644 src/types/changes.ts create mode 100644 src/types/edges.ts create mode 100644 src/types/general.ts create mode 100644 src/types/handles.ts create mode 100644 src/types/nodes.ts create mode 100644 src/types/utils.ts diff --git a/src/additional-components/MiniMap/index.tsx b/src/additional-components/MiniMap/index.tsx index 9cc5a0c1..98735e55 100644 --- a/src/additional-components/MiniMap/index.tsx +++ b/src/additional-components/MiniMap/index.tsx @@ -5,7 +5,7 @@ import shallow from 'zustand/shallow'; import { useStore } from '../../store'; import { getRectOfNodes } from '../../utils/graph'; import { getBoundsofRects } from '../../utils'; -import { Node, Rect, ReactFlowState } from '../../types'; +import { Node, ReactFlowState, Rect } from '../../types'; import MiniMapNode from './MiniMapNode'; type StringFunc = (node: Node) => string; diff --git a/src/components/ConnectionLine/index.tsx b/src/components/ConnectionLine/index.tsx index 7a40dd71..8ce8e0f1 100644 --- a/src/components/ConnectionLine/index.tsx +++ b/src/components/ConnectionLine/index.tsx @@ -5,20 +5,19 @@ import { useStore } from '../../store'; import { getBezierPath } from '../Edges/BezierEdge'; import { getSmoothStepPath } from '../Edges/SmoothStepEdge'; import { - ElementId, NodeInternalsItem, HandleElement, - Position, ConnectionLineType, ConnectionLineComponent, HandleType, Node, ReactFlowState, + Position, } from '../../types'; interface ConnectionLineProps { - connectionNodeId: ElementId; - connectionHandleId: ElementId | null; + connectionNodeId: string; + connectionHandleId: string | null; connectionHandleType: HandleType; connectionPositionX: number; connectionPositionY: number; diff --git a/src/components/Handle/handler.ts b/src/components/Handle/handler.ts index 03fd37df..2ef44055 100644 --- a/src/components/Handle/handler.ts +++ b/src/components/Handle/handler.ts @@ -3,16 +3,15 @@ import { MouseEvent as ReactMouseEvent } from 'react'; import { getHostForElement } from '../../utils'; import { - ElementId, - XYPosition, - OnConnectFunc, - OnConnectStartFunc, - OnConnectStopFunc, - OnConnectEndFunc, + OnConnect, + OnConnectStart, + OnConnectStop, + OnConnectEnd, ConnectionMode, SetConnectionId, Connection, HandleType, + XYPosition, } from '../../types'; type ValidConnectionFunc = (connection: Connection) => boolean; @@ -32,8 +31,8 @@ function checkElementBelowIsValid( event: MouseEvent, connectionMode: ConnectionMode, isTarget: boolean, - nodeId: ElementId, - handleId: ElementId | null, + nodeId: string, + handleId: string | null, isValidConnection: ValidConnectionFunc, doc: Document | ShadowRoot ) { @@ -91,19 +90,19 @@ function resetRecentHandle(hoveredHandle: Element): void { export function onMouseDown( event: ReactMouseEvent, - handleId: ElementId | null, - nodeId: ElementId, + handleId: string | null, + nodeId: string, setConnectionNodeId: SetSourceIdFunc, setPosition: SetPosition, - onConnect: OnConnectFunc, + onConnect: OnConnect, isTarget: boolean, isValidConnection: ValidConnectionFunc, connectionMode: ConnectionMode, elementEdgeUpdaterType?: HandleType, onEdgeUpdateEnd?: (evt: MouseEvent) => void, - onConnectStart?: OnConnectStartFunc, - onConnectStop?: OnConnectStopFunc, - onConnectEnd?: OnConnectEndFunc + onConnectStart?: OnConnectStart, + onConnectStop?: OnConnectStop, + onConnectEnd?: OnConnectEnd ): void { const reactFlowNode = (event.target as Element).closest('.react-flow'); // when react-flow is used inside a shadow root we can't use document diff --git a/src/components/Handle/index.tsx b/src/components/Handle/index.tsx index 2f594b27..e3b0111c 100644 --- a/src/components/Handle/index.tsx +++ b/src/components/Handle/index.tsx @@ -4,7 +4,7 @@ import shallow from 'zustand/shallow'; import { useStore } from '../../store'; import NodeIdContext from '../../contexts/NodeIdContext'; -import { HandleProps, Connection, ElementId, Position, ReactFlowState } from '../../types'; +import { HandleProps, Connection, ReactFlowState, Position } from '../../types'; import { onMouseDown, SetSourceIdFunc, SetPosition } from './handler'; @@ -37,7 +37,7 @@ const Handle = forwardRef( }, ref ) => { - const nodeId = useContext(NodeIdContext) as ElementId; + const nodeId = useContext(NodeIdContext) as string; const { setPosition, setConnectionNodeId, diff --git a/src/components/Nodes/wrapNode.tsx b/src/components/Nodes/wrapNode.tsx index f700f106..58265fc4 100644 --- a/src/components/Nodes/wrapNode.tsx +++ b/src/components/Nodes/wrapNode.tsx @@ -5,7 +5,7 @@ import shallow from 'zustand/shallow'; import { useStore } from '../../store'; import { Provider } from '../../contexts/NodeIdContext'; -import { NodeComponentProps, WrapNodeProps, ReactFlowState } from '../../types'; +import { NodeProps, WrapNodeProps, ReactFlowState } from '../../types'; const selector = (s: ReactFlowState) => ({ addSelectedElements: s.addSelectedElements, @@ -15,7 +15,7 @@ const selector = (s: ReactFlowState) => ({ unselectNodesAndEdges: s.unselectNodesAndEdges, }); -export default (NodeComponent: ComponentType) => { +export default (NodeComponent: ComponentType) => { const NodeWrapper = ({ id, type, diff --git a/src/components/StoreUpdater/index.tsx b/src/components/StoreUpdater/index.tsx index 33593e4d..894e3335 100644 --- a/src/components/StoreUpdater/index.tsx +++ b/src/components/StoreUpdater/index.tsx @@ -6,10 +6,10 @@ import { Node, Edge, ReactFlowState, - OnConnectFunc, - OnConnectStartFunc, - OnConnectStopFunc, - OnConnectEndFunc, + OnConnect, + OnConnectStart, + OnConnectStop, + OnConnectEnd, CoordinateExtent, OnNodesChange, OnEdgesChange, @@ -20,10 +20,10 @@ import { interface StoreUpdaterProps { nodes: Node[]; edges: Edge[]; - onConnect?: OnConnectFunc; - onConnectStart?: OnConnectStartFunc; - onConnectStop?: OnConnectStopFunc; - onConnectEnd?: OnConnectEndFunc; + onConnect?: OnConnect; + onConnectStart?: OnConnectStart; + onConnectStop?: OnConnectStop; + onConnectEnd?: OnConnectEnd; nodesDraggable?: boolean; nodesConnectable?: boolean; minZoom?: number; diff --git a/src/container/EdgeRenderer/utils.ts b/src/container/EdgeRenderer/utils.ts index 1f94f616..29a29425 100644 --- a/src/container/EdgeRenderer/utils.ts +++ b/src/container/EdgeRenderer/utils.ts @@ -4,7 +4,7 @@ import { BezierEdge, StepEdge, SmoothStepEdge, StraightEdge } from '../../compon import wrapEdge from '../../components/Edges/wrapEdge'; import { rectToBox } from '../../utils'; -import { EdgeTypesType, EdgeProps, Position, XYPosition, ElementId, HandleElement, Transform, Rect } from '../../types'; +import { EdgeTypesType, EdgeProps, HandleElement, Position, XYPosition, Transform, Rect } from '../../types'; export function createEdgeTypes(edgeTypes: EdgeTypesType): EdgeTypesType { const standardTypes: EdgeTypesType = { @@ -59,7 +59,7 @@ export function getHandlePosition(position: Position, nodeRect: Rect, handle: an } } -export function getHandle(bounds: HandleElement[], handleId: ElementId | null): HandleElement | null { +export function getHandle(bounds: HandleElement[], handleId: string | null): HandleElement | null { if (!bounds) { return null; } diff --git a/src/container/NodeRenderer/index.tsx b/src/container/NodeRenderer/index.tsx index d02dc5d6..3482db92 100644 --- a/src/container/NodeRenderer/index.tsx +++ b/src/container/NodeRenderer/index.tsx @@ -85,7 +85,7 @@ const NodeRenderer = (props: NodeRendererProps) => { isHidden={node.isHidden} xPos={internals?.positionAbsolute?.x || 0} yPos={internals?.positionAbsolute?.y || 0} - dragging={node.dragging} + dragging={!!node.dragging} isInitialized={isInitialized} snapGrid={snapGrid} snapToGrid={snapToGrid} diff --git a/src/container/NodeRenderer/utils.ts b/src/container/NodeRenderer/utils.ts index 9af887a9..ede9dc72 100644 --- a/src/container/NodeRenderer/utils.ts +++ b/src/container/NodeRenderer/utils.ts @@ -4,28 +4,20 @@ import DefaultNode from '../../components/Nodes/DefaultNode'; import InputNode from '../../components/Nodes/InputNode'; import OutputNode from '../../components/Nodes/OutputNode'; import wrapNode from '../../components/Nodes/wrapNode'; -import { NodeTypesType, NodeComponentProps } from '../../types'; +import { NodeTypesType, NodeProps } from '../../types'; export function createNodeTypes(nodeTypes: NodeTypesType): NodeTypesType { const standardTypes: NodeTypesType = { - input: wrapNode((nodeTypes.input || InputNode) as ComponentType< - NodeComponentProps - >), - default: wrapNode((nodeTypes.default || DefaultNode) as ComponentType< - NodeComponentProps - >), - output: wrapNode((nodeTypes.output || OutputNode) as ComponentType< - NodeComponentProps - >), + input: wrapNode((nodeTypes.input || InputNode) as ComponentType), + default: wrapNode((nodeTypes.default || DefaultNode) as ComponentType), + output: wrapNode((nodeTypes.output || OutputNode) as ComponentType), }; const wrappedTypes = {} as NodeTypesType; const specialTypes: NodeTypesType = Object.keys(nodeTypes) - .filter(k => !['input', 'default', 'output'].includes(k)) + .filter((k) => !['input', 'default', 'output'].includes(k)) .reduce((res, key) => { - res[key] = wrapNode((nodeTypes[key] || DefaultNode) as ComponentType< - NodeComponentProps - >); + res[key] = wrapNode((nodeTypes[key] || DefaultNode) as ComponentType); return res; }, wrappedTypes); diff --git a/src/container/ReactFlow/index.tsx b/src/container/ReactFlow/index.tsx index 9f266fb7..fdfc5756 100644 --- a/src/container/ReactFlow/index.tsx +++ b/src/container/ReactFlow/index.tsx @@ -22,17 +22,17 @@ import { OnSelectionChangeFunc, NodeTypesType, EdgeTypesType, - OnLoadFunc, + OnLoad, Node, Edge, ConnectionMode, ConnectionLineType, ConnectionLineComponent, FlowTransform, - OnConnectStartFunc, - OnConnectStopFunc, - OnConnectEndFunc, - OnConnectFunc, + OnConnectStart, + OnConnectStop, + OnConnectEnd, + OnConnect, CoordinateExtent, KeyCode, PanOnScrollMode, @@ -72,11 +72,11 @@ export interface ReactFlowProps extends Omit, 'on onNodeDragStart?: (event: ReactMouseEvent, node: Node) => void; onNodeDrag?: (event: ReactMouseEvent, node: Node) => void; onNodeDragStop?: (event: ReactMouseEvent, node: Node) => void; - onConnect?: OnConnectFunc; - onConnectStart?: OnConnectStartFunc; - onConnectStop?: OnConnectStopFunc; - onConnectEnd?: OnConnectEndFunc; - onLoad?: OnLoadFunc; + onConnect?: OnConnect; + onConnectStart?: OnConnectStart; + onConnectStop?: OnConnectStop; + onConnectEnd?: OnConnectEnd; + onLoad?: OnLoad; onMove?: (flowTransform?: FlowTransform) => void; onMoveStart?: (flowTransform?: FlowTransform) => void; onMoveEnd?: (flowTransform?: FlowTransform) => void; diff --git a/src/contexts/NodeIdContext.ts b/src/contexts/NodeIdContext.ts index cc19227f..ba112d70 100644 --- a/src/contexts/NodeIdContext.ts +++ b/src/contexts/NodeIdContext.ts @@ -1,8 +1,6 @@ import { createContext } from 'react'; -import { ElementId } from '../types'; - -type ContextProps = ElementId | null; +type ContextProps = string | null; export const NodeIdContext = createContext>(null); export const Provider = NodeIdContext.Provider; diff --git a/src/hooks/useOnLoadHandler.ts b/src/hooks/useOnLoadHandler.ts index 39c123eb..ed128817 100644 --- a/src/hooks/useOnLoadHandler.ts +++ b/src/hooks/useOnLoadHandler.ts @@ -3,9 +3,9 @@ import { useEffect, useRef } from 'react'; import { pointToRendererPoint } from '../utils/graph'; import { useStoreApi } from '../store'; import useZoomPanHelper from '../hooks/useZoomPanHelper'; -import { OnLoadFunc, XYPosition, Node, Edge, FlowExportObject } from '../types'; +import { OnLoad, XYPosition, Node, Edge, FlowExportObject } from '../types'; -function useOnLoadHandler(onLoad: OnLoadFunc | undefined) { +function useOnLoadHandler(onLoad: OnLoad | undefined) { const isInitialized = useRef(false); const store = useStoreApi(); const { zoomIn, zoomOut, zoomTo, transform: setTransform, fitView, initialized } = useZoomPanHelper(); diff --git a/src/hooks/useUpdateNodeInternals.ts b/src/hooks/useUpdateNodeInternals.ts index 69e978a2..27da895f 100644 --- a/src/hooks/useUpdateNodeInternals.ts +++ b/src/hooks/useUpdateNodeInternals.ts @@ -1,14 +1,14 @@ import { useCallback } from 'react'; import { useStore } from '../store'; -import { ElementId, UpdateNodeInternals, ReactFlowState } from '../types'; +import { UpdateNodeInternals, ReactFlowState } from '../types'; const updateNodeDimsSelector = (state: ReactFlowState) => state.updateNodeDimensions; function useUpdateNodeInternals(): UpdateNodeInternals { const updateNodeDimensions = useStore(updateNodeDimsSelector); - return useCallback((id: ElementId) => { + return useCallback((id: string) => { const nodeElement = document.querySelector(`.react-flow__node[data-id="${id}"]`) as HTMLDivElement; if (nodeElement) { diff --git a/src/hooks/useZoomPanHelper.ts b/src/hooks/useZoomPanHelper.ts index 37938632..aacc48da 100644 --- a/src/hooks/useZoomPanHelper.ts +++ b/src/hooks/useZoomPanHelper.ts @@ -4,7 +4,7 @@ import shallow from 'zustand/shallow'; import { useStoreApi, useStore } from '../store'; import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '../utils/graph'; -import { FitViewParams, FlowTransform, ZoomPanHelperFunctions, Rect, XYPosition, ReactFlowState } from '../types'; +import { FitViewParams, FlowTransform, ZoomPanHelperFunctions, ReactFlowState, Rect, XYPosition } from '../types'; const DEFAULT_PADDING = 0.1; diff --git a/src/store/index.ts b/src/store/index.ts index 27764555..c12e10c7 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -9,15 +9,12 @@ import { Edge, NodeDimensionUpdate, NodeDiffUpdate, - XYPosition, InitD3ZoomPayload, CoordinateExtent, - Transform, - Dimensions, - OnConnectFunc, - OnConnectStartFunc, - OnConnectStopFunc, - OnConnectEndFunc, + OnConnect, + OnConnectStart, + OnConnectStop, + OnConnectEnd, SetConnectionId, SnapGrid, NodeChange, @@ -25,18 +22,20 @@ import { OnEdgesChange, EdgeChange, NodeDimensionChange, + Transform, + Dimensions, + XYPosition, } from '../types'; import { isNode, isEdge, getRectOfNodes, getNodesInside, getConnectedEdges } from '../utils/graph'; import { getHandleBounds } from '../components/Nodes/utils'; -import { createNodeInternals } from './utils'; +import { createNodeInternals, createNodeOrEdgeSelectionChange } from './utils'; const { Provider, useStore, useStoreApi } = createContext(); -const createNodeOrEdgeSelectionChange = (selected: boolean) => (item: Node | Edge) => ({ - id: item.id, - type: 'select', - selected, -}); +const infiniteExtent: CoordinateExtent = [ + [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY], + [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY], +]; const createStore = () => create((set, get) => ({ @@ -47,27 +46,16 @@ const createStore = () => edges: [], onNodesChange: null, onEdgesChange: null, - selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 }, - d3Zoom: null, d3Selection: null, d3ZoomHandler: undefined, minZoom: 0.5, maxZoom: 2, - translateExtent: [ - [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY], - [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY], - ], - - nodeExtent: [ - [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY], - [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY], - ], - + translateExtent: infiniteExtent, + nodeExtent: infiniteExtent, nodesSelectionActive: false, selectionActive: false, - userSelectionRect: { startX: 0, startY: 0, @@ -345,10 +333,10 @@ const createStore = () => unsetNodesSelection: () => set({ nodesSelectionActive: false }), updateTransform: (transform: Transform) => set({ transform }), updateSize: (size: Dimensions) => set({ width: size.width || 500, height: size.height || 500 }), - setOnConnect: (onConnect: OnConnectFunc) => set({ onConnect }), - setOnConnectStart: (onConnectStart: OnConnectStartFunc) => set({ onConnectStart }), - setOnConnectStop: (onConnectStop: OnConnectStopFunc) => set({ onConnectStop }), - setOnConnectEnd: (onConnectEnd: OnConnectEndFunc) => set({ onConnectEnd }), + setOnConnect: (onConnect: OnConnect) => set({ onConnect }), + setOnConnectStart: (onConnectStart: OnConnectStart) => set({ onConnectStart }), + setOnConnectStop: (onConnectStop: OnConnectStop) => set({ onConnectStop }), + setOnConnectEnd: (onConnectEnd: OnConnectEnd) => set({ onConnectEnd }), setConnectionPosition: (connectionPosition: XYPosition) => set({ connectionPosition }), setConnectionNodeId: (params: SetConnectionId) => set({ ...params }), setSnapToGrid: (snapToGrid: boolean) => set({ snapToGrid }), diff --git a/src/store/utils.ts b/src/store/utils.ts index 42704f21..6f34e2cb 100644 --- a/src/store/utils.ts +++ b/src/store/utils.ts @@ -1,7 +1,6 @@ -import { ElementId, Node, NodeInternals, NodeInternalsItem, XYPosition } from '../types'; +import { Node, Edge, NodeInternals, NodeInternalsItem, XYZPosition } from '../types'; -type XYZPosition = XYPosition & { z: number }; -type ParentNodes = Record; +type ParentNodes = Record; function calculateXYZPosition( node: NodeInternalsItem, @@ -33,7 +32,7 @@ function calculateXYZPosition( }); } export function createNodeInternals(nodes: Node[], nodeInternals: NodeInternals): NodeInternals { - const nextNodeInternals = new Map(); + const nextNodeInternals = new Map(); const parentNodes: ParentNodes = {}; nodes.forEach((node) => { @@ -86,3 +85,9 @@ export function createNodeInternals(nodes: Node[], nodeInternals: NodeInternals) return nextNodeInternals; } + +export const createNodeOrEdgeSelectionChange = (selected: boolean) => (item: Node | Edge) => ({ + id: item.id, + type: 'select', + selected, +}); diff --git a/src/types/changes.ts b/src/types/changes.ts new file mode 100644 index 00000000..fd29a477 --- /dev/null +++ b/src/types/changes.ts @@ -0,0 +1,28 @@ +import { XYPosition, Dimensions } from './utils'; +import { NodeHandleBounds } from './nodes'; + +export type NodeDimensionChange = { + id: string; + type: 'dimensions'; + dimensions?: Dimensions; + position?: XYPosition; + handleBounds?: NodeHandleBounds; + dragging?: boolean; +}; + +export type NodeSelectionChange = { + id: string; + type: 'select'; + selected: boolean; +}; + +export type NodeRemoveChange = { + id: string; + type: 'remove'; +}; + +export type NodeChange = NodeDimensionChange | NodeSelectionChange | NodeRemoveChange; + +export type EdgeSelectionChange = NodeSelectionChange; +export type EdgeRemoveChange = NodeRemoveChange; +export type EdgeChange = EdgeSelectionChange | EdgeRemoveChange; diff --git a/src/types/edges.ts b/src/types/edges.ts new file mode 100644 index 00000000..94d242d7 --- /dev/null +++ b/src/types/edges.ts @@ -0,0 +1,158 @@ +import { CSSProperties, ReactNode, HTMLAttributes } from 'react'; + +import { Position } from './utils'; +import { OnConnect, Connection } from './general'; +import { HandleElement } from './handles'; +import { Node } from './nodes'; + +// interface for the user edge items +export interface Edge { + id: string; + type?: string; + source: string; + target: string; + sourceHandle?: string | null; + targetHandle?: string | null; + label?: string | ReactNode; + labelStyle?: CSSProperties; + labelShowBg?: boolean; + labelBgStyle?: CSSProperties; + labelBgPadding?: [number, number]; + labelBgBorderRadius?: number; + style?: CSSProperties; + animated?: boolean; + isHidden?: boolean; + data?: T; + className?: string; + sourceNode?: Node; + targetNode?: Node; + selected?: boolean; + markerStart?: EdgeMarkerType; + markerEnd?: EdgeMarkerType; +} + +// props that get passed to a custom edge +export interface EdgeProps { + id: string; + source: string; + target: string; + sourceX: number; + sourceY: number; + targetX: number; + targetY: number; + selected?: boolean; + animated?: boolean; + sourcePosition: Position; + targetPosition: Position; + label?: string | ReactNode; + labelStyle?: CSSProperties; + labelShowBg?: boolean; + labelBgStyle?: CSSProperties; + labelBgPadding?: [number, number]; + labelBgBorderRadius?: number; + style?: CSSProperties; + data?: T; + sourceHandleId?: string | null; + targetHandleId?: string | null; + markerStart?: string; + markerEnd?: string; +} + +export type EdgeMouseHandler = (event: React.MouseEvent, edge: Edge) => void; + +export interface WrapEdgeProps { + id: string; + className?: string; + type: string; + data?: T; + onClick?: EdgeMouseHandler; + onEdgeDoubleClick?: EdgeMouseHandler; + selected: boolean; + animated?: boolean; + label?: string | ReactNode; + labelStyle?: CSSProperties; + labelShowBg?: boolean; + labelBgStyle?: CSSProperties; + labelBgPadding?: [number, number]; + labelBgBorderRadius?: number; + style?: CSSProperties; + source: string; + target: string; + sourceHandleId: string | null; + targetHandleId: string | null; + sourceX: number; + sourceY: number; + targetX: number; + targetY: number; + sourcePosition: Position; + targetPosition: Position; + elementsSelectable?: boolean; + isHidden?: boolean; + handleEdgeUpdate: boolean; + onConnectEdge: OnConnect; + onContextMenu?: EdgeMouseHandler; + onMouseEnter?: EdgeMouseHandler; + onMouseMove?: EdgeMouseHandler; + onMouseLeave?: EdgeMouseHandler; + edgeUpdaterRadius?: number; + onEdgeUpdateStart?: EdgeMouseHandler; + onEdgeUpdateEnd?: (event: MouseEvent, edge: Edge) => void; + markerStart?: EdgeMarkerType; + markerEnd?: EdgeMarkerType; +} + +export interface EdgeSmoothStepProps extends EdgeProps { + borderRadius?: number; +} + +export interface EdgeTextProps extends HTMLAttributes { + x: number; + y: number; + label?: string | ReactNode; + labelStyle?: CSSProperties; + labelShowBg?: boolean; + labelBgStyle?: CSSProperties; + labelBgPadding?: [number, number]; + labelBgBorderRadius?: number; +} + +export enum ConnectionLineType { + Bezier = 'default', + Straight = 'straight', + Step = 'step', + SmoothStep = 'smoothstep', +} + +export type ConnectionLineComponentProps = { + sourceX: number; + sourceY: number; + sourcePosition?: Position; + targetX: number; + targetY: number; + targetPosition?: Position; + connectionLineStyle?: CSSProperties; + connectionLineType: ConnectionLineType; + sourceNode?: Node; + sourceHandle?: HandleElement; +}; + +export type ConnectionLineComponent = React.ComponentType; + +export type OnEdgeUpdateFunc = (oldEdge: Edge, newConnection: Connection) => void; + +export interface EdgeMarker { + type: ArrowHeadType; + color?: string; + width?: number; + height?: number; + units?: string; + orient?: string; + strokeWidth?: number; +} + +export type EdgeMarkerType = string | EdgeMarker; + +export enum ArrowHeadType { + Arrow = 'arrow', + ArrowClosed = 'arrowclosed', +} diff --git a/src/types/general.ts b/src/types/general.ts new file mode 100644 index 00000000..68dd316e --- /dev/null +++ b/src/types/general.ts @@ -0,0 +1,217 @@ +import { MouseEvent as ReactMouseEvent, ReactNode } from 'react'; +import { Selection as D3Selection, ZoomBehavior } from 'd3'; + +import { XYPosition, Rect, Transform, CoordinateExtent, Dimensions } from './utils'; +import { NodeChange, EdgeChange } from './changes'; +import { Node, NodeInternals, NodeDimensionUpdate, NodeDiffUpdate } from './nodes'; +import { Edge } from './edges'; +import { HandleType } from './handles'; + +export type FlowElement = Node | Edge; + +export type Elements = Array>; + +export type NodeTypesType = { [key: string]: ReactNode }; +export type EdgeTypesType = NodeTypesType; + +export type FitView = (fitViewOptions?: FitViewParams) => void; + +export type Project = (position: XYPosition) => XYPosition; + +export type ToObject = () => FlowExportObject; + +export type OnNodesChange = (nodes: NodeChange[]) => void; + +export type OnEdgesChange = (nodes: EdgeChange[]) => void; + +export interface SelectionRect extends Rect { + startX: number; + startY: number; + draw: boolean; +} + +export type OnLoadParams = { + zoomIn: () => void; + zoomOut: () => void; + zoomTo: (zoomLevel: number) => void; + fitView: FitView; + project: Project; + getNodes: () => Node[]; + getEdges: () => Edge[]; + setTransform: (transform: FlowTransform) => void; + toObject: ToObject; +}; + +export type OnLoad = (params: OnLoadParams) => void; + +export interface Connection { + source: string | null; + target: string | null; + sourceHandle: string | null; + targetHandle: string | null; +} + +export enum ConnectionMode { + Strict = 'strict', + Loose = 'loose', +} + +export type FlowExportObject = { + nodes: Node[]; + edges: Edge[]; + position: [number, number]; + zoom: number; +}; + +export type OnConnect = (connection: Connection) => void; + +export type FitViewParams = { + padding?: number; + includeHiddenNodes?: boolean; + minZoom?: number; + maxZoom?: number; +}; + +export type OnConnectStartParams = { + nodeId: string | null; + handleId: string | null; + handleType: HandleType | null; +}; + +export type OnConnectStart = (event: ReactMouseEvent, params: OnConnectStartParams) => void; + +export type OnConnectStop = (event: MouseEvent) => void; + +export type OnConnectEnd = (event: MouseEvent) => void; + +export type SetConnectionId = { + connectionNodeId: string | null; + connectionHandleId: string | null; + connectionHandleType: HandleType | null; +}; + +export enum BackgroundVariant { + Lines = 'lines', + Dots = 'dots', +} + +export type FlowTransform = { + x: number; + y: number; + zoom: number; +}; + +export type KeyCode = string | Array; + +export type SnapGrid = [number, number]; + +export enum PanOnScrollMode { + Free = 'free', + Vertical = 'vertical', + Horizontal = 'horizontal', +} + +export interface ZoomPanHelperFunctions { + zoomIn: () => void; + zoomOut: () => void; + zoomTo: (zoomLevel: number) => void; + transform: (transform: FlowTransform) => void; + fitView: FitView; + setCenter: (x: number, y: number, zoom?: number) => void; + fitBounds: (bounds: Rect, padding?: number) => void; + project: (position: XYPosition) => XYPosition; + initialized: boolean; +} + +export type InitD3ZoomPayload = { + d3Zoom: ZoomBehavior; + d3Selection: D3Selection; + d3ZoomHandler: ((this: Element, event: any, d: unknown) => void) | undefined; + transform: Transform; +}; + +export interface ReactFlowState { + width: number; + height: number; + transform: Transform; + nodes: Node[]; + nodeInternals: NodeInternals; + edges: Edge[]; + selectedNodesBbox: Rect; + onNodesChange: OnNodesChange | null; + onEdgesChange: OnEdgesChange | null; + + d3Zoom: ZoomBehavior | null; + d3Selection: D3Selection | null; + d3ZoomHandler: ((this: Element, event: any, d: unknown) => void) | undefined; + minZoom: number; + maxZoom: number; + translateExtent: CoordinateExtent; + nodeExtent: CoordinateExtent; + + nodesSelectionActive: boolean; + selectionActive: boolean; + + userSelectionRect: SelectionRect; + + connectionNodeId: string | null; + connectionHandleId: string | null; + connectionHandleType: HandleType | null; + connectionPosition: XYPosition; + connectionMode: ConnectionMode; + + snapToGrid: boolean; + snapGrid: SnapGrid; + + nodesDraggable: boolean; + nodesConnectable: boolean; + elementsSelectable: boolean; + + multiSelectionActive: boolean; + + reactFlowVersion: string; + + setNodes: (nodes: Node[]) => void; + setEdges: (edges: Edge[], nodes: Node[]) => void; + updateNodeDimensions: (updates: NodeDimensionUpdate[]) => void; + updateNodePosition: (update: NodeDiffUpdate) => void; + setUserSelection: (mousePos: XYPosition) => void; + updateUserSelection: (mousePos: XYPosition) => void; + unsetUserSelection: () => void; + unsetNodesSelection: () => void; + resetSelectedElements: () => void; + unselectNodesAndEdges: () => void; + addSelectedElements: (elements: Elements) => void; + updateTransform: (transform: Transform) => void; + updateSize: (size: Dimensions) => void; + initD3Zoom: (payload: InitD3ZoomPayload) => void; + setMinZoom: (minZoom: number) => void; + setMaxZoom: (maxZoom: number) => void; + setTranslateExtent: (translateExtent: CoordinateExtent) => void; + setNodeExtent: (nodeExtent: CoordinateExtent) => void; + setOnConnect: (onConnectFunction: OnConnect) => void; + setOnConnectStart: (onConnectFunction: OnConnectStart) => void; + setOnConnectStop: (onConnectFunction: OnConnectStop) => void; + setOnConnectEnd: (onConnectFunction: OnConnectEnd) => void; + setConnectionPosition: (connectionPosition: XYPosition) => void; + setConnectionNodeId: (payload: SetConnectionId) => void; + setSnapToGrid: (snapToGrid: boolean) => void; + setSnapGrid: (snapGrid: SnapGrid) => void; + setInteractive: (isInteractive: boolean) => void; + setNodesDraggable: (nodesDraggable: boolean) => void; + setNodesConnectable: (nodesConnectable: boolean) => void; + setElementsSelectable: (elementsSelectable: boolean) => void; + setMultiSelectionActive: (multiSelectionActive: boolean) => void; + setConnectionMode: (connectionMode: ConnectionMode) => void; + setOnNodesChange: (onNodesChange: OnNodesChange) => void; + setOnEdgesChange: (onEdgesChange: OnEdgesChange) => void; + + onConnect?: OnConnect; + onConnectStart?: OnConnectStart; + onConnectStop?: OnConnectStop; + onConnectEnd?: OnConnectEnd; +} + +export type UpdateNodeInternals = (nodeId: string) => void; + +export type OnSelectionChangeFunc = (params: { nodes: Node[]; edges: Edge[] }) => void; diff --git a/src/types/handles.ts b/src/types/handles.ts new file mode 100644 index 00000000..9114b360 --- /dev/null +++ b/src/types/handles.ts @@ -0,0 +1,18 @@ +import { XYPosition, Position, Dimensions } from './utils'; +import { OnConnect, Connection } from './general'; + +export type HandleType = 'source' | 'target'; + +export interface HandleElement extends XYPosition, Dimensions { + id?: string | null; + position: Position; +} + +export interface HandleProps { + type: HandleType; + position: Position; + isConnectable?: boolean; + onConnect?: OnConnect; + isValidConnection?: (connection: Connection) => boolean; + id?: string; +} diff --git a/src/types/index.ts b/src/types/index.ts index d37949b9..bf9e688a 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,565 +1,6 @@ -import React, { CSSProperties, MouseEvent as ReactMouseEvent, HTMLAttributes, ReactNode } from 'react'; -import { Selection as D3Selection, ZoomBehavior } from 'd3'; - -export type ElementId = string; - -export type FlowElement = Node | Edge; - -export type Elements = Array>; - -export type Transform = [number, number, number]; - -export type NodeDimensionChange = { - id: string; - type: 'dimensions'; - dimensions?: Dimensions; - position?: XYPosition; - handleBounds?: NodeHandleBounds; - dragging?: boolean; -}; - -export type NodeSelectionChange = { - id: string; - type: 'select'; - selected: boolean; -}; -export type NodeRemoveChange = { - id: string; - type: 'remove'; -}; -export type NodeChange = NodeDimensionChange | NodeSelectionChange | NodeRemoveChange; - -export type EdgeSelectionChange = NodeSelectionChange; -export type EdgeRemoveChange = NodeRemoveChange; -export type EdgeChange = EdgeSelectionChange | EdgeRemoveChange; - -export enum Position { - Left = 'left', - Top = 'top', - Right = 'right', - Bottom = 'bottom', -} - -export interface XYPosition { - x: number; - y: number; -} - -export interface Dimensions { - width: number; - height: number; -} - -export interface Rect extends Dimensions, XYPosition {} - -export interface Box extends XYPosition { - x2: number; - y2: number; -} - -export type SnapGrid = [number, number]; - -export type NodeHandleBounds = { - source: HandleElement[] | null; - target: HandleElement[] | null; -}; - -export interface Node { - id: ElementId; - position: XYPosition; - type?: string; - data?: T; - style?: CSSProperties; - className?: string; - targetPosition?: Position; - sourcePosition?: Position; - isHidden?: boolean; - selected?: boolean; - dragging?: boolean; - draggable?: boolean; - selectable?: boolean; - connectable?: boolean; - dragHandle?: string; - width?: number | null; - height?: number | null; - parentNode?: ElementId; - zIndex?: number; - extent?: 'parent' | CoordinateExtent; -} - -export enum ArrowHeadType { - Arrow = 'arrow', - ArrowClosed = 'arrowclosed', -} - -export interface EdgeMarker { - type: ArrowHeadType; - color?: string; - width?: number; - height?: number; - units?: string; - orient?: string; - strokeWidth?: number; -} - -export type EdgeMarkerType = string | EdgeMarker; - -export interface Edge { - id: ElementId; - type?: string; - source: ElementId; - target: ElementId; - sourceHandle?: ElementId | null; - targetHandle?: ElementId | null; - label?: string | ReactNode; - labelStyle?: CSSProperties; - labelShowBg?: boolean; - labelBgStyle?: CSSProperties; - labelBgPadding?: [number, number]; - labelBgBorderRadius?: number; - style?: CSSProperties; - animated?: boolean; - isHidden?: boolean; - data?: T; - className?: string; - sourceNode?: Node; - targetNode?: Node; - selected?: boolean; - markerStart?: EdgeMarkerType; - markerEnd?: EdgeMarkerType; -} - -export enum BackgroundVariant { - Lines = 'lines', - Dots = 'dots', -} - -export type HandleType = 'source' | 'target'; - -export type NodeTypesType = { [key: string]: ReactNode }; - -export type EdgeTypesType = NodeTypesType; - -export interface SelectionRect extends Rect { - startX: number; - startY: number; - draw: boolean; -} - -export interface WrapEdgeProps { - id: ElementId; - className?: string; - type: string; - data?: T; - onClick?: (event: React.MouseEvent, edge: Edge) => void; - onEdgeDoubleClick?: (event: React.MouseEvent, edge: Edge) => void; - selected: boolean; - animated?: boolean; - label?: string | ReactNode; - labelStyle?: CSSProperties; - labelShowBg?: boolean; - labelBgStyle?: CSSProperties; - labelBgPadding?: [number, number]; - labelBgBorderRadius?: number; - style?: CSSProperties; - source: ElementId; - target: ElementId; - sourceHandleId: ElementId | null; - targetHandleId: ElementId | null; - sourceX: number; - sourceY: number; - targetX: number; - targetY: number; - sourcePosition: Position; - targetPosition: Position; - elementsSelectable?: boolean; - isHidden?: boolean; - handleEdgeUpdate: boolean; - onConnectEdge: OnConnectFunc; - onContextMenu?: (event: React.MouseEvent, edge: Edge) => void; - onMouseEnter?: (event: React.MouseEvent, edge: Edge) => void; - onMouseMove?: (event: React.MouseEvent, edge: Edge) => void; - onMouseLeave?: (event: React.MouseEvent, edge: Edge) => void; - edgeUpdaterRadius?: number; - onEdgeUpdateStart?: (event: React.MouseEvent, edge: Edge) => void; - onEdgeUpdateEnd?: (event: MouseEvent, edge: Edge) => void; - markerStart?: EdgeMarkerType; - markerEnd?: EdgeMarkerType; -} - -export interface EdgeProps { - id: ElementId; - source: ElementId; - target: ElementId; - sourceX: number; - sourceY: number; - targetX: number; - targetY: number; - selected?: boolean; - animated?: boolean; - sourcePosition: Position; - targetPosition: Position; - label?: string | ReactNode; - labelStyle?: CSSProperties; - labelShowBg?: boolean; - labelBgStyle?: CSSProperties; - labelBgPadding?: [number, number]; - labelBgBorderRadius?: number; - style?: CSSProperties; - data?: T; - sourceHandleId?: ElementId | null; - targetHandleId?: ElementId | null; - markerStart?: string; - markerEnd?: string; -} -export interface EdgeSmoothStepProps extends EdgeProps { - borderRadius?: number; -} - -export interface EdgeTextProps extends HTMLAttributes { - x: number; - y: number; - label?: string | ReactNode; - labelStyle?: CSSProperties; - labelShowBg?: boolean; - labelBgStyle?: CSSProperties; - labelBgPadding?: [number, number]; - labelBgBorderRadius?: number; -} - -export interface NodeProps { - id: ElementId; - type: string; - data: T; - selected: boolean; - isConnectable: boolean; - xPos?: number; - yPos?: number; - targetPosition?: Position; - sourcePosition?: Position; - dragging?: boolean; - dragHandle?: string; - zIndex?: number; -} - -export interface NodeComponentProps { - id: ElementId; - type: string; - data: T; - selected?: boolean; - isConnectable: boolean; - transform?: Transform; - xPos?: number; - yPos?: number; - targetPosition?: Position; - sourcePosition?: Position; - onClick?: (node: Node) => void; - onNodeDoubleClick?: (node: Node) => void; - onMouseEnter?: (node: Node) => void; - onMouseMove?: (node: Node) => void; - onMouseLeave?: (node: Node) => void; - onContextMenu?: (node: Node) => void; - onNodeDragStart?: (node: Node) => void; - onNodeDrag?: (node: Node) => void; - onNodeDragStop?: (node: Node) => void; - style?: CSSProperties; - dragging?: boolean; - dragHandle?: string; - zIndex?: number; -} - -export interface WrapNodeProps { - id: ElementId; - type: string; - data: T; - selected: boolean; - scale: number; - xPos: number; - yPos: number; - width?: number | null; - height?: number | null; - isSelectable: boolean; - isDraggable: boolean; - isConnectable: boolean; - selectNodesOnDrag: boolean; - onClick?: (event: ReactMouseEvent, node: Node) => void; - onNodeDoubleClick?: (event: ReactMouseEvent, node: Node) => void; - onMouseEnter?: (event: ReactMouseEvent, node: Node) => void; - onMouseMove?: (event: ReactMouseEvent, node: Node) => void; - onMouseLeave?: (event: ReactMouseEvent, node: Node) => void; - onContextMenu?: (event: ReactMouseEvent, node: Node) => void; - onNodeDragStart?: (event: ReactMouseEvent, node: Node) => void; - onNodeDrag?: (event: ReactMouseEvent, node: Node) => void; - onNodeDragStop?: (event: ReactMouseEvent, node: Node) => void; - style?: CSSProperties; - className?: string; - sourcePosition?: Position; - targetPosition?: Position; - isHidden?: boolean; - isInitialized?: boolean; - snapToGrid?: boolean; - snapGrid?: SnapGrid; - dragging?: boolean; - resizeObserver: ResizeObserver | null; - dragHandle?: string; - zIndex: number; - isParent: boolean; -} - -export type FitViewParams = { - padding?: number; - includeHiddenNodes?: boolean; - minZoom?: number; - maxZoom?: number; -}; - -export type FlowExportObject = { - nodes: Node[]; - edges: Edge[]; - position: [number, number]; - zoom: number; -}; - -export type FitViewFunc = (fitViewOptions?: FitViewParams) => void; -export type ProjectFunc = (position: XYPosition) => XYPosition; -export type ToObjectFunc = () => FlowExportObject; - -export type OnLoadParams = { - zoomIn: () => void; - zoomOut: () => void; - zoomTo: (zoomLevel: number) => void; - fitView: FitViewFunc; - project: ProjectFunc; - getNodes: () => Node[]; - getEdges: () => Edge[]; - setTransform: (transform: FlowTransform) => void; - toObject: ToObjectFunc; -}; - -export type OnLoadFunc = (params: OnLoadParams) => void; - -export interface Connection { - source: ElementId | null; - target: ElementId | null; - sourceHandle: ElementId | null; - targetHandle: ElementId | null; -} - -export enum ConnectionMode { - Strict = 'strict', - Loose = 'loose', -} - -export enum ConnectionLineType { - Bezier = 'default', - Straight = 'straight', - Step = 'step', - SmoothStep = 'smoothstep', -} - -export type ConnectionLineComponentProps = { - sourceX: number; - sourceY: number; - sourcePosition?: Position; - targetX: number; - targetY: number; - targetPosition?: Position; - connectionLineStyle?: CSSProperties; - connectionLineType: ConnectionLineType; - sourceNode?: Node; - sourceHandle?: HandleElement; -}; - -export type ConnectionLineComponent = React.ComponentType; - -export type OnConnectFunc = (connection: Connection) => void; -export type OnConnectStartParams = { - nodeId: ElementId | null; - handleId: ElementId | null; - handleType: HandleType | null; -}; -export type OnConnectStartFunc = (event: ReactMouseEvent, params: OnConnectStartParams) => void; -export type OnConnectStopFunc = (event: MouseEvent) => void; -export type OnConnectEndFunc = (event: MouseEvent) => void; - -export type SetConnectionId = { - connectionNodeId: ElementId | null; - connectionHandleId: ElementId | null; - connectionHandleType: HandleType | null; -}; - -export interface HandleElement extends XYPosition, Dimensions { - id?: ElementId | null; - position: Position; -} - -export interface HandleProps { - type: HandleType; - position: Position; - isConnectable?: boolean; - onConnect?: OnConnectFunc; - isValidConnection?: (connection: Connection) => boolean; - id?: ElementId; -} - -export type NodePosUpdate = { - id: ElementId; - pos: XYPosition; -}; - -export type NodeDiffUpdate = { - id?: ElementId; - diff?: XYPosition; - dragging?: boolean; -}; - -export type FlowTransform = { - x: number; - y: number; - zoom: number; -}; - -export type CoordinateExtent = [[number, number], [number, number]]; - -export type KeyCode = string | Array; - -export enum PanOnScrollMode { - Free = 'free', - Vertical = 'vertical', - Horizontal = 'horizontal', -} - -export interface ZoomPanHelperFunctions { - zoomIn: () => void; - zoomOut: () => void; - zoomTo: (zoomLevel: number) => void; - transform: (transform: FlowTransform) => void; - fitView: FitViewFunc; - setCenter: (x: number, y: number, zoom?: number) => void; - fitBounds: (bounds: Rect, padding?: number) => void; - project: (position: XYPosition) => XYPosition; - initialized: boolean; -} - -export type OnEdgeUpdateFunc = (oldEdge: Edge, newConnection: Connection) => void; - -export type NodeDimensionUpdate = { - id: ElementId; - nodeElement: HTMLDivElement; - forceUpdate?: boolean; -}; - -export type InitD3ZoomPayload = { - d3Zoom: ZoomBehavior; - d3Selection: D3Selection; - d3ZoomHandler: ((this: Element, event: any, d: unknown) => void) | undefined; - transform: Transform; -}; - -export type OnNodesChange = (nodes: NodeChange[]) => void; -export type OnEdgesChange = (nodes: EdgeChange[]) => void; - -export type NodeInternalsItem = { - id?: string; - width?: number | null; - height?: number | null; - parentNode?: ElementId; - position?: XYPosition; - positionAbsolute?: XYPosition; - handleBounds?: NodeHandleBounds; - z?: number; - isParent?: boolean; -}; - -export type NodeInternals = Map; - -export interface ReactFlowState { - width: number; - height: number; - transform: Transform; - nodes: Node[]; - nodeInternals: NodeInternals; - edges: Edge[]; - selectedNodesBbox: Rect; - onNodesChange: OnNodesChange | null; - onEdgesChange: OnEdgesChange | null; - - d3Zoom: ZoomBehavior | null; - d3Selection: D3Selection | null; - d3ZoomHandler: ((this: Element, event: any, d: unknown) => void) | undefined; - minZoom: number; - maxZoom: number; - translateExtent: CoordinateExtent; - nodeExtent: CoordinateExtent; - - nodesSelectionActive: boolean; - selectionActive: boolean; - - userSelectionRect: SelectionRect; - - connectionNodeId: ElementId | null; - connectionHandleId: ElementId | null; - connectionHandleType: HandleType | null; - connectionPosition: XYPosition; - connectionMode: ConnectionMode; - - snapToGrid: boolean; - snapGrid: SnapGrid; - - nodesDraggable: boolean; - nodesConnectable: boolean; - elementsSelectable: boolean; - - multiSelectionActive: boolean; - - reactFlowVersion: string; - - setNodes: (nodes: Node[]) => void; - setEdges: (edges: Edge[], nodes: Node[]) => void; - updateNodeDimensions: (updates: NodeDimensionUpdate[]) => void; - updateNodePosition: (update: NodeDiffUpdate) => void; - setUserSelection: (mousePos: XYPosition) => void; - updateUserSelection: (mousePos: XYPosition) => void; - unsetUserSelection: () => void; - unsetNodesSelection: () => void; - resetSelectedElements: () => void; - unselectNodesAndEdges: () => void; - addSelectedElements: (elements: Elements) => void; - updateTransform: (transform: Transform) => void; - updateSize: (size: Dimensions) => void; - initD3Zoom: (payload: InitD3ZoomPayload) => void; - setMinZoom: (minZoom: number) => void; - setMaxZoom: (maxZoom: number) => void; - setTranslateExtent: (translateExtent: CoordinateExtent) => void; - setNodeExtent: (nodeExtent: CoordinateExtent) => void; - setOnConnect: (onConnectFunction: OnConnectFunc) => void; - setOnConnectStart: (onConnectFunction: OnConnectStartFunc) => void; - setOnConnectStop: (onConnectFunction: OnConnectStopFunc) => void; - setOnConnectEnd: (onConnectFunction: OnConnectEndFunc) => void; - setConnectionPosition: (connectionPosition: XYPosition) => void; - setConnectionNodeId: (payload: SetConnectionId) => void; - setSnapToGrid: (snapToGrid: boolean) => void; - setSnapGrid: (snapGrid: SnapGrid) => void; - setInteractive: (isInteractive: boolean) => void; - setNodesDraggable: (nodesDraggable: boolean) => void; - setNodesConnectable: (nodesConnectable: boolean) => void; - setElementsSelectable: (elementsSelectable: boolean) => void; - setMultiSelectionActive: (multiSelectionActive: boolean) => void; - setConnectionMode: (connectionMode: ConnectionMode) => void; - setOnNodesChange: (onNodesChange: OnNodesChange) => void; - setOnEdgesChange: (onEdgesChange: OnEdgesChange) => void; - - onConnect?: OnConnectFunc; - onConnectStart?: OnConnectStartFunc; - onConnectStop?: OnConnectStopFunc; - onConnectEnd?: OnConnectEndFunc; -} - -export type UpdateNodeInternals = (nodeId: ElementId) => void; - -export type OnSelectionChangeFunc = (params: { nodes: Node[]; edges: Edge[] }) => void; - -export type NodeRendererNode = { - childNodes?: NodeRendererNode[]; - node: Node; -}; +export * from './general'; +export * from './nodes'; +export * from './edges'; +export * from './handles'; +export * from './changes'; +export * from './utils'; diff --git a/src/types/nodes.ts b/src/types/nodes.ts new file mode 100644 index 00000000..f2b7b02a --- /dev/null +++ b/src/types/nodes.ts @@ -0,0 +1,116 @@ +import { CSSProperties, MouseEvent as ReactMouseEvent } from 'react'; + +import { SnapGrid } from './general'; +import { XYPosition, Position, CoordinateExtent } from './utils'; +import { HandleElement } from './handles'; + +// interface for the user node items +export interface Node { + id: string; + position: XYPosition; + type?: string; + data?: T; + style?: CSSProperties; + className?: string; + targetPosition?: Position; + sourcePosition?: Position; + isHidden?: boolean; + selected?: boolean; + dragging?: boolean; + draggable?: boolean; + selectable?: boolean; + connectable?: boolean; + dragHandle?: string; + width?: number | null; + height?: number | null; + parentNode?: string; + zIndex?: number; + extent?: 'parent' | CoordinateExtent; +} + +// props that get passed to a custom node +export interface NodeProps { + id: string; + type: string; + data: T; + selected: boolean; + isConnectable: boolean; + xPos: number; + yPos: number; + dragging: boolean; + zIndex: number; + targetPosition?: Position; + sourcePosition?: Position; + dragHandle?: string; +} + +export type NodeMouseHandler = (event: ReactMouseEvent, node: Node) => void; + +export interface WrapNodeProps { + id: string; + type: string; + data: T; + selected: boolean; + isConnectable: boolean; + scale: number; + xPos: number; + yPos: number; + width?: number | null; + height?: number | null; + isSelectable: boolean; + isDraggable: boolean; + selectNodesOnDrag: boolean; + onClick?: NodeMouseHandler; + onNodeDoubleClick?: NodeMouseHandler; + onMouseEnter?: NodeMouseHandler; + onMouseMove?: NodeMouseHandler; + onMouseLeave?: NodeMouseHandler; + onContextMenu?: NodeMouseHandler; + onNodeDragStart?: NodeMouseHandler; + onNodeDrag?: NodeMouseHandler; + onNodeDragStop?: NodeMouseHandler; + style?: CSSProperties; + className?: string; + sourcePosition?: Position; + targetPosition?: Position; + isHidden?: boolean; + isInitialized?: boolean; + snapToGrid?: boolean; + snapGrid?: SnapGrid; + dragging: boolean; + resizeObserver: ResizeObserver | null; + dragHandle?: string; + zIndex: number; + isParent: boolean; +} + +export type NodeHandleBounds = { + source: HandleElement[] | null; + target: HandleElement[] | null; +}; + +export type NodeDiffUpdate = { + id?: string; + diff?: XYPosition; + dragging?: boolean; +}; + +export type NodeDimensionUpdate = { + id: string; + nodeElement: HTMLDivElement; + forceUpdate?: boolean; +}; + +export type NodeInternalsItem = { + id?: string; + width?: number | null; + height?: number | null; + parentNode?: string; + position?: XYPosition; + positionAbsolute?: XYPosition; + handleBounds?: NodeHandleBounds; + z?: number; + isParent?: boolean; +}; + +export type NodeInternals = Map; diff --git a/src/types/utils.ts b/src/types/utils.ts new file mode 100644 index 00000000..eadce743 --- /dev/null +++ b/src/types/utils.ts @@ -0,0 +1,29 @@ +export enum Position { + Left = 'left', + Top = 'top', + Right = 'right', + Bottom = 'bottom', +} + +export interface XYPosition { + x: number; + y: number; +} + +export type XYZPosition = XYPosition & { z: number }; + +export interface Dimensions { + width: number; + height: number; +} + +export interface Rect extends Dimensions, XYPosition {} + +export interface Box extends XYPosition { + x2: number; + y2: number; +} + +export type Transform = [number, number, number]; + +export type CoordinateExtent = [[number, number], [number, number]]; diff --git a/src/utils/graph.ts b/src/utils/graph.ts index 9ceba91d..b575bbf7 100644 --- a/src/utils/graph.ts +++ b/src/utils/graph.ts @@ -1,6 +1,6 @@ import { boxToRect, clamp, getBoundsOfBoxes, rectToBox } from '../utils'; -import { ElementId, Node, Edge, Elements, Transform, XYPosition, Rect, Connection, EdgeMarkerType } from '../types'; +import { Node, Edge, Elements, Connection, EdgeMarkerType, Transform, XYPosition, Rect } from '../types'; export const isEdge = (element: Node | Connection | Edge): element is Edge => 'id' in element && 'source' in element && 'target' in element; @@ -26,7 +26,7 @@ export const getIncomers = (node: Node, nodes: Node[], edges: Edge[]): Node[] => return nodes.filter((n) => incomersIds.includes(n.id)); }; -const getEdgeId = ({ source, sourceHandle, target, targetHandle }: Connection): ElementId => +const getEdgeId = ({ source, sourceHandle, target, targetHandle }: Connection): string => `reactflow__edge-${source}${sourceHandle}-${target}${targetHandle}`; export const getMarkerId = (marker: EdgeMarkerType | undefined): string => {