Skip to content

Commit e2d12f4

Browse files
wahiche-idealhuangbangsheng
andauthored
feat: Support document.activeElement (#393)
Co-authored-by: huangbangsheng <[email protected]>
1 parent fb2db17 commit e2d12f4

File tree

3 files changed

+127
-98
lines changed

3 files changed

+127
-98
lines changed

src/Dialog/Content/Panel.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { IDialogPropTypes } from '../../IDialogPropTypes';
66
import MemoChildren from './MemoChildren';
77

88
const sentinelStyle = { width: 0, height: 0, overflow: 'hidden', outline: 'none' };
9+
const entityStyle = { outline: 'none' };
910

1011
export interface PanelProps extends Omit<IDialogPropTypes, 'getOpenCount'> {
1112
prefixCls: string;
@@ -53,10 +54,11 @@ const Panel = React.forwardRef<ContentRef, PanelProps>((props, ref) => {
5354

5455
const sentinelStartRef = useRef<HTMLDivElement>();
5556
const sentinelEndRef = useRef<HTMLDivElement>();
57+
const entityRef = useRef<HTMLDivElement>();
5658

5759
React.useImperativeHandle(ref, () => ({
5860
focus: () => {
59-
sentinelStartRef.current?.focus();
61+
entityRef.current?.focus();
6062
},
6163
changeActive: (next) => {
6264
const { activeElement } = document;
@@ -130,9 +132,11 @@ const Panel = React.forwardRef<ContentRef, PanelProps>((props, ref) => {
130132
onMouseUp={onMouseUp}
131133
>
132134
<div tabIndex={0} ref={sentinelStartRef} style={sentinelStyle} aria-hidden="true" />
133-
<MemoChildren shouldUpdate={visible || forceRender}>
134-
{modalRender ? modalRender(content) : content}
135-
</MemoChildren>
135+
<div ref={entityRef} tabIndex={-1} style={entityStyle}>
136+
<MemoChildren shouldUpdate={visible || forceRender}>
137+
{modalRender ? modalRender(content) : content}
138+
</MemoChildren>
139+
</div>
136140
<div tabIndex={0} ref={sentinelEndRef} style={sentinelStyle} aria-hidden="true" />
137141
</div>
138142
);

tests/__snapshots__/index.spec.tsx.snap

Lines changed: 96 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,25 @@ exports[`dialog add rootClassName should render correct 1`] = `
2424
tabindex="0"
2525
/>
2626
<div
27-
class="rc-dialog-content"
27+
style="outline: none;"
28+
tabindex="-1"
2829
>
29-
<button
30-
aria-label="Close"
31-
class="rc-dialog-close"
32-
type="button"
30+
<div
31+
class="rc-dialog-content"
3332
>
34-
<span
35-
class="rc-dialog-close-x"
33+
<button
34+
aria-label="Close"
35+
class="rc-dialog-close"
36+
type="button"
37+
>
38+
<span
39+
class="rc-dialog-close-x"
40+
/>
41+
</button>
42+
<div
43+
class="rc-dialog-body"
3644
/>
37-
</button>
38-
<div
39-
class="rc-dialog-body"
40-
/>
45+
</div>
4146
</div>
4247
<div
4348
aria-hidden="true"
@@ -72,30 +77,35 @@ exports[`dialog should render correct 1`] = `
7277
tabindex="0"
7378
/>
7479
<div
75-
class="rc-dialog-content"
80+
style="outline: none;"
81+
tabindex="-1"
7682
>
77-
<button
78-
aria-label="Close"
79-
class="rc-dialog-close"
80-
type="button"
81-
>
82-
<span
83-
class="rc-dialog-close-x"
84-
/>
85-
</button>
8683
<div
87-
class="rc-dialog-header"
84+
class="rc-dialog-content"
8885
>
86+
<button
87+
aria-label="Close"
88+
class="rc-dialog-close"
89+
type="button"
90+
>
91+
<span
92+
class="rc-dialog-close-x"
93+
/>
94+
</button>
8995
<div
90-
class="rc-dialog-title"
91-
id="test-id"
96+
class="rc-dialog-header"
9297
>
93-
Default
98+
<div
99+
class="rc-dialog-title"
100+
id="test-id"
101+
>
102+
Default
103+
</div>
94104
</div>
105+
<div
106+
class="rc-dialog-body"
107+
/>
95108
</div>
96-
<div
97-
class="rc-dialog-body"
98-
/>
99109
</div>
100110
<div
101111
aria-hidden="true"
@@ -131,34 +141,39 @@ exports[`dialog should support classNames 1`] = `
131141
tabindex="0"
132142
/>
133143
<div
134-
class="rc-dialog-content custom-content"
144+
style="outline: none;"
145+
tabindex="-1"
135146
>
136-
<button
137-
aria-label="Close"
138-
class="rc-dialog-close"
139-
type="button"
140-
>
141-
<span
142-
class="rc-dialog-close-x"
143-
/>
144-
</button>
145147
<div
146-
class="rc-dialog-header custom-header"
148+
class="rc-dialog-content custom-content"
147149
>
150+
<button
151+
aria-label="Close"
152+
class="rc-dialog-close"
153+
type="button"
154+
>
155+
<span
156+
class="rc-dialog-close-x"
157+
/>
158+
</button>
148159
<div
149-
class="rc-dialog-title"
150-
id="test-id"
160+
class="rc-dialog-header custom-header"
151161
>
152-
Default
162+
<div
163+
class="rc-dialog-title"
164+
id="test-id"
165+
>
166+
Default
167+
</div>
168+
</div>
169+
<div
170+
class="rc-dialog-body custom-body"
171+
/>
172+
<div
173+
class="rc-dialog-footer custom-footer"
174+
>
175+
Footer
153176
</div>
154-
</div>
155-
<div
156-
class="rc-dialog-body custom-body"
157-
/>
158-
<div
159-
class="rc-dialog-footer custom-footer"
160-
>
161-
Footer
162177
</div>
163178
</div>
164179
<div
@@ -197,38 +212,43 @@ exports[`dialog should support styles 1`] = `
197212
tabindex="0"
198213
/>
199214
<div
200-
class="rc-dialog-content"
201-
style="background: orange;"
215+
style="outline: none;"
216+
tabindex="-1"
202217
>
203-
<button
204-
aria-label="Close"
205-
class="rc-dialog-close"
206-
type="button"
207-
>
208-
<span
209-
class="rc-dialog-close-x"
210-
/>
211-
</button>
212218
<div
213-
class="rc-dialog-header"
214-
style="background: red;"
219+
class="rc-dialog-content"
220+
style="background: orange;"
215221
>
222+
<button
223+
aria-label="Close"
224+
class="rc-dialog-close"
225+
type="button"
226+
>
227+
<span
228+
class="rc-dialog-close-x"
229+
/>
230+
</button>
216231
<div
217-
class="rc-dialog-title"
218-
id="test-id"
232+
class="rc-dialog-header"
233+
style="background: red;"
219234
>
220-
Default
235+
<div
236+
class="rc-dialog-title"
237+
id="test-id"
238+
>
239+
Default
240+
</div>
241+
</div>
242+
<div
243+
class="rc-dialog-body"
244+
style="background: green;"
245+
/>
246+
<div
247+
class="rc-dialog-footer"
248+
style="background: blue;"
249+
>
250+
Footer
221251
</div>
222-
</div>
223-
<div
224-
class="rc-dialog-body"
225-
style="background: green;"
226-
/>
227-
<div
228-
class="rc-dialog-footer"
229-
style="background: blue;"
230-
>
231-
Footer
232252
</div>
233253
</div>
234254
<div

tests/index.spec.tsx

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ describe('dialog', () => {
5151
wrapper.update();
5252

5353
expect(wrapper.render()).toMatchSnapshot();
54-
expect(spy).toHaveBeenCalledWith(`Warning: wrapStyle is deprecated, please use styles instead.`);
54+
expect(spy).toHaveBeenCalledWith(
55+
`Warning: wrapStyle is deprecated, please use styles instead.`,
56+
);
5557
expect(wrapper.find('.customize-root-class').length).toBeTruthy();
5658
expect(wrapper.find('.rc-dialog-wrap').props().style.fontSize).toBe(10);
5759
expect(wrapper.find('.rc-dialog').props().style.height).toEqual(903);
@@ -248,16 +250,16 @@ describe('dialog', () => {
248250
describe('Tab should keep focus in dialog', () => {
249251
it('basic tabbing', () => {
250252
const wrapper = mount(<Dialog visible />, { attachTo: document.body });
251-
const sentinelEnd = document.querySelectorAll(
252-
'.rc-dialog-content + div',
253-
)[0] as unknown as HTMLDivElement;
253+
const sentinelEnd = document.querySelector(
254+
'.rc-dialog > div:last-child',
255+
) as unknown as HTMLDivElement;
254256
sentinelEnd.focus();
255257

256258
wrapper.find('.rc-dialog-wrap').simulate('keyDown', {
257259
keyCode: KeyCode.TAB,
258260
});
259261

260-
const sentinelStart = document.querySelectorAll('.rc-dialog > div')[0];
262+
const sentinelStart = document.querySelector('.rc-dialog > div:first-child');
261263
expect(document.activeElement).toBe(sentinelStart);
262264

263265
wrapper.unmount();
@@ -266,14 +268,14 @@ describe('dialog', () => {
266268
it('trap focus after shift-tabbing', () => {
267269
render(<Dialog visible />);
268270

269-
document.querySelector<HTMLDivElement>('.rc-dialog > div').focus();
271+
document.querySelector<HTMLDivElement>('.rc-dialog > div:first-child')?.focus();
270272

271-
fireEvent.keyDown(document.querySelector('.rc-dialog-wrap'), {
273+
fireEvent.keyDown(document.querySelector('.rc-dialog-wrap')!, {
272274
keyCode: KeyCode.TAB,
273275
key: 'Tab',
274276
shiftKey: true,
275277
});
276-
const sentinelEnd = document.querySelector('.rc-dialog-content + div');
278+
const sentinelEnd = document.querySelector('.rc-dialog > div:last-child');
277279
expect(document.activeElement).toBe(sentinelEnd);
278280
});
279281
});
@@ -555,8 +557,8 @@ describe('dialog', () => {
555557
const wrapper = mount(
556558
<Dialog
557559
visible
558-
title='Default'
559-
footer='Footer'
560+
title="Default"
561+
footer="Footer"
560562
classNames={{
561563
header: 'custom-header',
562564
body: 'custom-body',
@@ -579,15 +581,14 @@ describe('dialog', () => {
579581
expect(wrapper.find('.rc-dialog-footer').props().className).toContain('custom-footer');
580582
expect(wrapper.find('.rc-dialog-mask').props().className).toContain('custom-mask');
581583
expect(wrapper.find('.rc-dialog-content').props().className).toContain('custom-content');
582-
583584
});
584585

585586
it('should support styles', () => {
586587
const wrapper = mount(
587588
<Dialog
588589
visible
589-
title='Default'
590-
footer='Footer'
590+
title="Default"
591+
footer="Footer"
591592
styles={{
592593
header: { background: 'red' },
593594
body: { background: 'green' },
@@ -616,20 +617,24 @@ describe('dialog', () => {
616617
const wrapper = mount(
617618
<Dialog
618619
visible
619-
title='Default'
620-
footer='Footer'
620+
title="Default"
621+
footer="Footer"
621622
bodyStyle={{ background: 'green' }}
622623
maskStyle={{ background: 'yellow' }}
623-
wrapClassName='custom-wrapper'
624+
wrapClassName="custom-wrapper"
624625
style={{ width: 600 }}
625626
height={903}
626627
/>,
627628
);
628629
jest.runAllTimers();
629630
wrapper.update();
630631

631-
expect(spy).toHaveBeenCalledWith(`Warning: bodyStyle is deprecated, please use styles instead.`);
632-
expect(spy).toHaveBeenCalledWith(`Warning: maskStyle is deprecated, please use styles instead.`);
632+
expect(spy).toHaveBeenCalledWith(
633+
`Warning: bodyStyle is deprecated, please use styles instead.`,
634+
);
635+
expect(spy).toHaveBeenCalledWith(
636+
`Warning: maskStyle is deprecated, please use styles instead.`,
637+
);
633638
expect(spy).toHaveBeenCalledWith(
634639
`Warning: wrapClassName is deprecated, please use classNames instead.`,
635640
);

0 commit comments

Comments
 (0)