react-table
Version:
Hooks for building lightweight, fast and extendable datagrids for React
136 lines (107 loc) • 2.89 kB
JavaScript
const reSplitAlphaNumeric = /([0-9]+)/gm
// Mixed sorting is slow, but very inclusive of many edge cases.
// It handles numbers, mixed alphanumeric combinations, and even
// null, undefined, and Infinity
export const alphanumeric = (rowA, rowB, columnId) => {
let [a, b] = getRowValuesByColumnID(rowA, rowB, columnId)
// Force to strings (or "" for unsupported types)
a = toString(a)
b = toString(b)
// Split on number groups, but keep the delimiter
// Then remove falsey split values
a = a.split(reSplitAlphaNumeric).filter(Boolean)
b = b.split(reSplitAlphaNumeric).filter(Boolean)
// While
while (a.length && b.length) {
let aa = a.shift()
let bb = b.shift()
const an = parseInt(aa, 10)
const bn = parseInt(bb, 10)
const combo = [an, bn].sort()
// Both are string
if (isNaN(combo[0])) {
if (aa > bb) {
return 1
}
if (bb > aa) {
return -1
}
continue
}
// One is a string, one is a number
if (isNaN(combo[1])) {
return isNaN(an) ? -1 : 1
}
// Both are numbers
if (an > bn) {
return 1
}
if (bn > an) {
return -1
}
}
return a.length - b.length
}
export function datetime(rowA, rowB, columnId) {
let [a, b] = getRowValuesByColumnID(rowA, rowB, columnId)
a = a.getTime()
b = b.getTime()
return compareBasic(a, b)
}
export function basic(rowA, 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)
}
// Utils
function compareBasic(a, b) {
return a === b ? 0 : a > b ? 1 : -1
}
function getRowValuesByColumnID(row1, row2, columnId) {
return [row1.values[columnId], row2.values[columnId]]
}
function toString(a) {
if (typeof a === 'number') {
if (isNaN(a) || a === Infinity || a === -Infinity) {
return ''
}
return String(a)
}
if (typeof a === 'string') {
return a
}
return ''
}