index.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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/collapse/constants';
  5. import CollapseFoundation, {
  6. ArgsType,
  7. CollapseAdapter,
  8. CollapseProps,
  9. CollapseState
  10. } from '@douyinfe/semi-foundation/collapse/foundation';
  11. import BaseComponent from '../_base/baseComponent';
  12. import CollapsePanel from './item';
  13. import '@douyinfe/semi-foundation/collapse/collapse.scss';
  14. import { noop } from '@douyinfe/semi-foundation/utils/function';
  15. import { isEqual } from 'lodash';
  16. import CollapseContext from './collapse-context';
  17. export { CollapsePanelProps } from './item';
  18. export interface CollapseReactProps extends CollapseProps{
  19. expandIcon?: React.ReactNode;
  20. collapseIcon?: React.ReactNode;
  21. style?: CSSProperties;
  22. onChange?: (activeKey: CollapseProps['activeKey'], e: React.MouseEvent) => void;
  23. }
  24. export { CollapseState };
  25. class Collapse extends BaseComponent<CollapseReactProps, CollapseState> {
  26. static Panel = CollapsePanel;
  27. static propTypes = {
  28. activeKey: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
  29. defaultActiveKey: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
  30. accordion: PropTypes.bool,
  31. onChange: PropTypes.func,
  32. expandIcon: PropTypes.node,
  33. collapseIcon: PropTypes.node,
  34. style: PropTypes.object,
  35. className: PropTypes.string,
  36. keepDOM: PropTypes.bool,
  37. motion: PropTypes.oneOfType([PropTypes.bool, PropTypes.func, PropTypes.object]),
  38. expandIconPosition: PropTypes.oneOf(strings.iconPosition)
  39. };
  40. static defaultProps = {
  41. defaultActiveKey: '',
  42. onChange: noop,
  43. expandIconPosition: 'right'
  44. };
  45. constructor(props: CollapseReactProps) {
  46. super(props);
  47. this.foundation = new CollapseFoundation(this.adapter);
  48. const initKeys = this.foundation.initActiveKey();
  49. this.state = {
  50. activeSet: new Set(initKeys)
  51. };
  52. this.onChange = this.onChange.bind(this);
  53. }
  54. get adapter(): CollapseAdapter {
  55. return {
  56. ...super.adapter,
  57. handleChange: (activeKey: CollapseProps['activeKey'], e: React.MouseEvent) => this.props.onChange(activeKey, e),
  58. addActiveKey: (activeSet: CollapseState['activeSet']) => this.setState({ activeSet }),
  59. };
  60. }
  61. static getDerivedStateFromProps(props: CollapseReactProps, state: CollapseState) {
  62. if (props.activeKey) {
  63. const keys = Array.isArray(props.activeKey) ? props.activeKey : [props.activeKey];
  64. const newSet = new Set(keys);
  65. if (!isEqual(newSet, state.activeSet)) {
  66. return {
  67. ...state,
  68. activeSet: newSet,
  69. };
  70. }
  71. return state;
  72. }
  73. return state;
  74. }
  75. componentWillUnmount() {
  76. this.foundation.destroy();
  77. }
  78. onChange = (activeKey: string, e: React.MouseEvent) => {
  79. this.foundation.handleChange(activeKey, e);
  80. };
  81. render() {
  82. // eslint-disable-next-line max-len
  83. const { defaultActiveKey, accordion, style, motion, className, keepDOM, expandIconPosition, expandIcon, collapseIcon, children, ...rest } = this.props;
  84. const clsPrefix = cls(cssClasses.PREFIX, className);
  85. const { activeSet } = this.state;
  86. return (
  87. <div className={clsPrefix} style={style}>
  88. <CollapseContext.Provider
  89. value={{
  90. activeSet,
  91. expandIcon,
  92. collapseIcon,
  93. keepDOM,
  94. expandIconPosition,
  95. onClick: this.onChange,
  96. motion
  97. }}
  98. >
  99. {children}
  100. </CollapseContext.Provider>
  101. </div>
  102. );
  103. }
  104. }
  105. export default Collapse;