Skip to content

Commit 0e5cf97

Browse files
Passing generateGroupId props (#3520)
Add `groupIdGetter` prop Co-authored-by: Aman Mahajan <[email protected]>
1 parent 80e9943 commit 0e5cf97

File tree

4 files changed

+41
-11
lines changed

4 files changed

+41
-11
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,8 @@ function MyGridTest() {
520520

521521
###### `onExpandedGroupIdsChange?: Maybe<(expandedGroupIds: Set<unknown>) => void>`
522522

523+
###### `groupIdGetter?: Maybe<(groupKey: string, parentId?: string) => string>`
524+
523525
#### `<TextEditor />`
524526

525527
##### Props

src/DataGrid.tsx

-2
Original file line numberDiff line numberDiff line change
@@ -1037,7 +1037,6 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
10371037
// Reset the positions if the current values are no longer valid. This can happen if a column or row is removed
10381038
if (selectedPosition.idx > maxColIdx || selectedPosition.rowIdx > maxRowIdx) {
10391039
setSelectedPosition({ idx: -1, rowIdx: minRowIdx - 1, mode: 'SELECT' });
1040-
// eslint-disable-next-line react-compiler/react-compiler
10411040
setDraggedOverRowIdx(undefined);
10421041
}
10431042

@@ -1165,7 +1164,6 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
11651164
);
11661165
})}
11671166
<RowSelectionChangeContext value={selectRowLatest}>
1168-
{/* eslint-disable-next-line react-compiler/react-compiler */}
11691167
{getViewportRows()}
11701168
</RowSelectionChangeContext>
11711169
{bottomSummaryRows?.map((row, rowIdx) => {

src/TreeDataGrid.tsx

+10-3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export interface TreeDataGridProps<R, SR = unknown, K extends Key = Key>
3939
) => Record<string, readonly NoInfer<R>[]>;
4040
expandedGroupIds: ReadonlySet<unknown>;
4141
onExpandedGroupIdsChange: (expandedGroupIds: Set<unknown>) => void;
42+
groupIdGetter?: Maybe<(groupKey: string, parentId?: string) => string>;
4243
}
4344

4445
type GroupByDictionary<TRow> = Record<
@@ -66,13 +67,15 @@ export function TreeDataGrid<R, SR = unknown, K extends Key = Key>({
6667
rowGrouper,
6768
expandedGroupIds,
6869
onExpandedGroupIdsChange,
70+
groupIdGetter: rawGroupIdGetter,
6971
...props
7072
}: TreeDataGridProps<R, SR, K>) {
7173
const defaultRenderers = useDefaultRenderers<R, SR>();
7274
const rawRenderRow = renderers?.renderRow ?? defaultRenderers?.renderRow ?? defaultRenderRow;
7375
const headerAndTopSummaryRowsCount = 1 + (props.topSummaryRows?.length ?? 0);
7476
const { leftKey, rightKey } = getLeftRightKey(props.direction);
7577
const toggleGroupLatest = useLatestFunc(toggleGroup);
78+
const groupIdGetter = rawGroupIdGetter ?? defaultGroupIdGetter;
7679

7780
const { columns, groupBy } = useMemo(() => {
7881
const columns = [...rawColumns].sort(({ key: aKey }, { key: bKey }) => {
@@ -144,6 +147,7 @@ export function TreeDataGrid<R, SR = unknown, K extends Key = Key>({
144147
if (!groupedRows) return [rawRows, isGroupRow];
145148

146149
const flattenedRows: Array<R | GroupRow<R>> = [];
150+
147151
const expandGroup = (
148152
rows: GroupByDictionary<R> | readonly R[],
149153
parentId: string | undefined,
@@ -154,8 +158,7 @@ export function TreeDataGrid<R, SR = unknown, K extends Key = Key>({
154158
return;
155159
}
156160
Object.keys(rows).forEach((groupKey, posInSet, keys) => {
157-
// TODO: should users have control over the generated key?
158-
const id = parentId !== undefined ? `${parentId}__${groupKey}` : groupKey;
161+
const id = groupIdGetter(groupKey, parentId);
159162
const isExpanded = expandedGroupIds.has(id);
160163
const { childRows, childGroups, startRowIndex } = rows[groupKey];
161164

@@ -185,7 +188,7 @@ export function TreeDataGrid<R, SR = unknown, K extends Key = Key>({
185188
function isGroupRow(row: R | GroupRow<R>): row is GroupRow<R> {
186189
return allGroupRows.has(row);
187190
}
188-
}, [expandedGroupIds, groupedRows, rawRows]);
191+
}, [expandedGroupIds, groupedRows, rawRows, groupIdGetter]);
189192

190193
const rowHeight = useMemo(() => {
191194
if (typeof rawRowHeight === 'function') {
@@ -445,6 +448,10 @@ export function TreeDataGrid<R, SR = unknown, K extends Key = Key>({
445448
);
446449
}
447450

451+
function defaultGroupIdGetter(groupKey: string, parentId: string | undefined) {
452+
return parentId !== undefined ? `${parentId}__${groupKey}` : groupKey;
453+
}
454+
448455
function isReadonlyArray(arr: unknown): arr is readonly unknown[] {
449456
return Array.isArray(arr);
450457
}

test/browser/TreeDataGrid.test.tsx

+29-6
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,13 @@ const onCellPasteSpy = vi.fn(({ row }: { row: Row }) => row);
8484
function rowKeyGetter(row: Row) {
8585
return row.id;
8686
}
87-
88-
function TestGrid({ groupBy }: { groupBy: string[] }) {
87+
function TestGrid({
88+
groupBy,
89+
groupIdGetter
90+
}: {
91+
groupBy: string[];
92+
groupIdGetter: ((groupKey: string, parentId?: string) => string) | undefined;
93+
}) {
8994
const [rows, setRows] = useState(initialRows);
9095
const [selectedRows, setSelectedRows] = useState((): ReadonlySet<number> => new Set());
9196
const [expandedGroupIds, setExpandedGroupIds] = useState(
@@ -108,6 +113,7 @@ function TestGrid({ groupBy }: { groupBy: string[] }) {
108113
onRowsChange={setRows}
109114
onCellCopy={onCellCopySpy}
110115
onCellPaste={onCellPasteSpy}
116+
groupIdGetter={groupIdGetter}
111117
/>
112118
);
113119
}
@@ -118,10 +124,8 @@ function rowGrouper(rows: readonly Row[], columnKey: string) {
118124
return Object.groupBy(rows, (r) => r[columnKey]) as Record<string, readonly R[]>;
119125
}
120126

121-
function setup(groupBy: string[]) {
122-
onCellCopySpy.mockClear();
123-
onCellPasteSpy.mockClear();
124-
page.render(<TestGrid groupBy={groupBy} />);
127+
function setup(groupBy: string[], groupIdGetter?: (groupKey: string, parentId?: string) => string) {
128+
page.render(<TestGrid groupBy={groupBy} groupIdGetter={groupIdGetter} />);
125129
}
126130

127131
function getHeaderCellsContent() {
@@ -155,6 +159,25 @@ test('should group by multiple columns', async () => {
155159
expect(getRows()).toHaveLength(4);
156160
});
157161

162+
test('should use groupIdGetter when provided', async () => {
163+
const groupIdGetter = vi.fn((groupKey: string, parentId?: string) =>
164+
parentId !== undefined ? `${groupKey}#${parentId}` : groupKey
165+
);
166+
setup(['country', 'year'], groupIdGetter);
167+
expect(groupIdGetter).toHaveBeenCalled();
168+
expect(getTreeGrid()).toHaveAttribute('aria-rowcount', '13');
169+
expect(getHeaderCellsContent()).toStrictEqual(['', 'Country', 'Year', 'Sport', 'Id']);
170+
expect(getRows()).toHaveLength(4);
171+
groupIdGetter.mockClear();
172+
await userEvent.click(page.getByRole('gridcell', { name: 'USA' }));
173+
expect(getRows()).toHaveLength(6);
174+
expect(groupIdGetter).toHaveBeenCalled();
175+
await userEvent.click(page.getByRole('gridcell', { name: 'Canada' }));
176+
expect(getRows()).toHaveLength(8);
177+
await userEvent.click(page.getByRole('gridcell', { name: '2020' }));
178+
expect(getRows()).toHaveLength(9);
179+
});
180+
158181
test('should ignore duplicate groupBy columns', async () => {
159182
setup(['year', 'year', 'year']);
160183
await expect.element(getTreeGrid()).toHaveAttribute('aria-rowcount', '10');

0 commit comments

Comments
 (0)