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]andGitHub a8e1b33284 😍 🤵🏽‍♂️ update sizes-es.json 👍 2019-12-18 17:42:06 +00:00
size-plugin[bot]andGitHub 67ce7d8f0b 🧖🏽 👵 update sizes-cjs.json 👍 2019-12-18 17:42:05 +00:00
Tanner Linsley 4e08fd500e v7.0.0-rc.13 2019-12-18 10:40:08 -07:00
Tanner Linsley cb59098685 Fix column hiding, add useControlledStat hook 2019-12-18 10:39:35 -07:00
Tanner Linsley d7b6e69c5f 7.0.0-rc.12 2019-12-17 22:10:56 -07:00
Tanner Linsley b69e300b00 Merge branch 'master' of https://github.com/react-tools/react-table 2019-12-17 20:54:33 -07:00
size-plugin[bot]andGitHub 04e1309ed7 📤 🙏🏻 update sizes-es.json 👍 2019-12-18 03:54:31 +00:00
size-plugin[bot]andGitHub 4ed950d990 🤾‍♂️ 🤤 update sizes-cjs.json 👍 2019-12-18 03:54:30 +00:00
Tanner Linsley fdc3b22e54 Merge branch 'master' of https://github.com/react-tools/react-table 2019-12-17 20:54:23 -07:00
hanvyjandTanner Linsley 4e013632dd Fix groupBy removed columns (#1776) (#1782) 2019-12-17 20:52:57 -07:00
Michael LiandTanner Linsley 80ceeee83f Update useTable.md (#1788) 2019-12-17 20:52:39 -07:00
Tanner Linsley b3771502f8 v7.0.0-rc.11 2019-12-17 20:50:59 -07:00
Tanner Linsley 0df8cc5088 Update useFlexLayout.md 2019-12-17 20:46:03 -07:00
Tanner Linsley 7cebab7fb6 Merge branch 'master' of https://github.com/react-tools/react-table 2019-12-17 20:44:48 -07:00
Tanner Linsley 717ea7b211 Update Docs 2019-12-17 20:44:33 -07:00
size-plugin[bot]andGitHub 823d93946b 💁🏿‍♂️ 🚵‍♂️ update sizes-es.json 👍 2019-12-18 03:43:47 +00:00
size-plugin[bot]andGitHub b01749c5c7 🕴️ 🍀 update sizes-cjs.json 👍 2019-12-18 03:43:46 +00:00
Tanner Linsley b48cddb92b Add back useFlexLayout and full-width-resizable-table example 2019-12-17 20:41:28 -07:00
Tanner Linsley f48ef14975 Fix reset to use initial state, then fall back to default state 2019-12-17 20:40:34 -07:00
Tanner Linsley eeee14830d Update Changelog 2019-12-17 19:32:07 -07:00
Tanner Linsley f2776d0005 Fix getcolumnsHooks 2019-12-17 19:31:50 -07:00
Tanner Linsley ee18cf4b89 Add streaming rows snapshot 2019-12-17 19:31:09 -07:00
Chris NorwoodandTanner Linsley 632ea28c4b Update to use React.Fragment spread with row props (#1781) 2019-12-13 18:08:01 -07:00
Tanner LinsleyandGitHub 506a22062e Update README.md 2019-12-13 13:52:59 -07:00
size-plugin[bot]andGitHub 9e81e44da3 ☺️ 👨🏿‍🦳 update sizes-es.json 👍 2019-12-13 08:02:58 +00:00
size-plugin[bot]andGitHub acd6ac5d14 🤹🏽 🏋🏾 update sizes-es.json 👍 2019-12-13 08:00:27 +00:00
size-plugin[bot]andGitHub 78634585e7 🍒 👨🏼‍🍳 update sizes-es.json 👍 2019-12-13 07:55:23 +00:00
Tanner Linsley c8d2180e5b Create sandbox.config.json 2019-12-13 00:52:32 -07:00
Tanner Linsley 0575c1b36d Update examples.md 2019-12-13 00:50:11 -07:00
77 changed files with 22865 additions and 835 deletions
+25 -25
View File
@@ -1,13 +1,32 @@
{
"dist/index.js": {
"bundled": 104720,
"minified": 48438,
"gzipped": 13005
"bundled": 112754,
"minified": 52324,
"gzipped": 13765
},
"dist/index.es.js": {
"bundled": 103833,
"minified": 47648,
"gzipped": 12849,
"bundled": 111817,
"minified": 51488,
"gzipped": 13599,
"treeshaked": {
"rollup": {
"code": 80,
"import_statements": 21
},
"webpack": {
"code": 8484
}
}
},
"dist\\index.js": {
"bundled": 104977,
"minified": 48560,
"gzipped": 13057
},
"dist\\index.es.js": {
"bundled": 104090,
"minified": 47770,
"gzipped": 12900,
"treeshaked": {
"rollup": {
"code": 80,
@@ -17,24 +36,5 @@
"code": 8227
}
}
},
"dist\\index.js": {
"bundled": 105386,
"minified": 49565,
"gzipped": 13008
},
"dist\\index.es.js": {
"bundled": 104543,
"minified": 48815,
"gzipped": 12856,
"treeshaked": {
"rollup": {
"code": 80,
"import_statements": 21
},
"webpack": {
"code": 8444
}
}
}
}
+28
View File
@@ -1,3 +1,31 @@
## 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
- Fixed an issue where column hiding wasn't working properly.
## 7.0.0-rc.12
- Fixed an issue where removing a grouped column would result in a crash
## 7.0.0-rc.11
- Fixed an issue where plugins using the `columns` hook were not getting decorated properly
- Added back a new rendition of the `useFlexLayout` plugin and accompanying example.
- Fixed all reset actions to use the initial state passed into the table, then fall back to the default initial state for the hook
## 7.0.0-rc.10
- Optimizations made to make accessors, prop getters and other internals much faster. 10x in some cases!
+1
View File
@@ -183,6 +183,7 @@ This library is being built and maintained by me, @tannerlinsley and I am always
<li>Pekka Tapani</li>
<li>Eric Lanehart (@pushred)</li>
<li>Anish P Patel (@anishpatelyaadada)</li>
<li>Alin Porumb (@alinporumb)</li>
</ul>
</td>
<td>
+1
View File
@@ -20,6 +20,7 @@ React Table is essentially a compatible collection of **custom React hooks**:
- Layout Hooks
- [`useBlockLayout`](./useBlockLayout.md)
- [`useAbsoluteLayout`](./useAbsoluteLayout.md)
- [`useFlexLayout`](./useFlexLayout.md)
- [`useResizeColumns`](./useResizeColumns.md)
- 3rd Party Plugin Hooks
- Want your custom plugin hook listed here? [Submit a PR!](https://github.com/tannerlinsley/react-table/compare)
+6
View File
@@ -25,6 +25,12 @@
- **Usage Required**
- This core prop getter is required to to enable absolute layout for rows cells
### HeaderGroup Properties
- `getHeaderGroupProps`
- **Usage Required**
- This core prop getter is required to to enable absolute layout for headers
### Header Properties
- `getHeaderProps`
+6
View File
@@ -19,6 +19,12 @@
- **Usage Required**
- This core prop getter is required to to enable absolute layout for rows cells
### HeaderGroup Properties
- `getHeaderGroupProps`
- **Usage Required**
- This core prop getter is required to to enable absolute layout for headers
### Header Properties
- `getHeaderProps`
+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
+43
View File
@@ -0,0 +1,43 @@
# `useFlexLayout`
- Plugin Hook
- Optional
`useFlexLayout` is a plugin hook that adds support for headers and cells to be rendered as `inline-block` `div`s (or other non-table elements) with `width` being used as the flex-basis and flex-grow. This hook becomes useful when implementing both virtualized and resizable tables that must also be able to stretch to fill all available space.
**NOTE:** Although no additional options are needed for this plugin to work, the core column options `width`, `minWidth` and `maxWidth` are used to calculate column and cell widths and must be set:
- `minWidth` is only used to limit column resizing. It does not define the minimum width for a column.
- `width` is used as both the `flex-basis` and `flex-grow`. This means that it essentially acts as both the minimum width and flex-ratio of the column.
- `maxWidth` is only used to limit column resizing. It does not define the maximum width for a column.
[See Column Options](#column-options) for more information on these options.
### Row Properties
- `getRowProps`
- **Usage Required**
- This core prop getter is required to to enable absolute layout for rows
### Cell Properties
- `getCellProps`
- **Usage Required**
- This core prop getter is required to to enable absolute layout for rows cells
### HeaderGroup Properties
- `getHeaderGroupProps`
- **Usage Required**
- This core prop getter is required to to enable absolute layout for headers
### Header Properties
- `getHeaderProps`
- **Usage Required**
- This core prop getter is required to to enable absolute layout for headers
### Example (Full Width Resizable Table)
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/full-width-resizable-table)
- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/full-width-resizable-table)
+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)
+1 -1
View File
@@ -25,7 +25,7 @@ The following options are supported via the main options object passed to `useTa
- Optional
- The initial state object for hidden columns
- If a column's ID is contained in this array, it will be hidden
- `reducer: Function(newState, action, prevState) => newState`
- `stateReducer: Function(newState, action, prevState) => newState`
- Optional
- With every action that is dispatched to the table's internal `React.useReducer` instance, this reducer is called and is allowed to modify the final state object for updating.
- It is passed the `newState`, `action`, and `prevState` and is expected to either return the `newState` or a modified version of the `newState`
+9
View File
@@ -16,6 +16,9 @@
- Grouping
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/grouping)
- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/grouping)
- Grouping (Single Column)
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/grouping-column)
- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/grouping-column)
- Pagination
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/pagination)
- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/pagination)
@@ -46,6 +49,12 @@
- Row DnD
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/row-dnd)
- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/row-dnd)
- Full Width Table (Table Elements with collapsible content)
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/full-width-table)
- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/full-width-table)
- Full Width Resizable Table (via `useFlexLayout`)
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/full-width-resizable-table)
- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/full-width-resizable-table)
- **Complex**
- The "Kitchen Sink"
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/kitchen-sink)
+4 -2
View File
@@ -71,8 +71,10 @@ function Table({ columns, data }) {
</div>
{flatColumns.map(column => (
<div key={column.id}>
<input type="checkbox" {...column.getToggleHiddenProps()} />{' '}
{column.id}
<label>
<input type="checkbox" {...column.getToggleHiddenProps()} />{' '}
{column.id}
</label>
</div>
))}
<br />
+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"
+4
View File
@@ -0,0 +1,4 @@
{
"presets": ["react-app"],
"plugins": ["styled-components"]
}
+1
View File
@@ -0,0 +1 @@
SKIP_PREFLIGHT_CHECK=true
+7
View File
@@ -0,0 +1,7 @@
{
"extends": ["react-app", "prettier"],
"rules": {
// "eqeqeq": 0,
// "jsx-a11y/anchor-is-valid": 0
}
}
+23
View File
@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+29
View File
@@ -0,0 +1,29 @@
const path = require('path')
const resolveFrom = require('resolve-from')
const fixLinkedDependencies = config => {
config.resolve = {
...config.resolve,
alias: {
...config.resolve.alias,
react$: resolveFrom(path.resolve('node_modules'), 'react'),
'react-dom$': resolveFrom(path.resolve('node_modules'), 'react-dom'),
},
}
return config
}
const includeSrcDirectory = config => {
config.resolve = {
...config.resolve,
modules: [path.resolve('src'), ...config.resolve.modules],
}
return config
}
module.exports = [
['use-babel-config', '.babelrc'],
['use-eslint-config', '.eslintrc'],
fixLinkedDependencies,
// includeSrcDirectory,
]
+4
View File
@@ -0,0 +1,4 @@
# Full Width Resizable Table (via useFlexLayout)
- [Open this example in a new CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/full-width-resizable-table)
- `yarn` and `yarn start` to run and edit the example
+35
View File
@@ -0,0 +1,35 @@
{
"private": true,
"scripts": {
"start": "rescripts start",
"build": "rescripts build",
"test": "rescripts test",
"eject": "rescripts eject"
},
"dependencies": {
"namor": "^1.1.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1",
"react-table": "latest",
"styled-components": "^4.3.2"
},
"devDependencies": {
"@rescripts/cli": "^0.0.11",
"@rescripts/rescript-use-babel-config": "^0.0.8",
"@rescripts/rescript-use-eslint-config": "^0.0.9",
"babel-eslint": "10.0.1"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

+38
View File
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
+15
View File
@@ -0,0 +1,15 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
+3
View File
@@ -0,0 +1,3 @@
{
"infiniteLoopProtection": false
}
+193
View File
@@ -0,0 +1,193 @@
import React from 'react'
import styled from 'styled-components'
import { useTable, useResizeColumns, useFlexLayout } from 'react-table'
import makeData from './makeData'
const Styles = styled.div`
padding: 1rem;
.table {
${'' /* These styles are suggested for the table fill all available space in its containing element */}
display: block;
${'' /* These styles are required for a horizontaly scrollable table overflow */}
overflow: auto;
border-spacing: 0;
border: 1px solid black;
.thead {
${'' /* These styles are required for a scrollable body to align with the header properly */}
overflow-y: auto;
overflow-x: hidden;
}
.tbody {
${'' /* These styles are required for a scrollable table body */}
overflow-y: scroll;
overflow-x: hidden;
height: 250px;
}
.tr {
:last-child {
.td {
border-bottom: 0;
}
}
}
.th,
.td {
margin: 0;
padding: 0.5rem;
border-bottom: 1px solid black;
border-right: 1px solid black;
${'' /* In this example we use an absolutely position resizer,
so this is required. */}
position: relative;
:last-child {
border-right: 0;
}
.resizer {
display: inline-block;
background: blue;
width: 10px;
height: 100%;
position: absolute;
right: 0;
top: 0;
z-index: 1;
${'' /* prevents from scrolling while dragging on touch devices */}
touch-action:none;
&.isResizing {
background: red;
}
}
}
}
`
function Table({ columns, data }) {
const defaultColumn = React.useMemo(
() => ({
// When using the useFlexLayout:
minWidth: 30, // minWidth is only used as a limit for resizing
width: 150, // width is used for both the flex-basis and flex-grow
maxWidth: 200, // maxWidth is only used as a limit for resizing
}),
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable(
{
columns,
data,
defaultColumn,
},
useResizeColumns,
useFlexLayout
)
return (
<div {...getTableProps()} className="table">
<div>
{headerGroups.map(headerGroup => (
<div {...headerGroup.getHeaderGroupProps()} className="tr">
{headerGroup.headers.map(column => (
<div {...column.getHeaderProps()} className="th">
{column.render('Header')}
{/* Use column.getResizerProps to hook up the events correctly */}
<div
{...column.getResizerProps()}
className={`resizer ${column.isResizing ? 'isResizing' : ''}`}
/>
</div>
))}
</div>
))}
</div>
<div {...getTableBodyProps()} className="tbody">
{rows.map((row, i) => {
prepareRow(row)
return (
<div {...row.getRowProps()} className="tr">
{row.cells.map(cell => {
return (
<div {...cell.getCellProps()} className="td">
{cell.render('Cell')}
</div>
)
})}
</div>
)
})}
</div>
</div>
)
}
function App() {
const columns = React.useMemo(
() => [
{
Header: 'Name',
columns: [
{
Header: 'First Name',
accessor: 'firstName',
},
{
Header: 'Last Name',
accessor: 'lastName',
},
],
},
{
Header: 'Info',
columns: [
{
Header: 'Age',
accessor: 'age',
width: 50,
},
{
Header: 'Visits',
accessor: 'visits',
width: 50,
},
{
Header: 'Status',
accessor: 'status',
},
{
Header: 'Profile Progress',
accessor: 'progress',
},
],
},
],
[]
)
const data = React.useMemo(() => makeData(20), [])
return (
<Styles>
<Table columns={columns} data={data} />
</Styles>
)
}
export default App
+9
View File
@@ -0,0 +1,9 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
it('renders without crashing', () => {
const div = document.createElement('div')
ReactDOM.render(<App />, div)
ReactDOM.unmountComponentAtNode(div)
})
+13
View File
@@ -0,0 +1,13 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
+6
View File
@@ -0,0 +1,6 @@
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))
+40
View File
@@ -0,0 +1,40 @@
import namor from 'namor'
const range = len => {
const arr = []
for (let i = 0; i < len; i++) {
arr.push(i)
}
return arr
}
const newPerson = () => {
const statusChance = Math.random()
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100),
progress: Math.floor(Math.random() * 100),
status:
statusChance > 0.66
? 'relationship'
: statusChance > 0.33
? 'complicated'
: 'single',
}
}
export default function makeData(...lens) {
const makeDataLevel = (depth = 0) => {
const len = lens[depth]
return range(len).map(d => {
return {
...newPerson(),
subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined,
}
})
}
return makeDataLevel()
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,3 @@
{
"infiniteLoopProtection": false
}
+19 -4
View File
@@ -33,6 +33,20 @@ const Styles = styled.div`
}
`
function useControlledState(state, { instance }) {
return React.useMemo(() => {
if (state.groupBy.length) {
return {
...state,
hiddenColumns: [...state.hiddenColumns, ...state.groupBy].filter(
(d, i, all) => all.indexOf(d) === i
),
}
}
return state
}, [state])
}
function Table({ columns, data }) {
const {
getTableProps,
@@ -40,7 +54,7 @@ function Table({ columns, data }) {
headerGroups,
rows,
prepareRow,
state: { groupBy, expanded },
state,
} = useTable(
{
columns,
@@ -50,7 +64,8 @@ function Table({ columns, data }) {
useExpanded,
// Our custom plugin to add the expander column
hooks => {
hooks.flatColumns.push((columns, instance) => {
hooks.useControlledState.push(useControlledState)
hooks.flatColumns.push((columns, { instance }) => {
if (!instance.state.groupBy.length) {
return columns
}
@@ -100,7 +115,7 @@ function Table({ columns, data }) {
return null
},
},
...columns.map(d => ({ ...d, isVisible: !d.isGrouped })),
...columns,
]
})
}
@@ -113,7 +128,7 @@ function Table({ columns, data }) {
return (
<>
<pre>
<code>{JSON.stringify({ groupBy, expanded: expanded }, null, 2)}</code>
<code>{JSON.stringify({ state }, null, 2)}</code>
</pre>
<Legend />
<table {...getTableProps()}>
+4
View File
@@ -0,0 +1,4 @@
{
"presets": ["react-app"],
"plugins": ["styled-components"]
}
+1
View File
@@ -0,0 +1 @@
SKIP_PREFLIGHT_CHECK=true
+7
View File
@@ -0,0 +1,7 @@
{
"extends": ["react-app", "prettier"],
"rules": {
// "eqeqeq": 0,
// "jsx-a11y/anchor-is-valid": 0
}
}
+23
View File
@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+29
View File
@@ -0,0 +1,29 @@
const path = require('path')
const resolveFrom = require('resolve-from')
const fixLinkedDependencies = config => {
config.resolve = {
...config.resolve,
alias: {
...config.resolve.alias,
react$: resolveFrom(path.resolve('node_modules'), 'react'),
'react-dom$': resolveFrom(path.resolve('node_modules'), 'react-dom'),
},
}
return config
}
const includeSrcDirectory = config => {
config.resolve = {
...config.resolve,
modules: [path.resolve('src'), ...config.resolve.modules],
}
return config
}
module.exports = [
['use-babel-config', '.babelrc'],
['use-eslint-config', '.eslintrc'],
fixLinkedDependencies,
// includeSrcDirectory,
]
+6
View File
@@ -0,0 +1,6 @@
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app) and Rescripts.
You can:
- [Open this example in a new CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/streaming-rows)
- `yarn` and `yarn start` to run and edit the example
+36
View File
@@ -0,0 +1,36 @@
{
"private": true,
"scripts": {
"start": "rescripts start",
"build": "rescripts build",
"test": "rescripts test",
"eject": "rescripts eject"
},
"dependencies": {
"namor": "^1.1.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1",
"react-table": "latest",
"react-window": "^1.8.5",
"styled-components": "^4.3.2"
},
"devDependencies": {
"@rescripts/cli": "^0.0.11",
"@rescripts/rescript-use-babel-config": "^0.0.8",
"@rescripts/rescript-use-eslint-config": "^0.0.9",
"babel-eslint": "10.0.1"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

+38
View File
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
@@ -0,0 +1,15 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
@@ -0,0 +1,5 @@
{
"infiniteLoopProtection": false,
"hardReloadOnChange": false,
"view": "browser"
}
+217
View File
@@ -0,0 +1,217 @@
import React from 'react'
import styled from 'styled-components'
import { useTable, useBlockLayout, useRowSelect } from 'react-table'
const Styles = styled.div`
padding: 1rem;
.table {
display: inline-block;
border-spacing: 0;
border: 1px solid black;
.tr {
:last-child {
.td {
border-bottom: 0;
}
}
}
.th,
.td {
margin: 0;
padding: 0.5rem;
border-bottom: 1px solid black;
border-right: 1px solid black;
:last-child {
border-right: 0;
}
}
}
`
let sourceGridData = []
const updateRateMS = 16
function Table({ columns }) {
// Use the state and functions returned from useTable to build your UI
const [data, setData] = React.useState([])
const timerRunning = React.useRef()
if (!timerRunning.current) {
timerRunning.current = true
setInterval(() => {
sourceGridData.push(makeRow(sourceGridData.length))
let newData = [...sourceGridData]
setData(newData)
}, updateRateMS)
}
const defaultColumn = React.useMemo(
() => ({
width: 150,
}),
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
toggleAllRowsSelected,
prepareRow,
state,
} = useTable(
{
autoResetSelectedRows: false,
columns,
data,
defaultColumn,
},
useBlockLayout,
useRowSelect
)
// Render the UI for your table
return (
<>
<div {...getTableProps()} className="table">
<div className="thead">
{headerGroups.map(headerGroup => (
<div {...headerGroup.getHeaderGroupProps()} className="tr">
{headerGroup.headers.map(column => (
<div {...column.getHeaderProps()} className="th">
{column.render('Header')}
</div>
))}
</div>
))}
</div>
<div {...getTableBodyProps()}>
{rows.slice(0, 10).map(row => {
prepareRow(row)
return (
<div
{...row.getRowProps({
style: {
backgroundColor: row.isSelected ? 'green' : '',
},
onClick: e => {
toggleAllRowsSelected(false)
row.toggleRowSelected()
},
})}
className="tr"
>
{row.cells.map(cell => {
return (
<div {...cell.getCellProps()} className="td">
{cell.render('Cell')}
</div>
)
})}
</div>
)
})}
</div>
</div>
<pre>
<code>{JSON.stringify(state, null, 2)}</code>
</pre>
</>
)
}
function App() {
const columns = React.useMemo(
() => [
{
Header: 'ID',
accessor: 'id',
},
{
Header: 'Name',
accessor: 'name',
},
{
Header: 'age',
accessor: 'age',
},
{
Header: 'gender',
accessor: 'gender',
},
{
Header: 'height',
accessor: 'height',
},
{
Header: 'color',
accessor: 'col',
},
{
Header: 'dob',
accessor: 'dob',
},
],
[]
)
return (
<Styles>
<Table columns={columns} />
</Styles>
)
}
function makeRow(id) {
let r = Math.floor(Math.random() * 3) + 1
if (r === 0) {
return {
Id: id,
name: 'Billy Bob',
age: 12,
gender: 'male',
height: 95,
col: 'red',
dob: '14/05/2010',
}
} else if (r === 1) {
return {
Id: id,
name: 'Jenny Jane',
age: 42,
gender: 'female',
height: 142,
col: 'blue',
dob: '30/07/1954',
}
} else if (r === 2) {
return {
Id: id,
name: 'Steve McAlistaire',
age: 35,
gender: 'male',
height: 176,
col: 'green',
dob: '04/11/1982',
}
} else if (r === 3) {
return {
Id: id,
name: 'Jeff Joe',
age: 35,
gender: 'male',
height: 176,
col: 'green',
dob: '04/11/1982',
}
}
}
export default App
+9
View File
@@ -0,0 +1,9 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
it('renders without crashing', () => {
const div = document.createElement('div')
ReactDOM.render(<App />, div)
ReactDOM.unmountComponentAtNode(div)
})
+13
View File
@@ -0,0 +1,13 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
+6
View File
@@ -0,0 +1,6 @@
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))
+40
View File
@@ -0,0 +1,40 @@
import namor from 'namor'
const range = len => {
const arr = []
for (let i = 0; i < len; i++) {
arr.push(i)
}
return arr
}
const newPerson = () => {
const statusChance = Math.random()
return {
firstName: namor.generate({ words: 1, numbers: 0 }),
lastName: namor.generate({ words: 1, numbers: 0 }),
age: Math.floor(Math.random() * 30),
visits: Math.floor(Math.random() * 100),
progress: Math.floor(Math.random() * 100),
status:
statusChance > 0.66
? 'relationship'
: statusChance > 0.33
? 'complicated'
: 'single',
}
}
export default function makeData(...lens) {
const makeDataLevel = (depth = 0) => {
const len = lens[depth]
return range(len).map(d => {
return {
...newPerson(),
subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined,
}
})
}
return makeDataLevel()
}
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -74,8 +74,8 @@ function Table({ columns: userColumns, data, renderRowSubComponent }) {
prepareRow(row)
return (
// Use a React.Fragment here so the table markup is still valid
<>
<tr {...row.getRowProps()}>
<React.Fragment {...row.getRowProps()}>
<tr>
{row.cells.map(cell => {
return (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
@@ -100,7 +100,7 @@ function Table({ columns: userColumns, data, renderRowSubComponent }) {
</td>
</tr>
) : null}
</>
</React.Fragment>
)
})}
</tbody>
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "react-table",
"version": "7.0.0-rc.10",
"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 -213
View File
@@ -1,221 +1,11 @@
[
{
"timestamp": 1576222078852,
"timestamp": 1576690899177,
"files": [
{
"filename": "index.js",
"size": 22042,
"delta": -647
}
]
},
{
"timestamp": 1576165979638,
"files": [
{
"filename": "index.js",
"size": 22689,
"delta": 135
}
]
},
{
"timestamp": 1576044489324,
"files": [
{
"filename": "index.js",
"size": 22554,
"delta": -79
}
]
},
{
"timestamp": 1576020969676,
"files": [
{
"filename": "index.js",
"size": 22633,
"delta": -10
}
]
},
{
"timestamp": 1576007021431,
"files": [
{
"filename": "index.js",
"size": 22643,
"delta": -7
}
]
},
{
"timestamp": 1576004320856,
"files": [
{
"filename": "index.js",
"size": 22650,
"delta": 30
}
]
},
{
"timestamp": 1576003432935,
"files": [
{
"filename": "index.js",
"size": 22620,
"delta": 652
}
]
},
{
"timestamp": 1575985310396,
"files": [
{
"filename": "index.js",
"size": 21968,
"delta": 323
}
]
},
{
"timestamp": 1575910923566,
"files": [
{
"filename": "index.js",
"size": 21645,
"delta": 56
}
]
},
{
"timestamp": 1575859193604,
"files": [
{
"filename": "index.js",
"size": 21589,
"delta": 563
}
]
},
{
"timestamp": 1575690248030,
"files": [
{
"filename": "index.js",
"size": 21026,
"delta": 1
}
]
},
{
"timestamp": 1575675308812,
"files": [
{
"filename": "index.js",
"size": 21025,
"delta": -421
}
]
},
{
"timestamp": 1575620433902,
"files": [
{
"filename": "index.js",
"size": 21446,
"delta": -1
}
]
},
{
"timestamp": 1575607054721,
"files": [
{
"filename": "index.js",
"size": 21447,
"delta": 26
}
]
},
{
"timestamp": 1575605755429,
"files": [
{
"filename": "index.js",
"size": 21421,
"delta": 170
}
]
},
{
"timestamp": 1575579354616,
"files": [
{
"filename": "index.js",
"size": 21251,
"delta": 6
}
]
},
{
"timestamp": 1575578830463,
"files": [
{
"filename": "index.js",
"size": 21245,
"delta": 652
}
]
},
{
"timestamp": 1575555421868,
"files": [
{
"filename": "index.js",
"size": 20593,
"delta": 24
}
]
},
{
"timestamp": 1575517726476,
"files": [
{
"filename": "index.js",
"size": 20569,
"delta": 58
}
]
},
{
"timestamp": 1575391465436,
"files": [
{
"filename": "index.js",
"size": 20511,
"delta": 1
}
]
},
{
"timestamp": 1575345020328,
"files": [
{
"filename": "index.js",
"size": 20510,
"delta": 5
}
]
},
{
"timestamp": 1575331661254,
"files": [
{
"filename": "index.js",
"size": 20505,
"delta": 20505
"size": 22438,
"delta": 35
}
]
}
+3 -203
View File
@@ -1,211 +1,11 @@
[
{
"timestamp": 1576222088784,
"timestamp": 1576690906689,
"files": [
{
"filename": "index.es.js",
"size": 21847,
"delta": -668
}
]
},
{
"timestamp": 1576165986389,
"files": [
{
"filename": "index.es.js",
"size": 22515,
"delta": 140
}
]
},
{
"timestamp": 1576044496748,
"files": [
{
"filename": "index.es.js",
"size": 22375,
"delta": -76
}
]
},
{
"timestamp": 1576020979047,
"files": [
{
"filename": "index.es.js",
"size": 22451,
"delta": -10
}
]
},
{
"timestamp": 1576007027792,
"files": [
{
"filename": "index.es.js",
"size": 22461,
"delta": -7
}
]
},
{
"timestamp": 1576004327554,
"files": [
{
"filename": "index.es.js",
"size": 22468,
"delta": 30
}
]
},
{
"timestamp": 1576003439933,
"files": [
{
"filename": "index.es.js",
"size": 22438,
"delta": 656
}
]
},
{
"timestamp": 1575985317929,
"files": [
{
"filename": "index.es.js",
"size": 21782,
"delta": 324
}
]
},
{
"timestamp": 1575910931774,
"files": [
{
"filename": "index.es.js",
"size": 21458,
"delta": 55
}
]
},
{
"timestamp": 1575859200604,
"files": [
{
"filename": "index.es.js",
"size": 21403,
"delta": 561
}
]
},
{
"timestamp": 1575675317538,
"files": [
{
"filename": "index.es.js",
"size": 20842,
"delta": -383
}
]
},
{
"timestamp": 1575620442742,
"files": [
{
"filename": "index.es.js",
"size": 21225,
"delta": -1
}
]
},
{
"timestamp": 1575607059725,
"files": [
{
"filename": "index.es.js",
"size": 21226,
"delta": 26
}
]
},
{
"timestamp": 1575605764195,
"files": [
{
"filename": "index.es.js",
"size": 21200,
"delta": 170
}
]
},
{
"timestamp": 1575579366180,
"files": [
{
"filename": "index.es.js",
"size": 21030,
"delta": 7
}
]
},
{
"timestamp": 1575578837727,
"files": [
{
"filename": "index.es.js",
"size": 21023,
"delta": 575
}
]
},
{
"timestamp": 1575555429414,
"files": [
{
"filename": "index.es.js",
"size": 20448,
"delta": 21
}
]
},
{
"timestamp": 1575517715056,
"files": [
{
"filename": "index.es.js",
"size": 20427,
"delta": 59
}
]
},
{
"timestamp": 1575391457318,
"files": [
{
"filename": "index.es.js",
"size": 20368,
"delta": -1
}
]
},
{
"timestamp": 1575345027852,
"files": [
{
"filename": "index.es.js",
"size": 20369,
"delta": 4
}
]
},
{
"timestamp": 1575331668355,
"files": [
{
"filename": "index.es.js",
"size": 20365,
"delta": 20365
"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
})
})
}
+12 -18
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 => {
@@ -58,7 +58,7 @@ const defaultGetToggleHideAllColumnsProps = (props, instance) => [
},
]
function reducer(state, action, previousState, instanceRef) {
function reducer(state, action, previousState, instance) {
if (action.type === actions.init) {
return {
hiddenColumns: [],
@@ -69,7 +69,7 @@ function reducer(state, action, previousState, instanceRef) {
if (action.type === actions.resetHiddenColumns) {
return {
...state,
hiddenColumns: [],
hiddenColumns: instance.initialState.hiddenColumns || [],
}
}
@@ -104,9 +104,7 @@ function reducer(state, action, previousState, instanceRef) {
return {
...state,
hiddenColumns: shouldAll
? instanceRef.current.flatColumns.map(d => d.id)
: [],
hiddenColumns: shouldAll ? instance.flatColumns.map(d => d.id) : [],
}
}
}
@@ -123,10 +121,7 @@ function useInstanceBeforeDimensions(instance) {
}
const handleColumn = (column, parentVisible) => {
column.isVisible =
typeof column.isVisible !== 'undefined'
? column.isVisible
: parentVisible && !hiddenColumns.includes(column.id)
column.isVisible = parentVisible && !hiddenColumns.includes(column.id)
let totalVisibleHeaderCount = 0
@@ -187,7 +182,7 @@ function useInstance(instance) {
const getToggleHideAllColumnsProps = makePropGetter(
getToggleHideAllColumnsPropsHooks(),
getInstance()
{ instance: getInstance() }
)
// Snapshot hook and disallow more from being added
@@ -205,11 +200,10 @@ function useInstance(instance) {
})
}
column.getToggleHiddenProps = makePropGetter(
getToggleHiddenPropsHooks(),
getInstance(),
column
)
column.getToggleHiddenProps = makePropGetter(getToggleHiddenPropsHooks(), {
instance: getInstance(),
column,
})
})
Object.assign(instance, {
+75 -49
View File
@@ -133,8 +133,18 @@ export const useTable = (props, ...plugins) => {
reducer(initialState, { type: actions.init })
)
// Snapshot hook and disallow more from being added
const getUseControlledStateHooks = useConsumeHookGetter(
getInstance().hooks,
'useControlledState'
)
// Allow the user to control the final state with hooks
const state = useControlledState(reducerState)
const state = reduceHooks(
[...getUseControlledStateHooks(), useControlledState],
reducerState,
{ instance: getInstance() }
)
Object.assign(getInstance(), {
state,
@@ -153,10 +163,11 @@ export const useTable = (props, ...plugins) => {
// Decorate All the columns
let columns = React.useMemo(
() =>
reduceHooks(
getColumnsHooks(),
decorateColumnTree(userColumns, defaultColumn),
getInstance()
decorateColumnTree(
reduceHooks(getColumnsHooks(), userColumns, {
instance: getInstance(),
}),
defaultColumn
),
[
defaultColumn,
@@ -164,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() }),
]
)
@@ -254,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() }),
]
)
@@ -292,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() }),
]
)
@@ -320,7 +332,15 @@ export const useTable = (props, ...plugins) => {
loopHooks(getUseInstanceBeforeDimensions(), getInstance())
// Header Visibility is needed by this point
getInstance().totalColumnsWidth = calculateHeaderWidths(headers)
const [
totalColumnsMinWidth,
totalColumnsWidth,
totalColumnsMaxWidth,
] = calculateHeaderWidths(headers)
getInstance().totalColumnsMinWidth = totalColumnsMinWidth
getInstance().totalColumnsWidth = totalColumnsWidth
getInstance().totalColumnsMaxWidth = totalColumnsMaxWidth
// Snapshot hook and disallow more from being added
const getUseInstance = useConsumeHookGetter(
@@ -350,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,
})
}
)
@@ -398,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
@@ -424,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.
@@ -456,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 => {
@@ -467,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, {
@@ -482,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,
@@ -503,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(
@@ -514,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(
@@ -531,7 +545,9 @@ export const useTable = (props, ...plugins) => {
}
function calculateHeaderWidths(headers, left = 0) {
let sumTotalMinWidth = 0
let sumTotalWidth = 0
let sumTotalMaxWidth = 0
headers.forEach(header => {
let { headers: subHeaders } = header
@@ -539,18 +555,28 @@ function calculateHeaderWidths(headers, left = 0) {
header.totalLeft = left
if (subHeaders && subHeaders.length) {
header.totalWidth = calculateHeaderWidths(subHeaders, left)
const [totalMinWidth, totalWidth, totalMaxWidth] = calculateHeaderWidths(
subHeaders,
left
)
header.totalMinWidth = totalMinWidth
header.totalWidth = totalWidth
header.totalMaxWidth = totalMaxWidth
} else {
header.totalMinWidth = header.minWidth
header.totalWidth = Math.min(
Math.max(header.minWidth, header.width),
header.maxWidth
)
header.totalMaxWidth = header.maxWidth
}
if (header.isVisible) {
left += header.totalWidth
sumTotalMinWidth += header.totalMinWidth
sumTotalWidth += header.totalWidth
sumTotalMaxWidth += header.totalMaxWidth
}
})
return sumTotalWidth
return [sumTotalMinWidth, sumTotalWidth, sumTotalMaxWidth]
}
+2
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'
@@ -11,3 +12,4 @@ export { useColumnOrder } from './plugin-hooks/useColumnOrder'
export { useResizeColumns } from './plugin-hooks/useResizeColumns'
export { useAbsoluteLayout } from './plugin-hooks/useAbsoluteLayout'
export { useBlockLayout } from './plugin-hooks/useBlockLayout'
export { useFlexLayout } from './plugin-hooks/useFlexLayout'
+7 -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}`,
})
@@ -36,6 +36,7 @@ export default function makeDefaultPluginHooks() {
return {
useOptions: [],
stateReducers: [],
useControlledState: [],
columns: [],
columnsDeps: [],
flatColumns: [],
@@ -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()
})
@@ -64,6 +64,9 @@ function Table({ columns, data }) {
columns,
data,
defaultColumn,
initialState: {
groupBy: ["Column Doesn't Exist"],
},
},
useGroupBy,
useExpanded
+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: {
+11 -8
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)
@@ -17,7 +17,7 @@ export const useColumnOrder = hooks => {
useColumnOrder.pluginName = 'useColumnOrder'
function reducer(state, action) {
function reducer(state, action, previousState, instance) {
if (action.type === actions.init) {
return {
columnOrder: [],
@@ -28,7 +28,7 @@ function reducer(state, action) {
if (action.type === actions.resetColumnOrder) {
return {
...state,
columnOrder: [],
columnOrder: instance.initialState.columnOrder || [],
}
}
@@ -40,11 +40,14 @@ function reducer(state, action) {
}
}
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
+7 -8
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 => {
@@ -38,7 +38,7 @@ const defaultGetExpandedToggleProps = (props, instance, row) => [
]
// Reducer
function reducer(state, action) {
function reducer(state, action, previousState, instance) {
if (action.type === actions.init) {
return {
expanded: {},
@@ -49,7 +49,7 @@ function reducer(state, action) {
if (action.type === actions.resetExpanded) {
return {
...state,
expanded: {},
expanded: instance.initialState.expanded || {},
}
}
@@ -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(() => {
+10 -34
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'
@@ -33,7 +34,7 @@ function reducer(state, action, previousState, instance) {
if (action.type === actions.resetFilters) {
return {
...state,
filters: [],
filters: instance.initialState.filters || [],
}
}
@@ -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
)
}
+53
View File
@@ -0,0 +1,53 @@
export function useFlexLayout(hooks) {
hooks.getTableBodyProps.push(getTableBodyProps)
hooks.getRowProps.push(getRowStyles)
hooks.getHeaderGroupProps.push(getRowStyles)
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,
})
}
+28 -12
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
@@ -46,7 +46,7 @@ const defaultGetGroupByToggleProps = (props, instance, header) => [
]
// Reducer
function reducer(state, action) {
function reducer(state, action, previousState, instance) {
if (action.type === actions.init) {
return {
groupBy: [],
@@ -57,7 +57,7 @@ function reducer(state, action) {
if (action.type === actions.resetGroupBy) {
return {
...state,
groupBy: [],
groupBy: instance.initialState.groupBy || [],
}
}
@@ -81,11 +81,20 @@ function reducer(state, action) {
}
}
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
const groupByColumns = groupBy.map(g => flatColumns.find(col => col.id === g))
const groupByColumns = groupBy
.map(g => flatColumns.find(col => col.id === g))
.filter(col => !!col)
const nonGroupByColumns = flatColumns.filter(col => !groupBy.includes(col.id))
flatColumns = [...groupByColumns, ...nonGroupByColumns]
@@ -158,8 +167,7 @@ function useInstance(instance) {
flatHeaders.forEach(header => {
header.getGroupByToggleProps = makePropGetter(
getGroupByTogglePropsHooks(),
getInstance(),
header
{ instance: getInstance(), header }
)
})
@@ -180,6 +188,11 @@ function useInstance(instance) {
return [rows, flatRows]
}
// Ensure that the list of filtered columns exist
const existingGroupBy = groupBy.filter(g =>
flatColumns.find(col => col.id === g)
)
// Find the columns that can or are aggregating
// Uses each column to aggregate rows into a single value
const aggregateRowsToValues = (rows, isAggregated) => {
@@ -187,7 +200,7 @@ function useInstance(instance) {
flatColumns.forEach(column => {
// Don't aggregate columns that are in the groupBy
if (groupBy.includes(column.id)) {
if (existingGroupBy.includes(column.id)) {
values[column.id] = rows[0] ? rows[0].values[column.id] : null
return
}
@@ -234,11 +247,11 @@ function useInstance(instance) {
// Recursively group the data
const groupRecursively = (rows, depth = 0, parentId) => {
// This is the last level, just return the rows
if (depth === groupBy.length) {
if (depth === existingGroupBy.length) {
return rows
}
const columnId = groupBy[depth]
const columnId = existingGroupBy[depth]
// Group the rows together for this level
let groupedRows = groupByFn(rows, columnId)
@@ -251,7 +264,10 @@ function useInstance(instance) {
subRows = groupRecursively(subRows, depth + 1, id)
const values = aggregateRowsToValues(subRows, depth < groupBy.length)
const values = aggregateRowsToValues(
subRows,
depth < existingGroupBy.length
)
const row = {
id,
+1 -1
View File
@@ -37,7 +37,7 @@ function reducer(state, action, previousState, instance) {
if (action.type === actions.resetPage) {
return {
...state,
pageIndex: 0,
pageIndex: instance.initialState.pageIndex || 0,
}
}
+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,
})
}
})
}
+10 -11
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 => {
@@ -81,7 +81,7 @@ function reducer(state, action, previousState, instance) {
if (action.type === actions.resetSelectedRows) {
return {
...state,
selectedRowIds: {},
selectedRowIds: instance.initialState.selectedRowIds || {},
}
}
@@ -126,16 +126,16 @@ function reducer(state, action, previousState, instance) {
return state
}
let newSelectedRowPaths = { ...state.selectedRowIds }
let newSelectedRowIds = { ...state.selectedRowIds }
const handleRowById = id => {
const row = flatGroupedRowsById[id]
if (!row.isGrouped) {
if (!isSelected && shouldExist) {
newSelectedRowPaths[id] = true
newSelectedRowIds[id] = true
} else if (isSelected && !shouldExist) {
delete newSelectedRowPaths[id]
delete newSelectedRowIds[id]
}
}
@@ -148,12 +148,12 @@ function reducer(state, action, previousState, instance) {
return {
...state,
selectedRowIds: newSelectedRowPaths,
selectedRowIds: newSelectedRowIds,
}
}
}
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 }
)
})
+2 -2
View File
@@ -18,7 +18,7 @@ export const useRowState = hooks => {
useRowState.pluginName = 'useRowState'
function reducer(state, action) {
function reducer(state, action, previousState, instance) {
if (action.type === actions.init) {
return {
rowState: {},
@@ -29,7 +29,7 @@ function reducer(state, action) {
if (action.type === actions.resetRowState) {
return {
...state,
rowState: {},
rowState: instance.initialState.rowState || {},
}
}
+6 -7
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 [
@@ -66,7 +66,7 @@ function reducer(state, action, previousState, instance) {
if (action.type === actions.resetSortBy) {
return {
...state,
sortBy: [],
sortBy: instance.initialState.sortBy || [],
}
}
@@ -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