refactor(types): use custom node type as generic

This commit is contained in:
moklick
2023-12-07 12:24:03 +01:00
parent 0f657a5193
commit 10f31e79e6
12 changed files with 160 additions and 116 deletions
@@ -4,12 +4,12 @@ import type { PanelPosition, XYPosition } from '@xyflow/system';
import type { Node } from '../../types'; import type { Node } from '../../types';
export type GetMiniMapNodeAttribute<NodeData = any> = (node: Node<NodeData>) => string; export type GetMiniMapNodeAttribute<NodeType extends Node = Node> = (node: NodeType) => string;
export type MiniMapProps<NodeData = any> = Omit<HTMLAttributes<SVGSVGElement>, 'onClick'> & { export type MiniMapProps<NodeType extends Node = Node> = Omit<HTMLAttributes<SVGSVGElement>, 'onClick'> & {
nodeColor?: string | GetMiniMapNodeAttribute<NodeData>; nodeColor?: string | GetMiniMapNodeAttribute<NodeType>;
nodeStrokeColor?: string | GetMiniMapNodeAttribute<NodeData>; nodeStrokeColor?: string | GetMiniMapNodeAttribute<NodeType>;
nodeClassName?: string | GetMiniMapNodeAttribute<NodeData>; nodeClassName?: string | GetMiniMapNodeAttribute<NodeType>;
nodeBorderRadius?: number; nodeBorderRadius?: number;
nodeStrokeWidth?: number; nodeStrokeWidth?: number;
nodeComponent?: ComponentType<MiniMapNodeProps>; nodeComponent?: ComponentType<MiniMapNodeProps>;
@@ -18,7 +18,7 @@ export type MiniMapProps<NodeData = any> = Omit<HTMLAttributes<SVGSVGElement>, '
maskStrokeWidth?: number; maskStrokeWidth?: number;
position?: PanelPosition; position?: PanelPosition;
onClick?: (event: MouseEvent, position: XYPosition) => void; onClick?: (event: MouseEvent, position: XYPosition) => void;
onNodeClick?: (event: MouseEvent, node: Node<NodeData>) => void; onNodeClick?: (event: MouseEvent, node: NodeType) => void;
pannable?: boolean; pannable?: boolean;
zoomable?: boolean; zoomable?: boolean;
ariaLabel?: string | null; ariaLabel?: string | null;
@@ -27,8 +27,8 @@ export type MiniMapProps<NodeData = any> = Omit<HTMLAttributes<SVGSVGElement>, '
offsetScale?: number; offsetScale?: number;
}; };
export type MiniMapNodes = Pick< export type MiniMapNodes<NodeType extends Node = Node> = Pick<
MiniMapProps, MiniMapProps<NodeType>,
'nodeColor' | 'nodeStrokeColor' | 'nodeClassName' | 'nodeBorderRadius' | 'nodeStrokeWidth' | 'nodeComponent' 'nodeColor' | 'nodeStrokeColor' | 'nodeClassName' | 'nodeBorderRadius' | 'nodeStrokeWidth' | 'nodeComponent'
> & { > & {
onClick?: (event: MouseEvent, nodeId: string) => void; onClick?: (event: MouseEvent, nodeId: string) => void;
+2 -2
View File
@@ -5,8 +5,8 @@ import type { Node, ReactFlowState } from '../types';
const nodesSelector = (state: ReactFlowState) => state.nodes; const nodesSelector = (state: ReactFlowState) => state.nodes;
function useNodes<NodeData>(): Node<NodeData>[] { function useNodes<NodeType extends Node = Node>(): NodeType[] {
const nodes = useStore(nodesSelector, shallow); const nodes = useStore(nodesSelector, shallow) as NodeType[];
return nodes; return nodes;
} }
@@ -11,14 +11,14 @@ type OnChange<ChangesType> = (changes: ChangesType[]) => void;
// const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); // const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
function createUseItemsState( function createUseItemsState(
applyChanges: ApplyChanges<Node, NodeChange> applyChanges: ApplyChanges<Node, NodeChange>
): <NodeData = any>( ): <NodeType extends Node = Node>(
initialItems: Node<NodeData>[] initialItems: NodeType[]
) => [Node<NodeData>[], Dispatch<SetStateAction<Node<NodeData>[]>>, OnChange<NodeChange>]; ) => [NodeType[], Dispatch<SetStateAction<NodeType[]>>, OnChange<NodeChange>];
function createUseItemsState( function createUseItemsState(
applyChanges: ApplyChanges<Edge, EdgeChange> applyChanges: ApplyChanges<Edge, EdgeChange>
): <EdgeData = any>( ): <EdgeType extends Edge = Edge>(
initialItems: Edge<EdgeData>[] initialItems: EdgeType[]
) => [Edge<EdgeData>[], Dispatch<SetStateAction<Edge<EdgeData>[]>>, OnChange<EdgeChange>]; ) => [EdgeType[], Dispatch<SetStateAction<EdgeType[]>>, OnChange<EdgeChange>];
function createUseItemsState( function createUseItemsState(
applyChanges: ApplyChanges<any, any> applyChanges: ApplyChanges<any, any>
): (initialItems: any[]) => [any[], Dispatch<SetStateAction<any[]>>, OnChange<any>] { ): (initialItems: any[]) => [any[], Dispatch<SetStateAction<any[]>>, OnChange<any>] {
+30 -29
View File
@@ -26,31 +26,34 @@ import type {
} from '../types'; } from '../types';
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlowInstance<NodeData, EdgeData> { export default function useReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(): ReactFlowInstance<
NodeType,
EdgeType
> {
const viewportHelper = useViewportHelper(); const viewportHelper = useViewportHelper();
const store = useStoreApi(); const store = useStoreApi();
const getNodes = useCallback<Instance.GetNodes<NodeData>>(() => { const getNodes = useCallback<Instance.GetNodes<NodeType>>(() => {
return store.getState().nodes.map((n) => ({ ...n })); return store.getState().nodes.map((n) => ({ ...n })) as NodeType[];
}, []); }, []);
const getNode = useCallback<Instance.GetNode<NodeData>>((id) => { const getNode = useCallback<Instance.GetNode<NodeType>>((id) => {
return store.getState().nodeLookup.get(id); return store.getState().nodeLookup.get(id) as NodeType;
}, []); }, []);
const getEdges = useCallback<Instance.GetEdges<EdgeData>>(() => { const getEdges = useCallback<Instance.GetEdges<EdgeType>>(() => {
const { edges = [] } = store.getState(); const { edges = [] } = store.getState();
return edges.map((e) => ({ ...e })); return edges.map((e) => ({ ...e })) as EdgeType[];
}, []); }, []);
const getEdge = useCallback<Instance.GetEdge<EdgeData>>((id) => { const getEdge = useCallback<Instance.GetEdge<EdgeType>>((id) => {
const { edges = [] } = store.getState(); const { edges = [] } = store.getState();
return edges.find((e) => e.id === id); return edges.find((e) => e.id === id) as EdgeType;
}, []); }, []);
const setNodes = useCallback<Instance.SetNodes<NodeData>>((payload) => { const setNodes = useCallback<Instance.SetNodes<NodeType>>((payload) => {
const { nodes, setNodes, hasDefaultNodes, onNodesChange } = store.getState(); const { nodes, setNodes, hasDefaultNodes, onNodesChange } = store.getState();
const nextNodes = typeof payload === 'function' ? payload(nodes) : payload; const nextNodes = typeof payload === 'function' ? payload(nodes as NodeType[]) : payload;
if (hasDefaultNodes) { if (hasDefaultNodes) {
setNodes(nextNodes); setNodes(nextNodes);
@@ -58,14 +61,14 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
const changes = const changes =
nextNodes.length === 0 nextNodes.length === 0
? nodes.map((node) => ({ type: 'remove', id: node.id } as NodeRemoveChange)) ? nodes.map((node) => ({ type: 'remove', id: node.id } as NodeRemoveChange))
: nextNodes.map((node) => ({ item: node, type: 'reset' } as NodeResetChange<NodeData>)); : nextNodes.map((node) => ({ item: node, type: 'reset' } as NodeResetChange<NodeType>));
onNodesChange(changes); onNodesChange(changes);
} }
}, []); }, []);
const setEdges = useCallback<Instance.SetEdges<EdgeData>>((payload) => { const setEdges = useCallback<Instance.SetEdges<EdgeType>>((payload) => {
const { edges = [], setEdges, hasDefaultEdges, onEdgesChange } = store.getState(); const { edges = [], setEdges, hasDefaultEdges, onEdgesChange } = store.getState();
const nextEdges = typeof payload === 'function' ? payload(edges) : payload; const nextEdges = typeof payload === 'function' ? payload(edges as EdgeType[]) : payload;
if (hasDefaultEdges) { if (hasDefaultEdges) {
setEdges(nextEdges); setEdges(nextEdges);
@@ -73,12 +76,12 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
const changes = const changes =
nextEdges.length === 0 nextEdges.length === 0
? edges.map((edge) => ({ type: 'remove', id: edge.id } as EdgeRemoveChange)) ? edges.map((edge) => ({ type: 'remove', id: edge.id } as EdgeRemoveChange))
: nextEdges.map((edge) => ({ item: edge, type: 'reset' } as EdgeResetChange<EdgeData>)); : nextEdges.map((edge) => ({ item: edge, type: 'reset' } as EdgeResetChange<EdgeType>));
onEdgesChange(changes); onEdgesChange(changes);
} }
}, []); }, []);
const addNodes = useCallback<Instance.AddNodes<NodeData>>((payload) => { const addNodes = useCallback<Instance.AddNodes<NodeType>>((payload) => {
const nodes = Array.isArray(payload) ? payload : [payload]; const nodes = Array.isArray(payload) ? payload : [payload];
const { nodes: currentNodes, hasDefaultNodes, onNodesChange, setNodes } = store.getState(); const { nodes: currentNodes, hasDefaultNodes, onNodesChange, setNodes } = store.getState();
@@ -86,29 +89,29 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
const nextNodes = [...currentNodes, ...nodes]; const nextNodes = [...currentNodes, ...nodes];
setNodes(nextNodes); setNodes(nextNodes);
} else if (onNodesChange) { } else if (onNodesChange) {
const changes = nodes.map((node) => ({ item: node, type: 'add' } as NodeAddChange<NodeData>)); const changes = nodes.map((node) => ({ item: node, type: 'add' } as NodeAddChange<NodeType>));
onNodesChange(changes); onNodesChange(changes);
} }
}, []); }, []);
const addEdges = useCallback<Instance.AddEdges<EdgeData>>((payload) => { const addEdges = useCallback<Instance.AddEdges<EdgeType>>((payload) => {
const nextEdges = Array.isArray(payload) ? payload : [payload]; const nextEdges = Array.isArray(payload) ? payload : [payload];
const { edges = [], setEdges, hasDefaultEdges, onEdgesChange } = store.getState(); const { edges = [], setEdges, hasDefaultEdges, onEdgesChange } = store.getState();
if (hasDefaultEdges) { if (hasDefaultEdges) {
setEdges([...edges, ...nextEdges]); setEdges([...edges, ...nextEdges]);
} else if (onEdgesChange) { } else if (onEdgesChange) {
const changes = nextEdges.map((edge) => ({ item: edge, type: 'add' } as EdgeAddChange<EdgeData>)); const changes = nextEdges.map((edge) => ({ item: edge, type: 'add' } as EdgeAddChange<EdgeType>));
onEdgesChange(changes); onEdgesChange(changes);
} }
}, []); }, []);
const toObject = useCallback<Instance.ToObject<NodeData, EdgeData>>(() => { const toObject = useCallback<Instance.ToObject<NodeType, EdgeType>>(() => {
const { nodes = [], edges = [], transform } = store.getState(); const { nodes = [], edges = [], transform } = store.getState();
const [x, y, zoom] = transform; const [x, y, zoom] = transform;
return { return {
nodes: nodes.map((n) => ({ ...n })), nodes: nodes.map((n) => ({ ...n })) as NodeType[],
edges: edges.map((e) => ({ ...e })), edges: edges.map((e) => ({ ...e })) as EdgeType[],
viewport: { viewport: {
x, x,
y, y,
@@ -180,11 +183,9 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
}, []); }, []);
const getNodeRect = useCallback( const getNodeRect = useCallback(
( (nodeOrRect: NodeType | { id: Node['id'] } | Rect): [Rect | null, NodeType | null | undefined, boolean] => {
nodeOrRect: Node<NodeData> | { id: Node['id'] } | Rect
): [Rect | null, Node<NodeData> | null | undefined, boolean] => {
const isRect = isRectObject(nodeOrRect); const isRect = isRectObject(nodeOrRect);
const node = isRect ? null : store.getState().nodeLookup.get(nodeOrRect.id); const node = isRect ? null : (store.getState().nodeLookup.get(nodeOrRect.id) as NodeType);
if (!isRect && !node) { if (!isRect && !node) {
[null, null, isRect]; [null, null, isRect];
@@ -197,7 +198,7 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
[] []
); );
const getIntersectingNodes = useCallback<Instance.GetIntersectingNodes<NodeData>>( const getIntersectingNodes = useCallback<Instance.GetIntersectingNodes<NodeType>>(
(nodeOrRect, partially = true, nodes) => { (nodeOrRect, partially = true, nodes) => {
const [nodeRect, node, isRect] = getNodeRect(nodeOrRect); const [nodeRect, node, isRect] = getNodeRect(nodeOrRect);
@@ -215,12 +216,12 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
const partiallyVisible = partially && overlappingArea > 0; const partiallyVisible = partially && overlappingArea > 0;
return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height; return partiallyVisible || overlappingArea >= nodeRect.width * nodeRect.height;
}); }) as NodeType[];
}, },
[] []
); );
const isNodeIntersecting = useCallback<Instance.IsNodeIntersecting<NodeData>>( const isNodeIntersecting = useCallback<Instance.IsNodeIntersecting<NodeType>>(
(nodeOrRect, area, partially = true) => { (nodeOrRect, area, partially = true) => {
const [nodeRect] = getNodeRect(nodeOrRect); const [nodeRect] = getNodeRect(nodeOrRect);
+8 -8
View File
@@ -30,13 +30,13 @@ export type NodeRemoveChange = {
type: 'remove'; type: 'remove';
}; };
export type NodeAddChange<NodeData = any> = { export type NodeAddChange<NodeType extends Node = Node> = {
item: Node<NodeData>; item: NodeType;
type: 'add'; type: 'add';
}; };
export type NodeResetChange<NodeData = any> = { export type NodeResetChange<NodeType extends Node = Node> = {
item: Node<NodeData>; item: NodeType;
type: 'reset'; type: 'reset';
}; };
@@ -50,12 +50,12 @@ export type NodeChange =
export type EdgeSelectionChange = NodeSelectionChange; export type EdgeSelectionChange = NodeSelectionChange;
export type EdgeRemoveChange = NodeRemoveChange; export type EdgeRemoveChange = NodeRemoveChange;
export type EdgeAddChange<EdgeData = any> = { export type EdgeAddChange<EdgeType extends Edge = Edge> = {
item: Edge<EdgeData>; item: EdgeType;
type: 'add'; type: 'add';
}; };
export type EdgeResetChange<EdgeData = any> = { export type EdgeResetChange<EdgeType extends Edge = Edge> = {
item: Edge<EdgeData>; item: EdgeType;
type: 'reset'; type: 'reset';
}; };
export type EdgeChange = EdgeSelectionChange | EdgeRemoveChange | EdgeAddChange | EdgeResetChange; export type EdgeChange = EdgeSelectionChange | EdgeRemoveChange | EdgeAddChange | EdgeResetChange;
+33 -1
View File
@@ -1,6 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { CSSProperties, HTMLAttributes, ReactNode, MouseEvent as ReactMouseEvent, ComponentType } from 'react'; import type {
CSSProperties,
HTMLAttributes,
ReactNode,
MouseEvent as ReactMouseEvent,
ComponentType,
MemoExoticComponent,
} from 'react';
import type { import type {
EdgeBase, EdgeBase,
BezierPathOptions, BezierPathOptions,
@@ -119,6 +126,9 @@ export type BaseEdgeProps = EdgeLabelOptions & {
style?: CSSProperties; style?: CSSProperties;
}; };
/**
* Helper type for edge components that get exported by the library.
*/
export type EdgeComponentProps = EdgePosition & export type EdgeComponentProps = EdgePosition &
EdgeLabelOptions & { EdgeLabelOptions & {
id?: EdgeProps['id']; id?: EdgeProps['id'];
@@ -134,10 +144,29 @@ export type EdgeComponentWithPathOptions<PathOptions> = EdgeComponentProps & {
pathOptions?: PathOptions; pathOptions?: PathOptions;
}; };
/**
* BezierEdge component props
*/
export type BezierEdgeProps = EdgeComponentWithPathOptions<BezierPathOptions>; export type BezierEdgeProps = EdgeComponentWithPathOptions<BezierPathOptions>;
/**
* SmoothStepEdge component props
*/
export type SmoothStepEdgeProps = EdgeComponentWithPathOptions<SmoothStepPathOptions>; export type SmoothStepEdgeProps = EdgeComponentWithPathOptions<SmoothStepPathOptions>;
/**
* StepEdge component props
*/
export type StepEdgeProps = EdgeComponentWithPathOptions<StepPathOptions>; export type StepEdgeProps = EdgeComponentWithPathOptions<StepPathOptions>;
/**
* StraightEdge component props
*/
export type StraightEdgeProps = Omit<EdgeComponentProps, 'sourcePosition' | 'targetPosition'>; export type StraightEdgeProps = Omit<EdgeComponentProps, 'sourcePosition' | 'targetPosition'>;
/**
* SimpleBezier component props
*/
export type SimpleBezierEdgeProps = EdgeComponentProps; export type SimpleBezierEdgeProps = EdgeComponentProps;
export type OnEdgeUpdateFunc<T = any> = (oldEdge: Edge<T>, newConnection: Connection) => void; export type OnEdgeUpdateFunc<T = any> = (oldEdge: Edge<T>, newConnection: Connection) => void;
@@ -157,3 +186,6 @@ export type ConnectionLineComponentProps = {
}; };
export type ConnectionLineComponent = ComponentType<ConnectionLineComponentProps>; export type ConnectionLineComponent = ComponentType<ConnectionLineComponentProps>;
export type EdgeTypes = { [key: string]: ComponentType<EdgeProps> };
export type EdgeTypesWrapped = { [key: string]: MemoExoticComponent<ComponentType<WrapEdgeProps>> };
+4 -9
View File
@@ -1,9 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { ComponentType, MemoExoticComponent } from 'react';
import { import {
FitViewParamsBase, FitViewParamsBase,
FitViewOptionsBase, FitViewOptionsBase,
NodeProps,
ZoomInOut, ZoomInOut,
ZoomTo, ZoomTo,
SetViewport, SetViewport,
@@ -14,7 +12,7 @@ import {
XYPosition, XYPosition,
} from '@xyflow/system'; } from '@xyflow/system';
import type { NodeChange, EdgeChange, Node, WrapNodeProps, Edge, EdgeProps, WrapEdgeProps, ReactFlowInstance } from '.'; import type { NodeChange, EdgeChange, Node, Edge, ReactFlowInstance } from '.';
export type OnNodesChange = (changes: NodeChange[]) => void; export type OnNodesChange = (changes: NodeChange[]) => void;
export type OnEdgesChange = (changes: EdgeChange[]) => void; export type OnEdgesChange = (changes: EdgeChange[]) => void;
@@ -23,11 +21,6 @@ export type OnNodesDelete = (nodes: Node[]) => void;
export type OnEdgesDelete = (edges: Edge[]) => void; export type OnEdgesDelete = (edges: Edge[]) => void;
export type OnDelete = (params: { nodes: Node[]; edges: Edge[] }) => void; export type OnDelete = (params: { nodes: Node[]; edges: Edge[] }) => void;
export type NodeTypes = { [key: string]: ComponentType<NodeProps> };
export type NodeTypesWrapped = { [key: string]: MemoExoticComponent<ComponentType<WrapNodeProps>> };
export type EdgeTypes = { [key: string]: ComponentType<EdgeProps> };
export type EdgeTypesWrapped = { [key: string]: MemoExoticComponent<ComponentType<WrapEdgeProps>> };
export type UnselectNodesAndEdgesParams = { export type UnselectNodesAndEdgesParams = {
nodes?: Node[]; nodes?: Node[];
edges?: Edge[]; edges?: Edge[];
@@ -43,7 +36,9 @@ export type OnSelectionChangeFunc = (params: OnSelectionChangeParams) => void;
export type FitViewParams = FitViewParamsBase<Node>; export type FitViewParams = FitViewParamsBase<Node>;
export type FitViewOptions = FitViewOptionsBase<Node>; export type FitViewOptions = FitViewOptionsBase<Node>;
export type FitView = (fitViewOptions?: FitViewOptions) => boolean; export type FitView = (fitViewOptions?: FitViewOptions) => boolean;
export type OnInit<NodeData = any, EdgeData = any> = (reactFlowInstance: ReactFlowInstance<NodeData, EdgeData>) => void; export type OnInit<NodeType extends Node = Node, EdgeType extends Edge = Edge> = (
reactFlowInstance: ReactFlowInstance<NodeType, EdgeType>
) => void;
export type ViewportHelperFunctions = { export type ViewportHelperFunctions = {
zoomIn: ZoomInOut; zoomIn: ZoomInOut;
+35 -32
View File
@@ -3,9 +3,9 @@
import type { Rect, Viewport } from '@xyflow/system'; import type { Rect, Viewport } from '@xyflow/system';
import type { Node, Edge, ViewportHelperFunctions } from '.'; import type { Node, Edge, ViewportHelperFunctions } from '.';
export type ReactFlowJsonObject<NodeData = any, EdgeData = any> = { export type ReactFlowJsonObject<NodeType extends Node = Node, EdgeType extends Edge = Edge> = {
nodes: Node<NodeData>[]; nodes: NodeType[];
edges: Edge<EdgeData>[]; edges: EdgeType[];
viewport: Viewport; viewport: Viewport;
}; };
@@ -15,30 +15,33 @@ export type DeleteElementsOptions = {
}; };
export namespace Instance { export namespace Instance {
export type GetNodes<NodeData> = () => Node<NodeData>[]; export type GetNodes<NodeType extends Node = Node> = () => NodeType[];
export type SetNodes<NodeData> = ( export type SetNodes<NodeType extends Node = Node> = (
payload: Node<NodeData>[] | ((nodes: Node<NodeData>[]) => Node<NodeData>[]) payload: NodeType[] | ((nodes: NodeType[]) => NodeType[])
) => void; ) => void;
export type AddNodes<NodeData> = (payload: Node<NodeData>[] | Node<NodeData>) => void; export type AddNodes<NodeType extends Node = Node> = (payload: NodeType[] | NodeType) => void;
export type GetNode<NodeData> = (id: string) => Node<NodeData> | undefined; export type GetNode<NodeType extends Node = Node> = (id: string) => NodeType | undefined;
export type GetEdges<EdgeData> = () => Edge<EdgeData>[]; export type GetEdges<EdgeType extends Edge = Edge> = () => EdgeType[];
export type SetEdges<EdgeData> = ( export type SetEdges<EdgeType extends Edge = Edge> = (
payload: Edge<EdgeData>[] | ((edges: Edge<EdgeData>[]) => Edge<EdgeData>[]) payload: EdgeType[] | ((edges: EdgeType[]) => EdgeType[])
) => void; ) => void;
export type GetEdge<EdgeData> = (id: string) => Edge<EdgeData> | undefined; export type GetEdge<EdgeType extends Edge = Edge> = (id: string) => EdgeType | undefined;
export type AddEdges<EdgeData> = (payload: Edge<EdgeData>[] | Edge<EdgeData>) => void; export type AddEdges<EdgeType extends Edge = Edge> = (payload: EdgeType[] | EdgeType) => void;
export type ToObject<NodeData = any, EdgeData = any> = () => ReactFlowJsonObject<NodeData, EdgeData>; export type ToObject<NodeType extends Node = Node, EdgeType extends Edge = Edge> = () => ReactFlowJsonObject<
NodeType,
EdgeType
>;
export type DeleteElements = ({ nodes, edges }: DeleteElementsOptions) => { export type DeleteElements = ({ nodes, edges }: DeleteElementsOptions) => {
deletedNodes: Node[]; deletedNodes: Node[];
deletedEdges: Edge[]; deletedEdges: Edge[];
}; };
export type GetIntersectingNodes<NodeData> = ( export type GetIntersectingNodes<NodeType extends Node = Node> = (
node: Node<NodeData> | { id: Node['id'] } | Rect, node: NodeType | { id: Node['id'] } | Rect,
partially?: boolean, partially?: boolean,
nodes?: Node<NodeData>[] nodes?: NodeType[]
) => Node<NodeData>[]; ) => NodeType[];
export type IsNodeIntersecting<NodeData> = ( export type IsNodeIntersecting<NodeType extends Node = Node> = (
node: Node<NodeData> | { id: Node['id'] } | Rect, node: NodeType | { id: Node['id'] } | Rect,
area: Rect, area: Rect,
partially?: boolean partially?: boolean
) => boolean; ) => boolean;
@@ -47,18 +50,18 @@ export namespace Instance {
export type getOutgoers = (node: string | Node | { id: Node['id'] }) => Node[]; export type getOutgoers = (node: string | Node | { id: Node['id'] }) => Node[];
} }
export type ReactFlowInstance<NodeData = any, EdgeData = any> = { export type ReactFlowInstance<NodeType extends Node = Node, EdgeType extends Edge = Edge> = {
getNodes: Instance.GetNodes<NodeData>; getNodes: Instance.GetNodes<NodeType>;
setNodes: Instance.SetNodes<NodeData>; setNodes: Instance.SetNodes<NodeType>;
addNodes: Instance.AddNodes<NodeData>; addNodes: Instance.AddNodes<NodeType>;
getNode: Instance.GetNode<NodeData>; getNode: Instance.GetNode<NodeType>;
getEdges: Instance.GetEdges<EdgeData>; getEdges: Instance.GetEdges<EdgeType>;
setEdges: Instance.SetEdges<EdgeData>; setEdges: Instance.SetEdges<EdgeType>;
addEdges: Instance.AddEdges<EdgeData>; addEdges: Instance.AddEdges<EdgeType>;
getEdge: Instance.GetEdge<EdgeData>; getEdge: Instance.GetEdge<EdgeType>;
toObject: Instance.ToObject<NodeData, EdgeData>; toObject: Instance.ToObject<NodeType, EdgeType>;
deleteElements: Instance.DeleteElements; deleteElements: Instance.DeleteElements;
getIntersectingNodes: Instance.GetIntersectingNodes<NodeData>; getIntersectingNodes: Instance.GetIntersectingNodes<NodeType>;
isNodeIntersecting: Instance.IsNodeIntersecting<NodeData>; isNodeIntersecting: Instance.IsNodeIntersecting<NodeType>;
viewportInitialized: boolean; viewportInitialized: boolean;
} & Omit<ViewportHelperFunctions, 'initialized'>; } & Omit<ViewportHelperFunctions, 'initialized'>;
+8 -13
View File
@@ -1,5 +1,6 @@
import type { CSSProperties, MouseEvent as ReactMouseEvent } from 'react'; /* eslint-disable @typescript-eslint/no-explicit-any */
import type { NodeBase, XYPosition } from '@xyflow/system'; import type { CSSProperties, ComponentType, MemoExoticComponent, MouseEvent as ReactMouseEvent } from 'react';
import type { NodeBase, NodeProps, XYPosition } from '@xyflow/system';
/** /**
* The node data structure that gets used for the nodes prop. * The node data structure that gets used for the nodes prop.
@@ -9,17 +10,8 @@ export type Node<NodeData = any, NodeType extends string | undefined = string |
NodeData, NodeData,
NodeType NodeType
> & { > & {
/**
* Inline style object
*/
style?: CSSProperties; style?: CSSProperties;
/**
* Inline style object
*/
className?: string; className?: string;
/**
* Inline style object
*/
resizing?: boolean; resizing?: boolean;
}; };
@@ -27,8 +19,8 @@ export type NodeMouseHandler = (event: ReactMouseEvent, node: Node) => void;
export type NodeDragHandler = (event: ReactMouseEvent, node: Node, nodes: Node[]) => void; export type NodeDragHandler = (event: ReactMouseEvent, node: Node, nodes: Node[]) => void;
export type SelectionDragHandler = (event: ReactMouseEvent, nodes: Node[]) => void; export type SelectionDragHandler = (event: ReactMouseEvent, nodes: Node[]) => void;
export type WrapNodeProps<NodeData = any> = Pick< export type WrapNodeProps<NodeType extends Node = Node> = Pick<
Node<NodeData>, NodeType,
'id' | 'data' | 'style' | 'className' | 'dragHandle' | 'sourcePosition' | 'targetPosition' | 'hidden' | 'ariaLabel' 'id' | 'data' | 'style' | 'className' | 'dragHandle' | 'sourcePosition' | 'targetPosition' | 'hidden' | 'ariaLabel'
> & { > & {
type: string; type: string;
@@ -59,3 +51,6 @@ export type WrapNodeProps<NodeData = any> = Pick<
width?: number; width?: number;
height?: number; height?: number;
}; };
export type NodeTypes = { [key: string]: ComponentType<NodeProps> };
export type NodeTypesWrapped = { [key: string]: MemoExoticComponent<ComponentType<WrapNodeProps>> };
+4 -4
View File
@@ -159,8 +159,8 @@ function applyChanges(changes: any[], elements: any[]): any[] {
<ReactFLow nodes={nodes} edges={edges} onNodesChange={onNodesChange} /> <ReactFLow nodes={nodes} edges={edges} onNodesChange={onNodesChange} />
); );
*/ */
export function applyNodeChanges<NodeData = any>(changes: NodeChange[], nodes: Node<NodeData>[]): Node<NodeData>[] { export function applyNodeChanges<NodeType extends Node = Node>(changes: NodeChange[], nodes: NodeType[]): NodeType[] {
return applyChanges(changes, nodes) as Node<NodeData>[]; return applyChanges(changes, nodes) as NodeType[];
} }
/** /**
@@ -183,8 +183,8 @@ export function applyNodeChanges<NodeData = any>(changes: NodeChange[], nodes: N
<ReactFLow nodes={nodes} edges={edges} onEdgesChange={onEdgesChange} /> <ReactFLow nodes={nodes} edges={edges} onEdgesChange={onEdgesChange} />
); );
*/ */
export function applyEdgeChanges<EdgeData = any>(changes: EdgeChange[], edges: Edge<EdgeData>[]): Edge<EdgeData>[] { export function applyEdgeChanges<EdgeType extends Edge = Edge>(changes: EdgeChange[], edges: EdgeType[]): EdgeType[] {
return applyChanges(changes, edges) as Edge<EdgeData>[]; return applyChanges(changes, edges) as EdgeType[];
} }
export const createSelectionChange = (id: string, selected: boolean) => ({ export const createSelectionChange = (id: string, selected: boolean) => ({
+18
View File
@@ -53,6 +53,9 @@ export type EdgeProps<T = any> = Omit<Edge<T>, 'sourceHandle' | 'targetHandle' |
targetHandleId?: string | null; targetHandleId?: string | null;
}; };
/**
* Helper type for edge components that get exported by the library.
*/
export type EdgeComponentProps = EdgePosition & { export type EdgeComponentProps = EdgePosition & {
id?: EdgeProps['id']; id?: EdgeProps['id'];
hidden?: EdgeProps['hidden']; hidden?: EdgeProps['hidden'];
@@ -73,9 +76,24 @@ export type EdgeComponentWithPathOptions<PathOptions> = EdgeComponentProps & {
pathOptions?: PathOptions; pathOptions?: PathOptions;
}; };
/**
* BezierEdge component props
*/
export type BezierEdgeProps = EdgeComponentWithPathOptions<BezierPathOptions>; export type BezierEdgeProps = EdgeComponentWithPathOptions<BezierPathOptions>;
/**
* SmoothStepEdge component props
*/
export type SmoothStepEdgeProps = EdgeComponentWithPathOptions<SmoothStepPathOptions>; export type SmoothStepEdgeProps = EdgeComponentWithPathOptions<SmoothStepPathOptions>;
/**
* StepEdge component props
*/
export type StepEdgeProps = EdgeComponentWithPathOptions<StepPathOptions>; export type StepEdgeProps = EdgeComponentWithPathOptions<StepPathOptions>;
/**
* StraightEdge component props
*/
export type StraightEdgeProps = Omit<EdgeComponentProps, 'sourcePosition' | 'targetPosition'>; export type StraightEdgeProps = Omit<EdgeComponentProps, 'sourcePosition' | 'targetPosition'>;
export type EdgeTypes = Record<string, ComponentType<SvelteComponent<EdgeProps>>>; export type EdgeTypes = Record<string, ComponentType<SvelteComponent<EdgeProps>>>;
+4 -4
View File
@@ -1,11 +1,11 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import type { ComponentType, SvelteComponent } from 'svelte'; import type { ComponentType, SvelteComponent } from 'svelte';
import type { NodeBase, NodeProps } from '@xyflow/system'; import type { NodeBase, NodeProps } from '@xyflow/system';
// @todo: currently the helper function only like Node from '@reactflow/core' /**
// we need a base node type or helpes that accept Node like types * The node data structure that gets used for the nodes prop.
// eslint-disable-next-line @typescript-eslint/no-explicit-any * @public
*/
export type Node< export type Node<
NodeData = any, NodeData = any,
NodeType extends string | undefined = string | undefined NodeType extends string | undefined = string | undefined