Skip to content

Commit b4fe331

Browse files
thyeggmanjoshblack
andauthored
Add sparse sorting to DataTable (#3749)
* Co-authored-by: Josh Black <joshblack@github.com> * Add another value for blank equality comparison * Update sortBy comment * chore: add changeset --------- Co-authored-by: Josh Black <joshblack@users.noreply.github.com>
1 parent ba6c074 commit b4fe331

File tree

3 files changed

+99
-5
lines changed

3 files changed

+99
-5
lines changed

.changeset/metal-horses-teach.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@primer/react': minor
3+
---
4+
5+
Add suport for sparse sorting to DataTable
6+
7+
<!-- Changed components: DataTable -->

src/DataTable/__tests__/DataTable.test.tsx

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,81 @@ describe('DataTable', () => {
551551
})
552552
})
553553

554+
it('should sort sparsely populated columns with blank values at the end', async () => {
555+
const user = userEvent.setup()
556+
557+
render(
558+
<DataTable
559+
data={[
560+
{
561+
id: 1,
562+
value: null,
563+
},
564+
{
565+
id: 2,
566+
value: 2,
567+
},
568+
{
569+
id: 3,
570+
value: '',
571+
},
572+
{
573+
id: 4,
574+
value: 3,
575+
},
576+
{
577+
id: 5,
578+
value: 1,
579+
},
580+
]}
581+
columns={[
582+
{
583+
header: 'Value',
584+
field: 'value',
585+
sortBy: true,
586+
},
587+
]}
588+
initialSortColumn="value"
589+
initialSortDirection="ASC"
590+
/>,
591+
)
592+
593+
const header = screen.getByRole('columnheader', {
594+
name: 'Value',
595+
})
596+
expect(header).toHaveAttribute('aria-sort', 'ascending')
597+
598+
// Change to descending
599+
await user.click(screen.getByText('Value'))
600+
601+
let rows = screen
602+
.getAllByRole('row')
603+
.filter(row => {
604+
return queryByRole(row, 'cell')
605+
})
606+
.map(row => {
607+
const cell = getByRole(row, 'cell')
608+
return cell.textContent
609+
})
610+
611+
expect(rows).toEqual(['3', '2', '1', '', ''])
612+
613+
// Change to ascending
614+
await user.click(screen.getByText('Value'))
615+
616+
rows = screen
617+
.getAllByRole('row')
618+
.filter(row => {
619+
return queryByRole(row, 'cell')
620+
})
621+
.map(row => {
622+
const cell = getByRole(row, 'cell')
623+
return cell.textContent
624+
})
625+
626+
expect(rows).toEqual(['1', '2', '3', '', ''])
627+
})
628+
554629
it('should change the sort direction on mouse click', async () => {
555630
const user = userEvent.setup()
556631
render(

src/DataTable/useTable.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ export function useTable<Data extends UniqueRow>({
116116
}
117117

118118
/**
119-
* Sort the rows of a table with the given column sort state
119+
* Sort the rows of a table with the given column sort state. If the data in the table is sparse,
120+
* blank values will be ordered last regardless of the sort direction.
120121
*/
121122
function sortRows(state: Exclude<ColumnSortState, null>) {
122123
const header = headers.find(header => {
@@ -156,12 +157,23 @@ export function useTable<Data extends UniqueRow>({
156157
const valueA = get(a, header.column.field)
157158
const valueB = get(b, header.column.field)
158159

159-
if (state.direction === SortDirection.ASC) {
160+
if (valueA && valueB) {
161+
if (state.direction === SortDirection.ASC) {
162+
// @ts-ignore todo
163+
return sortMethod(valueA, valueB)
164+
}
160165
// @ts-ignore todo
161-
return sortMethod(valueA, valueB)
166+
return sortMethod(valueB, valueA)
167+
}
168+
169+
if (valueA) {
170+
return -1
171+
}
172+
173+
if (valueB) {
174+
return 1
162175
}
163-
// @ts-ignore todo
164-
return sortMethod(valueB, valueA)
176+
return 0
165177
})
166178
})
167179
}

0 commit comments

Comments
 (0)