Skip to content

Commit 40355b8

Browse files
authored
fix: focusTriggerAfterClose not working (#307)
close #280 ant-design/ant-design#32923
1 parent d8e2732 commit 40355b8

File tree

2 files changed

+70
-6
lines changed

2 files changed

+70
-6
lines changed

src/Dialog/index.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,23 @@ export default function Dialog(props: IDialogPropTypes) {
5151
// ========================== Init ==========================
5252
const ariaId = useId();
5353

54+
function saveLastOutSideActiveElementRef() {
55+
if (!contains(wrapperRef.current, document.activeElement)) {
56+
lastOutSideActiveElementRef.current = document.activeElement as HTMLElement;
57+
}
58+
}
59+
60+
function focusDialogContent() {
61+
if (!contains(wrapperRef.current, document.activeElement)) {
62+
contentRef.current?.focus();
63+
}
64+
}
65+
5466
// ========================= Events =========================
5567
function onDialogVisibleChanged(newVisible: boolean) {
68+
// Try to focus
5669
if (newVisible) {
57-
// Try to focus
58-
if (!contains(wrapperRef.current, document.activeElement)) {
59-
lastOutSideActiveElementRef.current = document.activeElement as HTMLElement;
60-
contentRef.current?.focus();
61-
}
70+
focusDialogContent();
6271
} else {
6372
// Clean up scroll bar & focus back
6473
setAnimatedVisible(false);
@@ -131,6 +140,7 @@ export default function Dialog(props: IDialogPropTypes) {
131140
useEffect(() => {
132141
if (visible) {
133142
setAnimatedVisible(true);
143+
saveLastOutSideActiveElementRef();
134144
}
135145
}, [visible]);
136146

tests/index.spec.tsx

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable react/no-render-return-value, max-classes-per-file, func-names, no-console */
2-
import React, { cloneElement } from 'react';
2+
import React, { cloneElement, useEffect } from 'react';
33
import { act } from 'react-dom/test-utils';
44
import { render } from '@testing-library/react';
55
import type { ReactWrapper } from 'enzyme';
@@ -362,6 +362,60 @@ describe('dialog', () => {
362362
expect(modalRender.find('.rc-dialog-content').props().style.background).toEqual('#1890ff');
363363
});
364364

365+
describe('focusTriggerAfterClose', () => {
366+
it('should focus trigger after close dialog', () => {
367+
const Demo = () => {
368+
const [visible, setVisible] = React.useState(false);
369+
return (
370+
<>
371+
<button onClick={() => setVisible(true)}>trigger</button>
372+
<Dialog visible={visible} onClose={() => setVisible(false)}>
373+
content
374+
</Dialog>
375+
</>
376+
);
377+
};
378+
const wrapper = mount(<Demo />, { attachTo: document.body });
379+
const trigger = wrapper.find('button').at(0);
380+
(trigger.getDOMNode() as any).focus();
381+
trigger.simulate('click');
382+
jest.runAllTimers();
383+
const closeButton = wrapper.find('.rc-dialog-close');
384+
closeButton.simulate('click');
385+
jest.runAllTimers();
386+
expect(document.activeElement).toBe(trigger.getDOMNode());
387+
wrapper.unmount();
388+
});
389+
390+
it('should focus trigger after close dialog when contains focusable element', () => {
391+
const Demo = () => {
392+
const [visible, setVisible] = React.useState(false);
393+
const inputRef = React.useRef(null);
394+
useEffect(() => {
395+
inputRef.current?.focus();
396+
}, []);
397+
return (
398+
<>
399+
<button onClick={() => setVisible(true)}>trigger</button>
400+
<Dialog visible={visible} onClose={() => setVisible(false)}>
401+
<input ref={inputRef} />
402+
</Dialog>
403+
</>
404+
);
405+
};
406+
const wrapper = mount(<Demo />, { attachTo: document.body });
407+
const trigger = wrapper.find('button').at(0);
408+
(trigger.getDOMNode() as any).focus();
409+
trigger.simulate('click');
410+
jest.runAllTimers();
411+
const closeButton = wrapper.find('.rc-dialog-close');
412+
closeButton.simulate('click');
413+
jest.runAllTimers();
414+
expect(document.activeElement).toBe(trigger.getDOMNode());
415+
wrapper.unmount();
416+
});
417+
});
418+
365419
describe('size should work', () => {
366420
it('width', () => {
367421
const wrapper = mount(<Dialog visible width={1128} />);

0 commit comments

Comments
 (0)