@rowsncolumns/grid 9.0.3 → 13.2.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +100 -0
- package/Readme.md +53 -59
- package/dist/cjs/Cell.d.ts +35 -0
- package/dist/cjs/Cell.d.ts.map +1 -0
- package/dist/cjs/Cell.js +29 -0
- package/dist/{CellOverlay.d.ts → cjs/CellOverlay.d.ts} +5 -5
- package/dist/cjs/CellOverlay.d.ts.map +1 -0
- package/dist/cjs/CellOverlay.js +126 -0
- package/dist/cjs/Context.d.ts +8 -0
- package/dist/cjs/Context.d.ts.map +1 -0
- package/dist/cjs/Context.js +13 -0
- package/dist/{FillHandle.d.ts → cjs/FillHandle.d.ts} +2 -1
- package/dist/cjs/FillHandle.d.ts.map +1 -0
- package/dist/cjs/FillHandle.js +26 -0
- package/dist/cjs/Grid.d.ts +558 -0
- package/dist/cjs/Grid.d.ts.map +1 -0
- package/dist/cjs/Grid.js +2446 -0
- package/dist/{GridLine.d.ts → cjs/GridLine.d.ts} +2 -1
- package/dist/cjs/GridLine.d.ts.map +1 -0
- package/dist/cjs/GridLine.js +10 -0
- package/dist/cjs/Image.d.ts +11 -0
- package/dist/cjs/Image.d.ts.map +1 -0
- package/dist/cjs/Image.js +57 -0
- package/dist/cjs/MemoizedGrid.d.ts +49 -0
- package/dist/cjs/MemoizedGrid.d.ts.map +1 -0
- package/dist/cjs/MemoizedGrid.js +105 -0
- package/dist/cjs/Selection.d.ts +5 -0
- package/dist/cjs/Selection.d.ts.map +1 -0
- package/dist/cjs/Selection.js +10 -0
- package/dist/{helpers.d.ts → cjs/helpers.d.ts} +59 -39
- package/dist/cjs/helpers.d.ts.map +1 -0
- package/dist/cjs/helpers.js +1409 -0
- package/dist/{hooks → cjs/hooks}/useCopyPaste.d.ts +3 -2
- package/dist/cjs/hooks/useCopyPaste.d.ts.map +1 -0
- package/dist/cjs/hooks/useCopyPaste.js +230 -0
- package/dist/{hooks → cjs/hooks}/useEditable.d.ts +21 -8
- package/dist/cjs/hooks/useEditable.d.ts.map +1 -0
- package/dist/cjs/hooks/useEditable.js +491 -0
- package/dist/{hooks → cjs/hooks}/useFilter.d.ts +3 -2
- package/dist/cjs/hooks/useFilter.d.ts.map +1 -0
- package/dist/cjs/hooks/useFilter.js +97 -0
- package/dist/{hooks → cjs/hooks}/useImage.d.ts +1 -0
- package/dist/cjs/hooks/useImage.d.ts.map +1 -0
- package/dist/cjs/hooks/useImage.js +80 -0
- package/dist/{hooks → cjs/hooks}/usePagination.d.ts +3 -2
- package/dist/cjs/hooks/usePagination.d.ts.map +1 -0
- package/dist/cjs/hooks/usePagination.js +53 -0
- package/dist/{hooks → cjs/hooks}/useSizer.d.ts +28 -29
- package/dist/cjs/hooks/useSizer.d.ts.map +1 -0
- package/dist/cjs/hooks/useSizer.js +176 -0
- package/dist/{hooks → cjs/hooks}/useTooltip.d.ts +2 -1
- package/dist/cjs/hooks/useTooltip.d.ts.map +1 -0
- package/dist/cjs/hooks/useTooltip.js +82 -0
- package/dist/{hooks → cjs/hooks}/useUndo.d.ts +2 -1
- package/dist/cjs/hooks/useUndo.d.ts.map +1 -0
- package/dist/cjs/hooks/useUndo.js +87 -0
- package/dist/cjs/index.d.ts +19 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +29 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/{types.d.ts → cjs/types.d.ts} +8 -3
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/{types.js → cjs/types.js} +7 -8
- package/dist/cjs/utils.d.ts +9 -0
- package/dist/cjs/utils.d.ts.map +1 -0
- package/dist/cjs/utils.js +58 -0
- package/dist/cjs/vitest.config.d.ts +3 -0
- package/dist/cjs/vitest.config.d.ts.map +1 -0
- package/dist/cjs/vitest.config.js +24 -0
- package/dist/esm/Cell.d.ts +35 -0
- package/dist/esm/Cell.d.ts.map +1 -0
- package/dist/esm/Cell.js +24 -0
- package/dist/esm/CellOverlay.d.ts +21 -0
- package/dist/esm/CellOverlay.d.ts.map +1 -0
- package/dist/esm/CellOverlay.js +120 -0
- package/dist/esm/Context.d.ts +8 -0
- package/dist/esm/Context.d.ts.map +1 -0
- package/dist/esm/Context.js +9 -0
- package/dist/esm/FillHandle.d.ts +8 -0
- package/dist/esm/FillHandle.d.ts.map +1 -0
- package/dist/{FillHandle.js → esm/FillHandle.js} +5 -11
- package/dist/esm/Grid.d.ts +558 -0
- package/dist/esm/Grid.d.ts.map +1 -0
- package/dist/esm/Grid.js +2451 -0
- package/dist/esm/GridLine.d.ts +5 -0
- package/dist/esm/GridLine.d.ts.map +1 -0
- package/dist/esm/GridLine.js +7 -0
- package/dist/esm/Image.d.ts +11 -0
- package/dist/esm/Image.d.ts.map +1 -0
- package/dist/esm/Image.js +53 -0
- package/dist/esm/MemoizedGrid.d.ts +49 -0
- package/dist/esm/MemoizedGrid.d.ts.map +1 -0
- package/dist/esm/MemoizedGrid.js +98 -0
- package/dist/esm/Selection.d.ts +5 -0
- package/dist/esm/Selection.d.ts.map +1 -0
- package/dist/esm/Selection.js +7 -0
- package/dist/esm/helpers.d.ts +281 -0
- package/dist/esm/helpers.d.ts.map +1 -0
- package/dist/esm/helpers.js +1260 -0
- package/dist/esm/hooks/useCopyPaste.d.ts +53 -0
- package/dist/esm/hooks/useCopyPaste.d.ts.map +1 -0
- package/dist/{hooks → esm/hooks}/useCopyPaste.js +40 -46
- package/dist/esm/hooks/useEditable.d.ts +253 -0
- package/dist/esm/hooks/useEditable.d.ts.map +1 -0
- package/dist/esm/hooks/useEditable.js +482 -0
- package/dist/esm/hooks/useFilter.d.ts +69 -0
- package/dist/esm/hooks/useFilter.d.ts.map +1 -0
- package/dist/{hooks → esm/hooks}/useFilter.js +22 -42
- package/dist/esm/hooks/useImage.d.ts +13 -0
- package/dist/esm/hooks/useImage.d.ts.map +1 -0
- package/dist/esm/hooks/useImage.js +76 -0
- package/dist/esm/hooks/usePagination.d.ts +69 -0
- package/dist/esm/hooks/usePagination.d.ts.map +1 -0
- package/dist/esm/hooks/usePagination.js +47 -0
- package/dist/esm/hooks/useSizer.d.ts +114 -0
- package/dist/esm/hooks/useSizer.d.ts.map +1 -0
- package/dist/esm/hooks/useSizer.js +176 -0
- package/dist/esm/hooks/useTooltip.d.ts +43 -0
- package/dist/esm/hooks/useTooltip.d.ts.map +1 -0
- package/dist/esm/hooks/useTooltip.js +80 -0
- package/dist/esm/hooks/useUndo.d.ts +36 -0
- package/dist/esm/hooks/useUndo.d.ts.map +1 -0
- package/dist/{hooks → esm/hooks}/useUndo.js +16 -25
- package/dist/esm/index.d.ts +19 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +17 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -0
- package/dist/esm/types.d.ts +70 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +68 -0
- package/dist/esm/utils.d.ts +9 -0
- package/dist/esm/utils.d.ts.map +1 -0
- package/dist/esm/utils.js +104 -0
- package/dist/esm/vitest.config.d.ts +3 -0
- package/dist/esm/vitest.config.d.ts.map +1 -0
- package/dist/esm/vitest.config.js +22 -0
- package/package.json +28 -29
- package/dist/Cell.d.ts +0 -23
- package/dist/Cell.js +0 -55
- package/dist/Cell.js.map +0 -1
- package/dist/CellOverlay.js +0 -116
- package/dist/CellOverlay.js.map +0 -1
- package/dist/FillHandle.js.map +0 -1
- package/dist/Grid.d.ts +0 -385
- package/dist/Grid.js +0 -1684
- package/dist/Grid.js.map +0 -1
- package/dist/GridLine.js +0 -13
- package/dist/GridLine.js.map +0 -1
- package/dist/Image.d.ts +0 -8
- package/dist/Image.js +0 -50
- package/dist/Image.js.map +0 -1
- package/dist/Selection.d.ts +0 -4
- package/dist/Selection.js +0 -9
- package/dist/Selection.js.map +0 -1
- package/dist/helpers.js +0 -1033
- package/dist/helpers.js.map +0 -1
- package/dist/hooks/useCopyPaste.js.map +0 -1
- package/dist/hooks/useEditable.js +0 -477
- package/dist/hooks/useEditable.js.map +0 -1
- package/dist/hooks/useFilter.js.map +0 -1
- package/dist/hooks/useImage.js +0 -42
- package/dist/hooks/useImage.js.map +0 -1
- package/dist/hooks/usePagination.js +0 -73
- package/dist/hooks/usePagination.js.map +0 -1
- package/dist/hooks/useSelection.d.ts +0 -175
- package/dist/hooks/useSelection.js +0 -980
- package/dist/hooks/useSelection.js.map +0 -1
- package/dist/hooks/useSizer.js +0 -150
- package/dist/hooks/useSizer.js.map +0 -1
- package/dist/hooks/useTooltip.js +0 -106
- package/dist/hooks/useTooltip.js.map +0 -1
- package/dist/hooks/useTouch.d.ts +0 -21
- package/dist/hooks/useTouch.js +0 -73
- package/dist/hooks/useTouch.js.map +0 -1
- package/dist/hooks/useUndo.js.map +0 -1
- package/dist/index.d.ts +0 -25
- package/dist/index.js +0 -61
- package/dist/index.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.d.ts +0 -8
- package/dist/utils.js +0 -153
- package/dist/utils.js.map +0 -1
- package/src/Cell.tsx +0 -100
- package/src/CellOverlay.tsx +0 -191
- package/src/FillHandle.tsx +0 -37
- package/src/Grid.tsx +0 -2677
- package/src/GridLine.tsx +0 -23
- package/src/Image.tsx +0 -43
- package/src/Selection.tsx +0 -9
- package/src/helpers.ts +0 -1455
- package/src/hooks/useCopyPaste.ts +0 -265
- package/src/hooks/useEditable.tsx +0 -945
- package/src/hooks/useFilter.tsx +0 -233
- package/src/hooks/useImage.ts +0 -57
- package/src/hooks/usePagination.tsx +0 -153
- package/src/hooks/useSelection.ts +0 -1437
- package/src/hooks/useSizer.ts +0 -312
- package/src/hooks/useTooltip.tsx +0 -172
- package/src/hooks/useTouch.ts +0 -116
- package/src/hooks/useUndo.ts +0 -134
- package/src/index.tsx +0 -46
- package/src/tests/Grid.spec.tsx +0 -47
- package/src/tests/helpers.test.ts +0 -292
- package/src/tests/usePagination.test.ts +0 -28
- package/src/tests/useSelection.test.ts +0 -27
- package/src/tests/useUndo.test.ts +0 -73
- package/src/types.ts +0 -69
- package/src/utils.tsx +0 -287
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
2
|
+
import { autoSizerCanvas, castToString, clampIndex, findNextCellWithinBounds, isEqualCells, isNull, } from "../helpers";
|
|
3
|
+
import { Direction, KeyCodes } from "./../types";
|
|
4
|
+
/**
|
|
5
|
+
* Default cell editor
|
|
6
|
+
* @param props
|
|
7
|
+
*/
|
|
8
|
+
const DefaultEditor = (props) => {
|
|
9
|
+
const { onChange, onSubmit, onCancel, position, cell, getNextFocusableCell, value = "", activeCell, autoFocus = true, onKeyDown, selections, scrollPosition, maxWidth, maxHeight, isFrozenRow, isFrozenColumn, frozenRowOffset, frozenColumnOffset, isNewValue, ...rest } = props;
|
|
10
|
+
const borderWidth = 2;
|
|
11
|
+
const padding = 10; /* 2 + 1 + 1 + 2 + 2 */
|
|
12
|
+
const inputRef = useRef(null);
|
|
13
|
+
const { x = 0, y = 0, width = 0, height = 0 } = position;
|
|
14
|
+
const getWidth = useCallback((text) => {
|
|
15
|
+
const textWidth = autoSizerCanvas.measureText(text)?.width || 0;
|
|
16
|
+
return Math.max(textWidth + padding, width + borderWidth / 2);
|
|
17
|
+
}, [width]);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
setInputWidth(getWidth(value));
|
|
20
|
+
}, [value]);
|
|
21
|
+
const [inputWidth, setInputWidth] = useState(() => getWidth(value));
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (!inputRef.current)
|
|
24
|
+
return;
|
|
25
|
+
if (autoFocus)
|
|
26
|
+
inputRef.current.focus();
|
|
27
|
+
/* Focus cursor at the end */
|
|
28
|
+
inputRef.current.selectionStart = castToString(value)?.length ?? 0;
|
|
29
|
+
}, []);
|
|
30
|
+
const inputHeight = height;
|
|
31
|
+
return (React.createElement("div", { style: {
|
|
32
|
+
top: y - borderWidth / 2,
|
|
33
|
+
left: x,
|
|
34
|
+
position: "absolute",
|
|
35
|
+
width: inputWidth,
|
|
36
|
+
height: inputHeight + borderWidth,
|
|
37
|
+
padding: borderWidth,
|
|
38
|
+
boxShadow: "0 2px 6px 2px rgba(60,64,67,.15)",
|
|
39
|
+
border: "2px #1a73e8 solid",
|
|
40
|
+
background: "white",
|
|
41
|
+
} },
|
|
42
|
+
React.createElement("textarea", { rows: 1, cols: 1, ref: inputRef, value: value, style: {
|
|
43
|
+
font: "12px Arial",
|
|
44
|
+
lineHeight: 1.2,
|
|
45
|
+
width: "100%",
|
|
46
|
+
height: "100%",
|
|
47
|
+
padding: "0 1px",
|
|
48
|
+
margin: 0,
|
|
49
|
+
boxSizing: "border-box",
|
|
50
|
+
borderWidth: 0,
|
|
51
|
+
outline: "none",
|
|
52
|
+
resize: "none",
|
|
53
|
+
overflow: "hidden",
|
|
54
|
+
verticalAlign: "top",
|
|
55
|
+
background: "transparent",
|
|
56
|
+
}, onChange: (e) => {
|
|
57
|
+
onChange?.(e.target.value, cell);
|
|
58
|
+
}, onKeyDown: (e) => {
|
|
59
|
+
if (!inputRef.current)
|
|
60
|
+
return;
|
|
61
|
+
const isShiftKey = e.nativeEvent.shiftKey;
|
|
62
|
+
const isMetaKey = e.nativeEvent.metaKey;
|
|
63
|
+
const value = inputRef.current.value;
|
|
64
|
+
const isCursorAtEnd = value.length === inputRef.current.selectionEnd;
|
|
65
|
+
const isNewCondition = isNewValue && !isShiftKey && !isMetaKey && isCursorAtEnd;
|
|
66
|
+
// Enter key
|
|
67
|
+
if (e.which === KeyCodes.Enter) {
|
|
68
|
+
onSubmit &&
|
|
69
|
+
onSubmit(value, cell, getNextFocusableCell?.(cell, isShiftKey ? Direction.Up : Direction.Down));
|
|
70
|
+
}
|
|
71
|
+
if (isNewCondition && e.which === KeyCodes.Right) {
|
|
72
|
+
onSubmit &&
|
|
73
|
+
onSubmit(value, cell, getNextFocusableCell?.(cell, Direction.Right));
|
|
74
|
+
}
|
|
75
|
+
if (isNewCondition && e.which === KeyCodes.Left) {
|
|
76
|
+
onSubmit &&
|
|
77
|
+
onSubmit(value, cell, getNextFocusableCell?.(cell, Direction.Left));
|
|
78
|
+
}
|
|
79
|
+
if (isNewCondition && e.which === KeyCodes.Up) {
|
|
80
|
+
onSubmit &&
|
|
81
|
+
onSubmit(value, cell, getNextFocusableCell?.(cell, Direction.Up));
|
|
82
|
+
}
|
|
83
|
+
if (isNewCondition && e.which === KeyCodes.Down) {
|
|
84
|
+
onSubmit &&
|
|
85
|
+
onSubmit(value, cell, getNextFocusableCell?.(cell, Direction.Down));
|
|
86
|
+
}
|
|
87
|
+
if (e.which === KeyCodes.Escape) {
|
|
88
|
+
onCancel && onCancel(e);
|
|
89
|
+
}
|
|
90
|
+
if (e.which === KeyCodes.Tab) {
|
|
91
|
+
e.preventDefault();
|
|
92
|
+
onSubmit &&
|
|
93
|
+
onSubmit(value, cell, getNextFocusableCell?.(cell, isShiftKey ? Direction.Left : Direction.Right));
|
|
94
|
+
}
|
|
95
|
+
onKeyDown?.(e);
|
|
96
|
+
}, ...rest })));
|
|
97
|
+
};
|
|
98
|
+
export const getDefaultEditor = (cell) => DefaultEditor;
|
|
99
|
+
const defaultCanEdit = (cell) => true;
|
|
100
|
+
const defaultIsHidden = (i) => false;
|
|
101
|
+
/**
|
|
102
|
+
* Hook to make grid editable
|
|
103
|
+
* @param param
|
|
104
|
+
*
|
|
105
|
+
* TODO:
|
|
106
|
+
* 1. Edit a cell
|
|
107
|
+
* 2. Tab to next cell
|
|
108
|
+
* 3. Enter a value
|
|
109
|
+
* 4. Press down key
|
|
110
|
+
*
|
|
111
|
+
* Moves to incorrect cell
|
|
112
|
+
*/
|
|
113
|
+
const useEditable = ({ getEditor = getDefaultEditor, gridRef, getValue, onChange, onSubmit, onCancel, onDelete, selections = [], activeCell, canEdit = defaultCanEdit, frozenRows = 0, frozenColumns = 0, hideOnBlur = true, isHiddenRow = defaultIsHidden, isHiddenColumn = defaultIsHidden, rowCount, columnCount, selectionTopBound = 0, selectionBottomBound = rowCount - 1, selectionLeftBound = 0, selectionRightBound = columnCount - 1, editorProps, onBeforeEdit, onKeyDown, sticky = false, }) => {
|
|
114
|
+
const [isEditorShown, setShowEditor] = useState(false);
|
|
115
|
+
const [value, setValue] = useState("");
|
|
116
|
+
const [position, setPosition] = useState({
|
|
117
|
+
x: 0,
|
|
118
|
+
y: 0,
|
|
119
|
+
width: 0,
|
|
120
|
+
height: 0,
|
|
121
|
+
});
|
|
122
|
+
const currentActiveCellRef = useRef(null);
|
|
123
|
+
const initialActiveCell = useRef(undefined);
|
|
124
|
+
const [scrollPosition, setScrollPosition] = useState({
|
|
125
|
+
scrollLeft: 0,
|
|
126
|
+
scrollTop: 0,
|
|
127
|
+
});
|
|
128
|
+
const [autoFocus, setAutoFocus] = useState(true);
|
|
129
|
+
const isDirtyRef = useRef(false);
|
|
130
|
+
const isEnteringNewValue = useRef(false);
|
|
131
|
+
const currentValueRef = useRef(value);
|
|
132
|
+
const initialValueRef = useRef(undefined);
|
|
133
|
+
const maxEditorDimensionsRef = useRef(undefined);
|
|
134
|
+
const showEditor = useCallback(() => setShowEditor(true), []);
|
|
135
|
+
const hideEditor = useCallback(() => {
|
|
136
|
+
setShowEditor(false);
|
|
137
|
+
currentActiveCellRef.current = null;
|
|
138
|
+
}, []);
|
|
139
|
+
const focusGrid = useCallback(() => {
|
|
140
|
+
requestAnimationFrame(() => gridRef.current && gridRef.current.focus());
|
|
141
|
+
}, []);
|
|
142
|
+
/* Keep ref in sync */
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
currentValueRef.current = value;
|
|
145
|
+
});
|
|
146
|
+
/**
|
|
147
|
+
* Make a cell editable
|
|
148
|
+
* @param coords
|
|
149
|
+
* @param initialValue
|
|
150
|
+
*/
|
|
151
|
+
const makeEditable = useCallback((coords, initialValue, autoFocus = true) => {
|
|
152
|
+
if (!gridRef.current)
|
|
153
|
+
return;
|
|
154
|
+
/* Get actual coords for merged cells */
|
|
155
|
+
coords = gridRef.current.getActualCellCoords(coords);
|
|
156
|
+
/* Check if its the same cell */
|
|
157
|
+
if (isEqualCells(coords, currentActiveCellRef.current)) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
/* Call on before edit */
|
|
161
|
+
if (canEdit(coords)) {
|
|
162
|
+
/* Let user modify coords before edit */
|
|
163
|
+
onBeforeEdit?.(coords);
|
|
164
|
+
/* Focus */
|
|
165
|
+
gridRef.current?.scrollToCell(coords);
|
|
166
|
+
currentActiveCellRef.current = coords;
|
|
167
|
+
/* Get offsets */
|
|
168
|
+
const pos = gridRef.current.getCellOffsetFromCoords(coords);
|
|
169
|
+
if (isNull(pos)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const scrollPosition = gridRef.current.getScrollPosition();
|
|
173
|
+
const cellValue = getValue?.(coords.rowIndex, coords.columnIndex);
|
|
174
|
+
const value = initialValue ?? cellValue ?? "";
|
|
175
|
+
const cellPosition = sticky
|
|
176
|
+
? // Editor is rendered outside the <Grid /> component
|
|
177
|
+
// If the user has scrolled down, and then activate the editor, we will need to adjust the position
|
|
178
|
+
// of the sticky editor accordingly
|
|
179
|
+
// Subsequent scroll events has no effect, cos of sticky option
|
|
180
|
+
getCellPosition(pos, scrollPosition)
|
|
181
|
+
: pos;
|
|
182
|
+
/**
|
|
183
|
+
* Set max editor ref based on grid container
|
|
184
|
+
*/
|
|
185
|
+
const { containerWidth, containerHeight } = gridRef.current.getDimensions();
|
|
186
|
+
maxEditorDimensionsRef.current = {
|
|
187
|
+
height: containerHeight - (cellPosition.y ?? 0),
|
|
188
|
+
width: containerWidth - (cellPosition.x ?? 0),
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* If the user has entered a value in the cell, mark it as dirty
|
|
192
|
+
* So that during mousedown, onSubmit gets called
|
|
193
|
+
*/
|
|
194
|
+
isEnteringNewValue.current =
|
|
195
|
+
initialValue !== void 0 || cellValue === void 0;
|
|
196
|
+
isDirtyRef.current = !!initialValue;
|
|
197
|
+
initialValueRef.current = initialValue ?? value;
|
|
198
|
+
/* Trigger onChange handlers */
|
|
199
|
+
setValue(value);
|
|
200
|
+
onChange?.(value, coords);
|
|
201
|
+
setAutoFocus(autoFocus);
|
|
202
|
+
setScrollPosition(scrollPosition);
|
|
203
|
+
setPosition(cellPosition);
|
|
204
|
+
showEditor();
|
|
205
|
+
}
|
|
206
|
+
}, [frozenRows, frozenColumns, onBeforeEdit, canEdit, sticky, getValue]);
|
|
207
|
+
/* Frozen flags */
|
|
208
|
+
const isFrozenRow = currentActiveCellRef.current &&
|
|
209
|
+
currentActiveCellRef.current?.rowIndex < frozenRows;
|
|
210
|
+
const isFrozenColumn = currentActiveCellRef.current &&
|
|
211
|
+
currentActiveCellRef.current?.columnIndex < frozenColumns;
|
|
212
|
+
/**
|
|
213
|
+
* Get current cell position based on scroll position
|
|
214
|
+
* @param position
|
|
215
|
+
* @param scrollPosition
|
|
216
|
+
*/
|
|
217
|
+
const getCellPosition = (position, scrollPosition) => {
|
|
218
|
+
if (!currentActiveCellRef.current)
|
|
219
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
220
|
+
return {
|
|
221
|
+
...position,
|
|
222
|
+
x: position.x -
|
|
223
|
+
(isFrozenColumn ? 0 : scrollPosition.scrollLeft),
|
|
224
|
+
y: position.y - (isFrozenRow ? 0 : scrollPosition.scrollTop),
|
|
225
|
+
};
|
|
226
|
+
};
|
|
227
|
+
/* Activate edit mode */
|
|
228
|
+
const handleDoubleClick = useCallback((e) => {
|
|
229
|
+
if (!gridRef.current)
|
|
230
|
+
return;
|
|
231
|
+
const coords = gridRef.current.getCellCoordsFromOffset(e.nativeEvent.clientX, e.nativeEvent.clientY);
|
|
232
|
+
if (!coords)
|
|
233
|
+
return;
|
|
234
|
+
const { rowIndex, columnIndex } = coords;
|
|
235
|
+
makeEditable({ rowIndex, columnIndex });
|
|
236
|
+
}, [makeEditable, frozenRows, frozenColumns]);
|
|
237
|
+
const isSelectionKey = useCallback((keyCode) => {
|
|
238
|
+
return ([
|
|
239
|
+
KeyCodes.Right,
|
|
240
|
+
KeyCodes.Left,
|
|
241
|
+
KeyCodes.Up,
|
|
242
|
+
KeyCodes.Down,
|
|
243
|
+
KeyCodes.Meta,
|
|
244
|
+
KeyCodes.Escape,
|
|
245
|
+
KeyCodes.Tab,
|
|
246
|
+
KeyCodes.Home,
|
|
247
|
+
KeyCodes.End,
|
|
248
|
+
KeyCodes.CapsLock,
|
|
249
|
+
KeyCodes.PageDown,
|
|
250
|
+
KeyCodes.PageUp,
|
|
251
|
+
KeyCodes.ScrollLock,
|
|
252
|
+
KeyCodes.NumLock,
|
|
253
|
+
KeyCodes.Insert,
|
|
254
|
+
KeyCodes.Pause,
|
|
255
|
+
].indexOf(keyCode) !== -1 ||
|
|
256
|
+
// Exclude Function keys
|
|
257
|
+
(keyCode >= KeyCodes.F1 && keyCode <= KeyCodes.F12));
|
|
258
|
+
}, []);
|
|
259
|
+
/**
|
|
260
|
+
* Helper function to keep track of
|
|
261
|
+
* the first cell that the user started editing
|
|
262
|
+
* @param cell
|
|
263
|
+
*/
|
|
264
|
+
const setInitialActiveCell = (cell) => {
|
|
265
|
+
initialActiveCell.current = cell;
|
|
266
|
+
};
|
|
267
|
+
const handleKeyDown = useCallback((e) => {
|
|
268
|
+
const keyCode = e.nativeEvent.keyCode;
|
|
269
|
+
const isEnter = keyCode === KeyCodes.Enter;
|
|
270
|
+
if (keyCode === KeyCodes.Tab && !initialActiveCell.current) {
|
|
271
|
+
setInitialActiveCell(activeCell);
|
|
272
|
+
}
|
|
273
|
+
// if (isArrowKey(keyCode)) {
|
|
274
|
+
// setInitialActiveCell(null);
|
|
275
|
+
// }
|
|
276
|
+
if (isSelectionKey(keyCode) ||
|
|
277
|
+
e.nativeEvent.ctrlKey ||
|
|
278
|
+
(e.nativeEvent.shiftKey &&
|
|
279
|
+
(e.nativeEvent.key === "Shift" ||
|
|
280
|
+
e.nativeEvent.which === KeyCodes.SPACE)) ||
|
|
281
|
+
e.nativeEvent.metaKey ||
|
|
282
|
+
e.nativeEvent.which === KeyCodes.ALT)
|
|
283
|
+
return;
|
|
284
|
+
/* If user has not made any selection yet */
|
|
285
|
+
if (!activeCell)
|
|
286
|
+
return;
|
|
287
|
+
const { rowIndex, columnIndex } = activeCell;
|
|
288
|
+
if (keyCode === KeyCodes.Delete || keyCode === KeyCodes.BackSpace) {
|
|
289
|
+
// TODO: onbefore delete
|
|
290
|
+
onDelete && onDelete(activeCell, selections);
|
|
291
|
+
e.preventDefault();
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
const initialValue = isEnter // Enter key
|
|
295
|
+
? undefined
|
|
296
|
+
: e.nativeEvent.key;
|
|
297
|
+
/* Open the editor */
|
|
298
|
+
makeEditable({ rowIndex, columnIndex }, initialValue);
|
|
299
|
+
/* Prevent the first keystroke */
|
|
300
|
+
e.preventDefault();
|
|
301
|
+
}, [getValue, selections, activeCell, onDelete]);
|
|
302
|
+
/**
|
|
303
|
+
* Get next focusable cell
|
|
304
|
+
* Respects selection bounds
|
|
305
|
+
*/
|
|
306
|
+
const getNextFocusableCell = useCallback((currentCell, direction = Direction.Right) => {
|
|
307
|
+
/* Next immediate cell */
|
|
308
|
+
const range = gridRef.current?.getCellBounds(currentCell);
|
|
309
|
+
if (!range)
|
|
310
|
+
return null;
|
|
311
|
+
let nextActiveCell;
|
|
312
|
+
switch (direction) {
|
|
313
|
+
case Direction.Right: {
|
|
314
|
+
const columnIndex = clampIndex(Math.min(range.endColumnIndex + 1, selectionRightBound), isHiddenColumn, direction);
|
|
315
|
+
nextActiveCell = {
|
|
316
|
+
rowIndex: range.startRowIndex,
|
|
317
|
+
columnIndex,
|
|
318
|
+
};
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
case Direction.Up: {
|
|
322
|
+
const rowIndex = clampIndex(Math.max(range.startRowIndex - 1, selectionTopBound), isHiddenRow, direction);
|
|
323
|
+
nextActiveCell = {
|
|
324
|
+
rowIndex,
|
|
325
|
+
columnIndex: range.startColumnIndex,
|
|
326
|
+
};
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
case Direction.Left: {
|
|
330
|
+
const columnIndex = clampIndex(Math.max(range.startColumnIndex - 1, selectionLeftBound), isHiddenColumn, direction);
|
|
331
|
+
nextActiveCell = {
|
|
332
|
+
rowIndex: range.startRowIndex,
|
|
333
|
+
columnIndex,
|
|
334
|
+
};
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
case Direction.Down: {
|
|
338
|
+
// Down
|
|
339
|
+
const rowIndex = clampIndex(Math.min((initialActiveCell.current?.rowIndex ?? range.endRowIndex) + 1, selectionBottomBound), isHiddenRow, direction);
|
|
340
|
+
nextActiveCell = {
|
|
341
|
+
rowIndex,
|
|
342
|
+
columnIndex: initialActiveCell.current?.columnIndex ?? range.startColumnIndex,
|
|
343
|
+
};
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
if (direction === Direction.Right && !initialActiveCell.current) {
|
|
348
|
+
setInitialActiveCell(currentCell);
|
|
349
|
+
}
|
|
350
|
+
if (direction === Direction.Down) {
|
|
351
|
+
/* Move to the next row + cell */
|
|
352
|
+
setInitialActiveCell(null);
|
|
353
|
+
}
|
|
354
|
+
/* If user has selected some cells and active cell is within this selection */
|
|
355
|
+
if (selections.length && currentCell && gridRef.current) {
|
|
356
|
+
const { range } = selections[selections.length - 1];
|
|
357
|
+
const activeCellBounds = gridRef.current.getCellBounds(currentCell);
|
|
358
|
+
const nextCell = findNextCellWithinBounds(activeCellBounds, range, direction);
|
|
359
|
+
if (nextCell)
|
|
360
|
+
nextActiveCell = nextCell;
|
|
361
|
+
}
|
|
362
|
+
return nextActiveCell;
|
|
363
|
+
}, [
|
|
364
|
+
selections,
|
|
365
|
+
isHiddenRow,
|
|
366
|
+
isHiddenColumn,
|
|
367
|
+
selectionBottomBound,
|
|
368
|
+
selectionTopBound,
|
|
369
|
+
]);
|
|
370
|
+
/* Save the value */
|
|
371
|
+
const handleSubmit = useCallback((value, activeCell, nextActiveCell) => {
|
|
372
|
+
/**
|
|
373
|
+
* Hide the editor first, so that we can handle onBlur events
|
|
374
|
+
* 1. Editor hides -> Submit
|
|
375
|
+
* 2. If user clicks outside the grid, onBlur is called, if there is a activeCell, we do another submit
|
|
376
|
+
*/
|
|
377
|
+
hideEditor();
|
|
378
|
+
/* Save the new value */
|
|
379
|
+
onSubmit && onSubmit(value, activeCell, nextActiveCell);
|
|
380
|
+
/* Keep the focus */
|
|
381
|
+
focusGrid();
|
|
382
|
+
}, [onSubmit]);
|
|
383
|
+
/* When the input is blurred out */
|
|
384
|
+
const handleCancel = useCallback((e) => {
|
|
385
|
+
hideEditor();
|
|
386
|
+
onCancel && onCancel(e);
|
|
387
|
+
/* Keep the focus back in the grid */
|
|
388
|
+
focusGrid();
|
|
389
|
+
}, [onCancel]);
|
|
390
|
+
const handleMouseDown = useCallback((e) => {
|
|
391
|
+
/* Persistent input, hides only during Enter key or during submit or cancel calls */
|
|
392
|
+
if (!hideOnBlur) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
if (currentActiveCellRef.current) {
|
|
396
|
+
if (isDirtyRef.current) {
|
|
397
|
+
handleSubmit(currentValueRef.current, currentActiveCellRef.current);
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
handleCancel();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
setInitialActiveCell(null);
|
|
404
|
+
}, [hideOnBlur, handleSubmit, handleCancel]);
|
|
405
|
+
const handleChange = useCallback((newValue, activeCell) => {
|
|
406
|
+
/**
|
|
407
|
+
* Make sure we dont call onChange if initialValue is set
|
|
408
|
+
* This is to accomodate for editor that fire onChange during initialvalue
|
|
409
|
+
* Eg: Slate <Editor value='' onChange />
|
|
410
|
+
*/
|
|
411
|
+
if (initialValueRef.current !== void 0 &&
|
|
412
|
+
initialValueRef.current === newValue) {
|
|
413
|
+
initialValueRef.current = void 0;
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (!currentActiveCellRef.current)
|
|
417
|
+
return;
|
|
418
|
+
/* Check if the value has changed. Used to conditionally submit if editor is not in focus */
|
|
419
|
+
isDirtyRef.current = newValue !== value;
|
|
420
|
+
setValue(newValue);
|
|
421
|
+
onChange?.(newValue, activeCell);
|
|
422
|
+
}, [value]);
|
|
423
|
+
const handleScroll = useCallback((scrollPos) => {
|
|
424
|
+
if (!currentActiveCellRef.current)
|
|
425
|
+
return;
|
|
426
|
+
setScrollPosition(scrollPos);
|
|
427
|
+
}, []);
|
|
428
|
+
/* Editor */
|
|
429
|
+
const editingCell = currentActiveCellRef.current;
|
|
430
|
+
const Editor = useMemo(() => {
|
|
431
|
+
return editingCell
|
|
432
|
+
? getEditor(editingCell) || getDefaultEditor(editingCell)
|
|
433
|
+
: null;
|
|
434
|
+
}, [editingCell]);
|
|
435
|
+
const handleBlur = useCallback((e) => {
|
|
436
|
+
if (currentActiveCellRef.current) {
|
|
437
|
+
/* Keep the focus */
|
|
438
|
+
focusGrid();
|
|
439
|
+
}
|
|
440
|
+
}, []);
|
|
441
|
+
const finalCellPosition = useMemo(() => {
|
|
442
|
+
/**
|
|
443
|
+
* Since the editor is sticky,
|
|
444
|
+
* we dont need to adjust the position,
|
|
445
|
+
* as scrollposition wont move the editor
|
|
446
|
+
*
|
|
447
|
+
* When the editor is first active, in makeEditable,
|
|
448
|
+
* we accomodate for the initial scrollPosition
|
|
449
|
+
*/
|
|
450
|
+
if (sticky) {
|
|
451
|
+
return position;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* If editor is not sticky, keep adjusting
|
|
455
|
+
* its position to accomodate for scroll
|
|
456
|
+
*/
|
|
457
|
+
return getCellPosition(position, scrollPosition);
|
|
458
|
+
}, [sticky, position, scrollPosition, frozenColumns, frozenRows]);
|
|
459
|
+
/* Get offset of frozen rows and columns */
|
|
460
|
+
const frozenRowOffset = useMemo(() => gridRef.current?.getRowOffset(frozenRows), [frozenRows]);
|
|
461
|
+
const frozenColumnOffset = useMemo(() => gridRef.current?.getColumnOffset(frozenColumns), [frozenColumns]);
|
|
462
|
+
const editorComponent = isEditorShown && Editor ? (React.createElement(Editor, { ...editorProps?.(),
|
|
463
|
+
/* This is the cell that is currently being edited */
|
|
464
|
+
cell: editingCell, activeCell: activeCell, autoFocus: autoFocus, value: value, isNewValue: isEnteringNewValue.current, selections: selections, onChange: handleChange, onSubmit: handleSubmit, onCancel: handleCancel, position: finalCellPosition, scrollPosition: scrollPosition, getNextFocusableCell: getNextFocusableCell, onBlur: handleBlur, onKeyDown: onKeyDown, maxWidth: maxEditorDimensionsRef.current?.width, maxHeight: maxEditorDimensionsRef.current?.height, isFrozenRow: isFrozenRow, isFrozenColumn: isFrozenColumn, frozenRowOffset: frozenRowOffset, frozenColumnOffset: frozenColumnOffset })) : null;
|
|
465
|
+
return {
|
|
466
|
+
editorComponent,
|
|
467
|
+
onDoubleClick: handleDoubleClick,
|
|
468
|
+
onKeyDown: handleKeyDown,
|
|
469
|
+
getNextFocusableCell,
|
|
470
|
+
isEditInProgress: !!editingCell,
|
|
471
|
+
editingCell,
|
|
472
|
+
makeEditable,
|
|
473
|
+
setValue: handleChange,
|
|
474
|
+
hideEditor,
|
|
475
|
+
showEditor,
|
|
476
|
+
submitEditor: handleSubmit,
|
|
477
|
+
cancelEditor: handleCancel,
|
|
478
|
+
onMouseDown: handleMouseDown,
|
|
479
|
+
onScroll: handleScroll,
|
|
480
|
+
};
|
|
481
|
+
};
|
|
482
|
+
export default useEditable;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { AreaStyle, CellInterface, GridRange, GridRef } from "./../Grid";
|
|
3
|
+
export interface FilterView {
|
|
4
|
+
bounds: GridRange;
|
|
5
|
+
filters?: Filter;
|
|
6
|
+
style?: AreaStyle;
|
|
7
|
+
title?: string;
|
|
8
|
+
}
|
|
9
|
+
export type Filter = Record<string, FilterDefinition>;
|
|
10
|
+
export type FilterDefinition<T = string | number> = {
|
|
11
|
+
condition?: FilterConditionDefinition<T>;
|
|
12
|
+
equals?: T[];
|
|
13
|
+
sort?: SortDirection;
|
|
14
|
+
};
|
|
15
|
+
export type FilterOperators = ContainsTextOperators | DataValidationOperator;
|
|
16
|
+
export type FilterConditionDefinition<T = string | number> = {
|
|
17
|
+
operator?: FilterOperators;
|
|
18
|
+
values?: T[];
|
|
19
|
+
};
|
|
20
|
+
export type SortDirection = "asc" | "desc";
|
|
21
|
+
export type DataValidationOperator = "isEmpty" | "notIsEmpty" | "between" | "notBetween" | "equal" | "notEqual" | "greaterThan" | "lessThan" | "greaterThanOrEqual" | "lessThanOrEqual";
|
|
22
|
+
export type ContainsTextOperators = "containsText" | "notContainsText" | "containsBlanks" | "notContainsBlanks" | "containsErrors" | "notContainsErrors" | "startsWithText" | "endsWithText" | "equalText";
|
|
23
|
+
export interface FilterProps {
|
|
24
|
+
/**
|
|
25
|
+
* Returns filter component
|
|
26
|
+
*/
|
|
27
|
+
getFilterComponent?: (cell: CellInterface | null) => React.ElementType | null;
|
|
28
|
+
/**
|
|
29
|
+
* Access grid methods
|
|
30
|
+
*/
|
|
31
|
+
gridRef: React.MutableRefObject<GridRef | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Get value of a cell
|
|
34
|
+
*/
|
|
35
|
+
getValue: (cell: CellInterface) => any;
|
|
36
|
+
/**
|
|
37
|
+
* Width of the filter panel
|
|
38
|
+
*/
|
|
39
|
+
width?: number;
|
|
40
|
+
offset?: number;
|
|
41
|
+
frozenRows?: number;
|
|
42
|
+
frozenColumns?: number;
|
|
43
|
+
}
|
|
44
|
+
export interface FilterResults {
|
|
45
|
+
/**
|
|
46
|
+
* Component to render filter
|
|
47
|
+
*/
|
|
48
|
+
filterComponent: React.ReactNode;
|
|
49
|
+
/**
|
|
50
|
+
* Enable filter
|
|
51
|
+
*/
|
|
52
|
+
showFilter: (cell: CellInterface, index: number, filterView: FilterView, filter?: FilterDefinition) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Hide filter component
|
|
55
|
+
*/
|
|
56
|
+
hideFilter: () => void;
|
|
57
|
+
}
|
|
58
|
+
export interface FilterState {
|
|
59
|
+
filterView: FilterView;
|
|
60
|
+
filter?: FilterDefinition;
|
|
61
|
+
index: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Use filter hook
|
|
65
|
+
* @param param0
|
|
66
|
+
*/
|
|
67
|
+
declare const useFilter: ({ getFilterComponent, gridRef, width, offset, getValue, frozenRows, frozenColumns, }: FilterProps) => FilterResults;
|
|
68
|
+
export default useFilter;
|
|
69
|
+
//# sourceMappingURL=useFilter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFilter.d.ts","sourceRoot":"","sources":["../../../hooks/useFilter.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAG9D,OAAO,KAAK,EACV,SAAS,EACT,aAAa,EAEb,SAAS,EACT,OAAO,EACR,MAAM,WAAW,CAAC;AAEnB,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AACtD,MAAM,MAAM,gBAAgB,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,IAAI;IAClD,SAAS,CAAC,EAAE,yBAAyB,CAAC,CAAC,CAAC,CAAC;IACzC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;IACb,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB,CAAC;AACF,MAAM,MAAM,eAAe,GAAG,qBAAqB,GAAG,sBAAsB,CAAC;AAC7E,MAAM,MAAM,yBAAyB,CAAC,CAAC,GAAG,MAAM,GAAG,MAAM,IAAI;IAC3D,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;CACd,CAAC;AACF,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,CAAC;AAC3C,MAAM,MAAM,sBAAsB,GAC9B,SAAS,GACT,YAAY,GACZ,SAAS,GACT,YAAY,GACZ,OAAO,GACP,UAAU,GACV,aAAa,GACb,UAAU,GACV,oBAAoB,GACpB,iBAAiB,CAAC;AAEtB,MAAM,MAAM,qBAAqB,GAC7B,cAAc,GACd,iBAAiB,GACjB,gBAAgB,GAChB,mBAAmB,GACnB,gBAAgB,GAChB,mBAAmB,GACnB,gBAAgB,GAChB,cAAc,GACd,WAAW,CAAC;AAEhB,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,KAAK,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;IAC9E;;OAEG;IACH,OAAO,EAAE,KAAK,CAAC,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAChD;;OAEG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,GAAG,CAAC;IACvC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC;IACjC;;OAEG;IACH,UAAU,EAAE,CACV,IAAI,EAAE,aAAa,EACnB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,UAAU,EACtB,MAAM,CAAC,EAAE,gBAAgB,KACtB,IAAI,CAAC;IACV;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAKD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,QAAA,MAAM,SAAS,GAAI,sFAQhB,WAAW,KAAG,aA0HhB,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -1,30 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
const react_1 = __importStar(require("react"));
|
|
27
|
-
const helpers_1 = require("../helpers");
|
|
1
|
+
import React, { useCallback, useMemo, useState } from "react";
|
|
2
|
+
import { isNull } from "../helpers";
|
|
28
3
|
/* Default filter component */
|
|
29
4
|
const getDefaultFilerComponent = (cell) => null;
|
|
30
5
|
/**
|
|
@@ -32,20 +7,22 @@ const getDefaultFilerComponent = (cell) => null;
|
|
|
32
7
|
* @param param0
|
|
33
8
|
*/
|
|
34
9
|
const useFilter = ({ getFilterComponent = getDefaultFilerComponent, gridRef, width = 220, offset = 20, getValue, frozenRows = 0, frozenColumns = 0, }) => {
|
|
35
|
-
const [filterCell, setFilterCell] =
|
|
36
|
-
const [isFilterVisible, setIsFilterVisible] =
|
|
37
|
-
const [currentFilter, setCurrentFilter] =
|
|
38
|
-
const [position, setPosition] =
|
|
10
|
+
const [filterCell, setFilterCell] = useState(null);
|
|
11
|
+
const [isFilterVisible, setIsFilterVisible] = useState(false);
|
|
12
|
+
const [currentFilter, setCurrentFilter] = useState(null);
|
|
13
|
+
const [position, setPosition] = useState({
|
|
39
14
|
x: 0,
|
|
40
15
|
y: 0,
|
|
16
|
+
width: 0,
|
|
17
|
+
height: 0,
|
|
41
18
|
});
|
|
42
|
-
const FilterComponent =
|
|
19
|
+
const FilterComponent = useMemo(() => {
|
|
43
20
|
return getFilterComponent(filterCell);
|
|
44
21
|
}, [filterCell]);
|
|
45
22
|
/**
|
|
46
23
|
* Show filter panel
|
|
47
24
|
*/
|
|
48
|
-
const handleShowFilter =
|
|
25
|
+
const handleShowFilter = useCallback((coords, index, filterView, filter) => {
|
|
49
26
|
if (!gridRef.current)
|
|
50
27
|
return;
|
|
51
28
|
/* Get actual coords for merged cells */
|
|
@@ -57,12 +34,16 @@ const useFilter = ({ getFilterComponent = getDefaultFilerComponent, gridRef, wid
|
|
|
57
34
|
/* Check if its frozen */
|
|
58
35
|
const isFrozenColumn = coords.columnIndex < frozenColumns;
|
|
59
36
|
const isFrozenRow = coords.rowIndex < frozenRows;
|
|
37
|
+
if (isNull(pos)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
60
40
|
/* Set cell position */
|
|
61
|
-
setPosition(() => {
|
|
41
|
+
setPosition((prev) => {
|
|
62
42
|
const left = pos.x;
|
|
63
43
|
const top = pos.y;
|
|
64
44
|
const cellWidth = pos.width;
|
|
65
45
|
return {
|
|
46
|
+
...prev,
|
|
66
47
|
x: left +
|
|
67
48
|
cellWidth -
|
|
68
49
|
(isFrozenColumn ? 0 : scrollPosition.scrollLeft) <
|
|
@@ -85,33 +66,32 @@ const useFilter = ({ getFilterComponent = getDefaultFilerComponent, gridRef, wid
|
|
|
85
66
|
/* Show filter */
|
|
86
67
|
showFilter();
|
|
87
68
|
}, [frozenRows, frozenColumns]);
|
|
88
|
-
const hideFilter =
|
|
69
|
+
const hideFilter = useCallback(() => {
|
|
89
70
|
setIsFilterVisible(false);
|
|
90
71
|
}, []);
|
|
91
|
-
const showFilter =
|
|
72
|
+
const showFilter = useCallback(() => {
|
|
92
73
|
setIsFilterVisible(true);
|
|
93
74
|
}, []);
|
|
94
|
-
const values =
|
|
75
|
+
const values = useMemo(() => {
|
|
95
76
|
if (!filterCell || !currentFilter)
|
|
96
77
|
return [];
|
|
97
78
|
const { filterView } = currentFilter;
|
|
98
79
|
const { columnIndex } = filterCell;
|
|
99
80
|
const { bounds } = filterView;
|
|
100
81
|
const filterValues = new Set();
|
|
101
|
-
for (let i = bounds.
|
|
82
|
+
for (let i = bounds.startRowIndex + 1; i <= bounds.endRowIndex; i++) {
|
|
102
83
|
const cell = { rowIndex: i, columnIndex };
|
|
103
84
|
const text = getValue(cell);
|
|
104
|
-
const value =
|
|
85
|
+
const value = isNull(text) ? "" : text;
|
|
105
86
|
filterValues.add(value);
|
|
106
87
|
}
|
|
107
88
|
return Array.from(filterValues);
|
|
108
89
|
}, [filterCell, currentFilter]);
|
|
109
|
-
const filterComponent = isFilterVisible && FilterComponent ? (
|
|
90
|
+
const filterComponent = isFilterVisible && FilterComponent ? (React.createElement(FilterComponent, { position: position, width: width, values: values, index: currentFilter?.index, filterView: currentFilter?.filterView, filter: currentFilter?.filter, columnIndex: filterCell?.columnIndex, rowIndex: filterCell?.rowIndex, onRequestClose: hideFilter, onRequestShow: handleShowFilter })) : null;
|
|
110
91
|
return {
|
|
111
92
|
filterComponent,
|
|
112
93
|
showFilter: handleShowFilter,
|
|
113
94
|
hideFilter,
|
|
114
95
|
};
|
|
115
96
|
};
|
|
116
|
-
|
|
117
|
-
//# sourceMappingURL=useFilter.js.map
|
|
97
|
+
export default useFilter;
|