Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(component.pagination): Add new component pagination #10

Merged
merged 51 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
245b778
feat(ods.component.pagination): osds-pagination component
Kranysys Mar 1, 2023
405d04a
feat(ods.component.pagination): only useful attributes
Kranysys Mar 17, 2023
dc229ce
feat(ods.component.pagination): page select with enter and space
Kranysys Mar 20, 2023
ac3cdbe
feat(ods.component.pagination): disabled
Kranysys Mar 20, 2023
0e4a57a
fix(ods.component.pagination): cleaning all attributes, scss, tests, …
Kranysys Mar 21, 2023
ae867d1
feat(ods.component.pagination): documentation design, css cursor padd…
Kranysys Mar 22, 2023
547a561
feat(ods.component.pagination): add unit tests pagination, fix types
Kranysys Mar 22, 2023
14088f8
feat(ods.component.pagination): attributes testing, fixing default-cu…
Kranysys Mar 23, 2023
9b0fadd
feat(ods.component.pagination): e2e tests, unit tests, refactor, clean
Kranysys Mar 23, 2023
33dbd02
feat(ods.component.pagination): screenshots testing
Kranysys Mar 24, 2023
9612db5
feat(ods.component.pagination): adding unit tests with pages
Kranysys Mar 24, 2023
7d0f705
feat(ods.component.pagination): storybook of pagination
Kranysys Mar 27, 2023
0893730
fix(pagination): the lockfile would have been modified
stevering Mar 27, 2023
361d195
feat(ods.component.pagination): adding examples in storybook
Kranysys Mar 28, 2023
25d40f2
feat(ods.component.pagination): buttons size 2.25rem
Kranysys Mar 29, 2023
72617a0
feat(ods.component.pagination): buttons contrasted to ghost
Kranysys Mar 29, 2023
91a3c6e
feat(ods.component.pagination): ellipsis to osds-text, disabled class…
Kranysys Mar 31, 2023
471be80
feat(pagination): add component to typedoc file
astagnol Apr 3, 2023
3232ecc
feat(pagination): rm unnecessary jest dependency in testing
astagnol Apr 3, 2023
aa03735
feat(pagination): adding tests of current page on screenshots
Kranysys Apr 4, 2023
3c96e23
feat(pagination): scss size, disabled testing, some fixes
Kranysys Apr 4, 2023
382da5c
feat(pagination): tests E2E for counting links
Kranysys Apr 5, 2023
c2568ce
feat(pagination): tests E2E for clicking buttons
Kranysys Apr 5, 2023
f4bba1c
feat(pagination): controller refactoring, testings, mock, filter
Kranysys Apr 6, 2023
66a5017
feat(pagination): changing pageindex to current, cleaning
Kranysys Apr 8, 2023
5d32079
feat(pagination): focus the selected page all cases
Kranysys Apr 11, 2023
806b802
fix(pagination): some fixes
Kranysys Apr 21, 2023
46017f4
feat(pagination): refactorization, testing
Kranysys Apr 25, 2023
b53e974
feat(pagination): logic in controller, 100% tested
Kranysys Apr 25, 2023
1fda9b3
feat(pagination): using createPageList without id, refactor, cleaning
Kranysys Apr 25, 2023
993995c
fix(pagination): yarn.lock
Kranysys Apr 25, 2023
9edca4d
feat(pagination): renaming OdsPagination event
Kranysys Apr 25, 2023
2035fcc
fix(pagination): page logic changed
Kranysys Apr 26, 2023
ebd89d2
feat(pagination): theming, fixes
Kranysys Apr 26, 2023
e48a632
fix(pagination): div, disabled scss, fix js conflict
Kranysys Apr 26, 2023
d114d91
feat(pagination): renaming total, removing defaultCurrent, refactor a…
Kranysys Apr 26, 2023
d3e9570
feat(pagination): renderArrows refactor, fixes
Kranysys Apr 27, 2023
4381e97
feat(pagination): renderEllipsis refactor
Kranysys Apr 27, 2023
14226f3
feat(pagination): scss coding style, unit tests, fixes
Kranysys Apr 27, 2023
4dfab90
fix(pagination): totalPages to total, current
Kranysys Apr 27, 2023
db1f0ad
feat(pagination): events unit tests
Kranysys Apr 27, 2023
caf1ac0
fix(pagination): odsCurrentChange to odsPaginationChanged
Kranysys Apr 27, 2023
d80a84f
Merge branch 'master' into feat/pagination-component
Kranysys Apr 27, 2023
2e9d65b
feat(pagination): unit tests 100% events
Kranysys Apr 28, 2023
f95bcf0
feat(pagination): use css variables & theme
astagnol May 2, 2023
d10da55
fix(pagination): e2e test fixes
Kranysys May 2, 2023
87cd2c8
feat(pagination): testing onCurrentChange and odsPaginationChanged
Kranysys May 2, 2023
a6c133f
feat(pagination): updates for master, some fixes
Kranysys May 10, 2023
c217c1c
Merge branch 'master' into feat/pagination-component
Kranysys May 10, 2023
f17b80c
fix(pagination): 11.0.1 to 12.1.0
Kranysys May 10, 2023
2a08753
feat(pagination): testing controller with keyboard events
Kranysys May 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions packages/design/components/pagination/design-pagination.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## Preview

<osds-pagination current="5" total-pages="9"></osds-pagination>

## Description

Pagination helps to separate an important quantity of data into multiple pages, having links to the relative pages.

## Anatomy

Five areas are included in the component :

- Previous page arrow Button (presented as disabled)
- First page number Button
- Selected page Button
- (in situations) Truncated pagination (ellipsis Button)
- Next page arrow Button

## Colors

Only one color is applied on the Pagination: Primary.
The primary color from your theme is applied.

## Sizes

The Pagination exists in a unique size SM.

## Behaviours

A Pagination can be focused, hovered and disabled.
Current page Button has a selected styling, yet it is a not clickable Button (as readonly). Ellispsis Buttons are also not clickable.
If the selected page number is the first page, the previous page arrow Button is disabled; same thing applies with the last page as selected and the next page arrow Button disabled.

## Accessibility

All Buttons are accessible via tabulation controls.
You can select the page by pressing space or enter.
1 change: 1 addition & 0 deletions packages/libraries/core/scripts/generate-typedoc-md.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const components = [
'OdsLink',
'OdsLocationTile',
'OdsMessage',
'OdsPagination',
'OdsQuantity',
'OdsRadio',
'OdsRadioButton',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { OdsComponentAttributes } from '../ods-component-attributes';

export interface OdsPaginationAttributes extends OdsComponentAttributes {
/**
* indicates if the pagination is entirely disabled.
* it means no interactions (hover, click, focus, etc)
*/
disabled: boolean;
/**
* Its corresponding default current page. If no current page, it will be this page selected by default.
*/
defaultCurrent?: number;
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
/**
* Its corresponding current page.
*/
current: number;
/**
* The total amount of pages
*/
totalPages: number;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { OdsClearLoggerSpy, OdsInitializeLoggerSpy, OdsLoggerSpyReferences } from '@ovhcloud/ods-testing/src';

import { OdsLogger } from '../../logger/ods-logger';
import { OdsPagination } from './ods-pagination';
import { OdsPaginationController } from './ods-pagination-controller';
import { OdsPaginationMock } from './ods-pagination-mock';

describe('spec:ods-pagination-controller', () => {
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
let controller: OdsPaginationController;
let component: OdsPagination;
let loggerSpyReferences: OdsLoggerSpyReferences;

function setup(attributes: Partial<OdsPagination> = {}) {
component = { ...component, ...attributes };
controller = new OdsPaginationController(component);
}

beforeEach(() => {
component = new OdsPaginationMock();

const loggerMocked = new OdsLogger('myLoggerMocked');
loggerSpyReferences = OdsInitializeLoggerSpy({
loggerMocked: loggerMocked as never,
spiedClass: OdsPaginationController,
});
});

afterEach(() => {
OdsClearLoggerSpy(loggerSpyReferences);
jest.clearAllMocks();
});

describe('methods', () => {
describe('createPageList', () => {
it('should generate the correct number of pages', async () => {
const attributes = { disabled: false, current: 2, totalPages: 8 };
setup(attributes);
const pageList = controller.createPageList(component.totalPages, component.current);
expect(pageList).toHaveLength(8);
});

it('should generate the correct page list', async () => {
const attributes = { disabled: false, current: 2, totalPages: 9 };
setup(attributes);
const pageList = controller.createPageList(component.totalPages, component.current);

expect(pageList).toHaveLength(9);
expect(pageList[0].id).toEqual(1);
expect(pageList[1].id).toEqual(2);
expect(pageList[2].id).toEqual(3);
expect(pageList[3].id).toEqual(4);
expect(pageList[4].id).toEqual(5);
expect(pageList[5].id).toEqual(6);
expect(pageList[6].id).toEqual(7);
expect(pageList[7].id).toEqual(8);
expect(pageList[8].id).toEqual(9);
});

it('should display the correct page list following to the current page 5', async () => {
const attributes = { disabled: false, current: 5, totalPages: 9 };
setup(attributes);
const pageList = controller.createPageList(component.totalPages, component.current);

expect(pageList).toHaveLength(9);
expect(pageList[0].active).toBeTruthy();
expect(pageList[1].active).toBeFalsy();
expect(pageList[2].active).toBeFalsy();
expect(pageList[3].active).toBeTruthy();
expect(pageList[4].active).toBeTruthy();
expect(pageList[5].active).toBeTruthy();
expect(pageList[6].active).toBeFalsy();
expect(pageList[7].active).toBeFalsy();
expect(pageList[8].active).toBeTruthy();
});

it('should display the correct page list following to the current page 2', async () => {
const attributes = { disabled: false, current: 2, totalPages: 9 };
setup(attributes);
const pageList = controller.createPageList(component.totalPages, component.current);

expect(pageList).toHaveLength(9);
expect(pageList[0].active).toBeTruthy();
expect(pageList[1].active).toBeTruthy();
expect(pageList[2].active).toBeTruthy();
expect(pageList[3].active).toBeTruthy();
expect(pageList[4].active).toBeTruthy();
expect(pageList[5].active).toBeFalsy();
expect(pageList[6].active).toBeFalsy();
expect(pageList[7].active).toBeFalsy();
expect(pageList[8].active).toBeTruthy();
});

it('should display the correct page list following to the current page 3', async () => {
const attributes = { disabled: false, current: 3, totalPages: 9 };
setup(attributes);
const pageList = controller.createPageList(component.totalPages, component.current);

expect(pageList).toHaveLength(9);
expect(pageList[0].active).toBeTruthy();
expect(pageList[1].active).toBeTruthy();
expect(pageList[2].active).toBeTruthy();
expect(pageList[3].active).toBeTruthy();
expect(pageList[4].active).toBeTruthy();
expect(pageList[5].active).toBeFalsy();
expect(pageList[6].active).toBeFalsy();
expect(pageList[7].active).toBeFalsy();
expect(pageList[8].active).toBeTruthy();
});

it('should display the correct page list following to the current page 4', async () => {
const attributes = { disabled: false, current: 4, totalPages: 9 };
setup(attributes);
const pageList = controller.createPageList(component.totalPages, component.current);

expect(pageList).toHaveLength(9);
expect(pageList[0].active).toBeTruthy();
expect(pageList[1].active).toBeTruthy();
expect(pageList[2].active).toBeTruthy();
expect(pageList[3].active).toBeTruthy();
expect(pageList[4].active).toBeTruthy();
expect(pageList[5].active).toBeFalsy();
expect(pageList[6].active).toBeFalsy();
expect(pageList[7].active).toBeFalsy();
expect(pageList[8].active).toBeTruthy();
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { OdsComponentController } from '../ods-component-controller';
import { OdsPagination } from './ods-pagination';

/**
* common controller logic for pagination component used by the different implementations.
* it contains all the glue between framework implementation and the third party service.
*/
export class OdsPaginationController extends OdsComponentController<OdsPagination> {
constructor(component: OdsPagination) {
super(component);
}

createPageList(totalPages: number, pageSelected: number) {
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
let pageList = [];
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
for (let i = 1; i <= totalPages; i++) {
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
pageList.push({ id: i, active: false });
}

let startIndex = Math.max(pageSelected - 2, 1);
let endIndex = Math.min(startIndex + 4, totalPages);

if (totalPages <= 5) {
for (let i = 0; i < pageList.length; i++) {
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
pageList[i].active = true;
}
} else {
// >6
if (totalPages - pageSelected < 2) {
// last pages of a long list
startIndex = totalPages - 4;
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
}
if (totalPages > 5 && endIndex - startIndex < 4) {
if (startIndex === 1) {
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
endIndex = Math.min(startIndex + 5, totalPages);
} else if (endIndex === totalPages) {
startIndex = Math.max(endIndex - 5, 1);
}
}

for (let i = startIndex; i <= endIndex; i++) {
if (i == pageSelected - 2 && pageSelected < totalPages - 1 && pageSelected > 4 && pageSelected < totalPages - 2) {
continue;
}
if (i == pageSelected + 2 && pageSelected < totalPages - 3 && i > 5) {
continue;
}
pageList[i - 1].active = true;
}

if (startIndex > 1) {
pageList[0].active = true;
}

if (endIndex < totalPages) {
pageList[totalPages - 1].active = true;
}
}
return pageList;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface OdsPaginationCurrentChangeEventDetail {
current: number;
oldCurrent?: number;
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { OdsPaginationCurrentChangeEventDetail } from './ods-pagination-current-change-event-detail';

export type OdsPaginationCurrentChangeEvent = CustomEvent<OdsPaginationCurrentChangeEventDetail>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// import { OdsThemeColorIntent } from '@ovhcloud/ods-theming';
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
import { OdsPaginationAttributes } from './ods-pagination-attributes';

/**
* default attribute values of pagination
*/
export const odsPaginationDefaultAttributesDoc: OdsPaginationAttributes = {
disabled: false,
defaultCurrent: undefined,
current: 1,
totalPages: 1,
} as const;

export const odsPaginationDefaultAttributes = odsPaginationDefaultAttributesDoc as unknown as OdsPaginationAttributes;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { OdsComponentEvents } from '../ods-component-events';
import { OdsPaginationCurrentChangeEventDetail } from './ods-pagination-current-change-event-detail';

export interface OdsPaginationEvents extends OdsComponentEvents {
/**
* Emitted when the value has changed
*/
odsCurrentChange: OdsPaginationCurrentChangeEventDetail;
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { OdsComponentMethods } from '../ods-component-methods';

export interface OdsPaginationMethods extends OdsComponentMethods {
/**
* set page index on the component
*/
setPageIndex(value: number): void;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { OdsPagination } from './ods-pagination';
import { OdsPaginationController } from './ods-pagination-controller';
import { OdsPaginationEvents } from './ods-pagination-events';
import { OdsPaginationMethods } from './ods-pagination-methods';
import { OdsPaginationCurrentChangeEventDetail } from './ods-pagination-current-change-event-detail';

export class OdsPaginationMock implements OdsPagination<OdsPaginationMethods, OdsPaginationEvents> {
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
disabled: boolean = false;
Kranysys marked this conversation as resolved.
Show resolved Hide resolved
defaultCurrent?: number;
current: number = 1;
totalPages: number = 1;
Kranysys marked this conversation as resolved.
Show resolved Hide resolved

odsCurrentChange!: OdsPaginationCurrentChangeEventDetail;

controller: OdsPaginationController = jest.fn() as unknown as OdsPaginationController;

setPageIndex = jest.fn();

onKeyup = jest.fn();

emitChange = jest.fn();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { OdsComponentGenericMethods } from '../ods-component-generic-methods';
import { OdsComponentGenericEvents } from '../ods-component-generic-events';
import { OdsComponent } from '../ods-component';
import { OdsPaginationMethods } from './ods-pagination-methods';
import { OdsPaginationEvents } from './ods-pagination-events';
import { OdsPaginationAttributes } from './ods-pagination-attributes';
import { OdsPaginationController } from './ods-pagination-controller';

/**
* interface description of all implementation of `ods-pagination`.
* each implementation must have defined events, methods, attributes
* and one controller for the common behavior logic
*/
export type OdsPagination<
ComponentMethods extends OdsComponentGenericMethods<OdsPaginationMethods> = OdsComponentGenericMethods<OdsPaginationMethods>,
ComponentEvents extends OdsComponentGenericEvents<OdsPaginationEvents> = OdsComponentGenericEvents<OdsPaginationEvents>,
> = OdsComponent<ComponentMethods, ComponentEvents, OdsPaginationAttributes, OdsPaginationController>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export * from './ods-pagination';
export * from './ods-pagination-attributes';
export * from './ods-pagination-controller';
export * from './ods-pagination-default-attributes';
export * from './ods-pagination-events';
export * from './ods-pagination-methods';
export * from './ods-pagination-current-change-event';
export * from './ods-pagination-current-change-event-detail';
1 change: 1 addition & 0 deletions packages/libraries/core/src/components/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export * from './icon/public-api';
export * from './input/public-api';
export * from './link/public-api';
export * from './location-tile/public-api';
export * from './pagination/public-api';
export * from './message/public-api';
export * from './quantity/public-api';
export * from './radio/public-api';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { OdsPaginationAttributes } from '@ovhcloud/ods-core';

/**
* base attributes value of pagination
*/
export const odsPaginationBaseAttributes: OdsPaginationAttributes = {
disabled: false,
defaultCurrent: undefined,
current: 1,
totalPages: 1,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ods-pagination-base-attributes';
1 change: 1 addition & 0 deletions packages/libraries/testing/src/components/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export * from './input/public-api';
export * from './link/public-api';
export * from './location-tile/public-api';
export * from './message/public-api';
export * from './pagination/public-api';
export * from './quantity/public-api';
export * from './radio/public-api';
export * from './radio-button/public-api';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
| Name | Default | Description |
| ---- | ------- | ------------------------------------ |
| - | 🚫 | pagination main content (by default) |
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
| Name | type | Description |
| ------------------ | --------------------------------------- | -------------------- |
| `odsCurrentChange` | `OdsPaginationCurrentChangeEventDetail` | Current page changed |
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
| Name | Type | Description |
| -------------- | ------ | ------------------ |
| `setPageIndex` | `void` | Set Page pageindex |
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
| Name | Type | default | Description |
| ------------------ | --------- | ------- | ---------------------------- |
| `[disabled]` | `boolean` | `false` | Disabled state |
| `[currentDefault]` | `number` | `''` | Default curent selected page |
| `[current]` | `number` | `'1'` | The selected page |
| `[totalPages]` | `number` | `'1'` | The total number of pages |
Loading