Better selection usability (#4379)

* use pointer capture for selection boxes

* fixed selection box behaviour

* promoted modifier listeners to window level

* selection should still happen when shift key is let go during selection

* ported changes to svelte flow

* review changes
This commit is contained in:
Peter Kogo
2024-06-19 17:05:04 +02:00
committed by GitHub
parent 75acd24cee
commit 86438a954f
4 changed files with 67 additions and 40 deletions
@@ -75,15 +75,24 @@
$selectionKeyPressed || $selectionRect || (selectionOnDrag && _panOnDrag !== true);
$: hasActiveSelection = $elementsSelectable && (isSelecting || $selectionRectMode === 'user');
function onClick(event: MouseEvent | TouchEvent) {
dispatch('paneclick', { event });
// Used to prevent click events when the user lets go of the selectionKey during a selection
let selectionInProgress = false;
function onClick(event: MouseEvent | TouchEvent) {
// We prevent click events when the user let go of the selectionKey during a selection
if (selectionInProgress) {
selectionInProgress = false;
return;
}
dispatch('paneclick', { event });
unselectNodesAndEdges();
selectionRectMode.set(null);
}
function onMouseDown(event: MouseEvent) {
function onPointerDown(event: PointerEvent) {
containerBounds = container.getBoundingClientRect();
container.setPointerCapture(event.pointerId);
if (
!elementsSelectable ||
@@ -111,10 +120,13 @@
// onSelectionStart?.(event);
}
function onMouseMove(event: MouseEvent) {
function onPointerMove(event: PointerEvent) {
if (!isSelecting || !containerBounds || !$selectionRect) {
return;
}
selectionInProgress = true;
const mousePos = getEventPosition(event, containerBounds);
const startX = $selectionRect.startX ?? 0;
const startY = $selectionRect.startY ?? 0;
@@ -157,11 +169,13 @@
selectionRect.set(nextUserSelectRect);
}
function onMouseUp(event: MouseEvent) {
function onPointerUp(event: PointerEvent) {
if (event.button !== 0) {
return;
}
container.releasePointerCapture(event.pointerId);
// We only want to trigger click functions when in selection mode if
// the user did not move the mouse.
if (!isSelecting && $selectionRectMode === 'user' && event.target === container) {
@@ -173,17 +187,14 @@
$selectionRectMode = 'nodes';
}
// onSelectionEnd?.(event);
}
const onMouseLeave = () => {
if ($selectionRectMode === 'user') {
selectionRectMode.set(selectedNodes.length > 0 ? 'nodes' : null);
// onSelectionEnd?.(event);
// If the user kept holding the selectionKey during the selection,
// we need to reset the selectionInProgress, so the next click event is not prevented
if ($selectionKeyPressed) {
selectionInProgress = false;
}
selectionRect.set(null);
};
// onSelectionEnd?.(event);
}
const onContextMenu = (event: MouseEvent) => {
if (Array.isArray(_panOnDrag) && _panOnDrag?.includes(2)) {
@@ -204,10 +215,9 @@
class:dragging={$dragging}
class:selection={isSelecting}
on:click={hasActiveSelection ? undefined : wrapHandler(onClick, container)}
on:mousedown={hasActiveSelection ? onMouseDown : undefined}
on:mousemove={hasActiveSelection ? onMouseMove : undefined}
on:mouseup={hasActiveSelection ? onMouseUp : undefined}
on:mouseleave={hasActiveSelection ? onMouseLeave : undefined}
on:pointerdown={hasActiveSelection ? onPointerDown : undefined}
on:pointermove={hasActiveSelection ? onPointerMove : undefined}
on:pointerup={hasActiveSelection ? onPointerUp : undefined}
on:contextmenu={wrapHandler(onContextMenu, container)}
>
<slot />