feat: add pagination component
This commit is contained in:
parent
0750431ceb
commit
a88f36041e
24 changed files with 717 additions and 5 deletions
|
|
@ -67,6 +67,7 @@ The accessibility column indicates whether the functionality is accessible in it
|
||||||
| [tooltip](https://lion-web-components.netlify.app/?path=/docs/overlays-tooltip--main) | [](https://www.npmjs.com/package/@lion/tooltip) | Tooltip element | [#175][i175] |
|
| [tooltip](https://lion-web-components.netlify.app/?path=/docs/overlays-tooltip--main) | [](https://www.npmjs.com/package/@lion/tooltip) | Tooltip element | [#175][i175] |
|
||||||
| **-- [Navigation System](https://lion-web-components.netlify.app/?path=/docs/navigation-intro--page) --** | | Components which are used to guide users | |
|
| **-- [Navigation System](https://lion-web-components.netlify.app/?path=/docs/navigation-intro--page) --** | | Components which are used to guide users | |
|
||||||
| [accordion](https://lion-web-components.netlify.app/?path=/docs/navigation-accordion--main) | [](https://www.npmjs.com/package/@lion/accordion) | Accordion | ✔️ |
|
| [accordion](https://lion-web-components.netlify.app/?path=/docs/navigation-accordion--main) | [](https://www.npmjs.com/package/@lion/accordion) | Accordion | ✔️ |
|
||||||
|
| [pagination](https://lion-web-components.netlify.app/?path=/docs/navigation-pagination--main) | [](https://www.npmjs.com/package/@lion/pagination) | Pagination | ✔️ |
|
||||||
| [steps](https://lion-web-components.netlify.app/?path=/docs/navigation-steps--main) | [](https://www.npmjs.com/package/@lion/steps) | Multi Step System | n/a |
|
| [steps](https://lion-web-components.netlify.app/?path=/docs/navigation-steps--main) | [](https://www.npmjs.com/package/@lion/steps) | Multi Step System | n/a |
|
||||||
| [tabs](https://lion-web-components.netlify.app/?path=/docs/navigation-tabs--main) | [](https://www.npmjs.com/package/@lion/tabs) | Move between a small number of equally important views | n/a |
|
| [tabs](https://lion-web-components.netlify.app/?path=/docs/navigation-tabs--main) | [](https://www.npmjs.com/package/@lion/tabs) | Move between a small number of equally important views | n/a |
|
||||||
| **-- [localize System](https://lion-web-components.netlify.app/?path=/docs/localize-intro--page) --** | | Localize text, numbers, dates and a way to store/fetch these data. | |
|
| **-- [localize System](https://lion-web-components.netlify.app/?path=/docs/localize-intro--page) --** | | Localize text, numbers, dates and a way to store/fetch these data. | |
|
||||||
|
|
@ -77,7 +78,7 @@ The accessibility column indicates whether the functionality is accessible in it
|
||||||
| [core](https://lion-web-components.netlify.app/?path=/docs/others-system-core--page) | [](https://www.npmjs.com/package/@lion/core) | Core System (exports LitElement, lit-html) | n/a |
|
| [core](https://lion-web-components.netlify.app/?path=/docs/others-system-core--page) | [](https://www.npmjs.com/package/@lion/core) | Core System (exports LitElement, lit-html) | n/a |
|
||||||
| [ajax](https://lion-web-components.netlify.app/?path=/docs/others-ajax--performing-get-requests) | [](https://www.npmjs.com/package/@lion/ajax) | Fetching data via ajax request | n/a |
|
| [ajax](https://lion-web-components.netlify.app/?path=/docs/others-ajax--performing-get-requests) | [](https://www.npmjs.com/package/@lion/ajax) | Fetching data via ajax request | n/a |
|
||||||
| [calendar](https://lion-web-components.netlify.app/?path=/docs/others-calendar--main) | [](https://www.npmjs.com/package/@lion/calendar) | Standalone calendar | [#195][i195], [#194][i194] |
|
| [calendar](https://lion-web-components.netlify.app/?path=/docs/others-calendar--main) | [](https://www.npmjs.com/package/@lion/calendar) | Standalone calendar | [#195][i195], [#194][i194] |
|
||||||
| [collapsible](https://lion-web-components.netlify.app/?path=/docs/others-collapsible--main) | [](https://www.npmjs.com/package/@lion/collapsible) | Combination of a button and a chunk of extra content | |
|
| [collapsible](https://lion-web-components.netlify.app/?path=/docs/others-collapsible--main) | [](https://www.npmjs.com/package/@lion/collapsible) | Combination of a button and a chunk of extra content | ✔️ |
|
||||||
| **-- [Helpers](https://lion-web-components.netlify.app/?path=/docs/helpers-intro--page) --** | [](https://www.npmjs.com/package/@lion/helpers) | Helpers to make your and your life easier | |
|
| **-- [Helpers](https://lion-web-components.netlify.app/?path=/docs/helpers-intro--page) --** | [](https://www.npmjs.com/package/@lion/helpers) | Helpers to make your and your life easier | |
|
||||||
| [sb-action-logger](https://lion-web-components.netlify.app/?path=/docs/helpers-storybook-action-logger--main) | | Storybook action logger |
|
| [sb-action-logger](https://lion-web-components.netlify.app/?path=/docs/helpers-storybook-action-logger--main) | | Storybook action logger |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,12 @@ Navigational elements are used to guide users within your page.
|
||||||
|
|
||||||
## Packages
|
## Packages
|
||||||
|
|
||||||
| Package | Version | Description |
|
| Package | Version | Description |
|
||||||
| ---------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- |
|
||||||
| [steps](?path=/docs/navigation-steps--default-story) | [](https://www.npmjs.com/package/@lion/steps) | Multi Step System |
|
| [accordion](?path=/docs/accordion-steps--default-story) | [](https://www.npmjs.com/package/@lion/accordion) | A component to toggle the display of sections of content |
|
||||||
| [tabs](?path=/docs/navigation-tabs--default-story) | [](https://www.npmjs.com/package/@lion/tabs) | Move between a small number of equally important views |
|
| [pagination](?path=/docs/pagination-steps--default-story) | [](https://www.npmjs.com/package/@lion/pagination) | A component that handles pagination |
|
||||||
|
| [steps](?path=/docs/navigation-steps--default-story) | [](https://www.npmjs.com/package/@lion/steps) | Multi Step System |
|
||||||
|
| [tabs](?path=/docs/navigation-tabs--default-story) | [](https://www.npmjs.com/package/@lion/tabs) | Move between a small number of equally important views |
|
||||||
|
|
||||||
```js script
|
```js script
|
||||||
export default {
|
export default {
|
||||||
|
|
|
||||||
1
packages/pagination/CHANGELOG.md
Normal file
1
packages/pagination/CHANGELOG.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
# Change Log
|
||||||
145
packages/pagination/README.md
Normal file
145
packages/pagination/README.md
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
# Pagination
|
||||||
|
|
||||||
|
`lion-pagination` component that handles pagination.
|
||||||
|
|
||||||
|
```js script
|
||||||
|
import { html } from 'lit-html';
|
||||||
|
|
||||||
|
import './lion-pagination.js';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Navigation/Pagination',
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const main = () => html` <lion-pagination count="20" current="10"></lion-pagination> `;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- You can pass the total number of pages in the `count` parameter, and the current page in the `current` parameter. If `current` is not defined it will default to the value 1.
|
||||||
|
- On a click or parameter change of `current` it will fire an event back called `current-changed`.
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm i --save @lion/pagination
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { LionPagination } from '@lion/pagination';
|
||||||
|
// or
|
||||||
|
import '@lion/pagination/lion-pagination.js';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```html
|
||||||
|
<lion-pagination count="20" current="10"></lion-pagination>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
### Without current defined
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const withoutCurrentPage = () => {
|
||||||
|
return html` <lion-pagination count="20"></lion-pagination> `;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ensure a count value
|
||||||
|
|
||||||
|
Be sure to set a count value or you will get an "empty" pagination.
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const ensureCount = () => {
|
||||||
|
return html` <lion-pagination></lion-pagination> `;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Methods
|
||||||
|
|
||||||
|
There are the following methods available to control the pagination.
|
||||||
|
|
||||||
|
- `next()`: move forward in pagination
|
||||||
|
- `previous()`: goes back to pagination
|
||||||
|
- `first()`: to the first page
|
||||||
|
- `last()`: to the last page
|
||||||
|
- `goto(pageNumber)`: to the specific page
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const methods = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
document.getElementById('pagination-method-demo').innerText = document.getElementById(
|
||||||
|
'pagination-method',
|
||||||
|
).current;
|
||||||
|
});
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<p>The current page is: <span id="pagination-method-demo"></span></p>
|
||||||
|
<lion-pagination
|
||||||
|
id="pagination-method"
|
||||||
|
count="100"
|
||||||
|
current="75"
|
||||||
|
@current-changed=${e => {
|
||||||
|
const paginationState = document.getElementById('pagination-method-demo');
|
||||||
|
paginationState.innerText = e.target.current;
|
||||||
|
}}
|
||||||
|
></lion-pagination>
|
||||||
|
<section style="margin-top:16px">
|
||||||
|
<button @click=${() => document.getElementById('pagination-method').previous()}>
|
||||||
|
Previous
|
||||||
|
</button>
|
||||||
|
<button @click=${() => document.getElementById('pagination-method').next()}>
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<button @click=${() => document.getElementById('pagination-method').first()}>
|
||||||
|
First
|
||||||
|
</button>
|
||||||
|
<button @click=${() => document.getElementById('pagination-method').last()}>
|
||||||
|
Last
|
||||||
|
</button>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<button @click=${() => document.getElementById('pagination-method').goto(55)}>
|
||||||
|
Go to 55
|
||||||
|
</button>
|
||||||
|
</section>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Event
|
||||||
|
|
||||||
|
`lion-pagination` fires an event on button click to notify the component's current state. It is useful for analytics purposes or to perform some actions on page change.
|
||||||
|
|
||||||
|
- `@current-changed`: triggers when the current page is changed
|
||||||
|
|
||||||
|
```js preview-story
|
||||||
|
export const event = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
document.getElementById('pagination-event-demo-text').innerText = document.getElementById(
|
||||||
|
'pagination-event-demo',
|
||||||
|
).current;
|
||||||
|
});
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<p>The current page is: <span id="pagination-event-demo-text"></span></p>
|
||||||
|
<lion-pagination
|
||||||
|
id="pagination-event-demo"
|
||||||
|
count="10"
|
||||||
|
current="5"
|
||||||
|
@current-changed=${e => {
|
||||||
|
const paginationState = document.getElementById('pagination-event-demo-text');
|
||||||
|
paginationState.innerText = e.target.current;
|
||||||
|
}}
|
||||||
|
></lion-pagination>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
```
|
||||||
1
packages/pagination/index.js
Normal file
1
packages/pagination/index.js
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export { LionPagination } from './src/LionPagination.js';
|
||||||
3
packages/pagination/lion-pagination.js
Normal file
3
packages/pagination/lion-pagination.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { LionPagination } from './src/LionPagination.js';
|
||||||
|
|
||||||
|
customElements.define('lion-pagination', LionPagination);
|
||||||
46
packages/pagination/package.json
Normal file
46
packages/pagination/package.json
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
{
|
||||||
|
"name": "@lion/pagination",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "A component that handles pagination.",
|
||||||
|
"license": "MIT",
|
||||||
|
"author": "ing-bank",
|
||||||
|
"homepage": "https://github.com/ing-bank/lion/",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/ing-bank/lion.git",
|
||||||
|
"directory": "packages/pagination"
|
||||||
|
},
|
||||||
|
"main": "index.js",
|
||||||
|
"module": "index.js",
|
||||||
|
"files": [
|
||||||
|
"*.d.ts",
|
||||||
|
"*.js",
|
||||||
|
"docs",
|
||||||
|
"src",
|
||||||
|
"test",
|
||||||
|
"test-helpers",
|
||||||
|
"translations",
|
||||||
|
"types"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"prepublishOnly": "../../scripts/npm-prepublish.js",
|
||||||
|
"start": "cd ../../ && yarn dev-server --open packages/pagination/README.md",
|
||||||
|
"test": "cd ../../ && yarn test:browser --grep \"packages/pagination/test/**/*.test.js\"",
|
||||||
|
"test:watch": "cd ../../ && yarn test:browser:watch --grep \"packages/pagination/test/**/*.test.js\""
|
||||||
|
},
|
||||||
|
"sideEffects": [
|
||||||
|
"lion-pagination.js"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@lion/core": "0.10.0",
|
||||||
|
"@lion/localize": "0.14.2"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"lion",
|
||||||
|
"pagination",
|
||||||
|
"web-components"
|
||||||
|
],
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
}
|
||||||
|
}
|
||||||
296
packages/pagination/src/LionPagination.js
Normal file
296
packages/pagination/src/LionPagination.js
Normal file
|
|
@ -0,0 +1,296 @@
|
||||||
|
import { LitElement, html, css } from '@lion/core';
|
||||||
|
import { LocalizeMixin } from '@lion/localize';
|
||||||
|
/**
|
||||||
|
* `LionPagination` is a class for custom Pagination element (`<lion-pagination>` web component).
|
||||||
|
*
|
||||||
|
* @customElement lion-pagination
|
||||||
|
* @extends LitElement
|
||||||
|
*/
|
||||||
|
export class LionPagination extends LocalizeMixin(LitElement) {
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
button[aria-current='true'] {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get localizeNamespaces() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'lion-pagination': locale => {
|
||||||
|
switch (locale) {
|
||||||
|
case 'bg-BG':
|
||||||
|
return import('../translations/bg.js');
|
||||||
|
case 'cs-CZ':
|
||||||
|
return import('../translations/cs.js');
|
||||||
|
case 'de-AT':
|
||||||
|
case 'de-DE':
|
||||||
|
return import('../translations/de.js');
|
||||||
|
case 'en-AU':
|
||||||
|
case 'en-GB':
|
||||||
|
case 'en-PH':
|
||||||
|
case 'en-US':
|
||||||
|
return import('../translations/en.js');
|
||||||
|
case 'es-ES':
|
||||||
|
return import('../translations/es.js');
|
||||||
|
case 'fr-FR':
|
||||||
|
case 'fr-BE':
|
||||||
|
return import('../translations/fr.js');
|
||||||
|
case 'hu-HU':
|
||||||
|
return import('../translations/hu.js');
|
||||||
|
case 'it-IT':
|
||||||
|
return import('../translations/it.js');
|
||||||
|
case 'nl-BE':
|
||||||
|
case 'nl-NL':
|
||||||
|
return import('../translations/nl.js');
|
||||||
|
case 'pl-PL':
|
||||||
|
return import('../translations/pl.js');
|
||||||
|
case 'ro-RO':
|
||||||
|
return import('../translations/ro.js');
|
||||||
|
case 'ru-RU':
|
||||||
|
return import('../translations/ru.js');
|
||||||
|
case 'sk-SK':
|
||||||
|
return import('../translations/sk.js');
|
||||||
|
case 'uk-UA':
|
||||||
|
return import('../translations/uk.js');
|
||||||
|
case 'zh-CN':
|
||||||
|
return import('../translations/zh.js');
|
||||||
|
default:
|
||||||
|
return import('../translations/en.js');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...super.localizeNamespaces,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
current: {
|
||||||
|
type: Number,
|
||||||
|
reflect: true,
|
||||||
|
},
|
||||||
|
count: {
|
||||||
|
type: Number,
|
||||||
|
reflect: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
set current(value) {
|
||||||
|
if (value !== this.current) {
|
||||||
|
const oldValue = this.current;
|
||||||
|
this.__current = value;
|
||||||
|
this.dispatchEvent(new Event('current-changed'));
|
||||||
|
this.requestUpdate('current', oldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get current() {
|
||||||
|
return this.__current;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.__visiblePages = 5;
|
||||||
|
this.current = 1;
|
||||||
|
this.count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go next in pagination
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
next() {
|
||||||
|
if (this.current < this.count) {
|
||||||
|
this.__fire(this.current + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to first page
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
first() {
|
||||||
|
if (this.count >= 1) {
|
||||||
|
this.__fire(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the last page
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
last() {
|
||||||
|
if (this.count >= 1) {
|
||||||
|
this.__fire(this.count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go to the specific page
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
goto(pageNumber) {
|
||||||
|
if (pageNumber >= 1 && pageNumber <= this.count) {
|
||||||
|
this.__fire(pageNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Go back in pagination
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
previous() {
|
||||||
|
if (this.current !== 1) {
|
||||||
|
this.__fire(this.current - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set desired page in the pagination and fire the current changed event.
|
||||||
|
* @param {Number} page page number to be set
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
__fire(page) {
|
||||||
|
if (page !== this.current) {
|
||||||
|
this.current = page;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate nav list based on current page selection.
|
||||||
|
* @returns {Array}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
__calculateNavList() {
|
||||||
|
const start = 1;
|
||||||
|
const finish = this.count;
|
||||||
|
// If there are more pages then we want to display we have to redo the list each time
|
||||||
|
// Else we can just return the same list every time.
|
||||||
|
if (this.count > this.__visiblePages) {
|
||||||
|
// Calculate left side of current page and right side
|
||||||
|
const pos3 = this.current - 1;
|
||||||
|
const pos4 = this.current;
|
||||||
|
const pos5 = this.current + 1;
|
||||||
|
// if pos 3 is lower than 4 we have a predefined list of elements
|
||||||
|
if (pos4 <= 4) {
|
||||||
|
const list = Array(this.__visiblePages)
|
||||||
|
.fill()
|
||||||
|
.map((_, idx) => start + idx);
|
||||||
|
list.push('...');
|
||||||
|
list.push(this.count);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
// if we are close to the end of the list with the current page then we have again a predefined list
|
||||||
|
if (finish - pos4 <= 3) {
|
||||||
|
const list = [];
|
||||||
|
list.push(1);
|
||||||
|
list.push('...');
|
||||||
|
const listRemaining = Array(this.__visiblePages)
|
||||||
|
.fill()
|
||||||
|
.map((_, idx) => this.count - this.__visiblePages + 1 + idx);
|
||||||
|
return list.concat(listRemaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [start, '...', pos3, pos4, pos5, '...', finish];
|
||||||
|
}
|
||||||
|
return Array(finish - start + 1)
|
||||||
|
.fill()
|
||||||
|
.map((_, idx) => start + idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get previous or next button template.
|
||||||
|
* This method can be overridden to apply customized template in wrapper.
|
||||||
|
* @param {String} label namespace label i.e. next or previous
|
||||||
|
* @returns {TemplateResult} icon template
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
_prevNextIconTemplate(label) {
|
||||||
|
return label === 'next' ? html` > ` : html` < `;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get next or previous button template.
|
||||||
|
* This method can be overridden to apply customized template in wrapper.
|
||||||
|
* @param {String} label namespace label i.e. next or previous
|
||||||
|
* @param {Number} pageNumber page number to be set
|
||||||
|
* @param {String} namespace namespace prefix for translations
|
||||||
|
* @returns {TemplateResult} nav item template
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
_prevNextButtonTemplate(label, pageNumber, namespace = 'lion') {
|
||||||
|
return html`
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
aria-label=${this.msgLit(`${namespace}-pagination:${label}`)}
|
||||||
|
@click=${() => this.__fire(pageNumber)}
|
||||||
|
>
|
||||||
|
${this._prevNextIconTemplate(label)}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get disabled button template.
|
||||||
|
* This method can be overridden to apply customized template in wrapper.
|
||||||
|
* @param {String} label namespace label i.e. next or previous
|
||||||
|
* @returns {TemplateResult} nav item template
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
_disabledButtonTemplate(label) {
|
||||||
|
return html`
|
||||||
|
<li>
|
||||||
|
<button disabled>${this._prevNextIconTemplate(label)}</button>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<nav role="navigation" aria-label="${this.msgLit('lion-pagination:label')}">
|
||||||
|
<ul>
|
||||||
|
${this.current > 1
|
||||||
|
? this._prevNextButtonTemplate('previous', this.current - 1)
|
||||||
|
: this._disabledButtonTemplate('previous')}
|
||||||
|
${this.__calculateNavList().map(page =>
|
||||||
|
page === '...'
|
||||||
|
? html` <li><span>${page}</span></li> `
|
||||||
|
: html`
|
||||||
|
<li>
|
||||||
|
<button
|
||||||
|
aria-label="${this.msgLit('lion-pagination:page', { page })}"
|
||||||
|
aria-current=${page === this.current}
|
||||||
|
@click=${() => this.__fire(page)}
|
||||||
|
>
|
||||||
|
${page}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
`,
|
||||||
|
)}
|
||||||
|
${this.current < this.count
|
||||||
|
? this._prevNextButtonTemplate('next', this.current + 1)
|
||||||
|
: this._disabledButtonTemplate('next')}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
127
packages/pagination/test/lion-pagination.test.js
Normal file
127
packages/pagination/test/lion-pagination.test.js
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
import { html, fixture, expect } from '@open-wc/testing';
|
||||||
|
import sinon from 'sinon';
|
||||||
|
|
||||||
|
import '../lion-pagination.js';
|
||||||
|
|
||||||
|
describe('Pagination', () => {
|
||||||
|
it('has states for count and current', async () => {
|
||||||
|
const el = await fixture(html` <lion-pagination count="4"></lion-pagination> `);
|
||||||
|
expect(el.getAttribute('count')).to.equal('4');
|
||||||
|
expect(el.getAttribute('current')).to.equal('1');
|
||||||
|
el.count = 8;
|
||||||
|
el.current = 2;
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(el.getAttribute('count')).to.equal('8');
|
||||||
|
expect(el.getAttribute('current')).to.equal('2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('disables the previous button if on first page', async () => {
|
||||||
|
const el = await fixture(html` <lion-pagination count="4"></lion-pagination> `);
|
||||||
|
const buttons = Array.from(el.shadowRoot.querySelectorAll('button'));
|
||||||
|
expect(buttons[0]).to.has.attribute('disabled');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('disables the next button if on last page', async () => {
|
||||||
|
const el = await fixture(html` <lion-pagination count="4" current="4"></lion-pagination> `);
|
||||||
|
const buttons = Array.from(el.shadowRoot.querySelectorAll('button'));
|
||||||
|
expect(buttons[buttons.length - 1]).to.has.attribute('disabled');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('User interaction', () => {
|
||||||
|
it('can go to previous page with previous button', async () => {
|
||||||
|
const el = await fixture(html` <lion-pagination count="6" current="2"></lion-pagination> `);
|
||||||
|
const buttons = Array.from(el.shadowRoot.querySelectorAll('button'));
|
||||||
|
buttons[0].click();
|
||||||
|
expect(el.current).to.equal(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can go to next page with next button', async () => {
|
||||||
|
const el = await fixture(html` <lion-pagination count="6" current="2"></lion-pagination> `);
|
||||||
|
const buttons = Array.from(el.shadowRoot.querySelectorAll('button'));
|
||||||
|
buttons[buttons.length - 1].click();
|
||||||
|
expect(el.current).to.equal(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('goes to the page when clicking on its button', async () => {
|
||||||
|
const el = await fixture(html` <lion-pagination count="6" current="2"></lion-pagination> `);
|
||||||
|
const buttons = Array.from(el.shadowRoot.querySelectorAll('button'));
|
||||||
|
buttons[5].click();
|
||||||
|
expect(el.current).to.equal(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fires current-changed event when interacting with the pagination', async () => {
|
||||||
|
const changeSpy = sinon.spy();
|
||||||
|
const el = await fixture(html`
|
||||||
|
<lion-pagination count="6" current="2" @current-changed=${changeSpy}></lion-pagination>
|
||||||
|
`);
|
||||||
|
const buttons = Array.from(el.shadowRoot.querySelectorAll('button'));
|
||||||
|
const previous = buttons[0];
|
||||||
|
const next = buttons[buttons.length - 1];
|
||||||
|
const page5 = buttons[5];
|
||||||
|
|
||||||
|
previous.click();
|
||||||
|
expect(changeSpy).to.have.callCount(1);
|
||||||
|
|
||||||
|
next.click();
|
||||||
|
expect(changeSpy).to.have.callCount(2);
|
||||||
|
|
||||||
|
page5.click();
|
||||||
|
expect(changeSpy).to.have.callCount(3);
|
||||||
|
|
||||||
|
el.current = 3;
|
||||||
|
expect(changeSpy).to.have.callCount(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does NOT fire current-changed event when clicking on a current page number', async () => {
|
||||||
|
const changeSpy = sinon.spy();
|
||||||
|
const el = await fixture(html`
|
||||||
|
<lion-pagination count="6" current="2" @current-changed=${changeSpy}></lion-pagination>
|
||||||
|
`);
|
||||||
|
const page2 = el.shadowRoot.querySelector("button[aria-current='true']");
|
||||||
|
page2.click();
|
||||||
|
expect(changeSpy).to.not.be.called;
|
||||||
|
expect(el.current).to.equal(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should goto next and previous page using `next()` and `previous()`', async () => {
|
||||||
|
const el = await fixture(html` <lion-pagination count="6" current="2"></lion-pagination> `);
|
||||||
|
el.next();
|
||||||
|
expect(el.current).to.equal(3);
|
||||||
|
el.previous();
|
||||||
|
expect(el.current).to.equal(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should goto first and last page using `first()` and `last()`', async () => {
|
||||||
|
const el = await fixture(html` <lion-pagination count="5" current="2"></lion-pagination> `);
|
||||||
|
expect(el.current).to.equal(2);
|
||||||
|
el.first();
|
||||||
|
expect(el.current).to.equal(1);
|
||||||
|
el.last();
|
||||||
|
expect(el.current).to.equal(5);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should goto 7 page using `goto()`', async () => {
|
||||||
|
const el = await fixture(html` <lion-pagination count="10" current="2"></lion-pagination> `);
|
||||||
|
expect(el.current).to.equal(2);
|
||||||
|
el.goto(7);
|
||||||
|
expect(el.current).to.equal(7);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Accessibility', () => {
|
||||||
|
it('sets aria-current to the current page', async () => {
|
||||||
|
const el = await fixture(html` <lion-pagination count="3"></lion-pagination> `);
|
||||||
|
const buttons = Array.from(el.shadowRoot.querySelectorAll('button'));
|
||||||
|
// button[0] is the previous button
|
||||||
|
expect(buttons[1].getAttribute('aria-current')).to.equal('true');
|
||||||
|
expect(buttons[2].getAttribute('aria-current')).to.equal('false');
|
||||||
|
expect(buttons[3].getAttribute('aria-current')).to.equal('false');
|
||||||
|
|
||||||
|
el.current = 2;
|
||||||
|
await el.updateComplete;
|
||||||
|
expect(buttons[1].getAttribute('aria-current')).to.equal('false');
|
||||||
|
expect(buttons[2].getAttribute('aria-current')).to.equal('true');
|
||||||
|
expect(buttons[3].getAttribute('aria-current')).to.equal('false');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
6
packages/pagination/translations/bg.js
Normal file
6
packages/pagination/translations/bg.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Навигация по страниците',
|
||||||
|
previous: 'Предишна страница',
|
||||||
|
next: 'Следваща страница',
|
||||||
|
page: 'Страница {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/cs.js
Normal file
6
packages/pagination/translations/cs.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Navigace stránky',
|
||||||
|
previous: 'Předchozí strana',
|
||||||
|
next: 'Další strana',
|
||||||
|
page: 'Strana {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/de.js
Normal file
6
packages/pagination/translations/de.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Seitennavigation',
|
||||||
|
previous: 'Vorherige Seite',
|
||||||
|
next: 'Nächste Seite',
|
||||||
|
page: 'Seite {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/en.js
Normal file
6
packages/pagination/translations/en.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Page navigation',
|
||||||
|
previous: 'Previous page',
|
||||||
|
next: 'Next page',
|
||||||
|
page: 'Page {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/es.js
Normal file
6
packages/pagination/translations/es.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Navegación de la página',
|
||||||
|
previous: 'Página anterior',
|
||||||
|
next: 'Página siguiente',
|
||||||
|
page: 'Página {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/fr.js
Normal file
6
packages/pagination/translations/fr.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Navigation de page',
|
||||||
|
previous: 'Page précédente',
|
||||||
|
next: 'Page suivante',
|
||||||
|
page: 'Page {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/hu.js
Normal file
6
packages/pagination/translations/hu.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Oldalnavigáció',
|
||||||
|
previous: 'Előző oldal',
|
||||||
|
next: 'Következő oldal',
|
||||||
|
page: '{page}. oldal',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/it.js
Normal file
6
packages/pagination/translations/it.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Navigazione pagina',
|
||||||
|
previous: 'Pagina Precedente',
|
||||||
|
next: 'Pagina successiva',
|
||||||
|
page: 'Pagina {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/nl.js
Normal file
6
packages/pagination/translations/nl.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Pagina navigatie',
|
||||||
|
previous: 'Vorige pagina',
|
||||||
|
next: 'Volgende pagina',
|
||||||
|
page: 'Pagina {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/pl.js
Normal file
6
packages/pagination/translations/pl.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Nawigacja strony',
|
||||||
|
previous: 'Poprzednia strona',
|
||||||
|
next: 'Następna strona',
|
||||||
|
page: 'Strona {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/ro.js
Normal file
6
packages/pagination/translations/ro.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Navigare în pagină',
|
||||||
|
previous: 'Pagină anterioară',
|
||||||
|
next: 'Pagină următoare',
|
||||||
|
page: 'Pagina {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/ru.js
Normal file
6
packages/pagination/translations/ru.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Навигация по страницам',
|
||||||
|
previous: 'Предыдущая страница',
|
||||||
|
next: 'Следующая страница',
|
||||||
|
page: 'Страница {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/sk.js
Normal file
6
packages/pagination/translations/sk.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Navigácia stranami',
|
||||||
|
previous: 'Predchádzajúca strana',
|
||||||
|
next: 'Ďalšia strana',
|
||||||
|
page: 'Strana {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/uk.js
Normal file
6
packages/pagination/translations/uk.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: 'Навігація по сторінках',
|
||||||
|
previous: 'Попередня сторінка',
|
||||||
|
next: 'Наступна сторінка',
|
||||||
|
page: 'Сторінка {page}',
|
||||||
|
};
|
||||||
6
packages/pagination/translations/zh.js
Normal file
6
packages/pagination/translations/zh.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
label: '页面导航',
|
||||||
|
previous: '上一页',
|
||||||
|
next: '下一页',
|
||||||
|
page: '页 {page}',
|
||||||
|
};
|
||||||
Loading…
Reference in a new issue