Compare commits

..
Author SHA1 Message Date
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
tannerlinsley 4f01c32216 v7.0.0-alpha.20 2019-08-06 20:01:52 -06:00
tannerlinsley 5145a632c9 Merge branch 'master' of https://github.com/react-tools/react-table 2019-08-06 20:01:11 -06:00
tannerlinsley 8508a6567d feat(multiple): useRowState, fix useRowSelect/useSortBy/usePagination 2019-08-06 19:57:48 -06:00
PierreandTanner Linsley 1e80dd85d6 fix: disableSorting in column config level (#1434) 2019-08-06 08:03:17 -06:00
Tanner LinsleyandGitHub 3cbb49fc37 Update README.md 2019-08-05 14:52:56 -06:00
tannerlinsley 110e04bf61 v7.0.0-alpha.19 2019-08-05 09:00:16 -06:00
tannerlinsley 2b30c84abc fix(utils/example): fixed ensurePluginOrder utility, perf/debug updates 2019-08-05 08:59:35 -06:00
tannerlinsley fd0fe43ad9 Merge branch 'master' of https://github.com/react-tools/react-table 2019-08-05 08:45:18 -06:00
gargrohandTanner Linsley 5975e0c4cd [Minor] use actual param in ensurePluginOrder (#1429) 2019-08-05 08:45:01 -06:00
gargrohandTanner Linsley e7bbddbb0f [Minor] typo correction (#1431) 2019-08-05 08:44:16 -06:00
Tanner LinsleyandGitHub 49a1023467 Update README.md 2019-08-05 08:43:39 -06:00
Tanner LinsleyandGitHub 7167350921 Update README.md 2019-08-05 08:39:54 -06:00
Tanner LinsleyandGitHub 77cb0d97a8 Update README.md 2019-08-05 07:39:55 -06:00
Tanner LinsleyandGitHub 0672de486a Update README.md 2019-08-05 07:38:07 -06:00
Tanner LinsleyandGitHub e0f83d32fe Update README.md 2019-08-05 06:53:29 -06:00
Tanner LinsleyandGitHub 3aaa5b9b1e Update README.md 2019-08-05 06:52:46 -06:00
Tanner LinsleyandGitHub 352de348fe Update README.md 2019-08-05 06:48:00 -06:00
tannerlinsley 21d3853dba v7.0.0-alpha.18 2019-08-03 14:37:38 -06:00
tannerlinsley 095979b9db docs(readme): updated readme 2019-08-03 14:36:52 -06:00
tannerlinsley f52d5af115 docs(examples): updated example directory names 2019-08-03 14:31:13 -06:00
tannerlinsley 037c32345f feat(use-row-select): added useRowSelect plugin hook + related 2019-08-03 14:20:08 -06:00
tannerlinsley 6ad0d4e0c0 Merge branch 'master' of https://github.com/react-tools/react-table 2019-08-02 07:43:30 -06:00
tannerlinsley 512790bc1c fix(multiple): sub-components example, minor refactors
Fixes #1423
2019-08-02 07:42:42 -06:00
gargrohandTanner Linsley 118b873531 fix(useFilters): Honor column level disableFilters by setting canFilters correct value (#1427)
* correcting typos

* [minor ] Readme update

* Honor `columnDisableFilters` in useFilters by setting `canFilters` correct value
2019-08-02 07:28:38 -06:00
tannerlinsley 39c2b152f6 docs(readme): better docs on nested columns 2019-07-31 16:21:03 -06:00
tannerlinsley adfc82b472 v7.0.0-alpha.17 2019-07-31 12:27:58 -06:00
tannerlinsley 6030282428 Merge branch 'master' of https://github.com/react-tools/react-table 2019-07-31 12:27:18 -06:00
tannerlinsley f6ee2a3d99 fix(npm/examples): added src back to npm package, fixed grouping example 2019-07-31 12:27:06 -06:00
AurimasandTanner Linsley 633cc27a99 fix(utils): default Cell renderer cleanup (#1421) 2019-07-31 08:47:21 -06:00
tannerlinsley 02b2671f5c v7.0.0-alpha.16 2019-07-30 17:01:59 -06:00
tannerlinsley 2c5610d885 test(usegroupby/useexpanded): improved tests for useGroupBy/useExpanded 2019-07-30 17:00:59 -06:00
tannerlinsley 12e7b3220d test: snapshots for useFilters, useGroupBy, useSortBy 2019-07-30 15:57:11 -06:00
tannerlinsley bcefe5d6e8 v7.0.0-alpha.15 2019-07-30 14:10:19 -06:00
tannerlinsley df827d76e2 test(usefilters): added useFilters test placeholder 2019-07-30 14:09:48 -06:00
tannerlinsley 0ae8693444 fix(global): fix npm dist, update docs 2019-07-30 14:07:31 -06:00
tannerlinsley 56f3dc9fe6 docs(example): removed page options from the pagination example state 2019-07-30 12:54:19 -06:00
tannerlinsley 5f58786e94 docs(examples): added pagination example 2019-07-30 12:51:14 -06:00
182 changed files with 57959 additions and 314 deletions
+848 -108
View File
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

+275
View File
@@ -0,0 +1,275 @@
import React from 'react'
import styled from 'styled-components'
import { useTable, 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;
}
input {
font-size: 1rem;
padding: 0;
margin: 0;
border: 0;
}
}
}
.pagination {
padding: 0.5rem;
}
`
// Create an editable cell renderer
const EditableCell = ({
value: initialValue,
row: { index },
column: { id },
updateMyData, // This is a custom function that we supplied to our table instance
}) => {
// We need to keep and update the state of the cell normally
const [value, setValue] = React.useState(initialValue)
const onChange = e => {
setValue(e.target.value)
}
// We'll only update the external data when the input is blurred
const onBlur = () => {
updateMyData(index, id, value)
}
return <input value={value} onChange={onChange} onBlur={onBlur} />
}
// Set our editable cell renderer as the default Cell renderer
const defaultColumn = {
Cell: EditableCell,
}
// Be sure to pass our updateMyData and the disablePageResetOnDataChange option
function Table({ columns, data, updateMyData, disablePageResetOnDataChange }) {
// For this example, we're using pagination to illustrate how to stop
// the current page from resetting when our data changes
// Otherwise, nothing is different here.
const {
getTableProps,
headerGroups,
prepareRow,
page,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
state: [{ pageIndex, pageSize }],
} = useTable(
{
columns,
data,
defaultColumn,
disablePageResetOnDataChange,
// updateMyData isn't part of the API, but
// anything we put into these options will
// automatically be available on the instance.
// That way we can call this function from our
// cell renderer!
updateMyData,
},
usePagination
)
// Render the UI for your table
return (
<>
<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>
)
)}
</tbody>
</table>
<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>
</>
)
}
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',
},
],
},
],
[]
)
const [data, setData] = React.useState(() => makeData(20))
// We need to keep the table from resetting the pageIndex when we
// Update data. So we can keep track of that flag with a ref.
const skipPageResetRef = React.useRef(false)
// When our cell renderer calls updateMyData, we'll use
// the rowIndex, columnID and new value to update the
// original data
const updateMyData = (rowIndex, columnID, value) => {
// We also turn on the flag to not reset the page
skipPageResetRef.current = true
setData(old => {
return old.filter((row, index) => {
if (index === rowIndex) {
return {
...old[rowIndex],
[columnID]: value,
}
}
return row
})
})
}
// After data chagnes, we turn the flag back off
// so that if data actually changes when we're not
// editing it, the page is reset
React.useEffect(
() => {
skipPageResetRef.current = false
},
[data]
)
// Let's add a data resetter/randomizer to help
// illustrate that flow...
const resetData = () => setData(makeData(20))
return (
<Styles>
<button onClick={resetData}>Reset Data</button>
<Table
columns={columns}
data={data}
updateMyData={updateMyData}
disablePageResetOnDataChange={skipPageResetRef.current}
/>
</Styles>
)
}
export default App

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

+159
View File
@@ -0,0 +1,159 @@
import React from 'react'
import styled from 'styled-components'
import { useTable, useExpanded } 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;
}
}
}
`
function Table({ columns: userColumns, data }) {
const {
getTableProps,
headerGroups,
rows,
prepareRow,
state: [{ expanded }],
} = useTable(
{
columns: userColumns,
data,
},
useExpanded // Use the useExpanded plugin hook
)
return (
<>
<pre>
<code>{JSON.stringify({ expanded }, 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>
{rows.map(
(row, i) =>
prepareRow(row) || (
<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>
</>
)
}
function App() {
const columns = React.useMemo(
() => [
{
// Build our expander column
Header: () => null, // No header, please
id: 'expander', // Make sure it has an ID
Cell: ({ row }) =>
// Use the row.canExpand and row.getExpandedToggleProps prop getter
// to build the toggle for expanding a row
row.canExpand ? (
<span
{...row.getExpandedToggleProps({
style: {
// We can even use the row.depth property
// and paddingLeft to indicate the depth
// of the row
paddingLeft: `${row.depth * 2}rem`,
},
})}
>
{row.isExpanded ? '👇' : '👉'}
</span>
) : null,
},
{
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',
},
],
},
],
[]
)
const data = React.useMemo(() => makeData(5, 5, 5), [])
return (
<Styles>
<Table columns={columns} data={data} />
</Styles>
)
}
export default App

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

@@ -49,9 +49,9 @@ function Table({ columns, data }) {
useExpanded // useGroupBy would be pretty useless without useExpanded ;)
)
// We don't want to render all 2000 rows for this example, so cap
// We don't want to render all of the rows for this example, so cap
// it at 20 for this use case
const firstPageRows = rows.slice()
const firstPageRows = rows.slice(0, 100)
return (
<>
@@ -68,7 +68,7 @@ function Table({ columns, data }) {
{column.canGroupBy ? (
// If the column can be grouped, let's add a toggle
<span {...column.getGroupByToggleProps()}>
{column.grouped ? '🛑' : '👊'}
{column.grouped ? '🛑 ' : '👊 '}
</span>
) : null}
{column.render('Header')}
@@ -102,14 +102,9 @@ function Table({ columns, data }) {
{cell.grouped ? (
// If it's a grouped cell, add an expander and row count
<>
<span
style={{
cursor: 'pointer',
}}
onClick={() => row.toggleExpanded()}
>
<span {...row.getExpandedToggleProps()}>
{row.isExpanded ? '👇' : '👉'}
</span>
</span>{' '}
{cell.render('Cell')} ({row.subRows.length})
</>
) : cell.aggregated ? (
@@ -129,7 +124,7 @@ function Table({ columns, data }) {
</tbody>
</table>
<br />
<div>Showing the first 20 results of {rows.length} rows</div>
<div>Showing the first 100 results of {rows.length} rows</div>
</>
)
}
+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)
})
+12
View File
@@ -0,0 +1,12 @@
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import * as serviceWorker from './serviceWorker'
ReactDOM.render(<App />, document.getElementById('root'))
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister()
+135
View File
@@ -0,0 +1,135 @@
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
)
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href)
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config)
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
)
})
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config)
}
})
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing
if (installingWorker == null) {
return
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
)
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration)
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.')
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration)
}
}
}
}
}
})
.catch(error => {
console.error('Error during service worker registration:', error)
})
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type')
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload()
})
})
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config)
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
)
})
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister()
})
}
}
+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*
@@ -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/basic)
- `yarn` and `yarn start` to run and edit the example
@@ -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": "next",
"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

@@ -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,3 @@
{
"infiniteLoopProtection": false
}
+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
@@ -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)
})
@@ -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;
}
@@ -0,0 +1,12 @@
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import * as serviceWorker from './serviceWorker'
ReactDOM.render(<App />, document.getElementById('root'))
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister()
@@ -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()
}
@@ -0,0 +1,135 @@
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
)
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href)
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config)
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
)
})
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config)
}
})
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing
if (installingWorker == null) {
return
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
)
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration)
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.')
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration)
}
}
}
}
}
})
.catch(error => {
console.error('Error during service worker registration:', error)
})
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type')
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload()
})
})
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config)
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
)
})
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister()
})
}
}
File diff suppressed because it is too large Load Diff
+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/basic)
- `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": "next",
"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
}
@@ -76,7 +76,6 @@ function Table({ columns, data }) {
pageCount,
canNextPage,
canPreviousPage,
pageOptions: [...pageOptions.slice(0, 6), '...'],
},
null,
2
+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)
})

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