diff --git a/packages/yoroi-extension/app/components/widgets/Dialog.js b/packages/yoroi-extension/app/components/widgets/Dialog.js index 5a6d7aa7c2..8017383829 100644 --- a/packages/yoroi-extension/app/components/widgets/Dialog.js +++ b/packages/yoroi-extension/app/components/widgets/Dialog.js @@ -1,24 +1,21 @@ +/* eslint-disable no-nested-ternary */ // @flow -import React, { Component } from 'react'; +import React from 'react'; import { map } from 'lodash'; -import { observer } from 'mobx-react'; import classnames from 'classnames'; import type { Node, Element } from 'react'; -import { Modal } from 'react-polymorph/lib/components/Modal'; -// TODO: Remove RP Button -import { Button } from 'react-polymorph/lib/components/Button'; -import { ButtonSkin } from 'react-polymorph/lib/skins/simple/ButtonSkin'; -import { ModalSkin } from 'react-polymorph/lib/skins/simple/ModalSkin'; -import styles from './Dialog.scss'; +import { Modal, Typography } from '@mui/material'; +import { Box, styled } from '@mui/system'; +import { LoadingButton } from '@mui/lab'; type ActionType = {| +label: string, +onClick: void => PossiblyAsync, +primary?: boolean, + +danger?: boolean, +isSubmitting?: boolean, +disabled?: boolean, +className?: ?string, - +themeOverrides?: {...}, |}; type Props = {| @@ -28,112 +25,148 @@ type Props = {| +closeButton?: Element, +backButton?: Node, +className?: string, - +styleOverride?: {...}, - +onClose?: ?(void => PossiblyAsync), + +styleOverride?: { ... }, + +onClose?: ?(void) => PossiblyAsync, +closeOnOverlayClick?: boolean, |}; -@observer -export default class Dialog extends Component { - static defaultProps: {| - actions: void, - backButton: void, - children: void, - className: void, - closeButton: void, - closeOnOverlayClick: void, - onClose: void, - styleOverride: void, - title: void, - |} = { - title: undefined, - children: undefined, - actions: undefined, - closeButton: undefined, - backButton: undefined, - className: undefined, - styleOverride: undefined, - onClose: undefined, - closeOnOverlayClick: undefined, - }; +export default function DialogFn(props: Props): Node { + const { + title, + children, + actions, + closeOnOverlayClick, + onClose, + className, + closeButton, + backButton, + } = props; - render(): Node { - const { - title, - children, - actions, - closeOnOverlayClick, - onClose, - className, - closeButton, - backButton, - } = this.props; + const hasSubmitting = + actions != null && actions.filter(action => action.isSubmitting === true).length > 0; - const hasSubmitting = actions != null && actions.filter( - action => action.isSubmitting === true - ).length > 0; - - return ( - { + if (reason !== 'backdropClick') { + onClose?.(event); + } + } + } + sx={{ + background: 'var(--mui-dialog-overlay-background-color)', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + '& .MuiBackdrop-root': { + background: 'none', + }, + }} + > + + {title != null && title !== '' ? ( + + {title} + + ) : null} + {children != null ? {children} : null} + {actions && actions.length > 0 && ( + + {map(actions, (action, i: number) => { + const buttonClasses = classnames([ + // Keep classnames for testing + action.className != null ? action.className : null, + action.primary === true ? 'primary' : 'secondary', + ]); + return ( + + {action.label} + + ); + })} + + )} + {!hasSubmitting && closeButton ? React.cloneElement(closeButton, { onClose }) : null} + {!hasSubmitting && backButton} + + + ); +} -
- {(title != null && title !== '') - ? ( -
-

{title}

-
) - : null - } - - {children != null - ? ( -
- {children} -
) - : null - } - - {actions && actions.length > 0 && ( -
- {map(actions, (action, i: number) => { - const buttonClasses = classnames([ - action.className != null ? action.className : null, - action.primary === true ? 'primary' : 'secondary', - action.isSubmitting === true && action.primary === true - ? styles.isSubmittingPrimary - : null, - action.isSubmitting === true && action.primary !== true - ? styles.isSubmittingSecondary - : null, - ]); - return ( -
) - } +DialogFn.defaultProps = { + title: undefined, + children: undefined, + actions: undefined, + closeButton: undefined, + backButton: undefined, + className: undefined, + styleOverride: undefined, + onClose: undefined, + closeOnOverlayClick: false, +}; - {!hasSubmitting && closeButton ? React.cloneElement(closeButton, { onClose }) : null} - {!hasSubmitting && backButton} +const ModalContainer = styled(Box)(({ theme }) => ({ + position: 'relative', + minWidth: 'var(--mui-dialog-min-width-cmn)', + borderRadius: theme.name === 'classic' ? 0 : 8, + paddingTop: theme.name === 'classic' ? '25px' : '24px', + paddingBottom: theme.name === 'classic' ? '30px' : '40px', + maxWidth: theme.name === 'classic' ? '785px' : '560px', + backgroundColor: 'var(--mui-dialog-background-color)', + color: 'var(--mui-dialog-text-color)', + maxHeight: '80vh', -
- - ); - } -} + '& .dialog__title': { + flex: 1, + marginBottom: theme.name === 'classic' ? '22px' : '40px', + fontWeight: 500, + textAlign: 'center', + textTransform: 'uppercase', + letterSpacing: 0, + }, +})); +const ModalContent = styled(Box)(({ theme }) => ({ + overflowX: 'hidden', + overflowY: 'overlay', + maxHeight: '60vh', + paddingLeft: theme.name === 'classic' ? '30px' : '40px', + paddingRight: theme.name === 'classic' ? '30px' : '40px', +})); +const ModalFooter = styled(Box)(({ theme }) => ({ + display: 'flex', + paddingLeft: theme.name === 'classic' ? '30px' : '40px', + paddingRight: theme.name === 'classic' ? '30px' : '40px', + marginTop: theme.name === 'classic' ? '20px' : '34px', + '& button': { + width: ' 50%', + '&:only-child': { + margin: 'auto', + width: '100%', + }, + '& + button': { + marginLeft: '20px', + }, + }, +})); diff --git a/packages/yoroi-extension/app/components/widgets/Dialog.scss b/packages/yoroi-extension/app/components/widgets/Dialog.scss deleted file mode 100644 index 854d94f689..0000000000 --- a/packages/yoroi-extension/app/components/widgets/Dialog.scss +++ /dev/null @@ -1,79 +0,0 @@ - @import '../../themes/mixins/loading-spinner'; - -.component { - color: var(--theme-dialog-title-color); - display: flex; - flex: 1; - flex-direction: column; - position: relative; - - & > .title { - font-family: var(--font-medium); - font-size: 16px; - line-height: 19px; - margin: var(--theme-dialog-title-margin); - text-align: center; - text-transform: uppercase; - letter-spacing: 0; - } - - & > .content { - flex: 1; - overflow-x: hidden; - overflow-y: overlay; - padding: 0 30px; - margin: 0 -30px; - max-height: 60vh; - } - - & > .actions { - display: flex; - flex-shrink: 0; - margin: var(--theme-dialog-input-actions-margin); - - button { - width: 50%; - - &:only-child { - margin: auto; - width: 100%; - } - - & + button { - margin-left: 20px; - } - } - } -} - -:global(.YoroiModern) { - .component { - margin: var(--theme-modal-margin-cmn); - min-width: var(--theme-modal-min-max-width-cmn); - max-width: var(--theme-modal-min-max-width-cmn); - - & > .title { - font-size: 16px; - letter-spacing: 0px; - } - - & > .content { - padding: 0 40px; - margin: 0 -40px; - max-height: 60vh; - - /* Fix: non-zero bottom margin helps dynamic height rendering and prevents unnecessary scrollbars */ - & > :last-child { - margin-bottom: 1px; - } - } - } -} - -.isSubmittingPrimary { - @include loading-spinner("../../assets/images/spinner-light.svg"); -} -.isSubmittingSecondary { - @include loading-spinner("../../assets/images/spinner-dark.svg"); - opacity: 0.5; -} diff --git a/packages/yoroi-extension/app/components/widgets/DialogBackButton.js b/packages/yoroi-extension/app/components/widgets/DialogBackButton.js index 49fb9d9a31..343c3d441f 100644 --- a/packages/yoroi-extension/app/components/widgets/DialogBackButton.js +++ b/packages/yoroi-extension/app/components/widgets/DialogBackButton.js @@ -3,21 +3,34 @@ import { Component } from 'react'; import type { Node } from 'react'; import { observer } from 'mobx-react'; import BackArrow from '../../assets/images/back-arrow-ic.inline.svg'; -import styles from './DialogBackButton.scss'; +import { IconButton } from '@mui/material'; type Props = {| - +onBack: void => PossiblyAsync + +onBack: void => PossiblyAsync, |}; @observer export default class DialogBackButton extends Component { - render(): Node { const { onBack } = this.props; return ( - + ); } } diff --git a/packages/yoroi-extension/app/components/widgets/DialogBackButton.scss b/packages/yoroi-extension/app/components/widgets/DialogBackButton.scss deleted file mode 100644 index 44a61635c5..0000000000 --- a/packages/yoroi-extension/app/components/widgets/DialogBackButton.scss +++ /dev/null @@ -1,13 +0,0 @@ -.component { - position: absolute; - top: 4px; - left: 0; - cursor: pointer; - svg { - width: 20px; - height: 16px; - path { - fill: var(--theme-icon-back-button-color); - } - } -} \ No newline at end of file diff --git a/packages/yoroi-extension/app/components/widgets/DialogCloseButton.js b/packages/yoroi-extension/app/components/widgets/DialogCloseButton.js index 7bc18614b5..be2438ae99 100644 --- a/packages/yoroi-extension/app/components/widgets/DialogCloseButton.js +++ b/packages/yoroi-extension/app/components/widgets/DialogCloseButton.js @@ -4,7 +4,7 @@ import type { Node } from 'react'; import { observer } from 'mobx-react'; import CloseCross from '../../assets/images/cross-dark.inline.svg'; -import styles from './DialogCloseButton.scss'; +import { IconButton } from '@mui/material'; type Props = {| +onClose?: void => PossiblyAsync, @@ -13,20 +13,26 @@ type Props = {| @observer export default class DialogCloseButton extends Component { - static defaultProps: {|icon: null, onClose: void|} = { + static defaultProps: {| icon: null, onClose: void |} = { onClose: undefined, - icon: null + icon: null, }; render(): Node { const { onClose, icon } = this.props; - const Svg = (icon != null && icon !== '') - ? icon - : CloseCross; + const Svg = icon != null && icon !== '' ? icon : CloseCross; return ( - + ); } } diff --git a/packages/yoroi-extension/app/components/widgets/DialogCloseButton.scss b/packages/yoroi-extension/app/components/widgets/DialogCloseButton.scss deleted file mode 100644 index d4e805ca4e..0000000000 --- a/packages/yoroi-extension/app/components/widgets/DialogCloseButton.scss +++ /dev/null @@ -1,24 +0,0 @@ -.component { - position: absolute; - top: -8px; - right: 0; - cursor: pointer; - display: inline-flex; - margin-left: 5px; - width: 32px; - height: 32px; - border-radius: 50%; - transition: background-color 0.3s; - & > svg { - display: block; - margin: auto; - height: 16px; - width: 16px; - path { - fill: var(--theme-icon-close-button-color); - } - } - &:hover { - background-color: var(--cmn-default-color-grey-5); - } -} diff --git a/packages/yoroi-extension/app/styles/globalStyles.js b/packages/yoroi-extension/app/styles/globalStyles.js index 7d42c6c59d..e0bc75aa76 100644 --- a/packages/yoroi-extension/app/styles/globalStyles.js +++ b/packages/yoroi-extension/app/styles/globalStyles.js @@ -86,6 +86,12 @@ const globalStyles = (theme: Object): Node => ( '--mui-tooltip-background-color': 'hsl(225 4% 38% / 0.9)', '--mui-tooltip-border-color': 'hsl(214deg 16% 81%)', '--mui-tooltip-text-color': 'hsl(0 0% 100%)', + + /* === MODAL === */ + '--mui-dialog-background-color': 'hsl(0 0% 100%)', + '--mui-dialog-text-color': 'hsl(231deg 8% 18%)', + '--mui-dialog-overlay-background-color': 'hsl(226deg 71% 8% / 80%)', + '--mui-dialog-min-width-cmn': '540px', }, }} />