dropdownButton.tsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import * as React from 'react';
  2. import styled from '@emotion/styled';
  3. import Button from 'app/components/button';
  4. import {IconChevron} from 'app/icons';
  5. import space from 'app/styles/space';
  6. type Props = Omit<React.ComponentProps<typeof Button>, 'type' | 'priority'> & {
  7. /**
  8. * The fixed prefix text to show in the button eg: 'Sort By'
  9. */
  10. prefix?: React.ReactNode;
  11. /**
  12. * Whether or not the button should render as open
  13. */
  14. isOpen?: boolean;
  15. /**
  16. * Should a chevron icon be shown?
  17. */
  18. showChevron?: boolean;
  19. /**
  20. * Should the bottom border become transparent when open?
  21. */
  22. hideBottomBorder?: boolean;
  23. /**
  24. * Button color
  25. */
  26. priority?: 'default' | 'primary' | 'form';
  27. /**
  28. * Forward a ref to the button's root
  29. */
  30. forwardedRef?: React.Ref<typeof Button>;
  31. };
  32. const DropdownButton = ({
  33. children,
  34. forwardedRef,
  35. prefix,
  36. isOpen = false,
  37. showChevron = false,
  38. hideBottomBorder = true,
  39. disabled = false,
  40. priority = 'form',
  41. ...props
  42. }: Props) => {
  43. return (
  44. <StyledButton
  45. {...props}
  46. type="button"
  47. disabled={disabled}
  48. priority={priority}
  49. isOpen={isOpen}
  50. hideBottomBorder={hideBottomBorder}
  51. ref={forwardedRef}
  52. >
  53. {prefix && <LabelText>{prefix}</LabelText>}
  54. {children}
  55. {showChevron && <StyledChevron size="10px" direction={isOpen ? 'up' : 'down'} />}
  56. </StyledButton>
  57. );
  58. };
  59. DropdownButton.defaultProps = {
  60. showChevron: true,
  61. };
  62. const StyledChevron = styled(IconChevron)`
  63. margin-left: 0.33em;
  64. `;
  65. const StyledButton = styled(Button)<
  66. Required<Pick<Props, 'isOpen' | 'disabled' | 'hideBottomBorder' | 'priority'>>
  67. >`
  68. border-bottom-right-radius: ${p => (p.isOpen ? 0 : p.theme.borderRadius)};
  69. border-bottom-left-radius: ${p => (p.isOpen ? 0 : p.theme.borderRadius)};
  70. position: relative;
  71. z-index: 2;
  72. box-shadow: ${p => (p.isOpen || p.disabled ? 'none' : p.theme.dropShadowLight)};
  73. &,
  74. &:active,
  75. &:focus,
  76. &:hover {
  77. border-bottom-color: ${p =>
  78. p.isOpen && p.hideBottomBorder
  79. ? 'transparent'
  80. : p.theme.button[p.priority].borderActive};
  81. }
  82. `;
  83. const LabelText = styled('span')`
  84. &:after {
  85. content: ':';
  86. }
  87. font-weight: 400;
  88. padding-right: ${space(0.75)};
  89. `;
  90. export default React.forwardRef<typeof Button, Props>((props, ref) => (
  91. <DropdownButton forwardedRef={ref} {...props} />
  92. ));