navSteps.tsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import React, { cloneElement, Children, useMemo, isValidElement, ReactElement } from 'react';
  2. import PropTypes from 'prop-types';
  3. import getDataAttr from '@douyinfe/semi-foundation/utils/getDataAttr';
  4. import cls from 'classnames';
  5. import { stepsClasses as css } from '@douyinfe/semi-foundation/steps/constants';
  6. export type Size = 'default' | 'small';
  7. export interface NavStepsProps {
  8. prefixCls?: string;
  9. className?: string;
  10. style?: React.CSSProperties;
  11. current?: number;
  12. initial?: number;
  13. size?: Size;
  14. children?: React.ReactNode;
  15. onChange?: (current: number) => void;
  16. "aria-label"?: string
  17. }
  18. const Steps = (props: NavStepsProps) => {
  19. const { size, current, initial, children, prefixCls, className, style, onChange, ...rest } = props;
  20. const inner = useMemo(() => {
  21. const filteredChildren = Children.toArray(children).filter(c => isValidElement(c)) as Array<ReactElement>;
  22. const total = filteredChildren.length;
  23. const content = Children.map(filteredChildren, (child: React.ReactElement, index) => {
  24. if (!child) {
  25. return null;
  26. }
  27. const childProps = {
  28. index,
  29. total,
  30. ...child.props,
  31. };
  32. childProps.active = index === current;
  33. childProps.onChange = onChange ? () => {
  34. if (index !== current) {
  35. onChange(index + initial);
  36. }
  37. } : undefined;
  38. return cloneElement(child, { ...childProps });
  39. });
  40. return content;
  41. }, [children, prefixCls, current, size, initial, onChange]);
  42. const wrapperCls = cls(className, {
  43. [`${prefixCls}-nav`]: true,
  44. [`${prefixCls}-${size}`]: size !== 'default',
  45. });
  46. return (
  47. <div aria-label={props["aria-label"]} className={wrapperCls} style={style} {...getDataAttr(rest)}>
  48. {inner}
  49. </div>
  50. );
  51. };
  52. Steps.propTypes = {
  53. prefixCls: PropTypes.string,
  54. className: PropTypes.string,
  55. style: PropTypes.object,
  56. current: PropTypes.number,
  57. initial: PropTypes.number,
  58. size: PropTypes.oneOf(['small', 'default']),
  59. };
  60. Steps.defaultProps = {
  61. prefixCls: css.PREFIX,
  62. current: 0,
  63. direction: 'horizontal',
  64. size: 'default',
  65. initial: 0,
  66. status: 'process',
  67. };
  68. export default Steps;