fix(child-nodes): dragging when parent is selected
This commit is contained in:
+21
-86
@@ -25,55 +25,14 @@ import {
|
|||||||
Transform,
|
Transform,
|
||||||
Dimensions,
|
Dimensions,
|
||||||
XYPosition,
|
XYPosition,
|
||||||
ReactFlowStore,
|
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import { getHandleBounds } from '../components/Nodes/utils';
|
import { getHandleBounds } from '../components/Nodes/utils';
|
||||||
import { createSelectionChange, getSelectionChanges } from '../utils/changes';
|
import { createSelectionChange, getSelectionChanges } from '../utils/changes';
|
||||||
import { createNodeInternals } from './utils';
|
import { createNodeInternals, createPositionChange, isParentSelected } from './utils';
|
||||||
|
import initialState from './initialState';
|
||||||
|
|
||||||
const { Provider, useStore, useStoreApi } = createContext<ReactFlowState>();
|
const { Provider, useStore, useStoreApi } = createContext<ReactFlowState>();
|
||||||
|
|
||||||
const infiniteExtent: CoordinateExtent = [
|
|
||||||
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
|
|
||||||
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
|
|
||||||
];
|
|
||||||
|
|
||||||
const initialState: ReactFlowStore = {
|
|
||||||
width: 0,
|
|
||||||
height: 0,
|
|
||||||
transform: [0, 0, 1],
|
|
||||||
nodeInternals: new Map(),
|
|
||||||
edges: [],
|
|
||||||
onNodesChange: null,
|
|
||||||
onEdgesChange: null,
|
|
||||||
selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 },
|
|
||||||
d3Zoom: null,
|
|
||||||
d3Selection: null,
|
|
||||||
d3ZoomHandler: undefined,
|
|
||||||
minZoom: 0.5,
|
|
||||||
maxZoom: 2,
|
|
||||||
translateExtent: infiniteExtent,
|
|
||||||
nodeExtent: infiniteExtent,
|
|
||||||
nodesSelectionActive: false,
|
|
||||||
userSelectionActive: false,
|
|
||||||
connectionNodeId: null,
|
|
||||||
connectionHandleId: null,
|
|
||||||
connectionHandleType: 'source',
|
|
||||||
connectionPosition: { x: 0, y: 0 },
|
|
||||||
connectionMode: ConnectionMode.Strict,
|
|
||||||
|
|
||||||
snapGrid: [15, 15],
|
|
||||||
snapToGrid: false,
|
|
||||||
|
|
||||||
nodesDraggable: true,
|
|
||||||
nodesConnectable: true,
|
|
||||||
elementsSelectable: true,
|
|
||||||
|
|
||||||
multiSelectionActive: false,
|
|
||||||
|
|
||||||
reactFlowVersion: typeof __REACT_FLOW_VERSION__ !== 'undefined' ? __REACT_FLOW_VERSION__ : '-',
|
|
||||||
};
|
|
||||||
|
|
||||||
const createStore = () =>
|
const createStore = () =>
|
||||||
create<ReactFlowState>((set, get) => ({
|
create<ReactFlowState>((set, get) => ({
|
||||||
...initialState,
|
...initialState,
|
||||||
@@ -89,7 +48,7 @@ const createStore = () =>
|
|||||||
updateNodeDimensions: (updates: NodeDimensionUpdate[]) => {
|
updateNodeDimensions: (updates: NodeDimensionUpdate[]) => {
|
||||||
const { onNodesChange, transform, nodeInternals } = get();
|
const { onNodesChange, transform, nodeInternals } = get();
|
||||||
|
|
||||||
const nodesToChange: NodeChange[] = updates.reduce<NodeChange[]>((res, update) => {
|
const changes: NodeChange[] = updates.reduce<NodeChange[]>((res, update) => {
|
||||||
const node = nodeInternals.get(update.id);
|
const node = nodeInternals.get(update.id);
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
@@ -108,12 +67,11 @@ const createStore = () =>
|
|||||||
...dimensions,
|
...dimensions,
|
||||||
});
|
});
|
||||||
|
|
||||||
const change = {
|
res.push({
|
||||||
id: node.id,
|
id: node.id,
|
||||||
type: 'dimensions',
|
type: 'dimensions',
|
||||||
dimensions,
|
dimensions,
|
||||||
} as NodeChange;
|
} as NodeChange);
|
||||||
res.push(change);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,53 +80,30 @@ const createStore = () =>
|
|||||||
|
|
||||||
set({ nodeInternals: new Map(nodeInternals) });
|
set({ nodeInternals: new Map(nodeInternals) });
|
||||||
|
|
||||||
if (nodesToChange?.length > 0) {
|
if (changes?.length > 0) {
|
||||||
onNodesChange?.(nodesToChange);
|
onNodesChange?.(changes);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateNodePosition: ({ id, diff, dragging }: NodeDiffUpdate) => {
|
updateNodePosition: ({ id, diff, dragging }: NodeDiffUpdate) => {
|
||||||
const { onNodesChange, nodeExtent, nodeInternals } = get();
|
const { onNodesChange, nodeExtent, nodeInternals } = get();
|
||||||
|
|
||||||
if (onNodesChange) {
|
if (onNodesChange) {
|
||||||
const nodes = Array.from(nodeInternals);
|
const changes: NodeDimensionChange[] = [];
|
||||||
const matchingNodes = nodes.filter(([_, n]) => !!(n.selected || n.id === id));
|
|
||||||
if (matchingNodes?.length) {
|
|
||||||
onNodesChange(
|
|
||||||
matchingNodes?.map(([_, node]) => {
|
|
||||||
const change: NodeDimensionChange = {
|
|
||||||
id: node.id,
|
|
||||||
type: 'dimensions',
|
|
||||||
dragging: !!dragging,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (diff) {
|
nodeInternals.forEach((node) => {
|
||||||
let currentExtent = nodeExtent || node.extent;
|
if (node.selected) {
|
||||||
|
if (!node.parentNode) {
|
||||||
|
changes.push(createPositionChange({ node, diff, dragging, nodeExtent, nodeInternals }));
|
||||||
|
} else if (!isParentSelected(node, nodeInternals)) {
|
||||||
|
changes.push(createPositionChange({ node, diff, dragging, nodeExtent, nodeInternals }));
|
||||||
|
}
|
||||||
|
} else if (node.id === id) {
|
||||||
|
changes.push(createPositionChange({ node, diff, dragging, nodeExtent, nodeInternals }));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (node.extent === 'parent' && node.parentNode && node.width && node.height) {
|
if (changes?.length) {
|
||||||
const parent = nodeInternals.get(node.parentNode);
|
onNodesChange(changes);
|
||||||
currentExtent =
|
|
||||||
parent?.width && parent?.height
|
|
||||||
? [
|
|
||||||
[0, 0],
|
|
||||||
[parent.width - node.width, parent.height - node.height],
|
|
||||||
]
|
|
||||||
: currentExtent;
|
|
||||||
}
|
|
||||||
|
|
||||||
change.position = currentExtent
|
|
||||||
? clampPosition(
|
|
||||||
{
|
|
||||||
x: node.position.x + diff.x,
|
|
||||||
y: node.position.y + diff.y,
|
|
||||||
},
|
|
||||||
currentExtent
|
|
||||||
)
|
|
||||||
: { x: node.position.x + diff.x, y: node.position.y + diff.y };
|
|
||||||
}
|
|
||||||
|
|
||||||
return change;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { CoordinateExtent, ReactFlowStore, ConnectionMode } from '../types';
|
||||||
|
|
||||||
|
const infiniteExtent: CoordinateExtent = [
|
||||||
|
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
|
||||||
|
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
|
||||||
|
];
|
||||||
|
|
||||||
|
const initialState: ReactFlowStore = {
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
transform: [0, 0, 1],
|
||||||
|
nodeInternals: new Map(),
|
||||||
|
edges: [],
|
||||||
|
onNodesChange: null,
|
||||||
|
onEdgesChange: null,
|
||||||
|
selectedNodesBbox: { x: 0, y: 0, width: 0, height: 0 },
|
||||||
|
d3Zoom: null,
|
||||||
|
d3Selection: null,
|
||||||
|
d3ZoomHandler: undefined,
|
||||||
|
minZoom: 0.5,
|
||||||
|
maxZoom: 2,
|
||||||
|
translateExtent: infiniteExtent,
|
||||||
|
nodeExtent: infiniteExtent,
|
||||||
|
nodesSelectionActive: false,
|
||||||
|
userSelectionActive: false,
|
||||||
|
connectionNodeId: null,
|
||||||
|
connectionHandleId: null,
|
||||||
|
connectionHandleType: 'source',
|
||||||
|
connectionPosition: { x: 0, y: 0 },
|
||||||
|
connectionMode: ConnectionMode.Strict,
|
||||||
|
|
||||||
|
snapGrid: [15, 15],
|
||||||
|
snapToGrid: false,
|
||||||
|
|
||||||
|
nodesDraggable: true,
|
||||||
|
nodesConnectable: true,
|
||||||
|
elementsSelectable: true,
|
||||||
|
|
||||||
|
multiSelectionActive: false,
|
||||||
|
|
||||||
|
reactFlowVersion: typeof __REACT_FLOW_VERSION__ !== 'undefined' ? __REACT_FLOW_VERSION__ : '-',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default initialState;
|
||||||
+70
-2
@@ -1,5 +1,13 @@
|
|||||||
import { Node, NodeInternals, NodeInternalsItem, XYZPosition } from '../types';
|
import {
|
||||||
import { isNumeric } from '../utils';
|
CoordinateExtent,
|
||||||
|
Node,
|
||||||
|
NodeDimensionChange,
|
||||||
|
NodeInternals,
|
||||||
|
NodeInternalsItem,
|
||||||
|
XYPosition,
|
||||||
|
XYZPosition,
|
||||||
|
} from '../types';
|
||||||
|
import { clampPosition, isNumeric } from '../utils';
|
||||||
|
|
||||||
type ParentNodes = Record<string, boolean>;
|
type ParentNodes = Record<string, boolean>;
|
||||||
|
|
||||||
@@ -104,3 +112,63 @@ export function createNodeInternals(nodes: Node[], nodeInternals: NodeInternals)
|
|||||||
|
|
||||||
return nextNodeInternals;
|
return nextNodeInternals;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isParentSelected(node: NodeInternalsItem, nodeInternals: NodeInternals): boolean {
|
||||||
|
if (!node.parentNode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentNode = nodeInternals.get(node.parentNode);
|
||||||
|
|
||||||
|
if (!parentNode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentNode.selected) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isParentSelected(parentNode, nodeInternals);
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreatePostiionChangeParams = {
|
||||||
|
node: NodeInternalsItem;
|
||||||
|
nodeExtent: CoordinateExtent;
|
||||||
|
nodeInternals: NodeInternals;
|
||||||
|
diff?: XYPosition;
|
||||||
|
dragging?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createPositionChange({
|
||||||
|
node,
|
||||||
|
diff,
|
||||||
|
dragging,
|
||||||
|
nodeExtent,
|
||||||
|
nodeInternals,
|
||||||
|
}: CreatePostiionChangeParams): NodeDimensionChange {
|
||||||
|
const change: NodeDimensionChange = {
|
||||||
|
id: node.id,
|
||||||
|
type: 'dimensions',
|
||||||
|
dragging: !!dragging,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (diff) {
|
||||||
|
const nextPosition = { x: node.position.x + diff.x, y: node.position.y + diff.y };
|
||||||
|
let currentExtent = nodeExtent || node.extent;
|
||||||
|
|
||||||
|
if (node.extent === 'parent' && node.parentNode && node.width && node.height) {
|
||||||
|
const parent = nodeInternals.get(node.parentNode);
|
||||||
|
currentExtent =
|
||||||
|
parent?.width && parent?.height
|
||||||
|
? [
|
||||||
|
[0, 0],
|
||||||
|
[parent.width - node.width, parent.height - node.height],
|
||||||
|
]
|
||||||
|
: currentExtent;
|
||||||
|
}
|
||||||
|
|
||||||
|
change.position = currentExtent ? clampPosition(nextPosition, currentExtent) : nextPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user