draggableTabMenuButton.tsx 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import styled from '@emotion/styled';
  2. import {DropdownMenu, type MenuItemProps} from 'sentry/components/dropdownMenu';
  3. import {IconEllipsis} from 'sentry/icons';
  4. interface DraggableTabMenuButtonProps {
  5. menuOptions: MenuItemProps[];
  6. 'aria-label'?: string;
  7. hasUnsavedChanges?: boolean;
  8. }
  9. export function DraggableTabMenuButton({
  10. hasUnsavedChanges = false,
  11. menuOptions,
  12. ...props
  13. }: DraggableTabMenuButtonProps) {
  14. return (
  15. <TriggerIconWrap>
  16. <StyledDropdownMenu
  17. position="bottom-start"
  18. triggerProps={{
  19. 'aria-label': props['aria-label'] ?? 'Tab Options',
  20. size: 'zero',
  21. showChevron: false,
  22. borderless: true,
  23. icon: (
  24. <ButtonWrapper>
  25. <IconEllipsis compact />
  26. {hasUnsavedChanges && <UnsavedChangesIndicator role="presentation" />}
  27. </ButtonWrapper>
  28. ),
  29. style: {width: '18px', height: '16px', borderRadius: '4px'},
  30. }}
  31. items={menuOptions}
  32. offset={[-10, 5]}
  33. />
  34. </TriggerIconWrap>
  35. );
  36. }
  37. const StyledDropdownMenu = styled(DropdownMenu)`
  38. font-weight: ${p => p.theme.fontWeightNormal};
  39. `;
  40. const UnsavedChangesIndicator = styled('div')`
  41. width: 7px;
  42. height: 7px;
  43. border-radius: 50%;
  44. background: ${p => p.theme.active};
  45. border: solid 1px ${p => p.theme.background};
  46. position: absolute;
  47. top: -3px;
  48. right: -3px;
  49. `;
  50. const ButtonWrapper = styled('div')`
  51. width: 18px;
  52. height: 16px;
  53. border: 1px solid ${p => p.theme.gray200};
  54. border-radius: 4px;
  55. `;
  56. const TriggerIconWrap = styled('div')`
  57. position: relative;
  58. display: flex;
  59. align-items: center;
  60. `;