sortLink.tsx 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import React from 'react';
  2. import styled from '@emotion/styled';
  3. import {LocationDescriptorObject} from 'history';
  4. import omit from 'lodash/omit';
  5. import Link from 'app/components/links/link';
  6. import {IconArrow} from 'app/icons';
  7. export type Alignments = 'left' | 'right' | undefined;
  8. export type Directions = 'desc' | 'asc' | undefined;
  9. type Props = {
  10. align: Alignments;
  11. title: React.ReactNode;
  12. direction: Directions;
  13. canSort: boolean;
  14. generateSortLink: () => LocationDescriptorObject | undefined;
  15. onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void;
  16. };
  17. class SortLink extends React.Component<Props> {
  18. renderArrow() {
  19. const {direction} = this.props;
  20. if (!direction) {
  21. return null;
  22. }
  23. if (direction === 'desc') {
  24. return <StyledIconArrow size="xs" direction="down" />;
  25. }
  26. return <StyledIconArrow size="xs" direction="up" />;
  27. }
  28. render() {
  29. const {align, title, canSort, generateSortLink, onClick} = this.props;
  30. const target = generateSortLink();
  31. if (!target || !canSort) {
  32. return <StyledNonLink align={align}>{title}</StyledNonLink>;
  33. }
  34. return (
  35. <StyledLink align={align} to={target} onClick={onClick}>
  36. {title} {this.renderArrow()}
  37. </StyledLink>
  38. );
  39. }
  40. }
  41. type LinkProps = React.ComponentPropsWithoutRef<typeof Link>;
  42. type StyledLinkProps = LinkProps & {align: Alignments};
  43. const StyledLink = styled((props: StyledLinkProps) => {
  44. const forwardProps = omit(props, ['align']);
  45. return <Link {...forwardProps} />;
  46. })`
  47. display: block;
  48. width: 100%;
  49. white-space: nowrap;
  50. color: inherit;
  51. &:hover,
  52. &:active,
  53. &:focus,
  54. &:visited {
  55. color: inherit;
  56. }
  57. ${(p: StyledLinkProps) => (p.align ? `text-align: ${p.align};` : '')}
  58. `;
  59. const StyledNonLink = styled('div')<{align: Alignments}>`
  60. display: block;
  61. width: 100%;
  62. white-space: nowrap;
  63. ${(p: {align: Alignments}) => (p.align ? `text-align: ${p.align};` : '')}
  64. `;
  65. const StyledIconArrow = styled(IconArrow)`
  66. vertical-align: top;
  67. `;
  68. export default SortLink;