refactor(nodes): rename computed to measured, add helpers

This commit is contained in:
moklick
2024-04-03 14:54:24 +02:00
parent f45f50671d
commit ea18e46a1a
32 changed files with 159 additions and 226 deletions
@@ -6,7 +6,7 @@ import { shallow } from 'zustand/shallow';
import { useStore } from '../../hooks/useStore';
import { MiniMapNode } from './MiniMapNode';
import type { ReactFlowState, Node } from '../../types';
import type { ReactFlowState, Node, InternalNode } from '../../types';
import type { MiniMapNodes as MiniMapNodesProps, GetMiniMapNodeAttribute, MiniMapNodeProps } from './types';
declare const window: any;
@@ -85,7 +85,7 @@ function NodeComponentWrapperInner<NodeType extends Node>({
shapeRendering: string;
}) {
const { node, x, y } = useStore((s) => {
const node = s.nodeLookup.get(id) as NodeType;
const node = s.nodeLookup.get(id) as InternalNode<NodeType>;
const { x, y } = getNodePositionWithOrigin(node, node?.origin || nodeOrigin).positionAbsolute;
return {
@@ -5,12 +5,14 @@ import {
ResizeControlVariant,
type XYResizerInstance,
type XYResizerChange,
XYResizerChildChange,
type XYResizerChildChange,
type NodeChange,
type NodeDimensionChange,
type NodePositionChange,
} from '@xyflow/system';
import { useStoreApi } from '../../hooks/useStore';
import { useNodeId } from '../../contexts/NodeIdContext';
import type { NodeChange, NodeDimensionChange, NodePositionChange } from '../../types';
import type { ResizeControlProps, ResizeControlLineProps } from './types';
function ResizeControl({
@@ -12,8 +12,8 @@ import type { NodeToolbarProps } from './types';
const nodeEqualityFn = (a?: InternalNode, b?: InternalNode) =>
a?.internals.positionAbsolute.x !== b?.internals.positionAbsolute.x ||
a?.internals.positionAbsolute.y !== b?.internals.positionAbsolute.y ||
a?.computed.width !== b?.computed.width ||
a?.computed.height !== b?.computed.height ||
a?.measured.width !== b?.measured.width ||
a?.measured.height !== b?.measured.height ||
a?.selected !== b?.selected ||
a?.internals.z !== b?.internals.z;
@@ -64,8 +64,8 @@ const ConnectionLine = ({
}
const fromHandle = handleId ? handleBounds.find((d) => d.id === handleId) : handleBounds[0];
const fromHandleX = fromHandle ? fromHandle.x + fromHandle.width / 2 : (fromNode.computed.width ?? 0) / 2;
const fromHandleY = fromHandle ? fromHandle.y + fromHandle.height / 2 : fromNode.computed.height ?? 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 ?? 0) + fromHandleX;
const fromY = (fromNode.internals.positionAbsolute.y ?? 0) + fromHandleY;
const fromPosition = fromHandle?.position;
+2 -2
View File
@@ -5,13 +5,13 @@
import { useRef, type MouseEvent as ReactMouseEvent, type ReactNode } from 'react';
import { shallow } from 'zustand/shallow';
import cc from 'classcat';
import { getNodesInside, getEventPosition, SelectionMode } from '@xyflow/system';
import { getNodesInside, getEventPosition, SelectionMode, type NodeChange, type EdgeChange } from '@xyflow/system';
import { UserSelection } from '../../components/UserSelection';
import { containerStyle } from '../../styles/utils';
import { useStore, useStoreApi } from '../../hooks/useStore';
import { getSelectionChanges } from '../../utils';
import type { ReactFlowProps, ReactFlowState, NodeChange, EdgeChange } from '../../types';
import type { ReactFlowProps, ReactFlowState } from '../../types';
type PaneProps = {
isSelecting: boolean;
@@ -0,0 +1,21 @@
import { useCallback } from 'react';
import { shallow } from 'zustand/shallow';
import { useStore } from './useStore';
import type { InternalNode, Node } from '../types';
/**
* Hook for getting an internal node by id
*
* @public
* @param id - id of the node
* @returns array with visible node ids
*/
export function useInternalNode<NodeType extends Node = Node>(id: string): InternalNode<NodeType> | undefined {
const node = useStore(
useCallback((s) => s.nodeLookup.get(id) as InternalNode<NodeType> | undefined, [id]),
shallow
);
return node;
}
+5 -16
View File
@@ -1,12 +1,5 @@
import { useCallback, useMemo, useRef, useState } from 'react';
import {
getElementsToRemove,
getOverlappingArea,
isRectObject,
nodeHasDimensions,
nodeToRect,
type Rect,
} from '@xyflow/system';
import { getElementsToRemove, getOverlappingArea, isRectObject, nodeToRect, type Rect } from '@xyflow/system';
import useViewportHelper from './useViewportHelper';
import { useStoreApi } from './useStore';
@@ -32,7 +25,7 @@ export function useReactFlow<NodeType extends Node = Node, EdgeType extends Edge
}, []);
const getNode = useCallback<Instance.GetNode<NodeType>>((id) => {
return store.getState().nodeLookup.get(id)?.internals.userProvidedNode as NodeType;
return store.getState().nodeLookup.get(id)?.internals.userNode as NodeType;
}, []);
const getEdges = useCallback<Instance.GetEdges<EdgeType>>(() => {
@@ -223,13 +216,9 @@ export function useReactFlow<NodeType extends Node = Node, EdgeType extends Edge
[]
);
const getNodeRect = useCallback((nodeOrRect: NodeType | { id: NodeType['id'] }): Rect | null => {
const node =
isNode(nodeOrRect) && nodeHasDimensions(nodeOrRect)
? nodeOrRect
: (store.getState().nodeLookup.get(nodeOrRect.id)?.internals.userProvidedNode as NodeType);
return node ? nodeToRect(node) : null;
const getNodeRect = useCallback(({ id }: { id: string }): Rect | null => {
const internalNode = store.getState().nodeLookup.get(id);
return internalNode ? nodeToRect(internalNode) : null;
}, []);
const getIntersectingNodes = useCallback<Instance.GetIntersectingNodes<NodeType>>(
@@ -48,12 +48,12 @@ const useViewportHelper = (): ViewportHelperFunctions => {
return { x, y, zoom };
},
fitView: (options) => {
const { nodes, width, height, nodeOrigin, minZoom, maxZoom, panZoom } = store.getState();
const { nodeLookup, width, height, nodeOrigin, minZoom, maxZoom, panZoom } = store.getState();
return panZoom
? fitView(
{
nodes,
nodeLookup,
width,
height,
nodeOrigin,
@@ -1,13 +1,13 @@
import { getNodesInside } from '@xyflow/system';
import { useCallback } from 'react';
import { shallow } from 'zustand/shallow';
import { getNodesInside } from '@xyflow/system';
import { useStore } from './useStore';
import type { Node, ReactFlowState } from '../types';
import { useCallback } from 'react';
const selector = (onlyRenderVisible: boolean) => (s: ReactFlowState) => {
return onlyRenderVisible
? getNodesInside<Node>(s.nodes, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true).map(
? getNodesInside<Node>(s.nodeLookup, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, true).map(
(node) => node.id
)
: Array.from(s.nodeLookup.keys());
+1
View File
@@ -26,6 +26,7 @@ export { useNodesInitialized, type UseNodesInitializedOptions } from './hooks/us
export { useHandleConnections } from './hooks/useHandleConnections';
export { useNodesData } from './hooks/useNodesData';
export { useConnection } from './hooks/useConnection';
export { useInternalNode } from './hooks/useInternalNode';
export { useNodeId } from './contexts/NodeIdContext';
export { applyNodeChanges, applyEdgeChanges } from './utils/changes';
+18 -24
View File
@@ -2,27 +2,20 @@ import { createWithEqualityFn } from 'zustand/traditional';
import {
clampPosition,
fitView as fitViewSystem,
adoptUserProvidedNodes,
adoptUserNodes,
updateAbsolutePositions,
panBy as panBySystem,
updateNodeDimensions as updateNodeDimensionsSystem,
updateConnectionLookup,
handleParentExpand,
NodeChange,
EdgeSelectionChange,
NodeSelectionChange,
} from '@xyflow/system';
import { applyEdgeChanges, applyNodeChanges, createSelectionChange, getSelectionChanges } from '../utils/changes';
import getInitialState from './initialState';
import type {
ReactFlowState,
Node,
Edge,
EdgeSelectionChange,
NodeSelectionChange,
UnselectNodesAndEdgesParams,
FitViewOptions,
InternalNode,
} from '../types';
import type { ReactFlowState, Node, Edge, UnselectNodesAndEdgesParams, FitViewOptions, InternalNode } from '../types';
const createRFStore = ({
nodes,
@@ -52,7 +45,7 @@ const createRFStore = ({
//
// When this happens, we take the note objects passed by the user and extend them with fields
// relevant for internal React Flow operations.
adoptUserProvidedNodes(nodes, nodeLookup, { nodeOrigin, elevateNodesOnSelect });
adoptUserNodes(nodes, nodeLookup, { nodeOrigin, elevateNodesOnSelect });
set({ nodes });
},
@@ -263,21 +256,22 @@ const createRFStore = ({
triggerEdgeChanges(edgeChanges);
},
setNodeExtent: (nodeExtent) => {
const { nodes } = get();
const { nodeLookup } = get();
for (const [, node] of nodeLookup) {
const positionAbsolute = clampPosition(node.position, nodeExtent);
nodeLookup.set(node.id, {
...node,
internals: {
...node.internals,
positionAbsolute,
},
});
}
set({
nodeExtent,
nodes: nodes.map((node) => {
const positionAbsolute = clampPosition(node.position, nodeExtent);
return {
...node,
computed: {
...node.computed,
positionAbsolute,
},
};
}),
});
},
panBy: (delta): boolean => {
+2 -2
View File
@@ -1,7 +1,7 @@
import {
infiniteExtent,
ConnectionMode,
adoptUserProvidedNodes,
adoptUserNodes,
getNodesBounds,
getViewportForBounds,
Transform,
@@ -35,7 +35,7 @@ const getInitialState = ({
const storeNodes = defaultNodes ?? nodes ?? [];
updateConnectionLookup(connectionLookup, edgeLookup, storeEdges);
adoptUserProvidedNodes(storeNodes, nodeLookup, {
adoptUserNodes(storeNodes, nodeLookup, {
nodeOrigin: [0, 0],
elevateNodesOnSelect: false,
});
-71
View File
@@ -1,71 +0,0 @@
import type { XYPosition, Dimensions } from '@xyflow/system';
import type { Node, Edge } from '.';
export type NodeDimensionChange = {
id: string;
type: 'dimensions';
dimensions?: Dimensions;
resizing?: boolean;
};
export type NodePositionChange = {
id: string;
type: 'position';
position?: XYPosition;
positionAbsolute?: XYPosition;
dragging?: boolean;
};
export type NodeSelectionChange = {
id: string;
type: 'select';
selected: boolean;
};
export type NodeRemoveChange = {
id: string;
type: 'remove';
};
export type NodeAddChange<NodeType extends Node = Node> = {
item: NodeType;
type: 'add';
};
export type NodeReplaceChange<NodeType extends Node = Node> = {
id: string;
item: NodeType;
type: 'replace';
};
/**
* Union type of all possible node changes.
* @public
*/
export type NodeChange<NodeType extends Node = Node> =
| NodeDimensionChange
| NodePositionChange
| NodeSelectionChange
| NodeRemoveChange
| NodeAddChange<NodeType>
| NodeReplaceChange<NodeType>;
export type EdgeSelectionChange = NodeSelectionChange;
export type EdgeRemoveChange = NodeRemoveChange;
export type EdgeAddChange<EdgeType extends Edge = Edge> = {
item: EdgeType;
type: 'add';
};
export type EdgeReplaceChange<EdgeType extends Edge = Edge> = {
id: string;
item: EdgeType;
type: 'replace';
};
export type EdgeChange<EdgeType extends Edge = Edge> =
| EdgeSelectionChange
| EdgeRemoveChange
| EdgeAddChange<EdgeType>
| EdgeReplaceChange<EdgeType>;
+3 -1
View File
@@ -12,9 +12,11 @@ import {
XYPosition,
OnBeforeDeleteBase,
Connection,
NodeChange,
EdgeChange,
} from '@xyflow/system';
import type { NodeChange, EdgeChange, Node, Edge, ReactFlowInstance, EdgeProps, NodeProps } from '.';
import type { Node, Edge, ReactFlowInstance, EdgeProps, NodeProps } from '.';
export type OnNodesChange<NodeType extends Node = Node> = (changes: NodeChange<NodeType>[]) => void;
export type OnEdgesChange<EdgeType extends Edge = Edge> = (changes: EdgeChange<EdgeType>[]) => void;
-1
View File
@@ -1,6 +1,5 @@
export * from './nodes';
export * from './edges';
export * from './changes';
export * from './component-props';
export * from './general';
export * from './store';
+2 -2
View File
@@ -25,12 +25,13 @@ import {
type EdgeLookup,
type ConnectionLookup,
type NodeLookup,
NodeChange,
EdgeChange,
} from '@xyflow/system';
import type {
Edge,
Node,
NodeChange,
OnNodesChange,
OnEdgesChange,
DefaultEdgeOptions,
@@ -43,7 +44,6 @@ import type {
OnNodeDrag,
OnBeforeDelete,
IsValidConnection,
EdgeChange,
InternalNode,
} from '.';
+8 -9
View File
@@ -1,14 +1,13 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { EdgeLookup, NodeLookup } from '@xyflow/system';
import type {
Node,
Edge,
import {
EdgeLookup,
NodeLookup,
EdgeChange,
NodeChange,
NodeSelectionChange,
EdgeSelectionChange,
InternalNode,
} from '../types';
} from '@xyflow/system';
import type { Node, Edge, InternalNode } from '../types';
// This function applies changes to nodes or edges that are triggered by React Flow internally.
// When you drag a node for example, React Flow will send a position change update.
@@ -97,9 +96,9 @@ function applyChange(change: any, element: any): any {
case 'dimensions': {
if (typeof change.dimensions !== 'undefined') {
element.computed ??= {};
element.computed.width = change.dimensions.width;
element.computed.height = change.dimensions.height;
element.measured ??= {};
element.measured.width = change.dimensions.width;
element.measured.height = change.dimensions.height;
if (change.resizing) {
element.width = change.dimensions.width;