@@ -2,11 +2,19 @@ import * as React from 'react';
2
2
import classNames from 'classnames' ;
3
3
import CSSMotion from 'rc-motion' ;
4
4
import type { CSSMotionProps } from 'rc-motion' ;
5
- import type { DrawerPanelRef } from './DrawerPanel' ;
6
5
import DrawerPanel from './DrawerPanel' ;
7
6
import type ScrollLocker from 'rc-util/lib/Dom/scrollLocker' ;
8
7
import DrawerContext from './context' ;
9
8
import type { DrawerContextProps } from './context' ;
9
+ import KeyCode from 'rc-util/lib/KeyCode' ;
10
+
11
+ const sentinelStyle : React . CSSProperties = {
12
+ width : 0 ,
13
+ height : 0 ,
14
+ overflow : 'hidden' ,
15
+ outline : 'none' ,
16
+ position : 'absolute' ,
17
+ } ;
10
18
11
19
export type Placement = 'left' | 'right' | 'top' | 'bottom' ;
12
20
@@ -97,6 +105,48 @@ export default function DrawerPopup(props: DrawerPopupProps) {
97
105
onClose,
98
106
} = props ;
99
107
108
+ // ================================ Refs ================================
109
+ const panelRef = React . useRef < HTMLDivElement > ( ) ;
110
+ const sentinelStartRef = React . useRef < HTMLDivElement > ( ) ;
111
+ const sentinelEndRef = React . useRef < HTMLDivElement > ( ) ;
112
+
113
+ const onPanelKeyDown : React . KeyboardEventHandler < HTMLDivElement > = event => {
114
+ const { keyCode, shiftKey } = event ;
115
+
116
+ switch ( keyCode ) {
117
+ // Tab active
118
+ case KeyCode . TAB : {
119
+ if ( keyCode === KeyCode . TAB ) {
120
+ if ( ! shiftKey && document . activeElement === sentinelEndRef . current ) {
121
+ sentinelStartRef . current ?. focus ( { preventScroll : true } ) ;
122
+ } else if (
123
+ shiftKey &&
124
+ document . activeElement === sentinelStartRef . current
125
+ ) {
126
+ sentinelEndRef . current ?. focus ( { preventScroll : true } ) ;
127
+ }
128
+ }
129
+ break ;
130
+ }
131
+
132
+ // Close
133
+ case KeyCode . ESC : {
134
+ if ( onClose && keyboard ) {
135
+ onClose ( event ) ;
136
+ }
137
+ break ;
138
+ }
139
+ }
140
+ } ;
141
+
142
+ // ========================== Control ===========================
143
+ // Auto Focus
144
+ React . useEffect ( ( ) => {
145
+ if ( open && autoFocus ) {
146
+ panelRef . current ?. focus ( { preventScroll : true } ) ;
147
+ }
148
+ } , [ open , autoFocus ] ) ;
149
+
100
150
// ============================ Push ============================
101
151
const [ pushed , setPushed ] = React . useState ( false ) ;
102
152
@@ -130,8 +180,6 @@ export default function DrawerPopup(props: DrawerPopupProps) {
130
180
) ;
131
181
132
182
// ========================= ScrollLock =========================
133
- const panelRef = React . useRef < DrawerPanelRef > ( ) ;
134
-
135
183
// Tell parent to push
136
184
React . useEffect ( ( ) => {
137
185
if ( open ) {
@@ -157,20 +205,6 @@ export default function DrawerPopup(props: DrawerPopupProps) {
157
205
[ ] ,
158
206
) ;
159
207
160
- // ========================== Control ===========================
161
- // Auto Focus
162
- React . useEffect ( ( ) => {
163
- if ( open && autoFocus ) {
164
- panelRef . current ?. focus ( ) ;
165
- }
166
- } , [ open , autoFocus ] ) ;
167
-
168
- const onPanelClose : React . KeyboardEventHandler < HTMLDivElement > = event => {
169
- if ( onClose && keyboard ) {
170
- onClose ( event ) ;
171
- }
172
- } ;
173
-
174
208
// =========================== zIndex ===========================
175
209
const zIndexStyle : React . CSSProperties = { } ;
176
210
if ( zIndex ) {
@@ -252,7 +286,6 @@ export default function DrawerPopup(props: DrawerPopupProps) {
252
286
{ ( { className : motionClassName , style : motionStyle } , motionRef ) => {
253
287
return (
254
288
< DrawerPanel
255
- ref = { panelRef }
256
289
containerRef = { motionRef }
257
290
prefixCls = { prefixCls }
258
291
className = { classNames ( className , motionClassName ) }
@@ -263,7 +296,6 @@ export default function DrawerPopup(props: DrawerPopupProps) {
263
296
width = { width }
264
297
height = { height }
265
298
placement = { placement }
266
- onClose = { onPanelClose }
267
299
>
268
300
{ children }
269
301
</ DrawerPanel >
@@ -286,9 +318,26 @@ export default function DrawerPopup(props: DrawerPopupProps) {
286
318
} ,
287
319
) }
288
320
style = { rootStyle }
321
+ tabIndex = { - 1 }
322
+ ref = { panelRef }
323
+ onKeyDown = { onPanelKeyDown }
289
324
>
290
325
{ maskNode }
326
+ < div
327
+ tabIndex = { 0 }
328
+ ref = { sentinelStartRef }
329
+ style = { sentinelStyle }
330
+ aria-hidden = "true"
331
+ data-sentinel = "start"
332
+ />
291
333
{ panelNode }
334
+ < div
335
+ tabIndex = { 0 }
336
+ ref = { sentinelEndRef }
337
+ style = { sentinelStyle }
338
+ aria-hidden = "true"
339
+ data-sentinel = "end"
340
+ />
292
341
</ div >
293
342
</ DrawerContext . Provider >
294
343
) ;
0 commit comments