toggle.tsx 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import {Children, useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import {IconAdd, IconSubtract} from 'sentry/icons';
  4. import {t} from 'sentry/locale';
  5. type Props = {
  6. children: React.ReactNode;
  7. highUp: boolean;
  8. };
  9. function Toggle({highUp, children}: Props) {
  10. const [isExpanded, setIsExpanded] = useState(false);
  11. if (Children.count(children) === 0) {
  12. return null;
  13. }
  14. const wrappedChildren = <ValueWrapper>{children}</ValueWrapper>;
  15. if (highUp) {
  16. return wrappedChildren;
  17. }
  18. return (
  19. <span>
  20. <IconWrapper
  21. aria-label={isExpanded ? t('Collapse') : t('Expand')}
  22. isExpanded={isExpanded}
  23. onClick={evt => {
  24. setIsExpanded(!isExpanded);
  25. evt.preventDefault();
  26. }}
  27. >
  28. {isExpanded ? (
  29. <IconSubtract legacySize="10px" color="white" />
  30. ) : (
  31. <IconAdd legacySize="10px" color="white" />
  32. )}
  33. </IconWrapper>
  34. {isExpanded && wrappedChildren}
  35. </span>
  36. );
  37. }
  38. export default Toggle;
  39. const IconWrapper = styled('div')<{isExpanded: boolean}>`
  40. border-radius: 2px;
  41. display: inline-flex;
  42. align-items: center;
  43. justify-content: center;
  44. cursor: pointer;
  45. ${p =>
  46. p.isExpanded
  47. ? `
  48. background: ${p.theme.gray300};
  49. border: 1px solid ${p.theme.gray300};
  50. &:hover {
  51. background: ${p.theme.gray400};
  52. }
  53. `
  54. : `
  55. background: ${p.theme.blue300};
  56. border: 1px solid ${p.theme.blue300};
  57. &:hover {
  58. background: ${p.theme.blue200};
  59. }
  60. `}
  61. `;
  62. const ValueWrapper = styled('span')`
  63. display: block;
  64. padding: 0 0 0 15px;
  65. `;