You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Dialog.tsx 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import React, { useCallback } from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import { useDispatch } from 'react-redux';
  4. import { makeStyles } from 'tss-react/mui';
  5. import { hideDialog } from '../../../dialog/actions';
  6. import { IconCloseLarge } from '../../../icons/svg';
  7. import { withPixelLineHeight } from '../../../styles/functions.web';
  8. import { operatesWithEnterKey } from '../../functions.web';
  9. import BaseDialog, { IProps as IBaseDialogProps } from './BaseDialog';
  10. import Button from './Button';
  11. import ClickableIcon from './ClickableIcon';
  12. const useStyles = makeStyles()(theme => {
  13. return {
  14. header: {
  15. width: '100%',
  16. padding: '24px',
  17. boxSizing: 'border-box',
  18. display: 'flex',
  19. alignItems: 'flex-start',
  20. justifyContent: 'space-between'
  21. },
  22. title: {
  23. color: theme.palette.text01,
  24. ...withPixelLineHeight(theme.typography.heading5),
  25. margin: 0,
  26. padding: 0
  27. },
  28. content: {
  29. height: 'auto',
  30. overflowY: 'auto',
  31. width: '100%',
  32. boxSizing: 'border-box',
  33. padding: '0 24px',
  34. overflowX: 'hidden',
  35. minHeight: '40px',
  36. '@media (max-width: 448px)': {
  37. height: '100%'
  38. }
  39. },
  40. footer: {
  41. width: '100%',
  42. boxSizing: 'border-box',
  43. display: 'flex',
  44. alignItems: 'center',
  45. justifyContent: 'flex-end',
  46. padding: '24px',
  47. '& button:last-child': {
  48. marginLeft: '16px'
  49. }
  50. }
  51. };
  52. });
  53. interface IDialogProps extends IBaseDialogProps {
  54. back?: {
  55. hidden?: boolean;
  56. onClick?: () => void;
  57. translationKey?: string;
  58. };
  59. cancel?: {
  60. hidden?: boolean;
  61. translationKey?: string;
  62. };
  63. children?: React.ReactNode;
  64. disableAutoHideOnSubmit?: boolean;
  65. hideCloseButton?: boolean;
  66. ok?: {
  67. disabled?: boolean;
  68. hidden?: boolean;
  69. translationKey?: string;
  70. };
  71. onCancel?: () => void;
  72. onSubmit?: () => void;
  73. }
  74. const Dialog = ({
  75. back = { hidden: true },
  76. cancel = { translationKey: 'dialog.Cancel' },
  77. children,
  78. className,
  79. description,
  80. disableAutoHideOnSubmit = false,
  81. disableBackdropClose,
  82. hideCloseButton,
  83. disableEnter,
  84. disableEscape,
  85. ok = { translationKey: 'dialog.Ok' },
  86. onCancel,
  87. onSubmit,
  88. size,
  89. testId,
  90. title,
  91. titleKey
  92. }: IDialogProps) => {
  93. const { classes } = useStyles();
  94. const { t } = useTranslation();
  95. const dispatch = useDispatch();
  96. const onClose = useCallback(() => {
  97. dispatch(hideDialog());
  98. onCancel?.();
  99. }, [ onCancel ]);
  100. const submit = useCallback(() => {
  101. if (onSubmit && (
  102. (document.activeElement && !operatesWithEnterKey(document.activeElement))
  103. || !document.activeElement
  104. )) {
  105. !disableAutoHideOnSubmit && dispatch(hideDialog());
  106. onSubmit();
  107. }
  108. }, [ onSubmit ]);
  109. return (
  110. <BaseDialog
  111. className = { className }
  112. description = { description }
  113. disableBackdropClose = { disableBackdropClose }
  114. disableEnter = { disableEnter }
  115. disableEscape = { disableEscape }
  116. onClose = { onClose }
  117. size = { size }
  118. submit = { submit }
  119. testId = { testId }
  120. title = { title }
  121. titleKey = { titleKey }>
  122. <div className = { classes.header }>
  123. <h1
  124. className = { classes.title }
  125. id = 'dialog-title'>
  126. {title ?? t(titleKey ?? '')}
  127. </h1>
  128. {!hideCloseButton && (
  129. <ClickableIcon
  130. accessibilityLabel = { t('dialog.accessibilityLabel.close') }
  131. icon = { IconCloseLarge }
  132. id = 'modal-header-close-button'
  133. onClick = { onClose } />
  134. )}
  135. </div>
  136. <div
  137. className = { classes.content }
  138. data-autofocus-inside = 'true'>
  139. {children}
  140. </div>
  141. <div
  142. className = { classes.footer }
  143. data-autofocus-inside = 'true'>
  144. {!back.hidden && <Button
  145. accessibilityLabel = { t(back.translationKey ?? '') }
  146. labelKey = { back.translationKey }
  147. // eslint-disable-next-line react/jsx-handler-names
  148. onClick = { back.onClick }
  149. type = 'secondary' />}
  150. {!cancel.hidden && <Button
  151. accessibilityLabel = { t(cancel.translationKey ?? '') }
  152. labelKey = { cancel.translationKey }
  153. onClick = { onClose }
  154. type = 'tertiary' />}
  155. {!ok.hidden && <Button
  156. accessibilityLabel = { t(ok.translationKey ?? '') }
  157. disabled = { ok.disabled }
  158. id = 'modal-dialog-ok-button'
  159. isSubmit = { true }
  160. labelKey = { ok.translationKey }
  161. { ...(!ok.disabled && { onClick: submit }) } />}
  162. </div>
  163. </BaseDialog>
  164. );
  165. };
  166. export default Dialog;