mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-05-15 08:58:22 +08:00
190 lines
4.6 KiB
TypeScript
190 lines
4.6 KiB
TypeScript
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
|