@mui/x-data-grid
Version:
The Community plan edition of the MUI X Data Grid components.
122 lines (121 loc) • 5.7 kB
JavaScript
'use client';
import * as React from 'react';
import { styled } from '@mui/system';
import { useRtl } from '@mui/system/RtlProvider';
import composeClasses from '@mui/utils/composeClasses';
import { gridDimensionsSelector, gridPinnedColumnsSelector, useGridEvent, useGridSelector } from "../hooks/index.js";
import { gridPinnedRowsSelector } from "../hooks/features/rows/gridRowsSelector.js";
import { useGridRootProps } from "../hooks/utils/useGridRootProps.js";
import { vars } from "../constants/cssVariables.js";
import { useGridPrivateApiContext } from "../hooks/utils/useGridPrivateApiContext.js";
import { gridHasScrollXSelector, gridHasScrollYSelector } from "../hooks/features/dimensions/gridDimensionsSelectors.js";
import { getDataGridUtilityClass } from "../constants/index.js";
import { jsx as _jsx } from "react/jsx-runtime";
const useUtilityClasses = ownerState => {
const {
classes,
position
} = ownerState;
const slots = {
root: ['scrollShadow', `scrollShadow--${position}`]
};
return composeClasses(slots, getDataGridUtilityClass, classes);
};
const ScrollShadow = styled('div', {
name: 'MuiDataGrid',
slot: 'ScrollShadow',
overridesResolver: (props, styles) => [styles.root, styles[props.position]]
})(({
theme
}) => ({
position: 'absolute',
inset: 0,
pointerEvents: 'none',
transition: vars.transition(['box-shadow'], {
duration: vars.transitions.duration.short
}),
'--length': theme.palette.mode === 'dark' ? '8px' : '6px',
'--length-inverse': 'calc(var(--length) * -1)',
'--opacity': theme.palette.mode === 'dark' ? '0.7' : '0.18',
'--blur': 'var(--length)',
'--spread': 'calc(var(--length) * -1)',
'--color': '0, 0, 0',
'--color-start': 'rgba(var(--color), calc(var(--hasScrollStart) * var(--opacity)))',
'--color-end': 'rgba(var(--color), calc(var(--hasScrollEnd) * var(--opacity)))',
variants: [{
props: {
position: 'vertical'
},
style: {
top: 'var(--DataGrid-topContainerHeight)',
bottom: 'calc(var(--DataGrid-bottomContainerHeight) + var(--DataGrid-hasScrollX) * var(--DataGrid-scrollbarSize))',
boxShadow: 'inset 0 var(--length) var(--blur) var(--spread) var(--color-start), inset 0 var(--length-inverse) var(--blur) var(--spread) var(--color-end)'
}
}, {
props: {
position: 'horizontal'
},
style: {
left: 'var(--DataGrid-leftPinnedWidth)',
right: 'calc(var(--DataGrid-rightPinnedWidth) + var(--DataGrid-hasScrollY) * var(--DataGrid-scrollbarSize))',
boxShadow: 'inset var(--length) 0 var(--blur) var(--spread) var(--color-start), inset var(--length-inverse) 0 var(--blur) var(--spread) var(--color-end)'
}
}]
}));
function GridScrollShadows(props) {
const {
position
} = props;
const rootProps = useGridRootProps();
const ownerState = {
classes: rootProps.classes,
position
};
const classes = useUtilityClasses(ownerState);
const ref = React.useRef(null);
const apiRef = useGridPrivateApiContext();
const hasScrollX = useGridSelector(apiRef, gridHasScrollXSelector);
const hasScrollY = useGridSelector(apiRef, gridHasScrollYSelector);
const pinnedRows = useGridSelector(apiRef, gridPinnedRowsSelector);
const pinnedColumns = useGridSelector(apiRef, gridPinnedColumnsSelector);
const initialScrollable = position === 'vertical' ? hasScrollY && pinnedRows?.bottom?.length > 0 : hasScrollX && pinnedColumns?.right?.length !== undefined && pinnedColumns?.right?.length > 0;
const isRtl = useRtl();
const updateScrollShadowVisibility = React.useCallback(scrollPosition => {
if (!ref.current) {
return;
}
// Math.abs to convert negative scroll position (RTL) to positive
const scroll = Math.abs(Math.round(scrollPosition));
const dimensions = gridDimensionsSelector(apiRef);
const maxScroll = Math.round(dimensions.contentSize[position === 'vertical' ? 'height' : 'width'] - dimensions.viewportInnerSize[position === 'vertical' ? 'height' : 'width']);
const hasPinnedStart = position === 'vertical' ? pinnedRows?.top?.length > 0 : pinnedColumns?.left?.length !== undefined && pinnedColumns?.left?.length > 0;
const hasPinnedEnd = position === 'vertical' ? pinnedRows?.bottom?.length > 0 : pinnedColumns?.right?.length !== undefined && pinnedColumns?.right?.length > 0;
const scrollIsNotAtStart = isRtl ? scroll < maxScroll : scroll > 0;
const scrollIsNotAtEnd = isRtl ? scroll > 0 : scroll < maxScroll;
ref.current.style.setProperty('--hasScrollStart', hasPinnedStart && scrollIsNotAtStart ? '1' : '0');
ref.current.style.setProperty('--hasScrollEnd', hasPinnedEnd && scrollIsNotAtEnd ? '1' : '0');
}, [pinnedRows, pinnedColumns, isRtl, position, apiRef]);
const handleScrolling = scrollParams => {
updateScrollShadowVisibility(scrollParams[position === 'vertical' ? 'top' : 'left']);
};
const handleColumnResizeStop = () => {
if (position === 'horizontal') {
updateScrollShadowVisibility(apiRef.current.virtualScrollerRef?.current?.scrollLeft || 0);
}
};
useGridEvent(apiRef, 'scrollPositionChange', handleScrolling);
useGridEvent(apiRef, 'columnResizeStop', handleColumnResizeStop);
React.useEffect(() => {
updateScrollShadowVisibility((position === 'horizontal' ? apiRef.current.virtualScrollerRef?.current?.scrollLeft : apiRef.current.virtualScrollerRef?.current?.scrollTop) ?? 0);
}, [updateScrollShadowVisibility, apiRef, position]);
return /*#__PURE__*/_jsx(ScrollShadow, {
className: classes.root,
ownerState: ownerState,
ref: ref,
style: {
'--hasScrollStart': 0,
'--hasScrollEnd': initialScrollable ? '1' : '0'
}
});
}
export { GridScrollShadows };