mirror of
https://github.com/gosticks/react-table.git
synced 2026-01-30 13:27:31 +00:00
v7.0.0-beta.20
This commit is contained in:
parent
dac4744727
commit
127a7fca87
@ -1,20 +1,20 @@
|
||||
{
|
||||
"dist/index.js": {
|
||||
"bundled": 90287,
|
||||
"minified": 43056,
|
||||
"gzipped": 11505
|
||||
"bundled": 96409,
|
||||
"minified": 46532,
|
||||
"gzipped": 12274
|
||||
},
|
||||
"dist/index.es.js": {
|
||||
"bundled": 89704,
|
||||
"minified": 42548,
|
||||
"gzipped": 11385,
|
||||
"bundled": 95844,
|
||||
"minified": 46040,
|
||||
"gzipped": 12164,
|
||||
"treeshaked": {
|
||||
"rollup": {
|
||||
"code": 450,
|
||||
"code": 78,
|
||||
"import_statements": 21
|
||||
},
|
||||
"webpack": {
|
||||
"code": 3712
|
||||
"code": 11105
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,3 +1,13 @@
|
||||
## 7.0.0-beta.20
|
||||
|
||||
- Internals have been reworked to use `useReducer` instead of `useState` for stability and architecture
|
||||
- The `state` option has been removed in favor of using a custom reducer
|
||||
- The `reducer` option has been changed to a new function signature: `function (newState, action, oldState) => newState`
|
||||
- The `setState` table instance method is no longer supported
|
||||
- The `dispatch` table instanced method was added
|
||||
- The `ReactTable.actions` export is now a plain object of action types mapped to identically named action strings
|
||||
- The `ReactTable.reducerHandlers` export was added, which is a plain object of plugin hook names mapped to their respective reducer functions
|
||||
|
||||
## 7.0.0-beta.19
|
||||
|
||||
- Added an `isAggregated` boolean parameter to the `aggregate` function signature
|
||||
|
||||
73
docs/api.md
73
docs/api.md
@ -87,16 +87,11 @@ The following options are supported via the main options object passed to `useTa
|
||||
- Optional
|
||||
- The initial state object for the table.
|
||||
- Upon table initialization, this object is **merged over the table's `defaultState` object** (eg. `{...defaultState, ...initialState}`) that React Table and its hooks use to register default state to produce the final initial state object passed to the `React.useState` hook internally.
|
||||
- `state: Object`
|
||||
- `reducer: Function(newState, action, prevState) => newState`
|
||||
- Optional
|
||||
- Must be **memoized**
|
||||
- When either the internal `state` or this `state` object change, this object is **always merged over the internal table state** (eg. `{...state, ...overrides}`) to produce the final state object that is then passed to the `useTable` options.
|
||||
- `reducer: Function(oldState, newState) => finalState`
|
||||
- Optional
|
||||
- Must be **memoized**
|
||||
- Inspired by Kent C. Dodd's [State Reducer Pattern](https://kentcdodds.com/blog/the-state-reducer-pattern-with-react-hooks)
|
||||
- With every `setState` call to the table's internal `React.useState` instance, this reducer is called and is allowed to modify the final state object for updating.
|
||||
- It is passed the `oldState`, the `newState`, and when provided, an optional action `type`.
|
||||
- With every action that is dispatched to the table's internal `React.useReducer` instance, this reducer is called and is allowed to modify the final state object for updating.
|
||||
- It is passed the `newState`, `action`, and `prevState` and is expected to either return the `newState` or a modified version of the `newState`
|
||||
- May also be used to "control" the state of the table, by overriding certain pieces of state regardless of the action.
|
||||
- `defaultColumn: Object`
|
||||
- Optional
|
||||
- Defaults to `{}`
|
||||
@ -114,7 +109,7 @@ The following options are supported via the main options object passed to `useTa
|
||||
- Defaults to `(row) => row.subRows || []`
|
||||
- Use this function to change how React Table detects subrows. You could even use this function to generate sub rows if you want.
|
||||
- By default, it will attempt to return the `subRows` property on the row, or an empty array if that is not found.
|
||||
- `getRowID: Function(row, relativeIndex) => string`
|
||||
- `getRowId: Function(row, relativeIndex) => string`
|
||||
- Use this function to change how React Table detects unique rows and also how it constructs each row's underlying `path` property.
|
||||
- Optional
|
||||
- Must be **memoized**
|
||||
@ -182,18 +177,14 @@ The following options are supported on any column object you can pass to `column
|
||||
The following properties are available on the table instance returned from `useTable`
|
||||
|
||||
- `state: Object`
|
||||
- **Memoized** - This object reference will not change unless either the internal state or the `state` overrides option provided change.
|
||||
- This is the final state object of the table, which is the product of the `initialState`, internal state, optional `state` overrides option and the `reducer` option (if applicable).
|
||||
- `setState: Function(updater, type) => void`
|
||||
- **Memoized** - This function reference will not change unless the internal state `reducer` is changed
|
||||
- **Memoized** - This object reference will not change unless the internal table state is modified.
|
||||
- This is the final state object of the table, which is the product of the `initialState`, internal table reducer and (optionally) a custom `reducer` supplied by the user.
|
||||
- `dispatch: Function({ type: Actions[type], ...payload }) => void`
|
||||
- This function is used both internally by React Table, and optionally by you (the developer) to update the table state programmatically.
|
||||
- `updater: Function`
|
||||
- This parameter is identical to the `setState` API exposed by `React.useState`.
|
||||
- If a function is passed, that function will be called with the previous state and is expected to return a new version of the state.
|
||||
- If a value is passed, it will replace the state entirely.
|
||||
- `type: String`
|
||||
- Optional
|
||||
- `type: Actions[type] | String`
|
||||
- The action type corresponding to what action being taken against the state.
|
||||
- `...payload`
|
||||
- Any other action data that is associated with the action
|
||||
- `columns: Array<Column>`
|
||||
- A **nested** array of final column objects, **similar in structure to the original columns configuration option**.
|
||||
- See [Column Properties](#column-properties) for more information
|
||||
@ -237,9 +228,9 @@ The following properties are available on the table instance returned from `useT
|
||||
- This function can be used to update the internal state for any row.
|
||||
- Pass it a valid `rowPath` array and `updater`. The `updater` may be a value or function, similar to `React.useState`'s usage.
|
||||
- If `updater` is a function, it will be passed the previous value
|
||||
- `setCellState: Function(rowPath, columnID, updater: Function | any) => void`
|
||||
- `setCellState: Function(rowPath, columnId, updater: Function | any) => void`
|
||||
- This function can be used to update the internal state for any cell.
|
||||
- Pass it a valid `rowPath` array, `columnID` and `updater`. The `updater` may be a value or function, similar to `React.useState`'s usage.
|
||||
- Pass it a valid `rowPath` array, `columnId` and `updater`. The `updater` may be a value or function, similar to `React.useState`'s usage.
|
||||
- If `updater` is a function, it will be passed the previous value
|
||||
|
||||
### HeaderGroup Properties
|
||||
@ -287,8 +278,8 @@ The following additional properties are available on every `row` object returned
|
||||
- `cells: Array<Cell>`
|
||||
- An array of `Cell` objects containing properties and functions specific to the row and column it belongs to.
|
||||
- See [Cell Properties](#cell-properties) for more information
|
||||
- `values: Object<columnID: any>`
|
||||
- A map of this row's **resolved** values by columnID, eg. `{ firstName: 'Tanner', lastName: 'Linsley' }`
|
||||
- `values: Object<columnId: any>`
|
||||
- A map of this row's **resolved** values by columnId, eg. `{ firstName: 'Tanner', lastName: 'Linsley' }`
|
||||
- `getRowProps: Function(?props)`
|
||||
- **Required**
|
||||
- This function is used to resolve any props needed for this row.
|
||||
@ -352,7 +343,7 @@ The following additional properties are available on every `Cell` object returne
|
||||
|
||||
The following options are supported via the main options object passed to `useTable(options)`
|
||||
|
||||
- `state.sortBy: Array<Object<id: columnID, desc: Bool>>`
|
||||
- `state.sortBy: Array<Object<id: columnId, desc: Bool>>`
|
||||
- Must be **memoized**
|
||||
- An array of sorting objects. If there is more than one object in the array, multi-sorting will be enabled. Each sorting object should contain an `id` key with the corresponding column ID to sort by. An optional `desc` key may be set to true or false to indicated ascending or descending sorting for that column. This information is stored in state since the table is allowed to manipulate the filter through user interaction.
|
||||
- `initialState.sortBy`
|
||||
@ -428,7 +419,7 @@ The following values are provided to the table `instance`:
|
||||
- An array of **sorted** rows.
|
||||
- `preSortedRows: Array<Row>`
|
||||
- The array of rows that were originally sorted.
|
||||
- `toggleSortBy: Function(ColumnID: String, descending: Bool, isMulti: Bool) => void`
|
||||
- `toggleSortBy: Function(ColumnId: String, descending: Bool, isMulti: Bool) => void`
|
||||
- This function can be used to programmatically toggle the sorting for any specific column
|
||||
|
||||
### Column Properties
|
||||
@ -439,7 +430,7 @@ The following properties are available on every `Column` object returned by the
|
||||
- Denotes whether a column is sortable or not depending on if it has a valid accessor/data model or is manually disabled via an option.
|
||||
- `toggleSortBy: Function(descending, multi) => void`
|
||||
- This function can be used to programmatically toggle the sorting for this column.
|
||||
- This function is similar to the `instance`-level `toggleSortBy`, however, passing a columnID is not required since it is located on a `Column` object already.
|
||||
- This function is similar to the `instance`-level `toggleSortBy`, however, passing a columnId is not required since it is located on a `Column` object already.
|
||||
- `getSortByToggleProps: Function(props) => props`
|
||||
- **Required**
|
||||
- This function is used to resolve any props needed for this column's UI that is responsible for toggling the sort direction when the user clicks it.
|
||||
@ -474,9 +465,9 @@ The following properties are available on every `Column` object returned by the
|
||||
|
||||
The following options are supported via the main options object passed to `useTable(options)`
|
||||
|
||||
- `state.filters: Object<columnID: filterValue>`
|
||||
- `state.filters: Object<columnId: filterValue>`
|
||||
- Must be **memoized**
|
||||
- An object of columnID's and their corresponding filter values. This information is stored in state since the table is allowed to manipulate the filter through user interaction.
|
||||
- An object of columnId's and their corresponding filter values. This information is stored in state since the table is allowed to manipulate the filter through user interaction.
|
||||
- `initialState.filters`
|
||||
- Identical to the `state.filters` option above
|
||||
- `manualFilters: Bool`
|
||||
@ -532,7 +523,7 @@ The following values are provided to the table `instance`:
|
||||
- `preFilteredRows: Array<Row>`
|
||||
- The array of rows **used right before filtering**.
|
||||
- Among many other use-cases, these rows are directly useful for building option lists in filters, since the resulting filtered `rows` do not contain every possible option.
|
||||
- `setFilter: Function(columnID, filterValue) => void`
|
||||
- `setFilter: Function(columnId, filterValue) => void`
|
||||
- An instance-level function used to update the filter value for a specific column.
|
||||
- `setAllFilters: Function(filtersObject) => void`
|
||||
- An instance-level function used to update the values for **all** filters on the table, all at once.
|
||||
@ -619,7 +610,7 @@ The following values are provided to the table `instance`:
|
||||
- An array of **grouped and aggregated** rows.
|
||||
- `preGroupedRows: Array<Row>`
|
||||
- The array of rows originally used to create the grouped rows.
|
||||
- `toggleGroupBy: Function(columnID: String, ?set: Bool) => void`
|
||||
- `toggleGroupBy: Function(columnId: String, ?set: Bool) => void`
|
||||
- This function can be used to programmatically set or toggle the groupBy state for a specific column.
|
||||
|
||||
### Column Properties
|
||||
@ -645,7 +636,7 @@ The following properties are available on every `Column` object returned by the
|
||||
|
||||
The following properties are available on every `Row` object returned by the table instance.
|
||||
|
||||
- `groupByID: String`
|
||||
- `groupById: String`
|
||||
- The column ID for which this row is being grouped.
|
||||
- Will be `undefined` if the row is an original row from `data` and not a materialized one from the grouping.
|
||||
- `groupByVal: any`
|
||||
@ -924,7 +915,7 @@ The following additional properties are available on every **prepared** `row` ob
|
||||
|
||||
The following options are supported via the main options object passed to `useTable(options)`
|
||||
|
||||
- `state.rowState: Object<RowPathKey:Object<any, cellState: {columnID: Object}>>`
|
||||
- `state.rowState: Object<RowPathKey:Object<any, cellState: {columnId: Object}>>`
|
||||
- Optional
|
||||
- Defaults to `{}`
|
||||
- If a row's path key (eg. a row path of `[1, 3, 2]` would have a path key of `1.3.2`) is found in this array, it will have the state of the value corresponding to that key.
|
||||
@ -936,6 +927,14 @@ The following options are supported via the main options object passed to `useTa
|
||||
- Optional
|
||||
- This function may optionally return the initial state for a row.
|
||||
- If this function is defined, it will be passed a `Row` object, from which you can return a value to use as the initial state, eg. `row => row.original.initialState`
|
||||
- `getResetRowStateDeps: Function(instance) => [...useEffectDependencies]`
|
||||
- Optional
|
||||
- Defaults to resetting the `rowState` state to `{}` when the dependencies below change
|
||||
- ```js
|
||||
const getResetRowStateDeps = ({ data }) => [data]
|
||||
```
|
||||
- If set, the dependencies returned from this function will be used to determine when the effect to reset the `rowState` state is fired.
|
||||
- To disable, set to `false`
|
||||
|
||||
### Instance Properties
|
||||
|
||||
@ -944,7 +943,7 @@ The following values are provided to the table `instance`:
|
||||
- `setRowState: Function(rowPath: Array<string>, updater: Function | Any) => void`
|
||||
- Use this function to programmatically update the state of a row.
|
||||
- `updater` can be a function or value. If a `function` is passed, it will receive the current value and expect a new one to be returned.
|
||||
- `setCellState: Function(rowPath: Array<string>, columnID: String, updater: Function | Any) => void`
|
||||
- `setCellState: Function(rowPath: Array<string>, columnId: String, updater: Function | Any) => void`
|
||||
- Use this function to programmatically update the cell of a row.
|
||||
- `updater` can be a function or value. If a `function` is passed, it will receive the current value and expect a new one to be returned.
|
||||
|
||||
@ -964,7 +963,7 @@ The following additional properties are available on every **prepared** `row` ob
|
||||
The following additional properties are available on every `Cell` object returned in an array of `cells` on every row object.
|
||||
|
||||
- `state: Object`
|
||||
- This is the state object for each cell, pre-mapped to the cell from the table state's `rowState` object via `rowState[row.path.join('.')].cellState[columnID]`
|
||||
- This is the state object for each cell, pre-mapped to the cell from the table state's `rowState` object via `rowState[row.path.join('.')].cellState[columnId]`
|
||||
- `setState: Function(updater: Function | any)`
|
||||
- Use this function to programmatically update the state of a cell.
|
||||
- `updater` can be a function or value. If a `function` is passed, it will receive the current value and expect a new one to be returned.
|
||||
@ -1086,7 +1085,7 @@ The core column options `width`, `minWidth` and `maxWidth` are used to calculate
|
||||
|
||||
The following options are supported via the main options object passed to `useTable(options)`
|
||||
|
||||
- `state.columnOrder: Array<ColumnID>`
|
||||
- `state.columnOrder: Array<ColumnId>`
|
||||
- Optional
|
||||
- Defaults to `[]`
|
||||
- Any column ID's not represented in this array will be naturally ordered based on their position in the original table's `column` structure
|
||||
@ -1097,7 +1096,7 @@ The following options are supported via the main options object passed to `useTa
|
||||
|
||||
The following values are provided to the table `instance`:
|
||||
|
||||
- `setColumnOrder: Function(updater: Function | Array<ColumnID>) => void`
|
||||
- `setColumnOrder: Function(updater: Function | Array<ColumnId>) => void`
|
||||
|
||||
- Use this function to programmatically update the columnOrder.
|
||||
- `updater` can be a function or value. If a `function` is passed, it will receive the current value and expect a new one to be returned.
|
||||
|
||||
@ -236,9 +236,9 @@ function App() {
|
||||
// Update data. So we can keep track of that flag with a ref.
|
||||
|
||||
// When our cell renderer calls updateMyData, we'll use
|
||||
// the rowIndex, columnID and new value to update the
|
||||
// the rowIndex, columnId and new value to update the
|
||||
// original data
|
||||
const updateMyData = (rowIndex, columnID, value) => {
|
||||
const updateMyData = (rowIndex, columnId, value) => {
|
||||
// We also turn on the flag to not reset the page
|
||||
setSkipPageReset(true)
|
||||
setData(old =>
|
||||
@ -246,7 +246,7 @@ function App() {
|
||||
if (index === rowIndex) {
|
||||
return {
|
||||
...old[rowIndex],
|
||||
[columnID]: value,
|
||||
[columnId]: value,
|
||||
}
|
||||
}
|
||||
return row
|
||||
|
||||
@ -582,9 +582,9 @@ function App() {
|
||||
const skipPageResetRef = React.useRef(false)
|
||||
|
||||
// When our cell renderer calls updateMyData, we'll use
|
||||
// the rowIndex, columnID and new value to update the
|
||||
// the rowIndex, columnId and new value to update the
|
||||
// original data
|
||||
const updateMyData = (rowIndex, columnID, value) => {
|
||||
const updateMyData = (rowIndex, columnId, value) => {
|
||||
// We also turn on the flag to not reset the page
|
||||
skipPageResetRef.current = true
|
||||
setData(old =>
|
||||
@ -592,7 +592,7 @@ function App() {
|
||||
if (index === rowIndex) {
|
||||
return {
|
||||
...row,
|
||||
[columnID]: value,
|
||||
[columnId]: value,
|
||||
}
|
||||
}
|
||||
return row
|
||||
|
||||
@ -581,9 +581,9 @@ function App() {
|
||||
const skipResetRef = React.useRef(false)
|
||||
|
||||
// When our cell renderer calls updateMyData, we'll use
|
||||
// the rowIndex, columnID and new value to update the
|
||||
// the rowIndex, columnId and new value to update the
|
||||
// original data
|
||||
const updateMyData = (rowIndex, columnID, value) => {
|
||||
const updateMyData = (rowIndex, columnId, value) => {
|
||||
// We also turn on the flag to not reset the page
|
||||
skipResetRef.current = true
|
||||
setData(old =>
|
||||
@ -591,7 +591,7 @@ function App() {
|
||||
if (index === rowIndex) {
|
||||
return {
|
||||
...row,
|
||||
[columnID]: value,
|
||||
[columnId]: value,
|
||||
}
|
||||
}
|
||||
return row
|
||||
|
||||
@ -918,7 +918,7 @@
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.2"
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5":
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.2", "@babel/runtime@^7.5.5":
|
||||
version "7.7.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.4.tgz#b23a856751e4bf099262f867767889c0e3fe175b"
|
||||
integrity sha512-r24eVUUr0QqNZa+qrImUk8fn5SPhHq+IfYvIoIMg0do3GdK9sMdiLKP3GYVVaxpPKORgm8KRKaNTEhAjgIpLMw==
|
||||
@ -8218,10 +8218,10 @@ react-scripts@3.0.1:
|
||||
optionalDependencies:
|
||||
fsevents "2.0.6"
|
||||
|
||||
react-table@^7.0.0-beta.15:
|
||||
version "7.0.0-beta.15"
|
||||
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.0.0-beta.15.tgz#66dc4c71f9e77f5c92ac65a307341d6d3e045d33"
|
||||
integrity sha512-Qr0HjVkYIPLi7BJiHm6ZfRIH00Ziu/bdonwouwKY10hsaqQi9AyH9kF4cXJChBQuspfjsnqnP9kQAjsEIoAeUQ==
|
||||
react-table@next:
|
||||
version "7.0.0-beta.19"
|
||||
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.0.0-beta.19.tgz#8563ae56f693cbffa10060772ba1f1cd4e926bb2"
|
||||
integrity sha512-BRt7zW7PGyg67fR2CK9M2fwP6BocjQN870w3P+K+vDJMkpewGjSPDscCU5sJMBqCEjKWg85k2pVkiwQPg9ofgQ==
|
||||
|
||||
react@^16.8.6:
|
||||
version "16.12.0"
|
||||
@ -9093,13 +9093,6 @@ stealthy-require@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
|
||||
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
|
||||
|
||||
stop-runaway-react-effects@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/stop-runaway-react-effects/-/stop-runaway-react-effects-1.2.1.tgz#ffc9df565021c69cd2c04171e7f0e4a6c7eb2b21"
|
||||
integrity sha512-56AK/rkH+/Y1ZUF+QYsl/7Z/caSnF46RmkbF6AemYWue2tZpAlOOj+VdcLdhFGo5Vg7ajDP2Lqq+3UhbdWQRmQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.4.4"
|
||||
|
||||
stream-browserify@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
|
||||
|
||||
@ -61,7 +61,6 @@ function Table({
|
||||
nextPage,
|
||||
previousPage,
|
||||
setPageSize,
|
||||
rows,
|
||||
// Get the state from the instance
|
||||
state: { pageIndex, pageSize },
|
||||
} = useTable(
|
||||
@ -245,7 +244,7 @@ function App() {
|
||||
// even a server. But for this example, we'll just fake it.
|
||||
|
||||
// Give this fetch an ID
|
||||
const fetchID = ++fetchIdRef.current
|
||||
const fetchId = ++fetchIdRef.current
|
||||
|
||||
// Set the loading state
|
||||
setLoading(true)
|
||||
@ -253,7 +252,7 @@ function App() {
|
||||
// We'll even set a delay to simulate a server here
|
||||
setTimeout(() => {
|
||||
// Only update the data if this is the latest fetch
|
||||
if (fetchID === fetchIdRef.current) {
|
||||
if (fetchId === fetchIdRef.current) {
|
||||
const startRow = pageSize * pageIndex
|
||||
const endRow = startRow + pageSize
|
||||
setData(serverData.slice(startRow, endRow))
|
||||
|
||||
@ -62,6 +62,7 @@ function Table({ columns, data }) {
|
||||
columns,
|
||||
data,
|
||||
initialState: { pageIndex: 2 },
|
||||
debug: true,
|
||||
},
|
||||
usePagination
|
||||
)
|
||||
@ -95,19 +96,16 @@ function Table({ columns, data }) {
|
||||
))}
|
||||
</thead>
|
||||
<tbody {...getTableBodyProps()}>
|
||||
{page.map(
|
||||
(row, i) => {
|
||||
prepareRow(row);
|
||||
return (
|
||||
<tr {...row.getRowProps()}>
|
||||
{row.cells.map(cell => {
|
||||
return (
|
||||
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
|
||||
)
|
||||
})}
|
||||
</tr>
|
||||
)}
|
||||
)}
|
||||
{page.map((row, i) => {
|
||||
prepareRow(row)
|
||||
return (
|
||||
<tr {...row.getRowProps()}>
|
||||
{row.cells.map(cell => {
|
||||
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
|
||||
})}
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
{/*
|
||||
|
||||
@ -39,7 +39,7 @@ const Styles = styled.div`
|
||||
const Table = ({ columns, data }) => {
|
||||
const [records, setRecords] = React.useState(data)
|
||||
|
||||
const getRowID = React.useCallback(row => {
|
||||
const getRowId = React.useCallback(row => {
|
||||
return row.id
|
||||
}, [])
|
||||
|
||||
@ -52,7 +52,7 @@ const Table = ({ columns, data }) => {
|
||||
} = useTable({
|
||||
data: records,
|
||||
columns,
|
||||
getRowID,
|
||||
getRowId,
|
||||
})
|
||||
|
||||
const moveRow = (dragIndex, hoverIndex) => {
|
||||
|
||||
@ -47,6 +47,7 @@ function Table({ columns, data }) {
|
||||
{
|
||||
columns,
|
||||
data,
|
||||
debug: true,
|
||||
},
|
||||
useRowSelect
|
||||
)
|
||||
@ -65,19 +66,16 @@ function Table({ columns, data }) {
|
||||
))}
|
||||
</thead>
|
||||
<tbody {...getTableBodyProps()}>
|
||||
{rows.map(
|
||||
(row, i) => {
|
||||
prepareRow(row);
|
||||
return (
|
||||
<tr {...row.getRowProps()}>
|
||||
{row.cells.map(cell => {
|
||||
return (
|
||||
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
|
||||
)
|
||||
})}
|
||||
</tr>
|
||||
)}
|
||||
)}
|
||||
{rows.map((row, i) => {
|
||||
prepareRow(row)
|
||||
return (
|
||||
<tr {...row.getRowProps()}>
|
||||
{row.cells.map(cell => {
|
||||
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
|
||||
})}
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Selected Rows: {selectedRowPaths.length}</p>
|
||||
|
||||
2
index.d.ts
vendored
2
index.d.ts
vendored
@ -484,7 +484,7 @@ export interface UseRowStateInstanceProps<D extends object> {
|
||||
setRowState: (rowPath: string[], updater: UseRowUpdater) => void // Purposely not exposing action
|
||||
setCellState: (
|
||||
rowPath: string[],
|
||||
columnID: IdType<D>,
|
||||
columnId: IdType<D>,
|
||||
updater: UseRowUpdater
|
||||
) => void
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-table",
|
||||
"version": "7.0.0-beta.19",
|
||||
"version": "7.0.0-beta.20",
|
||||
"description": "A fast, lightweight, opinionated table and datagrid built on React",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/tannerlinsley/react-table#readme",
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
const actions = {}
|
||||
const types = {}
|
||||
|
||||
export { actions, types }
|
||||
|
||||
export const addActions = (...acts) => {
|
||||
acts.forEach(action => {
|
||||
// Action values are formatted this way to discourage
|
||||
// you (the dev) from interacting with them in any way
|
||||
// other than importing `{ actions } from 'react-table'`
|
||||
// and referencing an action via `actions[actionName]`
|
||||
actions[action] = `React Table Action: ${action}`
|
||||
types[actions[action]] = true
|
||||
})
|
||||
}
|
||||
@ -15,13 +15,17 @@ import {
|
||||
const renderErr =
|
||||
'You must specify a valid render component. This could be "column.Cell", "column.Header", "column.Filter", "column.Aggregated" or any other custom renderer component.'
|
||||
|
||||
export const actions = {
|
||||
init: 'init',
|
||||
}
|
||||
export const defaultState = {}
|
||||
export const reducerHandlers = {}
|
||||
|
||||
const defaultInitialState = {}
|
||||
const defaultColumnInstance = {}
|
||||
const defaultReducer = (old, newState) => newState
|
||||
const defaultReducer = (state, action, prevState) => state
|
||||
const defaultGetSubRows = (row, index) => row.subRows || []
|
||||
const defaultGetRowID = (row, index) => index
|
||||
const defaultGetRowId = (row, index) => index
|
||||
|
||||
export const useTable = (props, ...plugins) => {
|
||||
// Destructure props
|
||||
@ -29,53 +33,54 @@ export const useTable = (props, ...plugins) => {
|
||||
data,
|
||||
columns: userColumns,
|
||||
initialState = defaultInitialState,
|
||||
state: userState,
|
||||
defaultColumn = defaultColumnInstance,
|
||||
getSubRows = defaultGetSubRows,
|
||||
getRowID = defaultGetRowID,
|
||||
reducer = defaultReducer,
|
||||
getRowId = defaultGetRowId,
|
||||
reducer: userReducer = defaultReducer,
|
||||
debug,
|
||||
} = props
|
||||
|
||||
debug = process.env.NODE_ENV === 'production' ? false : debug
|
||||
|
||||
// But use the users table state if provided
|
||||
let [originalState, originalSetState] = React.useState({
|
||||
...defaultState,
|
||||
...initialState,
|
||||
})
|
||||
const reducer = (state, action) => {
|
||||
let nextState = Object.keys(reducerHandlers)
|
||||
.map(key => reducerHandlers[key])
|
||||
.reduce((state, handler) => handler(state, action) || state, state)
|
||||
|
||||
const state = React.useMemo(() => {
|
||||
if (userState) {
|
||||
const newState = {
|
||||
...originalState,
|
||||
}
|
||||
Object.keys(userState).forEach(key => {
|
||||
newState[key] = userState[key]
|
||||
})
|
||||
return newState
|
||||
nextState = userReducer(nextState, action, state)
|
||||
|
||||
if (process.env.NODE_ENV !== 'production' && debug) {
|
||||
console.log('')
|
||||
console.log('React Table Action: ', action)
|
||||
console.log('New State: ', nextState)
|
||||
}
|
||||
return originalState
|
||||
}, [originalState, userState])
|
||||
return nextState
|
||||
}
|
||||
|
||||
const setState = React.useCallback(
|
||||
(updater, type) => {
|
||||
return originalSetState(old => {
|
||||
const newState = typeof updater === 'function' ? updater(old) : updater
|
||||
return reducer(old, newState, type)
|
||||
})
|
||||
},
|
||||
[reducer]
|
||||
// But use the users table state if provided
|
||||
const [state, originalDispatch] = React.useReducer(reducer, undefined, () =>
|
||||
reducer(initialState, { type: actions.init })
|
||||
)
|
||||
|
||||
// The table instance ref
|
||||
let instanceRef = React.useRef({})
|
||||
|
||||
const dispatch = React.useCallback(action => {
|
||||
if (!action.type) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
console.info({ action })
|
||||
throw new Error('Unknown Action Type! 👆')
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
originalDispatch({ ...action, instanceRef })
|
||||
}, [])
|
||||
|
||||
Object.assign(instanceRef.current, {
|
||||
...props,
|
||||
data, // The raw data
|
||||
state,
|
||||
setState, // The resolved table state
|
||||
state, // The state dispatcher
|
||||
dispatch, // The resolved table state
|
||||
plugins, // All resolved plugins
|
||||
hooks: {
|
||||
columnsBeforeHeaderGroups: [],
|
||||
@ -94,14 +99,13 @@ export const useTable = (props, ...plugins) => {
|
||||
})
|
||||
|
||||
// Allow plugins to register hooks
|
||||
if (process.env.NODE_ENV === 'development' && debug) console.time('plugins')
|
||||
if (process.env.NODE_ENV !== 'production' && debug) console.time('plugins')
|
||||
|
||||
plugins.filter(Boolean).forEach(plugin => {
|
||||
plugin(instanceRef.current.hooks)
|
||||
})
|
||||
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
console.timeEnd('plugins')
|
||||
if (process.env.NODE_ENV !== 'production' && debug) console.timeEnd('plugins')
|
||||
|
||||
// Decorate All the columns
|
||||
let columns = React.useMemo(
|
||||
@ -112,7 +116,7 @@ export const useTable = (props, ...plugins) => {
|
||||
// Get the flat list of all columns and allow hooks to decorate
|
||||
// those columns (and trigger this memoization via deps)
|
||||
let flatColumns = React.useMemo(() => {
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.time('hooks.columnsBeforeHeaderGroups')
|
||||
|
||||
let newColumns = applyHooks(
|
||||
@ -121,7 +125,7 @@ export const useTable = (props, ...plugins) => {
|
||||
instanceRef.current
|
||||
)
|
||||
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.timeEnd('hooks.columnsBeforeHeaderGroups')
|
||||
return newColumns
|
||||
}, [
|
||||
@ -152,7 +156,7 @@ export const useTable = (props, ...plugins) => {
|
||||
|
||||
// Access the row model
|
||||
const [rows, flatRows] = React.useMemo(() => {
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.time('getAccessedRows')
|
||||
|
||||
let flatRows = []
|
||||
@ -162,10 +166,10 @@ export const useTable = (props, ...plugins) => {
|
||||
// Keep the original reference around
|
||||
const original = originalRow
|
||||
|
||||
const rowID = getRowID(originalRow, i)
|
||||
const rowId = getRowId(originalRow, i)
|
||||
|
||||
// Make the new path for the row
|
||||
const path = [...parentPath, rowID]
|
||||
const path = [...parentPath, rowId]
|
||||
|
||||
const row = {
|
||||
original,
|
||||
@ -209,10 +213,10 @@ export const useTable = (props, ...plugins) => {
|
||||
|
||||
// Use the resolved data
|
||||
const accessedData = data.map((d, i) => accessRow(d, i))
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.timeEnd('getAccessedRows')
|
||||
return [accessedData, flatRows]
|
||||
}, [debug, data, getRowID, getSubRows, flatColumns])
|
||||
}, [debug, data, getRowId, getSubRows, flatColumns])
|
||||
|
||||
instanceRef.current.rows = rows
|
||||
instanceRef.current.flatRows = flatRows
|
||||
@ -226,24 +230,24 @@ export const useTable = (props, ...plugins) => {
|
||||
[]
|
||||
)
|
||||
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.time('hooks.useBeforeDimensions')
|
||||
instanceRef.current = applyHooks(
|
||||
instanceRef.current.hooks.useBeforeDimensions,
|
||||
instanceRef.current
|
||||
)
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.timeEnd('hooks.useBeforeDimensions')
|
||||
|
||||
calculateDimensions(instanceRef.current)
|
||||
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.time('hooks.useMain')
|
||||
instanceRef.current = applyHooks(
|
||||
instanceRef.current.hooks.useMain,
|
||||
instanceRef.current
|
||||
)
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.timeEnd('hooks.useMain')
|
||||
|
||||
// Each materialized header needs to be assigned a render function and other
|
||||
@ -316,14 +320,14 @@ export const useTable = (props, ...plugins) => {
|
||||
})
|
||||
|
||||
// Run the rows (this could be a dangerous hook with a ton of data)
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.time('hooks.useRows')
|
||||
instanceRef.current.rows = applyHooks(
|
||||
instanceRef.current.hooks.useRows,
|
||||
instanceRef.current.rows,
|
||||
instanceRef.current
|
||||
)
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.timeEnd('hooks.useRows')
|
||||
|
||||
// The prepareRow function is absolutely necessary and MUST be called on
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import * as utils from './utils'
|
||||
export { utils }
|
||||
export { defaultColumn } from './utils'
|
||||
export { useTable, defaultState } from './hooks/useTable'
|
||||
export { useTable, actions, reducerHandlers } from './hooks/useTable'
|
||||
export { useExpanded } from './plugin-hooks/useExpanded'
|
||||
export { useFilters } from './plugin-hooks/useFilters'
|
||||
export { useGroupBy } from './plugin-hooks/useGroupBy'
|
||||
@ -13,4 +13,3 @@ export { useColumnOrder } from './plugin-hooks/useColumnOrder'
|
||||
export { useResizeColumns } from './plugin-hooks/useResizeColumns'
|
||||
export { useAbsoluteLayout } from './plugin-hooks/useAbsoluteLayout'
|
||||
export { useBlockLayout } from './plugin-hooks/useBlockLayout'
|
||||
export { actions, addActions } from './actions'
|
||||
|
||||
@ -1,11 +1,37 @@
|
||||
import React from 'react'
|
||||
|
||||
import { addActions, actions } from '../actions'
|
||||
import { defaultState } from '../hooks/useTable'
|
||||
import { actions, reducerHandlers } from '../hooks/useTable'
|
||||
import { functionalUpdate } from '../utils'
|
||||
|
||||
defaultState.columnOrder = []
|
||||
const pluginName = 'useColumnOrder'
|
||||
|
||||
addActions('setColumnOrder')
|
||||
// Actions
|
||||
actions.resetColumnOrder = 'resetColumnOrder'
|
||||
actions.setColumnOrder = 'setColumnOrder'
|
||||
|
||||
// Reducer
|
||||
reducerHandlers[pluginName] = (state, action) => {
|
||||
if (action.type === actions.init) {
|
||||
return {
|
||||
columnOrder: [],
|
||||
...state,
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.resetColumnOrder) {
|
||||
return {
|
||||
...state,
|
||||
columnOrder: [],
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.setColumnOrder) {
|
||||
return {
|
||||
...state,
|
||||
columnOrder: functionalUpdate(action.columnOrder, state.columnOrder),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const useColumnOrder = hooks => {
|
||||
hooks.columnsBeforeHeaderGroupsDeps.push((deps, instance) => {
|
||||
@ -15,7 +41,7 @@ export const useColumnOrder = hooks => {
|
||||
hooks.useMain.push(useMain)
|
||||
}
|
||||
|
||||
useColumnOrder.pluginName = 'useColumnOrder'
|
||||
useColumnOrder.pluginName = pluginName
|
||||
|
||||
function columnsBeforeHeaderGroups(columns, instance) {
|
||||
const {
|
||||
@ -37,8 +63,8 @@ function columnsBeforeHeaderGroups(columns, instance) {
|
||||
|
||||
// Loop over the columns and place them in order into the new array
|
||||
while (columnsCopy.length && columnOrderCopy.length) {
|
||||
const targetColumnID = columnOrderCopy.shift()
|
||||
const foundIndex = columnsCopy.findIndex(d => d.id === targetColumnID)
|
||||
const targetColumnId = columnOrderCopy.shift()
|
||||
const foundIndex = columnsCopy.findIndex(d => d.id === targetColumnId)
|
||||
if (foundIndex > -1) {
|
||||
columnsInOrder.push(columnsCopy.splice(foundIndex, 1)[0])
|
||||
}
|
||||
@ -49,19 +75,13 @@ function columnsBeforeHeaderGroups(columns, instance) {
|
||||
}
|
||||
|
||||
function useMain(instance) {
|
||||
const { setState } = instance
|
||||
const { dispatch } = instance
|
||||
|
||||
const setColumnOrder = React.useCallback(
|
||||
updater => {
|
||||
return setState(old => {
|
||||
return {
|
||||
...old,
|
||||
columnOrder:
|
||||
typeof updater === 'function' ? updater(old.columnOrder) : updater,
|
||||
}
|
||||
}, actions.setColumnOrder)
|
||||
columnOrder => {
|
||||
return dispatch({ type: actions.setColumnOrder, columnOrder })
|
||||
},
|
||||
[setState]
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
return {
|
||||
|
||||
@ -6,19 +6,58 @@ import {
|
||||
expandRows,
|
||||
safeUseLayoutEffect,
|
||||
} from '../utils'
|
||||
import { addActions, actions } from '../actions'
|
||||
import { defaultState } from '../hooks/useTable'
|
||||
import { actions, reducerHandlers } from '../hooks/useTable'
|
||||
|
||||
defaultState.expanded = []
|
||||
const pluginName = 'useExpanded'
|
||||
|
||||
addActions('toggleExpanded', 'setExpanded')
|
||||
// Actions
|
||||
actions.toggleExpandedByPath = 'toggleExpandedByPath'
|
||||
actions.resetExpanded = 'resetExpanded'
|
||||
|
||||
// Reducer
|
||||
reducerHandlers[pluginName] = (state, action) => {
|
||||
if (action.type === actions.init) {
|
||||
return {
|
||||
expanded: [],
|
||||
...state,
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.resetExpanded) {
|
||||
return {
|
||||
...state,
|
||||
expanded: [],
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.toggleExpandedByPath) {
|
||||
const { path, expanded } = action
|
||||
const key = path.join('.')
|
||||
const exists = state.expanded.includes(key)
|
||||
const shouldExist = typeof set !== 'undefined' ? expanded : !exists
|
||||
let newExpanded = new Set(state.expanded)
|
||||
|
||||
if (!exists && shouldExist) {
|
||||
newExpanded.add(key)
|
||||
} else if (exists && !shouldExist) {
|
||||
newExpanded.delete(key)
|
||||
} else {
|
||||
return state
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
expanded: [...newExpanded.values()],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const useExpanded = hooks => {
|
||||
hooks.getExpandedToggleProps = []
|
||||
hooks.useMain.push(useMain)
|
||||
}
|
||||
|
||||
useExpanded.pluginName = 'useExpanded'
|
||||
useExpanded.pluginName = pluginName
|
||||
|
||||
const defaultGetResetExpandedDeps = ({ data }) => [data]
|
||||
|
||||
@ -31,7 +70,7 @@ function useMain(instance) {
|
||||
expandSubRows = true,
|
||||
hooks,
|
||||
state: { expanded },
|
||||
setState,
|
||||
dispatch,
|
||||
getResetExpandedDeps = defaultGetResetExpandedDeps,
|
||||
} = instance
|
||||
|
||||
@ -39,41 +78,16 @@ function useMain(instance) {
|
||||
const isMountedRef = React.useRef()
|
||||
safeUseLayoutEffect(() => {
|
||||
if (isMountedRef.current) {
|
||||
setState(
|
||||
old => ({
|
||||
...old,
|
||||
expanded: [],
|
||||
}),
|
||||
actions.setExpanded
|
||||
)
|
||||
dispatch({ type: actions.resetExpanded })
|
||||
}
|
||||
isMountedRef.current = true
|
||||
}, [
|
||||
setState,
|
||||
dispatch,
|
||||
...(getResetExpandedDeps ? getResetExpandedDeps(instance) : []),
|
||||
])
|
||||
|
||||
const toggleExpandedByPath = (path, set) => {
|
||||
const key = path.join('.')
|
||||
|
||||
return setState(old => {
|
||||
const exists = old.expanded.includes(key)
|
||||
const shouldExist = typeof set !== 'undefined' ? set : !exists
|
||||
let newExpanded = new Set(old.expanded)
|
||||
|
||||
if (!exists && shouldExist) {
|
||||
newExpanded.add(key)
|
||||
} else if (exists && !shouldExist) {
|
||||
newExpanded.delete(key)
|
||||
} else {
|
||||
return old
|
||||
}
|
||||
|
||||
return {
|
||||
...old,
|
||||
expanded: [...newExpanded.values()],
|
||||
}
|
||||
}, actions.toggleExpanded)
|
||||
const toggleExpandedByPath = (path, expanded) => {
|
||||
dispatch({ type: actions.toggleExpandedByPath, path, expanded })
|
||||
}
|
||||
|
||||
// use reference to avoid memory leak in #1608
|
||||
@ -106,7 +120,7 @@ function useMain(instance) {
|
||||
})
|
||||
|
||||
const expandedRows = React.useMemo(() => {
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.info('getExpandedRows')
|
||||
|
||||
if (paginateExpandedRows) {
|
||||
|
||||
@ -1,19 +1,118 @@
|
||||
import React from 'react'
|
||||
|
||||
import { getFirstDefined, isFunction, safeUseLayoutEffect } from '../utils'
|
||||
import {
|
||||
getFirstDefined,
|
||||
isFunction,
|
||||
safeUseLayoutEffect,
|
||||
functionalUpdate,
|
||||
} from '../utils'
|
||||
import * as filterTypes from '../filterTypes'
|
||||
import { addActions, actions } from '../actions'
|
||||
import { defaultState } from '../hooks/useTable'
|
||||
import { actions, reducerHandlers } from '../hooks/useTable'
|
||||
|
||||
defaultState.filters = {}
|
||||
const pluginName = 'useFilters'
|
||||
|
||||
addActions('setFilter', 'setAllFilters')
|
||||
// Actions
|
||||
actions.resetFilters = 'resetFilters'
|
||||
actions.setFilter = 'setFilter'
|
||||
actions.setAllFilters = 'setAllFilters'
|
||||
|
||||
// Reducer
|
||||
reducerHandlers[pluginName] = (state, action) => {
|
||||
if (action.type === actions.init) {
|
||||
return {
|
||||
filters: {},
|
||||
...state,
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.resetFilters) {
|
||||
return {
|
||||
...state,
|
||||
filters: {},
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.setFilter) {
|
||||
const {
|
||||
columnId,
|
||||
filterValue,
|
||||
instanceRef: {
|
||||
current: { flatColumns, userFilterTypes },
|
||||
},
|
||||
} = action
|
||||
|
||||
const column = flatColumns.find(d => d.id === columnId)
|
||||
|
||||
if (!column) {
|
||||
throw new Error(
|
||||
`React-Table: Could not find a column with id: ${columnId}`
|
||||
)
|
||||
}
|
||||
|
||||
const filterMethod = getFilterMethod(
|
||||
column.filter,
|
||||
userFilterTypes || {},
|
||||
filterTypes
|
||||
)
|
||||
|
||||
const newFilter = functionalUpdate(filterValue, state.filters[columnId])
|
||||
|
||||
//
|
||||
if (shouldAutoRemove(filterMethod.autoRemove, newFilter)) {
|
||||
const { [columnId]: remove, ...newFilters } = state.filters
|
||||
|
||||
return {
|
||||
...state,
|
||||
filters: newFilters,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
filters: {
|
||||
...state.filters,
|
||||
[columnId]: newFilter,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.setAllFilters) {
|
||||
const {
|
||||
filters,
|
||||
instanceRef: {
|
||||
current: { flatColumns, filterTypes: userFilterTypes },
|
||||
},
|
||||
} = action
|
||||
|
||||
const newFilters = functionalUpdate(filters, state.filters)
|
||||
|
||||
// Filter out undefined values
|
||||
Object.keys(newFilters).forEach(id => {
|
||||
const newFilter = newFilters[id]
|
||||
const column = flatColumns.find(d => d.id === id)
|
||||
const filterMethod = getFilterMethod(
|
||||
column.filter,
|
||||
userFilterTypes || {},
|
||||
filterTypes
|
||||
)
|
||||
|
||||
if (shouldAutoRemove(filterMethod.autoRemove, newFilter)) {
|
||||
delete newFilters[id]
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
...state,
|
||||
filters: newFilters,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const useFilters = hooks => {
|
||||
hooks.useMain.push(useMain)
|
||||
}
|
||||
|
||||
useFilters.pluginName = 'useFilters'
|
||||
useFilters.pluginName = pluginName
|
||||
|
||||
function useMain(instance) {
|
||||
const {
|
||||
@ -26,7 +125,7 @@ function useMain(instance) {
|
||||
defaultCanFilter = false,
|
||||
disableFilters,
|
||||
state: { filters },
|
||||
setState,
|
||||
dispatch,
|
||||
getResetFiltersDeps = false,
|
||||
} = instance
|
||||
|
||||
@ -37,77 +136,20 @@ function useMain(instance) {
|
||||
const isMountedRef = React.useRef()
|
||||
safeUseLayoutEffect(() => {
|
||||
if (isMountedRef.current) {
|
||||
setState(
|
||||
old => ({
|
||||
...old,
|
||||
filters: {},
|
||||
}),
|
||||
actions.setAllFilters
|
||||
)
|
||||
dispatch({ type: actions.resetFilters })
|
||||
}
|
||||
isMountedRef.current = true
|
||||
}, [setState, ...(getResetFiltersDeps ? getResetFiltersDeps(instance) : [])])
|
||||
}, [dispatch, ...(getResetFiltersDeps ? getResetFiltersDeps(instance) : [])])
|
||||
|
||||
const setFilter = (id, updater) => {
|
||||
const column = flatColumns.find(d => d.id === id)
|
||||
|
||||
if (!column) {
|
||||
throw new Error(`React-Table: Could not find a column with id: ${id}`)
|
||||
}
|
||||
|
||||
const filterMethod = getFilterMethod(
|
||||
column.filter,
|
||||
userFilterTypes || {},
|
||||
filterTypes
|
||||
)
|
||||
|
||||
return setState(old => {
|
||||
const newFilter =
|
||||
typeof updater === 'function' ? updater(old.filters[id]) : updater
|
||||
|
||||
//
|
||||
if (shouldAutoRemove(filterMethod.autoRemove, newFilter)) {
|
||||
const { [id]: remove, ...newFilters } = old.filters
|
||||
return {
|
||||
...old,
|
||||
filters: newFilters,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...old,
|
||||
filters: {
|
||||
...old.filters,
|
||||
[id]: newFilter,
|
||||
},
|
||||
}
|
||||
}, actions.setFilter)
|
||||
const setFilter = (columnId, filterValue) => {
|
||||
dispatch({ type: actions.setFilter, columnId, filterValue })
|
||||
}
|
||||
|
||||
const setAllFilters = updater => {
|
||||
return setState(old => {
|
||||
const newFilters = typeof updater === 'function' ? updater(old) : updater
|
||||
|
||||
// Filter out undefined values
|
||||
Object.keys(newFilters).forEach(id => {
|
||||
const newFilter = newFilters[id]
|
||||
const column = flatColumns.find(d => d.id === id)
|
||||
const filterMethod = getFilterMethod(
|
||||
column.filter,
|
||||
userFilterTypes || {},
|
||||
filterTypes
|
||||
)
|
||||
|
||||
if (shouldAutoRemove(filterMethod.autoRemove, newFilter)) {
|
||||
delete newFilters[id]
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
...old,
|
||||
filters: newFilters,
|
||||
}
|
||||
}, actions.setAllFilters)
|
||||
const setAllFilters = filters => {
|
||||
dispatch({
|
||||
type: actions.setAllFilters,
|
||||
filters,
|
||||
})
|
||||
}
|
||||
|
||||
flatColumns.forEach(column => {
|
||||
@ -150,7 +192,7 @@ function useMain(instance) {
|
||||
|
||||
const filteredFlatRows = []
|
||||
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.info('getFilteredRows')
|
||||
|
||||
// Filters top level and nested rows
|
||||
@ -158,9 +200,9 @@ function useMain(instance) {
|
||||
let filteredRows = rows
|
||||
|
||||
filteredRows = Object.entries(filters).reduce(
|
||||
(filteredSoFar, [columnID, filterValue]) => {
|
||||
(filteredSoFar, [columnId, filterValue]) => {
|
||||
// Find the filters column
|
||||
const column = flatColumns.find(d => d.id === columnID)
|
||||
const column = flatColumns.find(d => d.id === columnId)
|
||||
|
||||
if (!column) {
|
||||
return filteredSoFar
|
||||
@ -187,7 +229,7 @@ function useMain(instance) {
|
||||
// to get the filtered rows back
|
||||
column.filteredRows = filterMethod(
|
||||
filteredSoFar,
|
||||
columnID,
|
||||
columnId,
|
||||
filterValue,
|
||||
column
|
||||
)
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import React from 'react'
|
||||
|
||||
import * as aggregations from '../aggregations'
|
||||
import { addActions, actions } from '../actions'
|
||||
import { defaultState } from '../hooks/useTable'
|
||||
import { actions, reducerHandlers } from '../hooks/useTable'
|
||||
import {
|
||||
mergeProps,
|
||||
applyPropHooks,
|
||||
@ -11,9 +10,47 @@ import {
|
||||
ensurePluginOrder,
|
||||
} from '../utils'
|
||||
|
||||
defaultState.groupBy = []
|
||||
const pluginName = 'useGroupBy'
|
||||
|
||||
addActions('toggleGroupBy')
|
||||
// Actions
|
||||
actions.resetGroupBy = 'resetGroupBy'
|
||||
actions.toggleGroupBy = 'toggleGroupBy'
|
||||
|
||||
// Reducer
|
||||
reducerHandlers[pluginName] = (state, action) => {
|
||||
if (action.type === actions.init) {
|
||||
return {
|
||||
groupBy: [],
|
||||
...state,
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.resetGroupBy) {
|
||||
return {
|
||||
...state,
|
||||
groupBy: [],
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.toggleGroupBy) {
|
||||
const { columnId, toggle } = action
|
||||
|
||||
const resolvedToggle =
|
||||
typeof toggle !== 'undefined' ? toggle : !state.groupBy.includes(columnId)
|
||||
|
||||
if (resolvedToggle) {
|
||||
return {
|
||||
...state,
|
||||
groupBy: [...state.groupBy, columnId],
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
groupBy: state.groupBy.filter(d => d !== columnId),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const useGroupBy = hooks => {
|
||||
hooks.columnsBeforeHeaderGroups.push(columnsBeforeHeaderGroups)
|
||||
@ -24,7 +61,7 @@ export const useGroupBy = hooks => {
|
||||
hooks.useMain.push(useMain)
|
||||
}
|
||||
|
||||
useGroupBy.pluginName = 'useGroupBy'
|
||||
useGroupBy.pluginName = pluginName
|
||||
|
||||
function columnsBeforeHeaderGroups(flatColumns, { state: { groupBy } }) {
|
||||
// Sort grouped columns to the start of the column list
|
||||
@ -61,7 +98,7 @@ function useMain(instance) {
|
||||
hooks,
|
||||
plugins,
|
||||
state: { groupBy },
|
||||
setState,
|
||||
dispatch,
|
||||
} = instance
|
||||
|
||||
ensurePluginOrder(plugins, [], 'useGroupBy', ['useSortBy', 'useExpanded'])
|
||||
@ -91,21 +128,8 @@ function useMain(instance) {
|
||||
column.Aggregated = column.Aggregated || column.Cell
|
||||
})
|
||||
|
||||
const toggleGroupBy = (id, toggle) => {
|
||||
return setState(old => {
|
||||
const resolvedToggle =
|
||||
typeof toggle !== 'undefined' ? toggle : !groupBy.includes(id)
|
||||
if (resolvedToggle) {
|
||||
return {
|
||||
...old,
|
||||
groupBy: [...groupBy, id],
|
||||
}
|
||||
}
|
||||
return {
|
||||
...old,
|
||||
groupBy: groupBy.filter(d => d !== id),
|
||||
}
|
||||
}, actions.toggleGroupBy)
|
||||
const toggleGroupBy = (columnId, toggle) => {
|
||||
dispatch({ type: actions.toggleGroupBy, columnId, toggle })
|
||||
}
|
||||
|
||||
hooks.getGroupByToggleProps = []
|
||||
@ -158,7 +182,7 @@ function useMain(instance) {
|
||||
return [rows, flatRows]
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.info('getGroupedRows')
|
||||
// Find the columns that can or are aggregating
|
||||
|
||||
@ -223,15 +247,15 @@ function useMain(instance) {
|
||||
return rows
|
||||
}
|
||||
|
||||
const columnID = groupBy[depth]
|
||||
const columnId = groupBy[depth]
|
||||
|
||||
// Group the rows together for this level
|
||||
let groupedRows = groupByFn(rows, columnID)
|
||||
let groupedRows = groupByFn(rows, columnId)
|
||||
|
||||
// Recurse to sub rows before aggregation
|
||||
groupedRows = Object.entries(groupedRows).map(
|
||||
([groupByVal, subRows], index) => {
|
||||
const path = [...parentPath, `${columnID}:${groupByVal}`]
|
||||
const path = [...parentPath, `${columnId}:${groupByVal}`]
|
||||
|
||||
subRows = groupRecursively(subRows, depth + 1, path)
|
||||
|
||||
@ -239,7 +263,7 @@ function useMain(instance) {
|
||||
|
||||
const row = {
|
||||
isAggregated: true,
|
||||
groupByID: columnID,
|
||||
groupByID: columnId,
|
||||
groupByVal,
|
||||
values,
|
||||
subRows,
|
||||
|
||||
@ -1,20 +1,70 @@
|
||||
import React from 'react'
|
||||
|
||||
//
|
||||
import { addActions, actions } from '../actions'
|
||||
import { defaultState } from '../hooks/useTable'
|
||||
import { ensurePluginOrder, safeUseLayoutEffect, expandRows } from '../utils'
|
||||
|
||||
defaultState.pageSize = 10
|
||||
defaultState.pageIndex = 0
|
||||
import { actions, reducerHandlers } from '../hooks/useTable'
|
||||
import {
|
||||
ensurePluginOrder,
|
||||
safeUseLayoutEffect,
|
||||
expandRows,
|
||||
functionalUpdate,
|
||||
} from '../utils'
|
||||
|
||||
addActions('pageChange', 'pageSizeChange')
|
||||
const pluginName = 'usePagination'
|
||||
|
||||
// Actions
|
||||
actions.resetPage = 'resetPage'
|
||||
actions.gotoPage = 'gotoPage'
|
||||
actions.setPageSize = 'setPageSize'
|
||||
|
||||
// Reducer
|
||||
reducerHandlers[pluginName] = (state, action) => {
|
||||
if (action.type === actions.init) {
|
||||
return {
|
||||
pageSize: 10,
|
||||
pageIndex: 0,
|
||||
...state,
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.resetPage) {
|
||||
return {
|
||||
...state,
|
||||
pageIndex: 0,
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.gotoPage) {
|
||||
const { pageCount } = action.instanceRef.current
|
||||
const newPageIndex = functionalUpdate(action.pageIndex, state.pageIndex)
|
||||
|
||||
if (newPageIndex < 0 || newPageIndex > pageCount - 1) {
|
||||
return state
|
||||
}
|
||||
return {
|
||||
...state,
|
||||
pageIndex: newPageIndex,
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.setPageSize) {
|
||||
const { pageSize } = action
|
||||
const topRowIndex = state.pageSize * state.pageIndex
|
||||
const pageIndex = Math.floor(topRowIndex / pageSize)
|
||||
|
||||
return {
|
||||
...state,
|
||||
pageIndex,
|
||||
pageSize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const usePagination = hooks => {
|
||||
hooks.useMain.push(useMain)
|
||||
}
|
||||
|
||||
usePagination.pluginName = 'usePagination'
|
||||
usePagination.pluginName = pluginName
|
||||
|
||||
const defaultGetResetPageDeps = ({
|
||||
data,
|
||||
@ -34,7 +84,7 @@ function useMain(instance) {
|
||||
paginateExpandedRows = true,
|
||||
expandSubRows = true,
|
||||
state: { pageSize, pageIndex, expanded },
|
||||
setState,
|
||||
dispatch,
|
||||
} = instance
|
||||
|
||||
ensurePluginOrder(
|
||||
@ -48,16 +98,10 @@ function useMain(instance) {
|
||||
const isMountedRef = React.useRef()
|
||||
safeUseLayoutEffect(() => {
|
||||
if (isMountedRef.current) {
|
||||
setState(
|
||||
old => ({
|
||||
...old,
|
||||
pageIndex: 0,
|
||||
}),
|
||||
actions.pageChange
|
||||
)
|
||||
dispatch({ type: actions.resetPage })
|
||||
}
|
||||
isMountedRef.current = true
|
||||
}, [setState, ...(getResetPageDeps ? getResetPageDeps(instance) : [])])
|
||||
}, [dispatch, ...(getResetPageDeps ? getResetPageDeps(instance) : [])])
|
||||
|
||||
const pageCount = manualPagination
|
||||
? userPageCount
|
||||
@ -74,7 +118,7 @@ function useMain(instance) {
|
||||
if (manualPagination) {
|
||||
page = rows
|
||||
} else {
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.info('getPage')
|
||||
|
||||
const pageStart = pageSize * pageIndex
|
||||
@ -104,23 +148,10 @@ function useMain(instance) {
|
||||
const canNextPage = pageCount === -1 || pageIndex < pageCount - 1
|
||||
|
||||
const gotoPage = React.useCallback(
|
||||
updater => {
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
console.info('gotoPage')
|
||||
return setState(old => {
|
||||
const newPageIndex =
|
||||
typeof updater === 'function' ? updater(old.pageIndex) : updater
|
||||
|
||||
if (newPageIndex < 0 || newPageIndex > pageCount - 1) {
|
||||
return old
|
||||
}
|
||||
return {
|
||||
...old,
|
||||
pageIndex: newPageIndex,
|
||||
}
|
||||
}, actions.pageChange)
|
||||
pageIndex => {
|
||||
dispatch({ type: actions.gotoPage, pageIndex })
|
||||
},
|
||||
[debug, pageCount, setState]
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
const previousPage = React.useCallback(() => {
|
||||
@ -133,17 +164,9 @@ function useMain(instance) {
|
||||
|
||||
const setPageSize = React.useCallback(
|
||||
pageSize => {
|
||||
setState(old => {
|
||||
const topRowIndex = old.pageSize * old.pageIndex
|
||||
const pageIndex = Math.floor(topRowIndex / pageSize)
|
||||
return {
|
||||
...old,
|
||||
pageIndex,
|
||||
pageSize,
|
||||
}
|
||||
}, actions.pageSizeChange)
|
||||
dispatch({ type: actions.setPageSize, pageSize })
|
||||
},
|
||||
[setState]
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
return {
|
||||
|
||||
@ -1,20 +1,89 @@
|
||||
import React from 'react'
|
||||
|
||||
import { defaultState } from '../hooks/useTable'
|
||||
import { defaultColumn, getFirstDefined } from '../utils'
|
||||
import { mergeProps, applyPropHooks } from '../utils'
|
||||
import { actions, reducerHandlers } from '../hooks/useTable'
|
||||
import {
|
||||
defaultColumn,
|
||||
getFirstDefined,
|
||||
mergeProps,
|
||||
applyPropHooks,
|
||||
} from '../utils'
|
||||
|
||||
defaultState.columnResizing = {
|
||||
columnWidths: {},
|
||||
}
|
||||
const pluginName = 'useResizeColumns'
|
||||
|
||||
// Default Column
|
||||
defaultColumn.canResize = true
|
||||
|
||||
// Actions
|
||||
actions.columnStartResizing = 'columnStartResizing'
|
||||
actions.columnResizing = 'columnResizing'
|
||||
actions.columnDoneResizing = 'columnDoneResizing'
|
||||
|
||||
// Reducer
|
||||
reducerHandlers[pluginName] = (state, action) => {
|
||||
if (action.type === actions.init) {
|
||||
return {
|
||||
columnResizing: {
|
||||
columnWidths: {},
|
||||
},
|
||||
...state,
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.columnStartResizing) {
|
||||
const { startX, columnId, headerIdWidths } = action
|
||||
|
||||
return {
|
||||
...state,
|
||||
columnResizing: {
|
||||
...state.columnResizing,
|
||||
startX,
|
||||
headerIdWidths,
|
||||
isResizingColumn: columnId,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.columnResizing) {
|
||||
const { clientX } = action
|
||||
const { startX, headerIdWidths } = state.columnResizing
|
||||
|
||||
const deltaX = clientX - startX
|
||||
const percentageDeltaX = deltaX / headerIdWidths.length
|
||||
|
||||
const newColumnWidths = {}
|
||||
headerIdWidths.forEach(([headerId, headerWidth], index) => {
|
||||
newColumnWidths[headerId] = Math.max(headerWidth + percentageDeltaX, 0)
|
||||
})
|
||||
|
||||
return {
|
||||
...state,
|
||||
columnResizing: {
|
||||
...state.columnResizing,
|
||||
columnWidths: {
|
||||
...state.columnResizing.columnWidths,
|
||||
...action.columnWidths,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.columnDoneResizing) {
|
||||
return {
|
||||
...state,
|
||||
columnResizing: {
|
||||
...state.columnResizing,
|
||||
startX: null,
|
||||
isResizingColumn: null,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const useResizeColumns = hooks => {
|
||||
hooks.useBeforeDimensions.push(useBeforeDimensions)
|
||||
}
|
||||
|
||||
useResizeColumns.pluginName = 'useResizeColumns'
|
||||
useResizeColumns.pluginName = pluginName
|
||||
|
||||
const useBeforeDimensions = instance => {
|
||||
instance.hooks.getResizerProps = []
|
||||
@ -24,7 +93,7 @@ const useBeforeDimensions = instance => {
|
||||
disableResizing,
|
||||
hooks: { getHeaderProps },
|
||||
state: { columnResizing },
|
||||
setState,
|
||||
dispatch,
|
||||
} = instance
|
||||
|
||||
getHeaderProps.push(() => {
|
||||
@ -37,60 +106,32 @@ const useBeforeDimensions = instance => {
|
||||
|
||||
const onMouseDown = (e, header) => {
|
||||
const headersToResize = getLeafHeaders(header)
|
||||
const startWidths = headersToResize.map(header => header.totalWidth)
|
||||
const startX = e.clientX
|
||||
const headerIdWidths = headersToResize.map(d => [d.id, d.totalWidth])
|
||||
|
||||
const clientX = e.clientX
|
||||
|
||||
const onMouseMove = e => {
|
||||
const currentX = e.clientX
|
||||
const deltaX = currentX - startX
|
||||
const clientX = e.clientX
|
||||
|
||||
const percentageDeltaX = deltaX / headersToResize.length
|
||||
|
||||
const newColumnWidths = {}
|
||||
headersToResize.forEach((header, index) => {
|
||||
newColumnWidths[header.id] = Math.max(
|
||||
startWidths[index] + percentageDeltaX,
|
||||
0
|
||||
)
|
||||
})
|
||||
|
||||
setState(old => ({
|
||||
...old,
|
||||
columnResizing: {
|
||||
...old.columnResizing,
|
||||
columnWidths: {
|
||||
...old.columnResizing.columnWidths,
|
||||
...newColumnWidths,
|
||||
},
|
||||
},
|
||||
}))
|
||||
dispatch({ type: actions.columnResizing, clientX })
|
||||
}
|
||||
|
||||
const onMouseUp = e => {
|
||||
document.removeEventListener('mousemove', onMouseMove)
|
||||
document.removeEventListener('mouseup', onMouseUp)
|
||||
|
||||
setState(old => ({
|
||||
...old,
|
||||
columnResizing: {
|
||||
...old.columnResizing,
|
||||
startX: null,
|
||||
isResizingColumn: null,
|
||||
},
|
||||
}))
|
||||
dispatch({ type: actions.columnDoneResizing })
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', onMouseMove)
|
||||
document.addEventListener('mouseup', onMouseUp)
|
||||
|
||||
setState(old => ({
|
||||
...old,
|
||||
columnResizing: {
|
||||
...old.columnResizing,
|
||||
startX,
|
||||
isResizingColumn: header.id,
|
||||
},
|
||||
}))
|
||||
dispatch({
|
||||
type: actions.columnStartResizing,
|
||||
columnId: header.id,
|
||||
headerIdWidths,
|
||||
clientX,
|
||||
})
|
||||
}
|
||||
|
||||
// use reference to avoid memory leak in #1608
|
||||
|
||||
@ -6,12 +6,113 @@ import {
|
||||
ensurePluginOrder,
|
||||
safeUseLayoutEffect,
|
||||
} from '../utils'
|
||||
import { addActions, actions } from '../actions'
|
||||
import { defaultState } from '../hooks/useTable'
|
||||
import { actions, reducerHandlers } from '../hooks/useTable'
|
||||
|
||||
defaultState.selectedRowPaths = []
|
||||
const pluginName = 'useRowSelect'
|
||||
|
||||
addActions('toggleRowSelected', 'toggleRowSelectedAll', 'setSelectedRowPaths')
|
||||
// Actions
|
||||
actions.resetSelectedRows = 'resetSelectedRows'
|
||||
actions.toggleRowSelectedAll = 'toggleRowSelectedAll'
|
||||
actions.toggleRowSelected = 'toggleRowSelected'
|
||||
|
||||
// Reducer
|
||||
reducerHandlers[pluginName] = (state, action) => {
|
||||
if (action.type === actions.init) {
|
||||
return {
|
||||
selectedRowPaths: [],
|
||||
...state,
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.resetSelectedRows) {
|
||||
return {
|
||||
...state,
|
||||
selectedRowPaths: [],
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.toggleRowSelectedAll) {
|
||||
const {
|
||||
selected,
|
||||
instanceRef: {
|
||||
current: { isAllRowsSelected, flatRowPaths },
|
||||
},
|
||||
} = action
|
||||
|
||||
const selectAll =
|
||||
typeof selected !== 'undefined' ? selected : !isAllRowsSelected
|
||||
|
||||
return {
|
||||
...state,
|
||||
selectedRowPaths: selectAll ? flatRowPaths : [],
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.toggleRowSelected) {
|
||||
const {
|
||||
path,
|
||||
selected,
|
||||
instanceRef: {
|
||||
current: { flatRowPaths },
|
||||
},
|
||||
} = action
|
||||
|
||||
const key = path.join('.')
|
||||
const childRowPrefixKey = [key, '.'].join('')
|
||||
|
||||
// Join the paths of deep rows
|
||||
// to make a key, then manage all of the keys
|
||||
// in a flat object
|
||||
const exists = state.selectedRowPaths.includes(key)
|
||||
const shouldExist = typeof set !== 'undefined' ? selected : !exists
|
||||
let newSelectedRows = new Set(state.selectedRowPaths)
|
||||
|
||||
if (!exists && shouldExist) {
|
||||
flatRowPaths.forEach(rowPath => {
|
||||
if (rowPath === key || rowPath.startsWith(childRowPrefixKey)) {
|
||||
newSelectedRows.add(rowPath)
|
||||
}
|
||||
})
|
||||
} else if (exists && !shouldExist) {
|
||||
flatRowPaths.forEach(rowPath => {
|
||||
if (rowPath === key || rowPath.startsWith(childRowPrefixKey)) {
|
||||
newSelectedRows.delete(rowPath)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return state
|
||||
}
|
||||
|
||||
const updateParentRow = (selectedRowPaths, path) => {
|
||||
const parentPath = path.slice(0, path.length - 1)
|
||||
const parentKey = parentPath.join('.')
|
||||
const selected =
|
||||
flatRowPaths.filter(rowPath => {
|
||||
const path = rowPath
|
||||
return (
|
||||
path !== parentKey &&
|
||||
path.startsWith(parentKey) &&
|
||||
!selectedRowPaths.has(path)
|
||||
)
|
||||
}).length === 0
|
||||
if (selected) {
|
||||
selectedRowPaths.add(parentKey)
|
||||
} else {
|
||||
selectedRowPaths.delete(parentKey)
|
||||
}
|
||||
if (parentPath.length > 1) updateParentRow(selectedRowPaths, parentPath)
|
||||
}
|
||||
|
||||
// If the row is a subRow update
|
||||
// its parent row to reflect changes
|
||||
if (path.length > 1) updateParentRow(newSelectedRows, path)
|
||||
|
||||
return {
|
||||
...state,
|
||||
selectedRowPaths: [...newSelectedRows.values()],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const useRowSelect = hooks => {
|
||||
hooks.getToggleRowSelectedProps = []
|
||||
@ -20,7 +121,7 @@ export const useRowSelect = hooks => {
|
||||
hooks.useMain.push(useMain)
|
||||
}
|
||||
|
||||
useRowSelect.pluginName = 'useRowSelect'
|
||||
useRowSelect.pluginName = pluginName
|
||||
|
||||
function useRows(rows, instance) {
|
||||
const {
|
||||
@ -54,7 +155,7 @@ function useMain(instance) {
|
||||
flatRows,
|
||||
getResetSelectedRowPathsDeps = defaultGetResetSelectedRowPathsDeps,
|
||||
state: { selectedRowPaths },
|
||||
setState,
|
||||
dispatch,
|
||||
} = instance
|
||||
|
||||
ensurePluginOrder(
|
||||
@ -78,90 +179,21 @@ function useMain(instance) {
|
||||
const isMountedRef = React.useRef()
|
||||
safeUseLayoutEffect(() => {
|
||||
if (isMountedRef.current) {
|
||||
setState(
|
||||
old => ({
|
||||
...old,
|
||||
selectedRowPaths: [],
|
||||
}),
|
||||
actions.setSelectedRowPaths
|
||||
)
|
||||
dispatch({ type: actions.resetSelectedRows })
|
||||
}
|
||||
isMountedRef.current = true
|
||||
}, [
|
||||
setState,
|
||||
dispatch,
|
||||
...(getResetSelectedRowPathsDeps
|
||||
? getResetSelectedRowPathsDeps(instance)
|
||||
: []),
|
||||
])
|
||||
|
||||
const toggleRowSelectedAll = set => {
|
||||
setState(old => {
|
||||
const selectAll = typeof set !== 'undefined' ? set : !isAllRowsSelected
|
||||
return {
|
||||
...old,
|
||||
selectedRowPaths: selectAll ? flatRowPaths : [],
|
||||
}
|
||||
}, actions.toggleRowSelectedAll)
|
||||
}
|
||||
const toggleRowSelectedAll = selected =>
|
||||
dispatch({ type: actions.toggleRowSelectedAll, selected })
|
||||
|
||||
const updateParentRow = (selectedRowPaths, path) => {
|
||||
const parentPath = path.slice(0, path.length - 1)
|
||||
const parentKey = parentPath.join('.')
|
||||
const selected =
|
||||
flatRowPaths.filter(rowPath => {
|
||||
const path = rowPath
|
||||
return (
|
||||
path !== parentKey &&
|
||||
path.startsWith(parentKey) &&
|
||||
!selectedRowPaths.has(path)
|
||||
)
|
||||
}).length === 0
|
||||
if (selected) {
|
||||
selectedRowPaths.add(parentKey)
|
||||
} else {
|
||||
selectedRowPaths.delete(parentKey)
|
||||
}
|
||||
if (parentPath.length > 1) updateParentRow(selectedRowPaths, parentPath)
|
||||
}
|
||||
|
||||
const toggleRowSelected = (path, set) => {
|
||||
const key = path.join('.')
|
||||
const childRowPrefixKey = [key, '.'].join('')
|
||||
|
||||
return setState(old => {
|
||||
// Join the paths of deep rows
|
||||
// to make a key, then manage all of the keys
|
||||
// in a flat object
|
||||
const exists = old.selectedRowPaths.includes(key)
|
||||
const shouldExist = typeof set !== 'undefined' ? set : !exists
|
||||
let newSelectedRows = new Set(old.selectedRowPaths)
|
||||
|
||||
if (!exists && shouldExist) {
|
||||
flatRowPaths.forEach(rowPath => {
|
||||
if (rowPath === key || rowPath.startsWith(childRowPrefixKey)) {
|
||||
newSelectedRows.add(rowPath)
|
||||
}
|
||||
})
|
||||
} else if (exists && !shouldExist) {
|
||||
flatRowPaths.forEach(rowPath => {
|
||||
if (rowPath === key || rowPath.startsWith(childRowPrefixKey)) {
|
||||
newSelectedRows.delete(rowPath)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
return old
|
||||
}
|
||||
|
||||
// If the row is a subRow update
|
||||
// its parent row to reflect changes
|
||||
if (path.length > 1) updateParentRow(newSelectedRows, path)
|
||||
|
||||
return {
|
||||
...old,
|
||||
selectedRowPaths: [...newSelectedRows.values()],
|
||||
}
|
||||
}, actions.toggleRowSelected)
|
||||
}
|
||||
const toggleRowSelected = (path, selected) =>
|
||||
dispatch({ type: actions.toggleRowSelected, path, selected })
|
||||
|
||||
// use reference to avoid memory leak in #1608
|
||||
const instanceRef = React.useRef()
|
||||
@ -217,13 +249,13 @@ function useMain(instance) {
|
||||
props
|
||||
)
|
||||
}
|
||||
// }
|
||||
|
||||
return row
|
||||
})
|
||||
|
||||
return {
|
||||
...instance,
|
||||
flatRowPaths,
|
||||
toggleRowSelected,
|
||||
toggleRowSelectedAll,
|
||||
getToggleAllRowsSelectedProps,
|
||||
|
||||
@ -1,48 +1,77 @@
|
||||
import React from 'react'
|
||||
|
||||
import { addActions, actions } from '../actions'
|
||||
import { defaultState } from '../hooks/useTable'
|
||||
//
|
||||
|
||||
defaultState.rowState = {}
|
||||
import { actions, reducerHandlers } from '../hooks/useTable'
|
||||
import { functionalUpdate, safeUseLayoutEffect } from '../utils'
|
||||
|
||||
addActions('setRowState', 'setCellState')
|
||||
const pluginName = 'useRowState'
|
||||
|
||||
// Actions
|
||||
actions.setRowState = 'setRowState'
|
||||
actions.resetRowState = 'resetRowState'
|
||||
|
||||
// Reducer
|
||||
reducerHandlers[pluginName] = (state, action) => {
|
||||
if (action.type === actions.init) {
|
||||
return {
|
||||
rowState: {},
|
||||
...state,
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.resetRowState) {
|
||||
return {
|
||||
...state,
|
||||
rowState: {},
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.setRowState) {
|
||||
const { path, value } = action
|
||||
|
||||
const pathKey = path.join('.')
|
||||
|
||||
return {
|
||||
...state,
|
||||
rowState: {
|
||||
...state.rowState,
|
||||
[pathKey]: functionalUpdate(value, state.rowState[pathKey]),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const useRowState = hooks => {
|
||||
hooks.useMain.push(useMain)
|
||||
}
|
||||
|
||||
useRowState.pluginName = 'useRowState'
|
||||
useRowState.pluginName = pluginName
|
||||
|
||||
const defaultGetResetRowStateDeps = ({ data }) => [data]
|
||||
|
||||
function useMain(instance) {
|
||||
const {
|
||||
hooks,
|
||||
rows,
|
||||
initialRowStateAccessor,
|
||||
getResetRowStateDeps = defaultGetResetRowStateDeps,
|
||||
state: { rowState },
|
||||
setState,
|
||||
dispatch,
|
||||
} = instance
|
||||
|
||||
const setRowState = React.useCallback(
|
||||
(path, updater, action = actions.setRowState) => {
|
||||
const pathKey = path.join('.')
|
||||
return setState(old => {
|
||||
return {
|
||||
...old,
|
||||
rowState: {
|
||||
...old.rowState,
|
||||
[pathKey]:
|
||||
typeof updater === 'function'
|
||||
? updater(old.rowState[pathKey])
|
||||
: updater,
|
||||
},
|
||||
}
|
||||
}, action)
|
||||
},
|
||||
[setState]
|
||||
(path, value, columnId) =>
|
||||
dispatch({
|
||||
type: actions.setRowState,
|
||||
path,
|
||||
value,
|
||||
columnId,
|
||||
}),
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
const setCellState = React.useCallback(
|
||||
(rowPath, columnID, updater) => {
|
||||
(rowPath, columnId, updater) => {
|
||||
return setRowState(
|
||||
rowPath,
|
||||
old => {
|
||||
@ -50,14 +79,14 @@ function useMain(instance) {
|
||||
...old,
|
||||
cellState: {
|
||||
...old.cellState,
|
||||
[columnID]:
|
||||
[columnId]:
|
||||
typeof updater === 'function'
|
||||
? updater(old.cellState[columnID])
|
||||
? updater(old.cellState[columnId])
|
||||
: updater,
|
||||
},
|
||||
}
|
||||
},
|
||||
actions.setCellState
|
||||
columnId
|
||||
)
|
||||
},
|
||||
[setRowState]
|
||||
@ -66,18 +95,16 @@ function useMain(instance) {
|
||||
const rowsMountedRef = React.useRef()
|
||||
|
||||
// When data changes, reset row and cell state
|
||||
React.useEffect(() => {
|
||||
safeUseLayoutEffect(() => {
|
||||
if (rowsMountedRef.current) {
|
||||
setState(old => {
|
||||
return {
|
||||
...old,
|
||||
rowState: {},
|
||||
}
|
||||
}, actions.setRowState)
|
||||
dispatch({ type: actions.resetRowState })
|
||||
}
|
||||
|
||||
rowsMountedRef.current = true
|
||||
}, [rows, setState])
|
||||
}, [
|
||||
dispatch,
|
||||
...(getResetRowStateDeps ? getResetRowStateDeps(instance) : []),
|
||||
])
|
||||
|
||||
hooks.prepareRow.push(row => {
|
||||
const pathKey = row.path.join('.')
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import React from 'react'
|
||||
|
||||
import { ensurePluginOrder, defaultColumn, safeUseLayoutEffect } from '../utils'
|
||||
import { addActions, actions } from '../actions'
|
||||
import { defaultState } from '../hooks/useTable'
|
||||
import { actions, reducerHandlers } from '../hooks/useTable'
|
||||
import * as sortTypes from '../sortTypes'
|
||||
import {
|
||||
mergeProps,
|
||||
@ -12,17 +11,148 @@ import {
|
||||
isFunction,
|
||||
} from '../utils'
|
||||
|
||||
defaultState.sortBy = []
|
||||
const pluginName = 'useSortBy'
|
||||
|
||||
// Actions
|
||||
actions.resetSortBy = 'resetSortBy'
|
||||
actions.toggleSortBy = 'toggleSortBy'
|
||||
actions.clearSortBy = 'clearSortBy'
|
||||
|
||||
// Reducer
|
||||
reducerHandlers[pluginName] = (state, action) => {
|
||||
if (action.type === actions.init) {
|
||||
return {
|
||||
sortBy: [],
|
||||
...state,
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.resetSortBy) {
|
||||
return {
|
||||
...state,
|
||||
sortBy: {},
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.clearSortBy) {
|
||||
const { sortBy } = state
|
||||
const newSortBy = sortBy.filter(d => d.id !== action.columnID)
|
||||
|
||||
return {
|
||||
...state,
|
||||
sortBy: newSortBy,
|
||||
}
|
||||
}
|
||||
|
||||
if (action.type === actions.toggleSortBy) {
|
||||
const {
|
||||
columnId,
|
||||
desc,
|
||||
multi,
|
||||
instanceRef: {
|
||||
current: {
|
||||
flatColumns,
|
||||
disableMultiSort,
|
||||
disableSortRemove,
|
||||
disableMultiRemove,
|
||||
maxMultiSortColCount = Number.MAX_SAFE_INTEGER,
|
||||
},
|
||||
},
|
||||
} = action
|
||||
const { sortBy } = state
|
||||
|
||||
// Find the column for this columnId
|
||||
const column = flatColumns.find(d => d.id === columnId)
|
||||
const { sortDescFirst } = column
|
||||
|
||||
// Find any existing sortBy for this column
|
||||
const existingSortBy = sortBy.find(d => d.id === columnId)
|
||||
const existingIndex = sortBy.findIndex(d => d.id === columnId)
|
||||
const hasDescDefined = typeof desc !== 'undefined' && desc !== null
|
||||
|
||||
let newSortBy = []
|
||||
|
||||
// What should we do with this sort action?
|
||||
let sortAction
|
||||
|
||||
if (!disableMultiSort && multi) {
|
||||
if (existingSortBy) {
|
||||
sortAction = 'toggle'
|
||||
} else {
|
||||
sortAction = 'add'
|
||||
}
|
||||
} else {
|
||||
// Normal mode
|
||||
if (existingIndex !== sortBy.length - 1) {
|
||||
sortAction = 'replace'
|
||||
} else if (existingSortBy) {
|
||||
sortAction = 'toggle'
|
||||
} else {
|
||||
sortAction = 'replace'
|
||||
}
|
||||
}
|
||||
|
||||
// Handle toggle states that will remove the sortBy
|
||||
if (
|
||||
sortAction === 'toggle' && // Must be toggling
|
||||
!disableSortRemove && // If disableSortRemove, disable in general
|
||||
!hasDescDefined && // Must not be setting desc
|
||||
(multi ? !disableMultiRemove : true) && // If multi, don't allow if disableMultiRemove
|
||||
((existingSortBy && // Finally, detect if it should indeed be removed
|
||||
existingSortBy.desc &&
|
||||
!sortDescFirst) ||
|
||||
(!existingSortBy.desc && sortDescFirst))
|
||||
) {
|
||||
sortAction = 'remove'
|
||||
}
|
||||
|
||||
if (sortAction === 'replace') {
|
||||
newSortBy = [
|
||||
{
|
||||
id: columnId,
|
||||
desc: hasDescDefined ? desc : sortDescFirst,
|
||||
},
|
||||
]
|
||||
} else if (sortAction === 'add') {
|
||||
newSortBy = [
|
||||
...sortBy,
|
||||
{
|
||||
id: columnId,
|
||||
desc: hasDescDefined ? desc : sortDescFirst,
|
||||
},
|
||||
]
|
||||
// Take latest n columns
|
||||
newSortBy.splice(0, newSortBy.length - maxMultiSortColCount)
|
||||
} else if (sortAction === 'toggle') {
|
||||
// This flips (or sets) the
|
||||
newSortBy = sortBy.map(d => {
|
||||
if (d.id === columnId) {
|
||||
return {
|
||||
...d,
|
||||
desc: hasDescDefined ? desc : !existingSortBy.desc,
|
||||
}
|
||||
}
|
||||
return d
|
||||
})
|
||||
} else if (sortAction === 'remove') {
|
||||
newSortBy = sortBy.filter(d => d.id !== columnId)
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
sortBy: newSortBy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defaultColumn.sortType = 'alphanumeric'
|
||||
defaultColumn.sortDescFirst = false
|
||||
|
||||
addActions('sortByChange')
|
||||
|
||||
export const useSortBy = hooks => {
|
||||
hooks.useMain.push(useMain)
|
||||
}
|
||||
|
||||
useSortBy.pluginName = 'useSortBy'
|
||||
useSortBy.pluginName = pluginName
|
||||
|
||||
function useMain(instance) {
|
||||
const {
|
||||
@ -34,15 +164,11 @@ function useMain(instance) {
|
||||
manualSorting,
|
||||
defaultCanSort,
|
||||
disableSortBy,
|
||||
disableSortRemove,
|
||||
disableMultiRemove,
|
||||
disableMultiSort,
|
||||
isMultiSortEvent = e => e.shiftKey,
|
||||
maxMultiSortColCount = Number.MAX_SAFE_INTEGER,
|
||||
flatHeaders,
|
||||
hooks,
|
||||
state: { sortBy },
|
||||
setState,
|
||||
dispatch,
|
||||
plugins,
|
||||
getResetSortByDeps = false,
|
||||
} = instance
|
||||
@ -55,104 +181,14 @@ function useMain(instance) {
|
||||
const isMountedRef = React.useRef()
|
||||
safeUseLayoutEffect(() => {
|
||||
if (isMountedRef.current) {
|
||||
setState(
|
||||
old => ({
|
||||
...old,
|
||||
sortBy: [],
|
||||
}),
|
||||
actions.sortByChange
|
||||
)
|
||||
dispatch({ type: actions.resetSortBy })
|
||||
}
|
||||
isMountedRef.current = true
|
||||
}, [setState, ...(getResetSortByDeps ? getResetSortByDeps(instance) : [])])
|
||||
}, [dispatch, ...(getResetSortByDeps ? getResetSortByDeps(instance) : [])])
|
||||
|
||||
// Updates sorting based on a columnID, desc flag and multi flag
|
||||
const toggleSortBy = (columnID, desc, multi) => {
|
||||
return setState(old => {
|
||||
const { sortBy } = old
|
||||
|
||||
// Find the column for this columnID
|
||||
const column = flatColumns.find(d => d.id === columnID)
|
||||
const { sortDescFirst } = column
|
||||
|
||||
// Find any existing sortBy for this column
|
||||
const existingSortBy = sortBy.find(d => d.id === columnID)
|
||||
const existingIndex = sortBy.findIndex(d => d.id === columnID)
|
||||
const hasDescDefined = typeof desc !== 'undefined' && desc !== null
|
||||
|
||||
let newSortBy = []
|
||||
|
||||
// What should we do with this sort action?
|
||||
let action
|
||||
|
||||
if (!disableMultiSort && multi) {
|
||||
if (existingSortBy) {
|
||||
action = 'toggle'
|
||||
} else {
|
||||
action = 'add'
|
||||
}
|
||||
} else {
|
||||
// Normal mode
|
||||
if (existingIndex !== sortBy.length - 1) {
|
||||
action = 'replace'
|
||||
} else if (existingSortBy) {
|
||||
action = 'toggle'
|
||||
} else {
|
||||
action = 'replace'
|
||||
}
|
||||
}
|
||||
|
||||
// Handle toggle states that will remove the sortBy
|
||||
if (
|
||||
action === 'toggle' && // Must be toggling
|
||||
!disableSortRemove && // If disableSortRemove, disable in general
|
||||
!hasDescDefined && // Must not be setting desc
|
||||
(multi ? !disableMultiRemove : true) && // If multi, don't allow if disableMultiRemove
|
||||
((existingSortBy && // Finally, detect if it should indeed be removed
|
||||
existingSortBy.desc &&
|
||||
!sortDescFirst) ||
|
||||
(!existingSortBy.desc && sortDescFirst))
|
||||
) {
|
||||
action = 'remove'
|
||||
}
|
||||
|
||||
if (action === 'replace') {
|
||||
newSortBy = [
|
||||
{
|
||||
id: columnID,
|
||||
desc: hasDescDefined ? desc : sortDescFirst,
|
||||
},
|
||||
]
|
||||
} else if (action === 'add') {
|
||||
newSortBy = [
|
||||
...sortBy,
|
||||
{
|
||||
id: columnID,
|
||||
desc: hasDescDefined ? desc : sortDescFirst,
|
||||
},
|
||||
]
|
||||
// Take latest n columns
|
||||
newSortBy.splice(0, newSortBy.length - maxMultiSortColCount)
|
||||
} else if (action === 'toggle') {
|
||||
// This flips (or sets) the
|
||||
newSortBy = sortBy.map(d => {
|
||||
if (d.id === columnID) {
|
||||
return {
|
||||
...d,
|
||||
desc: hasDescDefined ? desc : !existingSortBy.desc,
|
||||
}
|
||||
}
|
||||
return d
|
||||
})
|
||||
} else if (action === 'remove') {
|
||||
newSortBy = sortBy.filter(d => d.id !== columnID)
|
||||
}
|
||||
|
||||
return {
|
||||
...old,
|
||||
sortBy: newSortBy,
|
||||
}
|
||||
}, actions.sortByChange)
|
||||
// Updates sorting based on a columnId, desc flag and multi flag
|
||||
const toggleSortBy = (columnId, desc, multi) => {
|
||||
dispatch({ type: actions.toggleSortBy, columnId, desc, multi })
|
||||
}
|
||||
|
||||
// use reference to avoid memory leak in #1608
|
||||
@ -182,15 +218,8 @@ function useMain(instance) {
|
||||
column.toggleSortBy = (desc, multi) =>
|
||||
toggleSortBy(column.id, desc, multi)
|
||||
|
||||
column.clearSorting = () => {
|
||||
return setState(old => {
|
||||
const { sortBy } = old
|
||||
const newSortBy = sortBy.filter(d => d.id !== column.id)
|
||||
return {
|
||||
...old,
|
||||
sortBy: newSortBy,
|
||||
}
|
||||
}, actions.sortByChange)
|
||||
column.clearSortBy = () => {
|
||||
dispatch({ type: actions.clearSortBy, columnId: column.id })
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,7 +259,7 @@ function useMain(instance) {
|
||||
if (manualSorting || !sortBy.length) {
|
||||
return rows
|
||||
}
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.time('getSortedRows')
|
||||
|
||||
// Filter out sortBys that correspond to non existing columns
|
||||
@ -302,7 +331,7 @@ function useMain(instance) {
|
||||
return sortedData
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'development' && debug)
|
||||
if (process.env.NODE_ENV !== 'production' && debug)
|
||||
console.timeEnd('getSortedRows')
|
||||
|
||||
return sortData(rows)
|
||||
|
||||
@ -3,9 +3,9 @@ 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 = getRowValueByColumnID(rowA, columnID)
|
||||
let b = getRowValueByColumnID(rowB, columnID)
|
||||
export const alphanumeric = (rowA, rowB, columnId) => {
|
||||
let a = getRowValueByColumnID(rowA, columnId)
|
||||
let b = getRowValueByColumnID(rowB, columnId)
|
||||
// Force to strings (or "" for unsupported types)
|
||||
a = toString(a)
|
||||
b = toString(b)
|
||||
@ -53,9 +53,9 @@ export const alphanumeric = (rowA, rowB, columnID) => {
|
||||
return a.length - b.length
|
||||
}
|
||||
|
||||
export function datetime(rowA, rowB, columnID) {
|
||||
let a = getRowValueByColumnID(rowA, columnID)
|
||||
let b = getRowValueByColumnID(rowB, columnID)
|
||||
export function datetime(rowA, rowB, columnId) {
|
||||
let a = getRowValueByColumnID(rowA, columnId)
|
||||
let b = getRowValueByColumnID(rowB, columnId)
|
||||
|
||||
a = a.getTime()
|
||||
b = b.getTime()
|
||||
@ -63,9 +63,9 @@ export function datetime(rowA, rowB, columnID) {
|
||||
return compareBasic(a, b)
|
||||
}
|
||||
|
||||
export function basic(rowA, rowB, columnID) {
|
||||
let a = getRowValueByColumnID(rowA, columnID)
|
||||
let b = getRowValueByColumnID(rowB, columnID)
|
||||
export function basic(rowA, rowB, columnId) {
|
||||
let a = getRowValueByColumnID(rowA, columnId)
|
||||
let b = getRowValueByColumnID(rowB, columnId)
|
||||
|
||||
return compareBasic(a, b)
|
||||
}
|
||||
@ -76,8 +76,8 @@ function compareBasic(a, b) {
|
||||
return a === b ? 0 : a > b ? 1 : -1
|
||||
}
|
||||
|
||||
function getRowValueByColumnID(row, columnID) {
|
||||
return row.values[columnID]
|
||||
function getRowValueByColumnID(row, columnId) {
|
||||
return row.values[columnId]
|
||||
}
|
||||
|
||||
function toString(a) {
|
||||
|
||||
22
src/utils.js
22
src/utils.js
@ -113,24 +113,24 @@ export function makeHeaderGroups(flatColumns, defaultColumn) {
|
||||
// If the column has a parent, add it if necessary
|
||||
if (column.parent) {
|
||||
const similarParentColumns = parentColumns.filter(
|
||||
d => d.originalID === column.parent.id
|
||||
d => d.originalId === column.parent.id
|
||||
)
|
||||
if (isFirst || latestParentColumn.originalID !== column.parent.id) {
|
||||
if (isFirst || latestParentColumn.originalId !== column.parent.id) {
|
||||
parentColumns.push({
|
||||
...column.parent,
|
||||
originalID: column.parent.id,
|
||||
originalId: column.parent.id,
|
||||
id: [column.parent.id, similarParentColumns.length].join('_'),
|
||||
})
|
||||
}
|
||||
} else if (hasParents) {
|
||||
// If other columns have parents, we'll need to add a place holder if necessary
|
||||
const originalID = [column.id, 'placeholder'].join('_')
|
||||
const originalId = [column.id, 'placeholder'].join('_')
|
||||
const similarParentColumns = parentColumns.filter(
|
||||
d => d.originalID === originalID
|
||||
d => d.originalId === originalId
|
||||
)
|
||||
const placeholderColumn = decorateColumn(
|
||||
{
|
||||
originalID,
|
||||
originalId,
|
||||
id: [column.id, 'placeholder', similarParentColumns.length].join(
|
||||
'_'
|
||||
),
|
||||
@ -140,7 +140,7 @@ export function makeHeaderGroups(flatColumns, defaultColumn) {
|
||||
)
|
||||
if (
|
||||
isFirst ||
|
||||
latestParentColumn.originalID !== placeholderColumn.originalID
|
||||
latestParentColumn.originalId !== placeholderColumn.originalId
|
||||
) {
|
||||
parentColumns.push(placeholderColumn)
|
||||
}
|
||||
@ -245,11 +245,11 @@ export function getFirstDefined(...args) {
|
||||
}
|
||||
}
|
||||
|
||||
export function defaultGroupByFn(rows, columnID) {
|
||||
export function defaultGroupByFn(rows, columnId) {
|
||||
return rows.reduce((prev, row, i) => {
|
||||
// TODO: Might want to implement a key serializer here so
|
||||
// irregular column values can still be grouped if needed?
|
||||
const resKey = `${row.values[columnID]}`
|
||||
const resKey = `${row.values[columnId]}`
|
||||
prev[resKey] = Array.isArray(prev[resKey]) ? prev[resKey] : []
|
||||
prev[resKey].push(row)
|
||||
return prev
|
||||
@ -438,6 +438,10 @@ export function expandRows(
|
||||
return expandedRows
|
||||
}
|
||||
|
||||
export function functionalUpdate(updater, old) {
|
||||
return typeof updater === 'function' ? updater(old) : updater
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
function makePathArray(obj) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user