Merge branch 'next' into absolute-origin

This commit is contained in:
moklick
2024-06-27 17:03:58 +02:00
15 changed files with 130 additions and 125 deletions
@@ -7,7 +7,6 @@ import {
ConnectionMode,
getBezierPath,
getSmoothStepPath,
type ConnectionStatus,
type HandleType,
} from '@xyflow/system';
@@ -15,13 +14,21 @@ import { useStore } from '../../hooks/useStore';
import { getSimpleBezierPath } from '../Edges/SimpleBezierEdge';
import type { ConnectionLineComponent, ReactFlowState, ReactFlowStore } from '../../types';
function getConnectionStatus(isValid: boolean | null) {
if (isValid === null) {
return null;
}
return isValid ? 'valid' : 'invalid';
}
type ConnectionLineProps = {
nodeId: string;
handleType: HandleType;
type: ConnectionLineType;
style?: CSSProperties;
CustomComponent?: ConnectionLineComponent;
connectionStatus: ConnectionStatus | null;
isValid: boolean | null;
};
const oppositePosition = {
@@ -37,18 +44,17 @@ const ConnectionLine = ({
style,
type = ConnectionLineType.Bezier,
CustomComponent,
connectionStatus,
isValid,
}: ConnectionLineProps) => {
const { fromNode, handleId, toX, toY, connectionMode, endPosition, isValid } = useStore(
const { fromNode, startHandle, endHandle, toX, toY, connectionMode } = useStore(
useCallback(
(s: ReactFlowStore) => ({
fromNode: s.nodeLookup.get(nodeId),
handleId: s.connectionStartHandle?.handleId,
toX: (s.connectionPosition.x - s.transform[0]) / s.transform[2],
toY: (s.connectionPosition.y - s.transform[1]) / s.transform[2],
startHandle: s.connection.fromHandle,
endHandle: s.connection.toHandle,
toX: (s.connection.position.x - s.transform[0]) / s.transform[2],
toY: (s.connection.position.y - s.transform[1]) / s.transform[2],
connectionMode: s.connectionMode,
endPosition: s.connectionEndHandle?.position,
isValid: s.connectionStatus === 'valid',
}),
[nodeId]
),
@@ -66,13 +72,15 @@ const ConnectionLine = ({
return null;
}
const handleId = startHandle?.handleId;
const fromHandle = handleId ? handleBounds.find((d) => d.id === handleId) : handleBounds[0];
const fromHandleX = fromHandle ? fromHandle.x + fromHandle.width / 2 : (fromNode.measured.width ?? 0) / 2;
const fromHandleY = fromHandle ? fromHandle.y + fromHandle.height / 2 : fromNode.measured.height ?? 0;
const fromX = fromNode.internals.positionAbsolute.x + fromHandleX;
const fromY = fromNode.internals.positionAbsolute.y + fromHandleY;
const fromPosition = fromHandle?.position;
const toPosition = isValid && endPosition ? endPosition : fromPosition ? oppositePosition[fromPosition] : null;
const toPosition =
isValid && endHandle?.position ? endHandle.position : fromPosition ? oppositePosition[fromPosition] : null;
if (!fromPosition || !toPosition) {
return null;
@@ -83,7 +91,7 @@ const ConnectionLine = ({
<CustomComponent
connectionLineType={type}
connectionLineStyle={style}
fromNode={fromNode}
fromNode={fromNode.internals.userNode}
fromHandle={fromHandle}
fromX={fromX}
fromY={fromY}
@@ -91,7 +99,7 @@ const ConnectionLine = ({
toY={toY}
fromPosition={fromPosition}
toPosition={toPosition}
connectionStatus={connectionStatus}
connectionStatus={getConnectionStatus(isValid)}
/>
);
}
@@ -136,19 +144,19 @@ type ConnectionLineWrapperProps = {
};
const selector = (s: ReactFlowState) => ({
nodeId: s.connectionStartHandle?.nodeId,
handleType: s.connectionStartHandle?.type,
nodeId: s.connection.fromHandle?.nodeId,
handleType: s.connection.fromHandle?.type,
nodesConnectable: s.nodesConnectable,
connectionStatus: s.connectionStatus,
isValid: s.connection.isValid,
width: s.width,
height: s.height,
});
export function ConnectionLineWrapper({ containerStyle, style, type, component }: ConnectionLineWrapperProps) {
const { nodeId, handleType, nodesConnectable, width, height, connectionStatus } = useStore(selector, shallow);
const isValid = !!(nodeId && handleType && width && nodesConnectable);
const { nodeId, handleType, nodesConnectable, width, height, isValid } = useStore(selector, shallow);
const renderConnectionLine = !!(nodeId && handleType && width && nodesConnectable);
if (!isValid) {
if (!renderConnectionLine) {
return null;
}
@@ -159,14 +167,14 @@ export function ConnectionLineWrapper({ containerStyle, style, type, component }
height={height}
className="react-flow__connectionline react-flow__container"
>
<g className={cc(['react-flow__connection', connectionStatus])}>
<g className={cc(['react-flow__connection', getConnectionStatus(isValid)])}>
<ConnectionLine
nodeId={nodeId}
handleType={handleType}
style={style}
type={type}
CustomComponent={component}
connectionStatus={connectionStatus}
isValid={isValid}
/>
</g>
</svg>
@@ -96,7 +96,7 @@ export function EdgeUpdateAnchors<EdgeType extends Edge = Edge>({
onReconnectEnd: _onReconnectEnd,
updateConnection,
getTransform: () => store.getState().transform,
getConnectionStartHandle: () => store.getState().connectionStartHandle,
getFromHandle: () => store.getState().connection.fromHandle,
});
};
+10 -15
View File
@@ -39,28 +39,23 @@ const selector = (s: ReactFlowState) => ({
const connectingSelector =
(nodeId: string | null, handleId: string | null, type: HandleType) => (state: ReactFlowState) => {
const {
connectionStartHandle: startHandle,
connectionEndHandle: endHandle,
connectionClickStartHandle: clickHandle,
connectionMode,
connectionStatus,
} = state;
const { connectionClickStartHandle: clickHandle, connectionMode, connection } = state;
const connectingTo = endHandle?.nodeId === nodeId && endHandle?.handleId === handleId && endHandle?.type === type;
const { fromHandle, toHandle, isValid } = connection;
const connectingTo = toHandle?.nodeId === nodeId && toHandle?.handleId === handleId && toHandle?.type === type;
return {
connectingFrom:
startHandle?.nodeId === nodeId && startHandle?.handleId === handleId && startHandle?.type === type,
connectingFrom: fromHandle?.nodeId === nodeId && fromHandle?.handleId === handleId && fromHandle?.type === type,
connectingTo,
clickConnecting:
clickHandle?.nodeId === nodeId && clickHandle?.handleId === handleId && clickHandle?.type === type,
isPossibleEndHandle:
connectionMode === ConnectionMode.Strict
? startHandle?.type !== type
: nodeId !== startHandle?.nodeId || handleId !== startHandle?.handleId,
connectionInProcess: !!startHandle,
valid: connectingTo && connectionStatus === 'valid',
? fromHandle?.type !== type
: nodeId !== fromHandle?.nodeId || handleId !== fromHandle?.handleId,
connectionInProcess: !!fromHandle,
valid: connectingTo && isValid,
};
};
@@ -144,7 +139,7 @@ function HandleComponent(
onConnect: onConnectExtended,
isValidConnection: isValidConnection || currentStore.isValidConnection,
getTransform: () => store.getState().transform,
getConnectionStartHandle: () => store.getState().connectionStartHandle,
getFromHandle: () => store.getState().connection.fromHandle,
});
}
+5 -19
View File
@@ -2,33 +2,19 @@ import { shallow } from 'zustand/shallow';
import { useStore } from './useStore';
import type { ReactFlowStore } from '../types/store';
import { ConnectionState } from '@xyflow/system';
const selector = (s: ReactFlowStore) => ({
startHandle: s.connectionStartHandle,
endHandle: s.connectionEndHandle,
status: s.connectionStatus,
position: s.connectionStartHandle ? s.connectionPosition : null,
...s.connection,
inProgress: s.connection.fromHandle !== null,
});
type UseConnectionResult = {
/** The start handle where the user interaction started or null */
startHandle: ReactFlowStore['connectionStartHandle'];
/** The target handle that's inside the connection radius or null */
endHandle: ReactFlowStore['connectionEndHandle'];
/** The current connection status 'valid', 'invalid' or null*/
status: ReactFlowStore['connectionStatus'];
/** The current connection position or null */
position: ReactFlowStore['connectionPosition'] | null;
};
/**
* Hook for accessing the ongoing connection.
*
* @public
* @returns ongoing connection
*/
export function useConnection(): UseConnectionResult {
const ongoingConnection = useStore(selector, shallow);
return ongoingConnection;
export function useConnection(): ConnectionState & { inProgress: boolean } {
return useStore(selector, shallow);
}
-1
View File
@@ -49,7 +49,6 @@ export {
type OnMoveStart,
type OnMoveEnd,
type Connection,
type ConnectionStatus,
ConnectionMode,
type OnConnectStartParams,
type OnConnectStart,
+15 -8
View File
@@ -309,18 +309,25 @@ const createStore = ({
options
);
},
cancelConnection: () =>
cancelConnection: () => {
const { connection } = get();
set({
connectionStatus: null,
connectionStartHandle: null,
connectionEndHandle: null,
}),
connection: {
position: connection.position,
fromHandle: null,
toHandle: null,
isValid: null,
},
});
},
updateConnection: (params) => {
const { connectionPosition } = get();
const { connection } = get();
const currentConnection = {
...params,
connectionPosition: params.connectionPosition ?? connectionPosition,
connection: {
...params,
position: params.position ?? connection.position,
},
};
set(currentConnection);
+6 -4
View File
@@ -79,8 +79,6 @@ const getInitialState = ({
nodesSelectionActive: false,
userSelectionActive: false,
userSelectionRect: null,
connectionPosition: { x: 0, y: 0 },
connectionStatus: null,
connectionMode: ConnectionMode.Strict,
domNode: null,
paneDragging: false,
@@ -106,8 +104,12 @@ const getInitialState = ({
multiSelectionActive: false,
connectionStartHandle: null,
connectionEndHandle: null,
connection: {
fromHandle: null,
toHandle: null,
position: { x: 0, y: 0 },
isValid: null,
},
connectionClickStartHandle: null,
connectOnClick: true,
+1 -2
View File
@@ -11,7 +11,6 @@ import type {
Connection,
ConnectionLineType,
HandleElement,
ConnectionStatus,
EdgePosition,
StepPathOptions,
OnError,
@@ -202,7 +201,7 @@ export type ConnectionLineComponentProps = {
toY: number;
fromPosition: Position;
toPosition: Position;
connectionStatus: ConnectionStatus | null;
connectionStatus: 'valid' | 'invalid' | null;
};
export type ConnectionLineComponent = ComponentType<ConnectionLineComponentProps>;
+6 -11
View File
@@ -1,6 +1,6 @@
import {
ConnectionMode,
type ConnectionStatus,
type ConnectionState,
type CoordinateExtent,
type InternalNodeUpdate,
type UpdateNodePositions,
@@ -12,7 +12,6 @@ import {
type SnapGrid,
type ConnectingHandle,
type Transform,
type XYPosition,
type PanZoomInstance,
type PanBy,
type OnConnectStart,
@@ -25,9 +24,9 @@ import {
type EdgeLookup,
type ConnectionLookup,
type NodeLookup,
NodeChange,
EdgeChange,
ParentLookup,
type NodeChange,
type EdgeChange,
type ParentLookup,
} from '@xyflow/system';
import type {
@@ -79,9 +78,9 @@ export type ReactFlowStore<NodeType extends Node = Node, EdgeType extends Edge =
userSelectionActive: boolean;
userSelectionRect: SelectionRect | null;
connectionPosition: XYPosition;
connectionStatus: ConnectionStatus | null;
connection: ConnectionState;
connectionMode: ConnectionMode;
connectionClickStartHandle: ConnectingHandle | null;
snapToGrid: boolean;
snapGrid: SnapGrid;
@@ -98,10 +97,6 @@ export type ReactFlowStore<NodeType extends Node = Node, EdgeType extends Edge =
multiSelectionActive: boolean;
connectionStartHandle: ConnectingHandle | null;
connectionEndHandle: ConnectingHandle | null;
connectionClickStartHandle: ConnectingHandle | null;
onNodeDragStart?: OnNodeDrag<NodeType>;
onNodeDrag?: OnNodeDrag<NodeType>;
onNodeDragStop?: OnNodeDrag<NodeType>;