Skip to content

Commit

Permalink
feat: Add two new built in sort types (#3235)
Browse files Browse the repository at this point in the history
* 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 (#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.
  • Loading branch information
goldflag authored Apr 25, 2021
1 parent 1fb9d55 commit fa662bc
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 10 deletions.
2 changes: 1 addition & 1 deletion docs/src/pages/docs/api/useSortBy.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ The following options are supported on any `Column` object passed to the `column
- `sortType: String | Function(rowA: <Row>, rowB: <Row>, columnId: String, desc: Bool)`
- Used to compare 2 rows of data and order them correctly.
- 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.
- String options: `basic`, `datetime`, `alphanumeric`. Defaults to `alphanumeric`.
- String options: `string`, `number`, `basic`, `datetime`, `alphanumeric`. Defaults to `alphanumeric`.
- The resolved function from the this string/function will be used to sort the this column's data.
- 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.
- If a `function` is passed, it will be used.
Expand Down
2 changes: 2 additions & 0 deletions src/plugin-hooks/tests/useSortBy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ function App({ useTableRef, initialState }) {
{
Header: 'First Name',
accessor: 'firstName',
sortType: 'string'
},
{
Header: 'Last Name',
Expand All @@ -168,6 +169,7 @@ function App({ useTableRef, initialState }) {
{
Header: 'Age',
accessor: 'age',
sortType: 'number'
},
{
Header: 'Visits',
Expand Down
59 changes: 50 additions & 9 deletions src/sortTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ const reSplitAlphaNumeric = /([0-9]+)/gm
// It handles numbers, mixed alphanumeric combinations, and even
// null, undefined, and Infinity
export const alphanumeric = (rowA, rowB, columnId) => {
let a = getRowValueByColumnID(rowA, columnId)
let b = getRowValueByColumnID(rowB, columnId)
let [a, b] = getRowValuesByColumnID(rowA, rowB, columnId)

// Force to strings (or "" for unsupported types)
a = toString(a)
b = toString(b)
Expand Down Expand Up @@ -52,10 +52,8 @@ export const alphanumeric = (rowA, rowB, columnId) => {

return a.length - b.length
}

export function datetime(rowA, rowB, columnId) {
let a = getRowValueByColumnID(rowA, columnId)
let b = getRowValueByColumnID(rowB, columnId)
let [a, b] = getRowValuesByColumnID(rowA, rowB, columnId)

a = a.getTime()
b = b.getTime()
Expand All @@ -64,8 +62,51 @@ export function datetime(rowA, rowB, columnId) {
}

export function basic(rowA, rowB, columnId) {
let a = getRowValueByColumnID(rowA, columnId)
let b = getRowValueByColumnID(rowB, columnId)
let [a, b] = getRowValuesByColumnID(rowA, rowB, columnId)

return compareBasic(a, b)
}

export function string(rowA, rowB, columnId) {
let [a, b] = getRowValuesByColumnID(rowA, rowB, columnId)

a = a.split('').filter(Boolean)
b = b.split('').filter(Boolean)

while (a.length && b.length) {
let aa = a.shift()
let bb = b.shift()

let alower = aa.toLowerCase()
let blower = bb.toLowerCase()

// Case insensitive comparison until characters match
if (alower > blower) {
return 1
}
if (blower > alower) {
return -1
}
// If lowercase characters are identical
if (aa > bb) {
return 1
}
if (bb > aa) {
return -1
}
continue
}

return a.length - b.length
}

export function number(rowA, rowB, columnId) {
let [a, b] = getRowValuesByColumnID(rowA, rowB, columnId)

const replaceNonNumeric = /[^0-9.]/gi

a = Number(String(a).replace(replaceNonNumeric, ''))
b = Number(String(b).replace(replaceNonNumeric, ''))

return compareBasic(a, b)
}
Expand All @@ -76,8 +117,8 @@ function compareBasic(a, b) {
return a === b ? 0 : a > b ? 1 : -1
}

function getRowValueByColumnID(row, columnId) {
return row.values[columnId]
function getRowValuesByColumnID(row1, row2, columnId) {
return [row1.values[columnId], row2.values[columnId]]
}

function toString(a) {
Expand Down

1 comment on commit fa662bc

@vercel
Copy link

@vercel vercel bot commented on fa662bc Apr 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.