@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.
Files changed (46) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/constants.d.ts +22 -0
  3. package/constants.js +26 -0
  4. package/esm/constants.d.ts +22 -0
  5. package/esm/constants.js +20 -0
  6. package/esm/features/colspan.d.ts +4 -4
  7. package/esm/features/dimensions.d.ts +14 -8
  8. package/esm/features/dimensions.js +26 -7
  9. package/esm/features/index.d.ts +1 -1
  10. package/esm/features/index.js +1 -1
  11. package/esm/features/keyboard.d.ts +3 -3
  12. package/esm/features/keyboard.js +1 -1
  13. package/esm/features/rowspan.d.ts +4 -4
  14. package/esm/features/virtualization/index.d.ts +2 -0
  15. package/esm/features/virtualization/index.js +2 -0
  16. package/esm/features/virtualization/layout.d.ts +129 -0
  17. package/esm/features/virtualization/layout.js +152 -0
  18. package/esm/features/{virtualization.d.ts → virtualization/virtualization.d.ts} +35 -58
  19. package/esm/features/{virtualization.js → virtualization/virtualization.js} +97 -134
  20. package/esm/index.d.ts +2 -1
  21. package/esm/index.js +3 -2
  22. package/esm/models/core.d.ts +7 -0
  23. package/esm/models/core.js +7 -0
  24. package/esm/models/dimensions.d.ts +8 -0
  25. package/esm/useVirtualizer.d.ts +25 -69
  26. package/esm/useVirtualizer.js +21 -4
  27. package/features/colspan.d.ts +4 -4
  28. package/features/dimensions.d.ts +14 -8
  29. package/features/dimensions.js +26 -7
  30. package/features/index.d.ts +1 -1
  31. package/features/keyboard.d.ts +3 -3
  32. package/features/rowspan.d.ts +4 -4
  33. package/features/virtualization/index.d.ts +2 -0
  34. package/features/virtualization/index.js +27 -0
  35. package/features/virtualization/layout.d.ts +129 -0
  36. package/features/virtualization/layout.js +163 -0
  37. package/features/{virtualization.d.ts → virtualization/virtualization.d.ts} +35 -58
  38. package/features/{virtualization.js → virtualization/virtualization.js} +97 -134
  39. package/index.d.ts +2 -1
  40. package/index.js +12 -1
  41. package/models/core.d.ts +7 -0
  42. package/models/core.js +8 -1
  43. package/models/dimensions.d.ts +8 -0
  44. package/package.json +2 -2
  45. package/useVirtualizer.d.ts +25 -69
  46. 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 "../models/colspan.js";
5
- import { Dimensions } from "./dimensions.js";
6
- import type { BaseState, VirtualizerParams } from "../useVirtualizer.js";
7
- import { PinnedRowPosition, RenderContext, ColumnsRenderContext, ColumnWithWidth, RowId, RowEntry } from "../models/index.js";
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: VirtualizerParams): Virtualization.State;
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
- declare function useVirtualization(store: Store<BaseState>, params: VirtualizerParams, api: RequiredAPI): {
56
- getters: {
57
- setPanels: React.Dispatch<React.SetStateAction<Readonly<Map<any, React.ReactNode>>>>;
58
- getOffsetTop: () => number;
59
- getRows: (rowParams?: {
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("../models/core");
25
- var _dimensions = require("./dimensions");
26
- var _models = require("../models");
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
- store: (0, _store.createSelector)(state => state.virtualization),
44
- renderContext: (0, _store.createSelector)(state => state.virtualization.renderContext),
45
- enabledForRows: (0, _store.createSelector)(state => state.virtualization.enabledForRows),
46
- enabledForColumns: (0, _store.createSelector)(state => state.virtualization.enabledForColumns)
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
- refs,
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
- const refSetter = name => node => {
462
- if (node && refs[name].current !== node) {
463
- refs[name].current = node;
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 containerCleanup = React.useRef(undefined);
468
- const containerRef = (0, _useEventCallback.default)(node => {
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
- containerCleanup.current = () => {
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 scrollerCleanup = React.useRef(undefined);
498
- const scrollerRef = (0, _useEventCallback.default)(node => {
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
- scrollerCleanup.current = () => {
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 scrollbarVerticalRef = (0, _useEventCallback.default)(refSetter('scrollbarVertical'));
524
- const scrollbarHorizontalRef = (0, _useEventCallback.default)(refSetter('scrollbarHorizontal'));
525
- const getters = {
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
- getContainerProps: () => ({
531
- ref: containerRef
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
- getCellColSpanInfo,
577
- calculateColSpan,
578
- getHiddenCellsOrigin
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: params.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
@@ -1,2 +1,3 @@
1
1
  export * from "./useVirtualizer.js";
2
- export * from "./features/index.js";
2
+ export * from "./features/index.js";
3
+ export * from "./constants.js";