From 7ef3f1e8f61cc74da58d1010059178998aa5205c Mon Sep 17 00:00:00 2001 From: Polle Pas Date: Tue, 7 Nov 2023 13:50:40 +0100 Subject: [PATCH] #638 Select multiple cells by dragging --- .../src/components/TableEditor/Cell.tsx | 23 +++++++++++++++++-- .../TableEditor/TableEditorContext.tsx | 8 +++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/browser/data-browser/src/components/TableEditor/Cell.tsx b/browser/data-browser/src/components/TableEditor/Cell.tsx index 1cefc59e2..6fdee579b 100644 --- a/browser/data-browser/src/components/TableEditor/Cell.tsx +++ b/browser/data-browser/src/components/TableEditor/Cell.tsx @@ -45,6 +45,7 @@ export function Cell({ const ref = useRef(null); const { + mouseDown, selectedRow, selectedColumn, multiSelectCornerRow, @@ -57,6 +58,7 @@ export function Cell({ setCursorMode, registerEventListener, disabledKeyboardInteractions, + setMouseDown, } = useTableEditorContext(); const isActive = rowIndex === selectedRow && columnIndex === selectedColumn; @@ -64,8 +66,21 @@ export function Cell({ rowIndex === multiSelectCornerRow && columnIndex === multiSelectCornerColumn; - const handleClick = useCallback( + const handleMouseUp = useCallback(() => { + setMouseDown(false); + }, []); + + const handleMouseEnter = useCallback(() => { + if (mouseDown) { + setMultiSelectCorner(rowIndex, columnIndex); + setCursorMode(CursorMode.MultiSelect); + } + }, [mouseDown, rowIndex, columnIndex]); + + const handleMouseDown = useCallback( (e: React.MouseEvent) => { + setMouseDown(true); + // When Shift is pressed, enter multi-select mode if (e.shiftKey) { e.stopPropagation(); @@ -90,6 +105,8 @@ export function Cell({ if (isActive && columnIndex !== 0) { // Enter edit mode when clicking on a higlighted cell, except when it's the index column. + setMultiSelectCorner(undefined, undefined); + return setCursorMode(CursorMode.Edit); } @@ -155,10 +172,12 @@ export function Cell({ disabled={disabled} role={role ?? 'gridcell'} className={className} - onClick={handleClick} allowUserSelect={cursorMode === CursorMode.Edit} align={align} tabIndex={isActive ? 0 : -1} + onMouseDown={handleMouseDown} + onMouseUp={handleMouseUp} + onMouseEnter={handleMouseEnter} > {children} diff --git a/browser/data-browser/src/components/TableEditor/TableEditorContext.tsx b/browser/data-browser/src/components/TableEditor/TableEditorContext.tsx index 1d679d70c..82f02d10e 100644 --- a/browser/data-browser/src/components/TableEditor/TableEditorContext.tsx +++ b/browser/data-browser/src/components/TableEditor/TableEditorContext.tsx @@ -28,6 +28,8 @@ function emptySetState(_: T | ((__: T) => T)): undefined { } export interface TableEditorContext { + mouseDown: boolean; + setMouseDown: React.Dispatch>; tableRef: React.MutableRefObject; disabledKeyboardInteractions: Set; setDisabledKeyboardInteractions: React.Dispatch< @@ -62,6 +64,8 @@ export interface TableEditorContext { } const initial = { + mouseDown: false, + setMouseDown: emptySetState, tableRef: { current: null }, disabledKeyboardInteractions: new Set(), setDisabledKeyboardInteractions: emptySetState, @@ -92,6 +96,7 @@ const TableEditorContext = React.createContext(initial); export function TableEditorContextProvider({ children, }: React.PropsWithChildren): JSX.Element { + const [mouseDown, setMouseDown] = useState(false); const tableRef = useRef(null); const listRef = useRef(null); const [eventManager] = useState( @@ -159,6 +164,8 @@ export function TableEditorContextProvider({ const context = useMemo( () => ({ + mouseDown, + setMouseDown, tableRef, disabledKeyboardInteractions, setDisabledKeyboardInteractions, @@ -195,6 +202,7 @@ export function TableEditorContextProvider({ isDragging, cursorMode, emitInteractionsFired, + mouseDown, ], );