components.tsx 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import styled from '@emotion/styled';
  2. import {Button, ButtonProps} from 'sentry/components/button';
  3. import {IconClose} from 'sentry/icons/iconClose';
  4. import {t} from 'sentry/locale';
  5. import {space} from 'sentry/styles/space';
  6. const ModalHeader = styled('header')`
  7. position: relative;
  8. border-bottom: 1px solid ${p => p.theme.border};
  9. padding: ${space(3)} ${space(3)};
  10. margin: -${space(4)} -${space(2)} ${space(3)} -${space(3)};
  11. @media (min-width: ${p => p.theme.breakpoints.medium}) {
  12. padding: ${space(3)} ${space(4)};
  13. margin: -${space(4)} -${space(4)} ${space(3)} -${space(4)};
  14. }
  15. h1,
  16. h2,
  17. h3,
  18. h4,
  19. h5,
  20. h6 {
  21. font-size: 20px;
  22. font-weight: 600;
  23. margin-bottom: 0;
  24. line-height: 1.1;
  25. }
  26. `;
  27. const CloseButton = styled((p: Omit<ButtonProps, 'aria-label'>) => (
  28. <Button
  29. aria-label={t('Close Modal')}
  30. icon={<IconClose legacySize="10px" />}
  31. size="zero"
  32. {...p}
  33. />
  34. ))`
  35. position: absolute;
  36. top: 0;
  37. right: 0;
  38. transform: translate(50%, -50%);
  39. border-radius: 50%;
  40. height: 24px;
  41. width: 24px;
  42. `;
  43. const ModalBody = styled('section')`
  44. font-size: ${p => p.theme.fontSizeMedium};
  45. p:last-child {
  46. margin-bottom: 0;
  47. }
  48. img {
  49. max-width: 100%;
  50. }
  51. `;
  52. const ModalFooter = styled('footer')`
  53. border-top: 1px solid ${p => p.theme.border};
  54. display: flex;
  55. justify-content: flex-end;
  56. padding: ${space(3)} ${space(2)};
  57. margin: ${space(3)} -${space(3)} -${space(4)};
  58. @media (min-width: ${p => p.theme.breakpoints.medium}) {
  59. padding: ${space(3)} ${space(4)};
  60. margin: ${space(3)} -${space(4)} -${space(4)};
  61. }
  62. `;
  63. interface ClosableHeaderProps extends React.HTMLAttributes<HTMLHeadingElement> {
  64. /**
  65. * Show a close button in the header
  66. */
  67. closeButton?: boolean;
  68. }
  69. /**
  70. * Creates a ModalHeader that includes props to enable the close button
  71. */
  72. const makeClosableHeader = (closeModal: () => void) => {
  73. const ClosableHeader = ({closeButton, children, ...props}: ClosableHeaderProps) => (
  74. <ModalHeader {...props}>
  75. {children}
  76. {closeButton ? <CloseButton onClick={closeModal} /> : null}
  77. </ModalHeader>
  78. );
  79. return ClosableHeader;
  80. };
  81. /**
  82. * Creates a CloseButton component that is connected to the provided closeModal trigger
  83. */
  84. const makeCloseButton =
  85. (closeModal: () => void) => (props: Omit<ButtonProps, 'aria-label'>) =>
  86. <CloseButton {...props} onClick={closeModal} />;
  87. export {makeClosableHeader, makeCloseButton, ModalBody, ModalFooter};