From a345b2670bcbe66d12f45f7a0bc2704a01b3f696 Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 24 Jan 2024 18:25:31 +0100 Subject: [PATCH] feat(react): infer node types from passed nodes --- .../react/src/examples/CustomNode/index.tsx | 2 +- .../react/src/examples/UseNodesData/index.tsx | 2 +- .../src/components/NodeWrapper/index.tsx | 8 +- .../src/components/NodesSelection/index.tsx | 12 +- .../src/components/StoreUpdater/index.tsx | 8 +- .../src/container/FlowRenderer/index.tsx | 14 +- .../react/src/container/GraphView/index.tsx | 18 +- .../src/container/NodeRenderer/index.tsx | 14 +- .../react/src/container/ReactFlow/index.tsx | 540 +++++++++--------- .../react/src/hooks/useNodesEdgesState.ts | 16 +- packages/react/src/hooks/useOnInitHandler.ts | 6 +- packages/react/src/hooks/useStore.ts | 4 +- packages/react/src/types/component-props.ts | 34 +- packages/react/src/types/nodes.ts | 14 +- packages/react/src/types/store.ts | 26 +- 15 files changed, 364 insertions(+), 354 deletions(-) diff --git a/examples/react/src/examples/CustomNode/index.tsx b/examples/react/src/examples/CustomNode/index.tsx index a8c0f55d..772d4ddd 100644 --- a/examples/react/src/examples/CustomNode/index.tsx +++ b/examples/react/src/examples/CustomNode/index.tsx @@ -44,7 +44,7 @@ const nodeTypes = { const CustomNodeFlow = () => { const [nodes, setNodes] = useState([]); - const onNodesChange: OnNodesChange = useCallback( + const onNodesChange: OnNodesChange = useCallback( (changes) => setNodes((nds) => { const nextNodes = applyNodeChanges(changes, nds); diff --git a/examples/react/src/examples/UseNodesData/index.tsx b/examples/react/src/examples/UseNodesData/index.tsx index d6b697a9..b9bc68f1 100644 --- a/examples/react/src/examples/UseNodesData/index.tsx +++ b/examples/react/src/examples/UseNodesData/index.tsx @@ -18,7 +18,7 @@ import UppercaseNode from './UppercaseNode'; export type TextNode = Node<{ text: string }, 'text'>; export type ResultNode = Node<{}, 'result'>; export type UppercaseNode = Node<{}, 'uppercase'>; -export type MyNode = Node<{ text: string }, 'text'> | Node<{}, 'result'> | Node<{}, 'uppercase'>; +export type MyNode = TextNode | ResultNode | UppercaseNode; const nodeTypes = { text: TextNode, diff --git a/packages/react/src/components/NodeWrapper/index.tsx b/packages/react/src/components/NodeWrapper/index.tsx index 1e796de1..017dd0f9 100644 --- a/packages/react/src/components/NodeWrapper/index.tsx +++ b/packages/react/src/components/NodeWrapper/index.tsx @@ -17,9 +17,9 @@ import { useDrag } from '../../hooks/useDrag'; import { useUpdateNodePositions } from '../../hooks/useUpdateNodePositions'; import { handleNodeClick } from '../Nodes/utils'; import { arrowKeyDiffs, builtinNodeTypes } from './utils'; -import type { NodeWrapperProps } from '../../types'; +import type { Node, NodeWrapperProps } from '../../types'; -export function NodeWrapper({ +export function NodeWrapper({ id, onClick, onMouseEnter, @@ -40,9 +40,9 @@ export function NodeWrapper({ nodeExtent, nodeOrigin, onError, -}: NodeWrapperProps) { +}: NodeWrapperProps) { const { node, positionAbsoluteX, positionAbsoluteY, zIndex, isParent } = useStore((s) => { - const node = s.nodeLookup.get(id)!; + const node = s.nodeLookup.get(id)! as NodeType; const positionAbsolute = nodeExtent ? clampPosition(node.computed?.positionAbsolute, nodeExtent) diff --git a/packages/react/src/components/NodesSelection/index.tsx b/packages/react/src/components/NodesSelection/index.tsx index f8aeb77c..8ba01979 100644 --- a/packages/react/src/components/NodesSelection/index.tsx +++ b/packages/react/src/components/NodesSelection/index.tsx @@ -14,8 +14,8 @@ import { useUpdateNodePositions } from '../../hooks/useUpdateNodePositions'; import { arrowKeyDiffs } from '../NodeWrapper/utils'; import type { Node, ReactFlowState } from '../../types'; -export type NodesSelectionProps = { - onSelectionContextMenu?: (event: MouseEvent, nodes: Node[]) => void; +export type NodesSelectionProps = { + onSelectionContextMenu?: (event: MouseEvent, nodes: NodeType[]) => void; noPanClassName?: string; disableKeyboardA11y: boolean; }; @@ -32,7 +32,11 @@ const selector = (s: ReactFlowState) => { }; }; -export function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboardA11y }: NodesSelectionProps) { +export function NodesSelection({ + onSelectionContextMenu, + noPanClassName, + disableKeyboardA11y, +}: NodesSelectionProps) { const store = useStoreApi(); const { width, height, transformString, userSelectionActive } = useStore(selector, shallow); const updatePositions = useUpdateNodePositions(); @@ -58,7 +62,7 @@ export function NodesSelection({ onSelectionContextMenu, noPanClassName, disable const onContextMenu = onSelectionContextMenu ? (event: MouseEvent) => { const selectedNodes = store.getState().nodes.filter((n) => n.selected); - onSelectionContextMenu(event, selectedNodes); + onSelectionContextMenu(event, selectedNodes as NodeType[]); } : undefined; diff --git a/packages/react/src/components/StoreUpdater/index.tsx b/packages/react/src/components/StoreUpdater/index.tsx index 3a12594c..6211ea59 100644 --- a/packages/react/src/components/StoreUpdater/index.tsx +++ b/packages/react/src/components/StoreUpdater/index.tsx @@ -68,7 +68,9 @@ const reactFlowFieldsToTrack = [ ] as const; type ReactFlowFieldsToTrack = (typeof reactFlowFieldsToTrack)[number]; -type StoreUpdaterProps = Pick & { rfId: string }; +type StoreUpdaterProps = Pick, ReactFlowFieldsToTrack> & { + rfId: string; +}; // rfId doesn't exist in ReactFlowProps, but it's one of the fields we want to update const fieldsToTrack = [...reactFlowFieldsToTrack, 'rfId'] as const; @@ -84,7 +86,7 @@ const selector = (s: ReactFlowState) => ({ reset: s.reset, }); -export function StoreUpdater(props: StoreUpdaterProps) { +export function StoreUpdater(props: StoreUpdaterProps) { const { setNodes, setEdges, @@ -106,7 +108,7 @@ export function StoreUpdater(props: StoreUpdaterProps) { }; }, []); - const previousFields = useRef>({ + const previousFields = useRef>>({ // these are values that are also passed directly to other components // than the StoreUpdater. We can reduce the number of setStore calls // by setting the same values here as prev fields. diff --git a/packages/react/src/container/FlowRenderer/index.tsx b/packages/react/src/container/FlowRenderer/index.tsx index 2670be70..6aa49a2a 100644 --- a/packages/react/src/container/FlowRenderer/index.tsx +++ b/packages/react/src/container/FlowRenderer/index.tsx @@ -7,10 +7,10 @@ import { GraphViewProps } from '../GraphView'; import { ZoomPane } from '../ZoomPane'; import { Pane } from '../Pane'; import { NodesSelection } from '../../components/NodesSelection'; -import type { ReactFlowState } from '../../types'; +import type { ReactFlowState, Node } from '../../types'; -export type FlowRendererProps = Omit< - GraphViewProps, +export type FlowRendererProps = Omit< + GraphViewProps, | 'snapToGrid' | 'nodeTypes' | 'edgeTypes' @@ -32,7 +32,7 @@ const selector = (s: ReactFlowState) => { return { nodesSelectionActive: s.nodesSelectionActive, userSelectionActive: s.userSelectionActive }; }; -const FlowRendererComponent = ({ +function FlowRendererComponent({ children, onPaneClick, onPaneMouseEnter, @@ -68,7 +68,7 @@ const FlowRendererComponent = ({ disableKeyboardA11y, onViewportChange, isControlledViewport, -}: FlowRendererProps) => { +}: FlowRendererProps) { const { nodesSelectionActive, userSelectionActive } = useStore(selector); const selectionKeyPressed = useKeyPress(selectionKeyCode); const panActivationKeyPressed = useKeyPress(panActivationKeyCode); @@ -125,8 +125,8 @@ const FlowRendererComponent = ({ ); -}; +} FlowRendererComponent.displayName = 'FlowRenderer'; -export const FlowRenderer = memo(FlowRendererComponent); +export const FlowRenderer = memo(FlowRendererComponent) as typeof FlowRendererComponent; diff --git a/packages/react/src/container/GraphView/index.tsx b/packages/react/src/container/GraphView/index.tsx index fd7ac277..0615258c 100644 --- a/packages/react/src/container/GraphView/index.tsx +++ b/packages/react/src/container/GraphView/index.tsx @@ -8,15 +8,15 @@ import { useOnInitHandler } from '../../hooks/useOnInitHandler'; import { useViewportSync } from '../../hooks/useViewportSync'; import { ConnectionLineWrapper } from '../../components/ConnectionLine'; import { useNodeOrEdgeTypesWarning } from './useNodeOrEdgeTypesWarning'; -import type { ReactFlowProps } from '../../types'; +import type { Node, ReactFlowProps } from '../../types'; -export type GraphViewProps = Omit< - ReactFlowProps, +export type GraphViewProps = Omit< + ReactFlowProps, 'onSelectionChange' | 'nodes' | 'edges' | 'onMove' | 'onMoveStart' | 'onMoveEnd' | 'elevateEdgesOnSelect' > & Required< Pick< - ReactFlowProps, + ReactFlowProps, | 'selectionKeyCode' | 'deleteKeyCode' | 'multiSelectionKeyCode' @@ -38,7 +38,7 @@ export type GraphViewProps = Omit< rfId: string; }; -function GraphViewComponent({ +function GraphViewComponent({ nodeTypes, edgeTypes, onInit, @@ -102,7 +102,7 @@ function GraphViewComponent({ rfId, viewport, onViewportChange, -}: GraphViewProps) { +}: GraphViewProps) { useNodeOrEdgeTypesWarning(nodeTypes); useNodeOrEdgeTypesWarning(edgeTypes); @@ -110,7 +110,7 @@ function GraphViewComponent({ useViewportSync(viewport); return ( - onPaneClick={onPaneClick} onPaneMouseEnter={onPaneMouseEnter} onPaneMouseMove={onPaneMouseMove} @@ -174,7 +174,7 @@ function GraphViewComponent({ />
- nodeTypes={nodeTypes} onNodeClick={onNodeClick} onNodeDoubleClick={onNodeDoubleClick} @@ -197,4 +197,4 @@ function GraphViewComponent({ GraphViewComponent.displayName = 'GraphView'; -export const GraphView = memo(GraphViewComponent); +export const GraphView = memo(GraphViewComponent) as typeof GraphViewComponent; diff --git a/packages/react/src/container/NodeRenderer/index.tsx b/packages/react/src/container/NodeRenderer/index.tsx index 11cab66f..39b20323 100644 --- a/packages/react/src/container/NodeRenderer/index.tsx +++ b/packages/react/src/container/NodeRenderer/index.tsx @@ -7,10 +7,10 @@ import { containerStyle } from '../../styles/utils'; import { GraphViewProps } from '../GraphView'; import { useResizeObserver } from './useResizeObserver'; import { NodeWrapper } from '../../components/NodeWrapper'; -import type { ReactFlowState } from '../../types'; +import type { Node, ReactFlowState } from '../../types'; -export type NodeRendererProps = Pick< - GraphViewProps, +export type NodeRendererProps = Pick< + GraphViewProps, | 'onNodeClick' | 'onNodeDoubleClick' | 'onNodeMouseEnter' @@ -35,7 +35,7 @@ const selector = (s: ReactFlowState) => ({ onError: s.onError, }); -const NodeRendererComponent = (props: NodeRendererProps) => { +function NodeRendererComponent(props: NodeRendererProps) { const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, onError } = useStore(selector, shallow); const nodeIds = useVisibleNodeIds(props.onlyRenderVisibleElements); const resizeObserver = useResizeObserver(); @@ -67,7 +67,7 @@ const NodeRendererComponent = (props: NodeRendererProps) => { // moved into `NodeComponentWrapper`. This ensures they are // memorized – so if `NodeRenderer` *has* to rerender, it only // needs to regenerate the list of nodes, nothing else. - key={nodeId} id={nodeId} nodeTypes={props.nodeTypes} @@ -94,8 +94,8 @@ const NodeRendererComponent = (props: NodeRendererProps) => { })}
); -}; +} NodeRendererComponent.displayName = 'NodeRenderer'; -export const NodeRenderer = memo(NodeRendererComponent); +export const NodeRenderer = memo(NodeRendererComponent) as typeof NodeRendererComponent; diff --git a/packages/react/src/container/ReactFlow/index.tsx b/packages/react/src/container/ReactFlow/index.tsx index d64af5ec..2516b4e7 100644 --- a/packages/react/src/container/ReactFlow/index.tsx +++ b/packages/react/src/container/ReactFlow/index.tsx @@ -1,4 +1,4 @@ -import { forwardRef, type CSSProperties } from 'react'; +import { ForwardedRef, forwardRef, type CSSProperties } from 'react'; import cc from 'classcat'; import { ConnectionLineType, @@ -17,7 +17,7 @@ import { StoreUpdater } from '../../components/StoreUpdater'; import { useColorModeClass } from '../../hooks/useColorModeClass'; import { GraphView } from '../GraphView'; import { Wrapper } from './Wrapper'; -import type { ReactFlowProps, ReactFlowRefType } from '../../types'; +import type { ReactFlowProps, ReactFlowRefType, Node } from '../../types'; export const initNodeOrigin: NodeOrigin = [0, 0]; const initDefaultViewport: Viewport = { x: 0, y: 0, zoom: 1 }; @@ -30,272 +30,276 @@ const wrapperStyle: CSSProperties = { zIndex: 0, }; -const ReactFlow = forwardRef( - ( - { - nodes, - edges, - defaultNodes, - defaultEdges, - className, - nodeTypes, - edgeTypes, - onNodeClick, - onEdgeClick, - onInit, - onMove, - onMoveStart, - onMoveEnd, - onConnect, - onConnectStart, - onConnectEnd, - onClickConnectStart, - onClickConnectEnd, - onNodeMouseEnter, - onNodeMouseMove, - onNodeMouseLeave, - onNodeContextMenu, - onNodeDoubleClick, - onNodeDragStart, - onNodeDrag, - onNodeDragStop, - onNodesDelete, - onEdgesDelete, - onDelete, - onSelectionChange, - onSelectionDragStart, - onSelectionDrag, - onSelectionDragStop, - onSelectionContextMenu, - onSelectionStart, - onSelectionEnd, - onBeforeDelete, - connectionMode, - connectionLineType = ConnectionLineType.Bezier, - connectionLineStyle, - connectionLineComponent, - connectionLineContainerStyle, - deleteKeyCode = 'Backspace', - selectionKeyCode = 'Shift', - selectionOnDrag = false, - selectionMode = SelectionMode.Full, - panActivationKeyCode = 'Space', - multiSelectionKeyCode = isMacOs() ? 'Meta' : 'Control', - zoomActivationKeyCode = isMacOs() ? 'Meta' : 'Control', - snapToGrid, - snapGrid, - onlyRenderVisibleElements = false, - selectNodesOnDrag, - nodesDraggable, - nodesConnectable, - nodesFocusable, - nodeOrigin = initNodeOrigin, - edgesFocusable, - edgesUpdatable, - elementsSelectable = true, - defaultViewport = initDefaultViewport, - minZoom = 0.5, - maxZoom = 2, - translateExtent = infiniteExtent, - preventScrolling = true, - nodeExtent, - defaultMarkerColor = '#b1b1b7', - zoomOnScroll = true, - zoomOnPinch = true, - panOnScroll = false, - panOnScrollSpeed = 0.5, - panOnScrollMode = PanOnScrollMode.Free, - zoomOnDoubleClick = true, - panOnDrag = true, - onPaneClick, - onPaneMouseEnter, - onPaneMouseMove, - onPaneMouseLeave, - onPaneScroll, - onPaneContextMenu, - children, - onEdgeUpdate, - onEdgeContextMenu, - onEdgeDoubleClick, - onEdgeMouseEnter, - onEdgeMouseMove, - onEdgeMouseLeave, - onEdgeUpdateStart, - onEdgeUpdateEnd, - edgeUpdaterRadius = 10, - onNodesChange, - onEdgesChange, - noDragClassName = 'nodrag', - noWheelClassName = 'nowheel', - noPanClassName = 'nopan', - fitView, - fitViewOptions, - connectOnClick, - attributionPosition, - proOptions, - defaultEdgeOptions, - elevateNodesOnSelect, - elevateEdgesOnSelect, - disableKeyboardA11y = false, - autoPanOnConnect, - autoPanOnNodeDrag, - connectionRadius, - isValidConnection, - onError, - style, - id, - nodeDragThreshold, - viewport, - onViewportChange, - width, - height, - colorMode = 'light', - ...rest - }, - ref - ) => { - const rfId = id || '1'; - const colorModeClassName = useColorModeClass(colorMode); +declare module 'react' { + function forwardRef>( + render: (props: P, ref: React.Ref) => React.ReactNode | null + ): (props: P & React.RefAttributes) => React.ReactNode | null; +} - return ( -
- - - - - {children} - - - -
- ); - } -); +function ReactFlow( + { + nodes, + edges, + defaultNodes, + defaultEdges, + className, + nodeTypes, + edgeTypes, + onNodeClick, + onEdgeClick, + onInit, + onMove, + onMoveStart, + onMoveEnd, + onConnect, + onConnectStart, + onConnectEnd, + onClickConnectStart, + onClickConnectEnd, + onNodeMouseEnter, + onNodeMouseMove, + onNodeMouseLeave, + onNodeContextMenu, + onNodeDoubleClick, + onNodeDragStart, + onNodeDrag, + onNodeDragStop, + onNodesDelete, + onEdgesDelete, + onDelete, + onSelectionChange, + onSelectionDragStart, + onSelectionDrag, + onSelectionDragStop, + onSelectionContextMenu, + onSelectionStart, + onSelectionEnd, + onBeforeDelete, + connectionMode, + connectionLineType = ConnectionLineType.Bezier, + connectionLineStyle, + connectionLineComponent, + connectionLineContainerStyle, + deleteKeyCode = 'Backspace', + selectionKeyCode = 'Shift', + selectionOnDrag = false, + selectionMode = SelectionMode.Full, + panActivationKeyCode = 'Space', + multiSelectionKeyCode = isMacOs() ? 'Meta' : 'Control', + zoomActivationKeyCode = isMacOs() ? 'Meta' : 'Control', + snapToGrid, + snapGrid, + onlyRenderVisibleElements = false, + selectNodesOnDrag, + nodesDraggable, + nodesConnectable, + nodesFocusable, + nodeOrigin = initNodeOrigin, + edgesFocusable, + edgesUpdatable, + elementsSelectable = true, + defaultViewport = initDefaultViewport, + minZoom = 0.5, + maxZoom = 2, + translateExtent = infiniteExtent, + preventScrolling = true, + nodeExtent, + defaultMarkerColor = '#b1b1b7', + zoomOnScroll = true, + zoomOnPinch = true, + panOnScroll = false, + panOnScrollSpeed = 0.5, + panOnScrollMode = PanOnScrollMode.Free, + zoomOnDoubleClick = true, + panOnDrag = true, + onPaneClick, + onPaneMouseEnter, + onPaneMouseMove, + onPaneMouseLeave, + onPaneScroll, + onPaneContextMenu, + children, + onEdgeUpdate, + onEdgeContextMenu, + onEdgeDoubleClick, + onEdgeMouseEnter, + onEdgeMouseMove, + onEdgeMouseLeave, + onEdgeUpdateStart, + onEdgeUpdateEnd, + edgeUpdaterRadius = 10, + onNodesChange, + onEdgesChange, + noDragClassName = 'nodrag', + noWheelClassName = 'nowheel', + noPanClassName = 'nopan', + fitView, + fitViewOptions, + connectOnClick, + attributionPosition, + proOptions, + defaultEdgeOptions, + elevateNodesOnSelect, + elevateEdgesOnSelect, + disableKeyboardA11y = false, + autoPanOnConnect, + autoPanOnNodeDrag, + connectionRadius, + isValidConnection, + onError, + style, + id, + nodeDragThreshold, + viewport, + onViewportChange, + width, + height, + colorMode = 'light', + ...rest + }: ReactFlowProps, + ref: ForwardedRef +) { + const rfId = id || '1'; + const colorModeClassName = useColorModeClass(colorMode); -ReactFlow.displayName = 'ReactFlow'; + return ( +
+ + + onInit={onInit} + onNodeClick={onNodeClick} + onEdgeClick={onEdgeClick} + onNodeMouseEnter={onNodeMouseEnter} + onNodeMouseMove={onNodeMouseMove} + onNodeMouseLeave={onNodeMouseLeave} + onNodeContextMenu={onNodeContextMenu} + onNodeDoubleClick={onNodeDoubleClick} + nodeTypes={nodeTypes} + edgeTypes={edgeTypes} + connectionLineType={connectionLineType} + connectionLineStyle={connectionLineStyle} + connectionLineComponent={connectionLineComponent} + connectionLineContainerStyle={connectionLineContainerStyle} + selectionKeyCode={selectionKeyCode} + selectionOnDrag={selectionOnDrag} + selectionMode={selectionMode} + deleteKeyCode={deleteKeyCode} + multiSelectionKeyCode={multiSelectionKeyCode} + panActivationKeyCode={panActivationKeyCode} + zoomActivationKeyCode={zoomActivationKeyCode} + onlyRenderVisibleElements={onlyRenderVisibleElements} + defaultViewport={defaultViewport} + translateExtent={translateExtent} + minZoom={minZoom} + maxZoom={maxZoom} + preventScrolling={preventScrolling} + zoomOnScroll={zoomOnScroll} + zoomOnPinch={zoomOnPinch} + zoomOnDoubleClick={zoomOnDoubleClick} + panOnScroll={panOnScroll} + panOnScrollSpeed={panOnScrollSpeed} + panOnScrollMode={panOnScrollMode} + panOnDrag={panOnDrag} + onPaneClick={onPaneClick} + onPaneMouseEnter={onPaneMouseEnter} + onPaneMouseMove={onPaneMouseMove} + onPaneMouseLeave={onPaneMouseLeave} + onPaneScroll={onPaneScroll} + onPaneContextMenu={onPaneContextMenu} + onSelectionContextMenu={onSelectionContextMenu} + onSelectionStart={onSelectionStart} + onSelectionEnd={onSelectionEnd} + onEdgeUpdate={onEdgeUpdate} + onEdgeContextMenu={onEdgeContextMenu} + onEdgeDoubleClick={onEdgeDoubleClick} + onEdgeMouseEnter={onEdgeMouseEnter} + onEdgeMouseMove={onEdgeMouseMove} + onEdgeMouseLeave={onEdgeMouseLeave} + onEdgeUpdateStart={onEdgeUpdateStart} + onEdgeUpdateEnd={onEdgeUpdateEnd} + edgeUpdaterRadius={edgeUpdaterRadius} + defaultMarkerColor={defaultMarkerColor} + noDragClassName={noDragClassName} + noWheelClassName={noWheelClassName} + noPanClassName={noPanClassName} + rfId={rfId} + disableKeyboardA11y={disableKeyboardA11y} + nodeOrigin={nodeOrigin} + nodeExtent={nodeExtent} + viewport={viewport} + onViewportChange={onViewportChange} + /> + + + {children} + + + +
+ ); +} -export default ReactFlow; +export default forwardRef(ReactFlow) as ( + props: ReactFlowProps & { ref?: React.ForwardedRef } +) => ReturnType; diff --git a/packages/react/src/hooks/useNodesEdgesState.ts b/packages/react/src/hooks/useNodesEdgesState.ts index 766ee049..fae87c02 100644 --- a/packages/react/src/hooks/useNodesEdgesState.ts +++ b/packages/react/src/hooks/useNodesEdgesState.ts @@ -1,7 +1,7 @@ import { useState, useCallback, type Dispatch, type SetStateAction } from 'react'; import { applyNodeChanges, applyEdgeChanges } from '../utils/changes'; -import type { Node, NodeChange, Edge, EdgeChange } from '../types'; +import type { Node, Edge, OnNodesChange, OnEdgesChange } from '../types'; /** * Hook for managing the state of nodes - should only be used for prototyping / simple use cases. @@ -10,12 +10,12 @@ import type { Node, NodeChange, Edge, EdgeChange } from '../types'; * @param initialNodes * @returns an array [nodes, setNodes, onNodesChange] */ -export function useNodesState( +export function useNodesState( initialNodes: NodeType[] -): [NodeType[], Dispatch>, (changes: NodeChange[]) => void] { +): [NodeType[], Dispatch>, OnNodesChange] { const [nodes, setNodes] = useState(initialNodes); - const onNodesChange = useCallback( - (changes: NodeChange[]) => setNodes((nds) => applyNodeChanges(changes, nds)), + const onNodesChange: OnNodesChange = useCallback( + (changes) => setNodes((nds) => applyNodeChanges(changes, nds)), [] ); @@ -31,10 +31,10 @@ export function useNodesState( */ export function useEdgesState( initialEdges: EdgeType[] -): [EdgeType[], Dispatch>, (changes: EdgeChange[]) => void] { +): [EdgeType[], Dispatch>, OnEdgesChange] { const [edges, setEdges] = useState(initialEdges); - const onEdgesChange = useCallback( - (changes: EdgeChange[]) => setEdges((eds) => applyEdgeChanges(changes, eds)), + const onEdgesChange: OnEdgesChange = useCallback( + (changes) => setEdges((eds) => applyEdgeChanges(changes, eds)), [] ); diff --git a/packages/react/src/hooks/useOnInitHandler.ts b/packages/react/src/hooks/useOnInitHandler.ts index 5b677c1a..782b0379 100644 --- a/packages/react/src/hooks/useOnInitHandler.ts +++ b/packages/react/src/hooks/useOnInitHandler.ts @@ -1,15 +1,15 @@ import { useEffect, useRef } from 'react'; import { useReactFlow } from './useReactFlow'; -import type { OnInit } from '../types'; +import type { OnInit, Node } from '../types'; /** * Hook for calling onInit handler. * * @internal */ -export function useOnInitHandler(onInit: OnInit | undefined) { - const rfInstance = useReactFlow(); +export function useOnInitHandler(onInit: OnInit | undefined) { + const rfInstance = useReactFlow(); const isInitialized = useRef(false); useEffect(() => { diff --git a/packages/react/src/hooks/useStore.ts b/packages/react/src/hooks/useStore.ts index 96587161..9f7f8255 100644 --- a/packages/react/src/hooks/useStore.ts +++ b/packages/react/src/hooks/useStore.ts @@ -31,7 +31,7 @@ function useStore( return useZustandStore(store, selector, equalityFn); } -const useStoreApi = () => { +function useStoreApi() { const store = useContext(StoreContext); if (store === null) { @@ -47,6 +47,6 @@ const useStoreApi = () => { }), [store] ); -}; +} export { useStore, useStoreApi }; diff --git a/packages/react/src/types/component-props.ts b/packages/react/src/types/component-props.ts index 6018e1f5..f5f854ab 100644 --- a/packages/react/src/types/component-props.ts +++ b/packages/react/src/types/component-props.ts @@ -50,7 +50,7 @@ import type { * ReactFlow component props. * @public */ -export interface ReactFlowProps extends Omit, 'onError'> { +export interface ReactFlowProps extends Omit, 'onError'> { /** An array of nodes to render in a controlled flow. * @example * const nodes = [ @@ -62,7 +62,7 @@ export interface ReactFlowProps extends Omit, 'on * } * ]; */ - nodes?: Node[]; + nodes?: NodeType[]; /** An array of edges to render in a controlled flow. * @example * const edges = [ @@ -75,7 +75,7 @@ export interface ReactFlowProps extends Omit, 'on */ edges?: Edge[]; /** The initial nodes to render in an uncontrolled flow. */ - defaultNodes?: Node[]; + defaultNodes?: NodeType[]; /** The initial edges to render in an uncontrolled flow. */ defaultEdges?: Edge[]; /** Defaults to be applied to all new edges that are added to the flow. @@ -99,23 +99,23 @@ export interface ReactFlowProps extends Omit, 'on */ defaultEdgeOptions?: DefaultEdgeOptions; /** This event handler is called when a user clicks on a node */ - onNodeClick?: NodeMouseHandler; + onNodeClick?: NodeMouseHandler; /** This event handler is called when a user double clicks on a node */ - onNodeDoubleClick?: NodeMouseHandler; + onNodeDoubleClick?: NodeMouseHandler; /** This event handler is called when mouse of a user enters a node */ - onNodeMouseEnter?: NodeMouseHandler; + onNodeMouseEnter?: NodeMouseHandler; /** This event handler is called when mouse of a user moves over a node */ - onNodeMouseMove?: NodeMouseHandler; + onNodeMouseMove?: NodeMouseHandler; /** This event handler is called when mouse of a user leaves a node */ - onNodeMouseLeave?: NodeMouseHandler; + onNodeMouseLeave?: NodeMouseHandler; /** This event handler is called when a user right clicks on a node */ - onNodeContextMenu?: NodeMouseHandler; + onNodeContextMenu?: NodeMouseHandler; /** This event handler is called when a user starts to drag a node */ - onNodeDragStart?: OnNodeDrag; + onNodeDragStart?: OnNodeDrag; /** This event handler is called when a user drags a node */ - onNodeDrag?: OnNodeDrag; + onNodeDrag?: OnNodeDrag; /** This event handler is called when a user stops dragging a node */ - onNodeDragStop?: OnNodeDrag; + onNodeDragStop?: OnNodeDrag; /** This event handler is called when a user clicks on an edge */ onEdgeClick?: (event: ReactMouseEvent, edge: Edge) => void; /** This event handler is called when a user right clicks on an edge */ @@ -147,7 +147,7 @@ export interface ReactFlowProps extends Omit, 'on * * return () */ - onNodesChange?: OnNodesChange; + onNodesChange?: OnNodesChange; /** This event handler is called when a Edge is updated * @example // Use EdgesState hook to create edges and get onEdgesChange handler * import ReactFlow, { useEdgesState } from '@xyflow/react'; @@ -166,7 +166,7 @@ export interface ReactFlowProps extends Omit, 'on */ onEdgesChange?: OnEdgesChange; /** This event handler gets called when a Node is deleted */ - onNodesDelete?: OnNodesDelete; + onNodesDelete?: OnNodesDelete; /** This event handler gets called when a Edge is deleted */ onEdgesDelete?: OnEdgesDelete; /** This event handler gets called when a Node or Edge is deleted */ @@ -179,7 +179,7 @@ export interface ReactFlowProps extends Omit, 'on onSelectionDragStop?: SelectionDragHandler; onSelectionStart?: (event: ReactMouseEvent) => void; onSelectionEnd?: (event: ReactMouseEvent) => void; - onSelectionContextMenu?: (event: ReactMouseEvent, nodes: Node[]) => void; + onSelectionContextMenu?: (event: ReactMouseEvent, nodes: NodeType[]) => void; /** When a connection line is completed and two nodes are connected by the user, this event fires with the new connection. * * You can use the addEdge utility to convert the connection to a complete edge. @@ -201,7 +201,7 @@ export interface ReactFlowProps extends Omit, 'on onClickConnectStart?: OnConnectStart; onClickConnectEnd?: OnConnectEnd; /** This event handler gets called when a flow has finished initializing */ - onInit?: OnInit; + onInit?: OnInit; /** This event handler is called while the user is either panning or zooming the viewport. */ onMove?: OnMove; /** This event handler gets called when a user starts to pan or zoom the viewport */ @@ -223,7 +223,7 @@ export interface ReactFlowProps extends Omit, 'on /** This event handler gets called when mouse leaves the pane */ onPaneMouseLeave?: (event: ReactMouseEvent) => void; /** This handler gets called before the user deletes nodes or edges and provides a way to abort the deletion by returning false. */ - onBeforeDelete?: OnBeforeDelete; + onBeforeDelete?: OnBeforeDelete; /** Custom node types to be available in a flow. * * React Flow matches a node's type to a component in the nodeTypes object. diff --git a/packages/react/src/types/nodes.ts b/packages/react/src/types/nodes.ts index 612c1d50..9b28c78f 100644 --- a/packages/react/src/types/nodes.ts +++ b/packages/react/src/types/nodes.ts @@ -26,18 +26,18 @@ export type OnNodeDrag = ( nodes: NodeType[] ) => void; -export type NodeWrapperProps = { +export type NodeWrapperProps = { id: string; nodesConnectable: boolean; elementsSelectable: boolean; nodesDraggable: boolean; nodesFocusable: boolean; - onClick?: NodeMouseHandler; - onDoubleClick?: NodeMouseHandler; - onMouseEnter?: NodeMouseHandler; - onMouseMove?: NodeMouseHandler; - onMouseLeave?: NodeMouseHandler; - onContextMenu?: NodeMouseHandler; + onClick?: NodeMouseHandler; + onDoubleClick?: NodeMouseHandler; + onMouseEnter?: NodeMouseHandler; + onMouseMove?: NodeMouseHandler; + onMouseLeave?: NodeMouseHandler; + onContextMenu?: NodeMouseHandler; resizeObserver: ResizeObserver | null; noDragClassName: string; noPanClassName: string; diff --git a/packages/react/src/types/store.ts b/packages/react/src/types/store.ts index b3e0449e..27482dba 100644 --- a/packages/react/src/types/store.ts +++ b/packages/react/src/types/store.ts @@ -45,17 +45,17 @@ import type { OnBeforeDelete, } from '.'; -export type ReactFlowStore = { +export type ReactFlowStore = { rfId: string; width: number; height: number; transform: Transform; - nodes: Node[]; - nodeLookup: NodeLookup; + nodes: NodeType[]; + nodeLookup: NodeLookup; edges: Edge[]; edgeLookup: EdgeLookup; connectionLookup: ConnectionLookup; - onNodesChange: OnNodesChange | null; + onNodesChange: OnNodesChange | null; onEdgesChange: OnEdgesChange | null; hasDefaultNodes: boolean; hasDefaultEdges: boolean; @@ -98,9 +98,9 @@ export type ReactFlowStore = { connectionEndHandle: ConnectingHandle | null; connectionClickStartHandle: ConnectingHandle | null; - onNodeDragStart?: OnNodeDrag; - onNodeDrag?: OnNodeDrag; - onNodeDragStop?: OnNodeDrag; + onNodeDragStart?: OnNodeDrag; + onNodeDrag?: OnNodeDrag; + onNodeDragStop?: OnNodeDrag; onSelectionDragStart?: OnSelectionDrag; onSelectionDrag?: OnSelectionDrag; @@ -147,10 +147,10 @@ export type ReactFlowStore = { lib: string; }; -export type ReactFlowActions = { - setNodes: (nodes: Node[]) => void; +export type ReactFlowActions = { + setNodes: (nodes: NodeType[]) => void; setEdges: (edges: Edge[]) => void; - setDefaultNodesAndEdges: (nodes?: Node[], edges?: Edge[]) => void; + setDefaultNodesAndEdges: (nodes?: NodeType[], edges?: Edge[]) => void; updateNodeDimensions: (updates: Map) => void; updateNodePositions: UpdateNodePositions; resetSelectedElements: () => void; @@ -164,9 +164,9 @@ export type ReactFlowActions = { cancelConnection: () => void; updateConnection: UpdateConnection; reset: () => void; - triggerNodeChanges: (changes: NodeChange[]) => void; + triggerNodeChanges: (changes: NodeChange[]) => void; panBy: PanBy; - fitView: (nodes: Node[], options?: FitViewOptions) => boolean; + fitView: (nodes: NodeType[], options?: FitViewOptions) => boolean; }; -export type ReactFlowState = ReactFlowStore & ReactFlowActions; +export type ReactFlowState = ReactFlowStore & ReactFlowActions;