All files / src/stepper Stepper.tsx

100% Statements 4/4
100% Branches 8/8
100% Functions 2/2
100% Lines 4/4

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115                                                                                                                                                    4x 4x                   4x     20x                                                    
import React from "react";
import classNames from "classnames";
import { StyledProps } from "../_type";
import { useConfig } from "../_util/config-context";
 
export interface StepperProps extends StyledProps {
  /**
   * 步骤条的类型
   *
   * - `default` - 默认类型,一般用于提示用户在多步操作中进行到哪个步骤
   * - `process` - 用于展示一个流程说明,水平布局
   * - `process-vertical` - 用于展示一个流程说明,垂直布局
   * - `process-vertical-dot` 用于展示一个流程说明,垂直布局,并且用圆点表示步骤
   * @default "default"
   */
  type?: "default" | "process" | "process-vertical" | "process-vertical-dot";
 
  /**
   * 步骤条中步骤列表
   */
  steps: Step[];
 
  /**
   * 当前激活步骤的 `key`
   */
  current?: string;
 
  /**
   * 仅用做展示的步骤条,没有进度状态区分
   *
   * @default false
   */
  readonly?: boolean;
 
  /**
   * 步骤标题展示不换行
   *
   * @default false
   */
  nowrap?: boolean;
}
 
export interface Step {
  /**
   * 步骤条中步骤项 `id`,在同一个步骤条中不允许重复
   */
  id: string;
 
  /**
   * 步骤说明文本
   */
  label?: React.ReactNode;
 
  /**
   * 关于当前步骤的详细说明,适用于垂直布局的步骤
   */
  detail?: React.ReactNode;
 
  /**
   * 当前步骤到下一个步骤的提示内容
   * 可以描述步骤的预计耗时,或者通过条件等
   */
  tip?: React.ReactNode;
}
 
export function Stepper({
  type,
  steps,
  current,
  readonly,
  nowrap,
  className,
  style,
}: StepperProps) {
  const { classPrefix } = useConfig();
  const stepperClassName = classNames({
    [`${classPrefix}-step`]: true,
    [`${classPrefix}-step--alternative`]: type === "process",
    [`${classPrefix}-step--vertical`]: type === "process-vertical",
    [`${classPrefix}-step--dot`]: type === "process-vertical-dot",
    [`${classPrefix}-step--readonly`]: readonly,
    [`${classPrefix}-step--wrap-normal`]: nowrap,
    [className]: className,
  });
 
  return (
    <div className={stepperClassName} style={style}>
      {steps.map((step, index, steps) => (
        <div
          key={step.id}
          className={classNames(`${classPrefix}-step__item`, {
            "is-current": !readonly && step.id === current,
          })}
        >
          <div className={`${classPrefix}-step__num`}>{index + 1}</div>
          <div className={`${classPrefix}-step__content`}>
            <div className={`${classPrefix}-step__title`}>{step.label}</div>
            {step.detail && (
              <div className={`${classPrefix}-step__description`}>
                {step.detail}
              </div>
            )}
          </div>
          {step.tip && (
            <div className={`${classPrefix}-step__tips`}>{step.tip}</div>
          )}
          {index < steps.length - 1 && (
            <div className={`${classPrefix}-step__arrow`} />
          )}
        </div>
      ))}
    </div>
  );
}