@mui/x-virtualizer 0.1.0
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/CHANGELOG.md +10645 -0
- package/README.md +3 -0
- package/esm/features/colspan.d.ts +28 -0
- package/esm/features/colspan.js +88 -0
- package/esm/features/dimensions.d.ts +41 -0
- package/esm/features/dimensions.js +465 -0
- package/esm/features/index.d.ts +5 -0
- package/esm/features/index.js +5 -0
- package/esm/features/keyboard.d.ts +16 -0
- package/esm/features/keyboard.js +35 -0
- package/esm/features/rowspan.d.ts +25 -0
- package/esm/features/rowspan.js +36 -0
- package/esm/features/virtualization.d.ts +103 -0
- package/esm/features/virtualization.js +844 -0
- package/esm/index.d.ts +2 -0
- package/esm/index.js +9 -0
- package/esm/models/colspan.d.ts +13 -0
- package/esm/models/colspan.js +1 -0
- package/esm/models/core.d.ts +72 -0
- package/esm/models/core.js +43 -0
- package/esm/models/dimensions.d.ts +132 -0
- package/esm/models/dimensions.js +1 -0
- package/esm/models/index.d.ts +4 -0
- package/esm/models/index.js +4 -0
- package/esm/models/rowspan.d.ts +17 -0
- package/esm/models/rowspan.js +1 -0
- package/esm/package.json +1 -0
- package/esm/useVirtualizer.d.ts +193 -0
- package/esm/useVirtualizer.js +26 -0
- package/features/colspan.d.ts +28 -0
- package/features/colspan.js +94 -0
- package/features/dimensions.d.ts +41 -0
- package/features/dimensions.js +472 -0
- package/features/index.d.ts +5 -0
- package/features/index.js +60 -0
- package/features/keyboard.d.ts +16 -0
- package/features/keyboard.js +40 -0
- package/features/rowspan.d.ts +25 -0
- package/features/rowspan.js +42 -0
- package/features/virtualization.d.ts +103 -0
- package/features/virtualization.js +853 -0
- package/index.d.ts +2 -0
- package/index.js +34 -0
- package/models/colspan.d.ts +13 -0
- package/models/colspan.js +5 -0
- package/models/core.d.ts +72 -0
- package/models/core.js +49 -0
- package/models/dimensions.d.ts +132 -0
- package/models/dimensions.js +5 -0
- package/models/index.d.ts +4 -0
- package/models/index.js +49 -0
- package/models/rowspan.d.ts +17 -0
- package/models/rowspan.js +5 -0
- package/package.json +67 -0
- package/useVirtualizer.d.ts +193 -0
- package/useVirtualizer.js +33 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Store } from '@mui/x-internals/store';
|
|
2
|
+
import { ColumnWithWidth, DimensionsState, RowId, RowsMetaState, Size } from "../models/index.js";
|
|
3
|
+
import type { BaseState, VirtualizerParams } from "../useVirtualizer.js";
|
|
4
|
+
export declare const Dimensions: {
|
|
5
|
+
initialize: typeof initializeState;
|
|
6
|
+
use: typeof useDimensions;
|
|
7
|
+
selectors: {
|
|
8
|
+
rootSize: (state: BaseState) => Size;
|
|
9
|
+
dimensions: (state: BaseState) => DimensionsState;
|
|
10
|
+
rowHeight: (state: BaseState) => number;
|
|
11
|
+
rowsMeta: (state: BaseState) => RowsMetaState;
|
|
12
|
+
columnPositions: (_: any, columns: ColumnWithWidth[]) => number[];
|
|
13
|
+
needsHorizontalScrollbar: (state: BaseState) => boolean;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export declare namespace Dimensions {
|
|
17
|
+
type State = {
|
|
18
|
+
rootSize: Size;
|
|
19
|
+
dimensions: DimensionsState;
|
|
20
|
+
rowsMeta: RowsMetaState;
|
|
21
|
+
rowHeights: Map<any, any>;
|
|
22
|
+
};
|
|
23
|
+
type API = ReturnType<typeof useDimensions>;
|
|
24
|
+
}
|
|
25
|
+
declare function initializeState(params: VirtualizerParams): Dimensions.State;
|
|
26
|
+
declare function useDimensions(store: Store<BaseState>, params: VirtualizerParams, _api: {}): {
|
|
27
|
+
updateDimensions: () => void;
|
|
28
|
+
debouncedUpdateDimensions: ((() => void) & import("@mui/x-internals/throttle/throttle").Cancelable) | undefined;
|
|
29
|
+
rowsMeta: {
|
|
30
|
+
getRowHeight: (rowId: RowId) => any;
|
|
31
|
+
setLastMeasuredRowIndex: (index: number) => void;
|
|
32
|
+
storeRowHeightMeasurement: (id: RowId, height: number) => void;
|
|
33
|
+
hydrateRowsMeta: () => void;
|
|
34
|
+
observeRowHeight: (element: Element, rowId: RowId) => () => void | undefined;
|
|
35
|
+
rowHasAutoHeight: (id: RowId) => any;
|
|
36
|
+
getRowHeightEntry: (rowId: RowId) => any;
|
|
37
|
+
getLastMeasuredRowIndex: () => number;
|
|
38
|
+
resetRowHeights: () => void;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
|
|
4
|
+
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
|
5
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
6
|
+
Object.defineProperty(exports, "__esModule", {
|
|
7
|
+
value: true
|
|
8
|
+
});
|
|
9
|
+
exports.Dimensions = void 0;
|
|
10
|
+
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
11
|
+
var React = _interopRequireWildcard(require("react"));
|
|
12
|
+
var _ownerDocument = _interopRequireDefault(require("@mui/utils/ownerDocument"));
|
|
13
|
+
var _useLazyRef = _interopRequireDefault(require("@mui/utils/useLazyRef"));
|
|
14
|
+
var _useEnhancedEffect = _interopRequireDefault(require("@mui/utils/useEnhancedEffect"));
|
|
15
|
+
var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
|
|
16
|
+
var _throttle = require("@mui/x-internals/throttle");
|
|
17
|
+
var _isDeepEqual = require("@mui/x-internals/isDeepEqual");
|
|
18
|
+
var _math = require("@mui/x-internals/math");
|
|
19
|
+
var _store = require("@mui/x-internals/store");
|
|
20
|
+
var _models = require("../models");
|
|
21
|
+
/* eslint-disable import/export, @typescript-eslint/no-redeclare */
|
|
22
|
+
/* eslint-disable no-underscore-dangle */
|
|
23
|
+
|
|
24
|
+
const EMPTY_DIMENSIONS = {
|
|
25
|
+
isReady: false,
|
|
26
|
+
root: _models.Size.EMPTY,
|
|
27
|
+
viewportOuterSize: _models.Size.EMPTY,
|
|
28
|
+
viewportInnerSize: _models.Size.EMPTY,
|
|
29
|
+
contentSize: _models.Size.EMPTY,
|
|
30
|
+
minimumSize: _models.Size.EMPTY,
|
|
31
|
+
hasScrollX: false,
|
|
32
|
+
hasScrollY: false,
|
|
33
|
+
scrollbarSize: 0,
|
|
34
|
+
headerHeight: 0,
|
|
35
|
+
groupHeaderHeight: 0,
|
|
36
|
+
headerFilterHeight: 0,
|
|
37
|
+
rowWidth: 0,
|
|
38
|
+
rowHeight: 0,
|
|
39
|
+
columnsTotalWidth: 0,
|
|
40
|
+
leftPinnedWidth: 0,
|
|
41
|
+
rightPinnedWidth: 0,
|
|
42
|
+
headersTotalHeight: 0,
|
|
43
|
+
topContainerHeight: 0,
|
|
44
|
+
bottomContainerHeight: 0
|
|
45
|
+
};
|
|
46
|
+
const selectors = {
|
|
47
|
+
rootSize: state => state.rootSize,
|
|
48
|
+
dimensions: state => state.dimensions,
|
|
49
|
+
rowHeight: state => state.dimensions.rowHeight,
|
|
50
|
+
rowsMeta: state => state.rowsMeta,
|
|
51
|
+
columnPositions: (0, _store.createSelectorMemoized)((_, columns) => {
|
|
52
|
+
const positions = [];
|
|
53
|
+
let currentPosition = 0;
|
|
54
|
+
for (let i = 0; i < columns.length; i += 1) {
|
|
55
|
+
positions.push(currentPosition);
|
|
56
|
+
currentPosition += columns[i].computedWidth;
|
|
57
|
+
}
|
|
58
|
+
return positions;
|
|
59
|
+
}),
|
|
60
|
+
needsHorizontalScrollbar: state => state.dimensions.viewportOuterSize.width > 0 && state.dimensions.columnsTotalWidth > state.dimensions.viewportOuterSize.width
|
|
61
|
+
};
|
|
62
|
+
const Dimensions = exports.Dimensions = {
|
|
63
|
+
initialize: initializeState,
|
|
64
|
+
use: useDimensions,
|
|
65
|
+
selectors
|
|
66
|
+
};
|
|
67
|
+
function initializeState(params) {
|
|
68
|
+
const dimensions = (0, _extends2.default)({}, EMPTY_DIMENSIONS, params.dimensions);
|
|
69
|
+
const {
|
|
70
|
+
rowCount
|
|
71
|
+
} = params;
|
|
72
|
+
const {
|
|
73
|
+
rowHeight
|
|
74
|
+
} = dimensions;
|
|
75
|
+
const rowsMeta = {
|
|
76
|
+
currentPageTotalHeight: rowCount * rowHeight,
|
|
77
|
+
positions: Array.from({
|
|
78
|
+
length: rowCount
|
|
79
|
+
}, (_, i) => i * rowHeight),
|
|
80
|
+
pinnedTopRowsTotalHeight: 0,
|
|
81
|
+
pinnedBottomRowsTotalHeight: 0
|
|
82
|
+
};
|
|
83
|
+
const rowHeights = new Map();
|
|
84
|
+
return {
|
|
85
|
+
rootSize: _models.Size.EMPTY,
|
|
86
|
+
dimensions,
|
|
87
|
+
rowsMeta,
|
|
88
|
+
rowHeights
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function useDimensions(store, params, _api) {
|
|
92
|
+
const isFirstSizing = React.useRef(true);
|
|
93
|
+
const {
|
|
94
|
+
refs,
|
|
95
|
+
dimensions: {
|
|
96
|
+
rowHeight,
|
|
97
|
+
headerHeight,
|
|
98
|
+
columnsTotalWidth,
|
|
99
|
+
groupHeaderHeight,
|
|
100
|
+
headerFilterHeight,
|
|
101
|
+
headersTotalHeight,
|
|
102
|
+
leftPinnedWidth,
|
|
103
|
+
rightPinnedWidth
|
|
104
|
+
}
|
|
105
|
+
} = params;
|
|
106
|
+
const updateDimensions = React.useCallback(() => {
|
|
107
|
+
if (isFirstSizing.current) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const rootSize = selectors.rootSize(store.state);
|
|
111
|
+
const rowsMeta = selectors.rowsMeta(store.state);
|
|
112
|
+
|
|
113
|
+
// All the floating point dimensions should be rounded to .1 decimal places to avoid subpixel rendering issues
|
|
114
|
+
// https://github.com/mui/mui-x/issues/9550#issuecomment-1619020477
|
|
115
|
+
// https://github.com/mui/mui-x/issues/15721
|
|
116
|
+
const scrollbarSize = measureScrollbarSize(params.refs.container.current, params.scrollbarSize);
|
|
117
|
+
const topContainerHeight = headersTotalHeight + rowsMeta.pinnedTopRowsTotalHeight;
|
|
118
|
+
const bottomContainerHeight = rowsMeta.pinnedBottomRowsTotalHeight;
|
|
119
|
+
const contentSize = {
|
|
120
|
+
width: columnsTotalWidth,
|
|
121
|
+
height: (0, _math.roundToDecimalPlaces)(rowsMeta.currentPageTotalHeight, 1)
|
|
122
|
+
};
|
|
123
|
+
let viewportOuterSize;
|
|
124
|
+
let viewportInnerSize;
|
|
125
|
+
let hasScrollX = false;
|
|
126
|
+
let hasScrollY = false;
|
|
127
|
+
if (params.autoHeight) {
|
|
128
|
+
hasScrollY = false;
|
|
129
|
+
hasScrollX = Math.round(columnsTotalWidth) > Math.round(rootSize.width);
|
|
130
|
+
viewportOuterSize = {
|
|
131
|
+
width: rootSize.width,
|
|
132
|
+
height: topContainerHeight + bottomContainerHeight + contentSize.height
|
|
133
|
+
};
|
|
134
|
+
viewportInnerSize = {
|
|
135
|
+
width: Math.max(0, viewportOuterSize.width - (hasScrollY ? scrollbarSize : 0)),
|
|
136
|
+
height: Math.max(0, viewportOuterSize.height - (hasScrollX ? scrollbarSize : 0))
|
|
137
|
+
};
|
|
138
|
+
} else {
|
|
139
|
+
viewportOuterSize = {
|
|
140
|
+
width: rootSize.width,
|
|
141
|
+
height: rootSize.height
|
|
142
|
+
};
|
|
143
|
+
viewportInnerSize = {
|
|
144
|
+
width: Math.max(0, viewportOuterSize.width),
|
|
145
|
+
height: Math.max(0, viewportOuterSize.height - topContainerHeight - bottomContainerHeight)
|
|
146
|
+
};
|
|
147
|
+
const content = contentSize;
|
|
148
|
+
const container = viewportInnerSize;
|
|
149
|
+
const hasScrollXIfNoYScrollBar = content.width > container.width;
|
|
150
|
+
const hasScrollYIfNoXScrollBar = content.height > container.height;
|
|
151
|
+
if (hasScrollXIfNoYScrollBar || hasScrollYIfNoXScrollBar) {
|
|
152
|
+
hasScrollY = hasScrollYIfNoXScrollBar;
|
|
153
|
+
hasScrollX = content.width + (hasScrollY ? scrollbarSize : 0) > container.width;
|
|
154
|
+
|
|
155
|
+
// We recalculate the scroll y to consider the size of the x scrollbar.
|
|
156
|
+
if (hasScrollX) {
|
|
157
|
+
hasScrollY = content.height + scrollbarSize > container.height;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (hasScrollY) {
|
|
161
|
+
viewportInnerSize.width -= scrollbarSize;
|
|
162
|
+
}
|
|
163
|
+
if (hasScrollX) {
|
|
164
|
+
viewportInnerSize.height -= scrollbarSize;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const rowWidth = Math.max(viewportOuterSize.width, columnsTotalWidth + (hasScrollY ? scrollbarSize : 0));
|
|
168
|
+
const minimumSize = {
|
|
169
|
+
width: columnsTotalWidth,
|
|
170
|
+
height: topContainerHeight + contentSize.height + bottomContainerHeight
|
|
171
|
+
};
|
|
172
|
+
const newDimensions = {
|
|
173
|
+
isReady: true,
|
|
174
|
+
root: rootSize,
|
|
175
|
+
viewportOuterSize,
|
|
176
|
+
viewportInnerSize,
|
|
177
|
+
contentSize,
|
|
178
|
+
minimumSize,
|
|
179
|
+
hasScrollX,
|
|
180
|
+
hasScrollY,
|
|
181
|
+
scrollbarSize,
|
|
182
|
+
headerHeight,
|
|
183
|
+
groupHeaderHeight,
|
|
184
|
+
headerFilterHeight,
|
|
185
|
+
rowWidth,
|
|
186
|
+
rowHeight,
|
|
187
|
+
columnsTotalWidth,
|
|
188
|
+
leftPinnedWidth,
|
|
189
|
+
rightPinnedWidth,
|
|
190
|
+
headersTotalHeight,
|
|
191
|
+
topContainerHeight,
|
|
192
|
+
bottomContainerHeight
|
|
193
|
+
};
|
|
194
|
+
const prevDimensions = store.state.dimensions;
|
|
195
|
+
if ((0, _isDeepEqual.isDeepEqual)(prevDimensions, newDimensions)) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
store.update({
|
|
199
|
+
dimensions: newDimensions
|
|
200
|
+
});
|
|
201
|
+
}, [store, params.refs.container, params.scrollbarSize, params.autoHeight, rowHeight, headerHeight, groupHeaderHeight, headerFilterHeight, columnsTotalWidth, headersTotalHeight, leftPinnedWidth, rightPinnedWidth]);
|
|
202
|
+
const {
|
|
203
|
+
resizeThrottleMs,
|
|
204
|
+
onResize
|
|
205
|
+
} = params;
|
|
206
|
+
const updateDimensionCallback = (0, _useEventCallback.default)(updateDimensions);
|
|
207
|
+
const debouncedUpdateDimensions = React.useMemo(() => resizeThrottleMs > 0 ? (0, _throttle.throttle)(() => {
|
|
208
|
+
updateDimensionCallback();
|
|
209
|
+
onResize?.(store.state.rootSize);
|
|
210
|
+
}, resizeThrottleMs) : undefined, [resizeThrottleMs, onResize, store, updateDimensionCallback]);
|
|
211
|
+
React.useEffect(() => debouncedUpdateDimensions?.clear, [debouncedUpdateDimensions]);
|
|
212
|
+
(0, _useEnhancedEffect.default)(() => observeRootNode(refs.container.current, store), [refs, store]);
|
|
213
|
+
(0, _useEnhancedEffect.default)(updateDimensions, [updateDimensions]);
|
|
214
|
+
(0, _store.useStoreEffect)(store, selectors.rootSize, (_, size) => {
|
|
215
|
+
params.onResize?.(size);
|
|
216
|
+
if (isFirstSizing.current || !debouncedUpdateDimensions) {
|
|
217
|
+
// We want to initialize the grid dimensions as soon as possible to avoid flickering
|
|
218
|
+
isFirstSizing.current = false;
|
|
219
|
+
updateDimensions();
|
|
220
|
+
} else {
|
|
221
|
+
debouncedUpdateDimensions();
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
const rowsMeta = useRowsMeta(store, params, updateDimensions);
|
|
225
|
+
return {
|
|
226
|
+
updateDimensions,
|
|
227
|
+
debouncedUpdateDimensions,
|
|
228
|
+
rowsMeta
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function useRowsMeta(store, params, updateDimensions) {
|
|
232
|
+
const heightCache = store.state.rowHeights;
|
|
233
|
+
const {
|
|
234
|
+
rows,
|
|
235
|
+
getRowHeight: getRowHeightProp,
|
|
236
|
+
getRowSpacing,
|
|
237
|
+
getEstimatedRowHeight
|
|
238
|
+
} = params;
|
|
239
|
+
const lastMeasuredRowIndex = React.useRef(-1);
|
|
240
|
+
const hasRowWithAutoHeight = React.useRef(false);
|
|
241
|
+
const isHeightMetaValid = React.useRef(false);
|
|
242
|
+
const pinnedRows = params.pinnedRows;
|
|
243
|
+
const rowHeight = (0, _store.useStore)(store, selectors.rowHeight);
|
|
244
|
+
const getRowHeightEntry = (0, _useEventCallback.default)(rowId => {
|
|
245
|
+
let entry = heightCache.get(rowId);
|
|
246
|
+
if (entry === undefined) {
|
|
247
|
+
entry = {
|
|
248
|
+
content: store.state.dimensions.rowHeight,
|
|
249
|
+
spacingTop: 0,
|
|
250
|
+
spacingBottom: 0,
|
|
251
|
+
detail: 0,
|
|
252
|
+
autoHeight: false,
|
|
253
|
+
needsFirstMeasurement: true
|
|
254
|
+
};
|
|
255
|
+
heightCache.set(rowId, entry);
|
|
256
|
+
}
|
|
257
|
+
return entry;
|
|
258
|
+
});
|
|
259
|
+
const {
|
|
260
|
+
rowIdToIndexMap,
|
|
261
|
+
applyRowHeight
|
|
262
|
+
} = params;
|
|
263
|
+
const processHeightEntry = React.useCallback(row => {
|
|
264
|
+
// HACK: rowHeight trails behind the most up-to-date value just enough to
|
|
265
|
+
// mess the initial rowsMeta hydration :/
|
|
266
|
+
eslintUseValue(rowHeight);
|
|
267
|
+
const dimensions = selectors.dimensions(store.state);
|
|
268
|
+
const baseRowHeight = dimensions.rowHeight;
|
|
269
|
+
const entry = getRowHeightEntry(row.id);
|
|
270
|
+
if (!getRowHeightProp) {
|
|
271
|
+
entry.content = baseRowHeight;
|
|
272
|
+
entry.needsFirstMeasurement = false;
|
|
273
|
+
} else {
|
|
274
|
+
const rowHeightFromUser = getRowHeightProp(row);
|
|
275
|
+
if (rowHeightFromUser === 'auto') {
|
|
276
|
+
if (entry.needsFirstMeasurement) {
|
|
277
|
+
const estimatedRowHeight = getEstimatedRowHeight ? getEstimatedRowHeight(row) : baseRowHeight;
|
|
278
|
+
|
|
279
|
+
// If the row was not measured yet use the estimated row height
|
|
280
|
+
entry.content = estimatedRowHeight ?? baseRowHeight;
|
|
281
|
+
}
|
|
282
|
+
hasRowWithAutoHeight.current = true;
|
|
283
|
+
entry.autoHeight = true;
|
|
284
|
+
} else {
|
|
285
|
+
// Default back to base rowHeight if getRowHeight returns null value.
|
|
286
|
+
entry.content = rowHeightFromUser ?? dimensions.rowHeight;
|
|
287
|
+
entry.needsFirstMeasurement = false;
|
|
288
|
+
entry.autoHeight = false;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (getRowSpacing) {
|
|
292
|
+
const indexRelativeToCurrentPage = rowIdToIndexMap.get(row.id) ?? -1;
|
|
293
|
+
const spacing = getRowSpacing(row, {
|
|
294
|
+
isFirstVisible: indexRelativeToCurrentPage === 0,
|
|
295
|
+
isLastVisible: indexRelativeToCurrentPage === rows.length - 1,
|
|
296
|
+
indexRelativeToCurrentPage
|
|
297
|
+
});
|
|
298
|
+
entry.spacingTop = spacing.top ?? 0;
|
|
299
|
+
entry.spacingBottom = spacing.bottom ?? 0;
|
|
300
|
+
} else {
|
|
301
|
+
entry.spacingTop = 0;
|
|
302
|
+
entry.spacingBottom = 0;
|
|
303
|
+
}
|
|
304
|
+
applyRowHeight?.(entry, row);
|
|
305
|
+
return entry;
|
|
306
|
+
}, [store, rows, getRowHeightProp, getRowHeightEntry, getEstimatedRowHeight, rowHeight, getRowSpacing, rowIdToIndexMap, applyRowHeight]);
|
|
307
|
+
const hydrateRowsMeta = React.useCallback(() => {
|
|
308
|
+
hasRowWithAutoHeight.current = false;
|
|
309
|
+
const pinnedTopRowsTotalHeight = pinnedRows.top.reduce((acc, row) => {
|
|
310
|
+
const entry = processHeightEntry(row);
|
|
311
|
+
return acc + entry.content + entry.spacingTop + entry.spacingBottom + entry.detail;
|
|
312
|
+
}, 0);
|
|
313
|
+
const pinnedBottomRowsTotalHeight = pinnedRows.bottom.reduce((acc, row) => {
|
|
314
|
+
const entry = processHeightEntry(row);
|
|
315
|
+
return acc + entry.content + entry.spacingTop + entry.spacingBottom + entry.detail;
|
|
316
|
+
}, 0);
|
|
317
|
+
const positions = [];
|
|
318
|
+
const currentPageTotalHeight = rows.reduce((acc, row) => {
|
|
319
|
+
positions.push(acc);
|
|
320
|
+
const entry = processHeightEntry(row);
|
|
321
|
+
const total = entry.content + entry.spacingTop + entry.spacingBottom + entry.detail;
|
|
322
|
+
return acc + total;
|
|
323
|
+
}, 0);
|
|
324
|
+
if (!hasRowWithAutoHeight.current) {
|
|
325
|
+
// No row has height=auto, so all rows are already measured
|
|
326
|
+
lastMeasuredRowIndex.current = Infinity;
|
|
327
|
+
}
|
|
328
|
+
const didHeightsChange = pinnedTopRowsTotalHeight !== store.state.rowsMeta.pinnedTopRowsTotalHeight || pinnedBottomRowsTotalHeight !== store.state.rowsMeta.pinnedBottomRowsTotalHeight || currentPageTotalHeight !== store.state.rowsMeta.currentPageTotalHeight;
|
|
329
|
+
const rowsMeta = {
|
|
330
|
+
currentPageTotalHeight,
|
|
331
|
+
positions,
|
|
332
|
+
pinnedTopRowsTotalHeight,
|
|
333
|
+
pinnedBottomRowsTotalHeight
|
|
334
|
+
};
|
|
335
|
+
store.set('rowsMeta', rowsMeta);
|
|
336
|
+
if (didHeightsChange) {
|
|
337
|
+
updateDimensions();
|
|
338
|
+
}
|
|
339
|
+
isHeightMetaValid.current = true;
|
|
340
|
+
}, [store, pinnedRows, rows, processHeightEntry, updateDimensions]);
|
|
341
|
+
const hydrateRowsMetaLatest = (0, _useEventCallback.default)(hydrateRowsMeta);
|
|
342
|
+
const getRowHeight = rowId => {
|
|
343
|
+
return heightCache.get(rowId)?.content ?? selectors.rowHeight(store.state);
|
|
344
|
+
};
|
|
345
|
+
const storeRowHeightMeasurement = (id, height) => {
|
|
346
|
+
const entry = getRowHeightEntry(id);
|
|
347
|
+
const didChange = entry.content !== height;
|
|
348
|
+
entry.needsFirstMeasurement = false;
|
|
349
|
+
entry.content = height;
|
|
350
|
+
isHeightMetaValid.current && (isHeightMetaValid.current = !didChange);
|
|
351
|
+
};
|
|
352
|
+
const rowHasAutoHeight = id => {
|
|
353
|
+
return heightCache.get(id)?.autoHeight ?? false;
|
|
354
|
+
};
|
|
355
|
+
const getLastMeasuredRowIndex = () => {
|
|
356
|
+
return lastMeasuredRowIndex.current;
|
|
357
|
+
};
|
|
358
|
+
const setLastMeasuredRowIndex = index => {
|
|
359
|
+
if (hasRowWithAutoHeight.current && index > lastMeasuredRowIndex.current) {
|
|
360
|
+
lastMeasuredRowIndex.current = index;
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
const resetRowHeights = () => {
|
|
364
|
+
heightCache.clear();
|
|
365
|
+
hydrateRowsMeta();
|
|
366
|
+
};
|
|
367
|
+
const resizeObserver = (0, _useLazyRef.default)(() => typeof ResizeObserver === 'undefined' ? undefined : new ResizeObserver(entries => {
|
|
368
|
+
for (let i = 0; i < entries.length; i += 1) {
|
|
369
|
+
const entry = entries[i];
|
|
370
|
+
const height = entry.borderBoxSize && entry.borderBoxSize.length > 0 ? entry.borderBoxSize[0].blockSize : entry.contentRect.height;
|
|
371
|
+
const rowId = entry.target.__mui_id;
|
|
372
|
+
const focusedVirtualRowId = params.focusedVirtualCell()?.id;
|
|
373
|
+
if (focusedVirtualRowId === rowId && height === 0) {
|
|
374
|
+
// Focused virtual row has 0 height.
|
|
375
|
+
// We don't want to store it to avoid scroll jumping.
|
|
376
|
+
// https://github.com/mui/mui-x/issues/14726
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
storeRowHeightMeasurement(rowId, height);
|
|
380
|
+
}
|
|
381
|
+
if (!isHeightMetaValid.current) {
|
|
382
|
+
// Avoids "ResizeObserver loop completed with undelivered notifications" error
|
|
383
|
+
requestAnimationFrame(() => {
|
|
384
|
+
hydrateRowsMetaLatest();
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
})).current;
|
|
388
|
+
const observeRowHeight = (element, rowId) => {
|
|
389
|
+
element.__mui_id = rowId;
|
|
390
|
+
resizeObserver?.observe(element);
|
|
391
|
+
return () => resizeObserver?.unobserve(element);
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// The effect is used to build the rows meta data - currentPageTotalHeight and positions.
|
|
395
|
+
// Because of variable row height this is needed for the virtualization
|
|
396
|
+
(0, _useEnhancedEffect.default)(() => {
|
|
397
|
+
hydrateRowsMeta();
|
|
398
|
+
}, [hydrateRowsMeta]);
|
|
399
|
+
return {
|
|
400
|
+
getRowHeight,
|
|
401
|
+
setLastMeasuredRowIndex,
|
|
402
|
+
storeRowHeightMeasurement,
|
|
403
|
+
hydrateRowsMeta,
|
|
404
|
+
observeRowHeight,
|
|
405
|
+
rowHasAutoHeight,
|
|
406
|
+
getRowHeightEntry,
|
|
407
|
+
getLastMeasuredRowIndex,
|
|
408
|
+
resetRowHeights
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
function observeRootNode(node, store) {
|
|
412
|
+
if (!node) {
|
|
413
|
+
return undefined;
|
|
414
|
+
}
|
|
415
|
+
const bounds = node.getBoundingClientRect();
|
|
416
|
+
const initialSize = {
|
|
417
|
+
width: (0, _math.roundToDecimalPlaces)(bounds.width, 1),
|
|
418
|
+
height: (0, _math.roundToDecimalPlaces)(bounds.height, 1)
|
|
419
|
+
};
|
|
420
|
+
if (store.state.rootSize === _models.Size.EMPTY || !_models.Size.equals(initialSize, store.state.rootSize)) {
|
|
421
|
+
store.update({
|
|
422
|
+
rootSize: initialSize
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
if (typeof ResizeObserver === 'undefined') {
|
|
426
|
+
return undefined;
|
|
427
|
+
}
|
|
428
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
429
|
+
if (!entry) {
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
const rootSize = {
|
|
433
|
+
width: (0, _math.roundToDecimalPlaces)(entry.contentRect.width, 1),
|
|
434
|
+
height: (0, _math.roundToDecimalPlaces)(entry.contentRect.height, 1)
|
|
435
|
+
};
|
|
436
|
+
if (!_models.Size.equals(rootSize, store.state.rootSize)) {
|
|
437
|
+
store.update({
|
|
438
|
+
rootSize
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
observer.observe(node);
|
|
443
|
+
return () => {
|
|
444
|
+
observer.disconnect();
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
const scrollbarSizeCache = new WeakMap();
|
|
448
|
+
function measureScrollbarSize(element, scrollbarSize) {
|
|
449
|
+
if (scrollbarSize !== undefined) {
|
|
450
|
+
return scrollbarSize;
|
|
451
|
+
}
|
|
452
|
+
if (element === null) {
|
|
453
|
+
return 0;
|
|
454
|
+
}
|
|
455
|
+
const cachedSize = scrollbarSizeCache.get(element);
|
|
456
|
+
if (cachedSize !== undefined) {
|
|
457
|
+
return cachedSize;
|
|
458
|
+
}
|
|
459
|
+
const doc = (0, _ownerDocument.default)(element);
|
|
460
|
+
const scrollDiv = doc.createElement('div');
|
|
461
|
+
scrollDiv.style.width = '99px';
|
|
462
|
+
scrollDiv.style.height = '99px';
|
|
463
|
+
scrollDiv.style.position = 'absolute';
|
|
464
|
+
scrollDiv.style.overflow = 'scroll';
|
|
465
|
+
scrollDiv.className = 'scrollDiv';
|
|
466
|
+
element.appendChild(scrollDiv);
|
|
467
|
+
const size = scrollDiv.offsetWidth - scrollDiv.clientWidth;
|
|
468
|
+
element.removeChild(scrollDiv);
|
|
469
|
+
scrollbarSizeCache.set(element, size);
|
|
470
|
+
return size;
|
|
471
|
+
}
|
|
472
|
+
function eslintUseValue(_) {}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _colspan = require("./colspan");
|
|
7
|
+
Object.keys(_colspan).forEach(function (key) {
|
|
8
|
+
if (key === "default" || key === "__esModule") return;
|
|
9
|
+
if (key in exports && exports[key] === _colspan[key]) return;
|
|
10
|
+
Object.defineProperty(exports, key, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function () {
|
|
13
|
+
return _colspan[key];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
var _dimensions = require("./dimensions");
|
|
18
|
+
Object.keys(_dimensions).forEach(function (key) {
|
|
19
|
+
if (key === "default" || key === "__esModule") return;
|
|
20
|
+
if (key in exports && exports[key] === _dimensions[key]) return;
|
|
21
|
+
Object.defineProperty(exports, key, {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function () {
|
|
24
|
+
return _dimensions[key];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
var _keyboard = require("./keyboard");
|
|
29
|
+
Object.keys(_keyboard).forEach(function (key) {
|
|
30
|
+
if (key === "default" || key === "__esModule") return;
|
|
31
|
+
if (key in exports && exports[key] === _keyboard[key]) return;
|
|
32
|
+
Object.defineProperty(exports, key, {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
get: function () {
|
|
35
|
+
return _keyboard[key];
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
var _rowspan = require("./rowspan");
|
|
40
|
+
Object.keys(_rowspan).forEach(function (key) {
|
|
41
|
+
if (key === "default" || key === "__esModule") return;
|
|
42
|
+
if (key in exports && exports[key] === _rowspan[key]) return;
|
|
43
|
+
Object.defineProperty(exports, key, {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
get: function () {
|
|
46
|
+
return _rowspan[key];
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
var _virtualization = require("./virtualization");
|
|
51
|
+
Object.keys(_virtualization).forEach(function (key) {
|
|
52
|
+
if (key === "default" || key === "__esModule") return;
|
|
53
|
+
if (key in exports && exports[key] === _virtualization[key]) return;
|
|
54
|
+
Object.defineProperty(exports, key, {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () {
|
|
57
|
+
return _virtualization[key];
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Store } from '@mui/x-internals/store';
|
|
2
|
+
import type { BaseState, VirtualizerParams } from "../useVirtualizer.js";
|
|
3
|
+
export declare const Keyboard: {
|
|
4
|
+
initialize: typeof initializeState;
|
|
5
|
+
use: typeof useKeyboard;
|
|
6
|
+
selectors: {};
|
|
7
|
+
};
|
|
8
|
+
export declare namespace Keyboard {
|
|
9
|
+
type State = {};
|
|
10
|
+
type API = ReturnType<typeof useKeyboard>;
|
|
11
|
+
}
|
|
12
|
+
declare function initializeState(_params: VirtualizerParams): Keyboard.State;
|
|
13
|
+
declare function useKeyboard(store: Store<BaseState & Keyboard.State>, params: VirtualizerParams, _api: {}): {
|
|
14
|
+
getViewportPageSize: () => number;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.Keyboard = void 0;
|
|
7
|
+
var _dimensions = require("./dimensions");
|
|
8
|
+
var _virtualization = require("./virtualization");
|
|
9
|
+
/* eslint-disable import/export, @typescript-eslint/no-redeclare */
|
|
10
|
+
|
|
11
|
+
const selectors = {};
|
|
12
|
+
const Keyboard = exports.Keyboard = {
|
|
13
|
+
initialize: initializeState,
|
|
14
|
+
use: useKeyboard,
|
|
15
|
+
selectors
|
|
16
|
+
};
|
|
17
|
+
function initializeState(_params) {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
function useKeyboard(store, params, _api) {
|
|
21
|
+
const getViewportPageSize = () => {
|
|
22
|
+
const dimensions = _dimensions.Dimensions.selectors.dimensions(store.state);
|
|
23
|
+
if (!dimensions.isReady) {
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// TODO: Use a combination of scrollTop, dimensions.viewportInnerSize.height and rowsMeta.possitions
|
|
28
|
+
// to find out the maximum number of rows that can fit in the visible part of the grid
|
|
29
|
+
if (params.getRowHeight) {
|
|
30
|
+
const renderContext = _virtualization.Virtualization.selectors.renderContext(store.state);
|
|
31
|
+
const viewportPageSize = renderContext.lastRowIndex - renderContext.firstRowIndex;
|
|
32
|
+
return Math.min(viewportPageSize - 1, params.rows.length);
|
|
33
|
+
}
|
|
34
|
+
const maximumPageSizeWithoutScrollBar = Math.floor(dimensions.viewportInnerSize.height / dimensions.rowHeight);
|
|
35
|
+
return Math.min(maximumPageSizeWithoutScrollBar, params.rows.length);
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
getViewportPageSize
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Store } from '@mui/x-internals/store';
|
|
2
|
+
import type { BaseState, VirtualizerParams } from "../useVirtualizer.js";
|
|
3
|
+
import type { RowSpanningState } from "../models/rowspan.js";
|
|
4
|
+
import { Virtualization } from "./virtualization.js";
|
|
5
|
+
export declare const Rowspan: {
|
|
6
|
+
initialize: typeof initializeState;
|
|
7
|
+
use: typeof useRowspan;
|
|
8
|
+
selectors: {
|
|
9
|
+
state: (state: Rowspan.State) => RowSpanningState;
|
|
10
|
+
hiddenCells: (state: Rowspan.State) => Record<any, Record<number, boolean>>;
|
|
11
|
+
spannedCells: (state: Rowspan.State) => Record<any, Record<number, number>>;
|
|
12
|
+
hiddenCellsOriginMap: (state: Rowspan.State) => Record<number, Record<number, number>>;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export declare namespace Rowspan {
|
|
16
|
+
type State = {
|
|
17
|
+
rowSpanning: RowSpanningState;
|
|
18
|
+
};
|
|
19
|
+
type API = ReturnType<typeof useRowspan>;
|
|
20
|
+
}
|
|
21
|
+
declare function initializeState(params: VirtualizerParams): Rowspan.State;
|
|
22
|
+
declare function useRowspan(store: Store<BaseState & Rowspan.State>, _params: VirtualizerParams, _api: Virtualization.API): {
|
|
23
|
+
getHiddenCellsOrigin: () => Record<number, Record<number, number>>;
|
|
24
|
+
};
|
|
25
|
+
export {};
|