Sider.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import React, { CSSProperties } from 'react';
  2. import cls from 'classnames';
  3. import PropTypes from 'prop-types';
  4. import { cssClasses, strings } from '@douyinfe/semi-foundation/layout/constants';
  5. import getDataAttr from '@douyinfe/semi-foundation/utils/getDataAttr';
  6. import LayoutContext from './layout-context';
  7. import { registerMediaQuery } from '../_utils';
  8. const responsiveMap: ResponsiveMap = {
  9. xs: '(max-width: 575px)',
  10. sm: '(min-width: 576px)',
  11. md: '(min-width: 768px)',
  12. lg: '(min-width: 992px)',
  13. xl: '(min-width: 1200px)',
  14. xxl: '(min-width: 1600px)',
  15. };
  16. export interface ResponsiveMap {
  17. xs: string;
  18. sm: string;
  19. md: string;
  20. lg: string;
  21. xl: string;
  22. xxl: string;
  23. }
  24. const generateId = ((): () => string => {
  25. let i = 0;
  26. return (): string => {
  27. i += 1;
  28. return `${cssClasses.PREFIX}-sider-${i}`;
  29. };
  30. })();
  31. const bpt = strings.BREAKPOINT;
  32. export interface SiderProps {
  33. prefixCls?: string;
  34. style?: CSSProperties;
  35. className?: string;
  36. breakpoint?: Array<keyof ResponsiveMap>;
  37. onBreakpoint?: (screen: keyof ResponsiveMap, match: boolean) => void;
  38. }
  39. class Sider extends React.PureComponent<SiderProps> {
  40. static propTypes = {
  41. prefixCls: PropTypes.string,
  42. style: PropTypes.object,
  43. className: PropTypes.string,
  44. breakpoint: PropTypes.arrayOf(PropTypes.oneOf(bpt)),
  45. onBreakpoint: PropTypes.func,
  46. };
  47. static defaultProps = {
  48. prefixCls: cssClasses.PREFIX,
  49. };
  50. static contextType = LayoutContext;
  51. unRegisters: Array<() => void> = [];
  52. uniqueId = '';
  53. constructor(props: SiderProps) {
  54. super(props);
  55. this.uniqueId = generateId();
  56. }
  57. componentDidMount(): void {
  58. const { breakpoint } = this.props;
  59. const matchBpt: Array<keyof ResponsiveMap> = Object.keys(responsiveMap).filter((item: keyof ResponsiveMap) => breakpoint && breakpoint.indexOf(item) !== -1) as any;
  60. const unRegisters = matchBpt.map(screen => registerMediaQuery(responsiveMap[screen], {
  61. match: () => {
  62. this.responsiveHandler(screen, true);
  63. },
  64. unmatch: () => {
  65. this.responsiveHandler(screen, false);
  66. },
  67. }));
  68. this.unRegisters = unRegisters;
  69. if (this.context.siderHook) {
  70. this.context.siderHook.addSider(this.uniqueId);
  71. }
  72. }
  73. componentWillUnmount(): void {
  74. this.unRegisters.forEach(unRegister => unRegister());
  75. if (this.context.siderHook) {
  76. this.context.siderHook.removeSider(this.uniqueId);
  77. }
  78. }
  79. responsiveHandler(screen: keyof ResponsiveMap, matches: boolean): void {
  80. const { onBreakpoint } = this.props;
  81. if (onBreakpoint) {
  82. onBreakpoint(screen, matches);
  83. }
  84. }
  85. render() {
  86. const { prefixCls, className, children, style, ...others } = this.props;
  87. const classString = cls(className, {
  88. [`${prefixCls}-sider`]: true,
  89. });
  90. return (
  91. <aside className={classString} style={style} {...getDataAttr(others)}>
  92. <div className={`${prefixCls}-sider-children`}>
  93. {children}
  94. </div>
  95. </aside>
  96. );
  97. }
  98. }
  99. export default Sider;