Compare commits

...
Author SHA1 Message Date
tannerlinsley 3aef7d3379 v7.0.0-alpha.22 2019-08-15 14:20:40 -06:00
tannerlinsley d9a4b6bd85 refactor: improve renderer function ergonomics
The renderer function for headers, columns, cells, aggregates, filters, etc used to mix properties
from all of those contexts, including rows. Now thow contexts are located on their own reserved
properties, eg. `Cell: ({ cell: { value}, row, column, ...instance }) => value`

BREAKING CHANGE: The renderer function for headers, columns, cells, aggregates, filters, etc used
2019-08-15 14:16:52 -06:00
tannerlinsley d50ec588bc fix(use-pagination): fixed use pagination pageIndex bug
Use pagination will no longer synchronously reset the pageIndex to 0 on mount
2019-08-15 09:55:22 -06:00
tannerlinsley f9242f604d fix(usesortby): fix usesortby merge regression 2019-08-15 09:04:07 -06:00
Eugene KrevenetsandTanner Linsley 59f6a768a7 improve(use-table): use single instance of defaultColumn property (#1451)
in case of using construction like:
```
{
  defaultColumn = {}
}
```
`defaultColumn` will get new instance each time, so as result it force to recalculation each of `React.useMemo`.
2019-08-15 08:58:42 -06:00
Maximilian BrandauandTanner Linsley bcd0da7379 fix: update colSpan (#1447)
Only count visible columns for determining the colSpan

fix #1446
2019-08-15 08:57:22 -06:00
tannerlinsley 14ea0abf27 docs(readme): fix Zappi link 2019-08-15 08:39:03 -06:00
tannerlinsley 696edacd48 fix(use-flex-layout): fix flex layout hook to use new internal hooks 2019-08-15 08:36:33 -06:00
tannerlinsley f665972584 Merge branch 'master' of https://github.com/react-tools/react-table 2019-08-15 08:31:57 -06:00
tannerlinsley deb15c3908 docs(readme): updated readme 2019-08-15 08:28:37 -06:00
Eugene KrevenetsandTanner Linsley c77ffacdc9 improve(sort): don't sort subrows less than 2 characters (#1449)
it improves performance because cuts a lot of sorting manipulations
2019-08-15 08:11:12 -06:00
gargrohandTanner Linsley d4303a2468 [v7] useSort - Multisort functionality: Limit max cols and optional shift key (#1433)
* [v7] useSort - Multisort functionality: Limit `multiSort` number and configurable shift key

1. Provide configuration for multisort that pressing shift key is not compulsory

2. Configurable limit on max number of columns for multisort, like configuration has been provided that `maxMultiSortColCount` is 3, suppose currenlty table is sorted by `[A, B, C]` and then clicking `D` for sorting should result in table sorted by `[B, C , D]`

* update readme for new multisort options

* Use `isMultiSortEvent` function 

so as to make `shift` key optional or take decision based on other parameters for multisorting

* `isMultiSortEvent` updated readme
2019-08-14 10:47:02 -06:00
Marian LumbaandTanner Linsley dc629aedfa updating code sandbox links (#1437) 2019-08-08 14:11:32 -06:00
tannerlinsley 134f3dc064 v7.0.0-alpha.21 2019-08-06 22:34:17 -06:00
tannerlinsley a667b7cb13 fix(use-pagination): better controlled/manual use-pagination 2019-08-06 22:32:17 -06:00
170 changed files with 11873 additions and 1017 deletions
+43 -33
View File
@@ -77,7 +77,7 @@ Hooks for building **lightweight, fast and extendable datagrids** for React
</a>
</td>
<td align="center" valign="middle">
<a href="https://zappi.com/web" target="_blank">
<a href="https://zappi.io/web/" target="_blank">
<img width='230' src="https://raw.githubusercontent.com/tannerlinsley/files/master/images/patreon/sponsor-zappi.png">
</a>
</td>
@@ -111,11 +111,9 @@ Hooks for building **lightweight, fast and extendable datagrids** for React
</a>
</td>
<td>
<ul>
<li>Nicholas Kaufmann</li>
<li>Pekka</li>
<li>Jon Eickmeier</li>
</ul>
<div>Nicholas Kaufmann</div>
<div><a href="https://www.metso.com/">Pekka</a></div>
<div>Jon Eickmeier</div>
</td>
</tr>
</tbody>
@@ -130,14 +128,12 @@ Hooks for building **lightweight, fast and extendable datagrids** for React
</a>
</td>
<td>
<ul>
<li>Sortmy.games</li>
<li>Hugo Meissner</li>
<li>Benoit Leger-Derville</li>
<li>Thomas Funk</li>
<li>Dan Houle</li>
<li>David Pickut</li>
</ul>
<div>Sortmy.games</div>
<div>Hugo Meissner</div>
<div>Benoit Leger-Derville</div>
<div>Thomas Funk</div>
<div>Dan Houle</div>
<div>David Pickut</div>
</td>
</tr>
</tbody>
@@ -182,15 +178,18 @@ import {
# Examples
- [Basic - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/basic-client-side)
- [Sorting - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/sorting-client-side)
- [Filtering - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/filtering-client-side)
- [Grouping - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/grouping-client-side)
- [Pagination - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/pagination-client-side)
- [Row Selection - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/row-selection-client-side)
- [Expanding - Client Side](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/expanding-client-side)
- [Sub Components](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/sub-components)
- [Editable Data](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/editable-cells)
- Simple
- [Basic](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/basic)
- [Sorting](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/sorting)
- [Filtering](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/filtering)
- [Grouping](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/grouping)
- [Pagination](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/pagination)
- [Row Selection](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/row-selection)
- [Expanding](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/expanding)
- [Sub Components](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/sub-components)
- [Editable Data](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/editable-data)
- Controlled
- [Pagination (Controlled)](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/pagination-controlled)
# Concepts
@@ -223,6 +222,8 @@ React Table is essentially a compatible collection of **custom React hooks**:
- The primary React Table hook
- [`useTable`](#usetable)
- Utility Hooks
- [`useTableState`](#useTableState)
- Plugin Hooks
- Core Plugin Hooks
- [`useTableState`](#useTableState)
@@ -232,6 +233,8 @@ React Table is essentially a compatible collection of **custom React hooks**:
- [`useExpanded`](#useExpanded)
- [`usePagination`](#usePagination)
- [`useTokenPagination`](#useTokenPagination)
- [`useRowSelect`](#useRowSelect)
- [`useRowState`](#useRowState)
- Layout Plugin Hooks
- [`useFlexLayout`](#useFlexLayout)
- [`useAbsoluteLayout`](#useAbsoluteLayout) (coming soon!)
@@ -348,13 +351,13 @@ The following options are supported on any column object you can pass to `column
- The data model for hidden columns is still calculated including sorting, filters, and grouping.
- `Header: String | Function | React.Component => JSX`
- Optional
- Defaults to `({ id }) => id`
- Defaults to `() => null`
- Receives the table instance and column model as props
- Must either be a **string or return valid JSX**
- If a function/component is passed, it will be used for formatting the header value, eg. You can use a `Header` function to dynamically format the header using any table or column state.
- `Cell: Function | React.Component => JSX`
- Optional
- Defaults to `({ value }) => value`
- Defaults to `({ cell: { value } }) => value`
- Receives the table instance and cell model as props
- Must return valid JSX
- This function (or component) is primarily used for formatting the column value, eg. If your column accessor returns a date object, you can use a `Cell` function to format that date to a readable format.
@@ -421,7 +424,8 @@ The following properties are available on every `Column` object returned by the
- `visible: Boolean`
- The resolved visible state for the column, derived from the column's `show` property
- `render: Function(type: String | Function | Component, ?props)`
- This function is used to render content in context of a column.
- This function is used to render content with the added context of a column.
- The entire table `instance` will be passed to the renderer with the addition of a `column` property, containing a reference to the column
- If `type` is a string, will render using the `column[type]` renderer. React Table ships with default `Header` renderers. Other renderers like `Filter` are available via hooks like `useFilters`.
- If a function or component is passed instead of a string, it will be be passed the table instance and column model as props and is expected to return any valid JSX.
- `getHeaderProps: Function(?props)`
@@ -476,7 +480,8 @@ The following additional properties are available on every `Cell` object returne
- Custom props may be passed. **NOTE: Custom props will override built-in table props, so be careful!**
- `render: Function(type: String | Function | Component, ?props)`
- **Required**
- This function is used to render content in context of a cell.
- This function is used to render content with the added context of a cell.
- The entire table `instance` will be passed to the renderer with the addition of `column`, `row` and `cell` properties, containing a reference to each respective item.
- If `type` is a string, will render using the `column[type]` renderer. React Table ships with a default `Cell` renderer. Other renderers like `Aggregated` are available via hooks like `useFilters`.
- If a function or component is passed instead of a string, it will be be passed the table instance and cell model as props and is expected to return any valid JSX.
@@ -584,6 +589,11 @@ The following options are supported via the main options object passed to `useTa
- Disables sorting for every column in the entire table.
- `disableMultiSort: Bool`
- Disables multi-sorting for the entire table.
- `isMultiSortEvent: Function`
- Allows to override default multisort behaviour(i.e. multisort applies when shift key is presssed), if this function is provided then returned boolean value from this function will make decision whether newly applied sort action will be considered as multisort or not.
- Receives `event` as argument.
- `maxMultiSortColCount: Number`
- Limit on max number of columns for multisort, e.g. if set to 3, and suppose table is sorted by `[A, B, C]` and then clicking `D` for sorting should result in table sorted by `[B, C , D]`
- `disableSortRemove: Bool`
- If true, the un-sorted state will not be available to columns once they have been sorted.
- `disableMultiRemove: Bool`
@@ -789,7 +799,7 @@ The following properties are available on every `Column` object returned by the
- An column-level function used to update the filter value for this column
- `filterValue: any`
- The current filter value for this column, resolved from the table state's `filters` object
- `preFilteredRows: Array<row>`
- `preFilteredColumnRows: Array<row>`
- The array of rows that were originally passed to this columns filter **before** they were filtered.
- This array of rows can be useful if building faceted filter options.
@@ -1056,7 +1066,7 @@ function App() {
// then sum any of those counts if they are
// aggregated further
aggregate: ['sum', 'count'],
Aggregated: ({ value }) => `${value} Names`,
Aggregated: ({ cell: { value } }) => `${value} Names`,
},
{
Header: 'Last Name',
@@ -1066,7 +1076,7 @@ function App() {
// being aggregated, then sum those counts if
// they are aggregated further
aggregate: ['sum', 'uniqueCount'],
Aggregated: ({ value }) => `${value} Unique Names`,
Aggregated: ({ cell: { value } }) => `${value} Unique Names`,
},
],
},
@@ -1078,14 +1088,14 @@ function App() {
accessor: 'age',
// Aggregate the average age of visitors
aggregate: 'average',
Aggregated: ({ value }) => `${value} (avg)`,
Aggregated: ({ cell: { value } }) => `${value} (avg)`,
},
{
Header: 'Visits',
accessor: 'visits',
// Aggregate the sum of all visits
aggregate: 'sum',
Aggregated: ({ value }) => `${value} (total)`,
Aggregated: ({ cell: { value } }) => `${value} (total)`,
},
{
Header: 'Status',
@@ -1096,7 +1106,7 @@ function App() {
accessor: 'progress',
// Use our custom roundedMedian aggregator
aggregate: roundedMedian,
Aggregated: ({ value }) => `${value} (med)`,
Aggregated: ({ cell: { value } }) => `${value} (med)`,
},
],
},
+1
View File
@@ -13,4 +13,5 @@ module.exports = {
rootDir: path.resolve(__dirname, '../../'),
roots: ['<rootDir>/src', __dirname],
transformIgnorePatterns: ['node_modules'],
snapshotSerializers: [require.resolve('snapshot-diff/serializer.js')],
}
+1
View File
@@ -1 +1,2 @@
import '@testing-library/jest-dom/extend-expect'
import 'snapshot-diff/extend-expect'

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

+1 -1
View File
@@ -2,5 +2,5 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
You can:
- [Open this example in a new CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/basic)
- [Open this example in a new CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/editable-data)
- `yarn` and `yarn start` to run and edit the example
@@ -2,5 +2,5 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
You can:
- [Open this example in a new CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/basic)
- [Open this example in a new CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/expanding)
- `yarn` and `yarn start` to run and edit the example

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

@@ -2,5 +2,5 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
You can:
- [Open this example in a new CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/basic)
- [Open this example in a new CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/filtering)
- `yarn` and `yarn start` to run and edit the example

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

@@ -36,14 +36,16 @@ const Styles = styled.div`
`
// Define a default UI for filtering
function DefaultColumnFilter({ filterValue, setFilter }) {
function DefaultColumnFilter({ filterValue, preFilteredRows, setFilter }) {
const count = preFilteredRows.length
return (
<input
value={filterValue || ''}
onChange={e => {
setFilter(e.target.value || undefined) // Set undefined to remove the filter entirely
}}
placeholder="Search..."
placeholder={`Search ${count} records...`}
/>
)
}
@@ -88,6 +90,7 @@ function SelectColumnFilter({ filterValue, setFilter, preFilteredRows, id }) {
function SliderColumnFilter({ filterValue, setFilter, preFilteredRows, id }) {
// Calculate the min and max
// using the preFilteredRows
const [min, max] = React.useMemo(
() => {
let min = 0
@@ -120,7 +123,25 @@ function SliderColumnFilter({ filterValue, setFilter, preFilteredRows, id }) {
// This is a custom UI for our 'between' or number range
// filter. It uses two number boxes and filters rows to
// ones that have values between the two
function NumberRangeColumnFilter({ filterValue = [], setFilter }) {
function NumberRangeColumnFilter({
filterValue = [],
preFilteredRows,
setFilter,
id,
}) {
const [min, max] = React.useMemo(
() => {
let min = 0
let max = 0
preFilteredRows.forEach(row => {
min = Math.min(row.values[id], min)
max = Math.max(row.values[id], max)
})
return [min, max]
},
[id, preFilteredRows]
)
return (
<div
style={{
@@ -134,7 +155,7 @@ function NumberRangeColumnFilter({ filterValue = [], setFilter }) {
const val = e.target.value
setFilter((old = []) => [val ? parseInt(val, 10) : undefined, old[1]])
}}
placeholder="Min"
placeholder={`Min (${min})`}
style={{
width: '70px',
marginRight: '0.5rem',
@@ -148,7 +169,7 @@ function NumberRangeColumnFilter({ filterValue = [], setFilter }) {
const val = e.target.value
setFilter((old = []) => [old[0], val ? parseInt(val, 10) : undefined])
}}
placeholder="Max"
placeholder={`Max (${max})`}
style={{
width: '70px',
marginLeft: '0.5rem',
@@ -2,5 +2,5 @@ This project was bootstrapped with [Create React App](https://github.com/faceboo
You can:
- [Open this example in a new CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/basic)
- [Open this example in a new CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/grouping)
- `yarn` and `yarn start` to run and edit the example

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

+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/pagination-controlled)
- `yarn` and `yarn start` to run and edit the example

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

+276
View File
@@ -0,0 +1,276 @@
import React from 'react'
import styled from 'styled-components'
import { useTable, useTableState, usePagination } from 'react-table'
import makeData from './makeData'
const Styles = styled.div`
padding: 1rem;
table {
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;
}
}
}
.pagination {
padding: 0.5rem;
}
`
// Let's add a fetchData method to our Table component that will be used to fetch
// new data when pagination state changes
// We can also add a loading state to let our table know it's loading new data
function Table({
columns,
data,
fetchData,
loading,
pageCount: controlledPageCount,
}) {
// Use useTableState to hoist the state (and state updater) out of the table and control it
const tableState = useTableState({ pageIndex: 0 })
// Now we can get our table state from the hoisted table state tuple
const [{ pageIndex, pageSize }] = tableState
// Listen for changes in pagination and use the state to fetch our new data
React.useEffect(
() => {
fetchData({ pageIndex, pageSize })
},
[fetchData, pageIndex, pageSize]
)
const {
getTableProps,
headerGroups,
prepareRow,
page,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
} = useTable(
{
columns,
data,
state: tableState, // Pass our hoisted table state
manualPagination: true, // Tell the usePagination
// hook that we'll handle our own data fetching
// This means we'll also have to provide our own
// pageCount.
pageCount: controlledPageCount,
},
usePagination
)
// Render the UI for your table
return (
<>
<pre>
<code>
{JSON.stringify(
{
pageIndex,
pageSize,
pageCount,
canNextPage,
canPreviousPage,
},
null,
2
)}
</code>
</pre>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody>
{page.map(
(row, i) =>
prepareRow(row) || (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
)
})}
</tr>
)
)}
{loading ? (
// Use our custom loading state to show a loading indicator
<tr>
<td>Loading...</td>
</tr>
) : null}
</tbody>
</table>
{/*
Pagination can be built however you'd like.
This is just a very basic UI implementation:
*/}
<div className="pagination">
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}>
{'<<'}
</button>{' '}
<button onClick={() => previousPage()} disabled={!canPreviousPage}>
{'<'}
</button>{' '}
<button onClick={() => nextPage()} disabled={!canNextPage}>
{'>'}
</button>{' '}
<button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}>
{'>>'}
</button>{' '}
<span>
Page{' '}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{' '}
</span>
<span>
| Go to page:{' '}
<input
type="number"
defaultValue={pageIndex + 1}
onChange={e => {
const page = e.target.value ? Number(e.target.value) - 1 : 0
gotoPage(page)
}}
style={{ width: '100px' }}
/>
</span>{' '}
<select
value={pageSize}
onChange={e => {
setPageSize(Number(e.target.value))
}}
>
{[10, 20, 30, 40, 50].map(pageSize => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
</>
)
}
// Let's simulate a large dataset on the server (outside of our component)
const serverData = makeData(10000)
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',
},
{
Header: 'Visits',
accessor: 'visits',
},
{
Header: 'Status',
accessor: 'status',
},
{
Header: 'Profile Progress',
accessor: 'progress',
},
],
},
],
[]
)
// We'll start our table without any data
const [data, setData] = React.useState([])
const [loading, setLoading] = React.useState(false)
const [pageCount, setPageCount] = React.useState(0)
const fetchData = React.useCallback(({ pageSize, pageIndex }) => {
// This will get called when the table needs new data
// You could fetch your data from literally anywhere,
// even a server. But for this example, we'll just fake it.
// Set the loading state
setLoading(true)
// We'll even set a delay to simulate a server here
setTimeout(() => {
const startRow = pageSize * pageIndex
const endRow = startRow + pageSize
setData(serverData.slice(startRow, endRow))
// Your server could send back total page count.
// For now we'll just fake it, too
setPageCount(Math.ceil(serverData.length / pageSize))
setLoading(false)
}, 1000)
}, [])
return (
<Styles>
<Table
columns={columns}
data={data}
fetchData={fetchData}
loading={loading}
pageCount={pageCount}
/>
</Styles>
)
}
export default App
+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/pagination)
- `yarn` and `yarn start` to run and edit the example

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Some files were not shown because too many files have changed in this diff Show More