import type { ReactNode } from 'react'; import React from 'react'; import CloseOutlined from '@ant-design/icons/CloseOutlined'; import classNames from 'classnames'; import type { ButtonProps } from '../button'; import Button from '../button'; import { useLocale } from '../locale'; import defaultLocale from '../locale/en_US'; import type { TourStepProps } from './interface'; function isValidNode(node: ReactNode): boolean { return node !== undefined && node !== null; } interface TourPanelProps { stepProps: Omit & { closable?: Exclude; }; current: number; type: TourStepProps['type']; indicatorsRender?: TourStepProps['indicatorsRender']; } // Due to the independent design of Panel, it will be too coupled to put in rc-tour, // so a set of Panel logic is implemented separately in antd. const TourPanel: React.FC = (props) => { const { stepProps, current, type, indicatorsRender } = props; const { prefixCls, total = 1, title, onClose, onPrev, onNext, onFinish, cover, description, nextButtonProps, prevButtonProps, type: stepType, closable, } = stepProps; const mergedType = stepType ?? type; const mergedCloseIcon = React.useMemo(() => { let defaultCloseIcon: React.ReactNode = ; if (closable && closable.closeIcon) { defaultCloseIcon = closable.closeIcon; } return ( ); }, [closable]); const isLastStep = current === total - 1; const prevBtnClick = () => { onPrev?.(); prevButtonProps?.onClick?.(); }; const nextBtnClick = () => { if (isLastStep) { onFinish?.(); } else { onNext?.(); } nextButtonProps?.onClick?.(); }; const headerNode = isValidNode(title) ? (
{title}
) : null; const descriptionNode = isValidNode(description) ? (
{description}
) : null; const coverNode = isValidNode(cover) ?
{cover}
: null; let mergedIndicatorNode: ReactNode; if (indicatorsRender) { mergedIndicatorNode = indicatorsRender(current, total); } else { mergedIndicatorNode = [...Array.from({ length: total }).keys()].map( (stepItem, index) => ( ), ); } const mainBtnType = mergedType === 'primary' ? 'default' : 'primary'; const secondaryBtnProps: ButtonProps = { type: 'default', ghost: mergedType === 'primary', }; const [contextLocale] = useLocale('Tour', defaultLocale.Tour); return (
{closable && mergedCloseIcon} {coverNode} {headerNode} {descriptionNode}
{total > 1 &&
{mergedIndicatorNode}
}
{current !== 0 ? ( ) : null}
); }; export default TourPanel;