Refine: drag area: pointer movement might prevent action click

This commit is contained in:
aleksey-hoffman committed 2026-07-08 15:43:48 +03:00
1 parent e711a5e33c
commit c776f0ba8b
4 files changed
+140 -10

No files matched your search

@@ -27,7 +27,7 @@ import {
type FileBrowserBoxSelectionBox,
} from '../utils/file-browser-box-selection-hit-test';
import type { FileBrowserVirtualRow } from '../utils/file-browser-virtual-rows';
import { clearDocumentTextSelection } from '../utils/file-browser-document-selection';
import { clearDocumentTextSelection } from '@/utils/document-selection';
const BOX_SELECTION_OVERLAY_CLASS = 'file-browser-box-selection-overlay';
const FILE_BROWSER_CONTENT_SELECTOR = '.file-browser__content';
@@ -6,7 +6,7 @@ import { ref, type Ref } from 'vue';
import type { DirEntry } from '@/types/dir-entry';
import { UI_CONSTANTS } from '@/constants';
import normalizePath from '@/utils/normalize-path';
import { clearDocumentTextSelection } from '../utils/file-browser-document-selection';
import { clearDocumentTextSelection } from '@/utils/document-selection';
export type PendingDoubleClick = {
path: string;
+138 -8
View File
@@ -4,8 +4,9 @@ Copyright © 2021 - present Aleksey Hoffman. All rights reserved.
-->
<script setup lang="ts">
import { computed } from 'vue';
import { computed, onBeforeUnmount } from 'vue';
import { useRoute } from 'vue-router';
import { getCurrentWindow } from '@tauri-apps/api/window';
import Spacer from './spacer.vue';
import WindowActions from './window-actions.vue';
import { GlobalSearchToolbarButton } from '@/modules/global-search';
@@ -13,8 +14,24 @@ import { LanShareReplaceDialog, LanShareToolbarButton } from '@/modules/lan-shar
import { StatusCenterToolbarButton } from '@/modules/status-center';
import CommandPaletteToolbarButton from '@/modules/extensions/components/command-palette-toolbar-button.vue';
import { ProgressiveBlur, type ProgressiveBlurLayer } from '@/components/ui/progressive-blur';
import { clearDocumentTextSelection } from '@/utils/document-selection';
interface ToolbarDragSession {
pointerId: number;
startClientX: number;
startClientY: number;
}
const WINDOW_DRAG_MOVE_THRESHOLD_PX = 8;
const WINDOW_DRAG_CLICK_SUPPRESSION_MS = 300;
const WINDOW_DRAG_EXCLUDED_SELECTOR = '.tab-bar';
const route = useRoute();
const appWindow = getCurrentWindow();
let toolbarDragSession: ToolbarDragSession | null = null;
let shouldSuppressNextToolbarClick = false;
let toolbarClickSuppressionTimeout: number | undefined;
const isAbsolute = computed(() => {
return route.name === 'home';
@@ -54,6 +71,119 @@ const toolbarProgressiveBlurLayers: ProgressiveBlurLayer[] = [
end: '100%',
},
];
function clearToolbarClickSuppression() {
shouldSuppressNextToolbarClick = false;
if (toolbarClickSuppressionTimeout === undefined) {
return;
}
window.clearTimeout(toolbarClickSuppressionTimeout);
toolbarClickSuppressionTimeout = undefined;
}
function suppressNextToolbarClick() {
clearToolbarClickSuppression();
shouldSuppressNextToolbarClick = true;
toolbarClickSuppressionTimeout = window.setTimeout(
clearToolbarClickSuppression,
WINDOW_DRAG_CLICK_SUPPRESSION_MS,
);
}
function startToolbarDragTracking() {
window.addEventListener('pointermove', handleToolbarPointerMove, true);
window.addEventListener('pointerup', handleToolbarPointerEnd, true);
window.addEventListener('pointercancel', handleToolbarPointerEnd, true);
}
function stopToolbarDragTracking() {
window.removeEventListener('pointermove', handleToolbarPointerMove, true);
window.removeEventListener('pointerup', handleToolbarPointerEnd, true);
window.removeEventListener('pointercancel', handleToolbarPointerEnd, true);
}
function finishToolbarDragSession() {
if (!toolbarDragSession) {
return;
}
stopToolbarDragTracking();
toolbarDragSession = null;
}
function shouldSkipToolbarWindowDrag(event: PointerEvent) {
if (event.button !== 0 || !event.isPrimary || event.pointerType !== 'mouse') {
return true;
}
if (!(event.target instanceof Element)) {
return false;
}
return Boolean(event.target.closest(WINDOW_DRAG_EXCLUDED_SELECTOR));
}
function handleToolbarPointerDown(event: PointerEvent) {
if (shouldSkipToolbarWindowDrag(event)) {
return;
}
clearDocumentTextSelection();
finishToolbarDragSession();
toolbarDragSession = {
pointerId: event.pointerId,
startClientX: event.clientX,
startClientY: event.clientY,
};
startToolbarDragTracking();
}
function handleToolbarPointerMove(event: PointerEvent) {
if (!toolbarDragSession || event.pointerId !== toolbarDragSession.pointerId) {
return;
}
const pointerMoveX = event.clientX - toolbarDragSession.startClientX;
const pointerMoveY = event.clientY - toolbarDragSession.startClientY;
const pointerMoveDistanceSquared = pointerMoveX * pointerMoveX + pointerMoveY * pointerMoveY;
if (pointerMoveDistanceSquared < WINDOW_DRAG_MOVE_THRESHOLD_PX ** 2) {
return;
}
finishToolbarDragSession();
suppressNextToolbarClick();
appWindow.startDragging().catch((error: unknown) => {
console.error('Failed to start window drag:', error);
});
}
function handleToolbarPointerEnd(event: PointerEvent) {
if (!toolbarDragSession || event.pointerId !== toolbarDragSession.pointerId) {
return;
}
finishToolbarDragSession();
}
function handleToolbarClick(event: MouseEvent) {
if (!shouldSuppressNextToolbarClick) {
return;
}
event.preventDefault();
event.stopPropagation();
clearToolbarClickSuppression();
}
onBeforeUnmount(() => {
finishToolbarDragSession();
clearToolbarClickSuppression();
});
</script>
<template>
@@ -69,7 +199,11 @@ const toolbarProgressiveBlurLayers: ProgressiveBlurLayer[] = [
class="window-toolbar-progressive-blur"
:layers="toolbarProgressiveBlurLayers"
/>
<div class="window-toolbar-action-layer">
<div
class="window-toolbar-action-layer"
@click.capture="handleToolbarClick"
@pointerdown.capture="handleToolbarPointerDown"
>
<LanShareReplaceDialog />
<CommandPaletteToolbarButton />
<div class="window-toolbar-extension-embed-teleport-target" />
@@ -159,6 +293,7 @@ const toolbarProgressiveBlurLayers: ProgressiveBlurLayer[] = [
.window-toolbar-spacer {
z-index: 4;
-webkit-app-region: drag;
}
.window-toolbar-action-layer {
@@ -170,18 +305,13 @@ const toolbarProgressiveBlurLayers: ProgressiveBlurLayer[] = [
flex: 1 1 auto;
align-items: center;
justify-content: center;
-webkit-app-region: drag;
gap: 8px;
inset-inline-start: 0;
padding-inline-start: 4px;
}
.window-toolbar-action-layer,
.window-toolbar-action-layer :deep(*) {
-webkit-app-region: drag;
}
.window-toolbar-action-layer :deep(.tab-bar),
.window-toolbar-action-layer :deep(.tab-bar *) {
-webkit-app-region: no-drag;
}