child nodes get repositioned correctly when resizing top or left
This commit is contained in:
@@ -116,6 +116,29 @@ const initialNodes: Node[] = [
|
|||||||
position: { x: 250, y: 400 },
|
position: { x: 250, y: 400 },
|
||||||
style: { ...nodeStyle },
|
style: { ...nodeStyle },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: '5',
|
||||||
|
type: 'defaultResizer',
|
||||||
|
data: { label: 'Parent' },
|
||||||
|
position: { x: 700, y: 0 },
|
||||||
|
style: { ...nodeStyle, width: 300, height: 300 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5a',
|
||||||
|
type: 'defaultResizer',
|
||||||
|
data: { label: 'Child' },
|
||||||
|
position: { x: 50, y: 50 },
|
||||||
|
parentNode: '5',
|
||||||
|
style: { ...nodeStyle },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5b',
|
||||||
|
type: 'defaultResizer',
|
||||||
|
data: { label: 'Child' },
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
parentNode: '5',
|
||||||
|
style: { ...nodeStyle },
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const CustomNodeFlow = () => {
|
const CustomNodeFlow = () => {
|
||||||
|
|||||||
@@ -100,6 +100,29 @@
|
|||||||
data: { label: 'horizontal resizer with maxWidth', maxWidth: 300 },
|
data: { label: 'horizontal resizer with maxWidth', maxWidth: 300 },
|
||||||
position: { x: 250, y: 400 },
|
position: { x: 250, y: 400 },
|
||||||
style: nodeStyle
|
style: nodeStyle
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5',
|
||||||
|
type: 'defaultResizer',
|
||||||
|
data: { label: 'Parent' },
|
||||||
|
position: { x: 700, y: 0 },
|
||||||
|
style: nodeStyle + 'width: 300px; height: 300px'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5a',
|
||||||
|
type: 'defaultResizer',
|
||||||
|
data: { label: 'Child' },
|
||||||
|
position: { x: 50, y: 50 },
|
||||||
|
parentNode: '5',
|
||||||
|
style: nodeStyle
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5b',
|
||||||
|
type: 'defaultResizer',
|
||||||
|
data: { label: 'Child' },
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
parentNode: '5',
|
||||||
|
style: nodeStyle
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import { useRef, useEffect, memo } from 'react';
|
import { useRef, useEffect, memo } from 'react';
|
||||||
import cc from 'classcat';
|
import cc from 'classcat';
|
||||||
import { XYResizer, ResizeControlVariant, type XYResizerInstance, type XYResizerChange } from '@xyflow/system';
|
import {
|
||||||
|
XYResizer,
|
||||||
|
ResizeControlVariant,
|
||||||
|
type XYResizerInstance,
|
||||||
|
type XYResizerChange,
|
||||||
|
XYResizerChildChange,
|
||||||
|
} from '@xyflow/system';
|
||||||
|
|
||||||
import { useStoreApi } from '../../hooks/useStore';
|
import { useStoreApi } from '../../hooks/useStore';
|
||||||
import { useNodeId } from '../../contexts/NodeIdContext';
|
import { useNodeId } from '../../contexts/NodeIdContext';
|
||||||
@@ -52,7 +58,7 @@ function ResizeControl({
|
|||||||
snapToGrid,
|
snapToGrid,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onChange: (change: XYResizerChange) => {
|
onChange: (change: XYResizerChange, childChanges: XYResizerChildChange[]) => {
|
||||||
const { triggerNodeChanges } = store.getState();
|
const { triggerNodeChanges } = store.getState();
|
||||||
|
|
||||||
const changes: NodeChange[] = [];
|
const changes: NodeChange[] = [];
|
||||||
@@ -83,6 +89,17 @@ function ResizeControl({
|
|||||||
|
|
||||||
changes.push(dimensionChange);
|
changes.push(dimensionChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
childChanges.forEach((childChange) => {
|
||||||
|
const positionChange: NodePositionChange = {
|
||||||
|
id: childChange.id,
|
||||||
|
type: 'position',
|
||||||
|
position: childChange.position,
|
||||||
|
};
|
||||||
|
|
||||||
|
changes.push(positionChange);
|
||||||
|
});
|
||||||
|
|
||||||
triggerNodeChanges(changes);
|
triggerNodeChanges(changes);
|
||||||
},
|
},
|
||||||
onEnd: () => {
|
onEnd: () => {
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
ResizeControlVariant,
|
ResizeControlVariant,
|
||||||
type ControlPosition,
|
type ControlPosition,
|
||||||
type XYResizerInstance,
|
type XYResizerInstance,
|
||||||
type XYResizerChange
|
type XYResizerChange,
|
||||||
|
type XYResizerChildChange
|
||||||
} from '@xyflow/system';
|
} from '@xyflow/system';
|
||||||
import type { ResizeControlProps } from './types';
|
import type { ResizeControlProps } from './types';
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@
|
|||||||
snapToGrid: !!$snapGrid
|
snapToGrid: !!$snapGrid
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onChange: (change: XYResizerChange) => {
|
onChange: (change: XYResizerChange, childChanges: XYResizerChildChange[]) => {
|
||||||
const node = $nodeLookup.get(id);
|
const node = $nodeLookup.get(id);
|
||||||
if (node) {
|
if (node) {
|
||||||
node.height = change.isHeightChange ? change.height : node.height;
|
node.height = change.isHeightChange ? change.height : node.height;
|
||||||
@@ -76,6 +77,13 @@
|
|||||||
? { x: change.x, y: change.y }
|
? { x: change.x, y: change.y }
|
||||||
: node.position;
|
: node.position;
|
||||||
|
|
||||||
|
childChanges.forEach((childChange) => {
|
||||||
|
const childNode = $nodeLookup.get(childChange.id);
|
||||||
|
if (childNode) {
|
||||||
|
childNode.position = childChange.position;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$nodes = $nodes;
|
$nodes = $nodes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { select } from 'd3-selection';
|
|||||||
|
|
||||||
import { getControlDirection, getDimensionsAfterResize, getPositionAfterResize, getResizeDirection } from './utils';
|
import { getControlDirection, getDimensionsAfterResize, getPositionAfterResize, getResizeDirection } from './utils';
|
||||||
import { getPointerPosition } from '../utils';
|
import { getPointerPosition } from '../utils';
|
||||||
import type { NodeLookup, Transform } from '../types';
|
import type { NodeBase, NodeLookup, Transform } from '../types';
|
||||||
import type { OnResize, OnResizeEnd, OnResizeStart, ResizeDragEvent, ShouldResize, ControlPosition } from './types';
|
import type { OnResize, OnResizeEnd, OnResizeStart, ResizeDragEvent, ShouldResize, ControlPosition } from './types';
|
||||||
|
|
||||||
const initPrevValues = { width: 0, height: 0, x: 0, y: 0 };
|
const initPrevValues = { width: 0, height: 0, x: 0, y: 0 };
|
||||||
@@ -28,6 +28,14 @@ const initChange = {
|
|||||||
|
|
||||||
export type XYResizerChange = typeof initChange;
|
export type XYResizerChange = typeof initChange;
|
||||||
|
|
||||||
|
export type XYResizerChildChange = {
|
||||||
|
id: string;
|
||||||
|
position: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
type XYResizerParams = {
|
type XYResizerParams = {
|
||||||
domNode: HTMLDivElement;
|
domNode: HTMLDivElement;
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
@@ -37,7 +45,7 @@ type XYResizerParams = {
|
|||||||
snapGrid?: [number, number];
|
snapGrid?: [number, number];
|
||||||
snapToGrid: boolean;
|
snapToGrid: boolean;
|
||||||
};
|
};
|
||||||
onChange: (changes: XYResizerChange) => void;
|
onChange: (changes: XYResizerChange, childChanges: XYResizerChildChange[]) => void;
|
||||||
onEnd?: () => void;
|
onEnd?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -78,6 +86,8 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange }: XYResize
|
|||||||
|
|
||||||
const controlDirection = getControlDirection(controlPosition);
|
const controlDirection = getControlDirection(controlPosition);
|
||||||
|
|
||||||
|
let childNodes: XYResizerChildChange[] = [];
|
||||||
|
|
||||||
const dragHandler = drag<HTMLDivElement, unknown>()
|
const dragHandler = drag<HTMLDivElement, unknown>()
|
||||||
.on('start', (event: ResizeDragEvent) => {
|
.on('start', (event: ResizeDragEvent) => {
|
||||||
const { nodeLookup, transform, snapGrid, snapToGrid } = getStoreItems();
|
const { nodeLookup, transform, snapGrid, snapToGrid } = getStoreItems();
|
||||||
@@ -98,6 +108,15 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange }: XYResize
|
|||||||
aspectRatio: prevValues.width / prevValues.height,
|
aspectRatio: prevValues.width / prevValues.height,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
childNodes = [];
|
||||||
|
nodeLookup.forEach((_node, _nodeId) => {
|
||||||
|
if (_node.parentNode === nodeId) {
|
||||||
|
childNodes.push({
|
||||||
|
id: _nodeId,
|
||||||
|
position: { ..._node.position },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
onResizeStart?.(event, { ...prevValues });
|
onResizeStart?.(event, { ...prevValues });
|
||||||
})
|
})
|
||||||
.on('drag', (event: ResizeDragEvent) => {
|
.on('drag', (event: ResizeDragEvent) => {
|
||||||
@@ -105,6 +124,8 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange }: XYResize
|
|||||||
const pointerPosition = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
const pointerPosition = getPointerPosition(event.sourceEvent, { transform, snapGrid, snapToGrid });
|
||||||
const node = nodeLookup.get(nodeId);
|
const node = nodeLookup.get(nodeId);
|
||||||
|
|
||||||
|
let childChanges: XYResizerChildChange[] = [];
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
const change = { ...initChange };
|
const change = { ...initChange };
|
||||||
|
|
||||||
@@ -137,6 +158,18 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange }: XYResize
|
|||||||
prevValues.x = change.x;
|
prevValues.x = change.x;
|
||||||
prevValues.y = change.y;
|
prevValues.y = change.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (childNodes.length > 0) {
|
||||||
|
const xChange = x - prevX;
|
||||||
|
const yChange = y - prevY;
|
||||||
|
childNodes.forEach((childNode) => {
|
||||||
|
childNode.position = {
|
||||||
|
x: childNode.position.x - xChange,
|
||||||
|
y: childNode.position.y - yChange,
|
||||||
|
};
|
||||||
|
childChanges.push(childNode);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isWidthChange || isHeightChange) {
|
if (isWidthChange || isHeightChange) {
|
||||||
@@ -170,7 +203,7 @@ export function XYResizer({ domNode, nodeId, getStoreItems, onChange }: XYResize
|
|||||||
}
|
}
|
||||||
|
|
||||||
onResize?.(event, nextValues);
|
onResize?.(event, nextValues);
|
||||||
onChange(change);
|
onChange(change, childChanges);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.on('end', (event: ResizeDragEvent) => {
|
.on('end', (event: ResizeDragEvent) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user