@mui/x-virtualizer 0.2.10 → 0.2.11
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 +112 -0
- package/constants.d.ts +22 -0
- package/constants.js +26 -0
- package/esm/constants.d.ts +22 -0
- package/esm/constants.js +20 -0
- package/esm/features/colspan.d.ts +4 -4
- package/esm/features/dimensions.d.ts +14 -8
- package/esm/features/dimensions.js +26 -7
- package/esm/features/index.d.ts +1 -1
- package/esm/features/index.js +1 -1
- package/esm/features/keyboard.d.ts +3 -3
- package/esm/features/keyboard.js +1 -1
- package/esm/features/rowspan.d.ts +4 -4
- package/esm/features/virtualization/index.d.ts +2 -0
- package/esm/features/virtualization/index.js +2 -0
- package/esm/features/virtualization/layout.d.ts +129 -0
- package/esm/features/virtualization/layout.js +152 -0
- package/esm/features/{virtualization.d.ts → virtualization/virtualization.d.ts} +35 -58
- package/esm/features/{virtualization.js → virtualization/virtualization.js} +97 -134
- package/esm/index.d.ts +2 -1
- package/esm/index.js +3 -2
- package/esm/models/core.d.ts +7 -0
- package/esm/models/core.js +7 -0
- package/esm/models/dimensions.d.ts +8 -0
- package/esm/useVirtualizer.d.ts +25 -69
- package/esm/useVirtualizer.js +21 -4
- package/features/colspan.d.ts +4 -4
- package/features/dimensions.d.ts +14 -8
- package/features/dimensions.js +26 -7
- package/features/index.d.ts +1 -1
- package/features/keyboard.d.ts +3 -3
- package/features/rowspan.d.ts +4 -4
- package/features/virtualization/index.d.ts +2 -0
- package/features/virtualization/index.js +27 -0
- package/features/virtualization/layout.d.ts +129 -0
- package/features/virtualization/layout.js +163 -0
- package/features/{virtualization.d.ts → virtualization/virtualization.d.ts} +35 -58
- package/features/{virtualization.js → virtualization/virtualization.js} +97 -134
- package/index.d.ts +2 -1
- package/index.js +12 -1
- package/models/core.d.ts +7 -0
- package/models/core.js +8 -1
- package/models/dimensions.d.ts +8 -0
- package/package.json +2 -2
- package/useVirtualizer.d.ts +25 -69
- package/useVirtualizer.js +20 -3
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
|
|
4
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.LayoutList = exports.LayoutDataGridLegacy = exports.LayoutDataGrid = exports.Layout = void 0;
|
|
9
|
+
var _useForkRef = _interopRequireDefault(require("@mui/utils/useForkRef"));
|
|
10
|
+
var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
|
|
11
|
+
var platform = _interopRequireWildcard(require("@mui/x-internals/platform"));
|
|
12
|
+
var _store = require("@mui/x-internals/store");
|
|
13
|
+
var _dimensions = require("../../features/dimensions");
|
|
14
|
+
var _virtualization = require("./virtualization");
|
|
15
|
+
/* eslint-disable react-hooks/rules-of-hooks */
|
|
16
|
+
|
|
17
|
+
class Layout {
|
|
18
|
+
static elements = ['scroller', 'container'];
|
|
19
|
+
constructor(refs) {
|
|
20
|
+
this.refs = refs;
|
|
21
|
+
}
|
|
22
|
+
refSetter(name) {
|
|
23
|
+
return node => {
|
|
24
|
+
if (node && this.refs[name].current !== node) {
|
|
25
|
+
this.refs[name].current = node;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.Layout = Layout;
|
|
31
|
+
class LayoutDataGrid extends Layout {
|
|
32
|
+
static elements = ['scroller', 'container', 'content', 'positioner', 'scrollbarVertical', 'scrollbarHorizontal'];
|
|
33
|
+
use(store, _params, _api, layoutParams) {
|
|
34
|
+
const {
|
|
35
|
+
scrollerRef,
|
|
36
|
+
containerRef
|
|
37
|
+
} = layoutParams;
|
|
38
|
+
const scrollbarVerticalRef = (0, _useEventCallback.default)(this.refSetter('scrollbarVertical'));
|
|
39
|
+
const scrollbarHorizontalRef = (0, _useEventCallback.default)(this.refSetter('scrollbarHorizontal'));
|
|
40
|
+
store.state.virtualization.context = {
|
|
41
|
+
scrollerRef,
|
|
42
|
+
containerRef,
|
|
43
|
+
scrollbarVerticalRef,
|
|
44
|
+
scrollbarHorizontalRef
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
static selectors = {
|
|
48
|
+
containerProps: (0, _store.createSelectorMemoized)(_virtualization.Virtualization.selectors.context, context => ({
|
|
49
|
+
ref: context.containerRef
|
|
50
|
+
})),
|
|
51
|
+
scrollerProps: (0, _store.createSelectorMemoized)(_virtualization.Virtualization.selectors.context, _dimensions.Dimensions.selectors.autoHeight, _dimensions.Dimensions.selectors.needsHorizontalScrollbar, (context, autoHeight, needsHorizontalScrollbar) => ({
|
|
52
|
+
ref: context.scrollerRef,
|
|
53
|
+
style: {
|
|
54
|
+
overflowX: !needsHorizontalScrollbar ? 'hidden' : undefined,
|
|
55
|
+
overflowY: autoHeight ? 'hidden' : undefined
|
|
56
|
+
},
|
|
57
|
+
role: 'presentation',
|
|
58
|
+
// `tabIndex` shouldn't be used along role=presentation, but it fixes a Firefox bug
|
|
59
|
+
// https://github.com/mui/mui-x/pull/13891#discussion_r1683416024
|
|
60
|
+
tabIndex: platform.isFirefox ? -1 : undefined
|
|
61
|
+
})),
|
|
62
|
+
contentProps: (0, _store.createSelectorMemoized)(_dimensions.Dimensions.selectors.contentHeight, _dimensions.Dimensions.selectors.minimalContentHeight, _dimensions.Dimensions.selectors.columnsTotalWidth, _dimensions.Dimensions.selectors.needsHorizontalScrollbar, (contentHeight, minimalContentHeight, columnsTotalWidth, needsHorizontalScrollbar) => ({
|
|
63
|
+
style: {
|
|
64
|
+
width: needsHorizontalScrollbar ? columnsTotalWidth : 'auto',
|
|
65
|
+
flexBasis: contentHeight === 0 ? minimalContentHeight : contentHeight,
|
|
66
|
+
flexShrink: 0
|
|
67
|
+
},
|
|
68
|
+
role: 'presentation'
|
|
69
|
+
})),
|
|
70
|
+
positionerProps: (0, _store.createSelectorMemoized)(_virtualization.Virtualization.selectors.offsetTop, offsetTop => ({
|
|
71
|
+
style: {
|
|
72
|
+
transform: `translate3d(0, ${offsetTop}px, 0)`
|
|
73
|
+
}
|
|
74
|
+
})),
|
|
75
|
+
scrollbarHorizontalProps: (0, _store.createSelectorMemoized)(_virtualization.Virtualization.selectors.context, _virtualization.Virtualization.selectors.scrollPosition, (context, scrollPosition) => ({
|
|
76
|
+
ref: context.scrollbarHorizontalRef,
|
|
77
|
+
scrollPosition
|
|
78
|
+
})),
|
|
79
|
+
scrollbarVerticalProps: (0, _store.createSelectorMemoized)(_virtualization.Virtualization.selectors.context, _virtualization.Virtualization.selectors.scrollPosition, (context, scrollPosition) => ({
|
|
80
|
+
ref: context.scrollbarVerticalRef,
|
|
81
|
+
scrollPosition
|
|
82
|
+
})),
|
|
83
|
+
scrollAreaProps: (0, _store.createSelectorMemoized)(_virtualization.Virtualization.selectors.scrollPosition, scrollPosition => ({
|
|
84
|
+
scrollPosition
|
|
85
|
+
}))
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// The current virtualizer API is exposed on one of the DataGrid slots, so we need to keep
|
|
90
|
+
// the old API for backward compatibility. This API prevents using fine-grained reactivity
|
|
91
|
+
// as all props are returned in a single object, so everything re-renders on any change.
|
|
92
|
+
//
|
|
93
|
+
// TODO(v9): Remove the legacy API.
|
|
94
|
+
exports.LayoutDataGrid = LayoutDataGrid;
|
|
95
|
+
class LayoutDataGridLegacy extends LayoutDataGrid {
|
|
96
|
+
use(store, _params, _api, layoutParams) {
|
|
97
|
+
super.use(store, _params, _api, layoutParams);
|
|
98
|
+
const containerProps = store.use(LayoutDataGrid.selectors.containerProps);
|
|
99
|
+
const scrollerProps = store.use(LayoutDataGrid.selectors.scrollerProps);
|
|
100
|
+
const contentProps = store.use(LayoutDataGrid.selectors.contentProps);
|
|
101
|
+
const positionerProps = store.use(LayoutDataGrid.selectors.positionerProps);
|
|
102
|
+
const scrollbarVerticalProps = store.use(LayoutDataGrid.selectors.scrollbarVerticalProps);
|
|
103
|
+
const scrollbarHorizontalProps = store.use(LayoutDataGrid.selectors.scrollbarHorizontalProps);
|
|
104
|
+
const scrollAreaProps = store.use(LayoutDataGrid.selectors.scrollAreaProps);
|
|
105
|
+
return {
|
|
106
|
+
getContainerProps: () => containerProps,
|
|
107
|
+
getScrollerProps: () => scrollerProps,
|
|
108
|
+
getContentProps: () => contentProps,
|
|
109
|
+
getPositionerProps: () => positionerProps,
|
|
110
|
+
getScrollbarVerticalProps: () => scrollbarVerticalProps,
|
|
111
|
+
getScrollbarHorizontalProps: () => scrollbarHorizontalProps,
|
|
112
|
+
getScrollAreaProps: () => scrollAreaProps
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
exports.LayoutDataGridLegacy = LayoutDataGridLegacy;
|
|
117
|
+
class LayoutList extends Layout {
|
|
118
|
+
static elements = ['scroller', 'container', 'content', 'positioner'];
|
|
119
|
+
use(store, _params, _api, layoutParams) {
|
|
120
|
+
const {
|
|
121
|
+
scrollerRef,
|
|
122
|
+
containerRef
|
|
123
|
+
} = layoutParams;
|
|
124
|
+
const mergedRef = (0, _useForkRef.default)(scrollerRef, containerRef);
|
|
125
|
+
store.state.virtualization.context = {
|
|
126
|
+
mergedRef
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
static selectors = {
|
|
130
|
+
containerProps: (0, _store.createSelectorMemoized)(_virtualization.Virtualization.selectors.context, _dimensions.Dimensions.selectors.autoHeight, _dimensions.Dimensions.selectors.needsHorizontalScrollbar, (context, autoHeight, needsHorizontalScrollbar) => ({
|
|
131
|
+
ref: context.mergedRef,
|
|
132
|
+
style: {
|
|
133
|
+
overflowX: !needsHorizontalScrollbar ? 'hidden' : undefined,
|
|
134
|
+
overflowY: autoHeight ? 'hidden' : undefined,
|
|
135
|
+
position: 'relative'
|
|
136
|
+
},
|
|
137
|
+
role: 'presentation',
|
|
138
|
+
// `tabIndex` shouldn't be used along role=presentation, but it fixes a Firefox bug
|
|
139
|
+
// https://github.com/mui/mui-x/pull/13891#discussion_r1683416024
|
|
140
|
+
tabIndex: platform.isFirefox ? -1 : undefined
|
|
141
|
+
})),
|
|
142
|
+
contentProps: (0, _store.createSelectorMemoized)(_dimensions.Dimensions.selectors.contentHeight, contentHeight => {
|
|
143
|
+
return {
|
|
144
|
+
style: {
|
|
145
|
+
position: 'absolute',
|
|
146
|
+
display: 'inline-block',
|
|
147
|
+
width: '100%',
|
|
148
|
+
height: contentHeight,
|
|
149
|
+
top: 0,
|
|
150
|
+
left: 0,
|
|
151
|
+
zIndex: -1
|
|
152
|
+
},
|
|
153
|
+
role: 'presentation'
|
|
154
|
+
};
|
|
155
|
+
}),
|
|
156
|
+
positionerProps: (0, _store.createSelectorMemoized)(_virtualization.Virtualization.selectors.offsetTop, offsetTop => ({
|
|
157
|
+
style: {
|
|
158
|
+
height: offsetTop
|
|
159
|
+
}
|
|
160
|
+
}))
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
exports.LayoutList = LayoutList;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { integer } from '@mui/x-internals/types';
|
|
3
3
|
import { Store } from '@mui/x-internals/store';
|
|
4
|
-
import type { CellColSpanInfo } from "
|
|
5
|
-
import { Dimensions } from "
|
|
6
|
-
import type { BaseState,
|
|
7
|
-
import {
|
|
4
|
+
import type { CellColSpanInfo } from "../../models/colspan.js";
|
|
5
|
+
import { Dimensions } from "../dimensions.js";
|
|
6
|
+
import type { BaseState, ParamsWithDefaults } from "../../useVirtualizer.js";
|
|
7
|
+
import type { Layout } from "./layout.js";
|
|
8
|
+
import { RenderContext, ColumnsRenderContext, ColumnWithWidth, RowId, ScrollPosition } from "../../models/index.js";
|
|
8
9
|
export type VirtualizationParams = {
|
|
9
10
|
/** @default false */
|
|
10
11
|
isRtl?: boolean;
|
|
@@ -15,11 +16,16 @@ export type VirtualizationParams = {
|
|
|
15
16
|
* @default 150 */
|
|
16
17
|
columnBufferPx?: number;
|
|
17
18
|
};
|
|
18
|
-
export type VirtualizationState = {
|
|
19
|
+
export type VirtualizationState<K extends string = string> = {
|
|
19
20
|
enabled: boolean;
|
|
20
21
|
enabledForRows: boolean;
|
|
21
22
|
enabledForColumns: boolean;
|
|
22
23
|
renderContext: RenderContext;
|
|
24
|
+
props: Record<K, Record<string, any>>;
|
|
25
|
+
context: Record<string, any>;
|
|
26
|
+
scrollPosition: {
|
|
27
|
+
current: ScrollPosition;
|
|
28
|
+
};
|
|
23
29
|
};
|
|
24
30
|
export declare const EMPTY_RENDER_CONTEXT: {
|
|
25
31
|
firstRowIndex: number;
|
|
@@ -31,20 +37,31 @@ export declare const Virtualization: {
|
|
|
31
37
|
initialize: typeof initializeState;
|
|
32
38
|
use: typeof useVirtualization;
|
|
33
39
|
selectors: {
|
|
34
|
-
store: (state: BaseState) => VirtualizationState
|
|
40
|
+
store: (state: BaseState) => VirtualizationState<string>;
|
|
35
41
|
renderContext: (state: BaseState) => RenderContext;
|
|
36
42
|
enabledForRows: (state: BaseState) => boolean;
|
|
37
43
|
enabledForColumns: (state: BaseState) => boolean;
|
|
44
|
+
offsetTop: (args_0: Virtualization.State<Layout<{
|
|
45
|
+
scroller: React.RefObject<HTMLElement | null>;
|
|
46
|
+
container: React.RefObject<HTMLElement | null>;
|
|
47
|
+
} & Record<string, React.RefObject<HTMLElement | null>>>> & Dimensions.State) => number;
|
|
48
|
+
context: (state: BaseState) => Record<string, any>;
|
|
49
|
+
scrollPosition: (state: BaseState) => {
|
|
50
|
+
current: ScrollPosition;
|
|
51
|
+
};
|
|
38
52
|
};
|
|
39
53
|
};
|
|
40
54
|
export declare namespace Virtualization {
|
|
41
|
-
type State = {
|
|
42
|
-
virtualization: VirtualizationState
|
|
55
|
+
type State<L extends Layout> = {
|
|
56
|
+
virtualization: VirtualizationState<L extends Layout<infer E> ? keyof E : string>;
|
|
43
57
|
getters: ReturnType<typeof useVirtualization>['getters'];
|
|
44
58
|
};
|
|
45
59
|
type API = ReturnType<typeof useVirtualization>;
|
|
46
60
|
}
|
|
47
|
-
declare function initializeState(params:
|
|
61
|
+
declare function initializeState(params: ParamsWithDefaults): Virtualization.State<Layout<{
|
|
62
|
+
scroller: React.RefObject<HTMLElement | null>;
|
|
63
|
+
container: React.RefObject<HTMLElement | null>;
|
|
64
|
+
} & Record<string, React.RefObject<HTMLElement | null>>>>;
|
|
48
65
|
/** APIs to override for colspan/rowspan */
|
|
49
66
|
type AbstractAPI = {
|
|
50
67
|
getCellColSpanInfo: (rowId: RowId, columnIndex: integer) => CellColSpanInfo;
|
|
@@ -52,58 +69,18 @@ type AbstractAPI = {
|
|
|
52
69
|
getHiddenCellsOrigin: () => Record<RowId, Record<number, number>>;
|
|
53
70
|
};
|
|
54
71
|
type RequiredAPI = Dimensions.API & AbstractAPI;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
rows?: RowEntry[];
|
|
61
|
-
position?: PinnedRowPosition;
|
|
62
|
-
renderContext?: RenderContext;
|
|
63
|
-
}, unstable_rowTree?: Record<RowId, any>) => React.ReactNode[];
|
|
64
|
-
rows: RowEntry[];
|
|
65
|
-
getContainerProps: () => {
|
|
66
|
-
ref: (node: HTMLDivElement | null) => (() => void | undefined) | undefined;
|
|
67
|
-
};
|
|
68
|
-
getScrollerProps: () => {
|
|
69
|
-
ref: (node: HTMLDivElement | null) => (() => void | undefined) | undefined;
|
|
70
|
-
style: React.CSSProperties;
|
|
71
|
-
role: string;
|
|
72
|
-
tabIndex: number | undefined;
|
|
73
|
-
};
|
|
74
|
-
getContentProps: () => {
|
|
75
|
-
ref: (node: HTMLDivElement | null) => void;
|
|
76
|
-
style: React.CSSProperties;
|
|
77
|
-
role: string;
|
|
78
|
-
};
|
|
79
|
-
getScrollbarVerticalProps: () => {
|
|
80
|
-
ref: (node: HTMLDivElement | null) => void;
|
|
81
|
-
scrollPosition: React.RefObject<{
|
|
82
|
-
top: number;
|
|
83
|
-
left: number;
|
|
84
|
-
}>;
|
|
85
|
-
};
|
|
86
|
-
getScrollbarHorizontalProps: () => {
|
|
87
|
-
ref: (node: HTMLDivElement | null) => void;
|
|
88
|
-
scrollPosition: React.RefObject<{
|
|
89
|
-
top: number;
|
|
90
|
-
left: number;
|
|
91
|
-
}>;
|
|
92
|
-
};
|
|
93
|
-
getScrollAreaProps: () => {
|
|
94
|
-
scrollPosition: React.RefObject<{
|
|
95
|
-
top: number;
|
|
96
|
-
left: number;
|
|
97
|
-
}>;
|
|
98
|
-
};
|
|
99
|
-
};
|
|
100
|
-
useVirtualization: () => BaseState;
|
|
101
|
-
setPanels: React.Dispatch<React.SetStateAction<Readonly<Map<any, React.ReactNode>>>>;
|
|
102
|
-
forceUpdateRenderContext: () => void;
|
|
103
|
-
scheduleUpdateRenderContext: () => void;
|
|
72
|
+
export type VirtualizationLayoutParams = {
|
|
73
|
+
containerRef: (node: HTMLDivElement | null) => void;
|
|
74
|
+
scrollerRef: (node: HTMLDivElement | null) => void;
|
|
75
|
+
};
|
|
76
|
+
declare function useVirtualization(store: Store<BaseState>, params: ParamsWithDefaults, api: RequiredAPI): {
|
|
104
77
|
getCellColSpanInfo: (rowId: RowId, columnIndex: integer) => CellColSpanInfo;
|
|
105
78
|
calculateColSpan: (rowId: RowId, minFirstColumn: integer, maxLastColumn: integer, columns: ColumnWithWidth[]) => void;
|
|
106
79
|
getHiddenCellsOrigin: () => Record<RowId, Record<number, number>>;
|
|
80
|
+
getters: any;
|
|
81
|
+
setPanels: React.Dispatch<React.SetStateAction<Readonly<Map<any, React.ReactNode>>>>;
|
|
82
|
+
forceUpdateRenderContext: () => void;
|
|
83
|
+
scheduleUpdateRenderContext: () => void;
|
|
107
84
|
};
|
|
108
85
|
export declare function areRenderContextsEqual(context1: RenderContext, context2: RenderContext): boolean;
|
|
109
86
|
export declare function computeOffsetLeft(columnPositions: number[], renderContext: ColumnsRenderContext, pinnedLeftLength: number): number;
|
|
@@ -21,9 +21,9 @@ var platform = _interopRequireWildcard(require("@mui/x-internals/platform"));
|
|
|
21
21
|
var _useRunOnce = require("@mui/x-internals/useRunOnce");
|
|
22
22
|
var _store = require("@mui/x-internals/store");
|
|
23
23
|
var _reactMajor = _interopRequireDefault(require("@mui/x-internals/reactMajor"));
|
|
24
|
-
var _core = require("
|
|
25
|
-
var _dimensions = require("
|
|
26
|
-
var _models = require("
|
|
24
|
+
var _core = require("../../models/core");
|
|
25
|
+
var _dimensions = require("../dimensions");
|
|
26
|
+
var _models = require("../../models");
|
|
27
27
|
/* eslint-disable import/export, @typescript-eslint/no-redeclare */
|
|
28
28
|
|
|
29
29
|
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
|
|
@@ -39,12 +39,18 @@ const EMPTY_RENDER_CONTEXT = exports.EMPTY_RENDER_CONTEXT = {
|
|
|
39
39
|
firstColumnIndex: 0,
|
|
40
40
|
lastColumnIndex: 0
|
|
41
41
|
};
|
|
42
|
-
const selectors = {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
const selectors = (() => {
|
|
43
|
+
const firstRowIndexSelector = (0, _store.createSelector)(state => state.virtualization.renderContext.firstRowIndex);
|
|
44
|
+
return {
|
|
45
|
+
store: (0, _store.createSelector)(state => state.virtualization),
|
|
46
|
+
renderContext: (0, _store.createSelector)(state => state.virtualization.renderContext),
|
|
47
|
+
enabledForRows: (0, _store.createSelector)(state => state.virtualization.enabledForRows),
|
|
48
|
+
enabledForColumns: (0, _store.createSelector)(state => state.virtualization.enabledForColumns),
|
|
49
|
+
offsetTop: (0, _store.createSelector)(_dimensions.Dimensions.selectors.rowPositions, firstRowIndexSelector, (rowPositions, firstRowIndex) => rowPositions[firstRowIndex] ?? 0),
|
|
50
|
+
context: (0, _store.createSelector)(state => state.virtualization.context),
|
|
51
|
+
scrollPosition: (0, _store.createSelector)(state => state.virtualization.scrollPosition)
|
|
52
|
+
};
|
|
53
|
+
})();
|
|
48
54
|
const Virtualization = exports.Virtualization = {
|
|
49
55
|
initialize: initializeState,
|
|
50
56
|
use: useVirtualization,
|
|
@@ -56,7 +62,12 @@ function initializeState(params) {
|
|
|
56
62
|
enabled: !platform.isJSDOM,
|
|
57
63
|
enabledForRows: !platform.isJSDOM,
|
|
58
64
|
enabledForColumns: !platform.isJSDOM,
|
|
59
|
-
renderContext: EMPTY_RENDER_CONTEXT
|
|
65
|
+
renderContext: EMPTY_RENDER_CONTEXT,
|
|
66
|
+
props: params.layout.constructor.elements.reduce((acc, key) => (acc[key], acc), {}),
|
|
67
|
+
context: {},
|
|
68
|
+
scrollPosition: {
|
|
69
|
+
current: _models.ScrollPosition.EMPTY
|
|
70
|
+
}
|
|
60
71
|
}, params.initialState?.virtualization),
|
|
61
72
|
// FIXME: refactor once the state shape is settled
|
|
62
73
|
getters: null
|
|
@@ -68,10 +79,10 @@ function initializeState(params) {
|
|
|
68
79
|
|
|
69
80
|
function useVirtualization(store, params, api) {
|
|
70
81
|
const {
|
|
71
|
-
|
|
82
|
+
layout,
|
|
72
83
|
dimensions: {
|
|
73
84
|
rowHeight,
|
|
74
|
-
columnsTotalWidth
|
|
85
|
+
columnsTotalWidth = 0
|
|
75
86
|
},
|
|
76
87
|
virtualization: {
|
|
77
88
|
isRtl = false,
|
|
@@ -85,8 +96,6 @@ function useVirtualization(store, params, api) {
|
|
|
85
96
|
columns,
|
|
86
97
|
pinnedRows = _core.PinnedRows.EMPTY,
|
|
87
98
|
pinnedColumns = _core.PinnedColumns.EMPTY,
|
|
88
|
-
minimalContentHeight,
|
|
89
|
-
autoHeight,
|
|
90
99
|
onWheel,
|
|
91
100
|
onTouchMove,
|
|
92
101
|
onRenderContextChange,
|
|
@@ -95,7 +104,6 @@ function useVirtualization(store, params, api) {
|
|
|
95
104
|
renderRow,
|
|
96
105
|
renderInfiniteLoadingTrigger
|
|
97
106
|
} = params;
|
|
98
|
-
const needsHorizontalScrollbar = (0, _store.useStore)(store, _dimensions.Dimensions.selectors.needsHorizontalScrollbar);
|
|
99
107
|
const hasBottomPinnedRows = pinnedRows.bottom.length > 0;
|
|
100
108
|
const [panels, setPanels] = React.useState(EMPTY_DETAIL_PANELS);
|
|
101
109
|
const isUpdateScheduled = React.useRef(false);
|
|
@@ -103,7 +111,6 @@ function useVirtualization(store, params, api) {
|
|
|
103
111
|
const renderContext = (0, _store.useStore)(store, selectors.renderContext);
|
|
104
112
|
const enabledForRows = (0, _store.useStore)(store, selectors.enabledForRows);
|
|
105
113
|
const enabledForColumns = (0, _store.useStore)(store, selectors.enabledForColumns);
|
|
106
|
-
const rowsMeta = (0, _store.useStore)(store, _dimensions.Dimensions.selectors.rowsMeta);
|
|
107
114
|
const contentHeight = (0, _store.useStore)(store, _dimensions.Dimensions.selectors.contentHeight);
|
|
108
115
|
|
|
109
116
|
/*
|
|
@@ -131,7 +138,10 @@ function useVirtualization(store, params, api) {
|
|
|
131
138
|
const updateRenderContext = React.useCallback(nextRenderContext => {
|
|
132
139
|
if (!areRenderContextsEqual(nextRenderContext, store.state.virtualization.renderContext)) {
|
|
133
140
|
store.set('virtualization', (0, _extends2.default)({}, store.state.virtualization, {
|
|
134
|
-
renderContext: nextRenderContext
|
|
141
|
+
renderContext: nextRenderContext,
|
|
142
|
+
scrollPosition: {
|
|
143
|
+
current: (0, _extends2.default)({}, scrollPosition.current)
|
|
144
|
+
}
|
|
135
145
|
}));
|
|
136
146
|
}
|
|
137
147
|
|
|
@@ -147,7 +157,7 @@ function useVirtualization(store, params, api) {
|
|
|
147
157
|
previousContextScrollPosition.current = scrollPosition.current;
|
|
148
158
|
}, [store, onRenderContextChange]);
|
|
149
159
|
const triggerUpdateRenderContext = (0, _useEventCallback.default)(() => {
|
|
150
|
-
const scroller = refs.scroller.current;
|
|
160
|
+
const scroller = layout.refs.scroller.current;
|
|
151
161
|
if (!scroller) {
|
|
152
162
|
return undefined;
|
|
153
163
|
}
|
|
@@ -175,6 +185,11 @@ function useVirtualization(store, params, api) {
|
|
|
175
185
|
const didChangeDirection = scrollCache.direction !== direction;
|
|
176
186
|
const shouldUpdate = didCrossThreshold || didChangeDirection;
|
|
177
187
|
if (!shouldUpdate) {
|
|
188
|
+
store.set('virtualization', (0, _extends2.default)({}, store.state.virtualization, {
|
|
189
|
+
scrollPosition: {
|
|
190
|
+
current: (0, _extends2.default)({}, scrollPosition.current)
|
|
191
|
+
}
|
|
192
|
+
}));
|
|
178
193
|
return renderContext;
|
|
179
194
|
}
|
|
180
195
|
|
|
@@ -241,9 +256,6 @@ function useVirtualization(store, params, api) {
|
|
|
241
256
|
onScrollChange?.(scrollPosition.current, nextRenderContext);
|
|
242
257
|
}
|
|
243
258
|
});
|
|
244
|
-
const getOffsetTop = () => {
|
|
245
|
-
return rowsMeta.positions[renderContext.firstRowIndex] ?? 0;
|
|
246
|
-
};
|
|
247
259
|
|
|
248
260
|
/**
|
|
249
261
|
* HACK: unstable_rowTree fixes the issue described below, but does it by tightly coupling this
|
|
@@ -372,34 +384,13 @@ function useVirtualization(store, params, api) {
|
|
|
372
384
|
if (panel) {
|
|
373
385
|
rowElements.push(panel);
|
|
374
386
|
}
|
|
375
|
-
if (rowParams.position === undefined && isLastVisibleInSection) {
|
|
387
|
+
if (rowParams.position === undefined && isLastVisibleInSection && renderInfiniteLoadingTrigger) {
|
|
376
388
|
rowElements.push(renderInfiniteLoadingTrigger(id));
|
|
377
389
|
}
|
|
378
390
|
});
|
|
379
391
|
return rowElements;
|
|
380
392
|
};
|
|
381
|
-
const scrollerStyle = React.useMemo(() => ({
|
|
382
|
-
overflowX: !needsHorizontalScrollbar ? 'hidden' : undefined,
|
|
383
|
-
overflowY: autoHeight ? 'hidden' : undefined
|
|
384
|
-
}), [needsHorizontalScrollbar, autoHeight]);
|
|
385
|
-
const contentSize = React.useMemo(() => {
|
|
386
|
-
const size = {
|
|
387
|
-
width: needsHorizontalScrollbar ? columnsTotalWidth : 'auto',
|
|
388
|
-
flexBasis: contentHeight,
|
|
389
|
-
flexShrink: 0
|
|
390
|
-
};
|
|
391
|
-
if (size.flexBasis === 0) {
|
|
392
|
-
size.flexBasis = minimalContentHeight; // Give room to show the overlay when there no rows.
|
|
393
|
-
}
|
|
394
|
-
return size;
|
|
395
|
-
}, [columnsTotalWidth, contentHeight, needsHorizontalScrollbar, minimalContentHeight]);
|
|
396
393
|
const scrollRestoreCallback = React.useRef(null);
|
|
397
|
-
const contentNodeRef = React.useCallback(node => {
|
|
398
|
-
if (!node) {
|
|
399
|
-
return;
|
|
400
|
-
}
|
|
401
|
-
scrollRestoreCallback.current?.(columnsTotalWidth, contentHeight);
|
|
402
|
-
}, [columnsTotalWidth, contentHeight]);
|
|
403
394
|
(0, _useEnhancedEffect.default)(() => {
|
|
404
395
|
if (!isRenderContextReady.current) {
|
|
405
396
|
return;
|
|
@@ -407,15 +398,15 @@ function useVirtualization(store, params, api) {
|
|
|
407
398
|
forceUpdateRenderContextCallback();
|
|
408
399
|
}, [enabledForColumns, enabledForRows, forceUpdateRenderContextCallback]);
|
|
409
400
|
(0, _useEnhancedEffect.default)(() => {
|
|
410
|
-
if (refs.scroller.current) {
|
|
411
|
-
refs.scroller.current.scrollLeft = 0;
|
|
401
|
+
if (layout.refs.scroller.current) {
|
|
402
|
+
layout.refs.scroller.current.scrollLeft = 0;
|
|
412
403
|
}
|
|
413
|
-
}, [refs.scroller, scrollReset]);
|
|
404
|
+
}, [layout.refs.scroller, scrollReset]);
|
|
414
405
|
(0, _useRunOnce.useRunOnce)(renderContext !== EMPTY_RENDER_CONTEXT, () => {
|
|
415
406
|
onScrollChange?.(scrollPosition.current, renderContext);
|
|
416
407
|
isRenderContextReady.current = true;
|
|
417
|
-
if (initialState?.scroll && refs.scroller.current) {
|
|
418
|
-
const scroller = refs.scroller.current;
|
|
408
|
+
if (initialState?.scroll && layout.refs.scroller.current) {
|
|
409
|
+
const scroller = layout.refs.scroller.current;
|
|
419
410
|
const {
|
|
420
411
|
top,
|
|
421
412
|
left
|
|
@@ -458,20 +449,14 @@ function useVirtualization(store, params, api) {
|
|
|
458
449
|
}
|
|
459
450
|
});
|
|
460
451
|
(0, _store.useStoreEffect)(store, _dimensions.Dimensions.selectors.dimensions, forceUpdateRenderContext);
|
|
461
|
-
|
|
462
|
-
if (
|
|
463
|
-
|
|
452
|
+
(0, _useEnhancedEffect.default)(() => {
|
|
453
|
+
if (layout.refs.scroller) {
|
|
454
|
+
scrollRestoreCallback.current?.(columnsTotalWidth, contentHeight);
|
|
464
455
|
}
|
|
465
|
-
};
|
|
456
|
+
}, [layout.refs.scroller, columnsTotalWidth, contentHeight]);
|
|
466
457
|
const isFirstSizing = React.useRef(true);
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
if (!node) {
|
|
470
|
-
// Cleanup for R18
|
|
471
|
-
containerCleanup.current?.();
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
refs.container.current = node;
|
|
458
|
+
const containerRef = useRefCallback(node => {
|
|
459
|
+
layout.refs.container.current = node;
|
|
475
460
|
const unsubscribe = (0, _dimensions.observeRootNode)(node, store, rootSize => {
|
|
476
461
|
if (rootSize.width === 0 && rootSize.height === 0 && store.state.rootSize.height !== 0 && store.state.rootSize.width !== 0) {
|
|
477
462
|
return;
|
|
@@ -485,98 +470,58 @@ function useVirtualization(store, params, api) {
|
|
|
485
470
|
api.debouncedUpdateDimensions();
|
|
486
471
|
}
|
|
487
472
|
});
|
|
488
|
-
|
|
473
|
+
return () => {
|
|
489
474
|
unsubscribe?.();
|
|
490
|
-
refs.container.current = null;
|
|
475
|
+
layout.refs.container.current = null;
|
|
491
476
|
};
|
|
492
|
-
if (_reactMajor.default >= 19) {
|
|
493
|
-
/* eslint-disable-next-line consistent-return */
|
|
494
|
-
return containerCleanup.current;
|
|
495
|
-
}
|
|
496
477
|
});
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
if (!node) {
|
|
500
|
-
// Cleanup for R18
|
|
501
|
-
scrollerCleanup.current?.();
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
scrollerCleanup.current?.();
|
|
505
|
-
refs.scroller.current = node;
|
|
478
|
+
const scrollerRef = useRefCallback(node => {
|
|
479
|
+
layout.refs.scroller.current = node;
|
|
506
480
|
const opts = {
|
|
507
481
|
passive: true
|
|
508
482
|
};
|
|
509
483
|
node.addEventListener('scroll', handleScroll, opts);
|
|
510
484
|
node.addEventListener('wheel', onWheel, opts);
|
|
511
485
|
node.addEventListener('touchmove', onTouchMove, opts);
|
|
512
|
-
|
|
486
|
+
return () => {
|
|
513
487
|
node.removeEventListener('scroll', handleScroll, opts);
|
|
514
488
|
node.removeEventListener('wheel', onWheel, opts);
|
|
515
489
|
node.removeEventListener('touchmove', onTouchMove, opts);
|
|
516
|
-
refs.scroller.current = null;
|
|
490
|
+
layout.refs.scroller.current = null;
|
|
517
491
|
};
|
|
518
|
-
if (_reactMajor.default >= 19) {
|
|
519
|
-
/* eslint-disable-next-line consistent-return */
|
|
520
|
-
return scrollerCleanup.current;
|
|
521
|
-
}
|
|
522
492
|
});
|
|
523
|
-
const
|
|
524
|
-
|
|
525
|
-
|
|
493
|
+
const layoutParams = {
|
|
494
|
+
containerRef,
|
|
495
|
+
scrollerRef
|
|
496
|
+
};
|
|
497
|
+
const layoutAPI = layout.use(store, params, api, layoutParams);
|
|
498
|
+
const getters = (0, _extends2.default)({
|
|
526
499
|
setPanels,
|
|
527
|
-
getOffsetTop,
|
|
528
500
|
getRows,
|
|
529
|
-
rows: params.rows
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
}),
|
|
533
|
-
getScrollerProps: () => ({
|
|
534
|
-
ref: scrollerRef,
|
|
535
|
-
style: scrollerStyle,
|
|
536
|
-
role: 'presentation',
|
|
537
|
-
// `tabIndex` shouldn't be used along role=presentation, but it fixes a Firefox bug
|
|
538
|
-
// https://github.com/mui/mui-x/pull/13891#discussion_r1683416024
|
|
539
|
-
tabIndex: platform.isFirefox ? -1 : undefined
|
|
540
|
-
}),
|
|
541
|
-
getContentProps: () => ({
|
|
542
|
-
ref: contentNodeRef,
|
|
543
|
-
style: contentSize,
|
|
544
|
-
role: 'presentation'
|
|
545
|
-
}),
|
|
546
|
-
getScrollbarVerticalProps: () => ({
|
|
547
|
-
ref: scrollbarVerticalRef,
|
|
548
|
-
scrollPosition
|
|
549
|
-
}),
|
|
550
|
-
getScrollbarHorizontalProps: () => ({
|
|
551
|
-
ref: scrollbarHorizontalRef,
|
|
552
|
-
scrollPosition
|
|
553
|
-
}),
|
|
554
|
-
getScrollAreaProps: () => ({
|
|
555
|
-
scrollPosition
|
|
556
|
-
})
|
|
557
|
-
};
|
|
558
|
-
|
|
559
|
-
/* Placeholder API functions for colspan & rowspan to re-implement */
|
|
560
|
-
|
|
561
|
-
const getCellColSpanInfo = () => {
|
|
562
|
-
throw new Error('Unimplemented: colspan feature is required');
|
|
563
|
-
};
|
|
564
|
-
const calculateColSpan = () => {
|
|
565
|
-
throw new Error('Unimplemented: colspan feature is required');
|
|
566
|
-
};
|
|
567
|
-
const getHiddenCellsOrigin = () => {
|
|
568
|
-
throw new Error('Unimplemented: rowspan feature is required');
|
|
569
|
-
};
|
|
570
|
-
return {
|
|
501
|
+
rows: params.rows
|
|
502
|
+
}, layoutAPI);
|
|
503
|
+
return (0, _extends2.default)({
|
|
571
504
|
getters,
|
|
572
|
-
useVirtualization: () => (0, _store.useStore)(store, state => state),
|
|
573
505
|
setPanels,
|
|
574
506
|
forceUpdateRenderContext,
|
|
575
|
-
scheduleUpdateRenderContext
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
507
|
+
scheduleUpdateRenderContext
|
|
508
|
+
}, createSpanningAPI());
|
|
509
|
+
}
|
|
510
|
+
function useRefCallback(fn) {
|
|
511
|
+
const refCleanup = React.useRef(undefined);
|
|
512
|
+
const refCallback = (0, _useEventCallback.default)(node => {
|
|
513
|
+
if (!node) {
|
|
514
|
+
// Cleanup for R18
|
|
515
|
+
refCleanup.current?.();
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
refCleanup.current = fn(node);
|
|
519
|
+
if (_reactMajor.default >= 19) {
|
|
520
|
+
/* eslint-disable-next-line consistent-return */
|
|
521
|
+
return refCleanup.current;
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
return refCallback;
|
|
580
525
|
}
|
|
581
526
|
function inputsSelector(store, params, api, enabledForRows, enabledForColumns) {
|
|
582
527
|
const dimensions = _dimensions.Dimensions.selectors.dimensions(store.state);
|
|
@@ -590,7 +535,7 @@ function inputsSelector(store, params, api, enabledForRows, enabledForColumns) {
|
|
|
590
535
|
api,
|
|
591
536
|
enabledForRows,
|
|
592
537
|
enabledForColumns,
|
|
593
|
-
autoHeight:
|
|
538
|
+
autoHeight: dimensions.autoHeight,
|
|
594
539
|
rowBufferPx: params.virtualization.rowBufferPx,
|
|
595
540
|
columnBufferPx: params.virtualization.columnBufferPx,
|
|
596
541
|
leftPinnedWidth: dimensions.leftPinnedWidth,
|
|
@@ -895,6 +840,24 @@ function getFirstNonSpannedColumnToRender({
|
|
|
895
840
|
}
|
|
896
841
|
return firstNonSpannedColumnToRender;
|
|
897
842
|
}
|
|
843
|
+
|
|
844
|
+
/** Placeholder API functions for colspan & rowspan to re-implement */
|
|
845
|
+
function createSpanningAPI() {
|
|
846
|
+
const getCellColSpanInfo = () => {
|
|
847
|
+
throw new Error('Unimplemented: colspan feature is required');
|
|
848
|
+
};
|
|
849
|
+
const calculateColSpan = () => {
|
|
850
|
+
throw new Error('Unimplemented: colspan feature is required');
|
|
851
|
+
};
|
|
852
|
+
const getHiddenCellsOrigin = () => {
|
|
853
|
+
throw new Error('Unimplemented: rowspan feature is required');
|
|
854
|
+
};
|
|
855
|
+
return {
|
|
856
|
+
getCellColSpanInfo,
|
|
857
|
+
calculateColSpan,
|
|
858
|
+
getHiddenCellsOrigin
|
|
859
|
+
};
|
|
860
|
+
}
|
|
898
861
|
function roundToDecimalPlaces(value, decimals) {
|
|
899
862
|
return Math.round(value * 10 ** decimals) / 10 ** decimals;
|
|
900
863
|
}
|
package/index.d.ts
CHANGED