sortLink.tsx 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import {browserHistory} from 'react-router';
  2. import styled from '@emotion/styled';
  3. import type {LocationDescriptorObject} from 'history';
  4. import Link from 'sentry/components/links/link';
  5. import {IconArrow} from 'sentry/icons';
  6. export type Alignments = 'left' | 'right' | undefined;
  7. export type Directions = 'desc' | 'asc' | undefined;
  8. type Props = {
  9. align: Alignments;
  10. canSort: boolean;
  11. direction: Directions;
  12. generateSortLink: () => LocationDescriptorObject | undefined;
  13. title: React.ReactNode;
  14. onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void;
  15. replace?: boolean;
  16. };
  17. function SortLink({
  18. align,
  19. title,
  20. canSort,
  21. generateSortLink,
  22. onClick,
  23. direction,
  24. replace,
  25. }: Props) {
  26. const target = generateSortLink();
  27. if (!target || !canSort) {
  28. return <StyledNonLink align={align}>{title}</StyledNonLink>;
  29. }
  30. const arrow = !direction ? null : (
  31. <StyledIconArrow size="xs" direction={direction === 'desc' ? 'down' : 'up'} />
  32. );
  33. const handleOnClick: React.MouseEventHandler<HTMLAnchorElement> = e => {
  34. if (replace) {
  35. e.preventDefault();
  36. browserHistory.replace(target);
  37. }
  38. onClick?.(e);
  39. };
  40. return (
  41. <StyledLink align={align} to={target} onClick={handleOnClick}>
  42. {title} {arrow}
  43. </StyledLink>
  44. );
  45. }
  46. type LinkProps = React.ComponentPropsWithoutRef<typeof Link>;
  47. type StyledLinkProps = LinkProps & {align: Alignments};
  48. const StyledLink = styled((props: StyledLinkProps) => {
  49. // @ts-expect-error It doesn't look like the `css` property is a part of the props,
  50. // but prior to this style of destructure-omitting it, it was being omitted
  51. // with lodash.omit. I mean keeping it omitted here just in case.
  52. const {align: _align, css: _css, ...forwardProps} = props;
  53. return <Link {...forwardProps} />;
  54. })`
  55. display: block;
  56. width: 100%;
  57. white-space: nowrap;
  58. color: inherit;
  59. &:hover,
  60. &:active,
  61. &:focus,
  62. &:visited {
  63. color: inherit;
  64. }
  65. ${(p: StyledLinkProps) => (p.align ? `text-align: ${p.align};` : '')}
  66. `;
  67. const StyledNonLink = styled('div')<{align: Alignments}>`
  68. display: block;
  69. width: 100%;
  70. white-space: nowrap;
  71. ${(p: {align: Alignments}) => (p.align ? `text-align: ${p.align};` : '')}
  72. `;
  73. const StyledIconArrow = styled(IconArrow)`
  74. vertical-align: top;
  75. `;
  76. export default SortLink;