Skip to content

Commit

Permalink
feat: Support document.activeElement (#393)
Browse files Browse the repository at this point in the history
Co-authored-by: huangbangsheng <huangbangsheng@joyy.com>
  • Loading branch information
wahiche-ideal and huangbangsheng committed Jan 27, 2024
1 parent fb2db17 commit e2d12f4
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 98 deletions.
12 changes: 8 additions & 4 deletions src/Dialog/Content/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { IDialogPropTypes } from '../../IDialogPropTypes';
import MemoChildren from './MemoChildren';

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

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

const sentinelStartRef = useRef<HTMLDivElement>();
const sentinelEndRef = useRef<HTMLDivElement>();
const entityRef = useRef<HTMLDivElement>();

React.useImperativeHandle(ref, () => ({
focus: () => {
sentinelStartRef.current?.focus();
entityRef.current?.focus();
},
changeActive: (next) => {
const { activeElement } = document;
Expand Down Expand Up @@ -130,9 +132,11 @@ const Panel = React.forwardRef<ContentRef, PanelProps>((props, ref) => {
onMouseUp={onMouseUp}
>
<div tabIndex={0} ref={sentinelStartRef} style={sentinelStyle} aria-hidden="true" />
<MemoChildren shouldUpdate={visible || forceRender}>
{modalRender ? modalRender(content) : content}
</MemoChildren>
<div ref={entityRef} tabIndex={-1} style={entityStyle}>
<MemoChildren shouldUpdate={visible || forceRender}>
{modalRender ? modalRender(content) : content}
</MemoChildren>
</div>
<div tabIndex={0} ref={sentinelEndRef} style={sentinelStyle} aria-hidden="true" />
</div>
);
Expand Down
172 changes: 96 additions & 76 deletions tests/__snapshots__/index.spec.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,25 @@ exports[`dialog add rootClassName should render correct 1`] = `
tabindex="0"
/>
<div
class="rc-dialog-content"
style="outline: none;"
tabindex="-1"
>
<button
aria-label="Close"
class="rc-dialog-close"
type="button"
<div
class="rc-dialog-content"
>
<span
class="rc-dialog-close-x"
<button
aria-label="Close"
class="rc-dialog-close"
type="button"
>
<span
class="rc-dialog-close-x"
/>
</button>
<div
class="rc-dialog-body"
/>
</button>
<div
class="rc-dialog-body"
/>
</div>
</div>
<div
aria-hidden="true"
Expand Down Expand Up @@ -72,30 +77,35 @@ exports[`dialog should render correct 1`] = `
tabindex="0"
/>
<div
class="rc-dialog-content"
style="outline: none;"
tabindex="-1"
>
<button
aria-label="Close"
class="rc-dialog-close"
type="button"
>
<span
class="rc-dialog-close-x"
/>
</button>
<div
class="rc-dialog-header"
class="rc-dialog-content"
>
<button
aria-label="Close"
class="rc-dialog-close"
type="button"
>
<span
class="rc-dialog-close-x"
/>
</button>
<div
class="rc-dialog-title"
id="test-id"
class="rc-dialog-header"
>
Default
<div
class="rc-dialog-title"
id="test-id"
>
Default
</div>
</div>
<div
class="rc-dialog-body"
/>
</div>
<div
class="rc-dialog-body"
/>
</div>
<div
aria-hidden="true"
Expand Down Expand Up @@ -131,34 +141,39 @@ exports[`dialog should support classNames 1`] = `
tabindex="0"
/>
<div
class="rc-dialog-content custom-content"
style="outline: none;"
tabindex="-1"
>
<button
aria-label="Close"
class="rc-dialog-close"
type="button"
>
<span
class="rc-dialog-close-x"
/>
</button>
<div
class="rc-dialog-header custom-header"
class="rc-dialog-content custom-content"
>
<button
aria-label="Close"
class="rc-dialog-close"
type="button"
>
<span
class="rc-dialog-close-x"
/>
</button>
<div
class="rc-dialog-title"
id="test-id"
class="rc-dialog-header custom-header"
>
Default
<div
class="rc-dialog-title"
id="test-id"
>
Default
</div>
</div>
<div
class="rc-dialog-body custom-body"
/>
<div
class="rc-dialog-footer custom-footer"
>
Footer
</div>
</div>
<div
class="rc-dialog-body custom-body"
/>
<div
class="rc-dialog-footer custom-footer"
>
Footer
</div>
</div>
<div
Expand Down Expand Up @@ -197,38 +212,43 @@ exports[`dialog should support styles 1`] = `
tabindex="0"
/>
<div
class="rc-dialog-content"
style="background: orange;"
style="outline: none;"
tabindex="-1"
>
<button
aria-label="Close"
class="rc-dialog-close"
type="button"
>
<span
class="rc-dialog-close-x"
/>
</button>
<div
class="rc-dialog-header"
style="background: red;"
class="rc-dialog-content"
style="background: orange;"
>
<button
aria-label="Close"
class="rc-dialog-close"
type="button"
>
<span
class="rc-dialog-close-x"
/>
</button>
<div
class="rc-dialog-title"
id="test-id"
class="rc-dialog-header"
style="background: red;"
>
Default
<div
class="rc-dialog-title"
id="test-id"
>
Default
</div>
</div>
<div
class="rc-dialog-body"
style="background: green;"
/>
<div
class="rc-dialog-footer"
style="background: blue;"
>
Footer
</div>
</div>
<div
class="rc-dialog-body"
style="background: green;"
/>
<div
class="rc-dialog-footer"
style="background: blue;"
>
Footer
</div>
</div>
<div
Expand Down
41 changes: 23 additions & 18 deletions tests/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ describe('dialog', () => {
wrapper.update();

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

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

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

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

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

fireEvent.keyDown(document.querySelector('.rc-dialog-wrap'), {
fireEvent.keyDown(document.querySelector('.rc-dialog-wrap')!, {
keyCode: KeyCode.TAB,
key: 'Tab',
shiftKey: true,
});
const sentinelEnd = document.querySelector('.rc-dialog-content + div');
const sentinelEnd = document.querySelector('.rc-dialog > div:last-child');
expect(document.activeElement).toBe(sentinelEnd);
});
});
Expand Down Expand Up @@ -555,8 +557,8 @@ describe('dialog', () => {
const wrapper = mount(
<Dialog
visible
title='Default'
footer='Footer'
title="Default"
footer="Footer"
classNames={{
header: 'custom-header',
body: 'custom-body',
Expand All @@ -579,15 +581,14 @@ describe('dialog', () => {
expect(wrapper.find('.rc-dialog-footer').props().className).toContain('custom-footer');
expect(wrapper.find('.rc-dialog-mask').props().className).toContain('custom-mask');
expect(wrapper.find('.rc-dialog-content').props().className).toContain('custom-content');

});

it('should support styles', () => {
const wrapper = mount(
<Dialog
visible
title='Default'
footer='Footer'
title="Default"
footer="Footer"
styles={{
header: { background: 'red' },
body: { background: 'green' },
Expand Down Expand Up @@ -616,20 +617,24 @@ describe('dialog', () => {
const wrapper = mount(
<Dialog
visible
title='Default'
footer='Footer'
title="Default"
footer="Footer"
bodyStyle={{ background: 'green' }}
maskStyle={{ background: 'yellow' }}
wrapClassName='custom-wrapper'
wrapClassName="custom-wrapper"
style={{ width: 600 }}
height={903}
/>,
);
jest.runAllTimers();
wrapper.update();

expect(spy).toHaveBeenCalledWith(`Warning: bodyStyle is deprecated, please use styles instead.`);
expect(spy).toHaveBeenCalledWith(`Warning: maskStyle is deprecated, please use styles instead.`);
expect(spy).toHaveBeenCalledWith(
`Warning: bodyStyle is deprecated, please use styles instead.`,
);
expect(spy).toHaveBeenCalledWith(
`Warning: maskStyle is deprecated, please use styles instead.`,
);
expect(spy).toHaveBeenCalledWith(
`Warning: wrapClassName is deprecated, please use classNames instead.`,
);
Expand Down

1 comment on commit e2d12f4

@vercel
Copy link

@vercel vercel bot commented on e2d12f4 Jan 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.