diff --git a/src/TreeDataGrid.tsx b/src/TreeDataGrid.tsx index 2de102da6d..7aea6211aa 100644 --- a/src/TreeDataGrid.tsx +++ b/src/TreeDataGrid.tsx @@ -36,6 +36,7 @@ export interface TreeDataGridProps ) => Record[]>; expandedGroupIds: ReadonlySet; onExpandedGroupIdsChange: (expandedGroupIds: Set) => void; + generateGroupId?: (groupKey: string, parentId?: string) => string; } type GroupByDictionary = Record< @@ -62,6 +63,7 @@ function TreeDataGrid( rowGrouper, expandedGroupIds, onExpandedGroupIdsChange, + generateGroupId, ...props }: TreeDataGridProps, ref: React.Ref @@ -144,6 +146,15 @@ function TreeDataGrid( if (!groupedRows) return [rawRows, isGroupRow]; const flattenedRows: Array> = []; + + const groupIdGenerator = (groupKey: string, parentId?: string) => { + if (generateGroupId !== undefined && typeof generateGroupId === 'function') { + return generateGroupId(groupKey, parentId); + } + + return `${parentId}__${groupKey}`; + }; + const expandGroup = ( rows: GroupByDictionary | readonly R[], parentId: string | undefined, @@ -154,8 +165,7 @@ function TreeDataGrid( return; } Object.keys(rows).forEach((groupKey, posInSet, keys) => { - // TODO: should users have control over the generated key? - const id = parentId !== undefined ? `${parentId}__${groupKey}` : groupKey; + const id = groupIdGenerator(groupKey, parentId); const isExpanded = expandedGroupIds.has(id); const { childRows, childGroups, startRowIndex } = rows[groupKey]; @@ -185,7 +195,7 @@ function TreeDataGrid( function isGroupRow(row: R | GroupRow): row is GroupRow { return allGroupRows.has(row); } - }, [expandedGroupIds, groupedRows, rawRows]); + }, [expandedGroupIds, groupedRows, rawRows, generateGroupId]); const rowHeight = useMemo(() => { if (typeof rawRowHeight === 'function') { diff --git a/test/TreeDataGrid.test.tsx b/test/TreeDataGrid.test.tsx index 1f252bf5db..0f55399445 100644 --- a/test/TreeDataGrid.test.tsx +++ b/test/TreeDataGrid.test.tsx @@ -93,7 +93,12 @@ function rowKeyGetter(row: Row) { return row.id; } -function TestGrid({ groupBy }: { groupBy: string[] }) { +interface TestGridProps { + groupBy: string[]; + generateGroupId: ((groupKey: string, parentId?: string) => string) | undefined; +} + +function TestGrid({ groupBy, generateGroupId }: TestGridProps) { const [rows, setRows] = useState(initialRows); const [selectedRows, setSelectedRows] = useState((): ReadonlySet => new Set()); const [expandedGroupIds, setExpandedGroupIds] = useState( @@ -122,12 +127,16 @@ function TestGrid({ groupBy }: { groupBy: string[] }) { onExpandedGroupIdsChange={setExpandedGroupIds} onRowsChange={setRows} onPaste={onPaste} + {...(generateGroupId && { generateGroupId })} /> ); } -function setup(groupBy: string[]) { - render(); +function setup( + groupBy: string[], + generateGroupId?: (groupKey: string, parentId?: string) => string +) { + render(); } function getHeaderCellsContent() { @@ -161,6 +170,15 @@ test('should group by multiple columns', () => { expect(getRows()).toHaveLength(4); }); +test('should group by multiple columns when passing generateGroupId', () => { + setup(['country', 'year'], (groupKey, parentId) => + parentId !== undefined ? `${groupKey}#${parentId}` : groupKey + ); + expect(getTreeGrid()).toHaveAttribute('aria-rowcount', '13'); + expect(getHeaderCellsContent()).toStrictEqual(['', 'Country', 'Year', 'Sport', 'Id']); + expect(getRows()).toHaveLength(4); +}); + test('should ignore duplicate groupBy columns', () => { setup(['year', 'year', 'year']); expect(getTreeGrid()).toHaveAttribute('aria-rowcount', '10'); @@ -184,6 +202,20 @@ test('should toggle group when group cell is clicked', async () => { expect(getRows()).toHaveLength(5); }); +test('should toggle group when group cell is clicked and is passing `generateGroupId` props', async () => { + setup(['country', 'year'], (groupKey, parentId) => + parentId !== undefined ? `${groupKey}#${parentId}` : groupKey + ); + expect(getTreeGrid()).toHaveAttribute('aria-rowcount', '13'); + expect(getHeaderCellsContent()).toStrictEqual(['', 'Country', 'Year', 'Sport', 'Id']); + await userEvent.click(screen.getByRole('gridcell', { name: 'USA' })); + expect(getRows()).toHaveLength(6); + await userEvent.click(screen.getByRole('gridcell', { name: 'Canada' })); + expect(getRows()).toHaveLength(8); + await userEvent.click(screen.getByRole('gridcell', { name: '2020' })); + expect(getRows()).toHaveLength(9); +}); + test('should toggle group using keyboard', async () => { setup(['year']); expect(getRows()).toHaveLength(5);