Skip to content

Commit 0bc6c04

Browse files
authored
refactor: Use focus lock hooks instead of sentinel elements (#529)
* chore: init * chore: focus refactor * test: clean up
1 parent 401b183 commit 0bc6c04

File tree

5 files changed

+91
-185
lines changed

5 files changed

+91
-185
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"dependencies": {
5353
"@rc-component/motion": "^1.1.3",
5454
"@rc-component/portal": "^2.0.0",
55-
"@rc-component/util": "^1.0.1",
55+
"@rc-component/util": "^1.5.0",
5656
"clsx": "^2.1.1"
5757
},
5858
"devDependencies": {

src/Dialog/Content/Panel.tsx

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,12 @@
11
import { clsx } from 'clsx';
22
import { useComposeRef } from '@rc-component/util/lib/ref';
3+
import { useLockFocus } from '@rc-component/util/lib/Dom/focus';
34
import React, { useMemo, useRef } from 'react';
45
import { RefContext } from '../../context';
56
import type { IDialogPropTypes } from '../../IDialogPropTypes';
67
import MemoChildren from './MemoChildren';
78
import pickAttrs from '@rc-component/util/lib/pickAttrs';
89

9-
const sentinelStyle: React.CSSProperties = {
10-
width: 0,
11-
height: 0,
12-
overflow: 'hidden',
13-
outline: 'none',
14-
};
15-
16-
const entityStyle: React.CSSProperties = {
17-
outline: 'none',
18-
};
19-
2010
export interface PanelProps extends Omit<IDialogPropTypes, 'getOpenCount'> {
2111
prefixCls: string;
2212
ariaId?: string;
@@ -27,7 +17,6 @@ export interface PanelProps extends Omit<IDialogPropTypes, 'getOpenCount'> {
2717

2818
export type PanelRef = {
2919
focus: () => void;
30-
changeActive: (next: boolean) => void;
3120
};
3221

3322
const Panel = React.forwardRef<PanelRef, PanelProps>((props, ref) => {
@@ -58,23 +47,14 @@ const Panel = React.forwardRef<PanelRef, PanelProps>((props, ref) => {
5847

5948
// ================================= Refs =================================
6049
const { panel: panelRef } = React.useContext(RefContext);
50+
const internalRef = useRef<HTMLDivElement>(null);
51+
const mergedRef = useComposeRef(holderRef, panelRef, internalRef);
6152

62-
const mergedRef = useComposeRef(holderRef, panelRef);
63-
64-
const sentinelStartRef = useRef<HTMLDivElement>(null);
65-
const sentinelEndRef = useRef<HTMLDivElement>(null);
53+
useLockFocus(visible, () => internalRef.current);
6654

6755
React.useImperativeHandle(ref, () => ({
6856
focus: () => {
69-
sentinelStartRef.current?.focus({ preventScroll: true });
70-
},
71-
changeActive: (next) => {
72-
const { activeElement } = document;
73-
if (next && activeElement === sentinelEndRef.current) {
74-
sentinelStartRef.current.focus({ preventScroll: true });
75-
} else if (!next && activeElement === sentinelStartRef.current) {
76-
sentinelEndRef.current.focus({ preventScroll: true });
77-
}
57+
internalRef.current?.focus({ preventScroll: true });
7858
},
7959
}));
8060

@@ -167,13 +147,11 @@ const Panel = React.forwardRef<PanelRef, PanelProps>((props, ref) => {
167147
className={clsx(prefixCls, className)}
168148
onMouseDown={onMouseDown}
169149
onMouseUp={onMouseUp}
150+
tabIndex={-1}
170151
>
171-
<div ref={sentinelStartRef} tabIndex={0} style={entityStyle}>
172-
<MemoChildren shouldUpdate={visible || forceRender}>
173-
{modalRender ? modalRender(content) : content}
174-
</MemoChildren>
175-
</div>
176-
<div tabIndex={0} ref={sentinelEndRef} style={sentinelStyle} />
152+
<MemoChildren shouldUpdate={visible || forceRender}>
153+
{modalRender ? modalRender(content) : content}
154+
</MemoChildren>
177155
</div>
178156
);
179157
});

src/Dialog/index.tsx

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ const Dialog: React.FC<IDialogPropTypes> = (props) => {
4747

4848
if (process.env.NODE_ENV !== 'production') {
4949
['wrapStyle', 'bodyStyle', 'maskStyle'].forEach((prop) => {
50-
// (prop in props) && console.error(`Warning: ${prop} is deprecated, please use styles instead.`)
5150
warning(!(prop in props), `${prop} is deprecated, please use styles instead.`);
5251
});
5352
if ('wrapClassName' in props) {
@@ -148,11 +147,6 @@ const Dialog: React.FC<IDialogPropTypes> = (props) => {
148147
onInternalClose(e);
149148
return;
150149
}
151-
152-
// keep focus inside dialog
153-
if (visible && e.keyCode === KeyCode.TAB) {
154-
contentRef.current.changeActive(!e.shiftKey);
155-
}
156150
}
157151

158152
// ========================= Effect =========================
@@ -200,7 +194,6 @@ const Dialog: React.FC<IDialogPropTypes> = (props) => {
200194
className={modalClassNames?.mask}
201195
/>
202196
<div
203-
tabIndex={-1}
204197
onKeyDown={onWrapperKeyDown}
205198
className={clsx(`${prefixCls}-wrap`, wrapClassName, modalClassNames?.wrapper)}
206199
ref={wrapperRef}

0 commit comments

Comments
 (0)