import React, { CSSProperties, PropsWithChildren, createContext, cloneElement, isValidElement, HTMLAttributes } from 'react' import classNames from 'classnames' import { usePrefix } from '../ConfigProvider' import { concat, isDev } from '../utils' import Step, { StepProps } from './Item' import { WithRef } from '../utils/type' export { default as Step } from './Item' export type { StepProps } from './Item' export type StepsProps = { className?: string /** * 步骤条方向 * @default horizontal */ direction?: 'horizontal' | 'vertical' /** * 当前序号,从 0 开始计数 * @default 0 */ current?: number /** * 传递该参数时,步骤条可点击切换 */ onChange?: (current: number) => void /** * 当前步骤的状态 * @default process */ status?: StepStatus /** * 每个步骤项的标题放置位置,仅在步骤条为水平方向时生效,放置到图标右侧时步骤项的描述不展示 * @default bottom */ labelPlacement?: 'bottom' | 'right' style?: CSSProperties /** * 根元素的 html 属性 */ rootHtmlProps?: WithRef, HTMLDivElement> } export type StepStatus = 'process' | 'finish' | 'error' | 'wait' type StepsContext = { current: number status: StepStatus onChange?: (current: number) => void } export const stepsContext = createContext({ current: 0, status: 'process' }) export default function Steps(props: PropsWithChildren) { const { className, style, children, current = 0, direction = 'horizontal', status = 'process', labelPlacement = 'bottom', onChange, rootHtmlProps } = props const prefix = usePrefix('steps') const labelRightDisplayed = direction === 'horizontal' && labelPlacement === 'right' const stepsClassName = classNames(prefix, className, { [concat(prefix, direction)]: true, [concat(prefix, 'clickable')]: onChange != null, [concat(prefix, 'label-placement', labelPlacement)]: labelRightDisplayed }, rootHtmlProps?.className) return (
{React.Children.map(children, (item, number) => { if (!isValidElement(item)) { return null } const { description } = item.props as StepProps if (isDev) { if (item.type !== Step) { console.warn('`Steps` only accepts children of type `Step`.') } if (labelRightDisplayed && description != null) { console.warn('`description` will not be displayed when `labelPlacement` value is `right`.') } } return cloneElement(item, { number }) })}
) }