Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions src/documentation/components/Organisms/Modals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
ModalButtons,
ModalContent,
} from '@/organisms/Modals/'
import { ModalMultiple, ModalMultipleProps } from '@/organisms/Modals/ModalMultiple/ModalMultiple'
import { useState } from 'react'

export const ModalDemo = ({
type,
Expand Down Expand Up @@ -298,3 +300,40 @@ export const ModalAlertDemo = ({
</>
)
}

export const ModalMultipleDemo = (): JSX.Element => {
const { isOpen, onOpen, onClose } = useDisclosure()
const [type, setType] = useState<ModalMultipleProps['type']>('modal')
return (
<>
<BtnPrimary onClick={onOpen}>ModalMultiple</BtnPrimary>
<ModalMultiple
type={type}
isOpen={isOpen}
onClose={onClose}
title={type === 'modal' ? 'Confirmación' : '¿Seguro que deseas borrar esta pregunta?'}
status="info"
description="Por favor escoge otro horario."
>
{type === 'modal' ? (
<ModalContent>
<p>alumnos, además de definir el uso de la plataforma de estudio.</p>
<ModalButtons>
<BtnPrimary onClick={() => setType('modal')}>Guardar</BtnPrimary>
<BtnSecondary onClick={() => onClose()}>Cancelar</BtnSecondary>
</ModalButtons>
</ModalContent>
) : (
<ModalAlertButtons>
<BtnLink as="button" onClick={() => setType('modal')}>
Aceptar
</BtnLink>
<BtnLink as="button" onClick={() => onClose()}>
Cancelar
</BtnLink>
</ModalAlertButtons>
)}
</ModalMultiple>
</>
)
}
72 changes: 71 additions & 1 deletion src/documentation/pages/Organisms/Modals.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { MyHeading, MyText, MyTitle, Code, ListComponent } from '@/documentation/components'
import { ModalAlertDemo, ModalDemo } from '@/documentation/components/Organisms/Modals'
import {
ModalAlertDemo,
ModalDemo,
ModalMultipleDemo,
} from '@/documentation/components/Organisms/Modals'

export const ViewModals = (): JSX.Element => {
return (
Expand Down Expand Up @@ -131,6 +135,72 @@ export function View(){
withoutDescription
/>
</ListComponent>
<MyTitle>Tipo ModalMultiple</MyTitle>
<MyText>
Es un componente unificador que permite renderizar dos tipos de modal distintos dentro de un
mismo flujo: <br />
<br /> <strong>modal</strong> → Modal tradicional (contenido libre, cabecera, footer,
botones, scroll).
<br /> <strong>modalAlert / modalLoading</strong> → Modal de alerta o de carga, con
contenido reducido y foco en la acción del usuario. <br />
<br /> Está pensado para casos donde el estado del modal cambia (por ejemplo,
confirmaciones, advertencias o pasos intermedios) sin necesidad de cerrar y volver a abrir
otro modal.
</MyText>
<ListComponent>
<ModalMultipleDemo />
</ListComponent>
<Code
text={`
import {
ModalMultiple,
ModalMultipleProps,
BtnPrimary,
BtnSecondary,
ModalContent,
ModalButtons,
ModalAlertButtons,
BtnLink
} from '@eclass/ui-kit'
import { useDisclosure } from '@chakra-ui/react'

export function View(){
const { isOpen, onOpen, onClose } = useDisclosure()
const [type, setType] = useState<ModalMultipleProps['type']>('modal')

return (
<>
<BtnPrimary onClick={onOpen}>ModalMultiple</BtnPrimary>
<ModalMultiple
type={type}
isOpen={isOpen}
onClose={onClose}
title={type === 'modal' ? 'Confirmación' : '¿Seguro que deseas borrar esta pregunta?'}
status="info"
description="Por favor escoge otro horario."
>
{type === 'modal' ? (
<ModalContent>
<p>alumnos, además de definir el uso de la plataforma de estudio.</p>
<ModalButtons>
<BtnPrimary onClick={() => setType('modalAlert')}>Guardar</BtnPrimary>
<BtnSecondary onClick={() => onClose()}>Cancelar</BtnSecondary>
</ModalButtons>
</ModalContent>
) : (
<ModalAlertButtons>
<BtnLink as="button" onClick={() => setType('modal')}>
Aceptar
</BtnLink>
<BtnLink as="button" onClick={() => onClose()}>
Cancelar
</BtnLink>
</ModalAlertButtons>
)}
</ModalMultiple>
</>)
}`}
/>
</>
)
}
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export {
ModalButtons,
ModalContent,
ModalAlertButtons,
ModalMultiple,
ModalMultipleProps,
} from './organisms/Modals'
export { ModalAlert } from './organisms/ModalAlert'
export { Eventos } from './organisms/Events'
Expand Down
136 changes: 35 additions & 101 deletions src/organisms/Modals/Modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import {
Box,
Modal as ChakraModal,
ModalCloseButton,
ModalContent as ChakraModalContent,
ModalHeader,
ModalOverlay,
useMediaQuery,
} from '@chakra-ui/react'
import { Modal as ChakraModal, ModalOverlay, ModalContent } from '@chakra-ui/react'

import { vars } from '@/theme'
import { IModal } from '../types'
import { ModalContentBase } from './ModalContentBase'
import { useModalConfig } from './useModalConfig'

export const uiKitModalIsDesktop = 641
export const ModalPadding = {
py: '32px',
px: '24px',
}

export const Modal = ({
children,
Expand All @@ -25,101 +22,38 @@ export const Modal = ({
fixedButtons = false,
autoFocus = false,
}: IModal): JSX.Element => {
const py = '32px'
const px = '24px'

const [isDesktop] = useMediaQuery(`(min-width: ${uiKitModalIsDesktop}px)`)

const isInside = scrollBehavior === 'inside' || fixedButtons

return (
<>
<ChakraModal
closeOnOverlayClick={closeOnOverlayClick}
closeOnEsc={closeOnOverlayClick}
isOpen={isOpen}
motionPreset="scale"
onClose={onClose}
scrollBehavior={isInside ? 'inside' : 'outside'}
autoFocus={autoFocus}
>
<ModalOverlay />
<ChakraModalContent
maxH={isInside ? '100dvh' : 'auto'}
minH={isDesktop ? '300px' : '100dvh'}
padding={0}
width="100%"
sx={{
bgColor: vars('colors-neutral-white'),
borderRadius: isDesktop ? '8px' : 0,
mt: isDesktop ? '48px' : 0,
mb: isDesktop ? '48px' : 0,
marginX: isDesktop ? 'auto' : 0,
maxH: isInside ? 'calc(100dvh - 96px)' : 'auto',
maxWidth: isDesktop ? '690px' : '100%',
const modalConfig = useModalConfig({
closeOnOverlayClick,
scrollBehavior,
fixedButtons,
withoutMargin,
})

...(fixedButtons && {
'.uikit-modalContent': {
pb: 0,
},
'.uikit-modalButtons': {
py: py,
px: px,
},
}),
...(withoutMargin && {
'.uikit-modalContent': {
pt: 0,
px: 0,
},
'.uikit-modalButtons': {
px: px,
},
}),
}}
return (
<ChakraModal
closeOnOverlayClick={modalConfig.closeOnOverlayClick}
closeOnEsc={modalConfig.closeOnEsc}
isOpen={isOpen}
motionPreset="scale"
onClose={onClose}
scrollBehavior={isInside ? 'inside' : 'outside'}
autoFocus={autoFocus}
blockScrollOnMount={false}
>
<ModalOverlay />
<ModalContent {...modalConfig.contentProps}>
<ModalContentBase
fixedButtons={fixedButtons}
withoutMargin={withoutMargin}
title={title}
closeOnOverlayClick={closeOnOverlayClick}
fixedSubtitle={fixedSubtitle}
>
<ModalHeader
bg={vars('colors-main-deepSkyBlue')}
borderTopRadius={isDesktop ? '8px' : 0}
color={vars('colors-neutral-white')}
fontFamily="Roboto"
fontSize={isDesktop ? '20px' : '18px'}
fontWeight={700}
lineHeight={1}
mb={withoutMargin ? 0 : '32px'}
paddingY={px}
textAlign="center"
>
{title}
</ModalHeader>
{closeOnOverlayClick && (
<ModalCloseButton
background="transparent!important"
border="none"
color={vars('colors-neutral-white')}
h="12px"
p="22px"
right={0}
top={0}
w="12px"
_focus={{
boxShadow: 'none',
}}
_focusVisible={{
boxShadow: `inset 0 0 0 2px ${vars(
'colors-alert-deepSkyBlue'
)}, inset 0 0 0 4px ${vars('colors-neutral-white')}`,
}}
/>
)}
{fixedSubtitle?.trim() && (
<Box as="p" fontSize="14px" lineHeight="19px" mb={py} textAlign="center" px={px}>
{fixedSubtitle}
</Box>
)}
{children}
</ChakraModalContent>
</ChakraModal>
</>
</ModalContentBase>
</ModalContent>
</ChakraModal>
)
}
62 changes: 62 additions & 0 deletions src/organisms/Modals/Modal/ModalContentBase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Box, ModalCloseButton, ModalHeader, useMediaQuery } from '@chakra-ui/react'

import { vars } from '@/theme'
import { IModalContentBase } from '../types'
import { uiKitModalIsDesktop } from './Modal'

export const ModalContentBase = ({
children,
closeOnOverlayClick,
fixedSubtitle,
title,
withoutMargin,
}: IModalContentBase): JSX.Element => {
const [isDesktop] = useMediaQuery(`(min-width: ${uiKitModalIsDesktop}px)`)
const py = '32px'
const px = '24px'

return (
<>
<ModalHeader
bg={vars('colors-main-deepSkyBlue')}
borderTopRadius={isDesktop ? '8px' : 0}
color={vars('colors-neutral-white')}
fontFamily="Roboto"
fontSize={isDesktop ? '20px' : '18px'}
fontWeight={700}
lineHeight={1}
mb={withoutMargin ? 0 : '32px'}
paddingY={px}
textAlign="center"
>
{title}
</ModalHeader>
{closeOnOverlayClick && (
<ModalCloseButton
background="transparent!important"
border="none"
color={vars('colors-neutral-white')}
h="12px"
p="22px"
right={0}
top={0}
w="12px"
_focus={{
boxShadow: 'none',
}}
_focusVisible={{
boxShadow: `inset 0 0 0 2px ${vars('colors-alert-deepSkyBlue')}, inset 0 0 0 4px ${vars(
'colors-neutral-white'
)}`,
}}
/>
)}
{fixedSubtitle?.trim() && (
<Box as="p" fontSize="14px" lineHeight="19px" mb={py} textAlign="center" px={px}>
{fixedSubtitle}
</Box>
)}
{children}
</>
)
}
Loading