-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feat(web-react): Introduce UncontrolledPagination component
- Loading branch information
Showing
7 changed files
with
272 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
66 changes: 66 additions & 0 deletions
66
packages/web-react/src/components/Pagination/UncontrolledPagination.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import React from 'react'; | ||
import { SpiritUncontrolledPaginationProps } from '../../types/pagination'; | ||
import Pagination from './Pagination'; | ||
import PaginationItem from './PaginationItem'; | ||
import PaginationLink from './PaginationLink'; | ||
import PaginationLinkNext from './PaginationLinkNext'; | ||
import PaginationLinkPrevious from './PaginationLinkPrevious'; | ||
import { usePagination } from './usePagination'; | ||
|
||
export const UncontrolledPagination = (props: SpiritUncontrolledPaginationProps): JSX.Element => { | ||
const { | ||
accessibilityLabel, | ||
accessibilityLabelPrevious = 'Previous', | ||
accessibilityLabelNext = 'Next', | ||
defaultPage = 1, | ||
onChange, | ||
totalPages = 0, | ||
visiblePages = 5, | ||
...rest | ||
} = props; | ||
const { currentPage, pages, handlePageChange } = usePagination({ | ||
defaultPage, | ||
onChange, | ||
totalPages, | ||
visiblePages, | ||
}); | ||
|
||
return ( | ||
<Pagination {...rest}> | ||
{currentPage !== 1 && ( | ||
<PaginationLinkPrevious | ||
accessibilityLabel={accessibilityLabelPrevious} | ||
onClick={(event) => { | ||
event.preventDefault(); | ||
handlePageChange(currentPage - 1); | ||
}} | ||
/> | ||
)} | ||
{pages?.map((pageNumber: number) => ( | ||
<PaginationItem key={pageNumber}> | ||
<PaginationLink | ||
accessibilityLabel={`${accessibilityLabel} ${pageNumber}`} | ||
href="#" | ||
isCurrent={currentPage === pageNumber} | ||
pageNumber={pageNumber} | ||
onClick={(event) => { | ||
event.preventDefault(); | ||
handlePageChange(pageNumber); | ||
}} | ||
/> | ||
</PaginationItem> | ||
))} | ||
{currentPage !== totalPages && ( | ||
<PaginationLinkNext | ||
accessibilityLabel={accessibilityLabelNext} | ||
onClick={(event) => { | ||
event.preventDefault(); | ||
handlePageChange(currentPage + 1); | ||
}} | ||
/> | ||
)} | ||
</Pagination> | ||
); | ||
}; | ||
|
||
export default UncontrolledPagination; |
53 changes: 53 additions & 0 deletions
53
packages/web-react/src/components/Pagination/__tests__/UncontrolledPagination.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { fireEvent, render, screen } from '@testing-library/react'; | ||
import React from 'react'; | ||
import UncontrolledPagination from '../UncontrolledPagination'; | ||
|
||
describe('UncontrolledPagination', () => { | ||
const onPageChange = jest.fn(); | ||
|
||
beforeEach(() => { | ||
onPageChange.mockClear(); | ||
}); | ||
|
||
it('renders pagination items with test page selected', () => { | ||
render( | ||
<UncontrolledPagination accessibilityLabel="test page" totalPages={10} defaultPage={5} onChange={onPageChange} />, | ||
); | ||
|
||
const items = screen.getAllByRole('button'); | ||
expect(items).toHaveLength(2); | ||
|
||
const selectedPageItem = screen.getByText('test page 5').parentElement; | ||
expect(selectedPageItem).toHaveClass('Pagination__link Pagination__link--current'); | ||
}); | ||
|
||
it('renders disabled items for the first and last page', () => { | ||
const { container } = render( | ||
<UncontrolledPagination accessibilityLabel="test page" totalPages={10} defaultPage={1} onChange={onPageChange} />, | ||
); | ||
|
||
const items = screen.getAllByRole('button'); | ||
expect(items).toHaveLength(1); | ||
|
||
const firstPageItem = screen.getByText('test page 1').parentElement; | ||
const lastItemPage = container.querySelector('.Button--square'); | ||
|
||
expect(firstPageItem).toHaveClass('Pagination__link Pagination__link--current'); | ||
expect(lastItemPage).toHaveClass('Button Button--secondary Button--medium Button--square'); | ||
}); | ||
|
||
it('calls the onPageChange function when an item is clicked', () => { | ||
render( | ||
<UncontrolledPagination accessibilityLabel="test page" totalPages={10} defaultPage={5} onChange={onPageChange} />, | ||
); | ||
|
||
const items = screen.getAllByRole('button'); | ||
expect(items).toHaveLength(2); | ||
|
||
const nextPageItem = screen.getByText('test page 6'); | ||
|
||
fireEvent.click(nextPageItem); | ||
|
||
expect(onPageChange).toHaveBeenCalledWith(6); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
export { default as Pagination } from './Pagination'; | ||
export { default as PaginationButtonLink } from './PaginationButtonLink'; | ||
export { default as PaginationItem } from './PaginationItem'; | ||
export { default as PaginationLink } from './PaginationLink'; | ||
export { default as PaginationButtonLink } from './PaginationButtonLink'; | ||
export { default as PaginationLinkPrevious } from './PaginationLinkPrevious'; | ||
export { default as PaginationLinkNext } from './PaginationLinkNext'; | ||
export * from './usePaginationStyleProps'; | ||
export { default as PaginationLinkPrevious } from './PaginationLinkPrevious'; | ||
export * from './UncontrolledPagination'; | ||
export { default as UncontrolledPagination } from './UncontrolledPagination'; | ||
export * from './constants'; | ||
export * from './usePaginationStyleProps'; |
43 changes: 43 additions & 0 deletions
43
packages/web-react/src/components/Pagination/stories/UncontrolledPagination.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
import React from 'react'; | ||
|
||
import { UncontrolledPagination } from '..'; | ||
|
||
const meta: Meta<typeof UncontrolledPagination> = { | ||
title: 'Components/Pagination', | ||
component: UncontrolledPagination, | ||
parameters: { | ||
layout: 'centered', | ||
}, | ||
argTypes: { | ||
defaultPage: { | ||
control: 'number', | ||
description: 'Default page for the first render; please reload the page to apply this setting.', | ||
table: { | ||
defaultValue: { summary: 1 }, | ||
}, | ||
}, | ||
totalPages: { | ||
control: 'number', | ||
}, | ||
visiblePages: { | ||
control: 'number', | ||
table: { | ||
defaultValue: { summary: 5 }, | ||
}, | ||
}, | ||
}, | ||
args: { | ||
defaultPage: 3, | ||
totalPages: 10, | ||
visiblePages: 5, | ||
}, | ||
}; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof UncontrolledPagination>; | ||
|
||
export const UncontrolledPaginationPlayground: Story = { | ||
name: 'UncontrolledPagination', | ||
render: (args) => <UncontrolledPagination {...args} />, | ||
}; |
48 changes: 48 additions & 0 deletions
48
packages/web-react/src/components/Pagination/usePagination.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { useCallback, useMemo, useState } from 'react'; | ||
import { UsePaginationProps } from '../../types/pagination'; | ||
|
||
export const usePagination = ({ totalPages, onChange, defaultPage, visiblePages }: UsePaginationProps) => { | ||
const [currentPage, setCurrentPage] = useState(defaultPage <= 0 || defaultPage > totalPages ? 1 : defaultPage ?? 1); | ||
const [pages, setPagesArray] = useState([visiblePages] ?? [5]); | ||
|
||
useMemo(() => { | ||
const currentVisiblePages = visiblePages > totalPages ? totalPages : visiblePages; | ||
const firstPageChapter = | ||
totalPages - currentPage < currentVisiblePages ? totalPages - (currentVisiblePages - 1) : currentPage; | ||
|
||
setPagesArray(Array.from(Array(currentVisiblePages), (_, index) => index + firstPageChapter)); | ||
}, [visiblePages, currentPage, totalPages]); | ||
|
||
const handlePageChange = useCallback( | ||
(pageNumber: number) => { | ||
setCurrentPage(pageNumber); | ||
onChange && onChange(pageNumber); | ||
}, | ||
[onChange], | ||
); | ||
|
||
const getPagination = () => { | ||
const halfChap = Math.floor(visiblePages / 2); | ||
let startPage = Math.max(1, currentPage - halfChap); | ||
const endPage = Math.min(startPage + visiblePages - 1, totalPages); | ||
|
||
if (totalPages - visiblePages < startPage - 1) { | ||
const tmpStartPage = totalPages - visiblePages + 1; | ||
startPage = tmpStartPage < 1 ? 1 : tmpStartPage; | ||
} | ||
|
||
return Array.from({ length: endPage - startPage + 1 }, (_, i) => startPage + i); | ||
}; | ||
|
||
useMemo(() => { | ||
setPagesArray(getPagination()); | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
}, []); | ||
|
||
return { | ||
totalPages, | ||
currentPage, | ||
pages, | ||
handlePageChange, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters