import type { ReactNode } from 'react'; import React from 'react'; import CloseOutlined from '@ant-design/icons/CloseOutlined'; import classNames from 'classnames'; import pickAttrs from 'rc-util/lib/pickAttrs'; 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']; actionsRender?: TourStepProps['actionsRender']; } // 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, actionsRender } = props; const { prefixCls, total = 1, title, onClose, onPrev, onNext, onFinish, cover, description, nextButtonProps, prevButtonProps, type: stepType, closable, } = stepProps; const mergedType = stepType ?? type; const ariaProps = pickAttrs(closable ?? {}, true); const [contextLocaleGlobal] = useLocale('global', defaultLocale.global); const [contextLocaleTour] = useLocale('Tour', defaultLocale.Tour); const mergedCloseIcon = ( ); 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 defaultActionsNode = ( <> {current !== 0 ? ( ) : null} ); return (
{closable && mergedCloseIcon} {coverNode} {headerNode} {descriptionNode}
{total > 1 &&
{mergedIndicatorNode}
}
{actionsRender ? actionsRender(defaultActionsNode, { current, total }) : defaultActionsNode}
); }; export default TourPanel;