ColumnSorter.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import React, { PureComponent } from 'react';
  2. import PropTypes from 'prop-types';
  3. import cls from 'classnames';
  4. import { noop } from 'lodash';
  5. import { IconCaretup, IconCaretdown } from '@douyinfe/semi-icons';
  6. import { cssClasses, strings } from '@douyinfe/semi-foundation/table/constants';
  7. import { SortIcon, SortOrder } from './interface';
  8. import isEnterPress from '@douyinfe/semi-foundation/utils/isEnterPress';
  9. export interface ColumnSorterProps {
  10. className?: string;
  11. style?: React.CSSProperties;
  12. onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
  13. prefixCls?: string;
  14. sortOrder?: SortOrder;
  15. title?: React.ReactNode;
  16. sortIcon?: SortIcon
  17. }
  18. export default class ColumnSorter extends PureComponent<ColumnSorterProps> {
  19. static propTypes = {
  20. className: PropTypes.string,
  21. style: PropTypes.object,
  22. onClick: PropTypes.func,
  23. prefixCls: PropTypes.string,
  24. sortOrder: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
  25. sortIcon: PropTypes.func,
  26. };
  27. static defaultProps = {
  28. prefixCls: cssClasses.PREFIX,
  29. onClick: noop,
  30. sortOrder: false,
  31. };
  32. render() {
  33. const { prefixCls, onClick, sortOrder, style, title, sortIcon } = this.props;
  34. const iconBtnSize = 'default';
  35. const upCls = cls(`${prefixCls}-column-sorter-up`, {
  36. on: sortOrder === strings.SORT_DIRECTIONS[0],
  37. });
  38. const downCls = cls(`${prefixCls}-column-sorter-down`, {
  39. on: sortOrder === strings.SORT_DIRECTIONS[1],
  40. });
  41. const ariaProps = {
  42. /**
  43. * Set 'aria-sort' to aria-columnheader is difficult, so set 'aria-label' about sort info to sorter
  44. * reference: https://developer.mozilla.org/en-US/docs/Web/API/Element/ariaSort
  45. */
  46. 'aria-label': `Current sort order is ${sortOrder ? `${sortOrder}ing` : 'none'}`,
  47. 'aria-roledescription': 'Sort data with this column',
  48. };
  49. const renderSortIcon = () => {
  50. if (typeof sortIcon === 'function') {
  51. return sortIcon({ sortOrder });
  52. } else {
  53. return (
  54. <div style={style} className={`${prefixCls}-column-sorter`}>
  55. <span className={`${upCls}`}>
  56. <IconCaretup size={iconBtnSize} />
  57. </span>
  58. <span className={`${downCls}`}>
  59. <IconCaretdown size={iconBtnSize} />
  60. </span>
  61. </div>
  62. );
  63. }
  64. };
  65. return (
  66. <div
  67. role="button"
  68. {...ariaProps}
  69. tabIndex={-1}
  70. className={`${prefixCls}-column-sorter-wrapper`}
  71. onClick={onClick}
  72. onKeyPress={e => isEnterPress(e) && onClick(e as any)}
  73. >
  74. {title}
  75. {renderSortIcon()}
  76. </div>
  77. );
  78. }
  79. }