@tanstack/table-core 8.0.0-alpha.67 → 8.0.0-alpha.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/aggregationFns.js +25 -37
- package/build/cjs/aggregationFns.js.map +1 -1
- package/build/cjs/core.js +167 -46
- package/build/cjs/core.js.map +1 -1
- package/build/cjs/createTable.js +24 -40
- package/build/cjs/createTable.js.map +1 -1
- package/build/cjs/features/Cells.js +28 -34
- package/build/cjs/features/Cells.js.map +1 -1
- package/build/cjs/features/ColumnSizing.js +102 -116
- package/build/cjs/features/ColumnSizing.js.map +1 -1
- package/build/cjs/features/Columns.js +52 -79
- package/build/cjs/features/Columns.js.map +1 -1
- package/build/cjs/features/Expanding.js +49 -58
- package/build/cjs/features/Expanding.js.map +1 -1
- package/build/cjs/features/Filters.js +98 -193
- package/build/cjs/features/Filters.js.map +1 -1
- package/build/cjs/features/Grouping.js +53 -71
- package/build/cjs/features/Grouping.js.map +1 -1
- package/build/cjs/features/Headers.js +109 -165
- package/build/cjs/features/Headers.js.map +1 -1
- package/build/cjs/features/Ordering.js +31 -43
- package/build/cjs/features/Ordering.js.map +1 -1
- package/build/cjs/features/Pagination.js +79 -82
- package/build/cjs/features/Pagination.js.map +1 -1
- package/build/cjs/features/Pinning.js +71 -125
- package/build/cjs/features/Pinning.js.map +1 -1
- package/build/cjs/features/RowSelection.js +93 -112
- package/build/cjs/features/RowSelection.js.map +1 -1
- package/build/cjs/features/Rows.js +32 -22
- package/build/cjs/features/Rows.js.map +1 -1
- package/build/cjs/features/Sorting.js +54 -73
- package/build/cjs/features/Sorting.js.map +1 -1
- package/build/cjs/features/Visibility.js +47 -86
- package/build/cjs/features/Visibility.js.map +1 -1
- package/build/cjs/filterFns.js +48 -72
- package/build/cjs/filterFns.js.map +1 -1
- package/build/cjs/index.js +13 -13
- package/build/cjs/sortingFns.js +21 -21
- package/build/cjs/sortingFns.js.map +1 -1
- package/build/cjs/utils/filterRowsUtils.js +49 -55
- package/build/cjs/utils/filterRowsUtils.js.map +1 -1
- package/build/cjs/utils/getCoreRowModel.js +98 -0
- package/build/cjs/utils/getCoreRowModel.js.map +1 -0
- package/build/cjs/utils/getExpandedRowModel.js +17 -21
- package/build/cjs/utils/getExpandedRowModel.js.map +1 -1
- package/build/cjs/utils/getFacetedMinMaxValues.js +48 -0
- package/build/cjs/utils/getFacetedMinMaxValues.js.map +1 -0
- package/build/cjs/utils/getFacetedRowModel.js +50 -0
- package/build/cjs/utils/getFacetedRowModel.js.map +1 -0
- package/build/cjs/utils/getFacetedUniqueValues.js +48 -0
- package/build/cjs/utils/getFacetedUniqueValues.js.map +1 -0
- package/build/cjs/utils/getFilteredRowModel.js +130 -0
- package/build/cjs/utils/getFilteredRowModel.js.map +1 -0
- package/build/cjs/utils/getGroupedRowModel.js +126 -136
- package/build/cjs/utils/getGroupedRowModel.js.map +1 -1
- package/build/cjs/utils/getPaginationRowModel.js +39 -39
- package/build/cjs/utils/getPaginationRowModel.js.map +1 -1
- package/build/cjs/utils/getSortedRowModel.js +112 -0
- package/build/cjs/utils/getSortedRowModel.js.map +1 -0
- package/build/cjs/utils.js +36 -207
- package/build/cjs/utils.js.map +1 -1
- package/build/esm/index.js +1778 -2347
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +421 -481
- package/build/types/core.d.ts +3 -5
- package/build/types/features/Cells.d.ts +1 -1
- package/build/types/features/ColumnSizing.d.ts +2 -2
- package/build/types/features/Columns.d.ts +1 -1
- package/build/types/features/Expanding.d.ts +1 -1
- package/build/types/features/Filters.d.ts +12 -7
- package/build/types/features/Grouping.d.ts +5 -4
- package/build/types/features/Ordering.d.ts +1 -1
- package/build/types/features/Pagination.d.ts +4 -4
- package/build/types/features/Pinning.d.ts +1 -1
- package/build/types/features/RowSelection.d.ts +1 -1
- package/build/types/features/Rows.d.ts +4 -3
- package/build/types/features/Sorting.d.ts +2 -1
- package/build/types/features/Visibility.d.ts +1 -0
- package/build/types/index.d.ts +6 -4
- package/build/types/types.d.ts +3 -13
- package/build/types/utils/filterRowsUtils.d.ts +3 -3
- package/build/types/utils/getCoreRowModel.d.ts +2 -0
- package/build/types/utils/getFacetedMinMaxValues.d.ts +2 -0
- package/build/types/utils/getFacetedRowModel.d.ts +2 -0
- package/build/types/utils/getFacetedUniqueValues.d.ts +2 -0
- package/build/types/utils/{getCoreRowModelSync.d.ts → getFilteredRowModel.d.ts} +1 -1
- package/build/types/utils/getGroupedRowModel.d.ts +1 -1
- package/build/types/utils/getSortedRowModel.d.ts +2 -0
- package/build/types/utils.d.ts +1 -17
- package/build/umd/index.development.js +1779 -2350
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +1 -1
- package/src/core.ts +197 -45
- package/src/features/Cells.ts +7 -11
- package/src/features/ColumnSizing.ts +27 -19
- package/src/features/Columns.ts +4 -8
- package/src/features/Expanding.ts +5 -3
- package/src/features/Filters.ts +105 -162
- package/src/features/Grouping.ts +21 -23
- package/src/features/Ordering.ts +5 -3
- package/src/features/Pagination.ts +32 -19
- package/src/features/Pinning.ts +13 -7
- package/src/features/RowSelection.ts +5 -3
- package/src/features/Rows.ts +21 -6
- package/src/features/Sorting.ts +14 -12
- package/src/features/Visibility.ts +7 -0
- package/src/filterFns.ts +9 -9
- package/src/index.ts +12 -4
- package/src/sortingFns.ts +11 -11
- package/src/types.ts +3 -16
- package/src/utils/filterRowsUtils.ts +47 -68
- package/src/utils/{getCoreRowModelSync.ts → getCoreRowModel.ts} +2 -8
- package/src/utils/getFacetedMinMaxValues.ts +37 -0
- package/src/utils/getFacetedRowModel.ts +50 -0
- package/src/utils/getFacetedUniqueValues.ts +37 -0
- package/src/utils/{getFilteredRowModelSync.ts → getFilteredRowModel.ts} +29 -20
- package/src/utils/getGroupedRowModel.ts +52 -61
- package/src/utils/{getSortedRowModelSync.ts → getSortedRowModel.ts} +3 -3
- package/src/utils.ts +28 -236
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -112
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
- package/build/cjs/utils/getCoreRowModelAsync.js +0 -125
- package/build/cjs/utils/getCoreRowModelAsync.js.map +0 -1
- package/build/cjs/utils/getCoreRowModelSync.js +0 -102
- package/build/cjs/utils/getCoreRowModelSync.js.map +0 -1
- package/build/cjs/utils/getFilteredRowModelSync.js +0 -125
- package/build/cjs/utils/getFilteredRowModelSync.js.map +0 -1
- package/build/cjs/utils/getSortedRowModelSync.js +0 -118
- package/build/cjs/utils/getSortedRowModelSync.js.map +0 -1
- package/build/types/utils/getCoreRowModelAsync.d.ts +0 -4
- package/build/types/utils/getFilteredRowModelAsync.d.ts +0 -4
- package/build/types/utils/getFilteredRowModelSync.d.ts +0 -2
- package/build/types/utils/getSortedRowModelAsync.d.ts +0 -13
- package/build/types/utils/getSortedRowModelSync.d.ts +0 -2
- package/src/utils/getCoreRowModelAsync.ts +0 -104
- package/src/utils/getFilteredRowModelAsync.ts +0 -157
- package/src/utils/getSortedRowModelAsync.ts +0 -200
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { TableInstance, TableGenerics } from '../types'
|
|
2
|
+
import { memo } from '../utils'
|
|
3
|
+
|
|
4
|
+
export function getFacetedUniqueValues<TGenerics extends TableGenerics>(): (
|
|
5
|
+
instance: TableInstance<TGenerics>,
|
|
6
|
+
columnId: string
|
|
7
|
+
) => () => Map<any, number> {
|
|
8
|
+
return (instance, columnId) =>
|
|
9
|
+
memo(
|
|
10
|
+
() => [instance.getColumn(columnId).getFacetedRowModel()],
|
|
11
|
+
facetedRowModel => {
|
|
12
|
+
let facetedUniqueValues = new Map<any, number>()
|
|
13
|
+
|
|
14
|
+
for (let i = 0; i < facetedRowModel.flatRows.length; i++) {
|
|
15
|
+
const value = facetedRowModel.flatRows[i]?.getValue(columnId)
|
|
16
|
+
|
|
17
|
+
if (facetedUniqueValues.has(value)) {
|
|
18
|
+
facetedUniqueValues.set(
|
|
19
|
+
value,
|
|
20
|
+
(facetedUniqueValues.get(value) ?? 0) + 1
|
|
21
|
+
)
|
|
22
|
+
} else {
|
|
23
|
+
facetedUniqueValues.set(value, 1)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return facetedUniqueValues
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
key:
|
|
31
|
+
process.env.NODE_ENV === 'development' &&
|
|
32
|
+
'getFacetedUniqueValues_' + columnId,
|
|
33
|
+
debug: () => instance.options.debugAll ?? instance.options.debugTable,
|
|
34
|
+
onChange: () => {},
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ColumnFilter,
|
|
3
|
-
FilterFn,
|
|
4
|
-
ResolvedColumnFilter,
|
|
5
|
-
} from '../features/Filters'
|
|
1
|
+
import { ResolvedColumnFilter } from '../features/Filters'
|
|
6
2
|
import { TableInstance, RowModel, TableGenerics, Row } from '../types'
|
|
7
3
|
import { memo } from '../utils'
|
|
8
4
|
import { filterRows } from './filterRowsUtils'
|
|
9
5
|
|
|
10
|
-
export function
|
|
6
|
+
export function getFilteredRowModel<TGenerics extends TableGenerics>(): (
|
|
11
7
|
instance: TableInstance<TGenerics>
|
|
12
8
|
) => () => RowModel<TGenerics> {
|
|
13
9
|
return instance =>
|
|
@@ -83,34 +79,38 @@ export function getFilteredRowModelSync<TGenerics extends TableGenerics>(): (
|
|
|
83
79
|
})
|
|
84
80
|
}
|
|
85
81
|
|
|
82
|
+
let currentColumnFilter
|
|
83
|
+
let currentGlobalFilter
|
|
84
|
+
|
|
86
85
|
// Flag the prefiltered row model with each filter state
|
|
87
86
|
for (let j = 0; j < rowModel.flatRows.length; j++) {
|
|
88
|
-
const row = rowModel.flatRows[j]
|
|
87
|
+
const row = rowModel.flatRows[j]!
|
|
89
88
|
|
|
90
89
|
row.columnFilterMap = {}
|
|
91
90
|
|
|
92
91
|
if (resolvedColumnFilters.length) {
|
|
93
92
|
for (let i = 0; i < resolvedColumnFilters.length; i++) {
|
|
94
|
-
|
|
93
|
+
currentColumnFilter = resolvedColumnFilters[i]!
|
|
95
94
|
|
|
96
95
|
// Tag the row with the column filter state
|
|
97
|
-
row.columnFilterMap[
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
row.columnFilterMap[currentColumnFilter.id] =
|
|
97
|
+
currentColumnFilter.filterFn(
|
|
98
|
+
row,
|
|
99
|
+
currentColumnFilter.id,
|
|
100
|
+
currentColumnFilter.resolvedValue
|
|
101
|
+
)
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
if (resolvedGlobalFilters.length) {
|
|
106
106
|
for (let i = 0; i < resolvedGlobalFilters.length; i++) {
|
|
107
|
-
|
|
107
|
+
currentGlobalFilter = resolvedGlobalFilters[i]!
|
|
108
108
|
// Tag the row with the first truthy global filter state
|
|
109
109
|
if (
|
|
110
|
-
|
|
110
|
+
currentGlobalFilter.filterFn(
|
|
111
111
|
row,
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
currentGlobalFilter.id,
|
|
113
|
+
currentGlobalFilter.resolvedValue
|
|
114
114
|
)
|
|
115
115
|
) {
|
|
116
116
|
row.columnFilterMap.__global__ = true
|
|
@@ -124,12 +124,21 @@ export function getFilteredRowModelSync<TGenerics extends TableGenerics>(): (
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
const filterRowsImpl = (row: Row<TGenerics>) => {
|
|
128
|
+
// Horizontally filter rows through each column
|
|
129
|
+
for (let i = 0; i < filterableIds.length; i++) {
|
|
130
|
+
if (row.columnFilterMap[filterableIds[i]!] === false) {
|
|
131
|
+
return false
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return true
|
|
135
|
+
}
|
|
136
|
+
|
|
127
137
|
// Filter final rows using all of the active filters
|
|
128
|
-
return filterRows(rowModel.rows,
|
|
138
|
+
return filterRows(rowModel.rows, filterRowsImpl, instance)
|
|
129
139
|
},
|
|
130
140
|
{
|
|
131
|
-
key:
|
|
132
|
-
process.env.NODE_ENV === 'development' && 'getFilteredRowModelSync',
|
|
141
|
+
key: process.env.NODE_ENV === 'development' && 'getFilteredRowModel',
|
|
133
142
|
debug: () => instance.options.debugAll ?? instance.options.debugTable,
|
|
134
143
|
onChange: () => {
|
|
135
144
|
instance.queue(() => {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { CoreRow } from '../features/Rows'
|
|
1
2
|
import { TableInstance, Row, RowModel, TableGenerics } from '../types'
|
|
2
3
|
import { flattenBy, memo } from '../utils'
|
|
3
4
|
|
|
4
|
-
export function
|
|
5
|
+
export function getGroupedRowModel<TGenerics extends TableGenerics>(): (
|
|
5
6
|
instance: TableInstance<TGenerics>
|
|
6
7
|
) => () => RowModel<TGenerics> {
|
|
7
8
|
return instance =>
|
|
@@ -17,56 +18,6 @@ export function getGroupedRowModelSync<TGenerics extends TableGenerics>(): (
|
|
|
17
18
|
instance.getColumn(columnId)
|
|
18
19
|
)
|
|
19
20
|
|
|
20
|
-
// Find the columns that can or are aggregating
|
|
21
|
-
// Uses each column to aggregate rows into a single value
|
|
22
|
-
const aggregateRowsToValues = (
|
|
23
|
-
leafRows: Row<TGenerics>[],
|
|
24
|
-
groupedRows: Row<TGenerics>[],
|
|
25
|
-
depth: number
|
|
26
|
-
) => {
|
|
27
|
-
const values: Record<string, unknown> = {}
|
|
28
|
-
|
|
29
|
-
instance.getAllLeafColumns().forEach(column => {
|
|
30
|
-
// Don't aggregate columns that are in the grouping
|
|
31
|
-
if (existingGrouping.includes(column.id)) {
|
|
32
|
-
values[column.id] = groupedRows[0]
|
|
33
|
-
? groupedRows[0].values[column.id]
|
|
34
|
-
: null
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Aggregate the values
|
|
39
|
-
const aggregateFn = instance.getColumnAggregationFn(column.id)
|
|
40
|
-
|
|
41
|
-
if (aggregateFn) {
|
|
42
|
-
values[column.id] = aggregateFn(
|
|
43
|
-
() =>
|
|
44
|
-
leafRows.map(row => {
|
|
45
|
-
let columnValue = row.values[column.id]
|
|
46
|
-
|
|
47
|
-
if (!depth && column.aggregateValue) {
|
|
48
|
-
columnValue = column.aggregateValue(columnValue)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return columnValue
|
|
52
|
-
}),
|
|
53
|
-
() => groupedRows.map(row => row.values[column.id])
|
|
54
|
-
)
|
|
55
|
-
} else if (column.aggregationFn) {
|
|
56
|
-
console.info({ column })
|
|
57
|
-
throw new Error(
|
|
58
|
-
process.env.NODE_ENV !== 'production'
|
|
59
|
-
? `Table: Invalid column.aggregateType option for column listed above`
|
|
60
|
-
: ''
|
|
61
|
-
)
|
|
62
|
-
} else {
|
|
63
|
-
values[column.id] = null
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
return values
|
|
68
|
-
}
|
|
69
|
-
|
|
70
21
|
const groupedFlatRows: Row<TGenerics>[] = []
|
|
71
22
|
const groupedRowsById: Record<string, Row<TGenerics>> = {}
|
|
72
23
|
// const onlyGroupedFlatRows: Row[] = [];
|
|
@@ -104,21 +55,61 @@ export function getGroupedRowModelSync<TGenerics extends TableGenerics>(): (
|
|
|
104
55
|
? flattenBy(groupedRows, row => row.subRows)
|
|
105
56
|
: groupedRows
|
|
106
57
|
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
const row = instance.createRow(
|
|
110
|
-
id,
|
|
111
|
-
undefined,
|
|
112
|
-
index,
|
|
113
|
-
depth,
|
|
114
|
-
values
|
|
115
|
-
)
|
|
58
|
+
const row = instance.createRow(id, undefined, index, depth)
|
|
116
59
|
|
|
117
60
|
Object.assign(row, {
|
|
118
61
|
groupingColumnId: columnId,
|
|
119
62
|
groupingValue,
|
|
120
63
|
subRows,
|
|
121
64
|
leafRows,
|
|
65
|
+
getValue: (columnId: string) => {
|
|
66
|
+
// Don't aggregate columns that are in the grouping
|
|
67
|
+
if (existingGrouping.includes(columnId)) {
|
|
68
|
+
if (row.valuesCache.hasOwnProperty(columnId)) {
|
|
69
|
+
return row.valuesCache[columnId]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (groupedRows[0]) {
|
|
73
|
+
row.valuesCache[columnId] =
|
|
74
|
+
groupedRows[0].getValue(columnId) ?? undefined
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return row.valuesCache[columnId]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (row.groupingValuesCache.hasOwnProperty(columnId)) {
|
|
81
|
+
return row.groupingValuesCache[columnId]
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Aggregate the values
|
|
85
|
+
const column = instance.getColumn(columnId)
|
|
86
|
+
const aggregateFn = column.getColumnAggregationFn()
|
|
87
|
+
|
|
88
|
+
if (aggregateFn) {
|
|
89
|
+
row.groupingValuesCache[columnId] = aggregateFn(
|
|
90
|
+
() =>
|
|
91
|
+
leafRows.map(row => {
|
|
92
|
+
let columnValue = row.getValue(columnId)
|
|
93
|
+
|
|
94
|
+
if (!depth && column.aggregateValue) {
|
|
95
|
+
columnValue = column.aggregateValue(columnValue)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return columnValue
|
|
99
|
+
}),
|
|
100
|
+
() => groupedRows.map(row => row.getValue(columnId))
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
return row.groupingValuesCache[columnId]
|
|
104
|
+
} else if (column.aggregationFn) {
|
|
105
|
+
console.info({ column })
|
|
106
|
+
throw new Error(
|
|
107
|
+
process.env.NODE_ENV !== 'production'
|
|
108
|
+
? `Table: Invalid column.aggregateType option for column listed above`
|
|
109
|
+
: ''
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
},
|
|
122
113
|
})
|
|
123
114
|
|
|
124
115
|
subRows.forEach(subRow => {
|
|
@@ -180,7 +171,7 @@ function groupBy<TGenerics extends TableGenerics>(
|
|
|
180
171
|
const groupMap = new Map<any, Row<TGenerics>[]>()
|
|
181
172
|
|
|
182
173
|
return rows.reduce((map, row) => {
|
|
183
|
-
const resKey = `${row.
|
|
174
|
+
const resKey = `${row.getValue(columnId)}`
|
|
184
175
|
const previous = map.get(resKey)
|
|
185
176
|
if (!previous) {
|
|
186
177
|
map.set(resKey, [row])
|
|
@@ -2,7 +2,7 @@ import { TableInstance, Row, RowModel, TableGenerics } from '../types'
|
|
|
2
2
|
import { SortingFn } from '../features/Sorting'
|
|
3
3
|
import { memo } from '../utils'
|
|
4
4
|
|
|
5
|
-
export function
|
|
5
|
+
export function getSortedRowModel<TGenerics extends TableGenerics>(): (
|
|
6
6
|
instance: TableInstance<TGenerics>
|
|
7
7
|
) => () => RowModel<TGenerics> {
|
|
8
8
|
return instance =>
|
|
@@ -53,8 +53,8 @@ export function getSortedRowModelSync<TGenerics extends TableGenerics>(): (
|
|
|
53
53
|
const isDesc = sortEntry?.desc ?? false
|
|
54
54
|
|
|
55
55
|
if (columnInfo.sortUndefined) {
|
|
56
|
-
const aValue = rowA.
|
|
57
|
-
const bValue = rowB.
|
|
56
|
+
const aValue = rowA.getValue(sortEntry.id)
|
|
57
|
+
const bValue = rowB.getValue(sortEntry.id)
|
|
58
58
|
|
|
59
59
|
const aUndefined = typeof aValue === 'undefined'
|
|
60
60
|
const bUndefined = typeof bValue === 'undefined'
|
package/src/utils.ts
CHANGED
|
@@ -21,35 +21,6 @@ export function noop() {
|
|
|
21
21
|
//
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
export function getBatchGroups<T>(arr: T[], count: number) {
|
|
25
|
-
const groups: { start: number; end: number; items: T[] }[] = [
|
|
26
|
-
{
|
|
27
|
-
start: 0,
|
|
28
|
-
end: count - 1,
|
|
29
|
-
items: [],
|
|
30
|
-
},
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
let groupIndex = 0
|
|
34
|
-
let group = groups[groupIndex]
|
|
35
|
-
|
|
36
|
-
for (let i = 0; i < arr.length; i++) {
|
|
37
|
-
if (i > group.end) {
|
|
38
|
-
groupIndex++
|
|
39
|
-
groups[groupIndex] = {
|
|
40
|
-
start: i,
|
|
41
|
-
end: i + count - 1,
|
|
42
|
-
items: [],
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
group = groups[groupIndex]
|
|
46
|
-
const item = arr[i]
|
|
47
|
-
group.items.push(item)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return groups
|
|
51
|
-
}
|
|
52
|
-
|
|
53
24
|
export function makeStateUpdater(key: keyof TableState, instance: unknown) {
|
|
54
25
|
return (updater: Updater<any>) => {
|
|
55
26
|
;(instance as any).setState(<TTableState>(old: TTableState) => {
|
|
@@ -94,7 +65,7 @@ export function memo<TDeps extends readonly any[], TResult>(
|
|
|
94
65
|
opts: {
|
|
95
66
|
key: any
|
|
96
67
|
debug?: () => any
|
|
97
|
-
onChange?: (result: TResult
|
|
68
|
+
onChange?: (result: TResult) => void
|
|
98
69
|
}
|
|
99
70
|
): () => TResult {
|
|
100
71
|
let deps: any[] = []
|
|
@@ -110,225 +81,46 @@ export function memo<TDeps extends readonly any[], TResult>(
|
|
|
110
81
|
newDeps.length !== deps.length ||
|
|
111
82
|
newDeps.some((dep: any, index: number) => deps[index] !== dep)
|
|
112
83
|
|
|
113
|
-
if (depsChanged) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
84
|
+
if (!depsChanged) {
|
|
85
|
+
return result!
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
deps = newDeps
|
|
89
|
+
|
|
90
|
+
let resultTime: number
|
|
91
|
+
if (opts.key && opts.debug) resultTime = Date.now()
|
|
92
|
+
|
|
93
|
+
result = fn(...newDeps)
|
|
94
|
+
opts?.onChange?.(result)
|
|
120
95
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const resultFpsPercentage = resultEndTime / 16
|
|
96
|
+
if (opts.key && opts.debug) {
|
|
97
|
+
if (opts?.debug()) {
|
|
98
|
+
const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100
|
|
99
|
+
const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100
|
|
100
|
+
const resultFpsPercentage = resultEndTime / 16
|
|
127
101
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
return str
|
|
102
|
+
const pad = (str: number | string, num: number) => {
|
|
103
|
+
str = String(str)
|
|
104
|
+
while (str.length < num) {
|
|
105
|
+
str = ' ' + str
|
|
134
106
|
}
|
|
107
|
+
return str
|
|
108
|
+
}
|
|
135
109
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
110
|
+
console.info(
|
|
111
|
+
`%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,
|
|
112
|
+
`
|
|
139
113
|
font-size: .6rem;
|
|
140
114
|
font-weight: bold;
|
|
141
115
|
color: hsl(${Math.max(
|
|
142
116
|
0,
|
|
143
117
|
Math.min(120 - 120 * resultFpsPercentage, 120)
|
|
144
118
|
)}deg 100% 31%);`,
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
length: `${deps.length} -> ${newDeps.length}`,
|
|
148
|
-
...newDeps
|
|
149
|
-
.map((_, index) => {
|
|
150
|
-
if (deps[index] !== newDeps[index]) {
|
|
151
|
-
return [index, deps[index], newDeps[index]]
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return false
|
|
155
|
-
})
|
|
156
|
-
.filter(Boolean)
|
|
157
|
-
.reduce(
|
|
158
|
-
(accu, [a, b]: any) => ({
|
|
159
|
-
...accu,
|
|
160
|
-
[a]: b,
|
|
161
|
-
}),
|
|
162
|
-
{}
|
|
163
|
-
),
|
|
164
|
-
}
|
|
165
|
-
)
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
oldResult = undefined
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return result!
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
type WorkFn = () => void
|
|
177
|
-
|
|
178
|
-
export function incrementalMemo<TDeps extends readonly any[], TResult>(
|
|
179
|
-
getDeps: () => [...TDeps],
|
|
180
|
-
getInitialValue: (...args: NoInfer<[...TDeps]>) => TResult,
|
|
181
|
-
schedule: (
|
|
182
|
-
...args: NoInfer<[...TDeps]>
|
|
183
|
-
) => (resultRef: {
|
|
184
|
-
current: TResult
|
|
185
|
-
}) => (scheduler: (workFn: WorkFn) => void) => void,
|
|
186
|
-
opts: {
|
|
187
|
-
key: any
|
|
188
|
-
onProgress: (
|
|
189
|
-
progress: number,
|
|
190
|
-
nextResult: TResult,
|
|
191
|
-
result?: TResult
|
|
192
|
-
) => void
|
|
193
|
-
onChange: (result: TResult, previousResult?: TResult) => void
|
|
194
|
-
initialSync?: boolean
|
|
195
|
-
timeout?: number
|
|
196
|
-
debug?: () => any
|
|
197
|
-
}
|
|
198
|
-
): () => TResult {
|
|
199
|
-
let oldDeps: any[]
|
|
200
|
-
let deps: any[]
|
|
201
|
-
let result: TResult | undefined
|
|
202
|
-
let nextResultRef: { current: TResult }
|
|
203
|
-
let tasks: WorkFn[] = []
|
|
204
|
-
let totalTaskCount = 0
|
|
205
|
-
let resultStartTime: number
|
|
206
|
-
let batchIndex = 0
|
|
207
|
-
let progress = 0
|
|
208
|
-
let working = false
|
|
209
|
-
let callback: ReturnType<typeof requestIdleCallback>
|
|
210
|
-
|
|
211
|
-
const timeout = opts.timeout ?? 100
|
|
212
|
-
|
|
213
|
-
const onProgress = (latestResult: TResult, previousResult?: TResult) => {
|
|
214
|
-
progress = 1 - tasks.length / totalTaskCount
|
|
215
|
-
opts.onProgress(progress, latestResult, previousResult)
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return () => {
|
|
219
|
-
const scheduleFn = (workFn: WorkFn) => {
|
|
220
|
-
totalTaskCount++
|
|
221
|
-
tasks.push(workFn)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const newDeps = getDeps()
|
|
225
|
-
|
|
226
|
-
let first = false
|
|
227
|
-
|
|
228
|
-
if (!deps) {
|
|
229
|
-
first = true
|
|
230
|
-
deps = []
|
|
231
|
-
result = getInitialValue(...newDeps)
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
const depsChanged =
|
|
235
|
-
newDeps.length !== deps.length ||
|
|
236
|
-
newDeps.some((dep: any, index: number) => deps[index] !== dep)
|
|
237
|
-
|
|
238
|
-
if (depsChanged) {
|
|
239
|
-
cancelIdleCallback(callback)
|
|
240
|
-
oldDeps = deps
|
|
241
|
-
deps = newDeps
|
|
242
|
-
totalTaskCount = 0
|
|
243
|
-
tasks = []
|
|
244
|
-
nextResultRef = { current: getInitialValue(...newDeps) }
|
|
245
|
-
resultStartTime = Date.now()
|
|
246
|
-
schedule(...newDeps)(nextResultRef)(scheduleFn)
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const commitResult = () => {
|
|
250
|
-
cancelIdleCallback(callback)
|
|
251
|
-
|
|
252
|
-
if (opts.key && opts.debug) {
|
|
253
|
-
if (opts?.debug()) {
|
|
254
|
-
const resultEndTime =
|
|
255
|
-
Math.round((Date.now() - resultStartTime!) * 100) / 100
|
|
256
|
-
const resultFpsPercentage = resultEndTime / batchIndex / 16
|
|
257
|
-
|
|
258
|
-
console.info(
|
|
259
|
-
`%c⏱ ${resultEndTime} ms / ${batchIndex} tasks = ${Math.round(
|
|
260
|
-
resultEndTime / batchIndex
|
|
261
|
-
)} ms/task`,
|
|
262
|
-
`
|
|
263
|
-
font-size: .6rem;
|
|
264
|
-
font-weight: bold;
|
|
265
|
-
color: hsl(${Math.max(
|
|
266
|
-
0,
|
|
267
|
-
Math.min(120 - 120 * resultFpsPercentage, 120)
|
|
268
|
-
)}deg 100% 31%);`,
|
|
269
|
-
opts?.key,
|
|
270
|
-
{
|
|
271
|
-
length: `${oldDeps.length} -> ${deps.length}`,
|
|
272
|
-
...deps
|
|
273
|
-
.map((_, index) => {
|
|
274
|
-
if (oldDeps[index] !== deps[index]) {
|
|
275
|
-
return [index, oldDeps[index], deps[index]]
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return false
|
|
279
|
-
})
|
|
280
|
-
.filter(Boolean)
|
|
281
|
-
.reduce(
|
|
282
|
-
(accu, [a, b]: any) => ({
|
|
283
|
-
...accu,
|
|
284
|
-
[a]: b,
|
|
285
|
-
}),
|
|
286
|
-
{}
|
|
287
|
-
),
|
|
288
|
-
}
|
|
289
|
-
)
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
working = false
|
|
294
|
-
let previousResult = result
|
|
295
|
-
result = nextResultRef.current
|
|
296
|
-
onProgress(result, previousResult)
|
|
297
|
-
opts.onChange(result, previousResult)
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
if (opts.initialSync && first) {
|
|
301
|
-
batchIndex = 1
|
|
302
|
-
first = false
|
|
303
|
-
for (let i = 0; i < tasks.length; i++) {
|
|
304
|
-
tasks[i]()
|
|
305
|
-
}
|
|
306
|
-
tasks = []
|
|
307
|
-
commitResult()
|
|
308
|
-
} else if (!working && tasks.length) {
|
|
309
|
-
cancelIdleCallback(callback)
|
|
310
|
-
working = true
|
|
311
|
-
batchIndex = 0
|
|
312
|
-
|
|
313
|
-
const workLoop = (deadline: any) => {
|
|
314
|
-
while (tasks.length && deadline.timeRemaining() > 0) {
|
|
315
|
-
tasks.shift()!()
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (!tasks.length) {
|
|
319
|
-
commitResult()
|
|
320
|
-
} else {
|
|
321
|
-
++batchIndex
|
|
322
|
-
onProgress(nextResultRef.current, result)
|
|
323
|
-
callback = requestIdleCallback(workLoop, { timeout })
|
|
324
|
-
}
|
|
119
|
+
opts?.key
|
|
120
|
+
)
|
|
325
121
|
}
|
|
326
|
-
|
|
327
|
-
callback = requestIdleCallback(workLoop, { timeout })
|
|
328
122
|
}
|
|
329
123
|
|
|
330
124
|
return result!
|
|
331
125
|
}
|
|
332
126
|
}
|
|
333
|
-
|
|
334
|
-
// opts?.onChange?.(result, oldResult)
|