UNPKG

@mui/x-data-grid

Version:

The Community plan edition of the MUI X Data Grid components.

223 lines (216 loc) 10.1 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import * as React from 'react'; import useEventCallback from '@mui/utils/useEventCallback'; import { useRtl } from '@mui/system/RtlProvider'; import { roundToDecimalPlaces } from '@mui/x-internals/math'; import { useStoreEffect } from '@mui/x-internals/store'; import { useVirtualizer } from '@mui/x-virtualizer'; import { useFirstRender } from "../utils/useFirstRender.js"; import { createSelector } from "../../utils/createSelector.js"; import { useGridSelector } from "../utils/useGridSelector.js"; import { gridContentHeightSelector, gridHasFillerSelector, gridVerticalScrollbarWidthSelector } from "../features/dimensions/gridDimensionsSelectors.js"; import { gridDensityFactorSelector } from "../features/density/index.js"; import { gridVisibleColumnDefinitionsSelector, gridVisiblePinnedColumnDefinitionsSelector, gridColumnPositionsSelector, gridHasColSpanSelector } from "../features/columns/gridColumnsSelector.js"; import { gridPinnedRowsSelector, gridRowCountSelector } from "../features/rows/gridRowsSelector.js"; import { useGridVisibleRows } from "../utils/useGridVisibleRows.js"; import { gridPaginationSelector } from "../features/pagination/index.js"; import { gridFocusedVirtualCellSelector } from "../features/virtualization/gridFocusedVirtualCellSelector.js"; import { gridRowSelectionManagerSelector } from "../features/rowSelection/index.js"; import { DATA_GRID_PROPS_DEFAULT_VALUES } from "../../constants/dataGridPropsDefaultValues.js"; import { getValidRowHeight, minimalContentHeight, rowHeightWarning } from "../features/rows/gridRowsUtils.js"; import { getTotalHeaderHeight } from "../features/columns/gridColumnsUtils.js"; import { jsx as _jsx } from "react/jsx-runtime"; function identity(x) { return x; } const columnsTotalWidthSelector = createSelector(gridVisibleColumnDefinitionsSelector, gridColumnPositionsSelector, (visibleColumns, positions) => { const colCount = visibleColumns.length; if (colCount === 0) { return 0; } return roundToDecimalPlaces(positions[colCount - 1] + visibleColumns[colCount - 1].computedWidth, 1); }); /** * Virtualizer setup */ export function useGridVirtualizer(apiRef, rootProps) { const isRtl = useRtl(); const { listView } = rootProps; const visibleColumns = useGridSelector(apiRef, gridVisibleColumnDefinitionsSelector); const pinnedRows = useGridSelector(apiRef, gridPinnedRowsSelector); const pinnedColumns = gridVisiblePinnedColumnDefinitionsSelector(apiRef); const rowSelectionManager = useGridSelector(apiRef, gridRowSelectionManagerSelector); const isRowSelected = id => rowSelectionManager.has(id) && apiRef.current.isRowSelectable(id); const currentPage = useGridVisibleRows(apiRef); const hasColSpan = useGridSelector(apiRef, gridHasColSpanSelector); /* TODO: extract dimensions code */ const contentHeight = useGridSelector(apiRef, gridContentHeightSelector); const verticalScrollbarWidth = useGridSelector(apiRef, gridVerticalScrollbarWidthSelector); const hasFiller = useGridSelector(apiRef, gridHasFillerSelector); const { autoHeight } = rootProps; const scrollReset = listView; // <DIMENSIONS> const density = useGridSelector(apiRef, gridDensityFactorSelector); const baseRowHeight = getValidRowHeight(rootProps.rowHeight, DATA_GRID_PROPS_DEFAULT_VALUES.rowHeight, rowHeightWarning); const rowHeight = Math.floor(baseRowHeight * density); const headerHeight = Math.floor(rootProps.columnHeaderHeight * density); const groupHeaderHeight = Math.floor((rootProps.columnGroupHeaderHeight ?? rootProps.columnHeaderHeight) * density); const headerFilterHeight = Math.floor((rootProps.headerFilterHeight ?? rootProps.columnHeaderHeight) * density); const columnsTotalWidth = useGridSelector(apiRef, columnsTotalWidthSelector); const headersTotalHeight = getTotalHeaderHeight(apiRef, rootProps); const leftPinnedWidth = pinnedColumns.left.reduce((w, col) => w + col.computedWidth, 0); const rightPinnedWidth = pinnedColumns.right.reduce((w, col) => w + col.computedWidth, 0); const dimensions = { rowHeight, headerHeight, groupHeaderHeight, headerFilterHeight, columnsTotalWidth, headersTotalHeight, leftPinnedWidth, rightPinnedWidth }; // </DIMENSIONS> // <ROWS_META> const dataRowCount = useGridSelector(apiRef, gridRowCountSelector); const pagination = useGridSelector(apiRef, gridPaginationSelector); const rowCount = Math.min(pagination.enabled ? pagination.paginationModel.pageSize : dataRowCount, dataRowCount); const { getRowHeight, getEstimatedRowHeight, getRowSpacing } = rootProps; // </ROWS_META> const focusedVirtualCell = useGridSelector(apiRef, gridFocusedVirtualCellSelector); const virtualizer = useVirtualizer({ scrollbarSize: rootProps.scrollbarSize, dimensions, initialState: { scroll: rootProps.initialState?.scroll, dimensions: apiRef.current.state.dimensions, rowSpanning: apiRef.current.state.rowSpanning, virtualization: apiRef.current.state.virtualization }, isRtl, rows: currentPage.rows, range: currentPage.range, rowIdToIndexMap: currentPage.rowIdToIndexMap, rowCount, columns: visibleColumns, pinnedRows, pinnedColumns, refs: { container: apiRef.current.mainElementRef, scroller: apiRef.current.virtualScrollerRef, scrollbarVertical: apiRef.current.virtualScrollbarVerticalRef, scrollbarHorizontal: apiRef.current.virtualScrollbarHorizontalRef }, hasColSpan, contentHeight, minimalContentHeight, autoHeight, getRowHeight: React.useMemo(() => { if (!getRowHeight) { return undefined; } return rowEntry => getRowHeight(_extends({}, rowEntry, { densityFactor: density })); }, [getRowHeight, density]), getEstimatedRowHeight: React.useMemo(() => getEstimatedRowHeight ? rowEntry => getEstimatedRowHeight(_extends({}, rowEntry, { densityFactor: density })) : undefined, [getEstimatedRowHeight, density]), getRowSpacing: React.useMemo(() => getRowSpacing ? (rowEntry, visibility) => getRowSpacing(_extends({}, rowEntry, visibility, { indexRelativeToCurrentPage: apiRef.current.getRowIndexRelativeToVisibleRows(rowEntry.id) })) : undefined, [apiRef, getRowSpacing]), applyRowHeight: useEventCallback((entry, row) => apiRef.current.unstable_applyPipeProcessors('rowHeight', entry, row)), virtualizeColumnsWithAutoRowHeight: rootProps.virtualizeColumnsWithAutoRowHeight, focusedVirtualCell: useEventCallback(() => focusedVirtualCell), rowBufferPx: rootProps.rowBufferPx, columnBufferPx: rootProps.columnBufferPx, resizeThrottleMs: rootProps.resizeThrottleMs, onResize: useEventCallback(size => apiRef.current.publishEvent('resize', size)), onWheel: useEventCallback(event => { apiRef.current.publishEvent('virtualScrollerWheel', {}, event); }), onTouchMove: useEventCallback(event => { apiRef.current.publishEvent('virtualScrollerTouchMove', {}, event); }), onRenderContextChange: useEventCallback(nextRenderContext => { apiRef.current.publishEvent('renderedRowsIntervalChange', nextRenderContext); }), onScrollChange: (scrollPosition, nextRenderContext) => { apiRef.current.publishEvent('scrollPositionChange', { top: scrollPosition.top, left: scrollPosition.left, renderContext: nextRenderContext }); }, scrollReset, getColspan: (rowId, column) => { if (typeof column.colSpan === 'function') { const row = apiRef.current.getRow(rowId); const value = apiRef.current.getRowValue(row, column); return column.colSpan(value, row, column, apiRef) ?? 0; } return column.colSpan ?? 0; }, renderRow: params => /*#__PURE__*/_jsx(rootProps.slots.row, _extends({ row: params.model, rowId: params.id, index: params.rowIndex, selected: isRowSelected(params.id), offsetLeft: params.offsetLeft, columnsTotalWidth: columnsTotalWidth, rowHeight: params.baseRowHeight, pinnedColumns: pinnedColumns, visibleColumns: params.columns, firstColumnIndex: params.firstColumnIndex, lastColumnIndex: params.lastColumnIndex, focusedColumnIndex: params.focusedColumnIndex, isFirstVisible: params.isFirstVisible, isLastVisible: params.isLastVisible, isNotVisible: params.isVirtualFocusRow, showBottomBorder: params.showBottomBorder, scrollbarWidth: verticalScrollbarWidth, gridHasFiller: hasFiller }, rootProps.slotProps?.row), params.id), renderInfiniteLoadingTrigger: id => apiRef.current.getInfiniteLoadingTriggerElement?.({ lastRowId: id }) }); // HACK: Keep the grid's store in sync with the virtualizer store. We set up the // subscription in the render phase rather than in an effect because other grid // initialization code runs between those two moments. // // TODO(v9): Remove this useFirstRender(() => { apiRef.current.store.state.dimensions = virtualizer.store.state.dimensions; apiRef.current.store.state.rowsMeta = virtualizer.store.state.rowsMeta; apiRef.current.store.state.virtualization = virtualizer.store.state.virtualization; }); useStoreEffect(virtualizer.store, identity, (_, state) => { if (state.dimensions !== apiRef.current.state.dimensions) { apiRef.current.setState(gridState => _extends({}, gridState, { dimensions: state.dimensions })); } if (state.rowsMeta !== apiRef.current.state.rowsMeta) { apiRef.current.setState(gridState => _extends({}, gridState, { rowsMeta: state.rowsMeta })); } if (state.virtualization !== apiRef.current.state.virtualization) { apiRef.current.setState(gridState => _extends({}, gridState, { virtualization: state.virtualization })); } }); apiRef.current.register('private', { virtualizer }); }