react-konva-grid
Version:
Canvas grid to render large set of tabular data with virtualization.
96 lines (79 loc) • 2.65 kB
text/typescript
import React, { useState, useCallback, useRef } from "react";
import { IArea, TGridRef } from "./../Grid";
interface IOptions {
gridRef?: TGridRef;
initialSelections?: IArea[];
}
/**
* useSelection hook to enable selection in datagrid
* @param initialSelection
*/
const useSelection = (options: IOptions = {}) => {
const { gridRef, initialSelections = [] } = options;
const [selections, setSelections] = useState<IArea[]>(initialSelections);
const selectionStart = useRef<IArea>();
const isSelectionMode = useRef<boolean>();
const handleMouseDown = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
/* Exit early if grid is not initialized */
if (!gridRef || !gridRef.current) return;
/* Activate selection mode */
isSelectionMode.current = true;
const { rowIndex, columnIndex } = gridRef.current.getCellCoordsFromOffsets(
e.clientX,
e.clientY
);
/* To cater to merged Cells, get the bounds from internal fn */
const bounds = gridRef.current.getCellBounds({ rowIndex, columnIndex });
/**
* Save the initial Selection in ref
* so we can adjust the bounds in mousemove
*/
selectionStart.current = bounds;
/* Add selection to state */
setSelections([bounds]);
}, []);
/**
* Mousemove handler
*/
const handleMouseMove = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
/* Exit if user is not in selection mode */
if (!isSelectionMode.current || !gridRef) return;
/* Get the current selection */
const _selectionStart = selectionStart.current as IArea;
/* Exit early */
if (!_selectionStart) return;
const {
rowIndex,
columnIndex,
} = gridRef.current.getCellCoordsFromOffsets(e.clientX, e.clientY);
/* Get new bounds */
const bounds = gridRef.current.getCellBounds({ rowIndex, columnIndex });
setSelections((prevSelection) => {
return prevSelection.map((selection) => {
return {
top: Math.min(bounds.top, _selectionStart.top),
bottom: Math.max(bounds.bottom, _selectionStart.bottom),
left: Math.min(bounds.left, _selectionStart.left),
right: Math.max(bounds.right, _selectionStart.right),
};
});
});
},
[isSelectionMode]
);
/**
* Mouse up handler
*/
const handleMouseUp = useCallback(() => {
/* Reset selection mode */
isSelectionMode.current = false;
}, []);
return {
selections,
onMouseDown: handleMouseDown,
onMouseMove: handleMouseMove,
onMouseUp: handleMouseUp,
};
};
export default useSelection;