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
+2 -2
View File
@@ -5,8 +5,8 @@ import type { Node, ReactFlowState } from '../types';
const nodesSelector = (state: ReactFlowState) => state.nodes;
function useNodes<NodeData>(): Node<NodeData>[] {
const nodes = useStore(nodesSelector, shallow);
function useNodes<NodeType extends Node = Node>(): NodeType[] {
const nodes = useStore(nodesSelector, shallow) as NodeType[];
return nodes;
}
@@ -11,14 +11,14 @@ type OnChange<ChangesType> = (changes: ChangesType[]) => void;
// const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
function createUseItemsState(
applyChanges: ApplyChanges<Node, NodeChange>
): <NodeData = any>(
initialItems: Node<NodeData>[]
) => [Node<NodeData>[], Dispatch<SetStateAction<Node<NodeData>[]>>, OnChange<NodeChange>];
): <NodeType extends Node = Node>(
initialItems: NodeType[]
) => [NodeType[], Dispatch<SetStateAction<NodeType[]>>, OnChange<NodeChange>];
function createUseItemsState(
applyChanges: ApplyChanges<Edge, EdgeChange>
): <EdgeData = any>(
initialItems: Edge<EdgeData>[]
) => [Edge<EdgeData>[], Dispatch<SetStateAction<Edge<EdgeData>[]>>, OnChange<EdgeChange>];
): <EdgeType extends Edge = Edge>(
initialItems: EdgeType[]
) => [EdgeType[], Dispatch<SetStateAction<EdgeType[]>>, OnChange<EdgeChange>];
function createUseItemsState(
applyChanges: ApplyChanges<any, any>
): (initialItems: any[]) => [any[], Dispatch<SetStateAction<any[]>>, OnChange<any>] {
+30 -29
View File
@@ -26,31 +26,34 @@ import type {
} from '../types';
/* 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 store = useStoreApi();
const getNodes = useCallback<Instance.GetNodes<NodeData>>(() => {
return store.getState().nodes.map((n) => ({ ...n }));
const getNodes = useCallback<Instance.GetNodes<NodeType>>(() => {
return store.getState().nodes.map((n) => ({ ...n })) as NodeType[];
}, []);
const getNode = useCallback<Instance.GetNode<NodeData>>((id) => {
return store.getState().nodeLookup.get(id);
const getNode = useCallback<Instance.GetNode<NodeType>>((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();
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();
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 nextNodes = typeof payload === 'function' ? payload(nodes) : payload;
const nextNodes = typeof payload === 'function' ? payload(nodes as NodeType[]) : payload;
if (hasDefaultNodes) {
setNodes(nextNodes);
@@ -58,14 +61,14 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
const changes =
nextNodes.length === 0
? 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);
}
}, []);
const setEdges = useCallback<Instance.SetEdges<EdgeData>>((payload) => {
const setEdges = useCallback<Instance.SetEdges<EdgeType>>((payload) => {
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) {
setEdges(nextEdges);
@@ -73,12 +76,12 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
const changes =
nextEdges.length === 0
? 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);
}
}, []);
const addNodes = useCallback<Instance.AddNodes<NodeData>>((payload) => {
const addNodes = useCallback<Instance.AddNodes<NodeType>>((payload) => {
const nodes = Array.isArray(payload) ? payload : [payload];
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];
setNodes(nextNodes);
} 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);
}
}, []);
const addEdges = useCallback<Instance.AddEdges<EdgeData>>((payload) => {
const addEdges = useCallback<Instance.AddEdges<EdgeType>>((payload) => {
const nextEdges = Array.isArray(payload) ? payload : [payload];
const { edges = [], setEdges, hasDefaultEdges, onEdgesChange } = store.getState();
if (hasDefaultEdges) {
setEdges([...edges, ...nextEdges]);
} 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);
}
}, []);
const toObject = useCallback<Instance.ToObject<NodeData, EdgeData>>(() => {
const toObject = useCallback<Instance.ToObject<NodeType, EdgeType>>(() => {
const { nodes = [], edges = [], transform } = store.getState();
const [x, y, zoom] = transform;
return {
nodes: nodes.map((n) => ({ ...n })),
edges: edges.map((e) => ({ ...e })),
nodes: nodes.map((n) => ({ ...n })) as NodeType[],
edges: edges.map((e) => ({ ...e })) as EdgeType[],
viewport: {
x,
y,
@@ -180,11 +183,9 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
}, []);
const getNodeRect = useCallback(
(
nodeOrRect: Node<NodeData> | { id: Node['id'] } | Rect
): [Rect | null, Node<NodeData> | null | undefined, boolean] => {
(nodeOrRect: NodeType | { id: Node['id'] } | Rect): [Rect | null, NodeType | null | undefined, boolean] => {
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) {
[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) => {
const [nodeRect, node, isRect] = getNodeRect(nodeOrRect);
@@ -215,12 +216,12 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
const partiallyVisible = partially && overlappingArea > 0;
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) => {
const [nodeRect] = getNodeRect(nodeOrRect);