feat(nested-nodes): simplify nested node rendering
This commit is contained in:
+10
-17
@@ -26,38 +26,40 @@ const initialNodes: Node[] = [
|
||||
{
|
||||
id: '4',
|
||||
data: { label: 'Node 4' },
|
||||
position: { x: 0, y: 0 },
|
||||
position: { x: 100, y: 200 },
|
||||
className: 'light',
|
||||
style: { backgroundColor: 'rgba(255, 0, 0, .2)' },
|
||||
width: 0,
|
||||
height: 0,
|
||||
width: 600,
|
||||
height: 300,
|
||||
},
|
||||
{
|
||||
id: '4a',
|
||||
data: { label: 'Node 4a' },
|
||||
position: { x: 70, y: 200 },
|
||||
position: { x: 115, y: 215 },
|
||||
className: 'light',
|
||||
parentNode: '4',
|
||||
},
|
||||
{
|
||||
id: '4b',
|
||||
data: { label: 'Node 4b' },
|
||||
position: { x: 0, y: 0 },
|
||||
position: { x: 250, y: 250 },
|
||||
className: 'light',
|
||||
style: { backgroundColor: 'rgba(255, 0, 0, .2)' },
|
||||
parentNode: '4',
|
||||
height: 200,
|
||||
width: 350,
|
||||
},
|
||||
{
|
||||
id: '4b1',
|
||||
data: { label: 'Node 4b1' },
|
||||
position: { x: 150, y: 270 },
|
||||
position: { x: 270, y: 270 },
|
||||
className: 'light',
|
||||
parentNode: '4b',
|
||||
},
|
||||
{
|
||||
id: '4b2',
|
||||
data: { label: 'Node 4b2' },
|
||||
position: { x: 420, y: 370 },
|
||||
position: { x: 500, y: 400 },
|
||||
className: 'light',
|
||||
parentNode: '4b',
|
||||
},
|
||||
@@ -129,18 +131,9 @@ const BasicFlow = () => {
|
||||
setEdges((es) => applyEdgeChanges(changes, es));
|
||||
}, []);
|
||||
|
||||
const nodesWithLabel = useMemo(
|
||||
() =>
|
||||
nodes.map((n) => {
|
||||
n.data = { ...n.data, label: `${n.width}x${n.height}` };
|
||||
return n;
|
||||
}),
|
||||
[nodes]
|
||||
);
|
||||
|
||||
return (
|
||||
<ReactFlow
|
||||
nodes={nodesWithLabel}
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
onLoad={onLoad}
|
||||
onNodesChange={onNodesChange}
|
||||
|
||||
@@ -23,6 +23,8 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
scale,
|
||||
xPos,
|
||||
yPos,
|
||||
width,
|
||||
height,
|
||||
isSelected,
|
||||
onClick,
|
||||
onMouseEnter,
|
||||
@@ -49,6 +51,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
resizeObserver,
|
||||
dragHandle,
|
||||
zIndex,
|
||||
isParentNode,
|
||||
}: WrapNodeProps) => {
|
||||
const {
|
||||
addSelectedElements,
|
||||
@@ -70,6 +73,8 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave ? 'all' : 'none',
|
||||
// prevents jumping of nodes on start
|
||||
// opacity: isInitialized ? 1 : 0,
|
||||
width: isParentNode && width !== null ? width : 'auto',
|
||||
height: isParentNode && height !== null ? height : 'auto',
|
||||
...style,
|
||||
}),
|
||||
[
|
||||
@@ -84,6 +89,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
onMouseEnter,
|
||||
onMouseMove,
|
||||
onMouseLeave,
|
||||
isParentNode,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -200,10 +206,10 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (nodeElement.current && !isHidden && !isInitialized) {
|
||||
if (nodeElement.current && !isHidden && (!isInitialized || isParentNode)) {
|
||||
updateNodeDimensions([{ id, nodeElement: nodeElement.current, forceUpdate: true }]);
|
||||
}
|
||||
}, [id, isHidden, sourcePosition, targetPosition, isInitialized]);
|
||||
}, [id, isHidden, sourcePosition, targetPosition, isInitialized, isParentNode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (nodeElement.current) {
|
||||
@@ -225,6 +231,7 @@ export default (NodeComponent: ComponentType<NodeComponentProps>) => {
|
||||
{
|
||||
selected: isSelected,
|
||||
selectable: isSelectable,
|
||||
parent: isParentNode,
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import React, { memo, useMemo, ComponentType, MouseEvent, Fragment, useEffect } from 'react';
|
||||
import React, { memo, useMemo, ComponentType, MouseEvent, Fragment } from 'react';
|
||||
import shallow from 'zustand/shallow';
|
||||
|
||||
import { useStore } from '../../store';
|
||||
import { Node, NodeTypesType, ReactFlowState, WrapNodeProps, SnapGrid } from '../../types';
|
||||
import { getRectOfNodes } from '../../utils/graph';
|
||||
import useVisibleNodes from '../../hooks/useVisibleNodes';
|
||||
interface NodeRendererProps {
|
||||
nodeTypes: NodeTypesType;
|
||||
@@ -63,7 +62,7 @@ function Node({
|
||||
recursionDepth,
|
||||
...props
|
||||
}: NodeProps) {
|
||||
const onNodesChange = useStore((s) => s.onNodesChange);
|
||||
// const onNodesChange = useStore((s) => s.onNodesChange);
|
||||
const NodeComponent = (props.nodeTypes[nodeType] || props.nodeTypes.default) as ComponentType<WrapNodeProps>;
|
||||
const isNodeDraggable =
|
||||
typeof isDraggable !== 'undefined'
|
||||
@@ -77,39 +76,13 @@ function Node({
|
||||
typeof node.width !== 'undefined' &&
|
||||
typeof node.height !== 'undefined';
|
||||
|
||||
const { childNodes = [] } = node;
|
||||
const childRect = useMemo(() => getRectOfNodes(childNodes), [childNodes]);
|
||||
const isParentNode = !!childNodes.length;
|
||||
|
||||
const style = useMemo(() => {
|
||||
if (isParentNode) {
|
||||
return {
|
||||
...node.style,
|
||||
width: Math.floor(childRect.width) + 20,
|
||||
height: Math.floor(childRect.height) + 20,
|
||||
boxSizing: 'border-box',
|
||||
} as React.CSSProperties;
|
||||
}
|
||||
return node.style;
|
||||
}, [childRect.width, childRect.height, isParentNode, node.style]);
|
||||
|
||||
useEffect(() => {
|
||||
if (onNodesChange && isParentNode) {
|
||||
onNodesChange([
|
||||
{
|
||||
type: 'position',
|
||||
id: node.id,
|
||||
position: { x: Math.floor(childRect.x) - 10, y: Math.floor(childRect.y) - 10 },
|
||||
},
|
||||
]);
|
||||
}
|
||||
}, [childRect.width, childRect.height, childRect.x, childRect.y, isParentNode]);
|
||||
const isParentNode = !!node.childNodes?.length;
|
||||
|
||||
return (
|
||||
<NodeComponent
|
||||
id={node.id}
|
||||
className={node.className}
|
||||
style={style}
|
||||
style={node.style}
|
||||
type={nodeType}
|
||||
data={node.data}
|
||||
sourcePosition={node.sourcePosition}
|
||||
@@ -117,6 +90,8 @@ function Node({
|
||||
isHidden={node.isHidden}
|
||||
xPos={node.position.x}
|
||||
yPos={node.position.y}
|
||||
width={node.width}
|
||||
height={node.height}
|
||||
isDragging={node.isDragging}
|
||||
isInitialized={isInitialized}
|
||||
snapGrid={snapGrid}
|
||||
@@ -139,6 +114,7 @@ function Node({
|
||||
resizeObserver={resizeObserver}
|
||||
dragHandle={node.dragHandle}
|
||||
zIndex={3 + recursionDepth}
|
||||
isParentNode={isParentNode}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
+3
-3
@@ -25,7 +25,7 @@ import {
|
||||
OnNodesChange,
|
||||
OnEdgesChange,
|
||||
EdgeChange,
|
||||
NodePositionChange,
|
||||
NodeDimensionChange,
|
||||
} from '../types';
|
||||
import { isNode, isEdge, getRectOfNodes, getNodesInside, getConnectedEdges } from '../utils/graph';
|
||||
import { getHandleBounds } from '../components/Nodes/utils';
|
||||
@@ -194,9 +194,9 @@ const createStore = () =>
|
||||
if (matchingNodes?.length) {
|
||||
onNodesChange(
|
||||
matchingNodes.map((n) => {
|
||||
const change: NodePositionChange = {
|
||||
const change: NodeDimensionChange = {
|
||||
id: n.id,
|
||||
type: 'position',
|
||||
type: 'dimensions',
|
||||
isDragging: !!isDragging,
|
||||
};
|
||||
|
||||
|
||||
@@ -95,6 +95,7 @@
|
||||
user-select: none;
|
||||
pointer-events: all;
|
||||
transform-origin: 0 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.react-flow__nodesselection {
|
||||
|
||||
+7
-7
@@ -12,15 +12,12 @@ export type Transform = [number, number, number];
|
||||
export type NodeDimensionChange = {
|
||||
id: string;
|
||||
type: 'dimensions';
|
||||
dimensions: Dimensions;
|
||||
handleBounds?: NodeHandleBounds;
|
||||
};
|
||||
export type NodePositionChange = {
|
||||
id: string;
|
||||
type: 'position';
|
||||
dimensions?: Dimensions;
|
||||
position?: XYPosition;
|
||||
handleBounds?: NodeHandleBounds;
|
||||
isDragging?: boolean;
|
||||
};
|
||||
|
||||
export type NodeSelectionChange = {
|
||||
id: string;
|
||||
type: 'select';
|
||||
@@ -30,7 +27,7 @@ export type NodeRemoveChange = {
|
||||
id: string;
|
||||
type: 'remove';
|
||||
};
|
||||
export type NodeChange = NodeDimensionChange | NodePositionChange | NodeSelectionChange | NodeRemoveChange;
|
||||
export type NodeChange = NodeDimensionChange | NodeSelectionChange | NodeRemoveChange;
|
||||
|
||||
export type EdgeSelectionChange = NodeSelectionChange;
|
||||
export type EdgeRemoveChange = NodeRemoveChange;
|
||||
@@ -277,6 +274,8 @@ export interface WrapNodeProps<T = any> {
|
||||
scale: number;
|
||||
xPos: number;
|
||||
yPos: number;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
isSelectable: boolean;
|
||||
isDraggable: boolean;
|
||||
isConnectable: boolean;
|
||||
@@ -302,6 +301,7 @@ export interface WrapNodeProps<T = any> {
|
||||
resizeObserver: ResizeObserver | null;
|
||||
dragHandle?: string;
|
||||
zIndex: number;
|
||||
isParentNode: boolean;
|
||||
}
|
||||
|
||||
export type FitViewParams = {
|
||||
|
||||
+10
-5
@@ -301,17 +301,22 @@ function applyChanges(changes: NodeChange[] | EdgeChange[], elements: any[]): an
|
||||
|
||||
if (currentChange) {
|
||||
switch (currentChange.type) {
|
||||
case 'dimensions': {
|
||||
res.push({ ...item, ...currentChange.dimensions, handleBounds: currentChange.handleBounds });
|
||||
return res;
|
||||
}
|
||||
case 'select': {
|
||||
res.push({ ...item, isSelected: currentChange.isSelected });
|
||||
return res;
|
||||
}
|
||||
case 'position': {
|
||||
case 'dimensions': {
|
||||
const updateItem = { ...item };
|
||||
|
||||
if (typeof currentChange.dimensions !== 'undefined') {
|
||||
updateItem.width = currentChange.dimensions.width;
|
||||
updateItem.height = currentChange.dimensions.height;
|
||||
}
|
||||
|
||||
if (typeof currentChange.handleBounds !== 'undefined') {
|
||||
updateItem.handleBounds = currentChange.handleBounds;
|
||||
}
|
||||
|
||||
if (typeof currentChange.position !== 'undefined') {
|
||||
updateItem.position = currentChange.position;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user