mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-15 14:43:46 +01:00
Add focus trap to Modal component (#28754)
* Add focus-trap-react npm package * Trap the focus for the Modal * In some cases, the focus will not return to the trigger element * If there are no tabbable elements, the focus should fallback * Add explanations for focusTrapOptions props and extend test * Auto generate package-lock.json - Add focus-trap-react npm package GitOrigin-RevId: 488a05d5e95dd369c69bedcfaf7c1fd5e456e302
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import { useRef } from 'react'
|
||||
import {
|
||||
FocusTrap as FocusTrapReact,
|
||||
FocusTrapProps as FocusTrapReactProps,
|
||||
} from 'focus-trap-react'
|
||||
|
||||
export type FocusTrapProps = {
|
||||
active: FocusTrapReactProps['active']
|
||||
children: React.ReactNode
|
||||
focusTrapOptions?: FocusTrapReactProps['focusTrapOptions']
|
||||
}
|
||||
|
||||
export default function FocusTrap({
|
||||
active,
|
||||
focusTrapOptions,
|
||||
children,
|
||||
}: FocusTrapProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
return (
|
||||
<FocusTrapReact
|
||||
active={active}
|
||||
focusTrapOptions={{
|
||||
...focusTrapOptions,
|
||||
fallbackFocus: () => containerRef.current as HTMLElement,
|
||||
}}
|
||||
>
|
||||
<div ref={containerRef}>{children}</div>
|
||||
</FocusTrapReact>
|
||||
)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import FocusTrap from '../focus-trap'
|
||||
import {
|
||||
Modal,
|
||||
ModalProps,
|
||||
@@ -6,18 +7,44 @@ import {
|
||||
ModalFooterProps,
|
||||
} from 'react-bootstrap'
|
||||
import { ModalBodyProps } from 'react-bootstrap/ModalBody'
|
||||
import type { Options as FocusTrapOptions } from 'focus-trap'
|
||||
|
||||
type OLModalProps = ModalProps & {
|
||||
size?: 'sm' | 'lg'
|
||||
onHide: () => void
|
||||
}
|
||||
show?: boolean
|
||||
} & Pick<
|
||||
FocusTrapOptions,
|
||||
'escapeDeactivates' | 'clickOutsideDeactivates' | 'returnFocusOnDeactivate'
|
||||
>
|
||||
|
||||
type OLModalHeaderProps = ModalHeaderProps & {
|
||||
closeButton?: boolean
|
||||
}
|
||||
|
||||
export function OLModal({ children, ...props }: OLModalProps) {
|
||||
return <Modal {...props}>{children}</Modal>
|
||||
export function OLModal({
|
||||
children,
|
||||
show = false,
|
||||
onHide,
|
||||
returnFocusOnDeactivate = true, // Return focus to trigger element when modal closes
|
||||
escapeDeactivates = false, // Let React-Bootstrap Modal handle Escape key to avoid double Escape key handling
|
||||
clickOutsideDeactivates = true, // Allow focus trap to deactivate on outside click and let React-Bootstrap Modal handle it
|
||||
...props
|
||||
}: OLModalProps) {
|
||||
return (
|
||||
<Modal show={show} onHide={onHide} {...props}>
|
||||
<FocusTrap
|
||||
active={show}
|
||||
focusTrapOptions={{
|
||||
escapeDeactivates,
|
||||
clickOutsideDeactivates,
|
||||
returnFocusOnDeactivate,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</FocusTrap>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export function OLModalHeader({
|
||||
|
||||
Reference in New Issue
Block a user