index.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import cls from 'classnames';
  4. import BaseComponent from '../_base/baseComponent';
  5. import { cssClasses as css, strings } from '@douyinfe/semi-foundation/spin/constants';
  6. import SpinFoundation from '@douyinfe/semi-foundation/spin/foundation';
  7. import SpinIcon from './icon';
  8. import '@douyinfe/semi-foundation/spin/spin.scss';
  9. const prefixCls = css.PREFIX;
  10. export type SpinSize = 'small' | 'large' | 'middle';
  11. export interface SpinProps {
  12. size?: SpinSize;
  13. spinning?: boolean;
  14. indicator?: React.ReactNode;
  15. delay?: number;
  16. tip?: React.ReactNode;
  17. wrapperClassName?: string;
  18. style?: React.CSSProperties;
  19. childStyle?: React.CSSProperties;
  20. children?: React.ReactNode
  21. }
  22. interface SpinState {
  23. delay: number;
  24. loading: boolean
  25. }
  26. class Spin extends BaseComponent<SpinProps, SpinState> {
  27. static propTypes = {
  28. size: PropTypes.oneOf(strings.SIZE),
  29. spinning: PropTypes.bool,
  30. children: PropTypes.node,
  31. indicator: PropTypes.node,
  32. delay: PropTypes.number,
  33. tip: PropTypes.node,
  34. wrapperClassName: PropTypes.string,
  35. childStyle: PropTypes.object,
  36. style: PropTypes.object,
  37. };
  38. static defaultProps: SpinProps = {
  39. size: 'middle',
  40. spinning: true,
  41. children: null,
  42. indicator: null,
  43. delay: 0,
  44. };
  45. constructor(props: SpinProps) {
  46. super(props);
  47. this.foundation = new SpinFoundation(this.adapter);
  48. this.state = {
  49. delay: props.delay,
  50. loading: true,
  51. };
  52. }
  53. static getDerivedStateFromProps(props: SpinProps) {
  54. if (!props.delay) {
  55. return {
  56. loading: props.spinning
  57. };
  58. }
  59. if (props.spinning === false) {
  60. return {
  61. delay: 0,
  62. loading: false
  63. };
  64. }
  65. return {
  66. delay: props.delay
  67. };
  68. }
  69. get adapter() {
  70. return {
  71. ...super.adapter,
  72. setLoading: (value: boolean) => {
  73. this.setState({ loading: value });
  74. }
  75. };
  76. }
  77. componentWillUnmount() {
  78. this.foundation.destroy();
  79. }
  80. renderSpin() {
  81. const { indicator, tip } = this.props;
  82. const { loading } = this.state;
  83. return loading ? <div className={`${prefixCls}-wrapper`}>
  84. {indicator ? (
  85. <div className={`${prefixCls}-animate`} x-semi-prop="indicator">
  86. {indicator}
  87. </div>
  88. ) : (
  89. <SpinIcon />
  90. )}
  91. {tip ? <div x-semi-prop="tip">{tip}</div> : null}
  92. </div>:null;
  93. }
  94. render() {
  95. this.foundation.updateLoadingIfNeedDelay();
  96. const { children, style, wrapperClassName, childStyle, size, ...rest } = this.props;
  97. const { loading } = this.state;
  98. const spinCls = cls(
  99. prefixCls,
  100. wrapperClassName,
  101. {
  102. [`${prefixCls}-${size}`]: size,
  103. [`${prefixCls}-block`]: children,
  104. [`${prefixCls}-hidden`]: !loading,
  105. }
  106. );
  107. return (
  108. <div className={spinCls} style={style} {...this.getDataAttr(rest)}>
  109. {this.renderSpin()}
  110. <div className={`${prefixCls}-children`} style={childStyle} x-semi-prop="children">
  111. {children}
  112. </div>
  113. </div>
  114. );
  115. }
  116. }
  117. export default Spin;