Merge pull request #5684 from ysds/fix/nodes-selection-drag-after-programmatic-selection
fix: ensure drag handlers update when nodes selection changes programmatically
This commit is contained in:
5
.changeset/tender-ways-attend.md
Normal file
5
.changeset/tender-ways-attend.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@xyflow/react': patch
|
||||
---
|
||||
|
||||
Consolidate drag handler effects in useDrag to fix programmatic selection issues
|
||||
@@ -62,6 +62,7 @@ import MovingHandles from '../examples/MovingHandles';
|
||||
import DetachedHandle from '../examples/DetachedHandle';
|
||||
import ZIndexMode from '../examples/ZIndexMode';
|
||||
import Middlewares from '../examples/Middlewares';
|
||||
import NodeSelectionBug from '../examples/NodeSelectionBug';
|
||||
|
||||
export interface IRoute {
|
||||
name: string;
|
||||
@@ -390,6 +391,11 @@ const routes: IRoute[] = [
|
||||
path: 'z-index-mode',
|
||||
component: ZIndexMode,
|
||||
},
|
||||
{
|
||||
name: 'Node Selection Bug',
|
||||
path: 'node-selection-bug',
|
||||
component: NodeSelectionBug,
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
||||
|
||||
41
examples/react/src/examples/NodeSelectionBug/index.tsx
Normal file
41
examples/react/src/examples/NodeSelectionBug/index.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import { Node, ReactFlow, useNodesState } from '@xyflow/react';
|
||||
|
||||
import '@xyflow/react/dist/style.css';
|
||||
import { useRef } from 'react';
|
||||
|
||||
export default function App() {
|
||||
const [nodes, setNodes, onNodesChange] = useNodesState<Node>([
|
||||
{
|
||||
id: '0',
|
||||
position: { x: 0, y: 0 },
|
||||
data: { label: 'Rectangle Select Me First' },
|
||||
},
|
||||
]);
|
||||
const id = useRef(0);
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={() =>
|
||||
setNodes((nodes) => [
|
||||
...nodes.map((node) => ({ ...node, selected: false })),
|
||||
{
|
||||
id: (++id.current).toString(),
|
||||
position: { x: -100, y: 100 * Math.floor((id.current + 1) / 2) },
|
||||
data: { label: `Button Node ${id.current}` },
|
||||
selected: true,
|
||||
},
|
||||
{
|
||||
id: (++id.current).toString(),
|
||||
position: { x: 100, y: (100 * id.current) / 2 },
|
||||
data: { label: `Button Node ${id.current}` },
|
||||
selected: true,
|
||||
},
|
||||
])
|
||||
}
|
||||
>
|
||||
Click me to add nodes that are already selected.
|
||||
</button>
|
||||
<ReactFlow nodes={nodes} onNodesChange={onNodesChange} fitView></ReactFlow>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -51,11 +51,14 @@ export function NodesSelection<NodeType extends Node>({
|
||||
}
|
||||
}, [disableKeyboardA11y]);
|
||||
|
||||
const shouldRender = !userSelectionActive && width !== null && height !== null;
|
||||
|
||||
useDrag({
|
||||
nodeRef,
|
||||
disabled: !shouldRender,
|
||||
});
|
||||
|
||||
if (userSelectionActive || !width || !height) {
|
||||
if (!shouldRender) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,10 +52,11 @@ export function useDrag({
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (disabled) {
|
||||
xyDrag.current?.destroy();
|
||||
} else if (nodeRef.current) {
|
||||
xyDrag.current?.update({
|
||||
if (disabled || !nodeRef.current || !xyDrag.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
xyDrag.current.update({
|
||||
noDragClassName,
|
||||
handleSelector,
|
||||
domNode: nodeRef.current,
|
||||
@@ -63,11 +64,11 @@ export function useDrag({
|
||||
nodeId,
|
||||
nodeClickDistance,
|
||||
});
|
||||
|
||||
return () => {
|
||||
xyDrag.current?.destroy();
|
||||
};
|
||||
}
|
||||
}, [noDragClassName, handleSelector, disabled, isSelectable, nodeRef, nodeId]);
|
||||
}, [noDragClassName, handleSelector, disabled, isSelectable, nodeRef, nodeId, nodeClickDistance]);
|
||||
|
||||
return dragging;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user