Skip to content

Commit

Permalink
EPMRPP-89804 || Update Modal component (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
Vadim73i authored Jul 24, 2024
1 parent 2a77af9 commit 19bb318
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 30 deletions.
2 changes: 1 addition & 1 deletion src/components/modal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ Default width - 480px, height 100%
### Props :

- **title**: _string_, optional, default = ""
- **headerNode**: _node_, optional, default = null
- **children**: _node_, optional, default = null
- **footerNode**: _node_, optional, default = null
- **okButton**: _object_, optional, default = null
- **cancelButton**: _object_, optional, default = null
- **className**: _string_, optional, default = ""
- **size**: _string_, optional, default = "default"
- **onClose**: _function_, optional, default = () => {}
- **description**: _node_, optional, default = null

### Variants

Expand Down
15 changes: 14 additions & 1 deletion src/components/modal/modal.module.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
@import 'src/assets/styles/variables/typography';
@import 'src/assets/styles/mixins/font-scale';

$WIDTH-SMALL: 320px;
$WIDTH-DEFAULT: 480px;
$WIDTH-LARGE: 720px;
Expand Down Expand Up @@ -45,7 +48,7 @@ $WIDTH-LARGE: 720px;
transform: translate(-50%);
display: inline-block;
margin-bottom: 10px;
padding: 32px 48px;
padding: 32px 40px;
box-sizing: border-box;
background-color: var(--rp-ui-base-bg-100);
text-align: left;
Expand All @@ -56,6 +59,16 @@ $WIDTH-LARGE: 720px;
max-height: 90%;
}

.description {
display: inline-block;
width: 100%;
padding-bottom: 24px;
font-family: var(--rp-ui-base-font-family);
font-weight: $fw-regular;
@include font-scale();
color: var(--rp-ui-base-almost-black);
}

.size-default {
@include modalWidth($WIDTH-DEFAULT);
}
Expand Down
82 changes: 81 additions & 1 deletion src/components/modal/modal.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react';
import { Modal } from './modal';
import { FC, useState } from 'react';
import { Button } from '@components/button';

const meta: Meta<typeof Modal> = {
title: 'Modal',
Expand Down Expand Up @@ -32,6 +34,49 @@ export const Default: Story = {
args: {},
};

export const WithoutFooter: Story = {
args: {
withoutFooter: true,
description: 'title description',
},
};

export const WithSteps: Story = {
render: (args) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const [step, setStep] = useState<number>(1);

const CustomFooter: FC<{ closeHandler: () => void }> = ({ closeHandler }) => {
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
gap: 18,
}}
>
<Button variant={'ghost'} onClick={() => setStep(1)}>
Go to 1 step
</Button>
<Button variant={'ghost'} onClick={() => setStep(2)}>
Go to 2 step
</Button>
<Button onClick={() => console.log('done')}>OK</Button>
<Button variant={'danger'} onClick={() => closeHandler()}>
Cancel
</Button>
</div>
);
};

return (
<Modal {...args} title={'Modal with steps'} CustomFooter={CustomFooter}>
content for step {step}
</Modal>
);
},
};

export const Small: Story = {
args: {
size: 'small',
Expand All @@ -53,9 +98,44 @@ export const OverlayLightCyan: Story = {
export const Scrollable: Story = {
args: {
scrollable: true,
description: 'title description',
children: (
<>
<p style={{ marginBlockEnd: 0, marginBlockStart: 0 }}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing
elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
</p>
</>
),
},
};

export const ScrollableWithoutFooter: Story = {
args: {
scrollable: true,
withoutFooter: true,
children: (
<>
<p>
<p style={{ marginBlockEnd: 0, marginBlockStart: 0 }}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
Expand Down
64 changes: 45 additions & 19 deletions src/components/modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import styles from './modal.module.scss';
const cx = classNames.bind(styles);

const MODAL_MAX_RATIO = 0.9;
const MODAL_HEADER_AND_FOOTER_HEIGHT = 176;
const MODAL_HEADER_HEIGHT = 32 + 24;
const MODAL_HEADER_WITH_DESCRIPTION_HEIGHT = 32 + 8;
const MODAL_FOOTER_HEIGHT = 36 + 16;
const MODAL_LAYOUT_PADDING = 32 * 2;

type ModalOverlay = 'default' | 'light-cyan';

interface ModalProps {
onClose: () => void;
onClose?: () => void;
title?: ReactNode;
headerNode?: ReactNode;
children?: ReactNode;
footerNode?: ReactNode;
className?: string;
Expand All @@ -31,12 +33,14 @@ interface ModalProps {
okButton?: ButtonProps;
cancelButton?: ButtonProps;
scrollable?: boolean;
withoutFooter?: boolean;
CustomFooter?: FC<{ closeHandler: () => void }>;
description?: ReactNode;
}

// TODO: Fix issue with modal positioning
export const Modal: FC<ModalProps> = ({
title,
headerNode,
children,
footerNode,
okButton,
Expand All @@ -48,6 +52,9 @@ export const Modal: FC<ModalProps> = ({
zIndex = 2,
allowCloseOutside = true,
scrollable = false,
withoutFooter = false,
CustomFooter = null,
description = null,
}) => {
const [isShown, setShown] = useState(false);
const [modalHeight, setModalHeight] = useState(0);
Expand All @@ -57,7 +64,20 @@ export const Modal: FC<ModalProps> = ({
const windowHeight = windowSize.height;
const modalMaxHeight = windowHeight * MODAL_MAX_RATIO;
const modalMargin = (windowHeight - modalHeight) / 2;
const contentMaxHeight = modalMaxHeight - MODAL_HEADER_AND_FOOTER_HEIGHT;
const getContentMaxHeight = () => {
let contentMaxHeight = modalMaxHeight - MODAL_LAYOUT_PADDING;
if (!withoutFooter) {
contentMaxHeight = contentMaxHeight - MODAL_FOOTER_HEIGHT;
}

if (description) {
contentMaxHeight = contentMaxHeight - MODAL_HEADER_WITH_DESCRIPTION_HEIGHT;
} else {
contentMaxHeight = contentMaxHeight - MODAL_HEADER_HEIGHT;
}

return contentMaxHeight;
};

const closeModal = () => {
setShown(false);
Expand All @@ -81,10 +101,6 @@ export const Modal: FC<ModalProps> = ({
useEffect(() => {
setShown(true);

if (modalRef && modalRef.current) {
modalRef.current.focus();
}

document.addEventListener('keydown', onKeydown, false);

return () => document.removeEventListener('keydown', onKeydown, false);
Expand All @@ -105,22 +121,32 @@ export const Modal: FC<ModalProps> = ({
animate={{ opacity: 1, marginTop: modalMargin }}
exit={{ opacity: 0, marginTop: -modalMargin }}
transition={{ duration: 0.3 }}
onAnimationStart={() => modalRef.current?.focus()}
>
<ModalHeader title={title} headerNode={headerNode} onClose={closeModal} />
<ModalHeader title={title} onClose={closeModal} withDescription={!!description} />
{scrollable ? (
<Scrollbars autoHeight autoHeightMax={contentMaxHeight} hideTracksWhenNotNeeded>
<Scrollbars autoHeight autoHeightMax={getContentMaxHeight()} hideTracksWhenNotNeeded>
{description && <span className={cx('description')}>{description}</span>}
<ModalContent>{children}</ModalContent>
</Scrollbars>
) : (
<ModalContent>{children}</ModalContent>
<>
{description && <span className={cx('description')}>{description}</span>}
<ModalContent>{children}</ModalContent>
</>
)}
<ModalFooter
size={size}
footerNode={footerNode}
okButton={okButton}
cancelButton={cancelButton}
closeHandler={closeModal}
/>
{!withoutFooter &&
(CustomFooter ? (
<CustomFooter closeHandler={closeModal} />
) : (
<ModalFooter
size={size}
footerNode={footerNode}
okButton={okButton}
cancelButton={cancelButton}
closeHandler={closeModal}
/>
))}
</motion.div>
</div>
)}
Expand Down
2 changes: 1 addition & 1 deletion src/components/modal/modalContent/modalContent.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

.modal-content {
width: calc(100% - 34px);
margin-top: 13px;
font-family: var(--rp-ui-base-font-family);
font-weight: $fw-regular;
@include font-scale();
color: var(--rp-ui-color-text);
white-space: pre-line;
word-break: break-word;
padding: 0 0 16px;
}
7 changes: 4 additions & 3 deletions src/components/modal/modalHeader/modalHeader.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
@include font-scale(x4-medium);
color: var(--rp-ui-color-text);
padding-bottom: 24px;

&.width-description {
padding-bottom: 8px;
}
}

.modal-header-content {
display: flex;
justify-content: stretch;
align-items: center;
width: 100%;
padding-right: 30px;
box-sizing: border-box;
Expand Down
7 changes: 3 additions & 4 deletions src/components/modal/modalHeader/modalHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@ const cx = classNames.bind(styles);

interface ModalHeaderProps {
title?: ReactNode;
headerNode?: ReactNode;
onClose: () => void;
withDescription?: boolean;
}

export const ModalHeader: FC<ModalHeaderProps> = ({ title, onClose, headerNode }) => (
<div className={cx('modal-header')}>
export const ModalHeader: FC<ModalHeaderProps> = ({ title, onClose, withDescription = false }) => (
<div className={cx('modal-header', { 'width-description': withDescription })}>
<div className={cx('modal-header-content')}>
{title && <span className={cx('modal-title')}>{title}</span>}
{headerNode && headerNode}
</div>
<BaseIconButton className={cx('close-modal-icon')} onClick={onClose}>
<CloseIcon />
Expand Down

0 comments on commit 19bb318

Please sign in to comment.