@rowsncolumns/grid 9.0.4 → 13.2.33
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 -982
- 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 -1440
- 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
package/src/Grid.tsx
DELETED
|
@@ -1,2677 +0,0 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
useRef,
|
|
3
|
-
useCallback,
|
|
4
|
-
useState,
|
|
5
|
-
useMemo,
|
|
6
|
-
forwardRef,
|
|
7
|
-
useImperativeHandle,
|
|
8
|
-
useReducer,
|
|
9
|
-
memo,
|
|
10
|
-
useEffect,
|
|
11
|
-
Key,
|
|
12
|
-
UIEvent,
|
|
13
|
-
} from "react";
|
|
14
|
-
import { Stage, Layer, Group, Line } from "react-konva";
|
|
15
|
-
import {
|
|
16
|
-
getRowStartIndexForOffset,
|
|
17
|
-
getRowStopIndexForStartIndex,
|
|
18
|
-
getColumnStartIndexForOffset,
|
|
19
|
-
getColumnStopIndexForStartIndex,
|
|
20
|
-
itemKey,
|
|
21
|
-
getRowOffset as getRowOffsetHelper,
|
|
22
|
-
getColumnOffset as getColumnOffsetHelper,
|
|
23
|
-
getColumnWidth as getColumnWidthHelper,
|
|
24
|
-
getRowHeight as getRowHeightHelper,
|
|
25
|
-
getEstimatedTotalHeight,
|
|
26
|
-
getEstimatedTotalWidth,
|
|
27
|
-
getBoundedCells,
|
|
28
|
-
cellIdentifier,
|
|
29
|
-
throttle,
|
|
30
|
-
getOffsetForColumnAndAlignment,
|
|
31
|
-
getOffsetForRowAndAlignment,
|
|
32
|
-
requestTimeout,
|
|
33
|
-
cancelTimeout,
|
|
34
|
-
TimeoutID,
|
|
35
|
-
Align,
|
|
36
|
-
clampIndex,
|
|
37
|
-
canUseDOM,
|
|
38
|
-
} from "./helpers";
|
|
39
|
-
import type { ShapeConfig } from "konva/lib/Shape";
|
|
40
|
-
import { CellRenderer as defaultItemRenderer } from "./Cell";
|
|
41
|
-
import { CellRenderer as defaultOverlayRenderer } from "./CellOverlay";
|
|
42
|
-
import Selection from "./Selection";
|
|
43
|
-
import FillHandle from "./FillHandle";
|
|
44
|
-
import GridLine from "./GridLine";
|
|
45
|
-
import { createHTMLBox } from "./utils";
|
|
46
|
-
import invariant from "tiny-invariant";
|
|
47
|
-
import type { StageConfig } from "konva/lib/Stage";
|
|
48
|
-
import { Direction } from "./types";
|
|
49
|
-
import Konva from "konva";
|
|
50
|
-
|
|
51
|
-
export interface GridProps
|
|
52
|
-
extends Omit<React.HTMLAttributes<HTMLDivElement>, "onScroll" | "children"> {
|
|
53
|
-
/**
|
|
54
|
-
* Width of the grid
|
|
55
|
-
*/
|
|
56
|
-
width?: number;
|
|
57
|
-
/**
|
|
58
|
-
* Height of the grid
|
|
59
|
-
*/
|
|
60
|
-
height?: number;
|
|
61
|
-
/**
|
|
62
|
-
* No of columns in the grid
|
|
63
|
-
*/
|
|
64
|
-
columnCount: number;
|
|
65
|
-
/**
|
|
66
|
-
* No of rows in the grid
|
|
67
|
-
*/
|
|
68
|
-
rowCount: number;
|
|
69
|
-
/**
|
|
70
|
-
* Should return height of a row at an index
|
|
71
|
-
*/
|
|
72
|
-
rowHeight?: ItemSizer;
|
|
73
|
-
/**
|
|
74
|
-
* Should return width of a column at an index
|
|
75
|
-
*/
|
|
76
|
-
columnWidth?: ItemSizer;
|
|
77
|
-
/**
|
|
78
|
-
* Size of the scrollbar. Default is 13
|
|
79
|
-
*/
|
|
80
|
-
scrollbarSize?: number;
|
|
81
|
-
/**
|
|
82
|
-
* Helps in lazy grid width calculation
|
|
83
|
-
*/
|
|
84
|
-
estimatedColumnWidth?: number;
|
|
85
|
-
/**
|
|
86
|
-
* Helps in lazy grid height calculation
|
|
87
|
-
*/
|
|
88
|
-
estimatedRowHeight?: number;
|
|
89
|
-
/**
|
|
90
|
-
* Called when user scrolls the grid
|
|
91
|
-
*/
|
|
92
|
-
onScroll?: ({ scrollLeft, scrollTop }: ScrollCoords) => void;
|
|
93
|
-
/**
|
|
94
|
-
* Called immediately on scroll
|
|
95
|
-
*/
|
|
96
|
-
onImmediateScroll?: ({ scrollLeft, scrollTop }: ScrollCoords) => void;
|
|
97
|
-
/**
|
|
98
|
-
* Show scrollbars on the left and right of the grid
|
|
99
|
-
*/
|
|
100
|
-
showScrollbar?: boolean;
|
|
101
|
-
/**
|
|
102
|
-
* Currently active cell
|
|
103
|
-
*/
|
|
104
|
-
activeCell?: CellInterface | null;
|
|
105
|
-
/**
|
|
106
|
-
* Background of selection
|
|
107
|
-
*/
|
|
108
|
-
selectionBackgroundColor?: string;
|
|
109
|
-
/**
|
|
110
|
-
* Border color of selected area
|
|
111
|
-
*/
|
|
112
|
-
selectionBorderColor?: string;
|
|
113
|
-
/**
|
|
114
|
-
* Stroke width of the selection
|
|
115
|
-
*/
|
|
116
|
-
selectionStrokeWidth?: number;
|
|
117
|
-
/**
|
|
118
|
-
* Active Cell Stroke width
|
|
119
|
-
*/
|
|
120
|
-
activeCellStrokeWidth?: number;
|
|
121
|
-
/**
|
|
122
|
-
* Array of selected cell areas
|
|
123
|
-
*/
|
|
124
|
-
selections?: SelectionArea[];
|
|
125
|
-
/**
|
|
126
|
-
* Fill selection
|
|
127
|
-
*/
|
|
128
|
-
fillSelection?: SelectionArea | null;
|
|
129
|
-
/**
|
|
130
|
-
* Array of merged cells
|
|
131
|
-
*/
|
|
132
|
-
mergedCells?: AreaProps[];
|
|
133
|
-
/**
|
|
134
|
-
* Number of frozen rows
|
|
135
|
-
*/
|
|
136
|
-
frozenRows?: number;
|
|
137
|
-
/**
|
|
138
|
-
* Number of frozen columns
|
|
139
|
-
*/
|
|
140
|
-
frozenColumns?: number;
|
|
141
|
-
/**
|
|
142
|
-
* Snap to row and column when scrolling
|
|
143
|
-
*/
|
|
144
|
-
snap?: boolean;
|
|
145
|
-
/**
|
|
146
|
-
* Show shadow as you scroll for frozen rows and columns
|
|
147
|
-
*/
|
|
148
|
-
showFrozenShadow?: boolean;
|
|
149
|
-
/**
|
|
150
|
-
* Shadow settings
|
|
151
|
-
*/
|
|
152
|
-
shadowSettings?: ShapeConfig;
|
|
153
|
-
/**
|
|
154
|
-
* Scroll throttle wait timeout
|
|
155
|
-
*/
|
|
156
|
-
scrollThrottleTimeout?: number;
|
|
157
|
-
/**
|
|
158
|
-
* Cell styles for border
|
|
159
|
-
*/
|
|
160
|
-
borderStyles?: StylingProps;
|
|
161
|
-
/**
|
|
162
|
-
* Extend certains to coords
|
|
163
|
-
*/
|
|
164
|
-
cellAreas?: CellRangeArea[];
|
|
165
|
-
/**
|
|
166
|
-
* Cell renderer. Must be a Konva Component eg: Group, Rect etc
|
|
167
|
-
*/
|
|
168
|
-
itemRenderer?: (props: RendererProps) => React.ReactNode;
|
|
169
|
-
/**
|
|
170
|
-
* Render custom overlays like stroke on top of cell
|
|
171
|
-
*/
|
|
172
|
-
overlayRenderer?: (props: RendererProps) => React.ReactNode;
|
|
173
|
-
/**
|
|
174
|
-
* Allow users to customize selected cells design
|
|
175
|
-
*/
|
|
176
|
-
selectionRenderer?: (props: SelectionProps) => React.ReactNode;
|
|
177
|
-
/**
|
|
178
|
-
* Bind to fill handle
|
|
179
|
-
*/
|
|
180
|
-
fillHandleProps?: Record<string, (e: any) => void>;
|
|
181
|
-
/**
|
|
182
|
-
* Fired when scroll viewport changes
|
|
183
|
-
*/
|
|
184
|
-
onViewChange?: (view: ViewPortProps) => void;
|
|
185
|
-
/**
|
|
186
|
-
* Called right before a row is being rendered.
|
|
187
|
-
* Will be called for frozen cells and merged cells
|
|
188
|
-
*/
|
|
189
|
-
onBeforeRenderRow?: (rowIndex: number) => void;
|
|
190
|
-
/**
|
|
191
|
-
* Custom grid overlays
|
|
192
|
-
*/
|
|
193
|
-
children?: (props: ScrollCoords) => React.ReactNode;
|
|
194
|
-
/**
|
|
195
|
-
* Allows users to Wrap stage children in Top level Context
|
|
196
|
-
*/
|
|
197
|
-
wrapper?: (children: React.ReactNode) => React.ReactNode;
|
|
198
|
-
/**
|
|
199
|
-
* Props that can be injected to Konva stage
|
|
200
|
-
*/
|
|
201
|
-
stageProps?: Omit<StageConfig, "container">;
|
|
202
|
-
/**
|
|
203
|
-
* Show fillhandle
|
|
204
|
-
*/
|
|
205
|
-
showFillHandle?: boolean;
|
|
206
|
-
/**
|
|
207
|
-
* Overscan row and columns
|
|
208
|
-
*/
|
|
209
|
-
overscanCount?: number;
|
|
210
|
-
/**
|
|
211
|
-
* Border color of fill handle
|
|
212
|
-
*/
|
|
213
|
-
fillhandleBorderColor?: string;
|
|
214
|
-
/**
|
|
215
|
-
* Show grid lines.
|
|
216
|
-
* Useful for spreadsheets
|
|
217
|
-
*/
|
|
218
|
-
showGridLines?: boolean;
|
|
219
|
-
/**
|
|
220
|
-
* Customize grid line color
|
|
221
|
-
*/
|
|
222
|
-
gridLineColor?: string;
|
|
223
|
-
/**
|
|
224
|
-
* Width of the grid line
|
|
225
|
-
*/
|
|
226
|
-
gridLineWidth?: number;
|
|
227
|
-
/**
|
|
228
|
-
* Gridline component
|
|
229
|
-
*/
|
|
230
|
-
gridLineRenderer?: (props: ShapeConfig) => React.ReactNode;
|
|
231
|
-
/**
|
|
232
|
-
* Shadow stroke color
|
|
233
|
-
*/
|
|
234
|
-
shadowStroke?: string;
|
|
235
|
-
/**
|
|
236
|
-
* Draw overlay for each cell.
|
|
237
|
-
* Can be used to apply stroke or draw on top of a cell
|
|
238
|
-
*/
|
|
239
|
-
enableCellOverlay?: boolean;
|
|
240
|
-
/**
|
|
241
|
-
* Check if its hidden row
|
|
242
|
-
*/
|
|
243
|
-
isHiddenRow?: (rowIndex: number) => boolean;
|
|
244
|
-
/**
|
|
245
|
-
* Check if its a hidden column. Skip rendering hidden
|
|
246
|
-
*/
|
|
247
|
-
isHiddenColumn?: (columnIndex: number) => boolean;
|
|
248
|
-
/**
|
|
249
|
-
* Is Hidden cell
|
|
250
|
-
*/
|
|
251
|
-
isHiddenCell?: (rowIndex: number, columnIndex: number) => boolean;
|
|
252
|
-
/**
|
|
253
|
-
* Scale
|
|
254
|
-
*/
|
|
255
|
-
scale?: number;
|
|
256
|
-
/**
|
|
257
|
-
* Enable draging active cell and selections
|
|
258
|
-
*/
|
|
259
|
-
enableSelectionDrag?: boolean;
|
|
260
|
-
/**
|
|
261
|
-
* Is user currently dragging a selection
|
|
262
|
-
*/
|
|
263
|
-
isDraggingSelection?: boolean;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
export interface CellRangeArea extends CellInterface {
|
|
267
|
-
toColumnIndex: number;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
export type RefAttribute = {
|
|
271
|
-
ref?: React.Ref<GridRef>;
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
|
|
275
|
-
export interface SelectionProps
|
|
276
|
-
extends AreaMeta,
|
|
277
|
-
ShapeConfig,
|
|
278
|
-
Omit<React.HTMLAttributes<HTMLDivElement>, "draggable"> {
|
|
279
|
-
fillHandleProps?: Record<string, (e: any) => void>;
|
|
280
|
-
type: "fill" | "activeCell" | "selection" | "border";
|
|
281
|
-
isDragging?: boolean;
|
|
282
|
-
inProgress?: boolean;
|
|
283
|
-
activeCell?: CellInterface;
|
|
284
|
-
selection?: SelectionArea;
|
|
285
|
-
key: number;
|
|
286
|
-
draggable?: boolean;
|
|
287
|
-
bounds?: AreaProps;
|
|
288
|
-
borderCoverWidth?: number;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
export type ScrollCoords = {
|
|
292
|
-
scrollTop: number;
|
|
293
|
-
scrollLeft: number;
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
export type OptionalScrollCoords = {
|
|
297
|
-
scrollTop?: number;
|
|
298
|
-
scrollLeft?: number;
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
export interface ScrollState extends ScrollCoords {
|
|
302
|
-
isScrolling: boolean;
|
|
303
|
-
verticalScrollDirection: Direction;
|
|
304
|
-
horizontalScrollDirection: Direction;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
export type RenderComponent = React.FC<RendererProps>;
|
|
308
|
-
export interface CellPosition extends Pick<ShapeConfig, "x" | "y"> {
|
|
309
|
-
width?: ShapeConfig["width"];
|
|
310
|
-
height?: ShapeConfig["height"];
|
|
311
|
-
}
|
|
312
|
-
export interface RendererProps
|
|
313
|
-
extends CellInterface,
|
|
314
|
-
CellPosition,
|
|
315
|
-
Omit<ShapeConfig, "scale"> {
|
|
316
|
-
key: Key;
|
|
317
|
-
isMergedCell?: boolean;
|
|
318
|
-
isOverlay?: boolean;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
export type ItemSizer = (index: number) => number;
|
|
322
|
-
|
|
323
|
-
export interface SelectionArea extends AreaStyle {
|
|
324
|
-
bounds: AreaProps;
|
|
325
|
-
inProgress?: boolean;
|
|
326
|
-
/**
|
|
327
|
-
* When user drags the fill handle
|
|
328
|
-
*/
|
|
329
|
-
isFilling?: boolean;
|
|
330
|
-
}
|
|
331
|
-
export interface AreaProps {
|
|
332
|
-
top: number;
|
|
333
|
-
bottom: number;
|
|
334
|
-
left: number;
|
|
335
|
-
right: number;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
export interface CellInterface {
|
|
339
|
-
rowIndex: number;
|
|
340
|
-
columnIndex: number;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
export interface OptionalCellInterface {
|
|
344
|
-
rowIndex?: number;
|
|
345
|
-
columnIndex?: number;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
export interface ViewPortProps {
|
|
349
|
-
rowStartIndex: number;
|
|
350
|
-
rowStopIndex: number;
|
|
351
|
-
columnStartIndex: number;
|
|
352
|
-
columnStopIndex: number;
|
|
353
|
-
visibleRowStartIndex: number;
|
|
354
|
-
visibleRowStopIndex: number;
|
|
355
|
-
visibleColumnStartIndex: number;
|
|
356
|
-
visibleColumnStopIndex: number;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
export interface InstanceInterface {
|
|
360
|
-
columnMetadataMap: CellMetaDataMap;
|
|
361
|
-
rowMetadataMap: CellMetaDataMap;
|
|
362
|
-
lastMeasuredColumnIndex: number;
|
|
363
|
-
lastMeasuredRowIndex: number;
|
|
364
|
-
estimatedRowHeight: number;
|
|
365
|
-
estimatedColumnWidth: number;
|
|
366
|
-
recalcColumnIndices: number[];
|
|
367
|
-
recalcRowIndices: number[];
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
export type CellMetaDataMap = Record<number, CellMetaData>;
|
|
371
|
-
export type CellMetaData = {
|
|
372
|
-
offset: number;
|
|
373
|
-
size: number;
|
|
374
|
-
};
|
|
375
|
-
|
|
376
|
-
export interface SnapRowProps {
|
|
377
|
-
deltaY: number;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
export interface SnapColumnProps {
|
|
381
|
-
deltaX: number;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
export interface PosXY {
|
|
385
|
-
x?: number;
|
|
386
|
-
y?: number;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
export interface PosXYRequired {
|
|
390
|
-
x: number;
|
|
391
|
-
y: number;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
export type GridRef = {
|
|
395
|
-
scrollTo: (scrollPosition: ScrollCoords) => void;
|
|
396
|
-
scrollBy: (pos: PosXY) => void;
|
|
397
|
-
stage: Konva.Stage | null;
|
|
398
|
-
container: HTMLDivElement | null;
|
|
399
|
-
resetAfterIndices: (
|
|
400
|
-
coords: OptionalCellInterface,
|
|
401
|
-
shouldForceUpdate?: boolean
|
|
402
|
-
) => void;
|
|
403
|
-
getScrollPosition: () => ScrollCoords;
|
|
404
|
-
isMergedCell: (coords: CellInterface) => boolean;
|
|
405
|
-
getCellBounds: (coords: CellInterface, spanMerges?: boolean) => AreaProps;
|
|
406
|
-
getCellCoordsFromOffset: (
|
|
407
|
-
x: number,
|
|
408
|
-
y: number,
|
|
409
|
-
includeFrozen?: boolean
|
|
410
|
-
) => CellInterface | null;
|
|
411
|
-
getCellOffsetFromCoords: (coords: CellInterface) => CellPosition;
|
|
412
|
-
getActualCellCoords: (coords: CellInterface) => CellInterface;
|
|
413
|
-
scrollToItem: (coords: OptionalCellInterface, align?: Align) => void;
|
|
414
|
-
focus: () => void;
|
|
415
|
-
resizeColumns: (indices: number[]) => void;
|
|
416
|
-
resizeRows: (indices: number[]) => void;
|
|
417
|
-
getViewPort: () => ViewPortProps;
|
|
418
|
-
getRelativePositionFromOffset: (x: number, y: number) => PosXYRequired | null;
|
|
419
|
-
scrollToTop: () => void;
|
|
420
|
-
scrollToBottom: () => void;
|
|
421
|
-
getDimensions: () => {
|
|
422
|
-
containerWidth: number;
|
|
423
|
-
containerHeight: number;
|
|
424
|
-
estimatedTotalWidth: number;
|
|
425
|
-
estimatedTotalHeight: number;
|
|
426
|
-
};
|
|
427
|
-
getRowOffset: (index: number) => number;
|
|
428
|
-
getColumnOffset: (index: number) => number;
|
|
429
|
-
};
|
|
430
|
-
|
|
431
|
-
export type MergedCellMap = Map<string, AreaProps>;
|
|
432
|
-
|
|
433
|
-
export type StylingProps = AreaStyle[];
|
|
434
|
-
|
|
435
|
-
export interface AreaStyle extends AreaMeta {
|
|
436
|
-
bounds: AreaProps;
|
|
437
|
-
style?: Style;
|
|
438
|
-
strokeStyle?: "dashed" | "solid" | "dotted";
|
|
439
|
-
}
|
|
440
|
-
export interface AreaMeta {
|
|
441
|
-
title?: string;
|
|
442
|
-
[key: string]: any;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
export interface Style {
|
|
446
|
-
stroke?: string;
|
|
447
|
-
strokeLeftColor?: string;
|
|
448
|
-
strokeTopColor?: string;
|
|
449
|
-
strokeRightColor?: string;
|
|
450
|
-
strokeBottomColor?: string;
|
|
451
|
-
strokeWidth?: number;
|
|
452
|
-
strokeTopWidth?: number;
|
|
453
|
-
strokeRightWidth?: number;
|
|
454
|
-
strokeBottomWidth?: number;
|
|
455
|
-
strokeLeftWidth?: number;
|
|
456
|
-
strokeStyle?: string;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
interface ScrollSnapRef {
|
|
460
|
-
visibleRowStartIndex: number;
|
|
461
|
-
rowCount: number;
|
|
462
|
-
frozenRows: number;
|
|
463
|
-
visibleColumnStartIndex: number;
|
|
464
|
-
columnCount: number;
|
|
465
|
-
frozenColumns: number;
|
|
466
|
-
isHiddenRow?: (rowIndex: number) => boolean;
|
|
467
|
-
isHiddenColumn?: (columnIndex: number) => boolean;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
const DEFAULT_ESTIMATED_ITEM_SIZE = 50;
|
|
471
|
-
const defaultShadowSettings: ShapeConfig = {
|
|
472
|
-
strokeWidth: 1,
|
|
473
|
-
};
|
|
474
|
-
const defaultRowHeight = () => 20;
|
|
475
|
-
const defaultColumnWidth = () => 60;
|
|
476
|
-
const defaultSelectionRenderer = (props: SelectionProps) => {
|
|
477
|
-
return <Selection {...props} />;
|
|
478
|
-
};
|
|
479
|
-
const defaultGridLineRenderer = (props: ShapeConfig) => {
|
|
480
|
-
return <GridLine {...props} />;
|
|
481
|
-
};
|
|
482
|
-
export const RESET_SCROLL_EVENTS_DEBOUNCE_INTERVAL = 150;
|
|
483
|
-
/* Placeholder for empty array -> Prevents re-render */
|
|
484
|
-
const EMPTY_ARRAY: any = [];
|
|
485
|
-
|
|
486
|
-
/**
|
|
487
|
-
* Grid component using React Konva
|
|
488
|
-
* @param props
|
|
489
|
-
*
|
|
490
|
-
* TODO: Fix bug with snapping, since onWheel is a global handler, rowCount, columnCount becomes state
|
|
491
|
-
*/
|
|
492
|
-
const Grid: React.FC<GridProps & RefAttribute> = memo(
|
|
493
|
-
forwardRef<GridRef, GridProps>((props, forwardedRef) => {
|
|
494
|
-
const {
|
|
495
|
-
width: containerWidth = 800,
|
|
496
|
-
height: containerHeight = 600,
|
|
497
|
-
estimatedColumnWidth,
|
|
498
|
-
estimatedRowHeight,
|
|
499
|
-
rowHeight = defaultRowHeight,
|
|
500
|
-
columnWidth = defaultColumnWidth,
|
|
501
|
-
rowCount = 0,
|
|
502
|
-
columnCount = 0,
|
|
503
|
-
scrollbarSize = 13,
|
|
504
|
-
onScroll,
|
|
505
|
-
onImmediateScroll,
|
|
506
|
-
showScrollbar = true,
|
|
507
|
-
selectionBackgroundColor = "rgb(14, 101, 235, 0.1)",
|
|
508
|
-
selectionBorderColor = "#1a73e8",
|
|
509
|
-
selectionStrokeWidth = 1,
|
|
510
|
-
activeCellStrokeWidth = 2,
|
|
511
|
-
activeCell,
|
|
512
|
-
selections = EMPTY_ARRAY as SelectionArea[],
|
|
513
|
-
frozenRows = 0,
|
|
514
|
-
frozenColumns = 0,
|
|
515
|
-
itemRenderer = defaultItemRenderer,
|
|
516
|
-
enableCellOverlay = false,
|
|
517
|
-
overlayRenderer = defaultOverlayRenderer,
|
|
518
|
-
mergedCells = EMPTY_ARRAY as AreaProps[],
|
|
519
|
-
snap = false,
|
|
520
|
-
scrollThrottleTimeout = 80,
|
|
521
|
-
onViewChange,
|
|
522
|
-
selectionRenderer = defaultSelectionRenderer,
|
|
523
|
-
onBeforeRenderRow,
|
|
524
|
-
showFrozenShadow = false,
|
|
525
|
-
shadowSettings = defaultShadowSettings,
|
|
526
|
-
borderStyles = EMPTY_ARRAY as StylingProps,
|
|
527
|
-
children,
|
|
528
|
-
stageProps,
|
|
529
|
-
wrapper = (children: React.ReactNode): React.ReactNode => children,
|
|
530
|
-
cellAreas = EMPTY_ARRAY,
|
|
531
|
-
showFillHandle = false,
|
|
532
|
-
fillSelection,
|
|
533
|
-
overscanCount = 1,
|
|
534
|
-
fillHandleProps,
|
|
535
|
-
fillhandleBorderColor = "white",
|
|
536
|
-
showGridLines = false,
|
|
537
|
-
gridLineColor = "#E3E2E2",
|
|
538
|
-
gridLineWidth = 1,
|
|
539
|
-
gridLineRenderer = defaultGridLineRenderer,
|
|
540
|
-
isHiddenRow,
|
|
541
|
-
isHiddenColumn,
|
|
542
|
-
isHiddenCell,
|
|
543
|
-
scale = 1,
|
|
544
|
-
enableSelectionDrag = false,
|
|
545
|
-
isDraggingSelection = false,
|
|
546
|
-
...rest
|
|
547
|
-
} = props;
|
|
548
|
-
|
|
549
|
-
invariant(
|
|
550
|
-
!(children && typeof children !== "function"),
|
|
551
|
-
"Children should be a function"
|
|
552
|
-
);
|
|
553
|
-
|
|
554
|
-
/* Expose some methods in ref */
|
|
555
|
-
useImperativeHandle(forwardedRef, () => {
|
|
556
|
-
return {
|
|
557
|
-
scrollTo,
|
|
558
|
-
scrollBy,
|
|
559
|
-
scrollToItem,
|
|
560
|
-
stage: stageRef.current,
|
|
561
|
-
container: containerRef.current,
|
|
562
|
-
resetAfterIndices,
|
|
563
|
-
getScrollPosition,
|
|
564
|
-
isMergedCell,
|
|
565
|
-
getCellBounds,
|
|
566
|
-
getCellCoordsFromOffset,
|
|
567
|
-
getCellOffsetFromCoords,
|
|
568
|
-
getActualCellCoords,
|
|
569
|
-
focus: focusContainer,
|
|
570
|
-
resizeColumns,
|
|
571
|
-
resizeRows,
|
|
572
|
-
getViewPort,
|
|
573
|
-
getRelativePositionFromOffset,
|
|
574
|
-
scrollToTop,
|
|
575
|
-
scrollToBottom,
|
|
576
|
-
getDimensions,
|
|
577
|
-
getRowOffset,
|
|
578
|
-
getColumnOffset,
|
|
579
|
-
};
|
|
580
|
-
});
|
|
581
|
-
|
|
582
|
-
const instanceProps = useRef<InstanceInterface>({
|
|
583
|
-
columnMetadataMap: {},
|
|
584
|
-
rowMetadataMap: {},
|
|
585
|
-
lastMeasuredColumnIndex: -1,
|
|
586
|
-
lastMeasuredRowIndex: -1,
|
|
587
|
-
estimatedColumnWidth: estimatedColumnWidth || DEFAULT_ESTIMATED_ITEM_SIZE,
|
|
588
|
-
estimatedRowHeight: estimatedRowHeight || DEFAULT_ESTIMATED_ITEM_SIZE,
|
|
589
|
-
recalcColumnIndices: [],
|
|
590
|
-
recalcRowIndices: [],
|
|
591
|
-
});
|
|
592
|
-
const stageRef = useRef<Konva.Stage>(null);
|
|
593
|
-
const containerRef = useRef<HTMLDivElement>(null);
|
|
594
|
-
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
595
|
-
const verticalScrollRef = useRef<HTMLDivElement>(null);
|
|
596
|
-
const wheelingRef = useRef<number | null>(null);
|
|
597
|
-
const horizontalScrollRef = useRef<HTMLDivElement>(null);
|
|
598
|
-
const [_, forceRender] = useReducer((s) => s + 1, 0);
|
|
599
|
-
const [scrollState, setScrollState] = useState<ScrollState>({
|
|
600
|
-
scrollTop: 0,
|
|
601
|
-
scrollLeft: 0,
|
|
602
|
-
isScrolling: false,
|
|
603
|
-
verticalScrollDirection: Direction.Down,
|
|
604
|
-
horizontalScrollDirection: Direction.Right,
|
|
605
|
-
});
|
|
606
|
-
const scrollSnapRefs = useRef<ScrollSnapRef | null>(null);
|
|
607
|
-
const {
|
|
608
|
-
scrollTop,
|
|
609
|
-
scrollLeft,
|
|
610
|
-
isScrolling,
|
|
611
|
-
verticalScrollDirection,
|
|
612
|
-
horizontalScrollDirection,
|
|
613
|
-
} = scrollState;
|
|
614
|
-
const isMounted = useRef(false);
|
|
615
|
-
|
|
616
|
-
/* Focus container */
|
|
617
|
-
const focusContainer = useCallback(() => {
|
|
618
|
-
if (canUseDOM && document.activeElement !== containerRef.current) {
|
|
619
|
-
return containerRef.current?.focus();
|
|
620
|
-
}
|
|
621
|
-
}, []);
|
|
622
|
-
|
|
623
|
-
/**
|
|
624
|
-
* Get top offset of rowIndex
|
|
625
|
-
*/
|
|
626
|
-
const getRowOffset = useCallback(
|
|
627
|
-
(index: number) => {
|
|
628
|
-
return getRowOffsetHelper({
|
|
629
|
-
index,
|
|
630
|
-
rowHeight,
|
|
631
|
-
columnWidth,
|
|
632
|
-
instanceProps: instanceProps.current,
|
|
633
|
-
scale,
|
|
634
|
-
});
|
|
635
|
-
},
|
|
636
|
-
[rowHeight, columnWidth, instanceProps.current, scale]
|
|
637
|
-
);
|
|
638
|
-
|
|
639
|
-
/**
|
|
640
|
-
* Get lefft offset of columnIndex
|
|
641
|
-
*/
|
|
642
|
-
const getColumnOffset = useCallback(
|
|
643
|
-
(index: number) => {
|
|
644
|
-
return getColumnOffsetHelper({
|
|
645
|
-
index,
|
|
646
|
-
rowHeight,
|
|
647
|
-
columnWidth,
|
|
648
|
-
instanceProps: instanceProps.current,
|
|
649
|
-
scale,
|
|
650
|
-
});
|
|
651
|
-
},
|
|
652
|
-
[rowHeight, columnWidth, instanceProps.current, scale]
|
|
653
|
-
);
|
|
654
|
-
|
|
655
|
-
/**
|
|
656
|
-
* Get height of rowIndex
|
|
657
|
-
*/
|
|
658
|
-
const getRowHeight = useCallback(
|
|
659
|
-
(index: number) => {
|
|
660
|
-
return getRowHeightHelper(index, instanceProps.current);
|
|
661
|
-
},
|
|
662
|
-
[instanceProps.current]
|
|
663
|
-
);
|
|
664
|
-
|
|
665
|
-
/**
|
|
666
|
-
* Get height of columNiondex
|
|
667
|
-
*/
|
|
668
|
-
const getColumnWidth = useCallback(
|
|
669
|
-
(index: number) => {
|
|
670
|
-
return getColumnWidthHelper(index, instanceProps.current);
|
|
671
|
-
},
|
|
672
|
-
[instanceProps.current]
|
|
673
|
-
);
|
|
674
|
-
|
|
675
|
-
/**
|
|
676
|
-
* onScroll callback
|
|
677
|
-
*/
|
|
678
|
-
useEffect(() => {
|
|
679
|
-
if (!isMounted.current) return;
|
|
680
|
-
onScroll?.({ scrollTop, scrollLeft });
|
|
681
|
-
}, [scrollTop, scrollLeft]);
|
|
682
|
-
|
|
683
|
-
/**
|
|
684
|
-
* Handle mouse wheeel
|
|
685
|
-
*/
|
|
686
|
-
useEffect(() => {
|
|
687
|
-
scrollContainerRef.current?.addEventListener("wheel", handleWheel, {
|
|
688
|
-
passive: false,
|
|
689
|
-
});
|
|
690
|
-
isMounted.current = true;
|
|
691
|
-
return () => {
|
|
692
|
-
scrollContainerRef.current?.removeEventListener("wheel", handleWheel);
|
|
693
|
-
};
|
|
694
|
-
}, []);
|
|
695
|
-
|
|
696
|
-
/**
|
|
697
|
-
* Imperatively get the current scroll position
|
|
698
|
-
*/
|
|
699
|
-
const getScrollPosition = useCallback(() => {
|
|
700
|
-
return {
|
|
701
|
-
scrollTop,
|
|
702
|
-
scrollLeft,
|
|
703
|
-
};
|
|
704
|
-
}, [scrollTop, scrollLeft]);
|
|
705
|
-
|
|
706
|
-
/* Redraw grid imperatively */
|
|
707
|
-
const resetAfterIndices = useCallback(
|
|
708
|
-
(
|
|
709
|
-
{ columnIndex, rowIndex }: OptionalCellInterface,
|
|
710
|
-
shouldForceUpdate: boolean = true
|
|
711
|
-
) => {
|
|
712
|
-
if (typeof columnIndex === "number") {
|
|
713
|
-
instanceProps.current.recalcColumnIndices = [];
|
|
714
|
-
instanceProps.current.lastMeasuredColumnIndex = Math.min(
|
|
715
|
-
instanceProps.current.lastMeasuredColumnIndex,
|
|
716
|
-
columnIndex - 1
|
|
717
|
-
);
|
|
718
|
-
}
|
|
719
|
-
if (typeof rowIndex === "number") {
|
|
720
|
-
instanceProps.current.recalcRowIndices = [];
|
|
721
|
-
instanceProps.current.lastMeasuredRowIndex = Math.min(
|
|
722
|
-
instanceProps.current.lastMeasuredRowIndex,
|
|
723
|
-
rowIndex - 1
|
|
724
|
-
);
|
|
725
|
-
}
|
|
726
|
-
if (shouldForceUpdate) forceRender();
|
|
727
|
-
},
|
|
728
|
-
[]
|
|
729
|
-
);
|
|
730
|
-
|
|
731
|
-
/**
|
|
732
|
-
* Create a map of merged cells
|
|
733
|
-
* [rowIndex, columnindex] => [parentRowIndex, parentColumnIndex]
|
|
734
|
-
*/
|
|
735
|
-
const mergedCellMap = useMemo((): MergedCellMap => {
|
|
736
|
-
const mergedCellMap = new Map();
|
|
737
|
-
for (let i = 0; i < mergedCells.length; i++) {
|
|
738
|
-
const bounds = mergedCells[i];
|
|
739
|
-
for (const cell of getBoundedCells(bounds)) {
|
|
740
|
-
mergedCellMap.set(cell, bounds);
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
return mergedCellMap;
|
|
744
|
-
}, [mergedCells]);
|
|
745
|
-
|
|
746
|
-
/* Check if a cell is part of a merged cell */
|
|
747
|
-
const isMergedCell = useCallback(
|
|
748
|
-
({ rowIndex, columnIndex }: CellInterface) => {
|
|
749
|
-
return mergedCellMap.has(cellIdentifier(rowIndex, columnIndex));
|
|
750
|
-
},
|
|
751
|
-
[mergedCells]
|
|
752
|
-
);
|
|
753
|
-
|
|
754
|
-
/* Get top, left bounds of a cell */
|
|
755
|
-
const getCellBounds = useCallback(
|
|
756
|
-
(
|
|
757
|
-
{ rowIndex, columnIndex }: CellInterface,
|
|
758
|
-
spanMerges = true
|
|
759
|
-
): AreaProps => {
|
|
760
|
-
if (spanMerges) {
|
|
761
|
-
const isMerged = isMergedCell({ rowIndex, columnIndex });
|
|
762
|
-
if (isMerged)
|
|
763
|
-
return mergedCellMap.get(
|
|
764
|
-
cellIdentifier(rowIndex, columnIndex)
|
|
765
|
-
) as AreaProps;
|
|
766
|
-
}
|
|
767
|
-
return {
|
|
768
|
-
top: rowIndex,
|
|
769
|
-
left: columnIndex,
|
|
770
|
-
right: columnIndex,
|
|
771
|
-
bottom: rowIndex,
|
|
772
|
-
} as AreaProps;
|
|
773
|
-
},
|
|
774
|
-
[mergedCellMap]
|
|
775
|
-
);
|
|
776
|
-
|
|
777
|
-
/* Get top, left bounds of a cell */
|
|
778
|
-
const getActualCellCoords = useCallback(
|
|
779
|
-
({ rowIndex, columnIndex }: CellInterface): CellInterface => {
|
|
780
|
-
const isMerged = isMergedCell({ rowIndex, columnIndex });
|
|
781
|
-
if (isMerged) {
|
|
782
|
-
const cell = mergedCellMap.get(
|
|
783
|
-
cellIdentifier(rowIndex, columnIndex)
|
|
784
|
-
) as AreaProps;
|
|
785
|
-
return {
|
|
786
|
-
rowIndex: cell?.top,
|
|
787
|
-
columnIndex: cell?.left,
|
|
788
|
-
};
|
|
789
|
-
}
|
|
790
|
-
return {
|
|
791
|
-
rowIndex,
|
|
792
|
-
columnIndex,
|
|
793
|
-
};
|
|
794
|
-
},
|
|
795
|
-
[mergedCellMap]
|
|
796
|
-
);
|
|
797
|
-
|
|
798
|
-
const frozenColumnWidth = getColumnOffset(frozenColumns);
|
|
799
|
-
const frozenRowHeight = getRowOffset(frozenRows);
|
|
800
|
-
const [
|
|
801
|
-
rowStartIndex,
|
|
802
|
-
rowStopIndex,
|
|
803
|
-
visibleRowStartIndex,
|
|
804
|
-
visibleRowStopIndex,
|
|
805
|
-
] = useMemo(() => {
|
|
806
|
-
const startIndex = getRowStartIndexForOffset({
|
|
807
|
-
rowHeight,
|
|
808
|
-
columnWidth,
|
|
809
|
-
rowCount,
|
|
810
|
-
columnCount,
|
|
811
|
-
instanceProps: instanceProps.current,
|
|
812
|
-
offset: scrollTop + frozenRowHeight,
|
|
813
|
-
scale,
|
|
814
|
-
});
|
|
815
|
-
const stopIndex = getRowStopIndexForStartIndex({
|
|
816
|
-
startIndex,
|
|
817
|
-
rowCount,
|
|
818
|
-
rowHeight,
|
|
819
|
-
columnWidth,
|
|
820
|
-
scrollTop,
|
|
821
|
-
containerHeight,
|
|
822
|
-
instanceProps: instanceProps.current,
|
|
823
|
-
scale,
|
|
824
|
-
});
|
|
825
|
-
|
|
826
|
-
// Overscan by one item in each direction so that tab/focus works.
|
|
827
|
-
// If there isn't at least one extra item, tab loops back around.
|
|
828
|
-
const overscanBackward =
|
|
829
|
-
!isScrolling || verticalScrollDirection === Direction.Up
|
|
830
|
-
? Math.max(1, overscanCount)
|
|
831
|
-
: 1;
|
|
832
|
-
const overscanForward =
|
|
833
|
-
!isScrolling || verticalScrollDirection === Direction.Down
|
|
834
|
-
? Math.max(1, overscanCount)
|
|
835
|
-
: 1;
|
|
836
|
-
|
|
837
|
-
return [
|
|
838
|
-
Math.max(0, startIndex - overscanBackward),
|
|
839
|
-
Math.max(0, Math.min(rowCount - 1, stopIndex + overscanForward)),
|
|
840
|
-
startIndex,
|
|
841
|
-
stopIndex,
|
|
842
|
-
];
|
|
843
|
-
}, [
|
|
844
|
-
rowHeight,
|
|
845
|
-
columnWidth,
|
|
846
|
-
rowCount,
|
|
847
|
-
columnCount,
|
|
848
|
-
scale,
|
|
849
|
-
scrollTop,
|
|
850
|
-
containerHeight,
|
|
851
|
-
frozenRows,
|
|
852
|
-
overscanCount,
|
|
853
|
-
frozenRowHeight,
|
|
854
|
-
]);
|
|
855
|
-
|
|
856
|
-
const [
|
|
857
|
-
columnStartIndex,
|
|
858
|
-
columnStopIndex,
|
|
859
|
-
visibleColumnStartIndex,
|
|
860
|
-
visibleColumnStopIndex,
|
|
861
|
-
] = useMemo(() => {
|
|
862
|
-
const startIndex = getColumnStartIndexForOffset({
|
|
863
|
-
rowHeight,
|
|
864
|
-
columnWidth,
|
|
865
|
-
rowCount,
|
|
866
|
-
columnCount,
|
|
867
|
-
instanceProps: instanceProps.current,
|
|
868
|
-
offset: scrollLeft + frozenColumnWidth,
|
|
869
|
-
scale,
|
|
870
|
-
});
|
|
871
|
-
|
|
872
|
-
const stopIndex = getColumnStopIndexForStartIndex({
|
|
873
|
-
startIndex,
|
|
874
|
-
columnCount,
|
|
875
|
-
rowHeight,
|
|
876
|
-
columnWidth,
|
|
877
|
-
scrollLeft,
|
|
878
|
-
containerWidth,
|
|
879
|
-
instanceProps: instanceProps.current,
|
|
880
|
-
scale,
|
|
881
|
-
});
|
|
882
|
-
|
|
883
|
-
// Overscan by one item in each direction so that tab/focus works.
|
|
884
|
-
// If there isn't at least one extra item, tab loops back around.
|
|
885
|
-
const overscanBackward =
|
|
886
|
-
!isScrolling || horizontalScrollDirection === Direction.Left
|
|
887
|
-
? Math.max(1, overscanCount)
|
|
888
|
-
: 1;
|
|
889
|
-
const overscanForward =
|
|
890
|
-
!isScrolling || horizontalScrollDirection === Direction.Right
|
|
891
|
-
? Math.max(1, overscanCount)
|
|
892
|
-
: 1;
|
|
893
|
-
|
|
894
|
-
return [
|
|
895
|
-
Math.max(0, startIndex - overscanBackward),
|
|
896
|
-
Math.max(0, Math.min(columnCount - 1, stopIndex + overscanForward)),
|
|
897
|
-
startIndex,
|
|
898
|
-
stopIndex,
|
|
899
|
-
];
|
|
900
|
-
}, [
|
|
901
|
-
rowHeight,
|
|
902
|
-
columnWidth,
|
|
903
|
-
rowCount,
|
|
904
|
-
columnCount,
|
|
905
|
-
scale,
|
|
906
|
-
frozenColumns,
|
|
907
|
-
containerWidth,
|
|
908
|
-
scrollLeft,
|
|
909
|
-
frozenColumnWidth,
|
|
910
|
-
]);
|
|
911
|
-
|
|
912
|
-
const estimatedTotalHeight = getEstimatedTotalHeight(
|
|
913
|
-
rowCount,
|
|
914
|
-
instanceProps.current
|
|
915
|
-
);
|
|
916
|
-
const estimatedTotalWidth = getEstimatedTotalWidth(
|
|
917
|
-
columnCount,
|
|
918
|
-
instanceProps.current
|
|
919
|
-
);
|
|
920
|
-
|
|
921
|
-
/* Method to get dimensions of the grid */
|
|
922
|
-
const getDimensions = useCallback(() => {
|
|
923
|
-
return {
|
|
924
|
-
containerWidth,
|
|
925
|
-
containerHeight,
|
|
926
|
-
estimatedTotalWidth,
|
|
927
|
-
estimatedTotalHeight,
|
|
928
|
-
};
|
|
929
|
-
}, [
|
|
930
|
-
containerWidth,
|
|
931
|
-
containerHeight,
|
|
932
|
-
estimatedTotalWidth,
|
|
933
|
-
estimatedTotalHeight,
|
|
934
|
-
]);
|
|
935
|
-
|
|
936
|
-
/**
|
|
937
|
-
* Update snap properties if its active
|
|
938
|
-
* We need this because we are binding `onwheel` event to document
|
|
939
|
-
* So props go stale
|
|
940
|
-
*/
|
|
941
|
-
useEffect(() => {
|
|
942
|
-
if (snap) {
|
|
943
|
-
scrollSnapRefs.current = {
|
|
944
|
-
visibleRowStartIndex,
|
|
945
|
-
rowCount,
|
|
946
|
-
frozenRows,
|
|
947
|
-
visibleColumnStartIndex,
|
|
948
|
-
columnCount,
|
|
949
|
-
frozenColumns,
|
|
950
|
-
isHiddenRow,
|
|
951
|
-
isHiddenColumn,
|
|
952
|
-
};
|
|
953
|
-
}
|
|
954
|
-
}, [
|
|
955
|
-
snap,
|
|
956
|
-
visibleRowStartIndex,
|
|
957
|
-
rowCount,
|
|
958
|
-
frozenRows,
|
|
959
|
-
visibleColumnStartIndex,
|
|
960
|
-
columnCount,
|
|
961
|
-
frozenColumns,
|
|
962
|
-
isHiddenRow,
|
|
963
|
-
isHiddenColumn,
|
|
964
|
-
]);
|
|
965
|
-
|
|
966
|
-
/**
|
|
967
|
-
* Snaps vertical scrollbar to the next/prev visible row
|
|
968
|
-
*/
|
|
969
|
-
const snapToRowFn = useCallback(({ deltaY }: SnapRowProps) => {
|
|
970
|
-
if (!verticalScrollRef.current || !scrollSnapRefs.current) return;
|
|
971
|
-
if (deltaY !== 0) {
|
|
972
|
-
const direction = deltaY < 0 ? Direction.Up : Direction.Down;
|
|
973
|
-
const { visibleRowStartIndex, rowCount, isHiddenRow } =
|
|
974
|
-
scrollSnapRefs.current;
|
|
975
|
-
let nextRowIndex =
|
|
976
|
-
direction === Direction.Up
|
|
977
|
-
? // User is scrolling up
|
|
978
|
-
Math.max(0, visibleRowStartIndex - 1)
|
|
979
|
-
: Math.min(visibleRowStartIndex, rowCount - 1);
|
|
980
|
-
/* Ignore hidden row */
|
|
981
|
-
nextRowIndex = clampIndex(nextRowIndex, isHiddenRow, direction);
|
|
982
|
-
const rowHeight = getRowHeight(nextRowIndex);
|
|
983
|
-
verticalScrollRef.current.scrollTop +=
|
|
984
|
-
(direction === Direction.Up ? -1 : 1) * rowHeight;
|
|
985
|
-
}
|
|
986
|
-
}, []);
|
|
987
|
-
|
|
988
|
-
/**
|
|
989
|
-
* Snaps horizontal scrollbar to the next/prev visible column
|
|
990
|
-
*/
|
|
991
|
-
const snapToColumnFn = useCallback(({ deltaX }: SnapColumnProps) => {
|
|
992
|
-
if (!horizontalScrollRef.current || !scrollSnapRefs.current) return;
|
|
993
|
-
if (deltaX !== 0) {
|
|
994
|
-
const { visibleColumnStartIndex, columnCount, isHiddenColumn } =
|
|
995
|
-
scrollSnapRefs.current;
|
|
996
|
-
const direction = deltaX < 0 ? Direction.Left : Direction.Right;
|
|
997
|
-
let nextColumnIndex =
|
|
998
|
-
direction === Direction.Left
|
|
999
|
-
? Math.max(0, visibleColumnStartIndex - 1)
|
|
1000
|
-
: Math.min(visibleColumnStartIndex, columnCount - 1);
|
|
1001
|
-
/* Ignore hidden column */
|
|
1002
|
-
nextColumnIndex = clampIndex(
|
|
1003
|
-
nextColumnIndex,
|
|
1004
|
-
isHiddenColumn,
|
|
1005
|
-
direction
|
|
1006
|
-
);
|
|
1007
|
-
const columnWidth = getColumnWidth(nextColumnIndex);
|
|
1008
|
-
horizontalScrollRef.current.scrollLeft +=
|
|
1009
|
-
(direction === Direction.Left ? -1 : 1) * columnWidth;
|
|
1010
|
-
}
|
|
1011
|
-
}, []);
|
|
1012
|
-
const snapToRowThrottler = useRef<({ deltaY }: SnapRowProps) => void>();
|
|
1013
|
-
const snapToColumnThrottler =
|
|
1014
|
-
useRef<({ deltaX }: SnapColumnProps) => void>();
|
|
1015
|
-
|
|
1016
|
-
/**
|
|
1017
|
-
* Register snap throttlers
|
|
1018
|
-
*/
|
|
1019
|
-
useEffect(() => {
|
|
1020
|
-
if (snap) {
|
|
1021
|
-
snapToRowThrottler.current = throttle(
|
|
1022
|
-
snapToRowFn,
|
|
1023
|
-
scrollThrottleTimeout
|
|
1024
|
-
);
|
|
1025
|
-
snapToColumnThrottler.current = throttle(
|
|
1026
|
-
snapToColumnFn,
|
|
1027
|
-
scrollThrottleTimeout
|
|
1028
|
-
);
|
|
1029
|
-
}
|
|
1030
|
-
return () => {
|
|
1031
|
-
snapToRowThrottler.current = undefined;
|
|
1032
|
-
snapToColumnThrottler.current = undefined;
|
|
1033
|
-
};
|
|
1034
|
-
}, [snap]);
|
|
1035
|
-
|
|
1036
|
-
/* Find frozen column boundary */
|
|
1037
|
-
const isWithinFrozenColumnBoundary = useCallback(
|
|
1038
|
-
(x: number) => {
|
|
1039
|
-
return frozenColumns > 0 && x < frozenColumnWidth;
|
|
1040
|
-
},
|
|
1041
|
-
[frozenColumns, frozenColumnWidth]
|
|
1042
|
-
);
|
|
1043
|
-
|
|
1044
|
-
/* Find frozen row boundary */
|
|
1045
|
-
const isWithinFrozenRowBoundary = useCallback(
|
|
1046
|
-
(y: number) => {
|
|
1047
|
-
return frozenRows > 0 && y < frozenRowHeight;
|
|
1048
|
-
},
|
|
1049
|
-
[frozenRows, frozenRowHeight]
|
|
1050
|
-
);
|
|
1051
|
-
|
|
1052
|
-
/**
|
|
1053
|
-
* Get relative mouse position
|
|
1054
|
-
*/
|
|
1055
|
-
const getRelativePositionFromOffset = useCallback(
|
|
1056
|
-
(left: number, top: number): PosXYRequired | null => {
|
|
1057
|
-
invariant(
|
|
1058
|
-
typeof left === "number" && typeof top === "number",
|
|
1059
|
-
"Top and left should be a number"
|
|
1060
|
-
);
|
|
1061
|
-
if (!stageRef.current) return null;
|
|
1062
|
-
const stage = stageRef.current.getStage();
|
|
1063
|
-
const rect = containerRef.current?.getBoundingClientRect();
|
|
1064
|
-
if (rect) {
|
|
1065
|
-
left = left - rect.x;
|
|
1066
|
-
top = top - rect.y;
|
|
1067
|
-
}
|
|
1068
|
-
const { x, y } = stage
|
|
1069
|
-
.getAbsoluteTransform()
|
|
1070
|
-
.copy()
|
|
1071
|
-
.invert()
|
|
1072
|
-
.point({ x: left, y: top });
|
|
1073
|
-
|
|
1074
|
-
return { x, y };
|
|
1075
|
-
},
|
|
1076
|
-
[]
|
|
1077
|
-
);
|
|
1078
|
-
|
|
1079
|
-
/**
|
|
1080
|
-
* Get cell cordinates from current mouse x/y positions
|
|
1081
|
-
*/
|
|
1082
|
-
const getCellCoordsFromOffset = useCallback(
|
|
1083
|
-
(
|
|
1084
|
-
left: number,
|
|
1085
|
-
top: number,
|
|
1086
|
-
includeFrozen: boolean = true
|
|
1087
|
-
): CellInterface | null => {
|
|
1088
|
-
const pos = getRelativePositionFromOffset(left, top);
|
|
1089
|
-
if (!pos) return null;
|
|
1090
|
-
const { x, y } = pos;
|
|
1091
|
-
const rowOffset =
|
|
1092
|
-
includeFrozen && isWithinFrozenRowBoundary(y) ? y : y + scrollTop;
|
|
1093
|
-
const columnOffset =
|
|
1094
|
-
includeFrozen && isWithinFrozenColumnBoundary(x) ? x : x + scrollLeft;
|
|
1095
|
-
if (
|
|
1096
|
-
rowOffset > estimatedTotalHeight ||
|
|
1097
|
-
columnOffset > estimatedTotalWidth
|
|
1098
|
-
) {
|
|
1099
|
-
return null;
|
|
1100
|
-
}
|
|
1101
|
-
const rowIndex = getRowStartIndexForOffset({
|
|
1102
|
-
rowHeight,
|
|
1103
|
-
columnWidth,
|
|
1104
|
-
rowCount,
|
|
1105
|
-
columnCount,
|
|
1106
|
-
instanceProps: instanceProps.current,
|
|
1107
|
-
offset: rowOffset,
|
|
1108
|
-
scale,
|
|
1109
|
-
});
|
|
1110
|
-
const columnIndex = getColumnStartIndexForOffset({
|
|
1111
|
-
rowHeight,
|
|
1112
|
-
columnWidth,
|
|
1113
|
-
rowCount,
|
|
1114
|
-
columnCount,
|
|
1115
|
-
instanceProps: instanceProps.current,
|
|
1116
|
-
offset: columnOffset,
|
|
1117
|
-
scale,
|
|
1118
|
-
});
|
|
1119
|
-
/* To be compatible with merged cells */
|
|
1120
|
-
const bounds = getCellBounds({ rowIndex, columnIndex });
|
|
1121
|
-
|
|
1122
|
-
return { rowIndex: bounds.top, columnIndex: bounds.left };
|
|
1123
|
-
},
|
|
1124
|
-
[
|
|
1125
|
-
scrollLeft,
|
|
1126
|
-
rowHeight,
|
|
1127
|
-
columnWidth,
|
|
1128
|
-
scrollTop,
|
|
1129
|
-
rowCount,
|
|
1130
|
-
estimatedTotalHeight,
|
|
1131
|
-
estimatedTotalWidth,
|
|
1132
|
-
columnCount,
|
|
1133
|
-
mergedCellMap,
|
|
1134
|
-
]
|
|
1135
|
-
);
|
|
1136
|
-
|
|
1137
|
-
/**
|
|
1138
|
-
* Get cell offset position from rowIndex, columnIndex
|
|
1139
|
-
*/
|
|
1140
|
-
const getCellOffsetFromCoords = useCallback(
|
|
1141
|
-
(cell: CellInterface): CellPosition => {
|
|
1142
|
-
const {
|
|
1143
|
-
top: rowIndex,
|
|
1144
|
-
left: columnIndex,
|
|
1145
|
-
right,
|
|
1146
|
-
bottom,
|
|
1147
|
-
} = getCellBounds(cell);
|
|
1148
|
-
const x = getColumnOffset(columnIndex);
|
|
1149
|
-
const y = getRowOffset(rowIndex);
|
|
1150
|
-
const width = getColumnOffset(right + 1) - x;
|
|
1151
|
-
const height = getRowOffset(bottom + 1) - y;
|
|
1152
|
-
|
|
1153
|
-
return {
|
|
1154
|
-
x,
|
|
1155
|
-
y,
|
|
1156
|
-
width,
|
|
1157
|
-
height,
|
|
1158
|
-
};
|
|
1159
|
-
},
|
|
1160
|
-
[mergedCellMap]
|
|
1161
|
-
);
|
|
1162
|
-
|
|
1163
|
-
/**
|
|
1164
|
-
* Resize one or more columns
|
|
1165
|
-
*/
|
|
1166
|
-
|
|
1167
|
-
const resizeColumns = useCallback((indices: number[]) => {
|
|
1168
|
-
const leftMost = Math.min(...indices);
|
|
1169
|
-
instanceProps.current.recalcColumnIndices = indices;
|
|
1170
|
-
resetAfterIndices({ columnIndex: leftMost }, false);
|
|
1171
|
-
forceRender();
|
|
1172
|
-
}, []);
|
|
1173
|
-
|
|
1174
|
-
/**
|
|
1175
|
-
* Resize one or more rows
|
|
1176
|
-
*/
|
|
1177
|
-
const resizeRows = useCallback((indices: number[]) => {
|
|
1178
|
-
const topMost = Math.min(...indices);
|
|
1179
|
-
instanceProps.current.recalcRowIndices = indices;
|
|
1180
|
-
resetAfterIndices({ rowIndex: topMost }, false);
|
|
1181
|
-
forceRender();
|
|
1182
|
-
}, []);
|
|
1183
|
-
|
|
1184
|
-
/* Always if the viewport changes */
|
|
1185
|
-
useEffect(() => {
|
|
1186
|
-
if (instanceProps.current.recalcColumnIndices.length) {
|
|
1187
|
-
instanceProps.current.recalcColumnIndices.length = 0;
|
|
1188
|
-
}
|
|
1189
|
-
if (instanceProps.current.recalcRowIndices.length) {
|
|
1190
|
-
instanceProps.current.recalcRowIndices.length = 0;
|
|
1191
|
-
}
|
|
1192
|
-
}, [rowStopIndex, columnStopIndex, scale]);
|
|
1193
|
-
|
|
1194
|
-
/* Get current view port of the grid */
|
|
1195
|
-
const getViewPort = useCallback((): ViewPortProps => {
|
|
1196
|
-
return {
|
|
1197
|
-
rowStartIndex,
|
|
1198
|
-
rowStopIndex,
|
|
1199
|
-
columnStartIndex,
|
|
1200
|
-
columnStopIndex,
|
|
1201
|
-
visibleRowStartIndex,
|
|
1202
|
-
visibleRowStopIndex,
|
|
1203
|
-
visibleColumnStartIndex,
|
|
1204
|
-
visibleColumnStopIndex,
|
|
1205
|
-
};
|
|
1206
|
-
}, [
|
|
1207
|
-
rowStartIndex,
|
|
1208
|
-
rowStopIndex,
|
|
1209
|
-
columnStartIndex,
|
|
1210
|
-
columnStopIndex,
|
|
1211
|
-
visibleRowStartIndex,
|
|
1212
|
-
visibleRowStopIndex,
|
|
1213
|
-
visibleColumnStartIndex,
|
|
1214
|
-
visibleColumnStopIndex,
|
|
1215
|
-
]);
|
|
1216
|
-
|
|
1217
|
-
/**
|
|
1218
|
-
* When the grid is scrolling,
|
|
1219
|
-
* 1. Stage does not listen to any mouse events
|
|
1220
|
-
* 2. Div container does not listen to pointer events
|
|
1221
|
-
*/
|
|
1222
|
-
const resetIsScrollingTimeoutID = useRef<TimeoutID | null>(null);
|
|
1223
|
-
const resetIsScrollingDebounced = useCallback(() => {
|
|
1224
|
-
if (resetIsScrollingTimeoutID.current !== null) {
|
|
1225
|
-
cancelTimeout(resetIsScrollingTimeoutID.current);
|
|
1226
|
-
}
|
|
1227
|
-
resetIsScrollingTimeoutID.current = requestTimeout(
|
|
1228
|
-
resetIsScrolling,
|
|
1229
|
-
RESET_SCROLL_EVENTS_DEBOUNCE_INTERVAL
|
|
1230
|
-
);
|
|
1231
|
-
}, []);
|
|
1232
|
-
/* Reset isScrolling */
|
|
1233
|
-
const resetIsScrolling = useCallback(() => {
|
|
1234
|
-
resetIsScrollingTimeoutID.current = null;
|
|
1235
|
-
|
|
1236
|
-
setScrollState((prev) => {
|
|
1237
|
-
return {
|
|
1238
|
-
...prev,
|
|
1239
|
-
isScrolling: false,
|
|
1240
|
-
};
|
|
1241
|
-
});
|
|
1242
|
-
}, []);
|
|
1243
|
-
|
|
1244
|
-
/* Handle vertical scroll */
|
|
1245
|
-
const handleScroll = useCallback(
|
|
1246
|
-
(e: UIEvent<Element>) => {
|
|
1247
|
-
const { scrollTop } = e.currentTarget;
|
|
1248
|
-
|
|
1249
|
-
setScrollState((prev) => ({
|
|
1250
|
-
...prev,
|
|
1251
|
-
isScrolling: true,
|
|
1252
|
-
verticalScrollDirection:
|
|
1253
|
-
prev.scrollTop > scrollTop ? Direction.Up : Direction.Down,
|
|
1254
|
-
scrollTop,
|
|
1255
|
-
}));
|
|
1256
|
-
|
|
1257
|
-
/* Scroll callbacks */
|
|
1258
|
-
onImmediateScroll?.({ scrollTop, scrollLeft });
|
|
1259
|
-
|
|
1260
|
-
/* Reset isScrolling if required */
|
|
1261
|
-
resetIsScrollingDebounced();
|
|
1262
|
-
},
|
|
1263
|
-
[scrollLeft]
|
|
1264
|
-
);
|
|
1265
|
-
|
|
1266
|
-
/* Handle horizontal scroll */
|
|
1267
|
-
const handleScrollLeft = useCallback(
|
|
1268
|
-
(e: UIEvent<Element>) => {
|
|
1269
|
-
const { scrollLeft } = e.currentTarget;
|
|
1270
|
-
setScrollState((prev) => ({
|
|
1271
|
-
...prev,
|
|
1272
|
-
isScrolling: true,
|
|
1273
|
-
horizontalScrollDirection:
|
|
1274
|
-
prev.scrollLeft > scrollLeft ? Direction.Left : Direction.Right,
|
|
1275
|
-
scrollLeft,
|
|
1276
|
-
}));
|
|
1277
|
-
|
|
1278
|
-
/* Scroll callbacks */
|
|
1279
|
-
onImmediateScroll?.({ scrollLeft, scrollTop });
|
|
1280
|
-
|
|
1281
|
-
/* Reset isScrolling if required */
|
|
1282
|
-
resetIsScrollingDebounced();
|
|
1283
|
-
},
|
|
1284
|
-
[scrollTop]
|
|
1285
|
-
);
|
|
1286
|
-
|
|
1287
|
-
/* Scroll based on left, top position */
|
|
1288
|
-
const scrollTo = useCallback(
|
|
1289
|
-
({ scrollTop, scrollLeft }: OptionalScrollCoords) => {
|
|
1290
|
-
/* If scrollbar is visible, lets update it which triggers a state change */
|
|
1291
|
-
if (showScrollbar) {
|
|
1292
|
-
if (horizontalScrollRef.current && scrollLeft !== void 0)
|
|
1293
|
-
horizontalScrollRef.current.scrollLeft = scrollLeft;
|
|
1294
|
-
if (verticalScrollRef.current && scrollTop !== void 0)
|
|
1295
|
-
verticalScrollRef.current.scrollTop = scrollTop;
|
|
1296
|
-
} else {
|
|
1297
|
-
setScrollState((prev) => {
|
|
1298
|
-
return {
|
|
1299
|
-
...prev,
|
|
1300
|
-
scrollLeft: scrollLeft == void 0 ? prev.scrollLeft : scrollLeft,
|
|
1301
|
-
scrollTop: scrollTop == void 0 ? prev.scrollTop : scrollTop,
|
|
1302
|
-
};
|
|
1303
|
-
});
|
|
1304
|
-
}
|
|
1305
|
-
},
|
|
1306
|
-
[showScrollbar]
|
|
1307
|
-
);
|
|
1308
|
-
|
|
1309
|
-
/* Scroll grid to top */
|
|
1310
|
-
const scrollToTop = useCallback(() => {
|
|
1311
|
-
scrollTo({ scrollTop: 0, scrollLeft: 0 });
|
|
1312
|
-
}, []);
|
|
1313
|
-
|
|
1314
|
-
/* Scroll grid to bottom */
|
|
1315
|
-
const scrollToBottom = useCallback(() => {
|
|
1316
|
-
scrollTo({ scrollTop: estimatedTotalHeight - containerHeight });
|
|
1317
|
-
}, [estimatedTotalHeight, containerHeight]);
|
|
1318
|
-
|
|
1319
|
-
/**
|
|
1320
|
-
* Scrollby utility
|
|
1321
|
-
*/
|
|
1322
|
-
const scrollBy = useCallback(({ x, y }: PosXY) => {
|
|
1323
|
-
if (showScrollbar) {
|
|
1324
|
-
if (horizontalScrollRef.current && x !== void 0)
|
|
1325
|
-
horizontalScrollRef.current.scrollLeft += x;
|
|
1326
|
-
if (verticalScrollRef.current && y !== void 0)
|
|
1327
|
-
verticalScrollRef.current.scrollTop += y;
|
|
1328
|
-
} else {
|
|
1329
|
-
setScrollState((prev) => {
|
|
1330
|
-
return {
|
|
1331
|
-
...prev,
|
|
1332
|
-
scrollLeft: x == void 0 ? prev.scrollLeft : prev.scrollLeft + x,
|
|
1333
|
-
scrollTop: y == void 0 ? prev.scrollTop : prev.scrollTop + y,
|
|
1334
|
-
};
|
|
1335
|
-
});
|
|
1336
|
-
}
|
|
1337
|
-
}, []);
|
|
1338
|
-
|
|
1339
|
-
/**
|
|
1340
|
-
* Scrolls to cell
|
|
1341
|
-
* Respects frozen rows and columns
|
|
1342
|
-
*/
|
|
1343
|
-
const scrollToItem = useCallback(
|
|
1344
|
-
(
|
|
1345
|
-
{ rowIndex, columnIndex }: OptionalCellInterface,
|
|
1346
|
-
align: Align = Align.smart
|
|
1347
|
-
) => {
|
|
1348
|
-
const isFrozenRow = rowIndex !== void 0 && rowIndex < frozenRows;
|
|
1349
|
-
const isFrozenColumn =
|
|
1350
|
-
columnIndex !== void 0 && columnIndex < frozenColumns;
|
|
1351
|
-
const frozenColumnOffset = getColumnOffset(frozenColumns);
|
|
1352
|
-
/* Making sure getColumnWidth works */
|
|
1353
|
-
const x =
|
|
1354
|
-
columnIndex !== void 0 ? getColumnOffset(columnIndex) : void 0;
|
|
1355
|
-
/* Making sure getRowHeight works */
|
|
1356
|
-
const y = rowIndex !== void 0 ? getRowOffset(rowIndex) : void 0;
|
|
1357
|
-
const width = columnIndex !== void 0 ? getColumnWidth(columnIndex) : 0;
|
|
1358
|
-
const height = rowIndex !== void 0 ? getRowHeight(rowIndex) : 0;
|
|
1359
|
-
const columnAlign = width > containerWidth ? Align.start : align;
|
|
1360
|
-
const rowAlign = height > containerHeight ? Align.start : align;
|
|
1361
|
-
const newScrollLeft =
|
|
1362
|
-
columnIndex !== void 0 && !isFrozenColumn
|
|
1363
|
-
? getOffsetForColumnAndAlignment({
|
|
1364
|
-
index: columnIndex,
|
|
1365
|
-
containerHeight,
|
|
1366
|
-
containerWidth,
|
|
1367
|
-
columnCount,
|
|
1368
|
-
columnWidth,
|
|
1369
|
-
rowCount,
|
|
1370
|
-
rowHeight,
|
|
1371
|
-
scrollOffset: scrollLeft,
|
|
1372
|
-
instanceProps: instanceProps.current,
|
|
1373
|
-
scrollbarSize,
|
|
1374
|
-
frozenOffset: frozenColumnOffset,
|
|
1375
|
-
align: columnAlign,
|
|
1376
|
-
scale,
|
|
1377
|
-
estimatedTotalWidth,
|
|
1378
|
-
estimatedTotalHeight,
|
|
1379
|
-
})
|
|
1380
|
-
: void 0;
|
|
1381
|
-
|
|
1382
|
-
const frozenRowOffset = getRowOffset(frozenRows);
|
|
1383
|
-
const newScrollTop =
|
|
1384
|
-
rowIndex !== void 0 && !isFrozenRow
|
|
1385
|
-
? getOffsetForRowAndAlignment({
|
|
1386
|
-
index: rowIndex,
|
|
1387
|
-
containerHeight,
|
|
1388
|
-
containerWidth,
|
|
1389
|
-
columnCount,
|
|
1390
|
-
columnWidth,
|
|
1391
|
-
rowCount,
|
|
1392
|
-
rowHeight,
|
|
1393
|
-
scrollOffset: scrollTop,
|
|
1394
|
-
instanceProps: instanceProps.current,
|
|
1395
|
-
scrollbarSize,
|
|
1396
|
-
frozenOffset: frozenRowOffset,
|
|
1397
|
-
align: rowAlign,
|
|
1398
|
-
scale,
|
|
1399
|
-
estimatedTotalWidth,
|
|
1400
|
-
estimatedTotalHeight,
|
|
1401
|
-
})
|
|
1402
|
-
: void 0;
|
|
1403
|
-
|
|
1404
|
-
const coords = {
|
|
1405
|
-
scrollLeft: newScrollLeft,
|
|
1406
|
-
scrollTop: newScrollTop,
|
|
1407
|
-
};
|
|
1408
|
-
const isOutsideViewport =
|
|
1409
|
-
(rowIndex !== void 0 &&
|
|
1410
|
-
rowIndex > rowStopIndex + (rowStopIndex - rowStartIndex)) ||
|
|
1411
|
-
(columnIndex !== void 0 &&
|
|
1412
|
-
columnIndex >
|
|
1413
|
-
columnStopIndex + (columnStopIndex - columnStartIndex));
|
|
1414
|
-
|
|
1415
|
-
/* Scroll in the next frame, Useful when user wants to jump from 1st column to last */
|
|
1416
|
-
if (isOutsideViewport) {
|
|
1417
|
-
window.requestAnimationFrame(() => {
|
|
1418
|
-
scrollTo(coords);
|
|
1419
|
-
});
|
|
1420
|
-
} else scrollTo(coords);
|
|
1421
|
-
},
|
|
1422
|
-
[
|
|
1423
|
-
containerHeight,
|
|
1424
|
-
containerWidth,
|
|
1425
|
-
estimatedTotalWidth,
|
|
1426
|
-
estimatedTotalHeight,
|
|
1427
|
-
rowCount,
|
|
1428
|
-
columnCount,
|
|
1429
|
-
scrollbarSize,
|
|
1430
|
-
scrollLeft,
|
|
1431
|
-
scrollTop,
|
|
1432
|
-
frozenRows,
|
|
1433
|
-
frozenColumns,
|
|
1434
|
-
]
|
|
1435
|
-
);
|
|
1436
|
-
|
|
1437
|
-
/**
|
|
1438
|
-
* Fired when user tries to scroll the canvas
|
|
1439
|
-
*/
|
|
1440
|
-
const handleWheel = useCallback((event: WheelEvent) => {
|
|
1441
|
-
/* If user presses shift key, scroll horizontally */
|
|
1442
|
-
const isScrollingHorizontally = event.shiftKey;
|
|
1443
|
-
|
|
1444
|
-
/* Prevent browser back in Mac */
|
|
1445
|
-
event.preventDefault();
|
|
1446
|
-
const { deltaX, deltaY, deltaMode } = event;
|
|
1447
|
-
/* Scroll natively */
|
|
1448
|
-
if (wheelingRef.current) return;
|
|
1449
|
-
|
|
1450
|
-
let dx = isScrollingHorizontally ? deltaY : deltaX;
|
|
1451
|
-
let dy = deltaY;
|
|
1452
|
-
|
|
1453
|
-
/* Scroll only in one direction */
|
|
1454
|
-
const isHorizontal =
|
|
1455
|
-
isScrollingHorizontally || Math.abs(dx) > Math.abs(dy);
|
|
1456
|
-
|
|
1457
|
-
/* If snaps are active */
|
|
1458
|
-
if (snap) {
|
|
1459
|
-
if (isHorizontal) {
|
|
1460
|
-
snapToColumnThrottler.current?.({
|
|
1461
|
-
deltaX,
|
|
1462
|
-
});
|
|
1463
|
-
} else {
|
|
1464
|
-
snapToRowThrottler.current?.({
|
|
1465
|
-
deltaY,
|
|
1466
|
-
});
|
|
1467
|
-
}
|
|
1468
|
-
return;
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1471
|
-
if (deltaMode === 1) {
|
|
1472
|
-
dy = dy * scrollbarSize;
|
|
1473
|
-
}
|
|
1474
|
-
if (!horizontalScrollRef.current || !verticalScrollRef.current) return;
|
|
1475
|
-
const currentScroll = isHorizontal
|
|
1476
|
-
? horizontalScrollRef.current?.scrollLeft
|
|
1477
|
-
: verticalScrollRef.current?.scrollTop;
|
|
1478
|
-
wheelingRef.current = window.requestAnimationFrame(() => {
|
|
1479
|
-
wheelingRef.current = null;
|
|
1480
|
-
if (isHorizontal) {
|
|
1481
|
-
if (horizontalScrollRef.current)
|
|
1482
|
-
horizontalScrollRef.current.scrollLeft = currentScroll + dx;
|
|
1483
|
-
} else {
|
|
1484
|
-
if (verticalScrollRef.current)
|
|
1485
|
-
verticalScrollRef.current.scrollTop = currentScroll + dy;
|
|
1486
|
-
}
|
|
1487
|
-
});
|
|
1488
|
-
}, []);
|
|
1489
|
-
|
|
1490
|
-
/* Callback when visible rows or columns have changed */
|
|
1491
|
-
useEffect(() => {
|
|
1492
|
-
onViewChange?.({
|
|
1493
|
-
rowStartIndex,
|
|
1494
|
-
rowStopIndex,
|
|
1495
|
-
columnStartIndex,
|
|
1496
|
-
columnStopIndex,
|
|
1497
|
-
visibleRowStartIndex,
|
|
1498
|
-
visibleRowStopIndex,
|
|
1499
|
-
visibleColumnStartIndex,
|
|
1500
|
-
visibleColumnStopIndex,
|
|
1501
|
-
});
|
|
1502
|
-
}, [
|
|
1503
|
-
rowStartIndex,
|
|
1504
|
-
rowStopIndex,
|
|
1505
|
-
columnStartIndex,
|
|
1506
|
-
columnStopIndex,
|
|
1507
|
-
visibleRowStartIndex,
|
|
1508
|
-
visibleRowStopIndex,
|
|
1509
|
-
visibleColumnStartIndex,
|
|
1510
|
-
visibleColumnStopIndex,
|
|
1511
|
-
]);
|
|
1512
|
-
|
|
1513
|
-
/* Draw gridlines */
|
|
1514
|
-
const gridLines = [];
|
|
1515
|
-
const gridLinesFrozenRow = [];
|
|
1516
|
-
const gridLinesFrozenColumn = [];
|
|
1517
|
-
const gridLinesFrozenIntersection = [];
|
|
1518
|
-
if (showGridLines) {
|
|
1519
|
-
// Horizontal
|
|
1520
|
-
for (let rowIndex = rowStartIndex; rowIndex <= rowStopIndex; rowIndex++) {
|
|
1521
|
-
/* Ignore frozen rows */
|
|
1522
|
-
if (rowIndex < frozenRows || isHiddenRow?.(rowIndex)) continue;
|
|
1523
|
-
const x1 = getColumnOffset(frozenColumns);
|
|
1524
|
-
const x2 = getColumnOffset(Math.min(columnStopIndex + 1, columnCount));
|
|
1525
|
-
const y1 = getRowOffset(Math.min(rowIndex + 1, rowCount));
|
|
1526
|
-
const y2 = y1;
|
|
1527
|
-
gridLines.push(
|
|
1528
|
-
gridLineRenderer({
|
|
1529
|
-
points: [x1, y1, x2, y2],
|
|
1530
|
-
stroke: gridLineColor,
|
|
1531
|
-
strokeWidth: gridLineWidth,
|
|
1532
|
-
offsetY: -0.5,
|
|
1533
|
-
key: itemKey({ rowIndex: rowIndex, columnIndex: y1 }),
|
|
1534
|
-
})
|
|
1535
|
-
);
|
|
1536
|
-
gridLinesFrozenColumn.push(
|
|
1537
|
-
gridLineRenderer({
|
|
1538
|
-
points: [0, y1, x2, y2],
|
|
1539
|
-
stroke: gridLineColor,
|
|
1540
|
-
strokeWidth: gridLineWidth,
|
|
1541
|
-
offsetY: -0.5,
|
|
1542
|
-
key: itemKey({ rowIndex: rowIndex, columnIndex: y1 }),
|
|
1543
|
-
})
|
|
1544
|
-
);
|
|
1545
|
-
}
|
|
1546
|
-
// Vertical
|
|
1547
|
-
for (
|
|
1548
|
-
let columnIndex = columnStartIndex;
|
|
1549
|
-
columnIndex <= columnStopIndex;
|
|
1550
|
-
columnIndex++
|
|
1551
|
-
) {
|
|
1552
|
-
const x1 = getColumnOffset(Math.min(columnIndex + 1, columnCount));
|
|
1553
|
-
const x2 = x1;
|
|
1554
|
-
const y1 = getRowOffset(frozenRows);
|
|
1555
|
-
const y2 = getRowOffset(Math.min(rowStopIndex + 1, rowCount));
|
|
1556
|
-
gridLines.push(
|
|
1557
|
-
gridLineRenderer({
|
|
1558
|
-
points: [x1, y1, x2, y2],
|
|
1559
|
-
stroke: gridLineColor,
|
|
1560
|
-
strokeWidth: gridLineWidth,
|
|
1561
|
-
offsetX: -0.5,
|
|
1562
|
-
key: itemKey({ rowIndex: x1, columnIndex: columnIndex }),
|
|
1563
|
-
})
|
|
1564
|
-
);
|
|
1565
|
-
gridLinesFrozenRow.push(
|
|
1566
|
-
gridLineRenderer({
|
|
1567
|
-
points: [x1, 0, x2, y2],
|
|
1568
|
-
stroke: gridLineColor,
|
|
1569
|
-
strokeWidth: gridLineWidth,
|
|
1570
|
-
offsetX: -0.5,
|
|
1571
|
-
key: itemKey({ rowIndex: x1, columnIndex: columnIndex }),
|
|
1572
|
-
})
|
|
1573
|
-
);
|
|
1574
|
-
}
|
|
1575
|
-
for (
|
|
1576
|
-
let rowIndex = 0;
|
|
1577
|
-
rowIndex < Math.min(columnStopIndex, frozenRows);
|
|
1578
|
-
rowIndex++
|
|
1579
|
-
) {
|
|
1580
|
-
if (isHiddenRow?.(rowIndex)) continue;
|
|
1581
|
-
const x1 = 0;
|
|
1582
|
-
const x2 = getColumnOffset(Math.min(columnStopIndex + 1, columnCount));
|
|
1583
|
-
const y1 = getRowOffset(Math.min(rowIndex + 1, rowCount));
|
|
1584
|
-
const y2 = y1;
|
|
1585
|
-
gridLinesFrozenRow.push(
|
|
1586
|
-
gridLineRenderer({
|
|
1587
|
-
points: [x1, y1, x2, y2],
|
|
1588
|
-
stroke: gridLineColor,
|
|
1589
|
-
strokeWidth: gridLineWidth,
|
|
1590
|
-
offsetY: -0.5,
|
|
1591
|
-
key: itemKey({ rowIndex: rowIndex, columnIndex: y1 }),
|
|
1592
|
-
})
|
|
1593
|
-
);
|
|
1594
|
-
gridLinesFrozenIntersection.push(
|
|
1595
|
-
gridLineRenderer({
|
|
1596
|
-
points: [x1, y1, x2, y2],
|
|
1597
|
-
stroke: gridLineColor,
|
|
1598
|
-
strokeWidth: gridLineWidth,
|
|
1599
|
-
offsetY: -0.5,
|
|
1600
|
-
key: itemKey({ rowIndex: rowIndex, columnIndex: y1 }),
|
|
1601
|
-
})
|
|
1602
|
-
);
|
|
1603
|
-
}
|
|
1604
|
-
|
|
1605
|
-
for (
|
|
1606
|
-
let columnIndex = 0;
|
|
1607
|
-
columnIndex < Math.min(columnStopIndex, frozenColumns);
|
|
1608
|
-
columnIndex++
|
|
1609
|
-
) {
|
|
1610
|
-
const x1 = getColumnOffset(Math.min(columnIndex + 1, columnCount));
|
|
1611
|
-
const x2 = x1;
|
|
1612
|
-
const y1 = 0;
|
|
1613
|
-
const y2 = getRowOffset(Math.min(rowStopIndex + 1, rowCount));
|
|
1614
|
-
gridLinesFrozenColumn.push(
|
|
1615
|
-
gridLineRenderer({
|
|
1616
|
-
points: [x1, y1, x2, y2],
|
|
1617
|
-
stroke: gridLineColor,
|
|
1618
|
-
strokeWidth: gridLineWidth,
|
|
1619
|
-
offsetX: -0.5,
|
|
1620
|
-
key: itemKey({ rowIndex: x1, columnIndex: columnIndex }),
|
|
1621
|
-
})
|
|
1622
|
-
);
|
|
1623
|
-
gridLinesFrozenIntersection.push(
|
|
1624
|
-
gridLineRenderer({
|
|
1625
|
-
points: [x1, y1, x2, y2],
|
|
1626
|
-
stroke: gridLineColor,
|
|
1627
|
-
strokeWidth: gridLineWidth,
|
|
1628
|
-
offsetX: -0.5,
|
|
1629
|
-
key: itemKey({ rowIndex: x1, columnIndex: columnIndex }),
|
|
1630
|
-
})
|
|
1631
|
-
);
|
|
1632
|
-
}
|
|
1633
|
-
}
|
|
1634
|
-
|
|
1635
|
-
const mergedCellRenderMap = new Set();
|
|
1636
|
-
/* Draw all cells */
|
|
1637
|
-
const cells: React.ReactNode[] = [];
|
|
1638
|
-
/**
|
|
1639
|
-
* Lets users draw cells on top of existing canvas
|
|
1640
|
-
*/
|
|
1641
|
-
const cellOverlays: React.ReactNode[] = [];
|
|
1642
|
-
|
|
1643
|
-
if (columnCount > 0 && rowCount) {
|
|
1644
|
-
for (let rowIndex = rowStartIndex; rowIndex <= rowStopIndex; rowIndex++) {
|
|
1645
|
-
/* Skip frozen rows */
|
|
1646
|
-
if (rowIndex < frozenRows || isHiddenRow?.(rowIndex)) {
|
|
1647
|
-
continue;
|
|
1648
|
-
}
|
|
1649
|
-
/**
|
|
1650
|
-
* Do any pre-processing of the row before being renderered.
|
|
1651
|
-
* Useful for `react-table` to call `prepareRow(row)`
|
|
1652
|
-
*/
|
|
1653
|
-
onBeforeRenderRow?.(rowIndex);
|
|
1654
|
-
|
|
1655
|
-
for (
|
|
1656
|
-
let columnIndex = columnStartIndex;
|
|
1657
|
-
columnIndex <= columnStopIndex;
|
|
1658
|
-
columnIndex++
|
|
1659
|
-
) {
|
|
1660
|
-
/**
|
|
1661
|
-
* Skip frozen columns
|
|
1662
|
-
* Skip merged cells that are out of bounds
|
|
1663
|
-
*/
|
|
1664
|
-
if (columnIndex < frozenColumns) {
|
|
1665
|
-
continue;
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
|
-
const isMerged = isMergedCell({ rowIndex, columnIndex });
|
|
1669
|
-
const bounds = getCellBounds({ rowIndex, columnIndex });
|
|
1670
|
-
const actualRowIndex = isMerged ? bounds.top : rowIndex;
|
|
1671
|
-
const actualColumnIndex = isMerged ? bounds.left : columnIndex;
|
|
1672
|
-
const actualBottom = Math.max(rowIndex, bounds.bottom);
|
|
1673
|
-
const actualRight = Math.max(columnIndex, bounds.right);
|
|
1674
|
-
if (!isMerged && isHiddenCell?.(actualRowIndex, actualColumnIndex)) {
|
|
1675
|
-
continue;
|
|
1676
|
-
}
|
|
1677
|
-
if (isMerged) {
|
|
1678
|
-
const cellId = cellIdentifier(bounds.top, bounds.left);
|
|
1679
|
-
if (mergedCellRenderMap.has(cellId)) {
|
|
1680
|
-
continue;
|
|
1681
|
-
}
|
|
1682
|
-
mergedCellRenderMap.add(cellId);
|
|
1683
|
-
}
|
|
1684
|
-
|
|
1685
|
-
const y = getRowOffset(actualRowIndex);
|
|
1686
|
-
const height =
|
|
1687
|
-
getRowOffset(actualBottom) - y + getRowHeight(actualBottom);
|
|
1688
|
-
|
|
1689
|
-
const x = getColumnOffset(actualColumnIndex);
|
|
1690
|
-
|
|
1691
|
-
const width =
|
|
1692
|
-
getColumnOffset(actualRight) - x + getColumnWidth(actualRight);
|
|
1693
|
-
|
|
1694
|
-
cells.push(
|
|
1695
|
-
itemRenderer({
|
|
1696
|
-
x,
|
|
1697
|
-
y,
|
|
1698
|
-
width,
|
|
1699
|
-
height,
|
|
1700
|
-
rowIndex: actualRowIndex,
|
|
1701
|
-
columnIndex: actualColumnIndex,
|
|
1702
|
-
isMergedCell: isMerged,
|
|
1703
|
-
key: itemKey({
|
|
1704
|
-
rowIndex: actualRowIndex,
|
|
1705
|
-
columnIndex: actualColumnIndex,
|
|
1706
|
-
}),
|
|
1707
|
-
})
|
|
1708
|
-
);
|
|
1709
|
-
|
|
1710
|
-
if (enableCellOverlay) {
|
|
1711
|
-
cellOverlays.push(
|
|
1712
|
-
overlayRenderer({
|
|
1713
|
-
x,
|
|
1714
|
-
y,
|
|
1715
|
-
width,
|
|
1716
|
-
height,
|
|
1717
|
-
rowIndex: actualRowIndex,
|
|
1718
|
-
columnIndex: actualColumnIndex,
|
|
1719
|
-
isMergedCell: isMerged,
|
|
1720
|
-
key: itemKey({
|
|
1721
|
-
rowIndex: actualRowIndex,
|
|
1722
|
-
columnIndex: actualColumnIndex,
|
|
1723
|
-
}),
|
|
1724
|
-
})
|
|
1725
|
-
);
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
}
|
|
1730
|
-
|
|
1731
|
-
/**
|
|
1732
|
-
* Extend certain cells.
|
|
1733
|
-
* Mimics google sheets functionality where
|
|
1734
|
-
* oevrflowed cell content can cover adjacent cells
|
|
1735
|
-
*/
|
|
1736
|
-
const ranges = [];
|
|
1737
|
-
for (const { rowIndex, columnIndex, toColumnIndex } of cellAreas) {
|
|
1738
|
-
/* Skip merged cells, Merged cell cannot be extended */
|
|
1739
|
-
if (
|
|
1740
|
-
rowIndex < frozenRows ||
|
|
1741
|
-
columnIndex < frozenColumns ||
|
|
1742
|
-
isMergedCell({ rowIndex, columnIndex }) ||
|
|
1743
|
-
isHiddenCell?.(rowIndex, columnIndex)
|
|
1744
|
-
) {
|
|
1745
|
-
continue;
|
|
1746
|
-
}
|
|
1747
|
-
const x = getColumnOffset(columnIndex);
|
|
1748
|
-
const y = getRowOffset(rowIndex);
|
|
1749
|
-
const height = getRowHeight(rowIndex);
|
|
1750
|
-
const { x: offsetX = 0 } = getCellOffsetFromCoords({
|
|
1751
|
-
rowIndex,
|
|
1752
|
-
columnIndex: toColumnIndex + 1,
|
|
1753
|
-
});
|
|
1754
|
-
ranges.push(
|
|
1755
|
-
itemRenderer({
|
|
1756
|
-
x,
|
|
1757
|
-
y,
|
|
1758
|
-
width: offsetX - x,
|
|
1759
|
-
height,
|
|
1760
|
-
rowIndex,
|
|
1761
|
-
columnIndex,
|
|
1762
|
-
key: `range:${itemKey({ rowIndex, columnIndex })}`,
|
|
1763
|
-
})
|
|
1764
|
-
);
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
/* Draw frozen rows */
|
|
1768
|
-
const frozenRowCells = [];
|
|
1769
|
-
const frozenRowCellOverlays: React.ReactNode[] = [];
|
|
1770
|
-
for (
|
|
1771
|
-
let rowIndex = 0;
|
|
1772
|
-
rowIndex < Math.min(rowStopIndex, frozenRows);
|
|
1773
|
-
rowIndex++
|
|
1774
|
-
) {
|
|
1775
|
-
if (isHiddenRow?.(rowIndex)) continue;
|
|
1776
|
-
/**
|
|
1777
|
-
* Do any pre-processing of the row before being renderered.
|
|
1778
|
-
* Useful for `react-table` to call `prepareRow(row)`
|
|
1779
|
-
*/
|
|
1780
|
-
onBeforeRenderRow?.(rowIndex);
|
|
1781
|
-
|
|
1782
|
-
for (
|
|
1783
|
-
let columnIndex = columnStartIndex;
|
|
1784
|
-
columnIndex <= columnStopIndex;
|
|
1785
|
-
columnIndex++
|
|
1786
|
-
) {
|
|
1787
|
-
/* Skip merged cells columns */
|
|
1788
|
-
if (columnIndex < frozenColumns) {
|
|
1789
|
-
continue;
|
|
1790
|
-
}
|
|
1791
|
-
|
|
1792
|
-
const isMerged = isMergedCell({ rowIndex, columnIndex });
|
|
1793
|
-
const bounds = getCellBounds({ rowIndex, columnIndex });
|
|
1794
|
-
const actualRowIndex = isMerged ? bounds.top : rowIndex;
|
|
1795
|
-
const actualColumnIndex = isMerged ? bounds.left : columnIndex;
|
|
1796
|
-
const actualBottom = Math.max(rowIndex, bounds.bottom);
|
|
1797
|
-
const actualRight = Math.max(columnIndex, bounds.right);
|
|
1798
|
-
if (!isMerged && isHiddenCell?.(actualRowIndex, actualColumnIndex)) {
|
|
1799
|
-
continue;
|
|
1800
|
-
}
|
|
1801
|
-
if (isMerged) {
|
|
1802
|
-
const cellId = cellIdentifier(bounds.top, bounds.left);
|
|
1803
|
-
if (mergedCellRenderMap.has(cellId)) {
|
|
1804
|
-
continue;
|
|
1805
|
-
}
|
|
1806
|
-
mergedCellRenderMap.add(cellId);
|
|
1807
|
-
}
|
|
1808
|
-
|
|
1809
|
-
const y = getRowOffset(actualRowIndex);
|
|
1810
|
-
const height =
|
|
1811
|
-
getRowOffset(actualBottom) - y + getRowHeight(actualBottom);
|
|
1812
|
-
|
|
1813
|
-
const x = getColumnOffset(actualColumnIndex);
|
|
1814
|
-
|
|
1815
|
-
const width =
|
|
1816
|
-
getColumnOffset(actualRight) - x + getColumnWidth(actualRight);
|
|
1817
|
-
|
|
1818
|
-
frozenRowCells.push(
|
|
1819
|
-
itemRenderer({
|
|
1820
|
-
x,
|
|
1821
|
-
y,
|
|
1822
|
-
width,
|
|
1823
|
-
height,
|
|
1824
|
-
rowIndex: actualRowIndex,
|
|
1825
|
-
columnIndex: actualColumnIndex,
|
|
1826
|
-
isMergedCell: isMerged,
|
|
1827
|
-
key: itemKey({
|
|
1828
|
-
rowIndex: actualRowIndex,
|
|
1829
|
-
columnIndex: actualColumnIndex,
|
|
1830
|
-
}),
|
|
1831
|
-
})
|
|
1832
|
-
);
|
|
1833
|
-
|
|
1834
|
-
if (enableCellOverlay) {
|
|
1835
|
-
frozenRowCellOverlays.push(
|
|
1836
|
-
overlayRenderer({
|
|
1837
|
-
x,
|
|
1838
|
-
y,
|
|
1839
|
-
width,
|
|
1840
|
-
height,
|
|
1841
|
-
rowIndex: actualRowIndex,
|
|
1842
|
-
columnIndex: actualColumnIndex,
|
|
1843
|
-
isMergedCell: isMerged,
|
|
1844
|
-
key: itemKey({
|
|
1845
|
-
rowIndex: actualRowIndex,
|
|
1846
|
-
columnIndex: actualColumnIndex,
|
|
1847
|
-
}),
|
|
1848
|
-
})
|
|
1849
|
-
);
|
|
1850
|
-
}
|
|
1851
|
-
}
|
|
1852
|
-
}
|
|
1853
|
-
|
|
1854
|
-
/* Draw frozen columns */
|
|
1855
|
-
const frozenColumnCells = [];
|
|
1856
|
-
const frozenColumnCellOverlays = [];
|
|
1857
|
-
for (let rowIndex = rowStartIndex; rowIndex <= rowStopIndex; rowIndex++) {
|
|
1858
|
-
if (rowIndex < frozenRows || isHiddenRow?.(rowIndex)) {
|
|
1859
|
-
continue;
|
|
1860
|
-
}
|
|
1861
|
-
/**
|
|
1862
|
-
* Do any pre-processing of the row before being renderered.
|
|
1863
|
-
* Useful for `react-table` to call `prepareRow(row)`
|
|
1864
|
-
*/
|
|
1865
|
-
onBeforeRenderRow?.(rowIndex);
|
|
1866
|
-
|
|
1867
|
-
for (
|
|
1868
|
-
let columnIndex = 0;
|
|
1869
|
-
columnIndex < Math.min(columnStopIndex, frozenColumns);
|
|
1870
|
-
columnIndex++
|
|
1871
|
-
) {
|
|
1872
|
-
const isMerged = isMergedCell({ rowIndex, columnIndex });
|
|
1873
|
-
const bounds = getCellBounds({ rowIndex, columnIndex });
|
|
1874
|
-
const actualRowIndex = isMerged ? bounds.top : rowIndex;
|
|
1875
|
-
const actualColumnIndex = isMerged ? bounds.left : columnIndex;
|
|
1876
|
-
const actualBottom = Math.max(rowIndex, bounds.bottom);
|
|
1877
|
-
const actualRight = Math.max(columnIndex, bounds.right);
|
|
1878
|
-
if (!isMerged && isHiddenCell?.(actualRowIndex, actualColumnIndex)) {
|
|
1879
|
-
continue;
|
|
1880
|
-
}
|
|
1881
|
-
if (isMerged) {
|
|
1882
|
-
const cellId = cellIdentifier(bounds.top, bounds.left);
|
|
1883
|
-
if (mergedCellRenderMap.has(cellId)) {
|
|
1884
|
-
continue;
|
|
1885
|
-
}
|
|
1886
|
-
mergedCellRenderMap.add(cellId);
|
|
1887
|
-
}
|
|
1888
|
-
|
|
1889
|
-
const y = getRowOffset(actualRowIndex);
|
|
1890
|
-
const height =
|
|
1891
|
-
getRowOffset(actualBottom) - y + getRowHeight(actualBottom);
|
|
1892
|
-
|
|
1893
|
-
const x = getColumnOffset(actualColumnIndex);
|
|
1894
|
-
|
|
1895
|
-
const width =
|
|
1896
|
-
getColumnOffset(actualRight) - x + getColumnWidth(actualRight);
|
|
1897
|
-
|
|
1898
|
-
frozenColumnCells.push(
|
|
1899
|
-
itemRenderer({
|
|
1900
|
-
x,
|
|
1901
|
-
y,
|
|
1902
|
-
width,
|
|
1903
|
-
height,
|
|
1904
|
-
rowIndex: actualRowIndex,
|
|
1905
|
-
columnIndex: actualColumnIndex,
|
|
1906
|
-
isMergedCell: isMerged,
|
|
1907
|
-
key: itemKey({
|
|
1908
|
-
rowIndex: actualRowIndex,
|
|
1909
|
-
columnIndex: actualColumnIndex,
|
|
1910
|
-
}),
|
|
1911
|
-
})
|
|
1912
|
-
);
|
|
1913
|
-
|
|
1914
|
-
if (enableCellOverlay) {
|
|
1915
|
-
frozenColumnCellOverlays.push(
|
|
1916
|
-
overlayRenderer({
|
|
1917
|
-
x,
|
|
1918
|
-
y,
|
|
1919
|
-
width,
|
|
1920
|
-
height,
|
|
1921
|
-
rowIndex: actualRowIndex,
|
|
1922
|
-
columnIndex: actualColumnIndex,
|
|
1923
|
-
isMergedCell: isMerged,
|
|
1924
|
-
key: itemKey({
|
|
1925
|
-
rowIndex: actualRowIndex,
|
|
1926
|
-
columnIndex: actualColumnIndex,
|
|
1927
|
-
}),
|
|
1928
|
-
})
|
|
1929
|
-
);
|
|
1930
|
-
}
|
|
1931
|
-
}
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
/**
|
|
1935
|
-
* Frozen column shadow
|
|
1936
|
-
*/
|
|
1937
|
-
const frozenColumnShadow = useMemo(() => {
|
|
1938
|
-
const frozenColumnLineX = getColumnOffset(frozenColumns);
|
|
1939
|
-
const frozenColumnLineY = getRowOffset(
|
|
1940
|
-
Math.min(rowStopIndex + 1, rowCount)
|
|
1941
|
-
);
|
|
1942
|
-
return (
|
|
1943
|
-
<Line
|
|
1944
|
-
points={[frozenColumnLineX, 0, frozenColumnLineX, frozenColumnLineY]}
|
|
1945
|
-
offsetX={-0.5}
|
|
1946
|
-
strokeWidth={1}
|
|
1947
|
-
shadowForStrokeEnabled={false}
|
|
1948
|
-
strokeScaleEnabled={false}
|
|
1949
|
-
hitStrokeWidth={0}
|
|
1950
|
-
listening={false}
|
|
1951
|
-
perfectDrawEnabled={false}
|
|
1952
|
-
{...shadowSettings}
|
|
1953
|
-
/>
|
|
1954
|
-
);
|
|
1955
|
-
}, [
|
|
1956
|
-
shadowSettings,
|
|
1957
|
-
frozenColumns,
|
|
1958
|
-
rowStopIndex,
|
|
1959
|
-
rowCount,
|
|
1960
|
-
instanceProps.current.lastMeasuredColumnIndex,
|
|
1961
|
-
instanceProps.current.recalcColumnIndices,
|
|
1962
|
-
]);
|
|
1963
|
-
|
|
1964
|
-
/**
|
|
1965
|
-
* Frozen row shadow
|
|
1966
|
-
*/
|
|
1967
|
-
const frozenRowShadow = useMemo(() => {
|
|
1968
|
-
const frozenRowLineY = getRowOffset(frozenRows);
|
|
1969
|
-
const frozenRowLineX = getColumnOffset(
|
|
1970
|
-
Math.min(columnStopIndex + 1, columnCount)
|
|
1971
|
-
);
|
|
1972
|
-
return (
|
|
1973
|
-
<Line
|
|
1974
|
-
points={[0, frozenRowLineY, frozenRowLineX, frozenRowLineY]}
|
|
1975
|
-
offsetY={-0.5}
|
|
1976
|
-
strokeWidth={1}
|
|
1977
|
-
shadowForStrokeEnabled={false}
|
|
1978
|
-
strokeScaleEnabled={false}
|
|
1979
|
-
hitStrokeWidth={0}
|
|
1980
|
-
listening={false}
|
|
1981
|
-
perfectDrawEnabled={false}
|
|
1982
|
-
{...shadowSettings}
|
|
1983
|
-
/>
|
|
1984
|
-
);
|
|
1985
|
-
}, [
|
|
1986
|
-
shadowSettings,
|
|
1987
|
-
frozenRows,
|
|
1988
|
-
columnStopIndex,
|
|
1989
|
-
columnCount,
|
|
1990
|
-
instanceProps.current.lastMeasuredRowIndex,
|
|
1991
|
-
instanceProps.current.recalcRowIndices,
|
|
1992
|
-
]);
|
|
1993
|
-
|
|
1994
|
-
/* Draw frozen intersection cells */
|
|
1995
|
-
const frozenIntersectionCells = [];
|
|
1996
|
-
const frozenIntersectionCellOverlays = [];
|
|
1997
|
-
for (
|
|
1998
|
-
let rowIndex = 0;
|
|
1999
|
-
rowIndex < Math.min(rowStopIndex, frozenRows);
|
|
2000
|
-
rowIndex++
|
|
2001
|
-
) {
|
|
2002
|
-
if (isHiddenRow?.(rowIndex)) continue;
|
|
2003
|
-
for (
|
|
2004
|
-
let columnIndex = 0;
|
|
2005
|
-
columnIndex < Math.min(columnStopIndex, frozenColumns);
|
|
2006
|
-
columnIndex++
|
|
2007
|
-
) {
|
|
2008
|
-
const isMerged = isMergedCell({ rowIndex, columnIndex });
|
|
2009
|
-
const bounds = getCellBounds({ rowIndex, columnIndex });
|
|
2010
|
-
const actualRowIndex = isMerged ? bounds.top : rowIndex;
|
|
2011
|
-
const actualColumnIndex = isMerged ? bounds.left : columnIndex;
|
|
2012
|
-
const actualBottom = Math.max(rowIndex, bounds.bottom);
|
|
2013
|
-
const actualRight = Math.max(columnIndex, bounds.right);
|
|
2014
|
-
if (!isMerged && isHiddenCell?.(actualRowIndex, actualColumnIndex)) {
|
|
2015
|
-
continue;
|
|
2016
|
-
}
|
|
2017
|
-
if (isMerged) {
|
|
2018
|
-
const cellId = cellIdentifier(bounds.top, bounds.left);
|
|
2019
|
-
if (mergedCellRenderMap.has(cellId)) {
|
|
2020
|
-
continue;
|
|
2021
|
-
}
|
|
2022
|
-
mergedCellRenderMap.add(cellId);
|
|
2023
|
-
}
|
|
2024
|
-
|
|
2025
|
-
const y = getRowOffset(actualRowIndex);
|
|
2026
|
-
const height =
|
|
2027
|
-
getRowOffset(actualBottom) - y + getRowHeight(actualBottom);
|
|
2028
|
-
|
|
2029
|
-
const x = getColumnOffset(actualColumnIndex);
|
|
2030
|
-
|
|
2031
|
-
const width =
|
|
2032
|
-
getColumnOffset(actualRight) - x + getColumnWidth(actualRight);
|
|
2033
|
-
|
|
2034
|
-
frozenIntersectionCells.push(
|
|
2035
|
-
itemRenderer({
|
|
2036
|
-
x,
|
|
2037
|
-
y,
|
|
2038
|
-
width,
|
|
2039
|
-
height,
|
|
2040
|
-
rowIndex: actualRowIndex,
|
|
2041
|
-
columnIndex: actualColumnIndex,
|
|
2042
|
-
isMergedCell: isMerged,
|
|
2043
|
-
key: itemKey({
|
|
2044
|
-
rowIndex: actualRowIndex,
|
|
2045
|
-
columnIndex: actualColumnIndex,
|
|
2046
|
-
}),
|
|
2047
|
-
})
|
|
2048
|
-
);
|
|
2049
|
-
|
|
2050
|
-
if (enableCellOverlay) {
|
|
2051
|
-
frozenIntersectionCellOverlays.push(
|
|
2052
|
-
overlayRenderer({
|
|
2053
|
-
x,
|
|
2054
|
-
y,
|
|
2055
|
-
width,
|
|
2056
|
-
height,
|
|
2057
|
-
rowIndex: actualRowIndex,
|
|
2058
|
-
columnIndex: actualColumnIndex,
|
|
2059
|
-
isMergedCell: isMerged,
|
|
2060
|
-
key: itemKey({
|
|
2061
|
-
rowIndex: actualRowIndex,
|
|
2062
|
-
columnIndex: actualColumnIndex,
|
|
2063
|
-
}),
|
|
2064
|
-
})
|
|
2065
|
-
);
|
|
2066
|
-
}
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
|
|
2070
|
-
/**
|
|
2071
|
-
* Renders active cell
|
|
2072
|
-
*/
|
|
2073
|
-
let fillHandleDimension = {};
|
|
2074
|
-
let activeCellSelection = null;
|
|
2075
|
-
let activeCellSelectionFrozenColumn = null;
|
|
2076
|
-
let activeCellSelectionFrozenRow = null;
|
|
2077
|
-
let activeCellSelectionFrozenIntersection = null;
|
|
2078
|
-
if (activeCell) {
|
|
2079
|
-
const bounds = getCellBounds(activeCell);
|
|
2080
|
-
const { top, left, right, bottom } = bounds;
|
|
2081
|
-
const actualBottom = Math.min(rowStopIndex, bottom);
|
|
2082
|
-
const actualRight = Math.min(columnStopIndex, right);
|
|
2083
|
-
const isInFrozenColumn = left < frozenColumns;
|
|
2084
|
-
const isInFrozenRow = top < frozenRows;
|
|
2085
|
-
const isInFrozenIntersection = isInFrozenRow && isInFrozenColumn;
|
|
2086
|
-
const y = getRowOffset(top);
|
|
2087
|
-
const height =
|
|
2088
|
-
getRowOffset(actualBottom) - y + getRowHeight(actualBottom);
|
|
2089
|
-
|
|
2090
|
-
const x = getColumnOffset(left);
|
|
2091
|
-
|
|
2092
|
-
const width =
|
|
2093
|
-
getColumnOffset(actualRight) - x + getColumnWidth(actualRight);
|
|
2094
|
-
|
|
2095
|
-
const cell = selectionRenderer({
|
|
2096
|
-
stroke: selectionBorderColor,
|
|
2097
|
-
strokeWidth: activeCellStrokeWidth,
|
|
2098
|
-
fill: "transparent",
|
|
2099
|
-
x: x,
|
|
2100
|
-
y: y,
|
|
2101
|
-
width: width,
|
|
2102
|
-
height: height,
|
|
2103
|
-
type: "activeCell",
|
|
2104
|
-
key: 0,
|
|
2105
|
-
activeCell,
|
|
2106
|
-
isDragging: isDraggingSelection,
|
|
2107
|
-
/* Active cell is draggable only there are no other selections */
|
|
2108
|
-
draggable: enableSelectionDrag && !selections.length,
|
|
2109
|
-
});
|
|
2110
|
-
|
|
2111
|
-
if (isInFrozenIntersection) {
|
|
2112
|
-
activeCellSelectionFrozenIntersection = cell;
|
|
2113
|
-
} else if (isInFrozenRow) {
|
|
2114
|
-
activeCellSelectionFrozenRow = cell;
|
|
2115
|
-
} else if (isInFrozenColumn) {
|
|
2116
|
-
activeCellSelectionFrozenColumn = cell;
|
|
2117
|
-
} else {
|
|
2118
|
-
activeCellSelection = cell;
|
|
2119
|
-
}
|
|
2120
|
-
|
|
2121
|
-
fillHandleDimension = {
|
|
2122
|
-
x: x + width,
|
|
2123
|
-
y: y + height,
|
|
2124
|
-
};
|
|
2125
|
-
}
|
|
2126
|
-
|
|
2127
|
-
/**
|
|
2128
|
-
* Convert selections to area
|
|
2129
|
-
* Removed useMemo as changes to lastMeasureRowIndex, lastMeasuredColumnIndex,
|
|
2130
|
-
* does not trigger useMemo
|
|
2131
|
-
* Dependencies : [selections, rowStopIndex, columnStopIndex, instanceProps]
|
|
2132
|
-
*/
|
|
2133
|
-
|
|
2134
|
-
let isSelectionInProgress = false;
|
|
2135
|
-
const selectionAreas = [];
|
|
2136
|
-
const selectionAreasFrozenColumns = [];
|
|
2137
|
-
const selectionAreasFrozenRows = [];
|
|
2138
|
-
const selectionAreasIntersection = [];
|
|
2139
|
-
for (let i = 0; i < selections.length; i++) {
|
|
2140
|
-
const selection = selections[i];
|
|
2141
|
-
const { bounds, inProgress, style } = selection;
|
|
2142
|
-
const { top, left, right, bottom } = bounds;
|
|
2143
|
-
const selectionBounds = { x: 0, y: 0, width: 0, height: 0 };
|
|
2144
|
-
const actualBottom = Math.min(rowStopIndex, bottom);
|
|
2145
|
-
const actualRight = Math.min(columnStopIndex, right);
|
|
2146
|
-
const isLeftBoundFrozen = left < frozenColumns;
|
|
2147
|
-
const isTopBoundFrozen = top < frozenRows;
|
|
2148
|
-
const isIntersectionFrozen = top < frozenRows && left < frozenColumns;
|
|
2149
|
-
const isLast = i === selections.length - 1;
|
|
2150
|
-
const styles = {
|
|
2151
|
-
stroke: inProgress ? selectionBackgroundColor : selectionBorderColor,
|
|
2152
|
-
fill: selectionBackgroundColor,
|
|
2153
|
-
strokeWidth: isDraggingSelection ? 0 : 1,
|
|
2154
|
-
isDragging: isDraggingSelection,
|
|
2155
|
-
draggable: inProgress ? false : enableSelectionDrag,
|
|
2156
|
-
...style,
|
|
2157
|
-
};
|
|
2158
|
-
/**
|
|
2159
|
-
* If selection is in progress,
|
|
2160
|
-
* use this variable to hide fill handle
|
|
2161
|
-
*/
|
|
2162
|
-
if (inProgress) {
|
|
2163
|
-
isSelectionInProgress = true;
|
|
2164
|
-
}
|
|
2165
|
-
selectionBounds.y = getRowOffset(top);
|
|
2166
|
-
selectionBounds.height =
|
|
2167
|
-
getRowOffset(actualBottom) -
|
|
2168
|
-
selectionBounds.y +
|
|
2169
|
-
getRowHeight(actualBottom);
|
|
2170
|
-
|
|
2171
|
-
selectionBounds.x = getColumnOffset(left);
|
|
2172
|
-
|
|
2173
|
-
selectionBounds.width =
|
|
2174
|
-
getColumnOffset(actualRight) -
|
|
2175
|
-
selectionBounds.x +
|
|
2176
|
-
getColumnWidth(actualRight);
|
|
2177
|
-
|
|
2178
|
-
if (isLeftBoundFrozen) {
|
|
2179
|
-
const frozenColumnSelectionWidth =
|
|
2180
|
-
getColumnOffset(Math.min(right + 1, frozenColumns)) -
|
|
2181
|
-
getColumnOffset(left);
|
|
2182
|
-
selectionAreasFrozenColumns.push(
|
|
2183
|
-
selectionRenderer({
|
|
2184
|
-
...styles,
|
|
2185
|
-
type: "selection",
|
|
2186
|
-
key: i,
|
|
2187
|
-
x: selectionBounds.x,
|
|
2188
|
-
y: selectionBounds.y,
|
|
2189
|
-
width: frozenColumnSelectionWidth,
|
|
2190
|
-
height: selectionBounds.height,
|
|
2191
|
-
strokeRightWidth:
|
|
2192
|
-
frozenColumnSelectionWidth === selectionBounds.width &&
|
|
2193
|
-
!isDraggingSelection
|
|
2194
|
-
? selectionStrokeWidth
|
|
2195
|
-
: 0,
|
|
2196
|
-
selection,
|
|
2197
|
-
inProgress,
|
|
2198
|
-
})
|
|
2199
|
-
);
|
|
2200
|
-
}
|
|
2201
|
-
|
|
2202
|
-
if (isTopBoundFrozen) {
|
|
2203
|
-
const frozenRowSelectionHeight =
|
|
2204
|
-
getRowOffset(Math.min(bottom + 1, frozenRows)) - getRowOffset(top);
|
|
2205
|
-
selectionAreasFrozenRows.push(
|
|
2206
|
-
selectionRenderer({
|
|
2207
|
-
...styles,
|
|
2208
|
-
type: "selection",
|
|
2209
|
-
key: i,
|
|
2210
|
-
x: selectionBounds.x,
|
|
2211
|
-
y: selectionBounds.y,
|
|
2212
|
-
width: selectionBounds.width,
|
|
2213
|
-
height: frozenRowSelectionHeight,
|
|
2214
|
-
strokeBottomWidth:
|
|
2215
|
-
frozenRowSelectionHeight === selectionBounds.height &&
|
|
2216
|
-
!isDraggingSelection
|
|
2217
|
-
? selectionStrokeWidth
|
|
2218
|
-
: 0,
|
|
2219
|
-
selection,
|
|
2220
|
-
inProgress,
|
|
2221
|
-
})
|
|
2222
|
-
);
|
|
2223
|
-
}
|
|
2224
|
-
|
|
2225
|
-
if (isIntersectionFrozen) {
|
|
2226
|
-
const frozenIntersectionSelectionHeight =
|
|
2227
|
-
getRowOffset(Math.min(bottom + 1, frozenRows)) - getRowOffset(top);
|
|
2228
|
-
|
|
2229
|
-
const frozenIntersectionSelectionWidth =
|
|
2230
|
-
getColumnOffset(Math.min(right + 1, frozenColumns)) -
|
|
2231
|
-
getColumnOffset(left);
|
|
2232
|
-
|
|
2233
|
-
selectionAreasIntersection.push(
|
|
2234
|
-
selectionRenderer({
|
|
2235
|
-
...styles,
|
|
2236
|
-
type: "selection",
|
|
2237
|
-
key: i,
|
|
2238
|
-
x: selectionBounds.x,
|
|
2239
|
-
y: selectionBounds.y,
|
|
2240
|
-
width: frozenIntersectionSelectionWidth,
|
|
2241
|
-
height: frozenIntersectionSelectionHeight,
|
|
2242
|
-
strokeBottomWidth:
|
|
2243
|
-
frozenIntersectionSelectionHeight === selectionBounds.height &&
|
|
2244
|
-
!isDraggingSelection
|
|
2245
|
-
? selectionStrokeWidth
|
|
2246
|
-
: 0,
|
|
2247
|
-
strokeRightWidth:
|
|
2248
|
-
frozenIntersectionSelectionWidth === selectionBounds.width &&
|
|
2249
|
-
!isDraggingSelection
|
|
2250
|
-
? selectionStrokeWidth
|
|
2251
|
-
: 0,
|
|
2252
|
-
selection,
|
|
2253
|
-
inProgress,
|
|
2254
|
-
})
|
|
2255
|
-
);
|
|
2256
|
-
}
|
|
2257
|
-
selectionAreas.push(
|
|
2258
|
-
selectionRenderer({
|
|
2259
|
-
...styles,
|
|
2260
|
-
type: "selection",
|
|
2261
|
-
key: i,
|
|
2262
|
-
x: selectionBounds.x,
|
|
2263
|
-
y: selectionBounds.y,
|
|
2264
|
-
width: selectionBounds.width,
|
|
2265
|
-
height: selectionBounds.height,
|
|
2266
|
-
selection,
|
|
2267
|
-
inProgress,
|
|
2268
|
-
})
|
|
2269
|
-
);
|
|
2270
|
-
|
|
2271
|
-
if (isLast) {
|
|
2272
|
-
fillHandleDimension = {
|
|
2273
|
-
x: selectionBounds.x + selectionBounds.width,
|
|
2274
|
-
y: selectionBounds.y + selectionBounds.height,
|
|
2275
|
-
};
|
|
2276
|
-
}
|
|
2277
|
-
}
|
|
2278
|
-
|
|
2279
|
-
/**
|
|
2280
|
-
* Fillselection
|
|
2281
|
-
*/
|
|
2282
|
-
let fillSelections = null;
|
|
2283
|
-
if (fillSelection) {
|
|
2284
|
-
const { bounds } = fillSelection;
|
|
2285
|
-
const { top, left, right, bottom } = bounds;
|
|
2286
|
-
const actualBottom = Math.min(rowStopIndex, bottom);
|
|
2287
|
-
const actualRight = Math.min(columnStopIndex, right);
|
|
2288
|
-
const x = getColumnOffset(left);
|
|
2289
|
-
const y = getRowOffset(top);
|
|
2290
|
-
const height =
|
|
2291
|
-
getRowOffset(actualBottom) - y + getRowHeight(actualBottom);
|
|
2292
|
-
const width =
|
|
2293
|
-
getColumnOffset(actualRight) - x + getColumnWidth(actualRight);
|
|
2294
|
-
|
|
2295
|
-
fillSelections = selectionRenderer({
|
|
2296
|
-
type: "fill",
|
|
2297
|
-
x,
|
|
2298
|
-
y,
|
|
2299
|
-
width,
|
|
2300
|
-
height,
|
|
2301
|
-
key: -1,
|
|
2302
|
-
stroke: "gray",
|
|
2303
|
-
strokeStyle: "dashed",
|
|
2304
|
-
});
|
|
2305
|
-
}
|
|
2306
|
-
|
|
2307
|
-
const borderStyleCells = [];
|
|
2308
|
-
const borderStyleCellsFrozenColumns = [];
|
|
2309
|
-
const borderStyleCellsFrozenRows = [];
|
|
2310
|
-
const borderStyleCellsIntersection = [];
|
|
2311
|
-
for (let i = 0; i < borderStyles.length; i++) {
|
|
2312
|
-
const { bounds, style, title, ...rest } = borderStyles[i];
|
|
2313
|
-
const { top, right, bottom, left } = bounds;
|
|
2314
|
-
const isLeftBoundFrozen = left < frozenColumns;
|
|
2315
|
-
const isTopBoundFrozen = top < frozenRows;
|
|
2316
|
-
const isIntersectionFrozen = top < frozenRows && left < frozenColumns;
|
|
2317
|
-
const x = getColumnOffset(left);
|
|
2318
|
-
const y = getRowOffset(top);
|
|
2319
|
-
const width = getColumnOffset(Math.min(columnCount, right + 1)) - x;
|
|
2320
|
-
const height = getRowOffset(Math.min(rowCount, bottom + 1)) - y;
|
|
2321
|
-
|
|
2322
|
-
borderStyleCells.push(
|
|
2323
|
-
createHTMLBox({
|
|
2324
|
-
...rest,
|
|
2325
|
-
...style,
|
|
2326
|
-
x,
|
|
2327
|
-
y,
|
|
2328
|
-
key: i,
|
|
2329
|
-
width,
|
|
2330
|
-
height,
|
|
2331
|
-
type: "border",
|
|
2332
|
-
})
|
|
2333
|
-
);
|
|
2334
|
-
|
|
2335
|
-
if (isLeftBoundFrozen) {
|
|
2336
|
-
const frozenColumnSelectionWidth =
|
|
2337
|
-
getColumnOffset(Math.min(right + 1, frozenColumns)) -
|
|
2338
|
-
getColumnOffset(left);
|
|
2339
|
-
borderStyleCellsFrozenColumns.push(
|
|
2340
|
-
createHTMLBox({
|
|
2341
|
-
...rest,
|
|
2342
|
-
...style,
|
|
2343
|
-
type: "border",
|
|
2344
|
-
x,
|
|
2345
|
-
y,
|
|
2346
|
-
key: i,
|
|
2347
|
-
width: frozenColumnSelectionWidth,
|
|
2348
|
-
height,
|
|
2349
|
-
strokeRightWidth:
|
|
2350
|
-
frozenColumnSelectionWidth === width
|
|
2351
|
-
? style?.strokeRightWidth || style?.strokeWidth
|
|
2352
|
-
: 0,
|
|
2353
|
-
})
|
|
2354
|
-
);
|
|
2355
|
-
}
|
|
2356
|
-
|
|
2357
|
-
if (isTopBoundFrozen) {
|
|
2358
|
-
const frozenRowSelectionHeight =
|
|
2359
|
-
getRowOffset(Math.min(bottom + 1, frozenRows)) - getRowOffset(top);
|
|
2360
|
-
|
|
2361
|
-
borderStyleCellsFrozenRows.push(
|
|
2362
|
-
createHTMLBox({
|
|
2363
|
-
...rest,
|
|
2364
|
-
...style,
|
|
2365
|
-
type: "border",
|
|
2366
|
-
x,
|
|
2367
|
-
y,
|
|
2368
|
-
key: i,
|
|
2369
|
-
width,
|
|
2370
|
-
height: frozenRowSelectionHeight,
|
|
2371
|
-
strokeBottomWidth:
|
|
2372
|
-
frozenRowSelectionHeight === height
|
|
2373
|
-
? style?.strokeBottomWidth || style?.strokeWidth
|
|
2374
|
-
: 0,
|
|
2375
|
-
})
|
|
2376
|
-
);
|
|
2377
|
-
}
|
|
2378
|
-
|
|
2379
|
-
if (isIntersectionFrozen) {
|
|
2380
|
-
const frozenIntersectionSelectionHeight =
|
|
2381
|
-
getRowOffset(Math.min(bottom + 1, frozenRows)) - getRowOffset(top);
|
|
2382
|
-
|
|
2383
|
-
const frozenIntersectionSelectionWidth =
|
|
2384
|
-
getColumnOffset(Math.min(right + 1, frozenColumns)) -
|
|
2385
|
-
getColumnOffset(left);
|
|
2386
|
-
|
|
2387
|
-
borderStyleCellsIntersection.push(
|
|
2388
|
-
createHTMLBox({
|
|
2389
|
-
...rest,
|
|
2390
|
-
...style,
|
|
2391
|
-
type: "border",
|
|
2392
|
-
x,
|
|
2393
|
-
y,
|
|
2394
|
-
key: i,
|
|
2395
|
-
width: frozenIntersectionSelectionWidth,
|
|
2396
|
-
height: frozenIntersectionSelectionHeight,
|
|
2397
|
-
strokeBottomWidth:
|
|
2398
|
-
frozenIntersectionSelectionHeight === height
|
|
2399
|
-
? selectionStrokeWidth
|
|
2400
|
-
: 0,
|
|
2401
|
-
strokeRightWidth:
|
|
2402
|
-
frozenIntersectionSelectionWidth === width
|
|
2403
|
-
? selectionStrokeWidth
|
|
2404
|
-
: 0,
|
|
2405
|
-
})
|
|
2406
|
-
);
|
|
2407
|
-
}
|
|
2408
|
-
}
|
|
2409
|
-
|
|
2410
|
-
/* Spacing for frozen row/column clip */
|
|
2411
|
-
const frozenSpacing = 1;
|
|
2412
|
-
/**
|
|
2413
|
-
* Prevents drawing hit region when scrolling
|
|
2414
|
-
*/
|
|
2415
|
-
const listenToEvents = !isScrolling;
|
|
2416
|
-
/* Frozen row shadow */
|
|
2417
|
-
const frozenRowShadowComponent =
|
|
2418
|
-
showFrozenShadow && frozenRows !== 0 ? frozenRowShadow : null;
|
|
2419
|
-
/* Frozen column shadow */
|
|
2420
|
-
const frozenColumnShadowComponent =
|
|
2421
|
-
showFrozenShadow && frozenColumns !== 0 ? frozenColumnShadow : null;
|
|
2422
|
-
const stageChildren = (
|
|
2423
|
-
<>
|
|
2424
|
-
<Layer>
|
|
2425
|
-
<Group
|
|
2426
|
-
clipX={frozenColumnWidth}
|
|
2427
|
-
clipY={frozenRowHeight}
|
|
2428
|
-
clipWidth={containerWidth - frozenColumnWidth}
|
|
2429
|
-
clipHeight={containerHeight - frozenRowHeight}
|
|
2430
|
-
>
|
|
2431
|
-
<Group offsetY={scrollTop} offsetX={scrollLeft}>
|
|
2432
|
-
{gridLines}
|
|
2433
|
-
{cells}
|
|
2434
|
-
{cellOverlays}
|
|
2435
|
-
{ranges}
|
|
2436
|
-
</Group>
|
|
2437
|
-
</Group>
|
|
2438
|
-
|
|
2439
|
-
<Group
|
|
2440
|
-
clipX={frozenColumnWidth}
|
|
2441
|
-
clipY={0}
|
|
2442
|
-
clipWidth={containerWidth - frozenColumnWidth}
|
|
2443
|
-
clipHeight={frozenRowHeight + frozenSpacing}
|
|
2444
|
-
>
|
|
2445
|
-
<Group offsetY={0} offsetX={scrollLeft}>
|
|
2446
|
-
{gridLinesFrozenRow}
|
|
2447
|
-
{frozenRowCells}
|
|
2448
|
-
{frozenRowShadowComponent}
|
|
2449
|
-
{frozenRowCellOverlays}
|
|
2450
|
-
</Group>
|
|
2451
|
-
</Group>
|
|
2452
|
-
<Group
|
|
2453
|
-
clipX={0}
|
|
2454
|
-
clipY={frozenRowHeight}
|
|
2455
|
-
clipWidth={frozenColumnWidth + frozenSpacing}
|
|
2456
|
-
clipHeight={containerHeight - frozenRowHeight}
|
|
2457
|
-
>
|
|
2458
|
-
<Group offsetY={scrollTop} offsetX={0}>
|
|
2459
|
-
{gridLinesFrozenColumn}
|
|
2460
|
-
{frozenColumnCells}
|
|
2461
|
-
{frozenColumnShadowComponent}
|
|
2462
|
-
{frozenColumnCellOverlays}
|
|
2463
|
-
</Group>
|
|
2464
|
-
</Group>
|
|
2465
|
-
<Group
|
|
2466
|
-
offsetY={0}
|
|
2467
|
-
offsetX={0}
|
|
2468
|
-
clipX={0}
|
|
2469
|
-
clipY={0}
|
|
2470
|
-
clipWidth={frozenColumnWidth + frozenSpacing}
|
|
2471
|
-
clipHeight={frozenRowHeight + frozenSpacing}
|
|
2472
|
-
>
|
|
2473
|
-
{gridLinesFrozenIntersection}
|
|
2474
|
-
{frozenIntersectionCells}
|
|
2475
|
-
{frozenRowShadowComponent}
|
|
2476
|
-
{frozenColumnShadowComponent}
|
|
2477
|
-
{frozenIntersectionCellOverlays}
|
|
2478
|
-
</Group>
|
|
2479
|
-
</Layer>
|
|
2480
|
-
{children && typeof children === "function"
|
|
2481
|
-
? children({
|
|
2482
|
-
scrollLeft,
|
|
2483
|
-
scrollTop,
|
|
2484
|
-
})
|
|
2485
|
-
: null}
|
|
2486
|
-
</>
|
|
2487
|
-
);
|
|
2488
|
-
const fillHandleWidth = 8;
|
|
2489
|
-
const fillhandleComponent =
|
|
2490
|
-
showFillHandle && !isSelectionInProgress ? (
|
|
2491
|
-
<FillHandle
|
|
2492
|
-
{...fillHandleDimension}
|
|
2493
|
-
stroke={selectionBorderColor}
|
|
2494
|
-
size={fillHandleWidth}
|
|
2495
|
-
borderColor={fillhandleBorderColor}
|
|
2496
|
-
{...fillHandleProps}
|
|
2497
|
-
/>
|
|
2498
|
-
) : null;
|
|
2499
|
-
const selectionChildren = (
|
|
2500
|
-
<div
|
|
2501
|
-
style={{
|
|
2502
|
-
pointerEvents: "none",
|
|
2503
|
-
}}
|
|
2504
|
-
>
|
|
2505
|
-
<div
|
|
2506
|
-
style={{
|
|
2507
|
-
position: "absolute",
|
|
2508
|
-
left: frozenColumnWidth,
|
|
2509
|
-
top: frozenRowHeight,
|
|
2510
|
-
right: 0,
|
|
2511
|
-
bottom: 0,
|
|
2512
|
-
overflow: "hidden",
|
|
2513
|
-
}}
|
|
2514
|
-
>
|
|
2515
|
-
<div
|
|
2516
|
-
style={{
|
|
2517
|
-
transform: `translate(-${scrollLeft + frozenColumnWidth}px, -${
|
|
2518
|
-
scrollTop + frozenRowHeight
|
|
2519
|
-
}px)`,
|
|
2520
|
-
}}
|
|
2521
|
-
>
|
|
2522
|
-
{borderStyleCells}
|
|
2523
|
-
{fillSelections}
|
|
2524
|
-
{selectionAreas}
|
|
2525
|
-
{activeCellSelection}
|
|
2526
|
-
{fillhandleComponent}
|
|
2527
|
-
</div>
|
|
2528
|
-
</div>
|
|
2529
|
-
{frozenColumns ? (
|
|
2530
|
-
<div
|
|
2531
|
-
style={{
|
|
2532
|
-
position: "absolute",
|
|
2533
|
-
width: frozenColumnWidth + fillHandleWidth,
|
|
2534
|
-
top: frozenRowHeight,
|
|
2535
|
-
left: 0,
|
|
2536
|
-
bottom: 0,
|
|
2537
|
-
overflow: "hidden",
|
|
2538
|
-
}}
|
|
2539
|
-
>
|
|
2540
|
-
<div
|
|
2541
|
-
style={{
|
|
2542
|
-
transform: `translate(0, -${scrollTop + frozenRowHeight}px)`,
|
|
2543
|
-
}}
|
|
2544
|
-
>
|
|
2545
|
-
{borderStyleCellsFrozenColumns}
|
|
2546
|
-
{selectionAreasFrozenColumns}
|
|
2547
|
-
{activeCellSelectionFrozenColumn}
|
|
2548
|
-
{fillhandleComponent}
|
|
2549
|
-
</div>
|
|
2550
|
-
</div>
|
|
2551
|
-
) : null}
|
|
2552
|
-
{frozenRows ? (
|
|
2553
|
-
<div
|
|
2554
|
-
style={{
|
|
2555
|
-
position: "absolute",
|
|
2556
|
-
height: frozenRowHeight + fillHandleWidth,
|
|
2557
|
-
left: frozenColumnWidth,
|
|
2558
|
-
right: 0,
|
|
2559
|
-
top: 0,
|
|
2560
|
-
overflow: "hidden",
|
|
2561
|
-
}}
|
|
2562
|
-
>
|
|
2563
|
-
<div
|
|
2564
|
-
style={{
|
|
2565
|
-
transform: `translate(-${scrollLeft + frozenColumnWidth}px, 0)`,
|
|
2566
|
-
}}
|
|
2567
|
-
>
|
|
2568
|
-
{borderStyleCellsFrozenRows}
|
|
2569
|
-
{selectionAreasFrozenRows}
|
|
2570
|
-
{activeCellSelectionFrozenRow}
|
|
2571
|
-
{fillhandleComponent}
|
|
2572
|
-
</div>
|
|
2573
|
-
</div>
|
|
2574
|
-
) : null}
|
|
2575
|
-
{frozenRows && frozenColumns ? (
|
|
2576
|
-
<div
|
|
2577
|
-
style={{
|
|
2578
|
-
position: "absolute",
|
|
2579
|
-
height: frozenRowHeight + fillHandleWidth,
|
|
2580
|
-
width: frozenColumnWidth + fillHandleWidth,
|
|
2581
|
-
left: 0,
|
|
2582
|
-
top: 0,
|
|
2583
|
-
overflow: "hidden",
|
|
2584
|
-
pointerEvents: "none",
|
|
2585
|
-
}}
|
|
2586
|
-
>
|
|
2587
|
-
{borderStyleCellsIntersection}
|
|
2588
|
-
{selectionAreasIntersection}
|
|
2589
|
-
{activeCellSelectionFrozenIntersection}
|
|
2590
|
-
{fillhandleComponent}
|
|
2591
|
-
</div>
|
|
2592
|
-
) : null}
|
|
2593
|
-
</div>
|
|
2594
|
-
);
|
|
2595
|
-
return (
|
|
2596
|
-
<div
|
|
2597
|
-
style={{
|
|
2598
|
-
position: "relative",
|
|
2599
|
-
width: containerWidth,
|
|
2600
|
-
userSelect: "none",
|
|
2601
|
-
}}
|
|
2602
|
-
className="rowsncolumns-grid"
|
|
2603
|
-
ref={scrollContainerRef}
|
|
2604
|
-
>
|
|
2605
|
-
<div
|
|
2606
|
-
className="rowsncolumns-grid-container"
|
|
2607
|
-
tabIndex={0}
|
|
2608
|
-
ref={containerRef}
|
|
2609
|
-
{...rest}
|
|
2610
|
-
>
|
|
2611
|
-
<Stage
|
|
2612
|
-
width={containerWidth}
|
|
2613
|
-
height={containerHeight}
|
|
2614
|
-
ref={stageRef}
|
|
2615
|
-
listening={listenToEvents}
|
|
2616
|
-
{...stageProps}
|
|
2617
|
-
>
|
|
2618
|
-
{wrapper(stageChildren)}
|
|
2619
|
-
</Stage>
|
|
2620
|
-
</div>
|
|
2621
|
-
{selectionChildren}
|
|
2622
|
-
{showScrollbar ? (
|
|
2623
|
-
<>
|
|
2624
|
-
<div
|
|
2625
|
-
className="rowsncolumns-grid-scrollbar rowsncolumns-grid-scrollbar-y"
|
|
2626
|
-
tabIndex={-1}
|
|
2627
|
-
style={{
|
|
2628
|
-
height: containerHeight,
|
|
2629
|
-
overflow: "scroll",
|
|
2630
|
-
position: "absolute",
|
|
2631
|
-
right: 0,
|
|
2632
|
-
top: 0,
|
|
2633
|
-
width: scrollbarSize,
|
|
2634
|
-
willChange: "transform",
|
|
2635
|
-
}}
|
|
2636
|
-
onScroll={handleScroll}
|
|
2637
|
-
ref={verticalScrollRef}
|
|
2638
|
-
>
|
|
2639
|
-
<div
|
|
2640
|
-
style={{
|
|
2641
|
-
position: "absolute",
|
|
2642
|
-
height: estimatedTotalHeight,
|
|
2643
|
-
width: 1,
|
|
2644
|
-
}}
|
|
2645
|
-
/>
|
|
2646
|
-
</div>
|
|
2647
|
-
<div
|
|
2648
|
-
className="rowsncolumns-grid-scrollbar rowsncolumns-grid-scrollbar-x"
|
|
2649
|
-
tabIndex={-1}
|
|
2650
|
-
style={{
|
|
2651
|
-
overflow: "scroll",
|
|
2652
|
-
position: "absolute",
|
|
2653
|
-
bottom: 0,
|
|
2654
|
-
left: 0,
|
|
2655
|
-
width: containerWidth,
|
|
2656
|
-
height: scrollbarSize,
|
|
2657
|
-
willChange: "transform",
|
|
2658
|
-
}}
|
|
2659
|
-
onScroll={handleScrollLeft}
|
|
2660
|
-
ref={horizontalScrollRef}
|
|
2661
|
-
>
|
|
2662
|
-
<div
|
|
2663
|
-
style={{
|
|
2664
|
-
position: "absolute",
|
|
2665
|
-
width: estimatedTotalWidth,
|
|
2666
|
-
height: 1,
|
|
2667
|
-
}}
|
|
2668
|
-
/>
|
|
2669
|
-
</div>
|
|
2670
|
-
</>
|
|
2671
|
-
) : null}
|
|
2672
|
-
</div>
|
|
2673
|
-
);
|
|
2674
|
-
})
|
|
2675
|
-
);
|
|
2676
|
-
|
|
2677
|
-
export default Grid;
|