Compare commits

...
133 Commits
Author SHA1 Message Date
Tanner Linsley 5dd628144c v7.0.0 2020-03-10 13:28:30 -06:00
Tanner Linsley 0d0ce01544 Update README.md 2020-03-10 13:24:50 -06:00
Tanner Linsley afa21b0ad4 Update tests.yml 2020-03-10 13:21:51 -06:00
Tanner Linsley f42300d9e2 Update README.md 2020-03-10 13:21:17 -06:00
Tanner Linsley 920420e330 Workflows, not travis 2020-03-10 13:20:53 -06:00
Tanner Linsley 6482869e8a Fix possible empty page options 2020-03-10 12:05:13 -06:00
Tanner Linsley 42b41d1260 Fix #1944
Fix #1944
2020-03-09 10:43:59 -06:00
Tanner Linsley 3aa016e056 Move default sortBy and orderBy to plugin files 2020-03-09 07:58:42 -06:00
Tanner Linsley bfcc08e7eb Changing filters resets pagination 2020-03-09 06:54:14 -06:00
512f615988 Add disableGlobalFilter prop to allow for columns (and instance) to ignore global filter (#1963)
* size-snapshot created?

* Added `disableGlobalFilter` prop and associated tests

* Updated documentation

* improvement(useglobalfilter): add `disableGlobalFilter` prop

Adding `disableGlobalFilter` prop to both table and column to allow columns to be excluded from
Global Filter

* test(usefilters.test.js): added base test for disableGlobalFilter

Needed a test to make sure that disableGlobalFilter didn't break anything when applied

* Delete .size-snapshot.json

* Update README.md

Co-authored-by: Jason Clark <jason.clark@tcnbroadcasting.com>
Co-authored-by: Tanner Linsley <tannerlinsley@gmail.com>
2020-03-06 15:49:00 -07:00
RandGitHub 63754a58dd Fixed link in Table Options section (#1950) 2020-03-06 15:41:58 -07:00
Mario RibeiroandGitHub 4a483214ff Update useRowSelect.md (#1948)
Missing documentation for `getToggleRowSelectedProps`, used on the [example](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/row-selection).

The `indeterminate` field is not documented at all, and I wonder what's the difference to the `checked` field.
2020-03-06 15:31:14 -07:00
GiorgioandGitHub b2af02407b Add additional info for accessor docs (#1943)
Adds additional context on `accessor` field for column options.

### Context

https://github.com/tannerlinsley/react-table/issues/1927
2020-03-06 15:30:43 -07:00
ironicbrewandGitHub b9f7bda223 Updated react-dnd package (#1939)
+ Prevents code sandbox from crashing the dnd example
2020-03-06 15:28:59 -07:00
ta-andersandGitHub acdb28df60 fix(usecolumnvisibility): trigger resetHiddenColumns on columns change (#1938)
fix #1919
2020-03-06 15:28:08 -07:00
Tanner Linsley 34be17b093 Update useRowSelect.js 2020-03-06 15:27:43 -07:00
Mark JonesGitHubboatcoder@gmail.com <Mark Jones>Tanner Linsley
544c30b358 Fixes the RowSelect Reducer #1901 (#1925)
* Fixes the RowSelect Reducer #1901

* Delete .size-snapshot.json

* Delete useFilters.test.js.snap

Co-authored-by: boatcoder@gmail.com <Mark Jones>
Co-authored-by: Tanner Linsley <tannerlinsley@gmail.com>
2020-03-06 15:25:58 -07:00
343e76ce65 Fix useFlexLayout table min-width (#1924)
* Fix useFlexLayout table min-width

* Delete .size-snapshot.json

Co-authored-by: Tanner Linsley <tannerlinsley@gmail.com>
2020-03-06 14:57:36 -07:00
Tanner Linsley 23c9ad23fa Remove commitizen and husky for now 2020-03-06 14:54:55 -07:00
Tanner Linsley 9e1a3bfe99 Update package.json 2020-03-06 14:53:14 -07:00
Tanner Linsley 6d4a733a88 Fix row selection when used with global filter
Fixes #1900
Closes #1937
2020-03-06 14:52:29 -07:00
Tanner Linsley c740a0c7af Github action for size tracking, better imports and building 2020-03-06 14:19:15 -07:00
Tanner Linsley 48d6fcd60d Create settings.json 2020-03-06 14:11:25 -07:00
Tanner LinsleyandGitHub 10b84faa29 Update README.md 2020-03-03 14:19:54 -07:00
Tanner LinsleyandGitHub 292bbea1bf Update README.md 2020-02-28 14:46:36 -07:00
size-plugin[bot]andGitHub 2a72667ec1 👩🏾🤝👩🏼 💁🏼‍♂️ update sizes-es.json 👍 2020-02-28 21:45:33 +00:00
size-plugin[bot]andGitHub c92f3fb855 👨‍✈️ 🍇 update sizes-cjs.json 👍 2020-02-28 21:45:32 +00:00
Tanner LinsleyandGitHub fe1c9b4b11 Update README.md 2020-02-28 14:43:58 -07:00
size-plugin[bot]andGitHub e28fa775f2 💎 🧙 update sizes-es.json 👍 2020-02-21 14:05:01 +00:00
size-plugin[bot]andGitHub d9b2a9dc54 👯 🧠 update sizes-cjs.json 👍 2020-02-21 14:05:00 +00:00
73ed7efbe6 useTable: Fixes memoizing of headerGroups (#1920)
Co-authored-by: Tanner Linsley <tannerlinsley@gmail.com>
2020-02-21 07:04:41 -07:00
7498059e98 useRowSelect: remove redundant checks (#1918)
* useRowSelect: remove redundant checks

* Update useRowSelect.js

Co-authored-by: Tanner Linsley <tannerlinsley@gmail.com>
2020-02-21 07:03:27 -07:00
Josh StevensandGitHub a52a2e1265 Fix code sandbox for kitchen sink (#1915)
There's an error on this page that says `useGroupBy` must come after `useFilters`
2020-02-21 06:58:41 -07:00
Tanner Linsley facb216f5c Merge branch 'master' of https://github.com/react-tools/react-table 2020-02-15 20:03:38 -07:00
size-plugin[bot]andGitHub b1a31b8176 📬 🇦🇩 update sizes-es.json 👍 2020-02-16 03:03:02 +00:00
size-plugin[bot]andGitHub 5949932e77 🤾🏽 🚴🏿‍♂️ update sizes-cjs.json 👍 2020-02-16 03:03:01 +00:00
Tanner Linsley f330b795dc v7.0.0-rc.16 2020-02-15 20:02:57 -07:00
Tanner Linsley 07625844fd Update CHANGELOG.md 2020-02-15 20:02:17 -07:00
Tanner Linsley 6c2df78b20 Merge branch 'master' of https://github.com/react-tools/react-table 2020-02-15 20:01:20 -07:00
Tanner Linsley 917cfcc910 Better plugin order api 2020-02-15 20:00:42 -07:00
Tanner Linsley b161d6d47b Update App.js 2020-02-15 12:53:00 -07:00
size-plugin[bot]andGitHub a3c0d22dd6 🕋 🇦🇸 update sizes-es.json 👍 2020-02-15 19:46:41 +00:00
size-plugin[bot]andGitHub da82358d14 📥 🐧 update sizes-cjs.json 👍 2020-02-15 19:46:40 +00:00
Tanner Linsley 7eabe4b5cc Merge branch 'master' of https://github.com/react-tools/react-table 2020-02-15 12:45:00 -07:00
Tanner Linsley 083e81dc81 Normalize API method names and row modesl, add expandAll functionality including prop getter 2020-02-15 12:43:09 -07:00
Ryan-Sandy LeeandGitHub 53f379f789 improves setAllFilters documentation (#1908) 2020-02-14 17:33:59 -07:00
2bf99aaea0 docs(examples/material-ui-enhanced-table): Add more Material UI table (#1847)
* docs(examples/material-ui-enhanced-table): add more Material UI table

This enhanced Material UI table demonstrates client side pagination, sorting, global search, add
row, and delete row.

* Update EnhancedTable.js

Co-authored-by: Tanner Linsley <tannerlinsley@gmail.com>
2020-02-14 13:19:55 -07:00
size-plugin[bot]andGitHub 164b3d6b7e 🇧🇦 🧚‍♂️ update sizes-es.json 👍 2020-02-14 20:18:44 +00:00
size-plugin[bot]andGitHub 2f14310808 🤺 🗽 update sizes-cjs.json 👍 2020-02-14 20:18:43 +00:00
gargrohandGitHub 32ca5a240b Add Column data in autoRemove of Filters (#1906)
* Update utils.js

* Update useFilters.js
2020-02-14 13:15:38 -07:00
98b3161b2d Add option to allow toggleRowSelect to not select subRows (#1879)
* Add option to allow toggleRowSelect to not select subRows

Iif you are using manualGrouping, it's convenient to be able
to select the group without selecting all of the children.

This adds an instance option `selectChildRows`, which defaults to true,
that can be set to false to allow selection of the group without it
selecting all of the children.

* fix lint error

Co-authored-by: Tanner Linsley <tannerlinsley@gmail.com>
2020-02-14 13:14:10 -07:00
size-plugin[bot]andGitHub 4f8f7cd118 🟧 🍵 update sizes-es.json 👍 2020-02-14 20:14:02 +00:00
size-plugin[bot]andGitHub 074211003a 👨🏻‍🎨 🧹 update sizes-cjs.json 👍 2020-02-14 20:14:00 +00:00
1eb492694a wrap instance dispatchers in useCallback (#1874)
addresses https://github.com/tannerlinsley/react-table/issues/1808

Several of the instance methods added by plugins wrap their state update
functions in useCallback, the ones that didn't do this can lead to problems
where when they are used in a component, for instance in a hook, their
required presence in the dependency array causes an infinite loop as
executing the function triggers an instance update and a new function
generation.  This PR addresses this.

Co-authored-by: Tanner Linsley <tannerlinsley@gmail.com>
2020-02-14 13:07:56 -07:00
size-plugin[bot]andGitHub 5ab8842ccf 💦 🤴🏽 update sizes-es.json 👍 2020-02-14 20:07:33 +00:00
size-plugin[bot]andGitHub 6b11d48b43 🚷 🧘🏼 update sizes-cjs.json 👍 2020-02-14 20:07:31 +00:00
Tanner Linsley 14ff3ef6c5 Merge branch 'master' of https://github.com/react-tools/react-table 2020-02-14 13:03:25 -07:00
Tanner Linsley fce2ebe763 Update useGlobalFilter.js 2020-02-14 13:03:11 -07:00
size-plugin[bot]andGitHub 475c0a0637 🏼 👩🏻‍⚕️ update sizes-es.json 👍 2020-02-14 20:01:09 +00:00
size-plugin[bot]andGitHub af58d06a1e 🕤 🤷‍♂️ update sizes-cjs.json 👍 2020-02-14 20:01:08 +00:00
gargrohandGitHub 42ad10a7d8 correct column sort fn (#1866) 2020-02-14 13:00:42 -07:00
812b416367 fix: fix spelling of manualGroupBy parameter (#1860)
Co-authored-by: Tanner Linsley <tannerlinsley@gmail.com>
2020-02-14 12:57:05 -07:00
Ovieh MosleyandGitHub c984796190 Update App.js (#1858)
Fixed typo.
2020-02-14 12:55:42 -07:00
gargrohandGitHub 05d946ecfb Following columnId instaed of columnID (#1848) 2020-02-14 12:15:30 -07:00
size-plugin[bot]andGitHub 49bdf95205 👩🏾‍💻 👌🏻 update sizes-es.json 👍 2020-02-14 19:14:18 +00:00
size-plugin[bot]andGitHub 677dcdc250 🏢 🔕 update sizes-cjs.json 👍 2020-02-14 19:14:17 +00:00
Tanner Linsley 7dc9b85165 Polish merge conflicts and changelog updates 2020-02-14 12:12:24 -07:00
Tanner Linsley 21826a93e0 Merge branch 'master' of https://github.com/react-tools/react-table 2020-02-14 11:27:19 -07:00
Tanner Linsley e62fc0c535 Update .huskyrc.js 2020-02-14 11:26:48 -07:00
Tanner Linsley b989a8fa76 Changed: Tests, aggregation, hooks, columnVisibility, docs 2020-02-14 11:23:05 -07:00
Tanner LinsleyandGitHub b1b71103c4 Update README.md 2020-02-01 11:25:11 -07:00
Tanner LinsleyandGitHub 8f5fc11905 Update README.md 2020-01-29 12:11:49 -07:00
Tanner LinsleyandGitHub 29c7cb3483 Update README.md 2020-01-29 12:09:34 -07:00
Tanner LinsleyandGitHub dd3b50cc17 Update README.md 2020-01-29 12:07:14 -07:00
Tanner LinsleyandGitHub 2eb5fa9c1b Update README.md 2020-01-29 12:04:14 -07:00
Tanner LinsleyandGitHub 6db990250e Update README.md 2020-01-29 12:03:48 -07:00
Lukas BüngerandTanner Linsley 5f9950339b docs: link to the original blog post instead of medium (#1844) 2020-01-10 13:01:59 -07:00
size-plugin[bot]andGitHub 5486293677 ️ ⛷🏻 update sizes-es.json 👍 2020-01-10 19:58:16 +00:00
size-plugin[bot]andGitHub 703f83e6f4 💇🏿 🖍️ update sizes-cjs.json 👍 2020-01-10 19:58:15 +00:00
gargrohandTanner Linsley 140ca06086 Doc for https://github.com/tannerlinsley/react-table/pull/1615 (#1843) 2020-01-10 12:56:41 -07:00
size-plugin[bot]andGitHub 8277bfd4db 👩🏿‍🦲 🥝 update sizes-es.json 👍 2020-01-09 13:18:48 +00:00
size-plugin[bot]andGitHub 7645107d3d 🏓 update sizes-cjs.json 👍 2020-01-09 13:18:47 +00:00
ta-andersandTanner Linsley 8ea93b9fed fix(usefilters): fix userFilterTypes alias in setFilter action (#1842)
Fix to correctly alias filterTypes to userFilterTypes in set filter action, so that the filter
autoremove method is called correctly

fix #1831
2020-01-09 06:17:46 -07:00
gargrohandTanner Linsley 6ebf3183a0 [useSort] Add sort order custom sortMethod (#1615)
Added sort order as parameter for calling sortMethod(will be useful to provide more control in custom sortMethod)
2020-01-09 06:17:12 -07:00
size-plugin[bot]andGitHub 5778bc3dce 💇🏽‍♀️ 💂🏿‍♂️ update sizes-es.json 👍 2020-01-08 23:41:30 +00:00
size-plugin[bot]andGitHub 3b4a120ff5 👳🏽‍♀️ 🧢 update sizes-cjs.json 👍 2020-01-08 23:41:29 +00:00
Roman IvaskevychandTanner Linsley 2a0dc6778d fix(usepagination resetpage on globalfilter change): pageIndex reset (#1813)
autoReset pageIndex on globalFilter change

"fix #1812"
2020-01-08 16:33:25 -07:00
Muhaimin CSandTanner Linsley 8e310bd0e6 fix typo (#1815) 2020-01-08 16:32:50 -07:00
dependabot[bot]andTanner Linsley c7b146cf1e Bump handlebars from 4.1.2 to 4.6.0 (#1840)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.6.0.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.6.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-08 16:32:33 -07:00
dependabot[bot]andTanner Linsley 68606bb77c Bump handlebars from 4.1.2 to 4.6.0 in /examples/column-hiding (#1841)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.6.0.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.6.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: Tanner Linsley <tannerlinsley@gmail.com>
2020-01-08 16:32:22 -07:00
dependabot[bot]andTanner Linsley c880da6c3d Bump handlebars from 4.1.2 to 4.5.3 (#1816)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-08 16:31:19 -07:00
dependabot[bot]andTanner Linsley 9d97ac29a6 Bump handlebars from 4.1.2 to 4.5.3 in /examples/column-hiding (#1817)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-08 16:31:08 -07:00
dependabot[bot]andTanner Linsley b018ed64ed Bump handlebars from 4.1.2 to 4.5.3 in /examples/basic (#1818)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-08 16:30:56 -07:00
dependabot[bot]andTanner Linsley 71e7c542c4 Bump handlebars from 4.1.2 to 4.5.3 in /examples/grouping (#1819)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-08 16:30:46 -07:00
dependabot[bot]andTanner Linsley e3223ed1b9 Bump handlebars from 4.1.2 to 4.5.3 in /examples/row-selection (#1820)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-01-08 16:30:37 -07:00
Manuel BeaudruandTanner Linsley 35d36db4c9 Fixes a typo in the docs (#1822) 2020-01-08 16:30:14 -07:00
Hrusikesh PandaandTanner Linsley 649259ba77 fix bad link (#1830) 2020-01-08 16:29:55 -07:00
Manuel BeaudruandTanner Linsley 017ad2884e Fix typo in docs - removes a meaningless word (#1832) 2020-01-08 16:29:39 -07:00
gargrohandTanner Linsley 59c4558dc8 grouping txt (#1837)
* grouping txt

* Update App.js
2020-01-08 16:29:21 -07:00
Ahmed AshourandTanner Linsley 9baf3c275b Fix broken link in useTable.md (#1809) 2019-12-25 23:38:04 -07:00
size-plugin[bot]andGitHub 7db50b0f21 🤵🏻 👼🏽 update sizes-es.json 👍 2019-12-26 03:01:18 +00:00
size-plugin[bot]andGitHub ac1eeb4756 🇬🇧 😘 update sizes-cjs.json 👍 2019-12-26 03:01:17 +00:00
ggascoigneandTanner Linsley 1d8ffb18f7 Add fixed width column support to useFlexLayout (#1810)
* Add fixed width column support to useFlexLayout

*  Allow useFlexLayout to honor canResize by calculating flex width separately from total width.
*  Update example to show the selection checkbox since that's a common fixed width use case.
*  Add example for right aligning columns.
*  Tweaked the styles for the table to better align the resize handles (since it made verifying the rest easier when they weren't misaligned by the scroll bar width)

Note that the resize behavior is still rather strange, but that's a separate problem that this change didn't really effect.

* swich to react-table@latest
2019-12-25 19:59:43 -07:00
Tanner LinsleyandGitHub ed2fe54371 Update README.md 2019-12-21 11:46:08 -07:00
Darío HereñúandTanner Linsley 4a93e0f306 Minor contribution on line 58 (#1802)
* or just a reminder. Please obliterate at your will
2019-12-21 10:43:30 -07:00
Saurabh MauryaandTanner Linsley 66cc06365c Bootstrap example (#1801)
* Added bootstrap as an example UI library

* Rename folder
2019-12-21 09:06:38 -07:00
Tanner LinsleyandGitHub ede79d8b38 Update README.md 2019-12-20 07:56:12 -07:00
size-plugin[bot]andGitHub d43e4be548 🇹🇼 🐃 update sizes-es.json 👍 2019-12-19 22:23:32 +00:00
size-plugin[bot]andGitHub 58c28b574a 🚖 🕝 update sizes-cjs.json 👍 2019-12-19 22:23:31 +00:00
Aaron CorleyandTanner Linsley 45e5bed468 misc fixes for useGlobalFilter (#1795)
* docs(useglobalfilter.md): corrected documentation for setGlobalFilter

* fix(useglobalfilter.js): wrapped setGlobalFilter in useCallback

Wrapped setGlobalFilter in useCallback for identity stability.
2019-12-19 15:21:27 -07:00
Tanner Linsley 94a9b49187 Merge branch 'master' of https://github.com/react-tools/react-table 2019-12-18 13:31:17 -07:00
Tanner Linsley aa6d859ce9 Update README.md 2019-12-18 13:31:02 -07:00
size-plugin[bot]andGitHub 555fc828f5 👩🏼‍🔧 👝 update sizes-es.json 👍 2019-12-18 20:29:44 +00:00
size-plugin[bot]andGitHub 3e789ffe83 👴🏿 💬 update sizes-cjs.json 👍 2019-12-18 20:29:43 +00:00
Tanner Linsley b430f8e702 Merge branch 'master' of https://github.com/react-tools/react-table 2019-12-18 13:28:06 -07:00
Tanner Linsley cef55d58f3 v7.0.0-rc.15 2019-12-18 13:27:55 -07:00
Tanner Linsley d18f1ba4d8 Add global filtering support via useGlobalFilter 2019-12-18 13:22:58 -07:00
size-plugin[bot]andGitHub 73344a47e4 🕯️ 🛄 update sizes-es.json 👍 2019-12-18 19:01:07 +00:00
size-plugin[bot]andGitHub bf82d3c656 🟥 🏇🏾 update sizes-cjs.json 👍 2019-12-18 19:01:06 +00: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
176 changed files with 51809 additions and 10101 deletions
+2 -1
View File
@@ -11,7 +11,8 @@
],
"env": {
"test": {
"presets": ["@babel/preset-env", "@babel/react"]
"presets": ["@babel/preset-env", "@babel/react"],
"plugins": ["@babel/plugin-transform-runtime"]
}
}
}
-27
View File
@@ -1,27 +0,0 @@
name: CI
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
build-and-test:
name: '${{ matrix.platform }}: node.js ${{ matrix.node-version }}'
strategy:
matrix:
platform: [ubuntu-latest, windows-latest, macos-latest]
node-version: [10, 12]
runs-on: ${{ matrix.platform }}
env:
CI: true
steps:
- name: Checkout
uses: actions/checkout@master
- name: Set up Node.js
uses: actions/setup-node@master
with:
node-version: ${{ matrix.node-version }}
- name: Build and test
run: |
yarn install
yarn test
-3
View File
@@ -1,3 +0,0 @@
size-files:
- sizes-cjs.json
- sizes-es.json
+15
View File
@@ -0,0 +1,15 @@
name: Compressed Size
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2-beta
with:
fetch-depth: 1
- uses: preactjs/compressed-size-action@v1
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
+26
View File
@@ -0,0 +1,26 @@
name: react-table tests
on:
push:
branches:
- 'master'
pull_request:
jobs:
test:
name: 'node ${{ matrix.node }} ${{ matrix.os }} '
runs-on: '${{ matrix.os }}'
strategy:
matrix:
os: [ubuntu-latest]
node: [12, 10]
steps:
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
- uses: actions/checkout@v2-beta
with:
fetch-depth: 1
- run: npm i -g yarn
- run: yarn --frozen-lockfile
- run: yarn test:ci
+2
View File
@@ -10,4 +10,6 @@ react-table.css
.idea
.DS_Store
.history
.vscode
package-lock.json
coverage
-6
View File
@@ -1,6 +0,0 @@
module.exports = {
hooks: {
'pre-commit': 'lint-staged && yarn test:ci',
// 'commit-msg': 'commitlint -E HUSKY_GIT_PARAMS',
},
}
-40
View File
@@ -1,40 +0,0 @@
{
"dist/index.js": {
"bundled": 107213,
"minified": 49659,
"gzipped": 13264
},
"dist/index.es.js": {
"bundled": 106302,
"minified": 48847,
"gzipped": 13099,
"treeshaked": {
"rollup": {
"code": 80,
"import_statements": 21
},
"webpack": {
"code": 8249
}
}
},
"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
}
}
}
}
-18
View File
@@ -1,18 +0,0 @@
language: node_js
node_js:
- 10
- 12
os:
- linux
- osx
- windows
env:
global:
- YARN_GPG=no
cache: yarn
script: yarn test
+8
View File
@@ -0,0 +1,8 @@
{
"workbench.colorCustomizations": {
"titleBar.inactiveBackground": "#ff4154", // change this color!
"titleBar.activeBackground": "#ff4154", // change this color!
"titleBar.inactiveForeground": "#ffffff", // change this color!
"titleBar.activeForeground": "#ffffff" // change this color!
}
}
+78
View File
@@ -1,3 +1,81 @@
## 7.0.0 🎉
- Fixed an issue where page options array could be empty
- Fixed an issue where duplicate columns would be silently deduped. There is now a warning when duplicate columns are found based on their IDs
- Moved some functions around so they will get treeshaked with their respective plugins that use them.
- Fixed an issue where filters, sorting, or grouping changes would not reset pagination
- Added table and column level options for disabling global filters
- Fixed an issue where row selection was not deselecting rows
- Fixed an issue where flex table rendering was not giving the table a minimum width with necessary
- Fixed an issue where row selection would not work when using other row-transformative plugins like filters or grouping
- Fixed an issue where header groups were not memoized correctly
## 7.0.0-rc.16
- Moved away from snapshot tests. No more testing implementation details.
- Added `visibleColumns` and `visibleColumnsDeps` hooks to manipulate columns after all data is processed. Further visibility processing may result in these columns not being visible, such as `hiddenColumn` state
- The `useRows` hook has been deprecated due to its dangerous nature 💀
- Added the `instance.rowsById` object
- Renamed `instance.flatColumns` to `instance.allColumns` which now accumulates ALL columns created for the table, visible or not.
- Added the `instance.visibleColumns` object
- Fix an issue where `useAsyncDebounce` would crash when passed arguments
- Started development on the `usePivotColumns` plugin, which can be tested currently using the `_UNSTABLE_usePivotColumns` export.
- Renamed `cell.isRepeatedValue` to `cell.isPlaceholder`
- Removed `useConsumeHookGetter` as it was inefficient most of the time and noisy
- All hooks are now "consumed" right after main plugin functions are run. This means that any attempt to add a plugin after that will result in a runtime error (for good reason, since using hook points should not be a conditional or async operation)
- Added `instance.getHooks` for getting the list of hooks that was captured after plugins are run
- Normalized all "toggle" actions to use an optional `value` property to set the value instead of toggle. Previously properties like `selected`, `groupBy`, etc. were used, but not any more!
- Undocument `instance.dispatch`. Both plugins and users should be interacting with the table via methods assigned to the instance and other structures on the table. This should both reduce the surface API that React Table needs to expose and also the amount of documentation that is needed to understand how to use the API.
- `useRowState`'s `initialRowStateAccessor` and `initialCellStateAccessor` options now have a default of `row => ({})` and `cell => ({})` respectively.
- Removed the concept of complex aggregations (eg. `column.aggregate = ['sum', 'count']`). Instead, a better aggregation function signature is now used to allow for leaf node aggregation when needed.
- Added the `column.aggregateValue` option which allows resolving (or pre-aggregating) a cell's value before it is grouped and aggregated across rows. This is useful for cell values that are not primitive, eg. an array of values that you may want to unique and count before summing that count across your groupings
- The function signature for aggregation functions has changed to be `(leafValues, aggregatedValues) => aggregatedValue` where `leafValues` is a flat array containing all leaf rows currently grouped at the aggregation level and `aggregatedValues` is an array containing the aggregated values from the immediate child sub rows. Each has purpose in the types of aggregations they power where optimizations are made for either accuracy or performance.
- Fixed an issue where `setGlobalFilter` was not a stable callback
- Added a Bootstrap UI example
- Added fixed with column support for useFlexLayout
- Fixed an issue where `manualGlobalFilter` was not resetting pagination properly
- Fixed an issue where `useGlobalFilter` could be placed after `usePagination`
- Added the sort order direction as a parameter to the sortMethod function
- Fixed an issue where user filter types were not being referenced correctly
- Renamed the `row.getExpandedToggleProps` to `row.getToggleRowExpandedProps`
- Renamed the `row.toggleExpanded` method to `row.toggleRowExpanded`
- Added the `instance.toggleRowExpanded` and `instance.toggleAllRowsExpanded` methods
- Added the `instance.getToggleAllRowsExpandedProps` prop getter
- Added the `instance.filteredRowsById` property
- Added the `instance.preFilteredRowsById` property
- useFilters now properly updates the `instance.rowsById` property
- Added the `instance.globalFilteredRowsById` property
- Added the `instance.preGlobalFilteredRowsById` property
- useGlobalFilter now properly updates the `instance.rowsById` property
- Added the `instance.nonGroupedFlatRows` property
- Added the `instance.nonGroupedRowsById` property
- Added the `instance.onlyGroupedFlatRows` property
- Added the `instance.onlyGroupedRowsById` property
- Improved the api around ensuring plugin ordering
- Added more plugin order rules to avoid strange plugin integration results
## 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
+34 -33
View File
@@ -4,16 +4,21 @@
Hooks for building **lightweight, fast and extendable datagrids** for React
[![#TanStack](https://img.shields.io/twitter/url?color=%2308a0e9&label=%23TanStack&style=social&url=https%3A%2F%2Ftwitter.com%2Fintent%2Ftweet%3Fbutton_hashtag%3DTanStack)](https://twitter.com/intent/tweet?button_hashtag=TanStack)
<!-- [![GitHub Actions CI](https://github.com/tannerlinsley/react-table/workflows/CI/badge.svg)](https://github.com/tannerlinsley/react-table/actions) -->
[![Travis CI](https://travis-ci.org/tannerlinsley/react-table.svg?branch=master)](https://travis-ci.org/tannerlinsley/react-table)
[![Bundlephobia](https://badgen.net/bundlephobia/minzip/react-table@next)](https://bundlephobia.com/result?p=react-table@next)
[![NPM Package](https://img.shields.io/npm/dm/react-table.svg)](https://npmjs.com/package/react-table)
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/react-table)
[![GitHub Stars](https://img.shields.io/github/stars/tannerlinsley/react-table.svg?style=social&label=Star)](https://github.com/tannerlinsley/react-table)
[![Twitter Followers](https://img.shields.io/twitter/follow/tannerlinsley.svg?style=social&label=Follow)](https://twitter.com/tannerlinsley)
<a href="https://twitter.com/intent/tweet?button_hashtag=TanStack" target="\_parent">
<img alt="#TanStack" src="https://img.shields.io/twitter/url?color=%2308a0e9&label=%23TanStack&style=social&url=https%3A%2F%2Ftwitter.com%2Fintent%2Ftweet%3Fbutton_hashtag%3DTanStack">
</a><a href="https://github.com/tannerlinsley/react-table/actions?table=workflow%3A%22react-table+tests%22">
<img src="https://github.com/tannerlinsley/react-table/workflows/react-table%20tests/badge.svg" />
</a><a href="https://npmjs.com/package/react-table" target="\_parent">
<img alt="" src="https://img.shields.io/npm/dm/react-table.svg" />
</a><a href="https://bundlephobia.com/result?p=react-table@latest" target="\_parent">
<img alt="" src="https://badgen.net/bundlephobia/minzip/react-table@latest" />
</a><a href="https://spectrum.chat/react-table">
<img alt="Join the community on Spectrum" src="https://withspectrum.github.io/badge/badge.svg" />
</a><a href="https://github.com/tannerlinsley/react-table" target="\_parent">
<img alt="" src="https://img.shields.io/github/stars/tannerlinsley/react-table.svg?style=social&label=Star" />
</a><a href="https://twitter.com/tannerlinsley" target="\_parent">
<img alt="" src="https://img.shields.io/twitter/follow/tannerlinsley.svg?style=social&label=Follow" />
</a>
Enjoy this library? Try them all! [React Query](https://github.com/tannerlinsley/react-query), [React Form](https://github.com/tannerlinsley/react-form), [React Charts](https://github.com/tannerlinsley/react-charts)
@@ -81,11 +86,6 @@ This library is being built and maintained by me, @tannerlinsley and I am always
<img width='225' src="https://raw.githubusercontent.com/tannerlinsley/files/master/images/patreon/sponsor-retool.png">
</a>
</td>
<td align="center" valign="middle">
<a href="http://bjntech.com/index.html?utm_campaign=react_table" target="_blank">
<img width='225' src="https://raw.githubusercontent.com/tannerlinsley/files/master/images/patreon/sponsor-bjn.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://github.com/sponsors/tannerlinsley" target="_blank">
Become a Sponsor!
@@ -108,11 +108,6 @@ This library is being built and maintained by me, @tannerlinsley and I am always
<img width='225' src="https://nozzle.io/img/logo-blue.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://zappi.io/web/" target="_blank">
<img width='225' src="https://raw.githubusercontent.com/tannerlinsley/files/master/images/patreon/sponsor-zappi.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://github.com/sponsors/tannerlinsley" target="_blank">
Become a Sponsor!
@@ -129,6 +124,11 @@ This library is being built and maintained by me, @tannerlinsley and I am always
<a href="https://github.com/sponsors/tannerlinsley/" target="_blank">
<img width='150' src="https://raw.githubusercontent.com/tannerlinsley/files/master/images/patreon/silver.png">
</a>
</td>
<td align="center" valign="middle">
<a href="https://tripwire.com" target="_blank">
<img width='225' src="https://www.tripwire.com/-/media/tripwiredotcom/icons/tripwire-logo-footer.svg">
</a>
</td>
<td align="center" valign="middle">
<a href="https://github.com/sponsors/tannerlinsley" target="_blank">
@@ -150,7 +150,8 @@ This library is being built and maintained by me, @tannerlinsley and I am always
<td>
<ul>
<li>Jon Eickmeier</li>
<li><a href="https://github.com/Shah-Sahab">Syed Hussain<a></li>
<li><a href="https://github.com/rhefner">Richard Hefner (@rhefner)</a></li>
<li><a href="https://gitHub.com/snorkypie"> Steeve Lennmark (@snorkypie)</a></li>
</ul>
</td>
<td>
@@ -172,18 +173,18 @@ This library is being built and maintained by me, @tannerlinsley and I am always
</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>
<li>Jordan Soltman</li>
<li>Robert Tajnšek</li>
<li>Pekka Tapani</li>
<li>Eric Lanehart (@pushred)</li>
<li>Anish P Patel (@anishpatelyaadada)</li>
<li>Alin Porumb (@alinporumb)</li>
<li>Hugo Meissner</li>
<li>Benoit Leger-Derville</li>
<li>Thomas Funk</li>
<li>David Pickut</li>
<li>Jordan Soltman</li>
<li>Robert Tajnšek</li>
<li>Eric Lanehart (@pushred)</li>
<li>Anish P Patel (@anishpatelyaadada)</li>
<li>Alin Porumb (@alinporumb)</li>
<li>Janus Reith (@janus-reith)</li>
<li>Timo Mämecke (@timomeh)</li>
<li>Tyler Reiff (@reiff12)</li>
</ul>
</td>
<td>
-1
View File
@@ -1 +0,0 @@
module.exports = { extends: ['@commitlint/config-conventional'] }
+1 -1
View File
@@ -13,5 +13,5 @@ module.exports = {
rootDir: path.resolve(__dirname, '../../'),
roots: ['<rootDir>/src', __dirname],
transformIgnorePatterns: ['node_modules'],
snapshotSerializers: [require.resolve('snapshot-diff/serializer.js')],
collectCoverageFrom: ['src/**/*.js', '!**/*.test.js'],
}
-1
View File
@@ -1,2 +1 @@
import '@testing-library/jest-dom/extend-expect'
import 'snapshot-diff/extend-expect'
+2 -1
View File
@@ -10,6 +10,7 @@ React Table is essentially a compatible collection of **custom React hooks**:
- Core Plugin Hooks
- [`useGroupBy`](./useGroupBy.md)
- [`useFilters`](./useFilters.md)
- [`useGlobalFilter`](./useGlobalFilter.md)
- [`useSortBy`](./useSortBy.md)
- [`useExpanded`](./useExpanded.md)
- [`usePagination`](./usePagination.md)
@@ -54,7 +55,7 @@ const instance = useTable(
This multi-stage process is the secret sauce that allows React Table plugin hooks to work together and compose nicely, while not stepping on each others toes.
To dive deeper into plugins, see Plugins](TODO) and the [Plugin Guide
To dive deeper into plugins, see Plugins and the Plugin Guide
### Plugin Hook Order & Consistency
+8 -1
View File
@@ -41,6 +41,13 @@ The following properties are available on the table instance returned from `useT
- `rows: Array<Row>`
- An array of **expanded** rows.
- `toggleRowExpanded: Function(rowId, isExpanded?)`
- A function to toggle whether a row is expanded or not. The `isExpanded` boolean is optional, otherwise it will be a true toggle action
- `toggleAllRowsExpanded: Function(isExpanded?)`
- A function to toggle whether all of the rows in the table are expanded or not. The `isExpanded` boolean is optional, otherwise it will be a true toggle action
- `isAllRowsExpanded`
- `getToggleAllRowsExpandedProps: Function(userProps) => props`
- A prop getter function that returns all necessary props for an element to be clicked and toggle all of the rows expanded or not.
### Row Properties
@@ -48,7 +55,7 @@ The following additional properties are available on every `row` object returned
- `isExpanded: Bool`
- If `true`, this row is in an expanded state.
- `toggleExpanded: Function(?isExpanded: Bool) => void`
- `toggleRowExpanded: Function(?isExpanded: Bool) => void`
- This function will toggle the expanded state of a row between `true` and `false` or, if an `isExpanded` boolean is passed to the function, it will be set as the new `isExpanded` value.
- Rows with a hard-coded `manualExpandedKey` (defaults to `expanded`) set to `true` are not affected by this function or the internal expanded state.
+4 -2
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
@@ -68,8 +68,10 @@ The following values are provided to the table `instance`:
- 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.
- `setFilter: Function(columnId, filterValue) => void`
- An instance-level function used to update the filter value for a specific column.
- `setAllFilters: Function(filtersObject) => void`
- `setAllFilters: Function(filtersObjectArray) => void`
- An instance-level function used to update the values for **all** filters on the table, all at once.
- filtersObjectArray is an array of objects with id and value keys. Example: `[{ id: 'columnAccessor', value: 'valueToFilter' }]`
- Note: You must call setAllFilters with an array, even if that array is empty. eg: `setAllFilters([])`.
### Column Properties
+62
View File
@@ -0,0 +1,62 @@
# `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)
- `disableGlobalFilter: Bool`
- Disables global filtering for every column in the entire table.
- `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)
### Column Options
The following options are supported on any `Column` object passed to the `columns` option in `useTable()`
- `disableGlobalFilter: Bool`
- Optional
- If set to `true`, will disable global filtering for this column
### 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(filterValue) => void`
- An instance-level function used to update the global filter value.
### 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)
+14 -6
View File
@@ -38,12 +38,18 @@ The following options are supported on any `Column` object passed to the `column
- Receives the table instance and cell model as props
- Must return valid JSX
- This function (or component) formats this column's value when it is being grouped and aggregated, eg. If this column was showing the number of visits for a user to a website and it was currently being grouped to show an **average** of the values, the `Aggregated` function for this column could format that value to `1,000 Avg. Visits`
- `aggregate: String | [String, String] | Function(values, rows, isAggregated: Bool) => any`
- `aggregate: String | Function(leafValues, aggregatedValues) => any`
- Optional
- Used to aggregate values across rows, eg. `average`-ing the ages of many cells in a table"
- If a single `String` is passed, it must be the key of either a user defined or predefined `aggregations` function.
- If a tuple array of `[String, String]` is passed, both must be a key of either a user defined or predefined `aggregations` function.
- The first is used to aggregate raw values, eg. `sum`-ing raw values together
- The second is used to aggregate values that have already been aggregated, eg. `average`-ing the sums produced by the raw aggregation level
- If a `Function` is passed, this function will receive the `values`, original `rows` of those values, and an `isAggregated` `Bool` of whether or not the values and rows have already been aggregated.
- If a `Function` is passed, this function will receive both the leaf-row values and (if the rows have already been aggregated, the previously aggregated values) to be aggregated into a single value.
- The function signature for all aggregation functions is `(leafValues, aggregatedValues) => aggregatedValue` where `leafValues` is a flat array containing all leaf rows currently grouped at the aggregation level and `aggregatedValues` is an array containing the aggregated values from the immediate child sub rows. Each has purpose in the types of aggregations they power where optimizations are made for either accuracy or performance.
- For examples on how an aggregation functions work, see the source code for the built in aggregations in the [src/aggregations.js](../../src/aggregations.js) file.
- `aggregateValue: String | Function(values, row, column) => any`
- Optional
- When attempting to group/aggregate non primitive cell values (eg. arrays of items) you will likely need to resolve a stable primitive value like a number or string to use in normal row aggregations. This property can be used to aggregate or simply access the value to be used in aggregations eg. `count`-ing the unique number of items in a cell's array value before `sum`-ing that count across the table.
- If a single `String` is passed, it must be the key of either a user defined or predefined `aggregations` function.
- If a `Function` is passed, this function will receive the cell's accessed value, the original `row` object and the `column` associated with the cell
- `disableGroupBy: Boolean`
- Defaults to `false`
- If `true`, will disable grouping for this column.
@@ -92,6 +98,8 @@ The following properties are available on every `Row` object returned by the tab
- This object contains the **aggregated** values for this row's sub rows
- `subRows: Array<Row>`
- If the row is a materialized group row, this property is the array of materialized subRows that were grouped inside of this row.
- `leafRows: Array<Row>`
- If the row is a materialized group row, this property is an array containing all leaf node rows aggregated into this row.
- `depth: Int`
- If the row is a materialized group row, this is the grouping depth at which this row was created.
- `id: String`
@@ -108,7 +116,7 @@ The following additional properties are available on every `Cell` object returne
- `isGrouped: Bool`
- If `true`, this cell is a grouped cell, meaning it contains a grouping value and should usually display and expander.
- `isRepeatedValue: Bool`
- `isPlaceholder: Bool`
- If `true`, this cell is a repeated value cell, meaning it contains a value that is already being displayed elsewhere (usually by a parent row's cell).
- Most of the time, this cell is not required to be displayed and can safely be hidden during rendering
- `isAggregated: Bool`
+2 -1
View File
@@ -30,10 +30,11 @@ The following options are supported via the main options object passed to `useTa
- When `true`, the `pageIndex` state will automatically reset if `manualPagination` is `false` and any of the following conditions are met:
- `data` is changed
- `manualSortBy` is `false` and `state.sortBy` is changed
- `manualGlobalFilter` is `false` and `state.globalFilter` is changed
- `manualFilters` is `false` and `state.filters` is changed
- `manualGroupBy` is `false` and `state.groupBy` 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)
- For more information see the FAQ ["How do I stop my table state from automatically resetting when my data changes?"](../faq.md#how-do-i-stop-my-table-state-from-automatically-resetting-when-my-data-changes)
- `paginateExpandedRows: Bool`
- Optional
- Only applies when using the `useExpanded` plugin hook simultaneously
+7
View File
@@ -58,6 +58,13 @@ The following additional properties are available on every **prepared** `row` ob
- `toggleRowSelected: Function(?set)`
- Use this function to toggle this row's selected state.
- Optionally pass `true` or `false` to set it to that state
- `getToggleRowSelectedProps: Function(props) => props`
- Use this function to get the props needed for a **select row checkbox**.
- Props:
- `onChange: Function()`
- `style.cursor: 'pointer'`
- `checked: Bool`
- `title: 'Toggle Row Selected'`
### Example
+8 -2
View File
@@ -15,10 +15,16 @@ The following options are supported via the main options object passed to `useTa
- If a row's ID is found in this array, it will have the state of the value corresponding to that key.
- Individual row states can contain anything, but they also contain a `cellState` key, which provides cell-level state based on column ID's to every
**prepared** cell in the table.
- `initialRowStateAccessor: Function`
- `initialRowStateAccessor: Function(originalRow) => Object<any>`
- Optional
- This function may optionally return the initial state for a row.
- Defaults to: `row => ({})`
- This function should return the initial state for a row.
- If this function is defined, it will be passed a `Row` object, from which you can return a value to use as the initial state, eg. `row => row.original.initialState`
- `initialCellStateAccessor: Function(originalRow) => Object<any>`
- **Optional**
- Defaults to: `cell => ({})`
- This function should return the initial state for a cell.
- If this function is defined, it will be passed a `Cell` object, from which you can return a value to use as the initial state, eg. `cell => cell.row.original.initialCellState[cell.column.id]`
- `autoResetRowState: Boolean`
- Defaults to `true`
- When `true`, the `rowState` state will automatically reset if any of the following conditions are met:
+3 -3
View File
@@ -49,7 +49,7 @@ The following options are supported via the main options object passed to `useTa
- When `true`, the `sortBy` 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)
- For more information see the FAQ ["How do I stop my table state from automatically resetting when my data changes?"](../faq.md#how-do-i-stop-my-table-state-from-automatically-resetting-when-my-data-changes)
### Column Options
@@ -72,7 +72,7 @@ The following options are supported on any `Column` object passed to the `column
- Defaults to `false`
- If set to `true`, the underlying sorting direction will be inverted, but the UI will not.
- This may be useful in situations where positive and negative connotation is inverted, eg. a Golfing score where a lower score is considered more positive than a higher one.
- `sortType: String | Function`
- `sortType: String | Function(rowA: <Row>, rowB: <Row>, columnId: String, desc: Bool)`
- Used to compare 2 rows of data and order them correctly.
- If a **function** is passed, it must be **memoized**
- String options: `basic`, `datetime`, `alphanumeric`. Defaults to `alphanumeric`.
@@ -106,7 +106,7 @@ The following properties are available on every `Column` object returned by the
- This function is used to resolve any props needed for this column's UI that is responsible for toggling the sort direction when the user clicks it.
- You can use the `getSortByToggleProps` hook to extend its functionality.
- Custom props may be passed. **NOTE: Custom props may override built-in sortBy props, so be careful!**
- `clearSorting: Function() => void`
- `clearSortBy: Function() => void`
- This function can be used to programmatically clear the sorting for this column.
- `isSorted: Boolean`
- Denotes whether this column is currently being sorted
+13 -15
View File
@@ -25,7 +25,12 @@ 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`
- `autoResetHiddenColumns: Boolean`
- Defaults to `true`
- When `true`, the `hiddenColumns` state will automatically reset if any of the following conditions are met:
- `columns` is changed
- To disable, set to `false`
- `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`
@@ -35,7 +40,7 @@ The following options are supported via the main options object passed to `useTa
- If you need to control part of the table state, this is the place to do it.
- This function is run on every single render, just like a hook and allows you to alter the final state of the table if necessary.
- You can use hooks inside of this function, but most of the time, we just suggest using `React.useMemo` to memoize your state overrides.
- See the FAQ ["How can I manually control the table state?"](./faq.md#how-can-i-manually-control-the-table-state) for a an example.
- See the FAQ ["How can I manually control the table state?"](../faq.md#how-can-i-manually-control-the-table-state) for a an example.
- `defaultColumn: Object`
- Optional
- Defaults to `{}`
@@ -67,12 +72,13 @@ The following options are supported via the main options object passed to `useTa
The following options are supported on any column object you can pass to `columns`.
- `accessor: String | Function`
- `accessor: String | Function(originalRow, rowIndex) => any`
- **Required**
- This string/function is used to build the data model for your column.
- The data returned by an accessor should be **primitive** and sortable.
- If a string is passed, the column's value will be looked up on the original row via that key, eg. If your column's accessor is `firstName` then its value would be read from `row['firstName']`. You can also specify deeply nested values with accessors like `info.hobbies` or even `address[0].street`
- If a function is passed, the column's value will be looked up on the original row using this accessor function, eg. If your column's accessor is `row => row.firstName`, then its value would be determined by passing the row to this function and using the resulting value.
- Technically speaking, this field isn't required if you have a unique `id` for a column. This is used for things like expander or row selection columns. **Warning**: Only omit `accessor` if you really know what you're doing.
- `id: String`
- **Required if `accessor` is a function**
- This is the unique ID for the column. It is used by reference in things like sorting, grouping, filtering etc.
@@ -93,11 +99,6 @@ The following options are supported on any column object you can pass to `column
- 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.
- `show: Bool`
- Optional
- Defaults to `undefined`
- If set to `true`, will take priority over any state in `hiddenColumns` and force this column to be visible at all times.
- If set to `false` will take priority over any state in `hiddenColumns` and force this column to be hidden at all times.
- `width: Int`
- Optional
- Defaults to `150`
@@ -120,18 +121,15 @@ The following properties are available on the table instance returned from `useT
- `state: Object`
- **Memoized** - This object reference will not change unless the internal table state is modified.
- This is the final state object of the table, which is the product of the `initialState`, internal table reducer and (optionally) a custom `reducer` supplied by the user.
- `dispatch: Function({ type: Actions[type], ...payload }) => void`
- This function is used both internally by React Table, and optionally by you (the developer) to update the table state programmatically.
- `type: Actions[type] | String`
- The action type corresponding to what action being taken against the state.
- `...payload`
- Any other action data that is associated with the action
- `columns: Array<Column>`
- A **nested** array of final column objects, **similar in structure to the original columns configuration option**.
- See [Column Properties](#column-properties) for more information
- `flatColumns: Array<Column>`
- `allColumns: Array<Column>`
- A **flat** array of all final column objects.
- See [Column Properties](#column-properties) for more information
- `visibleColumns: Array<Column>`
- A **flat** array of all visible column objects derived from `allColumns`.
- See [Column Properties](#column-properties) for more information
- `headerGroups: Array<HeaderGroup>`
- An array of normalized header groups, each containing a flattened array of final column objects for that row.
- **Some of these headers may be materialized as placeholders**
+1 -1
View File
@@ -2,7 +2,7 @@
## React Table is a "headless" UI library
React Table is a headless utility, which means out of the box, it doesn't render or supply any actual UI elements. You are in charge of utilizing the state and callbacks of the hooks provided by this library to render your own table markup. [Read this article to understand why React Table is built this way](https://medium.com/merrickchristensen/headless-user-interface-components-565b0c0f2e18). If you don't want to, then here's a quick rundown anyway:
React Table is a headless utility, which means out of the box, it doesn't render or supply any actual UI elements. You are in charge of utilizing the state and callbacks of the hooks provided by this library to render your own table markup. [Read this article to understand why React Table is built this way](https://www.merrickchristensen.com/articles/headless-user-interface-components/). If you don't want to, then here's a quick rundown anyway:
- Separation of Concerns - Not that superficial kind you read about all the time. The real kind. React Table as a library honestly has no business being in charge of your UI. The look, feel, and overall experience of your table is what makes your app or product great. The less React Table gets in the way of that, the better!
- Maintenance - By removing the massive (and seemingly endless) API surface area required to support every UI use-case, React Table can remain small, easy-to-use and simple to update/maintain.
+3
View File
@@ -73,6 +73,9 @@
- Material-UI
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/material-UI-components)
- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/material-UI-components)
- Material-UI Enhanced Table
- [Source](https://github.com/tannerlinsley/react-table/tree/master/examples/material-UI-enhanced-table)
- [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/material-UI-enhanced-table)
- [ ] Styled-Components
- [ ] CSS
- [ ] Bootstrap
+2 -2
View File
@@ -40,10 +40,10 @@ function Table({ data, onFetchData }) {
data,
})
// When the these table states change, fetch new data!
// When these table states change, fetch new data!
React.useEffect(() => {
onFetchData({ pageIndex, pageSize, sortBy, filters })
}, [fetchData, pageIndex, pageSize, sortBy, filters])
}, [onFetchData, pageIndex, pageSize, sortBy, filters])
return </>
}
+25 -26
View File
@@ -205,7 +205,7 @@ function Table({ columns, data }) {
getTableBodyProps,
headerGroups,
rows,
flatColumns,
visibleColumns,
prepareRow,
setColumnOrder,
state,
@@ -230,7 +230,7 @@ function Table({ columns, data }) {
)
const randomizeColumns = () => {
setColumnOrder(shuffle(flatColumns.map(d => d.id)))
setColumnOrder(shuffle(visibleColumns.map(d => d.id)))
}
return (
@@ -267,30 +267,29 @@ function Table({ columns, data }) {
</thead>
<tbody {...getTableBodyProps()}>
<AnimatePresence>
{rows.slice(0, 10).map(
(row, i) => {
prepareRow(row);
return (
<motion.tr
{...row.getRowProps({
layoutTransition: spring,
exit: { opacity: 0, maxHeight: 0 },
})}
>
{row.cells.map((cell, i) => {
return (
<motion.td
{...cell.getCellProps({
layoutTransition: spring,
})}
>
{cell.render('Cell')}
</motion.td>
)
})}
</motion.tr>
)}
)}
{rows.slice(0, 10).map((row, i) => {
prepareRow(row)
return (
<motion.tr
{...row.getRowProps({
layoutTransition: spring,
exit: { opacity: 0, maxHeight: 0 },
})}
>
{row.cells.map((cell, i) => {
return (
<motion.td
{...cell.getCellProps({
layoutTransition: spring,
})}
>
{cell.render('Cell')}
</motion.td>
)
})}
</motion.tr>
)
})}
</AnimatePresence>
</tbody>
</table>
+10 -11
View File
@@ -59,17 +59,16 @@ function Table({ columns, data }) {
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(
(row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)}
)}
{rows.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
)
+13 -8
View File
@@ -2632,7 +2632,7 @@ commander@2.17.x:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
commander@^2.11.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.0:
commander@^2.11.0, commander@^2.19.0, commander@^2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
@@ -2642,6 +2642,11 @@ commander@~2.19.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
commander@~2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
common-tags@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937"
@@ -4369,9 +4374,9 @@ handle-thing@^2.0.0:
integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==
handlebars@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67"
integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==
version "4.5.3"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482"
integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==
dependencies:
neo-async "^2.6.0"
optimist "^0.6.1"
@@ -9435,11 +9440,11 @@ uglify-js@3.4.x:
source-map "~0.6.1"
uglify-js@^3.1.4:
version "3.6.0"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5"
integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==
version "3.7.3"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.3.tgz#f918fce9182f466d5140f24bb0ff35c2d32dcc6a"
integrity sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg==
dependencies:
commander "~2.20.0"
commander "~2.20.3"
source-map "~0.6.1"
unicode-canonical-property-names-ecmascript@^1.0.4:
@@ -0,0 +1,3 @@
{
"presets": ["react-app"]
}
+1
View File
@@ -0,0 +1 @@
SKIP_PREFLIGHT_CHECK=true
@@ -0,0 +1,7 @@
{
"extends": ["react-app", "prettier"],
"rules": {
// "eqeqeq": 0,
// "jsx-a11y/anchor-is-valid": 0
}
}
@@ -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,
]
@@ -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/material-UI-components)
- `yarn` and `yarn start` to run and edit the example
@@ -0,0 +1,37 @@
{
"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",
"bootstrap": "^4.4.1",
"react-bootstrap": "^1.0.0-beta.16"
},
"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",
"eslint-config-prettier": "^6.3.0"
},
"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"
}
+102
View File
@@ -0,0 +1,102 @@
import React from 'react'
import 'bootstrap/dist/css/bootstrap.min.css';
import BTable from 'react-bootstrap/Table';
import { useTable } from 'react-table'
import makeData from './makeData'
function Table({ columns, data }) {
// Use the state and functions returned from useTable to build your UI
const { getTableProps, headerGroups, rows, prepareRow } = useTable({
columns,
data,
})
// Render the UI for your table
return (
<BTable striped bordered hover size="sm" {...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)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<th {...cell.getCellProps()}>
{cell.render('Cell')}
</th>
)
})}
</tr>
)
})}
</tbody>
</BTable>
)
}
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 = React.useMemo(() => makeData(20), [])
return (
<div>
<Table columns={columns} data={data} />
</div>
)
}
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,6 @@
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))
@@ -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
View File
@@ -0,0 +1,3 @@
{
"presets": ["react-app"]
}
+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/material-UI-components)
- `yarn` and `yarn start` to run and edit the example
+37
View File
@@ -0,0 +1,37 @@
{
"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",
"bootstrap": "^4.4.1",
"react-bootstrap": "^1.0.0-beta.16"
},
"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",
"eslint-config-prettier": "^6.3.0"
},
"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"
}
+102
View File
@@ -0,0 +1,102 @@
import React from 'react'
import 'bootstrap/dist/css/bootstrap.min.css';
import BTable from 'react-bootstrap/Table';
import { useTable } from 'react-table'
import makeData from './makeData'
function Table({ columns, data }) {
// Use the state and functions returned from useTable to build your UI
const { getTableProps, headerGroups, rows, prepareRow } = useTable({
columns,
data,
})
// Render the UI for your table
return (
<BTable striped bordered hover size="sm" {...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)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<th {...cell.getCellProps()}>
{cell.render('Cell')}
</th>
)
})}
</tr>
)
})}
</tbody>
</BTable>
)
}
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 = React.useMemo(() => makeData(20), [])
return (
<div>
<Table columns={columns} data={data} />
</div>
)
}
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
+6 -4
View File
@@ -53,7 +53,7 @@ function Table({ columns, data }) {
headerGroups,
rows,
prepareRow,
flatColumns,
allColumns,
getToggleHideAllColumnsProps,
state,
} = useTable({
@@ -69,10 +69,12 @@ function Table({ columns, data }) {
<IndeterminateCheckbox {...getToggleHideAllColumnsProps()} /> Toggle
All
</div>
{flatColumns.map(column => (
{allColumns.map(column => (
<div key={column.id}>
<input type="checkbox" {...column.getToggleHiddenProps()} />{' '}
{column.id}
<label>
<input type="checkbox" {...column.getToggleHiddenProps()} />{' '}
{column.id}
</label>
</div>
))}
<br />
+13 -8
View File
@@ -2632,7 +2632,7 @@ commander@2.17.x:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
commander@^2.11.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.0:
commander@^2.11.0, commander@^2.19.0, commander@^2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
@@ -2642,6 +2642,11 @@ commander@~2.19.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
commander@~2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
common-tags@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937"
@@ -4369,9 +4374,9 @@ handle-thing@^2.0.0:
integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==
handlebars@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67"
integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==
version "4.6.0"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.6.0.tgz#33af6c3eda930d7a924f5d8f1c6d8edc3180512e"
integrity sha512-i1ZUP7Qp2JdkMaFon2a+b0m5geE8Z4ZTLaGkgrObkEd+OkUKyRbRWw4KxuFCoHfdETSY1yf9/574eVoNSiK7pw==
dependencies:
neo-async "^2.6.0"
optimist "^0.6.1"
@@ -9435,11 +9440,11 @@ uglify-js@3.4.x:
source-map "~0.6.1"
uglify-js@^3.1.4:
version "3.6.0"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5"
integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==
version "3.7.4"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.4.tgz#e6d83a1aa32ff448bd1679359ab13d8db0fe0743"
integrity sha512-tinYWE8X1QfCHxS1lBS8yiDekyhSXOO6R66yNOCdUJeojxxw+PX2BHAz/BWyW7PQ7pkiWVxJfIEbiDxyLWvUGg==
dependencies:
commander "~2.20.0"
commander "~2.20.3"
source-map "~0.6.1"
unicode-canonical-property-names-ecmascript@^1.0.4:
+12 -15
View File
@@ -50,7 +50,7 @@ function Table({ columns, data }) {
getTableBodyProps,
headerGroups,
rows,
flatColumns,
visibleColumns,
prepareRow,
setColumnOrder,
state,
@@ -63,7 +63,7 @@ function Table({ columns, data }) {
)
const randomizeColumns = () => {
setColumnOrder(shuffle(flatColumns.map(d => d.id)))
setColumnOrder(shuffle(visibleColumns.map(d => d.id)))
}
return (
@@ -80,19 +80,16 @@ function Table({ columns, data }) {
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.slice(0, 10).map(
(row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell, i) => {
return (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
)
})}
</tr>
)}
)}
{rows.slice(0, 10).map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell, i) => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
<pre>
+1 -1
View File
@@ -63,7 +63,7 @@ const EditableCell = ({
updateMyData(index, id, value)
}
// If the initialValue is changed externall, sync it up with our state
// If the initialValue is changed external, sync it up with our state
React.useEffect(() => {
setValue(initialValue)
}, [initialValue])
+7 -3
View File
@@ -88,14 +88,18 @@ function App() {
() => [
{
// Build our expander column
Header: () => null, // No header, please
id: 'expander', // Make sure it has an ID
Header: ({ getToggleAllRowsExpandedProps, isAllRowsExpanded }) => (
<span {...getToggleAllRowsExpandedProps()}>
{isAllRowsExpanded ? '👇' : '👉'}
</span>
),
Cell: ({ row }) =>
// Use the row.canExpand and row.getExpandedToggleProps prop getter
// Use the row.canExpand and row.getToggleRowExpandedProps prop getter
// to build the toggle for expanding a row
row.canExpand ? (
<span
{...row.getExpandedToggleProps({
{...row.getToggleRowExpandedProps({
style: {
// We can even use the row.depth property
// and paddingLeft to indicate the depth
+4 -4
View File
@@ -8087,10 +8087,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.15"
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.0.0-rc.15.tgz#bb855e4e2abbb4aaf0ed2334404a41f3ada8e13a"
integrity sha512-ofMOlgrioHhhvHjvjsQkxvfQzU98cqwy6BjPGNwhLN1vhgXeWi0mUGreaCPvRenEbTiXsQbMl4k3Xmx3Mut8Rw==
react@^16.8.6:
version "16.8.6"
+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,
visibleColumns,
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={visibleColumns.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"
@@ -10,7 +10,7 @@
"namor": "^1.1.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1",
"react-scripts": "3.3.0",
"react-table": "latest",
"styled-components": "^4.3.2"
},
+100 -28
View File
@@ -1,18 +1,22 @@
import React from 'react'
import styled from 'styled-components'
import { useTable, useResizeColumns, useFlexLayout } from 'react-table'
import {
useTable,
useResizeColumns,
useFlexLayout,
useRowSelect,
} from 'react-table'
import makeData from './makeData'
const Styles = styled.div`
padding: 1rem;
${'' /* 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;
.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;
@@ -35,13 +39,13 @@ const Styles = styled.div`
border-bottom: 0;
}
}
border-bottom: 1px solid black;
}
.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,
@@ -53,16 +57,15 @@ const Styles = styled.div`
}
.resizer {
display: inline-block;
right: 0;
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;
touch-action :none;
&.isResizing {
background: red;
@@ -72,6 +75,38 @@ const Styles = styled.div`
}
`
const headerProps = (props, { column }) => getStyles(props, column.align)
const cellProps = (props, { cell }) => getStyles(props, cell.column.align)
const getStyles = (props, align = 'left') => [
props,
{
style: {
justifyContent: align === 'right' ? 'flex-end' : 'flex-start',
alignItems: 'flex-start',
display: 'flex',
},
},
]
const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, ...rest }, ref) => {
const defaultRef = React.useRef()
const resolvedRef = ref || defaultRef
React.useEffect(() => {
resolvedRef.current.indeterminate = indeterminate
}, [resolvedRef, indeterminate])
return (
<>
<input type="checkbox" ref={resolvedRef} {...rest} />
</>
)
}
)
function Table({ columns, data }) {
const defaultColumn = React.useMemo(
() => ({
@@ -83,49 +118,84 @@ function Table({ columns, data }) {
[]
)
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable(
const { getTableProps, headerGroups, rows, prepareRow } = useTable(
{
columns,
data,
defaultColumn,
},
useResizeColumns,
useFlexLayout
useFlexLayout,
useRowSelect,
hooks => {
hooks.allColumns.push(columns => [
// Let's make a column for selection
{
id: 'selection',
disableResizing: true,
minWidth: 35,
width: 35,
maxWidth: 35,
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
...columns,
])
hooks.useInstanceBeforeDimensions.push(({ headerGroups }) => {
// fix the parent group of the selection button to not be resizable
const selectionGroupHeader = headerGroups[0].headers[0]
selectionGroupHeader.canResize = false
})
}
)
return (
<div {...getTableProps()} className="table">
<div>
{headerGroups.map(headerGroup => (
<div {...headerGroup.getHeaderGroupProps()} className="tr">
<div
{...headerGroup.getHeaderGroupProps({
// style: { paddingRight: '15px' },
})}
className="tr"
>
{headerGroup.headers.map(column => (
<div {...column.getHeaderProps()} className="th">
<div {...column.getHeaderProps(headerProps)} className="th">
{column.render('Header')}
{/* Use column.getResizerProps to hook up the events correctly */}
<div
{...column.getResizerProps()}
className={`resizer ${column.isResizing ? 'isResizing' : ''}`}
/>
{column.canResize && (
<div
{...column.getResizerProps()}
className={`resizer ${
column.isResizing ? 'isResizing' : ''
}`}
/>
)}
</div>
))}
</div>
))}
</div>
<div {...getTableBodyProps()} className="tbody">
{rows.map((row, i) => {
<div className="tbody">
{rows.map(row => {
prepareRow(row)
return (
<div {...row.getRowProps()} className="tr">
{row.cells.map(cell => {
return (
<div {...cell.getCellProps()} className="td">
<div {...cell.getCellProps(cellProps)} className="td">
{cell.render('Cell')}
</div>
)
@@ -161,11 +231,13 @@ function App() {
Header: 'Age',
accessor: 'age',
width: 50,
align: 'right',
},
{
Header: 'Visits',
accessor: 'visits',
width: 50,
align: 'right',
},
{
Header: 'Status',
File diff suppressed because it is too large Load Diff
+33 -18
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.visibleColumns.push((columns, { instance }) => {
if (!instance.state.groupBy.length) {
return columns
}
@@ -59,9 +74,9 @@ function Table({ columns, data }) {
{
id: 'expander', // Make sure it has an ID
// Build our expander column
Header: ({ flatColumns, state: { groupBy } }) => {
Header: ({ allColumns, state: { groupBy } }) => {
return groupBy.map(columnId => {
const column = flatColumns.find(d => d.id === columnId)
const column = allColumns.find(d => d.id === columnId)
return (
<span {...column.getHeaderProps()}>
@@ -82,7 +97,7 @@ function Table({ columns, data }) {
return (
<span
{...row.getExpandedToggleProps({
{...row.getToggleRowExpandedProps({
style: {
// We can even use the row.depth property
// and paddingLeft to indicate the depth
@@ -100,20 +115,20 @@ function Table({ columns, data }) {
return null
},
},
...columns.map(d => ({ ...d, isVisible: !d.isGrouped })),
...columns,
]
})
}
)
// We don't want to render all of the rows for this example, so cap
// it at 20 for this use case
// it at 100 for this use case
const firstPageRows = rows.slice(0, 100)
return (
<>
<pre>
<code>{JSON.stringify({ groupBy, expanded: expanded }, null, 2)}</code>
<code>{JSON.stringify({ state }, null, 2)}</code>
</pre>
<Legend />
<table {...getTableProps()}>
@@ -151,7 +166,7 @@ function Table({ columns, data }) {
? '#0aff0082'
: cell.isAggregated
? '#ffa50078'
: cell.isRepeatedValue
: cell.isPlaceholder
? '#ff000042'
: 'white',
}}
@@ -160,7 +175,7 @@ function Table({ columns, data }) {
? // If the cell is aggregated, use the Aggregated
// renderer for cell
cell.render('Aggregated')
: cell.isRepeatedValue
: cell.isPlaceholder
? null // For cells with repeated values, render null
: // Otherwise, just render the regular cell
cell.render('Cell')}
@@ -210,20 +225,20 @@ function Legend() {
padding: '0.5rem',
}}
>
Repeated Value
Placeholder
</span>
</div>
)
}
// This is a custom aggregator that
// takes in an array of values and
// takes in an array of leaf values and
// returns the rounded median
function roundedMedian(values) {
let min = values[0] || ''
let max = values[0] || ''
function roundedMedian(leafValues) {
let min = leafValues[0] || 0
let max = leafValues[0] || 0
values.forEach(value => {
leafValues.forEach(value => {
min = Math.min(min, value)
max = Math.max(max, value)
})
@@ -244,7 +259,7 @@ function App() {
// count the total rows being aggregated,
// then sum any of those counts if they are
// aggregated further
aggregate: ['sum', 'count'],
aggregate: 'count',
Aggregated: ({ cell: { value } }) => `${value} Names`,
},
{
@@ -254,7 +269,7 @@ function App() {
// first count the UNIQUE values from the rows
// being aggregated, then sum those counts if
// they are aggregated further
aggregate: ['sum', 'uniqueCount'],
aggregate: 'uniqueCount',
Aggregated: ({ cell: { value } }) => `${value} Unique Names`,
},
],
+53 -53
View File
@@ -51,7 +51,7 @@ function Table({ columns, data }) {
)
// We don't want to render all of the rows for this example, so cap
// it at 20 for this use case
// it at 100 for this use case
const firstPageRows = rows.slice(0, 100)
return (
@@ -79,50 +79,49 @@ function Table({ columns, data }) {
))}
</thead>
<tbody {...getTableBodyProps()}>
{firstPageRows.map(
(row, i) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td
// For educational purposes, let's color the
// cell depending on what type it is given
// from the useGroupBy hook
{...cell.getCellProps()}
style={{
background: cell.isGrouped
? '#0aff0082'
: cell.isAggregated
? '#ffa50078'
: cell.isRepeatedValue
? '#ff000042'
: 'white',
}}
>
{cell.isGrouped ? (
// If it's a grouped cell, add an expander and row count
<>
<span {...row.getExpandedToggleProps()}>
{row.isExpanded ? '👇' : '👉'}
</span>{' '}
{cell.render('Cell')} ({row.subRows.length})
</>
) : cell.isAggregated ? (
// If the cell is aggregated, use the Aggregated
// renderer for cell
cell.render('Aggregated')
) : cell.isRepeatedValue ? null : ( // For cells with repeated values, render null
// Otherwise, just render the regular cell
cell.render('Cell')
)}
</td>
)
})}
</tr>
)}
)}
{firstPageRows.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td
// For educational purposes, let's color the
// cell depending on what type it is given
// from the useGroupBy hook
{...cell.getCellProps()}
style={{
background: cell.isGrouped
? '#0aff0082'
: cell.isAggregated
? '#ffa50078'
: cell.isPlaceholder
? '#ff000042'
: 'white',
}}
>
{cell.isGrouped ? (
// If it's a grouped cell, add an expander and row count
<>
<span {...row.getToggleRowExpandedProps()}>
{row.isExpanded ? '👇' : '👉'}
</span>{' '}
{cell.render('Cell')} ({row.subRows.length})
</>
) : cell.isAggregated ? (
// If the cell is aggregated, use the Aggregated
// renderer for cell
cell.render('Aggregated')
) : cell.isPlaceholder ? null : ( // For cells with repeated values, render null
// Otherwise, just render the regular cell
cell.render('Cell')
)}
</td>
)
})}
</tr>
)
})}
</tbody>
</table>
<br />
@@ -170,13 +169,13 @@ function Legend() {
}
// This is a custom aggregator that
// takes in an array of values and
// takes in an array of leaf values and
// returns the rounded median
function roundedMedian(values) {
let min = values[0] || ''
let max = values[0] || ''
function roundedMedian(leafValues) {
let min = leafValues[0] || 0
let max = leafValues[0] || 0
values.forEach(value => {
leafValues.forEach(value => {
min = Math.min(min, value)
max = Math.max(max, value)
})
@@ -197,7 +196,7 @@ function App() {
// count the total rows being aggregated,
// then sum any of those counts if they are
// aggregated further
aggregate: ['sum', 'count'],
aggregate: 'count',
Aggregated: ({ cell: { value } }) => `${value} Names`,
},
{
@@ -207,7 +206,7 @@ function App() {
// first count the UNIQUE values from the rows
// being aggregated, then sum those counts if
// they are aggregated further
aggregate: ['sum', 'uniqueCount'],
aggregate: 'uniqueCount',
Aggregated: ({ cell: { value } }) => `${value} Unique Names`,
},
],
@@ -220,7 +219,8 @@ function App() {
accessor: 'age',
// Aggregate the average age of visitors
aggregate: 'average',
Aggregated: ({ cell: { value } }) => `${value} (avg)`,
Aggregated: ({ cell: { value } }) =>
`${Math.round(value * 100) / 100} (avg)`,
},
{
Header: 'Visits',
+13 -8
View File
@@ -2632,7 +2632,7 @@ commander@2.17.x:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
commander@^2.11.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.0:
commander@^2.11.0, commander@^2.19.0, commander@^2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
@@ -2642,6 +2642,11 @@ commander@~2.19.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
commander@~2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
common-tags@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937"
@@ -4369,9 +4374,9 @@ handle-thing@^2.0.0:
integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==
handlebars@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67"
integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==
version "4.5.3"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482"
integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==
dependencies:
neo-async "^2.6.0"
optimist "^0.6.1"
@@ -9435,11 +9440,11 @@ uglify-js@3.4.x:
source-map "~0.6.1"
uglify-js@^3.1.4:
version "3.6.0"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5"
integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==
version "3.7.3"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.3.tgz#f918fce9182f466d5140f24bb0ff35c2d32dcc6a"
integrity sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg==
dependencies:
commander "~2.20.0"
commander "~2.20.3"
source-map "~0.6.1"
unicode-canonical-property-names-ecmascript@^1.0.4:
+11 -11
View File
@@ -301,14 +301,14 @@ function Table({ columns, data, updateMyData, skipPageReset }) {
// when we edit the data, undefined means using the default
autoResetPage: !skipPageReset,
},
useGroupBy,
useFilters,
useGroupBy,
useSortBy,
useExpanded,
usePagination,
useRowSelect,
hooks => {
hooks.flatColumns.push(columns => [
hooks.visibleColumns.push(columns => [
{
id: 'selection',
// Make this column a groupByBoundary. This ensures that groupBy columns
@@ -378,7 +378,7 @@ function Table({ columns, data, updateMyData, skipPageReset }) {
{cell.isGrouped ? (
// If it's a grouped cell, add an expander and row count
<>
<span {...row.getExpandedToggleProps()}>
<span {...row.getToggleRowExpandedProps()}>
{row.isExpanded ? '👇' : '👉'}
</span>{' '}
{cell.render('Cell', { editable: false })} (
@@ -388,7 +388,7 @@ function Table({ columns, data, updateMyData, skipPageReset }) {
// If the cell is aggregated, use the Aggregated
// renderer for cell
cell.render('Aggregated')
) : cell.isRepeatedValue ? null : ( // For cells with repeated values, render null
) : cell.isPlaceholder ? null : ( // For cells with repeated values, render null
// Otherwise, just render the regular cell
cell.render('Cell', { editable: true })
)}
@@ -486,13 +486,13 @@ function filterGreaterThan(rows, id, filterValue) {
filterGreaterThan.autoRemove = val => typeof val !== 'number'
// This is a custom aggregator that
// takes in an array of values and
// takes in an array of leaf values and
// returns the rounded median
function roundedMedian(values) {
let min = values[0] || ''
let max = values[0] || ''
function roundedMedian(leafValues) {
let min = leafValues[0] || 0
let max = leafValues[0] || 0
values.forEach(value => {
leafValues.forEach(value => {
min = Math.min(min, value)
max = Math.max(max, value)
})
@@ -513,7 +513,7 @@ function App() {
// count the total rows being aggregated,
// then sum any of those counts if they are
// aggregated further
aggregate: ['sum', 'count'],
aggregate: 'count',
Aggregated: ({ cell: { value } }) => `${value} Names`,
},
{
@@ -525,7 +525,7 @@ function App() {
// first count the UNIQUE values from the rows
// being aggregated, then sum those counts if
// they are aggregated further
aggregate: ['sum', 'uniqueCount'],
aggregate: 'uniqueCount',
Aggregated: ({ cell: { value } }) => `${value} Unique Names`,
},
],
+4 -4
View File
@@ -8095,10 +8095,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.15"
resolved "https://registry.yarnpkg.com/react-table/-/react-table-7.0.0-rc.15.tgz#bb855e4e2abbb4aaf0ed2334404a41f3ada8e13a"
integrity sha512-ofMOlgrioHhhvHjvjsQkxvfQzU98cqwy6BjPGNwhLN1vhgXeWi0mUGreaCPvRenEbTiXsQbMl4k3Xmx3Mut8Rw==
react@^16.8.6:
version "16.8.6"
+22 -12
View File
@@ -282,7 +282,15 @@ function Table({ columns, data, updateMyData, skipReset }) {
nextPage,
previousPage,
setPageSize,
state: { pageIndex, pageSize, groupBy, expanded, filters, selectedRowIds },
state: {
pageIndex,
pageSize,
sortBy,
groupBy,
expanded,
filters,
selectedRowIds,
},
} = useTable(
{
columns,
@@ -299,6 +307,7 @@ function Table({ columns, data, updateMyData, skipReset }) {
// when we edit the data.
autoResetPage: !skipReset,
autoResetSelectedRows: !skipReset,
disableMultiSort: true,
},
useFilters,
useGroupBy,
@@ -308,7 +317,7 @@ function Table({ columns, data, updateMyData, skipReset }) {
useRowSelect,
// Here we will use a plugin to add our selection column
hooks => {
hooks.flatColumns.push(columns => {
hooks.visibleColumns.push(columns => {
return [
{
id: 'selection',
@@ -380,7 +389,7 @@ function Table({ columns, data, updateMyData, skipReset }) {
{cell.isGrouped ? (
// If it's a grouped cell, add an expander and row count
<>
<span {...row.getExpandedToggleProps()}>
<span {...row.getToggleRowExpandedProps()}>
{row.isExpanded ? '👇' : '👉'}
</span>{' '}
{cell.render('Cell', { editable: false })} (
@@ -390,7 +399,7 @@ function Table({ columns, data, updateMyData, skipReset }) {
// If the cell is aggregated, use the Aggregated
// renderer for cell
cell.render('Aggregated')
) : cell.isRepeatedValue ? null : ( // For cells with repeated values, render null
) : cell.isPlaceholder ? null : ( // For cells with repeated values, render null
// Otherwise, just render the regular cell
cell.render('Cell', { editable: true })
)}
@@ -459,6 +468,7 @@ function Table({ columns, data, updateMyData, skipReset }) {
pageCount,
canNextPage,
canPreviousPage,
sortBy,
groupBy,
expanded: expanded,
filters,
@@ -488,13 +498,13 @@ function filterGreaterThan(rows, id, filterValue) {
filterGreaterThan.autoRemove = val => typeof val !== 'number'
// This is a custom aggregator that
// takes in an array of values and
// takes in an array of leaf values and
// returns the rounded median
function roundedMedian(values) {
let min = values[0] || ''
let max = values[0] || ''
function roundedMedian(leafValues) {
let min = leafValues[0] || 0
let max = leafValues[0] || 0
values.forEach(value => {
leafValues.forEach(value => {
min = Math.min(min, value)
max = Math.max(max, value)
})
@@ -532,7 +542,7 @@ function App() {
// count the total rows being aggregated,
// then sum any of those counts if they are
// aggregated further
aggregate: ['sum', 'count'],
aggregate: 'count',
Aggregated: ({ cell: { value } }) => `${value} Names`,
},
{
@@ -544,7 +554,7 @@ function App() {
// first count the UNIQUE values from the rows
// being aggregated, then sum those counts if
// they are aggregated further
aggregate: ['sum', 'uniqueCount'],
aggregate: 'uniqueCount',
Aggregated: ({ cell: { value } }) => `${value} Unique Names`,
},
],
@@ -617,7 +627,7 @@ function App() {
)
}
// After data chagnes, we turn the flag back off
// After data changes, we turn the flag back off
// so that if data actually changes when we're not
// editing it, the page is reset
React.useEffect(() => {
@@ -0,0 +1,3 @@
{
"presets": ["react-app"]
}
+1
View File
@@ -0,0 +1 @@
SKIP_PREFLIGHT_CHECK=true
@@ -0,0 +1,7 @@
{
"extends": ["react-app", "prettier"],
"rules": {
// "eqeqeq": 0,
// "jsx-a11y/anchor-is-valid": 0
}
}
@@ -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,
]
@@ -0,0 +1,8 @@
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/material-UI-enhanced-table)
- `yarn` and `yarn start` to run and edit the example
It demonstrates client side pagination, sorting, global search, add row, and delete row.
@@ -0,0 +1,37 @@
{
"private": true,
"scripts": {
"start": "rescripts start",
"build": "rescripts build",
"test": "rescripts test",
"eject": "rescripts eject"
},
"dependencies": {
"@material-ui/core": "^4.8.3",
"@material-ui/icons": "^4.5.1",
"namor": "^1.1.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1",
"react-table": "latest"
},
"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",
"eslint-config-prettier": "^6.3.0"
},
"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,77 @@
import React from 'react'
import CssBaseline from '@material-ui/core/CssBaseline'
import EnhancedTable from './components/EnhancedTable'
import makeData from './makeData'
const App = () => {
const columns = React.useMemo(
() => [
{
Header: 'First Name',
accessor: 'firstName',
},
{
Header: 'Last Name',
accessor: 'lastName',
},
{
Header: 'Age',
accessor: 'age',
},
{
Header: 'Visits',
accessor: 'visits',
},
{
Header: 'Status',
accessor: 'status',
},
{
Header: 'Profile Progress',
accessor: 'progress',
},
],
[]
)
const [data, setData] = React.useState(React.useMemo(() => makeData(20), []))
const [skipPageReset, setSkipPageReset] = React.useState(false)
// 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.
// 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
setSkipPageReset(true)
setData(old =>
old.map((row, index) => {
if (index === rowIndex) {
return {
...old[rowIndex],
[columnId]: value,
}
}
return row
})
)
}
return (
<div>
<CssBaseline />
<EnhancedTable
columns={columns}
data={data}
setData={setData}
updateMyData={updateMyData}
skipPageReset={skipPageReset}
/>
</div>
)
}
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,152 @@
import React, { useState } from 'react'
import AddIcon from '@material-ui/icons/Add'
import Button from '@material-ui/core/Button'
import Dialog from '@material-ui/core/Dialog'
import DialogActions from '@material-ui/core/DialogActions'
import DialogContent from '@material-ui/core/DialogContent'
import DialogContentText from '@material-ui/core/DialogContentText'
import DialogTitle from '@material-ui/core/DialogTitle'
import IconButton from '@material-ui/core/IconButton'
import PropTypes from 'prop-types'
import Switch from '@material-ui/core/Switch'
import TextField from '@material-ui/core/TextField'
import Tooltip from '@material-ui/core/Tooltip'
const initialUser = {
firstName: '',
lastName: '',
age: 0,
visits: 0,
status: 'single',
progress: 0,
subRows: undefined,
}
const AddUserDialog = props => {
const [user, setUser] = useState(initialUser)
const { addUserHandler } = props
const [open, setOpen] = React.useState(false)
const [switchState, setSwitchState] = React.useState({
addMultiple: false,
})
const handleSwitchChange = name => event => {
setSwitchState({ ...switchState, [name]: event.target.checked })
}
const resetSwitch = () => {
setSwitchState({ addMultiple: false })
}
const handleClickOpen = () => {
setOpen(true)
}
const handleClose = () => {
setOpen(false)
resetSwitch()
}
const handleAdd = event => {
addUserHandler(user)
setUser(initialUser)
switchState.addMultiple ? setOpen(true) : setOpen(false)
}
const handleChange = name => ({ target: { value } }) => {
setUser({ ...user, [name]: value })
}
return (
<div>
<Tooltip title="Add">
<IconButton aria-label="add" onClick={handleClickOpen}>
<AddIcon />
</IconButton>
</Tooltip>
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="form-dialog-title"
>
<DialogTitle id="form-dialog-title">Add User</DialogTitle>
<DialogContent>
<DialogContentText>Demo add item to react table.</DialogContentText>
<TextField
autoFocus
margin="dense"
label="First Name"
type="text"
fullWidth
value={user.firstName}
onChange={handleChange('firstName')}
/>
<TextField
margin="dense"
label="Last Name"
type="text"
fullWidth
value={user.lastName}
onChange={handleChange('lastName')}
/>
<TextField
margin="dense"
label="Age"
type="number"
fullWidth
value={user.age}
onChange={handleChange('age')}
/>
<TextField
margin="dense"
label="Visits"
type="number"
fullWidth
value={user.visits}
onChange={handleChange('visits')}
/>
<TextField
margin="dense"
label="Status"
type="text"
fullWidth
value={user.status}
onChange={handleChange('status')}
/>
<TextField
margin="dense"
label="Profile Progress"
type="number"
fullWidth
value={user.progress}
onChange={handleChange('progress')}
/>
</DialogContent>
<DialogActions>
<Tooltip title="Add multiple">
<Switch
checked={switchState.addMultiple}
onChange={handleSwitchChange('addMultiple')}
value="addMultiple"
inputProps={{ 'aria-label': 'secondary checkbox' }}
/>
</Tooltip>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
<Button onClick={handleAdd} color="primary">
Add
</Button>
</DialogActions>
</Dialog>
</div>
)
}
AddUserDialog.propTypes = {
addUserHandler: PropTypes.func.isRequired,
}
export default AddUserDialog
@@ -0,0 +1,274 @@
import React from 'react'
import Checkbox from '@material-ui/core/Checkbox'
import MaUTable from '@material-ui/core/Table'
import PropTypes from 'prop-types'
import TableBody from '@material-ui/core/TableBody'
import TableCell from '@material-ui/core/TableCell'
import TableContainer from '@material-ui/core/TableContainer'
import TableFooter from '@material-ui/core/TableFooter'
import TableHead from '@material-ui/core/TableHead'
import TablePagination from '@material-ui/core/TablePagination'
import TablePaginationActions from './TablePaginationActions'
import TableRow from '@material-ui/core/TableRow'
import TableSortLabel from '@material-ui/core/TableSortLabel'
import TableToolbar from './TableToolbar'
import {
useGlobalFilter,
usePagination,
useRowSelect,
useSortBy,
useTable,
} from 'react-table'
const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, ...rest }, ref) => {
const defaultRef = React.useRef()
const resolvedRef = ref || defaultRef
React.useEffect(() => {
resolvedRef.current.indeterminate = indeterminate
}, [resolvedRef, indeterminate])
return (
<>
<Checkbox ref={resolvedRef} {...rest} />
</>
)
}
)
const inputStyle = {
padding: 0,
margin: 0,
border: 0,
background: 'transparent',
}
// Create an editable cell renderer
const EditableCell = ({
cell: { 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)
}
// If the initialValue is changed externall, sync it up with our state
React.useEffect(() => {
setValue(initialValue)
}, [initialValue])
return (
<input
style={inputStyle}
value={value}
onChange={onChange}
onBlur={onBlur}
/>
)
}
EditableCell.propTypes = {
cell: PropTypes.shape({
value: PropTypes.any.isRequired,
}),
row: PropTypes.shape({
index: PropTypes.number.isRequired,
}),
column: PropTypes.shape({
id: PropTypes.number.isRequired,
}),
updateMyData: PropTypes.func.isRequired,
}
// Set our editable cell renderer as the default Cell renderer
const defaultColumn = {
Cell: EditableCell,
}
const EnhancedTable = ({
columns,
data,
setData,
updateMyData,
skipPageReset,
}) => {
const {
getTableProps,
headerGroups,
prepareRow,
page,
gotoPage,
setPageSize,
preGlobalFilteredRows,
setGlobalFilter,
state: { pageIndex, pageSize, selectedRowIds, globalFilter },
} = useTable(
{
columns,
data,
defaultColumn,
autoResetPage: !skipPageReset,
// 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,
},
useGlobalFilter,
useSortBy,
usePagination,
useRowSelect,
hooks => {
hooks.allColumns.push(columns => [
// Let's make a column for selection
{
id: 'selection',
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox. Pagination is a problem since this will select all
// rows even though not all rows are on the current page. The solution should
// be server side pagination. For one, the clients should not download all
// rows in most cases. The client should only download data for the current page.
// In that case, getToggleAllRowsSelectedProps works fine.
Header: ({ getToggleAllRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
...columns,
])
}
)
const handleChangePage = (event, newPage) => {
gotoPage(newPage)
}
const handleChangeRowsPerPage = event => {
setPageSize(Number(event.target.value))
}
const removeByIndexs = (array, indexs) =>
array.filter((_, i) => !indexs.includes(i))
const deleteUserHandler = event => {
const newData = removeByIndexs(
data,
Object.keys(selectedRowIds).map(x => parseInt(x, 10))
)
setData(newData)
}
const addUserHandler = user => {
const newData = data.concat([user])
setData(newData)
}
// Render the UI for your table
return (
<TableContainer>
<TableToolbar
numSelected={Object.keys(selectedRowIds).length}
deleteUserHandler={deleteUserHandler}
addUserHandler={addUserHandler}
preGlobalFilteredRows={preGlobalFilteredRows}
setGlobalFilter={setGlobalFilter}
globalFilter={globalFilter}
/>
<MaUTable {...getTableProps()}>
<TableHead>
{headerGroups.map(headerGroup => (
<TableRow {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<TableCell
{...(column.id === 'selection'
? column.getHeaderProps()
: column.getHeaderProps(column.getSortByToggleProps()))}
>
{column.render('Header')}
{column.id !== 'selection' ? (
<TableSortLabel
active={column.isSorted}
// react-table has a unsorted state which is not treated here
direction={column.isSortedDesc ? 'desc' : 'asc'}
/>
) : null}
</TableCell>
))}
</TableRow>
))}
</TableHead>
<TableBody>
{page.map((row, i) => {
prepareRow(row)
return (
<TableRow {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<TableCell {...cell.getCellProps()}>
{cell.render('Cell')}
</TableCell>
)
})}
</TableRow>
)
})}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
rowsPerPageOptions={[
5,
10,
25,
{ label: 'All', value: data.length },
]}
colSpan={3}
count={data.length}
rowsPerPage={pageSize}
page={pageIndex}
SelectProps={{
inputProps: { 'aria-label': 'rows per page' },
native: true,
}}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
ActionsComponent={TablePaginationActions}
/>
</TableRow>
</TableFooter>
</MaUTable>
</TableContainer>
)
}
EnhancedTable.propTypes = {
columns: PropTypes.array.isRequired,
data: PropTypes.array.isRequired,
updateMyData: PropTypes.func.isRequired,
setData: PropTypes.func.isRequired,
skipPageReset: PropTypes.bool.isRequired,
}
export default EnhancedTable
@@ -0,0 +1,85 @@
import React from 'react'
import InputBase from '@material-ui/core/InputBase'
import { fade, makeStyles } from '@material-ui/core/styles'
import PropTypes from 'prop-types'
import SearchIcon from '@material-ui/icons/Search'
const useStyles = makeStyles(theme => ({
search: {
position: 'relative',
borderRadius: theme.shape.borderRadius,
backgroundColor: fade(theme.palette.common.white, 0.15),
'&:hover': {
backgroundColor: fade(theme.palette.common.white, 0.25),
},
marginRight: theme.spacing(2),
marginLeft: 0,
width: '100%',
[theme.breakpoints.up('sm')]: {
marginLeft: theme.spacing(3),
width: 'auto',
},
},
searchIcon: {
width: theme.spacing(7),
height: '100%',
position: 'absolute',
pointerEvents: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
inputRoot: {
color: 'inherit',
},
inputInput: {
padding: theme.spacing(1, 1, 1, 7),
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('md')]: {
width: 200,
},
},
}))
const GlobalFilter = ({
preGlobalFilteredRows,
globalFilter,
setGlobalFilter,
}) => {
const classes = useStyles()
const count = preGlobalFilteredRows.length
// Global filter only works with pagination from the first page.
// This may not be a problem for server side pagination when
// only the current page is downloaded.
return (
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase
value={globalFilter || ''}
onChange={e => {
setGlobalFilter(e.target.value || undefined) // Set undefined to remove the filter entirely
}}
placeholder={`${count} records...`}
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
inputProps={{ 'aria-label': 'search' }}
/>
</div>
)
}
GlobalFilter.propTypes = {
preGlobalFilteredRows: PropTypes.array.isRequired,
globalFilter: PropTypes.string.isRequired,
setGlobalFilter: PropTypes.func.isRequired,
}
export default GlobalFilter
@@ -0,0 +1,88 @@
import React from 'react'
import FirstPageIcon from '@material-ui/icons/FirstPage'
import IconButton from '@material-ui/core/IconButton'
import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft'
import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight'
import LastPageIcon from '@material-ui/icons/LastPage'
import { makeStyles, useTheme } from '@material-ui/core/styles'
import PropTypes from 'prop-types'
const useStyles = makeStyles(theme => ({
root: {
flexShrink: 0,
marginLeft: theme.spacing(2.5),
},
}))
const TablePaginationActions = props => {
const classes = useStyles()
const theme = useTheme()
const { count, page, rowsPerPage, onChangePage } = props
const handleFirstPageButtonClick = event => {
onChangePage(event, 0)
}
const handleBackButtonClick = event => {
onChangePage(event, page - 1)
}
const handleNextButtonClick = event => {
onChangePage(event, page + 1)
}
const handleLastPageButtonClick = event => {
onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1))
}
return (
<div className={classes.root}>
<IconButton
onClick={handleFirstPageButtonClick}
disabled={page === 0}
aria-label="first page"
>
{theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
</IconButton>
<IconButton
onClick={handleBackButtonClick}
disabled={page === 0}
aria-label="previous page"
>
{theme.direction === 'rtl' ? (
<KeyboardArrowRight />
) : (
<KeyboardArrowLeft />
)}
</IconButton>
<IconButton
onClick={handleNextButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label="next page"
>
{theme.direction === 'rtl' ? (
<KeyboardArrowLeft />
) : (
<KeyboardArrowRight />
)}
</IconButton>
<IconButton
onClick={handleLastPageButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label="last page"
>
{theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
</IconButton>
</div>
)
}
TablePaginationActions.propTypes = {
count: PropTypes.number.isRequired,
onChangePage: PropTypes.func.isRequired,
page: PropTypes.number.isRequired,
rowsPerPage: PropTypes.number.isRequired,
}
export default TablePaginationActions
@@ -0,0 +1,91 @@
import React from 'react'
import AddUserDialog from './AddUserDialog'
import clsx from 'clsx'
import DeleteIcon from '@material-ui/icons/Delete'
import GlobalFilter from './GlobalFilter'
import IconButton from '@material-ui/core/IconButton'
import { lighten, makeStyles } from '@material-ui/core/styles'
import PropTypes from 'prop-types'
import Toolbar from '@material-ui/core/Toolbar'
import Typography from '@material-ui/core/Typography'
import Tooltip from '@material-ui/core/Tooltip'
const useToolbarStyles = makeStyles(theme => ({
root: {
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(1),
},
highlight:
theme.palette.type === 'light'
? {
color: theme.palette.secondary.main,
backgroundColor: lighten(theme.palette.secondary.light, 0.85),
}
: {
color: theme.palette.text.primary,
backgroundColor: theme.palette.secondary.dark,
},
title: {
flex: '1 1 100%',
},
}))
const TableToolbar = props => {
const classes = useToolbarStyles()
const {
numSelected,
addUserHandler,
deleteUserHandler,
preGlobalFilteredRows,
setGlobalFilter,
globalFilter,
} = props
return (
<Toolbar
className={clsx(classes.root, {
[classes.highlight]: numSelected > 0,
})}
>
<AddUserDialog addUserHandler={addUserHandler} />
{numSelected > 0 ? (
<Typography
className={classes.title}
color="inherit"
variant="subtitle1"
>
{numSelected} selected
</Typography>
) : (
<Typography className={classes.title} variant="h6" id="tableTitle">
Users
</Typography>
)}
{numSelected > 0 ? (
<Tooltip title="Delete">
<IconButton aria-label="delete" onClick={deleteUserHandler}>
<DeleteIcon />
</IconButton>
</Tooltip>
) : (
<GlobalFilter
preGlobalFilteredRows={preGlobalFilteredRows}
globalFilter={globalFilter}
setGlobalFilter={setGlobalFilter}
/>
)}
</Toolbar>
)
}
TableToolbar.propTypes = {
numSelected: PropTypes.number.isRequired,
addUserHandler: PropTypes.func.isRequired,
deleteUserHandler: PropTypes.func.isRequired,
setGlobalFilter: PropTypes.func.isRequired,
preGlobalFilteredRows: PropTypes.array.isRequired,
globalFilter: PropTypes.string.isRequired,
}
export default TableToolbar
@@ -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,6 @@
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))
@@ -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()
}

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