@vuu-ui/vuu-table 2.1.19-beta.1 → 2.1.19-beta.2

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.
Files changed (85) hide show
  1. package/package.json +12 -13
  2. package/src/CellFocusState.mjs +25 -0
  3. package/src/Row.mjs +83 -0
  4. package/src/Table.css.js +441 -0
  5. package/src/Table.mjs +297 -0
  6. package/src/VirtualColSpan.mjs +12 -0
  7. package/src/applyHighlighting.mjs +28 -0
  8. package/src/bulk-edit/BulkEditPanel.css.js +27 -0
  9. package/src/bulk-edit/BulkEditPanel.mjs +77 -0
  10. package/src/bulk-edit/ColumnCascadingUpdateEditor.css.js +86 -0
  11. package/src/bulk-edit/ColumnCascadingUpdateEditor.mjs +59 -0
  12. package/src/bulk-edit/InsertNewRowEditor.css.js +86 -0
  13. package/src/bulk-edit/InsertNewRowEditor.mjs +59 -0
  14. package/src/bulk-edit/useBulkEditPanel.mjs +61 -0
  15. package/src/bulk-edit/useColumnCascadingEditor.mjs +124 -0
  16. package/src/cell-block/CellBlock.css.js +95 -0
  17. package/src/cell-block/CellBlock.mjs +32 -0
  18. package/src/cell-block/cellblock-utils.mjs +114 -0
  19. package/src/cell-block/useCellBlockSelection.mjs +245 -0
  20. package/src/cell-renderers/checkbox-cell/CheckboxCell.css.js +16 -0
  21. package/src/cell-renderers/checkbox-cell/CheckboxCell.mjs +56 -0
  22. package/src/cell-renderers/checkbox-cell/index.mjs +1 -0
  23. package/src/cell-renderers/checkbox-row-selector/CheckboxRowSelectorCell.css.js +19 -0
  24. package/src/cell-renderers/checkbox-row-selector/CheckboxRowSelectorCell.mjs +34 -0
  25. package/src/cell-renderers/checkbox-row-selector/index.mjs +1 -0
  26. package/src/cell-renderers/index.mjs +4 -0
  27. package/src/cell-renderers/input-cell/InputCell.css.js +81 -0
  28. package/src/cell-renderers/input-cell/InputCell.mjs +73 -0
  29. package/src/cell-renderers/input-cell/index.mjs +1 -0
  30. package/src/cell-renderers/input-cell/useInputCell.mjs +199 -0
  31. package/src/cell-renderers/toggle-cell/ToggleCell.css.js +31 -0
  32. package/src/cell-renderers/toggle-cell/ToggleCell.mjs +47 -0
  33. package/src/cell-renderers/toggle-cell/index.mjs +1 -0
  34. package/src/column-header-pill/ColumnHeaderPill.css.js +34 -0
  35. package/src/column-header-pill/ColumnHeaderPill.mjs +39 -0
  36. package/src/column-header-pill/GroupColumnPill.css.js +10 -0
  37. package/src/column-header-pill/GroupColumnPill.mjs +33 -0
  38. package/src/column-header-pill/SortIndicator.css.js +15 -0
  39. package/src/column-header-pill/SortIndicator.mjs +29 -0
  40. package/src/column-header-pill/index.mjs +3 -0
  41. package/src/column-resizing/ColumnResizer.css.js +32 -0
  42. package/src/column-resizing/ColumnResizer.mjs +69 -0
  43. package/src/column-resizing/index.mjs +2 -0
  44. package/src/column-resizing/useTableColumnResize.mjs +57 -0
  45. package/src/data-row/DataRow.mjs +298 -0
  46. package/src/header-cell/GroupHeaderCell.css.js +91 -0
  47. package/src/header-cell/GroupHeaderCell.mjs +98 -0
  48. package/src/header-cell/HeaderCell.css.js +182 -0
  49. package/src/header-cell/HeaderCell.mjs +126 -0
  50. package/src/header-cell/index.mjs +2 -0
  51. package/src/index.mjs +20 -0
  52. package/src/pagination/PaginationControl.css.js +18 -0
  53. package/src/pagination/PaginationControl.mjs +34 -0
  54. package/src/pagination/index.mjs +1 -0
  55. package/src/pagination/usePagination.mjs +29 -0
  56. package/src/table-cell/TableCell.css.js +67 -0
  57. package/src/table-cell/TableCell.mjs +54 -0
  58. package/src/table-cell/TableGroupCell.css.js +91 -0
  59. package/src/table-cell/TableGroupCell.mjs +61 -0
  60. package/src/table-cell/index.mjs +2 -0
  61. package/src/table-config/useTableConfig.mjs +49 -0
  62. package/src/table-config.mjs +38 -0
  63. package/src/table-data-source/DataRowMovingWindow.mjs +66 -0
  64. package/src/table-data-source/useDataSource.mjs +177 -0
  65. package/src/table-dom-utils.mjs +162 -0
  66. package/src/table-header/HeaderProvider.mjs +14 -0
  67. package/src/table-header/TableHeader.mjs +182 -0
  68. package/src/table-header/index.mjs +2 -0
  69. package/src/table-header/useTableHeader.mjs +69 -0
  70. package/src/useCell.mjs +22 -0
  71. package/src/useCellEditing.mjs +58 -0
  72. package/src/useCellFocus.mjs +112 -0
  73. package/src/useControlledTableNavigation.mjs +34 -0
  74. package/src/useEditableCell.mjs +18 -0
  75. package/src/useInitialValue.mjs +6 -0
  76. package/src/useKeyboardNavigation.mjs +275 -0
  77. package/src/useMeasuredHeight.mjs +44 -0
  78. package/src/useResizeObserver.mjs +118 -0
  79. package/src/useRowClassNameGenerators.mjs +21 -0
  80. package/src/useSelection.mjs +101 -0
  81. package/src/useTable.mjs +588 -0
  82. package/src/useTableContextMenu.mjs +54 -0
  83. package/src/useTableModel.mjs +344 -0
  84. package/src/useTableScroll.mjs +382 -0
  85. package/src/useTableViewport.mjs +120 -0
@@ -0,0 +1,382 @@
1
+ import { getColumnsInViewport, itemsChanged } from "@vuu-ui/vuu-utils";
2
+ import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
3
+ import { getRowElementByAriaIndex, howFarIsRowOutsideViewport } from "./table-dom-utils.mjs";
4
+ const SCROLL_MOVE_CHECK_THRESHOLD = 100;
5
+ const HORIZONTAL_SCROLL_BUFFER = 200;
6
+ const getMaxScroll = (container)=>{
7
+ const { clientHeight, clientWidth, scrollHeight, scrollWidth } = container;
8
+ return [
9
+ scrollWidth - clientWidth,
10
+ scrollHeight - clientHeight
11
+ ];
12
+ };
13
+ const getPctScroll = (container)=>{
14
+ const { clientHeight, clientWidth, scrollHeight, scrollLeft, scrollTop, scrollWidth } = container;
15
+ const maxScrollLeft = scrollWidth - clientWidth;
16
+ const pctScrollLeft = scrollLeft / (scrollWidth - clientWidth);
17
+ const maxScrollTop = scrollHeight - clientHeight;
18
+ const pctScrollTop = scrollTop / (scrollHeight - clientHeight);
19
+ return [
20
+ scrollLeft,
21
+ pctScrollLeft,
22
+ maxScrollLeft,
23
+ scrollTop,
24
+ pctScrollTop,
25
+ maxScrollTop
26
+ ];
27
+ };
28
+ const noScrolling = {
29
+ scrollToIndex: ()=>void 0,
30
+ scrollToKey: ()=>void 0
31
+ };
32
+ const useCallbackRef = ({ onAttach, onDetach })=>{
33
+ const ref = useRef(null);
34
+ const callbackRef = useCallback((el)=>{
35
+ if (el) {
36
+ ref.current = el;
37
+ onAttach?.(el);
38
+ } else if (ref.current) {
39
+ const { current: originalRef } = ref;
40
+ ref.current = el;
41
+ onDetach?.(originalRef);
42
+ }
43
+ }, [
44
+ onAttach,
45
+ onDetach
46
+ ]);
47
+ return callbackRef;
48
+ };
49
+ const useTableScroll = ({ cellFocusStateRef, columns, getRowAtPosition, onHorizontalScroll, onVerticalScroll, onVerticalScrollInSitu, rowHeight, scrollingApiRef, setRange, viewportMeasurements })=>{
50
+ const firstRowRef = useRef(0);
51
+ const rowHeightRef = useRef(rowHeight);
52
+ const contentContainerScrolledRef = useRef(false);
53
+ const contentContainerPosRef = useRef({
54
+ scrollTop: 0,
55
+ scrollLeft: 0
56
+ });
57
+ const scrollbarContainerScrolledRef = useRef(false);
58
+ const scrollbarContainerPosRef = useRef({
59
+ scrollTop: 0,
60
+ scrollLeft: 0
61
+ });
62
+ const scrollbarContainerRef = useRef(null);
63
+ const contentContainerRef = useRef(null);
64
+ const lastHorizontalScrollCheckPoint = useRef(0);
65
+ const { appliedPageSize, isVirtualScroll, rowCount: viewportRowCount, totalHeaderHeight, usesMeasuredHeaderHeight, viewportBodyHeight, viewportWidth } = viewportMeasurements;
66
+ const columnsWithinViewportRef = useRef([]);
67
+ const [, forceRefresh] = useState({});
68
+ const preSpanRef = useRef(0);
69
+ useMemo(()=>{
70
+ const [visibleColumns, offset] = getColumnsInViewport(columns, contentContainerPosRef.current.scrollLeft, contentContainerPosRef.current.scrollLeft + viewportWidth + HORIZONTAL_SCROLL_BUFFER);
71
+ preSpanRef.current = offset;
72
+ columnsWithinViewportRef.current = visibleColumns;
73
+ }, [
74
+ viewportWidth,
75
+ columns
76
+ ]);
77
+ const handleHorizontalScroll = useCallback((scrollLeft)=>{
78
+ contentContainerPosRef.current.scrollLeft = scrollLeft;
79
+ onHorizontalScroll?.(scrollLeft);
80
+ if (Math.abs(scrollLeft - lastHorizontalScrollCheckPoint.current) > SCROLL_MOVE_CHECK_THRESHOLD) {
81
+ lastHorizontalScrollCheckPoint.current = scrollLeft;
82
+ const [visibleColumns, pre] = getColumnsInViewport(columns, scrollLeft, scrollLeft + viewportWidth + HORIZONTAL_SCROLL_BUFFER);
83
+ if (itemsChanged(columnsWithinViewportRef.current, visibleColumns)) {
84
+ preSpanRef.current = pre;
85
+ columnsWithinViewportRef.current = visibleColumns;
86
+ forceRefresh({});
87
+ }
88
+ }
89
+ }, [
90
+ columns,
91
+ onHorizontalScroll,
92
+ viewportWidth
93
+ ]);
94
+ const handleVerticalScroll = useCallback((scrollTop, pctScrollTop)=>{
95
+ contentContainerPosRef.current.scrollTop = scrollTop;
96
+ const { current: prevFirstRow } = firstRowRef;
97
+ onVerticalScroll?.(scrollTop, pctScrollTop);
98
+ const firstRow = getRowAtPosition(scrollTop);
99
+ if (firstRow !== prevFirstRow) {
100
+ firstRowRef.current = firstRow;
101
+ const lastRow = firstRow + viewportRowCount;
102
+ setRange({
103
+ from: firstRow,
104
+ to: lastRow
105
+ });
106
+ const { current: focusState } = cellFocusStateRef;
107
+ if (focusState.cellPos) {
108
+ const prevLastRow = prevFirstRow + viewportRowCount;
109
+ const [row] = focusState.cellPos;
110
+ const wasInViewport = row >= prevFirstRow && row < prevLastRow;
111
+ const isInViewport = row >= firstRow && row < lastRow;
112
+ if (wasInViewport && !isInViewport) {
113
+ focusState.placeholderEl?.focus({
114
+ preventScroll: true
115
+ });
116
+ focusState.outsideViewport = row < firstRow ? "above" : "below";
117
+ } else if (isInViewport && !wasInViewport) focusState.outsideViewport = false;
118
+ }
119
+ }
120
+ onVerticalScrollInSitu?.(0);
121
+ }, [
122
+ cellFocusStateRef,
123
+ getRowAtPosition,
124
+ onVerticalScroll,
125
+ onVerticalScrollInSitu,
126
+ setRange,
127
+ viewportRowCount
128
+ ]);
129
+ const scrollTimerRef = useRef(null);
130
+ const checkScrollbarScrollPosition = useCallback(()=>{
131
+ const { current: scrollPos } = scrollbarContainerPosRef;
132
+ const { current: contentContainer } = contentContainerRef;
133
+ const { current: scrollbarContainer } = scrollbarContainerRef;
134
+ if (scrollbarContainer && contentContainer) {
135
+ const [scrollLeft, pctScrollLeft, , scrollTop, pctScrollTop] = getPctScroll(scrollbarContainer);
136
+ if (scrollLeft !== scrollPos.scrollLeft || scrollTop !== scrollPos.scrollTop) {
137
+ scrollbarContainerScrolledRef.current = true;
138
+ scrollPos.scrollLeft = scrollLeft;
139
+ scrollPos.scrollTop = scrollTop;
140
+ const [maxScrollLeft, maxScrollTop] = getMaxScroll(scrollbarContainer);
141
+ const contentScrollLeft = Math.round(pctScrollLeft * maxScrollLeft);
142
+ const contentScrollTop = pctScrollTop * maxScrollTop;
143
+ contentContainer.scrollTo({
144
+ left: contentScrollLeft,
145
+ top: contentScrollTop,
146
+ behavior: "auto"
147
+ });
148
+ }
149
+ scrollTimerRef.current = null;
150
+ }
151
+ }, []);
152
+ const handleScrollbarContainerScroll = useCallback(()=>{
153
+ const { current: contentContainer } = contentContainerRef;
154
+ const { current: scrollbarContainer } = scrollbarContainerRef;
155
+ const { current: contentContainerScrolled } = contentContainerScrolledRef;
156
+ const { current: scrollPos } = scrollbarContainerPosRef;
157
+ if (contentContainerScrolled) contentContainerScrolledRef.current = false;
158
+ else if (contentContainer && scrollbarContainer) {
159
+ scrollbarContainerScrolledRef.current = true;
160
+ const [scrollLeft, pctScrollLeft, , scrollTop, pctScrollTop] = getPctScroll(scrollbarContainer);
161
+ scrollPos.scrollLeft = scrollLeft;
162
+ scrollPos.scrollTop = scrollTop;
163
+ const [maxScrollLeft, maxScrollTop] = getMaxScroll(scrollbarContainer);
164
+ const contentScrollLeft = Math.round(pctScrollLeft * maxScrollLeft);
165
+ const contentScrollTop = pctScrollTop * maxScrollTop;
166
+ contentContainer.scrollTo({
167
+ left: contentScrollLeft,
168
+ top: contentScrollTop,
169
+ behavior: "auto"
170
+ });
171
+ }
172
+ if (scrollTimerRef.current) clearTimeout(scrollTimerRef.current);
173
+ scrollTimerRef.current = setTimeout(checkScrollbarScrollPosition, 60);
174
+ onVerticalScrollInSitu?.(0);
175
+ }, [
176
+ checkScrollbarScrollPosition,
177
+ onVerticalScrollInSitu
178
+ ]);
179
+ const handleContentContainerScroll = useCallback(()=>{
180
+ const { current: scrollbarContainerScrolled } = scrollbarContainerScrolledRef;
181
+ const { current: contentContainer } = contentContainerRef;
182
+ const { current: scrollbarContainer } = scrollbarContainerRef;
183
+ const { current: scrollPos } = contentContainerPosRef;
184
+ if (contentContainer && scrollbarContainer) {
185
+ const [scrollLeft, pctScrollLeft, maxScrollLeft, scrollTop, pctScrollTop, maxScrollTop] = getPctScroll(contentContainer);
186
+ contentContainerScrolledRef.current = true;
187
+ if (scrollbarContainerScrolled) scrollbarContainerScrolledRef.current = false;
188
+ else {
189
+ scrollbarContainer.scrollLeft = Math.round(pctScrollLeft * maxScrollLeft);
190
+ scrollbarContainer.scrollTop = pctScrollTop * maxScrollTop;
191
+ }
192
+ if (scrollPos.scrollTop !== scrollTop) handleVerticalScroll(scrollTop, pctScrollTop);
193
+ if (scrollPos.scrollLeft !== scrollLeft) handleHorizontalScroll(scrollLeft);
194
+ }
195
+ }, [
196
+ handleVerticalScroll,
197
+ handleHorizontalScroll
198
+ ]);
199
+ const handleAttachScrollbarContainer = useCallback((el)=>{
200
+ scrollbarContainerRef.current = el;
201
+ el.addEventListener("scroll", handleScrollbarContainerScroll, {
202
+ passive: true
203
+ });
204
+ }, [
205
+ handleScrollbarContainerScroll
206
+ ]);
207
+ const handleDetachScrollbarContainer = useCallback((el)=>{
208
+ scrollbarContainerRef.current = null;
209
+ el.removeEventListener("scroll", handleScrollbarContainerScroll);
210
+ }, [
211
+ handleScrollbarContainerScroll
212
+ ]);
213
+ const handleAttachContentContainer = useCallback((el)=>{
214
+ contentContainerRef.current = el;
215
+ el.addEventListener("scroll", handleContentContainerScroll, {
216
+ passive: true
217
+ });
218
+ }, [
219
+ handleContentContainerScroll
220
+ ]);
221
+ const handleDetachContentContainer = useCallback((el)=>{
222
+ contentContainerRef.current = null;
223
+ el.removeEventListener("scroll", handleContentContainerScroll);
224
+ }, [
225
+ handleContentContainerScroll
226
+ ]);
227
+ const contentContainerCallbackRef = useCallbackRef({
228
+ onAttach: handleAttachContentContainer,
229
+ onDetach: handleDetachContentContainer
230
+ });
231
+ const scrollbarContainerCallbackRef = useCallbackRef({
232
+ onAttach: handleAttachScrollbarContainer,
233
+ onDetach: handleDetachScrollbarContainer
234
+ });
235
+ const requestScroll = useCallback((scrollRequest)=>{
236
+ const { current: contentContainer } = contentContainerRef;
237
+ const { current: scrollbarContainer } = scrollbarContainerRef;
238
+ if (contentContainer) {
239
+ const [maxScrollLeft, maxScrollTop] = getMaxScroll(contentContainer);
240
+ const { scrollLeft, scrollTop } = contentContainer;
241
+ contentContainerScrolledRef.current = false;
242
+ switch(scrollRequest.type){
243
+ case "scroll-top":
244
+ if (scrollRequest.instant && 0 === scrollRequest.scrollPos && scrollbarContainer) {
245
+ contentContainer.scrollTop = 0;
246
+ scrollbarContainer.scrollTop = 0;
247
+ } else contentContainer.scrollTo({
248
+ top: scrollRequest.scrollPos,
249
+ left: scrollLeft,
250
+ behavior: "instant"
251
+ });
252
+ break;
253
+ case "scroll-bottom":
254
+ contentContainer.scrollTo({
255
+ top: scrollRequest.scrollPos - (viewportBodyHeight - 2 * rowHeight),
256
+ left: scrollLeft,
257
+ behavior: "instant"
258
+ });
259
+ break;
260
+ case "scroll-row":
261
+ {
262
+ const activeRow = getRowElementByAriaIndex(contentContainer, scrollRequest.rowIndex);
263
+ if (null !== activeRow) {
264
+ const [direction, distance] = howFarIsRowOutsideViewport(activeRow, totalHeaderHeight);
265
+ if (direction && distance) if (isVirtualScroll) {
266
+ const offset = "down" === direction ? 1 : -1;
267
+ onVerticalScrollInSitu?.(offset);
268
+ const firstRow = firstRowRef.current + offset;
269
+ firstRowRef.current = firstRow;
270
+ setRange({
271
+ from: firstRow,
272
+ to: firstRow + viewportRowCount
273
+ });
274
+ } else {
275
+ let newScrollLeft = scrollLeft;
276
+ let newScrollTop = scrollTop;
277
+ if ("up" === direction || "down" === direction) newScrollTop = Math.min(Math.max(0, scrollTop + distance), maxScrollTop);
278
+ else newScrollLeft = Math.min(Math.max(0, scrollLeft + distance), maxScrollLeft);
279
+ contentContainer.scrollTo({
280
+ top: newScrollTop,
281
+ left: newScrollLeft,
282
+ behavior: "instant"
283
+ });
284
+ }
285
+ }
286
+ }
287
+ break;
288
+ case "scroll-page":
289
+ {
290
+ const { direction } = scrollRequest;
291
+ if (isVirtualScroll) {
292
+ const offset = "down" === direction ? viewportRowCount : -viewportRowCount;
293
+ onVerticalScrollInSitu?.(offset);
294
+ const firstRow = firstRowRef.current + offset;
295
+ firstRowRef.current = firstRow;
296
+ setRange({
297
+ from: firstRow,
298
+ to: firstRow + viewportRowCount
299
+ });
300
+ } else {
301
+ const scrollBy = "down" === direction ? appliedPageSize : -appliedPageSize;
302
+ const newScrollTop = Math.min(Math.max(0, scrollTop + scrollBy), maxScrollTop);
303
+ contentContainer.scrollTo({
304
+ top: newScrollTop,
305
+ left: scrollLeft,
306
+ behavior: "auto"
307
+ });
308
+ }
309
+ }
310
+ break;
311
+ case "scroll-end":
312
+ {
313
+ const { direction } = scrollRequest;
314
+ const scrollTo = "end" === direction ? maxScrollTop : 0;
315
+ contentContainer.scrollTo({
316
+ top: scrollTo,
317
+ left: contentContainer.scrollLeft,
318
+ behavior: "auto"
319
+ });
320
+ }
321
+ break;
322
+ default:
323
+ console.warn(`unexpected scroll request ${scrollRequest["type"]}`);
324
+ }
325
+ }
326
+ }, [
327
+ appliedPageSize,
328
+ isVirtualScroll,
329
+ onVerticalScrollInSitu,
330
+ rowHeight,
331
+ setRange,
332
+ totalHeaderHeight,
333
+ viewportBodyHeight,
334
+ viewportRowCount
335
+ ]);
336
+ const scrollHandles = useMemo(()=>({
337
+ scrollToIndex: (rowIndex)=>{
338
+ if (scrollbarContainerRef.current) {
339
+ const scrollPos = (rowIndex - 30) * 20;
340
+ scrollbarContainerRef.current.scrollTop = scrollPos;
341
+ }
342
+ },
343
+ scrollToKey: (rowKey)=>{
344
+ console.log(`scrollToKey ${rowKey}`);
345
+ }
346
+ }), []);
347
+ useImperativeHandle(scrollingApiRef, ()=>{
348
+ if (scrollbarContainerRef.current) return scrollHandles;
349
+ return noScrolling;
350
+ }, [
351
+ scrollHandles
352
+ ]);
353
+ useEffect(()=>{
354
+ if (rowHeight !== rowHeightRef.current) {
355
+ rowHeightRef.current = rowHeight;
356
+ if (contentContainerPosRef.current.scrollTop > 0) {
357
+ if (contentContainerRef.current) contentContainerRef.current.scrollTop = 0;
358
+ }
359
+ } else if (usesMeasuredHeaderHeight) {
360
+ const { current: from } = firstRowRef;
361
+ const rowRange = {
362
+ from,
363
+ to: from + viewportRowCount
364
+ };
365
+ setRange(rowRange);
366
+ }
367
+ }, [
368
+ rowHeight,
369
+ setRange,
370
+ usesMeasuredHeaderHeight,
371
+ viewportRowCount
372
+ ]);
373
+ return {
374
+ columnsWithinViewport: columnsWithinViewportRef.current,
375
+ scrollbarContainerRef: scrollbarContainerCallbackRef,
376
+ contentContainerRef: contentContainerCallbackRef,
377
+ requestScroll,
378
+ scrollTop: contentContainerPosRef.current.scrollTop,
379
+ virtualColSpan: preSpanRef.current
380
+ };
381
+ };
382
+ export { noScrolling, useTableScroll };
@@ -0,0 +1,120 @@
1
+ import { actualRowPositioning, measurePinnedColumns, virtualRowPositioning } from "@vuu-ui/vuu-utils";
2
+ import { useCallback, useMemo, useRef } from "react";
3
+ const MAX_PIXEL_HEIGHT = 10000000;
4
+ const UNMEASURED_VIEWPORT = {
5
+ appliedPageSize: 0,
6
+ contentHeight: 0,
7
+ contentWidth: 0,
8
+ getRowAtPosition: ()=>-1,
9
+ getRowOffset: ()=>-1,
10
+ horizontalScrollbarHeight: 0,
11
+ isVirtualScroll: false,
12
+ pinnedWidthLeft: 0,
13
+ pinnedWidthRight: 0,
14
+ rowCount: 0,
15
+ setInSituRowOffset: ()=>void 0,
16
+ setScrollTop: ()=>void 0,
17
+ totalHeaderHeight: 0,
18
+ usesMeasuredHeaderHeight: false,
19
+ verticalScrollbarWidth: 0,
20
+ viewportBodyHeight: 0,
21
+ viewportWidth: 0
22
+ };
23
+ const getViewportHeightProps = (rowCount, rowHeight, size, showPaginationControls = false)=>{
24
+ if (showPaginationControls) return {
25
+ pixelContentHeight: size.height,
26
+ virtualContentHeight: size.height,
27
+ virtualisedExtent: 0
28
+ };
29
+ {
30
+ const virtualContentHeight = rowCount * rowHeight;
31
+ const pixelContentHeight = Math.min(virtualContentHeight, MAX_PIXEL_HEIGHT);
32
+ const virtualisedExtent = virtualContentHeight - pixelContentHeight;
33
+ return {
34
+ pixelContentHeight,
35
+ virtualContentHeight,
36
+ virtualisedExtent
37
+ };
38
+ }
39
+ };
40
+ const useTableViewport = ({ columns, headerHeight, rowCount, rowHeight, selectionEndSize = 4, showPaginationControls, size })=>{
41
+ const inSituRowOffsetRef = useRef(0);
42
+ const pctScrollTopRef = useRef(0);
43
+ const { virtualContentHeight, pixelContentHeight, virtualisedExtent } = getViewportHeightProps(rowCount, rowHeight, size, showPaginationControls);
44
+ const { pinnedWidthLeft, pinnedWidthRight, unpinnedWidth } = useMemo(()=>measurePinnedColumns(columns, selectionEndSize), [
45
+ columns,
46
+ selectionEndSize
47
+ ]);
48
+ const [getRowOffset, getRowAtPosition, isVirtualScroll] = useMemo(()=>{
49
+ if (!virtualisedExtent) return actualRowPositioning(rowHeight);
50
+ {
51
+ const [_getRowOffset, getRowAtPosition, _isVirtual] = virtualRowPositioning(rowHeight, virtualisedExtent, pctScrollTopRef);
52
+ const getOffset = (dataRow)=>_getRowOffset(dataRow, inSituRowOffsetRef.current);
53
+ return [
54
+ getOffset,
55
+ getRowAtPosition,
56
+ _isVirtual
57
+ ];
58
+ }
59
+ }, [
60
+ virtualisedExtent,
61
+ rowHeight
62
+ ]);
63
+ const setScrollTop = useCallback((_, scrollPct)=>{
64
+ pctScrollTopRef.current = scrollPct;
65
+ }, []);
66
+ const setInSituRowOffset = useCallback((rowIndexOffset)=>{
67
+ if (0 === rowIndexOffset) inSituRowOffsetRef.current = 0;
68
+ else inSituRowOffsetRef.current = Math.max(0, inSituRowOffsetRef.current + rowIndexOffset);
69
+ }, []);
70
+ return useMemo(()=>{
71
+ if (!size) return UNMEASURED_VIEWPORT;
72
+ {
73
+ const scrollbarSize = 10;
74
+ const contentWidth = pinnedWidthLeft + unpinnedWidth + pinnedWidthRight;
75
+ const horizontalScrollbarHeight = contentWidth > size.width ? scrollbarSize : 0;
76
+ const measuredHeaderHeight = -1 === headerHeight ? 0 : headerHeight;
77
+ const visibleRows = showPaginationControls ? Math.floor((pixelContentHeight - headerHeight) / rowHeight) : (size.height - headerHeight) / rowHeight;
78
+ const count = Number.isInteger(visibleRows) ? visibleRows : Math.ceil(visibleRows);
79
+ const viewportBodyHeight = size.height - measuredHeaderHeight;
80
+ const verticalScrollbarWidth = showPaginationControls ? 0 : pixelContentHeight > viewportBodyHeight ? scrollbarSize : 0;
81
+ const appliedPageSize = count * rowHeight * (pixelContentHeight / virtualContentHeight);
82
+ const viewportWidth = size.width;
83
+ return {
84
+ usesMeasuredHeaderHeight: -1 !== headerHeight,
85
+ appliedPageSize,
86
+ contentHeight: pixelContentHeight,
87
+ contentWidth,
88
+ getRowAtPosition,
89
+ getRowOffset,
90
+ isVirtualScroll,
91
+ horizontalScrollbarHeight,
92
+ pinnedWidthLeft,
93
+ pinnedWidthRight,
94
+ rowCount: count,
95
+ setInSituRowOffset,
96
+ setScrollTop,
97
+ totalHeaderHeight: headerHeight,
98
+ verticalScrollbarWidth,
99
+ viewportBodyHeight,
100
+ viewportWidth
101
+ };
102
+ }
103
+ }, [
104
+ size,
105
+ pinnedWidthLeft,
106
+ unpinnedWidth,
107
+ pinnedWidthRight,
108
+ headerHeight,
109
+ rowHeight,
110
+ showPaginationControls,
111
+ pixelContentHeight,
112
+ virtualContentHeight,
113
+ getRowAtPosition,
114
+ getRowOffset,
115
+ isVirtualScroll,
116
+ setInSituRowOffset,
117
+ setScrollTop
118
+ ]);
119
+ };
120
+ export { useTableViewport };