diff --git a/.changeset/rare-points-change.md b/.changeset/rare-points-change.md
new file mode 100644
index 00000000..9ce10e25
--- /dev/null
+++ b/.changeset/rare-points-change.md
@@ -0,0 +1,5 @@
+---
+'@reactflow/core': major
+---
+
+track modifier keys on useKeypress
diff --git a/examples/vite-app/src/examples/Figma/index.tsx b/examples/vite-app/src/examples/Figma/index.tsx
index 22f0dcce..64cfb4bb 100644
--- a/examples/vite-app/src/examples/Figma/index.tsx
+++ b/examples/vite-app/src/examples/Figma/index.tsx
@@ -38,6 +38,9 @@ const BasicFlow = () => {
onSelectionContextMenu={onPaneContextMenu}
>
+
+
+
);
};
diff --git a/examples/vite-app/src/examples/UseOnSelectionChange/index.tsx b/examples/vite-app/src/examples/UseOnSelectionChange/index.tsx
index 160ca769..b6f5531f 100644
--- a/examples/vite-app/src/examples/UseOnSelectionChange/index.tsx
+++ b/examples/vite-app/src/examples/UseOnSelectionChange/index.tsx
@@ -18,6 +18,20 @@ const initialNodes: Node[] = [
data: { label: 'Node 1' },
position: { x: 250, y: 5 },
},
+ {
+ id: '2',
+ type: 'default',
+ data: { label: 'Node 2' },
+ position: { x: 250, y: 100 },
+ },
+];
+
+const initialEdges: Edge[] = [
+ {
+ id: 'e1-2',
+ source: '1',
+ target: '2',
+ },
];
const SelectionLogger = () => {
@@ -34,7 +48,7 @@ const SelectionLogger = () => {
const Flow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
- const [edges, setEdges, onEdgesChange] = useEdgesState([]);
+ const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect = useCallback((params: Edge | Connection) => setEdges((els) => addEdge(params, els)), [setEdges]);
return (
@@ -52,6 +66,9 @@ const WrappedFlow = () => (
+
+
+
);
diff --git a/packages/core/src/hooks/useKeyPress.ts b/packages/core/src/hooks/useKeyPress.ts
index 20dcf37e..3301fc8f 100644
--- a/packages/core/src/hooks/useKeyPress.ts
+++ b/packages/core/src/hooks/useKeyPress.ts
@@ -19,6 +19,9 @@ const doc = typeof document !== 'undefined' ? document : null;
export default (keyCode: KeyCode | null = null, options: UseKeyPressOptions = { target: doc }): boolean => {
const [keyPressed, setKeyPressed] = useState(false);
+ // we need to remember if a modifier key is pressed in order to track it
+ const modifierPressed = useRef(false);
+
// we need to remember the pressed keys in order to support combinations
const pressedKeys = useRef(new Set([]));
@@ -43,7 +46,10 @@ export default (keyCode: KeyCode | null = null, options: UseKeyPressOptions = {
useEffect(() => {
if (keyCode !== null) {
const downHandler = (event: KeyboardEvent) => {
- if (isInputDOMNode(event)) {
+
+ modifierPressed.current = event.ctrlKey || event.metaKey || event.shiftKey;
+
+ if (!modifierPressed.current && isInputDOMNode(event)) {
return false;
}
const keyOrCode = useKeyOrCode(event.code, keysToWatch);
@@ -56,7 +62,7 @@ export default (keyCode: KeyCode | null = null, options: UseKeyPressOptions = {
};
const upHandler = (event: KeyboardEvent) => {
- if (isInputDOMNode(event)) {
+ if (!modifierPressed.current && isInputDOMNode(event)) {
return false;
}
const keyOrCode = useKeyOrCode(event.code, keysToWatch);
@@ -67,6 +73,7 @@ export default (keyCode: KeyCode | null = null, options: UseKeyPressOptions = {
} else {
pressedKeys.current.delete(event[keyOrCode]);
}
+ modifierPressed.current = false;
};
const resetHandler = () => {
diff --git a/packages/core/src/utils/index.ts b/packages/core/src/utils/index.ts
index 2d801d05..b4f0ca3f 100644
--- a/packages/core/src/utils/index.ts
+++ b/packages/core/src/utils/index.ts
@@ -104,11 +104,10 @@ export function isInputDOMNode(event: KeyboardEvent | ReactKeyboardEvent): boole
const target = (kbEvent.composedPath?.()?.[0] || event.target) as HTMLElement;
const isInput = ['INPUT', 'SELECT', 'TEXTAREA'].includes(target?.nodeName) || target?.hasAttribute('contenteditable');
- // we want to be able to do a multi selection event if we are in an input field
- const isModifierKey = event.ctrlKey || event.metaKey || event.shiftKey;
+
// when an input field is focused we don't want to trigger deletion or movement of nodes
- return (isInput && !isModifierKey) || !!target?.closest('.nokey');
+ return isInput || !!target?.closest('.nokey');
}
export const isMouseEvent = (