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
43 changes: 42 additions & 1 deletion src/organisms/Modals/Modal/Modal.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState } from 'react'
import { ChakraProvider } from '@chakra-ui/react'
import { render, screen } from '@testing-library/react'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'

import { Modal } from './Modal'
Expand All @@ -17,6 +18,30 @@ const renderWithChakra = (ui: React.ReactElement): any => {
return render(<ChakraProvider>{ui}</ChakraProvider>)
}

const ModalFocusHarness = ({
returnFocusOnClose = true,
}: {
returnFocusOnClose?: boolean
}): JSX.Element => {
const [isOpen, setIsOpen] = useState(false)

return (
<>
<button type="button" onClick={() => setIsOpen(true)}>
Open Modal
</button>
<Modal
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title="Focus Modal"
returnFocusOnClose={returnFocusOnClose}
>
<div>Focus Content</div>
</Modal>
</>
)
}

// Props por defecto para reducir repetición
const defaultProps = {
isOpen: true,
Expand Down Expand Up @@ -98,6 +123,22 @@ describe('Modal Component', () => {
await user.keyboard('{Escape}')
expect(onCloseMock).not.toHaveBeenCalled()
})

it('does not restore focus to trigger when returnFocusOnClose is false', async () => {
const user = userEvent.setup()
renderWithChakra(<ModalFocusHarness returnFocusOnClose={false} />)

const trigger = screen.getByRole('button', { name: 'Open Modal' })
trigger.focus()

await user.click(trigger)
await user.click(screen.getByLabelText('Close'))

await waitFor(() => {
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
})
expect(trigger).not.toHaveFocus()
})
})

describe('Modal Configuration', () => {
Expand Down
2 changes: 2 additions & 0 deletions src/organisms/Modals/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const Modal = ({
scrollBehavior = 'outside',
fixedButtons = false,
autoFocus = false,
returnFocusOnClose = true,
minWidth,
maxWidth,
minHeight,
Expand Down Expand Up @@ -48,6 +49,7 @@ export const Modal = ({
onClose={onClose}
scrollBehavior={isInside ? 'inside' : 'outside'}
autoFocus={autoFocus}
returnFocusOnClose={returnFocusOnClose}
blockScrollOnMount={false}
>
<ModalOverlay />
Expand Down
47 changes: 46 additions & 1 deletion src/organisms/Modals/ModalAlert/ModalAlert.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { render, screen } from '@testing-library/react'
import { useState } from 'react'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { ChakraProvider } from '@chakra-ui/react'

Expand All @@ -17,6 +18,34 @@ const renderWithChakra = (ui: React.ReactElement): any => {
return render(<ChakraProvider>{ui}</ChakraProvider>)
}

const ModalAlertFocusHarness = ({
returnFocusOnClose = true,
}: {
returnFocusOnClose?: boolean
}): JSX.Element => {
const [isOpen, setIsOpen] = useState(false)

return (
<>
<button type="button" onClick={() => setIsOpen(true)}>
Open Alert
</button>
<ModalAlertNew
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title="Focus Alert"
type="info"
status="info"
returnFocusOnClose={returnFocusOnClose}
>
<button type="button" onClick={() => setIsOpen(false)}>
Close Alert
</button>
</ModalAlertNew>
</>
)
}

describe('ModalAlertNew Component', () => {
it('renders with title and description', () => {
renderWithChakra(
Expand Down Expand Up @@ -111,4 +140,20 @@ describe('ModalAlertNew Component', () => {

expect(screen.getByText('Custom Description Node')).toBeInTheDocument()
})

it('does not restore focus to trigger when returnFocusOnClose is false', async () => {
const user = userEvent.setup()
renderWithChakra(<ModalAlertFocusHarness returnFocusOnClose={false} />)

const trigger = screen.getByRole('button', { name: 'Open Alert' })
trigger.focus()

await user.click(trigger)
await user.click(screen.getByRole('button', { name: 'Close Alert' }))

await waitFor(() => {
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
})
expect(trigger).not.toHaveFocus()
})
})
2 changes: 2 additions & 0 deletions src/organisms/Modals/ModalAlert/ModalAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useModalAlertConfig } from './useModalAlertConfig'
export const ModalAlertNew = ({
autoFocus = false,
type,
returnFocusOnClose = true,
isOpen,
onClose,
children,
Expand All @@ -25,6 +26,7 @@ export const ModalAlertNew = ({
onClose={onClose}
closeOnEsc={type !== 'loading'}
autoFocus={autoFocus}
returnFocusOnClose={returnFocusOnClose}
>
<ModalOverlay />
<ModalContent {...modalConfig.contentProps}>
Expand Down
44 changes: 43 additions & 1 deletion src/organisms/Modals/ModalMultiple/ModalMultiple.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState } from 'react'
import { ChakraProvider } from '@chakra-ui/react'
import { render, screen } from '@testing-library/react'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'

import { ModalMultiple } from './ModalMultiple'
Expand All @@ -17,6 +18,31 @@ const renderWithChakra = (ui: React.ReactElement): any => {
return render(<ChakraProvider>{ui}</ChakraProvider>)
}

const ModalMultipleFocusHarness = ({
returnFocusOnClose = true,
}: {
returnFocusOnClose?: boolean
}): JSX.Element => {
const [isOpen, setIsOpen] = useState(false)

return (
<>
<button type="button" onClick={() => setIsOpen(true)}>
Open Multiple
</button>
<ModalMultiple
type="modal"
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title="Focus Multiple"
returnFocusOnClose={returnFocusOnClose}
>
<div>Focus Content</div>
</ModalMultiple>
</>
)
}

describe('ModalMultiple Component', () => {
beforeEach(() => {
jest.clearAllMocks()
Expand Down Expand Up @@ -119,6 +145,22 @@ describe('ModalMultiple Component', () => {
await user.keyboard('{Escape}')
expect(onCloseMock).not.toHaveBeenCalled()
})

it('does not restore focus to trigger when returnFocusOnClose is false', async () => {
const user = userEvent.setup()
renderWithChakra(<ModalMultipleFocusHarness returnFocusOnClose={false} />)

const trigger = screen.getByRole('button', { name: 'Open Multiple' })
trigger.focus()

await user.click(trigger)
await user.click(screen.getByLabelText('Close'))

await waitFor(() => {
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
})
expect(trigger).not.toHaveFocus()
})
})

/* -------------------------------------------------------------------------- */
Expand Down
3 changes: 3 additions & 0 deletions src/organisms/Modals/ModalMultiple/ModalMultiple.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type BaseProps = ModalDefaultProps & {
isOpen: boolean
onClose: () => void
autoFocus?: boolean
returnFocusOnClose?: boolean
}

type ModalProps = BaseProps & {
Expand Down Expand Up @@ -85,6 +86,7 @@ export const ModalMultiple = (props: ModalMultipleProps): JSX.Element => {
isOpen,
onClose,
autoFocus = false,
returnFocusOnClose = true,
children,
title,
closeOnOverlayClick = true,
Expand Down Expand Up @@ -149,6 +151,7 @@ export const ModalMultiple = (props: ModalMultipleProps): JSX.Element => {
onClose={onClose}
motionPreset="scale"
autoFocus={autoFocus}
returnFocusOnClose={returnFocusOnClose}
closeOnOverlayClick={modalConfig.closeOnOverlayClick}
closeOnEsc={modalConfig.closeOnEsc}
scrollBehavior={modalConfig.scrollBehavior}
Expand Down
2 changes: 2 additions & 0 deletions src/organisms/Modals/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface IModal {
/** Si esta activo se fija el footer */
fixedButtons?: boolean
autoFocus?: boolean
returnFocusOnClose?: boolean
minWidth?: string | number
maxWidth?: string | number
minHeight?: string | number
Expand Down Expand Up @@ -59,6 +60,7 @@ export interface IModalButtons {

export interface IModalAlert {
autoFocus?: boolean
returnFocusOnClose?: boolean
children?: React.ReactNode
isOpen: boolean
onClose: () => void
Expand Down
Loading