From ad7403cc75ac5884830599f6be7ae66b73132d51 Mon Sep 17 00:00:00 2001 From: moklick Date: Sat, 17 Feb 2024 15:45:10 +0100 Subject: [PATCH] refactor(types): use same structure for nodes and edges --- .../EdgeWrapper/EdgeUpdateAnchors.tsx | 14 ++--- .../src/components/EdgeWrapper/index.tsx | 10 ++-- .../src/components/StoreUpdater/index.tsx | 11 ++-- .../src/container/EdgeRenderer/index.tsx | 14 ++--- .../src/container/FlowRenderer/index.tsx | 4 +- .../react/src/container/GraphView/index.tsx | 14 ++--- .../react/src/container/ReactFlow/index.tsx | 18 ++----- packages/react/src/hooks/useEdges.ts | 4 +- packages/react/src/hooks/useOnInitHandler.ts | 8 +-- packages/react/src/index.ts | 1 - packages/react/src/types/component-props.ts | 43 +++++++-------- packages/react/src/types/edges.ts | 53 ++++++++++--------- packages/react/src/types/general.ts | 10 +++- packages/react/src/types/nodes.ts | 9 ++-- packages/react/src/types/store.ts | 28 +++++----- .../src/lib/container/SvelteFlow/types.ts | 8 +-- packages/svelte/src/lib/hooks/useNodesData.ts | 2 +- packages/svelte/src/lib/index.ts | 1 - .../svelte/src/lib/store/initial-store.ts | 4 +- packages/svelte/src/lib/types/edges.ts | 41 ++++++++------ packages/svelte/src/lib/types/general.ts | 4 ++ packages/svelte/src/lib/types/nodes.ts | 4 +- packages/system/src/types/edges.ts | 7 ++- packages/system/src/types/nodes.ts | 11 ++-- 24 files changed, 176 insertions(+), 147 deletions(-) diff --git a/packages/react/src/components/EdgeWrapper/EdgeUpdateAnchors.tsx b/packages/react/src/components/EdgeWrapper/EdgeUpdateAnchors.tsx index db56017c..c84c2d3b 100644 --- a/packages/react/src/components/EdgeWrapper/EdgeUpdateAnchors.tsx +++ b/packages/react/src/components/EdgeWrapper/EdgeUpdateAnchors.tsx @@ -5,20 +5,20 @@ import { EdgeAnchor } from '../Edges/EdgeAnchor'; import type { EdgeWrapperProps, Edge } from '../../types/edges'; import { useStoreApi } from '../../hooks/useStore'; -type EdgeUpdateAnchorsProps = { - edge: Edge; +type EdgeUpdateAnchorsProps = { + edge: EdgeType; isUpdatable: boolean | 'source' | 'target'; edgeUpdaterRadius: EdgeWrapperProps['edgeUpdaterRadius']; sourceHandleId: Edge['sourceHandle']; targetHandleId: Edge['targetHandle']; - onEdgeUpdate: EdgeWrapperProps['onEdgeUpdate']; - onEdgeUpdateStart: EdgeWrapperProps['onEdgeUpdateStart']; - onEdgeUpdateEnd: EdgeWrapperProps['onEdgeUpdateEnd']; + onEdgeUpdate: EdgeWrapperProps['onEdgeUpdate']; + onEdgeUpdateStart: EdgeWrapperProps['onEdgeUpdateStart']; + onEdgeUpdateEnd: EdgeWrapperProps['onEdgeUpdateEnd']; setUpdateHover: (hover: boolean) => void; setUpdating: (updating: boolean) => void; } & EdgePosition; -export function EdgeUpdateAnchors({ +export function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, @@ -35,7 +35,7 @@ export function EdgeUpdateAnchors({ onEdgeUpdateEnd, setUpdating, setUpdateHover, -}: EdgeUpdateAnchorsProps) { +}: EdgeUpdateAnchorsProps) { const store = useStoreApi(); const handleEdgeUpdater = (event: React.MouseEvent, isSourceHandle: boolean) => { diff --git a/packages/react/src/components/EdgeWrapper/index.tsx b/packages/react/src/components/EdgeWrapper/index.tsx index 28323a19..b1fdb4a8 100644 --- a/packages/react/src/components/EdgeWrapper/index.tsx +++ b/packages/react/src/components/EdgeWrapper/index.tsx @@ -13,9 +13,9 @@ import { useStoreApi, useStore } from '../../hooks/useStore'; import { ARIA_EDGE_DESC_KEY } from '../A11yDescriptions'; import { builtinEdgeTypes, nullPosition } from './utils'; import { EdgeUpdateAnchors } from './EdgeUpdateAnchors'; -import type { EdgeWrapperProps } from '../../types'; +import type { Edge, EdgeWrapperProps } from '../../types'; -export function EdgeWrapper({ +export function EdgeWrapper({ id, edgesFocusable, edgesUpdatable, @@ -34,8 +34,8 @@ export function EdgeWrapper({ edgeTypes, noPanClassName, onError, -}: EdgeWrapperProps): JSX.Element | null { - let edge = useStore((s) => s.edgeLookup.get(id)!); +}: EdgeWrapperProps): JSX.Element | null { + let edge = useStore((s) => s.edgeLookup.get(id)!) as EdgeType; const defaultEdgeOptions = useStore((s) => s.defaultEdgeOptions); edge = defaultEdgeOptions ? { ...defaultEdgeOptions, ...edge } : edge; @@ -236,7 +236,7 @@ export function EdgeWrapper({ /> )} {isUpdatable && ( - edge={edge} isUpdatable={isUpdatable} edgeUpdaterRadius={edgeUpdaterRadius} diff --git a/packages/react/src/components/StoreUpdater/index.tsx b/packages/react/src/components/StoreUpdater/index.tsx index 6211ea59..9c77f5e0 100644 --- a/packages/react/src/components/StoreUpdater/index.tsx +++ b/packages/react/src/components/StoreUpdater/index.tsx @@ -68,7 +68,10 @@ const reactFlowFieldsToTrack = [ ] as const; type ReactFlowFieldsToTrack = (typeof reactFlowFieldsToTrack)[number]; -type StoreUpdaterProps = Pick, ReactFlowFieldsToTrack> & { +type StoreUpdaterProps = Pick< + ReactFlowProps, + ReactFlowFieldsToTrack +> & { rfId: string; }; @@ -86,7 +89,9 @@ const selector = (s: ReactFlowState) => ({ reset: s.reset, }); -export function StoreUpdater(props: StoreUpdaterProps) { +export function StoreUpdater( + props: StoreUpdaterProps +) { const { setNodes, setEdges, @@ -108,7 +113,7 @@ export function StoreUpdater(props: StoreUpdaterPr }; }, []); - 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/EdgeRenderer/index.tsx b/packages/react/src/container/EdgeRenderer/index.tsx index 5fdaa1af..3112179e 100644 --- a/packages/react/src/container/EdgeRenderer/index.tsx +++ b/packages/react/src/container/EdgeRenderer/index.tsx @@ -6,10 +6,10 @@ import { useVisibleEdgeIds } from '../../hooks/useVisibleEdgeIds'; import MarkerDefinitions from './MarkerDefinitions'; import { GraphViewProps } from '../GraphView'; import { EdgeWrapper } from '../../components/EdgeWrapper'; -import type { ReactFlowState } from '../../types'; +import type { Edge, ReactFlowState, Node } from '../../types'; -type EdgeRendererProps = Pick< - GraphViewProps, +type EdgeRendererProps = Pick< + GraphViewProps, | 'onEdgeClick' | 'onEdgeDoubleClick' | 'defaultMarkerColor' @@ -40,7 +40,7 @@ const selector = (s: ReactFlowState) => ({ onError: s.onError, }); -function EdgeRendererComponent({ +function EdgeRendererComponent({ defaultMarkerColor, onlyRenderVisibleElements, rfId, @@ -56,7 +56,7 @@ function EdgeRendererComponent({ onEdgeDoubleClick, onEdgeUpdateStart, onEdgeUpdateEnd, -}: EdgeRendererProps) { +}: EdgeRendererProps) { const { edgesFocusable, edgesUpdatable, elementsSelectable, onError } = useStore(selector, shallow); const edgeIds = useVisibleEdgeIds(onlyRenderVisibleElements); @@ -66,7 +66,7 @@ function EdgeRendererComponent({ {edgeIds.map((id) => { return ( - key={id} id={id} edgesFocusable={edgesFocusable} @@ -95,4 +95,4 @@ function EdgeRendererComponent({ EdgeRendererComponent.displayName = 'EdgeRenderer'; -export const EdgeRenderer = memo(EdgeRendererComponent); +export const EdgeRenderer = memo(EdgeRendererComponent) as typeof EdgeRendererComponent; diff --git a/packages/react/src/container/FlowRenderer/index.tsx b/packages/react/src/container/FlowRenderer/index.tsx index 6aa49a2a..14216ac2 100644 --- a/packages/react/src/container/FlowRenderer/index.tsx +++ b/packages/react/src/container/FlowRenderer/index.tsx @@ -9,7 +9,7 @@ import { Pane } from '../Pane'; import { NodesSelection } from '../../components/NodesSelection'; import type { ReactFlowState, Node } from '../../types'; -export type FlowRendererProps = Omit< +export type FlowRendererProps = Omit< GraphViewProps, | 'snapToGrid' | 'nodeTypes' @@ -32,7 +32,7 @@ const selector = (s: ReactFlowState) => { return { nodesSelectionActive: s.nodesSelectionActive, userSelectionActive: s.userSelectionActive }; }; -function FlowRendererComponent({ +function FlowRendererComponent({ children, onPaneClick, onPaneMouseEnter, diff --git a/packages/react/src/container/GraphView/index.tsx b/packages/react/src/container/GraphView/index.tsx index 0615258c..f1965b04 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 { Node, ReactFlowProps } from '../../types'; +import type { Edge, 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); @@ -148,7 +148,7 @@ function GraphViewComponent({ isControlledViewport={!!viewport} > - edgeTypes={edgeTypes} onEdgeClick={onEdgeClick} onEdgeDoubleClick={onEdgeDoubleClick} diff --git a/packages/react/src/container/ReactFlow/index.tsx b/packages/react/src/container/ReactFlow/index.tsx index 2516b4e7..d4875419 100644 --- a/packages/react/src/container/ReactFlow/index.tsx +++ b/packages/react/src/container/ReactFlow/index.tsx @@ -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, Node } from '../../types'; +import type { ReactFlowProps, ReactFlowRefType, Node, Edge } from '../../types'; export const initNodeOrigin: NodeOrigin = [0, 0]; const initDefaultViewport: Viewport = { x: 0, y: 0, zoom: 1 }; @@ -30,13 +30,7 @@ const wrapperStyle: CSSProperties = { zIndex: 0, }; -declare module 'react' { - function forwardRef>( - render: (props: P, ref: React.Ref) => React.ReactNode | null - ): (props: P & React.RefAttributes) => React.ReactNode | null; -} - -function ReactFlow( +function ReactFlow( { nodes, edges, @@ -156,7 +150,7 @@ function ReactFlow( height, colorMode = 'light', ...rest - }: ReactFlowProps, + }: ReactFlowProps, ref: ForwardedRef ) { const rfId = id || '1'; @@ -172,7 +166,7 @@ function ReactFlow( id={id} > - + onInit={onInit} onNodeClick={onNodeClick} onEdgeClick={onEdgeClick} @@ -300,6 +294,4 @@ function ReactFlow( ); } -export default forwardRef(ReactFlow) as ( - props: ReactFlowProps & { ref?: React.ForwardedRef } -) => ReturnType; +export default forwardRef(ReactFlow) as typeof ReactFlow; diff --git a/packages/react/src/hooks/useEdges.ts b/packages/react/src/hooks/useEdges.ts index bd748abb..3ed9de39 100644 --- a/packages/react/src/hooks/useEdges.ts +++ b/packages/react/src/hooks/useEdges.ts @@ -11,8 +11,8 @@ const edgesSelector = (state: ReactFlowState) => state.edges; * @public * @returns An array of edges */ -export function useEdges(): Edge[] { - const edges = useStore(edgesSelector, shallow); +export function useEdges(): EdgeType[] { + const edges = useStore(edgesSelector, shallow) as EdgeType[]; return edges; } diff --git a/packages/react/src/hooks/useOnInitHandler.ts b/packages/react/src/hooks/useOnInitHandler.ts index 782b0379..5d43731b 100644 --- a/packages/react/src/hooks/useOnInitHandler.ts +++ b/packages/react/src/hooks/useOnInitHandler.ts @@ -1,15 +1,17 @@ import { useEffect, useRef } from 'react'; import { useReactFlow } from './useReactFlow'; -import type { OnInit, Node } from '../types'; +import type { OnInit, Node, Edge } 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/index.ts b/packages/react/src/index.ts index bcb12cdf..a757ec23 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -53,7 +53,6 @@ export { type OnConnectStart, type OnConnect, type OnConnectEnd, - type IsValidConnection, type Viewport, type SnapGrid, PanOnScrollMode, diff --git a/packages/react/src/types/component-props.ts b/packages/react/src/types/component-props.ts index f5f854ab..ce6e94ad 100644 --- a/packages/react/src/types/component-props.ts +++ b/packages/react/src/types/component-props.ts @@ -18,7 +18,6 @@ import type { HandleType, SelectionMode, OnError, - IsValidConnection, ColorMode, SnapGrid, } from '@xyflow/system'; @@ -44,13 +43,15 @@ import type { EdgeMouseHandler, OnNodeDrag, OnBeforeDelete, + IsValidConnection, } from '.'; /** * 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 = [ @@ -73,11 +74,11 @@ export interface ReactFlowProps extends Omit extends Omit; /** This event handler is called when a user clicks on an edge */ - onEdgeClick?: (event: ReactMouseEvent, edge: Edge) => void; + onEdgeClick?: (event: ReactMouseEvent, edge: EdgeType) => void; /** This event handler is called when a user right clicks on an edge */ - onEdgeContextMenu?: EdgeMouseHandler; + onEdgeContextMenu?: EdgeMouseHandler; /** This event handler is called when mouse of a user enters an edge */ - onEdgeMouseEnter?: EdgeMouseHandler; + onEdgeMouseEnter?: EdgeMouseHandler; /** This event handler is called when mouse of a user moves over an edge */ - onEdgeMouseMove?: EdgeMouseHandler; + onEdgeMouseMove?: EdgeMouseHandler; /** This event handler is called when mouse of a user leaves an edge */ - onEdgeMouseLeave?: EdgeMouseHandler; + onEdgeMouseLeave?: EdgeMouseHandler; /** This event handler is called when a user double clicks on an edge */ - onEdgeDoubleClick?: EdgeMouseHandler; - onEdgeUpdateStart?: (event: ReactMouseEvent, edge: Edge, handleType: HandleType) => void; - onEdgeUpdateEnd?: (event: MouseEvent | TouchEvent, edge: Edge, handleType: HandleType) => void; - onEdgeUpdate?: OnEdgeUpdateFunc; + onEdgeDoubleClick?: EdgeMouseHandler; + onEdgeUpdateStart?: (event: ReactMouseEvent, edge: EdgeType, handleType: HandleType) => void; + onEdgeUpdateEnd?: (event: MouseEvent | TouchEvent, edge: EdgeType, handleType: HandleType) => void; + onEdgeUpdate?: OnEdgeUpdateFunc; /** This event handler is called when a Node is updated * @example // Use NodesState hook to create edges and get onNodesChange handler * import ReactFlow, { useNodesState } from '@xyflow/react'; @@ -164,19 +165,19 @@ export interface ReactFlowProps extends Omit) */ - onEdgesChange?: OnEdgesChange; + onEdgesChange?: OnEdgesChange; /** This event handler gets called when a Node is deleted */ onNodesDelete?: OnNodesDelete; /** This event handler gets called when a Edge is deleted */ - onEdgesDelete?: OnEdgesDelete; + onEdgesDelete?: OnEdgesDelete; /** This event handler gets called when a Node or Edge is deleted */ - onDelete?: OnDelete; + onDelete?: OnDelete; /** This event handler gets called when a user starts to drag a selection box */ - onSelectionDragStart?: SelectionDragHandler; + onSelectionDragStart?: SelectionDragHandler; /** This event handler gets called when a user drags a selection box */ - onSelectionDrag?: SelectionDragHandler; + onSelectionDrag?: SelectionDragHandler; /** This event handler gets called when a user stops dragging a selection box */ - onSelectionDragStop?: SelectionDragHandler; + onSelectionDragStop?: SelectionDragHandler; onSelectionStart?: (event: ReactMouseEvent) => void; onSelectionEnd?: (event: ReactMouseEvent) => void; onSelectionContextMenu?: (event: ReactMouseEvent, nodes: NodeType[]) => void; @@ -201,7 +202,7 @@ export interface ReactFlowProps extends Omit; + 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 +224,7 @@ export interface ReactFlowProps extends Omit 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/edges.ts b/packages/react/src/types/edges.ts index 2b514c96..4de6472e 100644 --- a/packages/react/src/types/edges.ts +++ b/packages/react/src/types/edges.ts @@ -30,7 +30,14 @@ export type EdgeLabelOptions = { export type EdgeUpdatable = boolean | HandleType; -export type DefaultEdge = EdgeBase & +/** + * The Edge type is mainly used for the `edges` that get passed to the ReactFlow component + * @public + */ +export type Edge< + EdgeData extends Record = Record, + EdgeType extends string | undefined = string | undefined +> = EdgeBase & EdgeLabelOptions & { style?: CSSProperties; className?: string; @@ -38,45 +45,41 @@ export type DefaultEdge = EdgeBase & focusable?: boolean; }; -type SmoothStepEdgeType = DefaultEdge & { +type SmoothStepEdgeType = Record> = Edge & { type: 'smoothstep'; pathOptions?: SmoothStepPathOptions; }; -type BezierEdgeType = DefaultEdge & { +type BezierEdgeType = Record> = Edge & { type: 'default'; pathOptions?: BezierPathOptions; }; -type StepEdgeType = DefaultEdge & { +type StepEdgeType = Record> = Edge & { type: 'step'; pathOptions?: StepPathOptions; }; -/** - * The Edge type is mainly used for the `edges` that get passed to the ReactFlow component - * @public - */ -export type Edge = DefaultEdge | SmoothStepEdgeType | BezierEdgeType | StepEdgeType; +export type BuiltInEdge = SmoothStepEdgeType | BezierEdgeType | StepEdgeType; -export type EdgeMouseHandler = (event: ReactMouseEvent, edge: Edge) => void; +export type EdgeMouseHandler = (event: ReactMouseEvent, edge: EdgeType) => void; -export type EdgeWrapperProps = { +export type EdgeWrapperProps = { id: string; edgesFocusable: boolean; edgesUpdatable: boolean; elementsSelectable: boolean; noPanClassName: string; - onClick?: EdgeMouseHandler; - onDoubleClick?: EdgeMouseHandler; - onEdgeUpdate?: OnEdgeUpdateFunc; - onContextMenu?: EdgeMouseHandler; - onMouseEnter?: EdgeMouseHandler; - onMouseMove?: EdgeMouseHandler; - onMouseLeave?: EdgeMouseHandler; + onClick?: EdgeMouseHandler; + onDoubleClick?: EdgeMouseHandler; + onEdgeUpdate?: OnEdgeUpdateFunc; + onContextMenu?: EdgeMouseHandler; + onMouseEnter?: EdgeMouseHandler; + onMouseMove?: EdgeMouseHandler; + onMouseLeave?: EdgeMouseHandler; edgeUpdaterRadius?: number; - onEdgeUpdateStart?: (event: ReactMouseEvent, edge: Edge, handleType: HandleType) => void; - onEdgeUpdateEnd?: (event: MouseEvent | TouchEvent, edge: Edge, handleType: HandleType) => void; + onEdgeUpdateStart?: (event: ReactMouseEvent, edge: EdgeType, handleType: HandleType) => void; + onEdgeUpdateEnd?: (event: MouseEvent | TouchEvent, edge: EdgeType, handleType: HandleType) => void; rfId?: string; edgeTypes?: EdgeTypes; onError?: OnError; @@ -94,10 +97,10 @@ export type EdgeTextProps = HTMLAttributes & * Custom edge component props * @public */ -export type EdgeProps = Pick< - Edge, - 'id' | 'animated' | 'data' | 'style' | 'selected' | 'source' | 'target' -> & +export type EdgeProps< + EdgeData extends Record = Record, + EdgeType extends string | undefined = string | undefined +> = Pick, 'id' | 'animated' | 'data' | 'style' | 'selected' | 'source' | 'target'> & EdgePosition & EdgeLabelOptions & { sourceHandleId?: string | null; @@ -185,7 +188,7 @@ export type StraightEdgeProps = Omit = (oldEdge: Edge, newConnection: Connection) => void; +export type OnEdgeUpdateFunc = (oldEdge: EdgeType, newConnection: Connection) => void; export type ConnectionLineComponentProps = { connectionLineStyle?: CSSProperties; diff --git a/packages/react/src/types/general.ts b/packages/react/src/types/general.ts index 4f3f127a..549921c2 100644 --- a/packages/react/src/types/general.ts +++ b/packages/react/src/types/general.ts @@ -12,6 +12,7 @@ import { XYPosition, NodeProps, OnBeforeDeleteBase, + Connection, } from '@xyflow/system'; import type { NodeChange, EdgeChange, Node, Edge, ReactFlowInstance, EdgeProps } from '.'; @@ -21,8 +22,11 @@ export type OnNodesChange = (changes: NodeChange = (changes: EdgeChange[]) => void; export type OnNodesDelete = (nodes: NodeType[]) => void; -export type OnEdgesDelete = (edges: Edge[]) => void; -export type OnDelete = (params: { nodes: Node[]; edges: Edge[] }) => void; +export type OnEdgesDelete = (edges: EdgeType[]) => void; +export type OnDelete = (params: { + nodes: NodeType[]; + edges: EdgeType[]; +}) => void; export type NodeTypes = { [key: string]: ComponentType }; export type EdgeTypes = { [key: string]: ComponentType }; @@ -139,3 +143,5 @@ export type OnBeforeDelete; + +export type IsValidConnection = (edge: EdgeType | Connection) => boolean; diff --git a/packages/react/src/types/nodes.ts b/packages/react/src/types/nodes.ts index 9ef7b9c3..c3c0ea94 100644 --- a/packages/react/src/types/nodes.ts +++ b/packages/react/src/types/nodes.ts @@ -7,11 +7,10 @@ import { NodeTypes } from './general'; * The node data structure that gets used for the nodes prop. * @public */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export type Node = NodeBase< - NodeData, - NodeType -> & { +export type Node< + NodeData extends Record = Record, + NodeType extends string | undefined = string | undefined +> = NodeBase & { style?: CSSProperties; className?: string; resizing?: boolean; diff --git a/packages/react/src/types/store.ts b/packages/react/src/types/store.ts index 38e3fbe9..30ac002a 100644 --- a/packages/react/src/types/store.ts +++ b/packages/react/src/types/store.ts @@ -21,7 +21,6 @@ import { type OnMoveStart, type OnMove, type OnMoveEnd, - type IsValidConnection, type UpdateConnection, type EdgeLookup, type ConnectionLookup, @@ -43,9 +42,10 @@ import type { OnDelete, OnNodeDrag, OnBeforeDelete, + IsValidConnection, } from '.'; -export type ReactFlowStore = { +export type ReactFlowStore = { rfId: string; width: number; height: number; @@ -53,10 +53,10 @@ export type ReactFlowStore = { nodes: NodeType[]; nodeLookup: NodeLookup; edges: Edge[]; - edgeLookup: EdgeLookup; + edgeLookup: EdgeLookup; connectionLookup: ConnectionLookup; onNodesChange: OnNodesChange | null; - onEdgesChange: OnEdgesChange | null; + onEdgesChange: OnEdgesChange | null; hasDefaultNodes: boolean; hasDefaultEdges: boolean; domNode: HTMLDivElement | null; @@ -124,8 +124,8 @@ export type ReactFlowStore = { fitViewDone: boolean; fitViewOnInitOptions: FitViewOptions | undefined; - onNodesDelete?: OnNodesDelete; - onEdgesDelete?: OnEdgesDelete; + onNodesDelete?: OnNodesDelete; + onEdgesDelete?: OnEdgesDelete; onDelete?: OnDelete; onError?: OnError; @@ -133,7 +133,7 @@ export type ReactFlowStore = { onViewportChangeStart?: OnViewportChange; onViewportChange?: OnViewportChange; onViewportChangeEnd?: OnViewportChange; - onBeforeDelete?: OnBeforeDelete; + onBeforeDelete?: OnBeforeDelete; onSelectionChangeHandlers: OnSelectionChangeFunc[]; @@ -142,15 +142,15 @@ export type ReactFlowStore = { autoPanOnNodeDrag: boolean; connectionRadius: number; - isValidConnection?: IsValidConnection; + isValidConnection?: IsValidConnection; lib: string; }; -export type ReactFlowActions = { +export type ReactFlowActions = { setNodes: (nodes: NodeType[]) => void; - setEdges: (edges: Edge[]) => void; - setDefaultNodesAndEdges: (nodes?: NodeType[], edges?: Edge[]) => void; + setEdges: (edges: EdgeType[]) => void; + setDefaultNodesAndEdges: (nodes?: NodeType[], edges?: EdgeType[]) => void; updateNodeDimensions: (updates: Map) => void; updateNodePositions: UpdateNodePositions; resetSelectedElements: () => void; @@ -169,4 +169,8 @@ export type ReactFlowActions = { fitView: (nodes: NodeType[], options?: FitViewOptions) => boolean; }; -export type ReactFlowState = ReactFlowStore & ReactFlowActions; +export type ReactFlowState = ReactFlowStore< + NodeType, + EdgeType +> & + ReactFlowActions; diff --git a/packages/svelte/src/lib/container/SvelteFlow/types.ts b/packages/svelte/src/lib/container/SvelteFlow/types.ts index aefa6f6e..b7dd2852 100644 --- a/packages/svelte/src/lib/container/SvelteFlow/types.ts +++ b/packages/svelte/src/lib/container/SvelteFlow/types.ts @@ -10,7 +10,6 @@ import type { OnMoveEnd, CoordinateExtent, PanOnScrollMode, - IsValidConnection, OnError, ConnectionMode, PanelPosition, @@ -18,8 +17,7 @@ import type { ColorMode, OnConnect, OnConnectStart, - OnConnectEnd, - OnBeforeDelete + OnConnectEnd } from '@xyflow/system'; import type { @@ -31,7 +29,9 @@ import type { DefaultEdgeOptions, FitViewOptions, OnDelete, - OnEdgeCreate + OnEdgeCreate, + OnBeforeDelete, + IsValidConnection } from '$lib/types'; import type { Writable } from 'svelte/store'; diff --git a/packages/svelte/src/lib/hooks/useNodesData.ts b/packages/svelte/src/lib/hooks/useNodesData.ts index 8e24645c..d45c8c9e 100644 --- a/packages/svelte/src/lib/hooks/useNodesData.ts +++ b/packages/svelte/src/lib/hooks/useNodesData.ts @@ -3,7 +3,7 @@ import { derived, type Readable } from 'svelte/store'; import type { Node } from '$lib/types'; import { useStore } from '$lib/store'; -function areNodesDataEqual(a: Node['data'][] | null, b: Node['data'][] | null) { +function areNodesDataEqual(a: (Node['data'] | null)[] | null, b: (Node['data'] | null)[] | null) { if ((!a && !b) || (!a?.length && !b?.length)) { true; } diff --git a/packages/svelte/src/lib/index.ts b/packages/svelte/src/lib/index.ts index 76394872..c484ec7e 100644 --- a/packages/svelte/src/lib/index.ts +++ b/packages/svelte/src/lib/index.ts @@ -66,7 +66,6 @@ export { type OnConnectStart, type OnConnect, type OnConnectEnd, - type IsValidConnection, type Viewport, type SnapGrid, PanOnScrollMode, diff --git a/packages/svelte/src/lib/store/initial-store.ts b/packages/svelte/src/lib/store/initial-store.ts index 6c18c877..40020aba 100644 --- a/packages/svelte/src/lib/store/initial-store.ts +++ b/packages/svelte/src/lib/store/initial-store.ts @@ -14,7 +14,6 @@ import { type MarkerProps, type PanZoomInstance, type CoordinateExtent, - type IsValidConnection, type NodeOrigin, type OnError, type Viewport, @@ -47,7 +46,8 @@ import type { FitViewOptions, OnDelete, OnEdgeCreate, - OnBeforeDelete + OnBeforeDelete, + IsValidConnection } from '$lib/types'; import { createNodesStore, createEdgesStore } from './utils'; import { initConnectionProps, type ConnectionProps } from './derived-connection-props'; diff --git a/packages/svelte/src/lib/types/edges.ts b/packages/svelte/src/lib/types/edges.ts index c99b201a..21bcdaa5 100644 --- a/packages/svelte/src/lib/types/edges.ts +++ b/packages/svelte/src/lib/types/edges.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ import type { SvelteComponent, ComponentType } from 'svelte'; import type { EdgeBase, @@ -11,41 +10,49 @@ import type { import type { Node } from '$lib/types'; -export type DefaultEdge = EdgeBase & { +/** + * The Edge type is mainly used for the `edges` that get passed to the SvelteFlow component. + */ +export type Edge< + EdgeData extends Record = Record, + EdgeType extends string | undefined = string | undefined +> = EdgeBase & { label?: string; labelStyle?: string; style?: string; class?: string; }; -type SmoothStepEdgeType = DefaultEdge & { - type: 'smoothstep'; +type SmoothStepEdge = Record> = Edge< + EdgeData, + 'smoothstep' +> & { pathOptions?: SmoothStepPathOptions; }; -type BezierEdgeType = DefaultEdge & { - type: 'default'; +type BezierEdge = Record> = Edge< + EdgeData, + 'default' +> & { pathOptions?: BezierPathOptions; }; -type StepEdgeType = DefaultEdge & { - type: 'step'; +type StepEdge = Record> = Edge< + EdgeData, + 'step' +> & { pathOptions?: StepPathOptions; }; -/** - * The Edge type is mainly used for the `edges` that get passed to the SvelteFlow component. - */ -export type Edge = - | DefaultEdge - | SmoothStepEdgeType - | BezierEdgeType - | StepEdgeType; +export type BuiltInEdge = SmoothStepEdge | BezierEdge | StepEdge; /** * Custom edge component props. */ -export type EdgeProps = Omit, 'sourceHandle' | 'targetHandle' | 'type'> & +export type EdgeProps< + EdgeData extends Record = Record, + EdgeType extends string | undefined = string | undefined +> = Omit, 'sourceHandle' | 'targetHandle' | 'type'> & EdgePosition & { markerStart?: string; markerEnd?: string; diff --git a/packages/svelte/src/lib/types/general.ts b/packages/svelte/src/lib/types/general.ts index e67ad88c..fe728fae 100644 --- a/packages/svelte/src/lib/types/general.ts +++ b/packages/svelte/src/lib/types/general.ts @@ -57,3 +57,7 @@ export type OnBeforeDelete< NodeType extends Node = Node, EdgeType extends Edge = Edge > = OnBeforeDeleteBase; + +export type IsValidConnection = ( + edge: EdgeType | Connection +) => boolean; diff --git a/packages/svelte/src/lib/types/nodes.ts b/packages/svelte/src/lib/types/nodes.ts index 4121754a..7a0fe082 100644 --- a/packages/svelte/src/lib/types/nodes.ts +++ b/packages/svelte/src/lib/types/nodes.ts @@ -7,7 +7,7 @@ import type { NodeBase, NodeProps } from '@xyflow/system'; * @public */ export type Node< - NodeData = any, + NodeData extends Record = Record, NodeType extends string | undefined = string | undefined > = NodeBase & { class?: string; @@ -17,3 +17,5 @@ export type Node< export type NodeTypes = Record>>; export type DefaultNodeOptions = Partial>; + +export type BuiltInNode = Node<{ label: string }, 'input' | 'output' | 'default'>; diff --git a/packages/system/src/types/edges.ts b/packages/system/src/types/edges.ts index e28ad058..37c299e8 100644 --- a/packages/system/src/types/edges.ts +++ b/packages/system/src/types/edges.ts @@ -1,11 +1,14 @@ import { Position } from './utils'; // eslint-disable-next-line @typescript-eslint/no-explicit-any -export type EdgeBase = { +export type EdgeBase< + EdgeData extends Record = Record, + EdgeType extends string | undefined = string | undefined +> = { /** Unique id of an edge */ id: string; /** Type of an edge defined in edgeTypes */ - type?: string; + type?: EdgeType; /** Id of source node */ source: string; /** Id of target node */ diff --git a/packages/system/src/types/nodes.ts b/packages/system/src/types/nodes.ts index b75e6d1b..4ac854ed 100644 --- a/packages/system/src/types/nodes.ts +++ b/packages/system/src/types/nodes.ts @@ -9,7 +9,10 @@ import { Optional } from '../utils/types'; * @typeParam T - type of the node data * @typeParam U - type of the node */ -export type NodeBase = { +export type NodeBase< + NodeData extends Record = Record, + NodeType extends string | undefined = string | undefined +> = { /** Unique id of a node */ id: string; /** Position of a node on the pane @@ -17,9 +20,9 @@ export type NodeBase */ position: XYPosition; /** Arbitrary data passed to a node */ - data: T; + data: NodeData; /** Type of node defined in nodeTypes */ - type?: U; + type?: NodeType; /** Only relevant for default, source, target nodeType. controls source position * @example 'right', 'left', 'top', 'bottom' */ @@ -70,7 +73,7 @@ export type NodeBase /** Holds a reference to the original node object provided by the user * (which may lack some fields, like `computed` or `[internalSymbol]`. Used * as an optimization to avoid certain operations. */ - userProvidedNode: NodeBase; + userProvidedNode: NodeBase; }; };