123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- import React from 'react'
- import clsx from 'clsx'
- import usePagination from './hook'
- import type {
- ButtonProps,
- IPagination,
- IPaginationProps,
- PageButtonProps,
- } from './type'
- const defaultState: IPagination = {
- currentPage: 0,
- setCurrentPage: () => {},
- truncableText: '...',
- truncableClassName: '',
- pages: [],
- hasPreviousPage: false,
- hasNextPage: false,
- previousPages: [],
- isPreviousTruncable: false,
- middlePages: [],
- isNextTruncable: false,
- nextPages: [],
- }
- const PaginationContext: React.Context<IPagination> = React.createContext<IPagination>(defaultState)
- export const PrevButton = ({
- className,
- children,
- dataTestId,
- as = <button />,
- ...buttonProps
- }: ButtonProps) => {
- const pagination = React.useContext(PaginationContext)
- const previous = () => {
- if (pagination.currentPage + 1 > 1)
- pagination.setCurrentPage(pagination.currentPage - 1)
- }
- const disabled = pagination.currentPage === 0
- return (
- <as.type
- {...buttonProps}
- {...as.props}
- className={clsx(className, as.props.className)}
- onClick={() => previous()}
- tabIndex={disabled ? '-1' : 0}
- disabled={disabled}
- data-testid={dataTestId}
- onKeyPress={(event: React.KeyboardEvent) => {
- event.preventDefault()
- if (event.key === 'Enter' && !disabled)
- previous()
- }}
- >
- {as.props.children ?? children}
- </as.type>
- )
- }
- export const NextButton = ({
- className,
- children,
- dataTestId,
- as = <button />,
- ...buttonProps
- }: ButtonProps) => {
- const pagination = React.useContext(PaginationContext)
- const next = () => {
- if (pagination.currentPage + 1 < pagination.pages.length)
- pagination.setCurrentPage(pagination.currentPage + 1)
- }
- const disabled = pagination.currentPage === pagination.pages.length - 1
- return (
- <as.type
- {...buttonProps}
- {...as.props}
- className={clsx(className, as.props.className)}
- onClick={() => next()}
- tabIndex={disabled ? '-1' : 0}
- disabled={disabled}
- data-testid={dataTestId}
- onKeyPress={(event: React.KeyboardEvent) => {
- event.preventDefault()
- if (event.key === 'Enter' && !disabled)
- next()
- }}
- >
- {as.props.children ?? children}
- </as.type>
- )
- }
- type ITruncableElementProps = {
- prev?: boolean
- }
- const TruncableElement = ({ prev }: ITruncableElementProps) => {
- const pagination: IPagination = React.useContext(PaginationContext)
- const {
- isPreviousTruncable,
- isNextTruncable,
- truncableText,
- truncableClassName,
- } = pagination
- return ((isPreviousTruncable && prev === true) || (isNextTruncable && !prev))
- ? (
- <li className={truncableClassName || undefined}>{truncableText}</li>
- )
- : null
- }
- export const PageButton = ({
- as = <a />,
- className,
- dataTestIdActive,
- dataTestIdInactive,
- activeClassName,
- inactiveClassName,
- renderExtraProps,
- }: PageButtonProps) => {
- const pagination: IPagination = React.useContext(PaginationContext)
- const renderPageButton = (page: number) => (
- <li key={page}>
- <as.type
- data-testid={
- clsx({
- [`${dataTestIdActive}`]:
- dataTestIdActive && pagination.currentPage + 1 === page,
- [`${dataTestIdInactive}-${page}`]:
- dataTestIdActive && pagination.currentPage + 1 !== page,
- }) || undefined
- }
- tabIndex={0}
- onKeyPress={(event: React.KeyboardEvent) => {
- if (event.key === 'Enter')
- pagination.setCurrentPage(page - 1)
- }}
- onClick={() => pagination.setCurrentPage(page - 1)}
- className={clsx(
- className,
- pagination.currentPage + 1 === page
- ? activeClassName
- : inactiveClassName,
- )}
- {...as.props}
- {...(renderExtraProps ? renderExtraProps(page) : {})}
- >
- {page}
- </as.type>
- </li>
- )
- return (
- <>
- {pagination.previousPages.map(renderPageButton)}
- <TruncableElement prev />
- {pagination.middlePages.map(renderPageButton)}
- <TruncableElement />
- {pagination.nextPages.map(renderPageButton)}
- </>
- )
- }
- export const Pagination = ({
- dataTestId,
- ...paginationProps
- }: IPaginationProps & { dataTestId?: string }) => {
- const pagination = usePagination(paginationProps)
- return (
- <PaginationContext.Provider value={pagination}>
- <div className={paginationProps.className} data-testid={dataTestId}>
- {paginationProps.children}
- </div>
- </PaginationContext.Provider>
- )
- }
- Pagination.PrevButton = PrevButton
- Pagination.NextButton = NextButton
- Pagination.PageButton = PageButton
|