├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .github
├── mergify.yml
└── workflows
│ └── ci.yml
├── .gitignore
├── .megalinter.yml
├── .npmrc
├── .nvmrc
├── .prettierrc
├── .trufflehog-ignore
├── LICENSE
├── README.md
├── SECURITY.md
├── example
├── README.md
├── next.config.js
├── package-lock.json
├── package.json
├── pages
│ ├── [dynamic].js
│ ├── _app.js
│ └── index.js
├── public
│ ├── example.png
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
└── styles
│ ├── main.css
│ └── theme.module.scss
├── package-lock.json
├── package.json
├── src
├── .eslintrc
├── components
│ ├── Icon.tsx
│ ├── Item.tsx
│ ├── Link.tsx
│ ├── List.tsx
│ └── Select.tsx
├── declarations.d.ts
├── index.module.scss
├── index.test.ts
├── index.tsx
├── lib
│ ├── get-page-numbers.ts
│ └── sizes.ts
└── react-app-env.d.ts
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | build/
2 | dist/
3 | node_modules/
4 | .snapshots/
5 | *.min.js
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "@typescript-eslint/parser",
3 | "plugins": [
4 | "@typescript-eslint"
5 | ],
6 | "extends": [
7 | "eslint:recommended",
8 | "plugin:@typescript-eslint/eslint-recommended",
9 | "plugin:@typescript-eslint/recommended",
10 | "prettier/react",
11 | "plugin:prettier/recommended"
12 | ],
13 | "env": {
14 | "node": true
15 | },
16 | "parserOptions": {
17 | "ecmaVersion": 2020,
18 | "ecmaFeatures": {
19 | "legacyDecorators": true,
20 | "jsx": true
21 | }
22 | },
23 | "settings": {
24 | "react": {
25 | "version": "16"
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/.github/mergify.yml:
--------------------------------------------------------------------------------
1 | ---
2 | pull_request_rules:
3 | - name: Auto-merge dependabot updates when checks pass
4 | conditions:
5 | - author=dependabot[bot]
6 | - label!=wontfix
7 | actions:
8 | review:
9 | type: APPROVE
10 | message: Automatically approving dependabot
11 | merge:
12 | method: merge
13 | - name: Auto-merge when all checks pass and the PR has been approved
14 | conditions:
15 | - "#review-requested=0"
16 | - "#approved-reviews-by>=1"
17 | actions:
18 | merge:
19 | method: merge
20 | - name: Ask for reviews
21 | conditions:
22 | - -closed
23 | - -draft
24 | - -author=dependabot[bot]
25 | actions:
26 | request_reviews:
27 | teams:
28 | - devs
29 | - name: Assign PR to its author
30 | conditions:
31 | - "#files=1"
32 | actions:
33 | assign:
34 | add_users:
35 | - "{{author}}"
36 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: 👮 CI
3 | on:
4 | pull_request:
5 | branches: [main]
6 | concurrency:
7 | group: ${{ github.workflow }}-${{ github.ref }}
8 | cancel-in-progress: true
9 | permissions: read-all
10 | jobs:
11 | build:
12 | name: 🔨 Build
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v4
16 | - uses: actions/setup-node@v4
17 | with:
18 | node-version-file: .nvmrc
19 | cache: npm
20 | - run: npm ci
21 | - run: npm run build
22 | test:
23 | name: 🧪 Test
24 | runs-on: ubuntu-latest
25 | steps:
26 | - uses: actions/checkout@v4
27 | - uses: actions/setup-node@v4
28 | with:
29 | node-version-file: .nvmrc
30 | cache: npm
31 | - run: npm ci
32 | - run: npm test
33 | lint:
34 | name: 🧹 Lint
35 | runs-on: ubuntu-latest
36 | permissions:
37 | contents: read
38 | pull-requests: write
39 | steps:
40 | - uses: actions/checkout@v4
41 | with:
42 | fetch-depth: 0
43 | - uses: actions/setup-node@v4
44 | with:
45 | node-version-file: .nvmrc
46 | cache: npm
47 | - run: npm ci
48 | - uses: oxsecurity/megalinter/flavors/javascript@v7
49 | env:
50 | VALIDATE_ALL_CODEBASE: false
51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # See https://help.github.com/ignore-files/ for more about ignoring files.
3 |
4 | # dependencies
5 | node_modules
6 |
7 | # builds
8 | build
9 | dist
10 | .rpt2_cache
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 |
24 | .next
25 |
--------------------------------------------------------------------------------
/.megalinter.yml:
--------------------------------------------------------------------------------
1 | # Configuration file for MegaLinter
2 | #
3 | # See all available variables at https://megalinter.io/latest/config-file/ and in
4 | # linters documentation
5 | ---
6 | APPLY_FIXES: none
7 |
8 | DISABLE:
9 | - COPYPASTE
10 | - SPELL
11 |
12 | DISABLE_LINTERS:
13 | # We use stylelint for CSS and SCSS linting
14 | - CSS_SCSS_LINT
15 | # Disable in favour of eslint
16 | - JAVASCRIPT_STANDARD
17 | # We use dependabot for vulnerability monitoring and patching
18 | - REPOSITORY_GRYPE
19 | # Not needed in this repository
20 | - REPOSITORY_TRIVY
21 | # Disable in favour of eslint
22 | - TYPESCRIPT_STANDARD
23 | # Link check flags localhost links in the contributing docs
24 | - MARKDOWN_MARKDOWN_LINK_CHECK
25 | # V8R keeps giving false positives
26 | - YAML_V8R
27 |
28 | SHOW_ELAPSED_TIME: true
29 |
30 | FILEIO_REPORTER: false
31 |
32 | # Config paths
33 | CSS_STYLELINT_CONFIG_FILE: stylelint.config.js
34 | JAVASCRIPT_ES_CONFIG_FILE: .eslintrc
35 | TYPESCRIPT_ES_CONFIG_FILE: .eslintrc
36 |
37 | # Executable overrides
38 | CSS_STYLELINT_CLI_EXECUTABLE: ['./node_modules/.bin/stylelint']
39 |
40 | # Linters configuration
41 | REPOSITORY_GITLEAKS_DISABLE_ERRORS: true
42 | REPOSITORY_TRUFFLEHOG_ARGUMENTS: --exclude_paths .trufflehog-ignore
43 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | audit=false
2 | noFund=true
3 | preferOffline=true
4 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 16.18.1
2 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "jsxSingleQuote": true,
4 | "semi": false,
5 | "tabWidth": 2,
6 | "bracketSpacing": true,
7 | "jsxBracketSameLine": false,
8 | "arrowParens": "always",
9 | "trailingComma": "none"
10 | }
11 |
--------------------------------------------------------------------------------
/.trufflehog-ignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .git
3 | dist
4 | example/.next
5 | example/node_modules
6 | example/next-env.d.ts
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2024 Etch Software Limited
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # next-pagination
2 |
3 | > The best damn pagination component. For Next.js
4 |
5 | [](https://www.npmjs.com/package/@etchteam/next-pagination) [](https://standardjs.com)
6 |
7 | TL;DR Just show me the [DEMO](https://etchteam.github.io/next-pagination)
8 |
9 |
10 |
11 | ## Why use this pagination module?
12 |
13 | - **Accessible.** Semantic HTML and fully marked up with appropriate aria roles for assisted browsing.
14 | - **Usable.** The base CSS styles account for keyboard focus states and fat finger touch targets.
15 | - **Responsive.** Works on all devices.
16 | - **Themeable.** Make it look however you want.
17 | - **Self contained.** There's only one required prop to get going. The rest of the logic is handled for you.
18 | - **Works with Next.** Integrated with the Next.js router.
19 |
20 | ## Install
21 |
22 | ```bash
23 | npm install --save @etchteam/next-pagination
24 | ```
25 |
26 | ## Usage
27 | This component is fairly self contained. You will need to pass the **total number of potential results** in order to calculate the number of pages to show.
28 |
29 | ```jsx
30 | import React, { Component } from 'react'
31 |
32 | import Pagination from '@etchteam/next-pagination'
33 |
34 | class Example extends Component {
35 | render() {
36 | return
37 | }
38 | }
39 | ```
40 |
41 | You will need to import the CSS, either in your `_app.js`, or in your Sass build.
42 |
43 | ```jsx
44 | import '@etchteam/next-pagination/dist/index.css'
45 | ```
46 |
47 | When used, the pagination component will reload the same route with added pagination query params.
48 |
49 | - `page` for the page number the user is on.
50 | - `size` for the number of results per page.
51 |
52 | e.g. ?page=4&size=20
53 |
54 | The **default page** is 1. The **default size** is 20.
55 |
56 | You'll need to load the actual data from your API yourself. We're only here for the front-end!
57 |
58 | ## Props
59 |
60 | | Name | Type | Description |
61 | | ------------------------ | ---------- | ----------------------------------------- |
62 | | `total` | `Number` | **Required.** The total number of pages. |
63 | | `theme` | `Object` | A CSS modules style object. |
64 | | `sizes` | `Array` | An array of page size numbers |
65 | | `perPageText` | `String` | Label for the page size dropdown |
66 | | `setPageSizeText` | `String` | Label for the invisible page size button |
67 | | `linkProps` | `Object` | Extra props to pass to the next.js links |
68 |
69 | ## Theming
70 | Next.js natively supports **CSS modules**, so this component supports injecting CSS module styles.
71 |
72 | Import the styles as you would for a normal component, but pass them as props.
73 |
74 | ```jsx
75 | [...]
76 | import styles from '/my/path/to/styles.module.css'
77 |
78 | class Example extends Component {
79 | render() {
80 | return
81 | }
82 | }
83 | ```
84 |
85 | The theme uses BEM class naming with the base class `next-pagination`. The file `/src/index.module.scss` should give you a solid idea of what's needed.
86 |
87 | ## Contribute
88 |
89 | This package was created with [create-react-library](https://github.com/transitive-bullshit/create-react-library#readme).
90 |
91 | ### Setup
92 |
93 | To get set up you'll need to run `npm install && cd example && npm install`
94 |
95 | ## Development
96 |
97 | In the root folder, run `npm run start`
98 | **At the same time**, in the example folder, run `npm run dev`
99 | Then head over to `localhost:3000` to see the example running.
100 |
101 | ## Deploy the example
102 |
103 | In the root folder run `npm run deploy` to deploy the example to github pages on the `gh-pages` branch of your repo.
104 |
105 | ## Publish to npm
106 |
107 | Feeling confident? Run `npm publish` to send the latest version to npm.
108 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | We only support the [latest version](https://www.npmjs.com/package/@etchteam/next-pagination/v/latest) of this package.
6 |
7 | ## Reporting a Code Vulnerability
8 |
9 | Please report suspected security vulnerabilities to security@etch.co, with a working proof of concept.
10 |
11 | We’ll try to respond within two working days (we work Monday to Friday, so if you report something on Friday, you probably won’t hear back until Monday or Tuesday).
12 |
13 | Once we’ve confirmed the vulnerability, we’ll get a fix out as soon as possible, and keep you updated throughout.
14 |
15 | ## Reporting a Vulnerable Package
16 |
17 | If you have a concern about a package that we’re using, and there isn’t an open pull request or issue, then please open one!
18 |
19 | We try to stay on top of package updates, but we always welcome extra help.
20 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | This example was bootstrapped with [Next.js](https://nextjs.org/).
2 |
3 | It is linked to the next-pagination package in the parent directory for development purposes.
4 |
5 | You can run `npm install` and then `npm dev` to test your package.
6 |
--------------------------------------------------------------------------------
/example/next.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-var-requires */
2 | const withSourceMaps = require('@zeit/next-source-maps')()
3 |
4 | const isProd = (process.env.NODE_ENV || 'production') === 'production'
5 |
6 | module.exports = withSourceMaps({
7 | assetPrefix: isProd ? '/next-pagination' : undefined,
8 | basePath: isProd ? '/next-pagination' : undefined
9 | })
10 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-pagination-example",
3 | "homepage": "https://etchteam.github.io/next-pagination",
4 | "version": "0.0.0",
5 | "private": true,
6 | "dependencies": {
7 | "@zeit/next-source-maps": "0.0.4-canary.1",
8 | "next": "^13.5.4",
9 | "@etchteam/next-pagination": "file:..",
10 | "node-sass": "9.0.0",
11 | "react": "file:../node_modules/react",
12 | "react-dom": "file:../node_modules/react-dom"
13 | },
14 | "scripts": {
15 | "dev": "next",
16 | "build": "next build && next export -o build",
17 | "start": "next start"
18 | },
19 | "browserslist": [
20 | ">0.2%",
21 | "not dead",
22 | "not ie <= 11",
23 | "not op_mini all"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/example/pages/[dynamic].js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Pagination from '@etchteam/next-pagination/dist'
3 |
4 | export default function Dynamic() {
5 | return (
6 |
7 |
Dynamic Pagination
8 |
9 | This page demonstrates pagination working with dynamic urls. Feel free
10 | to change the url to '/whatever-you-like' and see that the pagination
11 | retains the url.
12 |