Skip to content

Commit fa662bc

Browse files
authored
feat: Add two new built in sort types (TanStack#3235)
* feat(sortTypes): Add string and number sort types New sort types better serve certain edge cases for columns with string or number values. Number strips out non decimal or numerical value from strings and only sorts what is left. String sorts strings case-insensitively until it reaches a title, and then it will do case-sensitive sort (TanStack#3137). * docs(useSortBy): Add two new sort types Add new built-in sort functions 'number' and 'string' * test(useSortBy): Increase coverage for useSortBy Add new sort types (number, string) to certain columns to achieve sufficient coverage.
1 parent 1fb9d55 commit fa662bc

File tree

3 files changed

+53
-10
lines changed

3 files changed

+53
-10
lines changed

docs/src/pages/docs/api/useSortBy.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ The following options are supported on any `Column` object passed to the `column
7575
- `sortType: String | Function(rowA: <Row>, rowB: <Row>, columnId: String, desc: Bool)`
7676
- Used to compare 2 rows of data and order them correctly.
7777
- If a **function** is passed, it must be **memoized**. The sortType function should return 1 if rowA is larger, and -1 if rowB is larger. `react-table` will take care of the rest.
78-
- String options: `basic`, `datetime`, `alphanumeric`. Defaults to `alphanumeric`.
78+
- String options: `string`, `number`, `basic`, `datetime`, `alphanumeric`. Defaults to `alphanumeric`.
7979
- The resolved function from the this string/function will be used to sort the this column's data.
8080
- If a `string` is passed, the function with that name located on either the custom `sortTypes` option or the built-in sorting types object will be used.
8181
- If a `function` is passed, it will be used.

src/plugin-hooks/tests/useSortBy.test.js

+2
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ function App({ useTableRef, initialState }) {
155155
{
156156
Header: 'First Name',
157157
accessor: 'firstName',
158+
sortType: 'string'
158159
},
159160
{
160161
Header: 'Last Name',
@@ -168,6 +169,7 @@ function App({ useTableRef, initialState }) {
168169
{
169170
Header: 'Age',
170171
accessor: 'age',
172+
sortType: 'number'
171173
},
172174
{
173175
Header: 'Visits',

src/sortTypes.js

+50-9
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ const reSplitAlphaNumeric = /([0-9]+)/gm
44
// It handles numbers, mixed alphanumeric combinations, and even
55
// null, undefined, and Infinity
66
export const alphanumeric = (rowA, rowB, columnId) => {
7-
let a = getRowValueByColumnID(rowA, columnId)
8-
let b = getRowValueByColumnID(rowB, columnId)
7+
let [a, b] = getRowValuesByColumnID(rowA, rowB, columnId)
8+
99
// Force to strings (or "" for unsupported types)
1010
a = toString(a)
1111
b = toString(b)
@@ -52,10 +52,8 @@ export const alphanumeric = (rowA, rowB, columnId) => {
5252

5353
return a.length - b.length
5454
}
55-
5655
export function datetime(rowA, rowB, columnId) {
57-
let a = getRowValueByColumnID(rowA, columnId)
58-
let b = getRowValueByColumnID(rowB, columnId)
56+
let [a, b] = getRowValuesByColumnID(rowA, rowB, columnId)
5957

6058
a = a.getTime()
6159
b = b.getTime()
@@ -64,8 +62,51 @@ export function datetime(rowA, rowB, columnId) {
6462
}
6563

6664
export function basic(rowA, rowB, columnId) {
67-
let a = getRowValueByColumnID(rowA, columnId)
68-
let b = getRowValueByColumnID(rowB, columnId)
65+
let [a, b] = getRowValuesByColumnID(rowA, rowB, columnId)
66+
67+
return compareBasic(a, b)
68+
}
69+
70+
export function string(rowA, rowB, columnId) {
71+
let [a, b] = getRowValuesByColumnID(rowA, rowB, columnId)
72+
73+
a = a.split('').filter(Boolean)
74+
b = b.split('').filter(Boolean)
75+
76+
while (a.length && b.length) {
77+
let aa = a.shift()
78+
let bb = b.shift()
79+
80+
let alower = aa.toLowerCase()
81+
let blower = bb.toLowerCase()
82+
83+
// Case insensitive comparison until characters match
84+
if (alower > blower) {
85+
return 1
86+
}
87+
if (blower > alower) {
88+
return -1
89+
}
90+
// If lowercase characters are identical
91+
if (aa > bb) {
92+
return 1
93+
}
94+
if (bb > aa) {
95+
return -1
96+
}
97+
continue
98+
}
99+
100+
return a.length - b.length
101+
}
102+
103+
export function number(rowA, rowB, columnId) {
104+
let [a, b] = getRowValuesByColumnID(rowA, rowB, columnId)
105+
106+
const replaceNonNumeric = /[^0-9.]/gi
107+
108+
a = Number(String(a).replace(replaceNonNumeric, ''))
109+
b = Number(String(b).replace(replaceNonNumeric, ''))
69110

70111
return compareBasic(a, b)
71112
}
@@ -76,8 +117,8 @@ function compareBasic(a, b) {
76117
return a === b ? 0 : a > b ? 1 : -1
77118
}
78119

79-
function getRowValueByColumnID(row, columnId) {
80-
return row.values[columnId]
120+
function getRowValuesByColumnID(row1, row2, columnId) {
121+
return [row1.values[columnId], row2.values[columnId]]
81122
}
82123

83124
function toString(a) {

0 commit comments

Comments
 (0)