Merge branch 'main' into perf/noderenderer-minimap

This commit is contained in:
moklick
2023-12-13 16:32:02 +01:00
101 changed files with 2671 additions and 685 deletions
@@ -55,8 +55,8 @@ function Background({
{
...style,
...containerStyle,
'--background-color-props': bgColor,
'--background-pattern-color-props': color,
'--xy-background-color-props': bgColor,
'--xy-background-pattern-color-props': color,
} as CSSProperties
}
ref={ref}
@@ -129,10 +129,10 @@ function MiniMap({
style={
{
...style,
'--minimap-mask-color-props': typeof maskColor === 'string' ? maskColor : undefined,
'--minimap-node-background-color-props': typeof nodeColor === 'string' ? nodeColor : undefined,
'--minimap-node-stroke-color-props': typeof nodeStrokeColor === 'string' ? nodeStrokeColor : undefined,
'--minimap-node-stroke-width-props': typeof nodeStrokeWidth === 'string' ? nodeStrokeWidth : undefined,
'--xy-minimap-mask-color-props': typeof maskColor === 'string' ? maskColor : undefined,
'--xy-minimap-node-background-color-props': typeof nodeColor === 'string' ? nodeColor : undefined,
'--xy-minimap-node-stroke-color-props': typeof nodeStrokeColor === 'string' ? nodeStrokeColor : undefined,
'--xy-minimap-node-stroke-width-props': typeof nodeStrokeWidth === 'string' ? nodeStrokeWidth : undefined,
} as CSSProperties
}
className={cc(['react-flow__minimap', className])}
@@ -4,56 +4,67 @@ import { Position, getBezierPath } from '@xyflow/system';
import BaseEdge from './BaseEdge';
import type { BezierEdgeProps } from '../../types';
const BezierEdge = memo(
({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
pathOptions,
interactionWidth,
}: BezierEdgeProps) => {
const [path, labelX, labelY] = getBezierPath({
function createBezierEdge(params: { isInternal: boolean }) {
// eslint-disable-next-line react/display-name
return memo(
({
id,
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
curvature: pathOptions?.curvature,
});
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
pathOptions,
interactionWidth,
}: BezierEdgeProps) => {
const [path, labelX, labelY] = getBezierPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
curvature: pathOptions?.curvature,
});
return (
<BaseEdge
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
const _id = params.isInternal ? undefined : id;
return (
<BaseEdge
id={_id}
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
}
const BezierEdge = createBezierEdge({ isInternal: false });
const BezierEdgeInternal = createBezierEdge({ isInternal: true });
BezierEdge.displayName = 'BezierEdge';
BezierEdgeInternal.displayName = 'BezierEdgeInternal';
export default BezierEdge;
export { BezierEdge, BezierEdgeInternal };
@@ -2,7 +2,7 @@ import { memo } from 'react';
import { Position, getBezierEdgeCenter } from '@xyflow/system';
import BaseEdge from './BaseEdge';
import type { EdgeProps } from '../../types';
import type { SimpleBezierEdgeProps } from '../../types';
export interface GetSimpleBezierPathParams {
sourceX: number;
@@ -71,54 +71,65 @@ export function getSimpleBezierPath({
];
}
const SimpleBezierEdge = memo(
({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
interactionWidth,
}: EdgeProps) => {
const [path, labelX, labelY] = getSimpleBezierPath({
function createSimpleBezierEdge(params: { isInternal: boolean }) {
// eslint-disable-next-line react/display-name
return memo(
({
id,
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
});
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
interactionWidth,
}: SimpleBezierEdgeProps) => {
const [path, labelX, labelY] = getSimpleBezierPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
});
return (
<BaseEdge
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
const _id = params.isInternal ? undefined : id;
return (
<BaseEdge
id={_id}
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
}
const SimpleBezierEdge = createSimpleBezierEdge({ isInternal: false });
const SimpleBezierEdgeInternal = createSimpleBezierEdge({ isInternal: true });
SimpleBezierEdge.displayName = 'SimpleBezierEdge';
SimpleBezierEdgeInternal.displayName = 'SimpleBezierEdgeInternal';
export default SimpleBezierEdge;
export { SimpleBezierEdge, SimpleBezierEdgeInternal };
@@ -4,57 +4,68 @@ import { Position, getSmoothStepPath } from '@xyflow/system';
import BaseEdge from './BaseEdge';
import type { SmoothStepEdgeProps } from '../../types';
const SmoothStepEdge = memo(
({
sourceX,
sourceY,
targetX,
targetY,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
markerEnd,
markerStart,
pathOptions,
interactionWidth,
}: SmoothStepEdgeProps) => {
const [path, labelX, labelY] = getSmoothStepPath({
function createSmoothStepEdge(params: { isInternal: boolean }) {
// eslint-disable-next-line react/display-name
return memo(
({
id,
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
borderRadius: pathOptions?.borderRadius,
offset: pathOptions?.offset,
});
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
sourcePosition = Position.Bottom,
targetPosition = Position.Top,
markerEnd,
markerStart,
pathOptions,
interactionWidth,
}: SmoothStepEdgeProps) => {
const [path, labelX, labelY] = getSmoothStepPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
borderRadius: pathOptions?.borderRadius,
offset: pathOptions?.offset,
});
return (
<BaseEdge
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
const _id = params.isInternal ? undefined : id;
return (
<BaseEdge
id={_id}
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
}
const SmoothStepEdge = createSmoothStepEdge({ isInternal: false });
const SmoothStepEdgeInternal = createSmoothStepEdge({ isInternal: true });
SmoothStepEdge.displayName = 'SmoothStepEdge';
SmoothStepEdgeInternal.displayName = 'SmoothStepEdgeInternal';
export default SmoothStepEdge;
export { SmoothStepEdge, SmoothStepEdgeInternal };
@@ -1,15 +1,30 @@
import { memo, useMemo } from 'react';
import SmoothStepEdge from './SmoothStepEdge';
import type { SmoothStepEdgeProps } from '../../types';
import { SmoothStepEdge } from './SmoothStepEdge';
import type { StepEdgeProps } from '../../types';
const StepEdge = memo((props: SmoothStepEdgeProps) => (
<SmoothStepEdge
{...props}
pathOptions={useMemo(() => ({ borderRadius: 0, offset: props.pathOptions?.offset }), [props.pathOptions?.offset])}
/>
));
function createStepEdge(params: { isInternal: boolean }) {
// eslint-disable-next-line react/display-name
return memo(({ id, ...props }: StepEdgeProps) => {
const _id = params.isInternal ? undefined : id;
return (
<SmoothStepEdge
{...props}
id={_id}
pathOptions={useMemo(
() => ({ borderRadius: 0, offset: props.pathOptions?.offset }),
[props.pathOptions?.offset]
)}
/>
);
});
}
const StepEdge = createStepEdge({ isInternal: false });
const StepEdgeInternal = createStepEdge({ isInternal: true });
StepEdge.displayName = 'StepEdge';
StepEdgeInternal.displayName = 'StepEdgeInternal';
export default StepEdge;
export { StepEdge, StepEdgeInternal };
@@ -2,47 +2,58 @@ import { memo } from 'react';
import { getStraightPath } from '@xyflow/system';
import BaseEdge from './BaseEdge';
import type { EdgeProps } from '../../types';
import type { StraightEdgeProps } from '../../types';
const StraightEdge = memo(
({
sourceX,
sourceY,
targetX,
targetY,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
interactionWidth,
}: EdgeProps) => {
const [path, labelX, labelY] = getStraightPath({ sourceX, sourceY, targetX, targetY });
function createStraightEdge(params: { isInternal: boolean }) {
// eslint-disable-next-line react/display-name
return memo(
({
id,
sourceX,
sourceY,
targetX,
targetY,
label,
labelStyle,
labelShowBg,
labelBgStyle,
labelBgPadding,
labelBgBorderRadius,
style,
markerEnd,
markerStart,
interactionWidth,
}: StraightEdgeProps) => {
const [path, labelX, labelY] = getStraightPath({ sourceX, sourceY, targetX, targetY });
return (
<BaseEdge
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
const _id = params.isInternal ? undefined : id;
return (
<BaseEdge
id={_id}
path={path}
labelX={labelX}
labelY={labelY}
label={label}
labelStyle={labelStyle}
labelShowBg={labelShowBg}
labelBgStyle={labelBgStyle}
labelBgPadding={labelBgPadding}
labelBgBorderRadius={labelBgBorderRadius}
style={style}
markerEnd={markerEnd}
markerStart={markerStart}
interactionWidth={interactionWidth}
/>
);
}
);
}
const StraightEdge = createStraightEdge({ isInternal: false });
const StraightEdgeInternal = createStraightEdge({ isInternal: true });
StraightEdge.displayName = 'StraightEdge';
StraightEdgeInternal.displayName = 'StraightEdgeInternal';
export default StraightEdge;
export { StraightEdge, StraightEdgeInternal };
+9 -5
View File
@@ -1,5 +1,9 @@
export { default as SimpleBezierEdge } from './SimpleBezierEdge';
export { default as SmoothStepEdge } from './SmoothStepEdge';
export { default as StepEdge } from './StepEdge';
export { default as StraightEdge } from './StraightEdge';
export { default as BezierEdge } from './BezierEdge';
// We distinguish between internal and exported edges
// The internal edges are used directly like custom edges and always get an id, source and target props
// If you import an edge from the library, the id is optional and source and target are not used at all
export { SimpleBezierEdge, SimpleBezierEdgeInternal } from './SimpleBezierEdge';
export { SmoothStepEdge, SmoothStepEdgeInternal } from './SmoothStepEdge';
export { StepEdge, StepEdgeInternal } from './StepEdge';
export { StraightEdge, StraightEdgeInternal } from './StraightEdge';
export { BezierEdge, BezierEdgeInternal } from './BezierEdge';
@@ -171,7 +171,7 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
lib,
});
if (isValid) {
if (isValid && connection) {
onConnectExtended(connection);
}
@@ -1,6 +1,12 @@
import type { ComponentType } from 'react';
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge, SimpleBezierEdge } from '../../components/Edges';
import {
BezierEdgeInternal,
SmoothStepEdgeInternal,
StepEdgeInternal,
StraightEdgeInternal,
SimpleBezierEdgeInternal,
} from '../../components/Edges';
import wrapEdge from '../../components/Edges/wrapEdge';
import type { EdgeProps, EdgeTypes, EdgeTypesWrapped } from '../../types';
@@ -8,18 +14,18 @@ export type CreateEdgeTypes = (edgeTypes: EdgeTypes) => EdgeTypesWrapped;
export function createEdgeTypes(edgeTypes: EdgeTypes): EdgeTypesWrapped {
const standardTypes: EdgeTypesWrapped = {
default: wrapEdge((edgeTypes.default || BezierEdge) as ComponentType<EdgeProps>),
straight: wrapEdge((edgeTypes.bezier || StraightEdge) as ComponentType<EdgeProps>),
step: wrapEdge((edgeTypes.step || StepEdge) as ComponentType<EdgeProps>),
smoothstep: wrapEdge((edgeTypes.step || SmoothStepEdge) as ComponentType<EdgeProps>),
simplebezier: wrapEdge((edgeTypes.simplebezier || SimpleBezierEdge) as ComponentType<EdgeProps>),
default: wrapEdge((edgeTypes.default || BezierEdgeInternal) as ComponentType<EdgeProps>),
straight: wrapEdge((edgeTypes.bezier || StraightEdgeInternal) as ComponentType<EdgeProps>),
step: wrapEdge((edgeTypes.step || StepEdgeInternal) as ComponentType<EdgeProps>),
smoothstep: wrapEdge((edgeTypes.step || SmoothStepEdgeInternal) as ComponentType<EdgeProps>),
simplebezier: wrapEdge((edgeTypes.simplebezier || SimpleBezierEdgeInternal) as ComponentType<EdgeProps>),
};
const wrappedTypes = {} as EdgeTypesWrapped;
const specialTypes: EdgeTypesWrapped = Object.keys(edgeTypes)
.filter((k) => !['default', 'bezier'].includes(k))
.reduce((res, key) => {
res[key] = wrapEdge((edgeTypes[key] || BezierEdge) as ComponentType<EdgeProps>);
res[key] = wrapEdge((edgeTypes[key] || BezierEdgeInternal) as ComponentType<EdgeProps>);
return res;
}, wrappedTypes);
@@ -12,7 +12,13 @@ import {
} from '@xyflow/system';
import Attribution from '../../components/Attribution';
import { BezierEdge, SmoothStepEdge, StepEdge, StraightEdge, SimpleBezierEdge } from '../../components/Edges';
import {
BezierEdgeInternal,
SmoothStepEdgeInternal,
StepEdgeInternal,
StraightEdgeInternal,
SimpleBezierEdgeInternal,
} from '../../components/Edges';
import DefaultNode from '../../components/Nodes/DefaultNode';
import InputNode from '../../components/Nodes/InputNode';
import OutputNode from '../../components/Nodes/OutputNode';
@@ -33,11 +39,11 @@ const defaultNodeTypes: NodeTypes = {
};
const defaultEdgeTypes: EdgeTypes = {
default: BezierEdge,
straight: StraightEdge,
step: StepEdge,
smoothstep: SmoothStepEdge,
simplebezier: SimpleBezierEdge,
default: BezierEdgeInternal,
straight: StraightEdgeInternal,
step: StepEdgeInternal,
smoothstep: SmoothStepEdgeInternal,
simplebezier: SimpleBezierEdgeInternal,
};
const initNodeOrigin: NodeOrigin = [0, 0];
@@ -0,0 +1,54 @@
import { useEffect, useMemo, useRef } from 'react';
import { Connection, HandleType, areConnectionMapsEqual, handleConnectionChange } from '@xyflow/system';
import { useStore } from './useStore';
import { useNodeId } from '../contexts/NodeIdContext';
type useHandleConnectionsParams = {
type: HandleType;
id?: string | null;
nodeId?: string;
onConnect?: (connections: Connection[]) => void;
onDisconnect?: (connections: Connection[]) => void;
};
/**
* Hook to check if a <Handle /> is connected to another <Handle /> and get the connections.
*
* @public
* @param param.type - handle type 'source' or 'target'
* @param param.id - the handle id (this is only needed if the node has multiple handles of the same type)
* @param param.nodeId - node id - if not provided, the node id from the NodeIdContext is used
* @param param.onConnect - gets called when a connection is established
* @param param.onDisconnect - gets called when a connection is removed
* @returns an array with connections
*/
export function useHandleConnections({
type,
id = null,
nodeId,
onConnect,
onDisconnect,
}: useHandleConnectionsParams): Connection[] {
const _nodeId = useNodeId();
const prevConnections = useRef<Map<string, Connection> | null>(null);
const currentNodeId = nodeId || _nodeId;
const connections = useStore(
(state) => state.connectionLookup.get(`${currentNodeId}-${type}-${id}`),
areConnectionMapsEqual
);
useEffect(() => {
// @todo dicuss if onConnect/onDisconnect should be called when the component mounts/unmounts
if (prevConnections.current && prevConnections.current !== connections) {
const _connections = connections ?? new Map();
handleConnectionChange(prevConnections.current, _connections, onDisconnect);
handleConnectionChange(_connections, prevConnections.current, onConnect);
}
prevConnections.current = connections ?? new Map();
}, [connections, onConnect, onDisconnect]);
return useMemo(() => Array.from(connections?.values() ?? []), [connections]);
}
+40
View File
@@ -0,0 +1,40 @@
import { useCallback } from 'react';
import { shallow } from 'zustand/shallow';
import { useStore } from '../hooks/useStore';
import type { Node } from '../types';
export function useNodesData<NodeType extends Node = Node>(nodeId: string): NodeType['data'] | null;
export function useNodesData<NodeType extends Node = Node>(nodeIds: string[]): NodeType['data'][];
export function useNodesData<NodeType extends Node = Node>(
nodeIds: string[],
guard: (node: Node) => node is NodeType
): NodeType['data'][];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useNodesData(nodeIds: any): any {
const nodesData = useStore(
useCallback(
(s) => {
if (!Array.isArray(nodeIds)) {
return s.nodeLookup.get(nodeIds)?.data || null;
}
const data = [];
for (const nodeId of nodeIds) {
const nodeData = s.nodeLookup.get(nodeId)?.data;
if (nodeData) {
data.push(nodeData);
}
}
return data;
},
[nodeIds]
),
shallow
);
return nodesData;
}
+34 -1
View File
@@ -10,7 +10,7 @@ import {
} from '@xyflow/system';
import useViewportHelper from './useViewportHelper';
import { useStoreApi } from '../hooks/useStore';
import { useStoreApi } from './useStore';
import type {
ReactFlowInstance,
Instance,
@@ -24,6 +24,7 @@ import type {
Node,
Edge,
} from '../types';
import { isNode } from '../utils';
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlowInstance<NodeData, EdgeData> {
@@ -271,6 +272,36 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
return getOutgoersBase(node, nodes, edges);
}, []);
const updateNode = useCallback<Instance.UpdateNode>(
(id, nodeUpdate, options = { replace: true }) => {
setNodes((prevNodes) =>
prevNodes.map((node) => {
if (node.id === id) {
const nextNode = typeof nodeUpdate === 'function' ? nodeUpdate(node as Node) : nodeUpdate;
return options.replace && isNode(nextNode) ? nextNode : { ...node, ...nextNode };
}
return node;
})
);
},
[setNodes]
);
const updateNodeData = useCallback<Instance.UpdateNodeData>(
(id, dataUpdate, options = { replace: false }) => {
updateNode(
id,
(node) => {
const nextData = typeof dataUpdate === 'function' ? dataUpdate(node) : dataUpdate;
return options.replace ? { ...node, data: nextData } : { ...node, data: { ...node.data, ...nextData } };
},
options
);
},
[updateNode]
);
return useMemo(() => {
return {
...viewportHelper,
@@ -289,6 +320,8 @@ export default function useReactFlow<NodeData = any, EdgeData = any>(): ReactFlo
getConnectedEdges,
getIncomers,
getOutgoers,
updateNode,
updateNodeData,
};
}, [
viewportHelper,
+8 -6
View File
@@ -1,11 +1,11 @@
export { default as ReactFlow } from './container/ReactFlow';
export { default as Handle } from './components/Handle';
export { default as Handle, type HandleComponentProps } from './components/Handle';
export { default as EdgeText } from './components/Edges/EdgeText';
export { default as StraightEdge } from './components/Edges/StraightEdge';
export { default as StepEdge } from './components/Edges/StepEdge';
export { default as BezierEdge } from './components/Edges/BezierEdge';
export { default as SimpleBezierEdge, getSimpleBezierPath } from './components/Edges/SimpleBezierEdge';
export { default as SmoothStepEdge } from './components/Edges/SmoothStepEdge';
export { StraightEdge } from './components/Edges/StraightEdge';
export { StepEdge } from './components/Edges/StepEdge';
export { BezierEdge } from './components/Edges/BezierEdge';
export { SimpleBezierEdge, getSimpleBezierPath } from './components/Edges/SimpleBezierEdge';
export { SmoothStepEdge } from './components/Edges/SmoothStepEdge';
export { default as BaseEdge } from './components/Edges/BaseEdge';
export { default as ReactFlowProvider } from './components/ReactFlowProvider';
export { default as Panel, type PanelProps } from './components/Panel';
@@ -22,6 +22,8 @@ export { useStore, useStoreApi } from './hooks/useStore';
export { default as useOnViewportChange, type UseOnViewportChangeOptions } from './hooks/useOnViewportChange';
export { default as useOnSelectionChange, type UseOnSelectionChangeOptions } from './hooks/useOnSelectionChange';
export { default as useNodesInitialized, type UseNodesInitializedOptions } from './hooks/useNodesInitialized';
export { useHandleConnections } from './hooks/useHandleConnections';
export { useNodesData } from './hooks/useNodesData';
export { useNodeId } from './contexts/NodeIdContext';
export { applyNodeChanges, applyEdgeChanges, handleParentExpand } from './utils/changes';
+8 -2
View File
@@ -7,6 +7,7 @@ import {
panBy as panBySystem,
Dimensions,
updateNodeDimensions as updateNodeDimensionsSystem,
updateConnectionLookup,
} from '@xyflow/system';
import { applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes';
@@ -54,8 +55,12 @@ const createRFStore = ({
set({ nodes: nodesWithInternalData });
},
setEdges: (edges: Edge[]) => {
const { defaultEdgeOptions = {} } = get();
set({ edges: edges.map((e) => ({ ...defaultEdgeOptions, ...e })) });
const { defaultEdgeOptions = {}, connectionLookup } = get();
const nextEdges = edges.map((e) => ({ ...defaultEdgeOptions, ...e }));
updateConnectionLookup(connectionLookup, nextEdges);
set({ edges: nextEdges });
},
// when the user works with an uncontrolled flow,
// we set a flag `hasDefaultNodes` / `hasDefaultEdges`
@@ -332,6 +337,7 @@ const createRFStore = ({
set(currentConnection);
},
reset: () => {
// @todo: what should we do about this? Do we still need it?
// if you are on a SPA with multiple flows, we want to make sure that the store gets resetted
+4 -1
View File
@@ -5,6 +5,7 @@ import {
getNodesBounds,
getViewportForBounds,
Transform,
updateConnectionLookup,
} from '@xyflow/system';
import type { Edge, Node, ReactFlowStore } from '../types';
@@ -22,7 +23,8 @@ const getInitialState = ({
height?: number;
fitView?: boolean;
} = {}): ReactFlowStore => {
const nodeLookup = new Map<string, Node>();
const nodeLookup = new Map();
const connectionLookup = updateConnectionLookup(new Map(), edges);
const nextNodes = adoptUserProvidedNodes(nodes, nodeLookup, { nodeOrigin: [0, 0], elevateNodesOnSelect: false });
let transform: Transform = [0, 0, 1];
@@ -42,6 +44,7 @@ const getInitialState = ({
nodes: nextNodes,
nodeLookup,
edges: edges,
connectionLookup,
onNodesChange: null,
onEdgesChange: null,
hasDefaultNodes: false,
+20 -3
View File
@@ -13,6 +13,8 @@ import type {
HandleElement,
ConnectionStatus,
EdgePosition,
Optional,
StepPathOptions,
} from '@xyflow/system';
import { Node } from '.';
@@ -46,7 +48,12 @@ type BezierEdgeType<T> = DefaultEdge<T> & {
pathOptions?: BezierPathOptions;
};
export type Edge<T = any> = DefaultEdge<T> | SmoothStepEdgeType<T> | BezierEdgeType<T>;
type StepEdgeType<T> = DefaultEdge<T> & {
type: 'step';
pathOptions?: StepPathOptions;
};
export type Edge<T = any> = DefaultEdge<T> | SmoothStepEdgeType<T> | BezierEdgeType<T> | StepEdgeType<T>;
export type EdgeMouseHandler = (event: ReactMouseEvent, edge: Edge) => void;
@@ -100,14 +107,24 @@ export type BaseEdgeProps = Pick<EdgeProps, 'style' | 'markerStart' | 'markerEnd
path: string;
};
export type SmoothStepEdgeProps<T = any> = EdgeProps<T> & {
export type EdgeComponentProps<T = any> = Optional<Omit<EdgeProps<T>, 'source' | 'target'>, 'id'>;
export type StraightEdgeProps<T = any> = Omit<EdgeComponentProps<T>, 'sourcePosition' | 'targetPosition'>;
export type SmoothStepEdgeProps<T = any> = EdgeComponentProps<T> & {
pathOptions?: SmoothStepPathOptions;
};
export type BezierEdgeProps<T = any> = EdgeProps<T> & {
export type BezierEdgeProps<T = any> = EdgeComponentProps<T> & {
pathOptions?: BezierPathOptions;
};
export type StepEdgeProps<T = any> = EdgeComponentProps<T> & {
pathOptions?: StepPathOptions;
};
export type SimpleBezierEdgeProps<T = any> = EdgeComponentProps<T>;
export type OnEdgeUpdateFunc<T = any> = (oldEdge: Edge<T>, newConnection: Connection) => void;
export type ConnectionLineComponentProps = {
+13
View File
@@ -45,6 +45,17 @@ export namespace Instance {
export type getConnectedEdges = (id: string | (Node | { id: Node['id'] })[]) => Edge[];
export type getIncomers = (node: string | Node | { id: Node['id'] }) => Node[];
export type getOutgoers = (node: string | Node | { id: Node['id'] }) => Node[];
export type UpdateNode = (
id: string,
dataUpdate: Partial<Node> | ((node: Node) => Partial<Node>),
options?: { replace: boolean }
) => void;
export type UpdateNodeData = (
id: string,
dataUpdate: object | ((node: Node) => object),
options?: { replace: boolean }
) => void;
}
export type ReactFlowInstance<NodeData = any, EdgeData = any> = {
@@ -60,5 +71,7 @@ export type ReactFlowInstance<NodeData = any, EdgeData = any> = {
deleteElements: Instance.DeleteElements;
getIntersectingNodes: Instance.GetIntersectingNodes<NodeData>;
isNodeIntersecting: Instance.IsNodeIntersecting<NodeData>;
updateNode: Instance.UpdateNode;
updateNodeData: Instance.UpdateNodeData;
viewportInitialized: boolean;
} & Omit<ViewportHelperFunctions, 'initialized'>;
+3
View File
@@ -24,6 +24,7 @@ import {
type OnMoveEnd,
type IsValidConnection,
type UpdateConnection,
Connection,
} from '@xyflow/system';
import type {
@@ -49,6 +50,8 @@ export type ReactFlowStore = {
nodes: Node[];
nodeLookup: Map<string, Node>;
edges: Edge[];
connectionLookup: Map<string, Map<string, Connection>>;
onNodesChange: OnNodesChange | null;
onEdgesChange: OnEdgesChange | null;
hasDefaultNodes: boolean;
+2 -2
View File
@@ -10,8 +10,8 @@ import {
import type { Edge, Node } from '../types';
export const isNode = isNodeBase<Node, Edge>;
export const isEdge = isEdgeBase<Node, Edge>;
export const isNode = isNodeBase<Node>;
export const isEdge = isEdgeBase<Edge>;
export const getOutgoers = getOutgoersBase<Node, Edge>;
export const getIncomers = getIncomersBase<Node, Edge>;
export const addEdge = addEdgeBase<Edge>;