Skip to content

Commit

Permalink
feat(editor): Update panning and selection keybindings on new canvas (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
alexgrozav authored Nov 4, 2024
1 parent 5f3deea commit 5e2e205
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 122 deletions.
4 changes: 2 additions & 2 deletions packages/editor-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@
"@n8n/codemirror-lang-sql": "^1.0.2",
"@n8n/permissions": "workspace:*",
"@sentry/vue": "catalog:frontend",
"@vue-flow/background": "^1.3.0",
"@vue-flow/background": "^1.3.1",
"@vue-flow/controls": "^1.1.2",
"@vue-flow/core": "^1.41.2",
"@vue-flow/core": "^1.41.4",
"@vue-flow/minimap": "^1.5.0",
"@vue-flow/node-resizer": "^1.4.0",
"@vueuse/components": "^10.11.0",
Expand Down
16 changes: 0 additions & 16 deletions packages/editor-ui/src/components/canvas/Canvas.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,20 +220,4 @@ describe('Canvas', () => {
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');
});
});
});
});
88 changes: 18 additions & 70 deletions packages/editor-ui/src/components/canvas/Canvas.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,9 @@ import { Background } from '@vue-flow/background';
import { MiniMap } from '@vue-flow/minimap';
import Node from './elements/nodes/CanvasNode.vue';
import Edge from './elements/edges/CanvasEdge.vue';
import {
computed,
nextTick,
onMounted,
onUnmounted,
provide,
ref,
toRef,
useCssModule,
watch,
} from 'vue';
import { computed, onMounted, onUnmounted, provide, ref, toRef, useCssModule, watch } from 'vue';
import type { EventBus } from 'n8n-design-system';
import { createEventBus } from 'n8n-design-system';
import { createEventBus, useDeviceSupport } from 'n8n-design-system';
import { useContextMenu, type ContextMenuAction } from '@/composables/useContextMenu';
import { useKeybindings } from '@/composables/useKeybindings';
import ContextMenu from '@/components/ContextMenu/ContextMenu.vue';
Expand All @@ -42,7 +32,6 @@ import { CanvasKey } from '@/constants';
import { onKeyDown, onKeyUp, useDebounceFn } from '@vueuse/core';
import CanvasArrowHeadMarker from './elements/edges/CanvasArrowHeadMarker.vue';
import CanvasBackgroundStripedPattern from './elements/CanvasBackgroundStripedPattern.vue';
import { isMiddleMouseButton } from '@/utils/eventUtils';
const $style = useCssModule();
Expand Down Expand Up @@ -106,8 +95,9 @@ const props = withDefaults(
},
);
const { controlKeyCode } = useDeviceSupport();
const {
vueFlowRef,
getSelectedNodes: selectedNodes,
addSelectedNodes,
removeSelectedNodes,
Expand All @@ -130,7 +120,6 @@ const isPaneReady = ref(false);
const classes = computed(() => ({
[$style.canvas]: true,
[$style.ready]: isPaneReady.value,
[$style.draggable]: isPanningEnabled.value,
}));
/**
Expand All @@ -143,16 +132,16 @@ const disableKeyBindings = computed(() => !props.keyBindings);
* @see https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values#whitespace_keys
*/
const panningKeyCode = ' ';
const isPanningEnabled = ref(false);
const panningKeyCode = ref<string[]>([' ', controlKeyCode]);
const panningMouseButton = ref<number[]>([1]);
const selectionKeyCode = ref<true | null>(true);
onKeyDown(panningKeyCode, () => {
setPanningEnabled(true);
onKeyDown(panningKeyCode.value, () => {
selectionKeyCode.value = null;
});
onKeyUp(panningKeyCode, () => {
setPanningEnabled(false);
onKeyUp(panningKeyCode.value, () => {
selectionKeyCode.value = true;
});
const keyMap = computed(() => ({
Expand Down Expand Up @@ -184,29 +173,6 @@ const keyMap = computed(() => ({
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.
* We trigger a value refresh to ensure that the selection key code is set correctly again.
*
* @issue https://linear.app/n8n/issue/N8N-7843/selection-keycode-gets-unset-when-changing-tabs
*/
function resetSelectionKeyCode() {
selectionKeyCode.value = null;
void nextTick(() => {
selectionKeyCode.value = true;
});
}
/**
* Nodes
*/
Expand Down Expand Up @@ -392,28 +358,12 @@ function setReadonly(value: boolean) {
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() {
isPaneMoving.value = true;
}
function onPaneMoveEnd() {
isPaneMoving.value = false;
setPanningEnabled(false);
}
/**
Expand Down Expand Up @@ -522,13 +472,11 @@ function onMinimapMouseLeave() {
onMounted(() => {
props.eventBus.on('fitView', onFitView);
props.eventBus.on('nodes:select', onSelectNodes);
window.addEventListener('focus', resetSelectionKeyCode);
});
onUnmounted(() => {
props.eventBus.off('fitView', onFitView);
props.eventBus.off('nodes:select', onSelectNodes);
window.removeEventListener('focus', resetSelectionKeyCode);
});
onPaneReady(async () => {
Expand Down Expand Up @@ -560,6 +508,7 @@ provide(CanvasKey, {
:apply-changes="false"
:connection-line-options="{ markerEnd: MarkerType.ArrowClosed }"
:connection-radius="60"
:pan-on-drag="panningMouseButton"
pan-on-scroll
snap-to-grid
:snap-grid="[GRID_SIZE, GRID_SIZE]"
Expand All @@ -578,7 +527,6 @@ provide(CanvasKey, {
@nodes-change="onNodesChange"
@move-start="onPaneMoveStart"
@move-end="onPaneMoveEnd"
@mousedown="onPaneMouseDown"
>
<template #node-canvas-node="canvasNodeProps">
<Node
Expand Down Expand Up @@ -663,16 +611,16 @@ provide(CanvasKey, {
opacity: 1;
}
&.draggable :global(.vue-flow__pane) {
:global(.vue-flow__pane) {
cursor: grab;
}
:global(.vue-flow__pane) {
cursor: default;
}
&:global(.selection) {
cursor: default;
}
:global(.vue-flow__pane.dragging) {
cursor: grabbing;
&:global(.dragging) {
cursor: grabbing;
}
}
}
</style>
Expand Down
Loading

0 comments on commit 5e2e205

Please sign in to comment.