├── .github └── FUNDING.yml ├── .gitignore ├── tsconfig.json ├── package.json ├── rollup.config.ts ├── LICENSE.md ├── src └── index.ts └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [lepikhinb] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ESNext", "DOM"], 7 | "moduleResolution": "Node", 8 | "strict": true, 9 | "sourceMap": true, 10 | "resolveJsonModule": true, 11 | "isolatedModules": true, 12 | "esModuleInterop": true, 13 | "noEmit": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "noImplicitReturns": true, 17 | "skipLibCheck": true 18 | }, 19 | "include": ["src"] 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "momentum-paginator", 3 | "version": "1.0.7", 4 | "files": [ 5 | "dist" 6 | ], 7 | "main": "dist/index.js", 8 | "module": "dist/index.mjs", 9 | "typings": "dist/index.d.ts", 10 | "scripts": { 11 | "build": "rollup -c" 12 | }, 13 | "description": "Headless paginator for Laravel resources", 14 | "author": "Boris Lepikhin", 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/lepikhinb/momentum-paginator.git" 18 | }, 19 | "homepage": "https://github.com/lepikhinb/momentum-paginator#readme", 20 | "license": "MIT", 21 | "devDependencies": { 22 | "@types/node": "^17.0.41", 23 | "esbuild": "^0.14.43", 24 | "esno": "^0.16.3", 25 | "rollup": "^2.75.6", 26 | "rollup-plugin-dts": "^4.2.2", 27 | "rollup-plugin-esbuild": "^4.9.1", 28 | "typescript": "^4.5.4" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rollup.config.ts: -------------------------------------------------------------------------------- 1 | import dts from 'rollup-plugin-dts' 2 | import esbuild from 'rollup-plugin-esbuild' 3 | 4 | const name = require('./package.json').main.replace(/\.js$/, '') 5 | 6 | const bundle = config => ({ 7 | ...config, 8 | input: 'src/index.ts', 9 | external: id => !/^[./]/.test(id), 10 | }) 11 | 12 | export default [ 13 | bundle({ 14 | plugins: [esbuild()], 15 | output: [ 16 | { 17 | file: `${name}.js`, 18 | format: 'cjs', 19 | sourcemap: true, 20 | }, 21 | { 22 | file: `${name}.mjs`, 23 | format: 'es', 24 | sourcemap: true, 25 | }, 26 | ], 27 | }), 28 | bundle({ 29 | plugins: [dts()], 30 | output: { 31 | file: `${name}.d.ts`, 32 | format: 'es', 33 | }, 34 | }), 35 | ] -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Boris Lepikhin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | interface Paginator { 3 | data: T[]; 4 | meta?: PaginatorMeta; 5 | links?: PaginatorLink[]; 6 | } 7 | } 8 | 9 | export interface PaginatorLink { 10 | url: string | null | undefined; 11 | label: string; 12 | active: boolean; 13 | } 14 | 15 | export interface PaginatorItem { 16 | url: string | null | undefined; 17 | label: string; 18 | isPage: boolean; 19 | isActive: boolean; 20 | isPrevious: boolean; 21 | isNext: boolean; 22 | isCurrent: boolean; 23 | isSeparator: boolean; 24 | } 25 | 26 | export interface PaginatorMeta { 27 | current_page: number; 28 | first_page_url: string; 29 | from: number | null; 30 | last_page: number; 31 | last_page_url: string; 32 | next_page_url: string | null | undefined; 33 | path: string; 34 | per_page: number; 35 | prev_page_url: string | null | undefined; 36 | to: number | null; 37 | total: number; 38 | links?: PaginatorLink[]; 39 | } 40 | 41 | export const usePaginator = (data: Paginator | PaginatorMeta) => { 42 | const meta = (data as Paginator).meta ?? (data as PaginatorMeta); 43 | 44 | const links = (meta.links ?? data.links!).map((link) => { 45 | return { 46 | ...link, 47 | url: link.url ? decodeURIComponent(link.url!) : null, 48 | }; 49 | }); 50 | 51 | const items = links.map((link, index) => { 52 | return { 53 | url: link.url, 54 | label: link.label, 55 | isPage: !isNaN(+link.label), 56 | isPrevious: index === 0, 57 | isNext: index === links.length - 1, 58 | isCurrent: link.active, 59 | isSeparator: link.label == "...", 60 | isActive: !!link.url && !link.active, 61 | }; 62 | }) as PaginatorItem[]; 63 | 64 | const pages: PaginatorItem[] = items.filter( 65 | (item) => item.isPage || item.isSeparator 66 | ); 67 | 68 | const current = items.find((item) => item.isCurrent); 69 | const previous = items.find((item) => item.isPrevious)!; 70 | const next = items.find((item) => item.isNext)!; 71 | 72 | const first = { 73 | ...items[1], 74 | isActive: items[1].url !== current?.url, 75 | label: "«", 76 | }; 77 | 78 | const last = { 79 | ...items[items.length - 1], 80 | isActive: items[items.length - 1].url !== current?.url, 81 | label: "»", 82 | }; 83 | 84 | const from = meta.from; 85 | const to = meta.to; 86 | const total = meta.total; 87 | const itemsPerPage = meta.per_page; 88 | 89 | return { 90 | pages, 91 | items, 92 | previous, 93 | next, 94 | first, 95 | last, 96 | total, 97 | from, 98 | to, 99 | itemsPerPage, 100 | }; 101 | }; 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Momentum Paginator 2 | 3 | Momentum Paginator is a framework-agnostic headless wrapper around Laravel Pagination [meta data](https://laravel.com/docs/9.x/pagination#converting-results-to-json). It supports all basic pagination, Laravel Resources and third-party solutions, such as [laravel-data](https://spatie.be/docs/laravel-data/v1/as-a-resource/from-data-to-resource). 4 | 5 | The package helps you build reusable pagination components with a simple API. 6 | 7 | ## Installation 8 | 9 | You can install the package via npm or yarn: 10 | 11 | ```bash 12 | npm i momentum-paginator 13 | # or 14 | yarn add momentum-paginator 15 | ``` 16 | 17 | ## Usage 18 | 19 | Import the package, and init the paginator by passing paginated data you receive from backend. 20 | 21 | ```typescript 22 | import { usePaginator } from "momentum-paginator"; 23 | 24 | const paginator = usePaginator(users); 25 | // or 26 | const { from, to, total, previous, next, pages } = usePaginator(users); 27 | ``` 28 | 29 | ### Basic example 30 | 31 | ```vue 32 | 35 | ``` 36 | 37 | ### Advanced example (Vue 3) 38 | 39 | ```vue 40 | 47 | 48 | 86 | ``` 87 | 88 | ## Types 89 | 90 | ### Properties 91 | 92 | | name | type | description | 93 | | -------- | ------ | ------------------------------------------------------ | 94 | | items | Page[] | All page items, including `previous` and `next` | 95 | | pages | Page[] | Reduced list of pages, excluding `previous` and `next` | 96 | | previous | Page | Previous page | 97 | | next | Page | Next page | 98 | | first | Page | First page | 99 | | last | Page | Last page | 100 | | total | number | Total amount of results available | 101 | | from | number | Starting number of the current results | 102 | | to | number | Ending number of the current results | 103 | 104 | ### Page instance 105 | 106 | | name | type | description | 107 | | ----------- | ------- | --------------------------------------------------------------------------------- | 108 | | url | string | URL of the page | 109 | | label | string | Text label of the item (_page number, separator, previous and next page markers_) | 110 | | isActive | boolean | Indicates if the page is available for navigation | 111 | | isCurrent | boolean | Indicates if the page is the current one. | 112 | | isSeparator | boolean | Indicates if the item is a separator | 113 | 114 | ## Advanced Inertia 115 | 116 | [](https://advanced-inertia.com) 117 | 118 | Take your Inertia.js skills to the next level with my book [Advanced Inertia](https://advanced-inertia.com/). 119 | Learn advanced concepts and make apps with Laravel and Inertia.js a breeze to build and maintain. 120 | 121 | ## Momentum 122 | 123 | Momentum is a set of packages designed to improve your experience building Inertia-powered apps. 124 | 125 | - [Modal](https://github.com/lepikhinb/momentum-modal) — Build dynamic modal dialogs for Inertia apps 126 | - [Preflight](https://github.com/lepikhinb/momentum-preflight) — Realtime backend-driven validation for Inertia apps 127 | - [Paginator](https://github.com/lepikhinb/momentum-paginator) — Headless wrapper around Laravel Pagination 128 | - [Trail](https://github.com/lepikhinb/momentum-trail) — Frontend package to use Laravel routes with Inertia 129 | - [Lock](https://github.com/lepikhinb/momentum-lock) — Frontend package to use Laravel permissions with Inertia 130 | - [Layout](https://github.com/lepikhinb/momentum-layout) — Persistent layouts for Vue 3 apps 131 | - [Vite Plugin Watch](https://github.com/lepikhinb/vite-plugin-watch) — Vite plugin to run shell commands on file changes 132 | 133 | ## Credits 134 | 135 | - [Boris Lepikhin](https://twitter.com/lepikhinb) 136 | - [All Contributors](../../contributors) 137 | 138 | ## License 139 | 140 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 141 | --------------------------------------------------------------------------------