master 674c9da0074e cached
22 files
65.7 KB
15.5k tokens
1 requests
Download .txt
Repository: peshanghiwa/vue-awesome-paginate
Branch: master
Commit: 674c9da0074e
Files: 22
Total size: 65.7 KB

Directory structure:
gitextract_zilk4tla/

├── .gitignore
├── .prettierrc
├── .vscode/
│   └── extensions.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── index.html
├── package.json
├── src/
│   ├── App.vue
│   ├── VueAwesomePaginatePlugin.ts
│   ├── components/
│   │   ├── index.ts
│   │   └── vue-awesome-paginate.vue
│   ├── env.d.ts
│   └── main.ts
├── test/
│   ├── breakpoint-buttons.test.ts
│   ├── first-last-buttons.test.ts
│   ├── jump-buttons.test.ts
│   ├── navigation-buttons.test.ts
│   └── numbers-buttons.test.ts
├── tsconfig.json
├── tsconfig.vite-config.json
└── vite.config.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

================================================
FILE: .prettierrc
================================================
{
  "tabWidth": 2,
  "semi": true,
  "singleQuote": false
}


================================================
FILE: .vscode/extensions.json
================================================
{
  "recommendations": ["Vue.volar"]
}


================================================
FILE: CHANGELOG.md
================================================
- 1.2
  - Created @click event handler for the component
  - Added warning to replace onClick prop with @click event handler
  - Added warning that onClick prop will be deprecated in the next release
- 1.1.46
  - Fixed breaking issue with the component build
- 1.1.45 (This Version breaks DO NOT DOWNLOAD IT)
- 1.1.4
  - Added changelog file to the repository
  - Fixed Bugs
- 1.1.3
  - BREAKING: (current-page prop is replaced with v-model)
  - added new slots to docs
  - updated documentation
- 1.1.2
  - updated documentation
- 1.1.0
  - fixed typo in documentation
  - updated tsc package version to 1.0.9
  - fixed reactivity bug
- 1.0.5
  - fixed first and last button disappearing bug
- 1.0.4
  - added click handler to example
  - updated component directory
- fixed image issues in readme.markdown
  - 1.0.3
  - removed console.log
  - added documentation for ending buttons
  - added ending buttons
  - new vite configurations
  - new typescript configurations
  - updated folder structure
  - updated package dependecies
- 1.0.23
  - corrected name issue on markdown title
- 1.0.22
  - added new keywords
- 1.0.2
  - reverted back package.ts to indxe.ts
  - removed comments
  - added specific typings to some of the props
  - updated readme
- 1.0.1
  - updated tests directory
  - updated style for the component container
  - number buttons e2e tests
  - breakpoint buttons tests
  - first and lat button test
  - created testings for navigation buttons
  - cleanup
  - replaced js with ts for test file
  - added e2e tests for jump buttons
  - cleanup
  - configured typescript declaration for build time
- 1.0.0
  - totalItems updating issue fixed
- 0.0.11
  - added classes for disabled buttons
- 0.0.10
  - added component disabling feature
  - developer experience improvements
  - Create .prettierrc
- 0.0.9
  - updated documentation for type attribute
  - enabled link type attribute
  - Update .gitignore
- 0.0.8
  - Update README.md
- 0.0.7
  - Update README.md
- 0.0.6
  - Update README.md
  - Added Documentations
  - commenting unused codes in production
  - fixing naming convention issues
  - breakpoint disabling bug fix
  - code cleanup
  - updated module configs
  - MIT LICENSE
- 0.0.4
  - fixed types declaration issue
- 0.0.1
  - ts config updates
  - initial commit


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2016 Awe

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:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

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.


================================================
FILE: README.md
================================================
# Vue Awesome Paginate

#### _The Awesome Vue.js 3 Pagination Library_

<img  src="https://i.postimg.cc/kgTFryfP/header.gif"  alt="vue-wesome-paginate">

[![peshanghiwa - vue-awesome-paginate](https://img.shields.io/static/v1?label=peshanghiwa&message=vue-awesome-paginate&color=yellow&logo=github)](https://github.com/peshanghiwa/vue-awesome-paginate "Go to GitHub repo")

[![npm version](https://img.shields.io/npm/v/vue-awesome-paginate.svg)](http://badge.fury.io/js/vue-awesome-paginate) [![npm downloads](https://img.shields.io/npm/dm/vue-awesome-paginate.svg)](http://badge.fury.io/js/vue-awesome-paginate) [![License](https://img.shields.io/badge/License-MIT-blue)](https://github.com/peshanghiwa/vue-awesome-paginate/blob/main/LICENSE)

Vue Awesome Paginate is a modern and powerfull vue js pagination library with a large set of various pagination components that are flexible, very lightweight, SEO friendly, customizable with pure CSS and very easy to use.

## Key Features

- All pagination functionalities are built in to the package with 0 dependants.

- Various different types of pagination components that you can enable or disable according to your needs, and what suits your website best.

- Complete customization support for every component using pure CSS.

- Complete RTL support.

- Search Engine Optimization friendly.

- Different localizations support.

- Package is built with typescript and vite with complete support for vue.js (3x) and nuxt.js (3.x)

&nbsp;

# Table of Contents

- [**_Demo_**](#demo)

- [**_Requirements_**](#requirements)

- [**_Installation_**](#installation)

- [**_Vue.js_**](#vuejs)

- [**_Nuxt.js_**](#nuxtjs)

- [**_Usage_**](#usage)

- [**_API_**](#api)

- [**_Component Attributes_**](#Component-Attributes)

- [**_Class Name Attributes_**](#Class-Name-Attributes)

- [**_Slot Names_**](#Slot-Names)

- [**_Events_**](#Events)

- [**_Author_**](#author)

- [**_License_**](#license)

&nbsp;

## Demo

This is a simple [**_Demo_**](https://codesandbox.io/s/vue-awesome-paginate-demo-gcg21i) environment for the package where you can use and test the package.

## Requirements

This package supports both vue.js and nuxt.js, you are required to use one of these versions:

- Vue.js 3.x

- Nuxt.js 3.x

&nbsp;

## Installation

To use the package you must first add the it to your dependencies in your project.

```bash

$  npm  i  vue-awesome-paginate

```

Then you have to register the package in your project as well as import a necessary css file that comes with the package.

### Vue.js

main.js

```javascript
import { createApp } from "vue";

import App from "./App.vue";

// import the package

import VueAwesomePaginate from "vue-awesome-paginate";

// import the necessary css file

import "vue-awesome-paginate/dist/style.css";

// Register the package

createApp(App).use(VueAwesomePaginate).mount("#app");
```

### Nuxt.js

plugins/vue-awesome-paginate.js

```javascript
// import the package

import VueAwesomePaginate from "vue-awesome-paginate";

// import the necessary css file

import "vue-awesome-paginate/dist/style.css";

// Register the package

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(VueAwesomePaginate);
});
```

&nbsp;

## Usage

A complete vue-awesome-paginate component example with some custom CSS customization would be like this:

```html
<script setup lang="ts">
  import { ref } from "vue";

  const onClickHandler = (page: number) => {
    console.log(page);
  };

  const currentPage = ref(1);
</script>

<template>
  <vue-awesome-paginate
    :total-items="50"
    :items-per-page="5"
    :max-pages-shown="5"
    v-model="currentPage"
    @click="onClickHandler"
  />
</template>

<style>
  .pagination-container {
    display: flex;

    column-gap: 10px;
  }

  .paginate-buttons {
    height: 40px;

    width: 40px;

    border-radius: 20px;

    cursor: pointer;

    background-color: rgb(242, 242, 242);

    border: 1px solid rgb(217, 217, 217);

    color: black;
  }

  .paginate-buttons:hover {
    background-color: #d8d8d8;
  }

  .active-page {
    background-color: #3498db;

    border: 1px solid #3498db;

    color: white;
  }

  .active-page:hover {
    background-color: #2988c8;
  }
</style>
```

##### Result of the above code:

<img  src="https://i.postimg.cc/cC6MLtH5/1.png"  width="500" />

&nbsp;

&nbsp;

&nbsp;

&nbsp;

## Required Attributes

Total required attributes to build a full pagination for your website is only two attributes, the component will handle all the other functionalities and attributes by default

as simple as this example:

```html
<vue-awesome-paginate :total-items="200" v-model="currentPage" />
```

##### Result of the above code:

<img  src="https://i.postimg.cc/76JSv8Qp/2.png"  width="500" />

&nbsp;

&nbsp;

&nbsp;

&nbsp;

## Configurations

You have total control over your pagination component, you can configure every element's appearence, number and behavior.

Example: you can set items per single page, maximum pagination buttons to show and a click event handler.

```html
<vue-awesome-paginate
  :total-items="50"
  v-model="currentPage"
  :items-per-page="5"
  :max-pages-shown="5"
  @click="onClickHandler"
/>
```

##### Result of the above code:

<img  src="https://i.postimg.cc/wM6xXDJ0/3.png"  width="500" />

&nbsp;

&nbsp;

&nbsp;

&nbsp;

## (Show/Hide) or (Enable/Disable) breakpoint buttons

Breakpoint buttons are clickable and shown by default, if you click on them you will get a jump of max-pages-shown / 2 in the pagination

You can Disable/Enable or Hide/Show them through attributes

```html
<!-- Hide Breakpoint Buttons -->

<vue-awesome-paginate
  :total-items="50"
  v-model="currentPage"
  :items-per-page="5"
  :max-pages-shown="5"
  :show-breakpoint-buttons="false"
  @click="onClickHandler"
/>

<!-- Disable Breakpoint Buttons -->

<vue-awesome-paginate
  :total-items="50"
  v-model="currentPage"
  :items-per-page="5"
  :max-pages-shown="5"
  @click="onClickHandler"
  :disable-breakpoint-buttons="true"
/>
```

&nbsp;

&nbsp;

&nbsp;

## Show Ending Buttons (First and Last Page Buttons)

You can hide/show Ending buttons to be able to navigate to first and last page of the pagination component

```html
<!-- Hide the Prev/Next buttons permanently -->

<vue-awesome-paginate
  :total-items="50"
  v-model="currentPage"
  :items-per-page="5"
  :max-pages-shown="5"
  :show-ending-buttons="true"
  :show-breakpoint-buttons="false"
/>
```

##### Result of the above code:

<img  src="https://i.postimg.cc/7ZrsmXbH/4.png"  width="500" />

&nbsp;

&nbsp;

&nbsp;

&nbsp;

## Hide Prev/Next buttons

You can hide prev/next buttons in two ways

```html
<!-- Hide the Prev/Next buttons permanently -->

<vue-awesome-paginate
  :total-items="50"
  v-model="currentPage"
  :items-per-page="5"
  :max-pages-shown="5"
  @click="onClickHandler"
  :hide-prev-next="true"
/>

<!-- Hide the Prev button only when pagination is at the beginning and hide next button only when pagination reaches the end -->

<vue-awesome-paginate
  :total-items="50"
  v-model="currentPage"
  :items-per-page="5"
  :max-pages-shown="5"
  @click="onClickHandler"
  :hide-prev-next-when-ends="true"
/>
```

##### Result of the above code:

<img  src="https://i.postimg.cc/9Qv7GNfb/5.png"  width="500" >

&nbsp;

&nbsp;

&nbsp;

&nbsp;

## Change buttons content

You can change the content inside the prev/next buttons in two ways:

1- Pass a string to **prev-button-content** or **next-button-content** attributes

```html
<vue-awesome-paginate
  :total-items="50"
  v-model="currentPage"
  :items-per-page="5"
  :max-pages-shown="5"
  @click="onClickHandler"
  prev-button-content="<<<"
  next-button-content=">>>"
/>
```

##### Result of the above code:

<img  src="https://i.postimg.cc/tgxm5fN4/6.png"  width="500" />

&nbsp;

&nbsp;

2- Inject your own HTML content into the buttons through custom slots

```html
<vue-awesome-paginate
  :total-items="50"
  v-model="currentPage"
  :items-per-page="5"
  :max-pages-shown="5"
  @click="onClickHandler"
>
  <template #prev-button>
    <span>
      <img src="backward-arrow-icon.png" height="25" />
    </span>
  </template>

  <template #next-button>
    <span>
      <img src="forward-arrow-icon.png" height="25" />
    </span>
  </template>
</vue-awesome-paginate>
```

##### Result of the above code:

<img  src="https://i.postimg.cc/Pqj1gRkx/7.png"  width="500" />

&nbsp;

&nbsp;

&nbsp;

&nbsp;

## Custom Slots

**This 2nd method of injecting html through custom slots in to elements in the previous example is available for all the other controlling elements like breakpoint buttons and jump buttons etc...**

You can see all the slots in the slots table at API section

&nbsp;

&nbsp;

&nbsp;

&nbsp;

## Show Jump Buttons

Jump Buttons are extra layers on top of Prev/Next buttons, if you enable them they will appear at each ends of the component, you can customize and configure them just like any other elements of the component and if you click on them it will have the same behavior as clicking on breakppoint buttons which is jumping by (max-pages-show/2)

```html
<vue-awesome-paginate
  :total-items="50"
  v-model="currentPage"
  :items-per-page="5"
  :max-pages-shown="5"
  :show-breakpoint-buttons="false"
  :show-jump-buttons="true"
/>
```

##### Result of the above code:

<img  src="https://i.postimg.cc/7Pjhtt7T/8.png"  width="500" />

&nbsp;

&nbsp;

&nbsp;

&nbsp;

## Make the component SEO friendly

Pagination components can have a great impact on SEO, it's important to make your pagination elements links, so that when crawlers crawl your page, they will be able to find the pagination elements and extract the links from them.

In order to achive this you can replace the button elements with anchor tag elements by changing **type** attribute to "link" and specify a **linkUrl** attribute to tell crawlers and search engines where this pagination element is pointing to.

**linkUrl** attribute must be a string url to where the pagination element is pointing to, and the string must include \[page\] placeholder, which will be replaced with the actual page number.

example:

```html
<vue-awesome-paginate
  :total-items="50"
  v-model="currentPage"
  :items-per-page="5"
  :max-pages-shown="5"
  @click="onClickHandler"
  type="link"
  link-url="/blog/posts?page=[page]"
/>
```

**Note:** Changing buttons to anchor tags won't affect the functionality or the behavior of the component, it's just a way to make the component SEO friendly. you will still have to handle the navigation logic yourself in **on-click** event attribute.

&nbsp;

&nbsp;

&nbsp;

&nbsp;

## RTL and Locale Support

There are complete supports for RTL and different localizations without using any other 3rd party libraries

```html
<vue-awesome-paginate
  :total-items="50"
  v-model="currentPage"
  :items-per-page="5"
  :max-pages-shown="5"
  dir="rtl"
  locale="ar"
/>
```

##### Result of the above code:

<img  src="https://i.postimg.cc/d1kv8v5N/9.png"  width="500" />

&nbsp;

&nbsp;

&nbsp;

&nbsp;

## Custom Styles

By default pagination buttons have the default html styles, you can customize every element of the component through the default class names that are set for each element, or you can set your own class names for any element you want.

```html
<template>
  <vue-awesome-paginate
    :total-items="50"
    v-model="currentPage"
    :items-per-page="5"
    :max-pages-shown="5"
    paginate-buttons-class="btn"
    active-page-class="btn-active"
    back-button-class="back-btn"
    next-button-class="next-btn"
  />
</template>

<style>
  .btn {
    height: 40px;

    width: 40px;

    border: none;

    margin-inline: 5px;

    cursor: pointer;
  }

  .back-btn {
    background-color: red;
  }

  .next-btn {
    background-color: red;
  }

  .btn-active {
    background-color: blue;

    color: white;
  }
</style>
```

##### Result of the above code:

<img  src="https://i.postimg.cc/KzMS1fYd/10.png"  width="500" />

You don't necessarily need to set class names for the elements if you don't want to, you can just use their default class names that are available in the class names table in the API section.

**Important Note:** If the <style> tag of the parent component is scoped, you have to use the ::deep combinator in order to apply the styles to the elements of the component.

&nbsp;

&nbsp;

&nbsp;

&nbsp;

## API

### Component Attributes

Note that all the attributes in the table below can be written in both camel case and kebab case styles.

| Key                                                    | Description                                                                                                                                                     | Options              | Default  | Validations                                                                                                                                                 |
| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| totalItems                                             | Total Number of items that you want to paginate                                                                                                                 | Number               |          | Required                                                                                                                                                    |
| itemsPerPage                                           | Total Number of items that you explicitly want to show per one page                                                                                             | Number               | 10       | Must be greater than 0                                                                                                                                      |
| v-model                                                | Current active page                                                                                                                                             | Number               |          | Required and must be greater than 0                                                                                                                         |
| showEndingButtons                                      | Show First and Last page buttons on each endings of the pagination component                                                                                    | Boolean              | false    |                                                                                                                                                             |
| maxPagesShown                                          | Maximum pagination buttons (Number Buttons only) to be shown                                                                                                    | Number               | 5        | Must be greater than 0                                                                                                                                      |
| dir                                                    | Driection of the component (RTL Support)                                                                                                                        | "ltr" \| "rtl"       | "ltr"    | Must be one of either options                                                                                                                               |
| onClick (Deprecated, use @click event handler instead) | A function that runs when the user changes a page by clicking any of the elements of the component (Passing the new active page to the function as a parameter) | Function             | ()=>{}   |                                                                                                                                                             |
| type                                                   | HTML Element type of the pagination component                                                                                                                   | "button" \| "link"   | "button" | must be either a link or button                                                                                                                             |
| linkUrl                                                | The url string that the anchor tag is pointing to                                                                                                               | String               |          | required when type attribute is set to 'link', and must include "\[page\]" placeholder in order to be replaced with the actual page number during rendering |
| locale                                                 | Localization of the component (currently only Arabic, English and Persian locales are supported, more localization options will be added!                       | "en" \| "ar" \| "ir" | "en"     | Must be one of the available options)                                                                                                                       |
| prevButtonContent                                      | Content to be shown in the prev button                                                                                                                          | String \| Slot       | "<"      | Must be either a string or a custom slot                                                                                                                    |
| nextButtonContent                                      | Content to be shown in the prev button                                                                                                                          | String \| Slot       | ">"      | Must be either a string or a custom slot                                                                                                                    |
| hidePrevNext                                           | Hide the prev and next buttons permanently                                                                                                                      | Boolean              | false    |                                                                                                                                                             |
| hidePrevNextWhenEnds                                   | Hide the prev button when pagination is at the beginning and next button when the pagination is at the end                                                      | Boolean              | false    |                                                                                                                                                             |
| disablePagination                                      | Enable/Disable the whole component buttons                                                                                                                      | Boolean              | false    |                                                                                                                                                             |
| showBreakpointButtons                                  | Show/Hide the breakpoint buttons                                                                                                                                | Boolean              | true     |                                                                                                                                                             |

| disableBreakpointButtons | Enable/Disable the breakpoint buttons | Boolean | false | |
| startingBreakpointContent | Content to be shown in the starting breakpoint button | String \| Slot | "..." | Must be either a string or a custom slot |
| endingBreakpointButtonContent | Content to be shown in the ending breakpoint button | String \| Slot | "..." | Must be either a string or a custom slot |
| showJumpButtons | Show/Hide the jump buttons | Boolean | false | |
| backwardJumpButtonContent | Content to be shown in the backward jump button | String \| Slot | "<<" | Must be either a string or a custom slot |
| forwardJumpButtonContent | Content to be shown in the forward jump button | String \| Slot | ">>" | Must be either a string or a custom slot |
| firstPageContent | Content to be shown in the first page button | String \| Slot | "First" | Must be either a string or a custom slot |
| lastPageContent | Content to be shown in the last page button | String \| Slot | "Last" | Must be either a string or a custom slot |

&nbsp;

&nbsp;

&nbsp;

### Class Name Attributes

All the class names have a default value.

| Key                             | Description (Target)                                                                                                                             | Default                       |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------- |
| paginationContainerClass        | Styles for this class will be applied for the container of the whole compoent                                                                    | pagination-container          |
| paginateButtonsClass            | A global class name, styles for this class will be applied for all of the buttons inside the component                                           | paginate-buttons              |
| disabledPaginateButtonsClass    | A global class name, styles for this class will be applied for all of the buttons when disabled inside the component                             | disabled-paginate-buttons     |
| numberButtonsClass              | Styles for this class will be applied for all the number buttons                                                                                 | number-buttons                |
| activePageClass                 | Styles for this class will be applied for the current active page button                                                                         | active-page                   |
| firstPageButtonClass            | Styles for this class will be applied for the first page button                                                                                  | first-page-buton              |
| lastPageButtonClass             | Styles for this class will be applied for the last page button                                                                                   | last-page-buton               |
| backButtonClass                 | Styles for this class will be applied for the back button                                                                                        | back-button                   |
| nextButtonClass                 | Styles for this class will be applied for the next button                                                                                        | next-button                   |
| startingBreakpointButtonClass   | Styles for this class will be applied for the starting breakpoint button                                                                         | starting-breakpoint-button    |
| endingBreakpointButtonClass     | Styles for this class will be applied for the ending breakpoint button                                                                           | ending-breakpoint-button      |
| disabledBreakPointButtonClass   | Styles for this class will be applied for the breakpoint buttons when the whole pagination component is disbaled or the breakpoints are disabled | disabled-breakpoint-button    |
| backwardJumpButtonClass         | Styles for this class will be applied for the backward jump button                                                                               | backward-jump-button          |
| forwardJumpButtonClass          | Styles for this class will be applied for the forward jump button                                                                                | forward-jump-button           |
| firstButtonClass                | Styles for this class will be applied for the the very first button that shows when first break point button appears                             | first-button                  |
| lastButtonClass                 | Styles for this class will be applied for the the very last button that shows when last break point button appears                               | first-button                  |
| disabledFirstButtonClass        | Styles for this class will be applied for the first button when disabled                                                                         | disabled-first-button         |
| disabledLastButtonClass         | Styles for this class will be applied for the last button when disabled                                                                          | disabled-last-button          |
| disabledBackwardJumpButtonClass | Styles for this class will be applied for the backward jump button when pagination is disabled                                                   | disabled-backward-jump-button |
| disabledBackButtonClass         | Styles for this class will be applied for the back button when pagination is disabled                                                            | disabled-back-button          |
| disabledNextButtonClass         | Styles for this class will be applied for the next button when pagination is disabled                                                            | disabled-next-button          |
| disabledForwardJumpButtonClass  | Styles for this class will be applied for the forward jump button when pagination is disabled                                                    | disabled-forward-jump-button  |

&nbsp;

&nbsp;

&nbsp;

### Slot Names

These slot names can be used for Vue Slots in order to inject custom html in to the target element

| Slot Name                  |           Target           |
| -------------------------- | :------------------------: |
| prev-button                |        Prev Button         |
| next-button                |        Next Button         |
| backward-jump-button       |    Backward Jump Button    |
| forward-jump-button        |    Forward Jump Button     |
| starting-breakpoint-button | Starting Breakpoint Button |
| ending-breakpoint-button   |  Ending Breakpoint Button  |
| first-page-button          |     First Page Button      |
| last-page-button           |      Last Page Button      |

### Events

| Event Name | Description                                                                                        | Parameters     |
| ---------- | -------------------------------------------------------------------------------------------------- | -------------- |
| click      | A function that runs when the user changes a page by clicking any of the elements of the component | (page: number) |

## Author

[Peshang Hiwa](https://github.com/peshanghiwa)

## License

[The MIT License](http://opensource.org/licenses/MIT)


================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>


================================================
FILE: package.json
================================================
{
  "name": "vue-awesome-paginate",
  "private": false,
  "type": "module",
  "main": "dist/index.cjs",
  "module": "dist/index.js",
  "exports": {
    ".": {
      "types": "./dist/VueAwesomePaginatePlugin.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs"
    },
    "./dist/style.css": "./dist/style.css"
  },
  "browser": {
    "./dist/style.css": "./dist/style.css"
  },
  "types": "dist/VueAwesomePaginatePlugin.d.ts",
  "version": "1.2.0",
  "description": "Modern Vue 3 Pagination Module",
  "files": [
    "dist"
  ],
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "test": "vitest",
    "preview": "vite preview"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/peshanghiwa/vue-awesome-paginate"
  },
  "license": "MIT",
  "keywords": [
    "vue-awesome-paginate",
    "vue",
    "paginate",
    "nuxt",
    "pagination",
    "vue-pagination",
    "vue awesome paginate",
    "nuxt.js 3",
    "vue.js 3",
    "vue pagination",
    "vue pagination component",
    "vue pagination module",
    "vue paginate",
    "vue pagination",
    "vue.js paginate",
    "vue.js pagination"
  ],
  "dependencies": {
    "vue": "^3.4.30"
  },
  "devDependencies": {
    "@types/node": "^18.0.0",
    "@vitejs/plugin-vue": "^2.3.4",
    "@vue/test-utils": "^2.0.2",
    "@vue/tsconfig": "^0.1.3",
    "happy-dom": "^6.0.4",
    "rollup-plugin-typescript2": "^0.31.2",
    "tslib": "^2.4.0",
    "typescript": "^4.5.4",
    "vite": "^2.9.9",
    "vitest": "^0.18.1",
    "vue-tsc": "^1.0.9"
  }
}


================================================
FILE: src/App.vue
================================================
<script setup lang="ts">
import { ref } from "vue";
import vueAwesomePaginate from "./components/vue-awesome-paginate.vue";

const currentPage = ref(1);

const clickHandler = (page: number) => {
  console.log(page);
};
</script>

<template>
  <vue-awesome-paginate
    :total-items="50"
    v-model="currentPage"
    :items-per-page="5"
    :max-pages-shown="5"
    @click="clickHandler"
  />
</template>

<style>
.pagination-container {
  display: flex;
  column-gap: 10px;
}
.paginate-buttons {
  height: 40px;
  width: 40px;
  border-radius: 20px;
  cursor: pointer;
  background-color: rgb(242, 242, 242);
  border: 1px solid rgb(217, 217, 217);
  color: black;
}
.paginate-buttons:hover {
  background-color: #d8d8d8;
}
.active-page {
  background-color: #3498db;
  border: 1px solid #3498db;
  color: white;
}
.active-page:hover {
  background-color: #2988c8;
}
</style>


================================================
FILE: src/VueAwesomePaginatePlugin.ts
================================================
// This is where the package installs.
import type { App } from "vue";
import { VueAwesomePaginate } from "./components";

export default {
  install: (app: App) => {
    app.component("VueAwesomePaginate", VueAwesomePaginate);
  },
};

export { VueAwesomePaginate };


================================================
FILE: src/components/index.ts
================================================
export { default as VueAwesomePaginate } from "./vue-awesome-paginate.vue";


================================================
FILE: src/components/vue-awesome-paginate.vue
================================================
<script setup lang="ts">
import { toRef, type PropType } from "vue";
import { computed } from "vue";

// -------------------- //
// ---> Properties <--- //
// -------------------- //
const props = defineProps({
  // Configuration props
  totalItems: {
    type: Number,
    required: true,
  },
  itemsPerPage: {
    type: Number,
    default: 10,
    validator: (value: number) => {
      if (value <= 0) {
        const message = "itemsPerPage attribute must be greater than 0.";
        console.error(message);
        throw new TypeError(message);
      }
      return true;
    },
  },
  currentPage: {
    type: Number,
    default: 1,
    validator: (value: number) => {
      const message = "currentPage attribute must be greater than 0.";
      if (value <= 0) {
        console.error(message);
        throw new TypeError(message);
      }
      return true;
    },
  },
  modelValue: {
    type: Number,
    required: true,
    validator: (value: number) => {
      const message = "v-model is required and must be greater than 0.";
      if (value <= 0) {
        console.error(message);
        throw new TypeError(message);
      }
      return true;
    },
  },
  maxPagesShown: {
    type: Number,
    default: 5,
    validator: (value: number) => {
      const message = "maxPagesShown attribute must be greater than 0.";
      if (value <= 0) {
        console.error(message);
        throw new TypeError(message);
      }
      return true;
    },
  },
  dir: {
    type: String as PropType<"ltr" | "rtl">,
    default: "ltr",
    validator: (value: string) => {
      const message = 'dir attribute must be either "ltr" or "rtl".';
      if (value !== "ltr" && value !== "rtl") {
        console.error(message);
        throw new TypeError(message);
      }
      return true;
    },
  },
  type: {
    type: String as PropType<"link" | "button">,
    default: "button",
    validator: (value: string) => {
      const validTypess = ["link", "button"];
      const message =
        "type attribute must be one of the following: " +
        validTypess.join(", ");
      if (validTypess.indexOf(value) === -1) {
        console.error(message);
        throw new TypeError(message);
      }
      return true;
    },
  },
  onClick: {
    type: Function,
    default: () => {},
  },
  locale: {
    type: String as PropType<"en" | "ar" | "ir">,
    default: "en",
    validator: (value: string) => {
      const validLocales = ["en", "ar", "ir"];
      const message =
        "locale attribute must be one of the following: " +
        validLocales.join(", ");
      if (validLocales.indexOf(value) === -1) {
        console.error(message);
        throw new TypeError(message);
      }
      return true;
    },
  },
  prevButtonContent: {
    type: String,
    default: "<",
  },
  nextButtonContent: {
    type: String,
    default: ">",
  },
  hidePrevNext: {
    type: Boolean,
    default: false,
  },
  hidePrevNextWhenEnds: {
    type: Boolean,
    default: false,
  },
  showBreakpointButtons: {
    type: Boolean,
    default: true,
  },
  disableBreakpointButtons: {
    type: Boolean,
    default: false,
  },
  startingBreakpointContent: {
    type: String,
    default: "...",
  },
  endingBreakpointButtonContent: {
    type: String,
    default: "...",
  },
  showJumpButtons: {
    type: Boolean,
    default: false,
  },
  linkUrl: {
    type: String,
    default: "#",
  },
  backwardJumpButtonContent: {
    type: String,
    default: "<<",
  },
  forwardJumpButtonContent: {
    type: String,
    default: ">>",
  },
  disablePagination: {
    type: Boolean,
    default: false,
  },
  showEndingButtons: {
    type: Boolean,
    default: false,
  },
  firstPageContent: {
    type: String,
    default: "First",
  },
  lastPageContent: {
    type: String,
    default: "Last",
  },

  // Class props
  backButtonClass: {
    type: String,
    default: "back-button",
  },
  nextButtonClass: {
    type: String,
    default: "next-button",
  },
  firstButtonClass: {
    type: String,
    default: "first-button",
  },
  lastButtonClass: {
    type: String,
    default: "last-button",
  },
  numberButtonsClass: {
    type: String,
    default: "number-buttons",
  },
  startingBreakpointButtonClass: {
    type: String,
    default: "starting-breakpoint-button",
  },
  endingBreakPointButtonClass: {
    type: String,
    default: "ending-breakpoint-button",
  },
  firstPageButtonClass: {
    type: String,
    default: "first-page-button",
  },
  lastPageButtonClass: {
    type: String,
    default: "last-page-button",
  },

  // use this selector above all the other selectors because of css specificity
  paginateButtonsClass: {
    type: String,
    default: "paginate-buttons",
  },
  disabledPaginateButtonsClass: {
    type: String,
    default: "disabled-paginate-buttons",
  },
  activePageClass: {
    type: String,
    default: "active-page",
  },
  paginationContainerClass: {
    type: String,
    default: "pagination-container",
  },
  disabledBreakPointButtonClass: {
    type: String,
    default: "disabled-breakpoint-button",
  },
  backwardJumpButtonClass: {
    type: String,
    default: "backward-jump-button",
  },
  forwardJumpButtonClass: {
    type: String,
    default: "forward-jump-button",
  },
  disabledBackwardJumpButtonClass: {
    type: String,
    default: "disabled-backward-jump-button",
  },
  disabledBackButtonClass: {
    type: String,
    default: "disabled-back-button",
  },
  disabledFirstButtonClass: {
    type: String,
    default: "disabled-first-button",
  },
  disabledLastButtonClass: {
    type: String,
    default: "disabled-last-button",
  },
  disabledNextButtonClass: {
    type: String,
    default: "disabled-next-button",
  },
  disabledForwardJumpButtonClass: {
    type: String,
    default: "disabled-forward-jump-button",
  },
});

if (props.currentPage && !props.modelValue) {
  throw new Error(
    "currentPage/current-page is now deprecated, use v-model instead to set the current page."
  );
}

if (!props.modelValue) {
  throw new TypeError(`v-model is required for the paginate component.`);
}

// -------------- //
// ---> Refs <--- //
// -------------- //
const currentPageRef = toRef(props, "modelValue");

// ---------------- //
// ---> Events <--- //
// ---------------- //
const emit = defineEmits(["update:modelValue", "click"]);

// ----------------- //
// ---> Methods <--- //
// ----------------- //
const onClickHandler = (number: number) => {
  // if number is equal to the current page, do nothing
  if (number === currentPageRef.value) return;

  // if number is greater than the total pages, do nothing
  if (number > totalPages.value) return;

  // if number is less than 1, do nothing
  if (number < 1) return;

  // if pagination is disabled, do nothing
  if (props.disablePagination) return;

  emit("update:modelValue", number);
  emit("click", number);
};

const NumbersLocale = (number: number) => {
  switch (props.locale) {
    case "en":
      return number;
    case "ar":
      return number.toLocaleString("ar-SA");
    case "ir":
      return number.toLocaleString("fa-IR");
    default:
      return number;
  }
};
const navigationHandler = (page: number) => {
  if (props.type !== "link") return "";
  return props.linkUrl.replace("[page]", page.toString());
};

// ----------------------------- //
// ---> Computed properties <--- //
// ----------------------------- //
//calculating total pages
const totalPages = computed(() =>
  Math.ceil(props.totalItems / props.itemsPerPage)
);
// Pagination logic
const paginate = computed(() => {
  let startPage: number, endPage: number;
  // if total pages are less than maximum pages to be displayed (maxPagesShown), then show all pages
  if (totalPages.value <= props.maxPagesShown) {
    startPage = 1;
    endPage = totalPages.value;
  } else {
    // total pages is more than maxPagesShown...
    // calculating start and end pages
    let maxPagesShownBeforeCurrentPage = Math.floor(props.maxPagesShown / 2);
    let maxPagesShownAfterCurrentPage = Math.ceil(props.maxPagesShown / 2) - 1;
    if (currentPageRef.value <= maxPagesShownBeforeCurrentPage) {
      // current page is at the start of the pagination
      startPage = 1;
      endPage = props.maxPagesShown;
    } else if (
      currentPageRef.value + maxPagesShownAfterCurrentPage >=
      totalPages.value
    ) {
      // current page is at the end of the pagination
      startPage = totalPages.value - props.maxPagesShown + 1;
      endPage = totalPages.value;
    } else {
      // current page is somewhere in the middle of the pagination
      startPage = currentPageRef.value - maxPagesShownBeforeCurrentPage;
      endPage = currentPageRef.value + maxPagesShownAfterCurrentPage;
    }
  }
  // create an array of pages to be displayed
  let pages = Array.from(Array(endPage + 1 - startPage).keys()).map(
    (i) => startPage + i
  );

  if (props.dir === "rtl") {
    pages = pages.reverse();
  }

  return {
    totalItems: props.totalItems,
    currentPage: currentPageRef.value,
    itemsPerPage: props.itemsPerPage,
    totalPages: totalPages,
    startPage: startPage,
    endPage: endPage,
    pages: pages,
  };
});
// rtl check
const isRtl = computed(() => props.dir === "rtl");

// ---------------------------------- //
// ---> Components If Conditions <--- //
// ---------------------------------- //
const backButtonIfCondition = computed(() => {
  if (isRtl.value)
    return (
      !props.hidePrevNextWhenEnds || currentPageRef.value !== totalPages.value
    );

  return !props.hidePrevNextWhenEnds || currentPageRef.value !== 1;
});
const nextButtonIfCondition = computed(() => {
  if (isRtl.value)
    return !props.hidePrevNextWhenEnds || currentPageRef.value !== 1;

  return (
    !props.hidePrevNextWhenEnds || currentPageRef.value !== totalPages.value
  );
});
const startingBreakPointButtonIfCondition = computed(() => {
  if (isRtl.value) {
    return paginate.value.pages[0] < totalPages.value - 1;
  }

  return paginate.value.pages[0] >= 3;
});
const endingBreakPointButtonIfCondition = computed(() => {
  if (isRtl.value) {
    return paginate.value.pages[paginate.value.pages.length - 1] >= 3;
  }

  return (
    paginate.value.pages[paginate.value.pages.length - 1] < totalPages.value - 1
  );
});
const firstButtonIfCondition = computed(() => {
  if (isRtl.value) {
    return paginate.value.pages[0] < totalPages.value;
  }

  return paginate.value.pages[0] >= 2;
});
const lastButtonIfCondition = computed(() => {
  if (isRtl.value) {
    return paginate.value.pages[paginate.value.pages.length - 1] >= 2;
  }

  return (
    paginate.value.pages[paginate.value.pages.length - 1] < totalPages.value
  );
});
const firstPageButtonIfCondition = computed(() => {
  if (currentPageRef.value === 1) return false;
  return true;
});
const lastPageButtonIfCondition = computed(() => {
  if (currentPageRef.value === totalPages.value) return false;
  return true;
});

// --------------------------- //
// ---> Validations Check <--- //
// --------------------------- //
// current page can't be greater than total pages
// if (currentPageRef.value > totalPages) {
//   console.log("currentPage must be less than or equal to totalPages.");
//   throw new TypeError(`currentPage must be less than or equal to totalPages.`);
// }

// if type attribute is link, then linkUrl attribute is required
if (props.type === "link" && props.linkUrl === "#") {
  console.error(`linkUrl attribute is required if type attribute is 'link'`);
  throw new TypeError(
    `linkUrl attribute is required if type attribute is 'link'`
  );
}

// if type attribute is link, then linkUrl string must contain "[page]"
if (props.type === "link" && !props.linkUrl.includes("[page]")) {
  console.error(`linkUrl attribute must contain '[page]' substring`);
  throw new TypeError(`linkUrl attribute must contain '[page]' substring`);
}
</script>

<template>
  <!-- If the type prop is 'button' following template will render -->
  <ul id="componentContainer" :class="paginationContainerClass">
    <!-- Go back to first page Button -->
    <li v-if="showEndingButtons && firstPageButtonIfCondition">
      <component
        :is="type === 'button' ? 'button' : 'a'"
        :href="navigationHandler(isRtl ? totalPages : 1)"
        @click.prevent="onClickHandler(isRtl ? totalPages : 1)"
        :class="[
          firstPageButtonClass,
          paginateButtonsClass,
          disablePagination ? disabledPaginateButtonsClass : '',
        ]"
        :disabled="disablePagination"
      >
        <slot name="first-page-button">
          {{ firstPageContent }}
        </slot>
      </component>
    </li>

    <!-- Backward Jump Button -->
    <li v-if="showJumpButtons && startingBreakPointButtonIfCondition">
      <component
        :is="type === 'button' ? 'button' : 'a'"
        :href="
          navigationHandler(
            isRtl
              ? currentPageRef + Math.ceil(maxPagesShown / 2)
              : currentPageRef - Math.ceil(maxPagesShown / 2)
          )
        "
        @click.prevent="
          onClickHandler(
            isRtl
              ? currentPageRef + Math.ceil(maxPagesShown / 2)
              : currentPageRef - Math.ceil(maxPagesShown / 2)
          )
        "
        :class="[
          backwardJumpButtonClass,
          paginateButtonsClass,
          disablePagination ? disabledPaginateButtonsClass : '',
          disablePagination ? disabledBackwardJumpButtonClass : '',
        ]"
        :disabled="disablePagination"
      >
        <slot name="backward-jump-button">
          {{ backwardJumpButtonContent }}
        </slot>
      </component>
    </li>

    <!-- Back Button -->
    <li v-if="!hidePrevNext && backButtonIfCondition">
      <component
        :is="type === 'button' ? 'button' : 'a'"
        :href="
          navigationHandler(isRtl ? currentPageRef + 1 : currentPageRef - 1)
        "
        @click.prevent="
          onClickHandler(isRtl ? currentPageRef + 1 : currentPageRef - 1)
        "
        :class="[
          backButtonClass,
          paginateButtonsClass,
          disablePagination ? disabledPaginateButtonsClass : '',
          disablePagination ? disabledBackButtonClass : '',
        ]"
        :disabled="disablePagination"
      >
        <slot name="prev-button">
          {{ prevButtonContent }}
        </slot>
      </component>
    </li>

    <!-- First Button before Starting Breakpoint Button -->
    <li v-if="showBreakpointButtons && firstButtonIfCondition">
      <component
        :is="type === 'button' ? 'button' : 'a'"
        :href="navigationHandler(isRtl ? totalPages : 1)"
        @click.prevent="onClickHandler(isRtl ? totalPages : 1)"
        :class="[
          firstButtonClass,
          paginateButtonsClass,
          disablePagination ? disabledPaginateButtonsClass : '',
          disablePagination ? disabledFirstButtonClass : '',
        ]"
        :disabled="disablePagination"
      >
        {{ isRtl ? NumbersLocale(totalPages) : NumbersLocale(1) }}
      </component>
    </li>

    <!-- Starting Breakpoint Button -->
    <li v-if="showBreakpointButtons && startingBreakPointButtonIfCondition">
      <component
        :is="type === 'button' ? 'button' : 'a'"
        :href="
          navigationHandler(
            disableBreakpointButtons
              ? currentPageRef
              : isRtl
              ? currentPageRef + Math.ceil(maxPagesShown / 2)
              : currentPageRef - Math.ceil(maxPagesShown / 2)
          )
        "
        @click.prevent="
          onClickHandler(
            disableBreakpointButtons
              ? currentPageRef
              : isRtl
              ? currentPageRef + Math.ceil(maxPagesShown / 2)
              : currentPageRef - Math.ceil(maxPagesShown / 2)
          )
        "
        :disabled="disableBreakpointButtons || disablePagination"
        :class="[
          startingBreakpointButtonClass,
          paginateButtonsClass,
          disableBreakpointButtons || disablePagination
            ? `${disabledPaginateButtonsClass} ${disabledBreakPointButtonClass}`
            : '',
        ]"
      >
        <slot name="starting-breakpoint-button">
          {{ startingBreakpointContent }}
        </slot>
      </component>
    </li>

    <!-- Numbers Buttons -->
    <li v-for="(page, index) in paginate.pages" :key="index">
      <component
        :is="type === 'button' ? 'button' : 'a'"
        :href="navigationHandler(page)"
        @click.prevent="() => onClickHandler(page)"
        :class="[
          paginateButtonsClass,
          numberButtonsClass,
          page === currentPageRef ? activePageClass : '',
          disablePagination ? disabledPaginateButtonsClass : '',
        ]"
        :disabled="disablePagination"
      >
        {{ NumbersLocale(page) }}
      </component>
    </li>

    <!-- Ending Breakpoint Button -->
    <li v-if="showBreakpointButtons && endingBreakPointButtonIfCondition">
      <component
        :is="type === 'button' ? 'button' : 'a'"
        :href="
          navigationHandler(
            disableBreakpointButtons
              ? currentPageRef
              : isRtl
              ? currentPageRef - Math.ceil(maxPagesShown / 2)
              : currentPageRef + Math.ceil(maxPagesShown / 2)
          )
        "
        @click.prevent="
          onClickHandler(
            disableBreakpointButtons
              ? currentPageRef
              : isRtl
              ? currentPageRef - Math.ceil(maxPagesShown / 2)
              : currentPageRef + Math.ceil(maxPagesShown / 2)
          )
        "
        :disabled="disableBreakpointButtons || disablePagination"
        :class="[
          endingBreakPointButtonClass,
          paginateButtonsClass,
          disableBreakpointButtons || disablePagination
            ? `${disabledPaginateButtonsClass} ${disabledBreakPointButtonClass}`
            : '',
        ]"
      >
        <slot name="ending-breakpoint-button">
          {{ endingBreakpointButtonContent }}
        </slot>
      </component>
    </li>

    <!-- Last Button after Ending Breakingpoint Button-->
    <li v-if="showBreakpointButtons && lastButtonIfCondition">
      <component
        :is="type === 'button' ? 'button' : 'a'"
        :href="navigationHandler(isRtl ? 1 : totalPages)"
        @click.prevent="onClickHandler(isRtl ? 1 : totalPages)"
        :class="[
          lastButtonClass,
          paginateButtonsClass,
          disablePagination ? disabledPaginateButtonsClass : '',
          disablePagination ? disabledLastButtonClass : '',
        ]"
        :disabled="disablePagination"
      >
        {{ isRtl ? NumbersLocale(1) : NumbersLocale(totalPages) }}
      </component>
    </li>

    <!-- Next Button -->
    <li v-if="!hidePrevNext && nextButtonIfCondition">
      <component
        :is="type === 'button' ? 'button' : 'a'"
        :href="
          navigationHandler(isRtl ? currentPageRef - 1 : currentPageRef + 1)
        "
        @click.prevent="
          onClickHandler(isRtl ? currentPageRef - 1 : currentPageRef + 1)
        "
        :class="[
          paginateButtonsClass,
          nextButtonClass,
          disablePagination ? disabledPaginateButtonsClass : '',
          disablePagination ? disabledNextButtonClass : '',
        ]"
        :disabled="disablePagination"
      >
        <slot name="next-button">
          {{ nextButtonContent }}
        </slot>
      </component>
    </li>

    <!-- Forward Jump Button -->
    <li v-if="showJumpButtons && endingBreakPointButtonIfCondition">
      <component
        :is="type === 'button' ? 'button' : 'a'"
        :href="
          navigationHandler(
            isRtl
              ? currentPageRef - Math.ceil(maxPagesShown / 2)
              : currentPageRef + Math.ceil(maxPagesShown / 2)
          )
        "
        @click.prevent="
          onClickHandler(
            isRtl
              ? currentPageRef - Math.ceil(maxPagesShown / 2)
              : currentPageRef + Math.ceil(maxPagesShown / 2)
          )
        "
        :class="[
          forwardJumpButtonClass,
          paginateButtonsClass,
          disablePagination ? disabledPaginateButtonsClass : '',
          disablePagination ? disabledForwardJumpButtonClass : '',
        ]"
        :disabled="disablePagination"
      >
        <slot name="forward-jump-button">
          {{ forwardJumpButtonContent }}
        </slot>
      </component>
    </li>

    <!-- Go forward to last page -->
    <li v-if="showEndingButtons && lastPageButtonIfCondition">
      <component
        :is="type === 'button' ? 'button' : 'a'"
        :href="navigationHandler(isRtl ? 1 : totalPages)"
        @click.prevent="onClickHandler(isRtl ? 1 : totalPages)"
        :class="[
          lastPageButtonClass,
          paginateButtonsClass,
          disablePagination ? disabledPaginateButtonsClass : '',
        ]"
        :disabled="disablePagination"
      >
        <slot name="last-page-button">
          {{ lastPageContent }}
        </slot>
      </component>
    </li>
  </ul>
</template>

<style>
ul#componentContainer {
  /* resetting default stylings for ul tag */
  padding-inline-start: 0;
  list-style-type: none;
  display: inline-flex;
}

ul#componentContainer a {
  /* resetting default stylings for a tag */
  text-decoration: none;
  display: flex;
  justify-content: center;
  align-items: center;
}
</style>


================================================
FILE: src/env.d.ts
================================================
/// <reference types="vite/client" />
declare module "*.vue" {
  import type { DefineComponent } from "vue";
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
  const component: DefineComponent<{}, {}, any>;
  export default component;
}


================================================
FILE: src/main.ts
================================================
import { createApp } from "vue";
import App from "./App.vue";
import VueAwesomePaginatePlugin from "./VueAwesomePaginatePlugin";

createApp(App).use(VueAwesomePaginatePlugin).mount("#app");


================================================
FILE: test/breakpoint-buttons.test.ts
================================================
/**
 * @vitest-environment happy-dom
 */

import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import { ref } from "vue";

import VueAwesomePaginate from "../src/components/vue-awesome-paginate.vue";

describe("First and Last Buttons", () => {
  it("should render the ending breakpoint button only when pagination is at the very beggining", () => {
    const currentPage = ref(1);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 100,
        modelValue: currentPage,
      },
    });

    expect(wrapper.find(".starting-breakpoint-button").exists()).toBeFalsy();
    expect(wrapper.find(".ending-breakpoint-button").exists()).toBeTruthy();
  });
  it("should render the starting breakpoint button only when pagination is at the very end", () => {
    const currentPage = ref(10);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 100,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".starting-breakpoint-button").exists()).toBeTruthy();
    expect(wrapper.find(".ending-breakpoint-button").exists()).toBeFalsy();
  });
  it("should render both ending buttons when pagination is at the middle", () => {
    const currentPage = ref(5);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 100,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".starting-breakpoint-button").exists()).toBeTruthy();
    expect(wrapper.find(".ending-breakpoint-button").exists()).toBeTruthy();
  });
});


================================================
FILE: test/first-last-buttons.test.ts
================================================
/**
 * @vitest-environment happy-dom
 */

import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import { ref } from "vue";

import VueAwesomePaginate from "../src/components/vue-awesome-paginate.vue";

describe("First and Last Buttons", () => {
  it("should render the last button only when pagination is at the very beggining", () => {
    const currentPage = ref(1);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 100,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".first-button").exists()).toBeFalsy();
    expect(wrapper.find(".last-button").exists()).toBeTruthy();
  });
  it("should render the first button only when pagination is at the very end", () => {
    const currentPage = ref(10);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 100,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".first-button").exists()).toBeTruthy();
    expect(wrapper.find(".last-button").exists()).toBeFalsy();
  });
  it("should render both ending buttons only when pagination is at the middle", () => {
    const currentPage = ref(5);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 100,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".first-button").exists()).toBeTruthy();
    expect(wrapper.find(".last-button").exists()).toBeTruthy();
  });
  it("should render both ending buttons only when pagination is at the middle", () => {
    const currentPage = ref(5);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 100,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".first-button").exists()).toBeTruthy();
    expect(wrapper.find(".last-button").exists()).toBeTruthy();
  });
});


================================================
FILE: test/jump-buttons.test.ts
================================================
/**
 * @vitest-environment happy-dom
 */

import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import { ref } from "vue";

import VueAwesomePaginate from "../src/components/vue-awesome-paginate.vue";

describe("Jump Buttons", () => {
  it("should render the forward jump button only when page is 1", () => {
    const currentPage = ref(1);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        showJumpButtons: true,
        totalItems: 100,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".backward-jump-button").exists()).toBeFalsy();
    expect(wrapper.find(".forward-jump-button").exists()).toBeTruthy();
  });
  it("should render the backward jump button only when page is the last one", () => {
    const currentPage = ref(10);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        showJumpButtons: true,
        totalItems: 100,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".backward-jump-button").exists()).toBeTruthy();
    expect(wrapper.find(".forward-jump-button").exists()).toBeFalsy();
  });
  it("should render the both jump buttons", () => {
    const currentPage = ref(5);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        showJumpButtons: true,
        totalItems: 100,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".backward-jump-button").exists()).toBeTruthy();
    expect(wrapper.find(".forward-jump-button").exists()).toBeTruthy();
  });
  it("should not render the jump buttons when disabled", () => {
    const currentPage = ref(1);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        showJumpButtons: false,
        totalItems: 100,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".backward-jump-button").exists()).toBeFalsy();
    expect(wrapper.find(".forward-jump-button").exists()).toBeFalsy();
  });
  it("should not render the jump buttons when total-items / items-per-page is smaller than max-pages-shown", () => {
    const currentPage = ref(1);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        showJumpButtons: true,
        totalItems: 50,
        maxPagesShown: 5,
        itemsPerPage: 10,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".backward-jump-button").exists()).toBeFalsy();
    expect(wrapper.find(".forward-jump-button").exists()).toBeFalsy();
  });
});


================================================
FILE: test/navigation-buttons.test.ts
================================================
/**
 * @vitest-environment happy-dom
 */

import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import { ref } from "vue";

import VueAwesomePaginate from "../src/components/vue-awesome-paginate.vue";

describe("Jump Buttons", () => {
  it("should render navigation buttons under no configs", () => {
    const currentPage = ref(1);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 100,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".back-button").exists()).toBeTruthy();
    expect(wrapper.find(".next-button").exists()).toBeTruthy();
  });
  it("should not render navigation buttons when hidePrevNext is set to true", () => {
    const currentPage = ref(1);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 100,
        hidePrevNext: true,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".back-button").exists()).toBeFalsy();
    expect(wrapper.find(".next-button").exists()).toBeFalsy();
  });
  it("should render the next navigation button only when hidePrevNextWhenEnds is set to true and current page is 1", () => {
    const currentPage = ref(1);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 100,
        hidePrevNextWhenEnds: true,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".back-button").exists()).toBeFalsy();
    expect(wrapper.find(".next-button").exists()).toBeTruthy();
  });
  it("should render the back navigation button only when hidePrevNextWhenEnds is set to true and current page is last one", () => {
    const currentPage = ref(10);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 100,
        hidePrevNextWhenEnds: true,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".back-button").exists()).toBeTruthy();
    expect(wrapper.find(".next-button").exists()).toBeFalsy();
  });
  it("should render both navigation buttons only when hidePrevNextWhenEnds is set to true and current page is in the middle", () => {
    const currentPage = ref(5);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 100,
        hidePrevNextWhenEnds: true,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".back-button").exists()).toBeTruthy();
    expect(wrapper.find(".next-button").exists()).toBeTruthy();
  });
});


================================================
FILE: test/numbers-buttons.test.ts
================================================
/**
 * @vitest-environment happy-dom
 */

import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import { ref } from "vue";

import VueAwesomePaginate from "../src/components/vue-awesome-paginate.vue";

describe("First and Last Buttons", () => {
  it("should render 5 number buttons by default when total items are more than or equal to 50", () => {
    const currentPage = ref(1);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 50,
        modelValue: currentPage,
      },
    });
    expect(wrapper.find(".number-buttons").exists()).toBeTruthy();
    expect(wrapper.findAll(".number-buttons").length).toBe(5);
  });
  it("should render 3 number buttons when maxPagesShown is set to 3", () => {
    const currentPage = ref(1);
    const wrapper = mount(VueAwesomePaginate, {
      propsData: {
        totalItems: 50,
        modelValue: currentPage,
        maxPagesShown: 3,
      },
    });
    expect(wrapper.find(".number-buttons").exists()).toBeTruthy();
    expect(wrapper.findAll(".number-buttons").length).toBe(3);
  });
});


================================================
FILE: tsconfig.json
================================================
{
  "extends": "@vue/tsconfig/tsconfig.web.json",
  "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
  "compilerOptions": {
    "strictNullChecks": false,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "references": [
    {
      "path": "./tsconfig.vite-config.json"
    }
  ]
}


================================================
FILE: tsconfig.vite-config.json
================================================
{
  "extends": "@vue/tsconfig/tsconfig.node.json",
  "include": ["vite.config.*"],
  "compilerOptions": {
    "composite": true,
    "types": ["node", "vitest"]
  }
}


================================================
FILE: vite.config.ts
================================================
import { defineConfig } from "vite";

import vue from "@vitejs/plugin-vue";
import typescript2 from "rollup-plugin-typescript2";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    typescript2({
      check: false,
      include: ["src/components/*.vue"],
      tsconfigOverride: {
        compilerOptions: {
          sourceMap: true,
          declaration: true,
          declarationMap: true,
        },
        exclude: ["vite.config.ts", "main.ts"],
      },
    }),
  ],
  define: {
    __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false,
  },
  build: {
    cssCodeSplit: false,
    lib: {
      entry: "./src/VueAwesomePaginatePlugin.ts",
      formats: ["es", "cjs"],
      name: "VueAwesomePaginate",
      fileName: (format) => (format === "es" ? "index.js" : "index.cjs"),
    },
    rollupOptions: {
      external: ["vue"],
      output: {
        globals: {
          vue: "Vue",
        },
      },
    },
  },
});
Download .txt
gitextract_zilk4tla/

├── .gitignore
├── .prettierrc
├── .vscode/
│   └── extensions.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── index.html
├── package.json
├── src/
│   ├── App.vue
│   ├── VueAwesomePaginatePlugin.ts
│   ├── components/
│   │   ├── index.ts
│   │   └── vue-awesome-paginate.vue
│   ├── env.d.ts
│   └── main.ts
├── test/
│   ├── breakpoint-buttons.test.ts
│   ├── first-last-buttons.test.ts
│   ├── jump-buttons.test.ts
│   ├── navigation-buttons.test.ts
│   └── numbers-buttons.test.ts
├── tsconfig.json
├── tsconfig.vite-config.json
└── vite.config.ts
Condensed preview — 22 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (72K chars).
[
  {
    "path": ".gitignore",
    "chars": 252,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\npnpm-debug.log*\nlerna-debug.log*\n\nnode_modules\ndist\ndis"
  },
  {
    "path": ".prettierrc",
    "chars": 60,
    "preview": "{\n  \"tabWidth\": 2,\n  \"semi\": true,\n  \"singleQuote\": false\n}\n"
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 39,
    "preview": "{\n  \"recommendations\": [\"Vue.volar\"]\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 2301,
    "preview": "- 1.2\n  - Created @click event handler for the component\n  - Added warning to replace onClick prop with @click event han"
  },
  {
    "path": "LICENSE",
    "chars": 1070,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016 Awe\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
  },
  {
    "path": "README.md",
    "chars": 27538,
    "preview": "# Vue Awesome Paginate\n\n#### _The Awesome Vue.js 3 Pagination Library_\n\n<img  src=\"https://i.postimg.cc/kgTFryfP/header."
  },
  {
    "path": "index.html",
    "chars": 337,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <"
  },
  {
    "path": "package.json",
    "chars": 1578,
    "preview": "{\n  \"name\": \"vue-awesome-paginate\",\n  \"private\": false,\n  \"type\": \"module\",\n  \"main\": \"dist/index.cjs\",\n  \"module\": \"dis"
  },
  {
    "path": "src/App.vue",
    "chars": 877,
    "preview": "<script setup lang=\"ts\">\nimport { ref } from \"vue\";\nimport vueAwesomePaginate from \"./components/vue-awesome-paginate.vu"
  },
  {
    "path": "src/VueAwesomePaginatePlugin.ts",
    "chars": 268,
    "preview": "// This is where the package installs.\nimport type { App } from \"vue\";\nimport { VueAwesomePaginate } from \"./components\""
  },
  {
    "path": "src/components/index.ts",
    "chars": 76,
    "preview": "export { default as VueAwesomePaginate } from \"./vue-awesome-paginate.vue\";\n"
  },
  {
    "path": "src/components/vue-awesome-paginate.vue",
    "chars": 21441,
    "preview": "<script setup lang=\"ts\">\nimport { toRef, type PropType } from \"vue\";\nimport { computed } from \"vue\";\n\n// ---------------"
  },
  {
    "path": "src/env.d.ts",
    "chars": 283,
    "preview": "/// <reference types=\"vite/client\" />\ndeclare module \"*.vue\" {\n  import type { DefineComponent } from \"vue\";\n  // eslint"
  },
  {
    "path": "src/main.ts",
    "chars": 190,
    "preview": "import { createApp } from \"vue\";\nimport App from \"./App.vue\";\nimport VueAwesomePaginatePlugin from \"./VueAwesomePaginate"
  },
  {
    "path": "test/breakpoint-buttons.test.ts",
    "chars": 1580,
    "preview": "/**\n * @vitest-environment happy-dom\n */\n\nimport { describe, it, expect } from \"vitest\";\nimport { mount } from \"@vue/tes"
  },
  {
    "path": "test/first-last-buttons.test.ts",
    "chars": 1873,
    "preview": "/**\n * @vitest-environment happy-dom\n */\n\nimport { describe, it, expect } from \"vitest\";\nimport { mount } from \"@vue/tes"
  },
  {
    "path": "test/jump-buttons.test.ts",
    "chars": 2494,
    "preview": "/**\n * @vitest-environment happy-dom\n */\n\nimport { describe, it, expect } from \"vitest\";\nimport { mount } from \"@vue/tes"
  },
  {
    "path": "test/navigation-buttons.test.ts",
    "chars": 2489,
    "preview": "/**\n * @vitest-environment happy-dom\n */\n\nimport { describe, it, expect } from \"vitest\";\nimport { mount } from \"@vue/tes"
  },
  {
    "path": "test/numbers-buttons.test.ts",
    "chars": 1109,
    "preview": "/**\n * @vitest-environment happy-dom\n */\n\nimport { describe, it, expect } from \"vitest\";\nimport { mount } from \"@vue/tes"
  },
  {
    "path": "tsconfig.json",
    "chars": 310,
    "preview": "{\n  \"extends\": \"@vue/tsconfig/tsconfig.web.json\",\n  \"include\": [\"env.d.ts\", \"src/**/*\", \"src/**/*.vue\"],\n  \"compilerOpti"
  },
  {
    "path": "tsconfig.vite-config.json",
    "chars": 167,
    "preview": "{\n  \"extends\": \"@vue/tsconfig/tsconfig.node.json\",\n  \"include\": [\"vite.config.*\"],\n  \"compilerOptions\": {\n    \"composite"
  },
  {
    "path": "vite.config.ts",
    "chars": 965,
    "preview": "import { defineConfig } from \"vite\";\n\nimport vue from \"@vitejs/plugin-vue\";\nimport typescript2 from \"rollup-plugin-types"
  }
]

About this extraction

This page contains the full source code of the peshanghiwa/vue-awesome-paginate GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 22 files (65.7 KB), approximately 15.5k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!