toggle.tsx 1.6 KB

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