Skip to content

Commit 817b0c2

Browse files
committed
refactor: replace cell-based drag detection with pixel-distance threshold
Replace dragMovedToNewCell flag with a 5px pixel-distance threshold for selection drag detection. This prevents jitter from creating accidental selections while allowing precise single-char selection via intentional drag. - Track mousedown pixel position (mouseDownX/mouseDownY) - Only begin selection once mouse moves ≥5px from mousedown - Use squared distance comparison (no sqrt needed) - Clear selection on mouseup if threshold was never met
1 parent 3746232 commit 817b0c2

File tree

1 file changed

+21
-11
lines changed

1 file changed

+21
-11
lines changed

lib/selection-manager.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ export class SelectionManager {
4343
private selectionStart: { col: number; absoluteRow: number } | null = null;
4444
private selectionEnd: { col: number; absoluteRow: number } | null = null;
4545
private isSelecting: boolean = false;
46-
private dragMovedToNewCell: boolean = false; // Track if drag moved to a different cell
46+
private static readonly DRAG_THRESHOLD_PX = 5;
47+
private mouseDownX: number = 0;
48+
private mouseDownY: number = 0;
49+
private dragThresholdMet: boolean = false;
4750
private mouseDownTarget: EventTarget | null = null; // Track where mousedown occurred
4851

4952
// Track rows that need redraw for clearing old selection
@@ -454,27 +457,34 @@ export class SelectionManager {
454457
this.selectionStart = { col: cell.col, absoluteRow };
455458
this.selectionEnd = null; // Don't highlight until drag
456459
this.isSelecting = true;
457-
this.dragMovedToNewCell = false;
460+
this.mouseDownX = e.offsetX;
461+
this.mouseDownY = e.offsetY;
462+
this.dragThresholdMet = false;
458463
}
459464
});
460465

461466
// Mouse move on canvas - update selection
462467
canvas.addEventListener('mousemove', (e: MouseEvent) => {
463468
if (this.isSelecting) {
469+
// Check if drag threshold has been met
470+
if (!this.dragThresholdMet) {
471+
const dx = e.offsetX - this.mouseDownX;
472+
const dy = e.offsetY - this.mouseDownY;
473+
if (
474+
dx * dx + dy * dy <
475+
SelectionManager.DRAG_THRESHOLD_PX * SelectionManager.DRAG_THRESHOLD_PX
476+
) {
477+
return; // Below threshold, ignore
478+
}
479+
this.dragThresholdMet = true;
480+
}
481+
464482
// Mark current selection rows as dirty before updating
465483
this.markCurrentSelectionDirty();
466484

467485
const cell = this.pixelToCell(e.offsetX, e.offsetY);
468486
const absoluteRow = this.viewportRowToAbsolute(cell.row);
469487
this.selectionEnd = { col: cell.col, absoluteRow };
470-
471-
// Track if mouse has moved to a different cell than the start
472-
if (
473-
this.selectionStart &&
474-
(cell.col !== this.selectionStart.col || absoluteRow !== this.selectionStart.absoluteRow)
475-
) {
476-
this.dragMovedToNewCell = true;
477-
}
478488
this.requestRender();
479489

480490
// Check if near edges for auto-scroll
@@ -561,7 +571,7 @@ export class SelectionManager {
561571

562572
// Check if this was a click without drag, or sub-cell jitter.
563573
// If the mouse never moved to a different cell, treat as a click.
564-
if (!this.selectionEnd || !this.dragMovedToNewCell) {
574+
if (!this.selectionEnd || !this.dragThresholdMet) {
565575
this.clearSelection();
566576
return;
567577
}

0 commit comments

Comments
 (0)