fix(editor): Support middle click to scroll when using a mouse on new canvas (#11384)

This commit is contained in:
Alex Grozav 2024-10-24 16:51:37 +03:00 committed by GitHub
parent 74d870530b
commit 46f3b4a258
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 55 additions and 16 deletions

View file

@ -220,4 +220,20 @@ describe('Canvas', () => {
expect(container.querySelector('#diagonalHatch')).toBeInTheDocument(); expect(container.querySelector('#diagonalHatch')).toBeInTheDocument();
}); });
}); });
describe('pane', () => {
describe('onPaneMouseDown', () => {
it('should enable panning when middle mouse button is pressed', async () => {
const { getByTestId } = renderComponent();
const canvas = getByTestId('canvas');
const pane = canvas.querySelector('.vue-flow__pane');
if (!pane) throw new Error('VueFlow pane not in the document');
await fireEvent.mouseDown(canvas, { button: 1, view: window });
expect(canvas).toHaveClass('draggable');
});
});
});
}); });

View file

@ -43,6 +43,7 @@ import { onKeyDown, onKeyUp, useDebounceFn } from '@vueuse/core';
import CanvasArrowHeadMarker from './elements/edges/CanvasArrowHeadMarker.vue'; import CanvasArrowHeadMarker from './elements/edges/CanvasArrowHeadMarker.vue';
import { CanvasNodeRenderType } from '@/types'; import { CanvasNodeRenderType } from '@/types';
import CanvasBackgroundStripedPattern from './elements/CanvasBackgroundStripedPattern.vue'; import CanvasBackgroundStripedPattern from './elements/CanvasBackgroundStripedPattern.vue';
import { isMiddleMouseButton } from '@/utils/eventUtils';
const $style = useCssModule(); const $style = useCssModule();
@ -107,6 +108,7 @@ const props = withDefaults(
); );
const { const {
vueFlowRef,
getSelectedNodes: selectedNodes, getSelectedNodes: selectedNodes,
addSelectedNodes, addSelectedNodes,
removeSelectedNodes, removeSelectedNodes,
@ -143,18 +145,16 @@ const disableKeyBindings = computed(() => !props.keyBindings);
* @see https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values#whitespace_keys * @see https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values#whitespace_keys
*/ */
const isPanningEnabled = ref(false);
const panningKeyCode = ' '; const panningKeyCode = ' ';
const isPanningEnabled = ref(false);
const selectionKeyCode = ref<true | null>(true); const selectionKeyCode = ref<true | null>(true);
onKeyDown(panningKeyCode, () => { onKeyDown(panningKeyCode, () => {
isPanningEnabled.value = true; setPanningEnabled(true);
selectionKeyCode.value = null;
}); });
onKeyUp(panningKeyCode, () => { onKeyUp(panningKeyCode, () => {
isPanningEnabled.value = false; setPanningEnabled(false);
selectionKeyCode.value = true;
}); });
const keyMap = computed(() => ({ const keyMap = computed(() => ({
@ -186,6 +186,16 @@ const keyMap = computed(() => ({
useKeybindings(keyMap, { disabled: disableKeyBindings }); useKeybindings(keyMap, { disabled: disableKeyBindings });
function setPanningEnabled(value: boolean) {
if (value) {
isPanningEnabled.value = true;
selectionKeyCode.value = null;
} else {
isPanningEnabled.value = false;
selectionKeyCode.value = true;
}
}
/** /**
* When the window is focused, the selection key code is lost. * When the window is focused, the selection key code is lost.
* We trigger a value refresh to ensure that the selection key code is set correctly again. * We trigger a value refresh to ensure that the selection key code is set correctly again.
@ -384,12 +394,28 @@ function setReadonly(value: boolean) {
elementsSelectable.value = true; elementsSelectable.value = true;
} }
function onPaneMouseDown(event: MouseEvent) {
if (isMiddleMouseButton(event)) {
setPanningEnabled(true);
// Re-emit the event to start panning after setting the panning state to true
// This workaround is necessary because the Vue Flow library does not provide a way to
// start panning programmatically
void nextTick(() =>
vueFlowRef.value
?.querySelector('.vue-flow__pane')
?.dispatchEvent(new MouseEvent('mousedown', event)),
);
}
}
function onPaneMoveStart() { function onPaneMoveStart() {
isPaneMoving.value = true; isPaneMoving.value = true;
} }
function onPaneMoveEnd() { function onPaneMoveEnd() {
isPaneMoving.value = false; isPaneMoving.value = false;
setPanningEnabled(false);
} }
/** /**
@ -559,6 +585,7 @@ provide(CanvasKey, {
@nodes-change="onNodesChange" @nodes-change="onNodesChange"
@move-start="onPaneMoveStart" @move-start="onPaneMoveStart"
@move-end="onPaneMoveEnd" @move-end="onPaneMoveEnd"
@mousedown="onPaneMouseDown"
> >
<template #node-canvas-node="canvasNodeProps"> <template #node-canvas-node="canvasNodeProps">
<Node <Node
@ -647,6 +674,10 @@ provide(CanvasKey, {
cursor: grab; cursor: grab;
} }
:global(.vue-flow__pane) {
cursor: default;
}
:global(.vue-flow__pane.dragging) { :global(.vue-flow__pane.dragging) {
cursor: grabbing; cursor: grabbing;
} }

View file

@ -58,17 +58,6 @@
} }
} }
/**
* Pane
*/
.vue-flow__pane {
&,
&.draggable {
cursor: default;
}
}
/** /**
* Nodes * Nodes
*/ */

View file

@ -0,0 +1,3 @@
export function isMiddleMouseButton(event: MouseEvent) {
return event.which === 2 || event.button === 1;
}