-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathOrderByProvider.tsx
More file actions
86 lines (78 loc) · 3.54 KB
/
Copy pathOrderByProvider.tsx
File metadata and controls
86 lines (78 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import { type ReactNode, useContext, useMemo } from 'react'
import { ExclusiveSortContext, SortableColumnsContext } from '../contexts/DataContext.js'
import { OrderByContext, SortInfoAndActionsByColumnContext } from '../contexts/OrderByContext.js'
import { type OrderBy, toggleColumn, toggleColumnExclusive } from '../helpers/sort.js'
import { useInputState } from '../hooks/useInputState.js'
import type { HighTableProps } from '../types.js'
type Props = Pick<HighTableProps, 'orderBy' | 'onOrderByChange'> & {
/** Child components */
children: ReactNode
}
/**
* Handles sorting.
*
* Provides the global orderBy state, and a lookup table to get the state and toggle function for each column.
*
* The toggle function depends on the exclusiveSort mode (see DataContext):
* - if exclusiveSort is true, toggling a column will set it as the only sorted column, or remove it from the orderBy if it's already the only one sorted.
* - if exclusiveSort is false, toggling a column will add it to the orderBy (as the first sorted column), change its direction, or remove it from the orderBy, depending on its current state in the orderBy.
*
* The context value is memoized and won't change unless the orderBy or the sortable columns change, to avoid unnecessary re-renders of the consumers.
*/
export function OrderByProvider({ children, orderBy: controlledOrderBy, onOrderByChange }: Props) {
const exclusiveSort = useContext(ExclusiveSortContext)
const sortableColumns = useContext(SortableColumnsContext)
const [orderBy, setOrderBy] = useInputState<OrderBy>({
controlledValue: controlledOrderBy,
onChange: onOrderByChange,
initialUncontrolledValue: [],
})
// Check that all columns in state are sortable, and warn if not.
// The unsortable columns are not included in the context orderBy, so they are not sorted nor shown as ordered.
const filteredOrderBy = useMemo(() => {
// ^ memoizing this check to avoid logging warnings on every render, and only when orderBy or columnParameters change.
return orderBy.filter(({ column }) => {
if (!sortableColumns.has(column)) {
console.warn(`Column "${column}" is in orderBy but is not sortable. It will be ignored. Fix the orderBy state or mark the column as sortable in the DataFrame's columnDescriptors.`)
return false
}
return true
})
}, [orderBy, sortableColumns])
const toggleColumnOrderBy = useMemo(() => {
if (!setOrderBy) {
return undefined
}
if (exclusiveSort) {
return (columnName: string) => {
setOrderBy(toggleColumnExclusive(columnName, filteredOrderBy))
}
} else {
return (columnName: string) => {
setOrderBy(toggleColumn(columnName, filteredOrderBy))
}
}
}, [exclusiveSort, filteredOrderBy, setOrderBy])
const sortInfoAndActionsByColumn = useMemo(() => {
const sortInfoByColumn = new Map(
filteredOrderBy.map(({ column, direction }, index) => {
return [column, { direction, index }]
})
)
return new Map(
[...sortableColumns].map((column) => {
return [column, {
sortInfo: sortInfoByColumn.get(column),
toggleOrderBy: toggleColumnOrderBy ? () => { toggleColumnOrderBy(column) } : undefined,
}]
})
)
}, [sortableColumns, filteredOrderBy, toggleColumnOrderBy])
return (
<OrderByContext.Provider value={filteredOrderBy}>
<SortInfoAndActionsByColumnContext.Provider value={sortInfoAndActionsByColumn}>
{children}
</SortInfoAndActionsByColumnContext.Provider>
</OrderByContext.Provider>
)
}