index.tsx 3.6 KB

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