Refactor/modal component tests 1332 (#1392)
* feat: Add separate constants in theme for modal sizes and paddings * feat: Implement dynamic sizing and padding for Modal * feat: use dynamic modal feature for csv import * fix: Remove redundant props from spreadsheet-import * fix: use theme.spacing() instead * fix: place types to Modal.tsx, convert ternary to switch-case, give default value * fix: give px to modal sizes * enhance: add color style to modal * feat: add modal to storybook
This commit is contained in:
@ -37,7 +37,7 @@ export const ModalWrapper = ({ children, isOpen, onClose }: Props) => {
|
|||||||
const { rtl } = useSpreadsheetImportInternal();
|
const { rtl } = useSpreadsheetImportInternal();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledModal isOpen={isOpen}>
|
<StyledModal isOpen={isOpen} size="large">
|
||||||
<StyledRtlLtr dir={rtl ? 'rtl' : 'ltr'}>
|
<StyledRtlLtr dir={rtl ? 'rtl' : 'ltr'}>
|
||||||
<ModalCloseButton onClose={onClose} />
|
<ModalCloseButton onClose={onClose} />
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@ -12,14 +12,46 @@ import {
|
|||||||
|
|
||||||
import { ModalHotkeyScope } from './types/ModalHotkeyScope';
|
import { ModalHotkeyScope } from './types/ModalHotkeyScope';
|
||||||
|
|
||||||
const StyledModalDiv = styled(motion.div)`
|
const StyledModalDiv = styled(motion.div)<{
|
||||||
|
size?: ModalSize;
|
||||||
|
padding?: ModalPadding;
|
||||||
|
}>`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
background: ${({ theme }) => theme.background.primary};
|
background: ${({ theme }) => theme.background.primary};
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
max-height: 90vh;
|
max-height: 90vh;
|
||||||
z-index: 10000; // should be higher than Backdrop's z-index
|
z-index: 10000; // should be higher than Backdrop's z-index
|
||||||
|
|
||||||
|
width: ${({ size, theme }) => {
|
||||||
|
switch (size) {
|
||||||
|
case 'small':
|
||||||
|
return theme.modal.size.sm;
|
||||||
|
case 'medium':
|
||||||
|
return theme.modal.size.md;
|
||||||
|
case 'large':
|
||||||
|
return theme.modal.size.lg;
|
||||||
|
default:
|
||||||
|
return 'auto';
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
|
padding: ${({ padding, theme }) => {
|
||||||
|
switch (padding) {
|
||||||
|
case 'none':
|
||||||
|
return theme.spacing(0);
|
||||||
|
case 'small':
|
||||||
|
return theme.spacing(2);
|
||||||
|
case 'medium':
|
||||||
|
return theme.spacing(4);
|
||||||
|
case 'large':
|
||||||
|
return theme.spacing(6);
|
||||||
|
default:
|
||||||
|
return 'auto';
|
||||||
|
}
|
||||||
|
}};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledHeader = styled.div`
|
const StyledHeader = styled.div`
|
||||||
@ -85,12 +117,17 @@ function ModalFooter({ children, ...restProps }: ModalFooterProps) {
|
|||||||
/**
|
/**
|
||||||
* Modal
|
* Modal
|
||||||
*/
|
*/
|
||||||
|
export type ModalSize = 'small' | 'medium' | 'large';
|
||||||
|
export type ModalPadding = 'none' | 'small' | 'medium' | 'large';
|
||||||
|
|
||||||
type ModalProps = React.PropsWithChildren &
|
type ModalProps = React.PropsWithChildren &
|
||||||
React.ComponentProps<'div'> & {
|
React.ComponentProps<'div'> & {
|
||||||
isOpen?: boolean;
|
isOpen?: boolean;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
hotkeyScope?: ModalHotkeyScope;
|
hotkeyScope?: ModalHotkeyScope;
|
||||||
onEnter?: () => void;
|
onEnter?: () => void;
|
||||||
|
size?: ModalSize;
|
||||||
|
padding?: ModalPadding;
|
||||||
};
|
};
|
||||||
|
|
||||||
const modalVariants = {
|
const modalVariants = {
|
||||||
@ -105,6 +142,8 @@ export function Modal({
|
|||||||
onClose,
|
onClose,
|
||||||
hotkeyScope = ModalHotkeyScope.Default,
|
hotkeyScope = ModalHotkeyScope.Default,
|
||||||
onEnter,
|
onEnter,
|
||||||
|
size = 'medium',
|
||||||
|
padding = 'medium',
|
||||||
...restProps
|
...restProps
|
||||||
}: ModalProps) {
|
}: ModalProps) {
|
||||||
const modalRef = useRef<HTMLDivElement>(null);
|
const modalRef = useRef<HTMLDivElement>(null);
|
||||||
@ -157,6 +196,8 @@ export function Modal({
|
|||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
ref={modalRef}
|
ref={modalRef}
|
||||||
|
size={size}
|
||||||
|
padding={padding}
|
||||||
initial="hidden"
|
initial="hidden"
|
||||||
animate="visible"
|
animate="visible"
|
||||||
exit="exit"
|
exit="exit"
|
||||||
|
|||||||
@ -1,39 +1,40 @@
|
|||||||
import styled from '@emotion/styled';
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
import { Meta, StoryObj } from '@storybook/react';
|
|
||||||
|
|
||||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||||
|
|
||||||
import { Modal } from '../Modal';
|
import { Modal } from '../Modal';
|
||||||
|
import { ModalHotkeyScope } from '../types/ModalHotkeyScope';
|
||||||
|
|
||||||
const meta: Meta<typeof Modal> = {
|
const meta: Meta<typeof Modal> = {
|
||||||
title: 'UI/Modal/Modal',
|
title: 'UI/Modal/Modal',
|
||||||
component: Modal,
|
component: Modal,
|
||||||
decorators: [ComponentDecorator],
|
|
||||||
};
|
};
|
||||||
export default meta;
|
|
||||||
|
|
||||||
|
export default meta;
|
||||||
type Story = StoryObj<typeof Modal>;
|
type Story = StoryObj<typeof Modal>;
|
||||||
|
|
||||||
const StyledContentContainer = styled.div`
|
|
||||||
color: ${({ theme }) => theme.font.color.primary};
|
|
||||||
margin: 5px;
|
|
||||||
padding: ${({ theme }) => theme.spacing(10)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const args = {
|
|
||||||
isOpen: true,
|
|
||||||
children: (
|
|
||||||
<Modal.Content>
|
|
||||||
<StyledContentContainer>Lorem ipsum</StyledContentContainer>
|
|
||||||
</Modal.Content>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Default: Story = {
|
export const Default: Story = {
|
||||||
args,
|
args: {
|
||||||
|
isOpen: true,
|
||||||
|
size: 'medium',
|
||||||
|
padding: 'medium',
|
||||||
|
hotkeyScope: ModalHotkeyScope.Default,
|
||||||
|
children: (
|
||||||
|
<>
|
||||||
|
<Modal.Header>Stay in touch</Modal.Header>
|
||||||
|
<Modal.Content>
|
||||||
|
This is a dummy newletter form so don't bother trying to test it. Not
|
||||||
|
that I expect you to, anyways. :)
|
||||||
|
</Modal.Content>
|
||||||
|
<Modal.Footer>
|
||||||
|
By using Twenty, you're opting for the finest CRM experience you'll
|
||||||
|
ever encounter.
|
||||||
|
</Modal.Footer>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
},
|
||||||
decorators: [ComponentDecorator],
|
decorators: [ComponentDecorator],
|
||||||
};
|
argTypes: {
|
||||||
|
children: { control: false },
|
||||||
Default.argTypes = {
|
},
|
||||||
children: { control: false },
|
|
||||||
};
|
};
|
||||||
|
|||||||
7
front/src/modules/ui/theme/constants/modal.ts
Normal file
7
front/src/modules/ui/theme/constants/modal.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export const modal = {
|
||||||
|
size: {
|
||||||
|
sm: '300px',
|
||||||
|
md: '400px',
|
||||||
|
lg: '53%',
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -7,6 +7,7 @@ import { boxShadowDark, boxShadowLight } from './boxShadow';
|
|||||||
import { color, grayScale } from './colors';
|
import { color, grayScale } from './colors';
|
||||||
import { fontDark, fontLight } from './font';
|
import { fontDark, fontLight } from './font';
|
||||||
import { icon } from './icon';
|
import { icon } from './icon';
|
||||||
|
import { modal } from './modal';
|
||||||
import { tagDark, tagLight } from './tag';
|
import { tagDark, tagLight } from './tag';
|
||||||
import { text } from './text';
|
import { text } from './text';
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ const common = {
|
|||||||
color: color,
|
color: color,
|
||||||
grayScale: grayScale,
|
grayScale: grayScale,
|
||||||
icon: icon,
|
icon: icon,
|
||||||
|
modal: modal,
|
||||||
text: text,
|
text: text,
|
||||||
blur: blur,
|
blur: blur,
|
||||||
animation: animation,
|
animation: animation,
|
||||||
|
|||||||
Reference in New Issue
Block a user