draggableTabMenuButton.tsx 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  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. usePortal
  34. />
  35. </TriggerIconWrap>
  36. );
  37. }
  38. const StyledDropdownMenu = styled(DropdownMenu)`
  39. font-weight: ${p => p.theme.fontWeightNormal};
  40. `;
  41. const UnsavedChangesIndicator = styled('div')`
  42. width: 7px;
  43. height: 7px;
  44. border-radius: 50%;
  45. background: ${p => p.theme.active};
  46. border: solid 1px ${p => p.theme.background};
  47. position: absolute;
  48. top: -3px;
  49. right: -3px;
  50. `;
  51. const ButtonWrapper = styled('div')`
  52. width: 18px;
  53. height: 16px;
  54. border: 1px solid ${p => p.theme.gray200};
  55. border-radius: 4px;
  56. `;
  57. const TriggerIconWrap = styled('div')`
  58. position: relative;
  59. display: flex;
  60. align-items: center;
  61. `;