@@ -2,11 +2,19 @@ import * as React from 'react';
22import classNames from 'classnames' ;
33import CSSMotion from 'rc-motion' ;
44import type { CSSMotionProps } from 'rc-motion' ;
5- import type { DrawerPanelRef } from './DrawerPanel' ;
65import DrawerPanel from './DrawerPanel' ;
76import type ScrollLocker from 'rc-util/lib/Dom/scrollLocker' ;
87import DrawerContext from './context' ;
98import 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+ } ;
1018
1119export type Placement = 'left' | 'right' | 'top' | 'bottom' ;
1220
@@ -97,6 +105,48 @@ export default function DrawerPopup(props: DrawerPopupProps) {
97105 onClose,
98106 } = props ;
99107
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+
100150 // ============================ Push ============================
101151 const [ pushed , setPushed ] = React . useState ( false ) ;
102152
@@ -130,8 +180,6 @@ export default function DrawerPopup(props: DrawerPopupProps) {
130180 ) ;
131181
132182 // ========================= ScrollLock =========================
133- const panelRef = React . useRef < DrawerPanelRef > ( ) ;
134-
135183 // Tell parent to push
136184 React . useEffect ( ( ) => {
137185 if ( open ) {
@@ -157,20 +205,6 @@ export default function DrawerPopup(props: DrawerPopupProps) {
157205 [ ] ,
158206 ) ;
159207
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-
174208 // =========================== zIndex ===========================
175209 const zIndexStyle : React . CSSProperties = { } ;
176210 if ( zIndex ) {
@@ -252,7 +286,6 @@ export default function DrawerPopup(props: DrawerPopupProps) {
252286 { ( { className : motionClassName , style : motionStyle } , motionRef ) => {
253287 return (
254288 < DrawerPanel
255- ref = { panelRef }
256289 containerRef = { motionRef }
257290 prefixCls = { prefixCls }
258291 className = { classNames ( className , motionClassName ) }
@@ -263,7 +296,6 @@ export default function DrawerPopup(props: DrawerPopupProps) {
263296 width = { width }
264297 height = { height }
265298 placement = { placement }
266- onClose = { onPanelClose }
267299 >
268300 { children }
269301 </ DrawerPanel >
@@ -286,9 +318,26 @@ export default function DrawerPopup(props: DrawerPopupProps) {
286318 } ,
287319 ) }
288320 style = { rootStyle }
321+ tabIndex = { - 1 }
322+ ref = { panelRef }
323+ onKeyDown = { onPanelKeyDown }
289324 >
290325 { maskNode }
326+ < div
327+ tabIndex = { 0 }
328+ ref = { sentinelStartRef }
329+ style = { sentinelStyle }
330+ aria-hidden = "true"
331+ data-sentinel = "start"
332+ />
291333 { panelNode }
334+ < div
335+ tabIndex = { 0 }
336+ ref = { sentinelEndRef }
337+ style = { sentinelStyle }
338+ aria-hidden = "true"
339+ data-sentinel = "end"
340+ />
292341 </ div >
293342 </ DrawerContext . Provider >
294343 ) ;
0 commit comments