index.tsx 4.1 KB

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