UNPKG

@mui/x-data-grid

Version:

The community edition of the data grid component (MUI X).

387 lines (382 loc) 18.2 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { unstable_useForkRef as useForkRef } from '@mui/utils'; import { styled, useTheme } from '@mui/material/styles'; import { defaultMemoize } from 'reselect'; import { useGridSelector } from '../../utils'; import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext'; import { useGridRootProps } from '../../utils/useGridRootProps'; import { useGridApiEventHandler } from '../../utils/useGridApiEventHandler'; import { GridColumnHeaderItem } from '../../../components/columnHeaders/GridColumnHeaderItem'; import { getFirstColumnIndexToRender, getTotalHeaderHeight } from '../columns/gridColumnsUtils'; import { useGridVisibleRows } from '../../utils/useGridVisibleRows'; import { areRenderContextsEqual, getRenderableIndexes } from '../virtualization/useGridVirtualScroller'; import { gridVirtualizationColumnEnabledSelector } from '../virtualization'; import { GridColumnGroupHeader } from '../../../components/columnHeaders/GridColumnGroupHeader'; import { jsx as _jsx } from "react/jsx-runtime"; var GridColumnHeaderRow = styled('div', { name: 'MuiDataGrid', slot: 'ColumnHeaderRow', overridesResolver: function overridesResolver(props, styles) { return styles.columnHeaderRow; } })(function () { return { display: 'flex' }; }); function isUIEvent(event) { return !!event.target; } export var useGridColumnHeaders = function useGridColumnHeaders(props) { var innerRefProp = props.innerRef, _props$minColumnIndex = props.minColumnIndex, minColumnIndex = _props$minColumnIndex === void 0 ? 0 : _props$minColumnIndex, visibleColumns = props.visibleColumns, sortColumnLookup = props.sortColumnLookup, filterColumnLookup = props.filterColumnLookup, columnPositions = props.columnPositions, columnHeaderTabIndexState = props.columnHeaderTabIndexState, columnGroupHeaderTabIndexState = props.columnGroupHeaderTabIndexState, columnHeaderFocus = props.columnHeaderFocus, columnGroupHeaderFocus = props.columnGroupHeaderFocus, densityFactor = props.densityFactor, headerGroupingMaxDepth = props.headerGroupingMaxDepth, columnMenuState = props.columnMenuState, columnVisibility = props.columnVisibility, columnGroupsHeaderStructure = props.columnGroupsHeaderStructure, hasOtherElementInTabSequence = props.hasOtherElementInTabSequence; var theme = useTheme(); var _React$useState = React.useState(''), _React$useState2 = _slicedToArray(_React$useState, 2), dragCol = _React$useState2[0], setDragCol = _React$useState2[1]; var _React$useState3 = React.useState(''), _React$useState4 = _slicedToArray(_React$useState3, 2), resizeCol = _React$useState4[0], setResizeCol = _React$useState4[1]; var apiRef = useGridPrivateApiContext(); var hasVirtualization = useGridSelector(apiRef, gridVirtualizationColumnEnabledSelector); var rootProps = useGridRootProps(); var innerRef = React.useRef(null); var handleInnerRef = useForkRef(innerRefProp, innerRef); var _React$useState5 = React.useState(null), _React$useState6 = _slicedToArray(_React$useState5, 2), renderContext = _React$useState6[0], setRenderContextRaw = _React$useState6[1]; var prevRenderContext = React.useRef(renderContext); var prevScrollLeft = React.useRef(0); var currentPage = useGridVisibleRows(apiRef, rootProps); var totalHeaderHeight = getTotalHeaderHeight(apiRef, rootProps.columnHeaderHeight); var headerHeight = Math.floor(rootProps.columnHeaderHeight * densityFactor); var setRenderContext = React.useCallback(function (nextRenderContext) { if (renderContext && nextRenderContext && areRenderContextsEqual(renderContext, nextRenderContext)) { return; } setRenderContextRaw(nextRenderContext); }, [renderContext]); React.useEffect(function () { apiRef.current.columnHeadersContainerElementRef.current.scrollLeft = 0; }, [apiRef]); // memoize `getFirstColumnIndexToRender`, since it's called on scroll var getFirstColumnIndexToRenderRef = React.useRef(defaultMemoize(getFirstColumnIndexToRender, { equalityCheck: function equalityCheck(a, b) { return ['firstColumnIndex', 'minColumnIndex', 'columnBuffer'].every(function (key) { return a[key] === b[key]; }); } })); var updateInnerPosition = React.useCallback(function (nextRenderContext) { var _getRenderableIndexes = getRenderableIndexes({ firstIndex: nextRenderContext.firstRowIndex, lastIndex: nextRenderContext.lastRowIndex, minFirstIndex: 0, maxLastIndex: currentPage.rows.length, buffer: rootProps.rowBuffer }), _getRenderableIndexes2 = _slicedToArray(_getRenderableIndexes, 2), firstRowToRender = _getRenderableIndexes2[0], lastRowToRender = _getRenderableIndexes2[1]; var firstColumnToRender = getFirstColumnIndexToRenderRef.current({ firstColumnIndex: nextRenderContext.firstColumnIndex, minColumnIndex: minColumnIndex, columnBuffer: rootProps.columnBuffer, firstRowToRender: firstRowToRender, lastRowToRender: lastRowToRender, apiRef: apiRef, visibleRows: currentPage.rows }); var direction = theme.direction === 'ltr' ? 1 : -1; var offset = firstColumnToRender > 0 ? prevScrollLeft.current - direction * columnPositions[firstColumnToRender] : prevScrollLeft.current; innerRef.current.style.transform = "translate3d(".concat(-offset, "px, 0px, 0px)"); }, [columnPositions, minColumnIndex, rootProps.columnBuffer, apiRef, currentPage.rows, rootProps.rowBuffer, theme.direction]); React.useLayoutEffect(function () { if (renderContext) { updateInnerPosition(renderContext); } }, [renderContext, updateInnerPosition]); var handleScroll = React.useCallback(function (_ref, event) { var _prevRenderContext$cu, _prevRenderContext$cu2; var left = _ref.left, _ref$renderContext = _ref.renderContext, nextRenderContext = _ref$renderContext === void 0 ? null : _ref$renderContext; if (!innerRef.current) { return; } // Ignore vertical scroll. // Excepts the first event which sets the previous render context. if (prevScrollLeft.current === left && ((_prevRenderContext$cu = prevRenderContext.current) == null ? void 0 : _prevRenderContext$cu.firstColumnIndex) === (nextRenderContext == null ? void 0 : nextRenderContext.firstColumnIndex) && ((_prevRenderContext$cu2 = prevRenderContext.current) == null ? void 0 : _prevRenderContext$cu2.lastColumnIndex) === (nextRenderContext == null ? void 0 : nextRenderContext.lastColumnIndex)) { return; } prevScrollLeft.current = left; // We can only update the position when we guarantee that the render context has been // rendered. This is achieved using ReactDOM.flushSync or when the context doesn't change. var canUpdateInnerPosition = false; if (nextRenderContext !== prevRenderContext.current || !prevRenderContext.current) { // ReactDOM.flushSync cannot be called on `scroll` events fired inside effects if (isUIEvent(event)) { // To prevent flickering, the inner position can only be updated after the new context has // been rendered. ReactDOM.flushSync ensures that the state changes will happen before // updating the position. ReactDOM.flushSync(function () { setRenderContext(nextRenderContext); }); canUpdateInnerPosition = true; } else { setRenderContext(nextRenderContext); } prevRenderContext.current = nextRenderContext; } else { canUpdateInnerPosition = true; } // Pass directly the render context to avoid waiting for the next render if (nextRenderContext && canUpdateInnerPosition) { updateInnerPosition(nextRenderContext); } }, [updateInnerPosition, setRenderContext]); var handleColumnResizeStart = React.useCallback(function (params) { return setResizeCol(params.field); }, []); var handleColumnResizeStop = React.useCallback(function () { return setResizeCol(''); }, []); var handleColumnReorderStart = React.useCallback(function (params) { return setDragCol(params.field); }, []); var handleColumnReorderStop = React.useCallback(function () { return setDragCol(''); }, []); useGridApiEventHandler(apiRef, 'columnResizeStart', handleColumnResizeStart); useGridApiEventHandler(apiRef, 'columnResizeStop', handleColumnResizeStop); useGridApiEventHandler(apiRef, 'columnHeaderDragStart', handleColumnReorderStart); useGridApiEventHandler(apiRef, 'columnHeaderDragEnd', handleColumnReorderStop); useGridApiEventHandler(apiRef, 'scrollPositionChange', handleScroll); // Helper for computation common between getColumnHeaders and getColumnGroupHeaders var getColumnsToRender = function getColumnsToRender(params) { var _ref2 = params || {}, _ref2$renderContext = _ref2.renderContext, nextRenderContext = _ref2$renderContext === void 0 ? renderContext : _ref2$renderContext, _ref2$minFirstColumn = _ref2.minFirstColumn, minFirstColumn = _ref2$minFirstColumn === void 0 ? minColumnIndex : _ref2$minFirstColumn, _ref2$maxLastColumn = _ref2.maxLastColumn, maxLastColumn = _ref2$maxLastColumn === void 0 ? visibleColumns.length : _ref2$maxLastColumn; if (!nextRenderContext) { return null; } var _getRenderableIndexes3 = getRenderableIndexes({ firstIndex: nextRenderContext.firstRowIndex, lastIndex: nextRenderContext.lastRowIndex, minFirstIndex: 0, maxLastIndex: currentPage.rows.length, buffer: rootProps.rowBuffer }), _getRenderableIndexes4 = _slicedToArray(_getRenderableIndexes3, 2), firstRowToRender = _getRenderableIndexes4[0], lastRowToRender = _getRenderableIndexes4[1]; var firstColumnToRender = !hasVirtualization ? 0 : getFirstColumnIndexToRenderRef.current({ firstColumnIndex: nextRenderContext.firstColumnIndex, minColumnIndex: minFirstColumn, columnBuffer: rootProps.columnBuffer, apiRef: apiRef, firstRowToRender: firstRowToRender, lastRowToRender: lastRowToRender, visibleRows: currentPage.rows }); var lastColumnToRender = !hasVirtualization ? maxLastColumn : Math.min(nextRenderContext.lastColumnIndex + rootProps.columnBuffer, maxLastColumn); var renderedColumns = visibleColumns.slice(firstColumnToRender, lastColumnToRender); return { renderedColumns: renderedColumns, firstColumnToRender: firstColumnToRender, lastColumnToRender: lastColumnToRender, minFirstColumn: minFirstColumn, maxLastColumn: maxLastColumn }; }; var getColumnHeaders = function getColumnHeaders(params) { var other = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var columnsToRender = getColumnsToRender(params); if (columnsToRender == null) { return null; } var renderedColumns = columnsToRender.renderedColumns, firstColumnToRender = columnsToRender.firstColumnToRender; var columns = []; for (var i = 0; i < renderedColumns.length; i += 1) { var colDef = renderedColumns[i]; var columnIndex = firstColumnToRender + i; var isFirstColumn = columnIndex === 0; var tabIndex = columnHeaderTabIndexState !== null && columnHeaderTabIndexState.field === colDef.field || isFirstColumn && !hasOtherElementInTabSequence ? 0 : -1; var hasFocus = columnHeaderFocus !== null && columnHeaderFocus.field === colDef.field; var open = columnMenuState.open && columnMenuState.field === colDef.field; columns.push( /*#__PURE__*/_jsx(GridColumnHeaderItem, _extends({}, sortColumnLookup[colDef.field], { columnMenuOpen: open, filterItemsCounter: filterColumnLookup[colDef.field] && filterColumnLookup[colDef.field].length, headerHeight: headerHeight, isDragging: colDef.field === dragCol, colDef: colDef, colIndex: columnIndex, isResizing: resizeCol === colDef.field, hasFocus: hasFocus, tabIndex: tabIndex }, other), colDef.field)); } return /*#__PURE__*/_jsx(GridColumnHeaderRow, { role: "row", "aria-rowindex": headerGroupingMaxDepth + 1, ownerState: rootProps, children: columns }); }; var getColumnGroupHeaders = function getColumnGroupHeaders(params) { if (headerGroupingMaxDepth === 0) { return null; } var columnsToRender = getColumnsToRender(params); if (columnsToRender == null || columnsToRender.renderedColumns.length === 0) { return null; } var firstColumnToRender = columnsToRender.firstColumnToRender, lastColumnToRender = columnsToRender.lastColumnToRender; var columns = []; var headerToRender = []; var _loop = function _loop(depth) { var _apiRef$current$unsta, _apiRef$current$unsta2; var rowStructure = columnGroupsHeaderStructure[depth]; var firstColumnFieldToRender = visibleColumns[firstColumnToRender].field; var firstGroupToRender = (_apiRef$current$unsta = apiRef.current.unstable_getColumnGroupPath(firstColumnFieldToRender)[depth]) != null ? _apiRef$current$unsta : null; var firstGroupIndex = rowStructure.findIndex(function (_ref4) { var groupId = _ref4.groupId, columnFields = _ref4.columnFields; return groupId === firstGroupToRender && columnFields.includes(firstColumnFieldToRender); }); var lastColumnFieldToRender = visibleColumns[lastColumnToRender - 1].field; var lastGroupToRender = (_apiRef$current$unsta2 = apiRef.current.unstable_getColumnGroupPath(lastColumnFieldToRender)[depth]) != null ? _apiRef$current$unsta2 : null; var lastGroupIndex = rowStructure.findIndex(function (_ref5) { var groupId = _ref5.groupId, columnFields = _ref5.columnFields; return groupId === lastGroupToRender && columnFields.includes(lastColumnFieldToRender); }); var visibleColumnGroupHeader = rowStructure.slice(firstGroupIndex, lastGroupIndex + 1).map(function (groupStructure) { return _extends({}, groupStructure, { columnFields: groupStructure.columnFields.filter(function (field) { return columnVisibility[field] !== false; }) }); }).filter(function (groupStructure) { return groupStructure.columnFields.length > 0; }); var firstVisibleColumnIndex = visibleColumnGroupHeader[0].columnFields.indexOf(firstColumnFieldToRender); var hiddenGroupColumns = visibleColumnGroupHeader[0].columnFields.slice(0, firstVisibleColumnIndex); var leftOverflow = hiddenGroupColumns.reduce(function (acc, field) { var _column$computedWidth; var column = apiRef.current.getColumn(field); return acc + ((_column$computedWidth = column.computedWidth) != null ? _column$computedWidth : 0); }, 0); var columnIndex = firstColumnToRender; var elements = visibleColumnGroupHeader.map(function (_ref6) { var groupId = _ref6.groupId, columnFields = _ref6.columnFields; var hasFocus = columnGroupHeaderFocus !== null && columnGroupHeaderFocus.depth === depth && columnFields.includes(columnGroupHeaderFocus.field); var tabIndex = columnGroupHeaderTabIndexState !== null && columnGroupHeaderTabIndexState.depth === depth && columnFields.includes(columnGroupHeaderTabIndexState.field) ? 0 : -1; var headerInfo = { groupId: groupId, width: columnFields.reduce(function (acc, field) { return acc + apiRef.current.getColumn(field).computedWidth; }, 0), fields: columnFields, colIndex: columnIndex, hasFocus: hasFocus, tabIndex: tabIndex }; columnIndex += columnFields.length; return headerInfo; }); headerToRender.push({ leftOverflow: leftOverflow, elements: elements }); }; for (var depth = 0; depth < headerGroupingMaxDepth; depth += 1) { _loop(depth); } headerToRender.forEach(function (depthInfo, depthIndex) { columns.push( /*#__PURE__*/_jsx(GridColumnHeaderRow, { style: { height: "".concat(headerHeight, "px"), transform: "translateX(-".concat(depthInfo.leftOverflow, "px)") }, role: "row", "aria-rowindex": depthIndex + 1, ownerState: rootProps, children: depthInfo.elements.map(function (_ref3, groupIndex) { var groupId = _ref3.groupId, width = _ref3.width, fields = _ref3.fields, colIndex = _ref3.colIndex, hasFocus = _ref3.hasFocus, tabIndex = _ref3.tabIndex; return /*#__PURE__*/_jsx(GridColumnGroupHeader, { groupId: groupId, width: width, fields: fields, colIndex: colIndex, depth: depthIndex, isLastColumn: colIndex === visibleColumns.length - fields.length, maxDepth: headerToRender.length, height: headerHeight, hasFocus: hasFocus, tabIndex: tabIndex }, groupIndex); }) }, depthIndex)); }); return columns; }; var rootStyle = { minHeight: totalHeaderHeight, maxHeight: totalHeaderHeight, lineHeight: "".concat(headerHeight, "px") }; return { renderContext: renderContext, getColumnHeaders: getColumnHeaders, getColumnsToRender: getColumnsToRender, getColumnGroupHeaders: getColumnGroupHeaders, isDragging: !!dragCol, getRootProps: function getRootProps() { var other = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; return _extends({ style: rootStyle }, other); }, getInnerProps: function getInnerProps() { return { ref: handleInnerRef, role: 'rowgroup' }; }, headerHeight: headerHeight }; };