index.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. const spinIconCls = cls({
  84. [`${prefixCls}-animate`]: loading,
  85. });
  86. return loading ? (
  87. <div className={`${prefixCls}-wrapper`}>
  88. {indicator ? (
  89. <div className={spinIconCls} x-semi-prop="indicator">
  90. {indicator}
  91. </div>
  92. ) : (
  93. <SpinIcon />
  94. )}
  95. {tip ? <div x-semi-prop="tip">{tip}</div> : null}
  96. </div>
  97. ) : null;
  98. }
  99. render() {
  100. this.foundation.updateLoadingIfNeedDelay();
  101. const { children, style, wrapperClassName, childStyle, size } = this.props;
  102. const { loading } = this.state;
  103. const spinCls = cls(
  104. prefixCls,
  105. wrapperClassName,
  106. {
  107. [`${prefixCls}-${size}`]: size,
  108. [`${prefixCls}-block`]: children,
  109. [`${prefixCls}-hidden`]: !loading,
  110. }
  111. );
  112. return (
  113. <div className={spinCls} style={style}>
  114. {this.renderSpin()}
  115. <div className={`${prefixCls}-children`} style={childStyle} x-semi-prop="children">
  116. {children}
  117. </div>
  118. </div>
  119. );
  120. }
  121. }
  122. export default Spin;