1
0

CustomExpandIcon.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /* eslint-disable react-hooks/exhaustive-deps */
  2. import React, { useCallback } from 'react';
  3. import PropTypes from 'prop-types';
  4. import { noop } from 'lodash';
  5. import { IconChevronRight, IconChevronDown, IconTreeTriangleDown, IconTreeTriangleRight } from '@douyinfe/semi-icons';
  6. import { cssClasses } from '@douyinfe/semi-foundation/table/constants';
  7. import isEnterPress from '@douyinfe/semi-foundation/utils/isEnterPress';
  8. import Rotate from '../motions/Rotate';
  9. export interface CustomExpandIconProps {
  10. expanded?: boolean;
  11. componentType?: 'tree' | 'expand';
  12. onClick?: (nextExpand: boolean, e: React.MouseEvent<HTMLDivElement>) => void;
  13. onMouseEnter?: (e: React.MouseEvent<HTMLSpanElement>) => void;
  14. onMouseLeave?: (e: React.MouseEvent<HTMLSpanElement>) => void;
  15. expandIcon?: ((expanded?: boolean) => React.ReactNode) | React.ReactNode;
  16. prefixCls?: string;
  17. motion?: boolean;
  18. }
  19. /**
  20. * render expand icon
  21. */
  22. export default function CustomExpandIcon(props: CustomExpandIconProps) {
  23. const {
  24. expanded,
  25. componentType,
  26. onClick = noop,
  27. onMouseEnter = noop,
  28. onMouseLeave = noop,
  29. expandIcon,
  30. prefixCls = cssClasses.PREFIX,
  31. motion = true,
  32. } = props;
  33. let icon;
  34. if (React.isValidElement(expandIcon)) {
  35. icon = expandIcon;
  36. } else if (typeof expandIcon === 'function') {
  37. icon = expandIcon(expanded);
  38. } else if (componentType === 'tree') {
  39. icon = expanded && !motion ? <IconTreeTriangleDown size="small" /> : <IconTreeTriangleRight size="small" />;
  40. } else {
  41. icon = expanded && !motion ? <IconChevronDown /> : <IconChevronRight />;
  42. }
  43. const handleClick = useCallback(
  44. e => {
  45. if (typeof onClick === 'function') {
  46. onClick(!expanded, e);
  47. }
  48. },
  49. [expanded]
  50. );
  51. if (motion) {
  52. icon = (
  53. <Rotate isOpen={expanded} enterDeg={90}>
  54. {icon}
  55. </Rotate>
  56. );
  57. }
  58. return (
  59. <span
  60. role="button"
  61. aria-label="Expand this row"
  62. tabIndex={-1}
  63. onClick={handleClick}
  64. onMouseEnter={onMouseEnter}
  65. onMouseLeave={onMouseLeave}
  66. className={`${prefixCls}-expand-icon`}
  67. onKeyPress={e => isEnterPress(e) && handleClick(e as any)}
  68. >
  69. {icon}
  70. </span>
  71. );
  72. }
  73. CustomExpandIcon.propTypes = {
  74. expanded: PropTypes.bool,
  75. componentType: PropTypes.oneOf(['tree', 'expand']),
  76. onClick: PropTypes.func,
  77. onMouseEnter: PropTypes.func,
  78. onMouseLeave: PropTypes.func,
  79. expandIcon: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
  80. prefixCls: PropTypes.string,
  81. motion: PropTypes.bool,
  82. };
  83. CustomExpandIcon.defaultProps = {
  84. componentType: 'expand',
  85. onClick: noop,
  86. onMouseEnter: noop,
  87. onMouseLeave: noop,
  88. prefixCls: cssClasses.PREFIX,
  89. };