index.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import React, { PureComponent } from 'react';
  2. import cls from 'classnames';
  3. import PropTypes from 'prop-types';
  4. import '@douyinfe/semi-foundation/timeline/timeline.scss';
  5. import { cssClasses, strings } from '@douyinfe/semi-foundation/timeline/constants';
  6. import ConfigContext from '../configProvider/context';
  7. import Item, { TimelineItemProps } from './item';
  8. export { TimelineItemProps } from './item';
  9. export interface Data extends TimelineItemProps {
  10. content: React.ReactNode;
  11. }
  12. export interface TimelineProps {
  13. mode?: 'left' | 'right' | 'center' | 'alternate';
  14. className?: string;
  15. style?: React.CSSProperties;
  16. dataSource?: Data[];
  17. }
  18. const prefixCls = cssClasses.PREFIX;
  19. class Timeline extends PureComponent<TimelineProps> {
  20. static contextType = ConfigContext;
  21. static Item = Item;
  22. static propTypes = {
  23. mode: PropTypes.oneOf(strings.MODE),
  24. className: PropTypes.string,
  25. style: PropTypes.object,
  26. dataSource: PropTypes.array,
  27. };
  28. static defaultProps = {
  29. mode: 'left',
  30. };
  31. getPosCls = (ele: React.ReactElement, idx: number) => {
  32. const { mode } = this.props;
  33. if (mode === 'alternate') {
  34. if (ele.props.position) {
  35. return `${prefixCls}-item-${ele.props.position}`;
  36. }
  37. return idx % 2 === 0 ? `${prefixCls}-item-left` : `${prefixCls}-item-right`;
  38. }
  39. if (mode === 'center') {
  40. if (ele.props.position) {
  41. return `${prefixCls}-item-${ele.props.position}`;
  42. }
  43. return `${prefixCls}-item-left`;
  44. }
  45. if (mode === 'left' || mode === 'right') {
  46. return `${prefixCls}-item-${mode}`;
  47. }
  48. if (ele.props.position) {
  49. return `${prefixCls}-item-${ele.props.position}`;
  50. }
  51. return '';
  52. };
  53. addClassName = (items: React.ReactNode) => React.Children.map(items, (ele, idx) => {
  54. if (React.isValidElement(ele)) {
  55. return React.cloneElement(ele, {
  56. className: cls(
  57. ele.props.className,
  58. this.getPosCls(ele, idx)
  59. ),
  60. });
  61. }
  62. return ele;
  63. });
  64. render() {
  65. const { children, className, style, mode, dataSource } = this.props;
  66. const classString = cls(
  67. prefixCls,
  68. className,
  69. { [`${prefixCls}-${mode}`]: mode }
  70. );
  71. let childrenList;
  72. if (dataSource && dataSource.length) {
  73. const items = dataSource.map(
  74. (item, index) => <Item key={`timeline-item-${index}`} {...item}>{item.content}</Item>
  75. );
  76. childrenList = this.addClassName(items);
  77. }
  78. const items = childrenList || this.addClassName(children);
  79. return (
  80. <ul style={style} className={classString}>
  81. {items}
  82. </ul>
  83. );
  84. }
  85. }
  86. export default Timeline;