Skip to content

Commit 4ba9232

Browse files
committed
Custom sorter fn now parameterizes getValue() return values in addition to row objects
1 parent 633884b commit 4ba9232

File tree

3 files changed

+95
-20
lines changed

3 files changed

+95
-20
lines changed

.changeset/funny-crabs-guess.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@careswitch/svelte-data-table': minor
3+
---
4+
5+
Custom `sorter` fn now parameterizes `getValue()` return values in addition to row objects

src/index.test.ts

+81-15
Original file line numberDiff line numberDiff line change
@@ -112,21 +112,6 @@ describe('DataTable', () => {
112112
expect(table.getSortState('age')).toBeNull();
113113
});
114114

115-
it('should handle sorting with custom sorter function', () => {
116-
const customColumns = columns.map((col) =>
117-
col.id === 'name'
118-
? {
119-
...col,
120-
sorter: (a, b) => b.name.localeCompare(a.name) // Reverse alphabetical order
121-
}
122-
: col
123-
) satisfies ColumnDef<(typeof sampleData)[0]>[];
124-
const table = new DataTable({ data: sampleData, columns: customColumns });
125-
table.toggleSort('name');
126-
expect(table.rows[0].name).toBe('Eve');
127-
expect(table.rows[4].name).toBe('Alice');
128-
});
129-
130115
it('should maintain sort state when applying filters', () => {
131116
const table = new DataTable({ data: sampleData, columns });
132117
table.toggleSort('age');
@@ -167,6 +152,87 @@ describe('DataTable', () => {
167152
});
168153
});
169154

155+
describe('Enhanced Sorting', () => {
156+
const sampleData = [
157+
{ id: 1, name: 'Alice', age: 30, score: 85 },
158+
{ id: 2, name: 'Bob', age: 25, score: 92 },
159+
{ id: 3, name: 'Charlie', age: 35, score: 78 },
160+
{ id: 4, name: 'David', age: 28, score: 88 },
161+
{ id: 5, name: 'Eve', age: 32, score: 95 }
162+
];
163+
164+
const columns: ColumnDef<(typeof sampleData)[0]>[] = [
165+
{ id: 'id', key: 'id', name: 'ID', sortable: true },
166+
{ id: 'name', key: 'name', name: 'Name', sortable: true },
167+
{ id: 'age', key: 'age', name: 'Age', sortable: true },
168+
{ id: 'score', key: 'score', name: 'Score', sortable: true },
169+
{
170+
id: 'complexSort',
171+
key: 'score',
172+
name: 'Complex Sort',
173+
sortable: true,
174+
getValue: (row) => row.score,
175+
sorter: (a, b, rowA, rowB) => {
176+
// Sort by score, but if scores are equal, sort by age
177+
if (a === b) {
178+
return rowA.age - rowB.age;
179+
}
180+
return b - a; // Descending order of scores
181+
}
182+
}
183+
];
184+
185+
it('should sort using custom sorter with access to full row data', () => {
186+
const table = new DataTable({ data: sampleData, columns });
187+
table.toggleSort('complexSort');
188+
expect(table.rows[0].name).toBe('Eve'); // Highest score
189+
expect(table.rows[1].name).toBe('Bob'); // Second highest score
190+
expect(table.rows[2].name).toBe('David'); // Third highest score
191+
expect(table.rows[3].name).toBe('Alice'); // Equal score with Charlie, but younger
192+
expect(table.rows[4].name).toBe('Charlie'); // Equal score with Alice, but older
193+
});
194+
195+
it('should handle custom sorter with reverse direction', () => {
196+
const table = new DataTable({ data: sampleData, columns });
197+
table.toggleSort('complexSort');
198+
table.toggleSort('complexSort'); // Toggle twice for descending order
199+
expect(table.rows[0].name).toBe('Charlie');
200+
expect(table.rows[1].name).toBe('Alice');
201+
expect(table.rows[2].name).toBe('David');
202+
expect(table.rows[3].name).toBe('Bob');
203+
expect(table.rows[4].name).toBe('Eve');
204+
});
205+
206+
it('should use custom sorter with initial sort', () => {
207+
const table = new DataTable({
208+
data: sampleData,
209+
columns,
210+
initialSort: 'complexSort',
211+
initialSortDirection: 'desc'
212+
});
213+
expect(table.rows[0].name).toBe('Charlie');
214+
expect(table.rows[4].name).toBe('Eve');
215+
});
216+
217+
it('should maintain custom sort when applying filters', () => {
218+
const table = new DataTable({ data: sampleData, columns });
219+
table.toggleSort('complexSort');
220+
table.setFilter('age', [30, 32, 35]); // Filter out Bob and David
221+
expect(table.rows).toHaveLength(3);
222+
expect(table.rows[0].name).toBe('Eve');
223+
expect(table.rows[1].name).toBe('Alice');
224+
expect(table.rows[2].name).toBe('Charlie');
225+
});
226+
227+
it('should handle custom sorter with all equal primary values', () => {
228+
const equalScoreData = sampleData.map((row) => ({ ...row, score: 90 }));
229+
const table = new DataTable({ data: equalScoreData, columns });
230+
table.toggleSort('complexSort');
231+
expect(table.rows[0].name).toBe('Bob'); // Youngest
232+
expect(table.rows[4].name).toBe('Charlie'); // Oldest
233+
});
234+
});
235+
170236
describe('Filtering', () => {
171237
it('should apply single column filter', () => {
172238
const table = new DataTable({ data: sampleData, columns });

src/lib/DataTable.svelte.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
type ValueGetter<T, V> = (row: T) => V;
2-
type Sorter<T> = (a: T, b: T) => number;
2+
type Sorter<T, V> = (a: V, b: V, rowA: T, rowB: T) => number;
33
type Filter<T, V> = (value: V, filterValue: V, row: T) => boolean;
44

55
export interface ColumnDef<T, V = any> {
@@ -8,7 +8,7 @@ export interface ColumnDef<T, V = any> {
88
name: string;
99
sortable?: boolean;
1010
getValue?: ValueGetter<T, V>;
11-
sorter?: Sorter<T>;
11+
sorter?: Sorter<T, V>;
1212
filter?: Filter<T, V>;
1313
}
1414

@@ -127,11 +127,15 @@ export class DataTable<T> {
127127
if (columnId && direction) {
128128
const colDef = this.#getColumnDef(columnId);
129129
this.#sortedData = [...this.#filteredData].sort((a, b) => {
130-
if (colDef && colDef.sorter) {
131-
return direction === 'asc' ? colDef.sorter(a, b) : colDef.sorter(b, a);
132-
}
133130
const aVal = this.#getValue(a, columnId);
134131
const bVal = this.#getValue(b, columnId);
132+
133+
if (colDef && colDef.sorter) {
134+
return direction === 'asc'
135+
? colDef.sorter(aVal, bVal, a, b)
136+
: colDef.sorter(bVal, aVal, b, a);
137+
}
138+
135139
if (aVal < bVal) return direction === 'asc' ? -1 : 1;
136140
if (aVal > bVal) return direction === 'asc' ? 1 : -1;
137141
return 0;

0 commit comments

Comments
 (0)