Merge branch 'main' into feat/packages
This commit is contained in:
@@ -1,12 +1,21 @@
|
||||
# @reactflow/core
|
||||
|
||||
## 11.7.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#3043](https://github.com/wbkd/react-flow/pull/3043) [`cf7a7d3d`](https://github.com/wbkd/react-flow/commit/cf7a7d3dad1e73215a72a5dc72e21fd50208cdbb) - handles: handles on top of each other, reduce re-renderings
|
||||
- [#3046](https://github.com/wbkd/react-flow/pull/3046) [`07b975bb`](https://github.com/wbkd/react-flow/commit/07b975bbee3580249e36a19582213b250f78093c) - base-edge: pass id to base edge path
|
||||
- [#3007](https://github.com/wbkd/react-flow/pull/3007) [`c80d269b`](https://github.com/wbkd/react-flow/commit/c80d269b85a0054221f4639c328fc36a3befbe70) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - allow array of ids as updateNodeInternals arg
|
||||
- [#3029](https://github.com/wbkd/react-flow/pull/3029) [`a3fa164c`](https://github.com/wbkd/react-flow/commit/a3fa164c34cc820c79bb031c9fd97b72a3546614) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - autopan: only update nodes when transform change happen
|
||||
|
||||
## 11.7.0
|
||||
|
||||
Most notable updates:
|
||||
|
||||
- Handles: `isConnectableStart` and `isConnectableEnd` props to configure if you can start or end a connection at a certain handle
|
||||
- Edges: `updatable` option to enable updates for specific edges
|
||||
- useNodesInitialized: options to configure if hidden nodes should be included (false by default)
|
||||
- useNodesInitialized: options to configure if hidden nodes should be included (false by default)
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -20,7 +29,6 @@ Most notable updates:
|
||||
- [#2933](https://github.com/wbkd/react-flow/pull/2933) [`fe8cac0a`](https://github.com/wbkd/react-flow/commit/fe8cac0adb359109e0e9eafe8b9261ba354076bb) - prefix error keys with "error"
|
||||
- [#2939](https://github.com/wbkd/react-flow/pull/2939) [`4a4ca171`](https://github.com/wbkd/react-flow/commit/4a4ca171955f5c8d58b23e3ad48406f1a21dc402) - add connection result to store
|
||||
|
||||
|
||||
## 11.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@reactflow/core",
|
||||
"version": "11.7.0",
|
||||
"version": "11.7.1",
|
||||
"description": "Core components and util functions of React Flow.",
|
||||
"keywords": [
|
||||
"react",
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { BaseEdgeProps } from '../../types';
|
||||
import EdgeText from './EdgeText';
|
||||
|
||||
const BaseEdge = ({
|
||||
id,
|
||||
path,
|
||||
labelX,
|
||||
labelY,
|
||||
@@ -22,6 +23,7 @@ const BaseEdge = ({
|
||||
return (
|
||||
<>
|
||||
<path
|
||||
id={id}
|
||||
style={style}
|
||||
d={path}
|
||||
fill="none"
|
||||
|
||||
@@ -57,7 +57,7 @@ export function handlePointerDown({
|
||||
cancelConnection,
|
||||
} = getState();
|
||||
let autoPanId = 0;
|
||||
let prevClosestHandle: ConnectionHandle | null;
|
||||
let closestHandle: ConnectionHandle | null;
|
||||
|
||||
const { x, y } = getEventPosition(event.nativeEvent);
|
||||
const clickedHandle = doc?.elementFromPoint(x, y);
|
||||
@@ -112,9 +112,9 @@ export function handlePointerDown({
|
||||
|
||||
function onPointerMove(event: MouseEvent | TouchEvent) {
|
||||
const { transform } = getState();
|
||||
connectionPosition = getEventPosition(event, containerBounds);
|
||||
|
||||
prevClosestHandle = getClosestHandle(
|
||||
connectionPosition = getEventPosition(event, containerBounds);
|
||||
closestHandle = getClosestHandle(
|
||||
pointToRendererPoint(connectionPosition, transform, false, [1, 1]),
|
||||
connectionRadius,
|
||||
handleLookup
|
||||
@@ -127,7 +127,7 @@ export function handlePointerDown({
|
||||
|
||||
const result = isValidHandle(
|
||||
event,
|
||||
prevClosestHandle,
|
||||
closestHandle,
|
||||
connectionMode,
|
||||
nodeId,
|
||||
handleId,
|
||||
@@ -142,20 +142,20 @@ export function handlePointerDown({
|
||||
|
||||
setState({
|
||||
connectionPosition:
|
||||
prevClosestHandle && isValid
|
||||
closestHandle && isValid
|
||||
? rendererPointToPoint(
|
||||
{
|
||||
x: prevClosestHandle.x,
|
||||
y: prevClosestHandle.y,
|
||||
x: closestHandle.x,
|
||||
y: closestHandle.y,
|
||||
},
|
||||
transform
|
||||
)
|
||||
: connectionPosition,
|
||||
connectionStatus: getConnectionStatus(!!prevClosestHandle, isValid),
|
||||
connectionStatus: getConnectionStatus(!!closestHandle, isValid),
|
||||
connectionEndHandle: result.endHandle,
|
||||
});
|
||||
|
||||
if (!prevClosestHandle && !isValid && !handleDomNode) {
|
||||
if (!closestHandle && !isValid && !handleDomNode) {
|
||||
return resetRecentHandle(prevActiveHandle);
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ export function handlePointerDown({
|
||||
}
|
||||
|
||||
function onPointerUp(event: MouseEvent | TouchEvent) {
|
||||
if ((prevClosestHandle || handleDomNode) && connection && isValid) {
|
||||
if ((closestHandle || handleDomNode) && connection && isValid) {
|
||||
onConnect?.(connection);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
|
||||
const store = useStoreApi();
|
||||
const nodeId = useNodeId();
|
||||
const { connectOnClick, noPanClassName } = useStore(selector, shallow);
|
||||
const { connecting, clickConnecting } = useStore(connectingSelector(nodeId, handleId, type));
|
||||
const { connecting, clickConnecting } = useStore(connectingSelector(nodeId, handleId, type), shallow);
|
||||
|
||||
if (!nodeId) {
|
||||
store.getState().onError?.('010', errorMessages['error010']());
|
||||
|
||||
@@ -49,18 +49,30 @@ export function getClosestHandle(
|
||||
connectionRadius: number,
|
||||
handles: ConnectionHandle[]
|
||||
): ConnectionHandle | null {
|
||||
let closestHandle: ConnectionHandle | null = null;
|
||||
let closestHandles: ConnectionHandle[] = [];
|
||||
let minDistance = Infinity;
|
||||
|
||||
handles.forEach((handle) => {
|
||||
const distance = Math.sqrt(Math.pow(handle.x - pos.x, 2) + Math.pow(handle.y - pos.y, 2));
|
||||
if (distance <= connectionRadius && distance < minDistance) {
|
||||
if (distance <= connectionRadius) {
|
||||
if (distance < minDistance) {
|
||||
closestHandles = [handle];
|
||||
} else if (distance === minDistance) {
|
||||
// when multiple handles are on the same distance we collect all of them
|
||||
closestHandles.push(handle);
|
||||
}
|
||||
minDistance = distance;
|
||||
closestHandle = handle;
|
||||
}
|
||||
});
|
||||
|
||||
return closestHandle;
|
||||
if (!closestHandles.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return closestHandles.length === 1
|
||||
? closestHandles[0]
|
||||
: // if multiple handles are layouted on top of each other we take the one with type = target because it's more likely that the user wants to connect to this one
|
||||
closestHandles.find((handle) => handle.type === 'target') || closestHandles[0];
|
||||
}
|
||||
|
||||
type Result = {
|
||||
@@ -89,6 +101,8 @@ export function isValidHandle(
|
||||
);
|
||||
const { x, y } = getEventPosition(event);
|
||||
const handleBelow = doc.elementFromPoint(x, y);
|
||||
// we always want to prioritize the handle below the mouse cursor over the closest distance handle,
|
||||
// because it could be that the center of another handle is closer to the mouse pointer than the handle below the cursor
|
||||
const handleToCheck = handleBelow?.classList.contains('react-flow__handle') ? handleBelow : handleDomNode;
|
||||
|
||||
const result: Result = {
|
||||
|
||||
@@ -119,8 +119,9 @@ function useDrag({
|
||||
lastPos.current.x = (lastPos.current.x ?? 0) - xMovement / transform[2];
|
||||
lastPos.current.y = (lastPos.current.y ?? 0) - yMovement / transform[2];
|
||||
|
||||
updateNodes(lastPos.current as XYPosition);
|
||||
panBy({ x: xMovement, y: yMovement });
|
||||
if (panBy({ x: xMovement, y: yMovement })) {
|
||||
updateNodes(lastPos.current as XYPosition);
|
||||
}
|
||||
}
|
||||
autoPanId.current = requestAnimationFrame(autoPan);
|
||||
};
|
||||
|
||||
@@ -6,13 +6,20 @@ import { useStoreApi } from '../hooks/useStore';
|
||||
function useUpdateNodeInternals(): UpdateNodeInternals {
|
||||
const store = useStoreApi();
|
||||
|
||||
return useCallback<UpdateNodeInternals>((id: string) => {
|
||||
return useCallback<UpdateNodeInternals>((id: string | string[]) => {
|
||||
const { domNode, updateNodeDimensions } = store.getState();
|
||||
const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${id}"]`) as HTMLDivElement;
|
||||
|
||||
if (nodeElement) {
|
||||
requestAnimationFrame(() => updateNodeDimensions([{ id, nodeElement, forceUpdate: true }]));
|
||||
}
|
||||
const updateIds = Array.isArray(id) ? id : [id];
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
updateIds.forEach((updateId) => {
|
||||
const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${updateId}"]`) as HTMLDivElement;
|
||||
|
||||
if (nodeElement) {
|
||||
updateNodeDimensions([{ id: updateId, nodeElement, forceUpdate: true }]);
|
||||
}
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
}
|
||||
|
||||
|
||||
@@ -276,11 +276,11 @@ const createRFStore = () =>
|
||||
nodeInternals: new Map(nodeInternals),
|
||||
});
|
||||
},
|
||||
panBy: (delta: XYPosition) => {
|
||||
panBy: (delta: XYPosition): boolean => {
|
||||
const { transform, width, height, d3Zoom, d3Selection, translateExtent } = get();
|
||||
|
||||
if (!d3Zoom || !d3Selection || (!delta.x && !delta.y)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
const nextTransform = zoomIdentity.translate(transform[0] + delta.x, transform[1] + delta.y).scale(transform[2]);
|
||||
@@ -292,6 +292,13 @@ const createRFStore = () =>
|
||||
|
||||
const constrainedTransform = d3Zoom?.constrain()(nextTransform, extent, translateExtent);
|
||||
d3Zoom.transform(d3Selection, constrainedTransform);
|
||||
|
||||
const transformChanged =
|
||||
transform[0] !== constrainedTransform.x ||
|
||||
transform[1] !== constrainedTransform.y ||
|
||||
transform[2] !== constrainedTransform.k;
|
||||
|
||||
return transformChanged;
|
||||
},
|
||||
cancelConnection: () =>
|
||||
set({
|
||||
|
||||
@@ -109,6 +109,7 @@ export type EdgeProps<T = any> = Pick<
|
||||
|
||||
export type BaseEdgeProps = Pick<EdgeProps, 'style' | 'markerStart' | 'markerEnd' | 'interactionWidth'> &
|
||||
EdgeLabelOptions & {
|
||||
id?: string;
|
||||
labelX?: number;
|
||||
labelY?: number;
|
||||
path: string;
|
||||
|
||||
@@ -149,7 +149,7 @@ export type ReactFlowActions = {
|
||||
cancelConnection: () => void;
|
||||
reset: () => void;
|
||||
triggerNodeChanges: (changes: NodeChange[]) => void;
|
||||
panBy: (delta: XYPosition) => void;
|
||||
panBy: (delta: XYPosition) => boolean;
|
||||
};
|
||||
|
||||
export type ReactFlowState = ReactFlowStore & ReactFlowActions;
|
||||
|
||||
Reference in New Issue
Block a user