Skip to content

Commit a1d4291

Browse files
committed
Fix case-insensitive comparisons in useOrderedRows hook
1 parent 1a337f4 commit a1d4291

File tree

2 files changed

+33
-11
lines changed

2 files changed

+33
-11
lines changed

src/hooks/test/use-ordered-rows-test.js

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ import { useState } from 'preact/hooks';
33

44
import { useOrderedRows } from '../use-ordered-rows';
55

6+
// Some start with lowercase to test case-insensitive ordering
67
const starWarsCharacters = [
78
{ name: 'Luke Skywalker', age: 20 },
8-
{ name: 'Princess Leia Organa', age: 20 },
9+
{ name: 'leia Organa', age: 20 },
910
{ name: 'Han Solo', age: 25 },
11+
{ name: 'Baby Yoda', age: 2 },
12+
{ name: 'baby yöda The Second', age: 2 },
13+
{ name: 'young Anakin Skywalker', age: 10 },
1014
];
1115

1216
describe('useOrderedRows', () => {
@@ -81,24 +85,33 @@ describe('useOrderedRows', () => {
8185
{
8286
orderId: 'button-order-by-name-asc',
8387
expectedRows: [
88+
{ name: 'Baby Yoda', age: 2 },
89+
{ name: 'baby yöda The Second', age: 2 },
8490
{ name: 'Han Solo', age: 25 },
91+
{ name: 'leia Organa', age: 20 },
8592
{ name: 'Luke Skywalker', age: 20 },
86-
{ name: 'Princess Leia Organa', age: 20 },
93+
{ name: 'young Anakin Skywalker', age: 10 },
8794
],
8895
},
8996
{
9097
orderId: 'button-order-by-name-desc',
9198
expectedRows: [
92-
{ name: 'Princess Leia Organa', age: 20 },
99+
{ name: 'young Anakin Skywalker', age: 10 },
93100
{ name: 'Luke Skywalker', age: 20 },
101+
{ name: 'leia Organa', age: 20 },
94102
{ name: 'Han Solo', age: 25 },
103+
{ name: 'baby yöda The Second', age: 2 },
104+
{ name: 'Baby Yoda', age: 2 },
95105
],
96106
},
97107
{
98108
orderId: 'button-order-by-age-asc',
99109
expectedRows: [
110+
{ name: 'Baby Yoda', age: 2 },
111+
{ name: 'baby yöda The Second', age: 2 },
112+
{ name: 'young Anakin Skywalker', age: 10 },
100113
{ name: 'Luke Skywalker', age: 20 },
101-
{ name: 'Princess Leia Organa', age: 20 },
114+
{ name: 'leia Organa', age: 20 },
102115
{ name: 'Han Solo', age: 25 },
103116
],
104117
},
@@ -107,7 +120,10 @@ describe('useOrderedRows', () => {
107120
expectedRows: [
108121
{ name: 'Han Solo', age: 25 },
109122
{ name: 'Luke Skywalker', age: 20 },
110-
{ name: 'Princess Leia Organa', age: 20 },
123+
{ name: 'leia Organa', age: 20 },
124+
{ name: 'young Anakin Skywalker', age: 10 },
125+
{ name: 'Baby Yoda', age: 2 },
126+
{ name: 'baby yöda The Second', age: 2 },
111127
],
112128
},
113129
].forEach(({ orderId, expectedRows }) => {

src/hooks/use-ordered-rows.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ import { useMemo } from 'preact/hooks';
22

33
import type { Order } from '../types';
44

5+
const collator = new Intl.Collator(undefined, { sensitivity: 'case' });
6+
57
/**
68
* Orders a list of rows based on provided order options.
79
* Provided rows are not mutated, but a copy is returned instead.
10+
* Strings are compared using `Intl.Collator`, other types are compared using
11+
* standard JavaScript comparisons.
812
*/
913
export function useOrderedRows<Row>(
1014
rows: Row[],
@@ -15,16 +19,18 @@ export function useOrderedRows<Row>(
1519
return rows;
1620
}
1721

18-
return [...rows].sort((a, b) => {
19-
if (a[order.field] === b[order.field]) {
20-
return 0;
22+
return [...rows].sort(({ [order.field]: a }, { [order.field]: b }) => {
23+
const [x, y] = order.direction === 'ascending' ? [a, b] : [b, a];
24+
25+
if (typeof x === 'string' && typeof y === 'string') {
26+
return collator.compare(x, y);
2127
}
2228

23-
if (order.direction === 'ascending') {
24-
return a[order.field] > b[order.field] ? 1 : -1;
29+
if (x === y) {
30+
return 0;
2531
}
2632

27-
return a[order.field] > b[order.field] ? -1 : 1;
33+
return x > y ? 1 : -1;
2834
});
2935
}, [order, rows]);
3036
}

0 commit comments

Comments
 (0)