listLink.tsx 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. // eslint-disable-next-line no-restricted-imports
  2. import {Link as RouterLink, withRouter, WithRouterProps} from 'react-router';
  3. import styled from '@emotion/styled';
  4. import classNames from 'classnames';
  5. import {LocationDescriptor} from 'history';
  6. import * as qs from 'query-string';
  7. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  8. type LinkProps = Omit<React.ComponentProps<typeof RouterLink>, 'to'>;
  9. type Props = WithRouterProps &
  10. LinkProps & {
  11. /**
  12. * Link target. We don't want to expose the ToLocationFunction on this component.
  13. */
  14. to: LocationDescriptor;
  15. /**
  16. * The class to apply when the link is 'active'
  17. */
  18. activeClassName?: string;
  19. disabled?: boolean;
  20. index?: boolean;
  21. /**
  22. * Should be should be supplied by the parent component
  23. */
  24. isActive?: (location: LocationDescriptor, indexOnly?: boolean) => boolean;
  25. query?: string;
  26. };
  27. function ListLink({
  28. children,
  29. className,
  30. isActive,
  31. query,
  32. router,
  33. to,
  34. activeClassName = 'active',
  35. index = false,
  36. disabled = false,
  37. ...props
  38. }: Props) {
  39. const queryData = query ? qs.parse(query) : undefined;
  40. const targetLocation = typeof to === 'string' ? {pathname: to, query: queryData} : to;
  41. const target = normalizeUrl(targetLocation);
  42. const active = isActive?.(target, index) ?? router.isActive(target, index);
  43. return (
  44. <StyledLi
  45. className={classNames({[activeClassName]: active}, className)}
  46. disabled={disabled}
  47. >
  48. <RouterLink {...props} onlyActiveOnIndex={index} to={disabled ? '' : to}>
  49. {children}
  50. </RouterLink>
  51. </StyledLi>
  52. );
  53. }
  54. export default withRouter(ListLink);
  55. const StyledLi = styled('li', {
  56. shouldForwardProp: prop => prop !== 'disabled',
  57. })<{disabled?: boolean}>`
  58. ${p =>
  59. p.disabled &&
  60. `
  61. a {
  62. color:${p.theme.disabled} !important;
  63. pointer-events: none;
  64. :hover {
  65. color: ${p.theme.disabled} !important;
  66. }
  67. }
  68. `}
  69. `;