# All files / src/Pagination Pagination.tsx

95.74% Statements 45/47
83.33% Branches 15/18
50% Functions 4/8
94.44% Lines 34/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    1303x
    3x
    3x
    3x

    3x
    3x

    3x

    3x
    8x
    8x
    8x
    8x

    8x
    8x

    8x

    1x

    3x

    8x

    8x
    8x
    8x
    8x
    8x
    8x
    8x
    8x
    8x

    8x
    8x
    8x

    24x

    24x

    8x

    3x
     import { ChevronLeft, ChevronRight } from '@procore/core-icons/dist'
    import { NumberFormatter } from '@procore/globalization-toolkit'
    import { useId } from '@react-aria/utils'
    import React from 'react'
    import { Selection } from '../MenuImperative/MenuImperative.types'
    import { useI18nContext } from '../_hooks/I18n'
    import {
      StyledButton,
      StyledContainer,
      StyledCurrentPage,
      StyledPageCount,
    } from './Pagination.styles'
    import {
      PaginationHook,
      PaginationHookConfig,
      PresetPaginationProps,
    } from './Pagination.types'
    import { PaginationSelect } from './PaginationSelect'

    function noop() {}

    const usePagination = ({
      activePage = 0,
      items = 0,
      onSelectPage = () => {},
      perPage = 0,
    }: PaginationHookConfig): PaginationHook => {
      const pages = Math.ceil(items / perPage)
      activePage = pages === 0 ? 0 : activePage

      return {
        end: Math.min(activePage * perPage, items),
        isFirst: activePage < 2,
        isLast: activePage === pages,
        pages,
        selectNext: () => onSelectPage(activePage + 1),
        selectPage: (selection: Selection) => onSelectPage(selection.item),
        selectPrev: () => onSelectPage(activePage - 1),
        start: Math.max((activePage - 1) * perPage + 1, 0),
      }
    }

    /**

     We paginate pages that display large data sets to our users. This helps reduce
     page load time and makes the data easier to navigate.

     Pagination is commonly seen on tool landing pages, where we display 150 objects
     or table rows per page.

     @since 10.19.0

     @see [Storybook](https://procore.github.io/core/core-react/latest/?path=/story/demos-pagination--demo)

     @see [Design Guidelines](https://design.procore.com/pagination)

     */
    export const Pagination = React.forwardRef<
      HTMLDivElement,
      PresetPaginationProps
    >(function Pagination(
      { activePage = 1, items, onSelectPage = noop, perPage = 50, ...props },
      ref
    ) {
      const {
        end,
        isFirst,
        isLast,
        pages,
        selectNext,
        selectPage,
        selectPrev,
        start,
      } = usePagination({
        activePage,
        items,
        onSelectPage,
        perPage,
      })

      const i18n = useI18nContext()
      const labelId = useId()
      const selectId = useId()

      function formattedNumber(items: number) {
        const formatter = new NumberFormatter({ locale: i18n.locale })

        return formatter.formatNumber(items)
      }

      return (
        <StyledContainer ref={ref} {...props}>
          <StyledPageCount ref={ref} italic color="gray45">
            {i18n.t('core.pagination.notation', {
              end: formattedNumber(end),
              start: formattedNumber(start),
              totalItems: formattedNumber(items || 0),
            })}
          </StyledPageCount>
          <StyledCurrentPage id={labelId}>
            {i18n.t('core.pagination.page')}:
          </StyledCurrentPage>
          <PaginationSelect
            activePage={activePage}
            aria-labelledby={`${labelId} ${selectId}`}
            disabled={pages <= 1}
            id={selectId}
            onSelect={selectPage}
            pages={pages}
          />
          <StyledButton
            disabled={isFirst}
            variant="tertiary"
            aria-label={i18n.t('core.pagination.prevPage')}
            icon={<ChevronLeft />}
            onClick={selectPrev}
          />
          <StyledButton
            disabled={isLast}
            variant="tertiary"
            aria-label={i18n.t('core.pagination.nextPage')}
            icon={<ChevronRight />}
            onClick={selectNext}
          />
        </StyledContainer>
      )
    })

    Pagination.displayName = 'Pagination'