Skip to content

Commit ccd025e

Browse files
feat(organisms): agregamos modal simple y modal card
1 parent 1ccd17a commit ccd025e

9 files changed

Lines changed: 373 additions & 1 deletion

File tree

src/documentation/components/Organisms/Modals.tsx

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
import { useDisclosure } from '@chakra-ui/react'
1+
import { Box, useDisclosure } from '@chakra-ui/react'
22

33
import { BtnLink, BtnPrimary, BtnSecondary } from '@/molecules'
44
import {
55
Modal,
66
ModalAlertNew,
77
ModalAlertButtons,
88
ModalButtons,
9+
ModalCard,
10+
ModalCardContent,
911
ModalContent,
12+
ModalSimple,
1013
} from '@/organisms/Modals/'
1114
import { ModalMultiple, ModalMultipleProps } from '@/organisms/Modals/ModalMultiple/ModalMultiple'
1215
import { useState } from 'react'
@@ -302,6 +305,66 @@ export const ModalAlertDemo = ({
302305
)
303306
}
304307

308+
export const ModalSimpleDemo = (): JSX.Element => {
309+
const { isOpen, onOpen, onClose } = useDisclosure()
310+
311+
return (
312+
<>
313+
<BtnPrimary onClick={onOpen}>ModalSimple</BtnPrimary>
314+
<ModalSimple isOpen={isOpen} onClose={onClose}>
315+
<p>{text}</p>
316+
</ModalSimple>
317+
</>
318+
)
319+
}
320+
321+
export const ModalCardDemo = (): JSX.Element => {
322+
const { isOpen, onOpen, onClose } = useDisclosure()
323+
324+
return (
325+
<>
326+
<BtnPrimary onClick={onOpen}>ModalCard</BtnPrimary>
327+
<ModalCard isOpen={isOpen} onClose={onClose}>
328+
<ModalCardContent>
329+
<Box display="flex" flexDirection="column" alignItems="center" textAlign="center">
330+
<Box as="p" fontSize="20px" fontWeight={700} lineHeight="24px" mb="16px">
331+
!Has ganado una nueva medalla!
332+
</Box>
333+
<Box
334+
w="120px"
335+
h="120px"
336+
borderRadius="16px"
337+
bg="#E0EEFA"
338+
mb="16px"
339+
display="flex"
340+
alignItems="center"
341+
justifyContent="center"
342+
fontSize="14px"
343+
fontWeight={700}
344+
>
345+
Medal
346+
</Box>
347+
<Box as="p" fontSize="16px" fontWeight={700} lineHeight="24px" mb="8px">
348+
Blast off
349+
</Box>
350+
<Box as="p" fontSize="16px" lineHeight="24px" color="#808080" mb="16px">
351+
¡Felicitaciones, has comenzado tu viaje de estudio!
352+
</Box>
353+
<BtnLink as="button" onClick={onClose}>
354+
Ver mis medallas
355+
</BtnLink>
356+
</Box>
357+
</ModalCardContent>
358+
<ModalAlertButtons>
359+
<BtnLink as="button" onClick={onClose}>
360+
Entendido
361+
</BtnLink>
362+
</ModalAlertButtons>
363+
</ModalCard>
364+
</>
365+
)
366+
}
367+
305368
export const ModalMultipleDemo = (): JSX.Element => {
306369
const { isOpen, onOpen, onClose } = useDisclosure()
307370
const [type, setType] = useState<ModalMultipleProps['type']>('modal')

src/documentation/pages/Organisms/Modals.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { MyHeading, MyText, MyTitle, Code, ListComponent } from '@/documentation/components'
22
import {
33
ModalAlertDemo,
4+
ModalCardDemo,
45
ModalDemo,
56
ModalMultipleDemo,
7+
ModalSimpleDemo,
68
} from '@/documentation/components/Organisms/Modals'
79

810
export const ViewModals = (): JSX.Element => {
@@ -52,6 +54,77 @@ export function View(){
5254
</ModalContent>
5355
</Modal>
5456
)
57+
}`}
58+
/>
59+
<MyTitle>Tipo ModalSimple</MyTitle>
60+
<MyText>
61+
Es una variante mínima del modal para casos donde solo necesitas contenido libre y la acción
62+
de cierre. No renderiza la banda azul ni título, y mantiene la <strong>X</strong> como
63+
control principal junto con las props base del modal.
64+
</MyText>
65+
<MyText>El componente se importa de la siguiente manera:</MyText>
66+
<Code text="import { ModalSimple } from '@eclass/ui-kit'" />
67+
<ListComponent>
68+
<ModalSimpleDemo />
69+
</ListComponent>
70+
<Code
71+
text={`
72+
import { ModalSimple } from '@eclass/ui-kit'
73+
import { useDisclosure } from '@chakra-ui/react'
74+
75+
export function View(){
76+
const { isOpen, onOpen, onClose } = useDisclosure()
77+
78+
return (
79+
<>
80+
<BtnPrimary onClick={onOpen}>Abrir ModalSimple</BtnPrimary>
81+
<ModalSimple
82+
isOpen={isOpen}
83+
onClose={onClose}
84+
>
85+
<p>Contenido libre del modal...</p>
86+
</ModalSimple>
87+
</>
88+
)
89+
}`}
90+
/>
91+
<MyTitle>Tipo ModalCard</MyTitle>
92+
<MyText>
93+
Es una variante pensada para contenido tipo card, como logros o medallas. No renderiza
94+
iconos ni encabezado por defecto, mantiene la <strong>X</strong> para cerrar y permite
95+
contenido completamente libre. Su ancho está pensado para cards compactas.
96+
</MyText>
97+
<MyText>El componente se importa de la siguiente manera:</MyText>
98+
<Code text="import { ModalCard, ModalCardContent, ModalAlertButtons } from '@eclass/ui-kit'" />
99+
<ListComponent>
100+
<ModalCardDemo />
101+
</ListComponent>
102+
<Code
103+
text={`
104+
import { ModalCard, ModalCardContent, ModalAlertButtons, BtnLink } from '@eclass/ui-kit'
105+
import { useDisclosure } from '@chakra-ui/react'
106+
107+
export function View(){
108+
const { isOpen, onOpen, onClose } = useDisclosure()
109+
110+
return (
111+
<>
112+
<BtnPrimary onClick={onOpen}>Abrir ModalCard</BtnPrimary>
113+
<ModalCard
114+
isOpen={isOpen}
115+
onClose={onClose}
116+
>
117+
<ModalCardContent>
118+
<div>Contenido libre del card...</div>
119+
</ModalCardContent>
120+
<ModalAlertButtons>
121+
<BtnLink as="button" onClick={onClose}>
122+
Entendido
123+
</BtnLink>
124+
</ModalAlertButtons>
125+
</ModalCard>
126+
</>
127+
)
55128
}`}
56129
/>
57130
<MyTitle>Variantes del tipo Modal</MyTitle>

src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ export {
2626
ModalContent,
2727
ModalAlertButtons,
2828
ModalMultiple,
29+
ModalSimple,
30+
ModalCard,
31+
ModalCardContent,
2932
} from './organisms/Modals'
3033
export type { ModalMultipleProps } from './organisms/Modals'
3134
export { ModalAlert } from './organisms/ModalAlert'
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { ChakraProvider } from '@chakra-ui/react'
2+
import { render, screen } from '@testing-library/react'
3+
4+
import { ModalCard } from './ModalCard'
5+
6+
const renderWithChakra = (ui: React.ReactElement): any => {
7+
return render(<ChakraProvider>{ui}</ChakraProvider>)
8+
}
9+
10+
describe('ModalCard Component', () => {
11+
it('renders children content', () => {
12+
renderWithChakra(
13+
<ModalCard isOpen onClose={jest.fn()}>
14+
<div>Card content</div>
15+
</ModalCard>
16+
)
17+
18+
expect(screen.getByText('Card content')).toBeInTheDocument()
19+
expect(screen.getByRole('dialog')).toBeInTheDocument()
20+
})
21+
22+
it('does not render a close button', () => {
23+
renderWithChakra(
24+
<ModalCard isOpen onClose={jest.fn()}>
25+
<div>Card content</div>
26+
</ModalCard>
27+
)
28+
29+
expect(screen.queryByLabelText('Close')).not.toBeInTheDocument()
30+
})
31+
})
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { Modal as ChakraModal, ModalOverlay, ModalContent, Box } from '@chakra-ui/react'
2+
3+
import { vars } from '@/theme'
4+
import { IModalCard } from '../types'
5+
import { useModalConfig } from './useModalConfig'
6+
7+
export const ModalCard = ({
8+
children,
9+
isOpen,
10+
onClose,
11+
closeOnOverlayClick = true,
12+
closeOnEsc = true,
13+
}: IModalCard): JSX.Element => {
14+
const modalConfig = useModalConfig({
15+
closeOnOverlayClick,
16+
scrollBehavior: 'outside',
17+
fixedButtons: false,
18+
withoutMargin: false,
19+
})
20+
21+
return (
22+
<ChakraModal
23+
closeOnOverlayClick={closeOnOverlayClick}
24+
closeOnEsc={closeOnEsc}
25+
isOpen={isOpen}
26+
motionPreset="scale"
27+
onClose={onClose}
28+
scrollBehavior="outside"
29+
blockScrollOnMount={false}
30+
>
31+
<ModalOverlay />
32+
<ModalContent
33+
{...modalConfig.contentProps}
34+
maxW="355px"
35+
minW="355px"
36+
minH="auto"
37+
overflow="hidden"
38+
sx={{
39+
...modalConfig.contentProps.sx,
40+
bgColor: vars('colors-neutral-white'),
41+
maxWidth: '355px',
42+
}}
43+
>
44+
<Box>{children}</Box>
45+
</ModalContent>
46+
</ChakraModal>
47+
)
48+
}
49+
50+
export const ModalCardContent = ({ children }: { children: React.ReactNode }): JSX.Element => {
51+
return <Box p="32px">{children}</Box>
52+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { ChakraProvider } from '@chakra-ui/react'
2+
import { render, screen } from '@testing-library/react'
3+
import userEvent from '@testing-library/user-event'
4+
5+
import { ModalSimple } from './ModalSimple'
6+
7+
const renderWithChakra = (ui: React.ReactElement): any => {
8+
return render(<ChakraProvider>{ui}</ChakraProvider>)
9+
}
10+
11+
describe('ModalSimple Component', () => {
12+
it('renders children content', () => {
13+
renderWithChakra(
14+
<ModalSimple isOpen onClose={jest.fn()}>
15+
<div>Simple content</div>
16+
</ModalSimple>
17+
)
18+
19+
expect(screen.getByText('Simple content')).toBeInTheDocument()
20+
expect(screen.getByRole('dialog')).toBeInTheDocument()
21+
})
22+
23+
it('calls onClose when close button is clicked', async () => {
24+
const user = userEvent.setup()
25+
const onCloseMock = jest.fn()
26+
27+
renderWithChakra(
28+
<ModalSimple isOpen onClose={onCloseMock}>
29+
<div>Simple content</div>
30+
</ModalSimple>
31+
)
32+
33+
await user.click(screen.getByLabelText('Close'))
34+
expect(onCloseMock).toHaveBeenCalledTimes(1)
35+
})
36+
37+
it('does not call onClose when Escape key is pressed and closeOnEsc is false', async () => {
38+
const user = userEvent.setup()
39+
const onCloseMock = jest.fn()
40+
41+
renderWithChakra(
42+
<ModalSimple isOpen onClose={onCloseMock} closeOnEsc={false}>
43+
<div>Simple content</div>
44+
</ModalSimple>
45+
)
46+
47+
await user.keyboard('{Escape}')
48+
expect(onCloseMock).not.toHaveBeenCalled()
49+
})
50+
51+
it('removes inner spacing when withoutMargin is true', () => {
52+
renderWithChakra(
53+
<ModalSimple isOpen onClose={jest.fn()} withoutMargin>
54+
<div>Simple content</div>
55+
</ModalSimple>
56+
)
57+
58+
expect(screen.getByTestId('modal-simple-content')).toBeInTheDocument()
59+
expect(screen.getByText('Simple content')).toBeInTheDocument()
60+
})
61+
})

0 commit comments

Comments
 (0)