Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .eslintignore

This file was deleted.

28 changes: 0 additions & 28 deletions .eslintrc

This file was deleted.

39 changes: 30 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,67 @@ on:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions: read-all
permissions: {}
jobs:
build:
name: 🔨 Build
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
cache: npm
- run: npm ci
- run: npm ci --no-scripts
- run: npm run build
test:
name: 🧪 Test
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
cache: npm
- run: npm ci --no-scripts
- run: npm test
example:
name: 🖼️ Example build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm
cache-dependency-path: |
package-lock.json
example/package-lock.json
- run: npm ci
- run: npm test
- run: npm run build
- run: npm ci --prefix example
- run: npm run build --prefix example
- run: test -f example/build/index.html
lint:
name: 🧹 Lint
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: actions/setup-node@v4
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: .nvmrc
cache: npm
- run: npm ci
- uses: oxsecurity/megalinter/flavors/javascript@v7
- run: npm ci --no-scripts
- uses: oxsecurity/megalinter/flavors/javascript@8fbdead70d1409964ab3d5afa885e18ee85388bb # v9.4.0
env:
VALIDATE_ALL_CODEBASE: false
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3 changes: 1 addition & 2 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
audit=false
noFund=true
preferOffline=true
fund=false
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
16.18.1
24
3 changes: 3 additions & 0 deletions .stylelintrc.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
extends: ['@etchteam/stylelint-config']
}
71 changes: 61 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,55 @@ You'll need to load the actual data from your API yourself. We're only here for

| Name | Type | Description |
| ------------------------ | ---------- | ----------------------------------------- |
| `total` | `Number` | **Required.** The total number of pages. |
| `theme` | `Object` | A CSS modules style object. |
| `sizes` | `Array` | An array of page size numbers |
| `perPageText` | `String` | Label for the page size dropdown |
| `setPageSizeText` | `String` | Label for the invisible page size button |
| `linkProps` | `Object` | Extra props to pass to the next.js links |
| `total` | `Number` | **Required.** The total number of pages. |
| `theme` | `Object` | A CSS modules style object. |
| `sizes` | `Array` | An array of page size numbers |
| `perPageText` | `String` | Label for the page size dropdown |
| `setPageSizeText` | `String` | Label for the invisible page size button |
| `linkProps` | `Object` | Extra props to pass to the link component |
| `linkComponent` | `Component` | Custom link component. Defaults to `next/link`. Receives `href` + a legacy-behaviour anchor child. |

## Theming
Next.js natively supports **CSS modules**, so this component supports injecting CSS module styles.

Import the styles as you would for a normal component, but pass them as props.
### CSS custom properties (recommended)

The component exposes every theme value as a CSS custom property scoped to `.next-pagination`. Override any of them in your own stylesheet:

```css
.my-container .next-pagination {
--next-pagination-interactive-color: hotpink;
--next-pagination-border-radius: 8px;
}
```

Available variables:

```
--next-pagination-interactive-color
--next-pagination-spacing-vertical
--next-pagination-spacing-horizontal
--next-pagination-spacing-vertical-sm
--next-pagination-spacing-horizontal-sm
--next-pagination-border-width
--next-pagination-border-radius
--next-pagination-line-height
--next-pagination-item-background
--next-pagination-item-background-current
--next-pagination-item-background-disabled
--next-pagination-item-color
--next-pagination-item-color-current
--next-pagination-item-color-disabled
--next-pagination-item-border-color
--next-pagination-select-background
--next-pagination-select-border-color
--next-pagination-select-border-color-hover
```

### Full class-name override

For deeper customisation, pass a CSS modules style object via the `theme` prop:

```jsx
[...]
import styles from '/my/path/to/styles.module.css'

class Example extends Component {
Expand All @@ -82,7 +117,23 @@ class Example extends Component {
}
```

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.
The theme uses BEM class naming with the base class `next-pagination`. The file `/src/index.module.css` shows the full class list.

## Custom link component

By default the component renders navigation links with `next/link`. If you need to wrap or replace it (e.g. to add a custom prefetch strategy, swap in an app-router variant, or inject a shared analytics wrapper), pass your own via `linkComponent`:

```jsx
import NextLink from 'next/link'

const TrackedLink = (props) => (
<NextLink {...props} onClick={() => track('pagination')} />
)

<Pagination total={1000} linkComponent={TrackedLink} />
```

The component must accept `href`, `prefetch`, `passHref`, `legacyBehavior`, and a single anchor child.

## Contribute

Expand Down
27 changes: 27 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import nextjs from '@etchteam/eslint-config/nextjs'
import globals from 'globals'

export default [
{
ignores: [
'dist/**',
'example/.next/**',
'example/build/**',
'**/*.{yml,yaml}'
]
},
...nextjs,
{
files: ['**/*.cjs'],
languageOptions: {
sourceType: 'commonjs',
globals: globals.node
}
},
{
files: ['example/next.config.mjs'],
languageOptions: {
globals: globals.node
}
}
]
5 changes: 2 additions & 3 deletions example/next.config.js → example/next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const withSourceMaps = require('@zeit/next-source-maps')()
import withSourceMaps from '@zeit/next-source-maps'

const isProd = (process.env.NODE_ENV || 'production') === 'production'

module.exports = withSourceMaps({
export default withSourceMaps()({
assetPrefix: isProd ? '/next-pagination' : undefined,
basePath: isProd ? '/next-pagination' : undefined
})
Loading
Loading