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.