item.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import React, { PureComponent, ReactNode, CSSProperties } from 'react';
  2. import cls from 'classnames';
  3. import PropTypes from 'prop-types';
  4. import { cssClasses } from '@douyinfe/semi-foundation/collapse/constants';
  5. import Collapsible from '../collapsible';
  6. import CollapseContext, { CollapseContextType } from './collapse-context';
  7. import { IconChevronDown, IconChevronUp } from '@douyinfe/semi-icons';
  8. export interface CollapsePanelProps{
  9. itemKey: string;
  10. extra?: ReactNode;
  11. header?: ReactNode;
  12. className?: string;
  13. reCalcKey?: number | string;
  14. style?: CSSProperties;
  15. }
  16. export default class CollapsePanel extends PureComponent<CollapsePanelProps> {
  17. static contextType: React.Context<CollapseContextType> = CollapseContext;
  18. static propTypes = {
  19. itemKey: PropTypes.string,
  20. extra: PropTypes.node,
  21. header: PropTypes.oneOfType([
  22. PropTypes.string,
  23. PropTypes.node,
  24. ]),
  25. className: PropTypes.string,
  26. reCalcKey: PropTypes.oneOfType([
  27. PropTypes.string,
  28. PropTypes.number,
  29. ]),
  30. };
  31. renderHeader(active: boolean, expandIconEnable = true) {
  32. const {
  33. header,
  34. extra,
  35. } = this.props;
  36. let {
  37. expandIcon,
  38. collapseIcon,
  39. } = this.context;
  40. const { expandIconPosition } = this.context;
  41. if (typeof expandIcon === 'undefined') {
  42. expandIcon = (<IconChevronDown />);
  43. }
  44. if (typeof collapseIcon === 'undefined') {
  45. collapseIcon = (<IconChevronUp />);
  46. }
  47. const icon = (
  48. <span className={cls([`${cssClasses.PREFIX}-header-icon`,
  49. { [`${cssClasses.PREFIX}-header-iconDisabled`]: !expandIconEnable }])}>
  50. {/* eslint-disable-next-line no-nested-ternary */}
  51. {expandIconEnable ? (active ? collapseIcon : expandIcon) : expandIcon}
  52. </span>
  53. );
  54. const iconPosLeft = expandIconPosition === 'left';
  55. if (typeof header === 'string') {
  56. return (
  57. <>
  58. {iconPosLeft ? icon : null}
  59. <span>{header}</span>
  60. <span className={`${cssClasses.PREFIX}-header-right`}>
  61. <span>{extra}</span>
  62. {iconPosLeft ? null : icon}
  63. </span>
  64. </>
  65. );
  66. }
  67. return (
  68. <>
  69. {iconPosLeft ? icon : null}
  70. {header}
  71. {iconPosLeft ? null : icon}
  72. </>
  73. );
  74. }
  75. render() {
  76. const {
  77. className,
  78. children,
  79. itemKey,
  80. reCalcKey,
  81. ...restProps
  82. } = this.props;
  83. const {
  84. keepDOM,
  85. expandIconPosition,
  86. activeSet,
  87. onClick,
  88. motion,
  89. } = this.context;
  90. const active = activeSet.has(itemKey);
  91. const itemCls = cls(className, {
  92. [`${cssClasses.PREFIX}-item`]: true,
  93. });
  94. const headerCls = cls({
  95. [`${cssClasses.PREFIX}-header`]: true,
  96. [`${cssClasses.PREFIX}-header-iconLeft`]: expandIconPosition === 'left',
  97. });
  98. const contentCls = cls({
  99. [`${cssClasses.PREFIX}-content`]: true,
  100. });
  101. return (
  102. <div
  103. role="Collapse-panel"
  104. className={itemCls}
  105. {...restProps}
  106. >
  107. <div
  108. role="button"
  109. tabIndex={0}
  110. className={headerCls}
  111. aria-expanded={active ? 'true' : 'false'}
  112. onClick={e => onClick(itemKey, e)}
  113. >
  114. {this.renderHeader(active, children !== undefined)}
  115. </div>
  116. {
  117. children && (
  118. <Collapsible
  119. isOpen={active} keepDOM={keepDOM} motion={motion}
  120. reCalcKey={reCalcKey}>
  121. <div
  122. className={contentCls}
  123. >
  124. <div className={`${cssClasses.PREFIX}-content-wrapper`}>
  125. {children}
  126. </div>
  127. </div>
  128. </Collapsible>
  129. )
  130. }
  131. </div>
  132. );
  133. }
  134. }