grid-cell-selection 1.0.4 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -14,6 +14,8 @@ npm install grid-cell-selection
14
14
 
15
15
  ## Usage
16
16
 
17
+ ### Mouse Only
18
+
17
19
  ```tsx
18
20
  import React from "react";
19
21
  import { useGridCellSelection } from "grid-cell-selection";
@@ -32,6 +34,7 @@ function App() {
32
34
  <tr key={row}>
33
35
  {columns.map((column, col) => (
34
36
  <td
37
+ key={`${row}-${col}`}
35
38
  onMouseEnter={(event) => handleMouseEnter({ id: `${row}-${col}`, row, col }, event)}
36
39
  onMouseDown={(event) => handleMouseDown({ id: `${row}-${col}`, row, col }, event)}
37
40
  className={`${isCellSelected({ id: `${row}-${col}`, row, col }) ? "selected" : ""}`}
@@ -49,6 +52,60 @@ function App() {
49
52
  }
50
53
  ```
51
54
 
55
+ ### Mouse + Touch
56
+
57
+ > Note that data-cell-id, data-cell-row, and data-cell-col are required for touch events to work.
58
+
59
+ ```tsx
60
+ function App() {
61
+ const columns = ["A", "B", "C", "D", "E", "F", "G"];
62
+ const rows = 100;
63
+
64
+ const { isCellSelected, handleMouseDown, handleMouseEnter, handleMouseUp, handleTouchMove, handleTouchStart } =
65
+ useGridCellSelection({
66
+ options: { allowYScrollSelection: true, clearSelectionOnScroll: true, scrollThreshold: 100 },
67
+ });
68
+
69
+ return (
70
+ <table
71
+ onMouseUp={handleMouseUp}
72
+ onTouchMove={handleTouchMove}
73
+ onTouchEnd={handleMouseUp}
74
+ style={{ touchAction: "none" }}
75
+ >
76
+ <tbody>
77
+ {Array.from({ length: rows }, (_, row) => (
78
+ <tr key={row}>
79
+ {columns.map((column, col) => (
80
+ <td
81
+ key={`${row}-${col}`}
82
+ onMouseEnter={(event) => handleMouseEnter({ id: `${row}-${col}`, row, col }, event)}
83
+ onMouseDown={(event) => handleMouseDown({ id: `${row}-${col}`, row, col }, event)}
84
+ onTouchStart={(event) => handleTouchStart({ id: `${row}-${col}`, row, col }, event)}
85
+ className={`${isCellSelected({ id: `${row}-${col}`, row, col }) ? "selected" : ""}`}
86
+ data-cell-id={`${row}-${col}`} // Required for touch events
87
+ data-cell-row={row} // Required for touch events
88
+ data-cell-col={col} // Required for touch events
89
+ >
90
+ {column}
91
+ {row}
92
+ </td>
93
+ ))}
94
+ </tr>
95
+ ))}
96
+ </tbody>
97
+ </table>
98
+ );
99
+ }
100
+ ```
101
+
102
+ ```
103
+ Options:
104
+ - allowYScrollSelection: boolean - Whether to allow vertical scrolling selection
105
+ - clearSelectionOnScroll: boolean - Whether to clear the selection when the user scrolls
106
+ - scrollThreshold: number - The number of pixels the user must scroll before the selection is cleared
107
+ ```
108
+
52
109
  ## Cell Selection Behavior
53
110
 
54
111
  ### Single Cell Selection
@@ -1,10 +1,15 @@
1
1
  /// <reference types="react" />
2
- import { CellIdentifier } from "../types";
3
- export declare const useGridCellSelection: (allCells?: CellIdentifier[]) => {
2
+ import { CellIdentifier, SelectionOptions } from "../types";
3
+ export declare const useGridCellSelection: ({ allCells, options, }: {
4
+ allCells?: CellIdentifier[] | undefined;
5
+ options?: SelectionOptions | undefined;
6
+ }) => {
4
7
  selectedCells: Map<string, CellIdentifier>;
5
8
  isCellSelected: (cell: CellIdentifier) => boolean;
6
- handleMouseDown: (cell: CellIdentifier, event: import("react").MouseEvent<Element, MouseEvent>) => void;
7
- handleMouseEnter: (cell: CellIdentifier, event: import("react").MouseEvent<Element, MouseEvent>) => void;
9
+ handleMouseDown: (cell: CellIdentifier, event: import("react").MouseEvent<Element, MouseEvent> | import("react").TouchEvent<Element>) => void;
10
+ handleMouseEnter: (cell: CellIdentifier, event: import("react").MouseEvent<Element, MouseEvent> | import("react").TouchEvent<Element>) => void;
8
11
  handleMouseUp: () => void;
12
+ handleTouchMove: (event: React.TouchEvent) => void;
13
+ handleTouchStart: (cell: CellIdentifier, event: import("react").TouchEvent<Element>) => void;
9
14
  resetSelection: () => void;
10
15
  };
@@ -1,6 +1,7 @@
1
- import { CellIdentifier } from "../types";
2
- export declare const useMouseDragSelection: (toggleCellSelection: (cell: CellIdentifier, ctrlKey: boolean, shiftKey: boolean, newSelection: boolean) => void) => {
3
- handleMouseDown: (cell: CellIdentifier, event: React.MouseEvent) => void;
4
- handleMouseEnter: (cell: CellIdentifier, event: React.MouseEvent) => void;
1
+ import { CellIdentifier, SelectionOptions } from "../types";
2
+ export declare const useMouseDragSelection: (toggleCellSelection: (cell: CellIdentifier, ctrlKey: boolean, shiftKey: boolean, newSelection: boolean) => void, resetSelection: () => void, options: SelectionOptions) => {
3
+ handleMouseDown: (cell: CellIdentifier, event: React.MouseEvent | React.TouchEvent) => void;
4
+ handleMouseEnter: (cell: CellIdentifier, event: React.MouseEvent | React.TouchEvent) => void;
5
5
  handleMouseUp: () => void;
6
+ handleTouchStart: (cell: CellIdentifier, event: React.TouchEvent) => void;
6
7
  };
package/dist/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import { useState } from 'react';
1
+ import { useState, useRef, useCallback } from 'react';
2
2
 
3
3
  /******************************************************************************
4
4
  Copyright (c) Microsoft Corporation.
@@ -31,34 +31,64 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
31
31
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
32
32
  };
33
33
 
34
- var useMouseDragSelection = function (toggleCellSelection) {
34
+ var useMouseDragSelection = function (toggleCellSelection, resetSelection, options) {
35
35
  var _a = useState(false), isDragging = _a[0], setIsDragging = _a[1];
36
- var handleMouseDown = function (cell, event) {
36
+ var selectionStartScrollY = useRef(null);
37
+ var initialCellRef = useRef(null);
38
+ var handleTouchStart = function (cell, event) {
37
39
  setIsDragging(true);
40
+ initialCellRef.current = cell;
41
+ selectionStartScrollY.current = window.scrollY;
38
42
  toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, true);
39
43
  };
40
44
  var handleMouseEnter = function (cell, event) {
41
45
  if (isDragging) {
46
+ // Check if the user is dragging vertically
47
+ var isDraggingVertically = initialCellRef.current && cell.row !== initialCellRef.current.row;
48
+ // If the user is dragging vertically, prevent the selection
49
+ if (!options.allowYScrollSelection && isDraggingVertically) {
50
+ return;
51
+ }
42
52
  toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, false);
43
53
  }
44
54
  };
55
+ var handleMouseDown = function (cell, event) {
56
+ if (!isDragging) {
57
+ setIsDragging(true);
58
+ initialCellRef.current = cell;
59
+ toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, true);
60
+ }
61
+ };
45
62
  var handleMouseUp = function () {
46
63
  setIsDragging(false);
64
+ if (selectionStartScrollY.current !== null && options.clearSelectionOnScroll) {
65
+ console.log("scrollY", window.scrollY, "selectionStartScrollY", selectionStartScrollY.current);
66
+ if (Math.abs(window.scrollY - selectionStartScrollY.current) > options.scrollThreshold) {
67
+ resetSelection();
68
+ }
69
+ }
70
+ selectionStartScrollY.current = null;
47
71
  };
48
72
  return {
49
73
  handleMouseDown: handleMouseDown,
50
74
  handleMouseEnter: handleMouseEnter,
51
75
  handleMouseUp: handleMouseUp,
76
+ handleTouchStart: handleTouchStart,
52
77
  };
53
78
  };
54
79
 
55
80
  var getCellKey = function (cell) {
56
81
  return "".concat(cell.row, "-").concat(cell.col);
57
82
  };
58
- var useGridCellSelection = function (allCells) {
59
- var _a = useState({
83
+ var useGridCellSelection = function (_a) {
84
+ var allCells = _a.allCells, _b = _a.options, options = _b === void 0 ? {
85
+ allowYScrollSelection: true,
86
+ clearSelectionOnScroll: false,
87
+ scrollThreshold: 100,
88
+ } : _b;
89
+ var _c = useState({
60
90
  selectedCells: new Map(),
61
- }), selectionState = _a[0], setSelectionState = _a[1];
91
+ }), selectionState = _c[0], setSelectionState = _c[1];
62
92
  var toggleCellSelection = function (cell, ctrlKey, shiftKey, newSelection) {
63
93
  if (ctrlKey === void 0) { ctrlKey = false; }
64
94
  if (shiftKey === void 0) { shiftKey = false; }
@@ -90,13 +120,31 @@ var useGridCellSelection = function (allCells) {
90
120
  var resetSelection = function () {
91
121
  setSelectionState({ selectedCells: new Map() });
92
122
  };
93
- var _b = useMouseDragSelection(toggleCellSelection), handleMouseDown = _b.handleMouseDown, handleMouseEnter = _b.handleMouseEnter, handleMouseUp = _b.handleMouseUp;
123
+ var handleTouchMove = useCallback(function (event) {
124
+ // Get the touch point
125
+ console.log("selectedCells", selectionState.selectedCells);
126
+ if (selectionState.selectedCells.size > 0) {
127
+ var touch = event.touches[0];
128
+ var target = document.elementFromPoint(touch.clientX, touch.clientY);
129
+ // Get closest cell
130
+ var closest = target === null || target === void 0 ? void 0 : target.closest("[data-cell-id]");
131
+ var cellId = closest === null || closest === void 0 ? void 0 : closest.getAttribute("data-cell-id");
132
+ var cellRow = closest === null || closest === void 0 ? void 0 : closest.getAttribute("data-cell-row");
133
+ var cellCol = closest === null || closest === void 0 ? void 0 : closest.getAttribute("data-cell-col");
134
+ if (cellId && cellRow && cellCol && !selectionState.selectedCells.has(cellId)) {
135
+ handleMouseEnter({ id: cellId, row: parseInt(cellRow), col: parseInt(cellCol) }, event);
136
+ }
137
+ }
138
+ }, [selectionState.selectedCells]);
139
+ var _d = useMouseDragSelection(toggleCellSelection, resetSelection, options), handleMouseDown = _d.handleMouseDown, handleMouseEnter = _d.handleMouseEnter, handleMouseUp = _d.handleMouseUp, handleTouchStart = _d.handleTouchStart;
94
140
  return {
95
141
  selectedCells: selectionState.selectedCells,
96
142
  isCellSelected: isCellSelected,
97
143
  handleMouseDown: handleMouseDown,
98
144
  handleMouseEnter: handleMouseEnter,
99
145
  handleMouseUp: handleMouseUp,
146
+ handleTouchMove: handleTouchMove,
147
+ handleTouchStart: handleTouchStart,
100
148
  resetSelection: resetSelection,
101
149
  };
102
150
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/hooks/useMouseDragSelection.ts","../src/hooks/useCellSelection.ts"],"sourcesContent":["import { useState } from \"react\";\nimport { CellIdentifier } from \"../types\";\n\nexport const useMouseDragSelection = (\n toggleCellSelection: (cell: CellIdentifier, ctrlKey: boolean, shiftKey: boolean, newSelection: boolean) => void\n) => {\n const [isDragging, setIsDragging] = useState(false);\n\n const handleMouseDown = (cell: CellIdentifier, event: React.MouseEvent) => {\n setIsDragging(true);\n toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, true);\n };\n\n const handleMouseEnter = (cell: CellIdentifier, event: React.MouseEvent) => {\n if (isDragging) {\n toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, false);\n }\n };\n\n const handleMouseUp = () => {\n setIsDragging(false);\n };\n\n return {\n handleMouseDown,\n handleMouseEnter,\n handleMouseUp,\n };\n};\n","import { useState } from \"react\";\nimport { CellIdentifier, SelectionState } from \"../types\";\nimport { useMouseDragSelection } from \"./useMouseDragSelection\";\n\nconst getCellKey = (cell: Omit<CellIdentifier, \"id\">): string => {\n return `${cell.row}-${cell.col}`;\n};\n\nexport const useGridCellSelection = (allCells?: CellIdentifier[]) => {\n const [selectionState, setSelectionState] = useState<SelectionState>({\n selectedCells: new Map<string, CellIdentifier>(),\n });\n\n const toggleCellSelection = (cell: CellIdentifier, ctrlKey = false, shiftKey = false, newSelection = false) => {\n setSelectionState((prevState) => {\n const selectedCells = new Map(prevState.selectedCells);\n const cellKey = getCellKey(cell);\n\n if (prevState.startCell && !newSelection) {\n handleRangeSelection(selectedCells, prevState.startCell, cell, allCells);\n } else if ((shiftKey || ctrlKey) && newSelection) {\n handleSingleOrMultipleSelection(selectedCells, cellKey, cell);\n } else {\n if (selectedCells.has(cellKey)) {\n selectedCells.clear();\n } else {\n selectedCells.clear();\n selectedCells.set(cellKey, cell);\n }\n }\n\n return {\n ...prevState,\n selectedCells,\n startCell: newSelection ? cell : prevState.startCell,\n };\n });\n };\n\n const isCellSelected = (cell: CellIdentifier) => {\n return selectionState.selectedCells.has(getCellKey(cell));\n };\n\n const resetSelection = () => {\n setSelectionState({ selectedCells: new Map<string, CellIdentifier>() });\n };\n\n const { handleMouseDown, handleMouseEnter, handleMouseUp } = useMouseDragSelection(toggleCellSelection);\n\n return {\n selectedCells: selectionState.selectedCells,\n isCellSelected,\n handleMouseDown,\n handleMouseEnter,\n handleMouseUp,\n resetSelection,\n };\n};\n\n// Updated helper functions\nfunction handleRangeSelection(\n selectedCells: Map<string, CellIdentifier>,\n startCell: CellIdentifier,\n endCell: CellIdentifier,\n allCells?: CellIdentifier[]\n) {\n const action = selectedCells.has(getCellKey(startCell)) ? \"set\" : \"delete\";\n const [startRow, startCol] = [startCell.row, startCell.col];\n const [endRow, endCol] = [endCell.row, endCell.col];\n\n const minRow = Math.min(startRow, endRow);\n const maxRow = Math.max(startRow, endRow);\n const minCol = Math.min(startCol, endCol);\n const maxCol = Math.max(startCol, endCol);\n\n for (let row = minRow; row <= maxRow; row++) {\n for (let col = minCol; col <= maxCol; col++) {\n const cellKey = getCellKey({ row, col });\n if (action === \"set\") {\n if (allCells) {\n const cell = allCells.find((c) => c.row === row && c.col === col);\n cell && selectedCells.set(cellKey, cell);\n } else {\n selectedCells.set(cellKey, { id: cellKey, row, col });\n }\n } else {\n selectedCells.delete(cellKey);\n }\n }\n }\n}\n\nfunction handleSingleOrMultipleSelection(\n selectedCells: Map<string, CellIdentifier>,\n cellKey: string,\n cell: CellIdentifier\n) {\n if (selectedCells.has(cellKey)) {\n selectedCells.delete(cellKey);\n } else {\n selectedCells.set(cellKey, cell);\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.esm.js","sources":["../src/hooks/useMouseDragSelection.ts","../src/hooks/useCellSelection.ts"],"sourcesContent":["import { useRef, useState } from \"react\";\nimport { CellIdentifier, SelectionOptions } from \"../types\";\n\nexport const useMouseDragSelection = (\n toggleCellSelection: (cell: CellIdentifier, ctrlKey: boolean, shiftKey: boolean, newSelection: boolean) => void,\n resetSelection: () => void,\n options: SelectionOptions\n) => {\n const [isDragging, setIsDragging] = useState(false);\n\n const selectionStartScrollY = useRef<number | null>(null);\n const initialCellRef = useRef<CellIdentifier | null>(null);\n\n const handleTouchStart = (cell: CellIdentifier, event: React.TouchEvent) => {\n setIsDragging(true);\n initialCellRef.current = cell;\n selectionStartScrollY.current = window.scrollY;\n toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, true);\n };\n\n const handleMouseEnter = (cell: CellIdentifier, event: React.MouseEvent | React.TouchEvent) => {\n if (isDragging) {\n // Check if the user is dragging vertically\n const isDraggingVertically = initialCellRef.current && cell.row !== initialCellRef.current.row;\n\n // If the user is dragging vertically, prevent the selection\n if (!options.allowYScrollSelection && isDraggingVertically) {\n return;\n }\n\n toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, false);\n }\n };\n\n const handleMouseDown = (cell: CellIdentifier, event: React.MouseEvent | React.TouchEvent) => {\n if (!isDragging) {\n setIsDragging(true);\n initialCellRef.current = cell;\n toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, true);\n }\n };\n\n const handleMouseUp = () => {\n setIsDragging(false);\n if (selectionStartScrollY.current !== null && options.clearSelectionOnScroll) {\n console.log(\"scrollY\", window.scrollY, \"selectionStartScrollY\", selectionStartScrollY.current);\n if (Math.abs(window.scrollY - selectionStartScrollY.current) > options.scrollThreshold) {\n resetSelection();\n }\n }\n selectionStartScrollY.current = null;\n };\n\n return {\n handleMouseDown,\n handleMouseEnter,\n handleMouseUp,\n handleTouchStart,\n };\n};\n","import { useCallback, useState } from \"react\";\nimport { CellIdentifier, SelectionOptions, SelectionState } from \"../types\";\nimport { useMouseDragSelection } from \"./useMouseDragSelection\";\n\nconst getCellKey = (cell: Omit<CellIdentifier, \"id\">): string => {\n return `${cell.row}-${cell.col}`;\n};\n\nexport const useGridCellSelection = ({\n allCells,\n options = {\n allowYScrollSelection: true,\n clearSelectionOnScroll: false,\n scrollThreshold: 100,\n },\n}: {\n allCells?: CellIdentifier[];\n options?: SelectionOptions;\n}) => {\n const [selectionState, setSelectionState] = useState<SelectionState>({\n selectedCells: new Map<string, CellIdentifier>(),\n });\n\n const toggleCellSelection = (cell: CellIdentifier, ctrlKey = false, shiftKey = false, newSelection = false) => {\n setSelectionState((prevState) => {\n const selectedCells = new Map(prevState.selectedCells);\n const cellKey = getCellKey(cell);\n\n if (prevState.startCell && !newSelection) {\n handleRangeSelection(selectedCells, prevState.startCell, cell, allCells);\n } else if ((shiftKey || ctrlKey) && newSelection) {\n handleSingleOrMultipleSelection(selectedCells, cellKey, cell);\n } else {\n if (selectedCells.has(cellKey)) {\n selectedCells.clear();\n } else {\n selectedCells.clear();\n selectedCells.set(cellKey, cell);\n }\n }\n\n return {\n ...prevState,\n selectedCells,\n startCell: newSelection ? cell : prevState.startCell,\n };\n });\n };\n\n const isCellSelected = (cell: CellIdentifier) => {\n return selectionState.selectedCells.has(getCellKey(cell));\n };\n\n const resetSelection = () => {\n setSelectionState({ selectedCells: new Map<string, CellIdentifier>() });\n };\n\n const handleTouchMove = useCallback(\n (event: React.TouchEvent) => {\n // Get the touch point\n console.log(\"selectedCells\", selectionState.selectedCells);\n if (selectionState.selectedCells.size > 0) {\n const touch = event.touches[0];\n const target = document.elementFromPoint(touch.clientX, touch.clientY);\n // Get closest cell\n const closest = target?.closest(\"[data-cell-id]\");\n const cellId = closest?.getAttribute(\"data-cell-id\");\n const cellRow = closest?.getAttribute(\"data-cell-row\");\n const cellCol = closest?.getAttribute(\"data-cell-col\");\n if (cellId && cellRow && cellCol && !selectionState.selectedCells.has(cellId)) {\n handleMouseEnter({ id: cellId, row: parseInt(cellRow), col: parseInt(cellCol) }, event);\n }\n }\n },\n [selectionState.selectedCells]\n );\n\n const { handleMouseDown, handleMouseEnter, handleMouseUp, handleTouchStart } = useMouseDragSelection(\n toggleCellSelection,\n resetSelection,\n options\n );\n\n return {\n selectedCells: selectionState.selectedCells,\n isCellSelected,\n handleMouseDown,\n handleMouseEnter,\n handleMouseUp,\n handleTouchMove,\n handleTouchStart,\n resetSelection,\n };\n};\n\n// Updated helper functions\nfunction handleRangeSelection(\n selectedCells: Map<string, CellIdentifier>,\n startCell: CellIdentifier,\n endCell: CellIdentifier,\n allCells?: CellIdentifier[]\n) {\n const action = selectedCells.has(getCellKey(startCell)) ? \"set\" : \"delete\";\n const [startRow, startCol] = [startCell.row, startCell.col];\n const [endRow, endCol] = [endCell.row, endCell.col];\n\n const minRow = Math.min(startRow, endRow);\n const maxRow = Math.max(startRow, endRow);\n const minCol = Math.min(startCol, endCol);\n const maxCol = Math.max(startCol, endCol);\n\n for (let row = minRow; row <= maxRow; row++) {\n for (let col = minCol; col <= maxCol; col++) {\n const cellKey = getCellKey({ row, col });\n if (action === \"set\") {\n if (allCells) {\n const cell = allCells.find((c) => c.row === row && c.col === col);\n cell && selectedCells.set(cellKey, cell);\n } else {\n selectedCells.set(cellKey, { id: cellKey, row, col });\n }\n } else {\n selectedCells.delete(cellKey);\n }\n }\n }\n}\n\nfunction handleSingleOrMultipleSelection(\n selectedCells: Map<string, CellIdentifier>,\n cellKey: string,\n cell: CellIdentifier\n) {\n if (selectedCells.has(cellKey)) {\n selectedCells.delete(cellKey);\n } else {\n selectedCells.set(cellKey, cell);\n }\n}\n"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -35,34 +35,64 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
35
35
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
36
36
  };
37
37
 
38
- var useMouseDragSelection = function (toggleCellSelection) {
38
+ var useMouseDragSelection = function (toggleCellSelection, resetSelection, options) {
39
39
  var _a = react.useState(false), isDragging = _a[0], setIsDragging = _a[1];
40
- var handleMouseDown = function (cell, event) {
40
+ var selectionStartScrollY = react.useRef(null);
41
+ var initialCellRef = react.useRef(null);
42
+ var handleTouchStart = function (cell, event) {
41
43
  setIsDragging(true);
44
+ initialCellRef.current = cell;
45
+ selectionStartScrollY.current = window.scrollY;
42
46
  toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, true);
43
47
  };
44
48
  var handleMouseEnter = function (cell, event) {
45
49
  if (isDragging) {
50
+ // Check if the user is dragging vertically
51
+ var isDraggingVertically = initialCellRef.current && cell.row !== initialCellRef.current.row;
52
+ // If the user is dragging vertically, prevent the selection
53
+ if (!options.allowYScrollSelection && isDraggingVertically) {
54
+ return;
55
+ }
46
56
  toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, false);
47
57
  }
48
58
  };
59
+ var handleMouseDown = function (cell, event) {
60
+ if (!isDragging) {
61
+ setIsDragging(true);
62
+ initialCellRef.current = cell;
63
+ toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, true);
64
+ }
65
+ };
49
66
  var handleMouseUp = function () {
50
67
  setIsDragging(false);
68
+ if (selectionStartScrollY.current !== null && options.clearSelectionOnScroll) {
69
+ console.log("scrollY", window.scrollY, "selectionStartScrollY", selectionStartScrollY.current);
70
+ if (Math.abs(window.scrollY - selectionStartScrollY.current) > options.scrollThreshold) {
71
+ resetSelection();
72
+ }
73
+ }
74
+ selectionStartScrollY.current = null;
51
75
  };
52
76
  return {
53
77
  handleMouseDown: handleMouseDown,
54
78
  handleMouseEnter: handleMouseEnter,
55
79
  handleMouseUp: handleMouseUp,
80
+ handleTouchStart: handleTouchStart,
56
81
  };
57
82
  };
58
83
 
59
84
  var getCellKey = function (cell) {
60
85
  return "".concat(cell.row, "-").concat(cell.col);
61
86
  };
62
- var useGridCellSelection = function (allCells) {
63
- var _a = react.useState({
87
+ var useGridCellSelection = function (_a) {
88
+ var allCells = _a.allCells, _b = _a.options, options = _b === void 0 ? {
89
+ allowYScrollSelection: true,
90
+ clearSelectionOnScroll: false,
91
+ scrollThreshold: 100,
92
+ } : _b;
93
+ var _c = react.useState({
64
94
  selectedCells: new Map(),
65
- }), selectionState = _a[0], setSelectionState = _a[1];
95
+ }), selectionState = _c[0], setSelectionState = _c[1];
66
96
  var toggleCellSelection = function (cell, ctrlKey, shiftKey, newSelection) {
67
97
  if (ctrlKey === void 0) { ctrlKey = false; }
68
98
  if (shiftKey === void 0) { shiftKey = false; }
@@ -94,13 +124,31 @@ var useGridCellSelection = function (allCells) {
94
124
  var resetSelection = function () {
95
125
  setSelectionState({ selectedCells: new Map() });
96
126
  };
97
- var _b = useMouseDragSelection(toggleCellSelection), handleMouseDown = _b.handleMouseDown, handleMouseEnter = _b.handleMouseEnter, handleMouseUp = _b.handleMouseUp;
127
+ var handleTouchMove = react.useCallback(function (event) {
128
+ // Get the touch point
129
+ console.log("selectedCells", selectionState.selectedCells);
130
+ if (selectionState.selectedCells.size > 0) {
131
+ var touch = event.touches[0];
132
+ var target = document.elementFromPoint(touch.clientX, touch.clientY);
133
+ // Get closest cell
134
+ var closest = target === null || target === void 0 ? void 0 : target.closest("[data-cell-id]");
135
+ var cellId = closest === null || closest === void 0 ? void 0 : closest.getAttribute("data-cell-id");
136
+ var cellRow = closest === null || closest === void 0 ? void 0 : closest.getAttribute("data-cell-row");
137
+ var cellCol = closest === null || closest === void 0 ? void 0 : closest.getAttribute("data-cell-col");
138
+ if (cellId && cellRow && cellCol && !selectionState.selectedCells.has(cellId)) {
139
+ handleMouseEnter({ id: cellId, row: parseInt(cellRow), col: parseInt(cellCol) }, event);
140
+ }
141
+ }
142
+ }, [selectionState.selectedCells]);
143
+ var _d = useMouseDragSelection(toggleCellSelection, resetSelection, options), handleMouseDown = _d.handleMouseDown, handleMouseEnter = _d.handleMouseEnter, handleMouseUp = _d.handleMouseUp, handleTouchStart = _d.handleTouchStart;
98
144
  return {
99
145
  selectedCells: selectionState.selectedCells,
100
146
  isCellSelected: isCellSelected,
101
147
  handleMouseDown: handleMouseDown,
102
148
  handleMouseEnter: handleMouseEnter,
103
149
  handleMouseUp: handleMouseUp,
150
+ handleTouchMove: handleTouchMove,
151
+ handleTouchStart: handleTouchStart,
104
152
  resetSelection: resetSelection,
105
153
  };
106
154
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/hooks/useMouseDragSelection.ts","../src/hooks/useCellSelection.ts"],"sourcesContent":["import { useState } from \"react\";\nimport { CellIdentifier } from \"../types\";\n\nexport const useMouseDragSelection = (\n toggleCellSelection: (cell: CellIdentifier, ctrlKey: boolean, shiftKey: boolean, newSelection: boolean) => void\n) => {\n const [isDragging, setIsDragging] = useState(false);\n\n const handleMouseDown = (cell: CellIdentifier, event: React.MouseEvent) => {\n setIsDragging(true);\n toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, true);\n };\n\n const handleMouseEnter = (cell: CellIdentifier, event: React.MouseEvent) => {\n if (isDragging) {\n toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, false);\n }\n };\n\n const handleMouseUp = () => {\n setIsDragging(false);\n };\n\n return {\n handleMouseDown,\n handleMouseEnter,\n handleMouseUp,\n };\n};\n","import { useState } from \"react\";\nimport { CellIdentifier, SelectionState } from \"../types\";\nimport { useMouseDragSelection } from \"./useMouseDragSelection\";\n\nconst getCellKey = (cell: Omit<CellIdentifier, \"id\">): string => {\n return `${cell.row}-${cell.col}`;\n};\n\nexport const useGridCellSelection = (allCells?: CellIdentifier[]) => {\n const [selectionState, setSelectionState] = useState<SelectionState>({\n selectedCells: new Map<string, CellIdentifier>(),\n });\n\n const toggleCellSelection = (cell: CellIdentifier, ctrlKey = false, shiftKey = false, newSelection = false) => {\n setSelectionState((prevState) => {\n const selectedCells = new Map(prevState.selectedCells);\n const cellKey = getCellKey(cell);\n\n if (prevState.startCell && !newSelection) {\n handleRangeSelection(selectedCells, prevState.startCell, cell, allCells);\n } else if ((shiftKey || ctrlKey) && newSelection) {\n handleSingleOrMultipleSelection(selectedCells, cellKey, cell);\n } else {\n if (selectedCells.has(cellKey)) {\n selectedCells.clear();\n } else {\n selectedCells.clear();\n selectedCells.set(cellKey, cell);\n }\n }\n\n return {\n ...prevState,\n selectedCells,\n startCell: newSelection ? cell : prevState.startCell,\n };\n });\n };\n\n const isCellSelected = (cell: CellIdentifier) => {\n return selectionState.selectedCells.has(getCellKey(cell));\n };\n\n const resetSelection = () => {\n setSelectionState({ selectedCells: new Map<string, CellIdentifier>() });\n };\n\n const { handleMouseDown, handleMouseEnter, handleMouseUp } = useMouseDragSelection(toggleCellSelection);\n\n return {\n selectedCells: selectionState.selectedCells,\n isCellSelected,\n handleMouseDown,\n handleMouseEnter,\n handleMouseUp,\n resetSelection,\n };\n};\n\n// Updated helper functions\nfunction handleRangeSelection(\n selectedCells: Map<string, CellIdentifier>,\n startCell: CellIdentifier,\n endCell: CellIdentifier,\n allCells?: CellIdentifier[]\n) {\n const action = selectedCells.has(getCellKey(startCell)) ? \"set\" : \"delete\";\n const [startRow, startCol] = [startCell.row, startCell.col];\n const [endRow, endCol] = [endCell.row, endCell.col];\n\n const minRow = Math.min(startRow, endRow);\n const maxRow = Math.max(startRow, endRow);\n const minCol = Math.min(startCol, endCol);\n const maxCol = Math.max(startCol, endCol);\n\n for (let row = minRow; row <= maxRow; row++) {\n for (let col = minCol; col <= maxCol; col++) {\n const cellKey = getCellKey({ row, col });\n if (action === \"set\") {\n if (allCells) {\n const cell = allCells.find((c) => c.row === row && c.col === col);\n cell && selectedCells.set(cellKey, cell);\n } else {\n selectedCells.set(cellKey, { id: cellKey, row, col });\n }\n } else {\n selectedCells.delete(cellKey);\n }\n }\n }\n}\n\nfunction handleSingleOrMultipleSelection(\n selectedCells: Map<string, CellIdentifier>,\n cellKey: string,\n cell: CellIdentifier\n) {\n if (selectedCells.has(cellKey)) {\n selectedCells.delete(cellKey);\n } else {\n selectedCells.set(cellKey, cell);\n }\n}\n"],"names":["useState"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/hooks/useMouseDragSelection.ts","../src/hooks/useCellSelection.ts"],"sourcesContent":["import { useRef, useState } from \"react\";\nimport { CellIdentifier, SelectionOptions } from \"../types\";\n\nexport const useMouseDragSelection = (\n toggleCellSelection: (cell: CellIdentifier, ctrlKey: boolean, shiftKey: boolean, newSelection: boolean) => void,\n resetSelection: () => void,\n options: SelectionOptions\n) => {\n const [isDragging, setIsDragging] = useState(false);\n\n const selectionStartScrollY = useRef<number | null>(null);\n const initialCellRef = useRef<CellIdentifier | null>(null);\n\n const handleTouchStart = (cell: CellIdentifier, event: React.TouchEvent) => {\n setIsDragging(true);\n initialCellRef.current = cell;\n selectionStartScrollY.current = window.scrollY;\n toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, true);\n };\n\n const handleMouseEnter = (cell: CellIdentifier, event: React.MouseEvent | React.TouchEvent) => {\n if (isDragging) {\n // Check if the user is dragging vertically\n const isDraggingVertically = initialCellRef.current && cell.row !== initialCellRef.current.row;\n\n // If the user is dragging vertically, prevent the selection\n if (!options.allowYScrollSelection && isDraggingVertically) {\n return;\n }\n\n toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, false);\n }\n };\n\n const handleMouseDown = (cell: CellIdentifier, event: React.MouseEvent | React.TouchEvent) => {\n if (!isDragging) {\n setIsDragging(true);\n initialCellRef.current = cell;\n toggleCellSelection(cell, event.ctrlKey || event.metaKey, event.shiftKey, true);\n }\n };\n\n const handleMouseUp = () => {\n setIsDragging(false);\n if (selectionStartScrollY.current !== null && options.clearSelectionOnScroll) {\n console.log(\"scrollY\", window.scrollY, \"selectionStartScrollY\", selectionStartScrollY.current);\n if (Math.abs(window.scrollY - selectionStartScrollY.current) > options.scrollThreshold) {\n resetSelection();\n }\n }\n selectionStartScrollY.current = null;\n };\n\n return {\n handleMouseDown,\n handleMouseEnter,\n handleMouseUp,\n handleTouchStart,\n };\n};\n","import { useCallback, useState } from \"react\";\nimport { CellIdentifier, SelectionOptions, SelectionState } from \"../types\";\nimport { useMouseDragSelection } from \"./useMouseDragSelection\";\n\nconst getCellKey = (cell: Omit<CellIdentifier, \"id\">): string => {\n return `${cell.row}-${cell.col}`;\n};\n\nexport const useGridCellSelection = ({\n allCells,\n options = {\n allowYScrollSelection: true,\n clearSelectionOnScroll: false,\n scrollThreshold: 100,\n },\n}: {\n allCells?: CellIdentifier[];\n options?: SelectionOptions;\n}) => {\n const [selectionState, setSelectionState] = useState<SelectionState>({\n selectedCells: new Map<string, CellIdentifier>(),\n });\n\n const toggleCellSelection = (cell: CellIdentifier, ctrlKey = false, shiftKey = false, newSelection = false) => {\n setSelectionState((prevState) => {\n const selectedCells = new Map(prevState.selectedCells);\n const cellKey = getCellKey(cell);\n\n if (prevState.startCell && !newSelection) {\n handleRangeSelection(selectedCells, prevState.startCell, cell, allCells);\n } else if ((shiftKey || ctrlKey) && newSelection) {\n handleSingleOrMultipleSelection(selectedCells, cellKey, cell);\n } else {\n if (selectedCells.has(cellKey)) {\n selectedCells.clear();\n } else {\n selectedCells.clear();\n selectedCells.set(cellKey, cell);\n }\n }\n\n return {\n ...prevState,\n selectedCells,\n startCell: newSelection ? cell : prevState.startCell,\n };\n });\n };\n\n const isCellSelected = (cell: CellIdentifier) => {\n return selectionState.selectedCells.has(getCellKey(cell));\n };\n\n const resetSelection = () => {\n setSelectionState({ selectedCells: new Map<string, CellIdentifier>() });\n };\n\n const handleTouchMove = useCallback(\n (event: React.TouchEvent) => {\n // Get the touch point\n console.log(\"selectedCells\", selectionState.selectedCells);\n if (selectionState.selectedCells.size > 0) {\n const touch = event.touches[0];\n const target = document.elementFromPoint(touch.clientX, touch.clientY);\n // Get closest cell\n const closest = target?.closest(\"[data-cell-id]\");\n const cellId = closest?.getAttribute(\"data-cell-id\");\n const cellRow = closest?.getAttribute(\"data-cell-row\");\n const cellCol = closest?.getAttribute(\"data-cell-col\");\n if (cellId && cellRow && cellCol && !selectionState.selectedCells.has(cellId)) {\n handleMouseEnter({ id: cellId, row: parseInt(cellRow), col: parseInt(cellCol) }, event);\n }\n }\n },\n [selectionState.selectedCells]\n );\n\n const { handleMouseDown, handleMouseEnter, handleMouseUp, handleTouchStart } = useMouseDragSelection(\n toggleCellSelection,\n resetSelection,\n options\n );\n\n return {\n selectedCells: selectionState.selectedCells,\n isCellSelected,\n handleMouseDown,\n handleMouseEnter,\n handleMouseUp,\n handleTouchMove,\n handleTouchStart,\n resetSelection,\n };\n};\n\n// Updated helper functions\nfunction handleRangeSelection(\n selectedCells: Map<string, CellIdentifier>,\n startCell: CellIdentifier,\n endCell: CellIdentifier,\n allCells?: CellIdentifier[]\n) {\n const action = selectedCells.has(getCellKey(startCell)) ? \"set\" : \"delete\";\n const [startRow, startCol] = [startCell.row, startCell.col];\n const [endRow, endCol] = [endCell.row, endCell.col];\n\n const minRow = Math.min(startRow, endRow);\n const maxRow = Math.max(startRow, endRow);\n const minCol = Math.min(startCol, endCol);\n const maxCol = Math.max(startCol, endCol);\n\n for (let row = minRow; row <= maxRow; row++) {\n for (let col = minCol; col <= maxCol; col++) {\n const cellKey = getCellKey({ row, col });\n if (action === \"set\") {\n if (allCells) {\n const cell = allCells.find((c) => c.row === row && c.col === col);\n cell && selectedCells.set(cellKey, cell);\n } else {\n selectedCells.set(cellKey, { id: cellKey, row, col });\n }\n } else {\n selectedCells.delete(cellKey);\n }\n }\n }\n}\n\nfunction handleSingleOrMultipleSelection(\n selectedCells: Map<string, CellIdentifier>,\n cellKey: string,\n cell: CellIdentifier\n) {\n if (selectedCells.has(cellKey)) {\n selectedCells.delete(cellKey);\n } else {\n selectedCells.set(cellKey, cell);\n }\n}\n"],"names":["useState","useRef","useCallback"],"mappings":"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"}
@@ -3,6 +3,11 @@ export type CellIdentifier = {
3
3
  row: number;
4
4
  col: number;
5
5
  };
6
+ export interface SelectionOptions {
7
+ allowYScrollSelection: boolean;
8
+ clearSelectionOnScroll: boolean;
9
+ scrollThreshold: number;
10
+ }
6
11
  export interface SelectionState {
7
12
  selectedCells: Map<string, CellIdentifier>;
8
13
  startCell?: CellIdentifier;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grid-cell-selection",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "A React hook for grid cell selection",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",