Compare commits

...
Author SHA1 Message Date
Tanner Linsley b02701058b v7.0.0-rc.15 2019-12-18 13:24:38 -07:00
Tanner Linsley d18f1ba4d8 Add global filtering support via useGlobalFilter 2019-12-18 13:22:58 -07:00
Tanner Linsley 63d54b1e87 v7.0.0-rc.14 2019-12-18 11:55:16 -07:00
Tanner Linsley 6e853a3cff Merge branch 'master' of https://github.com/react-tools/react-table 2019-12-18 11:54:57 -07:00
Tanner Linsley 30a40aa0a2 Change meta signature for hooks 2019-12-18 11:54:43 -07:00
size-plugin[bot] a8e1b33284 😍 🤵🏽‍♂️ update sizes-es.json 👍 2019-12-18 17:42:06 +00:00
size-plugin[bot] 67ce7d8f0b 🧖🏽 👵 update sizes-cjs.json 👍 2019-12-18 17:42:05 +00:00
30 changed files with 1335 additions and 409 deletions
+7 -7
View File
@@ -1,20 +1,20 @@
{
"dist/index.js": {
"bundled": 107717,
"minified": 49867,
"gzipped": 13333
"bundled": 112754,
"minified": 52324,
"gzipped": 13765
},
"dist/index.es.js": {
"bundled": 106806,
"minified": 49055,
"gzipped": 13168,
"bundled": 111817,
"minified": 51488,
"gzipped": 13599,
"treeshaked": {
"rollup": {
"code": 80,
"import_statements": 21
},
"webpack": {
"code": 8239
"code": 8484
}
}
},
+13
View File
@@ -1,3 +1,16 @@
## 7.0.0-rc.15
- Added `useGlobalFilter` hook for performing table-wide filtering
- Filter function signature has changed to supply an array of column IDs (to support both the tranditional single column style and the new multi-column search style introduced with `useGlobalFilter`).
- Removed the `column` parameter from the filter function signature as it was unused and no longer made sense with the array of IDs change above.
- Updated the `filtering` example to use a global filter in addition to the column filters
## 7.0.0-rc.14
- Changed the function signature for all propGetter hooks to accept a single object of named meta properties instead of a variable length of meta arguments. The user props object has also been added as a property to all prop getters. For example, `hooks.getRowProps.push((props, instance, row) => [...])` is now written `hooks.getRowProps.push((props, { instance, row, userProps }) => [...])`
- Changed the function signature for all reduceHooks accept a single object of named meta properties instead of a variable length of meta arguments. For example, `hooks.flatColumns.push((flatColumns, instance) => flatColumns)` is now written `hooks.flatColumns.push((flatColumns, { instance }) => flatColumns)`
- Changed the function signature for all loopHooks accept a single object of named meta properties instead of a variable length of meta arguments. For example, `hooks.prepareRow.push((row, instance) => void)` is now written `hooks.prepareRow.push((row { instance }) => void)`
## 7.0.0-rc.13
- Added the `useControlledState` hook for plugins to manipulate the final state of the table similar to how users can
+1 -1
View File
@@ -3,7 +3,7 @@
- Plugin Hook
- Optional
`useFilters` is the hook that implements **row filtering**.
`useFilters` is the hook that implements **row filtering** and can even be used in conjunction with `useGlobalFilter`. It's also important to note that this hook can be used either **before or after** `useGlobalFilter`, depending on the performance characteristics you want to code for.
### Table Options
+52
View File
@@ -0,0 +1,52 @@
# `useGlobalFilter`
- Plugin Hook
- Optional
`useGlobalFilter` is the hook that implements **global row filtering** and can even be used in conjunction with `useFilters`. It's also important to note that this hook can be used either **before or after** `useFilters`, depending on the performance characteristics you want to code for.
### Table Options
The following options are supported via the main options object passed to `useTable(options)`
- `initialState.globalFilter: any`
- Must be **memoized**
- An array of objects containing 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.
- `globalFilter: String | Function`
- Optional
- Defaults to `text`
- The resolved function from the this string/function will be used to filter the table's data.
- If a `string` is passed, the function with that name located on either the custom `filterTypes` option or the built-in filtering types object will be used. If
- If a `function` is passed, it will be used directly.
- For more information on filter types, see Filtering
- If a **function** is passed, it must be **memoized**
- `manualGlobalFilter: Bool`
- Enables filter detection functionality, but does not automatically perform row filtering.
- Turn this on if you wish to implement your own row filter outside of the table (eg. server-side or manual row grouping/nesting)
- `filterTypes: Object<filterKey: filterType>`
- Must be **memoized**
- Allows overriding or adding additional filter types for the table to use. If the globalFilter type isn't found on this object, it will default to using the built-in filter types.
- For more information on filter types, see Filtering
- `autoResetGlobalFilter: Boolean`
- Defaults to `true`
- When `true`, the `globalFilter` state will automatically reset if any of the following conditions are met:
- `data` is changed
- To disable, set to `false`
- For more information see the FAQ ["How do I stop my table state from automatically resetting when my data changes?"](./faq#how-do-i-stop-my-table-state-from-automatically-resetting-when-my-data-changes)
### Instance Properties
The following values are provided to the table `instance`:
- `rows: Array<Row>`
- An array of **filtered** rows.
- `preGlobalFilteredRows: 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.
- `setGlobalFilter: Function(columnId, filterValue) => void`
- An instance-level function used to update the filter value for a specific column.
### Example
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/filtering)
- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/filtering)
+61 -20
View File
@@ -1,6 +1,6 @@
import React from 'react'
import styled from 'styled-components'
import { useTable, useFilters } from 'react-table'
import { useTable, useFilters, useGlobalFilter } from 'react-table'
// A great library for fuzzy filtering/sorting items
import matchSorter from 'match-sorter'
@@ -35,6 +35,32 @@ const Styles = styled.div`
}
`
// Define a default UI for filtering
function GlobalFilter({
preGlobalFilteredRows,
globalFilter,
setGlobalFilter,
}) {
const count = preGlobalFilteredRows.length
return (
<span>
Search:{' '}
<input
value={globalFilter || ''}
onChange={e => {
setGlobalFilter(e.target.value || undefined) // Set undefined to remove the filter entirely
}}
placeholder={`${count} records...`}
style={{
fontSize: '1.1rem',
border: '0',
}}
/>
</span>
)
}
// Define a default UI for filtering
function DefaultColumnFilter({
column: { filterValue, preFilteredRows, setFilter },
@@ -217,6 +243,9 @@ function Table({ columns, data }) {
rows,
prepareRow,
state,
flatColumns,
preGlobalFilteredRows,
setGlobalFilter,
} = useTable(
{
columns,
@@ -224,7 +253,8 @@ function Table({ columns, data }) {
defaultColumn, // Be sure to pass the defaultColumn option
filterTypes,
},
useFilters // useFilters!
useFilters, // useFilters!
useGlobalFilter // useGlobalFilter!
)
// We don't want to render all of the rows for this example, so cap
@@ -233,11 +263,6 @@ function Table({ columns, data }) {
return (
<>
<div>
<pre>
<code>{JSON.stringify(state.filters, null, 2)}</code>
</pre>
</div>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
@@ -251,25 +276,41 @@ function Table({ columns, data }) {
))}
</tr>
))}
<tr>
<th
colSpan={flatColumns.length}
style={{
textAlign: 'left',
}}
>
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={state.globalFilter}
setGlobalFilter={setGlobalFilter}
/>
</th>
</tr>
</thead>
<tbody {...getTableBodyProps()}>
{firstPageRows.map(
(row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
)
})}
</tr>
)}
)}
{firstPageRows.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
<br />
<div>Showing the first 20 results of {rows.length} rows</div>
<div>
<pre>
<code>{JSON.stringify(state.filters, null, 2)}</code>
</pre>
</div>
</>
)
}
+4 -4
View File
@@ -8094,10 +8094,10 @@ react-scripts@3.0.1:
optionalDependencies:
fsevents "2.0.6"
react-table@next:
version "7.0.0-alpha.7"
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.0.0-alpha.7.tgz#0cb6da6f32adb397e68505b7cdd4880d15d73017"
integrity sha512-oXE9RRkE2CFk1OloNCSTPQ9qxOdujgkCoW5b/srbJsBog/ySkWuozBTQkxH1wGNmnSxGyTrTxJqXdXPQam7VAw==
react-table@latest:
version "7.0.0-rc.14"
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.0.0-rc.14.tgz#bb4171fbdd56d78dd5f6b9e18694a36c00bd6261"
integrity sha512-9NyzAE0kLH8HA+DK86ynxVDxniO5ZdggAqI7nDKauWXQGVYNFId8+JJSescJ2vwP9nR2JKyCEDG9c+CjIaLNkA==
react@^16.8.6:
version "16.8.6"
+2 -2
View File
@@ -33,7 +33,7 @@ const Styles = styled.div`
}
`
function useControlledState(state, instance) {
function useControlledState(state, { instance }) {
return React.useMemo(() => {
if (state.groupBy.length) {
return {
@@ -65,7 +65,7 @@ function Table({ columns, data }) {
// Our custom plugin to add the expander column
hooks => {
hooks.useControlledState.push(useControlledState)
hooks.flatColumns.push((columns, instance) => {
hooks.flatColumns.push((columns, { instance }) => {
if (!instance.state.groupBy.length) {
return columns
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "react-table",
"version": "7.0.0-rc.13",
"version": "7.0.0-rc.15",
"description": "Hooks for building lightweight, fast and extendable datagrids for React",
"license": "MIT",
"homepage": "https://github.com/tannerlinsley/react-table#readme",
+3 -3
View File
@@ -1,11 +1,11 @@
[
{
"timestamp": 1576641254453,
"timestamp": 1576690899177,
"files": [
{
"filename": "index.js",
"size": 22403,
"delta": 49
"size": 22438,
"delta": 35
}
]
}
+3 -3
View File
@@ -1,11 +1,11 @@
[
{
"timestamp": 1576641263002,
"timestamp": 1576690906689,
"files": [
{
"filename": "index.es.js",
"size": 22202,
"delta": 49
"size": 22235,
"delta": 33
}
]
}
+51 -35
View File
@@ -1,79 +1,93 @@
export const text = (rows, id, filterValue) => {
export const text = (rows, ids, filterValue) => {
rows = rows.filter(row => {
const rowValue = row.values[id]
return String(rowValue)
.toLowerCase()
.includes(String(filterValue).toLowerCase())
return ids.some(id => {
const rowValue = row.values[id]
return String(rowValue)
.toLowerCase()
.includes(String(filterValue).toLowerCase())
})
})
return rows
}
text.autoRemove = val => !val
export const exactText = (rows, id, filterValue) => {
export const exactText = (rows, ids, filterValue) => {
return rows.filter(row => {
const rowValue = row.values[id]
return rowValue !== undefined
? String(rowValue).toLowerCase() === String(filterValue).toLowerCase()
: true
return ids.some(id => {
const rowValue = row.values[id]
return rowValue !== undefined
? String(rowValue).toLowerCase() === String(filterValue).toLowerCase()
: true
})
})
}
exactText.autoRemove = val => !val
export const exactTextCase = (rows, id, filterValue) => {
export const exactTextCase = (rows, ids, filterValue) => {
return rows.filter(row => {
const rowValue = row.values[id]
return rowValue !== undefined
? String(rowValue) === String(filterValue)
: true
return ids.some(id => {
const rowValue = row.values[id]
return rowValue !== undefined
? String(rowValue) === String(filterValue)
: true
})
})
}
exactTextCase.autoRemove = val => !val
export const includes = (rows, id, filterValue) => {
export const includes = (rows, ids, filterValue) => {
return rows.filter(row => {
const rowValue = row.values[id]
return filterValue.includes(rowValue)
return ids.some(id => {
const rowValue = row.values[id]
return filterValue.includes(rowValue)
})
})
}
includes.autoRemove = val => !val || !val.length
export const includesAll = (rows, id, filterValue) => {
export const includesAll = (rows, ids, filterValue) => {
return rows.filter(row => {
const rowValue = row.values[id]
return (
rowValue &&
rowValue.length &&
filterValue.every(val => rowValue.includes(val))
)
return ids.some(id => {
const rowValue = row.values[id]
return (
rowValue &&
rowValue.length &&
filterValue.every(val => rowValue.includes(val))
)
})
})
}
includesAll.autoRemove = val => !val || !val.length
export const exact = (rows, id, filterValue) => {
export const exact = (rows, ids, filterValue) => {
return rows.filter(row => {
const rowValue = row.values[id]
return rowValue === filterValue
return ids.some(id => {
const rowValue = row.values[id]
return rowValue === filterValue
})
})
}
exact.autoRemove = val => typeof val === 'undefined'
export const equals = (rows, id, filterValue) => {
export const equals = (rows, ids, filterValue) => {
return rows.filter(row => {
const rowValue = row.values[id]
// eslint-disable-next-line eqeqeq
return rowValue == filterValue
return ids.some(id => {
const rowValue = row.values[id]
// eslint-disable-next-line eqeqeq
return rowValue == filterValue
})
})
}
equals.autoRemove = val => val == null
export const between = (rows, id, filterValue) => {
export const between = (rows, ids, filterValue) => {
let [min, max] = filterValue || []
min = typeof min === 'number' ? min : -Infinity
@@ -86,8 +100,10 @@ export const between = (rows, id, filterValue) => {
}
return rows.filter(row => {
const rowValue = row.values[id]
return rowValue >= min && rowValue <= max
return ids.some(id => {
const rowValue = row.values[id]
return rowValue >= min && rowValue <= max
})
})
}
+8 -11
View File
@@ -19,7 +19,7 @@ export const useColumnVisibility = hooks => {
hooks.stateReducers.push(reducer)
hooks.useInstanceBeforeDimensions.push(useInstanceBeforeDimensions)
hooks.headerGroupsDeps.push((deps, instance) => [
hooks.headerGroupsDeps.push((deps, { instance }) => [
...deps,
instance.state.hiddenColumns,
])
@@ -28,7 +28,7 @@ export const useColumnVisibility = hooks => {
useColumnVisibility.pluginName = 'useColumnVisibility'
const defaultGetToggleHiddenProps = (props, instance, column) => [
const defaultGetToggleHiddenProps = (props, { column }) => [
props,
{
onChange: e => {
@@ -42,7 +42,7 @@ const defaultGetToggleHiddenProps = (props, instance, column) => [
},
]
const defaultGetToggleHideAllColumnsProps = (props, instance) => [
const defaultGetToggleHideAllColumnsProps = (props, { instance }) => [
props,
{
onChange: e => {
@@ -79,8 +79,6 @@ function reducer(state, action, previousState, instance) {
? action.value
: !state.hiddenColumns.includes(action.columnId)
console.log(action, should)
const hiddenColumns = should
? [...state.hiddenColumns, action.columnId]
: state.hiddenColumns.filter(d => d !== action.columnId)
@@ -184,7 +182,7 @@ function useInstance(instance) {
const getToggleHideAllColumnsProps = makePropGetter(
getToggleHideAllColumnsPropsHooks(),
getInstance()
{ instance: getInstance() }
)
// Snapshot hook and disallow more from being added
@@ -202,11 +200,10 @@ function useInstance(instance) {
})
}
column.getToggleHiddenProps = makePropGetter(
getToggleHiddenPropsHooks(),
getInstance(),
column
)
column.getToggleHiddenProps = makePropGetter(getToggleHiddenPropsHooks(), {
instance: getInstance(),
column,
})
})
Object.assign(instance, {
+40 -43
View File
@@ -143,7 +143,7 @@ export const useTable = (props, ...plugins) => {
const state = reduceHooks(
[...getUseControlledStateHooks(), useControlledState],
reducerState,
getInstance()
{ instance: getInstance() }
)
Object.assign(getInstance(), {
@@ -164,7 +164,9 @@ export const useTable = (props, ...plugins) => {
let columns = React.useMemo(
() =>
decorateColumnTree(
reduceHooks(getColumnsHooks(), userColumns, getInstance()),
reduceHooks(getColumnsHooks(), userColumns, {
instance: getInstance(),
}),
defaultColumn
),
[
@@ -173,7 +175,7 @@ export const useTable = (props, ...plugins) => {
getInstance,
userColumns,
// eslint-disable-next-line react-hooks/exhaustive-deps
...reduceHooks(getColumnsDepsHooks(), [], getInstance()),
...reduceHooks(getColumnsDepsHooks(), [], { instance: getInstance() }),
]
)
@@ -263,13 +265,14 @@ export const useTable = (props, ...plugins) => {
// have been access, and allow hooks to decorate
// those columns (and trigger this memoization via deps)
flatColumns = React.useMemo(
() => reduceHooks(flatColumnsHooks(), flatColumns, getInstance()),
() =>
reduceHooks(flatColumnsHooks(), flatColumns, { instance: getInstance() }),
[
flatColumns,
flatColumnsHooks,
getInstance,
// eslint-disable-next-line react-hooks/exhaustive-deps
...reduceHooks(flatColumnsDepsHooks(), [], getInstance()),
...reduceHooks(flatColumnsDepsHooks(), [], { instance: getInstance() }),
]
)
@@ -301,7 +304,7 @@ export const useTable = (props, ...plugins) => {
getHeaderGroups,
getInstance,
// eslint-disable-next-line react-hooks/exhaustive-deps
...reduceHooks(getHeaderGroupsDeps(), [], getInstance()),
...reduceHooks(getHeaderGroupsDeps(), [], { instance: getInstance() }),
]
)
@@ -367,18 +370,16 @@ export const useTable = (props, ...plugins) => {
column.render = makeRenderer(getInstance(), column)
// Give columns/headers a default getHeaderProps
column.getHeaderProps = makePropGetter(
getHeaderPropsHooks(),
getInstance(),
column
)
column.getHeaderProps = makePropGetter(getHeaderPropsHooks(), {
instance: getInstance(),
column,
})
// Give columns/headers a default getFooterProps
column.getFooterProps = makePropGetter(
getFooterPropsHooks(),
getInstance(),
column
)
column.getFooterProps = makePropGetter(getFooterPropsHooks(), {
instance: getInstance(),
column,
})
}
)
@@ -415,16 +416,12 @@ export const useTable = (props, ...plugins) => {
if (headerGroup.headers.length) {
headerGroup.getHeaderGroupProps = makePropGetter(
getHeaderGroupPropsHooks(),
getInstance(),
headerGroup,
i
{ instance: getInstance(), headerGroup, index: i }
)
headerGroup.getFooterGroupProps = makePropGetter(
getFooterGroupPropsHooks(),
getInstance(),
headerGroup,
i
{ instance: getInstance(), headerGroup, index: i }
)
return true
@@ -441,11 +438,9 @@ export const useTable = (props, ...plugins) => {
// Snapshot hook and disallow more from being added
const getUseRowsHooks = useConsumeHookGetter(getInstance().hooks, 'useRows')
getInstance().rows = reduceHooks(
getUseRowsHooks(),
getInstance().rows,
getInstance()
)
getInstance().rows = reduceHooks(getUseRowsHooks(), getInstance().rows, {
instance: getInstance(),
})
// The prepareRow function is absolutely necessary and MUST be called on
// any rows the user wishes to be displayed.
@@ -473,7 +468,10 @@ export const useTable = (props, ...plugins) => {
getInstance().prepareRow = React.useCallback(
row => {
row.getRowProps = makePropGetter(getRowPropsHooks(), getInstance(), row)
row.getRowProps = makePropGetter(getRowPropsHooks(), {
instance: getInstance(),
row,
})
// Build the visible cells for each row
row.allCells = flatColumns.map(column => {
@@ -484,11 +482,10 @@ export const useTable = (props, ...plugins) => {
}
// Give each cell a getCellProps base
cell.getCellProps = makePropGetter(
getCellPropsHooks(),
getInstance(),
cell
)
cell.getCellProps = makePropGetter(getCellPropsHooks(), {
instance: getInstance(),
cell,
})
// Give each cell a renderer function (supports multiple renderers)
cell.render = makeRenderer(getInstance(), column, {
@@ -499,10 +496,12 @@ export const useTable = (props, ...plugins) => {
return cell
})
row.cells = reduceHooks(cellsHooks(), row.allCells, getInstance())
row.cells = reduceHooks(cellsHooks(), row.allCells, {
instance: getInstance(),
})
// need to apply any row specific hooks (useExpanded requires this)
loopHooks(getPrepareRowHooks(), row, getInstance())
loopHooks(getPrepareRowHooks(), row, { instance: getInstance() })
},
[
getRowPropsHooks,
@@ -520,10 +519,9 @@ export const useTable = (props, ...plugins) => {
'getTableProps'
)
getInstance().getTableProps = makePropGetter(
getTablePropsHooks(),
getInstance()
)
getInstance().getTableProps = makePropGetter(getTablePropsHooks(), {
instance: getInstance(),
})
// Snapshot hook and disallow more from being added
const getTableBodyPropsHooks = useConsumeHookGetter(
@@ -531,10 +529,9 @@ export const useTable = (props, ...plugins) => {
'getTableBodyProps'
)
getInstance().getTableBodyProps = makePropGetter(
getTableBodyPropsHooks(),
getInstance()
)
getInstance().getTableBodyProps = makePropGetter(getTableBodyPropsHooks(), {
instance: getInstance(),
})
// Snapshot hook and disallow more from being added
const getUseFinalInstanceHooks = useConsumeHookGetter(
+1
View File
@@ -2,6 +2,7 @@ export * from './publicUtils'
export { useTable } from './hooks/useTable'
export { useExpanded } from './plugin-hooks/useExpanded'
export { useFilters } from './plugin-hooks/useFilters'
export { useGlobalFilter } from './plugin-hooks/useGlobalFilter'
export { useGroupBy } from './plugin-hooks/useGroupBy'
export { useSortBy } from './plugin-hooks/useSortBy'
export { usePagination } from './plugin-hooks/usePagination'
+6 -6
View File
@@ -1,33 +1,33 @@
const defaultCells = cell => cell.filter(d => d.column.isVisible)
const defaultGetHeaderProps = (props, instance, column) => ({
const defaultGetHeaderProps = (props, { column }) => ({
key: `header_${column.id}`,
colSpan: column.totalVisibleHeaderCount,
...props,
})
const defaultGetFooterProps = (props, instance, column) => ({
const defaultGetFooterProps = (props, { column }) => ({
key: `footer_${column.id}`,
colSpan: column.totalVisibleHeaderCount,
...props,
})
const defaultGetHeaderGroupProps = (props, instance, headerGroup, index) => ({
const defaultGetHeaderGroupProps = (props, { index }) => ({
key: `headerGroup_${index}`,
...props,
})
const defaultGetFooterGroupProps = (props, instance, headerGroup, index) => ({
const defaultGetFooterGroupProps = (props, { index }) => ({
key: `footerGroup_${index}`,
...props,
})
const defaultGetRowProps = (props, instance, row) => ({
const defaultGetRowProps = (props, { row }) => ({
key: `row_${row.id}`,
...props,
})
const defaultGetCellProps = (props, instance, cell) => ({
const defaultGetCellProps = (props, { cell }) => ({
...props,
key: `cell_${cell.row.id}_${cell.column.id}`,
})
@@ -1,151 +1,766 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders a filterable table 1`] = `
Snapshot Diff:
- First value
+ Second value
@@ -27,11 +27,11 @@
colspan="1"
>
Last Name
<DocumentFragment>
<table>
<thead>
<tr>
<th
colspan="2"
>
Name
</th>
<th
colspan="4"
>
Info
</th>
</tr>
<tr>
<th
colspan="1"
>
First Name
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Last Name
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Age
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Visits
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Status
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Profile Progress
<input
placeholder="Search..."
value=""
/>
</th>
</tr>
<tr>
<th
colspan="6"
style="text-align: left;"
>
<span>
<input
placeholder="Search..."
- value=""
+ value="l"
placeholder="Global search..."
style="font-size: 1.1rem; border: 0px;"
value=""
/>
</th>
<th
colspan="1"
>
@@ -87,50 +87,10 @@
<td>
status: In Relationship
</td>
<td>
progress: 50
- </td>
- </tr>
- <tr>
- <td>
- firstName: derek
- </td>
- <td>
- lastName: perkins
- </td>
- <td>
- age: 40
- </td>
- <td>
- visits: 40
- </td>
- <td>
- status: Single
- </td>
- <td>
- progress: 80
- </td>
- </tr>
- <tr>
- <td>
- firstName: joe
- </td>
- <td>
- lastName: bergevin
- </td>
- <td>
- age: 45
- </td>
- <td>
- visits: 20
- </td>
- <td>
- status: Complicated
- </td>
- <td>
- progress: 10
</td>
</tr>
<tr>
<td>
firstName: jaylen
</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
firstName: tanner
</td>
<td>
lastName: linsley
</td>
<td>
age: 29
</td>
<td>
visits: 100
</td>
<td>
status: In Relationship
</td>
<td>
progress: 50
</td>
</tr>
<tr>
<td>
firstName: derek
</td>
<td>
lastName: perkins
</td>
<td>
age: 40
</td>
<td>
visits: 40
</td>
<td>
status: Single
</td>
<td>
progress: 80
</td>
</tr>
<tr>
<td>
firstName: joe
</td>
<td>
lastName: bergevin
</td>
<td>
age: 45
</td>
<td>
visits: 20
</td>
<td>
status: Complicated
</td>
<td>
progress: 10
</td>
</tr>
<tr>
<td>
firstName: jaylen
</td>
<td>
lastName: linsley
</td>
<td>
age: 26
</td>
<td>
visits: 99
</td>
<td>
status: In Relationship
</td>
<td>
progress: 70
</td>
</tr>
</tbody>
</table>
</DocumentFragment>
`;
exports[`renders a filterable table 2`] = `
Snapshot Diff:
- First value
+ Second value
@@ -27,11 +27,11 @@
colspan="1"
>
Last Name
<DocumentFragment>
<table>
<thead>
<tr>
<th
colspan="2"
>
Name
</th>
<th
colspan="4"
>
Info
</th>
</tr>
<tr>
<th
colspan="1"
>
First Name
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Last Name
<input
placeholder="Search..."
value="l"
/>
</th>
<th
colspan="1"
>
Age
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Visits
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Status
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Profile Progress
<input
placeholder="Search..."
value=""
/>
</th>
</tr>
<tr>
<th
colspan="6"
style="text-align: left;"
>
<span>
<input
placeholder="Search..."
- value="l"
+ value="er"
placeholder="Global search..."
style="font-size: 1.1rem; border: 0px;"
value=""
/>
</th>
<th
colspan="1"
>
@@ -71,46 +71,46 @@
</tr>
</thead>
<tbody>
<tr>
<td>
- firstName: tanner
+ firstName: derek
</td>
<td>
- lastName: linsley
+ lastName: perkins
</td>
<td>
- age: 29
+ age: 40
</td>
<td>
- visits: 100
+ visits: 40
</td>
<td>
- status: In Relationship
+ status: Single
</td>
<td>
- progress: 50
+ progress: 80
</td>
</tr>
<tr>
<td>
- firstName: jaylen
+ firstName: joe
</td>
<td>
- lastName: linsley
+ lastName: bergevin
</td>
<td>
- age: 26
+ age: 45
</td>
<td>
- visits: 99
+ visits: 20
</td>
<td>
- status: In Relationship
+ status: Complicated
</td>
<td>
- progress: 70
+ progress: 10
</td>
</tr>
</tbody>
</table>
</DocumentFragment>
</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
firstName: tanner
</td>
<td>
lastName: linsley
</td>
<td>
age: 29
</td>
<td>
visits: 100
</td>
<td>
status: In Relationship
</td>
<td>
progress: 50
</td>
</tr>
<tr>
<td>
firstName: jaylen
</td>
<td>
lastName: linsley
</td>
<td>
age: 26
</td>
<td>
visits: 99
</td>
<td>
status: In Relationship
</td>
<td>
progress: 70
</td>
</tr>
</tbody>
</table>
</DocumentFragment>
`;
exports[`renders a filterable table 3`] = `
<DocumentFragment>
<table>
<thead>
<tr>
<th
colspan="2"
>
Name
</th>
<th
colspan="4"
>
Info
</th>
</tr>
<tr>
<th
colspan="1"
>
First Name
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Last Name
<input
placeholder="Search..."
value="er"
/>
</th>
<th
colspan="1"
>
Age
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Visits
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Status
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Profile Progress
<input
placeholder="Search..."
value=""
/>
</th>
</tr>
<tr>
<th
colspan="6"
style="text-align: left;"
>
<span>
<input
placeholder="Global search..."
style="font-size: 1.1rem; border: 0px;"
value=""
/>
</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
firstName: derek
</td>
<td>
lastName: perkins
</td>
<td>
age: 40
</td>
<td>
visits: 40
</td>
<td>
status: Single
</td>
<td>
progress: 80
</td>
</tr>
<tr>
<td>
firstName: joe
</td>
<td>
lastName: bergevin
</td>
<td>
age: 45
</td>
<td>
visits: 20
</td>
<td>
status: Complicated
</td>
<td>
progress: 10
</td>
</tr>
</tbody>
</table>
</DocumentFragment>
`;
exports[`renders a filterable table 4`] = `
<DocumentFragment>
<table>
<thead>
<tr>
<th
colspan="2"
>
Name
</th>
<th
colspan="4"
>
Info
</th>
</tr>
<tr>
<th
colspan="1"
>
First Name
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Last Name
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Age
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Visits
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Status
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Profile Progress
<input
placeholder="Search..."
value=""
/>
</th>
</tr>
<tr>
<th
colspan="6"
style="text-align: left;"
>
<span>
<input
placeholder="Global search..."
style="font-size: 1.1rem; border: 0px;"
value=""
/>
</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
firstName: tanner
</td>
<td>
lastName: linsley
</td>
<td>
age: 29
</td>
<td>
visits: 100
</td>
<td>
status: In Relationship
</td>
<td>
progress: 50
</td>
</tr>
<tr>
<td>
firstName: derek
</td>
<td>
lastName: perkins
</td>
<td>
age: 40
</td>
<td>
visits: 40
</td>
<td>
status: Single
</td>
<td>
progress: 80
</td>
</tr>
<tr>
<td>
firstName: joe
</td>
<td>
lastName: bergevin
</td>
<td>
age: 45
</td>
<td>
visits: 20
</td>
<td>
status: Complicated
</td>
<td>
progress: 10
</td>
</tr>
<tr>
<td>
firstName: jaylen
</td>
<td>
lastName: linsley
</td>
<td>
age: 26
</td>
<td>
visits: 99
</td>
<td>
status: In Relationship
</td>
<td>
progress: 70
</td>
</tr>
</tbody>
</table>
</DocumentFragment>
`;
exports[`renders a filterable table 5`] = `
<DocumentFragment>
<table>
<thead>
<tr>
<th
colspan="2"
>
Name
</th>
<th
colspan="4"
>
Info
</th>
</tr>
<tr>
<th
colspan="1"
>
First Name
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Last Name
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Age
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Visits
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Status
<input
placeholder="Search..."
value=""
/>
</th>
<th
colspan="1"
>
Profile Progress
<input
placeholder="Search..."
value=""
/>
</th>
</tr>
<tr>
<th
colspan="6"
style="text-align: left;"
>
<span>
<input
placeholder="Global search..."
style="font-size: 1.1rem; border: 0px;"
value="li"
/>
</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
firstName: tanner
</td>
<td>
lastName: linsley
</td>
<td>
age: 29
</td>
<td>
visits: 100
</td>
<td>
status: In Relationship
</td>
<td>
progress: 50
</td>
</tr>
<tr>
<td>
firstName: joe
</td>
<td>
lastName: bergevin
</td>
<td>
age: 45
</td>
<td>
visits: 20
</td>
<td>
status: Complicated
</td>
<td>
progress: 10
</td>
</tr>
<tr>
<td>
firstName: jaylen
</td>
<td>
lastName: linsley
</td>
<td>
age: 26
</td>
<td>
visits: 99
</td>
<td>
status: In Relationship
</td>
<td>
progress: 70
</td>
</tr>
</tbody>
</table>
</DocumentFragment>
`;
+45 -4
View File
@@ -2,6 +2,7 @@ import React from 'react'
import { render, fireEvent } from '@testing-library/react'
import { useTable } from '../../hooks/useTable'
import { useFilters } from '../useFilters'
import { useGlobalFilter } from '../useGlobalFilter'
const data = [
{
@@ -58,13 +59,17 @@ function Table({ columns, data }) {
headerGroups,
rows,
prepareRow,
flatColumns,
state,
setGlobalFilter,
} = useTable(
{
columns,
data,
defaultColumn,
},
useFilters
useFilters,
useGlobalFilter
)
return (
@@ -80,6 +85,28 @@ function Table({ columns, data }) {
))}
</tr>
))}
<tr>
<th
colSpan={flatColumns.length}
style={{
textAlign: 'left',
}}
>
<span>
<input
value={state.globalFilter || ''}
onChange={e => {
setGlobalFilter(e.target.value || undefined) // Set undefined to remove the filter entirely
}}
placeholder={`Global search...`}
style={{
fontSize: '1.1rem',
border: '0',
}}
/>
</span>
</th>
</tr>
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(
@@ -142,8 +169,11 @@ function App() {
}
test('renders a filterable table', () => {
const { getAllByPlaceholderText, asFragment } = render(<App />)
const { getAllByPlaceholderText, getByPlaceholderText, asFragment } = render(
<App />
)
const globalFilterInput = getByPlaceholderText('Global search...')
const filterInputs = getAllByPlaceholderText('Search...')
const beforeFilter = asFragment()
@@ -156,6 +186,17 @@ test('renders a filterable table', () => {
const afterFilter2 = asFragment()
expect(beforeFilter).toMatchDiffSnapshot(afterFilter1)
expect(afterFilter1).toMatchDiffSnapshot(afterFilter2)
fireEvent.change(filterInputs[1], { target: { value: '' } })
const afterFilter3 = asFragment()
fireEvent.change(globalFilterInput, { target: { value: 'li' } })
const afterFilter4 = asFragment()
expect(beforeFilter).toMatchSnapshot()
expect(afterFilter1).toMatchSnapshot()
expect(afterFilter2).toMatchSnapshot()
expect(afterFilter3).toMatchSnapshot()
expect(afterFilter4).toMatchSnapshot()
})
+5 -5
View File
@@ -11,18 +11,18 @@ export const useAbsoluteLayout = hooks => {
hooks.getHeaderGroupProps.push(getRowStyles)
hooks.useInstance.push(useInstance)
hooks.getHeaderProps.push((props, instance, header) => [
hooks.getHeaderProps.push((props, { column }) => [
props,
{
style: {
...cellStyles,
left: `${header.totalLeft}px`,
width: `${header.totalWidth}px`,
left: `${column.totalLeft}px`,
width: `${column.totalWidth}px`,
},
},
])
hooks.getCellProps.push((props, instance, cell) => [
hooks.getCellProps.push((props, { cell }) => [
props,
{
style: {
@@ -36,7 +36,7 @@ export const useAbsoluteLayout = hooks => {
useAbsoluteLayout.pluginName = 'useAbsoluteLayout'
const getRowStyles = (props, instance) => [
const getRowStyles = (props, { instance }) => [
props,
{
style: {
+4 -4
View File
@@ -3,7 +3,7 @@ const cellStyles = {
boxSizing: 'border-box',
}
const getRowStyles = (props, instance) => [
const getRowStyles = (props, { instance }) => [
props,
{
style: {
@@ -17,17 +17,17 @@ export const useBlockLayout = hooks => {
hooks.getRowProps.push(getRowStyles)
hooks.getHeaderGroupProps.push(getRowStyles)
hooks.getHeaderProps.push((props, instance, header) => [
hooks.getHeaderProps.push((props, { column }) => [
props,
{
style: {
...cellStyles,
width: `${header.totalWidth}px`,
width: `${column.totalWidth}px`,
},
},
])
hooks.getCellProps.push((props, instance, cell) => [
hooks.getCellProps.push((props, { cell }) => [
props,
{
style: {
+9 -6
View File
@@ -8,7 +8,7 @@ actions.setColumnOrder = 'setColumnOrder'
export const useColumnOrder = hooks => {
hooks.stateReducers.push(reducer)
hooks.flatColumnsDeps.push((deps, instance) => {
hooks.flatColumnsDeps.push((deps, { instance }) => {
return [...deps, instance.state.columnOrder]
})
hooks.flatColumns.push(flatColumns)
@@ -40,11 +40,14 @@ function reducer(state, action, previousState, instance) {
}
}
function flatColumns(columns, instance) {
const {
state: { columnOrder },
} = instance
function flatColumns(
columns,
{
instance: {
state: { columnOrder },
},
}
) {
// If there is no order, return the normal columns
if (!columnOrder || !columnOrder.length) {
return columns
+5 -6
View File
@@ -23,7 +23,7 @@ export const useExpanded = hooks => {
useExpanded.pluginName = 'useExpanded'
const defaultGetExpandedToggleProps = (props, instance, row) => [
const defaultGetExpandedToggleProps = (props, { row }) => [
props,
{
onClick: e => {
@@ -124,11 +124,10 @@ function useInstance(instance) {
hooks.prepareRow.push(row => {
row.toggleExpanded = set => instance.toggleExpanded(row.id, set)
row.getExpandedToggleProps = makePropGetter(
getExpandedTogglePropsHooks(),
getInstance(),
row
)
row.getExpandedToggleProps = makePropGetter(getExpandedTogglePropsHooks(), {
instance: getInstance(),
row,
})
})
const expandedRows = React.useMemo(() => {
+9 -33
View File
@@ -3,10 +3,11 @@ import React from 'react'
import {
actions,
getFirstDefined,
isFunction,
getFilterMethod,
useMountedLayoutEffect,
functionalUpdate,
useGetLatest,
shouldAutoRemoveFilter,
} from '../utils'
import * as filterTypes from '../filterTypes'
@@ -63,7 +64,7 @@ function reducer(state, action, previousState, instance) {
)
//
if (shouldAutoRemove(filterMethod.autoRemove, newFilter)) {
if (shouldAutoRemoveFilter(filterMethod.autoRemove, newFilter)) {
return {
...state,
filters: state.filters.filter(d => d.id !== columnId),
@@ -103,7 +104,7 @@ function reducer(state, action, previousState, instance) {
filterTypes
)
if (shouldAutoRemove(filterMethod.autoRemove, filter.value)) {
if (shouldAutoRemoveFilter(filterMethod.autoRemove, filter.value)) {
return false
}
return true
@@ -164,17 +165,9 @@ function useInstance(instance) {
column.filterValue = found && found.value
})
// TODO: Create a filter cache for incremental high speed multi-filtering
// This gets pretty complicated pretty fast, since you have to maintain a
// cache for each row group (top-level rows, and each row's recursive subrows)
// This would make multi-filtering a lot faster though. Too far?
const { filteredRows, filteredFlatRows } = React.useMemo(() => {
const [filteredRows, filteredFlatRows] = React.useMemo(() => {
if (manualFilters || !filters.length) {
return {
filteredRows: rows,
filteredFlatRows: flatRows,
}
return [rows, flatRows]
}
const filteredFlatRows = []
@@ -213,9 +206,8 @@ function useInstance(instance) {
// to get the filtered rows back
column.filteredRows = filterMethod(
filteredSoFar,
columnId,
filterValue,
column
[columnId],
filterValue
)
return column.filteredRows
@@ -244,10 +236,7 @@ function useInstance(instance) {
return filteredRows
}
return {
filteredRows: filterRows(rows),
filteredFlatRows,
}
return [filterRows(rows), filteredFlatRows]
}, [manualFilters, filters, rows, flatRows, flatColumns, userFilterTypes])
React.useMemo(() => {
@@ -284,16 +273,3 @@ function useInstance(instance) {
setAllFilters,
})
}
function shouldAutoRemove(autoRemove, value) {
return autoRemove ? autoRemove(value) : typeof value === 'undefined'
}
function getFilterMethod(filter, userFilterTypes, filterTypes) {
return (
isFunction(filter) ||
userFilterTypes[filter] ||
filterTypes[filter] ||
filterTypes.text
)
}
+47 -44
View File
@@ -1,50 +1,53 @@
export function useFlexLayout(hooks) {
hooks.getTableBodyProps.push((props, instance) => [
props,
{
style: {
minWidth: `${instance.totalColumnsWidth}px`,
},
},
])
const getRowStyles = (props, instance) => [
props,
{
style: {
display: 'flex',
flex: '1 0 auto',
minWidth: `${instance.totalColumnsMinWidth}px`,
},
},
]
hooks.getTableBodyProps.push(getTableBodyProps)
hooks.getRowProps.push(getRowStyles)
hooks.getHeaderGroupProps.push(getRowStyles)
hooks.getHeaderProps.push((props, instance, header) => [
props,
{
style: {
boxSizing: 'border-box',
flex: `${header.totalWidth} 0 auto`,
minWidth: `${header.totalMinWidth}px`,
width: `${header.totalWidth}px`,
},
},
])
hooks.getCellProps.push((props, instance, cell) => [
props,
{
style: {
boxSizing: 'border-box',
flex: `${cell.column.totalWidth} 0 auto`,
minWidth: `${cell.column.totalMinWidth}px`,
width: `${cell.column.totalWidth}px`,
},
},
])
hooks.getHeaderProps.push(getHeaderProps)
hooks.getCellProps.push(getCellProps)
}
useFlexLayout.pluginName = 'useFlexLayout'
const getTableBodyProps = (props, { instance }) => [
props,
{
style: {
minWidth: `${instance.totalColumnsWidth}px`,
},
},
]
const getRowStyles = (props, { instance }) => [
props,
{
style: {
display: 'flex',
flex: '1 0 auto',
minWidth: `${instance.totalColumnsMinWidth}px`,
},
},
]
const getHeaderProps = (props, { column }) => [
props,
{
style: {
boxSizing: 'border-box',
flex: `${column.totalWidth} 0 auto`,
minWidth: `${column.totalMinWidth}px`,
width: `${column.totalWidth}px`,
},
},
]
const getCellProps = (props, { cell }) => [
props,
{
style: {
boxSizing: 'border-box',
flex: `${cell.column.totalWidth} 0 auto`,
minWidth: `${cell.column.totalMinWidth}px`,
width: `${cell.column.totalWidth}px`,
},
},
]
+152
View File
@@ -0,0 +1,152 @@
import React from 'react'
import {
actions,
getFilterMethod,
useMountedLayoutEffect,
functionalUpdate,
useGetLatest,
shouldAutoRemoveFilter,
ensurePluginOrder,
} from '../utils'
import * as filterTypes from '../filterTypes'
// Actions
actions.resetGlobalFilter = 'resetGlobalFilter'
actions.setGlobalFilter = 'setGlobalFilter'
export const useGlobalFilter = hooks => {
hooks.stateReducers.push(reducer)
hooks.useInstance.push(useInstance)
}
useGlobalFilter.pluginName = 'useGlobalFilter'
function reducer(state, action, previousState, instance) {
if (action.type === actions.resetGlobalFilter) {
return {
...state,
globalFilter: instance.initialState.globalFilter || undefined,
}
}
if (action.type === actions.setGlobalFilter) {
const { filterValue } = action
const { userFilterTypes } = instance
const filterMethod = getFilterMethod(
instance.globalFilter,
userFilterTypes || {},
filterTypes
)
const newFilter = functionalUpdate(filterValue, state.globalFilter)
//
if (shouldAutoRemoveFilter(filterMethod.autoRemove, newFilter)) {
const { globalFilter, ...stateWithoutGlobalFilter } = state
return stateWithoutGlobalFilter
}
return {
...state,
globalFilter: newFilter,
}
}
}
function useInstance(instance) {
const {
data,
rows,
flatRows,
flatColumns,
filterTypes: userFilterTypes,
globalFilter,
manualGlobalFilter,
state: { globalFilter: globalFilterValue },
dispatch,
autoResetGlobalFilters = true,
plugins,
} = instance
ensurePluginOrder(plugins, [], 'useGlobalFilter', [
'useSortBy',
'useExpanded',
])
const setGlobalFilter = filterValue => {
dispatch({ type: actions.setGlobalFilter, filterValue })
}
// TODO: Create a filter cache for incremental high speed multi-filtering
// This gets pretty complicated pretty fast, since you have to maintain a
// cache for each row group (top-level rows, and each row's recursive subrows)
// This would make multi-filtering a lot faster though. Too far?
const [globalFilteredRows, globalFilteredFlatRows] = React.useMemo(() => {
if (manualGlobalFilter || typeof globalFilterValue === 'undefined') {
return [rows, flatRows]
}
const filteredFlatRows = []
const filterMethod = getFilterMethod(
globalFilter,
userFilterTypes || {},
filterTypes
)
if (!filterMethod) {
console.warn(`Could not find a valid 'globalFilter' option.`)
return rows
}
// Filters top level and nested rows
const filterRows = filteredRows => {
return filterMethod(
filteredRows,
flatColumns.map(d => d.id),
globalFilterValue
).map(row => {
filteredFlatRows.push(row)
return {
...row,
subRows:
row.subRows && row.subRows.length
? filterRows(row.subRows)
: row.subRows,
}
})
}
return [filterRows(rows), filteredFlatRows]
}, [
manualGlobalFilter,
globalFilter,
userFilterTypes,
rows,
flatRows,
flatColumns,
globalFilterValue,
])
const getAutoResetGlobalFilters = useGetLatest(autoResetGlobalFilters)
useMountedLayoutEffect(() => {
if (getAutoResetGlobalFilters()) {
dispatch({ type: actions.resetGlobalFilter })
}
}, [dispatch, manualGlobalFilter ? null : data])
Object.assign(instance, {
preGlobalFilteredRows: rows,
preGlobalFilteredFlatRows: flatRows,
globalFilteredRows,
globalFilteredFlatRows,
rows: globalFilteredRows,
flatRows: globalFilteredFlatRows,
setGlobalFilter,
})
}
+11 -5
View File
@@ -19,7 +19,7 @@ actions.toggleGroupBy = 'toggleGroupBy'
export const useGroupBy = hooks => {
hooks.getGroupByToggleProps = [defaultGetGroupByToggleProps]
hooks.stateReducers.push(reducer)
hooks.flatColumnsDeps.push((deps, instance) => [
hooks.flatColumnsDeps.push((deps, { instance }) => [
...deps,
instance.state.groupBy,
])
@@ -29,7 +29,7 @@ export const useGroupBy = hooks => {
useGroupBy.pluginName = 'useGroupBy'
const defaultGetGroupByToggleProps = (props, instance, header) => [
const defaultGetGroupByToggleProps = (props, { header }) => [
props,
{
onClick: header.canGroupBy
@@ -81,7 +81,14 @@ function reducer(state, action, previousState, instance) {
}
}
function flatColumns(flatColumns, { state: { groupBy } }) {
function flatColumns(
flatColumns,
{
instance: {
state: { groupBy },
},
}
) {
// Sort grouped columns to the start of the column list
// before the headers are built
@@ -160,8 +167,7 @@ function useInstance(instance) {
flatHeaders.forEach(header => {
header.getGroupByToggleProps = makePropGetter(
getGroupByTogglePropsHooks(),
getInstance(),
header
{ instance: getInstance(), header }
)
})
+5 -6
View File
@@ -26,7 +26,7 @@ export const useResizeColumns = hooks => {
hooks.useInstanceBeforeDimensions.push(useInstanceBeforeDimensions)
}
const defaultGetResizerProps = (props, instance, header) => {
const defaultGetResizerProps = (props, { instance, header }) => {
const { dispatch } = instance
const onResizeStart = (e, header) => {
@@ -215,11 +215,10 @@ const useInstanceBeforeDimensions = instance => {
header.isResizing = columnResizing.isResizingColumn === header.id
if (canResize) {
header.getResizerProps = makePropGetter(
getResizerPropsHooks(),
getInstance(),
header
)
header.getResizerProps = makePropGetter(getResizerPropsHooks(), {
instance: getInstance(),
header,
})
}
})
}
+5 -6
View File
@@ -26,7 +26,7 @@ export const useRowSelect = hooks => {
useRowSelect.pluginName = pluginName
const defaultGetToggleRowSelectedProps = (props, instance, row) => {
const defaultGetToggleRowSelectedProps = (props, { instance, row }) => {
const { manualRowSelectedKey = 'isSelected' } = instance
let checked = false
@@ -52,7 +52,7 @@ const defaultGetToggleRowSelectedProps = (props, instance, row) => {
]
}
const defaultGetToggleAllRowsSelectedProps = (props, instance) => [
const defaultGetToggleAllRowsSelectedProps = (props, { instance }) => [
props,
{
onChange: e => {
@@ -153,7 +153,7 @@ function reducer(state, action, previousState, instance) {
}
}
function useRows(rows, instance) {
function useRows(rows, { instance }) {
const {
state: { selectedRowIds },
} = instance
@@ -242,7 +242,7 @@ function useInstance(instance) {
const getToggleAllRowsSelectedProps = makePropGetter(
getToggleAllRowsSelectedPropsHooks(),
getInstance()
{ instance: getInstance() }
)
const getToggleRowSelectedPropsHooks = useConsumeHookGetter(
@@ -255,8 +255,7 @@ function useInstance(instance) {
row.getToggleRowSelectedProps = makePropGetter(
getToggleRowSelectedPropsHooks(),
getInstance(),
row
{ instance: getInstance(), row }
)
})
+5 -6
View File
@@ -31,7 +31,7 @@ export const useSortBy = hooks => {
useSortBy.pluginName = 'useSortBy'
const defaultGetSortByToggleProps = (props, instance, column) => {
const defaultGetSortByToggleProps = (props, { instance, column }) => {
const { isMultiSortEvent = e => e.shiftKey } = instance
return [
@@ -237,11 +237,10 @@ function useInstance(instance) {
}
}
column.getSortByToggleProps = makePropGetter(
getSortByTogglePropsHooks(),
getInstance(),
column
)
column.getSortByToggleProps = makePropGetter(getSortByTogglePropsHooks(), {
instance: getInstance(),
column,
})
const columnSort = sortBy.find(d => d.id === id)
column.isSorted = !!columnSort
+12 -8
View File
@@ -67,10 +67,10 @@ function mergeProps(...propList) {
}, {})
}
function handlePropGetter(prevProps, userProps, ...meta) {
function handlePropGetter(prevProps, userProps, meta) {
// Handle a lambda, pass it the previous props
if (typeof userProps === 'function') {
return handlePropGetter({}, userProps(prevProps, ...meta))
return handlePropGetter({}, userProps(prevProps, meta))
}
// Handle an array, merge each item as separate props
@@ -82,17 +82,21 @@ function handlePropGetter(prevProps, userProps, ...meta) {
return mergeProps(prevProps, userProps)
}
export const makePropGetter = (hooks, ...meta) => {
export const makePropGetter = (hooks, meta = {}) => {
return (userProps = {}) =>
[...hooks, userProps].reduce(
(prev, next) => handlePropGetter(prev, next, ...meta),
(prev, next) =>
handlePropGetter(prev, next, {
...meta,
userProps,
}),
{}
)
}
export const reduceHooks = (hooks, initial, ...args) =>
export const reduceHooks = (hooks, initial, meta = {}) =>
hooks.reduce((prev, next) => {
const nextValue = next(prev, ...args)
const nextValue = next(prev, meta)
if (process.env.NODE_ENV !== 'production') {
if (typeof nextValue === 'undefined') {
console.info(next)
@@ -104,9 +108,9 @@ export const reduceHooks = (hooks, initial, ...args) =>
return nextValue
}, initial)
export const loopHooks = (hooks, ...args) =>
export const loopHooks = (hooks, meta = {}) =>
hooks.forEach(hook => {
const nextValue = hook(...args)
const nextValue = hook(meta)
if (process.env.NODE_ENV !== 'production') {
if (typeof nextValue !== 'undefined') {
console.info(hook, nextValue)
+13
View File
@@ -267,6 +267,19 @@ export function expandRows(
return expandedRows
}
export function getFilterMethod(filter, userFilterTypes, filterTypes) {
return (
isFunction(filter) ||
userFilterTypes[filter] ||
filterTypes[filter] ||
filterTypes.text
)
}
export function shouldAutoRemoveFilter(autoRemove, value) {
return autoRemove ? autoRemove(value) : typeof value === 'undefined'
}
//
const reOpenBracket = /\[/g