diff --git a/packages/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx b/packages/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx index ca3ed2a60b8ac..bfd22a0b5dbeb 100644 --- a/packages/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx +++ b/packages/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx @@ -38,6 +38,8 @@ interface GridColumnHeaderItemProps { indexInSection: number; sectionLength: number; gridHasFiller: boolean; + isLastUnpinned: boolean; + isSiblingFocused: boolean; } type OwnerState = GridColumnHeaderItemProps & { @@ -56,6 +58,8 @@ const useUtilityClasses = (ownerState: OwnerState) => { showLeftBorder, filterItemsCounter, pinnedPosition, + isLastUnpinned, + isSiblingFocused, } = ownerState; const isColumnSorted = sortDirection != null; @@ -79,6 +83,10 @@ const useUtilityClasses = (ownerState: OwnerState) => { showLeftBorder && 'columnHeader--withLeftBorder', pinnedPosition === 'left' && 'columnHeader--pinnedLeft', pinnedPosition === 'right' && 'columnHeader--pinnedRight', + // TODO: Remove classes below and restore `:has` selectors when they are supported in jsdom + // See https://github.com/mui/mui-x/pull/14559 + isLastUnpinned && 'columnHeader--lastUnpinned', + isSiblingFocused && 'columnHeader--siblingFocused', ], draggableContainer: ['columnHeaderDraggableContainer'], titleContainer: ['columnHeaderTitleContainer'], @@ -326,7 +334,9 @@ GridColumnHeaderItem.propTypes = { indexInSection: PropTypes.number.isRequired, isDragging: PropTypes.bool.isRequired, isLast: PropTypes.bool.isRequired, + isLastUnpinned: PropTypes.bool.isRequired, isResizing: PropTypes.bool.isRequired, + isSiblingFocused: PropTypes.bool.isRequired, pinnedPosition: PropTypes.oneOf(['left', 'right']), sectionLength: PropTypes.number.isRequired, separatorSide: PropTypes.oneOf(['left', 'right']), diff --git a/packages/x-data-grid/src/components/containers/GridRootStyles.ts b/packages/x-data-grid/src/components/containers/GridRootStyles.ts index 0c574a7bf3c72..3d1e28b943794 100644 --- a/packages/x-data-grid/src/components/containers/GridRootStyles.ts +++ b/packages/x-data-grid/src/components/containers/GridRootStyles.ts @@ -289,12 +289,10 @@ export const GridRootStyles = styled('div', { // - the column has a left or right border // - the next column is pinned right and has a left border [`& .${c.columnHeader}:focus, - & .${c.columnHeader}:focus-within, - & .${c.columnHeader}:has(+ .${c.columnHeader}:focus), - & .${c.columnHeader}:has(+ .${c.columnHeader}:focus-within), & .${c['columnHeader--withLeftBorder']}, & .${c['columnHeader--withRightBorder']}, - & .${c.columnHeader}:has(+ .${c.filler} + .${c['columnHeader--withLeftBorder']}), + & .${c['columnHeader--siblingFocused']}, + & .${c['virtualScroller--hasScrollX']} .${c['columnHeader--lastUnpinned']}, & .${c['virtualScroller--hasScrollX']} .${c['columnHeader--last']} `]: { [`& .${c.columnSeparator}`]: { @@ -413,9 +411,7 @@ export const GridRootStyles = styled('div', { '@media (hover: none)': { [`& .${c.columnHeader}`]: columnHeaderStyles, [`& .${c.columnHeader}:focus, - & .${c.columnHeader}:focus-within, - & .${c.columnHeader}:has(+ .${c.columnHeader}:focus), - & .${c.columnHeader}:has(+ .${c.columnHeader}:focus-within)`]: { + & .${c['columnHeader--siblingFocused']}`]: { [`.${c['columnSeparator--resizable']}`]: { color: (t.vars || t).palette.primary.main, }, diff --git a/packages/x-data-grid/src/constants/gridClasses.ts b/packages/x-data-grid/src/constants/gridClasses.ts index 330723133d737..ca4ed8ad672f9 100644 --- a/packages/x-data-grid/src/constants/gridClasses.ts +++ b/packages/x-data-grid/src/constants/gridClasses.ts @@ -163,6 +163,17 @@ export interface GridClasses { * Styles applied to the last column header element. */ 'columnHeader--last': string; + /** + * Styles applied to the last unpinned column header item. + * @ignore - do not document. + */ + 'columnHeader--lastUnpinned': string; + /** + * Styles applied to a column header item when its sibling with a bordering separator is focused. + * @ignore - do not document. + */ + 'columnHeader--siblingFocused': string; + /** * Styles applied to the header checkbox cell element. */ @@ -686,6 +697,8 @@ export const gridClasses = generateUtilityClasses('MuiDataGrid', [ 'columnHeader--pinnedLeft', 'columnHeader--pinnedRight', 'columnHeader--last', + 'columnHeader--lastUnpinned', + 'columnHeader--siblingFocused', 'columnHeaderCheckbox', 'columnHeaderDraggableContainer', 'columnHeaderTitle', diff --git a/packages/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx b/packages/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx index 1b8d2a88a567c..c6bb0d81a9e6b 100644 --- a/packages/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx +++ b/packages/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx @@ -274,6 +274,17 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { computedWidth: colDef.computedWidth, }); + const siblingWithBorderingSeparator = + pinnedPosition === GridPinnedColumnPosition.RIGHT + ? renderedColumns[i - 1] + : renderedColumns[i + 1]; + const isSiblingFocused = siblingWithBorderingSeparator + ? columnHeaderFocus !== null && + columnHeaderFocus.field === siblingWithBorderingSeparator.field + : false; + const isLastUnpinned = + columnIndex + 1 === columnPositions.length - pinnedColumns.right.length; + columns.push( { indexInSection={i} sectionLength={renderedColumns.length} gridHasFiller={gridHasFiller} + isLastUnpinned={isLastUnpinned} + isSiblingFocused={isSiblingFocused} {...other} />, );