{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "pagination", "type": "registry:ui", "title": "Pagination", "description": "A pagination component that can be used to navigate through pages.", "registryDependencies": [ "@tra-kit/button", "@tra-kit/label" ], "files": [ { "path": "registry/tra-kit/components/pagination.tsx", "content": "import React from 'react';\r\nimport { cva, type VariantProps } from 'class-variance-authority';\r\nimport {\r\n CaretLeftIcon,\r\n CaretLineLeftIcon,\r\n CaretLineRightIcon,\r\n CaretRightIcon,\r\n} from '@phosphor-icons/react';\r\nimport { cn } from '@/lib/utils';\r\nimport Button, { type IButton } from './button';\r\nimport Input from './input';\r\n\r\nexport const paginationVariants = cva('', {\r\n variants: {\r\n status: {\r\n default: 'border-neutral-black/75 text-neutral-black/75 bg-transparent hover:bg-primary/40',\r\n active: '',\r\n disabled:\r\n 'border-neutral-disabled-text bg-neutral-disabled-text text-neutral-disabled-text cursor-not-allowed hover:bg-transparent',\r\n },\r\n size: {\r\n xs: 'size-6 min-h-6 min-w-6',\r\n sm: 'size-8 min-h-8 min-w-8',\r\n default: 'size-10 min-h-10 min-w-10',\r\n lg: 'size-12 min-h-12 min-w-12',\r\n xl: 'size-14 min-h-14 min-w-14',\r\n },\r\n },\r\n defaultVariants: {\r\n status: 'default',\r\n },\r\n});\r\n\r\ninterface IPagination extends VariantProps {\r\n mode?: 'default' | 'simple';\r\n totalPages: number;\r\n currentPage: number;\r\n onPageChange: (page: number) => void;\r\n maxVisiblePages?: number;\r\n color?: IButton['color'];\r\n variant?: IButton['variant'];\r\n rounded?: IButton['rounded'];\r\n hideFirstLastArrows?: boolean;\r\n hideNavigationArrows?: boolean;\r\n arrowsClassName?: string;\r\n size?: 'xs' | 'sm' | 'default' | 'lg' | 'xl';\r\n disabled?: boolean;\r\n simpleWithoutInput?: boolean;\r\n firstPageIconClassName?: string;\r\n lastPageIconClassName?: string;\r\n nextPageIconClassName?: string;\r\n previousPageIconClassName?: string;\r\n firstPageIcon?: React.ReactNode;\r\n lastPageIcon?: React.ReactNode;\r\n nextPageIcon?: React.ReactNode;\r\n previousPageIcon?: React.ReactNode;\r\n}\r\n\r\nconst Pagination: React.FC = ({\r\n mode = 'default',\r\n totalPages,\r\n currentPage,\r\n onPageChange,\r\n maxVisiblePages = 7,\r\n color,\r\n variant,\r\n hideFirstLastArrows = false,\r\n hideNavigationArrows = false,\r\n rounded = 'lg',\r\n arrowsClassName = '',\r\n size = 'default',\r\n disabled = false,\r\n simpleWithoutInput = false,\r\n firstPageIconClassName,\r\n lastPageIconClassName,\r\n nextPageIconClassName,\r\n previousPageIconClassName,\r\n firstPageIcon,\r\n lastPageIcon,\r\n nextPageIcon,\r\n previousPageIcon,\r\n}) => {\r\n const getPageNumbers = () => {\r\n const pageNumbers: (number | string)[] = [];\r\n const sidePages = Math.floor((maxVisiblePages - 3) / 2); // 3 is for current page and two ellipses\r\n\r\n if (totalPages <= maxVisiblePages) {\r\n return Array.from({ length: totalPages }, (_, i) => i + 1);\r\n }\r\n // Always add first page\r\n pageNumbers.push(1);\r\n if (currentPage - sidePages > 2) {\r\n pageNumbers.push('...');\r\n }\r\n // Calculate start and end of the central part\r\n let start = Math.max(2, currentPage - sidePages);\r\n let end = Math.min(totalPages - 1, currentPage + sidePages);\r\n // Adjust start and end if they are too close to the edges\r\n if (start <= 2) {\r\n start = 2;\r\n end = Math.min(totalPages - 1, start + maxVisiblePages - 4); // 4 is for first, last, and two ellipses\r\n }\r\n if (end >= totalPages - 1) {\r\n end = totalPages - 1;\r\n start = Math.max(2, end - maxVisiblePages + 4); // 4 is for first, last, and two ellipses\r\n }\r\n for (let i = start; i <= end; i++) {\r\n pageNumbers.push(i);\r\n }\r\n if (end < totalPages - 1) {\r\n pageNumbers.push('...');\r\n }\r\n // Always add last page\r\n if (totalPages !== 1) {\r\n pageNumbers.push(totalPages);\r\n }\r\n return pageNumbers;\r\n };\r\n\r\n const pageNumbers = getPageNumbers();\r\n\r\n return (\r\n \r\n {!hideFirstLastArrows && (\r\n onPageChange(1)}\r\n disabled={disabled ?? currentPage === 1}\r\n className={cn(\r\n paginationVariants({ size, status: currentPage === 1 ? 'disabled' : 'default' }),\r\n 'TraPagination-doubleLeft bg-transparent',\r\n arrowsClassName,\r\n )}\r\n color={color}\r\n aria-label=\"Go to first page\"\r\n title=\"Go to first page\"\r\n >\r\n {firstPageIcon ?? }\r\n \r\n )}\r\n {!hideNavigationArrows && (\r\n {\r\n if (currentPage > 1) onPageChange(currentPage - 1);\r\n }}\r\n disabled={disabled ?? currentPage === 1}\r\n className={cn(\r\n paginationVariants({ size, status: currentPage === 1 ? 'disabled' : 'default' }),\r\n 'TraPagination-left bg-transparent hover:bg-primary/90',\r\n arrowsClassName,\r\n )}\r\n color={color}\r\n aria-label=\"Previous page\"\r\n title=\"Previous page\"\r\n >\r\n {previousPageIcon ?? (\r\n \r\n )}\r\n \r\n )}\r\n {mode === 'simple' && simpleWithoutInput ? (\r\n
{`${currentPage} / ${totalPages}`}
\r\n ) : mode === 'simple' && !simpleWithoutInput ? (\r\n
\r\n {\r\n if (+e.target.value > totalPages) {\r\n onPageChange(totalPages);\r\n } else if (+e.target.value < 1) {\r\n onPageChange(1);\r\n } else {\r\n onPageChange(+e.target.value);\r\n }\r\n }}\r\n />\r\n /

{totalPages}

\r\n
\r\n ) : (\r\n <>\r\n {pageNumbers.map((page, index) => (\r\n \r\n {typeof page === 'number' ? (\r\n onPageChange(page)}\r\n className={cn(\r\n paginationVariants({\r\n size,\r\n status: page === currentPage ? 'active' : 'default',\r\n }),\r\n { 'TraPagination-selectedPageButton': page === currentPage },\r\n 'TraPagination-pageButton',\r\n )}\r\n color={color}\r\n aria-label={`Page ${page}`}\r\n title={`Page ${page}`}\r\n aria-current={page === currentPage ? 'page' : undefined}\r\n >\r\n {page}\r\n \r\n ) : (\r\n ...\r\n )}\r\n \r\n ))}\r\n \r\n )}\r\n {!hideNavigationArrows && (\r\n {\r\n if (currentPage < totalPages) onPageChange(currentPage + 1);\r\n }}\r\n disabled={disabled ?? currentPage === totalPages}\r\n className={cn(\r\n paginationVariants({\r\n size,\r\n status: currentPage === totalPages ? 'disabled' : 'default',\r\n }),\r\n 'bg-transparent',\r\n arrowsClassName,\r\n )}\r\n color={color}\r\n aria-label=\"Next page\"\r\n title=\"Next page\"\r\n >\r\n {nextPageIcon ?? }\r\n \r\n )}\r\n {!hideFirstLastArrows && (\r\n onPageChange(totalPages)}\r\n disabled={disabled ?? currentPage === totalPages}\r\n className={cn(\r\n paginationVariants({\r\n size,\r\n status: currentPage === totalPages ? 'disabled' : 'default',\r\n }),\r\n 'bg-transparent',\r\n arrowsClassName,\r\n )}\r\n color={color}\r\n aria-label=\"Go to last page\"\r\n title=\"Go to last page\"\r\n >\r\n {lastPageIcon ?? }\r\n \r\n )}\r\n \r\n );\r\n};\r\n\r\nexport default Pagination;\r\n", "type": "registry:ui" } ] }