@mui/x-data-grid
Version:
The community edition of the data grid component (MUI X).
224 lines (219 loc) • 10.8 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useGridDimensions = useGridDimensions;
var React = _interopRequireWildcard(require("react"));
var _utils = require("@mui/utils");
var _useGridApiEventHandler = require("../../utils/useGridApiEventHandler");
var _useGridApiMethod = require("../../utils/useGridApiMethod");
var _useGridLogger = require("../../utils/useGridLogger");
var _columns = require("../columns");
var _density = require("../density");
var _utils2 = require("../../utils");
var _useGridVisibleRows = require("../../utils/useGridVisibleRows");
var _gridRowsMetaSelector = require("../rows/gridRowsMetaSelector");
var _gridRowsUtils = require("../rows/gridRowsUtils");
var _gridColumnsUtils = require("../columns/gridColumnsUtils");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
const isTestEnvironment = process.env.NODE_ENV === 'test';
const hasScroll = ({
content,
container,
scrollBarSize
}) => {
const hasScrollXIfNoYScrollBar = content.width > container.width;
const hasScrollYIfNoXScrollBar = content.height > container.height;
let hasScrollX = false;
let hasScrollY = false;
if (hasScrollXIfNoYScrollBar || hasScrollYIfNoXScrollBar) {
hasScrollX = hasScrollXIfNoYScrollBar;
hasScrollY = content.height + (hasScrollX ? scrollBarSize : 0) > container.height;
// We recalculate the scroll x to consider the size of the y scrollbar.
if (hasScrollY) {
hasScrollX = content.width + scrollBarSize > container.width;
}
}
return {
hasScrollX,
hasScrollY
};
};
function useGridDimensions(apiRef, props) {
const logger = (0, _useGridLogger.useGridLogger)(apiRef, 'useResizeContainer');
const errorShown = React.useRef(false);
const rootDimensionsRef = React.useRef(null);
const fullDimensionsRef = React.useRef(null);
const rowsMeta = (0, _utils2.useGridSelector)(apiRef, _gridRowsMetaSelector.gridRowsMetaSelector);
const densityFactor = (0, _utils2.useGridSelector)(apiRef, _density.gridDensityFactorSelector);
const rowHeight = Math.floor(props.rowHeight * densityFactor);
const totalHeaderHeight = (0, _gridColumnsUtils.getTotalHeaderHeight)(apiRef, props.columnHeaderHeight);
const updateGridDimensionsRef = React.useCallback(() => {
const rootElement = apiRef.current.rootElementRef?.current;
const columnsTotalWidth = (0, _columns.gridColumnsTotalWidthSelector)(apiRef);
const pinnedRowsHeight = (0, _gridRowsUtils.calculatePinnedRowsHeight)(apiRef);
if (!rootDimensionsRef.current) {
return;
}
let scrollBarSize;
if (props.scrollbarSize != null) {
scrollBarSize = props.scrollbarSize;
} else if (!columnsTotalWidth || !rootElement) {
scrollBarSize = 0;
} else {
const doc = (0, _utils.unstable_ownerDocument)(rootElement);
const scrollDiv = doc.createElement('div');
scrollDiv.style.width = '99px';
scrollDiv.style.height = '99px';
scrollDiv.style.position = 'absolute';
scrollDiv.style.overflow = 'scroll';
scrollDiv.className = 'scrollDiv';
rootElement.appendChild(scrollDiv);
scrollBarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth;
rootElement.removeChild(scrollDiv);
}
let viewportOuterSize;
let hasScrollX;
let hasScrollY;
if (props.autoHeight) {
hasScrollY = false;
hasScrollX = Math.round(columnsTotalWidth) > Math.round(rootDimensionsRef.current.width);
viewportOuterSize = {
width: rootDimensionsRef.current.width,
height: rowsMeta.currentPageTotalHeight + (hasScrollX ? scrollBarSize : 0)
};
} else {
viewportOuterSize = {
width: rootDimensionsRef.current.width,
height: Math.max(rootDimensionsRef.current.height - totalHeaderHeight, 0)
};
const scrollInformation = hasScroll({
content: {
width: Math.round(columnsTotalWidth),
height: rowsMeta.currentPageTotalHeight
},
container: {
width: Math.round(viewportOuterSize.width),
height: viewportOuterSize.height - pinnedRowsHeight.top - pinnedRowsHeight.bottom
},
scrollBarSize
});
hasScrollY = scrollInformation.hasScrollY;
hasScrollX = scrollInformation.hasScrollX;
}
const viewportInnerSize = {
width: viewportOuterSize.width - (hasScrollY ? scrollBarSize : 0),
height: viewportOuterSize.height - (hasScrollX ? scrollBarSize : 0)
};
const newFullDimensions = {
viewportOuterSize,
viewportInnerSize,
hasScrollX,
hasScrollY,
scrollBarSize
};
const prevDimensions = fullDimensionsRef.current;
fullDimensionsRef.current = newFullDimensions;
if (newFullDimensions.viewportInnerSize.width !== prevDimensions?.viewportInnerSize.width || newFullDimensions.viewportInnerSize.height !== prevDimensions?.viewportInnerSize.height) {
apiRef.current.publishEvent('viewportInnerSizeChange', newFullDimensions.viewportInnerSize);
}
}, [apiRef, props.scrollbarSize, props.autoHeight, rowsMeta.currentPageTotalHeight, totalHeaderHeight]);
const [savedSize, setSavedSize] = React.useState();
const debouncedSetSavedSize = React.useMemo(() => (0, _utils.unstable_debounce)(setSavedSize, 60), []);
const previousSize = React.useRef();
(0, _utils.unstable_useEnhancedEffect)(() => {
if (savedSize) {
updateGridDimensionsRef();
apiRef.current.publishEvent('debouncedResize', rootDimensionsRef.current);
}
}, [apiRef, savedSize, updateGridDimensionsRef]);
// This is the function called by apiRef.current.resize()
const resize = React.useCallback(() => {
apiRef.current.computeSizeAndPublishResizeEvent();
}, [apiRef]);
const getRootDimensions = React.useCallback(() => fullDimensionsRef.current, []);
const getViewportPageSize = React.useCallback(() => {
const dimensions = apiRef.current.getRootDimensions();
if (!dimensions) {
return 0;
}
const currentPage = (0, _useGridVisibleRows.getVisibleRows)(apiRef, {
pagination: props.pagination,
paginationMode: props.paginationMode
});
// TODO: Use a combination of scrollTop, dimensions.viewportInnerSize.height and rowsMeta.possitions
// to find out the maximum number of rows that can fit in the visible part of the grid
if (props.getRowHeight) {
const renderContext = apiRef.current.getRenderContext();
const viewportPageSize = renderContext.lastRowIndex - renderContext.firstRowIndex;
return Math.min(viewportPageSize - 1, currentPage.rows.length);
}
const maximumPageSizeWithoutScrollBar = Math.floor(dimensions.viewportInnerSize.height / rowHeight);
return Math.min(maximumPageSizeWithoutScrollBar, currentPage.rows.length);
}, [apiRef, props.pagination, props.paginationMode, props.getRowHeight, rowHeight]);
const computeSizeAndPublishResizeEvent = React.useCallback(() => {
const mainEl = apiRef.current.mainElementRef?.current;
if (!mainEl) {
return;
}
const win = (0, _utils.unstable_ownerWindow)(mainEl);
const computedStyle = win.getComputedStyle(mainEl);
const height = parseFloat(computedStyle.height) || 0;
const width = parseFloat(computedStyle.width) || 0;
const hasHeightChanged = height !== previousSize.current?.height;
const hasWidthChanged = width !== previousSize.current?.width;
if (!previousSize.current || hasHeightChanged || hasWidthChanged) {
const size = {
width,
height
};
apiRef.current.publishEvent('resize', size);
previousSize.current = size;
}
}, [apiRef]);
const dimensionsApi = {
resize,
getRootDimensions
};
const dimensionsPrivateApi = {
getViewportPageSize,
updateGridDimensionsRef,
computeSizeAndPublishResizeEvent
};
(0, _useGridApiMethod.useGridApiMethod)(apiRef, dimensionsApi, 'public');
(0, _useGridApiMethod.useGridApiMethod)(apiRef, dimensionsPrivateApi, 'private');
const isFirstSizing = React.useRef(true);
const handleResize = React.useCallback(size => {
rootDimensionsRef.current = size;
// jsdom has no layout capabilities
const isJSDOM = /jsdom/.test(window.navigator.userAgent);
if (size.height === 0 && !errorShown.current && !props.autoHeight && !isJSDOM) {
logger.error(['The parent DOM element of the data grid has an empty height.', 'Please make sure that this element has an intrinsic height.', 'The grid displays with a height of 0px.', '', 'More details: https://mui.com/r/x-data-grid-no-dimensions.'].join('\n'));
errorShown.current = true;
}
if (size.width === 0 && !errorShown.current && !isJSDOM) {
logger.error(['The parent DOM element of the data grid has an empty width.', 'Please make sure that this element has an intrinsic width.', 'The grid displays with a width of 0px.', '', 'More details: https://mui.com/r/x-data-grid-no-dimensions.'].join('\n'));
errorShown.current = true;
}
if (isTestEnvironment) {
// We don't need to debounce the resize for tests.
setSavedSize(size);
isFirstSizing.current = false;
return;
}
if (isFirstSizing.current) {
// We want to initialize the grid dimensions as soon as possible to avoid flickering
setSavedSize(size);
isFirstSizing.current = false;
return;
}
debouncedSetSavedSize(size);
}, [props.autoHeight, debouncedSetSavedSize, logger]);
(0, _utils.unstable_useEnhancedEffect)(() => updateGridDimensionsRef(), [updateGridDimensionsRef]);
(0, _useGridApiEventHandler.useGridApiOptionHandler)(apiRef, 'sortedRowsSet', updateGridDimensionsRef);
(0, _useGridApiEventHandler.useGridApiOptionHandler)(apiRef, 'paginationModelChange', updateGridDimensionsRef);
(0, _useGridApiEventHandler.useGridApiOptionHandler)(apiRef, 'columnsChange', updateGridDimensionsRef);
(0, _useGridApiEventHandler.useGridApiEventHandler)(apiRef, 'resize', handleResize);
(0, _useGridApiEventHandler.useGridApiOptionHandler)(apiRef, 'debouncedResize', props.onResize);
}
;