From d1ceefdcdbd4cc859bb42c6d72896bb89accba4d Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Tue, 25 Jun 2024 13:07:25 +0200 Subject: [PATCH 01/89] Add visible row ids to parent id lookup selector --- .../features/filter/gridFilterSelector.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts index 9d376a2321f23..bc80a3aa301c1 100644 --- a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts +++ b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts @@ -1,6 +1,7 @@ import { createSelector, createSelectorMemoized } from '../../../utils/createSelector'; import { GridFilterItem } from '../../../models/gridFilterItem'; import { GridStateCommunity } from '../../../models/gridStateCommunity'; +import { GridRowId } from '../../../models/gridRows'; import { gridSortedRowEntriesSelector } from '../sorting/gridSortingSelector'; import { gridColumnLookupSelector } from '../columns/gridColumnsSelector'; import { gridRowMaximumTreeDepthSelector, gridRowTreeSelector } from '../rows/gridRowsSelector'; @@ -96,6 +97,30 @@ export const gridFilteredSortedRowIdsSelector = createSelectorMemoized( (filteredSortedRowEntries) => filteredSortedRowEntries.map((row) => row.id), ); +/** + * Get the row ids accessible after the filtering process to parent lookup. + * Does not contain the collapsed children. + * @category Filtering + */ +export const gridExpandedSortedRowIdsLookupSelector = createSelectorMemoized( + gridExpandedSortedRowIdsSelector, + gridRowTreeSelector, + (visibleSortedRowIds, rowTree) => + Object.values(rowTree).reduce((acc: Record, rowNode) => { + const parentRowId = rowNode.parent; + if (!visibleSortedRowIds.includes(rowNode.id) || parentRowId === null) { + return acc; + } + + if (!acc[parentRowId]) { + acc[parentRowId] = []; + } + + acc[parentRowId].push(rowNode.id); + return acc; + }, {}), +); + /** * Get the id and the model of the top level rows accessible after the filtering process. * @category Filtering From 895c71e311874f1147ee763ff5b4623bf9fe7141 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Tue, 25 Jun 2024 13:09:20 +0200 Subject: [PATCH 02/89] Extend grid row for the pro grid to include additional aria atteributes for the grid tree (level, position and set size) --- .../src/components/GridRow.tsx | 44 +++++++++++++++++++ .../dataGridProDefaultSlotsComponents.ts | 2 + 2 files changed, 46 insertions(+) create mode 100644 packages/x-data-grid-pro/src/components/GridRow.tsx diff --git a/packages/x-data-grid-pro/src/components/GridRow.tsx b/packages/x-data-grid-pro/src/components/GridRow.tsx new file mode 100644 index 0000000000000..b8194597a8a00 --- /dev/null +++ b/packages/x-data-grid-pro/src/components/GridRow.tsx @@ -0,0 +1,44 @@ +import * as React from 'react'; +import { + GridRow as DataGridRow, + GridRowProps, + gridExpandedSortedRowIdsLookupSelector, + gridFilteredDescendantCountLookupSelector, +} from '@mui/x-data-grid'; +import { useGridPrivateApiContext, useGridSelector } from '@mui/x-data-grid/internals'; +import { useGridRootProps } from '../hooks/utils/useGridRootProps'; + +export function GridRow(props: GridRowProps) { + const { rowId } = props; + const apiRef = useGridPrivateApiContext(); + const rootProps = useGridRootProps(); + const rowNode = apiRef.current.getRowNode(rowId); + + if (rootProps.treeData !== true || rowNode === null || rowNode.parent === null) { + return ; + } + + const filteredDescendantCountLookup = useGridSelector( + apiRef, + gridFilteredDescendantCountLookupSelector, + ); + const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; + + const sortedVisibleRowIdsLookup = useGridSelector(apiRef, gridExpandedSortedRowIdsLookupSelector); + const currentLevelIds = sortedVisibleRowIdsLookup[rowNode.parent]; + + const ariaAttributes = React.useMemo( + () => ({ + 'aria-level': rowNode.depth + 1, + 'aria-setsize': currentLevelIds.length, + 'aria-posinset': currentLevelIds.indexOf(rowNode.id) + 1, + // aria-expanded should only be added to the rows that contain children + ...(rowNode.type === 'group' && filteredDescendantCount > 0 + ? { 'aria-expanded': Boolean(rowNode.childrenExpanded) } + : {}), + }), + [rowNode, currentLevelIds, filteredDescendantCount], + ); + + return ; +} diff --git a/packages/x-data-grid-pro/src/constants/dataGridProDefaultSlotsComponents.ts b/packages/x-data-grid-pro/src/constants/dataGridProDefaultSlotsComponents.ts index 4888e88773474..15d99bb9c739e 100644 --- a/packages/x-data-grid-pro/src/constants/dataGridProDefaultSlotsComponents.ts +++ b/packages/x-data-grid-pro/src/constants/dataGridProDefaultSlotsComponents.ts @@ -6,6 +6,7 @@ import { GridHeaderFilterMenu } from '../components/headerFiltering/GridHeaderFi import { GridHeaderFilterCell } from '../components/headerFiltering/GridHeaderFilterCell'; import { GridDetailPanels } from '../components/GridDetailPanels'; import { GridPinnedRows } from '../components/GridPinnedRows'; +import { GridRow } from '../components/GridRow'; import materialSlots from '../material'; export const DATA_GRID_PRO_DEFAULT_SLOTS_COMPONENTS: GridProSlotsComponent = { @@ -17,4 +18,5 @@ export const DATA_GRID_PRO_DEFAULT_SLOTS_COMPONENTS: GridProSlotsComponent = { headerFilterCell: GridHeaderFilterCell, headerFilterMenu: GridHeaderFilterMenu, pinnedRows: GridPinnedRows, + row: GridRow, }; From 5b7aa0b9042b48494b5ad24279ced9a1eaeee5f0 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Tue, 25 Jun 2024 13:10:15 +0200 Subject: [PATCH 03/89] aria-rowcount is updated when filter is applied --- .../src/hooks/utils/useGridAriaAttributes.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx b/packages/x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx index fc4efefbcc8cb..07a2fc81f1650 100644 --- a/packages/x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx +++ b/packages/x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx @@ -2,18 +2,16 @@ import { gridVisibleColumnDefinitionsSelector } from '../features/columns/gridCo import { useGridSelector } from './useGridSelector'; import { useGridRootProps } from './useGridRootProps'; import { gridColumnGroupsHeaderMaxDepthSelector } from '../features/columnGrouping/gridColumnGroupsSelector'; -import { - gridPinnedRowsCountSelector, - gridRowCountSelector, -} from '../features/rows/gridRowsSelector'; +import { gridPinnedRowsCountSelector } from '../features/rows/gridRowsSelector'; import { useGridPrivateApiContext } from './useGridPrivateApiContext'; import { isMultipleRowSelectionEnabled } from '../features/rowSelection/utils'; +import { gridExpandedRowCountSelector } from '../features/filter/gridFilterSelector'; export const useGridAriaAttributes = () => { const apiRef = useGridPrivateApiContext(); const rootProps = useGridRootProps(); const visibleColumns = useGridSelector(apiRef, gridVisibleColumnDefinitionsSelector); - const totalRowCount = useGridSelector(apiRef, gridRowCountSelector); + const accessibleRowCount = useGridSelector(apiRef, gridExpandedRowCountSelector); const headerGroupingMaxDepth = useGridSelector(apiRef, gridColumnGroupsHeaderMaxDepthSelector); const pinnedRowsCount = useGridSelector(apiRef, gridPinnedRowsCountSelector); @@ -25,7 +23,7 @@ export const useGridAriaAttributes = () => { return { role, 'aria-colcount': visibleColumns.length, - 'aria-rowcount': headerGroupingMaxDepth + 1 + pinnedRowsCount + totalRowCount, + 'aria-rowcount': headerGroupingMaxDepth + 1 + pinnedRowsCount + accessibleRowCount, 'aria-multiselectable': isMultipleRowSelectionEnabled(rootProps), }; }; From 3cac35a2cf20c03bc67a0b7a3830194f9e8b4b1c Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Tue, 25 Jun 2024 13:54:18 +0200 Subject: [PATCH 04/89] Extract pro grid row into a separate component to use conditional rendering --- .../src/components/GridProRow.tsx | 44 +++++++++++++++++++ .../src/components/GridRow.tsx | 41 ++++------------- 2 files changed, 52 insertions(+), 33 deletions(-) create mode 100644 packages/x-data-grid-pro/src/components/GridProRow.tsx diff --git a/packages/x-data-grid-pro/src/components/GridProRow.tsx b/packages/x-data-grid-pro/src/components/GridProRow.tsx new file mode 100644 index 0000000000000..2e21dd2742090 --- /dev/null +++ b/packages/x-data-grid-pro/src/components/GridProRow.tsx @@ -0,0 +1,44 @@ +import * as React from 'react'; +import { + GridRow as DataGridRow, + GridRowId, + GridRowProps, + GridTreeNode, + gridExpandedSortedRowIdsLookupSelector, + gridFilteredDescendantCountLookupSelector, +} from '@mui/x-data-grid'; +import { useGridPrivateApiContext, useGridSelector } from '@mui/x-data-grid/internals'; + +export type GridTreeNodeWithParent = GridTreeNode & { parent: GridRowId }; +export interface GridRowProProps extends GridRowProps { + rowNode: GridTreeNodeWithParent; +} + +export function GridRowPro(props: GridRowProProps) { + const { rowNode, ...other } = props; + + const apiRef = useGridPrivateApiContext(); + const filteredDescendantCountLookup = useGridSelector( + apiRef, + gridFilteredDescendantCountLookupSelector, + ); + const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; + + const sortedVisibleRowIdsLookup = useGridSelector(apiRef, gridExpandedSortedRowIdsLookupSelector); + const currentLevelIds = sortedVisibleRowIdsLookup[rowNode.parent]; + + const ariaAttributes = React.useMemo( + () => ({ + 'aria-level': rowNode.depth + 1, + 'aria-setsize': currentLevelIds.length, + 'aria-posinset': currentLevelIds.indexOf(rowNode.id) + 1, + // aria-expanded should only be added to the rows that contain children + ...(rowNode.type === 'group' && filteredDescendantCount > 0 + ? { 'aria-expanded': Boolean(rowNode.childrenExpanded) } + : {}), + }), + [rowNode, currentLevelIds, filteredDescendantCount], + ); + + return ; +} diff --git a/packages/x-data-grid-pro/src/components/GridRow.tsx b/packages/x-data-grid-pro/src/components/GridRow.tsx index b8194597a8a00..2ca1cb3d897c7 100644 --- a/packages/x-data-grid-pro/src/components/GridRow.tsx +++ b/packages/x-data-grid-pro/src/components/GridRow.tsx @@ -1,44 +1,19 @@ import * as React from 'react'; -import { - GridRow as DataGridRow, - GridRowProps, - gridExpandedSortedRowIdsLookupSelector, - gridFilteredDescendantCountLookupSelector, -} from '@mui/x-data-grid'; -import { useGridPrivateApiContext, useGridSelector } from '@mui/x-data-grid/internals'; +import { GridRow as DataGridRow, GridRowProps } from '@mui/x-data-grid'; +import { useGridPrivateApiContext } from '@mui/x-data-grid/internals'; import { useGridRootProps } from '../hooks/utils/useGridRootProps'; +import { GridRowPro, GridTreeNodeWithParent } from './GridProRow'; export function GridRow(props: GridRowProps) { const { rowId } = props; + const apiRef = useGridPrivateApiContext(); const rootProps = useGridRootProps(); const rowNode = apiRef.current.getRowNode(rowId); - if (rootProps.treeData !== true || rowNode === null || rowNode.parent === null) { - return ; - } - - const filteredDescendantCountLookup = useGridSelector( - apiRef, - gridFilteredDescendantCountLookupSelector, - ); - const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; - - const sortedVisibleRowIdsLookup = useGridSelector(apiRef, gridExpandedSortedRowIdsLookupSelector); - const currentLevelIds = sortedVisibleRowIdsLookup[rowNode.parent]; - - const ariaAttributes = React.useMemo( - () => ({ - 'aria-level': rowNode.depth + 1, - 'aria-setsize': currentLevelIds.length, - 'aria-posinset': currentLevelIds.indexOf(rowNode.id) + 1, - // aria-expanded should only be added to the rows that contain children - ...(rowNode.type === 'group' && filteredDescendantCount > 0 - ? { 'aria-expanded': Boolean(rowNode.childrenExpanded) } - : {}), - }), - [rowNode, currentLevelIds, filteredDescendantCount], + return rootProps.treeData !== true || rowNode === null || rowNode.parent === null ? ( + + ) : ( + ); - - return ; } From b0c2ff9b2761268b76f886c123e538c1469a0b19 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Tue, 25 Jun 2024 13:59:39 +0200 Subject: [PATCH 05/89] Update API docs --- docs/pages/x/api/data-grid/selectors.json | 7 ++ .../src/components/GridRow.tsx | 84 ++++++++++++++++++- scripts/x-data-grid-premium.exports.json | 1 + scripts/x-data-grid-pro.exports.json | 1 + scripts/x-data-grid.exports.json | 1 + 5 files changed, 93 insertions(+), 1 deletion(-) diff --git a/docs/pages/x/api/data-grid/selectors.json b/docs/pages/x/api/data-grid/selectors.json index 092a70faf2623..5a334b2d13d81 100644 --- a/docs/pages/x/api/data-grid/selectors.json +++ b/docs/pages/x/api/data-grid/selectors.json @@ -172,6 +172,13 @@ "description": "Get the id and the model of the rows accessible after the filtering process.\nDoes not contain the collapsed children.", "supportsApiRef": true }, + { + "name": "gridExpandedSortedRowIdsLookupSelector", + "returnType": "Record", + "category": "Filtering", + "description": "Get the row ids accessible after the filtering process to parent lookup.\nDoes not contain the collapsed children.", + "supportsApiRef": true + }, { "name": "gridExpandedSortedRowIdsSelector", "returnType": "GridRowId[]", diff --git a/packages/x-data-grid-pro/src/components/GridRow.tsx b/packages/x-data-grid-pro/src/components/GridRow.tsx index 2ca1cb3d897c7..4fec676ba04c6 100644 --- a/packages/x-data-grid-pro/src/components/GridRow.tsx +++ b/packages/x-data-grid-pro/src/components/GridRow.tsx @@ -1,10 +1,11 @@ import * as React from 'react'; +import PropTypes from 'prop-types'; import { GridRow as DataGridRow, GridRowProps } from '@mui/x-data-grid'; import { useGridPrivateApiContext } from '@mui/x-data-grid/internals'; import { useGridRootProps } from '../hooks/utils/useGridRootProps'; import { GridRowPro, GridTreeNodeWithParent } from './GridProRow'; -export function GridRow(props: GridRowProps) { +function GridRow(props: GridRowProps) { const { rowId } = props; const apiRef = useGridPrivateApiContext(); @@ -17,3 +18,84 @@ export function GridRow(props: GridRowProps) { ); } + +GridRow.propTypes = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the TypeScript types and run "pnpm proptypes" | + // ---------------------------------------------------------------------- + dimensions: PropTypes.shape({ + bottomContainerHeight: PropTypes.number.isRequired, + columnsTotalWidth: PropTypes.number.isRequired, + contentSize: PropTypes.shape({ + height: PropTypes.number.isRequired, + width: PropTypes.number.isRequired, + }).isRequired, + hasScrollX: PropTypes.bool.isRequired, + hasScrollY: PropTypes.bool.isRequired, + headerFilterHeight: PropTypes.number.isRequired, + headerHeight: PropTypes.number.isRequired, + headersTotalHeight: PropTypes.number.isRequired, + isReady: PropTypes.bool.isRequired, + leftPinnedWidth: PropTypes.number.isRequired, + minimumSize: PropTypes.shape({ + height: PropTypes.number.isRequired, + width: PropTypes.number.isRequired, + }).isRequired, + rightPinnedWidth: PropTypes.number.isRequired, + root: PropTypes.shape({ + height: PropTypes.number.isRequired, + width: PropTypes.number.isRequired, + }).isRequired, + rowHeight: PropTypes.number.isRequired, + rowWidth: PropTypes.number.isRequired, + scrollbarSize: PropTypes.number.isRequired, + topContainerHeight: PropTypes.number.isRequired, + viewportInnerSize: PropTypes.shape({ + height: PropTypes.number.isRequired, + width: PropTypes.number.isRequired, + }).isRequired, + viewportOuterSize: PropTypes.shape({ + height: PropTypes.number.isRequired, + width: PropTypes.number.isRequired, + }).isRequired, + }).isRequired, + /** + * Determines which cell has focus. + * If `null`, no cell in this row has focus. + */ + focusedColumnIndex: PropTypes.number, + /** + * Index of the row in the whole sorted and filtered dataset. + * If some rows above have expanded children, this index also take those children into account. + */ + index: PropTypes.number.isRequired, + isFirstVisible: PropTypes.bool.isRequired, + isLastVisible: PropTypes.bool.isRequired, + isNotVisible: PropTypes.bool.isRequired, + offsetLeft: PropTypes.number.isRequired, + offsetTop: PropTypes.number, + onClick: PropTypes.func, + onDoubleClick: PropTypes.func, + onMouseEnter: PropTypes.func, + onMouseLeave: PropTypes.func, + pinnedColumns: PropTypes.object.isRequired, + renderContext: PropTypes.shape({ + firstColumnIndex: PropTypes.number.isRequired, + firstRowIndex: PropTypes.number.isRequired, + lastColumnIndex: PropTypes.number.isRequired, + lastRowIndex: PropTypes.number.isRequired, + }).isRequired, + row: PropTypes.object.isRequired, + rowHeight: PropTypes.oneOfType([PropTypes.oneOf(['auto']), PropTypes.number]).isRequired, + rowId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, + selected: PropTypes.bool.isRequired, + /** + * Determines which cell should be tabbable by having tabIndex=0. + * If `null`, no cell in this row is in the tab sequence. + */ + tabbableCell: PropTypes.string, + visibleColumns: PropTypes.arrayOf(PropTypes.object).isRequired, +} as any; + +export { GridRow }; diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index ac6c300397a0e..9bb48da8c2a7a 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -305,6 +305,7 @@ { "name": "GridExceljsProcessInput", "kind": "Interface" }, { "name": "gridExpandedRowCountSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowEntriesSelector", "kind": "Variable" }, + { "name": "gridExpandedSortedRowIdsLookupSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowIdsSelector", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExperimentalPremiumFeatures", "kind": "Interface" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index e9620df666a07..e6da5d2de8e3f 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -274,6 +274,7 @@ { "name": "GridEvents", "kind": "TypeAlias" }, { "name": "gridExpandedRowCountSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowEntriesSelector", "kind": "Variable" }, + { "name": "gridExpandedSortedRowIdsLookupSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowIdsSelector", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExperimentalProFeatures", "kind": "Interface" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index ac66be0724d09..7e64b2345a591 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -245,6 +245,7 @@ { "name": "GridEvents", "kind": "TypeAlias" }, { "name": "gridExpandedRowCountSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowEntriesSelector", "kind": "Variable" }, + { "name": "gridExpandedSortedRowIdsLookupSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowIdsSelector", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExperimentalFeatures", "kind": "Interface" }, From ce93f09a9938b2542e8298f9169e8065d4384b09 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Tue, 25 Jun 2024 14:49:36 +0200 Subject: [PATCH 06/89] Add tests --- .../src/tests/treeData.DataGridPro.test.tsx | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx index 9f80a0d0858e7..aa8eddc83e0bc 100644 --- a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx @@ -4,6 +4,7 @@ import { getColumnHeaderCell, getColumnHeadersTextContent, getColumnValues, + getRow, } from 'test/utils/helperFn'; import * as React from 'react'; import { expect } from 'chai'; @@ -725,6 +726,40 @@ describe(' - Tree data', () => { }); }); + describe('accessibility', () => { + it('should add necessary treegrid aria attributes to the rows', () => { + render(); + + expect(getRow(0).getAttribute('aria-level')).to.equal('1'); // A + expect(getRow(1).getAttribute('aria-level')).to.equal('2'); // A.A + expect(getRow(1).getAttribute('aria-posinset')).to.equal('1'); + expect(getRow(1).getAttribute('aria-setsize')).to.equal('2'); + expect(getRow(2).getAttribute('aria-level')).to.equal('2'); // A.B + }); + + it('should adjust treegrid aria attributes after filtering', () => { + render( + , + ); + + expect(getRow(0).getAttribute('aria-level')).to.equal('1'); // A + expect(getRow(1).getAttribute('aria-level')).to.equal('2'); // A.B + expect(getRow(1).getAttribute('aria-posinset')).to.equal('1'); + expect(getRow(1).getAttribute('aria-setsize')).to.equal('1'); // A.A is filtered out, set size is now 1 + expect(getRow(2).getAttribute('aria-level')).to.equal('1'); // B + }); + }); + describe('regressions', () => { // See https://github.com/mui/mui-x/issues/9402 it('should not fail with checkboxSelection', () => { From 3ddce457565b8b43a00f3e82f78f95e922618e0a Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 26 Jun 2024 08:22:58 +0200 Subject: [PATCH 07/89] Generate tree grid aria attributes via hook --- .../src/components/GridProRow.tsx | 44 -------------- .../src/components/GridRow.tsx | 15 ++--- .../hooks/utils/useGridRowAriaAttributes.tsx | 59 +++++++++++++++++++ 3 files changed, 63 insertions(+), 55 deletions(-) delete mode 100644 packages/x-data-grid-pro/src/components/GridProRow.tsx create mode 100644 packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.tsx diff --git a/packages/x-data-grid-pro/src/components/GridProRow.tsx b/packages/x-data-grid-pro/src/components/GridProRow.tsx deleted file mode 100644 index 2e21dd2742090..0000000000000 --- a/packages/x-data-grid-pro/src/components/GridProRow.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import * as React from 'react'; -import { - GridRow as DataGridRow, - GridRowId, - GridRowProps, - GridTreeNode, - gridExpandedSortedRowIdsLookupSelector, - gridFilteredDescendantCountLookupSelector, -} from '@mui/x-data-grid'; -import { useGridPrivateApiContext, useGridSelector } from '@mui/x-data-grid/internals'; - -export type GridTreeNodeWithParent = GridTreeNode & { parent: GridRowId }; -export interface GridRowProProps extends GridRowProps { - rowNode: GridTreeNodeWithParent; -} - -export function GridRowPro(props: GridRowProProps) { - const { rowNode, ...other } = props; - - const apiRef = useGridPrivateApiContext(); - const filteredDescendantCountLookup = useGridSelector( - apiRef, - gridFilteredDescendantCountLookupSelector, - ); - const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; - - const sortedVisibleRowIdsLookup = useGridSelector(apiRef, gridExpandedSortedRowIdsLookupSelector); - const currentLevelIds = sortedVisibleRowIdsLookup[rowNode.parent]; - - const ariaAttributes = React.useMemo( - () => ({ - 'aria-level': rowNode.depth + 1, - 'aria-setsize': currentLevelIds.length, - 'aria-posinset': currentLevelIds.indexOf(rowNode.id) + 1, - // aria-expanded should only be added to the rows that contain children - ...(rowNode.type === 'group' && filteredDescendantCount > 0 - ? { 'aria-expanded': Boolean(rowNode.childrenExpanded) } - : {}), - }), - [rowNode, currentLevelIds, filteredDescendantCount], - ); - - return ; -} diff --git a/packages/x-data-grid-pro/src/components/GridRow.tsx b/packages/x-data-grid-pro/src/components/GridRow.tsx index 4fec676ba04c6..a33cebdef6d87 100644 --- a/packages/x-data-grid-pro/src/components/GridRow.tsx +++ b/packages/x-data-grid-pro/src/components/GridRow.tsx @@ -1,22 +1,15 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { GridRow as DataGridRow, GridRowProps } from '@mui/x-data-grid'; -import { useGridPrivateApiContext } from '@mui/x-data-grid/internals'; -import { useGridRootProps } from '../hooks/utils/useGridRootProps'; -import { GridRowPro, GridTreeNodeWithParent } from './GridProRow'; +import { useGridRowAriaAttributes } from '../hooks/utils/useGridRowAriaAttributes'; function GridRow(props: GridRowProps) { const { rowId } = props; - const apiRef = useGridPrivateApiContext(); - const rootProps = useGridRootProps(); - const rowNode = apiRef.current.getRowNode(rowId); + const { getGridRowAriaAttributes } = useGridRowAriaAttributes(); + const ariaAttributes = getGridRowAriaAttributes(rowId); - return rootProps.treeData !== true || rowNode === null || rowNode.parent === null ? ( - - ) : ( - - ); + return ; } GridRow.propTypes = { diff --git a/packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.tsx b/packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.tsx new file mode 100644 index 0000000000000..c935f095dede9 --- /dev/null +++ b/packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.tsx @@ -0,0 +1,59 @@ +import * as React from 'react'; +import { + GridRowId, + gridExpandedSortedRowIdsLookupSelector, + gridFilteredDescendantCountLookupSelector, +} from '@mui/x-data-grid'; +import { useGridSelector } from '@mui/x-data-grid/internals'; +import { useGridRootProps } from './useGridRootProps'; +import { useGridPrivateApiContext } from './useGridPrivateApiContext'; + +interface GridRowAriaAttributes { + 'aria-level'?: number; + 'aria-setsize'?: number; + 'aria-posinset'?: number; + 'aria-expanded'?: boolean; +} + +export const useGridRowAriaAttributes = () => { + const apiRef = useGridPrivateApiContext(); + const rootProps = useGridRootProps(); + const filteredDescendantCountLookup = useGridSelector( + apiRef, + gridFilteredDescendantCountLookupSelector, + ); + const sortedVisibleRowIdsLookup = useGridSelector(apiRef, gridExpandedSortedRowIdsLookupSelector); + + const getGridRowAriaAttributes = React.useCallback<(rowId: GridRowId) => GridRowAriaAttributes>( + (rowId) => { + const rowNode = apiRef.current.getRowNode(rowId); + const ariaAttributes: GridRowAriaAttributes = {}; + + if (rootProps.treeData !== true || rowNode === null) { + return ariaAttributes; + } + + ariaAttributes['aria-level'] = rowNode.depth + 1; + + // aria-expanded should only be added to the rows that contain children + const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; + if (rowNode.type === 'group' && filteredDescendantCount > 0) { + ariaAttributes['aria-expanded'] = Boolean(rowNode.childrenExpanded); + } + + // if the parent is null, set size and position cannot be determined + if (rowNode.parent !== null) { + const currentLevelIds = sortedVisibleRowIdsLookup[rowNode.parent]; + ariaAttributes['aria-setsize'] = currentLevelIds.length; + ariaAttributes['aria-posinset'] = currentLevelIds.indexOf(rowNode.id) + 1; + } + + return ariaAttributes; + }, + [apiRef, rootProps.treeData, filteredDescendantCountLookup, sortedVisibleRowIdsLookup], + ); + + return { + getGridRowAriaAttributes, + }; +}; From 8f8b45bda1892152b2544d3a0f901df7c469610b Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 26 Jun 2024 15:13:06 +0200 Subject: [PATCH 08/89] Remove slow selector and filter out current level ids in the callback --- ...ibutes.tsx => useGridRowAriaAttributes.ts} | 15 ++++++++---- .../features/filter/gridFilterSelector.ts | 24 ------------------- 2 files changed, 11 insertions(+), 28 deletions(-) rename packages/x-data-grid-pro/src/hooks/utils/{useGridRowAriaAttributes.tsx => useGridRowAriaAttributes.ts} (79%) diff --git a/packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.tsx b/packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.ts similarity index 79% rename from packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.tsx rename to packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.ts index c935f095dede9..44e01aa7aef97 100644 --- a/packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.ts @@ -1,7 +1,9 @@ import * as React from 'react'; import { + GridAutoGeneratedGroupNode, + GridDataGroupNode, GridRowId, - gridExpandedSortedRowIdsLookupSelector, + gridExpandedSortedRowIdsSelector, gridFilteredDescendantCountLookupSelector, } from '@mui/x-data-grid'; import { useGridSelector } from '@mui/x-data-grid/internals'; @@ -22,7 +24,7 @@ export const useGridRowAriaAttributes = () => { apiRef, gridFilteredDescendantCountLookupSelector, ); - const sortedVisibleRowIdsLookup = useGridSelector(apiRef, gridExpandedSortedRowIdsLookupSelector); + const sortedVisibleRowIds = useGridSelector(apiRef, gridExpandedSortedRowIdsSelector); const getGridRowAriaAttributes = React.useCallback<(rowId: GridRowId) => GridRowAriaAttributes>( (rowId) => { @@ -43,14 +45,19 @@ export const useGridRowAriaAttributes = () => { // if the parent is null, set size and position cannot be determined if (rowNode.parent !== null) { - const currentLevelIds = sortedVisibleRowIdsLookup[rowNode.parent]; + const parentNode = apiRef.current.getRowNode(rowNode.parent) as + | GridDataGroupNode + | GridAutoGeneratedGroupNode; + const currentLevelIds = sortedVisibleRowIds.filter((id) => + parentNode.children.includes(id), + ); ariaAttributes['aria-setsize'] = currentLevelIds.length; ariaAttributes['aria-posinset'] = currentLevelIds.indexOf(rowNode.id) + 1; } return ariaAttributes; }, - [apiRef, rootProps.treeData, filteredDescendantCountLookup, sortedVisibleRowIdsLookup], + [apiRef, rootProps.treeData, filteredDescendantCountLookup, sortedVisibleRowIds], ); return { diff --git a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts index bc80a3aa301c1..4f3505ddf0974 100644 --- a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts +++ b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts @@ -97,30 +97,6 @@ export const gridFilteredSortedRowIdsSelector = createSelectorMemoized( (filteredSortedRowEntries) => filteredSortedRowEntries.map((row) => row.id), ); -/** - * Get the row ids accessible after the filtering process to parent lookup. - * Does not contain the collapsed children. - * @category Filtering - */ -export const gridExpandedSortedRowIdsLookupSelector = createSelectorMemoized( - gridExpandedSortedRowIdsSelector, - gridRowTreeSelector, - (visibleSortedRowIds, rowTree) => - Object.values(rowTree).reduce((acc: Record, rowNode) => { - const parentRowId = rowNode.parent; - if (!visibleSortedRowIds.includes(rowNode.id) || parentRowId === null) { - return acc; - } - - if (!acc[parentRowId]) { - acc[parentRowId] = []; - } - - acc[parentRowId].push(rowNode.id); - return acc; - }, {}), -); - /** * Get the id and the model of the top level rows accessible after the filtering process. * @category Filtering From 38c7cf39113b6aec80c7522d64a610a041eb0e29 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 26 Jun 2024 15:22:23 +0200 Subject: [PATCH 09/89] Remove unused import and rebuild API docs --- docs/pages/x/api/data-grid/selectors.json | 7 ------- .../src/hooks/features/filter/gridFilterSelector.ts | 1 - scripts/x-data-grid-premium.exports.json | 1 - scripts/x-data-grid-pro.exports.json | 1 - scripts/x-data-grid.exports.json | 1 - 5 files changed, 11 deletions(-) diff --git a/docs/pages/x/api/data-grid/selectors.json b/docs/pages/x/api/data-grid/selectors.json index 5a334b2d13d81..092a70faf2623 100644 --- a/docs/pages/x/api/data-grid/selectors.json +++ b/docs/pages/x/api/data-grid/selectors.json @@ -172,13 +172,6 @@ "description": "Get the id and the model of the rows accessible after the filtering process.\nDoes not contain the collapsed children.", "supportsApiRef": true }, - { - "name": "gridExpandedSortedRowIdsLookupSelector", - "returnType": "Record", - "category": "Filtering", - "description": "Get the row ids accessible after the filtering process to parent lookup.\nDoes not contain the collapsed children.", - "supportsApiRef": true - }, { "name": "gridExpandedSortedRowIdsSelector", "returnType": "GridRowId[]", diff --git a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts index 4f3505ddf0974..9d376a2321f23 100644 --- a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts +++ b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts @@ -1,7 +1,6 @@ import { createSelector, createSelectorMemoized } from '../../../utils/createSelector'; import { GridFilterItem } from '../../../models/gridFilterItem'; import { GridStateCommunity } from '../../../models/gridStateCommunity'; -import { GridRowId } from '../../../models/gridRows'; import { gridSortedRowEntriesSelector } from '../sorting/gridSortingSelector'; import { gridColumnLookupSelector } from '../columns/gridColumnsSelector'; import { gridRowMaximumTreeDepthSelector, gridRowTreeSelector } from '../rows/gridRowsSelector'; diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index 9bb48da8c2a7a..ac6c300397a0e 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -305,7 +305,6 @@ { "name": "GridExceljsProcessInput", "kind": "Interface" }, { "name": "gridExpandedRowCountSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowEntriesSelector", "kind": "Variable" }, - { "name": "gridExpandedSortedRowIdsLookupSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowIdsSelector", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExperimentalPremiumFeatures", "kind": "Interface" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index e6da5d2de8e3f..e9620df666a07 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -274,7 +274,6 @@ { "name": "GridEvents", "kind": "TypeAlias" }, { "name": "gridExpandedRowCountSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowEntriesSelector", "kind": "Variable" }, - { "name": "gridExpandedSortedRowIdsLookupSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowIdsSelector", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExperimentalProFeatures", "kind": "Interface" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index 7e64b2345a591..ac66be0724d09 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -245,7 +245,6 @@ { "name": "GridEvents", "kind": "TypeAlias" }, { "name": "gridExpandedRowCountSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowEntriesSelector", "kind": "Variable" }, - { "name": "gridExpandedSortedRowIdsLookupSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowIdsSelector", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExperimentalFeatures", "kind": "Interface" }, From b49a771b312def8e34edff96604808b6c1da5304 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 27 Jun 2024 09:13:49 +0200 Subject: [PATCH 10/89] Expand test with the assertion that checks reset of the position counter --- .../x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx index aa8eddc83e0bc..e7ebf3fb13a0d 100644 --- a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx @@ -726,7 +726,7 @@ describe(' - Tree data', () => { }); }); - describe('accessibility', () => { + describe.only('accessibility', () => { it('should add necessary treegrid aria attributes to the rows', () => { render(); @@ -735,6 +735,7 @@ describe(' - Tree data', () => { expect(getRow(1).getAttribute('aria-posinset')).to.equal('1'); expect(getRow(1).getAttribute('aria-setsize')).to.equal('2'); expect(getRow(2).getAttribute('aria-level')).to.equal('2'); // A.B + expect(getRow(4).getAttribute('aria-posinset')).to.equal('1'); // B.A }); it('should adjust treegrid aria attributes after filtering', () => { From 9587f1e942061ac23a44949c2a7d48e96c5a9674 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 27 Jun 2024 09:14:22 +0200 Subject: [PATCH 11/89] Add lookup selector for position in set (branch) of the tree --- .../features/filter/gridFilterSelector.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts index 9d376a2321f23..1aadb3f82540b 100644 --- a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts +++ b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts @@ -1,4 +1,5 @@ import { createSelector, createSelectorMemoized } from '../../../utils/createSelector'; +import { GridRowId } from '../../../models/gridRows'; import { GridFilterItem } from '../../../models/gridFilterItem'; import { GridStateCommunity } from '../../../models/gridStateCommunity'; import { gridSortedRowEntriesSelector } from '../sorting/gridSortingSelector'; @@ -96,6 +97,41 @@ export const gridFilteredSortedRowIdsSelector = createSelectorMemoized( (filteredSortedRowEntries) => filteredSortedRowEntries.map((row) => row.id), ); +/** + * Get the row ids accessible after the filtering process to position in the current tree level lookup. + * Does not contain the collapsed children. + * @category Filtering + */ +export const gridExpandedSortedRowIdsLookupSelector = createSelectorMemoized( + gridExpandedSortedRowIdsSelector, + gridRowTreeSelector, + (visibleSortedRowIds, rowTree) => { + const depthPositionCounter: Record = {}; + let lastDepth = 0; + + return visibleSortedRowIds.reduce((acc: Record, rowId) => { + const rowNode = rowTree[rowId]; + + if (!depthPositionCounter[rowNode.depth]) { + depthPositionCounter[rowNode.depth] = 0; + } + + // going deeper in the tree should keep the counters intact, because once we go back up + // position on that level continues from where it left off + // going back up in the tree should reset the counter for the levels below + // because the next item on that level is part of a different branch + if (rowNode.depth < lastDepth) { + depthPositionCounter[lastDepth] = 0; + } + + lastDepth = rowNode.depth; + depthPositionCounter[rowNode.depth]++; + acc[rowId] = depthPositionCounter[rowNode.depth]; + return acc; + }, {}); + }, +); + /** * Get the id and the model of the top level rows accessible after the filtering process. * @category Filtering From f6e08fadff995b098eeccc11311d9af27d8e7c89 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 27 Jun 2024 09:15:24 +0200 Subject: [PATCH 12/89] Use pipe processor to adjust aria attributes for better performance. Remove wrapping container --- .../src/components/GridRow.tsx | 94 ------------------- .../dataGridProDefaultSlotsComponents.ts | 2 - .../treeData/useGridTreeDataPreProcessors.tsx | 35 +++++++ .../hooks/utils/useGridRowAriaAttributes.ts | 66 ------------- .../x-data-grid/src/components/GridRow.tsx | 11 ++- .../pipeProcessing/gridPipeProcessingApi.ts | 4 + 6 files changed, 48 insertions(+), 164 deletions(-) delete mode 100644 packages/x-data-grid-pro/src/components/GridRow.tsx delete mode 100644 packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.ts diff --git a/packages/x-data-grid-pro/src/components/GridRow.tsx b/packages/x-data-grid-pro/src/components/GridRow.tsx deleted file mode 100644 index a33cebdef6d87..0000000000000 --- a/packages/x-data-grid-pro/src/components/GridRow.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import * as React from 'react'; -import PropTypes from 'prop-types'; -import { GridRow as DataGridRow, GridRowProps } from '@mui/x-data-grid'; -import { useGridRowAriaAttributes } from '../hooks/utils/useGridRowAriaAttributes'; - -function GridRow(props: GridRowProps) { - const { rowId } = props; - - const { getGridRowAriaAttributes } = useGridRowAriaAttributes(); - const ariaAttributes = getGridRowAriaAttributes(rowId); - - return ; -} - -GridRow.propTypes = { - // ----------------------------- Warning -------------------------------- - // | These PropTypes are generated from the TypeScript type definitions | - // | To update them edit the TypeScript types and run "pnpm proptypes" | - // ---------------------------------------------------------------------- - dimensions: PropTypes.shape({ - bottomContainerHeight: PropTypes.number.isRequired, - columnsTotalWidth: PropTypes.number.isRequired, - contentSize: PropTypes.shape({ - height: PropTypes.number.isRequired, - width: PropTypes.number.isRequired, - }).isRequired, - hasScrollX: PropTypes.bool.isRequired, - hasScrollY: PropTypes.bool.isRequired, - headerFilterHeight: PropTypes.number.isRequired, - headerHeight: PropTypes.number.isRequired, - headersTotalHeight: PropTypes.number.isRequired, - isReady: PropTypes.bool.isRequired, - leftPinnedWidth: PropTypes.number.isRequired, - minimumSize: PropTypes.shape({ - height: PropTypes.number.isRequired, - width: PropTypes.number.isRequired, - }).isRequired, - rightPinnedWidth: PropTypes.number.isRequired, - root: PropTypes.shape({ - height: PropTypes.number.isRequired, - width: PropTypes.number.isRequired, - }).isRequired, - rowHeight: PropTypes.number.isRequired, - rowWidth: PropTypes.number.isRequired, - scrollbarSize: PropTypes.number.isRequired, - topContainerHeight: PropTypes.number.isRequired, - viewportInnerSize: PropTypes.shape({ - height: PropTypes.number.isRequired, - width: PropTypes.number.isRequired, - }).isRequired, - viewportOuterSize: PropTypes.shape({ - height: PropTypes.number.isRequired, - width: PropTypes.number.isRequired, - }).isRequired, - }).isRequired, - /** - * Determines which cell has focus. - * If `null`, no cell in this row has focus. - */ - focusedColumnIndex: PropTypes.number, - /** - * Index of the row in the whole sorted and filtered dataset. - * If some rows above have expanded children, this index also take those children into account. - */ - index: PropTypes.number.isRequired, - isFirstVisible: PropTypes.bool.isRequired, - isLastVisible: PropTypes.bool.isRequired, - isNotVisible: PropTypes.bool.isRequired, - offsetLeft: PropTypes.number.isRequired, - offsetTop: PropTypes.number, - onClick: PropTypes.func, - onDoubleClick: PropTypes.func, - onMouseEnter: PropTypes.func, - onMouseLeave: PropTypes.func, - pinnedColumns: PropTypes.object.isRequired, - renderContext: PropTypes.shape({ - firstColumnIndex: PropTypes.number.isRequired, - firstRowIndex: PropTypes.number.isRequired, - lastColumnIndex: PropTypes.number.isRequired, - lastRowIndex: PropTypes.number.isRequired, - }).isRequired, - row: PropTypes.object.isRequired, - rowHeight: PropTypes.oneOfType([PropTypes.oneOf(['auto']), PropTypes.number]).isRequired, - rowId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired, - selected: PropTypes.bool.isRequired, - /** - * Determines which cell should be tabbable by having tabIndex=0. - * If `null`, no cell in this row is in the tab sequence. - */ - tabbableCell: PropTypes.string, - visibleColumns: PropTypes.arrayOf(PropTypes.object).isRequired, -} as any; - -export { GridRow }; diff --git a/packages/x-data-grid-pro/src/constants/dataGridProDefaultSlotsComponents.ts b/packages/x-data-grid-pro/src/constants/dataGridProDefaultSlotsComponents.ts index 15d99bb9c739e..4888e88773474 100644 --- a/packages/x-data-grid-pro/src/constants/dataGridProDefaultSlotsComponents.ts +++ b/packages/x-data-grid-pro/src/constants/dataGridProDefaultSlotsComponents.ts @@ -6,7 +6,6 @@ import { GridHeaderFilterMenu } from '../components/headerFiltering/GridHeaderFi import { GridHeaderFilterCell } from '../components/headerFiltering/GridHeaderFilterCell'; import { GridDetailPanels } from '../components/GridDetailPanels'; import { GridPinnedRows } from '../components/GridPinnedRows'; -import { GridRow } from '../components/GridRow'; import materialSlots from '../material'; export const DATA_GRID_PRO_DEFAULT_SLOTS_COMPONENTS: GridProSlotsComponent = { @@ -18,5 +17,4 @@ export const DATA_GRID_PRO_DEFAULT_SLOTS_COMPONENTS: GridProSlotsComponent = { headerFilterCell: GridHeaderFilterCell, headerFilterMenu: GridHeaderFilterMenu, pinnedRows: GridPinnedRows, - row: GridRow, }; diff --git a/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeDataPreProcessors.tsx b/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeDataPreProcessors.tsx index 74c0fcfcda382..5930c89c26bb9 100644 --- a/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeDataPreProcessors.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeDataPreProcessors.tsx @@ -7,6 +7,8 @@ import { GridGroupNode, GridRowId, GRID_CHECKBOX_SELECTION_FIELD, + gridFilteredDescendantCountLookupSelector, + gridExpandedSortedRowIdsLookupSelector, } from '@mui/x-data-grid'; import { GridPipeProcessor, @@ -208,6 +210,38 @@ export const useGridTreeDataPreProcessors = ( [privateApiRef, props.disableChildrenSorting], ); + const updateGridRowAriaAttributes = React.useCallback>( + (attributes, rowId) => { + const rowNode = privateApiRef.current.getRowNode(rowId); + const ariaAttributes = attributes as Record; + + if (props.treeData !== true || rowNode === null) { + return ariaAttributes; + } + + const filteredDescendantCountLookup = + gridFilteredDescendantCountLookupSelector(privateApiRef); + const sortedVisibleRowPositionsLookup = gridExpandedSortedRowIdsLookupSelector(privateApiRef); + + ariaAttributes['aria-level'] = rowNode.depth + 1; + + const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; + // aria-expanded should only be added to the rows that contain children + if (rowNode.type === 'group' && filteredDescendantCount > 0) { + ariaAttributes['aria-expanded'] = Boolean(rowNode.childrenExpanded); + } + + // if the parent is null, set size and position cannot be determined + if (rowNode.parent !== null) { + ariaAttributes['aria-setsize'] = filteredDescendantCountLookup[rowNode.parent] ?? 0; + ariaAttributes['aria-posinset'] = sortedVisibleRowPositionsLookup[rowNode.id]; + } + + return ariaAttributes; + }, + [privateApiRef, props.treeData], + ); + useGridRegisterPipeProcessor(privateApiRef, 'hydrateColumns', updateGroupingColumn); useGridRegisterStrategyProcessor( privateApiRef, @@ -223,6 +257,7 @@ export const useGridTreeDataPreProcessors = ( 'visibleRowsLookupCreation', getVisibleRowsLookup, ); + useGridRegisterPipeProcessor(privateApiRef, 'ariaAttributes', updateGridRowAriaAttributes); /** * 1ST RENDER diff --git a/packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.ts b/packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.ts deleted file mode 100644 index 44e01aa7aef97..0000000000000 --- a/packages/x-data-grid-pro/src/hooks/utils/useGridRowAriaAttributes.ts +++ /dev/null @@ -1,66 +0,0 @@ -import * as React from 'react'; -import { - GridAutoGeneratedGroupNode, - GridDataGroupNode, - GridRowId, - gridExpandedSortedRowIdsSelector, - gridFilteredDescendantCountLookupSelector, -} from '@mui/x-data-grid'; -import { useGridSelector } from '@mui/x-data-grid/internals'; -import { useGridRootProps } from './useGridRootProps'; -import { useGridPrivateApiContext } from './useGridPrivateApiContext'; - -interface GridRowAriaAttributes { - 'aria-level'?: number; - 'aria-setsize'?: number; - 'aria-posinset'?: number; - 'aria-expanded'?: boolean; -} - -export const useGridRowAriaAttributes = () => { - const apiRef = useGridPrivateApiContext(); - const rootProps = useGridRootProps(); - const filteredDescendantCountLookup = useGridSelector( - apiRef, - gridFilteredDescendantCountLookupSelector, - ); - const sortedVisibleRowIds = useGridSelector(apiRef, gridExpandedSortedRowIdsSelector); - - const getGridRowAriaAttributes = React.useCallback<(rowId: GridRowId) => GridRowAriaAttributes>( - (rowId) => { - const rowNode = apiRef.current.getRowNode(rowId); - const ariaAttributes: GridRowAriaAttributes = {}; - - if (rootProps.treeData !== true || rowNode === null) { - return ariaAttributes; - } - - ariaAttributes['aria-level'] = rowNode.depth + 1; - - // aria-expanded should only be added to the rows that contain children - const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; - if (rowNode.type === 'group' && filteredDescendantCount > 0) { - ariaAttributes['aria-expanded'] = Boolean(rowNode.childrenExpanded); - } - - // if the parent is null, set size and position cannot be determined - if (rowNode.parent !== null) { - const parentNode = apiRef.current.getRowNode(rowNode.parent) as - | GridDataGroupNode - | GridAutoGeneratedGroupNode; - const currentLevelIds = sortedVisibleRowIds.filter((id) => - parentNode.children.includes(id), - ); - ariaAttributes['aria-setsize'] = currentLevelIds.length; - ariaAttributes['aria-posinset'] = currentLevelIds.indexOf(rowNode.id) + 1; - } - - return ariaAttributes; - }, - [apiRef, rootProps.treeData, filteredDescendantCountLookup, sortedVisibleRowIds], - ); - - return { - getGridRowAriaAttributes, - }; -}; diff --git a/packages/x-data-grid/src/components/GridRow.tsx b/packages/x-data-grid/src/components/GridRow.tsx index ee26a2b20c1f6..b4c919eecdbda 100644 --- a/packages/x-data-grid/src/components/GridRow.tsx +++ b/packages/x-data-grid/src/components/GridRow.tsx @@ -307,6 +307,14 @@ const GridRow = React.forwardRef(function GridRow( }, [isNotVisible, rowHeight, styleProp, minHeight, sizes, rootProps.rowSpacingType]); const rowClassNames = apiRef.current.unstable_applyPipeProcessors('rowClassName', [], rowId); + const ariaAttributes = apiRef.current.unstable_applyPipeProcessors( + 'ariaAttributes', + { + 'aria-rowindex': ariaRowIndex, + 'aria-selected': selected, + }, + rowId, + ); if (typeof rootProps.getRowClassName === 'function') { const indexRelativeToCurrentPage = index - (currentPage.range?.firstRowIndex || 0); @@ -479,9 +487,8 @@ const GridRow = React.forwardRef(function GridRow( data-rowindex={index} role="row" className={clsx(...rowClassNames, classes.root, className)} - aria-rowindex={ariaRowIndex} - aria-selected={selected} style={style} + {...ariaAttributes} {...eventHandlers} {...other} > diff --git a/packages/x-data-grid/src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts b/packages/x-data-grid/src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts index 5e065f1a572ab..ed27b028b33b1 100644 --- a/packages/x-data-grid/src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts +++ b/packages/x-data-grid/src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts @@ -50,6 +50,10 @@ export interface GridPipeProcessingLookup { value: string[]; context: GridRowId; }; + ariaAttributes: { + value: Record; + context: GridRowId; + }; cellClassName: { value: string[]; context: GridCellCoordinates }; isCellSelected: { value: boolean; context: GridCellCoordinates }; canUpdateFocus: { From d5cced077a579b14e494e0b443a39a5eba507c06 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 27 Jun 2024 09:18:31 +0200 Subject: [PATCH 13/89] Fix lint issues --- .../x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx | 2 +- .../x-data-grid/src/hooks/features/filter/gridFilterSelector.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx index e7ebf3fb13a0d..4c35cc0a114e7 100644 --- a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx @@ -726,7 +726,7 @@ describe(' - Tree data', () => { }); }); - describe.only('accessibility', () => { + describe('accessibility', () => { it('should add necessary treegrid aria attributes to the rows', () => { render(); diff --git a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts index 1aadb3f82540b..8af74550dfa51 100644 --- a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts +++ b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts @@ -125,7 +125,7 @@ export const gridExpandedSortedRowIdsLookupSelector = createSelectorMemoized( } lastDepth = rowNode.depth; - depthPositionCounter[rowNode.depth]++; + depthPositionCounter[rowNode.depth] += 1; acc[rowId] = depthPositionCounter[rowNode.depth]; return acc; }, {}); From d5774f270e1cccd8b6828e36c20254d04a657fff Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 27 Jun 2024 09:19:57 +0200 Subject: [PATCH 14/89] Update API docs --- docs/pages/x/api/data-grid/selectors.json | 7 +++++++ scripts/x-data-grid-premium.exports.json | 1 + scripts/x-data-grid-pro.exports.json | 1 + scripts/x-data-grid.exports.json | 1 + 4 files changed, 10 insertions(+) diff --git a/docs/pages/x/api/data-grid/selectors.json b/docs/pages/x/api/data-grid/selectors.json index 092a70faf2623..91cb066f94835 100644 --- a/docs/pages/x/api/data-grid/selectors.json +++ b/docs/pages/x/api/data-grid/selectors.json @@ -172,6 +172,13 @@ "description": "Get the id and the model of the rows accessible after the filtering process.\nDoes not contain the collapsed children.", "supportsApiRef": true }, + { + "name": "gridExpandedSortedRowIdsLookupSelector", + "returnType": "Record", + "category": "Filtering", + "description": "Get the row ids accessible after the filtering process to position in the current tree level lookup.\nDoes not contain the collapsed children.", + "supportsApiRef": true + }, { "name": "gridExpandedSortedRowIdsSelector", "returnType": "GridRowId[]", diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index ac6c300397a0e..9bb48da8c2a7a 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -305,6 +305,7 @@ { "name": "GridExceljsProcessInput", "kind": "Interface" }, { "name": "gridExpandedRowCountSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowEntriesSelector", "kind": "Variable" }, + { "name": "gridExpandedSortedRowIdsLookupSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowIdsSelector", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExperimentalPremiumFeatures", "kind": "Interface" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index e9620df666a07..e6da5d2de8e3f 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -274,6 +274,7 @@ { "name": "GridEvents", "kind": "TypeAlias" }, { "name": "gridExpandedRowCountSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowEntriesSelector", "kind": "Variable" }, + { "name": "gridExpandedSortedRowIdsLookupSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowIdsSelector", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExperimentalProFeatures", "kind": "Interface" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index ac66be0724d09..7e64b2345a591 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -245,6 +245,7 @@ { "name": "GridEvents", "kind": "TypeAlias" }, { "name": "gridExpandedRowCountSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowEntriesSelector", "kind": "Variable" }, + { "name": "gridExpandedSortedRowIdsLookupSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowIdsSelector", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExperimentalFeatures", "kind": "Interface" }, From 8abb528eb0630e131964b65ecfd3580e3fce1623 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 27 Jun 2024 10:02:21 +0200 Subject: [PATCH 15/89] Fix counter reset logic --- .../src/hooks/features/filter/gridFilterSelector.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts index 8af74550dfa51..e66cf6c03f76c 100644 --- a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts +++ b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts @@ -116,12 +116,11 @@ export const gridExpandedSortedRowIdsLookupSelector = createSelectorMemoized( depthPositionCounter[rowNode.depth] = 0; } - // going deeper in the tree should keep the counters intact, because once we go back up - // position on that level continues from where it left off - // going back up in the tree should reset the counter for the levels below - // because the next item on that level is part of a different branch - if (rowNode.depth < lastDepth) { - depthPositionCounter[lastDepth] = 0; + // going deeper in the tree should reset the counter + // since it might have been used in some other branch at the same level, up in the tree + // going back up should keep the counter and continue where it left off + if (rowNode.depth > lastDepth) { + depthPositionCounter[rowNode.depth] = 0; } lastDepth = rowNode.depth; From 2b8b49366d6f20709cab5e73c1fa5db7e9ae732d Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 27 Jun 2024 10:10:29 +0200 Subject: [PATCH 16/89] Fix top level set size count --- .../features/treeData/useGridTreeDataPreProcessors.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeDataPreProcessors.tsx b/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeDataPreProcessors.tsx index 5930c89c26bb9..2118e6de3a6d6 100644 --- a/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeDataPreProcessors.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeDataPreProcessors.tsx @@ -9,6 +9,8 @@ import { GRID_CHECKBOX_SELECTION_FIELD, gridFilteredDescendantCountLookupSelector, gridExpandedSortedRowIdsLookupSelector, + GRID_ROOT_GROUP_ID, + gridFilteredTopLevelRowCountSelector, } from '@mui/x-data-grid'; import { GridPipeProcessor, @@ -219,6 +221,7 @@ export const useGridTreeDataPreProcessors = ( return ariaAttributes; } + const filteredTopLevelRowCount = gridFilteredTopLevelRowCountSelector(privateApiRef); const filteredDescendantCountLookup = gridFilteredDescendantCountLookupSelector(privateApiRef); const sortedVisibleRowPositionsLookup = gridExpandedSortedRowIdsLookupSelector(privateApiRef); @@ -233,7 +236,10 @@ export const useGridTreeDataPreProcessors = ( // if the parent is null, set size and position cannot be determined if (rowNode.parent !== null) { - ariaAttributes['aria-setsize'] = filteredDescendantCountLookup[rowNode.parent] ?? 0; + ariaAttributes['aria-setsize'] = + rowNode.parent === GRID_ROOT_GROUP_ID + ? filteredTopLevelRowCount + : filteredDescendantCountLookup[rowNode.parent]; ariaAttributes['aria-posinset'] = sortedVisibleRowPositionsLookup[rowNode.id]; } From 4289b1d2330171161c480fc4e764d123637c19f1 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 13:16:08 +0200 Subject: [PATCH 17/89] Remove grid row attributes pipe processor --- .../treeData/useGridTreeDataPreProcessors.tsx | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeDataPreProcessors.tsx b/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeDataPreProcessors.tsx index 2118e6de3a6d6..74c0fcfcda382 100644 --- a/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeDataPreProcessors.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/treeData/useGridTreeDataPreProcessors.tsx @@ -7,10 +7,6 @@ import { GridGroupNode, GridRowId, GRID_CHECKBOX_SELECTION_FIELD, - gridFilteredDescendantCountLookupSelector, - gridExpandedSortedRowIdsLookupSelector, - GRID_ROOT_GROUP_ID, - gridFilteredTopLevelRowCountSelector, } from '@mui/x-data-grid'; import { GridPipeProcessor, @@ -212,42 +208,6 @@ export const useGridTreeDataPreProcessors = ( [privateApiRef, props.disableChildrenSorting], ); - const updateGridRowAriaAttributes = React.useCallback>( - (attributes, rowId) => { - const rowNode = privateApiRef.current.getRowNode(rowId); - const ariaAttributes = attributes as Record; - - if (props.treeData !== true || rowNode === null) { - return ariaAttributes; - } - - const filteredTopLevelRowCount = gridFilteredTopLevelRowCountSelector(privateApiRef); - const filteredDescendantCountLookup = - gridFilteredDescendantCountLookupSelector(privateApiRef); - const sortedVisibleRowPositionsLookup = gridExpandedSortedRowIdsLookupSelector(privateApiRef); - - ariaAttributes['aria-level'] = rowNode.depth + 1; - - const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; - // aria-expanded should only be added to the rows that contain children - if (rowNode.type === 'group' && filteredDescendantCount > 0) { - ariaAttributes['aria-expanded'] = Boolean(rowNode.childrenExpanded); - } - - // if the parent is null, set size and position cannot be determined - if (rowNode.parent !== null) { - ariaAttributes['aria-setsize'] = - rowNode.parent === GRID_ROOT_GROUP_ID - ? filteredTopLevelRowCount - : filteredDescendantCountLookup[rowNode.parent]; - ariaAttributes['aria-posinset'] = sortedVisibleRowPositionsLookup[rowNode.id]; - } - - return ariaAttributes; - }, - [privateApiRef, props.treeData], - ); - useGridRegisterPipeProcessor(privateApiRef, 'hydrateColumns', updateGroupingColumn); useGridRegisterStrategyProcessor( privateApiRef, @@ -263,7 +223,6 @@ export const useGridTreeDataPreProcessors = ( 'visibleRowsLookupCreation', getVisibleRowsLookup, ); - useGridRegisterPipeProcessor(privateApiRef, 'ariaAttributes', updateGridRowAriaAttributes); /** * 1ST RENDER From 83f833be3da3fffbbd712dfd3a36184a68622a22 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 14:29:48 +0200 Subject: [PATCH 18/89] Add grid configuration context and models --- .../components/GridConfigurationContext.ts | 7 ++++++ .../src/context/GridContextProvider.tsx | 22 ++++++++++++++----- .../utils/useGridConfigurationContext.ts | 19 ++++++++++++++++ .../models/configuration/gridConfiguration.ts | 6 +++++ .../configuration/gridRowConfiguration.ts | 13 +++++++++++ 5 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 packages/x-data-grid/src/components/GridConfigurationContext.ts create mode 100644 packages/x-data-grid/src/hooks/utils/useGridConfigurationContext.ts create mode 100644 packages/x-data-grid/src/models/configuration/gridConfiguration.ts create mode 100644 packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts diff --git a/packages/x-data-grid/src/components/GridConfigurationContext.ts b/packages/x-data-grid/src/components/GridConfigurationContext.ts new file mode 100644 index 0000000000000..919b4cdf8ac9a --- /dev/null +++ b/packages/x-data-grid/src/components/GridConfigurationContext.ts @@ -0,0 +1,7 @@ +import * as React from 'react'; + +export const GridConfigurationContext = React.createContext(undefined); + +if (process.env.NODE_ENV !== 'production') { + GridConfigurationContext.displayName = 'GridConfigurationContext'; +} diff --git a/packages/x-data-grid/src/context/GridContextProvider.tsx b/packages/x-data-grid/src/context/GridContextProvider.tsx index 2fd8de2a3e435..d5557231ffcd3 100644 --- a/packages/x-data-grid/src/context/GridContextProvider.tsx +++ b/packages/x-data-grid/src/context/GridContextProvider.tsx @@ -3,21 +3,31 @@ import { GridApiContext } from '../components/GridApiContext'; import { GridPrivateApiContext } from '../hooks/utils/useGridPrivateApiContext'; import { GridPrivateApiCommunity } from '../models/api/gridApiCommunity'; import { GridRootPropsContext } from './GridRootPropsContext'; +import { GridConfiguration } from '../models/configuration/gridConfiguration'; +import { GridConfigurationContext } from '../components/GridConfigurationContext'; type GridContextProviderProps = { privateApiRef: React.MutableRefObject; + configuration: GridConfiguration; props: {}; children: React.ReactNode; }; -export function GridContextProvider({ privateApiRef, props, children }: GridContextProviderProps) { +export function GridContextProvider({ + privateApiRef, + configuration, + props, + children, +}: GridContextProviderProps) { const apiRef = React.useRef(privateApiRef.current.getPublicApi()); return ( - - - {children} - - + + + + {children} + + + ); } diff --git a/packages/x-data-grid/src/hooks/utils/useGridConfigurationContext.ts b/packages/x-data-grid/src/hooks/utils/useGridConfigurationContext.ts new file mode 100644 index 0000000000000..95395315624de --- /dev/null +++ b/packages/x-data-grid/src/hooks/utils/useGridConfigurationContext.ts @@ -0,0 +1,19 @@ +import * as React from 'react'; +import { GridConfigurationContext } from '../../components/GridConfigurationContext'; +import { GridConfiguration } from '../../models/configuration/gridConfiguration'; + +export const useGridConfigurationContext = () => { + const configuration = React.useContext(GridConfigurationContext); + + if (configuration === undefined) { + throw new Error( + [ + 'MUI X: Could not find the data grid configuration context.', + 'It looks like you rendered your component outside of a DataGrid, DataGridPro or DataGridPremium parent component.', + 'This can also happen if you are bundling multiple versions of the data grid.', + ].join('\n'), + ); + } + + return configuration as GridConfiguration; +}; diff --git a/packages/x-data-grid/src/models/configuration/gridConfiguration.ts b/packages/x-data-grid/src/models/configuration/gridConfiguration.ts new file mode 100644 index 0000000000000..c73bce3ec0065 --- /dev/null +++ b/packages/x-data-grid/src/models/configuration/gridConfiguration.ts @@ -0,0 +1,6 @@ +import { GridRowInternalHook } from './gridRowConfiguration'; + +export type GridInternalHook = GridRowInternalHook; +export interface GridConfiguration { + hooks: Record; +} diff --git a/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts b/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts new file mode 100644 index 0000000000000..d54db5a3009ff --- /dev/null +++ b/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts @@ -0,0 +1,13 @@ +import { GridRowId } from '../gridRows'; + +export type GridRowInternalHook = () => { + /** + * Get the ARIA attributes for a row + * @param {GridRowId} rowId The id of the row + * @param {number} index The position index of the row + */ + getRowAriaAttributes: ( + rowId: GridRowId, + index: number, + ) => Record; +}; From 52f6d750bf222aa1d67401b7f3dd002a4db1e43f Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 14:31:28 +0200 Subject: [PATCH 19/89] Create community and pro version of the hooks that compile row specific aria attributes --- .../src/hooks/features/rows/index.tsx | 1 + .../rows/useGridRowAriaAttributes.tsx | 69 +++++++++++++++++++ .../x-data-grid-pro/src/internals/index.ts | 1 + .../rows/useGridRowAriaAttributes.tsx | 36 ++++++++++ packages/x-data-grid/src/internals/index.ts | 1 + 5 files changed, 108 insertions(+) create mode 100644 packages/x-data-grid-pro/src/hooks/features/rows/index.tsx create mode 100644 packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx create mode 100644 packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx diff --git a/packages/x-data-grid-pro/src/hooks/features/rows/index.tsx b/packages/x-data-grid-pro/src/hooks/features/rows/index.tsx new file mode 100644 index 0000000000000..bf3c51abb3373 --- /dev/null +++ b/packages/x-data-grid-pro/src/hooks/features/rows/index.tsx @@ -0,0 +1 @@ +export * from './useGridRowAriaAttributes'; diff --git a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx new file mode 100644 index 0000000000000..ec3255df07887 --- /dev/null +++ b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -0,0 +1,69 @@ +import * as React from 'react'; +import { + GridRowId, + useGridSelector, + gridFilteredTopLevelRowCountSelector, + gridFilteredDescendantCountLookupSelector, + gridExpandedSortedRowIdsLookupSelector, + GRID_ROOT_GROUP_ID, +} from '@mui/x-data-grid'; +import { useGridRowAriaAttributes as useGridRowAriaAttributesCommunity } from '@mui/x-data-grid/internals'; +import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext'; +import { useGridRootProps } from '../../utils/useGridRootProps'; + +export const useGridRowAriaAttributes = () => { + const apiRef = useGridPrivateApiContext(); + const props = useGridRootProps(); + const { getRowAriaAttributes: getRowAriaAttributesCommunity } = + useGridRowAriaAttributesCommunity(); + + const filteredTopLevelRowCount = useGridSelector(apiRef, gridFilteredTopLevelRowCountSelector); + const filteredDescendantCountLookup = useGridSelector( + apiRef, + gridFilteredDescendantCountLookupSelector, + ); + const sortedVisibleRowPositionsLookup = useGridSelector( + apiRef, + gridExpandedSortedRowIdsLookupSelector, + ); + + const getRowAriaAttributes = React.useCallback( + (rowId: GridRowId, index: number) => { + const rowNode = apiRef.current.getRowNode(rowId); + const ariaAttributes = getRowAriaAttributesCommunity(rowId, index); + + if (rowNode === null || props.treeData !== true) { + return ariaAttributes; + } + + ariaAttributes['aria-level'] = rowNode.depth + 1; + + const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; + // aria-expanded should only be added to the rows that contain children + if (rowNode.type === 'group' && filteredDescendantCount > 0) { + ariaAttributes['aria-expanded'] = Boolean(rowNode.childrenExpanded); + } + + // if the parent is null, set size and position cannot be determined + if (rowNode.parent !== null) { + ariaAttributes['aria-setsize'] = + rowNode.parent === GRID_ROOT_GROUP_ID + ? filteredTopLevelRowCount + : filteredDescendantCountLookup[rowNode.parent]; + ariaAttributes['aria-posinset'] = sortedVisibleRowPositionsLookup[rowNode.id]; + } + + return ariaAttributes; + }, + [ + apiRef, + props.treeData, + filteredTopLevelRowCount, + filteredDescendantCountLookup, + sortedVisibleRowPositionsLookup, + getRowAriaAttributesCommunity, + ], + ); + + return { getRowAriaAttributes }; +}; diff --git a/packages/x-data-grid-pro/src/internals/index.ts b/packages/x-data-grid-pro/src/internals/index.ts index 28b184e2bd42c..05a57ae40b168 100644 --- a/packages/x-data-grid-pro/src/internals/index.ts +++ b/packages/x-data-grid-pro/src/internals/index.ts @@ -22,6 +22,7 @@ export { } from '../hooks/features/detailPanel/useGridDetailPanel'; export { useGridDetailPanelPreProcessors } from '../hooks/features/detailPanel/useGridDetailPanelPreProcessors'; export { useGridInfiniteLoader } from '../hooks/features/infiniteLoader/useGridInfiniteLoader'; +export { useGridRowAriaAttributes } from '../hooks/features/rows/useGridRowAriaAttributes'; export { useGridRowReorder } from '../hooks/features/rowReorder/useGridRowReorder'; export { useGridRowReorderPreProcessors } from '../hooks/features/rowReorder/useGridRowReorderPreProcessors'; export { useGridTreeData } from '../hooks/features/treeData/useGridTreeData'; diff --git a/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx new file mode 100644 index 0000000000000..034e47bbf36d9 --- /dev/null +++ b/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -0,0 +1,36 @@ +import * as React from 'react'; +import { GridRowId } from '../../../models/gridRows'; +import { GridRowInternalHook } from '../../../models/configuration/gridRowConfiguration'; +import { selectedIdsLookupSelector } from '../rowSelection'; +import { useGridSelector } from '../../utils/useGridSelector'; +import { gridColumnGroupsHeaderMaxDepthSelector } from '../columnGrouping/gridColumnGroupsSelector'; +import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext'; + +export const useGridRowAriaAttributes: GridRowInternalHook = () => { + const apiRef = useGridPrivateApiContext(); + const selectedIdsLookup = useGridSelector(apiRef, selectedIdsLookupSelector); + const headerGroupingMaxDepth = useGridSelector(apiRef, gridColumnGroupsHeaderMaxDepthSelector); + + const getRowAriaAttributes = React.useCallback( + (rowId: GridRowId, index: number) => { + const rowNode = apiRef.current.getRowNode(rowId); + const ariaAttributes = {} as Record; + + if (rowNode === null) { + return ariaAttributes; + } + + const ariaRowIndex = index + headerGroupingMaxDepth + 2; // 1 for the header row and 1 as it's 1-based + ariaAttributes['aria-rowindex'] = ariaRowIndex; + + if (selectedIdsLookup[rowId]) { + ariaAttributes['aria-selected'] = true; + } + + return ariaAttributes; + }, + [apiRef, selectedIdsLookup, headerGroupingMaxDepth], + ); + + return { getRowAriaAttributes }; +}; diff --git a/packages/x-data-grid/src/internals/index.ts b/packages/x-data-grid/src/internals/index.ts index 90f1ca592e487..051c7a54af04f 100644 --- a/packages/x-data-grid/src/internals/index.ts +++ b/packages/x-data-grid/src/internals/index.ts @@ -74,6 +74,7 @@ export { export { useGridEditing, editingStateInitializer } from '../hooks/features/editing/useGridEditing'; export { gridEditRowsStateSelector } from '../hooks/features/editing/gridEditingSelectors'; export { useGridRows, rowsStateInitializer } from '../hooks/features/rows/useGridRows'; +export { useGridRowAriaAttributes } from '../hooks/features/rows/useGridRowAriaAttributes'; export { useGridRowsPreProcessors } from '../hooks/features/rows/useGridRowsPreProcessors'; export type { GridRowTreeCreationParams, From 0cb9b81b862a795e7defa416cc7f7cf430f4d27b Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 14:31:52 +0200 Subject: [PATCH 20/89] Add hooks to the configuration context --- .../src/DataGridPremium/DataGridPremium.tsx | 6 ++++-- packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx | 5 ++++- packages/x-data-grid/src/DataGrid/DataGrid.tsx | 6 +++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index 13c08a00b7e19..ecb32a8115ee3 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -15,6 +15,7 @@ import { propValidatorsDataGridPro, PropValidator, validateProps, + useGridRowAriaAttributes, } from '@mui/x-data-grid-pro/internals'; import { useDataGridPremiumComponent } from './useDataGridPremiumComponent'; import { @@ -40,14 +41,15 @@ const DataGridPremiumRaw = React.forwardRef(function DataGridPremium + + + Date: Wed, 3 Jul 2024 14:32:17 +0200 Subject: [PATCH 21/89] Use configuration context to add aria attributes to the grid row --- packages/x-data-grid/src/components/GridRow.tsx | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/x-data-grid/src/components/GridRow.tsx b/packages/x-data-grid/src/components/GridRow.tsx index b4c919eecdbda..6b83d82671164 100644 --- a/packages/x-data-grid/src/components/GridRow.tsx +++ b/packages/x-data-grid/src/components/GridRow.tsx @@ -24,11 +24,11 @@ import { GRID_DETAIL_PANEL_TOGGLE_FIELD } from '../constants/gridDetailPanelTogg import type { GridDimensions } from '../hooks/features/dimensions'; import { gridSortModelSelector } from '../hooks/features/sorting/gridSortingSelector'; import { gridRowMaximumTreeDepthSelector } from '../hooks/features/rows/gridRowsSelector'; -import { gridColumnGroupsHeaderMaxDepthSelector } from '../hooks/features/columnGrouping/gridColumnGroupsSelector'; import { gridEditRowsStateSelector } from '../hooks/features/editing/gridEditingSelectors'; import { PinnedPosition, gridPinnedColumnPositionLookup } from './cell/GridCell'; import { GridScrollbarFillerCell as ScrollbarFiller } from './GridScrollbarFillerCell'; import { getPinnedCellOffset } from '../internals/utils/getPinnedCellOffset'; +import { useGridConfigurationContext } from '../hooks/utils/useGridConfigurationContext'; export interface GridRowProps extends React.HTMLAttributes { row: GridRowModel; @@ -112,12 +112,12 @@ const GridRow = React.forwardRef(function GridRow( ...other } = props; const apiRef = useGridApiContext(); + const gridConfiguration = useGridConfigurationContext(); const ref = React.useRef(null); const rootProps = useGridRootProps(); const currentPage = useGridVisibleRows(apiRef, rootProps); const sortModel = useGridSelector(apiRef, gridSortModelSelector); const treeDepth = useGridSelector(apiRef, gridRowMaximumTreeDepthSelector); - const headerGroupingMaxDepth = useGridSelector(apiRef, gridColumnGroupsHeaderMaxDepthSelector); const columnPositions = useGridSelector(apiRef, gridColumnPositionsSelector); const editRowsState = useGridSelector(apiRef, gridEditRowsStateSelector); const handleRef = useForkRef(ref, refProp); @@ -137,8 +137,6 @@ const GridRow = React.forwardRef(function GridRow( focusedColumnIndex < visibleColumns.length - pinnedColumns.right.length && focusedColumnIndex >= renderContext.lastColumnIndex; - const ariaRowIndex = index + headerGroupingMaxDepth + 2; // 1 for the header row and 1 as it's 1-based - const classes = composeGridClasses(rootProps.classes, { root: [ 'row', @@ -151,6 +149,7 @@ const GridRow = React.forwardRef(function GridRow( rowHeight === 'auto' && 'row--dynamicHeight', ], }); + const { getRowAriaAttributes } = gridConfiguration.hooks.useGridRowAriaAttributes(); React.useLayoutEffect(() => { if (currentPage.range) { @@ -307,14 +306,7 @@ const GridRow = React.forwardRef(function GridRow( }, [isNotVisible, rowHeight, styleProp, minHeight, sizes, rootProps.rowSpacingType]); const rowClassNames = apiRef.current.unstable_applyPipeProcessors('rowClassName', [], rowId); - const ariaAttributes = apiRef.current.unstable_applyPipeProcessors( - 'ariaAttributes', - { - 'aria-rowindex': ariaRowIndex, - 'aria-selected': selected, - }, - rowId, - ); + const ariaAttributes = getRowAriaAttributes(rowId, index); if (typeof rootProps.getRowClassName === 'function') { const indexRelativeToCurrentPage = index - (currentPage.range?.firstRowIndex || 0); From 0380e54163a07d3322142ff590d5760c4b1cf694 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 14:50:40 +0200 Subject: [PATCH 22/89] Fix lint issue --- .../x-data-grid/src/models/configuration/gridRowConfiguration.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts b/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts index d54db5a3009ff..7c0020c14d9e3 100644 --- a/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts +++ b/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts @@ -5,6 +5,7 @@ export type GridRowInternalHook = () => { * Get the ARIA attributes for a row * @param {GridRowId} rowId The id of the row * @param {number} index The position index of the row + * @returns {Record} The ARIA attributes */ getRowAriaAttributes: ( rowId: GridRowId, From a55ad860c678c48a5e023759ceaea0f171044588 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 14:51:13 +0200 Subject: [PATCH 23/89] Ignore multiple export lint issue for re-exporting of the aria attribute hook --- packages/x-data-grid-pro/src/internals/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/x-data-grid-pro/src/internals/index.ts b/packages/x-data-grid-pro/src/internals/index.ts index 05a57ae40b168..7b88761c0b3c2 100644 --- a/packages/x-data-grid-pro/src/internals/index.ts +++ b/packages/x-data-grid-pro/src/internals/index.ts @@ -22,6 +22,8 @@ export { } from '../hooks/features/detailPanel/useGridDetailPanel'; export { useGridDetailPanelPreProcessors } from '../hooks/features/detailPanel/useGridDetailPanelPreProcessors'; export { useGridInfiniteLoader } from '../hooks/features/infiniteLoader/useGridInfiniteLoader'; + +// eslint-disable-next-line import/export export { useGridRowAriaAttributes } from '../hooks/features/rows/useGridRowAriaAttributes'; export { useGridRowReorder } from '../hooks/features/rowReorder/useGridRowReorder'; export { useGridRowReorderPreProcessors } from '../hooks/features/rowReorder/useGridRowReorderPreProcessors'; From 82c7d7b4feaff5efe4f008cab2a3446579544f8d Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 14:52:03 +0200 Subject: [PATCH 24/89] Add additional assertions to the tree data accessbility test to cover set size calculation bug --- .../x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx index 4c35cc0a114e7..be2ef9a951906 100644 --- a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx @@ -758,6 +758,8 @@ describe(' - Tree data', () => { expect(getRow(1).getAttribute('aria-posinset')).to.equal('1'); expect(getRow(1).getAttribute('aria-setsize')).to.equal('1'); // A.A is filtered out, set size is now 1 expect(getRow(2).getAttribute('aria-level')).to.equal('1'); // B + expect(getRow(3).getAttribute('aria-posinset')).to.equal('1'); // B.A + expect(getRow(3).getAttribute('aria-setsize')).to.equal('2'); // B.A & B.B }); }); From 1ea6d0b7839d7da2992d04388ce907a8e4c43950 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 16:48:32 +0200 Subject: [PATCH 25/89] Add children count lookup --- .../src/hooks/features/rowGrouping/gridRowGroupingUtils.ts | 7 +++++++ .../src/hooks/features/treeData/gridTreeDataUtils.ts | 7 +++++++ .../src/hooks/features/filter/gridFilterState.ts | 5 +++++ .../src/hooks/features/filter/useGridFilter.tsx | 3 +++ 4 files changed, 22 insertions(+) diff --git a/packages/x-data-grid-premium/src/hooks/features/rowGrouping/gridRowGroupingUtils.ts b/packages/x-data-grid-premium/src/hooks/features/rowGrouping/gridRowGroupingUtils.ts index 361c76b069c51..1cdec6a7c6631 100644 --- a/packages/x-data-grid-premium/src/hooks/features/rowGrouping/gridRowGroupingUtils.ts +++ b/packages/x-data-grid-premium/src/hooks/features/rowGrouping/gridRowGroupingUtils.ts @@ -83,6 +83,7 @@ export const filterRowTreeFromGroupingColumns = ( ): Omit => { const { apiRef, rowTree, isRowMatchingFilters, filterModel } = params; const filteredRowsLookup: Record = {}; + const filteredChildrenCountLookup: Record = {}; const filteredDescendantCountLookup: Record = {}; const filterCache = {}; @@ -110,6 +111,7 @@ export const filterRowTreeFromGroupingColumns = ( isPassingFiltering = true; } + let filteredChildrenCount = 0; let filteredDescendantCount = 0; if (node.type === 'group') { node.children.forEach((childId) => { @@ -120,6 +122,9 @@ export const filterRowTreeFromGroupingColumns = ( [...ancestorsResults, filterResults], ); filteredDescendantCount += childSubTreeSize; + if (childSubTreeSize > 0) { + filteredChildrenCount += 1; + } }); } @@ -145,6 +150,7 @@ export const filterRowTreeFromGroupingColumns = ( return 0; } + filteredChildrenCountLookup[node.id] = filteredChildrenCount; filteredDescendantCountLookup[node.id] = filteredDescendantCount; if (node.type !== 'group') { @@ -164,6 +170,7 @@ export const filterRowTreeFromGroupingColumns = ( return { filteredRowsLookup, + filteredChildrenCountLookup, filteredDescendantCountLookup, }; }; diff --git a/packages/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataUtils.ts b/packages/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataUtils.ts index 9926ef35c3df5..ee8224e89b082 100644 --- a/packages/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataUtils.ts +++ b/packages/x-data-grid-pro/src/hooks/features/treeData/gridTreeDataUtils.ts @@ -32,6 +32,7 @@ export const filterRowTreeFromTreeData = ( ): Omit => { const { apiRef, rowTree, disableChildrenFiltering, isRowMatchingFilters } = params; const filteredRowsLookup: Record = {}; + const filteredChildrenCountLookup: Record = {}; const filteredDescendantCountLookup: Record = {}; const filterCache = {}; @@ -64,6 +65,7 @@ export const filterRowTreeFromTreeData = ( ); } + let filteredChildrenCount = 0; let filteredDescendantCount = 0; if (node.type === 'group') { node.children.forEach((childId) => { @@ -75,6 +77,9 @@ export const filterRowTreeFromTreeData = ( ); filteredDescendantCount += childSubTreeSize; + if (childSubTreeSize > 0) { + filteredChildrenCount += 1; + } }); } @@ -100,6 +105,7 @@ export const filterRowTreeFromTreeData = ( return 0; } + filteredChildrenCountLookup[node.id] = filteredChildrenCount; filteredDescendantCountLookup[node.id] = filteredDescendantCount; if (node.type === 'footer') { @@ -119,6 +125,7 @@ export const filterRowTreeFromTreeData = ( return { filteredRowsLookup, + filteredChildrenCountLookup, filteredDescendantCountLookup, }; }; diff --git a/packages/x-data-grid/src/hooks/features/filter/gridFilterState.ts b/packages/x-data-grid/src/hooks/features/filter/gridFilterState.ts index 0c216b8f55197..df84b7bf4aa37 100644 --- a/packages/x-data-grid/src/hooks/features/filter/gridFilterState.ts +++ b/packages/x-data-grid/src/hooks/features/filter/gridFilterState.ts @@ -21,6 +21,11 @@ export interface GridFilterState { * This is the equivalent of the `visibleRowsLookup` if all the groups were expanded. */ filteredRowsLookup: Record; + /** + * Amount of children that are passing the filters or have children that are passing the filter (does not count grand children). + * If a row is not registered in this lookup, it is supposed to have no descendant passing the filters. + */ + filteredChildrenCountLookup: Record; /** * Amount of descendants that are passing the filters. * For the Tree Data, it includes all the intermediate depth levels (= amount of children + amount of grand children + ...). diff --git a/packages/x-data-grid/src/hooks/features/filter/useGridFilter.tsx b/packages/x-data-grid/src/hooks/features/filter/useGridFilter.tsx index 031320af23c33..1ad1ae3d7d947 100644 --- a/packages/x-data-grid/src/hooks/features/filter/useGridFilter.tsx +++ b/packages/x-data-grid/src/hooks/features/filter/useGridFilter.tsx @@ -46,6 +46,7 @@ export const filterStateInitializer: GridStateInitializer< filter: { filterModel: sanitizeFilterModel(filterModel, props.disableMultipleColumnsFiltering, apiRef), filteredRowsLookup: {}, + filteredChildrenCountLookup: {}, filteredDescendantCountLookup: {}, }, visibleRowsLookup: {}, @@ -424,6 +425,7 @@ export const useGridFilter = ( if (props.filterMode !== 'client' || !params.isRowMatchingFilters) { return { filteredRowsLookup: {}, + filteredChildrenCountLookup: {}, filteredDescendantCountLookup: {}, }; } @@ -464,6 +466,7 @@ export const useGridFilter = ( return { filteredRowsLookup, + filteredChildrenCountLookup: {}, filteredDescendantCountLookup: {}, }; }, From 2aa18506d9deded33c4485d1ea53e5e2d69acbec Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 16:48:46 +0200 Subject: [PATCH 26/89] Add children count lookup selector --- .../src/hooks/features/filter/gridFilterSelector.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts index e66cf6c03f76c..ae24023bba400 100644 --- a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts +++ b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts @@ -44,6 +44,15 @@ export const gridFilteredRowsLookupSelector = createSelector( (filterState) => filterState.filteredRowsLookup, ); +/** + * @category Filtering + * @ignore - do not document. + */ +export const gridFilteredChildrenCountLookupSelector = createSelector( + gridFilterStateSelector, + (filterState) => filterState.filteredChildrenCountLookup, +); + /** * @category Filtering * @ignore - do not document. From e0f88306603030cb88a69ffec579fc8f94a9cfc3 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 16:49:15 +0200 Subject: [PATCH 27/89] Use children count lookup to determine the set size (excludes grand children) --- .../features/rows/useGridRowAriaAttributes.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx index ec3255df07887..15d7a21c92787 100644 --- a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -3,7 +3,7 @@ import { GridRowId, useGridSelector, gridFilteredTopLevelRowCountSelector, - gridFilteredDescendantCountLookupSelector, + gridFilteredChildrenCountLookupSelector, gridExpandedSortedRowIdsLookupSelector, GRID_ROOT_GROUP_ID, } from '@mui/x-data-grid'; @@ -18,9 +18,9 @@ export const useGridRowAriaAttributes = () => { useGridRowAriaAttributesCommunity(); const filteredTopLevelRowCount = useGridSelector(apiRef, gridFilteredTopLevelRowCountSelector); - const filteredDescendantCountLookup = useGridSelector( + const filteredChildrenCountLookup = useGridSelector( apiRef, - gridFilteredDescendantCountLookupSelector, + gridFilteredChildrenCountLookupSelector, ); const sortedVisibleRowPositionsLookup = useGridSelector( apiRef, @@ -38,9 +38,9 @@ export const useGridRowAriaAttributes = () => { ariaAttributes['aria-level'] = rowNode.depth + 1; - const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; + const filteredChildrenCount = filteredChildrenCountLookup[rowNode.id] ?? 0; // aria-expanded should only be added to the rows that contain children - if (rowNode.type === 'group' && filteredDescendantCount > 0) { + if (rowNode.type === 'group' && filteredChildrenCount > 0) { ariaAttributes['aria-expanded'] = Boolean(rowNode.childrenExpanded); } @@ -49,7 +49,7 @@ export const useGridRowAriaAttributes = () => { ariaAttributes['aria-setsize'] = rowNode.parent === GRID_ROOT_GROUP_ID ? filteredTopLevelRowCount - : filteredDescendantCountLookup[rowNode.parent]; + : filteredChildrenCountLookup[rowNode.parent]; ariaAttributes['aria-posinset'] = sortedVisibleRowPositionsLookup[rowNode.id]; } @@ -59,7 +59,7 @@ export const useGridRowAriaAttributes = () => { apiRef, props.treeData, filteredTopLevelRowCount, - filteredDescendantCountLookup, + filteredChildrenCountLookup, sortedVisibleRowPositionsLookup, getRowAriaAttributesCommunity, ], From c4677b779153b7007383944a022d3ab8b12e8bf0 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 16:49:35 +0200 Subject: [PATCH 28/89] Add tests for the new count lookup --- .../rowGrouping.DataGridPremium.test.tsx | 39 +++++++++++++++++++ .../src/tests/treeData.DataGridPro.test.tsx | 34 ++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/packages/x-data-grid-premium/src/tests/rowGrouping.DataGridPremium.test.tsx b/packages/x-data-grid-premium/src/tests/rowGrouping.DataGridPremium.test.tsx index 824d610884a26..6ca61d73bbcc4 100644 --- a/packages/x-data-grid-premium/src/tests/rowGrouping.DataGridPremium.test.tsx +++ b/packages/x-data-grid-premium/src/tests/rowGrouping.DataGridPremium.test.tsx @@ -2381,6 +2381,45 @@ describe(' - Row grouping', () => { // Corresponds to rows id 0, 1, 2 because of Cat A, ann id 4 because of Cat 1 expect(getColumnValues(1)).to.deep.equal(['', '0', '1', '2', '', '4']); }); + + it('should keep the correct count of the children and descendants in the filter state', () => { + const extendedColumns = [ + ...baselineProps.columns, + { + field: 'value1', + }, + ]; + + const extendedRows = rows.map((row, index) => ({ ...row, value1: `Value${index}` })); + const additionalRows = [ + { id: 5, category1: 'Cat A', category2: 'Cat 2', value1: 'Value5' }, + { id: 6, category1: 'Cat A', category2: 'Cat 2', value1: 'Value6' }, + { id: 7, category1: 'Cat B', category2: 'Cat 1', value1: 'Value7' }, + ]; + + render( + , + ); + + const { filteredChildrenCountLookup, filteredDescendantCountLookup } = + apiRef.current.state.filter; + + expect(filteredChildrenCountLookup['auto-generated-row-category1/Cat A']).to.equal(2); + expect(filteredDescendantCountLookup['auto-generated-row-category1/Cat A']).to.equal(5); + + expect( + filteredChildrenCountLookup['auto-generated-row-category1/Cat A-category2/Cat 2'], + ).to.equal(4); + expect( + filteredDescendantCountLookup['auto-generated-row-category1/Cat A-category2/Cat 2'], + ).to.equal(4); + }); }); describe('prop: rowGroupingColumnMode = "multiple"', () => { diff --git a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx index be2ef9a951906..2a0e42ee1c758 100644 --- a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx @@ -592,6 +592,40 @@ describe(' - Tree data', () => { expect(getColumnValues(0)).to.deep.equal(['B (1)', 'D', 'D (1)', 'A']); }); + + it('should keep the correct count of the children and descendants in the filter state', () => { + render( + , + ); + + const { filteredChildrenCountLookup, filteredDescendantCountLookup } = + apiRef.current.state.filter; + + expect(filteredChildrenCountLookup['A']).to.equal(3); + expect(filteredDescendantCountLookup['A']).to.equal(5); + + expect(filteredChildrenCountLookup['B']).to.equal(1); + expect(filteredDescendantCountLookup['B']).to.equal(1); + + expect(filteredChildrenCountLookup['C']).to.be.undefined; + expect(filteredDescendantCountLookup['C']).to.be.undefined; + }); }); describe('sorting', () => { From 2f4cb250728a96ad1862fff0b5cd5e9393d7294a Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 16:53:09 +0200 Subject: [PATCH 29/89] Fix lint issues --- .../src/tests/treeData.DataGridPro.test.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx index 2a0e42ee1c758..10cdbc982259b 100644 --- a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx @@ -617,14 +617,14 @@ describe(' - Tree data', () => { const { filteredChildrenCountLookup, filteredDescendantCountLookup } = apiRef.current.state.filter; - expect(filteredChildrenCountLookup['A']).to.equal(3); - expect(filteredDescendantCountLookup['A']).to.equal(5); + expect(filteredChildrenCountLookup.A).to.equal(3); + expect(filteredDescendantCountLookup.A).to.equal(5); - expect(filteredChildrenCountLookup['B']).to.equal(1); - expect(filteredDescendantCountLookup['B']).to.equal(1); + expect(filteredChildrenCountLookup.B).to.equal(1); + expect(filteredDescendantCountLookup.B).to.equal(1); - expect(filteredChildrenCountLookup['C']).to.be.undefined; - expect(filteredDescendantCountLookup['C']).to.be.undefined; + expect(filteredChildrenCountLookup.C).to.equal(undefined); + expect(filteredDescendantCountLookup.C).to.equal(undefined); }); }); From 323d3ebbf8f99a93ec991de67d53cf5948526733 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 16:59:14 +0200 Subject: [PATCH 30/89] Rebuild API docs --- scripts/x-data-grid-premium.exports.json | 1 + scripts/x-data-grid-pro.exports.json | 1 + scripts/x-data-grid.exports.json | 1 + 3 files changed, 3 insertions(+) diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index 9bb48da8c2a7a..059b14d6afb9c 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -325,6 +325,7 @@ { "name": "gridFilterActiveItemsSelector", "kind": "Variable" }, { "name": "GridFilterAltIcon", "kind": "Variable" }, { "name": "GridFilterApi", "kind": "Interface" }, + { "name": "gridFilteredChildrenCountLookupSelector", "kind": "Variable" }, { "name": "gridFilteredDescendantCountLookupSelector", "kind": "Variable" }, { "name": "gridFilteredDescendantRowCountSelector", "kind": "Variable" }, { "name": "gridFilteredRowCountSelector", "kind": "Variable" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index e6da5d2de8e3f..a546beb3c5743 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -294,6 +294,7 @@ { "name": "gridFilterActiveItemsSelector", "kind": "Variable" }, { "name": "GridFilterAltIcon", "kind": "Variable" }, { "name": "GridFilterApi", "kind": "Interface" }, + { "name": "gridFilteredChildrenCountLookupSelector", "kind": "Variable" }, { "name": "gridFilteredDescendantCountLookupSelector", "kind": "Variable" }, { "name": "gridFilteredDescendantRowCountSelector", "kind": "Variable" }, { "name": "gridFilteredRowCountSelector", "kind": "Variable" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index 7e64b2345a591..e33a3ed27a0ad 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -264,6 +264,7 @@ { "name": "gridFilterActiveItemsSelector", "kind": "Variable" }, { "name": "GridFilterAltIcon", "kind": "Variable" }, { "name": "GridFilterApi", "kind": "Interface" }, + { "name": "gridFilteredChildrenCountLookupSelector", "kind": "Variable" }, { "name": "gridFilteredDescendantCountLookupSelector", "kind": "Variable" }, { "name": "gridFilteredDescendantRowCountSelector", "kind": "Variable" }, { "name": "gridFilteredRowCountSelector", "kind": "Variable" }, From 65fa808c724929038841bf852802bb78af90069f Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 16:59:32 +0200 Subject: [PATCH 31/89] Remove ariaAttributes from pipe processing interface --- .../src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/x-data-grid/src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts b/packages/x-data-grid/src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts index ed27b028b33b1..5e065f1a572ab 100644 --- a/packages/x-data-grid/src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts +++ b/packages/x-data-grid/src/hooks/core/pipeProcessing/gridPipeProcessingApi.ts @@ -50,10 +50,6 @@ export interface GridPipeProcessingLookup { value: string[]; context: GridRowId; }; - ariaAttributes: { - value: Record; - context: GridRowId; - }; cellClassName: { value: string[]; context: GridCellCoordinates }; isCellSelected: { value: boolean; context: GridCellCoordinates }; canUpdateFocus: { From 841f0e0ca8e0aa9f5ac8197457f32c6f4dbbb69c Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 19:24:38 +0200 Subject: [PATCH 32/89] Extract static object to prevent unnecessary re-renders --- .../src/DataGridPremium/DataGridPremium.tsx | 3 +-- packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx | 3 +-- packages/x-data-grid/src/DataGrid/DataGrid.tsx | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index ecb32a8115ee3..251934e31cfcb 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -27,6 +27,7 @@ import { getReleaseInfo } from '../utils/releaseInfo'; export type { GridPremiumSlotsComponent as GridSlots } from '../models'; +const configuration = { hooks: { useGridRowAriaAttributes } }; const releaseInfo = getReleaseInfo(); let dataGridPremiumPropValidators: PropValidator[]; @@ -41,8 +42,6 @@ const DataGridPremiumRaw = React.forwardRef(function DataGridPremium( @@ -28,8 +29,6 @@ const DataGridProRaw = React.forwardRef(function DataGridPro[]; if (process.env.NODE_ENV !== 'production') { @@ -42,9 +43,6 @@ const DataGridRaw = React.forwardRef(function DataGrid Date: Wed, 3 Jul 2024 19:26:24 +0200 Subject: [PATCH 33/89] Rename useGridConfigurationContext -> useGridConfiguration --- packages/x-data-grid/src/components/GridRow.tsx | 4 ++-- ...useGridConfigurationContext.ts => useGridConfiguration.ts} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename packages/x-data-grid/src/hooks/utils/{useGridConfigurationContext.ts => useGridConfiguration.ts} (93%) diff --git a/packages/x-data-grid/src/components/GridRow.tsx b/packages/x-data-grid/src/components/GridRow.tsx index 6b83d82671164..90a39bc131fe2 100644 --- a/packages/x-data-grid/src/components/GridRow.tsx +++ b/packages/x-data-grid/src/components/GridRow.tsx @@ -28,7 +28,7 @@ import { gridEditRowsStateSelector } from '../hooks/features/editing/gridEditing import { PinnedPosition, gridPinnedColumnPositionLookup } from './cell/GridCell'; import { GridScrollbarFillerCell as ScrollbarFiller } from './GridScrollbarFillerCell'; import { getPinnedCellOffset } from '../internals/utils/getPinnedCellOffset'; -import { useGridConfigurationContext } from '../hooks/utils/useGridConfigurationContext'; +import { useGridConfiguration } from '../hooks/utils/useGridConfiguration'; export interface GridRowProps extends React.HTMLAttributes { row: GridRowModel; @@ -112,7 +112,7 @@ const GridRow = React.forwardRef(function GridRow( ...other } = props; const apiRef = useGridApiContext(); - const gridConfiguration = useGridConfigurationContext(); + const gridConfiguration = useGridConfiguration(); const ref = React.useRef(null); const rootProps = useGridRootProps(); const currentPage = useGridVisibleRows(apiRef, rootProps); diff --git a/packages/x-data-grid/src/hooks/utils/useGridConfigurationContext.ts b/packages/x-data-grid/src/hooks/utils/useGridConfiguration.ts similarity index 93% rename from packages/x-data-grid/src/hooks/utils/useGridConfigurationContext.ts rename to packages/x-data-grid/src/hooks/utils/useGridConfiguration.ts index 95395315624de..f65b863f77dba 100644 --- a/packages/x-data-grid/src/hooks/utils/useGridConfigurationContext.ts +++ b/packages/x-data-grid/src/hooks/utils/useGridConfiguration.ts @@ -2,7 +2,7 @@ import * as React from 'react'; import { GridConfigurationContext } from '../../components/GridConfigurationContext'; import { GridConfiguration } from '../../models/configuration/gridConfiguration'; -export const useGridConfigurationContext = () => { +export const useGridConfiguration = () => { const configuration = React.useContext(GridConfigurationContext); if (configuration === undefined) { From 0d0090daa0383763f3fd4a8ae6db356092492251 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Wed, 3 Jul 2024 19:37:54 +0200 Subject: [PATCH 34/89] Rename gridConfiguration -> configuration --- packages/x-data-grid/src/components/GridRow.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/x-data-grid/src/components/GridRow.tsx b/packages/x-data-grid/src/components/GridRow.tsx index 90a39bc131fe2..a2a3d194b5481 100644 --- a/packages/x-data-grid/src/components/GridRow.tsx +++ b/packages/x-data-grid/src/components/GridRow.tsx @@ -112,7 +112,7 @@ const GridRow = React.forwardRef(function GridRow( ...other } = props; const apiRef = useGridApiContext(); - const gridConfiguration = useGridConfiguration(); + const configuration = useGridConfiguration(); const ref = React.useRef(null); const rootProps = useGridRootProps(); const currentPage = useGridVisibleRows(apiRef, rootProps); @@ -149,7 +149,7 @@ const GridRow = React.forwardRef(function GridRow( rowHeight === 'auto' && 'row--dynamicHeight', ], }); - const { getRowAriaAttributes } = gridConfiguration.hooks.useGridRowAriaAttributes(); + const { getRowAriaAttributes } = configuration.hooks.useGridRowAriaAttributes(); React.useLayoutEffect(() => { if (currentPage.range) { From 226ac3fd8292a9711f2bc4d8280bda99e5166438 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 4 Jul 2024 23:28:39 +0200 Subject: [PATCH 35/89] Do not wrap aria attributes getter into an object --- .../rows/useGridRowAriaAttributes.tsx | 7 ++---- .../x-data-grid/src/components/GridRow.tsx | 2 +- .../rows/useGridRowAriaAttributes.tsx | 4 +--- .../configuration/gridRowConfiguration.ts | 24 +++++++++---------- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx index 15d7a21c92787..2af0b9c54aaa8 100644 --- a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -14,8 +14,7 @@ import { useGridRootProps } from '../../utils/useGridRootProps'; export const useGridRowAriaAttributes = () => { const apiRef = useGridPrivateApiContext(); const props = useGridRootProps(); - const { getRowAriaAttributes: getRowAriaAttributesCommunity } = - useGridRowAriaAttributesCommunity(); + const getRowAriaAttributesCommunity = useGridRowAriaAttributesCommunity(); const filteredTopLevelRowCount = useGridSelector(apiRef, gridFilteredTopLevelRowCountSelector); const filteredChildrenCountLookup = useGridSelector( @@ -27,7 +26,7 @@ export const useGridRowAriaAttributes = () => { gridExpandedSortedRowIdsLookupSelector, ); - const getRowAriaAttributes = React.useCallback( + return React.useCallback( (rowId: GridRowId, index: number) => { const rowNode = apiRef.current.getRowNode(rowId); const ariaAttributes = getRowAriaAttributesCommunity(rowId, index); @@ -64,6 +63,4 @@ export const useGridRowAriaAttributes = () => { getRowAriaAttributesCommunity, ], ); - - return { getRowAriaAttributes }; }; diff --git a/packages/x-data-grid/src/components/GridRow.tsx b/packages/x-data-grid/src/components/GridRow.tsx index a2a3d194b5481..02e29543cfa39 100644 --- a/packages/x-data-grid/src/components/GridRow.tsx +++ b/packages/x-data-grid/src/components/GridRow.tsx @@ -149,7 +149,7 @@ const GridRow = React.forwardRef(function GridRow( rowHeight === 'auto' && 'row--dynamicHeight', ], }); - const { getRowAriaAttributes } = configuration.hooks.useGridRowAriaAttributes(); + const getRowAriaAttributes = configuration.hooks.useGridRowAriaAttributes(); React.useLayoutEffect(() => { if (currentPage.range) { diff --git a/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx index 034e47bbf36d9..b8732116cb911 100644 --- a/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -11,7 +11,7 @@ export const useGridRowAriaAttributes: GridRowInternalHook = () => { const selectedIdsLookup = useGridSelector(apiRef, selectedIdsLookupSelector); const headerGroupingMaxDepth = useGridSelector(apiRef, gridColumnGroupsHeaderMaxDepthSelector); - const getRowAriaAttributes = React.useCallback( + return React.useCallback( (rowId: GridRowId, index: number) => { const rowNode = apiRef.current.getRowNode(rowId); const ariaAttributes = {} as Record; @@ -31,6 +31,4 @@ export const useGridRowAriaAttributes: GridRowInternalHook = () => { }, [apiRef, selectedIdsLookup, headerGroupingMaxDepth], ); - - return { getRowAriaAttributes }; }; diff --git a/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts b/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts index 7c0020c14d9e3..ea5f3d68e6ba0 100644 --- a/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts +++ b/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts @@ -1,14 +1,14 @@ import { GridRowId } from '../gridRows'; -export type GridRowInternalHook = () => { - /** - * Get the ARIA attributes for a row - * @param {GridRowId} rowId The id of the row - * @param {number} index The position index of the row - * @returns {Record} The ARIA attributes - */ - getRowAriaAttributes: ( - rowId: GridRowId, - index: number, - ) => Record; -}; +/** + * Get the ARIA attributes for a row + * @param {GridRowId} rowId The id of the row + * @param {number} index The position index of the row + * @returns {Record} The ARIA attributes + */ +type GetAriaAttributesFn = ( + rowId: GridRowId, + index: number, +) => Record; + +export type GridRowInternalHook = () => GetAriaAttributesFn; From bc80a39e4016c2a13ddd74279ed804b94ebe19ee Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 11 Jul 2024 08:59:56 +0200 Subject: [PATCH 36/89] Add new prop to the return value of the skip filtering utility --- .../src/hooks/features/serverSideTreeData/utils.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts b/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts index e1314f6aef1d1..d69792ffb71d0 100644 --- a/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts +++ b/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts @@ -3,6 +3,7 @@ import { getTreeNodeDescendants } from '@mui/x-data-grid/internals'; export function skipFiltering(rowTree: GridRowTreeConfig) { const filteredRowsLookup: Record = {}; + const filteredChildrenCountLookup: Record = {}; const filteredDescendantCountLookup: Record = {}; const nodes = Object.values(rowTree); @@ -13,6 +14,7 @@ export function skipFiltering(rowTree: GridRowTreeConfig) { return { filteredRowsLookup, + filteredChildrenCountLookup, filteredDescendantCountLookup, }; } From 49ae70f702b1eeb5aee1271b8c08fa5e96701f90 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 11 Jul 2024 10:58:36 +0200 Subject: [PATCH 37/89] Change hasServerChildren to serverChildrenCount to be able to re-use count for the aria attributes --- .../useGridDataSourceTreeDataPreProcessors.tsx | 2 +- .../src/hooks/features/serverSideTreeData/utils.ts | 1 + packages/x-data-grid-pro/src/utils/tree/createRowTree.ts | 2 +- .../x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts | 8 ++++---- packages/x-data-grid-pro/src/utils/tree/models.ts | 2 +- packages/x-data-grid-pro/src/utils/tree/updateRowTree.ts | 8 ++++---- packages/x-data-grid/src/models/gridRows.ts | 4 ++-- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/useGridDataSourceTreeDataPreProcessors.tsx b/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/useGridDataSourceTreeDataPreProcessors.tsx index 6c182e6c04d12..c09bc45b8dedf 100644 --- a/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/useGridDataSourceTreeDataPreProcessors.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/useGridDataSourceTreeDataPreProcessors.tsx @@ -151,7 +151,7 @@ export const useGridDataSourceTreeDataPreProcessors = ( path: [...parentPath, getGroupKey(params.dataRowIdToModelLookup[rowId])].map( (key): RowTreeBuilderGroupingCriterion => ({ key, field: null }), ), - hasServerChildren: !!count && count !== 0, + serverChildrenCount: count, }; }; diff --git a/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts b/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts index d69792ffb71d0..4ac6fff64150e 100644 --- a/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts +++ b/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts @@ -10,6 +10,7 @@ export function skipFiltering(rowTree: GridRowTreeConfig) { for (let i = 0; i < nodes.length; i += 1) { const node: any = nodes[i]; filteredRowsLookup[node.id] = true; + filteredChildrenCountLookup[node.id] = node.serverChildrenCount; } return { diff --git a/packages/x-data-grid-pro/src/utils/tree/createRowTree.ts b/packages/x-data-grid-pro/src/utils/tree/createRowTree.ts index 6f79cc1c727c0..081f518c13c61 100644 --- a/packages/x-data-grid-pro/src/utils/tree/createRowTree.ts +++ b/packages/x-data-grid-pro/src/utils/tree/createRowTree.ts @@ -33,7 +33,7 @@ export const createRowTree = (params: CreateRowTreeParams): GridRowTreeCreationV previousTree: params.previousTree, id: node.id, path: node.path, - hasServerChildren: node.hasServerChildren, + serverChildrenCount: node.serverChildrenCount, onDuplicatePath: params.onDuplicatePath, treeDepths, isGroupExpandedByDefault: params.isGroupExpandedByDefault, diff --git a/packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts b/packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts index 86cd27e020261..d0efb73ffb33b 100644 --- a/packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts +++ b/packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts @@ -59,7 +59,7 @@ interface InsertDataRowInTreeParams { onDuplicatePath?: GridTreePathDuplicateHandler; isGroupExpandedByDefault?: DataGridProProps['isGroupExpandedByDefault']; defaultGroupingExpansionDepth: number; - hasServerChildren?: boolean; + serverChildrenCount: number; groupsToFetch?: Set; } @@ -79,7 +79,7 @@ export const insertDataRowInTree = ({ onDuplicatePath, isGroupExpandedByDefault, defaultGroupingExpansionDepth, - hasServerChildren, + serverChildrenCount, groupsToFetch, }: InsertDataRowInTreeParams) => { let parentNodeId = GRID_ROOT_GROUP_ID; @@ -99,7 +99,7 @@ export const insertDataRowInTree = ({ // We create a leaf node for the data row. if (existingNodeIdWithPartialPath == null) { let node: GridLeafNode | GridDataSourceGroupNode; - if (hasServerChildren) { + if (serverChildrenCount !== 0) { node = { type: 'group', id, @@ -112,7 +112,7 @@ export const insertDataRowInTree = ({ children: [], childrenFromPath: {}, childrenExpanded: false, - hasServerChildren: true, + serverChildrenCount, }; const shouldFetchChildren = checkGroupChildrenExpansion( node, diff --git a/packages/x-data-grid-pro/src/utils/tree/models.ts b/packages/x-data-grid-pro/src/utils/tree/models.ts index 871d3fc86c97f..e10bb7d7ba144 100644 --- a/packages/x-data-grid-pro/src/utils/tree/models.ts +++ b/packages/x-data-grid-pro/src/utils/tree/models.ts @@ -8,7 +8,7 @@ export interface RowTreeBuilderGroupingCriterion { export interface RowTreeBuilderNode { id: GridRowId; path: RowTreeBuilderGroupingCriterion[]; - hasServerChildren?: boolean; + serverChildrenCount: number; } /** diff --git a/packages/x-data-grid-pro/src/utils/tree/updateRowTree.ts b/packages/x-data-grid-pro/src/utils/tree/updateRowTree.ts index 0c7ddc5144033..e56ca16d74f68 100644 --- a/packages/x-data-grid-pro/src/utils/tree/updateRowTree.ts +++ b/packages/x-data-grid-pro/src/utils/tree/updateRowTree.ts @@ -36,7 +36,7 @@ export const updateRowTree = (params: UpdateRowTreeParams): GridRowTreeCreationV : new Set([]); for (let i = 0; i < params.nodes.inserted.length; i += 1) { - const { id, path, hasServerChildren } = params.nodes.inserted[i]; + const { id, path, serverChildrenCount } = params.nodes.inserted[i]; insertDataRowInTree({ previousTree: params.previousTree, @@ -45,7 +45,7 @@ export const updateRowTree = (params: UpdateRowTreeParams): GridRowTreeCreationV updatedGroupsManager, id, path, - hasServerChildren, + serverChildrenCount, onDuplicatePath: params.onDuplicatePath, isGroupExpandedByDefault: params.isGroupExpandedByDefault, defaultGroupingExpansionDepth: params.defaultGroupingExpansionDepth, @@ -65,7 +65,7 @@ export const updateRowTree = (params: UpdateRowTreeParams): GridRowTreeCreationV } for (let i = 0; i < params.nodes.modified.length; i += 1) { - const { id, path, hasServerChildren } = params.nodes.modified[i]; + const { id, path, serverChildrenCount } = params.nodes.modified[i]; const pathInPreviousTree = getNodePathInTree({ tree, id }); const isInSameGroup = isDeepEqual(pathInPreviousTree, path); @@ -84,7 +84,7 @@ export const updateRowTree = (params: UpdateRowTreeParams): GridRowTreeCreationV updatedGroupsManager, id, path, - hasServerChildren, + serverChildrenCount, onDuplicatePath: params.onDuplicatePath, isGroupExpandedByDefault: params.isGroupExpandedByDefault, defaultGroupingExpansionDepth: params.defaultGroupingExpansionDepth, diff --git a/packages/x-data-grid/src/models/gridRows.ts b/packages/x-data-grid/src/models/gridRows.ts index 703433dc873cc..3d876c45aeed0 100644 --- a/packages/x-data-grid/src/models/gridRows.ts +++ b/packages/x-data-grid/src/models/gridRows.ts @@ -116,9 +116,9 @@ export interface GridDataGroupNode extends GridBasicGroupNode { export interface GridDataSourceGroupNode extends GridDataGroupNode { /** - * If true, this node has children on server. + * Number of children this node has on the server. Returns `-1` if unknown. */ - hasServerChildren: boolean; + serverChildrenCount: number; /** * The cached path to be passed on as `groupKey` to the server. */ From 2bbfa54bf3644361e357ef46971dedf979449833 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 11 Jul 2024 11:20:00 +0200 Subject: [PATCH 38/89] Fix build --- .../src/hooks/features/serverSideTreeData/utils.ts | 3 ++- packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts | 2 +- packages/x-data-grid-pro/src/utils/tree/models.ts | 2 +- packages/x-data-grid/src/models/gridRows.ts | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts b/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts index 4ac6fff64150e..9ebc120ee6a68 100644 --- a/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts +++ b/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts @@ -10,7 +10,8 @@ export function skipFiltering(rowTree: GridRowTreeConfig) { for (let i = 0; i < nodes.length; i += 1) { const node: any = nodes[i]; filteredRowsLookup[node.id] = true; - filteredChildrenCountLookup[node.id] = node.serverChildrenCount; + filteredChildrenCountLookup[node.id] = + node.serverChildrenCount !== undefined ? node.serverChildrenCount : -1; } return { diff --git a/packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts b/packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts index d0efb73ffb33b..b9ebd6f739545 100644 --- a/packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts +++ b/packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts @@ -59,7 +59,7 @@ interface InsertDataRowInTreeParams { onDuplicatePath?: GridTreePathDuplicateHandler; isGroupExpandedByDefault?: DataGridProProps['isGroupExpandedByDefault']; defaultGroupingExpansionDepth: number; - serverChildrenCount: number; + serverChildrenCount?: number; groupsToFetch?: Set; } diff --git a/packages/x-data-grid-pro/src/utils/tree/models.ts b/packages/x-data-grid-pro/src/utils/tree/models.ts index e10bb7d7ba144..b9daf689647e8 100644 --- a/packages/x-data-grid-pro/src/utils/tree/models.ts +++ b/packages/x-data-grid-pro/src/utils/tree/models.ts @@ -8,7 +8,7 @@ export interface RowTreeBuilderGroupingCriterion { export interface RowTreeBuilderNode { id: GridRowId; path: RowTreeBuilderGroupingCriterion[]; - serverChildrenCount: number; + serverChildrenCount?: number; } /** diff --git a/packages/x-data-grid/src/models/gridRows.ts b/packages/x-data-grid/src/models/gridRows.ts index 3d876c45aeed0..c9dc3c2c41212 100644 --- a/packages/x-data-grid/src/models/gridRows.ts +++ b/packages/x-data-grid/src/models/gridRows.ts @@ -118,7 +118,7 @@ export interface GridDataSourceGroupNode extends GridDataGroupNode { /** * Number of children this node has on the server. Returns `-1` if unknown. */ - serverChildrenCount: number; + serverChildrenCount?: number; /** * The cached path to be passed on as `groupKey` to the server. */ From c44f000f852a98b6100c8f3b3c3f967a2425bef0 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 11 Jul 2024 20:43:08 +0200 Subject: [PATCH 39/89] group row should not be made if serverChildrenCount is undefined --- packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts b/packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts index b9ebd6f739545..d006eb177b34e 100644 --- a/packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts +++ b/packages/x-data-grid-pro/src/utils/tree/insertDataRowInTree.ts @@ -99,7 +99,7 @@ export const insertDataRowInTree = ({ // We create a leaf node for the data row. if (existingNodeIdWithPartialPath == null) { let node: GridLeafNode | GridDataSourceGroupNode; - if (serverChildrenCount !== 0) { + if (serverChildrenCount !== undefined && serverChildrenCount !== 0) { node = { type: 'group', id, From 6289ff28420fd8145f4af441a8d71c5362a190ab Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Thu, 11 Jul 2024 21:15:16 +0200 Subject: [PATCH 40/89] Expand the filteredChildrenCountLookup description --- .../x-data-grid/src/hooks/features/filter/gridFilterState.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/x-data-grid/src/hooks/features/filter/gridFilterState.ts b/packages/x-data-grid/src/hooks/features/filter/gridFilterState.ts index df84b7bf4aa37..3e5aa75d6cbc6 100644 --- a/packages/x-data-grid/src/hooks/features/filter/gridFilterState.ts +++ b/packages/x-data-grid/src/hooks/features/filter/gridFilterState.ts @@ -24,6 +24,7 @@ export interface GridFilterState { /** * Amount of children that are passing the filters or have children that are passing the filter (does not count grand children). * If a row is not registered in this lookup, it is supposed to have no descendant passing the filters. + * If `GridDataSource` is being used to load the data, the value is `-1` if the children count is unknown. */ filteredChildrenCountLookup: Record; /** From 943ddcead563badbe1a00e2b2de17f0ab462b086 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Mon, 15 Jul 2024 12:08:17 +0200 Subject: [PATCH 41/89] treegird role is set if row grouping is in place --- .../x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx b/packages/x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx index 07a2fc81f1650..ad36d4d69227c 100644 --- a/packages/x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx +++ b/packages/x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx @@ -16,7 +16,11 @@ export const useGridAriaAttributes = () => { const pinnedRowsCount = useGridSelector(apiRef, gridPinnedRowsCountSelector); let role = 'grid'; - if ((rootProps as any).treeData) { + if ( + (rootProps as any).treeData || + (rootProps as any).rowGroupingModel || + (rootProps as any).initialState?.rowGrouping + ) { role = 'treegrid'; } From 752d575caffe00c6a49e7ed8703b6bea55341afe Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Mon, 15 Jul 2024 12:08:59 +0200 Subject: [PATCH 42/89] Add additional aria attributes to the rows in a grid that has row grouping enabled --- .../src/DataGridPremium/DataGridPremium.tsx | 2 +- .../src/hooks/features/rows/index.tsx | 1 + .../hooks/features/rows/useGridRowAriaAttributes.tsx | 12 ++++++++++++ .../hooks/features/rows/useGridRowAriaAttributes.tsx | 9 ++++++--- 4 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 packages/x-data-grid-premium/src/hooks/features/rows/index.tsx create mode 100644 packages/x-data-grid-premium/src/hooks/features/rows/useGridRowAriaAttributes.tsx diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index 251934e31cfcb..1f6ecc17f6e3f 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -15,7 +15,6 @@ import { propValidatorsDataGridPro, PropValidator, validateProps, - useGridRowAriaAttributes, } from '@mui/x-data-grid-pro/internals'; import { useDataGridPremiumComponent } from './useDataGridPremiumComponent'; import { @@ -24,6 +23,7 @@ import { } from '../models/dataGridPremiumProps'; import { useDataGridPremiumProps } from './useDataGridPremiumProps'; import { getReleaseInfo } from '../utils/releaseInfo'; +import { useGridRowAriaAttributes } from '../hooks/features/rows/useGridRowAriaAttributes'; export type { GridPremiumSlotsComponent as GridSlots } from '../models'; diff --git a/packages/x-data-grid-premium/src/hooks/features/rows/index.tsx b/packages/x-data-grid-premium/src/hooks/features/rows/index.tsx new file mode 100644 index 0000000000000..bf3c51abb3373 --- /dev/null +++ b/packages/x-data-grid-premium/src/hooks/features/rows/index.tsx @@ -0,0 +1 @@ +export * from './useGridRowAriaAttributes'; diff --git a/packages/x-data-grid-premium/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid-premium/src/hooks/features/rows/useGridRowAriaAttributes.tsx new file mode 100644 index 0000000000000..20b8916a4e59e --- /dev/null +++ b/packages/x-data-grid-premium/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -0,0 +1,12 @@ +import { + useGridRowAriaAttributes as useGridRowAriaAttributesPro, + useGridSelector, +} from '@mui/x-data-grid-pro/internals'; +import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext'; +import { gridRowGroupingModelSelector } from '../rowGrouping/gridRowGroupingSelector'; + +export const useGridRowAriaAttributes = () => { + const apiRef = useGridPrivateApiContext(); + const gridRowGroupingModel = useGridSelector(apiRef, gridRowGroupingModelSelector); + return useGridRowAriaAttributesPro(gridRowGroupingModel.length > 0); +}; diff --git a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx index 2af0b9c54aaa8..96a83ad9bf92b 100644 --- a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -11,7 +11,7 @@ import { useGridRowAriaAttributes as useGridRowAriaAttributesCommunity } from '@ import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext'; import { useGridRootProps } from '../../utils/useGridRootProps'; -export const useGridRowAriaAttributes = () => { +export const useGridRowAriaAttributes = (addTreeDataAttributes?: boolean) => { const apiRef = useGridPrivateApiContext(); const props = useGridRootProps(); const getRowAriaAttributesCommunity = useGridRowAriaAttributesCommunity(); @@ -26,12 +26,15 @@ export const useGridRowAriaAttributes = () => { gridExpandedSortedRowIdsLookupSelector, ); + const addAttributes = + addTreeDataAttributes !== undefined ? addTreeDataAttributes : props.treeData === true; + return React.useCallback( (rowId: GridRowId, index: number) => { const rowNode = apiRef.current.getRowNode(rowId); const ariaAttributes = getRowAriaAttributesCommunity(rowId, index); - if (rowNode === null || props.treeData !== true) { + if (!addAttributes || rowNode === null) { return ariaAttributes; } @@ -56,7 +59,7 @@ export const useGridRowAriaAttributes = () => { }, [ apiRef, - props.treeData, + addAttributes, filteredTopLevelRowCount, filteredChildrenCountLookup, sortedVisibleRowPositionsLookup, From 8a3fe598ff273888e72edb7b7d68bd887b0bd54d Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Mon, 15 Jul 2024 12:09:18 +0200 Subject: [PATCH 43/89] Add accessibility test to the row grouping feature --- .../rowGrouping.DataGridPremium.test.tsx | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/x-data-grid-premium/src/tests/rowGrouping.DataGridPremium.test.tsx b/packages/x-data-grid-premium/src/tests/rowGrouping.DataGridPremium.test.tsx index 6ca61d73bbcc4..994100b91b893 100644 --- a/packages/x-data-grid-premium/src/tests/rowGrouping.DataGridPremium.test.tsx +++ b/packages/x-data-grid-premium/src/tests/rowGrouping.DataGridPremium.test.tsx @@ -14,6 +14,7 @@ import { getColumnValues, getCell, getSelectByName, + getRow, } from 'test/utils/helperFn'; import { expect } from 'chai'; import { @@ -2762,6 +2763,27 @@ describe(' - Row grouping', () => { }); }); + describe('accessibility', () => { + it('should add necessary treegrid aria attributes to the rows', () => { + render( + , + ); + + expect(getRow(0).getAttribute('aria-level')).to.equal('1'); // Cat A + expect(getRow(1).getAttribute('aria-level')).to.equal('2'); // Cat 1 + expect(getRow(1).getAttribute('aria-posinset')).to.equal('1'); + expect(getRow(1).getAttribute('aria-setsize')).to.equal('2'); // Cat A has Cat 1 & Cat 2 + expect(getRow(2).getAttribute('aria-level')).to.equal('3'); // Cat 1 row + expect(getRow(3).getAttribute('aria-posinset')).to.equal('2'); // Cat 2 + expect(getRow(4).getAttribute('aria-posinset')).to.equal('1'); // Cat 2 row + expect(getRow(4).getAttribute('aria-setsize')).to.equal('2'); // Cat 2 has 2 rows + }); + }); + // See https://github.com/mui/mui-x/issues/8626 it('should properly update the rows when they change', async () => { render( From 587ec30289a4ac3f1f7c91b7b3a68f7f10142ea9 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Fri, 19 Jul 2024 09:49:56 +0200 Subject: [PATCH 44/89] Util cleanup --- .../src/hooks/features/serverSideTreeData/utils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts b/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts index 9ebc120ee6a68..4c725628cb86f 100644 --- a/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts +++ b/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts @@ -10,8 +10,7 @@ export function skipFiltering(rowTree: GridRowTreeConfig) { for (let i = 0; i < nodes.length; i += 1) { const node: any = nodes[i]; filteredRowsLookup[node.id] = true; - filteredChildrenCountLookup[node.id] = - node.serverChildrenCount !== undefined ? node.serverChildrenCount : -1; + filteredChildrenCountLookup[node.id] = node.serverChildrenCount ?? -1; } return { From aaf0f2e26e6016f1d6ba8fa8324c2f9e10f82d66 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Fri, 19 Jul 2024 10:39:54 +0200 Subject: [PATCH 45/89] Pass row node instead of id to the aria attributes hook --- .../features/rows/useGridRowAriaAttributes.tsx | 8 +++----- packages/x-data-grid/src/components/GridRow.tsx | 2 +- .../features/rows/useGridRowAriaAttributes.tsx | 13 ++++--------- .../models/configuration/gridRowConfiguration.ts | 6 +++--- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx index 96a83ad9bf92b..726584bd9e033 100644 --- a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { - GridRowId, + GridTreeNode, useGridSelector, gridFilteredTopLevelRowCountSelector, gridFilteredChildrenCountLookupSelector, @@ -30,9 +30,8 @@ export const useGridRowAriaAttributes = (addTreeDataAttributes?: boolean) => { addTreeDataAttributes !== undefined ? addTreeDataAttributes : props.treeData === true; return React.useCallback( - (rowId: GridRowId, index: number) => { - const rowNode = apiRef.current.getRowNode(rowId); - const ariaAttributes = getRowAriaAttributesCommunity(rowId, index); + (rowNode: GridTreeNode, index: number) => { + const ariaAttributes = getRowAriaAttributesCommunity(rowNode, index); if (!addAttributes || rowNode === null) { return ariaAttributes; @@ -58,7 +57,6 @@ export const useGridRowAriaAttributes = (addTreeDataAttributes?: boolean) => { return ariaAttributes; }, [ - apiRef, addAttributes, filteredTopLevelRowCount, filteredChildrenCountLookup, diff --git a/packages/x-data-grid/src/components/GridRow.tsx b/packages/x-data-grid/src/components/GridRow.tsx index 02e29543cfa39..3340b92ae0e46 100644 --- a/packages/x-data-grid/src/components/GridRow.tsx +++ b/packages/x-data-grid/src/components/GridRow.tsx @@ -306,7 +306,7 @@ const GridRow = React.forwardRef(function GridRow( }, [isNotVisible, rowHeight, styleProp, minHeight, sizes, rootProps.rowSpacingType]); const rowClassNames = apiRef.current.unstable_applyPipeProcessors('rowClassName', [], rowId); - const ariaAttributes = getRowAriaAttributes(rowId, index); + const ariaAttributes = rowNode ? getRowAriaAttributes(rowNode, index) : {}; if (typeof rootProps.getRowClassName === 'function') { const indexRelativeToCurrentPage = index - (currentPage.range?.firstRowIndex || 0); diff --git a/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx index b8732116cb911..4409697de7941 100644 --- a/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { GridRowId } from '../../../models/gridRows'; +import { GridTreeNode } from '../../../models/gridRows'; import { GridRowInternalHook } from '../../../models/configuration/gridRowConfiguration'; import { selectedIdsLookupSelector } from '../rowSelection'; import { useGridSelector } from '../../utils/useGridSelector'; @@ -12,23 +12,18 @@ export const useGridRowAriaAttributes: GridRowInternalHook = () => { const headerGroupingMaxDepth = useGridSelector(apiRef, gridColumnGroupsHeaderMaxDepthSelector); return React.useCallback( - (rowId: GridRowId, index: number) => { - const rowNode = apiRef.current.getRowNode(rowId); + (rowNode: GridTreeNode, index: number) => { const ariaAttributes = {} as Record; - if (rowNode === null) { - return ariaAttributes; - } - const ariaRowIndex = index + headerGroupingMaxDepth + 2; // 1 for the header row and 1 as it's 1-based ariaAttributes['aria-rowindex'] = ariaRowIndex; - if (selectedIdsLookup[rowId]) { + if (selectedIdsLookup[rowNode.id]) { ariaAttributes['aria-selected'] = true; } return ariaAttributes; }, - [apiRef, selectedIdsLookup, headerGroupingMaxDepth], + [selectedIdsLookup, headerGroupingMaxDepth], ); }; diff --git a/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts b/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts index ea5f3d68e6ba0..cc0a74d1caa62 100644 --- a/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts +++ b/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts @@ -1,13 +1,13 @@ -import { GridRowId } from '../gridRows'; +import { GridTreeNode } from '../gridRows'; /** * Get the ARIA attributes for a row - * @param {GridRowId} rowId The id of the row + * @param {GridTreeNode} rowNode The row node * @param {number} index The position index of the row * @returns {Record} The ARIA attributes */ type GetAriaAttributesFn = ( - rowId: GridRowId, + rowNode: GridTreeNode, index: number, ) => Record; From 6aae705ebc0585a732dd93f21c72928a8f809cbb Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Fri, 19 Jul 2024 12:23:30 +0200 Subject: [PATCH 46/89] Fallback to 0 if node does not have serverChildrenCount --- .../src/hooks/features/serverSideTreeData/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts b/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts index 4c725628cb86f..677f7210c9274 100644 --- a/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts +++ b/packages/x-data-grid-pro/src/hooks/features/serverSideTreeData/utils.ts @@ -10,7 +10,7 @@ export function skipFiltering(rowTree: GridRowTreeConfig) { for (let i = 0; i < nodes.length; i += 1) { const node: any = nodes[i]; filteredRowsLookup[node.id] = true; - filteredChildrenCountLookup[node.id] = node.serverChildrenCount ?? -1; + filteredChildrenCountLookup[node.id] = node.serverChildrenCount ?? 0; } return { From 3c9c0aebc9ded26117b5bde2a6e27636289853c6 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Fri, 19 Jul 2024 12:38:50 +0200 Subject: [PATCH 47/89] Fix server row count models and update their descriptions --- packages/x-data-grid/src/models/gridDataSource.ts | 3 ++- packages/x-data-grid/src/models/gridRows.ts | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/x-data-grid/src/models/gridDataSource.ts b/packages/x-data-grid/src/models/gridDataSource.ts index 58038fe0e2905..f2a26241b659f 100644 --- a/packages/x-data-grid/src/models/gridDataSource.ts +++ b/packages/x-data-grid/src/models/gridDataSource.ts @@ -72,7 +72,8 @@ export interface GridDataSource { /** * Used to determine the number of children a row has on server. * @param {GridRowModel} row The row to check the number of children - * @returns {number} The number of children the row has + * @returns {number} The number of children the row has. + * If the children count is not available for some reason, but there are some children, `getChildrenCount` should return `-1`. */ getChildrenCount?: (row: GridRowModel) => number; } diff --git a/packages/x-data-grid/src/models/gridRows.ts b/packages/x-data-grid/src/models/gridRows.ts index c9dc3c2c41212..62ff055ccff61 100644 --- a/packages/x-data-grid/src/models/gridRows.ts +++ b/packages/x-data-grid/src/models/gridRows.ts @@ -116,9 +116,9 @@ export interface GridDataGroupNode extends GridBasicGroupNode { export interface GridDataSourceGroupNode extends GridDataGroupNode { /** - * Number of children this node has on the server. Returns `-1` if unknown. + * Number of children this node has on the server. Returns `-1` if there are some children but the count is unknown. */ - serverChildrenCount?: number; + serverChildrenCount: number; /** * The cached path to be passed on as `groupKey` to the server. */ From 835182825ca98e91ecb1118a811cb6813d13990a Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Fri, 19 Jul 2024 12:50:24 +0200 Subject: [PATCH 48/89] Extend tests --- .../src/tests/treeData.DataGridPro.test.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx index 10cdbc982259b..1b635f67898a5 100644 --- a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx @@ -625,6 +625,13 @@ describe(' - Tree data', () => { expect(filteredChildrenCountLookup.C).to.equal(undefined); expect(filteredDescendantCountLookup.C).to.equal(undefined); + + act(() => { + apiRef.current.updateRows([{ name: 'A.D' }]); + }); + + expect(apiRef.current.state.filter.filteredChildrenCountLookup.A).to.equal(4); + expect(apiRef.current.state.filter.filteredDescendantCountLookup.A).to.equal(6); }); }); From b38642f03a47c7ae28745a70d94e1e69546a6e48 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Fri, 19 Jul 2024 12:57:16 +0200 Subject: [PATCH 49/89] Update filter state model description for the child count --- .../x-data-grid/src/hooks/features/filter/gridFilterState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-data-grid/src/hooks/features/filter/gridFilterState.ts b/packages/x-data-grid/src/hooks/features/filter/gridFilterState.ts index 3e5aa75d6cbc6..c48354461cf09 100644 --- a/packages/x-data-grid/src/hooks/features/filter/gridFilterState.ts +++ b/packages/x-data-grid/src/hooks/features/filter/gridFilterState.ts @@ -24,7 +24,7 @@ export interface GridFilterState { /** * Amount of children that are passing the filters or have children that are passing the filter (does not count grand children). * If a row is not registered in this lookup, it is supposed to have no descendant passing the filters. - * If `GridDataSource` is being used to load the data, the value is `-1` if the children count is unknown. + * If `GridDataSource` is being used to load the data, the value is `-1` if there are some children but the count is unknown. */ filteredChildrenCountLookup: Record; /** From c80b879caae69dd3e606fe3e367329ebea1a95cd Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Fri, 19 Jul 2024 12:58:02 +0200 Subject: [PATCH 50/89] Update selector name to better reflect its purpose. Make it private and update docs --- docs/pages/x/api/data-grid/selectors.json | 7 ------- .../src/hooks/features/rows/useGridRowAriaAttributes.tsx | 4 ++-- .../src/hooks/features/filter/gridFilterSelector.ts | 5 +++-- scripts/x-data-grid-premium.exports.json | 2 +- scripts/x-data-grid-pro.exports.json | 2 +- scripts/x-data-grid.exports.json | 2 +- 6 files changed, 8 insertions(+), 14 deletions(-) diff --git a/docs/pages/x/api/data-grid/selectors.json b/docs/pages/x/api/data-grid/selectors.json index 91cb066f94835..092a70faf2623 100644 --- a/docs/pages/x/api/data-grid/selectors.json +++ b/docs/pages/x/api/data-grid/selectors.json @@ -172,13 +172,6 @@ "description": "Get the id and the model of the rows accessible after the filtering process.\nDoes not contain the collapsed children.", "supportsApiRef": true }, - { - "name": "gridExpandedSortedRowIdsLookupSelector", - "returnType": "Record", - "category": "Filtering", - "description": "Get the row ids accessible after the filtering process to position in the current tree level lookup.\nDoes not contain the collapsed children.", - "supportsApiRef": true - }, { "name": "gridExpandedSortedRowIdsSelector", "returnType": "GridRowId[]", diff --git a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx index 726584bd9e033..beab496173c5c 100644 --- a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -4,7 +4,7 @@ import { useGridSelector, gridFilteredTopLevelRowCountSelector, gridFilteredChildrenCountLookupSelector, - gridExpandedSortedRowIdsLookupSelector, + gridExpandedSortedRowTreeLevelPositionLookupSelector, GRID_ROOT_GROUP_ID, } from '@mui/x-data-grid'; import { useGridRowAriaAttributes as useGridRowAriaAttributesCommunity } from '@mui/x-data-grid/internals'; @@ -23,7 +23,7 @@ export const useGridRowAriaAttributes = (addTreeDataAttributes?: boolean) => { ); const sortedVisibleRowPositionsLookup = useGridSelector( apiRef, - gridExpandedSortedRowIdsLookupSelector, + gridExpandedSortedRowTreeLevelPositionLookupSelector, ); const addAttributes = diff --git a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts index ae24023bba400..f9733a04f577c 100644 --- a/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts +++ b/packages/x-data-grid/src/hooks/features/filter/gridFilterSelector.ts @@ -107,11 +107,12 @@ export const gridFilteredSortedRowIdsSelector = createSelectorMemoized( ); /** - * Get the row ids accessible after the filtering process to position in the current tree level lookup. + * Get the ids to position in the current tree level lookup of the rows accessible after the filtering process. * Does not contain the collapsed children. * @category Filtering + * @ignore - do not document. */ -export const gridExpandedSortedRowIdsLookupSelector = createSelectorMemoized( +export const gridExpandedSortedRowTreeLevelPositionLookupSelector = createSelectorMemoized( gridExpandedSortedRowIdsSelector, gridRowTreeSelector, (visibleSortedRowIds, rowTree) => { diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index 059b14d6afb9c..1ef666b653615 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -305,8 +305,8 @@ { "name": "GridExceljsProcessInput", "kind": "Interface" }, { "name": "gridExpandedRowCountSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowEntriesSelector", "kind": "Variable" }, - { "name": "gridExpandedSortedRowIdsLookupSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowIdsSelector", "kind": "Variable" }, + { "name": "gridExpandedSortedRowTreeLevelPositionLookupSelector", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExperimentalPremiumFeatures", "kind": "Interface" }, { "name": "GridExportDisplayOptions", "kind": "Interface" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index a546beb3c5743..ab9c2c223c934 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -274,8 +274,8 @@ { "name": "GridEvents", "kind": "TypeAlias" }, { "name": "gridExpandedRowCountSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowEntriesSelector", "kind": "Variable" }, - { "name": "gridExpandedSortedRowIdsLookupSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowIdsSelector", "kind": "Variable" }, + { "name": "gridExpandedSortedRowTreeLevelPositionLookupSelector", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExperimentalProFeatures", "kind": "Interface" }, { "name": "GridExportDisplayOptions", "kind": "Interface" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index e33a3ed27a0ad..a72fa7faa785e 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -245,8 +245,8 @@ { "name": "GridEvents", "kind": "TypeAlias" }, { "name": "gridExpandedRowCountSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowEntriesSelector", "kind": "Variable" }, - { "name": "gridExpandedSortedRowIdsLookupSelector", "kind": "Variable" }, { "name": "gridExpandedSortedRowIdsSelector", "kind": "Variable" }, + { "name": "gridExpandedSortedRowTreeLevelPositionLookupSelector", "kind": "Variable" }, { "name": "GridExpandMoreIcon", "kind": "Variable" }, { "name": "GridExperimentalFeatures", "kind": "Interface" }, { "name": "GridExportDisplayOptions", "kind": "Interface" }, From 53f342ca1c642d2dce8384c104ef50f4d54be4ce Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Fri, 19 Jul 2024 13:01:56 +0200 Subject: [PATCH 51/89] Use sanitized grouping model selector --- .../src/hooks/features/rows/useGridRowAriaAttributes.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/x-data-grid-premium/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid-premium/src/hooks/features/rows/useGridRowAriaAttributes.tsx index 20b8916a4e59e..f844554f633ba 100644 --- a/packages/x-data-grid-premium/src/hooks/features/rows/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid-premium/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -3,10 +3,10 @@ import { useGridSelector, } from '@mui/x-data-grid-pro/internals'; import { useGridPrivateApiContext } from '../../utils/useGridPrivateApiContext'; -import { gridRowGroupingModelSelector } from '../rowGrouping/gridRowGroupingSelector'; +import { gridRowGroupingSanitizedModelSelector } from '../rowGrouping/gridRowGroupingSelector'; export const useGridRowAriaAttributes = () => { const apiRef = useGridPrivateApiContext(); - const gridRowGroupingModel = useGridSelector(apiRef, gridRowGroupingModelSelector); + const gridRowGroupingModel = useGridSelector(apiRef, gridRowGroupingSanitizedModelSelector); return useGridRowAriaAttributesPro(gridRowGroupingModel.length > 0); }; From 5f348d2bd20ecd8b65b28711cd00527190a31a56 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Fri, 19 Jul 2024 22:23:07 +0200 Subject: [PATCH 52/89] Use grid configuration to apply different values to the grid aria attributes --- .../src/DataGridPremium/DataGridPremium.tsx | 8 +++++++- .../src/hooks/utils/useGridAriaAttributes.tsx | 20 +++++++++++++++++++ .../src/DataGridPro/DataGridPro.tsx | 8 +++++++- .../src/hooks/utils/useGridAriaAttributes.tsx | 15 ++++++++++++++ .../x-data-grid-pro/src/internals/index.ts | 2 ++ .../x-data-grid/src/DataGrid/DataGrid.tsx | 8 +++++++- .../virtualization/GridMainContainer.tsx | 5 +++-- .../rows/useGridRowAriaAttributes.tsx | 4 ++-- .../src/hooks/utils/useGridAriaAttributes.tsx | 14 +++---------- packages/x-data-grid/src/internals/index.ts | 1 + .../models/configuration/gridConfiguration.ts | 14 ++++++++++--- .../configuration/gridRowConfiguration.ts | 11 ++++++---- 12 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 packages/x-data-grid-premium/src/hooks/utils/useGridAriaAttributes.tsx create mode 100644 packages/x-data-grid-pro/src/hooks/utils/useGridAriaAttributes.tsx diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index 1f6ecc17f6e3f..cb597ca51e9b1 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -23,11 +23,17 @@ import { } from '../models/dataGridPremiumProps'; import { useDataGridPremiumProps } from './useDataGridPremiumProps'; import { getReleaseInfo } from '../utils/releaseInfo'; +import { useGridAriaAttributes } from '../hooks/utils/useGridAriaAttributes'; import { useGridRowAriaAttributes } from '../hooks/features/rows/useGridRowAriaAttributes'; export type { GridPremiumSlotsComponent as GridSlots } from '../models'; -const configuration = { hooks: { useGridRowAriaAttributes } }; +const configuration = { + hooks: { + useGridAriaAttributes, + useGridRowAriaAttributes, + }, +}; const releaseInfo = getReleaseInfo(); let dataGridPremiumPropValidators: PropValidator[]; diff --git a/packages/x-data-grid-premium/src/hooks/utils/useGridAriaAttributes.tsx b/packages/x-data-grid-premium/src/hooks/utils/useGridAriaAttributes.tsx new file mode 100644 index 0000000000000..b3ce053badff3 --- /dev/null +++ b/packages/x-data-grid-premium/src/hooks/utils/useGridAriaAttributes.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +import { + useGridAriaAttributes as useGridAriaAttributesPro, + useGridSelector, +} from '@mui/x-data-grid-pro/internals'; +import { useGridPrivateApiContext } from './useGridPrivateApiContext'; +import { gridRowGroupingSanitizedModelSelector } from '../features/rowGrouping/gridRowGroupingSelector'; + +export const useGridAriaAttributes = (): React.HTMLAttributes => { + const ariaAttributesPro = useGridAriaAttributesPro(); + const apiRef = useGridPrivateApiContext(); + const gridRowGroupingModel = useGridSelector(apiRef, gridRowGroupingSanitizedModelSelector); + + const ariaAttributesPremium = gridRowGroupingModel.length > 0 ? { role: 'treegrid' } : {}; + + return { + ...ariaAttributesPro, + ...ariaAttributesPremium, + }; +}; diff --git a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index f287943197f0b..2bfd177cb80e0 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -16,11 +16,17 @@ import { DataGridProProps } from '../models/dataGridProProps'; import { useDataGridProProps } from './useDataGridProProps'; import { getReleaseInfo } from '../utils/releaseInfo'; import { propValidatorsDataGridPro } from '../internals/propValidation'; +import { useGridAriaAttributes } from '../hooks/utils/useGridAriaAttributes'; import { useGridRowAriaAttributes } from '../hooks/features/rows/useGridRowAriaAttributes'; export type { GridProSlotsComponent as GridSlots } from '../models'; -const configuration = { hooks: { useGridRowAriaAttributes } }; +const configuration = { + hooks: { + useGridAriaAttributes, + useGridRowAriaAttributes, + }, +}; const releaseInfo = getReleaseInfo(); const DataGridProRaw = React.forwardRef(function DataGridPro( diff --git a/packages/x-data-grid-pro/src/hooks/utils/useGridAriaAttributes.tsx b/packages/x-data-grid-pro/src/hooks/utils/useGridAriaAttributes.tsx new file mode 100644 index 0000000000000..1f5507728d8bd --- /dev/null +++ b/packages/x-data-grid-pro/src/hooks/utils/useGridAriaAttributes.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; +import { useGridAriaAttributes as useGridAriaAttributesCommunity } from '@mui/x-data-grid/internals'; +import { useGridRootProps } from './useGridRootProps'; + +export const useGridAriaAttributes = (): React.HTMLAttributes => { + const ariaAttributesCommunity = useGridAriaAttributesCommunity(); + const rootProps = useGridRootProps(); + + const ariaAttributesPro = rootProps.treeData ? { role: 'treegrid' } : {}; + + return { + ...ariaAttributesCommunity, + ...ariaAttributesPro, + }; +}; diff --git a/packages/x-data-grid-pro/src/internals/index.ts b/packages/x-data-grid-pro/src/internals/index.ts index 7b88761c0b3c2..e4c265212f5d6 100644 --- a/packages/x-data-grid-pro/src/internals/index.ts +++ b/packages/x-data-grid-pro/src/internals/index.ts @@ -23,6 +23,8 @@ export { export { useGridDetailPanelPreProcessors } from '../hooks/features/detailPanel/useGridDetailPanelPreProcessors'; export { useGridInfiniteLoader } from '../hooks/features/infiniteLoader/useGridInfiniteLoader'; +// eslint-disable-next-line import/export +export { useGridAriaAttributes } from '../hooks/utils/useGridAriaAttributes'; // eslint-disable-next-line import/export export { useGridRowAriaAttributes } from '../hooks/features/rows/useGridRowAriaAttributes'; export { useGridRowReorder } from '../hooks/features/rowReorder/useGridRowReorder'; diff --git a/packages/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/x-data-grid/src/DataGrid/DataGrid.tsx index 8dc82c0105302..a5faebe380546 100644 --- a/packages/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/x-data-grid/src/DataGrid/DataGrid.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { GridBody, GridFooterPlaceholder, GridHeader, GridRoot } from '../components'; +import { useGridAriaAttributes } from '../hooks/utils/useGridAriaAttributes'; import { useGridRowAriaAttributes } from '../hooks/features/rows/useGridRowAriaAttributes'; import { DataGridProcessedProps, DataGridProps } from '../models/props/DataGridProps'; import { GridContextProvider } from '../context/GridContextProvider'; @@ -16,7 +17,12 @@ import { export type { GridSlotsComponent as GridSlots } from '../models'; -const configuration = { hooks: { useGridRowAriaAttributes } }; +const configuration = { + hooks: { + useGridAriaAttributes, + useGridRowAriaAttributes, + }, +}; let propValidators: PropValidator[]; if (process.env.NODE_ENV !== 'production') { diff --git a/packages/x-data-grid/src/components/virtualization/GridMainContainer.tsx b/packages/x-data-grid/src/components/virtualization/GridMainContainer.tsx index 5a0d3668d12f2..8fcbd0a4109ee 100644 --- a/packages/x-data-grid/src/components/virtualization/GridMainContainer.tsx +++ b/packages/x-data-grid/src/components/virtualization/GridMainContainer.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { styled } from '@mui/system'; import { DataGridProcessedProps } from '../../models/props/DataGridProps'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; -import { useGridAriaAttributes } from '../../hooks/utils/useGridAriaAttributes'; +import { useGridConfiguration } from '../../hooks/utils/useGridConfiguration'; const GridPanelAnchor = styled('div')({ position: 'absolute', @@ -28,8 +28,9 @@ export const GridMainContainer = React.forwardRef< className: string; }> >((props, ref) => { - const ariaAttributes = useGridAriaAttributes(); const rootProps = useGridRootProps(); + const configuration = useGridConfiguration(); + const ariaAttributes = configuration.hooks.useGridAriaAttributes(); return ( { +export const useGridRowAriaAttributes = (): GetRowAriaAttributesFn => { const apiRef = useGridPrivateApiContext(); const selectedIdsLookup = useGridSelector(apiRef, selectedIdsLookupSelector); const headerGroupingMaxDepth = useGridSelector(apiRef, gridColumnGroupsHeaderMaxDepthSelector); diff --git a/packages/x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx b/packages/x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx index ad36d4d69227c..abfee1ab87465 100644 --- a/packages/x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx +++ b/packages/x-data-grid/src/hooks/utils/useGridAriaAttributes.tsx @@ -1,3 +1,4 @@ +import * as React from 'react'; import { gridVisibleColumnDefinitionsSelector } from '../features/columns/gridColumnsSelector'; import { useGridSelector } from './useGridSelector'; import { useGridRootProps } from './useGridRootProps'; @@ -7,7 +8,7 @@ import { useGridPrivateApiContext } from './useGridPrivateApiContext'; import { isMultipleRowSelectionEnabled } from '../features/rowSelection/utils'; import { gridExpandedRowCountSelector } from '../features/filter/gridFilterSelector'; -export const useGridAriaAttributes = () => { +export const useGridAriaAttributes = (): React.HTMLAttributes => { const apiRef = useGridPrivateApiContext(); const rootProps = useGridRootProps(); const visibleColumns = useGridSelector(apiRef, gridVisibleColumnDefinitionsSelector); @@ -15,17 +16,8 @@ export const useGridAriaAttributes = () => { const headerGroupingMaxDepth = useGridSelector(apiRef, gridColumnGroupsHeaderMaxDepthSelector); const pinnedRowsCount = useGridSelector(apiRef, gridPinnedRowsCountSelector); - let role = 'grid'; - if ( - (rootProps as any).treeData || - (rootProps as any).rowGroupingModel || - (rootProps as any).initialState?.rowGrouping - ) { - role = 'treegrid'; - } - return { - role, + role: 'grid', 'aria-colcount': visibleColumns.length, 'aria-rowcount': headerGroupingMaxDepth + 1 + pinnedRowsCount + accessibleRowCount, 'aria-multiselectable': isMultipleRowSelectionEnabled(rootProps), diff --git a/packages/x-data-grid/src/internals/index.ts b/packages/x-data-grid/src/internals/index.ts index 051c7a54af04f..644fde6328aad 100644 --- a/packages/x-data-grid/src/internals/index.ts +++ b/packages/x-data-grid/src/internals/index.ts @@ -74,6 +74,7 @@ export { export { useGridEditing, editingStateInitializer } from '../hooks/features/editing/useGridEditing'; export { gridEditRowsStateSelector } from '../hooks/features/editing/gridEditingSelectors'; export { useGridRows, rowsStateInitializer } from '../hooks/features/rows/useGridRows'; +export { useGridAriaAttributes } from '../hooks/utils/useGridAriaAttributes'; export { useGridRowAriaAttributes } from '../hooks/features/rows/useGridRowAriaAttributes'; export { useGridRowsPreProcessors } from '../hooks/features/rows/useGridRowsPreProcessors'; export type { diff --git a/packages/x-data-grid/src/models/configuration/gridConfiguration.ts b/packages/x-data-grid/src/models/configuration/gridConfiguration.ts index c73bce3ec0065..d4a7d7b2c4f05 100644 --- a/packages/x-data-grid/src/models/configuration/gridConfiguration.ts +++ b/packages/x-data-grid/src/models/configuration/gridConfiguration.ts @@ -1,6 +1,14 @@ -import { GridRowInternalHook } from './gridRowConfiguration'; +import * as React from 'react'; +import { GridRowAriaAttributesInternalHook } from './gridRowConfiguration'; + +export interface GridAriaAttributesInternalHook { + useGridAriaAttributes: () => React.HTMLAttributes; +} + +export interface GridInternalHook + extends GridAriaAttributesInternalHook, + GridRowAriaAttributesInternalHook {} -export type GridInternalHook = GridRowInternalHook; export interface GridConfiguration { - hooks: Record; + hooks: GridInternalHook; } diff --git a/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts b/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts index cc0a74d1caa62..c206f3b0dbab2 100644 --- a/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts +++ b/packages/x-data-grid/src/models/configuration/gridRowConfiguration.ts @@ -1,14 +1,17 @@ +import * as React from 'react'; import { GridTreeNode } from '../gridRows'; /** * Get the ARIA attributes for a row * @param {GridTreeNode} rowNode The row node * @param {number} index The position index of the row - * @returns {Record} The ARIA attributes + * @returns {React.HTMLAttributes} The ARIA attributes */ -type GetAriaAttributesFn = ( +export type GetRowAriaAttributesFn = ( rowNode: GridTreeNode, index: number, -) => Record; +) => React.HTMLAttributes; -export type GridRowInternalHook = () => GetAriaAttributesFn; +export interface GridRowAriaAttributesInternalHook { + useGridRowAriaAttributes: () => GetRowAriaAttributesFn; +} From 1ddc12930759946e10ff59cdd58888edac1256ca Mon Sep 17 00:00:00 2001 From: Armin Mehinovic <4390250+arminmeh@users.noreply.github.com> Date: Fri, 19 Jul 2024 22:24:09 +0200 Subject: [PATCH 53/89] Update serverChildrenCount description Co-authored-by: Bilal Shafi Signed-off-by: Armin Mehinovic <4390250+arminmeh@users.noreply.github.com> --- packages/x-data-grid/src/models/gridRows.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/x-data-grid/src/models/gridRows.ts b/packages/x-data-grid/src/models/gridRows.ts index 62ff055ccff61..f7282e9c59a12 100644 --- a/packages/x-data-grid/src/models/gridRows.ts +++ b/packages/x-data-grid/src/models/gridRows.ts @@ -116,7 +116,7 @@ export interface GridDataGroupNode extends GridBasicGroupNode { export interface GridDataSourceGroupNode extends GridDataGroupNode { /** - * Number of children this node has on the server. Returns `-1` if there are some children but the count is unknown. + * Number of children this node has on the server. Equals to `-1` if there are some children but the count is unknown. */ serverChildrenCount: number; /** From a79c41848d2972c657c727e43975873b9b7db915 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Fri, 2 Aug 2024 20:53:48 +0200 Subject: [PATCH 54/89] Group internal exports that need lint rule disabled --- packages/x-data-grid-pro/src/internals/index.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/x-data-grid-pro/src/internals/index.ts b/packages/x-data-grid-pro/src/internals/index.ts index e4c265212f5d6..c0de9e27064b8 100644 --- a/packages/x-data-grid-pro/src/internals/index.ts +++ b/packages/x-data-grid-pro/src/internals/index.ts @@ -4,8 +4,14 @@ export * from '@mui/x-data-grid/internals'; export { GridColumnHeaders } from '../components/GridColumnHeaders'; export { DATA_GRID_PRO_DEFAULT_SLOTS_COMPONENTS } from '../constants/dataGridProDefaultSlotsComponents'; -// eslint-disable-next-line import/export +/* eslint-disable import/export -- + * x-data-grid-pro internals that are overriding the x-data-grid internals + */ export { useGridColumnHeaders } from '../hooks/features/columnHeaders/useGridColumnHeaders'; +export { useGridAriaAttributes } from '../hooks/utils/useGridAriaAttributes'; +export { useGridRowAriaAttributes } from '../hooks/features/rows/useGridRowAriaAttributes'; +// eslint-enable import/export + export { useGridColumnPinning, columnPinningStateInitializer, @@ -23,10 +29,6 @@ export { export { useGridDetailPanelPreProcessors } from '../hooks/features/detailPanel/useGridDetailPanelPreProcessors'; export { useGridInfiniteLoader } from '../hooks/features/infiniteLoader/useGridInfiniteLoader'; -// eslint-disable-next-line import/export -export { useGridAriaAttributes } from '../hooks/utils/useGridAriaAttributes'; -// eslint-disable-next-line import/export -export { useGridRowAriaAttributes } from '../hooks/features/rows/useGridRowAriaAttributes'; export { useGridRowReorder } from '../hooks/features/rowReorder/useGridRowReorder'; export { useGridRowReorderPreProcessors } from '../hooks/features/rowReorder/useGridRowReorderPreProcessors'; export { useGridTreeData } from '../hooks/features/treeData/useGridTreeData'; From ea42fe2dca7a447641d593726d597353d6dfc419 Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Fri, 2 Aug 2024 21:36:08 +0200 Subject: [PATCH 55/89] debug: list installed dependencies --- netlify.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlify.toml b/netlify.toml index 767f5a910c795..941f0c053fec4 100644 --- a/netlify.toml +++ b/netlify.toml @@ -5,7 +5,7 @@ publish = "docs/export/" # Default build command. - command = "pnpm docs:build" + command = "pnpm list --filter docs && pnpm docs:build" [build.environment] NODE_VERSION = "18" From f91871c6e600f6ae81d4676a65483c7dee420843 Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Fri, 2 Aug 2024 23:07:45 +0200 Subject: [PATCH 56/89] try removing everything from .next except cache folder --- netlify.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlify.toml b/netlify.toml index 941f0c053fec4..2d25bb697d934 100644 --- a/netlify.toml +++ b/netlify.toml @@ -5,7 +5,7 @@ publish = "docs/export/" # Default build command. - command = "pnpm list --filter docs && pnpm docs:build" + command = "pnpm list --filter docs && rm -rf docs/.next/static && rm -rf docs/.next/server && rm -f docs/.next/* && ls -la docs/.next && pnpm docs:build" [build.environment] NODE_VERSION = "18" From f254de6627fc7e395b1b20433dc99444325a421d Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Fri, 2 Aug 2024 23:19:55 +0200 Subject: [PATCH 57/89] do not error on directories --- netlify.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlify.toml b/netlify.toml index 2d25bb697d934..14738c6212418 100644 --- a/netlify.toml +++ b/netlify.toml @@ -5,7 +5,7 @@ publish = "docs/export/" # Default build command. - command = "pnpm list --filter docs && rm -rf docs/.next/static && rm -rf docs/.next/server && rm -f docs/.next/* && ls -la docs/.next && pnpm docs:build" + command = "pnpm list --filter docs && rm -rf docs/.next/static && rm -rf docs/.next/server && rm -f docs/.next/* 2> /dev/null && ls -la docs/.next && pnpm docs:build" [build.environment] NODE_VERSION = "18" From f887561f6b83448bcb12863fb0abd9de6fd5b0a5 Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Fri, 2 Aug 2024 23:30:19 +0200 Subject: [PATCH 58/89] fix exit code 2 --- netlify.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlify.toml b/netlify.toml index 14738c6212418..e544b840795d4 100644 --- a/netlify.toml +++ b/netlify.toml @@ -5,7 +5,7 @@ publish = "docs/export/" # Default build command. - command = "pnpm list --filter docs && rm -rf docs/.next/static && rm -rf docs/.next/server && rm -f docs/.next/* 2> /dev/null && ls -la docs/.next && pnpm docs:build" + command = "pnpm list --filter docs && rm -rf docs/.next/static && rm -rf docs/.next/server && rm -f docs/.next/* || true && ls -la docs/.next && pnpm docs:build" [build.environment] NODE_VERSION = "18" From 43374fe7655c2908014d1445c9142f8e84eaecc4 Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Sat, 3 Aug 2024 00:46:07 +0200 Subject: [PATCH 59/89] fork netlify plugin --- netlify.toml | 2 +- packages/netlify-plugin-cache-docs/index.js | 64 +++++++++++++++++++ .../netlify-plugin-cache-docs/manifest.yml | 1 + .../netlify-plugin-cache-docs/package.json | 21 ++++++ pnpm-lock.yaml | 6 ++ 5 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 packages/netlify-plugin-cache-docs/index.js create mode 100644 packages/netlify-plugin-cache-docs/manifest.yml create mode 100644 packages/netlify-plugin-cache-docs/package.json diff --git a/netlify.toml b/netlify.toml index e544b840795d4..aa5d995f834d5 100644 --- a/netlify.toml +++ b/netlify.toml @@ -13,4 +13,4 @@ PNPM_FLAGS = "--shamefully-hoist" [[plugins]] - package = "./node_modules/@mui/monorepo/packages/netlify-plugin-cache-docs" + package = "./packages/netlify-plugin-cache-docs" diff --git a/packages/netlify-plugin-cache-docs/index.js b/packages/netlify-plugin-cache-docs/index.js new file mode 100644 index 0000000000000..701231ce12095 --- /dev/null +++ b/packages/netlify-plugin-cache-docs/index.js @@ -0,0 +1,64 @@ +/* eslint-disable no-console */ +const path = require('path'); +const fse = require('fs-extra'); + +const CACHE_OUTPUT_FILE = 'cache-output.json'; + +function generateAbsolutePaths(context) { + const { constants } = context; + + const workspaceRoot = path.dirname(constants.CONFIG_PATH); + const docsWorkspacePath = path.join(workspaceRoot, 'docs'); + + const nextjsBuildDir = path.join(docsWorkspacePath, '.next'); + const digests = [path.join(workspaceRoot, 'pnpm-lock.yaml')]; + + return { digests, nextjsBuildDir }; +} + +module.exports = { + async onPreBuild(context) { + const { constants, utils } = context; + const { nextjsBuildDir } = generateAbsolutePaths({ constants }); + const success = await utils.cache.restore(nextjsBuildDir); + + console.log("'%s' exists: %s", nextjsBuildDir, String(fse.existsSync(nextjsBuildDir))); + + console.log( + "Restored the cached 'docs/.next' folder at the location '%s': %s", + nextjsBuildDir, + String(success), + ); + }, + async onPostBuild(context) { + const { constants, utils } = context; + const { digests, nextjsBuildDir } = generateAbsolutePaths({ constants }); + + console.log("'%s' exists: %s", nextjsBuildDir, String(fse.existsSync(nextjsBuildDir))); + + const success = await utils.cache.save(nextjsBuildDir, { + digests, + }); + + console.log( + "Cached 'docs/.next' folder at the location '%s': %s", + nextjsBuildDir, + String(success), + ); + }, + // debug + // based on: https://github.com/netlify-labs/netlify-plugin-debug-cache/blob/v1.0.3/index.js + async onEnd({ constants, utils }) { + const { PUBLISH_DIR } = constants; + const cacheManifestFileName = CACHE_OUTPUT_FILE; + const cacheManifestPath = path.join(PUBLISH_DIR, cacheManifestFileName); + console.log('Saving cache file manifest for debugging...'); + const files = await utils.cache.list(); + await fse.mkdirp(PUBLISH_DIR); + await fse.writeJSON(cacheManifestPath, files, { spaces: 2 }); + console.log(`Cache file count: ${files.length}`); + console.log(`Cache manifest saved to ${cacheManifestPath}`); + console.log(`Please download the build files to inspect ${cacheManifestFileName}.`); + console.log('Instructions => http://bit.ly/netlify-dl-cache'); + }, +}; diff --git a/packages/netlify-plugin-cache-docs/manifest.yml b/packages/netlify-plugin-cache-docs/manifest.yml new file mode 100644 index 0000000000000..46be74dddcce9 --- /dev/null +++ b/packages/netlify-plugin-cache-docs/manifest.yml @@ -0,0 +1 @@ +name: netlify-plugin-cache-docs diff --git a/packages/netlify-plugin-cache-docs/package.json b/packages/netlify-plugin-cache-docs/package.json new file mode 100644 index 0000000000000..7dd0b7b981977 --- /dev/null +++ b/packages/netlify-plugin-cache-docs/package.json @@ -0,0 +1,21 @@ +{ + "name": "netlify-plugin-cache-docs", + "version": "5.0.0", + "private": true, + "author": "MUI Team", + "description": "Alternative to netlify-plugin-cache-nextjs", + "keywords": [], + "repository": { + "type": "git", + "url": "https://github.com/mui/material-ui.git", + "directory": "packages/netlify-plugin-cache-docs" + }, + "license": "MIT", + "scripts": {}, + "dependencies": { + "fs-extra": "^11.2.0" + }, + "engines": { + "node": ">=12.0.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86a5d3a8f25e4..dd736f42579bc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -703,6 +703,12 @@ importers: specifier: ^7.16.1 version: 7.16.1(eslint@8.57.0)(typescript@5.5.4) + packages/netlify-plugin-cache-docs: + dependencies: + fs-extra: + specifier: ^11.2.0 + version: 11.2.0 + packages/x-charts: dependencies: '@babel/runtime': From 33a5376c0a5262f7a87f50699b98e3abf9c0c2f6 Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Sun, 4 Aug 2024 01:59:24 +0200 Subject: [PATCH 60/89] try removing docs/.next before build --- netlify.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlify.toml b/netlify.toml index aa5d995f834d5..085894feb1688 100644 --- a/netlify.toml +++ b/netlify.toml @@ -5,7 +5,7 @@ publish = "docs/export/" # Default build command. - command = "pnpm list --filter docs && rm -rf docs/.next/static && rm -rf docs/.next/server && rm -f docs/.next/* || true && ls -la docs/.next && pnpm docs:build" + command = "pnpm list --filter docs && rm -rf docs/.next && pnpm docs:build" [build.environment] NODE_VERSION = "18" From ba96136bfda6f91c9333dfa4442f6066e3d1c39e Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Sun, 4 Aug 2024 16:15:07 +0200 Subject: [PATCH 61/89] make sure the next folder does not exist before build --- netlify.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netlify.toml b/netlify.toml index 085894feb1688..41ea181501f9a 100644 --- a/netlify.toml +++ b/netlify.toml @@ -5,7 +5,7 @@ publish = "docs/export/" # Default build command. - command = "pnpm list --filter docs && rm -rf docs/.next && pnpm docs:build" + command = "pnpm list --filter docs && rm -rf docs/.next && ls -la docs && pnpm docs:build" [build.environment] NODE_VERSION = "18" From aeca849071f32c2f1d9dca86242db03c547d6868 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Mon, 5 Aug 2024 10:04:05 +0200 Subject: [PATCH 62/89] Code cleanup --- .../src/hooks/features/rows/useGridRowAriaAttributes.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx index beab496173c5c..97776f90cd5e8 100644 --- a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -26,14 +26,11 @@ export const useGridRowAriaAttributes = (addTreeDataAttributes?: boolean) => { gridExpandedSortedRowTreeLevelPositionLookupSelector, ); - const addAttributes = - addTreeDataAttributes !== undefined ? addTreeDataAttributes : props.treeData === true; - return React.useCallback( (rowNode: GridTreeNode, index: number) => { const ariaAttributes = getRowAriaAttributesCommunity(rowNode, index); - if (!addAttributes || rowNode === null) { + if (rowNode === null || !(props.treeData || addTreeDataAttributes)) { return ariaAttributes; } @@ -57,7 +54,8 @@ export const useGridRowAriaAttributes = (addTreeDataAttributes?: boolean) => { return ariaAttributes; }, [ - addAttributes, + props.treeData, + addTreeDataAttributes, filteredTopLevelRowCount, filteredChildrenCountLookup, sortedVisibleRowPositionsLookup, From 008cd4e6f7835be2583f4160f9e647d9b53c2172 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Mon, 5 Aug 2024 10:04:45 +0200 Subject: [PATCH 63/89] isRowSelectable returns false if the whole feature is disabled --- .../rowSelection/useGridRowSelection.ts | 4 ++++ .../src/tests/rowSelection.DataGrid.test.tsx | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts b/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts index 2888ec5929a1d..d582f06f26461 100644 --- a/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts +++ b/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts @@ -186,6 +186,10 @@ export const useGridRowSelection = ( const isRowSelectable = React.useCallback( (id) => { + if (props.rowSelection === false) { + return false; + } + if (propIsRowSelectable && !propIsRowSelectable(apiRef.current.getRowParams(id))) { return false; } diff --git a/packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx b/packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx index 4cfe95e32b9ca..f01954e76a1fe 100644 --- a/packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx +++ b/packages/x-data-grid/src/tests/rowSelection.DataGrid.test.tsx @@ -837,6 +837,27 @@ describe(' - Row selection', () => { }); }); + describe('accessibility', () => { + it('should add aria-selected attributes to the selectable rows', () => { + render(); + + // Select the first row + userEvent.mousePress(getCell(0, 0)); + expect(getRow(0).getAttribute('aria-selected')).to.equal('true'); + expect(getRow(1).getAttribute('aria-selected')).to.equal('false'); + }); + + it('should not add aria-selected attributes if the row selection is disabled', () => { + render(); + expect(getRow(0).getAttribute('aria-selected')).to.equal(null); + + // Try to select the first row + userEvent.mousePress(getCell(0, 0)); + // nothing should change + expect(getRow(0).getAttribute('aria-selected')).to.equal(null); + }); + }); + describe('performance', () => { it('should not rerender unrelated nodes', () => { // Couldn't use because we need to track multiple components From 41837e5fa5a0bb90e49af73a319e92652fb3ef3e Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Mon, 5 Aug 2024 10:07:35 +0200 Subject: [PATCH 64/89] Fix docs referring to a cell for a row API --- .../api-docs/data-grid/data-grid-premium/data-grid-premium.json | 2 +- .../api-docs/data-grid/data-grid-pro/data-grid-pro.json | 2 +- docs/translations/api-docs/data-grid/data-grid/data-grid.json | 2 +- .../x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx | 2 +- packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx | 2 +- packages/x-data-grid/src/DataGrid/DataGrid.tsx | 2 +- packages/x-data-grid/src/models/props/DataGridProps.ts | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json index a8b79b49fb93e..68ba1ef303b5f 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium/data-grid-premium.json @@ -223,7 +223,7 @@ "description": "Determines if a row can be selected.", "typeDescriptions": { "params": "With all properties from GridRowParams.", - "boolean": "A boolean indicating if the cell is selectable." + "boolean": "A boolean indicating if the row is selectable." } }, "keepColumnPositionIfDraggedOutside": { diff --git a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json index 914817291c87f..b52063f75d28a 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro/data-grid-pro.json @@ -204,7 +204,7 @@ "description": "Determines if a row can be selected.", "typeDescriptions": { "params": "With all properties from GridRowParams.", - "boolean": "A boolean indicating if the cell is selectable." + "boolean": "A boolean indicating if the row is selectable." } }, "keepColumnPositionIfDraggedOutside": { diff --git a/docs/translations/api-docs/data-grid/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid/data-grid.json index 08fa6f50e6c46..545e3c09ac3a1 100644 --- a/docs/translations/api-docs/data-grid/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid/data-grid.json @@ -150,7 +150,7 @@ "description": "Determines if a row can be selected.", "typeDescriptions": { "params": "With all properties from GridRowParams.", - "boolean": "A boolean indicating if the cell is selectable." + "boolean": "A boolean indicating if the row is selectable." } }, "keepNonExistentRowsSelected": { diff --git a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index cb597ca51e9b1..18b424a76bb4c 100644 --- a/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -493,7 +493,7 @@ DataGridPremiumRaw.propTypes = { /** * Determines if a row can be selected. * @param {GridRowParams} params With all properties from [[GridRowParams]]. - * @returns {boolean} A boolean indicating if the cell is selectable. + * @returns {boolean} A boolean indicating if the row is selectable. */ isRowSelectable: PropTypes.func, /** diff --git a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index 2bfd177cb80e0..b168aad4b0b4a 100644 --- a/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -449,7 +449,7 @@ DataGridProRaw.propTypes = { /** * Determines if a row can be selected. * @param {GridRowParams} params With all properties from [[GridRowParams]]. - * @returns {boolean} A boolean indicating if the cell is selectable. + * @returns {boolean} A boolean indicating if the row is selectable. */ isRowSelectable: PropTypes.func, /** diff --git a/packages/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/x-data-grid/src/DataGrid/DataGrid.tsx index a5faebe380546..72fcb94533209 100644 --- a/packages/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/x-data-grid/src/DataGrid/DataGrid.tsx @@ -369,7 +369,7 @@ DataGridRaw.propTypes = { /** * Determines if a row can be selected. * @param {GridRowParams} params With all properties from [[GridRowParams]]. - * @returns {boolean} A boolean indicating if the cell is selectable. + * @returns {boolean} A boolean indicating if the row is selectable. */ isRowSelectable: PropTypes.func, /** diff --git a/packages/x-data-grid/src/models/props/DataGridProps.ts b/packages/x-data-grid/src/models/props/DataGridProps.ts index 47a56c9a742a6..97b44620eca30 100644 --- a/packages/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/x-data-grid/src/models/props/DataGridProps.ts @@ -469,7 +469,7 @@ export interface DataGridPropsWithoutDefaultValue) => boolean; /** From a6cc046c18362d79f68820bc332a2ba7e11095df Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Mon, 5 Aug 2024 10:08:02 +0200 Subject: [PATCH 65/89] Selectable row always has 'aria-selected' attribute --- .../src/hooks/features/rows/useGridRowAriaAttributes.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx index 67080a7c97249..a7f615417085f 100644 --- a/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -18,8 +18,8 @@ export const useGridRowAriaAttributes = (): GetRowAriaAttributesFn => { const ariaRowIndex = index + headerGroupingMaxDepth + 2; // 1 for the header row and 1 as it's 1-based ariaAttributes['aria-rowindex'] = ariaRowIndex; - if (selectedIdsLookup[rowNode.id]) { - ariaAttributes['aria-selected'] = true; + if (apiRef.current.isRowSelectable(rowNode.id)) { + ariaAttributes['aria-selected'] = selectedIdsLookup[rowNode.id] !== undefined; } return ariaAttributes; From ac7007372570a1602dfb5c278bca3435e9a11d61 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Mon, 5 Aug 2024 10:51:05 +0200 Subject: [PATCH 66/89] pinned and footer rows should not get the set specific aria attributes --- .../rows/useGridRowAriaAttributes.tsx | 5 ++++ .../src/tests/treeData.DataGridPro.test.tsx | 28 +++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx index 97776f90cd5e8..1a5174ec5c4f0 100644 --- a/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid-pro/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -34,6 +34,11 @@ export const useGridRowAriaAttributes = (addTreeDataAttributes?: boolean) => { return ariaAttributes; } + // pinned and footer rows are not part of the rowgroup and should not get the set specific aria attributes + if (rowNode.type === 'footer' || rowNode.type === 'pinnedRow') { + return ariaAttributes; + } + ariaAttributes['aria-level'] = rowNode.depth + 1; const filteredChildrenCount = filteredChildrenCountLookup[rowNode.id] ?? 0; diff --git a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx index 1b635f67898a5..12260bda0f58d 100644 --- a/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx +++ b/packages/x-data-grid-pro/src/tests/treeData.DataGridPro.test.tsx @@ -769,7 +769,7 @@ describe(' - Tree data', () => { describe('accessibility', () => { it('should add necessary treegrid aria attributes to the rows', () => { - render(); + render(); expect(getRow(0).getAttribute('aria-level')).to.equal('1'); // A expect(getRow(1).getAttribute('aria-level')).to.equal('2'); // A.A @@ -782,7 +782,7 @@ describe(' - Tree data', () => { it('should adjust treegrid aria attributes after filtering', () => { render( - Tree data', () => { expect(getRow(3).getAttribute('aria-posinset')).to.equal('1'); // B.A expect(getRow(3).getAttribute('aria-setsize')).to.equal('2'); // B.A & B.B }); + + it('should not add the set specific aria attributes to pinned rows', () => { + render( + , + ); + + expect(getRow(0).getAttribute('aria-rowindex')).to.equal('2'); // header row is 1 + expect(getRow(0).getAttribute('aria-level')).to.equal(null); + expect(getRow(0).getAttribute('aria-posinset')).to.equal(null); + expect(getRow(0).getAttribute('aria-setsize')).to.equal(null); + expect(getRow(1).getAttribute('aria-rowindex')).to.equal('3'); + expect(getRow(1).getAttribute('aria-level')).to.equal('1'); // A + expect(getRow(1).getAttribute('aria-posinset')).to.equal('1'); + expect(getRow(1).getAttribute('aria-setsize')).to.equal('3'); // A, B, C + }); }); describe('regressions', () => { From 2a51b10e7d93dc4814f2e6b5196f221aa99c8246 Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Mon, 5 Aug 2024 10:56:21 +0200 Subject: [PATCH 67/89] Add missing dependencies --- .../src/hooks/features/rowSelection/useGridRowSelection.ts | 2 +- .../src/hooks/features/rows/useGridRowAriaAttributes.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts b/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts index d582f06f26461..935b05007aad3 100644 --- a/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts +++ b/packages/x-data-grid/src/hooks/features/rowSelection/useGridRowSelection.ts @@ -201,7 +201,7 @@ export const useGridRowSelection = ( return true; }, - [apiRef, propIsRowSelectable], + [apiRef, props.rowSelection, propIsRowSelectable], ); const getSelectedRows = React.useCallback( diff --git a/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx b/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx index a7f615417085f..112d58e4dfa3c 100644 --- a/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx +++ b/packages/x-data-grid/src/hooks/features/rows/useGridRowAriaAttributes.tsx @@ -24,6 +24,6 @@ export const useGridRowAriaAttributes = (): GetRowAriaAttributesFn => { return ariaAttributes; }, - [selectedIdsLookup, headerGroupingMaxDepth], + [apiRef, selectedIdsLookup, headerGroupingMaxDepth], ); }; From 9e546d814d818c6af60e3e034f90abe3e424c513 Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Mon, 5 Aug 2024 13:04:57 +0200 Subject: [PATCH 68/89] log @mui/joy/package.json --- docs/pages/_document.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/pages/_document.js b/docs/pages/_document.js index f9dfc9a7f73a6..9a13c76330a64 100644 --- a/docs/pages/_document.js +++ b/docs/pages/_document.js @@ -1,3 +1,6 @@ import MyDocument from '@mui/monorepo/docs/pages/_document'; +import packageJson from '@mui/joy/package.json'; + +console.log('@mui/joy/package.json', packageJson); export default MyDocument; From 73b64a7bc4347812ec6f0f675b8e1b177d1a9f68 Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Mon, 5 Aug 2024 13:10:54 +0200 Subject: [PATCH 69/89] fix import order --- docs/pages/_document.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/pages/_document.js b/docs/pages/_document.js index 9a13c76330a64..136c81d982481 100644 --- a/docs/pages/_document.js +++ b/docs/pages/_document.js @@ -1,6 +1,7 @@ -import MyDocument from '@mui/monorepo/docs/pages/_document'; import packageJson from '@mui/joy/package.json'; console.log('@mui/joy/package.json', packageJson); +// eslint-disable-next-line import/first +import MyDocument from '@mui/monorepo/docs/pages/_document'; export default MyDocument; From 0a72fd5515379653af190d242340199497f5304d Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Mon, 5 Aug 2024 13:47:16 +0200 Subject: [PATCH 70/89] log @mui/joy/package.json --- docs/package.json | 2 +- docs/pages/_document.js | 4 ---- docs/pages/_document2.js | 4 ++++ 3 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 docs/pages/_document2.js diff --git a/docs/package.json b/docs/package.json index 1c2da49546121..886450363c57e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,7 +5,7 @@ "author": "MUI Team", "license": "MIT", "scripts": { - "build": "rimraf ./export && cross-env NODE_ENV=production next build --profile && pnpm build-sw", + "build": "rimraf ./export && node --experimental-default-type=module pages/_document2.js && cross-env NODE_ENV=production next build --profile && pnpm build-sw", "build:clean": "rimraf .next && pnpm build", "build-sw": "node ./scripts/buildServiceWorker.js", "dev": "next dev --port 3001", diff --git a/docs/pages/_document.js b/docs/pages/_document.js index 136c81d982481..f9dfc9a7f73a6 100644 --- a/docs/pages/_document.js +++ b/docs/pages/_document.js @@ -1,7 +1,3 @@ -import packageJson from '@mui/joy/package.json'; - -console.log('@mui/joy/package.json', packageJson); -// eslint-disable-next-line import/first import MyDocument from '@mui/monorepo/docs/pages/_document'; export default MyDocument; diff --git a/docs/pages/_document2.js b/docs/pages/_document2.js new file mode 100644 index 0000000000000..6ba459641bf80 --- /dev/null +++ b/docs/pages/_document2.js @@ -0,0 +1,4 @@ +import packageJson from '@mui/joy/package.json' with { type: 'json' }; + +// eslint-disable-next-line no-console +console.log('@mui/joy/package.json', packageJson); From 6c45d83ddf7d363e71cf9ae80462fa3cd6f00d39 Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Mon, 5 Aug 2024 13:56:18 +0200 Subject: [PATCH 71/89] add InitColorSchemeScript import --- docs/pages/_document2.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/pages/_document2.js b/docs/pages/_document2.js index 6ba459641bf80..81d5c9871118e 100644 --- a/docs/pages/_document2.js +++ b/docs/pages/_document2.js @@ -1,4 +1,7 @@ import packageJson from '@mui/joy/package.json' with { type: 'json' }; +import JoyInitColorSchemeScript from '@mui/joy/InitColorSchemeScript'; // eslint-disable-next-line no-console console.log('@mui/joy/package.json', packageJson); +// eslint-disable-next-line no-console +console.log('JoyInitColorSchemeScript', typeof JoyInitColorSchemeScript); From b5965ee1f7024e8e55e0c336346fc144a33b3bbc Mon Sep 17 00:00:00 2001 From: Armin Mehinovic Date: Mon, 5 Aug 2024 14:37:41 +0200 Subject: [PATCH 72/89] Delete from the docs script --- docs/package.json | 2 +- docs/pages/_document2.js | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) delete mode 100644 docs/pages/_document2.js diff --git a/docs/package.json b/docs/package.json index 886450363c57e..61ec50c26416a 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,7 +5,7 @@ "author": "MUI Team", "license": "MIT", "scripts": { - "build": "rimraf ./export && node --experimental-default-type=module pages/_document2.js && cross-env NODE_ENV=production next build --profile && pnpm build-sw", + "build": "rimraf ./export && rm -rf ./.next && cross-env NODE_ENV=production next build --profile && pnpm build-sw", "build:clean": "rimraf .next && pnpm build", "build-sw": "node ./scripts/buildServiceWorker.js", "dev": "next dev --port 3001", diff --git a/docs/pages/_document2.js b/docs/pages/_document2.js deleted file mode 100644 index 81d5c9871118e..0000000000000 --- a/docs/pages/_document2.js +++ /dev/null @@ -1,7 +0,0 @@ -import packageJson from '@mui/joy/package.json' with { type: 'json' }; -import JoyInitColorSchemeScript from '@mui/joy/InitColorSchemeScript'; - -// eslint-disable-next-line no-console -console.log('@mui/joy/package.json', packageJson); -// eslint-disable-next-line no-console -console.log('JoyInitColorSchemeScript', typeof JoyInitColorSchemeScript); From cbaa80716e532fa44c6aa9d7606bf956598048f0 Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Mon, 5 Aug 2024 14:52:00 +0200 Subject: [PATCH 73/89] try importing InitColorSchemeScript from MUI X _document --- docs/package.json | 2 +- docs/pages/_document.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/package.json b/docs/package.json index 886450363c57e..1c2da49546121 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,7 +5,7 @@ "author": "MUI Team", "license": "MIT", "scripts": { - "build": "rimraf ./export && node --experimental-default-type=module pages/_document2.js && cross-env NODE_ENV=production next build --profile && pnpm build-sw", + "build": "rimraf ./export && cross-env NODE_ENV=production next build --profile && pnpm build-sw", "build:clean": "rimraf .next && pnpm build", "build-sw": "node ./scripts/buildServiceWorker.js", "dev": "next dev --port 3001", diff --git a/docs/pages/_document.js b/docs/pages/_document.js index f9dfc9a7f73a6..94b26a364ee4a 100644 --- a/docs/pages/_document.js +++ b/docs/pages/_document.js @@ -1,3 +1,8 @@ +import JoyInitColorSchemeScript from '@mui/joy/InitColorSchemeScript'; +// eslint-disable-next-line no-console +console.log('_document JoyInitColorSchemeScript', typeof JoyInitColorSchemeScript); + +// eslint-disable-next-line import/first import MyDocument from '@mui/monorepo/docs/pages/_document'; export default MyDocument; From 56f513194d3d615082628785ec13edfc3cc2c1e5 Mon Sep 17 00:00:00 2001 From: Andrew Cherniavskyi Date: Mon, 5 Aug 2024 15:00:25 +0200 Subject: [PATCH 74/89] duplicate _document from monorepo --- docs/pages/_document.js | 279 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 274 insertions(+), 5 deletions(-) diff --git a/docs/pages/_document.js b/docs/pages/_document.js index 94b26a364ee4a..c2ffa343a34cf 100644 --- a/docs/pages/_document.js +++ b/docs/pages/_document.js @@ -1,8 +1,277 @@ +import * as React from 'react'; +import Script from 'next/script'; +import { documentGetInitialProps } from '@mui/material-nextjs/v13-pagesRouter'; +import { ServerStyleSheets as JSSServerStyleSheets } from '@mui/styles'; +import { ServerStyleSheet } from 'styled-components'; +import Document, { Html, Head, Main, NextScript } from 'next/document'; +import GlobalStyles from '@mui/material/GlobalStyles'; +import MuiInitColorSchemeScript from '@mui/material/InitColorSchemeScript'; import JoyInitColorSchemeScript from '@mui/joy/InitColorSchemeScript'; -// eslint-disable-next-line no-console -console.log('_document JoyInitColorSchemeScript', typeof JoyInitColorSchemeScript); +import { pathnameToLanguage } from 'docs/src/modules/utils/helpers'; +import createEmotionCache from 'docs/src/createEmotionCache'; +import { getMetaThemeColor } from '@mui/docs/branding'; -// eslint-disable-next-line import/first -import MyDocument from '@mui/monorepo/docs/pages/_document'; +// You can find a benchmark of the available CSS minifiers under +// https://github.com/GoalSmashers/css-minification-benchmark +// We have found that clean-css is faster than cssnano but the output is larger. +// Waiting for https://github.com/cssinjs/jss/issues/279 +// 4% slower but 12% smaller output than doing it in a single step. +// +// It's using .browserslistrc +let prefixer; +let cleanCSS; +if (process.env.NODE_ENV === 'production') { + /* eslint-disable global-require */ + const postcss = require('postcss'); + const autoprefixer = require('autoprefixer'); + const CleanCSS = require('clean-css'); + /* eslint-enable global-require */ -export default MyDocument; + prefixer = postcss([autoprefixer]); + cleanCSS = new CleanCSS(); +} + +const PRODUCTION_GA = + process.env.DEPLOY_ENV === 'production' || process.env.DEPLOY_ENV === 'staging'; + +const GOOGLE_ANALYTICS_ID_V4 = PRODUCTION_GA ? 'G-5NXDQLC2ZK' : 'G-XJ83JQEK7J'; + +export default class MyDocument extends Document { + render() { + const { canonicalAsServer, userLanguage } = this.props; + + return ( + + + {/* + manifest.json provides metadata used when your web app is added to the + homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/ + */} + + {/* PWA primary color */} + + + + {/* iOS Icon */} + + {/* SEO */} + + + {/* + Preconnect allows the browser to setup early connections before an HTTP request + is actually sent to the server. + This includes DNS lookups, TLS negotiations, TCP handshakes. + */} + + + + {/* ========== Font preload (prevent font flash) ============= */} + 6kb) + href="/static/fonts/GeneralSans-Semibold-subset.woff2" + as="font" + type="font/woff2" + crossOrigin="anonymous" + /> +