components.tsx 2.3 KB

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