mirror of
https://github.com/gosticks/react-table.git
synced 2025-10-16 11:55:36 +00:00
Add global filtering support via useGlobalFilter
This commit is contained in:
parent
63d54b1e87
commit
d18f1ba4d8
@ -1,20 +1,20 @@
|
|||||||
{
|
{
|
||||||
"dist/index.js": {
|
"dist/index.js": {
|
||||||
"bundled": 108756,
|
"bundled": 112754,
|
||||||
"minified": 50398,
|
"minified": 52324,
|
||||||
"gzipped": 13421
|
"gzipped": 13765
|
||||||
},
|
},
|
||||||
"dist/index.es.js": {
|
"dist/index.es.js": {
|
||||||
"bundled": 107845,
|
"bundled": 111817,
|
||||||
"minified": 49586,
|
"minified": 51488,
|
||||||
"gzipped": 13253,
|
"gzipped": 13599,
|
||||||
"treeshaked": {
|
"treeshaked": {
|
||||||
"rollup": {
|
"rollup": {
|
||||||
"code": 80,
|
"code": 80,
|
||||||
"import_statements": 21
|
"import_statements": 21
|
||||||
},
|
},
|
||||||
"webpack": {
|
"webpack": {
|
||||||
"code": 8168
|
"code": 8484
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,3 +1,10 @@
|
|||||||
|
## 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
|
## 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 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 }) => [...])`
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
- Plugin Hook
|
- Plugin Hook
|
||||||
- Optional
|
- 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
|
### Table Options
|
||||||
|
|
||||||
|
|||||||
52
docs/api/useGlobalFilter.md
Normal file
52
docs/api/useGlobalFilter.md
Normal 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)
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
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
|
// A great library for fuzzy filtering/sorting items
|
||||||
import matchSorter from 'match-sorter'
|
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
|
// Define a default UI for filtering
|
||||||
function DefaultColumnFilter({
|
function DefaultColumnFilter({
|
||||||
column: { filterValue, preFilteredRows, setFilter },
|
column: { filterValue, preFilteredRows, setFilter },
|
||||||
@ -217,6 +243,9 @@ function Table({ columns, data }) {
|
|||||||
rows,
|
rows,
|
||||||
prepareRow,
|
prepareRow,
|
||||||
state,
|
state,
|
||||||
|
flatColumns,
|
||||||
|
preGlobalFilteredRows,
|
||||||
|
setGlobalFilter,
|
||||||
} = useTable(
|
} = useTable(
|
||||||
{
|
{
|
||||||
columns,
|
columns,
|
||||||
@ -224,7 +253,8 @@ function Table({ columns, data }) {
|
|||||||
defaultColumn, // Be sure to pass the defaultColumn option
|
defaultColumn, // Be sure to pass the defaultColumn option
|
||||||
filterTypes,
|
filterTypes,
|
||||||
},
|
},
|
||||||
useFilters // useFilters!
|
useFilters, // useFilters!
|
||||||
|
useGlobalFilter // useGlobalFilter!
|
||||||
)
|
)
|
||||||
|
|
||||||
// We don't want to render all of the rows for this example, so cap
|
// We don't want to render all of the rows for this example, so cap
|
||||||
@ -233,11 +263,6 @@ function Table({ columns, data }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
|
||||||
<pre>
|
|
||||||
<code>{JSON.stringify(state.filters, null, 2)}</code>
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
<table {...getTableProps()}>
|
<table {...getTableProps()}>
|
||||||
<thead>
|
<thead>
|
||||||
{headerGroups.map(headerGroup => (
|
{headerGroups.map(headerGroup => (
|
||||||
@ -251,25 +276,41 @@ function Table({ columns, data }) {
|
|||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
colSpan={flatColumns.length}
|
||||||
|
style={{
|
||||||
|
textAlign: 'left',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<GlobalFilter
|
||||||
|
preGlobalFilteredRows={preGlobalFilteredRows}
|
||||||
|
globalFilter={state.globalFilter}
|
||||||
|
setGlobalFilter={setGlobalFilter}
|
||||||
|
/>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody {...getTableBodyProps()}>
|
<tbody {...getTableBodyProps()}>
|
||||||
{firstPageRows.map(
|
{firstPageRows.map((row, i) => {
|
||||||
(row, i) => {
|
prepareRow(row)
|
||||||
prepareRow(row);
|
return (
|
||||||
return (
|
<tr {...row.getRowProps()}>
|
||||||
<tr {...row.getRowProps()}>
|
{row.cells.map(cell => {
|
||||||
{row.cells.map(cell => {
|
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
|
||||||
return (
|
})}
|
||||||
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
|
</tr>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</tr>
|
|
||||||
)}
|
|
||||||
)}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<br />
|
<br />
|
||||||
<div>Showing the first 20 results of {rows.length} rows</div>
|
<div>Showing the first 20 results of {rows.length} rows</div>
|
||||||
|
<div>
|
||||||
|
<pre>
|
||||||
|
<code>{JSON.stringify(state.filters, null, 2)}</code>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8094,10 +8094,10 @@ react-scripts@3.0.1:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents "2.0.6"
|
fsevents "2.0.6"
|
||||||
|
|
||||||
react-table@next:
|
react-table@latest:
|
||||||
version "7.0.0-alpha.7"
|
version "7.0.0-rc.14"
|
||||||
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.0.0-alpha.7.tgz#0cb6da6f32adb397e68505b7cdd4880d15d73017"
|
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.0.0-rc.14.tgz#bb4171fbdd56d78dd5f6b9e18694a36c00bd6261"
|
||||||
integrity sha512-oXE9RRkE2CFk1OloNCSTPQ9qxOdujgkCoW5b/srbJsBog/ySkWuozBTQkxH1wGNmnSxGyTrTxJqXdXPQam7VAw==
|
integrity sha512-9NyzAE0kLH8HA+DK86ynxVDxniO5ZdggAqI7nDKauWXQGVYNFId8+JJSescJ2vwP9nR2JKyCEDG9c+CjIaLNkA==
|
||||||
|
|
||||||
react@^16.8.6:
|
react@^16.8.6:
|
||||||
version "16.8.6"
|
version "16.8.6"
|
||||||
|
|||||||
@ -1,79 +1,93 @@
|
|||||||
export const text = (rows, id, filterValue) => {
|
export const text = (rows, ids, filterValue) => {
|
||||||
rows = rows.filter(row => {
|
rows = rows.filter(row => {
|
||||||
const rowValue = row.values[id]
|
return ids.some(id => {
|
||||||
return String(rowValue)
|
const rowValue = row.values[id]
|
||||||
.toLowerCase()
|
return String(rowValue)
|
||||||
.includes(String(filterValue).toLowerCase())
|
.toLowerCase()
|
||||||
|
.includes(String(filterValue).toLowerCase())
|
||||||
|
})
|
||||||
})
|
})
|
||||||
return rows
|
return rows
|
||||||
}
|
}
|
||||||
|
|
||||||
text.autoRemove = val => !val
|
text.autoRemove = val => !val
|
||||||
|
|
||||||
export const exactText = (rows, id, filterValue) => {
|
export const exactText = (rows, ids, filterValue) => {
|
||||||
return rows.filter(row => {
|
return rows.filter(row => {
|
||||||
const rowValue = row.values[id]
|
return ids.some(id => {
|
||||||
return rowValue !== undefined
|
const rowValue = row.values[id]
|
||||||
? String(rowValue).toLowerCase() === String(filterValue).toLowerCase()
|
return rowValue !== undefined
|
||||||
: true
|
? String(rowValue).toLowerCase() === String(filterValue).toLowerCase()
|
||||||
|
: true
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exactText.autoRemove = val => !val
|
exactText.autoRemove = val => !val
|
||||||
|
|
||||||
export const exactTextCase = (rows, id, filterValue) => {
|
export const exactTextCase = (rows, ids, filterValue) => {
|
||||||
return rows.filter(row => {
|
return rows.filter(row => {
|
||||||
const rowValue = row.values[id]
|
return ids.some(id => {
|
||||||
return rowValue !== undefined
|
const rowValue = row.values[id]
|
||||||
? String(rowValue) === String(filterValue)
|
return rowValue !== undefined
|
||||||
: true
|
? String(rowValue) === String(filterValue)
|
||||||
|
: true
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exactTextCase.autoRemove = val => !val
|
exactTextCase.autoRemove = val => !val
|
||||||
|
|
||||||
export const includes = (rows, id, filterValue) => {
|
export const includes = (rows, ids, filterValue) => {
|
||||||
return rows.filter(row => {
|
return rows.filter(row => {
|
||||||
const rowValue = row.values[id]
|
return ids.some(id => {
|
||||||
return filterValue.includes(rowValue)
|
const rowValue = row.values[id]
|
||||||
|
return filterValue.includes(rowValue)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
includes.autoRemove = val => !val || !val.length
|
includes.autoRemove = val => !val || !val.length
|
||||||
|
|
||||||
export const includesAll = (rows, id, filterValue) => {
|
export const includesAll = (rows, ids, filterValue) => {
|
||||||
return rows.filter(row => {
|
return rows.filter(row => {
|
||||||
const rowValue = row.values[id]
|
return ids.some(id => {
|
||||||
return (
|
const rowValue = row.values[id]
|
||||||
rowValue &&
|
return (
|
||||||
rowValue.length &&
|
rowValue &&
|
||||||
filterValue.every(val => rowValue.includes(val))
|
rowValue.length &&
|
||||||
)
|
filterValue.every(val => rowValue.includes(val))
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
includesAll.autoRemove = val => !val || !val.length
|
includesAll.autoRemove = val => !val || !val.length
|
||||||
|
|
||||||
export const exact = (rows, id, filterValue) => {
|
export const exact = (rows, ids, filterValue) => {
|
||||||
return rows.filter(row => {
|
return rows.filter(row => {
|
||||||
const rowValue = row.values[id]
|
return ids.some(id => {
|
||||||
return rowValue === filterValue
|
const rowValue = row.values[id]
|
||||||
|
return rowValue === filterValue
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exact.autoRemove = val => typeof val === 'undefined'
|
exact.autoRemove = val => typeof val === 'undefined'
|
||||||
|
|
||||||
export const equals = (rows, id, filterValue) => {
|
export const equals = (rows, ids, filterValue) => {
|
||||||
return rows.filter(row => {
|
return rows.filter(row => {
|
||||||
const rowValue = row.values[id]
|
return ids.some(id => {
|
||||||
// eslint-disable-next-line eqeqeq
|
const rowValue = row.values[id]
|
||||||
return rowValue == filterValue
|
// eslint-disable-next-line eqeqeq
|
||||||
|
return rowValue == filterValue
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
equals.autoRemove = val => val == null
|
equals.autoRemove = val => val == null
|
||||||
|
|
||||||
export const between = (rows, id, filterValue) => {
|
export const between = (rows, ids, filterValue) => {
|
||||||
let [min, max] = filterValue || []
|
let [min, max] = filterValue || []
|
||||||
|
|
||||||
min = typeof min === 'number' ? min : -Infinity
|
min = typeof min === 'number' ? min : -Infinity
|
||||||
@ -86,8 +100,10 @@ export const between = (rows, id, filterValue) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return rows.filter(row => {
|
return rows.filter(row => {
|
||||||
const rowValue = row.values[id]
|
return ids.some(id => {
|
||||||
return rowValue >= min && rowValue <= max
|
const rowValue = row.values[id]
|
||||||
|
return rowValue >= min && rowValue <= max
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -79,8 +79,6 @@ function reducer(state, action, previousState, instance) {
|
|||||||
? action.value
|
? action.value
|
||||||
: !state.hiddenColumns.includes(action.columnId)
|
: !state.hiddenColumns.includes(action.columnId)
|
||||||
|
|
||||||
console.log(action, should)
|
|
||||||
|
|
||||||
const hiddenColumns = should
|
const hiddenColumns = should
|
||||||
? [...state.hiddenColumns, action.columnId]
|
? [...state.hiddenColumns, action.columnId]
|
||||||
: state.hiddenColumns.filter(d => d !== action.columnId)
|
: state.hiddenColumns.filter(d => d !== action.columnId)
|
||||||
|
|||||||
@ -2,6 +2,7 @@ export * from './publicUtils'
|
|||||||
export { useTable } from './hooks/useTable'
|
export { useTable } from './hooks/useTable'
|
||||||
export { useExpanded } from './plugin-hooks/useExpanded'
|
export { useExpanded } from './plugin-hooks/useExpanded'
|
||||||
export { useFilters } from './plugin-hooks/useFilters'
|
export { useFilters } from './plugin-hooks/useFilters'
|
||||||
|
export { useGlobalFilter } from './plugin-hooks/useGlobalFilter'
|
||||||
export { useGroupBy } from './plugin-hooks/useGroupBy'
|
export { useGroupBy } from './plugin-hooks/useGroupBy'
|
||||||
export { useSortBy } from './plugin-hooks/useSortBy'
|
export { useSortBy } from './plugin-hooks/useSortBy'
|
||||||
export { usePagination } from './plugin-hooks/usePagination'
|
export { usePagination } from './plugin-hooks/usePagination'
|
||||||
|
|||||||
@ -1,151 +1,766 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`renders a filterable table 1`] = `
|
exports[`renders a filterable table 1`] = `
|
||||||
Snapshot Diff:
|
<DocumentFragment>
|
||||||
- First value
|
<table>
|
||||||
+ Second value
|
<thead>
|
||||||
|
<tr>
|
||||||
@@ -27,11 +27,11 @@
|
<th
|
||||||
colspan="1"
|
colspan="2"
|
||||||
>
|
>
|
||||||
Last Name
|
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
|
<input
|
||||||
placeholder="Search..."
|
placeholder="Global search..."
|
||||||
- value=""
|
style="font-size: 1.1rem; border: 0px;"
|
||||||
+ value="l"
|
value=""
|
||||||
/>
|
/>
|
||||||
</th>
|
</span>
|
||||||
<th
|
</th>
|
||||||
colspan="1"
|
</tr>
|
||||||
>
|
</thead>
|
||||||
@@ -87,50 +87,10 @@
|
<tbody>
|
||||||
<td>
|
<tr>
|
||||||
status: In Relationship
|
<td>
|
||||||
</td>
|
firstName: tanner
|
||||||
<td>
|
</td>
|
||||||
progress: 50
|
<td>
|
||||||
- </td>
|
lastName: linsley
|
||||||
- </tr>
|
</td>
|
||||||
- <tr>
|
<td>
|
||||||
- <td>
|
age: 29
|
||||||
- firstName: derek
|
</td>
|
||||||
- </td>
|
<td>
|
||||||
- <td>
|
visits: 100
|
||||||
- lastName: perkins
|
</td>
|
||||||
- </td>
|
<td>
|
||||||
- <td>
|
status: In Relationship
|
||||||
- age: 40
|
</td>
|
||||||
- </td>
|
<td>
|
||||||
- <td>
|
progress: 50
|
||||||
- visits: 40
|
</td>
|
||||||
- </td>
|
</tr>
|
||||||
- <td>
|
<tr>
|
||||||
- status: Single
|
<td>
|
||||||
- </td>
|
firstName: derek
|
||||||
- <td>
|
</td>
|
||||||
- progress: 80
|
<td>
|
||||||
- </td>
|
lastName: perkins
|
||||||
- </tr>
|
</td>
|
||||||
- <tr>
|
<td>
|
||||||
- <td>
|
age: 40
|
||||||
- firstName: joe
|
</td>
|
||||||
- </td>
|
<td>
|
||||||
- <td>
|
visits: 40
|
||||||
- lastName: bergevin
|
</td>
|
||||||
- </td>
|
<td>
|
||||||
- <td>
|
status: Single
|
||||||
- age: 45
|
</td>
|
||||||
- </td>
|
<td>
|
||||||
- <td>
|
progress: 80
|
||||||
- visits: 20
|
</td>
|
||||||
- </td>
|
</tr>
|
||||||
- <td>
|
<tr>
|
||||||
- status: Complicated
|
<td>
|
||||||
- </td>
|
firstName: joe
|
||||||
- <td>
|
</td>
|
||||||
- progress: 10
|
<td>
|
||||||
</td>
|
lastName: bergevin
|
||||||
</tr>
|
</td>
|
||||||
<tr>
|
<td>
|
||||||
<td>
|
age: 45
|
||||||
firstName: jaylen
|
</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`] = `
|
exports[`renders a filterable table 2`] = `
|
||||||
Snapshot Diff:
|
<DocumentFragment>
|
||||||
- First value
|
<table>
|
||||||
+ Second value
|
<thead>
|
||||||
|
<tr>
|
||||||
@@ -27,11 +27,11 @@
|
<th
|
||||||
colspan="1"
|
colspan="2"
|
||||||
>
|
>
|
||||||
Last Name
|
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
|
<input
|
||||||
placeholder="Search..."
|
placeholder="Global search..."
|
||||||
- value="l"
|
style="font-size: 1.1rem; border: 0px;"
|
||||||
+ value="er"
|
value=""
|
||||||
/>
|
/>
|
||||||
</th>
|
</span>
|
||||||
<th
|
</th>
|
||||||
colspan="1"
|
</tr>
|
||||||
>
|
</thead>
|
||||||
@@ -71,46 +71,46 @@
|
<tbody>
|
||||||
</tr>
|
<tr>
|
||||||
</thead>
|
<td>
|
||||||
<tbody>
|
firstName: tanner
|
||||||
<tr>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
- firstName: tanner
|
lastName: linsley
|
||||||
+ firstName: derek
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
age: 29
|
||||||
- lastName: linsley
|
</td>
|
||||||
+ lastName: perkins
|
<td>
|
||||||
</td>
|
visits: 100
|
||||||
<td>
|
</td>
|
||||||
- age: 29
|
<td>
|
||||||
+ age: 40
|
status: In Relationship
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
- visits: 100
|
progress: 50
|
||||||
+ visits: 40
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
- status: In Relationship
|
<td>
|
||||||
+ status: Single
|
firstName: jaylen
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
- progress: 50
|
lastName: linsley
|
||||||
+ progress: 80
|
</td>
|
||||||
</td>
|
<td>
|
||||||
</tr>
|
age: 26
|
||||||
<tr>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
- firstName: jaylen
|
visits: 99
|
||||||
+ firstName: joe
|
</td>
|
||||||
</td>
|
<td>
|
||||||
<td>
|
status: In Relationship
|
||||||
- lastName: linsley
|
</td>
|
||||||
+ lastName: bergevin
|
<td>
|
||||||
</td>
|
progress: 70
|
||||||
<td>
|
</td>
|
||||||
- age: 26
|
</tr>
|
||||||
+ age: 45
|
</tbody>
|
||||||
</td>
|
</table>
|
||||||
<td>
|
</DocumentFragment>
|
||||||
- visits: 99
|
`;
|
||||||
+ visits: 20
|
|
||||||
</td>
|
exports[`renders a filterable table 3`] = `
|
||||||
<td>
|
<DocumentFragment>
|
||||||
- status: In Relationship
|
<table>
|
||||||
+ status: Complicated
|
<thead>
|
||||||
</td>
|
<tr>
|
||||||
<td>
|
<th
|
||||||
- progress: 70
|
colspan="2"
|
||||||
+ progress: 10
|
>
|
||||||
</td>
|
Name
|
||||||
</tr>
|
</th>
|
||||||
</tbody>
|
<th
|
||||||
</table>
|
colspan="4"
|
||||||
</DocumentFragment>
|
>
|
||||||
|
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>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import React from 'react'
|
|||||||
import { render, fireEvent } from '@testing-library/react'
|
import { render, fireEvent } from '@testing-library/react'
|
||||||
import { useTable } from '../../hooks/useTable'
|
import { useTable } from '../../hooks/useTable'
|
||||||
import { useFilters } from '../useFilters'
|
import { useFilters } from '../useFilters'
|
||||||
|
import { useGlobalFilter } from '../useGlobalFilter'
|
||||||
|
|
||||||
const data = [
|
const data = [
|
||||||
{
|
{
|
||||||
@ -58,13 +59,17 @@ function Table({ columns, data }) {
|
|||||||
headerGroups,
|
headerGroups,
|
||||||
rows,
|
rows,
|
||||||
prepareRow,
|
prepareRow,
|
||||||
|
flatColumns,
|
||||||
|
state,
|
||||||
|
setGlobalFilter,
|
||||||
} = useTable(
|
} = useTable(
|
||||||
{
|
{
|
||||||
columns,
|
columns,
|
||||||
data,
|
data,
|
||||||
defaultColumn,
|
defaultColumn,
|
||||||
},
|
},
|
||||||
useFilters
|
useFilters,
|
||||||
|
useGlobalFilter
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -80,6 +85,28 @@ function Table({ columns, data }) {
|
|||||||
))}
|
))}
|
||||||
</tr>
|
</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>
|
</thead>
|
||||||
<tbody {...getTableBodyProps()}>
|
<tbody {...getTableBodyProps()}>
|
||||||
{rows.map(
|
{rows.map(
|
||||||
@ -142,8 +169,11 @@ function App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test('renders a filterable table', () => {
|
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 filterInputs = getAllByPlaceholderText('Search...')
|
||||||
|
|
||||||
const beforeFilter = asFragment()
|
const beforeFilter = asFragment()
|
||||||
@ -156,6 +186,17 @@ test('renders a filterable table', () => {
|
|||||||
|
|
||||||
const afterFilter2 = asFragment()
|
const afterFilter2 = asFragment()
|
||||||
|
|
||||||
expect(beforeFilter).toMatchDiffSnapshot(afterFilter1)
|
fireEvent.change(filterInputs[1], { target: { value: '' } })
|
||||||
expect(afterFilter1).toMatchDiffSnapshot(afterFilter2)
|
|
||||||
|
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()
|
||||||
})
|
})
|
||||||
|
|||||||
@ -3,10 +3,11 @@ import React from 'react'
|
|||||||
import {
|
import {
|
||||||
actions,
|
actions,
|
||||||
getFirstDefined,
|
getFirstDefined,
|
||||||
isFunction,
|
getFilterMethod,
|
||||||
useMountedLayoutEffect,
|
useMountedLayoutEffect,
|
||||||
functionalUpdate,
|
functionalUpdate,
|
||||||
useGetLatest,
|
useGetLatest,
|
||||||
|
shouldAutoRemoveFilter,
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
import * as filterTypes from '../filterTypes'
|
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 {
|
return {
|
||||||
...state,
|
...state,
|
||||||
filters: state.filters.filter(d => d.id !== columnId),
|
filters: state.filters.filter(d => d.id !== columnId),
|
||||||
@ -103,7 +104,7 @@ function reducer(state, action, previousState, instance) {
|
|||||||
filterTypes
|
filterTypes
|
||||||
)
|
)
|
||||||
|
|
||||||
if (shouldAutoRemove(filterMethod.autoRemove, filter.value)) {
|
if (shouldAutoRemoveFilter(filterMethod.autoRemove, filter.value)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -164,17 +165,9 @@ function useInstance(instance) {
|
|||||||
column.filterValue = found && found.value
|
column.filterValue = found && found.value
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO: Create a filter cache for incremental high speed multi-filtering
|
const [filteredRows, filteredFlatRows] = React.useMemo(() => {
|
||||||
// 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(() => {
|
|
||||||
if (manualFilters || !filters.length) {
|
if (manualFilters || !filters.length) {
|
||||||
return {
|
return [rows, flatRows]
|
||||||
filteredRows: rows,
|
|
||||||
filteredFlatRows: flatRows,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const filteredFlatRows = []
|
const filteredFlatRows = []
|
||||||
@ -213,9 +206,8 @@ function useInstance(instance) {
|
|||||||
// to get the filtered rows back
|
// to get the filtered rows back
|
||||||
column.filteredRows = filterMethod(
|
column.filteredRows = filterMethod(
|
||||||
filteredSoFar,
|
filteredSoFar,
|
||||||
columnId,
|
[columnId],
|
||||||
filterValue,
|
filterValue
|
||||||
column
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return column.filteredRows
|
return column.filteredRows
|
||||||
@ -244,10 +236,7 @@ function useInstance(instance) {
|
|||||||
return filteredRows
|
return filteredRows
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return [filterRows(rows), filteredFlatRows]
|
||||||
filteredRows: filterRows(rows),
|
|
||||||
filteredFlatRows,
|
|
||||||
}
|
|
||||||
}, [manualFilters, filters, rows, flatRows, flatColumns, userFilterTypes])
|
}, [manualFilters, filters, rows, flatRows, flatColumns, userFilterTypes])
|
||||||
|
|
||||||
React.useMemo(() => {
|
React.useMemo(() => {
|
||||||
@ -284,16 +273,3 @@ function useInstance(instance) {
|
|||||||
setAllFilters,
|
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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
152
src/plugin-hooks/useGlobalFilter.js
Normal file
152
src/plugin-hooks/useGlobalFilter.js
Normal 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,
|
||||||
|
})
|
||||||
|
}
|
||||||
13
src/utils.js
13
src/utils.js
@ -267,6 +267,19 @@ export function expandRows(
|
|||||||
return expandedRows
|
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
|
const reOpenBracket = /\[/g
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user