index.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import React from 'react';
  2. import cls from 'classnames';
  3. import { cssClasses, strings } from '@douyinfe/semi-foundation/empty/constants';
  4. import '@douyinfe/semi-foundation/empty/empty.scss';
  5. import Typography from '../typography';
  6. import BaseComponent from '../_base/baseComponent';
  7. import { ArrayElement } from '../_base/base';
  8. const prefixCls = cssClasses.PREFIX;
  9. interface SVGNode {
  10. id?: string;
  11. viewBox?: string;
  12. url?: string;
  13. }
  14. export interface EmptyProps {
  15. layout?: ArrayElement<typeof strings.LAYOUT>;
  16. imageStyle?: React.CSSProperties;
  17. title?: React.ReactNode;
  18. description?: React.ReactNode;
  19. image?: React.ReactNode | SVGNode;
  20. darkModeImage?: React.ReactNode | SVGNode;
  21. style?: React.CSSProperties;
  22. className?: string;
  23. children?: React.ReactNode;
  24. }
  25. interface EmptyState {
  26. mode: any;
  27. }
  28. export default class Empty extends BaseComponent<EmptyProps, EmptyState> {
  29. static defaultProps = {
  30. layout: 'vertical',
  31. };
  32. body: any;
  33. observer: MutationObserver;
  34. constructor(props: EmptyProps) {
  35. super(props);
  36. this.state = {
  37. mode: null
  38. };
  39. }
  40. componentDidMount(): void {
  41. if (this.props.darkModeImage) {
  42. this.body = window.document.body;
  43. this.updateMode();
  44. const config = { attributes: true, childList: false, subtree: false };
  45. this.observer = new MutationObserver(this.observe);
  46. this.observer.observe(this.body, config);
  47. }
  48. }
  49. componentWillUnmount(): void {
  50. this.observer && this.observer.disconnect();
  51. }
  52. observe = (mutationsList: any): void => {
  53. for (const mutation of mutationsList) {
  54. if (mutation.type === 'attributes' && mutation.attributeName === 'theme-mode') {
  55. this.updateMode();
  56. }
  57. }
  58. }
  59. updateMode = (): void => {
  60. const val = this.body.getAttribute('theme-mode');
  61. if (val !== this.state.mode) {
  62. this.setState({ mode: val });
  63. }
  64. }
  65. render(): JSX.Element {
  66. const { className, image, description, style, title, imageStyle, children, layout, darkModeImage } = this.props;
  67. const alt = typeof description === 'string' ? description : 'empty';
  68. const imgSrc = ((this.state.mode === 'dark') && darkModeImage) ? darkModeImage : image;
  69. let imageNode = null;
  70. if (typeof imgSrc === 'string') {
  71. imageNode = <img alt={alt} src={imgSrc}/>;
  72. } else if (imgSrc && 'id' in (imgSrc as any)) {
  73. imageNode = (
  74. <svg
  75. // className={iconCls}
  76. aria-hidden="true"
  77. >
  78. <use xlinkHref={`#${(imgSrc as any).id}`}/>
  79. </svg>
  80. );
  81. } else {
  82. imageNode = imgSrc;
  83. }
  84. const wrapperCls = cls(className, prefixCls, {
  85. [`${prefixCls}-${layout}`]: layout,
  86. });
  87. const titleProps = imageNode ?
  88. {
  89. heading: 4,
  90. } :
  91. {
  92. heading: 6,
  93. style: { fontWeight: 400 },
  94. };
  95. return (
  96. <div className={wrapperCls} style={style}>
  97. <div className={`${prefixCls}-image`} style={imageStyle} x-semi-prop="image,darkModeImage">
  98. {imageNode}
  99. </div>
  100. <div className={`${prefixCls}-content`}>
  101. {title ? (
  102. <Typography.Title {...(titleProps as any)} className={`${prefixCls}-title`} x-semi-prop="title">
  103. {title}
  104. </Typography.Title>
  105. ) : null}
  106. {description ? (
  107. <div className={`${prefixCls}-description`} x-semi-prop="description">
  108. {description}
  109. </div>
  110. ) : null}
  111. {children ? (
  112. <div className={`${prefixCls}-footer`} x-semi-prop="children">
  113. {children}
  114. </div>
  115. ) : null}
  116. </div>
  117. </div>
  118. );
  119. }
  120. }