CustomExpandIcon.tsx 2.7 KB

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