diff --git a/src/Preview/index.tsx b/src/Preview/index.tsx index 065fdb1..44106ab 100644 --- a/src/Preview/index.tsx +++ b/src/Preview/index.tsx @@ -89,6 +89,10 @@ export interface InternalPreviewConfig { zIndex?: number; afterOpenChange?: (open: boolean) => void; + // Focus + /** Whether to trap focus within the preview when open. Default is true. */ + focusTrap?: boolean; + // Operation movable?: boolean; icons?: OperationIcons; @@ -193,6 +197,7 @@ const Preview: React.FC = props => { styles = {}, mousePosition, zIndex, + focusTrap = true, } = props; const imgRef = useRef(); @@ -397,7 +402,7 @@ const Preview: React.FC = props => { } }, [open]); - useLockFocus(open && portalRender, () => wrapperRef.current); + useLockFocus(focusTrap && open && portalRender, () => wrapperRef.current); // ========================== Render ========================== const bodyStyle: React.CSSProperties = { diff --git a/tests/preview.test.tsx b/tests/preview.test.tsx index f81744c..c40a293 100644 --- a/tests/preview.test.tsx +++ b/tests/preview.test.tsx @@ -1296,4 +1296,28 @@ describe('Preview', () => { rectSpy.mockRestore(); }); + + it('Focus should not be trapped when focusTrap is false', () => { + const rectSpy = jest.spyOn(HTMLElement.prototype, 'getBoundingClientRect').mockReturnValue({ + x: 0, y: 0, width: 100, height: 100, + top: 0, right: 100, bottom: 100, left: 0, + toJSON: () => undefined, + } as DOMRect); + + const { container } = render(no trap); + + act(() => { + jest.runAllTimers(); + }); + + const preview = document.querySelector('.rc-image-preview') as HTMLElement; + expect(preview).toBeTruthy(); + + // Focus outside the preview should not be redirected back + const wrapper = container.querySelector('.rc-image') as HTMLElement; + wrapper.focus(); + expect(document.activeElement).toBe(wrapper); + + rectSpy.mockRestore(); + }); });