Created
May 9, 2024 08:01
-
-
Save sprobejames/c452c0aca6310809ba0521f2e492f31b to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| 'use client'; | |
| import useControlled from './useControlled'; | |
| export default function usePagination(props = {}) { | |
| // keep default values in sync with @default tags in Pagination.propTypes | |
| const { | |
| boundaryCount = 1, | |
| componentName = 'usePagination', | |
| count = 1, | |
| defaultPage = 1, | |
| disabled = false, | |
| hideNextButton = false, | |
| hidePrevButton = false, | |
| onChange: handleChange, | |
| page: pageProp, | |
| showFirstButton = false, | |
| showLastButton = false, | |
| siblingCount = 1, | |
| ...other | |
| } = props; | |
| const [page, setPageState] = useControlled({ | |
| controlled: pageProp, | |
| default: defaultPage, | |
| name: componentName, | |
| state: 'page', | |
| }); | |
| const handleClick = (event, value) => { | |
| if (!pageProp) { | |
| setPageState(value); | |
| } | |
| if (handleChange) { | |
| handleChange(event, value); | |
| } | |
| }; | |
| // https://dev.to/namirsab/comment/2050 | |
| const range = (start, end) => { | |
| const length = end - start + 1; | |
| return Array.from({ length }, (_, i) => start + i); | |
| }; | |
| const startPages = range(1, Math.min(boundaryCount, count)); | |
| const endPages = range(Math.max(count - boundaryCount + 1, boundaryCount + 1), count); | |
| const siblingsStart = Math.max( | |
| Math.min( | |
| // Natural start | |
| page - siblingCount, | |
| // Lower boundary when page is high | |
| count - boundaryCount - siblingCount * 2 - 1 | |
| ), | |
| // Greater than startPages | |
| boundaryCount + 2 | |
| ); | |
| const siblingsEnd = Math.min( | |
| Math.max( | |
| // Natural end | |
| page + siblingCount, | |
| // Upper boundary when page is low | |
| boundaryCount + siblingCount * 2 + 2 | |
| ), | |
| // Less than endPages | |
| endPages.length > 0 ? endPages[0] - 2 : count - 1 | |
| ); | |
| // Basic list of items to render | |
| // for example itemList = ['first', 'previous', 1, 'ellipsis', 4, 5, 6, 'ellipsis', 10, 'next', 'last'] | |
| const itemList = [ | |
| ...(showFirstButton ? ['first'] : []), | |
| ...(hidePrevButton ? [] : ['previous']), | |
| ...startPages, | |
| // Start ellipsis | |
| ...(siblingsStart > boundaryCount + 2 | |
| ? ['start-ellipsis'] | |
| : boundaryCount + 1 < count - boundaryCount | |
| ? [boundaryCount + 1] | |
| : []), | |
| // Sibling pages | |
| ...range(siblingsStart, siblingsEnd), | |
| // End ellipsis | |
| ...(siblingsEnd < count - boundaryCount - 1 | |
| ? ['end-ellipsis'] | |
| : count - boundaryCount > boundaryCount | |
| ? [count - boundaryCount] | |
| : []), | |
| ...endPages, | |
| ...(hideNextButton ? [] : ['next']), | |
| ...(showLastButton ? ['last'] : []), | |
| ]; | |
| // Map the button type to its page number | |
| const buttonPage = (type) => { | |
| switch (type) { | |
| case 'first': | |
| return 1; | |
| case 'previous': | |
| return page - 1; | |
| case 'next': | |
| return page + 1; | |
| case 'last': | |
| return count; | |
| default: | |
| return null; | |
| } | |
| }; | |
| // Convert the basic item list to PaginationItem props objects | |
| const items = itemList.map((item) => { | |
| return typeof item === 'number' | |
| ? { | |
| onClick: (event) => { | |
| handleClick(event, item); | |
| }, | |
| type: 'page', | |
| page: item, | |
| selected: item === page, | |
| disabled, | |
| 'aria-current': item === page ? 'true' : undefined, | |
| } | |
| : { | |
| onClick: (event) => { | |
| handleClick(event, buttonPage(item)); | |
| }, | |
| type: item, | |
| page: buttonPage(item), | |
| selected: false, | |
| disabled: | |
| disabled || | |
| (item.indexOf('ellipsis') === -1 && | |
| (item === 'next' || item === 'last' ? page >= count : page <= 1)), | |
| }; | |
| }); | |
| return { | |
| items, | |
| ...other, | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment