dropdownButton.tsx 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  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. forwardedRef,
  31. ...props
  32. }: DropdownButtonProps) {
  33. return (
  34. <StyledButton
  35. aria-haspopup="true"
  36. aria-expanded={isOpen}
  37. hasPrefix={!!prefix}
  38. disabled={disabled}
  39. isOpen={isOpen}
  40. ref={forwardedRef}
  41. {...props}
  42. >
  43. {prefix && <LabelText>{prefix}</LabelText>}
  44. {children}
  45. {showChevron && (
  46. <StyledChevron size="xs" direction={isOpen ? 'up' : 'down'} aria-hidden="true" />
  47. )}
  48. </StyledButton>
  49. );
  50. }
  51. const StyledChevron = styled(IconChevron)`
  52. margin-left: ${space(0.75)};
  53. flex-shrink: 0;
  54. `;
  55. const StyledButton = styled(Button)<
  56. Required<Pick<DropdownButtonProps, 'isOpen' | 'disabled'>> & {
  57. hasPrefix: boolean;
  58. }
  59. >`
  60. position: relative;
  61. max-width: 100%;
  62. z-index: 2;
  63. ${p => (p.isOpen || p.disabled) && 'box-shadow: none;'}
  64. ${p => p.hasPrefix && `${ButtonLabel} {font-weight: 400;}`}
  65. `;
  66. const LabelText = styled('span')`
  67. &:after {
  68. content: ':';
  69. }
  70. font-weight: 600;
  71. padding-right: ${space(0.75)};
  72. `;
  73. export default forwardRef<HTMLElement, DropdownButtonProps>((props, ref) => (
  74. <DropdownButton forwardedRef={ref} {...props} />
  75. ));