dropdownButton.tsx 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import {forwardRef} from 'react';
  2. import styled from '@emotion/styled';
  3. import Button, {ButtonLabel, ButtonProps} from 'sentry/components/button';
  4. import {IconChevron} from 'sentry/icons';
  5. import space from 'sentry/styles/space';
  6. export interface DropdownButtonProps extends Omit<ButtonProps, 'type' | 'prefix'> {
  7. /**
  8. * Forward a ref to the button's root
  9. */
  10. forwardedRef?: React.ForwardedRef<HTMLElement>;
  11. /**
  12. * Whether or not the button should render as open
  13. */
  14. isOpen?: boolean;
  15. /**
  16. * The fixed prefix text to show in the button eg: 'Sort By'
  17. */
  18. prefix?: React.ReactNode;
  19. /**
  20. * Should a chevron icon be shown?
  21. */
  22. showChevron?: boolean;
  23. }
  24. function DropdownButton({
  25. children,
  26. prefix,
  27. isOpen = false,
  28. showChevron = true,
  29. disabled = false,
  30. priority = 'form',
  31. forwardedRef,
  32. ...props
  33. }: DropdownButtonProps) {
  34. return (
  35. <StyledButton
  36. type="button"
  37. aria-haspopup="true"
  38. aria-expanded={isOpen}
  39. hasPrefix={!!prefix}
  40. disabled={disabled}
  41. priority={priority}
  42. isOpen={isOpen}
  43. ref={forwardedRef}
  44. {...props}
  45. >
  46. {prefix && <LabelText>{prefix}</LabelText>}
  47. {children}
  48. {showChevron && (
  49. <StyledChevron size="xs" direction={isOpen ? 'up' : 'down'} aria-hidden="true" />
  50. )}
  51. </StyledButton>
  52. );
  53. }
  54. const StyledChevron = styled(IconChevron)`
  55. margin-left: ${space(0.75)};
  56. flex-shrink: 0;
  57. `;
  58. const StyledButton = styled(Button)<
  59. Required<Pick<DropdownButtonProps, 'isOpen' | 'disabled' | 'priority'>> & {
  60. hasPrefix: boolean;
  61. }
  62. >`
  63. position: relative;
  64. max-width: 100%;
  65. z-index: 2;
  66. ${p => (p.isOpen || p.disabled) && 'box-shadow: none;'}
  67. ${p => p.hasPrefix && `${ButtonLabel} {font-weight: 400;}`}
  68. `;
  69. const LabelText = styled('span')`
  70. &:after {
  71. content: ':';
  72. }
  73. font-weight: 600;
  74. padding-right: ${space(0.75)};
  75. `;
  76. export default forwardRef<HTMLElement, DropdownButtonProps>((props, ref) => (
  77. <DropdownButton forwardedRef={ref} {...props} />
  78. ));