fillSteps.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import React, { cloneElement, Children, useMemo } from 'react';
  2. import PropTypes from 'prop-types';
  3. import cls from 'classnames';
  4. import { stepsClasses as css } from '@douyinfe/semi-foundation/steps/constants';
  5. import { Row, Col } from '../grid';
  6. export type Status = 'wait' | 'process' | 'finish' | 'error' | 'warning';
  7. export type Direction = 'horizontal' | 'vertical';
  8. export interface FillStepsProps {
  9. prefixCls?: string;
  10. className?: string;
  11. current?: number;
  12. direction?: Direction;
  13. initial?: number;
  14. status?: Status;
  15. style?: React.CSSProperties;
  16. children?: React.ReactNode;
  17. onChange?: (current: number) => void;
  18. }
  19. const Steps = (props: FillStepsProps) => {
  20. const { current, status, children, prefixCls, initial, direction, className, style, onChange } = props;
  21. const inner = useMemo(() => {
  22. const filteredChildren = Children.toArray(children).filter(c => Boolean(c));
  23. const colStyle = direction === 'vertical' ? null : { width: `${100 / filteredChildren.length }%` };
  24. const content = Children.map(filteredChildren, (child: React.ReactElement, index) => {
  25. if (!child) {
  26. return null;
  27. }
  28. const stepNumber = initial + index;
  29. const childProps = {
  30. stepNumber: `${stepNumber + 1}`,
  31. direction,
  32. ...child.props,
  33. };
  34. if (status === 'error' && index === current - 1) {
  35. childProps.className = `${prefixCls}-next-error`;
  36. }
  37. if (!child.props.status) {
  38. if (stepNumber === current) {
  39. childProps.status = status;
  40. } else if (stepNumber < current) {
  41. childProps.status = 'finish';
  42. } else {
  43. childProps.status = 'wait';
  44. }
  45. }
  46. childProps.onChange = () => {
  47. if (index !== current) {
  48. onChange(index + initial);
  49. }
  50. };
  51. return <Col style={colStyle}>{cloneElement(child, { ...childProps })}</Col>;
  52. });
  53. return content;
  54. }, [children, initial, prefixCls, direction, status, current]);
  55. const wrapperCls = cls(className, {
  56. [prefixCls]: true,
  57. [`${prefixCls}-${ direction}`]: true
  58. });
  59. return (
  60. <div
  61. className={wrapperCls}
  62. style={style}
  63. >
  64. <Row type="flex" justify="start">
  65. {inner}
  66. </Row>
  67. </div>
  68. );
  69. };
  70. Steps.propTypes = {
  71. prefixCls: PropTypes.string,
  72. className: PropTypes.string,
  73. style: PropTypes.object,
  74. current: PropTypes.number,
  75. initial: PropTypes.number,
  76. direction: PropTypes.oneOf(['horizontal', 'vertical']),
  77. status: PropTypes.oneOf(['wait', 'process', 'finish', 'error', 'warning'])
  78. };
  79. Steps.defaultProps = {
  80. prefixCls: css.PREFIX,
  81. current: 0,
  82. direction: 'horizontal',
  83. initial: 0,
  84. status: 'process',
  85. };
  86. export default Steps;