From 68acd12ce67db13bee24c07064708359cc0b3ff9 Mon Sep 17 00:00:00 2001 From: Gabriel Abud Date: Tue, 25 Aug 2020 14:09:09 -0700 Subject: [PATCH] feat(Add Pagination): Add Optional Pagination Option (#17) * feat(Add Pagination): Add Optional Pagination Option * add example to README and add test for previous when page = 1 * update readme --- README.md | 82 ++++++++-- examples/basic/package-lock.json | 153 ++++++++++-------- examples/basic/src/App.tsx | 5 + examples/basic/src/PaginationTable.tsx | 77 +++++++++ package-lock.json | 211 ++++++++++++++++++++++++- package.json | 7 +- src/hooks.tsx | 85 +++++++++- src/test/makeData.tsx | 12 ++ src/test/pagination.spec.tsx | 102 ++++++++++++ src/types.ts | 15 ++ 10 files changed, 661 insertions(+), 88 deletions(-) create mode 100644 examples/basic/src/PaginationTable.tsx create mode 100644 src/test/pagination.spec.tsx diff --git a/README.md b/README.md index 3c6c0d3..85a48e9 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,19 @@ # React Final Table -![CI](https://github.com/Buuntu/react-final-table/workflows/tests/badge.svg) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) [![codecov](https://codecov.io/gh/Buuntu/react-final-table/branch/master/graph/badge.svg)](https://codecov.io/gh/Buuntu/react-final-table) ![minzipped-size](https://img.shields.io/bundlephobia/minzip/react-final-table) ![release](https://img.shields.io/npm/v/react-final-table) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) +![CI](https://github.com/Buuntu/react-final-table/workflows/tests/badge.svg) +[![License: +MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) +[![codecov](https://codecov.io/gh/Buuntu/react-final-table/branch/master/graph/badge.svg)](https://codecov.io/gh/Buuntu/react-final-table) +![minzipped-size](https://img.shields.io/bundlephobia/minzip/react-final-table) +![release](https://img.shields.io/npm/v/react-final-table) +[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) A [headless UI component libray](https://www.merrickchristensen.com/articles/headless-user-interface-components/) for managing complex table state in React. -Inspired by -[react-table](https://github.com/tannerlinsley/react-table) but with Typescript -support built in and a simpler API. +Inspired by [react-table](https://github.com/tannerlinsley/react-table) but with +Typescript support built in and a simpler API. ## Features @@ -32,16 +37,17 @@ support built in and a simpler API. - [Basic example](#basic-example) - [Searching](#searching) - [Row Selection](#row-selection) + - [Pagination](#pagination) - [Performance](#performance) - [Contributing](#contributing) ## Motivation -While there is an abundance of table libraries out there to help with sorting, filtering, pagination, and more, most are opinionated -about the user interface. Opinionated UIs can seem nice at first, but they -quickly become limiting. To embrace the Unix philosphy of separation of -concerns, the interface should be separate from the engine (from [The Art of -Unix +While there is an abundance of table libraries out there to help with sorting, +filtering, pagination, and more, most are opinionated about the user interface. +Opinionated UIs can seem nice at first, but they quickly become limiting. To +embrace the Unix philosphy of separation of concerns, the interface should be +separate from the engine (from [The Art of Unix Programming](https://www.goodreads.com/book/show/104745.The_Art_of_UNIX_Programming)). This is a minimal, type-safe, headless UI component library that you can plugin @@ -71,7 +77,9 @@ any table functionality. Only `columns` and `rows` are required as arguments: const { headers, rows } = useTable(columns, rows); ``` -1. `columns`: The first argument is an array of columns of type ColumnType. Only the name of each column is required. Each column has the following type signature: +1. `columns`: The first argument is an array of columns of type ColumnType. Only + the name of each column is required. Each column has the following type + signature: ```typescript type ColumnType = { @@ -84,7 +92,8 @@ type ColumnType = { }; ``` -2. `rows`: Rows is the second argument to useTable and can be an array of any _object_ type. +2. `rows`: Rows is the second argument to useTable and can be an array of any + _object_ type. ## Examples @@ -233,8 +242,57 @@ function App() { ); } +``` + +### Pagination + +```jsx +export const App: FC = () => { + const memoColumns = useMemo(() => columns, []); + const memoData = useMemo(() => data, []); -export default App; + const { headers, rows, pagination } = useTable<{ + firstName: string; + lastName: string; + }>(memoColumns, memoData, { pagination: true }); + + return ( + <> + + + + {headers.map((header, idx) => ( + + ))} + + + + {rows.map((row, idx) => ( + + {row.cells.map((cell, idx) => ( + + ))} + + ))} + +
{header.render()}
{cell.render()}
+
+ + +
+ + ); +} ``` ## Performance diff --git a/examples/basic/package-lock.json b/examples/basic/package-lock.json index 054a165..e867b31 100644 --- a/examples/basic/package-lock.json +++ b/examples/basic/package-lock.json @@ -65,9 +65,9 @@ } }, "@babel/generator": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz", - "integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==", + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.4.tgz", + "integrity": "sha512-Rn26vueFx0eOoz7iifCN2UHT6rGtnkSGWSoDRIy8jZN3B91PzeSULbswfLoOWuTuAcNwpG/mxy+uCTDnZ9Mp1g==", "requires": { "@babel/types": "^7.11.0", "jsesc": "^2.5.1", @@ -170,11 +170,10 @@ } }, "@babel/helper-explode-assignable-expression": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.4.tgz", - "integrity": "sha512-4K71RyRQNPRrR85sr5QY4X3VwG4wtVoXZB9+L3r1Gp38DhELyHCtovqydRi7c1Ovb17eRGiQ/FD5s8JdU0Uy5A==", + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.11.4.tgz", + "integrity": "sha512-ux9hm3zR4WV1Y3xXxXkdG/0gxF9nvI0YVmKVhvK9AfMoaQkemL3sJpXw+Xbz65azo8qJiEz2XVDUpK3KYhH3ZQ==", "requires": { - "@babel/traverse": "^7.10.4", "@babel/types": "^7.10.4" } }, @@ -256,14 +255,13 @@ } }, "@babel/helper-remap-async-to-generator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.4.tgz", - "integrity": "sha512-86Lsr6NNw3qTNl+TBcF1oRZMaVzJtbWTyTko+CQL/tvNvcGYEFKbLXDPxtW0HKk3McNOk4KzY55itGWCAGK5tg==", + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.11.4.tgz", + "integrity": "sha512-tR5vJ/vBa9wFy3m5LLv2faapJLnDFxNWff2SAYkSE4rLUdbp7CdObYFgI7wK4T/Mj4UzpjPwzR8Pzmr5m7MHGA==", "requires": { "@babel/helper-annotate-as-pure": "^7.10.4", "@babel/helper-wrap-function": "^7.10.4", "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", "@babel/types": "^7.10.4" } }, @@ -340,9 +338,9 @@ } }, "@babel/parser": { - "version": "7.11.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.3.tgz", - "integrity": "sha512-REo8xv7+sDxkKvoxEywIdsNFiZLybwdI7hcT5uEPyQrSMB4YQ973BfC9OOrD/81MaIjh6UxdulIQXkjmiH3PcA==" + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.4.tgz", + "integrity": "sha512-MggwidiH+E9j5Sh8pbrX5sJvMcsqS5o+7iB42M9/k0CD63MjYbdP4nhSh7uB5wnv2/RVzTZFTxzF/kIa5mrCqA==" }, "@babel/plugin-proposal-async-generator-functions": { "version": "7.10.5", @@ -1752,9 +1750,9 @@ "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" }, "@types/react": { - "version": "16.9.46", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.46.tgz", - "integrity": "sha512-dbHzO3aAq1lB3jRQuNpuZ/mnu+CdD3H0WVaaBQA8LTT3S33xhVBUj232T8M3tAhSWJs/D/UqORYUlJNl/8VQZg==", + "version": "16.9.47", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.47.tgz", + "integrity": "sha512-dAJO4VbrjYqTUwFiQqAKjLyHHl4RSTNnRyPdX3p16MPbDKvow51wxATUPxoe2QsiXNMEYrOjc2S6s92VjG+1VQ==", "requires": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -2200,18 +2198,18 @@ } }, "aggregate-error": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz", - "integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "requires": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "ajv": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", - "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "version": "6.12.4", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", + "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2656,13 +2654,13 @@ } }, "parse-json": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.1.tgz", - "integrity": "sha512-ztoZ4/DYeXQq4E21v169sC8qWINGpcosGv9XhTDvg9/hWvx/zrFkc9BiWxR58OJLHGk28j5BL0SDLeV2WmFZlQ==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", + "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", + "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" } }, @@ -3001,9 +2999,9 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "bn.js": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", - "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==" + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", + "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==" }, "body-parser": { "version": "1.19.0", @@ -3364,9 +3362,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001113", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001113.tgz", - "integrity": "sha512-qMvjHiKH21zzM/VDZr6oosO6Ri3U0V2tC015jRXjOecwQCJtsU5zklTNTk31jQbIOP8gha0h1ccM/g0ECP+4BA==" + "version": "1.0.30001117", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001117.tgz", + "integrity": "sha512-4tY0Fatzdx59kYjQs+bNxUwZB03ZEBgVmJ1UkFPz/Q8OLiUUbjct2EdpnXj0fvFTPej2EkbPIG0w8BWsjAyk1Q==" }, "capture-exit": { "version": "2.0.0", @@ -4198,9 +4196,9 @@ } }, "csstype": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.2.tgz", - "integrity": "sha512-ofovWglpqoqbfLNOTBNZLSbMuGrblAf1efvvArGKOZMBrIoJeu5UsAipQolkijtyQx5MtAzT/J9IHj/CEY1mJw==" + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.3.tgz", + "integrity": "sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag==" }, "cyclist": { "version": "1.0.1", @@ -4656,9 +4654,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.3.533", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.533.tgz", - "integrity": "sha512-YqAL+NXOzjBnpY+dcOKDlZybJDCOzgsq4koW3fvyty/ldTmsb4QazZpOWmVvZ2m0t5jbBf7L0lIGU3BUipwG+A==" + "version": "1.3.545", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.545.tgz", + "integrity": "sha512-+0R/i17u5E1cwF3g0W8Niq3UUKTUMyyT4kLkutZUHG8mDNvFsAckK3HIanzGVtixe3b6rknD8k7gHiR6nKFkgg==" }, "elliptic": { "version": "6.5.3", @@ -5337,9 +5335,9 @@ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, "eventemitter3": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", - "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.6.tgz", + "integrity": "sha512-s3GJL04SQoM+gn2c14oyqxvZ3Pcq7cduSDqy3sBFXx6UPSUmgVYwQM9zwkTn9je0lrfg0gHEwR42pF3Q2dCQkQ==" }, "events": { "version": "3.2.0", @@ -5516,9 +5514,9 @@ }, "dependencies": { "type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", - "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", + "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==" } } }, @@ -6884,6 +6882,11 @@ "is-extglob": "^2.1.1" } }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=" + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -7664,6 +7667,11 @@ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, + "json-parse-even-better-errors": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.0.tgz", + "integrity": "sha512-o3aP+RsWDJZayj1SbHNQAI8x0v3T3SKiGoZlNYfbUP1S3omJQ6i9CnqADqkSPaOAxwua4/1YWx5CM7oiChJt2Q==" + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -7902,9 +7910,9 @@ } }, "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, "lodash._reinterpolate": { "version": "3.0.0", @@ -8785,17 +8793,17 @@ } }, "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "requires": { "mimic-fn": "^2.1.0" } }, "open": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-7.1.0.tgz", - "integrity": "sha512-lLPI5KgOwEYCDKXf4np7y1PBEkj7HYIyP2DY8mVDRnx0VIIu6bNrRB0R66TuO7Mack6EnTNLm4uvcl1UoklTpA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-7.2.0.tgz", + "integrity": "sha512-4HeyhxCvBTI5uBePsAdi55C5fmqnWZ2e2MlmvWi5KW5tdH5rxoiv/aMtbeVxKZc3eWkT1GymMnLG8XC4Rq4TDQ==", "requires": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" @@ -10298,9 +10306,9 @@ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, "querystringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", - "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, "raf": { "version": "3.4.1", @@ -11414,12 +11422,33 @@ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==" }, "side-channel": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz", - "integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.3.tgz", + "integrity": "sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g==", "requires": { - "es-abstract": "^1.17.0-next.1", - "object-inspect": "^1.7.0" + "es-abstract": "^1.18.0-next.0", + "object-inspect": "^1.8.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz", + "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==", + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } } }, "signal-exit": { diff --git a/examples/basic/src/App.tsx b/examples/basic/src/App.tsx index d8ae02b..806ce40 100644 --- a/examples/basic/src/App.tsx +++ b/examples/basic/src/App.tsx @@ -1,6 +1,8 @@ import React, { useMemo } from 'react'; import { useTable } from 'react-final-table'; +import { PaginationTable } from './PaginationTable'; + const columns = [ { name: 'first_name', @@ -43,6 +45,7 @@ function App() { } ); + return ( <> @@ -75,6 +78,8 @@ function App() {
         {JSON.stringify(selectedRows)}
       
+

Pagination

+ ); } diff --git a/examples/basic/src/PaginationTable.tsx b/examples/basic/src/PaginationTable.tsx new file mode 100644 index 0000000..8896325 --- /dev/null +++ b/examples/basic/src/PaginationTable.tsx @@ -0,0 +1,77 @@ +import React, { FC } from 'react'; +import { useTable } from 'react-final-table'; +import { useMemo } from 'react'; + +const columns = [ + { + name: 'firstName', + label: 'First Name', + render: ({ value }: { value: string }) => ( + <> + + 🧙 + + {value} + + ), + }, + { + name: 'lastName', + label: 'Last Name', + }, +]; + +const data = [ + { + firstName: 'Frodo', + lastName: 'Baggins', + }, + { + firstName: 'Samwise', + lastName: 'Gamgee', + }, +]; + +export const PaginationTable: FC = () => { + const memoColumns = useMemo(() => columns, []); + const memoData = useMemo(() => [...Array(10).fill(data[0]), ...Array(10).fill(data[1])], []); + + const { headers, rows, pagination } = useTable<{ + firstName: string; + lastName: string; + }>(memoColumns, memoData, { pagination: true }); + + return ( + <> +
+ + + {headers.map((header, idx) => ( + + ))} + + + + {rows.map((row, idx) => ( + + {row.cells.map((cell, idx) => ( + + ))} + + ))} + +
{header.render()}
{cell.render()}
+
+ + +
+ +
{JSON.stringify({ rows }, null, 2)}
+
+ + ) +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b7ccc6c..611d379 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,19 +33,19 @@ } }, "@babel/core": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.10.5.tgz", - "integrity": "sha512-O34LQooYVDXPl7QWCdW9p4NR+QlzOr7xShPPJz8GsuCU3/8ua/wqTr7gmnxXv+WBESiGU/G5s16i6tUvHkNb+w==", + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.4.tgz", + "integrity": "sha512-5deljj5HlqRXN+5oJTY7Zs37iH3z3b++KjiKtIsJy1NrjOOVSEaJHEetLBhyu0aQOSNNZ/0IuEAan9GzRuDXHg==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.10.5", - "@babel/helper-module-transforms": "^7.10.5", + "@babel/generator": "^7.11.4", + "@babel/helper-module-transforms": "^7.11.0", "@babel/helpers": "^7.10.4", - "@babel/parser": "^7.10.5", + "@babel/parser": "^7.11.4", "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.5", - "@babel/types": "^7.10.5", + "@babel/traverse": "^7.11.0", + "@babel/types": "^7.11.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.1", @@ -56,6 +56,75 @@ "source-map": "^0.5.0" }, "dependencies": { + "@babel/generator": { + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.4.tgz", + "integrity": "sha512-Rn26vueFx0eOoz7iifCN2UHT6rGtnkSGWSoDRIy8jZN3B91PzeSULbswfLoOWuTuAcNwpG/mxy+uCTDnZ9Mp1g==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", + "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/template": "^7.10.4", + "@babel/types": "^7.11.0", + "lodash": "^4.17.19" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/parser": { + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.4.tgz", + "integrity": "sha512-MggwidiH+E9j5Sh8pbrX5sJvMcsqS5o+7iB42M9/k0CD63MjYbdP4nhSh7uB5wnv2/RVzTZFTxzF/kIa5mrCqA==", + "dev": true + }, + "@babel/traverse": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz", + "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.0", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.11.0", + "@babel/types": "^7.11.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "@babel/types": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", + "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -2118,6 +2187,12 @@ "uri-js": "^4.2.2" } }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -2458,6 +2533,81 @@ } } }, + "babel-loader": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz", + "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==", + "dev": true, + "requires": { + "find-cache-dir": "^2.1.0", + "loader-utils": "^1.4.0", + "mkdirp": "^0.5.3", + "pify": "^4.0.1", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, "babel-messages": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", @@ -2732,6 +2882,12 @@ "tweetnacl": "^0.14.3" } }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, "bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -3466,6 +3622,12 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -7205,6 +7367,28 @@ } } }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -9008,6 +9192,17 @@ "object-assign": "^4.1.1" } }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + }, "semver": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", diff --git a/package.json b/package.json index 174aafd..3fda37e 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "start": "tsdx watch", "build": "tsdx build", "test": "tsdx test --passWithNoTests", + "test:watch": "tsdx test --passWithNoTests --watch", "test-coverage": "tsdx test --passWithNoTests --collect-coverage", "lint": "tsdx lint", "prepare": "tsdx build", @@ -37,18 +38,21 @@ "name": "react-final-table", "module": "dist/react-final-table.esm.js", "devDependencies": { + "@babel/core": "^7.11.4", "@testing-library/jest-dom": "^5.11.3", "@testing-library/react": "^10.4.8", "@testing-library/react-hooks": "^3.4.1", "@types/faker": "^4.1.12", "@types/react": "^16.9.46", "@types/react-dom": "^16.9.8", + "babel-loader": "^8.1.0", "codecov": "^3.7.2", "faker": "^4.1.0", "husky": "^4.2.5", "jest-environment-jsdom-sixteen": "^1.0.3", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-is": "^16.13.1", "react-test-renderer": "^16.13.1", "tsdx": "^0.13.2", "tslib": "^2.0.1", @@ -61,5 +65,6 @@ "bugs": { "url": "https://github.com/Buuntu/react-final-table/issues" }, - "homepage": "https://github.com/Buuntu/react-final-table#readme" + "homepage": "https://github.com/Buuntu/react-final-table#readme", + "dependencies": {} } diff --git a/src/hooks.tsx b/src/hooks.tsx index e4b1bc0..283100f 100644 --- a/src/hooks.tsx +++ b/src/hooks.tsx @@ -1,4 +1,4 @@ -import { useMemo, useReducer, useEffect, ReactNode } from 'react'; +import { useMemo, useReducer, useEffect, ReactNode, useCallback } from 'react'; import { ColumnByNamesType, @@ -21,11 +21,60 @@ const createReducer = () => ( ): TableState => { switch (action.type) { case 'SET_ROWS': + if (state.paginationEnabled === true) { + return { + ...state, + rows: getPaginatedData( + action.data, + state.pagination.perPage, + state.pagination.page + ), + originalRows: action.data, + }; + } + return { ...state, rows: action.data, originalRows: action.data, }; + + case 'NEXT_PAGE': + const nextPage = state.pagination.page + 1; + return { + ...state, + rows: getPaginatedData( + state.originalRows, + state.pagination.perPage, + nextPage + ), + pagination: { + ...state.pagination, + page: nextPage, + canNext: + nextPage * state.pagination.perPage < state.originalRows.length, + canPrev: nextPage !== 1, + }, + }; + case 'PREV_PAGE': + const prevPage = + state.pagination.page === 1 ? 1 : state.pagination.page - 1; + + return { + ...state, + rows: getPaginatedData( + state.originalRows, + state.pagination.perPage, + prevPage + ), + pagination: { + ...state.pagination, + page: prevPage, + canNext: + prevPage * state.pagination.perPage < state.originalRows.length, + canPrev: prevPage !== 1, + }, + }; case 'TOGGLE_SORT': if (!(action.columnName in state.columnsByName)) { throw new Error(`Invalid column, ${action.columnName} not found`); @@ -230,13 +279,28 @@ export const useTable = ( rows: tableData, selectedRows: [], toggleAllState: false, - filterOn: false, + filterOn: !!options?.filter, + paginationEnabled: !!options?.pagination, + pagination: { + page: 1, + perPage: 10, + canNext: true, + canPrev: false, + nextPage: () => {}, + prevPage: () => {}, + }, }); + state.pagination.nextPage = useCallback(() => { + dispatch({ type: 'NEXT_PAGE' }); + }, [dispatch]); + state.pagination.prevPage = useCallback( + () => dispatch({ type: 'PREV_PAGE' }), + [dispatch] + ); + useEffect(() => { - if (tableData.length > 0) { - dispatch({ type: 'SET_ROWS', data: tableData }); - } + dispatch({ type: 'SET_ROWS', data: tableData }); }, [tableData]); const headers: HeaderType[] = useMemo(() => { @@ -269,6 +333,7 @@ export const useTable = ( dispatch({ type: 'TOGGLE_SORT', columnName }), setSearchString: (searchString: string) => dispatch({ type: 'SEARCH_STRING', searchString }), + pagination: state.pagination, toggleAllState: state.toggleAllState, }; }; @@ -322,3 +387,13 @@ const getColumnsByName = ( return columnsByName; }; + +const getPaginatedData = ( + rows: RowType[], + perPage: number, + page: number +) => { + const start = (page - 1) * perPage; + const end = start + perPage; + return rows.slice(start, end); +}; diff --git a/src/test/makeData.tsx b/src/test/makeData.tsx index 14297b9..1029149 100644 --- a/src/test/makeData.tsx +++ b/src/test/makeData.tsx @@ -243,6 +243,18 @@ const randomData = [ phone: '+1 (989) 455-3049', address: '513 Homecrest Court, Washington, Texas, 9075', }, + { + id: 20, + isActive: false, + age: 34, + eyeColor: 'blue', + firstName: 'Joe', + lastName: 'Delaney', + company: 'KENGEN', + email: 'joe.delaney@kengen.us', + phone: '+1 (233) 455-3049', + address: '232 Terrace Court, Washington, Texas, 2341', + }, ]; const columns = [ diff --git a/src/test/pagination.spec.tsx b/src/test/pagination.spec.tsx new file mode 100644 index 0000000..4832c1f --- /dev/null +++ b/src/test/pagination.spec.tsx @@ -0,0 +1,102 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import '@testing-library/jest-dom/extend-expect'; + +import { useTable } from '../hooks'; +import { makeData } from './makeData'; + +const Table = ({ + columns, + data, +}: { + columns: any[]; + data: { firstName: string; lastName: string }[]; +}) => { + const { headers, rows, pagination } = useTable<{ + firstName: string; + lastName: string; + }>(columns, data, { pagination: true }); + + return ( + <> + + + + {headers.map((header, idx) => ( + + ))} + + + + {rows.map((row, idx) => ( + + {row.cells.map((cell, idx) => ( + + ))} + + ))} + +
{header.render()}
{cell.render()}
+
+ + +
+ {pagination.canNext ? 'yes' : 'no'} +
+
+ {pagination.canPrev ? 'yes' : 'no'} +
+
+ + ); +}; + +test('Should render a basic table', () => { + const { columns, data } = makeData(20); + const firstTenData = data.slice(0, 10); + const nextTenData = data.slice(10, 20); + render(); + + const firstTen = screen.getAllByRole('table-row'); + expect(firstTen).toHaveLength(10); + + expect(screen.getByTestId('page-number')).toContainHTML('1'); + expect(screen.getByTestId('can-prev-page')).toContainHTML('no'); + expect(screen.getByTestId('can-next-page')).toContainHTML('yes'); + + screen.getByText(firstTenData[0].firstName); + screen.getByText(firstTenData[9].firstName); + + const nextPage = screen.getByTestId('next-page'); + const prevPage = screen.getByTestId('prev-page'); + + fireEvent.click(nextPage); + + expect(screen.getByTestId('can-prev-page')).toContainHTML('yes'); + expect(screen.getByTestId('can-next-page')).toContainHTML('no'); + + const nextTen = screen.getAllByRole('table-row'); + + expect(nextTen).toHaveLength(10); + + expect(screen.getByTestId('page-number')).toContainHTML('2'); + + screen.getByText(nextTenData[0].firstName); + screen.getByText(nextTenData[9].firstName); + + fireEvent.click(prevPage); + + expect(screen.getByTestId('page-number')).toContainHTML('1'); + + expect(nextTen).toHaveLength(10); + + // on page 1, clicking previous should do nothing + fireEvent.click(prevPage); + + expect(screen.getByTestId('page-number')).toContainHTML('1'); +}); diff --git a/src/types.ts b/src/types.ts index 56d4538..92021a1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -92,6 +92,7 @@ export interface UseTablePropsType { export interface UseTableOptionsType { sortable?: boolean; selectable?: boolean; + pagination?: boolean; filter?: (row: RowType[]) => RowType[]; } @@ -106,8 +107,18 @@ export interface UseTableReturnType { toggleAll: () => void; setSearchString: (searchString: string) => void; toggleAllState: boolean; + pagination: PaginatorType; } +type PaginatorType = { + nextPage: () => void; + prevPage: () => void; + page: number; + perPage: number; + canNext: boolean; + canPrev: boolean; +}; + export type TableState = { columnsByName: ColumnByNamesType; columns: ColumnStateType[]; @@ -116,6 +127,8 @@ export type TableState = { selectedRows: RowType[]; filterOn: boolean; toggleAllState: boolean; + pagination: PaginatorType; + paginationEnabled: boolean; }; export type TableAction = @@ -125,4 +138,6 @@ export type TableAction = | { type: 'SEARCH_STRING'; searchString: string } | { type: 'GLOBAL_FILTER_OFF' } | { type: 'SET_ROWS'; data: RowType[] } + | { type: 'NEXT_PAGE' } + | { type: 'PREV_PAGE' } | { type: 'TOGGLE_ALL' };