Skip to content

Commit

Permalink
feat(pagination): update component lifecycle by playing with the disp…
Browse files Browse the repository at this point in the history
…lay rather than re-renders
  • Loading branch information
Leotheluck authored and dpellier committed Jul 29, 2024
1 parent af1620b commit c560404
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,15 @@
}

&__button::part(button) {
display: flex;
display: none;
justify-content: center;
width: 2.5rem;
}

&__button--visible::part(button) {
display: flex;
}

&__button--selected::part(button) {
border-color: var(--ods-color-primary-800);
background-color: var(--ods-color-primary-800);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,14 @@ export class OdsPagination {
private leftArrowButtonId = 'pagination-left-arrow';
private rightArrowButtonId = 'pagination-right-arrow';
private hostId: string = '';
private maxPagesBeforeEllipsis = 6;
private minCurrentPageForRightEllipsis = 4;
private pagesBeforeEnd = 3;
private maxVisibleItems = 7;
private ellipsisThreshold = 4;

@Element() el!: HTMLElement;

@State() itemPerPage = ODS_PAGINATION_PER_PAGE.option_10;
@State() pageList: OdsPaginationPageList = [];
@State() current: number = 1;
@State() isPageKeyUp: boolean = false;

@Prop({ reflect: true }) public defaultCurrentPage: number = 1;
/** @docType OdsPaginationPerPage */
Expand Down Expand Up @@ -64,7 +62,7 @@ export class OdsPagination {

@Watch('current')
async onCurrentChange(current: number, oldCurrent?: number): Promise<void> {
this.updatePageList();
this.updatePageVisibility();
this.emitChange(current, oldCurrent);
}

Expand All @@ -74,6 +72,7 @@ export class OdsPagination {
this.actualTotalPages = this.totalPages;
}
this.updatePageList();
this.updatePageVisibility();
}

@Watch('itemPerPage')
Expand Down Expand Up @@ -118,27 +117,46 @@ export class OdsPagination {
this.current = getActualPage(this.defaultCurrentPage, this.actualTotalPages, this.current);

this.updatePageList();
this.updatePageVisibility();
this.isFirstLoad = false;
}

componentDidRender(): void {
if (this.isPageKeyUp) {
const allButtons = this.el.shadowRoot?.querySelectorAll('ods-button');
if (allButtons) {
allButtons.forEach((button) => {
if (button.getAttribute('label') === `${this.current}`) {
const shadowButton = button.shadowRoot?.querySelector('button');
if (shadowButton) {
shadowButton.focus();
}
}
});
}
}
private updatePageList(): void {
this.pageList = createPageList(this.actualTotalPages, this.current).map((page) => ({
...page,
isVisible: false,
}));
}

private updatePageList(): void {
this.pageList = createPageList(this.actualTotalPages, this.current);
private updatePageVisibility(): void {
const maxVisibleItems = 7;

this.pageList.forEach((page, index) => {
const pageId = index + 1;

if (pageId === 1 || pageId === this.actualTotalPages) {
page.isVisible = true;
} else if (this.actualTotalPages <= maxVisibleItems) {
page.isVisible = true;
} else if (this.current <= this.ellipsisThreshold) {
page.isVisible = pageId <= maxVisibleItems - 2;
} else if (this.current >= this.actualTotalPages - this.ellipsisThreshold) {
page.isVisible = pageId >= this.actualTotalPages - (maxVisibleItems - 3);
} else {
page.isVisible = pageId >= this.current - 1 && pageId <= this.current + 1;
}
});

const visiblePages = this.pageList.filter((page) => page.isVisible);
if (visiblePages.length > maxVisibleItems) {
if (this.current > this.ellipsisThreshold && this.current < this.actualTotalPages - this.ellipsisThreshold) {
visiblePages[1].isVisible = false;
} else if (this.current <= this.ellipsisThreshold) {
visiblePages[visiblePages.length - 2].isVisible = false;
} else {
visiblePages[1].isVisible = false;
}
}
}

private emitChange(current: number, oldCurrent?: number): void {
Expand All @@ -153,20 +171,18 @@ export class OdsPagination {
this.actualTotalPages = computeActualTotalPages(this.itemPerPage, this.totalItems, this.totalPages);

if (this.current === 1) {
// If current is already 1 we don't want to emit a change event
this.updatePageList();
this.updatePageVisibility();
} else {
await this.setCurrentPage(1);
}
}

private handlePreviousClick(page: number): void {
this.isPageKeyUp = false;
this.setCurrentPage(page - 1);
}

private handleNextClick(page: number): void {
this.isPageKeyUp = false;
this.setCurrentPage(page + 1);
}

Expand All @@ -176,20 +192,17 @@ export class OdsPagination {

private handlePreviousKeyUp(event: KeyboardEvent, page: number): void {
if (this.current > 1) {
this.isPageKeyUp = false;
this.onKeyUp(event, page - 1);
}
}

private handleNextKeyUp(event: KeyboardEvent, page: number): void {
if (this.current < this.pageList.length) {
this.isPageKeyUp = false;
this.onKeyUp(event, page + 1);
}
}

private handlePageKeyUp(event: KeyboardEvent, page: number): void {
this.isPageKeyUp = true;
this.onKeyUp(event, page);
}

Expand Down Expand Up @@ -249,15 +262,15 @@ export class OdsPagination {
);
}

private renderEllipsis(): typeof Fragment {
private renderEllipsis(key: string): typeof Fragment {
return (
<li>
<li key={key}>
<ods-button
class="ods-pagination__list__page__ellipsis"
color={ ODS_BUTTON_COLOR.primary }
isDisabled={ true }
color={ODS_BUTTON_COLOR.primary}
isDisabled={true}
label="&#x2026;"
variant={ ODS_BUTTON_VARIANT.ghost }
variant={ODS_BUTTON_VARIANT.ghost}
>
</ods-button>
</li>
Expand All @@ -269,11 +282,14 @@ export class OdsPagination {
return;
}

const renderEllipsisLeft = this.current > this.ellipsisThreshold && this.actualTotalPages > this.maxVisibleItems;
const renderEllipsisRight = this.current < this.actualTotalPages - this.ellipsisThreshold && this.actualTotalPages > this.maxVisibleItems;

return (
<Host
class="ods-pagination"
isDisabled={this.isDisabled}
id={ this.hostId }
id={this.hostId}
>
{
!!this.totalItems &&
Expand All @@ -294,7 +310,7 @@ export class OdsPagination {
}
</ods-select>
}
<ods-text preset={ ODS_TEXT_PRESET.label }>
<ods-text preset={ODS_TEXT_PRESET.label}>
<slot name="before-total-items"></slot>
{this.totalItems}
<slot name="after-total-items"></slot>
Expand All @@ -303,47 +319,76 @@ export class OdsPagination {
}

<ul class="ods-pagination__list">
{ this.renderArrow( 'left' ) }

{
this.pageList
.filter((page) => page.active)
.map((page) => {
const pageId = this.pageList.indexOf(page) + 1;
const shouldRenderLeftEllipsis = this.pageList.length > this.maxPagesBeforeEllipsis && this.pageList.length - this.current > this.pagesBeforeEnd && pageId === this.pageList.length;
const shouldRenderRightEllipsis = this.pageList.length > this.maxPagesBeforeEllipsis && this.current > this.minCurrentPageForRightEllipsis && pageId === 1;

shouldRenderLeftEllipsis || shouldRenderRightEllipsis && this.renderEllipsis();

return (
<div class="ods-pagination__list__page">
{ shouldRenderLeftEllipsis && this.renderEllipsis() }

<li>
<ods-button
key={pageId}
class={{
'ods-pagination__list__page__button': true,
'ods-pagination__list__page__button--selected': this.current === pageId,
}}
variant={this.current === pageId ? ODS_BUTTON_VARIANT.default : ODS_BUTTON_VARIANT.ghost}
isDisabled={this.isDisabled}
label={`${pageId}`}
color={ODS_BUTTON_COLOR.primary}
size={ODS_BUTTON_SIZE.md}
onClick={(): void => this.handlePageClick(pageId)}
onKeyUp={(event: KeyboardEvent): void => this.handlePageKeyUp(event, pageId)}
>
</ods-button>
</li>

{ shouldRenderRightEllipsis && this.renderEllipsis() }
</div>
);
})
}

{ this.renderArrow( 'right' ) }
{this.renderArrow('left')}

{(this.totalItems || this.actualTotalPages > 1) && (
<li key={1}>
<ods-button
class={{
'ods-pagination__list__page__button': true,
'ods-pagination__list__page__button--selected': this.current === 1,
'ods-pagination__list__page__button--visible': true,
}}
variant={this.current === 1 ? ODS_BUTTON_VARIANT.default : ODS_BUTTON_VARIANT.ghost}
isDisabled={this.isDisabled}
label={'1'}
color={ODS_BUTTON_COLOR.primary}
size={ODS_BUTTON_SIZE.md}
onClick={(): void => this.handlePageClick(1)}
onKeyUp={(event: KeyboardEvent): void => this.handlePageKeyUp(event, 1)}
>
</ods-button>
</li>
)}

{renderEllipsisLeft && this.renderEllipsis('left')}

{this.pageList.slice(1, this.pageList.length - 1).map((page, index) => {
const pageId = index + 2;
return (
<li key={pageId}>
<ods-button
class={{
'ods-pagination__list__page__button': true,
'ods-pagination__list__page__button--selected': this.current === pageId,
'ods-pagination__list__page__button--visible': page.isVisible,
}}
variant={this.current === pageId ? ODS_BUTTON_VARIANT.default : ODS_BUTTON_VARIANT.ghost}
isDisabled={this.isDisabled}
label={`${pageId}`}
color={ODS_BUTTON_COLOR.primary}
size={ODS_BUTTON_SIZE.md}
onClick={(): void => this.handlePageClick(pageId)}
onKeyUp={(event: KeyboardEvent): void => this.handlePageKeyUp(event, pageId)}
>
</ods-button>
</li>
);
})}

{renderEllipsisRight && this.renderEllipsis('right')}

{this.actualTotalPages > 1 && (
<li key={this.actualTotalPages}>
<ods-button
class={{
'ods-pagination__list__page__button': true,
'ods-pagination__list__page__button--selected': this.current === this.actualTotalPages,
'ods-pagination__list__page__button--visible': true,
}}
variant={this.current === this.actualTotalPages ? ODS_BUTTON_VARIANT.default : ODS_BUTTON_VARIANT.ghost}
isDisabled={this.isDisabled}
label={`${this.actualTotalPages}`}
color={ODS_BUTTON_COLOR.primary}
size={ODS_BUTTON_SIZE.md}
onClick={(): void => this.handlePageClick(this.actualTotalPages)}
onKeyUp={(event: KeyboardEvent): void => this.handlePageKeyUp(event, this.actualTotalPages)}
>
</ods-button>
</li>
)}

{this.renderArrow('right')}
</ul>
</Host>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function createPageList(totalPages: number, pageSelected: number): OdsPagination

// Create initial pageList with 'active' property set to false for each page.
for (let i = 1; i <= totalPages; i++) {
pageList.push({ active: false });
pageList.push({ active: false, isVisible: false });
}

let startIndex = Math.max(pageSelected - 2, 1);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
interface OdsPaginationPageContent {
active: boolean;
isVisible: boolean;
}

type OdsPaginationPageList = Array<OdsPaginationPageContent>;
Expand Down

0 comments on commit c560404

Please sign in to comment.
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy